summaryrefslogtreecommitdiffstats
path: root/chrome/browser/browser_theme_provider_mac.mm
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser/browser_theme_provider_mac.mm')
-rw-r--r--chrome/browser/browser_theme_provider_mac.mm317
1 files changed, 317 insertions, 0 deletions
diff --git a/chrome/browser/browser_theme_provider_mac.mm b/chrome/browser/browser_theme_provider_mac.mm
new file mode 100644
index 0000000..edac255
--- /dev/null
+++ b/chrome/browser/browser_theme_provider_mac.mm
@@ -0,0 +1,317 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/browser_theme_provider.h"
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/logging.h"
+#include "chrome/browser/browser_theme_pack.h"
+#include "gfx/color_utils.h"
+#include "skia/ext/skia_utils_mac.h"
+#import "third_party/GTM/AppKit/GTMNSColor+Luminance.h"
+
+NSString* const kBrowserThemeDidChangeNotification =
+ @"BrowserThemeDidChangeNotification";
+
+namespace {
+
+void HSLToHSB(const color_utils::HSL& hsl, CGFloat* h, CGFloat* s, CGFloat* b) {
+ SkColor color = color_utils::HSLToSkColor(hsl, 255); // alpha doesn't matter
+ SkScalar hsv[3];
+ SkColorToHSV(color, hsv);
+
+ *h = SkScalarToDouble(hsv[0]) / 360.0;
+ *s = SkScalarToDouble(hsv[1]);
+ *b = SkScalarToDouble(hsv[2]);
+}
+
+}
+
+NSImage* BrowserThemeProvider::GetNSImageNamed(int id,
+ bool allow_default) const {
+ DCHECK(CalledOnValidThread());
+
+ if (!allow_default && !HasCustomImage(id))
+ return nil;
+
+ // Check to see if we already have the image in the cache.
+ NSImageMap::const_iterator nsimage_iter = nsimage_cache_.find(id);
+ if (nsimage_iter != nsimage_cache_.end())
+ return nsimage_iter->second;
+
+ // Why don't we load the file directly into the image instead of the whole
+ // SkBitmap > native conversion?
+ // - For consistency with other platforms.
+ // - To get the generated tinted images.
+ SkBitmap* bitmap = GetBitmapNamed(id);
+ NSImage* nsimage = gfx::SkBitmapToNSImage(*bitmap);
+
+ // We loaded successfully. Cache the image.
+ if (nsimage) {
+ nsimage_cache_[id] = [nsimage retain];
+ return nsimage;
+ }
+
+ // We failed to retrieve the bitmap, show a debugging red square.
+ LOG(WARNING) << "Unable to load NSImage with id " << id;
+ NOTREACHED(); // Want to assert in debug mode.
+
+ static NSImage* empty_image = NULL;
+ if (!empty_image) {
+ // The placeholder image is bright red so people notice the problem. This
+ // image will be leaked, but this code should never be hit.
+ NSRect image_rect = NSMakeRect(0, 0, 32, 32);
+ empty_image = [[NSImage alloc] initWithSize:image_rect.size];
+ [empty_image lockFocus];
+ [[NSColor redColor] set];
+ NSRectFill(image_rect);
+ [empty_image unlockFocus];
+ }
+
+ return empty_image;
+}
+
+NSColor* BrowserThemeProvider::GetNSImageColorNamed(int id,
+ bool allow_default) const {
+ DCHECK(CalledOnValidThread());
+
+ // Check to see if we already have the color in the cache.
+ NSColorMap::const_iterator nscolor_iter = nscolor_cache_.find(id);
+ if (nscolor_iter != nscolor_cache_.end()) {
+ bool cached_is_default = nscolor_iter->second.second;
+ if (!cached_is_default || allow_default)
+ return nscolor_iter->second.first;
+ }
+
+ NSImage* image = GetNSImageNamed(id, allow_default);
+ if (!image)
+ return nil;
+ NSColor* image_color = [NSColor colorWithPatternImage:image];
+
+ // We loaded successfully. Cache the color.
+ if (image_color) {
+ nscolor_cache_[id] = std::make_pair([image_color retain],
+ !HasCustomImage(id));
+ }
+
+ return image_color;
+}
+
+NSColor* BrowserThemeProvider::GetNSColor(int id,
+ bool allow_default) const {
+ DCHECK(CalledOnValidThread());
+
+ // Check to see if we already have the color in the cache.
+ NSColorMap::const_iterator nscolor_iter = nscolor_cache_.find(id);
+ if (nscolor_iter != nscolor_cache_.end()) {
+ bool cached_is_default = nscolor_iter->second.second;
+ if (!cached_is_default || allow_default)
+ return nscolor_iter->second.first;
+ }
+
+ bool is_default = false;
+ SkColor sk_color;
+ if (theme_pack_.get() && theme_pack_->GetColor(id, &sk_color)) {
+ is_default = false;
+ } else {
+ is_default = true;
+ sk_color = GetDefaultColor(id);
+ }
+
+ if (is_default && !allow_default)
+ return nil;
+
+ NSColor* color = [NSColor
+ colorWithCalibratedRed:SkColorGetR(sk_color)/255.0
+ green:SkColorGetG(sk_color)/255.0
+ blue:SkColorGetB(sk_color)/255.0
+ alpha:SkColorGetA(sk_color)/255.0];
+
+ // We loaded successfully. Cache the color.
+ if (color)
+ nscolor_cache_[id] = std::make_pair([color retain], is_default);
+
+ return color;
+}
+
+NSColor* BrowserThemeProvider::GetNSColorTint(int id,
+ bool allow_default) const {
+ DCHECK(CalledOnValidThread());
+
+ // Check to see if we already have the color in the cache.
+ NSColorMap::const_iterator nscolor_iter = nscolor_cache_.find(id);
+ if (nscolor_iter != nscolor_cache_.end()) {
+ bool cached_is_default = nscolor_iter->second.second;
+ if (!cached_is_default || allow_default)
+ return nscolor_iter->second.first;
+ }
+
+ bool is_default = false;
+ color_utils::HSL tint;
+ if (theme_pack_.get() && theme_pack_->GetTint(id, &tint)) {
+ is_default = false;
+ } else {
+ is_default = true;
+ tint = GetDefaultTint(id);
+ }
+
+ if (is_default && !allow_default)
+ return nil;
+
+ NSColor* tint_color = nil;
+ if (tint.h == -1 && tint.s == -1 && tint.l == -1) {
+ tint_color = [NSColor blackColor];
+ } else {
+ CGFloat hue, saturation, brightness;
+ HSLToHSB(tint, &hue, &saturation, &brightness);
+
+ tint_color = [NSColor colorWithCalibratedHue:hue
+ saturation:saturation
+ brightness:brightness
+ alpha:1.0];
+ }
+
+ // We loaded successfully. Cache the color.
+ if (tint_color)
+ nscolor_cache_[id] = std::make_pair([tint_color retain], is_default);
+
+ return tint_color;
+}
+
+NSGradient* BrowserThemeProvider::GetNSGradient(int id) const {
+ DCHECK(CalledOnValidThread());
+
+ // Check to see if we already have the gradient in the cache.
+ NSGradientMap::const_iterator nsgradient_iter = nsgradient_cache_.find(id);
+ if (nsgradient_iter != nsgradient_cache_.end())
+ return nsgradient_iter->second;
+
+ NSGradient* gradient = nil;
+
+ // Note that we are not leaking when we assign a retained object to
+ // |gradient|; in all cases we cache it before we return.
+ switch (id) {
+ case GRADIENT_FRAME_INCOGNITO:
+ case GRADIENT_FRAME_INCOGNITO_INACTIVE: {
+ // TODO(avi): can we simplify this?
+ BOOL active = id == GRADIENT_FRAME_INCOGNITO;
+ NSColor* base_color = [NSColor colorWithCalibratedRed:83/255.0
+ green:108.0/255.0
+ blue:140/255.0
+ alpha:1.0];
+
+ NSColor *start_color =
+ [base_color gtm_colorAdjustedFor:GTMColorationBaseMidtone
+ faded:!active];
+ NSColor *end_color =
+ [base_color gtm_colorAdjustedFor:GTMColorationBaseShadow
+ faded:!active];
+
+ if (!active) {
+ start_color = [start_color gtm_colorByAdjustingLuminance:0.1
+ saturation:0.5];
+ end_color = [end_color gtm_colorByAdjustingLuminance:0.1
+ saturation:0.5];
+ }
+
+ gradient = [[NSGradient alloc] initWithStartingColor:start_color
+ endingColor:end_color];
+ break;
+ }
+
+ case GRADIENT_TOOLBAR:
+ case GRADIENT_TOOLBAR_INACTIVE: {
+ NSColor* base_color = [NSColor colorWithCalibratedWhite:0.2 alpha:1.0];
+ BOOL faded = (id == GRADIENT_TOOLBAR_INACTIVE ) ||
+ (id == GRADIENT_TOOLBAR_BUTTON_INACTIVE);
+ NSColor* start_color =
+ [base_color gtm_colorAdjustedFor:GTMColorationLightHighlight
+ faded:faded];
+ NSColor* mid_color =
+ [base_color gtm_colorAdjustedFor:GTMColorationLightMidtone
+ faded:faded];
+ NSColor* end_color =
+ [base_color gtm_colorAdjustedFor:GTMColorationLightShadow
+ faded:faded];
+ NSColor* glow_color =
+ [base_color gtm_colorAdjustedFor:GTMColorationLightPenumbra
+ faded:faded];
+
+ gradient =
+ [[NSGradient alloc] initWithColorsAndLocations:start_color, 0.0,
+ mid_color, 0.25,
+ end_color, 0.5,
+ glow_color, 0.75,
+ nil];
+ break;
+ }
+
+ case GRADIENT_TOOLBAR_BUTTON:
+ case GRADIENT_TOOLBAR_BUTTON_INACTIVE: {
+ NSColor* start_color = [NSColor colorWithCalibratedWhite:1.0 alpha:0.0];
+ NSColor* end_color = [NSColor colorWithCalibratedWhite:1.0 alpha:0.3];
+ gradient = [[NSGradient alloc] initWithStartingColor:start_color
+ endingColor:end_color];
+ break;
+ }
+ case GRADIENT_TOOLBAR_BUTTON_PRESSED:
+ case GRADIENT_TOOLBAR_BUTTON_PRESSED_INACTIVE: {
+ NSColor* base_color = [NSColor colorWithCalibratedWhite:0.5 alpha:1.0];
+ BOOL faded = id == GRADIENT_TOOLBAR_BUTTON_PRESSED_INACTIVE;
+ NSColor* start_color =
+ [base_color gtm_colorAdjustedFor:GTMColorationBaseShadow
+ faded:faded];
+ NSColor* end_color =
+ [base_color gtm_colorAdjustedFor:GTMColorationBaseMidtone
+ faded:faded];
+
+ gradient = [[NSGradient alloc] initWithStartingColor:start_color
+ endingColor:end_color];
+ break;
+ }
+ default:
+ LOG(WARNING) << "Gradient request with unknown id " << id;
+ NOTREACHED(); // Want to assert in debug mode.
+ break;
+ }
+
+ // We loaded successfully. Cache the gradient.
+ if (gradient)
+ nsgradient_cache_[id] = gradient; // created retained
+
+ return gradient;
+}
+
+// Let all the browser views know that themes have changed in a platform way.
+void BrowserThemeProvider::NotifyPlatformThemeChanged() {
+ NSNotificationCenter* defaultCenter = [NSNotificationCenter defaultCenter];
+ [defaultCenter postNotificationName:kBrowserThemeDidChangeNotification
+ object:[NSValue valueWithPointer:this]];
+}
+
+void BrowserThemeProvider::FreePlatformCaches() {
+ DCHECK(CalledOnValidThread());
+
+ // Free images.
+ for (NSImageMap::iterator i = nsimage_cache_.begin();
+ i != nsimage_cache_.end(); i++) {
+ [i->second release];
+ }
+ nsimage_cache_.clear();
+
+ // Free colors.
+ for (NSColorMap::iterator i = nscolor_cache_.begin();
+ i != nscolor_cache_.end(); i++) {
+ [i->second.first release];
+ }
+ nscolor_cache_.clear();
+
+ // Free gradients.
+ for (NSGradientMap::iterator i = nsgradient_cache_.begin();
+ i != nsgradient_cache_.end(); i++) {
+ [i->second release];
+ }
+ nsgradient_cache_.clear();
+}