Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / dom / Element.cpp
index c53453f..8eb9049 100644 (file)
@@ -30,6 +30,7 @@
 #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"
@@ -45,8 +46,9 @@
 #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/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"
@@ -166,7 +168,7 @@ static AttrNodeList& ensureAttrNodeListForElement(Element* element)
     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)
@@ -194,10 +196,6 @@ PassRefPtr<Element> Element::create(const QualifiedName& tagName, Document* docu
 
 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 (hasRareData())
@@ -262,9 +260,7 @@ bool Element::rendererIsFocusable() const
     // 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.
@@ -380,9 +376,6 @@ ActiveAnimations* Element::ensureActiveAnimations()
 
 bool Element::hasActiveAnimations() const
 {
-    if (!RuntimeEnabledFeatures::webAnimationsCSSEnabled())
-        return false;
-
     if (!hasRareData())
         return false;
 
@@ -744,6 +737,27 @@ void Element::setScrollLeft(int newLeft)
     }
 }
 
+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();
@@ -769,6 +783,27 @@ void Element::setScrollTop(int newTop)
     }
 }
 
+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();
@@ -1005,7 +1040,7 @@ void Element::attributeChanged(const QualifiedName& name, const AtomicString& ne
     shouldInvalidateStyle |= !styleResolver;
 
     if (shouldInvalidateStyle)
-        setNeedsStyleRecalc();
+        setNeedsStyleRecalc(SubtreeStyleChange);
 
     if (AXObjectCache* cache = document().existingAXObjectCache())
         cache->handleAttributeChanged(name, this);
@@ -1045,77 +1080,28 @@ static inline bool classStringHasClassName(const AtomicString& newClassString)
     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;
 
+    ASSERT(elementData());
     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)
@@ -1140,11 +1126,11 @@ bool Element::shouldInvalidateDistributionWhenAttributeChanged(ElementShadow* el
             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;
         }
     }
@@ -1193,8 +1179,8 @@ void Element::parserSetAttributes(const Vector<Attribute>& attributeVector)
     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);
 
@@ -1227,11 +1213,6 @@ String Element::nodeName() const
     return m_tagName.toString();
 }
 
-String Element::nodeNamePreservingCase() const
-{
-    return m_tagName.toString();
-}
-
 void Element::setPrefix(const AtomicString& prefix, ExceptionState& exceptionState)
 {
     UseCounter::count(document(), UseCounter::ElementSetPrefix);
@@ -1282,7 +1263,7 @@ const AtomicString& Element::locateNamespacePrefix(const AtomicString& namespace
 
 KURL Element::baseURI() const
 {
-    const AtomicString& baseAttribute = getAttribute(baseAttr);
+    const AtomicString& baseAttribute = fastGetAttribute(baseAttr);
     KURL base(KURL(), baseAttribute);
     if (!base.protocol().isEmpty())
         return base;
@@ -1444,7 +1425,7 @@ void Element::attach(const AttachContext& context)
                 document().updateFocusAppearanceSoon(false /* don't restore selection */);
             data->setNeedsFocusAppearanceUpdateSoonAfterAttach(false);
         }
-        if (RuntimeEnabledFeatures::webAnimationsCSSEnabled() && !renderer()) {
+        if (!renderer()) {
             if (ActiveAnimations* activeAnimations = data->activeAnimations()) {
                 activeAnimations->cssAnimations().cancel();
                 activeAnimations->setAnimationStyleChange(false);
@@ -1455,22 +1436,14 @@ void Element::attach(const AttachContext& context)
     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->clearPseudoElements();
-        data->setIsInsideRegion(false);
 
         // attach() will perform the below steps for us when inside recalcStyle.
         if (!document().inStyleRecalc()) {
@@ -1479,15 +1452,17 @@ void Element::detach(const AttachContext& context)
             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();
-                    activeAnimations->setAnimationStyleChange(false);
-                }
+        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);
             }
         }
 
@@ -1590,9 +1565,10 @@ void Element::recalcStyle(StyleRecalcChange change, Text* nextTextSibling)
     }
 
     // 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);
@@ -1630,7 +1606,7 @@ StyleRecalcChange Element::recalcOwnStyle(StyleRecalcChange change)
 
     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.
@@ -1643,60 +1619,64 @@ StyleRecalcChange Element::recalcOwnStyle(StyleRecalcChange change)
     if (styleChangeType() >= SubtreeStyleChange)
         return Force;
 
-    if (change <= Inherit)
-        return localChange;
+    if (change > Inherit || localChange > Inherit)
+        return max(localChange, change);
+
+    if (localChange < Inherit && (oldStyle->hasPseudoElementStyle() || newStyle->hasPseudoElementStyle()))
+        return UpdatePseudoElements;
 
-    return max(localChange, change);
+    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 (root->shouldCallRecalcStyle(change)) {
-            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 (shouldCallRecalcStyle(change))
-        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 (element->shouldCallRecalcStyle(change)) {
-                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 (shouldCallRecalcStyle(change)) {
-        updatePseudoElement(AFTER, change);
-        updatePseudoElement(BACKDROP, change);
-    }
+    updatePseudoElement(AFTER, change);
+    updatePseudoElement(BACKDROP, change);
 }
 
 void Element::checkForChildrenAdjacentRuleChanges()
@@ -1717,7 +1697,7 @@ void Element::checkForChildrenAdjacentRuleChanges()
         bool childRulesChanged = element->needsStyleRecalc() && element->styleChangeType() >= SubtreeStyleChange;
 
         if (forceCheckOfNextElementCount || forceCheckOfAnyElementSibling)
-            element->setNeedsStyleRecalc();
+            element->setNeedsStyleRecalc(SubtreeStyleChange);
 
         if (forceCheckOfNextElementCount)
             forceCheckOfNextElementCount--;
@@ -1762,7 +1742,7 @@ ElementShadow& Element::ensureShadow()
 
 void Element::didAffectSelector(AffectedSelectorMask mask)
 {
-    setNeedsStyleRecalc();
+    setNeedsStyleRecalc(SubtreeStyleChange);
     if (ElementShadow* elementShadow = shadowWhereNodeCanBeDistributed(*this))
         elementShadow->didAffectSelector(mask);
 }
@@ -1787,16 +1767,14 @@ PassRefPtr<ShadowRoot> Element::createShadowRoot(ExceptionState& exceptionState)
     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()) {
+    // 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));
 }
 
@@ -1857,7 +1835,7 @@ void Element::checkForEmptyStyleChange(RenderStyle* style)
         return;
 
     if (!style || (styleAffectedByEmpty() && (!style->emptyState() || hasChildNodes())))
-        setNeedsStyleRecalc();
+        setNeedsStyleRecalc(SubtreeStyleChange);
 }
 
 void Element::checkForSiblingStyleChanges(bool finishedParsingCallback, Node* beforeChange, Node* afterChange, int childCountDelta)
