Title: [221805] trunk
Revision
221805
Author
commit-qu...@webkit.org
Date
2017-09-08 20:09:09 -0700 (Fri, 08 Sep 2017)

Log Message

Implement HTMLImageElement.decoode() method
https://bugs.webkit.org/show_bug.cgi?id=176016

Patch by Said Abou-Hallawa <sabouhall...@apple.com> on 2017-09-08
Reviewed by Simon Fraser.

Source/WebCore:

The specs is:
https://html.spec.whatwg.org/multipage/embedded-content.html#dom-img-decode.

-- img.decode() waits till loading the image finishes. Otherwise it starts
decoding the image immediately.
-- If the image frame is already decoded, the promise will be resolved
before return.
-- If an error happens in loading the image or decoding the image frame,
the promise will be rejected with 'EncodingError' exception.
-- Animated image resolves the promise when the next frame is decoded and
the animation is advanced it. If the image is not displayed, decode() will
request the decoding the first frame and start animating the image.

Tests: fast/images/decode-animated-image.html
       fast/images/decode-render-animated-image.html
       fast/images/decode-render-static-image.html
       fast/images/decode-static-image-reject.html
       fast/images/decode-static-image-resolve.html

* html/HTMLImageElement.cpp:
(WebCore::HTMLImageElement::decode):
* html/HTMLImageElement.h:
* html/HTMLImageElement.idl:
* loader/ImageLoader.cpp:
(WebCore::ImageLoader::notifyFinished):
(WebCore::ImageLoader::decode):
(WebCore::ImageLoader::decodeError):
* loader/ImageLoader.h:
(WebCore::ImageLoader::hasPendingDecodePromise const):
* platform/graphics/BitmapImage.cpp:
(WebCore::BitmapImage::internalStartAnimation):
(WebCore::BitmapImage::internalAdvanceAnimation):
(WebCore::BitmapImage::decode):
(WebCore::BitmapImage::imageFrameAvailableAtIndex):
* platform/graphics/BitmapImage.h:
* platform/graphics/Image.h:
(WebCore::Image::decode):

LayoutTests:

* fast/images/decode-animated-image-expected.html: Added.
* fast/images/decode-animated-image.html: Added.
* fast/images/decode-render-animated-image-expected.html: Added.
* fast/images/decode-render-animated-image.html: Added.
* fast/images/decode-render-static-image-expected.html: Added.
* fast/images/decode-render-static-image.html: Added.
* fast/images/decode-static-image-reject-expected.txt: Added.
* fast/images/decode-static-image-reject.html: Added.
* fast/images/decode-static-image-resolve-expected.html: Added.
* fast/images/decode-static-image-resolve.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (221804 => 221805)


--- trunk/LayoutTests/ChangeLog	2017-09-09 00:33:44 UTC (rev 221804)
+++ trunk/LayoutTests/ChangeLog	2017-09-09 03:09:09 UTC (rev 221805)
@@ -1,3 +1,21 @@
+2017-09-08  Said Abou-Hallawa  <sabouhall...@apple.com>
+
+        Implement HTMLImageElement.decoode() method
+        https://bugs.webkit.org/show_bug.cgi?id=176016
+
+        Reviewed by Simon Fraser.
+
+        * fast/images/decode-animated-image-expected.html: Added.
+        * fast/images/decode-animated-image.html: Added.
+        * fast/images/decode-render-animated-image-expected.html: Added.
+        * fast/images/decode-render-animated-image.html: Added.
+        * fast/images/decode-render-static-image-expected.html: Added.
+        * fast/images/decode-render-static-image.html: Added.
+        * fast/images/decode-static-image-reject-expected.txt: Added.
+        * fast/images/decode-static-image-reject.html: Added.
+        * fast/images/decode-static-image-resolve-expected.html: Added.
+        * fast/images/decode-static-image-resolve.html: Added.
+
 2017-09-08  Joseph Pecoraro  <pecor...@apple.com>
 
         Fetch's Response.statusText is unexpectedly the full http status line for HTTP/2 responses

Added: trunk/LayoutTests/fast/images/decode-animated-image-expected.html (0 => 221805)


--- trunk/LayoutTests/fast/images/decode-animated-image-expected.html	                        (rev 0)
+++ trunk/LayoutTests/fast/images/decode-animated-image-expected.html	2017-09-09 03:09:09 UTC (rev 221805)
@@ -0,0 +1,11 @@
+<style>
+    div {
+        width: 100px;
+        height: 100px;
+        background-color: green;
+    }
+</style>
+<body>
+	<p>This tests calling decode() multiple times for an animated image.</p>
+    <div></div>
+</body>
\ No newline at end of file

