/src/mozilla-central/gfx/thebes/gfxXlibSurface.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
2 | | * This Source Code Form is subject to the terms of the Mozilla Public |
3 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
4 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
5 | | |
6 | | #include "gfxXlibSurface.h" |
7 | | |
8 | | #include "cairo.h" |
9 | | #include "cairo-xlib.h" |
10 | | #include "cairo-xlib-xrender.h" |
11 | | #include <X11/Xlibint.h> /* For XESetCloseDisplay */ |
12 | | #undef max // Xlibint.h defines this and it breaks std::max |
13 | | #undef min // Xlibint.h defines this and it breaks std::min |
14 | | #undef Data |
15 | | |
16 | | #include "nsTArray.h" |
17 | | #include "nsAlgorithm.h" |
18 | | #include "mozilla/gfx/2D.h" |
19 | | #include "mozilla/Preferences.h" |
20 | | #include <algorithm> |
21 | | #include "mozilla/CheckedInt.h" |
22 | | |
23 | | using namespace mozilla; |
24 | | using namespace mozilla::gfx; |
25 | | |
26 | | gfxXlibSurface::gfxXlibSurface(Display *dpy, Drawable drawable, Visual *visual) |
27 | | : mPixmapTaken(false), mDisplay(dpy), mDrawable(drawable) |
28 | | , mGLXPixmap(X11None) |
29 | 0 | { |
30 | 0 | const gfx::IntSize size = DoSizeQuery(); |
31 | 0 | cairo_surface_t *surf = cairo_xlib_surface_create(dpy, drawable, visual, size.width, size.height); |
32 | 0 | Init(surf); |
33 | 0 | } |
34 | | |
35 | | gfxXlibSurface::gfxXlibSurface(Display *dpy, Drawable drawable, Visual *visual, const gfx::IntSize& size) |
36 | | : mPixmapTaken(false), mDisplay(dpy), mDrawable(drawable) |
37 | | , mGLXPixmap(X11None) |
38 | 0 | { |
39 | 0 | NS_ASSERTION(Factory::CheckSurfaceSize(size, XLIB_IMAGE_SIDE_SIZE_LIMIT), |
40 | 0 | "Bad size"); |
41 | 0 |
|
42 | 0 | cairo_surface_t *surf = cairo_xlib_surface_create(dpy, drawable, visual, size.width, size.height); |
43 | 0 | Init(surf); |
44 | 0 | } |
45 | | |
46 | | gfxXlibSurface::gfxXlibSurface(Screen *screen, Drawable drawable, XRenderPictFormat *format, |
47 | | const gfx::IntSize& size) |
48 | | : mPixmapTaken(false) |
49 | | , mDisplay(DisplayOfScreen(screen)) |
50 | | , mDrawable(drawable) |
51 | | , mGLXPixmap(X11None) |
52 | 0 | { |
53 | 0 | NS_ASSERTION(Factory::CheckSurfaceSize(size, XLIB_IMAGE_SIDE_SIZE_LIMIT), |
54 | 0 | "Bad Size"); |
55 | 0 |
|
56 | 0 | cairo_surface_t *surf = |
57 | 0 | cairo_xlib_surface_create_with_xrender_format(mDisplay, drawable, |
58 | 0 | screen, format, |
59 | 0 | size.width, size.height); |
60 | 0 | Init(surf); |
61 | 0 | } |
62 | | |
63 | | gfxXlibSurface::gfxXlibSurface(cairo_surface_t *csurf) |
64 | | : mPixmapTaken(false) |
65 | | , mGLXPixmap(X11None) |
66 | 0 | { |
67 | 0 | MOZ_ASSERT(cairo_surface_status(csurf) == 0, |
68 | 0 | "Not expecting an error surface"); |
69 | 0 |
|
70 | 0 | mDrawable = cairo_xlib_surface_get_drawable(csurf); |
71 | 0 | mDisplay = cairo_xlib_surface_get_display(csurf); |
72 | 0 |
|
73 | 0 | Init(csurf, true); |
74 | 0 | } |
75 | | |
76 | | gfxXlibSurface::~gfxXlibSurface() |
77 | 0 | { |
78 | 0 | // gfxASurface's destructor calls RecordMemoryFreed(). |
79 | 0 | if (mPixmapTaken) { |
80 | 0 | if (mGLXPixmap) { |
81 | 0 | gl::sGLXLibrary.DestroyPixmap(mDisplay, mGLXPixmap); |
82 | 0 | } |
83 | 0 | XFreePixmap (mDisplay, mDrawable); |
84 | 0 | } |
85 | 0 | } |
86 | | |
87 | | static Drawable |
88 | | CreatePixmap(Screen *screen, const gfx::IntSize& size, unsigned int depth, |
89 | | Drawable relatedDrawable) |
90 | 0 | { |
91 | 0 | if (!Factory::CheckSurfaceSize(size, XLIB_IMAGE_SIDE_SIZE_LIMIT)) |
92 | 0 | return X11None; |
93 | 0 | |
94 | 0 | if (relatedDrawable == X11None) { |
95 | 0 | relatedDrawable = RootWindowOfScreen(screen); |
96 | 0 | } |
97 | 0 | Display *dpy = DisplayOfScreen(screen); |
98 | 0 | // X gives us a fatal error if we try to create a pixmap of width |
99 | 0 | // or height 0 |
100 | 0 | return XCreatePixmap(dpy, relatedDrawable, |
101 | 0 | std::max(1, size.width), std::max(1, size.height), |
102 | 0 | depth); |
103 | 0 | } |
104 | | |
105 | | void |
106 | | gfxXlibSurface::TakePixmap() |
107 | 0 | { |
108 | 0 | NS_ASSERTION(!mPixmapTaken, "I already own the Pixmap!"); |
109 | 0 | mPixmapTaken = true; |
110 | 0 |
|
111 | 0 | // The bit depth returned from Cairo is technically int, but this is |
112 | 0 | // the last place we'd be worried about that scenario. |
113 | 0 | unsigned int bitDepth = cairo_xlib_surface_get_depth(CairoSurface()); |
114 | 0 | MOZ_ASSERT((bitDepth % 8) == 0, "Memory used not recorded correctly"); |
115 | 0 |
|
116 | 0 | // Divide by 8 because surface_get_depth gives us the number of *bits* per |
117 | 0 | // pixel. |
118 | 0 | gfx::IntSize size = GetSize(); |
119 | 0 | CheckedInt32 totalBytes = CheckedInt32(size.width) * CheckedInt32(size.height) * (bitDepth/8); |
120 | 0 |
|
121 | 0 | // Don't do anything in the "else" case. We could add INT32_MAX, but that |
122 | 0 | // would overflow the memory used counter. It would also mean we tried for |
123 | 0 | // a 2G image. For now, we'll just assert, |
124 | 0 | MOZ_ASSERT(totalBytes.isValid(),"Did not expect to exceed 2Gb image"); |
125 | 0 | if (totalBytes.isValid()) { |
126 | 0 | RecordMemoryUsed(totalBytes.value()); |
127 | 0 | } |
128 | 0 | } |
129 | | |
130 | | Drawable |
131 | 0 | gfxXlibSurface::ReleasePixmap() { |
132 | 0 | NS_ASSERTION(mPixmapTaken, "I don't own the Pixmap!"); |
133 | 0 | mPixmapTaken = false; |
134 | 0 | RecordMemoryFreed(); |
135 | 0 | return mDrawable; |
136 | 0 | } |
137 | | |
138 | | static cairo_user_data_key_t gDestroyPixmapKey; |
139 | | |
140 | | struct DestroyPixmapClosure { |
141 | 0 | DestroyPixmapClosure(Drawable d, Screen *s) : mPixmap(d), mScreen(s) {} |
142 | | Drawable mPixmap; |
143 | | Screen *mScreen; |
144 | | }; |
145 | | |
146 | | static void |
147 | | DestroyPixmap(void *data) |
148 | 0 | { |
149 | 0 | DestroyPixmapClosure *closure = static_cast<DestroyPixmapClosure*>(data); |
150 | 0 | XFreePixmap(DisplayOfScreen(closure->mScreen), closure->mPixmap); |
151 | 0 | delete closure; |
152 | 0 | } |
153 | | |
154 | | /* static */ |
155 | | cairo_surface_t * |
156 | | gfxXlibSurface::CreateCairoSurface(Screen *screen, Visual *visual, |
157 | | const gfx::IntSize& size, Drawable relatedDrawable) |
158 | 0 | { |
159 | 0 | Drawable drawable = |
160 | 0 | CreatePixmap(screen, size, DepthOfVisual(screen, visual), |
161 | 0 | relatedDrawable); |
162 | 0 | if (!drawable) |
163 | 0 | return nullptr; |
164 | 0 | |
165 | 0 | cairo_surface_t* surface = |
166 | 0 | cairo_xlib_surface_create(DisplayOfScreen(screen), drawable, visual, |
167 | 0 | size.width, size.height); |
168 | 0 | if (cairo_surface_status(surface)) { |
169 | 0 | cairo_surface_destroy(surface); |
170 | 0 | XFreePixmap(DisplayOfScreen(screen), drawable); |
171 | 0 | return nullptr; |
172 | 0 | } |
173 | 0 | |
174 | 0 | DestroyPixmapClosure *closure = new DestroyPixmapClosure(drawable, screen); |
175 | 0 | cairo_surface_set_user_data(surface, &gDestroyPixmapKey, |
176 | 0 | closure, DestroyPixmap); |
177 | 0 | return surface; |
178 | 0 | } |
179 | | |
180 | | /* static */ |
181 | | already_AddRefed<gfxXlibSurface> |
182 | | gfxXlibSurface::Create(Screen *screen, Visual *visual, |
183 | | const gfx::IntSize& size, Drawable relatedDrawable) |
184 | 0 | { |
185 | 0 | Drawable drawable = |
186 | 0 | CreatePixmap(screen, size, DepthOfVisual(screen, visual), |
187 | 0 | relatedDrawable); |
188 | 0 | if (!drawable) |
189 | 0 | return nullptr; |
190 | 0 | |
191 | 0 | RefPtr<gfxXlibSurface> result = |
192 | 0 | new gfxXlibSurface(DisplayOfScreen(screen), drawable, visual, size); |
193 | 0 | result->TakePixmap(); |
194 | 0 |
|
195 | 0 | if (result->CairoStatus() != 0) |
196 | 0 | return nullptr; |
197 | 0 | |
198 | 0 | return result.forget(); |
199 | 0 | } |
200 | | |
201 | | /* static */ |
202 | | already_AddRefed<gfxXlibSurface> |
203 | | gfxXlibSurface::Create(Screen *screen, XRenderPictFormat *format, |
204 | | const gfx::IntSize& size, Drawable relatedDrawable) |
205 | 0 | { |
206 | 0 | Drawable drawable = |
207 | 0 | CreatePixmap(screen, size, format->depth, relatedDrawable); |
208 | 0 | if (!drawable) |
209 | 0 | return nullptr; |
210 | 0 | |
211 | 0 | RefPtr<gfxXlibSurface> result = |
212 | 0 | new gfxXlibSurface(screen, drawable, format, size); |
213 | 0 | result->TakePixmap(); |
214 | 0 |
|
215 | 0 | if (result->CairoStatus() != 0) |
216 | 0 | return nullptr; |
217 | 0 | |
218 | 0 | return result.forget(); |
219 | 0 | } |
220 | | |
221 | | static bool GetForce24bppPref() |
222 | 0 | { |
223 | 0 | return Preferences::GetBool("mozilla.widget.force-24bpp", false); |
224 | 0 | } |
225 | | |
226 | | already_AddRefed<gfxASurface> |
227 | | gfxXlibSurface::CreateSimilarSurface(gfxContentType aContent, |
228 | | const gfx::IntSize& aSize) |
229 | 0 | { |
230 | 0 | if (!mSurface || !mSurfaceValid) { |
231 | 0 | return nullptr; |
232 | 0 | } |
233 | 0 | |
234 | 0 | if (aContent == gfxContentType::COLOR) { |
235 | 0 | // cairo_surface_create_similar will use a matching visual if it can. |
236 | 0 | // However, systems with 16-bit or indexed default visuals may benefit |
237 | 0 | // from rendering with 24-bit formats. |
238 | 0 | static bool force24bpp = GetForce24bppPref(); |
239 | 0 | if (force24bpp |
240 | 0 | && cairo_xlib_surface_get_depth(CairoSurface()) != 24) { |
241 | 0 | XRenderPictFormat* format = |
242 | 0 | XRenderFindStandardFormat(mDisplay, PictStandardRGB24); |
243 | 0 | if (format) { |
244 | 0 | // Cairo only performs simple self-copies as desired if it |
245 | 0 | // knows that this is a Pixmap surface. It only knows that |
246 | 0 | // surfaces are pixmap surfaces if it creates the Pixmap |
247 | 0 | // itself, so we use cairo_surface_create_similar with a |
248 | 0 | // temporary reference surface to indicate the format. |
249 | 0 | Screen* screen = cairo_xlib_surface_get_screen(CairoSurface()); |
250 | 0 | RefPtr<gfxXlibSurface> depth24reference = |
251 | 0 | gfxXlibSurface::Create(screen, format, |
252 | 0 | gfx::IntSize(1, 1), mDrawable); |
253 | 0 | if (depth24reference) |
254 | 0 | return depth24reference-> |
255 | 0 | gfxASurface::CreateSimilarSurface(aContent, aSize); |
256 | 0 | } |
257 | 0 | } |
258 | 0 | } |
259 | 0 | |
260 | 0 | return gfxASurface::CreateSimilarSurface(aContent, aSize); |
261 | 0 | } |
262 | | |
263 | | void |
264 | | gfxXlibSurface::Finish() |
265 | 0 | { |
266 | 0 | if (mPixmapTaken && mGLXPixmap) { |
267 | 0 | gl::sGLXLibrary.DestroyPixmap(mDisplay, mGLXPixmap); |
268 | 0 | mGLXPixmap = X11None; |
269 | 0 | } |
270 | 0 | gfxASurface::Finish(); |
271 | 0 | } |
272 | | |
273 | | const gfx::IntSize |
274 | | gfxXlibSurface::GetSize() const |
275 | 0 | { |
276 | 0 | if (!mSurfaceValid) |
277 | 0 | return gfx::IntSize(0,0); |
278 | 0 | |
279 | 0 | return gfx::IntSize(cairo_xlib_surface_get_width(mSurface), |
280 | 0 | cairo_xlib_surface_get_height(mSurface)); |
281 | 0 | } |
282 | | |
283 | | const gfx::IntSize |
284 | | gfxXlibSurface::DoSizeQuery() |
285 | 0 | { |
286 | 0 | // figure out width/height/depth |
287 | 0 | Window root_ignore; |
288 | 0 | int x_ignore, y_ignore; |
289 | 0 | unsigned int bwidth_ignore, width, height, depth; |
290 | 0 |
|
291 | 0 | XGetGeometry(mDisplay, |
292 | 0 | mDrawable, |
293 | 0 | &root_ignore, &x_ignore, &y_ignore, |
294 | 0 | &width, &height, |
295 | 0 | &bwidth_ignore, &depth); |
296 | 0 |
|
297 | 0 | return gfx::IntSize(width, height); |
298 | 0 | } |
299 | | |
300 | | class DisplayTable { |
301 | | public: |
302 | | static bool GetColormapAndVisual(Screen* screen, |
303 | | XRenderPictFormat* format, |
304 | | Visual* visual, Colormap* colormap, |
305 | | Visual** visualForColormap); |
306 | | |
307 | | private: |
308 | | struct ColormapEntry { |
309 | | XRenderPictFormat* mFormat; |
310 | | // The Screen is needed here because colormaps (and their visuals) may |
311 | | // only be used on one Screen, but XRenderPictFormats are not unique |
312 | | // to any one Screen. |
313 | | Screen* mScreen; |
314 | | Visual* mVisual; |
315 | | Colormap mColormap; |
316 | | }; |
317 | | |
318 | | class DisplayInfo { |
319 | | public: |
320 | 0 | explicit DisplayInfo(Display* display) : mDisplay(display) { } |
321 | | Display* mDisplay; |
322 | | nsTArray<ColormapEntry> mColormapEntries; |
323 | | }; |
324 | | |
325 | | // Comparator for finding the DisplayInfo |
326 | | class FindDisplay { |
327 | | public: |
328 | | bool Equals(const DisplayInfo& info, const Display *display) const |
329 | 0 | { |
330 | 0 | return info.mDisplay == display; |
331 | 0 | } |
332 | | }; |
333 | | |
334 | | static int DisplayClosing(Display *display, XExtCodes* codes); |
335 | | |
336 | | nsTArray<DisplayInfo> mDisplays; |
337 | | static DisplayTable* sDisplayTable; |
338 | | }; |
339 | | |
340 | | DisplayTable* DisplayTable::sDisplayTable; |
341 | | |
342 | | // Pixmaps don't have a particular associated visual but the pixel values are |
343 | | // interpreted according to a visual/colormap pairs. |
344 | | // |
345 | | // cairo is designed for surfaces with either TrueColor visuals or the |
346 | | // default visual (which may not be true color). TrueColor visuals don't |
347 | | // really need a colormap because the visual indicates the pixel format, |
348 | | // and cairo uses the default visual with the default colormap, so cairo |
349 | | // surfaces don't need an explicit colormap. |
350 | | // |
351 | | // However, some toolkits (e.g. GDK) need a colormap even with TrueColor |
352 | | // visuals. We can create a colormap for these visuals, but it will use about |
353 | | // 20kB of memory in the server, so we use the default colormap when |
354 | | // suitable and share colormaps between surfaces. Another reason for |
355 | | // minimizing colormap turnover is that the plugin process must leak resources |
356 | | // for each new colormap id when using older GDK libraries (bug 569775). |
357 | | // |
358 | | // Only the format of the pixels is important for rendering to Pixmaps, so if |
359 | | // the format of a visual matches that of the surface, then that visual can be |
360 | | // used for rendering to the surface. Multiple visuals can match the same |
361 | | // format (but have different GLX properties), so the visual returned may |
362 | | // differ from the visual passed in. Colormaps are tied to a visual, so |
363 | | // should only be used with their visual. |
364 | | |
365 | | /* static */ bool |
366 | | DisplayTable::GetColormapAndVisual(Screen* aScreen, XRenderPictFormat* aFormat, |
367 | | Visual* aVisual, Colormap* aColormap, |
368 | | Visual** aVisualForColormap) |
369 | | |
370 | 0 | { |
371 | 0 | Display* display = DisplayOfScreen(aScreen); |
372 | 0 |
|
373 | 0 | // Use the default colormap if the default visual matches. |
374 | 0 | Visual *defaultVisual = DefaultVisualOfScreen(aScreen); |
375 | 0 | if (aVisual == defaultVisual |
376 | 0 | || (aFormat |
377 | 0 | && aFormat == XRenderFindVisualFormat(display, defaultVisual))) |
378 | 0 | { |
379 | 0 | *aColormap = DefaultColormapOfScreen(aScreen); |
380 | 0 | *aVisualForColormap = defaultVisual; |
381 | 0 | return true; |
382 | 0 | } |
383 | 0 | |
384 | 0 | // Only supporting TrueColor non-default visuals |
385 | 0 | if (!aVisual || aVisual->c_class != TrueColor) |
386 | 0 | return false; |
387 | 0 | |
388 | 0 | if (!sDisplayTable) { |
389 | 0 | sDisplayTable = new DisplayTable(); |
390 | 0 | } |
391 | 0 |
|
392 | 0 | nsTArray<DisplayInfo>* displays = &sDisplayTable->mDisplays; |
393 | 0 | size_t d = displays->IndexOf(display, 0, FindDisplay()); |
394 | 0 |
|
395 | 0 | if (d == displays->NoIndex) { |
396 | 0 | d = displays->Length(); |
397 | 0 | // Register for notification of display closing, when this info |
398 | 0 | // becomes invalid. |
399 | 0 | XExtCodes *codes = XAddExtension(display); |
400 | 0 | if (!codes) |
401 | 0 | return false; |
402 | 0 | |
403 | 0 | XESetCloseDisplay(display, codes->extension, DisplayClosing); |
404 | 0 | // Add a new DisplayInfo. |
405 | 0 | displays->AppendElement(display); |
406 | 0 | } |
407 | 0 |
|
408 | 0 | nsTArray<ColormapEntry>* entries = |
409 | 0 | &displays->ElementAt(d).mColormapEntries; |
410 | 0 |
|
411 | 0 | // Only a small number of formats are expected to be used, so just do a |
412 | 0 | // simple linear search. |
413 | 0 | for (uint32_t i = 0; i < entries->Length(); ++i) { |
414 | 0 | const ColormapEntry& entry = entries->ElementAt(i); |
415 | 0 | // Only the format and screen need to match. (The visual may differ.) |
416 | 0 | // If there is no format (e.g. no RENDER extension) then just compare |
417 | 0 | // the visual. |
418 | 0 | if ((aFormat && entry.mFormat == aFormat && entry.mScreen == aScreen) |
419 | 0 | || aVisual == entry.mVisual) { |
420 | 0 | *aColormap = entry.mColormap; |
421 | 0 | *aVisualForColormap = entry.mVisual; |
422 | 0 | return true; |
423 | 0 | } |
424 | 0 | } |
425 | 0 |
|
426 | 0 | // No existing entry. Create a colormap and add an entry. |
427 | 0 | Colormap colormap = XCreateColormap(display, RootWindowOfScreen(aScreen), |
428 | 0 | aVisual, AllocNone); |
429 | 0 | ColormapEntry* newEntry = entries->AppendElement(); |
430 | 0 | newEntry->mFormat = aFormat; |
431 | 0 | newEntry->mScreen = aScreen; |
432 | 0 | newEntry->mVisual = aVisual; |
433 | 0 | newEntry->mColormap = colormap; |
434 | 0 |
|
435 | 0 | *aColormap = colormap; |
436 | 0 | *aVisualForColormap = aVisual; |
437 | 0 | return true; |
438 | 0 | } |
439 | | |
440 | | /* static */ int |
441 | | DisplayTable::DisplayClosing(Display *display, XExtCodes* codes) |
442 | 0 | { |
443 | 0 | // No need to free the colormaps explicitly as they will be released when |
444 | 0 | // the connection is closed. |
445 | 0 | sDisplayTable->mDisplays.RemoveElement(display, FindDisplay()); |
446 | 0 | if (sDisplayTable->mDisplays.Length() == 0) { |
447 | 0 | delete sDisplayTable; |
448 | 0 | sDisplayTable = nullptr; |
449 | 0 | } |
450 | 0 | return 0; |
451 | 0 | } |
452 | | |
453 | | /* static */ |
454 | | bool |
455 | | gfxXlibSurface::GetColormapAndVisual(cairo_surface_t* aXlibSurface, |
456 | | Colormap* aColormap, Visual** aVisual) |
457 | 0 | { |
458 | 0 | XRenderPictFormat* format = |
459 | 0 | cairo_xlib_surface_get_xrender_format(aXlibSurface); |
460 | 0 | Screen* screen = cairo_xlib_surface_get_screen(aXlibSurface); |
461 | 0 | Visual* visual = cairo_xlib_surface_get_visual(aXlibSurface); |
462 | 0 |
|
463 | 0 | return DisplayTable::GetColormapAndVisual(screen, format, visual, |
464 | 0 | aColormap, aVisual); |
465 | 0 | } |
466 | | |
467 | | bool |
468 | | gfxXlibSurface::GetColormapAndVisual(Colormap* aColormap, Visual** aVisual) |
469 | 0 | { |
470 | 0 | if (!mSurfaceValid) |
471 | 0 | return false; |
472 | 0 | |
473 | 0 | return GetColormapAndVisual(CairoSurface(), aColormap, aVisual); |
474 | 0 | } |
475 | | |
476 | | /* static */ |
477 | | int |
478 | | gfxXlibSurface::DepthOfVisual(const Screen* screen, const Visual* visual) |
479 | 0 | { |
480 | 0 | for (int d = 0; d < screen->ndepths; d++) { |
481 | 0 | const Depth& d_info = screen->depths[d]; |
482 | 0 | if (visual >= &d_info.visuals[0] |
483 | 0 | && visual < &d_info.visuals[d_info.nvisuals]) |
484 | 0 | return d_info.depth; |
485 | 0 | } |
486 | 0 |
|
487 | 0 | NS_ERROR("Visual not on Screen."); |
488 | 0 | return 0; |
489 | 0 | } |
490 | | |
491 | | /* static */ |
492 | | Visual* |
493 | | gfxXlibSurface::FindVisual(Screen *screen, gfxImageFormat format) |
494 | 0 | { |
495 | 0 | int depth; |
496 | 0 | unsigned long red_mask, green_mask, blue_mask; |
497 | 0 | switch (format) { |
498 | 0 | case gfx::SurfaceFormat::A8R8G8B8_UINT32: |
499 | 0 | depth = 32; |
500 | 0 | red_mask = 0xff0000; |
501 | 0 | green_mask = 0xff00; |
502 | 0 | blue_mask = 0xff; |
503 | 0 | break; |
504 | 0 | case gfx::SurfaceFormat::X8R8G8B8_UINT32: |
505 | 0 | depth = 24; |
506 | 0 | red_mask = 0xff0000; |
507 | 0 | green_mask = 0xff00; |
508 | 0 | blue_mask = 0xff; |
509 | 0 | break; |
510 | 0 | case gfx::SurfaceFormat::R5G6B5_UINT16: |
511 | 0 | depth = 16; |
512 | 0 | red_mask = 0xf800; |
513 | 0 | green_mask = 0x7e0; |
514 | 0 | blue_mask = 0x1f; |
515 | 0 | break; |
516 | 0 | case gfx::SurfaceFormat::A8: |
517 | 0 | default: |
518 | 0 | return nullptr; |
519 | 0 | } |
520 | 0 | |
521 | 0 | for (int d = 0; d < screen->ndepths; d++) { |
522 | 0 | const Depth& d_info = screen->depths[d]; |
523 | 0 | if (d_info.depth != depth) |
524 | 0 | continue; |
525 | 0 | |
526 | 0 | for (int v = 0; v < d_info.nvisuals; v++) { |
527 | 0 | Visual* visual = &d_info.visuals[v]; |
528 | 0 |
|
529 | 0 | if (visual->c_class == TrueColor && |
530 | 0 | visual->red_mask == red_mask && |
531 | 0 | visual->green_mask == green_mask && |
532 | 0 | visual->blue_mask == blue_mask) |
533 | 0 | return visual; |
534 | 0 | } |
535 | 0 | } |
536 | 0 |
|
537 | 0 | return nullptr; |
538 | 0 | } |
539 | | |
540 | | /* static */ |
541 | | XRenderPictFormat* |
542 | | gfxXlibSurface::FindRenderFormat(Display *dpy, gfxImageFormat format) |
543 | 0 | { |
544 | 0 | switch (format) { |
545 | 0 | case gfx::SurfaceFormat::A8R8G8B8_UINT32: |
546 | 0 | return XRenderFindStandardFormat (dpy, PictStandardARGB32); |
547 | 0 | case gfx::SurfaceFormat::X8R8G8B8_UINT32: |
548 | 0 | return XRenderFindStandardFormat (dpy, PictStandardRGB24); |
549 | 0 | case gfx::SurfaceFormat::R5G6B5_UINT16: { |
550 | 0 | // PictStandardRGB16_565 is not standard Xrender format |
551 | 0 | // we should try to find related visual |
552 | 0 | // and find xrender format by visual |
553 | 0 | Visual *visual = FindVisual(DefaultScreenOfDisplay(dpy), format); |
554 | 0 | if (!visual) |
555 | 0 | return nullptr; |
556 | 0 | return XRenderFindVisualFormat(dpy, visual); |
557 | 0 | } |
558 | 0 | case gfx::SurfaceFormat::A8: |
559 | 0 | return XRenderFindStandardFormat (dpy, PictStandardA8); |
560 | 0 | default: |
561 | 0 | break; |
562 | 0 | } |
563 | 0 | |
564 | 0 | return nullptr; |
565 | 0 | } |
566 | | |
567 | | Screen* |
568 | | gfxXlibSurface::XScreen() |
569 | 0 | { |
570 | 0 | return cairo_xlib_surface_get_screen(CairoSurface()); |
571 | 0 | } |
572 | | |
573 | | XRenderPictFormat* |
574 | | gfxXlibSurface::XRenderFormat() |
575 | 0 | { |
576 | 0 | return cairo_xlib_surface_get_xrender_format(CairoSurface()); |
577 | 0 | } |
578 | | |
579 | | GLXPixmap |
580 | | gfxXlibSurface::GetGLXPixmap() |
581 | 0 | { |
582 | 0 | if (!mGLXPixmap) { |
583 | | #ifdef DEBUG |
584 | | // cairo_surface_has_show_text_glyphs is used solely for the |
585 | | // side-effect of setting the error on surface if |
586 | | // cairo_surface_finish() has been called. |
587 | | cairo_surface_has_show_text_glyphs(CairoSurface()); |
588 | | NS_ASSERTION(CairoStatus() != CAIRO_STATUS_SURFACE_FINISHED, |
589 | | "GetGLXPixmap called after surface finished"); |
590 | | #endif |
591 | | mGLXPixmap = gl::sGLXLibrary.CreatePixmap(this); |
592 | 0 | } |
593 | 0 | return mGLXPixmap; |
594 | 0 | } |
595 | | |
596 | | void |
597 | | gfxXlibSurface::BindGLXPixmap(GLXPixmap aPixmap) |
598 | 0 | { |
599 | 0 | MOZ_ASSERT(!mGLXPixmap, "A GLXPixmap is already bound!"); |
600 | 0 | mGLXPixmap = aPixmap; |
601 | 0 | } |
602 | | |