Move the CG ImageDecoder class from ImageSourceCG.cpp to ImageDecoderCG.h and .cpp
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 30 Mar 2016 19:10:18 +0000 (19:10 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 30 Mar 2016 19:10:18 +0000 (19:10 +0000)
https://bugs.webkit.org/show_bug.cgi?id=155980

Patch by Said Abou-Hallawa <sabouhallawa@apple,com> on 2016-03-30
Reviewed by Simon Fraser.

After this step, ImageSource.cpp and ImageSourceCG.cpp look very similar
so they can be merged in one file. All the redundant code in these two files
can be removed.

* PlatformAppleWin.cmake:
* PlatformMac.cmake:
* WebCore.xcodeproj/project.pbxproj:
* platform/graphics/cg/ImageDecoderCG.cpp: Copied from Source/WebCore/platform/graphics/cg/ImageSourceCG.cpp.
(WebCore::createImageSourceOptions):
(WebCore::imageSourceOptions):
(WebCore::orientationFromProperties):
(WebCore::sharedBufferGetBytesAtPosition):
(WebCore::sharedBufferRelease):
(WebCore::ImageDecoder::ImageDecoder):
(WebCore::ImageDecoder::subsamplingLevelForScale):
(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):
* platform/graphics/cg/ImageDecoderCG.h: Added.
(WebCore::ImageDecoder::create):
* platform/graphics/cg/ImageSourceCG.cpp:
(WebCore::ImageDecoder::create): Deleted.
(WebCore::createImageSourceOptions): Deleted.
(WebCore::imageSourceOptions): Deleted.
(WebCore::orientationFromProperties): Deleted.
(WebCore::sharedBufferGetBytesAtPosition): Deleted.
(WebCore::sharedBufferRelease): Deleted.
(WebCore::ImageDecoder::ImageDecoder): Deleted.
(WebCore::ImageDecoder::subsamplingLevelForScale): Deleted.
(WebCore::ImageDecoder::bytesDecodedToDetermineProperties): Deleted.
(WebCore::ImageDecoder::filenameExtension): Deleted.
(WebCore::ImageDecoder::isSizeAvailable): Deleted.
(WebCore::ImageDecoder::size): Deleted.
(WebCore::ImageDecoder::frameCount): Deleted.
(WebCore::ImageDecoder::repetitionCount): Deleted.
(WebCore::ImageDecoder::hotSpot): Deleted.
(WebCore::ImageDecoder::frameSizeAtIndex): Deleted.
(WebCore::ImageDecoder::frameIsCompleteAtIndex): Deleted.
(WebCore::ImageDecoder::orientationAtIndex): Deleted.
(WebCore::ImageDecoder::frameDurationAtIndex): Deleted.
(WebCore::ImageDecoder::allowSubsamplingOfFrameAtIndex): Deleted.
(WebCore::ImageDecoder::frameHasAlphaAtIndex): Deleted.
(WebCore::ImageDecoder::frameBytesAtIndex): Deleted.
(WebCore::ImageDecoder::createFrameImageAtIndex): Deleted.
(WebCore::ImageDecoder::setData): Deleted.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@198849 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebCore/ChangeLog
Source/WebCore/PlatformAppleWin.cmake
Source/WebCore/PlatformMac.cmake
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/platform/graphics/cg/ImageDecoderCG.cpp [new file with mode: 0644]
Source/WebCore/platform/graphics/cg/ImageDecoderCG.h [new file with mode: 0644]
Source/WebCore/platform/graphics/cg/ImageSourceCG.cpp

index 760fb7b..0411f0d 100644 (file)
@@ -1,3 +1,69 @@
+2016-03-30  Said Abou-Hallawa  <sabouhallawa@apple,com>
+
+        Move the CG ImageDecoder class from ImageSourceCG.cpp to ImageDecoderCG.h and .cpp
+        https://bugs.webkit.org/show_bug.cgi?id=155980
+
+        Reviewed by Simon Fraser.
+
+        After this step, ImageSource.cpp and ImageSourceCG.cpp look very similar
+        so they can be merged in one file. All the redundant code in these two files
+        can be removed.
+
+        * PlatformAppleWin.cmake:
+        * PlatformMac.cmake:
+        * WebCore.xcodeproj/project.pbxproj:
+        * platform/graphics/cg/ImageDecoderCG.cpp: Copied from Source/WebCore/platform/graphics/cg/ImageSourceCG.cpp.
+        (WebCore::createImageSourceOptions):
+        (WebCore::imageSourceOptions):
+        (WebCore::orientationFromProperties):
+        (WebCore::sharedBufferGetBytesAtPosition):
+        (WebCore::sharedBufferRelease):
+        (WebCore::ImageDecoder::ImageDecoder):
+        (WebCore::ImageDecoder::subsamplingLevelForScale):
+        (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):
+        * platform/graphics/cg/ImageDecoderCG.h: Added.
+        (WebCore::ImageDecoder::create):
+        * platform/graphics/cg/ImageSourceCG.cpp:
+        (WebCore::ImageDecoder::create): Deleted.
+        (WebCore::createImageSourceOptions): Deleted.
+        (WebCore::imageSourceOptions): Deleted.
+        (WebCore::orientationFromProperties): Deleted.
+        (WebCore::sharedBufferGetBytesAtPosition): Deleted.
+        (WebCore::sharedBufferRelease): Deleted.
+        (WebCore::ImageDecoder::ImageDecoder): Deleted.
+        (WebCore::ImageDecoder::subsamplingLevelForScale): Deleted.
+        (WebCore::ImageDecoder::bytesDecodedToDetermineProperties): Deleted.
+        (WebCore::ImageDecoder::filenameExtension): Deleted.
+        (WebCore::ImageDecoder::isSizeAvailable): Deleted.
+        (WebCore::ImageDecoder::size): Deleted.
+        (WebCore::ImageDecoder::frameCount): Deleted.
+        (WebCore::ImageDecoder::repetitionCount): Deleted.
+        (WebCore::ImageDecoder::hotSpot): Deleted.
+        (WebCore::ImageDecoder::frameSizeAtIndex): Deleted.
+        (WebCore::ImageDecoder::frameIsCompleteAtIndex): Deleted.
+        (WebCore::ImageDecoder::orientationAtIndex): Deleted.
+        (WebCore::ImageDecoder::frameDurationAtIndex): Deleted.
+        (WebCore::ImageDecoder::allowSubsamplingOfFrameAtIndex): Deleted.
+        (WebCore::ImageDecoder::frameHasAlphaAtIndex): Deleted.
+        (WebCore::ImageDecoder::frameBytesAtIndex): Deleted.
+        (WebCore::ImageDecoder::createFrameImageAtIndex): Deleted.
+        (WebCore::ImageDecoder::setData): Deleted.
+
 2016-03-30  Per Arne Vollan  <peavo@outlook.com>
 
         [WinCairo][MediaFoundation] Video size is not always set.
index e5209cb..c672cc7 100644 (file)
@@ -71,6 +71,7 @@ list(APPEND WebCore_SOURCES
     platform/graphics/cg/ImageBufferCG.cpp
     platform/graphics/cg/ImageBufferDataCG.cpp
     platform/graphics/cg/ImageCG.cpp
+    platform/graphics/cg/ImageDecoderCG.cpp
     platform/graphics/cg/ImageSourceCG.cpp
     platform/graphics/cg/ImageSourceCGWin.cpp
     platform/graphics/cg/IntPointCG.cpp
index 4e66a74..c8092c2 100644 (file)
@@ -405,6 +405,7 @@ list(APPEND WebCore_SOURCES
     platform/graphics/cg/ImageBufferCG.cpp
     platform/graphics/cg/ImageBufferDataCG.cpp
     platform/graphics/cg/ImageCG.cpp
+    platform/graphics/cg/ImageDecoderCG.cpp
     platform/graphics/cg/ImageSourceCG.cpp
     platform/graphics/cg/ImageSourceCGMac.mm
     platform/graphics/cg/IntPointCG.cpp
index 85d0115..381b60e 100644 (file)
                53EF766C16531994004CBE49 /* SettingsMacros.h in Copy Generated Headers */ = {isa = PBXBuildFile; fileRef = 53EF766A16530A61004CBE49 /* SettingsMacros.h */; };
                550A0BC9085F6039007353D6 /* QualifiedName.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 550A0BC7085F6039007353D6 /* QualifiedName.cpp */; };
                550A0BCA085F6039007353D6 /* QualifiedName.h in Headers */ = {isa = PBXBuildFile; fileRef = 550A0BC8085F6039007353D6 /* QualifiedName.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               555B87EC1CAAF0AB00349425 /* ImageDecoderCG.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 555B87EA1CAAF0AB00349425 /* ImageDecoderCG.cpp */; };
+               555B87ED1CAAF0AB00349425 /* ImageDecoderCG.h in Headers */ = {isa = PBXBuildFile; fileRef = 555B87EB1CAAF0AB00349425 /* ImageDecoderCG.h */; };
                572A7F211C6E5719009C6149 /* SimulatedClick.h in Headers */ = {isa = PBXBuildFile; fileRef = 572A7F201C6E5719009C6149 /* SimulatedClick.h */; };
                572A7F231C6E5A66009C6149 /* SimulatedClick.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 572A7F221C6E5A66009C6149 /* SimulatedClick.cpp */; };
                580371611A66F00A00BAF519 /* ClipRect.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5803715F1A66F00A00BAF519 /* ClipRect.cpp */; };
                53EF766A16530A61004CBE49 /* SettingsMacros.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SettingsMacros.h; sourceTree = "<group>"; };
                550A0BC7085F6039007353D6 /* QualifiedName.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = QualifiedName.cpp; sourceTree = "<group>"; tabWidth = 8; usesTabs = 0; };
                550A0BC8085F6039007353D6 /* QualifiedName.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = QualifiedName.h; sourceTree = "<group>"; tabWidth = 8; usesTabs = 0; };
+               555B87EA1CAAF0AB00349425 /* ImageDecoderCG.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ImageDecoderCG.cpp; sourceTree = "<group>"; };
+               555B87EB1CAAF0AB00349425 /* ImageDecoderCG.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ImageDecoderCG.h; sourceTree = "<group>"; };
                55D408F71A7C631800C78450 /* SVGImageClients.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SVGImageClients.h; sourceTree = "<group>"; };
                572A7F201C6E5719009C6149 /* SimulatedClick.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SimulatedClick.h; sourceTree = "<group>"; };
                572A7F221C6E5A66009C6149 /* SimulatedClick.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SimulatedClick.cpp; sourceTree = "<group>"; };
                                2292B27B1356669400CF11EF /* ImageBufferDataCG.cpp */,
                                22BD9F80135364FE009BD102 /* ImageBufferDataCG.h */,
                                B27535300B053814002CE64F /* ImageCG.cpp */,