@@ -1881,7 +1859,7 @@ void Element::checkForSiblingStyleChanges(bool finishedParsingCallback, Node* be
     // 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;
     }
 
@@ -1890,47 +1868,47 @@ void Element::checkForSiblingStyleChanges(bool finishedParsingCallback, Node* be
     // |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);
     }
 }
 
@@ -1955,7 +1933,7 @@ void Element::removeAllEventListeners()
 
 void Element::finishParsingChildren()
 {
-    setIsParsingChildrenFinished(true);
+    setIsFinishedParsingChildren(true);
     checkForSiblingStyleChanges(this, lastChild(), 0, 0);
 }
 
@@ -2031,11 +2009,6 @@ PassRefPtr<Attr> Element::setAttributeNode(Attr* attrNode, ExceptionState& excep
     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) {
@@ -2181,7 +2154,7 @@ bool Element::hasAttributeNS(const AtomicString& namespaceURI, const AtomicStrin
     return elementData()->getAttributeItem(qName);
 }
 
-void Element::focus(bool restorePreviousSelection, FocusDirection direction)
+void Element::focus(bool restorePreviousSelection, FocusType type)
 {
     if (!inDocument())
         return;
@@ -2208,7 +2181,7 @@ void Element::focus(bool restorePreviousSelection, FocusDirection direction)
         // 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;
     }
 
@@ -2270,7 +2243,7 @@ bool Element::isMouseFocusable() const
     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()));
@@ -2396,6 +2369,24 @@ static Element* contextElementForInsertion(const String& where, Element* element
     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);
@@ -2687,29 +2678,6 @@ bool Element::isInCanvasSubtree() const
     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;
@@ -2760,8 +2728,10 @@ void Element::normalizeAttributes()
 
 void Element::updatePseudoElement(PseudoId pseudoId, StyleRecalcChange change)
 {
+    ASSERT(!needsStyleRecalc());
     PseudoElement* element = pseudoElement(pseudoId);
-    if (element && (needsStyleRecalc() || element->shouldCallRecalcStyle(change))) {
+    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())
@@ -2770,7 +2740,7 @@ void Element::updatePseudoElement(PseudoId pseudoId, StyleRecalcChange change)
         // 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
@@ -2778,8 +2748,9 @@ void Element::updatePseudoElement(PseudoId pseudoId, StyleRecalcChange change)
         // 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)
@@ -2955,7 +2926,7 @@ void Element::webkitRequestPointerLock()
 
 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, ""))
@@ -2982,63 +2953,6 @@ bool Element::isSpellCheckingEnabled() const
     return true;
 }
 
-RenderRegion* Element::renderRegion() const
-{
-    if (renderer() && renderer()->isRenderNamedFlowFragmentContainer())
-        return toRenderBlockFlow(renderer())->renderNamedFlowFragment();
-
-    return 0;
-}
-
-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
 {
@@ -3131,7 +3045,7 @@ void Element::willModifyAttribute(const QualifiedName& name, const AtomicString&
 
     if (oldValue != newValue) {
         if (inActiveDocument() && hasSelectorForAttribute(&document(), name.localName()))
-           setNeedsStyleRecalc();
+            setNeedsStyleRecalc(SubtreeStyleChange);
 
         if (isUpgradedCustomElement())
             CustomElement::attributeDidChange(this, name.localName(), oldValue, newValue);
@@ -3208,18 +3122,17 @@ PassRefPtr<HTMLCollection> Element::ensureCachedHTMLCollection(CollectionType ty
     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)
@@ -3239,7 +3152,7 @@ void Element::scheduleLayerUpdate()
 
 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