Merge from Chromium at DEPS revision 228962

This commit was generated by merge_to_master.py.

Change-Id: Ifa868e6d63fe87d2338d9388aa5ea81f746d485f
diff --git a/Source/core/dom/Element.cpp b/Source/core/dom/Element.cpp
index 7d79c45..8be89e5 100644
--- a/Source/core/dom/Element.cpp
+++ b/Source/core/dom/Element.cpp
@@ -44,17 +44,14 @@
 #include "core/css/resolver/StyleResolver.h"
 #include "core/dom/Attr.h"
 #include "core/dom/Attribute.h"
+#include "core/dom/CSSSelectorWatch.h"
 #include "core/dom/ClientRect.h"
 #include "core/dom/ClientRectList.h"
-#include "core/dom/CustomElement.h"
-#include "core/dom/CustomElementRegistrationContext.h"
 #include "core/dom/DatasetDOMStringMap.h"
 #include "core/dom/Document.h"
 #include "core/dom/DocumentSharedObjectPool.h"
 #include "core/dom/ElementRareData.h"
-#include "core/events/EventDispatcher.h"
 #include "core/dom/ExceptionCode.h"
-#include "core/events/FocusEvent.h"
 #include "core/dom/FullscreenElementStack.h"
 #include "core/dom/MutationObserverInterestGroup.h"
 #include "core/dom/MutationRecord.h"
@@ -66,11 +63,16 @@
 #include "core/dom/ScriptableDocumentParser.h"
 #include "core/dom/SelectorQuery.h"
 #include "core/dom/Text.h"
+#include "core/dom/WhitespaceChildList.h"
+#include "core/dom/custom/CustomElement.h"
+#include "core/dom/custom/CustomElementRegistrationContext.h"
 #include "core/dom/shadow/InsertionPoint.h"
 #include "core/dom/shadow/ShadowRoot.h"
 #include "core/editing/FrameSelection.h"
 #include "core/editing/TextIterator.h"
 #include "core/editing/htmlediting.h"
+#include "core/events/EventDispatcher.h"
+#include "core/events/FocusEvent.h"
 #include "core/html/ClassList.h"
 #include "core/html/HTMLCollection.h"
 #include "core/html/HTMLDocument.h"
@@ -81,10 +83,10 @@
 #include "core/html/HTMLOptionsCollection.h"
 #include "core/html/HTMLTableRowsCollection.h"
 #include "core/html/parser/HTMLParserIdioms.h"
-#include "core/page/ContentSecurityPolicy.h"
+#include "core/frame/ContentSecurityPolicy.h"
 #include "core/page/FocusController.h"
-#include "core/page/Frame.h"
-#include "core/page/FrameView.h"
+#include "core/frame/Frame.h"
+#include "core/frame/FrameView.h"
 #include "core/page/Page.h"
 #include "core/page/PointerLockController.h"
 #include "core/rendering/FlowThreadController.h"
@@ -589,7 +591,7 @@
     document().updateStyleForNodeIfNeeded(this);
 
     if (RenderBox* renderer = renderBox()) {
-        if (!renderer->requiresLayoutToDetermineWidth())
+        if (renderer->canDetermineWidthWithoutLayout())
             return adjustLayoutUnitForAbsoluteZoom(renderer->fixedOffsetWidth(), renderer).round();
     }
 
