michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim:set ts=2 sts=2 sw=2 et cin: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "WinUtils.h" michael@0: michael@0: #include "gfxPlatform.h" michael@0: #include "nsWindow.h" michael@0: #include "nsWindowDefs.h" michael@0: #include "KeyboardLayout.h" michael@0: #include "nsIDOMMouseEvent.h" michael@0: #include "mozilla/gfx/2D.h" michael@0: #include "mozilla/gfx/DataSurfaceHelpers.h" michael@0: #include "mozilla/Preferences.h" michael@0: #include "mozilla/RefPtr.h" michael@0: #include "mozilla/WindowsVersion.h" michael@0: michael@0: #ifdef MOZ_LOGGING michael@0: #define FORCE_PR_LOG /* Allow logging in the release build */ michael@0: #endif // MOZ_LOGGING michael@0: #include "prlog.h" michael@0: michael@0: #include "nsString.h" michael@0: #include "nsDirectoryServiceUtils.h" michael@0: #include "imgIContainer.h" michael@0: #include "imgITools.h" michael@0: #include "nsStringStream.h" michael@0: #include "nsNetUtil.h" michael@0: #ifdef MOZ_PLACES michael@0: #include "mozIAsyncFavicons.h" michael@0: #endif michael@0: #include "nsIIconURI.h" michael@0: #include "nsIDownloader.h" michael@0: #include "nsINetUtil.h" michael@0: #include "nsIChannel.h" michael@0: #include "nsIObserver.h" michael@0: #include "imgIEncoder.h" michael@0: #include "nsIThread.h" michael@0: #include "MainThreadUtils.h" michael@0: #include "gfxColor.h" michael@0: #ifdef MOZ_METRO michael@0: #include "winrt/MetroInput.h" michael@0: #include "winrt/MetroUtils.h" michael@0: #endif // MOZ_METRO michael@0: michael@0: #ifdef NS_ENABLE_TSF michael@0: #include michael@0: #include "nsTextStore.h" michael@0: #endif // #ifdef NS_ENABLE_TSF michael@0: michael@0: #ifdef PR_LOGGING michael@0: PRLogModuleInfo* gWindowsLog = nullptr; michael@0: #endif michael@0: michael@0: using namespace mozilla::gfx; michael@0: michael@0: namespace mozilla { michael@0: namespace widget { michael@0: michael@0: NS_IMPL_ISUPPORTS(myDownloadObserver, nsIDownloadObserver) michael@0: #ifdef MOZ_PLACES michael@0: NS_IMPL_ISUPPORTS(AsyncFaviconDataReady, nsIFaviconDataCallback) michael@0: #endif michael@0: NS_IMPL_ISUPPORTS(AsyncEncodeAndWriteIcon, nsIRunnable) michael@0: NS_IMPL_ISUPPORTS(AsyncDeleteIconFromDisk, nsIRunnable) michael@0: NS_IMPL_ISUPPORTS(AsyncDeleteAllFaviconsFromDisk, nsIRunnable) michael@0: michael@0: michael@0: const char FaviconHelper::kJumpListCacheDir[] = "jumpListCache"; michael@0: const char FaviconHelper::kShortcutCacheDir[] = "shortcutCache"; michael@0: michael@0: // apis available on vista and up. michael@0: WinUtils::SHCreateItemFromParsingNamePtr WinUtils::sCreateItemFromParsingName = nullptr; michael@0: WinUtils::SHGetKnownFolderPathPtr WinUtils::sGetKnownFolderPath = nullptr; michael@0: michael@0: // We just leak these DLL HMODULEs. There's no point in calling FreeLibrary michael@0: // on them during shutdown anyway. michael@0: static const wchar_t kShellLibraryName[] = L"shell32.dll"; michael@0: static HMODULE sShellDll = nullptr; michael@0: static const wchar_t kDwmLibraryName[] = L"dwmapi.dll"; michael@0: static HMODULE sDwmDll = nullptr; michael@0: michael@0: WinUtils::DwmExtendFrameIntoClientAreaProc WinUtils::dwmExtendFrameIntoClientAreaPtr = nullptr; michael@0: WinUtils::DwmIsCompositionEnabledProc WinUtils::dwmIsCompositionEnabledPtr = nullptr; michael@0: WinUtils::DwmSetIconicThumbnailProc WinUtils::dwmSetIconicThumbnailPtr = nullptr; michael@0: WinUtils::DwmSetIconicLivePreviewBitmapProc WinUtils::dwmSetIconicLivePreviewBitmapPtr = nullptr; michael@0: WinUtils::DwmGetWindowAttributeProc WinUtils::dwmGetWindowAttributePtr = nullptr; michael@0: WinUtils::DwmSetWindowAttributeProc WinUtils::dwmSetWindowAttributePtr = nullptr; michael@0: WinUtils::DwmInvalidateIconicBitmapsProc WinUtils::dwmInvalidateIconicBitmapsPtr = nullptr; michael@0: WinUtils::DwmDefWindowProcProc WinUtils::dwmDwmDefWindowProcPtr = nullptr; michael@0: WinUtils::DwmGetCompositionTimingInfoProc WinUtils::dwmGetCompositionTimingInfoPtr = nullptr; michael@0: michael@0: /* static */ michael@0: void michael@0: WinUtils::Initialize() michael@0: { michael@0: #ifdef PR_LOGGING michael@0: if (!gWindowsLog) { michael@0: gWindowsLog = PR_NewLogModule("Widget"); michael@0: } michael@0: #endif michael@0: if (!sDwmDll && IsVistaOrLater()) { michael@0: sDwmDll = ::LoadLibraryW(kDwmLibraryName); michael@0: michael@0: if (sDwmDll) { michael@0: dwmExtendFrameIntoClientAreaPtr = (DwmExtendFrameIntoClientAreaProc)::GetProcAddress(sDwmDll, "DwmExtendFrameIntoClientArea"); michael@0: dwmIsCompositionEnabledPtr = (DwmIsCompositionEnabledProc)::GetProcAddress(sDwmDll, "DwmIsCompositionEnabled"); michael@0: dwmSetIconicThumbnailPtr = (DwmSetIconicThumbnailProc)::GetProcAddress(sDwmDll, "DwmSetIconicThumbnail"); michael@0: dwmSetIconicLivePreviewBitmapPtr = (DwmSetIconicLivePreviewBitmapProc)::GetProcAddress(sDwmDll, "DwmSetIconicLivePreviewBitmap"); michael@0: dwmGetWindowAttributePtr = (DwmGetWindowAttributeProc)::GetProcAddress(sDwmDll, "DwmGetWindowAttribute"); michael@0: dwmSetWindowAttributePtr = (DwmSetWindowAttributeProc)::GetProcAddress(sDwmDll, "DwmSetWindowAttribute"); michael@0: dwmInvalidateIconicBitmapsPtr = (DwmInvalidateIconicBitmapsProc)::GetProcAddress(sDwmDll, "DwmInvalidateIconicBitmaps"); michael@0: dwmDwmDefWindowProcPtr = (DwmDefWindowProcProc)::GetProcAddress(sDwmDll, "DwmDefWindowProc"); michael@0: dwmGetCompositionTimingInfoPtr = (DwmGetCompositionTimingInfoProc)::GetProcAddress(sDwmDll, "DwmGetCompositionTimingInfo"); michael@0: } michael@0: } michael@0: } michael@0: michael@0: // static michael@0: void michael@0: WinUtils::LogW(const wchar_t *fmt, ...) michael@0: { michael@0: va_list args = nullptr; michael@0: if(!lstrlenW(fmt)) { michael@0: return; michael@0: } michael@0: va_start(args, fmt); michael@0: int buflen = _vscwprintf(fmt, args); michael@0: wchar_t* buffer = new wchar_t[buflen+1]; michael@0: if (!buffer) { michael@0: va_end(args); michael@0: return; michael@0: } michael@0: vswprintf(buffer, buflen, fmt, args); michael@0: va_end(args); michael@0: michael@0: // MSVC, including remote debug sessions michael@0: OutputDebugStringW(buffer); michael@0: OutputDebugStringW(L"\n"); michael@0: michael@0: int len = wcslen(buffer); michael@0: if (len) { michael@0: char* utf8 = new char[len+1]; michael@0: memset(utf8, 0, sizeof(utf8)); michael@0: if (WideCharToMultiByte(CP_ACP, 0, buffer, michael@0: -1, utf8, len+1, nullptr, michael@0: nullptr) > 0) { michael@0: // desktop console michael@0: printf("%s\n", utf8); michael@0: #ifdef PR_LOGGING michael@0: NS_ASSERTION(gWindowsLog, "Called WinUtils Log() but Widget " michael@0: "log module doesn't exist!"); michael@0: PR_LOG(gWindowsLog, PR_LOG_ALWAYS, (utf8)); michael@0: #endif michael@0: } michael@0: delete[] utf8; michael@0: } michael@0: delete[] buffer; michael@0: } michael@0: michael@0: // static michael@0: void michael@0: WinUtils::Log(const char *fmt, ...) michael@0: { michael@0: va_list args = nullptr; michael@0: if(!strlen(fmt)) { michael@0: return; michael@0: } michael@0: va_start(args, fmt); michael@0: int buflen = _vscprintf(fmt, args); michael@0: char* buffer = new char[buflen+1]; michael@0: if (!buffer) { michael@0: va_end(args); michael@0: return; michael@0: } michael@0: vsprintf(buffer, fmt, args); michael@0: va_end(args); michael@0: michael@0: // MSVC, including remote debug sessions michael@0: OutputDebugStringA(buffer); michael@0: OutputDebugStringW(L"\n"); michael@0: michael@0: // desktop console michael@0: printf("%s\n", buffer); michael@0: michael@0: #ifdef PR_LOGGING michael@0: NS_ASSERTION(gWindowsLog, "Called WinUtils Log() but Widget " michael@0: "log module doesn't exist!"); michael@0: PR_LOG(gWindowsLog, PR_LOG_ALWAYS, (buffer)); michael@0: #endif michael@0: delete[] buffer; michael@0: } michael@0: michael@0: /* static */ michael@0: double michael@0: WinUtils::LogToPhysFactor() michael@0: { michael@0: // dpi / 96.0 michael@0: if (XRE_GetWindowsEnvironment() == WindowsEnvironmentType_Metro) { michael@0: #ifdef MOZ_METRO michael@0: return MetroUtils::LogToPhysFactor(); michael@0: #else michael@0: return 1.0; michael@0: #endif michael@0: } else { michael@0: HDC hdc = ::GetDC(nullptr); michael@0: double result = ::GetDeviceCaps(hdc, LOGPIXELSY) / 96.0; michael@0: ::ReleaseDC(nullptr, hdc); michael@0: return result; michael@0: } michael@0: } michael@0: michael@0: /* static */ michael@0: double michael@0: WinUtils::PhysToLogFactor() michael@0: { michael@0: // 1.0 / (dpi / 96.0) michael@0: return 1.0 / LogToPhysFactor(); michael@0: } michael@0: michael@0: /* static */ michael@0: double michael@0: WinUtils::PhysToLog(int32_t aValue) michael@0: { michael@0: return double(aValue) * PhysToLogFactor(); michael@0: } michael@0: michael@0: /* static */ michael@0: int32_t michael@0: WinUtils::LogToPhys(double aValue) michael@0: { michael@0: return int32_t(NS_round(aValue * LogToPhysFactor())); michael@0: } michael@0: michael@0: /* static */ michael@0: bool michael@0: WinUtils::PeekMessage(LPMSG aMsg, HWND aWnd, UINT aFirstMessage, michael@0: UINT aLastMessage, UINT aOption) michael@0: { michael@0: #ifdef NS_ENABLE_TSF michael@0: ITfMessagePump* msgPump = nsTextStore::GetMessagePump(); michael@0: if (msgPump) { michael@0: BOOL ret = FALSE; michael@0: HRESULT hr = msgPump->PeekMessageW(aMsg, aWnd, aFirstMessage, aLastMessage, michael@0: aOption, &ret); michael@0: NS_ENSURE_TRUE(SUCCEEDED(hr), false); michael@0: return ret; michael@0: } michael@0: #endif // #ifdef NS_ENABLE_TSF michael@0: return ::PeekMessageW(aMsg, aWnd, aFirstMessage, aLastMessage, aOption); michael@0: } michael@0: michael@0: /* static */ michael@0: bool michael@0: WinUtils::GetMessage(LPMSG aMsg, HWND aWnd, UINT aFirstMessage, michael@0: UINT aLastMessage) michael@0: { michael@0: #ifdef NS_ENABLE_TSF michael@0: ITfMessagePump* msgPump = nsTextStore::GetMessagePump(); michael@0: if (msgPump) { michael@0: BOOL ret = FALSE; michael@0: HRESULT hr = msgPump->GetMessageW(aMsg, aWnd, aFirstMessage, aLastMessage, michael@0: &ret); michael@0: NS_ENSURE_TRUE(SUCCEEDED(hr), false); michael@0: return ret; michael@0: } michael@0: #endif // #ifdef NS_ENABLE_TSF michael@0: return ::GetMessageW(aMsg, aWnd, aFirstMessage, aLastMessage); michael@0: } michael@0: michael@0: /* static */ michael@0: bool michael@0: WinUtils::GetRegistryKey(HKEY aRoot, michael@0: char16ptr_t aKeyName, michael@0: char16ptr_t aValueName, michael@0: wchar_t* aBuffer, michael@0: DWORD aBufferLength) michael@0: { michael@0: NS_PRECONDITION(aKeyName, "The key name is NULL"); michael@0: michael@0: HKEY key; michael@0: LONG result = michael@0: ::RegOpenKeyExW(aRoot, aKeyName, 0, KEY_READ | KEY_WOW64_32KEY, &key); michael@0: if (result != ERROR_SUCCESS) { michael@0: result = michael@0: ::RegOpenKeyExW(aRoot, aKeyName, 0, KEY_READ | KEY_WOW64_64KEY, &key); michael@0: if (result != ERROR_SUCCESS) { michael@0: return false; michael@0: } michael@0: } michael@0: michael@0: DWORD type; michael@0: result = michael@0: ::RegQueryValueExW(key, aValueName, nullptr, &type, (BYTE*) aBuffer, michael@0: &aBufferLength); michael@0: ::RegCloseKey(key); michael@0: if (result != ERROR_SUCCESS || type != REG_SZ) { michael@0: return false; michael@0: } michael@0: if (aBuffer) { michael@0: aBuffer[aBufferLength / sizeof(*aBuffer) - 1] = 0; michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: /* static */ michael@0: bool michael@0: WinUtils::HasRegistryKey(HKEY aRoot, char16ptr_t aKeyName) michael@0: { michael@0: MOZ_ASSERT(aRoot, "aRoot must not be NULL"); michael@0: MOZ_ASSERT(aKeyName, "aKeyName must not be NULL"); michael@0: HKEY key; michael@0: LONG result = michael@0: ::RegOpenKeyExW(aRoot, aKeyName, 0, KEY_READ | KEY_WOW64_32KEY, &key); michael@0: if (result != ERROR_SUCCESS) { michael@0: result = michael@0: ::RegOpenKeyExW(aRoot, aKeyName, 0, KEY_READ | KEY_WOW64_64KEY, &key); michael@0: if (result != ERROR_SUCCESS) { michael@0: return false; michael@0: } michael@0: } michael@0: ::RegCloseKey(key); michael@0: return true; michael@0: } michael@0: michael@0: /* static */ michael@0: HWND michael@0: WinUtils::GetTopLevelHWND(HWND aWnd, michael@0: bool aStopIfNotChild, michael@0: bool aStopIfNotPopup) michael@0: { michael@0: HWND curWnd = aWnd; michael@0: HWND topWnd = nullptr; michael@0: michael@0: while (curWnd) { michael@0: topWnd = curWnd; michael@0: michael@0: if (aStopIfNotChild) { michael@0: DWORD_PTR style = ::GetWindowLongPtrW(curWnd, GWL_STYLE); michael@0: michael@0: VERIFY_WINDOW_STYLE(style); michael@0: michael@0: if (!(style & WS_CHILD)) // first top-level window michael@0: break; michael@0: } michael@0: michael@0: HWND upWnd = ::GetParent(curWnd); // Parent or owner (if has no parent) michael@0: michael@0: // GetParent will only return the owner if the passed in window michael@0: // has the WS_POPUP style. michael@0: if (!upWnd && !aStopIfNotPopup) { michael@0: upWnd = ::GetWindow(curWnd, GW_OWNER); michael@0: } michael@0: curWnd = upWnd; michael@0: } michael@0: michael@0: return topWnd; michael@0: } michael@0: michael@0: static const wchar_t* michael@0: GetNSWindowPropName() michael@0: { michael@0: static wchar_t sPropName[40] = L""; michael@0: if (!*sPropName) { michael@0: _snwprintf(sPropName, 39, L"MozillansIWidgetPtr%p", michael@0: ::GetCurrentProcessId()); michael@0: sPropName[39] = '\0'; michael@0: } michael@0: return sPropName; michael@0: } michael@0: michael@0: /* static */ michael@0: bool michael@0: WinUtils::SetNSWindowBasePtr(HWND aWnd, nsWindowBase* aWidget) michael@0: { michael@0: if (!aWidget) { michael@0: ::RemovePropW(aWnd, GetNSWindowPropName()); michael@0: return true; michael@0: } michael@0: return ::SetPropW(aWnd, GetNSWindowPropName(), (HANDLE)aWidget); michael@0: } michael@0: michael@0: /* static */ michael@0: nsWindowBase* michael@0: WinUtils::GetNSWindowBasePtr(HWND aWnd) michael@0: { michael@0: return static_cast(::GetPropW(aWnd, GetNSWindowPropName())); michael@0: } michael@0: michael@0: /* static */ michael@0: nsWindow* michael@0: WinUtils::GetNSWindowPtr(HWND aWnd) michael@0: { michael@0: return static_cast(::GetPropW(aWnd, GetNSWindowPropName())); michael@0: } michael@0: michael@0: static BOOL CALLBACK michael@0: AddMonitor(HMONITOR, HDC, LPRECT, LPARAM aParam) michael@0: { michael@0: (*(int32_t*)aParam)++; michael@0: return TRUE; michael@0: } michael@0: michael@0: /* static */ michael@0: int32_t michael@0: WinUtils::GetMonitorCount() michael@0: { michael@0: int32_t monitorCount = 0; michael@0: EnumDisplayMonitors(nullptr, nullptr, AddMonitor, (LPARAM)&monitorCount); michael@0: return monitorCount; michael@0: } michael@0: michael@0: /* static */ michael@0: bool michael@0: WinUtils::IsOurProcessWindow(HWND aWnd) michael@0: { michael@0: if (!aWnd) { michael@0: return false; michael@0: } michael@0: DWORD processId = 0; michael@0: ::GetWindowThreadProcessId(aWnd, &processId); michael@0: return (processId == ::GetCurrentProcessId()); michael@0: } michael@0: michael@0: /* static */ michael@0: HWND michael@0: WinUtils::FindOurProcessWindow(HWND aWnd) michael@0: { michael@0: for (HWND wnd = ::GetParent(aWnd); wnd; wnd = ::GetParent(wnd)) { michael@0: if (IsOurProcessWindow(wnd)) { michael@0: return wnd; michael@0: } michael@0: } michael@0: return nullptr; michael@0: } michael@0: michael@0: static bool michael@0: IsPointInWindow(HWND aWnd, const POINT& aPointInScreen) michael@0: { michael@0: RECT bounds; michael@0: if (!::GetWindowRect(aWnd, &bounds)) { michael@0: return false; michael@0: } michael@0: michael@0: return (aPointInScreen.x >= bounds.left && aPointInScreen.x < bounds.right && michael@0: aPointInScreen.y >= bounds.top && aPointInScreen.y < bounds.bottom); michael@0: } michael@0: michael@0: /** michael@0: * FindTopmostWindowAtPoint() returns the topmost child window (topmost means michael@0: * forground in this context) of aWnd. michael@0: */ michael@0: michael@0: static HWND michael@0: FindTopmostWindowAtPoint(HWND aWnd, const POINT& aPointInScreen) michael@0: { michael@0: if (!::IsWindowVisible(aWnd) || !IsPointInWindow(aWnd, aPointInScreen)) { michael@0: return nullptr; michael@0: } michael@0: michael@0: HWND childWnd = ::GetTopWindow(aWnd); michael@0: while (childWnd) { michael@0: HWND topmostWnd = FindTopmostWindowAtPoint(childWnd, aPointInScreen); michael@0: if (topmostWnd) { michael@0: return topmostWnd; michael@0: } michael@0: childWnd = ::GetNextWindow(childWnd, GW_HWNDNEXT); michael@0: } michael@0: michael@0: return aWnd; michael@0: } michael@0: michael@0: struct FindOurWindowAtPointInfo michael@0: { michael@0: POINT mInPointInScreen; michael@0: HWND mOutWnd; michael@0: }; michael@0: michael@0: static BOOL CALLBACK michael@0: FindOurWindowAtPointCallback(HWND aWnd, LPARAM aLPARAM) michael@0: { michael@0: if (!WinUtils::IsOurProcessWindow(aWnd)) { michael@0: // This isn't one of our top-level windows; continue enumerating. michael@0: return TRUE; michael@0: } michael@0: michael@0: // Get the top-most child window under the point. If there's no child michael@0: // window, and the point is within the top-level window, then the top-level michael@0: // window will be returned. (This is the usual case. A child window michael@0: // would be returned for plugins.) michael@0: FindOurWindowAtPointInfo* info = michael@0: reinterpret_cast(aLPARAM); michael@0: HWND childWnd = FindTopmostWindowAtPoint(aWnd, info->mInPointInScreen); michael@0: if (!childWnd) { michael@0: // This window doesn't contain the point; continue enumerating. michael@0: return TRUE; michael@0: } michael@0: michael@0: // Return the HWND and stop enumerating. michael@0: info->mOutWnd = childWnd; michael@0: return FALSE; michael@0: } michael@0: michael@0: /* static */ michael@0: HWND michael@0: WinUtils::FindOurWindowAtPoint(const POINT& aPointInScreen) michael@0: { michael@0: FindOurWindowAtPointInfo info; michael@0: info.mInPointInScreen = aPointInScreen; michael@0: info.mOutWnd = nullptr; michael@0: michael@0: // This will enumerate all top-level windows in order from top to bottom. michael@0: EnumWindows(FindOurWindowAtPointCallback, reinterpret_cast(&info)); michael@0: return info.mOutWnd; michael@0: } michael@0: michael@0: /* static */ michael@0: UINT michael@0: WinUtils::GetInternalMessage(UINT aNativeMessage) michael@0: { michael@0: switch (aNativeMessage) { michael@0: case WM_MOUSEWHEEL: michael@0: return MOZ_WM_MOUSEVWHEEL; michael@0: case WM_MOUSEHWHEEL: michael@0: return MOZ_WM_MOUSEHWHEEL; michael@0: case WM_VSCROLL: michael@0: return MOZ_WM_VSCROLL; michael@0: case WM_HSCROLL: michael@0: return MOZ_WM_HSCROLL; michael@0: default: michael@0: return aNativeMessage; michael@0: } michael@0: } michael@0: michael@0: /* static */ michael@0: UINT michael@0: WinUtils::GetNativeMessage(UINT aInternalMessage) michael@0: { michael@0: switch (aInternalMessage) { michael@0: case MOZ_WM_MOUSEVWHEEL: michael@0: return WM_MOUSEWHEEL; michael@0: case MOZ_WM_MOUSEHWHEEL: michael@0: return WM_MOUSEHWHEEL; michael@0: case MOZ_WM_VSCROLL: michael@0: return WM_VSCROLL; michael@0: case MOZ_WM_HSCROLL: michael@0: return WM_HSCROLL; michael@0: default: michael@0: return aInternalMessage; michael@0: } michael@0: } michael@0: michael@0: /* static */ michael@0: uint16_t michael@0: WinUtils::GetMouseInputSource() michael@0: { michael@0: int32_t inputSource = nsIDOMMouseEvent::MOZ_SOURCE_MOUSE; michael@0: LPARAM lParamExtraInfo = ::GetMessageExtraInfo(); michael@0: if ((lParamExtraInfo & TABLET_INK_SIGNATURE) == TABLET_INK_CHECK) { michael@0: inputSource = (lParamExtraInfo & TABLET_INK_TOUCH) ? michael@0: nsIDOMMouseEvent::MOZ_SOURCE_TOUCH : nsIDOMMouseEvent::MOZ_SOURCE_PEN; michael@0: } michael@0: return static_cast(inputSource); michael@0: } michael@0: michael@0: bool michael@0: WinUtils::GetIsMouseFromTouch(uint32_t aEventType) michael@0: { michael@0: #define MOUSEEVENTF_FROMTOUCH 0xFF515700 michael@0: return (aEventType == NS_MOUSE_BUTTON_DOWN || michael@0: aEventType == NS_MOUSE_BUTTON_UP || michael@0: aEventType == NS_MOUSE_MOVE) && michael@0: (GetMessageExtraInfo() & MOUSEEVENTF_FROMTOUCH); michael@0: } michael@0: michael@0: /* static */ michael@0: MSG michael@0: WinUtils::InitMSG(UINT aMessage, WPARAM wParam, LPARAM lParam, HWND aWnd) michael@0: { michael@0: MSG msg; michael@0: msg.message = aMessage; michael@0: msg.wParam = wParam; michael@0: msg.lParam = lParam; michael@0: msg.hwnd = aWnd; michael@0: return msg; michael@0: } michael@0: michael@0: /* static */ michael@0: HRESULT michael@0: WinUtils::SHCreateItemFromParsingName(PCWSTR pszPath, IBindCtx *pbc, michael@0: REFIID riid, void **ppv) michael@0: { michael@0: if (sCreateItemFromParsingName) { michael@0: return sCreateItemFromParsingName(pszPath, pbc, riid, ppv); michael@0: } michael@0: michael@0: if (!sShellDll) { michael@0: sShellDll = ::LoadLibraryW(kShellLibraryName); michael@0: if (!sShellDll) { michael@0: return false; michael@0: } michael@0: } michael@0: michael@0: sCreateItemFromParsingName = (SHCreateItemFromParsingNamePtr) michael@0: GetProcAddress(sShellDll, "SHCreateItemFromParsingName"); michael@0: if (!sCreateItemFromParsingName) michael@0: return E_FAIL; michael@0: michael@0: return sCreateItemFromParsingName(pszPath, pbc, riid, ppv); michael@0: } michael@0: michael@0: /* static */ michael@0: HRESULT michael@0: WinUtils::SHGetKnownFolderPath(REFKNOWNFOLDERID rfid, michael@0: DWORD dwFlags, michael@0: HANDLE hToken, michael@0: PWSTR *ppszPath) michael@0: { michael@0: if (sGetKnownFolderPath) { michael@0: return sGetKnownFolderPath(rfid, dwFlags, hToken, ppszPath); michael@0: } michael@0: michael@0: if (!sShellDll) { michael@0: sShellDll = ::LoadLibraryW(kShellLibraryName); michael@0: if (!sShellDll) { michael@0: return false; michael@0: } michael@0: } michael@0: michael@0: sGetKnownFolderPath = (SHGetKnownFolderPathPtr) michael@0: GetProcAddress(sShellDll, "SHGetKnownFolderPath"); michael@0: if (!sGetKnownFolderPath) michael@0: return E_FAIL; michael@0: michael@0: return sGetKnownFolderPath(rfid, dwFlags, hToken, ppszPath); michael@0: } michael@0: michael@0: #ifdef MOZ_PLACES michael@0: /************************************************************************/ michael@0: /* Constructs as AsyncFaviconDataReady Object michael@0: /* @param aIOThread : the thread which performs the action michael@0: /* @param aURLShortcut : Differentiates between (false)Jumplistcache and (true)Shortcutcache michael@0: /************************************************************************/ michael@0: michael@0: AsyncFaviconDataReady::AsyncFaviconDataReady(nsIURI *aNewURI, michael@0: nsCOMPtr &aIOThread, michael@0: const bool aURLShortcut): michael@0: mNewURI(aNewURI), michael@0: mIOThread(aIOThread), michael@0: mURLShortcut(aURLShortcut) michael@0: { michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: myDownloadObserver::OnDownloadComplete(nsIDownloader *downloader, michael@0: nsIRequest *request, michael@0: nsISupports *ctxt, michael@0: nsresult status, michael@0: nsIFile *result) michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult AsyncFaviconDataReady::OnFaviconDataNotAvailable(void) michael@0: { michael@0: if (!mURLShortcut) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsCOMPtr icoFile; michael@0: nsresult rv = FaviconHelper::GetOutputIconPath(mNewURI, icoFile, mURLShortcut); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: nsCOMPtr mozIconURI; michael@0: rv = NS_NewURI(getter_AddRefs(mozIconURI), "moz-icon://.html?size=32"); michael@0: if (NS_FAILED(rv)) { michael@0: return rv; michael@0: } michael@0: michael@0: nsCOMPtr channel; michael@0: rv = NS_NewChannel(getter_AddRefs(channel), mozIconURI); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: nsCOMPtr downloadObserver = new myDownloadObserver; michael@0: nsCOMPtr listener; michael@0: rv = NS_NewDownloader(getter_AddRefs(listener), downloadObserver, icoFile); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: channel->AsyncOpen(listener, nullptr); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: AsyncFaviconDataReady::OnComplete(nsIURI *aFaviconURI, michael@0: uint32_t aDataLen, michael@0: const uint8_t *aData, michael@0: const nsACString &aMimeType) michael@0: { michael@0: if (!aDataLen || !aData) { michael@0: if (mURLShortcut) { michael@0: OnFaviconDataNotAvailable(); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsCOMPtr icoFile; michael@0: nsresult rv = FaviconHelper::GetOutputIconPath(mNewURI, icoFile, mURLShortcut); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: nsAutoString path; michael@0: rv = icoFile->GetPath(path); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: // Convert the obtained favicon data to an input stream michael@0: nsCOMPtr stream; michael@0: rv = NS_NewByteInputStream(getter_AddRefs(stream), michael@0: reinterpret_cast(aData), michael@0: aDataLen, michael@0: NS_ASSIGNMENT_DEPEND); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: // Decode the image from the format it was returned to us in (probably PNG) michael@0: nsAutoCString mimeTypeOfInputData; michael@0: mimeTypeOfInputData.AssignLiteral("image/vnd.microsoft.icon"); michael@0: nsCOMPtr container; michael@0: nsCOMPtr imgtool = do_CreateInstance("@mozilla.org/image/tools;1"); michael@0: rv = imgtool->DecodeImageData(stream, aMimeType, michael@0: getter_AddRefs(container)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: RefPtr surface = michael@0: container->GetFrame(imgIContainer::FRAME_FIRST, 0); michael@0: NS_ENSURE_TRUE(surface, NS_ERROR_FAILURE); michael@0: michael@0: RefPtr dataSurface; michael@0: IntSize size; michael@0: michael@0: if (mURLShortcut) { michael@0: // Create a 48x48 surface and paint the icon into the central 16x16 rect. michael@0: size.width = 48; michael@0: size.height = 48; michael@0: dataSurface = michael@0: Factory::CreateDataSourceSurface(size, SurfaceFormat::B8G8R8A8); michael@0: NS_ENSURE_TRUE(dataSurface, NS_ERROR_FAILURE); michael@0: michael@0: DataSourceSurface::MappedSurface map; michael@0: if (!dataSurface->Map(DataSourceSurface::MapType::WRITE, &map)) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: RefPtr dt = michael@0: Factory::CreateDrawTargetForData(BackendType::CAIRO, michael@0: map.mData, michael@0: dataSurface->GetSize(), michael@0: map.mStride, michael@0: dataSurface->GetFormat()); michael@0: dt->FillRect(Rect(0, 0, size.width, size.height), michael@0: ColorPattern(Color(1.0f, 1.0f, 1.0f, 1.0f))); michael@0: dt->DrawSurface(surface, michael@0: Rect(16, 16, 16, 16), michael@0: Rect(Point(0, 0), michael@0: Size(surface->GetSize().width, surface->GetSize().height))); michael@0: michael@0: dataSurface->Unmap(); michael@0: } else { michael@0: // By using the input image surface's size, we may end up encoding michael@0: // to a different size than a 16x16 (or bigger for higher DPI) ICO, but michael@0: // Windows will resize appropriately for us. If we want to encode ourselves michael@0: // one day because we like our resizing better, we'd have to manually michael@0: // resize the image here and use GetSystemMetrics w/ SM_CXSMICON and michael@0: // SM_CYSMICON. We don't support resizing images asynchronously at the michael@0: // moment anyway so getting the DPI aware icon size won't help. michael@0: size.width = surface->GetSize().width; michael@0: size.height = surface->GetSize().height; michael@0: dataSurface = surface->GetDataSurface(); michael@0: NS_ENSURE_TRUE(dataSurface, NS_ERROR_FAILURE); michael@0: } michael@0: michael@0: // Allocate a new buffer that we own and can use out of line in michael@0: // another thread. michael@0: uint8_t *data = SurfaceToPackedBGRA(dataSurface); michael@0: if (!data) { michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: } michael@0: int32_t stride = 4 * size.width; michael@0: int32_t dataLength = stride * size.height; michael@0: michael@0: // AsyncEncodeAndWriteIcon takes ownership of the heap allocated buffer michael@0: nsCOMPtr event = new AsyncEncodeAndWriteIcon(path, data, michael@0: dataLength, michael@0: stride, michael@0: size.width, michael@0: size.height, michael@0: mURLShortcut); michael@0: mIOThread->Dispatch(event, NS_DISPATCH_NORMAL); michael@0: michael@0: return NS_OK; michael@0: } michael@0: #endif michael@0: michael@0: // Warning: AsyncEncodeAndWriteIcon assumes ownership of the aData buffer passed in michael@0: AsyncEncodeAndWriteIcon::AsyncEncodeAndWriteIcon(const nsAString &aIconPath, michael@0: uint8_t *aBuffer, michael@0: uint32_t aBufferLength, michael@0: uint32_t aStride, michael@0: uint32_t aWidth, michael@0: uint32_t aHeight, michael@0: const bool aURLShortcut) : michael@0: mURLShortcut(aURLShortcut), michael@0: mIconPath(aIconPath), michael@0: mBuffer(aBuffer), michael@0: mBufferLength(aBufferLength), michael@0: mStride(aStride), michael@0: mWidth(aWidth), michael@0: mHeight(aHeight) michael@0: { michael@0: } michael@0: michael@0: NS_IMETHODIMP AsyncEncodeAndWriteIcon::Run() michael@0: { michael@0: NS_PRECONDITION(!NS_IsMainThread(), "Should not be called on the main thread."); michael@0: michael@0: nsCOMPtr iconStream; michael@0: nsRefPtr encoder = michael@0: do_CreateInstance("@mozilla.org/image/encoder;2?" michael@0: "type=image/vnd.microsoft.icon"); michael@0: NS_ENSURE_TRUE(encoder, NS_ERROR_FAILURE); michael@0: nsresult rv = encoder->InitFromData(mBuffer, mBufferLength, michael@0: mWidth, mHeight, michael@0: mStride, michael@0: imgIEncoder::INPUT_FORMAT_HOSTARGB, michael@0: EmptyString()); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: CallQueryInterface(encoder.get(), getter_AddRefs(iconStream)); michael@0: if (!iconStream) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: nsCOMPtr icoFile michael@0: = do_CreateInstance("@mozilla.org/file/local;1"); michael@0: NS_ENSURE_TRUE(icoFile, NS_ERROR_FAILURE); michael@0: rv = icoFile->InitWithPath(mIconPath); michael@0: michael@0: // Try to create the directory if it's not there yet michael@0: nsCOMPtr dirPath; michael@0: icoFile->GetParent(getter_AddRefs(dirPath)); michael@0: rv = (dirPath->Create(nsIFile::DIRECTORY_TYPE, 0777)); michael@0: if (NS_FAILED(rv) && rv != NS_ERROR_FILE_ALREADY_EXISTS) { michael@0: return rv; michael@0: } michael@0: michael@0: // Setup the output stream for the ICO file on disk michael@0: nsCOMPtr outputStream; michael@0: rv = NS_NewLocalFileOutputStream(getter_AddRefs(outputStream), icoFile); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: // Obtain the ICO buffer size from the re-encoded ICO stream michael@0: uint64_t bufSize64; michael@0: rv = iconStream->Available(&bufSize64); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: NS_ENSURE_TRUE(bufSize64 <= UINT32_MAX, NS_ERROR_FILE_TOO_BIG); michael@0: michael@0: uint32_t bufSize = (uint32_t)bufSize64; michael@0: michael@0: // Setup a buffered output stream from the stream object michael@0: // so that we can simply use WriteFrom with the stream object michael@0: nsCOMPtr bufferedOutputStream; michael@0: rv = NS_NewBufferedOutputStream(getter_AddRefs(bufferedOutputStream), michael@0: outputStream, bufSize); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: // Write out the icon stream to disk and make sure we wrote everything michael@0: uint32_t wrote; michael@0: rv = bufferedOutputStream->WriteFrom(iconStream, bufSize, &wrote); michael@0: NS_ASSERTION(bufSize == wrote, michael@0: "Icon wrote size should be equal to requested write size"); michael@0: michael@0: // Cleanup michael@0: bufferedOutputStream->Close(); michael@0: outputStream->Close(); michael@0: if (mURLShortcut) { michael@0: SendMessage(HWND_BROADCAST, WM_SETTINGCHANGE, SPI_SETNONCLIENTMETRICS, 0); michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: AsyncEncodeAndWriteIcon::~AsyncEncodeAndWriteIcon() michael@0: { michael@0: } michael@0: michael@0: AsyncDeleteIconFromDisk::AsyncDeleteIconFromDisk(const nsAString &aIconPath) michael@0: : mIconPath(aIconPath) michael@0: { michael@0: } michael@0: michael@0: NS_IMETHODIMP AsyncDeleteIconFromDisk::Run() michael@0: { michael@0: // Construct the parent path of the passed in path michael@0: nsCOMPtr icoFile = do_CreateInstance("@mozilla.org/file/local;1"); michael@0: NS_ENSURE_TRUE(icoFile, NS_ERROR_FAILURE); michael@0: nsresult rv = icoFile->InitWithPath(mIconPath); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: // Check if the cached ICO file exists michael@0: bool exists; michael@0: rv = icoFile->Exists(&exists); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: // Check that we aren't deleting some arbitrary file that is not an icon michael@0: if (StringTail(mIconPath, 4).LowerCaseEqualsASCII(".ico")) { michael@0: // Check if the cached ICO file exists michael@0: bool exists; michael@0: if (NS_FAILED(icoFile->Exists(&exists)) || !exists) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: // We found an ICO file that exists, so we should remove it michael@0: icoFile->Remove(false); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: AsyncDeleteIconFromDisk::~AsyncDeleteIconFromDisk() michael@0: { michael@0: } michael@0: michael@0: AsyncDeleteAllFaviconsFromDisk::AsyncDeleteAllFaviconsFromDisk() michael@0: { michael@0: } michael@0: michael@0: NS_IMETHODIMP AsyncDeleteAllFaviconsFromDisk::Run() michael@0: { michael@0: // Construct the path of our jump list cache michael@0: nsCOMPtr jumpListCacheDir; michael@0: nsresult rv = NS_GetSpecialDirectory("ProfLDS", michael@0: getter_AddRefs(jumpListCacheDir)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: rv = jumpListCacheDir->AppendNative( michael@0: nsDependentCString(FaviconHelper::kJumpListCacheDir)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: nsCOMPtr entries; michael@0: rv = jumpListCacheDir->GetDirectoryEntries(getter_AddRefs(entries)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: // Loop through each directory entry and remove all ICO files found michael@0: do { michael@0: bool hasMore = false; michael@0: if (NS_FAILED(entries->HasMoreElements(&hasMore)) || !hasMore) michael@0: break; michael@0: michael@0: nsCOMPtr supp; michael@0: if (NS_FAILED(entries->GetNext(getter_AddRefs(supp)))) michael@0: break; michael@0: michael@0: nsCOMPtr currFile(do_QueryInterface(supp)); michael@0: nsAutoString path; michael@0: if (NS_FAILED(currFile->GetPath(path))) michael@0: continue; michael@0: michael@0: if (StringTail(path, 4).LowerCaseEqualsASCII(".ico")) { michael@0: // Check if the cached ICO file exists michael@0: bool exists; michael@0: if (NS_FAILED(currFile->Exists(&exists)) || !exists) michael@0: continue; michael@0: michael@0: // We found an ICO file that exists, so we should remove it michael@0: currFile->Remove(false); michael@0: } michael@0: } while(true); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: AsyncDeleteAllFaviconsFromDisk::~AsyncDeleteAllFaviconsFromDisk() michael@0: { michael@0: } michael@0: michael@0: michael@0: /* michael@0: * (static) If the data is available, will return the path on disk where michael@0: * the favicon for page aFaviconPageURI is stored. If the favicon does not michael@0: * exist, or its cache is expired, this method will kick off an async request michael@0: * for the icon so that next time the method is called it will be available. michael@0: * @param aFaviconPageURI The URI of the page to obtain michael@0: * @param aICOFilePath The path of the icon file michael@0: * @param aIOThread The thread to perform the Fetch on michael@0: * @param aURLShortcut to distinguish between jumplistcache(false) and shortcutcache(true) michael@0: */ michael@0: nsresult FaviconHelper::ObtainCachedIconFile(nsCOMPtr aFaviconPageURI, michael@0: nsString &aICOFilePath, michael@0: nsCOMPtr &aIOThread, michael@0: bool aURLShortcut) michael@0: { michael@0: // Obtain the ICO file path michael@0: nsCOMPtr icoFile; michael@0: nsresult rv = GetOutputIconPath(aFaviconPageURI, icoFile, aURLShortcut); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: // Check if the cached ICO file already exists michael@0: bool exists; michael@0: rv = icoFile->Exists(&exists); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: if (exists) { michael@0: michael@0: // Obtain the file's last modification date in seconds michael@0: int64_t fileModTime = 0; michael@0: rv = icoFile->GetLastModifiedTime(&fileModTime); michael@0: fileModTime /= PR_MSEC_PER_SEC; michael@0: int32_t icoReCacheSecondsTimeout = GetICOCacheSecondsTimeout(); michael@0: int64_t nowTime = PR_Now() / int64_t(PR_USEC_PER_SEC); michael@0: michael@0: // If the last mod call failed or the icon is old then re-cache it michael@0: // This check is in case the favicon of a page changes michael@0: // the next time we try to build the jump list, the data will be available. michael@0: if (NS_FAILED(rv) || michael@0: (nowTime - fileModTime) > icoReCacheSecondsTimeout) { michael@0: CacheIconFileFromFaviconURIAsync(aFaviconPageURI, icoFile, aIOThread, aURLShortcut); michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: } michael@0: } else { michael@0: michael@0: // The file does not exist yet, obtain it async from the favicon service so that michael@0: // the next time we try to build the jump list it'll be available. michael@0: CacheIconFileFromFaviconURIAsync(aFaviconPageURI, icoFile, aIOThread, aURLShortcut); michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: } michael@0: michael@0: // The icoFile is filled with a path that exists, get its path michael@0: rv = icoFile->GetPath(aICOFilePath); michael@0: return rv; michael@0: } michael@0: michael@0: nsresult FaviconHelper::HashURI(nsCOMPtr &aCryptoHash, michael@0: nsIURI *aUri, michael@0: nsACString& aUriHash) michael@0: { michael@0: if (!aUri) michael@0: return NS_ERROR_INVALID_ARG; michael@0: michael@0: nsAutoCString spec; michael@0: nsresult rv = aUri->GetSpec(spec); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: if (!aCryptoHash) { michael@0: aCryptoHash = do_CreateInstance(NS_CRYPTO_HASH_CONTRACTID, &rv); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: } michael@0: michael@0: rv = aCryptoHash->Init(nsICryptoHash::MD5); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: rv = aCryptoHash->Update(reinterpret_cast(spec.BeginReading()), michael@0: spec.Length()); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: rv = aCryptoHash->Finish(true, aUriHash); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: michael@0: // (static) Obtains the ICO file for the favicon at page aFaviconPageURI michael@0: // If successful, the file path on disk is in the format: michael@0: // \jumpListCache\.ico michael@0: nsresult FaviconHelper::GetOutputIconPath(nsCOMPtr aFaviconPageURI, michael@0: nsCOMPtr &aICOFile, michael@0: bool aURLShortcut) michael@0: { michael@0: // Hash the input URI and replace any / with _ michael@0: nsAutoCString inputURIHash; michael@0: nsCOMPtr cryptoHash; michael@0: nsresult rv = HashURI(cryptoHash, aFaviconPageURI, michael@0: inputURIHash); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: char* cur = inputURIHash.BeginWriting(); michael@0: char* end = inputURIHash.EndWriting(); michael@0: for (; cur < end; ++cur) { michael@0: if ('/' == *cur) { michael@0: *cur = '_'; michael@0: } michael@0: } michael@0: michael@0: // Obtain the local profile directory and construct the output icon file path michael@0: rv = NS_GetSpecialDirectory("ProfLDS", getter_AddRefs(aICOFile)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: if (!aURLShortcut) michael@0: rv = aICOFile->AppendNative(nsDependentCString(kJumpListCacheDir)); michael@0: else michael@0: rv = aICOFile->AppendNative(nsDependentCString(kShortcutCacheDir)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: // Append the icon extension michael@0: inputURIHash.Append(".ico"); michael@0: rv = aICOFile->AppendNative(inputURIHash); michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: // (static) Asynchronously creates a cached ICO file on disk for the favicon of michael@0: // page aFaviconPageURI and stores it to disk at the path of aICOFile. michael@0: nsresult michael@0: FaviconHelper::CacheIconFileFromFaviconURIAsync(nsCOMPtr aFaviconPageURI, michael@0: nsCOMPtr aICOFile, michael@0: nsCOMPtr &aIOThread, michael@0: bool aURLShortcut) michael@0: { michael@0: #ifdef MOZ_PLACES michael@0: // Obtain the favicon service and get the favicon for the specified page michael@0: nsCOMPtr favIconSvc( michael@0: do_GetService("@mozilla.org/browser/favicon-service;1")); michael@0: NS_ENSURE_TRUE(favIconSvc, NS_ERROR_FAILURE); michael@0: michael@0: nsCOMPtr callback = michael@0: new mozilla::widget::AsyncFaviconDataReady(aFaviconPageURI, michael@0: aIOThread, michael@0: aURLShortcut); michael@0: michael@0: favIconSvc->GetFaviconDataForPage(aFaviconPageURI, callback); michael@0: #endif michael@0: return NS_OK; michael@0: } michael@0: michael@0: // Obtains the jump list 'ICO cache timeout in seconds' pref michael@0: int32_t FaviconHelper::GetICOCacheSecondsTimeout() { michael@0: michael@0: // Only obtain the setting at most once from the pref service. michael@0: // In the rare case that 2 threads call this at the same michael@0: // time it is no harm and we will simply obtain the pref twice. michael@0: // None of the taskbar list prefs are currently updated via a michael@0: // pref observer so I think this should suffice. michael@0: const int32_t kSecondsPerDay = 86400; michael@0: static bool alreadyObtained = false; michael@0: static int32_t icoReCacheSecondsTimeout = kSecondsPerDay; michael@0: if (alreadyObtained) { michael@0: return icoReCacheSecondsTimeout; michael@0: } michael@0: michael@0: // Obtain the pref michael@0: const char PREF_ICOTIMEOUT[] = "browser.taskbar.lists.icoTimeoutInSeconds"; michael@0: icoReCacheSecondsTimeout = Preferences::GetInt(PREF_ICOTIMEOUT, michael@0: kSecondsPerDay); michael@0: alreadyObtained = true; michael@0: return icoReCacheSecondsTimeout; michael@0: } michael@0: michael@0: michael@0: michael@0: michael@0: /* static */ michael@0: bool michael@0: WinUtils::GetShellItemPath(IShellItem* aItem, michael@0: nsString& aResultString) michael@0: { michael@0: NS_ENSURE_TRUE(aItem, false); michael@0: LPWSTR str = nullptr; michael@0: if (FAILED(aItem->GetDisplayName(SIGDN_FILESYSPATH, &str))) michael@0: return false; michael@0: aResultString.Assign(str); michael@0: CoTaskMemFree(str); michael@0: return !aResultString.IsEmpty(); michael@0: } michael@0: michael@0: /* static */ michael@0: nsIntRegion michael@0: WinUtils::ConvertHRGNToRegion(HRGN aRgn) michael@0: { michael@0: NS_ASSERTION(aRgn, "Don't pass NULL region here"); michael@0: michael@0: nsIntRegion rgn; michael@0: michael@0: DWORD size = ::GetRegionData(aRgn, 0, nullptr); michael@0: nsAutoTArray buffer; michael@0: buffer.SetLength(size); michael@0: michael@0: RGNDATA* data = reinterpret_cast(buffer.Elements()); michael@0: if (!::GetRegionData(aRgn, size, data)) michael@0: return rgn; michael@0: michael@0: if (data->rdh.nCount > MAX_RECTS_IN_REGION) { michael@0: rgn = ToIntRect(data->rdh.rcBound); michael@0: return rgn; michael@0: } michael@0: michael@0: RECT* rects = reinterpret_cast(data->Buffer); michael@0: for (uint32_t i = 0; i < data->rdh.nCount; ++i) { michael@0: RECT* r = rects + i; michael@0: rgn.Or(rgn, ToIntRect(*r)); michael@0: } michael@0: michael@0: return rgn; michael@0: } michael@0: michael@0: nsIntRect michael@0: WinUtils::ToIntRect(const RECT& aRect) michael@0: { michael@0: return nsIntRect(aRect.left, aRect.top, michael@0: aRect.right - aRect.left, michael@0: aRect.bottom - aRect.top); michael@0: } michael@0: michael@0: /* static */ michael@0: bool michael@0: WinUtils::IsIMEEnabled(const InputContext& aInputContext) michael@0: { michael@0: return IsIMEEnabled(aInputContext.mIMEState.mEnabled); michael@0: } michael@0: michael@0: /* static */ michael@0: bool michael@0: WinUtils::IsIMEEnabled(IMEState::Enabled aIMEState) michael@0: { michael@0: return (aIMEState == IMEState::ENABLED || michael@0: aIMEState == IMEState::PLUGIN); michael@0: } michael@0: michael@0: /* static */ michael@0: void michael@0: WinUtils::SetupKeyModifiersSequence(nsTArray* aArray, michael@0: uint32_t aModifiers) michael@0: { michael@0: for (uint32_t i = 0; i < ArrayLength(sModifierKeyMap); ++i) { michael@0: const uint32_t* map = sModifierKeyMap[i]; michael@0: if (aModifiers & map[0]) { michael@0: aArray->AppendElement(KeyPair(map[1], map[2])); michael@0: } michael@0: } michael@0: } michael@0: michael@0: /* static */ michael@0: bool michael@0: WinUtils::ShouldHideScrollbars() michael@0: { michael@0: #ifdef MOZ_METRO michael@0: if (XRE_GetWindowsEnvironment() == WindowsEnvironmentType_Metro) { michael@0: return widget::winrt::MetroInput::IsInputModeImprecise(); michael@0: } michael@0: #endif // MOZ_METRO michael@0: return false; michael@0: } michael@0: michael@0: } // namespace widget michael@0: } // namespace mozilla