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