Commit f987fe47 authored by Ionel Popescu's avatar Ionel Popescu Committed by Commit Bot

Add Mac support for the eye dropper.

This CL adds support for the eye dropper on Mac by using NSColorSampler.
This approach avoids the security dialog asking for more permissions.

Bug: 992297
Change-Id: Ia70d6c4daf3ec678e558ca528b63bfe960363f0f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2378773Reviewed-by: default avatarAvi Drissman <avi@chromium.org>
Reviewed-by: default avatarElly Fong-Jones <ellyjones@chromium.org>
Reviewed-by: default avatarMason Freed <masonfreed@chromium.org>
Commit-Queue: Ionel Popescu <iopopesc@microsoft.com>
Cr-Commit-Position: refs/heads/master@{#802457}
parent 666cec61
...@@ -210,6 +210,7 @@ ...@@ -210,6 +210,7 @@
#endif // OS_CHROMEOS #endif // OS_CHROMEOS
#if defined(OS_MAC) #if defined(OS_MAC)
#include "base/mac/mac_util.h"
#include "chrome/browser/ui/browser_dialogs.h" #include "chrome/browser/ui/browser_dialogs.h"
#endif // OS_MAC #endif // OS_MAC
...@@ -5364,7 +5365,7 @@ const FeatureEntry kFeatureEntries[] = { ...@@ -5364,7 +5365,7 @@ const FeatureEntry kFeatureEntries[] = {
FEATURE_VALUE_TYPE(features::kFormControlsRefresh)}, FEATURE_VALUE_TYPE(features::kFormControlsRefresh)},
{"color-picker-eye-dropper", flag_descriptions::kColorPickerEyeDropperName, {"color-picker-eye-dropper", flag_descriptions::kColorPickerEyeDropperName,
flag_descriptions::kColorPickerEyeDropperDescription, kOsWin, flag_descriptions::kColorPickerEyeDropperDescription, kOsWin | kOsMac,
FEATURE_VALUE_TYPE(features::kEyeDropper)}, FEATURE_VALUE_TYPE(features::kEyeDropper)},
#if defined(OS_CHROMEOS) #if defined(OS_CHROMEOS)
...@@ -6526,6 +6527,15 @@ bool SkipConditionalFeatureEntry(const flags_ui::FlagsStorage* storage, ...@@ -6526,6 +6527,15 @@ bool SkipConditionalFeatureEntry(const flags_ui::FlagsStorage* storage,
} }
#endif // OS_ANDROID #endif // OS_ANDROID
#if defined(OS_MAC)
// The Eye Dropper relies on the NSColorSampler API, which is available
// starting with macOS 10.15.
if (!strcmp("color-picker-eye-dropper", entry.internal_name) &&
!base::mac::IsAtLeastOS10_15()) {
return true;
}
#endif // OS_MAC
if (flags::IsFlagExpired(storage, entry.internal_name)) if (flags::IsFlagExpired(storage, entry.internal_name))
return true; return true;
......
...@@ -1287,6 +1287,8 @@ static_library("ui") { ...@@ -1287,6 +1287,8 @@ static_library("ui") {
"unload_controller.h", "unload_controller.h",
"views/eye_dropper/eye_dropper.cc", "views/eye_dropper/eye_dropper.cc",
"views/eye_dropper/eye_dropper.h", "views/eye_dropper/eye_dropper.h",
"views/eye_dropper/eye_dropper_view_mac.h",
"views/eye_dropper/eye_dropper_view_mac.mm",
"webui/app_launcher_login_handler.cc", "webui/app_launcher_login_handler.cc",
"webui/app_launcher_login_handler.h", "webui/app_launcher_login_handler.h",
"webui/app_management/app_management_page_handler.cc", "webui/app_management/app_management_page_handler.cc",
...@@ -3023,8 +3025,6 @@ static_library("ui") { ...@@ -3023,8 +3025,6 @@ static_library("ui") {
"views/color_chooser_win.cc", "views/color_chooser_win.cc",
"views/critical_notification_bubble_view.cc", "views/critical_notification_bubble_view.cc",
"views/critical_notification_bubble_view.h", "views/critical_notification_bubble_view.h",
"views/eye_dropper/eye_dropper_win.cc",
"views/eye_dropper/eye_dropper_win.h",
"views/frame/browser_desktop_window_tree_host.h", "views/frame/browser_desktop_window_tree_host.h",
"views/frame/browser_desktop_window_tree_host_win.cc", "views/frame/browser_desktop_window_tree_host_win.cc",
"views/frame/browser_desktop_window_tree_host_win.h", "views/frame/browser_desktop_window_tree_host_win.h",
...@@ -4159,6 +4159,8 @@ static_library("ui") { ...@@ -4159,6 +4159,8 @@ static_library("ui") {
"views/apps/shaped_app_window_targeter.cc", "views/apps/shaped_app_window_targeter.cc",
"views/apps/shaped_app_window_targeter.h", "views/apps/shaped_app_window_targeter.h",
"views/dropdown_bar_host_aura.cc", "views/dropdown_bar_host_aura.cc",
"views/eye_dropper/eye_dropper_view_aura.cc",
"views/eye_dropper/eye_dropper_view_aura.h",
"views/renderer_context_menu/render_view_context_menu_views.cc", "views/renderer_context_menu/render_view_context_menu_views.cc",
"views/renderer_context_menu/render_view_context_menu_views.h", "views/renderer_context_menu/render_view_context_menu_views.h",
"views/tab_contents/chrome_web_contents_view_delegate_views.cc", "views/tab_contents/chrome_web_contents_view_delegate_views.cc",
......
...@@ -7,11 +7,11 @@ ...@@ -7,11 +7,11 @@
#include "build/build_config.h" #include "build/build_config.h"
#include "content/public/browser/eye_dropper.h" #include "content/public/browser/eye_dropper.h"
#if !defined(OS_WIN) #if !defined(USE_AURA) && !defined(OS_MAC)
// Used for the platforms that don't support an eye dropper. // Used for the platforms that don't support an eye dropper.
std::unique_ptr<content::EyeDropper> ShowEyeDropper( std::unique_ptr<content::EyeDropper> ShowEyeDropper(
content::RenderFrameHost* frame, content::RenderFrameHost* frame,
content::EyeDropperListener* listener) { content::EyeDropperListener* listener) {
return nullptr; return nullptr;
} }
#endif // !defined(OS_WIN) #endif // !defined(USE_AURA) && !defined(OS_MAC)
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
#include "ui/display/display_switches.h" #include "ui/display/display_switches.h"
#if defined(OS_WIN) #if defined(OS_WIN)
#include "chrome/browser/ui/views/eye_dropper/eye_dropper_win.h" #include "chrome/browser/ui/views/eye_dropper/eye_dropper_view_aura.h"
#endif #endif
class EyeDropperBrowserTest : public UiBrowserTest, class EyeDropperBrowserTest : public UiBrowserTest,
...@@ -33,9 +33,11 @@ class EyeDropperBrowserTest : public UiBrowserTest, ...@@ -33,9 +33,11 @@ class EyeDropperBrowserTest : public UiBrowserTest,
// UiBrowserTest: // UiBrowserTest:
void ShowUi(const std::string& name) override { void ShowUi(const std::string& name) override {
#if defined(OS_WIN)
content::RenderFrameHost* parent_frame = content::RenderFrameHost* parent_frame =
browser()->tab_strip_model()->GetActiveWebContents()->GetMainFrame(); browser()->tab_strip_model()->GetActiveWebContents()->GetMainFrame();
eye_dropper_ = ShowEyeDropper(parent_frame, /*listener=*/nullptr); eye_dropper_ = ShowEyeDropper(parent_frame, /*listener=*/nullptr);
#endif
} }
bool VerifyUi() override { bool VerifyUi() override {
...@@ -44,7 +46,7 @@ class EyeDropperBrowserTest : public UiBrowserTest, ...@@ -44,7 +46,7 @@ class EyeDropperBrowserTest : public UiBrowserTest,
return false; return false;
views::Widget* widget = views::Widget* widget =
static_cast<EyeDropperWin*>(eye_dropper_.get())->GetWidget(); static_cast<EyeDropperViewAura*>(eye_dropper_.get())->GetWidget();
auto* test_info = testing::UnitTest::GetInstance()->current_test_info(); auto* test_info = testing::UnitTest::GetInstance()->current_test_info();
const std::string screenshot_name = const std::string screenshot_name =
base::StrCat({test_info->test_case_name(), "_", test_info->name()}); base::StrCat({test_info->test_case_name(), "_", test_info->name()});
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include "chrome/browser/ui/views/eye_dropper/eye_dropper_win.h" #include "chrome/browser/ui/views/eye_dropper/eye_dropper_view_aura.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "chrome/browser/ui/views/eye_dropper/eye_dropper.h" #include "chrome/browser/ui/views/eye_dropper/eye_dropper.h"
...@@ -19,9 +19,9 @@ ...@@ -19,9 +19,9 @@
#include "ui/gfx/native_widget_types.h" #include "ui/gfx/native_widget_types.h"
#include "ui/views/widget/widget.h" #include "ui/views/widget/widget.h"
class EyeDropperWin::PreEventDispatchHandler : public ui::EventHandler { class EyeDropperViewAura::PreEventDispatchHandler : public ui::EventHandler {
public: public:
explicit PreEventDispatchHandler(aura::Window* owner, EyeDropperWin* view); explicit PreEventDispatchHandler(EyeDropperViewAura* view);
PreEventDispatchHandler(const PreEventDispatchHandler&) = delete; PreEventDispatchHandler(const PreEventDispatchHandler&) = delete;
PreEventDispatchHandler& operator=(const PreEventDispatchHandler&) = delete; PreEventDispatchHandler& operator=(const PreEventDispatchHandler&) = delete;
~PreEventDispatchHandler() override; ~PreEventDispatchHandler() override;
...@@ -29,35 +29,37 @@ class EyeDropperWin::PreEventDispatchHandler : public ui::EventHandler { ...@@ -29,35 +29,37 @@ class EyeDropperWin::PreEventDispatchHandler : public ui::EventHandler {
private: private:
void OnMouseEvent(ui::MouseEvent* event) override; void OnMouseEvent(ui::MouseEvent* event) override;
aura::Window* owner_; EyeDropperViewAura* view_;
EyeDropperWin* view_;
}; };
EyeDropperWin::PreEventDispatchHandler::PreEventDispatchHandler( EyeDropperViewAura::PreEventDispatchHandler::PreEventDispatchHandler(
aura::Window* owner, EyeDropperViewAura* view)
EyeDropperWin* view) : view_(view) {
: owner_(owner), view_(view) {
// Ensure that this handler is called before color popup handler by using // Ensure that this handler is called before color popup handler by using
// a higher priority. // a higher priority.
owner_->AddPreTargetHandler(this, ui::EventTarget::Priority::kSystem); view->GetWidget()->GetNativeWindow()->AddPreTargetHandler(
this, ui::EventTarget::Priority::kSystem);
} }
EyeDropperWin::PreEventDispatchHandler::~PreEventDispatchHandler() { EyeDropperViewAura::PreEventDispatchHandler::~PreEventDispatchHandler() {
owner_->RemovePreTargetHandler(this); view_->GetWidget()->GetNativeWindow()->RemovePreTargetHandler(this);
} }
void EyeDropperWin::PreEventDispatchHandler::OnMouseEvent( void EyeDropperViewAura::PreEventDispatchHandler::OnMouseEvent(
ui::MouseEvent* event) { ui::MouseEvent* event) {
if (event->type() == ui::ET_MOUSE_PRESSED) { if (event->type() == ui::ET_MOUSE_PRESSED) {
// Avoid closing the color popup when the eye dropper is clicked. // Avoid closing the color popup when the eye dropper is clicked.
event->StopPropagation();
}
if (event->type() == ui::ET_MOUSE_RELEASED) {
view_->OnColorSelected(); view_->OnColorSelected();
event->StopPropagation(); event->StopPropagation();
} }
} }
class EyeDropperWin::ViewPositionHandler { class EyeDropperViewAura::ViewPositionHandler {
public: public:
explicit ViewPositionHandler(EyeDropperWin* owner); explicit ViewPositionHandler(EyeDropperViewAura* owner);
ViewPositionHandler(const ViewPositionHandler&) = delete; ViewPositionHandler(const ViewPositionHandler&) = delete;
ViewPositionHandler& operator=(const ViewPositionHandler&) = delete; ViewPositionHandler& operator=(const ViewPositionHandler&) = delete;
~ViewPositionHandler(); ~ViewPositionHandler();
...@@ -68,27 +70,29 @@ class EyeDropperWin::ViewPositionHandler { ...@@ -68,27 +70,29 @@ class EyeDropperWin::ViewPositionHandler {
// Timer used for updating the window location. // Timer used for updating the window location.
base::RepeatingTimer timer_; base::RepeatingTimer timer_;
EyeDropperWin* owner_; EyeDropperViewAura* owner_;
}; };
EyeDropperWin::ViewPositionHandler::ViewPositionHandler(EyeDropperWin* owner) EyeDropperViewAura::ViewPositionHandler::ViewPositionHandler(
EyeDropperViewAura* owner)
: owner_(owner) { : owner_(owner) {
// Use a value close to the refresh rate @60hz. // Use a value close to the refresh rate @60hz.
// TODO(iopopesc): Use SetCapture instead of a timer when support for // TODO(iopopesc): Use SetCapture instead of a timer when support for
// activating the eye dropper without closing the color popup is added. // activating the eye dropper without closing the color popup is added.
timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(16), this, timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(16), this,
&EyeDropperWin::ViewPositionHandler::UpdateViewPosition); &EyeDropperViewAura::ViewPositionHandler::UpdateViewPosition);
} }
EyeDropperWin::ViewPositionHandler::~ViewPositionHandler() { EyeDropperViewAura::ViewPositionHandler::~ViewPositionHandler() {
timer_.AbandonAndStop(); timer_.AbandonAndStop();
} }
void EyeDropperWin::ViewPositionHandler::UpdateViewPosition() { void EyeDropperViewAura::ViewPositionHandler::UpdateViewPosition() {
owner_->UpdatePosition(); owner_->UpdatePosition();
} }
class EyeDropperWin::ScreenCapturer : public webrtc::DesktopCapturer::Callback { class EyeDropperViewAura::ScreenCapturer
: public webrtc::DesktopCapturer::Callback {
public: public:
ScreenCapturer(); ScreenCapturer();
ScreenCapturer(const ScreenCapturer&) = delete; ScreenCapturer(const ScreenCapturer&) = delete;
...@@ -106,7 +110,7 @@ class EyeDropperWin::ScreenCapturer : public webrtc::DesktopCapturer::Callback { ...@@ -106,7 +110,7 @@ class EyeDropperWin::ScreenCapturer : public webrtc::DesktopCapturer::Callback {
SkBitmap frame_; SkBitmap frame_;
}; };
EyeDropperWin::ScreenCapturer::ScreenCapturer() { EyeDropperViewAura::ScreenCapturer::ScreenCapturer() {
// TODO(iopopesc): Update the captured frame after a period of time to match // TODO(iopopesc): Update the captured frame after a period of time to match
// latest content on screen. // latest content on screen.
capturer_ = content::desktop_capture::CreateScreenCapturer(); capturer_ = content::desktop_capture::CreateScreenCapturer();
...@@ -114,7 +118,7 @@ EyeDropperWin::ScreenCapturer::ScreenCapturer() { ...@@ -114,7 +118,7 @@ EyeDropperWin::ScreenCapturer::ScreenCapturer() {
capturer_->CaptureFrame(); capturer_->CaptureFrame();
} }
void EyeDropperWin::ScreenCapturer::OnCaptureResult( void EyeDropperViewAura::ScreenCapturer::OnCaptureResult(
webrtc::DesktopCapturer::Result result, webrtc::DesktopCapturer::Result result,
std::unique_ptr<webrtc::DesktopFrame> frame) { std::unique_ptr<webrtc::DesktopFrame> frame) {
if (result != webrtc::DesktopCapturer::Result::SUCCESS) if (result != webrtc::DesktopCapturer::Result::SUCCESS)
...@@ -126,12 +130,12 @@ void EyeDropperWin::ScreenCapturer::OnCaptureResult( ...@@ -126,12 +130,12 @@ void EyeDropperWin::ScreenCapturer::OnCaptureResult(
frame_.setImmutable(); frame_.setImmutable();
} }
SkBitmap EyeDropperWin::ScreenCapturer::GetBitmap() const { SkBitmap EyeDropperViewAura::ScreenCapturer::GetBitmap() const {
return frame_; return frame_;
} }
EyeDropperWin::EyeDropperWin(content::RenderFrameHost* frame, EyeDropperViewAura::EyeDropperViewAura(content::RenderFrameHost* frame,
content::EyeDropperListener* listener) content::EyeDropperListener* listener)
: render_frame_host_(frame), : render_frame_host_(frame),
listener_(listener), listener_(listener),
view_position_handler_(std::make_unique<ViewPositionHandler>(this)), view_position_handler_(std::make_unique<ViewPositionHandler>(this)),
...@@ -154,8 +158,7 @@ EyeDropperWin::EyeDropperWin(content::RenderFrameHost* frame, ...@@ -154,8 +158,7 @@ EyeDropperWin::EyeDropperWin(content::RenderFrameHost* frame,
widget->Init(std::move(params)); widget->Init(std::move(params));
widget->SetContentsView(this); widget->SetContentsView(this);
pre_dispatch_handler_ = std::make_unique<PreEventDispatchHandler>( pre_dispatch_handler_ = std::make_unique<PreEventDispatchHandler>(this);
widget->GetNativeWindow(), this);
auto* cursor_client = auto* cursor_client =
aura::client::GetCursorClient(widget->GetNativeWindow()->GetRootWindow()); aura::client::GetCursorClient(widget->GetNativeWindow()->GetRootWindow());
...@@ -164,21 +167,21 @@ EyeDropperWin::EyeDropperWin(content::RenderFrameHost* frame, ...@@ -164,21 +167,21 @@ EyeDropperWin::EyeDropperWin(content::RenderFrameHost* frame,
widget->Show(); widget->Show();
} }
EyeDropperWin::~EyeDropperWin() { EyeDropperViewAura::~EyeDropperViewAura() {
if (GetWidget()) if (GetWidget())
GetWidget()->CloseNow(); GetWidget()->CloseNow();
} }
void EyeDropperWin::OnPaint(gfx::Canvas* view_canvas) { void EyeDropperViewAura::OnPaint(gfx::Canvas* view_canvas) {
if (screen_capturer_->GetBitmap().drawsNothing()) if (screen_capturer_->GetBitmap().drawsNothing())
return; return;
constexpr float kDiameter = 90; constexpr float kDiameter = 90;
constexpr float kPixelSize = 10; constexpr float kPixelSize = 10;
// Clip circle for magnified projection.
const gfx::Size padding((size().width() - kDiameter) / 2, const gfx::Size padding((size().width() - kDiameter) / 2,
(size().height() - kDiameter) / 2); (size().height() - kDiameter) / 2);
// Clip circle for magnified projection.
SkPath clip_path; SkPath clip_path;
clip_path.addOval(SkRect::MakeXYWH(padding.width(), padding.height(), clip_path.addOval(SkRect::MakeXYWH(padding.width(), padding.height(),
kDiameter, kDiameter)); kDiameter, kDiameter));
...@@ -240,23 +243,23 @@ void EyeDropperWin::OnPaint(gfx::Canvas* view_canvas) { ...@@ -240,23 +243,23 @@ void EyeDropperWin::OnPaint(gfx::Canvas* view_canvas) {
OnPaintBorder(view_canvas); OnPaintBorder(view_canvas);
} }
void EyeDropperWin::WindowClosing() { void EyeDropperViewAura::WindowClosing() {
aura::client::GetCursorClient(GetWidget()->GetNativeWindow()->GetRootWindow()) aura::client::GetCursorClient(GetWidget()->GetNativeWindow()->GetRootWindow())
->UnlockCursor(); ->UnlockCursor();
pre_dispatch_handler_.reset(); pre_dispatch_handler_.reset();
} }
ui::ModalType EyeDropperWin::GetModalType() const { ui::ModalType EyeDropperViewAura::GetModalType() const {
return ui::MODAL_TYPE_SYSTEM; return ui::MODAL_TYPE_SYSTEM;
} }
void EyeDropperWin::OnWidgetMove() { void EyeDropperViewAura::OnWidgetMove() {
// Trigger a repaint since because the widget was moved, the content of the // Trigger a repaint since because the widget was moved, the content of the
// view needs to be updated. // view needs to be updated.
SchedulePaint(); SchedulePaint();
} }
void EyeDropperWin::UpdatePosition() { void EyeDropperViewAura::UpdatePosition() {
if (screen_capturer_->GetBitmap().drawsNothing() || !GetWidget()) if (screen_capturer_->GetBitmap().drawsNothing() || !GetWidget())
return; return;
...@@ -271,7 +274,7 @@ void EyeDropperWin::UpdatePosition() { ...@@ -271,7 +274,7 @@ void EyeDropperWin::UpdatePosition() {
size())); size()));
} }
void EyeDropperWin::OnColorSelected() { void EyeDropperViewAura::OnColorSelected() {
if (!selected_color_.has_value()) { if (!selected_color_.has_value()) {
listener_->ColorSelectionCanceled(); listener_->ColorSelectionCanceled();
return; return;
...@@ -284,5 +287,5 @@ void EyeDropperWin::OnColorSelected() { ...@@ -284,5 +287,5 @@ void EyeDropperWin::OnColorSelected() {
std::unique_ptr<content::EyeDropper> ShowEyeDropper( std::unique_ptr<content::EyeDropper> ShowEyeDropper(
content::RenderFrameHost* frame, content::RenderFrameHost* frame,
content::EyeDropperListener* listener) { content::EyeDropperListener* listener) {
return std::make_unique<EyeDropperWin>(frame, listener); return std::make_unique<EyeDropperViewAura>(frame, listener);
} }
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#ifndef CHROME_BROWSER_UI_VIEWS_EYE_DROPPER_EYE_DROPPER_WIN_H_ #ifndef CHROME_BROWSER_UI_VIEWS_EYE_DROPPER_EYE_DROPPER_VIEW_AURA_H_
#define CHROME_BROWSER_UI_VIEWS_EYE_DROPPER_EYE_DROPPER_WIN_H_ #define CHROME_BROWSER_UI_VIEWS_EYE_DROPPER_EYE_DROPPER_VIEW_AURA_H_
#include <memory> #include <memory>
...@@ -15,14 +15,14 @@ ...@@ -15,14 +15,14 @@
#include "ui/gfx/geometry/point.h" #include "ui/gfx/geometry/point.h"
#include "ui/views/widget/widget_delegate.h" #include "ui/views/widget/widget_delegate.h"
class EyeDropperWin : public content::EyeDropper, class EyeDropperViewAura : public content::EyeDropper,
public views::WidgetDelegateView { public views::WidgetDelegateView {
public: public:
EyeDropperWin(content::RenderFrameHost* frame, EyeDropperViewAura(content::RenderFrameHost* frame,
content::EyeDropperListener* listener); content::EyeDropperListener* listener);
EyeDropperWin(const EyeDropperWin&) = delete; EyeDropperViewAura(const EyeDropperViewAura&) = delete;
EyeDropperWin& operator=(const EyeDropperWin&) = delete; EyeDropperViewAura& operator=(const EyeDropperViewAura&) = delete;
~EyeDropperWin() override; ~EyeDropperViewAura() override;
protected: protected:
// views::WidgetDelegateView: // views::WidgetDelegateView:
...@@ -53,4 +53,4 @@ class EyeDropperWin : public content::EyeDropper, ...@@ -53,4 +53,4 @@ class EyeDropperWin : public content::EyeDropper,
base::Optional<SkColor> selected_color_; base::Optional<SkColor> selected_color_;
}; };
#endif // CHROME_BROWSER_UI_VIEWS_EYE_DROPPER_EYE_DROPPER_WIN_H_ #endif // CHROME_BROWSER_UI_VIEWS_EYE_DROPPER_EYE_DROPPER_VIEW_AURA_H_
// Copyright 2020 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.
#ifndef CHROME_BROWSER_UI_VIEWS_EYE_DROPPER_EYE_DROPPER_VIEW_MAC_H_
#define CHROME_BROWSER_UI_VIEWS_EYE_DROPPER_EYE_DROPPER_VIEW_MAC_H_
#include "base/mac/scoped_nsobject.h"
#include "content/public/browser/eye_dropper.h"
#include "content/public/browser/eye_dropper_listener.h"
@class NSColorSampler;
class EyeDropperViewMac : public content::EyeDropper {
public:
EyeDropperViewMac(content::EyeDropperListener* listener);
EyeDropperViewMac(const EyeDropperViewMac&) = delete;
EyeDropperViewMac& operator=(const EyeDropperViewMac&) = delete;
~EyeDropperViewMac() override;
private:
// Receives the color selection.
content::EyeDropperListener* listener_;
base::scoped_nsobject<NSColorSampler> color_sampler_;
};
#endif // CHROME_BROWSER_UI_VIEWS_EYE_DROPPER_EYE_DROPPER_VIEW_MAC_H_
// Copyright 2020 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/ui/views/eye_dropper/eye_dropper_view_mac.h"
#import <Cocoa/Cocoa.h>
#include "content/public/browser/render_frame_host.h"
#include "skia/ext/skia_utils_mac.h"
EyeDropperViewMac::EyeDropperViewMac(content::EyeDropperListener* listener)
: listener_(listener) {
if (!listener_)
return;
if (@available(macOS 10.15, *)) {
color_sampler_.reset([[NSColorSampler alloc] init]);
[color_sampler_ showSamplerWithSelectionHandler:^(NSColor* selectedColor) {
if (!selectedColor) {
listener_->ColorSelectionCanceled();
} else {
listener_->ColorSelected(skia::NSSystemColorToSkColor(selectedColor));
}
}];
}
}
EyeDropperViewMac::~EyeDropperViewMac() {}
std::unique_ptr<content::EyeDropper> ShowEyeDropper(
content::RenderFrameHost* frame,
content::EyeDropperListener* listener) {
if (@available(macOS 10.15, *)) {
return std::make_unique<EyeDropperViewMac>(listener);
}
return nullptr;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment