Merge from Chromium at DEPS revision 251904

This commit was generated by merge_to_master.py.

Change-Id: I8ca36eee41eba7e9a56d6728a9d19e5883d7058c
diff --git a/Source/core/dom/Element.cpp b/Source/core/dom/Element.cpp
index 369bf39..5f2ae80 100644
--- a/Source/core/dom/Element.cpp
+++ b/Source/core/dom/Element.cpp
@@ -30,33 +30,35 @@
 #include "RuntimeEnabledFeatures.h"
 #include "SVGNames.h"
 #include "XMLNames.h"
+#include "bindings/v8/Dictionary.h"
 #include "bindings/v8/ExceptionState.h"
 #include "core/accessibility/AXObjectCache.h"
 #include "core/animation/DocumentTimeline.h"
 #include "core/animation/css/CSSAnimations.h"
-#include "core/css/CSSParser.h"
 #include "core/css/CSSStyleSheet.h"
 #include "core/css/CSSValuePool.h"
 #include "core/css/PropertySetCSSStyleDeclaration.h"
 #include "core/css/StylePropertySet.h"
+#include "core/css/parser/BisonCSSParser.h"
 #include "core/css/resolver/StyleResolver.h"
 #include "core/dom/Attr.h"
 #include "core/dom/CSSSelectorWatch.h"
 #include "core/dom/ClientRect.h"
 #include "core/dom/ClientRectList.h"
 #include "core/dom/DatasetDOMStringMap.h"
-#include "core/dom/DocumentSharedObjectPool.h"
+#include "core/dom/ElementDataCache.h"
 #include "core/dom/ElementRareData.h"
+#include "core/dom/ElementTraversal.h"
 #include "core/dom/ExceptionCode.h"
 #include "core/dom/FullscreenElementStack.h"
 #include "core/dom/MutationObserverInterestGroup.h"
 #include "core/dom/MutationRecord.h"
 #include "core/dom/NamedNodeMap.h"
 #include "core/dom/NodeRenderStyle.h"
-#include "core/dom/NodeRenderingContext.h"
 #include "core/dom/PostAttachCallbacks.h"
 #include "core/dom/PresentationAttributeStyle.h"
 #include "core/dom/PseudoElement.h"
+#include "core/dom/RenderTreeBuilder.h"
 #include "core/dom/ScriptableDocumentParser.h"
 #include "core/dom/SelectorQuery.h"
 #include "core/dom/Text.h"
@@ -73,6 +75,7 @@
 #include "core/frame/ContentSecurityPolicy.h"
 #include "core/frame/Frame.h"
 #include "core/frame/FrameView.h"
+#include "core/frame/UseCounter.h"
 #include "core/html/ClassList.h"
 #include "core/html/HTMLCollection.h"
 #include "core/html/HTMLDocument.h"
@@ -88,15 +91,16 @@
 #include "core/page/FocusController.h"
 #include "core/page/Page.h"
 #include "core/page/PointerLockController.h"
-#include "core/rendering/FlowThreadController.h"
-#include "core/rendering/RenderNamedFlowFragment.h"
+#include "core/rendering/RenderLayer.h"
 #include "core/rendering/RenderView.h"
 #include "core/rendering/RenderWidget.h"
 #include "core/svg/SVGDocumentExtensions.h"
 #include "core/svg/SVGElement.h"
+#include "platform/scroll/ScrollableArea.h"
 #include "wtf/BitVector.h"
 #include "wtf/HashFunctions.h"
 #include "wtf/text/CString.h"
+#include "wtf/text/StringBuilder.h"
 #include "wtf/text/TextPosition.h"
 
 namespace WebCore {
@@ -164,7 +168,7 @@
     ASSERT(!attrNodeListMap().contains(element));
     element->setHasSyntheticAttrChildNodes(true);
     AttrNodeListMap::AddResult result = attrNodeListMap().add(element, adoptPtr(new AttrNodeList));
-    return *result.iterator->value;
+    return *result.storedValue->value;
 }
 
 static void removeAttrNodeListForElement(Element* element)
@@ -192,26 +196,10 @@
 
 Element::~Element()
 {
-    // When the document is not destroyed, an element that was part of a named flow
-    // content nodes should have been removed from the content nodes collection
-    // and the inNamedFlow flag reset.
-    ASSERT(!document().renderView() || !inNamedFlow());
+    ASSERT(needsAttach());
 
-    if (PropertySetCSSStyleDeclaration* cssomWrapper = inlineStyleCSSOMWrapper())
-        cssomWrapper->clearParentElement();
-
-    if (hasRareData()) {
-        ElementRareData* data = elementRareData();
-        data->setPseudoElement(BEFORE, 0);
-        data->setPseudoElement(AFTER, 0);
-        data->setPseudoElement(BACKDROP, 0);
-        data->clearShadow();
-
-        if (RuntimeEnabledFeatures::webAnimationsCSSEnabled()) {
-            if (ActiveAnimations* activeAnimations = data->activeAnimations())
-                activeAnimations->cssAnimations().cancel();
-        }
-    }
+    if (hasRareData())
+        elementRareData()->clearShadow();
 
     if (isCustomElement())
         CustomElement::wasDestroyed(this);
@@ -272,9 +260,7 @@
     // FIXME: These asserts should be in Node::isFocusable, but there are some
     // callsites like Document::setFocusedElement that would currently fail on
     // them. See crbug.com/251163
-    if (renderer()) {
-        ASSERT(!renderer()->needsLayout());
-    } else {
+    if (!renderer()) {
         // We can't just use needsStyleRecalc() because if the node is in a
         // display:none tree it might say it needs style recalc but the whole
         // document is actually up to date.
@@ -390,9 +376,6 @@
 
 bool Element::hasActiveAnimations() const
 {
-    if (!RuntimeEnabledFeatures::webAnimationsCSSEnabled())
-        return false;
-
     if (!hasRareData())
         return false;
 
@@ -414,6 +397,9 @@
 {
     if (!elementData())
         return;
+    // NOTE: anyAttributeMatches in SelectorChecker.cpp
+    // currently assumes that all lazy attributes have a null namespace.
+    // If that ever changes we'll need to fix that code.
     if (elementData()->m_styleAttributeIsDirty) {
         ASSERT(isStyledElement());
         synchronizeStyleAttributeInternal();
@@ -435,6 +421,8 @@
     }
     if (UNLIKELY(elementData()->m_animatedSVGAttributesAreDirty)) {
         ASSERT(isSVGElement());
+        // See comment in the AtomicString version of synchronizeAttribute()
+        // also.
         toSVGElement(this)->synchronizeAnimatedSVGAttribute(name);
     }
 }
@@ -452,8 +440,17 @@
     }
     if (elementData()->m_animatedSVGAttributesAreDirty) {
         // We're not passing a namespace argument on purpose. SVGNames::*Attr are defined w/o namespaces as well.
-        ASSERT(isSVGElement());
-        static_cast<const SVGElement*>(this)->synchronizeAnimatedSVGAttribute(QualifiedName(nullAtom, localName, nullAtom));
+
+        // FIXME: this code is called regardless of whether name is an
+        // animated SVG Attribute. It would seem we should only call this method
+        // if SVGElement::isAnimatableAttribute is true, but the list of
+        // animatable attributes in isAnimatableAttribute does not suffice to
+        // pass all layout tests. Also, m_animatedSVGAttributesAreDirty stays
+        // dirty unless synchronizeAnimatedSVGAttribute is called with
+        // anyQName(). This means that even if Element::synchronizeAttribute()
+        // is called on all attributes, m_animatedSVGAttributesAreDirty remains
+        // true.
+        toSVGElement(this)->synchronizeAnimatedSVGAttribute(QualifiedName(nullAtom, localName, nullAtom));
     }
 }
 
@@ -594,7 +591,7 @@
     return 0;
 }
 
-Element* Element::bindingsOffsetParent()
+Element* Element::offsetParentForBindings()
 {
     Element* element = offsetParent();
     if (!element || !element->isInShadowTree())
@@ -740,6 +737,27 @@
     }
 }
 
