diff --git a/firefox.spec b/firefox.spec index 59ed950..eb6b7a6 100644 --- a/firefox.spec +++ b/firefox.spec @@ -21,7 +21,7 @@ ExcludeArch: s390x %global build_with_clang 0 %global use_bundled_cbindgen 1 # FIXME disable PGO because of -j1 build would take ages -%global disable_multiprocess_compilation 1 +%global disable_multiprocess_compilation 0 # Build PGO+LTO on x86_64 and aarch64 only due to build issues # on other arches. %ifarch x86_64 aarch64 @@ -90,7 +90,7 @@ ExcludeArch: s390x Summary: Mozilla Firefox Web browser Name: firefox Version: 69.0 -Release: 1%{?pre_tag}%{?dist} +Release: 2%{?pre_tag}%{?dist} URL: https://www.mozilla.org/firefox/ License: MPLv1.1 or GPLv2+ or LGPLv2+ Source0: https://archive.mozilla.org/pub/firefox/releases/%{version}%{?pre_version}/source/firefox-%{version}%{?pre_version}.source.tar.xz @@ -127,7 +127,7 @@ Patch38: build-cacheFlush-missing.patch Patch40: build-aarch64-skia.patch Patch41: build-disable-elfhack.patch Patch44: build-arm-libopus.patch -Patch45: build-disable-multijobs-rust.patch +#Patch45: build-disable-multijobs-rust.patch # Fedora specific patches Patch215: firefox-enable-addons.patch @@ -150,6 +150,13 @@ Patch420: mozilla-1566876-webrtc-ind.patch # Wayland specific upstream patches Patch574: firefox-pipewire.patch +Patch575: mozilla-1548475.patch +Patch576: mozilla-1562827.patch +Patch578: mozilla-1567434-1.patch +Patch579: mozilla-1567434-2.patch +Patch580: mozilla-1573813.patch +Patch581: mozilla-1574036.patch +Patch582: mozilla-1576268.patch # PGO/LTO patches Patch600: pgo.patch @@ -326,7 +333,7 @@ This package contains results of tests executed during build. %endif %patch3 -p1 -b .arm %patch44 -p1 -b .build-arm-libopus -%patch45 -p1 -b .build-disable-multijobs-rust +#%patch45 -p1 -b .build-disable-multijobs-rust # Patch for big endian platforms only %if 0%{?big_endian} %patch26 -p1 -b .icu @@ -356,6 +363,13 @@ This package contains results of tests executed during build. # Wayland specific upstream patches %patch574 -p1 -b .firefox-pipewire +%patch575 -p1 -b .mozilla-1548475 +%patch576 -p1 -b .mozilla-1562827 +%patch578 -p1 -b .mozilla-1567434-1 +%patch579 -p1 -b .mozilla-1567434-2 +%patch580 -p1 -b .mozilla-1573813 +%patch581 -p1 -b .mozilla-1574036 +%patch582 -p1 -b .mozilla-1576268 # PGO patches %patch600 -p1 -b .pgo @@ -932,6 +946,12 @@ gtk-update-icon-cache %{_datadir}/icons/hicolor &>/dev/null || : #--------------------------------------------------------------------- %changelog +* Mon Sep 2 2019 Martin Stransky - 69.0-1 +- Added upstream Wayland patches (mozilla-1548475, mozilla-1562827, + mozilla-1567434, mozilla-1573813, mozilla-1574036, + mozilla-1576268). +- Enable multiprocess compilation. + * Thu Aug 29 2019 Jan Horak - 69.0-1 - Update to 69.0 diff --git a/mozilla-1548475.patch b/mozilla-1548475.patch new file mode 100644 index 0000000..b325683 --- /dev/null +++ b/mozilla-1548475.patch @@ -0,0 +1,34 @@ +diff --git a/dom/plugins/base/nsPluginHost.cpp b/dom/plugins/base/nsPluginHost.cpp +--- a/dom/plugins/base/nsPluginHost.cpp ++++ b/dom/plugins/base/nsPluginHost.cpp +@@ -105,6 +105,10 @@ + # include "windows.h" + # include "winbase.h" + #endif ++#if (MOZ_WIDGET_GTK) ++# include ++# include ++#endif + + #include "npapi.h" + +@@ -358,9 +362,15 @@ + mOverrideInternalTypes = + Preferences::GetBool("plugin.override_internal_types", false); + +- mPluginsDisabled = Preferences::GetBool("plugin.disable", false); +- +- Preferences::AddStrongObserver(this, "plugin.disable"); ++ bool waylandBackend = false; ++#if MOZ_WIDGET_GTK ++ waylandBackend = !GDK_IS_X11_DISPLAY(gdk_display_get_default()); ++#endif ++ mPluginsDisabled = ++ Preferences::GetBool("plugin.disable", false) || waylandBackend; ++ if (!waylandBackend) { ++ Preferences::AddStrongObserver(this, "plugin.disable"); ++ } + + nsCOMPtr obsService = + mozilla::services::GetObserverService(); + diff --git a/mozilla-1562827.patch b/mozilla-1562827.patch new file mode 100644 index 0000000..497133c --- /dev/null +++ b/mozilla-1562827.patch @@ -0,0 +1,141 @@ +diff -up firefox-69.0/widget/gtk/nsWindow.cpp.mozilla-1562827 firefox-69.0/widget/gtk/nsWindow.cpp +--- firefox-69.0/widget/gtk/nsWindow.cpp.mozilla-1562827 2019-09-02 15:16:15.031528276 +0200 ++++ firefox-69.0/widget/gtk/nsWindow.cpp 2019-09-02 15:16:15.037528254 +0200 +@@ -818,7 +818,6 @@ void nsWindow::SetParent(nsIWidget* aNew + if (mParent) { + mParent->RemoveChild(this); + } +- + mParent = aNewParent; + + GtkWidget* oldContainer = GetMozContainerWidget(); +@@ -830,88 +829,73 @@ void nsWindow::SetParent(nsIWidget* aNew + return; + } + ++ nsWindow* newParent = static_cast(aNewParent); ++ GdkWindow* newParentWindow = nullptr; ++ GtkWidget* newContainer = nullptr; + if (aNewParent) { + aNewParent->AddChild(this); +- ReparentNativeWidget(aNewParent); ++ newParentWindow = newParent->mGdkWindow; ++ newContainer = newParent->GetMozContainerWidget(); + } else { + // aNewParent is nullptr, but reparent to a hidden window to avoid + // destroying the GdkWindow and its descendants. + // An invisible container widget is needed to hold descendant + // GtkWidgets. +- GtkWidget* newContainer = EnsureInvisibleContainer(); +- GdkWindow* newParentWindow = gtk_widget_get_window(newContainer); +- ReparentNativeWidgetInternal(aNewParent, newContainer, newParentWindow, +- oldContainer); +- } +-} +- +-bool nsWindow::WidgetTypeSupportsAcceleration() { return !IsSmallPopup(); } +- +-void nsWindow::ReparentNativeWidget(nsIWidget* aNewParent) { +- MOZ_ASSERT(aNewParent, "null widget"); +- NS_ASSERTION(!mIsDestroyed, ""); +- NS_ASSERTION(!static_cast(aNewParent)->mIsDestroyed, ""); +- +- GtkWidget* oldContainer = GetMozContainerWidget(); +- if (!oldContainer) { +- // The GdkWindows have been destroyed so there is nothing else to +- // reparent. +- MOZ_ASSERT(gdk_window_is_destroyed(mGdkWindow), +- "live GdkWindow with no widget"); +- return; ++ newContainer = EnsureInvisibleContainer(); ++ newParentWindow = gtk_widget_get_window(newContainer); + } +- MOZ_ASSERT(!gdk_window_is_destroyed(mGdkWindow), +- "destroyed GdkWindow with widget"); + +- auto* newParent = static_cast(aNewParent); +- GdkWindow* newParentWindow = newParent->mGdkWindow; +- GtkWidget* newContainer = newParent->GetMozContainerWidget(); +- GtkWindow* shell = GTK_WINDOW(mShell); +- +- if (shell && gtk_window_get_transient_for(shell)) { +- GtkWindow* topLevelParent = +- GTK_WINDOW(gtk_widget_get_toplevel(newContainer)); +- gtk_window_set_transient_for(shell, topLevelParent); +- } +- +- ReparentNativeWidgetInternal(aNewParent, newContainer, newParentWindow, +- oldContainer); +-} +- +-void nsWindow::ReparentNativeWidgetInternal(nsIWidget* aNewParent, +- GtkWidget* aNewContainer, +- GdkWindow* aNewParentWindow, +- GtkWidget* aOldContainer) { +- if (!aNewContainer) { ++ if (!newContainer) { + // The new parent GdkWindow has been destroyed. +- MOZ_ASSERT(!aNewParentWindow || gdk_window_is_destroyed(aNewParentWindow), ++ MOZ_ASSERT(!newParentWindow || gdk_window_is_destroyed(newParentWindow), + "live GdkWindow with no widget"); + Destroy(); + } else { +- if (aNewContainer != aOldContainer) { +- MOZ_ASSERT(!gdk_window_is_destroyed(aNewParentWindow), ++ if (newContainer != oldContainer) { ++ MOZ_ASSERT(!gdk_window_is_destroyed(newParentWindow), + "destroyed GdkWindow with widget"); +- SetWidgetForHierarchy(mGdkWindow, aOldContainer, aNewContainer); ++ SetWidgetForHierarchy(mGdkWindow, oldContainer, newContainer); + +- if (aOldContainer == gInvisibleContainer) { ++ if (oldContainer == gInvisibleContainer) { + CheckDestroyInvisibleContainer(); + } + } + +- if (!mIsTopLevel) { +- gdk_window_reparent(mGdkWindow, aNewParentWindow, +- DevicePixelsToGdkCoordRoundDown(mBounds.x), +- DevicePixelsToGdkCoordRoundDown(mBounds.y)); +- } ++ gdk_window_reparent(mGdkWindow, newParentWindow, ++ DevicePixelsToGdkCoordRoundDown(mBounds.x), ++ DevicePixelsToGdkCoordRoundDown(mBounds.y)); ++ mToplevelParentWindow = GTK_WINDOW(gtk_widget_get_toplevel(newContainer)); + } + +- auto* newParent = static_cast(aNewParent); + bool parentHasMappedToplevel = newParent && newParent->mHasMappedToplevel; + if (mHasMappedToplevel != parentHasMappedToplevel) { + SetHasMappedToplevel(parentHasMappedToplevel); + } + } + ++bool nsWindow::WidgetTypeSupportsAcceleration() { return !IsSmallPopup(); } ++ ++void nsWindow::ReparentNativeWidget(nsIWidget* aNewParent) { ++ MOZ_ASSERT(aNewParent, "null widget"); ++ MOZ_ASSERT(!mIsDestroyed, ""); ++ MOZ_ASSERT(!static_cast(aNewParent)->mIsDestroyed, ""); ++ MOZ_ASSERT(!gdk_window_is_destroyed(mGdkWindow), ++ "destroyed GdkWindow with widget"); ++ ++ MOZ_ASSERT( ++ !mParent, ++ "nsWindow::ReparentNativeWidget() works on toplevel windows only."); ++ ++ auto* newParent = static_cast(aNewParent); ++ GtkWindow* newParentWidget = GTK_WINDOW(newParent->GetGtkWidget()); ++ GtkWindow* shell = GTK_WINDOW(mShell); ++ ++ if (shell && gtk_window_get_transient_for(shell)) { ++ gtk_window_set_transient_for(shell, newParentWidget); ++ mToplevelParentWindow = newParentWidget; ++ } ++} ++ + void nsWindow::SetModal(bool aModal) { + LOG(("nsWindow::SetModal [%p] %d\n", (void*)this, aModal)); + if (mIsDestroyed) return; +diff -up firefox-69.0/widget/gtk/nsWindow.h.mozilla-1562827 firefox-69.0/widget/gtk/nsWindow.h diff --git a/mozilla-1567434-1.patch b/mozilla-1567434-1.patch new file mode 100644 index 0000000..446cd6b --- /dev/null +++ b/mozilla-1567434-1.patch @@ -0,0 +1,226 @@ +diff --git a/widget/gtk/WindowSurfaceWayland.cpp b/widget/gtk/WindowSurfaceWayland.cpp +--- a/widget/gtk/WindowSurfaceWayland.cpp ++++ b/widget/gtk/WindowSurfaceWayland.cpp +@@ -616,8 +616,6 @@ + } + + if (!aFullScreenUpdate) { +- NS_WARNING( +- "We can't create a new Wayland buffer for non-fullscreen updates!"); + return nullptr; + } + +@@ -674,8 +672,6 @@ + (void*)buffer)); + + if (!buffer) { +- NS_WARNING( +- "WindowSurfaceWayland::LockWaylandBuffer(): No buffer available"); + return nullptr; + } + +diff --git a/widget/gtk/nsWindow.h b/widget/gtk/nsWindow.h +--- a/widget/gtk/nsWindow.h ++++ b/widget/gtk/nsWindow.h +@@ -487,6 +487,7 @@ + GtkWidget* mShell; + MozContainer* mContainer; + GdkWindow* mGdkWindow; ++ GtkWindow* mToplevelParentWindow; + bool mWindowShouldStartDragging = false; + PlatformCompositorWidgetDelegate* mCompositorWidgetDelegate; + +diff --git a/widget/gtk/nsWindow.cpp b/widget/gtk/nsWindow.cpp +--- a/widget/gtk/nsWindow.cpp ++++ b/widget/gtk/nsWindow.cpp +@@ -401,6 +401,7 @@ + mContainer = nullptr; + mGdkWindow = nullptr; + mShell = nullptr; ++ mToplevelParentWindow = nullptr; + mCompositorWidgetDelegate = nullptr; + mHasMappedToplevel = false; + mIsFullyObscured = false; +@@ -1144,6 +1145,8 @@ + nsWindow* window = + static_cast(gVisibleWaylandPopupWindows->data); + if (window->mPopupType != ePopupTypeTooltip) break; ++ LOG(("nsWindow::HideWaylandTooltips [%p] hidding tooltip [%p].\n", ++ (void*)this, window)); + window->HideWaylandWindow(); + gVisibleWaylandPopupWindows = g_list_delete_link( + gVisibleWaylandPopupWindows, gVisibleWaylandPopupWindows); +@@ -1172,9 +1175,12 @@ + // before we open another one on that level. It means that every open + // popup needs to have an unique parent. + GtkWidget* nsWindow::ConfigureWaylandPopupWindows() { ++ LOG(("nsWindow::ConfigureWaylandPopupWindows [%p]\n", (void*)this)); ++ + // Check if we're already configured. + if (gVisibleWaylandPopupWindows && + g_list_find(gVisibleWaylandPopupWindows, this)) { ++ LOG(("...[%p] is already configured.\n", (void*)this)); + return GTK_WIDGET(gtk_window_get_transient_for(GTK_WINDOW(mShell))); + } + +@@ -1182,9 +1188,15 @@ + // as it's short lived temporary window. + HideWaylandTooltips(); + +- GtkWindow* parentWidget = nullptr; ++ GtkWindow* parentWidget = mToplevelParentWindow; + if (gVisibleWaylandPopupWindows) { ++ LOG(("... there's visible active popup [%p]\n", ++ gVisibleWaylandPopupWindows->data)); ++ + if (mPopupType == ePopupTypeTooltip) { ++ LOG(("...[%p] is tooltip, parent [%p]\n", (void*)this, ++ gVisibleWaylandPopupWindows->data)); ++ + // Attach tooltip window to the latest popup window + // to have both visible. + nsWindow* window = +@@ -1200,12 +1212,19 @@ + // nsWindow::Create()) or we're toplevel popup without parent. + // In both cases just use parent which was passed to nsWindow::Create(). + if (!menuPopupFrame) { +- return GTK_WIDGET(gtk_window_get_transient_for(GTK_WINDOW(mShell))); ++ LOG(("...[%p] menuPopupFrame = null, using given parent widget [%p]\n", ++ (void*)this, parentWidget)); ++ return GTK_WIDGET(parentWidget); + } + + nsWindow* parentWindow = + static_cast(menuPopupFrame->GetParentMenuWidget()); ++ LOG(("...[%p] GetParentMenuWidget() = %p\n", (void*)this, parentWindow)); ++ + if (!parentWindow) { ++ LOG(("...[%p] using active/visible popups as a parent [%p]\n", ++ (void*)this, gVisibleWaylandPopupWindows->data)); ++ + // We're toplevel popup menu attached to another menu. Just use our + // latest popup as a parent. + parentWindow = +@@ -1234,10 +1253,10 @@ + } + } + ++ MOZ_ASSERT(parentWidget, "Missing parent widget for wayland popup!"); + if (parentWidget) { ++ LOG(("...[%p] set parent widget [%p]\n", (void*)this, parentWidget)); + gtk_window_set_transient_for(GTK_WINDOW(mShell), parentWidget); +- } else { +- parentWidget = gtk_window_get_transient_for(GTK_WINDOW(mShell)); + } + gVisibleWaylandPopupWindows = + g_list_prepend(gVisibleWaylandPopupWindows, this); +@@ -1248,9 +1267,11 @@ + static void NativeMoveResizeWaylandPopupCallback( + GdkWindow* window, const GdkRectangle* flipped_rect, + const GdkRectangle* final_rect, gboolean flipped_x, gboolean flipped_y, +- void* unused) { +- LOG(("%s flipped %d %d\n", __FUNCTION__, flipped_rect->x, flipped_rect->y)); +- LOG(("%s final %d %d\n", __FUNCTION__, final_rect->x, final_rect->y)); ++ void* aWindow) { ++ LOG(("%s [%p] flipped %d %d\n", __FUNCTION__, aWindow, flipped_rect->x, ++ flipped_rect->y)); ++ LOG(("%s [%p] final %d %d\n", __FUNCTION__, aWindow, final_rect->x, ++ final_rect->y)); + } + #endif + +@@ -1264,6 +1285,8 @@ + // Compositor may be confused by windows with width/height = 0 + // and positioning such windows leads to Bug 1555866. + if (!AreBoundsSane()) { ++ LOG(("nsWindow::NativeMoveResizeWaylandPopup [%p] Bounds are not sane\n", ++ (void*)this)); + return; + } + +@@ -1277,6 +1300,8 @@ + // - gdk_window_move_to_rect() is not available + // - the widget doesn't have a valid GdkWindow + if (!sGdkWindowMoveToRect || !gdkWindow) { ++ LOG(("nsWindow::NativeMoveResizeWaylandPopup [%p] use gtk_window_move()\n", ++ (void*)this)); + gtk_window_move(GTK_WINDOW(mShell), aPosition->x, aPosition->y); + return; + } +@@ -1302,8 +1327,12 @@ + } + LOG((" request result %d %d\n", rect.x, rect.y)); + #ifdef DEBUG +- g_signal_connect(gdkWindow, "moved-to-rect", +- G_CALLBACK(NativeMoveResizeWaylandPopupCallback), this); ++ if (!g_signal_handler_find( ++ gdkWindow, G_SIGNAL_MATCH_FUNC, 0, 0, nullptr, ++ FuncToGpointer(NativeMoveResizeWaylandPopupCallback), this)) { ++ g_signal_connect(gdkWindow, "moved-to-rect", ++ G_CALLBACK(NativeMoveResizeWaylandPopupCallback), this); ++ } + #endif + + GdkGravity rectAnchor = GDK_GRAVITY_NORTH_WEST; +@@ -3508,7 +3537,6 @@ + GtkWidget* parentMozContainer = nullptr; + GtkContainer* parentGtkContainer = nullptr; + GdkWindow* parentGdkWindow = nullptr; +- GtkWindow* topLevelParent = nullptr; + nsWindow* parentnsWindow = nullptr; + GtkWidget* eventWidget = nullptr; + bool drawToContainer = false; +@@ -3534,7 +3562,8 @@ + + // get the toplevel window just in case someone needs to use it + // for setting transients or whatever. +- topLevelParent = GTK_WINDOW(gtk_widget_get_toplevel(parentMozContainer)); ++ mToplevelParentWindow = ++ GTK_WINDOW(gtk_widget_get_toplevel(parentMozContainer)); + } + + if (!mIsX11Display) { +@@ -3542,7 +3571,7 @@ + // eWindowType_child is not supported on Wayland. Just switch to toplevel + // as a workaround. + mWindowType = eWindowType_toplevel; +- } else if (mWindowType == eWindowType_popup && !topLevelParent) { ++ } else if (mWindowType == eWindowType_popup && !mToplevelParentWindow) { + // Workaround for Wayland where the popup windows always need to have + // parent window. For example webrtc ui is a popup window without parent. + mWindowType = eWindowType_toplevel; +@@ -3677,7 +3706,7 @@ + gdk_get_program_class()); + gtk_window_set_type_hint(GTK_WINDOW(mShell), + GDK_WINDOW_TYPE_HINT_DIALOG); +- gtk_window_set_transient_for(GTK_WINDOW(mShell), topLevelParent); ++ gtk_window_set_transient_for(GTK_WINDOW(mShell), mToplevelParentWindow); + } else if (mWindowType == eWindowType_popup) { + gtk_window_set_wmclass(GTK_WINDOW(mShell), "Popup", + gdk_get_program_class()); +@@ -3730,10 +3759,11 @@ + } + gtk_window_set_type_hint(GTK_WINDOW(mShell), gtkTypeHint); + +- if (topLevelParent) { ++ if (mToplevelParentWindow) { + LOG(("nsWindow::Create [%p] Set popup parent %p\n", (void*)this, +- topLevelParent)); +- gtk_window_set_transient_for(GTK_WINDOW(mShell), topLevelParent); ++ mToplevelParentWindow)); ++ gtk_window_set_transient_for(GTK_WINDOW(mShell), ++ mToplevelParentWindow); + } + + // We need realized mShell at NativeMove(). +@@ -4011,7 +4041,8 @@ + #endif + } + +- LOG(("nsWindow [%p]\n", (void*)this)); ++ LOG(("nsWindow [%p] %s\n", (void*)this, ++ mWindowType == eWindowType_toplevel ? "Toplevel" : "Popup")); + if (mShell) { + LOG(("\tmShell %p mContainer %p mGdkWindow %p 0x%lx\n", mShell, mContainer, + mGdkWindow, mIsX11Display ? gdk_x11_window_get_xid(mGdkWindow) : 0)); + diff --git a/mozilla-1567434-2.patch b/mozilla-1567434-2.patch new file mode 100644 index 0000000..966118a --- /dev/null +++ b/mozilla-1567434-2.patch @@ -0,0 +1,35 @@ +diff --git a/widget/gtk/nsWindow.cpp b/widget/gtk/nsWindow.cpp +--- a/widget/gtk/nsWindow.cpp ++++ b/widget/gtk/nsWindow.cpp +@@ -1208,6 +1208,7 @@ + if (frame) { + menuPopupFrame = do_QueryFrame(frame); + } ++ + // The popup is not fully created yet (we're called from + // nsWindow::Create()) or we're toplevel popup without parent. + // In both cases just use parent which was passed to nsWindow::Create(). +@@ -1217,10 +1218,22 @@ + return GTK_WIDGET(parentWidget); + } + ++ LOG(("...[%p] is %s\n", (void*)this, ++ menuPopupFrame->IsContextMenu() ? "context menu" : "popup")); ++ + nsWindow* parentWindow = + static_cast(menuPopupFrame->GetParentMenuWidget()); + LOG(("...[%p] GetParentMenuWidget() = %p\n", (void*)this, parentWindow)); + ++ // If the popup is a regular menu but GetParentMenuWidget() returns ++ // nullptr which means it's connected non-menu parent ++ // (bookmark toolbar for instance). ++ // In this case use a parent given at nsWindow::Create(). ++ if (!parentWindow && !menuPopupFrame->IsContextMenu()) { ++ parentWindow = ++ get_window_for_gtk_widget(GTK_WIDGET(mToplevelParentWindow)); ++ } ++ + if (!parentWindow) { + LOG(("...[%p] using active/visible popups as a parent [%p]\n", + (void*)this, gVisibleWaylandPopupWindows->data)); + diff --git a/mozilla-1573813.patch b/mozilla-1573813.patch new file mode 100644 index 0000000..e9fca07 --- /dev/null +++ b/mozilla-1573813.patch @@ -0,0 +1,29 @@ +diff --git a/widget/gtk/nsWindow.cpp b/widget/gtk/nsWindow.cpp +--- a/widget/gtk/nsWindow.cpp ++++ b/widget/gtk/nsWindow.cpp +@@ -6577,11 +6577,22 @@ + } + + gint nsWindow::GdkScaleFactor() { ++ // For popup windows with parent window we need to get scale factor of the ++ // parent window. Otherwise the scale factor of the popup is not updated ++ // during it's hidden. ++ GdkWindow* scaledGdkWindow = mGdkWindow; ++ if (mToplevelParentWindow) { ++ scaledGdkWindow = gtk_widget_get_window(GTK_WIDGET(mToplevelParentWindow)); ++ // Fallback for windows which parent has been unrealized. ++ if (!scaledGdkWindow) { ++ scaledGdkWindow = mGdkWindow; ++ } ++ } + // Available as of GTK 3.10+ + static auto sGdkWindowGetScaleFactorPtr = + (gint(*)(GdkWindow*))dlsym(RTLD_DEFAULT, "gdk_window_get_scale_factor"); +- if (sGdkWindowGetScaleFactorPtr && mGdkWindow) +- return (*sGdkWindowGetScaleFactorPtr)(mGdkWindow); ++ if (sGdkWindowGetScaleFactorPtr && scaledGdkWindow) ++ return (*sGdkWindowGetScaleFactorPtr)(scaledGdkWindow); + return ScreenHelperGTK::GetGTKMonitorScaleFactor(); + } + + diff --git a/mozilla-1574036.patch b/mozilla-1574036.patch new file mode 100644 index 0000000..c3ecdc7 --- /dev/null +++ b/mozilla-1574036.patch @@ -0,0 +1,425 @@ +diff --git a/widget/gtk/WindowSurfaceWayland.h b/widget/gtk/WindowSurfaceWayland.h +--- a/widget/gtk/WindowSurfaceWayland.h ++++ b/widget/gtk/WindowSurfaceWayland.h +@@ -177,12 +177,9 @@ + + private: + WindowBackBuffer* CreateWaylandBuffer(int aWidth, int aHeight); +- WindowBackBuffer* GetWaylandBufferToDraw(int aWidth, int aHeight, +- bool aFullScreenUpdate); ++ WindowBackBuffer* GetWaylandBufferToDraw(bool aCanSwitchBuffer); + +- already_AddRefed LockWaylandBuffer(int aWidth, int aHeight, +- bool aClearBuffer, +- bool aFullScreenUpdate); ++ already_AddRefed LockWaylandBuffer(bool aCanSwitchBuffer); + void UnlockWaylandBuffer(); + + already_AddRefed LockImageSurface( +@@ -198,7 +195,10 @@ + + // TODO: Do we need to hold a reference to nsWindow object? + nsWindow* mWindow; +- LayoutDeviceIntRect mLastScreenRect; ++ // Buffer screen rects helps us understand if we operate on ++ // the same window size as we're called on WindowSurfaceWayland::Lock(). ++ // mBufferScreenRect is window size when our wayland buffer was allocated. ++ LayoutDeviceIntRect mBufferScreenRect; + nsWaylandDisplay* mWaylandDisplay; + WindowBackBuffer* mWaylandBuffer; + LayoutDeviceIntRegion mWaylandBufferDamage; +@@ -211,7 +211,8 @@ + AutoTArray mDelayedImageCommits; + bool mDrawToWaylandBufferDirectly; + bool mPendingCommit; +- bool mWaylandBufferFullScreenDamage; ++ bool mWholeWindowBufferDamage; ++ bool mBufferNeedsClear; + bool mIsMainThread; + bool mNeedScaleFactorUpdate; + +diff --git a/widget/gtk/WindowSurfaceWayland.cpp b/widget/gtk/WindowSurfaceWayland.cpp +--- a/widget/gtk/WindowSurfaceWayland.cpp ++++ b/widget/gtk/WindowSurfaceWayland.cpp +@@ -499,7 +499,8 @@ + mDelayedCommitHandle(nullptr), + mDrawToWaylandBufferDirectly(true), + mPendingCommit(false), +- mWaylandBufferFullScreenDamage(false), ++ mWholeWindowBufferDamage(false), ++ mBufferNeedsClear(false), + mIsMainThread(NS_IsMainThread()), + mNeedScaleFactorUpdate(true) { + for (int i = 0; i < BACK_BUFFER_NUM; i++) mBackupBuffer[i] = nullptr; +@@ -565,18 +566,20 @@ + } + + WindowBackBuffer* WindowSurfaceWayland::GetWaylandBufferToDraw( +- int aWidth, int aHeight, bool aFullScreenUpdate) { ++ bool aCanSwitchBuffer) { + LOGWAYLAND(("%s [%p] Requested buffer [%d x %d]\n", __PRETTY_FUNCTION__, +- (void*)this, aWidth, aHeight)); ++ (void*)this, mBufferScreenRect.width, mBufferScreenRect.height)); + + // There's no buffer created yet, create a new one. + if (!mWaylandBuffer) { +- MOZ_ASSERT(aFullScreenUpdate, "Created new buffer for partial drawing!"); ++ MOZ_ASSERT(aCanSwitchBuffer && mWholeWindowBufferDamage, ++ "Created new buffer for partial drawing!"); + LOGWAYLAND(("%s [%p] Created new buffer [%d x %d]\n", __PRETTY_FUNCTION__, +- (void*)this, aWidth, aHeight)); ++ (void*)this, mBufferScreenRect.width, ++ mBufferScreenRect.height)); + +- mWaylandBuffer = CreateWaylandBuffer(aWidth, aHeight); +- mWaylandBufferFullScreenDamage = true; ++ mWaylandBuffer = ++ CreateWaylandBuffer(mBufferScreenRect.width, mBufferScreenRect.height); + mNeedScaleFactorUpdate = true; + return mWaylandBuffer; + } +@@ -593,29 +596,31 @@ + LOGWAYLAND( + ("%s [%p] Use recent buffer.\n", __PRETTY_FUNCTION__, (void*)this)); + +- if (mWaylandBuffer->IsMatchingSize(aWidth, aHeight)) { ++ if (mWaylandBuffer->IsMatchingSize(mBufferScreenRect.width, ++ mBufferScreenRect.height)) { + LOGWAYLAND(("%s [%p] Size is ok, use the buffer [%d x %d]\n", +- __PRETTY_FUNCTION__, (void*)this, aWidth, aHeight)); ++ __PRETTY_FUNCTION__, (void*)this, mBufferScreenRect.width, ++ mBufferScreenRect.height)); + return mWaylandBuffer; + } + +- if (!aFullScreenUpdate) { ++ if (!aCanSwitchBuffer) { + NS_WARNING("We can't resize Wayland buffer for non-fullscreen updates!"); + return nullptr; + } + + LOGWAYLAND(("%s [%p] Reuse buffer with resize [%d x %d]\n", +- __PRETTY_FUNCTION__, (void*)this, aWidth, aHeight)); ++ __PRETTY_FUNCTION__, (void*)this, mBufferScreenRect.width, ++ mBufferScreenRect.height)); + +- mWaylandBuffer->Resize(aWidth, aHeight); ++ mWaylandBuffer->Resize(mBufferScreenRect.width, mBufferScreenRect.height); + // There's a chance that scale factor has been changed + // when buffer size changed +- mWaylandBufferFullScreenDamage = true; + mNeedScaleFactorUpdate = true; + return mWaylandBuffer; + } + +- if (!aFullScreenUpdate) { ++ if (!aCanSwitchBuffer) { + return nullptr; + } + +@@ -625,8 +630,10 @@ + availableBuffer++) { + if (!mBackupBuffer[availableBuffer]) { + LOGWAYLAND(("%s [%p] Created new buffer [%d x %d]\n", __PRETTY_FUNCTION__, +- (void*)this, aWidth, aHeight)); +- mBackupBuffer[availableBuffer] = CreateWaylandBuffer(aWidth, aHeight); ++ (void*)this, mBufferScreenRect.width, ++ mBufferScreenRect.height)); ++ mBackupBuffer[availableBuffer] = CreateWaylandBuffer( ++ mBufferScreenRect.width, mBufferScreenRect.height); + break; + } + +@@ -650,23 +657,23 @@ + __PRETTY_FUNCTION__, (void*)this, (void*)lastWaylandBuffer, + (void*)mWaylandBuffer)); + +- mWaylandBufferFullScreenDamage = true; + mNeedScaleFactorUpdate = true; + +- bool bufferNeedsResize = !mWaylandBuffer->IsMatchingSize(aWidth, aHeight); ++ bool bufferNeedsResize = !mWaylandBuffer->IsMatchingSize( ++ mBufferScreenRect.width, mBufferScreenRect.height); + if (bufferNeedsResize) { + LOGWAYLAND(("%s [%p] Resize buffer to [%d x %d]\n", __PRETTY_FUNCTION__, +- (void*)this, aWidth, aHeight)); +- mWaylandBuffer->Resize(aWidth, aHeight); ++ (void*)this, mBufferScreenRect.width, ++ mBufferScreenRect.height)); ++ mWaylandBuffer->Resize(mBufferScreenRect.width, mBufferScreenRect.height); + } + + return mWaylandBuffer; + } + + already_AddRefed WindowSurfaceWayland::LockWaylandBuffer( +- int aWidth, int aHeight, bool aClearBuffer, bool aFullScreenUpdate) { +- WindowBackBuffer* buffer = +- GetWaylandBufferToDraw(aWidth, aHeight, aFullScreenUpdate); ++ bool aCanSwitchBuffer) { ++ WindowBackBuffer* buffer = GetWaylandBufferToDraw(aCanSwitchBuffer); + + LOGWAYLAND(("%s [%p] Got buffer %p\n", __PRETTY_FUNCTION__, (void*)this, + (void*)buffer)); +@@ -675,8 +682,9 @@ + return nullptr; + } + +- if (aClearBuffer) { ++ if (mBufferNeedsClear && mWholeWindowBufferDamage) { + buffer->Clear(); ++ mBufferNeedsClear = false; + } + + return buffer->Lock(); +@@ -744,7 +752,7 @@ + const LayoutDeviceIntRegion& aRegion) { + MOZ_ASSERT(mIsMainThread == NS_IsMainThread()); + +- LayoutDeviceIntRect screenRect = mWindow->GetBounds(); ++ LayoutDeviceIntRect lockedScreenRect = mWindow->GetBounds(); + gfx::IntRect bounds = aRegion.GetBounds().ToUnknownRect(); + gfx::IntSize lockSize(bounds.XMost(), bounds.YMost()); + +@@ -753,54 +761,77 @@ + mWindow->IsWaylandPopup() && + (eTransparencyTransparent == mWindow->GetTransparencyMode()); + +- mDrawToWaylandBufferDirectly = +- isTransparentPopup ? IsPopupFullScreenUpdate(screenRect, aRegion) +- : IsWindowFullScreenUpdate(screenRect, aRegion); ++ // We have request to lock whole buffer/window. ++ mWholeWindowBufferDamage = ++ isTransparentPopup ? IsPopupFullScreenUpdate(lockedScreenRect, aRegion) ++ : IsWindowFullScreenUpdate(lockedScreenRect, aRegion); + +- bool needsClear = mWindow->WaylandSurfaceNeedsClear() || +- (isTransparentPopup && mDrawToWaylandBufferDirectly); ++ // Clear buffer when we (re)draw new transparent popup window, ++ // otherwise leave it as-is, mBufferNeedsClear can be set from previous ++ // (already pending) commits which are cached now. ++ if (mWholeWindowBufferDamage) { ++ mBufferNeedsClear = ++ mWindow->WaylandSurfaceNeedsClear() || isTransparentPopup; ++ } + + LOGWAYLAND(("%s [%p] lockSize [%d x %d] windowSize [%d x %d]\n", + __PRETTY_FUNCTION__, (void*)this, lockSize.width, lockSize.height, +- screenRect.width, screenRect.height)); ++ lockedScreenRect.width, lockedScreenRect.height)); + LOGWAYLAND((" nsWindow = %p\n", mWindow)); + LOGWAYLAND((" isPopup = %d\n", mWindow->IsWaylandPopup())); + LOGWAYLAND((" isTransparentPopup = %d\n", isTransparentPopup)); + LOGWAYLAND((" IsPopupFullScreenUpdate = %d\n", +- IsPopupFullScreenUpdate(screenRect, aRegion))); ++ IsPopupFullScreenUpdate(lockedScreenRect, aRegion))); + LOGWAYLAND((" IsWindowFullScreenUpdate = %d\n", +- IsWindowFullScreenUpdate(screenRect, aRegion))); +- LOGWAYLAND((" needsClear = %d\n", needsClear)); +- LOGWAYLAND( +- (" mDrawToWaylandBufferDirectly = %d\n", mDrawToWaylandBufferDirectly)); ++ IsWindowFullScreenUpdate(lockedScreenRect, aRegion))); ++ LOGWAYLAND((" mBufferNeedsClear = %d\n", mBufferNeedsClear)); ++ LOGWAYLAND((" mWholeWindowBufferDamage = %d\n", mWholeWindowBufferDamage)); ++ ++#if DEBUG ++ if (!(mBufferScreenRect == lockedScreenRect)) { ++ LOGWAYLAND((" screen size changed\n")); ++ } ++#endif + +- // Allow full screen allocation and clear +- // when window size changed. +- bool bufferRedraw = !(screenRect == mLastScreenRect); +- if (bufferRedraw) { +- mDrawToWaylandBufferDirectly = true; +- needsClear = true; ++ if (!(mBufferScreenRect == lockedScreenRect)) { ++ // Screen (window) size changed and we still have some painting pending ++ // for the last window size. That can happen when window is resized. ++ // We can't commit them any more as they're for former window size, so ++ // scratch them. ++ mDelayedImageCommits.Clear(); ++ ++ if (!mWholeWindowBufferDamage) { ++ NS_WARNING("Partial screen update when window is resized!"); ++ // This should not happen. Screen size changed but we got only ++ // partal screen update instead of whole screen. Discard this painting ++ // as it produces artifacts. ++ return nullptr; ++ } ++ mBufferScreenRect = lockedScreenRect; + } + +- if (mDrawToWaylandBufferDirectly) { ++ if (mWholeWindowBufferDamage) { ++ // We can lock/commit entire buffer direcly. ++ mDrawToWaylandBufferDirectly = true; ++ + // If there's any pending image commit scratch them as we're going + // to redraw the whole sceen anyway. + mDelayedImageCommits.Clear(); + +- RefPtr dt = +- LockWaylandBuffer(screenRect.width, screenRect.height, needsClear, +- /* aFullScreenUpdate */ true); ++ RefPtr dt = LockWaylandBuffer( ++ /* aCanSwitchBuffer */ mWholeWindowBufferDamage); + if (dt) { +- if (bufferRedraw) { +- mLastScreenRect = screenRect; +- } + return dt.forget(); + } ++ } + +- // We don't have any front buffer available. Try indirect drawing +- // to mImageSurface which is mirrored to front buffer at commit. +- mDrawToWaylandBufferDirectly = false; +- } ++ // We do indirect drawing due to: ++ // ++ // 1) We don't have any front buffer available. Try indirect drawing ++ // to mImageSurface which is mirrored to front buffer at commit. ++ // 2) Only part of the screen is locked. We can't lock entire screen for ++ // such drawing as it produces visible artifacts. ++ mDrawToWaylandBufferDirectly = false; + + LOGWAYLAND((" Indirect drawing.\n")); + return LockImageSurface(lockSize); +@@ -851,16 +882,14 @@ + LayoutDeviceIntRegion& aWaylandBufferDamage) { + MOZ_ASSERT(!mDrawToWaylandBufferDirectly); + +- LayoutDeviceIntRect screenRect = mWindow->GetBounds(); ++#ifdef DEBUG + gfx::IntRect bounds = aRegion.GetBounds().ToUnknownRect(); +- + gfx::Rect rect(bounds); +- if (rect.IsEmpty()) { +- return false; +- } ++ MOZ_ASSERT(!rect.IsEmpty(), "Empty drawing?"); ++#endif + + LOGWAYLAND(("%s [%p] screenSize [%d x %d]\n", __PRETTY_FUNCTION__, +- (void*)this, screenRect.width, screenRect.height)); ++ (void*)this, mBufferScreenRect.width, mBufferScreenRect.height)); + + RefPtr surf = + gfx::Factory::CreateSourceSurfaceForCairoSurface( +@@ -871,13 +900,8 @@ + return false; + } + +- // Allow full screen allocation and clear +- // when window size changed. +- bool bufferRedraw = !(screenRect == mLastScreenRect); +- RefPtr dt = +- LockWaylandBuffer(screenRect.width, screenRect.height, +- /* needs clear*/ bufferRedraw, +- /* aFullScreenUpdate */ bufferRedraw); ++ RefPtr dt = LockWaylandBuffer( ++ /* aCanSwitchBuffer */ mWholeWindowBufferDamage); + if (dt) { + LOGWAYLAND( + (" Flushing %ld cached WindowImageSurfaces to Wayland buffer\n", +@@ -885,14 +909,11 @@ + + // Draw any delayed image commits first + DrawDelayedImageCommits(dt, aWaylandBufferDamage); ++ // Draw image from recent WindowSurfaceWayland::Lock(). + WindowImageSurface::Draw(surf, dt, aRegion); + // Submit all drawing to final Wayland buffer upload + aWaylandBufferDamage.OrWith(aRegion); + UnlockWaylandBuffer(); +- +- if (bufferRedraw) { +- mLastScreenRect = screenRect; +- } + } else { + mDelayedImageCommits.AppendElement(WindowImageSurface(surf, aRegion)); + LOGWAYLAND((" Added WindowImageSurfaces, cached surfaces %ld\n", +@@ -930,29 +951,25 @@ + LOGWAYLAND(("%s [%p]\n", __PRETTY_FUNCTION__, (void*)this)); + LOGWAYLAND( + (" mDrawToWaylandBufferDirectly = %d\n", mDrawToWaylandBufferDirectly)); +- LOGWAYLAND((" mWaylandBufferFullScreenDamage = %d\n", +- mWaylandBufferFullScreenDamage)); ++ LOGWAYLAND((" mWholeWindowBufferDamage = %d\n", mWholeWindowBufferDamage)); + LOGWAYLAND((" mDelayedCommitHandle = %p\n", mDelayedCommitHandle)); + LOGWAYLAND((" mFrameCallback = %p\n", mFrameCallback)); + LOGWAYLAND((" mLastCommittedSurface = %p\n", mLastCommittedSurface)); + + if (!mDrawToWaylandBufferDirectly) { ++ MOZ_ASSERT(mDelayedImageCommits.Length(), ++ "Indirect drawing without any image?"); ++ + // There's some cached drawings - try to flush them now. +- LayoutDeviceIntRect screenRect = mWindow->GetBounds(); +- bool bufferRedraw = !(screenRect == mLastScreenRect); +- RefPtr dt = +- LockWaylandBuffer(screenRect.width, screenRect.height, +- /* needsClear */ bufferRedraw, +- /* full screen update */ bufferRedraw); ++ RefPtr dt = LockWaylandBuffer( ++ /* aCanSwitchBuffer */ mWholeWindowBufferDamage); ++ + if (dt) { + LOGWAYLAND(("%s [%p] flushed indirect drawing\n", __PRETTY_FUNCTION__, + (void*)this)); + DrawDelayedImageCommits(dt, mWaylandBufferDamage); + UnlockWaylandBuffer(); + mDrawToWaylandBufferDirectly = true; +- if (bufferRedraw) { +- mLastScreenRect = screenRect; +- } + } + } + +@@ -1000,10 +1017,10 @@ + mLastCommittedSurface = nullptr; + } + +- if (mWaylandBufferFullScreenDamage) { +- LayoutDeviceIntRect rect = mWindow->GetBounds(); +- wl_surface_damage(waylandSurface, 0, 0, rect.width, rect.height); +- mWaylandBufferFullScreenDamage = false; ++ if (mWholeWindowBufferDamage) { ++ wl_surface_damage(waylandSurface, 0, 0, mBufferScreenRect.width, ++ mBufferScreenRect.height); ++ mWholeWindowBufferDamage = false; + mNeedScaleFactorUpdate = true; + } else { + gint scaleFactor = mWindow->GdkScaleFactor(); +@@ -1043,24 +1060,24 @@ + + #ifdef DEBUG + { +- LayoutDeviceIntRect screenRect = mWindow->GetBounds(); + gfx::IntRect bounds = aInvalidRegion.GetBounds().ToUnknownRect(); + gfx::IntSize lockSize(bounds.XMost(), bounds.YMost()); + + LOGWAYLAND(("%s [%p] lockSize [%d x %d] screenSize [%d x %d]\n", + __PRETTY_FUNCTION__, (void*)this, lockSize.width, +- lockSize.height, screenRect.width, screenRect.height)); ++ lockSize.height, mBufferScreenRect.width, ++ mBufferScreenRect.height)); + LOGWAYLAND((" mDrawToWaylandBufferDirectly = %d\n", + mDrawToWaylandBufferDirectly)); +- LOGWAYLAND((" mWaylandBufferFullScreenDamage = %d\n", +- mWaylandBufferFullScreenDamage)); ++ LOGWAYLAND( ++ (" mWholeWindowBufferDamage = %d\n", mWholeWindowBufferDamage)); + } + #endif + + if (mDrawToWaylandBufferDirectly) { + MOZ_ASSERT(mWaylandBuffer->IsLocked()); + // If we're not at fullscreen damage add drawing area from aInvalidRegion +- if (!mWaylandBufferFullScreenDamage) { ++ if (!mWholeWindowBufferDamage) { + mWaylandBufferDamage.OrWith(aInvalidRegion); + } + UnlockWaylandBuffer(); + diff --git a/mozilla-1576268.patch b/mozilla-1576268.patch new file mode 100644 index 0000000..85fd1a8 --- /dev/null +++ b/mozilla-1576268.patch @@ -0,0 +1,17 @@ +diff --git a/widget/gtk/nsClipboardWayland.cpp b/widget/gtk/nsClipboardWayland.cpp +--- a/widget/gtk/nsClipboardWayland.cpp ++++ b/widget/gtk/nsClipboardWayland.cpp +@@ -195,6 +195,12 @@ + uint32_t all_actions = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY | + WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE; + ++ /* Default to move D&D action (Bug 1576268). ++ */ ++ if (dnd_actions == 0) { ++ all_actions = WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE; ++ } ++ + wl_data_offer_set_actions(mWaylandDataOffer, all_actions, dnd_actions); + + /* Workaround Wayland D&D architecture here. To get the data_device_drop() +