Changeset 214450 in webkit


Ignore:
Timestamp:
Mar 27, 2017, 7:23:10 PM (8 years ago)
Author:
commit-queue@webkit.org
Message:

REGRESSION(213764): Large images should not be decoded asynchronously when they are drawn on a canvas
https://bugs.webkit.org/show_bug.cgi?id=169771

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

Source/WebCore:

Sometimes we have to draw the image immediately like when a canvas calls
drawImage. In this case we have to decode the image synchronously to guarantee
the drawing. Other times we need to decode with the native size of the image.
The animated images have to be decoded with native size always. Otherwise
the frame cache will be messed up if the same image is animated with different
sizes. Currently we always decode asynchronously with sizeForDrawing. We need
to decouple the decoding mode from the sizeForDrawing.

This patch introduce the DecodingOptions class which can store and compare the
following four cases:

-- Synchronous: The frame has be decoded with native size only.
-- Asynchronous + anySize: This is passed from the Image::draw() callers.
-- Asynchronous + fullSize: The image has to be decoded with its full size.
-- Asynchronous + sizeForDrawing: The image can be decoded with sizeForDrawing unless
it was decoded with either a full size or sizeForDrawing which is larger than the
requested sizeForDrawing.

A new argument of type DecodingMode will be added to Image::draw() function.
Only when the drawing comes from the render tree, it will be Asynchronous.
Otherwise it will be Synchronous.

Tests: fast/images/animated-image-different-dest-size.html

fast/images/async-image-background-image.html
fast/images/async-image-canvas-draw-image.html

  • WebCore.xcodeproj/project.pbxproj:
  • platform/graphics/BitmapImage.cpp:

(WebCore::BitmapImage::frameImageAtIndexCacheIfNeeded): Gets the frame image, cache it synchronously if
the current one is invalid. frameImageAtIndex() returns whatever stored in the cache.
(WebCore::BitmapImage::nativeImage): Call frameImageAtIndexCacheIfNeeded() instead of frameImageAtIndex().
(WebCore::BitmapImage::nativeImageForCurrentFrame): Ditto.
(WebCore::BitmapImage::nativeImageOfSize): Ditto.
(WebCore::BitmapImage::framesNativeImages): Ditto.
(WebCore::BitmapImage::draw): Change the logic to do the following:
-- The animated image has to be decoded with its full size.
-- The animated image expects the current frame to be ready for drawing.
-- The large image decoding does not need to call internalStartAnimation().
-- The large image has to request async image decoding but draw the current one if it exists.
(WebCore::BitmapImage::drawPattern): Draw the pattern synchronously.
(WebCore::BitmapImage::shouldUseAsyncDecodingForLargeImages): Delete the call to shouldUseAsyncDecodingForTesting()
since it is only applied for animated images.
(WebCore::BitmapImage::shouldUseAsyncDecodingForAnimatedImages): Call shouldUseAsyncDecodingForAnimatedImageForTesting().
(WebCore::BitmapImage::internalStartAnimation): Request decoding with the full size.
(WebCore::BitmapImage::advanceAnimation): Call shouldUseAsyncDecodingForAnimatedImageForTesting().
(WebCore::BitmapImage::internalAdvanceAnimation): Assert the current frame is not being decoding asynchronously for any size.
(WebCore::BitmapImage::frameImageAtIndex): Deleted. Moved to the header file but with a new purpose: return
the current frame from the frame cache as is; do not cache a new one.
(WebCore::BitmapImage::shouldUseAsyncDecodingForLargeImage): Deleted. Function was renamed to shouldUseAsyncDecodingForLargeImages.
(WebCore::BitmapImage::shouldUseAsyncDecodingForAnimatedImage): Deleted. Function was renamed to shouldUseAsyncDecodingForAnimatedImages.

  • platform/graphics/BitmapImage.h:
  • platform/graphics/CrossfadeGeneratedImage.cpp:

(WebCore::CrossfadeGeneratedImage::draw): Add a new argument of type DecodingMode.

  • platform/graphics/CrossfadeGeneratedImage.h:
  • platform/graphics/DecodingOptions.h: Added.

(WebCore::DecodingOptions::DecodingOptions): Default constructor: Synchronous mode.
(WebCore::DecodingOptions::operator==): Compares two DecodingOptions for equality.
(WebCore::DecodingOptions::isSynchronous): Is the frame decoded synchronously?
(WebCore::DecodingOptions::isAsynchronous): Is the frame decoded asynchronously?
(WebCore::DecodingOptions::isAsynchronousCompatibleWith): Is this DecodingOptions compatible with another one?
(WebCore::DecodingOptions::hasFullSize): Is the decoding mode asynchronous but for the image full size?
(WebCore::DecodingOptions::hasSizeForDrawing): Is this decoding mode asynchronous but for a sizeForDrawing?
(WebCore::DecodingOptions::sizeForDrawing): Returns the sizeForDrawing. m_decodingModeOrSize has to hold an IntSize.
(WebCore::DecodingOptions::maxDimension): Moved form ImageFrame.cpp.
(WebCore::DecodingOptions::has): A helper function.
(WebCore::DecodingOptions::hasDecodingMode): Does m_decodingModeOrSize a DecodingMode?
(WebCore::DecodingOptions::hasSize): Does m_decodingModeOrSize an IntSize?

  • platform/graphics/GeneratedImage.h: Add a new argument of type DecodingMode.
  • platform/graphics/GradientImage.cpp:

(WebCore::GradientImage::draw): Ditto.

  • platform/graphics/GradientImage.h: Ditto.
  • platform/graphics/GraphicsContext.cpp:

(WebCore::GraphicsContext::drawImage): Pass the ImagePaintingOptions::m_DecodingMode to Image::draw().

  • platform/graphics/GraphicsContext.h:

(WebCore::ImagePaintingOptions::ImagePaintingOptions): Add a new member of type DecodingMode to ImagePaintingOptions.

  • platform/graphics/Image.cpp:

(WebCore::Image::drawTiled): Pass DecodingMode::Synchronous to Image::draw().

  • platform/graphics/Image.h: Add a new argument of type DecodingMode to Image::draw().
  • platform/graphics/ImageFrame.cpp:

(WebCore::ImageFrame::operator=): Replace m_sizeForDrawing by m_decodingOptions.
(WebCore::ImageFrame::hasNativeImage): Check if m_nativeImage is valid and the subsamplingLevels match.
(WebCore::ImageFrame::hasFullSizeNativeImage): Checks hasNativeImage() and whether the image frame was
decoded for the image full size.
(WebCore::ImageFrame::hasDecodedNativeImageCompatibleWithOptions): Checks hasNativeImage() and the DecodingOptions match.
(WebCore::maxDimension): Deleted. Moved to DecodingOptions.h.
(WebCore::ImageFrame::isBeingDecoded): Deleted. The check for having an ImageFrame being decoded is
moved to ImageFrameCache.
(WebCore::ImageFrame::hasValidNativeImage): Deleted. No need to this function.

  • platform/graphics/ImageFrame.h:

(WebCore::ImageFrame::hasNativeImage): Add an std::optional<SubsamplingLevel> argument.
(WebCore::ImageFrame::hasFullSizeNativeImage): Checks whether the ImageFrame was decoded for the image full size.
(WebCore::ImageFrame::enqueueSizeForDecoding): Deleted.
(WebCore::ImageFrame::dequeueSizeForDecoding): Deleted.
(WebCore::ImageFrame::clearSizeForDecoding): Deleted.
(WebCore::ImageFrame::isBeingDecoded): Deleted.
(WebCore::ImageFrame::sizeForDrawing): Deleted.
(WebCore::ImageFrame::hasDecodedNativeImage): Deleted.
The logic of knowing whether an ImageFrame is being decoded is moved to ImageFrameCache.

  • platform/graphics/ImageFrameCache.cpp:

(WebCore::ImageFrameCache::cacheFrameMetadataAtIndex): Caches the metadata of an ImageFrame. If the NativeImage
was decoded for a sizeForDrawing, the size of the ImageFrame will be the nativeImageSize(). Otherwise, the
frameSizeAtIndex() will be called.
(WebCore::ImageFrameCache::cacheFrameNativeImageAtIndex): Cache a new NativeImage which involves caching new
metadata and updating the memory cache. No need to check if the existing native image is valid or not for the
DecodingOptions. Actually it would be a bug if it happens. This is why cacheNativeImageForFrameRequest() asserts
!frame.hasAsyncNativeImage() before calling cacheFrameNativeImageAtIndex().
(WebCore::ImageFrameCache::cacheAsyncFrameNativeImageAtIndex): Cache new NativeImage which was decoded asynchronously.
(WebCore::ImageFrameCache::startAsyncDecodingQueue): Call cacheAsyncFrameNativeImageAtIndex() instead of
cacheNativeImageForFrameRequest() for clarity.
(WebCore::ImageFrameCache::requestFrameAsyncDecodingAtIndex): Call hasAsyncNativeImage() instead of hasValidNativeImage()
Call frameIsDecodingCompatibleWithOptionsAtIndex() instead of frame.isBeingDecoded(). Replace the call to enqueueSizeForDecoding()
by appending the same ImageFrameRequest to m_frameCommitQueue.
(WebCore::ImageFrameCache::isAsyncDecodingQueueIdle): Use m_frameCommitQueue to answer the question whether the decodingQueue is idle.
(WebCore::ImageFrameCache::stopAsyncDecodingQueue): Use m_frameCommitQueue to loop through all the ImageFrames which are currently being decoded.
(WebCore::ImageFrameCache::frameAtIndexCacheIfNeeded): For getting the metadata, this function needs a valid frame. If it is requested
to decode the nativeImage, it has to do it synchronously.
(WebCore::ImageFrameCache::singlePixelSolidColor): Don't cache the frame if it is an animated image or the size is not a single pixel.
(WebCore::ImageFrameCache::frameIsBeingDecodedAndIsCompatibleWithOptionsAtIndex): Use m_frameCommitQueue to answer the question whether an ImageFrame
is being decoded and is compatible with DecodingOptions.
(WebCore::ImageFrameCache::frameHasFullSizeNativeImageAtIndex): Calls ImageFrame::hasFullNativeImage() for a frame.
(WebCore::ImageFrameCache::frameHasDecodedNativeImageCompatibleWithOptionsAtIndex): Calls ImageFrame::hasDecodedNativeImageCompatibleWithOptions() for a frame.
(WebCore::ImageFrameCache::frameImageAtIndex): Returns the current NativeImage without caching.
(WebCore::ImageFrameCache::frameImageAtIndexCacheIfNeeded): Returns the current NativeImage but cache it synchronously if needed.
(WebCore::ImageFrameCache::setFrameNativeImageAtIndex): Deleted.
(WebCore::ImageFrameCache::setFrameMetadataAtIndex): Deleted.
(WebCore::ImageFrameCache::replaceFrameNativeImageAtIndex): Deleted.
(WebCore::ImageFrameCache::frameIsBeingDecodedAtIndex): Deleted.
(WebCore::ImageFrameCache::frameHasImageAtIndex): Deleted.
(WebCore::ImageFrameCache::frameHasValidNativeImageAtIndex): Deleted.
(WebCore::ImageFrameCache::frameHasDecodedNativeImage): Deleted.

  • platform/graphics/ImageFrameCache.h: Two ImageFrameRequest queues will be used.

-- The existing one m_frameRequestQueue which is shared between the main thread and decoding thread. The requests will be
dequeued from it before starting the decoding. The decoded NativeImage will be cached only on the main thread. The decoding
thread is not blocked by the callOnMainThread(). This means there might be multiple ImageFrameRequests which were dequeued
while their NativeImages have not been cached yet.
-- A new one m_frameCommitQueue which is track all the ImageFrameRequests whose NativeImages have not been cached yet.
(WebCore::ImageFrameCache::frameAtIndexCacheIfNeeded): Be explicit about caching the image frame. frameImageAtIndex()
returns the current image frame without caching. frameAtIndexCacheIfNeeded(). returns the current image frame but cache
it if needed.
(WebCore::ImageFrameCache::ImageFrameRequest::operator==): Compares two ImageFrameRequests for equality.

  • platform/graphics/ImageSource.cpp:

(WebCore::ImageSource::frameImageAtIndexCacheIfNeeded):
(WebCore::ImageSource::frameImageAtIndex): Deleted.

  • platform/graphics/ImageSource.h:

(WebCore::ImageSource::requestFrameAsyncDecodingAtIndex): Change the type of the argument from IntSize to be const std::optional<IntSize>.
(WebCore::ImageSource::frameIsBeingDecodedAndIsCompatibleWithOptionsAtIndex): Rename of frameIsBeingDecodedAtIndex(). Replace the argument of type
std::optional<IntSize> by an argument of type DecodingOptions.
(WebCore::ImageSource::frameHasFullSizeNativeImageAtIndex): A wrapper around the ImageFrameCache function.
(WebCore::ImageSource::frameHasDecodedNativeImageCompatibleWithOptionsAtIndex): Ditto.
(WebCore::ImageSource::frameImageAtIndex): Ditto.
(WebCore::ImageSource::frameIsBeingDecodedAtIndex): Deleted.
(WebCore::ImageSource::frameHasValidNativeImageAtIndex): Deleted.
(WebCore::ImageSource::frameHasDecodedNativeImage): Deleted.

  • platform/graphics/NamedImageGeneratedImage.cpp:

(WebCore::NamedImageGeneratedImage::draw): Add a new argument of type DecodingMode.

  • platform/graphics/NamedImageGeneratedImage.h: Ditto.
  • platform/graphics/cairo/ImageBufferCairo.cpp:

(WebCore::ImageBuffer::draw): Add a new argument of type DecodingMode.

  • platform/graphics/cg/ImageDecoderCG.cpp:

(WebCore::ImageDecoder::createFrameImageAtIndex): Replace the sizeForDrawing argument by a DecodingMode argument. Add a new handling
for decoding asynchronously for the image full size.

  • platform/graphics/cg/ImageDecoderCG.h: Change the prototype of the function.
  • platform/graphics/cg/PDFDocumentImage.cpp:

(WebCore::PDFDocumentImage::draw): Add a new argument of type DecodingMode.

  • platform/graphics/cg/PDFDocumentImage.h:
  • platform/graphics/win/ImageCGWin.cpp:

(WebCore::BitmapImage::getHBITMAPOfSize): Pass DecodingMode::Synchronous to Image::draw().
(WebCore::BitmapImage::drawFrameMatchingSourceSize): Ditto.

  • platform/graphics/win/ImageDecoderDirect2D.cpp:

(WebCore::ImageDecoder::createFrameImageAtIndex): Replace the sizeForDrawing argument by a DecodingMode argument.

  • platform/graphics/win/ImageDecoderDirect2D.h: Change the prototype of the function.
  • platform/image-decoders/ImageDecoder.cpp:

(WebCore::ImageDecoder::createFrameImageAtIndex): Replace the sizeForDrawing argument by a DecodingMode argument.

  • platform/image-decoders/ImageDecoder.h: Change the prototype of the function.
  • rendering/RenderBoxModelObject.cpp:

