Async image decoding for large images should be disabled after the first time a tile...
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 25 Jul 2017 18:53:08 +0000 (18:53 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 25 Jul 2017 18:53:08 +0000 (18:53 +0000)
https://bugs.webkit.org/show_bug.cgi?id=174451
<rdar://problem/31246421>

Patch by Said Abou-Hallawa <sabouhallawa@apple.com> on 2017-07-25
Reviewed by Simon Fraser.

Source/WebCore:

Flashing because of DOM mutation can be fixed by disabling the asynchronous
image decoding after the first time a tile was painted.

We can detect this by consulting the tile repaintCount. If it is zero, then
it is safe to use asynchronous image decoded. If the tile repaintCount is
greater than zero, we are not sure if the renderer rectangle has an image
drawn in it already or not. In this case we have to use the synchronous
image decoding to avoid causing a flash.

Tests: fast/images/async-image-background-change.html
       fast/images/async-image-src-change.html
       http/tests/multipart/multipart-async-image.html

* html/shadow/MediaControlElements.cpp:
(WebCore::MediaControlTextTrackContainerElement::createTextTrackRepresentationImage):
* page/FrameView.cpp:
(WebCore::FrameView::willPaintContents):
(WebCore::FrameView::paintContentsForSnapshot):
* page/PageOverlayController.cpp:
(WebCore::PageOverlayController::paintContents):
* page/PageOverlayController.h:
* page/linux/ResourceUsageOverlayLinux.cpp:
* page/mac/ServicesOverlayController.h:
* page/mac/ServicesOverlayController.mm:
(WebCore::ServicesOverlayController::Highlight::paintContents):
* platform/graphics/BitmapImage.cpp:
(WebCore::BitmapImage::draw):
* platform/graphics/BitmapImage.h:
* platform/graphics/GraphicsLayer.cpp:
(WebCore::GraphicsLayer::paintGraphicsLayerContents):
* platform/graphics/GraphicsLayer.h:
* platform/graphics/GraphicsLayerClient.h:
(WebCore::GraphicsLayerClient::paintContents):
* platform/graphics/avfoundation/cf/MediaPlayerPrivateAVFoundationCF.cpp:
(WebCore::LayerClient::platformCALayerPaintContents):
* platform/graphics/ca/GraphicsLayerCA.cpp:
(WebCore::GraphicsLayerCA::platformCALayerPaintContents):
* platform/graphics/ca/GraphicsLayerCA.h:
* platform/graphics/ca/PlatformCALayer.h:
* platform/graphics/ca/PlatformCALayerClient.h:
(WebCore::PlatformCALayerClient::platformCALayerRepaintCount):
* platform/graphics/ca/TileCoverageMap.cpp:
(WebCore::TileCoverageMap::platformCALayerPaintContents):
* platform/graphics/ca/TileCoverageMap.h:
* platform/graphics/ca/TileGrid.cpp:
(WebCore::TileGrid::platformCALayerPaintContents):
(WebCore::TileGrid::platformCALayerRepaintCount):
* platform/graphics/ca/TileGrid.h:
* platform/graphics/ca/cocoa/PlatformCALayerCocoa.mm:
(PlatformCALayer::drawLayerContents):
* platform/graphics/ca/win/PlatformCALayerWin.cpp:
(PlatformCALayer::drawLayerContents):
* platform/graphics/ca/win/PlatformCALayerWinInternal.cpp:
(PlatformCALayerWinInternal::displayCallback):
* platform/graphics/ca/win/WebTiledBackingLayerWin.cpp:
(WebTiledBackingLayerWin::displayCallback):
* platform/graphics/mac/WebLayer.mm:
(-[WebLayer drawInContext:]):
(-[WebSimpleLayer drawInContext:]):
* rendering/PaintPhase.h:
* rendering/RenderBoxModelObject.cpp:
(WebCore::RenderBoxModelObject::decodingModeForImageDraw):
* rendering/RenderElement.h:
* rendering/RenderLayer.cpp:
(WebCore::RenderLayer::paintLayerContents):
(WebCore::RenderLayer::paintForegroundForFragments):
* rendering/RenderLayerBacking.cpp:
(WebCore::RenderLayerBacking::paintContents):
* rendering/RenderLayerBacking.h:
* rendering/RenderLayerCompositor.cpp:
(WebCore::RenderLayerCompositor::paintContents):
* rendering/RenderLayerCompositor.h:
* rendering/RenderWidget.cpp:
(WebCore::RenderWidget::paintContents):
* testing/Internals.cpp:
(WebCore::imageFromImageElement):
(WebCore::bitmapImageFromImageElement):
(WebCore::Internals::imageFrameIndex):
(WebCore::Internals::setImageFrameDecodingDuration):
(WebCore::Internals::resetImageAnimation):
(WebCore::Internals::isImageAnimating):
(WebCore::Internals::setClearDecoderAfterAsyncFrameRequestForTesting):
(WebCore::Internals::imageDecodeCount):
(WebCore::Internals::setLargeImageAsyncDecodingEnabledForTesting):
* testing/Internals.h:
* testing/Internals.idl:

Source/WebKit:

* Shared/mac/RemoteLayerBackingStore.mm:
(WebKit::RemoteLayerBackingStore::drawInContext):
* WebProcess/InjectedBundle/DOM/InjectedBundleNodeHandle.cpp:
(WebKit::imageForRect):
* WebProcess/InjectedBundle/DOM/InjectedBundleRangeHandle.cpp:
(WebKit::InjectedBundleRangeHandle::renderedImage):
* WebProcess/WebPage/CoordinatedGraphics/CompositingCoordinator.cpp:
(WebKit::CompositingCoordinator::paintContents):
* WebProcess/WebPage/CoordinatedGraphics/CompositingCoordinator.h:

Source/WebKitLegacy/mac:

* WebView/WebFrame.mm:
(-[WebFrame _paintBehaviorForDestinationContext:]):
(-[WebFrame _drawRect:contentsOnly:]):
* WebView/WebHTMLView.mm:
(imageFromRect):

Source/WebKitLegacy/win:

* FullscreenVideoController.cpp:
(FullscreenVideoController::LayerClient::platformCALayerPaintContents):
* WebCoreSupport/AcceleratedCompositingContext.cpp:
(AcceleratedCompositingContext::paintContents):
* WebCoreSupport/AcceleratedCompositingContext.h:

LayoutTests:

To test async image decoding for large images, we have to create the <img>
element dynamically so we can listen to the load and webkitImageFrameReady
events and know reliably when to end the test. But with this patch the async
image decoding for large images will be disabled after the first paint.
That means async image decoding for large images will be disabled always
unless we force the async image decoding till the image is painted for the
first time. We use Internals::setLargeImageAsyncDecodingEnabledForTesting()
to force the async image decoding. So painting an image in this case will
require multiple paints; in all of them the async image decoding will be
enabled. But this is okay because it resembles the case where the <img> is
created from a static <img> tag in the HTML file.

For new tests, where we want to make sure that mutating the DOM will not
cause a flash, async image decoding will be forced till the image is drawn
for the first time. After that the async image decoding is enabled but not
forced.

Disable new tests for WK1 because the async image decoding is always enabled
because tiling does not necessarily exist in WK1 . But eventually the async
image decoding for large images will be always disabled for WK1.

* fast/images/async-image-background-change-expected.html: Added.
* fast/images/async-image-background-change.html: Added.
* fast/images/async-image-background-image-repeated.html:
* fast/images/async-image-background-image.html:
* fast/images/async-image-body-background-image.html:
* fast/images/async-image-multiple-clients-repaint.html:
* fast/images/async-image-src-change-expected.html: Added.
* fast/images/async-image-src-change.html: Added.
* fast/images/resources/green-400x400.png: Added.
* fast/images/resources/red-100x100.png: Added.
* fast/images/resources/red-400x400.png: Added.
* fast/images/sprite-sheet-image-draw.html:
* http/tests/multipart/multipart-async-image-expected.txt: Added.
* http/tests/multipart/multipart-async-image.html: Added.
* platform/ios-wk1/TestExpectations:
* platform/mac-wk1/TestExpectations:

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

69 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/images/async-image-background-change-expected.html [new file with mode: 0644]
LayoutTests/fast/images/async-image-background-change.html [new file with mode: 0644]
LayoutTests/fast/images/async-image-background-image-repeated.html
LayoutTests/fast/images/async-image-background-image.html
LayoutTests/fast/images/async-image-body-background-image.html
LayoutTests/fast/images/async-image-multiple-clients-repaint.html
LayoutTests/fast/images/async-image-src-change-expected.html [new file with mode: 0644]
LayoutTests/fast/images/async-image-src-change.html [new file with mode: 0644]
LayoutTests/fast/images/resources/green-400x400.png [new file with mode: 0644]
LayoutTests/fast/images/resources/red-100x100.png [new file with mode: 0644]
LayoutTests/fast/images/resources/red-400x400.png [new file with mode: 0644]
LayoutTests/fast/images/sprite-sheet-image-draw.html
LayoutTests/http/tests/multipart/multipart-async-image-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/multipart/multipart-async-image.html [new file with mode: 0644]
LayoutTests/platform/ios-wk1/TestExpectations
LayoutTests/platform/mac-wk1/TestExpectations
Source/WebCore/ChangeLog
Source/WebCore/html/shadow/MediaControlElements.cpp
Source/WebCore/page/FrameView.cpp
Source/WebCore/page/PageOverlayController.cpp
Source/WebCore/page/PageOverlayController.h
Source/WebCore/page/linux/ResourceUsageOverlayLinux.cpp
Source/WebCore/page/mac/ServicesOverlayController.h
Source/WebCore/page/mac/ServicesOverlayController.mm
Source/WebCore/platform/graphics/BitmapImage.cpp
Source/WebCore/platform/graphics/BitmapImage.h
Source/WebCore/platform/graphics/GraphicsLayer.cpp
Source/WebCore/platform/graphics/GraphicsLayer.h
Source/WebCore/platform/graphics/GraphicsLayerClient.h
Source/WebCore/platform/graphics/avfoundation/cf/MediaPlayerPrivateAVFoundationCF.cpp
Source/WebCore/platform/graphics/ca/GraphicsLayerCA.cpp
Source/WebCore/platform/graphics/ca/GraphicsLayerCA.h
Source/WebCore/platform/graphics/ca/PlatformCALayer.h
Source/WebCore/platform/graphics/ca/PlatformCALayerClient.h
Source/WebCore/platform/graphics/ca/TileCoverageMap.cpp
Source/WebCore/platform/graphics/ca/TileCoverageMap.h
Source/WebCore/platform/graphics/ca/TileGrid.cpp
Source/WebCore/platform/graphics/ca/TileGrid.h
Source/WebCore/platform/graphics/ca/cocoa/PlatformCALayerCocoa.mm
Source/WebCore/platform/graphics/ca/win/PlatformCALayerWin.cpp
Source/WebCore/platform/graphics/ca/win/PlatformCALayerWinInternal.cpp
Source/WebCore/platform/graphics/ca/win/WebTiledBackingLayerWin.cpp
Source/WebCore/platform/graphics/mac/WebLayer.mm
Source/WebCore/rendering/PaintPhase.h
Source/WebCore/rendering/RenderBoxModelObject.cpp
Source/WebCore/rendering/RenderElement.h
Source/WebCore/rendering/RenderLayer.cpp
Source/WebCore/rendering/RenderLayerBacking.cpp
Source/WebCore/rendering/RenderLayerBacking.h
Source/WebCore/rendering/RenderLayerCompositor.cpp
Source/WebCore/rendering/RenderLayerCompositor.h
Source/WebCore/rendering/RenderWidget.cpp
Source/WebCore/testing/Internals.cpp
Source/WebCore/testing/Internals.h
Source/WebCore/testing/Internals.idl
Source/WebKit/ChangeLog
Source/WebKit/Shared/mac/RemoteLayerBackingStore.mm
Source/WebKit/WebProcess/InjectedBundle/DOM/InjectedBundleNodeHandle.cpp
Source/WebKit/WebProcess/InjectedBundle/DOM/InjectedBundleRangeHandle.cpp
Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/CompositingCoordinator.cpp
Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/CompositingCoordinator.h
Source/WebKitLegacy/mac/ChangeLog
Source/WebKitLegacy/mac/WebView/WebFrame.mm
Source/WebKitLegacy/mac/WebView/WebHTMLView.mm
Source/WebKitLegacy/win/ChangeLog
Source/WebKitLegacy/win/FullscreenVideoController.cpp
Source/WebKitLegacy/win/WebCoreSupport/AcceleratedCompositingContext.cpp
Source/WebKitLegacy/win/WebCoreSupport/AcceleratedCompositingContext.h

index cf5364c13ff734e9da8fe5b1cab4b6dc9e77d7d4..e4ccabb78a2b654d96fad467edc2c9ed3bc48e00 100644 (file)
@@ -1,3 +1,49 @@
+2017-07-25  Said Abou-Hallawa  <sabouhallawa@apple.com>
+
+        Async image decoding for large images should be disabled after the first time a tile is painted
+        https://bugs.webkit.org/show_bug.cgi?id=174451
+        <rdar://problem/31246421>
+
+        Reviewed by Simon Fraser.
+
+        To test async image decoding for large images, we have to create the <img>
+        element dynamically so we can listen to the load and webkitImageFrameReady
+        events and know reliably when to end the test. But with this patch the async
+        image decoding for large images will be disabled after the first paint. 
+        That means async image decoding for large images will be disabled always
+        unless we force the async image decoding till the image is painted for the
+        first time. We use Internals::setLargeImageAsyncDecodingEnabledForTesting()
+        to force the async image decoding. So painting an image in this case will
+        require multiple paints; in all of them the async image decoding will be
+        enabled. But this is okay because it resembles the case where the <img> is
+        created from a static <img> tag in the HTML file.
+
+        For new tests, where we want to make sure that mutating the DOM will not
+        cause a flash, async image decoding will be forced till the image is drawn
+        for the first time. After that the async image decoding is enabled but not
+        forced.
+
+        Disable new tests for WK1 because the async image decoding is always enabled
+        because tiling does not necessarily exist in WK1 . But eventually the async
+        image decoding for large images will be always disabled for WK1.
+
+        * fast/images/async-image-background-change-expected.html: Added.
+        * fast/images/async-image-background-change.html: Added.
+        * fast/images/async-image-background-image-repeated.html:
+        * fast/images/async-image-background-image.html:
+        * fast/images/async-image-body-background-image.html:
+        * fast/images/async-image-multiple-clients-repaint.html:
+        * fast/images/async-image-src-change-expected.html: Added.
+        * fast/images/async-image-src-change.html: Added.
+        * fast/images/resources/green-400x400.png: Added.
+        * fast/images/resources/red-100x100.png: Added.
+        * fast/images/resources/red-400x400.png: Added.
+        * fast/images/sprite-sheet-image-draw.html:
+        * http/tests/multipart/multipart-async-image-expected.txt: Added.
+        * http/tests/multipart/multipart-async-image.html: Added.
+        * platform/ios-wk1/TestExpectations:
+        * platform/mac-wk1/TestExpectations:
+
 2017-07-25  Charlie Turner  <cturner@igalia.com>
 
         [GTK] Unreviewed test gardening
diff --git a/LayoutTests/fast/images/async-image-background-change-expected.html b/LayoutTests/fast/images/async-image-background-change-expected.html
new file mode 100644 (file)
index 0000000..c6b06f0
--- /dev/null
@@ -0,0 +1,10 @@
+<style>
+    div {
+        width: 400px;
+        height: 400px;
+        background-color: green;
+    }
+</style>
+<body>
+    <div></div>
+</body>
diff --git a/LayoutTests/fast/images/async-image-background-change.html b/LayoutTests/fast/images/async-image-background-change.html
new file mode 100644 (file)
index 0000000..fe33b1a
--- /dev/null
@@ -0,0 +1,71 @@
+<!DOCTYPE html>
+<html>
+<style>
+    div {
+        width: 400px;
+        height: 400px;
+    }
+ </style>
+ <body>
+    <div></div>
+    <script>
+        function loadImageAndSetBackground(element, image, src, forceAsyncImageDrawing) {
+            return new Promise((resolve) => {
+                image.onload = (() => {
+                    if (window.internals && window.testRunner && forceAsyncImageDrawing) {
+                        // Force async image decoding for this image.
+                        internals.setLargeImageAsyncDecodingEnabledForTesting(image, true);
+
+                        // Change the background of the element.
+                        element.style.backgroundImage = 'url(' + image.src + ')';
+
+                        // Force layout and display so the image gets drawn.
+                        document.body.offsetHeight;
+                        if (window.testRunner)
+                            testRunner.display();
+
+                        image.addEventListener("webkitImageFrameReady", function() {
+                            internals.setLargeImageAsyncDecodingEnabledForTesting(image, false);
+                            setTimeout(function() {
+                                // Force redraw to get the red image drawn.
+                                testRunner.display();
+                                resolve();
+                            }, 0);
+                        }, false);
+                    } else {
+                        // Change the background of the element.
+                        element.style.backgroundImage = 'url(' + image.src + ')';
+                        resolve();
+                    }
+                });
+                image.src = src;
+            });
+        }
+        (function() {
+            if (window.internals && window.testRunner) {
+                internals.clearMemoryCache();
+                internals.settings.setWebkitImageReadyEventEnabled(true);
+                internals.settings.setLargeImageAsyncDecodingEnabled(true);
+                testRunner.waitUntilDone();
+            }
+            var image = new Image;
+            document.body.appendChild(image);
+            var element = document.querySelector("div");
+
+            // Load a large (400x400) red image to force sync image decoding and drawing.
+            loadImageAndSetBackground(element, image, "resources/red-400x400.png", true).then(() => {
+                // Replace the large red image with a large (400x400) green image.
+                // Sync image decoding and drawing have to be forced in this case.
+                return loadImageAndSetBackground(element, image, "resources/green-400x400.png", false);
+            }).then(() => {
+                image.remove();
+                // A single paint is needed to draw the large (400x400) green image.
+                if (window.testRunner)
+                    testRunner.notifyDone();
+            });
+        })();
+    </script>
+ </body>
+ </html>
\ No newline at end of file
index 6f069c5644a940c89d5faf0940b849bbf0bbbb51..2822f799268039323658b139a66fb02ecb0a7748 100644 (file)
 
             var image = new Image();
             image.onload = function() {
-                var elements = document.getElementsByClassName("image-background");
+                 // Force async image decoding for this image.
+                if (window.internals)
+                    internals.setLargeImageAsyncDecodingEnabledForTesting(image, true);
+
                 // Change the background of the elements.
+                var elements = document.getElementsByClassName("image-background");
                 if (window.internals && window.testRunner) {
                     var promises = [];
                     for (var index = 0; index < elements.length; ++index)
index 1246b307b50711d7dd410d1daaf643858b6eb78b..db4877afec5fa39aa94b7a451dcab05a83ba5358 100644 (file)
 
             var image = new Image();
             image.onload = function() {
+                // Force async image decoding for this image.
+                if (window.internals)
+                    internals.setLargeImageAsyncDecodingEnabledForTesting(image, true);
+
+                // Change the background of the element.                 
                 var element = document.getElementsByClassName("image-background")[0];
-                // Change the background of the element.
                 element.style.backgroundImage = 'url(' + image.src + ')';
  
                 if (window.internals && window.testRunner) {
index ee821e3bb354f2ee2cacedbdc79d2988fabbc778..aacdd14f4200d1b81f7049f88a04acebef9cddd2 100644 (file)
 
             var image = new Image();
             image.onload = function() {
+                // Force async image decoding for this image.
+                if (window.internals)
+                    internals.setLargeImageAsyncDecodingEnabledForTesting(image, true);
+
                 var iframeDocument = document.querySelector('iframe').contentWindow.document;
 
                 if (window.internals && window.testRunner) {
index 3a8f4a6a35c0abb6284685703f36a381fab10554..816d5b0bc7b6b47be9ad6c6fcdf71a96ccda091e 100644 (file)
 
             var image = new Image();
             image.onload = function() {
+                // Force async image decoding for this image.
+                if (window.internals)
+                    internals.setLargeImageAsyncDecodingEnabledForTesting(image, true);
+
                 if (window.internals && window.testRunner) {
                     setElementImageBackground(document.querySelector(".small-box"), image).then(() => {
                         // Call the next setElementImageBackground() asynchronously, using setTimeout(, 0),
diff --git a/LayoutTests/fast/images/async-image-src-change-expected.html b/LayoutTests/fast/images/async-image-src-change-expected.html
new file mode 100644 (file)
index 0000000..c6b06f0
--- /dev/null
@@ -0,0 +1,10 @@
+<style>
+    div {
+        width: 400px;
+        height: 400px;
+        background-color: green;
+    }
+</style>
+<body>
+    <div></div>
+</body>
diff --git a/LayoutTests/fast/images/async-image-src-change.html b/LayoutTests/fast/images/async-image-src-change.html
new file mode 100644 (file)
index 0000000..ff0e0fd
--- /dev/null
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<html>
+<body>
+    <script>
+        function loadImageAndDraw(image, src, forceAsyncImageDrawing) {
+            return new Promise((resolve) => {
+                image.onload = (() => {
+                    if (window.internals && window.testRunner && forceAsyncImageDrawing) {
+                        // Force async image decoding for this image.
+                        internals.setLargeImageAsyncDecodingEnabledForTesting(image, true);
+
+                        // Force layout and display so the image gets drawn.
+                        document.body.offsetHeight;
+                        if (window.testRunner)
+                            testRunner.display();
+
+                        image.addEventListener("webkitImageFrameReady", function() {
+                            internals.setLargeImageAsyncDecodingEnabledForTesting(image, false);
+                            setTimeout(function() {
+                                // Force redraw to get the red image drawn.
+                                testRunner.display();
+                                resolve();
+                            }, 0);
+                        }, false);
+                    } else {
+                        resolve();                        
+                    }
+                });
+                image.src = src;
+            });
+        }
+        (function() {
+            if (window.internals && window.testRunner) {
+                internals.clearMemoryCache();
+                internals.settings.setWebkitImageReadyEventEnabled(true);
+                internals.settings.setLargeImageAsyncDecodingEnabled(true);
+                testRunner.waitUntilDone();
+            }
+            var image = new Image;
+            document.body.appendChild(image);
+            // Load a large (400x400) red image to force sync image decoding and drawing.
+            loadImageAndDraw(image, "resources/red-400x400.png", true).then(() => {
+                // Replace the large red image with a large (400x400) green image.
+                // Sync image decoding and drawing have to be forced in this case.
+                return loadImageAndDraw(image, "resources/green-400x400.png", false);
+            }).then(() => {
+                // A single paint is needed to draw the large (400x400) green image.
+                if (window.testRunner)
+                    testRunner.notifyDone();
+            });
+        })();
+    </script>
+ </body>
+ </html>
diff --git a/LayoutTests/fast/images/resources/green-400x400.png b/LayoutTests/fast/images/resources/green-400x400.png
new file mode 100644 (file)
index 0000000..5284982
Binary files /dev/null and b/LayoutTests/fast/images/resources/green-400x400.png differ
diff --git a/LayoutTests/fast/images/resources/red-100x100.png b/LayoutTests/fast/images/resources/red-100x100.png
new file mode 100644 (file)
index 0000000..91efea0
Binary files /dev/null and b/LayoutTests/fast/images/resources/red-100x100.png differ
diff --git a/LayoutTests/fast/images/resources/red-400x400.png b/LayoutTests/fast/images/resources/red-400x400.png
new file mode 100644 (file)
index 0000000..bf8772c
Binary files /dev/null and b/LayoutTests/fast/images/resources/red-400x400.png differ
index bda44fad434e7f740e6400ba1442b4470a3bcb04..859a6e31d5f2a0fafe8f78ff0ed2d321203af454 100644 (file)
 
             var image = new Image();
             image.onload = function() {
-                var element = document.getElementsByClassName("image-background")[0];
+                // Force async image decoding for this image.
+                if (window.internals)
+                    internals.setLargeImageAsyncDecodingEnabledForTesting(image, true);
+
                 // Change the background of the element.
+                var element = document.getElementsByClassName("image-background")[0];
                 element.style.backgroundImage = 'url(' + image.src + ')';
  
                 if (window.internals && window.testRunner) {
diff --git a/LayoutTests/http/tests/multipart/multipart-async-image-expected.txt b/LayoutTests/http/tests/multipart/multipart-async-image-expected.txt
new file mode 100644 (file)
index 0000000..fa0e021
--- /dev/null
@@ -0,0 +1,10 @@
+Make sure no async decoding is done for multipart images
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS The second frame of the multipart image was drawn without async image decoding.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/http/tests/multipart/multipart-async-image.html b/LayoutTests/http/tests/multipart/multipart-async-image.html
new file mode 100644 (file)
index 0000000..c43d81a
--- /dev/null
@@ -0,0 +1,70 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script src="../resources/js-test-pre.js"></script>
+</head>
+<body>
+    <script>
+        function multipartUrl() {
+            var relativePath = "../../../../fast/images/resources/";
+            return "resources/multipart.php"
+                    + "?interval=0.1"
+                    + "&img1=" + relativePath + "red-100x100.png"
+                    + "&img2=" + relativePath + "green-400x400.png"
+                    + "&img3=" + relativePath + "green-400x400.png";
+        }
+
+        var intervalID = null;
+        function finishTest() {
+            if (intervalID !== null)
+                clearInterval(intervalID);
+            finishJSTest();
+        }
+
+        (function() {
+            description("Make sure no async decoding is done for multipart images");
+            jsTestIsAsync = true;
+            if (window.internals && window.testRunner) {
+                internals.clearMemoryCache();
+                internals.settings.setWebkitImageReadyEventEnabled(true);
+                internals.settings.setLargeImageAsyncDecodingEnabled(true);
+            }
+            var image = new Image;
+            document.body.appendChild(image);
+            image.addEventListener("webkitImageFrameReady", function() {
+                // The first image is small (100x100) red image which does not
+                // require async image decoding. But drawing it should prevent
+                // any subsequent async image decoding for large images.
+                testFailed("Async image decoding was mistakenly requested.");
+                finishTest();
+            }, false);
+            image.onload = function() {
+                var count = 0;
+                intervalID = setInterval(function() {
+                    // Force layout and display.
+                    document.body.offsetHeight;
+                    testRunner.display();
+                    ++count;
+
+                    if (image.offsetWidth == 400 && count == 100) {
+                        testPassed("The second frame of the multipart image was drawn without async image decoding.");
+                        finishTest();
+                    }
+
+                    if (count > 200) {
+                        testFailed("Timeout: the second frame of the multipart image was not loaded.");
+                        finishTest();
+                    }
+                }, 10);
+            }
+            image.src = multipartUrl(); 
+        })();
+    </script>
+    <script src="../resources/js-test-post.js"></script>
+</body>
+</html>
index e891500c266ace164ad91f0c781e2949aa6aa5b2..2e9d8817c634848fce5991cff89dc02728c923fe 100644 (file)
@@ -1107,6 +1107,11 @@ http/tests/navigation/metaredirect-goback.html
 # Disk cache is WK2 only
 http/tests/cache/disk-cache
 
+# Async image decoding is WK2 only
+fast/images/async-image-background-change.html
+fast/images/async-image-src-change.html
+http/tests/multipart/multipart-async-image.html
+
 # Flaky as of 06/08/2015
 animations/animation-direction-reverse-hardware-opacity.html [ Failure Pass ]
 animations/animation-direction-reverse-hardware.html [ Failure Pass ]
index 26c3f4eea94a4930938350bb1ee488f05034487c..2b4156466c13336e2b2d2db1ae51ec942ff8b2f1 100644 (file)
@@ -156,6 +156,11 @@ http/tests/cache/disk-cache
 http/tests/inspector/network/resource-response-source-disk-cache.html
 http/tests/inspector/network/resource-sizes-disk-cache.html
 
+# Async image decoding is WK2 only
+fast/images/async-image-background-change.html
+fast/images/async-image-src-change.html
+http/tests/multipart/multipart-async-image.html
+
 [ Yosemite+ ] fast/ruby/ruby-expansion-cjk-2.html [ ImageOnlyFailure ]
 
 # ShouldOpenExternalURLs not yet supported in WK1
index f98d6b43123f3e29b647beca4367b7dbe8ab72a7..bfadf01be5e15d1f6f1c12214f761d60bbe9bd52 100644 (file)
@@ -1,3 +1,98 @@
+2017-07-25  Said Abou-Hallawa  <sabouhallawa@apple.com>
+
+        Async image decoding for large images should be disabled after the first time a tile is painted
+        https://bugs.webkit.org/show_bug.cgi?id=174451
+        <rdar://problem/31246421>
+
+        Reviewed by Simon Fraser.
+
+        Flashing because of DOM mutation can be fixed by disabling the asynchronous
+        image decoding after the first time a tile was painted.
+
+        We can detect this by consulting the tile repaintCount. If it is zero, then
+        it is safe to use asynchronous image decoded. If the tile repaintCount is
+        greater than zero, we are not sure if the renderer rectangle has an image
+        drawn in it already or not. In this case we have to use the synchronous
+        image decoding to avoid causing a flash.
+
+        Tests: fast/images/async-image-background-change.html
+               fast/images/async-image-src-change.html
+               http/tests/multipart/multipart-async-image.html
+
+        * html/shadow/MediaControlElements.cpp:
+        (WebCore::MediaControlTextTrackContainerElement::createTextTrackRepresentationImage):
+        * page/FrameView.cpp:
+        (WebCore::FrameView::willPaintContents):
+        (WebCore::FrameView::paintContentsForSnapshot):
+        * page/PageOverlayController.cpp:
+        (WebCore::PageOverlayController::paintContents):
+        * page/PageOverlayController.h:
+        * page/linux/ResourceUsageOverlayLinux.cpp:
+        * page/mac/ServicesOverlayController.h:
+        * page/mac/ServicesOverlayController.mm:
+        (WebCore::ServicesOverlayController::Highlight::paintContents):
+        * platform/graphics/BitmapImage.cpp:
+        (WebCore::BitmapImage::draw):
+        * platform/graphics/BitmapImage.h:
+        * platform/graphics/GraphicsLayer.cpp:
+        (WebCore::GraphicsLayer::paintGraphicsLayerContents):
+        * platform/graphics/GraphicsLayer.h:
+        * platform/graphics/GraphicsLayerClient.h:
+        (WebCore::GraphicsLayerClient::paintContents):
+        * platform/graphics/avfoundation/cf/MediaPlayerPrivateAVFoundationCF.cpp:
+        (WebCore::LayerClient::platformCALayerPaintContents):
+        * platform/graphics/ca/GraphicsLayerCA.cpp:
+        (WebCore::GraphicsLayerCA::platformCALayerPaintContents):
+        * platform/graphics/ca/GraphicsLayerCA.h:
+        * platform/graphics/ca/PlatformCALayer.h:
+        * platform/graphics/ca/PlatformCALayerClient.h:
+        (WebCore::PlatformCALayerClient::platformCALayerRepaintCount):
+        * platform/graphics/ca/TileCoverageMap.cpp:
+        (WebCore::TileCoverageMap::platformCALayerPaintContents):
+        * platform/graphics/ca/TileCoverageMap.h:
+        * platform/graphics/ca/TileGrid.cpp:
+        (WebCore::TileGrid::platformCALayerPaintContents):
+        (WebCore::TileGrid::platformCALayerRepaintCount):
+        * platform/graphics/ca/TileGrid.h:
+        * platform/graphics/ca/cocoa/PlatformCALayerCocoa.mm:
+        (PlatformCALayer::drawLayerContents):
+        * platform/graphics/ca/win/PlatformCALayerWin.cpp:
+        (PlatformCALayer::drawLayerContents):
+        * platform/graphics/ca/win/PlatformCALayerWinInternal.cpp:
+        (PlatformCALayerWinInternal::displayCallback):
+        * platform/graphics/ca/win/WebTiledBackingLayerWin.cpp:
+        (WebTiledBackingLayerWin::displayCallback):
+        * platform/graphics/mac/WebLayer.mm:
+        (-[WebLayer drawInContext:]):
+        (-[WebSimpleLayer drawInContext:]):
+        * rendering/PaintPhase.h:
+        * rendering/RenderBoxModelObject.cpp:
+        (WebCore::RenderBoxModelObject::decodingModeForImageDraw):
+        * rendering/RenderElement.h:
+        * rendering/RenderLayer.cpp:
+        (WebCore::RenderLayer::paintLayerContents):
+        (WebCore::RenderLayer::paintForegroundForFragments):
+        * rendering/RenderLayerBacking.cpp:
+        (WebCore::RenderLayerBacking::paintContents):
+        * rendering/RenderLayerBacking.h:
+        * rendering/RenderLayerCompositor.cpp:
+        (WebCore::RenderLayerCompositor::paintContents):
+        * rendering/RenderLayerCompositor.h:
+        * rendering/RenderWidget.cpp:
+        (WebCore::RenderWidget::paintContents):
+        * testing/Internals.cpp:
+        (WebCore::imageFromImageElement):
+        (WebCore::bitmapImageFromImageElement):
+        (WebCore::Internals::imageFrameIndex):
+        (WebCore::Internals::setImageFrameDecodingDuration):
+        (WebCore::Internals::resetImageAnimation):
+        (WebCore::Internals::isImageAnimating):
+        (WebCore::Internals::setClearDecoderAfterAsyncFrameRequestForTesting):
+        (WebCore::Internals::imageDecodeCount):
+        (WebCore::Internals::setLargeImageAsyncDecodingEnabledForTesting):
+        * testing/Internals.h:
+        * testing/Internals.idl:
+
 2017-07-23  Sam Weinig  <sam@webkit.org>
 
         [WebIDL] Add support for generating timer bindings
index 1df277ab68262649b35979eee8bda75803337105..543f61f9e87350d5786ddd66e4774e75354be616 100644 (file)
@@ -1409,7 +1409,7 @@ RefPtr<Image> MediaControlTextTrackContainerElement::createTextTrackRepresentati
     if (!buffer)
         return nullptr;
 
-    layer->paint(buffer->context(), paintingRect, LayoutSize(), PaintBehaviorFlattenCompositingLayers, nullptr, RenderLayer::PaintLayerPaintingCompositingAllPhases);
+    layer->paint(buffer->context(), paintingRect, LayoutSize(), PaintBehaviorFlattenCompositingLayers | PaintBehaviorSnapshotting, nullptr, RenderLayer::PaintLayerPaintingCompositingAllPhases);
 
     return ImageBuffer::sinkIntoImage(WTFMove(buffer));
 }
index 61d140a943066be1b147345ba4815668df25c572..7b5dc6cde440d83575863a15547f04f030cee166 100644 (file)
@@ -4405,13 +4405,16 @@ void FrameView::willPaintContents(GraphicsContext& context, const IntRect&, Pain
     if (FrameView* parentView = parentFrameView()) {
         if (parentView->paintBehavior() & PaintBehaviorFlattenCompositingLayers)
             m_paintBehavior |= PaintBehaviorFlattenCompositingLayers;
-            
-        if (parentView->paintBehavior() & PaintBehaviorAllowAsyncImageDecoding)
-            m_paintBehavior |= PaintBehaviorAllowAsyncImageDecoding;
+        
+        if (parentView->paintBehavior() & PaintBehaviorSnapshotting)
+            m_paintBehavior |= PaintBehaviorSnapshotting;
+        
+        if (parentView->paintBehavior() & PaintBehaviorTileFirstPaint)
+            m_paintBehavior |= PaintBehaviorTileFirstPaint;
     }
 
     if (document->printing())
-        m_paintBehavior = (m_paintBehavior & ~PaintBehaviorAllowAsyncImageDecoding) | PaintBehaviorFlattenCompositingLayers;
+        m_paintBehavior |= (PaintBehaviorFlattenCompositingLayers | PaintBehaviorSnapshotting);
 
     paintingState.isFlatteningPaintOfRootFrame = (m_paintBehavior & PaintBehaviorFlattenCompositingLayers) && !frame().ownerElement();
     if (paintingState.isFlatteningPaintOfRootFrame)
@@ -4531,7 +4534,7 @@ void FrameView::paintContentsForSnapshot(GraphicsContext& context, const IntRect
 
     // Cache paint behavior and set a new behavior appropriate for snapshots.
     PaintBehavior oldBehavior = paintBehavior();
-    setPaintBehavior((oldBehavior & ~PaintBehaviorAllowAsyncImageDecoding) | PaintBehaviorFlattenCompositingLayers);
+    setPaintBehavior(oldBehavior | (PaintBehaviorFlattenCompositingLayers | PaintBehaviorSnapshotting));
 
     // If the snapshot should exclude selection, then we'll clear the current selection
     // in the render tree only. This will allow us to restore the selection from the DOM
index 4241a4bfe2b991f6e71a4ee352483716dfa60cb6..2ca7ef056112eb542cf202278648768b7e90f118 100644 (file)
@@ -360,7 +360,7 @@ Vector<String> PageOverlayController::copyAccessibilityAttributesNames(bool para
     return { };
 }
 
-void PageOverlayController::paintContents(const WebCore::GraphicsLayer* graphicsLayer, WebCore::GraphicsContext& graphicsContext, WebCore::GraphicsLayerPaintingPhase, const WebCore::FloatRect& clipRect, GraphicsLayerPaintFlags)
+void PageOverlayController::paintContents(const WebCore::GraphicsLayer* graphicsLayer, WebCore::GraphicsContext& graphicsContext, WebCore::GraphicsLayerPaintingPhase, const WebCore::FloatRect& clipRect, GraphicsLayerPaintBehavior)
 {
     for (auto& overlayAndGraphicsLayer : m_overlayGraphicsLayers) {
         if (overlayAndGraphicsLayer.value.get() != graphicsLayer)
index b96451ad90973b24632d9ab847c64ce8be5e65ba..a329459f496ab017390c61724f9881d03a353afe 100644 (file)
@@ -88,7 +88,7 @@ private:
 
     // GraphicsLayerClient
     void notifyFlushRequired(const GraphicsLayer*) override;
-    void paintContents(const GraphicsLayer*, GraphicsContext&, GraphicsLayerPaintingPhase, const FloatRect& clipRect, GraphicsLayerPaintFlags) override;
+    void paintContents(const GraphicsLayer*, GraphicsContext&, GraphicsLayerPaintingPhase, const FloatRect& clipRect, GraphicsLayerPaintBehavior) override;
     float deviceScaleFactor() const override;
     bool shouldSkipLayerInDump(const GraphicsLayer*, LayerTreeAsTextBehavior) const override;
     void tiledBackingUsageChanged(const GraphicsLayer*, bool) override;
index ffc4942b2323ecb26ec85d9ff1c5b2dbfa00a67f..97f30b26803de232002964e9cd04d411e8fa4ebc 100644 (file)
@@ -85,7 +85,7 @@ public:
     }
 
 private:
-    void paintContents(const GraphicsLayer*, GraphicsContext& context, GraphicsLayerPaintingPhase, const FloatRect& clip, GraphicsLayerPaintFlags) override
+    void paintContents(const GraphicsLayer*, GraphicsContext& context, GraphicsLayerPaintingPhase, const FloatRect& clip, GraphicsLayerPaintBehavior) override
     {
         GraphicsContextStateSaver stateSaver(context);
         context.fillRect(clip, Color(0.0f, 0.0f, 0.0f, 0.8f));
index d3aab9fd616ac7bc37061a7d471b3fe83d366fb8..0fd4abf1c7fa5e1633025a7528fc57cb29b403cb 100644 (file)
@@ -82,7 +82,7 @@ private:
 
         // GraphicsLayerClient
         void notifyFlushRequired(const GraphicsLayer*) override;
-        void paintContents(const GraphicsLayer*, GraphicsContext&, GraphicsLayerPaintingPhase, const FloatRect& inClip, GraphicsLayerPaintFlags) override;
+        void paintContents(const GraphicsLayer*, GraphicsContext&, GraphicsLayerPaintingPhase, const FloatRect& inClip, GraphicsLayerPaintBehavior) override;
         float deviceScaleFactor() const override;
 
         void didFinishFadeOutAnimation();
index 6005291015d5ad7b0ebb9ffb0c0c7abebc8b28e4..60f76eab491540194a3dd454de09b9d21005d9ec 100644 (file)
@@ -129,7 +129,7 @@ void ServicesOverlayController::Highlight::notifyFlushRequired(const GraphicsLay
     page->chrome().client().scheduleCompositingLayerFlush();
 }
 
-void ServicesOverlayController::Highlight::paintContents(const GraphicsLayer*, GraphicsContext& graphicsContext, GraphicsLayerPaintingPhase, const FloatRect&, GraphicsLayerPaintFlags)
+void ServicesOverlayController::Highlight::paintContents(const GraphicsLayer*, GraphicsContext& graphicsContext, GraphicsLayerPaintingPhase, const FloatRect&, GraphicsLayerPaintBehavior)
 {
     if (!DataDetectorsLibrary())
         return;
index bc16b406e7f2fe9fe2b0cc756c5e69fa62b0f474..e49a6c3688ac2d4886a342f0caa67242360c8f57 100644 (file)
@@ -193,7 +193,7 @@ ImageDrawResult BitmapImage::draw(GraphicsContext& context, const FloatRect& des
     LOG(Images, "BitmapImage::%s - %p - url: %s [subsamplingLevel = %d scaleFactorForDrawing = (%.4f, %.4f)]", __FUNCTION__, this, sourceURL().string().utf8().data(), static_cast<int>(m_currentSubsamplingLevel), scaleFactorForDrawing.width(), scaleFactorForDrawing.height());
 
     NativeImagePtr image;
-    if (decodingMode == DecodingMode::Asynchronous && !canAnimate()) {
+    if (decodingMode == DecodingMode::Asynchronous) {
         ASSERT(!canAnimate());
         ASSERT(!m_currentFrame || m_animationFinished);
 
@@ -218,7 +218,7 @@ ImageDrawResult BitmapImage::draw(GraphicsContext& context, const FloatRect& des
         }
 
         image = frameImageAtIndex(m_currentFrame);
-        LOG(Images, "BitmapImage::%s - %p - url: %s [a decoded image frame is available for drawing]", __FUNCTION__, this, sourceURL().string().utf8().data());
+        LOG(Images, "BitmapImage::%s - %p - url: %s [a decoded frame will be used for asynchronous drawing]", __FUNCTION__, this, sourceURL().string().utf8().data());
     } else {
         StartAnimationStatus status = internalStartAnimation();
         ASSERT_IMPLIES(status == StartAnimationStatus::DecodingActive, (!m_currentFrame && !m_repetitionsComplete) || frameHasFullSizeNativeImageAtIndex(m_currentFrame, m_currentSubsamplingLevel));
@@ -227,17 +227,30 @@ ImageDrawResult BitmapImage::draw(GraphicsContext& context, const FloatRect& des
             fillWithSolidColor(context, destRect, Color(Color::yellow).colorWithAlpha(0.5), op);
             return result;
         }
-
-        if (frameIsBeingDecodedAndIsCompatibleWithOptionsAtIndex(m_currentFrame, DecodingMode::Asynchronous)) {
+        
+        // If the decodingMode changes from asynchronous to synchronous and new data is received,
+        // the current incomplete decoded frame has to be destroyed.
+        if (m_currentFrameDecodingStatus == DecodingStatus::Invalid)
+            m_source.destroyIncompleteDecodedData();
+        
+        bool frameIsCompatible = frameHasDecodedNativeImageCompatibleWithOptionsAtIndex(m_currentFrame, m_currentSubsamplingLevel, DecodingOptions(sizeForDrawing));
+        bool frameIsBeingDecoded = frameIsBeingDecodedAndIsCompatibleWithOptionsAtIndex(m_currentFrame, DecodingMode::Asynchronous);
+        
+        if (frameIsCompatible) {
+            image = frameImageAtIndex(m_currentFrame);
+            LOG(Images, "BitmapImage::%s - %p - url: %s [a decoded frame will reused for synchronous drawing]", __FUNCTION__, this, sourceURL().string().utf8().data());
+        } else if (frameIsBeingDecoded) {
             // FIXME: instead of showing the yellow rectangle and returning we need to wait for this frame to finish decoding.
             if (m_showDebugBackground) {
                 fillWithSolidColor(context, destRect, Color(Color::yellow).colorWithAlpha(0.5), op);
                 LOG(Images, "BitmapImage::%s - %p - url: %s [waiting for async decoding to finish]", __FUNCTION__, this, sourceURL().string().utf8().data());
             }
             return ImageDrawResult::DidRequestDecoding;
+        } else {
+            image = frameImageAtIndexCacheIfNeeded(m_currentFrame, m_currentSubsamplingLevel, &context);
+            LOG(Images, "BitmapImage::%s - %p - url: %s [an image frame will be decoded synchronously]", __FUNCTION__, this, sourceURL().string().utf8().data());
         }
-
-        image = frameImageAtIndexCacheIfNeeded(m_currentFrame, m_currentSubsamplingLevel, &context);
+        
         if (!image) // If it's too early we won't have an image yet.
             return ImageDrawResult::DidNothing;
 
index df9bb78a1db34807efe68d2a02c13f977fc8cc35..0a20c6da572e23d5ec8d8a7e168e951286829763 100644 (file)
@@ -107,6 +107,8 @@ public:
     bool canUseAsyncDecodingForLargeImages() const;
     bool shouldUseAsyncDecodingForAnimatedImages() const;
     void setClearDecoderAfterAsyncFrameRequestForTesting(bool value) { m_clearDecoderAfterAsyncFrameRequestForTesting = value; }
+    void setLargeImageAsyncDecodingEnabledForTesting(bool enabled) { m_largeImageAsyncDecodingEnabledForTesting = enabled; }
+    bool isLargeImageAsyncDecodingEnabledForTesting() const { return m_largeImageAsyncDecodingEnabledForTesting; }
 
     WEBCORE_EXPORT unsigned decodeCountForTesting() const;
 
@@ -224,6 +226,7 @@ private:
     bool m_showDebugBackground { false };
 
     bool m_clearDecoderAfterAsyncFrameRequestForTesting { false };
+    bool m_largeImageAsyncDecodingEnabledForTesting { false };
 
 #if !LOG_DISABLED
     size_t m_lateFrameCount { 0 };
index d12193be6a21f1ce306c5d04811995acc2fb56ab..28c34b69d487692efdb3ab77785cd6fca7263bf1 100644 (file)
@@ -418,7 +418,7 @@ void GraphicsLayer::setBackgroundColor(const Color& color)
     m_backgroundColor = color;
 }
 
-void GraphicsLayer::paintGraphicsLayerContents(GraphicsContext& context, const FloatRect& clip, GraphicsLayerPaintFlags flags)
+void GraphicsLayer::paintGraphicsLayerContents(GraphicsContext& context, const FloatRect& clip, GraphicsLayerPaintBehavior layerPaintBehavior)
 {
     FloatSize offset = offsetFromRenderer();
     context.translate(-offset);
@@ -426,7 +426,7 @@ void GraphicsLayer::paintGraphicsLayerContents(GraphicsContext& context, const F
     FloatRect clipRect(clip);
     clipRect.move(offset);
 
-    m_client.paintContents(this, context, m_paintingPhase, clipRect, flags);
+    m_client.paintContents(this, context, m_paintingPhase, clipRect, layerPaintBehavior);
 }
 
 String GraphicsLayer::animationNameForTransition(AnimatedPropertyID property)
index 3d1459c0813a98ae40052dede019b33f9989beb8..d234bb2b01dbbe4bac5b19d09c3411333d8f1901 100644 (file)
@@ -466,7 +466,7 @@ public:
     virtual bool usesContentsLayer() const { return false; }
 
     // Callback from the underlying graphics system to draw layer contents.
-    void paintGraphicsLayerContents(GraphicsContext&, const FloatRect& clip, GraphicsLayerPaintFlags = GraphicsLayerPaintFlags::AllowAsyncImageDecoding);
+    void paintGraphicsLayerContents(GraphicsContext&, const FloatRect& clip, GraphicsLayerPaintBehavior = GraphicsLayerPaintNormal);
 
     // For hosting this GraphicsLayer in a native layer hierarchy.
     virtual PlatformLayer* platformLayer() const { return 0; }
index 38f629ecade60a38555090a2bdcf3f3d57bb81ee..9f2ce11a3c64078a1072dbcadab30e3283690566 100644 (file)
@@ -75,7 +75,12 @@ enum LayerTreeAsTextBehaviorFlags {
 };
 typedef unsigned LayerTreeAsTextBehavior;
 
-enum class GraphicsLayerPaintFlags { None, AllowAsyncImageDecoding };
+enum GraphicsLayerPaintFlags {
+    GraphicsLayerPaintNormal                    = 0,
+    GraphicsLayerPaintSnapshotting              = 1 << 0,
+    GraphicsLayerPaintFirstTilePaint            = 1 << 1,
+};
+typedef unsigned GraphicsLayerPaintBehavior;
     
 class GraphicsLayerClient {
 public:
@@ -94,7 +99,7 @@ public:
     // Notification that this layer requires a flush before the next display refresh.
     virtual void notifyFlushBeforeDisplayRefresh(const GraphicsLayer*) { }
 
-    virtual void paintContents(const GraphicsLayer*, GraphicsContext&, GraphicsLayerPaintingPhase, const FloatRect& /* inClip */, GraphicsLayerPaintFlags) { }
+    virtual void paintContents(const GraphicsLayer*, GraphicsContext&, GraphicsLayerPaintingPhase, const FloatRect& /* inClip */, GraphicsLayerPaintBehavior) { }
     virtual void didCommitChangesForLayer(const GraphicsLayer*) const { }
 
     // Provides current transform (taking transform-origin and animations into account). Input matrix has been
index f8ef4d5be44a75aba24e7635296f921b16e81bcb..9035244aa7a149e06157f0cb8f66b7754bf86582 100644 (file)
@@ -220,7 +220,7 @@ private:
 
     virtual void platformCALayerAnimationStarted(CFTimeInterval beginTime) { }
     virtual GraphicsLayer::CompositingCoordinatesOrientation platformCALayerContentsOrientation() const { return GraphicsLayer::CompositingCoordinatesBottomUp; }
-    virtual void platformCALayerPaintContents(PlatformCALayer*, GraphicsContext&, const FloatRect&, GraphicsLayerPaintFlags) { }
+    virtual void platformCALayerPaintContents(PlatformCALayer*, GraphicsContext&, const FloatRect&, GraphicsLayerPaintBehavior) { }
     virtual bool platformCALayerShowDebugBorders() const { return false; }
     virtual bool platformCALayerShowRepaintCounter(PlatformCALayer*) const { return false; }
     virtual int platformCALayerIncrementRepaintCount(PlatformCALayer*) { return 0; }
index 6d9df5be61e64c654d84ed0de1123cdc624d0cfd..37d3b012a7bec4c0dbe24d7cc8b67fbe8cb8e296 100644 (file)
@@ -1579,7 +1579,7 @@ bool GraphicsLayerCA::platformCALayerShowRepaintCounter(PlatformCALayer* platfor
     return isShowingRepaintCounter();
 }
 
-void GraphicsLayerCA::platformCALayerPaintContents(PlatformCALayer*, GraphicsContext& context, const FloatRect& clip, GraphicsLayerPaintFlags flags)
+void GraphicsLayerCA::platformCALayerPaintContents(PlatformCALayer*, GraphicsContext& context, const FloatRect& clip, GraphicsLayerPaintBehavior layerPaintBehavior)
 {
     m_hasEverPainted = true;
     if (m_displayList) {
@@ -1595,7 +1595,7 @@ void GraphicsLayerCA::platformCALayerPaintContents(PlatformCALayer*, GraphicsCon
     }
 
     TraceScope tracingScope(PaintLayerStart, PaintLayerEnd);
-    paintGraphicsLayerContents(context, clip, flags);
+    paintGraphicsLayerContents(context, clip, layerPaintBehavior);
 }
 
 void GraphicsLayerCA::platformCALayerSetNeedsToRevalidateTiles()
index a3cdca5baca443f5f55ab4cd1871174f6938bae2..f7fbd233f52b9533f47fef669818609c83b2259f 100644 (file)
@@ -188,9 +188,10 @@ private:
     WEBCORE_EXPORT void platformCALayerAnimationStarted(const String& animationKey, CFTimeInterval beginTime) override;
     WEBCORE_EXPORT void platformCALayerAnimationEnded(const String& animationKey) override;
     CompositingCoordinatesOrientation platformCALayerContentsOrientation() const override { return contentsOrientation(); }
-    WEBCORE_EXPORT void platformCALayerPaintContents(PlatformCALayer*, GraphicsContext&, const FloatRect& clip, GraphicsLayerPaintFlags) override;
+    WEBCORE_EXPORT void platformCALayerPaintContents(PlatformCALayer*, GraphicsContext&, const FloatRect& clip, GraphicsLayerPaintBehavior) override;
     bool platformCALayerShowDebugBorders() const override { return isShowingDebugBorder(); }
     WEBCORE_EXPORT bool platformCALayerShowRepaintCounter(PlatformCALayer*) const override;
+    int platformCALayerRepaintCount(PlatformCALayer*) const override { return repaintCount(); }
     int platformCALayerIncrementRepaintCount(PlatformCALayer*) override { return incrementRepaintCount(); }
 
     bool platformCALayerContentsOpaque() const override { return contentsOpaque(); }
index 88a29a0ad9f6633cc59e7ada983e3f8bb94ef354..9361cf706e5da880b5be18537046cb604a7872ba 100644 (file)
@@ -276,7 +276,7 @@ public:
         
     // Functions allows us to share implementation across WebTiledLayer and WebLayer
     static RepaintRectList collectRectsToPaint(CGContextRef, PlatformCALayer*);
-    static void drawLayerContents(CGContextRef, PlatformCALayer*, RepaintRectList& dirtyRects, GraphicsLayerPaintFlags);
+    static void drawLayerContents(CGContextRef, PlatformCALayer*, RepaintRectList& dirtyRects, GraphicsLayerPaintBehavior);
     static void drawRepaintIndicator(CGContextRef, PlatformCALayer*, int repaintCount, CGColorRef customBackgroundColor);
     static CGRect frameForLayer(const PlatformLayer*);
 
index a36f34586d75eacfe3990759a99c2c366ff57498..fd332f0b1fb6442cf6b376b916bedaa1af0209ef 100644 (file)
@@ -43,9 +43,10 @@ public:
     virtual void platformCALayerAnimationStarted(const String& /*animationKey*/, CFTimeInterval) { }
     virtual void platformCALayerAnimationEnded(const String& /*animationKey*/) { }
     virtual GraphicsLayer::CompositingCoordinatesOrientation platformCALayerContentsOrientation() const { return GraphicsLayer::CompositingCoordinatesTopDown; }
-    virtual void platformCALayerPaintContents(PlatformCALayer*, GraphicsContext&, const FloatRect& inClip, GraphicsLayerPaintFlags) = 0;
+    virtual void platformCALayerPaintContents(PlatformCALayer*, GraphicsContext&, const FloatRect& inClip, GraphicsLayerPaintBehavior) = 0;
     virtual bool platformCALayerShowDebugBorders() const { return false; }
     virtual bool platformCALayerShowRepaintCounter(PlatformCALayer*) const { return false; }
+    virtual int platformCALayerRepaintCount(PlatformCALayer*) const { return 0; }
     virtual int platformCALayerIncrementRepaintCount(PlatformCALayer*) { return 0; }
     
     virtual bool platformCALayerContentsOpaque() const = 0;
index d62c7f574eef34f3ff71bf06257b23e755c81d3e..f54fc9907704a216ef6bb4744eed55ce1faa693f 100644 (file)
@@ -152,7 +152,7 @@ void TileCoverageMap::update()
     m_visibleViewportIndicatorLayer.get().setBorderColor(visibleRectIndicatorColor);
 }
 
-void TileCoverageMap::platformCALayerPaintContents(PlatformCALayer* platformCALayer, GraphicsContext& context, const FloatRect&, GraphicsLayerPaintFlags)
+void TileCoverageMap::platformCALayerPaintContents(PlatformCALayer* platformCALayer, GraphicsContext& context, const FloatRect&, GraphicsLayerPaintBehavior)
 {
     ASSERT_UNUSED(platformCALayer, platformCALayer == m_layer.ptr());
     m_controller.tileGrid().drawTileMapContents(context.platformContext(), m_layer.get().bounds());
index ab43a5606d280fc463da294789cd6564d8a48178..360b23196d84215298e6ee5e4d7c563a90c2f957 100644 (file)
@@ -61,7 +61,7 @@ private:
     GraphicsLayer::CompositingCoordinatesOrientation platformCALayerContentsOrientation() const override { return GraphicsLayer::CompositingCoordinatesTopDown; }
     bool platformCALayerContentsOpaque() const override { return true; }
     bool platformCALayerDrawsContent() const override { return true; }
-    void platformCALayerPaintContents(PlatformCALayer*, GraphicsContext&, const FloatRect&, GraphicsLayerPaintFlags) override;
+    void platformCALayerPaintContents(PlatformCALayer*, GraphicsContext&, const FloatRect&, GraphicsLayerPaintBehavior) override;
     float platformCALayerDeviceScaleFactor() const override;
 
     void updateTimerFired();
index 07fa9604838111ea69520dd6300cfd0bc749b89d..cb1687351d58e867b030d7f55b7b4d3e82c59e74 100644 (file)
@@ -712,13 +712,16 @@ void TileGrid::drawTileMapContents(CGContextRef context, CGRect layerBounds) con
     }
 }
 
-void TileGrid::platformCALayerPaintContents(PlatformCALayer* platformCALayer, GraphicsContext& context, const FloatRect&, GraphicsLayerPaintFlags flags)
+void TileGrid::platformCALayerPaintContents(PlatformCALayer* platformCALayer, GraphicsContext& context, const FloatRect&, GraphicsLayerPaintBehavior layerPaintBehavior)
 {
 #if PLATFORM(IOS)
     if (pthread_main_np())
         WebThreadLock();
 #endif
 
+    if (!platformCALayerRepaintCount(platformCALayer))
+        layerPaintBehavior |= GraphicsLayerPaintFirstTilePaint;
+
     {
         GraphicsContextStateSaver stateSaver(context);
 
@@ -727,7 +730,7 @@ void TileGrid::platformCALayerPaintContents(PlatformCALayer* platformCALayer, Gr
         context.scale(m_scale);
 
         PlatformCALayer::RepaintRectList dirtyRects = PlatformCALayer::collectRectsToPaint(context.platformContext(), platformCALayer);
-        PlatformCALayer::drawLayerContents(context.platformContext(), &m_controller.rootLayer(), dirtyRects, flags);
+        PlatformCALayer::drawLayerContents(context.platformContext(), &m_controller.rootLayer(), dirtyRects, layerPaintBehavior);
     }
 
     int repaintCount = platformCALayerIncrementRepaintCount(platformCALayer);
@@ -768,6 +771,12 @@ bool TileGrid::platformCALayerContentsOpaque() const
     return m_controller.tilesAreOpaque();
 }
 
+int TileGrid::platformCALayerRepaintCount(PlatformCALayer* platformCALayer) const
+{
+    const auto it = m_tileRepaintCounts.find(platformCALayer);
+    return it != m_tileRepaintCounts.end() ? it->value : 0;
+}
+
 int TileGrid::platformCALayerIncrementRepaintCount(PlatformCALayer* platformCALayer)
 {
     int repaintCount = 0;
index 8ca5c0440a51db25da3c1ed18b28f576f6b58af8..9835d2fe97667828b2cc01a579ac8bb2c7d9c65b 100644 (file)
@@ -143,9 +143,10 @@ private:
     void removeTiles(Vector<TileGrid::TileIndex>& toRemove);
 
     // PlatformCALayerClient
-    void platformCALayerPaintContents(PlatformCALayer*, GraphicsContext&, const FloatRect&, GraphicsLayerPaintFlags) override;
+    void platformCALayerPaintContents(PlatformCALayer*, GraphicsContext&, const FloatRect&, GraphicsLayerPaintBehavior) override;
     bool platformCALayerShowDebugBorders() const override;
     bool platformCALayerShowRepaintCounter(PlatformCALayer*) const override;
+    int platformCALayerRepaintCount(PlatformCALayer*) const override;
     int platformCALayerIncrementRepaintCount(PlatformCALayer*) override;
     bool platformCALayerContentsOpaque() const override;
     bool platformCALayerDrawsContent() const override { return true; }
index 8d9c5984653dce8afc58d41df4263f4b96e6950e..5c9b42ed1528ca4e3efa7a9428c90002498b0a44 100644 (file)
@@ -1119,12 +1119,15 @@ PlatformCALayer::RepaintRectList PlatformCALayer::collectRectsToPaint(CGContextR
     return dirtyRects;
 }
 
-void PlatformCALayer::drawLayerContents(CGContextRef context, WebCore::PlatformCALayer* platformCALayer, RepaintRectList& dirtyRects, GraphicsLayerPaintFlags flags)
+void PlatformCALayer::drawLayerContents(CGContextRef context, WebCore::PlatformCALayer* platformCALayer, RepaintRectList& dirtyRects, GraphicsLayerPaintBehavior layerPaintBehavior)
 {
     WebCore::PlatformCALayerClient* layerContents = platformCALayer->owner();
     if (!layerContents)
         return;
-    
+
+    if (!layerContents->platformCALayerRepaintCount(platformCALayer))
+        layerPaintBehavior |= GraphicsLayerPaintFirstTilePaint;
+
 #if PLATFORM(IOS)
     WKSetCurrentGraphicsContext(context);
 #endif
@@ -1166,7 +1169,7 @@ void PlatformCALayer::drawLayerContents(CGContextRef context, WebCore::PlatformC
             GraphicsContextStateSaver stateSaver(graphicsContext);
             graphicsContext.clip(rect);
             
-            layerContents->platformCALayerPaintContents(platformCALayer, graphicsContext, rect, flags);
+            layerContents->platformCALayerPaintContents(platformCALayer, graphicsContext, rect, layerPaintBehavior);
         }
         
 #if PLATFORM(IOS)
index 83c3f1cfa5b7d558158974b40931ef1b49fbed7e..d107b14dd5ecfc4b11138884f1dc6e5bf4ca5dfd 100644 (file)
@@ -109,7 +109,7 @@ PlatformCALayer::RepaintRectList PlatformCALayer::collectRectsToPaint(CGContextR
     return dirtyRects;
 }
 
-void PlatformCALayer::drawLayerContents(CGContextRef context, WebCore::PlatformCALayer* platformCALayer, RepaintRectList&, GraphicsLayerPaintFlags)
+void PlatformCALayer::drawLayerContents(CGContextRef context, WebCore::PlatformCALayer* platformCALayer, RepaintRectList&, GraphicsLayerPaintBehavior)
 {
     intern(platformCALayer)->displayCallback(platformCALayer->platformLayer(), context);
 }
index f408a951ec23576f994deead20e2c40e2009602c..36795c140cc758160ad26ef29b584c519532eb89 100644 (file)
@@ -104,7 +104,7 @@ void PlatformCALayerWinInternal::displayCallback(CACFLayerRef caLayer, CGContext
     // smaller than the layer bounds (e.g. tiled layers)
     CGRect clipBounds = CGContextGetClipBoundingBox(context);
     IntRect clip(enclosingIntRect(clipBounds));
-    client->platformCALayerPaintContents(owner(), graphicsContext, clip, GraphicsLayerPaintFlags::None);
+    client->platformCALayerPaintContents(owner(), graphicsContext, clip, GraphicsLayerPaintNormal);
 
     if (client->platformCALayerShowRepaintCounter(owner())
         && !repaintCountersAreDrawnByGridController(layerType)) {
index d4ee57b68b479e45ceea58fd9735e83287cc88fb..46b573b0f635e2f3559ed07e7223e7d7320bbbaa 100644 (file)
@@ -95,7 +95,7 @@ void WebTiledBackingLayerWin::displayCallback(CACFLayerRef caLayer, CGContextRef
     // smaller than the layer bounds (e.g. tiled layers)
     CGRect clipBounds = CGContextGetClipBoundingBox(context);
     IntRect clip(enclosingIntRect(clipBounds));
-    client->platformCALayerPaintContents(owner(), graphicsContext, clip, GraphicsLayerPaintFlags::None);
+    client->platformCALayerPaintContents(owner(), graphicsContext, clip, GraphicsLayerPaintNormal);
 
     if (client->platformCALayerShowRepaintCounter(owner())) {
         int drawCount = client->platformCALayerIncrementRepaintCount(owner());
index 8b9d177e9c87d75a90dfafd4f4cd0fb6a03ea427..3fc76c9c404587200d673dfcf1c05befdd23d943 100644 (file)
@@ -57,7 +57,7 @@ using namespace WebCore;
     PlatformCALayer* layer = PlatformCALayer::platformCALayer(self);
     if (layer) {
         PlatformCALayer::RepaintRectList rectsToPaint = PlatformCALayer::collectRectsToPaint(context, layer);
-        PlatformCALayer::drawLayerContents(context, layer, rectsToPaint, self.isRenderingInContext ? GraphicsLayerPaintFlags::None : GraphicsLayerPaintFlags::AllowAsyncImageDecoding);
+        PlatformCALayer::drawLayerContents(context, layer, rectsToPaint, self.isRenderingInContext ? GraphicsLayerPaintSnapshotting : GraphicsLayerPaintNormal);
     }
 }
 
@@ -137,7 +137,7 @@ using namespace WebCore;
         graphicsContext.setIsAcceleratedContext(layer->acceleratesDrawing());
 
         FloatRect clipBounds = CGContextGetClipBoundingBox(context);
-        layer->owner()->platformCALayerPaintContents(layer, graphicsContext, clipBounds, self.isRenderingInContext ? GraphicsLayerPaintFlags::None : GraphicsLayerPaintFlags::AllowAsyncImageDecoding);
+        layer->owner()->platformCALayerPaintContents(layer, graphicsContext, clipBounds, self.isRenderingInContext ? GraphicsLayerPaintSnapshotting : GraphicsLayerPaintNormal);
     }
 }
 
index 256b4a50d311b45fcfb55e3fedd472133b2992f9..37dc98c875206ddcb0320b6710c845ae8123a623 100644 (file)
@@ -64,7 +64,8 @@ enum PaintBehaviorFlags {
     PaintBehaviorSelectionAndBackgroundsOnly = 1 << 7,
     PaintBehaviorExcludeSelection            = 1 << 8,
     PaintBehaviorFlattenCompositingLayers    = 1 << 9, // Paint doesn't stop at compositing layer boundaries.
-    PaintBehaviorAllowAsyncImageDecoding     = 1 << 10,
+    PaintBehaviorSnapshotting                = 1 << 10,
+    PaintBehaviorTileFirstPaint              = 1 << 11,
 };
 
 typedef unsigned PaintBehavior;
index e39640b36035e52562330841db9816ca0cbe9fa9..3da4638ea3dcf97417d27586391feeac0b7784bc 100644 (file)
@@ -324,11 +324,20 @@ DecodingMode RenderBoxModelObject::decodingModeForImageDraw(const Image& image,
     if (IOSApplication::isIBooksStorytime())
         return DecodingMode::Synchronous;
 #endif
+    if (bitmapImage.isLargeImageAsyncDecodingEnabledForTesting())
+        return DecodingMode::Asynchronous;
+    if (document().isImageDocument())
+        return DecodingMode::Synchronous;
+    if (paintInfo.paintBehavior & PaintBehaviorSnapshotting)
+        return DecodingMode::Synchronous;
     if (!settings().largeImageAsyncDecodingEnabled())
         return DecodingMode::Synchronous;
     if (!bitmapImage.canUseAsyncDecodingForLargeImages())
         return DecodingMode::Synchronous;
-    if (paintInfo.paintBehavior & PaintBehaviorAllowAsyncImageDecoding)
+    if (paintInfo.paintBehavior & PaintBehaviorTileFirstPaint)
+        return DecodingMode::Asynchronous;
+    // FIXME: isVisibleInViewport() is not cheap. Find a way to make this condition faster.
+    if (!isVisibleInViewport())
         return DecodingMode::Asynchronous;
     return DecodingMode::Synchronous;
 }
index 2eb2afc0e81065c0ee13f7501f612bd79f927f68..4f8226b5dd5950ef9350da6fa9de98ad530a1e0f 100644 (file)
@@ -287,6 +287,7 @@ protected:
     void adjustFlowThreadStateOnContainingBlockChangeIfNeeded();
     
     bool noLongerAffectsParentBlock() const { return s_noLongerAffectsParentBlock; }
+    bool isVisibleInViewport() const;
 
 private:
     RenderElement(ContainerNode&, RenderStyle&&, BaseTypeFlags);
@@ -316,7 +317,6 @@ private:
     std::unique_ptr<RenderStyle> computeFirstLineStyle() const;
     void invalidateCachedFirstLineStyle();
 
-    bool isVisibleInViewport() const;
     bool canDestroyDecodedData() final { return !isVisibleInViewport(); }
     VisibleInViewportState imageFrameAvailable(CachedImage&, ImageAnimatingState, const IntRect* changeRect) final;
     void didRemoveCachedImageClient(CachedImage&) final;
index e7a7ec9138cdbb6d1d5cf712bc088ee45d6662aa..d8f37931133692059882e534625f925c514d07d4 100644 (file)
@@ -4383,9 +4383,12 @@ void RenderLayer::paintLayerContents(GraphicsContext& context, const LayerPainti
 
         if (paintingInfo.paintBehavior & PaintBehaviorFlattenCompositingLayers)
             paintBehavior |= PaintBehaviorFlattenCompositingLayers;
-            
-        if (paintingInfo.paintBehavior & PaintBehaviorAllowAsyncImageDecoding)
-            paintBehavior |= PaintBehaviorAllowAsyncImageDecoding;
+        
+        if (paintingInfo.paintBehavior & PaintBehaviorSnapshotting)
+            paintBehavior |= PaintBehaviorSnapshotting;
+        
+        if (paintingInfo.paintBehavior & PaintBehaviorTileFirstPaint)
+            paintBehavior |= PaintBehaviorTileFirstPaint;
 
         if (paintingInfo.paintBehavior & PaintBehaviorExcludeSelection)
             paintBehavior |= PaintBehaviorExcludeSelection;
@@ -4465,9 +4468,12 @@ void RenderLayer::paintLayerContents(GraphicsContext& context, const LayerPainti
         PaintBehavior paintBehavior = PaintBehaviorNormal;
         if (paintingInfo.paintBehavior & PaintBehaviorFlattenCompositingLayers)
             paintBehavior |= PaintBehaviorFlattenCompositingLayers;
-
-        if (paintingInfo.paintBehavior & PaintBehaviorAllowAsyncImageDecoding)
-            paintBehavior |= PaintBehaviorAllowAsyncImageDecoding;
+        
+        if (paintingInfo.paintBehavior & PaintBehaviorSnapshotting)
+            paintBehavior |= PaintBehaviorSnapshotting;
+        
+        if (paintingInfo.paintBehavior & PaintBehaviorTileFirstPaint)
+            paintBehavior |= PaintBehaviorTileFirstPaint;
 
         if (shouldPaintMask(paintingInfo.paintBehavior, localPaintFlags)) {
             // Paint the mask for the fragments.
@@ -4797,9 +4803,12 @@ void RenderLayer::paintForegroundForFragments(const LayerFragments& layerFragmen
 
     if (localPaintingInfo.paintBehavior & PaintBehaviorExcludeSelection)
         localPaintBehavior |= PaintBehaviorExcludeSelection;
-
-    if (localPaintingInfo.paintBehavior & PaintBehaviorAllowAsyncImageDecoding)
-        localPaintBehavior |= PaintBehaviorAllowAsyncImageDecoding;
+    
+    if (localPaintingInfo.paintBehavior & PaintBehaviorSnapshotting)
+        localPaintBehavior |= PaintBehaviorSnapshotting;
+    
+    if (localPaintingInfo.paintBehavior & PaintBehaviorTileFirstPaint)
+        localPaintBehavior |= PaintBehaviorTileFirstPaint;
 
     // Optimize clipping for the single fragment case.
     bool shouldClip = localPaintingInfo.clipToDirtyRect && layerFragments.size() == 1 && layerFragments[0].shouldPaintContent && !layerFragments[0].foregroundRect.isEmpty();
index 6b8fa76d7ed582a22ce76e25dd1c1e68ab8d8f45..a66704cbb6edcae604c85544a66a403cfe8d70c0 100644 (file)
@@ -2569,7 +2569,7 @@ void RenderLayerBacking::paintIntoLayer(const GraphicsLayer* graphicsLayer, Grap
 }
 
 // Up-call from compositing layer drawing callback.
-void RenderLayerBacking::paintContents(const GraphicsLayer* graphicsLayer, GraphicsContext& context, GraphicsLayerPaintingPhase paintingPhase, const FloatRect& clip, GraphicsLayerPaintFlags flags)
+void RenderLayerBacking::paintContents(const GraphicsLayer* graphicsLayer, GraphicsContext& context, GraphicsLayerPaintingPhase paintingPhase, const FloatRect& clip, GraphicsLayerPaintBehavior layerPaintBehavior)
 {
 #ifndef NDEBUG
     renderer().page().setIsPainting(true);
@@ -2580,6 +2580,9 @@ void RenderLayerBacking::paintContents(const GraphicsLayer* graphicsLayer, Graph
     adjustedClipRect.move(m_subpixelOffsetFromRenderer);
     IntRect dirtyRect = enclosingIntRect(adjustedClipRect);
 
+    if (!graphicsLayer->repaintCount())
+        layerPaintBehavior |= GraphicsLayerPaintFirstTilePaint;
+
     if (graphicsLayer == m_graphicsLayer.get()
         || graphicsLayer == m_foregroundLayer.get()
         || graphicsLayer == m_backgroundLayer.get()
@@ -2593,8 +2596,11 @@ void RenderLayerBacking::paintContents(const GraphicsLayer* graphicsLayer, Graph
 
         // We have to use the same root as for hit testing, because both methods can compute and cache clipRects.
         PaintBehavior behavior = PaintBehaviorNormal;
-        if (flags == GraphicsLayerPaintFlags::AllowAsyncImageDecoding)
-            behavior |= PaintBehaviorAllowAsyncImageDecoding;
+        if (layerPaintBehavior == GraphicsLayerPaintSnapshotting)
+            behavior |= PaintBehaviorSnapshotting;
+        
+        if (layerPaintBehavior == GraphicsLayerPaintFirstTilePaint)
+            behavior |= PaintBehaviorTileFirstPaint;
 
         paintIntoLayer(graphicsLayer, context, dirtyRect, behavior, paintingPhase);
 
index 9338ae313592203706e3a7e9f288facd52a1e99c..b3a8ba16ce027f80e5e47035c4fa9acb3086e6b6 100644 (file)
@@ -197,7 +197,7 @@ public:
     void notifyFlushRequired(const GraphicsLayer*) override;
     void notifyFlushBeforeDisplayRefresh(const GraphicsLayer*) override;
 
-    void paintContents(const GraphicsLayer*, GraphicsContext&, GraphicsLayerPaintingPhase, const FloatRect& clip, GraphicsLayerPaintFlags) override;
+    void paintContents(const GraphicsLayer*, GraphicsContext&, GraphicsLayerPaintingPhase, const FloatRect& clip, GraphicsLayerPaintBehavior) override;
 
     float deviceScaleFactor() const override;
     float contentsScaleMultiplierForNewTiles(const GraphicsLayer*) const override;
index 6cf143cbcb3a56aea554c0e823a0f81b696722e8..2ff6b6cdde67936c6543ecf9b25764213e4ea48f 100644 (file)
@@ -2895,7 +2895,7 @@ void paintScrollbar(Scrollbar* scrollbar, GraphicsContext& context, const IntRec
     context.restore();
 }
 
-void RenderLayerCompositor::paintContents(const GraphicsLayer* graphicsLayer, GraphicsContext& context, GraphicsLayerPaintingPhase, const FloatRect& clip, GraphicsLayerPaintFlags)
+void RenderLayerCompositor::paintContents(const GraphicsLayer* graphicsLayer, GraphicsContext& context, GraphicsLayerPaintingPhase, const FloatRect& clip, GraphicsLayerPaintBehavior)
 {
     IntRect pixelSnappedRectForIntegralPositionedItems = snappedIntRect(LayoutRect(clip));
     if (graphicsLayer == layerForHorizontalScrollbar())
index 9841bab85bdb0cd3d1b42cf8b3b9b5ad98c25e83..dce0434a54e64c8d8f162963fe08c183f0f37925 100644 (file)
@@ -337,7 +337,7 @@ private:
 
     // GraphicsLayerClient implementation
     void notifyFlushRequired(const GraphicsLayer*) override;
-    void paintContents(const GraphicsLayer*, GraphicsContext&, GraphicsLayerPaintingPhase, const FloatRect&, GraphicsLayerPaintFlags) override;
+    void paintContents(const GraphicsLayer*, GraphicsContext&, GraphicsLayerPaintingPhase, const FloatRect&, GraphicsLayerPaintBehavior) override;
     void customPositionForVisibleRectComputation(const GraphicsLayer*, FloatPoint&) const override;
     bool isTrackingRepaints() const override;
     
index ab61f06431426de774906459204b7748a5243a6d..8c1e7d4ea9795555dc717cb619a14eec11ded908 100644 (file)
@@ -230,10 +230,10 @@ void RenderWidget::paintContents(PaintInfo& paintInfo, const LayoutPoint& paintO
     LayoutRect paintRect = paintInfo.rect;
 
     PaintBehavior oldBehavior = PaintBehaviorNormal;
-    if (is<FrameView>(*m_widget) && (paintInfo.paintBehavior & PaintBehaviorAllowAsyncImageDecoding)) {
+    if (is<FrameView>(*m_widget) && (paintInfo.paintBehavior & PaintBehaviorTileFirstPaint)) {
         FrameView& frameView = downcast<FrameView>(*m_widget);
         oldBehavior = frameView.paintBehavior();
-        frameView.setPaintBehavior(oldBehavior | PaintBehaviorAllowAsyncImageDecoding);
+        frameView.setPaintBehavior(oldBehavior | PaintBehaviorTileFirstPaint);
     }
 
     IntPoint widgetLocation = m_widget->frameRect().location();
@@ -257,7 +257,7 @@ void RenderWidget::paintContents(PaintInfo& paintInfo, const LayoutPoint& paintO
             ASSERT(!paintInfo.overlapTestRequests->contains(this) || (paintInfo.overlapTestRequests->get(this) == m_widget->frameRect()));
             paintInfo.overlapTestRequests->set(this, m_widget->frameRect());
         }
-        if (paintInfo.paintBehavior & PaintBehaviorAllowAsyncImageDecoding)
+        if (paintInfo.paintBehavior & PaintBehaviorTileFirstPaint)
             frameView.setPaintBehavior(oldBehavior);
     }
 }
index 9496b29f56de326d60cee4a7ca2896d8b747832c..367913418a413087821f06951e368e7edf356b0a 100644 (file)
@@ -737,79 +737,58 @@ unsigned Internals::memoryCacheSize() const
     return MemoryCache::singleton().size();
 }
 
-unsigned Internals::imageFrameIndex(HTMLImageElement& element)
+static Image* imageFromImageElement(HTMLImageElement& element)
 {
     auto* cachedImage = element.cachedImage();
-    if (!cachedImage)
-        return 0;
-
-    auto* image = cachedImage->image();
-    return is<BitmapImage>(image) ? downcast<BitmapImage>(*image).currentFrame() : 0;
+    return cachedImage ? cachedImage->image() : nullptr;
 }
 
-void Internals::setImageFrameDecodingDuration(HTMLImageElement& element, float duration)
+static BitmapImage* bitmapImageFromImageElement(HTMLImageElement& element)
 {
-    auto* cachedImage = element.cachedImage();
-    if (!cachedImage)
-        return;
+    auto* image = imageFromImageElement(element);
+    return image && is<BitmapImage>(image) ? &downcast<BitmapImage>(*image) : nullptr;
+}
 
-    auto* image = cachedImage->image();
-    if (!is<BitmapImage>(image))
-        return;
+unsigned Internals::imageFrameIndex(HTMLImageElement& element)
+{
+    auto* bitmapImage = bitmapImageFromImageElement(element);
+    return bitmapImage ? bitmapImage->currentFrame() : 0;
+}
 
-    downcast<BitmapImage>(*image).setFrameDecodingDurationForTesting(Seconds { duration });
+void Internals::setImageFrameDecodingDuration(HTMLImageElement& element, float duration)
+{
+    if (auto* bitmapImage = bitmapImageFromImageElement(element))
+        bitmapImage->setFrameDecodingDurationForTesting(Seconds { duration });
 }
 
 void Internals::resetImageAnimation(HTMLImageElement& element)
 {
-    auto* cachedImage = element.cachedImage();
-    if (!cachedImage)
-        return;
-
-    auto* image = cachedImage->image();
-    if (!is<BitmapImage>(image))
-        return;
-
-    image->resetAnimation();
+    if (auto* image = imageFromImageElement(element))
+        image->resetAnimation();
 }
 
 bool Internals::isImageAnimating(HTMLImageElement& element)
 {
-    auto* cachedImage = element.cachedImage();
-    if (!cachedImage)
-        return false;
-
-    auto* image = cachedImage->image();
-    if (!image)
-        return false;
-
-    return image->isAnimating() || image->animationPending();
+    auto* image = imageFromImageElement(element);
+    return image && (image->isAnimating() || image->animationPending());
 }
 
-void Internals::setClearDecoderAfterAsyncFrameRequestForTesting(HTMLImageElement& element, bool value)
+void Internals::setClearDecoderAfterAsyncFrameRequestForTesting(HTMLImageElement& element, bool enabled)
 {
-    auto* cachedImage = element.cachedImage();
-    if (!cachedImage)
-        return;
-
-    auto* image = cachedImage->image();
-    if (!is<BitmapImage>(image))
-        return;
-
-    downcast<BitmapImage>(*image).setClearDecoderAfterAsyncFrameRequestForTesting(value);
+    if (auto* bitmapImage = bitmapImageFromImageElement(element))
+        bitmapImage->setClearDecoderAfterAsyncFrameRequestForTesting(enabled);
 }
 
 unsigned Internals::imageDecodeCount(HTMLImageElement& element)
 {
-    auto* cachedImage = element.cachedImage();
-    if (!cachedImage)
-        return 0;
-
-    auto* image = cachedImage->image();
-    if (!is<BitmapImage>(image))
-        return 0;
+    auto* bitmapImage = bitmapImageFromImageElement(element);
+    return bitmapImage ? bitmapImage->decodeCountForTesting() : 0;
+}
 
-    return downcast<BitmapImage>(*image).decodeCountForTesting();
+void Internals::setLargeImageAsyncDecodingEnabledForTesting(HTMLImageElement& element, bool enabled)
+{
+    if (auto* bitmapImage = bitmapImageFromImageElement(element))
+        bitmapImage->setLargeImageAsyncDecodingEnabledForTesting(enabled);
 }
 
 void Internals::setGridMaxTracksLimit(unsigned maxTrackLimit)
index e68aad662ff80c6298fb1ff1d16a9ef08fb05855..ec2f22b8f769c1f53b5f1720eb50e1fc52b6735b 100644 (file)
@@ -122,8 +122,9 @@ public:
     void setImageFrameDecodingDuration(HTMLImageElement&, float duration);
     void resetImageAnimation(HTMLImageElement&);
     bool isImageAnimating(HTMLImageElement&);
-    void setClearDecoderAfterAsyncFrameRequestForTesting(HTMLImageElement&, bool);
+    void setClearDecoderAfterAsyncFrameRequestForTesting(HTMLImageElement&, bool enabled);
     unsigned imageDecodeCount(HTMLImageElement&);
+    void setLargeImageAsyncDecodingEnabledForTesting(HTMLImageElement&, bool enabled);
 
     void setGridMaxTracksLimit(unsigned);
 
index ad6f5bccc9acc697fa7429104cf04734837d1c8a..89d14d71c31b41ca7585a0940492f93c84d651ef 100644 (file)
@@ -249,8 +249,9 @@ enum EventThrottlingBehavior {
     void setImageFrameDecodingDuration(HTMLImageElement element, unrestricted float duration);
     void resetImageAnimation(HTMLImageElement element);
     boolean isImageAnimating(HTMLImageElement element);
-    void setClearDecoderAfterAsyncFrameRequestForTesting(HTMLImageElement element, boolean value);
+    void setClearDecoderAfterAsyncFrameRequestForTesting(HTMLImageElement element, boolean enabled);
     unsigned long imageDecodeCount(HTMLImageElement element);
+    void setLargeImageAsyncDecodingEnabledForTesting(HTMLImageElement element, boolean enabled);
 
     void setGridMaxTracksLimit(unsigned long maxTracksLimit);
 
index 6f4a078165234c8aa1c3f86ff3276c067d5eab54..b81aab0f1d390c3de44efcef46aea43b37321855 100644 (file)
@@ -1,3 +1,21 @@
+2017-07-25  Said Abou-Hallawa  <sabouhallawa@apple.com>
+
+        Async image decoding for large images should be disabled after the first time a tile is painted
+        https://bugs.webkit.org/show_bug.cgi?id=174451
+        <rdar://problem/31246421>
+
+        Reviewed by Simon Fraser.
+
+        * Shared/mac/RemoteLayerBackingStore.mm:
+        (WebKit::RemoteLayerBackingStore::drawInContext):
+        * WebProcess/InjectedBundle/DOM/InjectedBundleNodeHandle.cpp:
+        (WebKit::imageForRect):
+        * WebProcess/InjectedBundle/DOM/InjectedBundleRangeHandle.cpp:
+        (WebKit::InjectedBundleRangeHandle::renderedImage):
+        * WebProcess/WebPage/CoordinatedGraphics/CompositingCoordinator.cpp:
+        (WebKit::CompositingCoordinator::paintContents):
+        * WebProcess/WebPage/CoordinatedGraphics/CompositingCoordinator.h:
+
 2017-07-25  Brian Burg  <bburg@apple.com>
 
         Web Automation: add support for uploading files
index 18f59f1e840ad9d2eaf9997628073fbc2b5b497f..69a6b55ef831094c1b761bd57c1de119e4491488 100644 (file)
@@ -336,7 +336,7 @@ void RemoteLayerBackingStore::drawInContext(GraphicsContext& context, CGImageRef
 
     context.scale(m_scale);
     
-    auto flags = m_layer->context() && m_layer->context()->nextFlushIsForImmediatePaint() ? WebCore::GraphicsLayerPaintFlags::None : WebCore::GraphicsLayerPaintFlags::AllowAsyncImageDecoding;
+    auto flags = m_layer->context() && m_layer->context()->nextFlushIsForImmediatePaint() ? WebCore::GraphicsLayerPaintSnapshotting : WebCore::GraphicsLayerPaintNormal;
     
     // FIXME: This should be moved to PlatformCALayerRemote for better layering.
     switch (m_layer->layerType()) {
index e2bd59dba735c09673b99b22d3a33e92528d3aa0..ca49b0c3792f2eb5b6d1f85ac2b1b82c8fb223b2 100644 (file)
@@ -169,7 +169,7 @@ static RefPtr<WebImage> imageForRect(FrameView* frameView, const IntRect& painti
     if (options & SnapshotOptionsExcludeSelectionHighlighting)
         shouldPaintSelection = FrameView::ExcludeSelection;
 
-    PaintBehavior paintBehavior = (frameView->paintBehavior() & ~PaintBehaviorAllowAsyncImageDecoding) | PaintBehaviorFlattenCompositingLayers;
+    PaintBehavior paintBehavior = frameView->paintBehavior() | (PaintBehaviorFlattenCompositingLayers | PaintBehaviorSnapshotting);
     if (options & SnapshotOptionsForceBlackText)
         paintBehavior |= PaintBehaviorForceBlackText;
     if (options & SnapshotOptionsForceWhiteText)
index e601d703ddefac99c18eee1ab80c3466ebb0ec00..d1fbc25d5c22760910c2744965e9643fcd269f2b 100644 (file)
@@ -143,7 +143,7 @@ RefPtr<WebImage> InjectedBundleRangeHandle::renderedImage(SnapshotOptions option
     graphicsContext->translate(-paintRect.x(), -paintRect.y());
 
     PaintBehavior oldPaintBehavior = frameView->paintBehavior();
-    PaintBehavior paintBehavior = (oldPaintBehavior & ~PaintBehaviorAllowAsyncImageDecoding) | PaintBehaviorSelectionOnly | PaintBehaviorFlattenCompositingLayers;
+    PaintBehavior paintBehavior = oldPaintBehavior | PaintBehaviorSelectionOnly | PaintBehaviorFlattenCompositingLayers | PaintBehaviorSnapshotting;
     if (options & SnapshotOptionsForceBlackText)
         paintBehavior |= PaintBehaviorForceBlackText;
     if (options & SnapshotOptionsForceWhiteText)
index d467fbcee49cf6ac871844f288e6869dcf39dd2c..1ce73fcdb1e2fdfaaac6f11d6940c7a8b455e102 100644 (file)
@@ -266,7 +266,7 @@ void CompositingCoordinator::notifyFlushRequired(const GraphicsLayer*)
         m_client.notifyFlushRequired();
 }
 
-void CompositingCoordinator::paintContents(const GraphicsLayer* graphicsLayer, GraphicsContext& graphicsContext, GraphicsLayerPaintingPhase, const FloatRect& clipRect, GraphicsLayerPaintFlags)
+void CompositingCoordinator::paintContents(const GraphicsLayer* graphicsLayer, GraphicsContext& graphicsContext, GraphicsLayerPaintingPhase, const FloatRect& clipRect, GraphicsLayerPaintBehavior)
 {
     m_client.paintLayerContents(graphicsLayer, graphicsContext, enclosingIntRect(clipRect));
 }
index e5aa6cb749d0e02a7a1b8bea5d549431c133c8e4..fb275631cff20f993f41312c9b9803ffddb70742 100644 (file)
@@ -101,7 +101,7 @@ private:
     // GraphicsLayerClient
     void notifyAnimationStarted(const WebCore::GraphicsLayer*, const String&, double time) override;
     void notifyFlushRequired(const WebCore::GraphicsLayer*) override;
-    void paintContents(const WebCore::GraphicsLayer*, WebCore::GraphicsContext&, WebCore::GraphicsLayerPaintingPhase, const WebCore::FloatRect& clipRect, WebCore::GraphicsLayerPaintFlags) override;
+    void paintContents(const WebCore::GraphicsLayer*, WebCore::GraphicsContext&, WebCore::GraphicsLayerPaintingPhase, const WebCore::FloatRect& clipRect, WebCore::GraphicsLayerPaintBehavior) override;
     float deviceScaleFactor() const override;
     float pageScaleFactor() const override;
 
index 7d44d9c8705c286936f7cb12bab09c88e7869159..e5898087d4be803951e3b5e2e48d272e29e43f87 100644 (file)
@@ -1,3 +1,17 @@
+2017-07-25  Said Abou-Hallawa  <sabouhallawa@apple.com>
+
+        Async image decoding for large images should be disabled after the first time a tile is painted
+        https://bugs.webkit.org/show_bug.cgi?id=174451
+        <rdar://problem/31246421>
+
+        Reviewed by Simon Fraser.
+
+        * WebView/WebFrame.mm:
+        (-[WebFrame _paintBehaviorForDestinationContext:]):
+        (-[WebFrame _drawRect:contentsOnly:]):
+        * WebView/WebHTMLView.mm:
+        (imageFromRect):
+
 2017-07-23  Darin Adler  <darin@apple.com>
 
         More NeverDestroyed and related cleanup
index 7cae06e6c2a3c4c2c60ce34ddb886f42eed6dd69..f0f8e628580b29fe047eddf6eb47578c6d05dd2d 100644 (file)
@@ -595,23 +595,23 @@ static inline WebDataSource *dataSource(DocumentLoader* loader)
     // -currentContextDrawingToScreen returns YES for bitmap contexts.
     BOOL isPrinting = ![NSGraphicsContext currentContextDrawingToScreen];
     if (isPrinting)
-        return PaintBehaviorFlattenCompositingLayers;
+        return PaintBehaviorFlattenCompositingLayers | PaintBehaviorSnapshotting;
 #endif
 
     if (!WKCGContextIsBitmapContext(context))
-        return PaintBehaviorAllowAsyncImageDecoding;
+        return PaintBehaviorNormal;
 
     // If we're drawing into a bitmap, we might be snapshotting, or drawing into a layer-backed view.
     if (WebHTMLView *htmlDocumentView = [self _webHTMLDocumentView]) {
 #if PLATFORM(IOS)
         if ([[htmlDocumentView window] isInSnapshottingPaint])
-            return 0;
+            return PaintBehaviorSnapshotting;
 #endif
         if ([htmlDocumentView _web_isDrawingIntoLayer])
-            return PaintBehaviorAllowAsyncImageDecoding;
+            return PaintBehaviorNormal;
     }
     
-    return PaintBehaviorFlattenCompositingLayers;
+    return PaintBehaviorFlattenCompositingLayers | PaintBehaviorSnapshotting;
 }
 
 - (void)_drawRect:(NSRect)rect contentsOnly:(BOOL)contentsOnly
@@ -644,9 +644,12 @@ static inline WebDataSource *dataSource(DocumentLoader* loader)
         if (FrameView* parentView = parentFrame ? parentFrame->view() : nullptr) {
             if (parentView->paintBehavior() & PaintBehaviorFlattenCompositingLayers)
                 paintBehavior |= PaintBehaviorFlattenCompositingLayers;
-                
-            if (parentView->paintBehavior() & PaintBehaviorAllowAsyncImageDecoding)
-                paintBehavior |= PaintBehaviorAllowAsyncImageDecoding;
+            
+            if (parentView->paintBehavior() & PaintBehaviorSnapshotting)
+                paintBehavior |= PaintBehaviorSnapshotting;
+            
+            if (parentView->paintBehavior() & PaintBehaviorTileFirstPaint)
+                paintBehavior |= PaintBehaviorTileFirstPaint;
         }
     } else
         paintBehavior |= [self _paintBehaviorForDestinationContext:ctx];
index acb8f52e787b4a6d89deaec22f341beee46e81d2..f94733bbeac393f63d30ff82a1da2f59a33a68cf 100644 (file)
@@ -7313,7 +7313,7 @@ static CGImageRef imageFromRect(Frame* frame, CGRect rect)
     WebHTMLView *view = (WebHTMLView *)documentView;
     
     PaintBehavior oldPaintBehavior = frame->view()->paintBehavior();
-    frame->view()->setPaintBehavior((oldPaintBehavior & ~PaintBehaviorAllowAsyncImageDecoding) | PaintBehaviorFlattenCompositingLayers);
+    frame->view()->setPaintBehavior(oldPaintBehavior | PaintBehaviorFlattenCompositingLayers | PaintBehaviorSnapshotting);
 
     BEGIN_BLOCK_OBJC_EXCEPTIONS;
     
index 50f58ce1f2d97e25aa199868e00115711a8a66f9..21059985220db287f5884bb8eba50948171da9b5 100644 (file)
@@ -1,3 +1,17 @@
+2017-07-25  Said Abou-Hallawa  <sabouhallawa@apple.com>
+
+        Async image decoding for large images should be disabled after the first time a tile is painted
+        https://bugs.webkit.org/show_bug.cgi?id=174451
+        <rdar://problem/31246421>
+
+        Reviewed by Simon Fraser.
+
+        * FullscreenVideoController.cpp:
+        (FullscreenVideoController::LayerClient::platformCALayerPaintContents):
+        * WebCoreSupport/AcceleratedCompositingContext.cpp:
+        (AcceleratedCompositingContext::paintContents):
+        * WebCoreSupport/AcceleratedCompositingContext.h:
+
 2017-07-23  Darin Adler  <darin@apple.com>
 
         More NeverDestroyed and related cleanup
index 9e60c4fd637c8dc90c705b1b4a70e7a6ea04ae60..e539cb1a0756f8d859b7cf2516741ebf05fcee56 100644 (file)
@@ -187,7 +187,7 @@ private:
 
     virtual void platformCALayerAnimationStarted(CFTimeInterval beginTime) { }
     virtual GraphicsLayer::CompositingCoordinatesOrientation platformCALayerContentsOrientation() const { return GraphicsLayer::CompositingCoordinatesBottomUp; }
-    virtual void platformCALayerPaintContents(PlatformCALayer*, GraphicsContext&, const FloatRect&, GraphicsLayerPaintFlags) { }
+    virtual void platformCALayerPaintContents(PlatformCALayer*, GraphicsContext&, const FloatRect&, GraphicsLayerPaintBehavior) { }
     virtual bool platformCALayerShowDebugBorders() const { return false; }
     virtual bool platformCALayerShowRepaintCounter(PlatformCALayer*) const { return false; }
     virtual int platformCALayerIncrementRepaintCount(PlatformCALayer*) { return 0; }
index cfaa7a7e0ff5e8201fe1ba2d8dc647f01833f51e..7a0c485d0efec8cec5235cbbd6e02669ce677d22 100644 (file)
@@ -403,7 +403,7 @@ void AcceleratedCompositingContext::layerFlushTimerFired()
         scheduleLayerFlush();
 }
 
-void AcceleratedCompositingContext::paintContents(const GraphicsLayer*, GraphicsContext& context, GraphicsLayerPaintingPhase, const FloatRect& rectToPaint, GraphicsLayerPaintFlags)
+void AcceleratedCompositingContext::paintContents(const GraphicsLayer*, GraphicsContext& context, GraphicsLayerPaintingPhase, const FloatRect& rectToPaint, GraphicsLayerPaintBehavior)
 {
     context.save();
     context.clip(rectToPaint);
index e3235c3fb79f121062873bc165e6e4f2f707f6be..f7f3842d6c972a08579ba2701d12b63b38cb0f82 100644 (file)
@@ -52,7 +52,7 @@ public:
     bool enabled();
 
     // GraphicsLayerClient
-    void paintContents(const WebCore::GraphicsLayer*, WebCore::GraphicsContext&, WebCore::GraphicsLayerPaintingPhase, const WebCore::FloatRect& rectToPaint, WebCore::GraphicsLayerPaintFlags) override;
+    void paintContents(const WebCore::GraphicsLayer*, WebCore::GraphicsContext&, WebCore::GraphicsLayerPaintingPhase, const WebCore::FloatRect& rectToPaint, WebCore::GraphicsLayerPaintBehavior) override;
     float deviceScaleFactor() const override;
 
     void initialize();