Merge from Chromium at DEPS revision r212014

This commit was generated by merge_to_master.py.

Change-Id: Ib07d03553a1e81485ac4ffc92b91e977c4875409
diff --git a/Source/core/dom/Element.cpp b/Source/core/dom/Element.cpp
index ab2f94d..ab7a395 100644
--- a/Source/core/dom/Element.cpp
+++ b/Source/core/dom/Element.cpp
@@ -42,7 +42,7 @@
 #include "core/dom/Attribute.h"
 #include "core/dom/ClientRect.h"
 #include "core/dom/ClientRectList.h"
-#include "core/dom/CustomElementRegistry.h"
+#include "core/dom/CustomElementRegistrationContext.h"
 #include "core/dom/DatasetDOMStringMap.h"
 #include "core/dom/Document.h"
 #include "core/dom/DocumentSharedObjectPool.h"
@@ -205,12 +205,12 @@
         ElementRareData* data = elementRareData();
         data->setPseudoElement(BEFORE, 0);
         data->setPseudoElement(AFTER, 0);
+        data->setPseudoElement(BACKDROP, 0);
         data->clearShadow();
     }
 
-    if (isCustomElement() && document() && document()->registry()) {
-        document()->registry()->customElementWasDestroyed(this);
-    }
+    if (isCustomElement() && document() && document()->registrationContext())
+        document()->registrationContext()->customElementIsBeingDestroyed(this);
 
     if (hasSyntheticAttrChildNodes())
         detachAllAttrNodesFromElement();
@@ -266,7 +266,7 @@
     }
 
     // FIXME: These asserts should be in Node::isFocusable, but there are some
