⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 197062 in webkit


Ignore:
Timestamp:
Feb 24, 2016, 11:37:40 PM (11 years ago)
Author:
Carlos Garcia Campos
Message:

[GTK] Tearing when entering AC mode
​https://bugs.webkit.org/show_bug.cgi?id=150955

Reviewed by Michael Catanzaro.

Source/WebCore:

  • platform/gtk/GtkUtilities.cpp:

(WebCore::widgetIsOnscreenToplevelWindow): Allow passing nullptr.

Source/WebKit2:

When entering accelerated compositing mode, we keep rendering the
non accelerated contents until we have the first frame of
accelerated compositing contents. When the view is created hidden,
for example when the browser opens a link in a new tab, the view
is not realized until it is mapped. The native surface handle for
compositing, needed by the web process to render accelerated
compositing contents, is not available until the view is realized,
because it depends on the properties of the parent. When a web
view is mapped for the first time, and then realized, we send the
native surface handle for compositing to the web process, and keep
rendering the non composited contents until we get the first
frame, but in this case we never had non composited contents and
we end up rendering an untinitalized surface. This sometimes just
produces flickering and sometimes rendering artifacts.
We can prevent this from happening by realizing the web view as
soon as possible. A GtkWidget can't be realized until it has been
added to a toplevel, so we can realize our view right after it is
added to a toplevel window, and wait until the view is actually
mapped to notify the web process that it has been added to a
window. This way can we enter accelerated compositing mode before
the web view is mapped, so that when mapped we don't try to paint
the previous contents and don't need to wait for the first frame.

  • UIProcess/API/gtk/WebKitWebViewBase.cpp:

(toplevelWindowFocusInEvent): Handle the case of the window being
hidden when receiving focus in. According to
gtk_window_focus_in_event, this can happen.
(webkitWebViewBaseSetToplevelOnScreenWindow): When the web view is
removed from its toplevel parent, update the IsInWindow and
WindowIsActive flags accordingly. When the view is added to a
toplevel, realize it and don't update the window flags, they will be
updated when the view is mapped the first time.
(webkitWebViewBaseMap): Also update IsInWindow and WindowIsActive
flags if needed. This way, if for example you open a youtube video
in a new tab, the video won't start playing until you visit the
tab, like we did when the view was realized on map.
(webkitWebViewBaseHierarchyChanged): Use hierarchy-changed signal
instead of parent-set to be notified when the view is added to or
removed from a toplevel.
(webkit_web_view_base_class_init): Implement hierarchy-changed
instead of parent-set.
(webkitWebViewBaseRealize): Do not call
webkitWebViewBaseSetToplevelOnScreenWindow on realize, it's now
webkitWebViewBaseSetToplevelOnScreenWindow the one realizing the view.

  • UIProcess/cairo/BackingStoreCairo.cpp:

(WebKit::BackingStore::createBackend): Do not realize the view
here, it should be realized already at this point. If it's not
realized at this point is because it hasn't been added to a
toplevel and gtk_widget_realize will not work anyway.
(WebKit::BackingStore::paint): This is changing the cairo source
operator, so save/restore the cairo context to ensure it doesn't
affect other drawing done after this.