+void Element::setScrollLeft(const Dictionary& scrollOptionsHorizontal, ExceptionState& exceptionState)
+{
+    String scrollBehaviorString;
+    ScrollBehavior scrollBehavior = ScrollBehaviorAuto;
+    if (scrollOptionsHorizontal.get("behavior", scrollBehaviorString)) {
+        if (!ScrollableArea::scrollBehaviorFromString(scrollBehaviorString, scrollBehavior)) {
+            exceptionState.throwTypeError("The ScrollBehavior provided is invalid.");
+            return;
+        }
+    }
+
+    int position;
+    if (!scrollOptionsHorizontal.get("x", position)) {
+        exceptionState.throwTypeError("ScrollOptionsHorizontal must include an 'x' member.");
+        return;
+    }
+
+    // FIXME: Use scrollBehavior to decide whether to scroll smoothly or instantly.
+    setScrollLeft(position);
+}
+
 void Element::setScrollTop(int newTop)
 {
     document().updateLayoutIgnorePendingStylesheets();
@@ -765,6 +783,27 @@
     }
 }
 
+void Element::setScrollTop(const Dictionary& scrollOptionsVertical, ExceptionState& exceptionState)
+{
+    String scrollBehaviorString;
+    ScrollBehavior scrollBehavior = ScrollBehaviorAuto;
+    if (scrollOptionsVertical.get("behavior", scrollBehaviorString)) {
+        if (!ScrollableArea::scrollBehaviorFromString(scrollBehaviorString, scrollBehavior)) {
+            exceptionState.throwTypeError("The ScrollBehavior provided is invalid.");
+            return;
+        }
+    }
+
+    int position;
+    if (!scrollOptionsVertical.get("y", position)) {
+        exceptionState.throwTypeError("ScrollOptionsVertical must include a 'y' member.");
+        return;
+    }
+
+    // FIXME: Use scrollBehavior to decide whether to scroll smoothly or instantly.
+    setScrollTop(position);
+}
+
 int Element::scrollWidth()
 {
     document().updateLayoutIgnorePendingStylesheets();
@@ -885,7 +924,7 @@
 void Element::setAttribute(const AtomicString& localName, const AtomicString& value, ExceptionState& exceptionState)
 {
     if (!Document::isValidName(localName)) {
-        exceptionState.throwUninformativeAndGenericDOMException(InvalidCharacterError);
+        exceptionState.throwDOMException(InvalidCharacterError, "'" + localName + "' is not a valid attribute name.");
         return;
     }
 
@@ -993,8 +1032,6 @@
         classAttributeChanged(newValue);
     } else if (name == HTMLNames::nameAttr) {
         setHasName(!newValue.isNull());
-    } else if (name == HTMLNames::pseudoAttr) {
-        shouldInvalidateStyle |= testShouldInvalidateStyle && isInShadowTree();
     }
 
     invalidateNodeListCachesInAncestors(&name, this);
@@ -1003,7 +1040,7 @@
     shouldInvalidateStyle |= !styleResolver;
 
     if (shouldInvalidateStyle)
-        setNeedsStyleRecalc();
+        setNeedsStyleRecalc(SubtreeStyleChange);
 
     if (AXObjectCache* cache = document().existingAXObjectCache())
         cache->handleAttributeChanged(name, this);
@@ -1043,77 +1080,27 @@
     return classStringHasClassName(newClassString.characters16(), length);
 }
 
-template<typename Checker>
-static bool checkSelectorForClassChange(const SpaceSplitString& changedClasses, const Checker& checker)
-{
-    unsigned changedSize = changedClasses.size();
-    for (unsigned i = 0; i < changedSize; ++i) {
-        if (checker.hasSelectorForClass(changedClasses[i]))
-            return true;
-    }
-    return false;
-}
-
-template<typename Checker>
-static bool checkSelectorForClassChange(const SpaceSplitString& oldClasses, const SpaceSplitString& newClasses, const Checker& checker)
-{
-    if (!oldClasses.size())
-        return checkSelectorForClassChange(newClasses, checker);
-
-    // Class vectors tend to be very short. This is faster than using a hash table.
-    BitVector remainingClassBits;
-    remainingClassBits.ensureSize(oldClasses.size());
-
-    for (unsigned i = 0; i < newClasses.size(); ++i) {
-        bool found = false;
-        for (unsigned j = 0; j < oldClasses.size(); ++j) {
-            if (newClasses[i] == oldClasses[j]) {
-                // Mark each class that is still in the newClasses so we can skip doing
-                // an n^2 search below when looking for removals. We can't break from
-                // this loop early since a class can appear more than once.
-                remainingClassBits.quickSet(j);
-                found = true;
-            }
-        }
-        // Class was added.
-        if (!found && checker.hasSelectorForClass(newClasses[i]))
-            return true;
-    }
-
-    for (unsigned i = 0; i < oldClasses.size(); ++i) {
-        if (remainingClassBits.quickGet(i))
-            continue;
-        // Class was removed.
-        if (checker.hasSelectorForClass(oldClasses[i]))
-            return true;
-    }
-
-    return false;
-}
-
 void Element::classAttributeChanged(const AtomicString& newClassString)
 {
     StyleResolver* styleResolver = document().styleResolver();
     bool testShouldInvalidateStyle = inActiveDocument() && styleResolver && styleChangeType() < SubtreeStyleChange;
-    bool shouldInvalidateStyle = false;
 
     if (classStringHasClassName(newClassString)) {
         const bool shouldFoldCase = document().inQuirksMode();
         const SpaceSplitString oldClasses = elementData()->classNames();
         elementData()->setClass(newClassString, shouldFoldCase);
         const SpaceSplitString& newClasses = elementData()->classNames();
-        shouldInvalidateStyle = testShouldInvalidateStyle && checkSelectorForClassChange(oldClasses, newClasses, styleResolver->ensureRuleFeatureSet());
+        if (testShouldInvalidateStyle)
+            styleResolver->ensureRuleFeatureSet().scheduleStyleInvalidationForClassChange(oldClasses, newClasses, this);
     } else {
         const SpaceSplitString& oldClasses = elementData()->classNames();
-        shouldInvalidateStyle = testShouldInvalidateStyle && checkSelectorForClassChange(oldClasses, styleResolver->ensureRuleFeatureSet());
+        if (testShouldInvalidateStyle)
+            styleResolver->ensureRuleFeatureSet().scheduleStyleInvalidationForClassChange(oldClasses, this);
         elementData()->clearClass();
     }
 
     if (hasRareData())
         elementRareData()->clearClassListValueForQuirksMode();
-
-    if (shouldInvalidateStyle)
-        setNeedsStyleRecalc();
 }
 
 bool Element::shouldInvalidateDistributionWhenAttributeChanged(ElementShadow* elementShadow, const QualifiedName& name, const AtomicString& newValue)
