widget/windows/WinUtils.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

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

mercurial