Merge from Chromium at DEPS revision r219274

This commit was generated by merge_to_master.py.

Change-Id: I4217737c165f68da34d720aa074431613911dc68
diff --git a/Source/core/dom/Attr.h b/Source/core/dom/Attr.h
index 3673be2..21b3685 100644
--- a/Source/core/dom/Attr.h
+++ b/Source/core/dom/Attr.h
@@ -63,6 +63,12 @@
     void attachToElement(Element*);
     void detachFromElementWithValue(const AtomicString&);
 
+    virtual const AtomicString& localName() const OVERRIDE { return m_name.localName(); }
+    virtual const AtomicString& namespaceURI() const OVERRIDE { return m_name.namespaceURI(); }
+    virtual const AtomicString& prefix() const OVERRIDE { return m_name.prefix(); }
+
+    virtual void setPrefix(const AtomicString&, ExceptionState&) OVERRIDE;
+
 private:
     Attr(Element*, const QualifiedName&);
     Attr(Document*, const QualifiedName&, const AtomicString& value);
@@ -72,12 +78,6 @@
     virtual String nodeName() const OVERRIDE { return name(); }
     virtual NodeType nodeType() const OVERRIDE { return ATTRIBUTE_NODE; }
 
-    virtual const AtomicString& localName() const OVERRIDE { return m_name.localName(); }
-    virtual const AtomicString& namespaceURI() const OVERRIDE { return m_name.namespaceURI(); }
-    virtual const AtomicString& prefix() const OVERRIDE { return m_name.prefix(); }
-
-    virtual void setPrefix(const AtomicString&, ExceptionState&);
-
     virtual String nodeValue() const OVERRIDE { return value(); }
     virtual void setNodeValue(const String&);
     virtual PassRefPtr<Node> cloneNode(bool deep = true);
diff --git a/Source/core/dom/Attr.idl b/Source/core/dom/Attr.idl
index 97c7c46..0dcdb02 100644
--- a/Source/core/dom/Attr.idl
+++ b/Source/core/dom/Attr.idl
@@ -35,5 +35,11 @@
     // DOM Level 3
 
     readonly attribute boolean isId;
+
+    // DOM 4
+
+    [TreatReturnedNullStringAs=Null, TreatNullAs=NullString, PerWorldBindings, SetterRaisesException] attribute DOMString prefix;
+    [TreatReturnedNullStringAs=Null, PerWorldBindings] readonly attribute DOMString namespaceURI;
+    [TreatReturnedNullStringAs=Null, PerWorldBindings] readonly attribute DOMString localName;
 };
 
diff --git a/Source/core/dom/CharacterData.cpp b/Source/core/dom/CharacterData.cpp
index 7221496..50b44c3 100644
--- a/Source/core/dom/CharacterData.cpp
+++ b/Source/core/dom/CharacterData.cpp
@@ -29,6 +29,7 @@
 #include "core/dom/MutationEvent.h"
 #include "core/dom/MutationObserverInterestGroup.h"
 #include "core/dom/MutationRecord.h"
+#include "core/dom/ProcessingInstruction.h"
 #include "core/dom/Text.h"
 #include "core/editing/FrameSelection.h"
 #include "core/inspector/InspectorInstrumentation.h"
@@ -97,7 +98,7 @@
 
     ASSERT(!renderer() || isTextNode());
     if (isTextNode())
-        toText(this)->updateTextRenderer(oldLength, 0);
+        toText(this)->updateTextRenderer(oldLength, 0, DeprecatedAttachNow);
 
     document()->incDOMTreeVersion();
 
@@ -107,16 +108,16 @@
     return characterLengthLimit;
 }
 
-void CharacterData::appendData(const String& data)
+void CharacterData::appendData(const String& data, AttachBehavior attachBehavior)
 {
     String newStr = m_data + data;
 
-    setDataAndUpdate(newStr, m_data.length(), 0, data.length());
+    setDataAndUpdate(newStr, m_data.length(), 0, data.length(), attachBehavior);
 
     // FIXME: Should we call textInserted here?
 }
 
-void CharacterData::insertData(unsigned offset, const String& data, ExceptionState& es)
+void CharacterData::insertData(unsigned offset, const String& data, ExceptionState& es, AttachBehavior attachBehavior)
 {
     if (offset > length()) {
         es.throwDOMException(IndexSizeError);
@@ -126,12 +127,12 @@
     String newStr = m_data;
     newStr.insert(data, offset);
 
-    setDataAndUpdate(newStr, offset, 0, data.length());
+    setDataAndUpdate(newStr, offset, 0, data.length(), attachBehavior);
 
     document()->textInserted(this, offset, data.length());
 }
 
-void CharacterData::deleteData(unsigned offset, unsigned count, ExceptionState& es)
+void CharacterData::deleteData(unsigned offset, unsigned count, ExceptionState& es, AttachBehavior attachBehavior)
 {
     if (offset > length()) {
         es.throwDOMException(IndexSizeError);
@@ -147,12 +148,12 @@
     String newStr = m_data;
     newStr.remove(offset, realCount);
 
-    setDataAndUpdate(newStr, offset, count, 0);
+    setDataAndUpdate(newStr, offset, count, 0, attachBehavior);
 
     document()->textRemoved(this, offset, realCount);
 }
 
-void CharacterData::replaceData(unsigned offset, unsigned count, const String& data, ExceptionState& es)
+void CharacterData::replaceData(unsigned offset, unsigned count, const String& data, ExceptionState& es, AttachBehavior attachBehavior)
 {
     if (offset > length()) {
         es.throwDOMException(IndexSizeError);
@@ -169,7 +170,7 @@
     newStr.remove(offset, realCount);
     newStr.insert(data, offset);
 
-    setDataAndUpdate(newStr, offset, count, data.length());
+    setDataAndUpdate(newStr, offset, count, data.length(), attachBehavior);
 
     // update the markers for spell checking and grammar checking
     document()->textRemoved(this, offset, realCount);
@@ -191,14 +192,17 @@
     setData(nodeValue);
 }
 
-void CharacterData::setDataAndUpdate(const String& newData, unsigned offsetOfReplacedData, unsigned oldLength, unsigned newLength)
+void CharacterData::setDataAndUpdate(const String& newData, unsigned offsetOfReplacedData, unsigned oldLength, unsigned newLength, AttachBehavior attachBehavior)
 {
     String oldData = m_data;
     m_data = newData;
 
     ASSERT(!renderer() || isTextNode());
     if (isTextNode())
-        toText(this)->updateTextRenderer(offsetOfReplacedData, oldLength);
+        toText(this)->updateTextRenderer(offsetOfReplacedData, oldLength, attachBehavior);
+
+    if (nodeType() == PROCESSING_INSTRUCTION_NODE)
+        toProcessingInstruction(this)->checkStyleSheet();
 
     if (document()->frame())
         document()->frame()->selection()->textWasReplaced(this, offsetOfReplacedData, oldLength, newLength);
diff --git a/Source/core/dom/CharacterData.h b/Source/core/dom/CharacterData.h
index 8077364..473456e 100644
--- a/Source/core/dom/CharacterData.h
+++ b/Source/core/dom/CharacterData.h
@@ -37,10 +37,10 @@
     void setData(const String&);
     unsigned length() const { return m_data.length(); }
     String substringData(unsigned offset, unsigned count, ExceptionState&);
-    void appendData(const String&);
-    void insertData(unsigned offset, const String&, ExceptionState&);
-    void deleteData(unsigned offset, unsigned count, ExceptionState&);
-    void replaceData(unsigned offset, unsigned count, const String&, ExceptionState&);
+    void appendData(const String&, AttachBehavior = AttachLazily);
+    void insertData(unsigned offset, const String&, ExceptionState&, AttachBehavior = AttachLazily);
+    void deleteData(unsigned offset, unsigned count, ExceptionState&, AttachBehavior = AttachLazily);
+    void replaceData(unsigned offset, unsigned count, const String&, ExceptionState&, AttachBehavior = AttachLazily);
 
     bool containsOnlyWhitespace() const;
 
@@ -66,15 +66,15 @@
     }
     void didModifyData(const String& oldValue);
 
+    String m_data;
+
 private:
     virtual String nodeValue() const OVERRIDE FINAL;
     virtual void setNodeValue(const String&) OVERRIDE FINAL;
     virtual bool isCharacterDataNode() const OVERRIDE FINAL { return true; }
     virtual int maxCharacterOffset() const OVERRIDE FINAL;
     virtual bool offsetInCharacters() const OVERRIDE FINAL;
-    void setDataAndUpdate(const String&, unsigned offsetOfReplacedData, unsigned oldLength, unsigned newLength);
-
-    String m_data;
+    void setDataAndUpdate(const String&, unsigned offsetOfReplacedData, unsigned oldLength, unsigned newLength, AttachBehavior = AttachLazily);
 };
 
 } // namespace WebCore
diff --git a/Source/core/dom/Clipboard.cpp b/Source/core/dom/Clipboard.cpp
index 0c7f725..ee98d9f 100644
--- a/Source/core/dom/Clipboard.cpp
+++ b/Source/core/dom/Clipboard.cpp
@@ -26,8 +26,8 @@
 #include "config.h"
 #include "core/dom/Clipboard.h"
 
+#include "core/fetch/ImageResource.h"
 #include "core/fileapi/FileList.h"
-#include "core/loader/cache/ImageResource.h"
 
 namespace WebCore {
 
diff --git a/Source/core/dom/Clipboard.h b/Source/core/dom/Clipboard.h
index a32134b..bc861de 100644
--- a/Source/core/dom/Clipboard.h
+++ b/Source/core/dom/Clipboard.h
@@ -27,7 +27,7 @@
 #include "bindings/v8/ScriptWrappable.h"
 #include "core/dom/ClipboardAccessPolicy.h"
 #include "core/dom/Node.h"
-#include "core/loader/cache/ResourcePtr.h"
+#include "core/fetch/ResourcePtr.h"
 #include "core/page/DragActions.h"
 #include "core/platform/DragImage.h"
 #include "core/platform/graphics/IntPoint.h"
diff --git a/Source/core/dom/ContainerNode.cpp b/Source/core/dom/ContainerNode.cpp
index 1b26b71..c184a5e 100644
--- a/Source/core/dom/ContainerNode.cpp
+++ b/Source/core/dom/ContainerNode.cpp
@@ -27,6 +27,7 @@
 #include "bindings/v8/ExceptionStatePlaceholder.h"
 #include "core/dom/ChildListMutationScope.h"
 #include "core/dom/ContainerNodeAlgorithms.h"
+#include "core/dom/ElementTraversal.h"
 #include "core/dom/EventNames.h"
 #include "core/dom/ExceptionCode.h"
 #include "core/dom/FullscreenElementStack.h"
@@ -173,10 +174,6 @@
         return false;
     }
 
-    if (newChild->inDocument() && newChild->isDocumentTypeNode()) {
-        es.throwDOMException(HierarchyRequestError);
-        return false;
-    }
     if (containsConsideringHostElements(newChild, newParent)) {
         es.throwDOMException(HierarchyRequestError);
         return false;
diff --git a/Source/core/dom/ContainerNode.h b/Source/core/dom/ContainerNode.h
index 86f37de..f795436 100644
--- a/Source/core/dom/ContainerNode.h
+++ b/Source/core/dom/ContainerNode.h
@@ -87,6 +87,9 @@
     Node* lastChild() const { return m_lastChild; }
     bool hasChildNodes() const { return m_firstChild; }
 
+    bool hasOneChild() const { return m_firstChild && !m_firstChild->nextSibling(); }
+    bool hasOneTextChild() const { return hasOneChild() && m_firstChild->isTextNode(); }
+
     // ParentNode interface API
     PassRefPtr<HTMLCollection> children();
     Element* firstElementChild() const;
@@ -96,10 +99,10 @@
     unsigned childNodeCount() const;
     Node* childNode(unsigned index) const;
 
-    void insertBefore(PassRefPtr<Node> newChild, Node* refChild, ExceptionState& = ASSERT_NO_EXCEPTION, AttachBehavior = AttachNow);
-    void replaceChild(PassRefPtr<Node> newChild, Node* oldChild, ExceptionState& = ASSERT_NO_EXCEPTION, AttachBehavior = AttachNow);
+    void insertBefore(PassRefPtr<Node> newChild, Node* refChild, ExceptionState& = ASSERT_NO_EXCEPTION, AttachBehavior = AttachLazily);
+    void replaceChild(PassRefPtr<Node> newChild, Node* oldChild, ExceptionState& = ASSERT_NO_EXCEPTION, AttachBehavior = AttachLazily);
     void removeChild(Node* child, ExceptionState& = ASSERT_NO_EXCEPTION);
-    void appendChild(PassRefPtr<Node> newChild, ExceptionState& = ASSERT_NO_EXCEPTION, AttachBehavior = AttachNow);
+    void appendChild(PassRefPtr<Node> newChild, ExceptionState& = ASSERT_NO_EXCEPTION, AttachBehavior = AttachLazily);
 
     // These methods are only used during parsing.
     // They don't send DOM mutation events or handle reparenting.
diff --git a/Source/core/dom/ContainerNodeAlgorithms.cpp b/Source/core/dom/ContainerNodeAlgorithms.cpp
index 59d65ed..9f4eeac 100644
--- a/Source/core/dom/ContainerNodeAlgorithms.cpp
+++ b/Source/core/dom/ContainerNodeAlgorithms.cpp
@@ -28,10 +28,20 @@
 
 #include "core/dom/Element.h"
 #include "core/dom/shadow/ElementShadow.h"
+#include "core/dom/shadow/ShadowRoot.h"
 #include "core/html/HTMLFrameOwnerElement.h"
 
 namespace WebCore {
 
+class ShadowRootVector : public Vector<RefPtr<ShadowRoot> > {
+public:
+    explicit ShadowRootVector(ElementShadow* tree)
+    {
+        for (ShadowRoot* root = tree->youngestShadowRoot(); root; root = root->olderShadowRoot())
+            append(root);
+    }
+};
+
 void ChildNodeInsertionNotifier::notifyDescendantInsertedIntoDocument(ContainerNode* node)
 {
     ChildNodesLazySnapshot snapshot(node);
@@ -121,7 +131,7 @@
     unsigned count = 0;
 
     if (node->isElementNode()) {
-        if (node->isFrameOwnerElement() && toFrameOwnerElement(node)->contentFrame())
+        if (node->isFrameOwnerElement() && toHTMLFrameOwnerElement(node)->contentFrame())
             count++;
 
         if (ElementShadow* shadow = toElement(node)->shadow()) {
diff --git a/Source/core/dom/ContainerNodeAlgorithms.h b/Source/core/dom/ContainerNodeAlgorithms.h
index f02eb7f..ebd5263 100644
--- a/Source/core/dom/ContainerNodeAlgorithms.h
+++ b/Source/core/dom/ContainerNodeAlgorithms.h
@@ -23,7 +23,6 @@
 #define ContainerNodeAlgorithms_h
 
 #include "core/dom/Document.h"
-#include "core/dom/NodeTraversal.h"
 #include "core/html/HTMLFrameOwnerElement.h"
 #include "core/inspector/InspectorInstrumentation.h"
 #include "wtf/Assertions.h"
@@ -289,7 +288,7 @@
         return;
 
     if (root->isHTMLElement() && root->isFrameOwnerElement())
-        m_frameOwners.append(toFrameOwnerElement(root));
+        m_frameOwners.append(toHTMLFrameOwnerElement(root));
 
     for (Node* child = root->firstChild(); child; child = child->nextSibling())
         collectFrameOwners(child);
diff --git a/Source/core/dom/CustomElement.cpp b/Source/core/dom/CustomElement.cpp
index 6ffcd2a..0529882 100644
--- a/Source/core/dom/CustomElement.cpp
+++ b/Source/core/dom/CustomElement.cpp
@@ -33,78 +33,103 @@
 
 #include "HTMLNames.h"
 #include "MathMLNames.h"
+#include "RuntimeEnabledFeatures.h"
 #include "SVGNames.h"
 #include "core/dom/CustomElementCallbackScheduler.h"
-#include "core/dom/CustomElementUpgradeCandidateMap.h"
+#include "core/dom/CustomElementObserver.h"
 #include "core/dom/Element.h"
 
 namespace WebCore {
 
-Vector<AtomicString>& CustomElement::allowedCustomTagNames()
+Vector<AtomicString>& CustomElement::embedderCustomElementNames()
 {
-    DEFINE_STATIC_LOCAL(Vector<AtomicString>, tagNames, ());
-    return tagNames;
+    DEFINE_STATIC_LOCAL(Vector<AtomicString>, names, ());
+    return names;
 }
 
-void CustomElement::allowTagName(const AtomicString& localName)
+void CustomElement::addEmbedderCustomElementName(const AtomicString& name)
 {
-    AtomicString lower = localName.lower();
-    if (isCustomTagName(lower))
+    AtomicString lower = name.lower();
+    if (isValidName(lower, EmbedderNames))
         return;
-    allowedCustomTagNames().append(lower);
+    embedderCustomElementNames().append(lower);
 }
 
-bool CustomElement::isValidTypeName(const AtomicString& name)
+static CustomElement::NameSet enabledNameSet()
 {
-    if (notFound != allowedCustomTagNames().find(name))
-        return true;
+    return CustomElement::NameSet((RuntimeEnabledFeatures::customElementsEnabled() ? CustomElement::StandardNames : 0) | (RuntimeEnabledFeatures::embedderCustomElementsEnabled() ? CustomElement::EmbedderNames : 0));
+}
 
-    if (allowedCustomTagNames().size() > 0)
-        return false;
+bool CustomElement::isValidName(const AtomicString& name, NameSet validNames)
+{
+    validNames = NameSet(validNames & enabledNameSet());
 
-    if (notFound == name.find('-'))
-        return false;
+    if ((validNames & EmbedderNames) && notFound != embedderCustomElementNames().find(name))
+        return Document::isValidName(name);
 
-    DEFINE_STATIC_LOCAL(Vector<AtomicString>, reservedNames, ());
-    if (reservedNames.isEmpty()) {
-        reservedNames.append(MathMLNames::annotation_xmlTag.localName());
-        reservedNames.append(SVGNames::color_profileTag.localName());
-        reservedNames.append(SVGNames::font_faceTag.localName());
-        reservedNames.append(SVGNames::font_face_srcTag.localName());
-        reservedNames.append(SVGNames::font_face_uriTag.localName());
-        reservedNames.append(SVGNames::font_face_formatTag.localName());
-        reservedNames.append(SVGNames::font_face_nameTag.localName());
-        reservedNames.append(SVGNames::missing_glyphTag.localName());
+    if ((validNames & StandardNames) && notFound != name.find('-')) {
+        DEFINE_STATIC_LOCAL(Vector<AtomicString>, reservedNames, ());
+        if (reservedNames.isEmpty()) {
+            reservedNames.append(MathMLNames::annotation_xmlTag.localName());
+            reservedNames.append(SVGNames::color_profileTag.localName());
+            reservedNames.append(SVGNames::font_faceTag.localName());
+            reservedNames.append(SVGNames::font_face_srcTag.localName());
+            reservedNames.append(SVGNames::font_face_uriTag.localName());
+            reservedNames.append(SVGNames::font_face_formatTag.localName());
+            reservedNames.append(SVGNames::font_face_nameTag.localName());
+            reservedNames.append(SVGNames::missing_glyphTag.localName());
+        }
+
+        if (notFound == reservedNames.find(name))
+            return Document::isValidName(name.string());
     }
 
-    if (notFound != reservedNames.find(name))
-        return false;
-
-    return Document::isValidName(name.string());
-}
-
-bool CustomElement::isCustomTagName(const AtomicString& localName)
-{
-    return isValidTypeName(localName);
+    return false;
 }
 
 void CustomElement::define(Element* element, PassRefPtr<CustomElementDefinition> passDefinition)
 {
     RefPtr<CustomElementDefinition> definition(passDefinition);
-    element->setCustomElementState(Element::Defined);
-    definitions().add(element, definition);
-    CustomElementCallbackScheduler::scheduleCreatedCallback(definition->callbacks(), element);
+
+    switch (element->customElementState()) {
+    case Element::NotCustomElement:
+    case Element::Upgraded:
+        ASSERT_NOT_REACHED();
+        break;
+
+    case Element::WaitingForParser:
+        definitions().add(element, definition);
+        break;
+
+    case Element::WaitingForUpgrade:
+        definitions().add(element, definition);
+        CustomElementCallbackScheduler::scheduleCreatedCallback(definition->callbacks(), element);
+        break;
+    }
 }
 
 CustomElementDefinition* CustomElement::definitionFor(Element* element)
 {
-    return definitions().get(element);
+    CustomElementDefinition* definition = definitions().get(element);
+    ASSERT(definition);
+    return definition;
+}
+
+void CustomElement::didFinishParsingChildren(Element* element)
+{
+    ASSERT(element->customElementState() == Element::WaitingForParser);
+    element->setCustomElementState(Element::WaitingForUpgrade);
+
+    CustomElementObserver::notifyElementDidFinishParsingChildren(element);
+
+    if (CustomElementDefinition* definition = definitions().get(element))
+        CustomElementCallbackScheduler::scheduleCreatedCallback(definition->callbacks(), element);
 }
 
 void CustomElement::attributeDidChange(Element* element, const AtomicString& name, const AtomicString& oldValue, const AtomicString& newValue)
 {
     ASSERT(element->customElementState() == Element::Upgraded);
-    CustomElementCallbackScheduler::scheduleAttributeChangedCallback(definitions().get(element)->callbacks(), element, name, oldValue, newValue);
+    CustomElementCallbackScheduler::scheduleAttributeChangedCallback(definitionFor(element)->callbacks(), element, name, oldValue, newValue);
 }
 
 void CustomElement::didEnterDocument(Element* element, Document* document)
@@ -112,7 +137,7 @@
     ASSERT(element->customElementState() == Element::Upgraded);
     if (!document->defaultView())
         return;
-    CustomElementCallbackScheduler::scheduleEnteredDocumentCallback(definitions().get(element)->callbacks(), element);
+    CustomElementCallbackScheduler::scheduleEnteredDocumentCallback(definitionFor(element)->callbacks(), element);
 }
 
 void CustomElement::didLeaveDocument(Element* element, Document* document)
@@ -120,7 +145,7 @@
     ASSERT(element->customElementState() == Element::Upgraded);
     if (!document->defaultView())
         return;
-    CustomElementCallbackScheduler::scheduleLeftDocumentCallback(definitions().get(element)->callbacks(), element);
+    CustomElementCallbackScheduler::scheduleLeftDocumentCallback(definitionFor(element)->callbacks(), element);
 }
 
 void CustomElement::wasDestroyed(Element* element)
@@ -130,13 +155,11 @@
         ASSERT_NOT_REACHED();
         break;
 
-    case Element::UpgradeCandidate:
-        CustomElementUpgradeCandidateMap::elementWasDestroyed(element);
-        break;
-
-    case Element::Defined:
+    case Element::WaitingForParser:
+    case Element::WaitingForUpgrade:
     case Element::Upgraded:
         definitions().remove(element);
+        CustomElementObserver::notifyElementWasDestroyed(element);
         break;
     }
 }
@@ -148,18 +171,6 @@
     ASSERT(result.isNewEntry);
 }
 
-void CustomElement::DefinitionMap::remove(Element* element)
-{
-    m_definitions.remove(element);
-}
-
-CustomElementDefinition* CustomElement::DefinitionMap::get(Element* element)
-{
-    DefinitionMap::ElementDefinitionHashMap::const_iterator it = m_definitions.find(element);
-    ASSERT(it != m_definitions.end());
-    return it->value.get();
-}
-
 CustomElement::DefinitionMap& CustomElement::definitions()
 {
     DEFINE_STATIC_LOCAL(DefinitionMap, map, ());
diff --git a/Source/core/dom/CustomElement.h b/Source/core/dom/CustomElement.h
index 4fc4b57..07ba3c0 100644
--- a/Source/core/dom/CustomElement.h
+++ b/Source/core/dom/CustomElement.h
@@ -46,13 +46,13 @@
 
 class CustomElement {
 public:
-    // FIXME: CustomElementRegistry requires isValidTypeName to be a
-    // superset of isCustomTagName; consider either merging these or
-    // separating them completely into
-    // isCustomTagName/isTypeExtensionName.
-    static bool isValidTypeName(const AtomicString& type);
-    static bool isCustomTagName(const AtomicString& localName);
-    static void allowTagName(const AtomicString& localName);
+    enum NameSet {
+        EmbedderNames = 1 << 0,
+        StandardNames = 1 << 1,
+        AllNames = EmbedderNames | StandardNames
+    };
+    static bool isValidName(const AtomicString& name, NameSet validNames = AllNames);
+    static void addEmbedderCustomElementName(const AtomicString& name);
 
     // API for registration contexts
     static void define(Element*, PassRefPtr<CustomElementDefinition>);
@@ -62,6 +62,7 @@
 
     // API for Element to kick off changes
 
+    static void didFinishParsingChildren(Element*);
     static void attributeDidChange(Element*, const AtomicString& name, const AtomicString& oldValue, const AtomicString& newValue);
     static void didEnterDocument(Element*, Document*);
     static void didLeaveDocument(Element*, Document*);
@@ -70,7 +71,7 @@
 private:
     CustomElement();
 
-    static Vector<AtomicString>& allowedCustomTagNames();
+    static Vector<AtomicString>& embedderCustomElementNames();
 
     // Maps resolved elements to their definitions
 
@@ -81,8 +82,8 @@
         ~DefinitionMap() { }
 
         void add(Element*, PassRefPtr<CustomElementDefinition>);
-        void remove(Element*);
-        CustomElementDefinition* get(Element*);
+        void remove(Element* element) { m_definitions.remove(element); }
+        CustomElementDefinition* get(Element* element) const { return m_definitions.get(element); }
 
     private:
         typedef HashMap<Element*, RefPtr<CustomElementDefinition> > ElementDefinitionHashMap;
diff --git a/Source/core/dom/CustomElementCallbackDispatcher.cpp b/Source/core/dom/CustomElementCallbackDispatcher.cpp
index 405d7cf..41d5ecf 100644
--- a/Source/core/dom/CustomElementCallbackDispatcher.cpp
+++ b/Source/core/dom/CustomElementCallbackDispatcher.cpp
@@ -113,14 +113,6 @@
     }
 }
 
-CustomElementCallbackQueue* CustomElementCallbackDispatcher::createCallbackQueue(PassRefPtr<Element> element)
-{
-    Element* key = element.get();
-    ElementCallbackQueueMap::AddResult result = m_elementCallbackQueueMap.add(key, CustomElementCallbackQueue::create(element));
-    ASSERT(result.isNewEntry);
-    return result.iterator->value.get();
-}
-
 CustomElementCallbackQueue* CustomElementCallbackDispatcher::ensureCallbackQueue(PassRefPtr<Element> element)
 {
     Element* key = element.get();
@@ -130,34 +122,38 @@
     return it->value.get();
 }
 
+// Finds or creates the callback queue for element. If the
+// createdCallback has not finished running, the callback queue is not
+// moved to the top-of-stack. Otherwise like
+// scheduleInCurrentElementQueue.
+CustomElementCallbackQueue* CustomElementCallbackDispatcher::schedule(PassRefPtr<Element> element)
+{
+    CustomElementCallbackQueue* callbackQueue = ensureCallbackQueue(element);
+    if (!callbackQueue->inCreatedCallback())
+        ensureInCurrentElementQueue(callbackQueue);
+    return callbackQueue;
+}
+
 // Finds or creates the callback queue for element. If the element's
 // callback queue is scheduled in an earlier processing stack frame,
 // its owner is set to the element queue on the top of the processing
 // stack. Because callback queues are processed exhaustively, this
 // effectively moves the callback queue to the top of the stack.
-CustomElementCallbackQueue* CustomElementCallbackDispatcher::ensureInCurrentElementQueue(PassRefPtr<Element> element)
+CustomElementCallbackQueue* CustomElementCallbackDispatcher::scheduleInCurrentElementQueue(PassRefPtr<Element> element)
 {
-    CustomElementCallbackQueue* queue = ensureCallbackQueue(element);
-    bool isInCurrentQueue = queue->owner() == currentElementQueue();
-    if (!isInCurrentQueue) {
-        queue->setOwner(currentElementQueue());
-        m_flattenedProcessingStack.append(queue);
-        ++s_elementQueueEnd;
-    }
-    return queue;
+    CustomElementCallbackQueue* callbackQueue = ensureCallbackQueue(element);
+    ensureInCurrentElementQueue(callbackQueue);
+    return callbackQueue;
 }
 
-CustomElementCallbackQueue* CustomElementCallbackDispatcher::createAtFrontOfCurrentElementQueue(PassRefPtr<Element> element)
+void CustomElementCallbackDispatcher::ensureInCurrentElementQueue(CustomElementCallbackQueue* callbackQueue)
 {
-    CustomElementCallbackQueue* queue = createCallbackQueue(element);
-    queue->setOwner(currentElementQueue());
+    if (callbackQueue->owner() == currentElementQueue())
+        return;
 
-    // The created callback is unique in being prepended to the front
-    // of the element queue
-    m_flattenedProcessingStack.insert(inCallbackDeliveryScope() ? s_elementQueueStart : kNumSentinels, queue);
+    callbackQueue->setOwner(currentElementQueue());
+    m_flattenedProcessingStack.append(callbackQueue);
     ++s_elementQueueEnd;
-
-    return queue;
 }
 
 } // namespace WebCore
diff --git a/Source/core/dom/CustomElementCallbackDispatcher.h b/Source/core/dom/CustomElementCallbackDispatcher.h
index 74c0ae7..f26ec9b 100644
--- a/Source/core/dom/CustomElementCallbackDispatcher.h
+++ b/Source/core/dom/CustomElementCallbackDispatcher.h
@@ -73,8 +73,8 @@
 protected:
     friend class CustomElementCallbackScheduler;
 
-    CustomElementCallbackQueue* createAtFrontOfCurrentElementQueue(PassRefPtr<Element>);
-    CustomElementCallbackQueue* ensureInCurrentElementQueue(PassRefPtr<Element>);
+    CustomElementCallbackQueue* schedule(PassRefPtr<Element>);
+    CustomElementCallbackQueue* scheduleInCurrentElementQueue(PassRefPtr<Element>);
 
 private:
     CustomElementCallbackDispatcher()
@@ -106,8 +106,8 @@
     static void processElementQueueAndPop();
     void processElementQueueAndPop(size_t start, size_t end);
 
-    CustomElementCallbackQueue* createCallbackQueue(PassRefPtr<Element>);
     CustomElementCallbackQueue* ensureCallbackQueue(PassRefPtr<Element>);
+    void ensureInCurrentElementQueue(CustomElementCallbackQueue*);
 
     // The processing stack, flattened. Element queues lower in the
     // stack appear toward the head of the vector. The first element
diff --git a/Source/core/dom/CustomElementCallbackInvocation.cpp b/Source/core/dom/CustomElementCallbackInvocation.cpp
index 82e50e1..4974dc0 100644
--- a/Source/core/dom/CustomElementCallbackInvocation.cpp
+++ b/Source/core/dom/CustomElementCallbackInvocation.cpp
@@ -45,6 +45,7 @@
 
 private:
     virtual void dispatch(Element*) OVERRIDE;
+    virtual bool isCreated() const OVERRIDE { return true; }
 };
 
 void CreatedInvocation::dispatch(Element* element)
diff --git a/Source/core/dom/CustomElementCallbackInvocation.h b/Source/core/dom/CustomElementCallbackInvocation.h
index c6f0818..d2f8135 100644
--- a/Source/core/dom/CustomElementCallbackInvocation.h
+++ b/Source/core/dom/CustomElementCallbackInvocation.h
@@ -49,6 +49,7 @@
 
     virtual ~CustomElementCallbackInvocation() { }
     virtual void dispatch(Element*) = 0;
+    virtual bool isCreated() const { return false; }
 
 protected:
     CustomElementCallbackInvocation(PassRefPtr<CustomElementLifecycleCallbacks> callbacks)
diff --git a/Source/core/dom/CustomElementCallbackQueue.cpp b/Source/core/dom/CustomElementCallbackQueue.cpp
index d5641bd..7078364 100644
--- a/Source/core/dom/CustomElementCallbackQueue.cpp
+++ b/Source/core/dom/CustomElementCallbackQueue.cpp
@@ -44,16 +44,22 @@
     : m_element(element)
     , m_owner(-1)
     , m_index(0)
+    , m_inCreatedCallback(false)
 {
 }
 
 void CustomElementCallbackQueue::processInElementQueue(ElementQueue caller)
 {
+    ASSERT(!m_inCreatedCallback);
+
     while (m_index < m_queue.size() && owner() == caller) {
+        m_inCreatedCallback = m_queue[m_index]->isCreated();
+
         // dispatch() may cause recursion which steals this callback
         // queue and reenters processInQueue. owner() == caller
         // detects this recursion and cedes processing.
         m_queue[m_index++]->dispatch(m_element.get());
+        m_inCreatedCallback = false;
     }
 
     if (owner() == caller && m_index == m_queue.size()) {
diff --git a/Source/core/dom/CustomElementCallbackQueue.h b/Source/core/dom/CustomElementCallbackQueue.h
index 7e39486..430766f 100644
--- a/Source/core/dom/CustomElementCallbackQueue.h
+++ b/Source/core/dom/CustomElementCallbackQueue.h
@@ -56,6 +56,7 @@
 
     void append(PassOwnPtr<CustomElementCallbackInvocation> invocation) { m_queue.append(invocation); }
     void processInElementQueue(ElementQueue);
+    bool inCreatedCallback() const { return m_inCreatedCallback; }
 
 private:
     CustomElementCallbackQueue(PassRefPtr<Element>);
@@ -64,6 +65,7 @@
     Vector<OwnPtr<CustomElementCallbackInvocation> > m_queue;
     ElementQueue m_owner;
     size_t m_index;
+    bool m_inCreatedCallback;
 };
 
 }
diff --git a/Source/core/dom/CustomElementCallbackScheduler.cpp b/Source/core/dom/CustomElementCallbackScheduler.cpp
index 4a95d2b..79252ba 100644
--- a/Source/core/dom/CustomElementCallbackScheduler.cpp
+++ b/Source/core/dom/CustomElementCallbackScheduler.cpp
@@ -43,7 +43,7 @@
     if (!callbacks->hasAttributeChangedCallback())
         return;
 
-    CustomElementCallbackQueue* queue = CustomElementCallbackDispatcher::instance().ensureInCurrentElementQueue(element);
+    CustomElementCallbackQueue* queue = CustomElementCallbackDispatcher::instance().schedule(element);
     queue->append(CustomElementCallbackInvocation::createAttributeChangedInvocation(callbacks, name, oldValue, newValue));
 }
 
@@ -52,7 +52,7 @@
     if (!callbacks->hasCreatedCallback())
         return;
 
-    CustomElementCallbackQueue* queue = CustomElementCallbackDispatcher::instance().createAtFrontOfCurrentElementQueue(element);
+    CustomElementCallbackQueue* queue = CustomElementCallbackDispatcher::instance().scheduleInCurrentElementQueue(element);
     queue->append(CustomElementCallbackInvocation::createInvocation(callbacks, CustomElementLifecycleCallbacks::Created));
 }
 
@@ -61,7 +61,7 @@
     if (!callbacks->hasEnteredDocumentCallback())
         return;
 
-    CustomElementCallbackQueue* queue = CustomElementCallbackDispatcher::instance().ensureInCurrentElementQueue(element);
+    CustomElementCallbackQueue* queue = CustomElementCallbackDispatcher::instance().schedule(element);
     queue->append(CustomElementCallbackInvocation::createInvocation(callbacks, CustomElementLifecycleCallbacks::EnteredDocument));
 }
 
@@ -70,7 +70,7 @@
     if (!callbacks->hasLeftDocumentCallback())
         return;
 
-    CustomElementCallbackQueue* queue = CustomElementCallbackDispatcher::instance().ensureInCurrentElementQueue(element);
+    CustomElementCallbackQueue* queue = CustomElementCallbackDispatcher::instance().schedule(element);
     queue->append(CustomElementCallbackInvocation::createInvocation(callbacks, CustomElementLifecycleCallbacks::LeftDocument));
 }
 
diff --git a/Source/core/dom/CustomElementException.cpp b/Source/core/dom/CustomElementException.cpp
new file mode 100644
index 0000000..b5752a8
--- /dev/null
+++ b/Source/core/dom/CustomElementException.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name of Google Inc. nor the names of its contributors
+ *    may be used to endorse or promote products derived from this
+ *    software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 THE COPYRIGHT
+ * OWNER 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 "core/dom/CustomElementException.h"
+
+#include "bindings/v8/ExceptionState.h"
+#include "core/dom/ExceptionCode.h"
+
+namespace WebCore {
+
+String CustomElementException::preamble(const AtomicString& type)
+{
+    return "Failed to call 'register' on 'Document' for type '" + type + "': ";
+}
+
+void CustomElementException::throwException(Reason reason, const AtomicString& type, ExceptionState& es)
+{
+    switch (reason) {
+    case CannotRegisterFromExtension:
+        es.throwDOMException(NotSupportedError, preamble(type) + "elements cannot be registered from extensions.");
+        return;
+
+    case ConstructorPropertyNotConfigurable:
+        es.throwDOMException(NotSupportedError, preamble(type) + "prototype constructor property is not configurable.");
+        return;
+
+    case ContextDestroyedCheckingPrototype:
+        es.throwDOMException(InvalidStateError, preamble(type) + "the context is no longer valid.");
+        return;
+
+    case ContextDestroyedCreatingCallbacks:
+        es.throwDOMException(InvalidStateError);
+        return;
+
+    case ContextDestroyedRegisteringDefinition:
+        es.throwDOMException(NotSupportedError);
+        return;
+
+    case InvalidName:
+        es.throwDOMException(InvalidCharacterError, preamble(type) + ": '" + type + "' is not a valid name.");
+        return;
+
+    case NotYetImplemented:
+        es.throwDOMException(InvalidStateError);
+        return;
+
+    case PrototypeDoesNotExtendHTMLElementSVGElementNamespace:
+        es.throwDOMException(NamespaceError, preamble(type) + "the prototype does not extend an HTML or SVG element.");
+        return;
+
+    case PrototypeDoesNotExtendHTMLElementSVGElementPrototype:
+        es.throwDOMException(InvalidStateError, preamble(type) + "the prototype does not extend an HTML or SVG element.");
+        return;
+
+    case PrototypeInUse:
+        es.throwDOMException(NotSupportedError, preamble(type) + "prototype is already in-use as an interface prototype object.");
+        return;
+
+    case PrototypeNotAnObject:
+        es.throwDOMException(InvalidStateError, preamble(type) + "the prototype option is not an object.");
+        return;
+
+    case TypeAlreadyRegistered:
+        es.throwDOMException(InvalidStateError, preamble(type) + "a type with that name is already registered.");
+        return;
+    }
+
+    ASSERT_NOT_REACHED();
+}
+
+} // namespace WebCore
diff --git a/Source/core/dom/CustomElementException.h b/Source/core/dom/CustomElementException.h
new file mode 100644
index 0000000..622ef22
--- /dev/null
+++ b/Source/core/dom/CustomElementException.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name of Google Inc. nor the names of its contributors
+ *    may be used to endorse or promote products derived from this
+ *    software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 THE COPYRIGHT
+ * OWNER 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 CustomElementException_h
+#define CustomElementException_h
+
+#include "wtf/text/AtomicString.h"
+#include "wtf/text/WTFString.h"
+
+namespace WebCore {
+
+class ExceptionState;
+
+class CustomElementException {
+public:
+    enum Reason {
+        CannotRegisterFromExtension,
+        ConstructorPropertyNotConfigurable,
+        ContextDestroyedCheckingPrototype,
+        ContextDestroyedCreatingCallbacks,
+        ContextDestroyedRegisteringDefinition,
+        InvalidName,
+        NotYetImplemented,
+        PrototypeDoesNotExtendHTMLElementSVGElementNamespace,
+        PrototypeDoesNotExtendHTMLElementSVGElementPrototype,
+        PrototypeInUse,
+        PrototypeNotAnObject,
+        TypeAlreadyRegistered
+    };
+
+    static void throwException(Reason, const AtomicString& type, ExceptionState&);
+
+private:
+    CustomElementException();
+
+    static String preamble(const AtomicString& type);
+};
+
+}
+
+#endif // CustomElementException_h
diff --git a/Source/core/dom/CustomElementObserver.cpp b/Source/core/dom/CustomElementObserver.cpp
new file mode 100644
index 0000000..45f1350
--- /dev/null
+++ b/Source/core/dom/CustomElementObserver.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name of Google Inc. nor the names of its contributors
+ *    may be used to endorse or promote products derived from this
+ *    software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 THE COPYRIGHT
+ * OWNER 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 "core/dom/CustomElementObserver.h"
+
+namespace WebCore {
+
+CustomElementObserver::ElementObserverMap& CustomElementObserver::elementObservers()
+{
+    DEFINE_STATIC_LOCAL(ElementObserverMap, map, ());
+    return map;
+}
+
+void CustomElementObserver::notifyElementDidFinishParsingChildren(Element* element)
+{
+    ElementObserverMap::iterator it = elementObservers().find(element);
+    if (it == elementObservers().end())
+        return;
+    it->value->elementDidFinishParsingChildren(element);
+}
+
+void CustomElementObserver::notifyElementWasDestroyed(Element* element)
+{
+    ElementObserverMap::iterator it = elementObservers().find(element);
+    if (it == elementObservers().end())
+        return;
+    it->value->elementWasDestroyed(element);
+}
+
+void CustomElementObserver::observe(Element* element)
+{
+    ElementObserverMap::AddResult result = elementObservers().add(element, this);
+    ASSERT(result.isNewEntry);
+}
+
+void CustomElementObserver::unobserve(Element* element)
+{
+    CustomElementObserver* observer = elementObservers().take(element);
+    ASSERT(observer == this);
+}
+
+} // namespace WebCore
diff --git a/Source/core/dom/CustomElementObserver.h b/Source/core/dom/CustomElementObserver.h
new file mode 100644
index 0000000..ab7c57d
--- /dev/null
+++ b/Source/core/dom/CustomElementObserver.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer
+ *    in the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name of Google Inc. nor the names of its contributors
+ *    may be used to endorse or promote products derived from this
+ *    software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 THE COPYRIGHT
+ * OWNER 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 CustomElementObserver_h
+#define CustomElementObserver_h
+
+#include "wtf/HashMap.h"
+
+namespace WebCore {
+
+class Element;
+
+class CustomElementObserver {
+public:
+    CustomElementObserver() { }
+    virtual ~CustomElementObserver() { }
+
+    // API for CustomElement to kick off notifications
+
+    static void notifyElementDidFinishParsingChildren(Element*);
+    static void notifyElementWasDestroyed(Element*);
+
+protected:
+    void observe(Element*);
+    void unobserve(Element*);
+
+    virtual void elementDidFinishParsingChildren(Element*) = 0;
+    virtual void elementWasDestroyed(Element* element) { unobserve(element); }
+
+private:
+    // Maps elements to the observer watching them. At most one per
+    // element at a time.
+    typedef HashMap<Element*, CustomElementObserver*> ElementObserverMap;
+    static ElementObserverMap& elementObservers();
+};
+
+}
+
+#endif // CustomElementObserver_h
diff --git a/Source/core/dom/CustomElementRegistrationContext.cpp b/Source/core/dom/CustomElementRegistrationContext.cpp
index 4589e7e..bedaf5e 100644
--- a/Source/core/dom/CustomElementRegistrationContext.cpp
+++ b/Source/core/dom/CustomElementRegistrationContext.cpp
@@ -35,6 +35,7 @@
 #include "SVGNames.h"
 #include "bindings/v8/ExceptionState.h"
 #include "core/dom/CustomElement.h"
+#include "core/dom/CustomElementCallbackScheduler.h"
 #include "core/dom/CustomElementDefinition.h"
 #include "core/dom/Element.h"
 #include "core/html/HTMLElement.h"
@@ -44,9 +45,9 @@
 
 namespace WebCore {
 
-void CustomElementRegistrationContext::registerElement(Document* document, CustomElementConstructorBuilder* constructorBuilder, const AtomicString& type, ExceptionState& es)
+void CustomElementRegistrationContext::registerElement(Document* document, CustomElementConstructorBuilder* constructorBuilder, const AtomicString& type, CustomElement::NameSet validNames, ExceptionState& es)
 {
-    CustomElementDefinition* definition = m_registry.registerElement(document, constructorBuilder, type, es);
+    CustomElementDefinition* definition = m_registry.registerElement(document, constructorBuilder, type, validNames, es);
 
     if (!definition)
         return;
@@ -57,9 +58,9 @@
         didResolveElement(definition, *it);
 }
 
-PassRefPtr<Element> CustomElementRegistrationContext::createCustomTagElement(Document* document, const QualifiedName& tagName)
+PassRefPtr<Element> CustomElementRegistrationContext::createCustomTagElement(Document* document, const QualifiedName& tagName, CreationMode mode)
 {
-    ASSERT(CustomElement::isCustomTagName(tagName.localName()));
+    ASSERT(CustomElement::isValidName(tagName.localName()));
 
     if (!document)
         return 0;
@@ -75,6 +76,7 @@
         return Element::create(tagName, document);
     }
 
+    element->setCustomElementState(mode == CreatedByParser ? Element::WaitingForParser : Element::WaitingForUpgrade);
     resolve(element.get(), nullAtom);
     return element.release();
 }
@@ -88,7 +90,7 @@
 {
     // If an element has a custom tag name it takes precedence over
     // the "is" attribute (if any).
-    const AtomicString& type = CustomElement::isCustomTagName(element->localName())
+    const AtomicString& type = CustomElement::isValidName(element->localName())
         ? element->localName()
         : typeExtension;
     ASSERT(!type.isNull());
@@ -108,14 +110,10 @@
 
 void CustomElementRegistrationContext::didCreateUnresolvedElement(const CustomElementDescriptor& descriptor, Element* element)
 {
+    ASSERT(element->customElementState() == Element::WaitingForParser || element->customElementState() == Element::WaitingForUpgrade);
     m_candidates.add(descriptor, element);
 }
 
-void CustomElementRegistrationContext::customElementWasDestroyed(Element* element)
-{
-    m_candidates.remove(element);
-}
-
 PassRefPtr<CustomElementRegistrationContext> CustomElementRegistrationContext::create()
 {
     return adoptRef(new CustomElementRegistrationContext());
@@ -129,7 +127,7 @@
     setTypeExtension(element, type);
 }
 
-void CustomElementRegistrationContext::setTypeExtension(Element* element, const AtomicString& type)
+void CustomElementRegistrationContext::setTypeExtension(Element* element, const AtomicString& type, CreationMode mode)
 {
     if (!element->isHTMLElement() && !element->isSVGElement())
         return;
@@ -144,7 +142,9 @@
     }
 
     // Custom tags take precedence over type extensions
-    ASSERT(!CustomElement::isCustomTagName(element->localName()));
+    ASSERT(!CustomElement::isValidName(element->localName()));
+
+    element->setCustomElementState(mode == CreatedByParser ? Element::WaitingForParser : Element::WaitingForUpgrade);
 
     if (CustomElementRegistrationContext* context = element->document()->registrationContext())
         context->didGiveTypeExtension(element, type);
diff --git a/Source/core/dom/CustomElementRegistrationContext.h b/Source/core/dom/CustomElementRegistrationContext.h
index 64099d3..7b8449f 100644
--- a/Source/core/dom/CustomElementRegistrationContext.h
+++ b/Source/core/dom/CustomElementRegistrationContext.h
@@ -54,15 +54,17 @@
     ~CustomElementRegistrationContext() { }
 
     // Definitions
-    void registerElement(Document*, CustomElementConstructorBuilder*, const AtomicString& type, ExceptionState&);
+    void registerElement(Document*, CustomElementConstructorBuilder*, const AtomicString& type, CustomElement::NameSet validNames, ExceptionState&);
 
     // Instance creation
-    PassRefPtr<Element> createCustomTagElement(Document*, const QualifiedName&);
-    static void setIsAttributeAndTypeExtension(Element*, const AtomicString& type);
-    static void setTypeExtension(Element*, const AtomicString& type);
+    enum CreationMode {
+        CreatedByParser,
+        NotCreatedByParser
+    };
 
-    // Instance lifecycle
-    void customElementWasDestroyed(Element*);
+    PassRefPtr<Element> createCustomTagElement(Document*, const QualifiedName&, CreationMode = NotCreatedByParser);
+    static void setIsAttributeAndTypeExtension(Element*, const AtomicString& type);
+    static void setTypeExtension(Element*, const AtomicString& type, CreationMode = NotCreatedByParser);
 
 protected:
     CustomElementRegistrationContext() { }
diff --git a/Source/core/dom/CustomElementRegistry.cpp b/Source/core/dom/CustomElementRegistry.cpp
index 9d9195c..b734c82 100644
--- a/Source/core/dom/CustomElementRegistry.cpp
+++ b/Source/core/dom/CustomElementRegistry.cpp
@@ -34,12 +34,11 @@
 #include "HTMLNames.h"
 #include "SVGNames.h"
 #include "bindings/v8/CustomElementConstructorBuilder.h"
-#include "bindings/v8/ExceptionState.h"
 #include "core/dom/CustomElement.h"
 #include "core/dom/CustomElementDefinition.h"
+#include "core/dom/CustomElementException.h"
 #include "core/dom/CustomElementRegistrationContext.h"
 #include "core/dom/DocumentLifecycleObserver.h"
-#include "core/dom/ExceptionCode.h"
 
 namespace WebCore {
 
@@ -59,7 +58,7 @@
     bool m_wentAway;
 };
 
-CustomElementDefinition* CustomElementRegistry::registerElement(Document* document, CustomElementConstructorBuilder* constructorBuilder, const AtomicString& userSuppliedName, ExceptionState& es)
+CustomElementDefinition* CustomElementRegistry::registerElement(Document* document, CustomElementConstructorBuilder* constructorBuilder, const AtomicString& userSuppliedName, CustomElement::NameSet validNames, ExceptionState& es)
 {
     // FIXME: In every instance except one it is the
     // CustomElementConstructorBuilder that observes document
@@ -67,31 +66,30 @@
     // consolidated in one place.
     RegistrationContextObserver observer(document);
 
-    if (!constructorBuilder->isFeatureAllowed()) {
-        es.throwDOMException(NotSupportedError);
-        return 0;
-    }
-
     AtomicString type = userSuppliedName.lower();
-    if (!CustomElement::isValidTypeName(type)) {
-        es.throwDOMException(InvalidCharacterError);
+
+    if (!constructorBuilder->isFeatureAllowed()) {
+        CustomElementException::throwException(CustomElementException::CannotRegisterFromExtension, type, es);
         return 0;
     }
 
-    if (!constructorBuilder->validateOptions()) {
-        es.throwDOMException(InvalidStateError);
+    if (!CustomElement::isValidName(type, validNames)) {
+        CustomElementException::throwException(CustomElementException::InvalidName, type, es);
         return 0;
     }
 
+    if (!constructorBuilder->validateOptions(type, es))
+        return 0;
+
     QualifiedName tagName = nullQName();
     if (!constructorBuilder->findTagName(type, tagName)) {
-        es.throwDOMException(NamespaceError);
+        CustomElementException::throwException(CustomElementException::PrototypeDoesNotExtendHTMLElementSVGElementNamespace, type, es);
         return 0;
     }
     ASSERT(tagName.namespaceURI() == HTMLNames::xhtmlNamespaceURI || tagName.namespaceURI() == SVGNames::svgNamespaceURI);
 
     if (m_registeredTypeNames.contains(type)) {
-        es.throwDOMException(InvalidStateError);
+        CustomElementException::throwException(CustomElementException::TypeAlreadyRegistered, type, es);
         return 0;
     }
 
@@ -102,23 +100,21 @@
     // Consulting the constructor builder could execute script and
     // kill the document.
     if (observer.registrationContextWentAway()) {
-        es.throwDOMException(InvalidStateError);
+        CustomElementException::throwException(CustomElementException::ContextDestroyedCreatingCallbacks, type, es);
         return 0;
     }
 
     const CustomElementDescriptor descriptor(type, tagName.namespaceURI(), tagName.localName());
     RefPtr<CustomElementDefinition> definition = CustomElementDefinition::create(descriptor, lifecycleCallbacks);
 
-    if (!constructorBuilder->createConstructor(document, definition.get())) {
-        es.throwDOMException(NotSupportedError);
+    if (!constructorBuilder->createConstructor(document, definition.get(), es))
         return 0;
-    }
 
     m_definitions.add(descriptor, definition);
     m_registeredTypeNames.add(descriptor.type());
 
     if (!constructorBuilder->didRegisterDefinition(definition.get())) {
-        es.throwDOMException(NotSupportedError);
+        CustomElementException::throwException(CustomElementException::ContextDestroyedRegisteringDefinition, type, es);
         return 0;
     }
 
diff --git a/Source/core/dom/CustomElementRegistry.h b/Source/core/dom/CustomElementRegistry.h
index c9ff8db..d1a79bd 100644
--- a/Source/core/dom/CustomElementRegistry.h
+++ b/Source/core/dom/CustomElementRegistry.h
@@ -31,6 +31,7 @@
 #ifndef CustomElementRegistry_h
 #define CustomElementRegistry_h
 
+#include "core/dom/CustomElement.h"
 #include "core/dom/CustomElementDefinition.h"
 #include "core/dom/CustomElementDescriptor.h"
 #include "core/dom/CustomElementDescriptorHash.h"
@@ -54,7 +55,7 @@
     CustomElementRegistry() { }
     virtual ~CustomElementRegistry() { }
 
-    CustomElementDefinition* registerElement(Document*, CustomElementConstructorBuilder*, const AtomicString& name, ExceptionState&);
+    CustomElementDefinition* registerElement(Document*, CustomElementConstructorBuilder*, const AtomicString& name, CustomElement::NameSet validNames, ExceptionState&);
     CustomElementDefinition* find(const CustomElementDescriptor&) const;
 
 private:
diff --git a/Source/core/dom/CustomElementUpgradeCandidateMap.cpp b/Source/core/dom/CustomElementUpgradeCandidateMap.cpp
index c84bcb7..8583eb2 100644
--- a/Source/core/dom/CustomElementUpgradeCandidateMap.cpp
+++ b/Source/core/dom/CustomElementUpgradeCandidateMap.cpp
@@ -39,14 +39,12 @@
 {
     UpgradeCandidateMap::const_iterator::Keys end = m_upgradeCandidates.end().keys();
     for (UpgradeCandidateMap::const_iterator::Keys it = m_upgradeCandidates.begin().keys(); it != end; ++it)
-        unregisterForElementDestructionNotification(*it, this);
+        unobserve(*it);
 }
 
 void CustomElementUpgradeCandidateMap::add(const CustomElementDescriptor& descriptor, Element* element)
 {
-    element->setCustomElementState(Element::UpgradeCandidate);
-
-    registerForElementDestructionNotification(element, this);
+    observe(element);
 
     UpgradeCandidateMap::AddResult result = m_upgradeCandidates.add(element, descriptor);
     ASSERT(result.isNewEntry);
@@ -59,8 +57,18 @@
 
 void CustomElementUpgradeCandidateMap::remove(Element* element)
 {
-    unregisterForElementDestructionNotification(element, this);
+    unobserve(element);
+    removeCommon(element);
+}
 
+void CustomElementUpgradeCandidateMap::elementWasDestroyed(Element* element)
+{
+    CustomElementObserver::elementWasDestroyed(element);
+    removeCommon(element);
+}
+
+void CustomElementUpgradeCandidateMap::removeCommon(Element* element)
+{
     UpgradeCandidateMap::iterator candidate = m_upgradeCandidates.find(element);
     ASSERT(candidate != m_upgradeCandidates.end());
 
@@ -70,42 +78,33 @@
     m_upgradeCandidates.remove(candidate);
 }
 
+void CustomElementUpgradeCandidateMap::elementDidFinishParsingChildren(Element* element)
+{
+    // An upgrade candidate finished parsing; reorder so that eventual
+    // upgrade order matches finished-parsing order.
+    moveToEnd(element);
+}
+
+void CustomElementUpgradeCandidateMap::moveToEnd(Element* element)
+{
+    UpgradeCandidateMap::iterator candidate = m_upgradeCandidates.find(element);
+    ASSERT(candidate != m_upgradeCandidates.end());
+
+    UnresolvedDefinitionMap::iterator elements = m_unresolvedDefinitions.find(candidate->value);
+    ASSERT(elements != m_unresolvedDefinitions.end());
+    elements->value.appendOrMoveToLast(element);
+}
+
 ListHashSet<Element*> CustomElementUpgradeCandidateMap::takeUpgradeCandidatesFor(const CustomElementDescriptor& descriptor)
 {
     const ListHashSet<Element*>& candidates = m_unresolvedDefinitions.take(descriptor);
 
     for (ElementSet::const_iterator candidate = candidates.begin(); candidate != candidates.end(); ++candidate) {
-        unregisterForElementDestructionNotification(*candidate, this);
+        unobserve(*candidate);
         m_upgradeCandidates.remove(*candidate);
     }
 
     return candidates;
 }
 
-void CustomElementUpgradeCandidateMap::elementWasDestroyed(Element* element)
-{
-    DestructionObserverMap::iterator it = destructionObservers().find(element);
-    if (it == destructionObservers().end())
-        return;
-    it->value->remove(element); // will also remove the destruction observer
-}
-
-CustomElementUpgradeCandidateMap::DestructionObserverMap& CustomElementUpgradeCandidateMap::destructionObservers()
-{
-    DEFINE_STATIC_LOCAL(DestructionObserverMap, map, ());
-    return map;
-}
-
-void CustomElementUpgradeCandidateMap::registerForElementDestructionNotification(Element* element, CustomElementUpgradeCandidateMap* observer)
-{
-    DestructionObserverMap::AddResult result = destructionObservers().add(element, observer);
-    ASSERT(result.isNewEntry);
-}
-
-void CustomElementUpgradeCandidateMap::unregisterForElementDestructionNotification(Element* element, CustomElementUpgradeCandidateMap* observer)
-{
-    CustomElementUpgradeCandidateMap* map = destructionObservers().take(element);
-    ASSERT(map == observer);
-}
-
 }
diff --git a/Source/core/dom/CustomElementUpgradeCandidateMap.h b/Source/core/dom/CustomElementUpgradeCandidateMap.h
index 2814c0a..f9f2311 100644
--- a/Source/core/dom/CustomElementUpgradeCandidateMap.h
+++ b/Source/core/dom/CustomElementUpgradeCandidateMap.h
@@ -33,6 +33,7 @@
 
 #include "core/dom/CustomElementDescriptor.h"
 #include "core/dom/CustomElementDescriptorHash.h"
+#include "core/dom/CustomElementObserver.h"
 #include "wtf/HashMap.h"
 #include "wtf/ListHashSet.h"
 #include "wtf/Noncopyable.h"
@@ -41,26 +42,26 @@
 
 class Element;
 
-class CustomElementUpgradeCandidateMap {
+class CustomElementUpgradeCandidateMap : CustomElementObserver {
     WTF_MAKE_NONCOPYABLE(CustomElementUpgradeCandidateMap);
 public:
     CustomElementUpgradeCandidateMap() { }
     ~CustomElementUpgradeCandidateMap();
 
-    static void elementWasDestroyed(Element*);
+    // API for CustomElementRegistrationContext to save and take candidates
+
+    typedef ListHashSet<Element*> ElementSet;
 
     void add(const CustomElementDescriptor&, Element*);
     void remove(Element*);
-
-    typedef ListHashSet<Element*> ElementSet;
     ElementSet takeUpgradeCandidatesFor(const CustomElementDescriptor&);
 
 private:
-    // Maps elements to upgrade candidate maps observing their destruction
-    typedef HashMap<Element*, CustomElementUpgradeCandidateMap*> DestructionObserverMap;
-    static DestructionObserverMap& destructionObservers();
-    static void registerForElementDestructionNotification(Element*, CustomElementUpgradeCandidateMap*);
-    static void unregisterForElementDestructionNotification(Element*, CustomElementUpgradeCandidateMap*);
+    virtual void elementWasDestroyed(Element*) OVERRIDE;
+    void removeCommon(Element*);
+
+    virtual void elementDidFinishParsingChildren(Element*) OVERRIDE;
+    void moveToEnd(Element*);
 
     typedef HashMap<Element*, CustomElementDescriptor> UpgradeCandidateMap;
     UpgradeCandidateMap m_upgradeCandidates;
diff --git a/Source/core/dom/DOMError.h b/Source/core/dom/DOMError.h
index 74d4d17..a66d0e2 100644
--- a/Source/core/dom/DOMError.h
+++ b/Source/core/dom/DOMError.h
@@ -59,10 +59,11 @@
     const String& name() const { return m_name; }
     const String& message() const { return m_message; }
 
-private:
+protected:
     explicit DOMError(const String& name);
-    explicit DOMError(const String& name, const String& message);
+    DOMError(const String& name, const String& message);
 
+private:
     const String m_name;
     const String m_message;
 };
diff --git a/Source/core/dom/DOMException.cpp b/Source/core/dom/DOMException.cpp
index 7510e27..348a94e 100644
--- a/Source/core/dom/DOMException.cpp
+++ b/Source/core/dom/DOMException.cpp
@@ -86,22 +86,24 @@
     return tableIndex < tableSize ? &coreExceptions[tableIndex] : 0;
 }
 
-DOMException::DOMException(unsigned short code, const String& name, const String& message)
+DOMException::DOMException(unsigned short code, const String& name, const String& sanitizedMessage, const String& unsanitizedMessage)
 {
     ASSERT(name);
     m_code = code;
     m_name = name;
-    m_message = message;
+    m_sanitizedMessage = sanitizedMessage;
+    m_unsanitizedMessage = unsanitizedMessage;
     ScriptWrappable::init(this);
 }
 
-PassRefPtr<DOMException> DOMException::create(ExceptionCode ec, const String& message)
+PassRefPtr<DOMException> DOMException::create(ExceptionCode ec, const String& sanitizedMessage, const String& unsanitizedMessage)
 {
     const CoreException* entry = getErrorEntry(ec);
     ASSERT(entry);
     return adoptRef(new DOMException(entry->code,
         entry->name ? entry->name : "Error",
-        message.isNull() ? String(entry->message) : message));
+        sanitizedMessage.isNull() ? String(entry->message) : sanitizedMessage,
+        unsanitizedMessage));
 }
 
 String DOMException::toString() const
@@ -109,6 +111,11 @@
     return name() + ": " + message();
 }
 
+String DOMException::toStringForConsole() const
+{
+    return name() + ": " + messageForConsole();
+}
+
 String DOMException::getErrorName(ExceptionCode ec)
 {
     const CoreException* entry = getErrorEntry(ec);
diff --git a/Source/core/dom/DOMException.h b/Source/core/dom/DOMException.h
index ca96483..825cf50 100644
--- a/Source/core/dom/DOMException.h
+++ b/Source/core/dom/DOMException.h
@@ -40,24 +40,30 @@
 
 class DOMException : public RefCounted<DOMException>, public ScriptWrappable {
 public:
-    static PassRefPtr<DOMException> create(ExceptionCode, const String& message = String());
+    static PassRefPtr<DOMException> create(ExceptionCode, const String& sanitizedMessage = String(), const String& unsanitizedMessage = String());
 
     unsigned short code() const { return m_code; }
     String name() const { return m_name; }
-    String message() const { return m_message; }
 
+    // This is the message that's exposed to JavaScript: never return unsanitized data.
+    String message() const { return m_sanitizedMessage; }
     String toString() const;
 
+    // This is the message that's exposed to the console: if an unsanitized message is present, we prefer it.
+    String messageForConsole() const { return !m_unsanitizedMessage.isEmpty() ? m_unsanitizedMessage : m_sanitizedMessage; }
+    String toStringForConsole() const;
+
     static String getErrorName(ExceptionCode);
     static String getErrorMessage(ExceptionCode);
     static unsigned short getLegacyErrorCode(ExceptionCode);
 
 private:
-    DOMException(unsigned short m_code, const String& name, const String& message);
+    DOMException(unsigned short m_code, const String& name, const String& sanitizedMessage, const String& unsanitizedMessage);
 
     unsigned short m_code;
     String m_name;
-    String m_message;
+    String m_sanitizedMessage;
+    String m_unsanitizedMessage;
 };
 
 } // namespace WebCore
diff --git a/Source/core/dom/DOMImplementation.cpp b/Source/core/dom/DOMImplementation.cpp
index 14c51fe..3b888bc 100644
--- a/Source/core/dom/DOMImplementation.cpp
+++ b/Source/core/dom/DOMImplementation.cpp
@@ -184,7 +184,7 @@
     if (!Document::parseQualifiedName(qualifiedName, prefix, localName, es))
         return 0;
 
-    return DocumentType::create(0, qualifiedName, publicId, systemId);
+    return DocumentType::create(m_document, qualifiedName, publicId, systemId);
 }
 
 DOMImplementation* DOMImplementation::getInterface(const String& /*feature*/)
@@ -213,16 +213,6 @@
             return 0;
     }
 
-    // WrongDocumentError: Raised if doctype has already been used with a different document or was
-    // created from a different implementation.
-    // Hixie's interpretation of the DOM Core spec suggests we should prefer
-    // other exceptions to WrongDocumentError (based on order mentioned in spec),
-    // but this matches the new DOM Core spec (http://www.w3.org/TR/domcore/).
-    if (doctype && doctype->document()) {
-        es.throwDOMException(WrongDocumentError);
-        return 0;
-    }
-
     if (doctype)
         doc->appendChild(doctype);
     if (documentElement)
diff --git a/Source/core/dom/DOMImplementation.idl b/Source/core/dom/DOMImplementation.idl
index 0d627f5..c110cb4 100644
--- a/Source/core/dom/DOMImplementation.idl
+++ b/Source/core/dom/DOMImplementation.idl
@@ -29,12 +29,12 @@
 
     // DOM Level 2
 
-     [RaisesException] DocumentType createDocumentType([TreatNullAs=NullString, TreatUndefinedAs=NullString,Default=Undefined] optional DOMString qualifiedName,
-                                                   [TreatNullAs=NullString, TreatUndefinedAs=NullString,Default=Undefined] optional DOMString publicId,
-                                                   [TreatNullAs=NullString, TreatUndefinedAs=NullString,Default=Undefined] optional DOMString systemId);
-     [RaisesException] Document createDocument([TreatNullAs=NullString,Default=Undefined] optional DOMString namespaceURI,
-                                           [TreatNullAs=NullString,Default=Undefined] optional DOMString qualifiedName,
-                                           [TreatNullAs=NullString,Default=Undefined] optional DocumentType doctype);
+     [RaisesException] DocumentType createDocumentType([TreatNullAs=NullString] DOMString qualifiedName,
+                                                       [TreatNullAs=NullString] DOMString publicId,
+                                                       [TreatNullAs=NullString] DOMString systemId);
+     [RaisesException] Document createDocument([TreatNullAs=NullString] DOMString namespaceURI,
+                                               [TreatNullAs=NullString] DOMString qualifiedName,
+                                               [Default=Undefined] optional DocumentType doctype);
 
     // DOMImplementationCSS interface from DOM Level 2 CSS
 
diff --git a/Source/core/dom/DataTransferItemList.h b/Source/core/dom/DataTransferItemList.h
index 91fd967..90d847f 100644
--- a/Source/core/dom/DataTransferItemList.h
+++ b/Source/core/dom/DataTransferItemList.h
@@ -56,8 +56,8 @@
     virtual PassRefPtr<DataTransferItem> item(unsigned long index) = 0;
     virtual void deleteItem(unsigned long index, ExceptionState&) = 0;
     virtual void clear() = 0;
-    virtual void add(const String& data, const String& type, ExceptionState&) = 0;
-    virtual void add(PassRefPtr<File>) = 0;
+    virtual PassRefPtr<DataTransferItem> add(const String& data, const String& type, ExceptionState&) = 0;
+    virtual PassRefPtr<DataTransferItem> add(PassRefPtr<File>) = 0;
 };
 
 } // namespace WebCore
diff --git a/Source/core/dom/DataTransferItemList.idl b/Source/core/dom/DataTransferItemList.idl
index eec5c0c..0babe03 100644
--- a/Source/core/dom/DataTransferItemList.idl
+++ b/Source/core/dom/DataTransferItemList.idl
@@ -28,15 +28,13 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-[
-    NoInterfaceObject
-] interface DataTransferItemList {
+interface DataTransferItemList {
     readonly attribute long length;
-    getter DataTransferItem item([Default=Undefined] optional unsigned long index);
+    [ImplementedAs=item] getter DataTransferItem (unsigned long index);
 
+    [RaisesException, ImplementedAs=deleteItem] void remove(unsigned long index);
     void clear();
-    void add(File? file);
-    [RaisesException] void add([Default=Undefined] optional DOMString data,
-             [Default=Undefined] optional DOMString type);
+    DataTransferItem add(File? file);
+    [RaisesException] DataTransferItem add(DOMString data, DOMString type);
 };
 
diff --git a/Source/core/dom/Document.cpp b/Source/core/dom/Document.cpp
index 62dee7a..9dfe1b6 100644
--- a/Source/core/dom/Document.cpp
+++ b/Source/core/dom/Document.cpp
@@ -37,6 +37,7 @@
 #include "XMLNames.h"
 #include "bindings/v8/CustomElementConstructorBuilder.h"
 #include "bindings/v8/Dictionary.h"
+#include "bindings/v8/ExceptionMessages.h"
 #include "bindings/v8/ExceptionState.h"
 #include "bindings/v8/ExceptionStatePlaceholder.h"
 #include "bindings/v8/ScriptController.h"
@@ -51,10 +52,10 @@
 #include "core/css/StyleSheetList.h"
 #include "core/css/resolver/StyleResolver.h"
 #include "core/dom/Attr.h"
+#include "core/dom/BeforeUnloadEvent.h"
 #include "core/dom/CDATASection.h"
 #include "core/dom/Comment.h"
 #include "core/dom/ContextFeatures.h"
-#include "core/dom/CustomElement.h"
 #include "core/dom/CustomElementRegistrationContext.h"
 #include "core/dom/DOMImplementation.h"
 #include "core/dom/DOMNamedFlowCollection.h"
@@ -66,6 +67,7 @@
 #include "core/dom/DocumentStyleSheetCollection.h"
 #include "core/dom/DocumentType.h"
 #include "core/dom/Element.h"
+#include "core/dom/ElementTraversal.h"
 #include "core/dom/Event.h"
 #include "core/dom/EventFactory.h"
 #include "core/dom/EventListener.h"
@@ -97,6 +99,7 @@
 #include "core/dom/shadow/ShadowRoot.h"
 #include "core/editing/Editor.h"
 #include "core/editing/FrameSelection.h"
+#include "core/fetch/ResourceFetcher.h"
 #include "core/html/FormController.h"
 #include "core/html/HTMLAllCollection.h"
 #include "core/html/HTMLAnchorElement.h"
@@ -108,6 +111,7 @@
 #include "core/html/HTMLHtmlElement.h"
 #include "core/html/HTMLIFrameElement.h"
 #include "core/html/HTMLImport.h"
+#include "core/html/HTMLInputElement.h"
 #include "core/html/HTMLLinkElement.h"
 #include "core/html/HTMLNameCollection.h"
 #include "core/html/HTMLScriptElement.h"
@@ -128,7 +132,6 @@
 #include "core/loader/Prerenderer.h"
 #include "core/loader/TextResourceDecoder.h"
 #include "core/loader/appcache/ApplicationCacheHost.h"
-#include "core/loader/cache/ResourceFetcher.h"
 #include "core/page/Chrome.h"
 #include "core/page/ChromeClient.h"
 #include "core/page/ContentSecurityPolicy.h"
@@ -144,7 +147,6 @@
 #include "core/page/PageConsole.h"
 #include "core/page/PointerLockController.h"
 #include "core/page/Settings.h"
-#include "core/page/ValidationMessageClient.h"
 #include "core/page/animation/AnimationController.h"
 #include "core/page/scrolling/ScrollingCoordinator.h"
 #include "core/platform/DateComponents.h"
@@ -401,7 +403,6 @@
     , m_bParsing(false)
     , m_styleRecalcTimer(this, &Document::styleRecalcTimerFired)
     , m_inStyleRecalc(false)
-    , m_closeAfterStyleRecalc(false)
     , m_gotoAnchorNeededAfterStylesheetsLoad(false)
     , m_containsValidityStyleRules(false)
     , m_updateFocusAppearanceRestoresSelection(false)
@@ -435,6 +436,7 @@
     , m_referrerPolicy(ReferrerPolicyDefault)
     , m_directionSetOnDocumentElement(false)
     , m_writingModeSetOnDocumentElement(false)
+    , m_didAllowNavigationViaBeforeUnloadConfirmationPanel(false)
     , m_writeRecursionIsTooDeep(false)
     , m_writeRecursionDepth(0)
     , m_wheelEventHandlerCount(0)
@@ -715,7 +717,7 @@
 
     RefPtr<Element> element;
 
-    if (CustomElement::isCustomTagName(localName) && registrationContext())
+    if (CustomElement::isValidName(localName) && registrationContext())
         element = registrationContext()->createCustomTagElement(this, QualifiedName(nullAtom, localName, xhtmlNamespaceURI));
     else
         element = createElement(localName, es);
@@ -739,7 +741,7 @@
     }
 
     RefPtr<Element> element;
-    if (CustomElement::isCustomTagName(qName.localName()) && registrationContext())
+    if (CustomElement::isValidName(qName.localName()) && registrationContext())
         element = registrationContext()->createCustomTagElement(this, qName);
     else
         element = createElementNS(namespaceURI, qualifiedName, es);
@@ -755,7 +757,7 @@
     return registerElement(state, name, Dictionary(), es);
 }
 
-ScriptValue Document::registerElement(WebCore::ScriptState* state, const AtomicString& name, const Dictionary& options, ExceptionState& es)
+ScriptValue Document::registerElement(WebCore::ScriptState* state, const AtomicString& name, const Dictionary& options, ExceptionState& es, CustomElement::NameSet validNames)
 {
     if (!registrationContext()) {
         es.throwDOMException(NotSupportedError);
@@ -763,7 +765,7 @@
     }
 
     CustomElementConstructorBuilder constructorBuilder(state, &options);
-    registrationContext()->registerElement(this, &constructorBuilder, name, es);
+    registrationContext()->registerElement(this, &constructorBuilder, name, validNames, es);
     return constructorBuilder.bindingsReturnValue();
 }
 
@@ -939,7 +941,7 @@
         }
 
         if (source->isFrameOwnerElement()) {
-            HTMLFrameOwnerElement* frameOwnerElement = toFrameOwnerElement(source.get());
+            HTMLFrameOwnerElement* frameOwnerElement = toHTMLFrameOwnerElement(source.get());
             if (frame() && frame()->tree()->isDescendantOf(frameOwnerElement->contentFrame())) {
                 es.throwDOMException(HierarchyRequestError);
                 return 0;
@@ -1082,8 +1084,11 @@
 
     switch (readyState) {
     case Loading:
-        if (!m_documentTiming.domLoading)
+        if (!m_documentTiming.domLoading) {
             m_documentTiming.domLoading = monotonicallyIncreasingTime();
+            if (RuntimeEnabledFeatures::webAnimationsEnabled())
+                m_timeline->setZeroTimeAsPerfTime(m_documentTiming.domLoading);
+        }
         break;
     case Interactive:
         if (!m_documentTiming.domInteractive)
@@ -1293,6 +1298,7 @@
 
     m_rawTitle = title;
 
+    StringWithDirection oldTitle = m_title;
     if (m_rawTitle.string().isEmpty())
         m_title = StringWithDirection();
     else {
@@ -1301,8 +1307,11 @@
         else
             m_title = canonicalizedTitle<UChar>(this, m_rawTitle);
     }
-    if (Frame* f = frame())
-        f->loader()->setTitle(m_title);
+
+    if (!m_frame || oldTitle == m_title)
+        return;
+    m_frame->loader()->history()->setCurrentItemTitle(m_title);
+    m_frame->loader()->client()->dispatchDidReceiveTitle(m_title);
 }
 
 void Document::setTitle(const String& title)
@@ -1314,7 +1323,7 @@
     else if (!m_titleElement) {
         if (HTMLElement* headElement = head()) {
             m_titleElement = createElement(titleTag, false);
-            headElement->appendChild(m_titleElement, ASSERT_NO_EXCEPTION, AttachLazily);
+            headElement->appendChild(m_titleElement);
         }
     }
 
@@ -1680,12 +1689,6 @@
         }
     }
 
-    // If we wanted to call implicitClose() during recalcStyle, do so now that we're finished.
-    if (m_closeAfterStyleRecalc) {
-        m_closeAfterStyleRecalc = false;
-        implicitClose();
-    }
-
     STYLE_STATS_PRINT();
     STYLE_STATS_CLEAR();
 
@@ -1888,11 +1891,8 @@
 {
     ASSERT(attached());
 
-    if (page()) {
-        page()->pointerLockController()->documentDetached(this);
-        if (ValidationMessageClient* client = page()->validationMessageClient())
-            client->documentDetached(*this);
-    }
+    if (page())
+        page()->documentDetached(this);
 
     if (this == topDocument())
         clearAXObjectCache();
@@ -1953,6 +1953,12 @@
 void Document::prepareForDestruction()
 {
     disconnectDescendantFrames();
+
+    // The process of disconnecting descendant frames could have already
+    // detached us.
+    if (!attached())
+        return;
+
     if (DOMWindow* window = this->domWindow())
         window->willDetachDocumentFromFrame();
     detach();
@@ -2122,7 +2128,7 @@
     // collection update in order to ensure they inherit all the relevant data
     // from their parent.
     if (shouldDisplaySeamlesslyWithParent())
-        styleResolverChanged(DeferRecalcStyle);
+        styleResolverChanged(RecalcStyleDeferred);
 
     m_parser = createParser();
     setParsing(true);
@@ -2163,9 +2169,9 @@
         return;
 
     if (oldBody)
-        documentElement()->replaceChild(newBody.release(), oldBody, es, AttachLazily);
+        documentElement()->replaceChild(newBody.release(), oldBody, es);
     else
-        documentElement()->appendChild(newBody.release(), es, AttachLazily);
+        documentElement()->appendChild(newBody.release(), es);
 }
 
 HTMLHeadElement* Document::head()
@@ -2210,11 +2216,7 @@
 
 void Document::implicitClose()
 {
-    // If we're in the middle of recalcStyle, we need to defer the close until the style information is accurate and all elements are re-attached.
-    if (m_inStyleRecalc) {
-        m_closeAfterStyleRecalc = true;
-        return;
-    }
+    ASSERT(!inStyleRecalc());
 
     bool wasLocationChangePending = frame() && frame()->navigationScheduler()->locationChangePending();
     bool doload = !parsing() && m_parser && !processingLoadEvent() && !wasLocationChangePending;
@@ -2322,6 +2324,95 @@
         accessSVGExtensions()->startAnimations();
 }
 
+bool Document::dispatchBeforeUnloadEvent(Chrome& chrome, Document* navigatingDocument)
+{
+    if (!m_domWindow)
+        return true;
+
+    if (!body())
+        return true;
+
+    RefPtr<Document> protect(this);
+
+    RefPtr<BeforeUnloadEvent> beforeUnloadEvent = BeforeUnloadEvent::create();
+    m_loadEventProgress = BeforeUnloadEventInProgress;
+    dispatchWindowEvent(beforeUnloadEvent.get(), this);
+    m_loadEventProgress = BeforeUnloadEventCompleted;
+    if (!beforeUnloadEvent->defaultPrevented())
+        defaultEventHandler(beforeUnloadEvent.get());
+    if (beforeUnloadEvent->result().isNull())
+        return true;
+
+    if (navigatingDocument->m_didAllowNavigationViaBeforeUnloadConfirmationPanel) {
+        addConsoleMessage(JSMessageSource, ErrorMessageLevel, "Blocked attempt to show multiple 'beforeunload' confirmation panels for a single navigation.");
+        return true;
+    }
+
+    String text = displayStringModifiedByEncoding(beforeUnloadEvent->result());
+    if (chrome.runBeforeUnloadConfirmPanel(text, m_frame)) {
+        navigatingDocument->m_didAllowNavigationViaBeforeUnloadConfirmationPanel = true;
+        return true;
+    }
+    return false;
+}
+
+void Document::dispatchUnloadEvents()
+{
+    RefPtr<Document> protect(this);
+    if (m_parser)
+        m_parser->stopParsing();
+
+    if (m_loadEventProgress >= LoadEventTried && m_loadEventProgress <= UnloadEventInProgress) {
+        Element* currentFocusedElement = focusedElement();
+        if (currentFocusedElement && currentFocusedElement->hasTagName(inputTag))
+            toHTMLInputElement(currentFocusedElement)->endEditing();
+        if (m_loadEventProgress < PageHideInProgress) {
+            m_loadEventProgress = PageHideInProgress;
+            dispatchWindowEvent(PageTransitionEvent::create(eventNames().pagehideEvent, false), this);
+            if (!m_frame)
+                return;
+
+            // The DocumentLoader (and thus its DocumentLoadTiming) might get destroyed
+            // while dispatching the event, so protect it to prevent writing the end
+            // time into freed memory.
+            RefPtr<DocumentLoader> documentLoader =  m_frame->loader()->provisionalDocumentLoader();
+            m_loadEventProgress = UnloadEventInProgress;
+            RefPtr<Event> unloadEvent(Event::create(eventNames().unloadEvent, false, false));
+            if (documentLoader && !documentLoader->timing()->unloadEventStart() && !documentLoader->timing()->unloadEventEnd()) {
+                DocumentLoadTiming* timing = documentLoader->timing();
+                ASSERT(timing->navigationStart());
+                timing->markUnloadEventStart();
+                dispatchWindowEvent(unloadEvent, this);
+                timing->markUnloadEventEnd();
+            } else {
+                m_frame->domWindow()->dispatchEvent(unloadEvent, m_frame->document());
+            }
+        }
+        updateStyleIfNeeded();
+        m_loadEventProgress = UnloadEventHandled;
+    }
+
+    if (!m_frame)
+        return;
+
+    // Don't remove event listeners from a transitional empty document (see https://bugs.webkit.org/show_bug.cgi?id=28716 for more information).
+    bool keepEventListeners = m_frame->loader()->stateMachine()->isDisplayingInitialEmptyDocument() && m_frame->loader()->provisionalDocumentLoader()
+        && isSecureTransitionTo(m_frame->loader()->provisionalDocumentLoader()->url());
+    if (!keepEventListeners)
+        removeAllEventListeners();
+}
+
+Document::PageDismissalType Document::pageDismissalEventBeingDispatched() const
+{
+    if (m_loadEventProgress == BeforeUnloadEventInProgress)
+        return BeforeUnloadDismissal;
+    if (m_loadEventProgress == PageHideInProgress)
+        return PageHideDismissal;
+    if (m_loadEventProgress == UnloadEventInProgress)
+        return UnloadDismissal;
+    return NoDismissal;
+}
+
 void Document::setParsing(bool b)
 {
     m_bParsing = b;
@@ -2424,7 +2515,7 @@
 
 void Document::logExceptionToConsole(const String& errorMessage, const String& sourceURL, int lineNumber, int columnNumber, PassRefPtr<ScriptCallStack> callStack)
 {
-    addMessage(JSMessageSource, ErrorMessageLevel, errorMessage, sourceURL, lineNumber, callStack);
+    internalAddMessage(JSMessageSource, ErrorMessageLevel, errorMessage, sourceURL, lineNumber, callStack, 0);
 }
 
 void Document::setURL(const KURL& url)
@@ -2613,6 +2704,7 @@
 
 void Document::seamlessParentUpdatedStylesheets()
 {
+    m_styleSheetCollection->didModifySeamlessParentStyleSheet();
     styleResolverChanged(RecalcStyleImmediately);
 }
 
@@ -2690,7 +2782,7 @@
     // -dwh
     m_styleSheetCollection->setSelectedStylesheetSetName(content);
     m_styleSheetCollection->setPreferredStylesheetSetName(content);
-    styleResolverChanged(DeferRecalcStyle);
+    styleResolverChanged(RecalcStyleDeferred);
 }
 
 void Document::processHttpEquivRefresh(const String& content)
@@ -2751,10 +2843,15 @@
         // intent, we must navigate away from the possibly partially-rendered document to a location that
         // doesn't inherit the parent's SecurityOrigin.
         frame->navigationScheduler()->scheduleLocationChange(securityOrigin(), SecurityOrigin::urlWithUniqueSecurityOrigin(), String());
-        addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, message, requestIdentifier);
+        addConsoleMessageWithRequestIdentifier(SecurityMessageSource, ErrorMessageLevel, message, requestIdentifier);
     }
 }
 
+static bool isInvalidSeparator(UChar c)
+{
+    return c == ';';
+}
+
 // Though isspace() considers \t and \v to be whitespace, Win IE doesn't.
 static bool isSeparator(UChar c)
 {
@@ -2763,6 +2860,8 @@
 
 void Document::processArguments(const String& features, void* data, ArgumentsCallback callback)
 {
+    bool error = false;
+
     // Tread lightly in this code -- it was specifically designed to mimic Win IE's parsing behavior.
     int keyBegin, keyEnd;
     int valueBegin, valueEnd;
@@ -2780,12 +2879,15 @@
         keyBegin = i;
 
         // skip to first separator
-        while (!isSeparator(buffer[i]))
+        while (!isSeparator(buffer[i])) {
+            error |= isInvalidSeparator(buffer[i]);
             i++;
+        }
         keyEnd = i;
 
         // skip to first '=', but don't skip past a ',' or the end of the string
         while (buffer[i] != '=') {
+            error |= isInvalidSeparator(buffer[i]);
             if (buffer[i] == ',' || i >= length)
                 break;
             i++;
@@ -2800,8 +2902,10 @@
         valueBegin = i;
 
         // skip to first separator
-        while (!isSeparator(buffer[i]))
+        while (!isSeparator(buffer[i])) {
+            error |= isInvalidSeparator(buffer[i]);
             i++;
+        }
         valueEnd = i;
 
         ASSERT_WITH_SECURITY_IMPLICATION(i <= length);
@@ -2810,6 +2914,8 @@
         String valueString = buffer.substring(valueBegin, valueEnd - valueBegin);
         callback(keyString, valueString, this, data);
     }
+    if (error)
+        reportViewportWarning(this, InvalidKeyValuePairSeparatorError, String(), String());
 }
 
 void Document::processViewport(const String& features, ViewportArguments::Type origin)
@@ -2982,31 +3088,11 @@
     return true;
 }
 
-PassRefPtr<Node> Document::cloneNode(bool deep)
+PassRefPtr<Node> Document::cloneNode(bool /*deep*/)
 {
-    RefPtr<Document> clone = cloneDocumentWithoutChildren();
-    clone->cloneDataFromDocument(*this);
-    if (deep)
-        cloneChildNodes(clone.get());
-    return clone.release();
-}
-
-PassRefPtr<Document> Document::cloneDocumentWithoutChildren()
-{
-    return create();
-}
-
-void Document::cloneDataFromDocument(const Document& other)
-{
-    m_url = other.url();
-    m_baseURL = other.baseURL();
-    m_baseURLOverride = other.baseURLOverride();
-    m_documentURI = other.documentURI();
-
-    setCompatibilityMode(other.compatibilityMode());
-    setContextFeatures(other.contextFeatures());
-    setSecurityOrigin(other.securityOrigin());
-    setDecoder(other.decoder());
+    // Spec says cloning Document nodes is "implementation dependent"
+    // so we do not support it...
+    return 0;
 }
 
 StyleSheetList* Document::styleSheets()
@@ -3029,7 +3115,7 @@
 void Document::setSelectedStylesheetSet(const String& aString)
 {
     m_styleSheetCollection->setSelectedStylesheetSetName(aString);
-    styleResolverChanged(DeferRecalcStyle);
+    styleResolverChanged(RecalcStyleDeferred);
 }
 
 void Document::evaluateMediaQueryList()
@@ -3050,7 +3136,7 @@
 
     bool needsRecalc = m_styleSheetCollection->updateActiveStyleSheets(updateMode);
 
-    if (updateType >= DeferRecalcStyle) {
+    if (updateType >= RecalcStyleDeferred) {
         setNeedsStyleRecalc();
         return;
     }
@@ -3276,7 +3362,7 @@
         m_focusedElement->setFocus(true);
 
         if (m_focusedElement->isRootEditableElement())
-            frame()->editor()->didBeginEditing();
+            frame()->editor()->didBeginEditing(m_focusedElement.get());
 
         // eww, I suck. set the qt focus correctly
         // ### find a better place in the code for this
@@ -3571,7 +3657,7 @@
 
 String Document::cookie(ExceptionState& es) const
 {
-    if (page() && !page()->settings()->cookieEnabled())
+    if (page() && !page()->settings().cookieEnabled())
         return String();
 
     // FIXME: The HTML5 DOM spec states that this attribute can raise an
@@ -3579,7 +3665,13 @@
     // browsing context.
 
     if (!securityOrigin()->canAccessCookies()) {
-        es.throwDOMException(SecurityError);
+        String accessDeniedMessage = "Access to 'cookie' is denied for this document.";
+        if (isSandboxed(SandboxOrigin))
+            es.throwSecurityError(accessDeniedMessage + " The document is sandboxed and lacks the 'allow-same-origin' flag.");
+        else if (url().protocolIs("data"))
+            es.throwSecurityError(accessDeniedMessage + " Cookies are disabled inside 'data:' URLs.");
+        else
+            es.throwSecurityError(accessDeniedMessage);
         return String();
     }
 
@@ -3592,7 +3684,7 @@
 
 void Document::setCookie(const String& value, ExceptionState& es)
 {
-    if (page() && !page()->settings()->cookieEnabled())
+    if (page() && !page()->settings().cookieEnabled())
         return;
 
     // FIXME: The HTML5 DOM spec states that this attribute can raise an
@@ -3600,7 +3692,13 @@
     // browsing context.
 
     if (!securityOrigin()->canAccessCookies()) {
-        es.throwDOMException(SecurityError);
+        String accessDeniedMessage = "Access to 'cookie' is denied for this document.";
+        if (isSandboxed(SandboxOrigin))
+            es.throwSecurityError(accessDeniedMessage + " The document is sandboxed and lacks the 'allow-same-origin' flag.");
+        else if (url().protocolIs("data"))
+            es.throwSecurityError(accessDeniedMessage + " Cookies are disabled inside 'data:' URLs.");
+        else
+            es.throwSecurityError(accessDeniedMessage);
         return;
     }
 
@@ -3613,8 +3711,8 @@
 
 String Document::referrer() const
 {
-    if (frame())
-        return frame()->loader()->referrer();
+    if (loader())
+        return loader()->request().httpReferrer();
     return String();
 }
 
@@ -3626,7 +3724,7 @@
 void Document::setDomain(const String& newDomain, ExceptionState& es)
 {
     if (SchemeRegistry::isDomainRelaxationForbiddenForURLScheme(securityOrigin()->protocol())) {
-        es.throwDOMException(SecurityError, "'document.domain' assignment is forbidden for the '" + securityOrigin()->protocol() + "' scheme.");
+        es.throwSecurityError(ExceptionMessages::failedToSet("domain", "Document", "assignment is forbidden for the '" + securityOrigin()->protocol() + "' scheme."));
         return;
     }
 
@@ -3648,17 +3746,17 @@
 
     int oldLength = domain().length();
     int newLength = newDomain.length();
-    String exceptionMessage =  "'document.domain' assignment failed: '" + newDomain + "' is not a suffix of '" + domain() + "'.";
+    String exceptionMessage =  ExceptionMessages::failedToSet("domain", "Document", "'" + newDomain + "' is not a suffix of '" + domain() + "'.");
     // e.g. newDomain = subdomain.www.example.com (25) and domain() = www.example.com (15)
     if (newLength >= oldLength) {
-        es.throwDOMException(SecurityError, exceptionMessage);
+        es.throwSecurityError(exceptionMessage);
         return;
     }
 
     String test = domain();
     // Check that it's a complete suffix, not e.g. "ample.com"
     if (test[oldLength - newLength - 1] != '.') {
-        es.throwDOMException(SecurityError, exceptionMessage);
+        es.throwSecurityError(exceptionMessage);
         return;
     }
 
@@ -3666,7 +3764,7 @@
     // and we check that it's the same thing as newDomain
     test.remove(0, oldLength - newLength);
     if (test != newDomain) {
-        es.throwDOMException(SecurityError, exceptionMessage);
+        es.throwSecurityError(exceptionMessage);
         return;
     }
 
@@ -4447,18 +4545,34 @@
     m_haveExplicitlyDisabledDNSPrefetch = true;
 }
 
-void Document::addConsoleMessage(MessageSource source, MessageLevel level, const String& message, unsigned long requestIdentifier)
+void Document::addMessage(MessageSource source, MessageLevel level, const String& message, const String& sourceURL, unsigned lineNumber, ScriptState* state)
 {
-    if (!isContextThread()) {
-        postTask(AddConsoleMessageTask::create(source, level, message));
-        return;
-    }
-
-    if (Page* page = this->page())
-        page->console()->addMessage(source, level, message, requestIdentifier, this);
+    internalAddMessage(source, level, message, sourceURL, lineNumber, 0, state);
 }
 
-void Document::addMessage(MessageSource source, MessageLevel level, const String& message, const String& sourceURL, unsigned lineNumber, PassRefPtr<ScriptCallStack> callStack, ScriptState* state, unsigned long requestIdentifier)
+void Document::internalAddMessage(MessageSource source, MessageLevel level, const String& message, const String& sourceURL, unsigned lineNumber, PassRefPtr<ScriptCallStack> callStack, ScriptState* state)
+{
+    if (!isContextThread()) {
+        postTask(AddConsoleMessageTask::create(source, level, message));
+        return;
+    }
+    Page* page = this->page();
+    if (!page)
+        return;
+
+    String messageURL = sourceURL;
+    if (!state && sourceURL.isNull() && !lineNumber) {
+        messageURL = url().string();
+        if (parsing() && !isInDocumentWrite() && scriptableDocumentParser()) {
+            ScriptableDocumentParser* parser = scriptableDocumentParser();
+            if (!parser->isWaitingForScripts() && !parser->isExecutingScript())
+                lineNumber = parser->lineNumber().oneBasedInt();
+        }
+    }
+    page->console().addMessage(source, level, message, messageURL, lineNumber, 0, callStack, state, 0);
+}
+
+void Document::addConsoleMessageWithRequestIdentifier(MessageSource source, MessageLevel level, const String& message, unsigned long requestIdentifier)
 {
     if (!isContextThread()) {
         postTask(AddConsoleMessageTask::create(source, level, message));
@@ -4466,7 +4580,7 @@
     }
 
     if (Page* page = this->page())
-        page->console()->addMessage(source, level, message, sourceURL, lineNumber, 0, callStack, state, requestIdentifier);
+        page->console().addMessage(source, level, message, String(), 0, 0, 0, 0, requestIdentifier);
 }
 
 struct PerformTaskContext {
@@ -4632,18 +4746,18 @@
 {
     if (!page())
         return;
-    if (Element* target = page()->pointerLockController()->element()) {
+    if (Element* target = page()->pointerLockController().element()) {
         if (target->document() != this)
             return;
     }
-    page()->pointerLockController()->requestPointerUnlock();
+    page()->pointerLockController().requestPointerUnlock();
 }
 
 Element* Document::webkitPointerLockElement() const
 {
-    if (!page() || page()->pointerLockController()->lockPending())
+    if (!page() || page()->pointerLockController().lockPending())
         return 0;
-    if (Element* element = page()->pointerLockController()->element()) {
+    if (Element* element = page()->pointerLockController().element()) {
         if (element->document() == this)
             return element;
     }
@@ -4752,7 +4866,7 @@
         if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
             scrollingCoordinator->touchEventTargetRectsDidChange(this);
         if (m_touchEventTargets->size() == 1)
-            page->chrome().client()->needTouchEvents(true);
+            page->chrome().client().needTouchEvents(true);
     }
 }
 
@@ -4760,7 +4874,9 @@
 {
     if (!m_touchEventTargets.get())
         return;
-    ASSERT(m_touchEventTargets->contains(handler));
+    // TODO(rbyers): Re-enable this ASSERT - http://crbug.com/254203.
+    // The known failure is benign, but the fix somehow causes a perf regression.
+    // ASSERT(m_touchEventTargets->contains(handler));
     m_touchEventTargets->remove(handler);
     if (Document* parent = parentDocument()) {
         parent->didRemoveTouchEventHandler(this);
@@ -4778,17 +4894,14 @@
         if (frame->document() && frame->document()->hasTouchEventHandlers())
             return;
     }
-    page->chrome().client()->needTouchEvents(false);
+    page->chrome().client().needTouchEvents(false);
 }
 
 void Document::didRemoveEventTargetNode(Node* handler)
 {
     if (m_touchEventTargets) {
-        if (handler == this)
-            m_touchEventTargets->clear();
-        else
-            m_touchEventTargets->removeAll(handler);
-        if (m_touchEventTargets->isEmpty() && parentDocument())
+        m_touchEventTargets->removeAll(handler);
+        if ((handler == this || m_touchEventTargets->isEmpty()) && parentDocument())
             parentDocument()->didRemoveEventTargetNode(this);
     }
 }
@@ -5121,7 +5234,7 @@
     Vector<RefPtr<Element> > associatedFormControls;
     copyToVector(m_associatedFormControls, associatedFormControls);
 
-    frame()->page()->chrome().client()->didAssociateFormControls(associatedFormControls);
+    frame()->page()->chrome().client().didAssociateFormControls(associatedFormControls);
     m_associatedFormControls.clear();
 }
 
diff --git a/Source/core/dom/Document.h b/Source/core/dom/Document.h
index cd90543..f0145de 100644
--- a/Source/core/dom/Document.h
+++ b/Source/core/dom/Document.h
@@ -30,6 +30,7 @@
 
 #include "bindings/v8/ScriptValue.h"
 #include "core/dom/ContainerNode.h"
+#include "core/dom/CustomElement.h"
 #include "core/dom/DOMTimeStamp.h"
 #include "core/dom/DocumentEventQueue.h"
 #include "core/dom/DocumentInit.h"
@@ -67,6 +68,7 @@
 class ScriptResource;
 class CanvasRenderingContext;
 class CharacterData;
+class Chrome;
 class Comment;
 class ContentSecurityPolicyResponseHeaders;
 class ContextFeatures;
@@ -168,9 +170,7 @@
     PageshowEventPersisted = 1
 };
 
-// FIXME: We should rename DeferRecalcStyle to RecalcStyleDeferred to be consitent.
-
-enum StyleResolverUpdateType { RecalcStyleImmediately, DeferRecalcStyle };
+enum StyleResolverUpdateType { RecalcStyleImmediately, RecalcStyleDeferred };
 
 enum StyleResolverUpdateMode {
     // Discards the StyleResolver and rebuilds it.
@@ -259,6 +259,7 @@
     DEFINE_ATTRIBUTE_EVENT_LISTENER(scroll);
     DEFINE_ATTRIBUTE_EVENT_LISTENER(select);
     DEFINE_ATTRIBUTE_EVENT_LISTENER(submit);
+    DEFINE_ATTRIBUTE_EVENT_LISTENER(wheel);
 
     DEFINE_ATTRIBUTE_EVENT_LISTENER(blur);
     DEFINE_ATTRIBUTE_EVENT_LISTENER(error);
@@ -448,9 +449,9 @@
 
     // FIXME: Switch all callers of styleResolverChanged to these or better ones and then make them
     // do something smarter.
-    void removedStyleSheet(StyleSheet*, StyleResolverUpdateType type = DeferRecalcStyle) { styleResolverChanged(type); }
-    void addedStyleSheet(StyleSheet*, StyleResolverUpdateType type = DeferRecalcStyle) { styleResolverChanged(type); }
-    void modifiedStyleSheet(StyleSheet*, StyleResolverUpdateType type = DeferRecalcStyle) { styleResolverChanged(type); }
+    void removedStyleSheet(StyleSheet*, StyleResolverUpdateType type = RecalcStyleDeferred) { styleResolverChanged(type); }
+    void addedStyleSheet(StyleSheet*, StyleResolverUpdateType type = RecalcStyleDeferred) { styleResolverChanged(type); }
+    void modifiedStyleSheet(StyleSheet*, StyleResolverUpdateType type = RecalcStyleDeferred) { styleResolverChanged(type); }
 
     void didAccessStyleResolver();
 
@@ -545,6 +546,17 @@
     // implicitClose() actually does the work of closing the input stream.
     void implicitClose();
 
+    bool dispatchBeforeUnloadEvent(Chrome&, Document* navigatingDocument);
+    void dispatchUnloadEvents();
+
+    enum PageDismissalType {
+        NoDismissal = 0,
+        BeforeUnloadDismissal = 1,
+        PageHideDismissal = 2,
+        UnloadDismissal = 3
+    };
+    PageDismissalType pageDismissalEventBeingDispatched() const;
+
     void cancelParsing();
 
     void write(const SegmentedString& text, Document* ownerDocument = 0);
@@ -754,6 +766,8 @@
     String title() const { return m_title.string(); }
     void setTitle(const String&);
 
+    const StringWithDirection& titleWithDirection() const { return m_title; }
+
     Element* titleElement() const { return m_titleElement.get(); }
     void setTitleElement(const StringWithDirection&, Element* titleElement);
     void removeTitle(Element* titleElement);
@@ -914,15 +928,15 @@
         LoadEventTried,
         LoadEventInProgress,
         LoadEventCompleted,
+        BeforeUnloadEventInProgress,
+        BeforeUnloadEventCompleted,
+        PageHideInProgress,
         UnloadEventInProgress,
         UnloadEventHandled
     };
     bool loadEventStillNeeded() const { return m_loadEventProgress == LoadEventNotRun; }
     bool processingLoadEvent() const { return m_loadEventProgress == LoadEventInProgress; }
     bool loadEventFinished() const { return m_loadEventProgress >= LoadEventCompleted; }
-    bool unloadEventStillNeeded() const { return m_loadEventProgress >= LoadEventTried && m_loadEventProgress <= UnloadEventInProgress; }
-    void unloadEventStarted() { m_loadEventProgress = UnloadEventInProgress; }
-    void unloadEventWasHandled() { m_loadEventProgress = UnloadEventHandled; }
 
     virtual bool isContextThread() const;
     virtual bool isJSExecutionForbidden() const { return false; }
@@ -994,7 +1008,8 @@
     PassRefPtr<Element> createElement(const AtomicString& localName, const AtomicString& typeExtension, ExceptionState&);
     PassRefPtr<Element> createElementNS(const AtomicString& namespaceURI, const String& qualifiedName, const AtomicString& typeExtension, ExceptionState&);
     ScriptValue registerElement(WebCore::ScriptState*, const AtomicString& name, ExceptionState&);
-    ScriptValue registerElement(WebCore::ScriptState*, const AtomicString& name, const Dictionary& options, ExceptionState&);
+    // FIXME: When embedders switch to using WebDocument::registerEmbedderCustomElement, make the default name set StandardNames.
+    ScriptValue registerElement(WebCore::ScriptState*, const AtomicString& name, const Dictionary& options, ExceptionState&, CustomElement::NameSet validNames = CustomElement::AllNames);
     CustomElementRegistrationContext* registrationContext() { return m_registrationContext.get(); }
 
     void setImport(HTMLImport*);
@@ -1011,7 +1026,7 @@
     void decrementActiveParserCount();
 
     void setContextFeatures(PassRefPtr<ContextFeatures>);
-    ContextFeatures* contextFeatures() const { return m_contextFeatures.get(); }
+    ContextFeatures* contextFeatures() { return m_contextFeatures.get(); }
 
     DocumentSharedObjectPool* sharedObjectPool() { return m_sharedObjectPool.get(); }
 
@@ -1039,7 +1054,7 @@
 
     void didAssociateFormControl(Element*);
 
-    virtual void addConsoleMessage(MessageSource, MessageLevel, const String& message, unsigned long requestIdentifier = 0);
+    void addConsoleMessageWithRequestIdentifier(MessageSource, MessageLevel, const String& message, unsigned long requestIdentifier);
 
     virtual DOMWindow* executingWindow() OVERRIDE { return domWindow(); }
     virtual void userEventWasHandled() OVERRIDE { resetLastHandledUserGestureTimestamp(); }
@@ -1062,8 +1077,6 @@
 
     virtual void dispose() OVERRIDE;
 
-    virtual PassRefPtr<Document> cloneDocumentWithoutChildren();
-
 private:
     friend class Node;
     friend class IgnoreDestructiveWriteCountIncrementer;
@@ -1083,7 +1096,6 @@
     virtual NodeType nodeType() const;
     virtual bool childTypeAllowed(NodeType) const;
     virtual PassRefPtr<Node> cloneNode(bool deep = true);
-    void cloneDataFromDocument(const Document&);
 
     virtual void refScriptExecutionContext() { ref(); }
     virtual void derefScriptExecutionContext() { deref(); }
@@ -1092,7 +1104,8 @@
     virtual const KURL& virtualURL() const; // Same as url(), but needed for ScriptExecutionContext to implement it without a performance loss for direct calls.
     virtual KURL virtualCompleteURL(const String&) const; // Same as completeURL() for the same reason as above.
 
-    virtual void addMessage(MessageSource, MessageLevel, const String& message, const String& sourceURL, unsigned lineNumber, PassRefPtr<ScriptCallStack>, ScriptState* = 0, unsigned long requestIdentifier = 0);
+    virtual void addMessage(MessageSource, MessageLevel, const String& message, const String& sourceURL, unsigned lineNumber, ScriptState*);
+    void internalAddMessage(MessageSource, MessageLevel, const String& message, const String& sourceURL, unsigned lineNumber, PassRefPtr<ScriptCallStack>, ScriptState*);
 
     virtual double timerAlignmentInterval() const;
 
@@ -1226,7 +1239,6 @@
 
     Timer<Document> m_styleRecalcTimer;
     bool m_inStyleRecalc;
-    bool m_closeAfterStyleRecalc;
 
     bool m_gotoAnchorNeededAfterStylesheetsLoad;
     bool m_isDNSPrefetchEnabled;
@@ -1317,6 +1329,8 @@
     bool m_directionSetOnDocumentElement;
     bool m_writingModeSetOnDocumentElement;
 
+    bool m_didAllowNavigationViaBeforeUnloadConfirmationPanel;
+
     DocumentTiming m_documentTiming;
     RefPtr<MediaQueryMatcher> m_mediaQueryMatcher;
     bool m_writeRecursionIsTooDeep;
diff --git a/Source/core/dom/Document.idl b/Source/core/dom/Document.idl
index 0fc91ba..bea2b66 100644
--- a/Source/core/dom/Document.idl
+++ b/Source/core/dom/Document.idl
@@ -33,10 +33,10 @@
     DocumentFragment   createDocumentFragment();
     [PerWorldBindings] Text createTextNode([Default=Undefined] optional DOMString data);
     Comment createComment([Default=Undefined] optional DOMString data);
-    [RaisesException] CDATASection createCDATASection([Default=Undefined] optional DOMString data);
+    [RaisesException, MeasureAs=DocumentCreateCDATASection] CDATASection createCDATASection([Default=Undefined] optional DOMString data); // Removed from DOM4.
     [RaisesException] ProcessingInstruction createProcessingInstruction([Default=Undefined] optional DOMString target,
                                                                                  [Default=Undefined] optional DOMString data);
-    [RaisesException] Attr createAttribute([Default=Undefined] optional DOMString name);
+    [RaisesException, MeasureAs=DocumentCreateAttribute] Attr createAttribute([Default=Undefined] optional DOMString name); // Removed from DOM4.
     [PerWorldBindings] NodeList           getElementsByTagName([Default=Undefined] optional DOMString tagname);
 
     // Introduced in DOM Level 2:
@@ -45,19 +45,19 @@
                     optional boolean deep);
     [CustomElementCallbacks=Enable, PerWorldBindings, ActivityLog=AccessForIsolatedWorlds, RaisesException] Element createElementNS([TreatNullAs=NullString,Default=Undefined] optional DOMString namespaceURI,
                             [TreatNullAs=NullString,Default=Undefined] optional DOMString qualifiedName);
-    [RaisesException] Attr createAttributeNS([TreatNullAs=NullString,Default=Undefined] optional DOMString namespaceURI,
-                                                                          [TreatNullAs=NullString,Default=Undefined] optional DOMString qualifiedName);
+    [RaisesException, MeasureAs=DocumentCreateAttributeNS] Attr createAttributeNS([TreatNullAs=NullString,Default=Undefined] optional DOMString namespaceURI,
+                                                                                  [TreatNullAs=NullString,Default=Undefined] optional DOMString qualifiedName); // Removed from DOM4.
      NodeList getElementsByTagNameNS([TreatNullAs=NullString,Default=Undefined] optional DOMString namespaceURI,
                                                    [Default=Undefined] optional DOMString localName);
     [PerWorldBindings] Element            getElementById([Default=Undefined] optional DOMString elementId);
 
     // DOM Level 3 Core
 
-    [TreatReturnedNullStringAs=Null] readonly attribute DOMString inputEncoding;
+    [TreatReturnedNullStringAs=Null, MeasureAs=DocumentInputEncoding] readonly attribute DOMString inputEncoding; // Removed from DOM4.
 
-    [TreatReturnedNullStringAs=Null] readonly attribute DOMString xmlEncoding;
-             [TreatReturnedNullStringAs=Null, TreatNullAs=NullString, SetterRaisesException] attribute DOMString xmlVersion;
-             [SetterRaisesException] attribute boolean xmlStandalone;
+    [TreatReturnedNullStringAs=Null, MeasureAs=DocumentXMLEncoding] readonly attribute DOMString xmlEncoding; // Removed from DOM4.
+    [TreatReturnedNullStringAs=Null, TreatNullAs=NullString, SetterRaisesException, MeasureAs=DocumentXMLVersion] attribute DOMString xmlVersion; // Removed from DOM4.
+    [SetterRaisesException, MeasureAs=DocumentXMLStandalone] attribute boolean xmlStandalone; // Removed from DOM4.
 
     [RaisesException, CustomElementCallbacks=Enable] Node               adoptNode([Default=Undefined] optional Node source);
 
@@ -133,9 +133,8 @@
     [Custom, Replaceable, PerWorldBindings, ActivityLog=AccessForIsolatedWorlds] readonly attribute Location location;
 
     // IE extensions
-
-             [TreatReturnedNullStringAs=Undefined, TreatNullAs=NullString] attribute DOMString charset;
-    [TreatReturnedNullStringAs=Undefined] readonly attribute DOMString defaultCharset;
+    [MeasureAs=DocumentCharset, TreatReturnedNullStringAs=Undefined, TreatNullAs=NullString] attribute DOMString charset;
+    [MeasureAs=DocumentCharset, TreatReturnedNullStringAs=Undefined] readonly attribute DOMString defaultCharset;
     [TreatReturnedNullStringAs=Undefined] readonly attribute DOMString readyState;
 
     Element            elementFromPoint([Default=Undefined] optional long x,
@@ -199,7 +198,8 @@
     [NotEnumerable, PerWorldBindings, ActivityLog=SetterForIsolatedWorlds] attribute EventHandler onmouseout;
     [NotEnumerable, PerWorldBindings, ActivityLog=SetterForIsolatedWorlds] attribute EventHandler onmouseover;
     [NotEnumerable, PerWorldBindings, ActivityLog=SetterForIsolatedWorlds] attribute EventHandler onmouseup;
-    [NotEnumerable, PerWorldBindings, ActivityLog=SetterForIsolatedWorlds] attribute EventHandler onmousewheel;
+    [NotEnumerable, PerWorldBindings, ActivityLog=SetterForIsolatedWorlds] attribute EventHandler onmousewheel; // Deprecated in favor of onwheel.
+    [NotEnumerable, PerWorldBindings, ActivityLog=SetterForIsolatedWorlds] attribute EventHandler onwheel;
     [NotEnumerable] attribute EventHandler onreadystatechange;
     [NotEnumerable] attribute EventHandler onscroll;
     [NotEnumerable] attribute EventHandler onselect;
@@ -261,8 +261,8 @@
                                                [Default=Undefined] optional float webkitForce);
     [EnabledAtRuntime=touch, Custom, RaisesException] TouchList createTouchList();
 
-    [DeprecateAs=PrefixedDocumentRegister, EnabledAtRuntime=customDOMElements, ImplementedAs=registerElement, CallWith=ScriptState, CustomElementCallbacks=Enable, RaisesException] CustomElementConstructor webkitRegister(DOMString name, optional Dictionary options);
-    [EnabledAtRuntime=customDOMElements, ImplementedAs=registerElement, CallWith=ScriptState, CustomElementCallbacks=Enable, RaisesException] CustomElementConstructor register(DOMString name, optional Dictionary options);
+    [DeprecateAs=PrefixedDocumentRegister, EnabledAtRuntime=customElements, ImplementedAs=registerElement, CallWith=ScriptState, CustomElementCallbacks=Enable, RaisesException] CustomElementConstructor webkitRegister(DOMString name, optional Dictionary options);
+    [EnabledAtRuntime=customElements, ImplementedAs=registerElement, CallWith=ScriptState, CustomElementCallbacks=Enable, RaisesException] CustomElementConstructor register(DOMString name, optional Dictionary options);
     [CustomElementCallbacks=Enable, PerWorldBindings, ActivityLog=AccessForIsolatedWorlds, RaisesException] Element createElement(DOMString localName, [TreatNullAs=NullString] DOMString typeExtension);
     [CustomElementCallbacks=Enable, PerWorldBindings, ActivityLog=AccessForIsolatedWorlds, RaisesException] Element createElementNS([TreatNullAs=NullString] DOMString namespaceURI, DOMString qualifiedName,
                             [TreatNullAs=NullString] DOMString typeExtension);
diff --git a/Source/core/dom/DocumentInit.cpp b/Source/core/dom/DocumentInit.cpp
index 8c508d4..caa4f8f 100644
--- a/Source/core/dom/DocumentInit.cpp
+++ b/Source/core/dom/DocumentInit.cpp
@@ -88,7 +88,7 @@
 
 PassRefPtr<CustomElementRegistrationContext> DocumentInit::registrationContext(Document* document) const
 {
-    if (!RuntimeEnabledFeatures::customDOMElementsEnabled())
+    if (!RuntimeEnabledFeatures::customElementsEnabled() && !RuntimeEnabledFeatures::embedderCustomElementsEnabled())
         return 0;
 
     if (!document->isHTMLDocument() && !document->isXHTMLDocument())
diff --git a/Source/core/dom/DocumentMarkerController.cpp b/Source/core/dom/DocumentMarkerController.cpp
index c47e8b8..168772b 100644
--- a/Source/core/dom/DocumentMarkerController.cpp
+++ b/Source/core/dom/DocumentMarkerController.cpp
@@ -160,7 +160,7 @@
             DocumentMarker marker = list->at(i);
             if (marker.startOffset() > toInsert.startOffset())
                 break;
-            if (marker.type() == toInsert.type() && marker.endOffset() >= toInsert.startOffset()) {
+            if (marker.type() == toInsert.type() && marker.type() != DocumentMarker::TextMatch && marker.endOffset() >= toInsert.startOffset()) {
                 toInsert.setStartOffset(marker.startOffset());
                 list->remove(i);
                 numMarkers--;
@@ -175,7 +175,7 @@
             DocumentMarker marker = list->at(j);
             if (marker.startOffset() > toInsert.endOffset())
                 break;
-            if (marker.type() == toInsert.type()) {
+            if (marker.type() == toInsert.type() && marker.type() != DocumentMarker::TextMatch) {
                 list->remove(j);
                 if (toInsert.endOffset() <= marker.endOffset()) {
                     toInsert.setEndOffset(marker.endOffset());
@@ -608,7 +608,7 @@
             break;
 
         // Skip marker that is wrong type or before target.
-        if (marker.endOffset() < startOffset || marker.type() != DocumentMarker::TextMatch)
+        if (marker.endOffset() <= startOffset || marker.type() != DocumentMarker::TextMatch)
             continue;
 
         marker.setActiveMatch(active);
diff --git a/Source/core/dom/DocumentOrderedMap.cpp b/Source/core/dom/DocumentOrderedMap.cpp
index ee4c389..bd58170 100644
--- a/Source/core/dom/DocumentOrderedMap.cpp
+++ b/Source/core/dom/DocumentOrderedMap.cpp
@@ -33,11 +33,10 @@
 
 #include "HTMLNames.h"
 #include "core/dom/Element.h"
-#include "core/dom/NodeTraversal.h"
+#include "core/dom/ElementTraversal.h"
 #include "core/dom/TreeScope.h"
 #include "core/html/HTMLLabelElement.h"
 #include "core/html/HTMLMapElement.h"
-#include "core/html/HTMLNameCollection.h"
 
 namespace WebCore {
 
@@ -48,11 +47,6 @@
     return element->getIdAttribute().impl() == key;
 }
 
-inline bool keyMatchesName(StringImpl* key, Element* element)
-{
-    return element->getNameAttribute().impl() == key;
-}
-
 inline bool keyMatchesMapName(StringImpl* key, Element* element)
 {
     return element->hasTagName(mapTag) && toHTMLMapElement(element)->getName().impl() == key;
@@ -71,6 +65,7 @@
 void DocumentOrderedMap::clear()
 {
     m_map.clear();
+    m_duplicateCounts.clear();
 }
 
 void DocumentOrderedMap::add(StringImpl* key, Element* element)
@@ -78,15 +73,29 @@
     ASSERT(key);
     ASSERT(element);
 
-    Map::AddResult addResult = m_map.add(key, MapEntry(element));
-    if (addResult.isNewEntry)
-        return;
+    if (!m_duplicateCounts.contains(key)) {
+        // Fast path. The key is not already in m_duplicateCounts, so we assume that it's
+        // also not already in m_map and try to add it. If that add succeeds, we're done.
+        Map::AddResult addResult = m_map.add(key, element);
+        if (addResult.isNewEntry)
+            return;
 
-    MapEntry& entry = addResult.iterator->value;
-    ASSERT(entry.count);
-    entry.element = 0;
-    entry.count++;
-    entry.orderedList.clear();
+        // The add failed, so this key was already cached in m_map.
+        // There are multiple elements with this key. Remove the m_map
+        // cache for this key so get searches for it next time it is called.
+        m_map.remove(addResult.iterator);
+        m_duplicateCounts.add(key);
+    } else {
+        // There are multiple elements with this key. Remove the m_map
+        // cache for this key so get will search for it next time it is called.
+        Map::iterator cachedItem = m_map.find(key);
+        if (cachedItem != m_map.end()) {
+            m_map.remove(cachedItem);
+            m_duplicateCounts.add(key);
+        }
+    }
+
+    m_duplicateCounts.add(key);
 }
 
 void DocumentOrderedMap::remove(StringImpl* key, Element* element)
@@ -94,20 +103,11 @@
     ASSERT(key);
     ASSERT(element);
 
-    Map::iterator it = m_map.find(key);
-    ASSERT(it != m_map.end());
-    MapEntry& entry = it->value;
-
-    ASSERT(entry.count);
-    if (entry.count == 1) {
-        ASSERT(!entry.element || entry.element == element);
-        m_map.remove(it);
-    } else {
-        if (entry.element == element)
-            entry.element = 0;
-        entry.count--;
-        entry.orderedList.clear(); // FIXME: Remove the element instead if there are only few items left.
-    }
+    Map::iterator cachedItem = m_map.find(key);
+    if (cachedItem != m_map.end() && cachedItem->value == element)
+        m_map.remove(cachedItem);
+    else
+        m_duplicateCounts.remove(key);
 }
 
 template<bool keyMatches(StringImpl*, Element*)>
@@ -116,23 +116,22 @@
     ASSERT(key);
     ASSERT(scope);
 
-    Map::iterator it = m_map.find(key);
-    if (it == m_map.end())
-        return 0;
-
-    MapEntry& entry = it->value;
-    ASSERT(entry.count);
-    if (entry.element)
-        return entry.element;
-
-    // We know there's at least one node that matches; iterate to find the first one.
-    for (Element* element = ElementTraversal::firstWithin(scope->rootNode()); element; element = ElementTraversal::next(element)) {
-        if (!keyMatches(key, element))
-            continue;
-        entry.element = element;
+    Element* element = m_map.get(key);
+    if (element)
         return element;
+
+    if (m_duplicateCounts.contains(key)) {
+        // We know there's at least one node that matches; iterate to find the first one.
+        for (element = ElementTraversal::firstWithin(scope->rootNode()); element; element = ElementTraversal::next(element)) {
+            if (!keyMatches(key, element))
+                continue;
+            m_duplicateCounts.remove(key);
+            m_map.set(key, element);
+            return element;
+        }
+        ASSERT_NOT_REACHED();
     }
-    ASSERT_NOT_REACHED();
+
     return 0;
 }
 
@@ -141,11 +140,6 @@
     return get<keyMatchesId>(key, scope);
 }
 
-Element* DocumentOrderedMap::getElementByName(StringImpl* key, const TreeScope* scope) const
-{
-    return get<keyMatchesName>(key, scope);
-}
-
 Element* DocumentOrderedMap::getElementByMapName(StringImpl* key, const TreeScope* scope) const
 {
     return get<keyMatchesMapName>(key, scope);
@@ -161,31 +155,4 @@
     return get<keyMatchesLabelForAttribute>(key, scope);
 }
 
-const Vector<Element*>* DocumentOrderedMap::getAllElementsById(StringImpl* key, const TreeScope* scope) const
-{
-    ASSERT(key);
-    ASSERT(scope);
-
-    Map::iterator it = m_map.find(key);
-    if (it == m_map.end())
-        return 0;
-
-    MapEntry& entry = it->value;
-    ASSERT(entry.count);
-    if (!entry.count)
-        return 0;
-
-    if (entry.orderedList.isEmpty()) {
-        entry.orderedList.reserveCapacity(entry.count);
-        for (Element* element = entry.element ? entry.element : ElementTraversal::firstWithin(scope->rootNode()); element; element = ElementTraversal::next(element)) {
-            if (!keyMatchesId(key, element))
-                continue;
-            entry.orderedList.append(element);
-        }
-        ASSERT(entry.orderedList.size() == entry.count);
-    }
-
-    return &entry.orderedList;
-}
-
 } // namespace WebCore
diff --git a/Source/core/dom/DocumentOrderedMap.h b/Source/core/dom/DocumentOrderedMap.h
index a86caf0..b6fc8e0 100644
--- a/Source/core/dom/DocumentOrderedMap.h
+++ b/Source/core/dom/DocumentOrderedMap.h
@@ -33,7 +33,6 @@
 
 #include "wtf/HashCountedSet.h"
 #include "wtf/HashMap.h"
-#include "wtf/Vector.h"
 #include "wtf/text/StringImpl.h"
 
 namespace WebCore {
@@ -48,60 +47,35 @@
     void clear();
 
     bool contains(StringImpl*) const;
-    bool containsSingle(StringImpl*) const;
     bool containsMultiple(StringImpl*) const;
-
     // concrete instantiations of the get<>() method template
     Element* getElementById(StringImpl*, const TreeScope*) const;
-    Element* getElementByName(StringImpl*, const TreeScope*) const;
     Element* getElementByMapName(StringImpl*, const TreeScope*) const;
     Element* getElementByLowercasedMapName(StringImpl*, const TreeScope*) const;
     Element* getElementByLabelForAttribute(StringImpl*, const TreeScope*) const;
 
-    const Vector<Element*>* getAllElementsById(StringImpl*, const TreeScope*) const;
-
     void checkConsistency() const;
 
 private:
     template<bool keyMatches(StringImpl*, Element*)> Element* get(StringImpl*, const TreeScope*) const;
 
-    struct MapEntry {
-        MapEntry()
-            : element(0)
-            , count(0)
-        {
-        }
-        explicit MapEntry(Element* firstElement)
-            : element(firstElement)
-            , count(1)
-        {
-        }
+    typedef HashMap<StringImpl*, Element*> Map;
 
-        Element* element;
-        unsigned count;
-        Vector<Element*> orderedList;
-    };
-
-    typedef HashMap<StringImpl*, MapEntry> Map;
-
+    // We maintain the invariant that m_duplicateCounts is the count of all elements with a given key
+    // excluding the one referenced in m_map, if any. This means it one less than the total count
+    // when the first node with a given key is cached, otherwise the same as the total count.
     mutable Map m_map;
+    mutable HashCountedSet<StringImpl*> m_duplicateCounts;
 };
 
-inline bool DocumentOrderedMap::containsSingle(StringImpl* id) const
-{
-    Map::const_iterator it = m_map.find(id);
-    return it != m_map.end() && it->value.count == 1;
-}
-
 inline bool DocumentOrderedMap::contains(StringImpl* id) const
 {
-    return m_map.contains(id);
+    return m_map.contains(id) || m_duplicateCounts.contains(id);
 }
 
 inline bool DocumentOrderedMap::containsMultiple(StringImpl* id) const
 {
-    Map::const_iterator it = m_map.find(id);
-    return it != m_map.end() && it->value.count > 1;
+    return m_duplicateCounts.contains(id);
 }
 
 } // namespace WebCore
diff --git a/Source/core/dom/DocumentStyleSheetCollection.cpp b/Source/core/dom/DocumentStyleSheetCollection.cpp
index 74ef2b1..bbcbe43 100644
--- a/Source/core/dom/DocumentStyleSheetCollection.cpp
+++ b/Source/core/dom/DocumentStyleSheetCollection.cpp
@@ -37,6 +37,8 @@
 #include "core/dom/Document.h"
 #include "core/dom/Element.h"
 #include "core/dom/ProcessingInstruction.h"
+#include "core/dom/ShadowTreeStyleSheetCollection.h"
+#include "core/dom/shadow/ShadowRoot.h"
 #include "core/html/HTMLIFrameElement.h"
 #include "core/html/HTMLLinkElement.h"
 #include "core/html/HTMLStyleElement.h"
@@ -63,6 +65,7 @@
     , m_usesBeforeAfterRulesOverride(false)
     , m_usesRemUnits(false)
     , m_collectionForDocument(document)
+    , m_needsDocumentStyleSheetsUpdate(true)
 {
 }
 
@@ -80,6 +83,55 @@
         m_authorStyleSheets[i]->clearOwnerNode();
 }
 
+void DocumentStyleSheetCollection::insertTreeScopeInDocumentOrder(TreeScopeSet& treeScopes, TreeScope* treeScope)
+{
+    if (treeScopes.isEmpty()) {
+        treeScopes.add(treeScope);
+        return;
+    }
+    if (treeScopes.contains(treeScope))
+        return;
+
+    TreeScopeSet::iterator begin = treeScopes.begin();
+    TreeScopeSet::iterator end = treeScopes.end();
+    TreeScopeSet::iterator it = end;
+    TreeScope* followingTreeScope = 0;
+    do {
+        --it;
+        TreeScope* n = *it;
+        unsigned short position = n->comparePosition(treeScope);
+        if (position & Node::DOCUMENT_POSITION_FOLLOWING) {
+            treeScopes.insertBefore(followingTreeScope, treeScope);
+            return;
+        }
+        followingTreeScope = n;
+    } while (it != begin);
+
+    treeScopes.insertBefore(followingTreeScope, treeScope);
+}
+
+StyleSheetCollection* DocumentStyleSheetCollection::ensureStyleSheetCollectionFor(TreeScope* treeScope)
+{
+    if (treeScope == m_document)
+        return &m_collectionForDocument;
+
+    HashMap<TreeScope*, OwnPtr<StyleSheetCollection> >::AddResult result = m_styleSheetCollectionMap.add(treeScope, nullptr);
+    if (result.isNewEntry)
+        result.iterator->value = adoptPtr(new ShadowTreeStyleSheetCollection(toShadowRoot(treeScope)));
+    return result.iterator->value.get();
+}
+
+StyleSheetCollection* DocumentStyleSheetCollection::styleSheetCollectionFor(TreeScope* treeScope)
+{
+    if (treeScope == m_document)
+        return &m_collectionForDocument;
+
+    HashMap<TreeScope*, OwnPtr<StyleSheetCollection> >::iterator it = m_styleSheetCollectionMap.find(treeScope);
+    if (it == m_styleSheetCollectionMap.end())
+        return 0;
+    return it->value.get();
+}
+
 const Vector<RefPtr<StyleSheet> >& DocumentStyleSheetCollection::styleSheetsForStyleSheetList()
 {
     return m_collectionForDocument.styleSheetsForStyleSheetList();
@@ -90,6 +142,19 @@
     return m_collectionForDocument.activeAuthorStyleSheets();
 }
 
+void DocumentStyleSheetCollection::getActiveAuthorStyleSheets(Vector<const Vector<RefPtr<CSSStyleSheet> >*>& activeAuthorStyleSheets) const
+{
+    activeAuthorStyleSheets.append(&m_collectionForDocument.activeAuthorStyleSheets());
+
+    HashMap<TreeScope*, OwnPtr<StyleSheetCollection> >::const_iterator::Values begin = m_styleSheetCollectionMap.values().begin();
+    HashMap<TreeScope*, OwnPtr<StyleSheetCollection> >::const_iterator::Values end = m_styleSheetCollectionMap.values().end();
+    HashMap<TreeScope*, OwnPtr<StyleSheetCollection> >::const_iterator::Values it = begin;
+    for (; it != end; ++it) {
+        const StyleSheetCollection* collection = it->get();
+        activeAuthorStyleSheets.append(&collection->activeAuthorStyleSheets());
+    }
+}
+
 void DocumentStyleSheetCollection::combineCSSFeatureFlags(const RuleFeatureSet& features)
 {
     // Delay resetting the flags until after next style recalc since unapplying the style may not work without these set (this is true at least with before/after).
@@ -188,9 +253,10 @@
 void DocumentStyleSheetCollection::invalidateInjectedStyleSheetCache()
 {
     m_injectedStyleSheetCacheValid = false;
+    m_needsDocumentStyleSheetsUpdate = true;
     // FIXME: updateInjectedStyleSheetCache is called inside StyleSheetCollection::updateActiveStyleSheets
     // and batch updates lots of sheets so we can't call addedStyleSheet() or removedStyleSheet().
-    m_document->styleResolverChanged(DeferRecalcStyle);
+    m_document->styleResolverChanged(RecalcStyleDeferred);
 }
 
 void DocumentStyleSheetCollection::addAuthorSheet(PassRefPtr<StyleSheetContents> authorSheet)
@@ -198,6 +264,7 @@
     ASSERT(!authorSheet->isUserStyleSheet());
     m_authorStyleSheets.append(CSSStyleSheet::create(authorSheet, m_document));
     m_document->addedStyleSheet(m_authorStyleSheets.last().get(), RecalcStyleImmediately);
+    m_needsDocumentStyleSheetsUpdate = true;
 }
 
 void DocumentStyleSheetCollection::addUserSheet(PassRefPtr<StyleSheetContents> userSheet)
@@ -205,16 +272,23 @@
     ASSERT(userSheet->isUserStyleSheet());
     m_userStyleSheets.append(CSSStyleSheet::create(userSheet, m_document));
     m_document->addedStyleSheet(m_userStyleSheets.last().get(), RecalcStyleImmediately);
+    m_needsDocumentStyleSheetsUpdate = true;
 }
 
 // This method is called whenever a top-level stylesheet has finished loading.
-void DocumentStyleSheetCollection::removePendingSheet(RemovePendingSheetNotificationType notification)
+void DocumentStyleSheetCollection::removePendingSheet(Node* styleSheetCandidateNode, RemovePendingSheetNotificationType notification)
 {
     // Make sure we knew this sheet was pending, and that our count isn't out of sync.
     ASSERT(m_pendingStylesheets > 0);
 
     m_pendingStylesheets--;
 
+    TreeScope* treeScope = isHTMLStyleElement(styleSheetCandidateNode) ? styleSheetCandidateNode->treeScope() : m_document;
+    if (treeScope == m_document)
+        m_needsDocumentStyleSheetsUpdate = true;
+    else
+        m_dirtyTreeScopes.add(treeScope);
+
     if (m_pendingStylesheets)
         return;
 
@@ -230,21 +304,59 @@
 
 void DocumentStyleSheetCollection::addStyleSheetCandidateNode(Node* node, bool createdByParser)
 {
-    m_collectionForDocument.addStyleSheetCandidateNode(node, createdByParser);
+    if (!node->inDocument())
+        return;
+
+    TreeScope* treeScope = isHTMLStyleElement(node) ? node->treeScope() : m_document;
+    ASSERT(isHTMLStyleElement(node) || treeScope == m_document);
+
+    StyleSheetCollection* collection = ensureStyleSheetCollectionFor(treeScope);
+    ASSERT(collection);
+    collection->addStyleSheetCandidateNode(node, createdByParser);
+
+    if (treeScope == m_document) {
+        m_needsDocumentStyleSheetsUpdate = true;
+        return;
+    }
+
+    insertTreeScopeInDocumentOrder(m_activeTreeScopes, treeScope);
+    m_dirtyTreeScopes.add(treeScope);
 }
 
 void DocumentStyleSheetCollection::removeStyleSheetCandidateNode(Node* node, ContainerNode* scopingNode)
 {
-    m_collectionForDocument.removeStyleSheetCandidateNode(node, scopingNode);
+    TreeScope* treeScope = scopingNode ? scopingNode->treeScope() : m_document;
+    ASSERT(isHTMLStyleElement(node) || treeScope == m_document);
+
+    StyleSheetCollection* collection = styleSheetCollectionFor(treeScope);
+    ASSERT(collection);
+    collection->removeStyleSheetCandidateNode(node, scopingNode);
+
+    if (treeScope == m_document) {
+        m_needsDocumentStyleSheetsUpdate = true;
+        return;
+    }
+    m_dirtyTreeScopes.add(treeScope);
+    m_activeTreeScopes.remove(treeScope);
 }
 
-static bool styleSheetsUseRemUnits(const Vector<RefPtr<CSSStyleSheet> >& sheets)
+void DocumentStyleSheetCollection::modifiedStyleSheetCandidateNode(Node* node)
 {
-    for (unsigned i = 0; i < sheets.size(); ++i) {
-        if (sheets[i]->contents()->usesRemUnits())
-            return true;
+    if (!node->inDocument())
+        return;
+
+    TreeScope* treeScope = isHTMLStyleElement(node) ? node->treeScope() : m_document;
+    ASSERT(isHTMLStyleElement(node) || treeScope == m_document);
+    if (treeScope == m_document) {
+        m_needsDocumentStyleSheetsUpdate = true;
+        return;
     }
-    return false;
+    m_dirtyTreeScopes.add(treeScope);
+}
+
+bool DocumentStyleSheetCollection::shouldUpdateShadowTreeStyleSheetCollection(StyleResolverUpdateMode updateMode)
+{
+    return !m_dirtyTreeScopes.isEmpty() || updateMode == FullStyleUpdate;
 }
 
 bool DocumentStyleSheetCollection::updateActiveStyleSheets(StyleResolverUpdateMode updateMode)
@@ -260,18 +372,91 @@
     if (!m_document->renderer() || !m_document->attached())
         return false;
 
-    StyleSheetCollection::StyleResolverUpdateType styleResolverUpdateType;
-    bool requiresFullStyleRecalc = m_collectionForDocument.updateActiveStyleSheets(this, updateMode, styleResolverUpdateType);
+    bool requiresFullStyleRecalc = false;
+    if (m_needsDocumentStyleSheetsUpdate || updateMode == FullStyleUpdate)
+        requiresFullStyleRecalc = m_collectionForDocument.updateActiveStyleSheets(this, updateMode);
+
+    if (shouldUpdateShadowTreeStyleSheetCollection(updateMode)) {
+        TreeScopeSet treeScopes = updateMode == FullStyleUpdate ? m_activeTreeScopes : m_dirtyTreeScopes;
+        HashSet<TreeScope*> treeScopesRemoved;
+
+        for (TreeScopeSet::iterator it = treeScopes.begin(); it != treeScopes.end(); ++it) {
+            TreeScope* treeScope = *it;
+            ASSERT(treeScope != m_document);
+            ShadowTreeStyleSheetCollection* collection = static_cast<ShadowTreeStyleSheetCollection*>(styleSheetCollectionFor(treeScope));
+            ASSERT(collection);
+            collection->updateActiveStyleSheets(this, updateMode);
+            if (!collection->hasStyleSheetCandidateNodes())
+                treeScopesRemoved.add(treeScope);
+        }
+        if (!treeScopesRemoved.isEmpty())
+            for (HashSet<TreeScope*>::iterator it = treeScopesRemoved.begin(); it != treeScopesRemoved.end(); ++it)
+                m_activeTreeScopes.remove(*it);
+        m_dirtyTreeScopes.clear();
+    }
+
+    if (StyleResolver* styleResolver = m_document->styleResolverIfExists()) {
+        styleResolver->finishAppendAuthorStyleSheets();
+        resetCSSFeatureFlags(styleResolver->ruleFeatureSet());
+    }
+
     m_needsUpdateActiveStylesheetsOnStyleRecalc = false;
+    activeStyleSheetsUpdatedForInspector();
+    m_usesRemUnits = m_collectionForDocument.usesRemUnits();
 
-    if (styleResolverUpdateType != StyleSheetCollection::Reconstruct)
-        resetCSSFeatureFlags(m_document->styleResolver()->ruleFeatureSet());
-
-    InspectorInstrumentation::activeStyleSheetsUpdated(m_document, m_collectionForDocument.styleSheetsForStyleSheetList());
-    m_usesRemUnits = styleSheetsUseRemUnits(m_collectionForDocument.activeAuthorStyleSheets());
-    m_document->notifySeamlessChildDocumentsOfStylesheetUpdate();
+    if (m_needsDocumentStyleSheetsUpdate || updateMode == FullStyleUpdate) {
+        m_document->notifySeamlessChildDocumentsOfStylesheetUpdate();
+        m_needsDocumentStyleSheetsUpdate = false;
+    }
 
     return requiresFullStyleRecalc;
 }
 
+void DocumentStyleSheetCollection::activeStyleSheetsUpdatedForInspector()
+{
+    if (m_activeTreeScopes.isEmpty()) {
+        InspectorInstrumentation::activeStyleSheetsUpdated(m_document, m_collectionForDocument.styleSheetsForStyleSheetList());
+        return;
+    }
+    Vector<RefPtr<StyleSheet> > activeStyleSheets;
+
+    activeStyleSheets.append(m_collectionForDocument.styleSheetsForStyleSheetList());
+
+    TreeScopeSet::iterator begin = m_activeTreeScopes.begin();
+    TreeScopeSet::iterator end = m_activeTreeScopes.end();
+    for (TreeScopeSet::iterator it = begin; it != end; ++it) {
+        if (StyleSheetCollection* collection = m_styleSheetCollectionMap.get(*it))
+            activeStyleSheets.append(collection->styleSheetsForStyleSheetList());
+    }
+
+    // FIXME: Inspector needs a vector which has all active stylesheets.
+    // However, creating such a large vector might cause performance regression.
+    // Need to implement some smarter solution.
+    InspectorInstrumentation::activeStyleSheetsUpdated(m_document, activeStyleSheets);
+}
+
+void DocumentStyleSheetCollection::didRemoveShadowRoot(ShadowRoot* shadowRoot)
+{
+    m_styleSheetCollectionMap.remove(shadowRoot);
+}
+
+void DocumentStyleSheetCollection::appendActiveAuthorStyleSheets(StyleResolver* styleResolver)
+{
+    ASSERT(styleResolver);
+
+    styleResolver->setBuildScopedStyleTreeInDocumentOrder(true);
+    styleResolver->appendAuthorStyleSheets(0, m_collectionForDocument.activeAuthorStyleSheets());
+
+    TreeScopeSet::iterator begin = m_activeTreeScopes.begin();
+    TreeScopeSet::iterator end = m_activeTreeScopes.end();
+    for (TreeScopeSet::iterator it = begin; it != end; ++it) {
+        if (StyleSheetCollection* collection = m_styleSheetCollectionMap.get(*it)) {
+            styleResolver->setBuildScopedStyleTreeInDocumentOrder(!collection->scopingNodesForStyleScoped());
+            styleResolver->appendAuthorStyleSheets(0, collection->activeAuthorStyleSheets());
+        }
+    }
+    styleResolver->finishAppendAuthorStyleSheets();
+    styleResolver->setBuildScopedStyleTreeInDocumentOrder(false);
+}
+
 }
diff --git a/Source/core/dom/DocumentStyleSheetCollection.h b/Source/core/dom/DocumentStyleSheetCollection.h
index bbafeb8..2dd47c5 100644
--- a/Source/core/dom/DocumentStyleSheetCollection.h
+++ b/Source/core/dom/DocumentStyleSheetCollection.h
@@ -64,6 +64,7 @@
 
     void addStyleSheetCandidateNode(Node*, bool createdByParser);
     void removeStyleSheetCandidateNode(Node*, ContainerNode* scopingNode = 0);
+    void modifiedStyleSheetCandidateNode(Node*);
 
     void clearPageUserSheet();
     void updatePageUserSheet();
@@ -87,7 +88,7 @@
         RemovePendingSheetNotifyImmediately,
         RemovePendingSheetNotifyLater
     };
-    void removePendingSheet(RemovePendingSheetNotificationType = RemovePendingSheetNotifyImmediately);
+    void removePendingSheet(Node* styleSheetCandidateNode, RemovePendingSheetNotificationType = RemovePendingSheetNotifyImmediately);
 
     bool hasPendingSheets() const { return m_pendingStylesheets > 0; }
 
@@ -105,9 +106,22 @@
     void combineCSSFeatureFlags(const RuleFeatureSet&);
     void resetCSSFeatureFlags(const RuleFeatureSet&);
 
+    void didModifySeamlessParentStyleSheet() { m_needsDocumentStyleSheetsUpdate = true; }
+    void didRemoveShadowRoot(ShadowRoot*);
+    void appendActiveAuthorStyleSheets(StyleResolver*);
+    void getActiveAuthorStyleSheets(Vector<const Vector<RefPtr<CSSStyleSheet> >*>& activeAuthorStyleSheets) const;
+
 private:
     DocumentStyleSheetCollection(Document*);
 
+    StyleSheetCollection* ensureStyleSheetCollectionFor(TreeScope*);
+    StyleSheetCollection* styleSheetCollectionFor(TreeScope*);
+    void activeStyleSheetsUpdatedForInspector();
+    bool shouldUpdateShadowTreeStyleSheetCollection(StyleResolverUpdateMode);
+
+    typedef ListHashSet<TreeScope*, 16> TreeScopeSet;
+    static void insertTreeScopeInDocumentOrder(TreeScopeSet&, TreeScope*);
+
     Document* m_document;
 
     // Track the number of currently loading top-level stylesheets needed for rendering.
@@ -125,10 +139,14 @@
     Vector<RefPtr<CSSStyleSheet> > m_userStyleSheets;
     Vector<RefPtr<CSSStyleSheet> > m_authorStyleSheets;
 
-    bool m_hadActiveLoadingStylesheet;
     bool m_needsUpdateActiveStylesheetsOnStyleRecalc;
 
-    StyleSheetCollection m_collectionForDocument;
+    StyleSheetCollectionForDocument m_collectionForDocument;
+    HashMap<TreeScope*, OwnPtr<StyleSheetCollection> > m_styleSheetCollectionMap;
+
+    TreeScopeSet m_dirtyTreeScopes;
+    TreeScopeSet m_activeTreeScopes;
+    bool m_needsDocumentStyleSheetsUpdate;
 
     String m_preferredStylesheetSetName;
     String m_selectedStylesheetSetName;
diff --git a/Source/core/dom/DocumentType.idl b/Source/core/dom/DocumentType.idl
index 8f192f3..510240a 100644
--- a/Source/core/dom/DocumentType.idl
+++ b/Source/core/dom/DocumentType.idl
@@ -22,14 +22,14 @@
     // DOM Level 1
 
     readonly attribute DOMString name;
-    readonly attribute NamedNodeMap entities;
-    readonly attribute NamedNodeMap notations;
+    [MeasureAs=DocumentTypeEntities] readonly attribute NamedNodeMap entities; // Removed from DOM4.
+    [MeasureAs=DocumentTypeNotations] readonly attribute NamedNodeMap notations; // Removed from DOM4.
 
     // DOM Level 2
 
     [TreatReturnedNullStringAs=Null] readonly attribute DOMString publicId;
     [TreatReturnedNullStringAs=Null] readonly attribute DOMString systemId;
-    [TreatReturnedNullStringAs=Null] readonly attribute DOMString internalSubset;
+    [TreatReturnedNullStringAs=Null, MeasureAs=DocumentTypeInternalSubset] readonly attribute DOMString internalSubset; // Removed from DOM4.
 };
 
 DocumentType implements ChildNode;
diff --git a/Source/core/dom/Element.cpp b/Source/core/dom/Element.cpp
index b7147bc..9577774 100644
--- a/Source/core/dom/Element.cpp
+++ b/Source/core/dom/Element.cpp
@@ -953,7 +953,7 @@
 inline void Element::attributeChangedFromParserOrByCloning(const QualifiedName& name, const AtomicString& newValue, AttributeModificationReason reason)
 {
     if (name == isAttr)
-        CustomElementRegistrationContext::setTypeExtension(this, newValue);
+        CustomElementRegistrationContext::setTypeExtension(this, newValue, reason == ModifiedDirectly ? CustomElementRegistrationContext::CreatedByParser : CustomElementRegistrationContext::NotCreatedByParser);
     attributeChanged(name, newValue, reason);
 }
 
@@ -1053,7 +1053,7 @@
 bool Element::shouldInvalidateDistributionWhenAttributeChanged(ElementShadow* elementShadow, const QualifiedName& name, const AtomicString& newValue)
 {
     ASSERT(elementShadow);
-    const SelectRuleFeatureSet& featureSet = elementShadow->distributor().ensureSelectFeatureSet(elementShadow);
+    const SelectRuleFeatureSet& featureSet = elementShadow->ensureSelectFeatureSet();
 
     if (isIdAttributeName(name)) {
         AtomicString oldId = elementData()->idForStyleResolution();
@@ -1206,14 +1206,6 @@
     return RenderObject::createObject(this, style);
 }
 
-bool Element::isInert() const
-{
-    const Element* dialog = document()->activeModalDialog();
-    if (dialog && !containsIncludingShadowDOM(dialog) && !dialog->containsIncludingShadowDOM(this))
-        return true;
-    return document()->ownerElement() && document()->ownerElement()->isInert();
-}
-
 Node::InsertionNotificationRequest Element::insertedInto(ContainerNode* insertionPoint)
 {
     // need to do superclass processing first so inDocument() is true
@@ -1229,6 +1221,9 @@
     if (Element* after = pseudoElement(AFTER))
         after->insertedInto(insertionPoint);
 
+    if (Element* backdrop = pseudoElement(BACKDROP))
+        backdrop->insertedInto(insertionPoint);
+
     if (!insertionPoint->isInTreeScope())
         return InsertionDone;
 
@@ -1279,7 +1274,7 @@
         setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(false);
 
     if (document()->page())
-        document()->page()->pointerLockController()->elementRemoved(this);
+        document()->page()->pointerLockController().elementRemoved(this);
 
     setSavedLayerScrollOffset(IntSize());
 
@@ -1318,6 +1313,16 @@
     StyleResolverParentPusher parentPusher(this);
     WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates;
 
+    // We've already been through detach when doing a lazyAttach, but we might
+    // need to clear any state that's been added since then.
+    if (hasRareData() && styleChangeType() == LazyAttachStyleChange) {
+        ElementRareData* data = elementRareData();
+        data->clearComputedStyle();
+        data->resetDynamicRestyleObservations();
+        if (!context.resolvedStyle)
+            data->resetStyleState();
+    }
+
     NodeRenderingContext(this, context.resolvedStyle).createRendererForElementIfNeeded();
 
     createPseudoElementIfNeeded(BEFORE);
@@ -1534,10 +1539,11 @@
         } else if (child->isElementNode()) {
             Element* element = toElement(child);
 
+            bool childRulesChanged = element->needsStyleRecalc() && element->styleChangeType() >= SubtreeStyleChange;
+
             if (forceCheckOfNextElementSibling || forceCheckOfAnyElementSibling)
                 element->setNeedsStyleRecalc();
 
-            bool childRulesChanged = element->needsStyleRecalc() && element->styleChangeType() >= SubtreeStyleChange;
             forceCheckOfNextElementSibling = childRulesChanged && hasDirectAdjacentRules;
             forceCheckOfAnyElementSibling = forceCheckOfAnyElementSibling || (childRulesChanged && hasIndirectAdjacentRules);
 
@@ -1550,8 +1556,10 @@
         forceReattachOfAnyWhitespaceSibling = didReattach || forceReattachOfAnyWhitespaceSibling;
     }
 
-    if (shouldRecalcStyle(change, this))
+    if (shouldRecalcStyle(change, this)) {
         updatePseudoElement(AFTER, change);
+        updatePseudoElement(BACKDROP, change);
+    }
 
     clearNeedsStyleRecalc();
     clearChildNeedsStyleRecalc();
@@ -1628,12 +1636,6 @@
     return shadowRoot;
 }
 
-Element* Element::uaShadowElementById(const AtomicString& id) const
-{
-    ShadowRoot* shadowRoot = userAgentShadowRoot();
-    return shadowRoot ? shadowRoot->getElementById(id) : 0;
-}
-
 bool Element::supportsShadowElementForUserAgentShadow() const
 {
     return true;
@@ -1770,6 +1772,8 @@
     checkForSiblingStyleChanges(this, renderStyle(), true, lastChild(), 0, 0);
     if (StyleResolver* styleResolver = document()->styleResolverIfExists())
         styleResolver->popParentElement(this);
+    if (isCustomElement())
+        CustomElement::didFinishParsingChildren(this);
 }
 
 #ifndef NDEBUG
@@ -1827,7 +1831,7 @@
     synchronizeAllAttributes();
     UniqueElementData* elementData = ensureUniqueElementData();
 
-    size_t index = elementData->getAttributeItemIndex(attrNode->qualifiedName());
+    size_t index = elementData->getAttributeItemIndex(attrNode->qualifiedName(), shouldIgnoreAttributeCase(this));
     if (index != notFound) {
         if (oldAttrNode)
             detachAttrNodeFromElementWithValue(oldAttrNode.get(), elementData->attributeItem(index)->value());
@@ -2630,7 +2634,7 @@
 void Element::webkitRequestPointerLock()
 {
     if (document()->page())
-        document()->page()->pointerLockController()->requestPointerLock(this);
+        document()->page()->pointerLockController().requestPointerLock(this);
 }
 
 SpellcheckAttributeState Element::spellcheckAttributeState() const
diff --git a/Source/core/dom/Element.h b/Source/core/dom/Element.h
index 7b075ce..556fe4f 100644
--- a/Source/core/dom/Element.h
+++ b/Source/core/dom/Element.h
@@ -87,7 +87,7 @@
 
     const Attribute* attributeItem(unsigned index) const;
     const Attribute* getAttributeItem(const QualifiedName&) const;
-    size_t getAttributeItemIndex(const QualifiedName&) const;
+    size_t getAttributeItemIndex(const QualifiedName&, bool shouldIgnoreCase = false) const;
     size_t getAttributeItemIndex(const AtomicString& name, bool shouldIgnoreAttributeCase) const;
     size_t getAttrIndex(Attr*) const;
 
@@ -216,6 +216,7 @@
     DEFINE_ATTRIBUTE_EVENT_LISTENER(scroll);
     DEFINE_ATTRIBUTE_EVENT_LISTENER(select);
     DEFINE_ATTRIBUTE_EVENT_LISTENER(submit);
+    DEFINE_ATTRIBUTE_EVENT_LISTENER(wheel);
 
     // These four attribute event handler attributes are overridden by HTMLBodyElement
     // and HTMLFrameSetElement to forward to the DOMWindow.
@@ -446,7 +447,6 @@
 
     ShadowRoot* userAgentShadowRoot() const;
     ShadowRoot* ensureUserAgentShadowRoot();
-    Element* uaShadowElementById(const AtomicString& id) const;
     virtual bool supportsShadowElementForUserAgentShadow() const;
     virtual const AtomicString& shadowPseudoId() const { return !part().isEmpty() ? part() : pseudo(); }
 
@@ -594,7 +594,6 @@
     // to event listeners, and prevents DOMActivate events from being sent at all.
     virtual bool isDisabledFormControl() const { return false; }
 
-    bool isInert() const;
     virtual bool shouldBeReparentedUnderRenderView(const RenderStyle*) const { return isInTopLayer(); }
 
     virtual bool childShouldCreateRenderer(const NodeRenderingContext&) const;
@@ -644,6 +643,8 @@
 
     InputMethodContext* inputMethodContext();
 
+    virtual void setPrefix(const AtomicString&, ExceptionState&) OVERRIDE FINAL;
+
 protected:
     Element(const QualifiedName& tagName, Document* document, ConstructionType type)
         : ContainerNode(document, type)
@@ -663,7 +664,7 @@
     virtual InsertionNotificationRequest insertedInto(ContainerNode*) OVERRIDE;
     virtual void removedFrom(ContainerNode*) OVERRIDE;
     virtual void childrenChanged(bool changedByParser = false, Node* beforeChange = 0, Node* afterChange = 0, int childCountDelta = 0) OVERRIDE;
-    virtual void removeAllEventListeners() OVERRIDE;
+    virtual void removeAllEventListeners() OVERRIDE FINAL;
 
     virtual void willRecalcStyle(StyleChange);
     virtual void didRecalcStyle(StyleChange);
@@ -728,7 +729,6 @@
 
     void scrollByUnits(int units, ScrollGranularity);
 
-    virtual void setPrefix(const AtomicString&, ExceptionState&) OVERRIDE FINAL;
     virtual NodeType nodeType() const OVERRIDE FINAL;
     virtual bool childTypeAllowed(NodeType) const OVERRIDE FINAL;
 
@@ -1037,12 +1037,12 @@
     return static_cast<const ShareableElementData*>(this)->m_attributeArray;
 }
 
-inline size_t ElementData::getAttributeItemIndex(const QualifiedName& name) const
+inline size_t ElementData::getAttributeItemIndex(const QualifiedName& name, bool shouldIgnoreCase) const
 {
     const Attribute* begin = attributeBase();
     for (unsigned i = 0; i < length(); ++i) {
         const Attribute& attribute = begin[i];
-        if (attribute.name().matches(name))
+        if (attribute.name().matchesPossiblyIgnoringCase(name, shouldIgnoreCase))
             return i;
     }
     return notFound;
diff --git a/Source/core/dom/Element.idl b/Source/core/dom/Element.idl
index 0137af9..9af4c05 100644
--- a/Source/core/dom/Element.idl
+++ b/Source/core/dom/Element.idl
@@ -30,12 +30,11 @@
     [RaisesException, CustomElementCallbacks=Enable] void setAttribute([Default=Undefined] optional DOMString name,
                                      [Default=Undefined] optional DOMString value);
     [CustomElementCallbacks=Enable] void removeAttribute([Default=Undefined] optional DOMString name);
-    Attr getAttributeNode([Default=Undefined] optional DOMString name);
-    [RaisesException, CustomElementCallbacks=Enable] Attr setAttributeNode([Default=Undefined, StrictTypeChecking] optional Attr newAttr);
-    [RaisesException, CustomElementCallbacks=Enable] Attr removeAttributeNode([Default=Undefined, StrictTypeChecking] optional Attr oldAttr);
+    [MeasureAs=ElementGetAttributeNode] Attr getAttributeNode([Default=Undefined] optional DOMString name); // Removed from DOM4.
+    [RaisesException, CustomElementCallbacks=Enable, MeasureAs=ElementSetAttributeNode] Attr setAttributeNode([Default=Undefined, StrictTypeChecking] optional Attr newAttr); // Removed from DOM4.
+    [RaisesException, CustomElementCallbacks=Enable, MeasureAs=ElementRemoveAttributeNode] Attr removeAttributeNode([Default=Undefined, StrictTypeChecking] optional Attr oldAttr); // Removed from DOM4.
     [PerWorldBindings] NodeList getElementsByTagName([Default=Undefined] optional DOMString name);
 
-    // For ObjC this is defined on Node for legacy support.
     [PerWorldBindings] readonly attribute NamedNodeMap     attributes;
     boolean            hasAttributes();
 
@@ -50,8 +49,8 @@
                                           DOMString localName);
      NodeList getElementsByTagNameNS([TreatNullAs=NullString,Default=Undefined] optional DOMString namespaceURI,
                                                    [Default=Undefined] optional DOMString localName);
-     Attr getAttributeNodeNS([TreatNullAs=NullString,Default=Undefined] optional DOMString namespaceURI,
-                                           [Default=Undefined] optional DOMString localName);
+     [MeasureAs=ElementGetAttributeNodeNS] Attr getAttributeNodeNS([TreatNullAs=NullString,Default=Undefined] optional DOMString namespaceURI,
+                                                                   [Default=Undefined] optional DOMString localName); // Removed from DOM4.
     [RaisesException, CustomElementCallbacks=Enable] Attr setAttributeNodeNS([Default=Undefined, StrictTypeChecking] optional Attr newAttr);
     boolean hasAttribute(DOMString name);
      boolean hasAttributeNS([TreatNullAs=NullString,Default=Undefined] optional DOMString namespaceURI,
@@ -63,6 +62,9 @@
     // iht.com relies on id returning the empty string when no id is present.
     // Other browsers do this as well. So we don't convert null to JS null.
     [Reflect] attribute DOMString id;
+    [TreatReturnedNullStringAs=Null, PerWorldBindings] readonly attribute DOMString namespaceURI;
+    [TreatReturnedNullStringAs=Null, TreatNullAs=NullString, PerWorldBindings, SetterRaisesException] attribute DOMString prefix;
+    [TreatReturnedNullStringAs=Null, PerWorldBindings] readonly attribute DOMString localName;
 
     // Common extensions
 
@@ -162,7 +164,8 @@
     [NotEnumerable, PerWorldBindings, ActivityLog=SetterForIsolatedWorlds] attribute EventHandler onmouseout;
     [NotEnumerable, PerWorldBindings, ActivityLog=SetterForIsolatedWorlds] attribute EventHandler onmouseover;
     [NotEnumerable, PerWorldBindings, ActivityLog=SetterForIsolatedWorlds] attribute EventHandler onmouseup;
-    [NotEnumerable, PerWorldBindings, ActivityLog=SetterForIsolatedWorlds] attribute EventHandler onmousewheel;
+    [NotEnumerable, PerWorldBindings, ActivityLog=SetterForIsolatedWorlds] attribute EventHandler onmousewheel; // Deprecated in favor of onwheel.
+    [NotEnumerable, PerWorldBindings, ActivityLog=SetterForIsolatedWorlds] attribute EventHandler onwheel;
     [NotEnumerable, PerWorldBindings] attribute EventHandler onscroll;
     [NotEnumerable, PerWorldBindings] attribute EventHandler onselect;
     [NotEnumerable, PerWorldBindings] attribute EventHandler onsubmit;
diff --git a/Source/core/dom/ElementTraversal.h b/Source/core/dom/ElementTraversal.h
new file mode 100644
index 0000000..0278732
--- /dev/null
+++ b/Source/core/dom/ElementTraversal.h
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef ElementTraversal_h
+#define ElementTraversal_h
+
+#include "core/dom/Element.h"
+#include "core/dom/NodeTraversal.h"
+
+namespace WebCore {
+
+namespace ElementTraversal {
+
+// First element child of the node.
+Element* firstWithin(const Node*);
+Element* firstWithin(const ContainerNode*);
+
+// Pre-order traversal skipping non-element nodes.
+Element* next(const Node*);
+Element* next(const Node*, const Node* stayWithin);
+Element* next(const ContainerNode*);
+Element* next(const ContainerNode*, const Node* stayWithin);
+
+// Like next, but skips children.
+Element* nextSkippingChildren(const Node*);
+Element* nextSkippingChildren(const Node*, const Node* stayWithin);
+Element* nextSkippingChildren(const ContainerNode*);
+Element* nextSkippingChildren(const ContainerNode*, const Node* stayWithin);
+
+// Pre-order traversal including the pseudo-elements.
+Element* previousIncludingPseudo(const Node*, const Node* stayWithin = 0);
+Element* nextIncludingPseudo(const Node*, const Node* stayWithin = 0);
+Element* nextIncludingPseudoSkippingChildren(const Node*, const Node* stayWithin = 0);
+
+// Utility function to traverse only the element and pseudo-element siblings of a node.
+Element* pseudoAwarePreviousSibling(const Node*);
+
+template <class NodeType>
+inline Element* firstElementWithinTemplate(NodeType* current)
+{
+    // Except for the root containers, only elements can have element children.
+    Node* node = current->firstChild();
+    while (node && !node->isElementNode())
+        node = node->nextSibling();
+    return toElement(node);
+}
+inline Element* firstWithin(const ContainerNode* current) { return firstElementWithinTemplate(current); }
+inline Element* firstWithin(const Node* current) { return firstElementWithinTemplate(current); }
+
+template <class NodeType>
+inline Element* traverseNextElementTemplate(NodeType* current)
+{
+    Node* node = NodeTraversal::next(current);
+    while (node && !node->isElementNode())
+        node = NodeTraversal::nextSkippingChildren(node);
+    return toElement(node);
+}
+inline Element* next(const ContainerNode* current) { return traverseNextElementTemplate(current); }
+inline Element* next(const Node* current) { return traverseNextElementTemplate(current); }
+
+template <class NodeType>
+inline Element* traverseNextElementTemplate(NodeType* current, const Node* stayWithin)
+{
+    Node* node = NodeTraversal::next(current, stayWithin);
+    while (node && !node->isElementNode())
+        node = NodeTraversal::nextSkippingChildren(node, stayWithin);
+    return toElement(node);
+}
+inline Element* next(const ContainerNode* current, const Node* stayWithin) { return traverseNextElementTemplate(current, stayWithin); }
+inline Element* next(const Node* current, const Node* stayWithin) { return traverseNextElementTemplate(current, stayWithin); }
+
+template <class NodeType>
+inline Element* traverseNextElementSkippingChildrenTemplate(NodeType* current)
+{
+    Node* node = NodeTraversal::nextSkippingChildren(current);
+    while (node && !node->isElementNode())
+        node = NodeTraversal::nextSkippingChildren(node);
+    return toElement(node);
+}
+inline Element* nextSkippingChildren(const ContainerNode* current) { return traverseNextElementSkippingChildrenTemplate(current); }
+inline Element* nextSkippingChildren(const Node* current) { return traverseNextElementSkippingChildrenTemplate(current); }
+
+template <class NodeType>
+inline Element* traverseNextElementSkippingChildrenTemplate(NodeType* current, const Node* stayWithin)
+{
+    Node* node = NodeTraversal::nextSkippingChildren(current, stayWithin);
+    while (node && !node->isElementNode())
+        node = NodeTraversal::nextSkippingChildren(node, stayWithin);
+    return toElement(node);
+}
+inline Element* nextSkippingChildren(const ContainerNode* current, const Node* stayWithin) { return traverseNextElementSkippingChildrenTemplate(current, stayWithin); }
+inline Element* nextSkippingChildren(const Node* current, const Node* stayWithin) { return traverseNextElementSkippingChildrenTemplate(current, stayWithin); }
+
+inline Element* previousIncludingPseudo(const Node* current, const Node* stayWithin)
+{
+    Node* node = NodeTraversal::previousIncludingPseudo(current, stayWithin);
+    while (node && !node->isElementNode())
+        node = NodeTraversal::previousIncludingPseudo(node, stayWithin);
+    return toElement(node);
+}
+
+inline Element* nextIncludingPseudo(const Node* current, const Node* stayWithin)
+{
+    Node* node = NodeTraversal::nextIncludingPseudo(current, stayWithin);
+    while (node && !node->isElementNode())
+        node = NodeTraversal::nextIncludingPseudo(node, stayWithin);
+    return toElement(node);
+}
+
+inline Element* nextIncludingPseudoSkippingChildren(const Node* current, const Node* stayWithin)
+{
+    Node* node = NodeTraversal::nextIncludingPseudoSkippingChildren(current, stayWithin);
+    while (node && !node->isElementNode())
+        node = NodeTraversal::nextIncludingPseudoSkippingChildren(node, stayWithin);
+    return toElement(node);
+}
+
+inline Element* pseudoAwarePreviousSibling(const Node* current)
+{
+    Node* node = current->pseudoAwarePreviousSibling();
+    while (node && !node->isElementNode())
+        node = node->pseudoAwarePreviousSibling();
+    return toElement(node);
+}
+
+}
+
+}
+
+#endif
diff --git a/Source/core/dom/ErrorEvent.cpp b/Source/core/dom/ErrorEvent.cpp
index 7c4b3c1..ecb3d4b 100644
--- a/Source/core/dom/ErrorEvent.cpp
+++ b/Source/core/dom/ErrorEvent.cpp
@@ -50,7 +50,7 @@
 
 ErrorEvent::ErrorEvent(const AtomicString& type, const ErrorEventInit& initializer)
     : Event(type, initializer)
-    , m_message(initializer.message)
+    , m_sanitizedMessage(initializer.message)
     , m_fileName(initializer.filename)
     , m_lineNumber(initializer.lineno)
     , m_columnNumber(initializer.colno)
@@ -60,7 +60,7 @@
 
 ErrorEvent::ErrorEvent(const String& message, const String& fileName, unsigned lineNumber, unsigned columnNumber)
     : Event(eventNames().errorEvent, false, true)
-    , m_message(message)
+    , m_sanitizedMessage(message)
     , m_fileName(fileName)
     , m_lineNumber(lineNumber)
     , m_columnNumber(columnNumber)
@@ -68,6 +68,12 @@
     ScriptWrappable::init(this);
 }
 
+void ErrorEvent::setUnsanitizedMessage(const String& message)
+{
+    ASSERT(m_unsanitizedMessage.isEmpty());
+    m_unsanitizedMessage = message;
+}
+
 ErrorEvent::~ErrorEvent()
 {
 }
diff --git a/Source/core/dom/ErrorEvent.h b/Source/core/dom/ErrorEvent.h
index 8215544..583f07f 100644
--- a/Source/core/dom/ErrorEvent.h
+++ b/Source/core/dom/ErrorEvent.h
@@ -65,19 +65,26 @@
     }
     virtual ~ErrorEvent();
 
-    const String& message() const { return m_message; }
+    // As 'message' is exposed to JavaScript, never return unsanitizedMessage.
+    const String& message() const { return m_sanitizedMessage; }
     const String& filename() const { return m_fileName; }
     unsigned lineno() const { return m_lineNumber; }
     unsigned colno() const { return m_columnNumber; }
 
+    // 'messageForConsole' is not exposed to JavaScript, and prefers 'm_unsanitizedMessage'.
+    const String& messageForConsole() const { return !m_unsanitizedMessage.isEmpty() ? m_unsanitizedMessage : m_sanitizedMessage; }
+
     virtual const AtomicString& interfaceName() const;
 
+    void setUnsanitizedMessage(const String&);
+
 private:
     ErrorEvent();
     ErrorEvent(const String& message, const String& fileName, unsigned lineNumber, unsigned columnNumber);
     ErrorEvent(const AtomicString&, const ErrorEventInit&);
 
-    String m_message;
+    String m_unsanitizedMessage;
+    String m_sanitizedMessage;
     String m_fileName;
     unsigned m_lineNumber;
     unsigned m_columnNumber;
diff --git a/Source/core/dom/EventNames.h b/Source/core/dom/EventNames.h
index 0c01af9..098071d 100644
--- a/Source/core/dom/EventNames.h
+++ b/Source/core/dom/EventNames.h
@@ -125,6 +125,7 @@
     macro(upgradeneeded) \
     macro(versionchange) \
     macro(webkitvisibilitychange) \
+    macro(wheel) \
     macro(write) \
     macro(writeend) \
     macro(writestart) \
diff --git a/Source/core/dom/EventPathWalker.cpp b/Source/core/dom/EventPathWalker.cpp
index 4853df6..de1d4d0 100644
--- a/Source/core/dom/EventPathWalker.cpp
+++ b/Source/core/dom/EventPathWalker.cpp
@@ -27,7 +27,7 @@
 #include "config.h"
 #include "core/dom/EventPathWalker.h"
 
-#include "core/dom/shadow/ContentDistributor.h"
+#include "core/dom/shadow/ElementShadow.h"
 #include "core/dom/shadow/InsertionPoint.h"
 #include "core/dom/shadow/ShadowRoot.h"
 
@@ -58,7 +58,7 @@
     ASSERT(m_node);
     ASSERT(m_distributedNode);
     if (ElementShadow* shadow = shadowOfParent(m_node)) {
-        if (InsertionPoint* insertionPoint = shadow->distributor().findInsertionPointFor(m_distributedNode)) {
+        if (InsertionPoint* insertionPoint = shadow->findInsertionPointFor(m_distributedNode)) {
             m_node = insertionPoint;
             m_isVisitingInsertionPointInReprojection = true;
             return;
diff --git a/Source/core/dom/EventTarget.cpp b/Source/core/dom/EventTarget.cpp
index db40321..30c6854 100644
--- a/Source/core/dom/EventTarget.cpp
+++ b/Source/core/dom/EventTarget.cpp
@@ -68,6 +68,11 @@
     return 0;
 }
 
+MessagePort* EventTarget::toMessagePort()
+{
+    return 0;
+}
+
 inline DOMWindow* EventTarget::executingWindow()
 {
     if (ScriptExecutionContext* context = scriptExecutionContext())
@@ -176,11 +181,14 @@
 {
 }
 
-static AtomicString prefixedType(const Event* event)
+static AtomicString legacyType(const Event* event)
 {
     if (event->type() == eventNames().transitionendEvent)
         return eventNames().webkitTransitionEndEvent;
 
+    if (event->type() == eventNames().wheelEvent)
+        return eventNames().mousewheelEvent;
+
     return emptyString();
 }
 
@@ -193,30 +201,30 @@
     if (!d)
         return true;
 
-    EventListenerVector* listenerPrefixedVector = 0;
-    AtomicString prefixedTypeName = prefixedType(event);
-    if (!prefixedTypeName.isEmpty())
-        listenerPrefixedVector = d->eventListenerMap.find(prefixedTypeName);
+    EventListenerVector* legacyListenersVector = 0;
+    AtomicString legacyTypeName = legacyType(event);
+    if (!legacyTypeName.isEmpty())
+        legacyListenersVector = d->eventListenerMap.find(legacyTypeName);
 
-    EventListenerVector* listenerUnprefixedVector = d->eventListenerMap.find(event->type());
+    EventListenerVector* listenersVector = d->eventListenerMap.find(event->type());
 
-    if (listenerUnprefixedVector)
-        fireEventListeners(event, d, *listenerUnprefixedVector);
-    else if (listenerPrefixedVector) {
+    if (listenersVector) {
+        fireEventListeners(event, d, *listenersVector);
+    } else if (legacyListenersVector) {
         AtomicString unprefixedTypeName = event->type();
-        event->setType(prefixedTypeName);
-        fireEventListeners(event, d, *listenerPrefixedVector);
+        event->setType(legacyTypeName);
+        fireEventListeners(event, d, *legacyListenersVector);
         event->setType(unprefixedTypeName);
     }
 
-    if (!prefixedTypeName.isEmpty()) {
+    if (legacyTypeName == eventNames().webkitTransitionEndEvent) {
         if (DOMWindow* executingWindow = this->executingWindow()) {
-            if (listenerPrefixedVector) {
-                if (listenerUnprefixedVector)
+            if (legacyListenersVector) {
+                if (listenersVector)
                     UseCounter::count(executingWindow, UseCounter::PrefixedAndUnprefixedTransitionEndEvent);
                 else
                     UseCounter::count(executingWindow, UseCounter::PrefixedTransitionEndEvent);
-            } else if (listenerUnprefixedVector) {
+            } else if (listenersVector) {
                 UseCounter::count(executingWindow, UseCounter::UnprefixedTransitionEndEvent);
             }
         }
diff --git a/Source/core/dom/EventTarget.h b/Source/core/dom/EventTarget.h
index 633d2d2..267306a 100644
--- a/Source/core/dom/EventTarget.h
+++ b/Source/core/dom/EventTarget.h
@@ -38,8 +38,8 @@
 
 namespace WebCore {
 
+    class ApplicationCache;
     class AudioContext;
-    class DOMApplicationCache;
     class DOMWindow;
     class DedicatedWorkerGlobalScope;
     class Event;
@@ -106,6 +106,7 @@
 
         virtual Node* toNode();
         virtual DOMWindow* toDOMWindow();
+        virtual MessagePort* toMessagePort();
 
         virtual bool addEventListener(const AtomicString& eventType, PassRefPtr<EventListener>, bool useCapture);
         virtual bool removeEventListener(const AtomicString& eventType, EventListener*, bool useCapture);
diff --git a/Source/core/dom/EventTargetFactory.in b/Source/core/dom/EventTargetFactory.in
index 1929c1e..abe0c16 100644
--- a/Source/core/dom/EventTargetFactory.in
+++ b/Source/core/dom/EventTargetFactory.in
@@ -9,7 +9,7 @@
 core/html/track/TextTrack
 core/html/track/TextTrackCue
 core/html/track/TextTrackList
-core/loader/appcache/DOMApplicationCache
+core/loader/appcache/ApplicationCache
 core/page/EventSource
 core/page/Performance
 core/page/Window ImplementedAs=DOMWindow
diff --git a/Source/core/dom/FullscreenElementStack.cpp b/Source/core/dom/FullscreenElementStack.cpp
index 78dfe24..b72b25b 100644
--- a/Source/core/dom/FullscreenElementStack.cpp
+++ b/Source/core/dom/FullscreenElementStack.cpp
@@ -188,7 +188,7 @@
             break;
 
         // There is a previously-established user preference, security risk, or platform limitation.
-        if (!document()->page() || !document()->page()->settings()->fullScreenEnabled())
+        if (!document()->page() || !document()->page()->settings().fullScreenEnabled())
             break;
 
         // 2. Let doc be element's node document. (i.e. "this")
@@ -240,7 +240,7 @@
         // 5. Return, and run the remaining steps asynchronously.
         // 6. Optionally, perform some animation.
         m_areKeysEnabledInFullScreen = flags & Element::ALLOW_KEYBOARD_INPUT;
-        document()->page()->chrome().client()->enterFullScreenForElement(element);
+        document()->page()->chrome().client().enterFullScreenForElement(element);
 
         // 7. Optionally, display a message indicating how the user can exit displaying the context object fullscreen.
         return;
@@ -331,12 +331,12 @@
     // Only exit out of full screen window mode if there are no remaining elements in the
     // full screen stack.
     if (!newTop) {
-        document()->page()->chrome().client()->exitFullScreenForElement(m_fullScreenElement.get());
+        document()->page()->chrome().client().exitFullScreenForElement(m_fullScreenElement.get());
         return;
     }
 
     // Otherwise, notify the chrome of the new full screen element.
-    document()->page()->chrome().client()->enterFullScreenForElement(newTop);
+    document()->page()->chrome().client().enterFullScreenForElement(newTop);
 }
 
 bool FullscreenElementStack::webkitFullscreenEnabled(Document* document)
@@ -360,7 +360,7 @@
     if (!document()->page())
         return;
 
-    ASSERT(document()->page()->settings()->fullScreenEnabled());
+    ASSERT(document()->page()->settings().fullScreenEnabled());
 
     if (m_fullScreenRenderer)
         m_fullScreenRenderer->unwrapRenderer();
diff --git a/Source/core/dom/GestureEvent.cpp b/Source/core/dom/GestureEvent.cpp
index a4f5cf8..6423c0a 100644
--- a/Source/core/dom/GestureEvent.cpp
+++ b/Source/core/dom/GestureEvent.cpp
@@ -115,9 +115,6 @@
 
 bool GestureEventDispatchMediator::dispatchEvent(EventDispatcher* dispatcher) const
 {
-    if (isDisabledFormControl(dispatcher->node()))
-        return true;
-
     dispatcher->dispatch();
     ASSERT(!event()->defaultPrevented());
     return event()->defaultHandled() || event()->defaultPrevented();
diff --git a/Source/core/dom/MessageChannel.idl b/Source/core/dom/MessageChannel.idl
index 3d62729..f5b5165 100644
--- a/Source/core/dom/MessageChannel.idl
+++ b/Source/core/dom/MessageChannel.idl
@@ -26,13 +26,9 @@
 
 [
     GlobalContext=Window&WorkerGlobalScope,
-    Constructor,
-    ConstructorCallWith=ScriptExecutionContext,
     CustomConstructor
 ] interface MessageChannel {
-
     readonly attribute MessagePort port1;
     readonly attribute MessagePort port2;
-
 };
 
diff --git a/Source/core/dom/MessageEvent.cpp b/Source/core/dom/MessageEvent.cpp
index ce6e8fa..351275c 100644
--- a/Source/core/dom/MessageEvent.cpp
+++ b/Source/core/dom/MessageEvent.cpp
@@ -33,6 +33,11 @@
 
 namespace WebCore {
 
+static inline bool isValidSource(EventTarget* source)
+{
+    return !source || source->toDOMWindow() || source->toMessagePort();
+}
+
 MessageEventInit::MessageEventInit()
 {
 }
@@ -48,13 +53,14 @@
     , m_dataType(DataTypeScriptValue)
     , m_origin(initializer.origin)
     , m_lastEventId(initializer.lastEventId)
-    , m_source(initializer.source)
+    , m_source(isValidSource(initializer.source.get()) ? initializer.source : 0)
     , m_ports(adoptPtr(new MessagePortArray(initializer.ports)))
 {
     ScriptWrappable::init(this);
+    ASSERT(isValidSource(m_source.get()));
 }
 
-MessageEvent::MessageEvent(const String& origin, const String& lastEventId, PassRefPtr<DOMWindow> source, PassOwnPtr<MessagePortArray> ports)
+MessageEvent::MessageEvent(const String& origin, const String& lastEventId, PassRefPtr<EventTarget> source, PassOwnPtr<MessagePortArray> ports)
     : Event(eventNames().messageEvent, false, false)
     , m_dataType(DataTypeScriptValue)
     , m_origin(origin)
@@ -63,9 +69,10 @@
     , m_ports(ports)
 {
     ScriptWrappable::init(this);
+    ASSERT(isValidSource(m_source.get()));
 }
 
-MessageEvent::MessageEvent(PassRefPtr<SerializedScriptValue> data, const String& origin, const String& lastEventId, PassRefPtr<DOMWindow> source, PassOwnPtr<MessagePortArray> ports)
+MessageEvent::MessageEvent(PassRefPtr<SerializedScriptValue> data, const String& origin, const String& lastEventId, PassRefPtr<EventTarget> source, PassOwnPtr<MessagePortArray> ports)
     : Event(eventNames().messageEvent, false, false)
     , m_dataType(DataTypeSerializedScriptValue)
     , m_dataAsSerializedScriptValue(data)
@@ -77,6 +84,7 @@
     ScriptWrappable::init(this);
     if (m_dataAsSerializedScriptValue)
         m_dataAsSerializedScriptValue->registerMemoryAllocatedWithCurrentScriptContext();
+    ASSERT(isValidSource(m_source.get()));
 }
 
 MessageEvent::MessageEvent(const String& data, const String& origin)
diff --git a/Source/core/dom/MessageEvent.h b/Source/core/dom/MessageEvent.h
index 7f54232..e6647c1 100644
--- a/Source/core/dom/MessageEvent.h
+++ b/Source/core/dom/MessageEvent.h
@@ -30,6 +30,7 @@
 
 #include "bindings/v8/SerializedScriptValue.h"
 #include "core/dom/Event.h"
+#include "core/dom/EventTarget.h"
 #include "core/dom/MessagePort.h"
 #include "core/fileapi/Blob.h"
 #include "core/page/DOMWindow.h"
@@ -37,14 +38,12 @@
 
 namespace WebCore {
 
-class DOMWindow;
-
 struct MessageEventInit : public EventInit {
     MessageEventInit();
 
     String origin;
     String lastEventId;
-    RefPtr<DOMWindow> source;
+    RefPtr<EventTarget> source;
     MessagePortArray ports;
 };
 
@@ -54,11 +53,11 @@
     {
         return adoptRef(new MessageEvent);
     }
-    static PassRefPtr<MessageEvent> create(PassOwnPtr<MessagePortArray> ports, const String& origin = "", const String& lastEventId = "", PassRefPtr<DOMWindow> source = 0)
+    static PassRefPtr<MessageEvent> create(PassOwnPtr<MessagePortArray> ports, const String& origin = "", const String& lastEventId = "", PassRefPtr<EventTarget> source = 0)
     {
         return adoptRef(new MessageEvent(origin, lastEventId, source, ports));
     }
-    static PassRefPtr<MessageEvent> create(PassOwnPtr<MessagePortArray> ports, PassRefPtr<SerializedScriptValue> data, const String& origin = "", const String& lastEventId = "", PassRefPtr<DOMWindow> source = 0)
+    static PassRefPtr<MessageEvent> create(PassOwnPtr<MessagePortArray> ports, PassRefPtr<SerializedScriptValue> data, const String& origin = "", const String& lastEventId = "", PassRefPtr<EventTarget> source = 0)
     {
         return adoptRef(new MessageEvent(data, origin, lastEventId, source, ports));
     }
@@ -85,7 +84,7 @@
 
     const String& origin() const { return m_origin; }
     const String& lastEventId() const { return m_lastEventId; }
-    DOMWindow* source() const { return m_source.get(); }
+    EventTarget* source() const { return m_source.get(); }
     MessagePortArray ports() const { return m_ports ? *m_ports : MessagePortArray(); }
 
     virtual const AtomicString& interfaceName() const;
@@ -112,8 +111,8 @@
 private:
     MessageEvent();
     MessageEvent(const AtomicString&, const MessageEventInit&);
-    MessageEvent(const String& origin, const String& lastEventId, PassRefPtr<DOMWindow> source, PassOwnPtr<MessagePortArray>);
-    MessageEvent(PassRefPtr<SerializedScriptValue> data, const String& origin, const String& lastEventId, PassRefPtr<DOMWindow> source, PassOwnPtr<MessagePortArray>);
+    MessageEvent(const String& origin, const String& lastEventId, PassRefPtr<EventTarget> source, PassOwnPtr<MessagePortArray>);
+    MessageEvent(PassRefPtr<SerializedScriptValue> data, const String& origin, const String& lastEventId, PassRefPtr<EventTarget> source, PassOwnPtr<MessagePortArray>);
 
     explicit MessageEvent(const String& data, const String& origin);
     explicit MessageEvent(PassRefPtr<Blob> data, const String& origin);
@@ -126,7 +125,7 @@
     RefPtr<ArrayBuffer> m_dataAsArrayBuffer;
     String m_origin;
     String m_lastEventId;
-    RefPtr<DOMWindow> m_source;
+    RefPtr<EventTarget> m_source;
     OwnPtr<MessagePortArray> m_ports;
 };
 
diff --git a/Source/core/dom/MessageEvent.idl b/Source/core/dom/MessageEvent.idl
index 3bc8866..33d1c33 100644
--- a/Source/core/dom/MessageEvent.idl
+++ b/Source/core/dom/MessageEvent.idl
@@ -31,7 +31,7 @@
 ] interface MessageEvent : Event {
     [InitializedByEventConstructor] readonly attribute DOMString origin;
     [InitializedByEventConstructor] readonly attribute DOMString lastEventId;
-    [InitializedByEventConstructor] readonly attribute Window source;
+    [InitializedByEventConstructor] readonly attribute EventTarget source; // May be a Window or a MessagePort
     [InitializedByEventConstructor, CustomGetter] readonly attribute any data;
     [InitializedByEventConstructor] readonly attribute MessagePort[] ports;
 
diff --git a/Source/core/dom/MessagePort.h b/Source/core/dom/MessagePort.h
index 337e225..34773c9 100644
--- a/Source/core/dom/MessagePort.h
+++ b/Source/core/dom/MessagePort.h
@@ -75,6 +75,7 @@
 
     virtual const AtomicString& interfaceName() const OVERRIDE;
     virtual ScriptExecutionContext* scriptExecutionContext() const OVERRIDE;
+    MessagePort* toMessagePort() OVERRIDE { return this; }
 
     void dispatchMessages();
 
diff --git a/Source/core/dom/MessagePort.idl b/Source/core/dom/MessagePort.idl
index 4324172..17ae449 100644
--- a/Source/core/dom/MessagePort.idl
+++ b/Source/core/dom/MessagePort.idl
@@ -28,8 +28,6 @@
 [
     ActiveDOMObject
 ] interface MessagePort : EventTarget {
-// We need to have something as an ObjC binding, because MessagePort is used in MessageEvent, which already has one,
-// but we don't want to actually expose the API while it is in flux.
     [Custom, RaisesException] void postMessage(any message, optional Array messagePorts);
 
     void start();
diff --git a/Source/core/dom/Node.cpp b/Source/core/dom/Node.cpp
index 3936024..c4eebe4 100644
--- a/Source/core/dom/Node.cpp
+++ b/Source/core/dom/Node.cpp
@@ -71,6 +71,7 @@
 #include "core/dom/shadow/InsertionPoint.h"
 #include "core/dom/shadow/ShadowRoot.h"
 #include "core/editing/htmlediting.h"
+#include "core/html/HTMLAnchorElement.h"
 #include "core/html/HTMLFrameOwnerElement.h"
 #include "core/html/HTMLStyleElement.h"
 #include "core/html/RadioNodeList.h"
@@ -83,6 +84,7 @@
 #include "core/platform/Partitions.h"
 #include "core/rendering/FlowThreadController.h"
 #include "core/rendering/RenderBox.h"
+#include "core/svg/graphics/SVGImage.h"
 #include "wtf/HashSet.h"
 #include "wtf/PassOwnPtr.h"
 #include "wtf/RefCountedLeakCounter.h"
@@ -782,6 +784,11 @@
     clearChildNeedsDistributionRecalc();
 }
 
+void Node::setIsLink(bool isLink)
+{
+    setFlag(isLink && !SVGImage::isInSVGImage(toElement(this)), IsLinkFlag);
+}
+
 void Node::markAncestorsWithChildNeedsDistributionRecalc()
 {
     for (Node* node = this; node && !node->childNeedsDistributionRecalc(); node = node->parentOrShadowHostNode())
@@ -833,25 +840,14 @@
 
 void Node::lazyAttach(ShouldSetAttached shouldSetAttached)
 {
-    // It's safe to synchronously attach here because we're in the middle of style recalc
-    // while it's not safe to mark nodes as needing style recalc except in the loop in
-    // Element::recalcStyle because we may mark an ancestor as not needing recalc and
-    // then the node would never get updated. One place this currently happens is
-    // HTMLObjectElement::renderFallbackContent which may call lazyAttach from inside
-    // attach which was triggered by a recalcStyle.
-    if (document()->inStyleRecalc()) {
-        attach();
-        return;
-    }
     markAncestorsWithChildNeedsStyleRecalc();
     for (Node* node = this; node; node = NodeTraversal::next(node, this)) {
         node->setStyleChange(LazyAttachStyleChange);
-        node->setChildNeedsStyleRecalc();
+        if (node->isContainerNode())
+            node->setChildNeedsStyleRecalc();
         // FIXME: This flag is only used by HTMLFrameElementBase and doesn't look needed.
         if (shouldSetAttached == SetAttached)
             node->setAttached();
-        if (isActiveInsertionPoint(node))
-            toInsertionPoint(node)->lazyAttachDistribution(shouldSetAttached);
         for (ShadowRoot* root = node->youngestShadowRoot(); root; root = root->olderShadowRoot())
             root->lazyAttach(shouldSetAttached);
     }
@@ -868,6 +864,14 @@
     return true;
 }
 
+bool Node::isInert() const
+{
+    const Element* dialog = document()->activeModalDialog();
+    if (dialog && !containsIncludingShadowDOM(dialog) && !dialog->containsIncludingShadowDOM(this))
+        return true;
+    return document()->ownerElement() && document()->ownerElement()->isInert();
+}
+
 unsigned Node::nodeIndex() const
 {
     Node *_tempNode = previousSibling();
@@ -1030,6 +1034,33 @@
     return false;
 }
 
+inline void Node::detachNode(Node* root, const AttachContext& context)
+{
+    Node* node = root;
+    while (node) {
+        if (node->styleChangeType() == LazyAttachStyleChange) {
+            // FIXME: This is needed because Node::lazyAttach marks nodes as being attached even
+            // though they've never been through attach(). This allows us to avoid doing all the
+            // virtual calls to detach() and other associated work.
+            node->clearAttached();
+            node->clearChildNeedsStyleRecalc();
+
+            for (ShadowRoot* shadowRoot = node->youngestShadowRoot(); shadowRoot; shadowRoot = shadowRoot->olderShadowRoot())
+                detachNode(shadowRoot, context);
+
+            node = NodeTraversal::next(node, root);
+            continue;
+        }
+        // Handle normal reattaches from style recalc (ex. display type changes)
+        // or descendants of lazy attached nodes that got actually attached, for example,
+        // by innerHTML or editing.
+        // FIXME: innerHTML and editing should also lazyAttach.
+        if (node->attached())
+            node->detach(context);
+        node = NodeTraversal::nextSkippingChildren(node, root);
+    }
+}
+
 void Node::reattach(const AttachContext& context)
 {
     // FIXME: Text::updateTextRenderer calls reattach outside a style recalc.
@@ -1037,8 +1068,7 @@
     AttachContext reattachContext(context);
     reattachContext.performingReattach = true;
 
-    if (attached())
-        detach(reattachContext);
+    detachNode(this, reattachContext);
     attach(reattachContext);
 }
 
@@ -1110,7 +1140,7 @@
         }
     }
 
-    clearFlag(IsAttachedFlag);
+    clearAttached();
 
 #ifndef NDEBUG
     detachingNode = 0;
@@ -1681,7 +1711,7 @@
             ChildListMutationScope mutation(this);
             container->removeChildren();
             if (!text.isEmpty())
-                container->appendChild(document()->createTextNode(text), es, AttachLazily);
+                container->appendChild(document()->createTextNode(text), es);
             return;
         }
         case DOCUMENT_NODE:
@@ -1867,8 +1897,6 @@
     return p;
 }
 
-#ifndef NDEBUG
-
 String Node::debugName() const
 {
     StringBuilder name;
@@ -1893,6 +1921,8 @@
     return name.toString();
 }
 
+#ifndef NDEBUG
+
 static void appendAttributeDesc(const Node* node, StringBuilder& stringBuilder, const QualifiedName& name, const char* attrDesc)
 {
     if (!node->isElementNode())
@@ -2125,7 +2155,13 @@
         if (AXObjectCache* cache = oldDocument->existingAXObjectCache())
             cache->remove(this);
 
-    const EventListenerVector& wheelListeners = getEventListeners(eventNames().mousewheelEvent);
+    const EventListenerVector& mousewheelListeners = getEventListeners(eventNames().mousewheelEvent);
+    for (size_t i = 0; i < mousewheelListeners.size(); ++i) {
+        oldDocument->didRemoveWheelEventHandler();
+        document()->didAddWheelEventHandler();
+    }
+
+    const EventListenerVector& wheelListeners = getEventListeners(eventNames().wheelEvent);
     for (size_t i = 0; i < wheelListeners.size(); ++i) {
         oldDocument->didRemoveWheelEventHandler();
         document()->didAddWheelEventHandler();
@@ -2158,7 +2194,7 @@
 
     if (Document* document = targetNode->document()) {
         document->addListenerTypeIfNeeded(eventType);
-        if (eventType == eventNames().mousewheelEvent)
+        if (eventType == eventNames().wheelEvent || eventType == eventNames().mousewheelEvent)
             document->didAddWheelEventHandler();
         else if (eventNames().isTouchEventType(eventType))
             document->didAddTouchEventHandler(targetNode);
@@ -2180,7 +2216,7 @@
     // FIXME: Notify Document that the listener has vanished. We need to keep track of a number of
     // listeners for each type, not just a bool - see https://bugs.webkit.org/show_bug.cgi?id=33861
     if (Document* document = targetNode->document()) {
-        if (eventType == eventNames().mousewheelEvent)
+        if (eventType == eventNames().wheelEvent || eventType == eventNames().mousewheelEvent)
             document->didRemoveWheelEventHandler();
         else if (eventNames().isTouchEventType(eventType))
             document->didRemoveTouchEventHandler(targetNode);
@@ -2464,9 +2500,8 @@
         if (dispatchDOMActivateEvent(detail, event))
             event->setDefaultHandled();
     } else if (eventType == eventNames().contextmenuEvent) {
-        if (Frame* frame = document()->frame())
-            if (Page* page = frame->page())
-                page->contextMenuController()->handleContextMenuEvent(event);
+        if (Page* page = document()->page())
+            page->contextMenuController().handleContextMenuEvent(event);
     } else if (eventType == eventNames().textInputEvent) {
         if (event->hasInterface(eventNames().interfaceForTextEvent))
             if (Frame* frame = document()->frame())
@@ -2488,7 +2523,7 @@
             }
         }
 #endif
-    } else if (eventType == eventNames().mousewheelEvent && event->hasInterface(eventNames().interfaceForWheelEvent)) {
+    } else if ((eventType == eventNames().wheelEvent || eventType == eventNames().mousewheelEvent) && event->hasInterface(eventNames().interfaceForWheelEvent)) {
         WheelEvent* wheelEvent = static_cast<WheelEvent*>(event);
 
         // If we don't have a renderer, send the wheel event to the first node we find with a renderer.
@@ -2623,15 +2658,14 @@
     document()->updateDistributionForNodeIfNeeded(this);
     Vector<InsertionPoint*, 8> insertionPoints;
     collectInsertionPointsWhereNodeIsDistributed(this, insertionPoints);
+    Vector<RefPtr<Node> > filteredInsertionPoints;
     for (size_t i = 0; i < insertionPoints.size(); ++i) {
         InsertionPoint* insertionPoint = insertionPoints[i];
         ASSERT(insertionPoint->containingShadowRoot());
-        if (insertionPoint->containingShadowRoot()->type() == ShadowRoot::UserAgentShadowRoot)
-            return StaticNodeList::createEmpty();
+        if (insertionPoint->containingShadowRoot()->type() != ShadowRoot::UserAgentShadowRoot)
+            filteredInsertionPoints.append(insertionPoint);
     }
-    Vector<RefPtr<Node> > asNodes;
-    asNodes.appendRange(insertionPoints.begin(), insertionPoints.end());
-    return StaticNodeList::adopt(asNodes);
+    return StaticNodeList::adopt(filteredInsertionPoints);
 }
 
 void Node::registerScopedHTMLStyleChild()
@@ -2707,22 +2741,22 @@
         ASSERT_NOT_REACHED(); // Everything starts in this state
         return;
 
-    case UpgradeCandidate:
+    case WaitingForParser:
         ASSERT(NotCustomElement == oldState);
         break;
 
-    case Defined:
-        ASSERT(UpgradeCandidate == oldState || NotCustomElement == oldState);
+    case WaitingForUpgrade:
+        ASSERT(NotCustomElement == oldState || WaitingForParser == oldState);
         break;
 
     case Upgraded:
-        ASSERT(Defined == oldState);
+        ASSERT(WaitingForParser == oldState || WaitingForUpgrade == oldState);
         break;
     }
 
     ASSERT(isHTMLElement() || isSVGElement());
-    setFlag(newState & 1, CustomElementIsUpgradeCandidateOrUpgraded);
-    setFlag(newState & 2, CustomElementHasDefinitionOrIsUpgraded);
+    setFlag(newState & 1, CustomElementWaitingForParserOrIsUpgraded);
+    setFlag(newState & 2, CustomElementWaitingForUpgradeOrIsUpgraded);
 
     if (oldState == NotCustomElement || newState == Upgraded)
         setNeedsStyleRecalc(); // :unresolved has changed
diff --git a/Source/core/dom/Node.h b/Source/core/dom/Node.h
index a651d06..bdfdb4c 100644
--- a/Source/core/dom/Node.h
+++ b/Source/core/dom/Node.h
@@ -25,6 +25,7 @@
 #ifndef Node_h
 #define Node_h
 
+#include "bindings/v8/ExceptionStatePlaceholder.h"
 #include "bindings/v8/ScriptWrappable.h"
 #include "core/dom/EventTarget.h"
 #include "core/dom/MutationObserver.h"
@@ -114,7 +115,7 @@
 };
 
 enum AttachBehavior {
-    AttachNow,
+    DeprecatedAttachNow,
     AttachLazily,
 };
 
@@ -204,10 +205,10 @@
     // These should all actually return a node, but this is only important for language bindings,
     // which will already know and hold a ref on the right node to return. Returning bool allows
     // these methods to be more efficient since they don't need to return a ref
-    void insertBefore(PassRefPtr<Node> newChild, Node* refChild, ExceptionState&, AttachBehavior = AttachNow);
-    void replaceChild(PassRefPtr<Node> newChild, Node* oldChild, ExceptionState&, AttachBehavior = AttachNow);
+    void insertBefore(PassRefPtr<Node> newChild, Node* refChild, ExceptionState& = ASSERT_NO_EXCEPTION, AttachBehavior = AttachLazily);
+    void replaceChild(PassRefPtr<Node> newChild, Node* oldChild, ExceptionState& = ASSERT_NO_EXCEPTION, AttachBehavior = AttachLazily);
     void removeChild(Node* child, ExceptionState&);
-    void appendChild(PassRefPtr<Node> newChild, ExceptionState&, AttachBehavior = AttachNow);
+    void appendChild(PassRefPtr<Node> newChild, ExceptionState& = ASSERT_NO_EXCEPTION, AttachBehavior = AttachLazily);
 
     bool hasChildNodes() const { return firstChild(); }
     virtual PassRefPtr<Node> cloneNode(bool deep = true) = 0;
@@ -245,12 +246,12 @@
 
     enum CustomElementState {
         NotCustomElement,
-        UpgradeCandidate,
-        Defined,
+        WaitingForParser,
+        WaitingForUpgrade,
         Upgraded
     };
     bool isCustomElement() const { return customElementState() != NotCustomElement; }
-    CustomElementState customElementState() const { return CustomElementState((getFlag(CustomElementHasDefinitionOrIsUpgraded) ? 2 : 0) | (getFlag(CustomElementIsUpgradeCandidateOrUpgraded) ? 1 : 0)); }
+    CustomElementState customElementState() const { return CustomElementState((getFlag(CustomElementWaitingForParserOrIsUpgraded) ? 1 : 0) | (getFlag(CustomElementWaitingForUpgradeOrIsUpgraded) ? 2 : 0)); }
     void setCustomElementState(CustomElementState newState);
 
     virtual bool isMediaControlElement() const { return false; }
@@ -400,9 +401,7 @@
 
     bool shouldNotifyRendererWithIdenticalStyles() const { return getFlag(NotifyRendererWithIdenticalStyles); }
 
-    void setIsLink(bool f) { setFlag(f, IsLinkFlag); }
-    void setIsLink() { setFlag(IsLinkFlag); }
-    void clearIsLink() { clearFlag(IsLinkFlag); }
+    void setIsLink(bool f);
 
     void setInNamedFlow() { setFlag(InNamedFlowFlag); }
     void clearInNamedFlow() { clearFlag(InNamedFlowFlag); }
@@ -433,6 +432,10 @@
     // This is called only when the node is focused.
     virtual bool shouldHaveFocusAppearance() const;
 
+    // Whether the node is inert. This can't be in Element because text nodes
+    // must be recognized as inert to prevent text selection.
+    bool isInert() const;
+
     enum UserSelectAllTreatment {
         UserSelectAllDoesNotAffectEditability,
         UserSelectAllIsAlwaysNonEditable
@@ -608,9 +611,9 @@
     //
     virtual void removedFrom(ContainerNode* insertionPoint);
 
-#ifndef NDEBUG
     String debugName() const;
 
+#ifndef NDEBUG
     virtual void formatForDebugger(char* buffer, unsigned length) const;
 
     void showNode(const char* prefix = "") const;
@@ -713,6 +716,9 @@
 
     PassRefPtr<NodeList> getDestinationInsertionPoints();
 
+    void setAlreadySpellChecked(bool flag) { setFlag(flag, AlreadySpellCheckedFlag); }
+    bool isAlreadySpellChecked() { return getFlag(AlreadySpellCheckedFlag); }
+
 private:
     enum NodeFlags {
         IsTextFlag = 1,
@@ -750,10 +756,11 @@
 
         NotifyRendererWithIdenticalStyles = 1 << 26,
 
-        CustomElementIsUpgradeCandidateOrUpgraded = 1 << 27,
-        CustomElementHasDefinitionOrIsUpgraded = 1 << 28,
+        CustomElementWaitingForParserOrIsUpgraded = 1 << 27,
+        CustomElementWaitingForUpgradeOrIsUpgraded = 1 << 28,
 
         ChildNeedsDistributionRecalc = 1 << 29,
+        AlreadySpellCheckedFlag = 1 << 30,
 
         DefaultNodeFlags = IsParsingChildrenFinishedFlag
     };
@@ -839,6 +846,9 @@
 
     void setStyleChange(StyleChangeType);
 
+    void detachNode(Node*, const AttachContext&);
+    void clearAttached() { clearFlag(IsAttachedFlag); }
+
     // Used to share code between lazyAttach and setNeedsStyleRecalc.
     void markAncestorsWithChildNeedsStyleRecalc();
 
diff --git a/Source/core/dom/Node.idl b/Source/core/dom/Node.idl
index 0c7c5a1..3d774a2 100644
--- a/Source/core/dom/Node.idl
+++ b/Source/core/dom/Node.idl
@@ -61,12 +61,12 @@
     [CustomElementCallbacks=Enable] void normalize();
 
     // Introduced in DOM Level 2:
-     boolean isSupported([Default=Undefined] optional DOMString feature,
-                                       [TreatNullAs=NullString,Default=Undefined] optional DOMString version);
+    [MeasureAs=NodeIsSupported] boolean isSupported([Default=Undefined] optional DOMString feature,
+                                                    [TreatNullAs=NullString,Default=Undefined] optional DOMString version); // Removed in DOM4.
 
-    [TreatReturnedNullStringAs=Null, PerWorldBindings] readonly attribute DOMString        namespaceURI;
-             [TreatReturnedNullStringAs=Null, TreatNullAs=NullString, PerWorldBindings, SetterRaisesException] attribute DOMString        prefix;
-    [TreatReturnedNullStringAs=Null, PerWorldBindings] readonly attribute DOMString        localName;
+    [TreatReturnedNullStringAs=Null, PerWorldBindings, MeasureAs=NodeNamespaceURI] readonly attribute DOMString namespaceURI; // Moved to Element and Attr in DOM4.
+    [TreatReturnedNullStringAs=Null, TreatNullAs=NullString, PerWorldBindings, SetterRaisesException, MeasureAs=NodePrefix] attribute DOMString prefix; // Moved to Element and Attr in DOM4.
+    [TreatReturnedNullStringAs=Null, PerWorldBindings, MeasureAs=NodeLocalName] readonly attribute DOMString localName; // Moved to Element and Attr in DOM4.
 
     // Introduced in DOM Level 3:
     [TreatReturnedNullStringAs=Null, PerWorldBindings] readonly attribute DOMString       baseURI;
@@ -74,7 +74,7 @@
              // FIXME: the spec says this can also raise on retrieval.
              [TreatReturnedNullStringAs=Null, TreatNullAs=NullString, PerWorldBindings, SetterRaisesException, CustomElementCallbacks=Enable] attribute DOMString       textContent;
 
-    boolean            isSameNode([Default=Undefined] optional Node other);
+    [MeasureAs=NodeIsSameNode] boolean isSameNode([Default=Undefined] optional Node other); // Removed in DOM4.
     boolean            isEqualNode([Default=Undefined] optional Node other);
     [TreatReturnedNullStringAs=Null] DOMString          lookupPrefix([TreatNullAs=NullString,Default=Undefined] optional DOMString namespaceURI);
     boolean            isDefaultNamespace([TreatNullAs=NullString,Default=Undefined] optional DOMString namespaceURI);
diff --git a/Source/core/dom/NodeTraversal.h b/Source/core/dom/NodeTraversal.h
index c9d5208..c6966a6 100644
--- a/Source/core/dom/NodeTraversal.h
+++ b/Source/core/dom/NodeTraversal.h
@@ -25,38 +25,10 @@
 #ifndef NodeTraversal_h
 #define NodeTraversal_h
 
-#include "core/dom/Element.h"
+#include "core/dom/Node.h"
 
 namespace WebCore {
 
-namespace ElementTraversal {
-
-// First element child of the node.
-Element* firstWithin(const Node*);
-Element* firstWithin(const ContainerNode*);
-
-// Pre-order traversal skipping non-element nodes.
-Element* next(const Node*);
-Element* next(const Node*, const Node* stayWithin);
-Element* next(const ContainerNode*);
-Element* next(const ContainerNode*, const Node* stayWithin);
-
-// Like next, but skips children.
-Element* nextSkippingChildren(const Node*);
-Element* nextSkippingChildren(const Node*, const Node* stayWithin);
-Element* nextSkippingChildren(const ContainerNode*);
-Element* nextSkippingChildren(const ContainerNode*, const Node* stayWithin);
-
-// Pre-order traversal including the pseudo-elements.
-Element* previousIncludingPseudo(const Node*, const Node* stayWithin = 0);
-Element* nextIncludingPseudo(const Node*, const Node* stayWithin = 0);
-Element* nextIncludingPseudoSkippingChildren(const Node*, const Node* stayWithin = 0);
-
-// Utility function to traverse only the element and pseudo-element siblings of a node.
-Element* pseudoAwarePreviousSibling(const Node*);
-
-}
-
 namespace NodeTraversal {
 
 // Does a pre-order traversal of the tree to find the next node after this one.
@@ -92,101 +64,6 @@
 Node* nextIncludingPseudo(const Node*, const Node* stayWithin = 0);
 Node* nextIncludingPseudoSkippingChildren(const Node*, const Node* stayWithin = 0);
 
-}
-
-namespace ElementTraversal {
-template <class NodeType>
-inline Element* firstElementWithinTemplate(NodeType* current)
-{
-    // Except for the root containers, only elements can have element children.
-    Node* node = current->firstChild();
-    while (node && !node->isElementNode())
-        node = node->nextSibling();
-    return toElement(node);
-}
-inline Element* firstWithin(const ContainerNode* current) { return firstElementWithinTemplate(current); }
-inline Element* firstWithin(const Node* current) { return firstElementWithinTemplate(current); }
-
-template <class NodeType>
-inline Element* traverseNextElementTemplate(NodeType* current)
-{
-    Node* node = NodeTraversal::next(current);
-    while (node && !node->isElementNode())
-        node = NodeTraversal::nextSkippingChildren(node);
-    return toElement(node);
-}
-inline Element* next(const ContainerNode* current) { return traverseNextElementTemplate(current); }
-inline Element* next(const Node* current) { return traverseNextElementTemplate(current); }
-
-template <class NodeType>
-inline Element* traverseNextElementTemplate(NodeType* current, const Node* stayWithin)
-{
-    Node* node = NodeTraversal::next(current, stayWithin);
-    while (node && !node->isElementNode())
-        node = NodeTraversal::nextSkippingChildren(node, stayWithin);
-    return toElement(node);
-}
-inline Element* next(const ContainerNode* current, const Node* stayWithin) { return traverseNextElementTemplate(current, stayWithin); }
-inline Element* next(const Node* current, const Node* stayWithin) { return traverseNextElementTemplate(current, stayWithin); }
-
-template <class NodeType>
-inline Element* traverseNextElementSkippingChildrenTemplate(NodeType* current)
-{
-    Node* node = NodeTraversal::nextSkippingChildren(current);
-    while (node && !node->isElementNode())
-        node = NodeTraversal::nextSkippingChildren(node);
-    return toElement(node);
-}
-inline Element* nextSkippingChildren(const ContainerNode* current) { return traverseNextElementSkippingChildrenTemplate(current); }
-inline Element* nextSkippingChildren(const Node* current) { return traverseNextElementSkippingChildrenTemplate(current); }
-
-template <class NodeType>
-inline Element* traverseNextElementSkippingChildrenTemplate(NodeType* current, const Node* stayWithin)
-{
-    Node* node = NodeTraversal::nextSkippingChildren(current, stayWithin);
-    while (node && !node->isElementNode())
-        node = NodeTraversal::nextSkippingChildren(node, stayWithin);
-    return toElement(node);
-}
-inline Element* nextSkippingChildren(const ContainerNode* current, const Node* stayWithin) { return traverseNextElementSkippingChildrenTemplate(current, stayWithin); }
-inline Element* nextSkippingChildren(const Node* current, const Node* stayWithin) { return traverseNextElementSkippingChildrenTemplate(current, stayWithin); }
-
-inline Element* previousIncludingPseudo(const Node* current, const Node* stayWithin)
-{
-    Node* node = NodeTraversal::previousIncludingPseudo(current, stayWithin);
-    while (node && !node->isElementNode())
-        node = NodeTraversal::previousIncludingPseudo(node, stayWithin);
-    return toElement(node);
-}
-
-inline Element* nextIncludingPseudo(const Node* current, const Node* stayWithin)
-{
-    Node* node = NodeTraversal::nextIncludingPseudo(current, stayWithin);
-    while (node && !node->isElementNode())
-        node = NodeTraversal::nextIncludingPseudo(node, stayWithin);
-    return toElement(node);
-}
-
-inline Element* nextIncludingPseudoSkippingChildren(const Node* current, const Node* stayWithin)
-{
-    Node* node = NodeTraversal::nextIncludingPseudoSkippingChildren(current, stayWithin);
-    while (node && !node->isElementNode())
-        node = NodeTraversal::nextIncludingPseudoSkippingChildren(node, stayWithin);
-    return toElement(node);
-}
-
-inline Element* pseudoAwarePreviousSibling(const Node* current)
-{
-    Node* node = current->pseudoAwarePreviousSibling();
-    while (node && !node->isElementNode())
-        node = node->pseudoAwarePreviousSibling();
-    return toElement(node);
-}
-
-}
-
-namespace NodeTraversal {
-
 Node* nextAncestorSibling(const Node*);
 Node* nextAncestorSibling(const Node*, const Node* stayWithin);
 
diff --git a/Source/core/dom/ParentNode.h b/Source/core/dom/ParentNode.h
new file mode 100644
index 0000000..9fb949a
--- /dev/null
+++ b/Source/core/dom/ParentNode.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2013 Samsung Electronics. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 THE COPYRIGHT
+ * OWNER 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 ParentNode_h
+#define ParentNode_h
+
+#include "core/dom/ContainerNode.h"
+
+namespace WebCore {
+
+class ParentNode {
+public:
+    static PassRefPtr<HTMLCollection> children(ContainerNode* node)
+    {
+        return node->children();
+    }
+
+    static Element* firstElementChild(ContainerNode* node)
+    {
+        return node->firstElementChild();
+    }
+
+    static Element* lastElementChild(ContainerNode* node)
+    {
+        return node->lastElementChild();
+    }
+
+    static unsigned childElementCount(ContainerNode* node)
+    {
+        return node->childElementCount();
+    }
+};
+
+} // namespace WebCore
+
+#endif // ParentNode_h
diff --git a/Source/core/dom/ParentNode.idl b/Source/core/dom/ParentNode.idl
index 358271b..8de54f8 100644
--- a/Source/core/dom/ParentNode.idl
+++ b/Source/core/dom/ParentNode.idl
@@ -1,6 +1,5 @@
 [
     NoInterfaceObject,
-    LegacyImplementedInBaseClass
 ] interface ParentNode {
     [PerWorldBindings] readonly attribute HTMLCollection children;
     [PerWorldBindings] readonly attribute Element firstElementChild;
diff --git a/Source/core/dom/PendingScript.cpp b/Source/core/dom/PendingScript.cpp
index aab3343..6ad05cf 100644
--- a/Source/core/dom/PendingScript.cpp
+++ b/Source/core/dom/PendingScript.cpp
@@ -27,7 +27,7 @@
 #include "core/dom/PendingScript.h"
 
 #include "core/dom/Element.h"
-#include "core/loader/cache/ScriptResource.h"
+#include "core/fetch/ScriptResource.h"
 
 namespace WebCore {
 
diff --git a/Source/core/dom/PendingScript.h b/Source/core/dom/PendingScript.h
index bf902b2..0f169a9 100644
--- a/Source/core/dom/PendingScript.h
+++ b/Source/core/dom/PendingScript.h
@@ -26,8 +26,8 @@
 #ifndef PendingScript_h
 #define PendingScript_h
 
-#include "core/loader/cache/ResourceClient.h"
-#include "core/loader/cache/ResourcePtr.h"
+#include "core/fetch/ResourceClient.h"
+#include "core/fetch/ResourcePtr.h"
 #include "wtf/PassRefPtr.h"
 #include "wtf/RefPtr.h"
 #include "wtf/text/TextPosition.h"
diff --git a/Source/core/dom/Position.cpp b/Source/core/dom/Position.cpp
index c71c102..02f46bc 100644
--- a/Source/core/dom/Position.cpp
+++ b/Source/core/dom/Position.cpp
@@ -844,7 +844,7 @@
 
 bool Position::nodeIsUserSelectNone(Node* node)
 {
-    return node && node->renderer() && node->renderer()->style()->userSelect() == SELECT_NONE && node->renderer()->style()->userModify() == READ_ONLY;
+    return node && node->renderer() && !node->renderer()->isSelectable();
 }
 
 ContainerNode* Position::findParent(const Node* node)
diff --git a/Source/core/dom/ProcessingInstruction.cpp b/Source/core/dom/ProcessingInstruction.cpp
index def6f8e..033c043 100644
--- a/Source/core/dom/ProcessingInstruction.cpp
+++ b/Source/core/dom/ProcessingInstruction.cpp
@@ -27,19 +27,18 @@
 #include "core/css/StyleSheetContents.h"
 #include "core/dom/Document.h"
 #include "core/dom/DocumentStyleSheetCollection.h"
-#include "core/loader/cache/CSSStyleSheetResource.h"
-#include "core/loader/cache/FetchRequest.h"
-#include "core/loader/cache/ResourceFetcher.h"
-#include "core/loader/cache/XSLStyleSheetResource.h"
+#include "core/fetch/CSSStyleSheetResource.h"
+#include "core/fetch/FetchRequest.h"
+#include "core/fetch/ResourceFetcher.h"
+#include "core/fetch/XSLStyleSheetResource.h"
 #include "core/xml/XSLStyleSheet.h"
 #include "core/xml/parser/XMLDocumentParser.h" // for parseAttributes()
 
 namespace WebCore {
 
 inline ProcessingInstruction::ProcessingInstruction(Document* document, const String& target, const String& data)
-    : Node(document, CreateOther)
+    : CharacterData(document, data, CreateOther)
     , m_target(target)
-    , m_data(data)
     , m_resource(0)
     , m_loading(false)
     , m_alternate(false)
@@ -67,14 +66,6 @@
         document()->styleSheetCollection()->removeStyleSheetCandidateNode(this);
 }
 
-void ProcessingInstruction::setData(const String& data)
-{
-    int oldLength = m_data.length();
-    m_data = data;
-    document()->textRemoved(this, 0, oldLength);
-    checkStyleSheet();
-}
-
 String ProcessingInstruction::nodeName() const
 {
     return m_target;
@@ -85,16 +76,6 @@
     return PROCESSING_INSTRUCTION_NODE;
 }
 
-String ProcessingInstruction::nodeValue() const
-{
-    return m_data;
-}
-
-void ProcessingInstruction::setNodeValue(const String& nodeValue)
-{
-    setData(nodeValue);
-}
-
 PassRefPtr<Node> ProcessingInstruction::cloneNode(bool /*deep*/)
 {
     // FIXME: Is it a problem that this does not copy m_localHref?
@@ -170,7 +151,7 @@
             else {
                 // The request may have been denied if (for example) the stylesheet is local and the document is remote.
                 m_loading = false;
-                document()->styleSheetCollection()->removePendingSheet();
+                document()->styleSheetCollection()->removePendingSheet(this);
             }
         }
     }
@@ -188,7 +169,7 @@
 bool ProcessingInstruction::sheetLoaded()
 {
     if (!isLoading()) {
-        document()->styleSheetCollection()->removePendingSheet();
+        document()->styleSheetCollection()->removePendingSheet(this);
         return true;
     }
     return false;
@@ -254,16 +235,6 @@
     sheet->setDisabled(m_alternate);
 }
 
-bool ProcessingInstruction::offsetInCharacters() const
-{
-    return true;
-}
-
-int ProcessingInstruction::maxCharacterOffset() const
-{
-    return static_cast<int>(m_data.length());
-}
-
 void ProcessingInstruction::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const
 {
     if (!sheet())
@@ -274,7 +245,7 @@
 
 Node::InsertionNotificationRequest ProcessingInstruction::insertedInto(ContainerNode* insertionPoint)
 {
-    Node::insertedInto(insertionPoint);
+    CharacterData::insertedInto(insertionPoint);
     if (!insertionPoint->inDocument())
         return InsertionDone;
     document()->styleSheetCollection()->addStyleSheetCandidateNode(this, m_createdByParser);
@@ -284,7 +255,7 @@
 
 void ProcessingInstruction::removedFrom(ContainerNode* insertionPoint)
 {
-    Node::removedFrom(insertionPoint);
+    CharacterData::removedFrom(insertionPoint);
     if (!insertionPoint->inDocument())
         return;
 
@@ -306,7 +277,7 @@
 void ProcessingInstruction::finishParsingChildren()
 {
     m_createdByParser = false;
-    Node::finishParsingChildren();
+    CharacterData::finishParsingChildren();
 }
 
 } // namespace
diff --git a/Source/core/dom/ProcessingInstruction.h b/Source/core/dom/ProcessingInstruction.h
index 1ae7976..7b216f0 100644
--- a/Source/core/dom/ProcessingInstruction.h
+++ b/Source/core/dom/ProcessingInstruction.h
@@ -22,23 +22,21 @@
 #ifndef ProcessingInstruction_h
 #define ProcessingInstruction_h
 
-#include "core/dom/Node.h"
-#include "core/loader/cache/ResourcePtr.h"
-#include "core/loader/cache/StyleSheetResourceClient.h"
+#include "core/dom/CharacterData.h"
+#include "core/fetch/ResourcePtr.h"
+#include "core/fetch/StyleSheetResourceClient.h"
 
 namespace WebCore {
 
 class StyleSheet;
 class CSSStyleSheet;
 
-class ProcessingInstruction FINAL : public Node, private StyleSheetResourceClient {
+class ProcessingInstruction FINAL : public CharacterData, private StyleSheetResourceClient {
 public:
     static PassRefPtr<ProcessingInstruction> create(Document*, const String& target, const String& data);
     virtual ~ProcessingInstruction();
 
     const String& target() const { return m_target; }
-    const String& data() const { return m_data; }
-    void setData(const String&);
 
     void setCreatedByParser(bool createdByParser) { m_createdByParser = createdByParser; }
 
@@ -54,15 +52,12 @@
     bool isLoading() const;
 
 private:
+    friend class CharacterData;
     ProcessingInstruction(Document*, const String& target, const String& data);
 
     virtual String nodeName() const;
     virtual NodeType nodeType() const;
-    virtual String nodeValue() const;
-    virtual void setNodeValue(const String&);
     virtual PassRefPtr<Node> cloneNode(bool deep = true);
-    virtual bool offsetInCharacters() const;
-    virtual int maxCharacterOffset() const;
 
     virtual InsertionNotificationRequest insertedInto(ContainerNode*) OVERRIDE;
     virtual void removedFrom(ContainerNode*) OVERRIDE;
@@ -78,7 +73,6 @@
     void parseStyleSheet(const String& sheet);
 
     String m_target;
-    String m_data;
     String m_localHref;
     String m_title;
     String m_media;
@@ -91,6 +85,12 @@
     bool m_isXSL;
 };
 
+inline ProcessingInstruction* toProcessingInstruction(Node* node)
+{
+    ASSERT_WITH_SECURITY_IMPLICATION(!node || node->nodeType() == Node::PROCESSING_INSTRUCTION_NODE);
+    return static_cast<ProcessingInstruction*>(node);
+}
+
 } //namespace
 
 #endif
diff --git a/Source/core/dom/ProcessingInstruction.idl b/Source/core/dom/ProcessingInstruction.idl
index 1767ee5..80aace5 100644
--- a/Source/core/dom/ProcessingInstruction.idl
+++ b/Source/core/dom/ProcessingInstruction.idl
@@ -18,12 +18,11 @@
  * Boston, MA 02110-1301, USA.
  */
 
-interface ProcessingInstruction : Node {
+interface ProcessingInstruction : CharacterData {
 
     // DOM Level 1
 
     [TreatReturnedNullStringAs=Null] readonly attribute DOMString target;
-             [TreatReturnedNullStringAs=Null, TreatNullAs=NullString] attribute DOMString data;
 
     // interface LinkStyle from DOM Level 2 Style Sheets
     readonly attribute StyleSheet sheet;
diff --git a/Source/core/dom/Promise.idl b/Source/core/dom/Promise.idl
index 2550866..d2fa864 100644
--- a/Source/core/dom/Promise.idl
+++ b/Source/core/dom/Promise.idl
@@ -28,6 +28,9 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+// FIXME: |PromiseValue| should be changed to |Promise|. http://crbug.com/266700
+// IDLs using |Promise| should be written with "typedef any PromiseValue;" and |PromiseValue|.
+
 callback PromiseInit = void (PromiseResolver resolver);
 callback AnyCallback = any (optional any value);
 [
diff --git a/Source/core/dom/QualifiedName.h b/Source/core/dom/QualifiedName.h
index 355ceeb..b42f9e4 100644
--- a/Source/core/dom/QualifiedName.h
+++ b/Source/core/dom/QualifiedName.h
@@ -82,6 +82,8 @@
 
     bool matches(const QualifiedName& other) const { return m_impl == other.m_impl || (localName() == other.localName() && namespaceURI() == other.namespaceURI()); }
 
+    bool matchesPossiblyIgnoringCase(const QualifiedName& other, bool shouldIgnoreCase) const { return m_impl == other.m_impl || (equalPossiblyIgnoringCase(localName(), other.localName(), shouldIgnoreCase) && namespaceURI() == other.namespaceURI()); }
+
     bool hasPrefix() const { return m_impl->m_prefix != nullAtom; }
     void setPrefix(const AtomicString& prefix) { *this = QualifiedName(prefix, localName(), namespaceURI()); }
 
diff --git a/Source/core/dom/ScriptExecutionContext.cpp b/Source/core/dom/ScriptExecutionContext.cpp
index 13191d8..2cc9e4b 100644
--- a/Source/core/dom/ScriptExecutionContext.cpp
+++ b/Source/core/dom/ScriptExecutionContext.cpp
@@ -205,13 +205,13 @@
     if (m_inDispatchErrorEvent) {
         if (!m_pendingExceptions)
             m_pendingExceptions = adoptPtr(new Vector<OwnPtr<PendingException> >());
-        m_pendingExceptions->append(adoptPtr(new PendingException(errorEvent->message(), errorEvent->lineno(), errorEvent->colno(), errorEvent->filename(), callStack)));
+        m_pendingExceptions->append(adoptPtr(new PendingException(errorEvent->messageForConsole(), errorEvent->lineno(), errorEvent->colno(), errorEvent->filename(), callStack)));
         return;
     }
 
     // First report the original exception and only then all the nested ones.
     if (!dispatchErrorEvent(errorEvent, corsStatus))
-        logExceptionToConsole(errorEvent->message(), errorEvent->filename(), errorEvent->lineno(), errorEvent->colno(), callStack);
+        logExceptionToConsole(errorEvent->messageForConsole(), errorEvent->filename(), errorEvent->lineno(), errorEvent->colno(), callStack);
 
     if (!m_pendingExceptions)
         return;
@@ -223,9 +223,14 @@
     m_pendingExceptions.clear();
 }
 
-void ScriptExecutionContext::addConsoleMessage(MessageSource source, MessageLevel level, const String& message, const String& sourceURL, unsigned lineNumber, ScriptState* state, unsigned long requestIdentifier)
+void ScriptExecutionContext::addConsoleMessage(MessageSource source, MessageLevel level, const String& message, const String& sourceURL, unsigned lineNumber)
 {
-    addMessage(source, level, message, sourceURL, lineNumber, 0, state, requestIdentifier);
+    addMessage(source, level, message, sourceURL, lineNumber, 0);
+}
+
+void ScriptExecutionContext::addConsoleMessage(MessageSource source, MessageLevel level, const String& message, ScriptState* state)
+{
+    addMessage(source, level, message, String(), 0, state);
 }
 
 bool ScriptExecutionContext::dispatchErrorEvent(PassRefPtr<ErrorEvent> event, AccessControlStatus corsStatus)
diff --git a/Source/core/dom/ScriptExecutionContext.h b/Source/core/dom/ScriptExecutionContext.h
index ee4a312..1bcf0ab 100644
--- a/Source/core/dom/ScriptExecutionContext.h
+++ b/Source/core/dom/ScriptExecutionContext.h
@@ -77,8 +77,8 @@
     bool shouldSanitizeScriptError(const String& sourceURL, AccessControlStatus);
     void reportException(PassRefPtr<ErrorEvent>, PassRefPtr<ScriptCallStack>, AccessControlStatus);
 
-    void addConsoleMessage(MessageSource, MessageLevel, const String& message, const String& sourceURL, unsigned lineNumber, ScriptState* = 0, unsigned long requestIdentifier = 0);
-    virtual void addConsoleMessage(MessageSource, MessageLevel, const String& message, unsigned long requestIdentifier = 0) = 0;
+    void addConsoleMessage(MessageSource, MessageLevel, const String& message, const String& sourceURL, unsigned lineNumber);
+    void addConsoleMessage(MessageSource, MessageLevel, const String& message, ScriptState* = 0);
 
     PublicURLManager& publicURLManager();
 
@@ -159,7 +159,7 @@
     virtual const KURL& virtualURL() const = 0;
     virtual KURL virtualCompleteURL(const String&) const = 0;
 
-    virtual void addMessage(MessageSource, MessageLevel, const String& message, const String& sourceURL, unsigned lineNumber, PassRefPtr<ScriptCallStack>, ScriptState* = 0, unsigned long requestIdentifier = 0) = 0;
+    virtual void addMessage(MessageSource, MessageLevel, const String& message, const String& sourceURL, unsigned lineNumber, ScriptState*) = 0;
     virtual EventTarget* errorEventTarget() = 0;
     virtual void logExceptionToConsole(const String& errorMessage, const String& sourceURL, int lineNumber, int columnNumber, PassRefPtr<ScriptCallStack>) = 0;
     bool dispatchErrorEvent(PassRefPtr<ErrorEvent>, AccessControlStatus);
diff --git a/Source/core/dom/ScriptLoader.cpp b/Source/core/dom/ScriptLoader.cpp
index 6d1c06b..55d6844 100644
--- a/Source/core/dom/ScriptLoader.cpp
+++ b/Source/core/dom/ScriptLoader.cpp
@@ -35,12 +35,12 @@
 #include "core/dom/ScriptRunner.h"
 #include "core/dom/ScriptableDocumentParser.h"
 #include "core/dom/Text.h"
+#include "core/fetch/FetchRequest.h"
+#include "core/fetch/ResourceFetcher.h"
+#include "core/fetch/ScriptResource.h"
 #include "core/html/HTMLImport.h"
 #include "core/html/HTMLScriptElement.h"
 #include "core/html/parser/HTMLParserIdioms.h"
-#include "core/loader/cache/FetchRequest.h"
-#include "core/loader/cache/ResourceFetcher.h"
-#include "core/loader/cache/ScriptResource.h"
 #include "core/page/ContentSecurityPolicy.h"
 #include "core/page/Frame.h"
 #include "core/platform/MIMETypeRegistry.h"
diff --git a/Source/core/dom/ScriptLoader.h b/Source/core/dom/ScriptLoader.h
index 390d83a..dfa8818 100644
--- a/Source/core/dom/ScriptLoader.h
+++ b/Source/core/dom/ScriptLoader.h
@@ -21,8 +21,8 @@
 #ifndef ScriptLoader_h
 #define ScriptLoader_h
 
-#include "core/loader/cache/ResourceClient.h"
-#include "core/loader/cache/ResourcePtr.h"
+#include "core/fetch/ResourceClient.h"
+#include "core/fetch/ResourcePtr.h"
 #include "wtf/text/TextPosition.h"
 #include "wtf/text/WTFString.h"
 
diff --git a/Source/core/dom/ScriptRunner.cpp b/Source/core/dom/ScriptRunner.cpp
index d25001e..f63ab50 100644
--- a/Source/core/dom/ScriptRunner.cpp
+++ b/Source/core/dom/ScriptRunner.cpp
@@ -30,7 +30,7 @@
 #include "core/dom/Element.h"
 #include "core/dom/PendingScript.h"
 #include "core/dom/ScriptLoader.h"
-#include "core/loader/cache/ScriptResource.h"
+#include "core/fetch/ScriptResource.h"
 
 namespace WebCore {
 
diff --git a/Source/core/dom/ScriptRunner.h b/Source/core/dom/ScriptRunner.h
index ef9e270..b793589 100644
--- a/Source/core/dom/ScriptRunner.h
+++ b/Source/core/dom/ScriptRunner.h
@@ -26,7 +26,7 @@
 #ifndef ScriptRunner_h
 #define ScriptRunner_h
 
-#include "core/loader/cache/ResourcePtr.h"
+#include "core/fetch/ResourcePtr.h"
 #include "core/platform/Timer.h"
 #include "wtf/HashMap.h"
 #include "wtf/Noncopyable.h"
diff --git a/Source/core/dom/SelectorQuery.cpp b/Source/core/dom/SelectorQuery.cpp
index 9e99139..db7afdf 100644
--- a/Source/core/dom/SelectorQuery.cpp
+++ b/Source/core/dom/SelectorQuery.cpp
@@ -33,7 +33,7 @@
 #include "core/css/SelectorCheckerFastPath.h"
 #include "core/css/SiblingTraversalStrategies.h"
 #include "core/dom/Document.h"
-#include "core/dom/NodeTraversal.h"
+#include "core/dom/ElementTraversal.h"
 #include "core/dom/StaticNodeList.h"
 
 namespace WebCore {
@@ -490,7 +490,7 @@
     CSSSelectorList selectorList;
     parser.parseSelector(selectors, selectorList);
 
-    if (!selectorList.first() || selectorList.hasInvalidSelector()) {
+    if (!selectorList.first()) {
         es.throwDOMException(SyntaxError);
         return 0;
     }
diff --git a/Source/core/dom/ShadowTreeStyleSheetCollection.cpp b/Source/core/dom/ShadowTreeStyleSheetCollection.cpp
new file mode 100644
index 0000000..2c53a05
--- /dev/null
+++ b/Source/core/dom/ShadowTreeStyleSheetCollection.cpp
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2001 Dirk Mueller (mueller@kde.org)
+ *           (C) 2006 Alexey Proskuryakov (ap@webkit.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "core/dom/ShadowTreeStyleSheetCollection.h"
+
+#include "HTMLNames.h"
+#include "core/css/CSSStyleSheet.h"
+#include "core/css/resolver/StyleResolver.h"
+#include "core/dom/Document.h"
+#include "core/dom/DocumentStyleSheetCollection.h"
+#include "core/dom/Element.h"
+#include "core/dom/shadow/ShadowRoot.h"
+#include "core/html/HTMLStyleElement.h"
+#include "core/page/Settings.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+ShadowTreeStyleSheetCollection::ShadowTreeStyleSheetCollection(ShadowRoot* shadowRoot)
+    : StyleSheetCollection(shadowRoot)
+{
+}
+
+void ShadowTreeStyleSheetCollection::collectStyleSheets(DocumentStyleSheetCollection* collections, Vector<RefPtr<StyleSheet> >& styleSheets, Vector<RefPtr<CSSStyleSheet> >& activeSheets)
+{
+    if (document()->settings() && !document()->settings()->authorAndUserStylesEnabled())
+        return;
+
+    DocumentOrderedList::iterator begin = m_styleSheetCandidateNodes.begin();
+    DocumentOrderedList::iterator end = m_styleSheetCandidateNodes.end();
+    for (DocumentOrderedList::iterator it = begin; it != end; ++it) {
+        Node* node = *it;
+        StyleSheet* sheet = 0;
+        CSSStyleSheet* activeSheet = 0;
+
+        if (!node->isHTMLElement() || !node->hasTagName(styleTag))
+            continue;
+
+        Element* element = toElement(node);
+        AtomicString title = element->getAttribute(titleAttr);
+        bool enabledViaScript = false;
+
+        sheet = static_cast<HTMLStyleElement*>(node)->sheet();
+        if (sheet && !sheet->disabled() && sheet->isCSSStyleSheet())
+            activeSheet = static_cast<CSSStyleSheet*>(sheet);
+
+        // FIXME: clarify how PREFERRED or ALTERNATE works in shadow trees.
+        // Should we set preferred/selected stylesheets name in shadow trees and
+        // use the name in document?
+        AtomicString rel = element->getAttribute(relAttr);
+        if (!enabledViaScript && sheet && !title.isEmpty()) {
+            if (collections->preferredStylesheetSetName().isEmpty()) {
+                if (element->hasLocalName(styleTag) || !rel.contains("alternate")) {
+                    collections->setPreferredStylesheetSetName(title);
+                    collections->setSelectedStylesheetSetName(title);
+                }
+            }
+            if (title != collections->preferredStylesheetSetName())
+                activeSheet = 0;
+        }
+
+        if (rel.contains("alternate") && title.isEmpty())
+            activeSheet = 0;
+
+        if (sheet)
+            styleSheets.append(sheet);
+        if (activeSheet)
+            activeSheets.append(activeSheet);
+    }
+}
+
+bool ShadowTreeStyleSheetCollection::updateActiveStyleSheets(DocumentStyleSheetCollection* collections, StyleResolverUpdateMode updateMode)
+{
+    Vector<RefPtr<StyleSheet> > styleSheets;
+    Vector<RefPtr<CSSStyleSheet> > activeCSSStyleSheets;
+    collectStyleSheets(collections, styleSheets, activeCSSStyleSheets);
+
+    bool requiresFullStyleRecalc = true;
+
+    // If we have already decided to destroy StyleResolver, we don't need to analyze. Reconstruction will take care.
+    if (StyleResolver* styleResolver = document()->styleResolverIfExists()) {
+        StyleResolverUpdateType styleResolverUpdateType;
+
+        analyzeStyleSheetChange(updateMode, activeAuthorStyleSheets(), activeCSSStyleSheets, styleResolverUpdateType, requiresFullStyleRecalc);
+
+        // FIXME: We might have already had styles in child treescope. In this case, we cannot use buildScopedStyleTreeInDocumentOrder.
+        // Need to change "false" to some valid condition.
+        styleResolver->setBuildScopedStyleTreeInDocumentOrder(false);
+        if (styleResolverUpdateType == Reset || styleResolverUpdateType == Reconstruct) {
+            // We should not destroy StyleResolver when we find any stylesheet update in a shadow tree.
+            // In this case, we will reset rulesets created from style elements in the shadow tree.
+            resetAllRuleSetsInTreeScope(styleResolver);
+            styleResolver->appendAuthorStyleSheets(0, activeCSSStyleSheets);
+        } else {
+            ASSERT(styleResolverUpdateType == Additive);
+            styleResolver->appendAuthorStyleSheets(m_activeAuthorStyleSheets.size(), activeCSSStyleSheets);
+        }
+    }
+    m_scopingNodesForStyleScoped.didRemoveScopingNodes();
+    m_activeAuthorStyleSheets.swap(activeCSSStyleSheets);
+    m_styleSheetsForStyleSheetList.swap(styleSheets);
+    updateUsesRemUnits();
+
+    return requiresFullStyleRecalc;
+}
+
+}
diff --git a/Source/core/dom/ShadowTreeStyleSheetCollection.h b/Source/core/dom/ShadowTreeStyleSheetCollection.h
new file mode 100644
index 0000000..e398440
--- /dev/null
+++ b/Source/core/dom/ShadowTreeStyleSheetCollection.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ *           (C) 1999 Antti Koivisto (koivisto@kde.org)
+ *           (C) 2001 Dirk Mueller (mueller@kde.org)
+ *           (C) 2006 Alexey Proskuryakov (ap@webkit.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef ShadowTreeStyleSheetCollection_h
+#define ShadowTreeStyleSheetCollection_h
+
+#include "core/dom/StyleSheetCollection.h"
+
+namespace WebCore {
+
+class CSSStyleSheet;
+class DocumentStyleSheetCollection;
+class ShadowRoot;
+class StyleSheet;
+class StyleSheetCollection;
+
+class ShadowTreeStyleSheetCollection FINAL : public StyleSheetCollection {
+    WTF_MAKE_NONCOPYABLE(ShadowTreeStyleSheetCollection); WTF_MAKE_FAST_ALLOCATED;
+public:
+    explicit ShadowTreeStyleSheetCollection(ShadowRoot*);
+
+    bool updateActiveStyleSheets(DocumentStyleSheetCollection*, StyleResolverUpdateMode);
+
+private:
+    void collectStyleSheets(DocumentStyleSheetCollection*, Vector<RefPtr<StyleSheet> >& styleSheets, Vector<RefPtr<CSSStyleSheet> >& activeSheets);
+};
+
+}
+
+#endif
+
diff --git a/Source/core/dom/StyleElement.cpp b/Source/core/dom/StyleElement.cpp
index 0320d16..8f31ee4 100644
--- a/Source/core/dom/StyleElement.cpp
+++ b/Source/core/dom/StyleElement.cpp
@@ -127,7 +127,7 @@
     Document* document = e->document();
     if (m_sheet) {
         if (m_sheet->isLoading())
-            document->styleSheetCollection()->removePendingSheet();
+            document->styleSheetCollection()->removePendingSheet(e);
         clearSheet();
     }
 
@@ -169,7 +169,7 @@
     if (isLoading())
         return false;
 
-    document->styleSheetCollection()->removePendingSheet();
+    document->styleSheetCollection()->removePendingSheet(m_sheet->ownerNode());
     return true;
 }
 
diff --git a/Source/core/dom/StyleSheetCollection.cpp b/Source/core/dom/StyleSheetCollection.cpp
index 80ca3d2..a665b80 100644
--- a/Source/core/dom/StyleSheetCollection.cpp
+++ b/Source/core/dom/StyleSheetCollection.cpp
@@ -37,13 +37,11 @@
 #include "core/dom/DocumentStyleSheetCollection.h"
 #include "core/dom/Element.h"
 #include "core/dom/ProcessingInstruction.h"
+#include "core/dom/shadow/ShadowRoot.h"
 #include "core/html/HTMLIFrameElement.h"
 #include "core/html/HTMLLinkElement.h"
 #include "core/html/HTMLStyleElement.h"
-#include "core/page/Page.h"
-#include "core/page/PageGroup.h"
 #include "core/page/Settings.h"
-#include "core/page/UserContentURLPattern.h"
 #include "core/svg/SVGStyleElement.h"
 
 namespace WebCore {
@@ -86,7 +84,115 @@
         m_scopingNodesForStyleScoped.remove(scopingNode);
 }
 
-void StyleSheetCollection::collectStyleSheets(DocumentStyleSheetCollection* collections, Vector<RefPtr<StyleSheet> >& styleSheets, Vector<RefPtr<CSSStyleSheet> >& activeSheets)
+StyleSheetCollection::StyleResolverUpdateType StyleSheetCollection::compareStyleSheets(const Vector<RefPtr<CSSStyleSheet> >& oldStyleSheets, const Vector<RefPtr<CSSStyleSheet> >& newStylesheets, Vector<StyleSheetContents*>& addedSheets)
+{
+    // Find out which stylesheets are new.
+    unsigned newStylesheetCount = newStylesheets.size();
+    unsigned oldStylesheetCount = oldStyleSheets.size();
+    if (newStylesheetCount < oldStylesheetCount)
+        return Reconstruct;
+
+    unsigned newIndex = 0;
+    for (unsigned oldIndex = 0; oldIndex < oldStylesheetCount; ++oldIndex) {
+        if (newIndex >= newStylesheetCount)
+            return Reconstruct;
+        while (oldStyleSheets[oldIndex] != newStylesheets[newIndex]) {
+            addedSheets.append(newStylesheets[newIndex]->contents());
+            ++newIndex;
+            if (newIndex == newStylesheetCount)
+                return Reconstruct;
+        }
+        ++newIndex;
+    }
+    bool hasInsertions = !addedSheets.isEmpty();
+    while (newIndex < newStylesheetCount) {
+        addedSheets.append(newStylesheets[newIndex]->contents());
+        ++newIndex;
+    }
+    // If all new sheets were added at the end of the list we can just add them to existing StyleResolver.
+    // If there were insertions we need to re-add all the stylesheets so rules are ordered correctly.
+    return hasInsertions ? Reset : Additive;
+}
+
+bool StyleSheetCollection::activeLoadingStyleSheetLoaded(const Vector<RefPtr<CSSStyleSheet> >& newStyleSheets)
+{
+    // StyleSheets of <style> elements that @import stylesheets are active but loading. We need to trigger a full recalc when such loads are done.
+    bool hasActiveLoadingStylesheet = false;
+    unsigned newStylesheetCount = newStyleSheets.size();
+    for (unsigned i = 0; i < newStylesheetCount; ++i) {
+        if (newStyleSheets[i]->isLoading())
+            hasActiveLoadingStylesheet = true;
+    }
+    if (m_hadActiveLoadingStylesheet && !hasActiveLoadingStylesheet) {
+        m_hadActiveLoadingStylesheet = false;
+        return true;
+    }
+    m_hadActiveLoadingStylesheet = hasActiveLoadingStylesheet;
+    return false;
+}
+
+void StyleSheetCollection::analyzeStyleSheetChange(StyleResolverUpdateMode updateMode, const Vector<RefPtr<CSSStyleSheet> >& oldStyleSheets, const Vector<RefPtr<CSSStyleSheet> >& newStyleSheets, StyleResolverUpdateType& styleResolverUpdateType, bool& requiresFullStyleRecalc)
+{
+    styleResolverUpdateType = Reconstruct;
+    requiresFullStyleRecalc = true;
+
+    if (activeLoadingStyleSheetLoaded(newStyleSheets))
+        return;
+
+    if (updateMode != AnalyzedStyleUpdate)
+        return;
+    if (!document()->styleResolverIfExists())
+        return;
+
+    // Find out which stylesheets are new.
+    Vector<StyleSheetContents*> addedSheets;
+    styleResolverUpdateType = compareStyleSheets(oldStyleSheets, newStyleSheets, addedSheets);
+
+    // If we are already parsing the body and so may have significant amount of elements, put some effort into trying to avoid style recalcs.
+    if (!document()->body() || document()->hasNodesWithPlaceholderStyle())
+        return;
+    StyleInvalidationAnalysis invalidationAnalysis(addedSheets);
+    if (invalidationAnalysis.dirtiesAllStyle())
+        return;
+    invalidationAnalysis.invalidateStyle(document());
+    requiresFullStyleRecalc = false;
+}
+
+void StyleSheetCollection::resetAllRuleSetsInTreeScope(StyleResolver* styleResolver)
+{
+    // FIXME: If many web developers use style scoped, implement reset RuleSets in per-scoping node manner.
+    if (DocumentOrderedList* styleScopedScopingNodes = scopingNodesForStyleScoped()) {
+        for (DocumentOrderedList::iterator it = styleScopedScopingNodes->begin(); it != styleScopedScopingNodes->end(); ++it)
+            styleResolver->resetAuthorStyle(toContainerNode(*it));
+    }
+    if (ListHashSet<Node*, 4>* removedNodes = scopingNodesRemoved()) {
+        for (ListHashSet<Node*, 4>::iterator it = removedNodes->begin(); it != removedNodes->end(); ++it)
+            styleResolver->resetAuthorStyle(toContainerNode(*it));
+    }
+    styleResolver->resetAuthorStyle(toContainerNode(m_treeScope->rootNode()));
+}
+
+static bool styleSheetsUseRemUnits(const Vector<RefPtr<CSSStyleSheet> >& sheets)
+{
+    for (unsigned i = 0; i < sheets.size(); ++i) {
+        if (sheets[i]->contents()->usesRemUnits())
+            return true;
+    }
+    return false;
+}
+
+void StyleSheetCollection::updateUsesRemUnits()
+{
+    m_usesRemUnits = styleSheetsUseRemUnits(m_activeAuthorStyleSheets);
+}
+
+StyleSheetCollectionForDocument::StyleSheetCollectionForDocument(TreeScope* treeScope)
+    : StyleSheetCollection(treeScope)
+{
+    ASSERT(treeScope->rootNode() == treeScope->rootNode()->document());
+}
+
+void StyleSheetCollectionForDocument::collectStyleSheets(DocumentStyleSheetCollection* collections, Vector<RefPtr<StyleSheet> >& styleSheets, Vector<RefPtr<CSSStyleSheet> >& activeSheets)
 {
     if (document()->settings() && !document()->settings()->authorAndUserStylesEnabled())
         return;
@@ -173,80 +279,6 @@
     }
 }
 
-StyleSheetCollection::StyleResolverUpdateType StyleSheetCollection::compareStyleSheets(const Vector<RefPtr<CSSStyleSheet> >& oldStyleSheets, const Vector<RefPtr<CSSStyleSheet> >& newStylesheets, Vector<StyleSheetContents*>& addedSheets)
-{
-    // Find out which stylesheets are new.
-    unsigned newStylesheetCount = newStylesheets.size();
-    unsigned oldStylesheetCount = oldStyleSheets.size();
-    if (newStylesheetCount < oldStylesheetCount)
-        return Reconstruct;
-
-    unsigned newIndex = 0;
-    for (unsigned oldIndex = 0; oldIndex < oldStylesheetCount; ++oldIndex) {
-        if (newIndex >= newStylesheetCount)
-            return Reconstruct;
-        while (oldStyleSheets[oldIndex] != newStylesheets[newIndex]) {
-            addedSheets.append(newStylesheets[newIndex]->contents());
-            ++newIndex;
-            if (newIndex == newStylesheetCount)
-                return Reconstruct;
-        }
-        ++newIndex;
-    }
-    bool hasInsertions = !addedSheets.isEmpty();
-    while (newIndex < newStylesheetCount) {
-        addedSheets.append(newStylesheets[newIndex]->contents());
-        ++newIndex;
-    }
-    // If all new sheets were added at the end of the list we can just add them to existing StyleResolver.
-    // If there were insertions we need to re-add all the stylesheets so rules are ordered correctly.
-    return hasInsertions ? Reset : Additive;
-}
-
-bool StyleSheetCollection::activeLoadingStyleSheetLoaded(const Vector<RefPtr<CSSStyleSheet> >& newStyleSheets)
-{
-    // StyleSheets of <style> elements that @import stylesheets are active but loading. We need to trigger a full recalc when such loads are done.
-    bool hasActiveLoadingStylesheet = false;
-    unsigned newStylesheetCount = newStyleSheets.size();
-    for (unsigned i = 0; i < newStylesheetCount; ++i) {
-        if (newStyleSheets[i]->isLoading())
-            hasActiveLoadingStylesheet = true;
-    }
-    if (m_hadActiveLoadingStylesheet && !hasActiveLoadingStylesheet) {
-        m_hadActiveLoadingStylesheet = false;
-        return true;
-    }
-    m_hadActiveLoadingStylesheet = hasActiveLoadingStylesheet;
-    return false;
-}
-
-void StyleSheetCollection::analyzeStyleSheetChange(StyleResolverUpdateMode updateMode, const Vector<RefPtr<CSSStyleSheet> >& oldStyleSheets, const Vector<RefPtr<CSSStyleSheet> >& newStyleSheets, StyleResolverUpdateType& styleResolverUpdateType, bool& requiresFullStyleRecalc)
-{
-    styleResolverUpdateType = Reconstruct;
-    requiresFullStyleRecalc = true;
-
-    if (activeLoadingStyleSheetLoaded(newStyleSheets))
-        return;
-
-    if (updateMode != AnalyzedStyleUpdate)
-        return;
-    if (!document()->styleResolverIfExists())
-        return;
-
-    // Find out which stylesheets are new.
-    Vector<StyleSheetContents*> addedSheets;
-    styleResolverUpdateType = compareStyleSheets(oldStyleSheets, newStyleSheets, addedSheets);
-
-    // If we are already parsing the body and so may have significant amount of elements, put some effort into trying to avoid style recalcs.
-    if (!document()->body() || document()->hasNodesWithPlaceholderStyle())
-        return;
-    StyleInvalidationAnalysis invalidationAnalysis(addedSheets);
-    if (invalidationAnalysis.dirtiesAllStyle())
-        return;
-    invalidationAnalysis.invalidateStyle(document());
-    requiresFullStyleRecalc = false;
-}
-
 static void collectActiveCSSStyleSheetsFromSeamlessParents(Vector<RefPtr<CSSStyleSheet> >& sheets, Document* document)
 {
     HTMLIFrameElement* seamlessParentIFrame = document->seamlessParentIFrame();
@@ -255,7 +287,7 @@
     sheets.append(seamlessParentIFrame->document()->styleSheetCollection()->activeAuthorStyleSheets());
 }
 
-bool StyleSheetCollection::updateActiveStyleSheets(DocumentStyleSheetCollection* collections, StyleResolverUpdateMode updateMode, StyleResolverUpdateType& styleResolverUpdateType)
+bool StyleSheetCollectionForDocument::updateActiveStyleSheets(DocumentStyleSheetCollection* collections, StyleResolverUpdateMode updateMode)
 {
     Vector<RefPtr<StyleSheet> > styleSheets;
     Vector<RefPtr<CSSStyleSheet> > activeCSSStyleSheets;
@@ -264,25 +296,20 @@
     collectActiveCSSStyleSheetsFromSeamlessParents(activeCSSStyleSheets, document());
     collectStyleSheets(collections, styleSheets, activeCSSStyleSheets);
 
+    StyleResolverUpdateType styleResolverUpdateType;
     bool requiresFullStyleRecalc;
     analyzeStyleSheetChange(updateMode, activeAuthorStyleSheets(), activeCSSStyleSheets, styleResolverUpdateType, requiresFullStyleRecalc);
 
     if (styleResolverUpdateType == Reconstruct) {
         document()->clearStyleResolver();
     } else {
-        StyleResolver* styleResolver = document()->styleResolver();
-        styleResolver->setBuildScopedStyleTreeInDocumentOrder(!scopingNodesForStyleScoped());
+        StyleResolver* styleResolver = document()->styleResolverIfExists();
+        ASSERT(styleResolver);
+        // FIXME: We might have already had styles in child treescope. In this case, we cannot use buildScopedStyleTreeInDocumentOrder.
+        // Need to change "false" to some valid condition.
+        styleResolver->setBuildScopedStyleTreeInDocumentOrder(false);
         if (styleResolverUpdateType == Reset) {
-            if (DocumentOrderedList* styleScopedScopingNodes = scopingNodesForStyleScoped()) {
-                for (DocumentOrderedList::iterator it = styleScopedScopingNodes->begin(); it != styleScopedScopingNodes->end(); ++it)
-                    styleResolver->resetAuthorStyle(toContainerNode(*it));
-            }
-            if (ListHashSet<Node*, 4>* removedNodes = scopingNodesRemoved()) {
-                for (ListHashSet<Node*, 4>::iterator it = removedNodes->begin(); it != removedNodes->end(); ++it)
-                    styleResolver->resetAuthorStyle(toContainerNode(*it));
-            }
-            ASSERT(m_treeScope->rootNode() == document());
-            styleResolver->resetAuthorStyle(toContainerNode(m_treeScope->rootNode()));
+            resetAllRuleSetsInTreeScope(styleResolver);
             styleResolver->appendAuthorStyleSheets(0, activeCSSStyleSheets);
         } else {
             ASSERT(styleResolverUpdateType == Additive);
@@ -292,6 +319,7 @@
     m_scopingNodesForStyleScoped.didRemoveScopingNodes();
     m_activeAuthorStyleSheets.swap(activeCSSStyleSheets);
     m_styleSheetsForStyleSheetList.swap(styleSheets);
+    updateUsesRemUnits();
 
     return requiresFullStyleRecalc;
 }
diff --git a/Source/core/dom/StyleSheetCollection.h b/Source/core/dom/StyleSheetCollection.h
index 91da785..ce41034 100644
--- a/Source/core/dom/StyleSheetCollection.h
+++ b/Source/core/dom/StyleSheetCollection.h
@@ -52,47 +52,63 @@
 class StyleSheetCollection {
     WTF_MAKE_NONCOPYABLE(StyleSheetCollection); WTF_MAKE_FAST_ALLOCATED;
 public:
-    explicit StyleSheetCollection(TreeScope*);
-
     void addStyleSheetCandidateNode(Node*, bool createdByParser);
     void removeStyleSheetCandidateNode(Node*, ContainerNode* scopingNode);
+    bool hasStyleSheetCandidateNodes() const { return !m_styleSheetCandidateNodes.isEmpty(); }
 
     Vector<RefPtr<CSSStyleSheet> >& activeAuthorStyleSheets() { return m_activeAuthorStyleSheets; }
     Vector<RefPtr<StyleSheet> >& styleSheetsForStyleSheetList() { return m_styleSheetsForStyleSheetList; }
     const Vector<RefPtr<CSSStyleSheet> >& activeAuthorStyleSheets() const { return m_activeAuthorStyleSheets; }
     const Vector<RefPtr<StyleSheet> >& styleSheetsForStyleSheetList() const { return m_styleSheetsForStyleSheetList; }
 
+    bool usesRemUnits() const { return m_usesRemUnits; }
+
     DocumentOrderedList& styleSheetCandidateNodes() { return m_styleSheetCandidateNodes; }
     DocumentOrderedList* scopingNodesForStyleScoped() { return m_scopingNodesForStyleScoped.scopingNodes(); }
     ListHashSet<Node*, 4>* scopingNodesRemoved() { return m_scopingNodesForStyleScoped.scopingNodesRemoved(); }
 
+protected:
+    explicit StyleSheetCollection(TreeScope*);
+
+    Document* document() { return m_treeScope->documentScope(); }
+
     enum StyleResolverUpdateType {
         Reconstruct,
         Reset,
         Additive
     };
-    bool updateActiveStyleSheets(DocumentStyleSheetCollection*, StyleResolverUpdateMode, StyleResolverUpdateType&);
+    void analyzeStyleSheetChange(StyleResolverUpdateMode, const Vector<RefPtr<CSSStyleSheet> >& oldStyleSheets, const Vector<RefPtr<CSSStyleSheet> >& newStylesheets, StyleResolverUpdateType&, bool& requiresFullStyleRecalc);
+    void resetAllRuleSetsInTreeScope(StyleResolver*);
+    void updateUsesRemUnits();
 
 private:
-    Document* document() { return m_treeScope->documentScope(); }
-
-    void collectStyleSheets(DocumentStyleSheetCollection* collections, Vector<RefPtr<StyleSheet> >& styleSheets, Vector<RefPtr<CSSStyleSheet> >& activeSheets);
-
     StyleResolverUpdateType compareStyleSheets(const Vector<RefPtr<CSSStyleSheet> >& oldStyleSheets, const Vector<RefPtr<CSSStyleSheet> >& newStylesheets, Vector<StyleSheetContents*>& addedSheets);
     bool activeLoadingStyleSheetLoaded(const Vector<RefPtr<CSSStyleSheet> >& newStyleSheets);
 
-    void analyzeStyleSheetChange(StyleResolverUpdateMode, const Vector<RefPtr<CSSStyleSheet> >& oldStyleSheets, const Vector<RefPtr<CSSStyleSheet> >& newStylesheets, StyleResolverUpdateType&, bool& requiresFullStyleRecalc);
-
+protected:
     Vector<RefPtr<StyleSheet> > m_styleSheetsForStyleSheetList;
     Vector<RefPtr<CSSStyleSheet> > m_activeAuthorStyleSheets;
 
     TreeScope* m_treeScope;
     bool m_hadActiveLoadingStylesheet;
+    bool m_usesRemUnits;
 
     DocumentOrderedList m_styleSheetCandidateNodes;
     StyleSheetScopingNodeList m_scopingNodesForStyleScoped;
 };
 
+// FIXME: rename this class to DocumentStyleSheetCollection.
+class StyleSheetCollectionForDocument FINAL : public StyleSheetCollection {
+    WTF_MAKE_NONCOPYABLE(StyleSheetCollectionForDocument); WTF_MAKE_FAST_ALLOCATED;
+public:
+    explicit StyleSheetCollectionForDocument(TreeScope*);
+
+    bool updateActiveStyleSheets(DocumentStyleSheetCollection*, StyleResolverUpdateMode);
+
+private:
+    void collectStyleSheets(DocumentStyleSheetCollection*, Vector<RefPtr<StyleSheet> >& styleSheets, Vector<RefPtr<CSSStyleSheet> >& activeSheets);
+};
+
 }
 
 #endif
diff --git a/Source/core/dom/Text.cpp b/Source/core/dom/Text.cpp
index 6a7878e..425aabd 100644
--- a/Source/core/dom/Text.cpp
+++ b/Source/core/dom/Text.cpp
@@ -292,13 +292,16 @@
     return false;
 }
 
-void Text::updateTextRenderer(unsigned offsetOfReplacedData, unsigned lengthOfReplacedData)
+void Text::updateTextRenderer(unsigned offsetOfReplacedData, unsigned lengthOfReplacedData, AttachBehavior attachBehavior)
 {
     if (!attached())
         return;
     RenderText* textRenderer = toRenderText(renderer());
     if (!textRenderer || !textRendererIsNeeded(NodeRenderingContext(this, textRenderer->style()))) {
-        reattach();
+        if (attachBehavior == DeprecatedAttachNow)
+            reattach();
+        else
+            lazyReattach();
         return;
     }
     textRenderer->setTextWithOffset(dataImpl(), offsetOfReplacedData, lengthOfReplacedData);
diff --git a/Source/core/dom/Text.h b/Source/core/dom/Text.h
index 1001eff..33a459a 100644
--- a/Source/core/dom/Text.h
+++ b/Source/core/dom/Text.h
@@ -49,7 +49,7 @@
     bool recalcTextStyle(StyleChange);
     bool textRendererIsNeeded(const NodeRenderingContext&);
     virtual RenderText* createTextRenderer(RenderStyle*);
-    void updateTextRenderer(unsigned offsetOfReplacedData, unsigned lengthOfReplacedData);
+    void updateTextRenderer(unsigned offsetOfReplacedData, unsigned lengthOfReplacedData, AttachBehavior = AttachLazily);
 
     virtual void attach(const AttachContext& = AttachContext()) OVERRIDE FINAL;
 
diff --git a/Source/core/dom/TreeScope.cpp b/Source/core/dom/TreeScope.cpp
index e54c9be..2a4ae34 100644
--- a/Source/core/dom/TreeScope.cpp
+++ b/Source/core/dom/TreeScope.cpp
@@ -31,9 +31,9 @@
 #include "core/dom/ContainerNode.h"
 #include "core/dom/Document.h"
 #include "core/dom/Element.h"
+#include "core/dom/ElementTraversal.h"
 #include "core/dom/EventPathWalker.h"
 #include "core/dom/IdTargetObserverRegistry.h"
-#include "core/dom/NodeTraversal.h"
 #include "core/dom/TreeScopeAdopter.h"
 #include "core/dom/shadow/ElementShadow.h"
 #include "core/dom/shadow/ShadowRoot.h"
diff --git a/Source/core/dom/ViewportArguments.cpp b/Source/core/dom/ViewportArguments.cpp
index 92ae2cf..0a2708d 100644
--- a/Source/core/dom/ViewportArguments.cpp
+++ b/Source/core/dom/ViewportArguments.cpp
@@ -68,7 +68,7 @@
     return value;
 }
 
-PageScaleConstraints ViewportArguments::resolve(const FloatSize& initialViewportSize, const FloatSize& deviceSize, int defaultWidth) const
+PageScaleConstraints ViewportArguments::resolve(const FloatSize& initialViewportSize, int defaultWidth) const
 {
     float resultWidth = width;
     float resultMaxWidth = maxWidth;
@@ -168,19 +168,19 @@
 
     switch (static_cast<int>(resultWidth)) {
     case ViewportArguments::ValueDeviceWidth:
-        resultWidth = deviceSize.width();
+        resultWidth = initialViewportSize.width();
         break;
     case ViewportArguments::ValueDeviceHeight:
-        resultWidth = deviceSize.height();
+        resultWidth = initialViewportSize.height();
         break;
     }
 
     switch (static_cast<int>(resultHeight)) {
     case ViewportArguments::ValueDeviceWidth:
-        resultHeight = deviceSize.width();
+        resultHeight = initialViewportSize.width();
         break;
     case ViewportArguments::ValueDeviceHeight:
-        resultHeight = deviceSize.height();
+        resultHeight = initialViewportSize.height();
         break;
     }
 
@@ -396,11 +396,12 @@
 static const char* viewportErrorMessageTemplate(ViewportErrorCode errorCode)
 {
     static const char* const errors[] = {
-        "Viewport argument key \"%replacement1\" not recognized and ignored.",
-        "Viewport argument value \"%replacement1\" for key \"%replacement2\" is invalid, and has been ignored.",
-        "Viewport argument value \"%replacement1\" for key \"%replacement2\" was truncated to its numeric prefix.",
-        "Viewport maximum-scale cannot be larger than 10.0. The maximum-scale will be set to 10.0.",
-        "Viewport target-densitydpi is not supported.",
+        "Note that ';' is not a key-value pair separator. The list should be comma-separated.",
+        "The key \"%replacement1\" is not recognized and ignored.",
+        "The value \"%replacement1\" for key \"%replacement2\" is invalid, and has been ignored.",
+        "The value \"%replacement1\" for key \"%replacement2\" was truncated to its numeric prefix.",
+        "The value for key \"maximum-scale\" is out of bounds and the value has been clamped.",
+        "The key \"target-densitydpi\" is not supported.",
     };
 
     return errors[errorCode];
@@ -409,6 +410,7 @@
 static MessageLevel viewportErrorMessageLevel(ViewportErrorCode errorCode)
 {
     switch (errorCode) {
+    case InvalidKeyValuePairSeparatorError:
     case TruncatedViewportArgumentValueError:
     case TargetDensityDpiUnsupported:
         return WarningMessageLevel;
@@ -434,9 +436,6 @@
     if (!replacement2.isNull())
         message.replace("%replacement2", replacement2);
 
-    if ((errorCode == UnrecognizedViewportArgumentValueError || errorCode == TruncatedViewportArgumentValueError) && replacement1.find(';') != WTF::notFound)
-        message.append(" Note that ';' is not a separator in viewport values. The list should be comma-separated.");
-
     // FIXME: This message should be moved off the console once a solution to https://bugs.webkit.org/show_bug.cgi?id=103274 exists.
     document->addConsoleMessage(RenderingMessageSource, viewportErrorMessageLevel(errorCode), message);
 }
diff --git a/Source/core/dom/ViewportArguments.h b/Source/core/dom/ViewportArguments.h
index 5afacfe..6533441 100644
--- a/Source/core/dom/ViewportArguments.h
+++ b/Source/core/dom/ViewportArguments.h
@@ -37,6 +37,7 @@
 class Document;
 
 enum ViewportErrorCode {
+    InvalidKeyValuePairSeparatorError,
     UnrecognizedViewportArgumentKeyError,
     UnrecognizedViewportArgumentValueError,
     TruncatedViewportArgumentValueError,
@@ -87,7 +88,7 @@
     }
 
     // All arguments are in CSS units.
-    PageScaleConstraints resolve(const FloatSize& initialViewportSize, const FloatSize& deviceSize, int defaultWidth) const;
+    PageScaleConstraints resolve(const FloatSize& initialViewportSize, int defaultWidth) const;
 
     float width;
     float minWidth;
diff --git a/Source/core/dom/VisitedLinkState.cpp b/Source/core/dom/VisitedLinkState.cpp
index 77e8fd1..cf1d417 100644
--- a/Source/core/dom/VisitedLinkState.cpp
+++ b/Source/core/dom/VisitedLinkState.cpp
@@ -30,7 +30,7 @@
 #include "core/dom/VisitedLinkState.h"
 
 #include "HTMLNames.h"
-#include "core/dom/NodeTraversal.h"
+#include "core/dom/ElementTraversal.h"
 #include "core/html/HTMLAnchorElement.h"
 #include "core/page/Page.h"
 #include "public/platform/Platform.h"
diff --git a/Source/core/dom/WheelEvent.cpp b/Source/core/dom/WheelEvent.cpp
index c7bdf0d..bcb3d69 100644
--- a/Source/core/dom/WheelEvent.cpp
+++ b/Source/core/dom/WheelEvent.cpp
@@ -3,6 +3,7 @@
  * Copyright (C) 2001 Tobias Anton (anton@stud.fbi.fh-darmstadt.de)
  * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
  * Copyright (C) 2003, 2005, 2006, 2008, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2013 Samsung Electronics. All rights reserved.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
@@ -29,15 +30,29 @@
 
 namespace WebCore {
 
+static inline double wheelTicksToPixels(double ticks)
+{
+    // Make sure we use +0 for all zeros.
+    if (!ticks)
+        return 0;
+    return -ticks * WheelEvent::TickMultiplier;
+}
+
 WheelEventInit::WheelEventInit()
-    : wheelDeltaX(0)
+    : deltaX(0)
+    , deltaY(0)
+    , deltaZ(0)
+    , wheelDeltaX(0)
     , wheelDeltaY(0)
     , deltaMode(WheelEvent::DOM_DELTA_PIXEL)
 {
 }
 
 WheelEvent::WheelEvent()
-    : m_deltaMode(DOM_DELTA_PIXEL)
+    : m_deltaX(0)
+    , m_deltaY(0)
+    , m_deltaZ(0)
+    , m_deltaMode(DOM_DELTA_PIXEL)
     , m_directionInvertedFromDevice(false)
 {
     ScriptWrappable::init(this);
@@ -45,7 +60,9 @@
 
 WheelEvent::WheelEvent(const AtomicString& type, const WheelEventInit& initializer)
     : MouseEvent(type, initializer)
-    , m_wheelDelta(IntPoint(initializer.wheelDeltaX, initializer.wheelDeltaY))
+    , m_deltaX(initializer.deltaX ? initializer.deltaX : -initializer.wheelDeltaX)
+    , m_deltaY(initializer.deltaY ? initializer.deltaY : -initializer.wheelDeltaY)
+    , m_deltaZ(initializer.deltaZ)
     , m_deltaMode(initializer.deltaMode)
 {
     ScriptWrappable::init(this);
@@ -54,12 +71,14 @@
 WheelEvent::WheelEvent(const FloatPoint& wheelTicks, const FloatPoint& rawDelta, unsigned deltaMode,
     PassRefPtr<AbstractView> view, const IntPoint& screenLocation, const IntPoint& pageLocation,
     bool ctrlKey, bool altKey, bool shiftKey, bool metaKey, bool directionInvertedFromDevice)
-    : MouseEvent(eventNames().mousewheelEvent,
+    : MouseEvent(eventNames().wheelEvent,
                  true, true, view, 0, screenLocation.x(), screenLocation.y(),
                  pageLocation.x(), pageLocation.y(),
                  0, 0,
                  ctrlKey, altKey, shiftKey, metaKey, 0, 0, 0, false)
-    , m_wheelDelta(IntPoint(static_cast<int>(wheelTicks.x() * TickMultiplier), static_cast<int>(wheelTicks.y() * TickMultiplier)))
+    , m_deltaX(wheelTicksToPixels(wheelTicks.x()))
+    , m_deltaY(wheelTicksToPixels(wheelTicks.y()))
+    , m_deltaZ(0) // FIXME: Not supported.
     , m_rawDelta(roundedIntPoint(rawDelta))
     , m_deltaMode(deltaMode)
     , m_directionInvertedFromDevice(directionInvertedFromDevice)
@@ -74,7 +93,7 @@
     if (dispatched())
         return;
 
-    initUIEvent(eventNames().mousewheelEvent, true, true, view, 0);
+    initUIEvent(eventNames().wheelEvent, true, true, view, 0);
 
     m_screenLocation = IntPoint(screenX, screenY);
     m_ctrlKey = ctrlKey;
@@ -82,9 +101,8 @@
     m_shiftKey = shiftKey;
     m_metaKey = metaKey;
 
-    // Normalize to the Windows 120 multiple
-    m_wheelDelta = IntPoint(rawDeltaX * TickMultiplier, rawDeltaY * TickMultiplier);
-
+    m_deltaX = wheelTicksToPixels(rawDeltaX);
+    m_deltaY = wheelTicksToPixels(rawDeltaY);
     m_rawDelta = IntPoint(rawDeltaX, rawDeltaY);
     m_deltaMode = DOM_DELTA_PIXEL;
     m_directionInvertedFromDevice = false;
diff --git a/Source/core/dom/WheelEvent.h b/Source/core/dom/WheelEvent.h
index ba17ab4..870c9b6 100644
--- a/Source/core/dom/WheelEvent.h
+++ b/Source/core/dom/WheelEvent.h
@@ -3,6 +3,7 @@
  * Copyright (C) 2001 Tobias Anton (anton@stud.fbi.fh-darmstadt.de)
  * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
  * Copyright (C) 2003, 2004, 2005, 2006, 2008, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2013 Samsung Electronics. All rights reserved.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
@@ -35,8 +36,11 @@
 struct WheelEventInit : public MouseEventInit {
     WheelEventInit();
 
-    int wheelDeltaX;
-    int wheelDeltaY;
+    double deltaX;
+    double deltaY;
+    double deltaZ;
+    int wheelDeltaX; // Deprecated.
+    int wheelDeltaY; // Deprecated.
     unsigned deltaMode;
 };
 
@@ -77,9 +81,12 @@
         int screenX, int screenY, int pageX, int pageY,
         bool ctrlKey, bool altKey, bool shiftKey, bool metaKey);
 
-    int wheelDelta() const { return m_wheelDelta.y() ? m_wheelDelta.y() : m_wheelDelta.x(); }
-    int wheelDeltaX() const { return m_wheelDelta.x(); }
-    int wheelDeltaY() const { return m_wheelDelta.y(); }
+    double deltaX() const { return m_deltaX; } // Positive when scrolling right.
+    double deltaY() const { return m_deltaY; } // Positive when scrolling down.
+    double deltaZ() const { return m_deltaZ; }
+    int wheelDelta() const { return wheelDeltaY() ? wheelDeltaY() : wheelDeltaX(); } // Deprecated.
+    int wheelDeltaX() const { return -m_deltaX; } // Deprecated, negative when scrolling right.
+    int wheelDeltaY() const { return -m_deltaY; } // Deprecated, negative when scrolling down.
     int rawDeltaX() const { return m_rawDelta.x(); }
     int rawDeltaY() const { return m_rawDelta.y(); }
     unsigned deltaMode() const { return m_deltaMode; }
@@ -96,7 +103,9 @@
         unsigned, PassRefPtr<AbstractView>, const IntPoint& screenLocation, const IntPoint& pageLocation,
         bool ctrlKey, bool altKey, bool shiftKey, bool metaKey, bool directionInvertedFromDevice);
 
-    IntPoint m_wheelDelta;
+    double m_deltaX;
+    double m_deltaY;
+    double m_deltaZ;
     IntPoint m_rawDelta;
     unsigned m_deltaMode;
     bool m_directionInvertedFromDevice;
diff --git a/Source/core/dom/WheelEvent.idl b/Source/core/dom/WheelEvent.idl
index 9dc0e4a..8ee63ae 100644
--- a/Source/core/dom/WheelEvent.idl
+++ b/Source/core/dom/WheelEvent.idl
@@ -1,6 +1,7 @@
 /*
  * Copyright (C) 2006, 2007, 2010 Apple Inc. All rights reserved.
  * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
+ * Copyright (C) 2013 Samsung Electronics. All rights reserved.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
@@ -18,17 +19,23 @@
  * Boston, MA 02110-1301, USA.
  */
 
+// Introduced in DOM Level 3:
 [
     ConstructorTemplate=Event
 ] interface WheelEvent : MouseEvent {
+    // DeltaModeCode
     const unsigned long              DOM_DELTA_PIXEL = 0x00;
     const unsigned long              DOM_DELTA_LINE  = 0x01;
     const unsigned long              DOM_DELTA_PAGE  = 0x02;
 
-    [InitializedByEventConstructor] readonly attribute long wheelDeltaX;
-    [InitializedByEventConstructor] readonly attribute long wheelDeltaY;
+    [InitializedByEventConstructor] readonly attribute double deltaX;
+    [InitializedByEventConstructor] readonly attribute double deltaY;
+    [InitializedByEventConstructor] readonly attribute double deltaZ;
     [InitializedByEventConstructor] readonly attribute unsigned long deltaMode;
 
+    // Non standard API.
+    [InitializedByEventConstructor] readonly attribute long wheelDeltaX;
+    [InitializedByEventConstructor] readonly attribute long wheelDeltaY;
     readonly attribute long wheelDelta;
 
     // WebKit Extension
diff --git a/Source/core/dom/shadow/ComposedShadowTreeWalker.cpp b/Source/core/dom/shadow/ComposedShadowTreeWalker.cpp
index c5a64fa..80ff995 100644
--- a/Source/core/dom/shadow/ComposedShadowTreeWalker.cpp
+++ b/Source/core/dom/shadow/ComposedShadowTreeWalker.cpp
@@ -29,7 +29,6 @@
 #include "core/dom/shadow/ComposedShadowTreeWalker.h"
 
 #include "core/dom/Element.h"
-#include "core/dom/shadow/ContentDistributor.h"
 #include "core/dom/shadow/ElementShadow.h"
 #include "core/dom/shadow/InsertionPoint.h"
 
diff --git a/Source/core/dom/shadow/ContentDistribution.cpp b/Source/core/dom/shadow/ContentDistribution.cpp
new file mode 100644
index 0000000..405ce56
--- /dev/null
+++ b/Source/core/dom/shadow/ContentDistribution.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 THE COPYRIGHT
+ * OWNER 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 "core/dom/shadow/ContentDistribution.h"
+
+namespace WebCore {
+
+void ContentDistribution::swap(ContentDistribution& other)
+{
+    m_nodes.swap(other.m_nodes);
+    m_indices.swap(other.m_indices);
+}
+
+void ContentDistribution::append(PassRefPtr<Node> node)
+{
+    size_t size = m_nodes.size();
+    m_indices.set(node.get(), size);
+    m_nodes.append(node);
+}
+
+size_t ContentDistribution::find(const Node* node) const
+{
+    HashMap<const Node*, size_t>::const_iterator it = m_indices.find(node);
+    if (it == m_indices.end())
+        return notFound;
+
+    return it.get()->value;
+}
+
+Node* ContentDistribution::nextTo(const Node* node) const
+{
+    size_t index = find(node);
+    if (index == notFound || index + 1 == size())
+        return 0;
+    return at(index + 1).get();
+}
+
+Node* ContentDistribution::previousTo(const Node* node) const
+{
+    size_t index = find(node);
+    if (index == notFound || !index)
+        return 0;
+    return at(index - 1).get();
+}
+
+} // namespace WebCore
diff --git a/Source/core/dom/shadow/ContentDistribution.h b/Source/core/dom/shadow/ContentDistribution.h
new file mode 100644
index 0000000..2fd8fc1
--- /dev/null
+++ b/Source/core/dom/shadow/ContentDistribution.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 THE COPYRIGHT
+ * OWNER 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 ContentDistribution_h
+#define ContentDistribution_h
+
+#include "core/dom/Node.h"
+#include "wtf/Forward.h"
+#include "wtf/HashMap.h"
+#include "wtf/Vector.h"
+
+namespace WebCore {
+
+class ContentDistribution {
+public:
+    PassRefPtr<Node> first() const { return m_nodes.first(); }
+    PassRefPtr<Node> last() const { return m_nodes.last(); }
+    PassRefPtr<Node> at(size_t index) const { return m_nodes.at(index); }
+
+    size_t size() const { return m_nodes.size(); }
+    bool isEmpty() const { return m_nodes.isEmpty(); }
+
+    void append(PassRefPtr<Node>);
+    void clear() { m_nodes.clear(); m_indices.clear(); }
+
+    bool contains(const Node* node) const { return m_indices.contains(node); }
+    size_t find(const Node*) const;
+    Node* nextTo(const Node*) const;
+    Node* previousTo(const Node*) const;
+
+    void swap(ContentDistribution& other);
+
+    const Vector<RefPtr<Node> >& nodes() const { return m_nodes; }
+
+private:
+    Vector<RefPtr<Node> > m_nodes;
+    HashMap<const Node*, size_t> m_indices;
+};
+
+}
+
+#endif
diff --git a/Source/core/dom/shadow/ContentDistributor.cpp b/Source/core/dom/shadow/ContentDistributor.cpp
deleted file mode 100644
index 9bbccdc..0000000
--- a/Source/core/dom/shadow/ContentDistributor.cpp
+++ /dev/null
@@ -1,337 +0,0 @@
-/*
- * Copyright (C) 2011 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:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "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 THE COPYRIGHT
- * OWNER 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 "core/dom/shadow/ContentDistributor.h"
-
-#include "core/dom/NodeTraversal.h"
-#include "core/dom/shadow/ElementShadow.h"
-#include "core/dom/shadow/ShadowRoot.h"
-#include "core/html/shadow/HTMLContentElement.h"
-#include "core/html/shadow/HTMLShadowElement.h"
-
-
-namespace WebCore {
-
-void ContentDistribution::swap(ContentDistribution& other)
-{
-    m_nodes.swap(other.m_nodes);
-    m_indices.swap(other.m_indices);
-}
-
-void ContentDistribution::append(PassRefPtr<Node> node)
-{
-    size_t size = m_nodes.size();
-    m_indices.set(node.get(), size);
-    m_nodes.append(node);
-}
-
-size_t ContentDistribution::find(const Node* node) const
-{
-    HashMap<const Node*, size_t>::const_iterator it = m_indices.find(node);
-    if (it == m_indices.end())
-        return notFound;
-
-    return it.get()->value;
-}
-
-Node* ContentDistribution::nextTo(const Node* node) const
-{
-    size_t index = find(node);
-    if (index == notFound || index + 1 == size())
-        return 0;
-    return at(index + 1).get();
-}
-
-Node* ContentDistribution::previousTo(const Node* node) const
-{
-    size_t index = find(node);
-    if (index == notFound || !index)
-        return 0;
-    return at(index - 1).get();
-}
-
-
-ScopeContentDistribution::ScopeContentDistribution()
-    : m_insertionPointAssignedTo(0)
-    , m_numberOfShadowElementChildren(0)
-    , m_numberOfContentElementChildren(0)
-    , m_numberOfElementShadowChildren(0)
-    , m_insertionPointListIsValid(false)
-{
-}
-
-void ScopeContentDistribution::setInsertionPointAssignedTo(PassRefPtr<InsertionPoint> insertionPoint)
-{
-    m_insertionPointAssignedTo = insertionPoint;
-}
-
-void ScopeContentDistribution::invalidateInsertionPointList()
-{
-    m_insertionPointListIsValid = false;
-    m_insertionPointList.clear();
-}
-
-const Vector<RefPtr<InsertionPoint> >& ScopeContentDistribution::ensureInsertionPointList(ShadowRoot* shadowRoot)
-{
-    if (m_insertionPointListIsValid)
-        return m_insertionPointList;
-
-    m_insertionPointListIsValid = true;
-    ASSERT(m_insertionPointList.isEmpty());
-
-    if (!shadowRoot->containsInsertionPoints())
-        return m_insertionPointList;
-
-    for (Element* element = ElementTraversal::firstWithin(shadowRoot); element; element = ElementTraversal::next(element, shadowRoot)) {
-        if (element->isInsertionPoint())
-            m_insertionPointList.append(toInsertionPoint(element));
-    }
-
-    return m_insertionPointList;
-}
-
-void ScopeContentDistribution::registerInsertionPoint(InsertionPoint* point)
-{
-    if (isHTMLShadowElement(point))
-        ++m_numberOfShadowElementChildren;
-    else if (isHTMLContentElement(point))
-        ++m_numberOfContentElementChildren;
-    else
-        ASSERT_NOT_REACHED();
-
-    invalidateInsertionPointList();
-}
-
-void ScopeContentDistribution::unregisterInsertionPoint(InsertionPoint* point)
-{
-    if (isHTMLShadowElement(point))
-        --m_numberOfShadowElementChildren;
-    else if (isHTMLContentElement(point))
-        --m_numberOfContentElementChildren;
-    else
-        ASSERT_NOT_REACHED();
-
-    ASSERT(m_numberOfContentElementChildren >= 0);
-    ASSERT(m_numberOfShadowElementChildren >= 0);
-
-    invalidateInsertionPointList();
-}
-
-ContentDistributor::ContentDistributor()
-    : m_needsSelectFeatureSet(false)
-{
-}
-
-ContentDistributor::~ContentDistributor()
-{
-}
-
-InsertionPoint* ContentDistributor::findInsertionPointFor(const Node* key) const
-{
-    return m_nodeToInsertionPoint.get(key);
-}
-
-void ContentDistributor::populate(Node* node, Vector<Node*>& pool)
-{
-    node->lazyReattachIfAttached();
-
-    if (!isActiveInsertionPoint(node)) {
-        pool.append(node);
-        return;
-    }
-
-    InsertionPoint* insertionPoint = toInsertionPoint(node);
-    if (insertionPoint->hasDistribution()) {
-        for (size_t i = 0; i < insertionPoint->size(); ++i)
-            populate(insertionPoint->at(i), pool);
-    } else {
-        for (Node* fallbackNode = insertionPoint->firstChild(); fallbackNode; fallbackNode = fallbackNode->nextSibling())
-            pool.append(fallbackNode);
-    }
-}
-
-void ContentDistributor::distribute(Element* host)
-{
-    Vector<Node*> pool;
-    for (Node* node = host->firstChild(); node; node = node->nextSibling())
-        populate(node, pool);
-
-    host->setNeedsStyleRecalc();
-
-    Vector<bool> distributed(pool.size());
-    distributed.fill(false);
-
-    Vector<HTMLShadowElement*, 8> activeShadowInsertionPoints;
-    for (ShadowRoot* root = host->youngestShadowRoot(); root; root = root->olderShadowRoot()) {
-        HTMLShadowElement* firstActiveShadowInsertionPoint = 0;
-
-        if (ScopeContentDistribution* scope = root->scopeDistribution()) {
-            const Vector<RefPtr<InsertionPoint> >& insertionPoints = scope->ensureInsertionPointList(root);
-            for (size_t i = 0; i < insertionPoints.size(); ++i) {
-                InsertionPoint* point = insertionPoints[i].get();
-                if (!point->isActive())
-                    continue;
-
-                if (isHTMLShadowElement(point)) {
-                    if (!firstActiveShadowInsertionPoint)
-                        firstActiveShadowInsertionPoint = toHTMLShadowElement(point);
-                } else {
-                    distributeSelectionsTo(point, pool, distributed);
-                    if (ElementShadow* shadow = shadowOfParentForDistribution(point))
-                        shadow->setNeedsDistributionRecalc();
-                }
-            }
-        }
-
-        if (firstActiveShadowInsertionPoint)
-            activeShadowInsertionPoints.append(firstActiveShadowInsertionPoint);
-    }
-
-    for (size_t i = activeShadowInsertionPoints.size(); i > 0; --i) {
-        HTMLShadowElement* shadowElement = activeShadowInsertionPoints[i - 1];
-        ShadowRoot* root = shadowElement->containingShadowRoot();
-        ASSERT(root);
-        if (!shadowElement->shouldSelect()) {
-            if (root->olderShadowRoot())
-                root->olderShadowRoot()->ensureScopeDistribution()->setInsertionPointAssignedTo(shadowElement);
-        } else if (root->olderShadowRoot()) {
-            distributeNodeChildrenTo(shadowElement, root->olderShadowRoot());
-            root->olderShadowRoot()->ensureScopeDistribution()->setInsertionPointAssignedTo(shadowElement);
-        } else {
-            distributeSelectionsTo(shadowElement, pool, distributed);
-        }
-        if (ElementShadow* shadow = shadowOfParentForDistribution(shadowElement))
-            shadow->setNeedsDistributionRecalc();
-    }
-}
-
-void ContentDistributor::distributeSelectionsTo(InsertionPoint* insertionPoint, const Vector<Node*>& pool, Vector<bool>& distributed)
-{
-    ContentDistribution distribution;
-
-    for (size_t i = 0; i < pool.size(); ++i) {
-        if (distributed[i])
-            continue;
-
-        if (isHTMLContentElement(insertionPoint) && !toHTMLContentElement(insertionPoint)->canSelectNode(pool, i))
-            continue;
-
-        Node* child = pool[i];
-        distribution.append(child);
-        m_nodeToInsertionPoint.add(child, insertionPoint);
-        distributed[i] = true;
-    }
-
-    insertionPoint->lazyReattachIfAttached();
-    insertionPoint->setDistribution(distribution);
-}
-
-void ContentDistributor::distributeNodeChildrenTo(InsertionPoint* insertionPoint, ContainerNode* containerNode)
-{
-    ContentDistribution distribution;
-    for (Node* node = containerNode->firstChild(); node; node = node->nextSibling()) {
-        node->lazyReattachIfAttached();
-        if (isActiveInsertionPoint(node)) {
-            InsertionPoint* innerInsertionPoint = toInsertionPoint(node);
-            if (innerInsertionPoint->hasDistribution()) {
-                for (size_t i = 0; i < innerInsertionPoint->size(); ++i) {
-                    distribution.append(innerInsertionPoint->at(i));
-                    m_nodeToInsertionPoint.add(innerInsertionPoint->at(i), insertionPoint);
-                }
-            } else {
-                for (Node* child = innerInsertionPoint->firstChild(); child; child = child->nextSibling()) {
-                    distribution.append(child);
-                    m_nodeToInsertionPoint.add(child, insertionPoint);
-                }
-            }
-        } else {
-            distribution.append(node);
-            m_nodeToInsertionPoint.add(node, insertionPoint);
-        }
-    }
-
-    insertionPoint->lazyReattachIfAttached();
-    insertionPoint->setDistribution(distribution);
-}
-
-const SelectRuleFeatureSet& ContentDistributor::ensureSelectFeatureSet(ElementShadow* shadow)
-{
-    if (!m_needsSelectFeatureSet)
-        return m_selectFeatures;
-
-    m_selectFeatures.clear();
-    for (ShadowRoot* root = shadow->oldestShadowRoot(); root; root = root->youngerShadowRoot())
-        collectSelectFeatureSetFrom(root);
-    m_needsSelectFeatureSet = false;
-    return m_selectFeatures;
-}
-
-void ContentDistributor::collectSelectFeatureSetFrom(ShadowRoot* root)
-{
-    if (!root->containsShadowRoots() && !root->containsContentElements())
-        return;
-
-    for (Element* element = ElementTraversal::firstWithin(root); element; element = ElementTraversal::next(element, root)) {
-        if (ElementShadow* shadow = element->shadow())
-            m_selectFeatures.add(shadow->ensureSelectFeatureSet());
-        if (!isHTMLContentElement(element))
-            continue;
-        const CSSSelectorList& list = toHTMLContentElement(element)->selectorList();
-        for (const CSSSelector* selector = list.first(); selector; selector = CSSSelectorList::next(selector)) {
-            for (const CSSSelector* component = selector; component; component = component->tagHistory())
-                m_selectFeatures.collectFeaturesFromSelector(component);
-        }
-    }
-}
-
-void ContentDistributor::didAffectSelector(Element* host, AffectedSelectorMask mask)
-{
-    if (ensureSelectFeatureSet(host->shadow()).hasSelectorFor(mask))
-        host->shadow()->setNeedsDistributionRecalc();
-}
-
-void ContentDistributor::willAffectSelector(Element* host)
-{
-    for (ElementShadow* shadow = host->shadow(); shadow; shadow = shadow->containingShadow()) {
-        if (shadow->distributor().needsSelectFeatureSet())
-            break;
-        shadow->distributor().setNeedsSelectFeatureSet();
-    }
-    host->shadow()->setNeedsDistributionRecalc();
-}
-
-void ContentDistributor::clearDistribution(Element* host)
-{
-    m_nodeToInsertionPoint.clear();
-
-    for (ShadowRoot* root = host->youngestShadowRoot(); root; root = root->olderShadowRoot()) {
-        if (ScopeContentDistribution* scope = root->scopeDistribution())
-            scope->setInsertionPointAssignedTo(0);
-    }
-}
-
-}
diff --git a/Source/core/dom/shadow/ContentDistributor.h b/Source/core/dom/shadow/ContentDistributor.h
deleted file mode 100644
index e98b40b..0000000
--- a/Source/core/dom/shadow/ContentDistributor.h
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright (C) 2011 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:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * 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.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "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 THE COPYRIGHT
- * OWNER 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 ContentDistributor_h
-#define ContentDistributor_h
-
-#include "core/dom/shadow/SelectRuleFeatureSet.h"
-#include "wtf/Forward.h"
-#include "wtf/HashMap.h"
-#include "wtf/Vector.h"
-
-namespace WebCore {
-
-class ContainerNode;
-class Element;
-class InsertionPoint;
-class Node;
-class ShadowRoot;
-
-class ContentDistribution {
-public:
-    PassRefPtr<Node> first() const { return m_nodes.first(); }
-    PassRefPtr<Node> last() const { return m_nodes.last(); }
-    PassRefPtr<Node> at(size_t index) const { return m_nodes.at(index); }
-
-    size_t size() const { return m_nodes.size(); }
-    bool isEmpty() const { return m_nodes.isEmpty(); }
-
-    void append(PassRefPtr<Node>);
-    void clear() { m_nodes.clear(); m_indices.clear(); }
-
-    bool contains(const Node* node) const { return m_indices.contains(node); }
-    size_t find(const Node*) const;
-    Node* nextTo(const Node*) const;
-    Node* previousTo(const Node*) const;
-
-    void swap(ContentDistribution& other);
-
-    const Vector<RefPtr<Node> >& nodes() const { return m_nodes; }
-
-private:
-    Vector<RefPtr<Node> > m_nodes;
-    HashMap<const Node*, size_t> m_indices;
-};
-
-class ScopeContentDistribution {
-public:
-    ScopeContentDistribution();
-
-    InsertionPoint* insertionPointAssignedTo() const { return m_insertionPointAssignedTo.get(); }
-    void setInsertionPointAssignedTo(PassRefPtr<InsertionPoint>);
-
-    void registerInsertionPoint(InsertionPoint*);
-    void unregisterInsertionPoint(InsertionPoint*);
-    bool hasShadowElementChildren() const { return m_numberOfShadowElementChildren > 0; }
-    bool hasContentElementChildren() const { return m_numberOfContentElementChildren > 0; }
-
-    void registerElementShadow() { ++m_numberOfElementShadowChildren; }
-    void unregisterElementShadow() { ASSERT(m_numberOfElementShadowChildren > 0); --m_numberOfElementShadowChildren; }
-    unsigned numberOfElementShadowChildren() const { return m_numberOfElementShadowChildren; }
-    bool hasElementShadowChildren() const { return m_numberOfElementShadowChildren > 0; }
-
-    void invalidateInsertionPointList();
-    const Vector<RefPtr<InsertionPoint> >& ensureInsertionPointList(ShadowRoot*);
-
-private:
-    RefPtr<InsertionPoint> m_insertionPointAssignedTo;
-    unsigned m_numberOfShadowElementChildren;
-    unsigned m_numberOfContentElementChildren;
-    unsigned m_numberOfElementShadowChildren;
-    bool m_insertionPointListIsValid;
-    Vector<RefPtr<InsertionPoint> > m_insertionPointList;
-};
-
-class ContentDistributor {
-    WTF_MAKE_NONCOPYABLE(ContentDistributor);
-public:
-    ContentDistributor();
-    ~ContentDistributor();
-
-    InsertionPoint* findInsertionPointFor(const Node* key) const;
-    const SelectRuleFeatureSet& ensureSelectFeatureSet(ElementShadow*);
-
-    void distributeSelectionsTo(InsertionPoint*, const Vector<Node*>& pool, Vector<bool>& distributed);
-    void distributeNodeChildrenTo(InsertionPoint*, ContainerNode*);
-
-    void didAffectSelector(Element* host, AffectedSelectorMask);
-    void willAffectSelector(Element* host);
-
-    void distribute(Element* host);
-    void clearDistribution(Element* host);
-
-private:
-    void populate(Node*, Vector<Node*>&);
-
-    void collectSelectFeatureSetFrom(ShadowRoot*);
-    bool needsSelectFeatureSet() const { return m_needsSelectFeatureSet; }
-    void setNeedsSelectFeatureSet() { m_needsSelectFeatureSet = true; }
-
-    typedef HashMap<const Node*, RefPtr<InsertionPoint> > NodeInsertionPointMap;
-    NodeInsertionPointMap m_nodeToInsertionPoint;
-    SelectRuleFeatureSet m_selectFeatures;
-    bool m_needsSelectFeatureSet;
-};
-
-}
-
-#endif
diff --git a/Source/core/dom/shadow/ElementShadow.cpp b/Source/core/dom/shadow/ElementShadow.cpp
index 380a5f7..b6eef01 100644
--- a/Source/core/dom/shadow/ElementShadow.cpp
+++ b/Source/core/dom/shadow/ElementShadow.cpp
@@ -28,9 +28,34 @@
 #include "core/dom/shadow/ElementShadow.h"
 
 #include "core/dom/ContainerNodeAlgorithms.h"
+#include "core/dom/ElementTraversal.h"
+#include "core/dom/NodeTraversal.h"
+#include "core/dom/shadow/ContentDistribution.h"
+#include "core/dom/shadow/InsertionPoint.h"
+#include "core/dom/shadow/ScopeContentDistribution.h"
+#include "core/dom/shadow/ShadowRoot.h"
+#include "core/html/shadow/HTMLContentElement.h"
+#include "core/html/shadow/HTMLShadowElement.h"
 
 namespace WebCore {
 
+PassOwnPtr<ElementShadow> ElementShadow::create()
+{
+    return adoptPtr(new ElementShadow());
+}
+
+ElementShadow::ElementShadow()
+    : m_needsDistributionRecalc(false)
+    , m_applyAuthorStyles(false)
+    , m_needsSelectFeatureSet(false)
+{
+}
+
+ElementShadow::~ElementShadow()
+{
+    removeAllShadowRoots();
+}
+
 ShadowRoot* ElementShadow::addShadowRoot(Element* shadowHost, ShadowRoot::ShadowRootType type)
 {
     RefPtr<ShadowRoot> shadowRoot = ShadowRoot::create(shadowHost->document(), type);
@@ -146,4 +171,191 @@
     return false;
 }
 
+InsertionPoint* ElementShadow::findInsertionPointFor(const Node* key) const
+{
+    return m_nodeToInsertionPoint.get(key);
+}
+
+void ElementShadow::populate(Node* node, Vector<Node*>& pool)
+{
+    if (!isActiveInsertionPoint(node)) {
+        pool.append(node);
+        return;
+    }
+
+    InsertionPoint* insertionPoint = toInsertionPoint(node);
+    if (insertionPoint->hasDistribution()) {
+        for (size_t i = 0; i < insertionPoint->size(); ++i)
+            populate(insertionPoint->at(i), pool);
+    } else {
+        for (Node* fallbackNode = insertionPoint->firstChild(); fallbackNode; fallbackNode = fallbackNode->nextSibling())
+            pool.append(fallbackNode);
+    }
+}
+
+void ElementShadow::distribute()
+{
+    Vector<Node*> pool;
+    for (Node* node = host()->firstChild(); node; node = node->nextSibling())
+        populate(node, pool);
+
+    host()->setNeedsStyleRecalc();
+
+    Vector<bool> distributed(pool.size());
+    distributed.fill(false);
+
+    Vector<HTMLShadowElement*, 8> activeShadowInsertionPoints;
+    for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadowRoot()) {
+        HTMLShadowElement* firstActiveShadowInsertionPoint = 0;
+
+        if (ScopeContentDistribution* scope = root->scopeDistribution()) {
+            const Vector<RefPtr<InsertionPoint> >& insertionPoints = scope->ensureInsertionPointList(root);
+            for (size_t i = 0; i < insertionPoints.size(); ++i) {
+                InsertionPoint* point = insertionPoints[i].get();
+                if (!point->isActive())
+                    continue;
+
+                if (isHTMLShadowElement(point)) {
+                    if (!firstActiveShadowInsertionPoint)
+                        firstActiveShadowInsertionPoint = toHTMLShadowElement(point);
+                } else {
+                    distributeSelectionsTo(point, pool, distributed);
+                    if (ElementShadow* shadow = shadowOfParentForDistribution(point))
+                        shadow->setNeedsDistributionRecalc();
+                }
+            }
+        }
+
+        if (firstActiveShadowInsertionPoint)
+            activeShadowInsertionPoints.append(firstActiveShadowInsertionPoint);
+    }
+
+    for (size_t i = activeShadowInsertionPoints.size(); i > 0; --i) {
+        HTMLShadowElement* shadowElement = activeShadowInsertionPoints[i - 1];
+        ShadowRoot* root = shadowElement->containingShadowRoot();
+        ASSERT(root);
+        if (!shadowElement->shouldSelect()) {
+            if (root->olderShadowRoot())
+                root->olderShadowRoot()->ensureScopeDistribution()->setInsertionPointAssignedTo(shadowElement);
+        } else if (root->olderShadowRoot()) {
+            distributeNodeChildrenTo(shadowElement, root->olderShadowRoot());
+            root->olderShadowRoot()->ensureScopeDistribution()->setInsertionPointAssignedTo(shadowElement);
+        } else {
+            distributeSelectionsTo(shadowElement, pool, distributed);
+        }
+        if (ElementShadow* shadow = shadowOfParentForDistribution(shadowElement))
+            shadow->setNeedsDistributionRecalc();
+    }
+
+    // Detach all nodes that were not distributed and have a renderer.
+    for (size_t i = 0; i < pool.size(); ++i) {
+        if (distributed[i])
+            continue;
+        if (pool[i]->renderer())
+            pool[i]->lazyReattachIfAttached();
+    }
+}
+
+void ElementShadow::distributeSelectionsTo(InsertionPoint* insertionPoint, const Vector<Node*>& pool, Vector<bool>& distributed)
+{
+    ContentDistribution distribution;
+
+    for (size_t i = 0; i < pool.size(); ++i) {
+        if (distributed[i])
+            continue;
+
+        if (isHTMLContentElement(insertionPoint) && !toHTMLContentElement(insertionPoint)->canSelectNode(pool, i))
+            continue;
+
+        Node* child = pool[i];
+        distribution.append(child);
+        m_nodeToInsertionPoint.add(child, insertionPoint);
+        distributed[i] = true;
+    }
+
+    insertionPoint->setDistribution(distribution);
+}
+
+void ElementShadow::distributeNodeChildrenTo(InsertionPoint* insertionPoint, ContainerNode* containerNode)
+{
+    ContentDistribution distribution;
+    for (Node* node = containerNode->firstChild(); node; node = node->nextSibling()) {
+        if (isActiveInsertionPoint(node)) {
+            InsertionPoint* innerInsertionPoint = toInsertionPoint(node);
+            if (innerInsertionPoint->hasDistribution()) {
+                for (size_t i = 0; i < innerInsertionPoint->size(); ++i) {
+                    distribution.append(innerInsertionPoint->at(i));
+                    m_nodeToInsertionPoint.add(innerInsertionPoint->at(i), insertionPoint);
+                }
+            } else {
+                for (Node* child = innerInsertionPoint->firstChild(); child; child = child->nextSibling()) {
+                    distribution.append(child);
+                    m_nodeToInsertionPoint.add(child, insertionPoint);
+                }
+            }
+        } else {
+            distribution.append(node);
+            m_nodeToInsertionPoint.add(node, insertionPoint);
+        }
+    }
+
+    insertionPoint->setDistribution(distribution);
+}
+
+const SelectRuleFeatureSet& ElementShadow::ensureSelectFeatureSet()
+{
+    if (!m_needsSelectFeatureSet)
+        return m_selectFeatures;
+
+    m_selectFeatures.clear();
+    for (ShadowRoot* root = oldestShadowRoot(); root; root = root->youngerShadowRoot())
+        collectSelectFeatureSetFrom(root);
+    m_needsSelectFeatureSet = false;
+    return m_selectFeatures;
+}
+
+void ElementShadow::collectSelectFeatureSetFrom(ShadowRoot* root)
+{
+    if (!root->containsShadowRoots() && !root->containsContentElements())
+        return;
+
+    for (Element* element = ElementTraversal::firstWithin(root); element; element = ElementTraversal::next(element, root)) {
+        if (ElementShadow* shadow = element->shadow())
+            m_selectFeatures.add(shadow->ensureSelectFeatureSet());
+        if (!isHTMLContentElement(element))
+            continue;
+        const CSSSelectorList& list = toHTMLContentElement(element)->selectorList();
+        for (const CSSSelector* selector = list.first(); selector; selector = CSSSelectorList::next(selector)) {
+            for (const CSSSelector* component = selector; component; component = component->tagHistory())
+                m_selectFeatures.collectFeaturesFromSelector(component);
+        }
+    }
+}
+
+void ElementShadow::didAffectSelector(AffectedSelectorMask mask)
+{
+    if (ensureSelectFeatureSet().hasSelectorFor(mask))
+        setNeedsDistributionRecalc();
+}
+
+void ElementShadow::willAffectSelector()
+{
+    for (ElementShadow* shadow = this; shadow; shadow = shadow->containingShadow()) {
+        if (shadow->needsSelectFeatureSet())
+            break;
+        shadow->setNeedsSelectFeatureSet();
+    }
+    setNeedsDistributionRecalc();
+}
+
+void ElementShadow::clearDistribution()
+{
+    m_nodeToInsertionPoint.clear();
+
+    for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadowRoot()) {
+        if (ScopeContentDistribution* scope = root->scopeDistribution())
+            scope->setInsertionPointAssignedTo(0);
+    }
+}
+
 } // namespace
diff --git a/Source/core/dom/shadow/ElementShadow.h b/Source/core/dom/shadow/ElementShadow.h
index 3f16157..8ac38e9 100644
--- a/Source/core/dom/shadow/ElementShadow.h
+++ b/Source/core/dom/shadow/ElementShadow.h
@@ -27,27 +27,24 @@
 #ifndef ElementShadow_h
 #define ElementShadow_h
 
-#include "core/dom/shadow/ContentDistributor.h"
+#include "core/dom/shadow/SelectRuleFeatureSet.h"
 #include "core/dom/shadow/ShadowRoot.h"
 #include "wtf/DoublyLinkedList.h"
+#include "wtf/Forward.h"
+#include "wtf/HashMap.h"
 #include "wtf/Noncopyable.h"
 #include "wtf/PassOwnPtr.h"
 #include "wtf/Vector.h"
 
 namespace WebCore {
 
+class InsertionPoint;
+
 class ElementShadow {
     WTF_MAKE_NONCOPYABLE(ElementShadow); WTF_MAKE_FAST_ALLOCATED;
 public:
-    static PassOwnPtr<ElementShadow> create()
-    {
-        return adoptPtr(new ElementShadow());
-    }
-
-    ~ElementShadow()
-    {
-        removeAllShadowRoots();
-    }
+    static PassOwnPtr<ElementShadow> create();
+    ~ElementShadow();
 
     Element* host() const;
     ShadowRoot* youngestShadowRoot() const { return m_shadowRoots.head(); }
@@ -55,47 +52,47 @@
     ElementShadow* containingShadow() const;
 
     ShadowRoot* addShadowRoot(Element* shadowHost, ShadowRoot::ShadowRootType);
+
     bool applyAuthorStyles() const { return m_applyAuthorStyles; }
+    bool didAffectApplyAuthorStyles();
+    bool containsActiveStyles() const;
 
     void attach(const Node::AttachContext&);
     void detach(const Node::AttachContext&);
 
     void removeAllEventListeners();
 
-    void didAffectSelector(AffectedSelectorMask mask) { m_distributor.didAffectSelector(host(), mask); }
-    void willAffectSelector() { m_distributor.willAffectSelector(host()); }
-    const SelectRuleFeatureSet& ensureSelectFeatureSet() { return m_distributor.ensureSelectFeatureSet(this); }
+    void didAffectSelector(AffectedSelectorMask);
+    void willAffectSelector();
+    const SelectRuleFeatureSet& ensureSelectFeatureSet();
 
-    // FIXME: Move all callers of this to APIs on ElementShadow and remove it.
-    ContentDistributor& distributor() { return m_distributor; }
-    const ContentDistributor& distributor() const { return m_distributor; }
-
-    void distributeIfNeeded()
-    {
-        if (m_needsDistributionRecalc)
-            m_distributor.distribute(host());
-        m_needsDistributionRecalc = false;
-    }
-    void clearDistribution() { m_distributor.clearDistribution(host()); }
-
+    void distributeIfNeeded();
     void setNeedsDistributionRecalc();
 
-    bool didAffectApplyAuthorStyles();
-    bool containsActiveStyles() const;
+    InsertionPoint* findInsertionPointFor(const Node*) const;
 
 private:
-    ElementShadow()
-        : m_needsDistributionRecalc(false)
-        , m_applyAuthorStyles(false)
-    { }
+    ElementShadow();
 
     void removeAllShadowRoots();
     bool resolveApplyAuthorStyles() const;
 
+    void distribute();
+    void clearDistribution();
+    void populate(Node*, Vector<Node*>&);
+    void collectSelectFeatureSetFrom(ShadowRoot*);
+    void distributeSelectionsTo(InsertionPoint*, const Vector<Node*>& pool, Vector<bool>& distributed);
+    void distributeNodeChildrenTo(InsertionPoint*, ContainerNode*);
+
+    bool needsSelectFeatureSet() const { return m_needsSelectFeatureSet; }
+    void setNeedsSelectFeatureSet() { m_needsSelectFeatureSet = true; }
+
+    HashMap<const Node*, RefPtr<InsertionPoint> > m_nodeToInsertionPoint;
+    SelectRuleFeatureSet m_selectFeatures;
     DoublyLinkedList<ShadowRoot> m_shadowRoots;
-    ContentDistributor m_distributor;
     bool m_needsDistributionRecalc;
     bool m_applyAuthorStyles;
+    bool m_needsSelectFeatureSet;
 };
 
 inline Element* ElementShadow::host() const
@@ -120,14 +117,12 @@
     return 0;
 }
 
-class ShadowRootVector : public Vector<RefPtr<ShadowRoot> > {
-public:
-    explicit ShadowRootVector(ElementShadow* tree)
-    {
-        for (ShadowRoot* root = tree->youngestShadowRoot(); root; root = root->olderShadowRoot())
-            append(root);
-    }
-};
+inline void ElementShadow::distributeIfNeeded()
+{
+    if (m_needsDistributionRecalc)
+        distribute();
+    m_needsDistributionRecalc = false;
+}
 
 inline ElementShadow* shadowOfParent(const Node* node)
 {
@@ -139,7 +134,6 @@
     return 0;
 }
 
-
 } // namespace
 
 #endif
diff --git a/Source/core/dom/shadow/InsertionPoint.cpp b/Source/core/dom/shadow/InsertionPoint.cpp
index b4626d7..f2447c4 100644
--- a/Source/core/dom/shadow/InsertionPoint.cpp
+++ b/Source/core/dom/shadow/InsertionPoint.cpp
@@ -35,6 +35,7 @@
 #include "core/dom/QualifiedName.h"
 #include "core/dom/StaticNodeList.h"
 #include "core/dom/shadow/ElementShadow.h"
+#include "core/dom/shadow/ScopeContentDistribution.h"
 #include "core/dom/shadow/ShadowRoot.h"
 
 namespace WebCore {
@@ -52,8 +53,52 @@
 {
 }
 
+void InsertionPoint::setDistribution(ContentDistribution& distribution)
+{
+    if (shouldUseFallbackElements()) {
+        for (Node* child = firstChild(); child; child = child->nextSibling())
+            child->lazyReattachIfAttached();
+    }
+
+    // Attempt not to reattach nodes that would be distributed to the exact same
+    // location by comparing the old and new distributions.
+
+    size_t i = 0;
+    size_t j = 0;
+
+    for ( ; i < m_distribution.size() && j < distribution.size(); ++i, ++j) {
+        if (m_distribution.size() < distribution.size()) {
+            // If the new distribution is larger than the old one, reattach all nodes in
+            // the new distribution that were inserted.
+            for ( ; j < distribution.size() && m_distribution.at(i) != distribution.at(j); ++j)
+                distribution.at(j)->lazyReattachIfAttached();
+        } else if (m_distribution.size() > distribution.size()) {
+            // If the old distribution is larger than the new one, reattach all nodes in
+            // the old distribution that were removed.
+            for ( ; i < m_distribution.size() && m_distribution.at(i) != distribution.at(j); ++i)
+                m_distribution.at(i)->lazyReattachIfAttached();
+        } else if (m_distribution.at(i) != distribution.at(j)) {
+            // If both distributions are the same length reattach both old and new.
+            m_distribution.at(i)->lazyReattachIfAttached();
+            distribution.at(j)->lazyReattachIfAttached();
+        }
+    }
+
+    // If we hit the end of either list above we need to reattach all remaining nodes.
+
+    for ( ; i < m_distribution.size(); ++i)
+        m_distribution.at(i)->lazyReattachIfAttached();
+
+    for ( ; j < distribution.size(); ++j)
+        distribution.at(j)->lazyReattachIfAttached();
+
+    m_distribution.swap(distribution);
+}
+
 void InsertionPoint::attach(const AttachContext& context)
 {
+    // FIXME: This loop shouldn't be needed since the distributed nodes should
+    // never be detached, we can probably remove it.
     for (size_t i = 0; i < m_distribution.size(); ++i) {
         if (!m_distribution.at(i)->attached())
             m_distribution.at(i)->attach(context);
@@ -64,20 +109,12 @@
 
 void InsertionPoint::detach(const AttachContext& context)
 {
-    for (size_t i = 0; i < m_distribution.size(); ++i) {
-        if (m_distribution.at(i)->attached())
-            m_distribution.at(i)->detach(context);
-    }
+    for (size_t i = 0; i < m_distribution.size(); ++i)
+        m_distribution.at(i)->lazyReattachIfAttached();
 
     HTMLElement::detach(context);
 }
 
-void InsertionPoint::lazyAttachDistribution(ShouldSetAttached shouldSetAttached)
-{
-    for (size_t i = 0; i < m_distribution.size(); ++i)
-        m_distribution.at(i)->lazyAttach(shouldSetAttached);
-}
-
 void InsertionPoint::willRecalcStyle(StyleChange change)
 {
     if (change < Inherit)
@@ -208,7 +245,7 @@
 
     while (current) {
         if (ElementShadow* shadow = shadowOfParentForDistribution(current)) {
-            if (InsertionPoint* insertedTo = shadow->distributor().findInsertionPointFor(projectedNode)) {
+            if (InsertionPoint* insertedTo = shadow->findInsertionPointFor(projectedNode)) {
                 current = insertedTo;
                 insertionPoint = insertedTo;
                 continue;
@@ -234,7 +271,7 @@
     const Node* current = node;
     while (true) {
         if (ElementShadow* shadow = shadowOfParentForDistribution(current)) {
-            if (InsertionPoint* insertedTo = shadow->distributor().findInsertionPointFor(node)) {
+            if (InsertionPoint* insertedTo = shadow->findInsertionPointFor(node)) {
                 current = insertedTo;
                 results.append(insertedTo);
                 continue;
diff --git a/Source/core/dom/shadow/InsertionPoint.h b/Source/core/dom/shadow/InsertionPoint.h
index 993ea34..aeb3243 100644
--- a/Source/core/dom/shadow/InsertionPoint.h
+++ b/Source/core/dom/shadow/InsertionPoint.h
@@ -32,8 +32,7 @@
 #define InsertionPoint_h
 
 #include "core/css/CSSSelectorList.h"
-#include "core/dom/shadow/ContentDistributor.h"
-#include "core/dom/shadow/ElementShadow.h"
+#include "core/dom/shadow/ContentDistribution.h"
 #include "core/html/HTMLElement.h"
 #include "wtf/Forward.h"
 
@@ -44,7 +43,7 @@
     virtual ~InsertionPoint();
 
     bool hasDistribution() const { return !m_distribution.isEmpty(); }
-    void setDistribution(ContentDistribution& distribution) { m_distribution.swap(distribution); }
+    void setDistribution(ContentDistribution&);
     void clearDistribution() { m_distribution.clear(); }
     bool isActive() const;
 
@@ -67,8 +66,6 @@
     Node* nextTo(const Node* node) const { return m_distribution.nextTo(node); }
     Node* previousTo(const Node* node) const { return m_distribution.previousTo(node); }
 
-    void lazyAttachDistribution(ShouldSetAttached);
-
 protected:
     InsertionPoint(const QualifiedName&, Document*);
     virtual bool rendererIsNeeded(const NodeRenderingContext&) OVERRIDE;
diff --git a/Source/core/dom/shadow/ScopeContentDistribution.cpp b/Source/core/dom/shadow/ScopeContentDistribution.cpp
new file mode 100644
index 0000000..b20ee65
--- /dev/null
+++ b/Source/core/dom/shadow/ScopeContentDistribution.cpp
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 THE COPYRIGHT
+ * OWNER 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 "core/dom/shadow/ScopeContentDistribution.h"
+
+#include "core/dom/ElementTraversal.h"
+#include "core/dom/shadow/InsertionPoint.h"
+#include "core/dom/shadow/ShadowRoot.h"
+#include "core/html/shadow/HTMLContentElement.h"
+#include "core/html/shadow/HTMLShadowElement.h"
+
+namespace WebCore {
+
+ScopeContentDistribution::ScopeContentDistribution()
+    : m_insertionPointAssignedTo(0)
+    , m_numberOfShadowElementChildren(0)
+    , m_numberOfContentElementChildren(0)
+    , m_numberOfElementShadowChildren(0)
+    , m_insertionPointListIsValid(false)
+{
+}
+
+void ScopeContentDistribution::setInsertionPointAssignedTo(PassRefPtr<InsertionPoint> insertionPoint)
+{
+    m_insertionPointAssignedTo = insertionPoint;
+}
+
+void ScopeContentDistribution::invalidateInsertionPointList()
+{
+    m_insertionPointListIsValid = false;
+    m_insertionPointList.clear();
+}
+
+const Vector<RefPtr<InsertionPoint> >& ScopeContentDistribution::ensureInsertionPointList(ShadowRoot* shadowRoot)
+{
+    if (m_insertionPointListIsValid)
+        return m_insertionPointList;
+
+    m_insertionPointListIsValid = true;
+    ASSERT(m_insertionPointList.isEmpty());
+
+    if (!shadowRoot->containsInsertionPoints())
+        return m_insertionPointList;
+
+    for (Element* element = ElementTraversal::firstWithin(shadowRoot); element; element = ElementTraversal::next(element, shadowRoot)) {
+        if (element->isInsertionPoint())
+            m_insertionPointList.append(toInsertionPoint(element));
+    }
+
+    return m_insertionPointList;
+}
+
+void ScopeContentDistribution::registerInsertionPoint(InsertionPoint* point)
+{
+    if (isHTMLShadowElement(point))
+        ++m_numberOfShadowElementChildren;
+    else if (isHTMLContentElement(point))
+        ++m_numberOfContentElementChildren;
+    else
+        ASSERT_NOT_REACHED();
+
+    invalidateInsertionPointList();
+}
+
+void ScopeContentDistribution::unregisterInsertionPoint(InsertionPoint* point)
+{
+    if (isHTMLShadowElement(point))
+        --m_numberOfShadowElementChildren;
+    else if (isHTMLContentElement(point))
+        --m_numberOfContentElementChildren;
+    else
+        ASSERT_NOT_REACHED();
+
+    ASSERT(m_numberOfContentElementChildren >= 0);
+    ASSERT(m_numberOfShadowElementChildren >= 0);
+
+    invalidateInsertionPointList();
+}
+
+} // namespace WebCore
diff --git a/Source/core/dom/shadow/ScopeContentDistribution.h b/Source/core/dom/shadow/ScopeContentDistribution.h
new file mode 100644
index 0000000..43ed09f
--- /dev/null
+++ b/Source/core/dom/shadow/ScopeContentDistribution.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 THE COPYRIGHT
+ * OWNER 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 ScopeContentDistribution_h
+#define ScopeContentDistribution_h
+
+#include "wtf/Forward.h"
+#include "wtf/Vector.h"
+
+namespace WebCore {
+
+class InsertionPoint;
+class ShadowRoot;
+
+class ScopeContentDistribution {
+public:
+    ScopeContentDistribution();
+
+    InsertionPoint* insertionPointAssignedTo() const { return m_insertionPointAssignedTo.get(); }
+    void setInsertionPointAssignedTo(PassRefPtr<InsertionPoint>);
+
+    void registerInsertionPoint(InsertionPoint*);
+    void unregisterInsertionPoint(InsertionPoint*);
+    bool hasShadowElementChildren() const { return m_numberOfShadowElementChildren > 0; }
+    bool hasContentElementChildren() const { return m_numberOfContentElementChildren > 0; }
+
+    void registerElementShadow() { ++m_numberOfElementShadowChildren; }
+    void unregisterElementShadow() { ASSERT(m_numberOfElementShadowChildren > 0); --m_numberOfElementShadowChildren; }
+    unsigned numberOfElementShadowChildren() const { return m_numberOfElementShadowChildren; }
+    bool hasElementShadowChildren() const { return m_numberOfElementShadowChildren > 0; }
+
+    void invalidateInsertionPointList();
+    const Vector<RefPtr<InsertionPoint> >& ensureInsertionPointList(ShadowRoot*);
+
+private:
+    RefPtr<InsertionPoint> m_insertionPointAssignedTo;
+    unsigned m_numberOfShadowElementChildren;
+    unsigned m_numberOfContentElementChildren;
+    unsigned m_numberOfElementShadowChildren;
+    bool m_insertionPointListIsValid;
+    Vector<RefPtr<InsertionPoint> > m_insertionPointList;
+};
+
+} // namespace WebCore
+
+#endif
diff --git a/Source/core/dom/shadow/ShadowRoot.cpp b/Source/core/dom/shadow/ShadowRoot.cpp
index a218b17..b9f9ce1 100644
--- a/Source/core/dom/shadow/ShadowRoot.cpp
+++ b/Source/core/dom/shadow/ShadowRoot.cpp
@@ -29,10 +29,11 @@
 
 #include "bindings/v8/ExceptionState.h"
 #include "core/css/resolver/StyleResolver.h"
+#include "core/dom/DocumentStyleSheetCollection.h"
 #include "core/dom/Text.h"
-#include "core/dom/shadow/ContentDistributor.h"
 #include "core/dom/shadow/ElementShadow.h"
 #include "core/dom/shadow/InsertionPoint.h"
+#include "core/dom/shadow/ScopeContentDistribution.h"
 #include "core/editing/markup.h"
 #include "core/platform/HistogramSupport.h"
 
@@ -76,6 +77,8 @@
     ASSERT(!m_prev);
     ASSERT(!m_next);
 
+    documentInternal()->styleSheetCollection()->didRemoveShadowRoot(this);
+
     // We cannot let ContainerNode destructor call willBeDeletedFrom()
     // for this ShadowRoot instance because TreeScope destructor
     // clears Node::m_treeScope thus ContainerNode is no longer able
diff --git a/Source/core/dom/shadow/ShadowRoot.h b/Source/core/dom/shadow/ShadowRoot.h
index 3bfcc3d..993fdb2 100644
--- a/Source/core/dom/shadow/ShadowRoot.h
+++ b/Source/core/dom/shadow/ShadowRoot.h
@@ -149,6 +149,17 @@
     return const_cast<ShadowRoot*>(toShadowRoot(static_cast<const Node*>(node)));
 }
 
+inline const ShadowRoot* toShadowRoot(const TreeScope* treeScope)
+{
+    ASSERT_WITH_SECURITY_IMPLICATION(!treeScope || (treeScope->rootNode() && treeScope->rootNode()->isShadowRoot()));
+    return static_cast<const ShadowRoot*>(treeScope);
+}
+
+inline ShadowRoot* toShadowRoot(TreeScope* treeScope)
+{
+    return const_cast<ShadowRoot*>(toShadowRoot(static_cast<const TreeScope*>(treeScope)));
+}
+
 } // namespace
 
 #endif