tor-browser

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

commit ea90b161fe6c4fc6ce870312f1a1c6190b07bb94
parent 6650ab8589f85c1a52664fe64dd13f33a625209b
Author: Narcis Beleuzu <nbeleuzu@mozilla.com>
Date:   Wed, 22 Oct 2025 16:09:41 +0300

Revert "Bug 1992198 [Linux] Use logical (widget) coordinates to calculate widget size/positions/boundaries r=emilio,layout-reviewers" for bc failures

This reverts commit ae425b2a55b4dd05374fbdcb80e09a19d1caa3e8.

Diffstat:
Mlayout/base/Units.h | 13-------------
Mwidget/gtk/ScreenHelperGTK.cpp | 28+++++++++++++---------------
Mwidget/gtk/nsWindow.cpp | 764++++++++++++++++++++++++++++++-------------------------------------------------
Mwidget/gtk/nsWindow.h | 87+++++++++++++++++++++++++------------------------------------------------------
Awidget/nsBaseWidget.h | 0
Mwidget/nsIWidget.h | 4+---
6 files changed, 331 insertions(+), 565 deletions(-)

diff --git a/layout/base/Units.h b/layout/base/Units.h @@ -178,7 +178,6 @@ typedef gfx::SizeTyped<DesktopPixel> DesktopSize; typedef gfx::IntSizeTyped<DesktopPixel> DesktopIntSize; typedef gfx::RectTyped<DesktopPixel> DesktopRect; typedef gfx::IntRectTyped<DesktopPixel> DesktopIntRect; -typedef gfx::IntMarginTyped<DesktopPixel> DesktopIntMargin; typedef gfx::CoordTyped<ExternalPixel> ExternalCoord; typedef gfx::IntCoordTyped<ExternalPixel> ExternalIntCoord; @@ -707,9 +706,6 @@ struct ParentLayerPixel {}; * - on Windows *with* per-monitor DPI support, they are physical device pixels * on each screen; note that this means the scaling between CSS pixels and * desktop pixels may vary across multiple displays. - * - on Linux, they're "Gdk points", which correspond to widget coordinates - * used by Gdk and X11 or Wayland compositor and are mapped to actual - * screen pixels by per-monitor screen scale. */ struct DesktopPixel {}; @@ -954,15 +950,6 @@ gfx::MarginTyped<Dst, F> operator/( aMargin.bottom.value / aScale.yScale, aMargin.left.value / aScale.xScale); } -template <class Src, class Dst> -gfx::MarginTyped<Dst> operator*(const gfx::IntMarginTyped<Src>& aMargin, - const gfx::ScaleFactor<Src, Dst>& aScale) { - return gfx::MarginTyped<Dst>(float(aMargin.top.value) * aScale.scale, - float(aMargin.right.value) * aScale.scale, - float(aMargin.bottom.value) * aScale.scale, - float(aMargin.left.value) * aScale.scale); -} - // Calculate the max or min or the ratios of the widths and heights of two // sizes, returning a scale factor in the correct units. diff --git a/widget/gtk/ScreenHelperGTK.cpp b/widget/gtk/ScreenHelperGTK.cpp @@ -78,12 +78,21 @@ static already_AddRefed<Screen> MakeScreenGtk(unsigned int aMonitor, workarea.width * geometryScaleFactor, workarea.height * geometryScaleFactor); + LayoutDeviceIntRect rect; DesktopToLayoutDeviceScale contentsScale(1.0); CSSToLayoutDeviceScale defaultCssScale(geometryScaleFactor); - contentsScale.scale = geometryScaleFactor; + if (GdkIsX11Display()) { + GdkRectangle monitor; + gdk_screen_get_monitor_geometry(defaultScreen, aMonitor, &monitor); + rect = LayoutDeviceIntRect(monitor.x * geometryScaleFactor, + monitor.y * geometryScaleFactor, + monitor.width * geometryScaleFactor, + monitor.height * geometryScaleFactor); + } else { + // Use per-monitor scaling factor in Wayland. + contentsScale.scale = geometryScaleFactor; #ifdef MOZ_WAYLAND - if (GdkIsWaylandDisplay()) { if (StaticPrefs::widget_wayland_fractional_scale_enabled()) { // Check if we're using fractional scale (see Bug 1985720). // In such case use workarea is already scaled by fractional scale factor. @@ -101,21 +110,10 @@ static already_AddRefed<Screen> MakeScreenGtk(unsigned int aMonitor, contentsScale.scale = fractionalScale; } } +#endif // Don't report screen shift in Wayland, see bug 1795066. availRect.MoveTo(0, 0); - } -#endif - - // Use workarea as screen rect on Wayland (Bug 1732682). - LayoutDeviceIntRect rect; - if (GdkIsX11Display()) { - GdkRectangle monitor; - gdk_screen_get_monitor_geometry(defaultScreen, aMonitor, &monitor); - rect = LayoutDeviceIntRect(monitor.x * geometryScaleFactor, - monitor.y * geometryScaleFactor, - monitor.width * geometryScaleFactor, - monitor.height * geometryScaleFactor); - } else { + // We use Gtk workarea on Wayland as it matches our needs (Bug 1732682). rect = availRect; } diff --git a/widget/gtk/nsWindow.cpp b/widget/gtk/nsWindow.cpp @@ -455,7 +455,7 @@ nsWindow::nsWindow() mConfiguredClearColor(false), mGotNonBlankPaint(false), mNeedsToRetryCapturingMouse(false) { - SetSafeWindowSize(mSizeConstraints.mMaxSize); + mSizeConstraints.mMaxSize = GetSafeWindowSize(mSizeConstraints.mMaxSize); if (!gGlobalsInitialized) { gGlobalsInitialized = true; @@ -592,14 +592,15 @@ void nsWindow::DispatchResized() { auto clientSize = GetClientSize(); - LOG("nsWindow::DispatchResized() client size [%d, %d]", (int)clientSize.width, + LOG("nsWindow::DispatchResized() size [%d, %d] client size [%d, %d]", + (int)(mBounds.width), (int)(mBounds.height), (int)clientSize.width, (int)clientSize.height); - // Check out painting texture size + // Check mBounds size if (mCompositorSession && - !wr::WindowSizeSanityCheck(clientSize.width, clientSize.height)) { - gfxCriticalNoteOnce << "Invalid mClientArea in MaybeDispatchResized " - << clientSize << " size state " << mSizeMode; + !wr::WindowSizeSanityCheck(mBounds.width, mBounds.height)) { + gfxCriticalNoteOnce << "Invalid mBounds in MaybeDispatchResized " << mBounds + << " size state " << mSizeMode; } // Notify the GtkCompositorWidget of a ClientSizeChange @@ -654,7 +655,7 @@ void nsWindow::OnDestroy(void) { } bool nsWindow::AreBoundsSane() { - // Check requested size, as mClientArea might not have been updated. + // Check requested size, as mBounds might not have been updated. return !mLastSizeRequest.IsEmpty(); } @@ -770,7 +771,14 @@ float nsWindow::GetDPI() { double nsWindow::GetDefaultScaleInternal() { return FractionalScaleFactor(); } DesktopToLayoutDeviceScale nsWindow::GetDesktopToDeviceScale() { - return DesktopToLayoutDeviceScale(FractionalScaleFactor()); +#ifdef MOZ_WAYLAND + if (GdkIsWaylandDisplay()) { + return DesktopToLayoutDeviceScale(FractionalScaleFactor()); + } +#endif + + // In Gtk/X11, we manage windows using device pixels. + return DesktopToLayoutDeviceScale(1.0); } bool nsWindow::WidgetTypeSupportsAcceleration() { @@ -887,9 +895,8 @@ void nsWindow::ConstrainPosition(DesktopIntPoint& aPoint) { double dpiScale = GetDefaultScale().scale; // we need to use the window size in logical screen pixels - auto bounds = GetScreenBounds(); - int32_t logWidth = std::max(NSToIntRound(bounds.width / dpiScale), 1); - int32_t logHeight = std::max(NSToIntRound(bounds.height / dpiScale), 1); + int32_t logWidth = std::max(NSToIntRound(mBounds.width / dpiScale), 1); + int32_t logHeight = std::max(NSToIntRound(mBounds.height / dpiScale), 1); /* get our playing field. use the current screen, or failing that for any reason, use device caps for the default screen. */ @@ -920,43 +927,33 @@ void nsWindow::ConstrainPosition(DesktopIntPoint& aPoint) { aPoint = ConstrainPositionToBounds(aPoint, {logWidth, logHeight}, screenRect); } -bool nsWindow::ConstrainSizeWithScale(int* aWidth, int* aHeight, - double aScale) { +void nsWindow::ConstrainSize(int* aWidth, int* aHeight) { // We store our constraints in inner sizes for convenience, but that means we // need to also constrain inner sizes as inner, rather than outer. - int scaledWidth = (*aWidth - mClientMargin.LeftRight()) * aScale; - int scaledHeight = (*aHeight - mClientMargin.TopBottom()) * aScale; - int tmpWidth = scaledWidth, tmpHeight = scaledHeight; - nsIWidget::ConstrainSize(&tmpWidth, &tmpHeight); - if (tmpWidth != scaledWidth || tmpHeight != scaledHeight) { - *aWidth = int(round(tmpWidth / aScale)) + mClientMargin.LeftRight(); - *aHeight = int(round(tmpHeight / aScale)) + mClientMargin.TopBottom(); - return true; - } - return false; + *aWidth -= mClientMargin.LeftRight(); + *aHeight -= mClientMargin.TopBottom(); + nsIWidget::ConstrainSize(aWidth, aHeight); + *aWidth += mClientMargin.LeftRight(); + *aHeight += mClientMargin.TopBottom(); } -// aConstrains are set is in device pixel sizes as it describes -// max texture / window size in pixels. void nsWindow::SetSizeConstraints(const SizeConstraints& aConstraints) { - mSizeConstraints = aConstraints; - SetSafeWindowSize(mSizeConstraints.mMinSize); - SetSafeWindowSize(mSizeConstraints.mMaxSize); + mSizeConstraints.mMinSize = GetSafeWindowSize(aConstraints.mMinSize); + mSizeConstraints.mMaxSize = GetSafeWindowSize(aConstraints.mMaxSize); // Store constraints as inner sizes rather than outer sizes. if (SizeMode() == nsSizeMode_Normal) { - auto margin = ToLayoutDevicePixels(mClientMargin); if (mSizeConstraints.mMinSize.height) { - mSizeConstraints.mMinSize.height -= margin.TopBottom(); + mSizeConstraints.mMinSize.height -= mClientMargin.TopBottom(); } if (mSizeConstraints.mMinSize.width) { - mSizeConstraints.mMinSize.width -= margin.LeftRight(); + mSizeConstraints.mMinSize.width -= mClientMargin.LeftRight(); } if (mSizeConstraints.mMaxSize.height != NS_MAXSIZE) { - mSizeConstraints.mMaxSize.height -= margin.TopBottom(); + mSizeConstraints.mMaxSize.height -= mClientMargin.TopBottom(); } if (mSizeConstraints.mMaxSize.width != NS_MAXSIZE) { - mSizeConstraints.mMaxSize.width -= margin.LeftRight(); + mSizeConstraints.mMaxSize.width -= mClientMargin.LeftRight(); } } @@ -1003,21 +1000,19 @@ void nsWindow::ApplySizeConstraints() { if (constraints.mMinSize != LayoutDeviceIntSize()) { gtk_widget_set_size_request( GTK_WIDGET(mContainer), - DevicePixelsToGdkCoordRound(constraints.mMinSize.width), - DevicePixelsToGdkCoordRound(constraints.mMinSize.height)); + DevicePixelsToGdkCoordRoundUp(constraints.mMinSize.width), + DevicePixelsToGdkCoordRoundUp(constraints.mMinSize.height)); if (ToplevelUsesCSD()) { - auto margin = ToLayoutDevicePixels(mClientMargin); - constraints.mMinSize.height += margin.TopBottom(); - constraints.mMinSize.width += margin.LeftRight(); + constraints.mMinSize.height += mClientMargin.TopBottom(); + constraints.mMinSize.width += mClientMargin.LeftRight(); } hints |= GDK_HINT_MIN_SIZE; } if (mSizeConstraints.mMaxSize != LayoutDeviceIntSize(NS_MAXSIZE, NS_MAXSIZE)) { if (ToplevelUsesCSD()) { - auto margin = ToLayoutDevicePixels(mClientMargin); - constraints.mMaxSize.height += margin.TopBottom(); - constraints.mMaxSize.width += margin.LeftRight(); + constraints.mMaxSize.height += mClientMargin.TopBottom(); + constraints.mMaxSize.width += mClientMargin.LeftRight(); } hints |= GDK_HINT_MAX_SIZE; } @@ -1025,10 +1020,11 @@ void nsWindow::ApplySizeConstraints() { // Constraints for the shell are outer sizes, but with SSD we need to use // inner sizes. GdkGeometry geometry{ - .min_width = DevicePixelsToGdkCoordRound(constraints.mMinSize.width), - .min_height = DevicePixelsToGdkCoordRound(constraints.mMinSize.height), - .max_width = DevicePixelsToGdkCoordRound(constraints.mMaxSize.width), - .max_height = DevicePixelsToGdkCoordRound(constraints.mMaxSize.height), + .min_width = DevicePixelsToGdkCoordRoundUp(constraints.mMinSize.width), + .min_height = DevicePixelsToGdkCoordRoundUp(constraints.mMinSize.height), + .max_width = DevicePixelsToGdkCoordRoundDown(constraints.mMaxSize.width), + .max_height = + DevicePixelsToGdkCoordRoundDown(constraints.mMaxSize.height), }; if (mAspectRatio != 0.0f && !mAspectResizer) { @@ -1076,58 +1072,33 @@ void nsWindow::Show(bool aState) { RefreshWindowClass(); } -LayoutDeviceIntPoint nsWindow::ToLayoutDevicePixels( - const DesktopIntPoint& aPoint) { - return LayoutDeviceIntPoint::Round(aPoint * GetDesktopToDeviceScale()); -} - -LayoutDeviceIntSize nsWindow::ToLayoutDevicePixels( - const DesktopIntSize& aSize) { - return LayoutDeviceIntSize::Round(aSize * GetDesktopToDeviceScale()); -} - -LayoutDeviceIntRect nsWindow::ToLayoutDevicePixels( - const DesktopIntRect& aRect) { - return LayoutDeviceIntRect::Round(aRect * GetDesktopToDeviceScale()); -} - -LayoutDeviceIntMargin nsWindow::ToLayoutDevicePixels( - const DesktopIntMargin& aMargin) { - return (aMargin * GetDesktopToDeviceScale()).Rounded(); -} - -DesktopIntPoint nsWindow::ToDesktopPixels(const LayoutDeviceIntPoint& aPoint) { - return DesktopIntPoint::Round(aPoint / GetDesktopToDeviceScale()); -} - -DesktopIntSize nsWindow::ToDesktopPixels(const LayoutDeviceIntSize& aSize) { - return DesktopIntSize::Round(aSize / GetDesktopToDeviceScale()); -} - -DesktopIntRect nsWindow::ToDesktopPixels(const LayoutDeviceIntRect& aRect) { - return DesktopIntRect::Round(aRect / GetDesktopToDeviceScale()); -} - -void nsWindow::ResizeInt(const Maybe<DesktopIntPoint>& aMove, - DesktopIntSize aSize) { +void nsWindow::ResizeInt(const Maybe<LayoutDeviceIntPoint>& aMove, + LayoutDeviceIntSize aSize) { LOG("nsWindow::ResizeInt w:%d h:%d\n", aSize.width, aSize.height); - const bool moved = - aMove && (*aMove != mLastMoveRequest || mClientArea.TopLeft() != *aMove); + aMove && (*aMove != mLastMoveRequest || mBounds.TopLeft() != *aMove); if (moved) { LOG(" with move to left:%d top:%d", aMove->x.value, aMove->y.value); mLastMoveRequest = *aMove; } - const bool resized = aSize != mLastSizeRequest || mClientArea.Size() != aSize; + ConstrainSize(&aSize.width, &aSize.height); + LOG(" ConstrainSize: w:%d h;%d\n", aSize.width, aSize.height); + + const bool resized = aSize != mLastSizeRequest || mBounds.Size() != aSize; #if MOZ_LOGGING - LOG(" resized %d aSize [%d, %d] mLastSizeRequest [%d, %d] " - "mClientArea [%d, %d]", + LOG(" resized %d aSize [%d, %d] mLastSizeRequest [%d, %d] mBounds [%d, %d]", resized, aSize.width, aSize.height, mLastSizeRequest.width, - mLastSizeRequest.height, mClientArea.width, mClientArea.height); + mLastSizeRequest.height, mBounds.width, mBounds.height); #endif mLastSizeRequest = aSize; + // Check size + if (mCompositorSession && + !wr::WindowSizeSanityCheck(aSize.width, aSize.height)) { + gfxCriticalNoteOnce << "Invalid aSize in ResizeInt " << aSize + << " size state " << mSizeMode; + } // Recalculate aspect ratio when resized from DOM if (mAspectRatio != 0.0) { @@ -1147,47 +1118,23 @@ void nsWindow::ResizeInt(const Maybe<DesktopIntPoint>& aMove, } void nsWindow::Resize(const DesktopSize& aSize, bool aRepaint) { + auto size = LayoutDeviceIntSize::Round(aSize * GetDesktopToDeviceScale()); LOG("nsWindow::Resize %s (scaled %s)", ToString(aSize).c_str(), - ToString(aSize).c_str()); - - double scale = GetDesktopToDeviceScale().scale; - auto size = DesktopIntSize::Round(aSize); - auto scaledSize = ToLayoutDevicePixels(size); - - if (ConstrainSizeWithScale(&size.width, &size.height, scale)) { - LOG(" ConstrainSizeWithScale: w:%d h:%d coord scale %f", size.width, - size.height, scale); - } - if (mCompositorSession && - !wr::WindowSizeSanityCheck(scaledSize.width, scaledSize.height)) { - gfxCriticalNoteOnce << "Invalid aSize in ResizeInt " << scaledSize - << " size state " << mSizeMode; - } - + ToString(size).c_str()); ResizeInt(Nothing(), size); } void nsWindow::Resize(const DesktopRect& aRect, bool aRepaint) { - double scale = GetDesktopToDeviceScale().scale; - auto size = DesktopIntSize::Round(aRect.Size()); - auto topLeft = DesktopIntPoint::Round(aRect.TopLeft()); - auto scaledSize = ToLayoutDevicePixels(size); + auto size = + LayoutDeviceIntSize::Round(aRect.Size() * GetDesktopToDeviceScale()); + auto topLeft = + LayoutDeviceIntPoint::Round(aRect.TopLeft() * GetDesktopToDeviceScale()); LOG("nsWindow::Resize [%.2f,%.2f] -> [%.2f x %.2f] scaled [%d,%d] -> " - "[%d x %d] repaint %d", + "[%d x %d] repaint %d\n", aRect.x, aRect.y, aRect.width, aRect.height, topLeft.x.value, topLeft.y.value, size.width, size.height, aRepaint); - if (ConstrainSizeWithScale(&size.width, &size.height, scale)) { - LOG(" ConstrainSizeWithScale: w:%d h:%d coord scale %f", size.width, - size.height, scale); - } - if (mCompositorSession && - !wr::WindowSizeSanityCheck(scaledSize.width, scaledSize.height)) { - gfxCriticalNoteOnce << "Invalid aSize in ResizeInt " << scaledSize - << " size state " << mSizeMode; - } - ResizeInt(Some(topLeft), size); } @@ -1196,30 +1143,27 @@ void nsWindow::Enable(bool aState) { mEnabled = aState; } bool nsWindow::IsEnabled() const { return mEnabled; } void nsWindow::Move(const DesktopPoint& aTopLeft) { - double scale = GetDesktopToDeviceScale().scale; - auto request = DesktopIntPoint::Round(aTopLeft); - - LOG("nsWindow::Move to [%d x %d] scale %f scaled [%.2f x %.2f]", - request.x.value, request.y.value, scale, request.x.value * scale, - request.y.value * scale); + auto request = + LayoutDeviceIntPoint::Round(aTopLeft * GetDesktopToDeviceScale()); + LOG("nsWindow::Move to %d x %d\n", request.x.value, request.y.value); if (mSizeMode != nsSizeMode_Normal && IsTopLevelWidget()) { - LOG(" size state is not normal, can't move, bailing"); + LOG(" size state is not normal, bailing"); return; } // Since a popup window's x/y coordinates are in relation to to // the parent, the parent might have moved so we always move a // popup window. - auto pos = GetScreenBoundsUnscaled().TopLeft(); - LOG(" bounds %d x %d\n", int(pos.x), int(pos.y)); - if (pos == request && mLastMoveRequest == request && + LOG(" bounds %d x %d\n", mBounds.x, mBounds.y); + if (mBounds.TopLeft() == request && mLastMoveRequest == request && mWindowType != WindowType::Popup) { LOG(" position is the same, return\n"); return; } // XXX Should we do some AreBoundsSane check here? + mLastMoveRequest = request; if (!mCreated) { @@ -1624,8 +1568,10 @@ void nsWindow::WaylandPopupHierarchyCalculatePositions() { // Anchored window has mPopupPosition already calculated against // its parent, no need to recalculate. LOG(" popup [%p] bounds [%d, %d] -> [%d x %d]", popup, - (int)(popup->mClientArea.x), (int)(popup->mClientArea.y), - (int)(popup->mClientArea.width), (int)(popup->mClientArea.height)); + (int)(popup->mBounds.x / FractionalScaleFactor()), + (int)(popup->mBounds.y / FractionalScaleFactor()), + (int)(popup->mBounds.width / FractionalScaleFactor()), + (int)(popup->mBounds.height / FractionalScaleFactor())); #ifdef MOZ_LOGGING if (LOG_ENABLED()) { if (nsMenuPopupFrame* popupFrame = GetPopupFrame()) { @@ -1715,8 +1661,7 @@ GdkPoint nsWindow::WaylandGetParentPosition() { GdkPoint topLeft = {0, 0}; nsWindow* window = GetEffectiveParent(); if (window->IsPopup()) { - auto offset = window->WidgetToScreenOffsetUnscaled(); - topLeft = GdkPoint{offset.x, offset.y}; + topLeft = DevicePixelsToGdkPointRoundDown(window->WidgetToScreenOffset()); } LOG("nsWindow::WaylandGetParentPosition() [%d, %d]\n", topLeft.x, topLeft.y); return topLeft; @@ -2070,18 +2015,11 @@ void nsWindow::WaylandPopupPropagateChangesToLayout(bool aMove, bool aResize) { } } if (aMove) { - auto pos = ToLayoutDevicePixels(mClientArea); - LOG(" needPositionUpdate, bounds [%d, %d]", pos.x, pos.y); - NotifyWindowMoved(pos.x, pos.y, ByMoveToRect::Yes); + LOG(" needPositionUpdate, bounds [%d, %d]", mBounds.x, mBounds.y); + NotifyWindowMoved(mBounds.x, mBounds.y, ByMoveToRect::Yes); } } -#ifdef MOZ_WAYLAND -LayoutDeviceIntSize nsWindow::GetMoveToRectPopupSize() { - return ToLayoutDevicePixels(mMoveToRectPopupSize); -} -#endif - void nsWindow::NativeMoveResizeWaylandPopupCallback( const GdkRectangle* aFinalSize, bool aFlippedX, bool aFlippedY) { // We're getting move-to-rect callback without move-to-rect call. @@ -2124,8 +2062,7 @@ void nsWindow::NativeMoveResizeWaylandPopupCallback( // perfectly round-trip. Compare gdk rects to check whether size or positions // have changed from what we'd request otherwise, in order to avoid // flickering. - const GdkRectangle currentGdkRect{mClientArea.x, mClientArea.y, - mClientArea.width, mClientArea.height}; + const GdkRectangle currentGdkRect = DevicePixelsToGdkRectRoundOut(mBounds); auto scale = GdkCeiledScaleFactor(); auto IsSubstantiallyDifferent = [=](gint a, gint b) { return std::abs(a - b) > scale; @@ -2137,17 +2074,17 @@ void nsWindow::NativeMoveResizeWaylandPopupCallback( const bool needsSizeUpdate = IsSubstantiallyDifferent(finalGdkRect.width, currentGdkRect.width) || IsSubstantiallyDifferent(finalGdkRect.height, currentGdkRect.height); - const DesktopIntRect newClientArea = DesktopIntRect( - finalGdkRect.x, finalGdkRect.y, finalGdkRect.width, finalGdkRect.height); - LOG(" orig gdk [%d, %d] -> [%d x %d]", currentGdkRect.x, currentGdkRect.y, + const LayoutDeviceIntRect newBounds = + MaybeRoundToDisplayPixels(GdkRectToDevicePixels(finalGdkRect)); + LOG(" orig gdk [%d, %d] -> [%d x %d]\n", currentGdkRect.x, currentGdkRect.y, currentGdkRect.width, currentGdkRect.height); LOG(" new gdk [%d, %d] -> [%d x %d]\n", finalGdkRect.x, finalGdkRect.y, finalGdkRect.width, finalGdkRect.height); - LOG(" orig mClientArea [%d, %d] -> [%d x %d]", mClientArea.x, mClientArea.y, - mClientArea.width, mClientArea.height); - LOG(" new mClientArea [%d, %d] -> [%d x %d]", newClientArea.x, - newClientArea.y, newClientArea.width, newClientArea.height); + LOG(" orig mBounds [%d, %d] -> [%d x %d]\n", mBounds.x, mBounds.y, + mBounds.width, mBounds.height); + LOG(" new mBounds [%d, %d] -> [%d x %d]", newBounds.x, newBounds.y, + newBounds.width, newBounds.height); if (!needsSizeUpdate && !needsPositionUpdate) { return; @@ -2156,27 +2093,24 @@ void nsWindow::NativeMoveResizeWaylandPopupCallback( // Wayland compositor changed popup size request from layout. // Set the constraints to use them in nsMenuPopupFrame::SetPopupPosition(). // Beware that gtk_window_resize() requests sizes asynchronously and so - // newClientArea might not have the size from the most recent + // newBounds might not have the size from the most recent // gtk_window_resize(). - if (mClientArea.width < mLastSizeRequest.width) { - mMoveToRectPopupSize.width = newClientArea.width; + if (newBounds.width < mLastSizeRequest.width) { + mMoveToRectPopupSize.width = newBounds.width; } - if (mClientArea.height < mLastSizeRequest.height) { - mMoveToRectPopupSize.height = newClientArea.height; + if (newBounds.height < mLastSizeRequest.height) { + mMoveToRectPopupSize.height = newBounds.height; } LOG(" mMoveToRectPopupSize set to [%d, %d]", mMoveToRectPopupSize.width, mMoveToRectPopupSize.height); } - - mClientArea = newClientArea; - mLastSizeRequest = newClientArea.Size(); - mLastMoveRequest = newClientArea.TopLeft(); - - // Check mClientArea size - auto scaledSize = ToLayoutDevicePixels(mClientArea); + mBounds = newBounds; + mLastSizeRequest = newBounds.Size(); + mLastMoveRequest = newBounds.TopLeft(); + // Check mBounds size if (mCompositorSession && - !wr::WindowSizeSanityCheck(scaledSize.width, scaledSize.height)) { - gfxCriticalNoteOnce << "Invalid mClientArea in PopupCallback " << scaledSize + !wr::WindowSizeSanityCheck(mBounds.width, mBounds.height)) { + gfxCriticalNoteOnce << "Invalid mBounds in PopupCallback " << mBounds << " size state " << mSizeMode; } WaylandPopupPropagateChangesToLayout(needsPositionUpdate, needsSizeUpdate); @@ -2217,15 +2151,14 @@ bool nsWindow::IsPopupDirectionRTL() { // It's used when we position noautihode popup and we don't use xdg_positioner. // See Bug 1718867 void nsWindow::WaylandPopupSetDirectPosition() { - GdkRectangle rect{mLastMoveRequest.x, mLastMoveRequest.y, - mLastSizeRequest.width, mLastSizeRequest.height}; + const LayoutDeviceIntRect frameRect(mLastMoveRequest, mLastSizeRequest); + GdkRectangle rect = DevicePixelsToGdkRectRoundOut(frameRect); LOG("nsWindow::WaylandPopupSetDirectPosition %d,%d -> %d x %d\n", rect.x, rect.y, rect.width, rect.height); mPopupPosition = {rect.x, rect.y}; - mClientArea.MoveTo(mLastMoveRequest); - mClientArea.SizeTo(mLastSizeRequest); + mBounds = frameRect; if (mIsDragPopup) { gtk_window_move(GTK_WINDOW(mShell), rect.x, rect.y); @@ -2272,8 +2205,8 @@ void nsWindow::WaylandPopupSetDirectPosition() { gtk_window_resize(GTK_WINDOW(mShell), rect.width, rect.height); if (mPopupPosition.x != rect.x) { - mClientArea.MoveTo(mPopupPosition.x, mPopupPosition.y); - LOG(" setting new client area [%d, %d]\n", mClientArea.x, mClientArea.y); + mBounds.MoveTo(GdkPointToDevicePixels(mPopupPosition)); + LOG(" setting new bounds [%d, %d]\n", mBounds.x, mBounds.y); WaylandPopupPropagateChangesToLayout(/* move */ true, /* resize */ false); } } @@ -2295,8 +2228,8 @@ bool nsWindow::WaylandPopupFitsToplevelWindow() { int parentHeight = gdk_window_get_height(toplevelGdkWindow); LOG(" parent size %d x %d", parentWidth, parentHeight); - GdkRectangle requestedRect{mLastMoveRequest.x, mLastMoveRequest.y, - mLastSizeRequest.width, mLastSizeRequest.height}; + GdkRectangle requestedRect = DevicePixelsToGdkRectRoundOut( + LayoutDeviceIntRect(mLastMoveRequest, mLastSizeRequest)); LOG(" popup topleft %d, %d size %d x %d", requestedRect.x, requestedRect.y, requestedRect.width, requestedRect.height); bool fits = requestedRect.x >= 0 && requestedRect.y >= 0 && @@ -2307,10 +2240,10 @@ bool nsWindow::WaylandPopupFitsToplevelWindow() { } void nsWindow::NativeMoveResizeWaylandPopup(bool aMove, bool aResize) { - GdkRectangle rect{mLastMoveRequest.x, mLastMoveRequest.y, - mLastSizeRequest.width, mLastSizeRequest.height}; + const LayoutDeviceIntRect frameRect(mLastMoveRequest, mLastSizeRequest); + GdkRectangle rect = DevicePixelsToGdkRectRoundOut(frameRect); - LOG("nsWindow::NativeMoveResizeWaylandPopup [%d,%d] -> [%d x %d] move %d " + LOG("nsWindow::NativeMoveResizeWaylandPopup Bounds %d,%d -> %d x %d move %d " "resize %d\n", rect.x, rect.y, rect.width, rect.height, aMove, aResize); @@ -2322,24 +2255,10 @@ void nsWindow::NativeMoveResizeWaylandPopup(bool aMove, bool aResize) { return; } - // We expect all Wayland popus have zero margin. If not, just position - // it as is and throw an error message. - if (!mClientMargin.IsAllZero()) { - gfxCriticalNoteOnce << "Invalid non-zero margin for WaylandPopup!"; - if (aMove) { - gtk_window_move(GTK_WINDOW(mShell), mLastMoveRequest.x, - mLastMoveRequest.y); - } - if (aResize) { - gtk_window_resize(GTK_WINDOW(mShell), mLastSizeRequest.width, - mLastSizeRequest.height); - } - } - if (mWaitingForMoveToRectCallback) { LOG(" waiting for move to rect, scheduling"); - // mClientArea position must not be overwritten before it is applied. - // OnShellConfigureEvent() will not set mClientArea to an old position for + // mBounds position must not be overwritten before it is applied. + // OnShellConfigureEvent() will not set mBounds to an old position for // GTK_WINDOW_POPUP. MOZ_ASSERT(gtk_window_get_window_type(GTK_WINDOW(mShell)) == GTK_WINDOW_POPUP); @@ -2385,8 +2304,7 @@ void nsWindow::NativeMoveResizeWaylandPopup(bool aMove, bool aResize) { LOG(" popup position changed from [%d, %d] to [%d, %d]\n", mPopupPosition.x, mPopupPosition.y, rect.x, rect.y); mPopupPosition = {rect.x, rect.y}; - mClientArea.MoveTo(mLastMoveRequest); - mClientArea.SizeTo(mLastSizeRequest); + mBounds = frameRect; UpdateWaylandPopupHierarchy(); } @@ -2700,18 +2618,15 @@ bool nsWindow::WaylandPopupCheckAndGetAnchor(GdkRectangle* aPopupAnchor, // Update popup layout coordinates from layout by recent popup hierarchy // (calculate correct position according to parent window) // and convert to Gtk coordinates. - DesktopIntRect anchorRect = - ToDesktopPixels(mPopupMoveToRectParams.mAnchorRect); + LayoutDeviceIntRect anchorRect = mPopupMoveToRectParams.mAnchorRect; if (!WaylandPopupIsFirst()) { GdkPoint parent = WaylandGetParentPosition(); LOG(" subtract parent position from anchor [%d, %d]\n", parent.x, parent.y); - anchorRect.x -= parent.x; - anchorRect.y -= parent.y; + anchorRect.MoveBy(-GdkPointToDevicePixels(parent)); } - *aPopupAnchor = GdkRectangle{anchorRect.x, anchorRect.y, anchorRect.width, - anchorRect.height}; + *aPopupAnchor = DevicePixelsToGdkRectRoundOut(anchorRect); LOG(" anchored to rectangle [%d, %d] -> [%d x %d]", aPopupAnchor->x, aPopupAnchor->y, aPopupAnchor->width, aPopupAnchor->height); @@ -3268,32 +3183,16 @@ void nsWindow::SetFocus(Raise aRaise, mozilla::dom::CallerType aCallerType) { LOG(" widget now has focus in SetFocus()"); } -DesktopIntRect nsWindow::GetScreenBoundsUnscaled() { - DesktopIntRect bounds = mClientArea; - bounds.Inflate(mClientMargin); - return bounds; -} - -LayoutDeviceIntRect nsWindow::GetScreenBounds() { - return ToLayoutDevicePixels(GetScreenBoundsUnscaled()); -} - -LayoutDeviceIntRect nsWindow::GetBounds() { - return ToLayoutDevicePixels(GetScreenBoundsUnscaled()); -} +LayoutDeviceIntRect nsWindow::GetScreenBounds() { return mBounds; } LayoutDeviceIntSize nsWindow::GetClientSize() { - return ToLayoutDevicePixels(mClientArea).Size(); + return GetClientBounds().Size(); } LayoutDeviceIntRect nsWindow::GetClientBounds() { - return ToLayoutDevicePixels(mClientArea); -} - -LayoutDeviceIntPoint nsWindow::GetClientOffset() { - auto scale = FractionalScaleFactor(); - return LayoutDeviceIntPoint(int(round(mClientMargin.left * scale)), - int(round(mClientMargin.top * scale))); + LayoutDeviceIntRect rect = GetBounds(); + rect.Deflate(mClientMargin); + return rect; } nsresult nsWindow::GetRestoredBounds(LayoutDeviceIntRect& aRect) { @@ -3306,13 +3205,12 @@ nsresult nsWindow::GetRestoredBounds(LayoutDeviceIntRect& aRect) { // though it's a bit unfortunate. aRect = GetScreenBounds(); aRect.SizeTo(GetClientSize()); - LOG("nsWindow::GetRestoredBounds() %s", ToString(aRect).c_str()); return NS_OK; } LayoutDeviceIntMargin nsWindow::NormalSizeModeClientToWindowMargin() { if (SizeMode() == nsSizeMode_Normal) { - return ToLayoutDevicePixels(mClientMargin); + return mClientMargin; } // TODO(emilio): When not using CSD decorations or not in the normal // sizemode, we can't know the size of the titlebar and window borders before @@ -3333,109 +3231,85 @@ LayoutDeviceIntCoord GetXWindowBorder(GdkWindow* aWin) { } #endif -/* - Window bounds are computed differently on X11, X11 CSD and Wayland CSD. - Let's say a non-maximized toplevel window is visible at 100,100: - - X11 (titlebar height is 40, decoration size 0): - Frame bounds: contains window position which includes window - decoration and system titlebar (100, 60) - Toplevel bounds: contains window position without tilebar (100,100) - mGdkWindow position: 0,0 (located at toplevel origin) - - X11 CSD (without system titlebar, CSD size is 40,40): - Frame bounds: contains window position which includes CSD - decorations (60,60). - Toplevel bounds: same as frame bounds. - mGdkWindow position: Relative position to toplevel decoration left - top corner, so matches CSD size - (40,40). - - Wayland CSD (with system titlebar, CSD size is 40,40, titlebar height 50): - Frame bounds: zero as Wayland doesn't report window position (0,0) - Toplevel bounds: same as frame bounds. - mGdkWindow position: Relative position to toplevel decoration left - top corner, so matches CSD + titlebar size - (40, 90). - - Wayland CSD (without system titlebar, CSD size is 40,40): - Frame bounds: zero as Wayland doesn't report window position (0,0) - Toplevel bounds: same as frame bounds. - mGdkWindow position: Relative position to toplevel decoration left - top corner, so matches CSD size - (40,40). -*/ -#ifdef MOZ_X11 -void nsWindow::RecomputeBoundsX11(bool aMayChangeCsdMargin) { - LOG("RecomputeBoundsX11(%d)", aMayChangeCsdMargin); +void nsWindow::RecomputeBounds(MayChangeCsdMargin aMayChangeCsdMargin) { + const bool mayChangeCsdMargin = + aMayChangeCsdMargin == MayChangeCsdMargin::Yes; + LOG("RecomputeBounds(%d)", mayChangeCsdMargin); + mPendingBoundsChange = false; + mPendingBoundsChangeMayChangeCsdMargin = false; auto* toplevel = GetToplevelGdkWindow(); + if (!toplevel || mIsDestroyed) { + return; + } - // Window position and size with window decoration AND system titlebar. - auto GetFrameTitlebarBounds = [&](GdkWindow* aWin) { + auto GetFrameBounds = [&](GdkWindow* aWin) { GdkRectangle b{0}; gdk_window_get_frame_extents(aWin, &b); - if (gtk_check_version(3, 24, 35) && +#ifdef MOZ_X11 + const bool isX11 = GdkIsX11Display(); + if (isX11 && gtk_check_version(3, 24, 35) && gdk_window_get_window_type(aWin) == GDK_WINDOW_TEMP) { // 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(); - return DesktopIntRect(int(round(b.x / scale)), int(round(b.y / scale)), - int(round(b.width / scale)), - int(round(b.height / scale))); + return LayoutDeviceRect(b.x, b.y, b.width, b.height); } - auto result = DesktopIntRect(b.x, b.y, b.width, b.height); - if (gtk_check_version(3, 24, 50)) { +#endif + auto result = GdkRectToFloatDevicePixels(b); +#ifdef MOZ_X11 + if (isX11 && gtk_check_version(3, 24, 50)) { if (auto border = GetXWindowBorder(aWin)) { // 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(); - result.width += 2 * border / scale; - result.height += 2 * border / scale; + result.width += 2 * border; + result.height += 2 * border; } } +#endif return result; }; - // Window position and size with decoration byt WITHOUT system titlebar. auto GetBounds = [&](GdkWindow* aWin) { GdkRectangle b{0}; - if (IsTopLevelWidget() && aWin == toplevel) { + if (IsTopLevelWidget() && GdkIsX11Display() && 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); gdk_window_get_origin(aWin, &b.x, &b.y); - return DesktopIntRect(b.x, b.y, b.width, b.height); + return GdkRectToFloatDevicePixels(b); } gdk_window_get_position(aWin, &b.x, &b.y); b.width = gdk_window_get_width(aWin); b.height = gdk_window_get_height(aWin); - return DesktopIntRect(b.x, b.y, b.width, b.height); + return GdkRectToFloatDevicePixels(b); }; - const auto toplevelBoundsWithTitlebar = GetFrameTitlebarBounds(toplevel); + const auto oldBounds = mBounds; + const auto oldMargin = mClientMargin; + const auto frameBounds = GetFrameBounds(toplevel); + const bool decorated = + IsTopLevelWidget() && mSizeMode != nsSizeMode_Fullscreen && !mUndecorated; const auto toplevelBounds = GetBounds(toplevel); - // Unscaled bounds include decorations and titlebar (X11) - DesktopIntRect finalBounds = [&] { - auto bounds = toplevelBoundsWithTitlebar; - // The toplevelBoundsWithTitlebar should always really be as wide as the - // toplevel bounds, but when opening multiple windows in quick succession on - // X11 they might not (see bug 1988787). This prevents having a really small - // window in such case. + mBounds = [&] { + auto bounds = frameBounds; + // The frameBounds should always really be as wide as the toplevel bounds, + // but when opening multiple windows in quick succession on X11 they might + // not (see bug 1988787). This prevents having a really small window in such + // case. bounds.width = std::max(bounds.width, toplevelBounds.width); bounds.height = std::max(bounds.height, toplevelBounds.height); - return bounds; + return LayoutDeviceIntRect::Round(bounds); }(); - const bool decorated = - IsTopLevelWidget() && mSizeMode != nsSizeMode_Fullscreen && !mUndecorated; if (!decorated) { mClientMargin = {}; - } else if (aMayChangeCsdMargin) { - // TODO: Do we really need so complex margin calculation on X11? - const DesktopIntRect clientRectRelativeToFrame = [&] { + } else if (mayChangeCsdMargin) { + const auto clientRectRelativeToFrame = [&] { auto topLevelBoundsRelativeToFrame = toplevelBounds; - topLevelBoundsRelativeToFrame -= toplevelBoundsWithTitlebar.TopLeft(); + topLevelBoundsRelativeToFrame -= frameBounds.TopLeft(); if (!mGdkWindow) { return topLevelBoundsRelativeToFrame; } @@ -3449,115 +3323,45 @@ void nsWindow::RecomputeBoundsX11(bool aMayChangeCsdMargin) { return gdkWindowBounds + topLevelBoundsRelativeToFrame.TopLeft(); }(); - mClientMargin = DesktopIntRect(DesktopIntPoint(), finalBounds.Size()) - - clientRectRelativeToFrame; - mClientMargin.EnsureAtLeast(DesktopIntMargin()); - } else { - // Assume the client margin remains the same. - } - - mClientArea = finalBounds; - mClientArea.Deflate(mClientMargin); -} -#endif -#ifdef MOZ_WAYLAND -void nsWindow::RecomputeBoundsWayland(bool aMayChangeCsdMargin) { - LOG("RecomputeBoundsWayland(%d)", aMayChangeCsdMargin); - - auto GetBounds = [&](GdkWindow* aWin) { - GdkRectangle b{0}; - gdk_window_get_position(aWin, &b.x, &b.y); - b.width = gdk_window_get_width(aWin); - b.height = gdk_window_get_height(aWin); - return DesktopIntRect(b.x, b.y, b.width, b.height); - }; - - const auto toplevelBounds = GetBounds(GetToplevelGdkWindow()); - - mClientArea = GetBounds(mGdkWindow); - if (mClientArea.X() < 0 || mClientArea.Y() < 0 || mClientArea.Width() <= 1 || - mClientArea.Height() <= 1) { - // If we don't have gdkwindow bounds, assume we take the whole toplevel. - mClientArea = toplevelBounds; - } - - const bool decorated = - IsTopLevelWidget() && mSizeMode != nsSizeMode_Fullscreen && !mUndecorated; - if (!decorated) { - mClientMargin = {}; - } else if (aMayChangeCsdMargin) { + // This is a bit tricky. For fractional scaling, we want the size and + // position to be rounded independently, to match the compositor scale, + // which is not the behavior of LayoutDeviceIntRect::Round (which rounds the + // edges instead). See bug 1849092. + const LayoutDeviceIntRect roundedClientRect( + LayoutDeviceIntPoint::Round(clientRectRelativeToFrame.TopLeft()), + LayoutDeviceIntSize::Round(clientRectRelativeToFrame.Size())); mClientMargin = - DesktopIntRect(DesktopIntPoint(), toplevelBounds.Size()) - mClientArea; - mClientMargin.EnsureAtLeast(DesktopIntMargin()); + LayoutDeviceIntRect(LayoutDeviceIntPoint(), mBounds.Size()) - + roundedClientRect; + mClientMargin.EnsureAtLeast(LayoutDeviceIntMargin()); } else { // Assume the client margin remains the same. } -} -#endif - -void nsWindow::RecomputeBounds(bool aMayChangeCsdMargin, bool aScaleChange) { - LOG("RecomputeBounds() margin %d scale change %d", aMayChangeCsdMargin, - aScaleChange); - - mPendingBoundsChange = false; - mPendingBoundsChangeMayChangeCsdMargin = false; - - auto* toplevel = GetToplevelGdkWindow(); - if (!toplevel || mIsDestroyed) { - return; - } - - const auto oldClientArea = mClientArea; - const auto oldMargin = mClientMargin; - -#ifdef MOZ_X11 - if (GdkIsX11Display()) { - RecomputeBoundsX11(aMayChangeCsdMargin); - } -#endif -#ifdef MOZ_WAYLAND - if (GdkIsWaylandDisplay()) { - RecomputeBoundsWayland(aMayChangeCsdMargin); - } -#endif - -#ifdef MOZ_LOGGING - if (LOG_ENABLED()) { - if (mHasReceivedSizeAllocate) { - if (!(mClientArea == mReceivedClientArea)) { - LOG("Received and calculated client areas are different! received %s " - "calculated %s", - ToString(mReceivedClientArea).c_str(), - ToString(mClientArea).c_str()); - } - } - } -#endif if (IsPopup()) { - // Popup windows is not moved by the window manager, and so any change in + // Popup windows not be moved by the window manager, and so any change in // position is a result of our direction. // - // mClientArea has already been set in Move() or Resize(), and that is more + // mBounds has already been set in Move() or Resize(), and that is more // up-to-date than the position in the ConfigureNotify event if the event // is from an earlier window move. // - // NOTE(emilio): If we remove the early mClientArea change in Move() / + // NOTE(emilio): If we remove the early mBounds change in Move() / // Resize(), we should be able to remove this special case (but some tests // would need to be adjusted to deal with the async popup moves). - MOZ_ASSERT(mLastMoveRequest == oldClientArea.TopLeft()); - mClientArea.MoveTo(oldClientArea.TopLeft()); + MOZ_ASSERT(mLastMoveRequest == oldBounds.TopLeft()); + mBounds.MoveTo(oldBounds.TopLeft()); } // Sometimes the window manager gives us garbage sizes (way past the maximum // texture size) causing crashes if we don't enforce sane sizes here. - auto size = mClientArea.Size(); - if (SetSafeWindowSize(size)) { - mClientArea.SizeTo(size); - } + auto unconstrainedBounds = mBounds; + mBounds.SizeTo(GetSafeWindowSize(mBounds.Size())); - LOG("client area old: %s new -> %s", ToString(oldClientArea).c_str(), - ToString(mClientArea).c_str()); + LOG("bounds old: %s new -> %s (%s unconstrained, frame = %s, toplevel = %s)", + ToString(oldBounds).c_str(), ToString(mBounds).c_str(), + ToString(unconstrainedBounds).c_str(), ToString(frameBounds).c_str(), + ToString(toplevelBounds).c_str()); LOG("margin old: %s new -> %s", ToString(oldMargin).c_str(), ToString(mClientMargin).c_str()); @@ -3572,10 +3376,10 @@ void nsWindow::RecomputeBounds(bool aMayChangeCsdMargin, bool aScaleChange) { // We need to send WindowMoved even if only the client margins changed // so that BrowserParent picks up the new offsets. - const bool moved = aScaleChange || aMayChangeCsdMargin || - oldClientArea.TopLeft() != mClientArea.TopLeft(); - const bool resized = aScaleChange || aMayChangeCsdMargin || - oldClientArea.Size() != mClientArea.Size(); + const bool moved = + clientMarginsChanged || oldBounds.TopLeft() != mBounds.TopLeft(); + const bool resized = + clientMarginsChanged || oldBounds.Size() != mBounds.Size(); if (moved) { if (IsTopLevelWidget()) { @@ -3583,8 +3387,7 @@ void nsWindow::RecomputeBounds(bool aMayChangeCsdMargin, bool aScaleChange) { // from Cygwin/X (bug 672103). RollupAllMenus(); } - auto pos = ToLayoutDevicePixels(mClientArea.TopLeft()); - NotifyWindowMoved(pos.x, pos.y); + NotifyWindowMoved(mBounds.x, mBounds.y); } if (resized) { DispatchResized(); @@ -3882,11 +3685,7 @@ void nsWindow::SetIcon(const nsAString& aIconSpec) { } LayoutDeviceIntPoint nsWindow::WidgetToScreenOffset() { - return ToLayoutDevicePixels(mClientArea.TopLeft()); -} - -DesktopIntPoint nsWindow::WidgetToScreenOffsetUnscaled() { - return DesktopIntPoint(mClientArea.x, mClientArea.y); + return mBounds.TopLeft() + GetClientOffset(); } void nsWindow::CaptureRollupEvents(bool aDoCapture) { @@ -4323,20 +4122,20 @@ gboolean nsWindow::OnShellConfigureEvent(GdkEventConfigure* aEvent) { } void nsWindow::OnContainerSizeAllocate(GtkAllocation* aAllocation) { - LOG("nsWindow::OnContainerSizeAllocate [%d,%d] -> [%d x %d] scaled [%.2f] " - "[%.2f x %.2f]", + LOG("nsWindow::OnContainerSizeAllocate [%d,%d] -> [%d x %d] scaled[%.2f] " + "[%.2f x " + "%.2f]", aAllocation->x, aAllocation->y, aAllocation->width, aAllocation->height, FractionalScaleFactor(), aAllocation->width * FractionalScaleFactor(), aAllocation->height * FractionalScaleFactor()); mHasReceivedSizeAllocate = true; - mReceivedClientArea = DesktopIntRect(aAllocation->x, aAllocation->y, - aAllocation->width, aAllocation->height); - if (!mGdkWindow) { return; } + auto oldClientBounds = GetClientBounds(); + // Bounds will get updated on the main configure. // Gecko permits running nested event loops during processing of events, // GtkWindow callers of gtk_widget_size_allocate expect the signal handlers @@ -4349,19 +4148,21 @@ void nsWindow::OnContainerSizeAllocate(GtkAllocation* aAllocation) { // Invalidate the new part of the window now for the pending paint to // minimize background flashes (GDK does not do this for external // renewClientSizes of toplevels.) - if (mClientArea.Size() == mReceivedClientArea.Size()) { + LayoutDeviceIntRect newClientBounds = GdkRectToDevicePixels(*aAllocation); + if (oldClientBounds.Size() == newClientBounds.Size()) { return; } - if (mClientArea.width < mReceivedClientArea.width) { - GdkRectangle rect{mClientArea.width, 0, - mReceivedClientArea.width - mClientArea.width, - mReceivedClientArea.height}; + if (oldClientBounds.width < newClientBounds.width) { + GdkRectangle rect = DevicePixelsToGdkRectRoundOut(LayoutDeviceIntRect( + oldClientBounds.width, 0, newClientBounds.width - oldClientBounds.width, + newClientBounds.height)); gdk_window_invalidate_rect(mGdkWindow, &rect, FALSE); } - if (mClientArea.height < mReceivedClientArea.height) { - GdkRectangle rect{0, mClientArea.height, mReceivedClientArea.width, - mReceivedClientArea.height - mClientArea.height}; + if (oldClientBounds.height < newClientBounds.height) { + GdkRectangle rect = DevicePixelsToGdkRectRoundOut( + LayoutDeviceIntRect(0, oldClientBounds.height, newClientBounds.width, + newClientBounds.height - oldClientBounds.height)); gdk_window_invalidate_rect(mGdkWindow, &rect, FALSE); } } @@ -4380,7 +4181,7 @@ void nsWindow::SchedulePendingBounds(MayChangeCsdMargin aMayChangeCsdMargin) { void nsWindow::MaybeRecomputeBounds() { LOG("MaybeRecomputeBounds %d", mPendingBoundsChange); if (mPendingBoundsChange) { - RecomputeBounds(mPendingBoundsChangeMayChangeCsdMargin); + RecomputeBounds(MayChangeCsdMargin(mPendingBoundsChangeMayChangeCsdMargin)); } } @@ -4519,11 +4320,10 @@ Maybe<GdkWindowEdge> nsWindow::CheckResizerEdge( const int resizerHeight = 15 * GdkCeiledScaleFactor(); const int resizerWidth = resizerHeight * 4; - auto bounds = GetScreenBounds(); const int topDist = aPoint.y; const int leftDist = aPoint.x; - const int rightDist = bounds.width - aPoint.x; - const int bottomDist = bounds.height - aPoint.y; + const int rightDist = mBounds.width - aPoint.x; + const int bottomDist = mBounds.height - aPoint.y; // We can't emulate resize of North/West edges on Wayland as we can't shift // toplevel window. @@ -4590,7 +4390,7 @@ void nsWindow::EmulateResizeDrag(GdkEventMotion* aEvent) { auto oldPoint = mLastResizePoint; mLastResizePoint = newPoint; - auto size = GetScreenBoundsUnscaled().Size(); + GdkRectangle size = DevicePixelsToGdkSizeRoundUp(mBounds.Size()); size.width += newPoint.x - oldPoint.x; size.height += newPoint.y - oldPoint.y; @@ -5684,7 +5484,7 @@ void nsWindow::OnWindowStateEvent(GtkWidget* aWidget, }(); if (mSizeMode != oldSizeMode || mIsTiled != oldIsTiled) { - RecomputeBounds(/* MayChangeCsdMargin */ false); + RecomputeBounds(MayChangeCsdMargin::No); } if (mSizeMode != oldSizeMode) { if (mWidgetListener) { @@ -5780,7 +5580,7 @@ void nsWindow::RefreshScale(bool aRefreshScreen, bool aForceRefresh) { return; } - RecomputeBounds(/* MayChangeCsdMargin */ true, /* ScaleChanged*/ true); + RecomputeBounds(MayChangeCsdMargin::Yes); if (mWidgetListener) { if (PresShell* presShell = mWidgetListener->GetPresShell()) { @@ -6266,6 +6066,7 @@ void nsWindow::ConfigureCompositor() { nsresult nsWindow::Create(nsIWidget* aParent, const LayoutDeviceIntRect& aRect, const widget::InitData& aInitData) { MOZ_DIAGNOSTIC_ASSERT(aInitData.mWindowType != WindowType::Invisible); + #ifdef ACCESSIBILITY // Send a DBus message to check whether a11y is enabled a11y::PreInit(); @@ -6288,14 +6089,13 @@ nsresult nsWindow::Create(nsIWidget* aParent, const LayoutDeviceIntRect& aRect, LOG("nsWindow::Create()"); // save our bounds - LOG(" mBounds: x:%d y:%d w:%d h:%d\n", aRect.x, aRect.y, aRect.width, - aRect.height); + mBounds = aRect; + LOG(" mBounds: x:%d y:%d w:%d h:%d\n", mBounds.x, mBounds.y, mBounds.width, + mBounds.height); - mClientArea = ToDesktopPixels(aRect); - ConstrainSizeWithScale(&mClientArea.width, &mClientArea.height, - GetDesktopToDeviceScale().scale); - mLastSizeRequest = mClientArea.Size(); - mLastMoveRequest = mClientArea.TopLeft(); + ConstrainSize(&mBounds.width, &mBounds.height); + mLastSizeRequest = mBounds.Size(); + mLastMoveRequest = mBounds.TopLeft(); const bool popupNeedsAlphaVisual = mWindowType == WindowType::Popup && @@ -6306,6 +6106,7 @@ nsresult nsWindow::Create(nsIWidget* aParent, const LayoutDeviceIntRect& aRect, LOG(" parent window [%p]", parentnsWindow); MOZ_ASSERT_IF(mWindowType == WindowType::Popup, parentnsWindow); + if (mWindowType != WindowType::Dialog && mWindowType != WindowType::Popup && mWindowType != WindowType::TopLevel) { MOZ_ASSERT_UNREACHABLE("Unexpected eWindowType"); @@ -6385,10 +6186,10 @@ nsresult nsWindow::Create(nsIWidget* aParent, const LayoutDeviceIntRect& aRect, // actually placed the window somewhere. If no placement has taken // place, we just let the window manager Do The Right Thing. if (AreBoundsSane()) { - LOG(" nsWindow::Create() Initial resize to %d x %d\n", mClientArea.width, - mClientArea.height); - gtk_window_resize(GTK_WINDOW(mShell), mClientArea.width, - mClientArea.height); + GdkRectangle size = DevicePixelsToGdkSizeRoundUp(mBounds.Size()); + LOG(" nsWindow::Create() Initial resize to %d x %d\n", size.width, + size.height); + gtk_window_resize(GTK_WINDOW(mShell), size.width, size.height); } if (mIsPIPWindow) { LOG(" Is PIP window\n"); @@ -6457,7 +6258,8 @@ nsresult nsWindow::Create(nsIWidget* aParent, const LayoutDeviceIntRect& aRect, if (GdkIsX11Display()) { NativeMoveResize(/* move */ true, /* resize */ false); } else if (AreBoundsSane()) { - mPopupPosition = {mClientArea.x, mClientArea.y}; + GdkRectangle rect = DevicePixelsToGdkRectRoundOut(mBounds); + mPopupPosition = {rect.x, rect.y}; } } else { // must be WindowType::TopLevel mGtkWindowRoleName = "Toplevel"; @@ -6482,7 +6284,7 @@ nsresult nsWindow::Create(nsIWidget* aParent, const LayoutDeviceIntRect& aRect, mSurface = new WaylandSurface( parentnsWindow ? MOZ_WL_SURFACE(parentnsWindow->GetMozContainer()) : nullptr, - gfx::IntSize(ToLayoutDevicePixels(mLastSizeRequest).ToUnknownSize())); + gfx::IntSize(mLastSizeRequest.width, mLastSizeRequest.height)); } container = moz_container_new(this, mSurface); #else @@ -6817,28 +6619,21 @@ nsAutoCString nsWindow::GetDebugTag() const { } void nsWindow::NativeMoveResize(bool aMoved, bool aResized) { - const DesktopIntRect frameRect(mLastMoveRequest, mLastSizeRequest); - - // Window size is calculated without decorations, Gtk adds decorations - // size to our request at gtk_window_resize(). + const LayoutDeviceIntRect frameRect(mLastMoveRequest, mLastSizeRequest); GdkRectangle moveResizeRect = [&] { auto cr = frameRect; - // In CSD mode gtk_window_move() / gtk_window_resize() expects coordinates - // without CSD frame so remove it. cr.Deflate(mClientMargin); - // SSD mode expects coordinates with decorations (outer frame) - // so put the margin offset back. + // gtk_window_move will undo the csd offset properly on its own, but + // nothing else, so do it manually if not drawing to the CSD titlebar. if (!ToplevelUsesCSD()) { - cr -= DesktopIntPoint(mClientMargin.left, mClientMargin.top); + cr -= GetClientOffset(); } - return GdkRectangle{cr.x, cr.y, cr.width, cr.height}; + return DevicePixelsToGdkRectRoundOut(cr); }(); - LOG("nsWindow::NativeMoveResize mLastMoveRequest [%d,%d] mClientMargin " - "[%d,%d] move %d resize %d to [%d,%d] -> [%d x %d]\n", - int(mLastMoveRequest.x), int(mLastMoveRequest.y), int(mClientMargin.left), - int(mClientMargin.top), aMoved, aResized, moveResizeRect.x, - moveResizeRect.y, moveResizeRect.width, moveResizeRect.height); + LOG("nsWindow::NativeMoveResize move %d resize %d to %d,%d -> %d x %d\n", + aMoved, aResized, moveResizeRect.x, moveResizeRect.y, + moveResizeRect.width, moveResizeRect.height); if (aResized && !AreBoundsSane()) { LOG(" bounds are insane, hidding the window"); @@ -6864,11 +6659,10 @@ void nsWindow::NativeMoveResize(bool aMoved, bool aResized) { // and move it when it's shown. if (aMoved && GdkIsX11Display() && IsPopup() && !gtk_widget_get_visible(GTK_WIDGET(mShell))) { + LOG(" store position of hidden popup window"); mHiddenPopupPositioned = true; mPopupPosition = {moveResizeRect.x, moveResizeRect.y}; - mClientArea.MoveTo(mLastMoveRequest); - LOG(" store position of hidden popup window [%d, %d]", mPopupPosition.x, - mPopupPosition.y); + mBounds.MoveTo(mLastMoveRequest); } if (IsWaylandPopup()) { @@ -6913,17 +6707,16 @@ void nsWindow::NativeMoveResize(bool aMoved, bool aResized) { // honored: "If the configure request has not changed, we don't ever resend // it, because it could mean fighting the user or window manager." // https://gitlab.gnome.org/GNOME/gtk/-/blob/3.24.31/gtk/gtkwindow.c#L9782 - // So we don't update mClientArea until OnContainerSizeAllocate() when we know + // So we don't update mBounds until OnContainerSizeAllocate() when we know // the request is granted. bool isOrWillBeVisible = mHasReceivedSizeAllocate || mNeedsShow || mIsShown; if (!isOrWillBeVisible || IsPopup()) { if (aResized) { - mClientArea.SizeTo(mLastSizeRequest); + mBounds.SizeTo(mLastSizeRequest); } if (aMoved) { - mClientArea.MoveTo(mLastMoveRequest); - auto pos = ToLayoutDevicePixels(mLastMoveRequest); - NotifyWindowMoved(pos.x, pos.y); + mBounds.MoveTo(mLastMoveRequest); + NotifyWindowMoved(mBounds.x, mBounds.y); } if (aResized) { DispatchResized(); @@ -7015,8 +6808,7 @@ void nsWindow::NativeShow(bool aAction) { #endif } if (mHiddenPopupPositioned && IsPopup()) { - LOG(" re-position hidden popup window [%d, %d]", mPopupPosition.x, - mPopupPosition.y); + LOG(" re-position hidden popup window"); gtk_window_move(GTK_WINDOW(mShell), mPopupPosition.x, mPopupPosition.y); mHiddenPopupPositioned = false; } @@ -7082,38 +6874,26 @@ void nsWindow::SetHasMappedToplevel(bool aState) { } } -bool nsWindow::SetSafeWindowSize(LayoutDeviceIntSize& aSize) { +LayoutDeviceIntSize nsWindow::GetSafeWindowSize(LayoutDeviceIntSize aSize) { // The X protocol uses CARD32 for window sizes, but the server (1.11.3) // reads it as CARD16. Sizes of pixmaps, used for drawing, are (unsigned) // CARD16 in the protocol, but the server's ProcCreatePixmap returns // BadAlloc if dimensions cannot be represented by signed shorts. // Because we are creating Cairo surfaces to represent window buffers, // we also must ensure that the window can fit in a Cairo surface. - // Keep some reserve for window margin/decorations. - bool changed = false; - int32_t maxSize = 32000; + LayoutDeviceIntSize result = aSize; + int32_t maxSize = 32767; if (mWindowRenderer && mWindowRenderer->AsKnowsCompositor()) { maxSize = std::min( maxSize, mWindowRenderer->AsKnowsCompositor()->GetMaxTextureSize()); } - if (aSize.width > maxSize) { - aSize.width = maxSize; - changed = true; - } - if (aSize.height > maxSize) { - aSize.height = maxSize; - changed = true; + if (result.width > maxSize) { + result.width = maxSize; } - return changed; -} - -bool nsWindow::SetSafeWindowSize(DesktopIntSize& aSize) { - auto layoutDeviceSize = ToLayoutDevicePixels(aSize); - auto ret = SetSafeWindowSize(layoutDeviceSize); - if (ret) { - aSize = ToDesktopPixels(layoutDeviceSize); + if (result.height > maxSize) { + result.height = maxSize; } - return ret; + return result; } void nsWindow::SetTransparencyMode(TransparencyMode aMode) { @@ -7180,10 +6960,10 @@ void nsWindow::SetInputRegion(const InputRegion& aInputRegion) { if (aInputRegion.mFullyTransparent) { region = cairo_region_create_rectangle(&rect); } else if (aInputRegion.mMargin != 0) { - DesktopIntRect inputRegion(DesktopIntPoint(), mLastSizeRequest); + LayoutDeviceIntRect inputRegion(LayoutDeviceIntPoint(), mLastSizeRequest); inputRegion.Deflate(aInputRegion.mMargin); - rect = {inputRegion.x, inputRegion.y, inputRegion.width, - inputRegion.height}; + GdkRectangle gdkRect = DevicePixelsToGdkRectRoundOut(inputRegion); + rect = {gdkRect.x, gdkRect.y, gdkRect.width, gdkRect.height}; region = cairo_region_create_rectangle(&rect); } @@ -7472,9 +7252,11 @@ already_AddRefed<widget::Screen> nsWindow::GetWidgetScreen() { } } + // GetScreenBounds() is slow for the GTK port so we override and use + // mBounds directly. ScreenManager& screenManager = ScreenManager::GetSingleton(); - DesktopIntRect deskBounds = - RoundedToInt(GetScreenBounds() / GetDesktopToDeviceScale()); + LayoutDeviceIntRect bounds = mBounds; + DesktopIntRect deskBounds = RoundedToInt(bounds / GetDesktopToDeviceScale()); return screenManager.ScreenForRect(deskBounds); } @@ -9181,8 +8963,10 @@ void nsWindow::SetCustomTitlebar(bool aState) { g_object_set_data(G_OBJECT(GetToplevelGdkWindow()), "nsWindow", this); if (AreBoundsSane()) { - gtk_window_resize(GTK_WINDOW(mShell), mClientArea.width, - mClientArea.height); + GdkRectangle size = + DevicePixelsToGdkSizeRoundUp(GetClientBounds().Size()); + LOG(" resize to %d x %d\n", size.width, size.height); + gtk_window_resize(GTK_WINDOW(mShell), size.width, size.height); } if (visible) { @@ -9245,9 +9029,9 @@ double nsWindow::FractionalScaleFactor() { return ScreenHelperGTK::GetGTKMonitorFractionalScaleFactor(); } -gint nsWindow::DevicePixelsToGdkCoordRound(int aPixels) { +gint nsWindow::DevicePixelsToGdkCoordRoundUp(int aPixels) { double scale = FractionalScaleFactor(); - return int(round(aPixels / scale)); + return ceil(aPixels / scale); } gint nsWindow::DevicePixelsToGdkCoordRoundDown(int aPixels) { @@ -9281,6 +9065,18 @@ GdkRectangle nsWindow::DevicePixelsToGdkRectRoundIn( return {x, y, std::max(right - x, 0), std::max(bottom - y, 0)}; } +GdkRectangle nsWindow::DevicePixelsToGdkSizeRoundUp( + const LayoutDeviceIntSize& aSize) { + double scale = FractionalScaleFactor(); + gint width = ceil(aSize.width / scale); + gint height = ceil(aSize.height / scale); + return {0, 0, width, height}; +} + +int nsWindow::GdkCoordToDevicePixels(gint aCoord) { + return (int)(aCoord * FractionalScaleFactor()); +} + LayoutDeviceIntPoint nsWindow::GdkEventCoordsToDevicePixels(gdouble aX, gdouble aY) { double scale = FractionalScaleFactor(); @@ -9293,6 +9089,26 @@ LayoutDeviceIntPoint nsWindow::GdkPointToDevicePixels(const GdkPoint& aPoint) { (float)(aPoint.y * scale)); } +LayoutDeviceIntMargin nsWindow::GtkBorderToDevicePixels( + const GtkBorder& aBorder) { + double scale = FractionalScaleFactor(); + return LayoutDeviceIntMargin{ + (int)(aBorder.top * scale), (int)(aBorder.right * scale), + (int)(aBorder.bottom * scale), (int)(aBorder.left * scale)}; +} + +LayoutDeviceIntRect nsWindow::GdkRectToDevicePixels(const GdkRectangle& aRect) { + return LayoutDeviceIntRect::Round(GdkRectToFloatDevicePixels(aRect)); +} + +LayoutDeviceRect nsWindow::GdkRectToFloatDevicePixels( + const GdkRectangle& aRect) { + double scale = FractionalScaleFactor(); + return LayoutDeviceRect((float)(aRect.x * scale), (float)(aRect.y * scale), + (float)(aRect.width * scale), + (float)(aRect.height * scale)); +} + nsresult nsWindow::SynthesizeNativeMouseEvent( LayoutDeviceIntPoint aPoint, NativeMouseMessage aNativeMessage, MouseButton aButton, nsIWidget::Modifiers aModifierFlags, @@ -9930,8 +9746,8 @@ void nsWindow::LockAspectRatio(bool aShouldLock) { } if (aShouldLock) { - float width = mLastSizeRequest.width; - float height = mLastSizeRequest.height; + float width = DevicePixelsToGdkCoordRoundDown(mLastSizeRequest.width); + float height = DevicePixelsToGdkCoordRoundDown(mLastSizeRequest.height); mAspectRatio = width / height; LOG("nsWindow::LockAspectRatio() width %.2f height %.2f aspect %.2f", width, diff --git a/widget/gtk/nsWindow.h b/widget/gtk/nsWindow.h @@ -203,30 +203,25 @@ class nsWindow final : public nsIWidget { void MoveToWorkspace(const nsAString& workspaceID) override; void Enable(bool aState) override; void SetFocus(Raise, mozilla::dom::CallerType aCallerType) override; - LayoutDeviceIntRect GetBounds() override; LayoutDeviceIntRect GetScreenBounds() override; - DesktopIntRect GetScreenBoundsUnscaled(); LayoutDeviceIntRect GetClientBounds() override; + LayoutDeviceIntRect GetBounds() override { return mBounds; } LayoutDeviceIntSize GetClientSize() override; - LayoutDeviceIntPoint GetClientOffset() override; + LayoutDeviceIntPoint GetClientOffset() override { + return LayoutDeviceIntPoint(mClientMargin.left, mClientMargin.top); + } GdkPoint GetCsdOffsetInGdkCoords(); LayoutDeviceIntPoint GetScreenEdgeSlop() override; nsresult GetRestoredBounds(LayoutDeviceIntRect&) override; bool PersistClientBounds() const override { return true; } LayoutDeviceIntMargin NormalSizeModeClientToWindowMargin() override; - bool ConstrainSizeWithScale(int* aWidth, int* aHeight, double aScale); + void ConstrainSize(int* aWidth, int* aHeight) override; // Recomputes the bounds according to our current window position. Dispatches // move / resizes as needed. - void RecomputeBounds(bool aMayChangeCsdMargin, bool aScaleChange = false); -#ifdef MOZ_X11 - void RecomputeBoundsX11(bool aMayChangeCsdMargin); -#endif -#ifdef MOZ_WAYLAND - void RecomputeBoundsWayland(bool aMayChangeCsdMargin); -#endif enum class MayChangeCsdMargin : bool { No = false, Yes }; + void RecomputeBounds(MayChangeCsdMargin); void SchedulePendingBounds(MayChangeCsdMargin); void MaybeRecomputeBounds(); @@ -238,7 +233,6 @@ class nsWindow final : public nsIWidget { void SetWindowClass(const nsAString& xulWinType, const nsAString& xulWinClass, const nsAString& xulWinName) override; LayoutDeviceIntPoint WidgetToScreenOffset() override; - DesktopIntPoint WidgetToScreenOffsetUnscaled(); void CaptureRollupEvents(bool aDoCapture) override; [[nodiscard]] nsresult GetAttention(int32_t aCycleCount) override; bool HasPendingInputEvent() override; @@ -429,25 +423,21 @@ class nsWindow final : public nsIWidget { gint GdkCeiledScaleFactor(); double FractionalScaleFactor(); - LayoutDeviceIntPoint ToLayoutDevicePixels(const DesktopIntPoint&); - LayoutDeviceIntSize ToLayoutDevicePixels(const DesktopIntSize&); - LayoutDeviceIntRect ToLayoutDevicePixels(const DesktopIntRect&); - LayoutDeviceIntMargin ToLayoutDevicePixels(const DesktopIntMargin&); - DesktopIntSize ToDesktopPixels(const LayoutDeviceIntSize&); - DesktopIntRect ToDesktopPixels(const LayoutDeviceIntRect&); - DesktopIntPoint ToDesktopPixels(const LayoutDeviceIntPoint&); - // To GDK - gint DevicePixelsToGdkCoordRound(int); - + gint DevicePixelsToGdkCoordRoundUp(int); gint DevicePixelsToGdkCoordRoundDown(int); GdkPoint DevicePixelsToGdkPointRoundDown(const LayoutDeviceIntPoint&); + GdkRectangle DevicePixelsToGdkSizeRoundUp(const LayoutDeviceIntSize&); GdkRectangle DevicePixelsToGdkRectRoundOut(const LayoutDeviceIntRect&); GdkRectangle DevicePixelsToGdkRectRoundIn(const LayoutDeviceIntRect&); // From GDK + int GdkCoordToDevicePixels(gint); LayoutDeviceIntPoint GdkPointToDevicePixels(const GdkPoint&); LayoutDeviceIntPoint GdkEventCoordsToDevicePixels(gdouble aX, gdouble aY); + LayoutDeviceIntRect GdkRectToDevicePixels(const GdkRectangle&); + LayoutDeviceIntMargin GtkBorderToDevicePixels(const GtkBorder&); + LayoutDeviceRect GdkRectToFloatDevicePixels(const GdkRectangle&); bool WidgetTypeSupportsAcceleration() override; bool WidgetTypeSupportsNativeCompositing() override; @@ -496,7 +486,9 @@ class nsWindow final : public nsIWidget { const LayoutDeviceIntPoint& aLockCenter) override; void LockNativePointer() override; void UnlockNativePointer() override; - LayoutDeviceIntSize GetMoveToRectPopupSize() override; + LayoutDeviceIntSize GetMoveToRectPopupSize() const override { + return mMoveToRectPopupSize; + }; #endif void ResumeCompositorImpl(); @@ -536,9 +528,7 @@ class nsWindow final : public nsIWidget { void NativeShow(bool aAction); void SetHasMappedToplevel(bool aState); - - bool SetSafeWindowSize(LayoutDeviceIntSize& aSize); - bool SetSafeWindowSize(DesktopIntSize& aSize); + LayoutDeviceIntSize GetSafeWindowSize(LayoutDeviceIntSize aSize); void DispatchContextMenuEventFromMouseEvent( uint16_t domButton, GdkEventButton* aEvent, @@ -575,8 +565,8 @@ class nsWindow final : public nsIWidget { nsWindow* GetTransientForWindowIfPopup(); bool IsHandlingTouchSequence(GdkEventSequence* aSequence); - void ResizeInt(const mozilla::Maybe<DesktopIntPoint>& aMove, - DesktopIntSize aSize); + void ResizeInt(const mozilla::Maybe<LayoutDeviceIntPoint>& aMove, + LayoutDeviceIntSize aSize); void NativeMoveResizeWaylandPopup(bool aMove, bool aResize); // Returns a window edge if the given point (in device pixels) is within a @@ -624,41 +614,18 @@ class nsWindow final : public nsIWidget { constexpr static const int sNoScale = -1; int mCeiledScaleFactor = sNoScale; - // Client area received by OnContainerSizeAllocate(). - // We don't use it directly but as a reference. - DesktopIntRect mReceivedClientArea{}; - - // The size requested, which might not be reflected in mClientArea. Used in + // The size requested, which might not be reflected in mBounds. Used in // WaylandPopupSetDirectPosition() to remember intended size for popup // positioning, in LockAspect() to remember the intended aspect ratio, and // to remember a size requested while waiting for moved-to-rect when - // OnSizeAllocate() might change mClientArea.Size(). - // All these values are in unscaled (Gdk) coordinates. - DesktopIntSize mLastSizeRequest; + // OnSizeAllocate() might change mBounds.Size(). + LayoutDeviceIntSize mLastSizeRequest; // 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{}; + LayoutDeviceIntPoint mLastMoveRequest; + // Margin from mBounds to the client rect (including CSD decorations). + LayoutDeviceIntMargin mClientMargin; + // Bounds of the window, as in GetBounds(). + LayoutDeviceIntRect mBounds; // This field omits duplicate scroll events caused by GNOME bug 726878. guint32 mLastScrollEventTime = GDK_CURRENT_TIME; @@ -968,7 +935,7 @@ class nsWindow final : public nsIWidget { // When popup is resized by Gtk by move-to-rect callback, // we store final popup size here. Then we use mMoveToRectPopupSize size // in following popup operations unless mLayoutPopupSizeCleared is set. - DesktopIntSize mMoveToRectPopupSize; + LayoutDeviceIntSize mMoveToRectPopupSize; #ifdef MOZ_ENABLE_DBUS RefPtr<mozilla::widget::DBusMenuBar> mDBusMenuBar; diff --git a/widget/nsBaseWidget.h b/widget/nsBaseWidget.h diff --git a/widget/nsIWidget.h b/widget/nsIWidget.h @@ -446,8 +446,6 @@ class nsIWidget : public nsSupportsWeakReference { typedef mozilla::DesktopIntRect DesktopIntRect; typedef mozilla::DesktopPoint DesktopPoint; typedef mozilla::DesktopIntPoint DesktopIntPoint; - typedef mozilla::DesktopIntSize DesktopIntSize; - typedef mozilla::DesktopIntMargin DesktopIntMargin; typedef mozilla::DesktopRect DesktopRect; typedef mozilla::DesktopSize DesktopSize; typedef mozilla::CSSPoint CSSPoint; @@ -1923,7 +1921,7 @@ class nsIWidget : public nsSupportsWeakReference { /** * Wayland specific routines. */ - virtual LayoutDeviceIntSize GetMoveToRectPopupSize() { + virtual LayoutDeviceIntSize GetMoveToRectPopupSize() const { NS_WARNING("GetLayoutPopupRect implemented only for wayland"); return LayoutDeviceIntSize(); }