@@ -1138,11 +1125,11 @@
             const bool shouldFoldCase = document().inQuirksMode();
             const SpaceSplitString& oldClasses = elementData()->classNames();
             const SpaceSplitString newClasses(newClassString, shouldFoldCase);
-            if (checkSelectorForClassChange(oldClasses, newClasses, featureSet))
+            if (featureSet.checkSelectorsForClassChange(oldClasses, newClasses))
                 return true;
         } else {
             const SpaceSplitString& oldClasses = elementData()->classNames();
-            if (checkSelectorForClassChange(oldClasses, featureSet))
+            if (featureSet.checkSelectorsForClassChange(oldClasses))
                 return true;
         }
     }
@@ -1191,8 +1178,8 @@
     if (attributeVector.isEmpty())
         return;
 
-    if (document().sharedObjectPool())
-        m_elementData = document().sharedObjectPool()->cachedShareableElementDataWithAttributes(attributeVector);
+    if (document().elementDataCache())
+        m_elementData = document().elementDataCache()->cachedShareableElementDataWithAttributes(attributeVector);
     else
         m_elementData = ShareableElementData::createWithAttributes(attributeVector);
 
@@ -1225,23 +1212,57 @@
     return m_tagName.toString();
 }
 
-String Element::nodeNamePreservingCase() const
-{
-    return m_tagName.toString();
-}
-
 void Element::setPrefix(const AtomicString& prefix, ExceptionState& exceptionState)
 {
-    checkSetPrefix(prefix, exceptionState);
+    UseCounter::count(document(), UseCounter::ElementSetPrefix);
+
+    if (!prefix.isEmpty() && !Document::isValidName(prefix)) {
+        exceptionState.throwDOMException(InvalidCharacterError, "The prefix '" + prefix + "' is not a valid name.");
+        return;
+    }
+
+    // FIXME: Raise NamespaceError if prefix is malformed per the Namespaces in XML specification.
+
+    const AtomicString& nodeNamespaceURI = namespaceURI();
+    if (nodeNamespaceURI.isEmpty() && !prefix.isEmpty()) {
+        exceptionState.throwDOMException(NamespaceError, "No namespace is set, so a namespace prefix may not be set.");
+        return;
+    }
+
+    if (prefix == xmlAtom && nodeNamespaceURI != XMLNames::xmlNamespaceURI) {
+        exceptionState.throwDOMException(NamespaceError, "The prefix '" + xmlAtom + "' may not be set on namespace '" + nodeNamespaceURI + "'.");
+        return;
+    }
+
     if (exceptionState.hadException())
         return;
 
     m_tagName.setPrefix(prefix.isEmpty() ? AtomicString() : prefix);
 }
 
+const AtomicString& Element::locateNamespacePrefix(const AtomicString& namespaceToLocate) const
+{
+    if (!prefix().isNull() && namespaceURI() == namespaceToLocate)
+        return prefix();
+
+    if (hasAttributes()) {
+        for (unsigned i = 0; i < attributeCount(); i++) {
+            const Attribute* attr = attributeItem(i);
+
+            if (attr->prefix() == xmlnsAtom && attr->value() == namespaceToLocate)
+                return attr->localName();
+        }
+    }
+
+    if (Element* parent = parentElement())
+        return parent->locateNamespacePrefix(namespaceToLocate);
+
+    return nullAtom;
+}
+
 KURL Element::baseURI() const
 {
-    const AtomicString& baseAttribute = getAttribute(baseAttr);
+    const AtomicString& baseAttribute = fastGetAttribute(baseAttr);
     KURL base(KURL(), baseAttribute);
     if (!base.protocol().isEmpty())
         return base;
@@ -1377,7 +1398,7 @@
             data->resetStyleState();
     }
 
-    NodeRenderingContext(this, context.resolvedStyle).createRendererForElementIfNeeded();
+    RenderTreeBuilder(this, context.resolvedStyle).createRendererForElementIfNeeded();
 
     addCallbackSelectors();
 
@@ -1403,29 +1424,25 @@
                 document().updateFocusAppearanceSoon(false /* don't restore selection */);
             data->setNeedsFocusAppearanceUpdateSoonAfterAttach(false);
         }
+        if (!renderer()) {
+            if (ActiveAnimations* activeAnimations = data->activeAnimations()) {
+                activeAnimations->cssAnimations().cancel();
+                activeAnimations->setAnimationStyleChange(false);
+            }
+        }
     }
 
     InspectorInstrumentation::didRecalculateStyleForElement(this);
 }
 
