Store new ComputedStyle object if style did not change.

The comparison of ComputedStyle does not take additional flags into
account. For instance, the AffectedBy* flags used for updating pseudo
classes like :hover. We used to call SetStyleInternal, but this was
removed because the previous comment said it was because of style
sharing which is now removed.

The display:contents case (768406) never worked because the code path
for StoreNonLayoutObjectComputedStyle() was always skipped when
computed style compared to be equal.

Bug: 768406, 767832
Change-Id: Iac4708e3cd3a6451d99c1bb2bb69efb74289b8eb
Reviewed-on: https://chromium-review.googlesource.com/681755
Reviewed-by: nainar <[email protected]>
Commit-Queue: Rune Lillesveen <[email protected]>
Cr-Commit-Position: refs/heads/master@{#504285}
diff --git a/third_party/WebKit/LayoutTests/fast/dynamic/hover-after-affected-by-change.html b/third_party/WebKit/LayoutTests/fast/dynamic/hover-after-affected-by-change.html
new file mode 100644
index 0000000..7269908a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/dynamic/hover-after-affected-by-change.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<style>
+  .affected:hover { color: green }
+  #hoveredContents { display: contents }
+</style>
+<div id="hovered">Hover me - should become green</div>
+<div id="hoveredContents">
+  <div id="hovered2">Hover me - should become green</div>
+</div>
+<script>
+  function mouseMoveTo(element) {
+    return new Promise((resolve, reject) => {
+      chrome.gpuBenchmarking.pointerActionSequence([{source: "mouse",
+          actions: [{ name: "pointerMove",
+              x: element.offsetLeft + 1,
+              y: element.offsetTop + 1 }]}],
+          resolve);
+    });
+  }
+
+  test(() => {
+    hovered.offsetTop;
+    hovered.className = "affected";
+    hoveredContents.className = "affected";
+  }, "Change selector matching causes different AffectedByHover flags.");
+
+  test(() => {
+    assert_exists(window, "chrome", "This test requires window.chrome.");
+    assert_exists(window.chrome, "gpuBenchmarking",
+        "This test requires chrome.gpuBenchmarking.");
+  }, "Preconditions.");
+
+  test(() => {
+    assert_equals(getComputedStyle(hovered).color, "rgb(0, 0, 0)");
+    mouseMoveTo(hovered).then(() => {
+      assert_equals(getComputedStyle(hovered).color, "rgb(0, 128, 0)");
+    });
+  }, "Check that :hover rule is applied.");
+
+  test(() => {
+    assert_equals(getComputedStyle(hoveredContents).color, "rgb(0, 0, 0)");
+    mouseMoveTo(hovered2).then(() => {
+      assert_equals(getComputedStyle(hoveredContents).color, "rgb(0, 128, 0)");
+    });
+  }, "Check that :hover rule is applied to display:contents element.");
+</script>
diff --git a/third_party/WebKit/Source/core/dom/Element.cpp b/third_party/WebKit/Source/core/dom/Element.cpp
index 876cdb5..3247b52 100644
--- a/third_party/WebKit/Source/core/dom/Element.cpp
+++ b/third_party/WebKit/Source/core/dom/Element.cpp
@@ -2148,15 +2148,21 @@
   if (local_change != kNoChange)
     UpdateCallbackSelectors(old_style.Get(), new_style.Get());
 
-  if (local_change != kNoChange) {
-    if (LayoutObject* layout_object = this->GetLayoutObject()) {
+  if (LayoutObject* layout_object = this->GetLayoutObject()) {
+    // kNoChange may means that the computed style didn't change, but there are
+    // additional flags in ComputedStyle which may have changed. For instance,
+    // the AffectedBy* flags. We don't need to go through the visual
+    // invalidation diffing in that case, but we replace the old ComputedStyle
+    // object with the new one to ensure the mentioned flags are up to date.
+    if (local_change == kNoChange)
+      layout_object->SetStyleInternal(new_style.Get());
+    else
       layout_object->SetStyle(new_style.Get());
-    } else {
-      if (ShouldStoreNonLayoutObjectComputedStyle(*new_style))
-        StoreNonLayoutObjectComputedStyle(new_style);
-      else if (HasRareData())
-        GetElementRareData()->ClearComputedStyle();
-    }
+  } else {
+    if (ShouldStoreNonLayoutObjectComputedStyle(*new_style))
+      StoreNonLayoutObjectComputedStyle(new_style);
+    else if (HasRareData())
+      GetElementRareData()->ClearComputedStyle();
   }
 
   if (GetStyleChangeType() >= kSubtreeStyleChange)