From 5ddde30071f639962dd557c453f2ad01f8f0fd00 Mon Sep 17 00:00:00 2001 From: Kristian Monsen Date: Wed, 8 Sep 2010 12:18:00 +0100 Subject: Merge WebKit at r66666 : Initial merge by git. Change-Id: I57dedeb49859adc9c539e760f0e749768c66626f --- WebCore/html/parser/CSSPreloadScanner.cpp | 160 ++ WebCore/html/parser/CSSPreloadScanner.h | 71 + WebCore/html/parser/HTMLConstructionSite.cpp | 467 ++++ WebCore/html/parser/HTMLConstructionSite.h | 149 ++ WebCore/html/parser/HTMLDocumentParser.cpp | 520 ++++ WebCore/html/parser/HTMLDocumentParser.h | 142 + WebCore/html/parser/HTMLElementStack.cpp | 535 ++++ WebCore/html/parser/HTMLElementStack.h | 154 ++ WebCore/html/parser/HTMLEntityNames.in | 2138 +++++++++++++++ WebCore/html/parser/HTMLEntityParser.cpp | 272 ++ WebCore/html/parser/HTMLEntityParser.h | 41 + WebCore/html/parser/HTMLEntitySearch.cpp | 132 + WebCore/html/parser/HTMLEntitySearch.h | 75 + WebCore/html/parser/HTMLEntityTable.h | 52 + WebCore/html/parser/HTMLFormattingElementList.cpp | 134 + WebCore/html/parser/HTMLFormattingElementList.h | 134 + WebCore/html/parser/HTMLParserScheduler.cpp | 95 + WebCore/html/parser/HTMLParserScheduler.h | 90 + WebCore/html/parser/HTMLPreloadScanner.cpp | 182 ++ WebCore/html/parser/HTMLPreloadScanner.h | 64 + WebCore/html/parser/HTMLScriptRunner.cpp | 304 +++ WebCore/html/parser/HTMLScriptRunner.h | 98 + WebCore/html/parser/HTMLScriptRunnerHost.h | 54 + WebCore/html/parser/HTMLToken.h | 526 ++++ WebCore/html/parser/HTMLTokenizer.cpp | 1690 ++++++++++++ WebCore/html/parser/HTMLTokenizer.h | 298 +++ WebCore/html/parser/HTMLTreeBuilder.cpp | 2860 +++++++++++++++++++++ WebCore/html/parser/HTMLTreeBuilder.h | 272 ++ WebCore/html/parser/HTMLViewSourceParser.cpp | 112 + WebCore/html/parser/HTMLViewSourceParser.h | 76 + WebCore/html/parser/create-html-entity-table | 178 ++ 31 files changed, 12075 insertions(+) create mode 100644 WebCore/html/parser/CSSPreloadScanner.cpp create mode 100644 WebCore/html/parser/CSSPreloadScanner.h create mode 100644 WebCore/html/parser/HTMLConstructionSite.cpp create mode 100644 WebCore/html/parser/HTMLConstructionSite.h create mode 100644 WebCore/html/parser/HTMLDocumentParser.cpp create mode 100644 WebCore/html/parser/HTMLDocumentParser.h create mode 100644 WebCore/html/parser/HTMLElementStack.cpp create mode 100644 WebCore/html/parser/HTMLElementStack.h create mode 100644 WebCore/html/parser/HTMLEntityNames.in create mode 100644 WebCore/html/parser/HTMLEntityParser.cpp create mode 100644 WebCore/html/parser/HTMLEntityParser.h create mode 100644 WebCore/html/parser/HTMLEntitySearch.cpp create mode 100644 WebCore/html/parser/HTMLEntitySearch.h create mode 100644 WebCore/html/parser/HTMLEntityTable.h create mode 100644 WebCore/html/parser/HTMLFormattingElementList.cpp create mode 100644 WebCore/html/parser/HTMLFormattingElementList.h create mode 100644 WebCore/html/parser/HTMLParserScheduler.cpp create mode 100644 WebCore/html/parser/HTMLParserScheduler.h create mode 100644 WebCore/html/parser/HTMLPreloadScanner.cpp create mode 100644 WebCore/html/parser/HTMLPreloadScanner.h create mode 100644 WebCore/html/parser/HTMLScriptRunner.cpp create mode 100644 WebCore/html/parser/HTMLScriptRunner.h create mode 100644 WebCore/html/parser/HTMLScriptRunnerHost.h create mode 100644 WebCore/html/parser/HTMLToken.h create mode 100644 WebCore/html/parser/HTMLTokenizer.cpp create mode 100644 WebCore/html/parser/HTMLTokenizer.h create mode 100644 WebCore/html/parser/HTMLTreeBuilder.cpp create mode 100644 WebCore/html/parser/HTMLTreeBuilder.h create mode 100644 WebCore/html/parser/HTMLViewSourceParser.cpp create mode 100644 WebCore/html/parser/HTMLViewSourceParser.h create mode 100755 WebCore/html/parser/create-html-entity-table (limited to 'WebCore/html/parser') diff --git a/WebCore/html/parser/CSSPreloadScanner.cpp b/WebCore/html/parser/CSSPreloadScanner.cpp new file mode 100644 index 0000000..729103e --- /dev/null +++ b/WebCore/html/parser/CSSPreloadScanner.cpp @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * Copyright (C) 2009 Torch Mobile, Inc. http://www.torchmobile.com/ + * Copyright (C) 2010 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 APPLE 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 APPLE 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" +#include "CSSPreloadScanner.h" + +#include "CSSHelper.h" +#include "CachedCSSStyleSheet.h" +#include "DocLoader.h" +#include "Document.h" +#include "HTMLToken.h" + +namespace WebCore { + +static inline bool isWhitespace(UChar c) +{ + return c == ' ' || c == '\n' || c == '\r' || c == '\t'; +} + +CSSPreloadScanner::CSSPreloadScanner(Document* document) + : m_document(document) +{ + reset(); +} + +void CSSPreloadScanner::reset() +{ + m_state = Initial; + m_rule.clear(); + m_ruleValue.clear(); +} + +void CSSPreloadScanner::scan(const HTMLToken& token, bool scanningBody) +{ + m_scanningBody = scanningBody; + + const HTMLToken::DataVector& characters = token.characters(); + for (HTMLToken::DataVector::const_iterator iter = characters.begin(); + iter != characters.end(); ++iter) { + tokenize(*iter); + } +} + +inline void CSSPreloadScanner::tokenize(UChar c) +{ + // We are just interested in @import rules, no need for real tokenization here + // Searching for other types of resources is probably low payoff. + switch (m_state) { + case Initial: + if (c == '@') + m_state = RuleStart; + else if (c == '/') + m_state = MaybeComment; + break; + case MaybeComment: + if (c == '*') + m_state = Comment; + else + m_state = Initial; + break; + case Comment: + if (c == '*') + m_state = MaybeCommentEnd; + break; + case MaybeCommentEnd: + if (c == '/') + m_state = Initial; + else if (c == '*') + ; + else + m_state = Comment; + break; + case RuleStart: + if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) { + m_rule.clear(); + m_ruleValue.clear(); + m_rule.append(c); + m_state = Rule; + } else + m_state = Initial; + break; + case Rule: + if (isWhitespace(c)) + m_state = AfterRule; + else if (c == ';') + m_state = Initial; + else + m_rule.append(c); + break; + case AfterRule: + if (isWhitespace(c)) + ; + else if (c == ';') + m_state = Initial; + else { + m_state = RuleValue; + m_ruleValue.append(c); + } + break; + case RuleValue: + if (isWhitespace(c)) + m_state = AfterRuleValue; + else if (c == ';') { + emitRule(); + m_state = Initial; + } else + m_ruleValue.append(c); + break; + case AfterRuleValue: + if (isWhitespace(c)) + ; + else if (c == ';') { + emitRule(); + m_state = Initial; + } else { + // FIXME: media rules + m_state = Initial; + } + break; + } +} + +void CSSPreloadScanner::emitRule() +{ + String rule(m_rule.data(), m_rule.size()); + if (equalIgnoringCase(rule, "import") && !m_ruleValue.isEmpty()) { + String value(m_ruleValue.data(), m_ruleValue.size()); + String url = deprecatedParseURL(value); + if (!url.isEmpty()) + m_document->docLoader()->preload(CachedResource::CSSStyleSheet, url, String(), m_scanningBody); + } + m_rule.clear(); + m_ruleValue.clear(); +} + +} diff --git a/WebCore/html/parser/CSSPreloadScanner.h b/WebCore/html/parser/CSSPreloadScanner.h new file mode 100644 index 0000000..7ac282f --- /dev/null +++ b/WebCore/html/parser/CSSPreloadScanner.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * Copyright (C) 2010 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 APPLE 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 APPLE 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. + */ + +#ifndef CSSPreloadScanner_h +#define CSSPreloadScanner_h + +#include "PlatformString.h" +#include + +namespace WebCore { + +class Document; +class HTMLToken; + +class CSSPreloadScanner : public Noncopyable { +public: + CSSPreloadScanner(Document*); + + void reset(); + void scan(const HTMLToken&, bool scanningBody); + +private: + enum State { + Initial, + MaybeComment, + Comment, + MaybeCommentEnd, + RuleStart, + Rule, + AfterRule, + RuleValue, + AfterRuleValue + }; + + inline void tokenize(UChar c); + void emitRule(); + + State m_state; + Vector m_rule; + Vector m_ruleValue; + + bool m_scanningBody; + Document* m_document; +}; + +} + +#endif diff --git a/WebCore/html/parser/HTMLConstructionSite.cpp b/WebCore/html/parser/HTMLConstructionSite.cpp new file mode 100644 index 0000000..975b1af --- /dev/null +++ b/WebCore/html/parser/HTMLConstructionSite.cpp @@ -0,0 +1,467 @@ +/* + * Copyright (C) 2010 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" +#include "HTMLTreeBuilder.h" + +#include "Comment.h" +#include "DocumentFragment.h" +#include "DocumentType.h" +#include "Element.h" +#include "Frame.h" +#include "HTMLDocument.h" +#include "HTMLElementFactory.h" +#include "HTMLFormElement.h" +#include "HTMLHtmlElement.h" +#include "HTMLNames.h" +#include "HTMLScriptElement.h" +#include "HTMLToken.h" +#include "HTMLTokenizer.h" +#include "LocalizedStrings.h" +#if ENABLE(MATHML) +#include "MathMLNames.h" +#endif +#include "NotImplemented.h" +#if ENABLE(SVG) +#include "SVGNames.h" +#endif +#include "ScriptController.h" +#include "Settings.h" +#include "Text.h" +#include + +namespace WebCore { + +using namespace HTMLNames; + +namespace { + +bool hasImpliedEndTag(Element* element) +{ + return element->hasTagName(ddTag) + || element->hasTagName(dtTag) + || element->hasTagName(liTag) + || element->hasTagName(optionTag) + || element->hasTagName(optgroupTag) + || element->hasTagName(pTag) + || element->hasTagName(rpTag) + || element->hasTagName(rtTag); +} + +bool causesFosterParenting(const QualifiedName& tagName) +{ + return tagName == tableTag + || tagName == tbodyTag + || tagName == tfootTag + || tagName == theadTag + || tagName == trTag; +} + +} // namespace + +template +PassRefPtr HTMLConstructionSite::attach(ContainerNode* parent, PassRefPtr prpChild) +{ + RefPtr child = prpChild; + + // FIXME: It's confusing that HTMLConstructionSite::attach does the magic + // redirection to the foster parent but HTMLConstructionSite::attachAtSite + // doesn't. It feels like we're missing a concept somehow. + if (shouldFosterParent()) { + fosterParent(child.get()); + ASSERT(child->attached() || !child->parent() || !child->parent()->attached()); + return child.release(); + } + + parent->parserAddChild(child); + + // An event handler (DOM Mutation, beforeload, et al.) could have removed + // the child, in which case we shouldn't try attaching it. + if (!child->parentNode()) + return child.release(); + + // It's slightly unfortunate that we need to hold a reference to child + // here to call attach(). We should investigate whether we can rely on + // |parent| to hold a ref at this point. In the common case (at least + // for elements), however, we'll get to use this ref in the stack of + // open elements. + if (parent->attached() && !child->attached()) + child->attach(); + return child.release(); +} + +void HTMLConstructionSite::attachAtSite(const AttachmentSite& site, PassRefPtr prpChild) +{ + RefPtr child = prpChild; + + if (site.nextChild) { + site.parent->parserInsertBefore(child, site.nextChild); + if (site.parent->attached() && !child->attached()) + child->attach(); + return; + } + site.parent->parserAddChild(child); + // It's slightly unfortunate that we need to hold a reference to child + // here to call attach(). We should investigate whether we can rely on + // |site.parent| to hold a ref at this point. + if (site.parent->attached() && !child->attached()) + child->attach(); +} + +HTMLConstructionSite::HTMLConstructionSite(Document* document, FragmentScriptingPermission scriptingPermission, bool isParsingFragment) + : m_document(document) + , m_fragmentScriptingPermission(scriptingPermission) + , m_isParsingFragment(isParsingFragment) + , m_redirectAttachToFosterParent(false) +{ +} + +HTMLConstructionSite::~HTMLConstructionSite() +{ +} + +void HTMLConstructionSite::detach() +{ + m_document = 0; +} + +void HTMLConstructionSite::setForm(HTMLFormElement* form) +{ + // This method should only be needed for HTMLTreeBuilder in the fragment case. + ASSERT(!m_form); + m_form = form; +} + +PassRefPtr HTMLConstructionSite::takeForm() +{ + return m_form.release(); +} + +void HTMLConstructionSite::dispatchDocumentElementAvailableIfNeeded() +{ + ASSERT(m_document); + if (m_document->frame() && !m_isParsingFragment) + m_document->frame()->loader()->dispatchDocumentElementAvailable(); +} + +void HTMLConstructionSite::insertHTMLHtmlStartTagBeforeHTML(AtomicHTMLToken& token) +{ + RefPtr element = HTMLHtmlElement::create(m_document); + element->setAttributeMap(token.takeAtributes(), m_fragmentScriptingPermission); + m_openElements.pushHTMLHtmlElement(attach(m_document, element.release())); + dispatchDocumentElementAvailableIfNeeded(); +} + +void HTMLConstructionSite::mergeAttributesFromTokenIntoElement(AtomicHTMLToken& token, Element* element) +{ + if (!token.attributes()) + return; + + NamedNodeMap* attributes = element->attributes(false); + for (unsigned i = 0; i < token.attributes()->length(); ++i) { + Attribute* attribute = token.attributes()->attributeItem(i); + if (!attributes->getAttributeItem(attribute->name())) + element->setAttribute(attribute->name(), attribute->value()); + } +} + +void HTMLConstructionSite::insertHTMLHtmlStartTagInBody(AtomicHTMLToken& token) +{ + // FIXME: parse error + mergeAttributesFromTokenIntoElement(token, m_openElements.htmlElement()); +} + +void HTMLConstructionSite::insertHTMLBodyStartTagInBody(AtomicHTMLToken& token) +{ + // FIXME: parse error + mergeAttributesFromTokenIntoElement(token, m_openElements.bodyElement()); +} + +void HTMLConstructionSite::insertDoctype(AtomicHTMLToken& token) +{ + ASSERT(token.type() == HTMLToken::DOCTYPE); + attach(m_document, DocumentType::create(m_document, token.name(), String::adopt(token.publicIdentifier()), String::adopt(token.systemIdentifier()))); + + if (token.forceQuirks()) + m_document->setCompatibilityMode(Document::QuirksMode); + else + m_document->setCompatibilityModeFromDoctype(); +} + +void HTMLConstructionSite::insertComment(AtomicHTMLToken& token) +{ + ASSERT(token.type() == HTMLToken::Comment); + attach(currentElement(), Comment::create(m_document, token.comment())); +} + +void HTMLConstructionSite::insertCommentOnDocument(AtomicHTMLToken& token) +{ + ASSERT(token.type() == HTMLToken::Comment); + attach(m_document, Comment::create(m_document, token.comment())); +} + +void HTMLConstructionSite::insertCommentOnHTMLHtmlElement(AtomicHTMLToken& token) +{ + ASSERT(token.type() == HTMLToken::Comment); + attach(m_openElements.htmlElement(), Comment::create(m_document, token.comment())); +} + +PassRefPtr HTMLConstructionSite::attachToCurrent(PassRefPtr child) +{ + return attach(currentElement(), child); +} + +void HTMLConstructionSite::insertHTMLHtmlElement(AtomicHTMLToken& token) +{ + ASSERT(!shouldFosterParent()); + m_openElements.pushHTMLHtmlElement(attachToCurrent(createHTMLElement(token))); + dispatchDocumentElementAvailableIfNeeded(); +} + +void HTMLConstructionSite::insertHTMLHeadElement(AtomicHTMLToken& token) +{ + ASSERT(!shouldFosterParent()); + m_head = attachToCurrent(createHTMLElement(token)); + m_openElements.pushHTMLHeadElement(m_head); +} + +void HTMLConstructionSite::insertHTMLBodyElement(AtomicHTMLToken& token) +{ + ASSERT(!shouldFosterParent()); + m_openElements.pushHTMLBodyElement(attachToCurrent(createHTMLElement(token))); +} + +void HTMLConstructionSite::insertHTMLFormElement(AtomicHTMLToken& token, bool isDemoted) +{ + RefPtr element = createHTMLElement(token); + ASSERT(element->hasTagName(formTag)); + RefPtr form = static_pointer_cast(element.release()); + form->setDemoted(isDemoted); + m_openElements.push(attachToCurrent(form.release())); + ASSERT(currentElement()->isHTMLElement()); + ASSERT(currentElement()->hasTagName(formTag)); + m_form = static_cast(currentElement()); +} + +void HTMLConstructionSite::insertHTMLElement(AtomicHTMLToken& token) +{ + m_openElements.push(attachToCurrent(createHTMLElement(token))); +} + +void HTMLConstructionSite::insertSelfClosingHTMLElement(AtomicHTMLToken& token) +{ + ASSERT(token.type() == HTMLToken::StartTag); + RefPtr element = attachToCurrent(createHTMLElement(token)); + // Normally HTMLElementStack is responsible for calling finishParsingChildren, + // but self-closing elements are never in the element stack so the stack + // doesn't get a chance to tell them that we're done parsing their children. + element->finishParsingChildren(); + // FIXME: Do we want to acknowledge the token's self-closing flag? + // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#acknowledge-self-closing-flag +} + +void HTMLConstructionSite::insertFormattingElement(AtomicHTMLToken& token) +{ + // http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#the-stack-of-open-elements + // Possible active formatting elements include: + // a, b, big, code, em, font, i, nobr, s, small, strike, strong, tt, and u. + insertHTMLElement(token); + m_activeFormattingElements.append(currentElement()); +} + +void HTMLConstructionSite::insertScriptElement(AtomicHTMLToken& token) +{ + RefPtr element = HTMLScriptElement::create(scriptTag, m_document, true); + if (m_fragmentScriptingPermission == FragmentScriptingAllowed) + element->setAttributeMap(token.takeAtributes(), m_fragmentScriptingPermission); + m_openElements.push(attachToCurrent(element.release())); +} + +void HTMLConstructionSite::insertForeignElement(AtomicHTMLToken& token, const AtomicString& namespaceURI) +{ + ASSERT(token.type() == HTMLToken::StartTag); + notImplemented(); // parseError when xmlns or xmlns:xlink are wrong. + + RefPtr element = attachToCurrent(createElement(token, namespaceURI)); + if (!token.selfClosing()) + m_openElements.push(element); +} + +void HTMLConstructionSite::insertTextNode(const String& characters) +{ + AttachmentSite site; + site.parent = currentElement(); + site.nextChild = 0; + if (shouldFosterParent()) + findFosterSite(site); + + Node* previousChild = site.nextChild ? site.nextChild->previousSibling() : site.parent->lastChild(); + if (previousChild && previousChild->isTextNode()) { + // FIXME: We're only supposed to append to this text node if it + // was the last text node inserted by the parser. + CharacterData* textNode = static_cast(previousChild); + textNode->parserAppendData(characters); + return; + } + + attachAtSite(site, Text::create(m_document, characters)); +} + +PassRefPtr HTMLConstructionSite::createElement(AtomicHTMLToken& token, const AtomicString& namespaceURI) +{ + QualifiedName tagName(nullAtom, token.name(), namespaceURI); + RefPtr element = m_document->createElement(tagName, true); + element->setAttributeMap(token.takeAtributes(), m_fragmentScriptingPermission); + return element.release(); +} + +PassRefPtr HTMLConstructionSite::createHTMLElement(AtomicHTMLToken& token) +{ + QualifiedName tagName(nullAtom, token.name(), xhtmlNamespaceURI); + // FIXME: This can't use HTMLConstructionSite::createElement because we + // have to pass the current form element. We should rework form association + // to occur after construction to allow better code sharing here. + RefPtr element = HTMLElementFactory::createHTMLElement(tagName, m_document, form(), true); + element->setAttributeMap(token.takeAtributes(), m_fragmentScriptingPermission); + ASSERT(element->isHTMLElement()); + return element.release(); +} + +PassRefPtr HTMLConstructionSite::createHTMLElementFromElementRecord(HTMLElementStack::ElementRecord* record) +{ + return createHTMLElementFromSavedElement(record->element()); +} + +namespace { + +PassRefPtr cloneAttributes(Element* element) +{ + NamedNodeMap* attributes = element->attributes(true); + if (!attributes) + return 0; + + RefPtr newAttributes = NamedNodeMap::create(); + for (size_t i = 0; i < attributes->length(); ++i) { + Attribute* attribute = attributes->attributeItem(i); + RefPtr clone = Attribute::createMapped(attribute->name(), attribute->value()); + newAttributes->addAttribute(clone); + } + return newAttributes.release(); +} + +} + +PassRefPtr HTMLConstructionSite::createHTMLElementFromSavedElement(Element* element) +{ + // FIXME: This method is wrong. We should be using the original token. + // Using an Element* causes us to fail examples like this: + //