Added: trunk/LayoutTests/fast/images/decode-animated-image.html (0 => 221805)


--- trunk/LayoutTests/fast/images/decode-animated-image.html	                        (rev 0)
+++ trunk/LayoutTests/fast/images/decode-animated-image.html	2017-09-09 03:09:09 UTC (rev 221805)
@@ -0,0 +1,27 @@
+<style>
+    canvas {
+        width: 100px;
+        height: 100px;
+    }
+</style>
+<body>
+    <p>This tests calling decode() multiple times for an animated image.</p>
+    <canvas></canvas>
+    <script>
+        if (window.testRunner)
+            testRunner.waitUntilDone();
+        var image = new Image;
+        image.src = ""
+        // First decode() will decode the red frame.
+        image.decode().then(() => {
+            // Second decode() will decode the green frame.
+            image.decode().then(() => {
+                let canvas = document.querySelector("canvas");
+                let context = canvas.getContext("2d");
+                context.drawImage(image, 0, 0, canvas.width, canvas.height);
+                if (window.testRunner)
+                    testRunner.notifyDone();
+            });
+        });
+    </script>
+</body>

Added: trunk/LayoutTests/fast/images/decode-render-animated-image-expected.html (0 => 221805)


--- trunk/LayoutTests/fast/images/decode-render-animated-image-expected.html	                        (rev 0)
+++ trunk/LayoutTests/fast/images/decode-render-animated-image-expected.html	2017-09-09 03:09:09 UTC (rev 221805)
@@ -0,0 +1,11 @@
+<style>
+    div {
+        width: 100px;
+        height: 100px;
+        background-color: blue;
+    }
+</style>
+<body>
+	<p>This tests calling decode() for a animated image which is also an element in the DOM tree.</p>
+    <div></div>
+</body>

Added: trunk/LayoutTests/fast/images/decode-render-animated-image.html (0 => 221805)


--- trunk/LayoutTests/fast/images/decode-render-animated-image.html	                        (rev 0)
+++ trunk/LayoutTests/fast/images/decode-render-animated-image.html	2017-09-09 03:09:09 UTC (rev 221805)
@@ -0,0 +1,55 @@
+ <style>
+     div {
+        width: 100px;
+        height: 100px;
+    }
+    canvas {
+        width: 100px;
+        height: 100px;
+        background-color: black;
+    }
+    img {
+        max-width: 100%;
+        max-height: 100%;
+    }
+</style>
+<body>
+    <p>This tests calling decode() for a animated image which is also an element in the DOM tree.</p>
+    <canvas></canvas>
+    <div></div>
+    <script>
+        if (window.internals && window.testRunner) {
+            internals.clearMemoryCache();
+            internals.settings.setWebkitImageReadyEventEnabled(true);
+            testRunner.waitUntilDone();
+        }
+
+        var image = new Image;
+        var parent = document.querySelector("div");
+        parent.appendChild(image);
+
+        image._onload_ = (() => {
+            if (window.internals && window.testRunner) {
+                // Force layout and display so the image gets drawn. The image will draw its red frame.
+                document.body.offsetHeight;
+                testRunner.display();
+
+                // Wait till decoding the next (green) frame finishes and the animation advances to it.
+                image.addEventListener("webkitImageFrameReady", function() {
+                    setTimeout(function() {
+                        // Request decoding the next (blue) frame. Wait till decoding finishes and the
+                        // animation advances to it.
+                        image.decode().then(() => {
+                            var canvas = document.querySelector("canvas");
+                            var context = canvas.getContext("2d");
+                            context.drawImage(image, 0, 0, canvas.width, canvas.height);
+                            parent.remove();
+                            testRunner.notifyDone();
+                        });
+                    }, 0);
+                });
+            }
+        });
+        image.src = ""
+    </script>
+</body>

Added: trunk/LayoutTests/fast/images/decode-render-static-image-expected.html (0 => 221805)


--- trunk/LayoutTests/fast/images/decode-render-static-image-expected.html	                        (rev 0)
+++ trunk/LayoutTests/fast/images/decode-render-static-image-expected.html	2017-09-09 03:09:09 UTC (rev 221805)
@@ -0,0 +1,11 @@
+<style>
+    div {
+        width: 200px;
+        height: 200px;
+        background-color: green;
+    }
+</style>
+<body>
+	<p>This tests calling decode() for a static image which is also an element in the DOM tree.</p>
+    <div></div>
+</body>

