1 /*
2 * Copyright (C) 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <gtest/gtest.h>
18
19 #include <canvas/CanvasFrontend.h>
20 #include <canvas/CanvasOpBuffer.h>
21 #include <canvas/CanvasOps.h>
22 #include <canvas/CanvasOpRasterizer.h>
23
24 #include <tests/common/CallCountingCanvas.h>
25
26 #include "SkPictureRecorder.h"
27 #include "SkColor.h"
28 #include "SkLatticeIter.h"
29 #include "pipeline/skia/AnimatedDrawables.h"
30 #include <SkNoDrawCanvas.h>
31
32 using namespace android;
33 using namespace android::uirenderer;
34 using namespace android::uirenderer::test;
35
36 class CanvasOpCountingReceiver {
37 public:
38 template <CanvasOpType T>
push_container(CanvasOpContainer<T> && op)39 void push_container(CanvasOpContainer<T>&& op) {
40 mOpCounts[static_cast<size_t>(T)] += 1;
41 }
42
operator [](CanvasOpType op) const43 int operator[](CanvasOpType op) const {
44 return mOpCounts[static_cast<size_t>(op)];
45 }
46
47 private:
48 std::array<int, static_cast<size_t>(CanvasOpType::COUNT)> mOpCounts;
49 };
50
TEST(CanvasFrontend,saveCount)51 TEST(CanvasFrontend, saveCount) {
52 SkNoDrawCanvas skiaCanvas(100, 100);
53 CanvasFrontend<CanvasOpCountingReceiver> opCanvas(100, 100);
54 const auto& receiver = opCanvas.receiver();
55
56 EXPECT_EQ(1, skiaCanvas.getSaveCount());
57 EXPECT_EQ(1, opCanvas.saveCount());
58
59 skiaCanvas.save();
60 opCanvas.save(SaveFlags::MatrixClip);
61 EXPECT_EQ(2, skiaCanvas.getSaveCount());
62 EXPECT_EQ(2, opCanvas.saveCount());
63
64 skiaCanvas.restore();
65 opCanvas.restore();
66 EXPECT_EQ(1, skiaCanvas.getSaveCount());
67 EXPECT_EQ(1, opCanvas.saveCount());
68
69 skiaCanvas.restore();
70 opCanvas.restore();
71 EXPECT_EQ(1, skiaCanvas.getSaveCount());
72 EXPECT_EQ(1, opCanvas.saveCount());
73
74 EXPECT_EQ(1, receiver[CanvasOpType::Save]);
75 EXPECT_EQ(1, receiver[CanvasOpType::Restore]);
76 }
77
TEST(CanvasFrontend,transform)78 TEST(CanvasFrontend, transform) {
79 SkNoDrawCanvas skiaCanvas(100, 100);
80 CanvasFrontend<CanvasOpCountingReceiver> opCanvas(100, 100);
81
82 skiaCanvas.translate(10, 10);
83 opCanvas.translate(10, 10);
84 EXPECT_EQ(skiaCanvas.getTotalMatrix(), opCanvas.transform());
85
86 {
87 skiaCanvas.save();
88 opCanvas.save(SaveFlags::Matrix);
89 skiaCanvas.scale(2.0f, 1.125f);
90 opCanvas.scale(2.0f, 1.125f);
91
92 EXPECT_EQ(skiaCanvas.getTotalMatrix(), opCanvas.transform());
93 skiaCanvas.restore();
94 opCanvas.restore();
95 }
96
97 EXPECT_EQ(skiaCanvas.getTotalMatrix(), opCanvas.transform());
98
99 {
100 skiaCanvas.save();
101 opCanvas.save(SaveFlags::Matrix);
102 skiaCanvas.rotate(90.f);
103 opCanvas.rotate(90.f);
104
105 EXPECT_EQ(skiaCanvas.getTotalMatrix(), opCanvas.transform());
106
107 {
108 skiaCanvas.save();
109 opCanvas.save(SaveFlags::Matrix);
110 skiaCanvas.skew(5.0f, 2.25f);
111 opCanvas.skew(5.0f, 2.25f);
112
113 EXPECT_EQ(skiaCanvas.getTotalMatrix(), opCanvas.transform());
114 skiaCanvas.restore();
115 opCanvas.restore();
116 }
117
118 skiaCanvas.restore();
119 opCanvas.restore();
120 }
121
122 EXPECT_EQ(skiaCanvas.getTotalMatrix(), opCanvas.transform());
123 }
124
TEST(CanvasFrontend,drawOpTransform)125 TEST(CanvasFrontend, drawOpTransform) {
126 CanvasFrontend<CanvasOpBuffer> opCanvas(100, 100);
127 const auto &receiver = opCanvas.receiver();
128
129 auto makeDrawRect = [] {
130 return CanvasOp<CanvasOpType::DrawRect>{
131 .rect = SkRect::MakeWH(50, 50),
132 .paint = SkPaint(SkColors::kBlack),
133 };
134 };
135
136 opCanvas.draw(makeDrawRect());
137
138 opCanvas.translate(10, 10);
139 opCanvas.draw(makeDrawRect());
140
141 opCanvas.save();
142 opCanvas.scale(2.0f, 4.0f);
143 opCanvas.draw(makeDrawRect());
144 opCanvas.restore();
145
146 opCanvas.save();
147 opCanvas.translate(20, 15);
148 opCanvas.draw(makeDrawRect());
149 opCanvas.save();
150 opCanvas.rotate(90.f);
151 opCanvas.draw(makeDrawRect());
152 opCanvas.restore();
153 opCanvas.restore();
154
155 // Validate the results
156 std::vector<SkMatrix> transforms;
157 transforms.reserve(5);
158 receiver.for_each([&](auto op) {
159 // Filter for the DrawRect calls; ignore the save & restores
160 // (TODO: Add a filtered for_each variant to OpBuffer?)
161 if (op->type() == CanvasOpType::DrawRect) {
162 transforms.push_back(op->transform());
163 }
164 });
165
166 EXPECT_EQ(transforms.size(), 5);
167
168 {
169 // First result should be identity
170 const auto &result = transforms[0];
171 EXPECT_EQ(SkMatrix::kIdentity_Mask, result.getType());
172 EXPECT_EQ(SkMatrix::I(), result);
173 }
174
175 {
176 // Should be translate 10, 10
177 const auto &result = transforms[1];
178 EXPECT_EQ(SkMatrix::kTranslate_Mask, result.getType());
179 SkMatrix m;
180 m.setTranslate(10, 10);
181 EXPECT_EQ(m, result);
182 }
183
184 {
185 // Should be translate 10, 10 + scale 2, 4
186 const auto &result = transforms[2];
187 EXPECT_EQ(SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask, result.getType());
188 SkMatrix m;
189 m.setTranslate(10, 10);
190 m.preScale(2.0f, 4.0f);
191 EXPECT_EQ(m, result);
192 }
193
194 {
195 // Should be translate 10, 10 + translate 20, 15
196 const auto &result = transforms[3];
197 EXPECT_EQ(SkMatrix::kTranslate_Mask, result.getType());
198 SkMatrix m;
199 m.setTranslate(30, 25);
200 EXPECT_EQ(m, result);
201 }
202
203 {
204 // Should be translate 10, 10 + translate 20, 15 + rotate 90
205 const auto &result = transforms[4];
206 EXPECT_EQ(SkMatrix::kTranslate_Mask | SkMatrix::kAffine_Mask | SkMatrix::kScale_Mask,
207 result.getType());
208 SkMatrix m;
209 m.setTranslate(30, 25);
210 m.preRotate(90.f);
211 EXPECT_EQ(m, result);
212 }
213 }