blob: b4e2a50f644dfb7794c32a986664dd827ed76eff [file] [log] [blame]
/*
* Copyright (C) 2013 Google, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY GOOGLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#if ENABLE(THREADED_HTML_PARSER)
#include "HTMLTreeBuilderSimulator.h"
#include "HTMLDocumentParser.h"
#include "HTMLNames.h"
#include "HTMLParserIdioms.h"
#include "HTMLTokenizer.h"
#include "HTMLTreeBuilder.h"
#include "MathMLNames.h"
#include "SVGNames.h"
namespace WebCore {
using namespace HTMLNames;
static bool tokenExitsForeignContent(const CompactHTMLToken& token)
{
// FIXME: This is copied from HTMLTreeBuilder::processTokenInForeignContent and changed to use threadSafeHTMLNamesMatch.
const HTMLIdentifier& tagName = token.data();
return threadSafeHTMLNamesMatch(tagName, bTag)
|| threadSafeHTMLNamesMatch(tagName, bigTag)
|| threadSafeHTMLNamesMatch(tagName, blockquoteTag)
|| threadSafeHTMLNamesMatch(tagName, bodyTag)
|| threadSafeHTMLNamesMatch(tagName, brTag)
|| threadSafeHTMLNamesMatch(tagName, centerTag)
|| threadSafeHTMLNamesMatch(tagName, codeTag)
|| threadSafeHTMLNamesMatch(tagName, ddTag)
|| threadSafeHTMLNamesMatch(tagName, divTag)
|| threadSafeHTMLNamesMatch(tagName, dlTag)
|| threadSafeHTMLNamesMatch(tagName, dtTag)
|| threadSafeHTMLNamesMatch(tagName, emTag)
|| threadSafeHTMLNamesMatch(tagName, embedTag)
|| threadSafeHTMLNamesMatch(tagName, h1Tag)
|| threadSafeHTMLNamesMatch(tagName, h2Tag)
|| threadSafeHTMLNamesMatch(tagName, h3Tag)
|| threadSafeHTMLNamesMatch(tagName, h4Tag)
|| threadSafeHTMLNamesMatch(tagName, h5Tag)
|| threadSafeHTMLNamesMatch(tagName, h6Tag)
|| threadSafeHTMLNamesMatch(tagName, headTag)
|| threadSafeHTMLNamesMatch(tagName, hrTag)
|| threadSafeHTMLNamesMatch(tagName, iTag)
|| threadSafeHTMLNamesMatch(tagName, imgTag)
|| threadSafeHTMLNamesMatch(tagName, liTag)
|| threadSafeHTMLNamesMatch(tagName, listingTag)
|| threadSafeHTMLNamesMatch(tagName, menuTag)
|| threadSafeHTMLNamesMatch(tagName, metaTag)
|| threadSafeHTMLNamesMatch(tagName, nobrTag)
|| threadSafeHTMLNamesMatch(tagName, olTag)
|| threadSafeHTMLNamesMatch(tagName, pTag)
|| threadSafeHTMLNamesMatch(tagName, preTag)
|| threadSafeHTMLNamesMatch(tagName, rubyTag)
|| threadSafeHTMLNamesMatch(tagName, sTag)
|| threadSafeHTMLNamesMatch(tagName, smallTag)
|| threadSafeHTMLNamesMatch(tagName, spanTag)
|| threadSafeHTMLNamesMatch(tagName, strongTag)
|| threadSafeHTMLNamesMatch(tagName, strikeTag)
|| threadSafeHTMLNamesMatch(tagName, subTag)
|| threadSafeHTMLNamesMatch(tagName, supTag)
|| threadSafeHTMLNamesMatch(tagName, tableTag)
|| threadSafeHTMLNamesMatch(tagName, ttTag)
|| threadSafeHTMLNamesMatch(tagName, uTag)
|| threadSafeHTMLNamesMatch(tagName, ulTag)
|| threadSafeHTMLNamesMatch(tagName, varTag)
|| (threadSafeHTMLNamesMatch(tagName, fontTag) && (token.getAttributeItem(colorAttr) || token.getAttributeItem(faceAttr) || token.getAttributeItem(sizeAttr)));
}
static bool tokenExitsSVG(const CompactHTMLToken& token)
{
// FIXME: It's very fragile that we special case foreignObject here to be case-insensitive.
return equalIgnoringCaseNonNull(token.data().asStringImpl(), SVGNames::foreignObjectTag.localName().impl());
}
static bool tokenExitsMath(const CompactHTMLToken& token)
{
// FIXME: This is copied from HTMLElementStack::isMathMLTextIntegrationPoint and changed to use threadSafeMatch.
const HTMLIdentifier& tagName = token.data();
return threadSafeMatch(tagName, MathMLNames::miTag)
|| threadSafeMatch(tagName, MathMLNames::moTag)
|| threadSafeMatch(tagName, MathMLNames::mnTag)
|| threadSafeMatch(tagName, MathMLNames::msTag)
|| threadSafeMatch(tagName, MathMLNames::mtextTag);
}
HTMLTreeBuilderSimulator::HTMLTreeBuilderSimulator(const HTMLParserOptions& options)
: m_options(options)
{
m_namespaceStack.append(HTML);
}
HTMLTreeBuilderSimulator::State HTMLTreeBuilderSimulator::stateFor(HTMLTreeBuilder* treeBuilder)
{
ASSERT(isMainThread());
State namespaceStack;
for (HTMLElementStack::ElementRecord* record = treeBuilder->openElements()->topRecord(); record; record = record->next()) {
Namespace currentNamespace = HTML;
if (record->namespaceURI() == SVGNames::svgNamespaceURI)
currentNamespace = SVG;
else if (record->namespaceURI() == MathMLNames::mathmlNamespaceURI)
currentNamespace = MathML;
if (namespaceStack.isEmpty() || namespaceStack.last() != currentNamespace)
namespaceStack.append(currentNamespace);
}
namespaceStack.reverse();
return namespaceStack;
}
bool HTMLTreeBuilderSimulator::simulate(const CompactHTMLToken& token, HTMLTokenizer* tokenizer)
{
if (token.type() == HTMLToken::StartTag) {
const HTMLIdentifier& tagName = token.data();
if (threadSafeMatch(tagName, SVGNames::svgTag))
m_namespaceStack.append(SVG);
if (threadSafeMatch(tagName, MathMLNames::mathTag))
m_namespaceStack.append(MathML);
if (inForeignContent() && tokenExitsForeignContent(token))
m_namespaceStack.removeLast();
if ((m_namespaceStack.last() == SVG && tokenExitsSVG(token))
|| (m_namespaceStack.last() == MathML && tokenExitsMath(token)))
m_namespaceStack.append(HTML);
if (!inForeignContent()) {
// FIXME: This is just a copy of Tokenizer::updateStateFor which uses threadSafeMatches.
if (threadSafeHTMLNamesMatch(tagName, textareaTag) || threadSafeHTMLNamesMatch(tagName, titleTag))
tokenizer->setState(HTMLTokenizer::RCDATAState);
else if (threadSafeHTMLNamesMatch(tagName, plaintextTag))
tokenizer->setState(HTMLTokenizer::PLAINTEXTState);
else if (threadSafeHTMLNamesMatch(tagName, scriptTag))
tokenizer->setState(HTMLTokenizer::ScriptDataState);
else if (threadSafeHTMLNamesMatch(tagName, styleTag)
|| threadSafeHTMLNamesMatch(tagName, iframeTag)
|| threadSafeHTMLNamesMatch(tagName, xmpTag)
|| (threadSafeHTMLNamesMatch(tagName, noembedTag) && m_options.pluginsEnabled)
|| threadSafeHTMLNamesMatch(tagName, noframesTag)
|| (threadSafeHTMLNamesMatch(tagName, noscriptTag) && m_options.scriptEnabled))
tokenizer->setState(HTMLTokenizer::RAWTEXTState);
}
}
if (token.type() == HTMLToken::EndTag) {
const HTMLIdentifier& tagName = token.data();
if ((m_namespaceStack.last() == SVG && threadSafeMatch(tagName, SVGNames::svgTag))
|| (m_namespaceStack.last() == MathML && threadSafeMatch(tagName, MathMLNames::mathTag))
|| (m_namespaceStack.contains(SVG) && m_namespaceStack.last() == HTML && tokenExitsSVG(token))
|| (m_namespaceStack.contains(MathML) && m_namespaceStack.last() == HTML && tokenExitsMath(token)))
m_namespaceStack.removeLast();
if (threadSafeHTMLNamesMatch(tagName, scriptTag)) {
if (!inForeignContent())
tokenizer->setState(HTMLTokenizer::DataState);
return false;
}
}
// FIXME: Also setForceNullCharacterReplacement when in text mode.
tokenizer->setForceNullCharacterReplacement(inForeignContent());
tokenizer->setShouldAllowCDATA(inForeignContent());
return true;
}
}
#endif // ENABLE(THREADED_HTML_PARSER)