Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / themes / theme_service_mac.mm
blob3c469126358652070a083b3ca2b756dff63164ec
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/themes/theme_service.h"
7 #import <Cocoa/Cocoa.h>
9 #include "base/logging.h"
10 #include "chrome/browser/themes/browser_theme_pack.h"
11 #include "chrome/browser/themes/theme_properties.h"
12 #include "skia/ext/skia_utils_mac.h"
13 #import "third_party/google_toolbox_for_mac/src/AppKit/GTMNSColor+Luminance.h"
14 #include "ui/base/resource/resource_bundle.h"
15 #include "ui/gfx/color_utils.h"
16 #include "ui/gfx/image/image.h"
17 #include "skia/ext/skia_utils_mac.h"
19 NSString* const kBrowserThemeDidChangeNotification =
20     @"BrowserThemeDidChangeNotification";
22 typedef ThemeProperties Properties;
24 namespace {
26 void HSLToHSB(const color_utils::HSL& hsl, CGFloat* h, CGFloat* s, CGFloat* b) {
27   SkColor color = color_utils::HSLToSkColor(hsl, 255);  // alpha doesn't matter
28   SkScalar hsv[3];
29   SkColorToHSV(color, hsv);
31   *h = SkScalarToDouble(hsv[0]) / 360.0;
32   *s = SkScalarToDouble(hsv[1]);
33   *b = SkScalarToDouble(hsv[2]);
36 }  // namespace
38 NSImage* ThemeService::GetNSImageNamed(int id) const {
39   DCHECK(CalledOnValidThread());
41   // Check to see if we already have the image in the cache.
42   NSImageMap::const_iterator nsimage_iter = nsimage_cache_.find(id);
43   if (nsimage_iter != nsimage_cache_.end())
44     return nsimage_iter->second;
46   // Why don't we load the file directly into the image instead of the whole
47   // gfx::Image > native conversion?
48   // - For consistency with other platforms.
49   // - To get the generated tinted images.
50   NSImage* nsimage = nil;
51   if (theme_supplier_.get()) {
52     gfx::Image image = theme_supplier_->GetImageNamed(id);
53     if (!image.IsEmpty())
54       nsimage = image.ToNSImage();
55   }
57   // If the theme didn't override this image then load it from the resource
58   // bundle.
59   if (!nsimage) {
60     nsimage = rb_.GetNativeImageNamed(id).ToNSImage();
61   }
63   // We loaded successfully.  Cache the image.
64   if (nsimage) {
65     nsimage_cache_[id] = [nsimage retain];
66     return nsimage;
67   }
69   // We failed to retrieve the bitmap, show a debugging red square.
70   LOG(WARNING) << "Unable to load NSImage with id " << id;
71   NOTREACHED();  // Want to assert in debug mode.
73   static NSImage* empty_image = NULL;
74   if (!empty_image) {
75     // The placeholder image is bright red so people notice the problem.  This
76     // image will be leaked, but this code should never be hit.
77     NSRect image_rect = NSMakeRect(0, 0, 32, 32);
78     empty_image = [[NSImage alloc] initWithSize:image_rect.size];
79     [empty_image lockFocus];
80     [[NSColor redColor] set];
81     NSRectFill(image_rect);
82     [empty_image unlockFocus];
83   }
85   return empty_image;
88 NSColor* ThemeService::GetNSImageColorNamed(int id) const {
89   DCHECK(CalledOnValidThread());
91   // Check to see if we already have the color in the cache.
92   NSColorMap::const_iterator nscolor_iter = nscolor_cache_.find(id);
93   if (nscolor_iter != nscolor_cache_.end())
94     return nscolor_iter->second;
96   NSImage* image = GetNSImageNamed(id);
97   if (!image)
98     return nil;
99   NSColor* image_color = [NSColor colorWithPatternImage:image];
101   // We loaded successfully.  Cache the color.
102   if (image_color)
103     nscolor_cache_[id] = [image_color retain];
105   return image_color;
108 NSColor* ThemeService::GetNSColor(int id) const {
109   DCHECK(CalledOnValidThread());
111   // Check to see if we already have the color in the cache.
112   NSColorMap::const_iterator nscolor_iter = nscolor_cache_.find(id);
113   if (nscolor_iter != nscolor_cache_.end())
114     return nscolor_iter->second;
116   SkColor sk_color = GetColor(id);
117   NSColor* color = gfx::SkColorToCalibratedNSColor(sk_color);
119   // We loaded successfully.  Cache the color.
120   if (color)
121     nscolor_cache_[id] = [color retain];
123   return color;
126 NSColor* ThemeService::GetNSColorTint(int id) const {
127   DCHECK(CalledOnValidThread());
129   // Check to see if we already have the color in the cache.
130   NSColorMap::const_iterator nscolor_iter = nscolor_cache_.find(id);
131   if (nscolor_iter != nscolor_cache_.end())
132     return nscolor_iter->second;
134   color_utils::HSL tint = GetTint(id);
135   NSColor* tint_color = nil;
136   if (tint.h == -1 && tint.s == -1 && tint.l == -1) {
137     tint_color = [NSColor blackColor];
138   } else {
139     CGFloat hue, saturation, brightness;
140     HSLToHSB(tint, &hue, &saturation, &brightness);
142     tint_color = [NSColor colorWithCalibratedHue:hue
143                                       saturation:saturation
144                                       brightness:brightness
145                                            alpha:1.0];
146   }
148   // We loaded successfully.  Cache the color.
149   if (tint_color)
150     nscolor_cache_[id] = [tint_color retain];
152   return tint_color;
155 NSGradient* ThemeService::GetNSGradient(int id) const {
156   DCHECK(CalledOnValidThread());
158   // Check to see if we already have the gradient in the cache.
159   NSGradientMap::const_iterator nsgradient_iter = nsgradient_cache_.find(id);
160   if (nsgradient_iter != nsgradient_cache_.end())
161     return nsgradient_iter->second;
163   NSGradient* gradient = nil;
165   // Note that we are not leaking when we assign a retained object to
166   // |gradient|; in all cases we cache it before we return.
167   switch (id) {
168     case Properties::GRADIENT_FRAME_INCOGNITO:
169     case Properties::GRADIENT_FRAME_INCOGNITO_INACTIVE: {
170       // TODO(avi): can we simplify this?
171       BOOL active = id == Properties::GRADIENT_FRAME_INCOGNITO;
172       NSColor* base_color = [NSColor colorWithCalibratedRed:83/255.0
173                                                       green:108.0/255.0
174                                                        blue:140/255.0
175                                                       alpha:1.0];
177       NSColor *start_color =
178           [base_color gtm_colorAdjustedFor:GTMColorationBaseMidtone
179                                      faded:!active];
180       NSColor *end_color =
181           [base_color gtm_colorAdjustedFor:GTMColorationBaseShadow
182                                      faded:!active];
184       if (!active) {
185         start_color = [start_color gtm_colorByAdjustingLuminance:0.1
186                                                       saturation:0.5];
187         end_color = [end_color gtm_colorByAdjustingLuminance:0.1
188                                                   saturation:0.5];
189       }
191       gradient = [[NSGradient alloc] initWithStartingColor:start_color
192                                                endingColor:end_color];
193       break;
194     }
196     case Properties::GRADIENT_TOOLBAR:
197     case Properties::GRADIENT_TOOLBAR_INACTIVE: {
198       NSColor* base_color = [NSColor colorWithCalibratedWhite:0.2 alpha:1.0];
199       BOOL faded = (id == Properties::GRADIENT_TOOLBAR_INACTIVE ) ||
200                    (id == Properties::GRADIENT_TOOLBAR_BUTTON_INACTIVE);
201       NSColor* start_color =
202           [base_color gtm_colorAdjustedFor:GTMColorationLightHighlight
203                                      faded:faded];
204       NSColor* mid_color =
205           [base_color gtm_colorAdjustedFor:GTMColorationLightMidtone
206                                      faded:faded];
207       NSColor* end_color =
208           [base_color gtm_colorAdjustedFor:GTMColorationLightShadow
209                                      faded:faded];
210       NSColor* glow_color =
211           [base_color gtm_colorAdjustedFor:GTMColorationLightPenumbra
212                                      faded:faded];
214       gradient =
215           [[NSGradient alloc] initWithColorsAndLocations:start_color, 0.0,
216                                                          mid_color, 0.25,
217                                                          end_color, 0.5,
218                                                          glow_color, 0.75,
219                                                          nil];
220       break;
221     }
223     case Properties::GRADIENT_TOOLBAR_BUTTON:
224     case Properties::GRADIENT_TOOLBAR_BUTTON_INACTIVE: {
225       NSColor* start_color = [NSColor colorWithCalibratedWhite:1.0 alpha:0.0];
226       NSColor* end_color = [NSColor colorWithCalibratedWhite:1.0 alpha:0.3];
227       gradient = [[NSGradient alloc] initWithStartingColor:start_color
228                                                endingColor:end_color];
229       break;
230     }
231     case Properties::GRADIENT_TOOLBAR_BUTTON_PRESSED:
232     case Properties::GRADIENT_TOOLBAR_BUTTON_PRESSED_INACTIVE: {
233       NSColor* base_color = [NSColor colorWithCalibratedWhite:0.5 alpha:1.0];
234       BOOL faded = id == Properties::GRADIENT_TOOLBAR_BUTTON_PRESSED_INACTIVE;
235       NSColor* start_color =
236           [base_color gtm_colorAdjustedFor:GTMColorationBaseShadow
237                                      faded:faded];
238       NSColor* end_color =
239           [base_color gtm_colorAdjustedFor:GTMColorationBaseMidtone
240                                      faded:faded];
242       gradient = [[NSGradient alloc] initWithStartingColor:start_color
243                                                endingColor:end_color];
244       break;
245     }
246     default:
247       LOG(WARNING) << "Gradient request with unknown id " << id;
248       NOTREACHED();  // Want to assert in debug mode.
249       break;
250   }
252   // We loaded successfully.  Cache the gradient.
253   if (gradient)
254     nsgradient_cache_[id] = gradient;  // created retained
256   return gradient;
259 // Let all the browser views know that themes have changed in a platform way.
260 void ThemeService::NotifyPlatformThemeChanged() {
261   NSNotificationCenter* defaultCenter = [NSNotificationCenter defaultCenter];
262   [defaultCenter postNotificationName:kBrowserThemeDidChangeNotification
263                                object:[NSValue valueWithPointer:this]];
266 void ThemeService::FreePlatformCaches() {
267   DCHECK(CalledOnValidThread());
269   // Free images.
270   for (NSImageMap::iterator i = nsimage_cache_.begin();
271        i != nsimage_cache_.end(); i++) {
272     [i->second release];
273   }
274   nsimage_cache_.clear();
276   // Free colors.
277   for (NSColorMap::iterator i = nscolor_cache_.begin();
278        i != nscolor_cache_.end(); i++) {
279     [i->second release];
280   }
281   nscolor_cache_.clear();
283   // Free gradients.
284   for (NSGradientMap::iterator i = nsgradient_cache_.begin();
285        i != nsgradient_cache_.end(); i++) {
286     [i->second release];
287   }
288   nsgradient_cache_.clear();