1 /*
2  * Copyright 2013 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "SkBitmap.h"
9 #include "SkBitmapDevice.h"
10 #include "SkCanvas.h"
11 #include "SkDraw.h"
12 #include "SkLayerDrawLooper.h"
13 #include "SkMatrix.h"
14 #include "SkPaint.h"
15 #include "SkRect.h"
16 #include "SkRefCnt.h"
17 #include "SkScalar.h"
18 #include "SkSmallAllocator.h"
19 #include "SkXfermode.h"
20 #include "Test.h"
21 
make_bm(int w,int h)22 static SkBitmap make_bm(int w, int h) {
23     SkBitmap bm;
24     bm.allocN32Pixels(w, h);
25     return bm;
26 }
27 
28 class FakeDevice : public SkBitmapDevice {
29 public:
FakeDevice()30     FakeDevice() : SkBitmapDevice(make_bm(100, 100)) { }
31 
drawRect(const SkDraw & draw,const SkRect & r,const SkPaint & paint)32     virtual void drawRect(const SkDraw& draw, const SkRect& r,
33                           const SkPaint& paint) override {
34         fLastMatrix = *draw.fMatrix;
35         this->INHERITED::drawRect(draw, r, paint);
36     }
37 
38     SkMatrix fLastMatrix;
39 
40 private:
41     typedef SkBitmapDevice INHERITED;
42 };
43 
test_frontToBack(skiatest::Reporter * reporter)44 static void test_frontToBack(skiatest::Reporter* reporter) {
45     SkLayerDrawLooper::Builder looperBuilder;
46     SkLayerDrawLooper::LayerInfo layerInfo;
47 
48     // Add the front layer, with the defaults.
49     (void)looperBuilder.addLayer(layerInfo);
50 
51     // Add the back layer, with some layer info set.
52     layerInfo.fOffset.set(10.0f, 20.0f);
53     layerInfo.fPaintBits |= SkLayerDrawLooper::kXfermode_Bit;
54     SkPaint* layerPaint = looperBuilder.addLayer(layerInfo);
55     layerPaint->setXfermodeMode(SkXfermode::kSrc_Mode);
56 
57     FakeDevice device;
58     SkCanvas canvas(&device);
59     SkPaint paint;
60     SkAutoTUnref<SkLayerDrawLooper> looper(looperBuilder.detachLooper());
61     SkSmallAllocator<1, 32> allocator;
62     void* buffer = allocator.reserveT<SkDrawLooper::Context>(looper->contextSize());
63     SkDrawLooper::Context* context = looper->createContext(&canvas, buffer);
64 
65     // The back layer should come first.
66     REPORTER_ASSERT(reporter, context->next(&canvas, &paint));
67     REPORTER_ASSERT(reporter, SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrc_Mode));
68     canvas.drawRect(SkRect::MakeWH(50.0f, 50.0f), paint);
69     REPORTER_ASSERT(reporter, 10.0f == device.fLastMatrix.getTranslateX());
70     REPORTER_ASSERT(reporter, 20.0f == device.fLastMatrix.getTranslateY());
71     paint.reset();
72 
73     // Then the front layer.
74     REPORTER_ASSERT(reporter, context->next(&canvas, &paint));
75     REPORTER_ASSERT(reporter, SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrcOver_Mode));
76     canvas.drawRect(SkRect::MakeWH(50.0f, 50.0f), paint);
77     REPORTER_ASSERT(reporter, 0.0f == device.fLastMatrix.getTranslateX());
78     REPORTER_ASSERT(reporter, 0.0f == device.fLastMatrix.getTranslateY());
79 
80     // Only two layers were added, so that should be the end.
81     REPORTER_ASSERT(reporter, !context->next(&canvas, &paint));
82 }
83 
test_backToFront(skiatest::Reporter * reporter)84 static void test_backToFront(skiatest::Reporter* reporter) {
85     SkLayerDrawLooper::Builder looperBuilder;
86     SkLayerDrawLooper::LayerInfo layerInfo;
87 
88     // Add the back layer, with the defaults.
89     (void)looperBuilder.addLayerOnTop(layerInfo);
90 
91     // Add the front layer, with some layer info set.
92     layerInfo.fOffset.set(10.0f, 20.0f);
93     layerInfo.fPaintBits |= SkLayerDrawLooper::kXfermode_Bit;
94     SkPaint* layerPaint = looperBuilder.addLayerOnTop(layerInfo);
95     layerPaint->setXfermodeMode(SkXfermode::kSrc_Mode);
96 
97     FakeDevice device;
98     SkCanvas canvas(&device);
99     SkPaint paint;
100     SkAutoTUnref<SkLayerDrawLooper> looper(looperBuilder.detachLooper());
101     SkSmallAllocator<1, 32> allocator;
102     void* buffer = allocator.reserveT<SkDrawLooper::Context>(looper->contextSize());
103     SkDrawLooper::Context* context = looper->createContext(&canvas, buffer);
104 
105     // The back layer should come first.
106     REPORTER_ASSERT(reporter, context->next(&canvas, &paint));
107     REPORTER_ASSERT(reporter, SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrcOver_Mode));
108     canvas.drawRect(SkRect::MakeWH(50.0f, 50.0f), paint);
109     REPORTER_ASSERT(reporter, 0.0f == device.fLastMatrix.getTranslateX());
110     REPORTER_ASSERT(reporter, 0.0f == device.fLastMatrix.getTranslateY());
111     paint.reset();
112 
113     // Then the front layer.
114     REPORTER_ASSERT(reporter, context->next(&canvas, &paint));
115     REPORTER_ASSERT(reporter, SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrc_Mode));
116     canvas.drawRect(SkRect::MakeWH(50.0f, 50.0f), paint);
117     REPORTER_ASSERT(reporter, 10.0f == device.fLastMatrix.getTranslateX());
118     REPORTER_ASSERT(reporter, 20.0f == device.fLastMatrix.getTranslateY());
119 
120     // Only two layers were added, so that should be the end.
121     REPORTER_ASSERT(reporter, !context->next(&canvas, &paint));
122 }
123 
test_mixed(skiatest::Reporter * reporter)124 static void test_mixed(skiatest::Reporter* reporter) {
125     SkLayerDrawLooper::Builder looperBuilder;
126     SkLayerDrawLooper::LayerInfo layerInfo;
127 
128     // Add the back layer, with the defaults.
129     (void)looperBuilder.addLayer(layerInfo);
130 
131     // Add the front layer, with some layer info set.
132     layerInfo.fOffset.set(10.0f, 20.0f);
133     layerInfo.fPaintBits |= SkLayerDrawLooper::kXfermode_Bit;
134     SkPaint* layerPaint = looperBuilder.addLayerOnTop(layerInfo);
135     layerPaint->setXfermodeMode(SkXfermode::kSrc_Mode);
136 
137     FakeDevice device;
138     SkCanvas canvas(&device);
139     SkPaint paint;
140     SkAutoTUnref<SkLayerDrawLooper> looper(looperBuilder.detachLooper());
141     SkSmallAllocator<1, 32> allocator;
142     void* buffer = allocator.reserveT<SkDrawLooper::Context>(looper->contextSize());
143     SkDrawLooper::Context* context = looper->createContext(&canvas, buffer);
144 
145     // The back layer should come first.
146     REPORTER_ASSERT(reporter, context->next(&canvas, &paint));
147     REPORTER_ASSERT(reporter, SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrcOver_Mode));
148     canvas.drawRect(SkRect::MakeWH(50.0f, 50.0f), paint);
149     REPORTER_ASSERT(reporter, 0.0f == device.fLastMatrix.getTranslateX());
150     REPORTER_ASSERT(reporter, 0.0f == device.fLastMatrix.getTranslateY());
151     paint.reset();
152 
153     // Then the front layer.
154     REPORTER_ASSERT(reporter, context->next(&canvas, &paint));
155     REPORTER_ASSERT(reporter, SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrc_Mode));
156     canvas.drawRect(SkRect::MakeWH(50.0f, 50.0f), paint);
157     REPORTER_ASSERT(reporter, 10.0f == device.fLastMatrix.getTranslateX());
158     REPORTER_ASSERT(reporter, 20.0f == device.fLastMatrix.getTranslateY());
159 
160     // Only two layers were added, so that should be the end.
161     REPORTER_ASSERT(reporter, !context->next(&canvas, &paint));
162 }
163 
DEF_TEST(LayerDrawLooper,reporter)164 DEF_TEST(LayerDrawLooper, reporter) {
165     test_frontToBack(reporter);
166     test_backToFront(reporter);
167     test_mixed(reporter);
168 }
169