TreeBuilder.java (279560B)
1 /* 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. 6 * 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: 13 * 14 * The above copyright notice and this permission notice shall be included in 15 * all copies or substantial portions of the Software. 16 * 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. 24 */ 25 26 /* 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." 34 */ 35 36 package nu.validator.htmlparser.impl; 37 38 import java.util.Arrays; 39 import java.util.HashMap; 40 import java.util.Map; 41 42 import org.xml.sax.ErrorHandler; 43 import org.xml.sax.Locator; 44 import org.xml.sax.SAXException; 45 import org.xml.sax.SAXParseException; 46 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; 60 61 public abstract class TreeBuilder<T> implements TokenHandler, 62 TreeBuilderState<T> { 63 64 /** 65 * Array version of U+FFFD. 66 */ 67 private static final @NoLength char[] REPLACEMENT_CHARACTER = { '\uFFFD' }; 68 69 // Start dispatch groups 70 71 final static int OTHER = 0; 72 73 final static int A = 1; 74 75 final static int BASE = 2; 76 77 final static int BODY = 3; 78 79 final static int BR = 4; 80 81 final static int BUTTON = 5; 82 83 final static int CAPTION = 6; 84 85 final static int COL = 7; 86 87 final static int COLGROUP = 8; 88 89 final static int FORM = 9; 90 91 final static int FRAME = 10; 92 93 final static int FRAMESET = 11; 94 95 final static int IMAGE = 12; 96 97 final static int INPUT = 13; 98 99 final static int RT_OR_RP = 14; 100 101 final static int LI = 15; 102 103 final static int LINK_OR_BASEFONT_OR_BGSOUND = 16; 104 105 final static int MATH = 17; 106 107 final static int META = 18; 108 109 final static int SVG = 19; 110 111 final static int HEAD = 20; 112 113 final static int HR = 22; 114 115 final static int HTML = 23; 116 117 final static int NOBR = 24; 118 119 final static int NOFRAMES = 25; 120 121 final static int NOSCRIPT = 26; 122 123 final static int OPTGROUP = 27; 124 125 final static int OPTION = 28; 126 127 final static int P = 29; 128 129 final static int PLAINTEXT = 30; 130 131 final static int SCRIPT = 31; 132 133 final static int SELECT = 32; 134 135 final static int STYLE = 33; 136 137 final static int TABLE = 34; 138 139 final static int TEXTAREA = 35; 140 141 final static int TITLE = 36; 142 143 final static int TR = 37; 144 145 final static int XMP = 38; 146 147 final static int TBODY_OR_THEAD_OR_TFOOT = 39; 148 149 final static int TD_OR_TH = 40; 150 151 final static int DD_OR_DT = 41; 152 153 final static int H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6 = 42; 154 155 final static int MARQUEE_OR_APPLET = 43; 156 157 final static int PRE_OR_LISTING = 44; 158 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; 160 161 final static int UL_OR_OL_OR_DL = 46; 162 163 final static int IFRAME = 47; 164 165 final static int EMBED = 48; 166 167 final static int AREA_OR_WBR = 49; 168 169 final static int DIV_OR_BLOCKQUOTE_OR_CENTER_OR_MENU = 50; 170 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; 172 173 final static int RUBY_OR_SPAN_OR_SUB_OR_SUP_OR_VAR = 52; 174 175 final static int RB_OR_RTC = 53; 176 177 final static int PARAM_OR_SOURCE_OR_TRACK = 55; 178 179 final static int MGLYPH_OR_MALIGNMARK = 56; 180 181 final static int MI_MO_MN_MS_MTEXT = 57; 182 183 final static int ANNOTATION_XML = 58; 184 185 final static int FOREIGNOBJECT_OR_DESC = 59; 186 187 final static int NOEMBED = 60; 188 189 final static int FIELDSET = 61; 190 191 final static int OUTPUT = 62; 192 193 final static int OBJECT = 63; 194 195 final static int FONT = 64; 196 197 final static int KEYGEN = 65; 198 199 final static int TEMPLATE = 66; 200 201 final static int IMG = 67; 202 203 // start insertion modes 204 205 private static final int IN_ROW = 0; 206 207 private static final int IN_TABLE_BODY = 1; 208 209 private static final int IN_TABLE = 2; 210 211 private static final int IN_CAPTION = 3; 212 213 private static final int IN_CELL = 4; 214 215 private static final int FRAMESET_OK = 5; 216 217 private static final int IN_BODY = 6; 218 219 private static final int IN_HEAD = 7; 220 221 private static final int IN_HEAD_NOSCRIPT = 8; 222 223 // no fall-through 224 225 private static final int IN_COLUMN_GROUP = 9; 226 227 // no fall-through 228 229 private static final int IN_SELECT_IN_TABLE = 10; 230 231 private static final int IN_SELECT = 11; 232 233 // no fall-through 234 235 private static final int AFTER_BODY = 12; 236 237 // no fall-through 238 239 private static final int IN_FRAMESET = 13; 240 241 private static final int AFTER_FRAMESET = 14; 242 243 // no fall-through 244 245 private static final int INITIAL = 15; 246 247 // could add fall-through 248 249 private static final int BEFORE_HTML = 16; 250 251 // could add fall-through 252 253 private static final int BEFORE_HEAD = 17; 254 255 // no fall-through 256 257 private static final int AFTER_HEAD = 18; 258 259 // no fall-through 260 261 private static final int AFTER_AFTER_BODY = 19; 262 263 // no fall-through 264 265 private static final int AFTER_AFTER_FRAMESET = 20; 266 267 // no fall-through 268 269 private static final int TEXT = 21; 270 271 private static final int IN_TEMPLATE = 22; 272 273 // start charset states 274 275 private static final int CHARSET_INITIAL = 0; 276 277 private static final int CHARSET_C = 1; 278 279 private static final int CHARSET_H = 2; 280 281 private static final int CHARSET_A = 3; 282 283 private static final int CHARSET_R = 4; 284 285 private static final int CHARSET_S = 5; 286 287 private static final int CHARSET_E = 6; 288 289 private static final int CHARSET_T = 7; 290 291 private static final int CHARSET_EQUALS = 8; 292 293 private static final int CHARSET_SINGLE_QUOTED = 9; 294 295 private static final int CHARSET_DOUBLE_QUOTED = 10; 296 297 private static final int CHARSET_UNQUOTED = 11; 298 299 // end pseudo enums 300 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//" }; 352 353 private static final int NOT_FOUND_ON_STACK = Integer.MAX_VALUE; 354 355 // [NOCPP[ 356 357 private static final @Local String HTML_LOCAL = "html"; 358 359 // ]NOCPP] 360 361 private int mode = INITIAL; 362 363 private int originalMode = INITIAL; 364 365 /** 366 * Used only when moving back to IN_BODY. 367 */ 368 private boolean framesetOk = true; 369 370 protected Tokenizer tokenizer; 371 372 // [NOCPP[ 373 374 protected ErrorHandler errorHandler; 375 376 private DocumentModeHandler documentModeHandler; 377 378 // ]NOCPP] 379 380 private boolean scriptingEnabled = false; 381 382 private boolean needToDropLF; 383 384 // [NOCPP[ 385 386 private boolean wantingComments; 387 388 // ]NOCPP] 389 390 private boolean fragment; 391 392 private @Local String contextName; 393 394 private @NsUri String contextNamespace; 395 396 private T contextNode; 397 398 /** 399 * Stack of template insertion modes 400 */ 401 private @Auto int[] templateModeStack; 402 403 /** 404 * Current template mode stack pointer. 405 */ 406 private int templateModePtr = -1; 407 408 private @Auto StackNode<T>[] stackNodes; 409 410 /** 411 * Index of the earliest possible unused or empty element in stackNodes. 412 */ 413 private int stackNodesIdx = -1; 414 415 private int numStackNodes = 0; 416 417 private @Auto StackNode<T>[] stack; 418 419 private int currentPtr = -1; 420 421 private @Auto StackNode<T>[] listOfActiveFormattingElements; 422 423 private int listPtr = -1; 424 425 private T formPointer; 426 427 private T headPointer; 428 429 protected @Auto char[] charBuffer; 430 431 protected int charBufferLen = 0; 432 433 private boolean quirks = false; 434 435 private boolean forceNoQuirks = false; 436 437 private boolean allowDeclarativeShadowRoots = false; 438 439 private boolean keepBuffer = false; 440 441 // [NOCPP[ 442 443 private boolean reportingDoctype = true; 444 445 private XmlViolationPolicy namePolicy = XmlViolationPolicy.ALTER_INFOSET; 446 447 private final Map<String, LocatorImpl> idLocations = new HashMap<String, LocatorImpl>(); 448 449 // ]NOCPP] 450 451 protected TreeBuilder() { 452 fragment = false; 453 } 454 455 /** 456 * Reports an condition that would make the infoset incompatible with XML 457 * 1.0 as fatal. 458 * 459 * @throws SAXException 460 * @throws SAXParseException 461 */ 462 protected void fatal() throws SAXException { 463 } 464 465 // CPPONLY: @Inline private @Creator Object htmlCreator(@HtmlCreator Object htmlCreator) { 466 // CPPONLY: @Creator Object creator; 467 // CPPONLY: creator.html = htmlCreator; 468 // CPPONLY: return creator; 469 // CPPONLY: } 470 // CPPONLY: 471 // CPPONLY: @Inline private @Creator Object svgCreator(@SvgCreator Object svgCreator) { 472 // CPPONLY: @Creator Object creator; 473 // CPPONLY: creator.svg = svgCreator; 474 // CPPONLY: return creator; 475 // CPPONLY: } 476 477 // [NOCPP[ 478 479 protected final void fatal(Exception e) throws SAXException { 480 SAXParseException spe = new SAXParseException(e.getMessage(), 481 tokenizer, e); 482 if (errorHandler != null) { 483 errorHandler.fatalError(spe); 484 } 485 throw spe; 486 } 487 488 final void fatal(String s) throws SAXException { 489 SAXParseException spe = new SAXParseException(s, tokenizer); 490 if (errorHandler != null) { 491 errorHandler.fatalError(spe); 492 } 493 throw spe; 494 } 495 496 /** 497 * Reports a Parse Error. 498 * 499 * @param message 500 * the message 501 * @throws SAXException 502 */ 503 final void err(String message) throws SAXException { 504 if (errorHandler == null) { 505 return; 506 } 507 errNoCheck(message); 508 } 509 510 /** 511 * Reports a Parse Error without checking if an error handler is present. 512 * 513 * @param message 514 * the message 515 * @throws SAXException 516 */ 517 final void errNoCheck(String message) throws SAXException { 518 SAXParseException spe = new SAXParseException(message, tokenizer); 519 errorHandler.error(spe); 520 } 521 522 private void errListUnclosedStartTags(int eltPos) throws SAXException { 523 if (currentPtr != -1) { 524 for (int i = currentPtr; i > eltPos; i--) { 525 reportUnclosedElementNameAndLocation(i); 526 } 527 } 528 } 529 530 /** 531 * Reports the name and location of an unclosed element. 532 * 533 * @throws SAXException 534 */ 535 private final void reportUnclosedElementNameAndLocation(int pos) throws SAXException { 536 StackNode<T> node = stack[pos]; 537 if (node.isOptionalEndTag()) { 538 return; 539 } 540 TaintableLocatorImpl locator = node.getLocator(); 541 if (locator.isTainted()) { 542 return; 543 } 544 locator.markTainted(); 545 SAXParseException spe = new SAXParseException( 546 "Unclosed element \u201C" + node.popName + "\u201D.", locator); 547 errorHandler.error(spe); 548 } 549 550 /** 551 * Reports a warning 552 * 553 * @param message 554 * the message 555 * @throws SAXException 556 */ 557 final void warn(String message) throws SAXException { 558 if (errorHandler == null) { 559 return; 560 } 561 SAXParseException spe = new SAXParseException(message, tokenizer); 562 errorHandler.warning(spe); 563 } 564 565 /** 566 * Reports a warning with an explicit locator 567 * 568 * @param message 569 * the message 570 * @throws SAXException 571 */ 572 final void warn(String message, Locator locator) throws SAXException { 573 if (errorHandler == null) { 574 return; 575 } 576 SAXParseException spe = new SAXParseException(message, locator); 577 errorHandler.warning(spe); 578 } 579 580 // ]NOCPP] 581 582 public void setKeepBuffer(boolean keepBuffer) { 583 this.keepBuffer = keepBuffer; 584 } 585 586 public boolean dropBufferIfLongerThan(int length) { 587 if (charBuffer.length > length) { 588 charBuffer = null; 589 return true; 590 } 591 return false; 592 } 593 594 @SuppressWarnings("unchecked") public final void startTokenization(Tokenizer self) throws SAXException { 595 tokenizer = self; 596 stackNodes = new StackNode[64]; 597 stack = new StackNode[64]; 598 templateModeStack = new int[64]; 599 listOfActiveFormattingElements = new StackNode[64]; 600 needToDropLF = false; 601 originalMode = INITIAL; 602 templateModePtr = -1; 603 stackNodesIdx = 0; 604 numStackNodes = 0; 605 currentPtr = -1; 606 listPtr = -1; 607 formPointer = null; 608 headPointer = null; 609 // [NOCPP[ 610 idLocations.clear(); 611 wantingComments = wantsComments(); 612 // ]NOCPP] 613 start(fragment); 614 charBufferLen = 0; 615 if (!keepBuffer) { 616 charBuffer = null; 617 } 618 framesetOk = true; 619 if (fragment) { 620 T elt; 621 if (contextNode != null) { 622 elt = contextNode; 623 } else { 624 elt = createHtmlElementSetAsRoot(tokenizer.emptyAttributes()); 625 } 626 // When the context node is not in the HTML namespace, contrary 627 // to the spec, the first node on the stack is not set to "html" 628 // in the HTML namespace. Instead, it is set to a node that has 629 // the characteristics of the appropriate "adjusted current node". 630 // This way, there is no need to perform "adjusted current node" 631 // checks during tree construction. Instead, it's sufficient to 632 // just look at the current node. However, this also means that it 633 // is not safe to treat "html" in the HTML namespace as a sentinel 634 // that ends stack popping. Instead, stack popping loops that are 635 // meant not to pop the first element on the stack need to check 636 // for currentPos becoming zero. 637 if (contextNamespace == "http://www.w3.org/2000/svg") { 638 ElementName elementName = ElementName.SVG; 639 if ("title" == contextName || "desc" == contextName 640 || "foreignObject" == contextName) { 641 // These elements are all alike and we don't care about 642 // the exact name. 643 elementName = ElementName.FOREIGNOBJECT; 644 } 645 // This is the SVG variant of the StackNode constructor. 646 StackNode<T> node = createStackNode(elementName, 647 elementName.getCamelCaseName(), elt 648 // [NOCPP[ 649 , errorHandler == null ? null 650 : new TaintableLocatorImpl(tokenizer) 651 // ]NOCPP] 652 ); 653 currentPtr++; 654 stack[currentPtr] = node; 655 tokenizer.setState(Tokenizer.DATA); 656 // The frameset-ok flag is set even though <frameset> never 657 // ends up being allowed as HTML frameset in the fragment case. 658 mode = FRAMESET_OK; 659 } else if (contextNamespace == "http://www.w3.org/1998/Math/MathML") { 660 ElementName elementName = ElementName.MATH; 661 if ("mi" == contextName || "mo" == contextName 662 || "mn" == contextName || "ms" == contextName 663 || "mtext" == contextName) { 664 // These elements are all alike and we don't care about 665 // the exact name. 666 elementName = ElementName.MTEXT; 667 } else if ("annotation-xml" == contextName) { 668 elementName = ElementName.ANNOTATION_XML; 669 // Blink does not check the encoding attribute of the 670 // annotation-xml element innerHTML is being set on. 671 // Let's do the same at least until 672 // https://www.w3.org/Bugs/Public/show_bug.cgi?id=26783 673 // is resolved. 674 } 675 // This is the MathML variant of the StackNode constructor. 676 StackNode<T> node = createStackNode(elementName, elt, 677 elementName.getName(), false 678 // [NOCPP[ 679 , errorHandler == null ? null 680 : new TaintableLocatorImpl(tokenizer) 681 // ]NOCPP] 682 ); 683 currentPtr++; 684 stack[currentPtr] = node; 685 tokenizer.setState(Tokenizer.DATA); 686 // The frameset-ok flag is set even though <frameset> never 687 // ends up being allowed as HTML frameset in the fragment case. 688 mode = FRAMESET_OK; 689 } else { // html 690 StackNode<T> node = createStackNode(ElementName.HTML, elt 691 // [NOCPP[ 692 , errorHandler == null ? null 693 : new TaintableLocatorImpl(tokenizer) 694 // ]NOCPP] 695 ); 696 currentPtr++; 697 stack[currentPtr] = node; 698 if ("template" == contextName) { 699 pushTemplateMode(IN_TEMPLATE); 700 } 701 resetTheInsertionMode(); 702 formPointer = getFormPointerForContext(contextNode); 703 if ("title" == contextName || "textarea" == contextName) { 704 tokenizer.setState(Tokenizer.RCDATA); 705 } else if ("style" == contextName || "xmp" == contextName 706 || "iframe" == contextName || "noembed" == contextName 707 || "noframes" == contextName 708 || (scriptingEnabled && "noscript" == contextName)) { 709 tokenizer.setState(Tokenizer.RAWTEXT); 710 } else if ("plaintext" == contextName) { 711 tokenizer.setState(Tokenizer.PLAINTEXT); 712 } else if ("script" == contextName) { 713 tokenizer.setState(Tokenizer.SCRIPT_DATA); 714 } else { 715 tokenizer.setState(Tokenizer.DATA); 716 } 717 } 718 } else { 719 mode = INITIAL; 720 // If we are viewing XML source, put a foreign element permanently 721 // on the stack so that cdataSectionAllowed() returns true. 722 // CPPONLY: if (tokenizer.isViewingXmlSource()) { 723 // CPPONLY: T elt = createElement("http://www.w3.org/2000/svg", 724 // CPPONLY: "svg", 725 // CPPONLY: tokenizer.emptyAttributes(), null, 726 // CPPONLY: svgCreator(NS_NewSVGSVGElement)); 727 // CPPONLY: StackNode<T> node = createStackNode(ElementName.SVG, 728 // CPPONLY: "svg", 729 // CPPONLY: elt); 730 // CPPONLY: currentPtr++; 731 // CPPONLY: stack[currentPtr] = node; 732 // CPPONLY: } 733 } 734 } 735 736 public final void doctype(@Local String name, String publicIdentifier, 737 String systemIdentifier, boolean forceQuirks) throws SAXException { 738 needToDropLF = false; 739 if (!isInForeign() && mode == INITIAL) { 740 // [NOCPP[ 741 if (reportingDoctype) { 742 // ]NOCPP] 743 String emptyString = Portability.newEmptyString(); 744 appendDoctypeToDocument(name == null ? "" : name, 745 publicIdentifier == null ? emptyString 746 : publicIdentifier, 747 systemIdentifier == null ? emptyString 748 : systemIdentifier); 749 Portability.releaseString(emptyString); 750 // [NOCPP[ 751 } 752 // ]NOCPP] 753 if (isQuirky(name, publicIdentifier, systemIdentifier, 754 forceQuirks)) { 755 errQuirkyDoctype(); 756 documentModeInternal(DocumentMode.QUIRKS_MODE, 757 publicIdentifier, systemIdentifier); 758 } else if (isAlmostStandards(publicIdentifier, 759 systemIdentifier)) { 760 errAlmostStandardsDoctype(); 761 documentModeInternal( 762 DocumentMode.ALMOST_STANDARDS_MODE, 763 publicIdentifier, systemIdentifier); 764 } else { 765 // [NOCPP[ 766 if ((Portability.literalEqualsString( 767 "-//W3C//DTD HTML 4.0//EN", publicIdentifier) && (systemIdentifier == null || Portability.literalEqualsString( 768 "http://www.w3.org/TR/REC-html40/strict.dtd", 769 systemIdentifier))) 770 || (Portability.literalEqualsString( 771 "-//W3C//DTD HTML 4.01//EN", 772 publicIdentifier) && (systemIdentifier == null || Portability.literalEqualsString( 773 "http://www.w3.org/TR/html4/strict.dtd", 774 systemIdentifier))) 775 || (Portability.literalEqualsString( 776 "-//W3C//DTD XHTML 1.0 Strict//EN", 777 publicIdentifier) && Portability.literalEqualsString( 778 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd", 779 systemIdentifier)) 780 || (Portability.literalEqualsString( 781 "-//W3C//DTD XHTML 1.1//EN", 782 publicIdentifier) && Portability.literalEqualsString( 783 "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd", 784 systemIdentifier)) 785 786 ) { 787 err("Obsolete doctype. Expected \u201C<!DOCTYPE html>\u201D."); 788 } else if (!((systemIdentifier == null || Portability.literalEqualsString( 789 "about:legacy-compat", systemIdentifier)) && publicIdentifier == null)) { 790 err("Legacy doctype. Expected \u201C<!DOCTYPE html>\u201D."); 791 } 792 // ]NOCPP] 793 documentModeInternal(DocumentMode.STANDARDS_MODE, 794 publicIdentifier, systemIdentifier); 795 } 796 797 /* 798 * 799 * Then, switch to the root element mode of the tree construction 800 * stage. 801 */ 802 mode = BEFORE_HTML; 803 return; 804 } 805 /* 806 * A DOCTYPE token Parse error. 807 */ 808 errStrayDoctype(); 809 /* 810 * Ignore the token. 811 */ 812 return; 813 } 814 815 public final void comment(@NoLength char[] buf, int start, int length) 816 throws SAXException { 817 needToDropLF = false; 818 // [NOCPP[ 819 if (!wantingComments) { 820 return; 821 } 822 // ]NOCPP] 823 if (!isInForeign()) { 824 switch (mode) { 825 case INITIAL: 826 case BEFORE_HTML: 827 case AFTER_AFTER_BODY: 828 case AFTER_AFTER_FRAMESET: 829 /* 830 * A comment token Append a Comment node to the Document 831 * object with the data attribute set to the data given in 832 * the comment token. 833 */ 834 appendCommentToDocument(buf, start, length); 835 return; 836 case AFTER_BODY: 837 /* 838 * A comment token Append a Comment node to the first 839 * element in the stack of open elements (the html element), 840 * with the data attribute set to the data given in the 841 * comment token. 842 */ 843 flushCharacters(); 844 appendComment(stack[0].node, buf, start, length); 845 return; 846 default: 847 break; 848 } 849 } 850 /* 851 * A comment token Append a Comment node to the current node with the 852 * data attribute set to the data given in the comment token. 853 */ 854 flushCharacters(); 855 appendComment(stack[currentPtr].node, buf, start, length); 856 return; 857 } 858 859 /** 860 * @see nu.validator.htmlparser.common.TokenHandler#characters(char[], int, 861 * int) 862 */ 863 public final void characters(@Const @NoLength char[] buf, int start, int length) 864 throws SAXException { 865 // Note: Can't attach error messages to EOF in C++ yet 866 867 // CPPONLY: if (tokenizer.isViewingXmlSource()) { 868 // CPPONLY: return; 869 // CPPONLY: } 870 if (needToDropLF) { 871 needToDropLF = false; 872 if (buf[start] == '\n') { 873 start++; 874 length--; 875 if (length == 0) { 876 return; 877 } 878 } 879 } 880 881 // optimize the most common case 882 switch (mode) { 883 case IN_BODY: 884 case IN_CELL: 885 case IN_CAPTION: 886 if (!isInForeignButNotHtmlOrMathTextIntegrationPoint()) { 887 reconstructTheActiveFormattingElements(); 888 } 889 // CPPONLY: MOZ_FALLTHROUGH; 890 case TEXT: 891 accumulateCharacters(buf, start, length); 892 return; 893 case IN_TABLE: 894 case IN_TABLE_BODY: 895 case IN_ROW: 896 accumulateCharactersForced(buf, start, length); 897 return; 898 default: 899 int end = start + length; 900 charactersloop: for (int i = start; i < end; i++) { 901 switch (buf[i]) { 902 case ' ': 903 case '\t': 904 case '\n': 905 case '\r': 906 case '\u000C': 907 /* 908 * A character token that is one of one of U+0009 909 * CHARACTER TABULATION, U+000A LINE FEED (LF), 910 * U+000C FORM FEED (FF), or U+0020 SPACE 911 */ 912 switch (mode) { 913 case INITIAL: 914 case BEFORE_HTML: 915 case BEFORE_HEAD: 916 /* 917 * Ignore the token. 918 */ 919 start = i + 1; 920 continue; 921 case IN_HEAD: 922 case IN_HEAD_NOSCRIPT: 923 case AFTER_HEAD: 924 case IN_COLUMN_GROUP: 925 case IN_FRAMESET: 926 case AFTER_FRAMESET: 927 /* 928 * Append the character to the current node. 929 */ 930 continue; 931 case FRAMESET_OK: 932 case IN_TEMPLATE: 933 case IN_BODY: 934 case IN_CELL: 935 case IN_CAPTION: 936 if (start < i) { 937 accumulateCharacters(buf, start, i 938 - start); 939 start = i; 940 } 941 942 /* 943 * Reconstruct the active formatting 944 * elements, if any. 945 */ 946 if (!isInForeignButNotHtmlOrMathTextIntegrationPoint()) { 947 flushCharacters(); 948 reconstructTheActiveFormattingElements(); 949 } 950 /* 951 * Append the token's character to the 952 * current node. 953 */ 954 break charactersloop; 955 case IN_SELECT: 956 case IN_SELECT_IN_TABLE: 957 break charactersloop; 958 case IN_TABLE: 959 case IN_TABLE_BODY: 960 case IN_ROW: 961 accumulateCharactersForced(buf, i, 1); 962 start = i + 1; 963 continue; 964 case AFTER_BODY: 965 case AFTER_AFTER_BODY: 966 case AFTER_AFTER_FRAMESET: 967 if (start < i) { 968 accumulateCharacters(buf, start, i 969 - start); 970 start = i; 971 } 972 /* 973 * Reconstruct the active formatting 974 * elements, if any. 975 */ 976 flushCharacters(); 977 reconstructTheActiveFormattingElements(); 978 /* 979 * Append the token's character to the 980 * current node. 981 */ 982 continue; 983 } 984 // CPPONLY: MOZ_FALLTHROUGH_ASSERT(); 985 default: 986 /* 987 * A character token that is not one of one of 988 * U+0009 CHARACTER TABULATION, U+000A LINE FEED 989 * (LF), U+000C FORM FEED (FF), or U+0020 SPACE 990 */ 991 switch (mode) { 992 case INITIAL: 993 /* 994 * Parse error. 995 */ 996 // [NOCPP[ 997 // XXX figure out a way to report this in the Gecko View Source case 998 err("Non-space characters found without seeing a doctype first. Expected \u201C<!DOCTYPE html>\u201D."); 999 // ]NOCPP] 1000 /* 1001 * 1002 * Set the document to quirks mode. 1003 */ 1004 documentModeInternal( 1005 DocumentMode.QUIRKS_MODE, null, 1006 null); 1007 /* 1008 * Then, switch to the root element mode of 1009 * the tree construction stage 1010 */ 1011 mode = BEFORE_HTML; 1012 /* 1013 * and reprocess the current token. 1014 */ 1015 i--; 1016 continue; 1017 case BEFORE_HTML: 1018 /* 1019 * Create an HTMLElement node with the tag 1020 * name html, in the HTML namespace. Append 1021 * it to the Document object. 1022 */ 1023 // No need to flush characters here, 1024 // because there's nothing to flush. 1025 appendHtmlElementToDocumentAndPush(); 1026 /* Switch to the main mode */ 1027 mode = BEFORE_HEAD; 1028 /* 1029 * reprocess the current token. 1030 */ 1031 i--; 1032 continue; 1033 case BEFORE_HEAD: 1034 if (start < i) { 1035 accumulateCharacters(buf, start, i 1036 - start); 1037 start = i; 1038 } 1039 /* 1040 * /Act as if a start tag token with the tag 1041 * name "head" and no attributes had been 1042 * seen, 1043 */ 1044 flushCharacters(); 1045 appendToCurrentNodeAndPushHeadElement(HtmlAttributes.EMPTY_ATTRIBUTES); 1046 mode = IN_HEAD; 1047 /* 1048 * then reprocess the current token. 1049 * 1050 * This will result in an empty head element 1051 * being generated, with the current token 1052 * being reprocessed in the "after head" 1053 * insertion mode. 1054 */ 1055 i--; 1056 continue; 1057 case IN_HEAD: 1058 if (start < i) { 1059 accumulateCharacters(buf, start, i 1060 - start); 1061 start = i; 1062 } 1063 /* 1064 * Act as if an end tag token with the tag 1065 * name "head" had been seen, 1066 */ 1067 flushCharacters(); 1068 pop(); 1069 mode = AFTER_HEAD; 1070 /* 1071 * and reprocess the current token. 1072 */ 1073 i--; 1074 continue; 1075 case IN_HEAD_NOSCRIPT: 1076 if (start < i) { 1077 accumulateCharacters(buf, start, i 1078 - start); 1079 start = i; 1080 } 1081 /* 1082 * Parse error. Act as if an end tag with 1083 * the tag name "noscript" had been seen 1084 */ 1085 errNonSpaceInNoscriptInHead(); 1086 flushCharacters(); 1087 pop(); 1088 mode = IN_HEAD; 1089 /* 1090 * and reprocess the current token. 1091 */ 1092 i--; 1093 continue; 1094 case AFTER_HEAD: 1095 if (start < i) { 1096 accumulateCharacters(buf, start, i 1097 - start); 1098 start = i; 1099 } 1100 /* 1101 * Act as if a start tag token with the tag 1102 * name "body" and no attributes had been 1103 * seen, 1104 */ 1105 flushCharacters(); 1106 appendToCurrentNodeAndPushBodyElement(); 1107 mode = FRAMESET_OK; 1108 /* 1109 * and then reprocess the current token. 1110 */ 1111 i--; 1112 continue; 1113 case FRAMESET_OK: 1114 framesetOk = false; 1115 mode = IN_BODY; 1116 i--; 1117 continue; 1118 case IN_TEMPLATE: 1119 case IN_BODY: 1120 case IN_CELL: 1121 case IN_CAPTION: 1122 if (start < i) { 1123 accumulateCharacters(buf, start, i 1124 - start); 1125 start = i; 1126 } 1127 /* 1128 * Reconstruct the active formatting 1129 * elements, if any. 1130 */ 1131 if (!isInForeignButNotHtmlOrMathTextIntegrationPoint()) { 1132 flushCharacters(); 1133 reconstructTheActiveFormattingElements(); 1134 } 1135 /* 1136 * Append the token's character to the 1137 * current node. 1138 */ 1139 break charactersloop; 1140 case IN_TABLE: 1141 case IN_TABLE_BODY: 1142 case IN_ROW: 1143 accumulateCharactersForced(buf, i, 1); 1144 start = i + 1; 1145 continue; 1146 case IN_COLUMN_GROUP: 1147 if (start < i) { 1148 accumulateCharacters(buf, start, i 1149 - start); 1150 start = i; 1151 } 1152 /* 1153 * Act as if an end tag with the tag name 1154 * "colgroup" had been seen, and then, if 1155 * that token wasn't ignored, reprocess the 1156 * current token. 1157 */ 1158 if (currentPtr == 0 || stack[currentPtr].getGroup() == 1159 TreeBuilder.TEMPLATE) { 1160 errNonSpaceInColgroupInFragment(); 1161 start = i + 1; 1162 continue; 1163 } 1164 flushCharacters(); 1165 pop(); 1166 mode = IN_TABLE; 1167 i--; 1168 continue; 1169 case IN_SELECT: 1170 case IN_SELECT_IN_TABLE: 1171 break charactersloop; 1172 case AFTER_BODY: 1173 errNonSpaceAfterBody(); 1174 fatal(); 1175 mode = framesetOk ? FRAMESET_OK : IN_BODY; 1176 i--; 1177 continue; 1178 case IN_FRAMESET: 1179 if (start < i) { 1180 accumulateCharacters(buf, start, i 1181 - start); 1182 // start index is adjusted below. 1183 } 1184 /* 1185 * Parse error. 1186 */ 1187 errNonSpaceInFrameset(); 1188 /* 1189 * Ignore the token. 1190 */ 1191 start = i + 1; 1192 continue; 1193 case AFTER_FRAMESET: 1194 if (start < i) { 1195 accumulateCharacters(buf, start, i 1196 - start); 1197 // start index is adjusted below. 1198 } 1199 /* 1200 * Parse error. 1201 */ 1202 errNonSpaceAfterFrameset(); 1203 /* 1204 * Ignore the token. 1205 */ 1206 start = i + 1; 1207 continue; 1208 case AFTER_AFTER_BODY: 1209 /* 1210 * Parse error. 1211 */ 1212 errNonSpaceInTrailer(); 1213 /* 1214 * Switch back to the main mode and 1215 * reprocess the token. 1216 */ 1217 mode = framesetOk ? FRAMESET_OK : IN_BODY; 1218 i--; 1219 continue; 1220 case AFTER_AFTER_FRAMESET: 1221 if (start < i) { 1222 accumulateCharacters(buf, start, i 1223 - start); 1224 // start index is adjusted below. 1225 } 1226 /* 1227 * Parse error. 1228 */ 1229 errNonSpaceInTrailer(); 1230 /* 1231 * Ignore the token. 1232 */ 1233 start = i + 1; 1234 continue; 1235 } 1236 } 1237 } 1238 if (start < end) { 1239 accumulateCharacters(buf, start, end - start); 1240 } 1241 } 1242 } 1243 1244 /** 1245 * @see nu.validator.htmlparser.common.TokenHandler#zeroOriginatingReplacementCharacter() 1246 */ 1247 public void zeroOriginatingReplacementCharacter() throws SAXException { 1248 if (mode == TEXT) { 1249 accumulateCharacters(REPLACEMENT_CHARACTER, 0, 1); 1250 return; 1251 } 1252 if (currentPtr >= 0) { 1253 if (isSpecialParentInForeign(stack[currentPtr])) { 1254 return; 1255 } 1256 accumulateCharacters(REPLACEMENT_CHARACTER, 0, 1); 1257 } 1258 } 1259 1260 /** 1261 * @see nu.validator.htmlparser.common.TokenHandler#zeroOrReplacementCharacter() 1262 */ 1263 public void zeroOrReplacementCharacter() throws SAXException { 1264 zeroOriginatingReplacementCharacter(); 1265 } 1266 1267 public final void eof() throws SAXException { 1268 flushCharacters(); 1269 // Note: Can't attach error messages to EOF in C++ yet 1270 eofloop: for (;;) { 1271 switch (mode) { 1272 case INITIAL: 1273 /* 1274 * Parse error. 1275 */ 1276 // [NOCPP[ 1277 err("End of file seen without seeing a doctype first. Expected \u201C<!DOCTYPE html>\u201D."); 1278 // ]NOCPP] 1279 /* 1280 * 1281 * Set the document to quirks mode. 1282 */ 1283 documentModeInternal(DocumentMode.QUIRKS_MODE, null, null); 1284 /* 1285 * Then, switch to the root element mode of the tree 1286 * construction stage 1287 */ 1288 mode = BEFORE_HTML; 1289 /* 1290 * and reprocess the current token. 1291 */ 1292 continue; 1293 case BEFORE_HTML: 1294 /* 1295 * Create an HTMLElement node with the tag name html, in the 1296 * HTML namespace. Append it to the Document object. 1297 */ 1298 appendHtmlElementToDocumentAndPush(); 1299 // XXX application cache manifest 1300 /* Switch to the main mode */ 1301 mode = BEFORE_HEAD; 1302 /* 1303 * reprocess the current token. 1304 */ 1305 continue; 1306 case BEFORE_HEAD: 1307 appendToCurrentNodeAndPushHeadElement(HtmlAttributes.EMPTY_ATTRIBUTES); 1308 mode = IN_HEAD; 1309 continue; 1310 case IN_HEAD: 1311 // [NOCPP[ 1312 if (errorHandler != null && currentPtr > 1) { 1313 errEofWithUnclosedElements(); 1314 } 1315 // ]NOCPP] 1316 while (currentPtr > 0) { 1317 popOnEof(); 1318 } 1319 mode = AFTER_HEAD; 1320 continue; 1321 case IN_HEAD_NOSCRIPT: 1322 // [NOCPP[ 1323 errEofWithUnclosedElements(); 1324 // ]NOCPP] 1325 while (currentPtr > 1) { 1326 popOnEof(); 1327 } 1328 mode = IN_HEAD; 1329 continue; 1330 case AFTER_HEAD: 1331 appendToCurrentNodeAndPushBodyElement(); 1332 mode = IN_BODY; 1333 continue; 1334 case IN_TABLE_BODY: 1335 case IN_ROW: 1336 case IN_TABLE: 1337 case IN_SELECT_IN_TABLE: 1338 case IN_SELECT: 1339 case IN_COLUMN_GROUP: 1340 case FRAMESET_OK: 1341 case IN_CAPTION: 1342 case IN_CELL: 1343 case IN_BODY: 1344 // [NOCPP[ 1345 // i > 0 to stop in time in the foreign fragment case. 1346 openelementloop: for (int i = currentPtr; i > 0; i--) { 1347 int group = stack[i].getGroup(); 1348 switch (group) { 1349 case DD_OR_DT: 1350 case LI: 1351 case P: 1352 case TBODY_OR_THEAD_OR_TFOOT: 1353 case TD_OR_TH: 1354 case BODY: 1355 case HTML: 1356 break; 1357 default: 1358 errEofWithUnclosedElements(); 1359 break openelementloop; 1360 } 1361 } 1362 // ]NOCPP] 1363 1364 if (isTemplateModeStackEmpty()) { 1365 break eofloop; 1366 } 1367 1368 // fall through to IN_TEMPLATE 1369 // CPPONLY: MOZ_FALLTHROUGH; 1370 case IN_TEMPLATE: 1371 int eltPos = findLast("template"); 1372 if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { 1373 assert fragment; 1374 break eofloop; 1375 } 1376 if (errorHandler != null) { 1377 errListUnclosedStartTags(0); 1378 } 1379 while (currentPtr >= eltPos) { 1380 pop(); 1381 } 1382 clearTheListOfActiveFormattingElementsUpToTheLastMarker(); 1383 popTemplateMode(); 1384 resetTheInsertionMode(); 1385 1386 // Reprocess token. 1387 continue; 1388 case TEXT: 1389 // [NOCPP[ 1390 if (errorHandler != null) { 1391 errNoCheck("End of file seen when expecting text or an end tag."); 1392 errListUnclosedStartTags(0); 1393 } 1394 // ]NOCPP] 1395 // XXX mark script as already executed 1396 if (originalMode == AFTER_HEAD) { 1397 popOnEof(); 1398 } 1399 popOnEof(); 1400 mode = originalMode; 1401 continue; 1402 case IN_FRAMESET: 1403 // [NOCPP[ 1404 if (errorHandler != null && currentPtr > 0) { 1405 errEofWithUnclosedElements(); 1406 } 1407 // ]NOCPP] 1408 break eofloop; 1409 case AFTER_BODY: 1410 case AFTER_FRAMESET: 1411 case AFTER_AFTER_BODY: 1412 case AFTER_AFTER_FRAMESET: 1413 default: 1414 // [NOCPP[ 1415 if (currentPtr == 0) { // This silliness is here to poison 1416 // buggy compiler optimizations in 1417 // GWT 1418 System.currentTimeMillis(); 1419 } 1420 // ]NOCPP] 1421 break eofloop; 1422 } 1423 } 1424 while (currentPtr > 0) { 1425 popOnEof(); 1426 } 1427 if (!fragment) { 1428 popOnEof(); 1429 } 1430 /* Stop parsing. */ 1431 } 1432 1433 /** 1434 * @see nu.validator.htmlparser.common.TokenHandler#endTokenization() 1435 */ 1436 public final void endTokenization() throws SAXException { 1437 formPointer = null; 1438 headPointer = null; 1439 contextName = null; 1440 contextNode = null; 1441 templateModeStack = null; 1442 if (stack != null) { 1443 while (currentPtr > -1) { 1444 stack[currentPtr].release(this); 1445 currentPtr--; 1446 } 1447 stack = null; 1448 } 1449 if (listOfActiveFormattingElements != null) { 1450 while (listPtr > -1) { 1451 if (listOfActiveFormattingElements[listPtr] != null) { 1452 listOfActiveFormattingElements[listPtr].release(this); 1453 } 1454 listPtr--; 1455 } 1456 listOfActiveFormattingElements = null; 1457 } 1458 if (stackNodes != null) { 1459 for (int i = 0; i < numStackNodes; i++) { 1460 assert stackNodes[i].isUnused(); 1461 Portability.delete(stackNodes[i]); 1462 } 1463 numStackNodes = 0; 1464 stackNodesIdx = 0; 1465 stackNodes = null; 1466 } 1467 // [NOCPP[ 1468 idLocations.clear(); 1469 // ]NOCPP] 1470 1471 if (!keepBuffer) { 1472 charBuffer = null; 1473 } 1474 end(); 1475 } 1476 1477 public final void startTag(ElementName elementName, 1478 HtmlAttributes attributes, boolean selfClosing) throws SAXException { 1479 flushCharacters(); 1480 1481 // [NOCPP[ 1482 boolean wasSelfClosing = selfClosing; 1483 boolean voidElement = false; 1484 if (errorHandler != null) { 1485 // ID uniqueness 1486 @IdType String id = attributes.getId(); 1487 if (id != null && !isTemplateContents()) { 1488 LocatorImpl oldLoc = idLocations.get(id); 1489 if (oldLoc != null) { 1490 err("Duplicate ID \u201C" + id + "\u201D."); 1491 errorHandler.warning(new SAXParseException( 1492 "The first occurrence of ID \u201C" + id 1493 + "\u201D was here.", oldLoc)); 1494 } else { 1495 idLocations.put(id, new LocatorImpl(tokenizer)); 1496 } 1497 } 1498 } 1499 // ]NOCPP] 1500 1501 int eltPos; 1502 needToDropLF = false; 1503 starttagloop: for (;;) { 1504 int group = elementName.getGroup(); 1505 @Local String name = elementName.getName(); 1506 if (isInForeign()) { 1507 StackNode<T> currentNode = stack[currentPtr]; 1508 @NsUri String currNs = currentNode.ns; 1509 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))))) { 1510 switch (group) { 1511 case B_OR_BIG_OR_CODE_OR_EM_OR_I_OR_S_OR_SMALL_OR_STRIKE_OR_STRONG_OR_TT_OR_U: 1512 case DIV_OR_BLOCKQUOTE_OR_CENTER_OR_MENU: 1513 case BODY: 1514 case BR: 1515 case RUBY_OR_SPAN_OR_SUB_OR_SUP_OR_VAR: 1516 case DD_OR_DT: 1517 case UL_OR_OL_OR_DL: 1518 case EMBED: 1519 case IMG: 1520 case H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6: 1521 case HEAD: 1522 case HR: 1523 case LI: 1524 case META: 1525 case NOBR: 1526 case P: 1527 case PRE_OR_LISTING: 1528 case TABLE: 1529 case FONT: 1530 // re-check FONT to deal with the special case 1531 if (!(group == FONT && !(attributes.contains(AttributeName.COLOR) 1532 || attributes.contains(AttributeName.FACE) || attributes.contains(AttributeName.SIZE)))) { 1533 errHtmlStartTagInForeignContext(name); 1534 if (!fragment) { 1535 while (!isSpecialParentInForeign(stack[currentPtr])) { 1536 popForeign(-1, -1); 1537 } 1538 continue starttagloop; 1539 } // else fall thru 1540 } 1541 // CPPONLY: MOZ_FALLTHROUGH; 1542 default: 1543 if ("http://www.w3.org/2000/svg" == currNs) { 1544 attributes.adjustForSvg(); 1545 if (selfClosing) { 1546 appendVoidElementToCurrentMayFosterSVG( 1547 elementName, attributes); 1548 selfClosing = false; 1549 } else { 1550 appendToCurrentNodeAndPushElementMayFosterSVG( 1551 elementName, attributes); 1552 } 1553 attributes = null; // CPP 1554 break starttagloop; 1555 } else { 1556 attributes.adjustForMath(); 1557 if (selfClosing) { 1558 appendVoidElementToCurrentMayFosterMathML( 1559 elementName, attributes); 1560 selfClosing = false; 1561 } else { 1562 appendToCurrentNodeAndPushElementMayFosterMathML( 1563 elementName, attributes); 1564 } 1565 attributes = null; // CPP 1566 break starttagloop; 1567 } 1568 } // switch 1569 } // foreignObject / annotation-xml 1570 } 1571 switch (mode) { 1572 case IN_TEMPLATE: 1573 switch (group) { 1574 case COL: 1575 popTemplateMode(); 1576 pushTemplateMode(IN_COLUMN_GROUP); 1577 mode = IN_COLUMN_GROUP; 1578 // Reprocess token. 1579 continue; 1580 case CAPTION: 1581 case COLGROUP: 1582 case TBODY_OR_THEAD_OR_TFOOT: 1583 popTemplateMode(); 1584 pushTemplateMode(IN_TABLE); 1585 mode = IN_TABLE; 1586 // Reprocess token. 1587 continue; 1588 case TR: 1589 popTemplateMode(); 1590 pushTemplateMode(IN_TABLE_BODY); 1591 mode = IN_TABLE_BODY; 1592 // Reprocess token. 1593 continue; 1594 case TD_OR_TH: 1595 popTemplateMode(); 1596 pushTemplateMode(IN_ROW); 1597 mode = IN_ROW; 1598 // Reprocess token. 1599 continue; 1600 case META: 1601 checkMetaCharset(attributes); 1602 appendVoidElementToCurrentMayFoster( 1603 elementName, 1604 attributes); 1605 selfClosing = false; 1606 // [NOCPP[ 1607 voidElement = true; 1608 // ]NOCPP] 1609 attributes = null; // CPP 1610 break starttagloop; 1611 case TITLE: 1612 startTagTitleInHead(elementName, attributes); 1613 attributes = null; // CPP 1614 break starttagloop; 1615 case BASE: 1616 case LINK_OR_BASEFONT_OR_BGSOUND: 1617 appendVoidElementToCurrentMayFoster( 1618 elementName, 1619 attributes); 1620 selfClosing = false; 1621 // [NOCPP[ 1622 voidElement = true; 1623 // ]NOCPP] 1624 attributes = null; // CPP 1625 break starttagloop; 1626 case SCRIPT: 1627 startTagScriptInHead(elementName, attributes); 1628 attributes = null; // CPP 1629 break starttagloop; 1630 case NOFRAMES: 1631 case STYLE: 1632 startTagGenericRawText(elementName, attributes); 1633 attributes = null; // CPP 1634 break starttagloop; 1635 case TEMPLATE: 1636 startTagTemplateInHead(elementName, attributes); 1637 attributes = null; // CPP 1638 break starttagloop; 1639 default: 1640 popTemplateMode(); 1641 pushTemplateMode(IN_BODY); 1642 mode = IN_BODY; 1643 // Reprocess token. 1644 continue; 1645 } 1646 case IN_ROW: 1647 switch (group) { 1648 case TD_OR_TH: 1649 clearStackBackTo(findLastOrRoot(TreeBuilder.TR)); 1650 appendToCurrentNodeAndPushElement( 1651 elementName, 1652 attributes); 1653 mode = IN_CELL; 1654 insertMarker(); 1655 attributes = null; // CPP 1656 break starttagloop; 1657 case CAPTION: 1658 case COL: 1659 case COLGROUP: 1660 case TBODY_OR_THEAD_OR_TFOOT: 1661 case TR: 1662 eltPos = findLastOrRoot(TreeBuilder.TR); 1663 if (eltPos == 0) { 1664 assert fragment || isTemplateContents(); 1665 errNoTableRowToClose(); 1666 break starttagloop; 1667 } 1668 clearStackBackTo(eltPos); 1669 pop(); 1670 mode = IN_TABLE_BODY; 1671 continue; 1672 default: 1673 // fall through to IN_TABLE 1674 } 1675 // CPPONLY: MOZ_FALLTHROUGH; 1676 case IN_TABLE_BODY: 1677 switch (group) { 1678 case TR: 1679 clearStackBackTo(findLastInTableScopeOrRootTemplateTbodyTheadTfoot()); 1680 appendToCurrentNodeAndPushElement( 1681 elementName, 1682 attributes); 1683 mode = IN_ROW; 1684 attributes = null; // CPP 1685 break starttagloop; 1686 case TD_OR_TH: 1687 errStartTagInTableBody(name); 1688 clearStackBackTo(findLastInTableScopeOrRootTemplateTbodyTheadTfoot()); 1689 appendToCurrentNodeAndPushElement( 1690 ElementName.TR, 1691 HtmlAttributes.EMPTY_ATTRIBUTES); 1692 mode = IN_ROW; 1693 continue; 1694 case CAPTION: 1695 case COL: 1696 case COLGROUP: 1697 case TBODY_OR_THEAD_OR_TFOOT: 1698 eltPos = findLastInTableScopeOrRootTemplateTbodyTheadTfoot(); 1699 if (eltPos == 0 || stack[eltPos].getGroup() == TEMPLATE) { 1700 assert fragment || isTemplateContents(); 1701 errStrayStartTag(name); 1702 break starttagloop; 1703 } else { 1704 clearStackBackTo(eltPos); 1705 pop(); 1706 mode = IN_TABLE; 1707 continue; 1708 } 1709 default: 1710 // fall through to IN_TABLE 1711 } 1712 // CPPONLY: MOZ_FALLTHROUGH; 1713 case IN_TABLE: 1714 intableloop: for (;;) { 1715 switch (group) { 1716 case CAPTION: 1717 clearStackBackTo(findLastOrRoot(TreeBuilder.TABLE)); 1718 insertMarker(); 1719 appendToCurrentNodeAndPushElement( 1720 elementName, 1721 attributes); 1722 mode = IN_CAPTION; 1723 attributes = null; // CPP 1724 break starttagloop; 1725 case COLGROUP: 1726 clearStackBackTo(findLastOrRoot(TreeBuilder.TABLE)); 1727 appendToCurrentNodeAndPushElement( 1728 elementName, 1729 attributes); 1730 mode = IN_COLUMN_GROUP; 1731 attributes = null; // CPP 1732 break starttagloop; 1733 case COL: 1734 clearStackBackTo(findLastOrRoot(TreeBuilder.TABLE)); 1735 appendToCurrentNodeAndPushElement( 1736 ElementName.COLGROUP, 1737 HtmlAttributes.EMPTY_ATTRIBUTES); 1738 mode = IN_COLUMN_GROUP; 1739 continue starttagloop; 1740 case TBODY_OR_THEAD_OR_TFOOT: 1741 clearStackBackTo(findLastOrRoot(TreeBuilder.TABLE)); 1742 appendToCurrentNodeAndPushElement( 1743 elementName, 1744 attributes); 1745 mode = IN_TABLE_BODY; 1746 attributes = null; // CPP 1747 break starttagloop; 1748 case TR: 1749 case TD_OR_TH: 1750 clearStackBackTo(findLastOrRoot(TreeBuilder.TABLE)); 1751 appendToCurrentNodeAndPushElement( 1752 ElementName.TBODY, 1753 HtmlAttributes.EMPTY_ATTRIBUTES); 1754 mode = IN_TABLE_BODY; 1755 continue starttagloop; 1756 case TEMPLATE: 1757 // fall through to IN_HEAD 1758 break intableloop; 1759 case TABLE: 1760 errTableSeenWhileTableOpen(); 1761 eltPos = findLastInTableScope(name); 1762 if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { 1763 assert fragment || isTemplateContents(); 1764 break starttagloop; 1765 } 1766 generateImpliedEndTags(); 1767 if (errorHandler != null && !isCurrent("table")) { 1768 errNoCheckUnclosedElementsOnStack(); 1769 } 1770 while (currentPtr >= eltPos) { 1771 pop(); 1772 } 1773 resetTheInsertionMode(); 1774 continue starttagloop; 1775 case SCRIPT: 1776 // XXX need to manage much more stuff 1777 // here if 1778 // supporting 1779 // document.write() 1780 appendToCurrentNodeAndPushElement( 1781 elementName, 1782 attributes); 1783 originalMode = mode; 1784 mode = TEXT; 1785 tokenizer.setStateAndEndTagExpectation( 1786 Tokenizer.SCRIPT_DATA, elementName); 1787 attributes = null; // CPP 1788 break starttagloop; 1789 case STYLE: 1790 appendToCurrentNodeAndPushElement( 1791 elementName, 1792 attributes); 1793 originalMode = mode; 1794 mode = TEXT; 1795 tokenizer.setStateAndEndTagExpectation( 1796 Tokenizer.RAWTEXT, elementName); 1797 attributes = null; // CPP 1798 break starttagloop; 1799 case INPUT: 1800 errStartTagInTable(name); 1801 if (!Portability.lowerCaseLiteralEqualsIgnoreAsciiCaseString( 1802 "hidden", 1803 attributes.getValue(AttributeName.TYPE))) { 1804 break intableloop; 1805 } 1806 appendVoidInputToCurrent( 1807 attributes, 1808 formPointer); 1809 selfClosing = false; 1810 // [NOCPP[ 1811 voidElement = true; 1812 // ]NOCPP] 1813 attributes = null; // CPP 1814 break starttagloop; 1815 case FORM: 1816 if (formPointer != null || isTemplateContents()) { 1817 errFormWhenFormOpen(); 1818 break starttagloop; 1819 } else { 1820 errStartTagInTable(name); 1821 appendVoidFormToCurrent(attributes); 1822 attributes = null; // CPP 1823 break starttagloop; 1824 } 1825 default: 1826 errStartTagInTable(name); 1827 // fall through to IN_BODY 1828 break intableloop; 1829 } 1830 } 1831 // CPPONLY: MOZ_FALLTHROUGH; 1832 case IN_CAPTION: 1833 switch (group) { 1834 case CAPTION: 1835 case COL: 1836 case COLGROUP: 1837 case TBODY_OR_THEAD_OR_TFOOT: 1838 case TR: 1839 case TD_OR_TH: 1840 eltPos = findLastInTableScope("caption"); 1841 if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { 1842 assert fragment || isTemplateContents(); 1843 errStrayStartTag(name); 1844 break starttagloop; 1845 } 1846 generateImpliedEndTags(); 1847 if (errorHandler != null && currentPtr != eltPos) { 1848 errNoCheckUnclosedElementsOnStack(); 1849 } 1850 while (currentPtr >= eltPos) { 1851 pop(); 1852 } 1853 clearTheListOfActiveFormattingElementsUpToTheLastMarker(); 1854 mode = IN_TABLE; 1855 continue; 1856 default: 1857 // fall through to IN_BODY 1858 } 1859 // CPPONLY: MOZ_FALLTHROUGH; 1860 case IN_CELL: 1861 switch (group) { 1862 case CAPTION: 1863 case COL: 1864 case COLGROUP: 1865 case TBODY_OR_THEAD_OR_TFOOT: 1866 case TR: 1867 case TD_OR_TH: 1868 eltPos = findLastInTableScopeTdTh(); 1869 if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { 1870 errNoCellToClose(); 1871 break starttagloop; 1872 } else { 1873 closeTheCell(eltPos); 1874 continue; 1875 } 1876 default: 1877 // fall through to IN_BODY 1878 } 1879 // CPPONLY: MOZ_FALLTHROUGH; 1880 case FRAMESET_OK: 1881 switch (group) { 1882 case FRAMESET: 1883 if (mode == FRAMESET_OK) { 1884 if (currentPtr == 0 || stack[1].getGroup() != BODY) { 1885 assert fragment || isTemplateContents(); 1886 errStrayStartTag(name); 1887 break starttagloop; 1888 } else { 1889 errFramesetStart(); 1890 detachFromParent(stack[1].node); 1891 while (currentPtr > 0) { 1892 pop(); 1893 } 1894 appendToCurrentNodeAndPushElement( 1895 elementName, 1896 attributes); 1897 mode = IN_FRAMESET; 1898 attributes = null; // CPP 1899 break starttagloop; 1900 } 1901 } else { 1902 errStrayStartTag(name); 1903 break starttagloop; 1904 } 1905 // NOT falling through! 1906 case PRE_OR_LISTING: 1907 case LI: 1908 case DD_OR_DT: 1909 case BUTTON: 1910 case MARQUEE_OR_APPLET: 1911 case OBJECT: 1912 case TABLE: 1913 case AREA_OR_WBR: 1914 case KEYGEN: 1915 case BR: 1916 case EMBED: 1917 case IMG: 1918 case INPUT: 1919 case HR: 1920 case TEXTAREA: 1921 case XMP: 1922 case IFRAME: 1923 case SELECT: 1924 if (mode == FRAMESET_OK 1925 && !(group == INPUT && Portability.lowerCaseLiteralEqualsIgnoreAsciiCaseString( 1926 "hidden", 1927 attributes.getValue(AttributeName.TYPE)))) { 1928 framesetOk = false; 1929 mode = IN_BODY; 1930 } 1931 // CPPONLY: MOZ_FALLTHROUGH; 1932 default: 1933 // fall through to IN_BODY 1934 } 1935 // CPPONLY: MOZ_FALLTHROUGH; 1936 case IN_BODY: 1937 inbodyloop: for (;;) { 1938 switch (group) { 1939 case HTML: 1940 errStrayStartTag(name); 1941 if (!fragment && !isTemplateContents()) { 1942 addAttributesToHtml(attributes); 1943 attributes = null; // CPP 1944 } 1945 break starttagloop; 1946 case BASE: 1947 case LINK_OR_BASEFONT_OR_BGSOUND: 1948 case META: 1949 case STYLE: 1950 case SCRIPT: 1951 case TITLE: 1952 case TEMPLATE: 1953 // Fall through to IN_HEAD 1954 break inbodyloop; 1955 case BODY: 1956 if (currentPtr == 0 || stack[1].getGroup() != BODY || isTemplateContents()) { 1957 assert fragment || isTemplateContents(); 1958 errStrayStartTag(name); 1959 break starttagloop; 1960 } 1961 errFooSeenWhenFooOpen(name); 1962 framesetOk = false; 1963 if (mode == FRAMESET_OK) { 1964 mode = IN_BODY; 1965 } 1966 if (addAttributesToBody(attributes)) { 1967 attributes = null; // CPP 1968 } 1969 break starttagloop; 1970 case P: 1971 case DIV_OR_BLOCKQUOTE_OR_CENTER_OR_MENU: 1972 case UL_OR_OL_OR_DL: 1973 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: 1974 implicitlyCloseP(); 1975 appendToCurrentNodeAndPushElementMayFoster( 1976 elementName, 1977 attributes); 1978 attributes = null; // CPP 1979 break starttagloop; 1980 case H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6: 1981 implicitlyCloseP(); 1982 if (stack[currentPtr].getGroup() == H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6) { 1983 errHeadingWhenHeadingOpen(); 1984 pop(); 1985 } 1986 appendToCurrentNodeAndPushElementMayFoster( 1987 elementName, 1988 attributes); 1989 attributes = null; // CPP 1990 break starttagloop; 1991 case FIELDSET: 1992 implicitlyCloseP(); 1993 appendToCurrentNodeAndPushElementMayFoster( 1994 elementName, 1995 attributes, formPointer); 1996 attributes = null; // CPP 1997 break starttagloop; 1998 case PRE_OR_LISTING: 1999 implicitlyCloseP(); 2000 appendToCurrentNodeAndPushElementMayFoster( 2001 elementName, 2002 attributes); 2003 needToDropLF = true; 2004 attributes = null; // CPP 2005 break starttagloop; 2006 case FORM: 2007 if (formPointer != null && !isTemplateContents()) { 2008 errFormWhenFormOpen(); 2009 break starttagloop; 2010 } else { 2011 implicitlyCloseP(); 2012 appendToCurrentNodeAndPushFormElementMayFoster(attributes); 2013 attributes = null; // CPP 2014 break starttagloop; 2015 } 2016 case LI: 2017 case DD_OR_DT: 2018 eltPos = currentPtr; 2019 for (;;) { 2020 StackNode<T> node = stack[eltPos]; // weak 2021 // ref 2022 if (node.getGroup() == group) { // LI or 2023 // DD_OR_DT 2024 generateImpliedEndTagsExceptFor(node.name); 2025 if (errorHandler != null 2026 && eltPos != currentPtr) { 2027 errUnclosedElementsImplied(eltPos, name); 2028 } 2029 while (currentPtr >= eltPos) { 2030 pop(); 2031 } 2032 break; 2033 } else if (eltPos == 0 || (node.isSpecial() 2034 && (node.ns != "http://www.w3.org/1999/xhtml" 2035 || (node.name != "p" 2036 && node.name != "address" 2037 && node.name != "div")))) { 2038 break; 2039 } 2040 eltPos--; 2041 } 2042 implicitlyCloseP(); 2043 appendToCurrentNodeAndPushElementMayFoster( 2044 elementName, 2045 attributes); 2046 attributes = null; // CPP 2047 break starttagloop; 2048 case PLAINTEXT: 2049 implicitlyCloseP(); 2050 appendToCurrentNodeAndPushElementMayFoster( 2051 elementName, 2052 attributes); 2053 tokenizer.setStateAndEndTagExpectation( 2054 Tokenizer.PLAINTEXT, elementName); 2055 attributes = null; // CPP 2056 break starttagloop; 2057 case A: 2058 int activeAPos = findInListOfActiveFormattingElementsContainsBetweenEndAndLastMarker("a"); 2059 if (activeAPos != -1) { 2060 errFooSeenWhenFooOpen(name); 2061 StackNode<T> activeA = listOfActiveFormattingElements[activeAPos]; 2062 activeA.retain(); 2063 adoptionAgencyEndTag("a"); 2064 removeFromStack(activeA); 2065 activeAPos = findInListOfActiveFormattingElements(activeA); 2066 if (activeAPos != -1) { 2067 removeFromListOfActiveFormattingElements(activeAPos); 2068 } 2069 activeA.release(this); 2070 } 2071 reconstructTheActiveFormattingElements(); 2072 appendToCurrentNodeAndPushFormattingElementMayFoster( 2073 elementName, 2074 attributes); 2075 attributes = null; // CPP 2076 break starttagloop; 2077 case B_OR_BIG_OR_CODE_OR_EM_OR_I_OR_S_OR_SMALL_OR_STRIKE_OR_STRONG_OR_TT_OR_U: 2078 case FONT: 2079 reconstructTheActiveFormattingElements(); 2080 maybeForgetEarlierDuplicateFormattingElement(elementName.getName(), attributes); 2081 appendToCurrentNodeAndPushFormattingElementMayFoster( 2082 elementName, 2083 attributes); 2084 attributes = null; // CPP 2085 break starttagloop; 2086 case NOBR: 2087 reconstructTheActiveFormattingElements(); 2088 if (TreeBuilder.NOT_FOUND_ON_STACK != findLastInScope("nobr")) { 2089 errFooSeenWhenFooOpen(name); 2090 adoptionAgencyEndTag("nobr"); 2091 reconstructTheActiveFormattingElements(); 2092 } 2093 appendToCurrentNodeAndPushFormattingElementMayFoster( 2094 elementName, 2095 attributes); 2096 attributes = null; // CPP 2097 break starttagloop; 2098 case BUTTON: 2099 eltPos = findLastInScope(name); 2100 if (eltPos != TreeBuilder.NOT_FOUND_ON_STACK) { 2101 errFooSeenWhenFooOpen(name); 2102 generateImpliedEndTags(); 2103 if (errorHandler != null 2104 && !isCurrent(name)) { 2105 errUnclosedElementsImplied(eltPos, name); 2106 } 2107 while (currentPtr >= eltPos) { 2108 pop(); 2109 } 2110 continue starttagloop; 2111 } else { 2112 reconstructTheActiveFormattingElements(); 2113 appendToCurrentNodeAndPushElementMayFoster( 2114 elementName, 2115 attributes, formPointer); 2116 attributes = null; // CPP 2117 break starttagloop; 2118 } 2119 case OBJECT: 2120 reconstructTheActiveFormattingElements(); 2121 appendToCurrentNodeAndPushElementMayFoster( 2122 elementName, 2123 attributes, formPointer); 2124 insertMarker(); 2125 attributes = null; // CPP 2126 break starttagloop; 2127 case MARQUEE_OR_APPLET: 2128 reconstructTheActiveFormattingElements(); 2129 appendToCurrentNodeAndPushElementMayFoster( 2130 elementName, 2131 attributes); 2132 insertMarker(); 2133 attributes = null; // CPP 2134 break starttagloop; 2135 case TABLE: 2136 // The only quirk. Blame Hixie and 2137 // Acid2. 2138 if (!quirks) { 2139 implicitlyCloseP(); 2140 } 2141 appendToCurrentNodeAndPushElementMayFoster( 2142 elementName, 2143 attributes); 2144 mode = IN_TABLE; 2145 attributes = null; // CPP 2146 break starttagloop; 2147 case BR: 2148 case EMBED: 2149 case AREA_OR_WBR: 2150 case KEYGEN: 2151 reconstructTheActiveFormattingElements(); 2152 // FALL THROUGH to PARAM_OR_SOURCE_OR_TRACK 2153 // CPPONLY: MOZ_FALLTHROUGH; 2154 case PARAM_OR_SOURCE_OR_TRACK: 2155 appendVoidElementToCurrentMayFoster( 2156 elementName, 2157 attributes); 2158 selfClosing = false; 2159 // [NOCPP[ 2160 voidElement = true; 2161 // ]NOCPP] 2162 attributes = null; // CPP 2163 break starttagloop; 2164 case HR: 2165 implicitlyCloseP(); 2166 appendVoidElementToCurrentMayFoster( 2167 elementName, 2168 attributes); 2169 selfClosing = false; 2170 // [NOCPP[ 2171 voidElement = true; 2172 // ]NOCPP] 2173 attributes = null; // CPP 2174 break starttagloop; 2175 case IMAGE: 2176 errImage(); 2177 elementName = ElementName.IMG; 2178 continue starttagloop; 2179 case IMG: 2180 case INPUT: 2181 reconstructTheActiveFormattingElements(); 2182 appendVoidElementToCurrentMayFoster( 2183 elementName, attributes, 2184 formPointer); 2185 selfClosing = false; 2186 // [NOCPP[ 2187 voidElement = true; 2188 // ]NOCPP] 2189 attributes = null; // CPP 2190 break starttagloop; 2191 case TEXTAREA: 2192 appendToCurrentNodeAndPushElementMayFoster( 2193 elementName, 2194 attributes, formPointer); 2195 tokenizer.setStateAndEndTagExpectation( 2196 Tokenizer.RCDATA, elementName); 2197 originalMode = mode; 2198 mode = TEXT; 2199 needToDropLF = true; 2200 attributes = null; // CPP 2201 break starttagloop; 2202 case XMP: 2203 implicitlyCloseP(); 2204 reconstructTheActiveFormattingElements(); 2205 appendToCurrentNodeAndPushElementMayFoster( 2206 elementName, 2207 attributes); 2208 originalMode = mode; 2209 mode = TEXT; 2210 tokenizer.setStateAndEndTagExpectation( 2211 Tokenizer.RAWTEXT, elementName); 2212 attributes = null; // CPP 2213 break starttagloop; 2214 case NOSCRIPT: 2215 if (!scriptingEnabled) { 2216 reconstructTheActiveFormattingElements(); 2217 appendToCurrentNodeAndPushElementMayFoster( 2218 elementName, 2219 attributes); 2220 attributes = null; // CPP 2221 break starttagloop; 2222 } 2223 // CPPONLY: MOZ_FALLTHROUGH; 2224 case NOFRAMES: 2225 case IFRAME: 2226 case NOEMBED: 2227 startTagGenericRawText(elementName, attributes); 2228 attributes = null; // CPP 2229 break starttagloop; 2230 case SELECT: 2231 reconstructTheActiveFormattingElements(); 2232 appendToCurrentNodeAndPushElementMayFoster( 2233 elementName, 2234 attributes, formPointer); 2235 switch (mode) { 2236 case IN_TABLE: 2237 case IN_CAPTION: 2238 case IN_COLUMN_GROUP: 2239 case IN_TABLE_BODY: 2240 case IN_ROW: 2241 case IN_CELL: 2242 mode = IN_SELECT_IN_TABLE; 2243 break; 2244 default: 2245 mode = IN_SELECT; 2246 break; 2247 } 2248 attributes = null; // CPP 2249 break starttagloop; 2250 case OPTGROUP: 2251 case OPTION: 2252 if (isCurrent("option")) { 2253 pop(); 2254 } 2255 reconstructTheActiveFormattingElements(); 2256 appendToCurrentNodeAndPushElementMayFoster( 2257 elementName, 2258 attributes); 2259 attributes = null; // CPP 2260 break starttagloop; 2261 case RB_OR_RTC: 2262 eltPos = findLastInScope("ruby"); 2263 if (eltPos != NOT_FOUND_ON_STACK) { 2264 generateImpliedEndTags(); 2265 } 2266 if (eltPos != currentPtr) { 2267 if (eltPos == NOT_FOUND_ON_STACK) { 2268 errStartTagSeenWithoutRuby(name); 2269 } else { 2270 errUnclosedChildrenInRuby(); 2271 } 2272 } 2273 appendToCurrentNodeAndPushElementMayFoster( 2274 elementName, 2275 attributes); 2276 attributes = null; // CPP 2277 break starttagloop; 2278 case RT_OR_RP: 2279 eltPos = findLastInScope("ruby"); 2280 if (eltPos != NOT_FOUND_ON_STACK) { 2281 generateImpliedEndTagsExceptFor("rtc"); 2282 } 2283 if (eltPos != currentPtr) { 2284 if (!isCurrent("rtc")) { 2285 if (eltPos == NOT_FOUND_ON_STACK) { 2286 errStartTagSeenWithoutRuby(name); 2287 } else { 2288 errUnclosedChildrenInRuby(); 2289 } 2290 } 2291 } 2292 appendToCurrentNodeAndPushElementMayFoster( 2293 elementName, 2294 attributes); 2295 attributes = null; // CPP 2296 break starttagloop; 2297 case MATH: 2298 reconstructTheActiveFormattingElements(); 2299 attributes.adjustForMath(); 2300 if (selfClosing) { 2301 appendVoidElementToCurrentMayFosterMathML( 2302 elementName, attributes); 2303 selfClosing = false; 2304 } else { 2305 appendToCurrentNodeAndPushElementMayFosterMathML( 2306 elementName, attributes); 2307 } 2308 attributes = null; // CPP 2309 break starttagloop; 2310 case SVG: 2311 reconstructTheActiveFormattingElements(); 2312 attributes.adjustForSvg(); 2313 if (selfClosing) { 2314 appendVoidElementToCurrentMayFosterSVG( 2315 elementName, 2316 attributes); 2317 selfClosing = false; 2318 } else { 2319 appendToCurrentNodeAndPushElementMayFosterSVG( 2320 elementName, attributes); 2321 } 2322 attributes = null; // CPP 2323 break starttagloop; 2324 case CAPTION: 2325 case COL: 2326 case COLGROUP: 2327 case TBODY_OR_THEAD_OR_TFOOT: 2328 case TR: 2329 case TD_OR_TH: 2330 case FRAME: 2331 case FRAMESET: 2332 case HEAD: 2333 errStrayStartTag(name); 2334 break starttagloop; 2335 case OUTPUT: 2336 reconstructTheActiveFormattingElements(); 2337 appendToCurrentNodeAndPushElementMayFoster( 2338 elementName, 2339 attributes, formPointer); 2340 attributes = null; // CPP 2341 break starttagloop; 2342 default: 2343 reconstructTheActiveFormattingElements(); 2344 appendToCurrentNodeAndPushElementMayFoster( 2345 elementName, 2346 attributes); 2347 attributes = null; // CPP 2348 break starttagloop; 2349 } 2350 } 2351 // CPPONLY: MOZ_FALLTHROUGH; 2352 case IN_HEAD: 2353 inheadloop: for (;;) { 2354 switch (group) { 2355 case HTML: 2356 errStrayStartTag(name); 2357 if (!fragment && !isTemplateContents()) { 2358 addAttributesToHtml(attributes); 2359 attributes = null; // CPP 2360 } 2361 break starttagloop; 2362 case BASE: 2363 case LINK_OR_BASEFONT_OR_BGSOUND: 2364 appendVoidElementToCurrentMayFoster( 2365 elementName, 2366 attributes); 2367 selfClosing = false; 2368 // [NOCPP[ 2369 voidElement = true; 2370 // ]NOCPP] 2371 attributes = null; // CPP 2372 break starttagloop; 2373 case META: 2374 // Fall through to IN_HEAD_NOSCRIPT 2375 break inheadloop; 2376 case TITLE: 2377 startTagTitleInHead(elementName, attributes); 2378 attributes = null; // CPP 2379 break starttagloop; 2380 case NOSCRIPT: 2381 if (scriptingEnabled) { 2382 appendToCurrentNodeAndPushElement( 2383 elementName, 2384 attributes); 2385 originalMode = mode; 2386 mode = TEXT; 2387 tokenizer.setStateAndEndTagExpectation( 2388 Tokenizer.RAWTEXT, elementName); 2389 } else { 2390 appendToCurrentNodeAndPushElementMayFoster( 2391 elementName, 2392 attributes); 2393 mode = IN_HEAD_NOSCRIPT; 2394 } 2395 attributes = null; // CPP 2396 break starttagloop; 2397 case SCRIPT: 2398 startTagScriptInHead(elementName, attributes); 2399 attributes = null; // CPP 2400 break starttagloop; 2401 case STYLE: 2402 case NOFRAMES: 2403 startTagGenericRawText(elementName, attributes); 2404 attributes = null; // CPP 2405 break starttagloop; 2406 case HEAD: 2407 /* Parse error. */ 2408 errFooSeenWhenFooOpen(name); 2409 /* Ignore the token. */ 2410 break starttagloop; 2411 case TEMPLATE: 2412 startTagTemplateInHead(elementName, attributes); 2413 attributes = null; // CPP 2414 break starttagloop; 2415 default: 2416 pop(); 2417 mode = AFTER_HEAD; 2418 continue starttagloop; 2419 } 2420 } 2421 // CPPONLY: MOZ_FALLTHROUGH; 2422 case IN_HEAD_NOSCRIPT: 2423 switch (group) { 2424 case HTML: 2425 // XXX did Hixie really mean to omit "base" 2426 // here? 2427 errStrayStartTag(name); 2428 if (!fragment && !isTemplateContents()) { 2429 addAttributesToHtml(attributes); 2430 attributes = null; // CPP 2431 } 2432 break starttagloop; 2433 case LINK_OR_BASEFONT_OR_BGSOUND: 2434 appendVoidElementToCurrentMayFoster( 2435 elementName, 2436 attributes); 2437 selfClosing = false; 2438 // [NOCPP[ 2439 voidElement = true; 2440 // ]NOCPP] 2441 attributes = null; // CPP 2442 break starttagloop; 2443 case META: 2444 checkMetaCharset(attributes); 2445 appendVoidElementToCurrentMayFoster( 2446 elementName, 2447 attributes); 2448 selfClosing = false; 2449 // [NOCPP[ 2450 voidElement = true; 2451 // ]NOCPP] 2452 attributes = null; // CPP 2453 break starttagloop; 2454 case STYLE: 2455 case NOFRAMES: 2456 appendToCurrentNodeAndPushElement( 2457 elementName, 2458 attributes); 2459 originalMode = mode; 2460 mode = TEXT; 2461 tokenizer.setStateAndEndTagExpectation( 2462 Tokenizer.RAWTEXT, elementName); 2463 attributes = null; // CPP 2464 break starttagloop; 2465 case HEAD: 2466 errFooSeenWhenFooOpen(name); 2467 break starttagloop; 2468 case NOSCRIPT: 2469 errFooSeenWhenFooOpen(name); 2470 break starttagloop; 2471 default: 2472 errBadStartTagInNoscriptInHead(name); 2473 pop(); 2474 mode = IN_HEAD; 2475 continue; 2476 } 2477 case IN_COLUMN_GROUP: 2478 switch (group) { 2479 case HTML: 2480 errStrayStartTag(name); 2481 if (!fragment && !isTemplateContents()) { 2482 addAttributesToHtml(attributes); 2483 attributes = null; // CPP 2484 } 2485 break starttagloop; 2486 case COL: 2487 appendVoidElementToCurrentMayFoster( 2488 elementName, 2489 attributes); 2490 selfClosing = false; 2491 // [NOCPP[ 2492 voidElement = true; 2493 // ]NOCPP] 2494 attributes = null; // CPP 2495 break starttagloop; 2496 case TEMPLATE: 2497 startTagTemplateInHead(elementName, attributes); 2498 attributes = null; // CPP 2499 break starttagloop; 2500 default: 2501 if (currentPtr == 0 || stack[currentPtr].getGroup() == TEMPLATE) { 2502 assert fragment || isTemplateContents(); 2503 errGarbageInColgroup(); 2504 break starttagloop; 2505 } 2506 pop(); 2507 mode = IN_TABLE; 2508 continue; 2509 } 2510 case IN_SELECT_IN_TABLE: 2511 switch (group) { 2512 case CAPTION: 2513 case TBODY_OR_THEAD_OR_TFOOT: 2514 case TR: 2515 case TD_OR_TH: 2516 case TABLE: 2517 errStartTagWithSelectOpen(name); 2518 eltPos = findLastInTableScope("select"); 2519 if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { 2520 assert fragment; 2521 break starttagloop; // http://www.w3.org/Bugs/Public/show_bug.cgi?id=8375 2522 } 2523 while (currentPtr >= eltPos) { 2524 pop(); 2525 } 2526 resetTheInsertionMode(); 2527 continue; 2528 default: 2529 // fall through to IN_SELECT 2530 } 2531 // CPPONLY: MOZ_FALLTHROUGH; 2532 case IN_SELECT: 2533 switch (group) { 2534 case HTML: 2535 errStrayStartTag(name); 2536 if (!fragment) { 2537 addAttributesToHtml(attributes); 2538 attributes = null; // CPP 2539 } 2540 break starttagloop; 2541 case OPTION: 2542 if (isCurrent("option")) { 2543 pop(); 2544 } 2545 appendToCurrentNodeAndPushElement( 2546 elementName, 2547 attributes); 2548 attributes = null; // CPP 2549 break starttagloop; 2550 case OPTGROUP: 2551 if (isCurrent("option")) { 2552 pop(); 2553 } 2554 if (isCurrent("optgroup")) { 2555 pop(); 2556 } 2557 appendToCurrentNodeAndPushElement( 2558 elementName, 2559 attributes); 2560 attributes = null; // CPP 2561 break starttagloop; 2562 case SELECT: 2563 errStartSelectWhereEndSelectExpected(); 2564 eltPos = findLastInTableScope(name); 2565 if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { 2566 assert fragment; 2567 errNoSelectInTableScope(); 2568 break starttagloop; 2569 } else { 2570 while (currentPtr >= eltPos) { 2571 pop(); 2572 } 2573 resetTheInsertionMode(); 2574 break starttagloop; 2575 } 2576 case INPUT: 2577 case TEXTAREA: 2578 errStartTagWithSelectOpen(name); 2579 eltPos = findLastInTableScope("select"); 2580 if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { 2581 assert fragment; 2582 break starttagloop; 2583 } 2584 while (currentPtr >= eltPos) { 2585 pop(); 2586 } 2587 resetTheInsertionMode(); 2588 continue; 2589 case SCRIPT: 2590 startTagScriptInHead(elementName, attributes); 2591 attributes = null; // CPP 2592 break starttagloop; 2593 case TEMPLATE: 2594 startTagTemplateInHead(elementName, attributes); 2595 attributes = null; // CPP 2596 break starttagloop; 2597 case HR: 2598 if (isCurrent("option")) { 2599 pop(); 2600 } 2601 if (isCurrent("optgroup")) { 2602 pop(); 2603 } 2604 appendVoidElementToCurrent(elementName, attributes); 2605 selfClosing = false; 2606 // [NOCPP[ 2607 voidElement = true; 2608 // ]NOCPP] 2609 attributes = null; // CPP 2610 break starttagloop; 2611 default: 2612 errStrayStartTag(name); 2613 break starttagloop; 2614 } 2615 case AFTER_BODY: 2616 switch (group) { 2617 case HTML: 2618 errStrayStartTag(name); 2619 if (!fragment && !isTemplateContents()) { 2620 addAttributesToHtml(attributes); 2621 attributes = null; // CPP 2622 } 2623 break starttagloop; 2624 default: 2625 errStrayStartTag(name); 2626 mode = framesetOk ? FRAMESET_OK : IN_BODY; 2627 continue; 2628 } 2629 case IN_FRAMESET: 2630 switch (group) { 2631 case FRAMESET: 2632 appendToCurrentNodeAndPushElement( 2633 elementName, 2634 attributes); 2635 attributes = null; // CPP 2636 break starttagloop; 2637 case FRAME: 2638 appendVoidElementToCurrentMayFoster( 2639 elementName, 2640 attributes); 2641 selfClosing = false; 2642 // [NOCPP[ 2643 voidElement = true; 2644 // ]NOCPP] 2645 attributes = null; // CPP 2646 break starttagloop; 2647 default: 2648 // fall through to AFTER_FRAMESET 2649 } 2650 // CPPONLY: MOZ_FALLTHROUGH; 2651 case AFTER_FRAMESET: 2652 switch (group) { 2653 case HTML: 2654 errStrayStartTag(name); 2655 if (!fragment && !isTemplateContents()) { 2656 addAttributesToHtml(attributes); 2657 attributes = null; // CPP 2658 } 2659 break starttagloop; 2660 case NOFRAMES: 2661 appendToCurrentNodeAndPushElement( 2662 elementName, 2663 attributes); 2664 originalMode = mode; 2665 mode = TEXT; 2666 tokenizer.setStateAndEndTagExpectation( 2667 Tokenizer.RAWTEXT, elementName); 2668 attributes = null; // CPP 2669 break starttagloop; 2670 default: 2671 errStrayStartTag(name); 2672 break starttagloop; 2673 } 2674 case INITIAL: 2675 /* 2676 * Parse error. 2677 */ 2678 errStartTagWithoutDoctype(); 2679 /* 2680 * 2681 * Set the document to quirks mode. 2682 */ 2683 documentModeInternal(DocumentMode.QUIRKS_MODE, null, null); 2684 /* 2685 * Then, switch to the root element mode of the tree 2686 * construction stage 2687 */ 2688 mode = BEFORE_HTML; 2689 /* 2690 * and reprocess the current token. 2691 */ 2692 continue; 2693 case BEFORE_HTML: 2694 switch (group) { 2695 case HTML: 2696 // optimize error check and streaming SAX by 2697 // hoisting 2698 // "html" handling here. 2699 if (attributes == HtmlAttributes.EMPTY_ATTRIBUTES) { 2700 // This has the right magic side effect 2701 // that 2702 // it 2703 // makes attributes in SAX Tree mutable. 2704 appendHtmlElementToDocumentAndPush(); 2705 } else { 2706 appendHtmlElementToDocumentAndPush(attributes); 2707 } 2708 // XXX application cache should fire here 2709 mode = BEFORE_HEAD; 2710 attributes = null; // CPP 2711 break starttagloop; 2712 default: 2713 /* 2714 * Create an HTMLElement node with the tag name 2715 * html, in the HTML namespace. Append it to the 2716 * Document object. 2717 */ 2718 appendHtmlElementToDocumentAndPush(); 2719 /* Switch to the main mode */ 2720 mode = BEFORE_HEAD; 2721 /* 2722 * reprocess the current token. 2723 */ 2724 continue; 2725 } 2726 case BEFORE_HEAD: 2727 switch (group) { 2728 case HTML: 2729 errStrayStartTag(name); 2730 if (!fragment && !isTemplateContents()) { 2731 addAttributesToHtml(attributes); 2732 attributes = null; // CPP 2733 } 2734 break starttagloop; 2735 case HEAD: 2736 /* 2737 * A start tag whose tag name is "head" 2738 * 2739 * Create an element for the token. 2740 * 2741 * Set the head element pointer to this new element 2742 * node. 2743 * 2744 * Append the new element to the current node and 2745 * push it onto the stack of open elements. 2746 */ 2747 appendToCurrentNodeAndPushHeadElement(attributes); 2748 /* 2749 * Change the insertion mode to "in head". 2750 */ 2751 mode = IN_HEAD; 2752 attributes = null; // CPP 2753 break starttagloop; 2754 default: 2755 /* 2756 * Any other start tag token 2757 * 2758 * Act as if a start tag token with the tag name 2759 * "head" and no attributes had been seen, 2760 */ 2761 appendToCurrentNodeAndPushHeadElement(HtmlAttributes.EMPTY_ATTRIBUTES); 2762 mode = IN_HEAD; 2763 /* 2764 * then reprocess the current token. 2765 * 2766 * This will result in an empty head element being 2767 * generated, with the current token being 2768 * reprocessed in the "after head" insertion mode. 2769 */ 2770 continue; 2771 } 2772 case AFTER_HEAD: 2773 switch (group) { 2774 case HTML: 2775 errStrayStartTag(name); 2776 if (!fragment && !isTemplateContents()) { 2777 addAttributesToHtml(attributes); 2778 attributes = null; // CPP 2779 } 2780 break starttagloop; 2781 case BODY: 2782 if (attributes.getLength() == 0) { 2783 // This has the right magic side effect 2784 // that 2785 // it 2786 // makes attributes in SAX Tree mutable. 2787 appendToCurrentNodeAndPushBodyElement(); 2788 } else { 2789 appendToCurrentNodeAndPushBodyElement(attributes); 2790 } 2791 framesetOk = false; 2792 mode = IN_BODY; 2793 attributes = null; // CPP 2794 break starttagloop; 2795 case FRAMESET: 2796 appendToCurrentNodeAndPushElement( 2797 elementName, 2798 attributes); 2799 mode = IN_FRAMESET; 2800 attributes = null; // CPP 2801 break starttagloop; 2802 case TEMPLATE: 2803 errFooBetweenHeadAndBody(name); 2804 pushHeadPointerOntoStack(); 2805 StackNode<T> headOnStack = stack[currentPtr]; 2806 startTagTemplateInHead(elementName, attributes); 2807 removeFromStack(headOnStack); 2808 attributes = null; // CPP 2809 break starttagloop; 2810 case BASE: 2811 case LINK_OR_BASEFONT_OR_BGSOUND: 2812 errFooBetweenHeadAndBody(name); 2813 pushHeadPointerOntoStack(); 2814 appendVoidElementToCurrentMayFoster( 2815 elementName, 2816 attributes); 2817 selfClosing = false; 2818 // [NOCPP[ 2819 voidElement = true; 2820 // ]NOCPP] 2821 pop(); // head 2822 attributes = null; // CPP 2823 break starttagloop; 2824 case META: 2825 errFooBetweenHeadAndBody(name); 2826 checkMetaCharset(attributes); 2827 pushHeadPointerOntoStack(); 2828 appendVoidElementToCurrentMayFoster( 2829 elementName, 2830 attributes); 2831 selfClosing = false; 2832 // [NOCPP[ 2833 voidElement = true; 2834 // ]NOCPP] 2835 pop(); // head 2836 attributes = null; // CPP 2837 break starttagloop; 2838 case SCRIPT: 2839 errFooBetweenHeadAndBody(name); 2840 pushHeadPointerOntoStack(); 2841 appendToCurrentNodeAndPushElement( 2842 elementName, 2843 attributes); 2844 originalMode = mode; 2845 mode = TEXT; 2846 tokenizer.setStateAndEndTagExpectation( 2847 Tokenizer.SCRIPT_DATA, elementName); 2848 attributes = null; // CPP 2849 break starttagloop; 2850 case STYLE: 2851 case NOFRAMES: 2852 errFooBetweenHeadAndBody(name); 2853 pushHeadPointerOntoStack(); 2854 appendToCurrentNodeAndPushElement( 2855 elementName, 2856 attributes); 2857 originalMode = mode; 2858 mode = TEXT; 2859 tokenizer.setStateAndEndTagExpectation( 2860 Tokenizer.RAWTEXT, elementName); 2861 attributes = null; // CPP 2862 break starttagloop; 2863 case TITLE: 2864 errFooBetweenHeadAndBody(name); 2865 pushHeadPointerOntoStack(); 2866 appendToCurrentNodeAndPushElement( 2867 elementName, 2868 attributes); 2869 originalMode = mode; 2870 mode = TEXT; 2871 tokenizer.setStateAndEndTagExpectation( 2872 Tokenizer.RCDATA, elementName); 2873 attributes = null; // CPP 2874 break starttagloop; 2875 case HEAD: 2876 errStrayStartTag(name); 2877 break starttagloop; 2878 default: 2879 appendToCurrentNodeAndPushBodyElement(); 2880 mode = FRAMESET_OK; 2881 continue; 2882 } 2883 case AFTER_AFTER_BODY: 2884 switch (group) { 2885 case HTML: 2886 errStrayStartTag(name); 2887 if (!fragment && !isTemplateContents()) { 2888 addAttributesToHtml(attributes); 2889 attributes = null; // CPP 2890 } 2891 break starttagloop; 2892 default: 2893 errStrayStartTag(name); 2894 fatal(); 2895 mode = framesetOk ? FRAMESET_OK : IN_BODY; 2896 continue; 2897 } 2898 case AFTER_AFTER_FRAMESET: 2899 switch (group) { 2900 case HTML: 2901 errStrayStartTag(name); 2902 if (!fragment && !isTemplateContents()) { 2903 addAttributesToHtml(attributes); 2904 attributes = null; // CPP 2905 } 2906 break starttagloop; 2907 case NOFRAMES: 2908 startTagGenericRawText(elementName, attributes); 2909 attributes = null; // CPP 2910 break starttagloop; 2911 default: 2912 errStrayStartTag(name); 2913 break starttagloop; 2914 } 2915 case TEXT: 2916 assert false; 2917 break starttagloop; // Avoid infinite loop if the assertion 2918 // fails 2919 } 2920 } 2921 if (selfClosing) { 2922 errSelfClosing(); 2923 // [NOCPP[ 2924 } else if (wasSelfClosing && voidElement 2925 && tokenizer.getErrorProfile() != null 2926 && tokenizer.getErrorProfile().get("html-strict") != null) { 2927 warn("Trailing slash on void elements has no effect and interacts" 2928 + " badly with unquoted attribute values."); 2929 // ]NOCPP] 2930 } 2931 // CPPONLY: if (mBuilder == null && attributes != HtmlAttributes.EMPTY_ATTRIBUTES) { 2932 // CPPONLY: Portability.delete(attributes); 2933 // CPPONLY: } 2934 } 2935 2936 private void startTagTitleInHead(ElementName elementName, HtmlAttributes attributes) throws SAXException { 2937 appendToCurrentNodeAndPushElementMayFoster(elementName, attributes); 2938 originalMode = mode; 2939 mode = TEXT; 2940 tokenizer.setStateAndEndTagExpectation(Tokenizer.RCDATA, elementName); 2941 } 2942 2943 private void startTagGenericRawText(ElementName elementName, HtmlAttributes attributes) throws SAXException { 2944 appendToCurrentNodeAndPushElementMayFoster(elementName, attributes); 2945 originalMode = mode; 2946 mode = TEXT; 2947 tokenizer.setStateAndEndTagExpectation(Tokenizer.RAWTEXT, elementName); 2948 } 2949 2950 private void startTagScriptInHead(ElementName elementName, HtmlAttributes attributes) throws SAXException { 2951 // XXX need to manage much more stuff here if supporting document.write() 2952 appendToCurrentNodeAndPushElementMayFoster(elementName, attributes); 2953 originalMode = mode; 2954 mode = TEXT; 2955 tokenizer.setStateAndEndTagExpectation(Tokenizer.SCRIPT_DATA, elementName); 2956 } 2957 2958 private void startTagTemplateInHead(ElementName elementName, HtmlAttributes attributes) throws SAXException { 2959 appendToCurrentNodeAndPushElement(elementName, attributes); 2960 insertMarker(); 2961 framesetOk = false; 2962 originalMode = mode; 2963 mode = IN_TEMPLATE; 2964 pushTemplateMode(IN_TEMPLATE); 2965 } 2966 2967 private boolean isTemplateContents() { 2968 return TreeBuilder.NOT_FOUND_ON_STACK != findLast("template"); 2969 } 2970 2971 private boolean isTemplateModeStackEmpty() { 2972 return templateModePtr == -1; 2973 } 2974 2975 private boolean isSpecialParentInForeign(StackNode<T> stackNode) { 2976 @NsUri String ns = stackNode.ns; 2977 return ("http://www.w3.org/1999/xhtml" == ns) 2978 || (stackNode.isHtmlIntegrationPoint()) 2979 || (("http://www.w3.org/1998/Math/MathML" == ns) && (stackNode.getGroup() == MI_MO_MN_MS_MTEXT)); 2980 } 2981 2982 private T getDeclarativeShadowRoot(T currentNode, T templateNode, HtmlAttributes attributes) { 2983 if (!isAllowDeclarativeShadowRoots()) { 2984 return null; 2985 } 2986 2987 String shadowRootMode = attributes.getValue(AttributeName.SHADOWROOTMODE); 2988 if (shadowRootMode == null) { 2989 return null; 2990 } 2991 2992 boolean shadowRootIsClonable = attributes.contains(AttributeName.SHADOWROOTCLONABLE); 2993 boolean shadowRootIsSerializable = attributes.contains(AttributeName.SHADOWROOTSERIALIZABLE); 2994 boolean shadowRootDelegatesFocus = attributes.contains(AttributeName.SHADOWROOTDELEGATESFOCUS); 2995 String shadowRootReferenceTarget = attributes.getValue(AttributeName.SHADOWROOTREFERENCETARGET); 2996 2997 return getShadowRootFromHost(currentNode, templateNode, shadowRootMode, shadowRootIsClonable, shadowRootIsSerializable, shadowRootDelegatesFocus, shadowRootReferenceTarget); 2998 } 2999 3000 /** 3001 * 3002 * <p> 3003 * C++ memory note: The return value must be released. 3004 * 3005 * @return 3006 * @throws SAXException 3007 * @throws StopSniffingException 3008 */ 3009 public static String extractCharsetFromContent(String attributeValue 3010 // CPPONLY: , TreeBuilder tb 3011 ) { 3012 // This is a bit ugly. Converting the string to char array in order to 3013 // make the portability layer smaller. 3014 int charsetState = CHARSET_INITIAL; 3015 int start = -1; 3016 int end = -1; 3017 @Auto char[] buffer = Portability.newCharArrayFromString(attributeValue); 3018 3019 charsetloop: for (int i = 0; i < buffer.length; i++) { 3020 char c = buffer[i]; 3021 switch (charsetState) { 3022 case CHARSET_INITIAL: 3023 switch (c) { 3024 case 'c': 3025 case 'C': 3026 charsetState = CHARSET_C; 3027 continue; 3028 default: 3029 continue; 3030 } 3031 case CHARSET_C: 3032 switch (c) { 3033 case 'h': 3034 case 'H': 3035 charsetState = CHARSET_H; 3036 continue; 3037 default: 3038 charsetState = CHARSET_INITIAL; 3039 continue; 3040 } 3041 case CHARSET_H: 3042 switch (c) { 3043 case 'a': 3044 case 'A': 3045 charsetState = CHARSET_A; 3046 continue; 3047 default: 3048 charsetState = CHARSET_INITIAL; 3049 continue; 3050 } 3051 case CHARSET_A: 3052 switch (c) { 3053 case 'r': 3054 case 'R': 3055 charsetState = CHARSET_R; 3056 continue; 3057 default: 3058 charsetState = CHARSET_INITIAL; 3059 continue; 3060 } 3061 case CHARSET_R: 3062 switch (c) { 3063 case 's': 3064 case 'S': 3065 charsetState = CHARSET_S; 3066 continue; 3067 default: 3068 charsetState = CHARSET_INITIAL; 3069 continue; 3070 } 3071 case CHARSET_S: 3072 switch (c) { 3073 case 'e': 3074 case 'E': 3075 charsetState = CHARSET_E; 3076 continue; 3077 default: 3078 charsetState = CHARSET_INITIAL; 3079 continue; 3080 } 3081 case CHARSET_E: 3082 switch (c) { 3083 case 't': 3084 case 'T': 3085 charsetState = CHARSET_T; 3086 continue; 3087 default: 3088 charsetState = CHARSET_INITIAL; 3089 continue; 3090 } 3091 case CHARSET_T: 3092 switch (c) { 3093 case '\t': 3094 case '\n': 3095 case '\u000C': 3096 case '\r': 3097 case ' ': 3098 continue; 3099 case '=': 3100 charsetState = CHARSET_EQUALS; 3101 continue; 3102 default: 3103 return null; 3104 } 3105 case CHARSET_EQUALS: 3106 switch (c) { 3107 case '\t': 3108 case '\n': 3109 case '\u000C': 3110 case '\r': 3111 case ' ': 3112 continue; 3113 case '\'': 3114 start = i + 1; 3115 charsetState = CHARSET_SINGLE_QUOTED; 3116 continue; 3117 case '\"': 3118 start = i + 1; 3119 charsetState = CHARSET_DOUBLE_QUOTED; 3120 continue; 3121 default: 3122 start = i; 3123 charsetState = CHARSET_UNQUOTED; 3124 continue; 3125 } 3126 case CHARSET_SINGLE_QUOTED: 3127 switch (c) { 3128 case '\'': 3129 end = i; 3130 break charsetloop; 3131 default: 3132 continue; 3133 } 3134 case CHARSET_DOUBLE_QUOTED: 3135 switch (c) { 3136 case '\"': 3137 end = i; 3138 break charsetloop; 3139 default: 3140 continue; 3141 } 3142 case CHARSET_UNQUOTED: 3143 switch (c) { 3144 case '\t': 3145 case '\n': 3146 case '\u000C': 3147 case '\r': 3148 case ' ': 3149 case ';': 3150 end = i; 3151 break charsetloop; 3152 default: 3153 continue; 3154 } 3155 } 3156 } 3157 if (start != -1) { 3158 if (end == -1) { 3159 if (charsetState == CHARSET_UNQUOTED) { 3160 end = buffer.length; 3161 } else { 3162 return null; 3163 } 3164 } 3165 return Portability.newStringFromBuffer(buffer, start, end 3166 - start 3167 // CPPONLY: , tb, false 3168 ); 3169 } 3170 return null; 3171 } 3172 3173 private void checkMetaCharset(HtmlAttributes attributes) 3174 throws SAXException { 3175 String charset = attributes.getValue(AttributeName.CHARSET); 3176 if (charset != null) { 3177 if (tokenizer.internalEncodingDeclaration(charset)) { 3178 requestSuspension(); 3179 return; 3180 } 3181 return; 3182 } 3183 if (!Portability.lowerCaseLiteralEqualsIgnoreAsciiCaseString( 3184 "content-type", 3185 attributes.getValue(AttributeName.HTTP_EQUIV))) { 3186 return; 3187 } 3188 String content = attributes.getValue(AttributeName.CONTENT); 3189 if (content != null) { 3190 String extract = TreeBuilder.extractCharsetFromContent(content 3191 // CPPONLY: , this 3192 ); 3193 // remember not to return early without releasing the string 3194 if (extract != null) { 3195 if (tokenizer.internalEncodingDeclaration(extract)) { 3196 requestSuspension(); 3197 } 3198 } 3199 Portability.releaseString(extract); 3200 } 3201 } 3202 3203 public final void endTag(ElementName elementName) throws SAXException { 3204 flushCharacters(); 3205 needToDropLF = false; 3206 int eltPos; 3207 int group = elementName.getGroup(); 3208 @Local String name = elementName.getName(); 3209 endtagloop: for (;;) { 3210 if (isInForeign()) { 3211 if (stack[currentPtr].name != name) { 3212 if (currentPtr == 0) { 3213 errStrayEndTag(name); 3214 } else { 3215 errEndTagDidNotMatchCurrentOpenElement(name, stack[currentPtr].popName); 3216 } 3217 } 3218 eltPos = currentPtr; 3219 int origPos = currentPtr; 3220 for (;;) { 3221 if (eltPos == 0) { 3222 assert fragment: "We can get this close to the root of the stack in foreign content only in the fragment case."; 3223 break endtagloop; 3224 } 3225 if (stack[eltPos].name == name) { 3226 while (currentPtr >= eltPos) { 3227 popForeign(origPos, eltPos); 3228 } 3229 break endtagloop; 3230 } 3231 if (stack[--eltPos].ns == "http://www.w3.org/1999/xhtml") { 3232 break; 3233 } 3234 } 3235 } 3236 switch (mode) { 3237 case IN_TEMPLATE: 3238 switch (group) { 3239 case TEMPLATE: 3240 // fall through to IN_HEAD 3241 break; 3242 default: 3243 errStrayEndTag(name); 3244 break endtagloop; 3245 } 3246 // CPPONLY: MOZ_FALLTHROUGH; 3247 case IN_ROW: 3248 switch (group) { 3249 case TR: 3250 eltPos = findLastOrRoot(TreeBuilder.TR); 3251 if (eltPos == 0) { 3252 assert fragment || isTemplateContents(); 3253 errNoTableRowToClose(); 3254 break endtagloop; 3255 } 3256 clearStackBackTo(eltPos); 3257 pop(); 3258 mode = IN_TABLE_BODY; 3259 break endtagloop; 3260 case TABLE: 3261 eltPos = findLastOrRoot(TreeBuilder.TR); 3262 if (eltPos == 0) { 3263 assert fragment || isTemplateContents(); 3264 errNoTableRowToClose(); 3265 break endtagloop; 3266 } 3267 clearStackBackTo(eltPos); 3268 pop(); 3269 mode = IN_TABLE_BODY; 3270 continue; 3271 case TBODY_OR_THEAD_OR_TFOOT: 3272 if (findLastInTableScope(name) == TreeBuilder.NOT_FOUND_ON_STACK) { 3273 errStrayEndTag(name); 3274 break endtagloop; 3275 } 3276 eltPos = findLastOrRoot(TreeBuilder.TR); 3277 if (eltPos == 0) { 3278 assert fragment || isTemplateContents(); 3279 errNoTableRowToClose(); 3280 break endtagloop; 3281 } 3282 clearStackBackTo(eltPos); 3283 pop(); 3284 mode = IN_TABLE_BODY; 3285 continue; 3286 case BODY: 3287 case CAPTION: 3288 case COL: 3289 case COLGROUP: 3290 case HTML: 3291 case TD_OR_TH: 3292 errStrayEndTag(name); 3293 break endtagloop; 3294 default: 3295 // fall through to IN_TABLE 3296 } 3297 // CPPONLY: MOZ_FALLTHROUGH; 3298 case IN_TABLE_BODY: 3299 switch (group) { 3300 case TBODY_OR_THEAD_OR_TFOOT: 3301 eltPos = findLastOrRoot(name); 3302 if (eltPos == 0) { 3303 errStrayEndTag(name); 3304 break endtagloop; 3305 } 3306 clearStackBackTo(eltPos); 3307 pop(); 3308 mode = IN_TABLE; 3309 break endtagloop; 3310 case TABLE: 3311 eltPos = findLastInTableScopeOrRootTemplateTbodyTheadTfoot(); 3312 if (eltPos == 0 || stack[eltPos].getGroup() == TEMPLATE) { 3313 assert fragment || isTemplateContents(); 3314 errStrayEndTag(name); 3315 break endtagloop; 3316 } 3317 clearStackBackTo(eltPos); 3318 pop(); 3319 mode = IN_TABLE; 3320 continue; 3321 case BODY: 3322 case CAPTION: 3323 case COL: 3324 case COLGROUP: 3325 case HTML: 3326 case TD_OR_TH: 3327 case TR: 3328 errStrayEndTag(name); 3329 break endtagloop; 3330 default: 3331 // fall through to IN_TABLE 3332 } 3333 // CPPONLY: MOZ_FALLTHROUGH; 3334 case IN_TABLE: 3335 switch (group) { 3336 case TABLE: 3337 eltPos = findLast("table"); 3338 if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { 3339 assert fragment || isTemplateContents(); 3340 errStrayEndTag(name); 3341 break endtagloop; 3342 } 3343 while (currentPtr >= eltPos) { 3344 pop(); 3345 } 3346 resetTheInsertionMode(); 3347 break endtagloop; 3348 case BODY: 3349 case CAPTION: 3350 case COL: 3351 case COLGROUP: 3352 case HTML: 3353 case TBODY_OR_THEAD_OR_TFOOT: 3354 case TD_OR_TH: 3355 case TR: 3356 errStrayEndTag(name); 3357 break endtagloop; 3358 case TEMPLATE: 3359 // fall through to IN_HEAD 3360 break; 3361 default: 3362 errStrayEndTag(name); 3363 // fall through to IN_BODY 3364 } 3365 // CPPONLY: MOZ_FALLTHROUGH; 3366 case IN_CAPTION: 3367 switch (group) { 3368 case CAPTION: 3369 eltPos = findLastInTableScope("caption"); 3370 if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { 3371 break endtagloop; 3372 } 3373 generateImpliedEndTags(); 3374 if (errorHandler != null && currentPtr != eltPos) { 3375 errUnclosedElements(eltPos, name); 3376 } 3377 while (currentPtr >= eltPos) { 3378 pop(); 3379 } 3380 clearTheListOfActiveFormattingElementsUpToTheLastMarker(); 3381 mode = IN_TABLE; 3382 break endtagloop; 3383 case TABLE: 3384 eltPos = findLastInTableScope("caption"); 3385 3386 if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { 3387 assert fragment || isTemplateContents(); 3388 errStrayEndTag(name); 3389 break endtagloop; 3390 } 3391 generateImpliedEndTags(); 3392 if (errorHandler != null && currentPtr != eltPos) { 3393 errUnclosedElements(eltPos, name); 3394 } 3395 while (currentPtr >= eltPos) { 3396 pop(); 3397 } 3398 clearTheListOfActiveFormattingElementsUpToTheLastMarker(); 3399 mode = IN_TABLE; 3400 continue; 3401 case BODY: 3402 case COL: 3403 case COLGROUP: 3404 case HTML: 3405 case TBODY_OR_THEAD_OR_TFOOT: 3406 case TD_OR_TH: 3407 case TR: 3408 errStrayEndTag(name); 3409 break endtagloop; 3410 default: 3411 // fall through to IN_BODY 3412 } 3413 // CPPONLY: MOZ_FALLTHROUGH; 3414 case IN_CELL: 3415 switch (group) { 3416 case TD_OR_TH: 3417 eltPos = findLastInTableScope(name); 3418 if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { 3419 errStrayEndTag(name); 3420 break endtagloop; 3421 } 3422 generateImpliedEndTags(); 3423 if (errorHandler != null && !isCurrent(name)) { 3424 errUnclosedElements(eltPos, name); 3425 } 3426 while (currentPtr >= eltPos) { 3427 pop(); 3428 } 3429 clearTheListOfActiveFormattingElementsUpToTheLastMarker(); 3430 mode = IN_ROW; 3431 break endtagloop; 3432 case TABLE: 3433 case TBODY_OR_THEAD_OR_TFOOT: 3434 case TR: 3435 if (findLastInTableScope(name) == TreeBuilder.NOT_FOUND_ON_STACK) { 3436 assert name == "tbody" || name == "tfoot" || name == "thead" || fragment || isTemplateContents(); 3437 errStrayEndTag(name); 3438 break endtagloop; 3439 } 3440 closeTheCell(findLastInTableScopeTdTh()); 3441 continue; 3442 case BODY: 3443 case CAPTION: 3444 case COL: 3445 case COLGROUP: 3446 case HTML: 3447 errStrayEndTag(name); 3448 break endtagloop; 3449 default: 3450 // fall through to IN_BODY 3451 } 3452 // CPPONLY: MOZ_FALLTHROUGH; 3453 case FRAMESET_OK: 3454 case IN_BODY: 3455 switch (group) { 3456 case BODY: 3457 if (!isSecondOnStackBody()) { 3458 assert fragment || isTemplateContents(); 3459 errStrayEndTag(name); 3460 break endtagloop; 3461 } 3462 assert currentPtr >= 1; 3463 if (errorHandler != null) { 3464 uncloseloop1: for (int i = 2; i <= currentPtr; i++) { 3465 switch (stack[i].getGroup()) { 3466 case DD_OR_DT: 3467 case LI: 3468 case OPTGROUP: 3469 case OPTION: // is this possible? 3470 case P: 3471 case RB_OR_RTC: 3472 case RT_OR_RP: 3473 case TD_OR_TH: 3474 case TBODY_OR_THEAD_OR_TFOOT: 3475 break; 3476 default: 3477 errEndWithUnclosedElements(name); 3478 break uncloseloop1; 3479 } 3480 } 3481 } 3482 mode = AFTER_BODY; 3483 break endtagloop; 3484 case HTML: 3485 if (!isSecondOnStackBody()) { 3486 assert fragment || isTemplateContents(); 3487 errStrayEndTag(name); 3488 break endtagloop; 3489 } 3490 if (errorHandler != null) { 3491 uncloseloop2: for (int i = 0; i <= currentPtr; i++) { 3492 switch (stack[i].getGroup()) { 3493 case DD_OR_DT: 3494 case LI: 3495 case P: 3496 case RB_OR_RTC: 3497 case RT_OR_RP: 3498 case TBODY_OR_THEAD_OR_TFOOT: 3499 case TD_OR_TH: 3500 case BODY: 3501 case HTML: 3502 break; 3503 default: 3504 errEndWithUnclosedElements(name); 3505 break uncloseloop2; 3506 } 3507 } 3508 } 3509 mode = AFTER_BODY; 3510 continue; 3511 case DIV_OR_BLOCKQUOTE_OR_CENTER_OR_MENU: 3512 case UL_OR_OL_OR_DL: 3513 case PRE_OR_LISTING: 3514 case FIELDSET: 3515 case BUTTON: 3516 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: 3517 eltPos = findLastInScope(name); 3518 if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { 3519 errStrayEndTag(name); 3520 } else { 3521 generateImpliedEndTags(); 3522 if (errorHandler != null && !isCurrent(name)) { 3523 errUnclosedElements(eltPos, name); 3524 } 3525 while (currentPtr >= eltPos) { 3526 pop(); 3527 } 3528 } 3529 break endtagloop; 3530 case FORM: 3531 if (!isTemplateContents()) { 3532 if (formPointer == null) { 3533 errStrayEndTag(name); 3534 break endtagloop; 3535 } 3536 formPointer = null; 3537 eltPos = findLastInScope(name); 3538 if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { 3539 errStrayEndTag(name); 3540 break endtagloop; 3541 } 3542 generateImpliedEndTags(); 3543 if (errorHandler != null && !isCurrent(name)) { 3544 errUnclosedElements(eltPos, name); 3545 } 3546 removeFromStack(eltPos); 3547 break endtagloop; 3548 } else { 3549 eltPos = findLastInScope(name); 3550 if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { 3551 errStrayEndTag(name); 3552 break endtagloop; 3553 } 3554 generateImpliedEndTags(); 3555 if (errorHandler != null && !isCurrent(name)) { 3556 errUnclosedElements(eltPos, name); 3557 } 3558 while (currentPtr >= eltPos) { 3559 pop(); 3560 } 3561 break endtagloop; 3562 } 3563 case P: 3564 eltPos = findLastInButtonScope("p"); 3565 if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { 3566 errNoElementToCloseButEndTagSeen("p"); 3567 // XXX Can the 'in foreign' case happen anymore? 3568 if (isInForeign()) { 3569 errHtmlStartTagInForeignContext(name); 3570 // Check for currentPtr for the fragment 3571 // case. 3572 while (currentPtr >= 0 && stack[currentPtr].ns != "http://www.w3.org/1999/xhtml") { 3573 pop(); 3574 } 3575 } 3576 appendVoidElementToCurrentMayFoster( 3577 elementName, 3578 HtmlAttributes.EMPTY_ATTRIBUTES); 3579 break endtagloop; 3580 } 3581 generateImpliedEndTagsExceptFor("p"); 3582 assert eltPos != TreeBuilder.NOT_FOUND_ON_STACK; 3583 if (errorHandler != null && eltPos != currentPtr) { 3584 errUnclosedElements(eltPos, name); 3585 } 3586 while (currentPtr >= eltPos) { 3587 pop(); 3588 } 3589 break endtagloop; 3590 case LI: 3591 eltPos = findLastInListScope(name); 3592 if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { 3593 errNoElementToCloseButEndTagSeen(name); 3594 } else { 3595 generateImpliedEndTagsExceptFor(name); 3596 if (errorHandler != null 3597 && eltPos != currentPtr) { 3598 errUnclosedElements(eltPos, name); 3599 } 3600 while (currentPtr >= eltPos) { 3601 pop(); 3602 } 3603 } 3604 break endtagloop; 3605 case DD_OR_DT: 3606 eltPos = findLastInScope(name); 3607 if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { 3608 errNoElementToCloseButEndTagSeen(name); 3609 } else { 3610 generateImpliedEndTagsExceptFor(name); 3611 if (errorHandler != null 3612 && eltPos != currentPtr) { 3613 errUnclosedElements(eltPos, name); 3614 } 3615 while (currentPtr >= eltPos) { 3616 pop(); 3617 } 3618 } 3619 break endtagloop; 3620 case H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6: 3621 eltPos = findLastInScopeHn(); 3622 if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { 3623 errStrayEndTag(name); 3624 } else { 3625 generateImpliedEndTags(); 3626 if (errorHandler != null && !isCurrent(name)) { 3627 errUnclosedElements(eltPos, name); 3628 } 3629 while (currentPtr >= eltPos) { 3630 pop(); 3631 } 3632 } 3633 break endtagloop; 3634 case OBJECT: 3635 case MARQUEE_OR_APPLET: 3636 eltPos = findLastInScope(name); 3637 if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { 3638 errStrayEndTag(name); 3639 } else { 3640 generateImpliedEndTags(); 3641 if (errorHandler != null && !isCurrent(name)) { 3642 errUnclosedElements(eltPos, name); 3643 } 3644 while (currentPtr >= eltPos) { 3645 pop(); 3646 } 3647 clearTheListOfActiveFormattingElementsUpToTheLastMarker(); 3648 } 3649 break endtagloop; 3650 case BR: 3651 errEndTagBr(); 3652 if (isInForeign()) { 3653 // XXX can this happen anymore? 3654 errHtmlStartTagInForeignContext(name); 3655 // Check for currentPtr for the fragment 3656 // case. 3657 while (currentPtr >= 0 && stack[currentPtr].ns != "http://www.w3.org/1999/xhtml") { 3658 pop(); 3659 } 3660 } 3661 reconstructTheActiveFormattingElements(); 3662 appendVoidElementToCurrentMayFoster( 3663 elementName, 3664 HtmlAttributes.EMPTY_ATTRIBUTES); 3665 break endtagloop; 3666 case TEMPLATE: 3667 // fall through to IN_HEAD; 3668 break; 3669 case AREA_OR_WBR: 3670 case KEYGEN: // XXX?? 3671 case PARAM_OR_SOURCE_OR_TRACK: 3672 case EMBED: 3673 case IMG: 3674 case IMAGE: 3675 case INPUT: 3676 case HR: 3677 case IFRAME: 3678 case NOEMBED: // XXX??? 3679 case NOFRAMES: // XXX?? 3680 case SELECT: 3681 case TABLE: 3682 case TEXTAREA: // XXX?? 3683 errStrayEndTag(name); 3684 break endtagloop; 3685 case NOSCRIPT: 3686 if (scriptingEnabled) { 3687 errStrayEndTag(name); 3688 break endtagloop; 3689 } 3690 // CPPONLY: MOZ_FALLTHROUGH; 3691 case A: 3692 case B_OR_BIG_OR_CODE_OR_EM_OR_I_OR_S_OR_SMALL_OR_STRIKE_OR_STRONG_OR_TT_OR_U: 3693 case FONT: 3694 case NOBR: 3695 if (adoptionAgencyEndTag(name)) { 3696 break endtagloop; 3697 } 3698 // else handle like any other tag 3699 // CPPONLY: MOZ_FALLTHROUGH; 3700 default: 3701 if (isCurrent(name)) { 3702 pop(); 3703 break endtagloop; 3704 } 3705 3706 eltPos = currentPtr; 3707 for (;;) { 3708 StackNode<T> node = stack[eltPos]; 3709 if (node.ns == "http://www.w3.org/1999/xhtml" && node.name == name) { 3710 generateImpliedEndTags(); 3711 if (errorHandler != null 3712 && !isCurrent(name)) { 3713 errUnclosedElements(eltPos, name); 3714 } 3715 while (currentPtr >= eltPos) { 3716 pop(); 3717 } 3718 break endtagloop; 3719 } else if (eltPos == 0 || node.isSpecial()) { 3720 errStrayEndTag(name); 3721 break endtagloop; 3722 } 3723 eltPos--; 3724 } 3725 } 3726 // CPPONLY: MOZ_FALLTHROUGH; 3727 case IN_HEAD: 3728 switch (group) { 3729 case HEAD: 3730 pop(); 3731 mode = AFTER_HEAD; 3732 break endtagloop; 3733 case BR: 3734 case HTML: 3735 case BODY: 3736 pop(); 3737 mode = AFTER_HEAD; 3738 continue; 3739 case TEMPLATE: 3740 endTagTemplateInHead(); 3741 break endtagloop; 3742 default: 3743 errStrayEndTag(name); 3744 break endtagloop; 3745 } 3746 case IN_HEAD_NOSCRIPT: 3747 switch (group) { 3748 case NOSCRIPT: 3749 pop(); 3750 mode = IN_HEAD; 3751 break endtagloop; 3752 case BR: 3753 errStrayEndTag(name); 3754 pop(); 3755 mode = IN_HEAD; 3756 continue; 3757 default: 3758 errStrayEndTag(name); 3759 break endtagloop; 3760 } 3761 case IN_COLUMN_GROUP: 3762 switch (group) { 3763 case COLGROUP: 3764 if (currentPtr == 0 || stack[currentPtr].getGroup() == 3765 TreeBuilder.TEMPLATE) { 3766 assert fragment || isTemplateContents(); 3767 errGarbageInColgroup(); 3768 break endtagloop; 3769 } 3770 pop(); 3771 mode = IN_TABLE; 3772 break endtagloop; 3773 case COL: 3774 errStrayEndTag(name); 3775 break endtagloop; 3776 case TEMPLATE: 3777 endTagTemplateInHead(); 3778 break endtagloop; 3779 default: 3780 if (currentPtr == 0 || stack[currentPtr].getGroup() == 3781 TreeBuilder.TEMPLATE) { 3782 assert fragment || isTemplateContents(); 3783 errGarbageInColgroup(); 3784 break endtagloop; 3785 } 3786 pop(); 3787 mode = IN_TABLE; 3788 continue; 3789 } 3790 case IN_SELECT_IN_TABLE: 3791 switch (group) { 3792 case CAPTION: 3793 case TABLE: 3794 case TBODY_OR_THEAD_OR_TFOOT: 3795 case TR: 3796 case TD_OR_TH: 3797 errEndTagSeenWithSelectOpen(name); 3798 if (findLastInTableScope(name) != TreeBuilder.NOT_FOUND_ON_STACK) { 3799 eltPos = findLastInTableScope("select"); 3800 if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { 3801 assert fragment; 3802 break endtagloop; // http://www.w3.org/Bugs/Public/show_bug.cgi?id=8375 3803 } 3804 while (currentPtr >= eltPos) { 3805 pop(); 3806 } 3807 resetTheInsertionMode(); 3808 continue; 3809 } else { 3810 break endtagloop; 3811 } 3812 default: 3813 // fall through to IN_SELECT 3814 } 3815 // CPPONLY: MOZ_FALLTHROUGH; 3816 case IN_SELECT: 3817 switch (group) { 3818 case OPTION: 3819 if (isCurrent("option")) { 3820 pop(); 3821 break endtagloop; 3822 } else { 3823 errStrayEndTag(name); 3824 break endtagloop; 3825 } 3826 case OPTGROUP: 3827 if (isCurrent("option") 3828 && "optgroup" == stack[currentPtr - 1].name) { 3829 pop(); 3830 } 3831 if (isCurrent("optgroup")) { 3832 pop(); 3833 } else { 3834 errStrayEndTag(name); 3835 } 3836 break endtagloop; 3837 case SELECT: 3838 eltPos = findLastInTableScope("select"); 3839 if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { 3840 assert fragment; 3841 errStrayEndTag(name); 3842 break endtagloop; 3843 } 3844 while (currentPtr >= eltPos) { 3845 pop(); 3846 } 3847 resetTheInsertionMode(); 3848 break endtagloop; 3849 case TEMPLATE: 3850 endTagTemplateInHead(); 3851 break endtagloop; 3852 default: 3853 errStrayEndTag(name); 3854 break endtagloop; 3855 } 3856 case AFTER_BODY: 3857 switch (group) { 3858 case HTML: 3859 if (fragment) { 3860 errStrayEndTag(name); 3861 break endtagloop; 3862 } else { 3863 mode = AFTER_AFTER_BODY; 3864 break endtagloop; 3865 } 3866 default: 3867 errEndTagAfterBody(); 3868 mode = framesetOk ? FRAMESET_OK : IN_BODY; 3869 continue; 3870 } 3871 case IN_FRAMESET: 3872 switch (group) { 3873 case FRAMESET: 3874 if (currentPtr == 0) { 3875 assert fragment; 3876 errStrayEndTag(name); 3877 break endtagloop; 3878 } 3879 pop(); 3880 if ((!fragment) && !isCurrent("frameset")) { 3881 mode = AFTER_FRAMESET; 3882 } 3883 break endtagloop; 3884 default: 3885 errStrayEndTag(name); 3886 break endtagloop; 3887 } 3888 case AFTER_FRAMESET: 3889 switch (group) { 3890 case HTML: 3891 mode = AFTER_AFTER_FRAMESET; 3892 break endtagloop; 3893 default: 3894 errStrayEndTag(name); 3895 break endtagloop; 3896 } 3897 case INITIAL: 3898 /* 3899 * Parse error. 3900 */ 3901 errEndTagSeenWithoutDoctype(); 3902 /* 3903 * 3904 * Set the document to quirks mode. 3905 */ 3906 documentModeInternal(DocumentMode.QUIRKS_MODE, null, null); 3907 /* 3908 * Then, switch to the root element mode of the tree 3909 * construction stage 3910 */ 3911 mode = BEFORE_HTML; 3912 /* 3913 * and reprocess the current token. 3914 */ 3915 continue; 3916 case BEFORE_HTML: 3917 switch (group) { 3918 case HEAD: 3919 case BR: 3920 case HTML: 3921 case BODY: 3922 /* 3923 * Create an HTMLElement node with the tag name 3924 * html, in the HTML namespace. Append it to the 3925 * Document object. 3926 */ 3927 appendHtmlElementToDocumentAndPush(); 3928 /* Switch to the main mode */ 3929 mode = BEFORE_HEAD; 3930 /* 3931 * reprocess the current token. 3932 */ 3933 continue; 3934 default: 3935 errStrayEndTag(name); 3936 break endtagloop; 3937 } 3938 case BEFORE_HEAD: 3939 switch (group) { 3940 case HEAD: 3941 case BR: 3942 case HTML: 3943 case BODY: 3944 appendToCurrentNodeAndPushHeadElement(HtmlAttributes.EMPTY_ATTRIBUTES); 3945 mode = IN_HEAD; 3946 continue; 3947 default: 3948 errStrayEndTag(name); 3949 break endtagloop; 3950 } 3951 case AFTER_HEAD: 3952 switch (group) { 3953 case TEMPLATE: 3954 endTagTemplateInHead(); 3955 break endtagloop; 3956 case HTML: 3957 case BODY: 3958 case BR: 3959 appendToCurrentNodeAndPushBodyElement(); 3960 mode = FRAMESET_OK; 3961 continue; 3962 default: 3963 errStrayEndTag(name); 3964 break endtagloop; 3965 } 3966 case AFTER_AFTER_BODY: 3967 errStrayEndTag(name); 3968 mode = framesetOk ? FRAMESET_OK : IN_BODY; 3969 continue; 3970 case AFTER_AFTER_FRAMESET: 3971 errStrayEndTag(name); 3972 break endtagloop; 3973 case TEXT: 3974 // XXX need to manage insertion point here 3975 pop(); 3976 if (originalMode == AFTER_HEAD) { 3977 silentPop(); 3978 } 3979 mode = originalMode; 3980 break endtagloop; 3981 } 3982 } // endtagloop 3983 } 3984 3985 private void endTagTemplateInHead() throws SAXException { 3986 int eltPos = findLast("template"); 3987 if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { 3988 errStrayEndTag("template"); 3989 return; 3990 } 3991 generateImpliedEndTagsThoroughly(); 3992 if (errorHandler != null && !isCurrent("template")) { 3993 errUnclosedElements(eltPos, "template"); 3994 } 3995 while (currentPtr >= eltPos) { 3996 pop(); 3997 } 3998 clearTheListOfActiveFormattingElementsUpToTheLastMarker(); 3999 popTemplateMode(); 4000 resetTheInsertionMode(); 4001 } 4002 4003 private int findLastInTableScopeOrRootTemplateTbodyTheadTfoot() { 4004 for (int i = currentPtr; i > 0; i--) { 4005 if (stack[i].ns == "http://www.w3.org/1999/xhtml" 4006 && (stack[i].getGroup() == TreeBuilder.TBODY_OR_THEAD_OR_TFOOT 4007 || stack[i].getGroup() == TreeBuilder.TEMPLATE)) { 4008 return i; 4009 } 4010 } 4011 return 0; 4012 } 4013 4014 private int findLast(@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) { 4017 return i; 4018 } 4019 } 4020 return TreeBuilder.NOT_FOUND_ON_STACK; 4021 } 4022 4023 private int findLastInTableScope(@Local String name) { 4024 for (int i = currentPtr; i > 0; i--) { 4025 if (stack[i].ns == "http://www.w3.org/1999/xhtml") { 4026 if (stack[i].name == name) { 4027 return i; 4028 } else if (stack[i].name == "table" || stack[i].name == "template") { 4029 return TreeBuilder.NOT_FOUND_ON_STACK; 4030 } 4031 } 4032 } 4033 return TreeBuilder.NOT_FOUND_ON_STACK; 4034 } 4035 4036 private int findLastInButtonScope(@Local String name) { 4037 for (int i = currentPtr; i > 0; i--) { 4038 if (stack[i].ns == "http://www.w3.org/1999/xhtml") { 4039 if (stack[i].name == name) { 4040 return i; 4041 } else if (stack[i].name == "button") { 4042 return TreeBuilder.NOT_FOUND_ON_STACK; 4043 } 4044 } 4045 4046 if (stack[i].isScoping()) { 4047 return TreeBuilder.NOT_FOUND_ON_STACK; 4048 } 4049 } 4050 return TreeBuilder.NOT_FOUND_ON_STACK; 4051 } 4052 4053 private int findLastInScope(@Local String name) { 4054 for (int i = currentPtr; i > 0; i--) { 4055 if (stack[i].ns == "http://www.w3.org/1999/xhtml" && stack[i].name == name) { 4056 return i; 4057 } else if (stack[i].isScoping()) { 4058 return TreeBuilder.NOT_FOUND_ON_STACK; 4059 } 4060 } 4061 return TreeBuilder.NOT_FOUND_ON_STACK; 4062 } 4063 4064 private int findLastInListScope(@Local String name) { 4065 for (int i = currentPtr; i > 0; i--) { 4066 if (stack[i].ns == "http://www.w3.org/1999/xhtml") { 4067 if (stack[i].name == name) { 4068 return i; 4069 } else if (stack[i].name == "ul" || stack[i].name == "ol") { 4070 return TreeBuilder.NOT_FOUND_ON_STACK; 4071 } 4072 } 4073 4074 if (stack[i].isScoping()) { 4075 return TreeBuilder.NOT_FOUND_ON_STACK; 4076 } 4077 } 4078 return TreeBuilder.NOT_FOUND_ON_STACK; 4079 } 4080 4081 private int findLastInScopeHn() { 4082 for (int i = currentPtr; i > 0; i--) { 4083 if (stack[i].getGroup() == TreeBuilder.H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6) { 4084 return i; 4085 } else if (stack[i].isScoping()) { 4086 return TreeBuilder.NOT_FOUND_ON_STACK; 4087 } 4088 } 4089 return TreeBuilder.NOT_FOUND_ON_STACK; 4090 } 4091 4092 private void generateImpliedEndTagsExceptFor(@Local String name) 4093 throws SAXException { 4094 for (;;) { 4095 StackNode<T> node = stack[currentPtr]; 4096 switch (node.getGroup()) { 4097 case P: 4098 case LI: 4099 case DD_OR_DT: 4100 case OPTION: 4101 case OPTGROUP: 4102 case RB_OR_RTC: 4103 case RT_OR_RP: 4104 if (node.ns == "http://www.w3.org/1999/xhtml" && node.name == name) { 4105 return; 4106 } 4107 pop(); 4108 continue; 4109 default: 4110 return; 4111 } 4112 } 4113 } 4114 4115 private void generateImpliedEndTags() throws SAXException { 4116 for (;;) { 4117 switch (stack[currentPtr].getGroup()) { 4118 case P: 4119 case LI: 4120 case DD_OR_DT: 4121 case OPTION: 4122 case OPTGROUP: 4123 case RB_OR_RTC: 4124 case RT_OR_RP: 4125 pop(); 4126 continue; 4127 default: 4128 return; 4129 } 4130 } 4131 } 4132 4133 private void generateImpliedEndTagsThoroughly() throws SAXException { 4134 for (;;) { 4135 switch (stack[currentPtr].getGroup()) { 4136 case CAPTION: 4137 case COLGROUP: 4138 case DD_OR_DT: 4139 case LI: 4140 case OPTGROUP: 4141 case OPTION: 4142 case P: 4143 case RB_OR_RTC: 4144 case RT_OR_RP: 4145 case TBODY_OR_THEAD_OR_TFOOT: 4146 case TD_OR_TH: 4147 case TR: 4148 pop(); 4149 continue; 4150 default: 4151 return; 4152 } 4153 } 4154 } 4155 4156 private boolean isSecondOnStackBody() { 4157 return currentPtr >= 1 && stack[1].getGroup() == TreeBuilder.BODY; 4158 } 4159 4160 private void documentModeInternal(DocumentMode m, String publicIdentifier, 4161 String systemIdentifier) 4162 throws SAXException { 4163 4164 if (forceNoQuirks) { 4165 // Srcdoc documents are always rendered in standards mode. 4166 quirks = false; 4167 if (documentModeHandler != null) { 4168 documentModeHandler.documentMode( 4169 DocumentMode.STANDARDS_MODE 4170 // [NOCPP[ 4171 , null, null 4172 // ]NOCPP] 4173 ); 4174 } 4175 return; 4176 } 4177 4178 quirks = (m == DocumentMode.QUIRKS_MODE); 4179 if (documentModeHandler != null) { 4180 documentModeHandler.documentMode( 4181 m 4182 // [NOCPP[ 4183 , publicIdentifier, systemIdentifier 4184 // ]NOCPP] 4185 ); 4186 } 4187 // [NOCPP[ 4188 documentMode(m, publicIdentifier, systemIdentifier); 4189 // ]NOCPP] 4190 } 4191 4192 private boolean isAlmostStandards(String publicIdentifier, 4193 String systemIdentifier) { 4194 if (Portability.lowerCaseLiteralIsPrefixOfIgnoreAsciiCaseString( 4195 "-//w3c//dtd xhtml 1.0 transitional//", publicIdentifier)) { 4196 return true; 4197 } 4198 if (Portability.lowerCaseLiteralIsPrefixOfIgnoreAsciiCaseString( 4199 "-//w3c//dtd xhtml 1.0 frameset//", publicIdentifier)) { 4200 return true; 4201 } 4202 if (systemIdentifier != null) { 4203 if (Portability.lowerCaseLiteralIsPrefixOfIgnoreAsciiCaseString( 4204 "-//w3c//dtd html 4.01 transitional//", publicIdentifier)) { 4205 return true; 4206 } 4207 if (Portability.lowerCaseLiteralIsPrefixOfIgnoreAsciiCaseString( 4208 "-//w3c//dtd html 4.01 frameset//", publicIdentifier)) { 4209 return true; 4210 } 4211 } 4212 return false; 4213 } 4214 4215 private boolean isQuirky(@Local String name, String publicIdentifier, 4216 String systemIdentifier, boolean forceQuirks) { 4217 if (forceQuirks) { 4218 return true; 4219 } 4220 if (name != HTML_LOCAL) { 4221 return true; 4222 } 4223 if (publicIdentifier != null) { 4224 for (int i = 0; i < TreeBuilder.QUIRKY_PUBLIC_IDS.length; i++) { 4225 if (Portability.lowerCaseLiteralIsPrefixOfIgnoreAsciiCaseString( 4226 TreeBuilder.QUIRKY_PUBLIC_IDS[i], publicIdentifier)) { 4227 return true; 4228 } 4229 } 4230 if (Portability.lowerCaseLiteralEqualsIgnoreAsciiCaseString( 4231 "-//w3o//dtd w3 html strict 3.0//en//", publicIdentifier) 4232 || Portability.lowerCaseLiteralEqualsIgnoreAsciiCaseString( 4233 "-/w3c/dtd html 4.0 transitional/en", 4234 publicIdentifier) 4235 || Portability.lowerCaseLiteralEqualsIgnoreAsciiCaseString( 4236 "html", publicIdentifier)) { 4237 return true; 4238 } 4239 } 4240 if (systemIdentifier == null) { 4241 if (Portability.lowerCaseLiteralIsPrefixOfIgnoreAsciiCaseString( 4242 "-//w3c//dtd html 4.01 transitional//", publicIdentifier)) { 4243 return true; 4244 } else if (Portability.lowerCaseLiteralIsPrefixOfIgnoreAsciiCaseString( 4245 "-//w3c//dtd html 4.01 frameset//", publicIdentifier)) { 4246 return true; 4247 } 4248 } else if (Portability.lowerCaseLiteralEqualsIgnoreAsciiCaseString( 4249 "http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd", 4250 systemIdentifier)) { 4251 return true; 4252 } 4253 return false; 4254 } 4255 4256 private void closeTheCell(int eltPos) throws SAXException { 4257 generateImpliedEndTags(); 4258 if (errorHandler != null && eltPos != currentPtr) { 4259 errUnclosedElementsCell(eltPos); 4260 } 4261 while (currentPtr >= eltPos) { 4262 pop(); 4263 } 4264 clearTheListOfActiveFormattingElementsUpToTheLastMarker(); 4265 mode = IN_ROW; 4266 return; 4267 } 4268 4269 private int findLastInTableScopeTdTh() { 4270 for (int i = currentPtr; i > 0; i--) { 4271 @Local String name = stack[i].name; 4272 if (stack[i].ns == "http://www.w3.org/1999/xhtml") { 4273 if ("td" == name || "th" == name) { 4274 return i; 4275 } else if (name == "table" || name == "template") { 4276 return TreeBuilder.NOT_FOUND_ON_STACK; 4277 } 4278 } 4279 } 4280 return TreeBuilder.NOT_FOUND_ON_STACK; 4281 } 4282 4283 private void clearStackBackTo(int eltPos) throws SAXException { 4284 int eltGroup = stack[eltPos].getGroup(); 4285 while (currentPtr > eltPos) { // > not >= intentional 4286 if (stack[currentPtr].ns == "http://www.w3.org/1999/xhtml" 4287 && stack[currentPtr].getGroup() == TEMPLATE 4288 && (eltGroup == TABLE || eltGroup == TBODY_OR_THEAD_OR_TFOOT|| eltGroup == TR || eltPos == 0)) { 4289 return; 4290 } 4291 pop(); 4292 } 4293 } 4294 4295 private void resetTheInsertionMode() { 4296 StackNode<T> node; 4297 @Local String name; 4298 @NsUri String ns; 4299 for (int i = currentPtr; i >= 0; i--) { 4300 node = stack[i]; 4301 name = node.name; 4302 ns = node.ns; 4303 if (i == 0) { 4304 if (!(contextNamespace == "http://www.w3.org/1999/xhtml" && (contextName == "td" || contextName == "th"))) { 4305 if (fragment) { 4306 // Make sure we are parsing a fragment otherwise the context element doesn't make sense. 4307 name = contextName; 4308 ns = contextNamespace; 4309 } 4310 } else { 4311 mode = framesetOk ? FRAMESET_OK : IN_BODY; // XXX from Hixie's email 4312 return; 4313 } 4314 } 4315 if ("select" == name) { 4316 int ancestorIndex = i; 4317 while (ancestorIndex > 0) { 4318 StackNode<T> ancestor = stack[ancestorIndex--]; 4319 if ("http://www.w3.org/1999/xhtml" == ancestor.ns) { 4320 if ("template" == ancestor.name) { 4321 break; 4322 } 4323 if ("table" == ancestor.name) { 4324 mode = IN_SELECT_IN_TABLE; 4325 return; 4326 } 4327 } 4328 } 4329 mode = IN_SELECT; 4330 return; 4331 } else if ("td" == name || "th" == name) { 4332 mode = IN_CELL; 4333 return; 4334 } else if ("tr" == name) { 4335 mode = IN_ROW; 4336 return; 4337 } else if ("tbody" == name || "thead" == name || "tfoot" == name) { 4338 mode = IN_TABLE_BODY; 4339 return; 4340 } else if ("caption" == name) { 4341 mode = IN_CAPTION; 4342 return; 4343 } else if ("colgroup" == name) { 4344 mode = IN_COLUMN_GROUP; 4345 return; 4346 } else if ("table" == name) { 4347 mode = IN_TABLE; 4348 return; 4349 } else if ("http://www.w3.org/1999/xhtml" != ns) { 4350 mode = framesetOk ? FRAMESET_OK : IN_BODY; 4351 return; 4352 } else if ("template" == name) { 4353 assert templateModePtr >= 0; 4354 mode = templateModeStack[templateModePtr]; 4355 return; 4356 } else if ("head" == name) { 4357 if (name == contextName) { 4358 mode = framesetOk ? FRAMESET_OK : IN_BODY; // really 4359 } else { 4360 mode = IN_HEAD; 4361 } 4362 return; 4363 } else if ("body" == name) { 4364 mode = framesetOk ? FRAMESET_OK : IN_BODY; 4365 return; 4366 } else if ("frameset" == name) { 4367 // TODO: Fragment case. Add error reporting. 4368 mode = IN_FRAMESET; 4369 return; 4370 } else if ("html" == name) { 4371 if (headPointer == null) { 4372 // TODO: Fragment case. Add error reporting. 4373 mode = BEFORE_HEAD; 4374 } else { 4375 mode = AFTER_HEAD; 4376 } 4377 return; 4378 } else if (i == 0) { 4379 mode = framesetOk ? FRAMESET_OK : IN_BODY; 4380 return; 4381 } 4382 } 4383 } 4384 4385 /** 4386 * @throws SAXException 4387 * 4388 */ 4389 private void implicitlyCloseP() throws SAXException { 4390 int eltPos = findLastInButtonScope("p"); 4391 if (eltPos == TreeBuilder.NOT_FOUND_ON_STACK) { 4392 return; 4393 } 4394 generateImpliedEndTagsExceptFor("p"); 4395 if (errorHandler != null && eltPos != currentPtr) { 4396 errUnclosedElementsImplied(eltPos, "p"); 4397 } 4398 while (currentPtr >= eltPos) { 4399 pop(); 4400 } 4401 } 4402 4403 private boolean debugOnlyClearLastStackSlot() { 4404 stack[currentPtr] = null; 4405 return true; 4406 } 4407 4408 private boolean debugOnlyClearLastListSlot() { 4409 listOfActiveFormattingElements[listPtr] = null; 4410 return true; 4411 } 4412 4413 private void pushTemplateMode(int mode) { 4414 templateModePtr++; 4415 if (templateModePtr == templateModeStack.length) { 4416 int[] newStack = new int[templateModeStack.length + 64]; 4417 System.arraycopy(templateModeStack, 0, newStack, 0, templateModeStack.length); 4418 templateModeStack = newStack; 4419 } 4420 templateModeStack[templateModePtr] = mode; 4421 } 4422 4423 @SuppressWarnings("unchecked") private void push(StackNode<T> node) throws SAXException { 4424 currentPtr++; 4425 if (currentPtr == stack.length) { 4426 StackNode<T>[] newStack = new StackNode[stack.length + 64]; 4427 System.arraycopy(stack, 0, newStack, 0, stack.length); 4428 stack = newStack; 4429 } 4430 stack[currentPtr] = node; 4431 elementPushed(node.ns, node.popName, node.node); 4432 } 4433 4434 @SuppressWarnings("unchecked") private void silentPush(StackNode<T> node) throws SAXException { 4435 currentPtr++; 4436 if (currentPtr == stack.length) { 4437 StackNode<T>[] newStack = new StackNode[stack.length + 64]; 4438 System.arraycopy(stack, 0, newStack, 0, stack.length); 4439 stack = newStack; 4440 } 4441 stack[currentPtr] = node; 4442 } 4443 4444 @SuppressWarnings("unchecked") private void append(StackNode<T> node) { 4445 listPtr++; 4446 if (listPtr == listOfActiveFormattingElements.length) { 4447 StackNode<T>[] newList = new StackNode[listOfActiveFormattingElements.length + 64]; 4448 System.arraycopy(listOfActiveFormattingElements, 0, newList, 0, 4449 listOfActiveFormattingElements.length); 4450 listOfActiveFormattingElements = newList; 4451 } 4452 listOfActiveFormattingElements[listPtr] = node; 4453 } 4454 4455 @Inline private void insertMarker() { 4456 append(null); 4457 } 4458 4459 private void clearTheListOfActiveFormattingElementsUpToTheLastMarker() { 4460 while (listPtr > -1) { 4461 if (listOfActiveFormattingElements[listPtr] == null) { 4462 --listPtr; 4463 return; 4464 } 4465 listOfActiveFormattingElements[listPtr].release(this); 4466 --listPtr; 4467 } 4468 } 4469 4470 @Inline private boolean isCurrent(@Local String name) { 4471 return stack[currentPtr].ns == "http://www.w3.org/1999/xhtml" && 4472 name == stack[currentPtr].name; 4473 } 4474 4475 private void removeFromStack(int pos) throws SAXException { 4476 if (currentPtr == pos) { 4477 pop(); 4478 } else { 4479 fatal(); 4480 stack[pos].release(this); 4481 System.arraycopy(stack, pos + 1, stack, pos, currentPtr - pos); 4482 assert debugOnlyClearLastStackSlot(); 4483 currentPtr--; 4484 } 4485 } 4486 4487 private void removeFromStack(StackNode<T> node) throws SAXException { 4488 if (stack[currentPtr] == node) { 4489 pop(); 4490 } else { 4491 int pos = currentPtr - 1; 4492 while (pos >= 0 && stack[pos] != node) { 4493 pos--; 4494 } 4495 if (pos == -1) { 4496 // dead code? 4497 return; 4498 } 4499 fatal(); 4500 node.release(this); 4501 System.arraycopy(stack, pos + 1, stack, pos, currentPtr - pos); 4502 currentPtr--; 4503 } 4504 } 4505 4506 private void removeFromListOfActiveFormattingElements(int pos) { 4507 assert listOfActiveFormattingElements[pos] != null; 4508 listOfActiveFormattingElements[pos].release(this); 4509 if (pos == listPtr) { 4510 assert debugOnlyClearLastListSlot(); 4511 listPtr--; 4512 return; 4513 } 4514 assert pos < listPtr; 4515 System.arraycopy(listOfActiveFormattingElements, pos + 1, 4516 listOfActiveFormattingElements, pos, listPtr - pos); 4517 assert debugOnlyClearLastListSlot(); 4518 listPtr--; 4519 } 4520 4521 /** 4522 * Adoption agency algorithm. 4523 * 4524 * @param name subject as described in the specified algorithm. 4525 * @return Returns true if the algorithm has completed and there is nothing remaining to 4526 * be done. Returns false if the algorithm needs to "act as described in the 'any other 4527 * end tag' entry" as described in the specified algorithm. 4528 * @throws SAXException 4529 */ 4530 private boolean adoptionAgencyEndTag(@Local String name) throws SAXException { 4531 // This check intends to ensure that for properly nested tags, closing tags will match 4532 // against the stack instead of the listOfActiveFormattingElements. 4533 if (stack[currentPtr].ns == "http://www.w3.org/1999/xhtml" && 4534 stack[currentPtr].name == name && 4535 findInListOfActiveFormattingElements(stack[currentPtr]) == -1) { 4536 // If the current element matches the name but isn't on the list of active 4537 // formatting elements, then it is possible that the list was mangled by the Noah's Ark 4538 // clause. In this case, we want to match the end tag against the stack instead of 4539 // proceeding with the AAA algorithm that may match against the list of 4540 // active formatting elements (and possibly mangle the tree in unexpected ways). 4541 pop(); 4542 return true; 4543 } 4544 4545 // If you crash around here, perhaps some stack node variable claimed to 4546 // be a weak ref isn't. 4547 for (int i = 0; i < 8; ++i) { 4548 int formattingEltListPos = listPtr; 4549 while (formattingEltListPos > -1) { 4550 StackNode<T> listNode = listOfActiveFormattingElements[formattingEltListPos]; // weak ref 4551 if (listNode == null) { 4552 formattingEltListPos = -1; 4553 break; 4554 } else if (listNode.name == name) { 4555 break; 4556 } 4557 formattingEltListPos--; 4558 } 4559 if (formattingEltListPos == -1) { 4560 return false; 4561 } 4562 // this *looks* like a weak ref to the list of formatting elements 4563 StackNode<T> formattingElt = listOfActiveFormattingElements[formattingEltListPos]; 4564 int formattingEltStackPos = currentPtr; 4565 boolean inScope = true; 4566 while (formattingEltStackPos > -1) { 4567 StackNode<T> node = stack[formattingEltStackPos]; // weak ref 4568 if (node == formattingElt) { 4569 break; 4570 } else if (node.isScoping()) { 4571 inScope = false; 4572 } 4573 formattingEltStackPos--; 4574 } 4575 if (formattingEltStackPos == -1) { 4576 errNoElementToCloseButEndTagSeen(name); 4577 removeFromListOfActiveFormattingElements(formattingEltListPos); 4578 return true; 4579 } 4580 if (!inScope) { 4581 errNoElementToCloseButEndTagSeen(name); 4582 return true; 4583 } 4584 // stackPos now points to the formatting element and it is in scope 4585 if (formattingEltStackPos != currentPtr) { 4586 errEndTagViolatesNestingRules(name); 4587 } 4588 int furthestBlockPos = formattingEltStackPos + 1; 4589 while (furthestBlockPos <= currentPtr) { 4590 StackNode<T> node = stack[furthestBlockPos]; // weak ref 4591 assert furthestBlockPos > 0: "How is formattingEltStackPos + 1 not > 0?"; 4592 if (node.isSpecial()) { 4593 break; 4594 } 4595 furthestBlockPos++; 4596 } 4597 if (furthestBlockPos > currentPtr) { 4598 // no furthest block 4599 while (currentPtr >= formattingEltStackPos) { 4600 pop(); 4601 } 4602 removeFromListOfActiveFormattingElements(formattingEltListPos); 4603 return true; 4604 } 4605 // commonAncestor is used for running the algorithm and 4606 // insertionCommonAncestor is used for the actual insertions to 4607 // keep them depth-limited. 4608 StackNode<T> commonAncestor = stack[formattingEltStackPos - 1]; // weak ref 4609 T insertionCommonAncestor = nodeFromStackWithBlinkCompat(formattingEltStackPos - 1); // weak ref 4610 StackNode<T> furthestBlock = stack[furthestBlockPos]; // weak ref 4611 // detachFromParent(furthestBlock.node); XXX AAA CHANGE 4612 int bookmark = formattingEltListPos; 4613 int nodePos = furthestBlockPos; 4614 StackNode<T> lastNode = furthestBlock; // weak ref 4615 int j = 0; 4616 for (;;) { 4617 ++j; 4618 nodePos--; 4619 if (nodePos == formattingEltStackPos) { 4620 break; 4621 } 4622 StackNode<T> node = stack[nodePos]; // weak ref 4623 int nodeListPos = findInListOfActiveFormattingElements(node); 4624 4625 if (j > 3 && nodeListPos != -1) { 4626 removeFromListOfActiveFormattingElements(nodeListPos); 4627 4628 // Adjust the indices into the list to account 4629 // for the removal of nodeListPos. 4630 if (nodeListPos <= formattingEltListPos) { 4631 formattingEltListPos--; 4632 } 4633 if (nodeListPos <= bookmark) { 4634 bookmark--; 4635 } 4636 4637 // Update position to reflect removal from list. 4638 nodeListPos = -1; 4639 } 4640 4641 if (nodeListPos == -1) { 4642 assert formattingEltStackPos < nodePos; 4643 assert bookmark < nodePos; 4644 assert furthestBlockPos > nodePos; 4645 removeFromStack(nodePos); // node is now a bad pointer in C++ 4646 furthestBlockPos--; 4647 continue; 4648 } 4649 // now node is both on stack and in the list 4650 if (nodePos == furthestBlockPos) { 4651 bookmark = nodeListPos + 1; 4652 } 4653 // if (hasChildren(node.node)) { XXX AAA CHANGE 4654 assert node == listOfActiveFormattingElements[nodeListPos]; 4655 assert node == stack[nodePos]; 4656 T clone = createElement("http://www.w3.org/1999/xhtml", 4657 node.name, node.attributes.cloneAttributes(), insertionCommonAncestor 4658 // CPPONLY: , htmlCreator(node.getHtmlCreator()) 4659 ); 4660 StackNode<T> newNode = createStackNode(node.getFlags(), node.ns, 4661 node.name, clone, node.popName, node.attributes 4662 // CPPONLY: , node.getHtmlCreator() 4663 // [NOCPP[ 4664 , node.getLocator() 4665 // ]NOCPP] 4666 ); // creation ownership goes to stack 4667 node.dropAttributes(); // adopt ownership to newNode 4668 stack[nodePos] = newNode; 4669 newNode.retain(); // retain for list 4670 listOfActiveFormattingElements[nodeListPos] = newNode; 4671 node.release(this); // release from stack 4672 node.release(this); // release from list 4673 node = newNode; 4674 // } XXX AAA CHANGE 4675 detachFromParent(lastNode.node); 4676 appendElement(lastNode.node, nodeFromStackWithBlinkCompat(nodePos)); 4677 lastNode = node; 4678 } 4679 // If we insert into a foster parent, for simplicity, we insert 4680 // accoding to the spec without Blink's depth limit. 4681 if (commonAncestor.isFosterParenting()) { 4682 fatal(); 4683 detachFromParent(lastNode.node); 4684 insertIntoFosterParent(lastNode.node); 4685 } else { 4686 detachFromParent(lastNode.node); 4687 appendElement(lastNode.node, insertionCommonAncestor); 4688 } 4689 T clone = createElement("http://www.w3.org/1999/xhtml", 4690 formattingElt.name, 4691 formattingElt.attributes.cloneAttributes(), furthestBlock.node 4692 // CPPONLY: , htmlCreator(formattingElt.getHtmlCreator()) 4693 ); 4694 StackNode<T> formattingClone = createStackNode( 4695 formattingElt.getFlags(), formattingElt.ns, 4696 formattingElt.name, clone, formattingElt.popName, 4697 formattingElt.attributes 4698 // CPPONLY: , formattingElt.getHtmlCreator() 4699 // [NOCPP[ 4700 , errorHandler == null ? null : new TaintableLocatorImpl(tokenizer) 4701 // ]NOCPP] 4702 ); // Ownership transfers to stack below 4703 formattingElt.dropAttributes(); // transfer ownership to 4704 // formattingClone 4705 appendChildrenToNewParent(furthestBlock.node, clone); 4706 appendElement(clone, furthestBlock.node); 4707 removeFromListOfActiveFormattingElements(formattingEltListPos); 4708 insertIntoListOfActiveFormattingElements(formattingClone, bookmark); 4709 assert formattingEltStackPos < furthestBlockPos; 4710 removeFromStack(formattingEltStackPos); 4711 // furthestBlockPos is now off by one and points to the slot after 4712 // it 4713 insertIntoStack(formattingClone, furthestBlockPos); 4714 } 4715 return true; 4716 } 4717 4718 private void insertIntoStack(StackNode<T> node, int position) 4719 throws SAXException { 4720 assert currentPtr + 1 < stack.length; 4721 assert position <= currentPtr + 1; 4722 if (position == currentPtr + 1) { 4723 push(node); 4724 } else { 4725 System.arraycopy(stack, position, stack, position + 1, 4726 (currentPtr - position) + 1); 4727 currentPtr++; 4728 stack[position] = node; 4729 } 4730 } 4731 4732 private void insertIntoListOfActiveFormattingElements( 4733 StackNode<T> formattingClone, int bookmark) { 4734 formattingClone.retain(); 4735 assert listPtr + 1 < listOfActiveFormattingElements.length; 4736 if (bookmark <= listPtr) { 4737 System.arraycopy(listOfActiveFormattingElements, bookmark, 4738 listOfActiveFormattingElements, bookmark + 1, 4739 (listPtr - bookmark) + 1); 4740 } 4741 listPtr++; 4742 listOfActiveFormattingElements[bookmark] = formattingClone; 4743 } 4744 4745 private int findInListOfActiveFormattingElements(StackNode<T> node) { 4746 for (int i = listPtr; i >= 0; i--) { 4747 if (node == listOfActiveFormattingElements[i]) { 4748 return i; 4749 } 4750 } 4751 return -1; 4752 } 4753 4754 private int findInListOfActiveFormattingElementsContainsBetweenEndAndLastMarker( 4755 @Local String name) { 4756 for (int i = listPtr; i >= 0; i--) { 4757 StackNode<T> node = listOfActiveFormattingElements[i]; 4758 if (node == null) { 4759 return -1; 4760 } else if (node.name == name) { 4761 return i; 4762 } 4763 } 4764 return -1; 4765 } 4766 4767 4768 private void maybeForgetEarlierDuplicateFormattingElement( 4769 @Local String name, HtmlAttributes attributes) throws SAXException { 4770 int candidate = -1; 4771 int count = 0; 4772 for (int i = listPtr; i >= 0; i--) { 4773 StackNode<T> node = listOfActiveFormattingElements[i]; 4774 if (node == null) { 4775 break; 4776 } 4777 if (node.name == name && node.attributes.equalsAnother(attributes)) { 4778 candidate = i; 4779 ++count; 4780 } 4781 } 4782 if (count >= 3) { 4783 removeFromListOfActiveFormattingElements(candidate); 4784 } 4785 } 4786 4787 private int findLastOrRoot(@Local String name) { 4788 for (int i = currentPtr; i > 0; i--) { 4789 if (stack[i].ns == "http://www.w3.org/1999/xhtml" && stack[i].name == name) { 4790 return i; 4791 } 4792 } 4793 return 0; 4794 } 4795 4796 private int findLastOrRoot(int group) { 4797 for (int i = currentPtr; i > 0; i--) { 4798 if (stack[i].ns == "http://www.w3.org/1999/xhtml" && stack[i].getGroup() == group) { 4799 return i; 4800 } 4801 } 4802 return 0; 4803 } 4804 4805 /** 4806 * Attempt to add attribute to the body element. 4807 * @param attributes the attributes 4808 * @return <code>true</code> iff the attributes were added 4809 * @throws SAXException 4810 */ 4811 private boolean addAttributesToBody(HtmlAttributes attributes) 4812 throws SAXException { 4813 // [NOCPP[ 4814 checkAttributes(attributes, "http://www.w3.org/1999/xhtml"); 4815 // ]NOCPP] 4816 if (currentPtr >= 1) { 4817 StackNode<T> body = stack[1]; 4818 if (body.getGroup() == TreeBuilder.BODY) { 4819 addAttributesToElement(body.node, attributes); 4820 return true; 4821 } 4822 } 4823 return false; 4824 } 4825 4826 private void addAttributesToHtml(HtmlAttributes attributes) 4827 throws SAXException { 4828 // [NOCPP[ 4829 checkAttributes(attributes, "http://www.w3.org/1999/xhtml"); 4830 // ]NOCPP] 4831 addAttributesToElement(stack[0].node, attributes); 4832 } 4833 4834 private void pushHeadPointerOntoStack() throws SAXException { 4835 assert headPointer != null; 4836 assert mode == AFTER_HEAD; 4837 fatal(); 4838 silentPush(createStackNode(ElementName.HEAD, headPointer 4839 // [NOCPP[ 4840 , errorHandler == null ? null : new TaintableLocatorImpl(tokenizer) 4841 // ]NOCPP] 4842 )); 4843 } 4844 4845 /** 4846 * @throws SAXException 4847 * 4848 */ 4849 private void reconstructTheActiveFormattingElements() throws SAXException { 4850 if (listPtr == -1) { 4851 return; 4852 } 4853 StackNode<T> mostRecent = listOfActiveFormattingElements[listPtr]; 4854 if (mostRecent == null || isInStack(mostRecent)) { 4855 return; 4856 } 4857 int entryPos = listPtr; 4858 for (;;) { 4859 entryPos--; 4860 if (entryPos == -1) { 4861 break; 4862 } 4863 if (listOfActiveFormattingElements[entryPos] == null) { 4864 break; 4865 } 4866 if (isInStack(listOfActiveFormattingElements[entryPos])) { 4867 break; 4868 } 4869 } 4870 while (entryPos < listPtr) { 4871 entryPos++; 4872 StackNode<T> entry = listOfActiveFormattingElements[entryPos]; 4873 StackNode<T> current = stack[currentPtr]; 4874 4875 T clone; 4876 if (current.isFosterParenting()) { 4877 clone = createAndInsertFosterParentedElement("http://www.w3.org/1999/xhtml", entry.name, 4878 entry.attributes.cloneAttributes() 4879 // CPPONLY: , htmlCreator(entry.getHtmlCreator()) 4880 ); 4881 } else { 4882 T currentNode = nodeFromStackWithBlinkCompat(currentPtr); 4883 clone = createElement("http://www.w3.org/1999/xhtml", entry.name, 4884 entry.attributes.cloneAttributes(), currentNode 4885 // CPPONLY: , htmlCreator(entry.getHtmlCreator()) 4886 ); 4887 appendElement(clone, currentNode); 4888 } 4889 4890 StackNode<T> entryClone = createStackNode(entry.getFlags(), 4891 entry.ns, entry.name, clone, entry.popName, 4892 entry.attributes 4893 // CPPONLY: , entry.getHtmlCreator() 4894 // [NOCPP[ 4895 , entry.getLocator() 4896 // ]NOCPP] 4897 ); 4898 4899 entry.dropAttributes(); // transfer ownership to entryClone 4900 4901 push(entryClone); 4902 // stack takes ownership of the local variable 4903 listOfActiveFormattingElements[entryPos] = entryClone; 4904 // overwriting the old entry on the list, so release & retain 4905 entry.release(this); 4906 entryClone.retain(); 4907 } 4908 } 4909 4910 void notifyUnusedStackNode(int idxInStackNodes) { 4911 // stackNodesIdx is the earliest possible index of a stack node that might be unused, 4912 // so update the index if necessary. 4913 if (idxInStackNodes < stackNodesIdx) { 4914 stackNodesIdx = idxInStackNodes; 4915 } 4916 } 4917 4918 @SuppressWarnings("unchecked") private StackNode<T> getUnusedStackNode() { 4919 // Search for an unused stack node. 4920 while (stackNodesIdx < numStackNodes) { 4921 if (stackNodes[stackNodesIdx].isUnused()) { 4922 return stackNodes[stackNodesIdx++]; 4923 } 4924 stackNodesIdx++; 4925 } 4926 4927 if (stackNodesIdx < stackNodes.length) { 4928 // No unused stack nodes, but there is still space in the storage array. 4929 stackNodes[stackNodesIdx] = new StackNode<T>(stackNodesIdx); 4930 numStackNodes++; 4931 return stackNodes[stackNodesIdx++]; 4932 } 4933 4934 // Could not find an unused stack node and storage array is full. 4935 StackNode<T>[] newStack = new StackNode[stackNodes.length + 64]; 4936 System.arraycopy(stackNodes, 0, newStack, 0, stackNodes.length); 4937 stackNodes = newStack; 4938 4939 // Create a new stack node and return it. 4940 stackNodes[stackNodesIdx] = new StackNode<T>(stackNodesIdx); 4941 numStackNodes++; 4942 return stackNodes[stackNodesIdx++]; 4943 } 4944 4945 private StackNode<T> createStackNode(int flags, @NsUri String ns, @Local String name, T node, 4946 @Local String popName, HtmlAttributes attributes 4947 // CPPONLY: , @HtmlCreator Object htmlCreator 4948 // [NOCPP[ 4949 , TaintableLocatorImpl locator 4950 // ]NOCPP] 4951 ) { 4952 StackNode<T> instance = getUnusedStackNode(); 4953 instance.setValues(flags, ns, name, node, popName, attributes 4954 // CPPONLY: , htmlCreator 4955 // [NOCPP[ 4956 , locator 4957 // ]NOCPP] 4958 ); 4959 return instance; 4960 } 4961 4962 private StackNode<T> createStackNode(ElementName elementName, T node 4963 // [NOCPP[ 4964 , TaintableLocatorImpl locator 4965 // ]NOCPP] 4966 ) { 4967 StackNode<T> instance = getUnusedStackNode(); 4968 instance.setValues(elementName, node 4969 // [NOCPP[ 4970 , locator 4971 // ]NOCPP] 4972 ); 4973 return instance; 4974 } 4975 4976 private StackNode<T> createStackNode(ElementName elementName, T node, HtmlAttributes attributes 4977 // [NOCPP[ 4978 , TaintableLocatorImpl locator 4979 // ]NOCPP] 4980 ) { 4981 StackNode<T> instance = getUnusedStackNode(); 4982 instance.setValues(elementName, node, attributes 4983 // [NOCPP[ 4984 , locator 4985 // ]NOCPP] 4986 ); 4987 return instance; 4988 } 4989 4990 private StackNode<T> createStackNode(ElementName elementName, T node, @Local String popName 4991 // [NOCPP[ 4992 , TaintableLocatorImpl locator 4993 // ]NOCPP] 4994 ) { 4995 StackNode<T> instance = getUnusedStackNode(); 4996 instance.setValues(elementName, node, popName 4997 // [NOCPP[ 4998 , locator 4999 // ]NOCPP] 5000 ); 5001 return instance; 5002 } 5003 5004 private StackNode<T> createStackNode(ElementName elementName, @Local String popName, T node 5005 // [NOCPP[ 5006 , TaintableLocatorImpl locator 5007 // ]NOCPP] 5008 ) { 5009 StackNode<T> instance = getUnusedStackNode(); 5010 instance.setValues(elementName, popName, node 5011 // [NOCPP[ 5012 , locator 5013 // ]NOCPP] 5014 ); 5015 return instance; 5016 } 5017 5018 private StackNode<T> createStackNode(ElementName elementName, T node, @Local String popName, 5019 boolean markAsIntegrationPoint 5020 // [NOCPP[ 5021 , TaintableLocatorImpl locator 5022 // ]NOCPP] 5023 ) { 5024 StackNode<T> instance = getUnusedStackNode(); 5025 instance.setValues(elementName, node, popName, markAsIntegrationPoint 5026 // [NOCPP[ 5027 , locator 5028 // ]NOCPP] 5029 ); 5030 return instance; 5031 } 5032 5033 private void insertIntoFosterParent(T child) throws SAXException { 5034 int tablePos = findLastOrRoot(TreeBuilder.TABLE); 5035 int templatePos = findLastOrRoot(TreeBuilder.TEMPLATE); 5036 5037 if (templatePos >= tablePos) { 5038 appendElement(child, stack[templatePos].node); 5039 return; 5040 } 5041 5042 StackNode<T> node = stack[tablePos]; 5043 insertFosterParentedChild(child, node.node, stack[tablePos - 1].node); 5044 } 5045 5046 private T createAndInsertFosterParentedElement(@NsUri String ns, @Local String name, 5047 HtmlAttributes attributes 5048 // CPPONLY: , @Creator Object creator 5049 ) throws SAXException { 5050 return createAndInsertFosterParentedElement(ns, name, attributes, null 5051 // CPPONLY: , creator 5052 ); 5053 } 5054 5055 private T createAndInsertFosterParentedElement(@NsUri String ns, @Local String name, 5056 HtmlAttributes attributes, T form 5057 // CPPONLY: , @Creator Object creator 5058 ) throws SAXException { 5059 int tablePos = findLastOrRoot(TreeBuilder.TABLE); 5060 int templatePos = findLastOrRoot(TreeBuilder.TEMPLATE); 5061 5062 if (templatePos >= tablePos) { 5063 T child = createElement(ns, name, attributes, form, stack[templatePos].node 5064 // CPPONLY: , creator 5065 ); 5066 appendElement(child, stack[templatePos].node); 5067 return child; 5068 } 5069 5070 StackNode<T> node = stack[tablePos]; 5071 return createAndInsertFosterParentedElement(ns, name, attributes, form, node.node, stack[tablePos - 1].node 5072 // CPPONLY: , creator 5073 ); 5074 } 5075 5076 private boolean isInStack(StackNode<T> node) { 5077 for (int i = currentPtr; i >= 0; i--) { 5078 if (stack[i] == node) { 5079 return true; 5080 } 5081 } 5082 return false; 5083 } 5084 5085 private void popTemplateMode() { 5086 templateModePtr--; 5087 } 5088 5089 private void pop() throws SAXException { 5090 StackNode<T> node = stack[currentPtr]; 5091 assert debugOnlyClearLastStackSlot(); 5092 currentPtr--; 5093 elementPopped(node.ns, node.popName, node.node); 5094 node.release(this); 5095 } 5096 5097 private void popForeign(int origPos, int eltPos) throws SAXException { 5098 StackNode<T> node = stack[currentPtr]; 5099 if (origPos != currentPtr || eltPos != currentPtr) { 5100 markMalformedIfScript(node.node); 5101 } 5102 assert debugOnlyClearLastStackSlot(); 5103 currentPtr--; 5104 elementPopped(node.ns, node.popName, node.node); 5105 node.release(this); 5106 } 5107 5108 private void silentPop() throws SAXException { 5109 StackNode<T> node = stack[currentPtr]; 5110 assert debugOnlyClearLastStackSlot(); 5111 currentPtr--; 5112 node.release(this); 5113 } 5114 5115 private void popOnEof() throws SAXException { 5116 StackNode<T> node = stack[currentPtr]; 5117 assert debugOnlyClearLastStackSlot(); 5118 currentPtr--; 5119 markMalformedIfScript(node.node); 5120 elementPopped(node.ns, node.popName, node.node); 5121 node.release(this); 5122 } 5123 5124 // [NOCPP[ 5125 private void checkAttributes(HtmlAttributes attributes, @NsUri String ns) 5126 throws SAXException { 5127 if (errorHandler != null) { 5128 int len = attributes.getXmlnsLength(); 5129 for (int i = 0; i < len; i++) { 5130 AttributeName name = attributes.getXmlnsAttributeName(i); 5131 if (name == AttributeName.XMLNS) { 5132 String xmlns = attributes.getXmlnsValue(i); 5133 if (!ns.equals(xmlns)) { 5134 err("Bad value \u201C" 5135 + xmlns 5136 + "\u201D for the attribute \u201Cxmlns\u201D (only \u201C" 5137 + ns + "\u201D permitted here)."); 5138 switch (namePolicy) { 5139 case ALTER_INFOSET: 5140 // fall through 5141 case ALLOW: 5142 warn("Attribute \u201Cxmlns\u201D is not serializable as XML 1.0."); 5143 break; 5144 case FATAL: 5145 fatal("Attribute \u201Cxmlns\u201D is not serializable as XML 1.0."); 5146 break; 5147 } 5148 } 5149 } else if (ns != "http://www.w3.org/1999/xhtml" 5150 && name == AttributeName.XMLNS_XLINK) { 5151 String xmlns = attributes.getXmlnsValue(i); 5152 if (!"http://www.w3.org/1999/xlink".equals(xmlns)) { 5153 err("Bad value \u201C" 5154 + xmlns 5155 + "\u201D for the attribute \u201Cxmlns:link\u201D (only \u201Chttp://www.w3.org/1999/xlink\u201D permitted here)."); 5156 switch (namePolicy) { 5157 case ALTER_INFOSET: 5158 // fall through 5159 case ALLOW: 5160 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."); 5161 break; 5162 case FATAL: 5163 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."); 5164 break; 5165 } 5166 } 5167 } else { 5168 err("Attribute \u201C" + attributes.getXmlnsLocalName(i) 5169 + "\u201D not allowed here."); 5170 switch (namePolicy) { 5171 case ALTER_INFOSET: 5172 // fall through 5173 case ALLOW: 5174 warn("Attribute with the local name \u201C" 5175 + attributes.getXmlnsLocalName(i) 5176 + "\u201D is not serializable as XML 1.0."); 5177 break; 5178 case FATAL: 5179 fatal("Attribute with the local name \u201C" 5180 + attributes.getXmlnsLocalName(i) 5181 + "\u201D is not serializable as XML 1.0."); 5182 break; 5183 } 5184 } 5185 } 5186 } 5187 attributes.processNonNcNames(this, namePolicy); 5188 } 5189 5190 private String checkPopName(@Local String name) throws SAXException { 5191 if (NCName.isNCName(name)) { 5192 return name; 5193 } else { 5194 switch (namePolicy) { 5195 case ALLOW: 5196 warn("Element name \u201C" + name 5197 + "\u201D cannot be represented as XML 1.0."); 5198 return name; 5199 case ALTER_INFOSET: 5200 warn("Element name \u201C" + name 5201 + "\u201D cannot be represented as XML 1.0."); 5202 return NCName.escapeName(name); 5203 case FATAL: 5204 fatal("Element name \u201C" + name 5205 + "\u201D cannot be represented as XML 1.0."); 5206 } 5207 } 5208 return null; // keep compiler happy 5209 } 5210 5211 // ]NOCPP] 5212 5213 private void appendHtmlElementToDocumentAndPush(HtmlAttributes attributes) 5214 throws SAXException { 5215 // [NOCPP[ 5216 checkAttributes(attributes, "http://www.w3.org/1999/xhtml"); 5217 // ]NOCPP] 5218 T elt = createHtmlElementSetAsRoot(attributes); 5219 StackNode<T> node = createStackNode(ElementName.HTML, 5220 elt 5221 // [NOCPP[ 5222 , errorHandler == null ? null : new TaintableLocatorImpl(tokenizer) 5223 // ]NOCPP] 5224 ); 5225 push(node); 5226 } 5227 5228 private void appendHtmlElementToDocumentAndPush() throws SAXException { 5229 appendHtmlElementToDocumentAndPush(tokenizer.emptyAttributes()); 5230 } 5231 5232 private void appendToCurrentNodeAndPushHeadElement(HtmlAttributes attributes) 5233 throws SAXException { 5234 // [NOCPP[ 5235 checkAttributes(attributes, "http://www.w3.org/1999/xhtml"); 5236 // ]NOCPP] 5237 T currentNode = nodeFromStackWithBlinkCompat(currentPtr); 5238 T elt = createElement("http://www.w3.org/1999/xhtml", "head", attributes, currentNode 5239 /* 5240 * head uses NS_NewHTMLSharedElement creator 5241 */ 5242 // CPPONLY: , htmlCreator(NS_NewHTMLSharedElement) 5243 ); 5244 appendElement(elt, currentNode); 5245 headPointer = elt; 5246 StackNode<T> node = createStackNode(ElementName.HEAD, 5247 elt 5248 // [NOCPP[ 5249 , errorHandler == null ? null : new TaintableLocatorImpl(tokenizer) 5250 // ]NOCPP] 5251 ); 5252 push(node); 5253 } 5254 5255 private void appendToCurrentNodeAndPushBodyElement(HtmlAttributes attributes) 5256 throws SAXException { 5257 appendToCurrentNodeAndPushElement(ElementName.BODY, 5258 attributes); 5259 } 5260 5261 private void appendToCurrentNodeAndPushBodyElement() throws SAXException { 5262 appendToCurrentNodeAndPushBodyElement(tokenizer.emptyAttributes()); 5263 } 5264 5265 private void appendToCurrentNodeAndPushFormElementMayFoster( 5266 HtmlAttributes attributes) throws SAXException { 5267 // [NOCPP[ 5268 checkAttributes(attributes, "http://www.w3.org/1999/xhtml"); 5269 // ]NOCPP] 5270 5271 T elt; 5272 StackNode<T> current = stack[currentPtr]; 5273 if (current.isFosterParenting()) { 5274 fatal(); 5275 elt = createAndInsertFosterParentedElement("http://www.w3.org/1999/xhtml", "form", attributes 5276 // CPPONLY: , htmlCreator(NS_NewHTMLFormElement) 5277 ); 5278 } else { 5279 T currentNode = nodeFromStackWithBlinkCompat(currentPtr); 5280 elt = createElement("http://www.w3.org/1999/xhtml", "form", attributes, currentNode 5281 // CPPONLY: , htmlCreator(NS_NewHTMLFormElement) 5282 ); 5283 appendElement(elt, currentNode); 5284 } 5285 5286 if (!isTemplateContents()) { 5287 formPointer = elt; 5288 } 5289 5290 StackNode<T> node = createStackNode(ElementName.FORM, 5291 elt 5292 // [NOCPP[ 5293 , errorHandler == null ? null : new TaintableLocatorImpl(tokenizer) 5294 // ]NOCPP] 5295 ); 5296 push(node); 5297 } 5298 5299 private void appendToCurrentNodeAndPushFormattingElementMayFoster( 5300 ElementName elementName, HtmlAttributes attributes) 5301 throws SAXException { 5302 // [NOCPP[ 5303 checkAttributes(attributes, "http://www.w3.org/1999/xhtml"); 5304 // ]NOCPP] 5305 // This method can't be called for custom elements 5306 HtmlAttributes clone = attributes.cloneAttributes(); 5307 // Attributes must not be read after calling createElement, because 5308 // createElement may delete attributes in C++. 5309 T elt; 5310 StackNode<T> current = stack[currentPtr]; 5311 if (current.isFosterParenting()) { 5312 fatal(); 5313 elt = createAndInsertFosterParentedElement("http://www.w3.org/1999/xhtml", elementName.getName(), attributes 5314 // CPPONLY: , htmlCreator(elementName.getHtmlCreator()) 5315 ); 5316 } else { 5317 T currentNode = nodeFromStackWithBlinkCompat(currentPtr); 5318 elt = createElement("http://www.w3.org/1999/xhtml", elementName.getName(), attributes, currentNode 5319 // CPPONLY: , htmlCreator(elementName.getHtmlCreator()) 5320 ); 5321 appendElement(elt, currentNode); 5322 } 5323 StackNode<T> node = createStackNode(elementName, elt, clone 5324 // [NOCPP[ 5325 , errorHandler == null ? null : new TaintableLocatorImpl(tokenizer) 5326 // ]NOCPP] 5327 ); 5328 push(node); 5329 append(node); 5330 node.retain(); // append doesn't retain itself 5331 } 5332 5333 private void appendToCurrentNodeAndPushElement(ElementName elementName, 5334 HtmlAttributes attributes) 5335 throws SAXException { 5336 // [NOCPP[ 5337 checkAttributes(attributes, "http://www.w3.org/1999/xhtml"); 5338 // ]NOCPP] 5339 // This method can't be called for custom elements 5340 T currentNode = nodeFromStackWithBlinkCompat(currentPtr); 5341 T elt = createElement("http://www.w3.org/1999/xhtml", elementName.getName(), attributes, currentNode 5342 // CPPONLY: , htmlCreator(elementName.getHtmlCreator()) 5343 ); 5344 if (ElementName.TEMPLATE == elementName) { 5345 T root = getDeclarativeShadowRoot(currentNode, elt, attributes); 5346 if (root != null) { 5347 setDocumentFragmentForTemplate(elt, root); 5348 elt = root; 5349 } else { 5350 appendElement(elt, currentNode); 5351 elt = getDocumentFragmentForTemplate(elt); 5352 } 5353 } else { 5354 appendElement(elt, currentNode); 5355 } 5356 StackNode<T> node = createStackNode(elementName, elt 5357 // [NOCPP[ 5358 , errorHandler == null ? null : new TaintableLocatorImpl(tokenizer) 5359 // ]NOCPP] 5360 ); 5361 push(node); 5362 } 5363 5364 private void appendToCurrentNodeAndPushElementMayFoster(ElementName elementName, 5365 HtmlAttributes attributes) 5366 throws SAXException { 5367 @Local String popName = elementName.getName(); 5368 // [NOCPP[ 5369 checkAttributes(attributes, "http://www.w3.org/1999/xhtml"); 5370 if (!elementName.isInterned()) { 5371 popName = checkPopName(popName); 5372 } 5373 // ]NOCPP] 5374 T elt; 5375 StackNode<T> current = stack[currentPtr]; 5376 if (current.isFosterParenting()) { 5377 fatal(); 5378 elt = createAndInsertFosterParentedElement("http://www.w3.org/1999/xhtml", popName, attributes 5379 // CPPONLY: , htmlCreator(elementName.getHtmlCreator()) 5380 ); 5381 } else { 5382 T currentNode = nodeFromStackWithBlinkCompat(currentPtr); 5383 elt = createElement("http://www.w3.org/1999/xhtml", popName, attributes, currentNode 5384 // CPPONLY: , htmlCreator(elementName.getHtmlCreator()) 5385 ); 5386 appendElement(elt, currentNode); 5387 } 5388 StackNode<T> node = createStackNode(elementName, elt, popName 5389 // [NOCPP[ 5390 , errorHandler == null ? null : new TaintableLocatorImpl(tokenizer) 5391 // ]NOCPP] 5392 ); 5393 push(node); 5394 } 5395 5396 private void appendToCurrentNodeAndPushElementMayFosterMathML( 5397 ElementName elementName, HtmlAttributes attributes) 5398 throws SAXException { 5399 @Local String popName = elementName.getName(); 5400 // [NOCPP[ 5401 checkAttributes(attributes, "http://www.w3.org/1998/Math/MathML"); 5402 if (!elementName.isInterned()) { 5403 popName = checkPopName(popName); 5404 } 5405 // ]NOCPP] 5406 boolean markAsHtmlIntegrationPoint = false; 5407 if (ElementName.ANNOTATION_XML == elementName 5408 && annotationXmlEncodingPermitsHtml(attributes)) { 5409 markAsHtmlIntegrationPoint = true; 5410 } 5411 // Attributes must not be read after calling createElement(), since 5412 // createElement may delete the object in C++. 5413 T elt; 5414 StackNode<T> current = stack[currentPtr]; 5415 if (current.isFosterParenting()) { 5416 fatal(); 5417 elt = createAndInsertFosterParentedElement("http://www.w3.org/1998/Math/MathML", popName, attributes 5418 // CPPONLY: , htmlCreator(null) 5419 ); 5420 } else { 5421 T currentNode = nodeFromStackWithBlinkCompat(currentPtr); 5422 elt = createElement("http://www.w3.org/1998/Math/MathML", popName, attributes, currentNode 5423 // CPPONLY: , htmlCreator(null) 5424 ); 5425 appendElement(elt, currentNode); 5426 } 5427 StackNode<T> node = createStackNode(elementName, elt, popName, 5428 markAsHtmlIntegrationPoint 5429 // [NOCPP[ 5430 , errorHandler == null ? null : new TaintableLocatorImpl(tokenizer) 5431 // ]NOCPP] 5432 ); 5433 push(node); 5434 } 5435 5436 // [NOCPP[ 5437 T getDocumentFragmentForTemplate(T template) { 5438 return template; 5439 } 5440 5441 void setDocumentFragmentForTemplate(T template, T fragment) { 5442 } 5443 5444 T getShadowRootFromHost(T host, T template, String shadowRootMode, 5445 boolean shadowRootIsClonable, boolean shadowRootIsSerializable, boolean shadowRootDelegatesFocus, 5446 String shadowRootReferenceTarget) { 5447 return null; 5448 } 5449 5450 T getFormPointerForContext(T context) { 5451 return null; 5452 } 5453 // ]NOCPP] 5454 5455 private boolean annotationXmlEncodingPermitsHtml(HtmlAttributes attributes) { 5456 String encoding = attributes.getValue(AttributeName.ENCODING); 5457 if (encoding == null) { 5458 return false; 5459 } 5460 return Portability.lowerCaseLiteralEqualsIgnoreAsciiCaseString( 5461 "application/xhtml+xml", encoding) 5462 || Portability.lowerCaseLiteralEqualsIgnoreAsciiCaseString( 5463 "text/html", encoding); 5464 } 5465 5466 private void appendToCurrentNodeAndPushElementMayFosterSVG( 5467 ElementName elementName, HtmlAttributes attributes) 5468 throws SAXException { 5469 @Local String popName = elementName.getCamelCaseName(); 5470 // [NOCPP[ 5471 checkAttributes(attributes, "http://www.w3.org/2000/svg"); 5472 if (!elementName.isInterned()) { 5473 popName = checkPopName(popName); 5474 } 5475 // ]NOCPP] 5476 T elt; 5477 StackNode<T> current = stack[currentPtr]; 5478 if (current.isFosterParenting()) { 5479 fatal(); 5480 elt = createAndInsertFosterParentedElement("http://www.w3.org/2000/svg", popName, attributes 5481 // CPPONLY: , svgCreator(elementName.getSvgCreator()) 5482 ); 5483 } else { 5484 T currentNode = nodeFromStackWithBlinkCompat(currentPtr); 5485 elt = createElement("http://www.w3.org/2000/svg", popName, attributes, currentNode 5486 // CPPONLY: , svgCreator(elementName.getSvgCreator()) 5487 ); 5488 appendElement(elt, currentNode); 5489 } 5490 StackNode<T> node = createStackNode(elementName, popName, elt 5491 // [NOCPP[ 5492 , errorHandler == null ? null : new TaintableLocatorImpl(tokenizer) 5493 // ]NOCPP] 5494 ); 5495 push(node); 5496 } 5497 5498 private void appendToCurrentNodeAndPushElementMayFoster(ElementName elementName, 5499 HtmlAttributes attributes, T form) 5500 throws SAXException { 5501 // [NOCPP[ 5502 checkAttributes(attributes, "http://www.w3.org/1999/xhtml"); 5503 // ]NOCPP] 5504 // Can't be called for custom elements 5505 T elt; 5506 T formOwner = form == null || fragment || isTemplateContents() ? null : form; 5507 StackNode<T> current = stack[currentPtr]; 5508 if (current.isFosterParenting()) { 5509 fatal(); 5510 elt = createAndInsertFosterParentedElement("http://www.w3.org/1999/xhtml", elementName.getName(), 5511 attributes, formOwner 5512 // CPPONLY: , htmlCreator(elementName.getHtmlCreator()) 5513 ); 5514 } else { 5515 T currentNode = nodeFromStackWithBlinkCompat(currentPtr); 5516 elt = createElement("http://www.w3.org/1999/xhtml", elementName.getName(), 5517 attributes, formOwner, currentNode 5518 // CPPONLY: , htmlCreator(elementName.getHtmlCreator()) 5519 ); 5520 appendElement(elt, currentNode); 5521 } 5522 StackNode<T> node = createStackNode(elementName, elt 5523 // [NOCPP[ 5524 , errorHandler == null ? null : new TaintableLocatorImpl(tokenizer) 5525 // ]NOCPP] 5526 ); 5527 push(node); 5528 } 5529 5530 private void appendVoidElementToCurrent( 5531 ElementName elementName, HtmlAttributes attributes) 5532 throws SAXException { 5533 @Local String popName = elementName.getName(); 5534 // [NOCPP[ 5535 checkAttributes(attributes, "http://www.w3.org/1999/xhtml"); 5536 if (!elementName.isInterned()) { 5537 popName = checkPopName(popName); 5538 } 5539 // ]NOCPP] 5540 T currentNode = nodeFromStackWithBlinkCompat(currentPtr); 5541 T elt = createElement("http://www.w3.org/1999/xhtml", popName, attributes, currentNode 5542 // CPPONLY: , htmlCreator(elementName.getHtmlCreator()) 5543 ); 5544 appendElement(elt, currentNode); 5545 elementPushed("http://www.w3.org/1999/xhtml", popName, elt); 5546 elementPopped("http://www.w3.org/1999/xhtml", popName, elt); 5547 } 5548 5549 private void appendVoidElementToCurrentMayFoster( 5550 ElementName elementName, HtmlAttributes attributes, T form) throws SAXException { 5551 @Local String name = elementName.getName(); 5552 // [NOCPP[ 5553 checkAttributes(attributes, "http://www.w3.org/1999/xhtml"); 5554 // ]NOCPP] 5555 // Can't be called for custom elements 5556 T elt; 5557 T formOwner = form == null || fragment || isTemplateContents() ? null : form; 5558 StackNode<T> current = stack[currentPtr]; 5559 if (current.isFosterParenting()) { 5560 fatal(); 5561 elt = createAndInsertFosterParentedElement("http://www.w3.org/1999/xhtml", name, 5562 attributes, formOwner 5563 // CPPONLY: , htmlCreator(elementName.getHtmlCreator()) 5564 ); 5565 } else { 5566 T currentNode = nodeFromStackWithBlinkCompat(currentPtr); 5567 elt = createElement("http://www.w3.org/1999/xhtml", name, 5568 5569 attributes, formOwner, currentNode 5570 // CPPONLY: , htmlCreator(elementName.getHtmlCreator()) 5571 ); 5572 appendElement(elt, currentNode); 5573 } 5574 elementPushed("http://www.w3.org/1999/xhtml", name, elt); 5575 elementPopped("http://www.w3.org/1999/xhtml", name, elt); 5576 } 5577 5578 private void appendVoidElementToCurrentMayFoster( 5579 ElementName elementName, HtmlAttributes attributes) 5580 throws SAXException { 5581 @Local String popName = elementName.getName(); 5582 // [NOCPP[ 5583 checkAttributes(attributes, "http://www.w3.org/1999/xhtml"); 5584 if (!elementName.isInterned()) { 5585 popName = checkPopName(popName); 5586 } 5587 // ]NOCPP] 5588 T elt; 5589 StackNode<T> current = stack[currentPtr]; 5590 if (current.isFosterParenting()) { 5591 fatal(); 5592 elt = createAndInsertFosterParentedElement("http://www.w3.org/1999/xhtml", popName, attributes 5593 // CPPONLY: , htmlCreator(elementName.getHtmlCreator()) 5594 ); 5595 } else { 5596 T currentNode = nodeFromStackWithBlinkCompat(currentPtr); 5597 elt = createElement("http://www.w3.org/1999/xhtml", popName, attributes, currentNode 5598 // CPPONLY: , htmlCreator(elementName.getHtmlCreator()) 5599 ); 5600 appendElement(elt, currentNode); 5601 } 5602 elementPushed("http://www.w3.org/1999/xhtml", popName, elt); 5603 elementPopped("http://www.w3.org/1999/xhtml", popName, elt); 5604 } 5605 5606 private void appendVoidElementToCurrentMayFosterSVG( 5607 ElementName elementName, HtmlAttributes attributes) 5608 throws SAXException { 5609 @Local String popName = elementName.getCamelCaseName(); 5610 // [NOCPP[ 5611 checkAttributes(attributes, "http://www.w3.org/2000/svg"); 5612 if (!elementName.isInterned()) { 5613 popName = checkPopName(popName); 5614 } 5615 // ]NOCPP] 5616 T elt; 5617 StackNode<T> current = stack[currentPtr]; 5618 if (current.isFosterParenting()) { 5619 fatal(); 5620 elt = createAndInsertFosterParentedElement("http://www.w3.org/2000/svg", popName, attributes 5621 // CPPONLY: , svgCreator(elementName.getSvgCreator()) 5622 ); 5623 } else { 5624 T currentNode = nodeFromStackWithBlinkCompat(currentPtr); 5625 elt = createElement("http://www.w3.org/2000/svg", popName, attributes, currentNode 5626 // CPPONLY: , svgCreator(elementName.getSvgCreator()) 5627 ); 5628 appendElement(elt, currentNode); 5629 } 5630 elementPushed("http://www.w3.org/2000/svg", popName, elt); 5631 elementPopped("http://www.w3.org/2000/svg", popName, elt); 5632 } 5633 5634 private void appendVoidElementToCurrentMayFosterMathML( 5635 ElementName elementName, HtmlAttributes attributes) 5636 throws SAXException { 5637 @Local String popName = elementName.getName(); 5638 // [NOCPP[ 5639 checkAttributes(attributes, "http://www.w3.org/1998/Math/MathML"); 5640 if (!elementName.isInterned()) { 5641 popName = checkPopName(popName); 5642 } 5643 // ]NOCPP] 5644 T elt; 5645 StackNode<T> current = stack[currentPtr]; 5646 if (current.isFosterParenting()) { 5647 fatal(); 5648 elt = createAndInsertFosterParentedElement("http://www.w3.org/1998/Math/MathML", popName, attributes 5649 // CPPONLY: , htmlCreator(null) 5650 ); 5651 } else { 5652 T currentNode = nodeFromStackWithBlinkCompat(currentPtr); 5653 elt = createElement("http://www.w3.org/1998/Math/MathML", popName, attributes, currentNode 5654 // CPPONLY: , htmlCreator(null) 5655 ); 5656 appendElement(elt, currentNode); 5657 } 5658 elementPushed("http://www.w3.org/1998/Math/MathML", popName, elt); 5659 elementPopped("http://www.w3.org/1998/Math/MathML", popName, elt); 5660 } 5661 5662 private void appendVoidInputToCurrent(HtmlAttributes attributes, T form) throws SAXException { 5663 // [NOCPP[ 5664 checkAttributes(attributes, "http://www.w3.org/1999/xhtml"); 5665 // ]NOCPP] 5666 // Can't be called for custom elements 5667 T currentNode = nodeFromStackWithBlinkCompat(currentPtr); 5668 T elt = createElement("http://www.w3.org/1999/xhtml", "input", attributes, 5669 form == null || fragment || isTemplateContents() ? null : form, currentNode 5670 // CPPONLY: , htmlCreator(NS_NewHTMLInputElement) 5671 ); 5672 appendElement(elt, currentNode); 5673 elementPushed("http://www.w3.org/1999/xhtml", "input", elt); 5674 elementPopped("http://www.w3.org/1999/xhtml", "input", elt); 5675 } 5676 5677 private void appendVoidFormToCurrent(HtmlAttributes attributes) throws SAXException { 5678 // [NOCPP[ 5679 checkAttributes(attributes, "http://www.w3.org/1999/xhtml"); 5680 // ]NOCPP] 5681 T currentNode = nodeFromStackWithBlinkCompat(currentPtr); 5682 T elt = createElement("http://www.w3.org/1999/xhtml", "form", 5683 attributes, currentNode 5684 // CPPONLY: , htmlCreator(NS_NewHTMLFormElement) 5685 ); 5686 formPointer = elt; 5687 // ownership transferred to form pointer 5688 appendElement(elt, currentNode); 5689 elementPushed("http://www.w3.org/1999/xhtml", "form", elt); 5690 elementPopped("http://www.w3.org/1999/xhtml", "form", elt); 5691 } 5692 5693 // [NOCPP[ 5694 5695 private final void accumulateCharactersForced(@Const @NoLength char[] buf, 5696 int start, int length) throws SAXException { 5697 System.arraycopy(buf, start, charBuffer, charBufferLen, length); 5698 charBufferLen += length; 5699 } 5700 5701 @Override public void ensureBufferSpace(int inputLength) 5702 throws SAXException { 5703 // TODO: Unify Tokenizer.strBuf and TreeBuilder.charBuffer so that 5704 // this method becomes unnecessary. 5705 int worstCase = charBufferLen + inputLength; 5706 if (charBuffer == null) { 5707 // Add an arbitrary small value to avoid immediate reallocation 5708 // once there are a few characters in the buffer. 5709 charBuffer = new char[worstCase + 128]; 5710 } else if (worstCase > charBuffer.length) { 5711 // HotSpot reportedly allocates memory with 8-byte accuracy, so 5712 // there's no point in trying to do math here to avoid slop. 5713 // Maybe we should add some small constant to worstCase here 5714 // but not doing that without profiling. In C++ with jemalloc, 5715 // the corresponding method should do math to round up here 5716 // to avoid slop. 5717 char[] newBuf = new char[worstCase]; 5718 System.arraycopy(charBuffer, 0, newBuf, 0, charBufferLen); 5719 charBuffer = newBuf; 5720 } 5721 } 5722 5723 // ]NOCPP] 5724 5725 protected void accumulateCharacters(@Const @NoLength char[] buf, int start, 5726 int length) throws SAXException { 5727 appendCharacters(stack[currentPtr].node, buf, start, length); 5728 } 5729 5730 // ------------------------------- // 5731 5732 protected final void requestSuspension() { 5733 tokenizer.requestSuspension(); 5734 } 5735 5736 protected abstract T createElement(@NsUri String ns, @Local String name, 5737 HtmlAttributes attributes, T intendedParent 5738 // CPPONLY: , @Creator Object creator 5739 ) throws SAXException; 5740 5741 protected T createElement(@NsUri String ns, @Local String name, 5742 HtmlAttributes attributes, T form, T intendedParent 5743 // CPPONLY: , @Creator Object creator 5744 ) throws SAXException { 5745 return createElement("http://www.w3.org/1999/xhtml", name, attributes, intendedParent 5746 // CPPONLY: , creator 5747 ); 5748 } 5749 5750 protected abstract T createHtmlElementSetAsRoot(HtmlAttributes attributes) 5751 throws SAXException; 5752 5753 protected abstract void detachFromParent(T element) throws SAXException; 5754 5755 protected abstract boolean hasChildren(T element) throws SAXException; 5756 5757 protected abstract void appendElement(T child, T newParent) 5758 throws SAXException; 5759 5760 protected abstract void appendChildrenToNewParent(T oldParent, T newParent) 5761 throws SAXException; 5762 5763 protected abstract void insertFosterParentedChild(T child, T table, 5764 T stackParent) throws SAXException; 5765 5766 // We don't generate CPP code for this method because it is not used in generated CPP 5767 // code. Instead, the form owner version of this method is called with a null form owner. 5768 // [NOCPP[ 5769 5770 protected abstract T createAndInsertFosterParentedElement(@NsUri String ns, @Local String name, 5771 HtmlAttributes attributes, T table, T stackParent) throws SAXException; 5772 5773 // ]NOCPP] 5774 5775 protected T createAndInsertFosterParentedElement(@NsUri String ns, @Local String name, 5776 HtmlAttributes attributes, T form, T table, T stackParent 5777 // CPPONLY: , @Creator Object creator 5778 ) throws SAXException { 5779 return createAndInsertFosterParentedElement(ns, name, attributes, table, stackParent); 5780 }; 5781 5782 protected abstract void insertFosterParentedCharacters( 5783 @NoLength char[] buf, int start, int length, T table, T stackParent) 5784 throws SAXException; 5785 5786 protected abstract void appendCharacters(T parent, @NoLength char[] buf, 5787 int start, int length) throws SAXException; 5788 5789 protected abstract void appendComment(T parent, @NoLength char[] buf, 5790 int start, int length) throws SAXException; 5791 5792 protected abstract void appendCommentToDocument(@NoLength char[] buf, 5793 int start, int length) throws SAXException; 5794 5795 protected abstract void addAttributesToElement(T element, 5796 HtmlAttributes attributes) throws SAXException; 5797 5798 protected void markMalformedIfScript(T elt) throws SAXException { 5799 5800 } 5801 5802 protected void start(boolean fragmentMode) throws SAXException { 5803 5804 } 5805 5806 protected void end() throws SAXException { 5807 5808 } 5809 5810 protected void appendDoctypeToDocument(@Local String name, 5811 String publicIdentifier, String systemIdentifier) 5812 throws SAXException { 5813 5814 } 5815 5816 protected void elementPushed(@NsUri String ns, @Local String name, T node) 5817 throws SAXException { 5818 5819 } 5820 5821 protected void elementPopped(@NsUri String ns, @Local String name, T node) 5822 throws SAXException { 5823 5824 } 5825 5826 // [NOCPP[ 5827 5828 protected void documentMode(DocumentMode m, String publicIdentifier, 5829 String systemIdentifier) 5830 throws SAXException { 5831 5832 } 5833 5834 /** 5835 * @see nu.validator.htmlparser.common.TokenHandler#wantsComments() 5836 */ 5837 public boolean wantsComments() { 5838 return wantingComments; 5839 } 5840 5841 public void setIgnoringComments(boolean ignoreComments) { 5842 wantingComments = !ignoreComments; 5843 } 5844 5845 /** 5846 * Sets the errorHandler. 5847 * 5848 * @param errorHandler 5849 * the errorHandler to set 5850 */ 5851 public final void setErrorHandler(ErrorHandler errorHandler) { 5852 this.errorHandler = errorHandler; 5853 } 5854 5855 /** 5856 * Returns the errorHandler. 5857 * 5858 * @return the errorHandler 5859 */ 5860 public ErrorHandler getErrorHandler() { 5861 return errorHandler; 5862 } 5863 5864 /** 5865 * The argument MUST be an interned string or <code>null</code>. 5866 * 5867 * @param context 5868 */ 5869 public final void setFragmentContext(@Local String context) { 5870 this.contextName = context; 5871 this.contextNamespace = "http://www.w3.org/1999/xhtml"; 5872 this.contextNode = null; 5873 this.fragment = (contextName != null); 5874 this.quirks = false; 5875 } 5876 5877 // ]NOCPP] 5878 5879 /** 5880 * @see nu.validator.htmlparser.common.TokenHandler#cdataSectionAllowed() 5881 */ 5882 @Inline public boolean cdataSectionAllowed() throws SAXException { 5883 return isInForeign(); 5884 } 5885 5886 private boolean isInForeign() { 5887 return currentPtr >= 0 5888 && stack[currentPtr].ns != "http://www.w3.org/1999/xhtml"; 5889 } 5890 5891 private boolean isInForeignButNotHtmlOrMathTextIntegrationPoint() { 5892 if (currentPtr < 0) { 5893 return false; 5894 } 5895 return !isSpecialParentInForeign(stack[currentPtr]); 5896 } 5897 5898 /** 5899 * The argument MUST be an interned string or <code>null</code>. 5900 * 5901 * @param context 5902 */ 5903 public final void setFragmentContext(@Local String context, 5904 @NsUri String ns, T node, boolean quirks) { 5905 // [NOCPP[ 5906 if (!((context == null && ns == null) 5907 || "http://www.w3.org/1999/xhtml" == ns 5908 || "http://www.w3.org/2000/svg" == ns || "http://www.w3.org/1998/Math/MathML" == ns)) { 5909 throw new IllegalArgumentException( 5910 "The namespace must be the HTML, SVG or MathML namespace (or null when the local name is null). Got: " 5911 + ns); 5912 } 5913 // ]NOCPP] 5914 this.contextName = context; 5915 this.contextNamespace = ns; 5916 this.contextNode = node; 5917 this.fragment = (contextName != null); 5918 this.quirks = quirks; 5919 } 5920 5921 protected final T currentNode() { 5922 return stack[currentPtr].node; 5923 } 5924 5925 /** 5926 * Returns the scriptingEnabled. 5927 * 5928 * @return the scriptingEnabled 5929 */ 5930 public boolean isScriptingEnabled() { 5931 return scriptingEnabled; 5932 } 5933 5934 /** 5935 * Sets the scriptingEnabled. 5936 * 5937 * @param scriptingEnabled 5938 * the scriptingEnabled to set 5939 */ 5940 public void setScriptingEnabled(boolean scriptingEnabled) { 5941 this.scriptingEnabled = scriptingEnabled; 5942 } 5943 5944 public void setForceNoQuirks(boolean forceNoQuirks) { 5945 this.forceNoQuirks = forceNoQuirks; 5946 } 5947 5948 // Redundant method retained because previously public. 5949 public void setIsSrcdocDocument(boolean isSrcdocDocument) { 5950 this.setForceNoQuirks(isSrcdocDocument); 5951 } 5952 5953 public boolean isAllowDeclarativeShadowRoots() { 5954 return allowDeclarativeShadowRoots; 5955 } 5956 5957 public void setAllowDeclarativeShadowRoots(boolean allow) { 5958 allowDeclarativeShadowRoots = allow; 5959 } 5960 5961 // [NOCPP[ 5962 5963 public void setNamePolicy(XmlViolationPolicy namePolicy) { 5964 this.namePolicy = namePolicy; 5965 } 5966 5967 /** 5968 * Sets the documentModeHandler. 5969 * 5970 * @param documentModeHandler 5971 * the documentModeHandler to set 5972 */ 5973 public void setDocumentModeHandler(DocumentModeHandler documentModeHandler) { 5974 this.documentModeHandler = documentModeHandler; 5975 } 5976 5977 /** 5978 * Sets the reportingDoctype. 5979 * 5980 * @param reportingDoctype 5981 * the reportingDoctype to set 5982 */ 5983 public void setReportingDoctype(boolean reportingDoctype) { 5984 this.reportingDoctype = reportingDoctype; 5985 } 5986 5987 // ]NOCPP] 5988 5989 /** 5990 * Flushes the pending characters. Public for document.write use cases only. 5991 * @throws SAXException 5992 */ 5993 public final void flushCharacters() throws SAXException { 5994 if (charBufferLen > 0) { 5995 if ((mode == IN_TABLE || mode == IN_TABLE_BODY || mode == IN_ROW) 5996 && charBufferContainsNonWhitespace()) { 5997 errNonSpaceInTable(); 5998 reconstructTheActiveFormattingElements(); 5999 if (!stack[currentPtr].isFosterParenting()) { 6000 // reconstructing gave us a new current node 6001 appendCharacters(currentNode(), charBuffer, 0, 6002 charBufferLen); 6003 charBufferLen = 0; 6004 return; 6005 } 6006 6007 int tablePos = findLastOrRoot(TreeBuilder.TABLE); 6008 int templatePos = findLastOrRoot(TreeBuilder.TEMPLATE); 6009 6010 if (templatePos >= tablePos) { 6011 appendCharacters(stack[templatePos].node, charBuffer, 0, charBufferLen); 6012 charBufferLen = 0; 6013 return; 6014 } 6015 6016 StackNode<T> tableElt = stack[tablePos]; 6017 insertFosterParentedCharacters(charBuffer, 0, charBufferLen, 6018 tableElt.node, stack[tablePos - 1].node); 6019 charBufferLen = 0; 6020 return; 6021 } 6022 appendCharacters(currentNode(), charBuffer, 0, charBufferLen); 6023 charBufferLen = 0; 6024 } 6025 } 6026 6027 private boolean charBufferContainsNonWhitespace() { 6028 for (int i = 0; i < charBufferLen; i++) { 6029 switch (charBuffer[i]) { 6030 case ' ': 6031 case '\t': 6032 case '\n': 6033 case '\r': 6034 case '\u000C': 6035 continue; 6036 default: 6037 return true; 6038 } 6039 } 6040 return false; 6041 } 6042 6043 /** 6044 * Creates a comparable snapshot of the tree builder state. Snapshot 6045 * creation is only supported immediately after a script end tag has been 6046 * processed. In C++ the caller is responsible for calling 6047 * <code>delete</code> on the returned object. 6048 * 6049 * @return a snapshot. 6050 * @throws SAXException 6051 */ 6052 @SuppressWarnings("unchecked") public TreeBuilderState<T> newSnapshot() 6053 throws SAXException { 6054 StackNode<T>[] listCopy = new StackNode[listPtr + 1]; 6055 for (int i = 0; i < listCopy.length; i++) { 6056 StackNode<T> node = listOfActiveFormattingElements[i]; 6057 if (node != null) { 6058 StackNode<T> newNode = new StackNode<T>(-1); 6059 newNode.setValues(node.getFlags(), node.ns, 6060 node.name, node.node, node.popName, 6061 node.attributes.cloneAttributes() 6062 // CPPONLY: , node.getHtmlCreator() 6063 // [NOCPP[ 6064 , node.getLocator() 6065 // ]NOCPP] 6066 ); 6067 listCopy[i] = newNode; 6068 } else { 6069 listCopy[i] = null; 6070 } 6071 } 6072 StackNode<T>[] stackCopy = new StackNode[currentPtr + 1]; 6073 for (int i = 0; i < stackCopy.length; i++) { 6074 StackNode<T> node = stack[i]; 6075 int listIndex = findInListOfActiveFormattingElements(node); 6076 if (listIndex == -1) { 6077 StackNode<T> newNode = new StackNode<T>(-1); 6078 newNode.setValues(node.getFlags(), node.ns, 6079 node.name, node.node, node.popName, 6080 null 6081 // CPPONLY: , node.getHtmlCreator() 6082 // [NOCPP[ 6083 , node.getLocator() 6084 // ]NOCPP] 6085 ); 6086 stackCopy[i] = newNode; 6087 } else { 6088 stackCopy[i] = listCopy[listIndex]; 6089 stackCopy[i].retain(); 6090 } 6091 } 6092 int[] templateModeStackCopy = new int[templateModePtr + 1]; 6093 System.arraycopy(templateModeStack, 0, templateModeStackCopy, 0, 6094 templateModeStackCopy.length); 6095 return new StateSnapshot<T>(stackCopy, listCopy, templateModeStackCopy, formPointer, 6096 headPointer, mode, originalMode, framesetOk, 6097 needToDropLF, quirks); 6098 } 6099 6100 public boolean snapshotMatches(TreeBuilderState<T> snapshot) { 6101 StackNode<T>[] stackCopy = snapshot.getStack(); 6102 int stackLen = snapshot.getStackLength(); 6103 StackNode<T>[] listCopy = snapshot.getListOfActiveFormattingElements(); 6104 int listLen = snapshot.getListOfActiveFormattingElementsLength(); 6105 int[] templateModeStackCopy = snapshot.getTemplateModeStack(); 6106 int templateModeStackLen = snapshot.getTemplateModeStackLength(); 6107 6108 if (stackLen != currentPtr + 1 6109 || listLen != listPtr + 1 6110 || templateModeStackLen != templateModePtr + 1 6111 || formPointer != snapshot.getFormPointer() 6112 || headPointer != snapshot.getHeadPointer() 6113 || mode != snapshot.getMode() 6114 || originalMode != snapshot.getOriginalMode() 6115 || framesetOk != snapshot.isFramesetOk() 6116 || needToDropLF != snapshot.isNeedToDropLF() 6117 || quirks != snapshot.isQuirks()) { // maybe just assert quirks 6118 return false; 6119 } 6120 for (int i = listLen - 1; i >= 0; i--) { 6121 if (listCopy[i] == null 6122 && listOfActiveFormattingElements[i] == null) { 6123 continue; 6124 } else if (listCopy[i] == null 6125 || listOfActiveFormattingElements[i] == null) { 6126 return false; 6127 } 6128 if (listCopy[i].node != listOfActiveFormattingElements[i].node) { 6129 return false; // it's possible that this condition is overly 6130 // strict 6131 } 6132 } 6133 for (int i = stackLen - 1; i >= 0; i--) { 6134 if (stackCopy[i].node != stack[i].node) { 6135 return false; 6136 } 6137 } 6138 for (int i = templateModeStackLen - 1; i >=0; i--) { 6139 if (templateModeStackCopy[i] != templateModeStack[i]) { 6140 return false; 6141 } 6142 } 6143 return true; 6144 } 6145 6146 @SuppressWarnings("unchecked") public void loadState( 6147 TreeBuilderState<T> snapshot) 6148 throws SAXException { 6149 // CPPONLY: mCurrentHtmlScriptCannotDocumentWriteOrBlock = false; 6150 StackNode<T>[] stackCopy = snapshot.getStack(); 6151 int stackLen = snapshot.getStackLength(); 6152 StackNode<T>[] listCopy = snapshot.getListOfActiveFormattingElements(); 6153 int listLen = snapshot.getListOfActiveFormattingElementsLength(); 6154 int[] templateModeStackCopy = snapshot.getTemplateModeStack(); 6155 int templateModeStackLen = snapshot.getTemplateModeStackLength(); 6156 6157 for (int i = 0; i <= listPtr; i++) { 6158 if (listOfActiveFormattingElements[i] != null) { 6159 listOfActiveFormattingElements[i].release(this); 6160 } 6161 } 6162 if (listOfActiveFormattingElements.length < listLen) { 6163 listOfActiveFormattingElements = new StackNode[listLen]; 6164 } 6165 listPtr = listLen - 1; 6166 6167 for (int i = 0; i <= currentPtr; i++) { 6168 stack[i].release(this); 6169 } 6170 if (stack.length < stackLen) { 6171 stack = new StackNode[stackLen]; 6172 } 6173 currentPtr = stackLen - 1; 6174 6175 if (templateModeStack.length < templateModeStackLen) { 6176 templateModeStack = new int[templateModeStackLen]; 6177 } 6178 templateModePtr = templateModeStackLen - 1; 6179 6180 for (int i = 0; i < listLen; i++) { 6181 StackNode<T> node = listCopy[i]; 6182 if (node != null) { 6183 StackNode<T> newNode = createStackNode(node.getFlags(), node.ns, 6184 node.name, node.node, 6185 node.popName, 6186 node.attributes.cloneAttributes() 6187 // CPPONLY: , node.getHtmlCreator() 6188 // [NOCPP[ 6189 , node.getLocator() 6190 // ]NOCPP] 6191 ); 6192 listOfActiveFormattingElements[i] = newNode; 6193 } else { 6194 listOfActiveFormattingElements[i] = null; 6195 } 6196 } 6197 for (int i = 0; i < stackLen; i++) { 6198 StackNode<T> node = stackCopy[i]; 6199 int listIndex = findInArray(node, listCopy); 6200 if (listIndex == -1) { 6201 StackNode<T> newNode = createStackNode(node.getFlags(), node.ns, 6202 node.name, node.node, 6203 node.popName, 6204 null 6205 // CPPONLY: , node.getHtmlCreator() 6206 // [NOCPP[ 6207 , node.getLocator() 6208 // ]NOCPP] 6209 ); 6210 stack[i] = newNode; 6211 } else { 6212 stack[i] = listOfActiveFormattingElements[listIndex]; 6213 stack[i].retain(); 6214 } 6215 } 6216 System.arraycopy(templateModeStackCopy, 0, templateModeStack, 0, templateModeStackLen); 6217 formPointer = snapshot.getFormPointer(); 6218 headPointer = snapshot.getHeadPointer(); 6219 mode = snapshot.getMode(); 6220 originalMode = snapshot.getOriginalMode(); 6221 framesetOk = snapshot.isFramesetOk(); 6222 needToDropLF = snapshot.isNeedToDropLF(); 6223 quirks = snapshot.isQuirks(); 6224 } 6225 6226 private int findInArray(StackNode<T> node, StackNode<T>[] arr) { 6227 for (int i = listPtr; i >= 0; i--) { 6228 if (node == arr[i]) { 6229 return i; 6230 } 6231 } 6232 return -1; 6233 } 6234 6235 /** 6236 * Returns <code>stack[stackPos].node</code> if <code>stackPos</code> is 6237 * smaller than Blink's magic limit or the node at Blink's magic limit 6238 * otherwise. 6239 * 6240 * In order to get Blink-compatible handling of excessive deeply-nested 6241 * markup, this method must be used to obtain the node that is used as the 6242 * parent node of an insertion. 6243 * 6244 * Blink's magic number is 512, but our counting is off by one compared to 6245 * Blink's way of counting, so in order to get the same 6246 * externally-observable outcome, we use 511 as our magic number. 6247 * 6248 * @param stackPos the stack position to attempt to read 6249 * @return node at the position capped to Blink's magic number 6250 * @throws SAXException 6251 */ 6252 private T nodeFromStackWithBlinkCompat(int stackPos) throws SAXException { 6253 // Magic number if off by one relative to Blink's magic number, but the 6254 // outcome is the same, because the counting is different by one. 6255 if (stackPos > 511) { 6256 errDeepTree(); 6257 return stack[511].node; 6258 } 6259 return stack[stackPos].node; 6260 } 6261 /** 6262 * @see nu.validator.htmlparser.impl.TreeBuilderState#getFormPointer() 6263 */ 6264 @Override 6265 public T getFormPointer() { 6266 return formPointer; 6267 } 6268 6269 /** 6270 * Returns the headPointer. 6271 * 6272 * @return the headPointer 6273 */ 6274 @Override 6275 public T getHeadPointer() { 6276 return headPointer; 6277 } 6278 6279 /** 6280 * @see nu.validator.htmlparser.impl.TreeBuilderState#getListOfActiveFormattingElements() 6281 */ 6282 @Override 6283 public StackNode<T>[] getListOfActiveFormattingElements() { 6284 return listOfActiveFormattingElements; 6285 } 6286 6287 /** 6288 * @see nu.validator.htmlparser.impl.TreeBuilderState#getStack() 6289 */ 6290 @Override 6291 public StackNode<T>[] getStack() { 6292 return stack; 6293 } 6294 6295 /** 6296 * @see nu.validator.htmlparser.impl.TreeBuilderState#getTemplateModeStack() 6297 */ 6298 @Override 6299 public int[] getTemplateModeStack() { 6300 return templateModeStack; 6301 } 6302 6303 /** 6304 * Returns the mode. 6305 * 6306 * @return the mode 6307 */ 6308 @Override 6309 public int getMode() { 6310 return mode; 6311 } 6312 6313 /** 6314 * Returns the originalMode. 6315 * 6316 * @return the originalMode 6317 */ 6318 @Override 6319 public int getOriginalMode() { 6320 return originalMode; 6321 } 6322 6323 /** 6324 * Returns the framesetOk. 6325 * 6326 * @return the framesetOk 6327 */ 6328 @Override 6329 public boolean isFramesetOk() { 6330 return framesetOk; 6331 } 6332 6333 /** 6334 * Returns the needToDropLF. 6335 * 6336 * @return the needToDropLF 6337 */ 6338 @Override 6339 public boolean isNeedToDropLF() { 6340 return needToDropLF; 6341 } 6342 6343 /** 6344 * Returns the quirks. 6345 * 6346 * @return the quirks 6347 */ 6348 @Override 6349 public boolean isQuirks() { 6350 return quirks; 6351 } 6352 6353 /** 6354 * @see nu.validator.htmlparser.impl.TreeBuilderState#getListOfActiveFormattingElementsLength() 6355 */ 6356 @Override 6357 public int getListOfActiveFormattingElementsLength() { 6358 return listPtr + 1; 6359 } 6360 6361 /** 6362 * @see nu.validator.htmlparser.impl.TreeBuilderState#getStackLength() 6363 */ 6364 @Override 6365 public int getStackLength() { 6366 return currentPtr + 1; 6367 } 6368 6369 /** 6370 * @see nu.validator.htmlparser.impl.TreeBuilderState#getTemplateModeStackLength() 6371 */ 6372 @Override 6373 public int getTemplateModeStackLength() { 6374 return templateModePtr + 1; 6375 } 6376 6377 /** 6378 * Complains about an over-deep tree. Theoretically this should just be 6379 * a warning, but in practice authors should take this as an error. 6380 * 6381 * @throws SAXException 6382 */ 6383 private void errDeepTree() throws SAXException { 6384 err("The document tree is more than 513 elements deep, which causes Firefox and Chrome to flatten the tree."); 6385 } 6386 6387 /** 6388 * Reports a stray start tag. 6389 * @param name the name of the stray tag 6390 * 6391 * @throws SAXException 6392 */ 6393 private void errStrayStartTag(@Local String name) throws SAXException { 6394 err("Stray start tag \u201C" + name + "\u201D."); 6395 } 6396 6397 /** 6398 * Reports a stray end tag. 6399 * @param name the name of the stray tag 6400 * 6401 * @throws SAXException 6402 */ 6403 private void errStrayEndTag(@Local String name) throws SAXException { 6404 err("Stray end tag \u201C" + name + "\u201D."); 6405 } 6406 6407 /** 6408 * Reports a state when elements expected to be closed were not. 6409 * 6410 * @param eltPos the position of the start tag on the stack of the element 6411 * being closed. 6412 * @param name the name of the end tag 6413 * 6414 * @throws SAXException 6415 */ 6416 private void errUnclosedElements(int eltPos, @Local String name) throws SAXException { 6417 errNoCheck("End tag \u201C" + name + "\u201D seen, but there were open elements."); 6418 errListUnclosedStartTags(eltPos); 6419 } 6420 6421 /** 6422 * Reports a state when elements expected to be closed ahead of an implied 6423 * end tag but were not. 6424 * 6425 * @param eltPos the position of the start tag on the stack of the element 6426 * being closed. 6427 * @param name the name of the end tag 6428 * 6429 * @throws SAXException 6430 */ 6431 private void errUnclosedElementsImplied(int eltPos, String name) throws SAXException { 6432 errNoCheck("End tag \u201C" + name + "\u201D implied, but there were open elements."); 6433 errListUnclosedStartTags(eltPos); 6434 } 6435 6436 /** 6437 * Reports a state when elements expected to be closed ahead of an implied 6438 * table cell close. 6439 * 6440 * @param eltPos the position of the start tag on the stack of the element 6441 * being closed. 6442 * @throws SAXException 6443 */ 6444 private void errUnclosedElementsCell(int eltPos) throws SAXException { 6445 errNoCheck("A table cell was implicitly closed, but there were open elements."); 6446 errListUnclosedStartTags(eltPos); 6447 } 6448 6449 private void errStrayDoctype() throws SAXException { 6450 err("Stray doctype."); 6451 } 6452 6453 private void errAlmostStandardsDoctype() throws SAXException { 6454 if (!forceNoQuirks) { 6455 err("Almost standards mode doctype. Expected \u201C<!DOCTYPE html>\u201D."); 6456 } 6457 } 6458 6459 private void errQuirkyDoctype() throws SAXException { 6460 if (!forceNoQuirks) { 6461 err("Quirky doctype. Expected \u201C<!DOCTYPE html>\u201D."); 6462 } 6463 } 6464 6465 private void errNonSpaceInTrailer() throws SAXException { 6466 err("Non-space character in page trailer."); 6467 } 6468 6469 private void errNonSpaceAfterFrameset() throws SAXException { 6470 err("Non-space after \u201Cframeset\u201D."); 6471 } 6472 6473 private void errNonSpaceInFrameset() throws SAXException { 6474 err("Non-space in \u201Cframeset\u201D."); 6475 } 6476 6477 private void errNonSpaceAfterBody() throws SAXException { 6478 err("Non-space character after body."); 6479 } 6480 6481 private void errNonSpaceInColgroupInFragment() throws SAXException { 6482 err("Non-space in \u201Ccolgroup\u201D when parsing fragment."); 6483 } 6484 6485 private void errNonSpaceInNoscriptInHead() throws SAXException { 6486 err("Non-space character inside \u201Cnoscript\u201D inside \u201Chead\u201D."); 6487 } 6488 6489 private void errFooBetweenHeadAndBody(@Local String name) throws SAXException { 6490 if (errorHandler == null) { 6491 return; 6492 } 6493 errNoCheck("\u201C" + name + "\u201D element between \u201Chead\u201D and \u201Cbody\u201D."); 6494 } 6495 6496 private void errStartTagWithoutDoctype() throws SAXException { 6497 if (!forceNoQuirks) { 6498 err("Start tag seen without seeing a doctype first. Expected \u201C<!DOCTYPE html>\u201D."); 6499 } 6500 } 6501 6502 private void errNoSelectInTableScope() throws SAXException { 6503 err("No \u201Cselect\u201D in table scope."); 6504 } 6505 6506 private void errStartSelectWhereEndSelectExpected() throws SAXException { 6507 err("\u201Cselect\u201D start tag where end tag expected."); 6508 } 6509 6510 private void errStartTagWithSelectOpen(@Local String name) 6511 throws SAXException { 6512 if (errorHandler == null) { 6513 return; 6514 } 6515 errNoCheck("\u201C" + name 6516 + "\u201D start tag with \u201Cselect\u201D open."); 6517 } 6518 6519 private void errBadStartTagInNoscriptInHead(@Local String name) throws SAXException { 6520 if (errorHandler == null) { 6521 return; 6522 } 6523 errNoCheck("Bad start tag in \u201C" + name 6524 + "\u201D in \u201Cnoscript\u201D in \u201Chead\u201D."); 6525 } 6526 6527 private void errImage() throws SAXException { 6528 err("Saw a start tag \u201Cimage\u201D."); 6529 } 6530 6531 private void errFooSeenWhenFooOpen(@Local String name) throws SAXException { 6532 if (errorHandler == null) { 6533 return; 6534 } 6535 errNoCheck("Start tag \u201C" + name + "\u201D seen but an element of the same type was already open."); 6536 } 6537 6538 private void errHeadingWhenHeadingOpen() throws SAXException { 6539 err("Heading cannot be a child of another heading."); 6540 } 6541 6542 private void errFramesetStart() throws SAXException { 6543 err("\u201Cframeset\u201D start tag seen."); 6544 } 6545 6546 private void errNoCellToClose() throws SAXException { 6547 err("No cell to close."); 6548 } 6549 6550 private void errStartTagInTable(@Local String name) throws SAXException { 6551 if (errorHandler == null) { 6552 return; 6553 } 6554 errNoCheck("Start tag \u201C" + name 6555 + "\u201D seen in \u201Ctable\u201D."); 6556 } 6557 6558 private void errFormWhenFormOpen() throws SAXException { 6559 err("Saw a \u201Cform\u201D start tag, but there was already an active \u201Cform\u201D element. Nested forms are not allowed. Ignoring the tag."); 6560 } 6561 6562 private void errTableSeenWhileTableOpen() throws SAXException { 6563 err("Start tag for \u201Ctable\u201D seen but the previous \u201Ctable\u201D is still open."); 6564 } 6565 6566 private void errStartTagInTableBody(@Local String name) throws SAXException { 6567 if (errorHandler == null) { 6568 return; 6569 } 6570 errNoCheck("\u201C" + name + "\u201D start tag in table body."); 6571 } 6572 6573 private void errEndTagSeenWithoutDoctype() throws SAXException { 6574 if (!forceNoQuirks) { 6575 err("End tag seen without seeing a doctype first. Expected \u201C<!DOCTYPE html>\u201D."); 6576 } 6577 } 6578 6579 private void errEndTagAfterBody() throws SAXException { 6580 err("Saw an end tag after \u201Cbody\u201D had been closed."); 6581 } 6582 6583 private void errEndTagSeenWithSelectOpen(@Local String name) throws SAXException { 6584 if (errorHandler == null) { 6585 return; 6586 } 6587 errNoCheck("\u201C" + name 6588 + "\u201D end tag with \u201Cselect\u201D open."); 6589 } 6590 6591 private void errGarbageInColgroup() throws SAXException { 6592 err("Garbage in \u201Ccolgroup\u201D fragment."); 6593 } 6594 6595 private void errEndTagBr() throws SAXException { 6596 err("End tag \u201Cbr\u201D."); 6597 } 6598 6599 private void errNoElementToCloseButEndTagSeen(@Local String name) 6600 throws SAXException { 6601 if (errorHandler == null) { 6602 return; 6603 } 6604 errNoCheck("No \u201C" + name + "\u201D element in scope but a \u201C" 6605 + name + "\u201D end tag seen."); 6606 } 6607 6608 private void errHtmlStartTagInForeignContext(@Local String name) 6609 throws SAXException { 6610 if (errorHandler == null) { 6611 return; 6612 } 6613 errNoCheck("HTML start tag \u201C" + name 6614 + "\u201D in a foreign namespace context."); 6615 } 6616 6617 private void errNoTableRowToClose() throws SAXException { 6618 err("No table row to close."); 6619 } 6620 6621 private void errNonSpaceInTable() throws SAXException { 6622 err("Misplaced non-space characters inside a table."); 6623 } 6624 6625 private void errUnclosedChildrenInRuby() throws SAXException { 6626 if (errorHandler == null) { 6627 return; 6628 } 6629 errNoCheck("Unclosed children in \u201Cruby\u201D."); 6630 } 6631 6632 private void errStartTagSeenWithoutRuby(@Local String name) throws SAXException { 6633 if (errorHandler == null) { 6634 return; 6635 } 6636 errNoCheck("Start tag \u201C" 6637 + name 6638 + "\u201D seen without a \u201Cruby\u201D element being open."); 6639 } 6640 6641 private void errSelfClosing() throws SAXException { 6642 if (errorHandler == null) { 6643 return; 6644 } 6645 errNoCheck("Self-closing syntax (\u201C/>\u201D) used on a non-void HTML element. Ignoring the slash and treating as a start tag."); 6646 } 6647 6648 private void errNoCheckUnclosedElementsOnStack() throws SAXException { 6649 errNoCheck("Unclosed elements on stack."); 6650 } 6651 6652 private void errEndTagDidNotMatchCurrentOpenElement(@Local String name, 6653 @Local String currOpenName) throws SAXException { 6654 if (errorHandler == null) { 6655 return; 6656 } 6657 errNoCheck("End tag \u201C" 6658 + name 6659 + "\u201D did not match the name of the current open element (\u201C" 6660 + currOpenName + "\u201D)."); 6661 } 6662 6663 private void errEndTagViolatesNestingRules(@Local String name) throws SAXException { 6664 if (errorHandler == null) { 6665 return; 6666 } 6667 errNoCheck("End tag \u201C" + name + "\u201D violates nesting rules."); 6668 } 6669 6670 private void errEofWithUnclosedElements() throws SAXException { 6671 if (errorHandler == null) { 6672 return; 6673 } 6674 errNoCheck("End of file seen and there were open elements."); 6675 // just report all remaining unclosed elements 6676 errListUnclosedStartTags(0); 6677 } 6678 6679 /** 6680 * Reports arriving at/near end of document with unclosed elements remaining. 6681 * 6682 * @param message 6683 * the message 6684 * @throws SAXException 6685 */ 6686 private void errEndWithUnclosedElements(@Local String name) throws SAXException { 6687 if (errorHandler == null) { 6688 return; 6689 } 6690 errNoCheck("End tag for \u201C" 6691 + name 6692 + "\u201D seen, but there were unclosed elements."); 6693 // just report all remaining unclosed elements 6694 errListUnclosedStartTags(0); 6695 } 6696 }