@@ -685,6 +687,17 @@
 int Element::scrollLeft()
 {
     document().updateLayoutIgnorePendingStylesheets();
+
+    if (document().documentElement() == this) {
+        if (document().inQuirksMode())
+            return 0;
+
+        if (FrameView* view = document().view()) {
+            if (RenderView* renderView = document().renderView())
+                return adjustForAbsoluteZoom(view->scrollX(), renderView);
+        }
+    }
+
     if (RenderBox* rend = renderBox())
         return adjustForAbsoluteZoom(rend->scrollLeft(), rend);
     return 0;
@@ -693,6 +706,17 @@
 int Element::scrollTop()
 {
     document().updateLayoutIgnorePendingStylesheets();
+
+    if (document().documentElement() == this) {
+        if (document().inQuirksMode())
+            return 0;
+
+        if (FrameView* view = document().view()) {
+            if (RenderView* renderView = document().renderView())
+                return adjustForAbsoluteZoom(view->scrollY(), renderView);
+        }
+    }
+
     if (RenderBox* rend = renderBox())
         return adjustForAbsoluteZoom(rend->scrollTop(), rend);
     return 0;
@@ -701,6 +725,27 @@
 void Element::setScrollLeft(int newLeft)
 {
     document().updateLayoutIgnorePendingStylesheets();
+
+    if (document().documentElement() == this) {
+        if (document().inQuirksMode())
+            return;
+
+        Frame* frame = document().frame();
+        if (!frame)
+            return;
+        FrameView* view = frame->view();
+        if (!view)
+            return;
+
+        // WHATWG spec says [1]: "If the element is the root element invoke scroll()
+        // with x as first argument and zero as second". Blink intentionally matches
+        // other engine's behaviors here, instead, where the 'y' scroll position is
+        // preversed. See [2].
+        // [1] http://dev.w3.org/csswg/cssom-view/#dom-element-scrollleft
+        // [2] https://www.w3.org/Bugs/Public/show_bug.cgi?id=23448
+        view->setScrollPosition(IntPoint(static_cast<int>(newLeft * frame->pageZoomFactor()), view->scrollY()));
+    }
+
     if (RenderBox* rend = renderBox())
         rend->setScrollLeft(static_cast<int>(newLeft * rend->style()->effectiveZoom()));
 }
@@ -708,6 +753,27 @@
 void Element::setScrollTop(int newTop)
 {
     document().updateLayoutIgnorePendingStylesheets();
+
+    if (document().documentElement() == this) {
+        if (document().inQuirksMode())
+            return;
+
+        Frame* frame = document().frame();
+        if (!frame)
+            return;
+        FrameView* view = frame->view();
+        if (!view)
+            return;
+
+        // WHATWG spec says [1]: "If the element is the root element invoke scroll()
+        // with zero as first argument and y as second". Blink intentionally
+        // matches other engine's behaviors here, instead, where the 'x' scroll
+        // position is preversed. See [2].
+        // [1] http://dev.w3.org/csswg/cssom-view/#dom-element-scrolltop
+        // [2] https://www.w3.org/Bugs/Public/show_bug.cgi?id=23448
+        view->setScrollPosition(IntPoint(view->scrollX(), static_cast<int>(newTop * frame->pageZoomFactor())));
+    }
+
     if (RenderBox* rend = renderBox())
         rend->setScrollTop(static_cast<int>(newTop * rend->style()->effectiveZoom()));
 }
@@ -917,7 +983,7 @@
     document().incDOMTreeVersion();
 
     StyleResolver* styleResolver = document().styleResolverIfExists();
-    bool testShouldInvalidateStyle = attached() && styleResolver && styleChangeType() < SubtreeStyleChange;
+    bool testShouldInvalidateStyle = confusingAndOftenMisusedAttached() && styleResolver && styleChangeType() < SubtreeStyleChange;
     bool shouldInvalidateStyle = false;
 
     if (isStyledElement() && name == styleAttr) {
@@ -1032,7 +1098,7 @@
 void Element::classAttributeChanged(const AtomicString& newClassString)
 {
     StyleResolver* styleResolver = document().styleResolverIfExists();
-    bool testShouldInvalidateStyle = attached() && styleResolver && styleChangeType() < SubtreeStyleChange;
+    bool testShouldInvalidateStyle = confusingAndOftenMisusedAttached() && styleResolver && styleChangeType() < SubtreeStyleChange;
     bool shouldInvalidateStyle = false;
 
     if (classStringHasClassName(newClassString)) {
@@ -1238,7 +1304,7 @@
         CustomElement::didEnterDocument(this, document());
 
     TreeScope& scope = insertionPoint->treeScope();
-    if (&scope != &treeScope())
+    if (scope != treeScope())
         return InsertionDone;
 
     const AtomicString& idValue = getIdAttribute();
@@ -1282,7 +1348,7 @@
 
     setSavedLayerScrollOffset(IntSize());
 
-    if (insertionPoint->isInTreeScope() && &treeScope() == &document()) {
+    if (insertionPoint->isInTreeScope() && treeScope() == document()) {
         const AtomicString& idValue = getIdAttribute();
         if (!idValue.isNull())
             updateId(insertionPoint->treeScope(), idValue, nullAtom);
@@ -1319,7 +1385,7 @@
 
     // We've already been through detach when doing a lazyAttach, but we might
     // need to clear any state that's been added since then.
-    if (hasRareData() && styleChangeType() == LazyAttachStyleChange) {
+    if (hasRareData() && styleChangeType() == NeedsReattachStyleChange) {
         ElementRareData* data = elementRareData();
         data->clearComputedStyle();
         data->resetDynamicRestyleObservations();
@@ -1329,6 +1395,9 @@
 
     NodeRenderingContext(this, context.resolvedStyle).createRendererForElementIfNeeded();
 
+    if (RenderStyle* style = renderStyle())
+        updateCallbackSelectors(0, style);
+
     createPseudoElementIfNeeded(BEFORE);
 
     // When a shadow root exists, it does the work of attaching the children.
@@ -1363,9 +1432,13 @@
 
 void Element::detach(const AttachContext& context)
 {
-    WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates;
+    RenderWidget::UpdateSuspendScope suspendWidgetHierarchyUpdates;
     unregisterNamedFlowContentNode();
     cancelFocusAppearanceUpdate();
+    if (RenderStyle* style = renderStyle()) {
+        if (!style->callbackSelectors().isEmpty())
+            updateCallbackSelectors(style, 0);
+    }
     if (hasRareData()) {
         ElementRareData* data = elementRareData();
         data->setPseudoElement(BEFORE, 0);
@@ -1446,18 +1519,21 @@
 {
     ASSERT(document().inStyleRecalc());
 
-    if (hasCustomStyleCallbacks())
-        willRecalcStyle(change);
-
     if (hasRareData() && (change > NoChange || needsStyleRecalc())) {
         ElementRareData* data = elementRareData();
         data->resetStyleState();
         data->clearComputedStyle();
     }
 
-    // Active InsertionPoints have no renderers so they never need to go through a recalc.
-    if ((change >= Inherit || needsStyleRecalc()) && parentRenderStyle() && !isActiveInsertionPoint(this))
-        change = recalcOwnStyle(change);
+    if ((change >= Inherit || needsStyleRecalc()) && parentRenderStyle()) {
+        if (hasCustomStyleCallbacks())
+            willRecalcStyle(change);
+        // Active InsertionPoints have no renderers so they never need to go through a recalc.
+        if (!isActiveInsertionPoint(this))
+            change = recalcOwnStyle(change);
+        if (hasCustomStyleCallbacks())
+            didRecalcStyle(change);
+    }
 
     // If we reattached we don't need to recalc the style of our descendants anymore.
     if (change < Reattach)
@@ -1466,12 +1542,21 @@
     clearNeedsStyleRecalc();
     clearChildNeedsStyleRecalc();
 
-    if (hasCustomStyleCallbacks())
-        didRecalcStyle(change);
-
     return change == Reattach;
 }
 
+static bool callbackSelectorsDiffer(RenderStyle* style1, RenderStyle* style2)
+{
+    const Vector<String> emptyVector;
+    const Vector<String>& callbackSelectors1 = style1 ? style1->callbackSelectors() : emptyVector;
+    const Vector<String>& callbackSelectors2 = style2 ? style2->callbackSelectors() : emptyVector;
+    if (callbackSelectors1.isEmpty() && callbackSelectors2.isEmpty()) {
+        // Help the inliner with this common case.
+        return false;
+    }
+    return callbackSelectors1 != callbackSelectors2;
+}
+
 StyleRecalcChange Element::recalcOwnStyle(StyleRecalcChange change)
 {
     ASSERT(document().inStyleRecalc());
@@ -1490,6 +1575,9 @@
 
     InspectorInstrumentation::didRecalculateStyleForElement(this);
 
+    if (localChange != NoChange && callbackSelectorsDiffer(oldStyle.get(), newStyle.get()))
+        updateCallbackSelectors(oldStyle.get(), newStyle.get());
+
     if (RenderObject* renderer = this->renderer()) {
         if (localChange != NoChange || pseudoStyleCacheIsInvalid(oldStyle.get(), newStyle.get()) || (change == Force && renderer->requiresForcedStyleRecalcPropagation()) || shouldNotifyRendererWithIdenticalStyles()) {
             renderer->setAnimatableStyle(newStyle.get());
@@ -1537,40 +1625,47 @@
     bool hasIndirectAdjacentRules = childrenAffectedByForwardPositionalRules();
     bool forceCheckOfNextElementSibling = false;
     bool forceCheckOfAnyElementSibling = false;
-    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()) {
+    if (hasDirectAdjacentRules || hasIndirectAdjacentRules) {
+        for (Node* child = firstChild(); child; child = child->nextSibling()) {
+            if (!child->isElementNode())
+                continue;
             Element* element = toElement(child);
-
             bool childRulesChanged = element->needsStyleRecalc() && element->styleChangeType() >= SubtreeStyleChange;
-
             if (forceCheckOfNextElementSibling || forceCheckOfAnyElementSibling)
                 element->setNeedsStyleRecalc();
-
             forceCheckOfNextElementSibling = childRulesChanged && hasDirectAdjacentRules;
             forceCheckOfAnyElementSibling = forceCheckOfAnyElementSibling || (childRulesChanged && hasIndirectAdjacentRules);
-
+        }
+    }
+    // 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.
+    // Reversing this loop can lead to non-deterministic results in our code to optimize out empty whitespace
+    // RenderTexts. We try to put off recalcing their style until the end to avoid this issue.
+    // See crbug.com/288225
+    WhitespaceChildList whitespaceChildList(change);
+    for (Node* child = lastChild(); child; child = child->previousSibling()) {
+        if (child->isTextNode()) {
+            Text* textChild = toText(child);
+            // FIXME: This check is expensive and may negate the performance gained by the optimization of
+            // avoiding whitespace renderers.
+            if (textChild->containsOnlyWhitespace())
+                whitespaceChildList.append(textChild);
+            else
+                textChild->recalcTextStyle(change);
+        } else if (child->isElementNode()) {
+            Element* element = toElement(child);
             if (shouldRecalcStyle(change, element)) {
                 parentPusher.push();
-                didReattach = element->recalcStyle(change);
+                element->recalcStyle(change);
             } else if (document().styleResolver()->supportsStyleSharing(element)) {
                 document().styleResolver()->addToStyleSharingList(element);
             }
         }
-
-        forceReattachOfAnyWhitespaceSibling = didReattach || forceReattachOfAnyWhitespaceSibling;
     }
 
+    whitespaceChildList.recalcStyle();
+
     if (shouldRecalcStyle(change, this)) {
         updatePseudoElement(AFTER, change);
         updatePseudoElement(BACKDROP, change);
@@ -1675,7 +1770,7 @@
 static void checkForSiblingStyleChanges(Element* e, RenderStyle* style, bool finishedParsingCallback,
                                         Node* beforeChange, Node* afterChange, int childCountDelta)
 {
-    if (!e->attached() || e->document().hasPendingForcedStyleRecalc() || e->styleChangeType() >= SubtreeStyleChange)
+    if (!e->confusingAndOftenMisusedAttached() || e->document().hasPendingForcedStyleRecalc() || e->styleChangeType() >= SubtreeStyleChange)
         return;
 
     // :empty selector.
@@ -1740,7 +1835,7 @@
     // 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 (e->childrenAffectedByDirectAdjacentRules() && afterChange) {
-        if (Node* firstElementAfterInsertion = afterChange->nextElementSibling())
+        if (Node* firstElementAfterInsertion = afterChange->isElementNode() ? afterChange : afterChange->nextElementSibling())
             firstElementAfterInsertion->setNeedsStyleRecalc();
     }
 }
@@ -1865,7 +1960,7 @@
         return 0;
     }
 
-    ASSERT(&document() == &attr->document());
+    ASSERT(document() == attr->document());
 
     synchronizeAttribute(attr->qualifiedName());
 
@@ -2055,11 +2150,8 @@
 
         // FIXME: We should restore the previous selection if there is one.
         VisibleSelection newSelection = VisibleSelection(firstPositionInOrBeforeNode(this), DOWNSTREAM);
-
-        if (frame->selection().shouldChangeSelection(newSelection)) {
-            frame->selection().setSelection(newSelection);
-            frame->selection().revealSelection();
-        }
+        frame->selection().setSelection(newSelection);
+        frame->selection().revealSelection();
     } else if (renderer() && !renderer()->isWidget())
         renderer()->scrollRectToVisible(boundingBox());
 }
@@ -2093,27 +2185,27 @@
 
 void Element::dispatchFocusEvent(Element* oldFocusedElement, FocusDirection)
 {
-    RefPtr<FocusEvent> event = FocusEvent::create(eventNames().focusEvent, false, false, document().defaultView(), 0, oldFocusedElement);
+    RefPtr<FocusEvent> event = FocusEvent::create(EventTypeNames::focus, false, false, document().defaultView(), 0, oldFocusedElement);
     EventDispatcher::dispatchEvent(this, FocusEventDispatchMediator::create(event.release()));
 }
 
 void Element::dispatchBlurEvent(Element* newFocusedElement)
 {
-    RefPtr<FocusEvent> event = FocusEvent::create(eventNames().blurEvent, false, false, document().defaultView(), 0, newFocusedElement);
+    RefPtr<FocusEvent> event = FocusEvent::create(EventTypeNames::blur, false, false, document().defaultView(), 0, newFocusedElement);
     EventDispatcher::dispatchEvent(this, BlurEventDispatchMediator::create(event.release()));
 }
 
 void Element::dispatchFocusInEvent(const AtomicString& eventType, Element* oldFocusedElement)
 {
     ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden());
-    ASSERT(eventType == eventNames().focusinEvent || eventType == eventNames().DOMFocusInEvent);
+    ASSERT(eventType == EventTypeNames::focusin || eventType == EventTypeNames::DOMFocusIn);
     dispatchScopedEventDispatchMediator(FocusInEventDispatchMediator::create(FocusEvent::create(eventType, true, false, document().defaultView(), 0, oldFocusedElement)));
 }
 
 void Element::dispatchFocusOutEvent(const AtomicString& eventType, Element* newFocusedElement)
 {
     ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden());
-    ASSERT(eventType == eventNames().focusoutEvent || eventType == eventNames().DOMFocusOutEvent);
+    ASSERT(eventType == EventTypeNames::focusout || eventType == EventTypeNames::DOMFocusOut);
     dispatchScopedEventDispatchMediator(FocusOutEventDispatchMediator::create(FocusEvent::create(eventType, true, false, document().defaultView(), 0, newFocusedElement)));
 }
 
@@ -2222,7 +2314,7 @@
             return usedStyle;
     }
 
-    if (!attached())
+    if (!confusingAndOftenMisusedAttached())
         // FIXME: Try to do better than this. Ensure that styleForElement() works for elements that are not in the
         // document tree and figure out when to destroy the computed style for such elements.
         return 0;
@@ -2434,6 +2526,15 @@
         document().cancelFocusAppearanceUpdate();
 }
 
+void Element::updateCallbackSelectors(RenderStyle* oldStyle, RenderStyle* newStyle)
+{
+    const Vector<String> emptyVector;
+    const Vector<String>& oldCallbackSelectors = oldStyle ? oldStyle->callbackSelectors() : emptyVector;
+    const Vector<String>& newCallbackSelectors = newStyle ? newStyle->callbackSelectors() : emptyVector;
+
+    CSSSelectorWatch::from(document()).updateSelectorMatches(oldCallbackSelectors, newCallbackSelectors);
+}
+
 void Element::normalizeAttributes()
 {
     if (!hasAttributes())
@@ -2831,7 +2932,7 @@
     }
 
     if (oldValue != newValue) {
-        if (attached() && hasSelectorForAttribute(&document(), name.localName()))
+        if (confusingAndOftenMisusedAttached() && hasSelectorForAttribute(&document(), name.localName()))
            setNeedsStyleRecalc();
 
         if (isUpgradedCustomElement())
@@ -2865,14 +2966,14 @@
     dispatchSubtreeModifiedEvent();
 }
 
-void Element::didMoveToNewDocument(Document* oldDocument)
+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 (oldDocument.inQuirksMode() != document().inQuirksMode()) {
         if (hasID())
             setIdAttribute(getIdAttribute());
         if (hasClass())
@@ -3397,7 +3498,7 @@
         style = cacheIterator->value->value;
         presentationAttributeCacheCleaner().didHitPresentationAttributeCache();
     } else {
-        style = MutableStylePropertySet::create(isSVGElement() ? SVGAttributeMode : CSSQuirksMode);
+        style = MutableStylePropertySet::create(isSVGElement() ? SVGAttributeMode : CSSAttributeMode);
         unsigned size = attributeCount();
         for (unsigned i = 0; i < size; ++i) {
             const Attribute* attribute = attributeItem(i);
@@ -3443,7 +3544,7 @@
 void Element::addPropertyToPresentationAttributeStyle(MutableStylePropertySet* style, CSSPropertyID propertyID, const String& value)
 {
     ASSERT(isStyledElement());
-    style->setProperty(propertyID, value, false, document().elementSheet()->contents());
+    style->setProperty(propertyID, value, false);
 }
 
 void ElementData::deref()