-void Element::unregisterNamedFlowContentNode()
-{
-    if (RuntimeEnabledFeatures::cssRegionsEnabled() && inNamedFlow() && document().renderView())
-        document().renderView()->flowThreadController()->unregisterNamedFlowContentNode(this);
-}
-
 void Element::detach(const AttachContext& context)
 {
     RenderWidget::UpdateSuspendScope suspendWidgetHierarchyUpdates;
-    unregisterNamedFlowContentNode();
     cancelFocusAppearanceUpdate();
     removeCallbackSelectors();
     if (hasRareData()) {
         ElementRareData* data = elementRareData();
-        data->setPseudoElement(BEFORE, 0);
-        data->setPseudoElement(AFTER, 0);
-        data->setPseudoElement(BACKDROP, 0);
-        data->setIsInsideRegion(false);
+        data->clearPseudoElements();
 
         // attach() will perform the below steps for us when inside recalcStyle.
         if (!document().inStyleRecalc()) {
@@ -1434,19 +1451,23 @@
             data->resetDynamicRestyleObservations();
         }
 
-        if (RuntimeEnabledFeatures::webAnimationsCSSEnabled()) {
-            if (ActiveAnimations* activeAnimations = data->activeAnimations()) {
-                if (context.performingReattach) {
-                    // FIXME: restart compositor animations rather than pull back to the main thread
-                    activeAnimations->cancelAnimationOnCompositor();
-                } else {
-                    activeAnimations->cssAnimations().cancel();
-                }
+        if (ActiveAnimations* activeAnimations = data->activeAnimations()) {
+            if (context.performingReattach) {
+                // FIXME: We call detach from withing style recalc, so compositingState is not up to date.
+                // https://code.google.com/p/chromium/issues/detail?id=339847
+                DisableCompositingQueryAsserts disabler;
+
+                // FIXME: restart compositor animations rather than pull back to the main thread
+                activeAnimations->cancelAnimationOnCompositor();
+            } else {
+                activeAnimations->cssAnimations().cancel();
+                activeAnimations->setAnimationStyleChange(false);
             }
         }
+
+        if (ElementShadow* shadow = data->shadow())
+            shadow->detach(context);
     }
-    if (ElementShadow* shadow = this->shadow())
-        shadow->detach(context);
     ContainerNode::detach(context);
 }
 
@@ -1543,9 +1564,10 @@
     }
 
     // If we reattached we don't need to recalc the style of our descendants anymore.
-    if ((change >= Inherit && change < Reattach) || childNeedsStyleRecalc())
+    if ((change >= UpdatePseudoElements && change < Reattach) || childNeedsStyleRecalc()) {
         recalcChildStyle(change);
-    clearChildNeedsStyleRecalc();
+        clearChildNeedsStyleRecalc();
+    }
 
     if (hasCustomStyleCallbacks())
         didRecalcStyle(change);
@@ -1583,7 +1605,7 @@
 
     if (RenderObject* renderer = this->renderer()) {
         if (localChange != NoChange || pseudoStyleCacheIsInvalid(oldStyle.get(), newStyle.get()) || shouldNotifyRendererWithIdenticalStyles()) {
-            renderer->setAnimatableStyle(newStyle.get());
+            renderer->setStyle(newStyle.get());
         } else {
             // Although no change occurred, we use the new style so that the cousin style sharing code won't get
             // fooled into believing this style is the same.
@@ -1593,68 +1615,67 @@
         }
     }
 
-    // If "rem" units are used anywhere in the document, and if the document element's font size changes, then go ahead and force font updating
-    // all the way down the tree. This is simpler than having to maintain a cache of objects (and such font size changes should be rare anyway).
-    if (document().styleEngine()->usesRemUnits() && document().documentElement() == this && oldStyle->fontSize() != newStyle->fontSize()) {
-        // Cached RenderStyles may depend on the re units.
-        document().ensureStyleResolver().invalidateMatchedPropertiesCache();
-        return Force;
-    }
-
     if (styleChangeType() >= SubtreeStyleChange)
         return Force;
 
-    return max(localChange, change);
+    if (change > Inherit || localChange > Inherit)
+        return max(localChange, change);
+
+    if (localChange < Inherit && (oldStyle->hasPseudoElementStyle() || newStyle->hasPseudoElementStyle()))
+        return UpdatePseudoElements;
+
+    return localChange;
 }
 
 void Element::recalcChildStyle(StyleRecalcChange change)
 {
     ASSERT(document().inStyleRecalc());
-    ASSERT(change >= Inherit || childNeedsStyleRecalc());
+    ASSERT(change >= UpdatePseudoElements || childNeedsStyleRecalc());
     ASSERT(!needsStyleRecalc());
 
     StyleResolverParentPusher parentPusher(*this);
 
-    for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadowRoot()) {
-        if (shouldRecalcStyle(change, root)) {
-            parentPusher.push();
-            root->recalcStyle(change);
+    if (change > UpdatePseudoElements || childNeedsStyleRecalc()) {
+        for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadowRoot()) {
+            if (root->shouldCallRecalcStyle(change)) {
+                parentPusher.push();
+                root->recalcStyle(change);
+            }
         }
     }
 
-    if (shouldRecalcStyle(change, this))
-        updatePseudoElement(BEFORE, change);
+    updatePseudoElement(BEFORE, change);
 
     if (change < Force && hasRareData() && childNeedsStyleRecalc())
         checkForChildrenAdjacentRuleChanges();
 
-    // This loop is deliberately backwards because we use insertBefore in the rendering tree, and want to avoid
-    // a potentially n^2 loop to find the insertion point while resolving style. Having us start from the last
-    // child and work our way back means in the common case, we'll find the insertion point in O(1) time.
-    // See crbug.com/288225
-    StyleResolver& styleResolver = document().ensureStyleResolver();
-    Text* lastTextNode = 0;
-    for (Node* child = lastChild(); child; child = child->previousSibling()) {
-        if (child->isTextNode()) {
-            toText(child)->recalcTextStyle(change, lastTextNode);
-            lastTextNode = toText(child);
-        } else if (child->isElementNode()) {
-            Element* element = toElement(child);
-            if (shouldRecalcStyle(change, element)) {
-                parentPusher.push();
-                element->recalcStyle(change, lastTextNode);
-            } else if (element->supportsStyleSharing()) {
-                styleResolver.addToStyleSharingList(*element);
+    if (change > UpdatePseudoElements || childNeedsStyleRecalc()) {
+        // This loop is deliberately backwards because we use insertBefore in the rendering tree, and want to avoid
+        // a potentially n^2 loop to find the insertion point while resolving style. Having us start from the last
+        // child and work our way back means in the common case, we'll find the insertion point in O(1) time.
+        // See crbug.com/288225
+        StyleResolver& styleResolver = document().ensureStyleResolver();
+        Text* lastTextNode = 0;
+        for (Node* child = lastChild(); child; child = child->previousSibling()) {
+            if (child->isTextNode()) {
+                toText(child)->recalcTextStyle(change, lastTextNode);
+                lastTextNode = toText(child);
+            } else if (child->isElementNode()) {
+                Element* element = toElement(child);
+                if (element->shouldCallRecalcStyle(change)) {
+                    parentPusher.push();
+                    element->recalcStyle(change, lastTextNode);
+                } else if (element->supportsStyleSharing()) {
+                    styleResolver.addToStyleSharingList(*element);
+                }
+                if (element->renderer())
+                    lastTextNode = 0;
             }
-            if (element->renderer())
-                lastTextNode = 0;
         }
     }
 
-    if (shouldRecalcStyle(change, this)) {
-        updatePseudoElement(AFTER, change);
-        updatePseudoElement(BACKDROP, change);
-    }
+    updatePseudoElement(AFTER, change);
+    updatePseudoElement(BACKDROP, change);
 }
 
 void Element::checkForChildrenAdjacentRuleChanges()
@@ -1675,7 +1696,7 @@
         bool childRulesChanged = element->needsStyleRecalc() && element->styleChangeType() >= SubtreeStyleChange;
 
         if (forceCheckOfNextElementCount || forceCheckOfAnyElementSibling)
-            element->setNeedsStyleRecalc();
+            element->setNeedsStyleRecalc(SubtreeStyleChange);
 
         if (forceCheckOfNextElementCount)
             forceCheckOfNextElementCount--;
@@ -1720,7 +1741,7 @@
 
 void Element::didAffectSelector(AffectedSelectorMask mask)
 {
-    setNeedsStyleRecalc();
+    setNeedsStyleRecalc(SubtreeStyleChange);
     if (ElementShadow* elementShadow = shadowWhereNodeCanBeDistributed(*this))
         elementShadow->didAffectSelector(mask);
 }
@@ -1736,7 +1757,7 @@
     if (styleChangeType() != NoStyleChange)
         return;
 
-    setNeedsStyleRecalc(LocalStyleChange, StyleChangeFromRenderer);
+    setNeedsStyleRecalc(LocalStyleChange);
     setAnimationStyleChange(true);
 }
 
@@ -1745,16 +1766,14 @@
     if (alwaysCreateUserAgentShadowRoot())
         ensureUserAgentShadowRoot();
 
-    if (RuntimeEnabledFeatures::authorShadowDOMForAnyElementEnabled())
-        return PassRefPtr<ShadowRoot>(ensureShadow().addShadowRoot(*this, ShadowRoot::AuthorShadowRoot));
-
-    // Since some elements recreates shadow root dynamically, multiple shadow
-    // subtrees won't work well in that element. Until they are fixed, we disable
-    // adding author shadow root for them.
-    if (!areAuthorShadowsAllowed()) {
-        exceptionState.throwUninformativeAndGenericDOMException(HierarchyRequestError);
+    // Some elements make assumptions about what kind of renderers they allow
+    // as children so we can't allow author shadows on them for now. An override
+    // flag is provided for testing how author shadows interact on these elements.
+    if (!areAuthorShadowsAllowed() && !RuntimeEnabledFeatures::authorShadowDOMForAnyElementEnabled()) {
+        exceptionState.throwDOMException(HierarchyRequestError, "Author-created shadow roots are disabled for this element.");
         return 0;
     }
+
     return PassRefPtr<ShadowRoot>(ensureShadow().addShadowRoot(*this, ShadowRoot::AuthorShadowRoot));
 }
 
@@ -1815,7 +1834,7 @@
         return;
 
     if (!style || (styleAffectedByEmpty() && (!style->emptyState() || hasChildNodes())))
-        setNeedsStyleRecalc();
+        setNeedsStyleRecalc(SubtreeStyleChange);
 }
 
 void Element::checkForSiblingStyleChanges(bool finishedParsingCallback, Node* beforeChange, Node* afterChange, int childCountDelta)
@@ -1839,7 +1858,7 @@
     // For performance reasons we just mark the parent node as changed, since we don't want to make childrenChanged O(n^2) by crawling all our kids
     // here. recalcStyle will then force a walk of the children when it sees that this has happened.
     if ((childrenAffectedByForwardPositionalRules() && afterChange) || (childrenAffectedByBackwardPositionalRules() && beforeChange)) {
-        setNeedsStyleRecalc();
+        setNeedsStyleRecalc(SubtreeStyleChange);
         return;
     }
 
@@ -1848,47 +1867,47 @@
     // |afterChange| is 0 in the parser case, so it works out that we'll skip this block.
     if (childrenAffectedByFirstChildRules() && afterChange) {
         // Find our new first child.
-        Node* newFirstChild = firstElementChild();
+        Element* newFirstChild = ElementTraversal::firstWithin(*this);
         RenderStyle* newFirstChildStyle = newFirstChild ? newFirstChild->renderStyle() : 0;
 
         // Find the first element node following |afterChange|
-        Node* firstElementAfterInsertion = afterChange->isElementNode() ? afterChange : afterChange->nextElementSibling();
+        Node* firstElementAfterInsertion = afterChange->isElementNode() ? afterChange : ElementTraversal::nextSibling(*afterChange);
         RenderStyle* firstElementAfterInsertionStyle = firstElementAfterInsertion ? firstElementAfterInsertion->renderStyle() : 0;
 
         // This is the insert/append case.
         if (newFirstChild != firstElementAfterInsertion && firstElementAfterInsertionStyle && firstElementAfterInsertionStyle->firstChildState())
-            firstElementAfterInsertion->setNeedsStyleRecalc();
+            firstElementAfterInsertion->setNeedsStyleRecalc(SubtreeStyleChange);
 
         // We also have to handle node removal.
         if (childCountDelta < 0 && newFirstChild == firstElementAfterInsertion && newFirstChild && (!newFirstChildStyle || !newFirstChildStyle->firstChildState()))
-            newFirstChild->setNeedsStyleRecalc();
+            newFirstChild->setNeedsStyleRecalc(SubtreeStyleChange);
     }
 
     // :last-child.  In the parser callback case, we don't have to check anything, since we were right the first time.
     // In the DOM case, we only need to do something if |afterChange| is not 0.
     if (childrenAffectedByLastChildRules() && beforeChange) {
         // Find our new last child.
-        Node* newLastChild = lastElementChild();
+        Node* newLastChild = ElementTraversal::lastWithin(*this);
         RenderStyle* newLastChildStyle = newLastChild ? newLastChild->renderStyle() : 0;
 
         // Find the last element node going backwards from |beforeChange|
-        Node* lastElementBeforeInsertion = beforeChange->isElementNode() ? beforeChange : beforeChange->previousElementSibling();
+        Node* lastElementBeforeInsertion = beforeChange->isElementNode() ? beforeChange : ElementTraversal::previousSibling(*beforeChange);
         RenderStyle* lastElementBeforeInsertionStyle = lastElementBeforeInsertion ? lastElementBeforeInsertion->renderStyle() : 0;
 
         if (newLastChild != lastElementBeforeInsertion && lastElementBeforeInsertionStyle && lastElementBeforeInsertionStyle->lastChildState())
-            lastElementBeforeInsertion->setNeedsStyleRecalc();
+            lastElementBeforeInsertion->setNeedsStyleRecalc(SubtreeStyleChange);
 
         // We also have to handle node removal.  The parser callback case is similar to node removal as well in that we need to change the last child
         // to match now.
         if ((childCountDelta < 0 || finishedParsingCallback) && newLastChild == lastElementBeforeInsertion && newLastChild && (!newLastChildStyle || !newLastChildStyle->lastChildState()))
-            newLastChild->setNeedsStyleRecalc();
+            newLastChild->setNeedsStyleRecalc(SubtreeStyleChange);
     }
 
     // The + selector.  We need to invalidate the first element following the insertion point.  It is the only possible element
     // that could be affected by this DOM change.
     if (childrenAffectedByDirectAdjacentRules() && afterChange) {
-        if (Node* firstElementAfterInsertion = afterChange->isElementNode() ? afterChange : afterChange->nextElementSibling())
-            firstElementAfterInsertion->setNeedsStyleRecalc();
+        if (Node* firstElementAfterInsertion = afterChange->isElementNode() ? afterChange : ElementTraversal::nextSibling(*afterChange))
+            firstElementAfterInsertion->setNeedsStyleRecalc(SubtreeStyleChange);
     }
 }
 
