Bug 378583 - Large pattern surfaces crash browser. r=tor,sr=roc

This commit is contained in:
longsonr@gmail.com 2007-06-13 02:02:48 -07:00
Родитель ab581cee9c
Коммит f02cb58e85
5 изменённых файлов: 122 добавлений и 49 удалений

Просмотреть файл

@ -51,13 +51,6 @@
#include "gfxContext.h"
#include "gfxImageSurface.h"
// maximum dimension of a filter - choose so that
// 4*(FILTER_RES_MAX^2) < UINT_MAX, it's small
// enough that it could be computed in a reasonable
// amount of time, and large enough for most content
// window sizes.
#define FILTER_RES_MAX 16384
nsIFrame*
NS_NewSVGFilterFrame(nsIPresShell* aPresShell, nsIContent* aContent, nsStyleContext* aContext)
{
@ -143,13 +136,6 @@ nsSVGFilterFrame::FilterPaint(nsSVGRenderState *aContext,
nsCOMPtr<nsIDOMSVGMatrix> ctm = nsSVGUtils::GetCanvasTM(frame);
float s1, s2;
ctm->GetA(&s1);
ctm->GetD(&s2);
#ifdef DEBUG_tor
fprintf(stderr, "scales: %f %f\n", s1, s2);
#endif
nsSVGElement *target = NS_STATIC_CAST(nsSVGElement*, frame->GetContent());
aTarget->SetMatrixPropagation(PR_FALSE);
@ -187,39 +173,51 @@ nsSVGFilterFrame::FilterPaint(nsSVGRenderState *aContext,
height = nsSVGUtils::UserSpace(target, tmpHeight);
}
PRInt32 filterResX = PRInt32(s1 * width + 0.5);
PRInt32 filterResY = PRInt32(s2 * height + 0.5);
PRBool resultOverflows;
gfxIntSize filterRes;
if (mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::filterRes)) {
PRInt32 filterResX, filterResY;
filter->mFilterResX->GetAnimVal(&filterResX);
filter->mFilterResY->GetAnimVal(&filterResY);
filterRes =
nsSVGUtils::ConvertToSurfaceSize(gfxSize(filterResX, filterResY),
&resultOverflows);
} else {
float s1, s2;
ctm->GetA(&s1);
ctm->GetD(&s2);
#ifdef DEBUG_tor
fprintf(stderr, "scales: %f %f\n", s1, s2);
#endif
filterRes =
nsSVGUtils::ConvertToSurfaceSize(gfxSize(s1 * width, s2 * height),
&resultOverflows);
}
// filterRes = 0 disables rendering, < 0 is error
if (filterResX <= 0.0f || filterResY <= 0.0f)
return NS_OK;
// prevent filters from overflowing or generally using excessive memory
filterResX = PR_MIN(FILTER_RES_MAX, filterResX);
filterResY = PR_MIN(FILTER_RES_MAX, filterResY);
// 0 disables rendering, < 0 is error
if (filterRes.width <= 0 || filterRes.height <= 0)
return NS_OK;
#ifdef DEBUG_tor
fprintf(stderr, "filter bbox: %f,%f %fx%f\n", x, y, width, height);
fprintf(stderr, "filterRes: %u %u\n", filterResX, filterResY);
fprintf(stderr, "filterRes: %u %u\n", filterRes.width, filterRes.height);
#endif
nsCOMPtr<nsIDOMSVGMatrix> filterTransform;
NS_NewSVGMatrix(getter_AddRefs(filterTransform),
filterResX/width, 0.0f,
0.0f, filterResY/height,
-x*filterResX/width, -y*filterResY/height);
filterRes.width / width, 0.0f,
0.0f, filterRes.height / height,
-x * filterRes.width / width, -y * filterRes.height / height);
aTarget->SetOverrideCTM(filterTransform);
aTarget->NotifyCanvasTMChanged(PR_TRUE);
// paint the target geometry
nsRefPtr<gfxImageSurface> tmpSurface =
new gfxImageSurface(gfxIntSize(filterResX, filterResY),
gfxASurface::ImageFormatARGB32);
new gfxImageSurface(filterRes, gfxASurface::ImageFormatARGB32);
if (!tmpSurface || !tmpSurface->Data()) {
FilterFailCleanup(aContext, aTarget);
return NS_OK;
@ -238,7 +236,7 @@ nsSVGFilterFrame::FilterPaint(nsSVGRenderState *aContext,
filter->mPrimitiveUnits->GetAnimVal(&primitiveUnits);
nsSVGFilterInstance instance(target, bbox,
x, y, width, height,
filterResX, filterResY,
filterRes.width, filterRes.height,
primitiveUnits);
nsSVGFilterInstance::ColorModel
colorModel(nsSVGFilterInstance::ColorModel::SRGB,
@ -246,8 +244,7 @@ nsSVGFilterFrame::FilterPaint(nsSVGRenderState *aContext,
if (requirements & NS_FE_SOURCEALPHA) {
nsRefPtr<gfxImageSurface> alpha =
new gfxImageSurface(gfxIntSize(filterResX, filterResY),
gfxASurface::ImageFormatARGB32);
new gfxImageSurface(filterRes, gfxASurface::ImageFormatARGB32);
if (!alpha || !alpha->Data()) {
FilterFailCleanup(aContext, aTarget);
@ -258,8 +255,8 @@ nsSVGFilterFrame::FilterPaint(nsSVGRenderState *aContext,
PRUint8 *alphaData = alpha->Data();
PRUint32 stride = tmpSurface->Stride();
for (PRUint32 yy = 0; yy < PRUint32(filterResY); yy++)
for (PRUint32 xx = 0; xx < PRUint32(filterResX); xx++) {
for (PRInt32 yy = 0; yy < filterRes.height; yy++)
for (PRInt32 xx = 0; xx < filterRes.width; xx++) {
alphaData[stride*yy + 4*xx + GFX_ARGB32_OFFSET_B] = 0;
alphaData[stride*yy + 4*xx + GFX_ARGB32_OFFSET_G] = 0;
alphaData[stride*yy + 4*xx + GFX_ARGB32_OFFSET_R] = 0;
@ -268,13 +265,15 @@ nsSVGFilterFrame::FilterPaint(nsSVGRenderState *aContext,
}
instance.DefineImage(NS_LITERAL_STRING("SourceAlpha"), alpha,
nsRect(0, 0, filterResX, filterResY), colorModel);
nsRect(0, 0, filterRes.width, filterRes.height),
colorModel);
}
// this always needs to be defined last because the default image
// for the first filter element is supposed to be SourceGraphic
instance.DefineImage(NS_LITERAL_STRING("SourceGraphic"), tmpSurface,
nsRect(0, 0, filterResX, filterResY), colorModel);
nsRect(0, 0, filterRes.width, filterRes.height),
colorModel);
for (PRUint32 k=0; k<count; ++k) {
nsIContent* child = mContent->GetChildAt(k);
@ -299,8 +298,8 @@ nsSVGFilterFrame::FilterPaint(nsSVGRenderState *aContext,
nsCOMPtr<nsIDOMSVGMatrix> scale, fini;
NS_NewSVGMatrix(getter_AddRefs(scale),
width/filterResX, 0.0f,
0.0f, height/filterResY,
width / filterRes.width, 0.0f,
0.0f, height / filterRes.height,
x, y);
ctm->Multiply(scale, getter_AddRefs(fini));

Просмотреть файл

@ -178,11 +178,22 @@ nsSVGMaskFrame::ComputeMaskAlpha(nsSVGRenderState *aContext,
clipExtents.Width(), clipExtents.Height());
#endif
gfxIntSize clipSize(PRInt32(clipExtents.Width() + 0.5),
PRInt32(clipExtents.Height() + 0.5));
PRBool resultOverflows;
gfxIntSize surfaceSize =
nsSVGUtils::ConvertToSurfaceSize(gfxSize(clipExtents.Width(),
clipExtents.Height()),
&resultOverflows);
// 0 disables mask, < 0 is an error
if (surfaceSize.width <= 0 || surfaceSize.height <= 0)
return nsnull;
if (resultOverflows)
return nsnull;
nsRefPtr<gfxImageSurface> image =
new gfxImageSurface(clipSize, gfxASurface::ImageFormatARGB32);
if (!image)
new gfxImageSurface(surfaceSize, gfxASurface::ImageFormatARGB32);
if (!image || !image->Data())
return nsnull;
gfxContext transferCtx(image);
@ -190,8 +201,8 @@ nsSVGMaskFrame::ComputeMaskAlpha(nsSVGRenderState *aContext,
transferCtx.SetSource(surface, -clipExtents.pos);
transferCtx.Paint();
PRUint32 width = clipSize.width;
PRUint32 height = clipSize.height;
PRUint32 width = surfaceSize.width;
PRUint32 height = surfaceSize.height;
PRUint8 *data = image->Data();
PRInt32 stride = image->Stride();

Просмотреть файл

@ -281,17 +281,40 @@ nsSVGPatternFrame::PaintPattern(gfxASurface** surface,
// Now that we have all of the necessary geometries, we can
// create our surface.
float surfaceWidth, surfaceHeight;
bbox->GetWidth(&surfaceWidth);
bbox->GetHeight(&surfaceHeight);
float patternWidth, patternHeight;
bbox->GetWidth(&patternWidth);
bbox->GetHeight(&patternHeight);
PRBool resultOverflows;
gfxIntSize surfaceSize =
nsSVGUtils::ConvertToSurfaceSize(gfxSize(patternWidth, patternHeight),
&resultOverflows);
// 0 disables rendering, < 0 is an error
if (surfaceSize.width <= 0 || surfaceSize.height <= 0)
return NS_ERROR_FAILURE;
if (resultOverflows) {
// scale down drawing to new pattern surface size
nsCOMPtr<nsIDOMSVGMatrix> tempTM, aCTM;
NS_NewSVGMatrix(getter_AddRefs(tempTM),
surfaceSize.width / patternWidth, 0.0f,
0.0f, surfaceSize.height / patternHeight,
0.0f, 0.0f);
mCTM->Multiply(tempTM, getter_AddRefs(aCTM));
aCTM.swap(mCTM);
// and magnify pattern to compensate
patternMatrix->Scale(patternWidth / surfaceSize.width,
patternHeight / surfaceSize.height);
}
#ifdef DEBUG_scooter
printf("Creating %dX%d surface\n",(int)(surfaceWidth),(int)(surfaceHeight));
printf("Creating %dX%d surface\n", int(surfaceSize.width), int(surfaceSize.height));
#endif
nsRefPtr<gfxASurface> tmpSurface =
gfxPlatform::GetPlatform()->CreateOffscreenSurface(gfxIntSize(PRInt32(surfaceWidth),
PRInt32(surfaceHeight)),
gfxPlatform::GetPlatform()->CreateOffscreenSurface(surfaceSize,
gfxASurface::ImageFormatARGB32);
if (!tmpSurface)
return NS_ERROR_FAILURE;

Просмотреть файл

@ -1283,6 +1283,28 @@ nsSVGUtils::ToBoundingPixelRect(const gfxRect& rect)
nscoord(ceil(rect.YMost()) - floor(rect.Y())));
}
gfxIntSize
nsSVGUtils::ConvertToSurfaceSize(const gfxSize& aSize, PRBool *aResultOverflows)
{
gfxIntSize surfaceSize =
gfxIntSize(PRInt32(aSize.width + 0.5), PRInt32(aSize.height + 0.5));
*aResultOverflows = (aSize.width >= PR_INT32_MAX + 0.5 ||
aSize.height >= PR_INT32_MAX + 0.5 ||
aSize.width <= PR_INT32_MIN - 0.5 ||
aSize.height <= PR_INT32_MIN - 0.5);
if (*aResultOverflows ||
!gfxASurface::CheckSurfaceSize(surfaceSize)) {
surfaceSize.width = PR_MIN(NS_SVG_OFFSCREEN_MAX_DIMENSION,
surfaceSize.width);
surfaceSize.height = PR_MIN(NS_SVG_OFFSCREEN_MAX_DIMENSION,
surfaceSize.height);
*aResultOverflows = PR_TRUE;
}
return surfaceSize;
}
gfxASurface *
nsSVGUtils::GetThebesComputationalSurface()
{

Просмотреть файл

@ -71,6 +71,8 @@ class gfxASurface;
class nsIRenderingContext;
struct gfxRect;
struct gfxMatrix;
struct gfxSize;
struct gfxIntSize;
#ifndef M_PI
#define M_PI 3.14159265358979323846
@ -109,6 +111,11 @@ struct gfxMatrix;
#define GFX_ARGB32_OFFSET_B 0
#endif
// maximum dimension of an offscreen surface - choose so that
// the surface size doesn't overflow a 32-bit signed int using
// 4 bytes per pixel; in line with gfxASurface::CheckSurfaceSize
#define NS_SVG_OFFSCREEN_MAX_DIMENSION 16384
/*
* Checks the svg enable preference and if a renderer could
* successfully be created. Declared as a function instead of a
@ -316,6 +323,17 @@ public:
static nsRect
ToBoundingPixelRect(const gfxRect& rect);
/*
* Convert a surface size to an integer for use by thebes
* possibly making it smaller in the process so the surface does not
* use excessive memory.
* @param aSize the desired surface size
* @param aResultOverflows true if the desired surface size is too big
* @return the surface size to use
*/
static gfxIntSize
ConvertToSurfaceSize(const gfxSize& aSize, PRBool *aResultOverflows);
/*
* Get a pointer to a surface that can be used to create thebes
* contexts for various measurement purposes.