Fix a problem with scaled filters in tiled SkPicture playback.
authorsenorblanco@chromium.org <senorblanco@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>
Wed, 5 Feb 2014 22:36:31 +0000 (22:36 +0000)
committersenorblanco@chromium.org <senorblanco@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>
Wed, 5 Feb 2014 22:36:31 +0000 (22:36 +0000)
The matrix used during filter application should be up-to-date, so that
the filter parameters can be scaled by the CTM (e.g., for hiDPI).
However, tiled playback defers setting of the matrix until after the
restore() call which draws the filter, which is too late. Moving the
setMatrix() ahead of the restore() sequence fixes the problem.

TEST=ImageFilterMatrixTest
R=junov@chromium.org

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

git-svn-id: http://skia.googlecode.com/svn/trunk@13331 2bbb7eff-a529-9590-31e7-b0007b416f81

src/core/SkPictureStateTree.cpp
tests/ImageFilterTest.cpp

index 26cc391..89942c7 100644 (file)
@@ -103,6 +103,7 @@ uint32_t SkPictureStateTree::Iterator::draw() {
     SkASSERT(this->isValid());
     if (fPlaybackIndex >= fDraws->count()) {
         // restore back to where we started
+        fCanvas->setMatrix(fPlaybackMatrix);
         if (fCurrentNode->fFlags & Node::kSaveLayer_Flag) { fCanvas->restore(); }
         fCurrentNode = fCurrentNode->fParent;
         while (NULL != fCurrentNode) {
@@ -110,7 +111,6 @@ uint32_t SkPictureStateTree::Iterator::draw() {
             if (fCurrentNode->fFlags & Node::kSaveLayer_Flag) { fCanvas->restore(); }
             fCurrentNode = fCurrentNode->fParent;
         }
-        fCanvas->setMatrix(fPlaybackMatrix);
         return kDrawComplete;
     }
 
index 22f63b7..a1d7a50 100644 (file)
 #include "SkDeviceImageFilterProxy.h"
 #include "SkDisplacementMapEffect.h"
 #include "SkDropShadowImageFilter.h"
+#include "SkFlattenableBuffers.h"
 #include "SkLightingImageFilter.h"
 #include "SkMatrixConvolutionImageFilter.h"
 #include "SkMergeImageFilter.h"
 #include "SkMorphologyImageFilter.h"
 #include "SkOffsetImageFilter.h"
+#include "SkPicture.h"
 #include "SkRect.h"
 #include "SkTileImageFilter.h"
 #include "SkXfermodeImageFilter.h"
 
 static const int kBitmapSize = 4;
 
+namespace {
+
+class MatrixTestImageFilter : public SkImageFilter {
+public:
+    MatrixTestImageFilter(skiatest::Reporter* reporter, const SkMatrix& expectedMatrix)
+      : SkImageFilter(0), fReporter(reporter), fExpectedMatrix(expectedMatrix) {
+    }
+
+    virtual bool onFilterImage(Proxy*, const SkBitmap& src, const SkMatrix& ctm,
+                               SkBitmap* result, SkIPoint* offset) SK_OVERRIDE {
+        REPORTER_ASSERT(fReporter, ctm == fExpectedMatrix);
+        return true;
+    }
+
+    SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(MatrixTestImageFilter)
+
+protected:
+    explicit MatrixTestImageFilter(SkReadBuffer& buffer) : SkImageFilter(0) {
+        fReporter = static_cast<skiatest::Reporter*>(buffer.readFunctionPtr());
+        buffer.readMatrix(&fExpectedMatrix);
+    }
+
+    virtual void flatten(SkWriteBuffer& buffer) const SK_OVERRIDE {
+        buffer.writeFunctionPtr(fReporter);
+        buffer.writeMatrix(fExpectedMatrix);
+    }
+
+private:
+    skiatest::Reporter* fReporter;
+    SkMatrix fExpectedMatrix;
+};
+
+}
+
 static void make_small_bitmap(SkBitmap& bitmap) {
     bitmap.setConfig(SkBitmap::kARGB_8888_Config, kBitmapSize, kBitmapSize);
     bitmap.allocPixels();
@@ -230,6 +266,39 @@ DEF_TEST(ImageFilterCropRect, reporter) {
     test_crop_rects(&device, reporter);
 }
 
+DEF_TEST(ImageFilterMatrixTest, reporter) {
+    SkBitmap temp;
+    temp.setConfig(SkBitmap::kARGB_8888_Config, 100, 100);
+    temp.allocPixels();
+    SkBitmapDevice device(temp);
+    SkCanvas canvas(&device);
+    canvas.scale(SkIntToScalar(2), SkIntToScalar(2));
+
+    SkMatrix expectedMatrix = canvas.getTotalMatrix();
+
+    SkPicture picture;
+    SkCanvas* recordingCanvas = picture.beginRecording(100, 100,
+        SkPicture::kOptimizeForClippedPlayback_RecordingFlag);
+
+    SkPaint paint;
+    SkAutoTUnref<MatrixTestImageFilter> imageFilter(
+        new MatrixTestImageFilter(reporter, expectedMatrix));
+    paint.setImageFilter(imageFilter.get());
+    SkCanvas::SaveFlags saveFlags = static_cast<SkCanvas::SaveFlags>(
+        SkCanvas::kHasAlphaLayer_SaveFlag | SkCanvas::kFullColorLayer_SaveFlag);
+    recordingCanvas->saveLayer(NULL, &paint, saveFlags);
+    SkPaint solidPaint;
+    solidPaint.setColor(0xFFFFFFFF);
+    recordingCanvas->save();
+    recordingCanvas->scale(SkIntToScalar(10), SkIntToScalar(10));
+    recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(100, 100)), solidPaint);
+    recordingCanvas->restore(); // scale
+    recordingCanvas->restore(); // saveLayer
+    picture.endRecording();
+
+    canvas.drawPicture(picture);
+}
+
 #if SK_SUPPORT_GPU
 DEF_GPUTEST(ImageFilterCropRectGPU, reporter, factory) {
     GrContext* context = factory->get(static_cast<GrContextFactory::GLContextType>(0));