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