[GTK] Using a native window for the WebView breaks GtkOverlay
authormrobinson@webkit.org <mrobinson@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 21 Aug 2012 20:29:16 +0000 (20:29 +0000)
committermrobinson@webkit.org <mrobinson@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 21 Aug 2012 20:29:16 +0000 (20:29 +0000)
https://bugs.webkit.org/show_bug.cgi?id=90085

Reviewed by Alejandro G. Castro.

.:

* configure.ac: Parse xcomposite pkg-config file during configuration.

Source/WebCore:

No new tests. This will be covered by pixel test for accelerated
compositing when they are activated.

* GNUmakefile.am: Add XComposite libraries to the linker list.
* GNUmakefile.list.am: Add RedirectedXCompositeWindow files to the source list.
Make a new section for GLX specific files.
* platform/graphics/glx/GLContextGLX.cpp:
(WebCore::GLContextGLX::sharedDisplay): Expose sharedDisplay as a static method
so that it can be called by other X11 specific code.
* platform/graphics/glx/GLContextGLX.h: Ditto.
* platform/gtk/RedirectedXCompositeWindow.cpp: Added. An implementation of a GL surface
that renders to an X-window which redirects to a pixmap.
* platform/gtk/RedirectedXCompositeWindow.h: Added.

Source/WebKit/gtk:

Rewrite AcceleratedCompositingContext for TextureMapperGL to be more similar to
the WebKit2 LayerTreeHost and switch from rendering directly to the widget window
to a window redirected to a pixmap via XComposite. The AcceleratedCompositingContext
now handles painting the non-composited content itself and no longer relies on the
ChromeClient backing store.

This fixes issues with using GtkOverlay WebKitWebView as well as making it possible
to run pixel tests with accelerated compositing turned on.

* WebCoreSupport/AcceleratedCompositingContext.h:
(AcceleratedCompositingContext):
* WebCoreSupport/AcceleratedCompositingContextGL.cpp:
Rename some methods to make them more similar to LayerTreeHost. Now we wait to render
the OpenGL context to the window until the widget's draw signal. Escape out of all
methods early if accelerated compositing is disabled.
* WebCoreSupport/ChromeClientGtk.cpp: Always check if accelerated compositing is on
before calling into AcceleratedCompositingContext methods. When AC is on, never paint
the backing store, deferring immediately to the AcceleratedCompositingContext. When
AC is turned on the backing store now shrinks to a small size to save memory.
* webkit/webkitwebview.cpp:
(resizeWebViewFromAllocation): ChromeClient is now responsible for talking to the
AcceleratedCompositingContext directly.
(webkit_web_view_size_allocate): Exit early if the allocation is not a resize. This
makes some deeper logic a bit simpler and avoids accidentally doing too much work for
widget movement.
(webkit_web_view_realize): We no longer need a native window.

Source/WebKit2:

Add XComposite libraries to the linker list for WebKit2.

* GNUmakefile.am: Add XComposite

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@126182 268f45cc-cd09-0410-ab3c-d52691b4dbfc

18 files changed:
ChangeLog
Source/WebCore/ChangeLog
Source/WebCore/GNUmakefile.am
Source/WebCore/GNUmakefile.list.am
Source/WebCore/platform/graphics/glx/GLContextGLX.cpp
Source/WebCore/platform/graphics/glx/GLContextGLX.h
Source/WebCore/platform/gtk/RedirectedXCompositeWindow.cpp [new file with mode: 0644]
Source/WebCore/platform/gtk/RedirectedXCompositeWindow.h [new file with mode: 0644]
Source/WebKit/gtk/ChangeLog
Source/WebKit/gtk/GNUmakefile.am
Source/WebKit/gtk/WebCoreSupport/AcceleratedCompositingContext.h
Source/WebKit/gtk/WebCoreSupport/AcceleratedCompositingContextGL.cpp
Source/WebKit/gtk/WebCoreSupport/ChromeClientGtk.cpp
Source/WebKit/gtk/WebCoreSupport/ChromeClientGtk.h
Source/WebKit/gtk/webkit/webkitwebview.cpp
Source/WebKit2/ChangeLog
Source/WebKit2/GNUmakefile.am
configure.ac

index 53349ef..f3aba42 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2012-08-21  Martin Robinson  <mrobinson@igalia.com>
+
+        [GTK] Using a native window for the WebView breaks GtkOverlay
+        https://bugs.webkit.org/show_bug.cgi?id=90085
+
+        Reviewed by Alejandro G. Castro.
+
+        * configure.ac: Parse xcomposite pkg-config file during configuration.
+
 2012-08-21  Patrick Gansterer  <paroga@webkit.org>
 
         Build fix for WinCE after r115348.
index f80d89b..dc47ced 100644 (file)
@@ -1,3 +1,24 @@
+2012-08-21  Martin Robinson  <mrobinson@igalia.com>
+
+        [GTK] Using a native window for the WebView breaks GtkOverlay
+        https://bugs.webkit.org/show_bug.cgi?id=90085
+
+        Reviewed by Alejandro G. Castro.
+
+        No new tests. This will be covered by pixel test for accelerated
+        compositing when they are activated.
+
+        * GNUmakefile.am: Add XComposite libraries to the linker list.
+        * GNUmakefile.list.am: Add RedirectedXCompositeWindow files to the source list.
+        Make a new section for GLX specific files.
+        * platform/graphics/glx/GLContextGLX.cpp:
+        (WebCore::GLContextGLX::sharedDisplay): Expose sharedDisplay as a static method
+        so that it can be called by other X11 specific code.
+        * platform/graphics/glx/GLContextGLX.h: Ditto.
+        * platform/gtk/RedirectedXCompositeWindow.cpp: Added. An implementation of a GL surface
+        that renders to an X-window which redirects to a pixmap.
+        * platform/gtk/RedirectedXCompositeWindow.h: Added.
+
 2012-08-21  David Hyatt  <hyatt@apple.com>
 
         [New Multicolumn] Make column rules paint properly.
index f9eab24..3940986 100644 (file)
@@ -1056,6 +1056,7 @@ libWebCoreGtk_la_CPPFLAGS = \
        $(LIBXSLT_CFLAGS) \
        $(SQLITE3_CFLAGS) \
        $(UNICODE_CFLAGS) \
+       $(XCOMPOSITE_CFLAGS) \
        $(XRENDER_CFLAGS) \
        $(XT_CFLAGS)
 
index 2bc9879..d487271 100644 (file)
@@ -5875,6 +5875,8 @@ webcoregtk_sources += \
        Source/WebCore/platform/graphics/cairo/GLContext.cpp \
        Source/WebCore/platform/graphics/cairo/GLContext.h \
        Source/WebCore/platform/gtk/GtkWidgetBackingStoreX11.cpp \
+       Source/WebCore/platform/gtk/RedirectedXCompositeWindow.cpp \
+       Source/WebCore/platform/gtk/RedirectedXCompositeWindow.h \
        Source/WebCore/plugins/gtk/gtk2xtbin.c \
        Source/WebCore/plugins/gtk/gtk2xtbin.h \
        Source/WebCore/plugins/gtk/PluginPackageGtk.cpp \
