/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim:set ts=2 sts=2 sw=2 et cin: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
using GetDpiForWindowProc = UINT(WINAPI*)(HWND); static GetDpiForWindowProc sGetDpiForWindow = NULL;
/* static */ void WinUtils::Initialize() { // Dpi-Awareness is not supported with Win32k Lockdown enabled, so we don't // initialize DPI-related members and assert later that nothing accidently // uses these static members if (!IsWin32kLockedDown()) {
HMODULE user32Dll = ::GetModuleHandleW(L"user32"); if (user32Dll) { auto getThreadDpiAwarenessContext =
(decltype(GetThreadDpiAwarenessContext)*)::GetProcAddress(
user32Dll, "GetThreadDpiAwarenessContext"); auto areDpiAwarenessContextsEqual =
(decltype(AreDpiAwarenessContextsEqual)*)::GetProcAddress(
user32Dll, "AreDpiAwarenessContextsEqual"); if (getThreadDpiAwarenessContext && areDpiAwarenessContextsEqual &&
areDpiAwarenessContextsEqual(
getThreadDpiAwarenessContext(),
DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE)) { // Only per-monitor v1 requires these workarounds.
sEnableNonClientDpiScaling =
(EnableNonClientDpiScalingProc)::GetProcAddress(
user32Dll, "EnableNonClientDpiScaling");
sSetThreadDpiAwarenessContext =
(SetThreadDpiAwarenessContextProc)::GetProcAddress(
user32Dll, "SetThreadDpiAwarenessContext");
}
// NOTE: this function was copied out into the body of the pre-XUL skeleton // UI window proc (PreXULSkeletonUI.cpp). If this function changes at any // point, we should probably factor this out and use it from both locations. if (msg == WM_NCCREATE && sEnableNonClientDpiScaling) {
sEnableNonClientDpiScaling(hWnd);
} return ::DefWindowProcW(hWnd, msg, wParam, lParam);
}
// static float WinUtils::SystemDPI() { // The result of GetDeviceCaps won't change dynamically, as it predates // per-monitor DPI and support for on-the-fly resolution changes. // Therefore, we only need to look it up once. staticfloat dpi = 0; if (dpi <= 0) {
HDC screenDC = GetDC(nullptr);
dpi = GetDeviceCaps(screenDC, LOGPIXELSY);
ReleaseDC(nullptr, screenDC);
}
// Bug 1012487 - dpi can be 0 when the Screen DC is used off the // main thread on windows. For now just assume a 100% DPI for this // drawing call. // XXX - fixme! return dpi > 0 ? dpi : 96;
}
/* static */ double WinUtils::LogToPhysFactor(HWND aWnd) { // if there's an ancestor window, we want to share its DPI setting
HWND ancestor = ::GetAncestor(aWnd, GA_ROOTOWNER);
// The GetDpiForWindow api is not available everywhere where we run as // per-monitor, but if it is available rely on it to tell us the scale // factor of the window. See bug 1722085. if (sGetDpiForWindow) {
UINT dpi = sGetDpiForWindow(ancestor ? ancestor : aWnd); if (dpi > 0) { returnstatic_cast<double>(dpi) / 96.0;
}
} return LogToPhysFactor(::MonitorFromWindow(ancestor ? ancestor : aWnd,
MONITOR_DEFAULTTOPRIMARY));
}
int pixelsPerInchY = ::GetDeviceCaps(aHdc, LOGPIXELSY); int marginTop = ::GetDeviceCaps(aHdc, PHYSICALOFFSETY); int printableAreaHeight = ::GetDeviceCaps(aHdc, VERTRES); int physicalHeight = ::GetDeviceCaps(aHdc, PHYSICALHEIGHT);
int pixelsPerInchX = ::GetDeviceCaps(aHdc, LOGPIXELSX); int marginLeft = ::GetDeviceCaps(aHdc, PHYSICALOFFSETX); int printableAreaWidth = ::GetDeviceCaps(aHdc, HORZRES); int physicalWidth = ::GetDeviceCaps(aHdc, PHYSICALWIDTH);
const DWORD waitStart = ::GetTickCount();
DWORD elapsed = 0; while (true) { if (aTimeoutMs != INFINITE) {
elapsed = ::GetTickCount() - waitStart;
} if (elapsed >= aTimeoutMs) { break;
}
DWORD result;
{
AUTO_PROFILER_THREAD_SLEEP;
result = ::MsgWaitForMultipleObjectsEx(0, NULL, aTimeoutMs - elapsed,
MOZ_QS_ALLEVENT, waitFlags);
}
NS_WARNING_ASSERTION(result != WAIT_FAILED, "Wait failed"); if (result == WAIT_TIMEOUT) { break;
} #ifdefined(ACCESSIBILITY) if (result == WAIT_IO_COMPLETION) { if (NS_IsMainThread()) { // We executed an APC that would have woken up the hang monitor. Since // there are no more APCs pending and we are now going to sleep again, // we should notify the hang monitor.
mozilla::BackgroundHangMonitor().NotifyWait();
} continue;
} #endif// defined(ACCESSIBILITY)
// Sent messages (via SendMessage and friends) are processed differently // than queued messages (via PostMessage); the destination window procedure // of the sent message is called during (Get|Peek)Message. Since PeekMessage // does not tell us whether it processed any sent messages, we need to query // this ahead of time. bool haveSentMessagesPending =
(HIWORD(::GetQueueStatus(QS_SENDMESSAGE)) & QS_SENDMESSAGE) != 0;
MSG msg = {0}; if (haveSentMessagesPending ||
::PeekMessageW(&msg, nullptr, 0, 0, PM_NOREMOVE)) { break;
} // The message is intended for another thread that has been synchronized // with our input queue; yield to give other threads an opportunity to // process the message. This should prevent busy waiting if resumed due // to another thread's message.
::SwitchToThread();
}
}
if (aStopIfNotChild) {
DWORD_PTR style = ::GetWindowLongPtrW(curWnd, GWL_STYLE);
VERIFY_WINDOW_STYLE(style);
if (!(style & WS_CHILD)) // first top-level window break;
}
HWND upWnd = ::GetParent(curWnd); // Parent or owner (if has no parent)
// GetParent will only return the owner if the passed in window // has the WS_POPUP style. if (!upWnd && !aStopIfNotPopup) {
upWnd = ::GetWindow(curWnd, GW_OWNER);
}
curWnd = upWnd;
}
return topWnd;
}
// Map from native window handles to nsWindow structures. Does not AddRef. // Inherently unsafe to access outside the main thread.
MOZ_RUNINIT static nsTHashMap<HWND, nsWindow*> sExtantNSWindows;
struct FindOurWindowAtPointInfo {
POINT mInPointInScreen;
HWND mOutWnd;
};
staticBOOL CALLBACK FindOurWindowAtPointCallback(HWND aWnd, LPARAM aLPARAM) { if (!WinUtils::IsOurProcessWindow(aWnd)) { // This isn't one of our top-level windows; continue enumerating. returnTRUE;
}
// Get the top-most child window under the point. If there's no child // window, and the point is within the top-level window, then the top-level // window will be returned. (This is the usual case. A child window // would be returned for plugins.)
FindOurWindowAtPointInfo* info = reinterpret_cast<FindOurWindowAtPointInfo*>(aLPARAM);
HWND childWnd = FindTopmostWindowAtPoint(aWnd, info->mInPointInScreen); if (!childWnd) { // This window doesn't contain the point; continue enumerating. returnTRUE;
}
// Return the HWND and stop enumerating.
info->mOutWnd = childWnd; returnFALSE;
}
// This will enumerate all top-level windows in order from top to bottom.
EnumWindows(FindOurWindowAtPointCallback, reinterpret_cast<LPARAM>(&info)); return info.mOutWnd;
}
/* static */
UINT WinUtils::GetInternalMessage(UINT aNativeMessage) { switch (aNativeMessage) { case WM_MOUSEWHEEL: return MOZ_WM_MOUSEVWHEEL; case WM_MOUSEHWHEEL: return MOZ_WM_MOUSEHWHEEL; case WM_VSCROLL: return MOZ_WM_VSCROLL; case WM_HSCROLL: return MOZ_WM_HSCROLL; default: return aNativeMessage;
}
}
/* static */
UINT WinUtils::GetNativeMessage(UINT aInternalMessage) { switch (aInternalMessage) { case MOZ_WM_MOUSEVWHEEL: return WM_MOUSEWHEEL; case MOZ_WM_MOUSEHWHEEL: return WM_MOUSEHWHEEL; case MOZ_WM_VSCROLL: return WM_VSCROLL; case MOZ_WM_HSCROLL: return WM_HSCROLL; default: return aInternalMessage;
}
}
#ifdef MOZ_PLACES /************************************************************************ * Constructs as AsyncFaviconDataReady Object * @param aIOThread : the thread which performs the action * @param aURLShortcut : Differentiates between (false)Jumplistcache and * (true)Shortcutcache * @param aRunnable : Executed in the aIOThread when the favicon cache is * avaiable * @param [aPromiseHolder=null]: Optional PromiseHolder that will be forwarded * to AsyncEncodeAndWriteIcon if getting the * favicon from the favicon service succeeds. If * it doesn't succeed, the held MozPromise will * be rejected.
************************************************************************/
// Decode the image from the format it was returned to us in (probably PNG)
nsCOMPtr<imgIContainer> container;
nsCOMPtr<imgITools> imgtool = do_CreateInstance("@mozilla.org/image/tools;1");
rv = imgtool->DecodeImageFromBuffer(reinterpret_cast<constchar*>(aData),
aDataLen, aMimeType,
getter_AddRefs(container));
NS_ENSURE_SUCCESS(rv, rv);
dataSurface->Unmap();
} else { // By using the input image surface's size, we may end up encoding // to a different size than a 16x16 (or bigger for higher DPI) ICO, but // Windows will resize appropriately for us. If we want to encode ourselves // one day because we like our resizing better, we'd have to manually // resize the image here and use GetSystemMetrics w/ SM_CXSMICON and // SM_CYSMICON. We don't support resizing images asynchronously at the // moment anyway so getting the DPI aware icon size won't help.
size.width = surface->GetSize().width;
size.height = surface->GetSize().height;
dataSurface = surface->GetDataSurface();
NS_ENSURE_TRUE(dataSurface, NS_ERROR_FAILURE);
}
// Allocate a new buffer that we own and can use out of line in // another thread.
UniquePtr<uint8_t[]> data = SurfaceToPackedBGRA(dataSurface); if (!data) { return NS_ERROR_OUT_OF_MEMORY;
}
int32_t stride = 4 * size.width;
// AsyncEncodeAndWriteIcon takes ownership of the heap allocated buffer
nsCOMPtr<nsIRunnable> event = new AsyncEncodeAndWriteIcon(
path, std::move(data), stride, size.width, size.height,
mRunnable.forget(), std::move(mPromiseHolder));
mIOThread->Dispatch(event, NS_DISPATCH_NORMAL);
NS_IMETHODIMP AsyncEncodeAndWriteIcon::Run() {
MOZ_ASSERT(!NS_IsMainThread(), "Should not be called on the main thread.");
// Note that since we're off the main thread we can't use // gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget()
RefPtr<DataSourceSurface> surface = Factory::CreateWrappingDataSourceSurface(
mBuffer.get(), mStride, IntSize(mWidth, mHeight),
SurfaceFormat::B8G8R8A8);
if (mRunnable) {
mRunnable->Run();
} if (mPromiseHolder) {
mPromiseHolder->ResolveIfExists(mIconPath, __func__);
} return rv;
}
AsyncEncodeAndWriteIcon::~AsyncEncodeAndWriteIcon() { if (mPromiseHolder) {
mPromiseHolder->RejectIfExists(NS_ERROR_FAILURE, __func__);
}
}
AsyncDeleteAllFaviconsFromDisk::AsyncDeleteAllFaviconsFromDisk( bool aIgnoreRecent)
: mIgnoreRecent(aIgnoreRecent) { // We can't call FaviconHelper::GetICOCacheSecondsTimeout() on non-main // threads, as it reads a pref, so cache its value here.
mIcoNoDeleteSeconds = FaviconHelper::GetICOCacheSecondsTimeout() + 600;
// Prepare the profile directory cache on the main thread, to ensure we wont // do this on non-main threads.
Unused << NS_GetSpecialDirectory("ProfLDS",
getter_AddRefs(mJumpListCacheDir));
}
NS_IMETHODIMP AsyncDeleteAllFaviconsFromDisk::Run() { if (!mJumpListCacheDir) { return NS_ERROR_FAILURE;
} // Construct the path of our jump list cache
nsresult rv = mJumpListCacheDir->AppendNative(
nsDependentCString(FaviconHelper::kJumpListCacheDir));
NS_ENSURE_SUCCESS(rv, rv);
// Loop through each directory entry and remove all ICO files found do {
nsCOMPtr<nsIFile> currFile; if (NS_FAILED(entries->GetNextFile(getter_AddRefs(currFile))) || !currFile) break;
nsAutoString path; if (NS_FAILED(currFile->GetPath(path))) continue;
if (StringTail(path, 4).LowerCaseEqualsASCII(".ico")) { // Check if the cached ICO file exists bool exists; if (NS_FAILED(currFile->Exists(&exists)) || !exists) continue;
if (mIgnoreRecent) { // Check to make sure the icon wasn't just recently created. // If it was created recently, don't delete it yet.
int64_t fileModTime = 0;
rv = currFile->GetLastModifiedTime(&fileModTime);
fileModTime /= PR_MSEC_PER_SEC; // If the icon is older than the regeneration time (+ 10 min to be // safe), then it's old and we can get rid of it. // This code is only hit directly after a regeneration.
int64_t nowTime = PR_Now() / int64_t(PR_USEC_PER_SEC); if (NS_FAILED(rv) || (nowTime - fileModTime) < mIcoNoDeleteSeconds) { continue;
}
}
// We found an ICO file that exists, so we should remove it
currFile->Remove(false);
}
} while (true);
/* * (static) If the data is available, will return the path on disk where * the favicon for page aFaviconPageURI is stored. If the favicon does not * exist, or its cache is expired, this method will kick off an async request * for the icon so that next time the method is called it will be available. * @param aFaviconPageURI The URI of the page to obtain * @param aICOFilePath The path of the icon file * @param aIOThread The thread to perform the Fetch on * @param aURLShortcut to distinguish between jumplistcache(false) and * shortcutcache(true) * @param aRunnable Executed in the aIOThread when the favicon cache is * avaiable
*/
nsresult FaviconHelper::ObtainCachedIconFile(
nsCOMPtr<nsIURI> aFaviconPageURI, nsString& aICOFilePath,
RefPtr<LazyIdleThread>& aIOThread, bool aURLShortcut,
already_AddRefed<nsIRunnable> aRunnable) {
nsCOMPtr<nsIRunnable> runnable = aRunnable; // Obtain the ICO file path
nsCOMPtr<nsIFile> icoFile;
nsresult rv = GetOutputIconPath(aFaviconPageURI, icoFile, aURLShortcut);
NS_ENSURE_SUCCESS(rv, rv);
// Check if the cached ICO file already exists bool exists;
rv = icoFile->Exists(&exists);
NS_ENSURE_SUCCESS(rv, rv);
if (exists) { // Obtain the file's last modification date in seconds
int64_t fileModTime = 0;
rv = icoFile->GetLastModifiedTime(&fileModTime);
fileModTime /= PR_MSEC_PER_SEC;
int32_t icoReCacheSecondsTimeout = GetICOCacheSecondsTimeout();
int64_t nowTime = PR_Now() / int64_t(PR_USEC_PER_SEC);
// If the last mod call failed or the icon is old then re-cache it // This check is in case the favicon of a page changes // the next time we try to build the jump list, the data will be available. if (NS_FAILED(rv) || (nowTime - fileModTime) > icoReCacheSecondsTimeout) {
CacheIconFileFromFaviconURIAsync(aFaviconPageURI, icoFile, aIOThread,
aURLShortcut, runnable.forget(),
nullptr); return NS_ERROR_NOT_AVAILABLE;
}
} else { // The file does not exist yet, obtain it async from the favicon service so // that the next time we try to build the jump list it'll be available.
CacheIconFileFromFaviconURIAsync(aFaviconPageURI, icoFile, aIOThread,
aURLShortcut, runnable.forget(), nullptr); return NS_ERROR_NOT_AVAILABLE;
}
// The icoFile is filled with a path that exists, get its path
rv = icoFile->GetPath(aICOFilePath); return rv;
}
/** * (static) * Attempts to obtain a favicon from the nsIFaviconService and cache it on * disk in a place where Win32 utilities (like the jump list) can access them. * * In the event that the favicon was cached recently, the returned MozPromise * will resolve with the cache path. If the cache is expired, it will be * refreshed before returning the path. * * In the event that the favicon cannot be retrieved from the nsIFaviconService, * or something goes wrong writing the cache to disk, the returned MozPromise * will reject with an nsresult code. * * This is similar to the ObtainCachedIconFile method, except that all IO * happens on the aIOThread rather than only some of the IO. * * @param aFaviconPageURI * The URI of the page to obtain the favicon for. * @param aIOThread * The thread to perform the cache check and fetch/write on. * @param aCacheDir * Which cache directory to use for the returned favicon (see * FaviconHelper::IconCacheDir). * @returns {RefPtr<ObtainCachedIconFileAsyncPromise>} * Resolves with the path of the cached favicon, or rejects with an nsresult * in the event that the favicon cannot be retrieved and/or cached.
*/ auto FaviconHelper::ObtainCachedIconFileAsync(
nsCOMPtr<nsIURI> aFaviconPageURI, RefPtr<LazyIdleThread>& aIOThread,
FaviconHelper::IconCacheDir aCacheDir)
-> RefPtr<ObtainCachedIconFileAsyncPromise> { bool useShortcutCacheDir =
aCacheDir == FaviconHelper::IconCacheDir::ShortcutCacheDir;
// Obtain the file path that the ICO, if it exists, is expected to be // at for aFaviconPageURI
nsCOMPtr<nsIFile> icoFile;
nsresult rv =
GetOutputIconPath(aFaviconPageURI, icoFile, useShortcutCacheDir); if (NS_FAILED(rv)) { return ObtainCachedIconFileAsyncPromise::CreateAndReject(rv, __func__);
}
if (NS_FAILED(rv)) { return ObtainCachedIconFileAsyncPromise::CreateAndReject(
rv, "ObtainCachedIconFileAsync disk cache check: exists failed");
}
if (exists) { // Obtain the file's last modification date in seconds
int64_t fileModTime = 0;
rv = icoFile->GetLastModifiedTime(&fileModTime);
fileModTime /= PR_MSEC_PER_SEC;
int64_t nowTime = PR_Now() / int64_t(PR_USEC_PER_SEC);
// If the file seems to be less than icoReCacheSecondsTimeout old, // then we can go ahead and return its path on the filesystem. if (NS_SUCCEEDED(rv) &&
(nowTime - fileModTime) < icoReCacheSecondsTimeout) {
nsAutoString icoFilePath;
rv = icoFile->GetPath(icoFilePath); if (NS_SUCCEEDED(rv)) { return ObtainCachedIconFileAsyncPromise::CreateAndResolve(
icoFilePath, "ObtainCachedIconFileAsync disk cache check: found");
}
}
}
// Now dispatch a runnable to the main thread that will call // CacheIconFileFromFaviconURIAsync to request the favicon.
RefPtr<nsISerialEventTarget> currentThread =
GetCurrentSerialEventTarget();
// Hash a URI using a cryptographic hash function (currently SHA-256) // Output will be a base64-encoded string of the hash. static nsresult HashURI(nsIURI* aUri, nsACString& aUriHash) {
nsAutoCString spec;
nsresult rv = aUri->GetSpec(spec);
NS_ENSURE_SUCCESS(rv, rv);
// Add some context to the hash to even further reduce the chances of // collision. Note that we are hashing this string with its null-terminator. constchar kHashUriContext[] = "firefox-uri";
rv = cryptoHash->Update(reinterpret_cast<const uint8_t*>(kHashUriContext), sizeof(kHashUriContext));
NS_ENSURE_SUCCESS(rv, rv);
// (static) Obtains the ICO file for the favicon at page aFaviconPageURI // If successful, the file path on disk is in the format: // <ProfLDS>\jumpListCache\<hash(aFaviconPageURI)>.ico // // We generate the name with a cryptographically secure hash function in order // to ensure that malicious websites can't intentionally craft URLs to collide // with legitimate websites.
nsresult FaviconHelper::GetOutputIconPath(nsCOMPtr<nsIURI> aFaviconPageURI,
nsCOMPtr<nsIFile>& aICOFile, bool aURLShortcut) {
nsAutoCString inputURIHash;
nsresult rv = HashURI(aFaviconPageURI, inputURIHash);
NS_ENSURE_SUCCESS(rv, rv); char* cur = inputURIHash.BeginWriting(); char* end = inputURIHash.EndWriting(); for (; cur < end; ++cur) { if ('/' == *cur) {
*cur = '_';
}
}
// Obtain the local profile directory and construct the output icon file path
rv = NS_GetSpecialDirectory("ProfLDS", getter_AddRefs(aICOFile));
NS_ENSURE_SUCCESS(rv, rv); if (!aURLShortcut)
rv = aICOFile->AppendNative(nsDependentCString(kJumpListCacheDir)); else
rv = aICOFile->AppendNative(nsDependentCString(kShortcutCacheDir));
NS_ENSURE_SUCCESS(rv, rv);
// Append the icon extension
inputURIHash.AppendLiteral(".ico");
rv = aICOFile->AppendNative(inputURIHash);
return rv;
}
// (static) Asynchronously creates a cached ICO file on disk for the favicon of // page aFaviconPageURI and stores it to disk at the path of aICOFile.
nsresult FaviconHelper::CacheIconFileFromFaviconURIAsync(
nsCOMPtr<nsIURI> aFaviconPageURI, nsCOMPtr<nsIFile> aICOFile,
RefPtr<nsISerialEventTarget> aIOThread, bool aURLShortcut,
already_AddRefed<nsIRunnable> aRunnable,
UniquePtr<MozPromiseHolder<ObtainCachedIconFileAsyncPromise>>
aPromiseHolder) {
MOZ_ASSERT(NS_IsMainThread());
nsCOMPtr<nsIRunnable> runnable = aRunnable; #ifdef MOZ_PLACES // Obtain the favicon service and get the favicon for the specified page
nsCOMPtr<nsIFaviconService> favIconSvc(
do_GetService("@mozilla.org/browser/favicon-service;1"));
NS_ENSURE_TRUE(favIconSvc, NS_ERROR_FAILURE);
nsCOMPtr<nsIFaviconDataCallback> callback = new mozilla::widget::AsyncFaviconDataReady(
aFaviconPageURI, aIOThread, aURLShortcut, runnable.forget(),
std::move(aPromiseHolder));
// Obtains the jump list 'ICO cache timeout in seconds' pref
int32_t FaviconHelper::GetICOCacheSecondsTimeout() { // Only obtain the setting at most once from the pref service. // In the rare case that 2 threads call this at the same // time it is no harm and we will simply obtain the pref twice. // None of the taskbar list prefs are currently updated via a // pref observer so I think this should suffice. const int32_t kSecondsPerDay = 86400; staticbool alreadyObtained = false; static int32_t icoReCacheSecondsTimeout = kSecondsPerDay; if (alreadyObtained) { return icoReCacheSecondsTimeout;
}
// For either of the following formats we want to set the biBitCount member // of the BITMAPINFOHEADER struct to 32, below. For that value the bitmap // format defines that the A8/X8 WORDs in the bitmap byte stream be ignored // for the BI_RGB value we use for the biCompression member.
MOZ_ASSERT(surface->GetFormat() == SurfaceFormat::B8G8R8A8 ||
surface->GetFormat() == SurfaceFormat::B8G8R8X8);
// get a file output stream
nsCOMPtr<nsIOutputStream> stream;
rv = NS_NewLocalFileOutputStream(getter_AddRefs(stream), aFile);
NS_ENSURE_SUCCESS(rv, rv);
DataSourceSurface::MappedSurface map; if (!dataSurface->Map(DataSourceSurface::MapType::READ, &map)) { return NS_ERROR_FAILURE;
}
// write the bitmap headers and rgb pixel data to the file
rv = NS_ERROR_FAILURE; if (stream) {
uint32_t written;
stream->Write((constchar*)&bf, sizeof(BITMAPFILEHEADER), &written); if (written == sizeof(BITMAPFILEHEADER)) {
stream->Write((constchar*)&bmi, sizeof(BITMAPV4HEADER), &written); if (written == sizeof(BITMAPV4HEADER)) { if (hasAlpha) { // color mask
colormask[0] = 0x00FF0000;
colormask[1] = 0x0000FF00;
colormask[2] = 0x000000FF;
stream->Write((constchar*)colormask, sizeof(colormask), &written);
} if (!hasAlpha || written == sizeof(colormask)) { // write out the image data backwards because the desktop won't // show bitmaps with negative heights for top-to-bottom
uint32_t i = map.mStride * height; do {
i -= map.mStride;
stream->Write(((constchar*)map.mData) + i, bytesPerRow, &written); if (written == bytesPerRow) {
rv = NS_OK;
} else {
rv = NS_ERROR_FAILURE; break;
}
} while (i != 0);
}
}
}
stream->Close();
}
dataSurface->Unmap();
return rv;
}
// This is in use here and in dom/events/TouchEvent.cpp /* static */
uint32_t WinUtils::IsTouchDeviceSupportPresent() {
int32_t touchCapabilities = ::GetSystemMetrics(SM_DIGITIZER);
int32_t touchFlags = NID_EXTERNAL_TOUCH | NID_INTEGRATED_TOUCH; if (StaticPrefs::dom_w3c_pointer_events_scroll_by_pen_enabled()) {
touchFlags |= NID_EXTERNAL_PEN | NID_INTEGRATED_PEN;
} return (touchCapabilities & NID_READY) && (touchCapabilities & touchFlags);
}
// static void WinUtils::GetClipboardFormatAsString(UINT aFormat, nsAString& aOutput) { wchar_t buf[256] = {}; // Get registered format name and ensure the existence of a terminating '\0' // if the registered name is more than 256 characters. if (::GetClipboardFormatNameW(aFormat, buf, ARRAYSIZE(buf) - 1)) {
aOutput.Append(buf); return;
} // Standard clipboard formats // https://learn.microsoft.com/en-us/windows/win32/dataxchg/standard-clipboard-formats switch (aFormat) { case CF_TEXT: // 1
aOutput.Append(u"CF_TEXT"_ns); break; case CF_BITMAP: // 2
aOutput.Append(u"CF_BITMAP"_ns); break; case CF_DIB: // 8
aOutput.Append(u"CF_DIB"_ns); break; case CF_UNICODETEXT: // 13
aOutput.Append(u"CF_UNICODETEXT"_ns); break; case CF_HDROP: // 15
aOutput.Append(u"CF_HDROP"_ns); break; case CF_DIBV5: // 17
aOutput.Append(u"CF_DIBV5"_ns); break; default:
aOutput.AppendPrintf("%u", aFormat); break;
}
}
staticbool IsTabletDevice() { // Guarantees that: // - The device has a touch screen. // - It is used as a tablet which means that it has no keyboard connected.
if (WindowsUIUtils::GetInWin10TabletMode()) { returntrue;
}
if (!GetSystemMetrics(SM_MAXIMUMTOUCHES)) { returnfalse;
}
// If the device is docked, the user is treating the device as a PC. if (GetSystemMetrics(SM_SYSTEMDOCKED)) { returnfalse;
}
// If the device is not supporting rotation, it's unlikely to be a tablet, // a convertible or a detachable. See: // https://msdn.microsoft.com/en-us/library/windows/desktop/dn629263(v=vs.85).aspx
AR_STATE rotation_state; if (WinUtils::GetAutoRotationState(&rotation_state) &&
(rotation_state & (AR_NOT_SUPPORTED | AR_LAPTOP | AR_NOSENSOR))) { returnfalse;
}
// PlatformRoleSlate was added in Windows 8+.
POWER_PLATFORM_ROLE role = WinUtils::GetPowerPlatformRole(); if (role == PlatformRoleMobile || role == PlatformRoleSlate) { return !GetSystemMetrics(SM_CONVERTIBLESLATEMODE);
} returnfalse;
}
bool WinUtils::SystemHasMouse() { // As per MSDN, this value is rarely false because of virtual mice, and // some machines report the existance of a mouse port as a mouse. // // We probably could try to distinguish if we wanted, but a virtual mouse // might be there for a reason, and maybe we shouldn't assume we know // better. return !!::GetSystemMetrics(SM_MOUSEPRESENT);
}
if (handle == INVALID_HANDLE_VALUE) {
MOZ_LOG(sNTFSLog, LogLevel::Error,
("Failed to open file handle to resolve path. GetLastError=%lu",
GetLastError())); returnfalse;
}
// GetFinalPathNameByHandle sticks a '\\?\' in front of the path, // but that confuses some APIs so strip it off. It will also put // '\\?\UNC\' in front of network paths, we convert that to '\\'. if (aPath.compare(0, 7, L"\\\\?\\UNC") == 0) {
aPath.erase(2, 6);
} elseif (aPath.compare(0, 4, L"\\\\?\\") == 0) {
aPath.erase(0, 4);
}
MOZ_LOG(sNTFSLog, LogLevel::Debug,
("ResolveJunctionPointsAndSymLinks: Resolved path to: %S",
aPath.c_str())); returntrue;
}
/* static */ bool WinUtils::MakeLongPath(nsAString& aPath) { wchar_t tempPath[MAX_PATH + 1];
DWORD longResult =
GetLongPathNameW((char16ptr_t)PromiseFlatString(aPath).get(), tempPath,
std::size(tempPath)); if (longResult > std::size(tempPath)) { // Our buffer is too short, and we're guaranteeing <= MAX_PATH results. returnfalse;
} elseif (longResult) { // Success.
aPath = tempPath;
MOZ_ASSERT(aPath.Length() <= MAX_PATH);
} // GetLongPathNameW returns 0 if the path is not found or is not rooted, // but we shouldn't consider that a failure condition. returntrue;
}
/* static */ bool WinUtils::UnexpandEnvVars(nsAString& aPath) { wchar_t tempPath[MAX_PATH + 1]; // PathUnExpandEnvStringsW returns false if it doesn't make any // substitutions. Silently continue using the unaltered path. if (PathUnExpandEnvStringsW((char16ptr_t)PromiseFlatString(aPath).get(),
tempPath, std::size(tempPath))) {
aPath = tempPath;
MOZ_ASSERT(aPath.Length() <= MAX_PATH);
} returntrue;
}
wchar_t tmpPath[MAX_PATH + 1] = {}; if (GetTempPath(MAX_PATH, tmpPath)) { // GetTempPath's result always ends with a backslash, which we don't want
uint32_t tmpPathLen = wcslen(tmpPath); if (tmpPathLen) {
tmpPath[tmpPathLen - 1] = 0;
}
nsAutoString cleanTmpPath(tmpPath); if (UnexpandEnvVars(cleanTmpPath)) {
constexpr auto tempVar = u"%TEMP%"_ns;
Unused << result.emplaceBack(std::make_pair(
nsString(cleanTmpPath), nsDependentString(tempVar, 0)));
}
}
// If we add more items to the whitelist, ensure we still don't invoke an // unnecessary heap allocation.
MOZ_ASSERT(result.length() <= kMaxWhitelistedItems);
return result;
}
/** * This function provides an array of (system path, substitution) pairs that are * considered to be acceptable with respect to privacy, for the purposes of * submitting within telemetry or crash reports. * * The substitution string's void flag may be set. If it is, no subsitution is * necessary. Otherwise, the consumer should replace the system path with the * substitution. * * @see PreparePathForTelemetry for an example of its usage.
*/ /* static */ const WinUtils::WhitelistVec& WinUtils::GetWhitelistedPaths() { static WhitelistVec sWhitelist([]() -> WhitelistVec { auto setClearFn = [ptr = &sWhitelist]() -> void {
RunOnShutdown([ptr]() -> void { ptr->clear(); },
ShutdownPhase::XPCOMShutdownFinal);
};
/** * This function is located here (as opposed to nsSystemInfo or elsewhere) * because we need to gather this information as early as possible during * startup.
*/ /* static */ bool WinUtils::GetAppInitDLLs(nsAString& aOutput) {
aOutput.Truncate();
HKEY hkey = NULL; if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Windows",
0, KEY_QUERY_VALUE, &hkey)) { returnfalse;
}
nsAutoRegKey key(hkey); LONG status; constwchar_t kLoadAppInitDLLs[] = L"LoadAppInit_DLLs";
DWORD loadAppInitDLLs = 0;
DWORD loadAppInitDLLsLen = sizeof(loadAppInitDLLs);
status = RegQueryValueExW(hkey, kLoadAppInitDLLs, nullptr, nullptr,
(LPBYTE)&loadAppInitDLLs, &loadAppInitDLLsLen); if (status != ERROR_SUCCESS) { returnfalse;
} if (!loadAppInitDLLs) { // If loadAppInitDLLs is zero then AppInit_DLLs is disabled. // In this case we'll return true along with an empty output string. returntrue;
}
DWORD numBytes = 0; constwchar_t kAppInitDLLs[] = L"AppInit_DLLs"; // Query for required buffer size
status = RegQueryValueExW(hkey, kAppInitDLLs, nullptr, nullptr, nullptr,
&numBytes); if (status != ERROR_SUCCESS) { returnfalse;
} // Allocate the buffer and query for the actual data
mozilla::UniquePtr<wchar_t[]> data =
mozilla::MakeUnique<wchar_t[]>(numBytes / sizeof(wchar_t));
status = RegQueryValueExW(hkey, kAppInitDLLs, nullptr, nullptr,
(LPBYTE)data.get(), &numBytes); if (status != ERROR_SUCCESS) { returnfalse;
} // For each token, split up the filename components and then check the // name of the file. constwchar_t kDelimiters[] = L", "; wchar_t* tokenContext = nullptr; wchar_t* token = wcstok_s(data.get(), kDelimiters, &tokenContext); while (token) {
nsAutoString cleanPath(token); // Since these paths are short paths originating from the registry, we need // to canonicalize them, lengthen them, and sanitize them before we can // check them against the whitelist if (PreparePathForTelemetry(cleanPath)) {
--> --------------------
--> maximum size reached
--> --------------------
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.78Bemerkung:
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.