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
michael@0 | 1 | /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
michael@0 | 2 | /* vim:set ts=2 sts=2 sw=2 et cin: */ |
michael@0 | 3 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 4 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 5 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 6 | |
michael@0 | 7 | #include "WinUtils.h" |
michael@0 | 8 | |
michael@0 | 9 | #include "gfxPlatform.h" |
michael@0 | 10 | #include "nsWindow.h" |
michael@0 | 11 | #include "nsWindowDefs.h" |
michael@0 | 12 | #include "KeyboardLayout.h" |
michael@0 | 13 | #include "nsIDOMMouseEvent.h" |
michael@0 | 14 | #include "mozilla/gfx/2D.h" |
michael@0 | 15 | #include "mozilla/gfx/DataSurfaceHelpers.h" |
michael@0 | 16 | #include "mozilla/Preferences.h" |
michael@0 | 17 | #include "mozilla/RefPtr.h" |
michael@0 | 18 | #include "mozilla/WindowsVersion.h" |
michael@0 | 19 | |
michael@0 | 20 | #ifdef MOZ_LOGGING |
michael@0 | 21 | #define FORCE_PR_LOG /* Allow logging in the release build */ |
michael@0 | 22 | #endif // MOZ_LOGGING |
michael@0 | 23 | #include "prlog.h" |
michael@0 | 24 | |
michael@0 | 25 | #include "nsString.h" |
michael@0 | 26 | #include "nsDirectoryServiceUtils.h" |
michael@0 | 27 | #include "imgIContainer.h" |
michael@0 | 28 | #include "imgITools.h" |
michael@0 | 29 | #include "nsStringStream.h" |
michael@0 | 30 | #include "nsNetUtil.h" |
michael@0 | 31 | #ifdef MOZ_PLACES |
michael@0 | 32 | #include "mozIAsyncFavicons.h" |
michael@0 | 33 | #endif |
michael@0 | 34 | #include "nsIIconURI.h" |
michael@0 | 35 | #include "nsIDownloader.h" |
michael@0 | 36 | #include "nsINetUtil.h" |
michael@0 | 37 | #include "nsIChannel.h" |
michael@0 | 38 | #include "nsIObserver.h" |
michael@0 | 39 | #include "imgIEncoder.h" |
michael@0 | 40 | #include "nsIThread.h" |
michael@0 | 41 | #include "MainThreadUtils.h" |
michael@0 | 42 | #include "gfxColor.h" |
michael@0 | 43 | #ifdef MOZ_METRO |
michael@0 | 44 | #include "winrt/MetroInput.h" |
michael@0 | 45 | #include "winrt/MetroUtils.h" |
michael@0 | 46 | #endif // MOZ_METRO |
michael@0 | 47 | |
michael@0 | 48 | #ifdef NS_ENABLE_TSF |
michael@0 | 49 | #include <textstor.h> |
michael@0 | 50 | #include "nsTextStore.h" |
michael@0 | 51 | #endif // #ifdef NS_ENABLE_TSF |
michael@0 | 52 | |
michael@0 | 53 | #ifdef PR_LOGGING |
michael@0 | 54 | PRLogModuleInfo* gWindowsLog = nullptr; |
michael@0 | 55 | #endif |
michael@0 | 56 | |
michael@0 | 57 | using namespace mozilla::gfx; |
michael@0 | 58 | |
michael@0 | 59 | namespace mozilla { |
michael@0 | 60 | namespace widget { |
michael@0 | 61 | |
michael@0 | 62 | NS_IMPL_ISUPPORTS(myDownloadObserver, nsIDownloadObserver) |
michael@0 | 63 | #ifdef MOZ_PLACES |
michael@0 | 64 | NS_IMPL_ISUPPORTS(AsyncFaviconDataReady, nsIFaviconDataCallback) |
michael@0 | 65 | #endif |
michael@0 | 66 | NS_IMPL_ISUPPORTS(AsyncEncodeAndWriteIcon, nsIRunnable) |
michael@0 | 67 | NS_IMPL_ISUPPORTS(AsyncDeleteIconFromDisk, nsIRunnable) |
michael@0 | 68 | NS_IMPL_ISUPPORTS(AsyncDeleteAllFaviconsFromDisk, nsIRunnable) |
michael@0 | 69 | |
michael@0 | 70 | |
michael@0 | 71 | const char FaviconHelper::kJumpListCacheDir[] = "jumpListCache"; |
michael@0 | 72 | const char FaviconHelper::kShortcutCacheDir[] = "shortcutCache"; |
michael@0 | 73 | |
michael@0 | 74 | // apis available on vista and up. |
michael@0 | 75 | WinUtils::SHCreateItemFromParsingNamePtr WinUtils::sCreateItemFromParsingName = nullptr; |
michael@0 | 76 | WinUtils::SHGetKnownFolderPathPtr WinUtils::sGetKnownFolderPath = nullptr; |
michael@0 | 77 | |
michael@0 | 78 | // We just leak these DLL HMODULEs. There's no point in calling FreeLibrary |
michael@0 | 79 | // on them during shutdown anyway. |
michael@0 | 80 | static const wchar_t kShellLibraryName[] = L"shell32.dll"; |
michael@0 | 81 | static HMODULE sShellDll = nullptr; |
michael@0 | 82 | static const wchar_t kDwmLibraryName[] = L"dwmapi.dll"; |
michael@0 | 83 | static HMODULE sDwmDll = nullptr; |
michael@0 | 84 | |
michael@0 | 85 | WinUtils::DwmExtendFrameIntoClientAreaProc WinUtils::dwmExtendFrameIntoClientAreaPtr = nullptr; |
michael@0 | 86 | WinUtils::DwmIsCompositionEnabledProc WinUtils::dwmIsCompositionEnabledPtr = nullptr; |
michael@0 | 87 | WinUtils::DwmSetIconicThumbnailProc WinUtils::dwmSetIconicThumbnailPtr = nullptr; |
michael@0 | 88 | WinUtils::DwmSetIconicLivePreviewBitmapProc WinUtils::dwmSetIconicLivePreviewBitmapPtr = nullptr; |
michael@0 | 89 | WinUtils::DwmGetWindowAttributeProc WinUtils::dwmGetWindowAttributePtr = nullptr; |
michael@0 | 90 | WinUtils::DwmSetWindowAttributeProc WinUtils::dwmSetWindowAttributePtr = nullptr; |
michael@0 | 91 | WinUtils::DwmInvalidateIconicBitmapsProc WinUtils::dwmInvalidateIconicBitmapsPtr = nullptr; |
michael@0 | 92 | WinUtils::DwmDefWindowProcProc WinUtils::dwmDwmDefWindowProcPtr = nullptr; |
michael@0 | 93 | WinUtils::DwmGetCompositionTimingInfoProc WinUtils::dwmGetCompositionTimingInfoPtr = nullptr; |
michael@0 | 94 | |
michael@0 | 95 | /* static */ |
michael@0 | 96 | void |
michael@0 | 97 | WinUtils::Initialize() |
michael@0 | 98 | { |
michael@0 | 99 | #ifdef PR_LOGGING |
michael@0 | 100 | if (!gWindowsLog) { |
michael@0 | 101 | gWindowsLog = PR_NewLogModule("Widget"); |
michael@0 | 102 | } |
michael@0 | 103 | #endif |
michael@0 | 104 | if (!sDwmDll && IsVistaOrLater()) { |
michael@0 | 105 | sDwmDll = ::LoadLibraryW(kDwmLibraryName); |
michael@0 | 106 | |
michael@0 | 107 | if (sDwmDll) { |
michael@0 | 108 | dwmExtendFrameIntoClientAreaPtr = (DwmExtendFrameIntoClientAreaProc)::GetProcAddress(sDwmDll, "DwmExtendFrameIntoClientArea"); |
michael@0 | 109 | dwmIsCompositionEnabledPtr = (DwmIsCompositionEnabledProc)::GetProcAddress(sDwmDll, "DwmIsCompositionEnabled"); |
michael@0 | 110 | dwmSetIconicThumbnailPtr = (DwmSetIconicThumbnailProc)::GetProcAddress(sDwmDll, "DwmSetIconicThumbnail"); |
michael@0 | 111 | dwmSetIconicLivePreviewBitmapPtr = (DwmSetIconicLivePreviewBitmapProc)::GetProcAddress(sDwmDll, "DwmSetIconicLivePreviewBitmap"); |
michael@0 | 112 | dwmGetWindowAttributePtr = (DwmGetWindowAttributeProc)::GetProcAddress(sDwmDll, "DwmGetWindowAttribute"); |
michael@0 | 113 | dwmSetWindowAttributePtr = (DwmSetWindowAttributeProc)::GetProcAddress(sDwmDll, "DwmSetWindowAttribute"); |
michael@0 | 114 | dwmInvalidateIconicBitmapsPtr = (DwmInvalidateIconicBitmapsProc)::GetProcAddress(sDwmDll, "DwmInvalidateIconicBitmaps"); |
michael@0 | 115 | dwmDwmDefWindowProcPtr = (DwmDefWindowProcProc)::GetProcAddress(sDwmDll, "DwmDefWindowProc"); |
michael@0 | 116 | dwmGetCompositionTimingInfoPtr = (DwmGetCompositionTimingInfoProc)::GetProcAddress(sDwmDll, "DwmGetCompositionTimingInfo"); |
michael@0 | 117 | } |
michael@0 | 118 | } |
michael@0 | 119 | } |
michael@0 | 120 | |
michael@0 | 121 | // static |
michael@0 | 122 | void |
michael@0 | 123 | WinUtils::LogW(const wchar_t *fmt, ...) |
michael@0 | 124 | { |
michael@0 | 125 | va_list args = nullptr; |
michael@0 | 126 | if(!lstrlenW(fmt)) { |
michael@0 | 127 | return; |
michael@0 | 128 | } |
michael@0 | 129 | va_start(args, fmt); |
michael@0 | 130 | int buflen = _vscwprintf(fmt, args); |
michael@0 | 131 | wchar_t* buffer = new wchar_t[buflen+1]; |
michael@0 | 132 | if (!buffer) { |
michael@0 | 133 | va_end(args); |
michael@0 | 134 | return; |
michael@0 | 135 | } |
michael@0 | 136 | vswprintf(buffer, buflen, fmt, args); |
michael@0 | 137 | va_end(args); |
michael@0 | 138 | |
michael@0 | 139 | // MSVC, including remote debug sessions |
michael@0 | 140 | OutputDebugStringW(buffer); |
michael@0 | 141 | OutputDebugStringW(L"\n"); |
michael@0 | 142 | |
michael@0 | 143 | int len = wcslen(buffer); |
michael@0 | 144 | if (len) { |
michael@0 | 145 | char* utf8 = new char[len+1]; |
michael@0 | 146 | memset(utf8, 0, sizeof(utf8)); |
michael@0 | 147 | if (WideCharToMultiByte(CP_ACP, 0, buffer, |
michael@0 | 148 | -1, utf8, len+1, nullptr, |
michael@0 | 149 | nullptr) > 0) { |
michael@0 | 150 | // desktop console |
michael@0 | 151 | printf("%s\n", utf8); |
michael@0 | 152 | #ifdef PR_LOGGING |
michael@0 | 153 | NS_ASSERTION(gWindowsLog, "Called WinUtils Log() but Widget " |
michael@0 | 154 | "log module doesn't exist!"); |
michael@0 | 155 | PR_LOG(gWindowsLog, PR_LOG_ALWAYS, (utf8)); |
michael@0 | 156 | #endif |
michael@0 | 157 | } |
michael@0 | 158 | delete[] utf8; |
michael@0 | 159 | } |
michael@0 | 160 | delete[] buffer; |
michael@0 | 161 | } |
michael@0 | 162 | |
michael@0 | 163 | // static |
michael@0 | 164 | void |
michael@0 | 165 | WinUtils::Log(const char *fmt, ...) |
michael@0 | 166 | { |
michael@0 | 167 | va_list args = nullptr; |
michael@0 | 168 | if(!strlen(fmt)) { |
michael@0 | 169 | return; |
michael@0 | 170 | } |
michael@0 | 171 | va_start(args, fmt); |
michael@0 | 172 | int buflen = _vscprintf(fmt, args); |
michael@0 | 173 | char* buffer = new char[buflen+1]; |
michael@0 | 174 | if (!buffer) { |
michael@0 | 175 | va_end(args); |
michael@0 | 176 | return; |
michael@0 | 177 | } |
michael@0 | 178 | vsprintf(buffer, fmt, args); |
michael@0 | 179 | va_end(args); |
michael@0 | 180 | |
michael@0 | 181 | // MSVC, including remote debug sessions |
michael@0 | 182 | OutputDebugStringA(buffer); |
michael@0 | 183 | OutputDebugStringW(L"\n"); |
michael@0 | 184 | |
michael@0 | 185 | // desktop console |
michael@0 | 186 | printf("%s\n", buffer); |
michael@0 | 187 | |
michael@0 | 188 | #ifdef PR_LOGGING |
michael@0 | 189 | NS_ASSERTION(gWindowsLog, "Called WinUtils Log() but Widget " |
michael@0 | 190 | "log module doesn't exist!"); |
michael@0 | 191 | PR_LOG(gWindowsLog, PR_LOG_ALWAYS, (buffer)); |
michael@0 | 192 | #endif |
michael@0 | 193 | delete[] buffer; |
michael@0 | 194 | } |
michael@0 | 195 | |
michael@0 | 196 | /* static */ |
michael@0 | 197 | double |
michael@0 | 198 | WinUtils::LogToPhysFactor() |
michael@0 | 199 | { |
michael@0 | 200 | // dpi / 96.0 |
michael@0 | 201 | if (XRE_GetWindowsEnvironment() == WindowsEnvironmentType_Metro) { |
michael@0 | 202 | #ifdef MOZ_METRO |
michael@0 | 203 | return MetroUtils::LogToPhysFactor(); |
michael@0 | 204 | #else |
michael@0 | 205 | return 1.0; |
michael@0 | 206 | #endif |
michael@0 | 207 | } else { |
michael@0 | 208 | HDC hdc = ::GetDC(nullptr); |
michael@0 | 209 | double result = ::GetDeviceCaps(hdc, LOGPIXELSY) / 96.0; |
michael@0 | 210 | ::ReleaseDC(nullptr, hdc); |
michael@0 | 211 | return result; |
michael@0 | 212 | } |
michael@0 | 213 | } |
michael@0 | 214 | |
michael@0 | 215 | /* static */ |
michael@0 | 216 | double |
michael@0 | 217 | WinUtils::PhysToLogFactor() |
michael@0 | 218 | { |
michael@0 | 219 | // 1.0 / (dpi / 96.0) |
michael@0 | 220 | return 1.0 / LogToPhysFactor(); |
michael@0 | 221 | } |
michael@0 | 222 | |
michael@0 | 223 | /* static */ |
michael@0 | 224 | double |
michael@0 | 225 | WinUtils::PhysToLog(int32_t aValue) |
michael@0 | 226 | { |
michael@0 | 227 | return double(aValue) * PhysToLogFactor(); |
michael@0 | 228 | } |
michael@0 | 229 | |
michael@0 | 230 | /* static */ |
michael@0 | 231 | int32_t |
michael@0 | 232 | WinUtils::LogToPhys(double aValue) |
michael@0 | 233 | { |
michael@0 | 234 | return int32_t(NS_round(aValue * LogToPhysFactor())); |
michael@0 | 235 | } |
michael@0 | 236 | |
michael@0 | 237 | /* static */ |
michael@0 | 238 | bool |
michael@0 | 239 | WinUtils::PeekMessage(LPMSG aMsg, HWND aWnd, UINT aFirstMessage, |
michael@0 | 240 | UINT aLastMessage, UINT aOption) |
michael@0 | 241 | { |
michael@0 | 242 | #ifdef NS_ENABLE_TSF |
michael@0 | 243 | ITfMessagePump* msgPump = nsTextStore::GetMessagePump(); |
michael@0 | 244 | if (msgPump) { |
michael@0 | 245 | BOOL ret = FALSE; |
michael@0 | 246 | HRESULT hr = msgPump->PeekMessageW(aMsg, aWnd, aFirstMessage, aLastMessage, |
michael@0 | 247 | aOption, &ret); |
michael@0 | 248 | NS_ENSURE_TRUE(SUCCEEDED(hr), false); |
michael@0 | 249 | return ret; |
michael@0 | 250 | } |
michael@0 | 251 | #endif // #ifdef NS_ENABLE_TSF |
michael@0 | 252 | return ::PeekMessageW(aMsg, aWnd, aFirstMessage, aLastMessage, aOption); |
michael@0 | 253 | } |
michael@0 | 254 | |
michael@0 | 255 | /* static */ |
michael@0 | 256 | bool |
michael@0 | 257 | WinUtils::GetMessage(LPMSG aMsg, HWND aWnd, UINT aFirstMessage, |
michael@0 | 258 | UINT aLastMessage) |
michael@0 | 259 | { |
michael@0 | 260 | #ifdef NS_ENABLE_TSF |
michael@0 | 261 | ITfMessagePump* msgPump = nsTextStore::GetMessagePump(); |
michael@0 | 262 | if (msgPump) { |
michael@0 | 263 | BOOL ret = FALSE; |
michael@0 | 264 | HRESULT hr = msgPump->GetMessageW(aMsg, aWnd, aFirstMessage, aLastMessage, |
michael@0 | 265 | &ret); |
michael@0 | 266 | NS_ENSURE_TRUE(SUCCEEDED(hr), false); |
michael@0 | 267 | return ret; |
michael@0 | 268 | } |
michael@0 | 269 | #endif // #ifdef NS_ENABLE_TSF |
michael@0 | 270 | return ::GetMessageW(aMsg, aWnd, aFirstMessage, aLastMessage); |
michael@0 | 271 | } |
michael@0 | 272 | |
michael@0 | 273 | /* static */ |
michael@0 | 274 | bool |
michael@0 | 275 | WinUtils::GetRegistryKey(HKEY aRoot, |
michael@0 | 276 | char16ptr_t aKeyName, |
michael@0 | 277 | char16ptr_t aValueName, |
michael@0 | 278 | wchar_t* aBuffer, |
michael@0 | 279 | DWORD aBufferLength) |
michael@0 | 280 | { |
michael@0 | 281 | NS_PRECONDITION(aKeyName, "The key name is NULL"); |
michael@0 | 282 | |
michael@0 | 283 | HKEY key; |
michael@0 | 284 | LONG result = |
michael@0 | 285 | ::RegOpenKeyExW(aRoot, aKeyName, 0, KEY_READ | KEY_WOW64_32KEY, &key); |
michael@0 | 286 | if (result != ERROR_SUCCESS) { |
michael@0 | 287 | result = |
michael@0 | 288 | ::RegOpenKeyExW(aRoot, aKeyName, 0, KEY_READ | KEY_WOW64_64KEY, &key); |
michael@0 | 289 | if (result != ERROR_SUCCESS) { |
michael@0 | 290 | return false; |
michael@0 | 291 | } |
michael@0 | 292 | } |
michael@0 | 293 | |
michael@0 | 294 | DWORD type; |
michael@0 | 295 | result = |
michael@0 | 296 | ::RegQueryValueExW(key, aValueName, nullptr, &type, (BYTE*) aBuffer, |
michael@0 | 297 | &aBufferLength); |
michael@0 | 298 | ::RegCloseKey(key); |
michael@0 | 299 | if (result != ERROR_SUCCESS || type != REG_SZ) { |
michael@0 | 300 | return false; |
michael@0 | 301 | } |
michael@0 | 302 | if (aBuffer) { |
michael@0 | 303 | aBuffer[aBufferLength / sizeof(*aBuffer) - 1] = 0; |
michael@0 | 304 | } |
michael@0 | 305 | return true; |
michael@0 | 306 | } |
michael@0 | 307 | |
michael@0 | 308 | /* static */ |
michael@0 | 309 | bool |
michael@0 | 310 | WinUtils::HasRegistryKey(HKEY aRoot, char16ptr_t aKeyName) |
michael@0 | 311 | { |
michael@0 | 312 | MOZ_ASSERT(aRoot, "aRoot must not be NULL"); |
michael@0 | 313 | MOZ_ASSERT(aKeyName, "aKeyName must not be NULL"); |
michael@0 | 314 | HKEY key; |
michael@0 | 315 | LONG result = |
michael@0 | 316 | ::RegOpenKeyExW(aRoot, aKeyName, 0, KEY_READ | KEY_WOW64_32KEY, &key); |
michael@0 | 317 | if (result != ERROR_SUCCESS) { |
michael@0 | 318 | result = |
michael@0 | 319 | ::RegOpenKeyExW(aRoot, aKeyName, 0, KEY_READ | KEY_WOW64_64KEY, &key); |
michael@0 | 320 | if (result != ERROR_SUCCESS) { |
michael@0 | 321 | return false; |
michael@0 | 322 | } |
michael@0 | 323 | } |
michael@0 | 324 | ::RegCloseKey(key); |
michael@0 | 325 | return true; |
michael@0 | 326 | } |
michael@0 | 327 | |
michael@0 | 328 | /* static */ |
michael@0 | 329 | HWND |
michael@0 | 330 | WinUtils::GetTopLevelHWND(HWND aWnd, |
michael@0 | 331 | bool aStopIfNotChild, |
michael@0 | 332 | bool aStopIfNotPopup) |
michael@0 | 333 | { |
michael@0 | 334 | HWND curWnd = aWnd; |
michael@0 | 335 | HWND topWnd = nullptr; |
michael@0 | 336 | |
michael@0 | 337 | while (curWnd) { |
michael@0 | 338 | topWnd = curWnd; |
michael@0 | 339 | |
michael@0 | 340 | if (aStopIfNotChild) { |
michael@0 | 341 | DWORD_PTR style = ::GetWindowLongPtrW(curWnd, GWL_STYLE); |
michael@0 | 342 | |
michael@0 | 343 | VERIFY_WINDOW_STYLE(style); |
michael@0 | 344 | |
michael@0 | 345 | if (!(style & WS_CHILD)) // first top-level window |
michael@0 | 346 | break; |
michael@0 | 347 | } |
michael@0 | 348 | |
michael@0 | 349 | HWND upWnd = ::GetParent(curWnd); // Parent or owner (if has no parent) |
michael@0 | 350 | |
michael@0 | 351 | // GetParent will only return the owner if the passed in window |
michael@0 | 352 | // has the WS_POPUP style. |
michael@0 | 353 | if (!upWnd && !aStopIfNotPopup) { |
michael@0 | 354 | upWnd = ::GetWindow(curWnd, GW_OWNER); |
michael@0 | 355 | } |
michael@0 | 356 | curWnd = upWnd; |
michael@0 | 357 | } |
michael@0 | 358 | |
michael@0 | 359 | return topWnd; |
michael@0 | 360 | } |
michael@0 | 361 | |
michael@0 | 362 | static const wchar_t* |
michael@0 | 363 | GetNSWindowPropName() |
michael@0 | 364 | { |
michael@0 | 365 | static wchar_t sPropName[40] = L""; |
michael@0 | 366 | if (!*sPropName) { |
michael@0 | 367 | _snwprintf(sPropName, 39, L"MozillansIWidgetPtr%p", |
michael@0 | 368 | ::GetCurrentProcessId()); |
michael@0 | 369 | sPropName[39] = '\0'; |
michael@0 | 370 | } |
michael@0 | 371 | return sPropName; |
michael@0 | 372 | } |
michael@0 | 373 | |
michael@0 | 374 | /* static */ |
michael@0 | 375 | bool |
michael@0 | 376 | WinUtils::SetNSWindowBasePtr(HWND aWnd, nsWindowBase* aWidget) |
michael@0 | 377 | { |
michael@0 | 378 | if (!aWidget) { |
michael@0 | 379 | ::RemovePropW(aWnd, GetNSWindowPropName()); |
michael@0 | 380 | return true; |
michael@0 | 381 | } |
michael@0 | 382 | return ::SetPropW(aWnd, GetNSWindowPropName(), (HANDLE)aWidget); |
michael@0 | 383 | } |
michael@0 | 384 | |
michael@0 | 385 | /* static */ |
michael@0 | 386 | nsWindowBase* |
michael@0 | 387 | WinUtils::GetNSWindowBasePtr(HWND aWnd) |
michael@0 | 388 | { |
michael@0 | 389 | return static_cast<nsWindowBase*>(::GetPropW(aWnd, GetNSWindowPropName())); |
michael@0 | 390 | } |
michael@0 | 391 | |
michael@0 | 392 | /* static */ |
michael@0 | 393 | nsWindow* |
michael@0 | 394 | WinUtils::GetNSWindowPtr(HWND aWnd) |
michael@0 | 395 | { |
michael@0 | 396 | return static_cast<nsWindow*>(::GetPropW(aWnd, GetNSWindowPropName())); |
michael@0 | 397 | } |
michael@0 | 398 | |
michael@0 | 399 | static BOOL CALLBACK |
michael@0 | 400 | AddMonitor(HMONITOR, HDC, LPRECT, LPARAM aParam) |
michael@0 | 401 | { |
michael@0 | 402 | (*(int32_t*)aParam)++; |
michael@0 | 403 | return TRUE; |
michael@0 | 404 | } |
michael@0 | 405 | |
michael@0 | 406 | /* static */ |
michael@0 | 407 | int32_t |
michael@0 | 408 | WinUtils::GetMonitorCount() |
michael@0 | 409 | { |
michael@0 | 410 | int32_t monitorCount = 0; |
michael@0 | 411 | EnumDisplayMonitors(nullptr, nullptr, AddMonitor, (LPARAM)&monitorCount); |
michael@0 | 412 | return monitorCount; |
michael@0 | 413 | } |
michael@0 | 414 | |
michael@0 | 415 | /* static */ |
michael@0 | 416 | bool |
michael@0 | 417 | WinUtils::IsOurProcessWindow(HWND aWnd) |
michael@0 | 418 | { |
michael@0 | 419 | if (!aWnd) { |
michael@0 | 420 | return false; |
michael@0 | 421 | } |
michael@0 | 422 | DWORD processId = 0; |
michael@0 | 423 | ::GetWindowThreadProcessId(aWnd, &processId); |
michael@0 | 424 | return (processId == ::GetCurrentProcessId()); |
michael@0 | 425 | } |
michael@0 | 426 | |
michael@0 | 427 | /* static */ |
michael@0 | 428 | HWND |
michael@0 | 429 | WinUtils::FindOurProcessWindow(HWND aWnd) |
michael@0 | 430 | { |
michael@0 | 431 | for (HWND wnd = ::GetParent(aWnd); wnd; wnd = ::GetParent(wnd)) { |
michael@0 | 432 | if (IsOurProcessWindow(wnd)) { |
michael@0 | 433 | return wnd; |
michael@0 | 434 | } |
michael@0 | 435 | } |
michael@0 | 436 | return nullptr; |
michael@0 | 437 | } |
michael@0 | 438 | |
michael@0 | 439 | static bool |
michael@0 | 440 | IsPointInWindow(HWND aWnd, const POINT& aPointInScreen) |
michael@0 | 441 | { |
michael@0 | 442 | RECT bounds; |
michael@0 | 443 | if (!::GetWindowRect(aWnd, &bounds)) { |
michael@0 | 444 | return false; |
michael@0 | 445 | } |
michael@0 | 446 | |
michael@0 | 447 | return (aPointInScreen.x >= bounds.left && aPointInScreen.x < bounds.right && |
michael@0 | 448 | aPointInScreen.y >= bounds.top && aPointInScreen.y < bounds.bottom); |
michael@0 | 449 | } |
michael@0 | 450 | |
michael@0 | 451 | /** |
michael@0 | 452 | * FindTopmostWindowAtPoint() returns the topmost child window (topmost means |
michael@0 | 453 | * forground in this context) of aWnd. |
michael@0 | 454 | */ |
michael@0 | 455 | |
michael@0 | 456 | static HWND |
michael@0 | 457 | FindTopmostWindowAtPoint(HWND aWnd, const POINT& aPointInScreen) |
michael@0 | 458 | { |
michael@0 | 459 | if (!::IsWindowVisible(aWnd) || !IsPointInWindow(aWnd, aPointInScreen)) { |
michael@0 | 460 | return nullptr; |
michael@0 | 461 | } |
michael@0 | 462 | |
michael@0 | 463 | HWND childWnd = ::GetTopWindow(aWnd); |
michael@0 | 464 | while (childWnd) { |
michael@0 | 465 | HWND topmostWnd = FindTopmostWindowAtPoint(childWnd, aPointInScreen); |
michael@0 | 466 | if (topmostWnd) { |
michael@0 | 467 | return topmostWnd; |
michael@0 | 468 | } |
michael@0 | 469 | childWnd = ::GetNextWindow(childWnd, GW_HWNDNEXT); |
michael@0 | 470 | } |
michael@0 | 471 | |
michael@0 | 472 | return aWnd; |
michael@0 | 473 | } |
michael@0 | 474 | |
michael@0 | 475 | struct FindOurWindowAtPointInfo |
michael@0 | 476 | { |
michael@0 | 477 | POINT mInPointInScreen; |
michael@0 | 478 | HWND mOutWnd; |
michael@0 | 479 | }; |
michael@0 | 480 | |
michael@0 | 481 | static BOOL CALLBACK |
michael@0 | 482 | FindOurWindowAtPointCallback(HWND aWnd, LPARAM aLPARAM) |
michael@0 | 483 | { |
michael@0 | 484 | if (!WinUtils::IsOurProcessWindow(aWnd)) { |
michael@0 | 485 | // This isn't one of our top-level windows; continue enumerating. |
michael@0 | 486 | return TRUE; |
michael@0 | 487 | } |
michael@0 | 488 | |
michael@0 | 489 | // Get the top-most child window under the point. If there's no child |
michael@0 | 490 | // window, and the point is within the top-level window, then the top-level |
michael@0 | 491 | // window will be returned. (This is the usual case. A child window |
michael@0 | 492 | // would be returned for plugins.) |
michael@0 | 493 | FindOurWindowAtPointInfo* info = |
michael@0 | 494 | reinterpret_cast<FindOurWindowAtPointInfo*>(aLPARAM); |
michael@0 | 495 | HWND childWnd = FindTopmostWindowAtPoint(aWnd, info->mInPointInScreen); |
michael@0 | 496 | if (!childWnd) { |
michael@0 | 497 | // This window doesn't contain the point; continue enumerating. |
michael@0 | 498 | return TRUE; |
michael@0 | 499 | } |
michael@0 | 500 | |
michael@0 | 501 | // Return the HWND and stop enumerating. |
michael@0 | 502 | info->mOutWnd = childWnd; |
michael@0 | 503 | return FALSE; |
michael@0 | 504 | } |
michael@0 | 505 | |
michael@0 | 506 | /* static */ |
michael@0 | 507 | HWND |
michael@0 | 508 | WinUtils::FindOurWindowAtPoint(const POINT& aPointInScreen) |
michael@0 | 509 | { |
michael@0 | 510 | FindOurWindowAtPointInfo info; |
michael@0 | 511 | info.mInPointInScreen = aPointInScreen; |
michael@0 | 512 | info.mOutWnd = nullptr; |
michael@0 | 513 | |
michael@0 | 514 | // This will enumerate all top-level windows in order from top to bottom. |
michael@0 | 515 | EnumWindows(FindOurWindowAtPointCallback, reinterpret_cast<LPARAM>(&info)); |
michael@0 | 516 | return info.mOutWnd; |
michael@0 | 517 | } |
michael@0 | 518 | |
michael@0 | 519 | /* static */ |
michael@0 | 520 | UINT |
michael@0 | 521 | WinUtils::GetInternalMessage(UINT aNativeMessage) |
michael@0 | 522 | { |
michael@0 | 523 | switch (aNativeMessage) { |
michael@0 | 524 | case WM_MOUSEWHEEL: |
michael@0 | 525 | return MOZ_WM_MOUSEVWHEEL; |
michael@0 | 526 | case WM_MOUSEHWHEEL: |
michael@0 | 527 | return MOZ_WM_MOUSEHWHEEL; |
michael@0 | 528 | case WM_VSCROLL: |
michael@0 | 529 | return MOZ_WM_VSCROLL; |
michael@0 | 530 | case WM_HSCROLL: |
michael@0 | 531 | return MOZ_WM_HSCROLL; |
michael@0 | 532 | default: |
michael@0 | 533 | return aNativeMessage; |
michael@0 | 534 | } |
michael@0 | 535 | } |
michael@0 | 536 | |
michael@0 | 537 | /* static */ |
michael@0 | 538 | UINT |
michael@0 | 539 | WinUtils::GetNativeMessage(UINT aInternalMessage) |
michael@0 | 540 | { |
michael@0 | 541 | switch (aInternalMessage) { |
michael@0 | 542 | case MOZ_WM_MOUSEVWHEEL: |
michael@0 | 543 | return WM_MOUSEWHEEL; |
michael@0 | 544 | case MOZ_WM_MOUSEHWHEEL: |
michael@0 | 545 | return WM_MOUSEHWHEEL; |
michael@0 | 546 | case MOZ_WM_VSCROLL: |
michael@0 | 547 | return WM_VSCROLL; |
michael@0 | 548 | case MOZ_WM_HSCROLL: |
michael@0 | 549 | return WM_HSCROLL; |
michael@0 | 550 | default: |
michael@0 | 551 | return aInternalMessage; |
michael@0 | 552 | } |
michael@0 | 553 | } |
michael@0 | 554 | |
michael@0 | 555 | /* static */ |
michael@0 | 556 | uint16_t |
michael@0 | 557 | WinUtils::GetMouseInputSource() |
michael@0 | 558 | { |
michael@0 | 559 | int32_t inputSource = nsIDOMMouseEvent::MOZ_SOURCE_MOUSE; |
michael@0 | 560 | LPARAM lParamExtraInfo = ::GetMessageExtraInfo(); |
michael@0 | 561 | if ((lParamExtraInfo & TABLET_INK_SIGNATURE) == TABLET_INK_CHECK) { |
michael@0 | 562 | inputSource = (lParamExtraInfo & TABLET_INK_TOUCH) ? |
michael@0 | 563 | nsIDOMMouseEvent::MOZ_SOURCE_TOUCH : nsIDOMMouseEvent::MOZ_SOURCE_PEN; |
michael@0 | 564 | } |
michael@0 | 565 | return static_cast<uint16_t>(inputSource); |
michael@0 | 566 | } |
michael@0 | 567 | |
michael@0 | 568 | bool |
michael@0 | 569 | WinUtils::GetIsMouseFromTouch(uint32_t aEventType) |
michael@0 | 570 | { |
michael@0 | 571 | #define MOUSEEVENTF_FROMTOUCH 0xFF515700 |
michael@0 | 572 | return (aEventType == NS_MOUSE_BUTTON_DOWN || |
michael@0 | 573 | aEventType == NS_MOUSE_BUTTON_UP || |
michael@0 | 574 | aEventType == NS_MOUSE_MOVE) && |
michael@0 | 575 | (GetMessageExtraInfo() & MOUSEEVENTF_FROMTOUCH); |
michael@0 | 576 | } |
michael@0 | 577 | |
michael@0 | 578 | /* static */ |
michael@0 | 579 | MSG |
michael@0 | 580 | WinUtils::InitMSG(UINT aMessage, WPARAM wParam, LPARAM lParam, HWND aWnd) |
michael@0 | 581 | { |
michael@0 | 582 | MSG msg; |
michael@0 | 583 | msg.message = aMessage; |
michael@0 | 584 | msg.wParam = wParam; |
michael@0 | 585 | msg.lParam = lParam; |
michael@0 | 586 | msg.hwnd = aWnd; |
michael@0 | 587 | return msg; |
michael@0 | 588 | } |
michael@0 | 589 | |
michael@0 | 590 | /* static */ |
michael@0 | 591 | HRESULT |
michael@0 | 592 | WinUtils::SHCreateItemFromParsingName(PCWSTR pszPath, IBindCtx *pbc, |
michael@0 | 593 | REFIID riid, void **ppv) |
michael@0 | 594 | { |
michael@0 | 595 | if (sCreateItemFromParsingName) { |
michael@0 | 596 | return sCreateItemFromParsingName(pszPath, pbc, riid, ppv); |
michael@0 | 597 | } |
michael@0 | 598 | |
michael@0 | 599 | if (!sShellDll) { |
michael@0 | 600 | sShellDll = ::LoadLibraryW(kShellLibraryName); |
michael@0 | 601 | if (!sShellDll) { |
michael@0 | 602 | return false; |
michael@0 | 603 | } |
michael@0 | 604 | } |
michael@0 | 605 | |
michael@0 | 606 | sCreateItemFromParsingName = (SHCreateItemFromParsingNamePtr) |
michael@0 | 607 | GetProcAddress(sShellDll, "SHCreateItemFromParsingName"); |
michael@0 | 608 | if (!sCreateItemFromParsingName) |
michael@0 | 609 | return E_FAIL; |
michael@0 | 610 | |
michael@0 | 611 | return sCreateItemFromParsingName(pszPath, pbc, riid, ppv); |
michael@0 | 612 | } |
michael@0 | 613 | |
michael@0 | 614 | /* static */ |
michael@0 | 615 | HRESULT |
michael@0 | 616 | WinUtils::SHGetKnownFolderPath(REFKNOWNFOLDERID rfid, |
michael@0 | 617 | DWORD dwFlags, |
michael@0 | 618 | HANDLE hToken, |
michael@0 | 619 | PWSTR *ppszPath) |
michael@0 | 620 | { |
michael@0 | 621 | if (sGetKnownFolderPath) { |
michael@0 | 622 | return sGetKnownFolderPath(rfid, dwFlags, hToken, ppszPath); |
michael@0 | 623 | } |
michael@0 | 624 | |
michael@0 | 625 | if (!sShellDll) { |
michael@0 | 626 | sShellDll = ::LoadLibraryW(kShellLibraryName); |
michael@0 | 627 | if (!sShellDll) { |
michael@0 | 628 | return false; |
michael@0 | 629 | } |
michael@0 | 630 | } |
michael@0 | 631 | |
michael@0 | 632 | sGetKnownFolderPath = (SHGetKnownFolderPathPtr) |
michael@0 | 633 | GetProcAddress(sShellDll, "SHGetKnownFolderPath"); |
michael@0 | 634 | if (!sGetKnownFolderPath) |
michael@0 | 635 | return E_FAIL; |
michael@0 | 636 | |
michael@0 | 637 | return sGetKnownFolderPath(rfid, dwFlags, hToken, ppszPath); |
michael@0 | 638 | } |
michael@0 | 639 | |
michael@0 | 640 | #ifdef MOZ_PLACES |
michael@0 | 641 | /************************************************************************/ |
michael@0 | 642 | /* Constructs as AsyncFaviconDataReady Object |
michael@0 | 643 | /* @param aIOThread : the thread which performs the action |
michael@0 | 644 | /* @param aURLShortcut : Differentiates between (false)Jumplistcache and (true)Shortcutcache |
michael@0 | 645 | /************************************************************************/ |
michael@0 | 646 | |
michael@0 | 647 | AsyncFaviconDataReady::AsyncFaviconDataReady(nsIURI *aNewURI, |
michael@0 | 648 | nsCOMPtr<nsIThread> &aIOThread, |
michael@0 | 649 | const bool aURLShortcut): |
michael@0 | 650 | mNewURI(aNewURI), |
michael@0 | 651 | mIOThread(aIOThread), |
michael@0 | 652 | mURLShortcut(aURLShortcut) |
michael@0 | 653 | { |
michael@0 | 654 | } |
michael@0 | 655 | |
michael@0 | 656 | NS_IMETHODIMP |
michael@0 | 657 | myDownloadObserver::OnDownloadComplete(nsIDownloader *downloader, |
michael@0 | 658 | nsIRequest *request, |
michael@0 | 659 | nsISupports *ctxt, |
michael@0 | 660 | nsresult status, |
michael@0 | 661 | nsIFile *result) |
michael@0 | 662 | { |
michael@0 | 663 | return NS_OK; |
michael@0 | 664 | } |
michael@0 | 665 | |
michael@0 | 666 | nsresult AsyncFaviconDataReady::OnFaviconDataNotAvailable(void) |
michael@0 | 667 | { |
michael@0 | 668 | if (!mURLShortcut) { |
michael@0 | 669 | return NS_OK; |
michael@0 | 670 | } |
michael@0 | 671 | |
michael@0 | 672 | nsCOMPtr<nsIFile> icoFile; |
michael@0 | 673 | nsresult rv = FaviconHelper::GetOutputIconPath(mNewURI, icoFile, mURLShortcut); |
michael@0 | 674 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 675 | |
michael@0 | 676 | nsCOMPtr<nsIURI> mozIconURI; |
michael@0 | 677 | rv = NS_NewURI(getter_AddRefs(mozIconURI), "moz-icon://.html?size=32"); |
michael@0 | 678 | if (NS_FAILED(rv)) { |
michael@0 | 679 | return rv; |
michael@0 | 680 | } |
michael@0 | 681 | |
michael@0 | 682 | nsCOMPtr<nsIChannel> channel; |
michael@0 | 683 | rv = NS_NewChannel(getter_AddRefs(channel), mozIconURI); |
michael@0 | 684 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 685 | |
michael@0 | 686 | nsCOMPtr<nsIDownloadObserver> downloadObserver = new myDownloadObserver; |
michael@0 | 687 | nsCOMPtr<nsIStreamListener> listener; |
michael@0 | 688 | rv = NS_NewDownloader(getter_AddRefs(listener), downloadObserver, icoFile); |
michael@0 | 689 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 690 | |
michael@0 | 691 | channel->AsyncOpen(listener, nullptr); |
michael@0 | 692 | return NS_OK; |
michael@0 | 693 | } |
michael@0 | 694 | |
michael@0 | 695 | NS_IMETHODIMP |
michael@0 | 696 | AsyncFaviconDataReady::OnComplete(nsIURI *aFaviconURI, |
michael@0 | 697 | uint32_t aDataLen, |
michael@0 | 698 | const uint8_t *aData, |
michael@0 | 699 | const nsACString &aMimeType) |
michael@0 | 700 | { |
michael@0 | 701 | if (!aDataLen || !aData) { |
michael@0 | 702 | if (mURLShortcut) { |
michael@0 | 703 | OnFaviconDataNotAvailable(); |
michael@0 | 704 | } |
michael@0 | 705 | |
michael@0 | 706 | return NS_OK; |
michael@0 | 707 | } |
michael@0 | 708 | |
michael@0 | 709 | nsCOMPtr<nsIFile> icoFile; |
michael@0 | 710 | nsresult rv = FaviconHelper::GetOutputIconPath(mNewURI, icoFile, mURLShortcut); |
michael@0 | 711 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 712 | |
michael@0 | 713 | nsAutoString path; |
michael@0 | 714 | rv = icoFile->GetPath(path); |
michael@0 | 715 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 716 | |
michael@0 | 717 | // Convert the obtained favicon data to an input stream |
michael@0 | 718 | nsCOMPtr<nsIInputStream> stream; |
michael@0 | 719 | rv = NS_NewByteInputStream(getter_AddRefs(stream), |
michael@0 | 720 | reinterpret_cast<const char*>(aData), |
michael@0 | 721 | aDataLen, |
michael@0 | 722 | NS_ASSIGNMENT_DEPEND); |
michael@0 | 723 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 724 | |
michael@0 | 725 | // Decode the image from the format it was returned to us in (probably PNG) |
michael@0 | 726 | nsAutoCString mimeTypeOfInputData; |
michael@0 | 727 | mimeTypeOfInputData.AssignLiteral("image/vnd.microsoft.icon"); |
michael@0 | 728 | nsCOMPtr<imgIContainer> container; |
michael@0 | 729 | nsCOMPtr<imgITools> imgtool = do_CreateInstance("@mozilla.org/image/tools;1"); |
michael@0 | 730 | rv = imgtool->DecodeImageData(stream, aMimeType, |
michael@0 | 731 | getter_AddRefs(container)); |
michael@0 | 732 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 733 | |
michael@0 | 734 | RefPtr<SourceSurface> surface = |
michael@0 | 735 | container->GetFrame(imgIContainer::FRAME_FIRST, 0); |
michael@0 | 736 | NS_ENSURE_TRUE(surface, NS_ERROR_FAILURE); |
michael@0 | 737 | |
michael@0 | 738 | RefPtr<DataSourceSurface> dataSurface; |
michael@0 | 739 | IntSize size; |
michael@0 | 740 | |
michael@0 | 741 | if (mURLShortcut) { |
michael@0 | 742 | // Create a 48x48 surface and paint the icon into the central 16x16 rect. |
michael@0 | 743 | size.width = 48; |
michael@0 | 744 | size.height = 48; |
michael@0 | 745 | dataSurface = |
michael@0 | 746 | Factory::CreateDataSourceSurface(size, SurfaceFormat::B8G8R8A8); |
michael@0 | 747 | NS_ENSURE_TRUE(dataSurface, NS_ERROR_FAILURE); |
michael@0 | 748 | |
michael@0 | 749 | DataSourceSurface::MappedSurface map; |
michael@0 | 750 | if (!dataSurface->Map(DataSourceSurface::MapType::WRITE, &map)) { |
michael@0 | 751 | return NS_ERROR_FAILURE; |
michael@0 | 752 | } |
michael@0 | 753 | |
michael@0 | 754 | RefPtr<DrawTarget> dt = |
michael@0 | 755 | Factory::CreateDrawTargetForData(BackendType::CAIRO, |
michael@0 | 756 | map.mData, |
michael@0 | 757 | dataSurface->GetSize(), |
michael@0 | 758 | map.mStride, |
michael@0 | 759 | dataSurface->GetFormat()); |
michael@0 | 760 | dt->FillRect(Rect(0, 0, size.width, size.height), |
michael@0 | 761 | ColorPattern(Color(1.0f, 1.0f, 1.0f, 1.0f))); |
michael@0 | 762 | dt->DrawSurface(surface, |
michael@0 | 763 | Rect(16, 16, 16, 16), |
michael@0 | 764 | Rect(Point(0, 0), |
michael@0 | 765 | Size(surface->GetSize().width, surface->GetSize().height))); |
michael@0 | 766 | |
michael@0 | 767 | dataSurface->Unmap(); |
michael@0 | 768 | } else { |
michael@0 | 769 | // By using the input image surface's size, we may end up encoding |
michael@0 | 770 | // to a different size than a 16x16 (or bigger for higher DPI) ICO, but |
michael@0 | 771 | // Windows will resize appropriately for us. If we want to encode ourselves |
michael@0 | 772 | // one day because we like our resizing better, we'd have to manually |
michael@0 | 773 | // resize the image here and use GetSystemMetrics w/ SM_CXSMICON and |
michael@0 | 774 | // SM_CYSMICON. We don't support resizing images asynchronously at the |
michael@0 | 775 | // moment anyway so getting the DPI aware icon size won't help. |
michael@0 | 776 | size.width = surface->GetSize().width; |
michael@0 | 777 | size.height = surface->GetSize().height; |
michael@0 | 778 | dataSurface = surface->GetDataSurface(); |
michael@0 | 779 | NS_ENSURE_TRUE(dataSurface, NS_ERROR_FAILURE); |
michael@0 | 780 | } |
michael@0 | 781 | |
michael@0 | 782 | // Allocate a new buffer that we own and can use out of line in |
michael@0 | 783 | // another thread. |
michael@0 | 784 | uint8_t *data = SurfaceToPackedBGRA(dataSurface); |
michael@0 | 785 | if (!data) { |
michael@0 | 786 | return NS_ERROR_OUT_OF_MEMORY; |
michael@0 | 787 | } |
michael@0 | 788 | int32_t stride = 4 * size.width; |
michael@0 | 789 | int32_t dataLength = stride * size.height; |
michael@0 | 790 | |
michael@0 | 791 | // AsyncEncodeAndWriteIcon takes ownership of the heap allocated buffer |
michael@0 | 792 | nsCOMPtr<nsIRunnable> event = new AsyncEncodeAndWriteIcon(path, data, |
michael@0 | 793 | dataLength, |
michael@0 | 794 | stride, |
michael@0 | 795 | size.width, |
michael@0 | 796 | size.height, |
michael@0 | 797 | mURLShortcut); |
michael@0 | 798 | mIOThread->Dispatch(event, NS_DISPATCH_NORMAL); |
michael@0 | 799 | |
michael@0 | 800 | return NS_OK; |
michael@0 | 801 | } |
michael@0 | 802 | #endif |
michael@0 | 803 | |
michael@0 | 804 | // Warning: AsyncEncodeAndWriteIcon assumes ownership of the aData buffer passed in |
michael@0 | 805 | AsyncEncodeAndWriteIcon::AsyncEncodeAndWriteIcon(const nsAString &aIconPath, |
michael@0 | 806 | uint8_t *aBuffer, |
michael@0 | 807 | uint32_t aBufferLength, |
michael@0 | 808 | uint32_t aStride, |
michael@0 | 809 | uint32_t aWidth, |
michael@0 | 810 | uint32_t aHeight, |
michael@0 | 811 | const bool aURLShortcut) : |
michael@0 | 812 | mURLShortcut(aURLShortcut), |
michael@0 | 813 | mIconPath(aIconPath), |
michael@0 | 814 | mBuffer(aBuffer), |
michael@0 | 815 | mBufferLength(aBufferLength), |
michael@0 | 816 | mStride(aStride), |
michael@0 | 817 | mWidth(aWidth), |
michael@0 | 818 | mHeight(aHeight) |
michael@0 | 819 | { |
michael@0 | 820 | } |
michael@0 | 821 | |
michael@0 | 822 | NS_IMETHODIMP AsyncEncodeAndWriteIcon::Run() |
michael@0 | 823 | { |
michael@0 | 824 | NS_PRECONDITION(!NS_IsMainThread(), "Should not be called on the main thread."); |
michael@0 | 825 | |
michael@0 | 826 | nsCOMPtr<nsIInputStream> iconStream; |
michael@0 | 827 | nsRefPtr<imgIEncoder> encoder = |
michael@0 | 828 | do_CreateInstance("@mozilla.org/image/encoder;2?" |
michael@0 | 829 | "type=image/vnd.microsoft.icon"); |
michael@0 | 830 | NS_ENSURE_TRUE(encoder, NS_ERROR_FAILURE); |
michael@0 | 831 | nsresult rv = encoder->InitFromData(mBuffer, mBufferLength, |
michael@0 | 832 | mWidth, mHeight, |
michael@0 | 833 | mStride, |
michael@0 | 834 | imgIEncoder::INPUT_FORMAT_HOSTARGB, |
michael@0 | 835 | EmptyString()); |
michael@0 | 836 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 837 | CallQueryInterface(encoder.get(), getter_AddRefs(iconStream)); |
michael@0 | 838 | if (!iconStream) { |
michael@0 | 839 | return NS_ERROR_FAILURE; |
michael@0 | 840 | } |
michael@0 | 841 | |
michael@0 | 842 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 843 | nsCOMPtr<nsIFile> icoFile |
michael@0 | 844 | = do_CreateInstance("@mozilla.org/file/local;1"); |
michael@0 | 845 | NS_ENSURE_TRUE(icoFile, NS_ERROR_FAILURE); |
michael@0 | 846 | rv = icoFile->InitWithPath(mIconPath); |
michael@0 | 847 | |
michael@0 | 848 | // Try to create the directory if it's not there yet |
michael@0 | 849 | nsCOMPtr<nsIFile> dirPath; |
michael@0 | 850 | icoFile->GetParent(getter_AddRefs(dirPath)); |
michael@0 | 851 | rv = (dirPath->Create(nsIFile::DIRECTORY_TYPE, 0777)); |
michael@0 | 852 | if (NS_FAILED(rv) && rv != NS_ERROR_FILE_ALREADY_EXISTS) { |
michael@0 | 853 | return rv; |
michael@0 | 854 | } |
michael@0 | 855 | |
michael@0 | 856 | // Setup the output stream for the ICO file on disk |
michael@0 | 857 | nsCOMPtr<nsIOutputStream> outputStream; |
michael@0 | 858 | rv = NS_NewLocalFileOutputStream(getter_AddRefs(outputStream), icoFile); |
michael@0 | 859 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 860 | |
michael@0 | 861 | // Obtain the ICO buffer size from the re-encoded ICO stream |
michael@0 | 862 | uint64_t bufSize64; |
michael@0 | 863 | rv = iconStream->Available(&bufSize64); |
michael@0 | 864 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 865 | NS_ENSURE_TRUE(bufSize64 <= UINT32_MAX, NS_ERROR_FILE_TOO_BIG); |
michael@0 | 866 | |
michael@0 | 867 | uint32_t bufSize = (uint32_t)bufSize64; |
michael@0 | 868 | |
michael@0 | 869 | // Setup a buffered output stream from the stream object |
michael@0 | 870 | // so that we can simply use WriteFrom with the stream object |
michael@0 | 871 | nsCOMPtr<nsIOutputStream> bufferedOutputStream; |
michael@0 | 872 | rv = NS_NewBufferedOutputStream(getter_AddRefs(bufferedOutputStream), |
michael@0 | 873 | outputStream, bufSize); |
michael@0 | 874 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 875 | |
michael@0 | 876 | // Write out the icon stream to disk and make sure we wrote everything |
michael@0 | 877 | uint32_t wrote; |
michael@0 | 878 | rv = bufferedOutputStream->WriteFrom(iconStream, bufSize, &wrote); |
michael@0 | 879 | NS_ASSERTION(bufSize == wrote, |
michael@0 | 880 | "Icon wrote size should be equal to requested write size"); |
michael@0 | 881 | |
michael@0 | 882 | // Cleanup |
michael@0 | 883 | bufferedOutputStream->Close(); |
michael@0 | 884 | outputStream->Close(); |
michael@0 | 885 | if (mURLShortcut) { |
michael@0 | 886 | SendMessage(HWND_BROADCAST, WM_SETTINGCHANGE, SPI_SETNONCLIENTMETRICS, 0); |
michael@0 | 887 | } |
michael@0 | 888 | return rv; |
michael@0 | 889 | } |
michael@0 | 890 | |
michael@0 | 891 | AsyncEncodeAndWriteIcon::~AsyncEncodeAndWriteIcon() |
michael@0 | 892 | { |
michael@0 | 893 | } |
michael@0 | 894 | |
michael@0 | 895 | AsyncDeleteIconFromDisk::AsyncDeleteIconFromDisk(const nsAString &aIconPath) |
michael@0 | 896 | : mIconPath(aIconPath) |
michael@0 | 897 | { |
michael@0 | 898 | } |
michael@0 | 899 | |
michael@0 | 900 | NS_IMETHODIMP AsyncDeleteIconFromDisk::Run() |
michael@0 | 901 | { |
michael@0 | 902 | // Construct the parent path of the passed in path |
michael@0 | 903 | nsCOMPtr<nsIFile> icoFile = do_CreateInstance("@mozilla.org/file/local;1"); |
michael@0 | 904 | NS_ENSURE_TRUE(icoFile, NS_ERROR_FAILURE); |
michael@0 | 905 | nsresult rv = icoFile->InitWithPath(mIconPath); |
michael@0 | 906 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 907 | |
michael@0 | 908 | // Check if the cached ICO file exists |
michael@0 | 909 | bool exists; |
michael@0 | 910 | rv = icoFile->Exists(&exists); |
michael@0 | 911 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 912 | |
michael@0 | 913 | // Check that we aren't deleting some arbitrary file that is not an icon |
michael@0 | 914 | if (StringTail(mIconPath, 4).LowerCaseEqualsASCII(".ico")) { |
michael@0 | 915 | // Check if the cached ICO file exists |
michael@0 | 916 | bool exists; |
michael@0 | 917 | if (NS_FAILED(icoFile->Exists(&exists)) || !exists) |
michael@0 | 918 | return NS_ERROR_FAILURE; |
michael@0 | 919 | |
michael@0 | 920 | // We found an ICO file that exists, so we should remove it |
michael@0 | 921 | icoFile->Remove(false); |
michael@0 | 922 | } |
michael@0 | 923 | |
michael@0 | 924 | return NS_OK; |
michael@0 | 925 | } |
michael@0 | 926 | |
michael@0 | 927 | AsyncDeleteIconFromDisk::~AsyncDeleteIconFromDisk() |
michael@0 | 928 | { |
michael@0 | 929 | } |
michael@0 | 930 | |
michael@0 | 931 | AsyncDeleteAllFaviconsFromDisk::AsyncDeleteAllFaviconsFromDisk() |
michael@0 | 932 | { |
michael@0 | 933 | } |
michael@0 | 934 | |
michael@0 | 935 | NS_IMETHODIMP AsyncDeleteAllFaviconsFromDisk::Run() |
michael@0 | 936 | { |
michael@0 | 937 | // Construct the path of our jump list cache |
michael@0 | 938 | nsCOMPtr<nsIFile> jumpListCacheDir; |
michael@0 | 939 | nsresult rv = NS_GetSpecialDirectory("ProfLDS", |
michael@0 | 940 | getter_AddRefs(jumpListCacheDir)); |
michael@0 | 941 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 942 | rv = jumpListCacheDir->AppendNative( |
michael@0 | 943 | nsDependentCString(FaviconHelper::kJumpListCacheDir)); |
michael@0 | 944 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 945 | nsCOMPtr<nsISimpleEnumerator> entries; |
michael@0 | 946 | rv = jumpListCacheDir->GetDirectoryEntries(getter_AddRefs(entries)); |
michael@0 | 947 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 948 | |
michael@0 | 949 | // Loop through each directory entry and remove all ICO files found |
michael@0 | 950 | do { |
michael@0 | 951 | bool hasMore = false; |
michael@0 | 952 | if (NS_FAILED(entries->HasMoreElements(&hasMore)) || !hasMore) |
michael@0 | 953 | break; |
michael@0 | 954 | |
michael@0 | 955 | nsCOMPtr<nsISupports> supp; |
michael@0 | 956 | if (NS_FAILED(entries->GetNext(getter_AddRefs(supp)))) |
michael@0 | 957 | break; |
michael@0 | 958 | |
michael@0 | 959 | nsCOMPtr<nsIFile> currFile(do_QueryInterface(supp)); |
michael@0 | 960 | nsAutoString path; |
michael@0 | 961 | if (NS_FAILED(currFile->GetPath(path))) |
michael@0 | 962 | continue; |
michael@0 | 963 | |
michael@0 | 964 | if (StringTail(path, 4).LowerCaseEqualsASCII(".ico")) { |
michael@0 | 965 | // Check if the cached ICO file exists |
michael@0 | 966 | bool exists; |
michael@0 | 967 | if (NS_FAILED(currFile->Exists(&exists)) || !exists) |
michael@0 | 968 | continue; |
michael@0 | 969 | |
michael@0 | 970 | // We found an ICO file that exists, so we should remove it |
michael@0 | 971 | currFile->Remove(false); |
michael@0 | 972 | } |
michael@0 | 973 | } while(true); |
michael@0 | 974 | |
michael@0 | 975 | return NS_OK; |
michael@0 | 976 | } |
michael@0 | 977 | |
michael@0 | 978 | AsyncDeleteAllFaviconsFromDisk::~AsyncDeleteAllFaviconsFromDisk() |
michael@0 | 979 | { |
michael@0 | 980 | } |
michael@0 | 981 | |
michael@0 | 982 | |
michael@0 | 983 | /* |
michael@0 | 984 | * (static) If the data is available, will return the path on disk where |
michael@0 | 985 | * the favicon for page aFaviconPageURI is stored. If the favicon does not |
michael@0 | 986 | * exist, or its cache is expired, this method will kick off an async request |
michael@0 | 987 | * for the icon so that next time the method is called it will be available. |
michael@0 | 988 | * @param aFaviconPageURI The URI of the page to obtain |
michael@0 | 989 | * @param aICOFilePath The path of the icon file |
michael@0 | 990 | * @param aIOThread The thread to perform the Fetch on |
michael@0 | 991 | * @param aURLShortcut to distinguish between jumplistcache(false) and shortcutcache(true) |
michael@0 | 992 | */ |
michael@0 | 993 | nsresult FaviconHelper::ObtainCachedIconFile(nsCOMPtr<nsIURI> aFaviconPageURI, |
michael@0 | 994 | nsString &aICOFilePath, |
michael@0 | 995 | nsCOMPtr<nsIThread> &aIOThread, |
michael@0 | 996 | bool aURLShortcut) |
michael@0 | 997 | { |
michael@0 | 998 | // Obtain the ICO file path |
michael@0 | 999 | nsCOMPtr<nsIFile> icoFile; |
michael@0 | 1000 | nsresult rv = GetOutputIconPath(aFaviconPageURI, icoFile, aURLShortcut); |
michael@0 | 1001 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 1002 | |
michael@0 | 1003 | // Check if the cached ICO file already exists |
michael@0 | 1004 | bool exists; |
michael@0 | 1005 | rv = icoFile->Exists(&exists); |
michael@0 | 1006 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 1007 | |
michael@0 | 1008 | if (exists) { |
michael@0 | 1009 | |
michael@0 | 1010 | // Obtain the file's last modification date in seconds |
michael@0 | 1011 | int64_t fileModTime = 0; |
michael@0 | 1012 | rv = icoFile->GetLastModifiedTime(&fileModTime); |
michael@0 | 1013 | fileModTime /= PR_MSEC_PER_SEC; |
michael@0 | 1014 | int32_t icoReCacheSecondsTimeout = GetICOCacheSecondsTimeout(); |
michael@0 | 1015 | int64_t nowTime = PR_Now() / int64_t(PR_USEC_PER_SEC); |
michael@0 | 1016 | |
michael@0 | 1017 | // If the last mod call failed or the icon is old then re-cache it |
michael@0 | 1018 | // This check is in case the favicon of a page changes |
michael@0 | 1019 | // the next time we try to build the jump list, the data will be available. |
michael@0 | 1020 | if (NS_FAILED(rv) || |
michael@0 | 1021 | (nowTime - fileModTime) > icoReCacheSecondsTimeout) { |
michael@0 | 1022 | CacheIconFileFromFaviconURIAsync(aFaviconPageURI, icoFile, aIOThread, aURLShortcut); |
michael@0 | 1023 | return NS_ERROR_NOT_AVAILABLE; |
michael@0 | 1024 | } |
michael@0 | 1025 | } else { |
michael@0 | 1026 | |
michael@0 | 1027 | // The file does not exist yet, obtain it async from the favicon service so that |
michael@0 | 1028 | // the next time we try to build the jump list it'll be available. |
michael@0 | 1029 | CacheIconFileFromFaviconURIAsync(aFaviconPageURI, icoFile, aIOThread, aURLShortcut); |
michael@0 | 1030 | return NS_ERROR_NOT_AVAILABLE; |
michael@0 | 1031 | } |
michael@0 | 1032 | |
michael@0 | 1033 | // The icoFile is filled with a path that exists, get its path |
michael@0 | 1034 | rv = icoFile->GetPath(aICOFilePath); |
michael@0 | 1035 | return rv; |
michael@0 | 1036 | } |
michael@0 | 1037 | |
michael@0 | 1038 | nsresult FaviconHelper::HashURI(nsCOMPtr<nsICryptoHash> &aCryptoHash, |
michael@0 | 1039 | nsIURI *aUri, |
michael@0 | 1040 | nsACString& aUriHash) |
michael@0 | 1041 | { |
michael@0 | 1042 | if (!aUri) |
michael@0 | 1043 | return NS_ERROR_INVALID_ARG; |
michael@0 | 1044 | |
michael@0 | 1045 | nsAutoCString spec; |
michael@0 | 1046 | nsresult rv = aUri->GetSpec(spec); |
michael@0 | 1047 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 1048 | |
michael@0 | 1049 | if (!aCryptoHash) { |
michael@0 | 1050 | aCryptoHash = do_CreateInstance(NS_CRYPTO_HASH_CONTRACTID, &rv); |
michael@0 | 1051 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 1052 | } |
michael@0 | 1053 | |
michael@0 | 1054 | rv = aCryptoHash->Init(nsICryptoHash::MD5); |
michael@0 | 1055 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 1056 | rv = aCryptoHash->Update(reinterpret_cast<const uint8_t*>(spec.BeginReading()), |
michael@0 | 1057 | spec.Length()); |
michael@0 | 1058 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 1059 | rv = aCryptoHash->Finish(true, aUriHash); |
michael@0 | 1060 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 1061 | |
michael@0 | 1062 | return NS_OK; |
michael@0 | 1063 | } |
michael@0 | 1064 | |
michael@0 | 1065 | |
michael@0 | 1066 | |
michael@0 | 1067 | // (static) Obtains the ICO file for the favicon at page aFaviconPageURI |
michael@0 | 1068 | // If successful, the file path on disk is in the format: |
michael@0 | 1069 | // <ProfLDS>\jumpListCache\<hash(aFaviconPageURI)>.ico |
michael@0 | 1070 | nsresult FaviconHelper::GetOutputIconPath(nsCOMPtr<nsIURI> aFaviconPageURI, |
michael@0 | 1071 | nsCOMPtr<nsIFile> &aICOFile, |
michael@0 | 1072 | bool aURLShortcut) |
michael@0 | 1073 | { |
michael@0 | 1074 | // Hash the input URI and replace any / with _ |
michael@0 | 1075 | nsAutoCString inputURIHash; |
michael@0 | 1076 | nsCOMPtr<nsICryptoHash> cryptoHash; |
michael@0 | 1077 | nsresult rv = HashURI(cryptoHash, aFaviconPageURI, |
michael@0 | 1078 | inputURIHash); |
michael@0 | 1079 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 1080 | char* cur = inputURIHash.BeginWriting(); |
michael@0 | 1081 | char* end = inputURIHash.EndWriting(); |
michael@0 | 1082 | for (; cur < end; ++cur) { |
michael@0 | 1083 | if ('/' == *cur) { |
michael@0 | 1084 | *cur = '_'; |
michael@0 | 1085 | } |
michael@0 | 1086 | } |
michael@0 | 1087 | |
michael@0 | 1088 | // Obtain the local profile directory and construct the output icon file path |
michael@0 | 1089 | rv = NS_GetSpecialDirectory("ProfLDS", getter_AddRefs(aICOFile)); |
michael@0 | 1090 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 1091 | if (!aURLShortcut) |
michael@0 | 1092 | rv = aICOFile->AppendNative(nsDependentCString(kJumpListCacheDir)); |
michael@0 | 1093 | else |
michael@0 | 1094 | rv = aICOFile->AppendNative(nsDependentCString(kShortcutCacheDir)); |
michael@0 | 1095 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 1096 | |
michael@0 | 1097 | // Append the icon extension |
michael@0 | 1098 | inputURIHash.Append(".ico"); |
michael@0 | 1099 | rv = aICOFile->AppendNative(inputURIHash); |
michael@0 | 1100 | |
michael@0 | 1101 | return rv; |
michael@0 | 1102 | } |
michael@0 | 1103 | |
michael@0 | 1104 | // (static) Asynchronously creates a cached ICO file on disk for the favicon of |
michael@0 | 1105 | // page aFaviconPageURI and stores it to disk at the path of aICOFile. |
michael@0 | 1106 | nsresult |
michael@0 | 1107 | FaviconHelper::CacheIconFileFromFaviconURIAsync(nsCOMPtr<nsIURI> aFaviconPageURI, |
michael@0 | 1108 | nsCOMPtr<nsIFile> aICOFile, |
michael@0 | 1109 | nsCOMPtr<nsIThread> &aIOThread, |
michael@0 | 1110 | bool aURLShortcut) |
michael@0 | 1111 | { |
michael@0 | 1112 | #ifdef MOZ_PLACES |
michael@0 | 1113 | // Obtain the favicon service and get the favicon for the specified page |
michael@0 | 1114 | nsCOMPtr<mozIAsyncFavicons> favIconSvc( |
michael@0 | 1115 | do_GetService("@mozilla.org/browser/favicon-service;1")); |
michael@0 | 1116 | NS_ENSURE_TRUE(favIconSvc, NS_ERROR_FAILURE); |
michael@0 | 1117 | |
michael@0 | 1118 | nsCOMPtr<nsIFaviconDataCallback> callback = |
michael@0 | 1119 | new mozilla::widget::AsyncFaviconDataReady(aFaviconPageURI, |
michael@0 | 1120 | aIOThread, |
michael@0 | 1121 | aURLShortcut); |
michael@0 | 1122 | |
michael@0 | 1123 | favIconSvc->GetFaviconDataForPage(aFaviconPageURI, callback); |
michael@0 | 1124 | #endif |
michael@0 | 1125 | return NS_OK; |
michael@0 | 1126 | } |
michael@0 | 1127 | |
michael@0 | 1128 | // Obtains the jump list 'ICO cache timeout in seconds' pref |
michael@0 | 1129 | int32_t FaviconHelper::GetICOCacheSecondsTimeout() { |
michael@0 | 1130 | |
michael@0 | 1131 | // Only obtain the setting at most once from the pref service. |
michael@0 | 1132 | // In the rare case that 2 threads call this at the same |
michael@0 | 1133 | // time it is no harm and we will simply obtain the pref twice. |
michael@0 | 1134 | // None of the taskbar list prefs are currently updated via a |
michael@0 | 1135 | // pref observer so I think this should suffice. |
michael@0 | 1136 | const int32_t kSecondsPerDay = 86400; |
michael@0 | 1137 | static bool alreadyObtained = false; |
michael@0 | 1138 | static int32_t icoReCacheSecondsTimeout = kSecondsPerDay; |
michael@0 | 1139 | if (alreadyObtained) { |
michael@0 | 1140 | return icoReCacheSecondsTimeout; |
michael@0 | 1141 | } |
michael@0 | 1142 | |
michael@0 | 1143 | // Obtain the pref |
michael@0 | 1144 | const char PREF_ICOTIMEOUT[] = "browser.taskbar.lists.icoTimeoutInSeconds"; |
michael@0 | 1145 | icoReCacheSecondsTimeout = Preferences::GetInt(PREF_ICOTIMEOUT, |
michael@0 | 1146 | kSecondsPerDay); |
michael@0 | 1147 | alreadyObtained = true; |
michael@0 | 1148 | return icoReCacheSecondsTimeout; |
michael@0 | 1149 | } |
michael@0 | 1150 | |
michael@0 | 1151 | |
michael@0 | 1152 | |
michael@0 | 1153 | |
michael@0 | 1154 | /* static */ |
michael@0 | 1155 | bool |
michael@0 | 1156 | WinUtils::GetShellItemPath(IShellItem* aItem, |
michael@0 | 1157 | nsString& aResultString) |
michael@0 | 1158 | { |
michael@0 | 1159 | NS_ENSURE_TRUE(aItem, false); |
michael@0 | 1160 | LPWSTR str = nullptr; |
michael@0 | 1161 | if (FAILED(aItem->GetDisplayName(SIGDN_FILESYSPATH, &str))) |
michael@0 | 1162 | return false; |
michael@0 | 1163 | aResultString.Assign(str); |
michael@0 | 1164 | CoTaskMemFree(str); |
michael@0 | 1165 | return !aResultString.IsEmpty(); |
michael@0 | 1166 | } |
michael@0 | 1167 | |
michael@0 | 1168 | /* static */ |
michael@0 | 1169 | nsIntRegion |
michael@0 | 1170 | WinUtils::ConvertHRGNToRegion(HRGN aRgn) |
michael@0 | 1171 | { |
michael@0 | 1172 | NS_ASSERTION(aRgn, "Don't pass NULL region here"); |
michael@0 | 1173 | |
michael@0 | 1174 | nsIntRegion rgn; |
michael@0 | 1175 | |
michael@0 | 1176 | DWORD size = ::GetRegionData(aRgn, 0, nullptr); |
michael@0 | 1177 | nsAutoTArray<uint8_t,100> buffer; |
michael@0 | 1178 | buffer.SetLength(size); |
michael@0 | 1179 | |
michael@0 | 1180 | RGNDATA* data = reinterpret_cast<RGNDATA*>(buffer.Elements()); |
michael@0 | 1181 | if (!::GetRegionData(aRgn, size, data)) |
michael@0 | 1182 | return rgn; |
michael@0 | 1183 | |
michael@0 | 1184 | if (data->rdh.nCount > MAX_RECTS_IN_REGION) { |
michael@0 | 1185 | rgn = ToIntRect(data->rdh.rcBound); |
michael@0 | 1186 | return rgn; |
michael@0 | 1187 | } |
michael@0 | 1188 | |
michael@0 | 1189 | RECT* rects = reinterpret_cast<RECT*>(data->Buffer); |
michael@0 | 1190 | for (uint32_t i = 0; i < data->rdh.nCount; ++i) { |
michael@0 | 1191 | RECT* r = rects + i; |
michael@0 | 1192 | rgn.Or(rgn, ToIntRect(*r)); |
michael@0 | 1193 | } |
michael@0 | 1194 | |
michael@0 | 1195 | return rgn; |
michael@0 | 1196 | } |
michael@0 | 1197 | |
michael@0 | 1198 | nsIntRect |
michael@0 | 1199 | WinUtils::ToIntRect(const RECT& aRect) |
michael@0 | 1200 | { |
michael@0 | 1201 | return nsIntRect(aRect.left, aRect.top, |
michael@0 | 1202 | aRect.right - aRect.left, |
michael@0 | 1203 | aRect.bottom - aRect.top); |
michael@0 | 1204 | } |
michael@0 | 1205 | |
michael@0 | 1206 | /* static */ |
michael@0 | 1207 | bool |
michael@0 | 1208 | WinUtils::IsIMEEnabled(const InputContext& aInputContext) |
michael@0 | 1209 | { |
michael@0 | 1210 | return IsIMEEnabled(aInputContext.mIMEState.mEnabled); |
michael@0 | 1211 | } |
michael@0 | 1212 | |
michael@0 | 1213 | /* static */ |
michael@0 | 1214 | bool |
michael@0 | 1215 | WinUtils::IsIMEEnabled(IMEState::Enabled aIMEState) |
michael@0 | 1216 | { |
michael@0 | 1217 | return (aIMEState == IMEState::ENABLED || |
michael@0 | 1218 | aIMEState == IMEState::PLUGIN); |
michael@0 | 1219 | } |
michael@0 | 1220 | |
michael@0 | 1221 | /* static */ |
michael@0 | 1222 | void |
michael@0 | 1223 | WinUtils::SetupKeyModifiersSequence(nsTArray<KeyPair>* aArray, |
michael@0 | 1224 | uint32_t aModifiers) |
michael@0 | 1225 | { |
michael@0 | 1226 | for (uint32_t i = 0; i < ArrayLength(sModifierKeyMap); ++i) { |
michael@0 | 1227 | const uint32_t* map = sModifierKeyMap[i]; |
michael@0 | 1228 | if (aModifiers & map[0]) { |
michael@0 | 1229 | aArray->AppendElement(KeyPair(map[1], map[2])); |
michael@0 | 1230 | } |
michael@0 | 1231 | } |
michael@0 | 1232 | } |
michael@0 | 1233 | |
michael@0 | 1234 | /* static */ |
michael@0 | 1235 | bool |
michael@0 | 1236 | WinUtils::ShouldHideScrollbars() |
michael@0 | 1237 | { |
michael@0 | 1238 | #ifdef MOZ_METRO |
michael@0 | 1239 | if (XRE_GetWindowsEnvironment() == WindowsEnvironmentType_Metro) { |
michael@0 | 1240 | return widget::winrt::MetroInput::IsInputModeImprecise(); |
michael@0 | 1241 | } |
michael@0 | 1242 | #endif // MOZ_METRO |
michael@0 | 1243 | return false; |
michael@0 | 1244 | } |
michael@0 | 1245 | |
michael@0 | 1246 | } // namespace widget |
michael@0 | 1247 | } // namespace mozilla |