-    // callsites like Document::setFocusedNode that would currently fail on
+    // callsites like Document::setFocusedElement that would currently fail on
     // them. See crbug.com/251163
     if (renderer()) {
         ASSERT(!renderer()->needsLayout());
@@ -823,7 +823,7 @@
 void Element::setAttribute(const AtomicString& localName, const AtomicString& value, ExceptionCode& ec)
 {
     if (!Document::isValidName(localName)) {
-        ec = INVALID_CHARACTER_ERR;
+        ec = InvalidCharacterError;
         return;
     }
 
@@ -907,14 +907,14 @@
     document()->incDOMTreeVersion();
 
     StyleResolver* styleResolver = document()->styleResolverIfExists();
-    bool testShouldInvalidateStyle = attached() && styleResolver && styleChangeType() < FullStyleChange;
+    bool testShouldInvalidateStyle = attached() && styleResolver && styleChangeType() < SubtreeStyleChange;
     bool shouldInvalidateStyle = false;
 
     if (isStyledElement() && name == styleAttr) {
         styleAttributeChanged(newValue, reason);
     } else if (isStyledElement() && isPresentationAttribute(name)) {
         elementData()->m_presentationAttributeStyleIsDirty = true;
-        setNeedsStyleRecalc(InlineStyleChange);
+        setNeedsStyleRecalc(LocalStyleChange);
     }
 
     if (isIdAttributeName(name)) {
@@ -946,9 +946,8 @@
 
 inline void Element::attributeChangedFromParserOrByCloning(const QualifiedName& name, const AtomicString& newValue, AttributeModificationReason reason)
 {
-    if (RuntimeEnabledFeatures::customDOMElementsEnabled() && name == isAttr) {
-        document()->ensureCustomElementRegistry()->didGiveTypeExtension(this, newValue);
-    }
+    if (name == isAttr)
+        document()->registrationContext()->didGiveTypeExtension(this, newValue);
     attributeChanged(name, newValue, reason);
 }
 
@@ -1023,7 +1022,7 @@
 void Element::classAttributeChanged(const AtomicString& newClassString)
 {
     StyleResolver* styleResolver = document()->styleResolverIfExists();
-    bool testShouldInvalidateStyle = attached() && styleResolver && styleChangeType() < FullStyleChange;
+    bool testShouldInvalidateStyle = attached() && styleResolver && styleChangeType() < SubtreeStyleChange;
     bool shouldInvalidateStyle = false;
 
     if (classStringHasClassName(newClassString)) {
@@ -1266,6 +1265,9 @@
     if (scope != treeScope())
         return InsertionDone;
 
+    if (isUpgradedCustomElement())
+        document()->registrationContext()->customElementDidEnterDocument(this);
+
     const AtomicString& idValue = getIdAttribute();
     if (!idValue.isNull())
         updateId(scope, nullAtom, idValue);
@@ -1292,7 +1294,10 @@
     if (Element* after = pseudoElement(AFTER))
         after->removedFrom(insertionPoint);
 
+    if (Element* backdrop = pseudoElement(BACKDROP))
+        backdrop->removedFrom(insertionPoint);
     document()->removeFromTopLayer(this);
+
     if (containsFullScreenElement())
         setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(false);
 
@@ -1318,8 +1323,13 @@
     }
 
     ContainerNode::removedFrom(insertionPoint);
-    if (wasInDocument && hasPendingResources())
-        document()->accessSVGExtensions()->removeElementFromPendingResources(this);
+    if (wasInDocument) {
+        if (hasPendingResources())
+            document()->accessSVGExtensions()->removeElementFromPendingResources(this);
+
+        if (isUpgradedCustomElement() && document()->registrationContext())
+            document()->registrationContext()->customElementDidLeaveDocument(this);
+    }
 }
 
 void Element::createRendererIfNeeded(const AttachContext& context)
@@ -1350,6 +1360,7 @@
     ContainerNode::attach(context);
 
     createPseudoElementIfNeeded(AFTER);
+    createPseudoElementIfNeeded(BACKDROP);
 
     if (hasRareData()) {
         ElementRareData* data = elementRareData();
@@ -1382,6 +1393,7 @@
         ElementRareData* data = elementRareData();
         data->setPseudoElement(BEFORE, 0);
         data->setPseudoElement(AFTER, 0);
+        data->setPseudoElement(BACKDROP, 0);
         data->setIsInCanvasSubtree(false);
         data->resetComputedStyle();
         data->resetDynamicRestyleObservations();
@@ -1445,7 +1457,7 @@
     return document()->styleResolver()->styleForElement(this);
 }
 
-void Element::recalcStyle(StyleChange change)
+bool Element::recalcStyle(StyleChange change)
 {
     ASSERT(document()->inStyleRecalc());
 
@@ -1487,13 +1499,13 @@
 
             if (hasCustomStyleCallbacks())
                 didRecalcStyle(change);
-            return;
+            return true;
         }
 
         InspectorInstrumentation::didRecalculateStyleForElement(this);
 
         if (RenderObject* renderer = this->renderer()) {
-            if (localChange != NoChange || pseudoStyleCacheIsInvalid(currentStyle.get(), newStyle.get()) || (change == Force && renderer->requiresForcedStyleRecalcPropagation()) || needsLayerUpdate())
+            if (localChange != NoChange || pseudoStyleCacheIsInvalid(currentStyle.get(), newStyle.get()) || (change == Force && renderer->requiresForcedStyleRecalcPropagation()) || shouldNotifyRendererWithIdenticalStyles())
                 renderer->setAnimatableStyle(newStyle.get());
             else if (needsStyleRecalc()) {
                 // Although no change occurred, we use the new style so that the cousin style sharing code won't get
@@ -1510,7 +1522,7 @@
             change = Force;
         }
 
-        if (styleChangeType() == FullStyleChange)
+        if (styleChangeType() == SubtreeStyleChange)
             change = Force;
         else if (change != Force)
             change = localChange;
@@ -1533,23 +1545,35 @@
     // without doing way too much re-resolution.
     bool forceCheckOfNextElementSibling = false;
     bool forceCheckOfAnyElementSibling = false;
-    for (Node *n = firstChild(); n; n = n->nextSibling()) {
-        if (n->isTextNode()) {
-            toText(n)->recalcTextStyle(change);
-            continue;
+    bool forceReattachOfAnyWhitespaceSibling = false;
+    for (Node* child = firstChild(); child; child = child->nextSibling()) {
+        bool didReattach = false;
+
+        if (child->renderer())
+            forceReattachOfAnyWhitespaceSibling = false;
+
+        if (child->isTextNode()) {
+            if (forceReattachOfAnyWhitespaceSibling && toText(child)->containsOnlyWhitespace())
+                child->reattach();
+            else
+                didReattach = toText(child)->recalcTextStyle(change);
+        } else if (child->isElementNode()) {
+            Element* element = toElement(child);
+
+            if (forceCheckOfNextElementSibling || forceCheckOfAnyElementSibling)
+                element->setNeedsStyleRecalc();
+
+            bool childRulesChanged = element->needsStyleRecalc() && element->styleChangeType() == SubtreeStyleChange;
+            forceCheckOfNextElementSibling = childRulesChanged && hasDirectAdjacentRules;
+            forceCheckOfAnyElementSibling = forceCheckOfAnyElementSibling || (childRulesChanged && hasIndirectAdjacentRules);
+
+            if (shouldRecalcStyle(change, element)) {
+                parentPusher.push();
+                didReattach = element->recalcStyle(change);
+            }
         }
-        if (!n->isElementNode())
-            continue;
-        Element* element = toElement(n);
-        bool childRulesChanged = element->needsStyleRecalc() && element->styleChangeType() == FullStyleChange;
-        if ((forceCheckOfNextElementSibling || forceCheckOfAnyElementSibling))
-            element->setNeedsStyleRecalc();
-        if (shouldRecalcStyle(change, element)) {
-            parentPusher.push();
-            element->recalcStyle(change);
-        }
-        forceCheckOfNextElementSibling = childRulesChanged && hasDirectAdjacentRules;
-        forceCheckOfAnyElementSibling = forceCheckOfAnyElementSibling || (childRulesChanged && hasIndirectAdjacentRules);
+
+        forceReattachOfAnyWhitespaceSibling = didReattach || forceReattachOfAnyWhitespaceSibling;
     }
 
     if (shouldRecalcStyle(change, this))
@@ -1560,6 +1584,7 @@
 
     if (hasCustomStyleCallbacks())
         didRecalcStyle(change);
+    return false;
 }
 
 ElementShadow* Element::shadow() const
@@ -1591,7 +1616,7 @@
     // subtrees won't work well in that element. Until they are fixed, we disable
     // adding author shadow root for them.
     if (!areAuthorShadowsAllowed()) {
-        ec = HIERARCHY_REQUEST_ERR;
+        ec = HierarchyRequestError;
         return 0;
     }
     return ensureShadow()->addShadowRoot(this, ShadowRoot::AuthorShadowRoot);
@@ -1810,7 +1835,7 @@
 PassRefPtr<Attr> Element::setAttributeNode(Attr* attrNode, ExceptionCode& ec)
 {
     if (!attrNode) {
-        ec = TYPE_MISMATCH_ERR;
+        ec = TypeMismatchError;
         return 0;
     }
 
@@ -1818,10 +1843,10 @@
     if (oldAttrNode.get() == attrNode)
         return attrNode; // This Attr is already attached to the element.
 
-    // INUSE_ATTRIBUTE_ERR: Raised if node is an Attr that is already an attribute of another Element object.
+    // 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()) {
-        ec = INUSE_ATTRIBUTE_ERR;
+        ec = InUseAttributeError;
         return 0;
     }
 
@@ -1853,11 +1878,11 @@
 PassRefPtr<Attr> Element::removeAttributeNode(Attr* attr, ExceptionCode& ec)
 {
     if (!attr) {
-        ec = TYPE_MISMATCH_ERR;
+        ec = TypeMismatchError;
         return 0;
     }
     if (attr->ownerElement() != this) {
-        ec = NOT_FOUND_ERR;
+        ec = NotFoundError;
         return 0;
     }
 
@@ -1867,7 +1892,7 @@
 
     size_t index = elementData()->getAttrIndex(attr);
     if (index == notFound) {
-        ec = NOT_FOUND_ERR;
+        ec = NotFoundError;
         return 0;
     }
 
@@ -1886,7 +1911,7 @@
     QualifiedName qName(prefix, localName, namespaceURI);
 
     if (!Document::hasValidNamespaceForAttributes(qName)) {
-        ec = NAMESPACE_ERR;
+        ec = NamespaceError;
         return false;
     }
 
@@ -2022,7 +2047,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()->setFocusedNode(this, doc->frame(), direction))
+        if (!page->focusController()->setFocusedElement(this, doc->frame(), direction))
             return;
     }
 
@@ -2063,12 +2088,12 @@
 void Element::blur()
 {
     cancelFocusAppearanceUpdate();
-    Document* doc = document();
-    if (treeScope()->focusedNode() == this) {
+    if (treeScope()->adjustedFocusedElement() == this) {
+        Document* doc = document();
         if (doc->frame())
-            doc->frame()->page()->focusController()->setFocusedNode(0, doc->frame());
+            doc->frame()->page()->focusController()->setFocusedElement(0, doc->frame());
         else
-            doc->setFocusedNode(0);
+            doc->setFocusedElement(0);
     }
 }
 
@@ -2327,11 +2352,6 @@
     return hasRareData() && elementRareData()->isInCanvasSubtree();
 }
 
-bool Element::isUnresolvedCustomElement()
-{
-    return isCustomElement() && document()->registry()->isUnresolved(this);
-}
-
 void Element::setIsInsideRegion(bool value)
 {
     if (value == isInsideRegion())
@@ -2423,7 +2443,10 @@
 
 void Element::createPseudoElementIfNeeded(PseudoId pseudoId)
 {
-    if (!document()->styleSheetCollection()->usesBeforeAfterRules())
+    if ((pseudoId == BEFORE || pseudoId == AFTER) && !document()->styleSheetCollection()->usesBeforeAfterRules())
+        return;
+
+    if (pseudoId == BACKDROP && !isInTopLayer())
         return;
 
     if (!renderer() || !pseudoElementRendererIsNeeded(renderer()->getCachedPseudoStyle(pseudoId)))
@@ -2434,7 +2457,10 @@
 
     ASSERT(!isPseudoElement());
     RefPtr<PseudoElement> element = PseudoElement::create(this, pseudoId);
+    if (pseudoId == BACKDROP)
+        document()->addToTopLayer(element.get(), this);
     element->attach();
+
     ensureElementRareData()->setPseudoElement(pseudoId, element.release());
 }
 
@@ -2463,7 +2489,7 @@
 bool Element::webkitMatchesSelector(const String& selector, ExceptionCode& ec)
 {
     if (selector.isEmpty()) {
-        ec = SYNTAX_ERR;
+        ec = SyntaxError;
         return false;
     }
 
@@ -2568,7 +2594,7 @@
 void Element::setContainsFullScreenElement(bool flag)
 {
     ensureElementRareData()->setContainsFullScreenElement(flag);
-    setNeedsStyleRecalc(SyntheticStyleChange);
+    setNeedsStyleRecalc(SubtreeStyleChange);
 }
 
 static Element* parentCrossingFrameBoundaries(Element* element)
@@ -2770,9 +2796,9 @@
         return;
 
     if (!oldForAttributeValue.isEmpty())
-        scope->removeLabel(oldForAttributeValue, static_cast<HTMLLabelElement*>(this));
+        scope->removeLabel(oldForAttributeValue, toHTMLLabelElement(this));
     if (!newForAttributeValue.isEmpty())
-        scope->addLabel(newForAttributeValue, static_cast<HTMLLabelElement*>(this));
+        scope->addLabel(newForAttributeValue, toHTMLLabelElement(this));
 }
 
 void Element::willModifyAttribute(const QualifiedName& name, const AtomicString& oldValue, const AtomicString& newValue)
@@ -2790,6 +2816,9 @@
     if (oldValue != newValue) {
         if (attached() && document()->styleResolver() && document()->styleResolver()->hasSelectorForAttribute(name.localName()))
            setNeedsStyleRecalc();
+
+        if (isUpgradedCustomElement())
+            document()->registrationContext()->customElementAttributeDidChange(this, name.localName(), oldValue, newValue);
     }
 
     if (OwnPtr<MutationObserverInterestGroup> recipients = MutationObserverInterestGroup::createForAttributesMutation(this, name))
@@ -2819,6 +2848,20 @@
     dispatchSubtreeModifiedEvent();
 }
 
+void Element::didMoveToNewDocument(Document* oldDocument)
+{
+    Node::didMoveToNewDocument(oldDocument);
+
+    // If the documents differ by quirks mode then they differ by case sensitivity
+    // for class and id names so we need to go through the attribute change logic
+    // to pick up the new casing in the ElementData.
+    if (oldDocument->inQuirksMode() != document()->inQuirksMode()) {
+        if (hasID())
+            setIdAttribute(getIdAttribute());
+        if (hasClass())
+            setAttribute(HTMLNames::classAttr, getClassAttribute());
+    }
+}
 
 void Element::updateNamedItemRegistration(const AtomicString& oldName, const AtomicString& newName)
 {
@@ -2865,7 +2908,9 @@
 
 static void scheduleLayerUpdateCallback(Node* node)
 {
-    node->setNeedsLayerUpdate();
+    // Notify the renderer even is the styles are identical since it may need to
+    // create or destroy a RenderLayer.
+    node->setNeedsStyleRecalc(LocalStyleChange, StyleChangeFromRenderer);
 }
 
 void Element::scheduleLayerUpdate()
@@ -2873,7 +2918,7 @@
     if (postAttachCallbacksAreSuspended())
         queuePostAttachCallback(scheduleLayerUpdateCallback, this);
     else
-        setNeedsLayerUpdate();
+        scheduleLayerUpdateCallback(this);
 }
 
 HTMLCollection* Element::cachedHTMLCollection(CollectionType type)
@@ -2983,14 +3028,22 @@
     if (!oldName.isNull() || !newName.isNull())
         updateName(oldName, newName);
 
+    // Quirks mode makes class and id not case sensitive. We can't share the ElementData
+    // if the idForStyleResolution and the className need different casing.
+    bool ownerDocumentsHaveDifferentCaseSensitivity = false;
+    if (other.hasClass() || other.hasID())
+        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.
+    // 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.
     if (other.m_elementData->isUnique()
+        && !ownerDocumentsHaveDifferentCaseSensitivity
         && !other.m_elementData->presentationAttributeStyle()
         && (!other.m_elementData->inlineStyle() || !other.m_elementData->inlineStyle()->hasCSSOMWrapper()))
         const_cast<Element&>(other).m_elementData = static_cast<const UniqueElementData*>(other.m_elementData.get())->makeShareableCopy();
 
-    if (!other.m_elementData->isUnique())
+    if (!other.m_elementData->isUnique() && !ownerDocumentsHaveDifferentCaseSensitivity)
         m_elementData = other.m_elementData;
     else
         m_elementData = other.m_elementData->makeUniqueCopy();
@@ -3196,14 +3249,14 @@
 
     elementData()->m_styleAttributeIsDirty = false;
 
-    setNeedsStyleRecalc(InlineStyleChange);
+    setNeedsStyleRecalc(LocalStyleChange);
     InspectorInstrumentation::didInvalidateStyleAttr(document(), this);
 }
 
 void Element::inlineStyleChanged()
 {
     ASSERT(isStyledElement());
-    setNeedsStyleRecalc(InlineStyleChange);
+    setNeedsStyleRecalc(LocalStyleChange);
     ASSERT(elementData());
     elementData()->m_styleAttributeIsDirty = true;
     InspectorInstrumentation::didInvalidateStyleAttr(document(), this);