(WebCore::RenderBoxModelObject::paintFillLayerExtended): Draw the background image asynchronously if the image size is large.

  • rendering/RenderImage.cpp:

(WebCore::RenderImage::paintIntoRect): Draw the background image element asynchronously if the image size is large.

  • svg/graphics/SVGImage.cpp:

(WebCore::SVGImage::drawForContainer): Pass DecodingMode::Synchronous to draw().
(WebCore::SVGImage::nativeImageForCurrentFrame): Ditto.
(WebCore::SVGImage::nativeImage): Ditto.
(WebCore::SVGImage::draw): Add a new argument of type DecodingMode.

  • svg/graphics/SVGImage.h: Change the prototype of the function.
  • svg/graphics/SVGImageForContainer.cpp:

(WebCore::SVGImageForContainer::draw): Add a new argument of type DecodingMode.

  • svg/graphics/SVGImageForContainer.h: Change the prototype of the function.

LayoutTests:

  • fast/images/animated-image-different-dest-size-expected.html: Added.
  • fast/images/animated-image-different-dest-size.html: Added.

This test crashes without this patch.

  • fast/images/animated-image-loop-count.html:

Clear the memory cache so the test can be not flaky. Running it with -repeat-each was failing.

  • fast/images/async-image-background-image-expected.html: Added.
  • fast/images/async-image-background-image.html: Added.

Ensures the background image can be drawn asynchronously if it is large.

  • fast/images/async-image-canvas-draw-image-expected.html: Added.
  • fast/images/async-image-canvas-draw-image.html: Added.

Ensures the image is drawn synchronously on the canvas regardless of its size.

  • fast/images/ordered-animated-image-frames.html:

Clear the memory cache so the test can be not flaky. Running it with -repeat-each was failing.

  • fast/images/reset-image-animation-expected.txt:
  • fast/images/reset-image-animation.html:

Change how the steps of the test are ordered so the test can be not flaky.
Running it with -repeat-each was failing.

  • fast/images/resources/red-green-blue-900-300.png: Added.
