blob: f988da3996657841555619008944713dfc24320e [file] [log] [blame]
Chris Craikb565df12015-10-05 13:00:52 -07001/*
2 * Copyright (C) 2015 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 <RecordedOp.h>
20#include <RecordingCanvas.h>
Chris Craik8160f202015-12-02 14:50:25 -080021#include <tests/common/TestUtils.h>
Chris Craik1713c772016-02-18 17:49:44 -080022#include <utils/Color.h>
Chris Craikb565df12015-10-05 13:00:52 -070023
24namespace android {
25namespace uirenderer {
26
Chris Craikb36af872015-10-16 14:23:12 -070027static void playbackOps(const DisplayList& displayList,
Chris Craik6fe991e52015-10-20 09:39:42 -070028 std::function<void(const RecordedOp&)> opReceiver) {
Chris Craik161f54b2015-11-05 11:08:52 -080029 for (auto& chunk : displayList.getChunks()) {
Chris Craikb565df12015-10-05 13:00:52 -070030 for (size_t opIndex = chunk.beginOpIndex; opIndex < chunk.endOpIndex; opIndex++) {
Chris Craikb36af872015-10-16 14:23:12 -070031 RecordedOp* op = displayList.getOps()[opIndex];
Chris Craik6fe991e52015-10-20 09:39:42 -070032 opReceiver(*op);
Chris Craikb565df12015-10-05 13:00:52 -070033 }
34 }
35}
36
37TEST(RecordingCanvas, emptyPlayback) {
Chris Craikb36af872015-10-16 14:23:12 -070038 auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) {
Florin Malitaeecff562015-12-21 10:43:01 -050039 canvas.save(SaveFlags::MatrixClip);
Chris Craikb565df12015-10-05 13:00:52 -070040 canvas.restore();
41 });
Chris Craik818c9fb2015-10-23 14:33:42 -070042 playbackOps(*dl, [](const RecordedOp& op) { ADD_FAILURE(); });
Chris Craikb565df12015-10-05 13:00:52 -070043}
44
Chris Craike4db79d2015-12-22 16:32:23 -080045TEST(RecordingCanvas, clipRect) {
46 auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 100, [](RecordingCanvas& canvas) {
Florin Malitaeecff562015-12-21 10:43:01 -050047 canvas.save(SaveFlags::MatrixClip);
Chris Craike4db79d2015-12-22 16:32:23 -080048 canvas.clipRect(0, 0, 100, 100, SkRegion::kIntersect_Op);
49 canvas.drawRect(0, 0, 50, 50, SkPaint());
50 canvas.drawRect(50, 50, 100, 100, SkPaint());
51 canvas.restore();
52 });
53
54 ASSERT_EQ(2u, dl->getOps().size()) << "Must be exactly two ops";
55 EXPECT_CLIP_RECT(Rect(100, 100), dl->getOps()[0]->localClip);
56 EXPECT_CLIP_RECT(Rect(100, 100), dl->getOps()[1]->localClip);
57 EXPECT_EQ(dl->getOps()[0]->localClip, dl->getOps()[1]->localClip)
58 << "Clip should be serialized once";
59}
60
Chris Craikcaa24182016-02-19 15:20:35 -080061TEST(RecordingCanvas, drawArc) {
62 auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
63 canvas.drawArc(0, 0, 200, 200, 0, 180, true, SkPaint());
64 canvas.drawArc(0, 0, 100, 100, 0, 360, true, SkPaint());
65 });
66
67 auto&& ops = dl->getOps();
68 ASSERT_EQ(2u, ops.size()) << "Must be exactly two ops";
69 EXPECT_EQ(RecordedOpId::ArcOp, ops[0]->opId);
70 EXPECT_EQ(Rect(200, 200), ops[0]->unmappedBounds);
71
72 EXPECT_EQ(RecordedOpId::OvalOp, ops[1]->opId)
73 << "Circular arcs should be converted to ovals";
74 EXPECT_EQ(Rect(100, 100), ops[1]->unmappedBounds);
75}
76
Chris Craika1717272015-11-19 13:02:43 -080077TEST(RecordingCanvas, drawLines) {
78 auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) {
79 SkPaint paint;
Chris Craik386aa032015-12-07 17:08:25 -080080 paint.setStrokeWidth(20); // doesn't affect recorded bounds - would be resolved at bake time
Chris Craika1717272015-11-19 13:02:43 -080081 float points[] = { 0, 0, 20, 10, 30, 40, 90 }; // NB: only 1 valid line
82 canvas.drawLines(&points[0], 7, paint);
83 });
84
85 ASSERT_EQ(1u, dl->getOps().size()) << "Must be exactly one op";
86 auto op = dl->getOps()[0];
87 ASSERT_EQ(RecordedOpId::LinesOp, op->opId);
88 EXPECT_EQ(4, ((LinesOp*)op)->floatCount)
89 << "float count must be rounded down to closest multiple of 4";
Chris Craik5430ab22015-12-10 16:28:16 -080090 EXPECT_EQ(Rect(20, 10), op->unmappedBounds)
Chris Craik386aa032015-12-07 17:08:25 -080091 << "unmapped bounds must be size of line, and not outset for stroke width";
Chris Craika1717272015-11-19 13:02:43 -080092}
93
94TEST(RecordingCanvas, drawRect) {
Chris Craikb36af872015-10-16 14:23:12 -070095 auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) {
Chris Craikb565df12015-10-05 13:00:52 -070096 canvas.drawRect(10, 20, 90, 180, SkPaint());
97 });
98
Chris Craika1717272015-11-19 13:02:43 -080099 ASSERT_EQ(1u, dl->getOps().size()) << "Must be exactly one op";
100 auto op = *(dl->getOps()[0]);
101 ASSERT_EQ(RecordedOpId::RectOp, op.opId);
Chris Craike4db79d2015-12-22 16:32:23 -0800102 EXPECT_EQ(nullptr, op.localClip);
Chris Craika1717272015-11-19 13:02:43 -0800103 EXPECT_EQ(Rect(10, 20, 90, 180), op.unmappedBounds);
104}
105
106TEST(RecordingCanvas, drawText) {
107 auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
108 SkPaint paint;
109 paint.setAntiAlias(true);
110 paint.setTextSize(20);
Chris Craik42a54072015-11-24 11:41:54 -0800111 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
Chris Craika1717272015-11-19 13:02:43 -0800112 TestUtils::drawTextToCanvas(&canvas, "test text", paint, 25, 25);
113 });
114
Chris Craikb565df12015-10-05 13:00:52 -0700115 int count = 0;
Chris Craikb36af872015-10-16 14:23:12 -0700116 playbackOps(*dl, [&count](const RecordedOp& op) {
Chris Craikb565df12015-10-05 13:00:52 -0700117 count++;
Chris Craika1717272015-11-19 13:02:43 -0800118 ASSERT_EQ(RecordedOpId::TextOp, op.opId);
Chris Craike4db79d2015-12-22 16:32:23 -0800119 EXPECT_EQ(nullptr, op.localClip);
Chris Craika1717272015-11-19 13:02:43 -0800120 EXPECT_TRUE(op.localMatrix.isIdentity());
121 EXPECT_TRUE(op.unmappedBounds.contains(25, 15, 50, 25))
122 << "Op expected to be 25+ pixels wide, 10+ pixels tall";
Chris Craikb565df12015-10-05 13:00:52 -0700123 });
Chris Craika6ac95e2015-11-02 18:06:59 -0800124 ASSERT_EQ(1, count);
Chris Craikb565df12015-10-05 13:00:52 -0700125}
126
Chris Craika1717272015-11-19 13:02:43 -0800127TEST(RecordingCanvas, drawText_strikeThruAndUnderline) {
128 auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
129 SkPaint paint;
130 paint.setAntiAlias(true);
131 paint.setTextSize(20);
Chris Craik42a54072015-11-24 11:41:54 -0800132 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
Chris Craika1717272015-11-19 13:02:43 -0800133 for (int i = 0; i < 2; i++) {
134 for (int j = 0; j < 2; j++) {
135 paint.setUnderlineText(i != 0);
136 paint.setStrikeThruText(j != 0);
137 TestUtils::drawTextToCanvas(&canvas, "test text", paint, 25, 25);
138 }
139 }
140 });
141
142 auto ops = dl->getOps();
143 ASSERT_EQ(8u, ops.size());
144
145 int index = 0;
146 EXPECT_EQ(RecordedOpId::TextOp, ops[index++]->opId); // no underline or strikethrough
147
148 EXPECT_EQ(RecordedOpId::TextOp, ops[index++]->opId);
149 EXPECT_EQ(RecordedOpId::RectOp, ops[index++]->opId); // strikethrough only
150
151 EXPECT_EQ(RecordedOpId::TextOp, ops[index++]->opId);
152 EXPECT_EQ(RecordedOpId::RectOp, ops[index++]->opId); // underline only
153
154 EXPECT_EQ(RecordedOpId::TextOp, ops[index++]->opId);
155 EXPECT_EQ(RecordedOpId::RectOp, ops[index++]->opId); // underline
156 EXPECT_EQ(RecordedOpId::RectOp, ops[index++]->opId); // strikethrough
157}
158
159TEST(RecordingCanvas, drawText_forceAlignLeft) {
160 auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
161 SkPaint paint;
162 paint.setAntiAlias(true);
163 paint.setTextSize(20);
Chris Craik42a54072015-11-24 11:41:54 -0800164 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
Chris Craika1717272015-11-19 13:02:43 -0800165 paint.setTextAlign(SkPaint::kLeft_Align);
166 TestUtils::drawTextToCanvas(&canvas, "test text", paint, 25, 25);
167 paint.setTextAlign(SkPaint::kCenter_Align);
168 TestUtils::drawTextToCanvas(&canvas, "test text", paint, 25, 25);
169 paint.setTextAlign(SkPaint::kRight_Align);
170 TestUtils::drawTextToCanvas(&canvas, "test text", paint, 25, 25);
171 });
172
173 int count = 0;
Chris Craik42a54072015-11-24 11:41:54 -0800174 float lastX = FLT_MAX;
175 playbackOps(*dl, [&count, &lastX](const RecordedOp& op) {
Chris Craika1717272015-11-19 13:02:43 -0800176 count++;
177 ASSERT_EQ(RecordedOpId::TextOp, op.opId);
178 EXPECT_EQ(SkPaint::kLeft_Align, op.paint->getTextAlign())
179 << "recorded drawText commands must force kLeft_Align on their paint";
Chris Craik42a54072015-11-24 11:41:54 -0800180
181 // verify TestUtils alignment offsetting (TODO: move asserts to Canvas base class)
182 EXPECT_GT(lastX, ((const TextOp&)op).x)
183 << "x coordinate should reduce across each of the draw commands, from alignment";
184 lastX = ((const TextOp&)op).x;
Chris Craika1717272015-11-19 13:02:43 -0800185 });
186 ASSERT_EQ(3, count);
187}
188
Chris Craik1713c772016-02-18 17:49:44 -0800189TEST(RecordingCanvas, drawColor) {
190 auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
191 canvas.drawColor(Color::Black, SkXfermode::kSrcOver_Mode);
192 });
193
194 ASSERT_EQ(1u, dl->getOps().size()) << "Must be exactly one op";
195 auto op = *(dl->getOps()[0]);
196 EXPECT_EQ(RecordedOpId::RectOp, op.opId);
197 EXPECT_EQ(nullptr, op.localClip);
198 EXPECT_TRUE(op.unmappedBounds.contains(Rect(-1000, -1000, 1000, 1000)))
199 << "no clip, unmappedBounds should resolve to be much larger than DL bounds";
200}
201
Chris Craikb565df12015-10-05 13:00:52 -0700202TEST(RecordingCanvas, backgroundAndImage) {
Chris Craikb36af872015-10-16 14:23:12 -0700203 auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) {
Chris Craikb565df12015-10-05 13:00:52 -0700204 SkBitmap bitmap;
205 bitmap.setInfo(SkImageInfo::MakeUnknown(25, 25));
206 SkPaint paint;
207 paint.setColor(SK_ColorBLUE);
208
Florin Malitaeecff562015-12-21 10:43:01 -0500209 canvas.save(SaveFlags::MatrixClip);
Chris Craikb565df12015-10-05 13:00:52 -0700210 {
211 // a background!
Florin Malitaeecff562015-12-21 10:43:01 -0500212 canvas.save(SaveFlags::MatrixClip);
Chris Craikb565df12015-10-05 13:00:52 -0700213 canvas.drawRect(0, 0, 100, 200, paint);
214 canvas.restore();
215 }
216 {
217 // an image!
Florin Malitaeecff562015-12-21 10:43:01 -0500218 canvas.save(SaveFlags::MatrixClip);
Chris Craikb565df12015-10-05 13:00:52 -0700219 canvas.translate(25, 25);
220 canvas.scale(2, 2);
221 canvas.drawBitmap(bitmap, 0, 0, nullptr);
222 canvas.restore();
223 }
224 canvas.restore();
225 });
226
227 int count = 0;
Chris Craikb36af872015-10-16 14:23:12 -0700228 playbackOps(*dl, [&count](const RecordedOp& op) {
Chris Craikb565df12015-10-05 13:00:52 -0700229 if (count == 0) {
230 ASSERT_EQ(RecordedOpId::RectOp, op.opId);
231 ASSERT_NE(nullptr, op.paint);
232 EXPECT_EQ(SK_ColorBLUE, op.paint->getColor());
Chris Craik5430ab22015-12-10 16:28:16 -0800233 EXPECT_EQ(Rect(100, 200), op.unmappedBounds);
Chris Craike4db79d2015-12-22 16:32:23 -0800234 EXPECT_EQ(nullptr, op.localClip);
Chris Craikb565df12015-10-05 13:00:52 -0700235
236 Matrix4 expectedMatrix;
237 expectedMatrix.loadIdentity();
238 EXPECT_MATRIX_APPROX_EQ(expectedMatrix, op.localMatrix);
239 } else {
240 ASSERT_EQ(RecordedOpId::BitmapOp, op.opId);
241 EXPECT_EQ(nullptr, op.paint);
Chris Craik5430ab22015-12-10 16:28:16 -0800242 EXPECT_EQ(Rect(25, 25), op.unmappedBounds);
Chris Craike4db79d2015-12-22 16:32:23 -0800243 EXPECT_EQ(nullptr, op.localClip);
Chris Craikb565df12015-10-05 13:00:52 -0700244
245 Matrix4 expectedMatrix;
246 expectedMatrix.loadTranslate(25, 25, 0);
247 expectedMatrix.scale(2, 2, 1);
248 EXPECT_MATRIX_APPROX_EQ(expectedMatrix, op.localMatrix);
249 }
250 count++;
251 });
Chris Craika6ac95e2015-11-02 18:06:59 -0800252 ASSERT_EQ(2, count);
Chris Craikb565df12015-10-05 13:00:52 -0700253}
254
Chris Craika1717272015-11-19 13:02:43 -0800255TEST(RecordingCanvas, saveLayer_simple) {
Chris Craik6fe991e52015-10-20 09:39:42 -0700256 auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
Florin Malitaeecff562015-12-21 10:43:01 -0500257 canvas.saveLayerAlpha(10, 20, 190, 180, 128, SaveFlags::ClipToLayer);
Chris Craik6fe991e52015-10-20 09:39:42 -0700258 canvas.drawRect(10, 20, 190, 180, SkPaint());
259 canvas.restore();
260 });
261 int count = 0;
262 playbackOps(*dl, [&count](const RecordedOp& op) {
263 Matrix4 expectedMatrix;
264 switch(count++) {
265 case 0:
266 EXPECT_EQ(RecordedOpId::BeginLayerOp, op.opId);
Chris Craika6ac95e2015-11-02 18:06:59 -0800267 EXPECT_EQ(Rect(10, 20, 190, 180), op.unmappedBounds);
Chris Craike4db79d2015-12-22 16:32:23 -0800268 EXPECT_EQ(nullptr, op.localClip);
Chris Craika6ac95e2015-11-02 18:06:59 -0800269 EXPECT_TRUE(op.localMatrix.isIdentity());
Chris Craik6fe991e52015-10-20 09:39:42 -0700270 break;
271 case 1:
272 EXPECT_EQ(RecordedOpId::RectOp, op.opId);
Chris Craike4db79d2015-12-22 16:32:23 -0800273 EXPECT_CLIP_RECT(Rect(180, 160), op.localClip);
Chris Craik6fe991e52015-10-20 09:39:42 -0700274 EXPECT_EQ(Rect(10, 20, 190, 180), op.unmappedBounds);
275 expectedMatrix.loadTranslate(-10, -20, 0);
276 EXPECT_MATRIX_APPROX_EQ(expectedMatrix, op.localMatrix);
277 break;
278 case 2:
279 EXPECT_EQ(RecordedOpId::EndLayerOp, op.opId);
Chris Craika6ac95e2015-11-02 18:06:59 -0800280 // Don't bother asserting recording state data - it's not used
Chris Craik6fe991e52015-10-20 09:39:42 -0700281 break;
282 default:
Chris Craik818c9fb2015-10-23 14:33:42 -0700283 ADD_FAILURE();
Chris Craik6fe991e52015-10-20 09:39:42 -0700284 }
285 });
286 EXPECT_EQ(3, count);
Chris Craikb565df12015-10-05 13:00:52 -0700287}
Chris Craik6fe991e52015-10-20 09:39:42 -0700288
Chris Craikb87eadd2016-01-06 09:16:05 -0800289TEST(RecordingCanvas, saveLayer_missingRestore) {
290 auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
Florin Malitaeecff562015-12-21 10:43:01 -0500291 canvas.saveLayerAlpha(0, 0, 200, 200, 128, SaveFlags::ClipToLayer);
Chris Craikb87eadd2016-01-06 09:16:05 -0800292 canvas.drawRect(0, 0, 200, 200, SkPaint());
293 // Note: restore omitted, shouldn't result in unmatched save
294 });
295 int count = 0;
296 playbackOps(*dl, [&count](const RecordedOp& op) {
297 if (count++ == 2) {
298 EXPECT_EQ(RecordedOpId::EndLayerOp, op.opId);
299 }
300 });
301 EXPECT_EQ(3, count) << "Missing a restore shouldn't result in an unmatched saveLayer";
302}
303
304TEST(RecordingCanvas, saveLayer_simpleUnclipped) {
305 auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
Florin Malitaeecff562015-12-21 10:43:01 -0500306 canvas.saveLayerAlpha(10, 20, 190, 180, 128, (SaveFlags::Flags)0); // unclipped
Chris Craikb87eadd2016-01-06 09:16:05 -0800307 canvas.drawRect(10, 20, 190, 180, SkPaint());
308 canvas.restore();
309 });
310 int count = 0;
311 playbackOps(*dl, [&count](const RecordedOp& op) {
312 switch(count++) {
313 case 0:
314 EXPECT_EQ(RecordedOpId::BeginUnclippedLayerOp, op.opId);
315 EXPECT_EQ(Rect(10, 20, 190, 180), op.unmappedBounds);
316 EXPECT_EQ(nullptr, op.localClip);
317 EXPECT_TRUE(op.localMatrix.isIdentity());
318 break;
319 case 1:
320 EXPECT_EQ(RecordedOpId::RectOp, op.opId);
321 EXPECT_EQ(nullptr, op.localClip);
322 EXPECT_EQ(Rect(10, 20, 190, 180), op.unmappedBounds);
323 EXPECT_TRUE(op.localMatrix.isIdentity());
324 break;
325 case 2:
326 EXPECT_EQ(RecordedOpId::EndUnclippedLayerOp, op.opId);
327 // Don't bother asserting recording state data - it's not used
328 break;
329 default:
330 ADD_FAILURE();
331 }
332 });
333 EXPECT_EQ(3, count);
334}
335
336TEST(RecordingCanvas, saveLayer_addClipFlag) {
337 auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
Florin Malitaeecff562015-12-21 10:43:01 -0500338 canvas.save(SaveFlags::MatrixClip);
Chris Craikb87eadd2016-01-06 09:16:05 -0800339 canvas.clipRect(10, 20, 190, 180, SkRegion::kIntersect_Op);
Florin Malitaeecff562015-12-21 10:43:01 -0500340 canvas.saveLayerAlpha(10, 20, 190, 180, 128, (SaveFlags::Flags)0); // unclipped
Chris Craikb87eadd2016-01-06 09:16:05 -0800341 canvas.drawRect(10, 20, 190, 180, SkPaint());
342 canvas.restore();
343 canvas.restore();
344 });
345 int count = 0;
346 playbackOps(*dl, [&count](const RecordedOp& op) {
347 if (count++ == 0) {
348 EXPECT_EQ(RecordedOpId::BeginLayerOp, op.opId)
349 << "Clip + unclipped saveLayer should result in a clipped layer";
350 }
351 });
352 EXPECT_EQ(3, count);
353}
354
Chris Craika1717272015-11-19 13:02:43 -0800355TEST(RecordingCanvas, saveLayer_viewportCrop) {
Chris Craik6fe991e52015-10-20 09:39:42 -0700356 auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
357 // shouldn't matter, since saveLayer will clip to its bounds
358 canvas.clipRect(-1000, -1000, 1000, 1000, SkRegion::kReplace_Op);
359
Florin Malitaeecff562015-12-21 10:43:01 -0500360 canvas.saveLayerAlpha(100, 100, 300, 300, 128, SaveFlags::ClipToLayer);
Chris Craik6fe991e52015-10-20 09:39:42 -0700361 canvas.drawRect(0, 0, 400, 400, SkPaint());
362 canvas.restore();
363 });
364 int count = 0;
365 playbackOps(*dl, [&count](const RecordedOp& op) {
366 if (count++ == 1) {
367 Matrix4 expectedMatrix;
368 EXPECT_EQ(RecordedOpId::RectOp, op.opId);
Chris Craike4db79d2015-12-22 16:32:23 -0800369 EXPECT_CLIP_RECT(Rect(100, 100), op.localClip) // Recorded clip rect should be
370 // intersection of viewport and saveLayer bounds, in layer space;
Chris Craik5430ab22015-12-10 16:28:16 -0800371 EXPECT_EQ(Rect(400, 400), op.unmappedBounds);
Chris Craik6fe991e52015-10-20 09:39:42 -0700372 expectedMatrix.loadTranslate(-100, -100, 0);
373 EXPECT_MATRIX_APPROX_EQ(expectedMatrix, op.localMatrix);
374 }
375 });
376 EXPECT_EQ(3, count);
Chris Craikb565df12015-10-05 13:00:52 -0700377}
Chris Craik6fe991e52015-10-20 09:39:42 -0700378
Chris Craika1717272015-11-19 13:02:43 -0800379TEST(RecordingCanvas, saveLayer_rotateUnclipped) {
Chris Craik6fe991e52015-10-20 09:39:42 -0700380 auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
Florin Malitaeecff562015-12-21 10:43:01 -0500381 canvas.save(SaveFlags::MatrixClip);
Chris Craik6fe991e52015-10-20 09:39:42 -0700382 canvas.translate(100, 100);
383 canvas.rotate(45);
384 canvas.translate(-50, -50);
385
Florin Malitaeecff562015-12-21 10:43:01 -0500386 canvas.saveLayerAlpha(0, 0, 100, 100, 128, SaveFlags::ClipToLayer);
Chris Craik6fe991e52015-10-20 09:39:42 -0700387 canvas.drawRect(0, 0, 100, 100, SkPaint());
388 canvas.restore();
389
390 canvas.restore();
391 });
392 int count = 0;
393 playbackOps(*dl, [&count](const RecordedOp& op) {
394 if (count++ == 1) {
Chris Craik6fe991e52015-10-20 09:39:42 -0700395 EXPECT_EQ(RecordedOpId::RectOp, op.opId);
Chris Craike4db79d2015-12-22 16:32:23 -0800396 EXPECT_CLIP_RECT(Rect(100, 100), op.localClip);
Chris Craik5430ab22015-12-10 16:28:16 -0800397 EXPECT_EQ(Rect(100, 100), op.unmappedBounds);
Chris Craika6ac95e2015-11-02 18:06:59 -0800398 EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), op.localMatrix)
399 << "Recorded op shouldn't see any canvas transform before the saveLayer";
Chris Craik6fe991e52015-10-20 09:39:42 -0700400 }
401 });
402 EXPECT_EQ(3, count);
403}
404
Chris Craika1717272015-11-19 13:02:43 -0800405TEST(RecordingCanvas, saveLayer_rotateClipped) {
Chris Craik6fe991e52015-10-20 09:39:42 -0700406 auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
Florin Malitaeecff562015-12-21 10:43:01 -0500407 canvas.save(SaveFlags::MatrixClip);
Chris Craik6fe991e52015-10-20 09:39:42 -0700408 canvas.translate(100, 100);
409 canvas.rotate(45);
410 canvas.translate(-200, -200);
411
412 // area of saveLayer will be clipped to parent viewport, so we ask for 400x400...
Florin Malitaeecff562015-12-21 10:43:01 -0500413 canvas.saveLayerAlpha(0, 0, 400, 400, 128, SaveFlags::ClipToLayer);
Chris Craik6fe991e52015-10-20 09:39:42 -0700414 canvas.drawRect(0, 0, 400, 400, SkPaint());
415 canvas.restore();
416
417 canvas.restore();
418 });
419 int count = 0;
420 playbackOps(*dl, [&count](const RecordedOp& op) {
421 if (count++ == 1) {
422 Matrix4 expectedMatrix;
423 EXPECT_EQ(RecordedOpId::RectOp, op.opId);
424
425 // ...and get about 58.6, 58.6, 341.4 341.4, because the bounds are clipped by
426 // the parent 200x200 viewport, but prior to rotation
Chris Craike4db79d2015-12-22 16:32:23 -0800427 ASSERT_NE(nullptr, op.localClip);
428 ASSERT_EQ(ClipMode::Rectangle, op.localClip->mode);
429 // NOTE: this check relies on saveLayer altering the clip post-viewport init. This
430 // causes the clip to be recorded by contained draw commands, though it's not necessary
431 // since the same clip will be computed at draw time. If such a change is made, this
432 // check could be done at record time by querying the clip, or the clip could be altered
433 // slightly so that it is serialized.
434 EXPECT_RECT_APPROX_EQ(Rect(58.57864, 58.57864, 341.42136, 341.42136),
435 (reinterpret_cast<const ClipRect*>(op.localClip))->rect);
436
Chris Craik5430ab22015-12-10 16:28:16 -0800437 EXPECT_EQ(Rect(400, 400), op.unmappedBounds);
Chris Craik6fe991e52015-10-20 09:39:42 -0700438 expectedMatrix.loadIdentity();
439 EXPECT_MATRIX_APPROX_EQ(expectedMatrix, op.localMatrix);
440 }
441 });
442 EXPECT_EQ(3, count);
443}
444
Chris Craik8d1f2122015-11-24 16:40:09 -0800445TEST(RecordingCanvas, drawRenderNode_projection) {
446 sp<RenderNode> background = TestUtils::createNode(50, 50, 150, 150,
447 [](RenderProperties& props, RecordingCanvas& canvas) {
448 SkPaint paint;
449 paint.setColor(SK_ColorWHITE);
450 canvas.drawRect(0, 0, 100, 100, paint);
451 });
452 {
453 background->mutateStagingProperties().setProjectionReceiver(false);
454
455 // NO RECEIVER PRESENT
456 auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200,
457 [&background](RecordingCanvas& canvas) {
458 canvas.drawRect(0, 0, 100, 100, SkPaint());
459 canvas.drawRenderNode(background.get());
460 canvas.drawRect(0, 0, 100, 100, SkPaint());
461 });
462 EXPECT_EQ(-1, dl->projectionReceiveIndex)
463 << "no projection receiver should have been observed";
464 }
465 {
466 background->mutateStagingProperties().setProjectionReceiver(true);
467
468 // RECEIVER PRESENT
469 auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200,
470 [&background](RecordingCanvas& canvas) {
471 canvas.drawRect(0, 0, 100, 100, SkPaint());
472 canvas.drawRenderNode(background.get());
473 canvas.drawRect(0, 0, 100, 100, SkPaint());
474 });
475
476 ASSERT_EQ(3u, dl->getOps().size()) << "Must be three ops";
477 auto op = dl->getOps()[1];
478 EXPECT_EQ(RecordedOpId::RenderNodeOp, op->opId);
479 EXPECT_EQ(1, dl->projectionReceiveIndex)
480 << "correct projection receiver not identified";
481
482 // verify the behavior works even though projection receiver hasn't been sync'd yet
483 EXPECT_TRUE(background->stagingProperties().isProjectionReceiver());
484 EXPECT_FALSE(background->properties().isProjectionReceiver());
485 }
486}
487
Chris Craik7fc1b032016-02-03 19:45:06 -0800488TEST(RecordingCanvas, firstClipWillReplace) {
489 auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
490 canvas.save(SaveFlags::MatrixClip);
491 // since no explicit clip set on canvas, this should be the one observed on op:
492 canvas.clipRect(-100, -100, 300, 300, SkRegion::kIntersect_Op);
493
494 SkPaint paint;
495 paint.setColor(SK_ColorWHITE);
496 canvas.drawRect(0, 0, 100, 100, paint);
497
498 canvas.restore();
499 });
500 ASSERT_EQ(1u, dl->getOps().size()) << "Must have one op";
501 // first clip must be preserved, even if it extends beyond canvas bounds
502 EXPECT_CLIP_RECT(Rect(-100, -100, 300, 300), dl->getOps()[0]->localClip);
503}
504
Chris Craika1717272015-11-19 13:02:43 -0800505TEST(RecordingCanvas, insertReorderBarrier) {
Chris Craik161f54b2015-11-05 11:08:52 -0800506 auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
507 canvas.drawRect(0, 0, 400, 400, SkPaint());
508 canvas.insertReorderBarrier(true);
509 canvas.insertReorderBarrier(false);
510 canvas.insertReorderBarrier(false);
511 canvas.insertReorderBarrier(true);
512 canvas.drawRect(0, 0, 400, 400, SkPaint());
513 canvas.insertReorderBarrier(false);
514 });
515
516 auto chunks = dl->getChunks();
517 EXPECT_EQ(0u, chunks[0].beginOpIndex);
518 EXPECT_EQ(1u, chunks[0].endOpIndex);
519 EXPECT_FALSE(chunks[0].reorderChildren);
520
521 EXPECT_EQ(1u, chunks[1].beginOpIndex);
522 EXPECT_EQ(2u, chunks[1].endOpIndex);
523 EXPECT_TRUE(chunks[1].reorderChildren);
524}
525
Chris Craik42a54072015-11-24 11:41:54 -0800526TEST(RecordingCanvas, refPaint) {
527 SkPaint paint;
528 paint.setAntiAlias(true);
529 paint.setTextSize(20);
530 paint.setTextAlign(SkPaint::kLeft_Align);
531 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
532
533 auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [&paint](RecordingCanvas& canvas) {
534 paint.setColor(SK_ColorBLUE);
535 // first three should use same paint
536 canvas.drawRect(0, 0, 200, 10, paint);
537 SkPaint paintCopy(paint);
538 canvas.drawRect(0, 10, 200, 20, paintCopy);
539 TestUtils::drawTextToCanvas(&canvas, "helloworld", paint, 50, 25);
540
541 // only here do we use different paint ptr
542 paint.setColor(SK_ColorRED);
543 canvas.drawRect(0, 20, 200, 30, paint);
544 });
545 auto ops = dl->getOps();
546 ASSERT_EQ(4u, ops.size());
547
548 // first three are the same
549 EXPECT_NE(nullptr, ops[0]->paint);
550 EXPECT_NE(&paint, ops[0]->paint);
551 EXPECT_EQ(ops[0]->paint, ops[1]->paint);
552 EXPECT_EQ(ops[0]->paint, ops[2]->paint);
553
554 // last is different, but still copied / non-null
555 EXPECT_NE(nullptr, ops[3]->paint);
556 EXPECT_NE(ops[0]->paint, ops[3]->paint);
557 EXPECT_NE(&paint, ops[3]->paint);
558}
559
Chris Craik6fe991e52015-10-20 09:39:42 -0700560} // namespace uirenderer
561} // namespace android