Added: trunk/LayoutTests/fast/images/decode-render-static-image.html (0 => 221805)


--- trunk/LayoutTests/fast/images/decode-render-static-image.html	                        (rev 0)
+++ trunk/LayoutTests/fast/images/decode-render-static-image.html	2017-09-09 03:09:09 UTC (rev 221805)
@@ -0,0 +1,56 @@
+<style>
+    div {
+        width: 100px;
+        height: 100px;
+    }
+    img {
+        max-width: 100%;
+        max-height: 100%;
+    }
+</style>
+<body>
+    <p>This tests calling decode() for a static image which is also an element in the DOM tree.</p>
+    <div></div>
+    <script>
+        if (window.internals && window.testRunner) {
+            internals.clearMemoryCache();
+            internals.settings.setWebkitImageReadyEventEnabled(true);
+            internals.settings.setLargeImageAsyncDecodingEnabled(true);
+            testRunner.waitUntilDone();
+        }
+
+        var image = new Image;
+        var parent = document.querySelector("div");
+        parent.appendChild(image);
+
+        image._onload_ = (() => {
+            if (window.internals && window.testRunner) {
+                // Force async image decoding for this image.
+                internals.setLargeImageAsyncDecodingEnabledForTesting(image, true);
+
+                // Force layout and display so the image gets drawn.
+                document.body.offsetHeight;
+                testRunner.display();
+
+                // testRunner.display() requests an async image decoding. Wait till it finishes.
+                image.addEventListener("webkitImageFrameReady", function() {
+                    // Execute this code in the next loop run.
+                    setTimeout(function() {
+                        testRunner.display();
+                        // The image frame was decoded for the renderer which is (100x100). This
+                        // decode() will request a new decoding with the native size which is (400x400).
+                        image.decode().then(() => {
+                            parent.style.width = "200px";
+                            parent.style.height = "200px";
+                            // No extra decoding is required to display the image after changing its size.
+                            // The image frame was decoded with the native size which is the maximum size
+                            // that an image can be decoded with.
+                            testRunner.notifyDone();
+                        });
+                    }, 0);
+                });
+            }
+        });
+        image.src = ""
+    </script>
+</body>

Added: trunk/LayoutTests/fast/images/decode-static-image-reject-expected.txt (0 => 221805)


--- trunk/LayoutTests/fast/images/decode-static-image-reject-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/images/decode-static-image-reject-expected.txt	2017-09-09 03:09:09 UTC (rev 221805)
@@ -0,0 +1,12 @@
+Test rejecting the decode() promise when loading the image fails.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Failed to decode image with no source. Result is: EncodingError: Missing source URL.
+Failed to decode image with non-existent source. Result is: EncodingError: Loading error.
+Failed to decode image with unsupported image format. Result is: EncodingError: Loading error.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/fast/images/decode-static-image-reject.html (0 => 221805)


--- trunk/LayoutTests/fast/images/decode-static-image-reject.html	                        (rev 0)
+++ trunk/LayoutTests/fast/images/decode-static-image-reject.html	2017-09-09 03:09:09 UTC (rev 221805)
@@ -0,0 +1,28 @@
+<head>
+    <script src=""
+</head>
+<body>
+    <div></div>
+    <script>
+        description("Test rejecting the decode() promise when loading the image fails.");
+        jsTestIsAsync = true;
+
+        var image = new Image;
+        image.decode()
+        .catch(reason => {
+            debug("Failed to decode image with no source. Result is: " + reason);
+            image.src = ""
+            return image.decode();
+        })
+        .catch(reason => {
+            debug("Failed to decode image with non-existent source. Result is: " + reason);
+            image.src = ""
+            return image.decode();
+        })
+        .catch(reason => {
+            debug("Failed to decode image with unsupported image format. Result is: " + reason);
+            finishJSTest();
+        });
+    </script>
+    <script src=""
+</body>

Added: trunk/LayoutTests/fast/images/decode-static-image-resolve-expected.html (0 => 221805)