@@ -1911,14 +1930,9 @@
         shadow->removeAllEventListeners();
 }
 
-void Element::beginParsingChildren()
-{
-    clearIsParsingChildrenFinished();
-}
-
 void Element::finishParsingChildren()
 {
-    setIsParsingChildrenFinished();
+    setIsFinishedParsingChildren(true);
     checkForSiblingStyleChanges(this, lastChild(), 0, 0);
 }
 
@@ -1959,7 +1973,7 @@
 PassRefPtr<Attr> Element::setAttributeNode(Attr* attrNode, ExceptionState& exceptionState)
 {
     if (!attrNode) {
-        exceptionState.throwUninformativeAndGenericDOMException(TypeMismatchError);
+        exceptionState.throwDOMException(TypeMismatchError, "The node provided is invalid.");
         return 0;
     }
 
@@ -1970,7 +1984,7 @@
     // InUseAttributeError: Raised if node is an Attr that is already an attribute of another Element object.
     // The DOM user must explicitly clone Attr nodes to re-use them in other elements.
     if (attrNode->ownerElement()) {
-        exceptionState.throwUninformativeAndGenericDOMException(InUseAttributeError);
+        exceptionState.throwDOMException(InUseAttributeError, "The node provided is an attribute node that is already an attribute of another Element; attribute nodes must be explicitly cloned.");
         return 0;
     }
 
@@ -1994,19 +2008,14 @@
     return oldAttrNode.release();
 }
 
