WebCore:
[WebKit-https.git] / WebCore / platform / graphics / mac / ColorMac.mm
1 /*
2  * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, 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 #import "config.h"
27 #import "Color.h"
28 #import "ColorMac.h"
29
30 #import <wtf/Assertions.h>
31 #import <wtf/RetainPtr.h>
32
33 @interface WebCoreControlTintObserver : NSObject
34 + (void)controlTintDidChange;
35 @end
36
37 namespace WebCore {
38
39 // NSColor calls don't throw, so no need to block Cocoa exceptions in this file
40
41 static RGBA32 oldAquaFocusRingColor = 0xFF7DADD9;
42 static bool tintIsKnown;
43 static void (*tintChangeFunction)();
44 static RGBA32 systemFocusRingColor;
45 static bool useOldAquaFocusRingColor;
46
47
48 static RGBA32 makeRGBAFromNSColor(NSColor *c)
49 {
50     return makeRGBA((int)(255 * [c redComponent]), (int)(255 * [c greenComponent]), (int)(255 * [c blueComponent]), (int)(255 * [c alphaComponent]));
51 }
52
53 Color colorFromNSColor(NSColor *c)
54 {
55     return Color(makeRGBAFromNSColor(c));
56 }
57
58 NSColor* nsColor(const Color& color)
59 {
60     unsigned c = color.rgb();
61     switch (c) {
62         case 0: {
63             // Need this to avoid returning nil because cachedRGBAValues will default to 0.
64             static RetainPtr<NSColor> clearColor = [NSColor clearColor];
65             return clearColor.get();
66         }
67         case Color::black: {
68             static RetainPtr<NSColor> blackColor = [NSColor blackColor];
69             return blackColor.get();
70         }
71         case Color::white: {
72             static RetainPtr<NSColor> whiteColor = [NSColor whiteColor];
73             return whiteColor.get();
74         }
75         default: {
76             const int cacheSize = 32;
77             static unsigned cachedRGBAValues[cacheSize];
78             static RetainPtr<NSColor> cachedColors[cacheSize];
79
80             for (int i = 0; i != cacheSize; ++i)
81                 if (cachedRGBAValues[i] == c)
82                     return cachedColors[i].get();
83
84 #ifdef COLORMATCH_EVERYTHING
85             NSColor* result = [NSColor colorWithCalibratedRed:color.red() / 255.0f
86                                                         green:color.green() / 255.0f
87                                                          blue:color.blue() / 255.0f
88                                                         alpha:color.alpha() /255.0f];
89 #else
90             NSColor* result = [NSColor colorWithDeviceRed:color.red() / 255.0f
91                                                     green:color.green() / 255.0f
92                                                      blue:color.blue() / 255.0f
93                                                     alpha:color.alpha() /255.0f];
94 #endif
95
96             static int cursor;
97             cachedRGBAValues[cursor] = c;
98             cachedColors[cursor] = result;
99             if (++cursor == cacheSize)
100                 cursor = 0;
101             return result;
102         }
103     }
104 }
105
106 static CGColorRef CGColorFromNSColor(NSColor* color)
107 {
108     // This needs to always use device colorspace so it can de-calibrate the color for
109     // CGColor to possibly recalibrate it.
110     NSColor* deviceColor = [color colorUsingColorSpaceName:NSDeviceRGBColorSpace];
111     CGFloat red = [deviceColor redComponent];
112     CGFloat green = [deviceColor greenComponent];
113     CGFloat blue = [deviceColor blueComponent];
114     CGFloat alpha = [deviceColor alphaComponent];
115     const CGFloat components[4] = { red, green, blue, alpha };
116     static CGColorSpaceRef deviceRGBColorSpace = CGColorSpaceCreateDeviceRGB();
117     CGColorRef cgColor = CGColorCreate(deviceRGBColorSpace, components);
118     return cgColor;
119 }
120
121 CGColorRef cgColor(const Color& c)
122 {
123     // We could directly create a CGColor here, but that would
124     // skip any RGB caching the nsColor method does. A direct 
125     // creation could be investigated for a possible performance win.
126     return CGColorFromNSColor(nsColor(c));
127 }
128
129 static void observeTint()
130 {
131     ASSERT(!tintIsKnown);
132     [[NSNotificationCenter defaultCenter] addObserver:[WebCoreControlTintObserver class]
133                                              selector:@selector(controlTintDidChange)
134                                                  name:NSControlTintDidChangeNotification
135                                                object:NSApp];
136     [WebCoreControlTintObserver controlTintDidChange];
137     tintIsKnown = true;
138 }
139
140 void setFocusRingColorChangeFunction(void (*function)())
141 {
142     ASSERT(!tintChangeFunction);
143     tintChangeFunction = function;
144     if (!tintIsKnown)
145         observeTint();
146 }
147
148 Color focusRingColor()
149 {
150     if (!tintIsKnown)
151         observeTint();
152     
153     if (usesTestModeFocusRingColor())
154         return oldAquaFocusRingColor;
155     
156     return systemFocusRingColor;
157 }
158
159 bool usesTestModeFocusRingColor()
160 {
161     return useOldAquaFocusRingColor;
162 }
163
164 void setUsesTestModeFocusRingColor(bool newValue)
165 {
166     useOldAquaFocusRingColor = newValue;
167 }
168
169 }
170
171 @implementation WebCoreControlTintObserver
172
173 + (void)controlTintDidChange
174 {
175 #ifdef COLORMATCH_EVERYTHING
176 #error Not yet implemented.
177 #else
178     NSColor* color = [[NSColor keyboardFocusIndicatorColor] colorUsingColorSpaceName:NSDeviceRGBColorSpace];
179     WebCore::systemFocusRingColor = WebCore::makeRGBAFromNSColor(color);
180 #endif
181 }
182
183 @end