blob: c39047ca1d89484881a0302676584c090494fc57 [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 Craik261725f2016-02-29 12:52:33 -080061TEST(RecordingCanvas, emptyClipRect) {
62 auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
63 canvas.save(SaveFlags::MatrixClip);
64 canvas.clipRect(0, 0, 100, 100, SkRegion::kIntersect_Op);
65 canvas.clipRect(100, 100, 200, 200, SkRegion::kIntersect_Op);
66 canvas.drawRect(0, 0, 50, 50, SkPaint()); // rejected at record time
67 canvas.restore();
68 });
69 ASSERT_EQ(0u, dl->getOps().size()) << "Must be zero ops. Rect should be rejected.";
70}
71
Chris Craikcaa24182016-02-19 15:20:35 -080072TEST(RecordingCanvas, drawArc) {
73 auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
74 canvas.drawArc(0, 0, 200, 200, 0, 180, true, SkPaint());
75 canvas.drawArc(0, 0, 100, 100, 0, 360, true, SkPaint());
76 });
77
78 auto&& ops = dl->getOps();
79 ASSERT_EQ(2u, ops.size()) << "Must be exactly two ops";
80 EXPECT_EQ(RecordedOpId::ArcOp, ops[0]->opId);
81 EXPECT_EQ(Rect(200, 200), ops[0]->unmappedBounds);
82
83 EXPECT_EQ(RecordedOpId::OvalOp, ops[1]->opId)
84 << "Circular arcs should be converted to ovals";
85 EXPECT_EQ(Rect(100, 100), ops[1]->unmappedBounds);
86}
87
Chris Craika1717272015-11-19 13:02:43 -080088TEST(RecordingCanvas, drawLines) {
89 auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) {
90 SkPaint paint;
Chris Craik386aa032015-12-07 17:08:25 -080091 paint.setStrokeWidth(20); // doesn't affect recorded bounds - would be resolved at bake time
Chris Craika1717272015-11-19 13:02:43 -080092 float points[] = { 0, 0, 20, 10, 30, 40, 90 }; // NB: only 1 valid line
93 canvas.drawLines(&points[0], 7, paint);
94 });
95
96 ASSERT_EQ(1u, dl->getOps().size()) << "Must be exactly one op";
97 auto op = dl->getOps()[0];
98 ASSERT_EQ(RecordedOpId::LinesOp, op->opId);
99 EXPECT_EQ(4, ((LinesOp*)op)->floatCount)
100 << "float count must be rounded down to closest multiple of 4";
Chris Craik5430ab22015-12-10 16:28:16 -0800101 EXPECT_EQ(Rect(20, 10), op->unmappedBounds)
Chris Craik386aa032015-12-07 17:08:25 -0800102 << "unmapped bounds must be size of line, and not outset for stroke width";
Chris Craika1717272015-11-19 13:02:43 -0800103}
104
105TEST(RecordingCanvas, drawRect) {
Chris Craikb36af872015-10-16 14:23:12 -0700106 auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) {
Chris Craikb565df12015-10-05 13:00:52 -0700107 canvas.drawRect(10, 20, 90, 180, SkPaint());
108 });
109
Chris Craika1717272015-11-19 13:02:43 -0800110 ASSERT_EQ(1u, dl->getOps().size()) << "Must be exactly one op";
111 auto op = *(dl->getOps()[0]);
112 ASSERT_EQ(RecordedOpId::RectOp, op.opId);
Chris Craike4db79d2015-12-22 16:32:23 -0800113 EXPECT_EQ(nullptr, op.localClip);
Chris Craika1717272015-11-19 13:02:43 -0800114 EXPECT_EQ(Rect(10, 20, 90, 180), op.unmappedBounds);
115}
116
117TEST(RecordingCanvas, drawText) {
118 auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
119 SkPaint paint;
120 paint.setAntiAlias(true);
121 paint.setTextSize(20);
Chris Craik42a54072015-11-24 11:41:54 -0800122 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
Chris Craika1717272015-11-19 13:02:43 -0800123 TestUtils::drawTextToCanvas(&canvas, "test text", paint, 25, 25);
124 });
125
Chris Craikb565df12015-10-05 13:00:52 -0700126 int count = 0;
Chris Craikb36af872015-10-16 14:23:12 -0700127 playbackOps(*dl, [&count](const RecordedOp& op) {
Chris Craikb565df12015-10-05 13:00:52 -0700128 count++;
Chris Craika1717272015-11-19 13:02:43 -0800129 ASSERT_EQ(RecordedOpId::TextOp, op.opId);
Chris Craike4db79d2015-12-22 16:32:23 -0800130 EXPECT_EQ(nullptr, op.localClip);
Chris Craika1717272015-11-19 13:02:43 -0800131 EXPECT_TRUE(op.localMatrix.isIdentity());
132 EXPECT_TRUE(op.unmappedBounds.contains(25, 15, 50, 25))
133 << "Op expected to be 25+ pixels wide, 10+ pixels tall";
Chris Craikb565df12015-10-05 13:00:52 -0700134 });
Chris Craika6ac95e2015-11-02 18:06:59 -0800135 ASSERT_EQ(1, count);
Chris Craikb565df12015-10-05 13:00:52 -0700136}
137
Chris Craika1717272015-11-19 13:02:43 -0800138TEST(RecordingCanvas, drawText_strikeThruAndUnderline) {
139 auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
140 SkPaint paint;
141 paint.setAntiAlias(true);
142 paint.setTextSize(20);
Chris Craik42a54072015-11-24 11:41:54 -0800143 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
Chris Craika1717272015-11-19 13:02:43 -0800144 for (int i = 0; i < 2; i++) {
145 for (int j = 0; j < 2; j++) {
146 paint.setUnderlineText(i != 0);
147 paint.setStrikeThruText(j != 0);
148 TestUtils::drawTextToCanvas(&canvas, "test text", paint, 25, 25);
149 }
150 }
151 });
152
153 auto ops = dl->getOps();
154 ASSERT_EQ(8u, ops.size());
155
156 int index = 0;
157 EXPECT_EQ(RecordedOpId::TextOp, ops[index++]->opId); // no underline or strikethrough
158
159 EXPECT_EQ(RecordedOpId::TextOp, ops[index++]->opId);
160 EXPECT_EQ(RecordedOpId::RectOp, ops[index++]->opId); // strikethrough only
161
162 EXPECT_EQ(RecordedOpId::TextOp, ops[index++]->opId);
163 EXPECT_EQ(RecordedOpId::RectOp, ops[index++]->opId); // underline only
164
165 EXPECT_EQ(RecordedOpId::TextOp, ops[index++]->opId);
166 EXPECT_EQ(RecordedOpId::RectOp, ops[index++]->opId); // underline
167 EXPECT_EQ(RecordedOpId::RectOp, ops[index++]->opId); // strikethrough
168}
169
170TEST(RecordingCanvas, drawText_forceAlignLeft) {
171 auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
172 SkPaint paint;
173 paint.setAntiAlias(true);
174 paint.setTextSize(20);
Chris Craik42a54072015-11-24 11:41:54 -0800175 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
Chris Craika1717272015-11-19 13:02:43 -0800176 paint.setTextAlign(SkPaint::kLeft_Align);
177 TestUtils::drawTextToCanvas(&canvas, "test text", paint, 25, 25);
178 paint.setTextAlign(SkPaint::kCenter_Align);
179 TestUtils::drawTextToCanvas(&canvas, "test text", paint, 25, 25);
180 paint.setTextAlign(SkPaint::kRight_Align);
181 TestUtils::drawTextToCanvas(&canvas, "test text", paint, 25, 25);
182 });
183
184 int count = 0;
Chris Craik42a54072015-11-24 11:41:54 -0800185 float lastX = FLT_MAX;
186 playbackOps(*dl, [&count, &lastX](const RecordedOp& op) {
Chris Craika1717272015-11-19 13:02:43 -0800187 count++;
188 ASSERT_EQ(RecordedOpId::TextOp, op.opId);
189 EXPECT_EQ(SkPaint::kLeft_Align, op.paint->getTextAlign())
190 << "recorded drawText commands must force kLeft_Align on their paint";
Chris Craik42a54072015-11-24 11:41:54 -0800191
192 // verify TestUtils alignment offsetting (TODO: move asserts to Canvas base class)
193 EXPECT_GT(lastX, ((const TextOp&)op).x)
194 << "x coordinate should reduce across each of the draw commands, from alignment";
195 lastX = ((const TextOp&)op).x;
Chris Craika1717272015-11-19 13:02:43 -0800196 });
197 ASSERT_EQ(3, count);
198}
199
Chris Craik1713c772016-02-18 17:49:44 -0800200TEST(RecordingCanvas, drawColor) {
201 auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
202 canvas.drawColor(Color::Black, SkXfermode::kSrcOver_Mode);
203 });
204
205 ASSERT_EQ(1u, dl->getOps().size()) << "Must be exactly one op";
206 auto op = *(dl->getOps()[0]);
207 EXPECT_EQ(RecordedOpId::RectOp, op.opId);
208 EXPECT_EQ(nullptr, op.localClip);
209 EXPECT_TRUE(op.unmappedBounds.contains(Rect(-1000, -1000, 1000, 1000)))
210 << "no clip, unmappedBounds should resolve to be much larger than DL bounds";
211}
212
Chris Craikb565df12015-10-05 13:00:52 -0700213TEST(RecordingCanvas, backgroundAndImage) {
Chris Craikb36af872015-10-16 14:23:12 -0700214 auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) {
Chris Craikb565df12015-10-05 13:00:52 -0700215 SkBitmap bitmap;
216 bitmap.setInfo(SkImageInfo::MakeUnknown(25, 25));
217 SkPaint paint;
218 paint.setColor(SK_ColorBLUE);
219
Florin Malitaeecff562015-12-21 10:43:01 -0500220 canvas.save(SaveFlags::MatrixClip);
Chris Craikb565df12015-10-05 13:00:52 -0700221 {
222 // a background!
Florin Malitaeecff562015-12-21 10:43:01 -0500223 canvas.save(SaveFlags::MatrixClip);
Chris Craikb565df12015-10-05 13:00:52 -0700224 canvas.drawRect(0, 0, 100, 200, paint);
225 canvas.restore();
226 }
227 {
228 // an image!
Florin Malitaeecff562015-12-21 10:43:01 -0500229 canvas.save(SaveFlags::MatrixClip);
Chris Craikb565df12015-10-05 13:00:52 -0700230 canvas.translate(25, 25);
231 canvas.scale(2, 2);
232 canvas.drawBitmap(bitmap, 0, 0, nullptr);
233 canvas.restore();
234 }
235 canvas.restore();
236 });
237
238 int count = 0;
Chris Craikb36af872015-10-16 14:23:12 -0700239 playbackOps(*dl, [&count](const RecordedOp& op) {
Chris Craikb565df12015-10-05 13:00:52 -0700240 if (count == 0) {
241 ASSERT_EQ(RecordedOpId::RectOp, op.opId);
242 ASSERT_NE(nullptr, op.paint);
243 EXPECT_EQ(SK_ColorBLUE, op.paint->getColor());
Chris Craik5430ab22015-12-10 16:28:16 -0800244 EXPECT_EQ(Rect(100, 200), op.unmappedBounds);
Chris Craike4db79d2015-12-22 16:32:23 -0800245 EXPECT_EQ(nullptr, op.localClip);
Chris Craikb565df12015-10-05 13:00:52 -0700246
247 Matrix4 expectedMatrix;
248 expectedMatrix.loadIdentity();
249 EXPECT_MATRIX_APPROX_EQ(expectedMatrix, op.localMatrix);
250 } else {
251 ASSERT_EQ(RecordedOpId::BitmapOp, op.opId);
252 EXPECT_EQ(nullptr, op.paint);
Chris Craik5430ab22015-12-10 16:28:16 -0800253 EXPECT_EQ(Rect(25, 25), op.unmappedBounds);
Chris Craike4db79d2015-12-22 16:32:23 -0800254 EXPECT_EQ(nullptr, op.localClip);
Chris Craikb565df12015-10-05 13:00:52 -0700255
256 Matrix4 expectedMatrix;
257 expectedMatrix.loadTranslate(25, 25, 0);
258 expectedMatrix.scale(2, 2, 1);
259 EXPECT_MATRIX_APPROX_EQ(expectedMatrix, op.localMatrix);
260 }
261 count++;
262 });
Chris Craika6ac95e2015-11-02 18:06:59 -0800263 ASSERT_EQ(2, count);
Chris Craikb565df12015-10-05 13:00:52 -0700264}
265
Chris Craika1717272015-11-19 13:02:43 -0800266TEST(RecordingCanvas, saveLayer_simple) {
Chris Craik6fe991e52015-10-20 09:39:42 -0700267 auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
Florin Malitaeecff562015-12-21 10:43:01 -0500268 canvas.saveLayerAlpha(10, 20, 190, 180, 128, SaveFlags::ClipToLayer);
Chris Craik6fe991e52015-10-20 09:39:42 -0700269 canvas.drawRect(10, 20, 190, 180, SkPaint());
270 canvas.restore();
271 });
272 int count = 0;
273 playbackOps(*dl, [&count](const RecordedOp& op) {
274 Matrix4 expectedMatrix;
275 switch(count++) {
276 case 0:
277 EXPECT_EQ(RecordedOpId::BeginLayerOp, op.opId);
Chris Craika6ac95e2015-11-02 18:06:59 -0800278 EXPECT_EQ(Rect(10, 20, 190, 180), op.unmappedBounds);
Chris Craike4db79d2015-12-22 16:32:23 -0800279 EXPECT_EQ(nullptr, op.localClip);
Chris Craika6ac95e2015-11-02 18:06:59 -0800280 EXPECT_TRUE(op.localMatrix.isIdentity());
Chris Craik6fe991e52015-10-20 09:39:42 -0700281 break;
282 case 1:
283 EXPECT_EQ(RecordedOpId::RectOp, op.opId);
Chris Craike4db79d2015-12-22 16:32:23 -0800284 EXPECT_CLIP_RECT(Rect(180, 160), op.localClip);
Chris Craik6fe991e52015-10-20 09:39:42 -0700285 EXPECT_EQ(Rect(10, 20, 190, 180), op.unmappedBounds);
286 expectedMatrix.loadTranslate(-10, -20, 0);
287 EXPECT_MATRIX_APPROX_EQ(expectedMatrix, op.localMatrix);
288 break;
289 case 2:
290 EXPECT_EQ(RecordedOpId::EndLayerOp, op.opId);
Chris Craika6ac95e2015-11-02 18:06:59 -0800291 // Don't bother asserting recording state data - it's not used
Chris Craik6fe991e52015-10-20 09:39:42 -0700292 break;
293 default:
Chris Craik818c9fb2015-10-23 14:33:42 -0700294 ADD_FAILURE();
Chris Craik6fe991e52015-10-20 09:39:42 -0700295 }
296 });
297 EXPECT_EQ(3, count);
Chris Craikb565df12015-10-05 13:00:52 -0700298}
Chris Craik6fe991e52015-10-20 09:39:42 -0700299
Chris Craikb87eadd2016-01-06 09:16:05 -0800300TEST(RecordingCanvas, saveLayer_missingRestore) {
301 auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
Florin Malitaeecff562015-12-21 10:43:01 -0500302 canvas.saveLayerAlpha(0, 0, 200, 200, 128, SaveFlags::ClipToLayer);
Chris Craikb87eadd2016-01-06 09:16:05 -0800303 canvas.drawRect(0, 0, 200, 200, SkPaint());
304 // Note: restore omitted, shouldn't result in unmatched save
305 });
306 int count = 0;
307 playbackOps(*dl, [&count](const RecordedOp& op) {
308 if (count++ == 2) {
309 EXPECT_EQ(RecordedOpId::EndLayerOp, op.opId);
310 }
311 });
312 EXPECT_EQ(3, count) << "Missing a restore shouldn't result in an unmatched saveLayer";
313}
314
315TEST(RecordingCanvas, saveLayer_simpleUnclipped) {
316 auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
Florin Malitaeecff562015-12-21 10:43:01 -0500317 canvas.saveLayerAlpha(10, 20, 190, 180, 128, (SaveFlags::Flags)0); // unclipped
Chris Craikb87eadd2016-01-06 09:16:05 -0800318 canvas.drawRect(10, 20, 190, 180, SkPaint());
319 canvas.restore();
320 });
321 int count = 0;
322 playbackOps(*dl, [&count](const RecordedOp& op) {
323 switch(count++) {
324 case 0:
325 EXPECT_EQ(RecordedOpId::BeginUnclippedLayerOp, op.opId);
326 EXPECT_EQ(Rect(10, 20, 190, 180), op.unmappedBounds);
327 EXPECT_EQ(nullptr, op.localClip);
328 EXPECT_TRUE(op.localMatrix.isIdentity());
329 break;
330 case 1:
331 EXPECT_EQ(RecordedOpId::RectOp, op.opId);
332 EXPECT_EQ(nullptr, op.localClip);
333 EXPECT_EQ(Rect(10, 20, 190, 180), op.unmappedBounds);
334 EXPECT_TRUE(op.localMatrix.isIdentity());
335 break;
336 case 2:
337 EXPECT_EQ(RecordedOpId::EndUnclippedLayerOp, op.opId);
338 // Don't bother asserting recording state data - it's not used
339 break;
340 default:
341 ADD_FAILURE();
342 }
343 });
344 EXPECT_EQ(3, count);
345}
346
347TEST(RecordingCanvas, saveLayer_addClipFlag) {
348 auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
Florin Malitaeecff562015-12-21 10:43:01 -0500349 canvas.save(SaveFlags::MatrixClip);
Chris Craikb87eadd2016-01-06 09:16:05 -0800350 canvas.clipRect(10, 20, 190, 180, SkRegion::kIntersect_Op);
Florin Malitaeecff562015-12-21 10:43:01 -0500351 canvas.saveLayerAlpha(10, 20, 190, 180, 128, (SaveFlags::Flags)0); // unclipped
Chris Craikb87eadd2016-01-06 09:16:05 -0800352 canvas.drawRect(10, 20, 190, 180, SkPaint());
353 canvas.restore();
354 canvas.restore();
355 });
356 int count = 0;
357 playbackOps(*dl, [&count](const RecordedOp& op) {
358 if (count++ == 0) {
359 EXPECT_EQ(RecordedOpId::BeginLayerOp, op.opId)
360 << "Clip + unclipped saveLayer should result in a clipped layer";
361 }
362 });
363 EXPECT_EQ(3, count);
364}
365
Chris Craika1717272015-11-19 13:02:43 -0800366TEST(RecordingCanvas, saveLayer_viewportCrop) {
Chris Craik6fe991e52015-10-20 09:39:42 -0700367 auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
368 // shouldn't matter, since saveLayer will clip to its bounds
369 canvas.clipRect(-1000, -1000, 1000, 1000, SkRegion::kReplace_Op);
370
Florin Malitaeecff562015-12-21 10:43:01 -0500371 canvas.saveLayerAlpha(100, 100, 300, 300, 128, SaveFlags::ClipToLayer);
Chris Craik6fe991e52015-10-20 09:39:42 -0700372 canvas.drawRect(0, 0, 400, 400, SkPaint());
373 canvas.restore();
374 });
375 int count = 0;
376 playbackOps(*dl, [&count](const RecordedOp& op) {
377 if (count++ == 1) {
378 Matrix4 expectedMatrix;
379 EXPECT_EQ(RecordedOpId::RectOp, op.opId);
Chris Craike4db79d2015-12-22 16:32:23 -0800380 EXPECT_CLIP_RECT(Rect(100, 100), op.localClip) // Recorded clip rect should be
381 // intersection of viewport and saveLayer bounds, in layer space;
Chris Craik5430ab22015-12-10 16:28:16 -0800382 EXPECT_EQ(Rect(400, 400), op.unmappedBounds);
Chris Craik6fe991e52015-10-20 09:39:42 -0700383 expectedMatrix.loadTranslate(-100, -100, 0);
384 EXPECT_MATRIX_APPROX_EQ(expectedMatrix, op.localMatrix);
385 }
386 });
387 EXPECT_EQ(3, count);
Chris Craikb565df12015-10-05 13:00:52 -0700388}
Chris Craik6fe991e52015-10-20 09:39:42 -0700389
Chris Craika1717272015-11-19 13:02:43 -0800390TEST(RecordingCanvas, saveLayer_rotateUnclipped) {
Chris Craik6fe991e52015-10-20 09:39:42 -0700391 auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
Florin Malitaeecff562015-12-21 10:43:01 -0500392 canvas.save(SaveFlags::MatrixClip);
Chris Craik6fe991e52015-10-20 09:39:42 -0700393 canvas.translate(100, 100);
394 canvas.rotate(45);
395 canvas.translate(-50, -50);
396
Florin Malitaeecff562015-12-21 10:43:01 -0500397 canvas.saveLayerAlpha(0, 0, 100, 100, 128, SaveFlags::ClipToLayer);
Chris Craik6fe991e52015-10-20 09:39:42 -0700398 canvas.drawRect(0, 0, 100, 100, SkPaint());
399 canvas.restore();
400
401 canvas.restore();
402 });
403 int count = 0;
404 playbackOps(*dl, [&count](const RecordedOp& op) {
405 if (count++ == 1) {
Chris Craik6fe991e52015-10-20 09:39:42 -0700406 EXPECT_EQ(RecordedOpId::RectOp, op.opId);
Chris Craike4db79d2015-12-22 16:32:23 -0800407 EXPECT_CLIP_RECT(Rect(100, 100), op.localClip);
Chris Craik5430ab22015-12-10 16:28:16 -0800408 EXPECT_EQ(Rect(100, 100), op.unmappedBounds);
Chris Craika6ac95e2015-11-02 18:06:59 -0800409 EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), op.localMatrix)
410 << "Recorded op shouldn't see any canvas transform before the saveLayer";
Chris Craik6fe991e52015-10-20 09:39:42 -0700411 }
412 });
413 EXPECT_EQ(3, count);
414}
415
Chris Craika1717272015-11-19 13:02:43 -0800416TEST(RecordingCanvas, saveLayer_rotateClipped) {
Chris Craik6fe991e52015-10-20 09:39:42 -0700417 auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
Florin Malitaeecff562015-12-21 10:43:01 -0500418 canvas.save(SaveFlags::MatrixClip);
Chris Craik6fe991e52015-10-20 09:39:42 -0700419 canvas.translate(100, 100);
420 canvas.rotate(45);
421 canvas.translate(-200, -200);
422
423 // area of saveLayer will be clipped to parent viewport, so we ask for 400x400...
Florin Malitaeecff562015-12-21 10:43:01 -0500424 canvas.saveLayerAlpha(0, 0, 400, 400, 128, SaveFlags::ClipToLayer);
Chris Craik6fe991e52015-10-20 09:39:42 -0700425 canvas.drawRect(0, 0, 400, 400, SkPaint());
426 canvas.restore();
427
428 canvas.restore();
429 });
430 int count = 0;
431 playbackOps(*dl, [&count](const RecordedOp& op) {
432 if (count++ == 1) {
433 Matrix4 expectedMatrix;
434 EXPECT_EQ(RecordedOpId::RectOp, op.opId);
435
436 // ...and get about 58.6, 58.6, 341.4 341.4, because the bounds are clipped by
437 // the parent 200x200 viewport, but prior to rotation
Chris Craike4db79d2015-12-22 16:32:23 -0800438 ASSERT_NE(nullptr, op.localClip);
439 ASSERT_EQ(ClipMode::Rectangle, op.localClip->mode);
440 // NOTE: this check relies on saveLayer altering the clip post-viewport init. This
441 // causes the clip to be recorded by contained draw commands, though it's not necessary
442 // since the same clip will be computed at draw time. If such a change is made, this
443 // check could be done at record time by querying the clip, or the clip could be altered
444 // slightly so that it is serialized.
445 EXPECT_RECT_APPROX_EQ(Rect(58.57864, 58.57864, 341.42136, 341.42136),
446 (reinterpret_cast<const ClipRect*>(op.localClip))->rect);
447
Chris Craik5430ab22015-12-10 16:28:16 -0800448 EXPECT_EQ(Rect(400, 400), op.unmappedBounds);
Chris Craik6fe991e52015-10-20 09:39:42 -0700449 expectedMatrix.loadIdentity();
450 EXPECT_MATRIX_APPROX_EQ(expectedMatrix, op.localMatrix);
451 }
452 });
453 EXPECT_EQ(3, count);
454}
455
Chris Craik8d1f2122015-11-24 16:40:09 -0800456TEST(RecordingCanvas, drawRenderNode_projection) {
457 sp<RenderNode> background = TestUtils::createNode(50, 50, 150, 150,
458 [](RenderProperties& props, RecordingCanvas& canvas) {
459 SkPaint paint;
460 paint.setColor(SK_ColorWHITE);
461 canvas.drawRect(0, 0, 100, 100, paint);
462 });
463 {
464 background->mutateStagingProperties().setProjectionReceiver(false);
465
466 // NO RECEIVER PRESENT
467 auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200,
468 [&background](RecordingCanvas& canvas) {
469 canvas.drawRect(0, 0, 100, 100, SkPaint());
470 canvas.drawRenderNode(background.get());
471 canvas.drawRect(0, 0, 100, 100, SkPaint());
472 });
473 EXPECT_EQ(-1, dl->projectionReceiveIndex)
474 << "no projection receiver should have been observed";
475 }
476 {
477 background->mutateStagingProperties().setProjectionReceiver(true);
478
479 // RECEIVER PRESENT
480 auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200,
481 [&background](RecordingCanvas& canvas) {
482 canvas.drawRect(0, 0, 100, 100, SkPaint());
483 canvas.drawRenderNode(background.get());
484 canvas.drawRect(0, 0, 100, 100, SkPaint());
485 });
486
487 ASSERT_EQ(3u, dl->getOps().size()) << "Must be three ops";
488 auto op = dl->getOps()[1];
489 EXPECT_EQ(RecordedOpId::RenderNodeOp, op->opId);
490 EXPECT_EQ(1, dl->projectionReceiveIndex)
491 << "correct projection receiver not identified";
492
493 // verify the behavior works even though projection receiver hasn't been sync'd yet
494 EXPECT_TRUE(background->stagingProperties().isProjectionReceiver());
495 EXPECT_FALSE(background->properties().isProjectionReceiver());
496 }
497}
498
Chris Craik7fc1b032016-02-03 19:45:06 -0800499TEST(RecordingCanvas, firstClipWillReplace) {
500 auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
501 canvas.save(SaveFlags::MatrixClip);
502 // since no explicit clip set on canvas, this should be the one observed on op:
503 canvas.clipRect(-100, -100, 300, 300, SkRegion::kIntersect_Op);
504
505 SkPaint paint;
506 paint.setColor(SK_ColorWHITE);
507 canvas.drawRect(0, 0, 100, 100, paint);
508
509 canvas.restore();
510 });
511 ASSERT_EQ(1u, dl->getOps().size()) << "Must have one op";
512 // first clip must be preserved, even if it extends beyond canvas bounds
513 EXPECT_CLIP_RECT(Rect(-100, -100, 300, 300), dl->getOps()[0]->localClip);
514}
515
Chris Craika1717272015-11-19 13:02:43 -0800516TEST(RecordingCanvas, insertReorderBarrier) {
Chris Craik161f54b2015-11-05 11:08:52 -0800517 auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
518 canvas.drawRect(0, 0, 400, 400, SkPaint());
519 canvas.insertReorderBarrier(true);
520 canvas.insertReorderBarrier(false);
521 canvas.insertReorderBarrier(false);
522 canvas.insertReorderBarrier(true);
523 canvas.drawRect(0, 0, 400, 400, SkPaint());
524 canvas.insertReorderBarrier(false);
525 });
526
527 auto chunks = dl->getChunks();
528 EXPECT_EQ(0u, chunks[0].beginOpIndex);
529 EXPECT_EQ(1u, chunks[0].endOpIndex);
530 EXPECT_FALSE(chunks[0].reorderChildren);
531
532 EXPECT_EQ(1u, chunks[1].beginOpIndex);
533 EXPECT_EQ(2u, chunks[1].endOpIndex);
534 EXPECT_TRUE(chunks[1].reorderChildren);
535}
536
Chris Craik42a54072015-11-24 11:41:54 -0800537TEST(RecordingCanvas, refPaint) {
538 SkPaint paint;
539 paint.setAntiAlias(true);
540 paint.setTextSize(20);
541 paint.setTextAlign(SkPaint::kLeft_Align);
542 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
543
544 auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [&paint](RecordingCanvas& canvas) {
545 paint.setColor(SK_ColorBLUE);
546 // first three should use same paint
547 canvas.drawRect(0, 0, 200, 10, paint);
548 SkPaint paintCopy(paint);
549 canvas.drawRect(0, 10, 200, 20, paintCopy);
550 TestUtils::drawTextToCanvas(&canvas, "helloworld", paint, 50, 25);
551
552 // only here do we use different paint ptr
553 paint.setColor(SK_ColorRED);
554 canvas.drawRect(0, 20, 200, 30, paint);
555 });
556 auto ops = dl->getOps();
557 ASSERT_EQ(4u, ops.size());
558
559 // first three are the same
560 EXPECT_NE(nullptr, ops[0]->paint);
561 EXPECT_NE(&paint, ops[0]->paint);
562 EXPECT_EQ(ops[0]->paint, ops[1]->paint);
563 EXPECT_EQ(ops[0]->paint, ops[2]->paint);
564
565 // last is different, but still copied / non-null
566 EXPECT_NE(nullptr, ops[3]->paint);
567 EXPECT_NE(ops[0]->paint, ops[3]->paint);
568 EXPECT_NE(&paint, ops[3]->paint);
569}
570
Chris Craik6fe991e52015-10-20 09:39:42 -0700571} // namespace uirenderer
572} // namespace android