Allow direct compositing of background images
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 11 Apr 2013 05:47:44 +0000 (05:47 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 11 Apr 2013 05:47:44 +0000 (05:47 +0000)
https://bugs.webkit.org/show_bug.cgi?id=108203

Patch by No'am Rosenthal <noam@webkit.org> on 2013-04-10
Reviewed by Simon Fraser.

Source/WebCore:

Use setContentsToImage for background images, if the GraphicsLayer has only a background
bitmap image and nothing else. Compute the contentsRect/contentsTileRect from the box model.
Added new properties to GraphicsLayer, contentsTilePhase and contentsTileSize, which controls the "single tile rect",
which allows us to compute the pattern-space transform of a tile, thus allowing background-size
and other characteristics of background images.

This feature is explicitly disabled when there is any composition with a background color or if
there are several background images, as in that case having a single backing store has some
advantages over directly compositing in hardware.

Currently, this feature is disabled for all ports, allowing ports to implement their backend
and decide when to enable it.

Note that RenderBoxModelObject::getGeometryForBackgroundImage crops the contents rect to the
area that contains the tiles, which allows us to assume full tiling in GraphicsLayer.
In this way contentsTileSize/Phase is equivalent to GraphicsContext::drawTiledImage.

Tests: compositing/patterns/direct-pattern-compositing-add-text.html
       compositing/patterns/direct-pattern-compositing-change.html
       compositing/patterns/direct-pattern-compositing-contain.html
       compositing/patterns/direct-pattern-compositing-cover.html
       compositing/patterns/direct-pattern-compositing-load.html
       compositing/patterns/direct-pattern-compositing-padding.html
       compositing/patterns/direct-pattern-compositing-position.html
       compositing/patterns/direct-pattern-compositing-rotation.html
       compositing/patterns/direct-pattern-compositing-size.html
       compositing/patterns/direct-pattern-compositing.html

* platform/graphics/GraphicsLayer.h:
(GraphicsLayer):
(WebCore::GraphicsLayer::setContentsTileSize):
(WebCore::GraphicsLayer::setContentsTilePhase):
(WebCore::GraphicsLayer::contentsTileSize):
(WebCore::GraphicsLayer::contentsTilePhase):
(WebCore::GraphicsLayer::supportsContentsTiling):
        Add a contentsTileRect property that enables tile-repeat of background images.

* rendering/RenderBox.cpp:
(WebCore::RenderBox::imageChanged):
        Pass background image changes to the layer backing.

* rendering/RenderBoxModelObject.cpp:
* rendering/RenderBoxModelObject.h:
(WebCore::RenderBoxModelObject::getGeometryForBackgroundImage):
        Expose a function that performs the geometry calculations needed to determine
        the tileRect for a background image. This function is also responsible
        for cropping the contentsRect to fit the area that is drawn into.

* rendering/RenderLayerBacking.h:
* rendering/RenderLayerBacking.cpp:
(WebCore::RenderLayerBacking::contentChanged):
(WebCore::RenderLayerBacking::updateGraphicsLayerConfiguration):
(WebCore::RenderLayerBacking::updateGraphicsLayerGeometry):
(WebCore::RenderLayerBacking::updateDirectlyCompositedContents):
(WebCore::RenderLayerBacking::resetContentsRect):
(WebCore::hasBoxDecorationsOrBackgroundImage):
(WebCore::RenderLayerBacking::updateDirectlyCompositedBackgroundColor):
(WebCore::canCreateTiledImage):
(WebCore::RenderLayerBacking::updateDirectlyCompositedBackgroundImage):
(WebCore::backgroundRectForBox):
        Allow background images to be directly composited if conditions allow (see bug description).

LayoutTests:

Added several ref-tests as preparation for supporting direct compositing of background
images.

* compositing/patterns/direct-pattern-compositing-add-text-expected.html: Added.
* compositing/patterns/direct-pattern-compositing-add-text.html: Added.
* compositing/patterns/direct-pattern-compositing-change-expected.html: Added.
* compositing/patterns/direct-pattern-compositing-change.html: Added.
* compositing/patterns/direct-pattern-compositing-contain-expected.html: Added.
* compositing/patterns/direct-pattern-compositing-contain.html: Added.
* compositing/patterns/direct-pattern-compositing-cover-expected.html: Added.
* compositing/patterns/direct-pattern-compositing-cover.html: Added.
* compositing/patterns/direct-pattern-compositing-expected.html: Added.
* compositing/patterns/direct-pattern-compositing-load-expected.html: Added.
* compositing/patterns/direct-pattern-compositing-load.html: Added.
* compositing/patterns/direct-pattern-compositing-padding-expected.html: Added.
* compositing/patterns/direct-pattern-compositing-padding.html: Added.
* compositing/patterns/direct-pattern-compositing-position-expected.html: Added.
* compositing/patterns/direct-pattern-compositing-position.html: Added.
* compositing/patterns/direct-pattern-compositing-size-expected.html: Added.
* compositing/patterns/direct-pattern-compositing-size.html: Added.
* compositing/patterns/direct-pattern-compositing.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@148172 268f45cc-cd09-0410-ab3c-d52691b4dbfc

26 files changed:
LayoutTests/ChangeLog
LayoutTests/compositing/patterns/direct-pattern-compositing-add-text-expected.html [new file with mode: 0644]
LayoutTests/compositing/patterns/direct-pattern-compositing-add-text.html [new file with mode: 0644]
LayoutTests/compositing/patterns/direct-pattern-compositing-change-expected.html [new file with mode: 0644]
LayoutTests/compositing/patterns/direct-pattern-compositing-change.html [new file with mode: 0644]
LayoutTests/compositing/patterns/direct-pattern-compositing-contain-expected.html [new file with mode: 0644]
LayoutTests/compositing/patterns/direct-pattern-compositing-contain.html [new file with mode: 0644]
LayoutTests/compositing/patterns/direct-pattern-compositing-cover-expected.html [new file with mode: 0644]
LayoutTests/compositing/patterns/direct-pattern-compositing-cover.html [new file with mode: 0644]
LayoutTests/compositing/patterns/direct-pattern-compositing-expected.html [new file with mode: 0644]
LayoutTests/compositing/patterns/direct-pattern-compositing-load-expected.html [new file with mode: 0644]
LayoutTests/compositing/patterns/direct-pattern-compositing-load.html [new file with mode: 0644]
LayoutTests/compositing/patterns/direct-pattern-compositing-padding-expected.html [new file with mode: 0644]
LayoutTests/compositing/patterns/direct-pattern-compositing-padding.html [new file with mode: 0644]
LayoutTests/compositing/patterns/direct-pattern-compositing-position-expected.html [new file with mode: 0644]
LayoutTests/compositing/patterns/direct-pattern-compositing-position.html [new file with mode: 0644]
LayoutTests/compositing/patterns/direct-pattern-compositing-size-expected.html [new file with mode: 0644]
LayoutTests/compositing/patterns/direct-pattern-compositing-size.html [new file with mode: 0644]
LayoutTests/compositing/patterns/direct-pattern-compositing.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/platform/graphics/GraphicsLayer.h
Source/WebCore/rendering/RenderBox.cpp
Source/WebCore/rendering/RenderBoxModelObject.cpp
Source/WebCore/rendering/RenderBoxModelObject.h
Source/WebCore/rendering/RenderLayerBacking.cpp
Source/WebCore/rendering/RenderLayerBacking.h

index f96c824..cb0991a 100644 (file)
@@ -1,3 +1,32 @@
+2013-04-10  No'am Rosenthal  <noam@webkit.org>
+
+        Allow direct compositing of background images
+        https://bugs.webkit.org/show_bug.cgi?id=108203
+
+        Reviewed by Simon Fraser.
+
+        Added several ref-tests as preparation for supporting direct compositing of background 
+        images.
+
+        * compositing/patterns/direct-pattern-compositing-add-text-expected.html: Added.
+        * compositing/patterns/direct-pattern-compositing-add-text.html: Added.
+        * compositing/patterns/direct-pattern-compositing-change-expected.html: Added.
+        * compositing/patterns/direct-pattern-compositing-change.html: Added.
+        * compositing/patterns/direct-pattern-compositing-contain-expected.html: Added.
+        * compositing/patterns/direct-pattern-compositing-contain.html: Added.
+        * compositing/patterns/direct-pattern-compositing-cover-expected.html: Added.
+        * compositing/patterns/direct-pattern-compositing-cover.html: Added.
+        * compositing/patterns/direct-pattern-compositing-expected.html: Added.
+        * compositing/patterns/direct-pattern-compositing-load-expected.html: Added.
+        * compositing/patterns/direct-pattern-compositing-load.html: Added.
+        * compositing/patterns/direct-pattern-compositing-padding-expected.html: Added.
+        * compositing/patterns/direct-pattern-compositing-padding.html: Added.
+        * compositing/patterns/direct-pattern-compositing-position-expected.html: Added.
+        * compositing/patterns/direct-pattern-compositing-position.html: Added.
+        * compositing/patterns/direct-pattern-compositing-size-expected.html: Added.
+        * compositing/patterns/direct-pattern-compositing-size.html: Added.
+        * compositing/patterns/direct-pattern-compositing.html: Added.
+
 2013-04-10  Benjamin Poulain  <bpoulain@apple.com>
 
         Mass remove all the empty directories
diff --git a/LayoutTests/compositing/patterns/direct-pattern-compositing-add-text-expected.html b/LayoutTests/compositing/patterns/direct-pattern-compositing-add-text-expected.html
new file mode 100644 (file)
index 0000000..9df737c
--- /dev/null
@@ -0,0 +1,30 @@
+<html lang="en">
+<head>
+  <script type="text/javascript" charset="utf-8">
+      function doTest()
+      {
+          var bg = document.querySelector(".test");
+          if (window.testRunner)
+            testRunner.dumpAsPixels(true);
+
+          // Change the layer to become background only.
+          if (window.testRunner)
+              testRunner.display();
+          bg.innerHTML = "123";
+      }
+
+      window.addEventListener('load', doTest, false);
+    </script>
+    <style>
+    .composited { -webkit-transform: rotate3d(0, 0, 1, 0); }
+    .test {
+      height: 200px;
+      width: 260px;
+      background-image: url(../resources/simple_image.png);
+    }
+   </style>
+</head>
+<body>
+  <div class="test"></div>
+</body>
+</html>
diff --git a/LayoutTests/compositing/patterns/direct-pattern-compositing-add-text.html b/LayoutTests/compositing/patterns/direct-pattern-compositing-add-text.html
new file mode 100644 (file)
index 0000000..65a6f80
--- /dev/null
@@ -0,0 +1,30 @@
+<html lang="en">
+<head>
+  <script type="text/javascript" charset="utf-8">
+      function doTest()
+      {
+          var bg = document.querySelector(".test");
+          if (window.testRunner)
+            testRunner.dumpAsPixels(true);
+
+          // Change the layer to become background only.
+          if (window.testRunner)
+              testRunner.display();
+          bg.innerHTML = "123";
+      }
+
+      window.addEventListener('load', doTest, false);
+    </script>
+    <style>
+    .composited { -webkit-transform: rotate3d(0, 0, 1, 0); }
+    .test {
+      height: 200px;
+      width: 260px;
+      background-image: url(../resources/simple_image.png);
+    }
+   </style>
+</head>
+<body>
+  <div class="test composited"></div>
+</body>
+</html>
diff --git a/LayoutTests/compositing/patterns/direct-pattern-compositing-change-expected.html b/LayoutTests/compositing/patterns/direct-pattern-compositing-change-expected.html
new file mode 100644 (file)
index 0000000..ec8ce47
--- /dev/null
@@ -0,0 +1,35 @@
+<html lang="en">
+<head>
+  <script type="text/javascript" charset="utf-8">
+      function doTest()
+      {
+          var bg = document.querySelector(".test");
+          if (window.testRunner)
+              testRunner.dumpAsText(true);
+
+          // Change the layer to become background only.
+          if (window.testRunner)
+              window.testRunner.display();
+          bg.innerHTML = "<span style=\"opacity:0\">123</span>";
+          if (window.testRunner)
+              testRunner.notifyDone();
+      }
+
+      if (window.testRunner)
+          testRunner.waitUntilDone();
+
+      window.addEventListener('load', doTest, false);
+    </script>
+    <style>
+    .composited { -webkit-transform: rotate3d(0, 0, 1, 0); }
+    .test {
+      height: 200px;
+      width: 260px;
+      background-image: url(../resources/simple_image.png);
+    }
+   </style>
+</head>
+<body>
+  <div class="test composited">123</div>
+</body>
+</html>
diff --git a/LayoutTests/compositing/patterns/direct-pattern-compositing-change.html b/LayoutTests/compositing/patterns/direct-pattern-compositing-change.html
new file mode 100644 (file)
index 0000000..9f7054a
--- /dev/null
@@ -0,0 +1,35 @@
+<html lang="en">
+<head>
+  <script type="text/javascript" charset="utf-8">
+      function doTest()
+      {
+          var bg = document.querySelector(".test");
+          if (window.testRunner)
+              testRunner.dumpAsText(true);
+
+          // Change the layer to become background only.
+          if (window.testRunner)
+              window.testRunner.display();
+          bg.innerHTML = "";
+          if (window.testRunner)
+              testRunner.notifyDone();
+      }
+
+      if (window.testRunner)
+          testRunner.waitUntilDone();
+
+      window.addEventListener('load', doTest, false);
+    </script>
+    <style>
+    .composited { -webkit-transform: rotate3d(0, 0, 1, 0); }
+    .test {
+      height: 200px;
+      width: 260px;
+      background-image: url(../resources/simple_image.png);
+    }
+   </style>
+</head>
+<body>
+  <div class="test composited">123</div>
+</body>
+</html>
diff --git a/LayoutTests/compositing/patterns/direct-pattern-compositing-contain-expected.html b/LayoutTests/compositing/patterns/direct-pattern-compositing-contain-expected.html
new file mode 100644 (file)
index 0000000..46a111c
--- /dev/null
@@ -0,0 +1,16 @@
+<html lang="en">
+<head>
+  <style>
+    .composited { -webkit-transform: rotate3d(0, 0, 1, 0); }
+    .test {
+      height: 200px;
+      width: 260px;
+      background-image: url(../resources/simple_image.png);
+      background-size: contain;
+    }
+   </style>
+</head>
+<body>
+  <div class="test"></div>
+</body>
+</html>
diff --git a/LayoutTests/compositing/patterns/direct-pattern-compositing-contain.html b/LayoutTests/compositing/patterns/direct-pattern-compositing-contain.html
new file mode 100644 (file)
index 0000000..cdfab18
--- /dev/null
@@ -0,0 +1,16 @@
+<html lang="en">
+<head>
+  <style>
+    .composited { -webkit-transform: rotate3d(0, 0, 1, 0); }
+    .test {
+      height: 200px;
+      width: 260px;
+      background-image: url(../resources/simple_image.png);
+      background-size: contain;
+    }
+   </style>
+</head>
+<body>
+  <div class="test composited"></div>
+</body>
+</html>
diff --git a/LayoutTests/compositing/patterns/direct-pattern-compositing-cover-expected.html b/LayoutTests/compositing/patterns/direct-pattern-compositing-cover-expected.html
new file mode 100644 (file)
index 0000000..0a5ffff
--- /dev/null
@@ -0,0 +1,16 @@
+<html lang="en">
+<head>
+  <style>
+    .composited { -webkit-transform: rotate3d(0, 0, 1, 30deg); }
+    .test {
+      height: 200px;
+      width: 260px;
+      background-image: url(../resources/simple_image.png);
+      background-size: cover;
+    }
+   </style>
+</head>
+<body>
+  <div class="test"></div>
+</body>
+</html>
diff --git a/LayoutTests/compositing/patterns/direct-pattern-compositing-cover.html b/LayoutTests/compositing/patterns/direct-pattern-compositing-cover.html
new file mode 100644 (file)
index 0000000..efff01e
--- /dev/null
@@ -0,0 +1,16 @@
+<html lang="en">
+<head>
+  <style>
+    .composited { -webkit-transform: rotate3d(0, 0, 1, 0); }
+    .test {
+      height: 200px;
+      width: 260px;
+      background-image: url(../resources/simple_image.png);
+      background-size: cover;
+    }
+   </style>
+</head>
+<body>
+  <div class="test composited"></div>
+</body>
+</html>
diff --git a/LayoutTests/compositing/patterns/direct-pattern-compositing-expected.html b/LayoutTests/compositing/patterns/direct-pattern-compositing-expected.html
new file mode 100644 (file)
index 0000000..9db022a
--- /dev/null
@@ -0,0 +1,14 @@
+<html lang="en">
+<head>
+  <style>
+    .composited { -webkit-transform: rotate3d(0, 0, 1, 0); }
+    .test {
+      height: 200px;
+      width: 260px;
+    }
+   </style>
+</head>
+<body>
+  <div class="test" style="background-image:url(../resources/simple_image.png)"></div>
+</body>
+</html>
diff --git a/LayoutTests/compositing/patterns/direct-pattern-compositing-load-expected.html b/LayoutTests/compositing/patterns/direct-pattern-compositing-load-expected.html
new file mode 100644 (file)
index 0000000..c5cc521
--- /dev/null
@@ -0,0 +1,42 @@
+<html lang="en">
+<head>
+  <script type="text/javascript" charset="utf-8">
+
+      function onBackgroundImageLoad()
+      {
+        if (window.testRunner)
+          testRunner.notifyDone();
+      }
+      function doTest()
+      {
+          var bg = document.querySelector(".test");
+          if (window.testRunner)
+              testRunner.dumpAsText(true);
+
+          // Change the layer to become background only.
+          if (window.testRunner)
+              window.testRunner.display();
+
+          var img = new Image;
+          img.onload = onBackgroundImageLoad;
+          img.src = "../resources/simple_image.png";
+      }
+
+      if (window.testRunner)
+          testRunner.waitUntilDone();
+
+      window.addEventListener('DOMContentLoaded', doTest, false);
+    </script>
+    <style>
+    .composited { -webkit-transform: rotate3d(0, 0, 1, 0); }
+    .test {
+      height: 200px;
+      width: 260px;
+      background-image: url(../resources/simple_image.png);
+    }
+   </style>
+</head>
+<body>
+  <div class="test composited"><span style="opacity:0">ABC</span></div>
+</body>
+</html>
diff --git a/LayoutTests/compositing/patterns/direct-pattern-compositing-load.html b/LayoutTests/compositing/patterns/direct-pattern-compositing-load.html
new file mode 100644 (file)
index 0000000..7a3d664
--- /dev/null
@@ -0,0 +1,42 @@
+<html lang="en">
+<head>
+  <script type="text/javascript" charset="utf-8">
+
+      function onBackgroundImageLoad()
+      {
+        if (window.testRunner)
+          testRunner.notifyDone();
+      }
+      function doTest()
+      {
+          var bg = document.querySelector(".test");
+          if (window.testRunner)
+              testRunner.dumpAsText(true);
+
+          // Change the layer to become background only.
+          if (window.testRunner)
+              window.testRunner.display();
+
+          var img = new Image;
+          img.onload = onBackgroundImageLoad;
+          img.src = "../resources/simple_image.png";
+      }
+
+      if (window.testRunner)
+          testRunner.waitUntilDone();
+
+      window.addEventListener('DOMContentLoaded', doTest, false);
+    </script>
+    <style>
+    .composited { -webkit-transform: rotate3d(0, 0, 1, 0); }
+    .test {
+      height: 200px;
+      width: 260px;
+      background-image: url(../resources/simple_image.png);
+    }
+   </style>
+</head>
+<body>
+  <div class="test composited"></div>
+</body>
+</html>
diff --git a/LayoutTests/compositing/patterns/direct-pattern-compositing-padding-expected.html b/LayoutTests/compositing/patterns/direct-pattern-compositing-padding-expected.html
new file mode 100644 (file)
index 0000000..7e4e3cb
--- /dev/null
@@ -0,0 +1,18 @@
+<html lang="en">
+<head>
+  <style>
+    .composited { -webkit-transform: translate3D(0, 0, 0); }
+    .test {
+      height: 200px;
+      width: 560px;
+      padding: 80px;
+      margin: 0;
+      background-origin: border;
+      background-image: url(../resources/simple_image.png);
+    }
+   </style>
+</head>
+<body>
+  <div class="test"></div>
+  </body>
+</html>
diff --git a/LayoutTests/compositing/patterns/direct-pattern-compositing-padding.html b/LayoutTests/compositing/patterns/direct-pattern-compositing-padding.html
new file mode 100644 (file)
index 0000000..8011b96
--- /dev/null
@@ -0,0 +1,18 @@
+<html lang="en">
+<head>
+  <style>
+    .composited { -webkit-transform: translate3D(0, 0, 0); }
+    .test {
+      height: 200px;
+      width: 560px;
+      padding: 80px;
+      margin: 0;
+      background-origin: border;
+      background-image: url(../resources/simple_image.png);
+    }
+   </style>
+</head>
+<body>
+  <div class="test composited"></div>
+  </body>
+</html>
diff --git a/LayoutTests/compositing/patterns/direct-pattern-compositing-position-expected.html b/LayoutTests/compositing/patterns/direct-pattern-compositing-position-expected.html
new file mode 100644 (file)
index 0000000..642e172
--- /dev/null
@@ -0,0 +1,17 @@
+<html lang="en">
+<head>
+  <style>
+    .composited { -webkit-transform: rotate3d(0, 0, 1, 0); }
+    .test {
+      height: 200px;
+      width: 560px;
+      background-image: url(../resources/simple_image.png);
+      background-size: 50% 50%;
+      background-position: 100px -30px;
+    }
+   </style>
+</head>
+<body>
+  <div class="test"></div>
+</body>
+</html>
diff --git a/LayoutTests/compositing/patterns/direct-pattern-compositing-position.html b/LayoutTests/compositing/patterns/direct-pattern-compositing-position.html
new file mode 100644 (file)
index 0000000..1911733
--- /dev/null
@@ -0,0 +1,17 @@
+<html lang="en">
+<head>
+  <style>
+    .composited { -webkit-transform: rotate3d(0, 0, 1, 0); }
+    .test {
+      height: 200px;
+      width: 560px;
+      background-image: url(../resources/simple_image.png);
+      background-size: 50% 50%;
+      background-position: 100px -30px;
+    }
+   </style>
+</head>
+<body>
+  <div class="test composited"></div>
+</body>
+</html>
diff --git a/LayoutTests/compositing/patterns/direct-pattern-compositing-size-expected.html b/LayoutTests/compositing/patterns/direct-pattern-compositing-size-expected.html
new file mode 100644 (file)
index 0000000..955ab27
--- /dev/null
@@ -0,0 +1,16 @@
+<html lang="en">
+<head>
+  <style>
+    .composited { -webkit-transform: rotate3d(0, 0, 1, 0); }
+    .test {
+      height: 200px;
+      width: 260px;
+      background-image: url(../resources/simple_image.png);
+      background-size: 80% 30%;
+    }
+   </style>
+</head>
+<body>
+  <div class="test"></div>
+</body>
+</html>
diff --git a/LayoutTests/compositing/patterns/direct-pattern-compositing-size.html b/LayoutTests/compositing/patterns/direct-pattern-compositing-size.html
new file mode 100644 (file)
index 0000000..63e3c1b
--- /dev/null
@@ -0,0 +1,16 @@
+<html lang="en">
+<head>
+  <style>
+    .composited { -webkit-transform: rotate3d(0, 0, 1, 0); }
+    .test {
+      height: 200px;
+      width: 260px;
+      background-image: url(../resources/simple_image.png);
+      background-size: 80% 30%;
+    }
+   </style>
+</head>
+<body>
+  <div class="test composited"></div>
+</body>
+</html>
diff --git a/LayoutTests/compositing/patterns/direct-pattern-compositing.html b/LayoutTests/compositing/patterns/direct-pattern-compositing.html
new file mode 100644 (file)
index 0000000..55f3e28
--- /dev/null
@@ -0,0 +1,14 @@
+<html lang="en">
+<head>
+  <style>
+    .composited { -webkit-transform: rotate3d(0, 0, 1, 0); }
+    .test {
+      height: 200px;
+      width: 260px;
+    }
+   </style>
+</head>
+<body>
+  <div class="test composited" style="background-image:url(../resources/simple_image.png)"></div>
+</body>
+</html>
index 172a0f4..a002f1a 100644 (file)
@@ -1,3 +1,72 @@
+2013-04-10  No'am Rosenthal  <noam@webkit.org>
+
+        Allow direct compositing of background images
+        https://bugs.webkit.org/show_bug.cgi?id=108203
+
+        Reviewed by Simon Fraser.
+
+        Use setContentsToImage for background images, if the GraphicsLayer has only a background
+        bitmap image and nothing else. Compute the contentsRect/contentsTileRect from the box model.
+        Added new properties to GraphicsLayer, contentsTilePhase and contentsTileSize, which controls the "single tile rect",
+        which allows us to compute the pattern-space transform of a tile, thus allowing background-size
+        and other characteristics of background images.
+
+        This feature is explicitly disabled when there is any composition with a background color or if
+        there are several background images, as in that case having a single backing store has some
+        advantages over directly compositing in hardware.
+
+        Currently, this feature is disabled for all ports, allowing ports to implement their backend
+        and decide when to enable it.
+
+        Note that RenderBoxModelObject::getGeometryForBackgroundImage crops the contents rect to the 
+        area that contains the tiles, which allows us to assume full tiling in GraphicsLayer.
+        In this way contentsTileSize/Phase is equivalent to GraphicsContext::drawTiledImage.
+
+        Tests: compositing/patterns/direct-pattern-compositing-add-text.html
+               compositing/patterns/direct-pattern-compositing-change.html
+               compositing/patterns/direct-pattern-compositing-contain.html
+               compositing/patterns/direct-pattern-compositing-cover.html
+               compositing/patterns/direct-pattern-compositing-load.html
+               compositing/patterns/direct-pattern-compositing-padding.html
+               compositing/patterns/direct-pattern-compositing-position.html
+               compositing/patterns/direct-pattern-compositing-rotation.html
+               compositing/patterns/direct-pattern-compositing-size.html
+               compositing/patterns/direct-pattern-compositing.html
+
+        * platform/graphics/GraphicsLayer.h:
+        (GraphicsLayer):
+        (WebCore::GraphicsLayer::setContentsTileSize):
+        (WebCore::GraphicsLayer::setContentsTilePhase):
+        (WebCore::GraphicsLayer::contentsTileSize):
+        (WebCore::GraphicsLayer::contentsTilePhase):
+        (WebCore::GraphicsLayer::supportsContentsTiling):
+                Add a contentsTileRect property that enables tile-repeat of background images.
+
+        * rendering/RenderBox.cpp:
+        (WebCore::RenderBox::imageChanged):
+                Pass background image changes to the layer backing.
+
+        * rendering/RenderBoxModelObject.cpp:
+        * rendering/RenderBoxModelObject.h:
+        (WebCore::RenderBoxModelObject::getGeometryForBackgroundImage):
+                Expose a function that performs the geometry calculations needed to determine 
+                the tileRect for a background image. This function is also responsible
+                for cropping the contentsRect to fit the area that is drawn into.
+
+        * rendering/RenderLayerBacking.h:
+        * rendering/RenderLayerBacking.cpp:
+        (WebCore::RenderLayerBacking::contentChanged):
+        (WebCore::RenderLayerBacking::updateGraphicsLayerConfiguration):
+        (WebCore::RenderLayerBacking::updateGraphicsLayerGeometry):
+        (WebCore::RenderLayerBacking::updateDirectlyCompositedContents):
+        (WebCore::RenderLayerBacking::resetContentsRect):
+        (WebCore::hasBoxDecorationsOrBackgroundImage):
+        (WebCore::RenderLayerBacking::updateDirectlyCompositedBackgroundColor):
+        (WebCore::canCreateTiledImage):
+        (WebCore::RenderLayerBacking::updateDirectlyCompositedBackgroundImage):
+        (WebCore::backgroundRectForBox):
+                Allow background images to be directly composited if conditions allow (see bug description).
+
 2013-04-10  Patrick Gansterer  <paroga@webkit.org>
 
         Replace ENABLE_LEGACY_WEB_AUDIO preprocessor statements in IDL files with Conditional attribute
index 4179a6e..184b42c 100644 (file)
@@ -326,6 +326,14 @@ public:
 
     virtual void setContentsNeedsDisplay() { };
 
+    // The tile phase is relative to the GraphicsLayer bounds.
+    virtual void setContentsTilePhase(const IntPoint& p) { m_contentsTilePhase = p; }
+    IntPoint contentsTilePhase() const { return m_contentsTilePhase; }
+
+    virtual void setContentsTileSize(const IntSize& s) { m_contentsTileSize = s; }
+    IntSize contentsTileSize() const { return m_contentsTileSize; }
+    bool hasContentsTiling() const { return !m_contentsTileSize.isEmpty(); }
+
     // Set that the position/size of the contents (image or video).
     IntRect contentsRect() const { return m_contentsRect; }
     virtual void setContentsRect(const IntRect& r) { m_contentsRect = r; }
@@ -435,6 +443,12 @@ public:
 #endif
     }
 
+    static bool supportsContentsTiling()
+    {
+        // FIXME: Enable the feature on different ports.
+        return false;
+    }
+
     void updateDebugIndicators();
 
     virtual bool canThrottleLayerFlush() const { return false; }
@@ -527,6 +541,8 @@ protected:
     FloatPoint m_replicatedLayerPosition; // For a replica layer, the position of the replica.
 
     IntRect m_contentsRect;
+    IntPoint m_contentsTilePhase;
+    IntSize m_contentsTileSize;
 
     int m_repaintCount;
 };
index f93b147..0b96d2a 100644 (file)
@@ -1428,8 +1428,13 @@ void RenderBox::imageChanged(WrappedImagePtr image, const IntRect*)
 
 
 #if USE(ACCELERATED_COMPOSITING)
-    if (hasLayer() && layer()->hasCompositedMask() && layersUseImage(image, style()->maskLayers()))
+    if (!isComposited())
+        return;
+
+    if (layer()->hasCompositedMask() && layersUseImage(image, style()->maskLayers()))
         layer()->contentChanged(MaskImageChanged);
+    if (layersUseImage(image, style()->backgroundLayers()))
+        layer()->contentChanged(BackgroundImageChanged);
 #endif
 }
 
index 3e01bf2..12c89e7 100644 (file)
@@ -1277,6 +1277,16 @@ void RenderBoxModelObject::calculateBackgroundImageGeometry(const FillLayer* fil
     geometry.setDestOrigin(geometry.destRect().location());
 }
 
