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