widget/windows/WinUtils.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/widget/windows/WinUtils.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1247 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* vim:set ts=2 sts=2 sw=2 et cin: */
     1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#include "WinUtils.h"
    1.11 +
    1.12 +#include "gfxPlatform.h"
    1.13 +#include "nsWindow.h"
    1.14 +#include "nsWindowDefs.h"
    1.15 +#include "KeyboardLayout.h"
    1.16 +#include "nsIDOMMouseEvent.h"
    1.17 +#include "mozilla/gfx/2D.h"
    1.18 +#include "mozilla/gfx/DataSurfaceHelpers.h"
    1.19 +#include "mozilla/Preferences.h"
    1.20 +#include "mozilla/RefPtr.h"
    1.21 +#include "mozilla/WindowsVersion.h"
    1.22 +
    1.23 +#ifdef MOZ_LOGGING
    1.24 +#define FORCE_PR_LOG /* Allow logging in the release build */
    1.25 +#endif // MOZ_LOGGING
    1.26 +#include "prlog.h"
    1.27 +
    1.28 +#include "nsString.h"
    1.29 +#include "nsDirectoryServiceUtils.h"
    1.30 +#include "imgIContainer.h"
    1.31 +#include "imgITools.h"
    1.32 +#include "nsStringStream.h"
    1.33 +#include "nsNetUtil.h"
    1.34 +#ifdef MOZ_PLACES
    1.35 +#include "mozIAsyncFavicons.h"
    1.36 +#endif
    1.37 +#include "nsIIconURI.h"
    1.38 +#include "nsIDownloader.h"
    1.39 +#include "nsINetUtil.h"
    1.40 +#include "nsIChannel.h"
    1.41 +#include "nsIObserver.h"
    1.42 +#include "imgIEncoder.h"
    1.43 +#include "nsIThread.h"
    1.44 +#include "MainThreadUtils.h"
    1.45 +#include "gfxColor.h"
    1.46 +#ifdef MOZ_METRO
    1.47 +#include "winrt/MetroInput.h"
    1.48 +#include "winrt/MetroUtils.h"
    1.49 +#endif // MOZ_METRO
    1.50 +
    1.51 +#ifdef NS_ENABLE_TSF
    1.52 +#include <textstor.h>
    1.53 +#include "nsTextStore.h"
    1.54 +#endif // #ifdef NS_ENABLE_TSF
    1.55 +
    1.56 +#ifdef PR_LOGGING
    1.57 +PRLogModuleInfo* gWindowsLog = nullptr;
    1.58 +#endif
    1.59 +
    1.60 +using namespace mozilla::gfx;
    1.61 +
    1.62 +namespace mozilla {
    1.63 +namespace widget {
    1.64 +
    1.65 +NS_IMPL_ISUPPORTS(myDownloadObserver, nsIDownloadObserver)
    1.66 +#ifdef MOZ_PLACES
    1.67 +NS_IMPL_ISUPPORTS(AsyncFaviconDataReady, nsIFaviconDataCallback)
    1.68 +#endif
    1.69 +NS_IMPL_ISUPPORTS(AsyncEncodeAndWriteIcon, nsIRunnable)
    1.70 +NS_IMPL_ISUPPORTS(AsyncDeleteIconFromDisk, nsIRunnable)
    1.71 +NS_IMPL_ISUPPORTS(AsyncDeleteAllFaviconsFromDisk, nsIRunnable)
    1.72 +
    1.73 +
    1.74 +const char FaviconHelper::kJumpListCacheDir[] = "jumpListCache";
    1.75 +const char FaviconHelper::kShortcutCacheDir[] = "shortcutCache";
    1.76 +
    1.77 +// apis available on vista and up.
    1.78 +WinUtils::SHCreateItemFromParsingNamePtr WinUtils::sCreateItemFromParsingName = nullptr;
    1.79 +WinUtils::SHGetKnownFolderPathPtr WinUtils::sGetKnownFolderPath = nullptr;
    1.80 +
    1.81 +// We just leak these DLL HMODULEs. There's no point in calling FreeLibrary
    1.82 +// on them during shutdown anyway.
    1.83 +static const wchar_t kShellLibraryName[] =  L"shell32.dll";
    1.84 +static HMODULE sShellDll = nullptr;
    1.85 +static const wchar_t kDwmLibraryName[] = L"dwmapi.dll";
    1.86 +static HMODULE sDwmDll = nullptr;
    1.87 +
    1.88 +WinUtils::DwmExtendFrameIntoClientAreaProc WinUtils::dwmExtendFrameIntoClientAreaPtr = nullptr;
    1.89 +WinUtils::DwmIsCompositionEnabledProc WinUtils::dwmIsCompositionEnabledPtr = nullptr;
    1.90 +WinUtils::DwmSetIconicThumbnailProc WinUtils::dwmSetIconicThumbnailPtr = nullptr;
    1.91 +WinUtils::DwmSetIconicLivePreviewBitmapProc WinUtils::dwmSetIconicLivePreviewBitmapPtr = nullptr;
    1.92 +WinUtils::DwmGetWindowAttributeProc WinUtils::dwmGetWindowAttributePtr = nullptr;
    1.93 +WinUtils::DwmSetWindowAttributeProc WinUtils::dwmSetWindowAttributePtr = nullptr;
    1.94 +WinUtils::DwmInvalidateIconicBitmapsProc WinUtils::dwmInvalidateIconicBitmapsPtr = nullptr;
    1.95 +WinUtils::DwmDefWindowProcProc WinUtils::dwmDwmDefWindowProcPtr = nullptr;
    1.96 +WinUtils::DwmGetCompositionTimingInfoProc WinUtils::dwmGetCompositionTimingInfoPtr = nullptr;
    1.97 +
    1.98 +/* static */
    1.99 +void
   1.100 +WinUtils::Initialize()
   1.101 +{
   1.102 +#ifdef PR_LOGGING
   1.103 +  if (!gWindowsLog) {
   1.104 +    gWindowsLog = PR_NewLogModule("Widget");
   1.105 +  }
   1.106 +#endif
   1.107 +  if (!sDwmDll && IsVistaOrLater()) {
   1.108 +    sDwmDll = ::LoadLibraryW(kDwmLibraryName);
   1.109 +
   1.110 +    if (sDwmDll) {
   1.111 +      dwmExtendFrameIntoClientAreaPtr = (DwmExtendFrameIntoClientAreaProc)::GetProcAddress(sDwmDll, "DwmExtendFrameIntoClientArea");
   1.112 +      dwmIsCompositionEnabledPtr = (DwmIsCompositionEnabledProc)::GetProcAddress(sDwmDll, "DwmIsCompositionEnabled");
   1.113 +      dwmSetIconicThumbnailPtr = (DwmSetIconicThumbnailProc)::GetProcAddress(sDwmDll, "DwmSetIconicThumbnail");
   1.114 +      dwmSetIconicLivePreviewBitmapPtr = (DwmSetIconicLivePreviewBitmapProc)::GetProcAddress(sDwmDll, "DwmSetIconicLivePreviewBitmap");
   1.115 +      dwmGetWindowAttributePtr = (DwmGetWindowAttributeProc)::GetProcAddress(sDwmDll, "DwmGetWindowAttribute");
   1.116 +      dwmSetWindowAttributePtr = (DwmSetWindowAttributeProc)::GetProcAddress(sDwmDll, "DwmSetWindowAttribute");
   1.117 +      dwmInvalidateIconicBitmapsPtr = (DwmInvalidateIconicBitmapsProc)::GetProcAddress(sDwmDll, "DwmInvalidateIconicBitmaps");
   1.118 +      dwmDwmDefWindowProcPtr = (DwmDefWindowProcProc)::GetProcAddress(sDwmDll, "DwmDefWindowProc");
   1.119 +      dwmGetCompositionTimingInfoPtr = (DwmGetCompositionTimingInfoProc)::GetProcAddress(sDwmDll, "DwmGetCompositionTimingInfo");
   1.120 +    }
   1.121 +  }
   1.122 +}
   1.123 +
   1.124 +// static
   1.125 +void
   1.126 +WinUtils::LogW(const wchar_t *fmt, ...)
   1.127 +{
   1.128 +  va_list args = nullptr;
   1.129 +  if(!lstrlenW(fmt)) {
   1.130 +    return;
   1.131 +  }
   1.132 +  va_start(args, fmt);
   1.133 +  int buflen = _vscwprintf(fmt, args);
   1.134 +  wchar_t* buffer = new wchar_t[buflen+1];
   1.135 +  if (!buffer) {
   1.136 +    va_end(args);
   1.137 +    return;
   1.138 +  }
   1.139 +  vswprintf(buffer, buflen, fmt, args);
   1.140 +  va_end(args);
   1.141 +
   1.142 +  // MSVC, including remote debug sessions
   1.143 +  OutputDebugStringW(buffer);
   1.144 +  OutputDebugStringW(L"\n");
   1.145 +
   1.146 +  int len = wcslen(buffer);
   1.147 +  if (len) {
   1.148 +    char* utf8 = new char[len+1];
   1.149 +    memset(utf8, 0, sizeof(utf8));
   1.150 +    if (WideCharToMultiByte(CP_ACP, 0, buffer,
   1.151 +                            -1, utf8, len+1, nullptr,
   1.152 +                            nullptr) > 0) {
   1.153 +      // desktop console
   1.154 +      printf("%s\n", utf8);
   1.155 +#ifdef PR_LOGGING
   1.156 +      NS_ASSERTION(gWindowsLog, "Called WinUtils Log() but Widget "
   1.157 +                                   "log module doesn't exist!");
   1.158 +      PR_LOG(gWindowsLog, PR_LOG_ALWAYS, (utf8));
   1.159 +#endif
   1.160 +    }
   1.161 +    delete[] utf8;
   1.162 +  }
   1.163 +  delete[] buffer;
   1.164 +}
   1.165 +
   1.166 +// static
   1.167 +void
   1.168 +WinUtils::Log(const char *fmt, ...)
   1.169 +{
   1.170 +  va_list args = nullptr;
   1.171 +  if(!strlen(fmt)) {
   1.172 +    return;
   1.173 +  }
   1.174 +  va_start(args, fmt);
   1.175 +  int buflen = _vscprintf(fmt, args);
   1.176 +  char* buffer = new char[buflen+1];
   1.177 +  if (!buffer) {
   1.178 +    va_end(args);
   1.179 +    return;
   1.180 +  }
   1.181 +  vsprintf(buffer, fmt, args);
   1.182 +  va_end(args);
   1.183 +
   1.184 +  // MSVC, including remote debug sessions
   1.185 +  OutputDebugStringA(buffer);
   1.186 +  OutputDebugStringW(L"\n");
   1.187 +
   1.188 +  // desktop console
   1.189 +  printf("%s\n", buffer);
   1.190 +
   1.191 +#ifdef PR_LOGGING
   1.192 +  NS_ASSERTION(gWindowsLog, "Called WinUtils Log() but Widget "
   1.193 +                               "log module doesn't exist!");
   1.194 +  PR_LOG(gWindowsLog, PR_LOG_ALWAYS, (buffer));
   1.195 +#endif
   1.196 +  delete[] buffer;
   1.197 +}
   1.198 +
   1.199 +/* static */
   1.200 +double
   1.201 +WinUtils::LogToPhysFactor()
   1.202 +{
   1.203 +  // dpi / 96.0
   1.204 +  if (XRE_GetWindowsEnvironment() == WindowsEnvironmentType_Metro) {
   1.205 +#ifdef MOZ_METRO
   1.206 +    return MetroUtils::LogToPhysFactor();
   1.207 +#else
   1.208 +    return 1.0;
   1.209 +#endif
   1.210 +  } else {
   1.211 +    HDC hdc = ::GetDC(nullptr);
   1.212 +    double result = ::GetDeviceCaps(hdc, LOGPIXELSY) / 96.0;
   1.213 +    ::ReleaseDC(nullptr, hdc);
   1.214 +    return result;
   1.215 +  }
   1.216 +}
   1.217 +
   1.218 +/* static */
   1.219 +double
   1.220 +WinUtils::PhysToLogFactor()
   1.221 +{
   1.222 +  // 1.0 / (dpi / 96.0)
   1.223 +  return 1.0 / LogToPhysFactor();
   1.224 +}
   1.225 +
   1.226 +/* static */
   1.227 +double
   1.228 +WinUtils::PhysToLog(int32_t aValue)
   1.229 +{
   1.230 +  return double(aValue) * PhysToLogFactor();
   1.231 +}
   1.232 +
   1.233 +/* static */
   1.234 +int32_t
   1.235 +WinUtils::LogToPhys(double aValue)
   1.236 +{
   1.237 +  return int32_t(NS_round(aValue * LogToPhysFactor()));
   1.238 +}
   1.239 +
   1.240 +/* static */
   1.241 +bool
   1.242 +WinUtils::PeekMessage(LPMSG aMsg, HWND aWnd, UINT aFirstMessage,
   1.243 +                      UINT aLastMessage, UINT aOption)
   1.244 +{
   1.245 +#ifdef NS_ENABLE_TSF
   1.246 +  ITfMessagePump* msgPump = nsTextStore::GetMessagePump();
   1.247 +  if (msgPump) {
   1.248 +    BOOL ret = FALSE;
   1.249 +    HRESULT hr = msgPump->PeekMessageW(aMsg, aWnd, aFirstMessage, aLastMessage,
   1.250 +                                       aOption, &ret);
   1.251 +    NS_ENSURE_TRUE(SUCCEEDED(hr), false);
   1.252 +    return ret;
   1.253 +  }
   1.254 +#endif // #ifdef NS_ENABLE_TSF
   1.255 +  return ::PeekMessageW(aMsg, aWnd, aFirstMessage, aLastMessage, aOption);
   1.256 +}
   1.257 +
   1.258 +/* static */
   1.259 +bool
   1.260 +WinUtils::GetMessage(LPMSG aMsg, HWND aWnd, UINT aFirstMessage,
   1.261 +                     UINT aLastMessage)
   1.262 +{
   1.263 +#ifdef NS_ENABLE_TSF
   1.264 +  ITfMessagePump* msgPump = nsTextStore::GetMessagePump();
   1.265 +  if (msgPump) {
   1.266 +    BOOL ret = FALSE;
   1.267 +    HRESULT hr = msgPump->GetMessageW(aMsg, aWnd, aFirstMessage, aLastMessage,
   1.268 +                                      &ret);
   1.269 +    NS_ENSURE_TRUE(SUCCEEDED(hr), false);
   1.270 +    return ret;
   1.271 +  }
   1.272 +#endif // #ifdef NS_ENABLE_TSF
   1.273 +  return ::GetMessageW(aMsg, aWnd, aFirstMessage, aLastMessage);
   1.274 +}
   1.275 +
   1.276 +/* static */
   1.277 +bool
   1.278 +WinUtils::GetRegistryKey(HKEY aRoot,
   1.279 +                         char16ptr_t aKeyName,
   1.280 +                         char16ptr_t aValueName,
   1.281 +                         wchar_t* aBuffer,
   1.282 +                         DWORD aBufferLength)
   1.283 +{
   1.284 +  NS_PRECONDITION(aKeyName, "The key name is NULL");
   1.285 +
   1.286 +  HKEY key;
   1.287 +  LONG result =
   1.288 +    ::RegOpenKeyExW(aRoot, aKeyName, 0, KEY_READ | KEY_WOW64_32KEY, &key);
   1.289 +  if (result != ERROR_SUCCESS) {
   1.290 +    result =
   1.291 +      ::RegOpenKeyExW(aRoot, aKeyName, 0, KEY_READ | KEY_WOW64_64KEY, &key);
   1.292 +    if (result != ERROR_SUCCESS) {
   1.293 +      return false;
   1.294 +    }
   1.295 +  }
   1.296 +
   1.297 +  DWORD type;
   1.298 +  result =
   1.299 +    ::RegQueryValueExW(key, aValueName, nullptr, &type, (BYTE*) aBuffer,
   1.300 +                       &aBufferLength);
   1.301 +  ::RegCloseKey(key);
   1.302 +  if (result != ERROR_SUCCESS || type != REG_SZ) {
   1.303 +    return false;
   1.304 +  }
   1.305 +  if (aBuffer) {
   1.306 +    aBuffer[aBufferLength / sizeof(*aBuffer) - 1] = 0;
   1.307 +  }
   1.308 +  return true;
   1.309 +}
   1.310 +
   1.311 +/* static */
   1.312 +bool
   1.313 +WinUtils::HasRegistryKey(HKEY aRoot, char16ptr_t aKeyName)
   1.314 +{
   1.315 +  MOZ_ASSERT(aRoot, "aRoot must not be NULL");
   1.316 +  MOZ_ASSERT(aKeyName, "aKeyName must not be NULL");
   1.317 +  HKEY key;
   1.318 +  LONG result =
   1.319 +    ::RegOpenKeyExW(aRoot, aKeyName, 0, KEY_READ | KEY_WOW64_32KEY, &key);
   1.320 +  if (result != ERROR_SUCCESS) {
   1.321 +    result =
   1.322 +      ::RegOpenKeyExW(aRoot, aKeyName, 0, KEY_READ | KEY_WOW64_64KEY, &key);
   1.323 +    if (result != ERROR_SUCCESS) {
   1.324 +      return false;
   1.325 +    }
   1.326 +  }
   1.327 +  ::RegCloseKey(key);
   1.328 +  return true;
   1.329 +}
   1.330 +
   1.331 +/* static */
   1.332 +HWND
   1.333 +WinUtils::GetTopLevelHWND(HWND aWnd,
   1.334 +                          bool aStopIfNotChild,
   1.335 +                          bool aStopIfNotPopup)
   1.336 +{
   1.337 +  HWND curWnd = aWnd;
   1.338 +  HWND topWnd = nullptr;
   1.339 +
   1.340 +  while (curWnd) {
   1.341 +    topWnd = curWnd;
   1.342 +
   1.343 +    if (aStopIfNotChild) {
   1.344 +      DWORD_PTR style = ::GetWindowLongPtrW(curWnd, GWL_STYLE);
   1.345 +
   1.346 +      VERIFY_WINDOW_STYLE(style);
   1.347 +
   1.348 +      if (!(style & WS_CHILD)) // first top-level window
   1.349 +        break;
   1.350 +    }
   1.351 +
   1.352 +    HWND upWnd = ::GetParent(curWnd); // Parent or owner (if has no parent)
   1.353 +
   1.354 +    // GetParent will only return the owner if the passed in window 
   1.355 +    // has the WS_POPUP style.
   1.356 +    if (!upWnd && !aStopIfNotPopup) {
   1.357 +      upWnd = ::GetWindow(curWnd, GW_OWNER);
   1.358 +    }
   1.359 +    curWnd = upWnd;
   1.360 +  }
   1.361 +
   1.362 +  return topWnd;
   1.363 +}
   1.364 +
   1.365 +static const wchar_t*
   1.366 +GetNSWindowPropName()
   1.367 +{
   1.368 +  static wchar_t sPropName[40] = L"";
   1.369 +  if (!*sPropName) {
   1.370 +    _snwprintf(sPropName, 39, L"MozillansIWidgetPtr%p",
   1.371 +               ::GetCurrentProcessId());
   1.372 +    sPropName[39] = '\0';
   1.373 +  }
   1.374 +  return sPropName;
   1.375 +}
   1.376 +
   1.377 +/* static */
   1.378 +bool
   1.379 +WinUtils::SetNSWindowBasePtr(HWND aWnd, nsWindowBase* aWidget)
   1.380 +{
   1.381 +  if (!aWidget) {
   1.382 +    ::RemovePropW(aWnd, GetNSWindowPropName());
   1.383 +    return true;
   1.384 +  }
   1.385 +  return ::SetPropW(aWnd, GetNSWindowPropName(), (HANDLE)aWidget);
   1.386 +}
   1.387 +
   1.388 +/* static */
   1.389 +nsWindowBase*
   1.390 +WinUtils::GetNSWindowBasePtr(HWND aWnd)
   1.391 +{
   1.392 +  return static_cast<nsWindowBase*>(::GetPropW(aWnd, GetNSWindowPropName()));
   1.393 +}
   1.394 +
   1.395 +/* static */
   1.396 +nsWindow*
   1.397 +WinUtils::GetNSWindowPtr(HWND aWnd)
   1.398 +{
   1.399 +  return static_cast<nsWindow*>(::GetPropW(aWnd, GetNSWindowPropName()));
   1.400 +}
   1.401 +
   1.402 +static BOOL CALLBACK
   1.403 +AddMonitor(HMONITOR, HDC, LPRECT, LPARAM aParam)
   1.404 +{
   1.405 +  (*(int32_t*)aParam)++;
   1.406 +  return TRUE;
   1.407 +}
   1.408 +
   1.409 +/* static */
   1.410 +int32_t
   1.411 +WinUtils::GetMonitorCount()
   1.412 +{
   1.413 +  int32_t monitorCount = 0;
   1.414 +  EnumDisplayMonitors(nullptr, nullptr, AddMonitor, (LPARAM)&monitorCount);
   1.415 +  return monitorCount;
   1.416 +}
   1.417 +
   1.418 +/* static */
   1.419 +bool
   1.420 +WinUtils::IsOurProcessWindow(HWND aWnd)
   1.421 +{
   1.422 +  if (!aWnd) {
   1.423 +    return false;
   1.424 +  }
   1.425 +  DWORD processId = 0;
   1.426 +  ::GetWindowThreadProcessId(aWnd, &processId);
   1.427 +  return (processId == ::GetCurrentProcessId());
   1.428 +}
   1.429 +
   1.430 +/* static */
   1.431 +HWND
   1.432 +WinUtils::FindOurProcessWindow(HWND aWnd)
   1.433 +{
   1.434 +  for (HWND wnd = ::GetParent(aWnd); wnd; wnd = ::GetParent(wnd)) {
   1.435 +    if (IsOurProcessWindow(wnd)) {
   1.436 +      return wnd;
   1.437 +    }
   1.438 +  }
   1.439 +  return nullptr;
   1.440 +}
   1.441 +
   1.442 +static bool
   1.443 +IsPointInWindow(HWND aWnd, const POINT& aPointInScreen)
   1.444 +{
   1.445 +  RECT bounds;
   1.446 +  if (!::GetWindowRect(aWnd, &bounds)) {
   1.447 +    return false;
   1.448 +  }
   1.449 +
   1.450 +  return (aPointInScreen.x >= bounds.left && aPointInScreen.x < bounds.right &&
   1.451 +          aPointInScreen.y >= bounds.top && aPointInScreen.y < bounds.bottom);
   1.452 +}
   1.453 +
   1.454 +/**
   1.455 + * FindTopmostWindowAtPoint() returns the topmost child window (topmost means
   1.456 + * forground in this context) of aWnd.
   1.457 + */
   1.458 +
   1.459 +static HWND
   1.460 +FindTopmostWindowAtPoint(HWND aWnd, const POINT& aPointInScreen)
   1.461 +{
   1.462 +  if (!::IsWindowVisible(aWnd) || !IsPointInWindow(aWnd, aPointInScreen)) {
   1.463 +    return nullptr;
   1.464 +  }
   1.465 +
   1.466 +  HWND childWnd = ::GetTopWindow(aWnd);
   1.467 +  while (childWnd) {
   1.468 +    HWND topmostWnd = FindTopmostWindowAtPoint(childWnd, aPointInScreen);
   1.469 +    if (topmostWnd) {
   1.470 +      return topmostWnd;
   1.471 +    }
   1.472 +    childWnd = ::GetNextWindow(childWnd, GW_HWNDNEXT);
   1.473 +  }
   1.474 +
   1.475 +  return aWnd;
   1.476 +}
   1.477 +
   1.478 +struct FindOurWindowAtPointInfo
   1.479 +{
   1.480 +  POINT mInPointInScreen;
   1.481 +  HWND mOutWnd;
   1.482 +};
   1.483 +
   1.484 +static BOOL CALLBACK
   1.485 +FindOurWindowAtPointCallback(HWND aWnd, LPARAM aLPARAM)
   1.486 +{
   1.487 +  if (!WinUtils::IsOurProcessWindow(aWnd)) {
   1.488 +    // This isn't one of our top-level windows; continue enumerating.
   1.489 +    return TRUE;
   1.490 +  }
   1.491 +
   1.492 +  // Get the top-most child window under the point.  If there's no child
   1.493 +  // window, and the point is within the top-level window, then the top-level
   1.494 +  // window will be returned.  (This is the usual case.  A child window
   1.495 +  // would be returned for plugins.)
   1.496 +  FindOurWindowAtPointInfo* info =
   1.497 +    reinterpret_cast<FindOurWindowAtPointInfo*>(aLPARAM);
   1.498 +  HWND childWnd = FindTopmostWindowAtPoint(aWnd, info->mInPointInScreen);
   1.499 +  if (!childWnd) {
   1.500 +    // This window doesn't contain the point; continue enumerating.
   1.501 +    return TRUE;
   1.502 +  }
   1.503 +
   1.504 +  // Return the HWND and stop enumerating.
   1.505 +  info->mOutWnd = childWnd;
   1.506 +  return FALSE;
   1.507 +}
   1.508 +
   1.509 +/* static */
   1.510 +HWND
   1.511 +WinUtils::FindOurWindowAtPoint(const POINT& aPointInScreen)
   1.512 +{
   1.513 +  FindOurWindowAtPointInfo info;
   1.514 +  info.mInPointInScreen = aPointInScreen;
   1.515 +  info.mOutWnd = nullptr;
   1.516 +
   1.517 +  // This will enumerate all top-level windows in order from top to bottom.
   1.518 +  EnumWindows(FindOurWindowAtPointCallback, reinterpret_cast<LPARAM>(&info));
   1.519 +  return info.mOutWnd;
   1.520 +}
   1.521 +
   1.522 +/* static */
   1.523 +UINT
   1.524 +WinUtils::GetInternalMessage(UINT aNativeMessage)
   1.525 +{
   1.526 +  switch (aNativeMessage) {
   1.527 +    case WM_MOUSEWHEEL:
   1.528 +      return MOZ_WM_MOUSEVWHEEL;
   1.529 +    case WM_MOUSEHWHEEL:
   1.530 +      return MOZ_WM_MOUSEHWHEEL;
   1.531 +    case WM_VSCROLL:
   1.532 +      return MOZ_WM_VSCROLL;
   1.533 +    case WM_HSCROLL:
   1.534 +      return MOZ_WM_HSCROLL;
   1.535 +    default:
   1.536 +      return aNativeMessage;
   1.537 +  }
   1.538 +}
   1.539 +
   1.540 +/* static */
   1.541 +UINT
   1.542 +WinUtils::GetNativeMessage(UINT aInternalMessage)
   1.543 +{
   1.544 +  switch (aInternalMessage) {
   1.545 +    case MOZ_WM_MOUSEVWHEEL:
   1.546 +      return WM_MOUSEWHEEL;
   1.547 +    case MOZ_WM_MOUSEHWHEEL:
   1.548 +      return WM_MOUSEHWHEEL;
   1.549 +    case MOZ_WM_VSCROLL:
   1.550 +      return WM_VSCROLL;
   1.551 +    case MOZ_WM_HSCROLL:
   1.552 +      return WM_HSCROLL;
   1.553 +    default:
   1.554 +      return aInternalMessage;
   1.555 +  }
   1.556 +}
   1.557 +
   1.558 +/* static */
   1.559 +uint16_t
   1.560 +WinUtils::GetMouseInputSource()
   1.561 +{
   1.562 +  int32_t inputSource = nsIDOMMouseEvent::MOZ_SOURCE_MOUSE;
   1.563 +  LPARAM lParamExtraInfo = ::GetMessageExtraInfo();
   1.564 +  if ((lParamExtraInfo & TABLET_INK_SIGNATURE) == TABLET_INK_CHECK) {
   1.565 +    inputSource = (lParamExtraInfo & TABLET_INK_TOUCH) ?
   1.566 +      nsIDOMMouseEvent::MOZ_SOURCE_TOUCH : nsIDOMMouseEvent::MOZ_SOURCE_PEN;
   1.567 +  }
   1.568 +  return static_cast<uint16_t>(inputSource);
   1.569 +}
   1.570 +
   1.571 +bool
   1.572 +WinUtils::GetIsMouseFromTouch(uint32_t aEventType)
   1.573 +{
   1.574 +#define MOUSEEVENTF_FROMTOUCH 0xFF515700
   1.575 +  return (aEventType == NS_MOUSE_BUTTON_DOWN ||
   1.576 +          aEventType == NS_MOUSE_BUTTON_UP ||
   1.577 +          aEventType == NS_MOUSE_MOVE) &&
   1.578 +          (GetMessageExtraInfo() & MOUSEEVENTF_FROMTOUCH);
   1.579 +}
   1.580 +
   1.581 +/* static */
   1.582 +MSG
   1.583 +WinUtils::InitMSG(UINT aMessage, WPARAM wParam, LPARAM lParam, HWND aWnd)
   1.584 +{
   1.585 +  MSG msg;
   1.586 +  msg.message = aMessage;
   1.587 +  msg.wParam  = wParam;
   1.588 +  msg.lParam  = lParam;
   1.589 +  msg.hwnd    = aWnd;
   1.590 +  return msg;
   1.591 +}
   1.592 +
   1.593 +/* static */
   1.594 +HRESULT
   1.595 +WinUtils::SHCreateItemFromParsingName(PCWSTR pszPath, IBindCtx *pbc,
   1.596 +                                      REFIID riid, void **ppv)
   1.597 +{
   1.598 +  if (sCreateItemFromParsingName) {
   1.599 +    return sCreateItemFromParsingName(pszPath, pbc, riid, ppv);
   1.600 +  }
   1.601 +
   1.602 +  if (!sShellDll) {
   1.603 +    sShellDll = ::LoadLibraryW(kShellLibraryName);
   1.604 +    if (!sShellDll) {
   1.605 +      return false;
   1.606 +    }
   1.607 +  }
   1.608 +
   1.609 +  sCreateItemFromParsingName = (SHCreateItemFromParsingNamePtr)
   1.610 +    GetProcAddress(sShellDll, "SHCreateItemFromParsingName");
   1.611 +  if (!sCreateItemFromParsingName)
   1.612 +    return E_FAIL;
   1.613 +
   1.614 +  return sCreateItemFromParsingName(pszPath, pbc, riid, ppv);
   1.615 +}
   1.616 +
   1.617 +/* static */
   1.618 +HRESULT 
   1.619 +WinUtils::SHGetKnownFolderPath(REFKNOWNFOLDERID rfid,
   1.620 +                               DWORD dwFlags,
   1.621 +                               HANDLE hToken,
   1.622 +                               PWSTR *ppszPath)
   1.623 +{
   1.624 +  if (sGetKnownFolderPath) {
   1.625 +    return sGetKnownFolderPath(rfid, dwFlags, hToken, ppszPath);
   1.626 +  }
   1.627 +
   1.628 +  if (!sShellDll) {
   1.629 +    sShellDll = ::LoadLibraryW(kShellLibraryName);
   1.630 +    if (!sShellDll) {
   1.631 +      return false;
   1.632 +    }
   1.633 +  }
   1.634 +
   1.635 +  sGetKnownFolderPath = (SHGetKnownFolderPathPtr)
   1.636 +    GetProcAddress(sShellDll, "SHGetKnownFolderPath");
   1.637 +  if (!sGetKnownFolderPath)
   1.638 +    return E_FAIL;
   1.639 +
   1.640 +  return sGetKnownFolderPath(rfid, dwFlags, hToken, ppszPath);
   1.641 +}
   1.642 +
   1.643 +#ifdef MOZ_PLACES
   1.644 +/************************************************************************/
   1.645 +/* Constructs as AsyncFaviconDataReady Object
   1.646 +/* @param aIOThread : the thread which performs the action
   1.647 +/* @param aURLShortcut : Differentiates between (false)Jumplistcache and (true)Shortcutcache
   1.648 +/************************************************************************/
   1.649 +
   1.650 +AsyncFaviconDataReady::AsyncFaviconDataReady(nsIURI *aNewURI, 
   1.651 +                                             nsCOMPtr<nsIThread> &aIOThread, 
   1.652 +                                             const bool aURLShortcut):
   1.653 +  mNewURI(aNewURI),
   1.654 +  mIOThread(aIOThread),
   1.655 +  mURLShortcut(aURLShortcut)
   1.656 +{
   1.657 +}
   1.658 +
   1.659 +NS_IMETHODIMP
   1.660 +myDownloadObserver::OnDownloadComplete(nsIDownloader *downloader, 
   1.661 +                                     nsIRequest *request, 
   1.662 +                                     nsISupports *ctxt, 
   1.663 +                                     nsresult status, 
   1.664 +                                     nsIFile *result)
   1.665 +{
   1.666 +  return NS_OK;
   1.667 +}
   1.668 +
   1.669 +nsresult AsyncFaviconDataReady::OnFaviconDataNotAvailable(void)
   1.670 +{
   1.671 +  if (!mURLShortcut) {
   1.672 +    return NS_OK;
   1.673 +  }
   1.674 +
   1.675 +  nsCOMPtr<nsIFile> icoFile;
   1.676 +  nsresult rv = FaviconHelper::GetOutputIconPath(mNewURI, icoFile, mURLShortcut);
   1.677 +  NS_ENSURE_SUCCESS(rv, rv);
   1.678 +
   1.679 +  nsCOMPtr<nsIURI> mozIconURI;
   1.680 +  rv = NS_NewURI(getter_AddRefs(mozIconURI), "moz-icon://.html?size=32");
   1.681 +  if (NS_FAILED(rv)) {
   1.682 +    return rv;
   1.683 +  }
   1.684 + 
   1.685 +  nsCOMPtr<nsIChannel> channel;
   1.686 +  rv = NS_NewChannel(getter_AddRefs(channel), mozIconURI);
   1.687 +  NS_ENSURE_SUCCESS(rv, rv);
   1.688 +
   1.689 +  nsCOMPtr<nsIDownloadObserver> downloadObserver = new myDownloadObserver;
   1.690 +  nsCOMPtr<nsIStreamListener> listener;
   1.691 +  rv = NS_NewDownloader(getter_AddRefs(listener), downloadObserver, icoFile);
   1.692 +  NS_ENSURE_SUCCESS(rv, rv);
   1.693 +
   1.694 +  channel->AsyncOpen(listener, nullptr);
   1.695 +  return NS_OK;
   1.696 +}
   1.697 +
   1.698 +NS_IMETHODIMP
   1.699 +AsyncFaviconDataReady::OnComplete(nsIURI *aFaviconURI,
   1.700 +                                  uint32_t aDataLen,
   1.701 +                                  const uint8_t *aData, 
   1.702 +                                  const nsACString &aMimeType)
   1.703 +{
   1.704 +  if (!aDataLen || !aData) {
   1.705 +    if (mURLShortcut) {
   1.706 +      OnFaviconDataNotAvailable();
   1.707 +    }
   1.708 +    
   1.709 +    return NS_OK;
   1.710 +  }
   1.711 +
   1.712 +  nsCOMPtr<nsIFile> icoFile;
   1.713 +  nsresult rv = FaviconHelper::GetOutputIconPath(mNewURI, icoFile, mURLShortcut);
   1.714 +  NS_ENSURE_SUCCESS(rv, rv);
   1.715 +  
   1.716 +  nsAutoString path;
   1.717 +  rv = icoFile->GetPath(path);
   1.718 +  NS_ENSURE_SUCCESS(rv, rv);
   1.719 +
   1.720 +  // Convert the obtained favicon data to an input stream
   1.721 +  nsCOMPtr<nsIInputStream> stream;
   1.722 +  rv = NS_NewByteInputStream(getter_AddRefs(stream),
   1.723 +                             reinterpret_cast<const char*>(aData),
   1.724 +                             aDataLen,
   1.725 +                             NS_ASSIGNMENT_DEPEND);
   1.726 +  NS_ENSURE_SUCCESS(rv, rv);
   1.727 +
   1.728 +  // Decode the image from the format it was returned to us in (probably PNG)
   1.729 +  nsAutoCString mimeTypeOfInputData;
   1.730 +  mimeTypeOfInputData.AssignLiteral("image/vnd.microsoft.icon");
   1.731 +  nsCOMPtr<imgIContainer> container;
   1.732 +  nsCOMPtr<imgITools> imgtool = do_CreateInstance("@mozilla.org/image/tools;1");
   1.733 +  rv = imgtool->DecodeImageData(stream, aMimeType,
   1.734 +                                getter_AddRefs(container));
   1.735 +  NS_ENSURE_SUCCESS(rv, rv);
   1.736 +
   1.737 +  RefPtr<SourceSurface> surface =
   1.738 +    container->GetFrame(imgIContainer::FRAME_FIRST, 0);
   1.739 +  NS_ENSURE_TRUE(surface, NS_ERROR_FAILURE);
   1.740 +
   1.741 +  RefPtr<DataSourceSurface> dataSurface;
   1.742 +  IntSize size;
   1.743 +
   1.744 +  if (mURLShortcut) {
   1.745 +    // Create a 48x48 surface and paint the icon into the central 16x16 rect.
   1.746 +    size.width = 48;
   1.747 +    size.height = 48;
   1.748 +    dataSurface =
   1.749 +      Factory::CreateDataSourceSurface(size, SurfaceFormat::B8G8R8A8);
   1.750 +    NS_ENSURE_TRUE(dataSurface, NS_ERROR_FAILURE);
   1.751 +
   1.752 +    DataSourceSurface::MappedSurface map;
   1.753 +    if (!dataSurface->Map(DataSourceSurface::MapType::WRITE, &map)) {
   1.754 +      return NS_ERROR_FAILURE;
   1.755 +    }
   1.756 +
   1.757 +    RefPtr<DrawTarget> dt =
   1.758 +      Factory::CreateDrawTargetForData(BackendType::CAIRO,
   1.759 +                                       map.mData,
   1.760 +                                       dataSurface->GetSize(),
   1.761 +                                       map.mStride,
   1.762 +                                       dataSurface->GetFormat());
   1.763 +    dt->FillRect(Rect(0, 0, size.width, size.height),
   1.764 +                 ColorPattern(Color(1.0f, 1.0f, 1.0f, 1.0f)));
   1.765 +    dt->DrawSurface(surface,
   1.766 +                    Rect(16, 16, 16, 16),
   1.767 +                    Rect(Point(0, 0),
   1.768 +                         Size(surface->GetSize().width, surface->GetSize().height)));
   1.769 +
   1.770 +    dataSurface->Unmap();
   1.771 +  } else {
   1.772 +    // By using the input image surface's size, we may end up encoding
   1.773 +    // to a different size than a 16x16 (or bigger for higher DPI) ICO, but
   1.774 +    // Windows will resize appropriately for us. If we want to encode ourselves
   1.775 +    // one day because we like our resizing better, we'd have to manually
   1.776 +    // resize the image here and use GetSystemMetrics w/ SM_CXSMICON and
   1.777 +    // SM_CYSMICON. We don't support resizing images asynchronously at the
   1.778 +    // moment anyway so getting the DPI aware icon size won't help.
   1.779 +    size.width = surface->GetSize().width;
   1.780 +    size.height = surface->GetSize().height;
   1.781 +    dataSurface = surface->GetDataSurface();
   1.782 +    NS_ENSURE_TRUE(dataSurface, NS_ERROR_FAILURE);
   1.783 +  }
   1.784 +
   1.785 +  // Allocate a new buffer that we own and can use out of line in
   1.786 +  // another thread.
   1.787 +  uint8_t *data = SurfaceToPackedBGRA(dataSurface);
   1.788 +  if (!data) {
   1.789 +    return NS_ERROR_OUT_OF_MEMORY;
   1.790 +  }
   1.791 +  int32_t stride = 4 * size.width;
   1.792 +  int32_t dataLength = stride * size.height;
   1.793 +
   1.794 +  // AsyncEncodeAndWriteIcon takes ownership of the heap allocated buffer
   1.795 +  nsCOMPtr<nsIRunnable> event = new AsyncEncodeAndWriteIcon(path, data,
   1.796 +                                                            dataLength,
   1.797 +                                                            stride,
   1.798 +                                                            size.width,
   1.799 +                                                            size.height,
   1.800 +                                                            mURLShortcut);
   1.801 +  mIOThread->Dispatch(event, NS_DISPATCH_NORMAL);
   1.802 +
   1.803 +  return NS_OK;
   1.804 +}
   1.805 +#endif
   1.806 +
   1.807 +// Warning: AsyncEncodeAndWriteIcon assumes ownership of the aData buffer passed in
   1.808 +AsyncEncodeAndWriteIcon::AsyncEncodeAndWriteIcon(const nsAString &aIconPath,
   1.809 +                                                 uint8_t *aBuffer,
   1.810 +                                                 uint32_t aBufferLength,
   1.811 +                                                 uint32_t aStride,
   1.812 +                                                 uint32_t aWidth,
   1.813 +                                                 uint32_t aHeight,
   1.814 +                                                 const bool aURLShortcut) :
   1.815 +  mURLShortcut(aURLShortcut),
   1.816 +  mIconPath(aIconPath),
   1.817 +  mBuffer(aBuffer),
   1.818 +  mBufferLength(aBufferLength),
   1.819 +  mStride(aStride),
   1.820 +  mWidth(aWidth),
   1.821 +  mHeight(aHeight)
   1.822 +{
   1.823 +}
   1.824 +
   1.825 +NS_IMETHODIMP AsyncEncodeAndWriteIcon::Run()
   1.826 +{
   1.827 +  NS_PRECONDITION(!NS_IsMainThread(), "Should not be called on the main thread.");
   1.828 +
   1.829 +  nsCOMPtr<nsIInputStream> iconStream;
   1.830 +  nsRefPtr<imgIEncoder> encoder =
   1.831 +    do_CreateInstance("@mozilla.org/image/encoder;2?"
   1.832 +                      "type=image/vnd.microsoft.icon");
   1.833 +  NS_ENSURE_TRUE(encoder, NS_ERROR_FAILURE);
   1.834 +  nsresult rv = encoder->InitFromData(mBuffer, mBufferLength,
   1.835 +                                      mWidth, mHeight,
   1.836 +                                      mStride,
   1.837 +                                      imgIEncoder::INPUT_FORMAT_HOSTARGB,
   1.838 +                                      EmptyString());
   1.839 +  NS_ENSURE_SUCCESS(rv, rv);
   1.840 +  CallQueryInterface(encoder.get(), getter_AddRefs(iconStream));
   1.841 +  if (!iconStream) {
   1.842 +    return NS_ERROR_FAILURE;
   1.843 +  }
   1.844 +
   1.845 +  NS_ENSURE_SUCCESS(rv, rv);
   1.846 +  nsCOMPtr<nsIFile> icoFile
   1.847 +    = do_CreateInstance("@mozilla.org/file/local;1");
   1.848 +  NS_ENSURE_TRUE(icoFile, NS_ERROR_FAILURE);
   1.849 +  rv = icoFile->InitWithPath(mIconPath);
   1.850 +
   1.851 +  // Try to create the directory if it's not there yet
   1.852 +  nsCOMPtr<nsIFile> dirPath;
   1.853 +  icoFile->GetParent(getter_AddRefs(dirPath));
   1.854 +  rv = (dirPath->Create(nsIFile::DIRECTORY_TYPE, 0777));
   1.855 +  if (NS_FAILED(rv) && rv != NS_ERROR_FILE_ALREADY_EXISTS) {
   1.856 +    return rv;
   1.857 +  }
   1.858 +
   1.859 +  // Setup the output stream for the ICO file on disk
   1.860 +  nsCOMPtr<nsIOutputStream> outputStream;
   1.861 +  rv = NS_NewLocalFileOutputStream(getter_AddRefs(outputStream), icoFile);
   1.862 +  NS_ENSURE_SUCCESS(rv, rv);
   1.863 +
   1.864 +  // Obtain the ICO buffer size from the re-encoded ICO stream
   1.865 +  uint64_t bufSize64;
   1.866 +  rv = iconStream->Available(&bufSize64);
   1.867 +  NS_ENSURE_SUCCESS(rv, rv);
   1.868 +  NS_ENSURE_TRUE(bufSize64 <= UINT32_MAX, NS_ERROR_FILE_TOO_BIG);
   1.869 +
   1.870 +  uint32_t bufSize = (uint32_t)bufSize64;
   1.871 +
   1.872 +  // Setup a buffered output stream from the stream object
   1.873 +  // so that we can simply use WriteFrom with the stream object
   1.874 +  nsCOMPtr<nsIOutputStream> bufferedOutputStream;
   1.875 +  rv = NS_NewBufferedOutputStream(getter_AddRefs(bufferedOutputStream),
   1.876 +                                  outputStream, bufSize);
   1.877 +  NS_ENSURE_SUCCESS(rv, rv);
   1.878 +
   1.879 +  // Write out the icon stream to disk and make sure we wrote everything
   1.880 +  uint32_t wrote;
   1.881 +  rv = bufferedOutputStream->WriteFrom(iconStream, bufSize, &wrote);
   1.882 +  NS_ASSERTION(bufSize == wrote, 
   1.883 +              "Icon wrote size should be equal to requested write size");
   1.884 +
   1.885 +  // Cleanup
   1.886 +  bufferedOutputStream->Close();
   1.887 +  outputStream->Close();
   1.888 +  if (mURLShortcut) {
   1.889 +    SendMessage(HWND_BROADCAST, WM_SETTINGCHANGE, SPI_SETNONCLIENTMETRICS, 0);
   1.890 +  }
   1.891 +  return rv;
   1.892 +}
   1.893 +
   1.894 +AsyncEncodeAndWriteIcon::~AsyncEncodeAndWriteIcon()
   1.895 +{
   1.896 +}
   1.897 +
   1.898 +AsyncDeleteIconFromDisk::AsyncDeleteIconFromDisk(const nsAString &aIconPath)
   1.899 +  : mIconPath(aIconPath)
   1.900 +{
   1.901 +}
   1.902 +
   1.903 +NS_IMETHODIMP AsyncDeleteIconFromDisk::Run()
   1.904 +{
   1.905 +  // Construct the parent path of the passed in path
   1.906 +  nsCOMPtr<nsIFile> icoFile = do_CreateInstance("@mozilla.org/file/local;1");
   1.907 +  NS_ENSURE_TRUE(icoFile, NS_ERROR_FAILURE);
   1.908 +  nsresult rv = icoFile->InitWithPath(mIconPath);
   1.909 +  NS_ENSURE_SUCCESS(rv, rv);
   1.910 +
   1.911 +  // Check if the cached ICO file exists
   1.912 +  bool exists;
   1.913 +  rv = icoFile->Exists(&exists);
   1.914 +  NS_ENSURE_SUCCESS(rv, rv);
   1.915 +
   1.916 +  // Check that we aren't deleting some arbitrary file that is not an icon
   1.917 +  if (StringTail(mIconPath, 4).LowerCaseEqualsASCII(".ico")) {
   1.918 +    // Check if the cached ICO file exists
   1.919 +    bool exists;
   1.920 +    if (NS_FAILED(icoFile->Exists(&exists)) || !exists)
   1.921 +      return NS_ERROR_FAILURE;
   1.922 +
   1.923 +    // We found an ICO file that exists, so we should remove it
   1.924 +    icoFile->Remove(false);
   1.925 +  }
   1.926 +
   1.927 +  return NS_OK;
   1.928 +}
   1.929 +
   1.930 +AsyncDeleteIconFromDisk::~AsyncDeleteIconFromDisk()
   1.931 +{
   1.932 +}
   1.933 +
   1.934 +AsyncDeleteAllFaviconsFromDisk::AsyncDeleteAllFaviconsFromDisk()
   1.935 +{
   1.936 +}
   1.937 +
   1.938 +NS_IMETHODIMP AsyncDeleteAllFaviconsFromDisk::Run()
   1.939 +{
   1.940 +  // Construct the path of our jump list cache
   1.941 +  nsCOMPtr<nsIFile> jumpListCacheDir;
   1.942 +  nsresult rv = NS_GetSpecialDirectory("ProfLDS", 
   1.943 +    getter_AddRefs(jumpListCacheDir));
   1.944 +  NS_ENSURE_SUCCESS(rv, rv);
   1.945 +  rv = jumpListCacheDir->AppendNative(
   1.946 +      nsDependentCString(FaviconHelper::kJumpListCacheDir));
   1.947 +  NS_ENSURE_SUCCESS(rv, rv);
   1.948 +  nsCOMPtr<nsISimpleEnumerator> entries;
   1.949 +  rv = jumpListCacheDir->GetDirectoryEntries(getter_AddRefs(entries));
   1.950 +  NS_ENSURE_SUCCESS(rv, rv);
   1.951 +
   1.952 +  // Loop through each directory entry and remove all ICO files found
   1.953 +  do {
   1.954 +    bool hasMore = false;
   1.955 +    if (NS_FAILED(entries->HasMoreElements(&hasMore)) || !hasMore)
   1.956 +      break;
   1.957 +
   1.958 +    nsCOMPtr<nsISupports> supp;
   1.959 +    if (NS_FAILED(entries->GetNext(getter_AddRefs(supp))))
   1.960 +      break;
   1.961 +
   1.962 +    nsCOMPtr<nsIFile> currFile(do_QueryInterface(supp));
   1.963 +    nsAutoString path;
   1.964 +    if (NS_FAILED(currFile->GetPath(path)))
   1.965 +      continue;
   1.966 +
   1.967 +    if (StringTail(path, 4).LowerCaseEqualsASCII(".ico")) {
   1.968 +      // Check if the cached ICO file exists
   1.969 +      bool exists;
   1.970 +      if (NS_FAILED(currFile->Exists(&exists)) || !exists)
   1.971 +        continue;
   1.972 +
   1.973 +      // We found an ICO file that exists, so we should remove it
   1.974 +      currFile->Remove(false);
   1.975 +    }
   1.976 +  } while(true);
   1.977 +
   1.978 +  return NS_OK;
   1.979 +}
   1.980 +
   1.981 +AsyncDeleteAllFaviconsFromDisk::~AsyncDeleteAllFaviconsFromDisk()
   1.982 +{
   1.983 +}
   1.984 +
   1.985 +
   1.986 +/*
   1.987 + * (static) If the data is available, will return the path on disk where 
   1.988 + * the favicon for page aFaviconPageURI is stored.  If the favicon does not
   1.989 + * exist, or its cache is expired, this method will kick off an async request
   1.990 + * for the icon so that next time the method is called it will be available. 
   1.991 + * @param aFaviconPageURI The URI of the page to obtain
   1.992 + * @param aICOFilePath The path of the icon file
   1.993 + * @param aIOThread The thread to perform the Fetch on
   1.994 + * @param aURLShortcut to distinguish between jumplistcache(false) and shortcutcache(true)
   1.995 + */
   1.996 +nsresult FaviconHelper::ObtainCachedIconFile(nsCOMPtr<nsIURI> aFaviconPageURI,
   1.997 +                                             nsString &aICOFilePath,
   1.998 +                                             nsCOMPtr<nsIThread> &aIOThread,
   1.999 +                                             bool aURLShortcut)
  1.1000 +{
  1.1001 +  // Obtain the ICO file path
  1.1002 +  nsCOMPtr<nsIFile> icoFile;
  1.1003 +  nsresult rv = GetOutputIconPath(aFaviconPageURI, icoFile, aURLShortcut);
  1.1004 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1005 +
  1.1006 +  // Check if the cached ICO file already exists
  1.1007 +  bool exists;
  1.1008 +  rv = icoFile->Exists(&exists);
  1.1009 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1010 +
  1.1011 +  if (exists) {
  1.1012 +
  1.1013 +    // Obtain the file's last modification date in seconds
  1.1014 +    int64_t fileModTime = 0;
  1.1015 +    rv = icoFile->GetLastModifiedTime(&fileModTime);
  1.1016 +    fileModTime /= PR_MSEC_PER_SEC;
  1.1017 +    int32_t icoReCacheSecondsTimeout = GetICOCacheSecondsTimeout();
  1.1018 +    int64_t nowTime = PR_Now() / int64_t(PR_USEC_PER_SEC);
  1.1019 +
  1.1020 +    // If the last mod call failed or the icon is old then re-cache it
  1.1021 +    // This check is in case the favicon of a page changes
  1.1022 +    // the next time we try to build the jump list, the data will be available.
  1.1023 +    if (NS_FAILED(rv) ||
  1.1024 +        (nowTime - fileModTime) > icoReCacheSecondsTimeout) {
  1.1025 +        CacheIconFileFromFaviconURIAsync(aFaviconPageURI, icoFile, aIOThread, aURLShortcut);
  1.1026 +        return NS_ERROR_NOT_AVAILABLE;
  1.1027 +    }
  1.1028 +  } else {
  1.1029 +
  1.1030 +    // The file does not exist yet, obtain it async from the favicon service so that
  1.1031 +    // the next time we try to build the jump list it'll be available.
  1.1032 +    CacheIconFileFromFaviconURIAsync(aFaviconPageURI, icoFile, aIOThread, aURLShortcut);
  1.1033 +    return NS_ERROR_NOT_AVAILABLE;
  1.1034 +  }
  1.1035 +
  1.1036 +  // The icoFile is filled with a path that exists, get its path
  1.1037 +  rv = icoFile->GetPath(aICOFilePath);
  1.1038 +  return rv;
  1.1039 +}
  1.1040 +
  1.1041 +nsresult FaviconHelper::HashURI(nsCOMPtr<nsICryptoHash> &aCryptoHash, 
  1.1042 +                                nsIURI *aUri, 
  1.1043 +                                nsACString& aUriHash)
  1.1044 +{
  1.1045 +  if (!aUri)
  1.1046 +    return NS_ERROR_INVALID_ARG;
  1.1047 +
  1.1048 +  nsAutoCString spec;
  1.1049 +  nsresult rv = aUri->GetSpec(spec);
  1.1050 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1051 +
  1.1052 +  if (!aCryptoHash) {
  1.1053 +    aCryptoHash = do_CreateInstance(NS_CRYPTO_HASH_CONTRACTID, &rv);
  1.1054 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1055 +  }
  1.1056 +
  1.1057 +  rv = aCryptoHash->Init(nsICryptoHash::MD5);
  1.1058 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1059 +  rv = aCryptoHash->Update(reinterpret_cast<const uint8_t*>(spec.BeginReading()), 
  1.1060 +                           spec.Length());
  1.1061 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1062 +  rv = aCryptoHash->Finish(true, aUriHash);
  1.1063 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1064 +
  1.1065 +  return NS_OK;
  1.1066 +}
  1.1067 +
  1.1068 +
  1.1069 +
  1.1070 +// (static) Obtains the ICO file for the favicon at page aFaviconPageURI
  1.1071 +// If successful, the file path on disk is in the format:
  1.1072 +// <ProfLDS>\jumpListCache\<hash(aFaviconPageURI)>.ico
  1.1073 +nsresult FaviconHelper::GetOutputIconPath(nsCOMPtr<nsIURI> aFaviconPageURI,
  1.1074 +  nsCOMPtr<nsIFile> &aICOFile,
  1.1075 +  bool aURLShortcut)
  1.1076 +{
  1.1077 +  // Hash the input URI and replace any / with _
  1.1078 +  nsAutoCString inputURIHash;
  1.1079 +  nsCOMPtr<nsICryptoHash> cryptoHash;
  1.1080 +  nsresult rv = HashURI(cryptoHash, aFaviconPageURI,
  1.1081 +                        inputURIHash);
  1.1082 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1083 +  char* cur = inputURIHash.BeginWriting();
  1.1084 +  char* end = inputURIHash.EndWriting();
  1.1085 +  for (; cur < end; ++cur) {
  1.1086 +    if ('/' == *cur) {
  1.1087 +      *cur = '_';
  1.1088 +    }
  1.1089 +  }
  1.1090 +
  1.1091 +  // Obtain the local profile directory and construct the output icon file path
  1.1092 +  rv = NS_GetSpecialDirectory("ProfLDS", getter_AddRefs(aICOFile));
  1.1093 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1094 +  if (!aURLShortcut)
  1.1095 +    rv = aICOFile->AppendNative(nsDependentCString(kJumpListCacheDir));
  1.1096 +  else
  1.1097 +    rv = aICOFile->AppendNative(nsDependentCString(kShortcutCacheDir));
  1.1098 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1099 +
  1.1100 +  // Append the icon extension
  1.1101 +  inputURIHash.Append(".ico");
  1.1102 +  rv = aICOFile->AppendNative(inputURIHash);
  1.1103 +
  1.1104 +  return rv;
  1.1105 +}
  1.1106 +
  1.1107 +// (static) Asynchronously creates a cached ICO file on disk for the favicon of
  1.1108 +// page aFaviconPageURI and stores it to disk at the path of aICOFile.
  1.1109 +nsresult 
  1.1110 +  FaviconHelper::CacheIconFileFromFaviconURIAsync(nsCOMPtr<nsIURI> aFaviconPageURI,
  1.1111 +                                                  nsCOMPtr<nsIFile> aICOFile,
  1.1112 +                                                  nsCOMPtr<nsIThread> &aIOThread,
  1.1113 +                                                  bool aURLShortcut)
  1.1114 +{
  1.1115 +#ifdef MOZ_PLACES
  1.1116 +  // Obtain the favicon service and get the favicon for the specified page
  1.1117 +  nsCOMPtr<mozIAsyncFavicons> favIconSvc(
  1.1118 +    do_GetService("@mozilla.org/browser/favicon-service;1"));
  1.1119 +  NS_ENSURE_TRUE(favIconSvc, NS_ERROR_FAILURE);
  1.1120 +
  1.1121 +  nsCOMPtr<nsIFaviconDataCallback> callback = 
  1.1122 +    new mozilla::widget::AsyncFaviconDataReady(aFaviconPageURI, 
  1.1123 +                                               aIOThread, 
  1.1124 +                                               aURLShortcut);
  1.1125 +
  1.1126 +  favIconSvc->GetFaviconDataForPage(aFaviconPageURI, callback);
  1.1127 +#endif
  1.1128 +  return NS_OK;
  1.1129 +}
  1.1130 +
  1.1131 +// Obtains the jump list 'ICO cache timeout in seconds' pref
  1.1132 +int32_t FaviconHelper::GetICOCacheSecondsTimeout() {
  1.1133 +
  1.1134 +  // Only obtain the setting at most once from the pref service.
  1.1135 +  // In the rare case that 2 threads call this at the same
  1.1136 +  // time it is no harm and we will simply obtain the pref twice.
  1.1137 +  // None of the taskbar list prefs are currently updated via a
  1.1138 +  // pref observer so I think this should suffice.
  1.1139 +  const int32_t kSecondsPerDay = 86400;
  1.1140 +  static bool alreadyObtained = false;
  1.1141 +  static int32_t icoReCacheSecondsTimeout = kSecondsPerDay;
  1.1142 +  if (alreadyObtained) {
  1.1143 +    return icoReCacheSecondsTimeout;
  1.1144 +  }
  1.1145 +
  1.1146 +  // Obtain the pref
  1.1147 +  const char PREF_ICOTIMEOUT[]  = "browser.taskbar.lists.icoTimeoutInSeconds";
  1.1148 +  icoReCacheSecondsTimeout = Preferences::GetInt(PREF_ICOTIMEOUT, 
  1.1149 +                                                 kSecondsPerDay);
  1.1150 +  alreadyObtained = true;
  1.1151 +  return icoReCacheSecondsTimeout;
  1.1152 +}
  1.1153 +
  1.1154 +
  1.1155 +
  1.1156 +
  1.1157 +/* static */
  1.1158 +bool
  1.1159 +WinUtils::GetShellItemPath(IShellItem* aItem,
  1.1160 +                           nsString& aResultString)
  1.1161 +{
  1.1162 +  NS_ENSURE_TRUE(aItem, false);
  1.1163 +  LPWSTR str = nullptr;
  1.1164 +  if (FAILED(aItem->GetDisplayName(SIGDN_FILESYSPATH, &str)))
  1.1165 +    return false;
  1.1166 +  aResultString.Assign(str);
  1.1167 +  CoTaskMemFree(str);
  1.1168 +  return !aResultString.IsEmpty();
  1.1169 +}
  1.1170 +
  1.1171 +/* static */
  1.1172 +nsIntRegion
  1.1173 +WinUtils::ConvertHRGNToRegion(HRGN aRgn)
  1.1174 +{
  1.1175 +  NS_ASSERTION(aRgn, "Don't pass NULL region here");
  1.1176 +
  1.1177 +  nsIntRegion rgn;
  1.1178 +
  1.1179 +  DWORD size = ::GetRegionData(aRgn, 0, nullptr);
  1.1180 +  nsAutoTArray<uint8_t,100> buffer;
  1.1181 +  buffer.SetLength(size);
  1.1182 +
  1.1183 +  RGNDATA* data = reinterpret_cast<RGNDATA*>(buffer.Elements());
  1.1184 +  if (!::GetRegionData(aRgn, size, data))
  1.1185 +    return rgn;
  1.1186 +
  1.1187 +  if (data->rdh.nCount > MAX_RECTS_IN_REGION) {
  1.1188 +    rgn = ToIntRect(data->rdh.rcBound);
  1.1189 +    return rgn;
  1.1190 +  }
  1.1191 +
  1.1192 +  RECT* rects = reinterpret_cast<RECT*>(data->Buffer);
  1.1193 +  for (uint32_t i = 0; i < data->rdh.nCount; ++i) {
  1.1194 +    RECT* r = rects + i;
  1.1195 +    rgn.Or(rgn, ToIntRect(*r));
  1.1196 +  }
  1.1197 +
  1.1198 +  return rgn;
  1.1199 +}
  1.1200 +
  1.1201 +nsIntRect
  1.1202 +WinUtils::ToIntRect(const RECT& aRect)
  1.1203 +{
  1.1204 +  return nsIntRect(aRect.left, aRect.top,
  1.1205 +                   aRect.right - aRect.left,
  1.1206 +                   aRect.bottom - aRect.top);
  1.1207 +}
  1.1208 +
  1.1209 +/* static */
  1.1210 +bool
  1.1211 +WinUtils::IsIMEEnabled(const InputContext& aInputContext)
  1.1212 +{
  1.1213 +  return IsIMEEnabled(aInputContext.mIMEState.mEnabled);
  1.1214 +}
  1.1215 +
  1.1216 +/* static */
  1.1217 +bool
  1.1218 +WinUtils::IsIMEEnabled(IMEState::Enabled aIMEState)
  1.1219 +{
  1.1220 +  return (aIMEState == IMEState::ENABLED ||
  1.1221 +          aIMEState == IMEState::PLUGIN);
  1.1222 +}
  1.1223 +
  1.1224 +/* static */
  1.1225 +void
  1.1226 +WinUtils::SetupKeyModifiersSequence(nsTArray<KeyPair>* aArray,
  1.1227 +                                    uint32_t aModifiers)
  1.1228 +{
  1.1229 +  for (uint32_t i = 0; i < ArrayLength(sModifierKeyMap); ++i) {
  1.1230 +    const uint32_t* map = sModifierKeyMap[i];
  1.1231 +    if (aModifiers & map[0]) {
  1.1232 +      aArray->AppendElement(KeyPair(map[1], map[2]));
  1.1233 +    }
  1.1234 +  }
  1.1235 +}
  1.1236 +
  1.1237 +/* static */
  1.1238 +bool
  1.1239 +WinUtils::ShouldHideScrollbars()
  1.1240 +{
  1.1241 +#ifdef MOZ_METRO
  1.1242 +  if (XRE_GetWindowsEnvironment() == WindowsEnvironmentType_Metro) {
  1.1243 +    return widget::winrt::MetroInput::IsInputModeImprecise();
  1.1244 +  }
  1.1245 +#endif // MOZ_METRO
  1.1246 +  return false;
  1.1247 +}
  1.1248 +
  1.1249 +} // namespace widget
  1.1250 +} // namespace mozilla

mercurial