+                               555B87EA1CAAF0AB00349425 /* ImageDecoderCG.cpp */,
+                               555B87EB1CAAF0AB00349425 /* ImageDecoderCG.h */,
                                B27535310B053814002CE64F /* ImageSourceCG.cpp */,
                                4B3480920EEF50D400AC1B41 /* ImageSourceCG.h */,
                                4B3480910EEF50D400AC1B41 /* ImageSourceCGMac.mm */,
                                5185FC8D1BB4C4E80012898F /* IDBFactory.h in Headers */,
                                69A6CBAD1C6BE42C00B836E9 /* AccessibilitySVGElement.h in Headers */,
                                5185FC8F1BB4C4E80012898F /* IDBGetResult.h in Headers */,
+                               555B87ED1CAAF0AB00349425 /* ImageDecoderCG.h in Headers */,
                                5185FC911BB4C4E80012898F /* IDBIndex.h in Headers */,
                                51F798F01BE880E7008AE491 /* IDBIndexInfo.h in Headers */,
                                5185FC951BB4C4E80012898F /* IDBKey.h in Headers */,
                                99CC0B5918BE984A006CEBCC /* ReplaySession.cpp in Sources */,
                                99CC0B5B18BE984A006CEBCC /* ReplaySessionSegment.cpp in Sources */,
                                F55B3DCF1251F12D003EF269 /* ResetInputType.cpp in Sources */,
