Diff
Modified: trunk/Source/WebCore/ChangeLog (213562 => 213563)
--- trunk/Source/WebCore/ChangeLog 2017-03-08 03:46:19 UTC (rev 213562)
+++ trunk/Source/WebCore/ChangeLog 2017-03-08 03:54:28 UTC (rev 213563)
@@ -1,3 +1,136 @@
+2017-03-07 Said Abou-Hallawa <[email protected]>
+
+ Asynchronous image decoding should consider the drawing size if it is smaller than the size of the image
+ https://bugs.webkit.org/show_bug.cgi?id=168814
+
+ Reviewed by Simon Fraser.
+
+ If the image destinationRect.size() is smaller than the imageSourceSize
+ (e.g. 3000x3000 pixels), CGImageSourceCreateThumbnailAtIndex() is slower
+ than CGImageSourceCreateImageAtIndex() in decoding this image. To overcome
+ this problem, the entry (kCGImageSourceThumbnailMaxPixelSize,
+ max(destinationRect.width, destinationRect.height)) is added to the options
+ dictionary when calling CGImageSourceCreateThumbnailAtIndex(). This will
+ avoid copying a large block of memory for the unscaled bitmap image.
+
+ An argument named 'sizeForDrawing' of type std::optional<IntSize> will be passed
+ all the way from BitmapImage to ImageDecoder. If bool(sizeForDrawing) equals
+ true that means we want async image decoding. Otherwise the image will be decoded
+ synchronously.
+
+ The subsamplingLevel argument will be passed as std::optional<SubsamplingLevel>.
+ to ImageFrame query functions. When combined with sizeForDrawing, the meaning of
+ these two arguments will be the following:
+ -- !bool(subsamplingLevel): No caching is required. return what is stored in ImageFrameCache.
+ -- bool(subsamplingLevel) && !bool(sizeForDrawing): Match subsamplingLevel only. Recache if it's different.
+ -- bool(subsamplingLevel) && bool(sizeForDrawing): Match both both. . Recache if one of them is different.
+
+ We are going to allow decoding the same ImageFrame for different sizeForDrawings.
+ The rule is a new decoding is allowed only if the maxPixelSize(sizeForDrawing) of
+ the last requested image decoding is less than the new request sizeForDrawing.
+
+ * loader/cache/CachedImage.h: Add a helper function which returns the URL of a CachedImage.
+
+ * platform/graphics/BitmapImage.cpp:
+ (WebCore::BitmapImage::frameImageAtIndex): Add a new argument for sizeForDrawing.
+ (WebCore::BitmapImage::nativeImage): Pass an empty sizeForDrawing to frameImageAtIndex(). We an image with the native size.
+ (WebCore::BitmapImage::nativeImageForCurrentFrame): Ditto.
+ (WebCore::BitmapImage::nativeImageOfSize): Ditto.
+ (WebCore::BitmapImage::draw): Pass the destRect.size() to internalStartAnimation().
+ (WebCore::BitmapImage::isAsyncDecodingRequired): A helper function to answer the question
+ whether the async image decoding is required. It takes into account the animated images, the
+ large image, and the image size.
+ (WebCore::BitmapImage::internalStartAnimation): If async image decoding is requested for this frame m_sizeForDraw
+ will be set. If internalStartAnimation() is called from startAnimation(), sizeForDraw will be empty. In this
+ case no async image decoding will be requested. This happens only when startAnimation() is called from outside
+ BitmapImage::draw().
+ (WebCore::BitmapImage::advanceAnimation): Change the log message.
+ (WebCore::BitmapImage::newFrameNativeImageAvailableAtIndex): Ditto.
+ * platform/graphics/BitmapImage.h:
+
+ * platform/graphics/ImageFrame.cpp:
+ (WebCore::ImageFrame::operator=): Include m_sizeForDraw in the properties of ImageFrame.
+ (WebCore::maxPixelSize): Returns the maximum of the width() and the height of an IntSize.
+ (WebCore::ImageFrame::isBeingDecoded): Returns true if the ImageFrame is currently being decoded for a specific sizeForDrawing.
+ (WebCore::ImageFrame::hasValidNativeImage): Ditto.
+ * platform/graphics/ImageFrame.h:
+ (WebCore::ImageFrame::enqueueSizeForDecoding): Adds a new sizeForDrawing; this sets the ImageFrame is being decoded for this sizeForDrawing.
+ (WebCore::ImageFrame::dequeueSizeForDecoding): Removes the first sizeForDrawing was enqueued; this marks this ImageFrame has finished decoding for this sizeForDrawing.
+ (WebCore::ImageFrame::clearSizeForDecoding): Clears the sizeForDecoding queue. Marks the ImageFrame for not being decoded.
+ (WebCore::ImageFrame::isEmpty): Replace Decoding::Empty by Decoding::None.
+ (WebCore::ImageFrame::sizeForDrawing): Returns the ImageFrame sizeForDraw.
+ (WebCore::ImageFrame::hasDecodedNativeImage): Returns true if the ImageFrame doesn't need decoding before drawing.
+ (WebCore::ImageFrame::hasValidNativeImage): Deleted. Moved to the source file.
+
+ * platform/graphics/ImageFrameCache.cpp:
+ (WebCore::ImageFrameCache::setFrameNativeImageAtIndex): Take a new argument for sizeForDraw.
+ (WebCore::ImageFrameCache::setFrameMetadataAtIndex): When sizeForDraw is set, use the decoder to get the image
+ frame size. Otherwise, get the size of the nativeImage.
+ (WebCore::ImageFrameCache::replaceFrameNativeImageAtIndex): Take a new argument for sizeForDraw.
+ (WebCore::ImageFrameCache::cacheFrameNativeImageAtIndex): Ditto.
+ (WebCore::ImageFrameCache::startAsyncDecodingQueue): Pass the sizeForDraw as a new property of the ImageFrame.
+ (WebCore::ImageFrameCache::requestFrameAsyncDecodingAtIndex): Store sizeForDraw in ImageFrameRequest. Delete unneeded check.
+ This function always receives a valid subsamplingLevel.
+ (WebCore::ImageFrameCache::stopAsyncDecodingQueue): Marks all the queued ImageFrames for not being decoded.
+ (WebCore::ImageFrameCache::frameAtIndexCacheIfNeeded): Take a new argument for sizeForDraw. If this function fixes the
+ properties of ImageFrame properties, keep the old sizeForDraw and/or subsamplingLevel. If a new frame is
+ decoded, no async image decoding will be done in this code path. So pass an empty std::optional<IntSize> to
+ ImageDecoder::createFrameImageAtIndex() and store std::optional<IntSize> in ImageFrame.
+ (WebCore::ImageFrameCache::frameMetadataAtIndex): A new helper function which takes a variable number of arguments which
+ will be passed to the (ImageFrame::*functor).
+ (WebCore::ImageFrameCache::frameMetadataAtIndexCacheIfNeeded): Make this function takes a variable number of arguments which
+ will be passed to the frameAtIndexCacheIfNeeded().
+ (WebCore::ImageFrameCache::size): Pass an Metadata, valid SubsamplingLevel and empty sizeForDraw to frameMetadataAtIndexCacheIfNeeded().
+ (WebCore::ImageFrameCache::sizeRespectingOrientation): Ditto.
+ (WebCore::ImageFrameCache::singlePixelSolidColor): Pass MetadataAndImage, empty SubsamplingLevel and empty sizeForDraw to
+ frameMetadataAtIndexCacheIfNeeded(); we can use the current frame image regardless of its size.
+ (WebCore::ImageFrameCache::frameIsBeingDecodedAtIndex): Pass the ImageFrame method as a function argument instead of
+ passing it as a template argument.
+ (WebCore::ImageFrameCache::frameIsCompleteAtIndex): Ditto.
+ (WebCore::ImageFrameCache::frameHasAlphaAtIndex): Ditto.
+ (WebCore::ImageFrameCache::frameHasImageAtIndex): Ditto.
+ (WebCore::ImageFrameCache::frameHasValidNativeImageAtIndex): Pass subsamplingLevel and sizeForDrawing to frameMetadataAtIndex().
+ (WebCore::ImageFrameCache::frameHasDecodedNativeImage): New helper function to answer the question whether an ImageFrame will need
+ decoding when drawing or not.
+ (WebCore::ImageFrameCache::frameSubsamplingLevelAtIndex): Pass the ImageFrame method as a function argument instead of
+ passing it as a template argument.
+ (WebCore::ImageFrameCache::frameSizeAtIndex): Ditto.
+ (WebCore::ImageFrameCache::frameBytesAtIndex): Ditto.
+ (WebCore::ImageFrameCache::frameDurationAtIndex): Ditto.
+ (WebCore::ImageFrameCache::frameOrientationAtIndex):
+ (WebCore::ImageFrameCache::frameImageAtIndex): Ditto.
+ (WebCore::ImageFrameCache::frameAtIndex): Deleted. Renamed to frameAtIndexCacheIfNeeded().
+ * platform/graphics/ImageFrameCache.h:
+ (WebCore::ImageFrameCache::frameAtIndexCacheIfNeeded):
+
+ * platform/graphics/ImageObserver.h: Define a virtual function for image sourceUrl().
+
+ * platform/graphics/ImageSource.cpp:
+ (WebCore::ImageSource::frameImageAtIndex): Take a new argument for sizeForDrawing.
+ * platform/graphics/ImageSource.h:
+ (WebCore::ImageSource::requestFrameAsyncDecodingAtIndex): Take a new argument for sizeForDrawing.
+ (WebCore::ImageSource::frameHasValidNativeImageAtIndex): Ditto.
+ (WebCore::ImageSource::frameHasDecodedNativeImage): New helper function.
+ (WebCore::ImageSource::frameImageAtIndex): Ditto.
+
+ * platform/graphics/cg/ImageDecoderCG.cpp:
+ (WebCore::createImageSourceOptions): Create a dictionary with the basic image decoding options.
+ (WebCore::createImageSourceAsyncOptions): Create a dictionary with the basic asynchronous image decoding options.
+ (WebCore::appendImageSourceOption): Append the SubsamplingLevel or the MaxPixelSize option to an CGImageSource options dictionary.
+ (WebCore::appendImageSourceOptions): Append the SubsamplingLevel and the MaxPixelSize option to an CGImageSource options dictionary.
+ (WebCore::imageSourceOptions): Creates a dictionary for the synchronous image decoding options.
+ (WebCore::imageSourceAsyncOptions): Creates a dictionary for the asynchronous image decoding options.
+ (WebCore::ImageDecoder::createFrameImageAtIndex): Replace the DecodingMode argument by an std::optional<IntSize>.
+ * platform/graphics/cg/ImageDecoderCG.h: Change a prototype.
+
+ * platform/graphics/win/ImageDecoderDirect2D.cpp:
+ (WebCore::ImageDecoder::createFrameImageAtIndex): Replace the DecodingMode argument by an std::optional<IntSize>.
+ * platform/graphics/win/ImageDecoderDirect2D.h: Change a prototype.
+
+ * platform/image-decoders/ImageDecoder.cpp:
+ (WebCore::ImageDecoder::createFrameImageAtIndex): Replace the DecodingMode argument by an std::optional<IntSize>.
+ * platform/image-decoders/ImageDecoder.h: Change a prototype.
+
2017-03-07 Simon Fraser <[email protected]>
Parsing -webkit-hyphenate-character uses confusingly named consumeLocale()
Modified: trunk/Source/WebCore/loader/cache/CachedImage.h (213562 => 213563)
--- trunk/Source/WebCore/loader/cache/CachedImage.h 2017-03-08 03:46:19 UTC (rev 213562)
+++ trunk/Source/WebCore/loader/cache/CachedImage.h 2017-03-08 03:54:28 UTC (rev 213563)
@@ -126,6 +126,7 @@
explicit CachedImageObserver(CachedImage&);
// ImageObserver API
+ URL sourceUrl() const override { return m_cachedImages[0]->url(); }
bool allowSubsampling() const final { return m_allowSubsampling; }
bool allowLargeImageAsyncDecoding() const override { return m_allowLargeImageAsyncDecoding; }
bool allowAnimatedImageAsyncDecoding() const override { return m_allowAnimatedImageAsyncDecoding; }
Modified: trunk/Source/WebCore/platform/graphics/BitmapImage.cpp (213562 => 213563)
--- trunk/Source/WebCore/platform/graphics/BitmapImage.cpp 2017-03-08 03:46:19 UTC (rev 213562)
+++ trunk/Source/WebCore/platform/graphics/BitmapImage.cpp 2017-03-08 03:54:28 UTC (rev 213563)
@@ -100,24 +100,24 @@
return m_source.dataChanged(data(), allDataReceived);
}
-NativeImagePtr BitmapImage::frameImageAtIndex(size_t index, SubsamplingLevel subsamplingLevel, const GraphicsContext* targetContext)
+NativeImagePtr BitmapImage::frameImageAtIndex(size_t index, const std::optional<SubsamplingLevel>& subsamplingLevel, const std::optional<IntSize>& sizeForDrawing, const GraphicsContext* targetContext)
{
- if (!frameHasValidNativeImageAtIndex(index, subsamplingLevel)) {
- LOG(Images, "BitmapImage %p %s - subsamplingLevel was %d, resampling", this, __FUNCTION__, static_cast<int>(frameSubsamplingLevelAtIndex(index)));
+ if (!frameHasValidNativeImageAtIndex(index, subsamplingLevel, sizeForDrawing)) {
+ LOG(Images, "BitmapImage::%s - %p - url: %s [subsamplingLevel was %d, resampling]", __FUNCTION__, this, sourceURL().characters8(), static_cast<int>(frameSubsamplingLevelAtIndex(index)));
invalidatePlatformData();
}
- return m_source.frameImageAtIndex(index, subsamplingLevel, targetContext);
+ return m_source.frameImageAtIndex(index, subsamplingLevel, sizeForDrawing, targetContext);
}
NativeImagePtr BitmapImage::nativeImage(const GraphicsContext* targetContext)
{
- return frameImageAtIndex(0, SubsamplingLevel::Default, targetContext);
+ return frameImageAtIndex(0, SubsamplingLevel::Default, { }, targetContext);
}
NativeImagePtr BitmapImage::nativeImageForCurrentFrame(const GraphicsContext* targetContext)
{
- return frameImageAtIndex(m_currentFrame, SubsamplingLevel::Default, targetContext);
+ return frameImageAtIndex(m_currentFrame, SubsamplingLevel::Default, { }, targetContext);
}
#if USE(CG)
@@ -126,13 +126,13 @@
size_t count = frameCount();
for (size_t i = 0; i < count; ++i) {
- auto image = frameImageAtIndex(i, SubsamplingLevel::Default, targetContext);
+ auto image = frameImageAtIndex(i, SubsamplingLevel::Default, { }, targetContext);
if (image && nativeImageSize(image) == size)
return image;
}
// Fallback to the first frame image if we can't find the right size
- return frameImageAtIndex(0, SubsamplingLevel::Default, targetContext);
+ return frameImageAtIndex(0, SubsamplingLevel::Default, { }, targetContext);
}
Vector<NativeImagePtr> BitmapImage::framesNativeImages()
@@ -161,6 +161,7 @@
if (destRect.isEmpty() || srcRect.isEmpty())
return;
+ m_sizeForDrawing = enclosingIntRect(destRect).size();
StartAnimationResult result = internalStartAnimation();
Color color;
@@ -176,10 +177,10 @@
float scale = subsamplingScale(context, destRect, srcRect);
m_currentSubsamplingLevel = allowSubsampling() ? m_source.subsamplingLevelForScale(scale) : SubsamplingLevel::Default;
- LOG(Images, "BitmapImage %p draw - subsamplingLevel %d at scale %.4f", this, static_cast<int>(m_currentSubsamplingLevel), scale);
+ 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);
- ASSERT_IMPLIES(result == StartAnimationResult::DecodingActive, m_source.frameHasValidNativeImageAtIndex(m_currentFrame, m_currentSubsamplingLevel));
- auto image = frameImageAtIndex(m_currentFrame, m_currentSubsamplingLevel, &context);
+ ASSERT_IMPLIES(result == StartAnimationResult::DecodingActive, m_source.frameHasValidNativeImageAtIndex(m_currentFrame, m_currentSubsamplingLevel, m_sizeForDrawing));
+ auto image = frameImageAtIndex(m_currentFrame, m_currentSubsamplingLevel, m_sizeForDrawing, &context);
if (!image) // If it's too early we won't have an image yet.
return;
@@ -237,6 +238,16 @@
return shouldAnimate() && frameCount() > 1;
}
+bool BitmapImage::isLargeImageAsyncDecodingRequired()
+{
+ return !canAnimate() && allowLargeImageAsyncDecoding() && (isAsyncDecodingForcedForTesting() || m_source.isAsyncDecodingRequired());
+}
+
+bool BitmapImage::isAnimatedImageAsyncDecodingRequired()
+{
+ return canAnimate() && allowAnimatedImageAsyncDecoding() && (isAsyncDecodingForcedForTesting() || m_source.isAsyncDecodingRequired());
+}
+
void BitmapImage::clearTimer()
{
m_frameTimer = nullptr;
@@ -259,8 +270,10 @@
// Don't start a new animation until we draw the frame that is currently being decoded.
size_t nextFrame = (m_currentFrame + 1) % frameCount();
- if (frameIsBeingDecodedAtIndex(nextFrame))
+ if (frameIsBeingDecodedAtIndex(nextFrame, m_sizeForDrawing)) {
+ LOG(Images, "BitmapImage::%s - %p - url: %s [nextFrame = %ld is being decoded]", __FUNCTION__, this, sourceURL().characters8(), nextFrame);
return StartAnimationResult::DecodingActive;
+ }
if (m_currentFrame >= frameCount() - 1) {
// Don't advance past the last frame if we haven't decoded the whole image
@@ -299,9 +312,18 @@
// it will be decoded on a separate work queue. When decoding nextFrame finishes, we will be notified
// 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 ((allowAnimatedImageAsyncDecoding() && m_source.isAsyncDecodingRequired()) || isAsyncDecodingForcedForTesting()) {
- if (!m_source.requestFrameAsyncDecodingAtIndex(nextFrame, m_currentSubsamplingLevel))
- LOG(Images, "BitmapImage %p %s - cachedFrameCount %ld nextFrame %ld", this, __FUNCTION__, ++m_cachedFrameCount, nextFrame);
+ if (m_sizeForDrawing && isAnimatedImageAsyncDecodingRequired()) {
+ bool isAsyncDecode = m_source.requestFrameAsyncDecodingAtIndex(nextFrame, m_currentSubsamplingLevel, *m_sizeForDrawing);
+
+#if !LOG_DISABLED
+ if (isAsyncDecode)
+ LOG(Images, "BitmapImage::%s - %p - url: %s [requesting async decoding for nextFrame = %ld]", __FUNCTION__, this, sourceURL().characters8(), nextFrame);
+ else
+ LOG(Images, "BitmapImage::%s - %p - url: %s [cachedFrameCount = %ld nextFrame = %ld]", __FUNCTION__, this, sourceURL().characters8(), ++m_cachedFrameCount, nextFrame);
+#else
+ UNUSED_PARAM(isAsyncDecode);
+#endif
+
m_desiredFrameDecodeTimeForTesting = time + std::max(m_frameDecodingDurationForTesting, 0.0f);
}
@@ -327,13 +349,13 @@
// Don't advance to nextFrame unless its decoding has finished or was not required.
size_t nextFrame = (m_currentFrame + 1) % frameCount();
- if (!frameIsBeingDecodedAtIndex(nextFrame))
+ if (!frameIsBeingDecodedAtIndex(nextFrame, m_sizeForDrawing))
internalAdvanceAnimation();
else {
// Force repaint if showDebugBackground() is on.
if (showDebugBackground())
imageObserver()->changedInRect(this);
- LOG(Images, "BitmapImage %p %s - lateFrameCount %ld nextFrame %ld", this, __FUNCTION__, ++m_lateFrameCount, nextFrame);
+ LOG(Images, "BitmapImage::%s - %p - url: %s [lateFrameCount = %ld nextFrame = %ld]", __FUNCTION__, this, sourceURL().characters8(), ++m_lateFrameCount, nextFrame);
}
}
@@ -340,12 +362,14 @@
void BitmapImage::internalAdvanceAnimation()
{
m_currentFrame = (m_currentFrame + 1) % frameCount();
- ASSERT(!frameIsBeingDecodedAtIndex(m_currentFrame));
+ ASSERT(!frameIsBeingDecodedAtIndex(m_currentFrame, m_sizeForDrawing));
destroyDecodedDataIfNecessary(false);
if (imageObserver())
imageObserver()->animationAdvanced(this);
+
+ LOG(Images, "BitmapImage::%s - %p - url: %s [m_currentFrame = %ld]", __FUNCTION__, this, sourceURL().characters8(), m_currentFrame);
}
void BitmapImage::stopAnimation()
@@ -377,7 +401,7 @@
if (canAnimate() && !m_frameTimer)
internalAdvanceAnimation();
else
- LOG(Images, "BitmapImage %p %s - earlyFrameCount %ld nextFrame %ld", this, __FUNCTION__, ++m_earlyFrameCount, index);
+ LOG(Images, "BitmapImage::%s - %p - url: %s [earlyFrameCount = %ld nextFrame = %ld]", __FUNCTION__, this, sourceURL().characters8(), ++m_earlyFrameCount, index);
}
void BitmapImage::dump(TextStream& ts) const
Modified: trunk/Source/WebCore/platform/graphics/BitmapImage.h (213562 => 213563)
--- trunk/Source/WebCore/platform/graphics/BitmapImage.h 2017-03-08 03:46:19 UTC (rev 213562)
+++ trunk/Source/WebCore/platform/graphics/BitmapImage.h 2017-03-08 03:54:28 UTC (rev 213563)
@@ -33,6 +33,7 @@
#include "ImageOrientation.h"
#include "ImageSource.h"
#include "IntSize.h"
+#include "URL.h"
#if USE(CG) || USE(APPKIT)
#include <wtf/RetainPtr.h>
@@ -81,10 +82,11 @@
IntSize sizeRespectingOrientation() const { return m_source.sizeRespectingOrientation(); }
Color singlePixelSolidColor() const override { return m_source.singlePixelSolidColor(); }
- bool frameIsBeingDecodedAtIndex(size_t index) const { return m_source.frameIsBeingDecodedAtIndex(index); }
+ bool frameIsBeingDecodedAtIndex(size_t index, const std::optional<IntSize>& sizeForDrawing) const { return m_source.frameIsBeingDecodedAtIndex(index, sizeForDrawing); }
+ bool frameHasDecodedNativeImage(size_t index) const { return m_source.frameHasDecodedNativeImage(index); }
bool frameIsCompleteAtIndex(size_t index) const { return m_source.frameIsCompleteAtIndex(index); }
bool frameHasAlphaAtIndex(size_t index) const { return m_source.frameHasAlphaAtIndex(index); }
- bool frameHasValidNativeImageAtIndex(size_t index, SubsamplingLevel subsamplingLevel) const { return m_source.frameHasValidNativeImageAtIndex(index, subsamplingLevel); }
+ bool frameHasValidNativeImageAtIndex(size_t index, const std::optional<SubsamplingLevel>& subsamplingLevel, const std::optional<IntSize>& sizeForDrawing) const { return m_source.frameHasValidNativeImageAtIndex(index, subsamplingLevel, sizeForDrawing); }
SubsamplingLevel frameSubsamplingLevelAtIndex(size_t index) const { return m_source.frameSubsamplingLevelAtIndex(index); }
float frameDurationAtIndex(size_t index) const { return m_source.frameDurationAtIndex(index); }
@@ -96,6 +98,8 @@
bool isAsyncDecodingForcedForTesting() const { return m_frameDecodingDurationForTesting > 0; }
void setFrameDecodingDurationForTesting(float duration) { m_frameDecodingDurationForTesting = duration; }
+ bool isLargeImageAsyncDecodingRequired();
+ bool isAnimatedImageAsyncDecodingRequired();
// Accessors for native image formats.
#if USE(APPKIT)
@@ -127,8 +131,9 @@
WEBCORE_EXPORT BitmapImage(NativeImagePtr&&, ImageObserver* = nullptr);
WEBCORE_EXPORT BitmapImage(ImageObserver* = nullptr);
- NativeImagePtr frameImageAtIndex(size_t, SubsamplingLevel = SubsamplingLevel::Default, const GraphicsContext* = nullptr);
+ NativeImagePtr frameImageAtIndex(size_t, const std::optional<SubsamplingLevel>& = { }, const std::optional<IntSize>& sizeForDrawing = { }, const GraphicsContext* = nullptr);
+ String sourceURL() const { return imageObserver() ? imageObserver()->sourceUrl().string() : emptyString(); }
bool allowSubsampling() const { return imageObserver() && imageObserver()->allowSubsampling(); }
bool allowLargeImageAsyncDecoding() const { return imageObserver() && imageObserver()->allowLargeImageAsyncDecoding(); }
bool allowAnimatedImageAsyncDecoding() const { return imageObserver() && imageObserver()->allowAnimatedImageAsyncDecoding(); }
@@ -197,6 +202,7 @@
size_t m_currentFrame { 0 }; // The index of the current frame of animation.
SubsamplingLevel m_currentSubsamplingLevel { SubsamplingLevel::Default };
+ std::optional<IntSize> m_sizeForDrawing;
std::unique_ptr<Timer> m_frameTimer;
RepetitionCount m_repetitionsComplete { RepetitionCountNone }; // How many repetitions we've finished.
double m_desiredFrameStartTime { 0 }; // The system time at which we hope to see the next call to startAnimation().
Modified: trunk/Source/WebCore/platform/graphics/ImageFrame.cpp (213562 => 213563)
--- trunk/Source/WebCore/platform/graphics/ImageFrame.cpp 2017-03-08 03:46:19 UTC (rev 213562)
+++ trunk/Source/WebCore/platform/graphics/ImageFrame.cpp 2017-03-08 03:54:28 UTC (rev 213563)
@@ -63,6 +63,7 @@
m_nativeImage = other.m_nativeImage;
m_subsamplingLevel = other.m_subsamplingLevel;
+ m_sizeForDrawing = other.m_sizeForDrawing;
m_orientation = other.m_orientation;
m_duration = other.m_duration;
@@ -123,7 +124,46 @@
#endif
return m_size;
}
+
+static int maxDimension(const IntSize& size)
+{
+ return std::max(size.width(), size.height());
+}
+bool ImageFrame::isBeingDecoded(const std::optional<IntSize>& sizeForDrawing) const
+{
+ if (!m_sizeForDecoding.size())
+ return false;
+
+ if (!sizeForDrawing)
+ return true;
+
+ // Return true if the ImageFrame will be decoded eventually with a suitable sizeForDecoding.
+ return maxDimension(m_sizeForDecoding.last()) >= maxDimension(*sizeForDrawing);
+}
+
+bool ImageFrame::hasValidNativeImage(const std::optional<SubsamplingLevel>& subsamplingLevel, const std::optional<IntSize>& sizeForDrawing) const
+{
+ ASSERT_IMPLIES(!subsamplingLevel, !sizeForDrawing);
+
+ if (!hasNativeImage())
+ return false;
+
+ // The caller does not care about subsamplingLevel or sizeForDrawing. The current NativeImage is fine.
+ if (!subsamplingLevel)
+ return true;
+
+ if (*subsamplingLevel < m_subsamplingLevel)
+ return false;
+
+ // The NativeImage was decoded with the native size. So it is valid for any size.
+ if (!m_sizeForDrawing)
+ return true;
+
+ // The NativeImage was decoded for a specific size. The two sizeForDrawings have to match.
+ return sizeForDrawing && maxDimension(*m_sizeForDrawing) >= maxDimension(*sizeForDrawing);
+}
+
Color ImageFrame::singlePixelSolidColor() const
{
if (!hasNativeImage() || m_size != IntSize(1, 1))
Modified: trunk/Source/WebCore/platform/graphics/ImageFrame.h (213562 => 213563)
--- trunk/Source/WebCore/platform/graphics/ImageFrame.h 2017-03-08 03:46:19 UTC (rev 213562)
+++ trunk/Source/WebCore/platform/graphics/ImageFrame.h 2017-03-08 03:54:28 UTC (rev 213563)
@@ -30,6 +30,7 @@
#include "ImageOrientation.h"
#include "IntSize.h"
#include "NativeImage.h"
+#include <wtf/Deque.h>
namespace WebCore {
@@ -37,7 +38,6 @@
// There are four subsampling levels: 0 = 1x, 1 = 0.5x, 2 = 0.25x, 3 = 0.125x.
enum class SubsamplingLevel {
- Undefinded = -1,
First = 0,
Default = First,
Level0 = First,
@@ -73,16 +73,11 @@
Ignored
};
-enum class DecodingMode {
- OnDemand,
- Immediate
-};
-
class ImageFrame {
friend class ImageFrameCache;
public:
- enum class Caching { Empty, Metadata, MetadataAndImage };
- enum class Decoding { Empty, BeingDecoded, Partial, Complete };
+ enum class Caching { Metadata, MetadataAndImage };
+ enum class Decoding { None, Partial, Complete };
ImageFrame();
ImageFrame(const ImageFrame& other) { operator=(other); }
@@ -103,8 +98,12 @@
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; }
+ void enqueueSizeForDecoding(const IntSize& sizeForDecoding) { m_sizeForDecoding.append(sizeForDecoding); }
+ void dequeueSizeForDecoding() { m_sizeForDecoding.removeFirst(); }
+ void clearSizeForDecoding() { m_sizeForDecoding.clear(); }
+
+ bool isEmpty() const { return m_decoding == Decoding::None; }
+ bool isBeingDecoded(const std::optional<IntSize>& sizeForDrawing = { }) const;
bool isPartial() const { return m_decoding == Decoding::Partial; }
bool isComplete() const { return m_decoding == Decoding::Complete; }
@@ -112,6 +111,7 @@
IntSize sizeRespectingOrientation() const { return !m_orientation.usesWidthAsHeight() ? size() : size().transposedSize(); }
unsigned frameBytes() const { return hasNativeImage() ? (size().area() * sizeof(RGBA32)).unsafeGet() : 0; }
SubsamplingLevel subsamplingLevel() const { return m_subsamplingLevel; }
+ std::optional<IntSize> sizeForDrawing() const { return m_sizeForDrawing; }
#if !USE(CG)
enum class DisposalMethod { Unspecified, DoNotDispose, RestoreToBackground, RestoreToPrevious };
@@ -131,7 +131,8 @@
bool hasAlpha() const { return !hasMetadata() || m_hasAlpha; }
bool hasNativeImage() const { return m_nativeImage; }
- bool hasValidNativeImage(SubsamplingLevel subsamplingLevel) const { return hasNativeImage() && subsamplingLevel >= m_subsamplingLevel; }
+ bool hasValidNativeImage(const std::optional<SubsamplingLevel>&, const std::optional<IntSize>& sizeForDrawing) const;
+ bool hasDecodedNativeImage() const { return hasNativeImage() && sizeForDrawing(); }
bool hasMetadata() const { return !size().isEmpty(); }
#if !USE(CG)
@@ -142,7 +143,7 @@
Color singlePixelSolidColor() const;
private:
- Decoding m_decoding { Decoding::Empty };
+ Decoding m_decoding { Decoding::None };
IntSize m_size;
#if !USE(CG)
@@ -152,6 +153,8 @@
NativeImagePtr m_nativeImage;
SubsamplingLevel m_subsamplingLevel { SubsamplingLevel::Default };
+ std::optional<IntSize> m_sizeForDrawing;
+ Deque<IntSize, 4> m_sizeForDecoding;
ImageOrientation m_orientation { DefaultImageOrientation };
float m_duration { 0 };
Modified: trunk/Source/WebCore/platform/graphics/ImageFrameCache.cpp (213562 => 213563)
--- trunk/Source/WebCore/platform/graphics/ImageFrameCache.cpp 2017-03-08 03:46:19 UTC (rev 213562)
+++ trunk/Source/WebCore/platform/graphics/ImageFrameCache.cpp 2017-03-08 03:54:28 UTC (rev 213563)
@@ -174,7 +174,7 @@
frame.m_hasAlpha = nativeImageHasAlpha(frame.m_nativeImage);
}
-void ImageFrameCache::setFrameNativeImageAtIndex(NativeImagePtr&& nativeImage, size_t index, SubsamplingLevel subsamplingLevel)
+void ImageFrameCache::setFrameNativeImageAtIndex(NativeImagePtr&& nativeImage, size_t index, SubsamplingLevel subsamplingLevel, const std::optional<IntSize>& sizeForDrawing)
{
ASSERT(index < m_frames.size());
ImageFrame& frame = m_frames[index];
@@ -182,10 +182,10 @@
ASSERT(isDecoderAvailable());
frame.m_nativeImage = WTFMove(nativeImage);
- setFrameMetadataAtIndex(index, subsamplingLevel);
+ setFrameMetadataAtIndex(index, subsamplingLevel, sizeForDrawing);
}
-void ImageFrameCache::setFrameMetadataAtIndex(size_t index, SubsamplingLevel subsamplingLevel)
+void ImageFrameCache::setFrameMetadataAtIndex(size_t index, SubsamplingLevel subsamplingLevel, const std::optional<IntSize>& sizeForDrawing)
{
ASSERT(index < m_frames.size());
ImageFrame& frame = m_frames[index];
@@ -196,20 +196,29 @@
return;
frame.m_subsamplingLevel = subsamplingLevel;
- frame.m_size = m_decoder->frameSizeAtIndex(index, subsamplingLevel);
+
+ if (!sizeForDrawing) {
+ frame.m_size = m_decoder->frameSizeAtIndex(index, frame.m_subsamplingLevel);
+ frame.m_sizeForDrawing = { };
+ } else {
+ ASSERT(frame.nativeImage());
+ frame.m_size = nativeImageSize(frame.nativeImage());
+ frame.m_sizeForDrawing = sizeForDrawing;
+ }
+
frame.m_orientation = m_decoder->frameOrientationAtIndex(index);
frame.m_hasAlpha = m_decoder->frameHasAlphaAtIndex(index);
-
+
if (repetitionCount())
frame.m_duration = m_decoder->frameDurationAtIndex(index);
}
-void ImageFrameCache::replaceFrameNativeImageAtIndex(NativeImagePtr&& nativeImage, size_t index, SubsamplingLevel subsamplingLevel)
+void ImageFrameCache::replaceFrameNativeImageAtIndex(NativeImagePtr&& nativeImage, size_t index, SubsamplingLevel subsamplingLevel, const std::optional<IntSize>& sizeForDrawing)
{
ASSERT(index < m_frames.size());
ImageFrame& frame = m_frames[index];
- if (!frame.hasValidNativeImage(subsamplingLevel)) {
+ if (!frame.hasValidNativeImage(subsamplingLevel, sizeForDrawing)) {
// Clear the current image frame and update the observer with this clearance.
unsigned decodedSize = frame.clear();
decodedSizeDecreased(decodedSize);
@@ -221,22 +230,23 @@
return;
// Copy the new image to the cache.
- setFrameNativeImageAtIndex(WTFMove(nativeImage), index, subsamplingLevel);
+ setFrameNativeImageAtIndex(WTFMove(nativeImage), index, subsamplingLevel, sizeForDrawing);
// Update the observer with the new image frame bytes.
decodedSizeIncreased(frame.frameBytes());
}
-void ImageFrameCache::cacheFrameNativeImageAtIndex(NativeImagePtr&& nativeImage, size_t index, SubsamplingLevel subsamplingLevel)
+void ImageFrameCache::cacheFrameNativeImageAtIndex(NativeImagePtr&& nativeImage, size_t index, SubsamplingLevel subsamplingLevel, const IntSize& sizeForDrawing)
{
if (!isDecoderAvailable())
return;
ASSERT(index < m_frames.size());
- ASSERT(m_frames[index].isBeingDecoded());
+ ASSERT(m_frames[index].isBeingDecoded(sizeForDrawing));
// Clean the old native image and set a new one
- replaceFrameNativeImageAtIndex(WTFMove(nativeImage), index, subsamplingLevel);
+ replaceFrameNativeImageAtIndex(WTFMove(nativeImage), index, subsamplingLevel, sizeForDrawing);
+ m_frames[index].dequeueSizeForDecoding();
// Notify the image with the readiness of the new frame NativeImage.
if (m_image)
@@ -267,26 +277,23 @@
while (m_frameRequestQueue.dequeue(frameRequest)) {
// Get the frame NativeImage on the decoding thread.
- NativeImagePtr nativeImage = m_decoder->createFrameImageAtIndex(frameRequest.index, frameRequest.subsamplingLevel, DecodingMode::Immediate);
+ NativeImagePtr nativeImage = m_decoder->createFrameImageAtIndex(frameRequest.index, frameRequest.subsamplingLevel, frameRequest.sizeForDrawing);
// Update the cached frames on the main thread to avoid updating the MemoryCache from a different thread.
callOnMainThread([this, protectedQueue = protectedQueue.copyRef(), nativeImage, frameRequest] () mutable {
// The queue may be closed if after we got the frame NativeImage, stopAsyncDecodingQueue() was called
if (protectedQueue.ptr() == m_decodingQueue)
- cacheFrameNativeImageAtIndex(WTFMove(nativeImage), frameRequest.index, frameRequest.subsamplingLevel);
+ cacheFrameNativeImageAtIndex(WTFMove(nativeImage), frameRequest.index, frameRequest.subsamplingLevel, frameRequest.sizeForDrawing);
});
}
});
}
-bool ImageFrameCache::requestFrameAsyncDecodingAtIndex(size_t index, SubsamplingLevel subsamplingLevel)
+bool ImageFrameCache::requestFrameAsyncDecodingAtIndex(size_t index, SubsamplingLevel subsamplingLevel, const IntSize& sizeForDrawing)
{
if (!isDecoderAvailable())
return false;
- if (!hasDecodingQueue())
- startAsyncDecodingQueue();
-
ASSERT(index < m_frames.size());
ImageFrame& frame = m_frames[index];
@@ -293,17 +300,17 @@
// 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 (frame.isBeingDecoded())
+ if (frame.isBeingDecoded(sizeForDrawing))
return true;
- if (subsamplingLevel == SubsamplingLevel::Undefinded)
- subsamplingLevel = frame.subsamplingLevel();
-
- if (frame.hasValidNativeImage(subsamplingLevel))
+ if (frame.hasValidNativeImage(subsamplingLevel, sizeForDrawing))
return false;
- frame.setDecoding(ImageFrame::Decoding::BeingDecoded);
- m_frameRequestQueue.enqueue({ index, subsamplingLevel });
+ if (!hasDecodingQueue())
+ startAsyncDecodingQueue();
+
+ frame.enqueueSizeForDecoding(sizeForDrawing);
+ m_frameRequestQueue.enqueue({ index, subsamplingLevel, sizeForDrawing });
return true;
}
@@ -316,25 +323,39 @@
m_decodingQueue = nullptr;
for (ImageFrame& frame : m_frames) {
- if (frame.isBeingDecoded())
+ if (frame.isBeingDecoded()) {
+ frame.clearSizeForDecoding();
frame.clear();
+ }
}
}
-const ImageFrame& ImageFrameCache::frameAtIndex(size_t index, SubsamplingLevel subsamplingLevel, ImageFrame::Caching caching)
+const ImageFrame& ImageFrameCache::frameAtIndexCacheIfNeeded(size_t index, ImageFrame::Caching caching, const std::optional<SubsamplingLevel>& subsamplingLevel, const std::optional<IntSize>& sizeForDrawing)
{
ASSERT(index < m_frames.size());
ImageFrame& frame = m_frames[index];
- if (!isDecoderAvailable() || frame.isBeingDecoded() || caching == ImageFrame::Caching::Empty)
+ if (!isDecoderAvailable() || frame.isBeingDecoded(sizeForDrawing))
return frame;
- if (subsamplingLevel == SubsamplingLevel::Undefinded)
- subsamplingLevel = frame.subsamplingLevel();
+ SubsamplingLevel subsamplingLevelValue = subsamplingLevel ? subsamplingLevel.value() : 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);
+ switch (caching) {
+ case ImageFrame::Caching::Metadata:
+ // Retrieve the metadata from ImageDecoder if the ImageFrame isn't complete.
+ if (frame.isComplete())
+ break;
+ setFrameMetadataAtIndex(index, subsamplingLevelValue, frame.sizeForDrawing());
+ break;
+
+ case ImageFrame::Caching::MetadataAndImage:
+ // Cache the image and retrieve the metadata from ImageDecoder only if there was not valid image stored.
+ if (frame.hasValidNativeImage(subsamplingLevel, sizeForDrawing))
+ break;
+ // We have to perform synchronous image decoding in this code path regardless of the sizeForDrawing value.
+ // So pass an empty sizeForDrawing to create an ImageFrame with the native size.
+ replaceFrameNativeImageAtIndex(m_decoder->createFrameImageAtIndex(index, subsamplingLevelValue, { }), index, subsamplingLevelValue, { });
+ break;
+ }
return frame;
}
@@ -362,18 +383,25 @@
return cachedValue->value();
}
-template<typename T, T (ImageFrame::*functor)() const>
-T ImageFrameCache::frameMetadataAtIndex(size_t index, SubsamplingLevel subsamplingLevel, ImageFrame::Caching caching, std::optional<T>* cachedValue)
+template<typename T, typename... Args>
+T ImageFrameCache::frameMetadataAtIndex(size_t index, T (ImageFrame::*functor)(Args...) const, Args&&... args)
{
+ const ImageFrame& frame = index < m_frames.size() ? m_frames[index] : ImageFrame::defaultFrame();
+ return (frame.*functor)(std::forward<Args>(args)...);
+}
+
+template<typename T, typename... Args>
+T ImageFrameCache::frameMetadataAtIndexCacheIfNeeded(size_t index, T (ImageFrame::*functor)() const, std::optional<T>* cachedValue, Args&&... args)
+{
if (cachedValue && *cachedValue)
return cachedValue->value();
-
- const ImageFrame& frame = index < m_frames.size() ? frameAtIndex(index, subsamplingLevel, caching) : ImageFrame::defaultFrame();
+ const ImageFrame& frame = index < m_frames.size() ? frameAtIndexCacheIfNeeded(index, std::forward<Args>(args)...) : ImageFrame::defaultFrame();
+
// Don't cache any unavailable frame metadata.
if (!frame.hasMetadata() || !cachedValue)
return (frame.*functor)();
-
+
*cachedValue = (frame.*functor)();
return cachedValue->value();
}
@@ -413,72 +441,77 @@
IntSize ImageFrameCache::size()
{
- return frameMetadataAtIndex<IntSize, (&ImageFrame::size)>(0, SubsamplingLevel::Default, ImageFrame::Caching::Metadata, &m_size);
+ return frameMetadataAtIndexCacheIfNeeded<IntSize>(0, (&ImageFrame::size), &m_size, ImageFrame::Caching::Metadata, SubsamplingLevel::Default);
}
IntSize ImageFrameCache::sizeRespectingOrientation()
{
- return frameMetadataAtIndex<IntSize, (&ImageFrame::sizeRespectingOrientation)>(0, SubsamplingLevel::Default, ImageFrame::Caching::Metadata, &m_sizeRespectingOrientation);
+ return frameMetadataAtIndexCacheIfNeeded<IntSize>(0, (&ImageFrame::sizeRespectingOrientation), &m_sizeRespectingOrientation, ImageFrame::Caching::Metadata, SubsamplingLevel::Default);
}
Color ImageFrameCache::singlePixelSolidColor()
{
- return frameCount() == 1 ? frameMetadataAtIndex<Color, (&ImageFrame::singlePixelSolidColor)>(0, SubsamplingLevel::Undefinded, ImageFrame::Caching::MetadataAndImage, &m_singlePixelSolidColor) : Color();
+ return frameCount() == 1 ? frameMetadataAtIndexCacheIfNeeded<Color>(0, (&ImageFrame::singlePixelSolidColor), &m_singlePixelSolidColor, ImageFrame::Caching::MetadataAndImage) : Color();
}
-bool ImageFrameCache::frameIsBeingDecodedAtIndex(size_t index)
+bool ImageFrameCache::frameIsBeingDecodedAtIndex(size_t index, const std::optional<IntSize>& sizeForDrawing)
{
- return frameMetadataAtIndex<bool, (&ImageFrame::isBeingDecoded)>(index);
+ return frameMetadataAtIndex<bool>(index, (&ImageFrame::isBeingDecoded), sizeForDrawing);
}
bool ImageFrameCache::frameIsCompleteAtIndex(size_t index)
{
- return frameMetadataAtIndex<bool, (&ImageFrame::isComplete)>(index);
+ return frameMetadataAtIndex<bool>(index, (&ImageFrame::isComplete));
}
bool ImageFrameCache::frameHasAlphaAtIndex(size_t index)
{
- return frameMetadataAtIndex<bool, (&ImageFrame::hasAlpha)>(index);
+ return frameMetadataAtIndex<bool>(index, (&ImageFrame::hasAlpha));
}
bool ImageFrameCache::frameHasImageAtIndex(size_t index)
{
- return frameMetadataAtIndex<bool, (&ImageFrame::hasNativeImage)>(index);
+ return frameMetadataAtIndex<bool>(index, (&ImageFrame::hasNativeImage));
}
-bool ImageFrameCache::frameHasValidNativeImageAtIndex(size_t index, SubsamplingLevel subsamplingLevel)
+bool ImageFrameCache::frameHasValidNativeImageAtIndex(size_t index, const std::optional<SubsamplingLevel>& subsamplingLevel, const std::optional<IntSize>& sizeForDrawing)
{
- return frameHasImageAtIndex(index) && subsamplingLevel >= frameSubsamplingLevelAtIndex(index);
+ return frameMetadataAtIndex<bool>(index, (&ImageFrame::hasValidNativeImage), subsamplingLevel, sizeForDrawing);
}
+
+bool ImageFrameCache::frameHasDecodedNativeImage(size_t index)
+{
+ return frameMetadataAtIndex<bool>(index, (&ImageFrame::hasDecodedNativeImage));
+}
SubsamplingLevel ImageFrameCache::frameSubsamplingLevelAtIndex(size_t index)
{
- return frameMetadataAtIndex<SubsamplingLevel, (&ImageFrame::subsamplingLevel)>(index);
+ return frameMetadataAtIndex<SubsamplingLevel>(index, (&ImageFrame::subsamplingLevel));
}
IntSize ImageFrameCache::frameSizeAtIndex(size_t index, SubsamplingLevel subsamplingLevel)
{
- return frameMetadataAtIndex<IntSize, (&ImageFrame::size)>(index, subsamplingLevel, ImageFrame::Caching::Metadata);
+ return frameMetadataAtIndexCacheIfNeeded<IntSize>(index, (&ImageFrame::size), nullptr, ImageFrame::Caching::Metadata, subsamplingLevel);
}
unsigned ImageFrameCache::frameBytesAtIndex(size_t index, SubsamplingLevel subsamplingLevel)
{
- return frameMetadataAtIndex<unsigned, (&ImageFrame::frameBytes)>(index, subsamplingLevel, ImageFrame::Caching::Metadata);
+ return frameMetadataAtIndexCacheIfNeeded<unsigned>(index, (&ImageFrame::frameBytes), nullptr, ImageFrame::Caching::Metadata, subsamplingLevel);
}
float ImageFrameCache::frameDurationAtIndex(size_t index)
{
- return frameMetadataAtIndex<float, (&ImageFrame::duration)>(index, SubsamplingLevel::Undefinded, ImageFrame::Caching::Metadata);
+ return frameMetadataAtIndexCacheIfNeeded<float>(index, (&ImageFrame::duration), nullptr, ImageFrame::Caching::Metadata);
}
ImageOrientation ImageFrameCache::frameOrientationAtIndex(size_t index)
{
- return frameMetadataAtIndex<ImageOrientation, (&ImageFrame::orientation)>(index, SubsamplingLevel::Undefinded, ImageFrame::Caching::Metadata);
+ return frameMetadataAtIndexCacheIfNeeded<ImageOrientation>(index, (&ImageFrame::orientation), nullptr, ImageFrame::Caching::Metadata);
}
-NativeImagePtr ImageFrameCache::frameImageAtIndex(size_t index, SubsamplingLevel subsamplingLevel)
+NativeImagePtr ImageFrameCache::frameImageAtIndex(size_t index, const std::optional<SubsamplingLevel>& subsamplingLevel, const std::optional<IntSize>& sizeForDrawing)
{
- return frameMetadataAtIndex<NativeImagePtr, (&ImageFrame::nativeImage)>(index, subsamplingLevel, ImageFrame::Caching::MetadataAndImage);
+ return frameMetadataAtIndexCacheIfNeeded<NativeImagePtr>(index, (&ImageFrame::nativeImage), nullptr, ImageFrame::Caching::MetadataAndImage, subsamplingLevel, sizeForDrawing);
}
}
Modified: trunk/Source/WebCore/platform/graphics/ImageFrameCache.h (213562 => 213563)
--- trunk/Source/WebCore/platform/graphics/ImageFrameCache.h 2017-03-08 03:46:19 UTC (rev 213562)
+++ trunk/Source/WebCore/platform/graphics/ImageFrameCache.h 2017-03-08 03:54:28 UTC (rev 213563)
@@ -69,7 +69,7 @@
// Asynchronous image decoding
void startAsyncDecodingQueue();
- bool requestFrameAsyncDecodingAtIndex(size_t, SubsamplingLevel);
+ bool requestFrameAsyncDecodingAtIndex(size_t, SubsamplingLevel, const IntSize&);
void stopAsyncDecodingQueue();
bool hasDecodingQueue() { return m_decodingQueue; }
@@ -88,11 +88,12 @@
Color singlePixelSolidColor();
// ImageFrame metadata which does not require caching the ImageFrame.
- bool frameIsBeingDecodedAtIndex(size_t);
+ bool frameIsBeingDecodedAtIndex(size_t, const std::optional<IntSize>& sizeForDrawing);
bool frameIsCompleteAtIndex(size_t);
bool frameHasAlphaAtIndex(size_t);
bool frameHasImageAtIndex(size_t);
- bool frameHasValidNativeImageAtIndex(size_t, SubsamplingLevel);
+ bool frameHasValidNativeImageAtIndex(size_t, const std::optional<SubsamplingLevel>&, const std::optional<IntSize>& sizeForDrawing);
+ bool frameHasDecodedNativeImage(size_t);
SubsamplingLevel frameSubsamplingLevelAtIndex(size_t);
// ImageFrame metadata which forces caching or re-caching the ImageFrame.
@@ -100,7 +101,7 @@
unsigned frameBytesAtIndex(size_t, SubsamplingLevel = SubsamplingLevel::Default);
float frameDurationAtIndex(size_t);
ImageOrientation frameOrientationAtIndex(size_t);
- NativeImagePtr frameImageAtIndex(size_t, SubsamplingLevel = SubsamplingLevel::Default);
+ NativeImagePtr frameImageAtIndex(size_t, const std::optional<SubsamplingLevel>&, const std::optional<IntSize>& sizeForDrawing);
private:
ImageFrameCache(Image*);
@@ -109,9 +110,12 @@
template<typename T, T (ImageDecoder::*functor)() const>
T metadata(const T& defaultValue, std::optional<T>* cachedValue = nullptr);
- template<typename T, T (ImageFrame::*functor)() const>
- T frameMetadataAtIndex(size_t index, SubsamplingLevel = SubsamplingLevel::Undefinded, ImageFrame::Caching = ImageFrame::Caching::Empty, std::optional<T>* = nullptr);
-
+ template<typename T, typename... Args>
+ T frameMetadataAtIndex(size_t, T (ImageFrame::*functor)(Args...) const, Args&&...);
+
+ template<typename T, typename... Args>
+ T frameMetadataAtIndexCacheIfNeeded(size_t, T (ImageFrame::*functor)() const, std::optional<T>* cachedValue, Args&&...);
+
bool isDecoderAvailable() const { return m_decoder; }
void destroyDecodedData(size_t frameCount, size_t excludeFrame);
void decodedSizeChanged(long long decodedSize);
@@ -121,14 +125,14 @@
void decodedSizeReset(unsigned decodedSize);
void setNativeImage(NativeImagePtr&&);
- void setFrameNativeImageAtIndex(NativeImagePtr&&, size_t, SubsamplingLevel);
- void setFrameMetadataAtIndex(size_t, SubsamplingLevel);
- void replaceFrameNativeImageAtIndex(NativeImagePtr&&, size_t, SubsamplingLevel);
- void cacheFrameNativeImageAtIndex(NativeImagePtr&&, size_t, SubsamplingLevel);
+ void setFrameNativeImageAtIndex(NativeImagePtr&&, size_t, SubsamplingLevel, const std::optional<IntSize>& sizeForDrawing);
+ void setFrameMetadataAtIndex(size_t, SubsamplingLevel, const std::optional<IntSize>& sizeForDrawing);
+ void replaceFrameNativeImageAtIndex(NativeImagePtr&&, size_t, SubsamplingLevel, const std::optional<IntSize>& sizeForDrawing);
+ void cacheFrameNativeImageAtIndex(NativeImagePtr&&, size_t, SubsamplingLevel, const IntSize& sizeForDrawing);
Ref<WorkQueue> decodingQueue();
- const ImageFrame& frameAtIndex(size_t, SubsamplingLevel, ImageFrame::Caching);
+ const ImageFrame& frameAtIndexCacheIfNeeded(size_t, ImageFrame::Caching, const std::optional<SubsamplingLevel>& = { }, const std::optional<IntSize>& sizeForDrawing = { });
Image* m_image { nullptr };
ImageDecoder* m_decoder { nullptr };
@@ -141,6 +145,7 @@
struct ImageFrameRequest {
size_t index;
SubsamplingLevel subsamplingLevel;
+ IntSize sizeForDrawing;
};
static const int BufferSize = 8;
using FrameRequestQueue = SynchronizedFixedQueue<ImageFrameRequest, BufferSize>;
Modified: trunk/Source/WebCore/platform/graphics/ImageObserver.h (213562 => 213563)
--- trunk/Source/WebCore/platform/graphics/ImageObserver.h 2017-03-08 03:46:19 UTC (rev 213562)
+++ trunk/Source/WebCore/platform/graphics/ImageObserver.h 2017-03-08 03:54:28 UTC (rev 213563)
@@ -30,6 +30,7 @@
class Image;
class IntRect;
+class URL;
// Interface for notification about changes to an image, including decoding,
// drawing, and animating.
@@ -37,6 +38,7 @@
protected:
virtual ~ImageObserver() {}
public:
+ virtual URL sourceUrl() const = 0;
virtual bool allowSubsampling() const = 0;
virtual bool allowLargeImageAsyncDecoding() const = 0;
virtual bool allowAnimatedImageAsyncDecoding() const = 0;
Modified: trunk/Source/WebCore/platform/graphics/ImageSource.cpp (213562 => 213563)
--- trunk/Source/WebCore/platform/graphics/ImageSource.cpp 2017-03-08 03:46:19 UTC (rev 213562)
+++ trunk/Source/WebCore/platform/graphics/ImageSource.cpp 2017-03-08 03:54:28 UTC (rev 213563)
@@ -191,11 +191,10 @@
return isDecoderAvailable() ? m_decoder->createFrameImageAtIndex(index, subsamplingLevel) : nullptr;
}
-NativeImagePtr ImageSource::frameImageAtIndex(size_t index, SubsamplingLevel subsamplingLevel, const GraphicsContext* targetContext)
+NativeImagePtr ImageSource::frameImageAtIndex(size_t index, const std::optional<SubsamplingLevel>& subsamplingLevel, const std::optional<IntSize>& sizeForDrawing, const GraphicsContext* targetContext)
{
setDecoderTargetContext(targetContext);
-
- return m_frameCache->frameImageAtIndex(index, subsamplingLevel);
+ return m_frameCache->frameImageAtIndex(index, subsamplingLevel, sizeForDrawing);
}
void ImageSource::dump(TextStream& ts)
Modified: trunk/Source/WebCore/platform/graphics/ImageSource.h (213562 => 213563)
--- trunk/Source/WebCore/platform/graphics/ImageSource.h 2017-03-08 03:46:19 UTC (rev 213562)
+++ trunk/Source/WebCore/platform/graphics/ImageSource.h 2017-03-08 03:54:28 UTC (rev 213563)
@@ -69,7 +69,7 @@
bool isAllDataReceived();
bool isAsyncDecodingRequired();
- bool requestFrameAsyncDecodingAtIndex(size_t index, SubsamplingLevel subsamplingLevel) { return m_frameCache->requestFrameAsyncDecodingAtIndex(index, subsamplingLevel); }
+ bool requestFrameAsyncDecodingAtIndex(size_t index, SubsamplingLevel subsamplingLevel, const IntSize& sizeForDrawing) { return m_frameCache->requestFrameAsyncDecodingAtIndex(index, subsamplingLevel, sizeForDrawing); }
bool hasDecodingQueue() const { return m_frameCache->hasDecodingQueue(); }
void stopAsyncDecodingQueue() { m_frameCache->stopAsyncDecodingQueue(); }
@@ -86,11 +86,12 @@
Color singlePixelSolidColor() { return m_frameCache->singlePixelSolidColor(); }
// ImageFrame metadata which does not require caching the ImageFrame.
- bool frameIsBeingDecodedAtIndex(size_t index) { return m_frameCache->frameIsBeingDecodedAtIndex(index); }
+ bool frameIsBeingDecodedAtIndex(size_t index, const std::optional<IntSize>& sizeForDrawing) { return m_frameCache->frameIsBeingDecodedAtIndex(index, sizeForDrawing); }
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); }
+ bool frameHasValidNativeImageAtIndex(size_t index, const std::optional<SubsamplingLevel>& subsamplingLevel, const std::optional<IntSize>& sizeForDrawing) { return m_frameCache->frameHasValidNativeImageAtIndex(index, subsamplingLevel, sizeForDrawing); }
+ bool frameHasDecodedNativeImage(size_t index) { return m_frameCache->frameHasDecodedNativeImage(index); }
SubsamplingLevel frameSubsamplingLevelAtIndex(size_t index) { return m_frameCache->frameSubsamplingLevelAtIndex(index); }
// ImageFrame metadata which forces caching or re-caching the ImageFrame.
@@ -98,7 +99,7 @@
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);
+ NativeImagePtr frameImageAtIndex(size_t index, const std::optional<SubsamplingLevel>& = { }, const std::optional<IntSize>& sizeForDrawing = { }, const GraphicsContext* targetContext = nullptr);
SubsamplingLevel maximumSubsamplingLevel();
SubsamplingLevel subsamplingLevelForScale(float);
Modified: trunk/Source/WebCore/platform/graphics/cg/ImageDecoderCG.cpp (213562 => 213563)
--- trunk/Source/WebCore/platform/graphics/cg/ImageDecoderCG.cpp 2017-03-08 03:46:19 UTC (rev 213562)
+++ trunk/Source/WebCore/platform/graphics/cg/ImageDecoderCG.cpp 2017-03-08 03:54:28 UTC (rev 213563)
@@ -58,41 +58,68 @@
const CFStringRef kCGImageSourceShouldPreferRGB32 = CFSTR("kCGImageSourceShouldPreferRGB32");
const CFStringRef kCGImageSourceSkipMetadata = CFSTR("kCGImageSourceSkipMetadata");
-static RetainPtr<CFDictionaryRef> createImageSourceOptions(SubsamplingLevel subsamplingLevel, DecodingMode decodingMode)
+static RetainPtr<CFMutableDictionaryRef> createImageSourceOptions()
{
RetainPtr<CFMutableDictionaryRef> options = adoptCF(CFDictionaryCreateMutable(nullptr, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
-
CFDictionarySetValue(options.get(), kCGImageSourceShouldCache, kCFBooleanTrue);
CFDictionarySetValue(options.get(), kCGImageSourceShouldPreferRGB32, kCFBooleanTrue);
CFDictionarySetValue(options.get(), kCGImageSourceSkipMetadata, kCFBooleanTrue);
-
- if (subsamplingLevel > SubsamplingLevel::First) {
- RetainPtr<CFNumberRef> subsampleNumber;
- subsamplingLevel = std::min(SubsamplingLevel::Last, std::max(SubsamplingLevel::First, subsamplingLevel));
- int subsampleInt = 1 << static_cast<int>(subsamplingLevel); // [0..3] => [1, 2, 4, 8]
- subsampleNumber = adoptCF(CFNumberCreate(nullptr, kCFNumberIntType, &subsampleInt));
- CFDictionarySetValue(options.get(), kCGImageSourceSubsampleFactor, subsampleNumber.get());
- }
-
- if (decodingMode == DecodingMode::Immediate) {
- CFDictionarySetValue(options.get(), kCGImageSourceShouldCacheImmediately, kCFBooleanTrue);
- CFDictionarySetValue(options.get(), kCGImageSourceCreateThumbnailFromImageAlways, kCFBooleanTrue);
- }
-
return options;
}
+
+static RetainPtr<CFMutableDictionaryRef> createImageSourceAsyncOptions()
+{
+ RetainPtr<CFMutableDictionaryRef> options = createImageSourceOptions();
+ CFDictionarySetValue(options.get(), kCGImageSourceShouldCacheImmediately, kCFBooleanTrue);
+ CFDictionarySetValue(options.get(), kCGImageSourceCreateThumbnailFromImageAlways, kCFBooleanTrue);
+ return options;
+}
-static RetainPtr<CFDictionaryRef> imageSourceOptions(SubsamplingLevel subsamplingLevel = SubsamplingLevel::Default, DecodingMode decodingMode = DecodingMode::OnDemand)
+static RetainPtr<CFMutableDictionaryRef> appendImageSourceOption(RetainPtr<CFMutableDictionaryRef>&& options, SubsamplingLevel subsamplingLevel)
{
- if (subsamplingLevel > SubsamplingLevel::First)
- return createImageSourceOptions(subsamplingLevel, decodingMode);
+ RetainPtr<CFNumberRef> subsampleNumber;
+ subsamplingLevel = std::min(SubsamplingLevel::Last, std::max(SubsamplingLevel::First, subsamplingLevel));
+ int subsampleInt = 1 << static_cast<int>(subsamplingLevel); // [0..3] => [1, 2, 4, 8]
+ subsampleNumber = adoptCF(CFNumberCreate(nullptr, kCFNumberIntType, &subsampleInt));
+ CFDictionarySetValue(options.get(), kCGImageSourceSubsampleFactor, subsampleNumber.get());
+ return WTFMove(options);
+}
- static NeverDestroyed<RetainPtr<CFDictionaryRef>> optionsOnDemand = createImageSourceOptions(SubsamplingLevel::First, DecodingMode::OnDemand);
- static NeverDestroyed<RetainPtr<CFDictionaryRef>> optionsImmediate = createImageSourceOptions(SubsamplingLevel::First, DecodingMode::Immediate);
+static RetainPtr<CFMutableDictionaryRef> appendImageSourceOption(RetainPtr<CFMutableDictionaryRef>&& options, const IntSize& sizeForDrawing)
+{
+ unsigned maxPixelSize = std::max(sizeForDrawing.width(), sizeForDrawing.height());
+ RetainPtr<CFNumberRef> maxPixelSizeNumber = adoptCF(CFNumberCreate(nullptr, kCFNumberIntType, &maxPixelSize));
+ CFDictionarySetValue(options.get(), kCGImageSourceThumbnailMaxPixelSize, maxPixelSizeNumber.get());
+ return WTFMove(options);
+}
+
+static RetainPtr<CFMutableDictionaryRef> appendImageSourceOptions(RetainPtr<CFMutableDictionaryRef>&& options, SubsamplingLevel subsamplingLevel, const std::optional<IntSize>& sizeForDrawing)
+{
+ if (subsamplingLevel != SubsamplingLevel::Default)
+ options = appendImageSourceOption(WTFMove(options), subsamplingLevel);
+
+ if (sizeForDrawing)
+ options = appendImageSourceOption(WTFMove(options), sizeForDrawing.value());
- return decodingMode == DecodingMode::OnDemand ? optionsOnDemand : optionsImmediate;
+ return WTFMove(options);
}
+
+static RetainPtr<CFDictionaryRef> imageSourceOptions(SubsamplingLevel subsamplingLevel = SubsamplingLevel::Default)
+{
+ static NeverDestroyed<RetainPtr<CFMutableDictionaryRef>> options = createImageSourceOptions();
+ if (subsamplingLevel == SubsamplingLevel::Default)
+ return options.get();
+ return appendImageSourceOption(adoptCF(CFDictionaryCreateMutableCopy(nullptr, 0, options.get().get())), subsamplingLevel);
+}
+static RetainPtr<CFDictionaryRef> imageSourceAsyncOptions(SubsamplingLevel subsamplingLevel = SubsamplingLevel::Default, const std::optional<IntSize>& sizeForDrawing = { })
+{
+ static NeverDestroyed<RetainPtr<CFMutableDictionaryRef>> options = createImageSourceAsyncOptions();
+ if (subsamplingLevel == SubsamplingLevel::Default && !sizeForDrawing)
+ return options.get();
+ return appendImageSourceOptions(adoptCF(CFDictionaryCreateMutableCopy(nullptr, 0, options.get().get())), subsamplingLevel, sizeForDrawing);
+}
+
static ImageOrientation orientationFromProperties(CFDictionaryRef imageProperties)
{
ASSERT(imageProperties);
@@ -339,17 +366,29 @@
return (frameSize.area() * 4).unsafeGet();
}
-NativeImagePtr ImageDecoder::createFrameImageAtIndex(size_t index, SubsamplingLevel subsamplingLevel, DecodingMode decodingMode) const
+NativeImagePtr ImageDecoder::createFrameImageAtIndex(size_t index, SubsamplingLevel subsamplingLevel, const std::optional<IntSize>& sizeForDrawing) const
{
LOG(Images, "ImageDecoder %p createFrameImageAtIndex %lu", this, index);
-
- RetainPtr<CFDictionaryRef> options = imageSourceOptions(subsamplingLevel, decodingMode);
+ RetainPtr<CFDictionaryRef> options;
RetainPtr<CGImageRef> image;
- if (decodingMode == DecodingMode::OnDemand)
+ if (!sizeForDrawing) {
+ // Decode an image synchronously for its native size.
+ options = imageSourceOptions(subsamplingLevel);
image = adoptCF(CGImageSourceCreateImageAtIndex(m_nativeDecoder.get(), index, options.get()));
- else
+ } else {
+ IntSize size = frameSizeAtIndex(index, subsamplingLevel);
+
+ if (size.unclampedArea() < sizeForDrawing.value().unclampedArea()) {
+ // Decode an image asynchronously for its native size.
+ options = imageSourceAsyncOptions(subsamplingLevel);
+ } else {
+ // Decode an image asynchronously for sizeForDrawing since it is smaller than the image native size.
+ options = imageSourceAsyncOptions(subsamplingLevel, sizeForDrawing);
+ }
+
image = adoptCF(CGImageSourceCreateThumbnailAtIndex(m_nativeDecoder.get(), index, options.get()));
+ }
#if PLATFORM(IOS)
// <rdar://problem/7371198> - CoreGraphics changed the default caching behaviour in iOS 4.0 to kCGImageCachingTransient
Modified: trunk/Source/WebCore/platform/graphics/cg/ImageDecoderCG.h (213562 => 213563)
--- trunk/Source/WebCore/platform/graphics/cg/ImageDecoderCG.h 2017-03-08 03:46:19 UTC (rev 213562)
+++ trunk/Source/WebCore/platform/graphics/cg/ImageDecoderCG.h 2017-03-08 03:54:28 UTC (rev 213563)
@@ -62,7 +62,7 @@
bool frameAllowSubsamplingAtIndex(size_t) const;
unsigned frameBytesAtIndex(size_t, SubsamplingLevel = SubsamplingLevel::Default) const;
- NativeImagePtr createFrameImageAtIndex(size_t, SubsamplingLevel = SubsamplingLevel::Default, DecodingMode = DecodingMode::OnDemand) const;
+ NativeImagePtr createFrameImageAtIndex(size_t, SubsamplingLevel = SubsamplingLevel::Default, const std::optional<IntSize>& sizeForDrawing = { }) const;
void setData(SharedBuffer&, bool allDataReceived);
bool isAllDataReceived() const { return m_isAllDataReceived; }
Modified: trunk/Source/WebCore/platform/graphics/win/ImageDecoderDirect2D.cpp (213562 => 213563)
--- trunk/Source/WebCore/platform/graphics/win/ImageDecoderDirect2D.cpp 2017-03-08 03:46:19 UTC (rev 213562)
+++ trunk/Source/WebCore/platform/graphics/win/ImageDecoderDirect2D.cpp 2017-03-08 03:54:28 UTC (rev 213563)
@@ -180,7 +180,7 @@
m_renderTarget = renderTarget;
}
-NativeImagePtr ImageDecoder::createFrameImageAtIndex(size_t index, SubsamplingLevel subsamplingLevel, DecodingMode) const
+NativeImagePtr ImageDecoder::createFrameImageAtIndex(size_t index, SubsamplingLevel subsamplingLevel, const std::optional<IntSize>&) const
{
if (!m_nativeDecoder || !m_renderTarget)
return nullptr;
Modified: trunk/Source/WebCore/platform/graphics/win/ImageDecoderDirect2D.h (213562 => 213563)
--- trunk/Source/WebCore/platform/graphics/win/ImageDecoderDirect2D.h 2017-03-08 03:46:19 UTC (rev 213562)
+++ trunk/Source/WebCore/platform/graphics/win/ImageDecoderDirect2D.h 2017-03-08 03:54:28 UTC (rev 213563)
@@ -67,7 +67,7 @@
bool frameAllowSubsamplingAtIndex(size_t) const;
unsigned frameBytesAtIndex(size_t, SubsamplingLevel = SubsamplingLevel::Default) const;
- NativeImagePtr createFrameImageAtIndex(size_t, SubsamplingLevel = SubsamplingLevel::Default, DecodingMode = DecodingMode::OnDemand) const;
+ NativeImagePtr createFrameImageAtIndex(size_t, SubsamplingLevel = SubsamplingLevel::Default, const std::optional<IntSize>& sizeForDraw = { }) const;
void setData(SharedBuffer&, bool allDataReceived);
bool isAllDataReceived() const { return m_isAllDataReceived; }
Modified: trunk/Source/WebCore/platform/image-decoders/ImageDecoder.cpp (213562 => 213563)
--- trunk/Source/WebCore/platform/image-decoders/ImageDecoder.cpp 2017-03-08 03:46:19 UTC (rev 213562)
+++ trunk/Source/WebCore/platform/image-decoders/ImageDecoder.cpp 2017-03-08 03:54:28 UTC (rev 213563)
@@ -207,7 +207,7 @@
return duration;
}
-NativeImagePtr ImageDecoder::createFrameImageAtIndex(size_t index, SubsamplingLevel, DecodingMode)
+NativeImagePtr ImageDecoder::createFrameImageAtIndex(size_t index, SubsamplingLevel, const std::optional<IntSize>&)
{
// Zero-height images can cause problems for some ports. If we have an empty image dimension, just bail.
if (size().isEmpty())
Modified: trunk/Source/WebCore/platform/image-decoders/ImageDecoder.h (213562 => 213563)
--- trunk/Source/WebCore/platform/image-decoders/ImageDecoder.h 2017-03-08 03:46:19 UTC (rev 213562)
+++ trunk/Source/WebCore/platform/image-decoders/ImageDecoder.h 2017-03-08 03:54:28 UTC (rev 213563)
@@ -137,7 +137,7 @@
float frameDurationAtIndex(size_t);
- NativeImagePtr createFrameImageAtIndex(size_t, SubsamplingLevel = SubsamplingLevel::Default, DecodingMode = DecodingMode::OnDemand);
+ NativeImagePtr createFrameImageAtIndex(size_t, SubsamplingLevel = SubsamplingLevel::Default, const std::optional<IntSize>& sizeForDraw = { });
void setIgnoreGammaAndColorProfile(bool flag) { m_ignoreGammaAndColorProfile = flag; }
bool ignoresGammaAndColorProfile() const { return m_ignoreGammaAndColorProfile; }