Bug 1712669 - Make Windows tooltip margin depend on cursor size. r=yjuglaret,win-reviewers,desktop-theme-reviewers,dao

I think we should start off with this. Other platforms can implement
this too, but exposing this to content seems like quite the rabbit hole.

Differential Revision: https://phabricator.services.mozilla.com/D203405
This commit is contained in:
Emilio Cobos Álvarez 2024-03-19 14:17:58 +00:00
parent 50bd75fa63
commit ade0599fdf
8 changed files with 49 additions and 10 deletions

View file

@ -2186,6 +2186,12 @@ nsMargin nsMenuPopupFrame::GetMargin() const {
margin.left += auOffset.x;
margin.right += auOffset.x;
}
if (mPopupType == PopupType::Tooltip) {
const auto auOffset =
CSSPixel::ToAppUnits(LookAndFeel::TooltipOffsetVertical());
margin.top += auOffset;
margin.bottom += auOffset;
}
return margin;
}

View file

@ -30,6 +30,8 @@ var gOriginalWidth = -1;
var gOriginalHeight = -1;
var gButton = null;
const kTooltipOffsetVertical = 10;
function runTest()
{
startPopupTests(popupTests);
@ -112,7 +114,7 @@ var popupTests = [
Math.round(buttonrect.left + parseFloat(popupstyle.marginLeft) + 6),
testname + " left position of tooltip");
is(Math.round(rect.top),
Math.round(buttonrect.top + parseFloat(popupstyle.marginTop) + 6),
Math.round(buttonrect.top + parseFloat(popupstyle.marginTop) + 6 + kTooltipOffsetVertical),
testname + " top position of tooltip");
var labelrect = document.getElementById("label").getBoundingClientRect();
@ -159,7 +161,7 @@ var popupTests = [
Math.round(buttonrect.left + parseFloat(popupstyle.marginLeft) + 4),
testname + " left position of tooltip");
is(Math.round(rect.top),
Math.round(buttonrect.top + parseFloat(popupstyle.marginTop) + 4),
Math.round(buttonrect.top + parseFloat(popupstyle.marginTop) + 4 + kTooltipOffsetVertical),
testname + " top position of tooltip");
var labelrect = document.getElementById("label").getBoundingClientRect();
@ -204,7 +206,7 @@ var popupTests = [
Math.round(buttonrect.left + parseFloat(popupstyle.marginLeft) + 6),
testname + " left position of tooltip");
is(Math.round(rect.top),
Math.round(buttonrect.top + parseFloat(popupstyle.marginTop) + 6),
Math.round(buttonrect.top + parseFloat(popupstyle.marginTop) + 6 + kTooltipOffsetVertical),
testname + " top position of tooltip");
var labelrect = document.getElementById("label").getBoundingClientRect();
@ -359,7 +361,14 @@ function moveWindowTo(x, y, callback, arg)
}
}
window.arguments[0].SimpleTest.waitForFocus(runTest, window);
(async function() {
let parent = window.arguments[0];
await Promise.all([
parent.SimpleTest.promiseFocus(window),
parent.SpecialPowers.pushPrefEnv({set: [["ui.tooltipOffsetVertical", kTooltipOffsetVertical]]}),
]);
runTest();
})();
]]>
</script>

View file

@ -389,10 +389,6 @@ tooltip {
pointer-events: none;
}
tooltip:not([position]) {
margin-top: 21px;
}
/**
* It's important that these styles are in a UA sheet, because the default
* tooltip is native anonymous content

View file

@ -186,6 +186,7 @@ class LookAndFeel {
*/
ContextMenuOffsetVertical,
ContextMenuOffsetHorizontal,
TooltipOffsetVertical,
/*
* A boolean value indicating whether client-side decorations are
@ -321,6 +322,11 @@ class LookAndFeel {
return GetInt(IntID::UseOverlayScrollbars);
}
static constexpr int32_t kDefaultTooltipOffset = 21;
static int32_t TooltipOffsetVertical() {
return GetInt(IntID::TooltipOffsetVertical, kDefaultTooltipOffset);
}
// Returns keyCode value of a modifier key which is used for accesskey.
// Returns 0 if the platform doesn't support access key.
static uint32_t GetMenuAccessKey();

View file

@ -167,6 +167,7 @@ static const char sIntPrefs[][45] = {
"ui.scrollbarFadeDuration",
"ui.contextMenuOffsetVertical",
"ui.contextMenuOffsetHorizontal",
"ui.tooltipOffsetVertical",
"ui.GtkCSDAvailable",
"ui.GtkCSDMinimizeButton",
"ui.GtkCSDMaximizeButton",

View file

@ -36,6 +36,17 @@ static int32_t GetSystemParam(long flag, int32_t def) {
return ::SystemParametersInfo(flag, 0, &value, 0) ? value : def;
}
static int32_t GetTooltipOffsetVertical() {
static constexpr DWORD kDefaultCursorSize = 32;
const DWORD cursorSize =
GetSystemParam(MOZ_SPI_CURSORSIZE, kDefaultCursorSize);
if (cursorSize == kDefaultCursorSize) {
return LookAndFeel::kDefaultTooltipOffset;
}
return std::ceilf(float(LookAndFeel::kDefaultTooltipOffset) *
float(cursorSize) / float(kDefaultCursorSize));
}
static bool SystemWantsDarkTheme() {
if (nsUXThemeData::IsHighContrastOn()) {
return LookAndFeel::IsDarkColor(
@ -523,6 +534,9 @@ nsresult nsLookAndFeel::NativeGetInt(IntID aID, int32_t& aResult) {
case IntID::ContextMenuOffsetHorizontal:
aResult = 2;
break;
case IntID::TooltipOffsetVertical:
aResult = GetTooltipOffsetVertical();
break;
case IntID::SystemUsesDarkTheme:
aResult = SystemWantsDarkTheme();
break;

View file

@ -40,6 +40,10 @@
#define SYS_COLOR_MAX 30
#define SYS_COLOR_COUNT (SYS_COLOR_MAX - SYS_COLOR_MIN + 1)
// Undocumented SPI, see bug 1712669 comment 4.
#define MOZ_SPI_CURSORSIZE 0x2028
#define MOZ_SPI_SETCURSORSIZE 0x2029
namespace mozilla::widget::WinRegistry {
class KeyWatcher;
}

View file

@ -78,6 +78,7 @@
#include <limits>
#include "mozilla/widget/WinMessages.h"
#include "nsLookAndFeel.h"
#include "nsWindow.h"
#include "nsWindowTaskbarConcealer.h"
#include "nsAppRunner.h"
@ -4939,10 +4940,12 @@ bool nsWindow::ProcessMessageInternal(UINT msg, WPARAM& wParam, LPARAM& lParam,
case WM_SETTINGCHANGE: {
if (wParam == SPI_SETCLIENTAREAANIMATION ||
wParam == SPI_SETKEYBOARDDELAY || wParam == SPI_SETMOUSEVANISH) {
wParam == SPI_SETKEYBOARDDELAY || wParam == SPI_SETMOUSEVANISH ||
wParam == MOZ_SPI_SETCURSORSIZE) {
// These need to update LookAndFeel cached values.
// They affect reduced motion settings / caret blink count / show
// pointer while typing, so no need to invalidate style / layout.
// pointer while typing / tooltip offset, so no need to invalidate style
// / layout.
NotifyThemeChanged(widget::ThemeChangeKind::MediaQueriesOnly);
break;
}