#include "config.h"
#include "Color.h"
#if USE(CG)
#include "ColorSpaceCG.h"
#include <wtf/Assertions.h>
#include <wtf/RetainPtr.h>
#include <wtf/TinyLRUCache.h>
#include <pal/spi/cg/CoreGraphicsSPI.h>
#include <wtf/StdLibExtras.h>
namespace WebCore {
static CGColorRef leakCGColor(const Color&) CF_RETURNS_RETAINED;
}
namespace WTF {
template<>
RetainPtr<CGColorRef> TinyLRUCachePolicy<WebCore::Color, RetainPtr<CGColorRef>>::createValueForKey(const WebCore::Color& color)
{
return adoptCF(WebCore::leakCGColor(color));
}
}
namespace WebCore {
static Optional<SRGBA<uint8_t>> roundAndClampToSRGBALossy(CGColorRef color)
{
if (!color)
return WTF::nullopt;
size_t numComponents = CGColorGetNumberOfComponents(color);
const CGFloat* components = CGColorGetComponents(color);
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();
}
return convertToComponentBytes(SRGBA { r, g, b, a });
}
Color::Color(CGColorRef color)
: Color(roundAndClampToSRGBALossy(color))
{
}
Color::Color(CGColorRef color, SemanticTag tag)
: Color(roundAndClampToSRGBALossy(color), tag)
{
}
static CGColorRef leakCGColor(const Color& color)
{
auto [colorSpace, components] = color.colorSpaceAndComponents();
auto cgColorSpace = cachedCGColorSpace(colorSpace);
if (colorSpace != ColorSpace::SRGB && cgColorSpace == sRGBColorSpaceRef()) {
auto colorConvertedToSRGBA = callWithColorType(components, colorSpace, [] (const auto& color) {
return toSRGBA(color);
});
components = asColorComponents(colorConvertedToSRGBA);
}
auto [r, g, b, a] = components;
CGFloat cgFloatComponents[4] { r, g, b, a };
return CGColorCreate(cgColorSpace, cgFloatComponents);
}
CGColorRef cachedCGColor(const Color& color)
{
if (color.isInline()) {
switch (PackedColor::RGBA { color.asInline() }.value) {
case PackedColor::RGBA { Color::transparentBlack }.value: {
static CGColorRef transparentCGColor = leakCGColor(color);
return transparentCGColor;
}
case PackedColor::RGBA { Color::black }.value: {
static CGColorRef blackCGColor = leakCGColor(color);
return blackCGColor;
}
case PackedColor::RGBA { Color::white }.value: {
static CGColorRef whiteCGColor = leakCGColor(color);
return whiteCGColor;
}
}
}
static NeverDestroyed<TinyLRUCache<Color, RetainPtr<CGColorRef>, 32>> cache;
return cache.get().get(color).get();
}
}
#endif // USE(CG)