summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/app/generated_resources.grd5
-rw-r--r--chrome/browser/ui/android/color_chooser_android.cc14
-rw-r--r--chrome/browser/ui/base_shell_dialog.h26
-rw-r--r--chrome/browser/ui/browser.cc23
-rw-r--r--chrome/browser/ui/browser.h9
-rw-r--r--chrome/browser/ui/cocoa/color_chooser_mac.mm138
-rw-r--r--chrome/browser/ui/gtk/color_chooser_gtk.cc114
-rw-r--r--chrome/browser/ui/select_file_dialog.h16
-rw-r--r--chrome/browser/ui/views/ash/color_chooser_aura.cc14
-rw-r--r--chrome/browser/ui/views/base_shell_dialog_win.cc104
-rw-r--r--chrome/browser/ui/views/base_shell_dialog_win.h93
-rw-r--r--chrome/browser/ui/views/color_chooser_dialog.cc81
-rw-r--r--chrome/browser/ui/views/color_chooser_dialog.h79
-rw-r--r--chrome/browser/ui/views/color_chooser_win.cc71
-rw-r--r--chrome/browser/ui/views/select_file_dialog_win.cc164
-rw-r--r--chrome/chrome_browser.gypi11
-rw-r--r--content/browser/tab_contents/tab_contents.cc43
-rw-r--r--content/browser/tab_contents/tab_contents.h12
-rw-r--r--content/common/view_messages.h19
-rw-r--r--content/content_browser.gypi1
-rw-r--r--content/content_renderer.gypi2
-rw-r--r--content/public/browser/color_chooser.h47
-rw-r--r--content/public/browser/web_contents.h8
-rw-r--r--content/public/browser/web_contents_delegate.cc6
-rw-r--r--content/public/browser/web_contents_delegate.h9
-rw-r--r--content/renderer/render_view_impl.cc10
-rw-r--r--content/renderer/render_view_impl.h3
-rw-r--r--content/renderer/renderer_webcolorchooser_impl.cc70
-rw-r--r--content/renderer/renderer_webcolorchooser_impl.h50
-rw-r--r--skia/ext/skia_utils_mac.h5
-rw-r--r--skia/ext/skia_utils_mac.mm20
31 files changed, 1088 insertions, 179 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index a6bcd76..1805d05 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -11786,6 +11786,11 @@ Some features may be unavailable. Please check that the profile exists and you
</message>
</if>
+ <!-- Color chooser dialog default titles (only used on Linux) -->
+ <message name="IDS_SELECT_COLOR_DIALOG_TITLE" desc="The default title for the Select Color color chooser dialog.">
+ Select Color
+ </message>
+
<!-- File chooser dialog default titles (only used on Linux) -->
<message name="IDS_SELECT_FOLDER_DIALOG_TITLE" desc="The default title for the Select Folder file chooser dialog.">
Select Folder
diff --git a/chrome/browser/ui/android/color_chooser_android.cc b/chrome/browser/ui/android/color_chooser_android.cc
new file mode 100644
index 0000000..b108796
--- /dev/null
+++ b/chrome/browser/ui/android/color_chooser_android.cc
@@ -0,0 +1,14 @@
+// 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.
+
+#include "content/public/browser/color_chooser.h"
+
+#include "base/logging.h"
+
+// static
+content::ColorChooser* content::ColorChooser::Create(
+ int identifier, content::WebContents* tab, SkColor initial_color) {
+ NOTIMPLEMENTED();
+ return NULL;
+}
diff --git a/chrome/browser/ui/base_shell_dialog.h b/chrome/browser/ui/base_shell_dialog.h
new file mode 100644
index 0000000..4a5a99c
--- /dev/null
+++ b/chrome/browser/ui/base_shell_dialog.h
@@ -0,0 +1,26 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_BASE_SHELL_DIALOG_H_
+#define CHROME_BROWSER_UI_BASE_SHELL_DIALOG_H_
+#pragma once
+
+#include "ui/gfx/native_widget_types.h"
+
+// A base class for shell dialogs.
+class BaseShellDialog {
+ public:
+ // Returns true if a shell dialog box is currently being shown modally
+ // to the specified owner.
+ virtual bool IsRunning(gfx::NativeWindow owning_window) const = 0;
+
+ // Notifies the dialog box that the listener has been destroyed and it should
+ // no longer be sent notifications.
+ virtual void ListenerDestroyed() = 0;
+
+ protected:
+ virtual ~BaseShellDialog() {}
+};
+
+#endif // CHROME_BROWSER_UI_BASE_SHELL_DIALOG_H_
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc
index a229eca..7bbb85d 100644
--- a/chrome/browser/ui/browser.cc
+++ b/chrome/browser/ui/browser.cc
@@ -149,6 +149,7 @@
#include "chrome/common/profiling.h"
#include "chrome/common/url_constants.h"
#include "chrome/common/web_apps.h"
+#include "content/public/browser/color_chooser.h"
#include "content/public/browser/devtools_manager.h"
#include "content/public/browser/download_item.h"
#include "content/public/browser/download_manager.h"
@@ -4136,6 +4137,28 @@ content::JavaScriptDialogCreator* Browser::GetJavaScriptDialogCreator() {
return GetJavaScriptDialogCreatorInstance();
}
+content::ColorChooser* Browser::OpenColorChooser(WebContents* tab,
+ int color_chooser_id,
+ const SkColor& color) {
+#if defined(OS_WIN)
+ // On Windows, only create a color chooser if one doesn't exist, because we
+ // can't close the old color chooser dialog.
+ if (!color_chooser_.get())
+ color_chooser_.reset(content::ColorChooser::Create(color_chooser_id, tab,
+ color));
+#else
+ if (color_chooser_.get())
+ color_chooser_->End();
+ color_chooser_.reset(content::ColorChooser::Create(color_chooser_id, tab,
+ color));
+#endif
+ return color_chooser_.get();
+}
+
+void Browser::DidEndColorChooser() {
+ color_chooser_.reset();
+}
+
void Browser::RunFileChooser(WebContents* tab,
const content::FileChooserParams& params) {
RunFileChooserHelper(tab, params);
diff --git a/chrome/browser/ui/browser.h b/chrome/browser/ui/browser.h
index 67755e6..c32d58c 100644
--- a/chrome/browser/ui/browser.h
+++ b/chrome/browser/ui/browser.h
@@ -1024,6 +1024,11 @@ class Browser : public TabHandlerDelegate,
virtual void DidNavigateToPendingEntry(content::WebContents* tab) OVERRIDE;
virtual content::JavaScriptDialogCreator*
GetJavaScriptDialogCreator() OVERRIDE;
+ virtual content::ColorChooser* OpenColorChooser(
+ content::WebContents* tab,
+ int color_chooser_id,
+ const SkColor& color) OVERRIDE;
+ virtual void DidEndColorChooser() OVERRIDE;
virtual void RunFileChooser(
content::WebContents* tab,
const content::FileChooserParams& params) OVERRIDE;
@@ -1474,6 +1479,10 @@ class Browser : public TabHandlerDelegate,
// True if the browser window has been shown at least once.
bool window_has_shown_;
+ // Currently open color chooser. Non-NULL after OpenColorChooser is called and
+ // before DidEndColorChooser is called.
+ scoped_ptr<content::ColorChooser> color_chooser_;
+
DISALLOW_COPY_AND_ASSIGN(Browser);
};
diff --git a/chrome/browser/ui/cocoa/color_chooser_mac.mm b/chrome/browser/ui/cocoa/color_chooser_mac.mm
new file mode 100644
index 0000000..bf050a6
--- /dev/null
+++ b/chrome/browser/ui/cocoa/color_chooser_mac.mm
@@ -0,0 +1,138 @@
+// 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.
+
+#include "content/public/browser/color_chooser.h"
+
+#import <Cocoa/Cocoa.h>
+
+#import "base/mac/cocoa_protocols.h"
+#import "base/memory/scoped_nsobject.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "skia/ext/skia_utils_mac.h"
+
+class ColorChooserMac;
+
+// A Listener class to act as a event target for NSColorPanel and send
+// the results to the C++ class, ColorChooserMac.
+@interface ColorPanelCocoa : NSObject<NSWindowDelegate> {
+ @private
+ // We don't call DidChooseColor if the change wasn't caused by the user
+ // interacting with the panel.
+ BOOL nonUserChange_;
+ ColorChooserMac* chooser_; // weak, owns this
+}
+
+- (id)initWithChooser:(ColorChooserMac*)chooser;
+
+// Called from NSColorPanel.
+- (void)didChooseColor:(NSColorPanel*)panel;
+
+// Sets color to the NSColorPanel as a non user change.
+- (void)setColor:(NSColor*)color;
+
+@end
+
+class ColorChooserMac : public content::ColorChooser,
+ public content::WebContentsObserver {
+ public:
+ ColorChooserMac(
+ int identifier, content::WebContents* tab, SkColor initial_color);
+ virtual ~ColorChooserMac();
+
+ // Called from ColorPanelCocoa.
+ void DidChooseColor(SkColor color);
+ void DidClose();
+
+ virtual void End() OVERRIDE;
+ virtual void SetSelectedColor(SkColor color) OVERRIDE;
+
+ private:
+ scoped_nsobject<ColorPanelCocoa> panel_;
+};
+
+content::ColorChooser* content::ColorChooser::Create(
+ int identifier, content::WebContents* tab, SkColor initial_color) {
+ return new ColorChooserMac(identifier, tab, initial_color);
+}
+
+ColorChooserMac::ColorChooserMac(
+ int identifier, content::WebContents* tab, SkColor initial_color)
+ : content::ColorChooser(identifier),
+ content::WebContentsObserver(tab) {
+ panel_.reset([[ColorPanelCocoa alloc] initWithChooser:this]);
+ [panel_ setColor:gfx::SkColorToDeviceNSColor(initial_color)];
+ [[NSColorPanel sharedColorPanel] makeKeyAndOrderFront:nil];
+}
+
+ColorChooserMac::~ColorChooserMac() {
+ // Always call End() before destroying.
+ DCHECK(!panel_);
+}
+
+void ColorChooserMac::DidChooseColor(SkColor color) {
+ if (web_contents())
+ web_contents()->DidChooseColorInColorChooser(identifier(), color);
+}
+
+void ColorChooserMac::DidClose() {
+ End();
+}
+
+void ColorChooserMac::End() {
+ panel_.reset();
+ if (web_contents())
+ web_contents()->DidEndColorChooser(identifier());
+}
+
+void ColorChooserMac::SetSelectedColor(SkColor color) {
+ [panel_ setColor:gfx::SkColorToDeviceNSColor(color)];
+}
+
+@implementation ColorPanelCocoa
+
+- (id)initWithChooser:(ColorChooserMac*)chooser {
+ if ((self = [super init])) {
+ chooser_ = chooser;
+ NSColorPanel* panel = [NSColorPanel sharedColorPanel];
+ [panel setShowsAlpha:NO];
+ [panel setDelegate:self];
+ [panel setTarget:self];
+ [panel setAction:@selector(didChooseColor:)];
+ }
+ return self;
+}
+
+- (void)dealloc {
+ NSColorPanel* panel = [NSColorPanel sharedColorPanel];
+ if ([panel delegate] == self) {
+ [panel setDelegate:nil];
+ [panel setTarget:nil];
+ [panel setAction:nil];
+ }
+
+ [super dealloc];
+}
+
+- (void)windowWillClose:(NSNotification*)notification {
+ chooser_->DidClose();
+ nonUserChange_ = NO;
+}
+
+- (void)didChooseColor:(NSColorPanel*)panel {
+ if (nonUserChange_) {
+ nonUserChange_ = NO;
+ return;
+ }
+ chooser_->DidChooseColor(gfx::NSDeviceColorToSkColor(
+ [[panel color] colorUsingColorSpaceName:NSDeviceRGBColorSpace]));
+ nonUserChange_ = NO;
+}
+
+- (void)setColor:(NSColor*)color {
+ nonUserChange_ = YES;
+ [[NSColorPanel sharedColorPanel] setColor:color];
+}
+
+@end
diff --git a/chrome/browser/ui/gtk/color_chooser_gtk.cc b/chrome/browser/ui/gtk/color_chooser_gtk.cc
new file mode 100644
index 0000000..8b9384fe
--- /dev/null
+++ b/chrome/browser/ui/gtk/color_chooser_gtk.cc
@@ -0,0 +1,114 @@
+// 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.
+
+#include <gtk/gtk.h>
+
+#include "content/public/browser/color_chooser.h"
+
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "grit/generated_resources.h"
+#include "ui/base/gtk/gtk_signal.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/gfx/skia_utils_gtk.h"
+
+class ColorChooserGtk : public content::ColorChooser,
+ public content::WebContentsObserver {
+ public:
+ ColorChooserGtk(
+ int identifier, content::WebContents* tab, SkColor initial_color);
+ virtual ~ColorChooserGtk();
+
+ virtual void End() OVERRIDE;
+ virtual void SetSelectedColor(SkColor color) OVERRIDE;
+
+ private:
+ CHROMEGTK_CALLBACK_0(ColorChooserGtk, void, OnColorChooserOk);
+ CHROMEGTK_CALLBACK_0(ColorChooserGtk, void, OnColorChooserCancel);
+ CHROMEGTK_CALLBACK_0(ColorChooserGtk, void, OnColorChooserDestroy);
+
+ GtkWidget* color_selection_dialog_;
+};
+
+content::ColorChooser* content::ColorChooser::Create(
+ int identifier, content::WebContents* tab, SkColor initial_color) {
+ return new ColorChooserGtk(identifier, tab, initial_color);
+}
+
+ColorChooserGtk::ColorChooserGtk(
+ int identifier, content::WebContents* tab, SkColor initial_color)
+ : content::ColorChooser(identifier),
+ content::WebContentsObserver(tab) {
+ color_selection_dialog_ = gtk_color_selection_dialog_new(
+ l10n_util::GetStringUTF8(IDS_SELECT_COLOR_DIALOG_TITLE).c_str());
+ GtkWidget* cancel_button;
+ GtkColorSelection* color_selection;
+ GtkWidget* ok_button;
+ g_object_get(color_selection_dialog_,
+ "cancel-button", &cancel_button,
+ "color-selection", &color_selection,
+ "ok-button", &ok_button,
+ NULL);
+ gtk_color_selection_set_has_opacity_control(color_selection, FALSE);
+ g_signal_connect(ok_button, "clicked",
+ G_CALLBACK(OnColorChooserOkThunk), this);
+ g_signal_connect(cancel_button, "clicked",
+ G_CALLBACK(OnColorChooserCancelThunk), this);
+ g_signal_connect(color_selection_dialog_, "destroy",
+ G_CALLBACK(OnColorChooserDestroyThunk), this);
+ GdkColor gdk_color = gfx::SkColorToGdkColor(initial_color);
+ gtk_color_selection_set_previous_color(color_selection, &gdk_color);
+ gtk_color_selection_set_current_color(color_selection, &gdk_color);
+ gtk_window_present(GTK_WINDOW(color_selection_dialog_));
+ g_object_unref(cancel_button);
+ g_object_unref(color_selection);
+ g_object_unref(ok_button);
+}
+
+ColorChooserGtk::~ColorChooserGtk() {
+ // Always call End() before destroying.
+ DCHECK(!color_selection_dialog_);
+}
+
+void ColorChooserGtk::OnColorChooserOk(GtkWidget* widget) {
+ GdkColor color;
+ GtkColorSelection* color_selection;
+ g_object_get(color_selection_dialog_,
+ "color-selection", &color_selection, NULL);
+ gtk_color_selection_get_current_color(color_selection, &color);
+ web_contents()->DidChooseColorInColorChooser(identifier(),
+ gfx::GdkColorToSkColor(color));
+ g_object_unref(color_selection);
+ gtk_widget_destroy(color_selection_dialog_);
+}
+
+void ColorChooserGtk::OnColorChooserCancel(GtkWidget* widget) {
+ gtk_widget_destroy(color_selection_dialog_);
+}
+
+void ColorChooserGtk::OnColorChooserDestroy(GtkWidget* widget) {
+ color_selection_dialog_ = NULL;
+ if (web_contents())
+ web_contents()->DidEndColorChooser(identifier());
+}
+
+void ColorChooserGtk::End() {
+ if (!color_selection_dialog_)
+ return;
+
+ gtk_widget_destroy(color_selection_dialog_);
+}
+
+void ColorChooserGtk::SetSelectedColor(SkColor color) {
+ if (!color_selection_dialog_)
+ return;
+
+ GdkColor gdk_color = gfx::SkColorToGdkColor(color);
+ GtkColorSelection* color_selection;
+ g_object_get(color_selection_dialog_,
+ "color-selection", &color_selection, NULL);
+ gtk_color_selection_set_previous_color(color_selection, &gdk_color);
+ gtk_color_selection_set_current_color(color_selection, &gdk_color);
+ g_object_unref(color_selection);
+}
diff --git a/chrome/browser/ui/select_file_dialog.h b/chrome/browser/ui/select_file_dialog.h
index 17b96be..6c0b5f3 100644
--- a/chrome/browser/ui/select_file_dialog.h
+++ b/chrome/browser/ui/select_file_dialog.h
@@ -12,6 +12,7 @@
#include "base/file_path.h"
#include "base/memory/ref_counted.h"
#include "base/string16.h"
+#include "chrome/browser/ui/base_shell_dialog.h"
#include "ui/gfx/native_widget_types.h"
namespace content {
@@ -25,21 +26,6 @@ extern std::wstring AppendExtensionIfNeeded(const std::wstring& filename,
const std::wstring& filter_selected,
const std::wstring& suggested_ext);
-// A base class for shell dialogs.
-class BaseShellDialog {
- public:
- // Returns true if a shell dialog box is currently being shown modally
- // to the specified owner.
- virtual bool IsRunning(gfx::NativeWindow owning_window) const = 0;
-
- // Notifies the dialog box that the listener has been destroyed and it should
- // no longer be sent notifications.
- virtual void ListenerDestroyed() = 0;
-
- protected:
- virtual ~BaseShellDialog() {}
-};
-
// Shows a dialog box for selecting a file or a folder.
class SelectFileDialog
: public base::RefCountedThreadSafe<SelectFileDialog>,
diff --git a/chrome/browser/ui/views/ash/color_chooser_aura.cc b/chrome/browser/ui/views/ash/color_chooser_aura.cc
new file mode 100644
index 0000000..b108796
--- /dev/null
+++ b/chrome/browser/ui/views/ash/color_chooser_aura.cc
@@ -0,0 +1,14 @@
+// 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.
+
+#include "content/public/browser/color_chooser.h"
+
+#include "base/logging.h"
+
+// static
+content::ColorChooser* content::ColorChooser::Create(
+ int identifier, content::WebContents* tab, SkColor initial_color) {
+ NOTIMPLEMENTED();
+ return NULL;
+}
diff --git a/chrome/browser/ui/views/base_shell_dialog_win.cc b/chrome/browser/ui/views/base_shell_dialog_win.cc
new file mode 100644
index 0000000..ffb77ea
--- /dev/null
+++ b/chrome/browser/ui/views/base_shell_dialog_win.cc
@@ -0,0 +1,104 @@
+// 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.
+
+#include "chrome/browser/ui/views/base_shell_dialog_win.h"
+
+#include <algorithm>
+
+#include "base/threading/thread.h"
+
+// Helpers to show certain types of Windows shell dialogs in a way that doesn't
+// block the UI of the entire app.
+
+class ShellDialogThread : public base::Thread {
+ public:
+ ShellDialogThread() : base::Thread("Chrome_ShellDialogThread") { }
+ ~ShellDialogThread();
+
+ protected:
+ void Init();
+
+ void CleanUp();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ShellDialogThread);
+};
+
+ShellDialogThread::~ShellDialogThread() {
+ Stop();
+}
+
+void ShellDialogThread::Init() {
+ // Initializes the COM library on the current thread.
+ CoInitialize(NULL);
+}
+
+void ShellDialogThread::CleanUp() {
+ // Closes the COM library on the current thread. CoInitialize must
+ // be balanced by a corresponding call to CoUninitialize.
+ CoUninitialize();
+}
+
+// static
+BaseShellDialogImpl::Owners BaseShellDialogImpl::owners_;
+int BaseShellDialogImpl::instance_count_ = 0;
+
+BaseShellDialogImpl::BaseShellDialogImpl() {
+ ++instance_count_;
+}
+
+BaseShellDialogImpl::~BaseShellDialogImpl() {
+ // All runs should be complete by the time this is called!
+ if (--instance_count_ == 0)
+ DCHECK(owners_.empty());
+}
+
+BaseShellDialogImpl::RunState BaseShellDialogImpl::BeginRun(HWND owner) {
+ // Cannot run a modal shell dialog if one is already running for this owner.
+ DCHECK(!IsRunningDialogForOwner(owner));
+ // The owner must be a top level window, otherwise we could end up with two
+ // entries in our map for the same top level window.
+ DCHECK(!owner || owner == GetAncestor(owner, GA_ROOT));
+ RunState run_state;
+ run_state.dialog_thread = CreateDialogThread();
+ run_state.owner = owner;
+ if (owner) {
+ owners_.insert(owner);
+ DisableOwner(owner);
+ }
+ return run_state;
+}
+
+void BaseShellDialogImpl::EndRun(RunState run_state) {
+ if (run_state.owner) {
+ DCHECK(IsRunningDialogForOwner(run_state.owner));
+ EnableOwner(run_state.owner);
+ DCHECK(owners_.find(run_state.owner) != owners_.end());
+ owners_.erase(run_state.owner);
+ }
+ DCHECK(run_state.dialog_thread);
+ delete run_state.dialog_thread;
+}
+
+bool BaseShellDialogImpl::IsRunningDialogForOwner(HWND owner) const {
+ return (owner && owners_.find(owner) != owners_.end());
+}
+
+void BaseShellDialogImpl::DisableOwner(HWND owner) {
+ if (IsWindow(owner))
+ EnableWindow(owner, FALSE);
+}
+
+// static
+base::Thread* BaseShellDialogImpl::CreateDialogThread() {
+ base::Thread* thread = new ShellDialogThread;
+ bool started = thread->Start();
+ DCHECK(started);
+ return thread;
+}
+
+void BaseShellDialogImpl::EnableOwner(HWND owner) {
+ if (IsWindow(owner))
+ EnableWindow(owner, TRUE);
+}
diff --git a/chrome/browser/ui/views/base_shell_dialog_win.h b/chrome/browser/ui/views/base_shell_dialog_win.h
new file mode 100644
index 0000000..fb84c28
--- /dev/null
+++ b/chrome/browser/ui/views/base_shell_dialog_win.h
@@ -0,0 +1,93 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_VIEWS_BASE_SHELL_DIALOG_WIN_H_
+#define CHROME_BROWSER_UI_VIEWS_BASE_SHELL_DIALOG_WIN_H_
+#pragma once
+
+#include <shlobj.h>
+#include <set>
+
+#include "chrome/browser/ui/base_shell_dialog.h"
+
+namespace base {
+class Thread;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// A base class for all shell dialog implementations that handles showing a
+// shell dialog modally on its own thread.
+class BaseShellDialogImpl {
+ public:
+ BaseShellDialogImpl();
+ virtual ~BaseShellDialogImpl();
+
+ protected:
+ // Represents a run of a dialog.
+ struct RunState {
+ // Owning HWND, may be null.
+ HWND owner;
+
+ // Thread dialog is run on.
+ base::Thread* dialog_thread;
+ };
+
+ // Called at the beginning of a modal dialog run. Disables the owner window
+ // and tracks it. Returns the message loop of the thread that the dialog will
+ // be run on.
+ RunState BeginRun(HWND owner);
+
+ // Cleans up after a dialog run. If the run_state has a valid HWND this makes
+ // sure that the window is enabled. This is essential because BeginRun
+ // aggressively guards against multiple modal dialogs per HWND. Must be called
+ // on the UI thread after the result of the dialog has been determined.
+ //
+ // In addition this deletes the Thread in RunState.
+ void EndRun(RunState run_state);
+
+ // Returns true if a modal shell dialog is currently active for the specified
+ // owner. Must be called on the UI thread.
+ bool IsRunningDialogForOwner(HWND owner) const;
+
+ // Disables the window |owner|. Can be run from either the ui or the dialog
+ // thread. Can be called on either the UI or the dialog thread. This function
+ // is called on the dialog thread after the modal Windows Common dialog
+ // functions return because Windows automatically re-enables the owning
+ // window when those functions return, but we don't actually want them to be
+ // re-enabled until the response of the dialog propagates back to the UI
+ // thread, so we disable the owner manually after the Common dialog function
+ // returns.
+ void DisableOwner(HWND owner);
+
+ private:
+ typedef std::set<HWND> Owners;
+
+ // Creates a thread to run a shell dialog on. Each dialog requires its own
+ // thread otherwise in some situations where a singleton owns a single
+ // instance of this object we can have a situation where a modal dialog in
+ // one window blocks the appearance of a modal dialog in another.
+ static base::Thread* CreateDialogThread();
+
+ // Enables the window |owner_|. Can only be run from the ui thread.
+ void EnableOwner(HWND owner);
+
+ // A list of windows that currently own active shell dialogs for this
+ // instance. For example, if the DownloadManager owns an instance of this
+ // object and there are two browser windows open both with Save As dialog
+ // boxes active, this list will consist of the two browser windows' HWNDs.
+ // The derived class must call EndRun once the dialog is done showing to
+ // remove the owning HWND from this list.
+ // This object is static since it is maintained for all instances of this
+ // object - i.e. you can't have two file pickers open for the
+ // same owner, even though they might be represented by different instances
+ // of this object.
+ // This set only contains non-null HWNDs. NULL hwnds are not added to this
+ // list.
+ static Owners owners_;
+ static int instance_count_;
+
+ DISALLOW_COPY_AND_ASSIGN(BaseShellDialogImpl);
+};
+
+#endif // CHROME_BROWSER_UI_VIEWS_BASE_SHELL_DIALOG_WIN_H_
diff --git a/chrome/browser/ui/views/color_chooser_dialog.cc b/chrome/browser/ui/views/color_chooser_dialog.cc
new file mode 100644
index 0000000..1a3c129
--- /dev/null
+++ b/chrome/browser/ui/views/color_chooser_dialog.cc
@@ -0,0 +1,81 @@
+// 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.
+
+#include "chrome/browser/ui/views/color_chooser_dialog.h"
+
+#include <commdlg.h>
+
+#include "base/bind.h"
+#include "base/message_loop.h"
+#include "base/threading/thread.h"
+#include "content/public/browser/browser_thread.h"
+#include "skia/ext/skia_utils_win.h"
+
+using content::BrowserThread;
+
+// static
+COLORREF ColorChooserDialog::g_custom_colors[16];
+
+ColorChooserDialog::ExecuteOpenParams::ExecuteOpenParams(SkColor color,
+ RunState run_state,
+ HWND owner)
+ : color(color),
+ run_state(run_state),
+ owner(owner) {
+}
+
+ColorChooserDialog::ColorChooserDialog(Listener* listener,
+ SkColor initial_color,
+ gfx::NativeWindow owning_window)
+ : listener_(listener) {
+ DCHECK(listener_);
+ CopyCustomColors(g_custom_colors, custom_colors_);
+ ExecuteOpenParams execute_params(initial_color, BeginRun(owning_window),
+ owning_window);
+ execute_params.run_state.dialog_thread->message_loop()->PostTask(FROM_HERE,
+ base::Bind(&ColorChooserDialog::ExecuteOpen, this, execute_params));
+}
+
+ColorChooserDialog::~ColorChooserDialog() {
+}
+
+bool ColorChooserDialog::IsRunning(HWND owning_hwnd) const {
+ return listener_ && IsRunningDialogForOwner(owning_hwnd);
+}
+
+void ColorChooserDialog::ListenerDestroyed() {
+ // Our associated listener has gone away, so we shouldn't call back to it if
+ // our worker thread returns after the listener is dead.
+ listener_ = NULL;
+}
+
+void ColorChooserDialog::ExecuteOpen(const ExecuteOpenParams& params) {
+ CHOOSECOLOR cc;
+ cc.lStructSize = sizeof(CHOOSECOLOR);
+ cc.hwndOwner = params.owner;
+ cc.rgbResult = skia::SkColorToCOLORREF(params.color);
+ cc.lpCustColors = custom_colors_;
+ cc.Flags = CC_ANYCOLOR | CC_FULLOPEN | CC_RGBINIT;
+ bool success = !!ChooseColor(&cc);
+ DisableOwner(cc.hwndOwner);
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ base::Bind(&ColorChooserDialog::DidCloseDialog, this, success,
+ skia::COLORREFToSkColor(cc.rgbResult), params.run_state));
+}
+
+void ColorChooserDialog::DidCloseDialog(bool chose_color,
+ SkColor color,
+ RunState run_state) {
+ if (!listener_)
+ return;
+ EndRun(run_state);
+ CopyCustomColors(custom_colors_, g_custom_colors);
+ if (chose_color)
+ listener_->DidChooseColor(color);
+ listener_->DidEnd();
+}
+
+void ColorChooserDialog::CopyCustomColors(COLORREF* src, COLORREF* dst) {
+ memcpy(dst, src, sizeof(COLORREF) * arraysize(g_custom_colors));
+}
diff --git a/chrome/browser/ui/views/color_chooser_dialog.h b/chrome/browser/ui/views/color_chooser_dialog.h
new file mode 100644
index 0000000..8eef9ba
--- /dev/null
+++ b/chrome/browser/ui/views/color_chooser_dialog.h
@@ -0,0 +1,79 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_VIEWS_COLOR_CHOOSER_DIALOG_H_
+#define CHROME_BROWSER_UI_VIEWS_COLOR_CHOOSER_DIALOG_H_
+#pragma once
+
+#include "base/memory/ref_counted.h"
+#include "chrome/browser/ui/base_shell_dialog.h"
+#include "chrome/browser/ui/views/color_chooser_dialog.h"
+#include "chrome/browser/ui/views/base_shell_dialog_win.h"
+#include "third_party/skia/include/core/SkColor.h"
+
+class ColorChooserDialog
+ : public base::RefCountedThreadSafe<ColorChooserDialog>,
+ public BaseShellDialog,
+ public BaseShellDialogImpl {
+ public:
+ // An interface implemented by a Listener object wishing to know about the
+ // the results from the color chooser dialog.
+ class Listener {
+ public:
+ virtual ~Listener() {}
+ virtual void DidChooseColor(SkColor color) = 0;
+ virtual void DidEnd() = 0;
+ };
+
+ ColorChooserDialog(Listener* listener,
+ SkColor initial_color,
+ gfx::NativeWindow owning_window);
+ virtual ~ColorChooserDialog();
+
+ // BaseShellDialog:
+ virtual bool IsRunning(HWND owning_hwnd) const OVERRIDE;
+ virtual void ListenerDestroyed() OVERRIDE;
+
+ private:
+ struct ExecuteOpenParams {
+ ExecuteOpenParams(SkColor color, RunState run_state, HWND owner);
+ SkColor color;
+ RunState run_state;
+ HWND owner;
+ };
+
+ // Called on the dialog thread to show the actual color chooser. This is
+ // shown modal to |params.owner|. Once it's closed, calls back to
+ // DidCloseDialog() on the UI thread.
+ void ExecuteOpen(const ExecuteOpenParams& params);
+
+ // Called on the UI thread when a color chooser is closed. |chose_color| is
+ // true if the user actually chose a color, in which case |color| is the
+ // chosen color. Calls back to the |listener_| (if applicable) to notify it
+ // of the results, and copies the modified array of |custom_colors_| back to
+ // |g_custom_colors| so future dialogs will see the changes.
+ void DidCloseDialog(bool chose_color, SkColor color, RunState run_state);
+
+ // Copies the array of colors in |src| to |dst|.
+ void CopyCustomColors(COLORREF*, COLORREF*);
+
+ // The user's custom colors. Kept process-wide so that they can be persisted
+ // from one dialog invocation to the next.
+ static COLORREF g_custom_colors[16];
+
+ // A copy of the custom colors for the current dialog to display and modify.
+ // This allows us to safely access the colors even if multiple windows are
+ // simultaneously showing color choosers (which would cause thread safety
+ // problems if we gave them direct handles to |g_custom_colors|).
+ COLORREF custom_colors_[16];
+
+ // The listener to notify when the user closes the dialog. This may be set to
+ // NULL before the color chooser is closed, signalling that the listener no
+ // longer cares about the outcome.
+ Listener* listener_;
+
+ DISALLOW_COPY_AND_ASSIGN(ColorChooserDialog);
+};
+
+#endif // CHROME_BROWSER_UI_VIEWS_COLOR_CHOOSER_DIALOG_H_
diff --git a/chrome/browser/ui/views/color_chooser_win.cc b/chrome/browser/ui/views/color_chooser_win.cc
new file mode 100644
index 0000000..04fc540
--- /dev/null
+++ b/chrome/browser/ui/views/color_chooser_win.cc
@@ -0,0 +1,71 @@
+// 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.
+
+#include <windows.h>
+
+#include "chrome/browser/platform_util.h"
+#include "chrome/browser/ui/views/color_chooser_dialog.h"
+#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/color_chooser.h"
+#include "content/public/browser/render_widget_host_view.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_observer.h"
+
+class ColorChooserWin : public content::ColorChooser,
+ public ColorChooserDialog::Listener,
+ public content::WebContentsObserver {
+ public:
+ ColorChooserWin(int identifier,
+ content::WebContents* tab,
+ SkColor initial_color);
+ ~ColorChooserWin();
+
+ // content::ColorChooser:
+ virtual void End() OVERRIDE {}
+ virtual void SetSelectedColor(SkColor color) OVERRIDE {}
+
+ // ColorChooserDialog::Listener:
+ virtual void DidChooseColor(SkColor color);
+ virtual void DidEnd();
+
+ private:
+ scoped_refptr<ColorChooserDialog> color_chooser_dialog_;
+};
+
+content::ColorChooser* content::ColorChooser::Create(int identifier,
+ content::WebContents* tab,
+ SkColor initial_color) {
+ return new ColorChooserWin(identifier, tab, initial_color);
+}
+
+ColorChooserWin::ColorChooserWin(int identifier,
+ content::WebContents* tab,
+ SkColor initial_color)
+ : content::ColorChooser(identifier),
+ content::WebContentsObserver(tab) {
+ gfx::NativeWindow owning_window = platform_util::GetTopLevel(
+ web_contents()->GetRenderViewHost()->GetView()->GetNativeView());
+ color_chooser_dialog_ = new ColorChooserDialog(this,
+ initial_color,
+ owning_window);
+}
+
+ColorChooserWin::~ColorChooserWin() {
+ // Always call End() before destroying.
+ DCHECK(!color_chooser_dialog_);
+}
+
+void ColorChooserWin::DidChooseColor(SkColor color) {
+ if (web_contents())
+ web_contents()->DidChooseColorInColorChooser(identifier(), color);
+}
+
+void ColorChooserWin::DidEnd() {
+ if (color_chooser_dialog_.get()) {
+ color_chooser_dialog_->ListenerDestroyed();
+ color_chooser_dialog_ = NULL;
+ }
+ if (web_contents())
+ web_contents()->DidEndColorChooser(identifier());
+}
diff --git a/chrome/browser/ui/views/select_file_dialog_win.cc b/chrome/browser/ui/views/select_file_dialog_win.cc
index 5414b42..80dedf2 100644
--- a/chrome/browser/ui/views/select_file_dialog_win.cc
+++ b/chrome/browser/ui/views/select_file_dialog_win.cc
@@ -22,6 +22,7 @@
#include "base/win/registry.h"
#include "base/win/scoped_comptr.h"
#include "base/win/windows_version.h"
+#include "chrome/browser/ui/views/base_shell_dialog_win.h"
#include "content/public/browser/browser_thread.h"
#include "grit/generated_resources.h"
#include "grit/ui_strings.h"
@@ -389,169 +390,6 @@ bool SaveFileAs(HWND owner,
} // namespace
-// Helpers to show certain types of Windows shell dialogs in a way that doesn't
-// block the UI of the entire app.
-
-class ShellDialogThread : public base::Thread {
- public:
- ShellDialogThread() : base::Thread("Chrome_ShellDialogThread") { }
- ~ShellDialogThread() {
- Stop();
- }
-
- protected:
- void Init() {
- // Initializes the COM library on the current thread.
- CoInitialize(NULL);
- }
-
- void CleanUp() {
- // Closes the COM library on the current thread. CoInitialize must
- // be balanced by a corresponding call to CoUninitialize.
- CoUninitialize();
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ShellDialogThread);
-};
-
-///////////////////////////////////////////////////////////////////////////////
-// A base class for all shell dialog implementations that handles showing a
-// shell dialog modally on its own thread.
-class BaseShellDialogImpl {
- public:
- BaseShellDialogImpl();
- virtual ~BaseShellDialogImpl();
-
- protected:
- // Represents a run of a dialog.
- struct RunState {
- // Owning HWND, may be null.
- HWND owner;
-
- // Thread dialog is run on.
- base::Thread* dialog_thread;
- };
-
- // Called at the beginning of a modal dialog run. Disables the owner window
- // and tracks it. Returns the message loop of the thread that the dialog will
- // be run on.
- RunState BeginRun(HWND owner);
-
- // Cleans up after a dialog run. If the run_state has a valid HWND this makes
- // sure that the window is enabled. This is essential because BeginRun
- // aggressively guards against multiple modal dialogs per HWND. Must be called
- // on the UI thread after the result of the dialog has been determined.
- //
- // In addition this deletes the Thread in RunState.
- void EndRun(RunState run_state);
-
- // Returns true if a modal shell dialog is currently active for the specified
- // owner. Must be called on the UI thread.
- bool IsRunningDialogForOwner(HWND owner) const;
-
- // Disables the window |owner|. Can be run from either the ui or the dialog
- // thread. Can be called on either the UI or the dialog thread. This function
- // is called on the dialog thread after the modal Windows Common dialog
- // functions return because Windows automatically re-enables the owning
- // window when those functions return, but we don't actually want them to be
- // re-enabled until the response of the dialog propagates back to the UI
- // thread, so we disable the owner manually after the Common dialog function
- // returns.
- void DisableOwner(HWND owner);
-
- private:
- // Creates a thread to run a shell dialog on. Each dialog requires its own
- // thread otherwise in some situations where a singleton owns a single
- // instance of this object we can have a situation where a modal dialog in
- // one window blocks the appearance of a modal dialog in another.
- static base::Thread* CreateDialogThread();
-
- // Enables the window |owner_|. Can only be run from the ui thread.
- void EnableOwner(HWND owner);
-
- // A list of windows that currently own active shell dialogs for this
- // instance. For example, if the DownloadManager owns an instance of this
- // object and there are two browser windows open both with Save As dialog
- // boxes active, this list will consist of the two browser windows' HWNDs.
- // The derived class must call EndRun once the dialog is done showing to
- // remove the owning HWND from this list.
- // This object is static since it is maintained for all instances of this
- // object - i.e. you can't have two file pickers open for the
- // same owner, even though they might be represented by different instances
- // of this object.
- // This set only contains non-null HWNDs. NULL hwnds are not added to this
- // list.
- typedef std::set<HWND> Owners;
- static Owners owners_;
- static int instance_count_;
-
- DISALLOW_COPY_AND_ASSIGN(BaseShellDialogImpl);
-};
-
-// static
-BaseShellDialogImpl::Owners BaseShellDialogImpl::owners_;
-int BaseShellDialogImpl::instance_count_ = 0;
-
-BaseShellDialogImpl::BaseShellDialogImpl() {
- ++instance_count_;
-}
-
-BaseShellDialogImpl::~BaseShellDialogImpl() {
- // All runs should be complete by the time this is called!
- if (--instance_count_ == 0)
- DCHECK(owners_.empty());
-}
-
-BaseShellDialogImpl::RunState BaseShellDialogImpl::BeginRun(HWND owner) {
- // Cannot run a modal shell dialog if one is already running for this owner.
- DCHECK(!IsRunningDialogForOwner(owner));
- // The owner must be a top level window, otherwise we could end up with two
- // entries in our map for the same top level window.
- DCHECK(!owner || owner == GetAncestor(owner, GA_ROOT));
- RunState run_state;
- run_state.dialog_thread = CreateDialogThread();
- run_state.owner = owner;
- if (owner) {
- owners_.insert(owner);
- DisableOwner(owner);
- }
- return run_state;
-}
-
-void BaseShellDialogImpl::EndRun(RunState run_state) {
- if (run_state.owner) {
- DCHECK(IsRunningDialogForOwner(run_state.owner));
- EnableOwner(run_state.owner);
- DCHECK(owners_.find(run_state.owner) != owners_.end());
- owners_.erase(run_state.owner);
- }
- DCHECK(run_state.dialog_thread);
- delete run_state.dialog_thread;
-}
-
-bool BaseShellDialogImpl::IsRunningDialogForOwner(HWND owner) const {
- return (owner && owners_.find(owner) != owners_.end());
-}
-
-void BaseShellDialogImpl::DisableOwner(HWND owner) {
- if (IsWindow(owner))
- EnableWindow(owner, FALSE);
-}
-
-// static
-base::Thread* BaseShellDialogImpl::CreateDialogThread() {
- base::Thread* thread = new ShellDialogThread;
- bool started = thread->Start();
- DCHECK(started);
- return thread;
-}
-
-void BaseShellDialogImpl::EnableOwner(HWND owner) {
- if (IsWindow(owner))
- EnableWindow(owner, TRUE);
-}
-
// Implementation of SelectFileDialog that shows a Windows common dialog for
// choosing a file or folder.
class SelectFileDialogImpl : public SelectFileDialog,
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 1c0de07..fdafa2b 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -2272,6 +2272,7 @@
'browser/ui/alternate_error_tab_observer.cc',
'browser/ui/alternate_error_tab_observer.h',
'browser/ui/android/certificate_viewer_android.cc',
+ 'browser/ui/android/color_chooser_android.cc',
'browser/ui/android/extensions/extension_view_android.cc',
'browser/ui/android/extensions/extension_view_android.h',
'browser/ui/android/external_protocol_dialog_android.cc',
@@ -2292,6 +2293,7 @@
'browser/ui/auto_login_info_bar_delegate.h',
'browser/ui/auto_login_prompter.cc',
'browser/ui/auto_login_prompter.h',
+ 'browser/ui/base_shell_dialog.h',
'browser/ui/base_window.h',
'browser/ui/blocked_content/blocked_content_container.cc',
'browser/ui/blocked_content/blocked_content_container.h',
@@ -2320,6 +2322,7 @@
'browser/ui/browser_tab_restore_service_delegate.cc',
'browser/ui/browser_tab_restore_service_delegate.h',
'browser/ui/browser_window.h',
+ 'browser/ui/color_chooser.h',
'browser/ui/certificate_dialogs.cc',
'browser/ui/certificate_dialogs.h',
'browser/ui/cocoa/about_ipc_controller.h',
@@ -2431,6 +2434,7 @@
'browser/ui/cocoa/chrome_event_processing_window.mm',
'browser/ui/cocoa/clickhold_button_cell.h',
'browser/ui/cocoa/clickhold_button_cell.mm',
+ 'browser/ui/cocoa/color_chooser_mac.mm',
'browser/ui/cocoa/command_observer_bridge.h',
'browser/ui/cocoa/command_observer_bridge.mm',
'browser/ui/cocoa/confirm_bubble_controller.h',
@@ -2858,6 +2862,7 @@
'browser/ui/gtk/collected_cookies_gtk.h',
'browser/ui/gtk/confirm_bubble_view.cc',
'browser/ui/gtk/confirm_bubble_view.h',
+ 'browser/ui/gtk/color_chooser_gtk.cc',
'browser/ui/gtk/constrained_html_delegate_gtk.cc',
'browser/ui/gtk/constrained_window_gtk.cc',
'browser/ui/gtk/constrained_window_gtk.h',
@@ -3214,6 +3219,7 @@
'browser/ui/views/ash/caps_lock_handler.h',
'browser/ui/views/ash/chrome_shell_delegate.cc',
'browser/ui/views/ash/chrome_shell_delegate.h',
+ 'browser/ui/views/ash/color_chooser_aura.cc',
'browser/ui/views/ash/gesture_prefs_aura.cc',
'browser/ui/views/ash/ime_controller_chromeos.cc',
'browser/ui/views/ash/ime_controller_chromeos.h',
@@ -3248,6 +3254,8 @@
'browser/ui/views/avatar_menu_bubble_view.h',
'browser/ui/views/avatar_menu_button.cc',
'browser/ui/views/avatar_menu_button.h',
+ 'browser/ui/views/base_shell_dialog_win.cc',
+ 'browser/ui/views/base_shell_dialog_win.h',
'browser/ui/views/bookmarks/bookmark_bar_instructions_view.cc',
'browser/ui/views/bookmarks/bookmark_bar_instructions_view.h',
'browser/ui/views/bookmarks/bookmark_bar_view.cc',
@@ -3490,6 +3498,9 @@
'browser/ui/views/select_file_dialog_extension.cc',
'browser/ui/views/select_file_dialog_extension.h',
'browser/ui/views/select_file_dialog_win.cc',
+ 'browser/ui/views/color_chooser_win.cc',
+ 'browser/ui/views/color_chooser_dialog.cc',
+ 'browser/ui/views/color_chooser_dialog.h',
'browser/ui/views/simple_message_box_win.cc',
'browser/ui/views/simple_message_box_views.cc',
'browser/ui/views/simple_message_box_views.h',
diff --git a/content/browser/tab_contents/tab_contents.cc b/content/browser/tab_contents/tab_contents.cc
index cf3fd3d..1ee9287 100644
--- a/content/browser/tab_contents/tab_contents.cc
+++ b/content/browser/tab_contents/tab_contents.cc
@@ -38,6 +38,7 @@
#include "content/common/view_messages.h"
#include "content/port/browser/render_widget_host_view_port.h"
#include "content/public/browser/browser_context.h"
+#include "content/public/browser/color_chooser.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/devtools_agent_host_registry.h"
#include "content/public/browser/download_manager.h"
@@ -272,7 +273,8 @@ TabContents::TabContents(content::BrowserContext* browser_context,
temporary_zoom_settings_(false),
content_restrictions_(0),
view_type_(content::VIEW_TYPE_TAB_CONTENTS),
- has_opener_(false) {
+ has_opener_(false),
+ color_chooser_(NULL) {
render_manager_.Init(browser_context, site_instance, routing_id);
view_.reset(content::GetContentClient()->browser()->
@@ -312,6 +314,9 @@ TabContents::~TabContents() {
if (dialog_creator_)
dialog_creator_->ResetJavaScriptState(this);
+ if (color_chooser_)
+ color_chooser_->End();
+
NotifyDisconnected();
// Notify any observer that have a reference on this tab contents.
@@ -558,6 +563,10 @@ bool TabContents::OnMessageReceived(const IPC::Message& message) {
IPC_MESSAGE_HANDLER(ViewHostMsg_Find_Reply, OnFindReply)
IPC_MESSAGE_HANDLER(ViewHostMsg_CrashedPlugin, OnCrashedPlugin)
IPC_MESSAGE_HANDLER(ViewHostMsg_AppCacheAccessed, OnAppCacheAccessed)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_OpenColorChooser, OnOpenColorChooser)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_EndColorChooser, OnEndColorChooser)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_SetSelectedColorInColorChooser,
+ OnSetSelectedColorInColorChooser)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP_EX()
@@ -1381,6 +1390,20 @@ bool TabContents::HasOpener() const {
return has_opener_;
}
+void TabContents::DidChooseColorInColorChooser(int color_chooser_id,
+ const SkColor& color) {
+ GetRenderViewHost()->Send(new ViewMsg_DidChooseColorResponse(
+ GetRenderViewHost()->GetRoutingID(), color_chooser_id, color));
+}
+
+void TabContents::DidEndColorChooser(int color_chooser_id) {
+ GetRenderViewHost()->Send(new ViewMsg_DidEndColorChooser(
+ GetRenderViewHost()->GetRoutingID(), color_chooser_id));
+ if (delegate_)
+ delegate_->DidEndColorChooser();
+ color_chooser_ = NULL;
+}
+
bool TabContents::FocusLocationBarByDefault() {
content::WebUI* web_ui = GetWebUIForCurrentState();
if (web_ui)
@@ -1690,6 +1713,24 @@ void TabContents::OnAppCacheAccessed(const GURL& manifest_url,
AppCacheAccessed(manifest_url, blocked_by_policy));
}
+void TabContents::OnOpenColorChooser(int color_chooser_id,
+ const SkColor& color) {
+ color_chooser_ = delegate_->OpenColorChooser(this, color_chooser_id, color);
+}
+
+void TabContents::OnEndColorChooser(int color_chooser_id) {
+ if (color_chooser_ &&
+ color_chooser_id == color_chooser_->identifier())
+ color_chooser_->End();
+}
+
+void TabContents::OnSetSelectedColorInColorChooser(int color_chooser_id,
+ const SkColor& color) {
+ if (color_chooser_ &&
+ color_chooser_id == color_chooser_->identifier())
+ color_chooser_->SetSelectedColor(color);
+}
+
// Notifies the RenderWidgetHost instance about the fact that the page is
// loading, or done loading and calls the base implementation.
void TabContents::SetIsLoading(bool is_loading,
diff --git a/content/browser/tab_contents/tab_contents.h b/content/browser/tab_contents/tab_contents.h
index 0878483..557f0ce 100644
--- a/content/browser/tab_contents/tab_contents.h
+++ b/content/browser/tab_contents/tab_contents.h
@@ -36,6 +36,7 @@ class SessionStorageNamespaceImpl;
struct ViewHostMsg_DidFailProvisionalLoadWithError_Params;
namespace content {
+class ColorChooser;
class DownloadItem;
class JavaScriptDialogCreator;
class RenderViewHost;
@@ -223,6 +224,9 @@ class CONTENT_EXPORT TabContents
virtual content::WebUI* GetWebUIForCurrentState() OVERRIDE;
virtual bool GotResponseToLockMouseRequest(bool allowed) OVERRIDE;
virtual bool HasOpener() const OVERRIDE;
+ virtual void DidChooseColorInColorChooser(int color_chooser_id,
+ const SkColor&) OVERRIDE;
+ virtual void DidEndColorChooser(int color_chooser_id) OVERRIDE;
// Implementation of PageNavigator.
virtual content::WebContents* OpenURL(
@@ -446,6 +450,11 @@ class CONTENT_EXPORT TabContents
bool final_update);
void OnCrashedPlugin(const FilePath& plugin_path);
void OnAppCacheAccessed(const GURL& manifest_url, bool blocked_by_policy);
+ void OnOpenColorChooser(int color_chooser_id,
+ const SkColor& color);
+ void OnEndColorChooser(int color_chooser_id);
+ void OnSetSelectedColorInColorChooser(int color_chooser_id,
+ const SkColor& color);
// Changes the IsLoading state and notifies delegate as needed
// |details| is used to provide details on the load that just finished
@@ -670,6 +679,9 @@ class CONTENT_EXPORT TabContents
// Is there an opener associated with this?
bool has_opener_;
+ // Color chooser that was opened by this tab.
+ content::ColorChooser* color_chooser_;
+
DISALLOW_COPY_AND_ASSIGN(TabContents);
};
diff --git a/content/common/view_messages.h b/content/common/view_messages.h
index 2cecf9e..41f6e83 100644
--- a/content/common/view_messages.h
+++ b/content/common/view_messages.h
@@ -1010,6 +1010,12 @@ IPC_MESSAGE_ROUTED0(ViewMsg_UpdateTargetURL_ACK)
IPC_MESSAGE_ROUTED1(ViewMsg_SetAltErrorPageURL,
GURL)
+// Notifies the color chooser client that the user selected a color.
+IPC_MESSAGE_ROUTED2(ViewMsg_DidChooseColorResponse, unsigned, SkColor)
+
+// Notifies the color chooser client that the color chooser has ended.
+IPC_MESSAGE_ROUTED1(ViewMsg_DidEndColorChooser, unsigned)
+
IPC_MESSAGE_ROUTED1(ViewMsg_RunFileChooserResponse,
std::vector<content::SelectedFileInfo>)
@@ -1691,6 +1697,19 @@ IPC_MESSAGE_ROUTED2(ViewHostMsg_SelectionBoundsChanged,
gfx::Rect /* start rect */,
gfx::Rect /* end rect */)
+// Asks the browser to open the color chooser.
+IPC_MESSAGE_ROUTED2(ViewHostMsg_OpenColorChooser,
+ int /* id */,
+ SkColor /* color */)
+
+// Asks the browser to end the color chooser.
+IPC_MESSAGE_ROUTED1(ViewHostMsg_EndColorChooser, int /* id */)
+
+// Change the selected color in the color chooser.
+IPC_MESSAGE_ROUTED2(ViewHostMsg_SetSelectedColorInColorChooser,
+ int /* id */,
+ SkColor /* color */)
+
// Asks the browser to display the file chooser. The result is returned in a
// ViewHost_RunFileChooserResponse message.
IPC_MESSAGE_ROUTED1(ViewHostMsg_RunFileChooser,
diff --git a/content/content_browser.gypi b/content/content_browser.gypi
index 8ee5461..bde2984 100644
--- a/content/content_browser.gypi
+++ b/content/content_browser.gypi
@@ -46,6 +46,7 @@
'public/browser/cert_store.h',
'public/browser/child_process_data.h',
'public/browser/child_process_security_policy.h',
+ 'public/browser/color_chooser.h',
'public/browser/content_browser_client.h',
'public/browser/content_ipc_logging.h',
'public/browser/devtools_agent_host_registry.h',
diff --git a/content/content_renderer.gypi b/content/content_renderer.gypi
index ca7fc6c..8080d3b 100644
--- a/content/content_renderer.gypi
+++ b/content/content_renderer.gypi
@@ -177,6 +177,8 @@
'renderer/renderer_webapplicationcachehost_impl.h',
'renderer/renderer_webcookiejar_impl.cc',
'renderer/renderer_webcookiejar_impl.h',
+ 'renderer/renderer_webcolorchooser_impl.cc',
+ 'renderer/renderer_webcolorchooser_impl.h',
'renderer/renderer_webkitplatformsupport_impl.cc',
'renderer/renderer_webkitplatformsupport_impl.h',
'renderer/renderer_webstoragearea_impl.cc',
diff --git a/content/public/browser/color_chooser.h b/content/public/browser/color_chooser.h
new file mode 100644
index 0000000..7519da5
--- /dev/null
+++ b/content/public/browser/color_chooser.h
@@ -0,0 +1,47 @@
+// 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.
+
+#ifndef CONTENT_PUBLIC_BROWSER_COLOR_CHOOSER_H_
+#define CONTENT_PUBLIC_BROWSER_COLOR_CHOOSER_H_
+#pragma once
+
+#include "third_party/skia/include/core/SkColor.h"
+
+namespace content {
+
+class RenderViewHost;
+class WebContents;
+
+// Abstraction object for color choosers for each platform.
+class ColorChooser {
+ public:
+ static ColorChooser* Create(int identifier,
+ WebContents* tab,
+ SkColor initial_color);
+ ColorChooser(int identifier) : identifier_(identifier) {}
+ virtual ~ColorChooser() {}
+
+ // Returns a unique identifier for this chooser. Identifiers are unique
+ // across a renderer process. This avoids race conditions in synchronizing
+ // the browser and renderer processes. For example, if a renderer closes one
+ // chooser and opens another, and simultaneously the user picks a color in the
+ // first chooser, the IDs can be used to drop the "chose a color" message
+ // rather than erroneously tell the renderer that the user picked a color in
+ // the second chooser.
+ int identifier() const { return identifier_; }
+
+ // Ends connection with color chooser. Closes color chooser depending on the
+ // platform.
+ virtual void End() = 0;
+
+ // Sets the selected color.
+ virtual void SetSelectedColor(SkColor color) = 0;
+
+private:
+ int identifier_;
+};
+
+}
+
+#endif // CONTENT_PUBLIC_BROWSER_COLOR_CHOOSER_H_
diff --git a/content/public/browser/web_contents.h b/content/public/browser/web_contents.h
index abd656a..80e4929 100644
--- a/content/public/browser/web_contents.h
+++ b/content/public/browser/web_contents.h
@@ -15,6 +15,7 @@
#include "content/public/browser/save_page_type.h"
#include "content/public/browser/web_ui.h"
#include "content/public/common/view_type.h"
+#include "third_party/skia/include/core/SkColor.h"
#include "ui/gfx/native_widget_types.h"
#include "webkit/glue/window_open_disposition.h"
@@ -356,6 +357,13 @@ class WebContents : public PageNavigator {
// locked.
virtual bool GotResponseToLockMouseRequest(bool allowed) = 0;
+ // Called when the user has selected a color in the color chooser.
+ virtual void DidChooseColorInColorChooser(int color_chooser_id,
+ const SkColor&) = 0;
+
+ // Called when the color chooser has ended.
+ virtual void DidEndColorChooser(int color_chooser_id) = 0;
+
// Returns true if the location bar should be focused by default rather than
// the page contents. The view calls this function when the tab is focused
// to see what it should do.
diff --git a/content/public/browser/web_contents_delegate.cc b/content/public/browser/web_contents_delegate.cc
index 39f8448..0e24df0 100644
--- a/content/public/browser/web_contents_delegate.cc
+++ b/content/public/browser/web_contents_delegate.cc
@@ -134,6 +134,12 @@ bool WebContentsDelegate::IsFullscreenForTab(const WebContents* tab) const {
return false;
}
+content::ColorChooser* WebContentsDelegate::OpenColorChooser(WebContents* tab,
+ int color_chooser_id,
+ const SkColor& color) {
+ return NULL;
+}
+
void WebContentsDelegate::WebIntentDispatch(
WebContents* tab,
WebIntentsDispatcher* intents_dispatcher) {
diff --git a/content/public/browser/web_contents_delegate.h b/content/public/browser/web_contents_delegate.h
index d5111fd..2d1669c 100644
--- a/content/public/browser/web_contents_delegate.h
+++ b/content/public/browser/web_contents_delegate.h
@@ -15,6 +15,7 @@
#include "content/public/browser/navigation_type.h"
#include "content/public/common/page_transition_types.h"
#include "content/public/common/window_container_type.h"
+#include "third_party/skia/include/core/SkColor.h"
#include "ui/gfx/native_widget_types.h"
#include "webkit/glue/window_open_disposition.h"
@@ -29,6 +30,7 @@ class ListValue;
namespace content {
class BrowserContext;
+class ColorChooser;
class DownloadItem;
class JavaScriptDialogCreator;
class RenderViewHost;
@@ -310,6 +312,13 @@ class CONTENT_EXPORT WebContentsDelegate {
// NULL in which case dialogs aren't shown.
virtual JavaScriptDialogCreator* GetJavaScriptDialogCreator();
+ // Called when color chooser should open. Returns the opened color chooser.
+ virtual content::ColorChooser* OpenColorChooser(WebContents* tab,
+ int color_chooser_id,
+ const SkColor& color);
+
+ virtual void DidEndColorChooser() {}
+
// Called when a file selection is to be done.
virtual void RunFileChooser(WebContents* tab,
const FileChooserParams& params) {}
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index b1bb198..52caa04 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -81,6 +81,7 @@
#include "content/renderer/render_widget_fullscreen_pepper.h"
#include "content/renderer/renderer_accessibility.h"
#include "content/renderer/renderer_webapplicationcachehost_impl.h"
+#include "content/renderer/renderer_webcolorchooser_impl.h"
#include "content/renderer/renderer_webstoragenamespace_impl.h"
#include "content/renderer/text_input_client_observer.h"
#include "content/renderer/v8_value_converter_impl.h"
@@ -1741,6 +1742,15 @@ bool RenderViewImpl::handleCurrentKeyboardEvent() {
return did_execute_command;
}
+WebKit::WebColorChooser* RenderViewImpl::createColorChooser(
+ WebKit::WebColorChooserClient* client,
+ const WebKit::WebColor& initial_color) {
+ RendererWebColorChooserImpl* color_chooser =
+ new RendererWebColorChooserImpl(this, client);
+ color_chooser->Open(static_cast<SkColor>(initial_color));
+ return color_chooser;
+}
+
bool RenderViewImpl::runFileChooser(
const WebKit::WebFileChooserParams& params,
WebFileChooserCompletion* chooser_completion) {
diff --git a/content/renderer/render_view_impl.h b/content/renderer/render_view_impl.h
index a104ebe..f523434 100644
--- a/content/renderer/render_view_impl.h
+++ b/content/renderer/render_view_impl.h
@@ -75,6 +75,7 @@ class PepperDeviceTest;
struct PP_NetAddress_Private;
class RenderWidgetFullscreenPepper;
class RendererAccessibility;
+class RendererWebColorChooserImpl;
class SkBitmap;
class InputTagSpeechDispatcher;
struct ViewMsg_Navigate_Params;
@@ -376,6 +377,8 @@ class RenderViewImpl : public RenderWidget,
virtual void didChangeSelection(bool is_selection_empty);
virtual void didExecuteCommand(const WebKit::WebString& command_name);
virtual bool handleCurrentKeyboardEvent();
+ virtual WebKit::WebColorChooser* createColorChooser(
+ WebKit::WebColorChooserClient*, const WebKit::WebColor& initial_color);
virtual bool runFileChooser(
const WebKit::WebFileChooserParams& params,
WebKit::WebFileChooserCompletion* chooser_completion);
diff --git a/content/renderer/renderer_webcolorchooser_impl.cc b/content/renderer/renderer_webcolorchooser_impl.cc
new file mode 100644
index 0000000..9a50b19
--- /dev/null
+++ b/content/renderer/renderer_webcolorchooser_impl.cc
@@ -0,0 +1,70 @@
+// 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.
+
+#include "content/renderer/renderer_webcolorchooser_impl.h"
+
+#include "content/common/view_messages.h"
+#include "content/renderer/render_view_impl.h"
+
+static int GenerateColorChooserIdentifier() {
+ static int next = 0;
+ return ++next;
+}
+
+RendererWebColorChooserImpl::RendererWebColorChooserImpl(
+ RenderViewImpl* render_view,
+ WebKit::WebColorChooserClient* client)
+ : content::RenderViewObserver(render_view),
+ identifier_(GenerateColorChooserIdentifier()),
+ client_(client) {
+}
+
+RendererWebColorChooserImpl::~RendererWebColorChooserImpl() {
+}
+
+bool RendererWebColorChooserImpl::OnMessageReceived(
+ const IPC::Message& message) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(RendererWebColorChooserImpl, message)
+ IPC_MESSAGE_HANDLER(ViewMsg_DidChooseColorResponse,
+ OnDidChooseColorResponse)
+ IPC_MESSAGE_HANDLER(ViewMsg_DidEndColorChooser,
+ OnDidEndColorChooser)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+}
+
+void RendererWebColorChooserImpl::FrameWillClose(WebKit::WebFrame* frame) {
+ endChooser();
+ client_->didEndChooser();
+}
+
+void RendererWebColorChooserImpl::setSelectedColor(WebKit::WebColor color) {
+ Send(new ViewHostMsg_SetSelectedColorInColorChooser(routing_id(), identifier_,
+ static_cast<SkColor>(color)));
+}
+
+void RendererWebColorChooserImpl::endChooser() {
+ Send(new ViewHostMsg_EndColorChooser(routing_id(), identifier_));
+}
+
+void RendererWebColorChooserImpl::Open(SkColor initial_color) {
+ Send(new ViewHostMsg_OpenColorChooser(routing_id(), identifier_,
+ initial_color));
+}
+
+void RendererWebColorChooserImpl::OnDidChooseColorResponse(
+ int color_chooser_id,
+ const SkColor& color) {
+ DCHECK(identifier_ == color_chooser_id);
+
+ client_->didChooseColor(static_cast<WebKit::WebColor>(color));
+}
+
+void RendererWebColorChooserImpl::OnDidEndColorChooser(int color_chooser_id) {
+ if (identifier_ != color_chooser_id)
+ return;
+ client_->didEndChooser();
+}
diff --git a/content/renderer/renderer_webcolorchooser_impl.h b/content/renderer/renderer_webcolorchooser_impl.h
new file mode 100644
index 0000000..afe0871
--- /dev/null
+++ b/content/renderer/renderer_webcolorchooser_impl.h
@@ -0,0 +1,50 @@
+// 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.
+
+#ifndef CONTENT_RENDERER_RENDERER_WEBCOLORCHOOSER_IMPL_H_
+#define CONTENT_RENDERER_RENDERER_WEBCOLORCHOOSER_IMPL_H_
+#pragma once
+
+#include "base/memory/scoped_ptr.h"
+#include "content/public/renderer/render_view_observer.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebColorChooser.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebColorChooserClient.h"
+#include "third_party/skia/include/core/SkColor.h"
+
+namespace WebKit {
+class WebFrame;
+}
+
+class RenderViewImpl;
+
+class RendererWebColorChooserImpl : public WebKit::WebColorChooser,
+ public content::RenderViewObserver {
+ public:
+ explicit RendererWebColorChooserImpl(RenderViewImpl* sender,
+ WebKit::WebColorChooserClient*);
+ virtual ~RendererWebColorChooserImpl();
+
+ virtual void setSelectedColor(const WebKit::WebColor);
+ virtual void endChooser();
+
+ void Open(SkColor initial_color);
+
+ WebKit::WebColorChooserClient* client() { return client_; }
+
+ private:
+ // RenderViewObserver implementation.
+ virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+ virtual void FrameWillClose(WebKit::WebFrame* frame) OVERRIDE;
+
+ void OnDidChooseColorResponse(int color_chooser_id,
+ const SkColor& color);
+ void OnDidEndColorChooser(int color_chooser_id);
+
+ int identifier_;
+ WebKit::WebColorChooserClient* client_;
+
+ DISALLOW_COPY_AND_ASSIGN(RendererWebColorChooserImpl);
+};
+
+#endif // CONTENT_RENDERER_RENDERER_WEBCOLORCHOOSER_IMPL_H_
diff --git a/skia/ext/skia_utils_mac.h b/skia/ext/skia_utils_mac.h
index 8d11165..683ddf0 100644
--- a/skia/ext/skia_utils_mac.h
+++ b/skia/ext/skia_utils_mac.h
@@ -64,8 +64,13 @@ SkColor CGColorRefToSkColor(CGColorRef color);
// Converts ARGB to CGColorRef.
CGColorRef SkColorToCGColorRef(SkColor color);
+// Converts NSColor to ARGB. Returns raw rgb values and does no colorspace
+// conversion. Only valid for colors in calibrated and device color spaces.
+SK_API SkColor NSDeviceColorToSkColor(NSColor* color);
+
// Converts ARGB to NSColor.
SK_API NSColor* SkColorToCalibratedNSColor(SkColor color);
+SK_API NSColor* SkColorToDeviceNSColor(SkColor color);
// Converts a CGImage to a SkBitmap.
SK_API SkBitmap CGImageToSkBitmap(CGImageRef image);
diff --git a/skia/ext/skia_utils_mac.mm b/skia/ext/skia_utils_mac.mm
index d639460..0c82a95e 100644
--- a/skia/ext/skia_utils_mac.mm
+++ b/skia/ext/skia_utils_mac.mm
@@ -190,6 +190,19 @@ CGColorRef SkColorToCGColorRef(SkColor color) {
SkColorGetA(color) / 255.0);
}
+// Converts NSColor to ARGB
+SkColor NSDeviceColorToSkColor(NSColor* color) {
+ DCHECK([color colorSpace] == [NSColorSpace genericRGBColorSpace] ||
+ [color colorSpace] == [NSColorSpace deviceRGBColorSpace]);
+ CGFloat red, green, blue, alpha;
+ color = [color colorUsingColorSpace:[NSColorSpace deviceRGBColorSpace]];
+ [color getRed:&red green:&green blue:&blue alpha:&alpha];
+ return SkColorSetARGB(SkScalarRound(255.0 * alpha),
+ SkScalarRound(255.0 * red),
+ SkScalarRound(255.0 * green),
+ SkScalarRound(255.0 * blue));
+}
+
// Converts ARGB to NSColor.
NSColor* SkColorToCalibratedNSColor(SkColor color) {
return [NSColor colorWithCalibratedRed:SkColorGetR(color) / 255.0
@@ -198,6 +211,13 @@ NSColor* SkColorToCalibratedNSColor(SkColor color) {
alpha:SkColorGetA(color) / 255.0];
}
+NSColor* SkColorToDeviceNSColor(SkColor color) {
+ return [NSColor colorWithDeviceRed:SkColorGetR(color) / 255.0
+ green:SkColorGetG(color) / 255.0
+ blue:SkColorGetB(color) / 255.0
+ alpha:SkColorGetA(color) / 255.0];
+}
+
SkBitmap CGImageToSkBitmap(CGImageRef image) {
if (!image)
return SkBitmap();