Fix matrix adjustment passed to filter processing.

When adjusting the CTM for filter use, we were subtracting off the
destination coordinates of the drawDevice() or drawSprite(). This is
not quite correct: we should subtract off the coordinates relative to
the device origin instead. This occurs when one filtered saveLayer() is
drawn inside another saveLayer(), both with non-zero origin.

This fixes layout test svg/batik/text/smallFonts.svg in Blink, and is
exercised by the provided unit test.

BUG=skia:
R=bsalomon@google.com

Review URL: https://codereview.chromium.org/222723002

git-svn-id: http://skia.googlecode.com/svn/trunk@14029 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/tests/ImageFilterTest.cpp b/tests/ImageFilterTest.cpp
index cfba1fa..4c8ddc6 100644
--- a/tests/ImageFilterTest.cpp
+++ b/tests/ImageFilterTest.cpp
@@ -19,6 +19,7 @@
 #include "SkFlattenableBuffers.h"
 #include "SkLightingImageFilter.h"
 #include "SkMatrixConvolutionImageFilter.h"
+#include "SkMatrixImageFilter.h"
 #include "SkMergeImageFilter.h"
 #include "SkMorphologyImageFilter.h"
 #include "SkOffsetImageFilter.h"
@@ -363,6 +364,57 @@
     REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
 }
 
+DEF_TEST(ImageFilterNestedSaveLayer, reporter) {
+    SkBitmap temp;
+    temp.allocN32Pixels(50, 50);
+    SkBitmapDevice device(temp);
+    SkCanvas canvas(&device);
+    canvas.clear(0x0);
+
+    SkBitmap bitmap;
+    bitmap.allocN32Pixels(10, 10);
+    bitmap.eraseColor(SK_ColorGREEN);
+
+    SkMatrix matrix;
+    matrix.setScale(SkIntToScalar(2), SkIntToScalar(2));
+    matrix.postTranslate(SkIntToScalar(-20), SkIntToScalar(-20));
+    SkAutoTUnref<SkImageFilter> matrixFilter(
+        SkMatrixImageFilter::Create(matrix, SkPaint::kLow_FilterLevel));
+
+    // Test that saveLayer() with a filter nested inside another saveLayer() applies the
+    // correct offset to the filter matrix.
+    SkRect bounds1 = SkRect::MakeXYWH(10, 10, 30, 30);
+    canvas.saveLayer(&bounds1, NULL);
+    SkPaint filterPaint;
+    filterPaint.setImageFilter(matrixFilter);
+    SkRect bounds2 = SkRect::MakeXYWH(20, 20, 10, 10);
+    canvas.saveLayer(&bounds2, &filterPaint);
+    SkPaint greenPaint;
+    greenPaint.setColor(SK_ColorGREEN);
+    canvas.drawRect(bounds2, greenPaint);
+    canvas.restore();
+    canvas.restore();
+    SkPaint strokePaint;
+    strokePaint.setStyle(SkPaint::kStroke_Style);
+    strokePaint.setColor(SK_ColorRED);
+
+    SkImageInfo info = SkImageInfo::MakeN32Premul(1, 1);
+    uint32_t pixel;
+    canvas.readPixels(info, &pixel, 4, 25, 25);
+    REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
+
+    // Test that drawSprite() with a filter nested inside a saveLayer() applies the
+    // correct offset to the filter matrix.
+    canvas.clear(0x0);
+    canvas.readPixels(info, &pixel, 4, 25, 25);
+    canvas.saveLayer(&bounds1, NULL);
+    canvas.drawSprite(bitmap, 20, 20, &filterPaint);
+    canvas.restore();
+
+    canvas.readPixels(info, &pixel, 4, 25, 25);
+    REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
+}
+
 DEF_TEST(XfermodeImageFilterCroppedInput, reporter) {
     SkBitmap temp;
     temp.allocN32Pixels(100, 100);