summaryrefslogtreecommitdiffstats
path: root/chrome/browser/browser_theme_provider_mac.mm
blob: 22de117784cab11c536ab905515dea13bf40bbd0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
// 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 "app/gfx/color_utils.h"
#include "base/logging.h"
#include "chrome/browser/browser_theme_pack.h"
#include "skia/ext/skia_utils_mac.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::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;
  }

  return nil;
}

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;

  CGFloat hue, saturation, brightness;
  HSLToHSB(tint, &hue, &saturation, &brightness);

  NSColor* 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;
  }

  return nil;
}

// 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();
}