Diff
Modified: trunk/Source/WebCore/ChangeLog (216881 => 216882)
--- trunk/Source/WebCore/ChangeLog 2017-05-15 22:07:54 UTC (rev 216881)
+++ trunk/Source/WebCore/ChangeLog 2017-05-15 22:10:37 UTC (rev 216882)
@@ -1,3 +1,96 @@
+2017-05-15 Said Abou-Hallawa <sabouhall...@apple.com>
+
+ REGRESSION (216471): Infinite repaint-drawing loop when asynchronously decoding incomplete image frames
+ https://bugs.webkit.org/show_bug.cgi?id=171900
+
+ Reviewed by Tim Horton.
+
+ -- Don't destroy incomplete decoded image frames for large images. This
+ is to avoid flickering while decoding another image frame with the new
+ data. The old incomplete image frame will be destroyed once the newer one
+ finishes decoding.
+
+ -- Extend the enum ImageFrame::DecodingStatus by adding a new value called
+ 'Decoding'. This new value will never be cached in the ImageFrame::
+ m_decodingStatus. Add a member m_currentFrameDecodingStatus to BitmapImage.
+ The purpose of this member is to invalidate the current frame, without
+ deleting it, when new encoded data is received.
+
+ -- Don't wait until the native image is decoded to cache the ImageFrame
+ decodingStatus. There is a big chance that more data arrives between
+ starting the decoding and finishing it such that the decoding changes
+ from Partial to Complete. We need to prevent keeping incomplete ImageFrames
+ cached because we mistakenly assume they are complete. To fix this issue
+ we need to know the ImageFrame decodingStatus when the decoding is requested.
+
+ * platform/graphics/BitmapImage.cpp:
+ (WebCore::BitmapImage::destroyDecodedData):
+ (WebCore::BitmapImage::dataChanged):
+ (WebCore::BitmapImage::draw):
+ (WebCore::BitmapImage::internalStartAnimation): At the beginning of this
+ function we check whether the next frame is being decoded or not and we
+ return DecodingActive if it is. Let's handle the second check here also
+ before requesting the decoding of nextFrame. We need to check whether the
+ nextFrame has a native image with decoded with the native size or not.
+ (WebCore::BitmapImage::internalAdvanceAnimation):
+ (WebCore::BitmapImage::imageFrameAvailableAtIndex):
+ * platform/graphics/BitmapImage.h:
+ * platform/graphics/ImageFrame.cpp:
+ (WebCore::ImageFrame::operator=):
+ (WebCore::ImageFrame::setDecodingStatus):
+ (WebCore::ImageFrame::decodingStatus):
+ * platform/graphics/ImageFrame.h:
+ (WebCore::ImageFrame::isInvalid):
+ (WebCore::ImageFrame::isPartial):
+ (WebCore::ImageFrame::isComplete):
+ (WebCore::ImageFrame::setDecoding): Deleted.
+ (WebCore::ImageFrame::decoding): Deleted.
+ (WebCore::ImageFrame::isEmpty): Deleted.
+ * platform/graphics/ImageFrameCache.cpp:
+ (WebCore::ImageFrameCache::setNativeImage):
+ (WebCore::ImageFrameCache::cacheMetadataAtIndex):
+ (WebCore::ImageFrameCache::cacheNativeImageAtIndex):
+ (WebCore::ImageFrameCache::cacheNativeImageAtIndexAsync):
+ (WebCore::ImageFrameCache::startAsyncDecodingQueue):
+ (WebCore::ImageFrameCache::requestFrameAsyncDecodingAtIndex):
+ (WebCore::ImageFrameCache::stopAsyncDecodingQueue):
+ (WebCore::ImageFrameCache::frameAtIndexCacheIfNeeded):
+ (WebCore::ImageFrameCache::frameDecodingStatusAtIndex):
+ (WebCore::ImageFrameCache::cacheFrameMetadataAtIndex): Deleted.
+ (WebCore::ImageFrameCache::cacheFrameNativeImageAtIndex): Deleted.
+ (WebCore::ImageFrameCache::cacheAsyncFrameNativeImageAtIndex): Deleted.
+ (WebCore::ImageFrameCache::frameIsCompleteAtIndex): Deleted.
+ * platform/graphics/ImageFrameCache.h:
+ (WebCore::ImageFrameCache::ImageFrameRequest::operator==):
+ * platform/graphics/ImageSource.cpp:
+ (WebCore::ImageSource::dataChanged):
+ * platform/graphics/ImageSource.h:
+ (WebCore::ImageSource::destroyIncompleteDecodedData):
+ (WebCore::ImageSource::requestFrameAsyncDecodingAtIndex): Let the caller
+ decide whether another request for the same image frame is allowed or not.
+ (WebCore::ImageSource::frameDecodingStatusAtIndex):
+ (WebCore::ImageSource::frameIsCompleteAtIndex): Deleted.
+ * platform/image-decoders/ImageDecoder.cpp:
+ (WebCore::ImageDecoder::frameDurationAtIndex):
+ (WebCore::ImageDecoder::createFrameImageAtIndex):
+ * platform/image-decoders/bmp/BMPImageReader.cpp:
+ (WebCore::BMPImageReader::decodeBMP):
+ * platform/image-decoders/gif/GIFImageDecoder.cpp:
+ (WebCore::GIFImageDecoder::clearFrameBufferCache):
+ (WebCore::GIFImageDecoder::haveDecodedRow):
+ (WebCore::GIFImageDecoder::frameComplete):
+ (WebCore::GIFImageDecoder::initFrameBuffer):
+ * platform/image-decoders/jpeg/JPEGImageDecoder.cpp:
+ (WebCore::JPEGImageDecoder::outputScanlines):
+ (WebCore::JPEGImageDecoder::jpegComplete):
+ * platform/image-decoders/png/PNGImageDecoder.cpp:
+ (WebCore::PNGImageDecoder::rowAvailable):
+ (WebCore::PNGImageDecoder::pngComplete):
+ (WebCore::PNGImageDecoder::clearFrameBufferCache):
+ (WebCore::PNGImageDecoder::frameComplete):
+ * platform/image-decoders/webp/WEBPImageDecoder.cpp:
+ (WebCore::WEBPImageDecoder::decode):
+
2017-05-15 Chris Dumez <cdu...@apple.com>
Align WebKitCSSMatrix stringifier with spec for DOMMatrix
Modified: trunk/Source/WebCore/platform/graphics/BitmapImage.cpp (216881 => 216882)
--- trunk/Source/WebCore/platform/graphics/BitmapImage.cpp 2017-05-15 22:07:54 UTC (rev 216881)
+++ trunk/Source/WebCore/platform/graphics/BitmapImage.cpp 2017-05-15 22:10:37 UTC (rev 216882)
@@ -81,8 +81,10 @@
m_source.destroyDecodedDataBeforeFrame(m_currentFrame);
else if (m_source.hasAsyncDecodingQueue())
m_source.destroyAllDecodedDataExcludeFrame(m_currentFrame);
- else
+ else {
m_source.destroyAllDecodedData();
+ m_currentFrameDecodingStatus = ImageFrame::DecodingStatus::Invalid;
+ }
// There's no need to throw away the decoder unless we're explicitly asked
// to destroy all of the frames.
@@ -109,6 +111,10 @@
EncodedDataStatus BitmapImage::dataChanged(bool allDataReceived)
{
+ if (!shouldUseAsyncDecodingForLargeImages())
+ m_source.destroyIncompleteDecodedData();
+
+ m_currentFrameDecodingStatus = ImageFrame::DecodingStatus::Invalid;
return m_source.dataChanged(data(), allDataReceived);
}
@@ -185,13 +191,13 @@
bool frameIsCompatible = frameHasDecodedNativeImageCompatibleWithOptionsAtIndex(m_currentFrame, m_currentSubsamplingLevel, DecodingOptions(sizeForDrawing));
bool frameIsBeingDecoded = frameIsBeingDecodedAndIsCompatibleWithOptionsAtIndex(m_currentFrame, DecodingOptions(sizeForDrawing));
- bool frameIsComplete = frameIsCompleteAtIndex(m_currentFrame);
// If the current frame is incomplete, a new request for decoding this frame has to be made even if
// it is currently being decoded. New data may have been received since the previous request was made.
- if ((!frameIsCompatible && !frameIsBeingDecoded) || !frameIsComplete) {
+ if ((!frameIsCompatible && !frameIsBeingDecoded) || m_currentFrameDecodingStatus == ImageFrame::DecodingStatus::Invalid) {
LOG(Images, "BitmapImage::%s - %p - url: %s [requesting large async decoding]", __FUNCTION__, this, sourceURL().string().utf8().data());
- frameIsBeingDecoded = m_source.requestFrameAsyncDecodingAtIndex(0, m_currentSubsamplingLevel, sizeForDrawing);
+ m_source.requestFrameAsyncDecodingAtIndex(0, m_currentSubsamplingLevel, sizeForDrawing);
+ m_currentFrameDecodingStatus = ImageFrame::DecodingStatus::Decoding;
}
if (!frameHasDecodedNativeImageCompatibleWithOptionsAtIndex(m_currentFrame, m_currentSubsamplingLevel, DecodingMode::Asynchronous)) {
@@ -201,7 +207,6 @@
}
image = frameImageAtIndex(m_currentFrame);
- ASSERT_IMPLIES(encodedDataStatus() == EncodedDataStatus::Complete, frameIsBeingDecoded || frameIsComplete);
LOG(Images, "BitmapImage::%s - %p - url: %s [a decoded image frame is available for drawing]", __FUNCTION__, this, sourceURL().string().utf8().data());
} else {
StartAnimationStatus status = internalStartAnimation();
@@ -238,6 +243,7 @@
orientation = frameOrientationAtIndex(m_currentFrame);
drawNativeImage(image, context, destRect, srcRect, IntSize(size()), op, mode, orientation);
+ m_currentFrameDecodingStatus = frameDecodingStatusAtIndex(m_currentFrame);
if (imageObserver())
imageObserver()->didDraw(this);
@@ -362,16 +368,13 @@
// through the callback newFrameNativeImageAvailableAtIndex(). Otherwise, advanceAnimation() will be called
// when the timer fires and m_currentFrame will be advanced to nextFrame since it is not being decoded.
if (shouldUseAsyncDecodingForAnimatedImages()) {
- bool isAsyncDecode = m_source.requestFrameAsyncDecodingAtIndex(nextFrame, m_currentSubsamplingLevel);
-
-#if !LOG_DISABLED
- if (isAsyncDecode)
+ if (frameHasDecodedNativeImageCompatibleWithOptionsAtIndex(nextFrame, m_currentSubsamplingLevel, { }))
+ LOG(Images, "BitmapImage::%s - %p - url: %s [cachedFrameCount = %ld nextFrame = %ld]", __FUNCTION__, this, sourceURL().string().utf8().data(), ++m_cachedFrameCount, nextFrame);
+ else {
+ m_source.requestFrameAsyncDecodingAtIndex(nextFrame, m_currentSubsamplingLevel);
+ m_currentFrameDecodingStatus = ImageFrame::DecodingStatus::Decoding;
LOG(Images, "BitmapImage::%s - %p - url: %s [requesting async decoding for nextFrame = %ld]", __FUNCTION__, this, sourceURL().string().utf8().data(), nextFrame);
- else
- LOG(Images, "BitmapImage::%s - %p - url: %s [cachedFrameCount = %ld nextFrame = %ld]", __FUNCTION__, this, sourceURL().string().utf8().data(), ++m_cachedFrameCount, nextFrame);
-#else
- UNUSED_PARAM(isAsyncDecode);
-#endif
+ }
m_desiredFrameDecodeTimeForTesting = time + std::max(m_frameDecodingDurationForTesting, 0_s);
if (m_clearDecoderAfterAsyncFrameRequestForTesting)
@@ -417,6 +420,8 @@
destroyDecodedDataIfNecessary(false);
+ if (m_currentFrameDecodingStatus == ImageFrame::DecodingStatus::Decoding)
+ m_currentFrameDecodingStatus = frameDecodingStatusAtIndex(m_currentFrame);
if (imageObserver())
imageObserver()->imageFrameAvailable(this, ImageAnimatingState::Yes);
@@ -464,10 +469,12 @@
LOG(Images, "BitmapImage::%s - %p - url: %s [earlyFrameCount = %ld nextFrame = %ld]", __FUNCTION__, this, sourceURL().string().utf8().data(), ++m_earlyFrameCount, index);
} else {
ASSERT(index == m_currentFrame && !m_currentFrame);
- imageObserver()->imageFrameAvailable(this, ImageAnimatingState::No);
-
if (m_source.isAsyncDecodingQueueIdle())
m_source.stopAsyncDecodingQueue();
+ if (m_currentFrameDecodingStatus == ImageFrame::DecodingStatus::Decoding)
+ m_currentFrameDecodingStatus = frameDecodingStatusAtIndex(m_currentFrame);
+ if (imageObserver())
+ imageObserver()->imageFrameAvailable(this, ImageAnimatingState::No);
}
}
Modified: trunk/Source/WebCore/platform/graphics/BitmapImage.h (216881 => 216882)
--- trunk/Source/WebCore/platform/graphics/BitmapImage.h 2017-05-15 22:07:54 UTC (rev 216881)
+++ trunk/Source/WebCore/platform/graphics/BitmapImage.h 2017-05-15 22:10:37 UTC (rev 216882)
@@ -86,7 +86,8 @@
IntSize sizeRespectingOrientation() const { return m_source.sizeRespectingOrientation(); }
Color singlePixelSolidColor() const override { return m_source.singlePixelSolidColor(); }
bool frameIsBeingDecodedAndIsCompatibleWithOptionsAtIndex(size_t index, const DecodingOptions& decodingOptions) const { return m_source.frameIsBeingDecodedAndIsCompatibleWithOptionsAtIndex(index, decodingOptions); }
- bool frameIsCompleteAtIndex(size_t index) const { return m_source.frameIsCompleteAtIndex(index); }
+ ImageFrame::DecodingStatus frameDecodingStatusAtIndex(size_t index) const { return m_source.frameDecodingStatusAtIndex(index); }
+ bool frameIsCompleteAtIndex(size_t index) const { return frameDecodingStatusAtIndex(index) == ImageFrame::DecodingStatus::Complete; }
bool frameHasAlphaAtIndex(size_t index) const { return m_source.frameHasAlphaAtIndex(index); }
bool frameHasFullSizeNativeImageAtIndex(size_t index, SubsamplingLevel subsamplingLevel) { return m_source.frameHasFullSizeNativeImageAtIndex(index, subsamplingLevel); }
@@ -200,6 +201,7 @@
size_t m_currentFrame { 0 }; // The index of the current frame of animation.
SubsamplingLevel m_currentSubsamplingLevel { SubsamplingLevel::Default };
+ ImageFrame::DecodingStatus m_currentFrameDecodingStatus { ImageFrame::DecodingStatus::Invalid };
std::unique_ptr<Timer> m_frameTimer;
RepetitionCount m_repetitionsComplete { RepetitionCountNone }; // How many repetitions we've finished.
MonotonicTime m_desiredFrameStartTime; // The system time at which we hope to see the next call to startAnimation().
Modified: trunk/Source/WebCore/platform/graphics/ImageFrame.cpp (216881 => 216882)
--- trunk/Source/WebCore/platform/graphics/ImageFrame.cpp 2017-05-15 22:07:54 UTC (rev 216881)
+++ trunk/Source/WebCore/platform/graphics/ImageFrame.cpp 2017-05-15 22:10:37 UTC (rev 216882)
@@ -50,7 +50,7 @@
if (this == &other)
return *this;
- m_decoding = other.m_decoding;
+ m_decodingStatus = other.m_decodingStatus;
m_size = other.m_size;
#if !USE(CG)
@@ -71,6 +71,18 @@
return *this;
}
+void ImageFrame::setDecodingStatus(DecodingStatus decodingStatus)
+{
+ ASSERT(decodingStatus != DecodingStatus::Decoding);
+ m_decodingStatus = decodingStatus;
+}
+
+ImageFrame::DecodingStatus ImageFrame::decodingStatus() const
+{
+ ASSERT(m_decodingStatus != DecodingStatus::Decoding);
+ return m_decodingStatus;
+}
+
unsigned ImageFrame::clearImage()
{
#if !USE(CG)
Modified: trunk/Source/WebCore/platform/graphics/ImageFrame.h (216881 => 216882)
--- trunk/Source/WebCore/platform/graphics/ImageFrame.h 2017-05-15 22:07:54 UTC (rev 216881)
+++ trunk/Source/WebCore/platform/graphics/ImageFrame.h 2017-05-15 22:10:37 UTC (rev 216882)
@@ -40,7 +40,7 @@
friend class ImageFrameCache;
public:
enum class Caching { Metadata, MetadataAndImage };
- enum class Decoding { None, Partial, Complete };
+ enum class DecodingStatus { Invalid, Partial, Complete, Decoding };
ImageFrame();
ImageFrame(const ImageFrame& other) { operator=(other); }
@@ -59,12 +59,12 @@
bool initialize(const IntSize&, bool premultiplyAlpha);
#endif
- void setDecoding(Decoding decoding) { m_decoding = decoding; }
- Decoding decoding() const { return m_decoding; }
+ void setDecodingStatus(DecodingStatus);
+ DecodingStatus decodingStatus() const;
- bool isEmpty() const { return m_decoding == Decoding::None; }
- bool isPartial() const { return m_decoding == Decoding::Partial; }
- bool isComplete() const { return m_decoding == Decoding::Complete; }
+ bool isInvalid() const { return m_decodingStatus == DecodingStatus::Invalid; }
+ bool isPartial() const { return m_decodingStatus == DecodingStatus::Partial; }
+ bool isComplete() const { return m_decodingStatus == DecodingStatus::Complete; }
IntSize size() const;
IntSize sizeRespectingOrientation() const { return !m_orientation.usesWidthAsHeight() ? size() : size().transposedSize(); }
@@ -101,7 +101,7 @@
Color singlePixelSolidColor() const;
private:
- Decoding m_decoding { Decoding::None };
+ DecodingStatus m_decodingStatus { DecodingStatus::Invalid };
IntSize m_size;
#if !USE(CG)
Modified: trunk/Source/WebCore/platform/graphics/ImageFrameCache.cpp (216881 => 216882)
--- trunk/Source/WebCore/platform/graphics/ImageFrameCache.cpp 2017-05-15 22:07:54 UTC (rev 216881)
+++ trunk/Source/WebCore/platform/graphics/ImageFrameCache.cpp 2017-05-15 22:10:37 UTC (rev 216882)
@@ -189,18 +189,22 @@
frame.m_nativeImage = WTFMove(nativeImage);
- frame.m_decoding = ImageFrame::Decoding::Complete;
+ frame.m_decodingStatus = ImageFrame::DecodingStatus::Complete;
frame.m_size = nativeImageSize(frame.m_nativeImage);
frame.m_hasAlpha = nativeImageHasAlpha(frame.m_nativeImage);
}
-void ImageFrameCache::cacheFrameMetadataAtIndex(size_t index, SubsamplingLevel subsamplingLevel)
+void ImageFrameCache::cacheMetadataAtIndex(size_t index, SubsamplingLevel subsamplingLevel, ImageFrame::DecodingStatus decodingStatus)
{
ASSERT(index < m_frames.size());
ImageFrame& frame = m_frames[index];
ASSERT(isDecoderAvailable());
- frame.m_decoding = m_decoder->frameIsCompleteAtIndex(index) ? ImageFrame::Decoding::Complete : ImageFrame::Decoding::Partial;
+ if (decodingStatus == ImageFrame::DecodingStatus::Invalid)
+ frame.m_decodingStatus = m_decoder->frameIsCompleteAtIndex(index) ? ImageFrame::DecodingStatus::Complete : ImageFrame::DecodingStatus::Partial;
+ else
+ frame.m_decodingStatus = decodingStatus;
+
if (frame.hasMetadata())
return;
@@ -219,7 +223,7 @@
frame.m_duration = m_decoder->frameDurationAtIndex(index);
}
-void ImageFrameCache::cacheFrameNativeImageAtIndex(NativeImagePtr&& nativeImage, size_t index, SubsamplingLevel subsamplingLevel, const DecodingOptions& decodingOptions)
+void ImageFrameCache::cacheNativeImageAtIndex(NativeImagePtr&& nativeImage, size_t index, SubsamplingLevel subsamplingLevel, const DecodingOptions& decodingOptions, ImageFrame::DecodingStatus decodingStatus)
{
ASSERT(index < m_frames.size());
ImageFrame& frame = m_frames[index];
@@ -235,22 +239,21 @@
// Move the new image to the cache.
frame.m_nativeImage = WTFMove(nativeImage);
frame.m_decodingOptions = decodingOptions;
- cacheFrameMetadataAtIndex(index, subsamplingLevel);
+ cacheMetadataAtIndex(index, subsamplingLevel, decodingStatus);
// Update the observer with the new image frame bytes.
decodedSizeIncreased(frame.frameBytes());
}
-void ImageFrameCache::cacheAsyncFrameNativeImageAtIndex(NativeImagePtr&& nativeImage, size_t index, SubsamplingLevel subsamplingLevel, const DecodingOptions& decodingOptions)
+void ImageFrameCache::cacheNativeImageAtIndexAsync(NativeImagePtr&& nativeImage, size_t index, SubsamplingLevel subsamplingLevel, const DecodingOptions& decodingOptions, ImageFrame::DecodingStatus decodingStatus)
{
if (!isDecoderAvailable())
return;
ASSERT(index < m_frames.size());
- ASSERT(!frameIsCompleteAtIndex(index) || !frameHasDecodedNativeImageCompatibleWithOptionsAtIndex(index, subsamplingLevel, decodingOptions));
// Clean the old native image and set a new one
- cacheFrameNativeImageAtIndex(WTFMove(nativeImage), index, subsamplingLevel, decodingOptions);
+ cacheNativeImageAtIndex(WTFMove(nativeImage), index, subsamplingLevel, decodingOptions, decodingStatus);
LOG(Images, "ImageFrameCache::%s - %p - url: %s [frame %ld has been cached]", __FUNCTION__, this, sourceURL().string().utf8().data(), index);
// Notify the image with the readiness of the new frame NativeImage.
@@ -297,7 +300,7 @@
if (protectedQueue.ptr() == m_decodingQueue) {
ASSERT(m_frameCommitQueue.first() == frameRequest);
m_frameCommitQueue.removeFirst();
- cacheAsyncFrameNativeImageAtIndex(WTFMove(nativeImage), frameRequest.index, frameRequest.subsamplingLevel, frameRequest.decodingOptions);
+ cacheNativeImageAtIndexAsync(WTFMove(nativeImage), frameRequest.index, frameRequest.subsamplingLevel, frameRequest.decodingOptions, frameRequest.decodingStatus);
} else
LOG(Images, "ImageFrameCache::%s - %p - url: %s [frame %ld will not cached]", __FUNCTION__, this, sourceURL().string().utf8().data(), frameRequest.index);
});
@@ -305,31 +308,18 @@
});
}
-bool ImageFrameCache::requestFrameAsyncDecodingAtIndex(size_t index, SubsamplingLevel subsamplingLevel, const std::optional<IntSize>& sizeForDrawing)
+void ImageFrameCache::requestFrameAsyncDecodingAtIndex(size_t index, SubsamplingLevel subsamplingLevel, const std::optional<IntSize>& sizeForDrawing)
{
- if (!isDecoderAvailable())
- return false;
-
- // Allow new requests for the same frame if the frame is incomplete.
- ASSERT(index < m_frames.size());
- if (frameIsCompleteAtIndex(index)) {
- // We need to coalesce multiple requests for decoding the same ImageFrame while it
- // is still being decoded. This may happen if the image rectangle is repainted
- // multiple times while the ImageFrame has not finished decoding.
- if (frameIsBeingDecodedAndIsCompatibleWithOptionsAtIndex(index, sizeForDrawing))
- return true;
-
- if (frameHasDecodedNativeImageCompatibleWithOptionsAtIndex(index, subsamplingLevel, sizeForDrawing))
- return false;
- }
-
+ ASSERT(isDecoderAvailable());
if (!hasAsyncDecodingQueue())
startAsyncDecodingQueue();
+
+ ASSERT(index < m_frames.size());
+ ImageFrame::DecodingStatus decodingStatus = m_decoder->frameIsCompleteAtIndex(index) ? ImageFrame::DecodingStatus::Complete : ImageFrame::DecodingStatus::Partial;
LOG(Images, "ImageFrameCache::%s - %p - url: %s [enqueuing frame %ld for decoding]", __FUNCTION__, this, sourceURL().string().utf8().data(), index);
- m_frameRequestQueue.enqueue({ index, subsamplingLevel, sizeForDrawing });
- m_frameCommitQueue.append({ index, subsamplingLevel, sizeForDrawing });
- return true;
+ m_frameRequestQueue.enqueue({ index, subsamplingLevel, sizeForDrawing, decodingStatus });
+ m_frameCommitQueue.append({ index, subsamplingLevel, sizeForDrawing, decodingStatus });
}
bool ImageFrameCache::isAsyncDecodingQueueIdle() const
@@ -344,7 +334,7 @@
std::for_each(m_frameCommitQueue.begin(), m_frameCommitQueue.end(), [this](const ImageFrameRequest& frameRequest) {
ImageFrame& frame = m_frames[frameRequest.index];
- if (!frame.isEmpty()) {
+ if (!frame.isInvalid()) {
LOG(Images, "ImageFrameCache::%s - %p - url: %s [decoding has been cancelled for frame %ld]", __FUNCTION__, this, sourceURL().string().utf8().data(), frameRequest.index);
frame.clear();
}
@@ -370,7 +360,7 @@
// Retrieve the metadata from ImageDecoder if the ImageFrame isn't complete.
if (frame.isComplete())
break;
- cacheFrameMetadataAtIndex(index, subsamplingLevelValue);
+ cacheMetadataAtIndex(index, subsamplingLevelValue);
break;
case ImageFrame::Caching::MetadataAndImage:
@@ -380,7 +370,7 @@
// We have to perform synchronous image decoding in this code.
NativeImagePtr nativeImage = m_decoder->createFrameImageAtIndex(index, subsamplingLevelValue);
// Clean the old native image and set a new one.
- cacheFrameNativeImageAtIndex(WTFMove(nativeImage), index, subsamplingLevelValue, DecodingMode::Synchronous);
+ cacheNativeImageAtIndex(WTFMove(nativeImage), index, subsamplingLevelValue, DecodingMode::Synchronous);
break;
}
@@ -509,9 +499,9 @@
return it != m_frameCommitQueue.end();
}
-bool ImageFrameCache::frameIsCompleteAtIndex(size_t index)
+ImageFrame::DecodingStatus ImageFrameCache::frameDecodingStatusAtIndex(size_t index)
{
- return frameMetadataAtIndex<bool>(index, (&ImageFrame::isComplete));
+ return frameMetadataAtIndex<ImageFrame::DecodingStatus>(index, (&ImageFrame::decodingStatus));
}
bool ImageFrameCache::frameHasAlphaAtIndex(size_t index)
Modified: trunk/Source/WebCore/platform/graphics/ImageFrameCache.h (216881 => 216882)
--- trunk/Source/WebCore/platform/graphics/ImageFrameCache.h 2017-05-15 22:07:54 UTC (rev 216881)
+++ trunk/Source/WebCore/platform/graphics/ImageFrameCache.h 2017-05-15 22:10:37 UTC (rev 216882)
@@ -71,7 +71,7 @@
// Asynchronous image decoding
void startAsyncDecodingQueue();
- bool requestFrameAsyncDecodingAtIndex(size_t, SubsamplingLevel, const std::optional<IntSize>&);
+ void requestFrameAsyncDecodingAtIndex(size_t, SubsamplingLevel, const std::optional<IntSize>&);
void stopAsyncDecodingQueue();
bool hasAsyncDecodingQueue() const { return m_decodingQueue; }
bool isAsyncDecodingQueueIdle() const;
@@ -94,13 +94,13 @@
// ImageFrame metadata which does not require caching the ImageFrame.
bool frameIsBeingDecodedAndIsCompatibleWithOptionsAtIndex(size_t, const DecodingOptions&);
- bool frameIsCompleteAtIndex(size_t);
+ ImageFrame::DecodingStatus frameDecodingStatusAtIndex(size_t);
bool frameHasAlphaAtIndex(size_t);
bool frameHasImageAtIndex(size_t);
bool frameHasFullSizeNativeImageAtIndex(size_t, const std::optional<SubsamplingLevel>&);
bool frameHasDecodedNativeImageCompatibleWithOptionsAtIndex(size_t, const std::optional<SubsamplingLevel>&, const DecodingOptions&);
SubsamplingLevel frameSubsamplingLevelAtIndex(size_t);
-
+
// ImageFrame metadata which forces caching or re-caching the ImageFrame.
IntSize frameSizeAtIndex(size_t, SubsamplingLevel = SubsamplingLevel::Default);
unsigned frameBytesAtIndex(size_t, SubsamplingLevel = SubsamplingLevel::Default);
@@ -132,9 +132,9 @@
void decodedSizeReset(unsigned decodedSize);
void setNativeImage(NativeImagePtr&&);
- void cacheFrameMetadataAtIndex(size_t, SubsamplingLevel);
- void cacheFrameNativeImageAtIndex(NativeImagePtr&&, size_t, SubsamplingLevel, const DecodingOptions&);
- void cacheAsyncFrameNativeImageAtIndex(NativeImagePtr&&, size_t, SubsamplingLevel, const DecodingOptions&);
+ void cacheMetadataAtIndex(size_t, SubsamplingLevel, ImageFrame::DecodingStatus = ImageFrame::DecodingStatus::Invalid);
+ void cacheNativeImageAtIndex(NativeImagePtr&&, size_t, SubsamplingLevel, const DecodingOptions&, ImageFrame::DecodingStatus = ImageFrame::DecodingStatus::Invalid);
+ void cacheNativeImageAtIndexAsync(NativeImagePtr&&, size_t, SubsamplingLevel, const DecodingOptions&, ImageFrame::DecodingStatus);
Ref<WorkQueue> decodingQueue();
@@ -152,9 +152,10 @@
size_t index;
SubsamplingLevel subsamplingLevel;
DecodingOptions decodingOptions;
+ ImageFrame::DecodingStatus decodingStatus;
bool operator==(const ImageFrameRequest& other) const
{
- return index == other.index && subsamplingLevel == other.subsamplingLevel && decodingOptions == other.decodingOptions;
+ return index == other.index && subsamplingLevel == other.subsamplingLevel && decodingOptions == other.decodingOptions && decodingStatus == other.decodingStatus;
}
};
static const int BufferSize = 8;
Modified: trunk/Source/WebCore/platform/graphics/ImageSource.cpp (216881 => 216882)
--- trunk/Source/WebCore/platform/graphics/ImageSource.cpp 2017-05-15 22:07:54 UTC (rev 216881)
+++ trunk/Source/WebCore/platform/graphics/ImageSource.cpp 2017-05-15 22:10:37 UTC (rev 216882)
@@ -113,8 +113,6 @@
EncodedDataStatus ImageSource::dataChanged(SharedBuffer* data, bool allDataReceived)
{
- m_frameCache->destroyIncompleteDecodedData();
-
#if PLATFORM(IOS)
// FIXME: We should expose a setting to enable/disable progressive loading and make this
// code conditional on it. Then we can remove the PLATFORM(IOS)-guard.
Modified: trunk/Source/WebCore/platform/graphics/ImageSource.h (216881 => 216882)
--- trunk/Source/WebCore/platform/graphics/ImageSource.h 2017-05-15 22:07:54 UTC (rev 216881)
+++ trunk/Source/WebCore/platform/graphics/ImageSource.h 2017-05-15 22:10:37 UTC (rev 216882)
@@ -57,6 +57,7 @@
void destroyAllDecodedData() { m_frameCache->destroyAllDecodedData(); }
void destroyAllDecodedDataExcludeFrame(size_t excludeFrame) { m_frameCache->destroyAllDecodedDataExcludeFrame(excludeFrame); }
void destroyDecodedDataBeforeFrame(size_t beforeFrame) { m_frameCache->destroyDecodedDataBeforeFrame(beforeFrame); }
+ void destroyIncompleteDecodedData() { m_frameCache->destroyIncompleteDecodedData(); }
void clearFrameBufferCache(size_t);
void clear(SharedBuffer* data);
@@ -70,7 +71,7 @@
bool isAllDataReceived();
bool shouldUseAsyncDecoding();
- bool requestFrameAsyncDecodingAtIndex(size_t index, SubsamplingLevel subsamplingLevel, const std::optional<IntSize>& sizeForDrawing = { }) { return m_frameCache->requestFrameAsyncDecodingAtIndex(index, subsamplingLevel, sizeForDrawing); }
+ void requestFrameAsyncDecodingAtIndex(size_t index, SubsamplingLevel subsamplingLevel, const std::optional<IntSize>& sizeForDrawing = { }) { m_frameCache->requestFrameAsyncDecodingAtIndex(index, subsamplingLevel, sizeForDrawing); }
bool hasAsyncDecodingQueue() const { return m_frameCache->hasAsyncDecodingQueue(); }
bool isAsyncDecodingQueueIdle() const { return m_frameCache->isAsyncDecodingQueueIdle(); }
void stopAsyncDecodingQueue() { m_frameCache->stopAsyncDecodingQueue(); }
@@ -90,7 +91,7 @@
// ImageFrame metadata which does not require caching the ImageFrame.
bool frameIsBeingDecodedAndIsCompatibleWithOptionsAtIndex(size_t index, const DecodingOptions& decodingOptions) { return m_frameCache->frameIsBeingDecodedAndIsCompatibleWithOptionsAtIndex(index, decodingOptions); }
- bool frameIsCompleteAtIndex(size_t index) { return m_frameCache->frameIsCompleteAtIndex(index); }
+ ImageFrame::DecodingStatus frameDecodingStatusAtIndex(size_t index) { return m_frameCache->frameDecodingStatusAtIndex(index); }
bool frameHasAlphaAtIndex(size_t index) { return m_frameCache->frameHasAlphaAtIndex(index); }
bool frameHasImageAtIndex(size_t index) { return m_frameCache->frameHasImageAtIndex(index); }
bool frameHasFullSizeNativeImageAtIndex(size_t index, const std::optional<SubsamplingLevel>& subsamplingLevel) { return m_frameCache->frameHasFullSizeNativeImageAtIndex(index, subsamplingLevel); }
Modified: trunk/Source/WebCore/platform/image-decoders/ImageDecoder.cpp (216881 => 216882)
--- trunk/Source/WebCore/platform/image-decoders/ImageDecoder.cpp 2017-05-15 22:07:54 UTC (rev 216881)
+++ trunk/Source/WebCore/platform/image-decoders/ImageDecoder.cpp 2017-05-15 22:10:37 UTC (rev 216882)
@@ -196,7 +196,7 @@
float ImageDecoder::frameDurationAtIndex(size_t index)
{
ImageFrame* buffer = frameBufferAtIndex(index);
- if (!buffer || buffer->isEmpty())
+ if (!buffer || buffer->isInvalid())
return 0;
// Many annoying ads specify a 0 duration to make an image flash as quickly as possible.
@@ -216,7 +216,7 @@
return nullptr;
ImageFrame* buffer = frameBufferAtIndex(index);
- if (!buffer || buffer->isEmpty() || !buffer->hasBackingStore())
+ if (!buffer || buffer->isInvalid() || !buffer->hasBackingStore())
return nullptr;
// Return the buffer contents as a native image. For some ports, the data
Modified: trunk/Source/WebCore/platform/image-decoders/bmp/BMPImageReader.cpp (216881 => 216882)
--- trunk/Source/WebCore/platform/image-decoders/bmp/BMPImageReader.cpp 2017-05-15 22:07:54 UTC (rev 216881)
+++ trunk/Source/WebCore/platform/image-decoders/bmp/BMPImageReader.cpp 2017-05-15 22:10:37 UTC (rev 216882)
@@ -77,11 +77,11 @@
// Initialize the framebuffer if needed.
ASSERT(m_buffer); // Parent should set this before asking us to decode!
- if (m_buffer->isEmpty()) {
+ if (m_buffer->isInvalid()) {
if (!m_buffer->initialize(m_parent->size(), m_parent->premultiplyAlpha()))
return m_parent->setFailed(); // Unable to allocate.
- m_buffer->setDecoding(ImageFrame::Decoding::Partial);
+ m_buffer->setDecodingStatus(ImageFrame::DecodingStatus::Partial);
m_buffer->setHasAlpha(false);
if (!m_isTopDown)
@@ -117,7 +117,7 @@
}
// Done!
- m_buffer->setDecoding(ImageFrame::Decoding::Complete);
+ m_buffer->setDecodingStatus(ImageFrame::DecodingStatus::Complete);
return true;
}
Modified: trunk/Source/WebCore/platform/image-decoders/gif/GIFImageDecoder.cpp (216881 => 216882)
--- trunk/Source/WebCore/platform/image-decoders/gif/GIFImageDecoder.cpp 2017-05-15 22:07:54 UTC (rev 216881)
+++ trunk/Source/WebCore/platform/image-decoders/gif/GIFImageDecoder.cpp 2017-05-15 22:10:37 UTC (rev 216882)
@@ -159,7 +159,7 @@
// has a disposal method other than DisposalMethod::RestoreToPrevious, stop
// scanning, as we'll only need this frame when decoding the next one.
Vector<ImageFrame>::iterator i(end);
- for (; (i != m_frameBufferCache.begin()) && (i->isEmpty() || (i->disposalMethod() == ImageFrame::DisposalMethod::RestoreToPrevious)); --i) {
+ for (; (i != m_frameBufferCache.begin()) && (i->isInvalid() || (i->disposalMethod() == ImageFrame::DisposalMethod::RestoreToPrevious)); --i) {
if (i->isComplete() && (i != end))
i->clear();
}
@@ -167,7 +167,7 @@
// Now |i| holds the last frame we need to preserve; clear prior frames.
for (Vector<ImageFrame>::iterator j(m_frameBufferCache.begin()); j != i; ++j) {
ASSERT(!j->isPartial());
- if (j->isEmpty())
+ if (j->isInvalid())
j->clear();
}
@@ -207,7 +207,7 @@
// Initialize the frame if necessary.
ImageFrame& buffer = m_frameBufferCache[frameIndex];
- if ((buffer.isEmpty() && !initFrameBuffer(frameIndex)) || !buffer.hasBackingStore())
+ if ((buffer.isInvalid() && !initFrameBuffer(frameIndex)) || !buffer.hasBackingStore())
return false;
RGBA32* currentAddress = buffer.backingStore()->pixelAt(xBegin, yBegin);
@@ -244,10 +244,10 @@
// Initialize the frame if necessary. Some GIFs insert do-nothing frames,
// in which case we never reach haveDecodedRow() before getting here.
ImageFrame& buffer = m_frameBufferCache[frameIndex];
- if (buffer.isEmpty() && !initFrameBuffer(frameIndex))
+ if (buffer.isInvalid() && !initFrameBuffer(frameIndex))
return false; // initFrameBuffer() has already called setFailed().
- buffer.setDecoding(ImageFrame::Decoding::Complete);
+ buffer.setDecodingStatus(ImageFrame::DecodingStatus::Complete);
buffer.setDuration(frameDuration);
buffer.setDisposalMethod(disposalMethod);
@@ -401,7 +401,7 @@
buffer->backingStore()->setFrameRect(IntRect(left, top, right - left, bottom - top));
// Update our status to be partially complete.
- buffer->setDecoding(ImageFrame::Decoding::Partial);
+ buffer->setDecodingStatus(ImageFrame::DecodingStatus::Partial);
// Reset the alpha pixel tracker for this frame.
m_currentBufferSawAlpha = false;
Modified: trunk/Source/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.cpp (216881 => 216882)
--- trunk/Source/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.cpp 2017-05-15 22:07:54 UTC (rev 216881)
+++ trunk/Source/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.cpp 2017-05-15 22:10:37 UTC (rev 216882)
@@ -605,10 +605,10 @@
// Initialize the framebuffer if needed.
ImageFrame& buffer = m_frameBufferCache[0];
- if (buffer.isEmpty()) {
+ if (buffer.isInvalid()) {
if (!buffer.initialize(scaledSize(), m_premultiplyAlpha))
return setFailed();
- buffer.setDecoding(ImageFrame::Decoding::Partial);
+ buffer.setDecodingStatus(ImageFrame::DecodingStatus::Partial);
// The buffer is transparent outside the decoded area while the image is
// loading. The completed image will be marked fully opaque in jpegComplete().
buffer.setHasAlpha(true);
@@ -652,7 +652,7 @@
// empty.
ImageFrame& buffer = m_frameBufferCache[0];
buffer.setHasAlpha(false);
- buffer.setDecoding(ImageFrame::Decoding::Complete);
+ buffer.setDecodingStatus(ImageFrame::DecodingStatus::Complete);
}
void JPEGImageDecoder::decode(bool onlySize, bool allDataReceived)
Modified: trunk/Source/WebCore/platform/image-decoders/png/PNGImageDecoder.cpp (216881 => 216882)
--- trunk/Source/WebCore/platform/image-decoders/png/PNGImageDecoder.cpp 2017-05-15 22:07:54 UTC (rev 216881)
+++ trunk/Source/WebCore/platform/image-decoders/png/PNGImageDecoder.cpp 2017-05-15 22:10:37 UTC (rev 216882)
@@ -430,7 +430,7 @@
return;
#endif
ImageFrame& buffer = m_frameBufferCache[m_currentFrame];
- if (buffer.isEmpty()) {
+ if (buffer.isInvalid()) {
png_structp png = m_reader->pngPtr();
if (!buffer.initialize(scaledSize(), m_premultiplyAlpha)) {
longjmp(JMPBUF(png), 1);
@@ -448,7 +448,7 @@
}
}
- buffer.setDecoding(ImageFrame::Decoding::Partial);
+ buffer.setDecodingStatus(ImageFrame::DecodingStatus::Partial);
buffer.setHasAlpha(false);
#if ENABLE(APNG)
@@ -556,7 +556,7 @@
}
#endif
if (!m_frameBufferCache.isEmpty())
- m_frameBufferCache.first().setDecoding(ImageFrame::Decoding::Complete);
+ m_frameBufferCache.first().setDecodingStatus(ImageFrame::DecodingStatus::Complete);
}
void PNGImageDecoder::decode(bool onlySize, unsigned haltAtFrame, bool allDataReceived)
@@ -740,7 +740,7 @@
const Vector<ImageFrame>::iterator end(m_frameBufferCache.begin() + clearBeforeFrame);
Vector<ImageFrame>::iterator i(end);
- for (; (i != m_frameBufferCache.begin()) && (i->isEmpty() || (i->disposalMethod() == ImageFrame::DisposalMethod::RestoreToPrevious)); --i) {
+ for (; (i != m_frameBufferCache.begin()) && (i->isInvalid() || (i->disposalMethod() == ImageFrame::DisposalMethod::RestoreToPrevious)); --i) {
if (i->isComplete() && (i != end))
i->clear();
}
@@ -748,7 +748,7 @@
// Now |i| holds the last frame we need to preserve; clear prior frames.
for (Vector<ImageFrame>::iterator j(m_frameBufferCache.begin()); j != i; ++j) {
ASSERT(!j->isPartial());
- if (j->isEmpty())
+ if (j->isInvalid())
j->clear();
}
}
@@ -823,7 +823,7 @@
return;
ImageFrame& buffer = m_frameBufferCache[m_currentFrame];
- buffer.setDecoding(ImageFrame::Decoding::Complete);
+ buffer.setDecodingStatus(ImageFrame::DecodingStatus::Complete);
png_bytep interlaceBuffer = m_reader->interlaceBuffer();
Modified: trunk/Source/WebCore/platform/image-decoders/webp/WEBPImageDecoder.cpp (216881 => 216882)
--- trunk/Source/WebCore/platform/image-decoders/webp/WEBPImageDecoder.cpp 2017-05-15 22:07:54 UTC (rev 216881)
+++ trunk/Source/WebCore/platform/image-decoders/webp/WEBPImageDecoder.cpp 2017-05-15 22:10:37 UTC (rev 216882)
@@ -116,10 +116,10 @@
ImageFrame& buffer = m_frameBufferCache[0];
ASSERT(!buffer.isComplete());
- if (buffer.isEmpty()) {
+ if (buffer.isInvalid()) {
if (!buffer.initialize(size(), m_premultiplyAlpha))
return setFailed();
- buffer.setDecoding(ImageFrame::Decoding::Partial);
+ buffer.setDecodingStatus(ImageFrame::DecodingStatus::Partial);
buffer.setHasAlpha(m_hasAlpha);
}
@@ -137,7 +137,7 @@
switch (WebPIUpdate(m_decoder, dataBytes, dataSize)) {
case VP8_STATUS_OK:
- buffer.setDecoding(ImageFrame::Decoding::Complete);
+ buffer.setDecodingStatus(ImageFrame::DecodingStatus::Complete);
clear();
return true;
case VP8_STATUS_SUSPENDED: