Bug 997304 - Copy the image data if it's not a suitable size for cairo. r=Bas

This commit is contained in:
Matt Woodrow 2014-07-01 17:52:51 +12:00
parent 59213f7de9
commit 8955c86721
2 changed files with 42 additions and 41 deletions

View File

@ -133,6 +133,36 @@ ReleaseData(void* aData)
static_cast<DataSourceSurface*>(aData)->Release(); static_cast<DataSourceSurface*>(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. * Returns cairo surface for the given SourceSurface.
* If possible, it will use the cairo_surface associated with aSurface, * 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 // investigation hasn't been done to determine the underlying cause. We
// will just handle the failure to allocate the surface to avoid a crash. // will just handle the failure to allocate the surface to avoid a crash.
if (cairo_surface_status(surf)) { 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; return nullptr;
} }
@ -1056,52 +1095,13 @@ DrawTargetCairo::CreateFilter(FilterType aType)
return FilterNodeSoftware::Create(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<SourceSurface> TemporaryRef<SourceSurface>
DrawTargetCairo::CreateSourceSurfaceFromData(unsigned char *aData, DrawTargetCairo::CreateSourceSurfaceFromData(unsigned char *aData,
const IntSize &aSize, const IntSize &aSize,
int32_t aStride, int32_t aStride,
SurfaceFormat aFormat) const SurfaceFormat aFormat) const
{ {
cairo_surface_t* surf = cairo_image_surface_create(GfxFormatToCairoFormat(aFormat), cairo_surface_t* surf = CopyToImageSurface(aData, aSize, aStride, 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));
RefPtr<SourceSurfaceCairo> source_surf = new SourceSurfaceCairo(surf, aSize, aFormat); RefPtr<SourceSurfaceCairo> source_surf = new SourceSurfaceCairo(surf, aSize, aFormat);
cairo_surface_destroy(surf); cairo_surface_destroy(surf);

View File

@ -198,6 +198,7 @@ private: // methods
// If the current operator is "source" then clear the destination before we // If the current operator is "source" then clear the destination before we
// draw into it, to simulate the effect of an unbounded source operator. // draw into it, to simulate the effect of an unbounded source operator.
void ClearSurfaceForUnboundedSource(const CompositionOp &aOperator); void ClearSurfaceForUnboundedSource(const CompositionOp &aOperator);
private: // data private: // data
cairo_t* mContext; cairo_t* mContext;
cairo_surface_t* mSurface; cairo_surface_t* mSurface;