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
36 namespace WebCore {
37
Color(CGColorRef color)38 Color::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
cachedCGColorSpace(ColorSpace colorSpace)73 static 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
leakCGColor(const Color & color,ColorSpace colorSpace)87 static 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
cachedCGColor(const Color & color)94 template<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
cachedCGColor(const Color & color,ColorSpace colorSpace)133 CGColorRef 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