blob: e7cdab7a23d96345cc6e8ec578a8616d132b7d51 [file] [log] [blame]
// Copyright (c) 2012 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.
#import "chrome/browser/ui/cocoa/color_chooser_mac.h"
#include "base/logging.h"
#include "chrome/browser/ui/color_chooser.h"
#include "skia/ext/skia_utils_mac.h"
ColorChooserMac* ColorChooserMac::current_color_chooser_ = NULL;
// static
ColorChooserMac* ColorChooserMac::Open(content::WebContents* web_contents,
SkColor initial_color) {
if (current_color_chooser_)
current_color_chooser_->End();
DCHECK(!current_color_chooser_);
current_color_chooser_ =
new ColorChooserMac(web_contents, initial_color);
return current_color_chooser_;
}
ColorChooserMac::ColorChooserMac(content::WebContents* web_contents,
SkColor initial_color)
: web_contents_(web_contents) {
panel_.reset([[ColorPanelCocoa alloc] initWithChooser:this]);
[panel_ setColor:skia::SkColorToDeviceNSColor(initial_color)];
[[NSColorPanel sharedColorPanel] makeKeyAndOrderFront:nil];
}
ColorChooserMac::~ColorChooserMac() {
// Always call End() before destroying.
DCHECK(!panel_);
}
void ColorChooserMac::DidChooseColorInColorPanel(SkColor color) {
if (web_contents_)
web_contents_->DidChooseColorInColorChooser(color);
}
void ColorChooserMac::DidCloseColorPanel() {
End();
}
void ColorChooserMac::End() {
if (panel_) {
panel_.reset();
DCHECK(current_color_chooser_ == this);
current_color_chooser_ = NULL;
if (web_contents_)
web_contents_->DidEndColorChooser();
}
}
void ColorChooserMac::SetSelectedColor(SkColor color) {
[panel_ setColor:skia::SkColorToDeviceNSColor(color)];
}
@interface NSColorPanel (Private)
// Private method returning the NSColorPanel's target.
- (id)__target;
@end
@implementation ColorPanelCocoa
- (id)initWithChooser:(ColorChooserMac*)chooser {
if ((self = [super init])) {
chooser_ = chooser;
NSColorPanel* panel = [NSColorPanel sharedColorPanel];
[panel setShowsAlpha:NO];
[panel setTarget:self];
[panel setAction:@selector(didChooseColor:)];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(windowWillClose:)
name:NSWindowWillCloseNotification
object:panel];
}
return self;
}
- (void)dealloc {
NSColorPanel* panel = [NSColorPanel sharedColorPanel];
// On macOS 10.13 the NSColorPanel delegate can apparently get reset to nil
// with the target left unchanged. Use the private __target method to see if
// the ColorPanelCocoa is still the target.
BOOL respondsToPrivateTargetMethod =
[panel respondsToSelector:@selector(__target)];
if (respondsToPrivateTargetMethod && [panel __target] == self) {
[panel setTarget:nil];
[panel setAction:nullptr];
}
[[NSNotificationCenter defaultCenter]
removeObserver:self
name:NSWindowWillCloseNotification
object:panel];
[super dealloc];
}
- (void)windowWillClose:(NSNotification*)notification {
chooser_->DidCloseColorPanel();
nonUserChange_ = NO;
}
- (void)didChooseColor:(NSColorPanel*)panel {
if (nonUserChange_) {
nonUserChange_ = NO;
return;
}
nonUserChange_ = NO;
NSColor* color = [panel color];
if ([[color colorSpaceName] isEqualToString:NSNamedColorSpace]) {
color = [color colorUsingColorSpace:[NSColorSpace genericRGBColorSpace]];
// Some colors in "Developer" palette in "Color Palettes" tab can't be
// converted to RGB. We just ignore such colors.
// TODO(tkent): We should notice the rejection to users.
if (!color)
return;
}
if ([color colorSpace] == [NSColorSpace genericRGBColorSpace]) {
// genericRGB -> deviceRGB conversion isn't ignorable. We'd like to use RGB
// values shown in NSColorPanel UI.
CGFloat red, green, blue, alpha;
[color getRed:&red green:&green blue:&blue alpha:&alpha];
SkColor skColor = SkColorSetARGB(SkScalarRoundToInt(255.0 * alpha),
SkScalarRoundToInt(255.0 * red),
SkScalarRoundToInt(255.0 * green),
SkScalarRoundToInt(255.0 * blue));
chooser_->DidChooseColorInColorPanel(skColor);
} else {
chooser_->DidChooseColorInColorPanel(skia::NSDeviceColorToSkColor(
[[panel color] colorUsingColorSpaceName:NSDeviceRGBColorSpace]));
}
}
- (void)setColor:(NSColor*)color {
nonUserChange_ = YES;
[[NSColorPanel sharedColorPanel] setColor:color];
}
namespace chrome {
content::ColorChooser* ShowColorChooser(content::WebContents* web_contents,
SkColor initial_color) {
return ColorChooserMac::Open(web_contents, initial_color);
}
} // namepace chrome
@end