Bug 1101128 part 2: Make nsDisplayImage::GetOpaqueRegion() take object-fit & object-position into account. r=seth
authorDaniel Holbert <dholbert@cs.stanford.edu>
Wed, 19 Nov 2014 18:34:52 -0800
changeset 240892 5cb767f5730d8307e339af71906696a4b5a1845e
parent 240891 67e4a03c17f0d6be9a74d5c350e33aad0755c44f
child 240893 09f275f4fc016e4268462a05da8b6b5676964a7c
push id4311
push userraliiev@mozilla.com
push dateMon, 12 Jan 2015 19:37:41 +0000
treeherdermozilla-beta@150c9fed433b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersseth
bugs1101128
milestone36.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1101128 part 2: Make nsDisplayImage::GetOpaqueRegion() take object-fit & object-position into account. r=seth
layout/generic/nsImageFrame.cpp
layout/reftests/image/image-object-fit-with-background-1-ref.html
layout/reftests/image/image-object-fit-with-background-1.html
layout/reftests/image/image-object-fit-with-background-2-ref.html
layout/reftests/image/image-object-fit-with-background-2.html
layout/reftests/image/image-object-position-with-background-1-ref.html
layout/reftests/image/image-object-position-with-background-1.html
layout/reftests/image/image-object-position-with-background-2-ref.html
layout/reftests/image/image-object-position-with-background-2.html
layout/reftests/image/reftest.list
--- a/layout/generic/nsImageFrame.cpp
+++ b/layout/generic/nsImageFrame.cpp
@@ -1451,17 +1451,36 @@ nsDisplayImage::GetLayerState(nsDisplayL
 /* virtual */ nsRegion
 nsDisplayImage::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
                                 bool* aSnap)
 {
   *aSnap = true;
   bool animated;
   if (mImage && mImage->GetAnimated(&animated) == NS_OK && !animated &&
       mImage->FrameIsOpaque(imgIContainer::FRAME_CURRENT)) {
-    return nsRegion(GetBounds(aSnap));
+    // OK, the entire region painted by the image is opaque. But what is that
+    // region? It's the image's "dest rect" (the rect where a full copy of
+    // the image is mapped), clipped to the container's content box (which is
+    // what GetBounds() returns). So, we grab those rects and intersect them.
+    const nsRect frameContentBox = GetBounds(aSnap);
+
+    // Note: To get the "dest rect", we have to provide the "constraint rect"
+    // (which is the content-box, with the effects of fragmentation undone).
+    nsImageFrame* imageFrame = static_cast<nsImageFrame*>(mFrame);
+    nsRect constraintRect(frameContentBox.TopLeft(),
+                          imageFrame->mComputedSize);
+    constraintRect.y -= imageFrame->GetContinuationOffset();
+
+    const nsRect destRect =
+      nsLayoutUtils::ComputeObjectDestRect(constraintRect,
+                                           imageFrame->mIntrinsicSize,
+                                           imageFrame->mIntrinsicRatio,
+                                           imageFrame->StylePosition());
+
+    return nsRegion(destRect.Intersect(frameContentBox));
   }
   return nsRegion();
 }
 
 already_AddRefed<Layer>
 nsDisplayImage::BuildLayer(nsDisplayListBuilder* aBuilder,
                            LayerManager* aManager,
                            const ContainerLayerParameters& aParameters)
