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