Changeset 213764 in webkit


Ignore:
Timestamp:
Mar 11, 2017, 7:00:46 PM (8 years ago)
Author:
commit-queue@webkit.org
Message:

Enable async image decoding for large images
https://bugs.webkit.org/show_bug.cgi?id=165039

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

Source/WebCore:

When BitmapImage::draw() is called for a large image, we are going to request async
image decoding for the native image instead of drawing it. If a lower resolution
native image is available for this, it is going to be drawn. Otherwise nothing will
be drawn. In both cases, a repaint will be scheduled for the image observer. This
should improve the image first time paint and the scrolling scenarios. It also makes
the scrolling more responsive by removing the decoding step from the main thread.

For now we are going to disable the asynchronous image decoding for the webkit test
runner because drawing the image does not block the page rendering anymore. An image
can be repainted later when its frame is ready for painting. This can cause a test
to fail because the webkit test runner may capture an image for the page before painting
all the images. The asynchronous image decoding can to be explicitly enabled from
the test page. Once the specs of the image 'async' attribute and 'ready' event is
approved, this should be revisited. It is important to test what we ship and eventually
async image decoding should be enabled in the webkit test runner.

  • loader/cache/CachedImage.h: Change the default of LargeImageAsyncDecoding and AnimatedImageAsyncDecoding

to be false. This change fixes a layout test which creates an CachedImage inside an ImageDocument. The
CachedImage in this case does not have a loader so getting the values of these options from the settings
which is false for the DRT/WTR did not happen.

  • platform/graphics/BitmapImage.cpp:

(WebCore::BitmapImage::destroyDecodedData): ImageSource::hasDecodingQueue() is renamed to ImageSource::hasAsyncDecodingQueue().
(WebCore::BitmapImage::frameImageAtIndex): Use String::utf8().data() instead of String::characters8().
(WebCore::BitmapImage::draw): If drawing the current frame is called while it is being
decoded, draw the current native image if the current frame was decoded but for a
different size and and will not invoke decoding while painting. If the frame is being
decoded and there isn't a decoded frame, return without drawing but set a flag that
that this image needs a repaint.
(WebCore::BitmapImage::shouldUseAsyncDecodingForLargeImage): Renaming a function.
(WebCore::BitmapImage::shouldUseAsyncDecodingForAnimatedImage): Ditto.
(WebCore::BitmapImage::internalStartAnimation): Use String::utf8().data() instead of String::characters8().
(WebCore::BitmapImage::advanceAnimation): Ditto.
(WebCore::BitmapImage::internalAdvanceAnimation): Ditto.
(WebCore::BitmapImage::newFrameNativeImageAvailableAtIndex): Now this callback can be
called form the ImageFrameCache when finishing a frame of an animated image or the
frame of a large image. For large images, we need to call CachedImage::changedInRect()
if this image needs a repaint. If the decoding queue is idle, we should close it.
(WebCore::BitmapImage::isLargeImageAsyncDecodingRequired): Deleted. Function was renamed.
(WebCore::BitmapImage::isAnimatedImageAsyncDecodingRequired): Deleted. Ditto.

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

(WebCore::ImageFrameCache::~ImageFrameCache): hasDecodingQueue() was renamed to hasAsyncDecodingQueue().
(WebCore::ImageFrameCache::decodingQueue): Change the QNS of the decoding thread to be WorkQueue::QOS::Default.
WorkQueue::QOS::UserInteractive causes the scrolling thread to preempted which can make the scrolling choppy.
(WebCore::ImageFrameCache::startAsyncDecodingQueue): hasDecodingQueue() was renamed to hasAsyncDecodingQueue().
(WebCore::ImageFrameCache::requestFrameAsyncDecodingAtIndex): Ditto.
(WebCore::ImageFrameCache::isAsyncDecodingQueueIdle): A helper function to tell whether the decoding thread is idle.
(WebCore::ImageFrameCache::stopAsyncDecodingQueue): hasDecodingQueue() was renamed to hasAsyncDecodingQueue().

  • platform/graphics/ImageFrameCache.h:

(WebCore::ImageFrameCache::hasAsyncDecodingQueue): Rename this function to be consistent with the rest of the functions.
(WebCore::ImageFrameCache::hasDecodingQueue): Deleted.

  • platform/graphics/ImageSource.cpp:

(WebCore::ImageSource::shouldUseAsyncDecoding): Renaming a function. Change the heuristic for large images be
a little bigger than the heuristic for animated images.
(WebCore::ImageSource::isAsyncDecodingRequired): Deleted.

  • platform/graphics/ImageSource.h:

