Bug 994081 - [3/3] Optimize surfaces on Cairo X11, r=Bas f=karlt

This commit is contained in:
Michael Wu 2014-05-22 20:06:16 -04:00
parent 82821675ed
commit 19d86c1d8f

View File

@ -11,6 +11,7 @@
#include "ScaledFontBase.h"
#include "BorrowedContext.h"
#include "FilterNodeSoftware.h"
#include "mozilla/Scoped.h"
#include "cairo.h"
#include "cairo-tee.h"
@ -27,6 +28,7 @@
#ifdef CAIRO_HAS_XLIB_SURFACE
#include "cairo-xlib.h"
#include "cairo-xlib-xrender.h"
#endif
#ifdef CAIRO_HAS_WIN32_SURFACE
@ -36,6 +38,9 @@
#include <algorithm>
namespace mozilla {
MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedCairoSurface, cairo_surface_t, cairo_surface_destroy);
namespace gfx {
cairo_surface_t *DrawTargetCairo::mDummySurface;
@ -1057,9 +1062,106 @@ DrawTargetCairo::CreateSourceSurfaceFromData(unsigned char *aData,
return source_surf;
}
#ifdef CAIRO_HAS_XLIB_SURFACE
static cairo_user_data_key_t gDestroyPixmapKey;
struct DestroyPixmapClosure {
DestroyPixmapClosure(Drawable d, Screen *s) : mPixmap(d), mScreen(s) {}
~DestroyPixmapClosure() {
XFreePixmap(DisplayOfScreen(mScreen), mPixmap);
}
Drawable mPixmap;
Screen *mScreen;
};
static void
DestroyPixmap(void *data)
{
delete static_cast<DestroyPixmapClosure*>(data);
}
#endif
TemporaryRef<SourceSurface>
DrawTargetCairo::OptimizeSourceSurface(SourceSurface *aSurface) const
{
#ifdef CAIRO_HAS_XLIB_SURFACE
if (cairo_surface_get_type(mSurface) != CAIRO_SURFACE_TYPE_XLIB) {
return aSurface;
}
IntSize size = aSurface->GetSize();
if (!size.width || !size.height) {
return aSurface;
}
// Although the dimension parameters in the xCreatePixmapReq wire protocol are
// 16-bit unsigned integers, the server's CreatePixmap returns BadAlloc if
// either dimension cannot be represented by a 16-bit *signed* integer.
#define XLIB_IMAGE_SIDE_SIZE_LIMIT 0x7fff
if (size.width > XLIB_IMAGE_SIDE_SIZE_LIMIT ||
size.height > XLIB_IMAGE_SIDE_SIZE_LIMIT) {
return aSurface;
}
SurfaceFormat format = aSurface->GetFormat();
Screen *screen = cairo_xlib_surface_get_screen(mSurface);
Display *dpy = DisplayOfScreen(screen);
XRenderPictFormat* xrenderFormat = nullptr;
switch (format) {
case SurfaceFormat::B8G8R8A8:
xrenderFormat = XRenderFindStandardFormat(dpy, PictStandardARGB32);
break;
case SurfaceFormat::B8G8R8X8:
xrenderFormat = XRenderFindStandardFormat(dpy, PictStandardRGB24);
break;
case SurfaceFormat::A8:
xrenderFormat = XRenderFindStandardFormat(dpy, PictStandardA8);
break;
default:
return aSurface;
}
if (!xrenderFormat) {
return aSurface;
}
Drawable pixmap = XCreatePixmap(dpy, RootWindowOfScreen(screen),
size.width, size.height,
xrenderFormat->depth);
if (!pixmap) {
return aSurface;
}
ScopedDeletePtr<DestroyPixmapClosure> closure(
new DestroyPixmapClosure(pixmap, screen));
ScopedCairoSurface csurf(
cairo_xlib_surface_create_with_xrender_format(dpy, pixmap,
screen, xrenderFormat,
size.width, size.height));
if (!csurf || cairo_surface_status(csurf)) {
return aSurface;
}
cairo_surface_set_user_data(csurf, &gDestroyPixmapKey,
closure.forget(), DestroyPixmap);
RefPtr<DrawTargetCairo> dt = new DrawTargetCairo();
if (!dt->Init(csurf, size, &format)) {
return aSurface;
}
dt->CopySurface(aSurface,
IntRect(0, 0, size.width, size.height),
IntPoint(0, 0));
dt->Flush();
RefPtr<SourceSurface> surf =
new SourceSurfaceCairo(csurf, size, format);
return surf;
#endif
return aSurface;
}