new file mode 100644
--- /dev/null
+++ b/layout/reftests/image/image-object-fit-with-background-1-ref.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+  <head>
+    <meta charset="utf-8">
+    <style type="text/css">
+      .test {
+        background: salmon;
+        padding: 4px;
+        width: 32px;
+        height: 32px;
+        display: block;
+        margin-bottom: 2px;
+      }
+    </style>
+  </head>
+  <body>
+    <img    class="test"    src="blue-32x32.png">
+    <embed  class="test"    src="blue-32x32.png">
+    <object class="test"   data="blue-32x32.png"></object>
+    <video  class="test" poster="blue-32x32.png"></video>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/image/image-object-fit-with-background-1.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!--
+     This testcase ensures that we paint the background around an opaque image,
+     when the image is kept from filling the container via 'object-fit'. This
+     is an interesting case because, by default, images fill their container,
+     which means we can often optimize away the background completely. BUT, if
+     "object-fit" prevents the image from filling its container, we can't
+     optimize away the background; it need to be painted in the uncovered area.
+-->
+<html>
+  <head>
+    <meta charset="utf-8">
+    <style type="text/css">
+      .test {
+        background: salmon;
+        object-fit: none;
+        width: 40px;
+        height: 40px;
+        display: block;
+        margin-bottom: 2px;
+      }
+    </style>
+  </head>
+  <body>
+    <img    class="test"    src="blue-32x32.png">
+    <embed  class="test"    src="blue-32x32.png">
+    <object class="test"   data="blue-32x32.png"></object>
+    <video  class="test" poster="blue-32x32.png"></video>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/image/image-object-fit-with-background-2-ref.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html class="reftest-print">
+  <head>
+    <meta charset="utf-8">
+    <style type="text/css">
+      .fakeBackground {
+        background: salmon;
+        height: 3in;
+        width: 32px;
+      }
+
+      img.test {
+        width: 32px;
+        height: 32px;
+        display: block; /* Required for fragmentation */
+      }
+    </style>
+  </head>
+  <body>
+    <div class="fakeBackground"></div>
+    <img class="test" src="blue-32x32.png">
+    <div class="fakeBackground"></div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/image/image-object-fit-with-background-2.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!--
+     This testcase ensures that we paint the background around an opaque image,
+     when the image is kept from filling the container via 'object-fit' (and
+     the img element is fragmented). This is an interesting case because, by
+     default, images fill their container, which means we can often optimize
+     away the background completely. BUT, if "object-fit" prevents the image
+     from filling its container, we can't optimize away the background; it need
+     to be painted in the uncovered area.
+-->
+<html class="reftest-print">
+  <head>
+    <meta charset="utf-8">
+    <style type="text/css">
+      img.test {
+        background: salmon;
+        object-fit: none;
+        width: 32px;
+        /* We make the height 6in larger than the image's intrinsic height,
+         * which gives us the following happy results:
+         *  (1) the <img> will split over several 3in tall reftest-print cards
+         *      (so, we get to test fragmentation).
+         *  (2) the image pixels end up on the second fragment (not the first),
+         *      so we get to test image-data painting on later fragments.
+         *  (3) the reference case can easily match us using a simple img
+         *      with 3in-tall divs before & after it.
+         */
+        height: calc(32px + 6in);
+        display: block; /* Required for fragmentation */
+      }
+    </style>
+  </head>
+  <body>
+    <img class="test" src="blue-32x32.png">
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/image/image-object-position-with-background-1-ref.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+  <head>
+    <meta charset="utf-8">
+    <style type="text/css">
+      .test {
+        background: salmon;
+        padding-top: 5px;
+        padding-left: 5px;
+        width: 27px;
+        height: 27px;
+        display: block;
+        margin-bottom: 2px;
+      }
+    </style>
+  </head>
+  <body>
+    <img    class="test"    src="blue-32x32.png">
+    <embed  class="test"    src="blue-32x32.png">
+    <object class="test"   data="blue-32x32.png"></object>
+    <video  class="test" poster="blue-32x32.png"></video>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/image/image-object-position-with-background-1.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!--
+     This testcase ensures that we paint the background around an opaque image,
+     when the image is offset from the container via 'object-position'. This is
+     an interesting case because, by default, images fill their container,
+     which means we can often optimize away the background completely. BUT, if
+     "object-position" offsets the image from its container's content-box, we
+     can't optimize away the background; it need to be painted in the uncovered
+     area.
+-->
+<html>
+  <head>
+    <meta charset="utf-8">
+    <style type="text/css">
+      .test {
+        background: salmon;
+        object-position: 5px 5px;
+        width: 32px;
+        height: 32px;
+        display: block;
+        margin-bottom: 2px;
+      }
+    </style>
+  </head>
+  <body>
+    <img    class="test"    src="blue-32x32.png">
+    <embed  class="test"    src="blue-32x32.png">
+    <object class="test"   data="blue-32x32.png"></object>
+    <video  class="test" poster="blue-32x32.png"></video>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/image/image-object-position-with-background-2-ref.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html class="reftest-print">
+  <head>
+    <meta charset="utf-8">
+    <style type="text/css">
+      img.test {
+        background: salmon;
+        padding-left: 10px;
+        padding-top: 20px;
+        width: 22px;
+        height: calc(5in - 20px);
+        display: block; /* Required for fragmentation */
+      }
+    </style>
+  </head>
+  <body>
+    <img class="test" src="blue-32x32.png">
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/image/image-object-position-with-background-2.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!--
+     This testcase ensures that we paint the background around an opaque image,
+     when the image is offset from the container via 'object-position' (and
+     the img element is fragmented). This is an interesting case because, by
+     default, images fill their container, which means we can often optimize
+     away the background completely. BUT, if "object-position" offsets the
+     image from its container's content-box, we can't optimize away the
+     background; it need to be painted in the uncovered area.
+-->
+<html class="reftest-print">
+  <head>
+    <meta charset="utf-8">
+    <style type="text/css">
+      img.test {
+        background: salmon;
+        object-position: 10px 20px;
+        width: 32px;
+        height: 5in;
+        display: block; /* Required for fragmentation */
+      }
+    </style>
+  </head>
+  <body>
+    <img class="test" src="blue-32x32.png">
+  </body>
+</html>
--- a/layout/reftests/image/reftest.list
+++ b/layout/reftests/image/reftest.list
@@ -6,16 +6,22 @@ fuzzy-if(Android,8,30) == background-ima
 skip-if(B2G&&browserIsRemote) == image-zoom-1.html image-zoom-1-ref.html
 skip-if(B2G&&browserIsRemote) == image-zoom-2.html image-zoom-1-ref.html
 == invalid-url-image-1.html invalid-url-image-1-ref.html
 random-if(/^Windows\x20NT\x205\.1/.test(http.oscpu)) == sync-image-switch-1a.html sync-image-switch-1-ref.html # bug 855050 for WinXP
 random-if(/^Windows\x20NT\x205\.1/.test(http.oscpu)) == sync-image-switch-1b.html sync-image-switch-1-ref.html # bug 855050 for WinXP
 random-if(/^Windows\x20NT\x205\.1/.test(http.oscpu)) == sync-image-switch-1c.html sync-image-switch-1-ref.html # bug 855050 for WinXP
 random-if(/^Windows\x20NT\x205\.1/.test(http.oscpu)) == sync-image-switch-1d.html sync-image-switch-1-ref.html # bug 855050 for WinXP
 
