Diff
Modified: trunk/Source/WebCore/ChangeLog (198781 => 198782)
--- trunk/Source/WebCore/ChangeLog 2016-03-29 15:42:46 UTC (rev 198781)
+++ trunk/Source/WebCore/ChangeLog 2016-03-29 16:18:25 UTC (rev 198782)
@@ -1,3 +1,184 @@
+2016-03-29 Said Abou-Hallawa <sabouhallawa@apple,com>
+
+ Create a CG ImageDecoder class instead of defining it as CGImageSourceRef
+ https://bugs.webkit.org/show_bug.cgi?id=155422
+
+ Reviewed by Simon Fraser.
+
+ Move the image CG decoding code from the class ImageSource out to a new
+ class named ImageDecoder. The purpose of this split is to unify the code
+ of the ImageSource for all platforms. This class should be a container
+ for the ImageDecoder. All the direct frame manipulation like querying the
+ frame metadata or creating a frame image should be the responsibility of
+ the ImageDecoder. The ImageSource will be responsible of the image frame
+ caching. When responding to a frame metadata query, for example. the
+ ImageSource checks its cache first. If an entry does not exist for the
+ requested frame, the ImageSource will cache the image and the metadata
+ of this frame. The ImageSource will respond at the end from the image
+ frame cache.
+
+ The plan after this patch is is the following:
+ -- Move the new class to separate files
+ -- Merge the ImageSource.cpp and ImageSourceCG.cpp. in one file
+ -- Move caching the FrameData from BitmapImage to ImageSource.
+
+ * loader/cache/CachedImage.cpp:
+ (WebCore::CachedImage::imageSizeForRenderer):
+ BitmapImage::sizeRespectingOrientation() does not take any argument now.
+ Fix the call to this function and delete the conditionally compiled code
+ since the code is the same for the two cases.
+
+ * platform/graphics/BitmapImage.cpp:
+ (WebCore::BitmapImage::updateSize):
+ (WebCore::BitmapImage::sizeRespectingOrientation):
+ (WebCore::BitmapImage::frameImageAtIndex):
+ (WebCore::BitmapImage::BitmapImage):
+ An image can have two sizes: size() and sizeRespectingOrientation(). The
+ sizeRespectingOrientation() is the transpose of size() iff the image
+ orientation has usesWidthAsHeight() is true. So there is no need for the
+ ImageOrientationDescription argument. So there is no need for the members
+ m_imageOrientation or m_shouldRespectImageOrientation. Also move
+ m_allowSubsampling and m_minimumSubsamplingLevel (which should be named
+ m_maximumSubsamplingLevel) to ImageSource instead.
+
+ (WebCore::BitmapImage::frameOrientationAtIndex): Replace DefaultImageOrientation
+ by ImageOrientation().
+
+ (WebCore::BitmapImage::dump): Move dumping the image metadata to the
+ ImageSource.
+
+ * platform/graphics/BitmapImage.h:
+
+ * platform/graphics/GraphicsContext.h:
+ * platform/graphics/ImageOrientation.h:
+ (WebCore::ImageOrientation::ImageOrientation):
+ (WebCore::ImageOrientation::fromEXIFValue):
+ (WebCore::ImageOrientation::operator ImageOrientationEnum):
+ Add a casting operator to ImageOrientation so it can be dumped as enum
+ value. Also add a default constructor and make the other constructor be
+ explicit. All the rvalues DefaultImageOrientation should be replaced by
+ ImageOrientation().
+
+ * platform/graphics/ImageSource.cpp:
+ (WebCore::ImageSource::ImageSource):
+ (WebCore::ImageSource::clear):
+ m_decoder is now a unique_ptr. To release it, assign it to nullptr.
+
+ (WebCore::ImageSource::ensureDecoderIsCreated): Ensure m_decoder is created.
+
+ (WebCore::ImageSource::setData): Call ensureDecoderIsCreated() before
+ actually setting the data.
+
+ (WebCore::ImageSource::isSizeAvailable): Use initialized();
+
+ (WebCore::ImageSource::size):
+ (WebCore::ImageSource::sizeRespectingOrientation):
+ (WebCore::ImageSource::frameSizeAtIndex):
+ These functions return the size of the image.
+
+ (WebCore::ImageSource::getHotSpot):
+ (WebCore::ImageSource::repetitionCount):
+ (WebCore::ImageSource::frameCount):
+ (WebCore::ImageSource::createFrameImageAtIndex):
+ (WebCore::ImageSource::frameDurationAtIndex):
+ (WebCore::ImageSource::orientationAtIndex):
+ (WebCore::ImageSource::frameHasAlphaAtIndex):
+ (WebCore::ImageSource::frameIsCompleteAtIndex):
+ (WebCore::ImageSource::frameBytesAtIndex):
+ Check for initialized() instead of checking m_decoder.
+
+ (WebCore::ImageSource::dump): Dump the image metadata.
+
+ (WebCore::ImageSource::initialized): Deleted.
+
+ * platform/graphics/ImageSource.h: The image decoder is now named
+ ImageDecoder for all platforms.
+
+ (WebCore::ImageSource::initialized): Moved to the header file.
+
+ (WebCore::ImageSource::setAllowSubsampling): Moved from BitmapImage.
+
+ * platform/graphics/cairo/BitmapImageCairo.cpp:
+ (WebCore::BitmapImage::BitmapImage):
+ (WebCore::BitmapImage::determineMinimumSubsamplingLevel): Deleted.
+ Delete initializing m_minimumSubsamplingLevel and determineMinimumSubsamplingLevel()
+ since they are moved to ImageSource.
+
+ * platform/graphics/cg/BitmapImageCG.cpp:
+ (WebCore::BitmapImage::BitmapImage):
+ (WebCore::BitmapImage::determineMinimumSubsamplingLevel): Deleted.
+ Delete members and methods which are now owned and calculated by ImageSource.
+
+ * platform/graphics/cg/ImageSourceCG.cpp:
+ (WebCore::ImageDecoder::create): Returns a CG ImageDecoder object.
+
+ (WebCore::orientationFromProperties): Replace DefaultImageOrientation
+ by ImageOrientation().
+
+ (WebCore::ImageDecoder::ImageDecoder): Creates a native CG image decoder.
+
+ (WebCore::ImageDecoder::~ImageDecoder): Releases the native CG image decoder.
+
+ (WebCore::ImageDecoder::subsamplingLevelForScale): Moved from ImageSource.
+ A new argument named 'maximumSubsamplingLevel' is added to low filter the
+ return value.
+
+ (WebCore::ImageDecoder::bytesDecodedToDetermineProperties):
+ (WebCore::ImageDecoder::filenameExtension):
+ (WebCore::ImageDecoder::isSizeAvailable):
+ (WebCore::ImageDecoder::size):
+ (WebCore::ImageDecoder::frameCount):
+ (WebCore::ImageDecoder::repetitionCount):
+ (WebCore::ImageDecoder::hotSpot):
+ (WebCore::ImageDecoder::frameSizeAtIndex):
+ (WebCore::ImageDecoder::frameIsCompleteAtIndex):
+ (WebCore::ImageDecoder::orientationAtIndex):
+ (WebCore::ImageDecoder::frameDurationAtIndex):
+ (WebCore::ImageDecoder::allowSubsamplingOfFrameAtIndex):
+ (WebCore::ImageDecoder::frameHasAlphaAtIndex):
+ (WebCore::ImageDecoder::frameBytesAtIndex):
+ (WebCore::ImageDecoder::createFrameImageAtIndex):
+ (WebCore::ImageDecoder::setData):
+ The code of these function was moved from the functions of ImageSource.
+
+ (WebCore::ImageSource::ImageSource):
+ (WebCore::ImageSource::~ImageSource):
+ (WebCore::ImageSource::clear):
+ (WebCore::ImageSource::ensureDecoderIsCreated):
+ (WebCore::ImageSource::setData):
+ (WebCore::ImageSource::filenameExtension):
+ (WebCore::ImageSource::calculateMaximumSubsamplingLevel):
+ (WebCore::ImageSource::maximumSubsamplingLevel):
+ (WebCore::ImageSource::subsamplingLevelForScale):
+ (WebCore::ImageSource::isSizeAvailable):
+ (WebCore::ImageSource::allowSubsamplingOfFrameAtIndex):
+ (WebCore::ImageSource::frameSizeAtIndex):
+ (WebCore::ImageSource::orientationAtIndex):
+ (WebCore::ImageSource::size):
+ (WebCore::ImageSource::sizeRespectingOrientation):
+ (WebCore::ImageSource::getHotSpot):
+ (WebCore::ImageSource::bytesDecodedToDetermineProperties):
+ (WebCore::ImageSource::repetitionCount):
+ (WebCore::ImageSource::frameCount):
+ (WebCore::ImageSource::createFrameImageAtIndex):
+ (WebCore::ImageSource::frameIsCompleteAtIndex):
+ (WebCore::ImageSource::frameDurationAtIndex):
+ (WebCore::ImageSource::frameHasAlphaAtIndex):
+ (WebCore::ImageSource::frameBytesAtIndex):
+ Call m_decoder's function to do the real work.
+
+ (WebCore::ImageSource::dump): Dump the image metadata.
+
+ (WebCore::ImageSource::initialized): Deleted.
+
+ * platform/image-decoders/ImageDecoder.cpp:
+ (WebCore::ImageDecoder::create):
+ * platform/image-decoders/ImageDecoder.h:
+ Change the return of ImageDecoder::create() to be unique_ptr.
+
+ * platform/mac/DragImageMac.mm:
+ (WebCore::createDragImageFromImage): Delete unneeded argument.
+
2016-03-29 Eric Carlson <[email protected]>
media/track/track-remove-track.html is flaky, crashing and failing
Modified: trunk/Source/WebCore/loader/cache/CachedImage.cpp (198781 => 198782)
--- trunk/Source/WebCore/loader/cache/CachedImage.cpp 2016-03-29 15:42:46 UTC (rev 198781)
+++ trunk/Source/WebCore/loader/cache/CachedImage.cpp 2016-03-29 16:18:25 UTC (rev 198782)
@@ -272,22 +272,14 @@
if (!m_image)
return LayoutSize();
- LayoutSize imageSize(m_image->size());
+ LayoutSize imageSize;
-#if ENABLE(CSS_IMAGE_ORIENTATION)
- if (renderer && is<BitmapImage>(*m_image)) {
- ImageOrientationDescription orientationDescription(renderer->shouldRespectImageOrientation(), renderer->style().imageOrientation());
- if (orientationDescription.respectImageOrientation() == RespectImageOrientation)
- imageSize = LayoutSize(downcast<BitmapImage>(*m_image).sizeRespectingOrientation(orientationDescription));
- }
-#else
- if (is<BitmapImage>(*m_image) && (renderer && renderer->shouldRespectImageOrientation() == RespectImageOrientation))
+ if (is<BitmapImage>(*m_image) && renderer && renderer->shouldRespectImageOrientation() == RespectImageOrientation)
imageSize = LayoutSize(downcast<BitmapImage>(*m_image).sizeRespectingOrientation());
-#endif // ENABLE(CSS_IMAGE_ORIENTATION)
-
- else if (is<SVGImage>(*m_image) && sizeType == UsedSize) {
+ else if (is<SVGImage>(*m_image) && sizeType == UsedSize)
imageSize = LayoutSize(m_svgImageCache->imageSizeForRenderer(renderer));
- }
+ else
+ imageSize = LayoutSize(m_image->size());
if (multiplier == 1.0f)
return imageSize;
Modified: trunk/Source/WebCore/platform/graphics/BitmapImage.cpp (198781 => 198782)
--- trunk/Source/WebCore/platform/graphics/BitmapImage.cpp 2016-03-29 15:42:46 UTC (rev 198781)
+++ trunk/Source/WebCore/platform/graphics/BitmapImage.cpp 2016-03-29 16:18:25 UTC (rev 198782)
@@ -47,9 +47,6 @@
BitmapImage::BitmapImage(ImageObserver* observer)
: Image(observer)
- , m_minimumSubsamplingLevel(0)
- , m_imageOrientation(OriginTopLeft)
- , m_shouldRespectImageOrientation(false)
, m_currentFrame(0)
, m_repetitionCount(cAnimationNone)
, m_repetitionCountStatus(Unknown)
@@ -62,9 +59,6 @@
// FIXME: We should expose a setting to enable/disable progressive loading remove the PLATFORM(IOS)-guard.
, m_progressiveLoadChunkTime(0)
, m_progressiveLoadChunkCount(0)
- , m_allowSubsampling(true)
-#else
- , m_allowSubsampling(false)
#endif
, m_isSolidColor(false)
, m_checkedForSolidColor(false)
@@ -236,20 +230,15 @@
imageObserver()->decodedSizeChanged(this, deltaBytes);
}
-void BitmapImage::updateSize(ImageOrientationDescription description) const
+void BitmapImage::updateSize() const
{
if (!m_sizeAvailable || m_haveSize)
return;
- m_size = m_source.size(description);
- m_sizeRespectingOrientation = m_source.size(ImageOrientationDescription(RespectImageOrientation, description.imageOrientation()));
+ m_size = m_source.size();
+ m_sizeRespectingOrientation = m_source.sizeRespectingOrientation();
- m_imageOrientation = static_cast<unsigned>(description.imageOrientation());
- m_shouldRespectImageOrientation = static_cast<unsigned>(description.respectImageOrientation());
-
m_haveSize = true;
-
- determineMinimumSubsamplingLevel();
didDecodeProperties();
}
@@ -259,9 +248,9 @@
return m_size;
}
-IntSize BitmapImage::sizeRespectingOrientation(ImageOrientationDescription description) const
+IntSize BitmapImage::sizeRespectingOrientation() const
{
- updateSize(description);
+ updateSize();
return m_sizeRespectingOrientation;
}
@@ -391,7 +380,7 @@
if (index >= frameCount())
return nullptr;
- SubsamplingLevel subsamplingLevel = std::min(m_source.subsamplingLevelForScale(presentationScaleHint), m_minimumSubsamplingLevel);
+ SubsamplingLevel subsamplingLevel = m_source.subsamplingLevelForScale(presentationScaleHint);
// We may have cached a frame with a higher subsampling level, in which case we need to
// re-decode with a lower level.
@@ -452,7 +441,7 @@
ImageOrientation BitmapImage::frameOrientationAtIndex(size_t index)
{
if (!ensureFrameIsCached(index, CacheMetadataOnly))
- return DefaultImageOrientation;
+ return ImageOrientation();
if (m_frames[index].m_haveMetadata)
return m_frames[index].m_orientation;
@@ -710,13 +699,10 @@
ts.dumpProperty("current-frame", m_currentFrame);
}
- if (allowSubsampling())
- ts.dumpProperty("allow-subsampling", allowSubsampling());
if (m_isSolidColor)
ts.dumpProperty("solid-color", m_isSolidColor);
- if (m_imageOrientation != OriginTopLeft)
- ts.dumpProperty("orientation", m_imageOrientation);
+ m_source.dump(ts);
}
}
Modified: trunk/Source/WebCore/platform/graphics/BitmapImage.h (198781 => 198782)
--- trunk/Source/WebCore/platform/graphics/BitmapImage.h 2016-03-29 15:42:46 UTC (rev 198781)
+++ trunk/Source/WebCore/platform/graphics/BitmapImage.h 2016-03-29 16:18:25 UTC (rev 198782)
@@ -123,7 +123,7 @@
// FloatSize due to override.
FloatSize size() const override;
- IntSize sizeRespectingOrientation(ImageOrientationDescription = ImageOrientationDescription()) const;
+ IntSize sizeRespectingOrientation() const;
bool getHotSpot(IntPoint&) const override;
@@ -179,16 +179,14 @@
bool canAnimate();
- bool allowSubsampling() const { return m_allowSubsampling; }
- void setAllowSubsampling(bool allowSubsampling) { m_allowSubsampling = allowSubsampling; }
+ void setAllowSubsampling(bool allowSubsampling) { m_source.setAllowSubsampling(allowSubsampling); }
size_t currentFrame() const { return m_currentFrame; }
private:
bool isBitmapImage() const override { return true; }
- void updateSize(ImageOrientationDescription = ImageOrientationDescription()) const;
- void determineMinimumSubsamplingLevel() const;
+ void updateSize() const;
protected:
enum RepetitionCountStatus {
@@ -295,11 +293,6 @@
mutable IntSize m_size; // The size to use for the overall image (will just be the size of the first image).
mutable IntSize m_sizeRespectingOrientation;
- mutable SubsamplingLevel m_minimumSubsamplingLevel;
-
- mutable unsigned m_imageOrientation : 4; // ImageOrientationEnum
- mutable unsigned m_shouldRespectImageOrientation : 1; // RespectImageOrientationEnum
-
size_t m_currentFrame; // The index of the current frame of animation.
Vector<FrameData, 1> m_frames; // An array of the cached frames of the animation. We have to ref frames to pin them in the cache.
@@ -327,8 +320,6 @@
double m_progressiveLoadChunkTime;
uint16_t m_progressiveLoadChunkCount;
#endif
-
- bool m_allowSubsampling : 1; // Whether we should attempt subsampling if this image is very large.
bool m_isSolidColor : 1; // Whether or not we are a 1x1 solid image.
bool m_checkedForSolidColor : 1; // Whether we've checked the frame for solid color.
Modified: trunk/Source/WebCore/platform/graphics/GraphicsContext.h (198781 => 198782)
--- trunk/Source/WebCore/platform/graphics/GraphicsContext.h 2016-03-29 15:42:46 UTC (rev 198781)
+++ trunk/Source/WebCore/platform/graphics/GraphicsContext.h 2016-03-29 16:18:25 UTC (rev 198782)
@@ -302,7 +302,7 @@
const GraphicsContextState& state() const { return m_state; }
#if USE(CG) || USE(CAIRO)
- WEBCORE_EXPORT void drawNativeImage(const NativeImagePtr&, const FloatSize& selfSize, const FloatRect& destRect, const FloatRect& srcRect, CompositeOperator = CompositeSourceOver, BlendMode = BlendModeNormal, ImageOrientation = DefaultImageOrientation);
+ WEBCORE_EXPORT void drawNativeImage(const NativeImagePtr&, const FloatSize& selfSize, const FloatRect& destRect, const FloatRect& srcRect, CompositeOperator = CompositeSourceOver, BlendMode = BlendModeNormal, ImageOrientation = ImageOrientation());
#endif
#if USE(CG)
Modified: trunk/Source/WebCore/platform/graphics/ImageOrientation.h (198781 => 198782)
--- trunk/Source/WebCore/platform/graphics/ImageOrientation.h 2016-03-29 15:42:46 UTC (rev 198781)
+++ trunk/Source/WebCore/platform/graphics/ImageOrientation.h 2016-03-29 16:18:25 UTC (rev 198782)
@@ -84,7 +84,12 @@
class ImageOrientation {
public:
- ImageOrientation(ImageOrientationEnum orientation = DefaultImageOrientation)
+ ImageOrientation()
+ : m_orientation(DefaultImageOrientation)
+ {
+ }
+
+ explicit ImageOrientation(ImageOrientationEnum orientation)
: m_orientation(orientation)
{
}
@@ -101,14 +106,16 @@
{
// Values direct from images may be invalid, in which case we use the default.
if (exifValue < OriginTopLeft || exifValue > OriginLeftBottom)
- return DefaultImageOrientation;
- return static_cast<ImageOrientationEnum>(exifValue);
+ return ImageOrientation();
+ return ImageOrientation(static_cast<ImageOrientationEnum>(exifValue));
}
// This transform can be used for drawing an image according to the orientation.
// It should be used in a right-handed coordinate system.
AffineTransform transformFromDefault(const FloatSize& drawnSize) const;
+ inline operator ImageOrientationEnum() const { return m_orientation; }
+
inline bool operator==(const ImageOrientation& other) const { return other.m_orientation == m_orientation; }
inline bool operator!=(const ImageOrientation& other) const { return !(*this == other); }
Modified: trunk/Source/WebCore/platform/graphics/ImageSource.cpp (198781 => 198782)
--- trunk/Source/WebCore/platform/graphics/ImageSource.cpp 2016-03-29 15:42:46 UTC (rev 198781)
+++ trunk/Source/WebCore/platform/graphics/ImageSource.cpp 2016-03-29 16:18:25 UTC (rev 198782)
@@ -43,8 +43,7 @@
#endif
ImageSource::ImageSource(ImageSource::AlphaOption alphaOption, ImageSource::GammaAndColorProfileOption gammaAndColorProfileOption)
- : m_decoder(0)
- , m_alphaOption(alphaOption)
+ : m_alphaOption(alphaOption)
, m_gammaAndColorProfileOption(gammaAndColorProfileOption)
{
}
@@ -62,29 +61,38 @@
return;
}
- delete m_decoder;
- m_decoder = 0;
+ m_decoder = nullptr;
+
if (data)
setData(data, allDataReceived);
}
-bool ImageSource::initialized() const
+void ImageSource::ensureDecoderIsCreated(SharedBuffer* data)
{
- return m_decoder;
-}
-
-void ImageSource::setData(SharedBuffer* data, bool allDataReceived)
-{
+ if (initialized())
+ return;
+
// Make the decoder by sniffing the bytes.
// This method will examine the data and instantiate an instance of the appropriate decoder plugin.
// If insufficient bytes are available to determine the image type, no decoder plugin will be
// made.
- if (!m_decoder) {
- m_decoder = static_cast<NativeImageDecoderPtr>(NativeImageDecoder::create(*data, m_alphaOption, m_gammaAndColorProfileOption));
+ m_decoder = ImageDecoder::create(*data, m_alphaOption, m_gammaAndColorProfileOption);
#if ENABLE(IMAGE_DECODER_DOWN_SAMPLING)
- if (m_decoder && s_maxPixelsPerDecodedImage)
- m_decoder->setMaxNumPixels(s_maxPixelsPerDecodedImage);
+ if (m_decoder && s_maxPixelsPerDecodedImage)
+ m_decoder->setMaxNumPixels(s_maxPixelsPerDecodedImage);
#endif
+}
+
+void ImageSource::setData(SharedBuffer* data, bool allDataReceived)
+{
+ if (!data)
+ return;
+
+ ensureDecoderIsCreated(data);
+
+ if (!initialized()) {
+ ASSERT_NOT_REACHED();
+ return;
}
if (m_decoder)
@@ -108,29 +116,33 @@
bool ImageSource::isSizeAvailable()
{
- return m_decoder && m_decoder->isSizeAvailable();
+ return initialized() && m_decoder->isSizeAvailable();
}
-IntSize ImageSource::size(ImageOrientationDescription description) const
+IntSize ImageSource::size() const
{
- return frameSizeAtIndex(0, 0, description);
+ return frameSizeAtIndex(0, 0);
}
-IntSize ImageSource::frameSizeAtIndex(size_t index, SubsamplingLevel, ImageOrientationDescription description) const
+IntSize ImageSource::sizeRespectingOrientation() const
{
- if (!m_decoder)
- return IntSize();
+ return frameSizeAtIndex(0, 0, RespectImageOrientation);
+}
+IntSize ImageSource::frameSizeAtIndex(size_t index, SubsamplingLevel, RespectImageOrientationEnum shouldRespectImageOrientation) const
+{
+ if (!initialized())
+ return { };
+
IntSize size = m_decoder->frameSizeAtIndex(index);
- if ((description.respectImageOrientation() == RespectImageOrientation) && m_decoder->orientation().usesWidthAsHeight())
- return IntSize(size.height(), size.width());
-
- return size;
+ ImageOrientation orientation = m_decoder->orientation();
+
+ return shouldRespectImageOrientation == RespectImageOrientation && orientation.usesWidthAsHeight() ? size.transposedSize() : size;
}
bool ImageSource::getHotSpot(IntPoint& hotSpot) const
{
- return m_decoder ? m_decoder->hotSpot(hotSpot) : false;
+ return initialized() && m_decoder->hotSpot(hotSpot);
}
size_t ImageSource::bytesDecodedToDetermineProperties() const
@@ -140,28 +152,28 @@
int ImageSource::repetitionCount()
{
- return m_decoder ? m_decoder->repetitionCount() : cAnimationNone;
+ return initialized() ? m_decoder->repetitionCount() : cAnimationNone;
}
size_t ImageSource::frameCount() const
{
- return m_decoder ? m_decoder->frameCount() : 0;
+ return initialized() ? m_decoder->frameCount() : 0;
}
NativeImagePtr ImageSource::createFrameImageAtIndex(size_t index, SubsamplingLevel)
{
- if (!m_decoder)
+ if (!initialized())
return nullptr;
- ImageFrame* buffer = m_decoder->frameBufferAtIndex(index);
- if (!buffer || buffer->status() == ImageFrame::FrameEmpty)
- return nullptr;
-
// Zero-height images can cause problems for some ports. If we have an
// empty image dimension, just bail.
if (size().isEmpty())
return nullptr;
+ ImageFrame* buffer = m_decoder->frameBufferAtIndex(index);
+ if (!buffer || buffer->status() == ImageFrame::FrameEmpty)
+ return nullptr;
+
// Return the buffer contents as a native image. For some ports, the data
// is already in a native container, and this just increments its refcount.
return buffer->asNewNativeImage();
@@ -169,7 +181,7 @@
float ImageSource::frameDurationAtIndex(size_t index)
{
- if (!m_decoder)
+ if (!initialized())
return 0;
ImageFrame* buffer = m_decoder->frameBufferAtIndex(index);
@@ -188,19 +200,17 @@
ImageOrientation ImageSource::orientationAtIndex(size_t) const
{
- return m_decoder ? m_decoder->orientation() : DefaultImageOrientation;
+ return initialized() ? m_decoder->orientation() : ImageOrientation();
}
bool ImageSource::frameHasAlphaAtIndex(size_t index)
{
- if (!m_decoder)
- return true;
- return m_decoder->frameHasAlphaAtIndex(index);
+ return !initialized() || m_decoder->frameHasAlphaAtIndex(index);
}
bool ImageSource::frameIsCompleteAtIndex(size_t index)
{
- if (!m_decoder)
+ if (!initialized())
return false;
ImageFrame* buffer = m_decoder->frameBufferAtIndex(index);
@@ -209,11 +219,19 @@
unsigned ImageSource::frameBytesAtIndex(size_t index, SubsamplingLevel) const
{
- if (!m_decoder)
- return 0;
- return m_decoder->frameBytesAtIndex(index);
+ return initialized() ? m_decoder->frameBytesAtIndex(index) : 0;
}
+void ImageSource::dump(TextStream& ts) const
+{
+ if (m_allowSubsampling)
+ ts.dumpProperty("allow-subsampling", m_allowSubsampling);
+
+ ImageOrientation orientation = orientationAtIndex(0);
+ if (orientation != OriginTopLeft)
+ ts.dumpProperty("orientation", orientation);
}
+
+}
#endif // USE(CG)
Modified: trunk/Source/WebCore/platform/graphics/ImageSource.h (198781 => 198782)
--- trunk/Source/WebCore/platform/graphics/ImageSource.h 2016-03-29 15:42:46 UTC (rev 198781)
+++ trunk/Source/WebCore/platform/graphics/ImageSource.h 2016-03-29 16:18:25 UTC (rev 198782)
@@ -29,6 +29,7 @@
#include "ImageOrientation.h"
#include "NativeImagePtr.h"
+#include "TextStream.h"
#include <wtf/Forward.h>
#include <wtf/Noncopyable.h>
@@ -45,20 +46,8 @@
class IntPoint;
class IntSize;
class SharedBuffer;
-
-#if USE(CG)
-typedef CGImageSourceRef NativeImageDecoderPtr;
-#else
class ImageDecoder;
-typedef ImageDecoder* NativeImageDecoderPtr;
-#endif
-#if USE(CG)
-#define NativeImageDecoder ImageDecoder
-#else
-typedef ImageDecoder NativeImageDecoder;
-#endif
-
// Right now GIFs are the only recognized image format that supports animation.
// The animation system and the constants below are designed with this in mind.
// GIFs have an optional 16-bit unsigned loop count that describes how an
@@ -82,6 +71,7 @@
class ImageSource {
WTF_MAKE_NONCOPYABLE(ImageSource);
+ friend class BitmapImage;
public:
enum AlphaOption {
AlphaPremultiplied,
@@ -122,19 +112,24 @@
SharedBuffer* data = ""
bool allDataReceived = false);
- bool initialized() const;
+ bool initialized() const { return m_decoder.get(); }
void setData(SharedBuffer* data, bool allDataReceived);
String filenameExtension() const;
SubsamplingLevel subsamplingLevelForScale(float) const;
bool allowSubsamplingOfFrameAtIndex(size_t) const;
+ void setAllowSubsampling(bool allowSubsampling) { m_allowSubsampling = allowSubsampling; }
+ SubsamplingLevel maximumSubsamplingLevel() const;
bool isSizeAvailable();
+
// Always original size, without subsampling.
- IntSize size(ImageOrientationDescription = ImageOrientationDescription()) const;
+ IntSize size() const;
+ IntSize sizeRespectingOrientation() const;
+
// Size of optionally subsampled frame.
- IntSize frameSizeAtIndex(size_t, SubsamplingLevel = 0, ImageOrientationDescription = ImageOrientationDescription()) const;
+ IntSize frameSizeAtIndex(size_t, SubsamplingLevel = 0, RespectImageOrientationEnum = DoNotRespectImageOrientation) const;
bool getHotSpot(IntPoint&) const;
@@ -163,7 +158,17 @@
#endif
private:
- NativeImageDecoderPtr m_decoder;
+ void ensureDecoderIsCreated(SharedBuffer*);
+ SubsamplingLevel calculateMaximumSubsamplingLevel() const;
+ void dump(TextStream&) const;
+
+ std::unique_ptr<ImageDecoder> m_decoder;
+
+#if PLATFORM(IOS)
+ bool m_allowSubsampling { true };
+#else
+ bool m_allowSubsampling { false };
+#endif
#if !USE(CG)
AlphaOption m_alphaOption;
Modified: trunk/Source/WebCore/platform/graphics/cairo/BitmapImageCairo.cpp (198781 => 198782)
--- trunk/Source/WebCore/platform/graphics/cairo/BitmapImageCairo.cpp 2016-03-29 15:42:46 UTC (rev 198781)
+++ trunk/Source/WebCore/platform/graphics/cairo/BitmapImageCairo.cpp 2016-03-29 16:18:25 UTC (rev 198782)
@@ -41,7 +41,6 @@
BitmapImage::BitmapImage(RefPtr<cairo_surface_t>&& nativeImage, ImageObserver* observer)
: Image(observer)
, m_size(cairoSurfaceSize(nativeImage.get()))
- , m_minimumSubsamplingLevel(0)
, m_currentFrame(0)
, m_repetitionCount(cAnimationNone)
, m_repetitionCountStatus(Unknown)
@@ -122,11 +121,6 @@
imageObserver()->didDraw(this);
}
-void BitmapImage::determineMinimumSubsamplingLevel() const
-{
- m_minimumSubsamplingLevel = 0;
-}
-
void BitmapImage::checkForSolidColor()
{
m_isSolidColor = false;
Modified: trunk/Source/WebCore/platform/graphics/cg/BitmapImageCG.cpp (198781 => 198782)
--- trunk/Source/WebCore/platform/graphics/cg/BitmapImageCG.cpp 2016-03-29 15:42:46 UTC (rev 198781)
+++ trunk/Source/WebCore/platform/graphics/cg/BitmapImageCG.cpp 2016-03-29 16:18:25 UTC (rev 198782)
@@ -55,7 +55,6 @@
if (clearMetadata)
m_haveMetadata = false;
- m_orientation = DefaultImageOrientation;
m_subsamplingLevel = 0;
if (m_image) {
@@ -70,9 +69,6 @@
BitmapImage::BitmapImage(RetainPtr<CGImageRef>&& image, ImageObserver* observer)
: Image(observer)
- , m_minimumSubsamplingLevel(0)
- , m_imageOrientation(OriginTopLeft)
- , m_shouldRespectImageOrientation(false)
, m_currentFrame(0)
, m_repetitionCount(cAnimationNone)
, m_repetitionCountStatus(Unknown)
@@ -105,28 +101,6 @@
checkForSolidColor();
}
-void BitmapImage::determineMinimumSubsamplingLevel() const
-{
- if (!m_allowSubsampling)
- return;
-
- if (!m_source.allowSubsamplingOfFrameAtIndex(0))
- return;
-
- // Values chosen to be appropriate for iOS.
- const int cMaximumImageAreaBeforeSubsampling = 5 * 1024 * 1024;
- const SubsamplingLevel maxSubsamplingLevel = 3;
-
- SubsamplingLevel currentLevel = 0;
- for ( ; currentLevel <= maxSubsamplingLevel; ++currentLevel) {
- IntSize frameSize = m_source.frameSizeAtIndex(0, currentLevel);
- if (frameSize.area() < cMaximumImageAreaBeforeSubsampling)
- break;
- }
-
- m_minimumSubsamplingLevel = currentLevel;
-}
-
void BitmapImage::checkForSolidColor()
{
m_checkedForSolidColor = true;
Modified: trunk/Source/WebCore/platform/graphics/cg/ImageSourceCG.cpp (198781 => 198782)
--- trunk/Source/WebCore/platform/graphics/cg/ImageSourceCG.cpp 2016-03-29 15:42:46 UTC (rev 198781)
+++ trunk/Source/WebCore/platform/graphics/cg/ImageSourceCG.cpp 2016-03-29 16:18:25 UTC (rev 198782)
@@ -51,61 +51,53 @@
#endif
namespace WebCore {
+
+class ImageDecoder {
+public:
+ ImageDecoder();
+
+ static std::unique_ptr<ImageDecoder> create()
+ {
+ return std::make_unique<ImageDecoder>();
+ }
-const CFStringRef WebCoreCGImagePropertyAPNGUnclampedDelayTime = CFSTR("UnclampedDelayTime");
-const CFStringRef WebCoreCGImagePropertyAPNGDelayTime = CFSTR("DelayTime");
-const CFStringRef WebCoreCGImagePropertyAPNGLoopCount = CFSTR("LoopCount");
+ static size_t bytesDecodedToDetermineProperties();
+ static SubsamplingLevel subsamplingLevelForScale(float scale, SubsamplingLevel maximumSubsamplingLevel);
-const CFStringRef kCGImageSourceShouldPreferRGB32 = CFSTR("kCGImageSourceShouldPreferRGB32");
-const CFStringRef kCGImageSourceSkipMetadata = CFSTR("kCGImageSourceSkipMetadata");
+ String filenameExtension() const;
+ bool isSizeAvailable() const;
+
+ // Always original size, without subsampling.
+ IntSize size() const;
+ size_t frameCount() const;
+ int repetitionCount() const;
+ bool hotSpot(IntPoint& hotSpot) const;
-#if !PLATFORM(COCOA)
-size_t sharedBufferGetBytesAtPosition(void* info, void* buffer, off_t position, size_t count)
-{
- SharedBuffer* sharedBuffer = static_cast<SharedBuffer*>(info);
- size_t sourceSize = sharedBuffer->size();
- if (position >= sourceSize)
- return 0;
+ IntSize frameSizeAtIndex(size_t, SubsamplingLevel) const;
+ bool frameIsCompleteAtIndex(size_t) const;
+ ImageOrientation orientationAtIndex(size_t) const;
- const char* source = sharedBuffer->data() + position;
- size_t amount = std::min<size_t>(count, sourceSize - position);
- memcpy(buffer, source, amount);
- return amount;
-}
+ float frameDurationAtIndex(size_t) const;
+ bool frameHasAlphaAtIndex(size_t) const;
+ bool allowSubsamplingOfFrameAtIndex(size_t) const;
+ unsigned frameBytesAtIndex(size_t, SubsamplingLevel = 0) const;
-void sharedBufferRelease(void* info)
-{
- SharedBuffer* sharedBuffer = static_cast<SharedBuffer*>(info);
- sharedBuffer->deref();
-}
-#endif
+ NativeImagePtr createFrameImageAtIndex(size_t, SubsamplingLevel) const;
-ImageSource::ImageSource(ImageSource::AlphaOption, ImageSource::GammaAndColorProfileOption)
- : m_decoder(0)
-{
- // FIXME: AlphaOption and GammaAndColorProfileOption are ignored.
-}
+ void setData(CFDataRef, bool allDataReceived);
+ void setData(SharedBuffer*, bool allDataReceived);
-ImageSource::~ImageSource()
-{
- clear(true);
-}
+protected:
+ mutable IntSize m_size;
+ RetainPtr<CGImageSourceRef> m_nativeDecoder;
+};
-void ImageSource::clear(bool destroyAllFrames, size_t, SharedBuffer* data, bool allDataReceived)
-{
- // Recent versions of ImageIO discard previously decoded image frames if the client
- // application no longer holds references to them, so there's no need to throw away
- // the decoder unless we're explicitly asked to destroy all of the frames.
- if (!destroyAllFrames)
- return;
+const CFStringRef WebCoreCGImagePropertyAPNGUnclampedDelayTime = CFSTR("UnclampedDelayTime");
+const CFStringRef WebCoreCGImagePropertyAPNGDelayTime = CFSTR("DelayTime");
+const CFStringRef WebCoreCGImagePropertyAPNGLoopCount = CFSTR("LoopCount");
- if (m_decoder) {
- CFRelease(m_decoder);
- m_decoder = 0;
- }
- if (data)
- setData(data, allDataReceived);
-}
+const CFStringRef kCGImageSourceShouldPreferRGB32 = CFSTR("kCGImageSourceShouldPreferRGB32");
+const CFStringRef kCGImageSourceSkipMetadata = CFSTR("kCGImageSourceSkipMetadata");
static RetainPtr<CFDictionaryRef> createImageSourceOptions(SubsamplingLevel subsamplingLevel)
{
@@ -135,173 +127,99 @@
return options;
}
-bool ImageSource::initialized() const
-{
- return m_decoder;
-}
-
-void ImageSource::setData(SharedBuffer* data, bool allDataReceived)
-{
-#if PLATFORM(COCOA)
- if (!m_decoder)
- m_decoder = CGImageSourceCreateIncremental(0);
- // On Mac the NSData inside the SharedBuffer can be secretly appended to without the SharedBuffer's knowledge. We use SharedBuffer's ability
- // to wrap itself inside CFData to get around this, ensuring that ImageIO is really looking at the SharedBuffer.
- CGImageSourceUpdateData(m_decoder, data->createCFData().get(), allDataReceived);
-#else
- if (!m_decoder)
- m_decoder = CGImageSourceCreateIncremental(0);
- // Create a CGDataProvider to wrap the SharedBuffer.
- data->ref();
- // We use the GetBytesAtPosition callback rather than the GetBytePointer one because SharedBuffer
- // does not provide a way to lock down the byte pointer and guarantee that it won't move, which
- // is a requirement for using the GetBytePointer callback.
- CGDataProviderDirectCallbacks providerCallbacks = { 0, 0, 0, sharedBufferGetBytesAtPosition, sharedBufferRelease };
- RetainPtr<CGDataProviderRef> dataProvider = adoptCF(CGDataProviderCreateDirect(data, data->size(), &providerCallbacks));
- CGImageSourceUpdateDataProvider(m_decoder, dataProvider.get(), allDataReceived);
-#endif
-}
-
-String ImageSource::filenameExtension() const
-{
- if (!m_decoder)
- return String();
- CFStringRef imageSourceType = CGImageSourceGetType(m_decoder);
- return WebCore::preferredExtensionForImageSourceType(imageSourceType);
-}
-
-SubsamplingLevel ImageSource::subsamplingLevelForScale(float scale) const
-{
- // There are four subsampling levels: 0 = 1x, 1 = 0.5x, 2 = 0.25x, 3 = 0.125x.
- float clampedScale = std::max<float>(0.125, std::min<float>(1, scale));
- int result = ceilf(log2f(1 / clampedScale));
- ASSERT(result >=0 && result <= 3);
- return result;
-}
-
-bool ImageSource::isSizeAvailable()
-{
- // Ragnaros yells: TOO SOON! You have awakened me TOO SOON, Executus!
- if (CGImageSourceGetStatus(m_decoder) < kCGImageStatusIncomplete)
- return false;
-
- RetainPtr<CFDictionaryRef> image0Properties = adoptCF(CGImageSourceCopyPropertiesAtIndex(m_decoder, 0, imageSourceOptions().get()));
- if (!image0Properties)
- return false;
-
- return CFDictionaryContainsKey(image0Properties.get(), kCGImagePropertyPixelWidth)
- && CFDictionaryContainsKey(image0Properties.get(), kCGImagePropertyPixelHeight);
-}
-
static ImageOrientation orientationFromProperties(CFDictionaryRef imageProperties)
{
ASSERT(imageProperties);
CFNumberRef orientationProperty = (CFNumberRef)CFDictionaryGetValue(imageProperties, kCGImagePropertyOrientation);
if (!orientationProperty)
- return DefaultImageOrientation;
+ return ImageOrientation();
int exifValue;
CFNumberGetValue(orientationProperty, kCFNumberIntType, &exifValue);
return ImageOrientation::fromEXIFValue(exifValue);
}
-bool ImageSource::allowSubsamplingOfFrameAtIndex(size_t) const
+#if !PLATFORM(COCOA)
+size_t sharedBufferGetBytesAtPosition(void* info, void* buffer, off_t position, size_t count)
{
- RetainPtr<CFDictionaryRef> properties = adoptCF(CGImageSourceCopyPropertiesAtIndex(m_decoder, 0, imageSourceOptions().get()));
- if (!properties)
- return false;
+ SharedBuffer* sharedBuffer = static_cast<SharedBuffer*>(info);
+ size_t sourceSize = sharedBuffer->size();
+ if (position >= sourceSize)
+ return 0;
- CFDictionaryRef jfifProperties = static_cast<CFDictionaryRef>(CFDictionaryGetValue(properties.get(), kCGImagePropertyJFIFDictionary));
- if (jfifProperties) {
- CFBooleanRef isProgCFBool = static_cast<CFBooleanRef>(CFDictionaryGetValue(jfifProperties, kCGImagePropertyJFIFIsProgressive));
- if (isProgCFBool) {
- bool isProgressive = CFBooleanGetValue(isProgCFBool);
- // Workaround for <rdar://problem/5184655> - Hang rendering very large progressive JPEG. Decoding progressive
- // images hangs for a very long time right now. Until this is fixed, don't sub-sample progressive images. This
- // will cause them to fail our large image check and they won't be decoded.
- // FIXME: Remove once underlying issue is fixed (<rdar://problem/5191418>)
- return !isProgressive;
- }
- }
-
- return true;
+ const char* source = sharedBuffer->data() + position;
+ size_t amount = std::min<size_t>(count, sourceSize - position);
+ memcpy(buffer, source, amount);
+ return amount;
}
-IntSize ImageSource::frameSizeAtIndex(size_t index, SubsamplingLevel subsamplingLevel, ImageOrientationDescription description) const
+void sharedBufferRelease(void* info)
{
- RetainPtr<CFDictionaryRef> properties = adoptCF(CGImageSourceCopyPropertiesAtIndex(m_decoder, index, imageSourceOptions(subsamplingLevel).get()));
-
- if (!properties)
- return IntSize();
-
- int width = 0;
- int height = 0;
- CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(properties.get(), kCGImagePropertyPixelWidth);
- if (num)
- CFNumberGetValue(num, kCFNumberIntType, &width);
- num = (CFNumberRef)CFDictionaryGetValue(properties.get(), kCGImagePropertyPixelHeight);
- if (num)
- CFNumberGetValue(num, kCFNumberIntType, &height);
-
- if ((description.respectImageOrientation() == RespectImageOrientation) && orientationFromProperties(properties.get()).usesWidthAsHeight())
- return IntSize(height, width);
-
- return IntSize(width, height);
+ SharedBuffer* sharedBuffer = static_cast<SharedBuffer*>(info);
+ sharedBuffer->deref();
}
-
-ImageOrientation ImageSource::orientationAtIndex(size_t index) const
+#endif
+
+ImageDecoder::ImageDecoder()
{
- RetainPtr<CFDictionaryRef> properties = adoptCF(CGImageSourceCopyPropertiesAtIndex(m_decoder, index, imageSourceOptions().get()));
- if (!properties)
- return DefaultImageOrientation;
-
- return orientationFromProperties(properties.get());
+ m_nativeDecoder = adoptCF(CGImageSourceCreateIncremental(nullptr));
}
+
+SubsamplingLevel ImageDecoder::subsamplingLevelForScale(float scale, SubsamplingLevel maximumSubsamplingLevel)
+{
+ // There are four subsampling levels: 0 = 1x, 1 = 0.5x, 2 = 0.25x, 3 = 0.125x.
+ float clampedScale = std::max<float>(0.125, std::min<float>(1, scale));
+ SubsamplingLevel result = ceilf(log2f(1 / clampedScale));
+ ASSERT(result >=0 && result <= 3);
+ return std::min(result, maximumSubsamplingLevel);
+}
-IntSize ImageSource::size(ImageOrientationDescription description) const
+size_t ImageDecoder::bytesDecodedToDetermineProperties()
{
- return frameSizeAtIndex(0, 0, description);
+ // Measured by tracing malloc/calloc calls on Mac OS 10.6.6, x86_64.
+ // A non-zero value ensures cached images with no decoded frames still enter
+ // the live decoded resources list when the CGImageSource decodes image
+ // properties, allowing the cache to prune the partially decoded image.
+ // This value is likely to be inaccurate on other platforms, but the overall
+ // behavior is unchanged.
+ return 13088;
}
+
+String ImageDecoder::filenameExtension() const
+{
+ CFStringRef imageSourceType = CGImageSourceGetType(m_nativeDecoder.get());
+ return WebCore::preferredExtensionForImageSourceType(imageSourceType);
+}
-bool ImageSource::getHotSpot(IntPoint& hotSpot) const
+bool ImageDecoder::isSizeAvailable() const
{
- RetainPtr<CFDictionaryRef> properties = adoptCF(CGImageSourceCopyPropertiesAtIndex(m_decoder, 0, imageSourceOptions().get()));
- if (!properties)
+ // Ragnaros yells: TOO SOON! You have awakened me TOO SOON, Executus!
+ if (CGImageSourceGetStatus(m_nativeDecoder.get()) < kCGImageStatusIncomplete)
return false;
- int x = -1, y = -1;
- CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(properties.get(), CFSTR("hotspotX"));
- if (!num || !CFNumberGetValue(num, kCFNumberIntType, &x))
+ RetainPtr<CFDictionaryRef> image0Properties = adoptCF(CGImageSourceCopyPropertiesAtIndex(m_nativeDecoder.get(), 0, imageSourceOptions().get()));
+ if (!image0Properties)
return false;
- num = (CFNumberRef)CFDictionaryGetValue(properties.get(), CFSTR("hotspotY"));
- if (!num || !CFNumberGetValue(num, kCFNumberIntType, &y))
- return false;
+ return CFDictionaryContainsKey(image0Properties.get(), kCGImagePropertyPixelWidth)
+ && CFDictionaryContainsKey(image0Properties.get(), kCGImagePropertyPixelHeight);
+}
- if (x < 0 || y < 0)
- return false;
-
- hotSpot = IntPoint(x, y);
- return true;
+IntSize ImageDecoder::size() const
+{
+ if (m_size.isEmpty())
+ m_size = frameSizeAtIndex(0, 0);
+ return m_size;
}
-size_t ImageSource::bytesDecodedToDetermineProperties() const
+size_t ImageDecoder::frameCount() const
{
- // Measured by tracing malloc/calloc calls on Mac OS 10.6.6, x86_64.
- // A non-zero value ensures cached images with no decoded frames still enter
- // the live decoded resources list when the CGImageSource decodes image
- // properties, allowing the cache to prune the partially decoded image.
- // This value is likely to be inaccurate on other platforms, but the overall
- // behavior is unchanged.
- return 13088;
+ return CGImageSourceGetCount(m_nativeDecoder.get());
}
-
-int ImageSource::repetitionCount()
+
+int ImageDecoder::repetitionCount() const
{
- if (!initialized())
- return cAnimationLoopOnce;
-
- RetainPtr<CFDictionaryRef> properties = adoptCF(CGImageSourceCopyProperties(m_decoder, imageSourceOptions().get()));
+ RetainPtr<CFDictionaryRef> properties = adoptCF(CGImageSourceCopyProperties(m_nativeDecoder.get(), imageSourceOptions().get()));
if (!properties)
return cAnimationLoopOnce;
@@ -335,61 +253,67 @@
return cAnimationNone;
}
-size_t ImageSource::frameCount() const
+bool ImageDecoder::hotSpot(IntPoint& hotSpot) const
{
- return m_decoder ? CGImageSourceGetCount(m_decoder) : 0;
+ RetainPtr<CFDictionaryRef> properties = adoptCF(CGImageSourceCopyPropertiesAtIndex(m_nativeDecoder.get(), 0, imageSourceOptions().get()));
+ if (!properties)
+ return false;
+
+ int x = -1, y = -1;
+ CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(properties.get(), CFSTR("hotspotX"));
+ if (!num || !CFNumberGetValue(num, kCFNumberIntType, &x))
+ return false;
+
+ num = (CFNumberRef)CFDictionaryGetValue(properties.get(), CFSTR("hotspotY"));
+ if (!num || !CFNumberGetValue(num, kCFNumberIntType, &y))
+ return false;
+
+ if (x < 0 || y < 0)
+ return false;
+
+ hotSpot = IntPoint(x, y);
+ return true;
}
-RetainPtr<CGImageRef> ImageSource::createFrameImageAtIndex(size_t index, SubsamplingLevel subsamplingLevel)
+IntSize ImageDecoder::frameSizeAtIndex(size_t index, SubsamplingLevel subsamplingLevel) const
{
- if (!initialized())
- return nullptr;
+ RetainPtr<CFDictionaryRef> properties = adoptCF(CGImageSourceCopyPropertiesAtIndex(m_nativeDecoder.get(), index, imageSourceOptions(subsamplingLevel).get()));
- RetainPtr<CGImageRef> image = adoptCF(CGImageSourceCreateImageAtIndex(m_decoder, index, imageSourceOptions(subsamplingLevel).get()));
+ if (!properties)
+ return { };
-#if PLATFORM(IOS)
- // <rdar://problem/7371198> - CoreGraphics changed the default caching behaviour in iOS 4.0 to kCGImageCachingTransient
- // which caused a performance regression for us since the images had to be resampled/recreated every time we called
- // CGContextDrawImage. We now tell CG to cache the drawn images. See also <rdar://problem/14366755> -
- // CoreGraphics needs to un-deprecate kCGImageCachingTemporary since it's still not the default.
-#if COMPILER(CLANG)
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wdeprecated-declarations"
-#endif
- CGImageSetCachingFlags(image.get(), kCGImageCachingTemporary);
-#if COMPILER(CLANG)
-#pragma clang diagnostic pop
-#endif
-#endif // PLATFORM(IOS)
+ int width = 0;
+ int height = 0;
+ CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(properties.get(), kCGImagePropertyPixelWidth);
+ if (num)
+ CFNumberGetValue(num, kCFNumberIntType, &width);
- CFStringRef imageUTI = CGImageSourceGetType(m_decoder);
- static const CFStringRef xbmUTI = CFSTR("public.xbitmap-image");
+ num = (CFNumberRef)CFDictionaryGetValue(properties.get(), kCGImagePropertyPixelHeight);
+ if (num)
+ CFNumberGetValue(num, kCFNumberIntType, &height);
- if (!imageUTI)
- return image;
-
- if (!CFEqual(imageUTI, xbmUTI))
- return image;
-
- // If it is an xbm image, mask out all the white areas to render them transparent.
- const CGFloat maskingColors[6] = {255, 255, 255, 255, 255, 255};
- RetainPtr<CGImageRef> maskedImage = adoptCF(CGImageCreateWithMaskingColors(image.get(), maskingColors));
- return maskedImage ? maskedImage : image;
+ return IntSize(width, height);
}
-bool ImageSource::frameIsCompleteAtIndex(size_t index)
+bool ImageDecoder::frameIsCompleteAtIndex(size_t index) const
{
ASSERT(frameCount());
- return CGImageSourceGetStatusAtIndex(m_decoder, index) == kCGImageStatusComplete;
+ return CGImageSourceGetStatusAtIndex(m_nativeDecoder.get(), index) == kCGImageStatusComplete;
}
-float ImageSource::frameDurationAtIndex(size_t index)
+ImageOrientation ImageDecoder::orientationAtIndex(size_t index) const
{
- if (!initialized())
- return 0;
+ RetainPtr<CFDictionaryRef> properties = adoptCF(CGImageSourceCopyPropertiesAtIndex(m_nativeDecoder.get(), index, imageSourceOptions().get()));
+ if (!properties)
+ return ImageOrientation();
+ return orientationFromProperties(properties.get());
+}
+
+float ImageDecoder::frameDurationAtIndex(size_t index) const
+{
float duration = 0;
- RetainPtr<CFDictionaryRef> properties = adoptCF(CGImageSourceCopyPropertiesAtIndex(m_decoder, index, imageSourceOptions().get()));
+ RetainPtr<CFDictionaryRef> properties = adoptCF(CGImageSourceCopyPropertiesAtIndex(m_nativeDecoder.get(), index, imageSourceOptions().get()));
if (properties) {
CFDictionaryRef gifProperties = (CFDictionaryRef)CFDictionaryGetValue(properties.get(), kCGImagePropertyGIFDictionary);
if (gifProperties) {
@@ -420,15 +344,34 @@
return duration;
}
-bool ImageSource::frameHasAlphaAtIndex(size_t index)
+bool ImageDecoder::allowSubsamplingOfFrameAtIndex(size_t) const
{
- if (!m_decoder)
- return false; // FIXME: why doesn't this return true?
+ RetainPtr<CFDictionaryRef> properties = adoptCF(CGImageSourceCopyPropertiesAtIndex(m_nativeDecoder.get(), 0, imageSourceOptions().get()));
+ if (!properties)
+ return false;
+ CFDictionaryRef jfifProperties = static_cast<CFDictionaryRef>(CFDictionaryGetValue(properties.get(), kCGImagePropertyJFIFDictionary));
+ if (jfifProperties) {
+ CFBooleanRef isProgCFBool = static_cast<CFBooleanRef>(CFDictionaryGetValue(jfifProperties, kCGImagePropertyJFIFIsProgressive));
+ if (isProgCFBool) {
+ bool isProgressive = CFBooleanGetValue(isProgCFBool);
+ // Workaround for <rdar://problem/5184655> - Hang rendering very large progressive JPEG. Decoding progressive
+ // images hangs for a very long time right now. Until this is fixed, don't sub-sample progressive images. This
+ // will cause them to fail our large image check and they won't be decoded.
+ // FIXME: Remove once underlying issue is fixed (<rdar://problem/5191418>)
+ return !isProgressive;
+ }
+ }
+
+ return true;
+}
+
+bool ImageDecoder::frameHasAlphaAtIndex(size_t index) const
+{
if (!frameIsCompleteAtIndex(index))
return true;
- CFStringRef imageType = CGImageSourceGetType(m_decoder);
+ CFStringRef imageType = CGImageSourceGetType(m_nativeDecoder.get());
// Return false if there is no image type or the image type is JPEG, because
// JPEG does not support alpha transparency.
@@ -441,11 +384,245 @@
return true;
}
+unsigned ImageDecoder::frameBytesAtIndex(size_t index, SubsamplingLevel subsamplingLevel) const
+{
+ IntSize frameSize = frameSizeAtIndex(index, subsamplingLevel);
+ return frameSize.area() * 4;
+}
+
+NativeImagePtr ImageDecoder::createFrameImageAtIndex(size_t index, SubsamplingLevel subsamplingLevel) const
+{
+ RetainPtr<CGImageRef> image = adoptCF(CGImageSourceCreateImageAtIndex(m_nativeDecoder.get(), index, imageSourceOptions(subsamplingLevel).get()));
+
+#if PLATFORM(IOS)
+ // <rdar://problem/7371198> - CoreGraphics changed the default caching behaviour in iOS 4.0 to kCGImageCachingTransient
+ // which caused a performance regression for us since the images had to be resampled/recreated every time we called
+ // CGContextDrawImage. We now tell CG to cache the drawn images. See also <rdar://problem/14366755> -
+ // CoreGraphics needs to un-deprecate kCGImageCachingTemporary since it's still not the default.
+#if COMPILER(CLANG)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+#endif
+ CGImageSetCachingFlags(image.get(), kCGImageCachingTemporary);
+#if COMPILER(CLANG)
+#pragma clang diagnostic pop
+#endif
+#endif // PLATFORM(IOS)
+
+ CFStringRef imageUTI = CGImageSourceGetType(m_nativeDecoder.get());
+ static const CFStringRef xbmUTI = CFSTR("public.xbitmap-image");
+
+ if (!imageUTI)
+ return image;
+
+ if (!CFEqual(imageUTI, xbmUTI))
+ return image;
+
+ // If it is an xbm image, mask out all the white areas to render them transparent.
+ const CGFloat maskingColors[6] = {255, 255, 255, 255, 255, 255};
+ RetainPtr<CGImageRef> maskedImage = adoptCF(CGImageCreateWithMaskingColors(image.get(), maskingColors));
+ return maskedImage ? maskedImage : image;
+}
+
+void ImageDecoder::setData(CFDataRef data, bool allDataReceived)
+{
+ CGImageSourceUpdateData(m_nativeDecoder.get(), data, allDataReceived);
+}
+
+void ImageDecoder::setData(SharedBuffer* data, bool allDataReceived)
+{
+#if PLATFORM(COCOA)
+ // On Mac the NSData inside the SharedBuffer can be secretly appended to without the SharedBuffer's knowledge.
+ // We use SharedBuffer's ability to wrap itself inside CFData to get around this, ensuring that ImageIO is
+ // really looking at the SharedBuffer.
+ setData(data->createCFData().get(), allDataReceived);
+ CGImageSourceUpdateData(m_nativeDecoder.get(), data->createCFData().get(), allDataReceived);
+#else
+ // Create a CGDataProvider to wrap the SharedBuffer.
+ data->ref();
+ // We use the GetBytesAtPosition callback rather than the GetBytePointer one because SharedBuffer
+ // does not provide a way to lock down the byte pointer and guarantee that it won't move, which
+ // is a requirement for using the GetBytePointer callback.
+ CGDataProviderDirectCallbacks providerCallbacks = { 0, 0, 0, sharedBufferGetBytesAtPosition, sharedBufferRelease };
+ RetainPtr<CGDataProviderRef> dataProvider = adoptCF(CGDataProviderCreateDirect(data, data->size(), &providerCallbacks));
+ CGImageSourceUpdateDataProvider(m_nativeDecoder.get(), dataProvider.get(), allDataReceived);
+#endif
+}
+
+ImageSource::ImageSource(ImageSource::AlphaOption, ImageSource::GammaAndColorProfileOption)
+{
+ // FIXME: AlphaOption and GammaAndColorProfileOption are ignored.
+}
+
+ImageSource::~ImageSource()
+{
+ clear(true);
+}
+
+void ImageSource::clear(bool destroyAllFrames, size_t, SharedBuffer* data, bool allDataReceived)
+{
+ // Recent versions of ImageIO discard previously decoded image frames if the client
+ // application no longer holds references to them, so there's no need to throw away
+ // the decoder unless we're explicitly asked to destroy all of the frames.
+ if (!destroyAllFrames)
+ return;
+
+ m_decoder = nullptr;
+
+ if (data)
+ setData(data, allDataReceived);
+}
+
+void ImageSource::ensureDecoderIsCreated(SharedBuffer*)
+{
+ if (initialized())
+ return;
+ m_decoder = ImageDecoder::create();
+}
+
+void ImageSource::setData(SharedBuffer* data, bool allDataReceived)
+{
+ if (!data)
+ return;
+
+ ensureDecoderIsCreated(data);
+
+ if (!initialized()) {
+ ASSERT_NOT_REACHED();
+ return;
+ }
+
+ m_decoder->setData(data, allDataReceived);
+}
+
+String ImageSource::filenameExtension() const
+{
+ return initialized() ? m_decoder->filenameExtension() : String();
+}
+
+SubsamplingLevel ImageSource::calculateMaximumSubsamplingLevel() const
+{
+ if (!m_allowSubsampling || !allowSubsamplingOfFrameAtIndex(0))
+ return 0;
+
+ // Values chosen to be appropriate for iOS.
+ const int cMaximumImageAreaBeforeSubsampling = 5 * 1024 * 1024;
+ const SubsamplingLevel maxSubsamplingLevel = 3;
+
+ SubsamplingLevel currentLevel = 0;
+ for ( ; currentLevel <= maxSubsamplingLevel; ++currentLevel) {
+ IntSize frameSize = frameSizeAtIndex(0, currentLevel);
+ if (frameSize.area() < cMaximumImageAreaBeforeSubsampling)
+ break;
+ }
+
+ return currentLevel;
+}
+
+SubsamplingLevel ImageSource::maximumSubsamplingLevel() const
+{
+#if PLATFORM(IOS)
+ return calculateMaximumSubsamplingLevel();
+#endif
+ return 0;
+}
+
+SubsamplingLevel ImageSource::subsamplingLevelForScale(float scale) const
+{
+ return ImageDecoder::subsamplingLevelForScale(scale, maximumSubsamplingLevel());
+}
+
+bool ImageSource::isSizeAvailable()
+{
+ return initialized() && m_decoder->isSizeAvailable();
+}
+
+bool ImageSource::allowSubsamplingOfFrameAtIndex(size_t index) const
+{
+ return initialized() && m_decoder->allowSubsamplingOfFrameAtIndex(index);
+}
+
+IntSize ImageSource::frameSizeAtIndex(size_t index, SubsamplingLevel subsamplingLevel, RespectImageOrientationEnum shouldRespectImageOrientation) const
+{
+ if (!initialized())
+ return { };
+
+ IntSize size = m_decoder->frameSizeAtIndex(index, subsamplingLevel);
+ ImageOrientation orientation = m_decoder->orientationAtIndex(index);
+
+ return shouldRespectImageOrientation == RespectImageOrientation && orientation.usesWidthAsHeight() ? size.transposedSize() : size;
+}
+
+ImageOrientation ImageSource::orientationAtIndex(size_t index) const
+{
+ return initialized() ? m_decoder->orientationAtIndex(index) : ImageOrientation();
+}
+
+IntSize ImageSource::size() const
+{
+ return frameSizeAtIndex(0, 0);
+}
+
+IntSize ImageSource::sizeRespectingOrientation() const
+{
+ return frameSizeAtIndex(0, 0, RespectImageOrientation);
+}
+
+bool ImageSource::getHotSpot(IntPoint& hotSpot) const
+{
+ return initialized() && m_decoder->hotSpot(hotSpot);
+}
+
+size_t ImageSource::bytesDecodedToDetermineProperties() const
+{
+ return ImageDecoder::bytesDecodedToDetermineProperties();
+}
+
+int ImageSource::repetitionCount()
+{
+ return initialized() ? m_decoder->repetitionCount() : cAnimationLoopOnce;
+}
+
+size_t ImageSource::frameCount() const
+{
+ return initialized() ? m_decoder->frameCount() : 0;
+}
+
+RetainPtr<CGImageRef> ImageSource::createFrameImageAtIndex(size_t index, SubsamplingLevel subsamplingLevel)
+{
+ return initialized() ? m_decoder->createFrameImageAtIndex(index, subsamplingLevel) : nullptr;
+}
+
+bool ImageSource::frameIsCompleteAtIndex(size_t index)
+{
+ return initialized() && m_decoder->frameIsCompleteAtIndex(index);
+}
+
+float ImageSource::frameDurationAtIndex(size_t index)
+{
+ return initialized() ? m_decoder->frameDurationAtIndex(index) : 0;
+}
+
+bool ImageSource::frameHasAlphaAtIndex(size_t index)
+{
+ return !initialized() || m_decoder->frameHasAlphaAtIndex(index);
+}
+
unsigned ImageSource::frameBytesAtIndex(size_t index, SubsamplingLevel subsamplingLevel) const
{
- IntSize frameSize = frameSizeAtIndex(index, subsamplingLevel, ImageOrientationDescription(RespectImageOrientation));
- return frameSize.width() * frameSize.height() * 4;
+ IntSize frameSize = frameSizeAtIndex(index, subsamplingLevel);
+ return frameSize.area() * 4;
}
+
+void ImageSource::dump(TextStream& ts) const
+{
+ if (m_allowSubsampling)
+ ts.dumpProperty("allow-subsampling", m_allowSubsampling);
+
+ ImageOrientation orientation = orientationAtIndex(0);
+ if (orientation != OriginTopLeft)
+ ts.dumpProperty("orientation", orientation);
+}
}
Modified: trunk/Source/WebCore/platform/image-decoders/ImageDecoder.cpp (198781 => 198782)
--- trunk/Source/WebCore/platform/image-decoders/ImageDecoder.cpp 2016-03-29 15:42:46 UTC (rev 198781)
+++ trunk/Source/WebCore/platform/image-decoders/ImageDecoder.cpp 2016-03-29 16:18:25 UTC (rev 198782)
@@ -95,35 +95,35 @@
}
-ImageDecoder* ImageDecoder::create(const SharedBuffer& data, ImageSource::AlphaOption alphaOption, ImageSource::GammaAndColorProfileOption gammaAndColorProfileOption)
+std::unique_ptr<ImageDecoder> ImageDecoder::create(const SharedBuffer& data, ImageSource::AlphaOption alphaOption, ImageSource::GammaAndColorProfileOption gammaAndColorProfileOption)
{
static const unsigned lengthOfLongestSignature = 14; // To wit: "RIFF????WEBPVP"
char contents[lengthOfLongestSignature];
unsigned length = copyFromSharedBuffer(contents, lengthOfLongestSignature, data, 0);
if (length < lengthOfLongestSignature)
- return 0;
+ return nullptr;
if (matchesGIFSignature(contents))
- return new GIFImageDecoder(alphaOption, gammaAndColorProfileOption);
+ return std::unique_ptr<ImageDecoder> { std::make_unique<GIFImageDecoder>(alphaOption, gammaAndColorProfileOption) };
if (matchesPNGSignature(contents))
- return new PNGImageDecoder(alphaOption, gammaAndColorProfileOption);
+ return std::unique_ptr<ImageDecoder> { std::make_unique<PNGImageDecoder>(alphaOption, gammaAndColorProfileOption) };
if (matchesICOSignature(contents) || matchesCURSignature(contents))
- return new ICOImageDecoder(alphaOption, gammaAndColorProfileOption);
+ return std::unique_ptr<ImageDecoder> { std::make_unique<ICOImageDecoder>(alphaOption, gammaAndColorProfileOption) };
if (matchesJPEGSignature(contents))
- return new JPEGImageDecoder(alphaOption, gammaAndColorProfileOption);
+ return std::unique_ptr<ImageDecoder> { std::make_unique<JPEGImageDecoder>(alphaOption, gammaAndColorProfileOption) };
#if USE(WEBP)
if (matchesWebPSignature(contents))
- return new WEBPImageDecoder(alphaOption, gammaAndColorProfileOption);
+ return std::unique_ptr<ImageDecoder> { std::make_unique<WEBPImageDecoder>(alphaOption, gammaAndColorProfileOption) };
#endif
if (matchesBMPSignature(contents))
- return new BMPImageDecoder(alphaOption, gammaAndColorProfileOption);
+ return std::unique_ptr<ImageDecoder> { std::make_unique<BMPImageDecoder>(alphaOption, gammaAndColorProfileOption) };
- return 0;
+ return nullptr;
}
ImageFrame::ImageFrame()
Modified: trunk/Source/WebCore/platform/image-decoders/ImageDecoder.h (198781 => 198782)
--- trunk/Source/WebCore/platform/image-decoders/ImageDecoder.h 2016-03-29 15:42:46 UTC (rev 198781)
+++ trunk/Source/WebCore/platform/image-decoders/ImageDecoder.h 2016-03-29 16:18:25 UTC (rev 198782)
@@ -248,7 +248,7 @@
// Returns a caller-owned decoder of the appropriate type. Returns 0 if
// we can't sniff a supported type from the provided data (possibly
// because there isn't enough data yet).
- static ImageDecoder* create(const SharedBuffer& data, ImageSource::AlphaOption, ImageSource::GammaAndColorProfileOption);
+ static std::unique_ptr<ImageDecoder> create(const SharedBuffer& data, ImageSource::AlphaOption, ImageSource::GammaAndColorProfileOption);
virtual String filenameExtension() const = 0;
Modified: trunk/Source/WebCore/platform/mac/DragImageMac.mm (198781 => 198782)
--- trunk/Source/WebCore/platform/mac/DragImageMac.mm 2016-03-29 15:42:46 UTC (rev 198781)
+++ trunk/Source/WebCore/platform/mac/DragImageMac.mm 2016-03-29 16:18:25 UTC (rev 198782)
@@ -91,7 +91,7 @@
if (is<BitmapImage>(*image)) {
ImageOrientation orientation;
BitmapImage& bitmapImage = downcast<BitmapImage>(*image);
- IntSize sizeRespectingOrientation = bitmapImage.sizeRespectingOrientation(description);
+ IntSize sizeRespectingOrientation = bitmapImage.sizeRespectingOrientation();
if (description.respectImageOrientation() == RespectImageOrientation)
orientation = bitmapImage.orientationForCurrentFrame();