+void RenderBoxModelObject::getGeometryForBackgroundImage(IntRect& destRect, IntPoint& phase, IntSize& tileSize)
+{
+    const FillLayer* backgroundLayer = style()->backgroundLayers();
+    BackgroundImageGeometry geometry;
+    calculateBackgroundImageGeometry(backgroundLayer, destRect, geometry);
+    phase = geometry.phase();
+    tileSize = geometry.tileSize();
+    destRect = geometry.destRect();
+}
+
 static LayoutUnit computeBorderImageSide(Length borderSlice, LayoutUnit borderSide, LayoutUnit imageSide, LayoutUnit boxExtent, RenderView* renderView)
 {
     if (borderSlice.isRelative())
index 404cedc..e60eb2b 100644 (file)
@@ -44,6 +44,7 @@ enum BackgroundBleedAvoidance {
 enum ContentChangeType {
     ImageChanged,
     MaskImageChanged,
+    BackgroundImageChanged,
     CanvasChanged,
     CanvasPixelsChanged,
     VideoChanged,
@@ -174,6 +175,7 @@ public:
 
     bool canHaveBoxInfoInRegion() const { return !isFloating() && !isReplaced() && !isInline() && !hasColumns() && !isTableCell() && isBlockFlow(); }
 
+    void getGeometryForBackgroundImage(IntRect& destRect, IntPoint& phase, IntSize& tileSize);
 #if USE(ACCELERATED_COMPOSITING)
     void contentChanged(ContentChangeType);
     bool hasAcceleratedCompositing() const;
index 39b9f52..b42fe1d 100644 (file)
@@ -552,7 +552,10 @@ bool RenderLayerBacking::updateGraphicsLayerConfiguration()
     } else
         m_graphicsLayer->setReplicatedByLayer(0);
 
-    updateBackgroundColor(isSimpleContainerCompositingLayer());
+    bool isSimpleContainer = isSimpleContainerCompositingLayer();
+    bool didUpdateContentsRect = false;
+    updateDirectlyCompositedContents(isSimpleContainer, didUpdateContentsRect);
+
     updateRootLayerConfiguration();
     
     if (isDirectlyCompositedImage())
@@ -854,13 +857,22 @@ void RenderLayerBacking::updateGraphicsLayerGeometry()
     // If this layer was created just for clipping or to apply perspective, it doesn't need its own backing store.
     setRequiresOwnBackingStore(compositor()->requiresOwnBackingStore(m_owningLayer, compAncestor));
 
-    updateContentsRect(isSimpleContainer);
-    updateBackgroundColor(isSimpleContainer);
+    bool didUpdateContentsRect = false;
+    updateDirectlyCompositedContents(isSimpleContainer, didUpdateContentsRect);
+    if (!didUpdateContentsRect)
+        resetContentsRect();
+
     updateDrawsContent(isSimpleContainer);
     updateAfterWidgetResize();
     registerScrollingLayers();
 }
 
+void RenderLayerBacking::updateDirectlyCompositedContents(bool isSimpleContainer, bool& didUpdateContentsRect)
+{
+    updateDirectlyCompositedBackgroundImage(isSimpleContainer, didUpdateContentsRect);
+    updateDirectlyCompositedBackgroundColor(isSimpleContainer, didUpdateContentsRect);
+}
+
 void RenderLayerBacking::registerScrollingLayers()
 {
     // Register fixed position layers and their containers with the scrolling coordinator.
@@ -932,15 +944,12 @@ void RenderLayerBacking::updateInternalHierarchy()
     }
 }
 