index 9496fc9..9540b86 100644 (file)
@@ -31,7 +31,7 @@ namespace WebCore {
 // because it might lead to crashes in some drivers (fglrx). We use a shared display
 // pointer here.
 static Display* gSharedDisplay = 0;
-static Display* sharedDisplay()
+Display* GLContextGLX::sharedDisplay()
 {
     if (!gSharedDisplay)
         gSharedDisplay = XOpenDisplay(0);
index 5e8c61c..b3b18c1 100644 (file)
@@ -39,7 +39,7 @@ namespace WebCore {
 class GLContextGLX : public GLContext {
     WTF_MAKE_NONCOPYABLE(GLContextGLX);
 public:
-    static PassOwnPtr<GLContextGLX> createContext(XID, GLContext* sharingContext = 0);
+    static PassOwnPtr<GLContextGLX> createContext(XID window, GLContext* sharingContext);
     static PassOwnPtr<GLContextGLX> createWindowContext(XID window, GLContext* sharingContext);
 
     virtual ~GLContextGLX();
@@ -48,6 +48,8 @@ public:
     virtual bool canRenderToDefaultFramebuffer();
     virtual IntSize defaultFrameBufferSize();
 
+    static Display* sharedDisplay();
+
 #if USE(3D_GRAPHICS)
     virtual PlatformGraphicsContext3D platformContext();
 #endif
diff --git a/Source/WebCore/platform/gtk/RedirectedXCompositeWindow.cpp b/Source/WebCore/platform/gtk/RedirectedXCompositeWindow.cpp
new file mode 100644 (file)
index 0000000..ae1d262
--- /dev/null
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2012 Igalia S.L.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "RedirectedXCompositeWindow.h"
+
+#include "GLContextGLX.h"
+#include <GL/glx.h>
+#include <X11/extensions/Xcomposite.h>
+#include <cairo-xlib.h>
+#include <gdk/gdkx.h>
+#include <glib.h>
+#include <gtk/gtk.h>
+
+namespace WebCore {
+
+PassOwnPtr<RedirectedXCompositeWindow> RedirectedXCompositeWindow::create(const IntSize& size)
+{
+    return adoptPtr(new RedirectedXCompositeWindow(size));
+}
+
+RedirectedXCompositeWindow::RedirectedXCompositeWindow(const IntSize& size)
+    : m_window(0)
+    , m_parentWindow(0)
+    , m_pixmap(0)
+    , m_surface(0)
+    , m_pendingResizeSourceId(0)
+    , m_needsNewPixmapAfterResize(false)
+{
+    Display* display = GLContextGLX::sharedDisplay();
+
+    // This is based on code from Chromium: src/content/common/gpu/image_transport_surface_linux.cc
+    XSetWindowAttributes windowAttributes;
+    windowAttributes.override_redirect = True;
+    m_parentWindow = XCreateWindow(display,
+                                   RootWindow(display, DefaultScreen(display)),
+                                   -100, -100, 1, 1,
+                                   0,
+                                   CopyFromParent,
+                                   InputOutput,
+                                   CopyFromParent,
+                                   CWOverrideRedirect,
+                                   &windowAttributes);
+    XMapWindow(display, m_parentWindow);
+
+    windowAttributes.event_mask = StructureNotifyMask;
+    windowAttributes.override_redirect = False;
+    m_window = XCreateWindow(display,
+                             m_parentWindow,
+                             0, 0, size.width(), size.height(),
+                             0,
+                             CopyFromParent,
+                             InputOutput,
+                             CopyFromParent,
+                             CWEventMask,
+                             &windowAttributes);
+    XMapWindow(display, m_window);
+
+    while (1) {
+        XEvent event;
+        XWindowEvent(display, m_window, StructureNotifyMask, &event);
+        if (event.type == MapNotify && event.xmap.window == m_window)
+            break;
+    }
+    XSelectInput(display, m_window, NoEventMask);
+
+    XCompositeRedirectWindow(display, m_window, CompositeRedirectManual);
+
+    resize(size);
+    resizeLater(); // Force update of the usable area.
+}
+
+RedirectedXCompositeWindow::~RedirectedXCompositeWindow()
+{
+    Display* display = GLContextGLX::sharedDisplay();
+    if (m_window)
+        XDestroyWindow(display, m_window);
+    if (m_parentWindow)
+        XDestroyWindow(display, m_parentWindow);
+    cleanupPixmapAndPixmapSurface();
+
+    if (m_pendingResizeSourceId)
+        g_source_remove(m_pendingResizeSourceId);
+}
+
+gboolean RedirectedXCompositeWindow::resizeLaterCallback(RedirectedXCompositeWindow* window)
+{
+    window->resizeLater();
+    return FALSE;
+}
+
+void RedirectedXCompositeWindow::resizeLater()
+{
+    m_usableSize = m_size;
+    m_pendingResizeSourceId = 0;
+}
+
+void RedirectedXCompositeWindow::resize(const IntSize& size)
+{
+    // When enlarging a redirected window, for the first render, the newly exposed areas seem
+    // to contain uninitialized memory on Intel drivers. To avoid rendering artifacts while
+    // resizing, we wait to render those new areas until after a short timeout. Thus, the
+    // "usable size" of the window is smaller than the actual size of the window for the first
+    // render.
+    m_usableSize = size.shrunkTo(m_usableSize);
+    if (m_usableSize.width() < size.width() || m_usableSize.height() < size.height()) { // The window is growing.
+        // We're being very conservative here. Instead of risking drawing artifacts while doing continuous
+        // opaque resizing, we err on the side of having more undrawn areas.
+        if (m_pendingResizeSourceId)
+            g_source_remove(m_pendingResizeSourceId);
+        m_pendingResizeSourceId = g_timeout_add(0, reinterpret_cast<GSourceFunc>(resizeLaterCallback), this);
+    }
+
+    Display* display = GLContextGLX::sharedDisplay();
+    XResizeWindow(display, m_window, size.width(), size.height());
+    glXWaitX();
+
+    // This swap is based on code in Chromium. It tries to work-around a bug in the Intel drivers
+    // where a swap is necessary to ensure the front and back buffers are properly resized.
+    if (context() == GLContext::getCurrent())
+        context()->swapBuffers();
+
+    m_size = size;
+    m_needsNewPixmapAfterResize = true;
+}
+
+GLContext* RedirectedXCompositeWindow::context()
+{
+    if (m_context)
+        return m_context.get();
+
+    ASSERT(m_window);
+    m_context = GLContext::createContextForWindow(m_window, GLContext::sharingContext());
+    return m_context.get();
+}
+
+void RedirectedXCompositeWindow::cleanupPixmapAndPixmapSurface()
+{
+    if (!m_pixmap)
+        return;
+
+    XFreePixmap(cairo_xlib_surface_get_display(m_surface.get()), m_pixmap);
+    m_pixmap = 0;
+    m_surface = nullptr;
+}
+
+cairo_surface_t* RedirectedXCompositeWindow::cairoSurfaceForWidget(GtkWidget* widget)
+{
+    if (!m_needsNewPixmapAfterResize && m_surface)
+        return m_surface.get();
+
+    m_needsNewPixmapAfterResize = false;
+
+    // It's important that the new pixmap be created with the same Display pointer as the target
+    // widget or else drawing speed can be 100x slower.
+    Display* newPixmapDisplay = GDK_DISPLAY_XDISPLAY(gtk_widget_get_display(widget));
+    Pixmap newPixmap = XCompositeNameWindowPixmap(newPixmapDisplay, m_window);
+    if (!newPixmap) {
+        cleanupPixmapAndPixmapSurface();
+        return 0;
+    }
+
+    XWindowAttributes windowAttributes;
+    if (!XGetWindowAttributes(newPixmapDisplay, m_window, &windowAttributes)) {
+        cleanupPixmapAndPixmapSurface();
+        XFreePixmap(newPixmapDisplay, newPixmap);
+        return 0;
+    }
+
+    RefPtr<cairo_surface_t> newSurface = adoptRef(cairo_xlib_surface_create(newPixmapDisplay, newPixmap,
+                                                                            windowAttributes.visual,
+                                                                            m_size.width(), m_size.height()));
+
+    // Nvidia drivers seem to prepare their redirected window pixmap asynchronously, so for a few fractions
+    // of a second after each resize, while doing continuous resizing (which constantly destroys and creates
+    // pixmap window-backings), the pixmap memory is uninitialized. To work around this issue, paint the old
+    // pixmap to the new one to properly initialize it.
+    if (m_surface) {
+        RefPtr<cairo_t> cr = adoptRef(cairo_create(newSurface.get()));
+        cairo_set_source_rgb(cr.get(), 1, 1, 1);
+        cairo_paint(cr.get());
+        cairo_set_source_surface(cr.get(), m_surface.get(), 0, 0);
+        cairo_paint(cr.get());
+    }
+
+    cleanupPixmapAndPixmapSurface();
+    m_pixmap = newPixmap;
+    m_surface = newSurface;
+
+    return m_surface.get();
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/gtk/RedirectedXCompositeWindow.h b/Source/WebCore/platform/gtk/RedirectedXCompositeWindow.h
new file mode 100644 (file)
index 0000000..39ec7ed
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2012, Igalia S.L.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef  RedirectedXCompositeWindow_h
+#define  RedirectedXCompositeWindow_h
+
+#include "GLContextGLX.h"
+#include "IntSize.h"
+#include "RefPtrCairo.h"
+
+typedef unsigned long Pixmap;
+typedef unsigned long Window;
+
+namespace WebCore {
+
+class RedirectedXCompositeWindow {
+public:
+    static PassOwnPtr<RedirectedXCompositeWindow> create(const IntSize&);
+    virtual ~RedirectedXCompositeWindow();
+
+    const IntSize& usableSize() { return m_usableSize; }
+    const IntSize& size() { return m_size; }
+
+    void resize(const IntSize& newSize);
+    GLContext* context();
+    cairo_surface_t* cairoSurfaceForWidget(GtkWidget*);
+
+private:
+    RedirectedXCompositeWindow(const IntSize&);
+
+    static gboolean resizeLaterCallback(RedirectedXCompositeWindow*);
+    void resizeLater();
+    void cleanupPixmapAndPixmapSurface();
+
+    IntSize m_size;
+    IntSize m_usableSize;
+    Window m_window;
+    Window m_parentWindow;
+    Pixmap m_pixmap;
+    OwnPtr<GLContext> m_context;
+    RefPtr<cairo_surface_t> m_surface;
+    unsigned int m_pendingResizeSourceId;
+    bool m_needsNewPixmapAfterResize;
+};
+
+} // namespace WebCore
+
+#endif // RedirectedXCompositeWindow_h
index 511a087..cd0c79a 100644 (file)
@@ -1,3 +1,37 @@
+2012-08-21  Martin Robinson  <mrobinson@igalia.com>
+
+        [GTK] Using a native window for the WebView breaks GtkOverlay
+        https://bugs.webkit.org/show_bug.cgi?id=90085
+
+        Reviewed by Alejandro G. Castro.
+
+        Rewrite AcceleratedCompositingContext for TextureMapperGL to be more similar to
+        the WebKit2 LayerTreeHost and switch from rendering directly to the widget window
+        to a window redirected to a pixmap via XComposite. The AcceleratedCompositingContext
+        now handles painting the non-composited content itself and no longer relies on the
+        ChromeClient backing store.
+
+        This fixes issues with using GtkOverlay WebKitWebView as well as making it possible
+        to run pixel tests with accelerated compositing turned on.
+
+        * WebCoreSupport/AcceleratedCompositingContext.h:
+        (AcceleratedCompositingContext):
+        * WebCoreSupport/AcceleratedCompositingContextGL.cpp:
+        Rename some methods to make them more similar to LayerTreeHost. Now we wait to render
+        the OpenGL context to the window until the widget's draw signal. Escape out of all
+        methods early if accelerated compositing is disabled.
+        * WebCoreSupport/ChromeClientGtk.cpp: Always check if accelerated compositing is on
+        before calling into AcceleratedCompositingContext methods. When AC is on, never paint
+        the backing store, deferring immediately to the AcceleratedCompositingContext. When
+        AC is turned on the backing store now shrinks to a small size to save memory.
+        * webkit/webkitwebview.cpp:
+        (resizeWebViewFromAllocation): ChromeClient is now responsible for talking to the
+        AcceleratedCompositingContext directly.
+        (webkit_web_view_size_allocate): Exit early if the allocation is not a resize. This
+        makes some deeper logic a bit simpler and avoids accidentally doing too much work for
+        widget movement.
+        (webkit_web_view_realize): We no longer need a native window.
+
 2012-08-15  Joanmarie Diggs  <jdiggs@igalia.com>
 
         [Gtk] atk_text_set_caret_offset() fails for table cells
index 215576e..00473f9 100644 (file)
@@ -101,6 +101,7 @@ libwebkitgtk_@WEBKITGTK_API_MAJOR_VERSION@_@WEBKITGTK_API_MINOR_VERSION@_la_LIBA
        $(PNG_LIBS) \
        $(SQLITE3_LIBS) \
        $(UNICODE_LIBS) \
+       $(XCOMPOSITE_LIBS) \
        $(XRENDER_LIBS) \
        $(XT_LIBS) \
        $(WINMM_LIBS) \
index 24a614d..45ef470 100644 (file)
 #include <wtf/PassOwnPtr.h>
 
 #if USE(TEXTURE_MAPPER)
+#include "TextureMapperLayer.h"
+#endif
+
 #if USE(TEXTURE_MAPPER_GL)
 #include "GLContext.h"
-#endif
-#include "TextureMapperLayer.h"
+#include "RedirectedXCompositeWindow.h"
 #endif
 
 #if USE(ACCELERATED_COMPOSITING)
@@ -47,11 +49,9 @@ public:
     }
 
     virtual ~AcceleratedCompositingContext();
-    void attachRootGraphicsLayer(WebCore::GraphicsLayer*);
-    void scheduleRootLayerRepaint(const WebCore::IntRect&);
-    void markForSync();
-    void syncLayersTimeout();
-    void syncLayersNow();
+    void setRootCompositingLayer(WebCore::GraphicsLayer*);
+    void setNonCompositedContentsNeedDisplay(const WebCore::IntRect&);
+    void scheduleLayerFlush();
     void resizeRootLayer(const WebCore::IntSize&);
     bool renderLayersToWindow(cairo_t*, const WebCore::IntRect& clipRect);
     bool enabled();
@@ -63,21 +63,37 @@ public:
     virtual bool showDebugBorders(const WebCore::GraphicsLayer*) const;
     virtual bool showRepaintCounter(const WebCore::GraphicsLayer*) const;
 
+    void initialize();
+    void compositeLayersToContext();
+    void flushAndRenderLayers();
+    bool flushPendingLayerChanges();
+    void scrollNonCompositedContents(const WebCore::IntRect& scrollRect, const WebCore::IntSize& scrollOffset);
+
 private:
     WebKitWebView* m_webView;
-    unsigned int m_syncTimerCallbackId;
+    unsigned int m_layerFlushTimerCallbackId;
 
 #if USE(CLUTTER)
     WebCore::GraphicsLayer* m_rootGraphicsLayer;
     GtkWidget* m_rootLayerEmbedder;
+#elif USE(TEXTURE_MAPPER_GL)
+    OwnPtr<WebCore::RedirectedXCompositeWindow> m_redirectedWindow;
+    OwnPtr<WebCore::GraphicsLayer> m_rootLayer;
+    OwnPtr<WebCore::GraphicsLayer> m_nonCompositedContentLayer;
+    OwnPtr<WebCore::TextureMapper> m_textureMapper;
+    double m_lastFlushTime;
+    double m_redrawPendingTime;
+    bool m_needsExtraFlush;
+
+    void layerFlushTimerFired();
+    void stopAnyPendingLayerFlush();
+    static gboolean layerFlushTimerFiredCallback(AcceleratedCompositingContext*);
+    WebCore::GLContext* prepareForRendering();
+    void clearEverywhere();
 #elif USE(TEXTURE_MAPPER)
     WebCore::TextureMapperLayer* m_rootTextureMapperLayer;
     OwnPtr<WebCore::GraphicsLayer> m_rootGraphicsLayer;
     OwnPtr<WebCore::TextureMapper> m_textureMapper;
-#if USE(TEXTURE_MAPPER_GL)
-    WebCore::GLContext* glContext();
-    OwnPtr<WebCore::GLContext> m_context;
-#endif
 #endif
 
     AcceleratedCompositingContext(WebKitWebView*);
index 64eb901..29ba349 100644 (file)
@@ -27,6 +27,7 @@
 #include "Frame.h"
 #include "FrameView.h"
 #include "PlatformContextCairo.h"
+#include "Settings.h"
 #include "TextureMapperGL.h"
 #include "TextureMapperLayer.h"
 #include "webkitwebviewprivate.h"
 #include <gdk/gdk.h>
 #include <gtk/gtk.h>
 
-#if defined(GDK_WINDOWING_X11)
-#define Region XRegion
-#define Font XFont
-#define Cursor XCursor
-#define Screen XScreen
-#include <gdk/gdkx.h>
-#endif
+const double gFramesPerSecond = 60;
+
+// There seems to be a delicate balance between the main loop being flooded
+// with motion events (that force flushes) and starving the main loop of events
+// with flush callbacks. This delay is entirely empirical.
+const double gScheduleDelay = (1.0 / (gFramesPerSecond / 3.0));
 
 using namespace WebCore;
 
@@ -49,150 +49,322 @@ namespace WebKit {
 
 AcceleratedCompositingContext::AcceleratedCompositingContext(WebKitWebView* webView)
     : m_webView(webView)
-    , m_syncTimerCallbackId(0)
-    , m_rootTextureMapperLayer(0)
+    , m_layerFlushTimerCallbackId(0)
+    , m_redirectedWindow(RedirectedXCompositeWindow::create(IntSize(1, 1)))
+    , m_lastFlushTime(0)
+    , m_redrawPendingTime(0)
+    , m_needsExtraFlush(false)
+{
+}
+
+static IntSize getWebViewSize(WebKitWebView* webView)
 {
+    GtkAllocation allocation;
+    gtk_widget_get_allocation(GTK_WIDGET(webView), &allocation);
+    return IntSize(allocation.width, allocation.height);
+}
+
+void AcceleratedCompositingContext::initialize()
+{
+    if (m_rootLayer)
+        return;
+
+    m_rootLayer = GraphicsLayer::create(this);
+    m_rootLayer->setDrawsContent(false);
+
+    IntSize pageSize = getWebViewSize(m_webView);
+    m_rootLayer->setSize(pageSize);
+
+    // The non-composited contents are a child of the root layer.
+    m_nonCompositedContentLayer = GraphicsLayer::create(this);
+    m_nonCompositedContentLayer->setDrawsContent(true);
+    m_nonCompositedContentLayer->setContentsOpaque(!m_webView->priv->transparent);
+    m_nonCompositedContentLayer->setSize(pageSize);
+    if (core(m_webView)->settings()->acceleratedDrawingEnabled())
+        m_nonCompositedContentLayer->setAcceleratesDrawing(true);
+
+#ifndef NDEBUG
+    m_rootLayer->setName("Root layer");
+    m_nonCompositedContentLayer->setName("Non-composited content");
+#endif
+
+    m_rootLayer->addChild(m_nonCompositedContentLayer.get());
+    m_nonCompositedContentLayer->setNeedsDisplay();
+
+    // The creation of the TextureMapper needs an active OpenGL context.
+    GLContext* context = m_redirectedWindow->context();
+    context->makeContextCurrent();
+    m_textureMapper = TextureMapperGL::create();
+
+    toTextureMapperLayer(m_rootLayer.get())->setTextureMapper(m_textureMapper.get());
+
+    scheduleLayerFlush();
 }
 
 AcceleratedCompositingContext::~AcceleratedCompositingContext()
 {
-    if (m_syncTimerCallbackId)
-        g_source_remove(m_syncTimerCallbackId);
+    stopAnyPendingLayerFlush();
+}
+
+void AcceleratedCompositingContext::stopAnyPendingLayerFlush()
+{
+    if (!m_layerFlushTimerCallbackId)
+        return;
+    g_source_remove(m_layerFlushTimerCallbackId);
+    m_layerFlushTimerCallbackId = 0;
 }
 
 bool AcceleratedCompositingContext::enabled()
 {
-    return m_rootTextureMapperLayer && m_textureMapper;
+    return m_rootLayer && m_textureMapper;
 }
 
-GLContext* AcceleratedCompositingContext::glContext()
+bool AcceleratedCompositingContext::renderLayersToWindow(cairo_t* cr, const IntRect& clipRect)
 {
-    if (m_context)
-        return m_context.get();
+    m_redrawPendingTime = 0;
 
-#if defined(GDK_WINDOWING_X11)
-    // FIXME: Gracefully account for situations where we do not have a realized window.
-    GdkWindow* gdkWindow = gtk_widget_get_window(GTK_WIDGET(m_webView));
-    if (gdkWindow && gdk_window_has_native(gdkWindow))
-        m_context = GLContext::createContextForWindow(GDK_WINDOW_XID(gdkWindow), GLContext::sharingContext());
-#endif
+    if (!enabled())
+        return false;
+
+    // It's important to paint a white background (if the WebView isn't transparent), because when growing
+    // the redirected window, the usable size of the window may be smaller than the allocation of our widget.
+    // We don't want to show artifacts in that case.
+    IntSize usableWindowSize = m_redirectedWindow->usableSize();
+    if (usableWindowSize != m_redirectedWindow->size()) {
+        if (!m_webView->priv->transparent) {
+            cairo_set_source_rgb(cr, 1, 1, 1);
+            cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
+        } else
+            cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
+        cairo_paint(cr);
+    }
 
-    return m_context.get();
+    cairo_surface_t* windowSurface = m_redirectedWindow->cairoSurfaceForWidget(GTK_WIDGET(m_webView));
+    if (!windowSurface)
+        return true;
+
+    cairo_rectangle(cr, clipRect.x(), clipRect.y(), clipRect.width(), clipRect.height());
+    cairo_set_source_surface(cr, windowSurface, 0, 0);
+    cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
+    cairo_fill(cr);
+
+    if (!m_layerFlushTimerCallbackId && toTextureMapperLayer(m_rootLayer.get())->descendantsOrSelfHaveRunningAnimations() || m_needsExtraFlush) {
+        m_needsExtraFlush = false;
+        double nextFlush = max((1 / gFramesPerSecond) - (currentTime() - m_lastFlushTime), 0.0);
+        m_layerFlushTimerCallbackId = g_timeout_add_full(GDK_PRIORITY_EVENTS, 1000 * nextFlush, reinterpret_cast<GSourceFunc>(layerFlushTimerFiredCallback), this, 0);
+    }
+
+    return true;
 }
 
-bool AcceleratedCompositingContext::renderLayersToWindow(cairo_t*, const IntRect& clipRect)
+GLContext* AcceleratedCompositingContext::prepareForRendering()
 {
     if (!enabled())
-        return false;
+        return 0;
 
-    GLContext* context = glContext();
+    GLContext* context = m_redirectedWindow->context();
     if (!context)
-        return false;
+        return 0;
 
     if (!context->makeContextCurrent())
-        return false;
+        return 0;
 
-    GtkAllocation allocation;
-    gtk_widget_get_allocation(GTK_WIDGET(m_webView), &allocation);
-    glViewport(0, 0, allocation.width, allocation.height);
+    return context;
+}
+
+void AcceleratedCompositingContext::compositeLayersToContext()
+{
+    GLContext* context = prepareForRendering();
+    if (!context)
+        return;
+
+    const IntSize& windowSize = m_redirectedWindow->size();
+    glViewport(0, 0, windowSize.width(), windowSize.height());
 
     m_textureMapper->beginPainting();
-    m_rootTextureMapperLayer->paint();
+    toTextureMapperLayer(m_rootLayer.get())->paint();
     m_textureMapper->endPainting();
 
     context->swapBuffers();
-    return true;
+
+    // FIXME: It seems that when using double-buffering (and on some drivers single-buffering)
+    // and XComposite window redirection, two swap buffers are required to force the pixmap
+    // to update. This isn't a problem during animations, because swapBuffer is continuously
+    // called. For non-animation situations we use this terrible hack until we can get to the
+    // bottom of the issue.
+    if (!toTextureMapperLayer(m_rootLayer.get())->descendantsOrSelfHaveRunningAnimations()) {
+        context->swapBuffers();
+        context->swapBuffers();
+    }
 }
 
-void AcceleratedCompositingContext::attachRootGraphicsLayer(GraphicsLayer* graphicsLayer)
+void AcceleratedCompositingContext::clearEverywhere()
 {
-    if (!graphicsLayer) {
-        m_rootGraphicsLayer.clear();
-        m_rootTextureMapperLayer = 0;
-        m_context.clear();
+    GLContext* context = prepareForRendering();
+    if (!context)
         return;
+
+    const IntSize& windowSize = m_redirectedWindow->size();
+    glViewport(0, 0, windowSize.width(), windowSize.height());
+    glClearColor(1, 1, 1, 1);
+    glClear(GL_COLOR_BUFFER_BIT);
+
+    context->swapBuffers();
+
+    // FIXME: It seems that when using double-buffering (and on some drivers single-buffering)
+    // and XComposite window redirection, two swap buffers are required to force the pixmap
+    // to update. This isn't a problem during animations, because swapBuffer is continuously
+    // called. For non-animation situations we use this terrible hack until we can get to the
+    // bottom of the issue.
+    if (!toTextureMapperLayer(m_rootLayer.get())->descendantsOrSelfHaveRunningAnimations()) {
+        context->swapBuffers();
+        context->swapBuffers();
     }
+}
 
-    m_rootGraphicsLayer = GraphicsLayer::create(this);
-    m_rootTextureMapperLayer = toTextureMapperLayer(m_rootGraphicsLayer.get());
-    m_rootGraphicsLayer->addChild(graphicsLayer);
-    m_rootGraphicsLayer->setDrawsContent(true);
-    m_rootGraphicsLayer->setMasksToBounds(false);
-    m_rootGraphicsLayer->setNeedsDisplay();
-    m_rootGraphicsLayer->setSize(core(m_webView)->mainFrame()->view()->frameRect().size());
+void AcceleratedCompositingContext::setRootCompositingLayer(GraphicsLayer* graphicsLayer)
+{
+    // Clearing everywhere when turning on or off the layer tree prevents us from flashing
+    // old content before the first flush.
+    clearEverywhere();
 
-    GLContext* context = glContext();
-    if (!context)
-        return;
+    if (!graphicsLayer) {
+        stopAnyPendingLayerFlush();
 
-    // The context needs to be active when creating the texture mapper. It's fine to
-    // avoid calling swapBuffers here, because it will just initialize shaders.
-    if (!context->makeContextCurrent())
+        // Shrink the offscreen window to save memory while accelerated compositing is turned off.
+        m_redirectedWindow->resize(IntSize(1, 1));
+        m_rootLayer = nullptr;
+        m_nonCompositedContentLayer = nullptr;
+        m_textureMapper = nullptr;
         return;
+    }
 
-    GtkAllocation allocation;
-    gtk_widget_get_allocation(GTK_WIDGET(m_webView), &allocation);
-    glViewport(0, 0, allocation.width, allocation.height);
+    if (graphicsLayer && !enabled())
+        m_redirectedWindow->resize(getWebViewSize(m_webView));
 
-    m_textureMapper = TextureMapperGL::create();
-    m_rootTextureMapperLayer->setTextureMapper(m_textureMapper.get());
-    m_rootGraphicsLayer->syncCompositingStateForThisLayerOnly();
+    // Add the accelerated layer tree hierarchy.
+    initialize();
+    m_nonCompositedContentLayer->removeAllChildren();
+    m_nonCompositedContentLayer->addChild(graphicsLayer);
+
+    stopAnyPendingLayerFlush();
+
+    // FIXME: Two flushes seem necessary to get the proper rendering in some cases. It's unclear
+    // if this is a bug with the RedirectedXComposite window or with this class.
+    m_needsExtraFlush = true;
+    scheduleLayerFlush();
+
+    m_layerFlushTimerCallbackId = g_timeout_add_full(GDK_PRIORITY_EVENTS, 500, reinterpret_cast<GSourceFunc>(layerFlushTimerFiredCallback), this, 0);
 }
 
-void AcceleratedCompositingContext::scheduleRootLayerRepaint(const IntRect& rect)
+void AcceleratedCompositingContext::setNonCompositedContentsNeedDisplay(const IntRect& rect)
 {
-    if (!m_rootGraphicsLayer)
+    if (!m_rootLayer)
         return;
     if (rect.isEmpty()) {
-        m_rootGraphicsLayer->setNeedsDisplay();
+        m_rootLayer->setNeedsDisplay();
         return;
     }
-    m_rootGraphicsLayer->setNeedsDisplayInRect(rect);
+    m_nonCompositedContentLayer->setNeedsDisplayInRect(rect);
+    scheduleLayerFlush();
 }
 
-void AcceleratedCompositingContext::resizeRootLayer(const IntSize& size)
+void AcceleratedCompositingContext::resizeRootLayer(const IntSize& newSize)
 {
-    if (!m_rootGraphicsLayer)
+    if (!enabled())
         return;
-    m_rootGraphicsLayer->setSize(size);
-    m_rootGraphicsLayer->syncCompositingStateForThisLayerOnly();
+
+    if (m_rootLayer->size() == newSize)
+        return;
+
+    m_redirectedWindow->resize(newSize);
+    m_rootLayer->setSize(newSize);
+
+    // If the newSize exposes new areas of the non-composited content a setNeedsDisplay is needed
+    // for those newly exposed areas.
+    FloatSize oldSize = m_nonCompositedContentLayer->size();
+    m_nonCompositedContentLayer->setSize(newSize);
+
+    if (newSize.width() > oldSize.width()) {
+        float height = std::min(static_cast<float>(newSize.height()), oldSize.height());
+        m_nonCompositedContentLayer->setNeedsDisplayInRect(FloatRect(oldSize.width(), 0, newSize.width() - oldSize.width(), height));
+    }
+
+    if (newSize.height() > oldSize.height())
+        m_nonCompositedContentLayer->setNeedsDisplayInRect(FloatRect(0, oldSize.height(), newSize.width(), newSize.height() - oldSize.height()));
+
+    m_nonCompositedContentLayer->setNeedsDisplayInRect(IntRect(IntPoint(), newSize));
+    flushAndRenderLayers();
+}
+
+void AcceleratedCompositingContext::scrollNonCompositedContents(const IntRect& scrollRect, const IntSize& scrollOffset)
+{
+    m_nonCompositedContentLayer->setNeedsDisplayInRect(scrollRect);
+    scheduleLayerFlush();
 }
 
-static gboolean syncLayersTimeoutCallback(AcceleratedCompositingContext* context)
+gboolean AcceleratedCompositingContext::layerFlushTimerFiredCallback(AcceleratedCompositingContext* context)
 {
-    context->syncLayersTimeout();
+    context->layerFlushTimerFired();
     return FALSE;
 }
 
-void AcceleratedCompositingContext::markForSync()
+void AcceleratedCompositingContext::scheduleLayerFlush()
 {
-    if (m_syncTimerCallbackId)
+    if (!enabled())
         return;
 
-    // We use a GLib timer because otherwise GTK+ event handling during
-    // dragging can starve WebCore timers, which have a lower priority.
-    m_syncTimerCallbackId = g_timeout_add_full(GDK_PRIORITY_EVENTS, 0, reinterpret_cast<GSourceFunc>(syncLayersTimeoutCallback), this, 0);
+    if (m_layerFlushTimerCallbackId)
+        return;
+
+    // We use a GLib timer because otherwise GTK+ event handling during dragging can
+    // starve WebCore timers, which have a lower priority.
+    double nextFlush = max(gScheduleDelay - (currentTime() - m_lastFlushTime), 0.0);
+    m_layerFlushTimerCallbackId = g_timeout_add_full(GDK_PRIORITY_EVENTS, nextFlush * 1000, reinterpret_cast<GSourceFunc>(layerFlushTimerFiredCallback), this, 0);
 }
 
-void AcceleratedCompositingContext::syncLayersNow()
+bool AcceleratedCompositingContext::flushPendingLayerChanges()
 {
-    if (m_rootGraphicsLayer)
-        m_rootGraphicsLayer->syncCompositingStateForThisLayerOnly();
-
-    core(m_webView)->mainFrame()->view()->syncCompositingStateIncludingSubframes();
+    m_rootLayer->syncCompositingStateForThisLayerOnly();
+    m_nonCompositedContentLayer->syncCompositingStateForThisLayerOnly();
+    return core(m_webView)->mainFrame()->view()->syncCompositingStateIncludingSubframes();
 }
 
-void AcceleratedCompositingContext::syncLayersTimeout()
+void AcceleratedCompositingContext::flushAndRenderLayers()
 {
-    m_syncTimerCallbackId = 0;
-    syncLayersNow();
-    if (!m_rootGraphicsLayer)
+    if (!enabled())
+        return;
+
+    Frame* frame = core(m_webView)->mainFrame();
+    if (!frame || !frame->contentRenderer() || !frame->view())
         return;
+    frame->view()->updateLayoutAndStyleIfNeededRecursive();
 
-    if (toTextureMapperLayer(m_rootGraphicsLayer.get())->descendantsOrSelfHaveRunningAnimations())
-        m_syncTimerCallbackId = g_timeout_add_full(GDK_PRIORITY_EVENTS, 1000.0 / 60.0, reinterpret_cast<GSourceFunc>(syncLayersTimeoutCallback), this, 0);
+    GLContext* context = m_redirectedWindow->context();
+    if (context && !context->makeContextCurrent())
+        return;
+
+    if (!flushPendingLayerChanges())
+        return;
 
-    renderLayersToWindow(0, IntRect());
+    m_lastFlushTime = currentTime();
+    compositeLayersToContext();
+
+    gtk_widget_queue_draw(GTK_WIDGET(m_webView));
+
+    // If it's been a long time since we've actually painted, which means that events might
+    // be starving the main loop, we should force a draw now. This seems to prevent display
+    // lag on http://2012.beercamp.com.
+    if (m_redrawPendingTime && currentTime() - m_redrawPendingTime > gScheduleDelay)
+        gdk_window_process_updates(gtk_widget_get_window(GTK_WIDGET(m_webView)), FALSE);
+    else if (!m_redrawPendingTime)
+        m_redrawPendingTime = currentTime();
+}
+
+void AcceleratedCompositingContext::layerFlushTimerFired()
+{
+    m_layerFlushTimerCallbackId = 0;
+    flushAndRenderLayers();
 }
 
 void AcceleratedCompositingContext::notifyAnimationStarted(const GraphicsLayer*, double time)
@@ -206,9 +378,10 @@ void AcceleratedCompositingContext::notifySyncRequired(const GraphicsLayer*)
 
 void AcceleratedCompositingContext::paintContents(const GraphicsLayer*, GraphicsContext& context, GraphicsLayerPaintingPhase, const IntRect& rectToPaint)
 {
-    cairo_t* cr = context.platformContext()->cr();
-    copyRectFromCairoSurfaceToContext(m_webView->priv->backingStore->cairoSurface(), cr,
-                                      IntSize(), rectToPaint);
+    context.save();
+    context.clip(rectToPaint);
+    core(m_webView)->mainFrame()->view()->paint(&context, rectToPaint);
+    context.restore();
 }
 
 bool AcceleratedCompositingContext::showDebugBorders(const GraphicsLayer*) const
index 41c8409..740e3bb 100644 (file)
@@ -142,17 +142,18 @@ void ChromeClient::setWindowRect(const FloatRect& rect)
     }
 }
 
-FloatRect ChromeClient::pageRect()
+static IntRect getWebViewRect(WebKitWebView* webView)
 {
     GtkAllocation allocation;
-#if GTK_CHECK_VERSION(2, 18, 0)
-    gtk_widget_get_allocation(GTK_WIDGET(m_webView), &allocation);
-#else
-    allocation = GTK_WIDGET(m_webView)->allocation;
-#endif
+    gtk_widget_get_allocation(GTK_WIDGET(webView), &allocation);
     return IntRect(allocation.x, allocation.y, allocation.width, allocation.height);
 }
 
+FloatRect ChromeClient::pageRect()
+{
+    return getWebViewRect(m_webView);
+}
+
 void ChromeClient::focus()
 {
     gtk_widget_grab_focus(GTK_WIDGET(m_webView));
@@ -419,10 +420,20 @@ static void clearEverywhereInBackingStore(WebKitWebView* webView, cairo_t* cr)
 
 void ChromeClient::widgetSizeChanged(const IntSize& oldWidgetSize, IntSize newSize)
 {
-    WidgetBackingStore* backingStore = m_webView->priv->backingStore.get();
+#if USE(ACCELERATED_COMPOSITING)
+    AcceleratedCompositingContext* compositingContext = m_webView->priv->acceleratedCompositingContext.get();
+    if (compositingContext->enabled()) {
+        m_webView->priv->acceleratedCompositingContext->resizeRootLayer(newSize);
+        return;
+    }
+#endif
 
     // Grow the backing store by at least 1.5 times the current size. This prevents
     // lots of unnecessary allocations during an opaque resize.
+    WidgetBackingStore* backingStore = m_webView->priv->backingStore.get();
+    if (backingStore && oldWidgetSize == newSize)
+        return;
+
     if (backingStore) {
         const IntSize& oldSize = backingStore->size();
         if (newSize.width() > oldSize.width())
@@ -526,20 +537,6 @@ static void paintWebView(WebKitWebView* webView, Frame* frame, Region dirtyRegio
     gc.restore();
 }
 
-void ChromeClient::invalidateWidgetRect(const IntRect& rect)
-{
-#if USE(ACCELERATED_COMPOSITING)
-    AcceleratedCompositingContext* acContext = m_webView->priv->acceleratedCompositingContext.get();
-    if (acContext->enabled()) {
-        acContext->scheduleRootLayerRepaint(rect);
-        return;
-    }
-#endif
-    gtk_widget_queue_draw_area(GTK_WIDGET(m_webView),
-                               rect.x(), rect.y(),
-                               rect.width(), rect.height());
-}
-
 void ChromeClient::performAllPendingScrolls()
 {
     if (!m_webView->priv->backingStore)
@@ -549,7 +546,7 @@ void ChromeClient::performAllPendingScrolls()
     for (size_t i = 0; i < m_rectsToScroll.size(); i++) {
         IntRect& scrollRect = m_rectsToScroll[i];
         m_webView->priv->backingStore->scroll(scrollRect, m_scrollOffsets[i]);
-        invalidateWidgetRect(scrollRect);
+        gtk_widget_queue_draw_area(GTK_WIDGET(m_webView), scrollRect.x(), scrollRect.y(), scrollRect.width(), scrollRect.height());
     }
 
     m_rectsToScroll.clear();
@@ -585,12 +582,7 @@ void ChromeClient::paint(WebCore::Timer<ChromeClient>*)
     }
 
     const IntRect& rect = m_dirtyRegion.bounds();
-    invalidateWidgetRect(rect);
-
-#if USE(ACCELERATED_COMPOSITING)
-    m_webView->priv->acceleratedCompositingContext->syncLayersNow();
-    m_webView->priv->acceleratedCompositingContext->renderLayersToWindow(0, rect);
-#endif
+    gtk_widget_queue_draw_area(GTK_WIDGET(m_webView), rect.x(), rect.y(), rect.width(), rect.height());
 
     m_dirtyRegion = Region();
     m_lastDisplayTime = currentTime();
@@ -606,6 +598,11 @@ void ChromeClient::paint(WebCore::Timer<ChromeClient>*)
 
 void ChromeClient::forcePaint()
 {
+#if USE(ACCELERATED_COMPOSITING)
+    if (m_webView->priv->acceleratedCompositingContext->enabled())
+        return;
+#endif
+
     m_forcePaint = true;
     paint(0);
     m_forcePaint = false;
@@ -617,6 +614,14 @@ void ChromeClient::invalidateRootView(const IntRect&, bool immediate)
 
 void ChromeClient::invalidateContentsAndRootView(const IntRect& updateRect, bool immediate)
 {
+#if USE(ACCELERATED_COMPOSITING)
+    AcceleratedCompositingContext* acContext = m_webView->priv->acceleratedCompositingContext.get();
+    if (acContext->enabled()) {
+        acContext->setNonCompositedContentsNeedDisplay(updateRect);
+        return;
+    }
+#endif
+
     if (updateRect.isEmpty())
         return;
     m_dirtyRegion.unite(updateRect);
@@ -625,12 +630,34 @@ void ChromeClient::invalidateContentsAndRootView(const IntRect& updateRect, bool
 
 void ChromeClient::invalidateContentsForSlowScroll(const IntRect& updateRect, bool immediate)
 {
-    invalidateContentsAndRootView(updateRect, immediate);
     m_adjustmentWatcher.updateAdjustmentsFromScrollbarsLater();
+
+#if USE(ACCELERATED_COMPOSITING)
+    AcceleratedCompositingContext* acContext = m_webView->priv->acceleratedCompositingContext.get();
+    if (acContext->enabled()) {
+        acContext->setNonCompositedContentsNeedDisplay(updateRect);
+        return;
+    }
+#endif
+
+    invalidateContentsAndRootView(updateRect, immediate);
 }
 
 void ChromeClient::scroll(const IntSize& delta, const IntRect& rectToScroll, const IntRect& clipRect)
 {
+    m_adjustmentWatcher.updateAdjustmentsFromScrollbarsLater();
+
+#if USE(ACCELERATED_COMPOSITING)
+    AcceleratedCompositingContext* compositingContext = m_webView->priv->acceleratedCompositingContext.get();
+    if (compositingContext->enabled()) {
+        ASSERT(!rectToScroll.isEmpty());
+        ASSERT(!delta.isEmpty());
+
+        compositingContext->scrollNonCompositedContents(rectToScroll, delta);
+        return;
+    }
+#endif
+
     m_rectsToScroll.append(rectToScroll);
     m_scrollOffsets.append(delta);
 
@@ -657,8 +684,6 @@ void ChromeClient::scroll(const IntSize& delta, const IntRect& rectToScroll, con
 
     m_dirtyRegion.unite(scrollRepaintRegion);
     m_displayTimer.startOneShot(0);
-
-    m_adjustmentWatcher.updateAdjustmentsFromScrollbarsLater();
 }
 
 IntRect ChromeClient::rootViewToScreen(const IntRect& rect) const
@@ -966,17 +991,32 @@ void ChromeClient::exitFullScreenForElement(WebCore::Element*)
 #if USE(ACCELERATED_COMPOSITING)
 void ChromeClient::attachRootGraphicsLayer(Frame* frame, GraphicsLayer* rootLayer)
 {
-    m_webView->priv->acceleratedCompositingContext->attachRootGraphicsLayer(rootLayer);
+    AcceleratedCompositingContext* context = m_webView->priv->acceleratedCompositingContext.get();
+    bool turningOffCompositing = !rootLayer && context->enabled();
+    bool turningOnCompositing = rootLayer && !context->enabled();
+
+    context->setRootCompositingLayer(rootLayer);
+
+    if (turningOnCompositing) {
+        m_displayTimer.stop();
+        m_webView->priv->backingStore = WebCore::WidgetBackingStore::create(GTK_WIDGET(m_webView), IntSize(1, 1));
+    }
+
+    if (turningOffCompositing) {
+        m_webView->priv->backingStore = WebCore::WidgetBackingStore::create(GTK_WIDGET(m_webView), getWebViewRect(m_webView).size());
+        RefPtr<cairo_t> cr = adoptRef(cairo_create(m_webView->priv->backingStore->cairoSurface()));
+        clearEverywhereInBackingStore(m_webView, cr.get());
+    }
 }
 
 void ChromeClient::setNeedsOneShotDrawingSynchronization()
 {
-    m_webView->priv->acceleratedCompositingContext->markForSync();
+    m_webView->priv->acceleratedCompositingContext->scheduleLayerFlush();
 }
 
 void ChromeClient::scheduleCompositingLayerSync()
 {
-    m_webView->priv->acceleratedCompositingContext->markForSync();
+    m_webView->priv->acceleratedCompositingContext->scheduleLayerFlush();
 }
 
 ChromeClient::CompositingTriggerFlags ChromeClient::allowedCompositingTriggers() const
index e5e2fa1..284bdaa 100644 (file)
@@ -179,7 +179,6 @@ namespace WebKit {
         double m_lastDisplayTime;
         unsigned int m_repaintSoonSourceId;
 
-        void invalidateWidgetRect(const IntRect&);
 #if ENABLE(FULLSCREEN_API)
         RefPtr<Element> m_fullScreenElement;
 #endif
index 9717806..a536894 100644 (file)
@@ -679,8 +679,10 @@ static gboolean webkit_web_view_draw(GtkWidget* widget, cairo_t* cr)
 
     WebKitWebViewPrivate* priv = WEBKIT_WEB_VIEW(widget)->priv;
 #if USE(TEXTURE_MAPPER)
-    if (priv->acceleratedCompositingContext->renderLayersToWindow(cr, clipRect))
+    if (priv->acceleratedCompositingContext->renderLayersToWindow(cr, clipRect)) {
+        GTK_WIDGET_CLASS(webkit_web_view_parent_class)->draw(widget, cr);
         return FALSE;
+    }
 #endif
 
     cairo_rectangle_list_t* rectList = cairo_copy_clip_rectangle_list(cr);
@@ -875,15 +877,16 @@ static void resizeWebViewFromAllocation(WebKitWebView* webView, GtkAllocation* a
     WebKit::ChromeClient* chromeClient = static_cast<WebKit::ChromeClient*>(page->chrome()->client());
     chromeClient->widgetSizeChanged(oldSize, IntSize(allocation->width, allocation->height));
     chromeClient->adjustmentWatcher()->updateAdjustmentsFromScrollbars();
-
-#if USE(ACCELERATED_COMPOSITING)
-    webView->priv->acceleratedCompositingContext->resizeRootLayer(IntSize(allocation->width, allocation->height));
-#endif
 }
 
 static void webkit_web_view_size_allocate(GtkWidget* widget, GtkAllocation* allocation)
 {
+    GtkAllocation oldAllocation;
+    gtk_widget_get_allocation(widget, &oldAllocation);
+
     GTK_WIDGET_CLASS(webkit_web_view_parent_class)->size_allocate(widget, allocation);
+    if (allocation->width == oldAllocation.width && allocation->height == oldAllocation.height)
+        return;
 
     WebKitWebView* webView = WEBKIT_WEB_VIEW(widget);
     if (!gtk_widget_get_mapped(widget)) {
@@ -1003,10 +1006,6 @@ static void webkit_web_view_realize(GtkWidget* widget)
 #endif
     GdkWindow* window = gdk_window_new(gtk_widget_get_parent_window(widget), &attributes, attributes_mask);
 
-#if USE(ACCELERATED_COMPOSITING) && USE(TEXTURE_MAPPER_GL)
-    WebKitWebViewPrivate* priv = WEBKIT_WEB_VIEW(widget)->priv;
-    priv->hasNativeWindow = gdk_window_ensure_native(window);
-#endif
     gtk_widget_set_window(widget, window);
     gdk_window_set_user_data(window, widget);
 
index 02be74b..e02657b 100644 (file)
@@ -1,3 +1,14 @@
+2012-08-21  Martin Robinson  <mrobinson@igalia.com>
+
+        [GTK] Using a native window for the WebView breaks GtkOverlay
+        https://bugs.webkit.org/show_bug.cgi?id=90085
+
+        Reviewed by Alejandro G. Castro.
+
+        Add XComposite libraries to the linker list for WebKit2.
+
+        * GNUmakefile.am: Add XComposite
+
 2012-08-21  Jesse van den Kieboom  <jessevdk@gnome.org> and Carlos Garcia Campos  <cgarcia@igalia.com>
 
         [GTK] Add destroy notify for register_uri_scheme
index 3edce0a..ba0ac69 100644 (file)
@@ -108,6 +108,7 @@ libwebkit2gtk_@WEBKITGTK_API_MAJOR_VERSION@_@WEBKITGTK_API_MINOR_VERSION@_la_CPP
        $(GTK_UNIX_PRINTING_CFLAGS) \
        $(LIBSOUP_CFLAGS) \
        $(UNICODE_CFLAGS) \
+       $(XCOMPOSITE_CFLAGS) \
        $(XT_CFLAGS)
 
 libwebkit2gtk_@WEBKITGTK_API_MAJOR_VERSION@_@WEBKITGTK_API_MINOR_VERSION@_la_CXXFLAGS = \
@@ -180,6 +181,7 @@ libwebkit2gtk_@WEBKITGTK_API_MAJOR_VERSION@_@WEBKITGTK_API_MINOR_VERSION@_la_LIB
        $(SQLITE3_LIBS) \
        $(UNICODE_LIBS) \
        $(XRENDER_LIBS) \
+       $(XCOMPOSITE_LIBS) \
        $(XT_LIBS) \
        $(ZLIB_LIBS)
 
index 78f2067..28f9af8 100644 (file)
@@ -565,6 +565,12 @@ AC_ARG_WITH(acceleration_backend,
                            ])
 AC_MSG_RESULT([$with_acceleration_backend])
 
+if test "$with_acceleration_backend" = "opengl"; then
+    PKG_CHECK_MODULES([XCOMPOSITE], [xcomposite]);
+    AC_SUBST(XCOMPOSITE_CFLAGS)
+    AC_SUBST(XCOMPOSITE_LIBS)
+fi
+
 # OpenGL is turned on by default (along with WebGL and accelerated compositing), but if
 # Clutter is chosen as the accelerated drawing backend, we want to disable it. COGL does 
 # not play well with OpenGL.