#include "config.h"
#include "ImageSource.h"
#if PLATFORM(CG)
#include "ImageSourceCG.h"
#include "IntSize.h"
#include "MIMETypeRegistry.h"
#include "SharedBuffer.h"
#include <ApplicationServices/ApplicationServices.h>
#include <wtf/UnusedParam.h>
namespace WebCore {
static const CFStringRef kCGImageSourceShouldPreferRGB32 = CFSTR("kCGImageSourceShouldPreferRGB32");
ImageSource::ImageSource()
: m_decoder(0)
{
}
ImageSource::~ImageSource()
{
clear(true);
}
void ImageSource::clear(bool destroyAllFrames, size_t, SharedBuffer* data, bool allDataReceived)
{
#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
if (!destroyAllFrames)
return;
#else
UNUSED_PARAM(destroyAllFrames);
#endif
if (m_decoder) {
CFRelease(m_decoder);
m_decoder = 0;
}
if (data)
setData(data, allDataReceived);
}
static CFDictionaryRef imageSourceOptions()
{
static CFDictionaryRef options;
if (!options) {
const unsigned numOptions = 2;
const void* keys[numOptions] = { kCGImageSourceShouldCache, kCGImageSourceShouldPreferRGB32 };
const void* values[numOptions] = { kCFBooleanTrue, kCFBooleanTrue };
options = CFDictionaryCreate(NULL, keys, values, numOptions,
&kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
}
return options;
}
bool ImageSource::initialized() const
{
return m_decoder;
}
void ImageSource::setData(SharedBuffer* data, bool allDataReceived)
{
if (!m_decoder)
m_decoder = CGImageSourceCreateIncremental(NULL);
#if PLATFORM(MAC)
CFDataRef cfData = data->createCFData();
#else
CFDataRef cfData = CFDataCreateWithBytesNoCopy(0, reinterpret_cast<const UInt8*>(data->data()), data->size(), kCFAllocatorNull);
#endif
CGImageSourceUpdateData(m_decoder, cfData, allDataReceived);
CFRelease(cfData);
}
String ImageSource::filenameExtension() const
{
if (!m_decoder)
return String();
CFStringRef imageSourceType = CGImageSourceGetType(m_decoder);
return WebCore::preferredExtensionForImageSourceType(imageSourceType);
}
bool ImageSource::isSizeAvailable()
{
bool result = false;
CGImageSourceStatus imageSourceStatus = CGImageSourceGetStatus(m_decoder);
if (imageSourceStatus >= kCGImageStatusIncomplete) {
CFDictionaryRef image0Properties = CGImageSourceCopyPropertiesAtIndex(m_decoder, 0, imageSourceOptions());
if (image0Properties) {
CFNumberRef widthNumber = (CFNumberRef)CFDictionaryGetValue(image0Properties, kCGImagePropertyPixelWidth);
CFNumberRef heightNumber = (CFNumberRef)CFDictionaryGetValue(image0Properties, kCGImagePropertyPixelHeight);
result = widthNumber && heightNumber;
CFRelease(image0Properties);
}
}
return result;
}
IntSize ImageSource::frameSizeAtIndex(size_t index) const
{
IntSize result;
CFDictionaryRef properties = CGImageSourceCopyPropertiesAtIndex(m_decoder, index, 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;
}
IntSize ImageSource::size() const
{
return frameSizeAtIndex(0);
}
int ImageSource::repetitionCount()
{
int result = cAnimationLoopOnce; if (!initialized())
return result;
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;
CFRelease(properties);
}
return result;
}
size_t ImageSource::frameCount() const
{
return m_decoder ? CGImageSourceGetCount(m_decoder) : 0;
}
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;
const CGFloat maskingColors[6] = {255, 255, 255, 255, 255, 255};
CGImageRef maskedImage = CGImageCreateWithMaskingColors(image, maskingColors);
if (!maskedImage)
return image;
CGImageRelease(image);
return maskedImage;
}
bool ImageSource::frameIsCompleteAtIndex(size_t index)
{
return CGImageSourceGetStatusAtIndex(m_decoder, index) == kCGImageStatusComplete;
}
float ImageSource::frameDurationAtIndex(size_t index)
{
if (!initialized())
return 0;
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);
}
if (duration < 0.051f)
return 0.100f;
return duration;
}
bool ImageSource::frameHasAlphaAtIndex(size_t)
{
if (!m_decoder)
return false;
CFStringRef imageType = CGImageSourceGetType(m_decoder);
if (!imageType || CFEqual(imageType, CFSTR("public.jpeg")))
return false;
return true;
}
}
#endif // PLATFORM(CG)