cedd453f29a830b23796ee5957f387afddeb7518
[WebKit-https.git] / Source / WebCore / platform / graphics / surfaces / glx / X11Helper.cpp
1 /*
2  * Copyright (C) 2013 Intel Corporation. All rights reserved.
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. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "X11Helper.h"
28
29 namespace WebCore {
30
31 // Used for handling XError.
32 static bool validOperation = true;
33 static int handleXPixmapCreationError(Display*, XErrorEvent* event)
34 {
35     if (event->error_code == BadMatch || event->error_code == BadWindow || event->error_code == BadAlloc) {
36         validOperation = false;
37
38         switch (event->error_code) {
39         case BadMatch:
40             LOG_ERROR("BadMatch.");
41             break;
42         case BadWindow:
43             LOG_ERROR("BadWindow.");
44             break;
45         case BadAlloc:
46             LOG_ERROR("BadAlloc.");
47             break;
48         default:
49             break;
50         }
51     }
52
53     return 0;
54 }
55
56 struct DisplayConnection {
57     DisplayConnection()
58     {
59         m_display = XOpenDisplay(0);
60
61         if (!m_display)
62             LOG_ERROR("Failed to make connection with X");
63     }
64
65     ~DisplayConnection()
66     {
67         XCloseDisplay(m_display);
68     }
69
70     Display* display() { return m_display; }
71 private:
72     Display* m_display;
73 };
74
75 struct OffScreenRootWindow {
76
77     OffScreenRootWindow()
78     {
79         m_window = 0;
80         Display* dpy = X11Helper::nativeDisplay();
81         if (!dpy)
82             return;
83
84         XSetWindowAttributes attributes;
85         attributes.override_redirect = true;
86         m_window = XCreateSimpleWindow(dpy, XDefaultRootWindow(dpy), -1, -1, 1, 1, 0, BlackPixel(dpy, 0), WhitePixel(dpy, 0));
87         // From http://tronche.com/gui/x/xlib/window/attributes/
88         XChangeWindowAttributes(dpy, m_window, CWOverrideRedirect, &attributes);
89         XMapWindow(dpy, m_window);
90
91         if (!m_window)
92             LOG_ERROR("Failed to create offscreen root window.");
93     }
94
95     ~OffScreenRootWindow()
96     {
97         if (!X11Helper::nativeDisplay())
98             return;
99
100         if (m_window) {
101             XUnmapWindow(X11Helper::nativeDisplay(), m_window);
102             XDestroyWindow(X11Helper::nativeDisplay(), m_window);
103             m_window = 0;
104         }
105     }
106
107     Window rootWindow()
108     {
109         return m_window;
110     }
111
112 private:
113     Window m_window;
114 };
115
116 ScopedXPixmapCreationErrorHandler::ScopedXPixmapCreationErrorHandler()
117 {
118     // XSync must be called to ensure that current errors are handled by the original handler.
119     XSync(X11Helper::nativeDisplay(), false);
120     m_previousErrorHandler = XSetErrorHandler(handleXPixmapCreationError);
121 }
122
123 ScopedXPixmapCreationErrorHandler::~ScopedXPixmapCreationErrorHandler()
124 {
125     // Restore the original handler.
126     XSetErrorHandler(m_previousErrorHandler);
127 }
128
129 bool ScopedXPixmapCreationErrorHandler::isValidOperation() const
130 {
131     validOperation = true;
132     // XSync is needed to catch possible errors as they are generated asynchronously.
133     XSync(X11Helper::nativeDisplay(), false);
134     return validOperation;
135 }
136
137 void X11Helper::resizeWindow(const IntRect& newRect, const uint32_t windowId)
138 {
139     XResizeWindow(nativeDisplay(), windowId, newRect.width(), newRect.height());
140     XFlush(nativeDisplay());
141 }
142
143 void X11Helper::createPixmap(Pixmap* handleId, const XVisualInfo& visualInfo, const IntSize& size)
144 {
145     Display* display = nativeDisplay();
146     if (!display)
147         return;
148
149     if (!visualInfo.visual) {
150         LOG_ERROR("Failed to find valid XVisual.");
151         return;
152     }
153
154     Window xWindow = offscreenRootWindow();
155     if (!xWindow) {
156         LOG_ERROR("Failed to create offscreen root window.");
157         return;
158     }
159
160     Pixmap tempHandleId = XCreatePixmap(display, xWindow, size.width(), size.height(), visualInfo.depth);
161
162     if (!tempHandleId) {
163         LOG_ERROR("Failed to create offscreen pixmap.");
164         return;
165     }
166
167     *handleId = tempHandleId;
168     XSync(X11Helper::nativeDisplay(), false);
169 }
170
171 void X11Helper::destroyPixmap(const uint32_t pixmapId)
172 {
173     if (!pixmapId)
174         return;
175
176     Display* display = nativeDisplay();
177     if (!display)
178         return;
179
180     XFreePixmap(display, pixmapId);
181     XSync(X11Helper::nativeDisplay(), false);
182 }
183
184 void X11Helper::createOffScreenWindow(uint32_t* handleId, const XVisualInfo& visInfo, const IntSize& size)
185 {
186 #if USE(GRAPHICS_SURFACE)
187     Display* display = nativeDisplay();
188     if (!display)
189         return;
190
191     if (!visInfo.visual) {
192         LOG_ERROR("Failed to find valid XVisual.");
193         return;
194     }
195
196     Window xWindow = offscreenRootWindow();
197     if (!xWindow)
198         return;
199
200     Colormap cmap = XCreateColormap(display, xWindow, visInfo.visual, AllocNone);
201     XSetWindowAttributes attribute;
202     attribute.background_pixel = WhitePixel(display, 0);
203     attribute.border_pixel = BlackPixel(display, 0);
204     attribute.colormap = cmap;
205     attribute.event_mask = ResizeRedirectMask;
206     uint32_t tempHandleId = XCreateWindow(display, xWindow, 0, 0, size.width(), size.height(), 0, visInfo.depth, InputOutput, visInfo.visual, CWBackPixel | CWBorderPixel | CWColormap, &attribute);
207
208     if (!tempHandleId) {
209         LOG_ERROR("Failed to create offscreen window.");
210         return;
211     }
212
213     XSetWindowBackgroundPixmap(display, tempHandleId, 0);
214     XCompositeRedirectWindow(display, tempHandleId, CompositeRedirectManual);
215     XMapWindow(display, tempHandleId);
216     *handleId = tempHandleId;
217 #else
218     UNUSED_PARAM(handleId);
219     UNUSED_PARAM(visInfo);
220     UNUSED_PARAM(size);
221 #endif
222 }
223
224 #if USE(EGL)
225 void X11Helper::createOffScreenWindow(uint32_t* handleId, const EGLint id, bool supportsAlpha, const IntSize& size)
226 {
227 #if USE(GRAPHICS_SURFACE)
228     VisualID visualId = static_cast<VisualID>(id);
229
230     if (!visualId)
231         return;
232
233     // EGL has suggested a visual id, so get the rest of the visual info for that id.
234     XVisualInfo visualInfoTemplate;
235     memset(&visualInfoTemplate, 0, sizeof(XVisualInfo));
236     visualInfoTemplate.visualid = visualId;
237     int matchingCount = 0;
238     OwnPtrX11<XVisualInfo> matchingVisuals(XGetVisualInfo(nativeDisplay(), VisualIDMask, &visualInfoTemplate, &matchingCount));
239     XVisualInfo* foundVisual = 0;
240
241     if (matchingVisuals) {
242         for (int i = 0; i< matchingCount; i++) {
243             XVisualInfo* temp = &matchingVisuals[i];
244
245             if (isXRenderExtensionSupported()) {
246                 XRenderPictFormat* format = XRenderFindVisualFormat(nativeDisplay(), temp->visual);
247
248                 if (format) {
249                     if (supportsAlpha) {
250                         if (temp->depth == 32 && format->direct.alphaMask > 0)
251                             foundVisual = temp;
252                     } else if (!format->direct.alphaMask)
253                         foundVisual = temp;
254                 }
255
256                 if (foundVisual)
257                     break;
258             }
259
260             int matchingdepth = supportsAlpha ? 32 : 24;
261
262             if (temp->depth == matchingdepth) {
263                 foundVisual = temp;
264                 break;
265             }
266         }
267
268         if (foundVisual)
269             createOffScreenWindow(handleId, *foundVisual, size);
270     }
271 #else
272     UNUSED_PARAM(handleId);
273     UNUSED_PARAM(id);
274     UNUSED_PARAM(size);
275 #endif
276 }
277 #endif
278
279 void X11Helper::destroyWindow(const uint32_t windowId)
280 {
281     if (!windowId)
282         return;
283
284     Display* display = nativeDisplay();
285     if (!display)
286         return;
287
288     XDestroyWindow(display, windowId);
289 }
290
291 bool X11Helper::isXRenderExtensionSupported()
292 {
293     static bool queryDone = false;
294     static bool supportsXRenderExtension = false;
295
296     if (!queryDone) {
297         queryDone = true;
298 #if USE(GRAPHICS_SURFACE)
299         Display* display = nativeDisplay();
300
301         if (display) {
302             int eventBasep, errorBasep;
303             supportsXRenderExtension = XRenderQueryExtension(display, &eventBasep, &errorBasep);
304         }
305 #endif
306     }
307
308     return supportsXRenderExtension;
309 }
310
311 Display* X11Helper::nativeDisplay()
312 {
313     // Display connection will only be broken at program shutdown.
314     static DisplayConnection displayConnection;
315     return displayConnection.display();
316 }
317
318 Window X11Helper::offscreenRootWindow()
319 {
320     static OffScreenRootWindow offscreenWindow;
321     return offscreenWindow.rootWindow();
322 }
323
324 }