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 nullptr, nullptr) {
32 }
33
drawRect(const SkRect & r,const SkPaint & paint)34 void drawRect(const SkRect& r, const SkPaint& paint) override {
35 fLastMatrix = this->ctm();
36 this->INHERITED::drawRect(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->setBlendMode(SkBlendMode::kSrc);
57
58 FakeDevice device;
59 SkCanvas canvas(sk_ref_sp(&device));
60 SkPaint paint;
61 auto looper(looperBuilder.detach());
62 SkArenaAlloc alloc{48};
63 SkDrawLooper::Context* context = looper->makeContext(&canvas, &alloc);
64
65 // The back layer should come first.
66 REPORTER_ASSERT(reporter, context->next(&canvas, &paint));
67 REPORTER_ASSERT(reporter, paint.getBlendMode() == SkBlendMode::kSrc);
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, paint.getBlendMode() == SkBlendMode::kSrcOver);
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->setBlendMode(SkBlendMode::kSrc);
96
97 FakeDevice device;
98 SkCanvas canvas(sk_ref_sp(&device));
99 SkPaint paint;
100 auto looper(looperBuilder.detach());
101 SkArenaAlloc alloc{48};
102 SkDrawLooper::Context* context = looper->makeContext(&canvas, &alloc);
103
104 // The back layer should come first.
105 REPORTER_ASSERT(reporter, context->next(&canvas, &paint));
106 REPORTER_ASSERT(reporter, paint.getBlendMode() == SkBlendMode::kSrcOver);
107 canvas.drawRect(SkRect::MakeWH(50.0f, 50.0f), paint);
108 REPORTER_ASSERT(reporter, 0.0f == device.fLastMatrix.getTranslateX());
109 REPORTER_ASSERT(reporter, 0.0f == device.fLastMatrix.getTranslateY());
110 paint.reset();
111
112 // Then the front layer.
113 REPORTER_ASSERT(reporter, context->next(&canvas, &paint));
114 REPORTER_ASSERT(reporter, paint.getBlendMode() == SkBlendMode::kSrc);
115 canvas.drawRect(SkRect::MakeWH(50.0f, 50.0f), paint);
116 REPORTER_ASSERT(reporter, 10.0f == device.fLastMatrix.getTranslateX());
117 REPORTER_ASSERT(reporter, 20.0f == device.fLastMatrix.getTranslateY());
118
119 // Only two layers were added, so that should be the end.
120 REPORTER_ASSERT(reporter, !context->next(&canvas, &paint));
121 }
122
test_mixed(skiatest::Reporter * reporter)123 static void test_mixed(skiatest::Reporter* reporter) {
124 SkLayerDrawLooper::Builder looperBuilder;
125 SkLayerDrawLooper::LayerInfo layerInfo;
126
127 // Add the back layer, with the defaults.
128 (void)looperBuilder.addLayer(layerInfo);
129
130 // Add the front layer, with some layer info set.
131 layerInfo.fOffset.set(10.0f, 20.0f);
132 layerInfo.fPaintBits |= SkLayerDrawLooper::kXfermode_Bit;
133 SkPaint* layerPaint = looperBuilder.addLayerOnTop(layerInfo);
134 layerPaint->setBlendMode(SkBlendMode::kSrc);
135
136 FakeDevice device;
137 SkCanvas canvas(sk_ref_sp(&device));
138 SkPaint paint;
139 sk_sp<SkDrawLooper> looper(looperBuilder.detach());
140 SkArenaAlloc alloc{48};
141 SkDrawLooper::Context* context = looper->makeContext(&canvas, &alloc);
142
143 // The back layer should come first.
144 REPORTER_ASSERT(reporter, context->next(&canvas, &paint));
145 REPORTER_ASSERT(reporter, paint.getBlendMode() == SkBlendMode::kSrcOver);
146 canvas.drawRect(SkRect::MakeWH(50.0f, 50.0f), paint);
147 REPORTER_ASSERT(reporter, 0.0f == device.fLastMatrix.getTranslateX());
148 REPORTER_ASSERT(reporter, 0.0f == device.fLastMatrix.getTranslateY());
149 paint.reset();
150
151 // Then the front layer.
152 REPORTER_ASSERT(reporter, context->next(&canvas, &paint));
153 REPORTER_ASSERT(reporter, paint.getBlendMode() == SkBlendMode::kSrc);
154 canvas.drawRect(SkRect::MakeWH(50.0f, 50.0f), paint);
155 REPORTER_ASSERT(reporter, 10.0f == device.fLastMatrix.getTranslateX());
156 REPORTER_ASSERT(reporter, 20.0f == device.fLastMatrix.getTranslateY());
157
158 // Only two layers were added, so that should be the end.
159 REPORTER_ASSERT(reporter, !context->next(&canvas, &paint));
160 }
161
DEF_TEST(LayerDrawLooper,reporter)162 DEF_TEST(LayerDrawLooper, reporter) {
163 test_frontToBack(reporter);
164 test_backToFront(reporter);
165 test_mixed(reporter);
166 }
167