TEXT
+ // When reconstructTheActiveFormattingElements calls this method to open + // a second tag to wrap TEXT, it will have id "2", even though the HTML5 + // spec implies it should be "1". Minefield matches the HTML5 spec here. + + ASSERT(element->isHTMLElement()); // otherwise localName() might be wrong. + AtomicHTMLToken fakeToken(HTMLToken::StartTag, element->localName(), cloneAttributes(element)); + return createHTMLElement(fakeToken); +} + +bool HTMLConstructionSite::indexOfFirstUnopenFormattingElement(unsigned& firstUnopenElementIndex) const +{ + if (m_activeFormattingElements.isEmpty()) + return false; + unsigned index = m_activeFormattingElements.size(); + do { + --index; + const HTMLFormattingElementList::Entry& entry = m_activeFormattingElements.at(index); + if (entry.isMarker() || m_openElements.contains(entry.element())) { + firstUnopenElementIndex = index + 1; + return firstUnopenElementIndex < m_activeFormattingElements.size(); + } + } while (index); + firstUnopenElementIndex = index; + return true; +} + +void HTMLConstructionSite::reconstructTheActiveFormattingElements() +{ + unsigned firstUnopenElementIndex; + if (!indexOfFirstUnopenFormattingElement(firstUnopenElementIndex)) + return; + + unsigned unopenEntryIndex = firstUnopenElementIndex; + ASSERT(unopenEntryIndex < m_activeFormattingElements.size()); + for (; unopenEntryIndex < m_activeFormattingElements.size(); ++unopenEntryIndex) { + HTMLFormattingElementList::Entry& unopenedEntry = m_activeFormattingElements.at(unopenEntryIndex); + RefPtr reconstructed = createHTMLElementFromSavedElement(unopenedEntry.element()); + m_openElements.push(attachToCurrent(reconstructed.release())); + unopenedEntry.replaceElement(currentElement()); + } +} + +void HTMLConstructionSite::generateImpliedEndTagsWithExclusion(const AtomicString& tagName) +{ + while (hasImpliedEndTag(currentElement()) && !currentElement()->hasLocalName(tagName)) + m_openElements.pop(); +} + +void HTMLConstructionSite::generateImpliedEndTags() +{ + while (hasImpliedEndTag(currentElement())) + m_openElements.pop(); +} + +void HTMLConstructionSite::findFosterSite(AttachmentSite& site) +{ + HTMLElementStack::ElementRecord* lastTableElementRecord = m_openElements.topmost(tableTag.localName()); + if (lastTableElementRecord) { + Element* lastTableElement = lastTableElementRecord->element(); + if (ContainerNode* parent = lastTableElement->parent()) { + site.parent = parent; + site.nextChild = lastTableElement; + return; + } + site.parent = lastTableElementRecord->next()->element(); + site.nextChild = 0; + return; + } + // Fragment case + site.parent = m_openElements.bottom(); // element + site.nextChild = 0; +} + +bool HTMLConstructionSite::shouldFosterParent() const +{ + return m_redirectAttachToFosterParent + && causesFosterParenting(currentElement()->tagQName()); +} + +void HTMLConstructionSite::fosterParent(Node* node) +{ + AttachmentSite site; + findFosterSite(site); + attachAtSite(site, node); +} + +} diff --git a/WebCore/html/parser/HTMLConstructionSite.h b/WebCore/html/parser/HTMLConstructionSite.h new file mode 100644 index 0000000..6bed6a7 --- /dev/null +++ b/WebCore/html/parser/HTMLConstructionSite.h @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2010 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. + */ + +#ifndef HTMLConstructionSite_h +#define HTMLConstructionSite_h + +#include "FragmentScriptingPermission.h" +#include "HTMLElementStack.h" +#include "HTMLFormattingElementList.h" +#include "NotImplemented.h" +#include +#include +#include + +namespace WebCore { + +class AtomicHTMLToken; +class Document; +class Element; + +class HTMLConstructionSite : public Noncopyable { +public: + HTMLConstructionSite(Document*, FragmentScriptingPermission, bool isParsingFragment); + ~HTMLConstructionSite(); + + void detach(); + + void insertDoctype(AtomicHTMLToken&); + void insertComment(AtomicHTMLToken&); + void insertCommentOnDocument(AtomicHTMLToken&); + void insertCommentOnHTMLHtmlElement(AtomicHTMLToken&); + void insertHTMLElement(AtomicHTMLToken&); + void insertSelfClosingHTMLElement(AtomicHTMLToken&); + void insertFormattingElement(AtomicHTMLToken&); + void insertHTMLHtmlElement(AtomicHTMLToken&); + void insertHTMLHeadElement(AtomicHTMLToken&); + void insertHTMLBodyElement(AtomicHTMLToken&); + void insertHTMLFormElement(AtomicHTMLToken&, bool isDemoted = false); + void insertScriptElement(AtomicHTMLToken&); + void insertTextNode(const String&); + void insertForeignElement(AtomicHTMLToken&, const AtomicString& namespaceURI); + + void insertHTMLHtmlStartTagBeforeHTML(AtomicHTMLToken&); + void insertHTMLHtmlStartTagInBody(AtomicHTMLToken&); + void insertHTMLBodyStartTagInBody(AtomicHTMLToken&); + + PassRefPtr createHTMLElement(AtomicHTMLToken&); + PassRefPtr createHTMLElementFromElementRecord(HTMLElementStack::ElementRecord*); + + bool shouldFosterParent() const; + void fosterParent(Node*); + + bool indexOfFirstUnopenFormattingElement(unsigned& firstUnopenElementIndex) const; + void reconstructTheActiveFormattingElements(); + + void generateImpliedEndTags(); + void generateImpliedEndTagsWithExclusion(const AtomicString& tagName); + + Element* currentElement() const { return m_openElements.top(); } + Element* oneBelowTop() const { return m_openElements.oneBelowTop(); } + + HTMLElementStack* openElements() const { return &m_openElements; } + HTMLFormattingElementList* activeFormattingElements() const { return &m_activeFormattingElements; } + + Element* head() const { return m_head.get(); } + + void setForm(HTMLFormElement*); + HTMLFormElement* form() const { return m_form.get(); } + PassRefPtr takeForm(); + + class RedirectToFosterParentGuard : public Noncopyable { + public: + RedirectToFosterParentGuard(HTMLConstructionSite& tree) + : m_tree(tree) + , m_wasRedirectingBefore(tree.m_redirectAttachToFosterParent) + { + m_tree.m_redirectAttachToFosterParent = true; + } + + ~RedirectToFosterParentGuard() + { + m_tree.m_redirectAttachToFosterParent = m_wasRedirectingBefore; + } + + private: + HTMLConstructionSite& m_tree; + bool m_wasRedirectingBefore; + }; + +private: + struct AttachmentSite { + ContainerNode* parent; + Node* nextChild; + }; + + template + PassRefPtr attach(ContainerNode* parent, PassRefPtr child); + PassRefPtr attachToCurrent(PassRefPtr); + + void attachAtSite(const AttachmentSite&, PassRefPtr child); + void findFosterSite(AttachmentSite&); + + PassRefPtr createHTMLElementFromSavedElement(Element*); + PassRefPtr createElement(AtomicHTMLToken&, const AtomicString& namespaceURI); + + void mergeAttributesFromTokenIntoElement(AtomicHTMLToken&, Element*); + void dispatchDocumentElementAvailableIfNeeded(); + + Document* m_document; + RefPtr m_head; + RefPtr m_form; + mutable HTMLElementStack m_openElements; + mutable HTMLFormattingElementList m_activeFormattingElements; + + FragmentScriptingPermission m_fragmentScriptingPermission; + bool m_isParsingFragment; + + // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#parsing-main-intable + // In the "in table" insertion mode, we sometimes get into a state where + // "whenever a node would be inserted into the current node, it must instead + // be foster parented." This flag tracks whether we're in that state. + bool m_redirectAttachToFosterParent; +}; + +} + +#endif diff --git a/WebCore/html/parser/HTMLDocumentParser.cpp b/WebCore/html/parser/HTMLDocumentParser.cpp new file mode 100644 index 0000000..0a1208d --- /dev/null +++ b/WebCore/html/parser/HTMLDocumentParser.cpp @@ -0,0 +1,520 @@ +/* + * Copyright (C) 2010 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 APPLE 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 APPLE 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" +#include "HTMLDocumentParser.h" + +#include "DocumentFragment.h" +#include "Element.h" +#include "Frame.h" +#include "HTMLNames.h" +#include "HTMLParserScheduler.h" +#include "HTMLTokenizer.h" +#include "HTMLPreloadScanner.h" +#include "HTMLScriptRunner.h" +#include "HTMLTreeBuilder.h" +#include "HTMLDocument.h" +#include "XSSAuditor.h" +#include + +#ifdef ANDROID_INSTRUMENT +#include "TimeCounter.h" +#endif + +#if ENABLE(INSPECTOR) +#include "InspectorTimelineAgent.h" +#endif + +namespace WebCore { + +using namespace HTMLNames; + +namespace { + +class NestingLevelIncrementer : public Noncopyable { +public: + explicit NestingLevelIncrementer(int& counter) + : m_counter(&counter) + { + ++(*m_counter); + } + + ~NestingLevelIncrementer() + { + --(*m_counter); + } + +private: + int* m_counter; +}; + +// This is a direct transcription of step 4 from: +// http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html#fragment-case +HTMLTokenizer::State tokenizerStateForContextElement(Element* contextElement, bool reportErrors) +{ + if (!contextElement) + return HTMLTokenizer::DataState; + + const QualifiedName& contextTag = contextElement->tagQName(); + + if (contextTag.matches(titleTag) || contextTag.matches(textareaTag)) + return HTMLTokenizer::RCDATAState; + if (contextTag.matches(styleTag) + || contextTag.matches(xmpTag) + || contextTag.matches(iframeTag) + || (contextTag.matches(noembedTag) && HTMLTreeBuilder::pluginsEnabled(contextElement->document()->frame())) + || (contextTag.matches(noscriptTag) && HTMLTreeBuilder::scriptEnabled(contextElement->document()->frame())) + || contextTag.matches(noframesTag)) + return reportErrors ? HTMLTokenizer::RAWTEXTState : HTMLTokenizer::PLAINTEXTState; + if (contextTag.matches(scriptTag)) + return reportErrors ? HTMLTokenizer::ScriptDataState : HTMLTokenizer::PLAINTEXTState; + if (contextTag.matches(plaintextTag)) + return HTMLTokenizer::PLAINTEXTState; + return HTMLTokenizer::DataState; +} + +} // namespace + +HTMLDocumentParser::HTMLDocumentParser(HTMLDocument* document, bool reportErrors) + : ScriptableDocumentParser(document) + , m_tokenizer(HTMLTokenizer::create()) + , m_scriptRunner(HTMLScriptRunner::create(document, this)) + , m_treeBuilder(HTMLTreeBuilder::create(m_tokenizer.get(), document, reportErrors)) + , m_parserScheduler(HTMLParserScheduler::create(this)) + , m_endWasDelayed(false) + , m_writeNestingLevel(0) +{ +} + +// FIXME: Member variables should be grouped into self-initializing structs to +// minimize code duplication between these constructors. +HTMLDocumentParser::HTMLDocumentParser(DocumentFragment* fragment, Element* contextElement, FragmentScriptingPermission scriptingPermission) + : ScriptableDocumentParser(fragment->document()) + , m_tokenizer(HTMLTokenizer::create()) + , m_treeBuilder(HTMLTreeBuilder::create(m_tokenizer.get(), fragment, contextElement, scriptingPermission)) + , m_endWasDelayed(false) + , m_writeNestingLevel(0) +{ + bool reportErrors = false; // For now document fragment parsing never reports errors. + m_tokenizer->setState(tokenizerStateForContextElement(contextElement, reportErrors)); +} + +HTMLDocumentParser::~HTMLDocumentParser() +{ + ASSERT(!m_parserScheduler); + ASSERT(!m_writeNestingLevel); + ASSERT(!m_preloadScanner); +} + +void HTMLDocumentParser::detach() +{ + DocumentParser::detach(); + if (m_scriptRunner) + m_scriptRunner->detach(); + m_treeBuilder->detach(); + // FIXME: It seems wrong that we would have a preload scanner here. + // Yet during fast/dom/HTMLScriptElement/script-load-events.html we do. + m_preloadScanner.clear(); + m_parserScheduler.clear(); // Deleting the scheduler will clear any timers. +} + +void HTMLDocumentParser::stopParsing() +{ + DocumentParser::stopParsing(); + m_parserScheduler.clear(); // Deleting the scheduler will clear any timers. +} + +bool HTMLDocumentParser::processingData() const +{ + return isScheduledForResume() || inWrite(); +} + +void HTMLDocumentParser::pumpTokenizerIfPossible(SynchronousMode mode) +{ + if (m_parserStopped || m_treeBuilder->isPaused()) + return; + + // Once a resume is scheduled, HTMLParserScheduler controls when we next pump. + if (isScheduledForResume()) { + ASSERT(mode == AllowYield); + return; + } + + pumpTokenizer(mode); +} + +bool HTMLDocumentParser::isScheduledForResume() const +{ + return m_parserScheduler && m_parserScheduler->isScheduledForResume(); +} + +// Used by HTMLParserScheduler +void HTMLDocumentParser::resumeParsingAfterYield() +{ + // pumpTokenizer can cause this parser to be detached from the Document, + // but we need to ensure it isn't deleted yet. + RefPtr protect(this); + + // We should never be here unless we can pump immediately. Call pumpTokenizer() + // directly so that ASSERTS will fire if we're wrong. + pumpTokenizer(AllowYield); + endIfDelayed(); +} + +bool HTMLDocumentParser::runScriptsForPausedTreeBuilder() +{ + ASSERT(m_treeBuilder->isPaused()); + + int scriptStartLine = 0; + RefPtr scriptElement = m_treeBuilder->takeScriptToProcess(scriptStartLine); + // We will not have a scriptRunner when parsing a DocumentFragment. + if (!m_scriptRunner) + return true; + return m_scriptRunner->execute(scriptElement.release(), scriptStartLine); +} + +void HTMLDocumentParser::pumpTokenizer(SynchronousMode mode) +{ + ASSERT(!isDetached()); + ASSERT(!m_parserStopped); + ASSERT(!m_treeBuilder->isPaused()); + ASSERT(!isScheduledForResume()); + // ASSERT that this object is both attached to the Document and protected. + ASSERT(refCount() >= 2); + + // We tell the InspectorTimelineAgent about every pump, even if we + // end up pumping nothing. It can filter out empty pumps itself. + willPumpLexer(); + + HTMLParserScheduler::PumpSession session; + // FIXME: This loop body has is now too long and needs cleanup. + while (mode == ForceSynchronous || m_parserScheduler->shouldContinueParsing(session)) { + if (!m_tokenizer->nextToken(m_input.current(), m_token)) + break; + + m_treeBuilder->constructTreeFromToken(m_token); + m_token.clear(); + + // JavaScript may have stopped or detached the parser. + if (isDetached() || m_parserStopped) + return; + + // The parser will pause itself when waiting on a script to load or run. + if (!m_treeBuilder->isPaused()) + continue; + + // If we're paused waiting for a script, we try to execute scripts before continuing. + bool shouldContinueParsing = runScriptsForPausedTreeBuilder(); + m_treeBuilder->setPaused(!shouldContinueParsing); + + // JavaScript may have stopped or detached the parser. + if (isDetached() || m_parserStopped) + return; + + if (!shouldContinueParsing) + break; + } + + // Ensure we haven't been totally deref'ed after pumping. Any caller of this + // function should be holding a RefPtr to this to ensure we weren't deleted. + ASSERT(refCount() >= 1); + + if (isWaitingForScripts()) { + ASSERT(m_tokenizer->state() == HTMLTokenizer::DataState); + if (!m_preloadScanner) { + m_preloadScanner.set(new HTMLPreloadScanner(document())); + m_preloadScanner->appendToEnd(m_input.current()); + } + m_preloadScanner->scan(); + } + + didPumpLexer(); +} + +void HTMLDocumentParser::willPumpLexer() +{ +#if ENABLE(INSPECTOR) + // FIXME: m_input.current().length() is only accurate if we + // end up parsing the whole buffer in this pump. We should pass how + // much we parsed as part of didWriteHTML instead of willWriteHTML. + if (InspectorTimelineAgent* timelineAgent = document()->inspectorTimelineAgent()) + timelineAgent->willWriteHTML(m_input.current().length(), m_tokenizer->lineNumber()); +#endif +} + +void HTMLDocumentParser::didPumpLexer() +{ +#if ENABLE(INSPECTOR) + if (InspectorTimelineAgent* timelineAgent = document()->inspectorTimelineAgent()) + timelineAgent->didWriteHTML(m_tokenizer->lineNumber()); +#endif +} + +bool HTMLDocumentParser::hasInsertionPoint() +{ + return m_input.hasInsertionPoint(); +} + +void HTMLDocumentParser::insert(const SegmentedString& source) +{ + if (m_parserStopped) + return; + +#ifdef ANDROID_INSTRUMENT + android::TimeCounter::start(android::TimeCounter::ParsingTimeCounter); +#endif + + // pumpTokenizer can cause this parser to be detached from the Document, + // but we need to ensure it isn't deleted yet. + RefPtr protect(this); + + { + NestingLevelIncrementer nestingLevelIncrementer(m_writeNestingLevel); + + SegmentedString excludedLineNumberSource(source); + excludedLineNumberSource.setExcludeLineNumbers(); + m_input.insertAtCurrentInsertionPoint(excludedLineNumberSource); + pumpTokenizerIfPossible(ForceSynchronous); + } + + endIfDelayed(); +} + +void HTMLDocumentParser::append(const SegmentedString& source) +{ + if (m_parserStopped) + return; + + // pumpTokenizer can cause this parser to be detached from the Document, + // but we need to ensure it isn't deleted yet. + RefPtr protect(this); + + { + NestingLevelIncrementer nestingLevelIncrementer(m_writeNestingLevel); + + m_input.appendToEnd(source); + if (m_preloadScanner) + m_preloadScanner->appendToEnd(source); + + if (m_writeNestingLevel > 1) { + // We've gotten data off the network in a nested write. + // We don't want to consume any more of the input stream now. Do + // not worry. We'll consume this data in a less-nested write(). +#ifdef ANDROID_INSTRUMENT + android::TimeCounter::record(android::TimeCounter::ParsingTimeCounter, __FUNCTION__); +#endif + return; + } + + pumpTokenizerIfPossible(AllowYield); + } + + endIfDelayed(); +#ifdef ANDROID_INSTRUMENT + android::TimeCounter::record(android::TimeCounter::ParsingTimeCounter, __FUNCTION__); +#endif +} + +void HTMLDocumentParser::end() +{ + ASSERT(!isDetached()); + ASSERT(!isScheduledForResume()); + + // pumpTokenizer can cause this parser to be detached from the Document, + // but we need to ensure it isn't deleted yet. + RefPtr protect(this); + + // NOTE: This pump should only ever emit buffered character tokens, + // so ForceSynchronous vs. AllowYield should be meaningless. + pumpTokenizerIfPossible(ForceSynchronous); + + // Informs the the rest of WebCore that parsing is really finished (and deletes this). + m_treeBuilder->finished(); +} + +void HTMLDocumentParser::attemptToEnd() +{ + // finish() indicates we will not receive any more data. If we are waiting on + // an external script to load, we can't finish parsing quite yet. + + if (shouldDelayEnd()) { + m_endWasDelayed = true; + return; + } + end(); +} + +void HTMLDocumentParser::endIfDelayed() +{ + // If we've already been detached, don't bother ending. + if (isDetached()) + return; + + if (!m_endWasDelayed || shouldDelayEnd()) + return; + + m_endWasDelayed = false; + end(); +} + +void HTMLDocumentParser::finish() +{ + // FIXME: We should ASSERT(!m_parserStopped) here, since it does not + // makes sense to call any methods on DocumentParser once it's been stopped. + // However, FrameLoader::stop calls Document::finishParsing unconditionally + // which in turn calls m_parser->finish(). + + // We're not going to get any more data off the network, so we tell the + // input stream we've reached the end of file. finish() can be called more + // than once, if the first time does not call end(). + if (!m_input.haveSeenEndOfFile()) + m_input.markEndOfFile(); + attemptToEnd(); +} + +bool HTMLDocumentParser::finishWasCalled() +{ + return m_input.haveSeenEndOfFile(); +} + +// This function is virtual and just for the DocumentParser interface. +bool HTMLDocumentParser::isExecutingScript() const +{ + return inScriptExecution(); +} + +// This function is non-virtual and used throughout the implementation. +bool HTMLDocumentParser::inScriptExecution() const +{ + if (!m_scriptRunner) + return false; + return m_scriptRunner->isExecutingScript(); +} + +int HTMLDocumentParser::lineNumber() const +{ + return m_tokenizer->lineNumber(); +} + +int HTMLDocumentParser::columnNumber() const +{ + return m_tokenizer->columnNumber(); +} + +bool HTMLDocumentParser::isWaitingForScripts() const +{ + return m_treeBuilder->isPaused(); +} + +void HTMLDocumentParser::resumeParsingAfterScriptExecution() +{ + ASSERT(!inScriptExecution()); + ASSERT(!m_treeBuilder->isPaused()); + + m_preloadScanner.clear(); + pumpTokenizerIfPossible(AllowYield); + endIfDelayed(); +} + +void HTMLDocumentParser::watchForLoad(CachedResource* cachedScript) +{ + ASSERT(!cachedScript->isLoaded()); + // addClient would call notifyFinished if the load were complete. + // Callers do not expect to be re-entered from this call, so they should + // not an already-loaded CachedResource. + cachedScript->addClient(this); +} + +void HTMLDocumentParser::stopWatchingForLoad(CachedResource* cachedScript) +{ + cachedScript->removeClient(this); +} + +bool HTMLDocumentParser::shouldLoadExternalScriptFromSrc(const AtomicString& srcValue) +{ + if (!xssAuditor()) + return true; + return xssAuditor()->canLoadExternalScriptFromSrc(srcValue); +} + +void HTMLDocumentParser::notifyFinished(CachedResource* cachedResource) +{ + // pumpTokenizer can cause this parser to be detached from the Document, + // but we need to ensure it isn't deleted yet. + RefPtr protect(this); + + ASSERT(m_scriptRunner); + ASSERT(!inScriptExecution()); + ASSERT(m_treeBuilder->isPaused()); + // Note: We only ever wait on one script at a time, so we always know this + // is the one we were waiting on and can un-pause the tree builder. + m_treeBuilder->setPaused(false); + bool shouldContinueParsing = m_scriptRunner->executeScriptsWaitingForLoad(cachedResource); + m_treeBuilder->setPaused(!shouldContinueParsing); + if (shouldContinueParsing) + resumeParsingAfterScriptExecution(); +} + +void HTMLDocumentParser::executeScriptsWaitingForStylesheets() +{ + // Document only calls this when the Document owns the DocumentParser + // so this will not be called in the DocumentFragment case. + ASSERT(m_scriptRunner); + // Ignore calls unless we have a script blocking the parser waiting on a + // stylesheet load. Otherwise we are currently parsing and this + // is a re-entrant call from encountering a tag. + if (!m_scriptRunner->hasScriptsWaitingForStylesheets()) + return; + + // pumpTokenizer can cause this parser to be detached from the Document, + // but we need to ensure it isn't deleted yet. + RefPtr protect(this); + + ASSERT(!m_scriptRunner->isExecutingScript()); + ASSERT(m_treeBuilder->isPaused()); + // Note: We only ever wait on one script at a time, so we always know this + // is the one we were waiting on and can un-pause the tree builder. + m_treeBuilder->setPaused(false); + bool shouldContinueParsing = m_scriptRunner->executeScriptsWaitingForStylesheets(); + m_treeBuilder->setPaused(!shouldContinueParsing); + if (shouldContinueParsing) + resumeParsingAfterScriptExecution(); +} + +ScriptController* HTMLDocumentParser::script() const +{ + return document()->frame() ? document()->frame()->script() : 0; +} + +void HTMLDocumentParser::parseDocumentFragment(const String& source, DocumentFragment* fragment, Element* contextElement, FragmentScriptingPermission scriptingPermission) +{ + RefPtr parser = HTMLDocumentParser::create(fragment, contextElement, scriptingPermission); + parser->insert(source); // Use insert() so that the parser will not yield. + parser->finish(); + ASSERT(!parser->processingData()); // Make sure we're done. + parser->detach(); // Allows ~DocumentParser to assert it was detached before destruction. +} + +} diff --git a/WebCore/html/parser/HTMLDocumentParser.h b/WebCore/html/parser/HTMLDocumentParser.h new file mode 100644 index 0000000..da21a2b --- /dev/null +++ b/WebCore/html/parser/HTMLDocumentParser.h @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2010 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 APPLE 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 APPLE 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. + */ + +#ifndef HTMLDocumentParser_h +#define HTMLDocumentParser_h + +#include "CachedResourceClient.h" +#include "FragmentScriptingPermission.h" +#include "HTMLInputStream.h" +#include "HTMLScriptRunnerHost.h" +#include "HTMLToken.h" +#include "ScriptableDocumentParser.h" +#include "SegmentedString.h" +#include "Timer.h" +#include + +namespace WebCore { + +class Document; +class DocumentFragment; +class HTMLDocument; +class HTMLParserScheduler; +class HTMLTokenizer; +class HTMLScriptRunner; +class HTMLTreeBuilder; +class HTMLPreloadScanner; +class ScriptController; +class ScriptSourceCode; + +class HTMLDocumentParser : public ScriptableDocumentParser, HTMLScriptRunnerHost, CachedResourceClient { +public: + static PassRefPtr create(HTMLDocument* document, bool reportErrors) + { + return adoptRef(new HTMLDocumentParser(document, reportErrors)); + } + static PassRefPtr create(DocumentFragment* fragment, Element* contextElement, FragmentScriptingPermission permission) + { + return adoptRef(new HTMLDocumentParser(fragment, contextElement, permission)); + } + + virtual ~HTMLDocumentParser(); + + // Exposed for HTMLParserScheduler + void resumeParsingAfterYield(); + + static void parseDocumentFragment(const String&, DocumentFragment*, Element* contextElement, FragmentScriptingPermission = FragmentScriptingAllowed); + +protected: + virtual void insert(const SegmentedString&); + virtual void finish(); + + HTMLDocumentParser(HTMLDocument*, bool reportErrors); + HTMLDocumentParser(DocumentFragment*, Element* contextElement, FragmentScriptingPermission); + +private: + // DocumentParser + virtual void detach(); + virtual bool hasInsertionPoint(); + virtual void append(const SegmentedString&); + virtual bool finishWasCalled(); + virtual bool processingData() const; + virtual void stopParsing(); + virtual bool isWaitingForScripts() const; + virtual bool isExecutingScript() const; + virtual void executeScriptsWaitingForStylesheets(); + virtual int lineNumber() const; + virtual int columnNumber() const; + + // HTMLScriptRunnerHost + virtual void watchForLoad(CachedResource*); + virtual void stopWatchingForLoad(CachedResource*); + virtual bool shouldLoadExternalScriptFromSrc(const AtomicString&); + virtual HTMLInputStream& inputStream() { return m_input; } + + // CachedResourceClient + virtual void notifyFinished(CachedResource*); + + void willPumpLexer(); + void didPumpLexer(); + + enum SynchronousMode { + AllowYield, + ForceSynchronous, + }; + void pumpTokenizer(SynchronousMode); + void pumpTokenizerIfPossible(SynchronousMode); + + bool runScriptsForPausedTreeBuilder(); + void resumeParsingAfterScriptExecution(); + + void begin(); + void attemptToEnd(); + void endIfDelayed(); + void end(); + + bool isScheduledForResume() const; + bool inScriptExecution() const; + bool inWrite() const { return m_writeNestingLevel > 0; } + bool shouldDelayEnd() const { return inWrite() || isWaitingForScripts() || inScriptExecution() || isScheduledForResume(); } + + ScriptController* script() const; + + HTMLInputStream m_input; + + // We hold m_token here because it might be partially complete. + HTMLToken m_token; + + OwnPtr m_tokenizer; + OwnPtr m_scriptRunner; + OwnPtr m_treeBuilder; + OwnPtr m_preloadScanner; + OwnPtr m_parserScheduler; + + bool m_endWasDelayed; + int m_writeNestingLevel; +}; + +} + +#endif diff --git a/WebCore/html/parser/HTMLElementStack.cpp b/WebCore/html/parser/HTMLElementStack.cpp new file mode 100644 index 0000000..b6f4111 --- /dev/null +++ b/WebCore/html/parser/HTMLElementStack.cpp @@ -0,0 +1,535 @@ +/* + * Copyright (C) 2010 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" +#include "HTMLElementStack.h" + +#include "Element.h" +#include "HTMLNames.h" +#include + +#if ENABLE(SVG) +#include "SVGNames.h" +#endif + +namespace WebCore { + +using namespace HTMLNames; + +namespace { + +inline bool isNumberedHeaderElement(Element* element) +{ + return element->hasTagName(h1Tag) + || element->hasTagName(h2Tag) + || element->hasTagName(h3Tag) + || element->hasTagName(h4Tag) + || element->hasTagName(h5Tag) + || element->hasTagName(h6Tag); +} + +inline bool isScopeMarker(Element* element) +{ + return element->hasTagName(appletTag) + || element->hasTagName(captionTag) +#if ENABLE(SVG_FOREIGN_OBJECT) + || element->hasTagName(SVGNames::foreignObjectTag) +#endif + || element->hasTagName(htmlTag) + || element->hasTagName(marqueeTag) + || element->hasTagName(objectTag) + || element->hasTagName(tableTag) + || element->hasTagName(tdTag) + || element->hasTagName(thTag); +} + +inline bool isListItemScopeMarker(Element* element) +{ + return isScopeMarker(element) + || element->hasTagName(olTag) + || element->hasTagName(ulTag); +} + +inline bool isTableScopeMarker(Element* element) +{ + return element->hasTagName(tableTag) + || element->hasTagName(htmlTag); +} + +inline bool isTableBodyScopeMarker(Element* element) +{ + return element->hasTagName(tbodyTag) + || element->hasTagName(tfootTag) + || element->hasTagName(theadTag) + || element->hasTagName(htmlTag); +} + +inline bool isTableRowScopeMarker(Element* element) +{ + return element->hasTagName(trTag) + || element->hasTagName(htmlTag); +} + +inline bool isButtonScopeMarker(Element* element) +{ + return isScopeMarker(element) + || element->hasTagName(buttonTag); +} + +} + +HTMLElementStack::ElementRecord::ElementRecord(PassRefPtr element, PassOwnPtr next) + : m_element(element) + , m_next(next) +{ + ASSERT(m_element); +} + +HTMLElementStack::ElementRecord::~ElementRecord() +{ +} + +void HTMLElementStack::ElementRecord::replaceElement(PassRefPtr element) +{ + ASSERT(element); + // FIXME: Should this call finishParsingChildren? + m_element = element; +} + +bool HTMLElementStack::ElementRecord::isAbove(ElementRecord* other) const +{ + for (ElementRecord* below = next(); below; below = below->next()) { + if (below == other) + return true; + } + return false; +} + +HTMLElementStack::HTMLElementStack() + : m_htmlElement(0) + , m_headElement(0) + , m_bodyElement(0) +{ +} + +HTMLElementStack::~HTMLElementStack() +{ +} + +bool HTMLElementStack::hasOnlyOneElement() const +{ + return !topRecord()->next(); +} + +bool HTMLElementStack::secondElementIsHTMLBodyElement() const +{ + // This is used the fragment case of and in the "in body" + // insertion mode. + // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#parsing-main-inbody + ASSERT(m_htmlElement); + // If we have a body element, it must always be the second element on the + // stack, as we always start with an html element, and any other element + // would cause the implicit creation of a body element. + return !!m_bodyElement; +} + +void HTMLElementStack::popHTMLHeadElement() +{ + ASSERT(top() == m_headElement); + m_headElement = 0; + popCommon(); +} + +void HTMLElementStack::popHTMLBodyElement() +{ + ASSERT(top() == m_bodyElement); + m_bodyElement = 0; + popCommon(); +} + +void HTMLElementStack::popAll() +{ + m_htmlElement = 0; + m_headElement = 0; + m_bodyElement = 0; + while (m_top) { + top()->finishParsingChildren(); + m_top = m_top->releaseNext(); + } +} + +void HTMLElementStack::pop() +{ + ASSERT(!top()->hasTagName(HTMLNames::headTag)); + popCommon(); +} + +void HTMLElementStack::popUntilElementWithNamespace(const AtomicString& namespaceURI) +{ + while (top()->namespaceURI() != namespaceURI) + pop(); +} + +void HTMLElementStack::popUntil(const AtomicString& tagName) +{ + while (!top()->hasLocalName(tagName)) { + // pop() will ASSERT at if callers fail to check that there is an + // element with localName |tagName| on the stack of open elements. + pop(); + } +} + +void HTMLElementStack::popUntilPopped(const AtomicString& tagName) +{ + popUntil(tagName); + pop(); +} + +void HTMLElementStack::popUntilNumberedHeaderElementPopped() +{ + while (!isNumberedHeaderElement(top())) + pop(); + pop(); +} + +void HTMLElementStack::popUntil(Element* element) +{ + while (top() != element) + pop(); +} + +void HTMLElementStack::popUntilPopped(Element* element) +{ + popUntil(element); + pop(); +} + +void HTMLElementStack::popUntilTableScopeMarker() +{ + // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#clear-the-stack-back-to-a-table-context + while (!isTableScopeMarker(top())) + pop(); +} + +void HTMLElementStack::popUntilTableBodyScopeMarker() +{ + // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#clear-the-stack-back-to-a-table-body-context + while (!isTableBodyScopeMarker(top())) + pop(); +} + +void HTMLElementStack::popUntilTableRowScopeMarker() +{ + // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#clear-the-stack-back-to-a-table-row-context + while (!isTableRowScopeMarker(top())) + pop(); +} + +void HTMLElementStack::pushHTMLHtmlElement(PassRefPtr element) +{ + ASSERT(!m_top); // should always be the bottom of the stack. + ASSERT(element->hasTagName(HTMLNames::htmlTag)); + ASSERT(!m_htmlElement); + m_htmlElement = element.get(); + pushCommon(element); +} + +void HTMLElementStack::pushHTMLHeadElement(PassRefPtr element) +{ + ASSERT(element->hasTagName(HTMLNames::headTag)); + ASSERT(!m_headElement); + m_headElement = element.get(); + pushCommon(element); +} + +void HTMLElementStack::pushHTMLBodyElement(PassRefPtr element) +{ + ASSERT(element->hasTagName(HTMLNames::bodyTag)); + ASSERT(!m_bodyElement); + m_bodyElement = element.get(); + pushCommon(element); +} + +void HTMLElementStack::push(PassRefPtr element) +{ + ASSERT(!element->hasTagName(HTMLNames::htmlTag)); + ASSERT(!element->hasTagName(HTMLNames::headTag)); + ASSERT(!element->hasTagName(HTMLNames::bodyTag)); + ASSERT(m_htmlElement); + pushCommon(element); +} + +void HTMLElementStack::insertAbove(PassRefPtr element, ElementRecord* recordBelow) +{ + ASSERT(element); + ASSERT(recordBelow); + ASSERT(m_top); + ASSERT(!element->hasTagName(HTMLNames::htmlTag)); + ASSERT(!element->hasTagName(HTMLNames::headTag)); + ASSERT(!element->hasTagName(HTMLNames::bodyTag)); + ASSERT(m_htmlElement); + if (recordBelow == m_top) { + push(element); + return; + } + + for (ElementRecord* recordAbove = m_top.get(); recordAbove; recordAbove = recordAbove->next()) { + if (recordAbove->next() != recordBelow) + continue; + + recordAbove->setNext(adoptPtr(new ElementRecord(element, recordAbove->releaseNext()))); + recordAbove->next()->element()->beginParsingChildren(); + return; + } + ASSERT_NOT_REACHED(); +} + +HTMLElementStack::ElementRecord* HTMLElementStack::topRecord() const +{ + ASSERT(m_top); + return m_top.get(); +} + +Element* HTMLElementStack::oneBelowTop() const +{ + // We should never be calling this if it could be 0. + ASSERT(m_top); + ASSERT(m_top->next()); + return m_top->next()->element(); +} + +Element* HTMLElementStack::bottom() const +{ + return htmlElement(); +} + +void HTMLElementStack::removeHTMLHeadElement(Element* element) +{ + ASSERT(m_headElement == element); + if (m_top->element() == element) { + popHTMLHeadElement(); + return; + } + m_headElement = 0; + removeNonTopCommon(element); +} + +void HTMLElementStack::remove(Element* element) +{ + ASSERT(!element->hasTagName(HTMLNames::headTag)); + if (m_top->element() == element) { + pop(); + return; + } + removeNonTopCommon(element); +} + +HTMLElementStack::ElementRecord* HTMLElementStack::find(Element* element) const +{ + for (ElementRecord* pos = m_top.get(); pos; pos = pos->next()) { + if (pos->element() == element) + return pos; + } + return 0; +} + +HTMLElementStack::ElementRecord* HTMLElementStack::topmost(const AtomicString& tagName) const +{ + for (ElementRecord* pos = m_top.get(); pos; pos = pos->next()) { + if (pos->element()->hasLocalName(tagName)) + return pos; + } + return 0; +} + +bool HTMLElementStack::contains(Element* element) const +{ + return !!find(element); +} + +bool HTMLElementStack::contains(const AtomicString& tagName) const +{ + return !!topmost(tagName); +} + +template +bool inScopeCommon(HTMLElementStack::ElementRecord* top, const AtomicString& targetTag) +{ + for (HTMLElementStack::ElementRecord* pos = top; pos; pos = pos->next()) { + Element* element = pos->element(); + if (element->hasLocalName(targetTag)) + return true; + if (isMarker(element)) + return false; + } + ASSERT_NOT_REACHED(); // is always on the stack and is a scope marker. + return false; +} + +bool HTMLElementStack::hasOnlyHTMLElementsInScope() const +{ + for (ElementRecord* record = m_top.get(); record; record = record->next()) { + Element* element = record->element(); + if (element->namespaceURI() != xhtmlNamespaceURI) + return false; + if (isScopeMarker(element)) + return true; + } + ASSERT_NOT_REACHED(); // is always on the stack and is a scope marker. + return true; +} + +bool HTMLElementStack::hasNumberedHeaderElementInScope() const +{ + for (ElementRecord* record = m_top.get(); record; record = record->next()) { + Element* element = record->element(); + if (isNumberedHeaderElement(element)) + return true; + if (isScopeMarker(element)) + return false; + } + ASSERT_NOT_REACHED(); // is always on the stack and is a scope marker. + return false; +} + +bool HTMLElementStack::inScope(Element* targetElement) const +{ + for (ElementRecord* pos = m_top.get(); pos; pos = pos->next()) { + Element* element = pos->element(); + if (element == targetElement) + return true; + if (isScopeMarker(element)) + return false; + } + ASSERT_NOT_REACHED(); // is always on the stack and is a scope marker. + return false; +} + +bool HTMLElementStack::inScope(const AtomicString& targetTag) const +{ + return inScopeCommon(m_top.get(), targetTag); +} + +bool HTMLElementStack::inScope(const QualifiedName& tagName) const +{ + // FIXME: Is localName() right for non-html elements? + return inScope(tagName.localName()); +} + +bool HTMLElementStack::inListItemScope(const AtomicString& targetTag) const +{ + return inScopeCommon(m_top.get(), targetTag); +} + +bool HTMLElementStack::inListItemScope(const QualifiedName& tagName) const +{ + // FIXME: Is localName() right for non-html elements? + return inListItemScope(tagName.localName()); +} + +bool HTMLElementStack::inTableScope(const AtomicString& targetTag) const +{ + return inScopeCommon(m_top.get(), targetTag); +} + +bool HTMLElementStack::inTableScope(const QualifiedName& tagName) const +{ + // FIXME: Is localName() right for non-html elements? + return inTableScope(tagName.localName()); +} + +bool HTMLElementStack::inButtonScope(const AtomicString& targetTag) const +{ + return inScopeCommon(m_top.get(), targetTag); +} + +bool HTMLElementStack::inButtonScope(const QualifiedName& tagName) const +{ + // FIXME: Is localName() right for non-html elements? + return inButtonScope(tagName.localName()); +} + +Element* HTMLElementStack::htmlElement() const +{ + ASSERT(m_htmlElement); + return m_htmlElement; +} + +Element* HTMLElementStack::headElement() const +{ + ASSERT(m_headElement); + return m_headElement; +} + +Element* HTMLElementStack::bodyElement() const +{ + ASSERT(m_bodyElement); + return m_bodyElement; +} + +void HTMLElementStack::pushCommon(PassRefPtr element) +{ + ASSERT(m_htmlElement); + m_top = adoptPtr(new ElementRecord(element, m_top.release())); + top()->beginParsingChildren(); +} + +void HTMLElementStack::popCommon() +{ + ASSERT(!top()->hasTagName(HTMLNames::htmlTag)); + ASSERT(!top()->hasTagName(HTMLNames::headTag) || !m_headElement); + ASSERT(!top()->hasTagName(HTMLNames::bodyTag) || !m_bodyElement); + top()->finishParsingChildren(); + m_top = m_top->releaseNext(); +} + +void HTMLElementStack::removeNonTopCommon(Element* element) +{ + ASSERT(!element->hasTagName(HTMLNames::htmlTag)); + ASSERT(!element->hasTagName(HTMLNames::bodyTag)); + ASSERT(top() != element); + for (ElementRecord* pos = m_top.get(); pos; pos = pos->next()) { + if (pos->next()->element() == element) { + // FIXME: Is it OK to call finishParsingChildren() + // when the children aren't actually finished? + element->finishParsingChildren(); + pos->setNext(pos->next()->releaseNext()); + return; + } + } + ASSERT_NOT_REACHED(); +} + +#ifndef NDEBUG + +void HTMLElementStack::show() +{ + for (ElementRecord* record = m_top.get(); record; record = record->next()) + record->element()->showNode(); +} + +#endif + +} diff --git a/WebCore/html/parser/HTMLElementStack.h b/WebCore/html/parser/HTMLElementStack.h new file mode 100644 index 0000000..73cfcb1 --- /dev/null +++ b/WebCore/html/parser/HTMLElementStack.h @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2010 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. + */ + +#ifndef HTMLElementStack_h +#define HTMLElementStack_h + +#include +#include +#include +#include +#include + +namespace WebCore { + +class Element; +class QualifiedName; + +// NOTE: The HTML5 spec uses a backwards (grows downward) stack. We're using +// more standard (grows upwards) stack terminology here. +class HTMLElementStack : public Noncopyable { +public: + HTMLElementStack(); + ~HTMLElementStack(); + + class ElementRecord : public Noncopyable { + public: + ~ElementRecord(); // Public for ~PassOwnPtr() + + Element* element() const { return m_element.get(); } + void replaceElement(PassRefPtr); + + bool isAbove(ElementRecord*) const; + + ElementRecord* next() const { return m_next.get(); } + + private: + friend class HTMLElementStack; + + ElementRecord(PassRefPtr, PassOwnPtr); + + PassOwnPtr releaseNext() { return m_next.release(); } + void setNext(PassOwnPtr next) { m_next = next; } + + RefPtr m_element; + OwnPtr m_next; + }; + + // Inlining this function is a (small) performance win on the parsing + // benchmark. + Element* top() const + { + ASSERT(m_top->element()); + return m_top->element(); + } + + Element* oneBelowTop() const; + ElementRecord* topRecord() const; + Element* bottom() const; + ElementRecord* find(Element*) const; + ElementRecord* topmost(const AtomicString& tagName) const; + + void insertAbove(PassRefPtr, ElementRecord*); + + void push(PassRefPtr); + void pushHTMLHtmlElement(PassRefPtr); + void pushHTMLHeadElement(PassRefPtr); + void pushHTMLBodyElement(PassRefPtr); + + void pop(); + void popUntil(const AtomicString& tagName); + void popUntilElementWithNamespace(const AtomicString& namespaceURI); + void popUntil(Element*); + void popUntilPopped(const AtomicString& tagName); + void popUntilPopped(Element*); + void popUntilNumberedHeaderElementPopped(); + void popUntilTableScopeMarker(); // "clear the stack back to a table context" in the spec. + void popUntilTableBodyScopeMarker(); // "clear the stack back to a table body context" in the spec. + void popUntilTableRowScopeMarker(); // "clear the stack back to a table row context" in the spec. + void popHTMLHeadElement(); + void popHTMLBodyElement(); + void popAll(); + + void remove(Element*); + void removeHTMLHeadElement(Element*); + + bool contains(Element*) const; + bool contains(const AtomicString& tagName) const; + + bool inScope(Element*) const; + bool inScope(const AtomicString& tagName) const; + bool inScope(const QualifiedName&) const; + bool inListItemScope(const AtomicString& tagName) const; + bool inListItemScope(const QualifiedName&) const; + bool inTableScope(const AtomicString& tagName) const; + bool inTableScope(const QualifiedName&) const; + bool inButtonScope(const AtomicString& tagName) const; + bool inButtonScope(const QualifiedName&) const; + + bool hasOnlyHTMLElementsInScope() const; + bool hasNumberedHeaderElementInScope() const; + + bool hasOnlyOneElement() const; + bool secondElementIsHTMLBodyElement() const; + + Element* htmlElement() const; + Element* headElement() const; + Element* bodyElement() const; + +#ifndef NDEBUG + void show(); +#endif + +private: + void pushCommon(PassRefPtr); + void popCommon(); + void removeNonTopCommon(Element*); + + OwnPtr m_top; + + // We remember , and as they are pushed. Their + // ElementRecords keep them alive. is never popped. + // FIXME: We don't currently require type-specific information about + // these elements so we haven't yet bothered to plumb the types all the + // way down through createElement, etc. + Element* m_htmlElement; + Element* m_headElement; + Element* m_bodyElement; +}; + +} // namespace WebCore + +#endif // HTMLElementStack_h diff --git a/WebCore/html/parser/HTMLEntityNames.in b/WebCore/html/parser/HTMLEntityNames.in new file mode 100644 index 0000000..2d42ab2 --- /dev/null +++ b/WebCore/html/parser/HTMLEntityNames.in @@ -0,0 +1,2138 @@ +"AElig;","U+000C6" +"AElig","U+000C6" +"AMP;","U+00026" +"AMP","U+00026" +"Aacute;","U+000C1" +"Aacute","U+000C1" +"Abreve;","U+00102" +"Acirc;","U+000C2" +"Acirc","U+000C2" +"Acy;","U+00410" +"Afr;","U+1D504" +"Agrave;","U+000C0" +"Agrave","U+000C0" +"Alpha;","U+00391" +"Amacr;","U+00100" +"And;","U+02A53" +"Aogon;","U+00104" +"Aopf;","U+1D538" +"ApplyFunction;","U+02061" +"Aring;","U+000C5" +"Aring","U+000C5" +"Ascr;","U+1D49C" +"Assign;","U+02254" +"Atilde;","U+000C3" +"Atilde","U+000C3" +"Auml;","U+000C4" +"Auml","U+000C4" +"Backslash;","U+02216" +"Barv;","U+02AE7" +"Barwed;","U+02306" +"Bcy;","U+00411" +"Because;","U+02235" +"Bernoullis;","U+0212C" +"Beta;","U+00392" +"Bfr;","U+1D505" +"Bopf;","U+1D539" +"Breve;","U+002D8" +"Bscr;","U+0212C" +"Bumpeq;","U+0224E" +"CHcy;","U+00427" +"COPY;","U+000A9" +"COPY","U+000A9" +"Cacute;","U+00106" +"Cap;","U+022D2" +"CapitalDifferentialD;","U+02145" +"Cayleys;","U+0212D" +"Ccaron;","U+0010C" +"Ccedil;","U+000C7" +"Ccedil","U+000C7" +"Ccirc;","U+00108" +"Cconint;","U+02230" +"Cdot;","U+0010A" +"Cedilla;","U+000B8" +"CenterDot;","U+000B7" +"Cfr;","U+0212D" +"Chi;","U+003A7" +"CircleDot;","U+02299" +"CircleMinus;","U+02296" +"CirclePlus;","U+02295" +"CircleTimes;","U+02297" +"ClockwiseContourIntegral;","U+02232" +"CloseCurlyDoubleQuote;","U+0201D" +"CloseCurlyQuote;","U+02019" +"Colon;","U+02237" +"Colone;","U+02A74" +"Congruent;","U+02261" +"Conint;","U+0222F" +"ContourIntegral;","U+0222E" +"Copf;","U+02102" +"Coproduct;","U+02210" +"CounterClockwiseContourIntegral;","U+02233" +"Cross;","U+02A2F" +"Cscr;","U+1D49E" +"Cup;","U+022D3" +"CupCap;","U+0224D" +"DD;","U+02145" +"DDotrahd;","U+02911" +"DJcy;","U+00402" +"DScy;","U+00405" +"DZcy;","U+0040F" +"Dagger;","U+02021" +"Darr;","U+021A1" +"Dashv;","U+02AE4" +"Dcaron;","U+0010E" +"Dcy;","U+00414" +"Del;","U+02207" +"Delta;","U+00394" +"Dfr;","U+1D507" +"DiacriticalAcute;","U+000B4" +"DiacriticalDot;","U+002D9" +"DiacriticalDoubleAcute;","U+002DD" +"DiacriticalGrave;","U+00060" +"DiacriticalTilde;","U+002DC" +"Diamond;","U+022C4" +"DifferentialD;","U+02146" +"Dopf;","U+1D53B" +"Dot;","U+000A8" +"DotDot;","U+020DC" +"DotEqual;","U+02250" +"DoubleContourIntegral;","U+0222F" +"DoubleDot;","U+000A8" +"DoubleDownArrow;","U+021D3" +"DoubleLeftArrow;","U+021D0" +"DoubleLeftRightArrow;","U+021D4" +"DoubleLeftTee;","U+02AE4" +"DoubleLongLeftArrow;","U+027F8" +"DoubleLongLeftRightArrow;","U+027FA" +"DoubleLongRightArrow;","U+027F9" +"DoubleRightArrow;","U+021D2" +"DoubleRightTee;","U+022A8" +"DoubleUpArrow;","U+021D1" +"DoubleUpDownArrow;","U+021D5" +"DoubleVerticalBar;","U+02225" +"DownArrow;","U+02193" +"DownArrowBar;","U+02913" +"DownArrowUpArrow;","U+021F5" +"DownBreve;","U+00311" +"DownLeftRightVector;","U+02950" +"DownLeftTeeVector;","U+0295E" +"DownLeftVector;","U+021BD" +"DownLeftVectorBar;","U+02956" +"DownRightTeeVector;","U+0295F" +"DownRightVector;","U+021C1" +"DownRightVectorBar;","U+02957" +"DownTee;","U+022A4" +"DownTeeArrow;","U+021A7" +"Downarrow;","U+021D3" +"Dscr;","U+1D49F" +"Dstrok;","U+00110" +"ENG;","U+0014A" +"ETH;","U+000D0" +"ETH","U+000D0" +"Eacute;","U+000C9" +"Eacute","U+000C9" +"Ecaron;","U+0011A" +"Ecirc;","U+000CA" +"Ecirc","U+000CA" +"Ecy;","U+0042D" +"Edot;","U+00116" +"Efr;","U+1D508" +"Egrave;","U+000C8" +"Egrave","U+000C8" +"Element;","U+02208" +"Emacr;","U+00112" +"EmptySmallSquare;","U+025FB" +"EmptyVerySmallSquare;","U+025AB" +"Eogon;","U+00118" +"Eopf;","U+1D53C" +"Epsilon;","U+00395" +"Equal;","U+02A75" +"EqualTilde;","U+02242" +"Equilibrium;","U+021CC" +"Escr;","U+02130" +"Esim;","U+02A73" +"Eta;","U+00397" +"Euml;","U+000CB" +"Euml","U+000CB" +"Exists;","U+02203" +"ExponentialE;","U+02147" +"Fcy;","U+00424" +"Ffr;","U+1D509" +"FilledSmallSquare;","U+025FC" +"FilledVerySmallSquare;","U+025AA" +"Fopf;","U+1D53D" +"ForAll;","U+02200" +"Fouriertrf;","U+02131" +"Fscr;","U+02131" +"GJcy;","U+00403" +"GT;","U+0003E" +"GT","U+0003E" +"Gamma;","U+00393" +"Gammad;","U+003DC" +"Gbreve;","U+0011E" +"Gcedil;","U+00122" +"Gcirc;","U+0011C" +"Gcy;","U+00413" +"Gdot;","U+00120" +"Gfr;","U+1D50A" +"Gg;","U+022D9" +"Gopf;","U+1D53E" +"GreaterEqual;","U+02265" +"GreaterEqualLess;","U+022DB" +"GreaterFullEqual;","U+02267" +"GreaterGreater;","U+02AA2" +"GreaterLess;","U+02277" +"GreaterSlantEqual;","U+02A7E" +"GreaterTilde;","U+02273" +"Gscr;","U+1D4A2" +"Gt;","U+0226B" +"HARDcy;","U+0042A" +"Hacek;","U+002C7" +"Hat;","U+0005E" +"Hcirc;","U+00124" +"Hfr;","U+0210C" +"HilbertSpace;","U+0210B" +"Hopf;","U+0210D" +"HorizontalLine;","U+02500" +"Hscr;","U+0210B" +"Hstrok;","U+00126" +"HumpDownHump;","U+0224E" +"HumpEqual;","U+0224F" +"IEcy;","U+00415" +"IJlig;","U+00132" +"IOcy;","U+00401" +"Iacute;","U+000CD" +"Iacute","U+000CD" +"Icirc;","U+000CE" +"Icirc","U+000CE" +"Icy;","U+00418" +"Idot;","U+00130" +"Ifr;","U+02111" +"Igrave;","U+000CC" +"Igrave","U+000CC" +"Im;","U+02111" +"Imacr;","U+0012A" +"ImaginaryI;","U+02148" +"Implies;","U+021D2" +"Int;","U+0222C" +"Integral;","U+0222B" +"Intersection;","U+022C2" +"InvisibleComma;","U+02063" +"InvisibleTimes;","U+02062" +"Iogon;","U+0012E" +"Iopf;","U+1D540" +"Iota;","U+00399" +"Iscr;","U+02110" +"Itilde;","U+00128" +"Iukcy;","U+00406" +"Iuml;","U+000CF" +"Iuml","U+000CF" +"Jcirc;","U+00134" +"Jcy;","U+00419" +"Jfr;","U+1D50D" +"Jopf;","U+1D541" +"Jscr;","U+1D4A5" +"Jsercy;","U+00408" +"Jukcy;","U+00404" +"KHcy;","U+00425" +"KJcy;","U+0040C" +"Kappa;","U+0039A" +"Kcedil;","U+00136" +"Kcy;","U+0041A" +"Kfr;","U+1D50E" +"Kopf;","U+1D542" +"Kscr;","U+1D4A6" +"LJcy;","U+00409" +"LT;","U+0003C" +"LT","U+0003C" +"Lacute;","U+00139" +"Lambda;","U+0039B" +"Lang;","U+027EA" +"Laplacetrf;","U+02112" +"Larr;","U+0219E" +"Lcaron;","U+0013D" +"Lcedil;","U+0013B" +"Lcy;","U+0041B" +"LeftAngleBracket;","U+027E8" +"LeftArrow;","U+02190" +"LeftArrowBar;","U+021E4" +"LeftArrowRightArrow;","U+021C6" +"LeftCeiling;","U+02308" +"LeftDoubleBracket;","U+027E6" +"LeftDownTeeVector;","U+02961" +"LeftDownVector;","U+021C3" +"LeftDownVectorBar;","U+02959" +"LeftFloor;","U+0230A" +"LeftRightArrow;","U+02194" +"LeftRightVector;","U+0294E" +"LeftTee;","U+022A3" +"LeftTeeArrow;","U+021A4" +"LeftTeeVector;","U+0295A" +"LeftTriangle;","U+022B2" +"LeftTriangleBar;","U+029CF" +"LeftTriangleEqual;","U+022B4" +"LeftUpDownVector;","U+02951" +"LeftUpTeeVector;","U+02960" +"LeftUpVector;","U+021BF" +"LeftUpVectorBar;","U+02958" +"LeftVector;","U+021BC" +"LeftVectorBar;","U+02952" +"Leftarrow;","U+021D0" +"Leftrightarrow;","U+021D4" +"LessEqualGreater;","U+022DA" +"LessFullEqual;","U+02266" +"LessGreater;","U+02276" +"LessLess;","U+02AA1" +"LessSlantEqual;","U+02A7D" +"LessTilde;","U+02272" +"Lfr;","U+1D50F" +"Ll;","U+022D8" +"Lleftarrow;","U+021DA" +"Lmidot;","U+0013F" +"LongLeftArrow;","U+027F5" +"LongLeftRightArrow;","U+027F7" +"LongRightArrow;","U+027F6" +"Longleftarrow;","U+027F8" +"Longleftrightarrow;","U+027FA" +"Longrightarrow;","U+027F9" +"Lopf;","U+1D543" +"LowerLeftArrow;","U+02199" +"LowerRightArrow;","U+02198" +"Lscr;","U+02112" +"Lsh;","U+021B0" +"Lstrok;","U+00141" +"Lt;","U+0226A" +"Map;","U+02905" +"Mcy;","U+0041C" +"MediumSpace;","U+0205F" +"Mellintrf;","U+02133" +"Mfr;","U+1D510" +"MinusPlus;","U+02213" +"Mopf;","U+1D544" +"Mscr;","U+02133" +"Mu;","U+0039C" +"NJcy;","U+0040A" +"Nacute;","U+00143" +"Ncaron;","U+00147" +"Ncedil;","U+00145" +"Ncy;","U+0041D" +"NegativeMediumSpace;","U+0200B" +"NegativeThickSpace;","U+0200B" +"NegativeThinSpace;","U+0200B" +"NegativeVeryThinSpace;","U+0200B" +"NestedGreaterGreater;","U+0226B" +"NestedLessLess;","U+0226A" +"NewLine;","U+0000A" +"Nfr;","U+1D511" +"NoBreak;","U+02060" +"NonBreakingSpace;","U+000A0" +"Nopf;","U+02115" +"Not;","U+02AEC" +"NotCongruent;","U+02262" +"NotCupCap;","U+0226D" +"NotDoubleVerticalBar;","U+02226" +"NotElement;","U+02209" +"NotEqual;","U+02260" +"NotExists;","U+02204" +"NotGreater;","U+0226F" +"NotGreaterEqual;","U+02271" +"NotGreaterLess;","U+02279" +"NotGreaterTilde;","U+02275" +"NotLeftTriangle;","U+022EA" +"NotLeftTriangleEqual;","U+022EC" +"NotLess;","U+0226E" +"NotLessEqual;","U+02270" +"NotLessGreater;","U+02278" +"NotLessTilde;","U+02274" +"NotPrecedes;","U+02280" +"NotPrecedesSlantEqual;","U+022E0" +"NotReverseElement;","U+0220C" +"NotRightTriangle;","U+022EB" +"NotRightTriangleEqual;","U+022ED" +"NotSquareSubsetEqual;","U+022E2" +"NotSquareSupersetEqual;","U+022E3" +"NotSubsetEqual;","U+02288" +"NotSucceeds;","U+02281" +"NotSucceedsSlantEqual;","U+022E1" +"NotSupersetEqual;","U+02289" +"NotTilde;","U+02241" +"NotTildeEqual;","U+02244" +"NotTildeFullEqual;","U+02247" +"NotTildeTilde;","U+02249" +"NotVerticalBar;","U+02224" +"Nscr;","U+1D4A9" +"Ntilde;","U+000D1" +"Ntilde","U+000D1" +"Nu;","U+0039D" +"OElig;","U+00152" +"Oacute;","U+000D3" +"Oacute","U+000D3" +"Ocirc;","U+000D4" +"Ocirc","U+000D4" +"Ocy;","U+0041E" +"Odblac;","U+00150" +"Ofr;","U+1D512" +"Ograve;","U+000D2" +"Ograve","U+000D2" +"Omacr;","U+0014C" +"Omega;","U+003A9" +"Omicron;","U+0039F" +"Oopf;","U+1D546" +"OpenCurlyDoubleQuote;","U+0201C" +"OpenCurlyQuote;","U+02018" +"Or;","U+02A54" +"Oscr;","U+1D4AA" +"Oslash;","U+000D8" +"Oslash","U+000D8" +"Otilde;","U+000D5" +"Otilde","U+000D5" +"Otimes;","U+02A37" +"Ouml;","U+000D6" +"Ouml","U+000D6" +"OverBar;","U+0203E" +"OverBrace;","U+023DE" +"OverBracket;","U+023B4" +"OverParenthesis;","U+023DC" +"PartialD;","U+02202" +"Pcy;","U+0041F" +"Pfr;","U+1D513" +"Phi;","U+003A6" +"Pi;","U+003A0" +"PlusMinus;","U+000B1" +"Poincareplane;","U+0210C" +"Popf;","U+02119" +"Pr;","U+02ABB" +"Precedes;","U+0227A" +"PrecedesEqual;","U+02AAF" +"PrecedesSlantEqual;","U+0227C" +"PrecedesTilde;","U+0227E" +"Prime;","U+02033" +"Product;","U+0220F" +"Proportion;","U+02237" +"Proportional;","U+0221D" +"Pscr;","U+1D4AB" +"Psi;","U+003A8" +"QUOT;","U+00022" +"QUOT","U+00022" +"Qfr;","U+1D514" +"Qopf;","U+0211A" +"Qscr;","U+1D4AC" +"RBarr;","U+02910" +"REG;","U+000AE" +"REG","U+000AE" +"Racute;","U+00154" +"Rang;","U+027EB" +"Rarr;","U+021A0" +"Rarrtl;","U+02916" +"Rcaron;","U+00158" +"Rcedil;","U+00156" +"Rcy;","U+00420" +"Re;","U+0211C" +"ReverseElement;","U+0220B" +"ReverseEquilibrium;","U+021CB" +"ReverseUpEquilibrium;","U+0296F" +"Rfr;","U+0211C" +"Rho;","U+003A1" +"RightAngleBracket;","U+027E9" +"RightArrow;","U+02192" +"RightArrowBar;","U+021E5" +"RightArrowLeftArrow;","U+021C4" +"RightCeiling;","U+02309" +"RightDoubleBracket;","U+027E7" +"RightDownTeeVector;","U+0295D" +"RightDownVector;","U+021C2" +"RightDownVectorBar;","U+02955" +"RightFloor;","U+0230B" +"RightTee;","U+022A2" +"RightTeeArrow;","U+021A6" +"RightTeeVector;","U+0295B" +"RightTriangle;","U+022B3" +"RightTriangleBar;","U+029D0" +"RightTriangleEqual;","U+022B5" +"RightUpDownVector;","U+0294F" +"RightUpTeeVector;","U+0295C" +"RightUpVector;","U+021BE" +"RightUpVectorBar;","U+02954" +"RightVector;","U+021C0" +"RightVectorBar;","U+02953" +"Rightarrow;","U+021D2" +"Ropf;","U+0211D" +"RoundImplies;","U+02970" +"Rrightarrow;","U+021DB" +"Rscr;","U+0211B" +"Rsh;","U+021B1" +"RuleDelayed;","U+029F4" +"SHCHcy;","U+00429" +"SHcy;","U+00428" +"SOFTcy;","U+0042C" +"Sacute;","U+0015A" +"Sc;","U+02ABC" +"Scaron;","U+00160" +"Scedil;","U+0015E" +"Scirc;","U+0015C" +"Scy;","U+00421" +"Sfr;","U+1D516" +"ShortDownArrow;","U+02193" +"ShortLeftArrow;","U+02190" +"ShortRightArrow;","U+02192" +"ShortUpArrow;","U+02191" +"Sigma;","U+003A3" +"SmallCircle;","U+02218" +"Sopf;","U+1D54A" +"Sqrt;","U+0221A" +"Square;","U+025A1" +"SquareIntersection;","U+02293" +"SquareSubset;","U+0228F" +"SquareSubsetEqual;","U+02291" +"SquareSuperset;","U+02290" +"SquareSupersetEqual;","U+02292" +"SquareUnion;","U+02294" +"Sscr;","U+1D4AE" +"Star;","U+022C6" +"Sub;","U+022D0" +"Subset;","U+022D0" +"SubsetEqual;","U+02286" +"Succeeds;","U+0227B" +"SucceedsEqual;","U+02AB0" +"SucceedsSlantEqual;","U+0227D" +"SucceedsTilde;","U+0227F" +"SuchThat;","U+0220B" +"Sum;","U+02211" +"Sup;","U+022D1" +"Superset;","U+02283" +"SupersetEqual;","U+02287" +"Supset;","U+022D1" +"THORN;","U+000DE" +"THORN","U+000DE" +"TRADE;","U+02122" +"TSHcy;","U+0040B" +"TScy;","U+00426" +"Tab;","U+00009" +"Tau;","U+003A4" +"Tcaron;","U+00164" +"Tcedil;","U+00162" +"Tcy;","U+00422" +"Tfr;","U+1D517" +"Therefore;","U+02234" +"Theta;","U+00398" +"ThinSpace;","U+02009" +"Tilde;","U+0223C" +"TildeEqual;","U+02243" +"TildeFullEqual;","U+02245" +"TildeTilde;","U+02248" +"Topf;","U+1D54B" +"TripleDot;","U+020DB" +"Tscr;","U+1D4AF" +"Tstrok;","U+00166" +"Uacute;","U+000DA" +"Uacute","U+000DA" +"Uarr;","U+0219F" +"Uarrocir;","U+02949" +"Ubrcy;","U+0040E" +"Ubreve;","U+0016C" +"Ucirc;","U+000DB" +"Ucirc","U+000DB" +"Ucy;","U+00423" +"Udblac;","U+00170" +"Ufr;","U+1D518" +"Ugrave;","U+000D9" +"Ugrave","U+000D9" +"Umacr;","U+0016A" +"UnderBar;","U+0005F" +"UnderBrace;","U+023DF" +"UnderBracket;","U+023B5" +"UnderParenthesis;","U+023DD" +"Union;","U+022C3" +"UnionPlus;","U+0228E" +"Uogon;","U+00172" +"Uopf;","U+1D54C" +"UpArrow;","U+02191" +"UpArrowBar;","U+02912" +"UpArrowDownArrow;","U+021C5" +"UpDownArrow;","U+02195" +"UpEquilibrium;","U+0296E" +"UpTee;","U+022A5" +"UpTeeArrow;","U+021A5" +"Uparrow;","U+021D1" +"Updownarrow;","U+021D5" +"UpperLeftArrow;","U+02196" +"UpperRightArrow;","U+02197" +"Upsi;","U+003D2" +"Upsilon;","U+003A5" +"Uring;","U+0016E" +"Uscr;","U+1D4B0" +"Utilde;","U+00168" +"Uuml;","U+000DC" +"Uuml","U+000DC" +"VDash;","U+022AB" +"Vbar;","U+02AEB" +"Vcy;","U+00412" +"Vdash;","U+022A9" +"Vdashl;","U+02AE6" +"Vee;","U+022C1" +"Verbar;","U+02016" +"Vert;","U+02016" +"VerticalBar;","U+02223" +"VerticalLine;","U+0007C" +"VerticalSeparator;","U+02758" +"VerticalTilde;","U+02240" +"VeryThinSpace;","U+0200A" +"Vfr;","U+1D519" +"Vopf;","U+1D54D" +"Vscr;","U+1D4B1" +"Vvdash;","U+022AA" +"Wcirc;","U+00174" +"Wedge;","U+022C0" +"Wfr;","U+1D51A" +"Wopf;","U+1D54E" +"Wscr;","U+1D4B2" +"Xfr;","U+1D51B" +"Xi;","U+0039E" +"Xopf;","U+1D54F" +"Xscr;","U+1D4B3" +"YAcy;","U+0042F" +"YIcy;","U+00407" +"YUcy;","U+0042E" +"Yacute;","U+000DD" +"Yacute","U+000DD" +"Ycirc;","U+00176" +"Ycy;","U+0042B" +"Yfr;","U+1D51C" +"Yopf;","U+1D550" +"Yscr;","U+1D4B4" +"Yuml;","U+00178" +"ZHcy;","U+00416" +"Zacute;","U+00179" +"Zcaron;","U+0017D" +"Zcy;","U+00417" +"Zdot;","U+0017B" +"ZeroWidthSpace;","U+0200B" +"Zeta;","U+00396" +"Zfr;","U+02128" +"Zopf;","U+02124" +"Zscr;","U+1D4B5" +"aacute;","U+000E1" +"aacute","U+000E1" +"abreve;","U+00103" +"ac;","U+0223E" +"acd;","U+0223F" +"acirc;","U+000E2" +"acirc","U+000E2" +"acute;","U+000B4" +"acute","U+000B4" +"acy;","U+00430" +"aelig;","U+000E6" +"aelig","U+000E6" +"af;","U+02061" +"afr;","U+1D51E" +"agrave;","U+000E0" +"agrave","U+000E0" +"alefsym;","U+02135" +"aleph;","U+02135" +"alpha;","U+003B1" +"amacr;","U+00101" +"amalg;","U+02A3F" +"amp;","U+00026" +"amp","U+00026" +"and;","U+02227" +"andand;","U+02A55" +"andd;","U+02A5C" +"andslope;","U+02A58" +"andv;","U+02A5A" +"ang;","U+02220" +"ange;","U+029A4" +"angle;","U+02220" +"angmsd;","U+02221" +"angmsdaa;","U+029A8" +"angmsdab;","U+029A9" +"angmsdac;","U+029AA" +"angmsdad;","U+029AB" +"angmsdae;","U+029AC" +"angmsdaf;","U+029AD" +"angmsdag;","U+029AE" +"angmsdah;","U+029AF" +"angrt;","U+0221F" +"angrtvb;","U+022BE" +"angrtvbd;","U+0299D" +"angsph;","U+02222" +"angst;","U+000C5" +"angzarr;","U+0237C" +"aogon;","U+00105" +"aopf;","U+1D552" +"ap;","U+02248" +"apE;","U+02A70" +"apacir;","U+02A6F" +"ape;","U+0224A" +"apid;","U+0224B" +"apos;","U+00027" +"approx;","U+02248" +"approxeq;","U+0224A" +"aring;","U+000E5" +"aring","U+000E5" +"ascr;","U+1D4B6" +"ast;","U+0002A" +"asymp;","U+02248" +"asympeq;","U+0224D" +"atilde;","U+000E3" +"atilde","U+000E3" +"auml;","U+000E4" +"auml","U+000E4" +"awconint;","U+02233" +"awint;","U+02A11" +"bNot;","U+02AED" +"backcong;","U+0224C" +"backepsilon;","U+003F6" +"backprime;","U+02035" +"backsim;","U+0223D" +"backsimeq;","U+022CD" +"barvee;","U+022BD" +"barwed;","U+02305" +"barwedge;","U+02305" +"bbrk;","U+023B5" +"bbrktbrk;","U+023B6" +"bcong;","U+0224C" +"bcy;","U+00431" +"bdquo;","U+0201E" +"becaus;","U+02235" +"because;","U+02235" +"bemptyv;","U+029B0" +"bepsi;","U+003F6" +"bernou;","U+0212C" +"beta;","U+003B2" +"beth;","U+02136" +"between;","U+0226C" +"bfr;","U+1D51F" +"bigcap;","U+022C2" +"bigcirc;","U+025EF" +"bigcup;","U+022C3" +"bigodot;","U+02A00" +"bigoplus;","U+02A01" +"bigotimes;","U+02A02" +"bigsqcup;","U+02A06" +"bigstar;","U+02605" +"bigtriangledown;","U+025BD" +"bigtriangleup;","U+025B3" +"biguplus;","U+02A04" +"bigvee;","U+022C1" +"bigwedge;","U+022C0" +"bkarow;","U+0290D" +"blacklozenge;","U+029EB" +"blacksquare;","U+025AA" +"blacktriangle;","U+025B4" +"blacktriangledown;","U+025BE" +"blacktriangleleft;","U+025C2" +"blacktriangleright;","U+025B8" +"blank;","U+02423" +"blk12;","U+02592" +"blk14;","U+02591" +"blk34;","U+02593" +"block;","U+02588" +"bnot;","U+02310" +"bopf;","U+1D553" +"bot;","U+022A5" +"bottom;","U+022A5" +"bowtie;","U+022C8" +"boxDL;","U+02557" +"boxDR;","U+02554" +"boxDl;","U+02556" +"boxDr;","U+02553" +"boxH;","U+02550" +"boxHD;","U+02566" +"boxHU;","U+02569" +"boxHd;","U+02564" +"boxHu;","U+02567" +"boxUL;","U+0255D" +"boxUR;","U+0255A" +"boxUl;","U+0255C" +"boxUr;","U+02559" +"boxV;","U+02551" +"boxVH;","U+0256C" +"boxVL;","U+02563" +"boxVR;","U+02560" +"boxVh;","U+0256B" +"boxVl;","U+02562" +"boxVr;","U+0255F" +"boxbox;","U+029C9" +"boxdL;","U+02555" +"boxdR;","U+02552" +"boxdl;","U+02510" +"boxdr;","U+0250C" +"boxh;","U+02500" +"boxhD;","U+02565" +"boxhU;","U+02568" +"boxhd;","U+0252C" +"boxhu;","U+02534" +"boxminus;","U+0229F" +"boxplus;","U+0229E" +"boxtimes;","U+022A0" +"boxuL;","U+0255B" +"boxuR;","U+02558" +"boxul;","U+02518" +"boxur;","U+02514" +"boxv;","U+02502" +"boxvH;","U+0256A" +"boxvL;","U+02561" +"boxvR;","U+0255E" +"boxvh;","U+0253C" +"boxvl;","U+02524" +"boxvr;","U+0251C" +"bprime;","U+02035" +"breve;","U+002D8" +"brvbar;","U+000A6" +"brvbar","U+000A6" +"bscr;","U+1D4B7" +"bsemi;","U+0204F" +"bsim;","U+0223D" +"bsime;","U+022CD" +"bsol;","U+0005C" +"bsolb;","U+029C5" +"bsolhsub;","U+027C8" +"bull;","U+02022" +"bullet;","U+02022" +"bump;","U+0224E" +"bumpE;","U+02AAE" +"bumpe;","U+0224F" +"bumpeq;","U+0224F" +"cacute;","U+00107" +"cap;","U+02229" +"capand;","U+02A44" +"capbrcup;","U+02A49" +"capcap;","U+02A4B" +"capcup;","U+02A47" +"capdot;","U+02A40" +"caret;","U+02041" +"caron;","U+002C7" +"ccaps;","U+02A4D" +"ccaron;","U+0010D" +"ccedil;","U+000E7" +"ccedil","U+000E7" +"ccirc;","U+00109" +"ccups;","U+02A4C" +"ccupssm;","U+02A50" +"cdot;","U+0010B" +"cedil;","U+000B8" +"cedil","U+000B8" +"cemptyv;","U+029B2" +"cent;","U+000A2" +"cent","U+000A2" +"centerdot;","U+000B7" +"cfr;","U+1D520" +"chcy;","U+00447" +"check;","U+02713" +"checkmark;","U+02713" +"chi;","U+003C7" +"cir;","U+025CB" +"cirE;","U+029C3" +"circ;","U+002C6" +"circeq;","U+02257" +"circlearrowleft;","U+021BA" +"circlearrowright;","U+021BB" +"circledR;","U+000AE" +"circledS;","U+024C8" +"circledast;","U+0229B" +"circledcirc;","U+0229A" +"circleddash;","U+0229D" +"cire;","U+02257" +"cirfnint;","U+02A10" +"cirmid;","U+02AEF" +"cirscir;","U+029C2" +"clubs;","U+02663" +"clubsuit;","U+02663" +"colon;","U+0003A" +"colone;","U+02254" +"coloneq;","U+02254" +"comma;","U+0002C" +"commat;","U+00040" +"comp;","U+02201" +"compfn;","U+02218" +"complement;","U+02201" +"complexes;","U+02102" +"cong;","U+02245" +"congdot;","U+02A6D" +"conint;","U+0222E" +"copf;","U+1D554" +"coprod;","U+02210" +"copy;","U+000A9" +"copy","U+000A9" +"copysr;","U+02117" +"crarr;","U+021B5" +"cross;","U+02717" +"cscr;","U+1D4B8" +"csub;","U+02ACF" +"csube;","U+02AD1" +"csup;","U+02AD0" +"csupe;","U+02AD2" +"ctdot;","U+022EF" +"cudarrl;","U+02938" +"cudarrr;","U+02935" +"cuepr;","U+022DE" +"cuesc;","U+022DF" +"cularr;","U+021B6" +"cularrp;","U+0293D" +"cup;","U+0222A" +"cupbrcap;","U+02A48" +"cupcap;","U+02A46" +"cupcup;","U+02A4A" +"cupdot;","U+0228D" +"cupor;","U+02A45" +"curarr;","U+021B7" +"curarrm;","U+0293C" +"curlyeqprec;","U+022DE" +"curlyeqsucc;","U+022DF" +"curlyvee;","U+022CE" +"curlywedge;","U+022CF" +"curren;","U+000A4" +"curren","U+000A4" +"curvearrowleft;","U+021B6" +"curvearrowright;","U+021B7" +"cuvee;","U+022CE" +"cuwed;","U+022CF" +"cwconint;","U+02232" +"cwint;","U+02231" +"cylcty;","U+0232D" +"dArr;","U+021D3" +"dHar;","U+02965" +"dagger;","U+02020" +"daleth;","U+02138" +"darr;","U+02193" +"dash;","U+02010" +"dashv;","U+022A3" +"dbkarow;","U+0290F" +"dblac;","U+002DD" +"dcaron;","U+0010F" +"dcy;","U+00434" +"dd;","U+02146" +"ddagger;","U+02021" +"ddarr;","U+021CA" +"ddotseq;","U+02A77" +"deg;","U+000B0" +"deg","U+000B0" +"delta;","U+003B4" +"demptyv;","U+029B1" +"dfisht;","U+0297F" +"dfr;","U+1D521" +"dharl;","U+021C3" +"dharr;","U+021C2" +"diam;","U+022C4" +"diamond;","U+022C4" +"diamondsuit;","U+02666" +"diams;","U+02666" +"die;","U+000A8" +"digamma;","U+003DD" +"disin;","U+022F2" +"div;","U+000F7" +"divide;","U+000F7" +"divide","U+000F7" +"divideontimes;","U+022C7" +"divonx;","U+022C7" +"djcy;","U+00452" +"dlcorn;","U+0231E" +"dlcrop;","U+0230D" +"dollar;","U+00024" +"dopf;","U+1D555" +"dot;","U+002D9" +"doteq;","U+02250" +"doteqdot;","U+02251" +"dotminus;","U+02238" +"dotplus;","U+02214" +"dotsquare;","U+022A1" +"doublebarwedge;","U+02306" +"downarrow;","U+02193" +"downdownarrows;","U+021CA" +"downharpoonleft;","U+021C3" +"downharpoonright;","U+021C2" +"drbkarow;","U+02910" +"drcorn;","U+0231F" +"drcrop;","U+0230C" +"dscr;","U+1D4B9" +"dscy;","U+00455" +"dsol;","U+029F6" +"dstrok;","U+00111" +"dtdot;","U+022F1" +"dtri;","U+025BF" +"dtrif;","U+025BE" +"duarr;","U+021F5" +"duhar;","U+0296F" +"dwangle;","U+029A6" +"dzcy;","U+0045F" +"dzigrarr;","U+027FF" +"eDDot;","U+02A77" +"eDot;","U+02251" +"eacute;","U+000E9" +"eacute","U+000E9" +"easter;","U+02A6E" +"ecaron;","U+0011B" +"ecir;","U+02256" +"ecirc;","U+000EA" +"ecirc","U+000EA" +"ecolon;","U+02255" +"ecy;","U+0044D" +"edot;","U+00117" +"ee;","U+02147" +"efDot;","U+02252" +"efr;","U+1D522" +"eg;","U+02A9A" +"egrave;","U+000E8" +"egrave","U+000E8" +"egs;","U+02A96" +"egsdot;","U+02A98" +"el;","U+02A99" +"elinters;","U+023E7" +"ell;","U+02113" +"els;","U+02A95" +"elsdot;","U+02A97" +"emacr;","U+00113" +"empty;","U+02205" +"emptyset;","U+02205" +"emptyv;","U+02205" +"emsp13;","U+02004" +"emsp14;","U+02005" +"emsp;","U+02003" +"eng;","U+0014B" +"ensp;","U+02002" +"eogon;","U+00119" +"eopf;","U+1D556" +"epar;","U+022D5" +"eparsl;","U+029E3" +"eplus;","U+02A71" +"epsi;","U+003B5" +"epsilon;","U+003B5" +"epsiv;","U+003F5" +"eqcirc;","U+02256" +"eqcolon;","U+02255" +"eqsim;","U+02242" +"eqslantgtr;","U+02A96" +"eqslantless;","U+02A95" +"equals;","U+0003D" +"equest;","U+0225F" +"equiv;","U+02261" +"equivDD;","U+02A78" +"eqvparsl;","U+029E5" +"erDot;","U+02253" +"erarr;","U+02971" +"escr;","U+0212F" +"esdot;","U+02250" +"esim;","U+02242" +"eta;","U+003B7" +"eth;","U+000F0" +"eth","U+000F0" +"euml;","U+000EB" +"euml","U+000EB" +"euro;","U+020AC" +"excl;","U+00021" +"exist;","U+02203" +"expectation;","U+02130" +"exponentiale;","U+02147" +"fallingdotseq;","U+02252" +"fcy;","U+00444" +"female;","U+02640" +"ffilig;","U+0FB03" +"fflig;","U+0FB00" +"ffllig;","U+0FB04" +"ffr;","U+1D523" +"filig;","U+0FB01" +"flat;","U+0266D" +"fllig;","U+0FB02" +"fltns;","U+025B1" +"fnof;","U+00192" +"fopf;","U+1D557" +"forall;","U+02200" +"fork;","U+022D4" +"forkv;","U+02AD9" +"fpartint;","U+02A0D" +"frac12;","U+000BD" +"frac12","U+000BD" +"frac13;","U+02153" +"frac14;","U+000BC" +"frac14","U+000BC" +"frac15;","U+02155" +"frac16;","U+02159" +"frac18;","U+0215B" +"frac23;","U+02154" +"frac25;","U+02156" +"frac34;","U+000BE" +"frac34","U+000BE" +"frac35;","U+02157" +"frac38;","U+0215C" +"frac45;","U+02158" +"frac56;","U+0215A" +"frac58;","U+0215D" +"frac78;","U+0215E" +"frasl;","U+02044" +"frown;","U+02322" +"fscr;","U+1D4BB" +"gE;","U+02267" +"gEl;","U+02A8C" +"gacute;","U+001F5" +"gamma;","U+003B3" +"gammad;","U+003DD" +"gap;","U+02A86" +"gbreve;","U+0011F" +"gcirc;","U+0011D" +"gcy;","U+00433" +"gdot;","U+00121" +"ge;","U+02265" +"gel;","U+022DB" +"geq;","U+02265" +"geqq;","U+02267" +"geqslant;","U+02A7E" +"ges;","U+02A7E" +"gescc;","U+02AA9" +"gesdot;","U+02A80" +"gesdoto;","U+02A82" +"gesdotol;","U+02A84" +"gesles;","U+02A94" +"gfr;","U+1D524" +"gg;","U+0226B" +"ggg;","U+022D9" +"gimel;","U+02137" +"gjcy;","U+00453" +"gl;","U+02277" +"glE;","U+02A92" +"gla;","U+02AA5" +"glj;","U+02AA4" +"gnE;","U+02269" +"gnap;","U+02A8A" +"gnapprox;","U+02A8A" +"gne;","U+02A88" +"gneq;","U+02A88" +"gneqq;","U+02269" +"gnsim;","U+022E7" +"gopf;","U+1D558" +"grave;","U+00060" +"gscr;","U+0210A" +"gsim;","U+02273" +"gsime;","U+02A8E" +"gsiml;","U+02A90" +"gt;","U+0003E" +"gt","U+0003E" +"gtcc;","U+02AA7" +"gtcir;","U+02A7A" +"gtdot;","U+022D7" +"gtlPar;","U+02995" +"gtquest;","U+02A7C" +"gtrapprox;","U+02A86" +"gtrarr;","U+02978" +"gtrdot;","U+022D7" +"gtreqless;","U+022DB" +"gtreqqless;","U+02A8C" +"gtrless;","U+02277" +"gtrsim;","U+02273" +"hArr;","U+021D4" +"hairsp;","U+0200A" +"half;","U+000BD" +"hamilt;","U+0210B" +"hardcy;","U+0044A" +"harr;","U+02194" +"harrcir;","U+02948" +"harrw;","U+021AD" +"hbar;","U+0210F" +"hcirc;","U+00125" +"hearts;","U+02665" +"heartsuit;","U+02665" +"hellip;","U+02026" +"hercon;","U+022B9" +"hfr;","U+1D525" +"hksearow;","U+02925" +"hkswarow;","U+02926" +"hoarr;","U+021FF" +"homtht;","U+0223B" +"hookleftarrow;","U+021A9" +"hookrightarrow;","U+021AA" +"hopf;","U+1D559" +"horbar;","U+02015" +"hscr;","U+1D4BD" +"hslash;","U+0210F" +"hstrok;","U+00127" +"hybull;","U+02043" +"hyphen;","U+02010" +"iacute;","U+000ED" +"iacute","U+000ED" +"ic;","U+02063" +"icirc;","U+000EE" +"icirc","U+000EE" +"icy;","U+00438" +"iecy;","U+00435" +"iexcl;","U+000A1" +"iexcl","U+000A1" +"iff;","U+021D4" +"ifr;","U+1D526" +"igrave;","U+000EC" +"igrave","U+000EC" +"ii;","U+02148" +"iiiint;","U+02A0C" +"iiint;","U+0222D" +"iinfin;","U+029DC" +"iiota;","U+02129" +"ijlig;","U+00133" +"imacr;","U+0012B" +"image;","U+02111" +"imagline;","U+02110" +"imagpart;","U+02111" +"imath;","U+00131" +"imof;","U+022B7" +"imped;","U+001B5" +"in;","U+02208" +"incare;","U+02105" +"infin;","U+0221E" +"infintie;","U+029DD" +"inodot;","U+00131" +"int;","U+0222B" +"intcal;","U+022BA" +"integers;","U+02124" +"intercal;","U+022BA" +"intlarhk;","U+02A17" +"intprod;","U+02A3C" +"iocy;","U+00451" +"iogon;","U+0012F" +"iopf;","U+1D55A" +"iota;","U+003B9" +"iprod;","U+02A3C" +"iquest;","U+000BF" +"iquest","U+000BF" +"iscr;","U+1D4BE" +"isin;","U+02208" +"isinE;","U+022F9" +"isindot;","U+022F5" +"isins;","U+022F4" +"isinsv;","U+022F3" +"isinv;","U+02208" +"it;","U+02062" +"itilde;","U+00129" +"iukcy;","U+00456" +"iuml;","U+000EF" +"iuml","U+000EF" +"jcirc;","U+00135" +"jcy;","U+00439" +"jfr;","U+1D527" +"jmath;","U+00237" +"jopf;","U+1D55B" +"jscr;","U+1D4BF" +"jsercy;","U+00458" +"jukcy;","U+00454" +"kappa;","U+003BA" +"kappav;","U+003F0" +"kcedil;","U+00137" +"kcy;","U+0043A" +"kfr;","U+1D528" +"kgreen;","U+00138" +"khcy;","U+00445" +"kjcy;","U+0045C" +"kopf;","U+1D55C" +"kscr;","U+1D4C0" +"lAarr;","U+021DA" +"lArr;","U+021D0" +"lAtail;","U+0291B" +"lBarr;","U+0290E" +"lE;","U+02266" +"lEg;","U+02A8B" +"lHar;","U+02962" +"lacute;","U+0013A" +"laemptyv;","U+029B4" +"lagran;","U+02112" +"lambda;","U+003BB" +"lang;","U+027E8" +"langd;","U+02991" +"langle;","U+027E8" +"lap;","U+02A85" +"laquo;","U+000AB" +"laquo","U+000AB" +"larr;","U+02190" +"larrb;","U+021E4" +"larrbfs;","U+0291F" +"larrfs;","U+0291D" +"larrhk;","U+021A9" +"larrlp;","U+021AB" +"larrpl;","U+02939" +"larrsim;","U+02973" +"larrtl;","U+021A2" +"lat;","U+02AAB" +"latail;","U+02919" +"late;","U+02AAD" +"lbarr;","U+0290C" +"lbbrk;","U+02772" +"lbrace;","U+0007B" +"lbrack;","U+0005B" +"lbrke;","U+0298B" +"lbrksld;","U+0298F" +"lbrkslu;","U+0298D" +"lcaron;","U+0013E" +"lcedil;","U+0013C" +"lceil;","U+02308" +"lcub;","U+0007B" +"lcy;","U+0043B" +"ldca;","U+02936" +"ldquo;","U+0201C" +"ldquor;","U+0201E" +"ldrdhar;","U+02967" +"ldrushar;","U+0294B" +"ldsh;","U+021B2" +"le;","U+02264" +"leftarrow;","U+02190" +"leftarrowtail;","U+021A2" +"leftharpoondown;","U+021BD" +"leftharpoonup;","U+021BC" +"leftleftarrows;","U+021C7" +"leftrightarrow;","U+02194" +"leftrightarrows;","U+021C6" +"leftrightharpoons;","U+021CB" +"leftrightsquigarrow;","U+021AD" +"leftthreetimes;","U+022CB" +"leg;","U+022DA" +"leq;","U+02264" +"leqq;","U+02266" +"leqslant;","U+02A7D" +"les;","U+02A7D" +"lescc;","U+02AA8" +"lesdot;","U+02A7F" +"lesdoto;","U+02A81" +"lesdotor;","U+02A83" +"lesges;","U+02A93" +"lessapprox;","U+02A85" +"lessdot;","U+022D6" +"lesseqgtr;","U+022DA" +"lesseqqgtr;","U+02A8B" +"lessgtr;","U+02276" +"lesssim;","U+02272" +"lfisht;","U+0297C" +"lfloor;","U+0230A" +"lfr;","U+1D529" +"lg;","U+02276" +"lgE;","U+02A91" +"lhard;","U+021BD" +"lharu;","U+021BC" +"lharul;","U+0296A" +"lhblk;","U+02584" +"ljcy;","U+00459" +"ll;","U+0226A" +"llarr;","U+021C7" +"llcorner;","U+0231E" +"llhard;","U+0296B" +"lltri;","U+025FA" +"lmidot;","U+00140" +"lmoust;","U+023B0" +"lmoustache;","U+023B0" +"lnE;","U+02268" +"lnap;","U+02A89" +"lnapprox;","U+02A89" +"lne;","U+02A87" +"lneq;","U+02A87" +"lneqq;","U+02268" +"lnsim;","U+022E6" +"loang;","U+027EC" +"loarr;","U+021FD" +"lobrk;","U+027E6" +"longleftarrow;","U+027F5" +"longleftrightarrow;","U+027F7" +"longmapsto;","U+027FC" +"longrightarrow;","U+027F6" +"looparrowleft;","U+021AB" +"looparrowright;","U+021AC" +"lopar;","U+02985" +"lopf;","U+1D55D" +"loplus;","U+02A2D" +"lotimes;","U+02A34" +"lowast;","U+02217" +"lowbar;","U+0005F" +"loz;","U+025CA" +"lozenge;","U+025CA" +"lozf;","U+029EB" +"lpar;","U+00028" +"lparlt;","U+02993" +"lrarr;","U+021C6" +"lrcorner;","U+0231F" +"lrhar;","U+021CB" +"lrhard;","U+0296D" +"lrm;","U+0200E" +"lrtri;","U+022BF" +"lsaquo;","U+02039" +"lscr;","U+1D4C1" +"lsh;","U+021B0" +"lsim;","U+02272" +"lsime;","U+02A8D" +"lsimg;","U+02A8F" +"lsqb;","U+0005B" +"lsquo;","U+02018" +"lsquor;","U+0201A" +"lstrok;","U+00142" +"lt;","U+0003C" +"lt","U+0003C" +"ltcc;","U+02AA6" +"ltcir;","U+02A79" +"ltdot;","U+022D6" +"lthree;","U+022CB" +"ltimes;","U+022C9" +"ltlarr;","U+02976" +"ltquest;","U+02A7B" +"ltrPar;","U+02996" +"ltri;","U+025C3" +"ltrie;","U+022B4" +"ltrif;","U+025C2" +"lurdshar;","U+0294A" +"luruhar;","U+02966" +"mDDot;","U+0223A" +"macr;","U+000AF" +"macr","U+000AF" +"male;","U+02642" +"malt;","U+02720" +"maltese;","U+02720" +"map;","U+021A6" +"mapsto;","U+021A6" +"mapstodown;","U+021A7" +"mapstoleft;","U+021A4" +"mapstoup;","U+021A5" +"marker;","U+025AE" +"mcomma;","U+02A29" +"mcy;","U+0043C" +"mdash;","U+02014" +"measuredangle;","U+02221" +"mfr;","U+1D52A" +"mho;","U+02127" +"micro;","U+000B5" +"micro","U+000B5" +"mid;","U+02223" +"midast;","U+0002A" +"midcir;","U+02AF0" +"middot;","U+000B7" +"middot","U+000B7" +"minus;","U+02212" +"minusb;","U+0229F" +"minusd;","U+02238" +"minusdu;","U+02A2A" +"mlcp;","U+02ADB" +"mldr;","U+02026" +"mnplus;","U+02213" +"models;","U+022A7" +"mopf;","U+1D55E" +"mp;","U+02213" +"mscr;","U+1D4C2" +"mstpos;","U+0223E" +"mu;","U+003BC" +"multimap;","U+022B8" +"mumap;","U+022B8" +"nLeftarrow;","U+021CD" +"nLeftrightarrow;","U+021CE" +"nRightarrow;","U+021CF" +"nVDash;","U+022AF" +"nVdash;","U+022AE" +"nabla;","U+02207" +"nacute;","U+00144" +"nap;","U+02249" +"napos;","U+00149" +"napprox;","U+02249" +"natur;","U+0266E" +"natural;","U+0266E" +"naturals;","U+02115" +"nbsp;","U+000A0" +"nbsp","U+000A0" +"ncap;","U+02A43" +"ncaron;","U+00148" +"ncedil;","U+00146" +"ncong;","U+02247" +"ncup;","U+02A42" +"ncy;","U+0043D" +"ndash;","U+02013" +"ne;","U+02260" +"neArr;","U+021D7" +"nearhk;","U+02924" +"nearr;","U+02197" +"nearrow;","U+02197" +"nequiv;","U+02262" +"nesear;","U+02928" +"nexist;","U+02204" +"nexists;","U+02204" +"nfr;","U+1D52B" +"nge;","U+02271" +"ngeq;","U+02271" +"ngsim;","U+02275" +"ngt;","U+0226F" +"ngtr;","U+0226F" +"nhArr;","U+021CE" +"nharr;","U+021AE" +"nhpar;","U+02AF2" +"ni;","U+0220B" +"nis;","U+022FC" +"nisd;","U+022FA" +"niv;","U+0220B" +"njcy;","U+0045A" +"nlArr;","U+021CD" +"nlarr;","U+0219A" +"nldr;","U+02025" +"nle;","U+02270" +"nleftarrow;","U+0219A" +"nleftrightarrow;","U+021AE" +"nleq;","U+02270" +"nless;","U+0226E" +"nlsim;","U+02274" +"nlt;","U+0226E" +"nltri;","U+022EA" +"nltrie;","U+022EC" +"nmid;","U+02224" +"nopf;","U+1D55F" +"not;","U+000AC" +"not","U+000AC" +"notin;","U+02209" +"notinva;","U+02209" +"notinvb;","U+022F7" +"notinvc;","U+022F6" +"notni;","U+0220C" +"notniva;","U+0220C" +"notnivb;","U+022FE" +"notnivc;","U+022FD" +"npar;","U+02226" +"nparallel;","U+02226" +"npolint;","U+02A14" +"npr;","U+02280" +"nprcue;","U+022E0" +"nprec;","U+02280" +"nrArr;","U+021CF" +"nrarr;","U+0219B" +"nrightarrow;","U+0219B" +"nrtri;","U+022EB" +"nrtrie;","U+022ED" +"nsc;","U+02281" +"nsccue;","U+022E1" +"nscr;","U+1D4C3" +"nshortmid;","U+02224" +"nshortparallel;","U+02226" +"nsim;","U+02241" +"nsime;","U+02244" +"nsimeq;","U+02244" +"nsmid;","U+02224" +"nspar;","U+02226" +"nsqsube;","U+022E2" +"nsqsupe;","U+022E3" +"nsub;","U+02284" +"nsube;","U+02288" +"nsubseteq;","U+02288" +"nsucc;","U+02281" +"nsup;","U+02285" +"nsupe;","U+02289" +"nsupseteq;","U+02289" +"ntgl;","U+02279" +"ntilde;","U+000F1" +"ntilde","U+000F1" +"ntlg;","U+02278" +"ntriangleleft;","U+022EA" +"ntrianglelefteq;","U+022EC" +"ntriangleright;","U+022EB" +"ntrianglerighteq;","U+022ED" +"nu;","U+003BD" +"num;","U+00023" +"numero;","U+02116" +"numsp;","U+02007" +"nvDash;","U+022AD" +"nvHarr;","U+02904" +"nvdash;","U+022AC" +"nvinfin;","U+029DE" +"nvlArr;","U+02902" +"nvrArr;","U+02903" +"nwArr;","U+021D6" +"nwarhk;","U+02923" +"nwarr;","U+02196" +"nwarrow;","U+02196" +"nwnear;","U+02927" +"oS;","U+024C8" +"oacute;","U+000F3" +"oacute","U+000F3" +"oast;","U+0229B" +"ocir;","U+0229A" +"ocirc;","U+000F4" +"ocirc","U+000F4" +"ocy;","U+0043E" +"odash;","U+0229D" +"odblac;","U+00151" +"odiv;","U+02A38" +"odot;","U+02299" +"odsold;","U+029BC" +"oelig;","U+00153" +"ofcir;","U+029BF" +"ofr;","U+1D52C" +"ogon;","U+002DB" +"ograve;","U+000F2" +"ograve","U+000F2" +"ogt;","U+029C1" +"ohbar;","U+029B5" +"ohm;","U+003A9" +"oint;","U+0222E" +"olarr;","U+021BA" +"olcir;","U+029BE" +"olcross;","U+029BB" +"oline;","U+0203E" +"olt;","U+029C0" +"omacr;","U+0014D" +"omega;","U+003C9" +"omicron;","U+003BF" +"omid;","U+029B6" +"ominus;","U+02296" +"oopf;","U+1D560" +"opar;","U+029B7" +"operp;","U+029B9" +"oplus;","U+02295" +"or;","U+02228" +"orarr;","U+021BB" +"ord;","U+02A5D" +"order;","U+02134" +"orderof;","U+02134" +"ordf;","U+000AA" +"ordf","U+000AA" +"ordm;","U+000BA" +"ordm","U+000BA" +"origof;","U+022B6" +"oror;","U+02A56" +"orslope;","U+02A57" +"orv;","U+02A5B" +"oscr;","U+02134" +"oslash;","U+000F8" +"oslash","U+000F8" +"osol;","U+02298" +"otilde;","U+000F5" +"otilde","U+000F5" +"otimes;","U+02297" +"otimesas;","U+02A36" +"ouml;","U+000F6" +"ouml","U+000F6" +"ovbar;","U+0233D" +"par;","U+02225" +"para;","U+000B6" +"para","U+000B6" +"parallel;","U+02225" +"parsim;","U+02AF3" +"parsl;","U+02AFD" +"part;","U+02202" +"pcy;","U+0043F" +"percnt;","U+00025" +"period;","U+0002E" +"permil;","U+02030" +"perp;","U+022A5" +"pertenk;","U+02031" +"pfr;","U+1D52D" +"phi;","U+003C6" +"phiv;","U+003D5" +"phmmat;","U+02133" +"phone;","U+0260E" +"pi;","U+003C0" +"pitchfork;","U+022D4" +"piv;","U+003D6" +"planck;","U+0210F" +"planckh;","U+0210E" +"plankv;","U+0210F" +"plus;","U+0002B" +"plusacir;","U+02A23" +"plusb;","U+0229E" +"pluscir;","U+02A22" +"plusdo;","U+02214" +"plusdu;","U+02A25" +"pluse;","U+02A72" +"plusmn;","U+000B1" +"plusmn","U+000B1" +"plussim;","U+02A26" +"plustwo;","U+02A27" +"pm;","U+000B1" +"pointint;","U+02A15" +"popf;","U+1D561" +"pound;","U+000A3" +"pound","U+000A3" +"pr;","U+0227A" +"prE;","U+02AB3" +"prap;","U+02AB7" +"prcue;","U+0227C" +"pre;","U+02AAF" +"prec;","U+0227A" +"precapprox;","U+02AB7" +"preccurlyeq;","U+0227C" +"preceq;","U+02AAF" +"precnapprox;","U+02AB9" +"precneqq;","U+02AB5" +"precnsim;","U+022E8" +"precsim;","U+0227E" +"prime;","U+02032" +"primes;","U+02119" +"prnE;","U+02AB5" +"prnap;","U+02AB9" +"prnsim;","U+022E8" +"prod;","U+0220F" +"profalar;","U+0232E" +"profline;","U+02312" +"profsurf;","U+02313" +"prop;","U+0221D" +"propto;","U+0221D" +"prsim;","U+0227E" +"prurel;","U+022B0" +"pscr;","U+1D4C5" +"psi;","U+003C8" +"puncsp;","U+02008" +"qfr;","U+1D52E" +"qint;","U+02A0C" +"qopf;","U+1D562" +"qprime;","U+02057" +"qscr;","U+1D4C6" +"quaternions;","U+0210D" +"quatint;","U+02A16" +"quest;","U+0003F" +"questeq;","U+0225F" +"quot;","U+00022" +"quot","U+00022" +"rAarr;","U+021DB" +"rArr;","U+021D2" +"rAtail;","U+0291C" +"rBarr;","U+0290F" +"rHar;","U+02964" +"racute;","U+00155" +"radic;","U+0221A" +"raemptyv;","U+029B3" +"rang;","U+027E9" +"rangd;","U+02992" +"range;","U+029A5" +"rangle;","U+027E9" +"raquo;","U+000BB" +"raquo","U+000BB" +"rarr;","U+02192" +"rarrap;","U+02975" +"rarrb;","U+021E5" +"rarrbfs;","U+02920" +"rarrc;","U+02933" +"rarrfs;","U+0291E" +"rarrhk;","U+021AA" +"rarrlp;","U+021AC" +"rarrpl;","U+02945" +"rarrsim;","U+02974" +"rarrtl;","U+021A3" +"rarrw;","U+0219D" +"ratail;","U+0291A" +"ratio;","U+02236" +"rationals;","U+0211A" +"rbarr;","U+0290D" +"rbbrk;","U+02773" +"rbrace;","U+0007D" +"rbrack;","U+0005D" +"rbrke;","U+0298C" +"rbrksld;","U+0298E" +"rbrkslu;","U+02990" +"rcaron;","U+00159" +"rcedil;","U+00157" +"rceil;","U+02309" +"rcub;","U+0007D" +"rcy;","U+00440" +"rdca;","U+02937" +"rdldhar;","U+02969" +"rdquo;","U+0201D" +"rdquor;","U+0201D" +"rdsh;","U+021B3" +"real;","U+0211C" +"realine;","U+0211B" +"realpart;","U+0211C" +"reals;","U+0211D" +"rect;","U+025AD" +"reg;","U+000AE" +"reg","U+000AE" +"rfisht;","U+0297D" +"rfloor;","U+0230B" +"rfr;","U+1D52F" +"rhard;","U+021C1" +"rharu;","U+021C0" +"rharul;","U+0296C" +"rho;","U+003C1" +"rhov;","U+003F1" +"rightarrow;","U+02192" +"rightarrowtail;","U+021A3" +"rightharpoondown;","U+021C1" +"rightharpoonup;","U+021C0" +"rightleftarrows;","U+021C4" +"rightleftharpoons;","U+021CC" +"rightrightarrows;","U+021C9" +"rightsquigarrow;","U+0219D" +"rightthreetimes;","U+022CC" +"ring;","U+002DA" +"risingdotseq;","U+02253" +"rlarr;","U+021C4" +"rlhar;","U+021CC" +"rlm;","U+0200F" +"rmoust;","U+023B1" +"rmoustache;","U+023B1" +"rnmid;","U+02AEE" +"roang;","U+027ED" +"roarr;","U+021FE" +"robrk;","U+027E7" +"ropar;","U+02986" +"ropf;","U+1D563" +"roplus;","U+02A2E" +"rotimes;","U+02A35" +"rpar;","U+00029" +"rpargt;","U+02994" +"rppolint;","U+02A12" +"rrarr;","U+021C9" +"rsaquo;","U+0203A" +"rscr;","U+1D4C7" +"rsh;","U+021B1" +"rsqb;","U+0005D" +"rsquo;","U+02019" +"rsquor;","U+02019" +"rthree;","U+022CC" +"rtimes;","U+022CA" +"rtri;","U+025B9" +"rtrie;","U+022B5" +"rtrif;","U+025B8" +"rtriltri;","U+029CE" +"ruluhar;","U+02968" +"rx;","U+0211E" +"sacute;","U+0015B" +"sbquo;","U+0201A" +"sc;","U+0227B" +"scE;","U+02AB4" +"scap;","U+02AB8" +"scaron;","U+00161" +"sccue;","U+0227D" +"sce;","U+02AB0" +"scedil;","U+0015F" +"scirc;","U+0015D" +"scnE;","U+02AB6" +"scnap;","U+02ABA" +"scnsim;","U+022E9" +"scpolint;","U+02A13" +"scsim;","U+0227F" +"scy;","U+00441" +"sdot;","U+022C5" +"sdotb;","U+022A1" +"sdote;","U+02A66" +"seArr;","U+021D8" +"searhk;","U+02925" +"searr;","U+02198" +"searrow;","U+02198" +"sect;","U+000A7" +"sect","U+000A7" +"semi;","U+0003B" +"seswar;","U+02929" +"setminus;","U+02216" +"setmn;","U+02216" +"sext;","U+02736" +"sfr;","U+1D530" +"sfrown;","U+02322" +"sharp;","U+0266F" +"shchcy;","U+00449" +"shcy;","U+00448" +"shortmid;","U+02223" +"shortparallel;","U+02225" +"shy;","U+000AD " +"shy","U+000AD " +"sigma;","U+003C3" +"sigmaf;","U+003C2" +"sigmav;","U+003C2" +"sim;","U+0223C" +"simdot;","U+02A6A" +"sime;","U+02243" +"simeq;","U+02243" +"simg;","U+02A9E" +"simgE;","U+02AA0" +"siml;","U+02A9D" +"simlE;","U+02A9F" +"simne;","U+02246" +"simplus;","U+02A24" +"simrarr;","U+02972" +"slarr;","U+02190" +"smallsetminus;","U+02216" +"smashp;","U+02A33" +"smeparsl;","U+029E4" +"smid;","U+02223" +"smile;","U+02323" +"smt;","U+02AAA" +"smte;","U+02AAC" +"softcy;","U+0044C" +"sol;","U+0002F" +"solb;","U+029C4" +"solbar;","U+0233F" +"sopf;","U+1D564" +"spades;","U+02660" +"spadesuit;","U+02660" +"spar;","U+02225" +"sqcap;","U+02293" +"sqcup;","U+02294" +"sqsub;","U+0228F" +"sqsube;","U+02291" +"sqsubset;","U+0228F" +"sqsubseteq;","U+02291" +"sqsup;","U+02290" +"sqsupe;","U+02292" +"sqsupset;","U+02290" +"sqsupseteq;","U+02292" +"squ;","U+025A1" +"square;","U+025A1" +"squarf;","U+025AA" +"squf;","U+025AA" +"srarr;","U+02192" +"sscr;","U+1D4C8" +"ssetmn;","U+02216" +"ssmile;","U+02323" +"sstarf;","U+022C6" +"star;","U+02606" +"starf;","U+02605" +"straightepsilon;","U+003F5" +"straightphi;","U+003D5" +"strns;","U+000AF" +"sub;","U+02282" +"subE;","U+02AC5" +"subdot;","U+02ABD" +"sube;","U+02286" +"subedot;","U+02AC3" +"submult;","U+02AC1" +"subnE;","U+02ACB" +"subne;","U+0228A" +"subplus;","U+02ABF" +"subrarr;","U+02979" +"subset;","U+02282" +"subseteq;","U+02286" +"subseteqq;","U+02AC5" +"subsetneq;","U+0228A" +"subsetneqq;","U+02ACB" +"subsim;","U+02AC7" +"subsub;","U+02AD5" +"subsup;","U+02AD3" +"succ;","U+0227B" +"succapprox;","U+02AB8" +"succcurlyeq;","U+0227D" +"succeq;","U+02AB0" +"succnapprox;","U+02ABA" +"succneqq;","U+02AB6" +"succnsim;","U+022E9" +"succsim;","U+0227F" +"sum;","U+02211" +"sung;","U+0266A" +"sup1;","U+000B9" +"sup1","U+000B9" +"sup2;","U+000B2" +"sup2","U+000B2" +"sup3;","U+000B3" +"sup3","U+000B3" +"sup;","U+02283" +"supE;","U+02AC6" +"supdot;","U+02ABE" +"supdsub;","U+02AD8" +"supe;","U+02287" +"supedot;","U+02AC4" +"suphsol;","U+027C9" +"suphsub;","U+02AD7" +"suplarr;","U+0297B" +"supmult;","U+02AC2" +"supnE;","U+02ACC" +"supne;","U+0228B" +"supplus;","U+02AC0" +"supset;","U+02283" +"supseteq;","U+02287" +"supseteqq;","U+02AC6" +"supsetneq;","U+0228B" +"supsetneqq;","U+02ACC" +"supsim;","U+02AC8" +"supsub;","U+02AD4" +"supsup;","U+02AD6" +"swArr;","U+021D9" +"swarhk;","U+02926" +"swarr;","U+02199" +"swarrow;","U+02199" +"swnwar;","U+0292A" +"szlig;","U+000DF" +"szlig","U+000DF" +"target;","U+02316" +"tau;","U+003C4" +"tbrk;","U+023B4" +"tcaron;","U+00165" +"tcedil;","U+00163" +"tcy;","U+00442" +"tdot;","U+020DB" +"telrec;","U+02315" +"tfr;","U+1D531" +"there4;","U+02234" +"therefore;","U+02234" +"theta;","U+003B8" +"thetasym;","U+003D1" +"thetav;","U+003D1" +"thickapprox;","U+02248" +"thicksim;","U+0223C" +"thinsp;","U+02009" +"thkap;","U+02248" +"thksim;","U+0223C" +"thorn;","U+000FE" +"thorn","U+000FE" +"tilde;","U+002DC" +"times;","U+000D7" +"times","U+000D7" +"timesb;","U+022A0" +"timesbar;","U+02A31" +"timesd;","U+02A30" +"tint;","U+0222D" +"toea;","U+02928" +"top;","U+022A4" +"topbot;","U+02336" +"topcir;","U+02AF1" +"topf;","U+1D565" +"topfork;","U+02ADA" +"tosa;","U+02929" +"tprime;","U+02034" +"trade;","U+02122" +"triangle;","U+025B5" +"triangledown;","U+025BF" +"triangleleft;","U+025C3" +"trianglelefteq;","U+022B4" +"triangleq;","U+0225C" +"triangleright;","U+025B9" +"trianglerighteq;","U+022B5" +"tridot;","U+025EC" +"trie;","U+0225C" +"triminus;","U+02A3A" +"triplus;","U+02A39" +"trisb;","U+029CD" +"tritime;","U+02A3B" +"trpezium;","U+023E2" +"tscr;","U+1D4C9" +"tscy;","U+00446" +"tshcy;","U+0045B" +"tstrok;","U+00167" +"twixt;","U+0226C" +"twoheadleftarrow;","U+0219E" +"twoheadrightarrow;","U+021A0" +"uArr;","U+021D1" +"uHar;","U+02963" +"uacute;","U+000FA" +"uacute","U+000FA" +"uarr;","U+02191" +"ubrcy;","U+0045E" +"ubreve;","U+0016D" +"ucirc;","U+000FB" +"ucirc","U+000FB" +"ucy;","U+00443" +"udarr;","U+021C5" +"udblac;","U+00171" +"udhar;","U+0296E" +"ufisht;","U+0297E" +"ufr;","U+1D532" +"ugrave;","U+000F9" +"ugrave","U+000F9" +"uharl;","U+021BF" +"uharr;","U+021BE" +"uhblk;","U+02580" +"ulcorn;","U+0231C" +"ulcorner;","U+0231C" +"ulcrop;","U+0230F" +"ultri;","U+025F8" +"umacr;","U+0016B" +"uml;","U+000A8" +"uml","U+000A8" +"uogon;","U+00173" +"uopf;","U+1D566" +"uparrow;","U+02191" +"updownarrow;","U+02195" +"upharpoonleft;","U+021BF" +"upharpoonright;","U+021BE" +"uplus;","U+0228E" +"upsi;","U+003C5" +"upsih;","U+003D2" +"upsilon;","U+003C5" +"upuparrows;","U+021C8" +"urcorn;","U+0231D" +"urcorner;","U+0231D" +"urcrop;","U+0230E" +"uring;","U+0016F" +"urtri;","U+025F9" +"uscr;","U+1D4CA" +"utdot;","U+022F0" +"utilde;","U+00169" +"utri;","U+025B5" +"utrif;","U+025B4" +"uuarr;","U+021C8" +"uuml;","U+000FC" +"uuml","U+000FC" +"uwangle;","U+029A7" +"vArr;","U+021D5" +"vBar;","U+02AE8" +"vBarv;","U+02AE9" +"vDash;","U+022A8" +"vangrt;","U+0299C" +"varepsilon;","U+003F5" +"varkappa;","U+003F0" +"varnothing;","U+02205" +"varphi;","U+003D5" +"varpi;","U+003D6" +"varpropto;","U+0221D" +"varr;","U+02195" +"varrho;","U+003F1" +"varsigma;","U+003C2" +"vartheta;","U+003D1" +"vartriangleleft;","U+022B2" +"vartriangleright;","U+022B3" +"vcy;","U+00432" +"vdash;","U+022A2" +"vee;","U+02228" +"veebar;","U+022BB" +"veeeq;","U+0225A" +"vellip;","U+022EE" +"verbar;","U+0007C" +"vert;","U+0007C" +"vfr;","U+1D533" +"vltri;","U+022B2" +"vopf;","U+1D567" +"vprop;","U+0221D" +"vrtri;","U+022B3" +"vscr;","U+1D4CB" +"vzigzag;","U+0299A" +"wcirc;","U+00175" +"wedbar;","U+02A5F" +"wedge;","U+02227" +"wedgeq;","U+02259" +"weierp;","U+02118" +"wfr;","U+1D534" +"wopf;","U+1D568" +"wp;","U+02118" +"wr;","U+02240" +"wreath;","U+02240" +"wscr;","U+1D4CC" +"xcap;","U+022C2" +"xcirc;","U+025EF" +"xcup;","U+022C3" +"xdtri;","U+025BD" +"xfr;","U+1D535" +"xhArr;","U+027FA" +"xharr;","U+027F7" +"xi;","U+003BE" +"xlArr;","U+027F8" +"xlarr;","U+027F5" +"xmap;","U+027FC" +"xnis;","U+022FB" +"xodot;","U+02A00" +"xopf;","U+1D569" +"xoplus;","U+02A01" +"xotime;","U+02A02" +"xrArr;","U+027F9" +"xrarr;","U+027F6" +"xscr;","U+1D4CD" +"xsqcup;","U+02A06" +"xuplus;","U+02A04" +"xutri;","U+025B3" +"xvee;","U+022C1" +"xwedge;","U+022C0" +"yacute;","U+000FD" +"yacute","U+000FD" +"yacy;","U+0044F" +"ycirc;","U+00177" +"ycy;","U+0044B" +"yen;","U+000A5" +"yen","U+000A5" +"yfr;","U+1D536" +"yicy;","U+00457" +"yopf;","U+1D56A" +"yscr;","U+1D4CE" +"yucy;","U+0044E" +"yuml;","U+000FF" +"yuml","U+000FF" +"zacute;","U+0017A" +"zcaron;","U+0017E" +"zcy;","U+00437" +"zdot;","U+0017C" +"zeetrf;","U+02128" +"zeta;","U+003B6" +"zfr;","U+1D537" +"zhcy;","U+00436" +"zigrarr;","U+021DD" +"zopf;","U+1D56B" +"zscr;","U+1D4CF" +"zwj;","U+0200D" +"zwnj;","U+0200C" diff --git a/WebCore/html/parser/HTMLEntityParser.cpp b/WebCore/html/parser/HTMLEntityParser.cpp new file mode 100644 index 0000000..6a422b8 --- /dev/null +++ b/WebCore/html/parser/HTMLEntityParser.cpp @@ -0,0 +1,272 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * Copyright (C) 2009 Torch Mobile, Inc. http://www.torchmobile.com/ + * Copyright (C) 2010 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 APPLE 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 APPLE 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" +#include "HTMLEntityParser.h" + +#include "HTMLEntitySearch.h" +#include "HTMLEntityTable.h" +#include + +using namespace WTF; + +namespace WebCore { + +namespace { + +static const UChar windowsLatin1ExtensionArray[32] = { + 0x20AC, 0x0081, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, // 80-87 + 0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, 0x008D, 0x017D, 0x008F, // 88-8F + 0x0090, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, // 90-97 + 0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, 0x009D, 0x017E, 0x0178, // 98-9F +}; + +inline UChar adjustEntity(UChar32 value) +{ + if ((value & ~0x1F) != 0x0080) + return value; + return windowsLatin1ExtensionArray[value - 0x80]; +} + +inline UChar32 legalEntityFor(UChar32 value) +{ + // FIXME: A number of specific entity values generate parse errors. + if (value == 0 || value > 0x10FFFF || (value >= 0xD800 && value <= 0xDFFF)) + return 0xFFFD; + if (U_IS_BMP(value)) + return adjustEntity(value); + return value; +} + +inline bool convertToUTF16(UChar32 value, Vector& decodedEntity) +{ + if (U_IS_BMP(value)) { + UChar character = static_cast(value); + ASSERT(character == value); + decodedEntity.append(character); + return true; + } + decodedEntity.append(U16_LEAD(value)); + decodedEntity.append(U16_TRAIL(value)); + return true; +} + +inline bool isHexDigit(UChar cc) +{ + return (cc >= '0' && cc <= '9') || (cc >= 'a' && cc <= 'f') || (cc >= 'A' && cc <= 'F'); +} + +inline bool isAlphaNumeric(UChar cc) +{ + return (cc >= '0' && cc <= '9') || (cc >= 'a' && cc <= 'z') || (cc >= 'A' && cc <= 'Z'); +} + +void unconsumeCharacters(SegmentedString& source, const Vector& consumedCharacters) +{ + if (consumedCharacters.size() == 1) + source.push(consumedCharacters[0]); + else if (consumedCharacters.size() == 2) { + source.push(consumedCharacters[0]); + source.push(consumedCharacters[1]); + } else + source.prepend(SegmentedString(String(consumedCharacters.data(), consumedCharacters.size()))); +} + +} + +bool consumeHTMLEntity(SegmentedString& source, Vector& decodedEntity, bool& notEnoughCharacters, UChar additionalAllowedCharacter) +{ + ASSERT(!additionalAllowedCharacter || additionalAllowedCharacter == '"' || additionalAllowedCharacter == '\'' || additionalAllowedCharacter == '>'); + ASSERT(!notEnoughCharacters); + ASSERT(decodedEntity.isEmpty()); + + enum EntityState { + Initial, + Number, + MaybeHexLowerCaseX, + MaybeHexUpperCaseX, + Hex, + Decimal, + Named + }; + EntityState entityState = Initial; + UChar32 result = 0; + Vector consumedCharacters; + + while (!source.isEmpty()) { + UChar cc = *source; + switch (entityState) { + case Initial: { + if (cc == '\x09' || cc == '\x0A' || cc == '\x0C' || cc == ' ' || cc == '<' || cc == '&') + return false; + if (additionalAllowedCharacter && cc == additionalAllowedCharacter) + return false; + if (cc == '#') { + entityState = Number; + break; + } + if ((cc >= 'a' && cc <= 'z') || (cc >= 'A' && cc <= 'Z')) { + entityState = Named; + continue; + } + return false; + } + case Number: { + if (cc == 'x') { + entityState = MaybeHexLowerCaseX; + break; + } + if (cc == 'X') { + entityState = MaybeHexUpperCaseX; + break; + } + if (cc >= '0' && cc <= '9') { + entityState = Decimal; + continue; + } + source.push('#'); + return false; + } + case MaybeHexLowerCaseX: { + if (isHexDigit(cc)) { + entityState = Hex; + continue; + } + source.push('#'); + source.push('x'); + return false; + } + case MaybeHexUpperCaseX: { + if (isHexDigit(cc)) { + entityState = Hex; + continue; + } + source.push('#'); + source.push('X'); + return false; + } + case Hex: { + if (cc >= '0' && cc <= '9') + result = result * 16 + cc - '0'; + else if (cc >= 'a' && cc <= 'f') + result = result * 16 + 10 + cc - 'a'; + else if (cc >= 'A' && cc <= 'F') + result = result * 16 + 10 + cc - 'A'; + else { + if (cc == ';') + source.advanceAndASSERT(cc); + return convertToUTF16(legalEntityFor(result), decodedEntity); + } + break; + } + case Decimal: { + if (cc >= '0' && cc <= '9') + result = result * 10 + cc - '0'; + else { + if (cc == ';') + source.advanceAndASSERT(cc); + return convertToUTF16(legalEntityFor(result), decodedEntity); + } + break; + } + case Named: { + HTMLEntitySearch entitySearch; + while (!source.isEmpty()) { + cc = *source; + entitySearch.advance(cc); + if (!entitySearch.isEntityPrefix()) + break; + consumedCharacters.append(cc); + source.advanceAndASSERT(cc); + } + notEnoughCharacters = source.isEmpty(); + if (notEnoughCharacters) { + // We can't an entity because there might be a longer entity + // that we could match if we had more data. + unconsumeCharacters(source, consumedCharacters); + return false; + } + if (!entitySearch.mostRecentMatch()) { + ASSERT(!entitySearch.currentValue()); + unconsumeCharacters(source, consumedCharacters); + return false; + } + if (entitySearch.mostRecentMatch()->length != entitySearch.currentLength()) { + // We've consumed too many characters. We need to walk the + // source back to the point at which we had consumed an + // actual entity. + unconsumeCharacters(source, consumedCharacters); + consumedCharacters.clear(); + const int length = entitySearch.mostRecentMatch()->length; + const UChar* reference = entitySearch.mostRecentMatch()->entity; + for (int i = 0; i < length; ++i) { + cc = *source; + ASSERT_UNUSED(reference, cc == *reference++); + consumedCharacters.append(cc); + source.advanceAndASSERT(cc); + ASSERT(!source.isEmpty()); + } + cc = *source; + } + if (entitySearch.mostRecentMatch()->lastCharacter() == ';' + || !additionalAllowedCharacter + || !(isAlphaNumeric(cc) || cc == '=')) { + return convertToUTF16(entitySearch.mostRecentMatch()->value, decodedEntity); + } + unconsumeCharacters(source, consumedCharacters); + return false; + } + } + consumedCharacters.append(cc); + source.advanceAndASSERT(cc); + } + ASSERT(source.isEmpty()); + notEnoughCharacters = true; + unconsumeCharacters(source, consumedCharacters); + return false; +} + +UChar decodeNamedEntity(const char* name) +{ + HTMLEntitySearch search; + while (*name) { + search.advance(*name++); + if (!search.isEntityPrefix()) + return 0; + } + search.advance(';'); + UChar32 entityValue = search.currentValue(); + if (U16_LENGTH(entityValue) != 1) { + // Callers need to move off this API if the entity table has values + // which do no fit in a 16 bit UChar! + ASSERT_NOT_REACHED(); + return 0; + } + return static_cast(entityValue); +} + +} // namespace WebCore diff --git a/WebCore/html/parser/HTMLEntityParser.h b/WebCore/html/parser/HTMLEntityParser.h new file mode 100644 index 0000000..f02e849 --- /dev/null +++ b/WebCore/html/parser/HTMLEntityParser.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * Copyright (C) 2010 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 APPLE 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 APPLE 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. + */ + +#ifndef HTMLEntityParser_h +#define HTMLEntityParser_h + +#include "SegmentedString.h" + +namespace WebCore { + +bool consumeHTMLEntity(SegmentedString&, Vector& decodedEntity, bool& notEnoughCharacters, UChar additionalAllowedCharacter = '\0'); + +// Used by the XML parser. Not suitable for use in HTML parsing. Use consumeHTMLEntity instead. +UChar decodeNamedEntity(const char*); + +} + +#endif diff --git a/WebCore/html/parser/HTMLEntitySearch.cpp b/WebCore/html/parser/HTMLEntitySearch.cpp new file mode 100644 index 0000000..580609e --- /dev/null +++ b/WebCore/html/parser/HTMLEntitySearch.cpp @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2010 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 APPLE 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 APPLE 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" +#include "HTMLEntitySearch.h" + +#include "HTMLEntityTable.h" + +namespace WebCore { + +namespace { + +const HTMLEntityTableEntry* halfway(const HTMLEntityTableEntry* left, const HTMLEntityTableEntry* right) +{ + return &left[(right - left) / 2]; +} + +} + +HTMLEntitySearch::HTMLEntitySearch() + : m_currentLength(0) + , m_currentValue(0) + , m_mostRecentMatch(0) + , m_first(HTMLEntityTable::firstEntry()) + , m_last(HTMLEntityTable::lastEntry()) +{ +} + +HTMLEntitySearch::CompareResult HTMLEntitySearch::compare(const HTMLEntityTableEntry* entry, UChar nextCharacter) const +{ + if (entry->length < m_currentLength + 1) + return Before; + UChar entryNextCharacter = entry->entity[m_currentLength]; + if (entryNextCharacter == nextCharacter) + return Prefix; + return entryNextCharacter < nextCharacter ? Before : After; +} + +const HTMLEntityTableEntry* HTMLEntitySearch::findFirst(UChar nextCharacter) const +{ + const HTMLEntityTableEntry* left = m_first; + const HTMLEntityTableEntry* right = m_last; + if (left == right) + return left; + CompareResult result = compare(left, nextCharacter); + if (result == Prefix) + return left; + if (result == After) + return right; + while (left + 1 < right) { + const HTMLEntityTableEntry* probe = halfway(left, right); + result = compare(probe, nextCharacter); + if (result == Before) + left = probe; + else { + ASSERT(result == After || result == Prefix); + right = probe; + } + } + ASSERT(left + 1 == right); + return right; +} + +const HTMLEntityTableEntry* HTMLEntitySearch::findLast(UChar nextCharacter) const +{ + const HTMLEntityTableEntry* left = m_first; + const HTMLEntityTableEntry* right = m_last; + if (left == right) + return right; + CompareResult result = compare(right, nextCharacter); + if (result == Prefix) + return right; + if (result == Before) + return left; + while (left + 1 < right) { + const HTMLEntityTableEntry* probe = halfway(left, right); + result = compare(probe, nextCharacter); + if (result == After) + right = probe; + else { + ASSERT(result == Before || result == Prefix); + left = probe; + } + } + ASSERT(left + 1 == right); + return left; +} + +void HTMLEntitySearch::advance(UChar nextCharacter) +{ + ASSERT(isEntityPrefix()); + if (!m_currentLength) { + m_first = HTMLEntityTable::firstEntryStartingWith(nextCharacter); + m_last = HTMLEntityTable::lastEntryStartingWith(nextCharacter); + } else { + m_first = findFirst(nextCharacter); + m_last = findLast(nextCharacter); + if (m_first == m_last && compare(m_first, nextCharacter) != Prefix) + return fail(); + } + ++m_currentLength; + if (m_first->length != m_currentLength) { + m_currentValue = 0; + return; + } + m_mostRecentMatch = m_first; + m_currentValue = m_mostRecentMatch->value; +} + +} diff --git a/WebCore/html/parser/HTMLEntitySearch.h b/WebCore/html/parser/HTMLEntitySearch.h new file mode 100644 index 0000000..0c66318 --- /dev/null +++ b/WebCore/html/parser/HTMLEntitySearch.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2010 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 APPLE 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 APPLE 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. + */ + +#ifndef HTMLEntitySearch_h +#define HTMLEntitySearch_h + +#include "PlatformString.h" + +namespace WebCore { + +struct HTMLEntityTableEntry; + +class HTMLEntitySearch { +public: + HTMLEntitySearch(); + + void advance(UChar); + + bool isEntityPrefix() const { return !!m_first; } + UChar32 currentValue() const { return m_currentValue; } + int currentLength() const { return m_currentLength; } + + const HTMLEntityTableEntry* mostRecentMatch() const { return m_mostRecentMatch; } + +private: + enum CompareResult { + Before, + Prefix, + After, + }; + + CompareResult compare(const HTMLEntityTableEntry*, UChar) const; + const HTMLEntityTableEntry* findFirst(UChar) const; + const HTMLEntityTableEntry* findLast(UChar) const; + + void fail() + { + m_currentValue = 0; + m_first = 0; + m_last = 0; + } + + int m_currentLength; + UChar32 m_currentValue; + + const HTMLEntityTableEntry* m_mostRecentMatch; + const HTMLEntityTableEntry* m_first; + const HTMLEntityTableEntry* m_last; +}; + +} + +#endif diff --git a/WebCore/html/parser/HTMLEntityTable.h b/WebCore/html/parser/HTMLEntityTable.h new file mode 100644 index 0000000..3b9ab4e --- /dev/null +++ b/WebCore/html/parser/HTMLEntityTable.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2010 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 APPLE 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 APPLE 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. + */ + +#ifndef HTMLEntityTable_h +#define HTMLEntityTable_h + +#include "PlatformString.h" + +namespace WebCore { + +struct HTMLEntityTableEntry { + UChar lastCharacter() const { return entity[length - 1]; } + + const UChar* entity; + int length; + UChar32 value; +}; + +class HTMLEntityTable { +public: + static const HTMLEntityTableEntry* firstEntry(); + static const HTMLEntityTableEntry* lastEntry(); + + static const HTMLEntityTableEntry* firstEntryStartingWith(UChar); + static const HTMLEntityTableEntry* lastEntryStartingWith(UChar); +}; + +} + +#endif diff --git a/WebCore/html/parser/HTMLFormattingElementList.cpp b/WebCore/html/parser/HTMLFormattingElementList.cpp new file mode 100644 index 0000000..22bf03e --- /dev/null +++ b/WebCore/html/parser/HTMLFormattingElementList.cpp @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2010 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" +#include "HTMLFormattingElementList.h" + +#include "Element.h" +#include "NotImplemented.h" + +namespace WebCore { + +HTMLFormattingElementList::HTMLFormattingElementList() +{ +} + +HTMLFormattingElementList::~HTMLFormattingElementList() +{ +} + +Element* HTMLFormattingElementList::closestElementInScopeWithName(const AtomicString& targetName) +{ + for (unsigned i = 1; i <= m_entries.size(); ++i) { + const Entry& entry = m_entries[m_entries.size() - i]; + if (entry.isMarker()) + return 0; + if (entry.element()->hasLocalName(targetName)) + return entry.element(); + } + return 0; +} + +bool HTMLFormattingElementList::contains(Element* element) +{ + return !!find(element); +} + +HTMLFormattingElementList::Entry* HTMLFormattingElementList::find(Element* element) +{ + size_t index = m_entries.reverseFind(element); + if (index != notFound) { + // This is somewhat of a hack, and is why this method can't be const. + return &m_entries[index]; + } + return 0; +} + +HTMLFormattingElementList::Bookmark HTMLFormattingElementList::bookmarkFor(Element* element) +{ + size_t index = m_entries.reverseFind(element); + ASSERT(index != notFound); + return Bookmark(&at(index)); +} + +void HTMLFormattingElementList::swapTo(Element* oldElement, Element* newElement, const Bookmark& bookmark) +{ + ASSERT(contains(oldElement)); + ASSERT(!contains(newElement)); + if (!bookmark.hasBeenMoved()) { + ASSERT(bookmark.mark()->element() == oldElement); + bookmark.mark()->replaceElement(newElement); + return; + } + size_t index = bookmark.mark() - first(); + ASSERT(index < size()); + m_entries.insert(index + 1, newElement); + remove(oldElement); +} + +void HTMLFormattingElementList::append(Element* element) +{ + m_entries.append(element); +} + +void HTMLFormattingElementList::remove(Element* element) +{ + size_t index = m_entries.reverseFind(element); + if (index != notFound) + m_entries.remove(index); +} + +void HTMLFormattingElementList::appendMarker() +{ + m_entries.append(Entry::MarkerEntry); +} + +void HTMLFormattingElementList::clearToLastMarker() +{ + // http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#clear-the-list-of-active-formatting-elements-up-to-the-last-marker + while (m_entries.size()) { + bool shouldStop = m_entries.last().isMarker(); + m_entries.removeLast(); + if (shouldStop) + break; + } +} + +#ifndef NDEBUG + +void HTMLFormattingElementList::show() +{ + for (unsigned i = 1; i <= m_entries.size(); ++i) { + const Entry& entry = m_entries[m_entries.size() - i]; + if (entry.isMarker()) + fprintf(stderr, "marker\n"); + else + entry.element()->showNode(); + } +} + +#endif + +} diff --git a/WebCore/html/parser/HTMLFormattingElementList.h b/WebCore/html/parser/HTMLFormattingElementList.h new file mode 100644 index 0000000..aca05bb --- /dev/null +++ b/WebCore/html/parser/HTMLFormattingElementList.h @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2010 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. + */ + +#ifndef HTMLFormattingElementList_h +#define HTMLFormattingElementList_h + +#include +#include +#include + +namespace WebCore { + +class Element; + +// This may end up merged into HTMLElementStack. +class HTMLFormattingElementList : public Noncopyable { +public: + HTMLFormattingElementList(); + ~HTMLFormattingElementList(); + + // Ideally Entry would be private, but HTMLTreeBuilder has to coordinate + // between the HTMLFormattingElementList and HTMLElementStack and needs + // access to Entry::isMarker() and Entry::replaceElement() to do so. + class Entry { + public: + // Inline because they're hot and Vector uses them. + explicit Entry(Element* element) + : m_element(element) + { + ASSERT(element); + } + enum MarkerEntryType { MarkerEntry }; + Entry(MarkerEntryType) + : m_element(0) + { + } + ~Entry() {} + + bool isMarker() const { return !m_element; } + + Element* element() const + { + // The fact that !m_element == isMarker() is an implementation detail + // callers should check isMarker() before calling element(). + ASSERT(m_element); + return m_element.get(); + } + void replaceElement(PassRefPtr element) { m_element = element; } + + // Needed for use with Vector. These are super-hot and must be inline. + bool operator==(Element* element) const { return m_element == element; } + bool operator!=(Element* element) const { return m_element != element; } + + private: + RefPtr m_element; + }; + + class Bookmark { + public: + Bookmark(Entry* entry) + : m_hasBeenMoved(false) + , m_mark(entry) + { + } + + void moveToAfter(Entry* before) + { + m_hasBeenMoved = true; + m_mark = before; + } + + bool hasBeenMoved() const { return m_hasBeenMoved; } + Entry* mark() const { return m_mark; } + + private: + bool m_hasBeenMoved; + Entry* m_mark; + }; + + bool isEmpty() const { return !size(); } + size_t size() const { return m_entries.size(); } + + Element* closestElementInScopeWithName(const AtomicString&); + + Entry* find(Element*); + bool contains(Element*); + void append(Element*); + void remove(Element*); + + Bookmark bookmarkFor(Element*); + void swapTo(Element* oldElement, Element* newElement, const Bookmark&); + + void appendMarker(); + // clearToLastMarker also clears the marker (per the HTML5 spec). + void clearToLastMarker(); + + const Entry& at(size_t i) const { return m_entries[i]; } + Entry& at(size_t i) { return m_entries[i]; } + +#ifndef NDEBUG + void show(); +#endif + +private: + Entry* first() { return &at(0); } + + Vector m_entries; +}; + +} + +#endif // HTMLFormattingElementList_h diff --git a/WebCore/html/parser/HTMLParserScheduler.cpp b/WebCore/html/parser/HTMLParserScheduler.cpp new file mode 100644 index 0000000..6e67697 --- /dev/null +++ b/WebCore/html/parser/HTMLParserScheduler.cpp @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2010 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 APPLE 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 APPLE 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" +#include "HTMLParserScheduler.h" + +#include "FrameView.h" // Only for isLayoutTimerActive +#include "HTMLDocumentParser.h" +#include "Document.h" + +// defaultParserChunkSize is used to define how many tokens the parser will +// process before checking against parserTimeLimit and possibly yielding. +// This is a performance optimization to prevent checking after every token. +static const int defaultParserChunkSize = 4096; + +// defaultParserTimeLimit is the seconds the parser will run in one write() call +// before yielding. Inline