Changeset 198782 in webkit
- Timestamp:
- Mar 29, 2016 9:18:25 AM (8 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 14 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r198780 r198782 1 2016-03-29 Said Abou-Hallawa <sabouhallawa@apple,com> 2 3 Create a CG ImageDecoder class instead of defining it as CGImageSourceRef 4 https://bugs.webkit.org/show_bug.cgi?id=155422 5 6 Reviewed by Simon Fraser. 7 8 Move the image CG decoding code from the class ImageSource out to a new 9 class named ImageDecoder. The purpose of this split is to unify the code 10 of the ImageSource for all platforms. This class should be a container 11 for the ImageDecoder. All the direct frame manipulation like querying the 12 frame metadata or creating a frame image should be the responsibility of 13 the ImageDecoder. The ImageSource will be responsible of the image frame 14 caching. When responding to a frame metadata query, for example. the 15 ImageSource checks its cache first. If an entry does not exist for the 16 requested frame, the ImageSource will cache the image and the metadata 17 of this frame. The ImageSource will respond at the end from the image 18 frame cache. 19 20 The plan after this patch is is the following: 21 -- Move the new class to separate files 22 -- Merge the ImageSource.cpp and ImageSourceCG.cpp. in one file 23 -- Move caching the FrameData from BitmapImage to ImageSource. 24 25 * loader/cache/CachedImage.cpp: 26 (WebCore::CachedImage::imageSizeForRenderer): 27 BitmapImage::sizeRespectingOrientation() does not take any argument now. 28 Fix the call to this function and delete the conditionally compiled code 29 since the code is the same for the two cases. 30 31 * platform/graphics/BitmapImage.cpp: 32 (WebCore::BitmapImage::updateSize): 33 (WebCore::BitmapImage::sizeRespectingOrientation): 34 (WebCore::BitmapImage::frameImageAtIndex): 35 (WebCore::BitmapImage::BitmapImage): 36 An image can have two sizes: size() and sizeRespectingOrientation(). The 37 sizeRespectingOrientation() is the transpose of size() iff the image 38 orientation has usesWidthAsHeight() is true. So there is no need for the 39 ImageOrientationDescription argument. So there is no need for the members 40 m_imageOrientation or m_shouldRespectImageOrientation. Also move 41 m_allowSubsampling and m_minimumSubsamplingLevel (which should be named 42 m_maximumSubsamplingLevel) to ImageSource instead. 43 44 (WebCore::BitmapImage::frameOrientationAtIndex): Replace DefaultImageOrientation 45 by ImageOrientation(). 46 47 (WebCore::BitmapImage::dump): Move dumping the image metadata to the 48 ImageSource. 49 50 * platform/graphics/BitmapImage.h: 51 52 * platform/graphics/GraphicsContext.h: 53 * platform/graphics/ImageOrientation.h: 54 (WebCore::ImageOrientation::ImageOrientation): 55 (WebCore::ImageOrientation::fromEXIFValue): 56 (WebCore::ImageOrientation::operator ImageOrientationEnum): 57 Add a casting operator to ImageOrientation so it can be dumped as enum 58 value. Also add a default constructor and make the other constructor be 59 explicit. All the rvalues DefaultImageOrientation should be replaced by 60 ImageOrientation(). 61 62 * platform/graphics/ImageSource.cpp: 63 (WebCore::ImageSource::ImageSource): 64 (WebCore::ImageSource::clear): 65 m_decoder is now a unique_ptr. To release it, assign it to nullptr. 66 67 (WebCore::ImageSource::ensureDecoderIsCreated): Ensure m_decoder is created. 68 69 (WebCore::ImageSource::setData): Call ensureDecoderIsCreated() before 70 actually setting the data. 71 72 (WebCore::ImageSource::isSizeAvailable): Use initialized(); 73 74 (WebCore::ImageSource::size): 75 (WebCore::ImageSource::sizeRespectingOrientation): 76 (WebCore::ImageSource::frameSizeAtIndex): 77 These functions return the size of the image. 78 79 (WebCore::ImageSource::getHotSpot): 80 (WebCore::ImageSource::repetitionCount): 81 (WebCore::ImageSource::frameCount): 82 (WebCore::ImageSource::createFrameImageAtIndex): 83 (WebCore::ImageSource::frameDurationAtIndex): 84 (WebCore::ImageSource::orientationAtIndex): 85 (WebCore::ImageSource::frameHasAlphaAtIndex): 86 (WebCore::ImageSource::frameIsCompleteAtIndex): 87 (WebCore::ImageSource::frameBytesAtIndex): 88 Check for initialized() instead of checking m_decoder. 89 90 (WebCore::ImageSource::dump): Dump the image metadata. 91 92 (WebCore::ImageSource::initialized): Deleted. 93 94 * platform/graphics/ImageSource.h: The image decoder is now named 95 ImageDecoder for all platforms. 96 97 (WebCore::ImageSource::initialized): Moved to the header file. 98 99 (WebCore::ImageSource::setAllowSubsampling): Moved from BitmapImage. 100 101 * platform/graphics/cairo/BitmapImageCairo.cpp: 102 (WebCore::BitmapImage::BitmapImage): 103 (WebCore::BitmapImage::determineMinimumSubsamplingLevel): Deleted. 104 Delete initializing m_minimumSubsamplingLevel and determineMinimumSubsamplingLevel() 105 since they are moved to ImageSource. 106 107 * platform/graphics/cg/BitmapImageCG.cpp: 108 (WebCore::BitmapImage::BitmapImage): 109 (WebCore::BitmapImage::determineMinimumSubsamplingLevel): Deleted. 110 Delete members and methods which are now owned and calculated by ImageSource. 111 112 * platform/graphics/cg/ImageSourceCG.cpp: 113 (WebCore::ImageDecoder::create): Returns a CG ImageDecoder object. 114 115 (WebCore::orientationFromProperties): Replace DefaultImageOrientation 116 by ImageOrientation(). 117 118 (WebCore::ImageDecoder::ImageDecoder): Creates a native CG image decoder. 119 120 (WebCore::ImageDecoder::~ImageDecoder): Releases the native CG image decoder. 121 122 (WebCore::ImageDecoder::subsamplingLevelForScale): Moved from ImageSource. 123 A new argument named 'maximumSubsamplingLevel' is added to low filter the 124 return value. 125 126 (WebCore::ImageDecoder::bytesDecodedToDetermineProperties): 127 (WebCore::ImageDecoder::filenameExtension): 128 (WebCore::ImageDecoder::isSizeAvailable): 129 (WebCore::ImageDecoder::size): 130 (WebCore::ImageDecoder::frameCount): 131 (WebCore::ImageDecoder::repetitionCount): 132 (WebCore::ImageDecoder::hotSpot): 133 (WebCore::ImageDecoder::frameSizeAtIndex): 134 (WebCore::ImageDecoder::frameIsCompleteAtIndex): 135 (WebCore::ImageDecoder::orientationAtIndex): 136 (WebCore::ImageDecoder::frameDurationAtIndex): 137 (WebCore::ImageDecoder::allowSubsamplingOfFrameAtIndex): 138 (WebCore::ImageDecoder::frameHasAlphaAtIndex): 139 (WebCore::ImageDecoder::frameBytesAtIndex): 140 (WebCore::ImageDecoder::createFrameImageAtIndex): 141 (WebCore::ImageDecoder::setData): 142 The code of these function was moved from the functions of ImageSource. 143 144 (WebCore::ImageSource::ImageSource): 145 (WebCore::ImageSource::~ImageSource): 146 (WebCore::ImageSource::clear): 147 (WebCore::ImageSource::ensureDecoderIsCreated): 148 (WebCore::ImageSource::setData): 149 (WebCore::ImageSource::filenameExtension): 150 (WebCore::ImageSource::calculateMaximumSubsamplingLevel): 151 (WebCore::ImageSource::maximumSubsamplingLevel): 152 (WebCore::ImageSource::subsamplingLevelForScale): 153 (WebCore::ImageSource::isSizeAvailable): 154 (WebCore::ImageSource::allowSubsamplingOfFrameAtIndex): 155 (WebCore::ImageSource::frameSizeAtIndex): 156 (WebCore::ImageSource::orientationAtIndex): 157 (WebCore::ImageSource::size): 158 (WebCore::ImageSource::sizeRespectingOrientation): 159 (WebCore::ImageSource::getHotSpot): 160 (WebCore::ImageSource::bytesDecodedToDetermineProperties): 161 (WebCore::ImageSource::repetitionCount): 162 (WebCore::ImageSource::frameCount): 163 (WebCore::ImageSource::createFrameImageAtIndex): 164 (WebCore::ImageSource::frameIsCompleteAtIndex): 165 (WebCore::ImageSource::frameDurationAtIndex): 166 (WebCore::ImageSource::frameHasAlphaAtIndex): 167 (WebCore::ImageSource::frameBytesAtIndex): 168 Call m_decoder's function to do the real work. 169 170 (WebCore::ImageSource::dump): Dump the image metadata. 171 172 (WebCore::ImageSource::initialized): Deleted. 173 174 * platform/image-decoders/ImageDecoder.cpp: 175 (WebCore::ImageDecoder::create): 176 * platform/image-decoders/ImageDecoder.h: 177 Change the return of ImageDecoder::create() to be unique_ptr. 178 179 * platform/mac/DragImageMac.mm: 180 (WebCore::createDragImageFromImage): Delete unneeded argument. 181 1 182 2016-03-29 Eric Carlson <eric.carlson@apple.com> 2 183 -
trunk/Source/WebCore/loader/cache/CachedImage.cpp
r198177 r198782 273 273 return LayoutSize(); 274 274 275 LayoutSize imageSize(m_image->size()); 276 277 #if ENABLE(CSS_IMAGE_ORIENTATION) 278 if (renderer && is<BitmapImage>(*m_image)) { 279 ImageOrientationDescription orientationDescription(renderer->shouldRespectImageOrientation(), renderer->style().imageOrientation()); 280 if (orientationDescription.respectImageOrientation() == RespectImageOrientation) 281 imageSize = LayoutSize(downcast<BitmapImage>(*m_image).sizeRespectingOrientation(orientationDescription)); 282 } 283 #else 284 if (is<BitmapImage>(*m_image) && (renderer && renderer->shouldRespectImageOrientation() == RespectImageOrientation)) 275 LayoutSize imageSize; 276 277 if (is<BitmapImage>(*m_image) && renderer && renderer->shouldRespectImageOrientation() == RespectImageOrientation) 285 278 imageSize = LayoutSize(downcast<BitmapImage>(*m_image).sizeRespectingOrientation()); 286 #endif // ENABLE(CSS_IMAGE_ORIENTATION) 287 288 else if (is<SVGImage>(*m_image) && sizeType == UsedSize) { 279 else if (is<SVGImage>(*m_image) && sizeType == UsedSize) 289 280 imageSize = LayoutSize(m_svgImageCache->imageSizeForRenderer(renderer)); 290 } 281 else 282 imageSize = LayoutSize(m_image->size()); 291 283 292 284 if (multiplier == 1.0f) -
trunk/Source/WebCore/platform/graphics/BitmapImage.cpp
r198655 r198782 48 48 BitmapImage::BitmapImage(ImageObserver* observer) 49 49 : Image(observer) 50 , m_minimumSubsamplingLevel(0)51 , m_imageOrientation(OriginTopLeft)52 , m_shouldRespectImageOrientation(false)53 50 , m_currentFrame(0) 54 51 , m_repetitionCount(cAnimationNone) … … 63 60 , m_progressiveLoadChunkTime(0) 64 61 , m_progressiveLoadChunkCount(0) 65 , m_allowSubsampling(true)66 #else67 , m_allowSubsampling(false)68 62 #endif 69 63 , m_isSolidColor(false) … … 237 231 } 238 232 239 void BitmapImage::updateSize( ImageOrientationDescription description) const233 void BitmapImage::updateSize() const 240 234 { 241 235 if (!m_sizeAvailable || m_haveSize) 242 236 return; 243 237 244 m_size = m_source.size(description); 245 m_sizeRespectingOrientation = m_source.size(ImageOrientationDescription(RespectImageOrientation, description.imageOrientation())); 246 247 m_imageOrientation = static_cast<unsigned>(description.imageOrientation()); 248 m_shouldRespectImageOrientation = static_cast<unsigned>(description.respectImageOrientation()); 238 m_size = m_source.size(); 239 m_sizeRespectingOrientation = m_source.sizeRespectingOrientation(); 249 240 250 241 m_haveSize = true; 251 252 determineMinimumSubsamplingLevel();253 242 didDecodeProperties(); 254 243 } … … 260 249 } 261 250 262 IntSize BitmapImage::sizeRespectingOrientation( ImageOrientationDescription description) const263 { 264 updateSize( description);251 IntSize BitmapImage::sizeRespectingOrientation() const 252 { 253 updateSize(); 265 254 return m_sizeRespectingOrientation; 266 255 } … … 392 381 return nullptr; 393 382 394 SubsamplingLevel subsamplingLevel = std::min(m_source.subsamplingLevelForScale(presentationScaleHint), m_minimumSubsamplingLevel);383 SubsamplingLevel subsamplingLevel = m_source.subsamplingLevelForScale(presentationScaleHint); 395 384 396 385 // We may have cached a frame with a higher subsampling level, in which case we need to … … 453 442 { 454 443 if (!ensureFrameIsCached(index, CacheMetadataOnly)) 455 return DefaultImageOrientation;444 return ImageOrientation(); 456 445 457 446 if (m_frames[index].m_haveMetadata) … … 711 700 } 712 701 713 if (allowSubsampling())714 ts.dumpProperty("allow-subsampling", allowSubsampling());715 702 if (m_isSolidColor) 716 703 ts.dumpProperty("solid-color", m_isSolidColor); 717 704 718 if (m_imageOrientation != OriginTopLeft) 719 ts.dumpProperty("orientation", m_imageOrientation); 720 } 721 722 } 705 m_source.dump(ts); 706 } 707 708 } -
trunk/Source/WebCore/platform/graphics/BitmapImage.h
r198655 r198782 124 124 // FloatSize due to override. 125 125 FloatSize size() const override; 126 IntSize sizeRespectingOrientation( ImageOrientationDescription = ImageOrientationDescription()) const;126 IntSize sizeRespectingOrientation() const; 127 127 128 128 bool getHotSpot(IntPoint&) const override; … … 180 180 bool canAnimate(); 181 181 182 bool allowSubsampling() const { return m_allowSubsampling; } 183 void setAllowSubsampling(bool allowSubsampling) { m_allowSubsampling = allowSubsampling; } 182 void setAllowSubsampling(bool allowSubsampling) { m_source.setAllowSubsampling(allowSubsampling); } 184 183 185 184 size_t currentFrame() const { return m_currentFrame; } … … 188 187 bool isBitmapImage() const override { return true; } 189 188 190 void updateSize(ImageOrientationDescription = ImageOrientationDescription()) const; 191 void determineMinimumSubsamplingLevel() const; 189 void updateSize() const; 192 190 193 191 protected: … … 296 294 mutable IntSize m_sizeRespectingOrientation; 297 295 298 mutable SubsamplingLevel m_minimumSubsamplingLevel;299 300 mutable unsigned m_imageOrientation : 4; // ImageOrientationEnum301 mutable unsigned m_shouldRespectImageOrientation : 1; // RespectImageOrientationEnum302 303 296 size_t m_currentFrame; // The index of the current frame of animation. 304 297 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. … … 328 321 uint16_t m_progressiveLoadChunkCount; 329 322 #endif 330 331 bool m_allowSubsampling : 1; // Whether we should attempt subsampling if this image is very large.332 323 bool m_isSolidColor : 1; // Whether or not we are a 1x1 solid image. 333 324 bool m_checkedForSolidColor : 1; // Whether we've checked the frame for solid color. -
trunk/Source/WebCore/platform/graphics/GraphicsContext.h
r198655 r198782 303 303 304 304 #if USE(CG) || USE(CAIRO) 305 WEBCORE_EXPORT void drawNativeImage(const NativeImagePtr&, const FloatSize& selfSize, const FloatRect& destRect, const FloatRect& srcRect, CompositeOperator = CompositeSourceOver, BlendMode = BlendModeNormal, ImageOrientation = DefaultImageOrientation);305 WEBCORE_EXPORT void drawNativeImage(const NativeImagePtr&, const FloatSize& selfSize, const FloatRect& destRect, const FloatRect& srcRect, CompositeOperator = CompositeSourceOver, BlendMode = BlendModeNormal, ImageOrientation = ImageOrientation()); 306 306 #endif 307 307 -
trunk/Source/WebCore/platform/graphics/ImageOrientation.h
r154375 r198782 85 85 class ImageOrientation { 86 86 public: 87 ImageOrientation(ImageOrientationEnum orientation = DefaultImageOrientation) 87 ImageOrientation() 88 : m_orientation(DefaultImageOrientation) 89 { 90 } 91 92 explicit ImageOrientation(ImageOrientationEnum orientation) 88 93 : m_orientation(orientation) 89 94 { … … 102 107 // Values direct from images may be invalid, in which case we use the default. 103 108 if (exifValue < OriginTopLeft || exifValue > OriginLeftBottom) 104 return DefaultImageOrientation;105 return static_cast<ImageOrientationEnum>(exifValue);109 return ImageOrientation(); 110 return ImageOrientation(static_cast<ImageOrientationEnum>(exifValue)); 106 111 } 107 112 … … 110 115 AffineTransform transformFromDefault(const FloatSize& drawnSize) const; 111 116 117 inline operator ImageOrientationEnum() const { return m_orientation; } 118 112 119 inline bool operator==(const ImageOrientation& other) const { return other.m_orientation == m_orientation; } 113 120 inline bool operator!=(const ImageOrientation& other) const { return !(*this == other); } -
trunk/Source/WebCore/platform/graphics/ImageSource.cpp
r198655 r198782 44 44 45 45 ImageSource::ImageSource(ImageSource::AlphaOption alphaOption, ImageSource::GammaAndColorProfileOption gammaAndColorProfileOption) 46 : m_decoder(0) 47 , m_alphaOption(alphaOption) 46 : m_alphaOption(alphaOption) 48 47 , m_gammaAndColorProfileOption(gammaAndColorProfileOption) 49 48 { … … 63 62 } 64 63 65 delete m_decoder;66 m_decoder = 0; 64 m_decoder = nullptr; 65 67 66 if (data) 68 67 setData(data, allDataReceived); 69 68 } 70 69 71 bool ImageSource::initialized() const 72 { 73 return m_decoder; 74 } 75 76 void ImageSource::setData(SharedBuffer* data, bool allDataReceived) 77 { 70 void ImageSource::ensureDecoderIsCreated(SharedBuffer* data) 71 { 72 if (initialized()) 73 return; 74 78 75 // Make the decoder by sniffing the bytes. 79 76 // This method will examine the data and instantiate an instance of the appropriate decoder plugin. 80 77 // If insufficient bytes are available to determine the image type, no decoder plugin will be 81 78 // made. 82 if (!m_decoder) { 83 m_decoder = static_cast<NativeImageDecoderPtr>(NativeImageDecoder::create(*data, m_alphaOption, m_gammaAndColorProfileOption)); 79 m_decoder = ImageDecoder::create(*data, m_alphaOption, m_gammaAndColorProfileOption); 84 80 #if ENABLE(IMAGE_DECODER_DOWN_SAMPLING) 85 86 81 if (m_decoder && s_maxPixelsPerDecodedImage) 82 m_decoder->setMaxNumPixels(s_maxPixelsPerDecodedImage); 87 83 #endif 84 } 85 86 void ImageSource::setData(SharedBuffer* data, bool allDataReceived) 87 { 88 if (!data) 89 return; 90 91 ensureDecoderIsCreated(data); 92 93 if (!initialized()) { 94 ASSERT_NOT_REACHED(); 95 return; 88 96 } 89 97 … … 109 117 bool ImageSource::isSizeAvailable() 110 118 { 111 return m_decoder && m_decoder->isSizeAvailable(); 112 } 113 114 IntSize ImageSource::size(ImageOrientationDescription description) const 115 { 116 return frameSizeAtIndex(0, 0, description); 117 } 118 119 IntSize ImageSource::frameSizeAtIndex(size_t index, SubsamplingLevel, ImageOrientationDescription description) const 120 { 121 if (!m_decoder) 122 return IntSize(); 119 return initialized() && m_decoder->isSizeAvailable(); 120 } 121 122 IntSize ImageSource::size() const 123 { 124 return frameSizeAtIndex(0, 0); 125 } 126 127 IntSize ImageSource::sizeRespectingOrientation() const 128 { 129 return frameSizeAtIndex(0, 0, RespectImageOrientation); 130 } 131 132 IntSize ImageSource::frameSizeAtIndex(size_t index, SubsamplingLevel, RespectImageOrientationEnum shouldRespectImageOrientation) const 133 { 134 if (!initialized()) 135 return { }; 123 136 124 137 IntSize size = m_decoder->frameSizeAtIndex(index); 125 if ((description.respectImageOrientation() == RespectImageOrientation) && m_decoder->orientation().usesWidthAsHeight()) 126 return IntSize(size.height(), size.width()); 127 128 return size; 138 ImageOrientation orientation = m_decoder->orientation(); 139 140 return shouldRespectImageOrientation == RespectImageOrientation && orientation.usesWidthAsHeight() ? size.transposedSize() : size; 129 141 } 130 142 131 143 bool ImageSource::getHotSpot(IntPoint& hotSpot) const 132 144 { 133 return m_decoder ? m_decoder->hotSpot(hotSpot) : false;145 return initialized() && m_decoder->hotSpot(hotSpot); 134 146 } 135 147 … … 141 153 int ImageSource::repetitionCount() 142 154 { 143 return m_decoder? m_decoder->repetitionCount() : cAnimationNone;155 return initialized() ? m_decoder->repetitionCount() : cAnimationNone; 144 156 } 145 157 146 158 size_t ImageSource::frameCount() const 147 159 { 148 return m_decoder? m_decoder->frameCount() : 0;160 return initialized() ? m_decoder->frameCount() : 0; 149 161 } 150 162 151 163 NativeImagePtr ImageSource::createFrameImageAtIndex(size_t index, SubsamplingLevel) 152 164 { 153 if (!m_decoder) 154 return nullptr; 155 156 ImageFrame* buffer = m_decoder->frameBufferAtIndex(index); 157 if (!buffer || buffer->status() == ImageFrame::FrameEmpty) 165 if (!initialized()) 158 166 return nullptr; 159 167 … … 163 171 return nullptr; 164 172 173 ImageFrame* buffer = m_decoder->frameBufferAtIndex(index); 174 if (!buffer || buffer->status() == ImageFrame::FrameEmpty) 175 return nullptr; 176 165 177 // Return the buffer contents as a native image. For some ports, the data 166 178 // is already in a native container, and this just increments its refcount. … … 170 182 float ImageSource::frameDurationAtIndex(size_t index) 171 183 { 172 if (! m_decoder)184 if (!initialized()) 173 185 return 0; 174 186 … … 189 201 ImageOrientation ImageSource::orientationAtIndex(size_t) const 190 202 { 191 return m_decoder ? m_decoder->orientation() : DefaultImageOrientation;203 return initialized() ? m_decoder->orientation() : ImageOrientation(); 192 204 } 193 205 194 206 bool ImageSource::frameHasAlphaAtIndex(size_t index) 195 207 { 196 if (!m_decoder) 197 return true; 198 return m_decoder->frameHasAlphaAtIndex(index); 208 return !initialized() || m_decoder->frameHasAlphaAtIndex(index); 199 209 } 200 210 201 211 bool ImageSource::frameIsCompleteAtIndex(size_t index) 202 212 { 203 if (! m_decoder)213 if (!initialized()) 204 214 return false; 205 215 … … 210 220 unsigned ImageSource::frameBytesAtIndex(size_t index, SubsamplingLevel) const 211 221 { 212 if (!m_decoder) 213 return 0; 214 return m_decoder->frameBytesAtIndex(index); 215 } 216 222 return initialized() ? m_decoder->frameBytesAtIndex(index) : 0; 223 } 224 225 void ImageSource::dump(TextStream& ts) const 226 { 227 if (m_allowSubsampling) 228 ts.dumpProperty("allow-subsampling", m_allowSubsampling); 229 230 ImageOrientation orientation = orientationAtIndex(0); 231 if (orientation != OriginTopLeft) 232 ts.dumpProperty("orientation", orientation); 233 } 234 217 235 } 218 236 -
trunk/Source/WebCore/platform/graphics/ImageSource.h
r198655 r198782 30 30 #include "ImageOrientation.h" 31 31 #include "NativeImagePtr.h" 32 #include "TextStream.h" 32 33 33 34 #include <wtf/Forward.h> … … 46 47 class IntSize; 47 48 class SharedBuffer; 48 49 #if USE(CG)50 typedef CGImageSourceRef NativeImageDecoderPtr;51 #else52 49 class ImageDecoder; 53 typedef ImageDecoder* NativeImageDecoderPtr;54 #endif55 56 #if USE(CG)57 #define NativeImageDecoder ImageDecoder58 #else59 typedef ImageDecoder NativeImageDecoder;60 #endif61 50 62 51 // Right now GIFs are the only recognized image format that supports animation. … … 83 72 class ImageSource { 84 73 WTF_MAKE_NONCOPYABLE(ImageSource); 74 friend class BitmapImage; 85 75 public: 86 76 enum AlphaOption { … … 123 113 bool allDataReceived = false); 124 114 125 bool initialized() const ;115 bool initialized() const { return m_decoder.get(); } 126 116 127 117 void setData(SharedBuffer* data, bool allDataReceived); … … 130 120 SubsamplingLevel subsamplingLevelForScale(float) const; 131 121 bool allowSubsamplingOfFrameAtIndex(size_t) const; 122 void setAllowSubsampling(bool allowSubsampling) { m_allowSubsampling = allowSubsampling; } 123 SubsamplingLevel maximumSubsamplingLevel() const; 132 124 133 125 bool isSizeAvailable(); 126 134 127 // Always original size, without subsampling. 135 IntSize size(ImageOrientationDescription = ImageOrientationDescription()) const; 128 IntSize size() const; 129 IntSize sizeRespectingOrientation() const; 130 136 131 // Size of optionally subsampled frame. 137 IntSize frameSizeAtIndex(size_t, SubsamplingLevel = 0, ImageOrientationDescription = ImageOrientationDescription()) const;132 IntSize frameSizeAtIndex(size_t, SubsamplingLevel = 0, RespectImageOrientationEnum = DoNotRespectImageOrientation) const; 138 133 139 134 bool getHotSpot(IntPoint&) const; … … 164 159 165 160 private: 166 NativeImageDecoderPtr m_decoder; 161 void ensureDecoderIsCreated(SharedBuffer*); 162 SubsamplingLevel calculateMaximumSubsamplingLevel() const; 163 void dump(TextStream&) const; 164 165 std::unique_ptr<ImageDecoder> m_decoder; 166 167 #if PLATFORM(IOS) 168 bool m_allowSubsampling { true }; 169 #else 170 bool m_allowSubsampling { false }; 171 #endif 167 172 168 173 #if !USE(CG) -
trunk/Source/WebCore/platform/graphics/cairo/BitmapImageCairo.cpp
r198655 r198782 42 42 : Image(observer) 43 43 , m_size(cairoSurfaceSize(nativeImage.get())) 44 , m_minimumSubsamplingLevel(0)45 44 , m_currentFrame(0) 46 45 , m_repetitionCount(cAnimationNone) … … 123 122 } 124 123 125 void BitmapImage::determineMinimumSubsamplingLevel() const126 {127 m_minimumSubsamplingLevel = 0;128 }129 130 124 void BitmapImage::checkForSolidColor() 131 125 { -
trunk/Source/WebCore/platform/graphics/cg/BitmapImageCG.cpp
r198655 r198782 56 56 m_haveMetadata = false; 57 57 58 m_orientation = DefaultImageOrientation;59 58 m_subsamplingLevel = 0; 60 59 … … 71 70 BitmapImage::BitmapImage(RetainPtr<CGImageRef>&& image, ImageObserver* observer) 72 71 : Image(observer) 73 , m_minimumSubsamplingLevel(0)74 , m_imageOrientation(OriginTopLeft)75 , m_shouldRespectImageOrientation(false)76 72 , m_currentFrame(0) 77 73 , m_repetitionCount(cAnimationNone) … … 106 102 } 107 103 108 void BitmapImage::determineMinimumSubsamplingLevel() const109 {110 if (!m_allowSubsampling)111 return;112 113 if (!m_source.allowSubsamplingOfFrameAtIndex(0))114 return;115 116 // Values chosen to be appropriate for iOS.117 const int cMaximumImageAreaBeforeSubsampling = 5 * 1024 * 1024;118 const SubsamplingLevel maxSubsamplingLevel = 3;119 120 SubsamplingLevel currentLevel = 0;121 for ( ; currentLevel <= maxSubsamplingLevel; ++currentLevel) {122 IntSize frameSize = m_source.frameSizeAtIndex(0, currentLevel);123 if (frameSize.area() < cMaximumImageAreaBeforeSubsampling)124 break;125 }126 127 m_minimumSubsamplingLevel = currentLevel;128 }129 130 104 void BitmapImage::checkForSolidColor() 131 105 { -
trunk/Source/WebCore/platform/graphics/cg/ImageSourceCG.cpp
r198655 r198782 52 52 53 53 namespace WebCore { 54 55 class ImageDecoder { 56 public: 57 ImageDecoder(); 58 59 static std::unique_ptr<ImageDecoder> create() 60 { 61 return std::make_unique<ImageDecoder>(); 62 } 63 64 static size_t bytesDecodedToDetermineProperties(); 65 static SubsamplingLevel subsamplingLevelForScale(float scale, SubsamplingLevel maximumSubsamplingLevel); 66 67 String filenameExtension() const; 68 bool isSizeAvailable() const; 69 70 // Always original size, without subsampling. 71 IntSize size() const; 72 size_t frameCount() const; 73 int repetitionCount() const; 74 bool hotSpot(IntPoint& hotSpot) const; 75 76 IntSize frameSizeAtIndex(size_t, SubsamplingLevel) const; 77 bool frameIsCompleteAtIndex(size_t) const; 78 ImageOrientation orientationAtIndex(size_t) const; 79 80 float frameDurationAtIndex(size_t) const; 81 bool frameHasAlphaAtIndex(size_t) const; 82 bool allowSubsamplingOfFrameAtIndex(size_t) const; 83 unsigned frameBytesAtIndex(size_t, SubsamplingLevel = 0) const; 84 85 NativeImagePtr createFrameImageAtIndex(size_t, SubsamplingLevel) const; 86 87 void setData(CFDataRef, bool allDataReceived); 88 void setData(SharedBuffer*, bool allDataReceived); 89 90 protected: 91 mutable IntSize m_size; 92 RetainPtr<CGImageSourceRef> m_nativeDecoder; 93 }; 54 94 55 95 const CFStringRef WebCoreCGImagePropertyAPNGUnclampedDelayTime = CFSTR("UnclampedDelayTime"); … … 59 99 const CFStringRef kCGImageSourceShouldPreferRGB32 = CFSTR("kCGImageSourceShouldPreferRGB32"); 60 100 const CFStringRef kCGImageSourceSkipMetadata = CFSTR("kCGImageSourceSkipMetadata"); 61 62 #if !PLATFORM(COCOA)63 size_t sharedBufferGetBytesAtPosition(void* info, void* buffer, off_t position, size_t count)64 {65 SharedBuffer* sharedBuffer = static_cast<SharedBuffer*>(info);66 size_t sourceSize = sharedBuffer->size();67 if (position >= sourceSize)68 return 0;69 70 const char* source = sharedBuffer->data() + position;71 size_t amount = std::min<size_t>(count, sourceSize - position);72 memcpy(buffer, source, amount);73 return amount;74 }75 76 void sharedBufferRelease(void* info)77 {78 SharedBuffer* sharedBuffer = static_cast<SharedBuffer*>(info);79 sharedBuffer->deref();80 }81 #endif82 83 ImageSource::ImageSource(ImageSource::AlphaOption, ImageSource::GammaAndColorProfileOption)84 : m_decoder(0)85 {86 // FIXME: AlphaOption and GammaAndColorProfileOption are ignored.87 }88 89 ImageSource::~ImageSource()90 {91 clear(true);92 }93 94 void ImageSource::clear(bool destroyAllFrames, size_t, SharedBuffer* data, bool allDataReceived)95 {96 // Recent versions of ImageIO discard previously decoded image frames if the client97 // application no longer holds references to them, so there's no need to throw away98 // the decoder unless we're explicitly asked to destroy all of the frames.99 if (!destroyAllFrames)100 return;101 102 if (m_decoder) {103 CFRelease(m_decoder);104 m_decoder = 0;105 }106 if (data)107 setData(data, allDataReceived);108 }109 101 110 102 static RetainPtr<CFDictionaryRef> createImageSourceOptions(SubsamplingLevel subsamplingLevel) … … 136 128 } 137 129 138 bool ImageSource::initialized() const139 {140 return m_decoder;141 }142 143 void ImageSource::setData(SharedBuffer* data, bool allDataReceived)144 {145 #if PLATFORM(COCOA)146 if (!m_decoder)147 m_decoder = CGImageSourceCreateIncremental(0);148 // On Mac the NSData inside the SharedBuffer can be secretly appended to without the SharedBuffer's knowledge. We use SharedBuffer's ability149 // to wrap itself inside CFData to get around this, ensuring that ImageIO is really looking at the SharedBuffer.150 CGImageSourceUpdateData(m_decoder, data->createCFData().get(), allDataReceived);151 #else152 if (!m_decoder)153 m_decoder = CGImageSourceCreateIncremental(0);154 // Create a CGDataProvider to wrap the SharedBuffer.155 data->ref();156 // We use the GetBytesAtPosition callback rather than the GetBytePointer one because SharedBuffer157 // does not provide a way to lock down the byte pointer and guarantee that it won't move, which158 // is a requirement for using the GetBytePointer callback.159 CGDataProviderDirectCallbacks providerCallbacks = { 0, 0, 0, sharedBufferGetBytesAtPosition, sharedBufferRelease };160 RetainPtr<CGDataProviderRef> dataProvider = adoptCF(CGDataProviderCreateDirect(data, data->size(), &providerCallbacks));161 CGImageSourceUpdateDataProvider(m_decoder, dataProvider.get(), allDataReceived);162 #endif163 }164 165 String ImageSource::filenameExtension() const166 {167 if (!m_decoder)168 return String();169 CFStringRef imageSourceType = CGImageSourceGetType(m_decoder);170 return WebCore::preferredExtensionForImageSourceType(imageSourceType);171 }172 173 SubsamplingLevel ImageSource::subsamplingLevelForScale(float scale) const174 {175 // There are four subsampling levels: 0 = 1x, 1 = 0.5x, 2 = 0.25x, 3 = 0.125x.176 float clampedScale = std::max<float>(0.125, std::min<float>(1, scale));177 int result = ceilf(log2f(1 / clampedScale));178 ASSERT(result >=0 && result <= 3);179 return result;180 }181 182 bool ImageSource::isSizeAvailable()183 {184 // Ragnaros yells: TOO SOON! You have awakened me TOO SOON, Executus!185 if (CGImageSourceGetStatus(m_decoder) < kCGImageStatusIncomplete)186 return false;187 188 RetainPtr<CFDictionaryRef> image0Properties = adoptCF(CGImageSourceCopyPropertiesAtIndex(m_decoder, 0, imageSourceOptions().get()));189 if (!image0Properties)190 return false;191 192 return CFDictionaryContainsKey(image0Properties.get(), kCGImagePropertyPixelWidth)193 && CFDictionaryContainsKey(image0Properties.get(), kCGImagePropertyPixelHeight);194 }195 196 130 static ImageOrientation orientationFromProperties(CFDictionaryRef imageProperties) 197 131 { … … 199 133 CFNumberRef orientationProperty = (CFNumberRef)CFDictionaryGetValue(imageProperties, kCGImagePropertyOrientation); 200 134 if (!orientationProperty) 201 return DefaultImageOrientation;135 return ImageOrientation(); 202 136 203 137 int exifValue; … … 206 140 } 207 141 208 bool ImageSource::allowSubsamplingOfFrameAtIndex(size_t) const 209 { 210 RetainPtr<CFDictionaryRef> properties = adoptCF(CGImageSourceCopyPropertiesAtIndex(m_decoder, 0, imageSourceOptions().get())); 142 #if !PLATFORM(COCOA) 143 size_t sharedBufferGetBytesAtPosition(void* info, void* buffer, off_t position, size_t count) 144 { 145 SharedBuffer* sharedBuffer = static_cast<SharedBuffer*>(info); 146 size_t sourceSize = sharedBuffer->size(); 147 if (position >= sourceSize) 148 return 0; 149 150 const char* source = sharedBuffer->data() + position; 151 size_t amount = std::min<size_t>(count, sourceSize - position); 152 memcpy(buffer, source, amount); 153 return amount; 154 } 155 156 void sharedBufferRelease(void* info) 157 { 158 SharedBuffer* sharedBuffer = static_cast<SharedBuffer*>(info); 159 sharedBuffer->deref(); 160 } 161 #endif 162 163 ImageDecoder::ImageDecoder() 164 { 165 m_nativeDecoder = adoptCF(CGImageSourceCreateIncremental(nullptr)); 166 } 167 168 SubsamplingLevel ImageDecoder::subsamplingLevelForScale(float scale, SubsamplingLevel maximumSubsamplingLevel) 169 { 170 // There are four subsampling levels: 0 = 1x, 1 = 0.5x, 2 = 0.25x, 3 = 0.125x. 171 float clampedScale = std::max<float>(0.125, std::min<float>(1, scale)); 172 SubsamplingLevel result = ceilf(log2f(1 / clampedScale)); 173 ASSERT(result >=0 && result <= 3); 174 return std::min(result, maximumSubsamplingLevel); 175 } 176 177 size_t ImageDecoder::bytesDecodedToDetermineProperties() 178 { 179 // Measured by tracing malloc/calloc calls on Mac OS 10.6.6, x86_64. 180 // A non-zero value ensures cached images with no decoded frames still enter 181 // the live decoded resources list when the CGImageSource decodes image 182 // properties, allowing the cache to prune the partially decoded image. 183 // This value is likely to be inaccurate on other platforms, but the overall 184 // behavior is unchanged. 185 return 13088; 186 } 187 188 String ImageDecoder::filenameExtension() const 189 { 190 CFStringRef imageSourceType = CGImageSourceGetType(m_nativeDecoder.get()); 191 return WebCore::preferredExtensionForImageSourceType(imageSourceType); 192 } 193 194 bool ImageDecoder::isSizeAvailable() const 195 { 196 // Ragnaros yells: TOO SOON! You have awakened me TOO SOON, Executus! 197 if (CGImageSourceGetStatus(m_nativeDecoder.get()) < kCGImageStatusIncomplete) 198 return false; 199 200 RetainPtr<CFDictionaryRef> image0Properties = adoptCF(CGImageSourceCopyPropertiesAtIndex(m_nativeDecoder.get(), 0, imageSourceOptions().get())); 201 if (!image0Properties) 202 return false; 203 204 return CFDictionaryContainsKey(image0Properties.get(), kCGImagePropertyPixelWidth) 205 && CFDictionaryContainsKey(image0Properties.get(), kCGImagePropertyPixelHeight); 206 } 207 208 IntSize ImageDecoder::size() const 209 { 210 if (m_size.isEmpty()) 211 m_size = frameSizeAtIndex(0, 0); 212 return m_size; 213 } 214 215 size_t ImageDecoder::frameCount() const 216 { 217 return CGImageSourceGetCount(m_nativeDecoder.get()); 218 } 219 220 int ImageDecoder::repetitionCount() const 221 { 222 RetainPtr<CFDictionaryRef> properties = adoptCF(CGImageSourceCopyProperties(m_nativeDecoder.get(), imageSourceOptions().get())); 223 if (!properties) 224 return cAnimationLoopOnce; 225 226 CFDictionaryRef gifProperties = (CFDictionaryRef)CFDictionaryGetValue(properties.get(), kCGImagePropertyGIFDictionary); 227 if (gifProperties) { 228 CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(gifProperties, kCGImagePropertyGIFLoopCount); 229 230 // No property means loop once. 231 if (!num) 232 return cAnimationLoopOnce; 233 234 int loopCount; 235 CFNumberGetValue(num, kCFNumberIntType, &loopCount); 236 237 // A property with value 0 means loop forever. 238 return loopCount ? loopCount : cAnimationLoopInfinite; 239 } 240 241 CFDictionaryRef pngProperties = (CFDictionaryRef)CFDictionaryGetValue(properties.get(), kCGImagePropertyPNGDictionary); 242 if (pngProperties) { 243 CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(pngProperties, WebCoreCGImagePropertyAPNGLoopCount); 244 if (!num) 245 return cAnimationLoopOnce; 246 247 int loopCount; 248 CFNumberGetValue(num, kCFNumberIntType, &loopCount); 249 return loopCount ? loopCount : cAnimationLoopInfinite; 250 } 251 252 // Turns out we're not an animated image after all, so we don't animate. 253 return cAnimationNone; 254 } 255 256 bool ImageDecoder::hotSpot(IntPoint& hotSpot) const 257 { 258 RetainPtr<CFDictionaryRef> properties = adoptCF(CGImageSourceCopyPropertiesAtIndex(m_nativeDecoder.get(), 0, imageSourceOptions().get())); 259 if (!properties) 260 return false; 261 262 int x = -1, y = -1; 263 CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(properties.get(), CFSTR("hotspotX")); 264 if (!num || !CFNumberGetValue(num, kCFNumberIntType, &x)) 265 return false; 266 267 num = (CFNumberRef)CFDictionaryGetValue(properties.get(), CFSTR("hotspotY")); 268 if (!num || !CFNumberGetValue(num, kCFNumberIntType, &y)) 269 return false; 270 271 if (x < 0 || y < 0) 272 return false; 273 274 hotSpot = IntPoint(x, y); 275 return true; 276 } 277 278 IntSize ImageDecoder::frameSizeAtIndex(size_t index, SubsamplingLevel subsamplingLevel) const 279 { 280 RetainPtr<CFDictionaryRef> properties = adoptCF(CGImageSourceCopyPropertiesAtIndex(m_nativeDecoder.get(), index, imageSourceOptions(subsamplingLevel).get())); 281 282 if (!properties) 283 return { }; 284 285 int width = 0; 286 int height = 0; 287 CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(properties.get(), kCGImagePropertyPixelWidth); 288 if (num) 289 CFNumberGetValue(num, kCFNumberIntType, &width); 290 291 num = (CFNumberRef)CFDictionaryGetValue(properties.get(), kCGImagePropertyPixelHeight); 292 if (num) 293 CFNumberGetValue(num, kCFNumberIntType, &height); 294 295 return IntSize(width, height); 296 } 297 298 bool ImageDecoder::frameIsCompleteAtIndex(size_t index) const 299 { 300 ASSERT(frameCount()); 301 return CGImageSourceGetStatusAtIndex(m_nativeDecoder.get(), index) == kCGImageStatusComplete; 302 } 303 304 ImageOrientation ImageDecoder::orientationAtIndex(size_t index) const 305 { 306 RetainPtr<CFDictionaryRef> properties = adoptCF(CGImageSourceCopyPropertiesAtIndex(m_nativeDecoder.get(), index, imageSourceOptions().get())); 307 if (!properties) 308 return ImageOrientation(); 309 310 return orientationFromProperties(properties.get()); 311 } 312 313 float ImageDecoder::frameDurationAtIndex(size_t index) const 314 { 315 float duration = 0; 316 RetainPtr<CFDictionaryRef> properties = adoptCF(CGImageSourceCopyPropertiesAtIndex(m_nativeDecoder.get(), index, imageSourceOptions().get())); 317 if (properties) { 318 CFDictionaryRef gifProperties = (CFDictionaryRef)CFDictionaryGetValue(properties.get(), kCGImagePropertyGIFDictionary); 319 if (gifProperties) { 320 if (CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(gifProperties, kCGImagePropertyGIFUnclampedDelayTime)) { 321 // Use the unclamped frame delay if it exists. 322 CFNumberGetValue(num, kCFNumberFloatType, &duration); 323 } else if (CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(gifProperties, kCGImagePropertyGIFDelayTime)) { 324 // Fall back to the clamped frame delay if the unclamped frame delay does not exist. 325 CFNumberGetValue(num, kCFNumberFloatType, &duration); 326 } 327 } 328 329 CFDictionaryRef pngProperties = (CFDictionaryRef)CFDictionaryGetValue(properties.get(), kCGImagePropertyPNGDictionary); 330 if (pngProperties) { 331 if (CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(pngProperties, WebCoreCGImagePropertyAPNGUnclampedDelayTime)) 332 CFNumberGetValue(num, kCFNumberFloatType, &duration); 333 else if (CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(pngProperties, WebCoreCGImagePropertyAPNGDelayTime)) 334 CFNumberGetValue(num, kCFNumberFloatType, &duration); 335 } 336 } 337 338 // Many annoying ads specify a 0 duration to make an image flash as quickly as possible. 339 // We follow Firefox's behavior and use a duration of 100 ms for any frames that specify 340 // a duration of <= 10 ms. See <rdar://problem/7689300> and <http://webkit.org/b/36082> 341 // for more information. 342 if (duration < 0.011f) 343 return 0.1f; 344 return duration; 345 } 346 347 bool ImageDecoder::allowSubsamplingOfFrameAtIndex(size_t) const 348 { 349 RetainPtr<CFDictionaryRef> properties = adoptCF(CGImageSourceCopyPropertiesAtIndex(m_nativeDecoder.get(), 0, imageSourceOptions().get())); 211 350 if (!properties) 212 351 return false; … … 228 367 } 229 368 230 IntSize ImageSource::frameSizeAtIndex(size_t index, SubsamplingLevel subsamplingLevel, ImageOrientationDescription description) const 231 { 232 RetainPtr<CFDictionaryRef> properties = adoptCF(CGImageSourceCopyPropertiesAtIndex(m_decoder, index, imageSourceOptions(subsamplingLevel).get())); 233 234 if (!properties) 235 return IntSize(); 236 237 int width = 0; 238 int height = 0; 239 CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(properties.get(), kCGImagePropertyPixelWidth); 240 if (num) 241 CFNumberGetValue(num, kCFNumberIntType, &width); 242 num = (CFNumberRef)CFDictionaryGetValue(properties.get(), kCGImagePropertyPixelHeight); 243 if (num) 244 CFNumberGetValue(num, kCFNumberIntType, &height); 245 246 if ((description.respectImageOrientation() == RespectImageOrientation) && orientationFromProperties(properties.get()).usesWidthAsHeight()) 247 return IntSize(height, width); 248 249 return IntSize(width, height); 250 } 251 252 ImageOrientation ImageSource::orientationAtIndex(size_t index) const 253 { 254 RetainPtr<CFDictionaryRef> properties = adoptCF(CGImageSourceCopyPropertiesAtIndex(m_decoder, index, imageSourceOptions().get())); 255 if (!properties) 256 return DefaultImageOrientation; 257 258 return orientationFromProperties(properties.get()); 259 } 260 261 IntSize ImageSource::size(ImageOrientationDescription description) const 262 { 263 return frameSizeAtIndex(0, 0, description); 264 } 265 266 bool ImageSource::getHotSpot(IntPoint& hotSpot) const 267 { 268 RetainPtr<CFDictionaryRef> properties = adoptCF(CGImageSourceCopyPropertiesAtIndex(m_decoder, 0, imageSourceOptions().get())); 269 if (!properties) 270 return false; 271 272 int x = -1, y = -1; 273 CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(properties.get(), CFSTR("hotspotX")); 274 if (!num || !CFNumberGetValue(num, kCFNumberIntType, &x)) 275 return false; 276 277 num = (CFNumberRef)CFDictionaryGetValue(properties.get(), CFSTR("hotspotY")); 278 if (!num || !CFNumberGetValue(num, kCFNumberIntType, &y)) 279 return false; 280 281 if (x < 0 || y < 0) 282 return false; 283 284 hotSpot = IntPoint(x, y); 369 bool ImageDecoder::frameHasAlphaAtIndex(size_t index) const 370 { 371 if (!frameIsCompleteAtIndex(index)) 372 return true; 373 374 CFStringRef imageType = CGImageSourceGetType(m_nativeDecoder.get()); 375 376 // Return false if there is no image type or the image type is JPEG, because 377 // JPEG does not support alpha transparency. 378 if (!imageType || CFEqual(imageType, CFSTR("public.jpeg"))) 379 return false; 380 381 // FIXME: Could return false for other non-transparent image formats. 382 // FIXME: Could maybe return false for a GIF Frame if we have enough info in the GIF properties dictionary 383 // to determine whether or not a transparent color was defined. 285 384 return true; 286 385 } 287 386 288 size_t ImageSource::bytesDecodedToDetermineProperties() const 289 { 290 // Measured by tracing malloc/calloc calls on Mac OS 10.6.6, x86_64. 291 // A non-zero value ensures cached images with no decoded frames still enter 292 // the live decoded resources list when the CGImageSource decodes image 293 // properties, allowing the cache to prune the partially decoded image. 294 // This value is likely to be inaccurate on other platforms, but the overall 295 // behavior is unchanged. 296 return 13088; 297 } 298 299 int ImageSource::repetitionCount() 300 { 301 if (!initialized()) 302 return cAnimationLoopOnce; 303 304 RetainPtr<CFDictionaryRef> properties = adoptCF(CGImageSourceCopyProperties(m_decoder, imageSourceOptions().get())); 305 if (!properties) 306 return cAnimationLoopOnce; 307 308 CFDictionaryRef gifProperties = (CFDictionaryRef)CFDictionaryGetValue(properties.get(), kCGImagePropertyGIFDictionary); 309 if (gifProperties) { 310 CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(gifProperties, kCGImagePropertyGIFLoopCount); 311 312 // No property means loop once. 313 if (!num) 314 return cAnimationLoopOnce; 315 316 int loopCount; 317 CFNumberGetValue(num, kCFNumberIntType, &loopCount); 318 319 // A property with value 0 means loop forever. 320 return loopCount ? loopCount : cAnimationLoopInfinite; 321 } 322 323 CFDictionaryRef pngProperties = (CFDictionaryRef)CFDictionaryGetValue(properties.get(), kCGImagePropertyPNGDictionary); 324 if (pngProperties) { 325 CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(pngProperties, WebCoreCGImagePropertyAPNGLoopCount); 326 if (!num) 327 return cAnimationLoopOnce; 328 329 int loopCount; 330 CFNumberGetValue(num, kCFNumberIntType, &loopCount); 331 return loopCount ? loopCount : cAnimationLoopInfinite; 332 } 333 334 // Turns out we're not an animated image after all, so we don't animate. 335 return cAnimationNone; 336 } 337 338 size_t ImageSource::frameCount() const 339 { 340 return m_decoder ? CGImageSourceGetCount(m_decoder) : 0; 341 } 342 343 RetainPtr<CGImageRef> ImageSource::createFrameImageAtIndex(size_t index, SubsamplingLevel subsamplingLevel) 344 { 345 if (!initialized()) 346 return nullptr; 347 348 RetainPtr<CGImageRef> image = adoptCF(CGImageSourceCreateImageAtIndex(m_decoder, index, imageSourceOptions(subsamplingLevel).get())); 387 unsigned ImageDecoder::frameBytesAtIndex(size_t index, SubsamplingLevel subsamplingLevel) const 388 { 389 IntSize frameSize = frameSizeAtIndex(index, subsamplingLevel); 390 return frameSize.area() * 4; 391 } 392 393 NativeImagePtr ImageDecoder::createFrameImageAtIndex(size_t index, SubsamplingLevel subsamplingLevel) const 394 { 395 RetainPtr<CGImageRef> image = adoptCF(CGImageSourceCreateImageAtIndex(m_nativeDecoder.get(), index, imageSourceOptions(subsamplingLevel).get())); 349 396 350 397 #if PLATFORM(IOS) … … 357 404 #pragma clang diagnostic ignored "-Wdeprecated-declarations" 358 405 #endif 359 CGImageSetCachingFlags(image.get(), kCGImageCachingTemporary);406 CGImageSetCachingFlags(image.get(), kCGImageCachingTemporary); 360 407 #if COMPILER(CLANG) 361 408 #pragma clang diagnostic pop … … 363 410 #endif // PLATFORM(IOS) 364 411 365 CFStringRef imageUTI = CGImageSourceGetType(m_ decoder);412 CFStringRef imageUTI = CGImageSourceGetType(m_nativeDecoder.get()); 366 413 static const CFStringRef xbmUTI = CFSTR("public.xbitmap-image"); 367 414 … … 371 418 if (!CFEqual(imageUTI, xbmUTI)) 372 419 return image; 373 420 374 421 // If it is an xbm image, mask out all the white areas to render them transparent. 375 422 const CGFloat maskingColors[6] = {255, 255, 255, 255, 255, 255}; … … 378 425 } 379 426 427 void ImageDecoder::setData(CFDataRef data, bool allDataReceived) 428 { 429 CGImageSourceUpdateData(m_nativeDecoder.get(), data, allDataReceived); 430 } 431 432 void ImageDecoder::setData(SharedBuffer* data, bool allDataReceived) 433 { 434 #if PLATFORM(COCOA) 435 // On Mac the NSData inside the SharedBuffer can be secretly appended to without the SharedBuffer's knowledge. 436 // We use SharedBuffer's ability to wrap itself inside CFData to get around this, ensuring that ImageIO is 437 // really looking at the SharedBuffer. 438 setData(data->createCFData().get(), allDataReceived); 439 CGImageSourceUpdateData(m_nativeDecoder.get(), data->createCFData().get(), allDataReceived); 440 #else 441 // Create a CGDataProvider to wrap the SharedBuffer. 442 data->ref(); 443 // We use the GetBytesAtPosition callback rather than the GetBytePointer one because SharedBuffer 444 // does not provide a way to lock down the byte pointer and guarantee that it won't move, which 445 // is a requirement for using the GetBytePointer callback. 446 CGDataProviderDirectCallbacks providerCallbacks = { 0, 0, 0, sharedBufferGetBytesAtPosition, sharedBufferRelease }; 447 RetainPtr<CGDataProviderRef> dataProvider = adoptCF(CGDataProviderCreateDirect(data, data->size(), &providerCallbacks)); 448 CGImageSourceUpdateDataProvider(m_nativeDecoder.get(), dataProvider.get(), allDataReceived); 449 #endif 450 } 451 452 ImageSource::ImageSource(ImageSource::AlphaOption, ImageSource::GammaAndColorProfileOption) 453 { 454 // FIXME: AlphaOption and GammaAndColorProfileOption are ignored. 455 } 456 457 ImageSource::~ImageSource() 458 { 459 clear(true); 460 } 461 462 void ImageSource::clear(bool destroyAllFrames, size_t, SharedBuffer* data, bool allDataReceived) 463 { 464 // Recent versions of ImageIO discard previously decoded image frames if the client 465 // application no longer holds references to them, so there's no need to throw away 466 // the decoder unless we're explicitly asked to destroy all of the frames. 467 if (!destroyAllFrames) 468 return; 469 470 m_decoder = nullptr; 471 472 if (data) 473 setData(data, allDataReceived); 474 } 475 476 void ImageSource::ensureDecoderIsCreated(SharedBuffer*) 477 { 478 if (initialized()) 479 return; 480 m_decoder = ImageDecoder::create(); 481 } 482 483 void ImageSource::setData(SharedBuffer* data, bool allDataReceived) 484 { 485 if (!data) 486 return; 487 488 ensureDecoderIsCreated(data); 489 490 if (!initialized()) { 491 ASSERT_NOT_REACHED(); 492 return; 493 } 494 495 m_decoder->setData(data, allDataReceived); 496 } 497 498 String ImageSource::filenameExtension() const 499 { 500 return initialized() ? m_decoder->filenameExtension() : String(); 501 } 502 503 SubsamplingLevel ImageSource::calculateMaximumSubsamplingLevel() const 504 { 505 if (!m_allowSubsampling || !allowSubsamplingOfFrameAtIndex(0)) 506 return 0; 507 508 // Values chosen to be appropriate for iOS. 509 const int cMaximumImageAreaBeforeSubsampling = 5 * 1024 * 1024; 510 const SubsamplingLevel maxSubsamplingLevel = 3; 511 512 SubsamplingLevel currentLevel = 0; 513 for ( ; currentLevel <= maxSubsamplingLevel; ++currentLevel) { 514 IntSize frameSize = frameSizeAtIndex(0, currentLevel); 515 if (frameSize.area() < cMaximumImageAreaBeforeSubsampling) 516 break; 517 } 518 519 return currentLevel; 520 } 521 522 SubsamplingLevel ImageSource::maximumSubsamplingLevel() const 523 { 524 #if PLATFORM(IOS) 525 return calculateMaximumSubsamplingLevel(); 526 #endif 527 return 0; 528 } 529 530 SubsamplingLevel ImageSource::subsamplingLevelForScale(float scale) const 531 { 532 return ImageDecoder::subsamplingLevelForScale(scale, maximumSubsamplingLevel()); 533 } 534 535 bool ImageSource::isSizeAvailable() 536 { 537 return initialized() && m_decoder->isSizeAvailable(); 538 } 539 540 bool ImageSource::allowSubsamplingOfFrameAtIndex(size_t index) const 541 { 542 return initialized() && m_decoder->allowSubsamplingOfFrameAtIndex(index); 543 } 544 545 IntSize ImageSource::frameSizeAtIndex(size_t index, SubsamplingLevel subsamplingLevel, RespectImageOrientationEnum shouldRespectImageOrientation) const 546 { 547 if (!initialized()) 548 return { }; 549 550 IntSize size = m_decoder->frameSizeAtIndex(index, subsamplingLevel); 551 ImageOrientation orientation = m_decoder->orientationAtIndex(index); 552 553 return shouldRespectImageOrientation == RespectImageOrientation && orientation.usesWidthAsHeight() ? size.transposedSize() : size; 554 } 555 556 ImageOrientation ImageSource::orientationAtIndex(size_t index) const 557 { 558 return initialized() ? m_decoder->orientationAtIndex(index) : ImageOrientation(); 559 } 560 561 IntSize ImageSource::size() const 562 { 563 return frameSizeAtIndex(0, 0); 564 } 565 566 IntSize ImageSource::sizeRespectingOrientation() const 567 { 568 return frameSizeAtIndex(0, 0, RespectImageOrientation); 569 } 570 571 bool ImageSource::getHotSpot(IntPoint& hotSpot) const 572 { 573 return initialized() && m_decoder->hotSpot(hotSpot); 574 } 575 576 size_t ImageSource::bytesDecodedToDetermineProperties() const 577 { 578 return ImageDecoder::bytesDecodedToDetermineProperties(); 579 } 580 581 int ImageSource::repetitionCount() 582 { 583 return initialized() ? m_decoder->repetitionCount() : cAnimationLoopOnce; 584 } 585 586 size_t ImageSource::frameCount() const 587 { 588 return initialized() ? m_decoder->frameCount() : 0; 589 } 590 591 RetainPtr<CGImageRef> ImageSource::createFrameImageAtIndex(size_t index, SubsamplingLevel subsamplingLevel) 592 { 593 return initialized() ? m_decoder->createFrameImageAtIndex(index, subsamplingLevel) : nullptr; 594 } 595 380 596 bool ImageSource::frameIsCompleteAtIndex(size_t index) 381 597 { 382 ASSERT(frameCount()); 383 return CGImageSourceGetStatusAtIndex(m_decoder, index) == kCGImageStatusComplete; 598 return initialized() && m_decoder->frameIsCompleteAtIndex(index); 384 599 } 385 600 386 601 float ImageSource::frameDurationAtIndex(size_t index) 387 602 { 388 if (!initialized()) 389 return 0; 390 391 float duration = 0; 392 RetainPtr<CFDictionaryRef> properties = adoptCF(CGImageSourceCopyPropertiesAtIndex(m_decoder, index, imageSourceOptions().get())); 393 if (properties) { 394 CFDictionaryRef gifProperties = (CFDictionaryRef)CFDictionaryGetValue(properties.get(), kCGImagePropertyGIFDictionary); 395 if (gifProperties) { 396 if (CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(gifProperties, kCGImagePropertyGIFUnclampedDelayTime)) { 397 // Use the unclamped frame delay if it exists. 398 CFNumberGetValue(num, kCFNumberFloatType, &duration); 399 } else if (CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(gifProperties, kCGImagePropertyGIFDelayTime)) { 400 // Fall back to the clamped frame delay if the unclamped frame delay does not exist. 401 CFNumberGetValue(num, kCFNumberFloatType, &duration); 402 } 403 } 404 405 CFDictionaryRef pngProperties = (CFDictionaryRef)CFDictionaryGetValue(properties.get(), kCGImagePropertyPNGDictionary); 406 if (pngProperties) { 407 if (CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(pngProperties, WebCoreCGImagePropertyAPNGUnclampedDelayTime)) 408 CFNumberGetValue(num, kCFNumberFloatType, &duration); 409 else if (CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(pngProperties, WebCoreCGImagePropertyAPNGDelayTime)) 410 CFNumberGetValue(num, kCFNumberFloatType, &duration); 411 } 412 } 413 414 // Many annoying ads specify a 0 duration to make an image flash as quickly as possible. 415 // We follow Firefox's behavior and use a duration of 100 ms for any frames that specify 416 // a duration of <= 10 ms. See <rdar://problem/7689300> and <http://webkit.org/b/36082> 417 // for more information. 418 if (duration < 0.011f) 419 return 0.1f; 420 return duration; 603 return initialized() ? m_decoder->frameDurationAtIndex(index) : 0; 421 604 } 422 605 423 606 bool ImageSource::frameHasAlphaAtIndex(size_t index) 424 607 { 425 if (!m_decoder) 426 return false; // FIXME: why doesn't this return true? 427 428 if (!frameIsCompleteAtIndex(index)) 429 return true; 430 431 CFStringRef imageType = CGImageSourceGetType(m_decoder); 432 433 // Return false if there is no image type or the image type is JPEG, because 434 // JPEG does not support alpha transparency. 435 if (!imageType || CFEqual(imageType, CFSTR("public.jpeg"))) 436 return false; 437 438 // FIXME: Could return false for other non-transparent image formats. 439 // FIXME: Could maybe return false for a GIF Frame if we have enough info in the GIF properties dictionary 440 // to determine whether or not a transparent color was defined. 441 return true; 608 return !initialized() || m_decoder->frameHasAlphaAtIndex(index); 442 609 } 443 610 444 611 unsigned ImageSource::frameBytesAtIndex(size_t index, SubsamplingLevel subsamplingLevel) const 445 612 { 446 IntSize frameSize = frameSizeAtIndex(index, subsamplingLevel, ImageOrientationDescription(RespectImageOrientation)); 447 return frameSize.width() * frameSize.height() * 4; 613 IntSize frameSize = frameSizeAtIndex(index, subsamplingLevel); 614 return frameSize.area() * 4; 615 } 616 617 void ImageSource::dump(TextStream& ts) const 618 { 619 if (m_allowSubsampling) 620 ts.dumpProperty("allow-subsampling", m_allowSubsampling); 621 622 ImageOrientation orientation = orientationAtIndex(0); 623 if (orientation != OriginTopLeft) 624 ts.dumpProperty("orientation", orientation); 448 625 } 449 626 -
trunk/Source/WebCore/platform/image-decoders/ImageDecoder.cpp
r156795 r198782 96 96 } 97 97 98 ImageDecoder*ImageDecoder::create(const SharedBuffer& data, ImageSource::AlphaOption alphaOption, ImageSource::GammaAndColorProfileOption gammaAndColorProfileOption)98 std::unique_ptr<ImageDecoder> ImageDecoder::create(const SharedBuffer& data, ImageSource::AlphaOption alphaOption, ImageSource::GammaAndColorProfileOption gammaAndColorProfileOption) 99 99 { 100 100 static const unsigned lengthOfLongestSignature = 14; // To wit: "RIFF????WEBPVP" … … 102 102 unsigned length = copyFromSharedBuffer(contents, lengthOfLongestSignature, data, 0); 103 103 if (length < lengthOfLongestSignature) 104 return 0;104 return nullptr; 105 105 106 106 if (matchesGIFSignature(contents)) 107 return new GIFImageDecoder(alphaOption, gammaAndColorProfileOption);107 return std::unique_ptr<ImageDecoder> { std::make_unique<GIFImageDecoder>(alphaOption, gammaAndColorProfileOption) }; 108 108 109 109 if (matchesPNGSignature(contents)) 110 return new PNGImageDecoder(alphaOption, gammaAndColorProfileOption);110 return std::unique_ptr<ImageDecoder> { std::make_unique<PNGImageDecoder>(alphaOption, gammaAndColorProfileOption) }; 111 111 112 112 if (matchesICOSignature(contents) || matchesCURSignature(contents)) 113 return new ICOImageDecoder(alphaOption, gammaAndColorProfileOption);113 return std::unique_ptr<ImageDecoder> { std::make_unique<ICOImageDecoder>(alphaOption, gammaAndColorProfileOption) }; 114 114 115 115 if (matchesJPEGSignature(contents)) 116 return new JPEGImageDecoder(alphaOption, gammaAndColorProfileOption);116 return std::unique_ptr<ImageDecoder> { std::make_unique<JPEGImageDecoder>(alphaOption, gammaAndColorProfileOption) }; 117 117 118 118 #if USE(WEBP) 119 119 if (matchesWebPSignature(contents)) 120 return new WEBPImageDecoder(alphaOption, gammaAndColorProfileOption);120 return std::unique_ptr<ImageDecoder> { std::make_unique<WEBPImageDecoder>(alphaOption, gammaAndColorProfileOption) }; 121 121 #endif 122 122 123 123 if (matchesBMPSignature(contents)) 124 return new BMPImageDecoder(alphaOption, gammaAndColorProfileOption);125 126 return 0;124 return std::unique_ptr<ImageDecoder> { std::make_unique<BMPImageDecoder>(alphaOption, gammaAndColorProfileOption) }; 125 126 return nullptr; 127 127 } 128 128 -
trunk/Source/WebCore/platform/image-decoders/ImageDecoder.h
r198655 r198782 249 249 // we can't sniff a supported type from the provided data (possibly 250 250 // because there isn't enough data yet). 251 static ImageDecoder*create(const SharedBuffer& data, ImageSource::AlphaOption, ImageSource::GammaAndColorProfileOption);251 static std::unique_ptr<ImageDecoder> create(const SharedBuffer& data, ImageSource::AlphaOption, ImageSource::GammaAndColorProfileOption); 252 252 253 253 virtual String filenameExtension() const = 0; -
trunk/Source/WebCore/platform/mac/DragImageMac.mm
r197789 r198782 92 92 ImageOrientation orientation; 93 93 BitmapImage& bitmapImage = downcast<BitmapImage>(*image); 94 IntSize sizeRespectingOrientation = bitmapImage.sizeRespectingOrientation( description);94 IntSize sizeRespectingOrientation = bitmapImage.sizeRespectingOrientation(); 95 95 96 96 if (description.respectImageOrientation() == RespectImageOrientation)
Note: See TracChangeset
for help on using the changeset viewer.