--- trunk/LayoutTests/fast/images/decode-static-image-resolve-expected.html	                        (rev 0)
+++ trunk/LayoutTests/fast/images/decode-static-image-resolve-expected.html	2017-09-09 03:09:09 UTC (rev 221805)
@@ -0,0 +1,11 @@
+<style>
+    div {
+        width: 100px;
+        height: 100px;
+        background-color: green;
+    }
+</style>
+<body>
+    <p>This tests resolving the decode() promise when loading and decoding a static image succeeds.</p>
+    <div></div>
+</body>
\ No newline at end of file

Added: trunk/LayoutTests/fast/images/decode-static-image-resolve.html (0 => 221805)


--- trunk/LayoutTests/fast/images/decode-static-image-resolve.html	                        (rev 0)
+++ trunk/LayoutTests/fast/images/decode-static-image-resolve.html	2017-09-09 03:09:09 UTC (rev 221805)
@@ -0,0 +1,24 @@
+<style>
+    canvas {
+        width: 100px;
+        height: 100px;
+        background-color: red;
+    }
+</style>
+<body>
+    <p>This tests resolving the decode() promise when loading and decoding a static image succeeds.</p>
+    <canvas></canvas>
+    <script>
+        if (window.testRunner)
+            testRunner.waitUntilDone();
+        var image = new Image;
+        image.src = ""
+        image.decode().then(() => {
+            let canvas = document.querySelector("canvas");
+            let context = canvas.getContext("2d");
+            context.drawImage(image, 0, 0, canvas.width, canvas.height);
+            if (window.testRunner)
+                testRunner.notifyDone();
+        });
+    </script>
+</body>

Modified: trunk/Source/WebCore/ChangeLog (221804 => 221805)


--- trunk/Source/WebCore/ChangeLog	2017-09-09 00:33:44 UTC (rev 221804)
+++ trunk/Source/WebCore/ChangeLog	2017-09-09 03:09:09 UTC (rev 221805)
@@ -1,3 +1,48 @@
+2017-09-08  Said Abou-Hallawa  <sabouhall...@apple.com>
+
+        Implement HTMLImageElement.decoode() method
+        https://bugs.webkit.org/show_bug.cgi?id=176016
+
+        Reviewed by Simon Fraser.
+
+        The specs is:
+        https://html.spec.whatwg.org/multipage/embedded-content.html#dom-img-decode.
+
+        -- img.decode() waits till loading the image finishes. Otherwise it starts
+        decoding the image immediately.
+        -- If the image frame is already decoded, the promise will be resolved
+        before return.
+        -- If an error happens in loading the image or decoding the image frame,
+        the promise will be rejected with 'EncodingError' exception.
+        -- Animated image resolves the promise when the next frame is decoded and 
+        the animation is advanced it. If the image is not displayed, decode() will
+        request the decoding the first frame and start animating the image.
+
+        Tests: fast/images/decode-animated-image.html
+               fast/images/decode-render-animated-image.html
+               fast/images/decode-render-static-image.html
+               fast/images/decode-static-image-reject.html
+               fast/images/decode-static-image-resolve.html
+
+        * html/HTMLImageElement.cpp:
+        (WebCore::HTMLImageElement::decode):
+        * html/HTMLImageElement.h:
+        * html/HTMLImageElement.idl:
+        * loader/ImageLoader.cpp:
+        (WebCore::ImageLoader::notifyFinished):
+        (WebCore::ImageLoader::decode):
+        (WebCore::ImageLoader::decodeError):
+        * loader/ImageLoader.h:
+        (WebCore::ImageLoader::hasPendingDecodePromise const):
+        * platform/graphics/BitmapImage.cpp:
+        (WebCore::BitmapImage::internalStartAnimation):
+        (WebCore::BitmapImage::internalAdvanceAnimation):
+        (WebCore::BitmapImage::decode):
+        (WebCore::BitmapImage::imageFrameAvailableAtIndex):
+        * platform/graphics/BitmapImage.h:
+        * platform/graphics/Image.h:
+        (WebCore::Image::decode):
+
 2017-09-08  Joseph Pecoraro  <pecor...@apple.com>
 
         Fetch's Response.statusText is unexpectedly the full http status line for HTTP/2 responses

Modified: trunk/Source/WebCore/html/HTMLImageElement.cpp (221804 => 221805)


--- trunk/Source/WebCore/html/HTMLImageElement.cpp	2017-09-09 00:33:44 UTC (rev 221804)
+++ trunk/Source/WebCore/html/HTMLImageElement.cpp	2017-09-09 03:09:09 UTC (rev 221805)
@@ -538,6 +538,11 @@
     return m_imageLoader.imageComplete();
 }
 