-PassRefPtr<Attr> Element::setAttributeNodeNS(Attr* attr, ExceptionState& exceptionState)
-{
-    return setAttributeNode(attr, exceptionState);
-}
-
 PassRefPtr<Attr> Element::removeAttributeNode(Attr* attr, ExceptionState& exceptionState)
 {
     if (!attr) {
-        exceptionState.throwUninformativeAndGenericDOMException(TypeMismatchError);
+        exceptionState.throwDOMException(TypeMismatchError, "The node provided is invalid.");
         return 0;
     }
     if (attr->ownerElement() != this) {
-        exceptionState.throwUninformativeAndGenericDOMException(NotFoundError);
+        exceptionState.throwDOMException(NotFoundError, "The node provided is owned by another element.");
         return 0;
     }
 
@@ -2016,7 +2025,7 @@
 
     size_t index = elementData()->getAttrIndex(attr);
     if (index == kNotFound) {
-        exceptionState.throwUninformativeAndGenericDOMException(NotFoundError);
+        exceptionState.throwDOMException(NotFoundError, "The attribute was not found on this element.");
         return 0;
     }
 
@@ -2035,7 +2044,7 @@
     QualifiedName qName(prefix, localName, namespaceURI);
 
     if (!Document::hasValidNamespaceForAttributes(qName)) {
-        exceptionState.throwUninformativeAndGenericDOMException(NamespaceError);
+        exceptionState.throwDOMException(NamespaceError, "'" + namespaceURI + "' is an invalid namespace for attributes.");
         return false;
     }
 
@@ -2144,7 +2153,7 @@
     return elementData()->getAttributeItem(qName);
 }
 
-void Element::focus(bool restorePreviousSelection, FocusDirection direction)
+void Element::focus(bool restorePreviousSelection, FocusType type)
 {
     if (!inDocument())
         return;
@@ -2171,7 +2180,7 @@
         // If a focus event handler changes the focus to a different node it
         // does not make sense to continue and update appearence.
         protect = this;
-        if (!page->focusController().setFocusedElement(this, doc.frame(), direction))
+        if (!page->focusController().setFocusedElement(this, doc.frame(), type))
             return;
     }
 
@@ -2233,7 +2242,7 @@
     return isFocusable();
 }
 
