IntSize ImageSource::size() const { IntSize result; CFDictionaryRef properties = CGImageSourceCopyPropertiesAtIndex(m_decoder, 0, imageSourceOptions()); if (properties) { int w = 0, h = 0; CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(properties, kCGImagePropertyPixelWidth); if (num) CFNumberGetValue(num, kCFNumberIntType, &w); num = (CFNumberRef)CFDictionaryGetValue(properties, kCGImagePropertyPixelHeight); if (num) CFNumberGetValue(num, kCFNumberIntType, &h); result = IntSize(w, h); CFRelease(properties); } return result; }
int ImageSource::repetitionCount() { int result = cAnimationLoopOnce; // No property means loop once. // A property with value 0 means loop forever. CFDictionaryRef properties = CGImageSourceCopyProperties(m_decoder, imageSourceOptions()); if (properties) { CFDictionaryRef gifProperties = (CFDictionaryRef)CFDictionaryGetValue(properties, kCGImagePropertyGIFDictionary); if (gifProperties) { CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(gifProperties, kCGImagePropertyGIFLoopCount); if (num) CFNumberGetValue(num, kCFNumberIntType, &result); } else result = cAnimationNone; // Turns out we're not a GIF after all, so we don't animate. CFRelease(properties); } return result; }
CGImageRef ImageSource::createFrameAtIndex(size_t index) { if (!initialized()) return 0; CGImageRef image = CGImageSourceCreateImageAtIndex(m_decoder, index, imageSourceOptions()); CFStringRef imageUTI = CGImageSourceGetType(m_decoder); static const CFStringRef xbmUTI = CFSTR("public.xbitmap-image"); if (!imageUTI || !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}; CGImageRef maskedImage = CGImageCreateWithMaskingColors(image, maskingColors); if (!maskedImage) return image; CGImageRelease(image); return maskedImage; }
NativeImagePtr ImageDecoder::createFrameImageAtIndex(size_t index, SubsamplingLevel subsamplingLevel, DecodingMode decodingMode) const { LOG(Images, "ImageDecoder %p createFrameImageAtIndex %lu", this, index); RetainPtr<CFDictionaryRef> options = imageSourceOptions(subsamplingLevel, decodingMode); RetainPtr<CGImageRef> image; if (decodingMode == DecodingMode::OnDemand) image = adoptCF(CGImageSourceCreateImageAtIndex(m_nativeDecoder.get(), index, options.get())); else image = adoptCF(CGImageSourceCreateThumbnailAtIndex(m_nativeDecoder.get(), index, options.get())); #if PLATFORM(IOS) // <rdar://problem/7371198> - CoreGraphics changed the default caching behaviour in iOS 4.0 to kCGImageCachingTransient // 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; }
IntSize ImageDecoder::frameSizeAtIndex(size_t index, SubsamplingLevel subsamplingLevel) const { RetainPtr<CFDictionaryRef> properties = adoptCF(CGImageSourceCopyPropertiesAtIndex(m_nativeDecoder.get(), index, imageSourceOptions(subsamplingLevel).get())); if (!properties) return { }; 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); return IntSize(width, height); }
ImageOrientation ImageDecoder::frameOrientationAtIndex(size_t index) const { RetainPtr<CFDictionaryRef> properties = adoptCF(CGImageSourceCopyPropertiesAtIndex(m_nativeDecoder.get(), index, imageSourceOptions().get())); if (!properties) return ImageOrientation(); return orientationFromProperties(properties.get()); }
RepetitionCount ImageDecoder::repetitionCount() const { RetainPtr<CFDictionaryRef> properties = adoptCF(CGImageSourceCopyProperties(m_nativeDecoder.get(), imageSourceOptions().get())); if (!properties) return RepetitionCountOnce; CFDictionaryRef gifProperties = (CFDictionaryRef)CFDictionaryGetValue(properties.get(), kCGImagePropertyGIFDictionary); if (gifProperties) { CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(gifProperties, kCGImagePropertyGIFLoopCount); // No property means loop once. if (!num) return RepetitionCountOnce; RepetitionCount loopCount; CFNumberGetValue(num, kCFNumberIntType, &loopCount); // A property with value 0 means loop forever. return loopCount ? loopCount : RepetitionCountInfinite; } CFDictionaryRef pngProperties = (CFDictionaryRef)CFDictionaryGetValue(properties.get(), kCGImagePropertyPNGDictionary); if (pngProperties) { CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(pngProperties, WebCoreCGImagePropertyAPNGLoopCount); if (!num) return RepetitionCountOnce; RepetitionCount loopCount; CFNumberGetValue(num, kCFNumberIntType, &loopCount); return loopCount ? loopCount : RepetitionCountInfinite; } // Turns out we're not an animated image after all, so we don't animate. return RepetitionCountNone; }
Optional<IntPoint> ImageDecoder::hotSpot() const { RetainPtr<CFDictionaryRef> properties = adoptCF(CGImageSourceCopyPropertiesAtIndex(m_nativeDecoder.get(), 0, imageSourceOptions().get())); if (!properties) return Nullopt; int x = -1, y = -1; CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(properties.get(), CFSTR("hotspotX")); if (!num || !CFNumberGetValue(num, kCFNumberIntType, &x)) return Nullopt; num = (CFNumberRef)CFDictionaryGetValue(properties.get(), CFSTR("hotspotY")); if (!num || !CFNumberGetValue(num, kCFNumberIntType, &y)) return Nullopt; if (x < 0 || y < 0) return Nullopt; return IntPoint(x, y); }
CGImageRef ImageSource::createFrameAtIndex(size_t index) { if (!initialized()) return 0; RetainPtr<CGImageRef> image = adoptCF(CGImageSourceCreateImageAtIndex(m_decoder, index, imageSourceOptions(SkipMetadata))); CFStringRef imageUTI = CGImageSourceGetType(m_decoder); static const CFStringRef xbmUTI = CFSTR("public.xbitmap-image"); if (!imageUTI || !CFEqual(imageUTI, xbmUTI)) return image.leakRef(); // 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)); if (!maskedImage) return image.leakRef(); return maskedImage.leakRef(); }
bool ImageDecoder::isSizeAvailable() const { // Ragnaros yells: TOO SOON! You have awakened me TOO SOON, Executus! if (CGImageSourceGetStatus(m_nativeDecoder.get()) < kCGImageStatusIncomplete) return false; RetainPtr<CFDictionaryRef> image0Properties = adoptCF(CGImageSourceCopyPropertiesAtIndex(m_nativeDecoder.get(), 0, imageSourceOptions().get())); if (!image0Properties) return false; return CFDictionaryContainsKey(image0Properties.get(), kCGImagePropertyPixelWidth) && CFDictionaryContainsKey(image0Properties.get(), kCGImagePropertyPixelHeight); }
float ImageSource::frameDurationAtIndex(size_t index) { if (!initialized()) return 0; float duration = 0; RetainPtr<CFDictionaryRef> properties(AdoptCF, CGImageSourceCopyPropertiesAtIndex(m_decoder, index, imageSourceOptions())); if (properties) { CFDictionaryRef typeProperties = (CFDictionaryRef)CFDictionaryGetValue(properties.get(), kCGImagePropertyGIFDictionary); if (typeProperties) { if (CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(typeProperties, WebCoreCGImagePropertyGIFUnclampedDelayTime)) { // Use the unclamped frame delay if it exists. CFNumberGetValue(num, kCFNumberFloatType, &duration); } else if (CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(typeProperties, kCGImagePropertyGIFDelayTime)) { // Fall back to the clamped frame delay if the unclamped frame delay does not exist. CFNumberGetValue(num, kCFNumberFloatType, &duration); } } } // Many annoying ads specify a 0 duration to make an image flash as quickly as possible. // We follow Firefox's behavior and use a duration of 100 ms for any frames that specify // a duration of <= 10 ms. See <rdar://problem/7689300> and <http://webkit.org/b/36082> // for more information. if (duration < 0.011f) return 0.100f; return duration; }
float ImageSource::frameDurationAtIndex(size_t index) { float duration = 0; CFDictionaryRef properties = CGImageSourceCopyPropertiesAtIndex(m_decoder, index, imageSourceOptions()); if (properties) { CFDictionaryRef typeProperties = (CFDictionaryRef)CFDictionaryGetValue(properties, kCGImagePropertyGIFDictionary); if (typeProperties) { CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(typeProperties, kCGImagePropertyGIFDelayTime); if (num) CFNumberGetValue(num, kCFNumberFloatType, &duration); } CFRelease(properties); } // Many annoying ads specify a 0 duration to make an image flash as quickly as possible. // We follow Firefox's behavior and use a duration of 100 ms for any frames that specify // a duration of <= 10 ms. See gfxImageFrame::GetTimeout in Gecko or Radar 4051389 for more. if (duration <= 0.010) return 0.100; return duration; }
CGImageRef ImageSource::createFrameAtIndex(size_t index) { return CGImageSourceCreateImageAtIndex(m_decoder, index, imageSourceOptions()); }
bool ImageSource::getHotSpot(IntPoint& hotSpot) const { RetainPtr<CFDictionaryRef> properties(AdoptCF, CGImageSourceCopyPropertiesAtIndex(m_decoder, 0, imageSourceOptions())); 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; }
IntSize ImageSource::frameSizeAtIndex(size_t index, ImageOrientationDescription description) const { RetainPtr<CFDictionaryRef> properties = adoptCF(CGImageSourceCopyPropertiesAtIndex(m_decoder, index, imageSourceOptions(SkipMetadata))); if (!properties) return IntSize(); int w = 0, h = 0; CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(properties.get(), kCGImagePropertyPixelWidth); if (num) CFNumberGetValue(num, kCFNumberIntType, &w); num = (CFNumberRef)CFDictionaryGetValue(properties.get(), kCGImagePropertyPixelHeight); if (num) CFNumberGetValue(num, kCFNumberIntType, &h); #if PLATFORM(IOS) if (!m_isProgressive) { CFDictionaryRef jfifProperties = static_cast<CFDictionaryRef>(CFDictionaryGetValue(properties.get(), kCGImagePropertyJFIFDictionary)); if (jfifProperties) { CFBooleanRef isProgCFBool = static_cast<CFBooleanRef>(CFDictionaryGetValue(jfifProperties, kCGImagePropertyJFIFIsProgressive)); if (isProgCFBool) m_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>) } } if ((m_baseSubsampling == 0) && !m_isProgressive) { IntSize subsampledSize(w, h); const int cMaximumImageSizeBeforeSubsampling = 5 * 1024 * 1024; while ((m_baseSubsampling < 3) && subsampledSize.width() * subsampledSize.height() > cMaximumImageSizeBeforeSubsampling) { // We know the size, but the actual image is very large and should be sub-sampled. // Increase the base subsampling and ask for the size again. If the image can be subsampled, the size will be // greatly reduced. 4x sub-sampling will make us support up to 320MP (5MP * 4^3) images, which should be plenty. // There's no callback from ImageIO when the size is available, so we do the check when we happen // to check the size and its non - zero. // Note: Some clients of this class don't call isSizeAvailable() so we can't rely on that. ++m_baseSubsampling; subsampledSize = frameSizeAtIndex(index, description.respectImageOrientation()); } w = subsampledSize.width(); h = subsampledSize.height(); } #endif if ((description.respectImageOrientation() == RespectImageOrientation) && orientationFromProperties(properties.get()).usesWidthAsHeight()) return IntSize(h, w); return IntSize(w, h); }
IntSize ImageSource::originalSize(RespectImageOrientationEnum shouldRespectOrientation) const { frameSizeAtIndex(0, shouldRespectOrientation); RetainPtr<CFDictionaryRef> properties = adoptCF(CGImageSourceCopyPropertiesAtIndex(m_decoder, 0, imageSourceOptions(SkipMetadata, -1))); if (!properties) return IntSize(); int width = 0; int height = 0; CFNumberRef number = (CFNumberRef)CFDictionaryGetValue(properties.get(), kCGImagePropertyPixelWidth); if (number) CFNumberGetValue(number, kCFNumberIntType, &width); number = static_cast<CFNumberRef>(CFDictionaryGetValue(properties.get(), kCGImagePropertyPixelHeight)); if (number) CFNumberGetValue(number, kCFNumberIntType, &height); if ((shouldRespectOrientation == RespectImageOrientation) && orientationFromProperties(properties.get()).usesWidthAsHeight()) return IntSize(height, width); return IntSize(width, height); }
void ImageSource::setData(NativeBytePtr data, bool allDataReceived) { if (!m_decoder) m_decoder = CGImageSourceCreateIncremental(imageSourceOptions()); CGImageSourceUpdateData(m_decoder, data, allDataReceived); }
bool ImageDecoder::frameAllowSubsamplingAtIndex(size_t) const { 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; }
IntSize ImageSource::frameSizeAtIndex(size_t index) const { IntSize result; RetainPtr<CFDictionaryRef> properties(AdoptCF, CGImageSourceCopyPropertiesAtIndex(m_decoder, index, imageSourceOptions())); if (properties) { int w = 0, h = 0; CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(properties.get(), kCGImagePropertyPixelWidth); if (num) CFNumberGetValue(num, kCFNumberIntType, &w); num = (CFNumberRef)CFDictionaryGetValue(properties.get(), kCGImagePropertyPixelHeight); if (num) CFNumberGetValue(num, kCFNumberIntType, &h); result = IntSize(w, h); } return result; }
IntSize ImageSource::frameSizeAtIndex(size_t index, SubsamplingLevel subsamplingLevel, ImageOrientationDescription description) const { 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); }
CGImageRef ImageSource::createFrameAtIndex(size_t index, float* scale) { UNUSED_PARAM(scale); if (!initialized()) return 0; #if !PLATFORM(IOS) UNUSED_PARAM(scale); RetainPtr<CGImageRef> image = adoptCF(CGImageSourceCreateImageAtIndex(m_decoder, index, imageSourceOptions(SkipMetadata))); #else // Subsampling can be 1, 2 or 3, which means quarter-, sixteenth- and sixty-fourth-size, respectively. // A zero or negative value means no subsampling. int subsampling = scale ? static_cast<int>(log2f(1.0f / std::max(0.1f, std::min(1.0f, *scale)))) : -1; RetainPtr<CGImageRef> image = adoptCF(CGImageSourceCreateImageAtIndex(m_decoder, index, imageSourceOptions(SkipMetadata, subsampling))); // <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 if (scale) { if (subsampling > 0) *scale = static_cast<float>(CGImageGetWidth(image.get())) / size(DoNotRespectImageOrientation).width(); else { ASSERT(static_cast<int>(CGImageGetWidth(image.get())) == size(DoNotRespectImageOrientation).width()); *scale = 1; } } #endif // !PLATFORM(IOS) CFStringRef imageUTI = CGImageSourceGetType(m_decoder); static const CFStringRef xbmUTI = CFSTR("public.xbitmap-image"); if (!imageUTI || !CFEqual(imageUTI, xbmUTI)) return image.leakRef(); // 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)); if (!maskedImage) return image.leakRef(); return maskedImage.leakRef(); }
int ImageSource::repetitionCount() { int result = cAnimationLoopOnce; // No property means loop once. if (!initialized()) return result; RetainPtr<CFDictionaryRef> properties(AdoptCF, CGImageSourceCopyProperties(m_decoder, imageSourceOptions())); if (properties) { CFDictionaryRef gifProperties = (CFDictionaryRef)CFDictionaryGetValue(properties.get(), kCGImagePropertyGIFDictionary); if (gifProperties) { CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(gifProperties, kCGImagePropertyGIFLoopCount); if (num) { // A property with value 0 means loop forever. CFNumberGetValue(num, kCFNumberIntType, &result); if (!result) result = cAnimationLoopInfinite; } } else result = cAnimationNone; // Turns out we're not a GIF after all, so we don't animate. } return result; }
ImageOrientation ImageSource::orientationAtIndex(size_t index) const { RetainPtr<CFDictionaryRef> properties = adoptCF(CGImageSourceCopyPropertiesAtIndex(m_decoder, index, imageSourceOptions().get())); if (!properties) return DefaultImageOrientation; return orientationFromProperties(properties.get()); }
bool ImageSource::isSizeAvailable() { bool result = false; CGImageSourceStatus imageSourceStatus = CGImageSourceGetStatus(m_decoder); // Ragnaros yells: TOO SOON! You have awakened me TOO SOON, Executus! if (imageSourceStatus >= kCGImageStatusIncomplete) { RetainPtr<CFDictionaryRef> image0Properties(AdoptCF, CGImageSourceCopyPropertiesAtIndex(m_decoder, 0, imageSourceOptions())); if (image0Properties) { CFNumberRef widthNumber = (CFNumberRef)CFDictionaryGetValue(image0Properties.get(), kCGImagePropertyPixelWidth); CFNumberRef heightNumber = (CFNumberRef)CFDictionaryGetValue(image0Properties.get(), kCGImagePropertyPixelHeight); result = widthNumber && heightNumber; } } return result; }
CGImageRef ImageSource::createFrameAtIndex(size_t index, SubsamplingLevel subsamplingLevel) { if (!initialized()) return nullptr; RetainPtr<CGImageRef> image = adoptCF(CGImageSourceCreateImageAtIndex(m_decoder, 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_decoder); static const CFStringRef xbmUTI = CFSTR("public.xbitmap-image"); if (!imageUTI) return image.leakRef(); #if PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000 if (CFEqual(imageUTI, kUTTypeGIF)) { CGImageSetCachingFlags(image.get(), kCGImageCachingTransient); return image.leakRef(); } #endif if (!CFEqual(imageUTI, xbmUTI)) return image.leakRef(); // 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)); if (!maskedImage) return image.leakRef(); return maskedImage.leakRef(); }
float ImageSource::frameDurationAtIndex(size_t index) { if (!initialized()) return 0; float duration = 0; RetainPtr<CFDictionaryRef> properties(AdoptCF, CGImageSourceCopyPropertiesAtIndex(m_decoder, index, imageSourceOptions())); if (properties) { CFDictionaryRef typeProperties = (CFDictionaryRef)CFDictionaryGetValue(properties.get(), kCGImagePropertyGIFDictionary); if (typeProperties) { CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(typeProperties, kCGImagePropertyGIFDelayTime); if (num) CFNumberGetValue(num, kCFNumberFloatType, &duration); } } // Many annoying ads specify a 0 duration to make an image flash as quickly as possible. // We follow WinIE's behavior and use a duration of 100 ms for any frames that specify // a duration of <= 50 ms. See <http://bugs.webkit.org/show_bug.cgi?id=14413> or Radar 4051389 for more. if (duration < 0.051f) return 0.100f; return duration; }
IntSize ImageSource::frameSizeAtIndex(size_t index, RespectImageOrientationEnum shouldRespectOrientation) const { RetainPtr<CFDictionaryRef> properties = adoptCF(CGImageSourceCopyPropertiesAtIndex(m_decoder, index, imageSourceOptions(SkipMetadata))); if (!properties) return IntSize(); int w = 0, h = 0; CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(properties.get(), kCGImagePropertyPixelWidth); if (num) CFNumberGetValue(num, kCFNumberIntType, &w); num = (CFNumberRef)CFDictionaryGetValue(properties.get(), kCGImagePropertyPixelHeight); if (num) CFNumberGetValue(num, kCFNumberIntType, &h); if ((shouldRespectOrientation == RespectImageOrientation) && orientationFromProperties(properties.get()).usesWidthAsHeight()) return IntSize(h, w); return IntSize(w, h); }