+void HTMLImageElement::decode(Ref<DeferredPromise>&& promise)
+{
+    return m_imageLoader.decode(WTFMove(promise));
+}
+
 void HTMLImageElement::addSubresourceAttributeURLs(ListHashSet<URL>& urls) const
 {
     HTMLElement::addSubresourceAttributeURLs(urls);

Modified: trunk/Source/WebCore/html/HTMLImageElement.h (221804 => 221805)


--- trunk/Source/WebCore/html/HTMLImageElement.h	2017-09-09 00:33:44 UTC (rev 221804)
+++ trunk/Source/WebCore/html/HTMLImageElement.h	2017-09-09 03:09:09 UTC (rev 221805)
@@ -79,6 +79,8 @@
 
     WEBCORE_EXPORT bool complete() const;
 
+    WEBCORE_EXPORT void decode(Ref<DeferredPromise>&&);
+
 #if PLATFORM(IOS)
     bool willRespondToMouseClickEvents() override;
 #endif

Modified: trunk/Source/WebCore/html/HTMLImageElement.idl (221804 => 221805)


--- trunk/Source/WebCore/html/HTMLImageElement.idl	2017-09-09 00:33:44 UTC (rev 221804)
+++ trunk/Source/WebCore/html/HTMLImageElement.idl	2017-09-09 03:09:09 UTC (rev 221805)
@@ -49,5 +49,7 @@
     readonly attribute long naturalWidth;
     readonly attribute long x;
     readonly attribute long y;
+
+    Promise<void> decode();
 };
 

Modified: trunk/Source/WebCore/loader/ImageLoader.cpp (221804 => 221805)


--- trunk/Source/WebCore/loader/ImageLoader.cpp	2017-09-09 00:33:44 UTC (rev 221804)
+++ trunk/Source/WebCore/loader/ImageLoader.cpp	2017-09-09 03:09:09 UTC (rev 221805)
@@ -291,6 +291,9 @@
         static NeverDestroyed<String> consoleMessage(MAKE_STATIC_STRING_IMPL("Cross-origin image load denied by Cross-Origin Resource Sharing policy."));
         element().document().addConsoleMessage(MessageSource::Security, MessageLevel::Error, consoleMessage);
 
+        if (hasPendingDecodePromises())
+            decodeError("Access control error.");
+        
         ASSERT(!m_hasPendingLoadEvent);
 
         // Only consider updating the protection ref-count of the Element immediately before returning
@@ -300,6 +303,8 @@
     }
 
     if (m_image->wasCanceled()) {
+        if (hasPendingDecodePromises())
+            decodeError("Loading was canceled.");
         m_hasPendingLoadEvent = false;
         // Only consider updating the protection ref-count of the Element immediately before returning
         // from this function as doing so might result in the destruction of this ImageLoader.
@@ -307,6 +312,8 @@
         return;
     }
 
+    if (hasPendingDecodePromises())
+        decode();
     loadEventSender().dispatchEventSoon(*this);
 }
 
@@ -369,6 +376,59 @@
     }   
 }
 
