#include "config.h"
#include "Color.h"
#if USE(CG)
#include "GraphicsContextCG.h"
#include <wtf/Assertions.h>
#include <wtf/RetainPtr.h>
#include <wtf/TinyLRUCache.h>
#if !PLATFORM(IOS)
#include <ApplicationServices/ApplicationServices.h>
#else
#include "CoreGraphicsSPI.h"
#include <wtf/StdLibExtras.h>
#endif // !PLATFORM(IOS)
namespace WebCore {
static CGColorRef leakCGColor(const Color&);
}
namespace WTF {
template<>
RetainPtr<CGColorRef> TinyLRUCachePolicy<WebCore::Color, RetainPtr<CGColorRef>>::createValueForKey(const WebCore::Color& color)
{
return adoptCF(WebCore::leakCGColor(color));
}
}
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)
{
CGFloat components[4];
color.getRGBA(components[0], components[1], components[2], components[3]);
return CGColorCreate(sRGBColorSpaceRef(), components);
}
CGColorRef cachedCGColor(const Color& color)
{
switch (color.rgb()) {
case Color::transparent: {
static CGColorRef transparentCGColor = leakCGColor(color);
return transparentCGColor;
}
case Color::black: {
static CGColorRef blackCGColor = leakCGColor(color);
return blackCGColor;
}
case Color::white: {
static CGColorRef whiteCGColor = leakCGColor(color);
return whiteCGColor;
}
}
ASSERT(color.rgb());
static NeverDestroyed<TinyLRUCache<Color, RetainPtr<CGColorRef>, 32>> cache;
return cache.get().get(color).get();
}
}
#endif // USE(CG)