mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 14:22:01 +00:00
371135, oom crashers with big images, r=stuart
This commit is contained in:
parent
2025358959
commit
1f64321330
@ -100,7 +100,10 @@ nsThebesImage::Init(PRInt32 aWidth, PRInt32 aHeight, PRInt32 aDepth, nsMaskRequi
|
||||
#ifdef XP_WIN
|
||||
if (!ShouldUseImageSurfaces()) {
|
||||
mWinSurface = new gfxWindowsSurface(gfxIntSize(mWidth, mHeight), format);
|
||||
mImageSurface = mWinSurface->GetImageSurface();
|
||||
if (mWinSurface && mWinSurface->Status() == 0) {
|
||||
// no error
|
||||
mImageSurface = mWinSurface->GetImageSurface();
|
||||
}
|
||||
}
|
||||
|
||||
if (!mImageSurface) {
|
||||
@ -110,6 +113,13 @@ nsThebesImage::Init(PRInt32 aWidth, PRInt32 aHeight, PRInt32 aDepth, nsMaskRequi
|
||||
#else
|
||||
mImageSurface = new gfxImageSurface(gfxIntSize(mWidth, mHeight), format);
|
||||
#endif
|
||||
|
||||
if (!mImageSurface || mImageSurface->Status()) {
|
||||
mImageSurface = nsnull;
|
||||
// guess
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
mStride = mImageSurface->Stride();
|
||||
|
||||
return NS_OK;
|
||||
@ -286,7 +296,7 @@ nsThebesImage::LockImagePixels(PRBool aMaskPixels)
|
||||
// Recover the pixels
|
||||
mImageSurface = new gfxImageSurface(gfxIntSize(mWidth, mHeight),
|
||||
gfxImageSurface::ImageFormatARGB32);
|
||||
if (!mImageSurface)
|
||||
if (!mImageSurface || mImageSurface->Status())
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
nsRefPtr<gfxContext> context = new gfxContext(mImageSurface);
|
||||
if (!context) {
|
||||
@ -464,6 +474,11 @@ nsThebesImage::ThebesDrawTile(gfxContext *thebesContext,
|
||||
|
||||
surface = new gfxImageSurface(gfxIntSize(width, height),
|
||||
gfxASurface::ImageFormatARGB32);
|
||||
if (!surface || surface->Status()) {
|
||||
thebesContext->SetMatrix(savedCTM);
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
tmpSurfaceGrip = surface;
|
||||
|
||||
nsRefPtr<gfxContext> tmpContext = new gfxContext(surface);
|
||||
|
@ -94,7 +94,10 @@ public:
|
||||
static already_AddRefed<gfxASurface> Wrap(cairo_surface_t *csurf);
|
||||
|
||||
/*** this DOES NOT addref the surface */
|
||||
cairo_surface_t *CairoSurface() { return mSurface; }
|
||||
cairo_surface_t *CairoSurface() {
|
||||
NS_ASSERTION(mSurface != nsnull, "gfxASurface::CairoSurface called with mSurface == nsnull!");
|
||||
return mSurface;
|
||||
}
|
||||
|
||||
gfxSurfaceType GetType() const;
|
||||
|
||||
@ -121,7 +124,17 @@ public:
|
||||
|
||||
virtual void Finish();
|
||||
|
||||
int Status();
|
||||
|
||||
/* Make sure that the given dimensions don't overflow a 32-bit signed int
|
||||
* using 4 bytes per pixel; optionally, make sure that either dimension
|
||||
* doesn't exceed the given limit.
|
||||
*/
|
||||
static PRBool CheckSurfaceSize(const gfxIntSize& sz, PRInt32 limit = 0);
|
||||
|
||||
protected:
|
||||
gfxASurface() : mSurface(nsnull), mFloatingRefs(0), mSurfaceValid(PR_FALSE) { }
|
||||
|
||||
static gfxASurface* GetSurfaceWrapper(cairo_surface_t *csurf);
|
||||
static void SetSurfaceWrapper(cairo_surface_t *csurf, gfxASurface *asurf);
|
||||
|
||||
@ -130,10 +143,13 @@ protected:
|
||||
virtual ~gfxASurface() {
|
||||
}
|
||||
private:
|
||||
cairo_surface_t *mSurface;
|
||||
PRPackedBool mHasFloatingRef;
|
||||
|
||||
static void SurfaceDestroyFunc(void *data);
|
||||
|
||||
cairo_surface_t *mSurface;
|
||||
PRInt32 mFloatingRefs;
|
||||
|
||||
protected:
|
||||
PRPackedBool mSurfaceValid;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -65,30 +65,47 @@ gfxASurface::AddRef(void)
|
||||
{
|
||||
NS_PRECONDITION(mSurface != nsnull, "gfxASurface::AddRef without mSurface");
|
||||
|
||||
if (mHasFloatingRef) {
|
||||
// eat the floating ref
|
||||
mHasFloatingRef = PR_FALSE;
|
||||
} else {
|
||||
cairo_surface_reference(mSurface);
|
||||
}
|
||||
if (mSurfaceValid) {
|
||||
if (mFloatingRefs) {
|
||||
// eat a floating ref
|
||||
mFloatingRefs--;
|
||||
} else {
|
||||
cairo_surface_reference(mSurface);
|
||||
}
|
||||
|
||||
return (nsrefcnt) cairo_surface_get_reference_count(mSurface);
|
||||
return (nsrefcnt) cairo_surface_get_reference_count(mSurface);
|
||||
} else {
|
||||
// the surface isn't valid, but we still need to refcount
|
||||
// the gfxASurface
|
||||
return ++mFloatingRefs;
|
||||
}
|
||||
}
|
||||
|
||||
nsrefcnt
|
||||
gfxASurface::Release(void)
|
||||
{
|
||||
NS_PRECONDITION(!mHasFloatingRef, "gfxASurface::Release while floating ref still outstanding!");
|
||||
NS_PRECONDITION(mSurface != nsnull, "gfxASurface::Release without mSurface");
|
||||
// Note that there is a destructor set on user data for mSurface,
|
||||
// which will delete this gfxASurface wrapper when the surface's refcount goes
|
||||
// out of scope.
|
||||
nsrefcnt refcnt = (nsrefcnt) cairo_surface_get_reference_count(mSurface);
|
||||
cairo_surface_destroy(mSurface);
|
||||
|
||||
// |this| may not be valid any more, don't use it!
|
||||
if (mSurfaceValid) {
|
||||
NS_ASSERTION(mFloatingRefs == 0, "gfxASurface::Release with floating refs still hanging around!");
|
||||
|
||||
return --refcnt;
|
||||
// Note that there is a destructor set on user data for mSurface,
|
||||
// which will delete this gfxASurface wrapper when the surface's refcount goes
|
||||
// out of scope.
|
||||
nsrefcnt refcnt = (nsrefcnt) cairo_surface_get_reference_count(mSurface);
|
||||
cairo_surface_destroy(mSurface);
|
||||
|
||||
// |this| may not be valid any more, don't use it!
|
||||
|
||||
return --refcnt;
|
||||
} else {
|
||||
if (--mFloatingRefs == 0) {
|
||||
delete this;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return mFloatingRefs;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@ -157,14 +174,22 @@ gfxASurface::Wrap (cairo_surface_t *csurf)
|
||||
void
|
||||
gfxASurface::Init(cairo_surface_t* surface, PRBool existingSurface)
|
||||
{
|
||||
if (cairo_surface_status(surface)) {
|
||||
// the surface has an error on it
|
||||
mSurfaceValid = PR_FALSE;
|
||||
cairo_surface_destroy(surface);
|
||||
return;
|
||||
}
|
||||
|
||||
SetSurfaceWrapper(surface, this);
|
||||
|
||||
mSurface = surface;
|
||||
mSurfaceValid = PR_TRUE;
|
||||
|
||||
if (existingSurface) {
|
||||
mHasFloatingRef = PR_FALSE;
|
||||
mFloatingRefs = 0;
|
||||
} else {
|
||||
mHasFloatingRef = PR_TRUE;
|
||||
mFloatingRefs = 1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -215,7 +240,6 @@ gfxASurface::MarkDirty(const gfxRect& r)
|
||||
(int) r.size.width, (int) r.size.height);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
gfxASurface::SetData(const cairo_user_data_key_t *key,
|
||||
void *user_data,
|
||||
@ -235,3 +259,37 @@ gfxASurface::Finish()
|
||||
{
|
||||
cairo_surface_finish(mSurface);
|
||||
}
|
||||
|
||||
int
|
||||
gfxASurface::Status()
|
||||
{
|
||||
if (!mSurfaceValid)
|
||||
return -1;
|
||||
|
||||
return cairo_surface_status(mSurface);
|
||||
}
|
||||
|
||||
/* static */
|
||||
PRBool
|
||||
gfxASurface::CheckSurfaceSize(const gfxIntSize& sz, PRInt32 limit)
|
||||
{
|
||||
if (sz.width <= 0 || sz.height <= 0)
|
||||
return PR_FALSE;
|
||||
|
||||
// check to make sure we don't overflow a 32-bit
|
||||
PRInt32 tmp = sz.width * sz.height;
|
||||
if (tmp / sz.height != sz.width)
|
||||
return PR_FALSE;
|
||||
|
||||
// always assume 4-byte stride
|
||||
tmp = tmp * 4;
|
||||
if (tmp / 4 != sz.width * sz.height)
|
||||
return PR_FALSE;
|
||||
|
||||
// reject images with sides bigger than limit
|
||||
if (limit &&
|
||||
(sz.width > limit || sz.height > limit))
|
||||
return PR_FALSE;
|
||||
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
@ -35,6 +35,8 @@
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "prmem.h"
|
||||
|
||||
#include "gfxImageSurface.h"
|
||||
|
||||
#include "cairo.h"
|
||||
@ -42,8 +44,15 @@
|
||||
gfxImageSurface::gfxImageSurface(const gfxIntSize& size, gfxImageFormat format) :
|
||||
mSize(size), mFormat(format)
|
||||
{
|
||||
long stride = ComputeStride();
|
||||
mData = new unsigned char[mSize.height * stride];
|
||||
mStride = ComputeStride();
|
||||
|
||||
if (!CheckSurfaceSize(size))
|
||||
return;
|
||||
|
||||
mData = (unsigned char *) malloc(mSize.height * mStride);
|
||||
if (!mData)
|
||||
return;
|
||||
|
||||
mOwnsData = PR_TRUE;
|
||||
|
||||
cairo_surface_t *surface =
|
||||
@ -51,9 +60,7 @@ gfxImageSurface::gfxImageSurface(const gfxIntSize& size, gfxImageFormat format)
|
||||
(cairo_format_t)format,
|
||||
mSize.width,
|
||||
mSize.height,
|
||||
stride);
|
||||
mStride = stride;
|
||||
|
||||
mStride);
|
||||
Init(surface);
|
||||
}
|
||||
|
||||
@ -71,8 +78,13 @@ gfxImageSurface::gfxImageSurface(cairo_surface_t *csurf)
|
||||
|
||||
gfxImageSurface::~gfxImageSurface()
|
||||
{
|
||||
if (mOwnsData)
|
||||
delete[] mData;
|
||||
if (!mSurfaceValid)
|
||||
return;
|
||||
|
||||
if (mOwnsData) {
|
||||
free(mData);
|
||||
mData = nsnull;
|
||||
}
|
||||
}
|
||||
|
||||
long
|
||||
|
@ -42,6 +42,9 @@
|
||||
gfxQuartzSurface::gfxQuartzSurface(const gfxSize& size, gfxImageFormat format)
|
||||
: mSize(size)
|
||||
{
|
||||
if (!CheckSurfaceSize(size))
|
||||
return;
|
||||
|
||||
cairo_surface_t *surf = cairo_quartz_surface_create
|
||||
((cairo_format_t) format, floor(size.width), floor(size.height));
|
||||
|
||||
|
@ -60,12 +60,11 @@ gfxWindowsSurface::gfxWindowsSurface(HDC dc, PRBool deleteDC) :
|
||||
gfxWindowsSurface::gfxWindowsSurface(const gfxIntSize& size, gfxImageFormat imageFormat) :
|
||||
mOwnsDC(PR_FALSE), mWnd(nsnull)
|
||||
{
|
||||
if (!CheckSurfaceSize(size))
|
||||
return;
|
||||
|
||||
cairo_surface_t *surf = cairo_win32_surface_create_with_dib((cairo_format_t)imageFormat,
|
||||
size.width, size.height);
|
||||
if (!surf || cairo_surface_status(surf)) {
|
||||
fprintf (stderr, "++++++++++++ gfxWindowsSurface: DIB surface creation failed!\n");
|
||||
}
|
||||
|
||||
Init(surf);
|
||||
|
||||
mDC = cairo_win32_surface_get_dc(CairoSurface());
|
||||
@ -74,12 +73,11 @@ gfxWindowsSurface::gfxWindowsSurface(const gfxIntSize& size, gfxImageFormat imag
|
||||
gfxWindowsSurface::gfxWindowsSurface(HDC dc, const gfxIntSize& size, gfxImageFormat imageFormat) :
|
||||
mOwnsDC(PR_FALSE), mWnd(nsnull)
|
||||
{
|
||||
if (!CheckSurfaceSize(size))
|
||||
return;
|
||||
|
||||
cairo_surface_t *surf = cairo_win32_surface_create_with_ddb(dc, (cairo_format_t)imageFormat,
|
||||
size.width, size.height);
|
||||
if (!surf || cairo_surface_status(surf)) {
|
||||
fprintf (stderr, "++++++++++++ gfxWindowsSurface: DDB surface creation failed!\n");
|
||||
}
|
||||
|
||||
Init(surf);
|
||||
|
||||
mDC = cairo_win32_surface_get_dc(CairoSurface());
|
||||
|
@ -51,6 +51,8 @@ typedef struct {
|
||||
|
||||
static void pixmap_free_func (void *);
|
||||
|
||||
#define XLIB_IMAGE_SIDE_SIZE_LIMIT 0xffff
|
||||
|
||||
gfxXlibSurface::gfxXlibSurface(Display *dpy, Drawable drawable, Visual *visual)
|
||||
: mPixmapTaken(PR_FALSE), mDisplay(dpy), mDrawable(drawable)
|
||||
{
|
||||
@ -62,6 +64,9 @@ gfxXlibSurface::gfxXlibSurface(Display *dpy, Drawable drawable, Visual *visual)
|
||||
gfxXlibSurface::gfxXlibSurface(Display *dpy, Drawable drawable, Visual *visual, const gfxIntSize& size)
|
||||
: mPixmapTaken(PR_FALSE), mDisplay(dpy), mDrawable(drawable), mSize(size)
|
||||
{
|
||||
if (!CheckSurfaceSize(size, XLIB_IMAGE_SIDE_SIZE_LIMIT))
|
||||
return;
|
||||
|
||||
cairo_surface_t *surf = cairo_xlib_surface_create(dpy, drawable, visual, mSize.width, mSize.height);
|
||||
Init(surf);
|
||||
}
|
||||
@ -70,6 +75,9 @@ gfxXlibSurface::gfxXlibSurface(Display *dpy, Visual *visual, const gfxIntSize& s
|
||||
: mPixmapTaken(PR_FALSE), mDisplay(dpy), mSize(size)
|
||||
|
||||
{
|
||||
if (!CheckSurfaceSize(size, XLIB_IMAGE_SIDE_SIZE_LIMIT))
|
||||
return;
|
||||
|
||||
mDrawable = (Drawable)XCreatePixmap(dpy,
|
||||
RootWindow(dpy, DefaultScreen(dpy)),
|
||||
mSize.width, mSize.height,
|
||||
@ -85,6 +93,9 @@ gfxXlibSurface::gfxXlibSurface(Display *dpy, Drawable drawable, XRenderPictForma
|
||||
const gfxIntSize& size)
|
||||
: mPixmapTaken(PR_FALSE), mDisplay(dpy), mDrawable(drawable), mSize(size)
|
||||
{
|
||||
if (!CheckSurfaceSize(size, XLIB_IMAGE_SIDE_SIZE_LIMIT))
|
||||
return;
|
||||
|
||||
cairo_surface_t *surf = cairo_xlib_surface_create_with_xrender_format(dpy, drawable,
|
||||
ScreenOfDisplay(dpy,DefaultScreen(dpy)),
|
||||
format, mSize.width, mSize.height);
|
||||
|
Loading…
Reference in New Issue
Block a user