Location:
trunk
Files:
8 added
42 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r214441 r214450  
     12017-03-27  Said Abou-Hallawa  <sabouhallawa@apple.com>
     2
     3        REGRESSION(213764): Large images should not be decoded asynchronously when they are drawn on a canvas
     4        https://bugs.webkit.org/show_bug.cgi?id=169771
     5
     6        Reviewed by Simon Fraser.
     7
     8        * fast/images/animated-image-different-dest-size-expected.html: Added.
     9        * fast/images/animated-image-different-dest-size.html: Added.
     10        This test crashes without this patch.
     11
     12        * fast/images/animated-image-loop-count.html:
     13        Clear the memory cache so the test can be not flaky. Running it with -repeat-each was failing.
     14
     15        * fast/images/async-image-background-image-expected.html: Added.
     16        * fast/images/async-image-background-image.html: Added.
     17        Ensures the background image can be drawn asynchronously if it is large.
     18
     19        * fast/images/async-image-canvas-draw-image-expected.html: Added.
     20        * fast/images/async-image-canvas-draw-image.html: Added.
     21        Ensures the image is drawn synchronously on the canvas regardless of its size.
     22
     23        * fast/images/ordered-animated-image-frames.html:
     24        Clear the memory cache so the test can be not flaky. Running it with -repeat-each was failing.
     25
     26        * fast/images/reset-image-animation-expected.txt:
     27        * fast/images/reset-image-animation.html:
     28        Change how the steps of the test are ordered so the test can be not flaky.
     29        Running it with -repeat-each was failing.
     30
     31        * fast/images/resources/red-green-blue-900-300.png: Added.
     32
    1332017-03-27  Youenn Fablet  <youenn@apple.com>
    234
  • trunk/LayoutTests/fast/images/animated-image-loop-count.html

    r210951 r214450  
    5858
    5959        (function() {
     60            if (window.internals)
     61                internals.clearMemoryCache();
     62
    6063            if (window.testRunner)
    6164                testRunner.waitUntilDone();
  • trunk/LayoutTests/fast/images/ordered-animated-image-frames.html

    r207386 r214450  
    1010    <canvas id="canvas"></canvas>
    1111    <script>
     12        if (window.internals)
     13            internals.clearMemoryCache();
     14
    1215        if (window.testRunner)
    1316            testRunner.waitUntilDone();
  • trunk/LayoutTests/fast/images/reset-image-animation-expected.txt

    r209131 r214450  
    44
    55
     6PASS internals.imageFrameIndex(image) is 0
     7PASS internals.imageFrameIndex(image) is 1
     8The animation of the image was reset.
     9PASS internals.imageFrameIndex(image) is 0
    610PASS internals.imageFrameIndex(image) is 1
    711PASS internals.imageFrameIndex(image) is 2
  • trunk/LayoutTests/fast/images/reset-image-animation.html

    r209131 r214450  
    77    <canvas id="canvas"></canvas>
    88    <script>
    9         description("Ensure the image animation is played in order after the animation is reset.");
    10         jsTestIsAsync = true;
    11 
    12         internals.clearMemoryCache();
    13 
    149        var image = new Image;
    15         image.onload = imageLoaded;
    16         image.src = "resources/animated-red-green-blue.gif";
    17        
    18         function imageLoaded()
    19         {
    20             if (!window.internals)
    21                 return;
    22             internals.setImageFrameDecodingDuration(image, 0.040);
    23             drawImage();
    24             drawLoop();
     10               
     11        function drawFrame(expectedFrame) {
     12            return new Promise((resolve) => {
     13                let canvas = document.getElementById("canvas");
     14                let context = canvas.getContext("2d");
     15                context.drawImage(image, 0, 0, canvas.width, canvas.height);
     16                shouldBe("internals.imageFrameIndex(image)", expectedFrame.toString());
     17                setTimeout(() => {
     18                    resolve(expectedFrame + 1);
     19                }, 30);
     20            });
    2521        }
    2622
    27         function drawImage()
    28         {
    29             if (drawImage.count == undefined)
    30                 drawImage.count = 0;
    31             var canvas = document.getElementById("canvas");
    32             var ctx = canvas.getContext("2d");
    33             ctx.drawImage(image, 0, 0, canvas.width, canvas.height);
    34             return ++drawImage.count;
     23        function drawImage(frameCount, expectedFrame) {
     24            let promise = drawFrame(expectedFrame);
     25            for (let frame = 1; frame < frameCount; ++frame) {
     26                promise = promise.then((expectedFrame) => {
     27                    return drawFrame(expectedFrame);
     28                });
     29            }
     30            return promise;
    3531        }
     32
     33        function loadImage(src, frameCount) {
     34            return new Promise((resolve) => {
     35                image.onload = (() => {
     36                    if (window.internals)
     37                        internals.setImageFrameDecodingDuration(image, 0.020);
     38                    drawImage(Math.ceil(frameCount / 2), 0).then(() => {
     39                        internals.resetImageAnimation(image);
     40                        debug("The animation of the image was reset.");
     41                        drawImage(frameCount, 0).then(resolve);
     42                    });
     43                });
     44                image.src = src;
     45            });
     46        }
     47
     48        (function() {
     49            if (window.internals)
     50                internals.clearMemoryCache();
     51
     52            description("Ensure the image animation is played in order after the animation is reset.");
     53            jsTestIsAsync = true;
    3654               
    37         function drawLoop()
    38         {
    39             setTimeout(function() {
    40                 switch (drawImage()) {
    41                 case 2:
    42                     shouldBe("internals.imageFrameIndex(image)", "1");
    43                     internals.resetImageAnimation(image);
    44                     drawLoop();
    45                     break;
    46 
    47                 case 5:
    48                     // The animation was reset at drawCount = 2. Three more
    49                     // drawings should make current_frame = 2.
    50                     shouldBe("internals.imageFrameIndex(image)", "2");
    51                     finishJSTest();
    52                     break;
    53                    
    54                 default:
    55                     drawLoop();
    56                 }
    57             }, 50);
    58         }
     55            loadImage("resources/animated-red-green-blue.gif", 3).then(() => {
     56                finishJSTest();
     57            });
     58        })();
    5959    </script>
    6060    <script src="../../resources/js-test-post.js"></script>
  • trunk/Source/WebCore/ChangeLog

    r214445 r214450  
     12017-03-27  Said Abou-Hallawa  <sabouhallawa@apple.com>
     2
     3        REGRESSION(213764): Large images should not be decoded asynchronously when they are drawn on a canvas
     4        https://bugs.webkit.org/show_bug.cgi?id=169771
     5
     6        Reviewed by Simon Fraser.
     7
     8        Sometimes we have to draw the image immediately like when a canvas calls 
     9        drawImage. In this case we have to decode the image synchronously to guarantee
     10        the drawing. Other times we need to decode with the native size of the image.
     11        The animated images have to be decoded with native size always. Otherwise
     12        the frame cache will be messed up if the same image is animated with different
     13        sizes. Currently we always decode asynchronously with sizeForDrawing. We need
     14        to decouple the decoding mode from the sizeForDrawing.
     15
     16        This patch introduce the DecodingOptions class which can store and compare the
     17        following four cases:
     18            -- Synchronous: The frame has be decoded with native size only.
     19            -- Asynchronous + anySize: This is passed from the Image::draw() callers.
     20            -- Asynchronous + fullSize: The image has to be decoded with its full size.
     21            -- Asynchronous + sizeForDrawing: The image can be decoded with sizeForDrawing unless
     22            it was decoded with either a full size or sizeForDrawing which is larger than the
     23            requested sizeForDrawing.
     24           
     25        A new argument of type DecodingMode will be added to Image::draw() function.
     26        Only when the drawing comes from the render tree, it will be Asynchronous.
     27        Otherwise it will be Synchronous.
     28
     29        Tests: fast/images/animated-image-different-dest-size.html
     30               fast/images/async-image-background-image.html
     31               fast/images/async-image-canvas-draw-image.html
     32
     33        * WebCore.xcodeproj/project.pbxproj:
     34        * platform/graphics/BitmapImage.cpp:
     35        (WebCore::BitmapImage::frameImageAtIndexCacheIfNeeded): Gets the frame image, cache it synchronously if
     36        the current one is invalid. frameImageAtIndex() returns whatever stored in the cache.
     37        (WebCore::BitmapImage::nativeImage): Call frameImageAtIndexCacheIfNeeded() instead of frameImageAtIndex().
     38        (WebCore::BitmapImage::nativeImageForCurrentFrame): Ditto.
     39        (WebCore::BitmapImage::nativeImageOfSize): Ditto.
     40        (WebCore::BitmapImage::framesNativeImages): Ditto.
     41        (WebCore::BitmapImage::draw): Change the logic to do the following:
     42        -- The animated image has to be decoded with its full size.
     43        -- The animated image expects the current frame to be ready for drawing.
     44        -- The large image decoding does not need to call internalStartAnimation().
     45        -- The large image has to request async image decoding but draw the current one if it exists.
     46        (WebCore::BitmapImage::drawPattern): Draw the pattern synchronously.
     47        (WebCore::BitmapImage::shouldUseAsyncDecodingForLargeImages): Delete the call to shouldUseAsyncDecodingForTesting()
     48        since it is only applied for animated images.
     49        (WebCore::BitmapImage::shouldUseAsyncDecodingForAnimatedImages): Call shouldUseAsyncDecodingForAnimatedImageForTesting().
     50        (WebCore::BitmapImage::internalStartAnimation): Request decoding with the full size.
     51        (WebCore::BitmapImage::advanceAnimation): Call shouldUseAsyncDecodingForAnimatedImageForTesting().
     52        (WebCore::BitmapImage::internalAdvanceAnimation): Assert the current frame is not being decoding asynchronously for any size.
     53        (WebCore::BitmapImage::frameImageAtIndex): Deleted. Moved to the header file but with a new purpose: return
     54        the current frame from the frame cache as is; do not cache a new one.
     55        (WebCore::BitmapImage::shouldUseAsyncDecodingForLargeImage): Deleted. Function was renamed to shouldUseAsyncDecodingForLargeImages.
     56        (WebCore::BitmapImage::shouldUseAsyncDecodingForAnimatedImage): Deleted. Function was renamed to shouldUseAsyncDecodingForAnimatedImages.
     57        * platform/graphics/BitmapImage.h:
     58        * platform/graphics/CrossfadeGeneratedImage.cpp:
     59        (WebCore::CrossfadeGeneratedImage::draw): Add a new argument of type DecodingMode.
     60        * platform/graphics/CrossfadeGeneratedImage.h:
     61        * platform/graphics/DecodingOptions.h: Added.
     62        (WebCore::DecodingOptions::DecodingOptions): Default constructor: Synchronous mode.
     63        (WebCore::DecodingOptions::operator==): Compares two DecodingOptions for equality.
     64        (WebCore::DecodingOptions::isSynchronous): Is the frame decoded synchronously?
     65        (WebCore::DecodingOptions::isAsynchronous): Is the frame decoded asynchronously?
     66        (WebCore::DecodingOptions::isAsynchronousCompatibleWith): Is this DecodingOptions compatible with another one?
     67        (WebCore::DecodingOptions::hasFullSize): Is the decoding mode asynchronous but for the image full size?
     68        (WebCore::DecodingOptions::hasSizeForDrawing): Is this decoding mode asynchronous but for a sizeForDrawing?
     69        (WebCore::DecodingOptions::sizeForDrawing): Returns the sizeForDrawing. m_decodingModeOrSize has to hold an IntSize.
     70        (WebCore::DecodingOptions::maxDimension): Moved form ImageFrame.cpp.
     71        (WebCore::DecodingOptions::has): A helper function.
     72        (WebCore::DecodingOptions::hasDecodingMode): Does m_decodingModeOrSize a DecodingMode?
     73        (WebCore::DecodingOptions::hasSize): Does m_decodingModeOrSize an IntSize?
     74        * platform/graphics/GeneratedImage.h: Add a new argument of type DecodingMode.
     75        * platform/graphics/GradientImage.cpp:
     76        (WebCore::GradientImage::draw): Ditto.
     77        * platform/graphics/GradientImage.h: Ditto.
     78        * platform/graphics/GraphicsContext.cpp:
     79        (WebCore::GraphicsContext::drawImage): Pass the ImagePaintingOptions::m_DecodingMode to Image::draw().
     80        * platform/graphics/GraphicsContext.h:
     81        (WebCore::ImagePaintingOptions::ImagePaintingOptions): Add a new member of type DecodingMode to ImagePaintingOptions.
     82        * platform/graphics/Image.cpp:
     83        (WebCore::Image::drawTiled): Pass DecodingMode::Synchronous to Image::draw().
     84        * platform/graphics/Image.h: Add a new argument of type DecodingMode to Image::draw().
     85        * platform/graphics/ImageFrame.cpp:
     86        (WebCore::ImageFrame::operator=): Replace m_sizeForDrawing by m_decodingOptions.
     87        (WebCore::ImageFrame::hasNativeImage): Check if m_nativeImage is valid and the subsamplingLevels match.
     88        (WebCore::ImageFrame::hasFullSizeNativeImage): Checks hasNativeImage() and whether the image frame was
     89        decoded for the image full size.
     90        (WebCore::ImageFrame::hasDecodedNativeImageCompatibleWithOptions): Checks hasNativeImage() and the DecodingOptions match.
     91        (WebCore::maxDimension): Deleted. Moved to DecodingOptions.h.
     92        (WebCore::ImageFrame::isBeingDecoded): Deleted. The check for having an ImageFrame being decoded is
     93        moved to ImageFrameCache.
     94        (WebCore::ImageFrame::hasValidNativeImage): Deleted. No need to this function.
     95        * platform/graphics/ImageFrame.h:
     96        (WebCore::ImageFrame::hasNativeImage): Add an std::optional<SubsamplingLevel> argument.
     97        (WebCore::ImageFrame::hasFullSizeNativeImage): Checks whether the ImageFrame was decoded for the image full size.
     98        (WebCore::ImageFrame::enqueueSizeForDecoding): Deleted.
     99        (WebCore::ImageFrame::dequeueSizeForDecoding): Deleted.
     100        (WebCore::ImageFrame::clearSizeForDecoding): Deleted.
     101        (WebCore::ImageFrame::isBeingDecoded): Deleted.
     102        (WebCore::ImageFrame::sizeForDrawing): Deleted.
     103        (WebCore::ImageFrame::hasDecodedNativeImage): Deleted.
     104        The logic of knowing whether an ImageFrame is being decoded is moved to ImageFrameCache.
     105        * platform/graphics/ImageFrameCache.cpp:
     106        (WebCore::ImageFrameCache::cacheFrameMetadataAtIndex): Caches the metadata of an ImageFrame. If the NativeImage
     107        was decoded for a sizeForDrawing, the size of the ImageFrame will be the nativeImageSize(). Otherwise, the
     108        frameSizeAtIndex() will be called.
     109        (WebCore::ImageFrameCache::cacheFrameNativeImageAtIndex): Cache a new NativeImage which involves caching new
     110        metadata and updating the memory cache. No need to check if the existing native image is valid or not for the
     111        DecodingOptions. Actually it would be a bug if it happens. This is why cacheNativeImageForFrameRequest() asserts
     112        !frame.hasAsyncNativeImage() before calling cacheFrameNativeImageAtIndex().
     113        (WebCore::ImageFrameCache::cacheAsyncFrameNativeImageAtIndex): Cache new NativeImage which was decoded asynchronously.
     114        (WebCore::ImageFrameCache::startAsyncDecodingQueue): Call cacheAsyncFrameNativeImageAtIndex() instead of
     115        cacheNativeImageForFrameRequest() for clarity.
     116        (WebCore::ImageFrameCache::requestFrameAsyncDecodingAtIndex): Call hasAsyncNativeImage() instead of hasValidNativeImage()
     117        Call frameIsDecodingCompatibleWithOptionsAtIndex() instead of frame.isBeingDecoded(). Replace the call to enqueueSizeForDecoding()
     118        by appending the same ImageFrameRequest to m_frameCommitQueue.
     119        (WebCore::ImageFrameCache::isAsyncDecodingQueueIdle): Use m_frameCommitQueue to answer the question whether the decodingQueue is idle.
     120        (WebCore::ImageFrameCache::stopAsyncDecodingQueue): Use m_frameCommitQueue to loop through all the ImageFrames which are currently being decoded.
     121        (WebCore::ImageFrameCache::frameAtIndexCacheIfNeeded): For getting the metadata, this function needs a valid frame. If it is requested
     122        to decode the nativeImage, it has to do it synchronously.
     123        (WebCore::ImageFrameCache::singlePixelSolidColor): Don't cache the frame if it is an animated image or the size is not a single pixel.
     124        (WebCore::ImageFrameCache::frameIsBeingDecodedAndIsCompatibleWithOptionsAtIndex): Use m_frameCommitQueue to answer the question whether an ImageFrame
     125        is being decoded and is compatible with DecodingOptions.
     126        (WebCore::ImageFrameCache::frameHasFullSizeNativeImageAtIndex): Calls ImageFrame::hasFullNativeImage() for a frame.
     127        (WebCore::ImageFrameCache::frameHasDecodedNativeImageCompatibleWithOptionsAtIndex): Calls ImageFrame::hasDecodedNativeImageCompatibleWithOptions() for a frame.
     128        (WebCore::ImageFrameCache::frameImageAtIndex): Returns the current NativeImage without caching.
     129        (WebCore::ImageFrameCache::frameImageAtIndexCacheIfNeeded): Returns the current NativeImage but cache it synchronously if needed.
     130        (WebCore::ImageFrameCache::setFrameNativeImageAtIndex): Deleted.
     131        (WebCore::ImageFrameCache::setFrameMetadataAtIndex): Deleted.
     132        (WebCore::ImageFrameCache::replaceFrameNativeImageAtIndex): Deleted.
     133        (WebCore::ImageFrameCache::frameIsBeingDecodedAtIndex): Deleted.
     134        (WebCore::ImageFrameCache::frameHasImageAtIndex): Deleted.
     135        (WebCore::ImageFrameCache::frameHasValidNativeImageAtIndex): Deleted.
     136        (WebCore::ImageFrameCache::frameHasDecodedNativeImage): Deleted.
     137        * platform/graphics/ImageFrameCache.h: Two ImageFrameRequest queues will be used.
     138        -- The existing one m_frameRequestQueue which is shared between the main thread and decoding thread. The requests will be
     139        dequeued from it before starting the decoding. The decoded NativeImage will be cached only on the main thread. The decoding
     140        thread is not blocked by the callOnMainThread(). This means there might be multiple ImageFrameRequests which were dequeued
     141        while their NativeImages have not been cached yet.
     142        -- A new one m_frameCommitQueue which is track all the ImageFrameRequests whose NativeImages have not been cached yet.
     143        (WebCore::ImageFrameCache::frameAtIndexCacheIfNeeded): Be explicit about caching the image frame. frameImageAtIndex()
     144        returns the current image frame without caching. frameAtIndexCacheIfNeeded(). returns the current image frame but cache
     145        it if needed.
     146        (WebCore::ImageFrameCache::ImageFrameRequest::operator==): Compares two ImageFrameRequests for equality.
     147        * platform/graphics/ImageSource.cpp:
     148        (WebCore::ImageSource::frameImageAtIndexCacheIfNeeded):
     149        (WebCore::ImageSource::frameImageAtIndex): Deleted.
     150        * platform/graphics/ImageSource.h:
     151        (WebCore::ImageSource::requestFrameAsyncDecodingAtIndex): Change the type of the argument from IntSize to be const std::optional<IntSize>.
     152        (WebCore::ImageSource::frameIsBeingDecodedAndIsCompatibleWithOptionsAtIndex): Rename of frameIsBeingDecodedAtIndex(). Replace the argument of type
     153        std::optional<IntSize> by an argument of type DecodingOptions.
     154        (WebCore::ImageSource::frameHasFullSizeNativeImageAtIndex): A wrapper around the ImageFrameCache function.
     155        (WebCore::ImageSource::frameHasDecodedNativeImageCompatibleWithOptionsAtIndex): Ditto.
     156        (WebCore::ImageSource::frameImageAtIndex): Ditto.
     157        (WebCore::ImageSource::frameIsBeingDecodedAtIndex): Deleted.
     158        (WebCore::ImageSource::frameHasValidNativeImageAtIndex): Deleted.
     159        (WebCore::ImageSource::frameHasDecodedNativeImage): Deleted.
     160        * platform/graphics/NamedImageGeneratedImage.cpp:
     161        (WebCore::NamedImageGeneratedImage::draw): Add a new argument of type DecodingMode.
     162        * platform/graphics/NamedImageGeneratedImage.h: Ditto.
     163        * platform/graphics/cairo/ImageBufferCairo.cpp:
     164        (WebCore::ImageBuffer::draw): Add a new argument of type DecodingMode.
     165        * platform/graphics/cg/ImageDecoderCG.cpp:
     166        (WebCore::ImageDecoder::createFrameImageAtIndex): Replace the sizeForDrawing argument by a DecodingMode argument. Add a new handling
     167        for decoding asynchronously for the image full size.
     168        * platform/graphics/cg/ImageDecoderCG.h: Change the prototype of the function.
     169        * platform/graphics/cg/PDFDocumentImage.cpp:
     170        (WebCore::PDFDocumentImage::draw): Add a new argument of type DecodingMode.
     171        * platform/graphics/cg/PDFDocumentImage.h:
     172        * platform/graphics/win/ImageCGWin.cpp:
     173        (WebCore::BitmapImage::getHBITMAPOfSize): Pass DecodingMode::Synchronous to Image::draw().
     174        (WebCore::BitmapImage::drawFrameMatchingSourceSize): Ditto.
     175        * platform/graphics/win/ImageDecoderDirect2D.cpp:
     176        (WebCore::ImageDecoder::createFrameImageAtIndex): Replace the sizeForDrawing argument by a DecodingMode argument.
     177        * platform/graphics/win/ImageDecoderDirect2D.h: Change the prototype of the function.
     178        * platform/image-decoders/ImageDecoder.cpp:
     179        (WebCore::ImageDecoder::createFrameImageAtIndex): Replace the sizeForDrawing argument by a DecodingMode argument.
     180        * platform/image-decoders/ImageDecoder.h: Change the prototype of the function.
     181        * rendering/RenderBoxModelObject.cpp:
     182        (WebCore::RenderBoxModelObject::paintFillLayerExtended): Draw the background image asynchronously if the image size is large.
     183        * rendering/RenderImage.cpp:
     184        (WebCore::RenderImage::paintIntoRect): Draw the background image element asynchronously if the image size is large.
     185        * svg/graphics/SVGImage.cpp:
     186        (WebCore::SVGImage::drawForContainer): Pass DecodingMode::Synchronous to draw().
     187        (WebCore::SVGImage::nativeImageForCurrentFrame): Ditto.
     188        (WebCore::SVGImage::nativeImage): Ditto.
     189        (WebCore::SVGImage::draw): Add a new argument of type DecodingMode.
     190        * svg/graphics/SVGImage.h: Change the prototype of the function.
     191        * svg/graphics/SVGImageForContainer.cpp:
     192        (WebCore::SVGImageForContainer::draw): Add a new argument of type DecodingMode.
     193        * svg/graphics/SVGImageForContainer.h: Change the prototype of the function.
     194
    11952017-03-27  Youenn Fablet  <youenn@apple.com>
    2196
  • trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj

    r214420 r214450  
    24902490                550A0BC9085F6039007353D6 /* QualifiedName.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 550A0BC7085F6039007353D6 /* QualifiedName.cpp */; };
    24912491                550A0BCA085F6039007353D6 /* QualifiedName.h in Headers */ = {isa = PBXBuildFile; fileRef = 550A0BC8085F6039007353D6 /* QualifiedName.h */; settings = {ATTRIBUTES = (Private, ); }; };
     2492                555130011E7CCCCB00A69E38 /* DecodingOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 555130001E7CCCCA00A69E38 /* DecodingOptions.h */; settings = {ATTRIBUTES = (Private, ); }; };
    24922493                555B87EC1CAAF0AB00349425 /* ImageDecoderCG.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 555B87EA1CAAF0AB00349425 /* ImageDecoderCG.cpp */; };
    24932494                555B87ED1CAAF0AB00349425 /* ImageDecoderCG.h in Headers */ = {isa = PBXBuildFile; fileRef = 555B87EB1CAAF0AB00349425 /* ImageDecoderCG.h */; };
     
    1016210163                550A0BC7085F6039007353D6 /* QualifiedName.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = QualifiedName.cpp; sourceTree = "<group>"; tabWidth = 8; usesTabs = 0; };
    1016310164                550A0BC8085F6039007353D6 /* QualifiedName.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = QualifiedName.h; sourceTree = "<group>"; tabWidth = 8; usesTabs = 0; };
     10165                555130001E7CCCCA00A69E38 /* DecodingOptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DecodingOptions.h; sourceTree = "<group>"; };
    1016410166                555B87EA1CAAF0AB00349425 /* ImageDecoderCG.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ImageDecoderCG.cpp; sourceTree = "<group>"; };
    1016510167                555B87EB1CAAF0AB00349425 /* ImageDecoderCG.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ImageDecoderCG.h; sourceTree = "<group>"; };
     
    2287522877                                2D2FC0551460CD6F00263633 /* CrossfadeGeneratedImage.h */,
    2287622878                                A8CB41020E85B8A50032C4F0 /* DashArray.h */,
     22879                                555130001E7CCCCA00A69E38 /* DecodingOptions.h */,
    2287722880                                49FC7A4F1444AF5F00A5D864 /* DisplayRefreshMonitor.cpp */,
    2287822881                                49AF2D6814435D050016A784 /* DisplayRefreshMonitor.h */,
     
    2817428177                                141DC054164834B900371E5A /* LayoutSize.h in Headers */,
    2817528178                                2D9066070BE141D400956998 /* LayoutState.h in Headers */,
     28179                                555130011E7CCCCB00A69E38 /* DecodingOptions.h in Headers */,
    2817628180                                141DC0481648348F00371E5A /* LayoutUnit.h in Headers */,
    2817728181                                CDE8B5ED1A69777300B4B66A /* LegacyCDMPrivateClearKey.h in Headers */,
  • trunk/Source/WebCore/platform/graphics/BitmapImage.cpp

    r214241 r214450  
    103103}
    104104
    105 NativeImagePtr BitmapImage::frameImageAtIndex(size_t index, const std::optional<SubsamplingLevel>& subsamplingLevel, const std::optional<IntSize>& sizeForDrawing, const GraphicsContext* targetContext)
    106 {
    107     if (!frameHasValidNativeImageAtIndex(index, subsamplingLevel, sizeForDrawing)) {
     105NativeImagePtr BitmapImage::frameImageAtIndexCacheIfNeeded(size_t index, SubsamplingLevel subsamplingLevel, const GraphicsContext* targetContext)
     106{
     107    if (!frameHasFullSizeNativeImageAtIndex(index, subsamplingLevel)) {
    108108        LOG(Images, "BitmapImage::%s - %p - url: %s [subsamplingLevel was %d, resampling]", __FUNCTION__, this, sourceURL().utf8().data(), static_cast<int>(frameSubsamplingLevelAtIndex(index)));
    109109        invalidatePlatformData();
    110110    }
    111111
    112     return m_source.frameImageAtIndex(index, subsamplingLevel, sizeForDrawing, targetContext);
     112    return m_source.frameImageAtIndexCacheIfNeeded(index, subsamplingLevel, targetContext);
    113113}
    114114
    115115NativeImagePtr BitmapImage::nativeImage(const GraphicsContext* targetContext)
    116116{
    117     return frameImageAtIndex(0, SubsamplingLevel::Default, { }, targetContext);
     117    return frameImageAtIndexCacheIfNeeded(0, SubsamplingLevel::Default, targetContext);
    118118}
    119119
    120120NativeImagePtr BitmapImage::nativeImageForCurrentFrame(const GraphicsContext* targetContext)
    121121{
    122     return frameImageAtIndex(m_currentFrame, SubsamplingLevel::Default, { }, targetContext);
     122    return frameImageAtIndexCacheIfNeeded(m_currentFrame, SubsamplingLevel::Default, targetContext);
    123123}
    124124
     
    129129
    130130    for (size_t i = 0; i < count; ++i) {
    131         auto image = frameImageAtIndex(i, SubsamplingLevel::Default, { }, targetContext);
     131        auto image = frameImageAtIndexCacheIfNeeded(i, SubsamplingLevel::Default, targetContext);
    132132        if (image && nativeImageSize(image) == size)
    133133            return image;
     
    135135
    136136    // Fallback to the first frame image if we can't find the right size
    137     return frameImageAtIndex(0, SubsamplingLevel::Default, { }, targetContext);
     137    return frameImageAtIndexCacheIfNeeded(0, SubsamplingLevel::Default, targetContext);
    138138}
    139139
     
    144144
    145145    for (size_t i = 0; i < count; ++i) {
    146         if (auto image = frameImageAtIndex(i))
     146        if (auto image = frameImageAtIndexCacheIfNeeded(i))
    147147            images.append(image);
    148148    }
     
    159159#endif
    160160
    161 void BitmapImage::draw(GraphicsContext& context, const FloatRect& destRect, const FloatRect& srcRect, CompositeOperator op, BlendMode mode, ImageOrientationDescription description)
     161void BitmapImage::draw(GraphicsContext& context, const FloatRect& destRect, const FloatRect& srcRect, CompositeOperator op, BlendMode mode, DecodingMode decodingMode, ImageOrientationDescription description)
    162162{
    163163    if (destRect.isEmpty() || srcRect.isEmpty())
     
    166166    float scale = subsamplingScale(context, destRect, srcRect);
    167167    m_currentSubsamplingLevel = allowSubsampling() ? m_source.subsamplingLevelForScale(scale) : SubsamplingLevel::Default;
    168     m_sizeForDrawing = enclosingIntRect(context.getCTM().mapRect(destRect)).size();
     168    IntSize sizeForDrawing = enclosingIntRect(context.getCTM().mapRect(destRect)).size();
    169169
    170170    LOG(Images, "BitmapImage::%s - %p - url: %s [subsamplingLevel = %d scale = %.4f]", __FUNCTION__, this, sourceURL().utf8().data(), static_cast<int>(m_currentSubsamplingLevel), scale);
    171171
    172     StartAnimationResult result = internalStartAnimation();
    173     if (result == StartAnimationResult::DecodingActive && showDebugBackground()) {
    174         fillWithSolidColor(context, destRect, Color(Color::yellow).colorWithAlpha(0.5), op);
    175         return;
    176     }
    177 
    178     ASSERT_IMPLIES(result == StartAnimationResult::DecodingActive, m_source.frameHasValidNativeImageAtIndex(m_currentFrame, m_currentSubsamplingLevel, m_sizeForDrawing));
    179 
    180172    NativeImagePtr image;
    181     if (shouldUseAsyncDecodingForLargeImage()) {
    182         if (m_source.frameHasValidNativeImageAtIndex(m_currentFrame, m_currentSubsamplingLevel, m_sizeForDrawing))
    183             image = frameImageAtIndex(m_currentFrame, m_currentSubsamplingLevel, m_sizeForDrawing, &context);
    184         else {
    185             ASSERT(!canAnimate() && !m_currentFrame);
    186             if (!frameIsBeingDecodedAtIndex(m_currentFrame, m_sizeForDrawing)) {
    187                 m_source.requestFrameAsyncDecodingAtIndex(0, m_currentSubsamplingLevel, m_sizeForDrawing);
    188                 LOG(Images, "BitmapImage::%s - %p - url: %s [requesting large async decoding]", __FUNCTION__, this, sourceURL().utf8().data());
     173    if (decodingMode == DecodingMode::Asynchronous && shouldUseAsyncDecodingForLargeImages()) {
     174        ASSERT(!canAnimate() && !m_currentFrame);
     175
     176        if (!frameHasDecodedNativeImageCompatibleWithOptionsAtIndex(m_currentFrame, m_currentSubsamplingLevel, DecodingOptions(sizeForDrawing))
     177            && !frameIsBeingDecodedAndIsCompatibleWithOptionsAtIndex(m_currentFrame, DecodingOptions(sizeForDrawing))) {
     178            m_source.requestFrameAsyncDecodingAtIndex(0, m_currentSubsamplingLevel, sizeForDrawing);
     179            LOG(Images, "BitmapImage::%s - %p - url: %s [requesting large async decoding]", __FUNCTION__, this, sourceURL().utf8().data());
     180        }
     181
     182        if (!frameHasDecodedNativeImageCompatibleWithOptionsAtIndex(m_currentFrame, m_currentSubsamplingLevel, DecodingMode::Asynchronous)) {
     183            if (showDebugBackground())
     184                fillWithSolidColor(context, destRect, Color(Color::yellow).colorWithAlpha(0.5), op);
     185            return;
     186        }
     187
     188        image = frameImageAtIndex(m_currentFrame);
     189    } else {
     190        StartAnimationStatus status = internalStartAnimation();
     191        ASSERT_IMPLIES(status == StartAnimationStatus::DecodingActive, frameHasFullSizeNativeImageAtIndex(m_currentFrame, m_currentSubsamplingLevel));
     192
     193        if (status == StartAnimationStatus::DecodingActive && showDebugBackground()) {
     194            fillWithSolidColor(context, destRect, Color(Color::yellow).colorWithAlpha(0.5), op);
     195            return;
     196        }
     197
     198        if (frameIsBeingDecodedAndIsCompatibleWithOptionsAtIndex(m_currentFrame, DecodingMode::Asynchronous)) {
     199            // FIXME: instead of showing the yellow rectangle and returning we need to wait for this the frame to finish decoding.
     200            if (showDebugBackground()) {
     201                fillWithSolidColor(context, destRect, Color(Color::yellow).colorWithAlpha(0.5), op);
     202                LOG(Images, "BitmapImage::%s - %p - url: %s [waiting for async decoding to finish]", __FUNCTION__, this, sourceURL().utf8().data());
    189203            }
    190 
    191             if (!frameHasDecodedNativeImage(m_currentFrame)) {
    192                 if (showDebugBackground())
    193                     fillWithSolidColor(context, destRect, Color(Color::yellow).colorWithAlpha(0.5), op);
    194                 return;
    195             }
    196 
    197             image = frameImageAtIndex(m_currentFrame);
    198         }
    199     } else {
    200         ASSERT(!frameIsBeingDecodedAtIndex(m_currentFrame, m_sizeForDrawing));
    201         if (shouldUseAsyncDecodingForAnimatedImage())
    202             image = frameImageAtIndex(m_currentFrame);
    203         else
    204             image = frameImageAtIndex(m_currentFrame, m_currentSubsamplingLevel, { }, &context);
    205     }
    206 
    207     if (!image) // If it's too early we won't have an image yet.
    208         return;
    209 
     204            return;
     205        }
     206
     207        image = frameImageAtIndexCacheIfNeeded(m_currentFrame, m_currentSubsamplingLevel, &context);
     208        if (!image) // If it's too early we won't have an image yet.
     209            return;
     210    }
     211
     212    ASSERT(image);
    210213    Color color = singlePixelSolidColor();
    211214    if (color.isValid()) {
     
    244247        setImageObserver(nullptr);
    245248
    246         draw(buffer->context(), tileRect, tileRect, op, blendMode, ImageOrientationDescription());
     249        draw(buffer->context(), tileRect, tileRect, op, blendMode, DecodingMode::Synchronous, ImageOrientationDescription());
    247250
    248251        setImageObserver(observer);
     
    268271}
    269272
    270 bool BitmapImage::shouldUseAsyncDecodingForLargeImage()
    271 {
    272     return !canAnimate() && allowLargeImageAsyncDecoding() && (shouldUseAsyncDecodingForTesting() || m_source.shouldUseAsyncDecoding());
    273 }
    274 
    275 bool BitmapImage::shouldUseAsyncDecodingForAnimatedImage()
    276 {
    277     return canAnimate() && allowAnimatedImageAsyncDecoding() && (shouldUseAsyncDecodingForTesting() || m_source.shouldUseAsyncDecoding());
     273bool BitmapImage::shouldUseAsyncDecodingForLargeImages()
     274{
     275    return !canAnimate() && allowLargeImageAsyncDecoding() && m_source.shouldUseAsyncDecoding();
     276}
     277
     278bool BitmapImage::shouldUseAsyncDecodingForAnimatedImages()
     279{
     280    return canAnimate() && allowAnimatedImageAsyncDecoding() && (shouldUseAsyncDecodingForAnimatedImagesForTesting() || m_source.shouldUseAsyncDecoding());
    278281}
    279282
     
    290293}
    291294
    292 BitmapImage::StartAnimationResult BitmapImage::internalStartAnimation()
     295BitmapImage::StartAnimationStatus BitmapImage::internalStartAnimation()
    293296{
    294297    if (!canAnimate())
    295         return StartAnimationResult::CannotStart;
     298        return StartAnimationStatus::CannotStart;
    296299
    297300    if (m_frameTimer)
    298         return StartAnimationResult::TimerActive;
     301        return StartAnimationStatus::TimerActive;
    299302
    300303    // Don't start a new animation until we draw the frame that is currently being decoded.
    301304    size_t nextFrame = (m_currentFrame + 1) % frameCount();
    302     if (frameIsBeingDecodedAtIndex(nextFrame, m_sizeForDrawing)) {
     305    if (frameIsBeingDecodedAndIsCompatibleWithOptionsAtIndex(nextFrame, DecodingMode::Asynchronous)) {
    303306        LOG(Images, "BitmapImage::%s - %p - url: %s [nextFrame = %ld is being decoded]", __FUNCTION__, this, sourceURL().utf8().data(), nextFrame);
    304         return StartAnimationResult::DecodingActive;
     307        return StartAnimationStatus::DecodingActive;
    305308    }
    306309
     
    311314        // wait on it.
    312315        if (!m_source.isAllDataReceived() && repetitionCount() == RepetitionCountOnce)
    313             return StartAnimationResult::IncompleteData;
     316            return StartAnimationStatus::IncompleteData;
    314317
    315318        ++m_repetitionsComplete;
     
    319322            m_animationFinished = true;
    320323            destroyDecodedDataIfNecessary(false);
    321             return StartAnimationResult::CannotStart;
     324            return StartAnimationStatus::CannotStart;
    322325        }
    323326
     
    327330    // Don't advance the animation to an incomplete frame.
    328331    if (!m_source.isAllDataReceived() && !frameIsCompleteAtIndex(nextFrame))
    329         return StartAnimationResult::IncompleteData;
     332        return StartAnimationStatus::IncompleteData;
    330333
    331334    double time = monotonicallyIncreasingTime();
     
    342345    // through the callback newFrameNativeImageAvailableAtIndex(). Otherwise, advanceAnimation() will be called
    343346    // when the timer fires and m_currentFrame will be advanced to nextFrame since it is not being decoded.
    344     if (shouldUseAsyncDecodingForAnimatedImage()) {
    345         bool isAsyncDecode = m_source.requestFrameAsyncDecodingAtIndex(nextFrame, m_currentSubsamplingLevel, m_sizeForDrawing);
     347    if (shouldUseAsyncDecodingForAnimatedImages()) {
     348        bool isAsyncDecode = m_source.requestFrameAsyncDecodingAtIndex(nextFrame, m_currentSubsamplingLevel);
    346349
    347350#if !LOG_DISABLED
     
    361364    ASSERT(!m_frameTimer);
    362365    startTimer(m_desiredFrameStartTime - time);
    363     return StartAnimationResult::Started;
     366    return StartAnimationStatus::Started;
    364367}
    365368
     
    370373    // Pretend as if decoding nextFrame has taken m_frameDecodingDurationForTesting from
    371374    // the time this decoding was requested.
    372     if (shouldUseAsyncDecodingForTesting()) {
     375    if (shouldUseAsyncDecodingForAnimatedImagesForTesting()) {
    373376        double time = monotonicallyIncreasingTime();
    374377        // Start a timer with the remaining time from now till the m_desiredFrameDecodeTime.
     
    381384    // Don't advance to nextFrame unless its decoding has finished or was not required.
    382385    size_t nextFrame = (m_currentFrame + 1) % frameCount();
    383     if (!frameIsBeingDecodedAtIndex(nextFrame, m_sizeForDrawing))
     386    if (!frameIsBeingDecodedAndIsCompatibleWithOptionsAtIndex(nextFrame, DecodingMode::Asynchronous))
    384387        internalAdvanceAnimation();
    385388    else {
     
    394397{
    395398    m_currentFrame = (m_currentFrame + 1) % frameCount();
    396     ASSERT(!frameIsBeingDecodedAtIndex(m_currentFrame, m_sizeForDrawing));
     399    ASSERT(!frameIsBeingDecodedAndIsCompatibleWithOptionsAtIndex(m_currentFrame, DecodingMode::Asynchronous));
    397400
    398401    destroyDecodedDataIfNecessary(false);
  • trunk/Source/WebCore/platform/graphics/BitmapImage.h

    r214103 r214450  
    8282    IntSize sizeRespectingOrientation() const { return m_source.sizeRespectingOrientation(); }
    8383    Color singlePixelSolidColor() const override { return m_source.singlePixelSolidColor(); }
    84 
    85     bool frameIsBeingDecodedAtIndex(size_t index, const std::optional<IntSize>& sizeForDrawing) const { return m_source.frameIsBeingDecodedAtIndex(index, sizeForDrawing); }
    86     bool frameHasDecodedNativeImage(size_t index) const { return m_source.frameHasDecodedNativeImage(index); }
     84    bool frameIsBeingDecodedAndIsCompatibleWithOptionsAtIndex(size_t index, const DecodingOptions& decodingOptions) const { return m_source.frameIsBeingDecodedAndIsCompatibleWithOptionsAtIndex(index, decodingOptions); }
    8785    bool frameIsCompleteAtIndex(size_t index) const { return m_source.frameIsCompleteAtIndex(index); }
    8886    bool frameHasAlphaAtIndex(size_t index) const { return m_source.frameHasAlphaAtIndex(index); }
    89     bool frameHasValidNativeImageAtIndex(size_t index, const std::optional<SubsamplingLevel>& subsamplingLevel, const std::optional<IntSize>& sizeForDrawing) const { return m_source.frameHasValidNativeImageAtIndex(index, subsamplingLevel, sizeForDrawing); }
     87
     88    bool frameHasFullSizeNativeImageAtIndex(size_t index, SubsamplingLevel subsamplingLevel) { return m_source.frameHasFullSizeNativeImageAtIndex(index, subsamplingLevel); }
     89    bool frameHasDecodedNativeImageCompatibleWithOptionsAtIndex(size_t index, const std::optional<SubsamplingLevel>& subsamplingLevel, const DecodingOptions& decodingOptions) { return m_source.frameHasDecodedNativeImageCompatibleWithOptionsAtIndex(index, subsamplingLevel, decodingOptions); }
     90
    9091    SubsamplingLevel frameSubsamplingLevelAtIndex(size_t index) const { return m_source.frameSubsamplingLevelAtIndex(index); }
    9192
     
    9798    ImageOrientation orientationForCurrentFrame() const override { return frameOrientationAtIndex(currentFrame()); }
    9899
    99     bool shouldUseAsyncDecodingForTesting() const { return m_frameDecodingDurationForTesting > 0; }
     100    bool shouldUseAsyncDecodingForAnimatedImagesForTesting() const { return m_frameDecodingDurationForTesting > 0; }
    100101    void setFrameDecodingDurationForTesting(float duration) { m_frameDecodingDurationForTesting = duration; }
    101     bool shouldUseAsyncDecodingForLargeImage();
    102     bool shouldUseAsyncDecodingForAnimatedImage();
     102    bool shouldUseAsyncDecodingForLargeImages();
     103    bool shouldUseAsyncDecodingForAnimatedImages();
    103104    void setClearDecoderAfterAsyncFrameRequestForTesting(bool value) { m_clearDecoderAfterAsyncFrameRequestForTesting = value; }
    104105
     
    133134    WEBCORE_EXPORT BitmapImage(ImageObserver* = nullptr);
    134135
    135     NativeImagePtr frameImageAtIndex(size_t, const std::optional<SubsamplingLevel>& = { }, const std::optional<IntSize>& sizeForDrawing = { }, const GraphicsContext* = nullptr);
     136    NativeImagePtr frameImageAtIndex(size_t index) { return m_source.frameImageAtIndex(index); }
     137    NativeImagePtr frameImageAtIndexCacheIfNeeded(size_t, SubsamplingLevel = SubsamplingLevel::Default, const GraphicsContext* = nullptr);
    136138
    137139    String sourceURL() const { return imageObserver() ? imageObserver()->sourceUrl().string() : emptyString(); }
     
    153155    void destroyDecodedDataIfNecessary(bool destroyAll = true);
    154156
    155     void draw(GraphicsContext&, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator, BlendMode, ImageOrientationDescription) override;
     157    void draw(GraphicsContext&, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator, BlendMode, DecodingMode, ImageOrientationDescription) override;
    156158    void drawPattern(GraphicsContext&, const FloatRect& destRect, const FloatRect& srcRect, const AffineTransform& patternTransform, const FloatPoint& phase, const FloatSize& spacing, CompositeOperator, BlendMode = BlendModeNormal) override;
    157159#if PLATFORM(WIN)
     
    160162
    161163    // Animation.
    162     enum class StartAnimationResult { CannotStart, IncompleteData, TimerActive, DecodingActive, Started };
     164    enum class StartAnimationStatus { CannotStart, IncompleteData, TimerActive, DecodingActive, Started };
    163165    bool isAnimated() const override { return m_source.frameCount() > 1; }
    164166    bool shouldAnimate();
    165167    bool canAnimate();
    166168    void startAnimation() override { internalStartAnimation(); }
    167     StartAnimationResult internalStartAnimation();
     169    StartAnimationStatus internalStartAnimation();
    168170    void advanceAnimation();
    169171    void internalAdvanceAnimation();
     
    204206    size_t m_currentFrame { 0 }; // The index of the current frame of animation.
    205207    SubsamplingLevel m_currentSubsamplingLevel { SubsamplingLevel::Default };
    206     IntSize m_sizeForDrawing;
    207208    std::unique_ptr<Timer> m_frameTimer;
    208209    RepetitionCount m_repetitionsComplete { RepetitionCountNone }; // How many repetitions we've finished.
  • trunk/Source/WebCore/platform/graphics/CrossfadeGeneratedImage.cpp

    r206631 r214450  
    8787}
    8888
    89 void CrossfadeGeneratedImage::draw(GraphicsContext& context, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator compositeOp, BlendMode blendMode, ImageOrientationDescription)
     89void CrossfadeGeneratedImage::draw(GraphicsContext& context, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator compositeOp, BlendMode blendMode, DecodingMode, ImageOrientationDescription)
    9090{
    9191    GraphicsContextStateSaver stateSaver(context);
  • trunk/Source/WebCore/platform/graphics/CrossfadeGeneratedImage.h

    r206631 r214450  
    5050
    5151protected:
    52     void draw(GraphicsContext&, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator, BlendMode, ImageOrientationDescription) override;
     52    void draw(GraphicsContext&, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator, BlendMode, DecodingMode, ImageOrientationDescription) override;
    5353    void drawPattern(GraphicsContext&, const FloatRect& dstRect, const FloatRect& srcRect, const AffineTransform& patternTransform, const FloatPoint& phase, const FloatSize& spacing, CompositeOperator, BlendMode) override;
    5454
  • trunk/Source/WebCore/platform/graphics/GeneratedImage.h

    r206631 r214450  
    4848
    4949protected:
    50     void draw(GraphicsContext&, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator, BlendMode, ImageOrientationDescription) override = 0;
     50    void draw(GraphicsContext&, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator, BlendMode, DecodingMode, ImageOrientationDescription) override = 0;
    5151    void drawPattern(GraphicsContext&, const FloatRect& destRect, const FloatRect& srcRect, const AffineTransform& patternTransform,
    5252        const FloatPoint& phase, const FloatSize& spacing, CompositeOperator, BlendMode) override = 0;
  • trunk/Source/WebCore/platform/graphics/GradientImage.cpp

    r210215 r214450  
    4242}
    4343
    44 void GradientImage::draw(GraphicsContext& destContext, const FloatRect& destRect, const FloatRect& srcRect, CompositeOperator compositeOp, BlendMode blendMode, ImageOrientationDescription)
     44void GradientImage::draw(GraphicsContext& destContext, const FloatRect& destRect, const FloatRect& srcRect, CompositeOperator compositeOp, BlendMode blendMode, DecodingMode, ImageOrientationDescription)
    4545{
    4646    GraphicsContextStateSaver stateSaver(destContext);
  • trunk/Source/WebCore/platform/graphics/GradientImage.h

    r210215 r214450  
    4545    GradientImage(Gradient&, const FloatSize&);
    4646
    47     void draw(GraphicsContext&, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator, BlendMode, ImageOrientationDescription) final;
     47    void draw(GraphicsContext&, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator, BlendMode, DecodingMode, ImageOrientationDescription) final;
    4848    void drawPattern(GraphicsContext&, const FloatRect& destRect, const FloatRect& srcRect, const AffineTransform& patternTransform, const FloatPoint& phase, const FloatSize& spacing, CompositeOperator, BlendMode) final;
    4949    bool isGradientImage() const final { return true; }
  • trunk/Source/WebCore/platform/graphics/GraphicsContext.cpp

    r208985 r214450  
    729729
    730730    InterpolationQualityMaintainer interpolationQualityForThisScope(*this, imagePaintingOptions.m_interpolationQuality);
    731     image.draw(*this, destination, source, imagePaintingOptions.m_compositeOperator, imagePaintingOptions.m_blendMode, imagePaintingOptions.m_orientationDescription);
     731    image.draw(*this, destination, source, imagePaintingOptions.m_compositeOperator, imagePaintingOptions.m_blendMode, imagePaintingOptions.m_decodingMode, imagePaintingOptions.m_orientationDescription);
    732732}
    733733
  • trunk/Source/WebCore/platform/graphics/GraphicsContext.h

    r208985 r214450  
    189189
    190190struct ImagePaintingOptions {
    191     ImagePaintingOptions(CompositeOperator compositeOperator = CompositeSourceOver, BlendMode blendMode = BlendModeNormal, ImageOrientationDescription orientationDescription = ImageOrientationDescription(), InterpolationQuality interpolationQuality = InterpolationDefault)
     191    ImagePaintingOptions(CompositeOperator compositeOperator = CompositeSourceOver, BlendMode blendMode = BlendModeNormal, DecodingMode decodingMode = DecodingMode::Synchronous, ImageOrientationDescription orientationDescription = ImageOrientationDescription(), InterpolationQuality interpolationQuality = InterpolationDefault)
    192192        : m_compositeOperator(compositeOperator)
    193193        , m_blendMode(blendMode)
     194        , m_decodingMode(decodingMode)
    194195        , m_orientationDescription(orientationDescription)
    195196        , m_interpolationQuality(interpolationQuality)
     
    197198    }
    198199
    199     ImagePaintingOptions(ImageOrientationDescription orientationDescription, InterpolationQuality interpolationQuality = InterpolationDefault, CompositeOperator compositeOperator = CompositeSourceOver, BlendMode blendMode = BlendModeNormal)
     200    ImagePaintingOptions(ImageOrientationDescription orientationDescription, InterpolationQuality interpolationQuality = InterpolationDefault, CompositeOperator compositeOperator = CompositeSourceOver, BlendMode blendMode = BlendModeNormal, DecodingMode decodingMode = DecodingMode::Synchronous)
    200201        : m_compositeOperator(compositeOperator)
    201202        , m_blendMode(blendMode)
     203        , m_decodingMode(decodingMode)
    202204        , m_orientationDescription(orientationDescription)
    203205        , m_interpolationQuality(interpolationQuality)
     
    205207    }
    206208
    207     ImagePaintingOptions(InterpolationQuality interpolationQuality, ImageOrientationDescription orientationDescription = ImageOrientationDescription(), CompositeOperator compositeOperator = CompositeSourceOver, BlendMode blendMode = BlendModeNormal)
     209    ImagePaintingOptions(InterpolationQuality interpolationQuality, ImageOrientationDescription orientationDescription = ImageOrientationDescription(), CompositeOperator compositeOperator = CompositeSourceOver, BlendMode blendMode = BlendModeNormal, DecodingMode decodingMode = DecodingMode::Synchronous)
    208210        : m_compositeOperator(compositeOperator)
    209211        , m_blendMode(blendMode)
     212        , m_decodingMode(decodingMode)
    210213        , m_orientationDescription(orientationDescription)
    211214        , m_interpolationQuality(interpolationQuality)
     
    217220    CompositeOperator m_compositeOperator;
    218221    BlendMode m_blendMode;
     222    DecodingMode m_decodingMode;
    219223    ImageOrientationDescription m_orientationDescription;
    220224    InterpolationQuality m_interpolationQuality;
  • trunk/Source/WebCore/platform/graphics/Image.cpp

    r210828 r214450  
    127127        visibleSrcRect.setWidth(destRect.width() / scale.width());
    128128        visibleSrcRect.setHeight(destRect.height() / scale.height());
    129         draw(ctxt, destRect, visibleSrcRect, op, blendMode, ImageOrientationDescription());
     129        draw(ctxt, destRect, visibleSrcRect, op, blendMode, DecodingMode::Synchronous, ImageOrientationDescription());
    130130        return;
    131131    }
     
    140140            visibleSrcRect.setWidth(1);
    141141            visibleSrcRect.setHeight(destRect.height() / scale.height());
    142             draw(ctxt, destRect, visibleSrcRect, op, BlendModeNormal, ImageOrientationDescription());
     142            draw(ctxt, destRect, visibleSrcRect, op, BlendModeNormal, DecodingMode::Synchronous, ImageOrientationDescription());
    143143            return;
    144144        }
     
    149149            visibleSrcRect.setWidth(destRect.width() / scale.width());
    150150            visibleSrcRect.setHeight(1);
    151             draw(ctxt, destRect, visibleSrcRect, op, BlendModeNormal, ImageOrientationDescription());
     151            draw(ctxt, destRect, visibleSrcRect, op, BlendModeNormal, DecodingMode::Synchronous, ImageOrientationDescription());
    152152            return;
    153153        }
     
    181181                fromRect.scale(1 / scale.width(), 1 / scale.height());
    182182
    183                 draw(ctxt, toRect, fromRect, op, BlendModeNormal, ImageOrientationDescription());
     183                draw(ctxt, toRect, fromRect, op, BlendModeNormal, DecodingMode::Synchronous, ImageOrientationDescription());
    184184                toX += currentTileRect.width();
    185185                currentTileRect.shiftXEdgeTo(oneTileRect.x());
  • trunk/Source/WebCore/platform/graphics/Image.h

    r213715 r214450  
    2929
    3030#include "Color.h"
     31#include "DecodingOptions.h"
    3132#include "FloatRect.h"
    3233#include "FloatSize.h"
     
    185186    virtual void drawFrameMatchingSourceSize(GraphicsContext&, const FloatRect& dstRect, const IntSize& srcSize, CompositeOperator) { }
    186187#endif
    187     virtual void draw(GraphicsContext&, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator, BlendMode, ImageOrientationDescription) = 0;
     188    virtual void draw(GraphicsContext&, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator, BlendMode, DecodingMode, ImageOrientationDescription) = 0;
    188189    void drawTiled(GraphicsContext&, const FloatRect& dstRect, const FloatPoint& srcPoint, const FloatSize& tileSize, const FloatSize& spacing, CompositeOperator, BlendMode);
    189190    void drawTiled(GraphicsContext&, const FloatRect& dstRect, const FloatRect& srcRect, const FloatSize& tileScaleFactor, TileRule hRule, TileRule vRule, CompositeOperator);
  • trunk/Source/WebCore/platform/graphics/ImageFrame.cpp

    r213563 r214450  
    6464    m_nativeImage = other.m_nativeImage;
    6565    m_subsamplingLevel = other.m_subsamplingLevel;
    66     m_sizeForDrawing = other.m_sizeForDrawing;
     66    m_decodingOptions = other.m_decodingOptions;
    6767
    6868    m_orientation = other.m_orientation;
     
    8686    clearNativeImageSubimages(m_nativeImage);
    8787    m_nativeImage = nullptr;
     88    m_decodingOptions = { };
    8889
    8990    return frameBytes;
     
    126127}
    127128   
    128 static int maxDimension(const IntSize& size)
     129bool ImageFrame::hasNativeImage(const std::optional<SubsamplingLevel>& subsamplingLevel) const
    129130{
    130     return std::max(size.width(), size.height());
     131    return m_nativeImage && (!subsamplingLevel || *subsamplingLevel >= m_subsamplingLevel);
    131132}
    132133
    133 bool ImageFrame::isBeingDecoded(const std::optional<IntSize>& sizeForDrawing) const
     134bool ImageFrame::hasFullSizeNativeImage(const std::optional<SubsamplingLevel>& subsamplingLevel) const
    134135{
    135     if (!m_sizeForDecoding.size())
    136         return false;
    137    
    138     if (!sizeForDrawing)
    139         return true;
     136    return hasNativeImage(subsamplingLevel) && (m_decodingOptions.isSynchronous() || m_decodingOptions.hasFullSize());
     137}
    140138
    141     // Return true if the ImageFrame will be decoded eventually with a suitable sizeForDecoding.
    142     return maxDimension(m_sizeForDecoding.last()) >= maxDimension(*sizeForDrawing);
    143 }
    144    
    145 bool ImageFrame::hasValidNativeImage(const std::optional<SubsamplingLevel>& subsamplingLevel, const std::optional<IntSize>& sizeForDrawing) const
     139bool ImageFrame::hasDecodedNativeImageCompatibleWithOptions(const std::optional<SubsamplingLevel>& subsamplingLevel, const DecodingOptions& decodingOptions) const
    146140{
    147     ASSERT_IMPLIES(!subsamplingLevel, !sizeForDrawing);
    148 
    149     if (!hasNativeImage())
    150         return false;
    151 
    152     // The caller does not care about subsamplingLevel or sizeForDrawing. The current NativeImage is fine.
    153     if (!subsamplingLevel)
    154         return true;
    155 
    156     if (*subsamplingLevel < m_subsamplingLevel)
    157         return false;
    158 
    159     // The NativeImage was decoded with the native size. So it is valid for any size.
    160     if (!m_sizeForDrawing)
    161         return true;
    162 
    163     // The NativeImage was decoded for a specific size. The two sizeForDrawings have to match.
    164     return sizeForDrawing && maxDimension(*m_sizeForDrawing) >= maxDimension(*sizeForDrawing);
     141    return hasNativeImage(subsamplingLevel) && m_decodingOptions.isAsynchronousCompatibleWith(decodingOptions);
    165142}
    166143
  • trunk/Source/WebCore/platform/graphics/ImageFrame.h

    r213563 r214450  
    2727
    2828#include "Color.h"
     29#include "DecodingOptions.h"
    2930#include "ImageBackingStore.h"
    3031#include "ImageOrientation.h"
     
    99100    void setDecoding(Decoding decoding) { m_decoding = decoding; }
    100101    Decoding decoding() const { return m_decoding; }
    101     void enqueueSizeForDecoding(const IntSize& sizeForDecoding) { m_sizeForDecoding.append(sizeForDecoding); }
    102     void dequeueSizeForDecoding() { m_sizeForDecoding.removeFirst(); }
    103     void clearSizeForDecoding() { m_sizeForDecoding.clear(); }
    104102
    105103    bool isEmpty() const { return m_decoding == Decoding::None; }
    106     bool isBeingDecoded(const std::optional<IntSize>& sizeForDrawing = { }) const;
    107104    bool isPartial() const { return m_decoding == Decoding::Partial; }
    108105    bool isComplete() const { return m_decoding == Decoding::Complete; }
     
    112109    unsigned frameBytes() const { return hasNativeImage() ? (size().area() * sizeof(RGBA32)).unsafeGet() : 0; }
    113110    SubsamplingLevel subsamplingLevel() const { return m_subsamplingLevel; }
    114     std::optional<IntSize> sizeForDrawing() const { return m_sizeForDrawing; }
    115111
    116112#if !USE(CG)
     
    131127    bool hasAlpha() const { return !hasMetadata() || m_hasAlpha; }
    132128
    133     bool hasNativeImage() const { return m_nativeImage; }
    134     bool hasValidNativeImage(const std::optional<SubsamplingLevel>&, const std::optional<IntSize>& sizeForDrawing) const;
    135     bool hasDecodedNativeImage() const { return hasNativeImage() && sizeForDrawing(); }
     129    bool hasNativeImage(const std::optional<SubsamplingLevel>& = { }) const;
     130    bool hasFullSizeNativeImage(const std::optional<SubsamplingLevel>& = { }) const;
     131    bool hasDecodedNativeImageCompatibleWithOptions(const std::optional<SubsamplingLevel>&, const DecodingOptions&) const;
    136132    bool hasMetadata() const { return !size().isEmpty(); }
    137133
     
    154150    NativeImagePtr m_nativeImage;
    155151    SubsamplingLevel m_subsamplingLevel { SubsamplingLevel::Default };
    156     std::optional<IntSize> m_sizeForDrawing;
    157     Deque<IntSize, 4> m_sizeForDecoding;
     152    DecodingOptions m_decodingOptions;
    158153
    159154    ImageOrientation m_orientation { DefaultImageOrientation };
  • trunk/Source/WebCore/platform/graphics/ImageFrameCache.cpp

    r214084 r214450  
    193193}
    194194
    195 void ImageFrameCache::setFrameNativeImageAtIndex(NativeImagePtr&& nativeImage, size_t index, SubsamplingLevel subsamplingLevel, const std::optional<IntSize>& sizeForDrawing)
    196 {
    197     ASSERT(index < m_frames.size());
    198     ImageFrame& frame = m_frames[index];
    199 
    200     ASSERT(isDecoderAvailable());
    201 
    202     frame.m_nativeImage = WTFMove(nativeImage);
    203     setFrameMetadataAtIndex(index, subsamplingLevel, sizeForDrawing);
    204 }
    205 
    206 void ImageFrameCache::setFrameMetadataAtIndex(size_t index, SubsamplingLevel subsamplingLevel, const std::optional<IntSize>& sizeForDrawing)
     195void ImageFrameCache::cacheFrameMetadataAtIndex(size_t index, SubsamplingLevel subsamplingLevel)
    207196{
    208197    ASSERT(index < m_frames.size());
     
    216205    frame.m_subsamplingLevel = subsamplingLevel;
    217206
    218     if (!sizeForDrawing) {
    219         frame.m_size = m_decoder->frameSizeAtIndex(index, frame.m_subsamplingLevel);
    220         frame.m_sizeForDrawing = { };
    221     } else {
    222         ASSERT(frame.nativeImage());
     207    if (frame.m_decodingOptions.hasSizeForDrawing()) {
     208        ASSERT(frame.hasNativeImage());
    223209        frame.m_size = nativeImageSize(frame.nativeImage());
    224         frame.m_sizeForDrawing = sizeForDrawing;
    225     }
     210    } else
     211        frame.m_size = m_decoder->frameSizeAtIndex(index, subsamplingLevel);
    226212
    227213    frame.m_orientation = m_decoder->frameOrientationAtIndex(index);
     
    232218}
    233219
    234 void ImageFrameCache::replaceFrameNativeImageAtIndex(NativeImagePtr&& nativeImage, size_t index, SubsamplingLevel subsamplingLevel, const std::optional<IntSize>& sizeForDrawing)
     220void ImageFrameCache::cacheFrameNativeImageAtIndex(NativeImagePtr&& nativeImage, size_t index, SubsamplingLevel subsamplingLevel, const DecodingOptions& decodingOptions)
    235221{
    236222    ASSERT(index < m_frames.size());
    237223    ImageFrame& frame = m_frames[index];
    238224
    239     if (!frame.hasValidNativeImage(subsamplingLevel, sizeForDrawing)) {
    240         // Clear the current image frame and update the observer with this clearance.
    241         unsigned decodedSize = frame.clear();
    242         decodedSizeDecreased(decodedSize);
    243     }
     225    // Clear the current image frame and update the observer with this clearance.
     226    decodedSizeDecreased(frame.clear());
    244227
    245228    // Do not cache the NativeImage if adding its frameByes to the MemoryCache will cause numerical overflow.
     
    248231        return;
    249232
    250     // Copy the new image to the cache.
    251     setFrameNativeImageAtIndex(WTFMove(nativeImage), index, subsamplingLevel, sizeForDrawing);
     233    // Move the new image to the cache.
     234    frame.m_nativeImage = WTFMove(nativeImage);
     235    frame.m_decodingOptions = decodingOptions;
     236    cacheFrameMetadataAtIndex(index, subsamplingLevel);
    252237
    253238    // Update the observer with the new image frame bytes.
     
    255240}
    256241
    257 void ImageFrameCache::cacheFrameNativeImageAtIndex(NativeImagePtr&& nativeImage, size_t index, SubsamplingLevel subsamplingLevel, const IntSize& sizeForDrawing)
     242void ImageFrameCache::cacheAsyncFrameNativeImageAtIndex(NativeImagePtr&& nativeImage, size_t index, SubsamplingLevel subsamplingLevel, const DecodingOptions& decodingOptions)
    258243{
    259244    if (!isDecoderAvailable())
     
    261246
    262247    ASSERT(index < m_frames.size());
    263     ASSERT(m_frames[index].isBeingDecoded(sizeForDrawing));
     248    ASSERT(!frameHasDecodedNativeImageCompatibleWithOptionsAtIndex(index, subsamplingLevel, decodingOptions));
    264249
    265250    // Clean the old native image and set a new one
    266     replaceFrameNativeImageAtIndex(WTFMove(nativeImage), index, subsamplingLevel, sizeForDrawing);
    267     m_frames[index].dequeueSizeForDecoding();
     251    cacheFrameNativeImageAtIndex(WTFMove(nativeImage), index, subsamplingLevel, decodingOptions);
    268252
    269253    // Notify the image with the readiness of the new frame NativeImage.
     
    299283
    300284            // Get the frame NativeImage on the decoding thread.
    301             NativeImagePtr nativeImage = protectedDecoder->createFrameImageAtIndex(frameRequest.index, frameRequest.subsamplingLevel, frameRequest.sizeForDrawing);
     285            NativeImagePtr nativeImage = protectedDecoder->createFrameImageAtIndex(frameRequest.index, frameRequest.subsamplingLevel, frameRequest.decodingOptions);
    302286
    303287            // Update the cached frames on the main thread to avoid updating the MemoryCache from a different thread.
    304288            callOnMainThread([this, protectedQueue = protectedQueue.copyRef(), nativeImage, frameRequest] () mutable {
    305289                // The queue may be closed if after we got the frame NativeImage, stopAsyncDecodingQueue() was called
    306                 if (protectedQueue.ptr() == m_decodingQueue)
    307                     cacheFrameNativeImageAtIndex(WTFMove(nativeImage), frameRequest.index, frameRequest.subsamplingLevel, frameRequest.sizeForDrawing);
     290                if (protectedQueue.ptr() == m_decodingQueue) {
     291                    ASSERT(m_frameCommitQueue.first() == frameRequest);
     292                    m_frameCommitQueue.removeFirst();
     293                    cacheAsyncFrameNativeImageAtIndex(WTFMove(nativeImage), frameRequest.index, frameRequest.subsamplingLevel, frameRequest.decodingOptions);
     294                }
    308295            });
    309296        }
     
    311298}
    312299
    313 bool ImageFrameCache::requestFrameAsyncDecodingAtIndex(size_t index, SubsamplingLevel subsamplingLevel, const IntSize& sizeForDrawing)
     300bool ImageFrameCache::requestFrameAsyncDecodingAtIndex(size_t index, SubsamplingLevel subsamplingLevel, const std::optional<IntSize>& sizeForDrawing)
    314301{
    315302    if (!isDecoderAvailable())
     
    317304
    318305    ASSERT(index < m_frames.size());
    319     ImageFrame& frame = m_frames[index];
    320306
    321307    // We need to coalesce multiple requests for decoding the same ImageFrame while it
    322308    // is still being decoded. This may happen if the image rectangle is repainted
    323309    // multiple times while the ImageFrame has not finished decoding.
    324     if (frame.isBeingDecoded(sizeForDrawing))
     310    if (frameIsBeingDecodedAndIsCompatibleWithOptionsAtIndex(index, sizeForDrawing))
    325311        return true;
    326312
    327     if (frame.hasValidNativeImage(subsamplingLevel, sizeForDrawing))
     313    if (frameHasDecodedNativeImageCompatibleWithOptionsAtIndex(index, subsamplingLevel, sizeForDrawing))
    328314        return false;
    329315
    330316    if (!hasAsyncDecodingQueue())
    331317        startAsyncDecodingQueue();
    332    
    333     frame.enqueueSizeForDecoding(sizeForDrawing);
     318
    334319    m_frameRequestQueue.enqueue({ index, subsamplingLevel, sizeForDrawing });
     320    m_frameCommitQueue.append({ index, subsamplingLevel, sizeForDrawing });
    335321    return true;
    336322}
     
    338324bool ImageFrameCache::isAsyncDecodingQueueIdle() const
    339325{
    340     for (const ImageFrame& frame : m_frames) {
    341         if (frame.isBeingDecoded())
    342             return false;
    343     }
    344     return true;
     326    return m_frameCommitQueue.isEmpty();
    345327}
    346328   
     
    350332        return;
    351333   
     334    std::for_each(m_frameCommitQueue.begin(), m_frameCommitQueue.end(), [this](const ImageFrameRequest& frameRequest) {
     335        ImageFrame& frame = m_frames[frameRequest.index];
     336        if (!frame.isEmpty())
     337            frame.clear();
     338    });
     339
    352340    m_frameRequestQueue.close();
     341    m_frameCommitQueue.clear();
    353342    m_decodingQueue = nullptr;
    354 
    355     for (ImageFrame& frame : m_frames) {
    356         if (frame.isBeingDecoded()) {
    357             frame.clearSizeForDecoding();
    358             frame.clear();
    359         }
    360     }
    361 }
    362 
    363 const ImageFrame& ImageFrameCache::frameAtIndexCacheIfNeeded(size_t index, ImageFrame::Caching caching, const std::optional<SubsamplingLevel>& subsamplingLevel, const std::optional<IntSize>& sizeForDrawing)
     343}
     344
     345const ImageFrame& ImageFrameCache::frameAtIndexCacheIfNeeded(size_t index, ImageFrame::Caching caching, const std::optional<SubsamplingLevel>& subsamplingLevel)
    364346{
    365347    ASSERT(index < m_frames.size());
    366348    ImageFrame& frame = m_frames[index];
    367     if (!isDecoderAvailable() || frame.isBeingDecoded(sizeForDrawing))
     349    if (!isDecoderAvailable() || frameIsBeingDecodedAndIsCompatibleWithOptionsAtIndex(index, DecodingMode::Asynchronous))
    368350        return frame;
    369351   
     
    375357        if (frame.isComplete())
    376358            break;
    377         setFrameMetadataAtIndex(index, subsamplingLevelValue, frame.sizeForDrawing());
     359        cacheFrameMetadataAtIndex(index, subsamplingLevelValue);
    378360        break;
    379361           
    380362    case ImageFrame::Caching::MetadataAndImage:
    381363        // Cache the image and retrieve the metadata from ImageDecoder only if there was not valid image stored.
    382         if (frame.hasValidNativeImage(subsamplingLevel, sizeForDrawing))
     364        if (frame.hasFullSizeNativeImage(subsamplingLevel))
    383365            break;
    384         // We have to perform synchronous image decoding in this code path regardless of the sizeForDrawing value.
    385         // So pass an empty sizeForDrawing to create an ImageFrame with the native size.
    386         replaceFrameNativeImageAtIndex(m_decoder->createFrameImageAtIndex(index, subsamplingLevelValue, { }), index, subsamplingLevelValue, { });
     366        // We have to perform synchronous image decoding in this code.
     367        NativeImagePtr nativeImage = m_decoder->createFrameImageAtIndex(index, subsamplingLevelValue);
     368        // Clean the old native image and set a new one.
     369        cacheFrameNativeImageAtIndex(WTFMove(nativeImage), index, subsamplingLevelValue, DecodingMode::Synchronous);
    387370        break;
    388371    }
     
    482465Color ImageFrameCache::singlePixelSolidColor()
    483466{
    484     return frameCount() == 1 ? frameMetadataAtIndexCacheIfNeeded<Color>(0, (&ImageFrame::singlePixelSolidColor), &m_singlePixelSolidColor, ImageFrame::Caching::MetadataAndImage) : Color();
    485 }
    486 
    487 bool ImageFrameCache::frameIsBeingDecodedAtIndex(size_t index, const std::optional<IntSize>& sizeForDrawing)
    488 {
    489     return frameMetadataAtIndex<bool>(index, (&ImageFrame::isBeingDecoded), sizeForDrawing);
     467    if (!m_singlePixelSolidColor && (size() != IntSize(1, 1) || frameCount() != 1))
     468        m_singlePixelSolidColor = Color();
     469
     470    if (m_singlePixelSolidColor)
     471        return m_singlePixelSolidColor.value();
     472
     473    return frameMetadataAtIndexCacheIfNeeded<Color>(0, (&ImageFrame::singlePixelSolidColor), &m_singlePixelSolidColor, ImageFrame::Caching::MetadataAndImage);
     474}
     475
     476bool ImageFrameCache::frameIsBeingDecodedAndIsCompatibleWithOptionsAtIndex(size_t index, const DecodingOptions& decodingOptions)
     477{
     478    auto it = std::find_if(m_frameCommitQueue.begin(), m_frameCommitQueue.end(), [index, &decodingOptions](const ImageFrameRequest& frameRequest) {
     479        return frameRequest.index == index && frameRequest.decodingOptions.isAsynchronousCompatibleWith(decodingOptions);
     480    });
     481    return it != m_frameCommitQueue.end();
    490482}
    491483
     
    500492}
    501493
    502 bool ImageFrameCache::frameHasImageAtIndex(size_t index)
    503 {
    504     return frameMetadataAtIndex<bool>(index, (&ImageFrame::hasNativeImage));
    505 }
    506 
    507 bool ImageFrameCache::frameHasValidNativeImageAtIndex(size_t index, const std::optional<SubsamplingLevel>& subsamplingLevel, const std::optional<IntSize>& sizeForDrawing)
    508 {
    509     return frameMetadataAtIndex<bool>(index, (&ImageFrame::hasValidNativeImage), subsamplingLevel, sizeForDrawing);
    510 }
    511    
    512 bool ImageFrameCache::frameHasDecodedNativeImage(size_t index)
    513 {
    514     return frameMetadataAtIndex<bool>(index, (&ImageFrame::hasDecodedNativeImage));
    515 }
    516 
     494bool ImageFrameCache::frameHasFullSizeNativeImageAtIndex(size_t index, const std::optional<SubsamplingLevel>& subsamplingLevel)
     495{
     496    return frameMetadataAtIndex<bool>(index, (&ImageFrame::hasFullSizeNativeImage), subsamplingLevel);
     497}
     498
     499bool ImageFrameCache::frameHasDecodedNativeImageCompatibleWithOptionsAtIndex(size_t index, const std::optional<SubsamplingLevel>& subsamplingLevel, const DecodingOptions& decodingOptions)
     500{
     501    return frameMetadataAtIndex<bool>(index, (&ImageFrame::hasDecodedNativeImageCompatibleWithOptions), subsamplingLevel, decodingOptions);
     502}
     503   
    517504SubsamplingLevel ImageFrameCache::frameSubsamplingLevelAtIndex(size_t index)
    518505{
     
    540527}
    541528
    542 NativeImagePtr ImageFrameCache::frameImageAtIndex(size_t index, const std::optional<SubsamplingLevel>& subsamplingLevel, const std::optional<IntSize>& sizeForDrawing)
    543 {
    544     return frameMetadataAtIndexCacheIfNeeded<NativeImagePtr>(index, (&ImageFrame::nativeImage), nullptr, ImageFrame::Caching::MetadataAndImage, subsamplingLevel, sizeForDrawing);
    545 }
    546 
    547 }
     529NativeImagePtr ImageFrameCache::frameImageAtIndex(size_t index)
     530{
     531    return frameMetadataAtIndex<NativeImagePtr>(index, (&ImageFrame::nativeImage));
     532}
     533
     534NativeImagePtr ImageFrameCache::frameImageAtIndexCacheIfNeeded(size_t index, SubsamplingLevel subsamplingLevel)
     535{
     536    return frameMetadataAtIndexCacheIfNeeded<NativeImagePtr>(index, (&ImageFrame::nativeImage), nullptr, ImageFrame::Caching::MetadataAndImage, subsamplingLevel);
     537}
     538
     539}
  • trunk/Source/WebCore/platform/graphics/ImageFrameCache.h

    r213833 r214450  
    7070    // Asynchronous image decoding
    7171    void startAsyncDecodingQueue();
    72     bool requestFrameAsyncDecodingAtIndex(size_t, SubsamplingLevel, const IntSize&);
     72    bool requestFrameAsyncDecodingAtIndex(size_t, SubsamplingLevel, const std::optional<IntSize>&);
    7373    void stopAsyncDecodingQueue();
    7474    bool hasAsyncDecodingQueue() const { return m_decodingQueue; }
     
    9090
    9191    // ImageFrame metadata which does not require caching the ImageFrame.
    92     bool frameIsBeingDecodedAtIndex(size_t, const std::optional<IntSize>& sizeForDrawing);
     92    bool frameIsBeingDecodedAndIsCompatibleWithOptionsAtIndex(size_t, const DecodingOptions&);
    9393    bool frameIsCompleteAtIndex(size_t);
    9494    bool frameHasAlphaAtIndex(size_t);
    9595    bool frameHasImageAtIndex(size_t);
    96     bool frameHasValidNativeImageAtIndex(size_t, const std::optional<SubsamplingLevel>&, const std::optional<IntSize>& sizeForDrawing);
    97     bool frameHasDecodedNativeImage(size_t);
     96    bool frameHasFullSizeNativeImageAtIndex(size_t, const std::optional<SubsamplingLevel>&);
     97    bool frameHasDecodedNativeImageCompatibleWithOptionsAtIndex(size_t, const std::optional<SubsamplingLevel>&, const DecodingOptions&);
    9898    SubsamplingLevel frameSubsamplingLevelAtIndex(size_t);
    9999   
     
    103103    float frameDurationAtIndex(size_t);
    104104    ImageOrientation frameOrientationAtIndex(size_t);
    105     NativeImagePtr frameImageAtIndex(size_t, const std::optional<SubsamplingLevel>&, const std::optional<IntSize>& sizeForDrawing);
     105
     106    NativeImagePtr frameImageAtIndex(size_t);
     107    NativeImagePtr frameImageAtIndexCacheIfNeeded(size_t, SubsamplingLevel);
    106108
    107109private:
     
    127129
    128130    void setNativeImage(NativeImagePtr&&);
    129     void setFrameNativeImageAtIndex(NativeImagePtr&&, size_t, SubsamplingLevel, const std::optional<IntSize>& sizeForDrawing);
    130     void setFrameMetadataAtIndex(size_t, SubsamplingLevel, const std::optional<IntSize>& sizeForDrawing);
    131     void replaceFrameNativeImageAtIndex(NativeImagePtr&&, size_t, SubsamplingLevel, const std::optional<IntSize>& sizeForDrawing);
    132     void cacheFrameNativeImageAtIndex(NativeImagePtr&&, size_t, SubsamplingLevel, const IntSize& sizeForDrawing);
     131    void cacheFrameMetadataAtIndex(size_t, SubsamplingLevel);
     132    void cacheFrameNativeImageAtIndex(NativeImagePtr&&, size_t, SubsamplingLevel, const DecodingOptions&);
     133    void cacheAsyncFrameNativeImageAtIndex(NativeImagePtr&&, size_t, SubsamplingLevel, const DecodingOptions&);
    133134
    134135    Ref<WorkQueue> decodingQueue();
    135136
    136     const ImageFrame& frameAtIndexCacheIfNeeded(size_t, ImageFrame::Caching, const std::optional<SubsamplingLevel>& = { }, const std::optional<IntSize>& sizeForDrawing = { });
     137    const ImageFrame& frameAtIndexCacheIfNeeded(size_t, ImageFrame::Caching, const std::optional<SubsamplingLevel>& = { });
    137138
    138139    Image* m_image { nullptr };
     
    147148        size_t index;
    148149        SubsamplingLevel subsamplingLevel;
    149         IntSize sizeForDrawing;
     150        DecodingOptions decodingOptions;
     151        bool operator==(const ImageFrameRequest& other) const
     152        {
     153            return index == other.index && subsamplingLevel == other.subsamplingLevel && decodingOptions == other.decodingOptions;
     154        }
    150155    };
    151156    static const int BufferSize = 8;
    152157    using FrameRequestQueue = SynchronizedFixedQueue<ImageFrameRequest, BufferSize>;
     158    using FrameCommitQueue = Deque<ImageFrameRequest, BufferSize>;
    153159    FrameRequestQueue m_frameRequestQueue;
     160    FrameCommitQueue m_frameCommitQueue;
    154161    RefPtr<WorkQueue> m_decodingQueue;
    155162
  • trunk/Source/WebCore/platform/graphics/ImageSource.cpp

    r213764 r214450  
    192192}
    193193
    194 NativeImagePtr ImageSource::frameImageAtIndex(size_t index, const std::optional<SubsamplingLevel>& subsamplingLevel, const std::optional<IntSize>& sizeForDrawing, const GraphicsContext* targetContext)
     194NativeImagePtr ImageSource::frameImageAtIndexCacheIfNeeded(size_t index, SubsamplingLevel subsamplingLevel, const GraphicsContext* targetContext)
    195195{
    196196    setDecoderTargetContext(targetContext);
    197     return m_frameCache->frameImageAtIndex(index, subsamplingLevel, sizeForDrawing);
     197    return m_frameCache->frameImageAtIndexCacheIfNeeded(index, subsamplingLevel);
    198198}
    199199
  • trunk/Source/WebCore/platform/graphics/ImageSource.h

    r213833 r214450  
    7070
    7171    bool shouldUseAsyncDecoding();
    72     bool requestFrameAsyncDecodingAtIndex(size_t index, SubsamplingLevel subsamplingLevel, const IntSize& sizeForDrawing) { return m_frameCache->requestFrameAsyncDecodingAtIndex(index, subsamplingLevel, sizeForDrawing); }
     72    bool requestFrameAsyncDecodingAtIndex(size_t index, SubsamplingLevel subsamplingLevel, const std::optional<IntSize>& sizeForDrawing = { }) { return m_frameCache->requestFrameAsyncDecodingAtIndex(index, subsamplingLevel, sizeForDrawing); }
    7373    bool hasAsyncDecodingQueue() const { return m_frameCache->hasAsyncDecodingQueue(); }
    7474    bool isAsyncDecodingQueueIdle() const  { return m_frameCache->isAsyncDecodingQueueIdle(); }
     
    8888
    8989    // ImageFrame metadata which does not require caching the ImageFrame.
    90     bool frameIsBeingDecodedAtIndex(size_t index, const std::optional<IntSize>& sizeForDrawing) { return m_frameCache->frameIsBeingDecodedAtIndex(index, sizeForDrawing); }
     90    bool frameIsBeingDecodedAndIsCompatibleWithOptionsAtIndex(size_t index, const DecodingOptions& decodingOptions) { return m_frameCache->frameIsBeingDecodedAndIsCompatibleWithOptionsAtIndex(index, decodingOptions); }
    9191    bool frameIsCompleteAtIndex(size_t index) { return m_frameCache->frameIsCompleteAtIndex(index); }
    9292    bool frameHasAlphaAtIndex(size_t index) { return m_frameCache->frameHasAlphaAtIndex(index); }
    9393    bool frameHasImageAtIndex(size_t index) { return m_frameCache->frameHasImageAtIndex(index); }
    94     bool frameHasValidNativeImageAtIndex(size_t index, const std::optional<SubsamplingLevel>& subsamplingLevel, const std::optional<IntSize>& sizeForDrawing) { return m_frameCache->frameHasValidNativeImageAtIndex(index, subsamplingLevel, sizeForDrawing); }
    95     bool frameHasDecodedNativeImage(size_t index) { return m_frameCache->frameHasDecodedNativeImage(index); }
     94    bool frameHasFullSizeNativeImageAtIndex(size_t index, const std::optional<SubsamplingLevel>& subsamplingLevel) { return m_frameCache->frameHasFullSizeNativeImageAtIndex(index, subsamplingLevel); }
     95    bool frameHasDecodedNativeImageCompatibleWithOptionsAtIndex(size_t index, const std::optional<SubsamplingLevel>& subsamplingLevel, const DecodingOptions& decodingOptions) { return m_frameCache->frameHasDecodedNativeImageCompatibleWithOptionsAtIndex(index, subsamplingLevel, decodingOptions); }
    9696    SubsamplingLevel frameSubsamplingLevelAtIndex(size_t index) { return m_frameCache->frameSubsamplingLevelAtIndex(index); }
    9797
     
    101101    float frameDurationAtIndex(size_t index) { return m_frameCache->frameDurationAtIndex(index); }
    102102    ImageOrientation frameOrientationAtIndex(size_t index) { return m_frameCache->frameOrientationAtIndex(index); }
    103     NativeImagePtr frameImageAtIndex(size_t index, const std::optional<SubsamplingLevel>& = { }, const std::optional<IntSize>& sizeForDrawing = { }, const GraphicsContext* targetContext = nullptr);
     103
     104    NativeImagePtr frameImageAtIndex(size_t index) { return m_frameCache->frameImageAtIndex(index); }
     105    NativeImagePtr frameImageAtIndexCacheIfNeeded(size_t, SubsamplingLevel = SubsamplingLevel::Default, const GraphicsContext* = nullptr);
    104106
    105107    SubsamplingLevel maximumSubsamplingLevel();
  • trunk/Source/WebCore/platform/graphics/NamedImageGeneratedImage.cpp

    r206631 r214450  
    4141}
    4242
    43 void NamedImageGeneratedImage::draw(GraphicsContext& context, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator compositeOp, BlendMode blendMode, ImageOrientationDescription)
     43void NamedImageGeneratedImage::draw(GraphicsContext& context, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator compositeOp, BlendMode blendMode, DecodingMode, ImageOrientationDescription)
    4444{
    4545#if USE(NEW_THEME) || PLATFORM(IOS)
  • trunk/Source/WebCore/platform/graphics/NamedImageGeneratedImage.h

    r206631 r214450  
    4141
    4242protected:
    43     void draw(GraphicsContext&, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator, BlendMode, ImageOrientationDescription) override;
     43    void draw(GraphicsContext&, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator, BlendMode, DecodingMode, ImageOrientationDescription) override;
    4444    void drawPattern(GraphicsContext&, const FloatRect& dstRect, const FloatRect& srcRect, const AffineTransform& patternTransform, const FloatPoint& phase, const FloatSize& spacing, CompositeOperator, BlendMode) override;
    4545
  • trunk/Source/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp

    r213491 r214450  
    284284    BackingStoreCopy copyMode = &destinationContext == &context() ? CopyBackingStore : DontCopyBackingStore;
    285285    RefPtr<Image> image = copyImage(copyMode);
    286     destinationContext.drawImage(*image, destRect, srcRect, ImagePaintingOptions(op, blendMode, ImageOrientationDescription()));
     286    destinationContext.drawImage(*image, destRect, srcRect, ImagePaintingOptions(op, blendMode, DecodingMode::Synchronous, ImageOrientationDescription()));
    287287}
    288288
  • trunk/Source/WebCore/platform/graphics/cg/ImageDecoderCG.cpp

    r213764 r214450  
    367367}
    368368
    369 NativeImagePtr ImageDecoder::createFrameImageAtIndex(size_t index, SubsamplingLevel subsamplingLevel, const std::optional<IntSize>& sizeForDrawing) const
     369NativeImagePtr ImageDecoder::createFrameImageAtIndex(size_t index, SubsamplingLevel subsamplingLevel, const DecodingOptions& decodingOptions) const
    370370{
    371371    LOG(Images, "ImageDecoder %p createFrameImageAtIndex %lu", this, index);
     
    373373    RetainPtr<CGImageRef> image;
    374374
    375     if (!sizeForDrawing) {
     375    if (!decodingOptions.isSynchronous()) {
     376        if (decodingOptions.hasSizeForDrawing()) {
     377            // CGImageSourceCreateThumbnailAtIndex() returns a CGImage with the image native size
     378            // regardless of the subsamplingLevel unless kCGImageSourceSubsampleFactor is passed.
     379            // Here we are trying to see which size is smaller: the image native size or the
     380            // sizeForDrawing. If we want a CGImage with the image native size, sizeForDrawing will
     381            // not passed. So we need to get the image native size with the default subsampling and
     382            // then compare it with sizeForDrawing.
     383            IntSize size = frameSizeAtIndex(index, SubsamplingLevel::Default);
     384            std::optional<IntSize> sizeForDrawing = decodingOptions.sizeForDrawing();
     385
     386            if (size.unclampedArea() < sizeForDrawing.value().unclampedArea()) {
     387                // Decode an image asynchronously for its native size.
     388                options = imageSourceAsyncOptions(subsamplingLevel);
     389            } else {
     390                // Decode an image asynchronously for sizeForDrawing since it is smaller than the image native size.
     391                options = imageSourceAsyncOptions(subsamplingLevel, sizeForDrawing);
     392            }
     393        } else
     394            options = imageSourceAsyncOptions(subsamplingLevel);
     395       
     396        image = adoptCF(CGImageSourceCreateThumbnailAtIndex(m_nativeDecoder.get(), index, options.get()));
     397    } else {
    376398        // Decode an image synchronously for its native size.
    377399        options = imageSourceOptions(subsamplingLevel);
    378400        image = adoptCF(CGImageSourceCreateImageAtIndex(m_nativeDecoder.get(), index, options.get()));
    379     } else {
    380         // CGImageSourceCreateThumbnailAtIndex() returns a CGImage with the image native size
    381         // regardless of the subsamplingLevel unless kCGImageSourceSubsampleFactor is passed.
    382         // Here we are trying to see which size is smaller: the image native size or the
    383         // sizeForDrawing. If we want a CGImage with the image native size, sizeForDrawing will
    384         // not passed. So we need to get the image native size with the default subsampling and
    385         // then compare it with sizeForDrawing.
    386         IntSize size = frameSizeAtIndex(index, SubsamplingLevel::Default);
    387 
    388         if (size.unclampedArea() < sizeForDrawing.value().unclampedArea()) {
    389             // Decode an image asynchronously for its native size.
    390             options = imageSourceAsyncOptions(subsamplingLevel);
    391         } else {
    392             // Decode an image asynchronously for sizeForDrawing since it is smaller than the image native size.
    393             options = imageSourceAsyncOptions(subsamplingLevel, sizeForDrawing);
    394         }
    395        
    396         image = adoptCF(CGImageSourceCreateThumbnailAtIndex(m_nativeDecoder.get(), index, options.get()));
    397401    }
    398402   
  • trunk/Source/WebCore/platform/graphics/cg/ImageDecoderCG.h

    r213833 r214450  
    6363    unsigned frameBytesAtIndex(size_t, SubsamplingLevel = SubsamplingLevel::Default) const;
    6464   
    65     NativeImagePtr createFrameImageAtIndex(size_t, SubsamplingLevel = SubsamplingLevel::Default, const std::optional<IntSize>& sizeForDrawing = { }) const;
     65    NativeImagePtr createFrameImageAtIndex(size_t, SubsamplingLevel = SubsamplingLevel::Default, const DecodingOptions& = DecodingMode::Synchronous) const;
    6666   
    6767    void setData(SharedBuffer&, bool allDataReceived);
  • trunk/Source/WebCore/platform/graphics/cg/PDFDocumentImage.cpp

    r209397 r214450  
    264264}
    265265
    266 void PDFDocumentImage::draw(GraphicsContext& context, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator op, BlendMode, ImageOrientationDescription)
     266void PDFDocumentImage::draw(GraphicsContext& context, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator op, BlendMode, DecodingMode, ImageOrientationDescription)
    267267{
    268268    if (!m_document || !m_hasPage)
  • trunk/Source/WebCore/platform/graphics/cg/PDFDocumentImage.h

    r206481 r214450  
    7373    FloatSize size() const override;
    7474
    75     void draw(GraphicsContext&, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator, BlendMode, ImageOrientationDescription) override;
     75    void draw(GraphicsContext&, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator, BlendMode, DecodingMode, ImageOrientationDescription) override;
    7676
    7777    // FIXME: Implement this to be less conservative.
  • trunk/Source/WebCore/platform/graphics/win/ImageCGWin.cpp

    r206742 r214450  
    8181        drawFrameMatchingSourceSize(gc, FloatRect(0.0f, 0.0f, bmpInfo.bmWidth, bmpInfo.bmHeight), *size, CompositeCopy);
    8282    else
    83         draw(gc, FloatRect(0.0f, 0.0f, bmpInfo.bmWidth, bmpInfo.bmHeight), FloatRect(0.0f, 0.0f, imageSize.width(), imageSize.height()), CompositeCopy, BlendModeNormal, ImageOrientationDescription());
     83        draw(gc, FloatRect(0.0f, 0.0f, bmpInfo.bmWidth, bmpInfo.bmHeight), FloatRect(0.0f, 0.0f, imageSize.width(), imageSize.height()), CompositeCopy, BlendModeNormal, DecodingMode::Synchronous, ImageOrientationDescription());
    8484
    8585    // Do cleanup
     
    9797            size_t currentFrame = m_currentFrame;
    9898            m_currentFrame = i;
    99             draw(ctxt, dstRect, FloatRect(0.0f, 0.0f, srcSize.width(), srcSize.height()), compositeOp, BlendModeNormal, ImageOrientationDescription());
     99            draw(ctxt, dstRect, FloatRect(0.0f, 0.0f, srcSize.width(), srcSize.height()), compositeOp, BlendModeNormal, DecodingMode::Synchronous, ImageOrientationDescription());
    100100            m_currentFrame = currentFrame;
    101101            return;
     
    105105    // No image of the correct size was found, fallback to drawing the current frame
    106106    FloatSize imageSize = BitmapImage::size();
    107     draw(ctxt, dstRect, FloatRect(0.0f, 0.0f, imageSize.width(), imageSize.height()), compositeOp, BlendModeNormal, ImageOrientationDescription());
     107    draw(ctxt, dstRect, FloatRect(0.0f, 0.0f, imageSize.width(), imageSize.height()), compositeOp, BlendModeNormal, DecodingMode::Synchronous, ImageOrientationDescription());
    108108}
    109109
  • trunk/Source/WebCore/platform/graphics/win/ImageDecoderDirect2D.cpp

    r213563 r214450  
    181181}
    182182
    183 NativeImagePtr ImageDecoder::createFrameImageAtIndex(size_t index, SubsamplingLevel subsamplingLevel, const std::optional<IntSize>&) const
     183NativeImagePtr ImageDecoder::createFrameImageAtIndex(size_t index, SubsamplingLevel subsamplingLevel, const DecodingOptions&) const
    184184{
    185185    if (!m_nativeDecoder || !m_renderTarget)
  • trunk/Source/WebCore/platform/graphics/win/ImageDecoderDirect2D.h

    r213833 r214450  
    6868    unsigned frameBytesAtIndex(size_t, SubsamplingLevel = SubsamplingLevel::Default) const;
    6969   
    70     NativeImagePtr createFrameImageAtIndex(size_t, SubsamplingLevel = SubsamplingLevel::Default, const std::optional<IntSize>& sizeForDraw = { }) const;
     70    NativeImagePtr createFrameImageAtIndex(size_t, SubsamplingLevel = SubsamplingLevel::Default, const DecodingOptions& = DecodingMode::Synchronous) const;
    7171   
    7272    void setData(SharedBuffer&, bool allDataReceived);
  • trunk/Source/WebCore/platform/image-decoders/ImageDecoder.cpp

    r213833 r214450  
    208208}
    209209
    210 NativeImagePtr ImageDecoder::createFrameImageAtIndex(size_t index, SubsamplingLevel, const std::optional<IntSize>&)
     210NativeImagePtr ImageDecoder::createFrameImageAtIndex(size_t index, SubsamplingLevel, const DecodingOptions&)
    211211{
    212212    // Zero-height images can cause problems for some ports. If we have an empty image dimension, just bail.
  • trunk/Source/WebCore/platform/image-decoders/ImageDecoder.h

    r213833 r214450  
    137137        float frameDurationAtIndex(size_t);
    138138       
    139         NativeImagePtr createFrameImageAtIndex(size_t, SubsamplingLevel = SubsamplingLevel::Default, const std::optional<IntSize>& sizeForDraw = { });
     139        NativeImagePtr createFrameImageAtIndex(size_t, SubsamplingLevel = SubsamplingLevel::Default, const DecodingOptions& = DecodingMode::Synchronous);
    140140
    141141        void setIgnoreGammaAndColorProfile(bool flag) { m_ignoreGammaAndColorProfile = flag; }
  • trunk/Source/WebCore/rendering/RenderBoxModelObject.cpp

    r214173 r214450  
    879879
    880880            auto interpolation = chooseInterpolationQuality(context, *image, &bgLayer, geometry.tileSize());
    881             context.drawTiledImage(*image, geometry.destRect(), toLayoutPoint(geometry.relativePhase()), geometry.tileSize(), geometry.spaceSize(), ImagePaintingOptions(compositeOp, bgLayer.blendMode(), ImageOrientationDescription(), interpolation));
     881            context.drawTiledImage(*image, geometry.destRect(), toLayoutPoint(geometry.relativePhase()), geometry.tileSize(), geometry.spaceSize(), ImagePaintingOptions(compositeOp, bgLayer.blendMode(), DecodingMode::Asynchronous, ImageOrientationDescription(), interpolation));
    882882        }
    883883    }
  • trunk/Source/WebCore/rendering/RenderImage.cpp

    r214173 r214450  
    582582
    583583    ImageOrientationDescription orientationDescription(shouldRespectImageOrientation(), style().imageOrientation());
    584     context.drawImage(*img, rect, ImagePaintingOptions(compositeOperator, BlendModeNormal, orientationDescription, interpolation));
     584    context.drawImage(*img, rect, ImagePaintingOptions(compositeOperator, BlendModeNormal, DecodingMode::Asynchronous, orientationDescription, interpolation));
    585585}
    586586
  • trunk/Source/WebCore/svg/graphics/SVGImage.cpp

    r213446 r214450  
    189189    scaledSrc.setSize(adjustedSrcSize);
    190190
    191     draw(context, dstRect, scaledSrc, compositeOp, blendMode, ImageOrientationDescription());
     191    draw(context, dstRect, scaledSrc, compositeOp, blendMode, DecodingMode::Synchronous, ImageOrientationDescription());
    192192
    193193    setImageObserver(observer);
     
    207207        return nullptr;
    208208
    209     draw(buffer->context(), rect(), rect(), CompositeSourceOver, BlendModeNormal, ImageOrientationDescription());
     209    draw(buffer->context(), rect(), rect(), CompositeSourceOver, BlendModeNormal, DecodingMode::Synchronous, ImageOrientationDescription());
    210210
    211211    // FIXME: WK(Bug 113657): We should use DontCopyBackingStore here.
     
    231231    GraphicsContext localContext(nativeImageTarget.get());
    232232
    233     draw(localContext, rect(), rect(), CompositeSourceOver, BlendModeNormal, ImageOrientationDescription());
     233    draw(localContext, rect(), rect(), CompositeSourceOver, BlendModeNormal, DecodingMode::Synchronous, ImageOrientationDescription());
    234234
    235235    COMPtr<ID2D1Bitmap> nativeImage;
     
    277277}
    278278
    279 void SVGImage::draw(GraphicsContext& context, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator compositeOp, BlendMode blendMode, ImageOrientationDescription)
     279void SVGImage::draw(GraphicsContext& context, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator compositeOp, BlendMode blendMode, DecodingMode, ImageOrientationDescription)
    280280{
    281281    if (!m_page)
  • trunk/Source/WebCore/svg/graphics/SVGImage.h

    r208668 r214450  
    9797
    9898    SVGImage(ImageObserver&, const URL&);
    99     void draw(GraphicsContext&, const FloatRect& fromRect, const FloatRect& toRect, CompositeOperator, BlendMode, ImageOrientationDescription) final;
     99    void draw(GraphicsContext&, const FloatRect& fromRect, const FloatRect& toRect, CompositeOperator, BlendMode, DecodingMode, ImageOrientationDescription) final;
    100100    void drawForContainer(GraphicsContext&, const FloatSize, float, const FloatRect&, const FloatRect&, CompositeOperator, BlendMode);
    101101    void drawPatternForContainer(GraphicsContext&, const FloatSize& containerSize, float zoom, const FloatRect& srcRect, const AffineTransform&, const FloatPoint& phase, const FloatSize& spacing,
  • trunk/Source/WebCore/svg/graphics/SVGImageForContainer.cpp

    r207357 r214450  
    3636
    3737void SVGImageForContainer::draw(GraphicsContext& context, const FloatRect& dstRect,
    38     const FloatRect& srcRect, CompositeOperator compositeOp, BlendMode blendMode, ImageOrientationDescription)
     38    const FloatRect& srcRect, CompositeOperator compositeOp, BlendMode blendMode, DecodingMode, ImageOrientationDescription)
    3939{
    4040    m_image->drawForContainer(context, m_containerSize, m_zoom, dstRect, srcRect, compositeOp, blendMode);
  • trunk/Source/WebCore/svg/graphics/SVGImageForContainer.h

    r208668 r214450  
    5656    }
    5757
    58     void draw(GraphicsContext&, const FloatRect&, const FloatRect&, CompositeOperator, BlendMode, ImageOrientationDescription) final;
     58    void draw(GraphicsContext&, const FloatRect&, const FloatRect&, CompositeOperator, BlendMode, DecodingMode, ImageOrientationDescription) final;
    5959
    6060    void drawPattern(GraphicsContext&, const FloatRect&, const FloatRect&, const AffineTransform&, const FloatPoint&, const FloatSize&, CompositeOperator, BlendMode) final;
Note: See TracChangeset for help on using the changeset viewer.