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

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

mercurial