#include "config.h"
#include "Color.h"
#if USE(CG)
#include "GraphicsContextCG.h"
#include <wtf/Assertions.h>
#include <wtf/RetainPtr.h>
#if !PLATFORM(IOS)
#include <ApplicationServices/ApplicationServices.h>
#else
#include <WebCore/CoreGraphicsSPI.h>
#include <wtf/StdLibExtras.h>
#endif // !PLATFORM(IOS)
namespace WebCore {
#if PLATFORM(IOS)
static CGColorRef createCGColorWithDeviceRGBA(CGColorRef sourceColor)
{
if (!sourceColor || CFEqual(CGColorGetColorSpace(sourceColor), deviceRGBColorSpaceRef()))
return CGColorRetain(sourceColor);
RetainPtr<CGColorTransformRef> colorTransform = adoptCF(CGColorTransformCreate(deviceRGBColorSpaceRef(), nullptr));
if (!colorTransform)
return CGColorRetain(sourceColor);
return CGColorTransformConvertColor(colorTransform.get(), sourceColor, kCGRenderingIntentDefault);
}
#endif // PLATFORM(IOS)
Color::Color(CGColorRef color)
{
if (!color) {
m_color = 0;
m_valid = false;
return;
}
#if !PLATFORM(IOS)
size_t numComponents = CGColorGetNumberOfComponents(color);
const CGFloat* components = CGColorGetComponents(color);
#else
RetainPtr<CGColorRef> correctedColor = adoptCF(createCGColorWithDeviceRGBA(color));
if (!correctedColor)
correctedColor = color;
size_t numComponents = CGColorGetNumberOfComponents(correctedColor.get());
const CGFloat* components = CGColorGetComponents(correctedColor.get());
#endif // !PLATFORM(IOS)
float r = 0;
float g = 0;
float b = 0;
float a = 0;
switch (numComponents) {
case 2:
r = g = b = components[0];
a = components[1];
break;
case 4:
r = components[0];
g = components[1];
b = components[2];
a = components[3];
break;
default:
ASSERT_NOT_REACHED();
}
m_color = makeRGBA(r * 255, g * 255, b * 255, a * 255);
m_valid = true;
}
static CGColorRef leakCGColor(const Color& color, ColorSpace colorSpace)
{
CGFloat components[4];
color.getRGBA(components[0], components[1], components[2], components[3]);
return CGColorCreate(cachedCGColorSpace(colorSpace), components);
}
template<ColorSpace colorSpace> static CGColorRef cachedCGColor(const Color& color)
{
switch (color.rgb()) {
case Color::transparent: {
static CGColorRef transparentCGColor = leakCGColor(color, colorSpace);
return transparentCGColor;
}
case Color::black: {
static CGColorRef blackCGColor = leakCGColor(color, colorSpace);
return blackCGColor;
}
case Color::white: {
static CGColorRef whiteCGColor = leakCGColor(color, colorSpace);
return whiteCGColor;
}
}
ASSERT(color.rgb());
const size_t cacheSize = 32;
static RGBA32 cachedRGBAValues[cacheSize];
static RetainPtr<CGColorRef>* cachedCGColors = new RetainPtr<CGColorRef>[cacheSize];
for (size_t i = 0; i < cacheSize; ++i) {
if (cachedRGBAValues[i] == color.rgb())
return cachedCGColors[i].get();
}
CGColorRef newCGColor = leakCGColor(color, colorSpace);
static size_t cursor;
cachedRGBAValues[cursor] = color.rgb();
cachedCGColors[cursor] = adoptCF(newCGColor);
if (++cursor == cacheSize)
cursor = 0;
return newCGColor;
}
CGColorRef cachedCGColor(const Color& color, ColorSpace colorSpace)
{
switch (colorSpace) {
case ColorSpaceDeviceRGB:
return cachedCGColor<ColorSpaceDeviceRGB>(color);
case ColorSpaceSRGB:
return cachedCGColor<ColorSpaceSRGB>(color);
case ColorSpaceLinearRGB:
return cachedCGColor<ColorSpaceLinearRGB>(color);
}
ASSERT_NOT_REACHED();
return cachedCGColor(color, ColorSpaceDeviceRGB);
}
}
#endif // USE(CG)