ImageSourceMac.cpp [plain text]
#include "config.h"
#include "ImageSource.h"
#include <CoreGraphics/CGImageSourcePrivate.h>
#include "IntSize.h"
namespace WebCore {
ImageSource::ImageSource()
: m_decoder(0), m_isProgressive(false), m_baseSubsampling(0)
{
}
ImageSource::~ImageSource()
{
clear();
}
void ImageSource::clear()
{
if (m_decoder) {
CFRelease(m_decoder);
m_decoder = 0;
}
}
const CFStringRef kCGImageSourceShouldPreferRGB32 = CFSTR("kCGImageSourceShouldPreferRGB32");
CFDictionaryRef ImageSource::imageSourceOptions(int requestedSubsampling) const
{
static CFDictionaryRef options[4] = {NULL, NULL, NULL, NULL};
int subsampling = std::min(3, m_isProgressive ? 0 : (requestedSubsampling + m_baseSubsampling));
if (!options[subsampling]) {
int subsampleInt = 1 << subsampling; CFNumberRef subsampleNumber = CFNumberCreate(NULL, kCFNumberIntType, &subsampleInt);
const void *keys[3] = { kCGImageSourceShouldCache, kCGImageSourceShouldPreferRGB32, kCGImageSourceSubsampleFactor };
const void *values[3] = { kCFBooleanTrue, kCFBooleanTrue, subsampleNumber };
options[subsampling] = CFDictionaryCreate(NULL, keys, values, 3,
&kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFRelease(subsampleNumber);
}
return options[subsampling];
}
bool ImageSource::initialized() const
{
return m_decoder;
}
void ImageSource::setData(NativeBytePtr data, bool allDataReceived)
{
if (!m_decoder)
m_decoder = CGImageSourceCreateIncremental(NULL);
CGImageSourceUpdateData(m_decoder, data, allDataReceived);
}
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::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);
if (!m_isProgressive)
{
CFDictionaryRef jfifProperties = (CFDictionaryRef)CFDictionaryGetValue(properties, kCGImagePropertyJFIFDictionary);
if (jfifProperties) {
CFBooleanRef isProgCFBool = (CFBooleanRef)CFDictionaryGetValue(jfifProperties, kCGImagePropertyJFIFIsProgressive);
if (isProgCFBool)
m_isProgressive = CFBooleanGetValue(isProgCFBool);
}
}
if ((m_baseSubsampling == 0) && !m_isProgressive) {
while ((m_baseSubsampling < 3) && (result.width() * result.height() > 2000000)) {
m_baseSubsampling++;
result = size();
}
}
CFRelease(properties);
}
return result;
}
int ImageSource::repetitionCount()
{
int result = cAnimationLoopOnce;
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, float scaleHint, float* actualScaleOut, ssize_t* bytesOut)
{
int subsampling = (int)log2f(1.0f / std::max(0.1f, std::min(1.0f, scaleHint)));
CGImageRef image = CGImageSourceCreateImageAtIndex(m_decoder, index, imageSourceOptions(subsampling));
*actualScaleOut = float(CGImageGetWidth(image)) / float(size().width()); *bytesOut = CGImageGetBytesPerRow(image) * CGImageGetHeight(image);
return image;
}
bool ImageSource::frameIsCompleteAtIndex(size_t index)
{
return CGImageSourceGetStatusAtIndex(m_decoder, index) == kCGImageStatusComplete;
}
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);
}
if (duration <= 0.010)
return 0.100;
return duration;
}
bool ImageSource::frameHasAlphaAtIndex(size_t index)
{
CFStringRef imageType = CGImageSourceGetType(m_decoder);
if (CFEqual(imageType, CFSTR("public.jpeg")))
return false;
return true;
}
}