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 "SkArenaAlloc.h"
9 #include "SkBitmap.h"
10 #include "SkBitmapDevice.h"
11 #include "SkCanvas.h"
12 #include "SkDraw.h"
13 #include "SkLayerDrawLooper.h"
14 #include "SkMatrix.h"
15 #include "SkPaint.h"
16 #include "SkRect.h"
17 #include "SkRefCnt.h"
18 #include "SkScalar.h"
19 #include "Test.h"
20
make_bm(int w,int h)21 static SkBitmap make_bm(int w, int h) {
22 SkBitmap bm;
23 bm.allocN32Pixels(w, h);
24 return bm;
25 }
26
27 // TODO: can this be derived from SkBaseDevice?
28 class FakeDevice : public SkBitmapDevice {
29 public:
FakeDevice()30 FakeDevice() : INHERITED(make_bm(100, 100), SkSurfaceProps(0, kUnknown_SkPixelGeometry)) {
31 }
32
drawRect(const SkRect & r,const SkPaint & paint)33 void drawRect(const SkRect& r, const SkPaint& paint) override {
34 fLastMatrix = this->ctm();
35 this->INHERITED::drawRect(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->setBlendMode(SkBlendMode::kSrc);
56
57 FakeDevice device;
58 SkCanvas canvas(&device);
59 SkPaint paint;
60 auto looper(looperBuilder.detach());
61 SkArenaAlloc alloc{48};
62 SkDrawLooper::Context* context = looper->makeContext(&canvas, &alloc);
63
64 // The back layer should come first.
65 REPORTER_ASSERT(reporter, context->next(&canvas, &paint));
66 REPORTER_ASSERT(reporter, paint.getBlendMode() == SkBlendMode::kSrc);
67 canvas.drawRect(SkRect::MakeWH(50.0f, 50.0f), paint);
68 REPORTER_ASSERT(reporter, 10.0f == device.fLastMatrix.getTranslateX());
69 REPORTER_ASSERT(reporter, 20.0f == device.fLastMatrix.getTranslateY());
70 paint.reset();
71
72 // Then the front layer.
73 REPORTER_ASSERT(reporter, context->next(&canvas, &paint));
74 REPORTER_ASSERT(reporter, paint.getBlendMode() == SkBlendMode::kSrcOver);
75 canvas.drawRect(SkRect::MakeWH(50.0f, 50.0f), paint);
76 REPORTER_ASSERT(reporter, 0.0f == device.fLastMatrix.getTranslateX());
77 REPORTER_ASSERT(reporter, 0.0f == device.fLastMatrix.getTranslateY());
78
79 // Only two layers were added, so that should be the end.
80 REPORTER_ASSERT(reporter, !context->next(&canvas, &paint));
81 }
82
test_backToFront(skiatest::Reporter * reporter)83 static void test_backToFront(skiatest::Reporter* reporter) {
84 SkLayerDrawLooper::Builder looperBuilder;
85 SkLayerDrawLooper::LayerInfo layerInfo;
86
87 // Add the back layer, with the defaults.
88 (void)looperBuilder.addLayerOnTop(layerInfo);
89
90 // Add the front layer, with some layer info set.
91 layerInfo.fOffset.set(10.0f, 20.0f);
92 layerInfo.fPaintBits |= SkLayerDrawLooper::kXfermode_Bit;
93 SkPaint* layerPaint = looperBuilder.addLayerOnTop(layerInfo);
94 layerPaint->setBlendMode(SkBlendMode::kSrc);
95
96 FakeDevice device;
97 SkCanvas canvas(&device);
98 SkPaint paint;
99 auto looper(looperBuilder.detach());
100 SkArenaAlloc alloc{48};
101 SkDrawLooper::Context* context = looper->makeContext(&canvas, &alloc);
102
103 // The back layer should come first.
104 REPORTER_ASSERT(reporter, context->next(&canvas, &paint));
105 REPORTER_ASSERT(reporter, paint.getBlendMode() == SkBlendMode::kSrcOver);
106 canvas.drawRect(SkRect::MakeWH(50.0f, 50.0f), paint);
107 REPORTER_ASSERT(reporter, 0.0f == device.fLastMatrix.getTranslateX());
108 REPORTER_ASSERT(reporter, 0.0f == device.fLastMatrix.getTranslateY());
109 paint.reset();
110
111 // Then the front layer.
112 REPORTER_ASSERT(reporter, context->next(&canvas, &paint));
113 REPORTER_ASSERT(reporter, paint.getBlendMode() == SkBlendMode::kSrc);
114 canvas.drawRect(SkRect::MakeWH(50.0f, 50.0f), paint);
115 REPORTER_ASSERT(reporter, 10.0f == device.fLastMatrix.getTranslateX());
116 REPORTER_ASSERT(reporter, 20.0f == device.fLastMatrix.getTranslateY());
117
118 // Only two layers were added, so that should be the end.
119 REPORTER_ASSERT(reporter, !context->next(&canvas, &paint));
120 }
121
test_mixed(skiatest::Reporter * reporter)122 static void test_mixed(skiatest::Reporter* reporter) {
123 SkLayerDrawLooper::Builder looperBuilder;
124 SkLayerDrawLooper::LayerInfo layerInfo;
125
126 // Add the back layer, with the defaults.
127 (void)looperBuilder.addLayer(layerInfo);
128
129 // Add the front layer, with some layer info set.
130 layerInfo.fOffset.set(10.0f, 20.0f);
131 layerInfo.fPaintBits |= SkLayerDrawLooper::kXfermode_Bit;
132 SkPaint* layerPaint = looperBuilder.addLayerOnTop(layerInfo);
133 layerPaint->setBlendMode(SkBlendMode::kSrc);
134
135 FakeDevice device;
136 SkCanvas canvas(&device);
137 SkPaint paint;
138 sk_sp<SkDrawLooper> looper(looperBuilder.detach());
139 SkArenaAlloc alloc{48};
140 SkDrawLooper::Context* context = looper->makeContext(&canvas, &alloc);
141
142 // The back layer should come first.
143 REPORTER_ASSERT(reporter, context->next(&canvas, &paint));
144 REPORTER_ASSERT(reporter, paint.getBlendMode() == SkBlendMode::kSrcOver);
145 canvas.drawRect(SkRect::MakeWH(50.0f, 50.0f), paint);
146 REPORTER_ASSERT(reporter, 0.0f == device.fLastMatrix.getTranslateX());
147 REPORTER_ASSERT(reporter, 0.0f == device.fLastMatrix.getTranslateY());
148 paint.reset();
149
150 // Then the front layer.
151 REPORTER_ASSERT(reporter, context->next(&canvas, &paint));
152 REPORTER_ASSERT(reporter, paint.getBlendMode() == SkBlendMode::kSrc);
153 canvas.drawRect(SkRect::MakeWH(50.0f, 50.0f), paint);
154 REPORTER_ASSERT(reporter, 10.0f == device.fLastMatrix.getTranslateX());
155 REPORTER_ASSERT(reporter, 20.0f == device.fLastMatrix.getTranslateY());
156
157 // Only two layers were added, so that should be the end.
158 REPORTER_ASSERT(reporter, !context->next(&canvas, &paint));
159 }
160
DEF_TEST(LayerDrawLooper,reporter)161 DEF_TEST(LayerDrawLooper, reporter) {
162 test_frontToBack(reporter);
163 test_backToFront(reporter);
164 test_mixed(reporter);
165 }
166