+# Tests for "object-fit" & "object-position"
+test-pref(layout.css.object-fit-and-position.enabled,true) == image-object-fit-with-background-1.html image-object-fit-with-background-1-ref.html
+test-pref(layout.css.object-fit-and-position.enabled,true) == image-object-fit-with-background-2.html image-object-fit-with-background-2-ref.html
+test-pref(layout.css.object-fit-and-position.enabled,true) == image-object-position-with-background-1.html image-object-position-with-background-1-ref.html
+test-pref(layout.css.object-fit-and-position.enabled,true) == image-object-position-with-background-2.html image-object-position-with-background-2-ref.html
+
 # Tests for image-orientation used with 'from-image' (note that all
 # image-orientation tests are fuzzy because the JPEG images do not perfectly
 # reproduce blocks of solid color, even at maximum quality):
 fuzzy(2,5) == image-orientation-from-image.html?none     image-orientation-ref.html?0
 fuzzy(1,1) == image-orientation-from-image.html?0        image-orientation-ref.html?0
 fuzzy(1,1) == image-orientation-from-image.html?90       image-orientation-ref.html?90
 fuzzy(1,1) == image-orientation-from-image.html?180      image-orientation-ref.html?180
 fuzzy(1,1) == image-orientation-from-image.html?270      image-orientation-ref.html?270