michael@0: /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "gfxXlibSurface.h" michael@0: michael@0: #include "cairo.h" michael@0: #include "cairo-xlib.h" michael@0: #include "cairo-xlib-xrender.h" michael@0: #include /* For XESetCloseDisplay */ michael@0: #undef max // Xlibint.h defines this and it breaks std::max michael@0: #undef min // Xlibint.h defines this and it breaks std::min michael@0: michael@0: #include "nsAutoPtr.h" michael@0: #include "nsTArray.h" michael@0: #include "nsAlgorithm.h" michael@0: #include "mozilla/Preferences.h" michael@0: #include michael@0: #include "mozilla/CheckedInt.h" michael@0: michael@0: using namespace mozilla; michael@0: michael@0: // Although the dimension parameters in the xCreatePixmapReq wire protocol are michael@0: // 16-bit unsigned integers, the server's CreatePixmap returns BadAlloc if michael@0: // either dimension cannot be represented by a 16-bit *signed* integer. michael@0: #define XLIB_IMAGE_SIDE_SIZE_LIMIT 0x7fff michael@0: michael@0: gfxXlibSurface::gfxXlibSurface(Display *dpy, Drawable drawable, Visual *visual) michael@0: : mPixmapTaken(false), mDisplay(dpy), mDrawable(drawable) michael@0: #if defined(GL_PROVIDER_GLX) michael@0: , mGLXPixmap(None) michael@0: #endif michael@0: { michael@0: const gfxIntSize size = DoSizeQuery(); michael@0: cairo_surface_t *surf = cairo_xlib_surface_create(dpy, drawable, visual, size.width, size.height); michael@0: Init(surf); michael@0: } michael@0: michael@0: gfxXlibSurface::gfxXlibSurface(Display *dpy, Drawable drawable, Visual *visual, const gfxIntSize& size) michael@0: : mPixmapTaken(false), mDisplay(dpy), mDrawable(drawable) michael@0: #if defined(GL_PROVIDER_GLX) michael@0: , mGLXPixmap(None) michael@0: #endif michael@0: { michael@0: NS_ASSERTION(CheckSurfaceSize(size, XLIB_IMAGE_SIDE_SIZE_LIMIT), michael@0: "Bad size"); michael@0: michael@0: cairo_surface_t *surf = cairo_xlib_surface_create(dpy, drawable, visual, size.width, size.height); michael@0: Init(surf); michael@0: } michael@0: michael@0: gfxXlibSurface::gfxXlibSurface(Screen *screen, Drawable drawable, XRenderPictFormat *format, michael@0: const gfxIntSize& size) michael@0: : mPixmapTaken(false), mDisplay(DisplayOfScreen(screen)), michael@0: mDrawable(drawable) michael@0: #if defined(GL_PROVIDER_GLX) michael@0: , mGLXPixmap(None) michael@0: #endif michael@0: { michael@0: NS_ASSERTION(CheckSurfaceSize(size, XLIB_IMAGE_SIDE_SIZE_LIMIT), michael@0: "Bad Size"); michael@0: michael@0: cairo_surface_t *surf = michael@0: cairo_xlib_surface_create_with_xrender_format(mDisplay, drawable, michael@0: screen, format, michael@0: size.width, size.height); michael@0: Init(surf); michael@0: } michael@0: michael@0: gfxXlibSurface::gfxXlibSurface(cairo_surface_t *csurf) michael@0: : mPixmapTaken(false) michael@0: #if defined(GL_PROVIDER_GLX) michael@0: , mGLXPixmap(None) michael@0: #endif michael@0: { michael@0: NS_PRECONDITION(cairo_surface_status(csurf) == 0, michael@0: "Not expecting an error surface"); michael@0: michael@0: mDrawable = cairo_xlib_surface_get_drawable(csurf); michael@0: mDisplay = cairo_xlib_surface_get_display(csurf); michael@0: michael@0: Init(csurf, true); michael@0: } michael@0: michael@0: gfxXlibSurface::~gfxXlibSurface() michael@0: { michael@0: #if defined(GL_PROVIDER_GLX) michael@0: if (mGLXPixmap) { michael@0: gl::sGLXLibrary.DestroyPixmap(mDisplay, mGLXPixmap); michael@0: } michael@0: #endif michael@0: // gfxASurface's destructor calls RecordMemoryFreed(). michael@0: if (mPixmapTaken) { michael@0: XFreePixmap (mDisplay, mDrawable); michael@0: } michael@0: } michael@0: michael@0: static Drawable michael@0: CreatePixmap(Screen *screen, const gfxIntSize& size, unsigned int depth, michael@0: Drawable relatedDrawable) michael@0: { michael@0: if (!gfxASurface::CheckSurfaceSize(size, XLIB_IMAGE_SIDE_SIZE_LIMIT)) michael@0: return None; michael@0: michael@0: if (relatedDrawable == None) { michael@0: relatedDrawable = RootWindowOfScreen(screen); michael@0: } michael@0: Display *dpy = DisplayOfScreen(screen); michael@0: // X gives us a fatal error if we try to create a pixmap of width michael@0: // or height 0 michael@0: return XCreatePixmap(dpy, relatedDrawable, michael@0: std::max(1, size.width), std::max(1, size.height), michael@0: depth); michael@0: } michael@0: michael@0: void michael@0: gfxXlibSurface::TakePixmap() michael@0: { michael@0: NS_ASSERTION(!mPixmapTaken, "I already own the Pixmap!"); michael@0: mPixmapTaken = true; michael@0: michael@0: // The bit depth returned from Cairo is technically int, but this is michael@0: // the last place we'd be worried about that scenario. michael@0: unsigned int bitDepth = cairo_xlib_surface_get_depth(CairoSurface()); michael@0: MOZ_ASSERT((bitDepth % 8) == 0, "Memory used not recorded correctly"); michael@0: michael@0: // Divide by 8 because surface_get_depth gives us the number of *bits* per michael@0: // pixel. michael@0: gfxIntSize size = GetSize(); michael@0: CheckedInt32 totalBytes = CheckedInt32(size.width) * CheckedInt32(size.height) * (bitDepth/8); michael@0: michael@0: // Don't do anything in the "else" case. We could add INT32_MAX, but that michael@0: // would overflow the memory used counter. It would also mean we tried for michael@0: // a 2G image. For now, we'll just assert, michael@0: MOZ_ASSERT(totalBytes.isValid(),"Did not expect to exceed 2Gb image"); michael@0: if (totalBytes.isValid()) { michael@0: RecordMemoryUsed(totalBytes.value()); michael@0: } michael@0: } michael@0: michael@0: Drawable michael@0: gfxXlibSurface::ReleasePixmap() { michael@0: NS_ASSERTION(mPixmapTaken, "I don't own the Pixmap!"); michael@0: mPixmapTaken = false; michael@0: RecordMemoryFreed(); michael@0: return mDrawable; michael@0: } michael@0: michael@0: static cairo_user_data_key_t gDestroyPixmapKey; michael@0: michael@0: struct DestroyPixmapClosure { michael@0: DestroyPixmapClosure(Drawable d, Screen *s) : mPixmap(d), mScreen(s) {} michael@0: Drawable mPixmap; michael@0: Screen *mScreen; michael@0: }; michael@0: michael@0: static void michael@0: DestroyPixmap(void *data) michael@0: { michael@0: DestroyPixmapClosure *closure = static_cast(data); michael@0: XFreePixmap(DisplayOfScreen(closure->mScreen), closure->mPixmap); michael@0: delete closure; michael@0: } michael@0: michael@0: /* static */ michael@0: cairo_surface_t * michael@0: gfxXlibSurface::CreateCairoSurface(Screen *screen, Visual *visual, michael@0: const gfxIntSize& size, Drawable relatedDrawable) michael@0: { michael@0: Drawable drawable = michael@0: CreatePixmap(screen, size, DepthOfVisual(screen, visual), michael@0: relatedDrawable); michael@0: if (!drawable) michael@0: return nullptr; michael@0: michael@0: cairo_surface_t* surface = michael@0: cairo_xlib_surface_create(DisplayOfScreen(screen), drawable, visual, michael@0: size.width, size.height); michael@0: if (cairo_surface_status(surface)) { michael@0: cairo_surface_destroy(surface); michael@0: XFreePixmap(DisplayOfScreen(screen), drawable); michael@0: return nullptr; michael@0: } michael@0: michael@0: DestroyPixmapClosure *closure = new DestroyPixmapClosure(drawable, screen); michael@0: cairo_surface_set_user_data(surface, &gDestroyPixmapKey, michael@0: closure, DestroyPixmap); michael@0: return surface; michael@0: } michael@0: michael@0: /* static */ michael@0: already_AddRefed michael@0: gfxXlibSurface::Create(Screen *screen, Visual *visual, michael@0: const gfxIntSize& size, Drawable relatedDrawable) michael@0: { michael@0: Drawable drawable = michael@0: CreatePixmap(screen, size, DepthOfVisual(screen, visual), michael@0: relatedDrawable); michael@0: if (!drawable) michael@0: return nullptr; michael@0: michael@0: nsRefPtr result = michael@0: new gfxXlibSurface(DisplayOfScreen(screen), drawable, visual, size); michael@0: result->TakePixmap(); michael@0: michael@0: if (result->CairoStatus() != 0) michael@0: return nullptr; michael@0: michael@0: return result.forget(); michael@0: } michael@0: michael@0: /* static */ michael@0: already_AddRefed michael@0: gfxXlibSurface::Create(Screen *screen, XRenderPictFormat *format, michael@0: const gfxIntSize& size, Drawable relatedDrawable) michael@0: { michael@0: Drawable drawable = michael@0: CreatePixmap(screen, size, format->depth, relatedDrawable); michael@0: if (!drawable) michael@0: return nullptr; michael@0: michael@0: nsRefPtr result = michael@0: new gfxXlibSurface(screen, drawable, format, size); michael@0: result->TakePixmap(); michael@0: michael@0: if (result->CairoStatus() != 0) michael@0: return nullptr; michael@0: michael@0: return result.forget(); michael@0: } michael@0: michael@0: static bool GetForce24bppPref() michael@0: { michael@0: return Preferences::GetBool("mozilla.widget.force-24bpp", false); michael@0: } michael@0: michael@0: already_AddRefed michael@0: gfxXlibSurface::CreateSimilarSurface(gfxContentType aContent, michael@0: const gfxIntSize& aSize) michael@0: { michael@0: if (!mSurface || !mSurfaceValid) { michael@0: return nullptr; michael@0: } michael@0: michael@0: if (aContent == gfxContentType::COLOR) { michael@0: // cairo_surface_create_similar will use a matching visual if it can. michael@0: // However, systems with 16-bit or indexed default visuals may benefit michael@0: // from rendering with 24-bit formats. michael@0: static bool force24bpp = GetForce24bppPref(); michael@0: if (force24bpp michael@0: && cairo_xlib_surface_get_depth(CairoSurface()) != 24) { michael@0: XRenderPictFormat* format = michael@0: XRenderFindStandardFormat(mDisplay, PictStandardRGB24); michael@0: if (format) { michael@0: // Cairo only performs simple self-copies as desired if it michael@0: // knows that this is a Pixmap surface. It only knows that michael@0: // surfaces are pixmap surfaces if it creates the Pixmap michael@0: // itself, so we use cairo_surface_create_similar with a michael@0: // temporary reference surface to indicate the format. michael@0: Screen* screen = cairo_xlib_surface_get_screen(CairoSurface()); michael@0: nsRefPtr depth24reference = michael@0: gfxXlibSurface::Create(screen, format, michael@0: gfxIntSize(1, 1), mDrawable); michael@0: if (depth24reference) michael@0: return depth24reference-> michael@0: gfxASurface::CreateSimilarSurface(aContent, aSize); michael@0: } michael@0: } michael@0: } michael@0: michael@0: return gfxASurface::CreateSimilarSurface(aContent, aSize); michael@0: } michael@0: michael@0: void michael@0: gfxXlibSurface::Finish() michael@0: { michael@0: #if defined(GL_PROVIDER_GLX) michael@0: if (mGLXPixmap) { michael@0: gl::sGLXLibrary.DestroyPixmap(mDisplay, mGLXPixmap); michael@0: mGLXPixmap = None; michael@0: } michael@0: #endif michael@0: gfxASurface::Finish(); michael@0: } michael@0: michael@0: const gfxIntSize michael@0: gfxXlibSurface::GetSize() const michael@0: { michael@0: if (!mSurfaceValid) michael@0: return gfxIntSize(0,0); michael@0: michael@0: return gfxIntSize(cairo_xlib_surface_get_width(mSurface), michael@0: cairo_xlib_surface_get_height(mSurface)); michael@0: } michael@0: michael@0: const gfxIntSize michael@0: gfxXlibSurface::DoSizeQuery() michael@0: { michael@0: // figure out width/height/depth michael@0: Window root_ignore; michael@0: int x_ignore, y_ignore; michael@0: unsigned int bwidth_ignore, width, height, depth; michael@0: michael@0: XGetGeometry(mDisplay, michael@0: mDrawable, michael@0: &root_ignore, &x_ignore, &y_ignore, michael@0: &width, &height, michael@0: &bwidth_ignore, &depth); michael@0: michael@0: return gfxIntSize(width, height); michael@0: } michael@0: michael@0: class DisplayTable { michael@0: public: michael@0: static bool GetColormapAndVisual(Screen* screen, michael@0: XRenderPictFormat* format, michael@0: Visual* visual, Colormap* colormap, michael@0: Visual** visualForColormap); michael@0: michael@0: private: michael@0: struct ColormapEntry { michael@0: XRenderPictFormat* mFormat; michael@0: // The Screen is needed here because colormaps (and their visuals) may michael@0: // only be used on one Screen, but XRenderPictFormats are not unique michael@0: // to any one Screen. michael@0: Screen* mScreen; michael@0: Visual* mVisual; michael@0: Colormap mColormap; michael@0: }; michael@0: michael@0: class DisplayInfo { michael@0: public: michael@0: DisplayInfo(Display* display) : mDisplay(display) { } michael@0: Display* mDisplay; michael@0: nsTArray mColormapEntries; michael@0: }; michael@0: michael@0: // Comparator for finding the DisplayInfo michael@0: class FindDisplay { michael@0: public: michael@0: bool Equals(const DisplayInfo& info, const Display *display) const michael@0: { michael@0: return info.mDisplay == display; michael@0: } michael@0: }; michael@0: michael@0: static int DisplayClosing(Display *display, XExtCodes* codes); michael@0: michael@0: nsTArray mDisplays; michael@0: static DisplayTable* sDisplayTable; michael@0: }; michael@0: michael@0: DisplayTable* DisplayTable::sDisplayTable; michael@0: michael@0: // Pixmaps don't have a particular associated visual but the pixel values are michael@0: // interpreted according to a visual/colormap pairs. michael@0: // michael@0: // cairo is designed for surfaces with either TrueColor visuals or the michael@0: // default visual (which may not be true color). TrueColor visuals don't michael@0: // really need a colormap because the visual indicates the pixel format, michael@0: // and cairo uses the default visual with the default colormap, so cairo michael@0: // surfaces don't need an explicit colormap. michael@0: // michael@0: // However, some toolkits (e.g. GDK) need a colormap even with TrueColor michael@0: // visuals. We can create a colormap for these visuals, but it will use about michael@0: // 20kB of memory in the server, so we use the default colormap when michael@0: // suitable and share colormaps between surfaces. Another reason for michael@0: // minimizing colormap turnover is that the plugin process must leak resources michael@0: // for each new colormap id when using older GDK libraries (bug 569775). michael@0: // michael@0: // Only the format of the pixels is important for rendering to Pixmaps, so if michael@0: // the format of a visual matches that of the surface, then that visual can be michael@0: // used for rendering to the surface. Multiple visuals can match the same michael@0: // format (but have different GLX properties), so the visual returned may michael@0: // differ from the visual passed in. Colormaps are tied to a visual, so michael@0: // should only be used with their visual. michael@0: michael@0: /* static */ bool michael@0: DisplayTable::GetColormapAndVisual(Screen* aScreen, XRenderPictFormat* aFormat, michael@0: Visual* aVisual, Colormap* aColormap, michael@0: Visual** aVisualForColormap) michael@0: michael@0: { michael@0: Display* display = DisplayOfScreen(aScreen); michael@0: michael@0: // Use the default colormap if the default visual matches. michael@0: Visual *defaultVisual = DefaultVisualOfScreen(aScreen); michael@0: if (aVisual == defaultVisual michael@0: || (aFormat michael@0: && aFormat == XRenderFindVisualFormat(display, defaultVisual))) michael@0: { michael@0: *aColormap = DefaultColormapOfScreen(aScreen); michael@0: *aVisualForColormap = defaultVisual; michael@0: return true; michael@0: } michael@0: michael@0: // Only supporting TrueColor non-default visuals michael@0: if (!aVisual || aVisual->c_class != TrueColor) michael@0: return false; michael@0: michael@0: if (!sDisplayTable) { michael@0: sDisplayTable = new DisplayTable(); michael@0: } michael@0: michael@0: nsTArray* displays = &sDisplayTable->mDisplays; michael@0: uint32_t d = displays->IndexOf(display, 0, FindDisplay()); michael@0: michael@0: if (d == displays->NoIndex) { michael@0: d = displays->Length(); michael@0: // Register for notification of display closing, when this info michael@0: // becomes invalid. michael@0: XExtCodes *codes = XAddExtension(display); michael@0: if (!codes) michael@0: return false; michael@0: michael@0: XESetCloseDisplay(display, codes->extension, DisplayClosing); michael@0: // Add a new DisplayInfo. michael@0: displays->AppendElement(display); michael@0: } michael@0: michael@0: nsTArray* entries = michael@0: &displays->ElementAt(d).mColormapEntries; michael@0: michael@0: // Only a small number of formats are expected to be used, so just do a michael@0: // simple linear search. michael@0: for (uint32_t i = 0; i < entries->Length(); ++i) { michael@0: const ColormapEntry& entry = entries->ElementAt(i); michael@0: // Only the format and screen need to match. (The visual may differ.) michael@0: // If there is no format (e.g. no RENDER extension) then just compare michael@0: // the visual. michael@0: if ((aFormat && entry.mFormat == aFormat && entry.mScreen == aScreen) michael@0: || aVisual == entry.mVisual) { michael@0: *aColormap = entry.mColormap; michael@0: *aVisualForColormap = entry.mVisual; michael@0: return true; michael@0: } michael@0: } michael@0: michael@0: // No existing entry. Create a colormap and add an entry. michael@0: Colormap colormap = XCreateColormap(display, RootWindowOfScreen(aScreen), michael@0: aVisual, AllocNone); michael@0: ColormapEntry* newEntry = entries->AppendElement(); michael@0: newEntry->mFormat = aFormat; michael@0: newEntry->mScreen = aScreen; michael@0: newEntry->mVisual = aVisual; michael@0: newEntry->mColormap = colormap; michael@0: michael@0: *aColormap = colormap; michael@0: *aVisualForColormap = aVisual; michael@0: return true; michael@0: } michael@0: michael@0: /* static */ int michael@0: DisplayTable::DisplayClosing(Display *display, XExtCodes* codes) michael@0: { michael@0: // No need to free the colormaps explicitly as they will be released when michael@0: // the connection is closed. michael@0: sDisplayTable->mDisplays.RemoveElement(display, FindDisplay()); michael@0: if (sDisplayTable->mDisplays.Length() == 0) { michael@0: delete sDisplayTable; michael@0: sDisplayTable = nullptr; michael@0: } michael@0: return 0; michael@0: } michael@0: michael@0: /* static */ michael@0: bool michael@0: gfxXlibSurface::GetColormapAndVisual(cairo_surface_t* aXlibSurface, michael@0: Colormap* aColormap, Visual** aVisual) michael@0: { michael@0: XRenderPictFormat* format = michael@0: cairo_xlib_surface_get_xrender_format(aXlibSurface); michael@0: Screen* screen = cairo_xlib_surface_get_screen(aXlibSurface); michael@0: Visual* visual = cairo_xlib_surface_get_visual(aXlibSurface); michael@0: michael@0: return DisplayTable::GetColormapAndVisual(screen, format, visual, michael@0: aColormap, aVisual); michael@0: } michael@0: michael@0: bool michael@0: gfxXlibSurface::GetColormapAndVisual(Colormap* aColormap, Visual** aVisual) michael@0: { michael@0: if (!mSurfaceValid) michael@0: return false; michael@0: michael@0: return GetColormapAndVisual(CairoSurface(), aColormap, aVisual); michael@0: } michael@0: michael@0: /* static */ michael@0: int michael@0: gfxXlibSurface::DepthOfVisual(const Screen* screen, const Visual* visual) michael@0: { michael@0: for (int d = 0; d < screen->ndepths; d++) { michael@0: const Depth& d_info = screen->depths[d]; michael@0: if (visual >= &d_info.visuals[0] michael@0: && visual < &d_info.visuals[d_info.nvisuals]) michael@0: return d_info.depth; michael@0: } michael@0: michael@0: NS_ERROR("Visual not on Screen."); michael@0: return 0; michael@0: } michael@0: michael@0: /* static */ michael@0: Visual* michael@0: gfxXlibSurface::FindVisual(Screen *screen, gfxImageFormat format) michael@0: { michael@0: int depth; michael@0: unsigned long red_mask, green_mask, blue_mask; michael@0: switch (format) { michael@0: case gfxImageFormat::ARGB32: michael@0: depth = 32; michael@0: red_mask = 0xff0000; michael@0: green_mask = 0xff00; michael@0: blue_mask = 0xff; michael@0: break; michael@0: case gfxImageFormat::RGB24: michael@0: depth = 24; michael@0: red_mask = 0xff0000; michael@0: green_mask = 0xff00; michael@0: blue_mask = 0xff; michael@0: break; michael@0: case gfxImageFormat::RGB16_565: michael@0: depth = 16; michael@0: red_mask = 0xf800; michael@0: green_mask = 0x7e0; michael@0: blue_mask = 0x1f; michael@0: break; michael@0: case gfxImageFormat::A8: michael@0: case gfxImageFormat::A1: michael@0: default: michael@0: return nullptr; michael@0: } michael@0: michael@0: for (int d = 0; d < screen->ndepths; d++) { michael@0: const Depth& d_info = screen->depths[d]; michael@0: if (d_info.depth != depth) michael@0: continue; michael@0: michael@0: for (int v = 0; v < d_info.nvisuals; v++) { michael@0: Visual* visual = &d_info.visuals[v]; michael@0: michael@0: if (visual->c_class == TrueColor && michael@0: visual->red_mask == red_mask && michael@0: visual->green_mask == green_mask && michael@0: visual->blue_mask == blue_mask) michael@0: return visual; michael@0: } michael@0: } michael@0: michael@0: return nullptr; michael@0: } michael@0: michael@0: /* static */ michael@0: XRenderPictFormat* michael@0: gfxXlibSurface::FindRenderFormat(Display *dpy, gfxImageFormat format) michael@0: { michael@0: switch (format) { michael@0: case gfxImageFormat::ARGB32: michael@0: return XRenderFindStandardFormat (dpy, PictStandardARGB32); michael@0: case gfxImageFormat::RGB24: michael@0: return XRenderFindStandardFormat (dpy, PictStandardRGB24); michael@0: case gfxImageFormat::RGB16_565: { michael@0: // PictStandardRGB16_565 is not standard Xrender format michael@0: // we should try to find related visual michael@0: // and find xrender format by visual michael@0: Visual *visual = FindVisual(DefaultScreenOfDisplay(dpy), format); michael@0: if (!visual) michael@0: return nullptr; michael@0: return XRenderFindVisualFormat(dpy, visual); michael@0: } michael@0: case gfxImageFormat::A8: michael@0: return XRenderFindStandardFormat (dpy, PictStandardA8); michael@0: case gfxImageFormat::A1: michael@0: return XRenderFindStandardFormat (dpy, PictStandardA1); michael@0: default: michael@0: break; michael@0: } michael@0: michael@0: return nullptr; michael@0: } michael@0: michael@0: Screen* michael@0: gfxXlibSurface::XScreen() michael@0: { michael@0: return cairo_xlib_surface_get_screen(CairoSurface()); michael@0: } michael@0: michael@0: XRenderPictFormat* michael@0: gfxXlibSurface::XRenderFormat() michael@0: { michael@0: return cairo_xlib_surface_get_xrender_format(CairoSurface()); michael@0: } michael@0: michael@0: #if defined(GL_PROVIDER_GLX) michael@0: GLXPixmap michael@0: gfxXlibSurface::GetGLXPixmap() michael@0: { michael@0: if (!mGLXPixmap) { michael@0: #ifdef DEBUG michael@0: // cairo_surface_has_show_text_glyphs is used solely for the michael@0: // side-effect of setting the error on surface if michael@0: // cairo_surface_finish() has been called. michael@0: cairo_surface_has_show_text_glyphs(CairoSurface()); michael@0: NS_ASSERTION(CairoStatus() != CAIRO_STATUS_SURFACE_FINISHED, michael@0: "GetGLXPixmap called after surface finished"); michael@0: #endif michael@0: mGLXPixmap = gl::sGLXLibrary.CreatePixmap(this); michael@0: } michael@0: return mGLXPixmap; michael@0: } michael@0: #endif michael@0: michael@0: gfxMemoryLocation michael@0: gfxXlibSurface::GetMemoryLocation() const michael@0: { michael@0: return gfxMemoryLocation::OUT_OF_PROCESS; michael@0: }