(WebCore::ImageSource::hasAsyncDecodingQueue): hasDecodingQueue() was renamed to hasAsyncDecodingQueue().
(WebCore::ImageSource::isAsyncDecodingQueueIdle): A wrapper for ImageFrameCache::isAsyncDecodingQueueIdle().
(WebCore::ImageSource::hasDecodingQueue): Deleted.

  • platform/graphics/cg/ImageDecoderCG.cpp:

(WebCore::ImageDecoder::createFrameImageAtIndex): CGImageSourceCreateThumbnailAtIndex() returns a CGImage with
the image native size regardless of the subsamplingLevel unless kCGImageSourceSubsampleFactor is passed. Here
we are trying to see which size is smaller: the image native size or the sizeForDrawing. If we want a CGImage
with the image native size, sizeForDrawing will not passed. So we need to get the image native size with the
default subsampling and then compare it with sizeForDrawing.

Source/WebKit2:

Add WK2 preferences for setting/getting LargeImageAsyncDecoding and
AnimatedImageAsyncDecoding.

  • UIProcess/API/C/WKPreferences.cpp:

(WKPreferencesSetLargeImageAsyncDecodingEnabled):
(WKPreferencesGetLargeImageAsyncDecodingEnabled):
(WKPreferencesSetAnimatedImageAsyncDecodingEnabled):
(WKPreferencesGetAnimatedImageAsyncDecodingEnabled):

  • UIProcess/API/C/WKPreferencesRefPrivate.h:

Tools:

Disable LargeImageAsyncDecoding for DRT/WTR.

  • DumpRenderTree/mac/DumpRenderTree.mm:

(resetWebPreferencesToConsistentValues):

  • WebKitTestRunner/TestController.cpp:

(WTR::TestController::resetPreferencesToConsistentValues):

Location:
trunk
Files:
15 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r213762 r213764  
     12017-03-11  Said Abou-Hallawa  <sabouhallawa@apple.com>
     2
     3        Enable async image decoding for large images
     4        https://bugs.webkit.org/show_bug.cgi?id=165039
     5
     6        Reviewed by Simon Fraser.
     7
     8        When BitmapImage::draw() is called for a large image, we are going to request async
     9        image decoding for the native image instead of drawing it. If a lower resolution
     10        native image is available for this, it is going to be drawn. Otherwise nothing will
     11        be drawn. In both cases, a repaint will be scheduled for the image observer. This
     12        should improve the image first time paint and the scrolling scenarios. It also makes
     13        the scrolling more responsive by removing the decoding step from the main thread.
     14       
     15        For now we are going to disable the asynchronous image decoding for the webkit test
     16        runner because drawing the image does not block the page rendering anymore. An image
     17        can be repainted later when its frame is ready for painting. This can cause a test
     18        to fail because the webkit test runner may capture an image for the page before painting
     19        all the images. The asynchronous image decoding can to be explicitly enabled from
     20        the test page. Once the specs of the image 'async' attribute and 'ready' event is
     21        approved, this should be revisited. It is important to test what we ship and eventually
     22        async image decoding should be enabled in the webkit test runner.
     23
     24        * loader/cache/CachedImage.h: Change the default of LargeImageAsyncDecoding and AnimatedImageAsyncDecoding
     25        to be false. This change fixes a layout test which creates an CachedImage inside an ImageDocument. The
     26        CachedImage in this case does not have a loader so getting the values of these options from the settings
     27        which is false for the DRT/WTR did not happen.
     28        * platform/graphics/BitmapImage.cpp:
     29        (WebCore::BitmapImage::destroyDecodedData): ImageSource::hasDecodingQueue() is renamed to ImageSource::hasAsyncDecodingQueue().
     30        (WebCore::BitmapImage::frameImageAtIndex): Use String::utf8().data() instead of String::characters8().
     31        (WebCore::BitmapImage::draw): If drawing the current frame is called while it is being
     32        decoded, draw the current native image if the current frame was decoded but for a
     33        different size  and and will not invoke decoding while painting. If the frame is being
     34        decoded and there isn't a decoded frame, return without drawing but set a flag that
     35        that this image needs a repaint.
     36        (WebCore::BitmapImage::shouldUseAsyncDecodingForLargeImage): Renaming a function.
     37        (WebCore::BitmapImage::shouldUseAsyncDecodingForAnimatedImage): Ditto.
     38        (WebCore::BitmapImage::internalStartAnimation): Use String::utf8().data() instead of String::characters8().
     39        (WebCore::BitmapImage::advanceAnimation): Ditto.
     40        (WebCore::BitmapImage::internalAdvanceAnimation): Ditto.
     41        (WebCore::BitmapImage::newFrameNativeImageAvailableAtIndex): Now this callback can be
     42        called form the ImageFrameCache when finishing a frame of an animated image or the
     43        frame of a large image. For large images, we need to call CachedImage::changedInRect()
     44        if this image needs a repaint. If the decoding queue is idle, we should close it.
     45        (WebCore::BitmapImage::isLargeImageAsyncDecodingRequired): Deleted. Function was renamed.
     46        (WebCore::BitmapImage::isAnimatedImageAsyncDecodingRequired): Deleted. Ditto.
     47        * platform/graphics/BitmapImage.h:
     48
     49        * platform/graphics/ImageFrameCache.cpp:
     50        (WebCore::ImageFrameCache::~ImageFrameCache): hasDecodingQueue() was renamed to hasAsyncDecodingQueue().
     51        (WebCore::ImageFrameCache::decodingQueue): Change the QNS of the decoding thread to be WorkQueue::QOS::Default.
     52        WorkQueue::QOS::UserInteractive causes the scrolling thread to preempted  which can make the scrolling choppy.
     53        (WebCore::ImageFrameCache::startAsyncDecodingQueue): hasDecodingQueue() was renamed to hasAsyncDecodingQueue().
     54        (WebCore::ImageFrameCache::requestFrameAsyncDecodingAtIndex): Ditto.
     55        (WebCore::ImageFrameCache::isAsyncDecodingQueueIdle): A helper function to tell whether the decoding thread is idle.
     56        (WebCore::ImageFrameCache::stopAsyncDecodingQueue): hasDecodingQueue() was renamed to hasAsyncDecodingQueue().
     57        * platform/graphics/ImageFrameCache.h:
     58        (WebCore::ImageFrameCache::hasAsyncDecodingQueue): Rename this function to be consistent with the rest of the functions.
     59        (WebCore::ImageFrameCache::hasDecodingQueue): Deleted.
     60
     61        * platform/graphics/ImageSource.cpp:
     62        (WebCore::ImageSource::shouldUseAsyncDecoding): Renaming a function. Change the heuristic for large images be
     63        a little bigger than the heuristic for animated images.
     64        (WebCore::ImageSource::isAsyncDecodingRequired): Deleted.
     65        * platform/graphics/ImageSource.h:
     66        (WebCore::ImageSource::hasAsyncDecodingQueue): hasDecodingQueue() was renamed to hasAsyncDecodingQueue().
     67        (WebCore::ImageSource::isAsyncDecodingQueueIdle): A wrapper for ImageFrameCache::isAsyncDecodingQueueIdle().
     68        (WebCore::ImageSource::hasDecodingQueue): Deleted.
     69       
     70        * platform/graphics/cg/ImageDecoderCG.cpp:
     71        (WebCore::ImageDecoder::createFrameImageAtIndex): CGImageSourceCreateThumbnailAtIndex() returns a CGImage with
     72        the image native size regardless of the subsamplingLevel unless kCGImageSourceSubsampleFactor is passed. Here
     73        we are trying to see which size is smaller: the image native size or the sizeForDrawing. If we want a CGImage
     74        with the image native size, sizeForDrawing will not passed. So we need to get the image native size with the
     75        default subsampling and then compare it with sizeForDrawing.
     76
    1772017-03-11  Jon Lee  <jonlee@apple.com>
    278
  • trunk/Source/WebCore/loader/cache/CachedImage.h

    r213563 r213764  
    145145        bool m_allowSubsampling { false };
    146146#endif
    147         bool m_allowLargeImageAsyncDecoding { true };
    148         bool m_allowAnimatedImageAsyncDecoding { true };
     147        bool m_allowLargeImageAsyncDecoding { false };
     148        bool m_allowAnimatedImageAsyncDecoding { false };
    149149        bool m_showDebugBackground { false };
    150150    };
  • trunk/Source/WebCore/platform/graphics/BitmapImage.cpp

    r213715 r213764  
    6868    if (!destroyAll)
    6969        m_source.destroyDecodedDataBeforeFrame(m_currentFrame);
    70     else if (m_source.hasDecodingQueue())
     70    else if (m_source.hasAsyncDecodingQueue())
    7171        m_source.destroyAllDecodedDataExcludeFrame(m_currentFrame);
    7272    else
     
    7575    // There's no need to throw away the decoder unless we're explicitly asked
    7676    // to destroy all of the frames.
    77     if (!destroyAll || m_source.hasDecodingQueue())
     77    if (!destroyAll || m_source.hasAsyncDecodingQueue())
    7878        m_source.clearFrameBufferCache(m_currentFrame);
    7979    else
     
    104104{
    105105    if (!frameHasValidNativeImageAtIndex(index, subsamplingLevel, sizeForDrawing)) {
    106         LOG(Images, "BitmapImage::%s - %p - url: %s [subsamplingLevel was %d, resampling]", __FUNCTION__, this, sourceURL().characters8(), static_cast<int>(frameSubsamplingLevelAtIndex(index)));
     106        LOG(Images, "BitmapImage::%s - %p - url: %s [subsamplingLevel was %d, resampling]", __FUNCTION__, this, sourceURL().utf8().data(), static_cast<int>(frameSubsamplingLevelAtIndex(index)));
    107107        invalidatePlatformData();
    108108    }
     
    162162        return;
    163163
    164     m_sizeForDrawing = enclosingIntRect(destRect).size();
     164    float scale = subsamplingScale(context, destRect, srcRect);
     165    m_currentSubsamplingLevel = allowSubsampling() ? m_source.subsamplingLevelForScale(scale) : SubsamplingLevel::Default;
     166    m_sizeForDrawing = enclosingIntRect(context.getCTM().mapRect(destRect)).size();
     167
     168    LOG(Images, "BitmapImage::%s - %p - url: %s [subsamplingLevel = %d scale = %.4f]", __FUNCTION__, this, sourceURL().utf8().data(), static_cast<int>(m_currentSubsamplingLevel), scale);
     169
    165170    StartAnimationResult result = internalStartAnimation();
    166 
    167     Color color;
    168     if (result == StartAnimationResult::DecodingActive && showDebugBackground())
    169         color = Color::yellow;
    170     else
    171         color = singlePixelSolidColor();
    172 
     171    if (result == StartAnimationResult::DecodingActive && showDebugBackground()) {
     172        fillWithSolidColor(context, destRect, Color::yellow, op);
     173        return;
     174    }
     175
     176    ASSERT_IMPLIES(result == StartAnimationResult::DecodingActive, m_source.frameHasValidNativeImageAtIndex(m_currentFrame, m_currentSubsamplingLevel, m_sizeForDrawing));
     177
     178    NativeImagePtr image;
     179    if (shouldUseAsyncDecodingForLargeImage()) {
     180        if (m_source.frameHasValidNativeImageAtIndex(m_currentFrame, m_currentSubsamplingLevel, m_sizeForDrawing))
     181            image = frameImageAtIndex(m_currentFrame, m_currentSubsamplingLevel, m_sizeForDrawing, &context);
     182        else {
     183            ASSERT(!canAnimate() && !m_currentFrame);
     184            if (!frameIsBeingDecodedAtIndex(m_currentFrame, m_sizeForDrawing)) {
     185                m_source.requestFrameAsyncDecodingAtIndex(0, m_currentSubsamplingLevel, m_sizeForDrawing);
     186                LOG(Images, "BitmapImage::%s - %p - url: %s [requesting large async decoding]", __FUNCTION__, this, sourceURL().utf8().data());
     187            }
     188
     189            if (!frameHasDecodedNativeImage(m_currentFrame)) {
     190                if (showDebugBackground())
     191                    fillWithSolidColor(context, destRect, Color::yellow, op);
     192                return;
     193            }
     194
     195            image = frameImageAtIndex(m_currentFrame);
     196        }
     197    } else {
     198        ASSERT(!frameIsBeingDecodedAtIndex(m_currentFrame, m_sizeForDrawing));
     199        image = frameImageAtIndex(m_currentFrame, m_currentSubsamplingLevel, { }, &context);
     200    }
     201
     202    if (!image) // If it's too early we won't have an image yet.
     203        return;
     204
     205    Color color = singlePixelSolidColor();
    173206    if (color.isValid()) {
    174207        fillWithSolidColor(context, destRect, color, op);
    175208        return;
    176209    }
    177 
    178     float scale = subsamplingScale(context, destRect, srcRect);
    179     m_currentSubsamplingLevel = allowSubsampling() ? m_source.subsamplingLevelForScale(scale) : SubsamplingLevel::Default;
    180     LOG(Images, "BitmapImage::%s - %p - url: %s [m_currentFrame = %ld subsamplingLevel = %d scale = %.4f]", __FUNCTION__, this, sourceURL().characters8(), m_currentFrame, static_cast<int>(m_currentSubsamplingLevel), scale);
    181 
    182     ASSERT_IMPLIES(result == StartAnimationResult::DecodingActive, m_source.frameHasValidNativeImageAtIndex(m_currentFrame, m_currentSubsamplingLevel, m_sizeForDrawing));
    183     auto image = frameImageAtIndex(m_currentFrame, m_currentSubsamplingLevel, m_sizeForDrawing, &context);
    184     if (!image) // If it's too early we won't have an image yet.
    185         return;
    186210
    187211    ImageOrientation orientation(description.imageOrientation());
     
    239263}
    240264
    241 bool BitmapImage::isLargeImageAsyncDecodingRequired()
    242 {
    243     return !canAnimate() && allowLargeImageAsyncDecoding() && (isAsyncDecodingForcedForTesting() || m_source.isAsyncDecodingRequired());
    244 }
    245 
    246 bool BitmapImage::isAnimatedImageAsyncDecodingRequired()
    247 {
    248     return canAnimate() && allowAnimatedImageAsyncDecoding() && (isAsyncDecodingForcedForTesting() || m_source.isAsyncDecodingRequired());
     265bool BitmapImage::shouldUseAsyncDecodingForLargeImage()
     266{
     267    return !canAnimate() && allowLargeImageAsyncDecoding() && (shouldUseAsyncDecodingForTesting() || m_source.shouldUseAsyncDecoding());
     268}
     269
     270bool BitmapImage::shouldUseAsyncDecodingForAnimatedImage()
     271{
     272    return canAnimate() && allowAnimatedImageAsyncDecoding() && (shouldUseAsyncDecodingForTesting() || m_source.shouldUseAsyncDecoding());
    249273}
    250274
     
    268292    if (m_frameTimer)
    269293        return StartAnimationResult::TimerActive;
    270    
     294
    271295    // Don't start a new animation until we draw the frame that is currently being decoded.
    272296    size_t nextFrame = (m_currentFrame + 1) % frameCount();
    273297    if (frameIsBeingDecodedAtIndex(nextFrame, m_sizeForDrawing)) {
    274         LOG(Images, "BitmapImage::%s - %p - url: %s [nextFrame = %ld is being decoded]", __FUNCTION__, this, sourceURL().characters8(), nextFrame);
     298        LOG(Images, "BitmapImage::%s - %p - url: %s [nextFrame = %ld is being decoded]", __FUNCTION__, this, sourceURL().utf8().data(), nextFrame);
    275299        return StartAnimationResult::DecodingActive;
    276300    }
     
    313337    // through the callback newFrameNativeImageAvailableAtIndex(). Otherwise, advanceAnimation() will be called
    314338    // when the timer fires and m_currentFrame will be advanced to nextFrame since it is not being decoded.
    315     if (m_sizeForDrawing && isAnimatedImageAsyncDecodingRequired()) {
    316         bool isAsyncDecode = m_source.requestFrameAsyncDecodingAtIndex(nextFrame, m_currentSubsamplingLevel, *m_sizeForDrawing);
     339    if (shouldUseAsyncDecodingForAnimatedImage()) {
     340        bool isAsyncDecode = m_source.requestFrameAsyncDecodingAtIndex(nextFrame, m_currentSubsamplingLevel, m_sizeForDrawing);
    317341
    318342#if !LOG_DISABLED
    319343        if (isAsyncDecode)
    320             LOG(Images, "BitmapImage::%s - %p - url: %s [requesting async decoding for nextFrame = %ld]", __FUNCTION__, this, sourceURL().characters8(), nextFrame);
     344            LOG(Images, "BitmapImage::%s - %p - url: %s [requesting async decoding for nextFrame = %ld]", __FUNCTION__, this, sourceURL().utf8().data(), nextFrame);
    321345        else
    322             LOG(Images, "BitmapImage::%s - %p - url: %s [cachedFrameCount = %ld nextFrame = %ld]", __FUNCTION__, this, sourceURL().characters8(), ++m_cachedFrameCount, nextFrame);
     346            LOG(Images, "BitmapImage::%s - %p - url: %s [cachedFrameCount = %ld nextFrame = %ld]", __FUNCTION__, this, sourceURL().utf8().data(), ++m_cachedFrameCount, nextFrame);
    323347#else
    324348        UNUSED_PARAM(isAsyncDecode);
     
    339363    // Pretend as if decoding nextFrame has taken m_frameDecodingDurationForTesting from
    340364    // the time this decoding was requested.
    341     if (isAsyncDecodingForcedForTesting()) {
     365    if (shouldUseAsyncDecodingForTesting()) {
    342366        double time = monotonicallyIncreasingTime();
    343367        // Start a timer with the remaining time from now till the m_desiredFrameDecodeTime.
     
    347371        }
    348372    }
    349    
     373
    350374    // Don't advance to nextFrame unless its decoding has finished or was not required.
    351375    size_t nextFrame = (m_currentFrame + 1) % frameCount();
     
    356380        if (showDebugBackground())
    357381            imageObserver()->changedInRect(this);
    358         LOG(Images, "BitmapImage::%s - %p - url: %s [lateFrameCount = %ld nextFrame = %ld]", __FUNCTION__, this, sourceURL().characters8(), ++m_lateFrameCount, nextFrame);
     382        LOG(Images, "BitmapImage::%s - %p - url: %s [lateFrameCount = %ld nextFrame = %ld]", __FUNCTION__, this, sourceURL().utf8().data(), ++m_lateFrameCount, nextFrame);
    359383    }
    360384}
     
    370394        imageObserver()->animationAdvanced(this);
    371395
    372     LOG(Images, "BitmapImage::%s - %p - url: %s [m_currentFrame = %ld]", __FUNCTION__, this, sourceURL().characters8(), m_currentFrame);
     396    LOG(Images, "BitmapImage::%s - %p - url: %s [m_currentFrame = %ld]", __FUNCTION__, this, sourceURL().utf8().data(), m_currentFrame);
    373397}
    374398
     
    396420{
    397421    UNUSED_PARAM(index);
    398     ASSERT(index == (m_currentFrame + 1) % frameCount());
    399 
    400     // Don't advance to nextFrame unless the timer was fired before its decoding finishes.
    401     if (canAnimate() && !m_frameTimer)
    402         internalAdvanceAnimation();
    403     else
    404         LOG(Images, "BitmapImage::%s - %p - url: %s [earlyFrameCount = %ld nextFrame = %ld]", __FUNCTION__, this, sourceURL().characters8(), ++m_earlyFrameCount, index);
     422    if (canAnimate()) {
     423        ASSERT(index == (m_currentFrame + 1) % frameCount());
     424       
     425        // Don't advance to nextFrame unless the timer was fired before its decoding finishes.
     426        if (canAnimate() && !m_frameTimer)
     427            internalAdvanceAnimation();
     428        else
     429            LOG(Images, "BitmapImage::%s - %p - url: %s [earlyFrameCount = %ld nextFrame = %ld]", __FUNCTION__, this, sourceURL().utf8().data(), ++m_earlyFrameCount, index);
     430    } else {
     431        ASSERT(index == m_currentFrame && !m_currentFrame);
     432        imageObserver()->changedInRect(this, nullptr);
     433       
     434        if (m_source.isAsyncDecodingQueueIdle())
     435            m_source.stopAsyncDecodingQueue();
     436    }
    405437}
    406438
  • trunk/Source/WebCore/platform/graphics/BitmapImage.h

    r213715 r213764  
    9797    ImageOrientation orientationForCurrentFrame() const override { return frameOrientationAtIndex(currentFrame()); }
    9898
    99     bool isAsyncDecodingForcedForTesting() const { return m_frameDecodingDurationForTesting > 0; }
     99    bool shouldUseAsyncDecodingForTesting() const { return m_frameDecodingDurationForTesting > 0; }
    100100    void setFrameDecodingDurationForTesting(float duration) { m_frameDecodingDurationForTesting = duration; }
    101     bool isLargeImageAsyncDecodingRequired();
    102     bool isAnimatedImageAsyncDecodingRequired();
     101    bool shouldUseAsyncDecodingForLargeImage();
     102    bool shouldUseAsyncDecodingForAnimatedImage();
    103103
    104104    // Accessors for native image formats.
     
    203203    size_t m_currentFrame { 0 }; // The index of the current frame of animation.
    204204    SubsamplingLevel m_currentSubsamplingLevel { SubsamplingLevel::Default };
    205     std::optional<IntSize> m_sizeForDrawing;
     205    IntSize m_sizeForDrawing;
    206206    std::unique_ptr<Timer> m_frameTimer;
    207207    RepetitionCount m_repetitionsComplete { RepetitionCountNone }; // How many repetitions we've finished.
  • trunk/Source/WebCore/platform/graphics/ImageFrameCache.cpp

    r213715 r213764  
    6868ImageFrameCache::~ImageFrameCache()
    6969{
    70     ASSERT(!hasDecodingQueue());
     70    ASSERT(!hasAsyncDecodingQueue());
    7171}
    7272
     
    257257{
    258258    if (!m_decodingQueue)
    259         m_decodingQueue = WorkQueue::create("org.webkit.ImageDecoder", WorkQueue::Type::Serial, WorkQueue::QOS::UserInteractive);
     259        m_decodingQueue = WorkQueue::create("org.webkit.ImageDecoder", WorkQueue::Type::Serial, WorkQueue::QOS::Default);
    260260   
    261261    return *m_decodingQueue;
     
    264264void ImageFrameCache::startAsyncDecodingQueue()
    265265{
    266     if (hasDecodingQueue() || !isDecoderAvailable())
     266    if (hasAsyncDecodingQueue() || !isDecoderAvailable())
    267267        return;
    268268
     
    307307        return false;
    308308
    309     if (!hasDecodingQueue())
     309    if (!hasAsyncDecodingQueue())
    310310        startAsyncDecodingQueue();
    311311   
     
    315315}
    316316
     317bool ImageFrameCache::isAsyncDecodingQueueIdle() const
     318{
     319    for (const ImageFrame& frame : m_frames) {
     320        if (frame.isBeingDecoded())
     321            return false;
     322    }
     323    return true;
     324}
     325   
    317326void ImageFrameCache::stopAsyncDecodingQueue()
    318327{
    319     if (!hasDecodingQueue())
     328    if (!hasAsyncDecodingQueue())
    320329        return;
    321330   
  • trunk/Source/WebCore/platform/graphics/ImageFrameCache.h

    r213715 r213764  
    7272    bool requestFrameAsyncDecodingAtIndex(size_t, SubsamplingLevel, const IntSize&);
    7373    void stopAsyncDecodingQueue();
    74     bool hasDecodingQueue() { return m_decodingQueue; }
     74    bool hasAsyncDecodingQueue() const { return m_decodingQueue; }
     75    bool isAsyncDecodingQueueIdle() const;
    7576
    7677    // Image metadata which is calculated either by the ImageDecoder or directly
  • trunk/Source/WebCore/platform/graphics/ImageSource.cpp

    r213563 r213764  
    149149}
    150150
    151 bool ImageSource::isAsyncDecodingRequired()
     151bool ImageSource::shouldUseAsyncDecoding()
    152152{
    153153    // FIXME: figure out the best heuristic for enabling async image decoding.
    154     return size().area() * sizeof(RGBA32) >= 100 * KB;
     154    return size().area() * sizeof(RGBA32) >= (frameCount() > 1 ? 100 * KB : 500 * KB);
    155155}
    156156
  • trunk/Source/WebCore/platform/graphics/ImageSource.h

    r213715 r213764  
    6969    bool isAllDataReceived();
    7070
    71     bool isAsyncDecodingRequired();
     71    bool shouldUseAsyncDecoding();
    7272    bool requestFrameAsyncDecodingAtIndex(size_t index, SubsamplingLevel subsamplingLevel, const IntSize& sizeForDrawing) { return m_frameCache->requestFrameAsyncDecodingAtIndex(index, subsamplingLevel, sizeForDrawing); }
    73     bool hasDecodingQueue() const { return m_frameCache->hasDecodingQueue(); }
     73    bool hasAsyncDecodingQueue() const { return m_frameCache->hasAsyncDecodingQueue(); }
     74    bool isAsyncDecodingQueueIdle() const  { return m_frameCache->isAsyncDecodingQueueIdle(); }
    7475    void stopAsyncDecodingQueue() { m_frameCache->stopAsyncDecodingQueue(); }
    7576
  • trunk/Source/WebCore/platform/graphics/cg/ImageDecoderCG.cpp

    r213563 r213764  
    378378        image = adoptCF(CGImageSourceCreateImageAtIndex(m_nativeDecoder.get(), index, options.get()));
    379379    } else {
    380         IntSize size = frameSizeAtIndex(index, subsamplingLevel);
     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);
    381387
    382388        if (size.unclampedArea() < sizeForDrawing.value().unclampedArea()) {
  • trunk/Source/WebKit2/ChangeLog

    r213760 r213764  
     12017-03-11  Said Abou-Hallawa  <sabouhallawa@apple.com>
     2
     3        Enable async image decoding for large images
     4        https://bugs.webkit.org/show_bug.cgi?id=165039
     5
     6        Reviewed by Simon Fraser.
     7
     8        Add WK2 preferences for setting/getting LargeImageAsyncDecoding and
     9        AnimatedImageAsyncDecoding.
     10       
     11        * UIProcess/API/C/WKPreferences.cpp:
     12        (WKPreferencesSetLargeImageAsyncDecodingEnabled):
     13        (WKPreferencesGetLargeImageAsyncDecodingEnabled):
     14        (WKPreferencesSetAnimatedImageAsyncDecodingEnabled):
     15        (WKPreferencesGetAnimatedImageAsyncDecodingEnabled):
     16        * UIProcess/API/C/WKPreferencesRefPrivate.h:
     17
    1182017-03-11  Alex Christensen  <achristensen@webkit.org>
    219
  • trunk/Source/WebKit2/UIProcess/API/C/WKPreferences.cpp

    r213715 r213764  
    16921692}
    16931693
     1694void WKPreferencesSetLargeImageAsyncDecodingEnabled(WKPreferencesRef preferencesRef, bool flag)
     1695{
     1696    toImpl(preferencesRef)->setLargeImageAsyncDecodingEnabled(flag);
     1697}
     1698
     1699bool WKPreferencesGetLargeImageAsyncDecodingEnabled(WKPreferencesRef preferencesRef)
     1700{
     1701    return toImpl(preferencesRef)->largeImageAsyncDecodingEnabled();
     1702}
     1703
     1704void WKPreferencesSetAnimatedImageAsyncDecodingEnabled(WKPreferencesRef preferencesRef, bool flag)
     1705{
     1706    toImpl(preferencesRef)->setAnimatedImageAsyncDecodingEnabled(flag);
     1707}
     1708
     1709bool WKPreferencesGetAnimatedImageAsyncDecodingEnabled(WKPreferencesRef preferencesRef)
     1710{
     1711    return toImpl(preferencesRef)->animatedImageAsyncDecodingEnabled();
     1712}
     1713
    16941714void WKPreferencesSetShouldSuppressKeyboardInputDuringProvisionalNavigation(WKPreferencesRef preferencesRef, bool flag)
    16951715{
  • trunk/Source/WebKit2/UIProcess/API/C/WKPreferencesRefPrivate.h

    r213715 r213764  
    466466WK_EXPORT bool WKPreferencesGetSubtleCryptoEnabled(WKPreferencesRef);
    467467
     468// Defaults to true.
     469WK_EXPORT void WKPreferencesSetLargeImageAsyncDecodingEnabled(WKPreferencesRef preferencesRef, bool flag);
     470WK_EXPORT bool WKPreferencesGetLargeImageAsyncDecodingEnabled(WKPreferencesRef preferencesRef);
     471
     472// Defaults to true.
     473WK_EXPORT void WKPreferencesSetAnimatedImageAsyncDecodingEnabled(WKPreferencesRef preferencesRef, bool flag);
     474WK_EXPORT bool WKPreferencesGetAnimatedImageAsyncDecodingEnabled(WKPreferencesRef preferencesRef);
     475
    468476// Defaults to false
    469477WK_EXPORT void WKPreferencesSetShouldSuppressKeyboardInputDuringProvisionalNavigation(WKPreferencesRef, bool flag);
  • trunk/Tools/ChangeLog

    r213752 r213764  
     12017-03-11  Said Abou-Hallawa  <sabouhallawa@apple.com>
     2
     3        Enable async image decoding for large images
     4        https://bugs.webkit.org/show_bug.cgi?id=165039
     5
     6        Reviewed by Simon Fraser.
     7
     8        Disable LargeImageAsyncDecoding for DRT/WTR.
     9
     10        * DumpRenderTree/mac/DumpRenderTree.mm:
     11        (resetWebPreferencesToConsistentValues):
     12        * WebKitTestRunner/TestController.cpp:
     13        (WTR::TestController::resetPreferencesToConsistentValues):
     14
    1152017-03-10  Alex Christensen  <achristensen@webkit.org>
    216
  • trunk/Tools/DumpRenderTree/mac/DumpRenderTree.mm

    r213715 r213764  
    957957   
    958958    [preferences setMediaStreamEnabled:YES];
     959   
     960    [preferences setLargeImageAsyncDecodingEnabled:NO];
    959961
    960962    [WebPreferences _clearNetworkLoaderSession];
  • trunk/Tools/WebKitTestRunner/TestController.cpp

    r213715 r213764  
    720720
    721721    WKPreferencesSetMockCaptureDevicesEnabled(preferences, true);
     722   
     723    WKPreferencesSetLargeImageAsyncDecodingEnabled(preferences, false);
    722724
    723725    platformResetPreferencesToConsistentValues();
Note: See TracChangeset for help on using the changeset viewer.