+void ImageLoader::decode(Ref<DeferredPromise>&& promise)
+{
+    m_decodingPromises.append(WTFMove(promise));
+    
+    if (!element().document().domWindow()) {
+        decodeError("Inactive document.");
+        return;
+    }
+    
+    AtomicString attr = element().imageSourceURL();
+    if (attr.isNull() || stripLeadingAndTrailingHTMLSpaces(attr).isEmpty()) {
+        decodeError("Missing source URL.");
+        return;
+    }
+    
+    if (m_imageComplete)
+        decode();
+}
+
+void ImageLoader::decodeError(String&& message)
+{
+    ASSERT(hasPendingDecodePromises());
+    for (auto& promise : m_decodingPromises)
+        promise->reject(Exception { EncodingError, WTFMove(message) });
+    m_decodingPromises.clear();
+}
+
+void ImageLoader::decode()
+{
+    ASSERT(hasPendingDecodePromises());
+    
+    if (!element().document().domWindow()) {
+        decodeError("Inactive document.");
+        return;
+    }
+
+    Image* image = m_image->image();
+    if (!image || m_image->errorOccurred()) {
+        decodeError("Loading error.");
+        return;
+    }
+
+    if (!image->isBitmapImage()) {
+        decodeError("Invalid image type.");
+        return;
+    }
+    
+    image->decode([promises = WTFMove(m_decodingPromises)]() mutable {
+        for (auto& promise : promises)
+            promise->resolve();
+    });
+}
+
 void ImageLoader::timerFired()
 {
     m_protectedElement = nullptr;

Modified: trunk/Source/WebCore/loader/ImageLoader.h (221804 => 221805)


--- trunk/Source/WebCore/loader/ImageLoader.h	2017-09-09 00:33:44 UTC (rev 221804)
+++ trunk/Source/WebCore/loader/ImageLoader.h	2017-09-09 03:09:09 UTC (rev 221805)
@@ -24,7 +24,9 @@
 
 #include "CachedImageClient.h"
 #include "CachedResourceHandle.h"
+#include "JSDOMPromiseDeferred.h"
 #include "Timer.h"
+#include <wtf/Vector.h>
 #include <wtf/text/AtomicString.h>
 
 namespace WebCore {
@@ -58,6 +60,8 @@
 
     CachedImage* image() const { return m_image.get(); }
     void clearImage(); // Cancels pending beforeload and load events, and doesn't dispatch new ones.
+    
+    void decode(Ref<DeferredPromise>&&);
 
     void setLoadManually(bool loadManually) { m_loadManually = loadManually; }
 
@@ -90,6 +94,10 @@
     void clearImageWithoutConsideringPendingLoadEvent();
     void clearFailedLoadURL();
 
+    bool hasPendingDecodePromises() const { return !m_decodingPromises.isEmpty(); }
+    void decodeError(String&&);
+    void decode();
+    
     void timerFired();
 
     Element& m_element;
@@ -97,6 +105,7 @@
     Timer m_derefElementTimer;
     RefPtr<Element> m_protectedElement;
     AtomicString m_failedLoadURL;
+    Vector<RefPtr<DeferredPromise>, 1> m_decodingPromises;
     bool m_hasPendingBeforeLoadEvent : 1;
     bool m_hasPendingLoadEvent : 1;
     bool m_hasPendingErrorEvent : 1;

Modified: trunk/Source/WebCore/platform/graphics/BitmapImage.cpp (221804 => 221805)


--- trunk/Source/WebCore/platform/graphics/BitmapImage.cpp	2017-09-09 00:33:44 UTC (rev 221804)
+++ trunk/Source/WebCore/platform/graphics/BitmapImage.cpp	2017-09-09 03:09:09 UTC (rev 221805)
@@ -464,7 +464,9 @@
 
     DecodingStatus decodingStatus = frameDecodingStatusAtIndex(m_currentFrame);
     setCurrentFrameDecodingStatusIfNecessary(decodingStatus);
-    
+
+    callDecodingCallbacks();
+
     if (imageObserver())
         imageObserver()->imageFrameAvailable(*this, ImageAnimatingState::Yes, nullptr, decodingStatus);
 
@@ -497,6 +499,47 @@
     destroyDecodedDataIfNecessary(true);
 }
 
+void BitmapImage::decode(WTF::Function<void()>&& callback)
+{
+    m_decodingCallbacks.append(WTFMove(callback));
+
+    if (canAnimate())  {
+        if (m_desiredFrameStartTime) {
+            internalStartAnimation();
+            return;
+        }
+
+        // The animated image has not been displayed. In this case, either the first frame has not been decoded yet or the animation has not started yet.
+        bool frameIsCompatible = frameHasDecodedNativeImageCompatibleWithOptionsAtIndex(m_currentFrame, m_currentSubsamplingLevel, std::optional<IntSize>());
+        bool frameIsBeingDecoded = frameIsBeingDecodedAndIsCompatibleWithOptionsAtIndex(m_currentFrame, std::optional<IntSize>());
+
+        if (frameIsCompatible)
+            internalStartAnimation();
+        else if (!frameIsBeingDecoded) {
+            m_source.requestFrameAsyncDecodingAtIndex(m_currentFrame, m_currentSubsamplingLevel, std::optional<IntSize>());
+            m_currentFrameDecodingStatus = DecodingStatus::Decoding;
+        }
+        return;
+    }
+
+    bool frameIsCompatible = frameHasDecodedNativeImageCompatibleWithOptionsAtIndex(m_currentFrame, m_currentSubsamplingLevel, std::optional<IntSize>());
+    bool frameIsBeingDecoded = frameIsBeingDecodedAndIsCompatibleWithOptionsAtIndex(m_currentFrame, std::optional<IntSize>());
+    
+    if (frameIsCompatible)
+        callDecodingCallbacks();
+    else if (!frameIsBeingDecoded) {
+        m_source.requestFrameAsyncDecodingAtIndex(m_currentFrame, m_currentSubsamplingLevel, std::optional<IntSize>());
+        m_currentFrameDecodingStatus = DecodingStatus::Decoding;
+    }
+}
+
+void BitmapImage::callDecodingCallbacks()
+{
+    for (auto& decodingCallback : m_decodingCallbacks)
+        decodingCallback();
+    m_decodingCallbacks.clear();
+}
+
 void BitmapImage::imageFrameAvailableAtIndex(size_t index)
 {
     LOG(Images, "BitmapImage::%s - %p - url: %s [requested frame %ld is now available]", __FUNCTION__, this, sourceURL().string().utf8().data(), index);
@@ -524,10 +567,14 @@
 
     DecodingStatus decodingStatus = frameDecodingStatusAtIndex(m_currentFrame);
     setCurrentFrameDecodingStatusIfNecessary(decodingStatus);
-    
+
     if (m_currentFrameDecodingStatus == DecodingStatus::Complete)
         ++m_decodeCountForTesting;
 
+    // Call m_decodingCallbacks only if the image frame was decoded with the native size.
+    if (frameHasDecodedNativeImageCompatibleWithOptionsAtIndex(m_currentFrame, m_currentSubsamplingLevel, std::optional<IntSize>()))
+        callDecodingCallbacks();
+
     if (imageObserver())
         imageObserver()->imageFrameAvailable(*this, ImageAnimatingState::No, nullptr, decodingStatus);
 }

Modified: trunk/Source/WebCore/platform/graphics/BitmapImage.h (221804 => 221805)


--- trunk/Source/WebCore/platform/graphics/BitmapImage.h	2017-09-09 00:33:44 UTC (rev 221804)
+++ trunk/Source/WebCore/platform/graphics/BitmapImage.h	2017-09-09 03:09:09 UTC (rev 221805)
@@ -178,8 +178,7 @@
     // automatically pause once all observers no longer want to render the image anywhere.
     void stopAnimation() override;
     void resetAnimation() override;
-    void imageFrameAvailableAtIndex(size_t) override;
-
+    
     // Handle platform-specific data
     void invalidatePlatformData();
 
@@ -197,6 +196,9 @@
     bool canDestroyDecodedData();
     void setCurrentFrameDecodingStatusIfNecessary(DecodingStatus);
     bool isBitmapImage() const override { return true; }
+    void decode(WTF::Function<void()>&&) override;
+    void callDecodingCallbacks();
+    void imageFrameAvailableAtIndex(size_t) override;
     void dump(WTF::TextStream&) const override;
 
     // Animated images over a certain size are considered large enough that we'll only hang on to one frame at a time.
@@ -211,6 +213,7 @@
     RepetitionCount m_repetitionsComplete { RepetitionCountNone }; // How many repetitions we've finished.
     MonotonicTime m_desiredFrameStartTime; // The system time at which we hope to see the next call to startAnimation().
 
+    Vector<Function<void()>, 1> m_decodingCallbacks;
     Seconds m_frameDecodingDurationForTesting;
     MonotonicTime m_desiredFrameDecodeTimeForTesting;
 

Modified: trunk/Source/WebCore/platform/graphics/Image.h (221804 => 221805)


--- trunk/Source/WebCore/platform/graphics/Image.h	2017-09-09 00:33:44 UTC (rev 221804)
+++ trunk/Source/WebCore/platform/graphics/Image.h	2017-09-09 03:09:09 UTC (rev 221805)
@@ -133,10 +133,12 @@
     void startAnimationAsynchronously();
     virtual void stopAnimation() {}
     virtual void resetAnimation() {}
-    virtual void imageFrameAvailableAtIndex(size_t) { }
     virtual bool isAnimating() const { return false; }
     bool animationPending() const { return m_animationStartTimer.isActive(); }
-    
+
+    virtual void decode(WTF::Function<void()>&&) { }
+    virtual void imageFrameAvailableAtIndex(size_t) { }
+
     // Typically the CachedImage that owns us.
     ImageObserver* imageObserver() const { return m_imageObserver; }
     void setImageObserver(ImageObserver* observer) { m_imageObserver = observer; }
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to