tor-browser

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

commit 6cb5ce2f04df8f791ad18b6cbe1f6a914697a773
parent 915de2a8936abd806de54f8052d40c0a988af314
Author: stransky <stransky@redhat.com>
Date:   Thu, 20 Nov 2025 10:21:49 +0000

Bug 1998657 [Wayland] Create EGLWindow over offscreen wl_surface and make it always available r=emilio

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

Diffstat:
Mwidget/gtk/MozContainerWayland.cpp | 19-------------------
Mwidget/gtk/MozContainerWayland.h | 4----
Mwidget/gtk/nsWindow.cpp | 164+++++++++++++++++++++----------------------------------------------------------
Mwidget/gtk/nsWindow.h | 6++----
4 files changed, 45 insertions(+), 148 deletions(-)

diff --git a/widget/gtk/MozContainerWayland.cpp b/widget/gtk/MozContainerWayland.cpp @@ -262,25 +262,6 @@ static bool moz_container_wayland_ensure_surface(MozContainer* container, return true; } -struct wl_egl_window* moz_container_wayland_get_egl_window( - MozContainer* container) { - LOGCONTAINER("%s [%p] mapped %d eglwindow %d", __FUNCTION__, - (void*)moz_container_get_nsWindow(container), - MOZ_WL_SURFACE(container)->IsMapped(), - MOZ_WL_SURFACE(container)->HasEGLWindow()); - - if (!MOZ_WL_SURFACE(container)->IsMapped()) { - return nullptr; - } - - // TODO: Get size from bounds instead of GdkWindow? - // We may be in rendering/compositor thread here. - GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(container)); - DesktopIntSize size(gdk_window_get_width(window), - gdk_window_get_height(window)); - return MOZ_WL_SURFACE(container)->GetEGLWindow(size); -} - double moz_container_wayland_get_scale(MozContainer* container) { nsWindow* window = moz_container_get_nsWindow(container); return window ? window->FractionalScaleFactor() : 1.0; diff --git a/widget/gtk/MozContainerWayland.h b/widget/gtk/MozContainerWayland.h @@ -49,10 +49,6 @@ void moz_container_wayland_map(GtkWidget*); gboolean moz_container_wayland_map_event(GtkWidget*, GdkEventAny*); void moz_container_wayland_size_allocate(GtkWidget*, GtkAllocation*); void moz_container_wayland_unmap(GtkWidget*); - -struct wl_egl_window* moz_container_wayland_get_egl_window( - MozContainer* container); - wl_surface* moz_gtk_widget_get_wl_surface(GtkWidget* aWidget); double moz_container_wayland_get_scale(MozContainer* container); diff --git a/widget/gtk/nsWindow.cpp b/widget/gtk/nsWindow.cpp @@ -411,8 +411,7 @@ static void GtkWindowSetTransientFor(GtkWindow* aWindow, GtkWindow* aParent) { } nsWindow::nsWindow() - : mWindowVisibilityMutex("nsWindow::mWindowVisibilityMutex"), - mIsMapped(false), + : mIsMapped(false), mIsDestroyed(false), mIsShown(false), mNeedsShow(false), @@ -719,6 +718,14 @@ void nsWindow::Destroy() { gtk_accessible_set_widget(GTK_ACCESSIBLE(ac), nullptr); } + // Owned by WaylandSurface or it's X11 ID, + // just drop the reference here. + mEGLWindow = nullptr; + + // mGdkWindow is owned by mContainer, will be deleted with mShell/mContainer. + g_object_set_data(G_OBJECT(mGdkWindow), "nsWindow", nullptr); + mGdkWindow = nullptr; + gtk_widget_destroy(mShell); mShell = nullptr; mContainer = nullptr; @@ -726,9 +733,6 @@ void nsWindow::Destroy() { mSurface = nullptr; #endif - MOZ_ASSERT(!mGdkWindow, - "mGdkWindow should be NULL when mContainer is destroyed"); - #ifdef ACCESSIBILITY if (mRootAccessible) { mRootAccessible = nullptr; @@ -3740,41 +3744,8 @@ void* nsWindow::GetNativeData(uint32_t aDataType) { } case NS_NATIVE_OPENGL_CONTEXT: return nullptr; - case NS_NATIVE_EGL_WINDOW: { - // On X11 we call it: - // 1) If window is mapped on OnMap() by nsWindow::ResumeCompositorImpl(), - // new EGLSurface/XWindow is created. - // 2) If window is hidden on OnUnmap(), we replace EGLSurface/XWindow - // by offline surface and release XWindow. - - // On Wayland it: - // 1) If window is mapped on OnMap(), we request frame callback - // at MozContainer. If we get frame callback at MozContainer, - // nsWindow::ResumeCompositorImpl() is called from it - // and EGLSurface/wl_surface is created. - // 2) If window is hidden on OnUnmap(), we replace EGLSurface/wl_surface - // by offline surface and release XWindow. - - // If nsWindow is already destroyed, don't try to get EGL window at all, - // we're going to be deleted anyway. - MutexAutoLock lock(mWindowVisibilityMutex); - void* eglWindow = nullptr; - if (mIsMapped && !mIsDestroyed) { -#ifdef MOZ_X11 - if (GdkIsX11Display()) { - eglWindow = (void*)GDK_WINDOW_XID(mGdkWindow); - } -#endif -#ifdef MOZ_WAYLAND - if (GdkIsWaylandDisplay()) { - eglWindow = moz_container_wayland_get_egl_window(mContainer); - } -#endif - } - LOG("Get NS_NATIVE_EGL_WINDOW mGdkWindow %p returned eglWindow %p", - mGdkWindow, eglWindow); - return eglWindow; - } + case NS_NATIVE_EGL_WINDOW: + return mIsDestroyed ? nullptr : mEGLWindow; default: NS_WARNING("nsWindow::GetNativeData called with bad value"); return nullptr; @@ -4103,8 +4074,8 @@ gboolean nsWindow::OnExposeEvent(cairo_t* cr) { } // Windows that are not visible will be painted after they become visible. - if (!mGdkWindow || !mHasMappedToplevel) { - LOG("quit, !mGdkWindow || !mHasMappedToplevel"); + if (!mHasMappedToplevel) { + LOG("quit, !mHasMappedToplevel"); return FALSE; } @@ -4138,8 +4109,8 @@ gboolean nsWindow::OnExposeEvent(cairo_t* cr) { // If the window has been destroyed during the will paint notification, // there is nothing left to do. - if (!mGdkWindow || mIsDestroyed) { - LOG("quit, !mGdkWindow || mIsDestroyed"); + if (mIsDestroyed) { + LOG("quit, mIsDestroyed"); return TRUE; } @@ -4292,7 +4263,7 @@ gboolean nsWindow::OnShellConfigureEvent(GdkEventConfigure* aEvent) { // Don't fire configure event for scale changes, we handle that // OnScaleEvent event. Skip that for toplevel windows only. - if (mGdkWindow && IsTopLevelWidget() && + if (IsTopLevelWidget() && mCeiledScaleFactor != gdk_window_get_scale_factor(mGdkWindow)) { LOG(" scale factor changed to %d, return early", gdk_window_get_scale_factor(mGdkWindow)); @@ -4318,10 +4289,6 @@ void nsWindow::OnContainerSizeAllocate(GtkAllocation* aAllocation) { mReceivedClientArea = DesktopIntRect(aAllocation->x, aAllocation->y, aAllocation->width, aAllocation->height); - if (!mGdkWindow) { - return; - } - // 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 @@ -4592,10 +4559,6 @@ void nsWindow::EmulateResizeDrag(GdkEventMotion* aEvent) { void nsWindow::OnMotionNotifyEvent(GdkEventMotion* aEvent) { mLastMouseCoordinates.Set(aEvent); - if (!mGdkWindow) { - return; - } - // Emulate gdk_window_begin_resize_drag() for windows // with fixed aspect ratio on Wayland. if (mAspectResizer && mAspectRatio != 0.0f) { @@ -4612,10 +4575,8 @@ void nsWindow::OnMotionNotifyEvent(GdkEventMotion* aEvent) { GdkWindow* dragWindow = nullptr; // find the top-level window - if (mGdkWindow) { - dragWindow = gdk_window_get_toplevel(mGdkWindow); - MOZ_ASSERT(dragWindow, "gdk_window_get_toplevel should not return null"); - } + dragWindow = gdk_window_get_toplevel(mGdkWindow); + MOZ_ASSERT(dragWindow, "gdk_window_get_toplevel should not return null"); #ifdef MOZ_X11 if (dragWindow && GdkIsX11Display()) { @@ -5050,10 +5011,6 @@ void nsWindow::OnButtonReleaseEvent(GdkEventButton* aEvent) { SetLastPointerDownEvent(nullptr); mLastMouseCoordinates.Set(aEvent); - if (!mGdkWindow) { - return; - } - if (mAspectResizer) { mAspectResizer = Nothing(); return; @@ -5231,7 +5188,7 @@ WidgetEventTime nsWindow::GetWidgetEventTime(guint32 aEventTime) { } TimeStamp nsWindow::GetEventTimeStamp(guint32 aEventTime) { - if (MOZ_UNLIKELY(!mGdkWindow)) { + if (MOZ_UNLIKELY(mIsDestroyed)) { // nsWindow has been Destroy()ed. return TimeStamp::Now(); } @@ -5267,7 +5224,6 @@ TimeStamp nsWindow::GetEventTimeStamp(guint32 aEventTime) { #ifdef MOZ_X11 mozilla::CurrentX11TimeGetter* nsWindow::GetCurrentTimeGetter() { - MOZ_ASSERT(mGdkWindow, "Expected mGdkWindow to be set"); if (MOZ_UNLIKELY(!mCurrentTimeGetter)) { mCurrentTimeGetter = MakeUnique<CurrentX11TimeGetter>(mGdkWindow); } @@ -5721,7 +5677,7 @@ void nsWindow::OnCompositedChanged() { // Let's follow the working scenario for now to avoid complexity // and maybe fix that later. void nsWindow::OnScaleEvent() { - if (!mGdkWindow || !IsTopLevelWidget()) { + if (!IsTopLevelWidget()) { return; } @@ -5739,7 +5695,6 @@ void nsWindow::RefreshScale(bool aRefreshScreen, bool aForceRefresh) { LOG("nsWindow::RefreshScale() GdkWindow scale %d refresh %d", gdk_window_get_scale_factor(mGdkWindow), aRefreshScreen); - MOZ_DIAGNOSTIC_ASSERT(mIsMapped && mGdkWindow); int ceiledScale = gdk_window_get_scale_factor(mGdkWindow); const bool scaleChanged = aForceRefresh || GdkCeiledScaleFactor() != ceiledScale; @@ -5784,7 +5739,7 @@ void nsWindow::SetDragPopupSurface( mDragPopupSurface = aDragPopupSurface; mDragPopupSurfaceRegion = aInvalidRegion; - if (mGdkWindow) { + if (!mIsDestroyed) { gdk_window_invalidate_rect(mGdkWindow, nullptr, false); } } @@ -6195,28 +6150,17 @@ nsCString nsWindow::GetPopupTypeName() { Window nsWindow::GetX11Window() { #ifdef MOZ_X11 if (GdkIsX11Display()) { - return mGdkWindow ? gdk_x11_window_get_xid(mGdkWindow) : X11None; + return gdk_x11_window_get_xid(mGdkWindow); } #endif return (Window) nullptr; } -void nsWindow::EnsureGdkWindow() { - MOZ_DIAGNOSTIC_ASSERT(mIsMapped); - if (!mGdkWindow) { - mGdkWindow = gtk_widget_get_window(GTK_WIDGET(mContainer)); - g_object_set_data(G_OBJECT(mGdkWindow), "nsWindow", this); - } -} - void nsWindow::ConfigureCompositor() { - MOZ_DIAGNOSTIC_ASSERT(mIsMapped); - LOG("nsWindow::ConfigureCompositor()"); - if (mIsDestroyed || !mIsMapped) { - LOG(" quit, mIsDestroyed = %d mIsMapped = %d", !!mIsDestroyed, - !!mIsMapped); + if (mIsDestroyed) { + LOG(" quit, mIsDestroyed = %d", !!mIsDestroyed); return; } // Compositor will be resumed at nsWindow::SetCompositorWidgetDelegate(). @@ -6479,6 +6423,24 @@ nsresult nsWindow::Create(nsIWidget* aParent, const LayoutDeviceIntRect& aRect, gtk_widget_realize(container); + mGdkWindow = gtk_widget_get_window(GTK_WIDGET(mContainer)); + g_object_set_data(G_OBJECT(mGdkWindow), "nsWindow", this); + +#ifdef MOZ_X11 + if (GdkIsX11Display()) { + mEGLWindow = (void*)GDK_WINDOW_XID(mGdkWindow); + } +#endif +#ifdef MOZ_WAYLAND + if (GdkIsWaylandDisplay() && mIsAccelerated) { + mEGLWindow = MOZ_WL_SURFACE(container)->GetEGLWindow(mClientArea.Size()); + } +#endif + if (mEGLWindow) { + LOG("Get NS_NATIVE_EGL_WINDOW mGdkWindow %p returned mEGLWindow %p", + mGdkWindow, mEGLWindow); + } + // make sure this is the focus widget in the container gtk_widget_show(container); @@ -9921,7 +9883,7 @@ bool nsWindow::SetEGLNativeWindowSize( // SetEGLNativeWindowSize() is Wayland only call. MOZ_ASSERT(GdkIsWaylandDisplay()); - if (!mIsMapped) { + if (mIsDestroyed) { return true; } @@ -9958,10 +9920,8 @@ void nsWindow::OnMap() { MaybeCreatePipResources(); { - MutexAutoLock lock(mWindowVisibilityMutex); mIsMapped = true; - EnsureGdkWindow(); RefreshScale(/* aRefreshScreen */ false); if (mIsAlert) { @@ -10013,7 +9973,6 @@ void nsWindow::OnUnmap() { ClearPipResources(); { - MutexAutoLock lock(mWindowVisibilityMutex); mIsMapped = false; mHasReceivedSizeAllocate = false; @@ -10027,23 +9986,8 @@ void nsWindow::OnUnmap() { } } - if (mGdkWindow) { - g_object_set_data(G_OBJECT(mGdkWindow), "nsWindow", nullptr); - mGdkWindow = nullptr; - } - // Reset scale for hidden windows mCeiledScaleFactor = sNoScale; - - // Clear resources (mainly XWindow) stored at GtkCompositorWidget. - // It makes sure we don't paint to it when nsWindow becomes hiden/deleted - // and XWindow is released. - if (mCompositorWidgetDelegate) { - mCompositorWidgetDelegate->CleanupResources(); - } - - // Clear nsWindow resources used for old (in-thread) rendering. - mSurfaceProvider.CleanupResources(); } // Until bug 1654938 is fixed we delete layer manager for hidden popups, @@ -10054,28 +9998,6 @@ void nsWindow::OnUnmap() { // see bug 1958695. if (mWindowType == WindowType::Popup && !mPopupTemporaryHidden) { DestroyLayerManager(); - } else { - // Widget is backed by OpenGL EGLSurface created over wl_surface/XWindow. - // - // RenderCompositorEGL::Resume() deletes recent EGLSurface, - // calls nsWindow::GetNativeData(NS_NATIVE_EGL_WINDOW) from compositor - // thread to get new native rendering surface. - // - // For hidden/unmapped windows we return nullptr NS_NATIVE_EGL_WINDOW at - // nsWindow::GetNativeData() so RenderCompositorEGL::Resume() creates - // offscreen fallback EGLSurface to avoid compositor pause. - // - // We don't want to pause compositor as it may lead to whole - // browser freeze (Bug 1777664). - // - // If RenderCompositorSWGL compositor is used (SW fallback) - // RenderCompositorSWGL::Resume() only requests full render for next paint - // as wl_surface/XWindow is managed by WindowSurfaceProvider owned - // directly by GtkCompositorWidget and that's covered by - // mCompositorWidgetDelegate->CleanupResources() call above. - if (CompositorBridgeChild* remoteRenderer = GetRemoteRenderer()) { - remoteRenderer->SendResume(); - } } } diff --git a/widget/gtk/nsWindow.h b/widget/gtk/nsWindow.h @@ -548,7 +548,6 @@ class nsWindow final : public nsIWidget { GtkWidget* GetToplevelWidget() const; nsWindow* GetContainerWindow() const; Window GetX11Window(); - void EnsureGdkWindow(); void SetUrgencyHint(GtkWidget* top_window, bool state); void SetDefaultIcon(void); void SetWindowDecoration(BorderStyle aStyle); @@ -592,6 +591,8 @@ class nsWindow final : public nsIWidget { GtkWidget* mShell = nullptr; MozContainer* mContainer = nullptr; GdkWindow* mGdkWindow = nullptr; + // mEGLWindow is owned by WaylandSurface or it's X11 ID. + void* mEGLWindow = nullptr; #ifdef MOZ_WAYLAND RefPtr<mozilla::widget::WaylandSurface> mSurface; #endif @@ -700,9 +701,6 @@ class nsWindow final : public nsIWidget { // If true, draw our own window titlebar. bool mDrawInTitlebar = false; - // This mutex protect window visibility changes. - mozilla::Mutex mWindowVisibilityMutex; - // This track real window visibility from OS perspective. // It's set by OnMap/OnUnmap which is based on Gtk events. mozilla::Atomic<bool, mozilla::Relaxed> mIsMapped;