-void Element::dispatchFocusEvent(Element* oldFocusedElement, FocusDirection)
+void Element::dispatchFocusEvent(Element* oldFocusedElement, FocusType)
 {
     RefPtr<FocusEvent> event = FocusEvent::create(EventTypeNames::focus, false, false, document().domWindow(), 0, oldFocusedElement);
     EventDispatcher::dispatchEvent(this, FocusEventDispatchMediator::create(event.release()));
@@ -2282,10 +2291,15 @@
 void Element::setOuterHTML(const String& html, ExceptionState& exceptionState)
 {
     Node* p = parentNode();
-    if (!p || !p->isElementNode()) {
-        exceptionState.throwUninformativeAndGenericDOMException(NoModificationAllowedError);
+    if (!p) {
+        exceptionState.throwDOMException(NoModificationAllowedError, "This element has no parent node.");
         return;
     }
+    if (!p->isElementNode()) {
+        exceptionState.throwDOMException(NoModificationAllowedError, "This element's parent is of type '" + p->nodeName() + "', which is not an element node.");
+        return;
+    }
+
     RefPtr<Element> parent = toElement(p);
     RefPtr<Node> prev = previousSibling();
     RefPtr<Node> next = nextSibling();
@@ -2354,6 +2368,24 @@
     return 0;
 }
 
+Element* Element::insertAdjacentElement(const String& where, Element* newChild, ExceptionState& exceptionState)
+{
+    if (!newChild) {
+        // IE throws COM Exception E_INVALIDARG; this is the best DOM exception alternative.
+        exceptionState.throwTypeError("The node provided is null.");
+        return 0;
+    }
+
+    Node* returnValue = insertAdjacent(where, newChild, exceptionState);
+    return toElement(returnValue);
+}
+
+void Element::insertAdjacentText(const String& where, const String& text, ExceptionState& exceptionState)
+{
+    RefPtr<Text> textNode = document().createTextNode(text);
+    insertAdjacent(where, textNode.get(), exceptionState);
+}
+
 void Element::insertAdjacentHTML(const String& where, const String& markup, ExceptionState& exceptionState)
 {
     RefPtr<Element> contextElement = contextElementForInsertion(where, this, exceptionState);
@@ -2427,15 +2459,19 @@
     return content.toString();
 }
 
-// pseudo is used via shadowPseudoId.
-const AtomicString& Element::pseudo() const
+const AtomicString& Element::shadowPseudoId() const
 {
-    return getAttribute(pseudoAttr);
+    if (ShadowRoot* root = containingShadowRoot()) {
+        if (root->type() == ShadowRoot::UserAgentShadowRoot)
+            return fastGetAttribute(pseudoAttr);
+    }
+    return nullAtom;
 }
 
-void Element::setPseudo(const AtomicString& value)
+void Element::setShadowPseudoId(const AtomicString& id)
 {
-    setAttribute(pseudoAttr, value);
+    ASSERT(CSSSelector::parsePseudoType(id) == CSSSelector::PseudoWebKitCustomElement || CSSSelector::parsePseudoType(id) == CSSSelector::PseudoUserAgentCustomElement);
+    setAttribute(pseudoAttr, id);
 }
 
 bool Element::isInDescendantTreeOf(const Element* shadowHost) const
@@ -2641,29 +2677,6 @@
     return hasRareData() && elementRareData()->isInCanvasSubtree();
 }
 
-void Element::setIsInsideRegion(bool value)
-{
-    if (value == isInsideRegion())
-        return;
-
-    ensureElementRareData().setIsInsideRegion(value);
-}
-
-bool Element::isInsideRegion() const
-{
-    return hasRareData() ? elementRareData()->isInsideRegion() : false;
-}
-
-void Element::setRegionOversetState(RegionOversetState state)
-{
-    ensureElementRareData().setRegionOversetState(state);
-}
-
-RegionOversetState Element::regionOversetState() const
-{
-    return hasRareData() ? elementRareData()->regionOversetState() : RegionUndefined;
-}
-
 AtomicString Element::computeInheritedLanguage() const
 {
     const Node* n = this;
@@ -2714,8 +2727,10 @@
 
 void Element::updatePseudoElement(PseudoId pseudoId, StyleRecalcChange change)
 {
+    ASSERT(!needsStyleRecalc());
     PseudoElement* element = pseudoElement(pseudoId);
-    if (element && (needsStyleRecalc() || shouldRecalcStyle(change, element))) {
+    if (element && (change == UpdatePseudoElements || element->shouldCallRecalcStyle(change))) {
+
         // Need to clear the cached style if the PseudoElement wants a recalc so it
         // computes a new style.
         if (element->needsStyleRecalc())
@@ -2724,7 +2739,7 @@
         // PseudoElement styles hang off their parent element's style so if we needed
         // a style recalc we should Force one on the pseudo.
         // FIXME: We should figure out the right text sibling to pass.
-        element->recalcStyle(needsStyleRecalc() ? Force : change);
+        element->recalcStyle(change == UpdatePseudoElements ? Force : change);
 
         // Wait until our parent is not displayed or pseudoElementRendererIsNeeded
         // is false, otherwise we could continously create and destroy PseudoElements
@@ -2732,32 +2747,20 @@
         // PseudoElement's renderer for each style recalc.
         if (!renderer() || !pseudoElementRendererIsNeeded(renderer()->getCachedPseudoStyle(pseudoId)))
             elementRareData()->setPseudoElement(pseudoId, 0);
-    } else if (change >= Inherit || needsStyleRecalc())
+    } else if (change >= UpdatePseudoElements) {
         createPseudoElementIfNeeded(pseudoId);
+    }
 }
 
 void Element::createPseudoElementIfNeeded(PseudoId pseudoId)
 {
-    if (needsPseudoElement(pseudoId))
-        createPseudoElement(pseudoId);
-}
+    if (isPseudoElement())
+        return;
 
-bool Element::needsPseudoElement(PseudoId pseudoId) const
-{
-    if (pseudoId == BACKDROP && !isInTopLayer())
-        return false;
-    if (!renderer() || !pseudoElementRendererIsNeeded(renderer()->getCachedPseudoStyle(pseudoId)))
-        return false;
-    if (!renderer()->canHaveGeneratedChildren())
-        return false;
-    return true;
-}
+    RefPtr<PseudoElement> element = document().ensureStyleResolver().createPseudoElementIfNeeded(*this, pseudoId);
+    if (!element)
+        return;
 
-void Element::createPseudoElement(PseudoId pseudoId)
-{
-    ASSERT(needsPseudoElement(pseudoId));
-    ASSERT(!isPseudoElement());
-    RefPtr<PseudoElement> element = PseudoElement::create(this, pseudoId);
     if (pseudoId == BACKDROP)
         document().addToTopLayer(element.get(), this);
     element->insertedInto(this);
@@ -2780,14 +2783,9 @@
     return 0;
 }
 
-bool Element::webkitMatchesSelector(const String& selector, ExceptionState& exceptionState)
+bool Element::matches(const String& selectors, ExceptionState& exceptionState)
 {
-    if (selector.isEmpty()) {
-        exceptionState.throwUninformativeAndGenericDOMException(SyntaxError);
-        return false;
-    }
-
-    SelectorQuery* selectorQuery = document().selectorQueryCache().add(selector, document(), exceptionState);
+    SelectorQuery* selectorQuery = document().selectorQueryCache().add(AtomicString(selectors), document(), exceptionState);
     if (!selectorQuery)
         return false;
     return selectorQuery->matches(*this);
@@ -2851,6 +2849,11 @@
 
 void Element::setUnsignedIntegralAttribute(const QualifiedName& attributeName, unsigned value)
 {
+    // Range restrictions are enforced for unsigned IDL attributes that
+    // reflect content attributes,
+    //   http://www.whatwg.org/specs/web-apps/current-work/multipage/common-dom-interfaces.html#reflecting-content-attributes-in-idl-attributes
+    if (value > 0x7fffffffu)
+        value = 0;
     setAttribute(attributeName, AtomicString::number(value));
 }
 
@@ -2864,15 +2867,6 @@
     setAttribute(attributeName, AtomicString::number(value));
 }
 
-bool Element::childShouldCreateRenderer(const Node& child) const
-{
-    // Only create renderers for SVG elements whose parents are SVG elements, or for proper <svg xmlns="svgNS"> subdocuments.
-    if (child.isSVGElement())
-        return child.hasTagName(SVGNames::svgTag) || isSVGElement();
-
-    return ContainerNode::childShouldCreateRenderer(child);
-}
-
 void Element::webkitRequestFullscreen()
 {
     FullscreenElementStack::from(&document())->requestFullScreenForElement(this, ALLOW_KEYBOARD_INPUT, FullscreenElementStack::EnforceIFrameAllowFullScreenRequirement);
@@ -2931,7 +2925,7 @@
 
 SpellcheckAttributeState Element::spellcheckAttributeState() const
 {
-    const AtomicString& value = getAttribute(HTMLNames::spellcheckAttr);
+    const AtomicString& value = fastGetAttribute(spellcheckAttr);
     if (value == nullAtom)
         return SpellcheckAttributeDefault;
     if (equalIgnoringCase(value, "true") || equalIgnoringCase(value, ""))
@@ -2958,79 +2952,6 @@
     return true;
 }
 
-RenderRegion* Element::renderRegion() const
-{
-    if (renderer() && renderer()->isRenderNamedFlowFragmentContainer())
-        return toRenderBlockFlow(renderer())->renderNamedFlowFragment();
-
-    return 0;
-}
-
-bool Element::shouldMoveToFlowThread(RenderStyle* styleToUse) const
-{
-    ASSERT(styleToUse);
-
-    if (FullscreenElementStack::isActiveFullScreenElement(this))
-        return false;
-
-    if (isInShadowTree())
-        return false;
-
-    if (styleToUse->flowThread().isEmpty())
-        return false;
-
-    return !isRegisteredWithNamedFlow();
-}
-
-const AtomicString& Element::webkitRegionOverset() const
-{
-    DEFINE_STATIC_LOCAL(AtomicString, undefinedState, ("undefined", AtomicString::ConstructFromLiteral));
-    if (!RuntimeEnabledFeatures::cssRegionsEnabled())
-        return undefinedState;
-
-    document().updateLayoutIgnorePendingStylesheets();
-
-    if (!renderRegion())
-        return undefinedState;
-
-    switch (renderRegion()->regionOversetState()) {
-    case RegionFit: {
-        DEFINE_STATIC_LOCAL(AtomicString, fitState, ("fit", AtomicString::ConstructFromLiteral));
-        return fitState;
-    }
-    case RegionEmpty: {
-        DEFINE_STATIC_LOCAL(AtomicString, emptyState, ("empty", AtomicString::ConstructFromLiteral));
-        return emptyState;
-    }
-    case RegionOverset: {
-        DEFINE_STATIC_LOCAL(AtomicString, overflowState, ("overset", AtomicString::ConstructFromLiteral));
-        return overflowState;
-    }
-    case RegionUndefined:
-        return undefinedState;
-    }
-
-    ASSERT_NOT_REACHED();
-    return undefinedState;
-}
-
-Vector<RefPtr<Range> > Element::webkitGetRegionFlowRanges() const
-{
-    Vector<RefPtr<Range> > rangeObjects;
-    if (!RuntimeEnabledFeatures::cssRegionsEnabled())
-        return rangeObjects;
-
-    document().updateLayoutIgnorePendingStylesheets();
-
-    if (renderer() && renderer()->isRenderNamedFlowFragmentContainer()) {
-        RenderNamedFlowFragment* region = toRenderBlockFlow(renderer())->renderNamedFlowFragment();
-        if (region->isValid())
-            region->getRanges(rangeObjects);
-    }
-
-    return rangeObjects;
-}
-
 #ifndef NDEBUG
 bool Element::fastAttributeLookupAllowed(const QualifiedName& name) const
 {
@@ -3038,7 +2959,7 @@
         return false;
 
     if (isSVGElement())
-        return !static_cast<const SVGElement*>(this)->isAnimatableAttribute(name);
+        return !toSVGElement(this)->isAnimatableAttribute(name);
 
     return true;
 }
@@ -3123,7 +3044,7 @@
 
     if (oldValue != newValue) {
         if (inActiveDocument() && hasSelectorForAttribute(&document(), name.localName()))
-           setNeedsStyleRecalc();
+            setNeedsStyleRecalc(SubtreeStyleChange);
 
         if (isUpgradedCustomElement())
             CustomElement::attributeDidChange(this, name.localName(), oldValue, newValue);
@@ -3200,18 +3121,17 @@
     if (HTMLCollection* collection = cachedHTMLCollection(type))
         return collection;
 
-    RefPtr<HTMLCollection> collection;
     if (type == TableRows) {
         ASSERT(hasTagName(tableTag));
-        return ensureRareData().ensureNodeLists().addCacheWithAtomicName<HTMLTableRowsCollection>(this, type);
+        return ensureRareData().ensureNodeLists().addCache<HTMLTableRowsCollection>(this, type);
     } else if (type == SelectOptions) {
         ASSERT(hasTagName(selectTag));
-        return ensureRareData().ensureNodeLists().addCacheWithAtomicName<HTMLOptionsCollection>(this, type);
+        return ensureRareData().ensureNodeLists().addCache<HTMLOptionsCollection>(this, type);
     } else if (type == FormControls) {
         ASSERT(hasTagName(formTag) || hasTagName(fieldsetTag));
-        return ensureRareData().ensureNodeLists().addCacheWithAtomicName<HTMLFormControlsCollection>(this, type);
+        return ensureRareData().ensureNodeLists().addCache<HTMLFormControlsCollection>(this, type);
     }
-    return ensureRareData().ensureNodeLists().addCacheWithAtomicName<HTMLCollection>(this, type);
+    return ensureRareData().ensureNodeLists().addCache<HTMLCollection>(this, type);
 }
 
 static void scheduleLayerUpdateCallback(Node* node)
@@ -3231,7 +3151,7 @@
 
 HTMLCollection* Element::cachedHTMLCollection(CollectionType type)
 {
-    return hasRareData() && rareData()->nodeLists() ? rareData()->nodeLists()->cacheWithAtomicName<HTMLCollection>(type) : 0;
+    return hasRareData() && rareData()->nodeLists() ? rareData()->nodeLists()->cached<HTMLCollection>(type) : 0;
 }
 
 IntSize Element::savedLayerScrollOffset() const
@@ -3343,12 +3263,10 @@
         ownerDocumentsHaveDifferentCaseSensitivity = other.document().inQuirksMode() != document().inQuirksMode();
 
     // If 'other' has a mutable ElementData, convert it to an immutable one so we can share it between both elements.
-    // We can only do this if there is no CSSOM wrapper for other's inline style, and there are no presentation attributes,
-    // and sharing the data won't result in different case sensitivity of class or id.
+    // We can only do this if there are no presentation attributes and sharing the data won't result in different case sensitivity of class or id.
     if (other.m_elementData->isUnique()
         && !ownerDocumentsHaveDifferentCaseSensitivity
-        && !other.m_elementData->presentationAttributeStyle()
-        && (!other.m_elementData->inlineStyle() || !other.m_elementData->inlineStyle()->hasCSSOMWrapper()))
+        && !other.m_elementData->presentationAttributeStyle())
         const_cast<Element&>(other).m_elementData = static_cast<const UniqueElementData*>(other.m_elementData.get())->makeShareableCopy();
 
     if (!other.m_elementData->isUnique() && !ownerDocumentsHaveDifferentCaseSensitivity)
@@ -3409,15 +3327,16 @@
     ASSERT(elementData());
     ASSERT(elementData()->m_styleAttributeIsDirty);
     elementData()->m_styleAttributeIsDirty = false;
-    if (const StylePropertySet* inlineStyle = this->inlineStyle())
-        const_cast<Element*>(this)->setSynchronizedLazyAttribute(styleAttr, inlineStyle->asText());
+    const StylePropertySet* inlineStyle = this->inlineStyle();
+    const_cast<Element*>(this)->setSynchronizedLazyAttribute(styleAttr,
+        inlineStyle ? AtomicString(inlineStyle->asText()) : nullAtom);
 }
 
 CSSStyleDeclaration* Element::style()
 {
     if (!isStyledElement())
         return 0;
-    return ensureMutableInlineStyle()->ensureInlineCSSStyleDeclaration(this);
+    return ensureElementRareData().ensureInlineCSSStyleDeclaration(this);
 }
 
 MutableStylePropertySet* Element::ensureMutableInlineStyle()
@@ -3433,13 +3352,11 @@
     return toMutableStylePropertySet(inlineStyle);
 }
 
