| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright (C) 2010 Google, Inc. All Rights Reserved. | |
| 3 * Copyright (C) 2011, 2014 Apple Inc. All rights reserved. | |
| 4 * | |
| 5 * Redistribution and use in source and binary forms, with or without | |
| 6 * modification, are permitted provided that the following conditions | |
| 7 * are met: | |
| 8 * 1. Redistributions of source code must retain the above copyright | |
| 9 * notice, this list of conditions and the following disclaimer. | |
| 10 * 2. Redistributions in binary form must reproduce the above copyright | |
| 11 * notice, this list of conditions and the following disclaimer in the | |
| 12 * documentation and/or other materials provided with the distribution. | |
| 13 * | |
| 14 * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. ``AS IS'' AND ANY | |
| 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
| 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
| 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE INC. OR | |
| 18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
| 19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
| 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
| 21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | |
| 22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 25 */ | |
| 26 | |
| 27 #include "sky/engine/core/html/parser/HTMLTreeBuilder.h" | |
| 28 | |
| 29 #include "gen/sky/core/HTMLNames.h" | |
| 30 #include "sky/engine/bindings/exception_state_placeholder.h" | |
| 31 #include "sky/engine/core/dom/DocumentFragment.h" | |
| 32 #include "sky/engine/core/html/HTMLTemplateElement.h" | |
| 33 #include "sky/engine/core/html/parser/AtomicHTMLToken.h" | |
| 34 #include "sky/engine/core/html/parser/HTMLDocumentParser.h" | |
| 35 #include "sky/engine/core/html/parser/HTMLParserIdioms.h" | |
| 36 #include "sky/engine/core/html/parser/HTMLToken.h" | |
| 37 #include "sky/engine/core/html/parser/HTMLTokenizer.h" | |
| 38 | |
| 39 namespace blink { | |
| 40 | |
| 41 static TextPosition uninitializedPositionValue1() | |
| 42 { | |
| 43 return TextPosition(OrdinalNumber::fromOneBasedInt(-1), OrdinalNumber::first
()); | |
| 44 } | |
| 45 | |
| 46 HTMLTreeBuilder::HTMLTreeBuilder(HTMLDocumentParser* parser, Document* document,
bool) | |
| 47 : | |
| 48 #if ENABLE(ASSERT) | |
| 49 m_isAttached(true), | |
| 50 #endif | |
| 51 m_tree(document) | |
| 52 , m_insertionMode(HTMLMode) | |
| 53 , m_originalInsertionMode(HTMLMode) | |
| 54 , m_parser(parser) | |
| 55 , m_scriptToProcessStartPosition(uninitializedPositionValue1()) | |
| 56 { | |
| 57 m_tree.openElements()->pushRootNode(document); | |
| 58 } | |
| 59 | |
| 60 HTMLTreeBuilder::~HTMLTreeBuilder() | |
| 61 { | |
| 62 } | |
| 63 | |
| 64 void HTMLTreeBuilder::detach() | |
| 65 { | |
| 66 #if ENABLE(ASSERT) | |
| 67 // This call makes little sense in fragment mode, but for consistency | |
| 68 // DocumentParser expects detach() to always be called before it's destroyed
. | |
| 69 m_isAttached = false; | |
| 70 #endif | |
| 71 // HTMLConstructionSite might be on the callstack when detach() is called | |
| 72 // otherwise we'd just call m_tree.clear() here instead. | |
| 73 m_tree.detach(); | |
| 74 } | |
| 75 | |
| 76 HTMLTreeBuilder::FragmentParsingContext::FragmentParsingContext() | |
| 77 : m_fragment(nullptr) | |
| 78 { | |
| 79 } | |
| 80 | |
| 81 HTMLTreeBuilder::FragmentParsingContext::FragmentParsingContext(DocumentFragment
* fragment, Element* contextElement) | |
| 82 : m_fragment(fragment) | |
| 83 { | |
| 84 ASSERT(!fragment->hasChildren()); | |
| 85 } | |
| 86 | |
| 87 HTMLTreeBuilder::FragmentParsingContext::~FragmentParsingContext() | |
| 88 { | |
| 89 } | |
| 90 | |
| 91 PassRefPtr<Element> HTMLTreeBuilder::takeScriptToProcess(TextPosition& scriptSta
rtPosition) | |
| 92 { | |
| 93 ASSERT(m_scriptToProcess); | |
| 94 ASSERT(!m_tree.hasPendingTasks()); | |
| 95 // Unpause ourselves, callers may pause us again when processing the script. | |
| 96 // The HTML5 spec is written as though scripts are executed inside the tree | |
| 97 // builder. We pause the parser to exit the tree builder, and then resume | |
| 98 // before running scripts. | |
| 99 scriptStartPosition = m_scriptToProcessStartPosition; | |
| 100 m_scriptToProcessStartPosition = uninitializedPositionValue1(); | |
| 101 return m_scriptToProcess.release(); | |
| 102 } | |
| 103 | |
| 104 void HTMLTreeBuilder::constructTree(AtomicHTMLToken* token) | |
| 105 { | |
| 106 const HTMLToken::Type type = token->type(); | |
| 107 | |
| 108 if (type == HTMLToken::Character) { | |
| 109 processCharacter(token); | |
| 110 return; | |
| 111 } | |
| 112 | |
| 113 // Any non-character token needs to cause us to flush any pending text immed
iately. | |
| 114 // NOTE: flush() can cause any queued tasks to execute, possibly re-entering
the parser. | |
| 115 m_tree.flush(); | |
| 116 | |
| 117 if (type == HTMLToken::StartTag) { | |
| 118 processStartTag(token); | |
| 119 } else if (type == HTMLToken::EndTag) { | |
| 120 processEndTag(token); | |
| 121 } else if (type == HTMLToken::EndOfFile) { | |
| 122 processEndOfFile(token); | |
| 123 } else { | |
| 124 ASSERT_NOT_REACHED(); | |
| 125 } | |
| 126 | |
| 127 m_tree.executeQueuedTasks(); | |
| 128 // We might be detached now. | |
| 129 } | |
| 130 | |
| 131 void HTMLTreeBuilder::processStartTag(AtomicHTMLToken* token) | |
| 132 { | |
| 133 ASSERT(token->type() == HTMLToken::StartTag); | |
| 134 const AtomicString& name = token->name(); | |
| 135 | |
| 136 if (name == HTMLNames::styleTag) { | |
| 137 processGenericRawTextStartTag(token); | |
| 138 } else if (name == HTMLNames::scriptTag) { | |
| 139 processScriptStartTag(token); | |
| 140 } else if (token->selfClosing()) { | |
| 141 m_tree.insertSelfClosingHTMLElement(token); | |
| 142 } else { | |
| 143 m_tree.insertHTMLElement(token); | |
| 144 } | |
| 145 } | |
| 146 | |
| 147 void HTMLTreeBuilder::processEndTag(AtomicHTMLToken* token) | |
| 148 { | |
| 149 ASSERT(token->type() == HTMLToken::EndTag); | |
| 150 | |
| 151 const InsertionMode mode = insertionMode(); | |
| 152 if (mode == HTMLMode) { | |
| 153 HTMLElementStack::ElementRecord* record = m_tree.openElements()->topReco
rd(); | |
| 154 while (record->next()) { | |
| 155 RefPtr<Element> element = record->element(); | |
| 156 if (element->hasLocalName(token->name())) { | |
| 157 m_tree.openElements()->popUntilPopped(element.get()); | |
| 158 ASSERT(m_tree.openElements()->topNode()); | |
| 159 return; | |
| 160 } | |
| 161 record = record->next(); | |
| 162 } | |
| 163 return; | |
| 164 } | |
| 165 | |
| 166 ASSERT(mode == TextMode); | |
| 167 if (token->name() == HTMLNames::scriptTag) { | |
| 168 // Pause ourselves so that parsing stops until the script can be process
ed by the caller. | |
| 169 ASSERT(m_tree.currentElement()->hasLocalName(HTMLNames::scriptTag.localN
ame())); | |
| 170 m_scriptToProcess = m_tree.currentElement(); | |
| 171 m_tree.openElements()->pop(); | |
| 172 setInsertionMode(m_originalInsertionMode); | |
| 173 return; | |
| 174 } | |
| 175 m_tree.openElements()->pop(); | |
| 176 setInsertionMode(m_originalInsertionMode); | |
| 177 } | |
| 178 | |
| 179 void HTMLTreeBuilder::processCharacter(AtomicHTMLToken* token) | |
| 180 { | |
| 181 ASSERT(token->type() == HTMLToken::Character); | |
| 182 m_tree.insertTextNode(token->characters()); | |
| 183 } | |
| 184 | |
| 185 void HTMLTreeBuilder::processEndOfFile(AtomicHTMLToken* token) | |
| 186 { | |
| 187 ASSERT(token->type() == HTMLToken::EndOfFile); | |
| 188 m_tree.processEndOfFile(); | |
| 189 } | |
| 190 | |
| 191 void HTMLTreeBuilder::processGenericRawTextStartTag(AtomicHTMLToken* token) | |
| 192 { | |
| 193 ASSERT(token->type() == HTMLToken::StartTag); | |
| 194 m_tree.insertHTMLElement(token); | |
| 195 m_originalInsertionMode = m_insertionMode; | |
| 196 setInsertionMode(TextMode); | |
| 197 } | |
| 198 | |
| 199 void HTMLTreeBuilder::processScriptStartTag(AtomicHTMLToken* token) | |
| 200 { | |
| 201 ASSERT(token->type() == HTMLToken::StartTag); | |
| 202 m_tree.insertScriptElement(token); | |
| 203 m_originalInsertionMode = m_insertionMode; | |
| 204 TextPosition position = m_parser->textPosition(); | |
| 205 m_scriptToProcessStartPosition = position; | |
| 206 setInsertionMode(TextMode); | |
| 207 } | |
| 208 | |
| 209 void HTMLTreeBuilder::finished() | |
| 210 { | |
| 211 if (isParsingFragment()) | |
| 212 return; | |
| 213 ASSERT(m_isAttached); | |
| 214 // Warning, this may detach the parser. Do not do anything else after this. | |
| 215 m_tree.finishedParsing(); | |
| 216 } | |
| 217 | |
| 218 } // namespace blink | |
| OLD | NEW |