#ifndef HTMLConstructionSite_h
#define HTMLConstructionSite_h
+#include "core/dom/Document.h"
#include "core/dom/ParserContentPolicy.h"
#include "core/html/parser/HTMLElementStack.h"
#include "core/html/parser/HTMLFormattingElementList.h"
#include "wtf/Vector.h"
#include "wtf/text/StringBuilder.h"
-namespace WebCore {
+namespace blink {
struct HTMLConstructionSiteTask {
+ ALLOW_ONLY_INLINE_ALLOCATION();
+public:
enum Operation {
Insert,
+ InsertText, // Handles possible merging of text nodes.
InsertAlreadyParsedChild, // Insert w/o calling begin/end parsing.
Reparent,
TakeAllChildren,
{
}
+ void trace(Visitor* visitor)
+ {
+ visitor->trace(parent);
+ visitor->trace(nextChild);
+ visitor->trace(child);
+ }
+
ContainerNode* oldParent()
{
// It's sort of ugly, but we store the |oldParent| in the |child| field
}
Operation operation;
- RefPtr<ContainerNode> parent;
- RefPtr<Node> nextChild;
- RefPtr<Node> child;
+ RefPtrWillBeMember<ContainerNode> parent;
+ RefPtrWillBeMember<Node> nextChild;
+ RefPtrWillBeMember<Node> child;
bool selfClosing;
};
-} // namespace WebCore
+} // namespace blink
-namespace WTF {
-template<> struct VectorTraits<WebCore::HTMLConstructionSiteTask> : SimpleClassVectorTraits { };
-} // namespace WTF
+WTF_ALLOW_MOVE_INIT_AND_COMPARE_WITH_MEM_FUNCTIONS(blink::HTMLConstructionSiteTask);
-namespace WebCore {
+namespace blink {
// Note: These are intentionally ordered so that when we concatonate
// strings and whitespaces the resulting whitespace is ws = min(ws1, ws2).
class Element;
class HTMLFormElement;
-class HTMLConstructionSite {
+class HTMLConstructionSite FINAL {
WTF_MAKE_NONCOPYABLE(HTMLConstructionSite);
+ DISALLOW_ALLOCATION();
public:
HTMLConstructionSite(Document*, ParserContentPolicy);
HTMLConstructionSite(DocumentFragment*, ParserContentPolicy);
~HTMLConstructionSite();
+ void trace(Visitor*);
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 setDefaultCompatibilityMode();
void processEndOfFile();
void finishedParsing();
void insertAlreadyParsedChild(HTMLStackItem* newParent, HTMLElementStack::ElementRecord* child);
void takeAllChildren(HTMLStackItem* newParent, HTMLElementStack::ElementRecord* oldParent);
- PassRefPtr<HTMLStackItem> createElementFromSavedToken(HTMLStackItem*);
+ PassRefPtrWillBeRawPtr<HTMLStackItem> createElementFromSavedToken(HTMLStackItem*);
bool shouldFosterParent() const;
- void fosterParent(PassRefPtr<Node>);
+ void fosterParent(PassRefPtrWillBeRawPtr<Node>);
bool indexOfFirstUnopenFormattingElement(unsigned& firstUnopenElementIndex) const;
void reconstructTheActiveFormattingElements();
void setForm(HTMLFormElement*);
HTMLFormElement* form() const { return m_form.get(); }
- PassRefPtr<HTMLFormElement> takeForm();
+ PassRefPtrWillBeRawPtr<HTMLFormElement> takeForm();
ParserContentPolicy parserContentPolicy() { return m_parserContentPolicy; }
private:
// In the common case, this queue will have only one task because most
// tokens produce only one DOM mutation.
- typedef Vector<HTMLConstructionSiteTask, 1> TaskQueue;
+ typedef WillBeHeapVector<HTMLConstructionSiteTask, 1> TaskQueue;
void setCompatibilityMode(Document::CompatibilityMode);
void setCompatibilityModeFromDoctype(const String& name, const String& publicId, const String& systemId);
- void attachLater(ContainerNode* parent, PassRefPtr<Node> child, bool selfClosing = false);
+ void attachLater(ContainerNode* parent, PassRefPtrWillBeRawPtr<Node> child, bool selfClosing = false);
void findFosterSite(HTMLConstructionSiteTask&);
- PassRefPtr<Element> createHTMLElement(AtomicHTMLToken*);
- PassRefPtr<Element> createElement(AtomicHTMLToken*, const AtomicString& namespaceURI);
+ PassRefPtrWillBeRawPtr<HTMLElement> createHTMLElement(AtomicHTMLToken*);
+ PassRefPtrWillBeRawPtr<Element> createElement(AtomicHTMLToken*, const AtomicString& namespaceURI);
void mergeAttributesFromTokenIntoElement(AtomicHTMLToken*, Element*);
void dispatchDocumentElementAvailableIfNeeded();
void executeTask(HTMLConstructionSiteTask&);
void queueTask(const HTMLConstructionSiteTask&);
- Document* m_document;
+ RawPtrWillBeMember<Document> 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.
- ContainerNode* m_attachmentRoot;
+ RawPtrWillBeMember<ContainerNode> m_attachmentRoot;
- RefPtr<HTMLStackItem> m_head;
- RefPtr<HTMLFormElement> m_form;
+ RefPtrWillBeMember<HTMLStackItem> m_head;
+ RefPtrWillBeMember<HTMLFormElement> m_form;
mutable HTMLElementStack m_openElements;
mutable HTMLFormattingElementList m_activeFormattingElements;
TaskQueue m_taskQueue;
+ class PendingText FINAL {
+ DISALLOW_ALLOCATION();
+ public:
+ PendingText()
+ : whitespaceMode(WhitespaceUnknown)
+ {
+ }
+
+ void append(PassRefPtrWillBeRawPtr<ContainerNode> newParent, PassRefPtrWillBeRawPtr<Node> newNextChild, const String& newString, WhitespaceMode newWhitespaceMode)
+ {
+ ASSERT(!parent || parent == newParent);
+ parent = newParent;
+ ASSERT(!nextChild || nextChild == newNextChild);
+ nextChild = newNextChild;
+ stringBuilder.append(newString);
+ whitespaceMode = std::min(whitespaceMode, newWhitespaceMode);
+ }
+
+ void swap(PendingText& other)
+ {
+ std::swap(whitespaceMode, other.whitespaceMode);
+ parent.swap(other.parent);
+ nextChild.swap(other.nextChild);
+ stringBuilder.swap(other.stringBuilder);
+ }
+
+ void discard()
+ {
+ PendingText discardedText;
+ swap(discardedText);
+ }
+
+ bool isEmpty()
+ {
+ // When the stringbuilder is empty, the parent and whitespace should also be "empty".
+ ASSERT(stringBuilder.isEmpty() == !parent);
+ ASSERT(!stringBuilder.isEmpty() || !nextChild);
+ ASSERT(!stringBuilder.isEmpty() || (whitespaceMode == WhitespaceUnknown));
+ return stringBuilder.isEmpty();
+ }
+
+ void trace(Visitor*);
+
+ RefPtrWillBeMember<ContainerNode> parent;
+ RefPtrWillBeMember<Node> nextChild;
+ StringBuilder stringBuilder;
+ WhitespaceMode whitespaceMode;
+ };
+
+ PendingText m_pendingText;
+
ParserContentPolicy m_parserContentPolicy;
bool m_isParsingFragment;
bool m_inQuirksMode;
};
-} // namespace WebCore
+} // namespace blink
#endif