Location:
trunk/Source
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r197060 r197062  
     12016-02-24  Carlos Garcia Campos  <cgarcia@igalia.com>
     2
     3        [GTK] Tearing when entering AC mode
     4        https://bugs.webkit.org/show_bug.cgi?id=150955
     5
     6        Reviewed by Michael Catanzaro.
     7
     8        * platform/gtk/GtkUtilities.cpp:
     9        (WebCore::widgetIsOnscreenToplevelWindow): Allow passing nullptr.
     10
    1112016-02-24  Chris Dumez  <cdumez@apple.com>
    212
  • trunk/Source/WebCore/platform/gtk/GtkUtilities.cpp

    r185502 r197062  
    5252bool widgetIsOnscreenToplevelWindow(GtkWidget* widget)
    5353{
    54     return gtk_widget_is_toplevel(widget) && GTK_IS_WINDOW(widget) && !GTK_IS_OFFSCREEN_WINDOW(widget);
     54    return widget && gtk_widget_is_toplevel(widget) && GTK_IS_WINDOW(widget) && !GTK_IS_OFFSCREEN_WINDOW(widget);
    5555}
    5656
  • trunk/Source/WebKit2/ChangeLog

    r197058 r197062  
     12016-02-24  Carlos Garcia Campos  <cgarcia@igalia.com>
     2
     3        [GTK] Tearing when entering AC mode
     4        https://bugs.webkit.org/show_bug.cgi?id=150955
     5
     6        Reviewed by Michael Catanzaro.
     7
     8        When entering accelerated compositing mode, we keep rendering the
     9        non accelerated contents until we have the first frame of
     10        accelerated compositing contents. When the view is created hidden,
     11        for example when the browser opens a link in a new tab, the view
     12        is not realized until it is mapped. The native surface handle for
     13        compositing, needed by the web process to render accelerated
     14        compositing contents, is not available until the view is realized,
     15        because it depends on the properties of the parent. When a web
     16        view is mapped for the first time, and then realized, we send the
     17        native surface handle for compositing to the web process, and keep
     18        rendering the non composited contents until we get the first
     19        frame, but in this case we never had non composited contents and
     20        we end up rendering an untinitalized surface. This sometimes just
     21        produces flickering and sometimes rendering artifacts.
     22        We can prevent this from happening by realizing the web view as
     23        soon as possible. A GtkWidget can't be realized until it has been
     24        added to a toplevel, so we can realize our view right after it is
     25        added to a toplevel window, and wait until the view is actually
     26        mapped to notify the web process that it has been added to a
     27        window. This way can we enter accelerated compositing mode before
     28        the web view is mapped, so that when mapped we don't try to paint
     29        the previous contents and don't need to wait for the first frame.
     30
     31        * UIProcess/API/gtk/WebKitWebViewBase.cpp:
     32        (toplevelWindowFocusInEvent): Handle the case of the window being
     33        hidden when receiving focus in. According to
     34        gtk_window_focus_in_event, this can happen.
     35        (webkitWebViewBaseSetToplevelOnScreenWindow): When the web view is
     36        removed from its toplevel parent, update the IsInWindow and
     37        WindowIsActive flags accordingly. When the view is added to a
     38        toplevel, realize it and don't update the window flags, they will be
     39        updated when the view is mapped the first time.
     40        (webkitWebViewBaseMap): Also update IsInWindow and WindowIsActive
     41        flags if needed. This way, if for example you open a youtube video
     42        in a new tab, the video won't start playing until you visit the
     43        tab, like we did when the view was realized on map.
     44        (webkitWebViewBaseHierarchyChanged): Use hierarchy-changed signal
     45        instead of parent-set to be notified when the view is added to or
     46        removed from a toplevel.
     47        (webkit_web_view_base_class_init): Implement hierarchy-changed
     48        instead of parent-set.
     49        (webkitWebViewBaseRealize): Do not call
     50        webkitWebViewBaseSetToplevelOnScreenWindow on realize, it's now
     51        webkitWebViewBaseSetToplevelOnScreenWindow the one realizing the view.
     52        * UIProcess/cairo/BackingStoreCairo.cpp:
     53        (WebKit::BackingStore::createBackend): Do not realize the view
     54        here, it should be realized already at this point. If it's not
     55        realized at this point is because it hasn't been added to a
     56        toplevel and gtk_widget_realize will not work anyway.
     57        (WebKit::BackingStore::paint): This is changing the cairo source
     58        operator, so save/restore the cairo context to ensure it doesn't
     59        affect other drawing done after this.
     60
    1612016-02-24  Nikos Andronikos  <nikos.andronikos-webkit@cisra.canon.com.au>
    262
  • trunk/Source/WebKit2/UIProcess/API/gtk/WebKitWebViewBase.cpp

    r196475 r197062  
    238238}
    239239
    240 static gboolean toplevelWindowFocusInEvent(GtkWidget*, GdkEventFocus*, WebKitWebViewBase* webViewBase)
    241 {
     240static gboolean toplevelWindowFocusInEvent(GtkWidget* widget, GdkEventFocus*, WebKitWebViewBase* webViewBase)
     241{
     242    // Spurious focus in events can occur when the window is hidden.
     243    if (!gtk_widget_get_visible(widget))
     244        return FALSE;
     245
    242246    WebKitWebViewBasePrivate* priv = webViewBase->priv;
    243247    if (priv->viewState & ViewState::WindowIsActive)
    … …  
    301305
    302306    priv->toplevelOnScreenWindow = window;
    303     if (!(priv->viewState & ViewState::IsInWindow)) {
    304         priv->viewState |= ViewState::IsInWindow;
    305         webkitWebViewBaseScheduleUpdateViewState(webViewBase, ViewState::IsInWindow);
    306     }
    307     if (!priv->toplevelOnScreenWindow)
    308         return;
     307
     308    if (!priv->toplevelOnScreenWindow) {
     309        ViewState::Flags flagsToUpdate = 0;
     310        if (priv->viewState & ViewState::IsInWindow) {
     311            priv->viewState &= ~ViewState::IsInWindow;
     312            flagsToUpdate |= ViewState::IsInWindow;
     313        }
     314        if (priv->viewState & ViewState::WindowIsActive) {
     315            priv->viewState &= ~ViewState::WindowIsActive;
     316            flagsToUpdate |= ViewState::IsInWindow;
     317        }
     318        if (flagsToUpdate)
     319            webkitWebViewBaseScheduleUpdateViewState(webViewBase, flagsToUpdate);
     320
     321        return;
     322    }
    309323
    310324    priv->toplevelFocusInEventID =
    … …  
    316330    priv->toplevelWindowStateEventID =
    317331        g_signal_connect(priv->toplevelOnScreenWindow, "window-state-event", G_CALLBACK(toplevelWindowStateEvent), webViewBase);
     332    gtk_widget_realize(GTK_WIDGET(webViewBase));
    318333}
    319334
    … …  
    384399
    385400    gtk_im_context_set_client_window(priv->inputMethodFilter.context(), window);
    386 
    387     GtkWidget* toplevel = gtk_widget_get_toplevel(widget);
    388     if (widgetIsOnscreenToplevelWindow(toplevel))
    389         webkitWebViewBaseSetToplevelOnScreenWindow(webView, GTK_WINDOW(toplevel));
    390401}
    391402
    … …  
    671682    WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
    672683    WebKitWebViewBasePrivate* priv = webViewBase->priv;
    673     if (priv->viewState & ViewState::IsVisible)
    674         return;
    675 
    676     priv->viewState |= ViewState::IsVisible;
    677     webkitWebViewBaseScheduleUpdateViewState(webViewBase, ViewState::IsVisible);
     684    ViewState::Flags flagsToUpdate = 0;
     685    if (!(priv->viewState & ViewState::IsVisible))
     686        flagsToUpdate |= ViewState::IsVisible;
     687    if (priv->toplevelOnScreenWindow) {
     688        if (!(priv->viewState & ViewState::IsInWindow))
     689            flagsToUpdate |= ViewState::IsInWindow;
     690        if (gtk_window_is_active(GTK_WINDOW(priv->toplevelOnScreenWindow)) && !(priv->viewState & ViewState::WindowIsActive))
     691            flagsToUpdate |= ViewState::WindowIsActive;
     692    }
     693    if (!flagsToUpdate)
     694        return;
     695
     696    priv->viewState |= flagsToUpdate;
     697    webkitWebViewBaseScheduleUpdateViewState(webViewBase, flagsToUpdate);
    678698}
    679699
    … …  
    10731093#endif // ENABLE(DRAG_SUPPORT)
    10741094
    1075 static void webkitWebViewBaseParentSet(GtkWidget* widget, GtkWidget* /* oldParent */)
    1076 {
    1077     if (!gtk_widget_get_parent(widget))
    1078         webkitWebViewBaseSetToplevelOnScreenWindow(WEBKIT_WEB_VIEW_BASE(widget), 0);
     1095static void webkitWebViewBaseHierarchyChanged(GtkWidget* widget, GtkWidget* oldToplevel)
     1096{
     1097    WebKitWebViewBasePrivate* priv = WEBKIT_WEB_VIEW_BASE(widget)->priv;
     1098    if (widgetIsOnscreenToplevelWindow(oldToplevel) && GTK_WINDOW(oldToplevel) == priv->toplevelOnScreenWindow) {
     1099        webkitWebViewBaseSetToplevelOnScreenWindow(WEBKIT_WEB_VIEW_BASE(widget), nullptr);
     1100        return;
     1101    }
     1102
     1103    if (!oldToplevel) {
     1104        GtkWidget* toplevel = gtk_widget_get_toplevel(widget);
     1105        if (widgetIsOnscreenToplevelWindow(toplevel))
     1106            webkitWebViewBaseSetToplevelOnScreenWindow(WEBKIT_WEB_VIEW_BASE(widget), GTK_WINDOW(toplevel));
     1107    }
    10791108}
    10801109
    … …  
    11351164#endif // ENABLE(DRAG_SUPPORT)
    11361165    widgetClass->get_accessible = webkitWebViewBaseGetAccessible;
    1137     widgetClass->parent_set = webkitWebViewBaseParentSet;
     1166    widgetClass->hierarchy_changed = webkitWebViewBaseHierarchyChanged;
    11381167    widgetClass->destroy = webkitWebViewBaseDestroy;
    11391168
  • trunk/Source/WebKit2/UIProcess/cairo/BackingStoreCairo.cpp

    r192140 r197062  
    6868
    6969#if PLATFORM(GTK)
    70     GtkWidget* viewWidget = m_webPageProxy.viewWidget();
    71     gtk_widget_realize(viewWidget);
    72     RefPtr<cairo_surface_t> surface = adoptRef(gdk_window_create_similar_surface(gtk_widget_get_window(viewWidget),
     70    RefPtr<cairo_surface_t> surface = adoptRef(gdk_window_create_similar_surface(gtk_widget_get_window(m_webPageProxy.viewWidget()),
    7371        CAIRO_CONTENT_COLOR_ALPHA, scaledSize.width(), scaledSize.height()));
    7472#else
    … …  
    8482    ASSERT(m_backend);
    8583
     84    cairo_save(context);
    8685    cairo_set_operator(context, CAIRO_OPERATOR_SOURCE);
    8786    cairo_set_source_surface(context, m_backend->surface(), 0, 0);
    8887    cairo_rectangle(context, rect.x(), rect.y(), rect.width(), rect.height());
    8988    cairo_fill(context);
     89    cairo_restore(context);
    9090}
    9191
Note: See TracChangeset for help on using the changeset viewer.