1/*
2 * Copyright (C) 2012-2016 Igalia S.L.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "AcceleratedSurfaceX11.h"
28
29#if PLATFORM(X11)
30
31#include "WebPage.h"
32#include <WebCore/PlatformDisplayX11.h>
33#include <WebCore/RefPtrCairo.h>
34#include <X11/Xlib.h>
35#include <X11/extensions/Xcomposite.h>
36#include <cairo-xlib.h>
37#include <gdk/gdkx.h>
38#include <wtf/RunLoop.h>
39
40namespace WebKit {
41using namespace WebCore;
42
43std::unique_ptr<AcceleratedSurfaceX11> AcceleratedSurfaceX11::create(WebPage& webPage, Client& client)
44{
45 if (!downcast<PlatformDisplayX11>(PlatformDisplay::sharedDisplay()).supportsXComposite())
46 return nullptr;
47 return std::unique_ptr<AcceleratedSurfaceX11>(new AcceleratedSurfaceX11(webPage, client));
48}
49
50static GdkVisual* defaultVisual()
51{
52 if (GdkVisual* visual = gdk_screen_get_rgba_visual(gdk_screen_get_default()))
53 return visual;
54 return gdk_screen_get_system_visual(gdk_screen_get_default());
55}
56
57AcceleratedSurfaceX11::AcceleratedSurfaceX11(WebPage& webPage, Client& client)
58 : AcceleratedSurface(webPage, client)
59 , m_display(downcast<PlatformDisplayX11>(PlatformDisplay::sharedDisplay()).native())
60{
61 Screen* screen = DefaultScreenOfDisplay(m_display);
62
63 ASSERT(downcast<PlatformDisplayX11>(PlatformDisplay::sharedDisplay()).native() == m_display);
64
65 GdkVisual* visual = defaultVisual();
66 XUniqueColormap colormap(XCreateColormap(m_display, RootWindowOfScreen(screen), GDK_VISUAL_XVISUAL(visual), AllocNone));
67
68 XSetWindowAttributes windowAttributes;
69 windowAttributes.override_redirect = True;
70 windowAttributes.colormap = colormap.get();
71
72 // CWBorderPixel must be present when the depth doesn't match the parent's one.
73 // See http://cgit.freedesktop.org/xorg/xserver/tree/dix/window.c?id=xorg-server-1.16.0#n703.
74 windowAttributes.border_pixel = 0;
75
76 m_parentWindow = XCreateWindow(m_display,
77 RootWindowOfScreen(screen),
78 -1, -1, 1, 1,
79 0,
80 gdk_visual_get_depth(visual),
81 InputOutput,
82 GDK_VISUAL_XVISUAL(visual),
83 CWOverrideRedirect | CWColormap | CWBorderPixel,
84 &windowAttributes);
85 XMapWindow(m_display, m_parentWindow.get());
86
87 windowAttributes.event_mask = StructureNotifyMask;
88 windowAttributes.override_redirect = False;
89
90 // Create the window of at last 1x1 since X doesn't allow to create empty windows.
91 m_window = XCreateWindow(m_display,
92 m_parentWindow.get(),
93 0, 0,
94 std::max(1, m_size.width()),
95 std::max(1, m_size.height()),
96 0,
97 CopyFromParent,
98 InputOutput,
99 CopyFromParent,
100 CWEventMask,
101 &windowAttributes);
102 XMapWindow(m_display, m_window.get());
103
104 while (1) {
105 XEvent event;
106 XWindowEvent(m_display, m_window.get(), StructureNotifyMask, &event);
107 if (event.type == MapNotify && event.xmap.window == m_window.get())
108 break;
109 }
110 XSelectInput(m_display, m_window.get(), NoEventMask);
111 XCompositeRedirectWindow(m_display, m_window.get(), CompositeRedirectManual);
112 createPixmap();
113}
114
115AcceleratedSurfaceX11::~AcceleratedSurfaceX11()
116{
117 ASSERT(m_display);
118 ASSERT(m_window);
119 ASSERT(m_parentWindow);
120
121 // Explicitly reset these because we need to ensure it happens in this order.
122 m_window.reset();
123 m_parentWindow.reset();
124}
125
126void AcceleratedSurfaceX11::createPixmap()
127{
128 m_pixmap = XCompositeNameWindowPixmap(m_display, m_window.get());
129 RefPtr<cairo_surface_t> surface = adoptRef(cairo_xlib_surface_create(m_display, m_pixmap.get(), GDK_VISUAL_XVISUAL(defaultVisual()), m_size.width(), m_size.height()));
130 RefPtr<cairo_t> cr = adoptRef(cairo_create(surface.get()));
131 cairo_set_operator(cr.get(), CAIRO_OPERATOR_CLEAR);
132 cairo_paint(cr.get());
133 XSync(m_display, False);
134}
135
136bool AcceleratedSurfaceX11::hostResize(const IntSize& size)
137{
138 if (!AcceleratedSurface::hostResize(size))
139 return false;
140
141 // Resize the window to at last 1x1 since X doesn't allow to create empty windows.
142 XResizeWindow(m_display, m_window.get(), std::max(1, m_size.width()), std::max(1, m_size.height()));
143 XFlush(m_display);
144
145 // Release the previous pixmap later to give some time to the UI process to update.
146 RunLoop::main().dispatchAfter(5_s, [pixmap = WTFMove(m_pixmap)] { });
147 createPixmap();
148 return true;
149}
150
151void AcceleratedSurfaceX11::didRenderFrame()
152{
153 // FIXME: frameComplete() should be called when the frame was actually rendered in the screen.
154 m_client.frameComplete();
155}
156
157} // namespace WebKit
158
159#endif // PLATFORM(X11)
160