1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/widget/windows/nsColorPicker.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,173 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- 1.5 + * 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "nsColorPicker.h" 1.11 + 1.12 +#include <shlwapi.h> 1.13 + 1.14 +#include "mozilla/AutoRestore.h" 1.15 +#include "nsIWidget.h" 1.16 +#include "WidgetUtils.h" 1.17 + 1.18 +using namespace mozilla::widget; 1.19 + 1.20 +namespace 1.21 +{ 1.22 +// Manages NS_NATIVE_TMP_WINDOW child windows. NS_NATIVE_TMP_WINDOWs are 1.23 +// temporary child windows of mParentWidget created to address RTL issues 1.24 +// in picker dialogs. We are responsible for destroying these. 1.25 +class AutoDestroyTmpWindow 1.26 +{ 1.27 +public: 1.28 + explicit AutoDestroyTmpWindow(HWND aTmpWnd) : 1.29 + mWnd(aTmpWnd) { 1.30 + } 1.31 + 1.32 + ~AutoDestroyTmpWindow() { 1.33 + if (mWnd) 1.34 + DestroyWindow(mWnd); 1.35 + } 1.36 + 1.37 + inline HWND get() const { return mWnd; } 1.38 +private: 1.39 + HWND mWnd; 1.40 +}; 1.41 + 1.42 +static DWORD ColorStringToRGB(const nsAString& aColor) 1.43 +{ 1.44 + DWORD result = 0; 1.45 + 1.46 + for (uint32_t i = 1; i < aColor.Length(); ++i) { 1.47 + result *= 16; 1.48 + 1.49 + char16_t c = aColor[i]; 1.50 + if (c >= '0' && c <= '9') { 1.51 + result += c - '0'; 1.52 + } else if (c >= 'a' && c <= 'f') { 1.53 + result += 10 + (c - 'a'); 1.54 + } else { 1.55 + result += 10 + (c - 'A'); 1.56 + } 1.57 + } 1.58 + 1.59 + DWORD r = result & 0x00FF0000; 1.60 + DWORD g = result & 0x0000FF00; 1.61 + DWORD b = result & 0x000000FF; 1.62 + 1.63 + r = r >> 16; 1.64 + b = b << 16; 1.65 + 1.66 + result = r | g | b; 1.67 + 1.68 + return result; 1.69 +} 1.70 + 1.71 +static nsString ToHexString(BYTE n) 1.72 +{ 1.73 + nsString result; 1.74 + if (n <= 0x0F) { 1.75 + result.Append('0'); 1.76 + } 1.77 + result.AppendInt(n, 16); 1.78 + return result; 1.79 +} 1.80 + 1.81 + 1.82 +static void 1.83 +BGRIntToRGBString(DWORD color, nsAString& aResult) 1.84 +{ 1.85 + BYTE r = GetRValue(color); 1.86 + BYTE g = GetGValue(color); 1.87 + BYTE b = GetBValue(color); 1.88 + 1.89 + aResult.AssignLiteral("#"); 1.90 + aResult.Append(ToHexString(r)); 1.91 + aResult.Append(ToHexString(g)); 1.92 + aResult.Append(ToHexString(b)); 1.93 +} 1.94 +} // anonymous namespace 1.95 + 1.96 +AsyncColorChooser::AsyncColorChooser(const nsAString& aInitialColor, 1.97 + nsIWidget* aParentWidget, 1.98 + nsIColorPickerShownCallback* aCallback) 1.99 + : mInitialColor(aInitialColor) 1.100 + , mParentWidget(aParentWidget) 1.101 + , mCallback(aCallback) 1.102 +{ 1.103 +} 1.104 + 1.105 +NS_IMETHODIMP 1.106 +AsyncColorChooser::Run() 1.107 +{ 1.108 + static COLORREF sCustomColors[16] = {0} ; 1.109 + 1.110 + MOZ_ASSERT(NS_IsMainThread(), 1.111 + "Color pickers can only be opened from main thread currently"); 1.112 + 1.113 + static bool sColorPickerOpen = false; 1.114 + // Allow only one color picker to be opened at a time, to workaround bug 944737 1.115 + if (!sColorPickerOpen) { 1.116 + mozilla::AutoRestore<bool> autoRestoreColorPickerOpen(sColorPickerOpen); 1.117 + sColorPickerOpen = true; 1.118 + 1.119 + AutoDestroyTmpWindow adtw((HWND) (mParentWidget.get() ? 1.120 + mParentWidget->GetNativeData(NS_NATIVE_TMP_WINDOW) : nullptr)); 1.121 + 1.122 + CHOOSECOLOR options; 1.123 + options.lStructSize = sizeof(options); 1.124 + options.hwndOwner = adtw.get(); 1.125 + options.Flags = CC_RGBINIT | CC_FULLOPEN; 1.126 + options.rgbResult = ColorStringToRGB(mInitialColor); 1.127 + options.lpCustColors = sCustomColors; 1.128 + 1.129 + if (ChooseColor(&options)) { 1.130 + BGRIntToRGBString(options.rgbResult, mColor); 1.131 + } 1.132 + } else { 1.133 + NS_WARNING("Currently, it's not possible to open more than one color " 1.134 + "picker at a time"); 1.135 + mColor = mInitialColor; 1.136 + } 1.137 + 1.138 + if (mCallback) { 1.139 + mCallback->Done(mColor); 1.140 + } 1.141 + 1.142 + return NS_OK; 1.143 +} 1.144 + 1.145 +/////////////////////////////////////////////////////////////////////////////// 1.146 +// nsIColorPicker 1.147 + 1.148 +nsColorPicker::nsColorPicker() 1.149 +{ 1.150 +} 1.151 + 1.152 +nsColorPicker::~nsColorPicker() 1.153 +{ 1.154 +} 1.155 + 1.156 +NS_IMPL_ISUPPORTS(nsColorPicker, nsIColorPicker) 1.157 + 1.158 +NS_IMETHODIMP 1.159 +nsColorPicker::Init(nsIDOMWindow* parent, 1.160 + const nsAString& title, 1.161 + const nsAString& aInitialColor) 1.162 +{ 1.163 + NS_PRECONDITION(parent, 1.164 + "Null parent passed to colorpicker, no color picker for you!"); 1.165 + mParentWidget = WidgetUtils::DOMWindowToWidget(parent); 1.166 + mInitialColor = aInitialColor; 1.167 + return NS_OK; 1.168 +} 1.169 + 1.170 +NS_IMETHODIMP 1.171 +nsColorPicker::Open(nsIColorPickerShownCallback* aCallback) 1.172 +{ 1.173 + NS_ENSURE_ARG(aCallback); 1.174 + nsCOMPtr<nsIRunnable> event = new AsyncColorChooser(mInitialColor, mParentWidget, aCallback); 1.175 + return NS_DispatchToMainThread(event); 1.176 +}