зеркало из https://github.com/mozilla/gecko-dev.git
Bug 378583 - Large pattern surfaces crash browser. r=tor,sr=roc
This commit is contained in:
Родитель
ab581cee9c
Коммит
f02cb58e85
|
@ -51,13 +51,6 @@
|
||||||
#include "gfxContext.h"
|
#include "gfxContext.h"
|
||||||
#include "gfxImageSurface.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*
|
nsIFrame*
|
||||||
NS_NewSVGFilterFrame(nsIPresShell* aPresShell, nsIContent* aContent, nsStyleContext* aContext)
|
NS_NewSVGFilterFrame(nsIPresShell* aPresShell, nsIContent* aContent, nsStyleContext* aContext)
|
||||||
{
|
{
|
||||||
|
@ -143,13 +136,6 @@ nsSVGFilterFrame::FilterPaint(nsSVGRenderState *aContext,
|
||||||
|
|
||||||
nsCOMPtr<nsIDOMSVGMatrix> ctm = nsSVGUtils::GetCanvasTM(frame);
|
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());
|
nsSVGElement *target = NS_STATIC_CAST(nsSVGElement*, frame->GetContent());
|
||||||
|
|
||||||
aTarget->SetMatrixPropagation(PR_FALSE);
|
aTarget->SetMatrixPropagation(PR_FALSE);
|
||||||
|
@ -187,39 +173,51 @@ nsSVGFilterFrame::FilterPaint(nsSVGRenderState *aContext,
|
||||||
height = nsSVGUtils::UserSpace(target, tmpHeight);
|
height = nsSVGUtils::UserSpace(target, tmpHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
PRInt32 filterResX = PRInt32(s1 * width + 0.5);
|
PRBool resultOverflows;
|
||||||
PRInt32 filterResY = PRInt32(s2 * height + 0.5);
|
gfxIntSize filterRes;
|
||||||
|
|
||||||
if (mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::filterRes)) {
|
if (mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::filterRes)) {
|
||||||
|
PRInt32 filterResX, filterResY;
|
||||||
filter->mFilterResX->GetAnimVal(&filterResX);
|
filter->mFilterResX->GetAnimVal(&filterResX);
|
||||||
filter->mFilterResY->GetAnimVal(&filterResY);
|
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
|
// 0 disables rendering, < 0 is error
|
||||||
filterResX = PR_MIN(FILTER_RES_MAX, filterResX);
|
if (filterRes.width <= 0 || filterRes.height <= 0)
|
||||||
filterResY = PR_MIN(FILTER_RES_MAX, filterResY);
|
return NS_OK;
|
||||||
|
|
||||||
#ifdef DEBUG_tor
|
#ifdef DEBUG_tor
|
||||||
fprintf(stderr, "filter bbox: %f,%f %fx%f\n", x, y, width, height);
|
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
|
#endif
|
||||||
|
|
||||||
nsCOMPtr<nsIDOMSVGMatrix> filterTransform;
|
nsCOMPtr<nsIDOMSVGMatrix> filterTransform;
|
||||||
NS_NewSVGMatrix(getter_AddRefs(filterTransform),
|
NS_NewSVGMatrix(getter_AddRefs(filterTransform),
|
||||||
filterResX/width, 0.0f,
|
filterRes.width / width, 0.0f,
|
||||||
0.0f, filterResY/height,
|
0.0f, filterRes.height / height,
|
||||||
-x*filterResX/width, -y*filterResY/height);
|
-x * filterRes.width / width, -y * filterRes.height / height);
|
||||||
aTarget->SetOverrideCTM(filterTransform);
|
aTarget->SetOverrideCTM(filterTransform);
|
||||||
aTarget->NotifyCanvasTMChanged(PR_TRUE);
|
aTarget->NotifyCanvasTMChanged(PR_TRUE);
|
||||||
|
|
||||||
// paint the target geometry
|
// paint the target geometry
|
||||||
nsRefPtr<gfxImageSurface> tmpSurface =
|
nsRefPtr<gfxImageSurface> tmpSurface =
|
||||||
new gfxImageSurface(gfxIntSize(filterResX, filterResY),
|
new gfxImageSurface(filterRes, gfxASurface::ImageFormatARGB32);
|
||||||
gfxASurface::ImageFormatARGB32);
|
|
||||||
if (!tmpSurface || !tmpSurface->Data()) {
|
if (!tmpSurface || !tmpSurface->Data()) {
|
||||||
FilterFailCleanup(aContext, aTarget);
|
FilterFailCleanup(aContext, aTarget);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
@ -238,7 +236,7 @@ nsSVGFilterFrame::FilterPaint(nsSVGRenderState *aContext,
|
||||||
filter->mPrimitiveUnits->GetAnimVal(&primitiveUnits);
|
filter->mPrimitiveUnits->GetAnimVal(&primitiveUnits);
|
||||||
nsSVGFilterInstance instance(target, bbox,
|
nsSVGFilterInstance instance(target, bbox,
|
||||||
x, y, width, height,
|
x, y, width, height,
|
||||||
filterResX, filterResY,
|
filterRes.width, filterRes.height,
|
||||||
primitiveUnits);
|
primitiveUnits);
|
||||||
nsSVGFilterInstance::ColorModel
|
nsSVGFilterInstance::ColorModel
|
||||||
colorModel(nsSVGFilterInstance::ColorModel::SRGB,
|
colorModel(nsSVGFilterInstance::ColorModel::SRGB,
|
||||||
|
@ -246,8 +244,7 @@ nsSVGFilterFrame::FilterPaint(nsSVGRenderState *aContext,
|
||||||
|
|
||||||
if (requirements & NS_FE_SOURCEALPHA) {
|
if (requirements & NS_FE_SOURCEALPHA) {
|
||||||
nsRefPtr<gfxImageSurface> alpha =
|
nsRefPtr<gfxImageSurface> alpha =
|
||||||
new gfxImageSurface(gfxIntSize(filterResX, filterResY),
|
new gfxImageSurface(filterRes, gfxASurface::ImageFormatARGB32);
|
||||||
gfxASurface::ImageFormatARGB32);
|
|
||||||
|
|
||||||
if (!alpha || !alpha->Data()) {
|
if (!alpha || !alpha->Data()) {
|
||||||
FilterFailCleanup(aContext, aTarget);
|
FilterFailCleanup(aContext, aTarget);
|
||||||
|
@ -258,8 +255,8 @@ nsSVGFilterFrame::FilterPaint(nsSVGRenderState *aContext,
|
||||||
PRUint8 *alphaData = alpha->Data();
|
PRUint8 *alphaData = alpha->Data();
|
||||||
PRUint32 stride = tmpSurface->Stride();
|
PRUint32 stride = tmpSurface->Stride();
|
||||||
|
|
||||||
for (PRUint32 yy = 0; yy < PRUint32(filterResY); yy++)
|
for (PRInt32 yy = 0; yy < filterRes.height; yy++)
|
||||||
for (PRUint32 xx = 0; xx < PRUint32(filterResX); xx++) {
|
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_B] = 0;
|
||||||
alphaData[stride*yy + 4*xx + GFX_ARGB32_OFFSET_G] = 0;
|
alphaData[stride*yy + 4*xx + GFX_ARGB32_OFFSET_G] = 0;
|
||||||
alphaData[stride*yy + 4*xx + GFX_ARGB32_OFFSET_R] = 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,
|
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
|
// this always needs to be defined last because the default image
|
||||||
// for the first filter element is supposed to be SourceGraphic
|
// for the first filter element is supposed to be SourceGraphic
|
||||||
instance.DefineImage(NS_LITERAL_STRING("SourceGraphic"), tmpSurface,
|
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) {
|
for (PRUint32 k=0; k<count; ++k) {
|
||||||
nsIContent* child = mContent->GetChildAt(k);
|
nsIContent* child = mContent->GetChildAt(k);
|
||||||
|
@ -299,8 +298,8 @@ nsSVGFilterFrame::FilterPaint(nsSVGRenderState *aContext,
|
||||||
|
|
||||||
nsCOMPtr<nsIDOMSVGMatrix> scale, fini;
|
nsCOMPtr<nsIDOMSVGMatrix> scale, fini;
|
||||||
NS_NewSVGMatrix(getter_AddRefs(scale),
|
NS_NewSVGMatrix(getter_AddRefs(scale),
|
||||||
width/filterResX, 0.0f,
|
width / filterRes.width, 0.0f,
|
||||||
0.0f, height/filterResY,
|
0.0f, height / filterRes.height,
|
||||||
x, y);
|
x, y);
|
||||||
|
|
||||||
ctm->Multiply(scale, getter_AddRefs(fini));
|
ctm->Multiply(scale, getter_AddRefs(fini));
|
||||||
|
|
|
@ -178,11 +178,22 @@ nsSVGMaskFrame::ComputeMaskAlpha(nsSVGRenderState *aContext,
|
||||||
clipExtents.Width(), clipExtents.Height());
|
clipExtents.Width(), clipExtents.Height());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
gfxIntSize clipSize(PRInt32(clipExtents.Width() + 0.5),
|
PRBool resultOverflows;
|
||||||
PRInt32(clipExtents.Height() + 0.5));
|
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 =
|
nsRefPtr<gfxImageSurface> image =
|
||||||
new gfxImageSurface(clipSize, gfxASurface::ImageFormatARGB32);
|
new gfxImageSurface(surfaceSize, gfxASurface::ImageFormatARGB32);
|
||||||
if (!image)
|
if (!image || !image->Data())
|
||||||
return nsnull;
|
return nsnull;
|
||||||
|
|
||||||
gfxContext transferCtx(image);
|
gfxContext transferCtx(image);
|
||||||
|
@ -190,8 +201,8 @@ nsSVGMaskFrame::ComputeMaskAlpha(nsSVGRenderState *aContext,
|
||||||
transferCtx.SetSource(surface, -clipExtents.pos);
|
transferCtx.SetSource(surface, -clipExtents.pos);
|
||||||
transferCtx.Paint();
|
transferCtx.Paint();
|
||||||
|
|
||||||
PRUint32 width = clipSize.width;
|
PRUint32 width = surfaceSize.width;
|
||||||
PRUint32 height = clipSize.height;
|
PRUint32 height = surfaceSize.height;
|
||||||
PRUint8 *data = image->Data();
|
PRUint8 *data = image->Data();
|
||||||
PRInt32 stride = image->Stride();
|
PRInt32 stride = image->Stride();
|
||||||
|
|
||||||
|
|
|
@ -281,17 +281,40 @@ nsSVGPatternFrame::PaintPattern(gfxASurface** surface,
|
||||||
|
|
||||||
// Now that we have all of the necessary geometries, we can
|
// Now that we have all of the necessary geometries, we can
|
||||||
// create our surface.
|
// create our surface.
|
||||||
float surfaceWidth, surfaceHeight;
|
float patternWidth, patternHeight;
|
||||||
bbox->GetWidth(&surfaceWidth);
|
bbox->GetWidth(&patternWidth);
|
||||||
bbox->GetHeight(&surfaceHeight);
|
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
|
#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
|
#endif
|
||||||
|
|
||||||
nsRefPtr<gfxASurface> tmpSurface =
|
nsRefPtr<gfxASurface> tmpSurface =
|
||||||
gfxPlatform::GetPlatform()->CreateOffscreenSurface(gfxIntSize(PRInt32(surfaceWidth),
|
gfxPlatform::GetPlatform()->CreateOffscreenSurface(surfaceSize,
|
||||||
PRInt32(surfaceHeight)),
|
|
||||||
gfxASurface::ImageFormatARGB32);
|
gfxASurface::ImageFormatARGB32);
|
||||||
if (!tmpSurface)
|
if (!tmpSurface)
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
|
|
|
@ -1283,6 +1283,28 @@ nsSVGUtils::ToBoundingPixelRect(const gfxRect& rect)
|
||||||
nscoord(ceil(rect.YMost()) - floor(rect.Y())));
|
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 *
|
gfxASurface *
|
||||||
nsSVGUtils::GetThebesComputationalSurface()
|
nsSVGUtils::GetThebesComputationalSurface()
|
||||||
{
|
{
|
||||||
|
|
|
@ -71,6 +71,8 @@ class gfxASurface;
|
||||||
class nsIRenderingContext;
|
class nsIRenderingContext;
|
||||||
struct gfxRect;
|
struct gfxRect;
|
||||||
struct gfxMatrix;
|
struct gfxMatrix;
|
||||||
|
struct gfxSize;
|
||||||
|
struct gfxIntSize;
|
||||||
|
|
||||||
#ifndef M_PI
|
#ifndef M_PI
|
||||||
#define M_PI 3.14159265358979323846
|
#define M_PI 3.14159265358979323846
|
||||||
|
@ -109,6 +111,11 @@ struct gfxMatrix;
|
||||||
#define GFX_ARGB32_OFFSET_B 0
|
#define GFX_ARGB32_OFFSET_B 0
|
||||||
#endif
|
#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
|
* Checks the svg enable preference and if a renderer could
|
||||||
* successfully be created. Declared as a function instead of a
|
* successfully be created. Declared as a function instead of a
|
||||||
|
@ -316,6 +323,17 @@ public:
|
||||||
static nsRect
|
static nsRect
|
||||||
ToBoundingPixelRect(const gfxRect& rect);
|
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
|
* Get a pointer to a surface that can be used to create thebes
|
||||||
* contexts for various measurement purposes.
|
* contexts for various measurement purposes.
|
||||||
|
|
Загрузка…
Ссылка в новой задаче