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 // TODO: can this be derived from SkBaseDevice?
29 class FakeDevice : public SkBitmapDevice {
30 public:
FakeDevice()31     FakeDevice() : INHERITED(make_bm(100, 100), SkSurfaceProps(0, kUnknown_SkPixelGeometry)) {
32     }
33 
drawRect(const SkDraw & draw,const SkRect & r,const SkPaint & paint)34     void drawRect(const SkDraw& draw, const SkRect& r, const SkPaint& paint) override {
35         fLastMatrix = *draw.fMatrix;
36         this->INHERITED::drawRect(draw, r, paint);
37     }
38 
39     SkMatrix fLastMatrix;
40 
41 private:
42     typedef SkBitmapDevice INHERITED;
43 };
44 
test_frontToBack(skiatest::Reporter * reporter)45 static void test_frontToBack(skiatest::Reporter* reporter) {
46     SkLayerDrawLooper::Builder looperBuilder;
47     SkLayerDrawLooper::LayerInfo layerInfo;
48 
49     // Add the front layer, with the defaults.
50     (void)looperBuilder.addLayer(layerInfo);
51 
52     // Add the back layer, with some layer info set.
53     layerInfo.fOffset.set(10.0f, 20.0f);
54     layerInfo.fPaintBits |= SkLayerDrawLooper::kXfermode_Bit;
55     SkPaint* layerPaint = looperBuilder.addLayer(layerInfo);
56     layerPaint->setXfermodeMode(SkXfermode::kSrc_Mode);
57 
58     FakeDevice device;
59     SkCanvas canvas(&device);
60     SkPaint paint;
61     SkAutoTUnref<SkLayerDrawLooper> looper(looperBuilder.detachLooper());
62     SkSmallAllocator<1, 32> allocator;
63     void* buffer = allocator.reserveT<SkDrawLooper::Context>(looper->contextSize());
64     SkDrawLooper::Context* context = looper->createContext(&canvas, buffer);
65 
66     // The back layer should come first.
67     REPORTER_ASSERT(reporter, context->next(&canvas, &paint));
68     REPORTER_ASSERT(reporter, SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrc_Mode));
69     canvas.drawRect(SkRect::MakeWH(50.0f, 50.0f), paint);
70     REPORTER_ASSERT(reporter, 10.0f == device.fLastMatrix.getTranslateX());
71     REPORTER_ASSERT(reporter, 20.0f == device.fLastMatrix.getTranslateY());
72     paint.reset();
73 
74     // Then the front layer.
75     REPORTER_ASSERT(reporter, context->next(&canvas, &paint));
76     REPORTER_ASSERT(reporter, SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrcOver_Mode));
77     canvas.drawRect(SkRect::MakeWH(50.0f, 50.0f), paint);
78     REPORTER_ASSERT(reporter, 0.0f == device.fLastMatrix.getTranslateX());
79     REPORTER_ASSERT(reporter, 0.0f == device.fLastMatrix.getTranslateY());
80 
81     // Only two layers were added, so that should be the end.
82     REPORTER_ASSERT(reporter, !context->next(&canvas, &paint));
83 }
84 
test_backToFront(skiatest::Reporter * reporter)85 static void test_backToFront(skiatest::Reporter* reporter) {
86     SkLayerDrawLooper::Builder looperBuilder;
87     SkLayerDrawLooper::LayerInfo layerInfo;
88 
89     // Add the back layer, with the defaults.
90     (void)looperBuilder.addLayerOnTop(layerInfo);
91 
92     // Add the front layer, with some layer info set.
93     layerInfo.fOffset.set(10.0f, 20.0f);
94     layerInfo.fPaintBits |= SkLayerDrawLooper::kXfermode_Bit;
95     SkPaint* layerPaint = looperBuilder.addLayerOnTop(layerInfo);
96     layerPaint->setXfermodeMode(SkXfermode::kSrc_Mode);
97 
98     FakeDevice device;
99     SkCanvas canvas(&device);
100     SkPaint paint;
101     SkAutoTUnref<SkLayerDrawLooper> looper(looperBuilder.detachLooper());
102     SkSmallAllocator<1, 32> allocator;
103     void* buffer = allocator.reserveT<SkDrawLooper::Context>(looper->contextSize());
104     SkDrawLooper::Context* context = looper->createContext(&canvas, buffer);
105 
106     // The back layer should come first.
107     REPORTER_ASSERT(reporter, context->next(&canvas, &paint));
108     REPORTER_ASSERT(reporter, SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrcOver_Mode));
109     canvas.drawRect(SkRect::MakeWH(50.0f, 50.0f), paint);
110     REPORTER_ASSERT(reporter, 0.0f == device.fLastMatrix.getTranslateX());
111     REPORTER_ASSERT(reporter, 0.0f == device.fLastMatrix.getTranslateY());
112     paint.reset();
113 
114     // Then the front layer.
115     REPORTER_ASSERT(reporter, context->next(&canvas, &paint));
116     REPORTER_ASSERT(reporter, SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrc_Mode));
117     canvas.drawRect(SkRect::MakeWH(50.0f, 50.0f), paint);
118     REPORTER_ASSERT(reporter, 10.0f == device.fLastMatrix.getTranslateX());
119     REPORTER_ASSERT(reporter, 20.0f == device.fLastMatrix.getTranslateY());
120 
121     // Only two layers were added, so that should be the end.
122     REPORTER_ASSERT(reporter, !context->next(&canvas, &paint));
123 }
124 
test_mixed(skiatest::Reporter * reporter)125 static void test_mixed(skiatest::Reporter* reporter) {
126     SkLayerDrawLooper::Builder looperBuilder;
127     SkLayerDrawLooper::LayerInfo layerInfo;
128 
129     // Add the back layer, with the defaults.
130     (void)looperBuilder.addLayer(layerInfo);
131 
132     // Add the front layer, with some layer info set.
133     layerInfo.fOffset.set(10.0f, 20.0f);
134     layerInfo.fPaintBits |= SkLayerDrawLooper::kXfermode_Bit;
135     SkPaint* layerPaint = looperBuilder.addLayerOnTop(layerInfo);
136     layerPaint->setXfermodeMode(SkXfermode::kSrc_Mode);
137 
138     FakeDevice device;
139     SkCanvas canvas(&device);
140     SkPaint paint;
141     SkAutoTUnref<SkLayerDrawLooper> looper(looperBuilder.detachLooper());
142     SkSmallAllocator<1, 32> allocator;
143     void* buffer = allocator.reserveT<SkDrawLooper::Context>(looper->contextSize());
144     SkDrawLooper::Context* context = looper->createContext(&canvas, buffer);
145 
146     // The back layer should come first.
147     REPORTER_ASSERT(reporter, context->next(&canvas, &paint));
148     REPORTER_ASSERT(reporter, SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrcOver_Mode));
149     canvas.drawRect(SkRect::MakeWH(50.0f, 50.0f), paint);
150     REPORTER_ASSERT(reporter, 0.0f == device.fLastMatrix.getTranslateX());
151     REPORTER_ASSERT(reporter, 0.0f == device.fLastMatrix.getTranslateY());
152     paint.reset();
153 
154     // Then the front layer.
155     REPORTER_ASSERT(reporter, context->next(&canvas, &paint));
156     REPORTER_ASSERT(reporter, SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrc_Mode));
157     canvas.drawRect(SkRect::MakeWH(50.0f, 50.0f), paint);
158     REPORTER_ASSERT(reporter, 10.0f == device.fLastMatrix.getTranslateX());
159     REPORTER_ASSERT(reporter, 20.0f == device.fLastMatrix.getTranslateY());
160 
161     // Only two layers were added, so that should be the end.
162     REPORTER_ASSERT(reporter, !context->next(&canvas, &paint));
163 }
164 
DEF_TEST(LayerDrawLooper,reporter)165 DEF_TEST(LayerDrawLooper, reporter) {
166     test_frontToBack(reporter);
167     test_backToFront(reporter);
168     test_mixed(reporter);
169 }
170