From 0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 03:47:29 +0200 Subject: Adding upstream version 115.8.0esr. Signed-off-by: Daniel Baumann --- widget/windows/nsWindowLoggedMessages.cpp | 307 ++++++++++++++++++++++++++++++ 1 file changed, 307 insertions(+) create mode 100644 widget/windows/nsWindowLoggedMessages.cpp (limited to 'widget/windows/nsWindowLoggedMessages.cpp') diff --git a/widget/windows/nsWindowLoggedMessages.cpp b/widget/windows/nsWindowLoggedMessages.cpp new file mode 100644 index 0000000000..ac0f05a875 --- /dev/null +++ b/widget/windows/nsWindowLoggedMessages.cpp @@ -0,0 +1,307 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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/. */ + +#include +#include +#include "mozilla/StaticPrefs_storage.h" +#include "mozilla/StaticPrefs_widget.h" +#include "nsWindowLoggedMessages.h" +#include "nsWindow.h" +#include "WinUtils.h" +#include +#include + +namespace mozilla::widget { + +// NCCALCSIZE_PARAMS and WINDOWPOS are relatively large structures, so store +// them as a pointer to save memory +using NcCalcSizeVariantData = + Variant>, RECT>; +// to save memory, hold the raw data and only convert to string +// when requested +using MessageSpecificData = + Variant, // WM_SIZE, WM_MOVE + WINDOWPOS, // WM_WINDOWPOSCHANGING, WM_WINDOWPOSCHANGED + std::pair, // WM_SIZING, WM_DPICHANGED, WM_MOVING + std::pair, // WM_SETTINGCHANGE + std::pair, // WM_NCCALCSIZE + MINMAXINFO // WM_GETMINMAXINFO + >; + +struct WindowMessageData { + long mEventCounter; + bool mIsPreEvent; + MessageSpecificData mSpecificData; + mozilla::Maybe mResult; + LRESULT mRetValue; + WindowMessageData(long eventCounter, bool isPreEvent, + MessageSpecificData&& specificData, + mozilla::Maybe result, LRESULT retValue) + : mEventCounter(eventCounter), + mIsPreEvent(isPreEvent), + mSpecificData(std::move(specificData)), + mResult(result), + mRetValue(retValue) {} + // Disallow copy constructor/operator since MessageSpecificData has a + // UniquePtr + WindowMessageData(const WindowMessageData&) = delete; + WindowMessageData& operator=(const WindowMessageData&) = delete; + WindowMessageData(WindowMessageData&&) = default; + WindowMessageData& operator=(WindowMessageData&&) = default; +}; + +struct WindowMessageDataSortKey { + long mEventCounter; + bool mIsPreEvent; + explicit WindowMessageDataSortKey(const WindowMessageData& data) + : mEventCounter(data.mEventCounter), mIsPreEvent(data.mIsPreEvent) {} + bool operator<(const WindowMessageDataSortKey& other) const { + if (mEventCounter < other.mEventCounter) { + return true; + } + if (other.mEventCounter < mEventCounter) { + return false; + } + if (mIsPreEvent && !other.mIsPreEvent) { + return true; + } + if (other.mIsPreEvent && !mIsPreEvent) { + return false; + } + // they're equal + return false; + } +}; + +struct CircularMessageBuffer { + // Only used when the vector is at its maximum size + size_t mNextFreeIndex = 0; + std::vector mMessages; +}; +static std::map> gWindowMessages; + +static HWND GetHwndFromWidget(nsIWidget* windowWidget) { + nsWindow* window = static_cast(windowWidget); + return window->GetWindowHandle(); +} + +MessageSpecificData MakeMessageSpecificData(UINT event, WPARAM wParam, + LPARAM lParam) { + // Since we store this data for every message we log, make sure it's of a + // reasonable size. Keep in mind we're storing up to 10 (number of message + // types) + // * 6 (default number of messages per type to keep) of these messages per + // window. + static_assert(sizeof(MessageSpecificData) <= 48); + switch (event) { + case WM_SIZE: + case WM_MOVE: + return MessageSpecificData(std::make_pair(wParam, lParam)); + case WM_WINDOWPOSCHANGING: + case WM_WINDOWPOSCHANGED: { + LPWINDOWPOS windowPosPtr = reinterpret_cast(lParam); + WINDOWPOS windowPos = *windowPosPtr; + return MessageSpecificData(std::move(windowPos)); + } + case WM_SIZING: + case WM_DPICHANGED: + case WM_MOVING: { + LPRECT rectPtr = reinterpret_cast(lParam); + RECT rect = *rectPtr; + return MessageSpecificData(std::make_pair(wParam, std::move(rect))); + } + case WM_SETTINGCHANGE: { + LPCWSTR wideStrPtr = reinterpret_cast(lParam); + nsString str(wideStrPtr); + return MessageSpecificData(std::make_pair(wParam, std::move(str))); + } + case WM_NCCALCSIZE: { + bool shouldIndicateValidArea = wParam == TRUE; + if (shouldIndicateValidArea) { + LPNCCALCSIZE_PARAMS ncCalcSizeParamsPtr = + reinterpret_cast(lParam); + NCCALCSIZE_PARAMS ncCalcSizeParams = *ncCalcSizeParamsPtr; + WINDOWPOS windowPos = *ncCalcSizeParams.lppos; + UniquePtr> ncCalcSizeData = + MakeUnique>( + std::pair(std::move(ncCalcSizeParams), std::move(windowPos))); + return MessageSpecificData( + std::make_pair(shouldIndicateValidArea, + NcCalcSizeVariantData(std::move(ncCalcSizeData)))); + } else { + LPRECT rectPtr = reinterpret_cast(lParam); + RECT rect = *rectPtr; + return MessageSpecificData(std::make_pair( + shouldIndicateValidArea, NcCalcSizeVariantData(std::move(rect)))); + } + } + case WM_GETMINMAXINFO: { + PMINMAXINFO minMaxInfoPtr = reinterpret_cast(lParam); + MINMAXINFO minMaxInfo = *minMaxInfoPtr; + return MessageSpecificData(std::move(minMaxInfo)); + } + default: + MOZ_ASSERT_UNREACHABLE( + "Unhandled message type in MakeMessageSpecificData"); + return MessageSpecificData(std::make_pair(wParam, lParam)); + } +} + +void AppendFriendlyMessageSpecificData(nsCString& str, UINT event, + bool isPreEvent, + const MessageSpecificData& data) { + switch (event) { + case WM_SIZE: { + const auto& params = data.as>(); + nsAutoCString tempStr = + WmSizeParamInfo(params.first, params.second, isPreEvent); + str.AppendASCII(tempStr); + break; + } + case WM_MOVE: { + const auto& params = data.as>(); + XLowWordYHighWordParamInfo(str, params.second, "upperLeft", isPreEvent); + break; + } + case WM_WINDOWPOSCHANGING: + case WM_WINDOWPOSCHANGED: { + const auto& params = data.as(); + WindowPosParamInfo(str, reinterpret_cast(¶ms), + "newSizeAndPos", isPreEvent); + break; + } + case WM_SIZING: { + const auto& params = data.as>(); + WindowEdgeParamInfo(str, params.first, "edge", isPreEvent); + str.AppendASCII(" "); + RectParamInfo(str, reinterpret_cast(¶ms.second), "rect", + isPreEvent); + break; + } + case WM_DPICHANGED: { + const auto& params = data.as>(); + XLowWordYHighWordParamInfo(str, params.first, "newDPI", isPreEvent); + str.AppendASCII(" "); + RectParamInfo(str, reinterpret_cast(¶ms.second), + "suggestedSizeAndPos", isPreEvent); + break; + } + case WM_MOVING: { + const auto& params = data.as>(); + RectParamInfo(str, reinterpret_cast(¶ms.second), "rect", + isPreEvent); + break; + } + case WM_SETTINGCHANGE: { + const auto& params = data.as>(); + UiActionParamInfo(str, params.first, "uiAction", isPreEvent); + str.AppendASCII(" "); + WideStringParamInfo( + str, + reinterpret_cast((const wchar_t*)(params.second.Data())), + "paramChanged", isPreEvent); + break; + } + case WM_NCCALCSIZE: { + const auto& params = data.as>(); + bool shouldIndicateValidArea = params.first; + if (shouldIndicateValidArea) { + const auto& validAreaParams = + params.second + .as>>(); + // Make pointer point to the cached data + validAreaParams->first.lppos = &validAreaParams->second; + nsAutoCString tempStr = WmNcCalcSizeParamInfo( + TRUE, reinterpret_cast(&validAreaParams->first), + isPreEvent); + str.AppendASCII(tempStr); + } else { + RECT rect = params.second.as(); + nsAutoCString tempStr = WmNcCalcSizeParamInfo( + FALSE, reinterpret_cast(&rect), isPreEvent); + str.AppendASCII(tempStr); + } + break; + } + case WM_GETMINMAXINFO: { + const auto& params = data.as(); + MinMaxInfoParamInfo(str, reinterpret_cast(¶ms), "", + isPreEvent); + break; + } + default: + MOZ_ASSERT(false, + "Unhandled message type in AppendFriendlyMessageSpecificData"); + str.AppendASCII("???"); + } +} + +nsCString MakeFriendlyMessage(UINT event, bool isPreEvent, long eventCounter, + const MessageSpecificData& data, + mozilla::Maybe result, LRESULT retValue) { + nsCString str; + const char* eventName = mozilla::widget::WinUtils::WinEventToEventName(event); + MOZ_ASSERT(eventName, "Unknown event name in MakeFriendlyMessage"); + eventName = eventName ? eventName : "(unknown)"; + str.AppendPrintf("%6ld %04x (%s) - ", eventCounter, event, eventName); + AppendFriendlyMessageSpecificData(str, event, isPreEvent, data); + const char* resultMsg = + result.isSome() ? (result.value() ? "true" : "false") : "initial call"; + str.AppendPrintf(" 0x%08llX (%s)", + result.isSome() ? static_cast(retValue) : 0, + resultMsg); + return str; +} + +void WindowClosed(HWND hwnd) { gWindowMessages.erase(hwnd); } + +void LogWindowMessage(HWND hwnd, UINT event, bool isPreEvent, long eventCounter, + WPARAM wParam, LPARAM lParam, mozilla::Maybe result, + LRESULT retValue) { + auto& hwndMessages = gWindowMessages[hwnd]; + auto& hwndWindowMessages = hwndMessages[event]; + WindowMessageData messageData = { + eventCounter, isPreEvent, MakeMessageSpecificData(event, wParam, lParam), + result, retValue}; + uint32_t numberOfMessagesToKeep = + StaticPrefs::widget_windows_messages_to_log(); + if (hwndWindowMessages.mMessages.size() < numberOfMessagesToKeep) { + // haven't reached limit yet + hwndWindowMessages.mMessages.push_back(std::move(messageData)); + } else { + hwndWindowMessages.mMessages[hwndWindowMessages.mNextFreeIndex] = + std::move(messageData); + } + hwndWindowMessages.mNextFreeIndex = + (hwndWindowMessages.mNextFreeIndex + 1) % numberOfMessagesToKeep; +} + +void GetLatestWindowMessages(RefPtr windowWidget, + nsTArray& messages) { + HWND hwnd = GetHwndFromWidget(windowWidget); + const auto& rawMessages = gWindowMessages[hwnd]; + nsTArray> + sortKeyAndMessageArray; + sortKeyAndMessageArray.SetCapacity( + rawMessages.size() * StaticPrefs::widget_windows_messages_to_log()); + for (const auto& eventAndMessage : rawMessages) { + for (const auto& messageData : eventAndMessage.second.mMessages) { + nsCString message = MakeFriendlyMessage( + eventAndMessage.first, messageData.mIsPreEvent, + messageData.mEventCounter, messageData.mSpecificData, + messageData.mResult, messageData.mRetValue); + WindowMessageDataSortKey sortKey(messageData); + sortKeyAndMessageArray.AppendElement( + std::make_pair(sortKey, std::move(message))); + } + } + std::sort(sortKeyAndMessageArray.begin(), sortKeyAndMessageArray.end()); + messages.SetCapacity(sortKeyAndMessageArray.Length()); + for (const std::pair& entry : + sortKeyAndMessageArray) { + messages.AppendElement(std::move(entry.second)); + } +} +} // namespace mozilla::widget -- cgit v1.2.3