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