Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "nsColorPicker.h"
9 #include <shlwapi.h>
11 #include "mozilla/AutoRestore.h"
12 #include "nsIWidget.h"
13 #include "WidgetUtils.h"
15 using namespace mozilla::widget;
17 namespace
18 {
19 // Manages NS_NATIVE_TMP_WINDOW child windows. NS_NATIVE_TMP_WINDOWs are
20 // temporary child windows of mParentWidget created to address RTL issues
21 // in picker dialogs. We are responsible for destroying these.
22 class AutoDestroyTmpWindow
23 {
24 public:
25 explicit AutoDestroyTmpWindow(HWND aTmpWnd) :
26 mWnd(aTmpWnd) {
27 }
29 ~AutoDestroyTmpWindow() {
30 if (mWnd)
31 DestroyWindow(mWnd);
32 }
34 inline HWND get() const { return mWnd; }
35 private:
36 HWND mWnd;
37 };
39 static DWORD ColorStringToRGB(const nsAString& aColor)
40 {
41 DWORD result = 0;
43 for (uint32_t i = 1; i < aColor.Length(); ++i) {
44 result *= 16;
46 char16_t c = aColor[i];
47 if (c >= '0' && c <= '9') {
48 result += c - '0';
49 } else if (c >= 'a' && c <= 'f') {
50 result += 10 + (c - 'a');
51 } else {
52 result += 10 + (c - 'A');
53 }
54 }
56 DWORD r = result & 0x00FF0000;
57 DWORD g = result & 0x0000FF00;
58 DWORD b = result & 0x000000FF;
60 r = r >> 16;
61 b = b << 16;
63 result = r | g | b;
65 return result;
66 }
68 static nsString ToHexString(BYTE n)
69 {
70 nsString result;
71 if (n <= 0x0F) {
72 result.Append('0');
73 }
74 result.AppendInt(n, 16);
75 return result;
76 }
79 static void
80 BGRIntToRGBString(DWORD color, nsAString& aResult)
81 {
82 BYTE r = GetRValue(color);
83 BYTE g = GetGValue(color);
84 BYTE b = GetBValue(color);
86 aResult.AssignLiteral("#");
87 aResult.Append(ToHexString(r));
88 aResult.Append(ToHexString(g));
89 aResult.Append(ToHexString(b));
90 }
91 } // anonymous namespace
93 AsyncColorChooser::AsyncColorChooser(const nsAString& aInitialColor,
94 nsIWidget* aParentWidget,
95 nsIColorPickerShownCallback* aCallback)
96 : mInitialColor(aInitialColor)
97 , mParentWidget(aParentWidget)
98 , mCallback(aCallback)
99 {
100 }
102 NS_IMETHODIMP
103 AsyncColorChooser::Run()
104 {
105 static COLORREF sCustomColors[16] = {0} ;
107 MOZ_ASSERT(NS_IsMainThread(),
108 "Color pickers can only be opened from main thread currently");
110 static bool sColorPickerOpen = false;
111 // Allow only one color picker to be opened at a time, to workaround bug 944737
112 if (!sColorPickerOpen) {
113 mozilla::AutoRestore<bool> autoRestoreColorPickerOpen(sColorPickerOpen);
114 sColorPickerOpen = true;
116 AutoDestroyTmpWindow adtw((HWND) (mParentWidget.get() ?
117 mParentWidget->GetNativeData(NS_NATIVE_TMP_WINDOW) : nullptr));
119 CHOOSECOLOR options;
120 options.lStructSize = sizeof(options);
121 options.hwndOwner = adtw.get();
122 options.Flags = CC_RGBINIT | CC_FULLOPEN;
123 options.rgbResult = ColorStringToRGB(mInitialColor);
124 options.lpCustColors = sCustomColors;
126 if (ChooseColor(&options)) {
127 BGRIntToRGBString(options.rgbResult, mColor);
128 }
129 } else {
130 NS_WARNING("Currently, it's not possible to open more than one color "
131 "picker at a time");
132 mColor = mInitialColor;
133 }
135 if (mCallback) {
136 mCallback->Done(mColor);
137 }
139 return NS_OK;
140 }
142 ///////////////////////////////////////////////////////////////////////////////
143 // nsIColorPicker
145 nsColorPicker::nsColorPicker()
146 {
147 }
149 nsColorPicker::~nsColorPicker()
150 {
151 }
153 NS_IMPL_ISUPPORTS(nsColorPicker, nsIColorPicker)
155 NS_IMETHODIMP
156 nsColorPicker::Init(nsIDOMWindow* parent,
157 const nsAString& title,
158 const nsAString& aInitialColor)
159 {
160 NS_PRECONDITION(parent,
161 "Null parent passed to colorpicker, no color picker for you!");
162 mParentWidget = WidgetUtils::DOMWindowToWidget(parent);
163 mInitialColor = aInitialColor;
164 return NS_OK;
165 }
167 NS_IMETHODIMP
168 nsColorPicker::Open(nsIColorPickerShownCallback* aCallback)
169 {
170 NS_ENSURE_ARG(aCallback);
171 nsCOMPtr<nsIRunnable> event = new AsyncColorChooser(mInitialColor, mParentWidget, aCallback);
172 return NS_DispatchToMainThread(event);
173 }