Diff
Modified: trunk/Source/WebCore/ChangeLog (208364 => 208365)
--- trunk/Source/WebCore/ChangeLog 2016-11-04 02:37:45 UTC (rev 208364)
+++ trunk/Source/WebCore/ChangeLog 2016-11-04 02:57:49 UTC (rev 208365)
@@ -1,3 +1,87 @@
+2016-11-03 Said Abou-Hallawa <[email protected]>
+
+ Add the asynchronous image decoding mode
+ https://bugs.webkit.org/show_bug.cgi?id=155546
+
+ Reviewed by Simon Fraser.
+
+ The asynchronous image decoding feature targets enhancing the rendering
+ in two scenarios: the animated images and scrolling a page which large
+ images. Enabling this feature for these two scenarios will be landed
+ separately.
+
+ The goal of the asynchronous image decoding is to have the decoded image
+ frame ready before it has to be drawn. Drawing an image does not have to
+ wait the image frame to be decoded.
+
+ * platform/graphics/BitmapImage.cpp:
+ (WebCore::BitmapImage::frameImageAtIndex): Use the negation of frameHasValidNativeImageAtIndex().
+ * platform/graphics/BitmapImage.h:
+ (WebCore::BitmapImage::frameIsBeingDecodedAtIndex): Answers whether a frame is being decoded.
+ (WebCore::BitmapImage::frameHasValidNativeImageAtIndex): Checks the validity of a frame.
+ (WebCore::BitmapImage::frameHasInvalidNativeImageAtIndex): Deleted.
+ * platform/graphics/Image.h:
+ (WebCore::Image::newFrameNativeImageAvailableAtIndex): Notifies the image with the availability of a frame NativeImage.
+ * platform/graphics/ImageFrame.h:
+ (WebCore::ImageFrame::isBeingDecoded): Answers whether the frame is being decoded.
+ (WebCore::ImageFrame::hasValidNativeImage): Checks the validity of the frame.
+ (WebCore::ImageFrame::hasInvalidNativeImage): Deleted.
+ * platform/graphics/ImageFrameCache.cpp:
+ (WebCore::ImageFrameCache::~ImageFrameCache): Asserts the decoding loop was ended before deleting the ImageFrameCache.
+ (WebCore::ImageFrameCache::setFrameNativeImageAtIndex): Rename this function to matches the other which take the frame index.
+ (WebCore::ImageFrameCache::setFrameMetadataAtIndex): Ditto.
+ (WebCore::ImageFrameCache::replaceFrameNativeImageAtIndex): It setts the ImageFrame's members and updates the decoded size.
+ (WebCore::ImageFrameCache::cacheFrameNativeImageAtIndex): Replaces the frame NativeImage and notifies the Image with the new frame.
+ (WebCore::ImageFrameCache::decodingQueue): Ensures the decoding WorkQueue is created and returns it.
+ (WebCore::ImageFrameCache::startAsyncDecodingQueue): Starts a decoding WorkQueue which loops until m_frameRequestQueue is closed.
+ (WebCore::ImageFrameCache::requestFrameAsyncDecodingAtIndex): Allows ImageSource to send a request to start asynchronous frame image decoding.
+ (WebCore::ImageFrameCache::stopAsyncDecodingQueue): Stops the decoding WorkQueue by closing m_frameRequestQueue.
+ (WebCore::ImageFrameCache::frameAtIndex): Call replaceFrameNativeImageAtIndex().
+ (WebCore::ImageFrameCache::frameIsBeingDecodedAtIndex): Returns true if a request for the image frame is issued but not finished yet.
+ (WebCore::ImageFrameCache::frameHasValidNativeImageAtIndex): Checks the validity of a frame.
+ (WebCore::ImageFrameCache::setFrameNativeImage): Deleted. Was renamed to be setFrameNativeImageAtIndex.
+ (WebCore::ImageFrameCache::setFrameMetadata): Deleted. Was renamed to be setFrameMetadataAtIndex
+ (WebCore::ImageFrameCache::frameHasInvalidNativeImageAtIndex): Deleted. Was renamed to be frameHasValidNativeImageAtIndex.
+ * platform/graphics/ImageFrameCache.h:
+ (WebCore::ImageFrameCache::create): The decoding queue needs to hold a reference to this class so it can stop decoding safely without blocking.
+ (WebCore::ImageFrameCache::hasDecodingQueue): Returns true if a decoding queue has started.
+ * platform/graphics/ImageSource.cpp:
+ (WebCore::ImageSource::ImageSource): Call ImageFrameCache::create().
+ (WebCore::ImageSource::clear): Deleting the decoder is unnecessary for asynchronous decoding because ImageFrameCache manages all the memory.
+
+ (WebCore::ImageSource::destroyDecodedData):
+ (WebCore::ImageSource::destroyDecodedDataIfNecessary):
+ (WebCore::ImageSource::ensureDecoderAvailable):
+ (WebCore::ImageSource::dataChanged):
+ (WebCore::ImageSource::isAllDataReceived):
+ (WebCore::ImageSource::isAsyncDecodingRequired): Answers the question whether the async image decoding is required for this ImageSource.
+ (WebCore::ImageSource::frameImageAtIndex):
+ * platform/graphics/ImageSource.h:
+ (WebCore::ImageSource::decodedSize):
+ (WebCore::ImageSource::requestFrameAsyncDecodingAtIndex):
+ (WebCore::ImageSource::stopAsyncDecodingQueue):
+ (WebCore::ImageSource::isSizeAvailable):
+ (WebCore::ImageSource::frameCount):
+ (WebCore::ImageSource::repetitionCount):
+ (WebCore::ImageSource::filenameExtension):
+ (WebCore::ImageSource::hotSpot):
+ (WebCore::ImageSource::size):
+ (WebCore::ImageSource::sizeRespectingOrientation):
+ (WebCore::ImageSource::singlePixelSolidColor):
+ (WebCore::ImageSource::frameIsBeingDecodedAtIndex):
+ (WebCore::ImageSource::frameIsCompleteAtIndex):
+ (WebCore::ImageSource::frameHasAlphaAtIndex):
+ (WebCore::ImageSource::frameHasImageAtIndex):
+ (WebCore::ImageSource::frameSubsamplingLevelAtIndex):
+ (WebCore::ImageSource::frameSizeAtIndex):
+ (WebCore::ImageSource::frameBytesAtIndex):
+ (WebCore::ImageSource::frameDurationAtIndex):
+ (WebCore::ImageSource::frameOrientationAtIndex):
+ Make m_frameCache a type Ref<ImageFrameCache>. Use '->' instead of '.' when accessing its members.
+
+ (WebCore::ImageSource::frameHasValidNativeImageAtIndex): Checks the validity of a frame.
+ (WebCore::ImageSource::frameHasInvalidNativeImageAtIndex): Deleted. Was renamed to be frameHasValidNativeImageAtIndex.
+
2016-11-03 Myles C. Maxfield <[email protected]>
[WebGL2] Implement getBufferSubData()
Modified: trunk/Source/WebCore/platform/graphics/BitmapImage.cpp (208364 => 208365)
--- trunk/Source/WebCore/platform/graphics/BitmapImage.cpp 2016-11-04 02:37:45 UTC (rev 208364)
+++ trunk/Source/WebCore/platform/graphics/BitmapImage.cpp 2016-11-04 02:57:49 UTC (rev 208365)
@@ -82,7 +82,7 @@
NativeImagePtr BitmapImage::frameImageAtIndex(size_t index, SubsamplingLevel subsamplingLevel, const GraphicsContext* targetContext)
{
- if (frameHasInvalidNativeImageAtIndex(index, subsamplingLevel)) {
+ if (!frameHasValidNativeImageAtIndex(index, subsamplingLevel)) {
LOG(Images, "BitmapImage %p frameImageAtIndex - subsamplingLevel was %d, resampling", this, static_cast<int>(frameSubsamplingLevelAtIndex(index)));
invalidatePlatformData();
}
Modified: trunk/Source/WebCore/platform/graphics/BitmapImage.h (208364 => 208365)
--- trunk/Source/WebCore/platform/graphics/BitmapImage.h 2016-11-04 02:37:45 UTC (rev 208364)
+++ trunk/Source/WebCore/platform/graphics/BitmapImage.h 2016-11-04 02:57:49 UTC (rev 208365)
@@ -82,9 +82,10 @@
void setAllowSubsampling(bool allowSubsampling) { m_source.setAllowSubsampling(allowSubsampling); }
+ bool frameIsBeingDecodedAtIndex(size_t index) const { return m_source.frameIsBeingDecodedAtIndex(index); }
bool frameIsCompleteAtIndex(size_t index) const { return m_source.frameIsCompleteAtIndex(index); }
bool frameHasAlphaAtIndex(size_t index) const { return m_source.frameHasAlphaAtIndex(index); }
- bool frameHasInvalidNativeImageAtIndex(size_t index, SubsamplingLevel subsamplingLevel) const { return m_source.frameHasInvalidNativeImageAtIndex(index, subsamplingLevel); }
+ bool frameHasValidNativeImageAtIndex(size_t index, SubsamplingLevel subsamplingLevel) const { return m_source.frameHasValidNativeImageAtIndex(index, subsamplingLevel); }
SubsamplingLevel frameSubsamplingLevelAtIndex(size_t index) const { return m_source.frameSubsamplingLevelAtIndex(index); }
float frameDurationAtIndex(size_t index) const { return m_source.frameDurationAtIndex(index); }
Modified: trunk/Source/WebCore/platform/graphics/Image.h (208364 => 208365)
--- trunk/Source/WebCore/platform/graphics/Image.h 2016-11-04 02:37:45 UTC (rev 208364)
+++ trunk/Source/WebCore/platform/graphics/Image.h 2016-11-04 02:57:49 UTC (rev 208365)
@@ -129,6 +129,7 @@
virtual void startAnimation() { }
virtual void stopAnimation() {}
virtual void resetAnimation() {}
+ virtual void newFrameNativeImageAvailableAtIndex(size_t) { }
// Typically the CachedImage that owns us.
ImageObserver* imageObserver() const { return m_imageObserver; }
Modified: trunk/Source/WebCore/platform/graphics/ImageFrame.h (208364 => 208365)
--- trunk/Source/WebCore/platform/graphics/ImageFrame.h 2016-11-04 02:37:45 UTC (rev 208364)
+++ trunk/Source/WebCore/platform/graphics/ImageFrame.h 2016-11-04 02:57:49 UTC (rev 208365)
@@ -82,7 +82,7 @@
friend class ImageFrameCache;
public:
enum class Caching { Empty, Metadata, MetadataAndImage };
- enum class Decoding { Empty, Partial, Complete };
+ enum class Decoding { Empty, BeingDecoded, Partial, Complete };
ImageFrame();
ImageFrame(const ImageFrame& other) { operator=(other); }
@@ -104,6 +104,7 @@
void setDecoding(Decoding decoding) { m_decoding = decoding; }
Decoding decoding() const { return m_decoding; }
bool isEmpty() const { return m_decoding == Decoding::Empty; }
+ bool isBeingDecoded() const { return m_decoding == Decoding::BeingDecoded; }
bool isPartial() const { return m_decoding == Decoding::Partial; }
bool isComplete() const { return m_decoding == Decoding::Complete; }
@@ -130,7 +131,7 @@
bool hasAlpha() const { return !hasMetadata() || m_hasAlpha; }
bool hasNativeImage() const { return m_nativeImage; }
- bool hasInvalidNativeImage(SubsamplingLevel subsamplingLevel) const { return hasNativeImage() && subsamplingLevel < m_subsamplingLevel; }
+ bool hasValidNativeImage(SubsamplingLevel subsamplingLevel) const { return hasNativeImage() && subsamplingLevel >= m_subsamplingLevel; }
bool hasMetadata() const { return !size().isEmpty(); }
#if !USE(CG)
Modified: trunk/Source/WebCore/platform/graphics/ImageFrameCache.cpp (208364 => 208365)
--- trunk/Source/WebCore/platform/graphics/ImageFrameCache.cpp 2016-11-04 02:37:45 UTC (rev 208364)
+++ trunk/Source/WebCore/platform/graphics/ImageFrameCache.cpp 2016-11-04 02:57:49 UTC (rev 208365)
@@ -39,8 +39,9 @@
#endif
#include <wtf/CheckedArithmetic.h>
+#include <wtf/MainThread.h>
+#include <wtf/RunLoop.h>
-
namespace WebCore {
ImageFrameCache::ImageFrameCache(Image* image)
@@ -64,6 +65,11 @@
m_sizeRespectingOrientation = m_size;
}
+ImageFrameCache::~ImageFrameCache()
+{
+ ASSERT(!hasDecodingQueue());
+}
+
void ImageFrameCache::destroyDecodedData(bool destroyAll, size_t count)
{
if (destroyAll)
@@ -178,7 +184,7 @@
frame.m_hasAlpha = nativeImageHasAlpha(frame.m_nativeImage);
}
-void ImageFrameCache::setFrameNativeImage(NativeImagePtr&& nativeImage, size_t index, SubsamplingLevel subsamplingLevel)
+void ImageFrameCache::setFrameNativeImageAtIndex(NativeImagePtr&& nativeImage, size_t index, SubsamplingLevel subsamplingLevel)
{
ASSERT(index < m_frames.size());
ImageFrame& frame = m_frames[index];
@@ -186,10 +192,10 @@
ASSERT(isDecoderAvailable());
frame.m_nativeImage = WTFMove(nativeImage);
- setFrameMetadata(index, subsamplingLevel);
+ setFrameMetadataAtIndex(index, subsamplingLevel);
}
-void ImageFrameCache::setFrameMetadata(size_t index, SubsamplingLevel subsamplingLevel)
+void ImageFrameCache::setFrameMetadataAtIndex(size_t index, SubsamplingLevel subsamplingLevel)
{
ASSERT(index < m_frames.size());
ImageFrame& frame = m_frames[index];
@@ -208,34 +214,121 @@
frame.m_duration = m_decoder->frameDurationAtIndex(index);
}
-const ImageFrame& ImageFrameCache::frameAtIndex(size_t index, SubsamplingLevel subsamplingLevel, ImageFrame::Caching caching)
+void ImageFrameCache::replaceFrameNativeImageAtIndex(NativeImagePtr&& nativeImage, size_t index, SubsamplingLevel subsamplingLevel)
{
ASSERT(index < m_frames.size());
ImageFrame& frame = m_frames[index];
- if (!isDecoderAvailable() || caching == ImageFrame::Caching::Empty)
- return frame;
+
+ if (!frame.hasValidNativeImage(subsamplingLevel)) {
+ // Clear the current image frame and update the observer with this clearance.
+ unsigned decodedSize = frame.clear();
+ decodedSizeDecreased(decodedSize);
+ }
+
+ // Do not cache the NativeImage if adding its frameByes to the MemoryCache will cause numerical overflow.
+ size_t frameBytes = size().unclampedArea() * sizeof(RGBA32);
+ if (!WTF::isInBounds<unsigned>(frameBytes + decodedSize()))
+ return;
+
+ // Copy the new image to the cache.
+ setFrameNativeImageAtIndex(WTFMove(nativeImage), index, subsamplingLevel);
+
+ // Update the observer with the new image frame bytes.
+ decodedSizeIncreased(frame.frameBytes());
+}
+
+void ImageFrameCache::cacheFrameNativeImageAtIndex(NativeImagePtr&& nativeImage, size_t index, SubsamplingLevel subsamplingLevel)
+{
+ if (!isDecoderAvailable())
+ return;
+
+ // Clean the old native image and set a new one
+ replaceFrameNativeImageAtIndex(WTFMove(nativeImage), index, subsamplingLevel);
+
+ // Notify the image with the readiness of the new frame NativeImage.
+ if (m_image)
+ m_image->newFrameNativeImageAvailableAtIndex(index);
+}
+
+Ref<WorkQueue> ImageFrameCache::decodingQueue()
+{
+ if (!m_decodingQueue)
+ m_decodingQueue = WorkQueue::create("org.webkit.ImageDecoder", WorkQueue::Type::Serial, WorkQueue::QOS::UserInteractive);
+ return *m_decodingQueue;
+}
+
+void ImageFrameCache::startAsyncDecodingQueue()
+{
+ if (hasDecodingQueue() || !isDecoderAvailable())
+ return;
+
+ Ref<ImageFrameCache> protectedThis = Ref<ImageFrameCache>(*this);
+ Ref<WorkQueue> protectedQueue = decodingQueue();
+
+ // We need to protect this and m_decodingQueue from being deleted while we are in the decoding loop.
+ decodingQueue()->dispatch([this, protectedThis = WTFMove(protectedThis), protectedQueue = WTFMove(protectedQueue)] {
+ ImageFrameRequest frameRequest;
+
+ while (m_frameRequestQueue.dequeue(frameRequest)) {
+ // Get the frame NativeImage on the decoding thread.
+ NativeImagePtr nativeImage = m_decoder->createFrameImageAtIndex(frameRequest.index, frameRequest.subsamplingLevel, DecodingMode::Immediate);
+
+ // Update the cached frames on the main thread to avoid updating the MemoryCache from a different thread.
+ callOnMainThread([this, nativeImage, frameRequest] () mutable {
+ // The queue may be closed if after we got the frame NativeImage, stopAsyncDecodingQueue() was called
+ if (hasDecodingQueue())
+ cacheFrameNativeImageAtIndex(WTFMove(nativeImage), frameRequest.index, frameRequest.subsamplingLevel);
+ });
+ }
+ });
+}
+
+void ImageFrameCache::requestFrameAsyncDecodingAtIndex(size_t index, SubsamplingLevel subsamplingLevel)
+{
+ if (!isDecoderAvailable())
+ return;
+
+ if (!hasDecodingQueue())
+ startAsyncDecodingQueue();
+
+ ASSERT(index < m_frames.size());
+ ImageFrame& frame = m_frames[index];
+
if (subsamplingLevel == SubsamplingLevel::Undefinded)
subsamplingLevel = frame.subsamplingLevel();
- if (frame.hasInvalidNativeImage(subsamplingLevel)) {
- unsigned decodedSize = frame.clear();
- decodedSizeDecreased(decodedSize);
- }
+ if (frame.hasValidNativeImage(subsamplingLevel))
+ return;
- if (!frame.isComplete() && caching == ImageFrame::Caching::Metadata)
- setFrameMetadata(index, subsamplingLevel);
+ frame.setDecoding(ImageFrame::Decoding::BeingDecoded);
+ m_frameRequestQueue.enqueue({ index, subsamplingLevel });
+}
+
+void ImageFrameCache::stopAsyncDecodingQueue()
+{
+ if (!hasDecodingQueue())
+ return;
- if (!frame.hasNativeImage() && caching == ImageFrame::Caching::MetadataAndImage) {
- size_t frameBytes = size().unclampedArea() * sizeof(RGBA32);
+ m_frameRequestQueue.close();
+ m_decodingQueue = nullptr;
+}
- // Do not create the NativeImage if adding its frameByes to the MemoryCache will cause numerical overflow.
- if (WTF::isInBounds<unsigned>(frameBytes + decodedSize())) {
- setFrameNativeImage(m_decoder->createFrameImageAtIndex(index, subsamplingLevel), index, subsamplingLevel);
- decodedSizeIncreased(frame.frameBytes());
- }
- }
+const ImageFrame& ImageFrameCache::frameAtIndex(size_t index, SubsamplingLevel subsamplingLevel, ImageFrame::Caching caching)
+{
+ ASSERT(index < m_frames.size());
+ ImageFrame& frame = m_frames[index];
+ if (!isDecoderAvailable() || frame.isBeingDecoded() || caching == ImageFrame::Caching::Empty)
+ return frame;
+ if (subsamplingLevel == SubsamplingLevel::Undefinded)
+ subsamplingLevel = frame.subsamplingLevel();
+
+ if (!frame.isComplete() && caching == ImageFrame::Caching::Metadata)
+ setFrameMetadataAtIndex(index, subsamplingLevel);
+ else if (!frame.hasValidNativeImage(subsamplingLevel) && caching == ImageFrame::Caching::MetadataAndImage)
+ replaceFrameNativeImageAtIndex(m_decoder->createFrameImageAtIndex(index, subsamplingLevel), index, subsamplingLevel);
+
return frame;
}
@@ -327,6 +420,11 @@
return frameCount() == 1 ? frameMetadataAtIndex<Color, (&ImageFrame::singlePixelSolidColor)>(0, SubsamplingLevel::Undefinded, ImageFrame::Caching::MetadataAndImage, &m_singlePixelSolidColor) : Color();
}
+bool ImageFrameCache::frameIsBeingDecodedAtIndex(size_t index)
+{
+ return frameMetadataAtIndex<bool, (&ImageFrame::isBeingDecoded)>(index);
+}
+
bool ImageFrameCache::frameIsCompleteAtIndex(size_t index)
{
return frameMetadataAtIndex<bool, (&ImageFrame::isComplete)>(index);
@@ -342,9 +440,9 @@
return frameMetadataAtIndex<bool, (&ImageFrame::hasNativeImage)>(index);
}
-bool ImageFrameCache::frameHasInvalidNativeImageAtIndex(size_t index, SubsamplingLevel subsamplingLevel)
+bool ImageFrameCache::frameHasValidNativeImageAtIndex(size_t index, SubsamplingLevel subsamplingLevel)
{
- return frameHasImageAtIndex(index) && subsamplingLevel < frameSubsamplingLevelAtIndex(index);
+ return frameHasImageAtIndex(index) && subsamplingLevel >= frameSubsamplingLevelAtIndex(index);
}
SubsamplingLevel ImageFrameCache::frameSubsamplingLevelAtIndex(size_t index)
Modified: trunk/Source/WebCore/platform/graphics/ImageFrameCache.h (208364 => 208365)
--- trunk/Source/WebCore/platform/graphics/ImageFrameCache.h 2016-11-04 02:37:45 UTC (rev 208364)
+++ trunk/Source/WebCore/platform/graphics/ImageFrameCache.h 2016-11-04 02:57:49 UTC (rev 208365)
@@ -30,6 +30,9 @@
#include <wtf/Forward.h>
#include <wtf/Optional.h>
+#include <wtf/SynchronizedFixedQueue.h>
+#include <wtf/WorkQueue.h>
+#include <wtf/threads/BinarySemaphore.h>
namespace WebCore {
@@ -37,12 +40,21 @@
class Image;
class ImageDecoder;
-class ImageFrameCache {
+class ImageFrameCache : public RefCounted<ImageFrameCache> {
friend class ImageSource;
public:
- ImageFrameCache(Image*);
- ImageFrameCache(NativeImagePtr&&);
+ static Ref<ImageFrameCache> create(Image* image)
+ {
+ return adoptRef(*new ImageFrameCache(image));
+ }
+ static Ref<ImageFrameCache> create(NativeImagePtr&& nativeImage)
+ {
+ return adoptRef(*new ImageFrameCache(WTFMove(nativeImage)));
+ }
+
+ ~ImageFrameCache();
+
void setDecoder(ImageDecoder* decoder) { m_decoder = decoder; }
ImageDecoder* decoder() const { return m_decoder; }
@@ -53,6 +65,12 @@
void growFrames();
void clearMetadata();
+
+ // Asynchronous image decoding
+ void startAsyncDecodingQueue();
+ void requestFrameAsyncDecodingAtIndex(size_t, SubsamplingLevel);
+ void stopAsyncDecodingQueue();
+ bool hasDecodingQueue() { return m_decodingQueue; }
// Image metadata which is calculated either by the ImageDecoder or directly
// from the NativeImage if this class was created for a memory image.
@@ -69,10 +87,11 @@
Color singlePixelSolidColor();
// ImageFrame metadata which does not require caching the ImageFrame.
+ bool frameIsBeingDecodedAtIndex(size_t);
bool frameIsCompleteAtIndex(size_t);
bool frameHasAlphaAtIndex(size_t);
bool frameHasImageAtIndex(size_t);
- bool frameHasInvalidNativeImageAtIndex(size_t, SubsamplingLevel);
+ bool frameHasValidNativeImageAtIndex(size_t, SubsamplingLevel);
SubsamplingLevel frameSubsamplingLevelAtIndex(size_t);
// ImageFrame metadata which forces caching or re-caching the ImageFrame.
@@ -83,6 +102,9 @@
NativeImagePtr frameImageAtIndex(size_t, SubsamplingLevel = SubsamplingLevel::Default);
private:
+ ImageFrameCache(Image*);
+ ImageFrameCache(NativeImagePtr&&);
+
template<typename T, T (ImageDecoder::*functor)() const>
T metadata(const T& defaultValue, Optional<T>* cachedValue = nullptr);
@@ -97,8 +119,13 @@
void decodedSizeReset(unsigned decodedSize);
void setNativeImage(NativeImagePtr&&);
- void setFrameNativeImage(NativeImagePtr&&, size_t, SubsamplingLevel);
- void setFrameMetadata(size_t, SubsamplingLevel);
+ void setFrameNativeImageAtIndex(NativeImagePtr&&, size_t, SubsamplingLevel);
+ void setFrameMetadataAtIndex(size_t, SubsamplingLevel);
+ void replaceFrameNativeImageAtIndex(NativeImagePtr&&, size_t, SubsamplingLevel);
+ void cacheFrameNativeImageAtIndex(NativeImagePtr&&, size_t, SubsamplingLevel);
+
+ Ref<WorkQueue> decodingQueue();
+
const ImageFrame& frameAtIndex(size_t, SubsamplingLevel, ImageFrame::Caching);
// Animated images over a certain size are considered large enough that we'll only hang on to one frame at a time.
@@ -115,6 +142,16 @@
Vector<ImageFrame, 1> m_frames;
+ // Asynchronous image decoding.
+ struct ImageFrameRequest {
+ size_t index;
+ SubsamplingLevel subsamplingLevel;
+ };
+ static const int BufferSize = 8;
+ using FrameRequestQueue = SynchronizedFixedQueue<ImageFrameRequest, BufferSize>;
+ FrameRequestQueue m_frameRequestQueue;
+ RefPtr<WorkQueue> m_decodingQueue;
+
// Image metadata.
Optional<bool> m_isSizeAvailable;
Optional<size_t> m_frameCount;
Modified: trunk/Source/WebCore/platform/graphics/ImageSource.cpp (208364 => 208365)
--- trunk/Source/WebCore/platform/graphics/ImageSource.cpp 2016-11-04 02:37:45 UTC (rev 208364)
+++ trunk/Source/WebCore/platform/graphics/ImageSource.cpp 2016-11-04 02:57:49 UTC (rev 208365)
@@ -46,12 +46,12 @@
namespace WebCore {
ImageSource::ImageSource(NativeImagePtr&& nativeImage)
- : m_frameCache(WTFMove(nativeImage))
+ : m_frameCache(ImageFrameCache::create(WTFMove(nativeImage)))
{
}
ImageSource::ImageSource(Image* image, AlphaOption alphaOption, GammaAndColorProfileOption gammaAndColorProfileOption)
- : m_frameCache(image)
+ : m_frameCache(ImageFrameCache::create(image))
, m_alphaOption(alphaOption)
, m_gammaAndColorProfileOption(gammaAndColorProfileOption)
{
@@ -72,19 +72,19 @@
{
// There's no need to throw away the decoder unless we're explicitly asked
// to destroy all of the frames.
- if (!destroyAll) {
+ if (!destroyAll || m_frameCache->hasDecodingQueue()) {
clearFrameBufferCache(count);
return;
}
m_decoder = nullptr;
- m_frameCache.setDecoder(nullptr);
+ m_frameCache->setDecoder(nullptr);
setData(data, isAllDataReceived());
}
void ImageSource::destroyDecodedData(SharedBuffer* data, bool destroyAll, size_t count)
{
- m_frameCache.destroyDecodedData(destroyAll, count);
+ m_frameCache->destroyDecodedData(destroyAll, count);
clear(destroyAll, count, data);
}
@@ -92,10 +92,10 @@
{
// If we have decoded frames but there is no encoded data, we shouldn't destroy
// the decoded image since we won't be able to reconstruct it later.
- if (!data && m_frameCache.frameCount())
+ if (!data && m_frameCache->frameCount())
return false;
- if (!m_frameCache.destroyDecodedDataIfNecessary(destroyAll, count))
+ if (!m_frameCache->destroyDecodedDataIfNecessary(destroyAll, count))
return false;
clear(destroyAll, count, data);
@@ -111,7 +111,7 @@
if (!isDecoderAvailable())
return false;
- m_frameCache.setDecoder(m_decoder.get());
+ m_frameCache->setDecoder(m_decoder.get());
return true;
}
@@ -138,7 +138,7 @@
bool ImageSource::dataChanged(SharedBuffer* data, bool allDataReceived)
{
- m_frameCache.destroyIncompleteDecodedData();
+ m_frameCache->destroyIncompleteDecodedData();
#if PLATFORM(IOS)
// FIXME: We should expose a setting to enable/disable progressive loading and make this
@@ -162,19 +162,25 @@
setData(data, allDataReceived);
#endif
- m_frameCache.clearMetadata();
+ m_frameCache->clearMetadata();
if (!isSizeAvailable())
return false;
- m_frameCache.growFrames();
+ m_frameCache->growFrames();
return true;
}
bool ImageSource::isAllDataReceived()
{
- return isDecoderAvailable() ? m_decoder->isAllDataReceived() : m_frameCache.frameCount();
+ return isDecoderAvailable() ? m_decoder->isAllDataReceived() : m_frameCache->frameCount();
}
+bool ImageSource::isAsyncDecodingRequired()
+{
+ // FIXME: figure out the best heuristic for enabling async image decoding.
+ return size().area() * sizeof(RGBA32) >= 100 * KB;
+}
+
SubsamplingLevel ImageSource::maximumSubsamplingLevel()
{
if (m_maximumSubsamplingLevel)
@@ -216,7 +222,7 @@
{
setDecoderTargetContext(targetContext);
- return m_frameCache.frameImageAtIndex(index, subsamplingLevel);
+ return m_frameCache->frameImageAtIndex(index, subsamplingLevel);
}
void ImageSource::dump(TextStream& ts)
Modified: trunk/Source/WebCore/platform/graphics/ImageSource.h (208364 => 208365)
--- trunk/Source/WebCore/platform/graphics/ImageSource.h 2016-11-04 02:37:45 UTC (rev 208364)
+++ trunk/Source/WebCore/platform/graphics/ImageSource.h 2016-11-04 02:57:49 UTC (rev 208365)
@@ -62,33 +62,38 @@
void setData(SharedBuffer* data, bool allDataReceived);
bool dataChanged(SharedBuffer* data, bool allDataReceived);
- unsigned decodedSize() const { return m_frameCache.decodedSize(); }
+ unsigned decodedSize() const { return m_frameCache->decodedSize(); }
bool isAllDataReceived();
+ bool isAsyncDecodingRequired();
+ void requestFrameAsyncDecodingAtIndex(size_t index, SubsamplingLevel subsamplingLevel) { m_frameCache->requestFrameAsyncDecodingAtIndex(index, subsamplingLevel); }
+ void stopAsyncDecodingQueue() { m_frameCache->stopAsyncDecodingQueue(); }
+
// Image metadata which is calculated by the decoder or can deduced by the case of the memory NativeImage.
- bool isSizeAvailable() { return m_frameCache.isSizeAvailable(); }
- size_t frameCount() { return m_frameCache.frameCount(); }
- RepetitionCount repetitionCount() { return m_frameCache.repetitionCount(); }
- String filenameExtension() { return m_frameCache.filenameExtension(); }
- Optional<IntPoint> hotSpot() { return m_frameCache.hotSpot(); }
+ bool isSizeAvailable() { return m_frameCache->isSizeAvailable(); }
+ size_t frameCount() { return m_frameCache->frameCount(); }
+ RepetitionCount repetitionCount() { return m_frameCache->repetitionCount(); }
+ String filenameExtension() { return m_frameCache->filenameExtension(); }
+ Optional<IntPoint> hotSpot() { return m_frameCache->hotSpot(); }
// Image metadata which is calculated from the first ImageFrame.
- IntSize size() { return m_frameCache.size(); }
- IntSize sizeRespectingOrientation() { return m_frameCache.sizeRespectingOrientation(); }
- Color singlePixelSolidColor() { return m_frameCache.singlePixelSolidColor(); }
+ IntSize size() { return m_frameCache->size(); }
+ IntSize sizeRespectingOrientation() { return m_frameCache->sizeRespectingOrientation(); }
+ Color singlePixelSolidColor() { return m_frameCache->singlePixelSolidColor(); }
// ImageFrame metadata which does not require caching the ImageFrame.
- bool frameIsCompleteAtIndex(size_t index) { return m_frameCache.frameIsCompleteAtIndex(index); }
- bool frameHasAlphaAtIndex(size_t index) { return m_frameCache.frameHasAlphaAtIndex(index); }
- bool frameHasImageAtIndex(size_t index) { return m_frameCache.frameHasImageAtIndex(index); }
- bool frameHasInvalidNativeImageAtIndex(size_t index, SubsamplingLevel subsamplingLevel) { return m_frameCache.frameHasInvalidNativeImageAtIndex(index, subsamplingLevel); }
- SubsamplingLevel frameSubsamplingLevelAtIndex(size_t index) { return m_frameCache.frameSubsamplingLevelAtIndex(index); }
+ bool frameIsBeingDecodedAtIndex(size_t index) { return m_frameCache->frameIsBeingDecodedAtIndex(index); }
+ bool frameIsCompleteAtIndex(size_t index) { return m_frameCache->frameIsCompleteAtIndex(index); }
+ bool frameHasAlphaAtIndex(size_t index) { return m_frameCache->frameHasAlphaAtIndex(index); }
+ bool frameHasImageAtIndex(size_t index) { return m_frameCache->frameHasImageAtIndex(index); }
+ bool frameHasValidNativeImageAtIndex(size_t index, SubsamplingLevel subsamplingLevel) { return m_frameCache->frameHasValidNativeImageAtIndex(index, subsamplingLevel); }
+ SubsamplingLevel frameSubsamplingLevelAtIndex(size_t index) { return m_frameCache->frameSubsamplingLevelAtIndex(index); }
// ImageFrame metadata which forces caching or re-caching the ImageFrame.
- IntSize frameSizeAtIndex(size_t index, SubsamplingLevel subsamplingLevel = SubsamplingLevel::Default) { return m_frameCache.frameSizeAtIndex(index, subsamplingLevel); }
- unsigned frameBytesAtIndex(size_t index, SubsamplingLevel subsamplingLevel = SubsamplingLevel::Default) { return m_frameCache.frameBytesAtIndex(index, subsamplingLevel); }
- float frameDurationAtIndex(size_t index) { return m_frameCache.frameDurationAtIndex(index); }
- ImageOrientation frameOrientationAtIndex(size_t index) { return m_frameCache.frameOrientationAtIndex(index); }
+ IntSize frameSizeAtIndex(size_t index, SubsamplingLevel subsamplingLevel = SubsamplingLevel::Default) { return m_frameCache->frameSizeAtIndex(index, subsamplingLevel); }
+ unsigned frameBytesAtIndex(size_t index, SubsamplingLevel subsamplingLevel = SubsamplingLevel::Default) { return m_frameCache->frameBytesAtIndex(index, subsamplingLevel); }
+ float frameDurationAtIndex(size_t index) { return m_frameCache->frameDurationAtIndex(index); }
+ ImageOrientation frameOrientationAtIndex(size_t index) { return m_frameCache->frameOrientationAtIndex(index); }
NativeImagePtr frameImageAtIndex(size_t index, SubsamplingLevel = SubsamplingLevel::Default, const GraphicsContext* targetContext = nullptr);
SubsamplingLevel maximumSubsamplingLevel();
@@ -103,7 +108,7 @@
void setDecoderTargetContext(const GraphicsContext*);
- ImageFrameCache m_frameCache;
+ Ref<ImageFrameCache> m_frameCache;
std::unique_ptr<ImageDecoder> m_decoder;
Optional<SubsamplingLevel> m_maximumSubsamplingLevel;