https://bugs.webkit.org/show_bug.cgi?id=174230
Patch by Said Abou-Hallawa <sabouhallawa@apple.com> on 2017-07-22
Reviewed by Simon Fraser.
Because of r219045, we now only repaint the CachedImageClinets which tried
to draw the image but they could not because they have to wait for the image
decoding to finish. This was done by keeping a HashSet of these clients
and make CachedImage own it. This HashSet is cleared once the image frame
finishes decoding and all the waited clients are repainted.
But Multiple asynchronous image decoding requests are allowed for the same
frame if new data is added to the image source. If we tried to draw the
same image twice before it finishes decoding the first request, we will
not be to record this second request since the HashSet will not add the
same client twice. When he second request finishes decoding, CachedImage
will not repaint any client since its HashSet is empty.
To fix this problem we can do the following. When an image frame finishes
decoding, CachedImage will keep its HashSet of pending drawing clients as
long as the image frame is a partially loaded frame.
* loader/cache/CachedImage.cpp:
(WebCore::CachedImage::CachedImageObserver::imageFrameAvailable):
(WebCore::CachedImage::imageFrameAvailable):
* loader/cache/CachedImage.h:
* platform/graphics/BitmapImage.cpp:
(WebCore::BitmapImage::destroyDecodedData):
(WebCore::BitmapImage::dataChanged):
(WebCore::BitmapImage::setCurrentFrameDecodingStatusIfNecessary):
(WebCore::BitmapImage::draw):
(WebCore::BitmapImage::internalStartAnimation):
(WebCore::BitmapImage::internalAdvanceAnimation):
(WebCore::BitmapImage::imageFrameAvailableAtIndex):
* platform/graphics/BitmapImage.h:
* platform/graphics/ImageFrame.cpp:
(WebCore::ImageFrame::decodingStatus):
* platform/graphics/ImageFrame.h: Move DecodingStatus out of this class
to ImageTypes.h to avoid adding other header files to ImageObvsever.h
* platform/graphics/ImageFrameCache.cpp:
(WebCore::ImageFrameCache::setNativeImage):
(WebCore::ImageFrameCache::cacheMetadataAtIndex):
(WebCore::ImageFrameCache::cacheNativeImageAtIndex):
(WebCore::ImageFrameCache::cacheNativeImageAtIndexAsync):
(WebCore::ImageFrameCache::requestFrameAsyncDecodingAtIndex):
(WebCore::ImageFrameCache::frameDecodingStatusAtIndex):
* platform/graphics/ImageFrameCache.h:
* platform/graphics/ImageObserver.h:
* platform/graphics/ImageSource.h:
(WebCore::ImageSource::frameDecodingStatusAtIndex):
* platform/graphics/ImageTypes.h:
* platform/image-decoders/bmp/BMPImageReader.cpp:
(WebCore::BMPImageReader::decodeBMP):
* platform/image-decoders/gif/GIFImageDecoder.cpp:
(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::frameComplete):
* platform/image-decoders/webp/WEBPImageDecoder.cpp:
(WebCore::WEBPImageDecoder::decode):
* rendering/RenderBoxModelObject.cpp:
(WebCore::RenderBoxModelObject::decodingModeForImageDraw):
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@219762
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2017-07-22 Said Abou-Hallawa <sabouhallawa@apple.com>
+
+ REGRESSION(r219045): A partially loaded image may not be repainted when its complete frame finishes decoding
+ https://bugs.webkit.org/show_bug.cgi?id=174230
+
+ Reviewed by Simon Fraser.
+
+ Because of r219045, we now only repaint the CachedImageClinets which tried
+ to draw the image but they could not because they have to wait for the image
+ decoding to finish. This was done by keeping a HashSet of these clients
+ and make CachedImage own it. This HashSet is cleared once the image frame
+ finishes decoding and all the waited clients are repainted.
+
+ But Multiple asynchronous image decoding requests are allowed for the same
+ frame if new data is added to the image source. If we tried to draw the
+ same image twice before it finishes decoding the first request, we will
+ not be to record this second request since the HashSet will not add the
+ same client twice. When he second request finishes decoding, CachedImage
+ will not repaint any client since its HashSet is empty.
+
+ To fix this problem we can do the following. When an image frame finishes
+ decoding, CachedImage will keep its HashSet of pending drawing clients as
+ long as the image frame is a partially loaded frame.
+
+ * loader/cache/CachedImage.cpp:
+ (WebCore::CachedImage::CachedImageObserver::imageFrameAvailable):
+ (WebCore::CachedImage::imageFrameAvailable):
+ * loader/cache/CachedImage.h:
+ * platform/graphics/BitmapImage.cpp:
+ (WebCore::BitmapImage::destroyDecodedData):
+ (WebCore::BitmapImage::dataChanged):
+ (WebCore::BitmapImage::setCurrentFrameDecodingStatusIfNecessary):
+ (WebCore::BitmapImage::draw):
+ (WebCore::BitmapImage::internalStartAnimation):
+ (WebCore::BitmapImage::internalAdvanceAnimation):
+ (WebCore::BitmapImage::imageFrameAvailableAtIndex):
+ * platform/graphics/BitmapImage.h:
+ * platform/graphics/ImageFrame.cpp:
+ (WebCore::ImageFrame::decodingStatus):
+ * platform/graphics/ImageFrame.h: Move DecodingStatus out of this class
+ to ImageTypes.h to avoid adding other header files to ImageObvsever.h
+ * platform/graphics/ImageFrameCache.cpp:
+ (WebCore::ImageFrameCache::setNativeImage):
+ (WebCore::ImageFrameCache::cacheMetadataAtIndex):
+ (WebCore::ImageFrameCache::cacheNativeImageAtIndex):
+ (WebCore::ImageFrameCache::cacheNativeImageAtIndexAsync):
+ (WebCore::ImageFrameCache::requestFrameAsyncDecodingAtIndex):
+ (WebCore::ImageFrameCache::frameDecodingStatusAtIndex):
+ * platform/graphics/ImageFrameCache.h:
+ * platform/graphics/ImageObserver.h:
+ * platform/graphics/ImageSource.h:
+ (WebCore::ImageSource::frameDecodingStatusAtIndex):
+ * platform/graphics/ImageTypes.h:
+ * platform/image-decoders/bmp/BMPImageReader.cpp:
+ (WebCore::BMPImageReader::decodeBMP):
+ * platform/image-decoders/gif/GIFImageDecoder.cpp:
+ (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::frameComplete):
+ * platform/image-decoders/webp/WEBPImageDecoder.cpp:
+ (WebCore::WEBPImageDecoder::decode):
+ * rendering/RenderBoxModelObject.cpp:
+ (WebCore::RenderBoxModelObject::decodingModeForImageDraw):
+
2017-07-22 Timothy Horton <timothy_horton@apple.com>
Drag and Drop preview image for Twitter link is the wrong shape
return true;
}
-void CachedImage::CachedImageObserver::imageFrameAvailable(const Image& image, ImageAnimatingState animatingState, const IntRect* changeRect)
+void CachedImage::CachedImageObserver::imageFrameAvailable(const Image& image, ImageAnimatingState animatingState, const IntRect* changeRect, DecodingStatus decodingStatus)
{
for (auto cachedImage : m_cachedImages)
- cachedImage->imageFrameAvailable(image, animatingState, changeRect);
+ cachedImage->imageFrameAvailable(image, animatingState, changeRect, decodingStatus);
}
void CachedImage::CachedImageObserver::changedInRect(const Image& image, const IntRect* rect)
return true;
}
-void CachedImage::imageFrameAvailable(const Image& image, ImageAnimatingState animatingState, const IntRect* changeRect)
+void CachedImage::imageFrameAvailable(const Image& image, ImageAnimatingState animatingState, const IntRect* changeRect, DecodingStatus decodingStatus)
{
if (&image != m_image)
return;
if (visibleState == VisibleInViewportState::No && animatingState == ImageAnimatingState::Yes)
m_image->stopAnimation();
- m_pendingImageDrawingClients.clear();
+ if (decodingStatus != DecodingStatus::Partial)
+ m_pendingImageDrawingClients.clear();
}
void CachedImage::changedInRect(const Image& image, const IntRect* rect)
void didDraw(const Image&) final;
bool canDestroyDecodedData(const Image&) final;
- void imageFrameAvailable(const Image&, ImageAnimatingState, const IntRect* changeRect = nullptr) final;
+ void imageFrameAvailable(const Image&, ImageAnimatingState, const IntRect* changeRect = nullptr, DecodingStatus = DecodingStatus::Invalid) final;
void changedInRect(const Image&, const IntRect*) final;
HashSet<CachedImage*> m_cachedImages;
void decodedSizeChanged(const Image&, long long delta);
void didDraw(const Image&);
bool canDestroyDecodedData(const Image&);
- void imageFrameAvailable(const Image&, ImageAnimatingState, const IntRect* changeRect = nullptr);
+ void imageFrameAvailable(const Image&, ImageAnimatingState, const IntRect* changeRect = nullptr, DecodingStatus = DecodingStatus::Invalid);
void changedInRect(const Image&, const IntRect*);
void addIncrementalDataBuffer(SharedBuffer&);
m_source.destroyAllDecodedDataExcludeFrame(m_currentFrame);
else {
m_source.destroyAllDecodedData();
- m_currentFrameDecodingStatus = ImageFrame::DecodingStatus::Invalid;
+ m_currentFrameDecodingStatus = DecodingStatus::Invalid;
}
// There's no need to throw away the decoder unless we're explicitly asked
if (m_source.decodedSize() && !canUseAsyncDecodingForLargeImages())
m_source.destroyIncompleteDecodedData();
- m_currentFrameDecodingStatus = ImageFrame::DecodingStatus::Invalid;
+ m_currentFrameDecodingStatus = DecodingStatus::Invalid;
return m_source.dataChanged(data(), allDataReceived);
}
+
+void BitmapImage::setCurrentFrameDecodingStatusIfNecessary(DecodingStatus decodingStatus)
+{
+ // When new data is received, m_currentFrameDecodingStatus is set to DecodingStatus::Invalid
+ // to force decoding the frame when it's drawn. m_currentFrameDecodingStatus should not be
+ // changed in this case till draw() is called and sets its value to DecodingStatus::Decoding.
+ if (m_currentFrameDecodingStatus != DecodingStatus::Decoding)
+ return;
+ m_currentFrameDecodingStatus = decodingStatus;
+}
NativeImagePtr BitmapImage::frameImageAtIndexCacheIfNeeded(size_t index, SubsamplingLevel subsamplingLevel, const GraphicsContext* targetContext)
{
// 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) || m_currentFrameDecodingStatus == ImageFrame::DecodingStatus::Invalid) {
+ if ((!frameIsCompatible && !frameIsBeingDecoded) || m_currentFrameDecodingStatus == DecodingStatus::Invalid) {
LOG(Images, "BitmapImage::%s - %p - url: %s [requesting large async decoding]", __FUNCTION__, this, sourceURL().string().utf8().data());
m_source.requestFrameAsyncDecodingAtIndex(m_currentFrame, m_currentSubsamplingLevel, sizeForDrawing);
- m_currentFrameDecodingStatus = ImageFrame::DecodingStatus::Decoding;
+ m_currentFrameDecodingStatus = DecodingStatus::Decoding;
}
- if (m_currentFrameDecodingStatus == ImageFrame::DecodingStatus::Decoding)
+ if (m_currentFrameDecodingStatus == DecodingStatus::Decoding)
result = ImageDrawResult::DidRequestDecoding;
if (!frameHasDecodedNativeImageCompatibleWithOptionsAtIndex(m_currentFrame, m_currentSubsamplingLevel, DecodingMode::Asynchronous)) {
if (!image) // If it's too early we won't have an image yet.
return ImageDrawResult::DidNothing;
- if (m_currentFrameDecodingStatus != ImageFrame::DecodingStatus::Complete)
+ if (m_currentFrameDecodingStatus != DecodingStatus::Complete)
++m_decodeCountForTesting;
}
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;
+ m_currentFrameDecodingStatus = DecodingStatus::Decoding;
LOG(Images, "BitmapImage::%s - %p - url: %s [requesting async decoding for nextFrame = %ld]", __FUNCTION__, this, sourceURL().string().utf8().data(), nextFrame);
}
destroyDecodedDataIfNecessary(false);
- if (m_currentFrameDecodingStatus == ImageFrame::DecodingStatus::Decoding)
- m_currentFrameDecodingStatus = frameDecodingStatusAtIndex(m_currentFrame);
+ DecodingStatus decodingStatus = frameDecodingStatusAtIndex(m_currentFrame);
+ setCurrentFrameDecodingStatusIfNecessary(decodingStatus);
+
if (imageObserver())
- imageObserver()->imageFrameAvailable(*this, ImageAnimatingState::Yes);
+ imageObserver()->imageFrameAvailable(*this, ImageAnimatingState::Yes, nullptr, decodingStatus);
LOG(Images, "BitmapImage::%s - %p - url: %s [m_currentFrame = %ld]", __FUNCTION__, this, sourceURL().string().utf8().data(), m_currentFrame);
}
ASSERT(index == m_currentFrame && !m_currentFrame);
if (m_source.isAsyncDecodingQueueIdle())
m_source.stopAsyncDecodingQueue();
- if (m_currentFrameDecodingStatus == ImageFrame::DecodingStatus::Decoding)
- m_currentFrameDecodingStatus = frameDecodingStatusAtIndex(m_currentFrame);
- if (m_currentFrameDecodingStatus == ImageFrame::DecodingStatus::Complete)
+ DecodingStatus decodingStatus = frameDecodingStatusAtIndex(m_currentFrame);
+ setCurrentFrameDecodingStatusIfNecessary(decodingStatus);
+
+ if (m_currentFrameDecodingStatus == DecodingStatus::Complete)
++m_decodeCountForTesting;
if (imageObserver())
- imageObserver()->imageFrameAvailable(*this, ImageAnimatingState::No);
+ imageObserver()->imageFrameAvailable(*this, ImageAnimatingState::No, nullptr, decodingStatus);
}
unsigned BitmapImage::decodeCountForTesting() const
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); }
- ImageFrame::DecodingStatus frameDecodingStatusAtIndex(size_t index) const { return m_source.frameDecodingStatusAtIndex(index); }
- bool frameIsCompleteAtIndex(size_t index) const { return frameDecodingStatusAtIndex(index) == ImageFrame::DecodingStatus::Complete; }
+ DecodingStatus frameDecodingStatusAtIndex(size_t index) const { return m_source.frameDecodingStatusAtIndex(index); }
+ bool frameIsCompleteAtIndex(size_t index) const { return frameDecodingStatusAtIndex(index) == 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); }
void clearTimer();
void startTimer(Seconds delay);
bool canDestroyDecodedData();
+ void setCurrentFrameDecodingStatusIfNecessary(DecodingStatus);
bool isBitmapImage() const override { return true; }
void dump(TextStream&) const override;
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 };
+ DecodingStatus m_currentFrameDecodingStatus { 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().
m_decodingStatus = decodingStatus;
}
-ImageFrame::DecodingStatus ImageFrame::decodingStatus() const
+DecodingStatus ImageFrame::decodingStatus() const
{
ASSERT(m_decodingStatus != DecodingStatus::Decoding);
return m_decodingStatus;
friend class ImageFrameCache;
public:
enum class Caching { Metadata, MetadataAndImage };
- enum class DecodingStatus { Invalid, Partial, Complete, Decoding };
ImageFrame();
ImageFrame(const ImageFrame& other) { operator=(other); }
frame.m_nativeImage = WTFMove(nativeImage);
- frame.m_decodingStatus = ImageFrame::DecodingStatus::Complete;
+ frame.m_decodingStatus = DecodingStatus::Complete;
frame.m_size = nativeImageSize(frame.m_nativeImage);
frame.m_hasAlpha = nativeImageHasAlpha(frame.m_nativeImage);
}
-void ImageFrameCache::cacheMetadataAtIndex(size_t index, SubsamplingLevel subsamplingLevel, ImageFrame::DecodingStatus decodingStatus)
+void ImageFrameCache::cacheMetadataAtIndex(size_t index, SubsamplingLevel subsamplingLevel, DecodingStatus decodingStatus)
{
ASSERT(index < m_frames.size());
ImageFrame& frame = m_frames[index];
ASSERT(isDecoderAvailable());
- if (decodingStatus == ImageFrame::DecodingStatus::Invalid)
- frame.m_decodingStatus = m_decoder->frameIsCompleteAtIndex(index) ? ImageFrame::DecodingStatus::Complete : ImageFrame::DecodingStatus::Partial;
+ if (decodingStatus == DecodingStatus::Invalid)
+ frame.m_decodingStatus = m_decoder->frameIsCompleteAtIndex(index) ? DecodingStatus::Complete : DecodingStatus::Partial;
else
frame.m_decodingStatus = decodingStatus;
frame.m_duration = m_decoder->frameDurationAtIndex(index);
}
-void ImageFrameCache::cacheNativeImageAtIndex(NativeImagePtr&& nativeImage, size_t index, SubsamplingLevel subsamplingLevel, const DecodingOptions& decodingOptions, ImageFrame::DecodingStatus decodingStatus)
+void ImageFrameCache::cacheNativeImageAtIndex(NativeImagePtr&& nativeImage, size_t index, SubsamplingLevel subsamplingLevel, const DecodingOptions& decodingOptions, DecodingStatus decodingStatus)
{
ASSERT(index < m_frames.size());
ImageFrame& frame = m_frames[index];
decodedSizeIncreased(frame.frameBytes());
}
-void ImageFrameCache::cacheNativeImageAtIndexAsync(NativeImagePtr&& nativeImage, size_t index, SubsamplingLevel subsamplingLevel, const DecodingOptions& decodingOptions, ImageFrame::DecodingStatus decodingStatus)
+void ImageFrameCache::cacheNativeImageAtIndexAsync(NativeImagePtr&& nativeImage, size_t index, SubsamplingLevel subsamplingLevel, const DecodingOptions& decodingOptions, DecodingStatus decodingStatus)
{
if (!isDecoderAvailable())
return;
startAsyncDecodingQueue();
ASSERT(index < m_frames.size());
- ImageFrame::DecodingStatus decodingStatus = m_decoder->frameIsCompleteAtIndex(index) ? ImageFrame::DecodingStatus::Complete : ImageFrame::DecodingStatus::Partial;
+ DecodingStatus decodingStatus = m_decoder->frameIsCompleteAtIndex(index) ? DecodingStatus::Complete : 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, decodingStatus });
return it != m_frameCommitQueue.end();
}
-ImageFrame::DecodingStatus ImageFrameCache::frameDecodingStatusAtIndex(size_t index)
+DecodingStatus ImageFrameCache::frameDecodingStatusAtIndex(size_t index)
{
- return frameMetadataAtIndex<ImageFrame::DecodingStatus>(index, (&ImageFrame::decodingStatus));
+ return frameMetadataAtIndex<DecodingStatus>(index, (&ImageFrame::decodingStatus));
}
bool ImageFrameCache::frameHasAlphaAtIndex(size_t index)
// ImageFrame metadata which does not require caching the ImageFrame.
bool frameIsBeingDecodedAndIsCompatibleWithOptionsAtIndex(size_t, const DecodingOptions&);
- ImageFrame::DecodingStatus frameDecodingStatusAtIndex(size_t);
+ DecodingStatus frameDecodingStatusAtIndex(size_t);
bool frameHasAlphaAtIndex(size_t);
bool frameHasImageAtIndex(size_t);
bool frameHasFullSizeNativeImageAtIndex(size_t, const std::optional<SubsamplingLevel>&);
void decodedSizeReset(unsigned decodedSize);
void setNativeImage(NativeImagePtr&&);
- 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);
+ void cacheMetadataAtIndex(size_t, SubsamplingLevel, DecodingStatus = DecodingStatus::Invalid);
+ void cacheNativeImageAtIndex(NativeImagePtr&&, size_t, SubsamplingLevel, const DecodingOptions&, DecodingStatus = DecodingStatus::Invalid);
+ void cacheNativeImageAtIndexAsync(NativeImagePtr&&, size_t, SubsamplingLevel, const DecodingOptions&, DecodingStatus);
Ref<WorkQueue> decodingQueue();
size_t index;
SubsamplingLevel subsamplingLevel;
DecodingOptions decodingOptions;
- ImageFrame::DecodingStatus decodingStatus;
+ DecodingStatus decodingStatus;
bool operator==(const ImageFrameRequest& other) const
{
return index == other.index && subsamplingLevel == other.subsamplingLevel && decodingOptions == other.decodingOptions && decodingStatus == other.decodingStatus;
virtual void didDraw(const Image&) = 0;
virtual bool canDestroyDecodedData(const Image&) = 0;
- virtual void imageFrameAvailable(const Image&, ImageAnimatingState, const IntRect* changeRect = nullptr) = 0;
+ virtual void imageFrameAvailable(const Image&, ImageAnimatingState, const IntRect* changeRect = nullptr, DecodingStatus = DecodingStatus::Invalid) = 0;
virtual void changedInRect(const Image&, const IntRect* changeRect = nullptr) = 0;
};
// ImageFrame metadata which does not require caching the ImageFrame.
bool frameIsBeingDecodedAndIsCompatibleWithOptionsAtIndex(size_t index, const DecodingOptions& decodingOptions) { return m_frameCache->frameIsBeingDecodedAndIsCompatibleWithOptionsAtIndex(index, decodingOptions); }
- ImageFrame::DecodingStatus frameDecodingStatusAtIndex(size_t index) { return m_frameCache->frameDecodingStatusAtIndex(index); }
+ 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); }
Complete
};
+enum class DecodingStatus {
+ Invalid,
+ Partial,
+ Complete,
+ Decoding
+};
+
enum class ImageDrawResult {
DidNothing,
DidRequestDecoding,
if (!m_buffer->initialize(m_parent->size(), m_parent->premultiplyAlpha()))
return m_parent->setFailed(); // Unable to allocate.
- m_buffer->setDecodingStatus(ImageFrame::DecodingStatus::Partial);
+ m_buffer->setDecodingStatus(DecodingStatus::Partial);
m_buffer->setHasAlpha(false);
if (!m_isTopDown)
}
// Done!
- m_buffer->setDecodingStatus(ImageFrame::DecodingStatus::Complete);
+ m_buffer->setDecodingStatus(DecodingStatus::Complete);
return true;
}
if (buffer.isInvalid() && !initFrameBuffer(frameIndex))
return false; // initFrameBuffer() has already called setFailed().
- buffer.setDecodingStatus(ImageFrame::DecodingStatus::Complete);
+ buffer.setDecodingStatus(DecodingStatus::Complete);
buffer.setDuration(frameDuration);
buffer.setDisposalMethod(disposalMethod);
buffer->backingStore()->setFrameRect(IntRect(left, top, right - left, bottom - top));
// Update our status to be partially complete.
- buffer->setDecodingStatus(ImageFrame::DecodingStatus::Partial);
+ buffer->setDecodingStatus(DecodingStatus::Partial);
// Reset the alpha pixel tracker for this frame.
m_currentBufferSawAlpha = false;
if (buffer.isInvalid()) {
if (!buffer.initialize(scaledSize(), m_premultiplyAlpha))
return setFailed();
- buffer.setDecodingStatus(ImageFrame::DecodingStatus::Partial);
+ buffer.setDecodingStatus(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);
// empty.
ImageFrame& buffer = m_frameBufferCache[0];
buffer.setHasAlpha(false);
- buffer.setDecodingStatus(ImageFrame::DecodingStatus::Complete);
+ buffer.setDecodingStatus(DecodingStatus::Complete);
}
void JPEGImageDecoder::decode(bool onlySize, bool allDataReceived)
}
}
- buffer.setDecodingStatus(ImageFrame::DecodingStatus::Partial);
+ buffer.setDecodingStatus(DecodingStatus::Partial);
buffer.setHasAlpha(false);
#if ENABLE(APNG)
}
#endif
if (!m_frameBufferCache.isEmpty())
- m_frameBufferCache.first().setDecodingStatus(ImageFrame::DecodingStatus::Complete);
+ m_frameBufferCache.first().setDecodingStatus(DecodingStatus::Complete);
}
void PNGImageDecoder::decode(bool onlySize, unsigned haltAtFrame, bool allDataReceived)
return;
ImageFrame& buffer = m_frameBufferCache[m_currentFrame];
- buffer.setDecodingStatus(ImageFrame::DecodingStatus::Complete);
+ buffer.setDecodingStatus(DecodingStatus::Complete);
png_bytep interlaceBuffer = m_reader->interlaceBuffer();
if (buffer.isInvalid()) {
if (!buffer.initialize(size(), m_premultiplyAlpha))
return setFailed();
- buffer.setDecodingStatus(ImageFrame::DecodingStatus::Partial);
+ buffer.setDecodingStatus(DecodingStatus::Partial);
buffer.setHasAlpha(m_hasAlpha);
}
switch (WebPIUpdate(m_decoder, dataBytes, dataSize)) {
case VP8_STATUS_OK:
- buffer.setDecodingStatus(ImageFrame::DecodingStatus::Complete);
+ buffer.setDecodingStatus(DecodingStatus::Complete);
clear();
return true;
case VP8_STATUS_SUSPENDED:
if (IOSApplication::isIBooksStorytime())
return DecodingMode::Synchronous;
#endif
- if (document().isImageDocument())
- return DecodingMode::Synchronous;
if (!settings().largeImageAsyncDecodingEnabled())
return DecodingMode::Synchronous;
if (!bitmapImage.canUseAsyncDecodingForLargeImages())