author | Martin Stransky <stransky@redhat.com> |
Thu, 02 Jan 2020 13:35:26 +0000 | |
changeset 508600 | c96194fe9f07a39d4d681b392d0bb7bb778ecf41 |
parent 508599 | 5bd709eb6bd1b084779922c508df2ec9ad98eebc |
child 508601 | 2955e3b6962e2386cce676514f01a9af9c954356 |
push id | 104107 |
push user | nbeleuzu@mozilla.com |
push date | Thu, 02 Jan 2020 13:42:13 +0000 |
treeherder | autoland@c96194fe9f07 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | heftig |
bugs | 1605120 |
milestone | 73.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/widget/gtk/mozcontainer.cpp +++ b/widget/gtk/mozcontainer.cpp @@ -203,16 +203,17 @@ void moz_container_init(MozContainer* co gtk_widget_set_can_focus(GTK_WIDGET(container), TRUE); gtk_container_set_resize_mode(GTK_CONTAINER(container), GTK_RESIZE_IMMEDIATE); gtk_widget_set_redraw_on_allocate(GTK_WIDGET(container), FALSE); #if defined(MOZ_WAYLAND) container->surface = nullptr; container->subsurface = nullptr; container->eglwindow = nullptr; + container->opaque_region = nullptr; container->frame_callback_handler = nullptr; container->frame_callback_handler_surface_id = -1; // We can draw to x11 window any time. container->ready_to_draw = gfxPlatformGtk::GetPlatform()->IsX11Display(); container->surface_needs_clear = true; container->subsurface_dx = 0; container->subsurface_dy = 0; container->surface_position_needs_update = 0; @@ -324,16 +325,21 @@ static void moz_container_unmap_wayland( g_clear_pointer(&container->subsurface, wl_subsurface_destroy); g_clear_pointer(&container->surface, wl_surface_destroy); g_clear_pointer(&container->frame_callback_handler, wl_callback_destroy); container->frame_callback_handler_surface_id = -1; container->surface_needs_clear = true; container->ready_to_draw = false; + if (container->opaque_region) { + wl_region_destroy(container->opaque_region); + container->opaque_region = nullptr; + } + LOGWAYLAND(("%s [%p]\n", __FUNCTION__, (void*)container)); } #endif void moz_container_map(GtkWidget* widget) { MozContainer* container; GList* tmp_list; GtkWidget* tmp_child; @@ -604,16 +610,18 @@ struct wl_surface* moz_container_get_wl_ (void*)container->surface)); } if (container->surface_position_needs_update) { moz_container_move(container, container->subsurface_dx, container->subsurface_dy); } + wl_surface_set_opaque_region(container->surface, container->opaque_region); + return container->surface; } struct wl_egl_window* moz_container_get_wl_egl_window(MozContainer* container, int scale) { LOGWAYLAND(("%s [%p] eglwindow %p\n", __FUNCTION__, (void*)container, (void*)container->eglwindow)); @@ -641,13 +649,21 @@ gboolean moz_container_has_wl_egl_window return container->eglwindow ? true : false; } gboolean moz_container_surface_needs_clear(MozContainer* container) { int ret = container->surface_needs_clear; container->surface_needs_clear = false; return ret; } + +void moz_container_set_opaque_region(MozContainer* container, + wl_region* opaque_region) { + if (container->opaque_region) { + wl_region_destroy(container->opaque_region); + } + container->opaque_region = opaque_region; +} #endif void moz_container_force_default_visual(MozContainer* container) { container->force_default_visual = true; }
--- a/widget/gtk/mozcontainer.h +++ b/widget/gtk/mozcontainer.h @@ -73,16 +73,17 @@ struct _MozContainer { GtkContainer container; GList* children; #ifdef MOZ_WAYLAND struct wl_surface* surface; struct wl_subsurface* subsurface; int subsurface_dx, subsurface_dy; struct wl_egl_window* eglwindow; + struct wl_region* opaque_region; struct wl_callback* frame_callback_handler; int frame_callback_handler_surface_id; gboolean surface_position_needs_update; gboolean surface_needs_clear; gboolean ready_to_draw; std::vector<std::function<void(void)>> initial_draw_cbs; #endif gboolean force_default_visual; @@ -109,11 +110,13 @@ void moz_container_move_resize(MozContai int width, int height); void moz_container_egl_window_set_size(MozContainer* container, int width, int height); void moz_container_scale_changed(MozContainer* container, GtkAllocation* aAllocation); void moz_container_add_initial_draw_callback( MozContainer* container, const std::function<void(void)>& initial_draw_cb); wl_surface* moz_gtk_widget_get_wl_surface(GtkWidget* aWidget); +void moz_container_set_opaque_region(MozContainer* container, + wl_region* opaque_region); #endif #endif /* __MOZ_CONTAINER_H__ */
--- a/widget/gtk/nsWindow.cpp +++ b/widget/gtk/nsWindow.cpp @@ -4789,132 +4789,165 @@ void nsWindow::SetWindowMouseTransparent // with -moz-window-dragging: drag. void nsWindow::UpdateWindowDraggingRegion( const LayoutDeviceIntRegion& aRegion) { if (mDraggableRegion != aRegion) { mDraggableRegion = aRegion; } } +// See subtract_corners_from_region() at gtk/gtkwindow.c +// We need to subtract corners from toplevel window opaque region +// to draw transparent corners of default Gtk titlebar. +// Both implementations (cairo_region_t and wl_region) needs to be synced. +static void SubtractTitlebarCorners(cairo_region_t* aRegion, int aX, int aY, + int aWindowWidth) { + cairo_rectangle_int_t rect = {aX, aY, TITLEBAR_SHAPE_MASK_HEIGHT, + TITLEBAR_SHAPE_MASK_HEIGHT}; + cairo_region_subtract_rectangle(aRegion, &rect); + rect = { + aX + aWindowWidth - TITLEBAR_SHAPE_MASK_HEIGHT, + aY, + TITLEBAR_SHAPE_MASK_HEIGHT, + TITLEBAR_SHAPE_MASK_HEIGHT, + }; + cairo_region_subtract_rectangle(aRegion, &rect); +} + #ifdef MOZ_WAYLAND -void nsWindow::UpdateOpaqueRegionWayland(cairo_region_t* aRegion) { +static void SubtractTitlebarCorners(wl_region* aRegion, int aX, int aY, + int aWindowWidth) { + wl_region_subtract(aRegion, aX, aY, TITLEBAR_SHAPE_MASK_HEIGHT, + TITLEBAR_SHAPE_MASK_HEIGHT); + wl_region_subtract(aRegion, aX + aWindowWidth - TITLEBAR_SHAPE_MASK_HEIGHT, + aY, TITLEBAR_SHAPE_MASK_HEIGHT, + TITLEBAR_SHAPE_MASK_HEIGHT); +} + +void nsWindow::UpdateTopLevelOpaqueRegionWayland(bool aSubtractCorners) { wl_surface* surface = moz_gtk_widget_get_wl_surface(GTK_WIDGET(mShell)); if (!surface) { return; } GdkDisplay* display = gtk_widget_get_display(GTK_WIDGET(mShell)); nsWaylandDisplay* waylandDisplay = WaylandDisplayGet(display); - - wl_region* wl_region = nullptr; - if (aRegion) { - struct wl_compositor* compositor = waylandDisplay->GetCompositor(); - wl_region = wl_compositor_create_region(compositor); - int n_rects = cairo_region_num_rectangles(aRegion); - for (int i = 0; i < n_rects; i++) { - cairo_rectangle_int_t rect; - cairo_region_get_rectangle(aRegion, i, &rect); - wl_region_add(wl_region, rect.x, rect.y, rect.width, rect.height); - } - } - - wl_surface_set_opaque_region(surface, wl_region); - if (wl_region) { - wl_region_destroy(wl_region); - } + struct wl_compositor* compositor = waylandDisplay->GetCompositor(); + + // Set opaque region to mShell. It's moved to mClientOffset.x/mClientOffset.y + // from origin as we need transparent shadows around a window. + wl_region* region = wl_compositor_create_region(compositor); + int x = DevicePixelsToGdkCoordRoundDown(mClientOffset.x); + int y = DevicePixelsToGdkCoordRoundDown(mClientOffset.y); + int width = DevicePixelsToGdkCoordRoundDown(mBounds.width); + int height = DevicePixelsToGdkCoordRoundDown(mBounds.height); + wl_region_add(region, x, y, width, height); + if (aSubtractCorners) { + SubtractTitlebarCorners(region, x, y, width); + } + wl_surface_set_opaque_region(surface, region); + wl_region_destroy(region); + + // Set region to mozcontainer which does not have any offset + region = wl_compositor_create_region(compositor); + wl_region_add(region, 0, 0, width, height); + if (aSubtractCorners) { + SubtractTitlebarCorners(region, 0, 0, width); + } + moz_container_set_opaque_region(mContainer, region); } #endif -void nsWindow::UpdateOpaqueRegionGtk(cairo_region_t* aRegion) { +static void GdkWindowSetOpaqueRegion(GdkWindow* aGdkWindow, + cairo_region_t* aRegion) { // Available as of GTK 3.10+ static auto sGdkWindowSetOpaqueRegion = (void (*)(GdkWindow*, cairo_region_t*))dlsym( RTLD_DEFAULT, "gdk_window_set_opaque_region"); if (MOZ_UNLIKELY(!sGdkWindowSetOpaqueRegion)) { LOG((" gdk_window_set_opaque_region is not available!\n")); return; } + (*sGdkWindowSetOpaqueRegion)(aGdkWindow, aRegion); +} + +void nsWindow::UpdateTopLevelOpaqueRegionGtk(bool aSubtractCorners) { + cairo_region_t* region = cairo_region_create(); + int x = DevicePixelsToGdkCoordRoundDown(mClientOffset.x); + int y = DevicePixelsToGdkCoordRoundDown(mClientOffset.y); + int width = DevicePixelsToGdkCoordRoundDown(mBounds.width); + int height = DevicePixelsToGdkCoordRoundDown(mBounds.height); + + cairo_rectangle_int_t rect = {x, y, width, height}; + cairo_region_union_rectangle(region, &rect); + + if (aSubtractCorners) { + SubtractTitlebarCorners(region, x, y, width); + } + GdkWindow* window = (mDrawToContainer) ? gtk_widget_get_window(mShell) : mGdkWindow; - if (gdk_window_get_window_type(window) == GDK_WINDOW_TOPLEVEL) { - (*sGdkWindowSetOpaqueRegion)(window, aRegion); + MOZ_ASSERT(gdk_window_get_window_type(window) == GDK_WINDOW_TOPLEVEL); + GdkWindowSetOpaqueRegion(window, region); + + cairo_region_destroy(region); +} + +void nsWindow::UpdatePopupOpaqueRegion( + const LayoutDeviceIntRegion& aOpaqueRegion) { + cairo_region_t* region = nullptr; + + if (!aOpaqueRegion.IsEmpty()) { + region = cairo_region_create(); + for (auto iter = aOpaqueRegion.RectIter(); !iter.Done(); iter.Next()) { + const LayoutDeviceIntRect& r = iter.Get(); + cairo_rectangle_int_t rect = {r.x, r.y, r.width, r.height}; + cairo_region_union_rectangle(region, &rect); + } + } + + GdkWindow* window = + (mDrawToContainer) ? gtk_widget_get_window(mShell) : mGdkWindow; + GdkWindowSetOpaqueRegion(window, region); + + if (region) { + cairo_region_destroy(region); } } void nsWindow::UpdateOpaqueRegion(const LayoutDeviceIntRegion& aOpaqueRegion) { - // Also don't set shape mask if we use transparency bitmap. + // Don't set shape mask if we use transparency bitmap. if (mTransparencyBitmapForTitlebar) { return; } - cairo_region_t* region = nullptr; - - // We don't tweak opaque regions for non-toplevel windows (popup, panels etc.) - // as they can be transparent by gecko. if (mWindowType != eWindowType_toplevel) { - if (!aOpaqueRegion.IsEmpty()) { - region = cairo_region_create(); - for (auto iter = aOpaqueRegion.RectIter(); !iter.Done(); iter.Next()) { - const LayoutDeviceIntRect& r = iter.Get(); - cairo_rectangle_int_t rect = {r.x, r.y, r.width, r.height}; - cairo_region_union_rectangle(region, &rect); - } - } + // We don't tweak opaque regions for non-toplevel windows + // (popup, panels etc.) as they can be transparent by gecko. + UpdatePopupOpaqueRegion(aOpaqueRegion); } else { // Gecko does not use transparent toplevel windows (see Bug 1469716), // however we need to make it transparent to draw round corners of // Gtk titlebar. - region = cairo_region_create(); - - GtkBorder decorationSize = {0, 0, 0, 0}; - if (mCSDSupportLevel == CSD_SUPPORT_CLIENT && - mSizeState == nsSizeMode_Normal) { - decorationSize = GetCSDDecorationSize( - gtk_window_get_window_type(GTK_WINDOW(mShell)) == GTK_WINDOW_POPUP); - } - - int width = DevicePixelsToGdkCoordRoundDown(mBounds.width); - int height = DevicePixelsToGdkCoordRoundDown(mBounds.height); - - cairo_rectangle_int_t rect = {decorationSize.left, decorationSize.top, - width, height}; - cairo_region_union_rectangle(region, &rect); // Subtract transparent corners which are used by // various Gtk themes for toplevel windows when titlebar // is rendered by gecko. - if (mDrawInTitlebar && !mIsPIPWindow && mSizeState == nsSizeMode_Normal && - !mIsTiled) { - cairo_rectangle_int_t rect = {decorationSize.left, decorationSize.top, - TITLEBAR_SHAPE_MASK_HEIGHT, - TITLEBAR_SHAPE_MASK_HEIGHT}; - cairo_region_subtract_rectangle(region, &rect); - rect = { - decorationSize.left + width - TITLEBAR_SHAPE_MASK_HEIGHT, - decorationSize.top, - TITLEBAR_SHAPE_MASK_HEIGHT, - TITLEBAR_SHAPE_MASK_HEIGHT, - }; - cairo_region_subtract_rectangle(region, &rect); + bool drawTilebarCorners = (mDrawInTitlebar && !mIsPIPWindow) && + (mSizeState == nsSizeMode_Normal && !mIsTiled); + if (mIsX11Display) { + UpdateTopLevelOpaqueRegionGtk(drawTilebarCorners); } - } - - if (mIsX11Display) { - UpdateOpaqueRegionGtk(region); - } #ifdef MOZ_WAYLAND - else { - UpdateOpaqueRegionWayland(region); - } + else { + UpdateTopLevelOpaqueRegionWayland(drawTilebarCorners); + } #endif - - if (region) { - cairo_region_destroy(region); } } nsresult nsWindow::ConfigureChildren( const nsTArray<Configuration>& aConfigurations) { // If this is a remotely updated widget we receive clipping, position, and // size information from a source other than our owner. Don't let our parent // update this information. @@ -7678,16 +7711,18 @@ GtkTextDirection nsWindow::GetTextDirect return wm.IsPhysicalLTR() ? GTK_TEXT_DIR_LTR : GTK_TEXT_DIR_RTL; } void nsWindow::LockAspectRatio(bool aShouldLock) { if (aShouldLock) { float width = (float)DevicePixelsToGdkCoordRoundDown(mBounds.width); float height = (float)DevicePixelsToGdkCoordRoundDown(mBounds.height); + // TODO - compare mShell GdkWindow size and mContainer GdkWindow size + // instead of GetCSDDecorationSize() call. if (mCSDSupportLevel == CSD_SUPPORT_CLIENT) { GtkBorder decorationSize = GetCSDDecorationSize( gtk_window_get_window_type(GTK_WINDOW(mShell)) == GTK_WINDOW_POPUP); width += decorationSize.left + decorationSize.right; height += decorationSize.top + decorationSize.bottom; } mAspectRatio = width / height;
--- a/widget/gtk/nsWindow.h +++ b/widget/gtk/nsWindow.h @@ -480,19 +480,20 @@ class nsWindow final : public nsBaseWidg void CheckForRollupDuringGrab() { CheckForRollup(0, 0, false, true); } bool GetDragInfo(mozilla::WidgetMouseEvent* aMouseEvent, GdkWindow** aWindow, gint* aButton, gint* aRootX, gint* aRootY); void ClearCachedResources(); nsIWidgetListener* GetListener(); #ifdef MOZ_WAYLAND - void UpdateOpaqueRegionWayland(cairo_region_t* aRegion); + void UpdateTopLevelOpaqueRegionWayland(bool aSubtractCorners); #endif - void UpdateOpaqueRegionGtk(cairo_region_t* aRegion); + void UpdateTopLevelOpaqueRegionGtk(bool aSubtractCorners); + void UpdatePopupOpaqueRegion(const LayoutDeviceIntRegion& aOpaqueRegion); nsWindow* GetTransientForWindowIfPopup(); bool IsHandlingTouchSequence(GdkEventSequence* aSequence); void ResizeInt(int aX, int aY, int aWidth, int aHeight, bool aMove, bool aRepaint); void NativeMoveResizeWaylandPopup(GdkPoint* aPosition, GdkRectangle* aSize);