Home | History | Annotate | Download | only in parser
      1 /*
      2  * Copyright (C) 2010 Google, Inc. All Rights Reserved.
      3  * Copyright (C) 2011 Apple Inc. All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  * 1. Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  * 2. Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in the
     12  *    documentation and/or other materials provided with the distribution.
     13  *
     14  * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. ``AS IS'' AND ANY
     15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL GOOGLE INC. OR
     18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     25  */
     26 
     27 #ifndef HTMLConstructionSite_h
     28 #define HTMLConstructionSite_h
     29 
     30 #include "core/dom/ParserContentPolicy.h"
     31 #include "core/html/parser/HTMLElementStack.h"
     32 #include "core/html/parser/HTMLFormattingElementList.h"
     33 #include "wtf/Noncopyable.h"
     34 #include "wtf/PassRefPtr.h"
     35 #include "wtf/RefPtr.h"
     36 #include "wtf/Vector.h"
     37 
     38 namespace WebCore {
     39 
     40 struct HTMLConstructionSiteTask {
     41     enum Operation {
     42         Insert,
     43         InsertAlreadyParsedChild,
     44         Reparent,
     45         TakeAllChildren,
     46     };
     47 
     48     explicit HTMLConstructionSiteTask(Operation op)
     49         : operation(op)
     50         , selfClosing(false)
     51     {
     52     }
     53 
     54     ContainerNode* oldParent()
     55     {
     56         // It's sort of ugly, but we store the |oldParent| in the |child| field
     57         // of the task so that we don't bloat the HTMLConstructionSiteTask
     58         // object in the common case of the Insert operation.
     59         return toContainerNode(child.get());
     60     }
     61 
     62     Operation operation;
     63     RefPtr<ContainerNode> parent;
     64     RefPtr<Node> nextChild;
     65     RefPtr<Node> child;
     66     bool selfClosing;
     67 };
     68 
     69 } // namespace WebCore
     70 
     71 namespace WTF {
     72 template<> struct VectorTraits<WebCore::HTMLConstructionSiteTask> : SimpleClassVectorTraits { };
     73 } // namespace WTF
     74 
     75 namespace WebCore {
     76 
     77 enum WhitespaceMode {
     78     AllWhitespace,
     79     NotAllWhitespace,
     80     WhitespaceUnknown
     81 };
     82 
     83 class AtomicHTMLToken;
     84 class Document;
     85 class Element;
     86 class HTMLFormElement;
     87 
     88 class HTMLConstructionSite {
     89     WTF_MAKE_NONCOPYABLE(HTMLConstructionSite);
     90 public:
     91     HTMLConstructionSite(Document*, ParserContentPolicy);
     92     HTMLConstructionSite(DocumentFragment*, ParserContentPolicy);
     93     ~HTMLConstructionSite();
     94 
     95     void detach();
     96     void executeQueuedTasks();
     97 
     98     void setDefaultCompatibilityMode();
     99     void finishedParsing();
    100 
    101     void insertDoctype(AtomicHTMLToken*);
    102     void insertComment(AtomicHTMLToken*);
    103     void insertCommentOnDocument(AtomicHTMLToken*);
    104     void insertCommentOnHTMLHtmlElement(AtomicHTMLToken*);
    105     void insertHTMLElement(AtomicHTMLToken*);
    106     void insertSelfClosingHTMLElement(AtomicHTMLToken*);
    107     void insertFormattingElement(AtomicHTMLToken*);
    108     void insertHTMLHeadElement(AtomicHTMLToken*);
    109     void insertHTMLBodyElement(AtomicHTMLToken*);
    110     void insertHTMLFormElement(AtomicHTMLToken*, bool isDemoted = false);
    111     void insertScriptElement(AtomicHTMLToken*);
    112     void insertTextNode(const String&, WhitespaceMode = WhitespaceUnknown);
    113     void insertForeignElement(AtomicHTMLToken*, const AtomicString& namespaceURI);
    114 
    115     void insertHTMLHtmlStartTagBeforeHTML(AtomicHTMLToken*);
    116     void insertHTMLHtmlStartTagInBody(AtomicHTMLToken*);
    117     void insertHTMLBodyStartTagInBody(AtomicHTMLToken*);
    118 
    119     void reparent(HTMLElementStack::ElementRecord* newParent, HTMLElementStack::ElementRecord* child);
    120     void reparent(HTMLElementStack::ElementRecord* newParent, HTMLStackItem* child);
    121     // insertAlreadyParsedChild assumes that |child| has already been parsed (i.e., we're just
    122     // moving it around in the tree rather than parsing it for the first time). That means
    123     // this function doesn't call beginParsingChildren / finishParsingChildren.
    124     void insertAlreadyParsedChild(HTMLStackItem* newParent, HTMLElementStack::ElementRecord* child);
    125     void takeAllChildren(HTMLStackItem* newParent, HTMLElementStack::ElementRecord* oldParent);
    126 
    127     PassRefPtr<HTMLStackItem> createElementFromSavedToken(HTMLStackItem*);
    128 
    129     bool shouldFosterParent() const;
    130     void fosterParent(PassRefPtr<Node>);
    131 
    132     bool indexOfFirstUnopenFormattingElement(unsigned& firstUnopenElementIndex) const;
    133     void reconstructTheActiveFormattingElements();
    134 
    135     void generateImpliedEndTags();
    136     void generateImpliedEndTagsWithExclusion(const AtomicString& tagName);
    137 
    138     bool inQuirksMode();
    139 
    140     bool isEmpty() const { return !m_openElements.stackDepth(); }
    141     HTMLElementStack::ElementRecord* currentElementRecord() const { return m_openElements.topRecord(); }
    142     Element* currentElement() const { return m_openElements.top(); }
    143     ContainerNode* currentNode() const { return m_openElements.topNode(); }
    144     HTMLStackItem* currentStackItem() const { return m_openElements.topStackItem(); }
    145     HTMLStackItem* oneBelowTop() const { return m_openElements.oneBelowTop(); }
    146     Document* ownerDocumentForCurrentNode();
    147     HTMLElementStack* openElements() const { return &m_openElements; }
    148     HTMLFormattingElementList* activeFormattingElements() const { return &m_activeFormattingElements; }
    149     bool currentIsRootNode() { return m_openElements.topNode() == m_openElements.rootNode(); }
    150 
    151     Element* head() const { return m_head->element(); }
    152     HTMLStackItem* headStackItem() const { return m_head.get(); }
    153 
    154     void setForm(HTMLFormElement*);
    155     HTMLFormElement* form() const { return m_form.get(); }
    156     PassRefPtr<HTMLFormElement> takeForm();
    157 
    158     ParserContentPolicy parserContentPolicy() { return m_parserContentPolicy; }
    159 
    160     class RedirectToFosterParentGuard {
    161         WTF_MAKE_NONCOPYABLE(RedirectToFosterParentGuard);
    162     public:
    163         RedirectToFosterParentGuard(HTMLConstructionSite& tree)
    164             : m_tree(tree)
    165             , m_wasRedirectingBefore(tree.m_redirectAttachToFosterParent)
    166         {
    167             m_tree.m_redirectAttachToFosterParent = true;
    168         }
    169 
    170         ~RedirectToFosterParentGuard()
    171         {
    172             m_tree.m_redirectAttachToFosterParent = m_wasRedirectingBefore;
    173         }
    174 
    175     private:
    176         HTMLConstructionSite& m_tree;
    177         bool m_wasRedirectingBefore;
    178     };
    179 
    180 private:
    181     // In the common case, this queue will have only one task because most
    182     // tokens produce only one DOM mutation.
    183     typedef Vector<HTMLConstructionSiteTask, 1> TaskQueue;
    184 
    185     void setCompatibilityMode(Document::CompatibilityMode);
    186     void setCompatibilityModeFromDoctype(const String& name, const String& publicId, const String& systemId);
    187 
    188     void attachLater(ContainerNode* parent, PassRefPtr<Node> child, bool selfClosing = false);
    189 
    190     void findFosterSite(HTMLConstructionSiteTask&);
    191 
    192     PassRefPtr<Element> createHTMLElement(AtomicHTMLToken*);
    193     PassRefPtr<Element> createElement(AtomicHTMLToken*, const AtomicString& namespaceURI);
    194 
    195     void mergeAttributesFromTokenIntoElement(AtomicHTMLToken*, Element*);
    196     void dispatchDocumentElementAvailableIfNeeded();
    197 
    198     Document* m_document;
    199 
    200     // This is the root ContainerNode to which the parser attaches all newly
    201     // constructed nodes. It points to a DocumentFragment when parsing fragments
    202     // and a Document in all other cases.
    203     ContainerNode* m_attachmentRoot;
    204 
    205     RefPtr<HTMLStackItem> m_head;
    206     RefPtr<HTMLFormElement> m_form;
    207     mutable HTMLElementStack m_openElements;
    208     mutable HTMLFormattingElementList m_activeFormattingElements;
    209 
    210     TaskQueue m_taskQueue;
    211 
    212     ParserContentPolicy m_parserContentPolicy;
    213     bool m_isParsingFragment;
    214 
    215     // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#parsing-main-intable
    216     // In the "in table" insertion mode, we sometimes get into a state where
    217     // "whenever a node would be inserted into the current node, it must instead
    218     // be foster parented."  This flag tracks whether we're in that state.
    219     bool m_redirectAttachToFosterParent;
    220 
    221     bool m_inQuirksMode;
    222 };
    223 
    224 } // namespace WebCore
    225 
    226 #endif
    227