+                               555B87EC1CAAF0AB00349425 /* ImageDecoderCG.cpp in Sources */,
                                934F713E0D5A6F2800018D69 /* ResourceErrorBase.cpp in Sources */,
                                7EE6846B12D26E3800E79415 /* ResourceErrorCF.cpp in Sources */,
                                514C76500CE9234E007EF3CD /* ResourceErrorMac.mm in Sources */,
diff --git a/Source/WebCore/platform/graphics/cg/ImageDecoderCG.cpp b/Source/WebCore/platform/graphics/cg/ImageDecoderCG.cpp
new file mode 100644 (file)
index 0000000..7fbd341
--- /dev/null
@@ -0,0 +1,410 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ImageDecoderCG.h"
+
+#if USE(CG)
+
+#include "ImageOrientation.h"
+#include "IntPoint.h"
+#include "IntSize.h"
+#include "SharedBuffer.h"
+#include <wtf/NeverDestroyed.h>
+
+#if !PLATFORM(IOS)
+#include <ApplicationServices/ApplicationServices.h>
+#else
+#include "CoreGraphicsSPI.h"
+#include <ImageIO/ImageIO.h>
+#endif
+
+#if USE(APPLE_INTERNAL_SDK)
+#import <ImageIO/CGImageSourcePrivate.h>
+#else
+const CFStringRef kCGImageSourceSubsampleFactor = CFSTR("kCGImageSourceSubsampleFactor");
+#endif
+
+namespace WebCore {
+
+const CFStringRef WebCoreCGImagePropertyAPNGUnclampedDelayTime = CFSTR("UnclampedDelayTime");
+const CFStringRef WebCoreCGImagePropertyAPNGDelayTime = CFSTR("DelayTime");
+const CFStringRef WebCoreCGImagePropertyAPNGLoopCount = CFSTR("LoopCount");
+
+const CFStringRef kCGImageSourceShouldPreferRGB32 = CFSTR("kCGImageSourceShouldPreferRGB32");
+const CFStringRef kCGImageSourceSkipMetadata = CFSTR("kCGImageSourceSkipMetadata");
+
+static RetainPtr<CFDictionaryRef> createImageSourceOptions(SubsamplingLevel subsamplingLevel)
+{
+    if (!subsamplingLevel) {
+        const unsigned numOptions = 3;
+        const void* keys[numOptions] = { kCGImageSourceShouldCache, kCGImageSourceShouldPreferRGB32, kCGImageSourceSkipMetadata };
+        const void* values[numOptions] = { kCFBooleanTrue, kCFBooleanTrue, kCFBooleanTrue };
+        return CFDictionaryCreate(nullptr, keys, values, numOptions, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+    }
+    
+    short constrainedSubsamplingLevel = std::min<short>(3, std::max<short>(0, subsamplingLevel));
+    int subsampleInt = 1 << constrainedSubsamplingLevel; // [0..3] => [1, 2, 4, 8]
+    
+    RetainPtr<CFNumberRef> subsampleNumber = adoptCF(CFNumberCreate(nullptr,  kCFNumberIntType,  &subsampleInt));
+    const CFIndex numOptions = 4;
+    const void* keys[numOptions] = { kCGImageSourceShouldCache, kCGImageSourceShouldPreferRGB32, kCGImageSourceSkipMetadata, kCGImageSourceSubsampleFactor };
+    const void* values[numOptions] = { kCFBooleanTrue, kCFBooleanTrue, kCFBooleanTrue, subsampleNumber.get() };
+    return adoptCF(CFDictionaryCreate(nullptr, keys, values, numOptions, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
+}
+
+static RetainPtr<CFDictionaryRef> imageSourceOptions(SubsamplingLevel subsamplingLevel = 0)
+{
+    if (subsamplingLevel)
+        return createImageSourceOptions(subsamplingLevel);
+    
+    static NeverDestroyed<RetainPtr<CFDictionaryRef>> options = createImageSourceOptions(0);
+    return options;
+}
+
+static ImageOrientation orientationFromProperties(CFDictionaryRef imageProperties)
+{
+    ASSERT(imageProperties);
+    CFNumberRef orientationProperty = (CFNumberRef)CFDictionaryGetValue(imageProperties, kCGImagePropertyOrientation);
+    if (!orientationProperty)
+        return ImageOrientation();
+    
+    int exifValue;
+    CFNumberGetValue(orientationProperty, kCFNumberIntType, &exifValue);
+    return ImageOrientation::fromEXIFValue(exifValue);
+}
+
+#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;
+    
+    const char* source = sharedBuffer->data() + position;
+    size_t amount = std::min<size_t>(count, sourceSize - position);
+    memcpy(buffer, source, amount);
+    return amount;
+}
+
+void sharedBufferRelease(void* info)
+{
+    SharedBuffer* sharedBuffer = static_cast<SharedBuffer*>(info);
+    sharedBuffer->deref();
+}
+#endif
+
+ImageDecoder::ImageDecoder()
+{
+    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);
+}
+
+size_t ImageDecoder::bytesDecodedToDetermineProperties()
+{
+    // 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 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);
+}
+
+IntSize ImageDecoder::size() const
+{
+    if (m_size.isEmpty())
+        m_size = frameSizeAtIndex(0, 0);
+    return m_size;
+}
+
+size_t ImageDecoder::frameCount() const
+{
+    return CGImageSourceGetCount(m_nativeDecoder.get());
+}
+
+int ImageDecoder::repetitionCount() const
+{
+    RetainPtr<CFDictionaryRef> properties = adoptCF(CGImageSourceCopyProperties(m_nativeDecoder.get(), imageSourceOptions().get()));
+    if (!properties)
+        return cAnimationLoopOnce;
+    
+    CFDictionaryRef gifProperties = (CFDictionaryRef)CFDictionaryGetValue(properties.get(), kCGImagePropertyGIFDictionary);
+    if (gifProperties) {
+        CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(gifProperties, kCGImagePropertyGIFLoopCount);
+        
+        // No property means loop once.
+        if (!num)
+            return cAnimationLoopOnce;
+        
+        int loopCount;
+        CFNumberGetValue(num, kCFNumberIntType, &loopCount);
+        
+        // A property with value 0 means loop forever.
+        return loopCount ? loopCount : cAnimationLoopInfinite;
+    }
+    
+    CFDictionaryRef pngProperties = (CFDictionaryRef)CFDictionaryGetValue(properties.get(), kCGImagePropertyPNGDictionary);
+    if (pngProperties) {
+        CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(pngProperties, WebCoreCGImagePropertyAPNGLoopCount);
+        if (!num)
+            return cAnimationLoopOnce;
+        
+        int loopCount;
+        CFNumberGetValue(num, kCFNumberIntType, &loopCount);
+        return loopCount ? loopCount : cAnimationLoopInfinite;
+    }
+    
+    // Turns out we're not an animated image after all, so we don't animate.
+    return cAnimationNone;
+}
+
+bool ImageDecoder::hotSpot(IntPoint& hotSpot) const
+{
+    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;
+}
+
+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);
+}
+
+bool ImageDecoder::frameIsCompleteAtIndex(size_t index) const
+{
+    ASSERT(frameCount());
+    return CGImageSourceGetStatusAtIndex(m_nativeDecoder.get(), index) == kCGImageStatusComplete;
+}
+
+ImageOrientation ImageDecoder::orientationAtIndex(size_t index) const
+{
+    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_nativeDecoder.get(), index, imageSourceOptions().get()));
+    if (properties) {
+        CFDictionaryRef gifProperties = (CFDictionaryRef)CFDictionaryGetValue(properties.get(), kCGImagePropertyGIFDictionary);
+        if (gifProperties) {
+            if (CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(gifProperties, kCGImagePropertyGIFUnclampedDelayTime)) {
+                // Use the unclamped frame delay if it exists.
+                CFNumberGetValue(num, kCFNumberFloatType, &duration);
+            } else if (CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(gifProperties, kCGImagePropertyGIFDelayTime)) {
+                // Fall back to the clamped frame delay if the unclamped frame delay does not exist.
+                CFNumberGetValue(num, kCFNumberFloatType, &duration);
+            }
+        }
+        
+        CFDictionaryRef pngProperties = (CFDictionaryRef)CFDictionaryGetValue(properties.get(), kCGImagePropertyPNGDictionary);
+        if (pngProperties) {
+            if (CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(pngProperties, WebCoreCGImagePropertyAPNGUnclampedDelayTime))
+                CFNumberGetValue(num, kCFNumberFloatType, &duration);
+            else if (CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(pngProperties, WebCoreCGImagePropertyAPNGDelayTime))
+                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.1f;
+    return duration;
+}
+
+bool ImageDecoder::allowSubsamplingOfFrameAtIndex(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;
+}
+
+bool ImageDecoder::frameHasAlphaAtIndex(size_t index) const
+{
+    if (!frameIsCompleteAtIndex(index))
+        return true;
+    
+    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.
+    if (!imageType || CFEqual(imageType, CFSTR("public.jpeg")))
+        return false;
+    
+    // FIXME: Could return false for other non-transparent image formats.
+    // FIXME: Could maybe return false for a GIF Frame if we have enough info in the GIF properties dictionary
+    // to determine whether or not a transparent color was defined.
+    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);
+#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
+}
+
+}
+
+#endif // USE(CG)
diff --git a/Source/WebCore/platform/graphics/cg/ImageDecoderCG.h b/Source/WebCore/platform/graphics/cg/ImageDecoderCG.h
new file mode 100644 (file)
index 0000000..8c6a9e2
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ImageDecoderCG_h
+#define ImageDecoderCG_h
+
+#include "ImageSourceCG.h"
+#include "IntSize.h"
+
+namespace WebCore {
+
+class ImageDecoder {
+public:
+    ImageDecoder();
+    
+    static std::unique_ptr<ImageDecoder> create()
+    {
+        return std::make_unique<ImageDecoder>();
+    }
+    
+    static size_t bytesDecodedToDetermineProperties();
+    static SubsamplingLevel subsamplingLevelForScale(float scale, SubsamplingLevel maximumSubsamplingLevel);
+    
+    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;
+    
+    IntSize frameSizeAtIndex(size_t, SubsamplingLevel) const;
+    bool frameIsCompleteAtIndex(size_t) const;
+    ImageOrientation orientationAtIndex(size_t) const;
+    
+    float frameDurationAtIndex(size_t) const;
+    bool frameHasAlphaAtIndex(size_t) const;
+    bool allowSubsamplingOfFrameAtIndex(size_t) const;
+    unsigned frameBytesAtIndex(size_t, SubsamplingLevel = 0) const;
+    
+    NativeImagePtr createFrameImageAtIndex(size_t, SubsamplingLevel) const;
+    
+    void setData(CFDataRef, bool allDataReceived);
+    void setData(SharedBuffer*, bool allDataReceived);
+    
+protected:
+    mutable IntSize m_size;
+    RetainPtr<CGImageSourceRef> m_nativeDecoder;
+};
+
+}
+
+#endif // ImageDecoderCG_h
index 9fb1a93..49d4e15 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2004, 2005, 2006, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2004, 2005, 2006, 2008, 2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 #if USE(CG)
 #include "ImageSourceCG.h"
 