-void RenderLayerBacking::updateContentsRect(bool isSimpleContainer)
+void RenderLayerBacking::resetContentsRect()
 {
-    IntRect contentsRect;
-    if (isSimpleContainer && renderer()->hasBackground())
-        contentsRect = backgroundBox();
-    else
-        contentsRect = contentsBox();
-
-    m_graphicsLayer->setContentsRect(contentsRect);
+    IntRect rect = contentsBox();
+    m_graphicsLayer->setContentsRect(rect);
+    m_graphicsLayer->setContentsTileSize(IntSize());
+    m_graphicsLayer->setContentsTilePhase(IntPoint());
 }
 
 void RenderLayerBacking::updateDrawsContent()
@@ -1356,9 +1365,17 @@ static bool hasBoxDecorations(const RenderStyle* style)
     return style->hasBorder() || style->hasBorderRadius() || style->hasOutline() || style->hasAppearance() || style->boxShadow() || style->hasFilter();
 }
 
+static bool canCreateTiledImage(const RenderStyle*);
+
 static bool hasBoxDecorationsOrBackgroundImage(const RenderStyle* style)
 {
-    return hasBoxDecorations(style) || style->hasBackgroundImage();
+    if (hasBoxDecorations(style))
+        return true;
+
+    if (!style->hasBackgroundImage())
+        return false;
+
+    return !GraphicsLayer::supportsContentsTiling() || !canCreateTiledImage(style);
 }
 
 Color RenderLayerBacking::rendererBackgroundColor() const
