summaryrefslogtreecommitdiff
path: root/chromium/components/remote_cocoa/app_shim/color_panel_bridge.mm
blob: f7f0de0bac8f9c351dd05c3a061d8dc1762b9106 (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
// 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
- (instancetype)init {
  if ((self = [super init])) {
    NSColorPanel* panel = [NSColorPanel sharedColorPanel];
    NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
    [nc addObserver:self
           selector:@selector(windowWillClose:)
               name:NSWindowWillCloseNotification
             object:panel];
    [nc addObserver:self
           selector:@selector(windowDidResignKey:)
               name:NSWindowDidResignKeyNotification
             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)windowDidResignKey:(NSNotification*)notification {
  // Close the color panel when the user clicks away.
  [self windowWillClose:notification];
  [[NSColorPanel sharedColorPanel] close];
}

- (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