-#include "CoreGraphicsSPI.h"
+#include "ImageDecoderCG.h"
 #include "ImageOrientation.h"
-#include "IntPoint.h"
-#include "IntSize.h"
-#include "MIMETypeRegistry.h"
 #include "SharedBuffer.h"
-#include <wtf/NeverDestroyed.h>
-
-#if !PLATFORM(IOS)
-#include <ApplicationServices/ApplicationServices.h>
-#else
-#include <ImageIO/ImageIO.h>
-#include <wtf/RetainPtr.h>
-#endif
-
-#if USE(APPLE_INTERNAL_SDK)
-#import <ImageIO/CGImageSourcePrivate.h>
-#else
-const CFStringRef kCGImageSourceSubsampleFactor = CFSTR("kCGImageSourceSubsampleFactor");
-#endif
 
 namespace WebCore {
-    
-class ImageDecoder {
-public:
-    ImageDecoder();
-    
-    static std::unique_ptr<ImageDecoder> create()
-    {
-        return std::make_unique<ImageDecoder>();
-    }
-
-    static size_t bytesDecodedToDetermineProperties();
-    static SubsamplingLevel subsamplingLevelForScale(float scale, SubsamplingLevel maximumSubsamplingLevel);
-
-    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;
-
-    IntSize frameSizeAtIndex(size_t, SubsamplingLevel) const;
-    bool frameIsCompleteAtIndex(size_t) const;
-    ImageOrientation orientationAtIndex(size_t) const;
-
-    float frameDurationAtIndex(size_t) const;
-    bool frameHasAlphaAtIndex(size_t) const;
-    bool allowSubsamplingOfFrameAtIndex(size_t) const;
-    unsigned frameBytesAtIndex(size_t, SubsamplingLevel = 0) const;
-
-    NativeImagePtr createFrameImageAtIndex(size_t, SubsamplingLevel) const;
-
-    void setData(CFDataRef, bool allDataReceived);
-    void setData(SharedBuffer*, bool allDataReceived);
-
-protected:
-    mutable IntSize m_size;
-    RetainPtr<CGImageSourceRef> m_nativeDecoder;
-};
-
-const CFStringRef WebCoreCGImagePropertyAPNGUnclampedDelayTime = CFSTR("UnclampedDelayTime");
-const CFStringRef WebCoreCGImagePropertyAPNGDelayTime = CFSTR("DelayTime");
-const CFStringRef WebCoreCGImagePropertyAPNGLoopCount = CFSTR("LoopCount");
-
-const CFStringRef kCGImageSourceShouldPreferRGB32 = CFSTR("kCGImageSourceShouldPreferRGB32");
-const CFStringRef kCGImageSourceSkipMetadata = CFSTR("kCGImageSourceSkipMetadata");
-
-static RetainPtr<CFDictionaryRef> createImageSourceOptions(SubsamplingLevel subsamplingLevel)
-{
-    if (!subsamplingLevel) {
-        const unsigned numOptions = 3;
-        const void* keys[numOptions] = { kCGImageSourceShouldCache, kCGImageSourceShouldPreferRGB32, kCGImageSourceSkipMetadata };
-        const void* values[numOptions] = { kCFBooleanTrue, kCFBooleanTrue, kCFBooleanTrue };
-        return CFDictionaryCreate(nullptr, keys, values, numOptions, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
-    }
-
-    short constrainedSubsamplingLevel = std::min<short>(3, std::max<short>(0, subsamplingLevel));
-    int subsampleInt = 1 << constrainedSubsamplingLevel; // [0..3] => [1, 2, 4, 8]
-
-    RetainPtr<CFNumberRef> subsampleNumber = adoptCF(CFNumberCreate(nullptr,  kCFNumberIntType,  &subsampleInt));
-    const CFIndex numOptions = 4;
-    const void* keys[numOptions] = { kCGImageSourceShouldCache, kCGImageSourceShouldPreferRGB32, kCGImageSourceSkipMetadata, kCGImageSourceSubsampleFactor };
-    const void* values[numOptions] = { kCFBooleanTrue, kCFBooleanTrue, kCFBooleanTrue, subsampleNumber.get() };
-    return adoptCF(CFDictionaryCreate(nullptr, keys, values, numOptions, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
-}
-
-static RetainPtr<CFDictionaryRef> imageSourceOptions(SubsamplingLevel subsamplingLevel = 0)
-{
-    if (subsamplingLevel)
-        return createImageSourceOptions(subsamplingLevel);
-
-    static NeverDestroyed<RetainPtr<CFDictionaryRef>> options = createImageSourceOptions(0);
-    return options;
-}
-
-static ImageOrientation orientationFromProperties(CFDictionaryRef imageProperties)
-{
-    ASSERT(imageProperties);
-    CFNumberRef orientationProperty = (CFNumberRef)CFDictionaryGetValue(imageProperties, kCGImagePropertyOrientation);
-    if (!orientationProperty)
-        return ImageOrientation();
-
-    int exifValue;
-    CFNumberGetValue(orientationProperty, kCFNumberIntType, &exifValue);
-    return ImageOrientation::fromEXIFValue(exifValue);
-}
-
-#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;
-
-    const char* source = sharedBuffer->data() + position;
-    size_t amount = std::min<size_t>(count, sourceSize - position);
-    memcpy(buffer, source, amount);
-    return amount;
-}
-
-void sharedBufferRelease(void* info)
-{
-    SharedBuffer* sharedBuffer = static_cast<SharedBuffer*>(info);
-    sharedBuffer->deref();
-}
-#endif
-    
-ImageDecoder::ImageDecoder()
-{
-    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);
-}
-
-size_t ImageDecoder::bytesDecodedToDetermineProperties()
-{
-    // 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 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);
-}
-
-IntSize ImageDecoder::size() const
-{
-    if (m_size.isEmpty())
-        m_size = frameSizeAtIndex(0, 0);
-    return m_size;
-}
-
-size_t ImageDecoder::frameCount() const
-{
-    return CGImageSourceGetCount(m_nativeDecoder.get());
-}
-
-int ImageDecoder::repetitionCount() const
-{
-    RetainPtr<CFDictionaryRef> properties = adoptCF(CGImageSourceCopyProperties(m_nativeDecoder.get(), imageSourceOptions().get()));
-    if (!properties)
-        return cAnimationLoopOnce;
-
-    CFDictionaryRef gifProperties = (CFDictionaryRef)CFDictionaryGetValue(properties.get(), kCGImagePropertyGIFDictionary);
-    if (gifProperties) {
-        CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(gifProperties, kCGImagePropertyGIFLoopCount);
-
-        // No property means loop once.
-        if (!num)
-            return cAnimationLoopOnce;
-
-        int loopCount;
-        CFNumberGetValue(num, kCFNumberIntType, &loopCount);
-
-        // A property with value 0 means loop forever.
-        return loopCount ? loopCount : cAnimationLoopInfinite;
-    }
-
-    CFDictionaryRef pngProperties = (CFDictionaryRef)CFDictionaryGetValue(properties.get(), kCGImagePropertyPNGDictionary);
-    if (pngProperties) {
-        CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(pngProperties, WebCoreCGImagePropertyAPNGLoopCount);
-        if (!num)
-            return cAnimationLoopOnce;
-
-        int loopCount;
-        CFNumberGetValue(num, kCFNumberIntType, &loopCount);
-        return loopCount ? loopCount : cAnimationLoopInfinite;
-    }
-
-    // Turns out we're not an animated image after all, so we don't animate.
-    return cAnimationNone;
-}
-
-bool ImageDecoder::hotSpot(IntPoint& hotSpot) const
-{
-    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;
-}
-
-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);
-}
-
-bool ImageDecoder::frameIsCompleteAtIndex(size_t index) const
-{
-    ASSERT(frameCount());
-    return CGImageSourceGetStatusAtIndex(m_nativeDecoder.get(), index) == kCGImageStatusComplete;
-}
-
-ImageOrientation ImageDecoder::orientationAtIndex(size_t index) const
-{
-    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_nativeDecoder.get(), index, imageSourceOptions().get()));
-    if (properties) {
-        CFDictionaryRef gifProperties = (CFDictionaryRef)CFDictionaryGetValue(properties.get(), kCGImagePropertyGIFDictionary);
-        if (gifProperties) {
-            if (CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(gifProperties, kCGImagePropertyGIFUnclampedDelayTime)) {
-                // Use the unclamped frame delay if it exists.
-                CFNumberGetValue(num, kCFNumberFloatType, &duration);
-            } else if (CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(gifProperties, kCGImagePropertyGIFDelayTime)) {
-                // Fall back to the clamped frame delay if the unclamped frame delay does not exist.
-                CFNumberGetValue(num, kCFNumberFloatType, &duration);
-            }
-        }
-
-        CFDictionaryRef pngProperties = (CFDictionaryRef)CFDictionaryGetValue(properties.get(), kCGImagePropertyPNGDictionary);
-        if (pngProperties) {
-            if (CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(pngProperties, WebCoreCGImagePropertyAPNGUnclampedDelayTime))
-                CFNumberGetValue(num, kCFNumberFloatType, &duration);
-            else if (CFNumberRef num = (CFNumberRef)CFDictionaryGetValue(pngProperties, WebCoreCGImagePropertyAPNGDelayTime))
-                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.1f;
-    return duration;
-}
-
-bool ImageDecoder::allowSubsamplingOfFrameAtIndex(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;
-}
-
-bool ImageDecoder::frameHasAlphaAtIndex(size_t index) const
-{
-    if (!frameIsCompleteAtIndex(index))
-        return true;
-
-    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.
-    if (!imageType || CFEqual(imageType, CFSTR("public.jpeg")))
-        return false;
-
-    // FIXME: Could return false for other non-transparent image formats.
-    // FIXME: Could maybe return false for a GIF Frame if we have enough info in the GIF properties dictionary
-    // to determine whether or not a transparent color was defined.
-    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);
-#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)
 {