@@ -1370,14 +1387,75 @@ Color RenderLayerBacking::rendererBackgroundColor() const
     return backgroundRenderer->style()->visitedDependentColor(CSSPropertyBackgroundColor);
 }
 
-void RenderLayerBacking::updateBackgroundColor(bool isSimpleContainer)
+void RenderLayerBacking::updateDirectlyCompositedBackgroundColor(bool isSimpleContainer, bool& didUpdateContentsRect)
 {
-    Color backgroundColor;
-    if (isSimpleContainer)
-        backgroundColor = rendererBackgroundColor();
+    if (!isSimpleContainer) {
+        m_graphicsLayer->setContentsToSolidColor(Color());
+        return;
+    }
+
+    Color backgroundColor = rendererBackgroundColor();
 
     // An unset (invalid) color will remove the solid color.
     m_graphicsLayer->setContentsToSolidColor(backgroundColor);
+    m_graphicsLayer->setContentsRect(backgroundBox());
+    didUpdateContentsRect = true;
+}
+
+bool canCreateTiledImage(const RenderStyle* style)
+{
+    const FillLayer* fillLayer = style->backgroundLayers();
+    if (fillLayer->next())
+        return false;
+
+    if (!fillLayer->imagesAreLoaded())
+        return false;
+
+    if (fillLayer->attachment() != ScrollBackgroundAttachment)
+        return false;
+
+    Color color = style->visitedDependentColor(CSSPropertyBackgroundColor);
+
+    // FIXME: Allow color+image compositing when it makes sense.
+    // For now bailing out.
+    if (color.isValid() && color.alpha())
+        return false;
+
+    StyleImage* styleImage = fillLayer->image();
+
+    // FIXME: support gradients with isGeneratedImage.
+    if (!styleImage->isCachedImage())
+        return false;
+
+    Image* image = styleImage->cachedImage()->image();
+    if (!image->isBitmapImage())
+        return false;
+
+    return true;
+}
+
+void RenderLayerBacking::updateDirectlyCompositedBackgroundImage(bool isSimpleContainer, bool& didUpdateContentsRect)
+{
+    if (!GraphicsLayer::supportsContentsTiling())
+        return;
+
+    const RenderStyle* style = renderer()->style();
+
+    if (!isSimpleContainer || !style->hasBackgroundImage()) {
+        m_graphicsLayer->setContentsToImage(0);
+        return;
+    }
+
+    IntRect destRect = backgroundBox();
+    IntPoint phase;
+    IntSize tileSize;
+    RefPtr<Image> image = style->backgroundLayers()->image()->cachedImage()->image();
+    toRenderBox(renderer())->getGeometryForBackgroundImage(destRect, phase, tileSize);
+    m_graphicsLayer->setContentsTileSize(tileSize);
+    m_graphicsLayer->setContentsTilePhase(phase);
+    m_graphicsLayer->setContentsRect(destRect);
+    m_graphicsLayer->setContentsToImage(image.get());
+    didUpdateContentsRect = true;
 }
 
 void RenderLayerBacking::updateRootLayerConfiguration()
