aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar reed@android.com <reed@android.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2009-03-16 18:46:55 +0000
committerGravatar reed@android.com <reed@android.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2009-03-16 18:46:55 +0000
commit3555591c158c242b071c7ec92ad75b6e4cb74af2 (patch)
tree67c53a7a4e2f428fce28c596f8e802fb96e2df70
parentdfb6fb5669b3625ad32c0563b44fb805d1369f68 (diff)
add sanity checks to handles extremely large coordinates or filter margins.
Should not hurt features (we hope), but is an easy way to survive malicious values on a small-memory machine like a handset. git-svn-id: http://skia.googlecode.com/svn/trunk@123 2bbb7eff-a529-9590-31e7-b0007b416f81
-rw-r--r--samplecode/SampleFontScalerTest.cpp16
-rw-r--r--src/core/SkDraw.cpp10
-rw-r--r--src/core/SkScan_AntiPath.cpp23
-rw-r--r--src/core/SkScan_Antihair.cpp10
-rw-r--r--src/effects/SkBlurMaskFilter.cpp10
5 files changed, 55 insertions, 14 deletions
diff --git a/samplecode/SampleFontScalerTest.cpp b/samplecode/SampleFontScalerTest.cpp
index 81dd60df3f..256d2f4eac 100644
--- a/samplecode/SampleFontScalerTest.cpp
+++ b/samplecode/SampleFontScalerTest.cpp
@@ -71,10 +71,24 @@ protected:
virtual void onDraw(SkCanvas* canvas) {
this->drawBG(canvas);
+ SkPaint paint;
+
+ {
+ SkPoint pts[4];
+ pts[0].set(1.61061274e+09, 6291456);
+ pts[1].set(-7.18397061e+15, -1.53091184e+13);
+ pts[2].set(-1.30077315e+16, -2.77196141e+13);
+ pts[3].set(-1.30077315e+16, -2.77196162e+13);
+
+ SkPath path;
+ path.moveTo(pts[0]);
+ path.cubicTo(pts[1], pts[2], pts[3]);
+ canvas->drawPath(path, paint);
+ }
+
canvas->translate(200, 20);
canvas->rotate(30);
- SkPaint paint;
paint.setAntiAlias(true);
paint.setTypeface(SkTypeface::CreateFromName("Times Roman", SkTypeface::kNormal))->safeUnref();
diff --git a/src/core/SkDraw.cpp b/src/core/SkDraw.cpp
index 1d3263f73e..bc981f95b4 100644
--- a/src/core/SkDraw.cpp
+++ b/src/core/SkDraw.cpp
@@ -2305,7 +2305,15 @@ static bool compute_bounds(const SkPath& devPath, const SkIRect* clipBounds,
if (clipBounds && !clipBounds->contains(*bounds)) {
SkIRect tmp = *bounds;
(void)tmp.intersect(*clipBounds);
- tmp.inset(-margin.fX, -margin.fY);
+ // Ugh. Guard against gigantic margins from wacky filters. Without this
+ // check we can request arbitrary amounts of slop beyond our visible
+ // clip, and bring down the renderer (at least on finite RAM machines
+ // like handsets, etc.). Need to balance this invented value between
+ // quality of large filters like blurs, and the corresponding memory
+ // requests.
+ static const int MAX_MARGIN = 128;
+ tmp.inset(-SkMin32(margin.fX, MAX_MARGIN),
+ -SkMin32(margin.fY, MAX_MARGIN));
(void)bounds->intersect(tmp);
}
diff --git a/src/core/SkScan_AntiPath.cpp b/src/core/SkScan_AntiPath.cpp
index 9cdeeaa56e..422d060255 100644
--- a/src/core/SkScan_AntiPath.cpp
+++ b/src/core/SkScan_AntiPath.cpp
@@ -335,8 +335,13 @@ void MaskSuperBlitter::blitH(int x, int y, int width)
///////////////////////////////////////////////////////////////////////////////
-static int overflows_short(int value) {
- return value - (short)value;
+/* Returns non-zero if (value << shift) overflows a short, which would mean
+ we could not shift it up and then convert to SkFixed.
+ i.e. is x expressible as signed (16-shift) bits?
+ */
+static int overflows_short_shift(int value, int shift) {
+ const int s = 16 + shift;
+ return (value << s >> s) - value;
}
void SkScan::AntiFillPath(const SkPath& path, const SkRegion& clip,
@@ -354,13 +359,13 @@ void SkScan::AntiFillPath(const SkPath& path, const SkRegion& clip,
return;
}
- if (overflows_short(ir.fLeft << SHIFT) ||
- overflows_short(ir.fRight << SHIFT) ||
- overflows_short(ir.width() << SHIFT) ||
- overflows_short(ir.fTop << SHIFT) ||
- overflows_short(ir.fBottom << SHIFT) ||
- overflows_short(ir.height() << SHIFT)) {
- // can't supersample, try drawing w/o antialiasing
+ // use bit-or since we expect all to pass, so no need to go slower with
+ // a short-circuiting logical-or
+ if (overflows_short_shift(ir.fLeft, SHIFT) |
+ overflows_short_shift(ir.fRight, SHIFT) |
+ overflows_short_shift(ir.fTop, SHIFT) |
+ overflows_short_shift(ir.fBottom, SHIFT)) {
+ // can't supersample, so draw w/o antialiasing
SkScan::FillPath(path, clip, blitter);
return;
}
diff --git a/src/core/SkScan_Antihair.cpp b/src/core/SkScan_Antihair.cpp
index 04e4690e63..3344698f86 100644
--- a/src/core/SkScan_Antihair.cpp
+++ b/src/core/SkScan_Antihair.cpp
@@ -212,8 +212,14 @@ static void do_anti_hairline(SkFDot6 x0, SkFDot6 y0, SkFDot6 x1, SkFDot6 y1,
if (SkAbs32(x1 - x0) > SkIntToFDot6(511) || SkAbs32(y1 - y0) > SkIntToFDot6(511))
{
- int hx = (x0 + x1) >> 1;
- int hy = (y0 + y1) >> 1;
+ /* instead of (x0 + x1) >> 1, we shift each separately. This is less
+ precise, but avoids overflowing the intermediate result if the
+ values are huge. A better fix might be to clip the original pts
+ directly (i.e. do the divide), so we don't spend time subdividing
+ huge lines at all.
+ */
+ int hx = (x0 >> 1) + (x1 >> 1);
+ int hy = (y0 >> 1) + (y1 >> 1);
do_anti_hairline(x0, y0, hx, hy, clip, blitter);
do_anti_hairline(hx, hy, x1, y1, clip, blitter);
return;
diff --git a/src/effects/SkBlurMaskFilter.cpp b/src/effects/SkBlurMaskFilter.cpp
index 2db60a58ef..b74cd99bcf 100644
--- a/src/effects/SkBlurMaskFilter.cpp
+++ b/src/effects/SkBlurMaskFilter.cpp
@@ -81,11 +81,19 @@ SkMask::Format SkBlurMaskFilterImpl::getFormat()
bool SkBlurMaskFilterImpl::filterMask(SkMask* dst, const SkMask& src, const SkMatrix& matrix, SkIPoint* margin)
{
SkScalar radius = matrix.mapRadius(fRadius);
+ // To avoid unseemly allocation requests (esp. for finite platforms like
+ // handset) we limit the radius so something manageable. (as opposed to
+ // a request like 10,000)
+ static const SkScalar MAX_RADIUS = SkIntToScalar(128);
+ radius = SkMinScalar(radius, MAX_RADIUS);
if (SkBlurMask::Blur(dst, src, radius, (SkBlurMask::Style)fBlurStyle))
{
- if (margin)
+ if (margin) {
+ // we need to integralize radius for our margin, so take the ceil
+ // just to be safe.
margin->set(SkScalarCeil(radius), SkScalarCeil(radius));
+ }
return true;
}
return false;