• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }