1/*
2 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2010 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "Color.h"
28
29#if USE(CG)
30
31#include "GraphicsContextCG.h"
32#include <wtf/Assertions.h>
33#include <wtf/RetainPtr.h>
34#include <ApplicationServices/ApplicationServices.h>
35
36namespace WebCore {
37
38Color::Color(CGColorRef color)
39{
40    if (!color) {
41        m_color = 0;
42        m_valid = false;
43        return;
44    }
45
46    size_t numComponents = CGColorGetNumberOfComponents(color);
47    const CGFloat* components = CGColorGetComponents(color);
48
49    float r = 0;
50    float g = 0;
51    float b = 0;
52    float a = 0;
53
54    switch (numComponents) {
55    case 2:
56        r = g = b = components[0];
57        a = components[1];
58        break;
59    case 4:
60        r = components[0];
61        g = components[1];
62        b = components[2];
63        a = components[3];
64        break;
65    default:
66        ASSERT_NOT_REACHED();
67    }
68
69    m_color = makeRGBA(r * 255, g * 255, b * 255, a * 255);
70    m_valid = true;
71}
72
73static inline CGColorSpaceRef cachedCGColorSpace(ColorSpace colorSpace)
74{
75    switch (colorSpace) {
76    case ColorSpaceDeviceRGB:
77        return deviceRGBColorSpaceRef();
78    case ColorSpaceSRGB:
79        return sRGBColorSpaceRef();
80    case ColorSpaceLinearRGB:
81        return linearRGBColorSpaceRef();
82    }
83    ASSERT_NOT_REACHED();
84    return deviceRGBColorSpaceRef();
85}
86
87static CGColorRef leakCGColor(const Color& color, ColorSpace colorSpace)
88{
89    CGFloat components[4];
90    color.getRGBA(components[0], components[1], components[2], components[3]);
91    return CGColorCreate(cachedCGColorSpace(colorSpace), components);
92}
93
94template<ColorSpace colorSpace> static CGColorRef cachedCGColor(const Color& color)
95{
96    switch (color.rgb()) {
97    case Color::transparent: {
98        static CGColorRef transparentCGColor = leakCGColor(color, colorSpace);
99        return transparentCGColor;
100    }
101    case Color::black: {
102        static CGColorRef blackCGColor = leakCGColor(color, colorSpace);
103        return blackCGColor;
104    }
105    case Color::white: {
106        static CGColorRef whiteCGColor = leakCGColor(color, colorSpace);
107        return whiteCGColor;
108    }
109    }
110
111    ASSERT(color.rgb());
112
113    const size_t cacheSize = 32;
114    static RGBA32 cachedRGBAValues[cacheSize];
115    static RetainPtr<CGColorRef>* cachedCGColors = new RetainPtr<CGColorRef>[cacheSize];
116
117    for (size_t i = 0; i < cacheSize; ++i) {
118        if (cachedRGBAValues[i] == color.rgb())
119            return cachedCGColors[i].get();
120    }
121
122    CGColorRef newCGColor = leakCGColor(color, colorSpace);
123
124    static size_t cursor;
125    cachedRGBAValues[cursor] = color.rgb();
126    cachedCGColors[cursor].adoptCF(newCGColor);
127    if (++cursor == cacheSize)
128        cursor = 0;
129
130    return newCGColor;
131}
132
133CGColorRef cachedCGColor(const Color& color, ColorSpace colorSpace)
134{
135    switch (colorSpace) {
136    case ColorSpaceDeviceRGB:
137        return cachedCGColor<ColorSpaceDeviceRGB>(color);
138    case ColorSpaceSRGB:
139        return cachedCGColor<ColorSpaceSRGB>(color);
140    case ColorSpaceLinearRGB:
141        return cachedCGColor<ColorSpaceLinearRGB>(color);
142    }
143    ASSERT_NOT_REACHED();
144    return cachedCGColor(color, ColorSpaceDeviceRGB);
145}
146
147}
148
149#endif // USE(CG)
150