/* * Copyright (C) 2010 Google, Inc. All Rights Reserved. * Copyright (C) 2011 Apple 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 SKY_ENGINE_CORE_HTML_PARSER_HTMLCONSTRUCTIONSITE_H_ #define SKY_ENGINE_CORE_HTML_PARSER_HTMLCONSTRUCTIONSITE_H_ #include "sky/engine/core/dom/Document.h" #include "sky/engine/core/html/parser/HTMLElementStack.h" #include "sky/engine/wtf/Noncopyable.h" #include "sky/engine/wtf/PassRefPtr.h" #include "sky/engine/wtf/RefPtr.h" #include "sky/engine/wtf/Vector.h" #include "sky/engine/wtf/text/StringBuilder.h" namespace blink { struct HTMLConstructionSiteTask { ALLOW_ONLY_INLINE_ALLOCATION(); public: enum Operation { Insert, InsertText, // Handles possible merging of text nodes. }; explicit HTMLConstructionSiteTask(Operation op) : operation(op) , selfClosing(false) { } Operation operation; RefPtr parent; RefPtr child; bool selfClosing; }; } // namespace blink WTF_ALLOW_MOVE_INIT_AND_COMPARE_WITH_MEM_FUNCTIONS(blink::HTMLConstructionSiteTask); namespace blink { class AtomicHTMLToken; class Document; class Element; class HTMLConstructionSite final { WTF_MAKE_NONCOPYABLE(HTMLConstructionSite); DISALLOW_ALLOCATION(); public: explicit HTMLConstructionSite(Document*); explicit HTMLConstructionSite(DocumentFragment*); ~HTMLConstructionSite(); void detach(); // executeQueuedTasks empties the queue but does not flush pending text. // NOTE: Possible reentrancy via JavaScript execution. void executeQueuedTasks(); // flushPendingText turns pending text into queued Text insertions, but does not execute them. void flushPendingText(); // Called before every token in HTMLTreeBuilder::processToken, thus inlined: void flush() { if (!hasPendingTasks()) return; flushPendingText(); executeQueuedTasks(); // NOTE: Possible reentrancy via JavaScript execution. ASSERT(!hasPendingTasks()); } bool hasPendingTasks() { return !m_pendingText.isEmpty() || !m_taskQueue.isEmpty(); } void processEndOfFile(); void finishedParsing(); void insertHTMLElement(AtomicHTMLToken*); void insertSelfClosingHTMLElement(AtomicHTMLToken*); void insertScriptElement(AtomicHTMLToken*); void insertTextNode(const String&); bool isEmpty() const { return !m_openElements.stackDepth(); } Element* currentElement() const { return m_openElements.top(); } ContainerNode* currentNode() const { return m_openElements.topNode(); } Document& ownerDocumentForCurrentNode(); HTMLElementStack* openElements() const { return &m_openElements; } private: // In the common case, this queue will have only one task because most // tokens produce only one DOM mutation. typedef Vector TaskQueue; void attachLater(ContainerNode* parent, PassRefPtr child, bool selfClosing = false); PassRefPtr createElement(AtomicHTMLToken*); void queueTask(const HTMLConstructionSiteTask&); RawPtr m_document; // This is the root ContainerNode to which the parser attaches all newly // constructed nodes. It points to a DocumentFragment when parsing fragments // and a Document in all other cases. RawPtr m_attachmentRoot; mutable HTMLElementStack m_openElements; TaskQueue m_taskQueue; class PendingText { DISALLOW_ALLOCATION(); public: PendingText() { } void append(PassRefPtr newParent, const String& newString) { ASSERT(!parent || parent == newParent); parent = newParent; stringBuilder.append(newString); } void swap(PendingText& other) { parent.swap(other.parent); stringBuilder.swap(other.stringBuilder); } void discard() { PendingText discardedText; swap(discardedText); } bool isEmpty() { // When the stringbuilder is empty, the parent should also be "empty". ASSERT(stringBuilder.isEmpty() == !parent); ASSERT(!stringBuilder.isEmpty() || !nextChild); return stringBuilder.isEmpty(); } RefPtr parent; RefPtr nextChild; StringBuilder stringBuilder; }; PendingText m_pendingText; }; } // namespace blink #endif // SKY_ENGINE_CORE_HTML_PARSER_HTMLCONSTRUCTIONSITE_H_