--- a/layout/svg/base/src/nsSVGFilterFrame.cpp
+++ b/layout/svg/base/src/nsSVGFilterFrame.cpp
@@ -46,16 +46,23 @@
#include "nsSVGUtils.h"
#include "nsSVGFilterElement.h"
#include "nsSVGFilterInstance.h"
#include "nsSVGFilters.h"
#include "gfxASurface.h"
#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)
{
return new (aPresShell) nsSVGFilterFrame(aContext);
}
nsIContent *
NS_GetSVGFilterElement(nsIURI *aURI, nsIContent *aContent)
@@ -192,33 +199,37 @@ nsSVGFilterFrame::FilterPaint(nsSVGRende
filter->GetFilterResY(getter_AddRefs(filterRes));
filterRes->GetAnimVal(&filterResY);
}
// 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);
+
#ifdef DEBUG_tor
fprintf(stderr, "filter bbox: %f,%f %fx%f\n", x, y, width, height);
fprintf(stderr, "filterRes: %u %u\n", filterResX, filterResY);
#endif
nsCOMPtr<nsIDOMSVGMatrix> filterTransform;
NS_NewSVGMatrix(getter_AddRefs(filterTransform),
filterResX/width, 0.0f,
0.0f, filterResY/height,
-x*filterResX/width, -y*filterResY/height);
aTarget->SetOverrideCTM(filterTransform);
aTarget->NotifyCanvasTMChanged(PR_TRUE);
// paint the target geometry
nsRefPtr<gfxImageSurface> tmpSurface =
new gfxImageSurface(gfxIntSize(filterResX, filterResY), gfxASurface::ImageFormatARGB32);
- if (!tmpSurface) {
+ if (!tmpSurface || !tmpSurface->Data()) {
FilterFailCleanup(aContext, aTarget);
return NS_OK;
}
gfxContext tmpContext(tmpSurface);
nsSVGRenderState tmpState(&tmpContext);
memset(tmpSurface->Data(), 0, tmpSurface->GetSize().height * tmpSurface->Stride());
@@ -234,27 +245,29 @@ nsSVGFilterFrame::FilterPaint(nsSVGRende
colorModel(nsSVGFilterInstance::ColorModel::SRGB,
nsSVGFilterInstance::ColorModel::PREMULTIPLIED);
if (requirements & NS_FE_SOURCEALPHA) {
cairo_surface_t *alpha =
cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
filterResX, filterResY);
- if (!alpha) {
+ if (!alpha || cairo_surface_status(alpha)) {
+ if (alpha)
+ cairo_surface_destroy(alpha);
FilterFailCleanup(aContext, aTarget);
return NS_OK;
}
PRUint8 *data = tmpSurface->Data();
PRUint8 *alphaData = cairo_image_surface_get_data(alpha);
PRUint32 stride = tmpSurface->Stride();
- for (PRUint32 yy=0; yy<filterResY; yy++)
- for (PRUint32 xx=0; xx<filterResX; xx++) {
+ for (PRUint32 yy = 0; yy < PRUint32(filterResY); yy++)
+ for (PRUint32 xx = 0; xx < PRUint32(filterResX); 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;
alphaData[stride*yy + 4*xx + GFX_ARGB32_OFFSET_A] =
data[stride*yy + 4*xx + 3];
}
instance.DefineImage(NS_LITERAL_STRING("SourceAlpha"), alpha,
@@ -495,18 +508,25 @@ nsSVGFilterInstance::GetFilterSubregion(
fprintf(stderr, "GFS[3]: %d %d %d %d\n",
result->x, result->y, result->width, result->height);
#endif
}
cairo_surface_t *
nsSVGFilterInstance::GetImage()
{
- return cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
- mFilterResX, mFilterResY);
+ cairo_surface_t *surface =
+ cairo_image_surface_create(CAIRO_FORMAT_ARGB32, mFilterResX, mFilterResY);
+
+ if (surface && cairo_surface_status(surface)) {
+ cairo_surface_destroy(surface);
+ surface = nsnull;
+ }
+
+ return surface;
}
void
nsSVGFilterInstance::LookupImage(const nsAString &aName,
cairo_surface_t **aImage,
nsRect *aRegion,
const ColorModel &aRequiredColorModel)
{