1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:expandtab:shiftwidth=4:tabstop=4:
3  */
4 /* This Source Code Form is subject to the terms of the Mozilla Public
5  * License, v. 2.0. If a copy of the MPL was not distributed with this
6  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 /*
8  * MozContainerWayland is a wrapper over MozContainer which provides
9  * wl_surface for MozContainer widget.
10  *
11  * The widget scheme looks like:
12  *
13  *   ---------------------------------------------------------
14  *  |  mShell Gtk widget (contains wl_surface owned by Gtk+)  |
15  *  |                                                         |
16  *  |  ---------------------------------------------------    |
17  *  | | mContainer (contains wl_surface owned by Gtk+)    |   |
18  *  | |                                                   |   |
19  *  | |  ---------------------------------------------    |   |
20  *  | | | wl_subsurface (attached to wl_surface       |   |   |
21  *  | | |                of mContainer)               |   |   |
22  *  | | |                                             |   |   |
23  *  | | |                                             |   |   |
24  *  | |  ---------------------------------------------    |   |
25  *  |  ---------------------------------------------------    |
26  *   ---------------------------------------------------------
27  *
28  *  We draw to wl_subsurface owned by MozContainerWayland.
29  *  We need to wait until wl_surface of mContainer is created
30  *  and then we create and attach our wl_subsurface to it.
31  *
32  *  First wl_subsurface creation has these steps:
33  *
34  *  1) moz_container_wayland_size_allocate() handler is called when
35  *     mContainer size/position is known.
36  *     It calls moz_container_wayland_surface_create_locked(), registers
37  *     a frame callback handler
38  *     moz_container_wayland_frame_callback_handler().
39  *
40  *  2) moz_container_wayland_frame_callback_handler() is called
41  *     when wl_surface owned by mozContainer is ready.
42  *     We call initial_draw_cbs() handler and we can create our wl_subsurface
43  *     on top of wl_surface owned by mozContainer.
44  *
45  *  When MozContainer hides/show again, moz_container_wayland_size_allocate()
46  *  handler may not be called as MozContainer size is set. So after first
47  *  show/hide sequence use moz_container_wayland_map_event() to create
48  *  wl_subsurface of MozContainer.
49  */
50 
51 #include "MozContainer.h"
52 
53 #include <dlfcn.h>
54 #include <glib.h>
55 #include <stdio.h>
56 #include <wayland-egl.h>
57 
58 #include "nsGtkUtils.h"
59 #include "nsWaylandDisplay.h"
60 
61 #ifdef MOZ_LOGGING
62 
63 #  include "mozilla/Logging.h"
64 #  include "nsTArray.h"
65 #  include "Units.h"
66 #  include "nsWindow.h"
67 extern mozilla::LazyLogModule gWidgetWaylandLog;
68 #  define LOGWAYLAND(args) \
69     MOZ_LOG(gWidgetWaylandLog, mozilla::LogLevel::Debug, args)
70 #else
71 #  define LOGWAYLAND(args)
72 #endif /* MOZ_LOGGING */
73 
74 using namespace mozilla;
75 using namespace mozilla::widget;
76 
77 /* init methods */
78 static void moz_container_wayland_destroy(GtkWidget* widget);
79 
80 /* widget class methods */
81 static void moz_container_wayland_map(GtkWidget* widget);
82 static gboolean moz_container_wayland_map_event(GtkWidget* widget,
83                                                 GdkEventAny* event);
84 static void moz_container_wayland_unmap(GtkWidget* widget);
85 static void moz_container_wayland_size_allocate(GtkWidget* widget,
86                                                 GtkAllocation* allocation);
87 static bool moz_container_wayland_surface_create_locked(
88     MozContainer* container);
89 static void moz_container_wayland_set_scale_factor_locked(
90     MozContainer* container);
91 static void moz_container_wayland_set_opaque_region_locked(
92     MozContainer* container);
93 
moz_container_get_nsWindow(MozContainer * container)94 static nsWindow* moz_container_get_nsWindow(MozContainer* container) {
95   gpointer user_data = g_object_get_data(G_OBJECT(container), "nsWindow");
96   return static_cast<nsWindow*>(user_data);
97 }
98 
99 // Imlemented in MozContainer.cpp
100 void moz_container_realize(GtkWidget* widget);
101 
102 // Invalidate gtk wl_surface to commit changes to wl_subsurface.
103 // wl_subsurface changes are effective when parent surface is commited.
moz_container_wayland_invalidate(MozContainer * container)104 static void moz_container_wayland_invalidate(MozContainer* container) {
105   LOGWAYLAND(("moz_container_wayland_invalidate [%p]\n", (void*)container));
106 
107   GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(container));
108   if (!window) {
109     LOGWAYLAND(("    Failed - missing GdkWindow!\n"));
110     return;
111   }
112 
113   GdkRectangle rect = (GdkRectangle){0, 0, gdk_window_get_width(window),
114                                      gdk_window_get_height(window)};
115   gdk_window_invalidate_rect(window, &rect, true);
116 }
117 
118 // Route input to parent wl_surface owned by Gtk+ so we get input
119 // events from Gtk+.
moz_container_clear_input_region(MozContainer * container)120 static void moz_container_clear_input_region(MozContainer* container) {
121   struct wl_compositor* compositor = WaylandDisplayGet()->GetCompositor();
122   MozContainerWayland* wl_container = &container->wl_container;
123   wl_region* region = wl_compositor_create_region(compositor);
124   wl_surface_set_input_region(wl_container->surface, region);
125   wl_region_destroy(region);
126 }
127 
moz_container_wayland_move_locked(MozContainer * container,int dx,int dy)128 static void moz_container_wayland_move_locked(MozContainer* container, int dx,
129                                               int dy) {
130   LOGWAYLAND(
131       ("moz_container_wayland_move [%p] %d,%d\n", (void*)container, dx, dy));
132 
133   MozContainerWayland* wl_container = &container->wl_container;
134 
135   if (wl_container->subsurface_dx == dx && wl_container->subsurface_dy == dy) {
136     return;
137   }
138 
139   wl_container->subsurface_dx = dx;
140   wl_container->subsurface_dy = dy;
141   wl_subsurface_set_position(wl_container->subsurface,
142                              wl_container->subsurface_dx,
143                              wl_container->subsurface_dy);
144 }
145 
146 // This is called from layout/compositor code only with
147 // size equal to GL rendering context. Otherwise there are
148 // rendering artifacts as wl_egl_window size does not match
149 // GL rendering pipeline setup.
moz_container_wayland_egl_window_set_size(MozContainer * container,int width,int height)150 void moz_container_wayland_egl_window_set_size(MozContainer* container,
151                                                int width, int height) {
152   MozContainerWayland* wl_container = &container->wl_container;
153   MutexAutoLock lock(*wl_container->container_lock);
154   if (wl_container->eglwindow) {
155     wl_egl_window_resize(wl_container->eglwindow, width, height, 0, 0);
156   }
157 }
158 
moz_container_wayland_class_init(MozContainerClass * klass)159 void moz_container_wayland_class_init(MozContainerClass* klass) {
160   /*GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
161     GtkObjectClass *object_class = GTK_OBJECT_CLASS (klass); */
162   GtkWidgetClass* widget_class = GTK_WIDGET_CLASS(klass);
163 
164   widget_class->map = moz_container_wayland_map;
165   widget_class->map_event = moz_container_wayland_map_event;
166   widget_class->destroy = moz_container_wayland_destroy;
167   widget_class->unmap = moz_container_wayland_unmap;
168   widget_class->realize = moz_container_realize;
169   widget_class->size_allocate = moz_container_wayland_size_allocate;
170 }
171 
moz_container_wayland_init(MozContainerWayland * container)172 void moz_container_wayland_init(MozContainerWayland* container) {
173   container->surface = nullptr;
174   container->subsurface = nullptr;
175   container->eglwindow = nullptr;
176   container->frame_callback_handler = nullptr;
177   container->viewport = nullptr;
178   container->ready_to_draw = false;
179   container->opaque_region_needs_updates = false;
180   container->opaque_region_subtract_corners = false;
181   container->opaque_region_used = false;
182   container->surface_needs_clear = true;
183   container->container_remapped = true;
184   container->subsurface_dx = 0;
185   container->subsurface_dy = 0;
186   container->before_first_size_alloc = true;
187   container->buffer_scale = 1;
188   container->initial_draw_cbs.clear();
189   container->container_lock = new mozilla::Mutex("MozContainer lock");
190 }
191 
moz_container_wayland_destroy(GtkWidget * widget)192 static void moz_container_wayland_destroy(GtkWidget* widget) {
193   MozContainerWayland* container = &MOZ_CONTAINER(widget)->wl_container;
194   delete container->container_lock;
195   container->container_lock = nullptr;
196   container->initial_draw_cbs.clear();
197 }
198 
moz_container_wayland_add_initial_draw_callback(MozContainer * container,const std::function<void (void)> & initial_draw_cb)199 void moz_container_wayland_add_initial_draw_callback(
200     MozContainer* container, const std::function<void(void)>& initial_draw_cb) {
201   container->wl_container.initial_draw_cbs.push_back(initial_draw_cb);
202 }
203 
moz_container_wayland_frame_callback_handler(void * data,struct wl_callback * callback,uint32_t time)204 static void moz_container_wayland_frame_callback_handler(
205     void* data, struct wl_callback* callback, uint32_t time) {
206   MozContainerWayland* wl_container = &MOZ_CONTAINER(data)->wl_container;
207 
208   LOGWAYLAND(
209       ("%s [%p] frame_callback_handler %p ready_to_draw %d (set to true)"
210        " initial_draw callback %zd\n",
211        __FUNCTION__, (void*)MOZ_CONTAINER(data),
212        (void*)wl_container->frame_callback_handler, wl_container->ready_to_draw,
213        wl_container->initial_draw_cbs.size()));
214 
215   g_clear_pointer(&wl_container->frame_callback_handler, wl_callback_destroy);
216 
217   if (!wl_container->ready_to_draw) {
218     wl_container->ready_to_draw = true;
219     for (auto const& cb : wl_container->initial_draw_cbs) {
220       cb();
221     }
222     wl_container->initial_draw_cbs.clear();
223   }
224 }
225 
226 static const struct wl_callback_listener moz_container_frame_listener = {
227     moz_container_wayland_frame_callback_handler};
228 
after_frame_clock_after_paint(GdkFrameClock * clock,MozContainer * container)229 static void after_frame_clock_after_paint(GdkFrameClock* clock,
230                                           MozContainer* container) {
231   struct wl_surface* surface = moz_container_wayland_surface_lock(container);
232   if (surface) {
233     wl_surface_commit(surface);
234     moz_container_wayland_surface_unlock(container, &surface);
235   }
236 }
237 
moz_gdk_wayland_window_add_frame_callback_surface_locked(MozContainer * container)238 static bool moz_gdk_wayland_window_add_frame_callback_surface_locked(
239     MozContainer* container) {
240   static auto sGdkWaylandWindowAddCallbackSurface =
241       (void (*)(GdkWindow*, struct wl_surface*))dlsym(
242           RTLD_DEFAULT, "gdk_wayland_window_add_frame_callback_surface");
243 
244   if (!StaticPrefs::widget_wayland_opaque_region_enabled_AtStartup() ||
245       !sGdkWaylandWindowAddCallbackSurface) {
246     return false;
247   }
248 
249   GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(container));
250   MozContainerWayland* wl_container = &container->wl_container;
251 
252   sGdkWaylandWindowAddCallbackSurface(window, wl_container->surface);
253 
254   GdkFrameClock* frame_clock = gdk_window_get_frame_clock(window);
255   g_signal_connect_after(frame_clock, "after-paint",
256                          G_CALLBACK(after_frame_clock_after_paint), container);
257   return true;
258 }
259 
moz_gdk_wayland_window_remove_frame_callback_surface_locked(MozContainer * container)260 static void moz_gdk_wayland_window_remove_frame_callback_surface_locked(
261     MozContainer* container) {
262   static auto sGdkWaylandWindowRemoveCallbackSurface =
263       (void (*)(GdkWindow*, struct wl_surface*))dlsym(
264           RTLD_DEFAULT, "gdk_wayland_window_remove_frame_callback_surface");
265 
266   if (!sGdkWaylandWindowRemoveCallbackSurface) {
267     return;
268   }
269 
270   GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(container));
271   MozContainerWayland* wl_container = &container->wl_container;
272 
273   if (wl_container->surface) {
274     sGdkWaylandWindowRemoveCallbackSurface(window, wl_container->surface);
275   }
276 
277   GdkFrameClock* frame_clock = gdk_window_get_frame_clock(window);
278   g_signal_handlers_disconnect_by_func(
279       frame_clock, FuncToGpointer(after_frame_clock_after_paint), container);
280 }
281 
moz_container_wayland_unmap_internal(MozContainer * container)282 static void moz_container_wayland_unmap_internal(MozContainer* container) {
283   MozContainerWayland* wl_container = &container->wl_container;
284   MutexAutoLock lock(*wl_container->container_lock);
285 
286   LOGWAYLAND(("%s [%p]\n", __FUNCTION__, (void*)container));
287 
288   if (wl_container->opaque_region_used) {
289     moz_gdk_wayland_window_remove_frame_callback_surface_locked(container);
290   }
291 
292   g_clear_pointer(&wl_container->eglwindow, wl_egl_window_destroy);
293   g_clear_pointer(&wl_container->subsurface, wl_subsurface_destroy);
294   g_clear_pointer(&wl_container->surface, wl_surface_destroy);
295   g_clear_pointer(&wl_container->viewport, wp_viewport_destroy);
296   g_clear_pointer(&wl_container->frame_callback_handler, wl_callback_destroy);
297 
298   wl_container->surface_needs_clear = true;
299   wl_container->ready_to_draw = false;
300   wl_container->buffer_scale = 1;
301   wl_container->container_remapped = true;
302 }
303 
moz_container_wayland_map_event(GtkWidget * widget,GdkEventAny * event)304 static gboolean moz_container_wayland_map_event(GtkWidget* widget,
305                                                 GdkEventAny* event) {
306   MozContainerWayland* wl_container = &MOZ_CONTAINER(widget)->wl_container;
307   LOGWAYLAND(("%s [%p]\n", __FUNCTION__, (void*)MOZ_CONTAINER(widget)));
308 
309   // Don't create wl_subsurface in map_event when it's already created or
310   // if we create it for the first time.
311   if (wl_container->ready_to_draw || wl_container->before_first_size_alloc) {
312     return FALSE;
313   }
314 
315   MutexAutoLock lock(*wl_container->container_lock);
316   if (!wl_container->surface) {
317     if (!moz_container_wayland_surface_create_locked(MOZ_CONTAINER(widget))) {
318       return FALSE;
319     }
320   }
321 
322   moz_container_wayland_set_scale_factor_locked(MOZ_CONTAINER(widget));
323   moz_container_wayland_set_opaque_region_locked(MOZ_CONTAINER(widget));
324   moz_container_clear_input_region(MOZ_CONTAINER(widget));
325   moz_container_wayland_invalidate(MOZ_CONTAINER(widget));
326   return FALSE;
327 }
328 
moz_container_wayland_map(GtkWidget * widget)329 void moz_container_wayland_map(GtkWidget* widget) {
330   LOGWAYLAND(("%s [%p]\n", __FUNCTION__, (void*)widget));
331 
332   g_return_if_fail(IS_MOZ_CONTAINER(widget));
333   gtk_widget_set_mapped(widget, TRUE);
334 
335   if (gtk_widget_get_has_window(widget)) {
336     gdk_window_show(gtk_widget_get_window(widget));
337   }
338 }
339 
moz_container_wayland_unmap(GtkWidget * widget)340 void moz_container_wayland_unmap(GtkWidget* widget) {
341   LOGWAYLAND(("%s [%p]\n", __FUNCTION__, (void*)widget));
342 
343   g_return_if_fail(IS_MOZ_CONTAINER(widget));
344   gtk_widget_set_mapped(widget, FALSE);
345 
346   if (gtk_widget_get_has_window(widget)) {
347     gdk_window_hide(gtk_widget_get_window(widget));
348     moz_container_wayland_unmap_internal(MOZ_CONTAINER(widget));
349   }
350 }
351 
moz_container_wayland_size_allocate(GtkWidget * widget,GtkAllocation * allocation)352 void moz_container_wayland_size_allocate(GtkWidget* widget,
353                                          GtkAllocation* allocation) {
354   MozContainer* container;
355   GtkAllocation tmp_allocation;
356 
357   g_return_if_fail(IS_MOZ_CONTAINER(widget));
358 
359   LOGWAYLAND(("moz_container_wayland_size_allocate [%p] %d,%d -> %d x %d\n",
360               (void*)widget, allocation->x, allocation->y, allocation->width,
361               allocation->height));
362 
363   /* short circuit if you can */
364   container = MOZ_CONTAINER(widget);
365   gtk_widget_get_allocation(widget, &tmp_allocation);
366   if (!container->children && tmp_allocation.x == allocation->x &&
367       tmp_allocation.y == allocation->y &&
368       tmp_allocation.width == allocation->width &&
369       tmp_allocation.height == allocation->height) {
370     return;
371   }
372   gtk_widget_set_allocation(widget, allocation);
373 
374   if (gtk_widget_get_has_window(widget) && gtk_widget_get_realized(widget)) {
375     gdk_window_move_resize(gtk_widget_get_window(widget), allocation->x,
376                            allocation->y, allocation->width,
377                            allocation->height);
378     // We need to position our subsurface according to GdkWindow
379     // when offset changes (GdkWindow is maximized for instance).
380     // see gtk-clutter-embed.c for reference.
381     MutexAutoLock lock(*container->wl_container.container_lock);
382     if (!container->wl_container.surface) {
383       if (!moz_container_wayland_surface_create_locked(container)) {
384         return;
385       }
386     }
387     moz_container_wayland_set_scale_factor_locked(container);
388     moz_container_wayland_set_opaque_region_locked(container);
389     moz_container_wayland_move_locked(container, allocation->x, allocation->y);
390     moz_container_clear_input_region(container);
391     moz_container_wayland_invalidate(MOZ_CONTAINER(widget));
392     container->wl_container.before_first_size_alloc = false;
393   }
394 }
395 
moz_container_wayland_create_opaque_region(int aX,int aY,int aWidth,int aHeight,bool aSubtractCorners)396 static wl_region* moz_container_wayland_create_opaque_region(
397     int aX, int aY, int aWidth, int aHeight, bool aSubtractCorners) {
398   struct wl_compositor* compositor = WaylandDisplayGet()->GetCompositor();
399   wl_region* region = wl_compositor_create_region(compositor);
400   wl_region_add(region, aX, aY, aWidth, aHeight);
401   if (aSubtractCorners) {
402     wl_region_subtract(region, aX, aY, TITLEBAR_SHAPE_MASK_HEIGHT,
403                        TITLEBAR_SHAPE_MASK_HEIGHT);
404     wl_region_subtract(region, aX + aWidth - TITLEBAR_SHAPE_MASK_HEIGHT, aY,
405                        TITLEBAR_SHAPE_MASK_HEIGHT, TITLEBAR_SHAPE_MASK_HEIGHT);
406   }
407   return region;
408 }
409 
moz_container_wayland_set_opaque_region_locked(MozContainer * container)410 static void moz_container_wayland_set_opaque_region_locked(
411     MozContainer* container) {
412   MozContainerWayland* wl_container = &container->wl_container;
413 
414   if (!wl_container->opaque_region_needs_updates) {
415     return;
416   }
417 
418   if (!wl_container->opaque_region_used) {
419     wl_container->opaque_region_needs_updates = false;
420     return;
421   }
422 
423   GtkAllocation allocation;
424   gtk_widget_get_allocation(GTK_WIDGET(container), &allocation);
425 
426   wl_region* region = moz_container_wayland_create_opaque_region(
427       0, 0, allocation.width, allocation.height,
428       wl_container->opaque_region_subtract_corners);
429   wl_surface_set_opaque_region(wl_container->surface, region);
430   wl_region_destroy(region);
431   wl_container->opaque_region_needs_updates = false;
432 }
433 
moz_container_wayland_set_opaque_region(MozContainer * container)434 static void moz_container_wayland_set_opaque_region(MozContainer* container) {
435   MozContainerWayland* wl_container = &container->wl_container;
436   MutexAutoLock lock(*wl_container->container_lock);
437   if (wl_container->surface) {
438     moz_container_wayland_set_opaque_region_locked(container);
439   }
440 }
441 
moz_container_wayland_set_scale_factor_locked(MozContainer * container)442 static void moz_container_wayland_set_scale_factor_locked(
443     MozContainer* container) {
444   MozContainerWayland* wl_container = &container->wl_container;
445   nsWindow* window = moz_container_get_nsWindow(container);
446 
447   if (window && window->UseFractionalScale()) {
448     if (!wl_container->viewport) {
449       wl_container->viewport = wp_viewporter_get_viewport(
450           WaylandDisplayGet()->GetViewporter(), wl_container->surface);
451     }
452 
453     GdkWindow* gdkWindow = gtk_widget_get_window(GTK_WIDGET(container));
454     wp_viewport_set_destination(wl_container->viewport,
455                                 gdk_window_get_width(gdkWindow),
456                                 gdk_window_get_height(gdkWindow));
457   } else {
458     int scale = window ? window->GdkCeiledScaleFactor() : 1;
459 
460     if (scale == wl_container->buffer_scale) {
461       return;
462     }
463 
464     LOGWAYLAND(("%s [%p] scale %d\n", __FUNCTION__, (void*)container, scale));
465     wl_surface_set_buffer_scale(wl_container->surface, scale);
466     wl_container->buffer_scale = scale;
467   }
468 }
469 
moz_container_wayland_set_scale_factor(MozContainer * container)470 void moz_container_wayland_set_scale_factor(MozContainer* container) {
471   MutexAutoLock lock(*container->wl_container.container_lock);
472   if (container->wl_container.surface) {
473     moz_container_wayland_set_scale_factor_locked(container);
474   }
475 }
476 
moz_container_wayland_surface_create_locked(MozContainer * container)477 static bool moz_container_wayland_surface_create_locked(
478     MozContainer* container) {
479   MozContainerWayland* wl_container = &container->wl_container;
480 
481   LOGWAYLAND(("%s [%p]\n", __FUNCTION__, (void*)container));
482 
483   GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(container));
484   wl_surface* parent_surface = gdk_wayland_window_get_wl_surface(window);
485   if (!parent_surface) {
486     LOGWAYLAND(("    Failed - missing parent surface!"));
487     return false;
488   }
489   LOGWAYLAND(("    gtk wl_surface %p ID %d\n", (void*)parent_surface,
490               wl_proxy_get_id((struct wl_proxy*)parent_surface)));
491 
492   // Available as of GTK 3.8+
493   struct wl_compositor* compositor = WaylandDisplayGet()->GetCompositor();
494   wl_container->surface = wl_compositor_create_surface(compositor);
495   if (!wl_container->surface) {
496     LOGWAYLAND(("    Failed - can't create surface!"));
497     return false;
498   }
499 
500   wl_container->subsurface =
501       wl_subcompositor_get_subsurface(WaylandDisplayGet()->GetSubcompositor(),
502                                       wl_container->surface, parent_surface);
503   if (!wl_container->subsurface) {
504     g_clear_pointer(&wl_container->surface, wl_surface_destroy);
505     LOGWAYLAND(("    Failed - can't create sub-surface!"));
506     return false;
507   }
508   wl_subsurface_set_desync(wl_container->subsurface);
509 
510   // Try to guess subsurface offset to avoid potential flickering.
511   int dx, dy;
512   if (moz_container_get_nsWindow(container)->GetCSDDecorationOffset(&dx, &dy)) {
513     wl_container->subsurface_dx = dx;
514     wl_container->subsurface_dy = dy;
515     wl_subsurface_set_position(wl_container->subsurface, dx, dy);
516     LOGWAYLAND(("    guessing subsurface position %d %d\n", dx, dy));
517   }
518 
519   // If there's pending frame callback it's for wrong parent surface,
520   // so delete it.
521   if (wl_container->frame_callback_handler) {
522     g_clear_pointer(&wl_container->frame_callback_handler, wl_callback_destroy);
523   }
524   wl_container->frame_callback_handler = wl_surface_frame(parent_surface);
525   wl_callback_add_listener(wl_container->frame_callback_handler,
526                            &moz_container_frame_listener, container);
527   LOGWAYLAND((
528       "    created frame callback ID %d\n",
529       wl_proxy_get_id((struct wl_proxy*)wl_container->frame_callback_handler)));
530 
531   wl_surface_commit(wl_container->surface);
532   wl_display_flush(WaylandDisplayGet()->GetDisplay());
533 
534   wl_container->opaque_region_used =
535       moz_gdk_wayland_window_add_frame_callback_surface_locked(container);
536 
537   LOGWAYLAND(("    created surface %p ID %d\n", (void*)wl_container->surface,
538               wl_proxy_get_id((struct wl_proxy*)wl_container->surface)));
539   return true;
540 }
541 
moz_container_wayland_surface_lock(MozContainer * container)542 struct wl_surface* moz_container_wayland_surface_lock(MozContainer* container) {
543   // Temporary disabled to avoid log noise
544   //  LOGWAYLAND(("%s [%p] surface %p ready_to_draw %d\n", __FUNCTION__,
545   //              (void*)container, (void*)container->wl_container.surface,
546   //              container->wl_container.ready_to_draw));
547   if (!container->wl_container.surface ||
548       !container->wl_container.ready_to_draw) {
549     return nullptr;
550   }
551 
552   container->wl_container.container_lock->Lock();
553 
554   moz_container_wayland_set_scale_factor_locked(container);
555   return container->wl_container.surface;
556 }
557 
moz_container_wayland_surface_unlock(MozContainer * container,struct wl_surface ** surface)558 void moz_container_wayland_surface_unlock(MozContainer* container,
559                                           struct wl_surface** surface) {
560   // Temporary disabled to avoid log noise
561   //  LOGWAYLAND(("%s [%p] surface %p\n", __FUNCTION__, (void*)container,
562   //              (void*)container->wl_container.surface));
563   if (*surface) {
564     container->wl_container.container_lock->Unlock();
565     *surface = nullptr;
566   }
567 }
568 
moz_container_wayland_get_egl_window(MozContainer * container,double scale)569 struct wl_egl_window* moz_container_wayland_get_egl_window(
570     MozContainer* container, double scale) {
571   MozContainerWayland* wl_container = &container->wl_container;
572 
573   LOGWAYLAND(("%s [%p] eglwindow %p\n", __FUNCTION__, (void*)container,
574               (void*)wl_container->eglwindow));
575 
576   MutexAutoLock lock(*wl_container->container_lock);
577   if (!wl_container->surface || !wl_container->ready_to_draw) {
578     return nullptr;
579   }
580   if (!wl_container->eglwindow) {
581     GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(container));
582     wl_container->eglwindow = wl_egl_window_create(
583         wl_container->surface, (int)round(gdk_window_get_width(window) * scale),
584         (int)round(gdk_window_get_height(window) * scale));
585 
586     LOGWAYLAND(("%s [%p] created eglwindow %p\n", __FUNCTION__,
587                 (void*)container, (void*)wl_container->eglwindow));
588   }
589   return wl_container->eglwindow;
590 }
591 
moz_container_wayland_has_egl_window(MozContainer * container)592 gboolean moz_container_wayland_has_egl_window(MozContainer* container) {
593   return container->wl_container.eglwindow != nullptr;
594 }
595 
moz_container_wayland_surface_needs_clear(MozContainer * container)596 gboolean moz_container_wayland_surface_needs_clear(MozContainer* container) {
597   int ret = container->wl_container.surface_needs_clear;
598   container->wl_container.surface_needs_clear = false;
599   return ret;
600 }
601 
moz_container_wayland_get_and_reset_remapped(MozContainer * container)602 gboolean moz_container_wayland_get_and_reset_remapped(MozContainer* container) {
603   int ret = container->wl_container.container_remapped;
604   container->wl_container.container_remapped = false;
605   return ret;
606 }
607 
moz_container_wayland_update_opaque_region(MozContainer * container,bool aSubtractCorners)608 void moz_container_wayland_update_opaque_region(MozContainer* container,
609                                                 bool aSubtractCorners) {
610   MozContainerWayland* wl_container = &container->wl_container;
611   wl_container->opaque_region_needs_updates = true;
612   wl_container->opaque_region_subtract_corners = aSubtractCorners;
613 
614   // When GL compositor / WebRender is used,
615   // moz_container_wayland_get_egl_window() is called only once when window
616   // is created or resized so update opaque region now.
617   if (moz_container_wayland_has_egl_window(container)) {
618     moz_container_wayland_set_opaque_region(container);
619   }
620 }
621 
moz_container_wayland_can_draw(MozContainer * container)622 gboolean moz_container_wayland_can_draw(MozContainer* container) {
623   return container ? container->wl_container.ready_to_draw : false;
624 }
625 
moz_container_wayland_get_scale(MozContainer * container)626 double moz_container_wayland_get_scale(MozContainer* container) {
627   MozContainerWayland* wl_container = &container->wl_container;
628   MutexAutoLock lock(*wl_container->container_lock);
629 
630   nsWindow* window = moz_container_get_nsWindow(container);
631   return window ? window->FractionalScaleFactor() : 1;
632 }
633 
moz_container_wayland_get_viewport(MozContainer * container)634 struct wp_viewport* moz_container_wayland_get_viewport(
635     MozContainer* container) {
636   MozContainerWayland* wl_container = &container->wl_container;
637   MutexAutoLock lock(*wl_container->container_lock);
638 
639   if (!wl_container->viewport) {
640     wl_container->viewport = wp_viewporter_get_viewport(
641         WaylandDisplayGet()->GetViewporter(), wl_container->surface);
642   }
643   return wl_container->viewport;
644 }
645