@@ -1614,6 +1692,9 @@ void RenderLayerBacking::contentChanged(ContentChangeType changeType)
         return;
     }
 
+    if ((changeType == BackgroundImageChanged) && canCreateTiledImage(renderer()->style()))
+        updateGraphicsLayerGeometry();
+
     if ((changeType == MaskImageChanged) && m_maskLayer) {
         // The composited layer bounds relies on box->maskClipRect(), which changes
         // when the mask image becomes available.
@@ -1708,8 +1789,7 @@ IntRect RenderLayerBacking::contentsBox() const
 
 static LayoutRect backgroundRectForBox(const RenderBox* box)
 {
-    EFillBox clip = box->style()->backgroundClip();
-    switch (clip) {
+    switch (box->style()->backgroundClip()) {
     case BorderFillBox:
         return box->borderBoxRect();
     case PaddingFillBox:
index e69ee8a..e4d7c0b 100644 (file)
@@ -258,8 +258,11 @@ private:
     void updateImageContents();
 
     Color rendererBackgroundColor() const;
-    void updateBackgroundColor(bool isSimpleContainer);
-    void updateContentsRect(bool isSimpleContainer);
+    void updateDirectlyCompositedBackgroundColor(bool isSimpleContainer, bool& didUpdateContentsRect);
+    void updateDirectlyCompositedBackgroundImage(bool isSimpleContainer, bool& didUpdateContentsRect);
+    void updateDirectlyCompositedContents(bool isSimpleContainer, bool& didUpdateContentsRect);
+
+    void resetContentsRect();
 
     bool hasVisibleNonCompositingDescendantLayers() const;