-PropertySetCSSStyleDeclaration* Element::inlineStyleCSSOMWrapper()
+void Element::clearMutableInlineStyleIfEmpty()
 {
-    if (!inlineStyle() || !inlineStyle()->hasCSSOMWrapper())
-        return 0;
-    PropertySetCSSStyleDeclaration* cssomWrapper = ensureMutableInlineStyle()->cssStyleDeclaration();
-    ASSERT(cssomWrapper && cssomWrapper->parentElement() == this);
-    return cssomWrapper;
+    if (ensureMutableInlineStyle()->isEmpty()) {
+        ensureUniqueElementData()->m_inlineStyle.clear();
+    }
 }
 
 inline void Element::setInlineStyleFromString(const AtomicString& newStyleString)
@@ -3457,7 +3374,7 @@
         inlineStyle.clear();
 
     if (!inlineStyle) {
-        inlineStyle = CSSParser::parseInlineStyleDeclaration(newStyleString, this);
+        inlineStyle = BisonCSSParser::parseInlineStyleDeclaration(newStyleString, this);
     } else {
         ASSERT(inlineStyle->isMutable());
         static_pointer_cast<MutableStylePropertySet>(inlineStyle)->parseDeclaration(newStyleString, document().elementSheet()->contents());
@@ -3472,8 +3389,6 @@
         startLineNumber = document().scriptableDocumentParser()->lineNumber();
 
     if (newStyleString.isNull()) {
-        if (PropertySetCSSStyleDeclaration* cssomWrapper = inlineStyleCSSOMWrapper())
-            cssomWrapper->clearParentElement();
         ensureUniqueElementData()->m_inlineStyle.clear();
     } else if (modificationReason == ModifiedByCloning || document().contentSecurityPolicy()->allowInlineStyle(document().url(), startLineNumber)) {
         setInlineStyleFromString(newStyleString);
@@ -3541,19 +3456,12 @@
 void Element::removeAllInlineStyleProperties()
 {
     ASSERT(isStyledElement());
-    if (!inlineStyle() || inlineStyle()->isEmpty())
+    if (!inlineStyle())
         return;
     ensureMutableInlineStyle()->clear();
     inlineStyleChanged();
 }
 
-void Element::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const
-{
-    ASSERT(isStyledElement());
-    if (const StylePropertySet* inlineStyle = elementData() ? elementData()->inlineStyle() : 0)
-        inlineStyle->addSubresourceStyleURLs(urls, document().elementSheet()->contents());
-}
-
 void Element::updatePresentationAttributeStyle()
 {
     // ShareableElementData doesn't store presentation attribute style, so make sure we have a UniqueElementData.
@@ -3582,7 +3490,7 @@
 
 bool Element::supportsStyleSharing() const
 {
-    if (!isStyledElement() || !parentElement())
+    if (!isStyledElement() || !parentOrShadowHostElement())
         return false;
     // If the element has inline style it is probably unique.
     if (inlineStyle())
@@ -3600,7 +3508,7 @@
         return false;
     if (focused())
         return false;
-    if (!parentElement()->childrenSupportStyleSharing())
+    if (!parentOrShadowHostElement()->childrenSupportStyleSharing())
         return false;
     if (hasScopedHTMLStyleChild())
         return false;
@@ -3610,8 +3518,6 @@
         return false;
     if (hasActiveAnimations())
         return false;
-    if (shadow() && shadow()->containsActiveStyles())
-        return false;
     // Turn off style sharing for elements that can gain layers for reasons outside of the style system.
     // See comments in RenderObject::setStyle().
     // FIXME: Why does gaining a layer from outside the style system require disabling sharing?