571b91342396cc8a0f5922be1255d10f5328358f
[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
29 #import <wtf/Assertions.h>
30 #import <wtf/RetainPtr.h>
31
32 @interface WebCoreControlTintObserver : NSObject
33 + (void)controlTintDidChange;
34 @end
35
36 namespace WebCore {
37
38 // NSColor calls don't throw, so no need to block Cocoa exceptions in this file
39
40 static bool tintIsKnown;
41 static bool tintIsKnownToBeGraphite;
42 static void (*tintChangeFunction)();
43
44 NSColor* nsColor(const Color& color)
45 {
46     unsigned c = color.rgb();
47     switch (c) {
48         case 0: {
49             // Need this to avoid returning nil because cachedRGBAValues will default to 0.
50             static RetainPtr<NSColor> clearColor = [NSColor clearColor];
51             return clearColor.get();
52         }
53         case Color::black: {
54             static RetainPtr<NSColor> blackColor = [NSColor blackColor];
55             return blackColor.get();
56         }
57         case Color::white: {
58             static RetainPtr<NSColor> whiteColor = [NSColor whiteColor];
59             return whiteColor.get();
60         }
61         default: {
62             const int cacheSize = 32;
63             static unsigned cachedRGBAValues[cacheSize];
64             static RetainPtr<NSColor> cachedColors[cacheSize];
65
66             for (int i = 0; i != cacheSize; ++i)
67                 if (cachedRGBAValues[i] == c)
68                     return cachedColors[i].get();
69
70 #ifdef COLORMATCH_EVERYTHING
71             NSColor* result = [NSColor colorWithCalibratedRed:color.red() / 255.0f
72                                                         green:color.green() / 255.0f
73                                                          blue:color.blue() / 255.0f
74                                                         alpha:color.alpha() /255.0f];
75 #else
76             NSColor* result = [NSColor colorWithDeviceRed:color.red() / 255.0f
77                                                     green:color.green() / 255.0f
78                                                      blue:color.blue() / 255.0f
79                                                     alpha:color.alpha() /255.0f];
80 #endif
81
82             static int cursor;
83             cachedRGBAValues[cursor] = c;
84             cachedColors[cursor] = result;
85             if (++cursor == cacheSize)
86                 cursor = 0;
87             return result;
88         }
89     }
90 }
91
92 static CGColorRef CGColorFromNSColor(NSColor* color)
93 {
94     // This needs to always use device colorspace so it can de-calibrate the color for
95     // CGColor to possibly recalibrate it.
96     NSColor* deviceColor = [color colorUsingColorSpaceName:NSDeviceRGBColorSpace];
97     CGFloat red = [deviceColor redComponent];
98     CGFloat green = [deviceColor greenComponent];
99     CGFloat blue = [deviceColor blueComponent];
100     CGFloat alpha = [deviceColor alphaComponent];
101     const CGFloat components[4] = { red, green, blue, alpha };
102     static CGColorSpaceRef deviceRGBColorSpace = CGColorSpaceCreateDeviceRGB();
103     CGColorRef cgColor = CGColorCreate(deviceRGBColorSpace, components);
104     return cgColor;
105 }
106
107 CGColorRef cgColor(const Color& c)
108 {
109     // We could directly create a CGColor here, but that would
110     // skip any RGB caching the nsColor method does. A direct 
111     // creation could be investigated for a possible performance win.
112     return CGColorFromNSColor(nsColor(c));
113 }
114
115 static void observeTint()
116 {
117     ASSERT(!tintIsKnown);
118     [[NSNotificationCenter defaultCenter] addObserver:[WebCoreControlTintObserver class]
119                                              selector:@selector(controlTintDidChange)
120                                                  name:NSControlTintDidChangeNotification
121                                                object:NSApp];
122     [WebCoreControlTintObserver controlTintDidChange];
123     tintIsKnown = true;
124 }
125
126 void setFocusRingColorChangeFunction(void (*function)())
127 {
128     ASSERT(!tintChangeFunction);
129     tintChangeFunction = function;
130     if (!tintIsKnown)
131         observeTint();
132 }
133
134 Color focusRingColor()
135 {
136     if (!tintIsKnown)
137         observeTint();
138     return tintIsKnownToBeGraphite ? 0xFF9CABBD : 0xFF7DADD9;
139 }
140
141 }
142
143 @implementation WebCoreControlTintObserver
144
145 + (void)controlTintDidChange
146 {
147     WebCore::tintIsKnownToBeGraphite = [NSColor currentControlTint] == NSGraphiteControlTint;
148 }
149
150 @end