From 8955c86721b67686266c0a9d3fbb16a29ac4939a Mon Sep 17 00:00:00 2001 From: Matt Woodrow Date: Tue, 1 Jul 2014 17:52:51 +1200 Subject: [PATCH] Bug 997304 - Copy the image data if it's not a suitable size for cairo. r=Bas --- gfx/2d/DrawTargetCairo.cpp | 82 +++++++++++++++++++------------------- gfx/2d/DrawTargetCairo.h | 1 + 2 files changed, 42 insertions(+), 41 deletions(-) diff --git a/gfx/2d/DrawTargetCairo.cpp b/gfx/2d/DrawTargetCairo.cpp index 57eb3de59ab8..d82c96219414 100644 --- a/gfx/2d/DrawTargetCairo.cpp +++ b/gfx/2d/DrawTargetCairo.cpp @@ -133,6 +133,36 @@ ReleaseData(void* aData) static_cast(aData)->Release(); } +cairo_surface_t* +CopyToImageSurface(unsigned char *aData, + const IntSize &aSize, + int32_t aStride, + SurfaceFormat aFormat) +{ + cairo_surface_t* surf = cairo_image_surface_create(GfxFormatToCairoFormat(aFormat), + aSize.width, + aSize.height); + // In certain scenarios, requesting larger than 8k image fails. Bug 803568 + // covers the details of how to run into it, but the full detailed + // investigation hasn't been done to determine the underlying cause. We + // will just handle the failure to allocate the surface to avoid a crash. + if (cairo_surface_status(surf)) { + return nullptr; + } + + unsigned char* surfData = cairo_image_surface_get_data(surf); + int surfStride = cairo_image_surface_get_stride(surf); + int32_t pixelWidth = BytesPerPixel(aFormat); + + for (int32_t y = 0; y < aSize.height; ++y) { + memcpy(surfData + y * surfStride, + aData + y * aStride, + aSize.width * pixelWidth); + } + cairo_surface_mark_dirty(surf); + return surf; +} + /** * Returns cairo surface for the given SourceSurface. * If possible, it will use the cairo_surface associated with aSurface, @@ -177,7 +207,16 @@ GetCairoSurfaceForSourceSurface(SourceSurface *aSurface, bool aExistingOnly = fa // investigation hasn't been done to determine the underlying cause. We // will just handle the failure to allocate the surface to avoid a crash. if (cairo_surface_status(surf)) { - cairo_surface_destroy(surf); + if (cairo_surface_status(surf) == CAIRO_STATUS_INVALID_STRIDE) { + // If we failed because of an invalid stride then copy into + // a new surface with a stride that cairo chooses. No need to + // set user data since we're not dependent on the original + // data. + return CopyToImageSurface(data->GetData(), + data->GetSize(), + data->Stride(), + data->GetFormat()); + } return nullptr; } @@ -1056,52 +1095,13 @@ DrawTargetCairo::CreateFilter(FilterType aType) return FilterNodeSoftware::Create(aType); } -/** - * Copies pixel data from aData into aSurface; aData must have the dimensions - * given in aSize, with a stride of aStride bytes and aPixelWidth bytes per pixel - */ -static void -CopyDataToCairoSurface(cairo_surface_t* aSurface, - unsigned char *aData, - const IntSize &aSize, - int32_t aStride, - int32_t aPixelWidth) -{ - unsigned char* surfData = cairo_image_surface_get_data(aSurface); - int surfStride = cairo_image_surface_get_stride(aSurface); - // In certain scenarios, requesting larger than 8k image fails. Bug 803568 - // covers the details of how to run into it, but the full detailed - // investigation hasn't been done to determine the underlying cause. We - // will just handle the failure to allocate the surface to avoid a crash. - if (!surfData) { - return; - } - for (int32_t y = 0; y < aSize.height; ++y) { - memcpy(surfData + y * surfStride, - aData + y * aStride, - aSize.width * aPixelWidth); - } - cairo_surface_mark_dirty(aSurface); -} - TemporaryRef DrawTargetCairo::CreateSourceSurfaceFromData(unsigned char *aData, const IntSize &aSize, int32_t aStride, SurfaceFormat aFormat) const { - cairo_surface_t* surf = cairo_image_surface_create(GfxFormatToCairoFormat(aFormat), - aSize.width, - aSize.height); - // In certain scenarios, requesting larger than 8k image fails. Bug 803568 - // covers the details of how to run into it, but the full detailed - // investigation hasn't been done to determine the underlying cause. We - // will just handle the failure to allocate the surface to avoid a crash. - if (cairo_surface_status(surf)) { - return nullptr; - } - - CopyDataToCairoSurface(surf, aData, aSize, aStride, BytesPerPixel(aFormat)); + cairo_surface_t* surf = CopyToImageSurface(aData, aSize, aStride, aFormat); RefPtr source_surf = new SourceSurfaceCairo(surf, aSize, aFormat); cairo_surface_destroy(surf); diff --git a/gfx/2d/DrawTargetCairo.h b/gfx/2d/DrawTargetCairo.h index 46ad2902ee4b..c4977841c736 100644 --- a/gfx/2d/DrawTargetCairo.h +++ b/gfx/2d/DrawTargetCairo.h @@ -198,6 +198,7 @@ private: // methods // If the current operator is "source" then clear the destination before we // draw into it, to simulate the effect of an unbounded source operator. void ClearSurfaceForUnboundedSource(const CompositionOp &aOperator); + private: // data cairo_t* mContext; cairo_surface_t* mSurface;