blob: eb2a87c5751e5522ffede7eb5a1e11a9cd65fbae [file] [log] [blame]
// Copyright 2019 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 "components/remote_cocoa/app_shim/color_panel_bridge.h"
#import <Cocoa/Cocoa.h>
#include "skia/ext/skia_utils_mac.h"
namespace {
// The currently active bridge, to which the ColorPanelListener will forward
// its observations.
remote_cocoa::ColorPanelBridge* g_current_panel_bridge = nullptr;
} // namespace
// A singleton listener class to act as a event target for NSColorPanel and
// send the results to the C++ class, ColorPanelBridge.
@interface ColorPanelListener : NSObject {
@protected
// We don't call DidChooseColor if the change wasn't caused by the user
// interacting with the panel.
BOOL nonUserChange_;
}
// Called from NSNotificationCenter.
- (void)windowWillClose:(NSNotification*)notification;
// Called from NSColorPanel.
- (void)didChooseColor:(NSColorPanel*)panel;
// The singleton instance.
+ (ColorPanelListener*)instance;
// Show the NSColorPanel.
- (void)showColorPanel;
// Sets color to the NSColorPanel as a non user change.
- (void)setColor:(NSColor*)color;
@end
@implementation ColorPanelListener
- (id)init {
if ((self = [super init])) {
NSColorPanel* panel = [NSColorPanel sharedColorPanel];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(windowWillClose:)
name:NSWindowWillCloseNotification
object:panel];
}
return self;
}
- (void)dealloc {
// This object is never freed.
NOTREACHED();
[super dealloc];
}
- (void)windowWillClose:(NSNotification*)notification {
if (g_current_panel_bridge)
g_current_panel_bridge->host()->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;
}
SkColor skColor = 0;
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 = SkColorSetARGB(
SkScalarRoundToInt(255.0 * alpha), SkScalarRoundToInt(255.0 * red),
SkScalarRoundToInt(255.0 * green), SkScalarRoundToInt(255.0 * blue));
} else {
skColor = skia::NSDeviceColorToSkColor(
[[panel color] colorUsingColorSpaceName:NSDeviceRGBColorSpace]);
}
if (g_current_panel_bridge)
g_current_panel_bridge->host()->DidChooseColorInColorPanel(skColor);
}
+ (ColorPanelListener*)instance {
static ColorPanelListener* listener = [[ColorPanelListener alloc] init];
return listener;
}
- (void)showColorPanel {
NSColorPanel* panel = [NSColorPanel sharedColorPanel];
[panel setShowsAlpha:NO];
[panel setTarget:self];
[panel setAction:@selector(didChooseColor:)];
[panel makeKeyAndOrderFront:nil];
}
- (void)setColor:(NSColor*)color {
nonUserChange_ = YES;
[[NSColorPanel sharedColorPanel] setColor:color];
}
@end
namespace remote_cocoa {
ColorPanelBridge::ColorPanelBridge(
mojo::PendingRemote<mojom::ColorPanelHost> host)
: host_(std::move(host)) {
g_current_panel_bridge = this;
}
ColorPanelBridge::~ColorPanelBridge() {
if (g_current_panel_bridge == this)
g_current_panel_bridge = nullptr;
}
void ColorPanelBridge::Show(uint32_t initial_color) {
ColorPanelListener* listener = [ColorPanelListener instance];
[listener setColor:skia::SkColorToDeviceNSColor(initial_color)];
[listener showColorPanel];
}
void ColorPanelBridge::SetSelectedColor(uint32_t color) {
ColorPanelListener* listener = [ColorPanelListener instance];
[listener setColor:skia::SkColorToDeviceNSColor(color)];
}
} // namespace remote_cocoa