tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 48aa2404e61655d5597e7056b758b0b6a45c8f2d
parent 057c945f2af107bb8b34eb4bfd1645117274c14e
Author: Emilio Cobos Álvarez <emilio@crisal.io>
Date:   Tue,  6 Jan 2026 12:22:51 +0000

Bug 2006480 - Factor client area + margin into its own struct. r=stransky

No behavior change but makes it a bit easier to reason about, and allows
us to compute the bounds out of band if we need to.

Differential Revision: https://phabricator.services.mozilla.com/D277320

Diffstat:
Mwidget/gtk/nsWindow.cpp | 111+++++++++++++++++++++++++++++++++++++++++++------------------------------------
Mwidget/gtk/nsWindow.h | 61+++++++++++++++++++++++++++++++++----------------------------
2 files changed, 94 insertions(+), 78 deletions(-)

diff --git a/widget/gtk/nsWindow.cpp b/widget/gtk/nsWindow.cpp @@ -3299,10 +3299,10 @@ LayoutDeviceIntCoord GetXWindowBorder(GdkWindow* aWin) { top corner, so matches CSD size - (40,40). */ #ifdef MOZ_X11 -void nsWindow::RecomputeBoundsX11() { - LOG("RecomputeBoundsX11()"); +auto nsWindow::Bounds::ComputeX11(const nsWindow* aWindow) -> Bounds { + LOG_WIN(aWindow, "Bounds::ComputeX11()"); - auto* toplevel = GetToplevelGdkWindow(); + auto* toplevel = aWindow->GetToplevelGdkWindow(); // Window position and size with window decoration AND system titlebar. auto GetFrameTitlebarBounds = [&](GdkWindow* aWin) { @@ -3310,12 +3310,13 @@ void nsWindow::RecomputeBoundsX11() { gdk_window_get_frame_extents(aWin, &b); if (gtk_check_version(3, 24, 35) && gdk_window_get_window_type(aWin) == GDK_WINDOW_TEMP) { - LOGVERBOSE( + LOG_WIN( + aWindow, " GetFrameTitlebarBounds gtk 3.24.35 & GDK_WINDOW_TEMP workaround"); // Workaround for https://gitlab.gnome.org/GNOME/gtk/-/merge_requests/4820 // Bug 1775017 Gtk < 3.24.35 returns scaled values for // override redirected window on X11. - double scale = FractionalScaleFactor(); + double scale = aWindow->FractionalScaleFactor(); return DesktopIntRect(int(round(b.x / scale)), int(round(b.y / scale)), int(round(b.width / scale)), int(round(b.height / scale))); @@ -3323,11 +3324,11 @@ void nsWindow::RecomputeBoundsX11() { auto result = DesktopIntRect(b.x, b.y, b.width, b.height); if (gtk_check_version(3, 24, 50)) { if (auto border = GetXWindowBorder(aWin)) { - LOGVERBOSE(" GetFrameTitlebarBounds gtk 3.24.50 workaround"); + LOG_WIN(aWindow, " GetFrameTitlebarBounds gtk 3.24.50 workaround"); // Workaround for // https://gitlab.gnome.org/GNOME/gtk/-/merge_requests/8423 // Bug 1958174 Gtk doesn't account for window border sizes on X11. - double scale = FractionalScaleFactor(); + double scale = aWindow->FractionalScaleFactor(); result.width += 2 * border / scale; result.height += 2 * border / scale; } @@ -3338,7 +3339,7 @@ void nsWindow::RecomputeBoundsX11() { // Window position and size with decoration but WITHOUT system titlebar. auto GetBounds = [&](GdkWindow* aWin) { GdkRectangle b{0}; - if (IsTopLevelWidget() && aWin == toplevel) { + if (aWindow->IsTopLevelWidget() && aWin == toplevel) { // We want the up-to-date size from the X server, not the last configure // event size, to avoid spurious resizes on e.g. sizemode changes. gdk_window_get_geometry(aWin, nullptr, nullptr, &b.width, &b.height); @@ -3352,11 +3353,11 @@ void nsWindow::RecomputeBoundsX11() { }; const auto toplevelBoundsWithTitlebar = GetFrameTitlebarBounds(toplevel); - const auto toplevelBounds = GetBounds(toplevel); + LOG_WIN(aWindow, " toplevelBoundsWithTitlebar %s", + ToString(toplevelBoundsWithTitlebar).c_str()); - LOGVERBOSE(" toplevelBoundsWithTitlebar %s", - ToString(toplevelBoundsWithTitlebar).c_str()); - LOGVERBOSE(" toplevelBounds %s", ToString(toplevelBounds).c_str()); + const auto toplevelBounds = GetBounds(toplevel); + LOG_WIN(aWindow, " toplevelBounds %s", ToString(toplevelBounds).c_str()); // Offset from system decoration to gtk decoration. const auto systemDecorationOffset = [&] { @@ -3376,31 +3377,35 @@ void nsWindow::RecomputeBoundsX11() { return offset; }(); + Bounds result; // This is relative to our parent window, that is, to topLevelBounds. - mClientArea = GetBounds(mGdkWindow); + result.mClientArea = GetBounds(aWindow->GetGdkWindow()); // Make it relative to topLevelBoundsWithTitlebar - mClientArea.MoveBy(systemDecorationOffset); - LOGVERBOSE(" mClientArea %s", ToString(mClientArea).c_str()); + result.mClientArea.MoveBy(systemDecorationOffset); + LOG_WIN(aWindow, " mClientArea %s", ToString(result.mClientArea).c_str()); - if (mClientArea.X() < 0 || mClientArea.Y() < 0 || mClientArea.Width() <= 1 || - mClientArea.Height() <= 1) { + if (result.mClientArea.X() < 0 || result.mClientArea.Y() < 0 || + result.mClientArea.Width() <= 1 || result.mClientArea.Height() <= 1) { // If we don't have gdkwindow bounds, assume we take the whole toplevel // except system decorations. - mClientArea = DesktopIntRect(systemDecorationOffset, toplevelBounds.Size()); + result.mClientArea = + DesktopIntRect(systemDecorationOffset, toplevelBounds.Size()); } - mClientMargin = + result.mClientMargin = DesktopIntRect(DesktopIntPoint(), toplevelBoundsWithTitlebar.Size()) - - mClientArea; - mClientMargin.EnsureAtLeast(DesktopIntMargin()); + result.mClientArea; + result.mClientMargin.EnsureAtLeast(DesktopIntMargin()); // We want mClientArea in global coordinates. We derive everything from here, // so move it to global coords. - mClientArea.MoveBy(toplevelBoundsWithTitlebar.TopLeft()); + result.mClientArea.MoveBy(toplevelBoundsWithTitlebar.TopLeft()); + return result; } #endif #ifdef MOZ_WAYLAND -void nsWindow::RecomputeBoundsWayland() { +auto nsWindow::Bounds::ComputeWayland(const nsWindow* aWindow) -> Bounds { + LOG_WIN(aWindow, "Bounds::ComputeWayland()"); auto GetBounds = [&](GdkWindow* aWin) { GdkRectangle b{0}; gdk_window_get_position(aWin, &b.x, &b.y); @@ -3409,27 +3414,41 @@ void nsWindow::RecomputeBoundsWayland() { return DesktopIntRect(b.x, b.y, b.width, b.height); }; - const auto toplevelBounds = GetBounds(GetToplevelGdkWindow()); - mClientArea = GetBounds(mGdkWindow); + const auto toplevelBounds = GetBounds(aWindow->GetToplevelGdkWindow()); + LOG_WIN(aWindow, " toplevelBounds %s", ToString(toplevelBounds).c_str()); + Bounds result; + result.mClientArea = GetBounds(aWindow->GetGdkWindow()); + LOG_WIN(aWindow, " bounds %s", ToString(result.mClientArea).c_str()); - LOG("RecomputeBoundsWayland() GetBounds(mGdkWindow) [%d,%d] -> [%d x %d] " - "GetBounds(mShell) [%d,%d] -> [%d x %d]", - mClientArea.x, mClientArea.y, mClientArea.width, mClientArea.height, - toplevelBounds.x, toplevelBounds.y, toplevelBounds.width, - toplevelBounds.height); - - if (mClientArea.X() < 0 || mClientArea.Y() < 0 || mClientArea.Width() <= 1 || - mClientArea.Height() <= 1) { + if (result.mClientArea.X() < 0 || result.mClientArea.Y() < 0 || + result.mClientArea.Width() <= 1 || result.mClientArea.Height() <= 1) { // If we don't have gdkwindow bounds yet, assume we take the whole toplevel. - mClientArea = toplevelBounds; + result.mClientArea = toplevelBounds; } - mClientMargin = - DesktopIntRect(DesktopIntPoint(), toplevelBounds.Size()) - mClientArea; - mClientMargin.EnsureAtLeast(DesktopIntMargin()); + result.mClientMargin = + DesktopIntRect(DesktopIntPoint(), toplevelBounds.Size()) - + result.mClientArea; + result.mClientMargin.EnsureAtLeast(DesktopIntMargin()); + return result; } #endif +auto nsWindow::Bounds::Compute(const nsWindow* aWindow) -> Bounds { +#ifdef MOZ_X11 + if (GdkIsX11Display()) { + return ComputeX11(aWindow); + } +#endif +#ifdef MOZ_WAYLAND + if (GdkIsWaylandDisplay()) { + return ComputeWayland(aWindow); + } +#endif + MOZ_ASSERT_UNREACHABLE("How?"); + return {}; +} + void nsWindow::RecomputeBounds(bool aScaleChange) { LOG("RecomputeBounds() scale change %d", aScaleChange); mPendingBoundsChange = false; @@ -3439,19 +3458,11 @@ void nsWindow::RecomputeBounds(bool aScaleChange) { return; } - const auto oldClientArea = mClientArea; const auto oldMargin = mClientMargin; - -#ifdef MOZ_X11 - if (GdkIsX11Display()) { - RecomputeBoundsX11(); - } -#endif -#ifdef MOZ_WAYLAND - if (GdkIsWaylandDisplay()) { - RecomputeBoundsWayland(); - } -#endif + const auto oldClientArea = mClientArea; + const auto newBounds = Bounds::Compute(this); + mClientArea = newBounds.mClientArea; + mClientMargin = newBounds.mClientMargin; if (IsPopup()) { // Popup windows is not moved by the window manager, and so any change in @@ -9066,7 +9077,7 @@ gint nsWindow::GdkCeiledScaleFactor() { return ScreenHelperGTK::GetGTKMonitorScaleFactor(); } -double nsWindow::FractionalScaleFactor() { +double nsWindow::FractionalScaleFactor() const { #ifdef MOZ_WAYLAND if (mSurface) { auto scale = mSurface->GetScale(); diff --git a/widget/gtk/nsWindow.h b/widget/gtk/nsWindow.h @@ -60,10 +60,11 @@ extern mozilla::LazyLogModule gWidgetPopupLog; extern mozilla::LazyLogModule gWidgetVsync; extern mozilla::LazyLogModule gWidgetWaylandLog; -# define LOG(str, ...) \ - MOZ_LOG(IsPopup() ? gWidgetPopupLog : gWidgetLog, \ - mozilla::LogLevel::Debug, \ - ("%s: " str, GetDebugTag().get(), ##__VA_ARGS__)) +# define LOG_WIN(win, str, ...) \ + MOZ_LOG(win->IsPopup() ? gWidgetPopupLog : gWidgetLog, \ + mozilla::LogLevel::Debug, \ + ("%s: " str, win->GetDebugTag().get(), ##__VA_ARGS__)) +# define LOG(...) LOG_WIN(this, __VA_ARGS__) # define LOGVERBOSE(str, ...) \ MOZ_LOG(IsPopup() ? gWidgetPopupLog : gWidgetLog, \ mozilla::LogLevel::Verbose, \ @@ -88,6 +89,7 @@ extern mozilla::LazyLogModule gWidgetWaylandLog; #else # define LOG(...) +# define LOG_WIN(...) # define LOGVERBOSE(...) # define LOGW(...) # define LOGDRAG(...) @@ -224,12 +226,33 @@ class nsWindow final : public nsIWidget { // Recomputes the bounds according to our current window position. Dispatches // move / resizes as needed. void RecomputeBounds(bool aScaleChange = false); + // Window bounds (as in GetBounds()) are composed as + // mClientArea.Inflate(mClientMargin)*scale, i.e.: + // + // mBounds.x = (mClientArea.x - mClientMargin.left) * scale; + // mBounds.y = (mClientArea.y - mClientMargin.top) * scale; + // mBounds.width = (mClientArea.width + + // (mClientMargin.right + mClientMargin.left)) * scale; + // mBounds.height = (mClientArea.height + + // (mClientMargin.top + mClientMargin.bottom)) * scale; + // + // We use mClientMargin and mClientArea in Gdk (logical, widget) coordinates + // instead of device pixel coordinates to avoid rounding errors. + struct Bounds { + // mClientArea is window rendering area in global coordinates. + DesktopIntRect mClientArea; + // mClientMargin contains CSD decorations size on Wayland and + // CSD decorations and system titlebar size on X11. + DesktopIntMargin mClientMargin; + + static Bounds Compute(const nsWindow*); #ifdef MOZ_X11 - void RecomputeBoundsX11(); + static Bounds ComputeX11(const nsWindow*); #endif #ifdef MOZ_WAYLAND - void RecomputeBoundsWayland(); + static Bounds ComputeWayland(const nsWindow*); #endif + }; void SchedulePendingBounds(); void MaybeRecomputeBounds(); @@ -436,7 +459,7 @@ class nsWindow final : public nsIWidget { // HiDPI scale conversion gint GdkCeiledScaleFactor(); - double FractionalScaleFactor(); + double FractionalScaleFactor() const; LayoutDeviceIntPoint ToLayoutDevicePixels(const DesktopIntPoint&); LayoutDeviceIntSize ToLayoutDevicePixels(const DesktopIntSize&); @@ -638,27 +661,9 @@ class nsWindow final : public nsIWidget { // Same but for positioning. Used to track move requests. DesktopIntPoint mLastMoveRequest; - // Window bounds (mBounds) are composed as - // mClientArea.Inflate(mClientMargin)*scale, i.e.: - // - // mBounds.x = (mClientArea.x - mClientMargin.left) * scale; - // mBounds.y = (mClientArea.y - mClientMargin.top) * scale; - // mBounds.width = (mClientArea.width + - // (mClientMargin.right + mClientMargin.left)) * scale; - // mBounds.height = (mClientArea.height + - // (mClientMargin.top + mClientMargin.bottom)) * scale; - // - // We use mClientMargin and mClientArea in Gdk (logical, widget) coordinates - // instead of mBounds i device pixel coordinates to avoid - // rounding errors. - - // mClientMargin contains CSD decorations size on Wayland and - // CSD decorations and system titlebar size on X11. - DesktopIntMargin mClientMargin{}; - - // mClientArea is window rendering area. mClientArea.x, mClientArea.y are - // equal to mClientMargin.left, mClientMargin.top. - DesktopIntRect mClientArea{}; + // See Bounds for these members. + DesktopIntRect mClientArea; + DesktopIntMargin mClientMargin; // This field omits duplicate scroll events caused by GNOME bug 726878. guint32 mLastScrollEventTime = GDK_CURRENT_TIME;