Bug 1364338: Force a repaint when CSS 'outline-width' or 'outline-offset' change. r?heycam draft
authorDaniel Holbert <dholbert@cs.stanford.edu>
Fri, 12 May 2017 18:42:10 -0700
changeset 577183 45563f2e5d1c4c40ccfb10380e506add8c35af46
parent 576108 b3c7773fcef04e2c0b8fcd39323a9b899718fe84
child 628457 adab88eaa2217de132c002181a4090f1e8648959
push id58644
push userdholbert@mozilla.com
push dateSat, 13 May 2017 01:48:51 +0000
reviewersheycam
bugs1364338
milestone55.0a1
Bug 1364338: Force a repaint when CSS 'outline-width' or 'outline-offset' change. r?heycam Previously, when these properties changed, we'd only send change hints to recompute overflow areas & trigger DLBI. If the outline was always outside of the element's border box, this old strategy was generally OK, because the outline tweak would cause a change to the overflow areas' size, and that would invalidate the changed area via DLBI & trigger a repaint. However, for outlines that are *inside* of the element (via negative 'outline-offset'), these change hints were not sufficient, because tweaks to the outline width & offset will NOT affect the size of the element's overflow areas and will not trigger any DLBI invalidation. So in order to correctly handle these changes, we really need to request a repaint of the affected element, since some piece of the element may need to be repainted even if it's not changing in size. MozReview-Commit-ID: J4KGUHrJ09U
layout/reftests/outline/outline-dynamic-change-1-ref.html
layout/reftests/outline/outline-dynamic-change-1a.html
layout/reftests/outline/outline-dynamic-change-1b.html
layout/reftests/outline/reftest.list
layout/style/nsStyleStruct.cpp
new file mode 100644
--- /dev/null
+++ b/layout/reftests/outline/outline-dynamic-change-1-ref.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <style>
+    #tweakMe {
+      height: 100px;
+      width: 100px;
+      background: gray;
+      outline: solid 6px black;
+      outline-offset: -16px;
+    }
+  </style>
+</head>
+<body>
+  <div id="tweakMe"></div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/outline/outline-dynamic-change-1a.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+  <title>
+    Test that dynamic tweaks to 'outline-offset' are reflected in the rendering.
+  </title>
+  <style>
+    #tweakMe {
+      height: 100px;
+      width: 100px;
+      background: gray;
+      outline: solid 6px black;
+      outline-offset: -10px;
+    }
+  </style>
+  <script>
+window.addEventListener("MozReftestInvalidate", function() {
+  tweakMe.style.outlineOffset = "-16px";
+  document.documentElement.removeAttribute("class");
+});
+  </script>
+</head>
+<body>
+  <div id="tweakMe"></div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/outline/outline-dynamic-change-1b.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+  <title>
+    Test that dynamic tweaks to 'outline-width' are reflected in the rendering.
+  </title>
+  <style>
+    #tweakMe {
+      height: 100px;
+      width: 100px;
+      background: gray;
+      outline: solid 2px black;
+      outline-offset: -16px;
+    }
+  </style>
+  <script>
+window.addEventListener("MozReftestInvalidate", function() {
+  tweakMe.style.outlineWidth = "6px";
+  document.documentElement.removeAttribute("class");
+});
+  </script>
+</head>
+<body>
+  <div id="tweakMe"></div>
+</body>
+</html>
--- a/layout/reftests/outline/reftest.list
+++ b/layout/reftests/outline/reftest.list
@@ -1,12 +1,14 @@
 fuzzy(2,18) == outline-and-box-shadow.html outline-and-box-shadow-ref.html
 fails-if(webrender) == outline-and-3d-transform-1a.html outline-and-3d-transform-1-ref.html
 fails-if(webrender) == outline-and-3d-transform-1b.html outline-and-3d-transform-1-ref.html
 fuzzy-if(gtkWidget,136,120) fuzzy-if(Android,255,356) fuzzy-if(d2d,16,96) fuzzy-if(cocoaWidget,255,120) fuzzy-if(winWidget,255,216) fails-if(webrender) == outline-and-3d-transform-2.html outline-and-3d-transform-2-ref.html
+== outline-dynamic-change-1a.html outline-dynamic-change-1-ref.html
+== outline-dynamic-change-1b.html outline-dynamic-change-1-ref.html
 == outline-overflow-block-abspos.html outline-overflow-block-ref.html
 == outline-overflow-block-float.html outline-overflow-block-ref.html
 == outline-overflow-inlineblock-abspos.html outline-overflow-inlineblock-ref.html
 == outline-overflow-inlineblock-float.html outline-overflow-inlineblock-ref.html
 pref(layout.css.outline-style-auto.enabled,true) skip-if(!gtkWidget&&!winWidget&&!cocoaWidget) == outline-auto-001.html outline-auto-001-ref.html # only works on platforms that supports NS_THEME_FOCUS_OUTLINE
 pref(layout.css.outline-style-auto.enabled,false) == outline-auto-001.html outline-auto-001-solid-ref.html
 == outline-initial-1a.html outline-initial-1-ref.html
 == outline-initial-1b.html outline-initial-1-ref.html
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -567,17 +567,18 @@ nsStyleOutline::RecalcData()
 
 nsChangeHint
 nsStyleOutline::CalcDifference(const nsStyleOutline& aNewData) const
 {
   if (mActualOutlineWidth != aNewData.mActualOutlineWidth ||
       (mActualOutlineWidth > 0 &&
        mOutlineOffset != aNewData.mOutlineOffset)) {
     return nsChangeHint_UpdateOverflow |
-           nsChangeHint_SchedulePaint;
+           nsChangeHint_SchedulePaint |
+           nsChangeHint_RepaintFrame;
   }
 
   if (mOutlineStyle != aNewData.mOutlineStyle ||
       mOutlineColor != aNewData.mOutlineColor ||
       mOutlineRadius != aNewData.mOutlineRadius) {
     if (mActualOutlineWidth > 0) {
       return nsChangeHint_RepaintFrame;
     }