gfx/thebes/gfxXlibSurface.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial