blob: f10948231123a4b8eae6c8b449fb73c7fd6c52ff [file] [log] [blame]
scroggo@google.comd614c6a2012-09-14 17:26:37 +00001/*
2 * Copyright 2012 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 */
tfarina@chromium.orge4fafb12013-12-12 21:11:12 +00007
mtklein3e8232b2014-08-18 13:39:11 -07008#include "SkBBoxHierarchy.h"
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +00009#include "SkBlurImageFilter.h"
reed@google.com21b519d2012-10-02 17:42:15 +000010#include "SkCanvas.h"
robertphillipsd8aa7b72014-10-30 16:45:02 -070011#include "SkColorMatrixFilter.h"
reed@google.comfe7b1ed2012-11-29 21:00:39 +000012#include "SkColorPriv.h"
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +000013#include "SkDashPathEffect.h"
reed@google.comfe7b1ed2012-11-29 21:00:39 +000014#include "SkData.h"
reed5965c8a2015-01-07 18:04:45 -080015#include "SkImageGenerator.h"
scroggo@google.com49ce11b2013-04-25 18:29:32 +000016#include "SkError.h"
halcanary@google.com3d50ea12014-01-02 13:15:13 +000017#include "SkImageEncoder.h"
18#include "SkImageGenerator.h"
robertphillips82365912014-11-12 09:32:34 -080019#include "SkLayerInfo.h"
msarett8715d472016-02-17 10:02:29 -080020#include "SkMD5.h"
reed@google.com21b519d2012-10-02 17:42:15 +000021#include "SkPaint.h"
scroggo@google.comd614c6a2012-09-14 17:26:37 +000022#include "SkPicture.h"
fmalita796e3652016-05-13 11:40:07 -070023#include "SkPictureAnalyzer.h"
robertphillips@google.com770963f2014-04-18 18:04:41 +000024#include "SkPictureRecorder.h"
robertphillips@google.com1f2f3382013-08-29 11:54:56 +000025#include "SkPictureUtils.h"
mtkleind72094d2014-08-27 12:12:23 -070026#include "SkPixelRef.h"
scroggo895c43b2014-12-11 10:53:58 -080027#include "SkPixelSerializer.h"
mtklein9db912c2015-05-19 11:11:26 -070028#include "SkMiniRecorder.h"
reed@google.com72aa79c2013-01-24 18:27:42 +000029#include "SkRRect.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000030#include "SkRandom.h"
tomhudson158fcaa2014-11-19 10:41:14 -080031#include "SkRecord.h"
reed@google.comfe7b1ed2012-11-29 21:00:39 +000032#include "SkShader.h"
scroggo@google.comd614c6a2012-09-14 17:26:37 +000033#include "SkStream.h"
robertphillips3e5c2b12015-03-23 05:46:51 -070034#include "sk_tool_utils.h"
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +000035
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000036#include "Test.h"
scroggo@google.comd614c6a2012-09-14 17:26:37 +000037
reed@google.com47b679b2014-05-14 18:58:16 +000038#include "SkLumaColorFilter.h"
39#include "SkColorFilterImageFilter.h"
40
reed@google.comfe7b1ed2012-11-29 21:00:39 +000041static void make_bm(SkBitmap* bm, int w, int h, SkColor color, bool immutable) {
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +000042 bm->allocN32Pixels(w, h);
reed@google.comfe7b1ed2012-11-29 21:00:39 +000043 bm->eraseColor(color);
44 if (immutable) {
45 bm->setImmutable();
46 }
47}
48
mtkleina16af212015-08-26 08:14:52 -070049// For a while willPlayBackBitmaps() ignored SkImages and just looked for SkBitmaps.
50static void test_images_are_found_by_willPlayBackBitmaps(skiatest::Reporter* reporter) {
reede3b38ce2016-01-08 09:18:44 -080051 // We just need _some_ SkImage
52 const SkPMColor pixel = 0;
53 const SkImageInfo info = SkImageInfo::MakeN32Premul(1, 1);
reed9ce9d672016-03-17 10:51:11 -070054 sk_sp<SkImage> image(SkImage::MakeRasterCopy(SkPixmap(info, &pixel, sizeof(pixel))));
mtkleina16af212015-08-26 08:14:52 -070055
56 SkPictureRecorder recorder;
reede3b38ce2016-01-08 09:18:44 -080057 recorder.beginRecording(100,100)->drawImage(image, 0,0);
reedca2622b2016-03-18 07:25:55 -070058 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
mtkleina16af212015-08-26 08:14:52 -070059
60 REPORTER_ASSERT(reporter, picture->willPlayBackBitmaps());
61}
62
tomhudson3a0f2792014-08-20 05:29:41 -070063/* Hit a few SkPicture::Analysis cases not handled elsewhere. */
mtklein8e126562014-10-01 09:29:35 -070064static void test_analysis(skiatest::Reporter* reporter) {
tomhudson3a0f2792014-08-20 05:29:41 -070065 SkPictureRecorder recorder;
66
mtklein8e126562014-10-01 09:29:35 -070067 SkCanvas* canvas = recorder.beginRecording(100, 100);
tomhudson3a0f2792014-08-20 05:29:41 -070068 {
69 canvas->drawRect(SkRect::MakeWH(10, 10), SkPaint ());
70 }
reedca2622b2016-03-18 07:25:55 -070071 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
tomhudson3a0f2792014-08-20 05:29:41 -070072 REPORTER_ASSERT(reporter, !picture->willPlayBackBitmaps());
73
mtklein8e126562014-10-01 09:29:35 -070074 canvas = recorder.beginRecording(100, 100);
tomhudson3a0f2792014-08-20 05:29:41 -070075 {
76 SkPaint paint;
77 // CreateBitmapShader is too smart for us; an empty (or 1x1) bitmap shader
78 // gets optimized into a non-bitmap form, so we create a 2x2 bitmap here.
79 SkBitmap bitmap;
80 bitmap.allocPixels(SkImageInfo::MakeN32Premul(2, 2));
81 bitmap.eraseColor(SK_ColorBLUE);
82 *(bitmap.getAddr32(0, 0)) = SK_ColorGREEN;
reed1a9b9642016-03-13 14:13:58 -070083 paint.setShader(SkShader::MakeBitmapShader(bitmap, SkShader::kClamp_TileMode,
84 SkShader::kClamp_TileMode));
85 REPORTER_ASSERT(reporter, paint.getShader()->isABitmap());
tomhudson3a0f2792014-08-20 05:29:41 -070086
87 canvas->drawRect(SkRect::MakeWH(10, 10), paint);
88 }
reedca2622b2016-03-18 07:25:55 -070089 REPORTER_ASSERT(reporter, recorder.finishRecordingAsPicture()->willPlayBackBitmaps());
tomhudson3a0f2792014-08-20 05:29:41 -070090}
91
92
scroggo@google.comd614c6a2012-09-14 17:26:37 +000093#ifdef SK_DEBUG
mtklein3e8232b2014-08-18 13:39:11 -070094// Ensure that deleting an empty SkPicture does not assert. Asserts only fire
robertphillipsdb539902014-07-01 08:47:04 -070095// in debug mode, so only run in debug mode.
96static void test_deleting_empty_picture() {
robertphillips@google.com84b18c72014-04-13 19:09:42 +000097 SkPictureRecorder recorder;
scroggo@google.comd614c6a2012-09-14 17:26:37 +000098 // Creates an SkPictureRecord
robertphillips9f1c2412014-06-09 06:25:34 -070099 recorder.beginRecording(0, 0);
robertphillipsdb539902014-07-01 08:47:04 -0700100 // Turns that into an SkPicture
reedca2622b2016-03-18 07:25:55 -0700101 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
robertphillipsdb539902014-07-01 08:47:04 -0700102 // Ceates a new SkPictureRecord
robertphillips9f1c2412014-06-09 06:25:34 -0700103 recorder.beginRecording(0, 0);
scroggo@google.comd614c6a2012-09-14 17:26:37 +0000104}
105
106// Ensure that serializing an empty picture does not assert. Likewise only runs in debug mode.
107static void test_serializing_empty_picture() {
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000108 SkPictureRecorder recorder;
robertphillips9f1c2412014-06-09 06:25:34 -0700109 recorder.beginRecording(0, 0);
reedca2622b2016-03-18 07:25:55 -0700110 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
scroggo@google.comd614c6a2012-09-14 17:26:37 +0000111 SkDynamicMemoryWStream stream;
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000112 picture->serialize(&stream);
scroggo@google.comd614c6a2012-09-14 17:26:37 +0000113}
114#endif
115
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000116static void rand_op(SkCanvas* canvas, SkRandom& rand) {
reed@google.com21b519d2012-10-02 17:42:15 +0000117 SkPaint paint;
118 SkRect rect = SkRect::MakeWH(50, 50);
119
120 SkScalar unit = rand.nextUScalar1();
121 if (unit <= 0.3) {
122// SkDebugf("save\n");
123 canvas->save();
124 } else if (unit <= 0.6) {
125// SkDebugf("restore\n");
126 canvas->restore();
127 } else if (unit <= 0.9) {
128// SkDebugf("clip\n");
129 canvas->clipRect(rect);
130 } else {
131// SkDebugf("draw\n");
132 canvas->drawPaint(paint);
133 }
134}
135
robertphillips@google.comb950c6f2014-04-25 00:02:12 +0000136#if SK_SUPPORT_GPU
tomhudson3a0f2792014-08-20 05:29:41 -0700137
fmalitab5fc58e2016-05-25 11:31:04 -0700138static SkPath make_convex_path() {
139 SkPath path;
140 path.lineTo(100, 0);
141 path.lineTo(50, 100);
142 path.close();
143
144 return path;
145}
146
147static SkPath make_concave_path() {
148 SkPath path;
149 path.lineTo(50, 50);
150 path.lineTo(100, 0);
151 path.lineTo(50, 100);
152 path.close();
153
154 return path;
155}
156
mtklein8e126562014-10-01 09:29:35 -0700157static void test_gpu_veto(skiatest::Reporter* reporter) {
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +0000158 SkPictureRecorder recorder;
159
mtklein8e126562014-10-01 09:29:35 -0700160 SkCanvas* canvas = recorder.beginRecording(100, 100);
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +0000161 {
162 SkPath path;
163 path.moveTo(0, 0);
164 path.lineTo(50, 50);
165
166 SkScalar intervals[] = { 1.0f, 1.0f };
reeda4393342016-03-18 11:22:57 -0700167 sk_sp<SkPathEffect> dash(SkDashPathEffect::Make(intervals, 2, 0));
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +0000168
169 SkPaint paint;
170 paint.setStyle(SkPaint::kStroke_Style);
171 paint.setPathEffect(dash);
172
robertphillips98b03152015-01-26 11:29:36 -0800173 for (int i = 0; i < 50; ++i) {
174 canvas->drawPath(path, paint);
175 }
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +0000176 }
reedca2622b2016-03-18 07:25:55 -0700177 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +0000178 // path effects currently render an SkPicture undesireable for GPU rendering
commit-bot@chromium.orga1ff26a2014-05-30 21:52:52 +0000179
halcanary96fcdcc2015-08-27 07:41:13 -0700180 const char *reason = nullptr;
fmalita796e3652016-05-13 11:40:07 -0700181 REPORTER_ASSERT(reporter,
182 !SkPictureGpuAnalyzer(picture).suitableForGpuRasterization(&reason));
bsalomon49f085d2014-09-05 13:34:00 -0700183 REPORTER_ASSERT(reporter, reason);
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +0000184
mtklein8e126562014-10-01 09:29:35 -0700185 canvas = recorder.beginRecording(100, 100);
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +0000186 {
187 SkPath path;
188
189 path.moveTo(0, 0);
190 path.lineTo(0, 50);
191 path.lineTo(25, 25);
192 path.lineTo(50, 50);
193 path.lineTo(50, 0);
194 path.close();
195 REPORTER_ASSERT(reporter, !path.isConvex());
196
197 SkPaint paint;
198 paint.setAntiAlias(true);
199 for (int i = 0; i < 50; ++i) {
200 canvas->drawPath(path, paint);
201 }
202 }
reedca2622b2016-03-18 07:25:55 -0700203 picture = recorder.finishRecordingAsPicture();
jvanverthd86b07a2014-11-04 08:50:15 -0800204 // A lot of small AA concave paths should be fine for GPU rendering
fmalita796e3652016-05-13 11:40:07 -0700205 REPORTER_ASSERT(reporter, SkPictureGpuAnalyzer(picture).suitableForGpuRasterization());
jvanverthd86b07a2014-11-04 08:50:15 -0800206
207 canvas = recorder.beginRecording(100, 100);
208 {
209 SkPath path;
210
211 path.moveTo(0, 0);
212 path.lineTo(0, 100);
213 path.lineTo(50, 50);
214 path.lineTo(100, 100);
215 path.lineTo(100, 0);
216 path.close();
217 REPORTER_ASSERT(reporter, !path.isConvex());
218
219 SkPaint paint;
220 paint.setAntiAlias(true);
221 for (int i = 0; i < 50; ++i) {
222 canvas->drawPath(path, paint);
223 }
224 }
reedca2622b2016-03-18 07:25:55 -0700225 picture = recorder.finishRecordingAsPicture();
jvanverthd86b07a2014-11-04 08:50:15 -0800226 // A lot of large AA concave paths currently render an SkPicture undesireable for GPU rendering
fmalita796e3652016-05-13 11:40:07 -0700227 REPORTER_ASSERT(reporter, !SkPictureGpuAnalyzer(picture).suitableForGpuRasterization());
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +0000228
mtklein8e126562014-10-01 09:29:35 -0700229 canvas = recorder.beginRecording(100, 100);
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +0000230 {
231 SkPath path;
232
233 path.moveTo(0, 0);
234 path.lineTo(0, 50);
235 path.lineTo(25, 25);
236 path.lineTo(50, 50);
237 path.lineTo(50, 0);
238 path.close();
239 REPORTER_ASSERT(reporter, !path.isConvex());
240
241 SkPaint paint;
242 paint.setAntiAlias(true);
243 paint.setStyle(SkPaint::kStroke_Style);
244 paint.setStrokeWidth(0);
245 for (int i = 0; i < 50; ++i) {
246 canvas->drawPath(path, paint);
247 }
248 }
reedca2622b2016-03-18 07:25:55 -0700249 picture = recorder.finishRecordingAsPicture();
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +0000250 // hairline stroked AA concave paths are fine for GPU rendering
fmalita796e3652016-05-13 11:40:07 -0700251 REPORTER_ASSERT(reporter, SkPictureGpuAnalyzer(picture).suitableForGpuRasterization());
tomhudson3a0f2792014-08-20 05:29:41 -0700252
mtklein8e126562014-10-01 09:29:35 -0700253 canvas = recorder.beginRecording(100, 100);
tomhudson3a0f2792014-08-20 05:29:41 -0700254 {
255 SkPaint paint;
256 SkScalar intervals [] = { 10, 20 };
reeda4393342016-03-18 11:22:57 -0700257 paint.setPathEffect(SkDashPathEffect::Make(intervals, 2, 25));
tomhudson3a0f2792014-08-20 05:29:41 -0700258
259 SkPoint points [2] = { { 0, 0 }, { 100, 0 } };
robertphillips98b03152015-01-26 11:29:36 -0800260
261 for (int i = 0; i < 50; ++i) {
262 canvas->drawPoints(SkCanvas::kLines_PointMode, 2, points, paint);
263 }
tomhudson3a0f2792014-08-20 05:29:41 -0700264 }
reedca2622b2016-03-18 07:25:55 -0700265 picture = recorder.finishRecordingAsPicture();
tomhudson3a0f2792014-08-20 05:29:41 -0700266 // fast-path dashed effects are fine for GPU rendering ...
fmalita796e3652016-05-13 11:40:07 -0700267 REPORTER_ASSERT(reporter, SkPictureGpuAnalyzer(picture).suitableForGpuRasterization());
tomhudson3a0f2792014-08-20 05:29:41 -0700268
mtklein8e126562014-10-01 09:29:35 -0700269 canvas = recorder.beginRecording(100, 100);
tomhudson3a0f2792014-08-20 05:29:41 -0700270 {
271 SkPaint paint;
272 SkScalar intervals [] = { 10, 20 };
reeda4393342016-03-18 11:22:57 -0700273 paint.setPathEffect(SkDashPathEffect::Make(intervals, 2, 25));
tomhudson3a0f2792014-08-20 05:29:41 -0700274
robertphillips98b03152015-01-26 11:29:36 -0800275 for (int i = 0; i < 50; ++i) {
276 canvas->drawRect(SkRect::MakeWH(10, 10), paint);
277 }
tomhudson3a0f2792014-08-20 05:29:41 -0700278 }
reedca2622b2016-03-18 07:25:55 -0700279 picture = recorder.finishRecordingAsPicture();
tomhudson3a0f2792014-08-20 05:29:41 -0700280 // ... but only when applied to drawPoint() calls
fmalita796e3652016-05-13 11:40:07 -0700281 REPORTER_ASSERT(reporter, !SkPictureGpuAnalyzer(picture).suitableForGpuRasterization());
mtklein53fecfb2014-08-21 09:11:37 -0700282
fmalitab5fc58e2016-05-25 11:31:04 -0700283 canvas = recorder.beginRecording(100, 100);
284 {
285 const SkPath convexClip = make_convex_path();
286 const SkPath concaveClip = make_concave_path();
287
288 for (int i = 0; i < 50; ++i) {
289 canvas->clipPath(convexClip);
290 canvas->clipPath(concaveClip);
291 canvas->clipPath(convexClip, SkRegion::kIntersect_Op, true);
292 canvas->drawRect(SkRect::MakeWH(100, 100), SkPaint());
293 }
294 }
295 picture = recorder.finishRecordingAsPicture();
296 // Convex clips and non-AA concave clips are fine on the GPU.
297 REPORTER_ASSERT(reporter, SkPictureGpuAnalyzer(picture).suitableForGpuRasterization());
298
299 canvas = recorder.beginRecording(100, 100);
300 {
301 const SkPath concaveClip = make_concave_path();
302 for (int i = 0; i < 50; ++i) {
303 canvas->clipPath(concaveClip, SkRegion::kIntersect_Op, true);
304 canvas->drawRect(SkRect::MakeWH(100, 100), SkPaint());
305 }
306 }
307 picture = recorder.finishRecordingAsPicture();
308 // ... but AA concave clips are not.
309 REPORTER_ASSERT(reporter, !SkPictureGpuAnalyzer(picture).suitableForGpuRasterization());
310
mtklein53fecfb2014-08-21 09:11:37 -0700311 // Nest the previous picture inside a new one.
mtklein8e126562014-10-01 09:29:35 -0700312 canvas = recorder.beginRecording(100, 100);
313 {
fmalita796e3652016-05-13 11:40:07 -0700314 canvas->drawPicture(picture);
mtklein53fecfb2014-08-21 09:11:37 -0700315 }
reedca2622b2016-03-18 07:25:55 -0700316 picture = recorder.finishRecordingAsPicture();
fmalita796e3652016-05-13 11:40:07 -0700317 REPORTER_ASSERT(reporter, !SkPictureGpuAnalyzer(picture).suitableForGpuRasterization());
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +0000318}
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +0000319
fmalita796e3652016-05-13 11:40:07 -0700320#endif // SK_SUPPORT_GPU
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +0000321
robertphillips82365912014-11-12 09:32:34 -0800322static void test_savelayer_extraction(skiatest::Reporter* reporter) {
323 static const int kWidth = 100;
324 static const int kHeight = 100;
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +0000325
robertphillips82365912014-11-12 09:32:34 -0800326 // Create complex paint that the bounding box computation code can't
327 // optimize away
328 SkScalar blueToRedMatrix[20] = { 0 };
329 blueToRedMatrix[2] = blueToRedMatrix[18] = SK_Scalar1;
robertphillips5605b562016-04-05 11:50:42 -0700330 sk_sp<SkColorFilter> blueToRed(SkColorFilter::MakeMatrixFilterRowMajor255(blueToRedMatrix));
331 sk_sp<SkImageFilter> filter(SkColorFilterImageFilter::Make(std::move(blueToRed), nullptr));
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +0000332
robertphillips82365912014-11-12 09:32:34 -0800333 SkPaint complexPaint;
robertphillips5605b562016-04-05 11:50:42 -0700334 complexPaint.setImageFilter(std::move(filter));
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +0000335
reedca2622b2016-03-18 07:25:55 -0700336 sk_sp<SkPicture> pict, child;
robertphillips82365912014-11-12 09:32:34 -0800337 SkRTreeFactory bbhFactory;
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +0000338
robertphillips82365912014-11-12 09:32:34 -0800339 {
340 SkPictureRecorder recorder;
robertphillipsd8aa7b72014-10-30 16:45:02 -0700341
robertphillips82365912014-11-12 09:32:34 -0800342 SkCanvas* c = recorder.beginRecording(SkIntToScalar(kWidth), SkIntToScalar(kHeight),
343 &bbhFactory,
344 SkPictureRecorder::kComputeSaveLayerInfo_RecordFlag);
robertphillipsd8aa7b72014-10-30 16:45:02 -0700345
halcanary96fcdcc2015-08-27 07:41:13 -0700346 c->saveLayer(nullptr, &complexPaint);
robertphillips82365912014-11-12 09:32:34 -0800347 c->restore();
robertphillipsd6283302014-08-27 11:53:28 -0700348
reedca2622b2016-03-18 07:25:55 -0700349 child = recorder.finishRecordingAsPicture();
robertphillips82365912014-11-12 09:32:34 -0800350 }
robertphillipsd6283302014-08-27 11:53:28 -0700351
robertphillips82365912014-11-12 09:32:34 -0800352 // create a picture with the structure:
353 // 1)
354 // SaveLayer
355 // Restore
356 // 2)
357 // SaveLayer
358 // Translate
359 // SaveLayer w/ bound
360 // Restore
361 // Restore
362 // 3)
363 // SaveLayer w/ copyable paint
364 // Restore
365 // 4)
366 // SaveLayer
367 // DrawPicture (which has a SaveLayer/Restore pair)
368 // Restore
369 // 5)
370 // SaveLayer
371 // DrawPicture with Matrix & Paint (with SaveLayer/Restore pair)
372 // Restore
373 {
374 SkPictureRecorder recorder;
robertphillipsd6283302014-08-27 11:53:28 -0700375
robertphillips82365912014-11-12 09:32:34 -0800376 SkCanvas* c = recorder.beginRecording(SkIntToScalar(kWidth),
377 SkIntToScalar(kHeight),
378 &bbhFactory,
379 SkPictureRecorder::kComputeSaveLayerInfo_RecordFlag);
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +0000380 // 1)
halcanary96fcdcc2015-08-27 07:41:13 -0700381 c->saveLayer(nullptr, &complexPaint); // layer #0
robertphillips82365912014-11-12 09:32:34 -0800382 c->restore();
383
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +0000384 // 2)
halcanary96fcdcc2015-08-27 07:41:13 -0700385 c->saveLayer(nullptr, nullptr); // layer #1
robertphillips01d6e5f2014-12-01 09:09:27 -0800386 c->translate(kWidth / 2.0f, kHeight / 2.0f);
robertphillips82365912014-11-12 09:32:34 -0800387 SkRect r = SkRect::MakeXYWH(0, 0, kWidth/2, kHeight/2);
388 c->saveLayer(&r, &complexPaint); // layer #2
389 c->restore();
390 c->restore();
391
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +0000392 // 3)
robertphillips82365912014-11-12 09:32:34 -0800393 {
halcanary96fcdcc2015-08-27 07:41:13 -0700394 c->saveLayer(nullptr, &complexPaint); // layer #3
robertphillips82365912014-11-12 09:32:34 -0800395 c->restore();
396 }
397
398 SkPaint layerPaint;
399 layerPaint.setColor(SK_ColorRED); // Non-alpha only to avoid SaveLayerDrawRestoreNooper
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +0000400 // 4)
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +0000401 {
halcanary96fcdcc2015-08-27 07:41:13 -0700402 c->saveLayer(nullptr, &layerPaint); // layer #4
robertphillips82365912014-11-12 09:32:34 -0800403 c->drawPicture(child); // layer #5 inside picture
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +0000404 c->restore();
robertphillips82365912014-11-12 09:32:34 -0800405 }
406 // 5
407 {
408 SkPaint picturePaint;
409 SkMatrix trans;
410 trans.setTranslate(10, 10);
bsalomone904c092014-07-17 10:50:59 -0700411
halcanary96fcdcc2015-08-27 07:41:13 -0700412 c->saveLayer(nullptr, &layerPaint); // layer #6
robertphillips82365912014-11-12 09:32:34 -0800413 c->drawPicture(child, &trans, &picturePaint); // layer #7 inside picture
bsalomone904c092014-07-17 10:50:59 -0700414 c->restore();
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +0000415 }
416
reedca2622b2016-03-18 07:25:55 -0700417 pict = recorder.finishRecordingAsPicture();
robertphillips82365912014-11-12 09:32:34 -0800418 }
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +0000419
robertphillips82365912014-11-12 09:32:34 -0800420 // Now test out the SaveLayer extraction
reedd990e2f2014-12-22 11:58:30 -0800421 if (!SkCanvas::Internal_Private_GetIgnoreSaveLayerBounds()) {
mtklein9db912c2015-05-19 11:11:26 -0700422 const SkBigPicture* bp = pict->asSkBigPicture();
423 REPORTER_ASSERT(reporter, bp);
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +0000424
mtklein9db912c2015-05-19 11:11:26 -0700425 const SkBigPicture::AccelData* data = bp->accelData();
robertphillips82365912014-11-12 09:32:34 -0800426 REPORTER_ASSERT(reporter, data);
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +0000427
robertphillips82365912014-11-12 09:32:34 -0800428 const SkLayerInfo *gpuData = static_cast<const SkLayerInfo*>(data);
429 REPORTER_ASSERT(reporter, 8 == gpuData->numBlocks());
robertphillipsd6283302014-08-27 11:53:28 -0700430
robertphillips82365912014-11-12 09:32:34 -0800431 const SkLayerInfo::BlockInfo& info0 = gpuData->block(0);
432 // The parent/child layers appear in reverse order
433 const SkLayerInfo::BlockInfo& info1 = gpuData->block(2);
434 const SkLayerInfo::BlockInfo& info2 = gpuData->block(1);
robertphillipsd6283302014-08-27 11:53:28 -0700435
robertphillips82365912014-11-12 09:32:34 -0800436 const SkLayerInfo::BlockInfo& info3 = gpuData->block(3);
robertphillipsd6283302014-08-27 11:53:28 -0700437
robertphillips82365912014-11-12 09:32:34 -0800438 // The parent/child layers appear in reverse order
439 const SkLayerInfo::BlockInfo& info4 = gpuData->block(5);
440 const SkLayerInfo::BlockInfo& info5 = gpuData->block(4);
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +0000441
robertphillips82365912014-11-12 09:32:34 -0800442 // The parent/child layers appear in reverse order
443 const SkLayerInfo::BlockInfo& info6 = gpuData->block(7);
444 const SkLayerInfo::BlockInfo& info7 = gpuData->block(6);
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +0000445
halcanary96fcdcc2015-08-27 07:41:13 -0700446 REPORTER_ASSERT(reporter, nullptr == info0.fPicture);
robertphillips82365912014-11-12 09:32:34 -0800447 REPORTER_ASSERT(reporter, kWidth == info0.fBounds.width() &&
448 kHeight == info0.fBounds.height());
449 REPORTER_ASSERT(reporter, info0.fLocalMat.isIdentity());
450 REPORTER_ASSERT(reporter, info0.fPreMat.isIdentity());
451 REPORTER_ASSERT(reporter, 0 == info0.fBounds.fLeft && 0 == info0.fBounds.fTop);
halcanary96fcdcc2015-08-27 07:41:13 -0700452 REPORTER_ASSERT(reporter, nullptr != info0.fPaint);
robertphillips82365912014-11-12 09:32:34 -0800453 REPORTER_ASSERT(reporter, !info0.fIsNested && !info0.fHasNestedLayers);
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +0000454
halcanary96fcdcc2015-08-27 07:41:13 -0700455 REPORTER_ASSERT(reporter, nullptr == info1.fPicture);
robertphillips82365912014-11-12 09:32:34 -0800456 REPORTER_ASSERT(reporter, kWidth/2.0 == info1.fBounds.width() &&
457 kHeight/2.0 == info1.fBounds.height());
458 REPORTER_ASSERT(reporter, info1.fLocalMat.isIdentity());
459 REPORTER_ASSERT(reporter, info1.fPreMat.isIdentity());
mtklein04c96952014-11-24 08:20:57 -0800460 REPORTER_ASSERT(reporter, kWidth/2.0 == info1.fBounds.fLeft &&
robertphillips82365912014-11-12 09:32:34 -0800461 kHeight/2.0 == info1.fBounds.fTop);
halcanary96fcdcc2015-08-27 07:41:13 -0700462 REPORTER_ASSERT(reporter, nullptr == info1.fPaint);
robertphillips82365912014-11-12 09:32:34 -0800463 REPORTER_ASSERT(reporter, !info1.fIsNested &&
464 info1.fHasNestedLayers); // has a nested SL
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +0000465
halcanary96fcdcc2015-08-27 07:41:13 -0700466 REPORTER_ASSERT(reporter, nullptr == info2.fPicture);
robertphillips82365912014-11-12 09:32:34 -0800467 REPORTER_ASSERT(reporter, kWidth / 2 == info2.fBounds.width() &&
468 kHeight / 2 == info2.fBounds.height()); // bound reduces size
469 REPORTER_ASSERT(reporter, !info2.fLocalMat.isIdentity());
470 REPORTER_ASSERT(reporter, info2.fPreMat.isIdentity());
471 REPORTER_ASSERT(reporter, kWidth / 2 == info2.fBounds.fLeft && // translated
472 kHeight / 2 == info2.fBounds.fTop);
halcanary96fcdcc2015-08-27 07:41:13 -0700473 REPORTER_ASSERT(reporter, nullptr != info2.fPaint);
robertphillips82365912014-11-12 09:32:34 -0800474 REPORTER_ASSERT(reporter, info2.fIsNested && !info2.fHasNestedLayers); // is nested
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +0000475
halcanary96fcdcc2015-08-27 07:41:13 -0700476 REPORTER_ASSERT(reporter, nullptr == info3.fPicture);
robertphillips82365912014-11-12 09:32:34 -0800477 REPORTER_ASSERT(reporter, kWidth == info3.fBounds.width() &&
478 kHeight == info3.fBounds.height());
479 REPORTER_ASSERT(reporter, info3.fLocalMat.isIdentity());
480 REPORTER_ASSERT(reporter, info3.fPreMat.isIdentity());
481 REPORTER_ASSERT(reporter, 0 == info3.fBounds.fLeft && 0 == info3.fBounds.fTop);
482 REPORTER_ASSERT(reporter, info3.fPaint);
483 REPORTER_ASSERT(reporter, !info3.fIsNested && !info3.fHasNestedLayers);
robertphillipsd6283302014-08-27 11:53:28 -0700484
halcanary96fcdcc2015-08-27 07:41:13 -0700485 REPORTER_ASSERT(reporter, nullptr == info4.fPicture);
robertphillips82365912014-11-12 09:32:34 -0800486 REPORTER_ASSERT(reporter, kWidth == info4.fBounds.width() &&
487 kHeight == info4.fBounds.height());
488 REPORTER_ASSERT(reporter, 0 == info4.fBounds.fLeft && 0 == info4.fBounds.fTop);
489 REPORTER_ASSERT(reporter, info4.fLocalMat.isIdentity());
490 REPORTER_ASSERT(reporter, info4.fPreMat.isIdentity());
491 REPORTER_ASSERT(reporter, info4.fPaint);
492 REPORTER_ASSERT(reporter, !info4.fIsNested &&
493 info4.fHasNestedLayers); // has a nested SL
robertphillipsd6283302014-08-27 11:53:28 -0700494
reedca2622b2016-03-18 07:25:55 -0700495 REPORTER_ASSERT(reporter, child.get() == info5.fPicture); // in a child picture
robertphillips82365912014-11-12 09:32:34 -0800496 REPORTER_ASSERT(reporter, kWidth == info5.fBounds.width() &&
497 kHeight == info5.fBounds.height());
498 REPORTER_ASSERT(reporter, 0 == info5.fBounds.fLeft && 0 == info5.fBounds.fTop);
499 REPORTER_ASSERT(reporter, info5.fLocalMat.isIdentity());
500 REPORTER_ASSERT(reporter, info5.fPreMat.isIdentity());
halcanary96fcdcc2015-08-27 07:41:13 -0700501 REPORTER_ASSERT(reporter, nullptr != info5.fPaint);
robertphillips82365912014-11-12 09:32:34 -0800502 REPORTER_ASSERT(reporter, info5.fIsNested && !info5.fHasNestedLayers); // is nested
robertphillipsd6283302014-08-27 11:53:28 -0700503
halcanary96fcdcc2015-08-27 07:41:13 -0700504 REPORTER_ASSERT(reporter, nullptr == info6.fPicture);
robertphillips82365912014-11-12 09:32:34 -0800505 REPORTER_ASSERT(reporter, kWidth-10 == info6.fBounds.width() &&
506 kHeight-10 == info6.fBounds.height());
507 REPORTER_ASSERT(reporter, 10 == info6.fBounds.fLeft && 10 == info6.fBounds.fTop);
508 REPORTER_ASSERT(reporter, info6.fLocalMat.isIdentity());
509 REPORTER_ASSERT(reporter, info6.fPreMat.isIdentity());
510 REPORTER_ASSERT(reporter, info6.fPaint);
511 REPORTER_ASSERT(reporter, !info6.fIsNested &&
512 info6.fHasNestedLayers); // has a nested SL
513
reedca2622b2016-03-18 07:25:55 -0700514 REPORTER_ASSERT(reporter, child.get() == info7.fPicture); // in a child picture
robertphillips82365912014-11-12 09:32:34 -0800515 REPORTER_ASSERT(reporter, kWidth == info7.fBounds.width() &&
516 kHeight == info7.fBounds.height());
517 REPORTER_ASSERT(reporter, 0 == info7.fBounds.fLeft && 0 == info7.fBounds.fTop);
518 REPORTER_ASSERT(reporter, info7.fLocalMat.isIdentity());
519 REPORTER_ASSERT(reporter, info7.fPreMat.isIdentity());
halcanary96fcdcc2015-08-27 07:41:13 -0700520 REPORTER_ASSERT(reporter, nullptr != info7.fPaint);
robertphillips82365912014-11-12 09:32:34 -0800521 REPORTER_ASSERT(reporter, info7.fIsNested && !info7.fHasNestedLayers); // is nested
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +0000522 }
523}
524
commit-bot@chromium.orgea7d08e2014-02-13 16:00:51 +0000525static void set_canvas_to_save_count_4(SkCanvas* canvas) {
526 canvas->restoreToCount(1);
527 canvas->save();
528 canvas->save();
529 canvas->save();
530}
531
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000532/**
533 * A canvas that records the number of saves, saveLayers and restores.
534 */
535class SaveCountingCanvas : public SkCanvas {
536public:
537 SaveCountingCanvas(int width, int height)
538 : INHERITED(width, height)
539 , fSaveCount(0)
540 , fSaveLayerCount(0)
541 , fRestoreCount(0){
542 }
543
reed4960eee2015-12-18 07:09:18 -0800544 SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec& rec) override {
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000545 ++fSaveLayerCount;
reed4960eee2015-12-18 07:09:18 -0800546 return this->INHERITED::getSaveLayerStrategy(rec);
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000547 }
548
mtklein36352bf2015-03-25 18:17:31 -0700549 void willSave() override {
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000550 ++fSaveCount;
Florin Malita5f6102d2014-06-30 10:13:28 -0400551 this->INHERITED::willSave();
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000552 }
553
mtklein36352bf2015-03-25 18:17:31 -0700554 void willRestore() override {
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000555 ++fRestoreCount;
556 this->INHERITED::willRestore();
557 }
558
559 unsigned int getSaveCount() const { return fSaveCount; }
560 unsigned int getSaveLayerCount() const { return fSaveLayerCount; }
561 unsigned int getRestoreCount() const { return fRestoreCount; }
562
563private:
564 unsigned int fSaveCount;
565 unsigned int fSaveLayerCount;
566 unsigned int fRestoreCount;
567
568 typedef SkCanvas INHERITED;
569};
570
skia.committer@gmail.com8e7d37d2014-05-28 03:06:06 +0000571void check_save_state(skiatest::Reporter* reporter, SkPicture* picture,
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000572 unsigned int numSaves, unsigned int numSaveLayers,
573 unsigned int numRestores) {
mtklein87c41382014-09-08 07:31:18 -0700574 SaveCountingCanvas canvas(SkScalarCeilToInt(picture->cullRect().width()),
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700575 SkScalarCeilToInt(picture->cullRect().height()));
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000576
robertphillipsc5ba71d2014-09-04 08:42:50 -0700577 picture->playback(&canvas);
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000578
mtklein87c41382014-09-08 07:31:18 -0700579 // Optimizations may have removed these,
580 // so expect to have seen no more than num{Saves,SaveLayers,Restores}.
581 REPORTER_ASSERT(reporter, numSaves >= canvas.getSaveCount());
582 REPORTER_ASSERT(reporter, numSaveLayers >= canvas.getSaveLayerCount());
583 REPORTER_ASSERT(reporter, numRestores >= canvas.getRestoreCount());
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000584}
585
586// This class exists so SkPicture can friend it and give it access to
587// the 'partialReplay' method.
588class SkPictureRecorderReplayTester {
589public:
reedca2622b2016-03-18 07:25:55 -0700590 static sk_sp<SkPicture> Copy(SkPictureRecorder* recorder) {
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000591 SkPictureRecorder recorder2;
592
robertphillips9f1c2412014-06-09 06:25:34 -0700593 SkCanvas* canvas = recorder2.beginRecording(10, 10);
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000594
595 recorder->partialReplay(canvas);
596
reedca2622b2016-03-18 07:25:55 -0700597 return recorder2.finishRecordingAsPicture();
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000598 }
599};
600
robertphillips9058d602014-06-10 11:45:46 -0700601static void create_imbalance(SkCanvas* canvas) {
602 SkRect clipRect = SkRect::MakeWH(2, 2);
603 SkRect drawRect = SkRect::MakeWH(10, 10);
604 canvas->save();
605 canvas->clipRect(clipRect, SkRegion::kReplace_Op);
606 canvas->translate(1.0f, 1.0f);
607 SkPaint p;
608 p.setColor(SK_ColorGREEN);
609 canvas->drawRect(drawRect, p);
610 // no restore
611}
612
613// This tests that replaying a potentially unbalanced picture into a canvas
614// doesn't affect the canvas' save count or matrix/clip state.
615static void check_balance(skiatest::Reporter* reporter, SkPicture* picture) {
616 SkBitmap bm;
617 bm.allocN32Pixels(4, 3);
618 SkCanvas canvas(bm);
619
620 int beforeSaveCount = canvas.getSaveCount();
621
622 SkMatrix beforeMatrix = canvas.getTotalMatrix();
623
624 SkRect beforeClip;
625
626 canvas.getClipBounds(&beforeClip);
627
628 canvas.drawPicture(picture);
629
630 REPORTER_ASSERT(reporter, beforeSaveCount == canvas.getSaveCount());
631 REPORTER_ASSERT(reporter, beforeMatrix == canvas.getTotalMatrix());
632
633 SkRect afterClip;
634
635 canvas.getClipBounds(&afterClip);
636
637 REPORTER_ASSERT(reporter, afterClip == beforeClip);
638}
639
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000640// Test out SkPictureRecorder::partialReplay
641DEF_TEST(PictureRecorder_replay, reporter) {
642 // check save/saveLayer state
643 {
644 SkPictureRecorder recorder;
645
robertphillips9f1c2412014-06-09 06:25:34 -0700646 SkCanvas* canvas = recorder.beginRecording(10, 10);
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000647
halcanary96fcdcc2015-08-27 07:41:13 -0700648 canvas->saveLayer(nullptr, nullptr);
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000649
reedca2622b2016-03-18 07:25:55 -0700650 sk_sp<SkPicture> copy(SkPictureRecorderReplayTester::Copy(&recorder));
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000651
652 // The extra save and restore comes from the Copy process.
reedca2622b2016-03-18 07:25:55 -0700653 check_save_state(reporter, copy.get(), 2, 1, 3);
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000654
halcanary96fcdcc2015-08-27 07:41:13 -0700655 canvas->saveLayer(nullptr, nullptr);
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000656
reedca2622b2016-03-18 07:25:55 -0700657 sk_sp<SkPicture> final(recorder.finishRecordingAsPicture());
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000658
reedca2622b2016-03-18 07:25:55 -0700659 check_save_state(reporter, final.get(), 1, 2, 3);
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000660
661 // The copy shouldn't pick up any operations added after it was made
reedca2622b2016-03-18 07:25:55 -0700662 check_save_state(reporter, copy.get(), 2, 1, 3);
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000663 }
664
665 // (partially) check leakage of draw ops
666 {
667 SkPictureRecorder recorder;
668
robertphillips9f1c2412014-06-09 06:25:34 -0700669 SkCanvas* canvas = recorder.beginRecording(10, 10);
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000670
671 SkRect r = SkRect::MakeWH(5, 5);
672 SkPaint p;
673
674 canvas->drawRect(r, p);
675
reedca2622b2016-03-18 07:25:55 -0700676 sk_sp<SkPicture> copy(SkPictureRecorderReplayTester::Copy(&recorder));
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000677
678 REPORTER_ASSERT(reporter, !copy->willPlayBackBitmaps());
679
680 SkBitmap bm;
681 make_bm(&bm, 10, 10, SK_ColorRED, true);
682
683 r.offset(5.0f, 5.0f);
reede47829b2015-08-06 10:02:53 -0700684 canvas->drawBitmapRect(bm, r, nullptr);
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000685
reedca2622b2016-03-18 07:25:55 -0700686 sk_sp<SkPicture> final(recorder.finishRecordingAsPicture());
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000687 REPORTER_ASSERT(reporter, final->willPlayBackBitmaps());
688
689 REPORTER_ASSERT(reporter, copy->uniqueID() != final->uniqueID());
690
691 // The snapshot shouldn't pick up any operations added after it was made
692 REPORTER_ASSERT(reporter, !copy->willPlayBackBitmaps());
693 }
robertphillips9058d602014-06-10 11:45:46 -0700694
695 // Recreate the Android partialReplay test case
696 {
697 SkPictureRecorder recorder;
698
halcanary96fcdcc2015-08-27 07:41:13 -0700699 SkCanvas* canvas = recorder.beginRecording(4, 3, nullptr, 0);
robertphillips9058d602014-06-10 11:45:46 -0700700 create_imbalance(canvas);
701
702 int expectedSaveCount = canvas->getSaveCount();
703
reedca2622b2016-03-18 07:25:55 -0700704 sk_sp<SkPicture> copy(SkPictureRecorderReplayTester::Copy(&recorder));
705 check_balance(reporter, copy.get());
robertphillips9058d602014-06-10 11:45:46 -0700706
707 REPORTER_ASSERT(reporter, expectedSaveCount = canvas->getSaveCount());
708
709 // End the recording of source to test the picture finalization
710 // process isn't complicated by the partialReplay step
reedca2622b2016-03-18 07:25:55 -0700711 sk_sp<SkPicture> final(recorder.finishRecordingAsPicture());
robertphillips9058d602014-06-10 11:45:46 -0700712 }
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000713}
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000714
commit-bot@chromium.orgea7d08e2014-02-13 16:00:51 +0000715static void test_unbalanced_save_restores(skiatest::Reporter* reporter) {
716 SkCanvas testCanvas(100, 100);
717 set_canvas_to_save_count_4(&testCanvas);
718
719 REPORTER_ASSERT(reporter, 4 == testCanvas.getSaveCount());
720
721 SkPaint paint;
722 SkRect rect = SkRect::MakeLTRB(-10000000, -10000000, 10000000, 10000000);
723
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000724 SkPictureRecorder recorder;
commit-bot@chromium.orgea7d08e2014-02-13 16:00:51 +0000725
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000726 {
727 // Create picture with 2 unbalanced saves
robertphillips9f1c2412014-06-09 06:25:34 -0700728 SkCanvas* canvas = recorder.beginRecording(100, 100);
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000729 canvas->save();
730 canvas->translate(10, 10);
731 canvas->drawRect(rect, paint);
732 canvas->save();
733 canvas->translate(10, 10);
734 canvas->drawRect(rect, paint);
reedca2622b2016-03-18 07:25:55 -0700735 sk_sp<SkPicture> extraSavePicture(recorder.finishRecordingAsPicture());
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000736
robertphillips9b14f262014-06-04 05:40:44 -0700737 testCanvas.drawPicture(extraSavePicture);
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000738 REPORTER_ASSERT(reporter, 4 == testCanvas.getSaveCount());
739 }
commit-bot@chromium.orgea7d08e2014-02-13 16:00:51 +0000740
741 set_canvas_to_save_count_4(&testCanvas);
742
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000743 {
744 // Create picture with 2 unbalanced restores
robertphillips9f1c2412014-06-09 06:25:34 -0700745 SkCanvas* canvas = recorder.beginRecording(100, 100);
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000746 canvas->save();
747 canvas->translate(10, 10);
748 canvas->drawRect(rect, paint);
749 canvas->save();
750 canvas->translate(10, 10);
751 canvas->drawRect(rect, paint);
752 canvas->restore();
753 canvas->restore();
754 canvas->restore();
755 canvas->restore();
reedca2622b2016-03-18 07:25:55 -0700756 sk_sp<SkPicture> extraRestorePicture(recorder.finishRecordingAsPicture());
commit-bot@chromium.orgea7d08e2014-02-13 16:00:51 +0000757
robertphillips9b14f262014-06-04 05:40:44 -0700758 testCanvas.drawPicture(extraRestorePicture);
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000759 REPORTER_ASSERT(reporter, 4 == testCanvas.getSaveCount());
760 }
commit-bot@chromium.orgea7d08e2014-02-13 16:00:51 +0000761
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000762 set_canvas_to_save_count_4(&testCanvas);
commit-bot@chromium.orgea7d08e2014-02-13 16:00:51 +0000763
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000764 {
robertphillips9f1c2412014-06-09 06:25:34 -0700765 SkCanvas* canvas = recorder.beginRecording(100, 100);
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000766 canvas->translate(10, 10);
767 canvas->drawRect(rect, paint);
reedca2622b2016-03-18 07:25:55 -0700768 sk_sp<SkPicture> noSavePicture(recorder.finishRecordingAsPicture());
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000769
robertphillips9b14f262014-06-04 05:40:44 -0700770 testCanvas.drawPicture(noSavePicture);
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000771 REPORTER_ASSERT(reporter, 4 == testCanvas.getSaveCount());
772 REPORTER_ASSERT(reporter, testCanvas.getTotalMatrix().isIdentity());
773 }
commit-bot@chromium.orgea7d08e2014-02-13 16:00:51 +0000774}
775
sugoi@google.com54f0d1b2013-02-27 19:17:41 +0000776static void test_peephole() {
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000777 SkRandom rand;
reed@google.com21b519d2012-10-02 17:42:15 +0000778
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000779 SkPictureRecorder recorder;
780
reed@google.com21b519d2012-10-02 17:42:15 +0000781 for (int j = 0; j < 100; j++) {
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000782 SkRandom rand2(rand); // remember the seed
reed@google.com21b519d2012-10-02 17:42:15 +0000783
robertphillips9f1c2412014-06-09 06:25:34 -0700784 SkCanvas* canvas = recorder.beginRecording(100, 100);
reed@google.com21b519d2012-10-02 17:42:15 +0000785
786 for (int i = 0; i < 1000; ++i) {
787 rand_op(canvas, rand);
788 }
reedca2622b2016-03-18 07:25:55 -0700789 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
jvanverth@google.comc490f802013-03-04 13:56:38 +0000790
791 rand = rand2;
reed@google.com21b519d2012-10-02 17:42:15 +0000792 }
793
794 {
robertphillips9f1c2412014-06-09 06:25:34 -0700795 SkCanvas* canvas = recorder.beginRecording(100, 100);
reed@google.com21b519d2012-10-02 17:42:15 +0000796 SkRect rect = SkRect::MakeWH(50, 50);
skia.committer@gmail.com52c24372012-10-03 02:01:13 +0000797
reed@google.com21b519d2012-10-02 17:42:15 +0000798 for (int i = 0; i < 100; ++i) {
799 canvas->save();
800 }
801 while (canvas->getSaveCount() > 1) {
802 canvas->clipRect(rect);
803 canvas->restore();
804 }
reedca2622b2016-03-18 07:25:55 -0700805 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
reed@google.com21b519d2012-10-02 17:42:15 +0000806 }
807}
808
scroggo@google.com4b90b112012-12-04 15:08:56 +0000809#ifndef SK_DEBUG
810// Only test this is in release mode. We deliberately crash in debug mode, since a valid caller
811// should never do this.
812static void test_bad_bitmap() {
813 // This bitmap has a width and height but no pixels. As a result, attempting to record it will
814 // fail.
815 SkBitmap bm;
commit-bot@chromium.orga3264e52014-05-30 13:26:10 +0000816 bm.setInfo(SkImageInfo::MakeN32Premul(100, 100));
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000817 SkPictureRecorder recorder;
robertphillips9f1c2412014-06-09 06:25:34 -0700818 SkCanvas* recordingCanvas = recorder.beginRecording(100, 100);
scroggo@google.com4b90b112012-12-04 15:08:56 +0000819 recordingCanvas->drawBitmap(bm, 0, 0);
reedca2622b2016-03-18 07:25:55 -0700820 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
scroggo@google.com4b90b112012-12-04 15:08:56 +0000821
822 SkCanvas canvas;
robertphillips9b14f262014-06-04 05:40:44 -0700823 canvas.drawPicture(picture);
scroggo@google.com4b90b112012-12-04 15:08:56 +0000824}
825#endif
826
scroggo@google.com7c9d5392012-12-10 15:40:55 +0000827static SkData* serialized_picture_from_bitmap(const SkBitmap& bitmap) {
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000828 SkPictureRecorder recorder;
mtklein87c41382014-09-08 07:31:18 -0700829 SkCanvas* canvas = recorder.beginRecording(SkIntToScalar(bitmap.width()),
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700830 SkIntToScalar(bitmap.height()));
scroggo@google.com7c9d5392012-12-10 15:40:55 +0000831 canvas->drawBitmap(bitmap, 0, 0);
reedca2622b2016-03-18 07:25:55 -0700832 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000833
scroggo@google.com7c9d5392012-12-10 15:40:55 +0000834 SkDynamicMemoryWStream wStream;
halcanaryf2848b62015-12-10 12:40:23 -0800835 SkAutoTUnref<SkPixelSerializer> serializer(
836 SkImageEncoder::CreatePixelSerializer());
837 picture->serialize(&wStream, serializer);
scroggo@google.com7c9d5392012-12-10 15:40:55 +0000838 return wStream.copyToData();
839}
840
scroggo@google.com49ce11b2013-04-25 18:29:32 +0000841struct ErrorContext {
842 int fErrors;
843 skiatest::Reporter* fReporter;
844};
845
846static void assert_one_parse_error_cb(SkError error, void* context) {
847 ErrorContext* errorContext = static_cast<ErrorContext*>(context);
848 errorContext->fErrors++;
849 // This test only expects one error, and that is a kParseError. If there are others,
850 // there is some unknown problem.
851 REPORTER_ASSERT_MESSAGE(errorContext->fReporter, 1 == errorContext->fErrors,
852 "This threw more errors than expected.");
853 REPORTER_ASSERT_MESSAGE(errorContext->fReporter, kParseError_SkError == error,
854 SkGetLastErrorString());
855}
856
msarett8715d472016-02-17 10:02:29 -0800857static void md5(const SkBitmap& bm, SkMD5::Digest* digest) {
858 SkAutoLockPixels autoLockPixels(bm);
859 SkASSERT(bm.getPixels());
860 SkMD5 md5;
861 size_t rowLen = bm.info().bytesPerPixel() * bm.width();
862 for (int y = 0; y < bm.height(); ++y) {
halcanary1e903042016-04-25 10:29:36 -0700863 md5.write(bm.getAddr(0, y), rowLen);
msarett8715d472016-02-17 10:02:29 -0800864 }
865 md5.finish(*digest);
866}
867
868DEF_TEST(Picture_EncodedData, reporter) {
scroggo@google.com7c9d5392012-12-10 15:40:55 +0000869 // Create a bitmap that will be encoded.
870 SkBitmap original;
871 make_bm(&original, 100, 100, SK_ColorBLUE, true);
872 SkDynamicMemoryWStream wStream;
873 if (!SkImageEncoder::EncodeStream(&wStream, original, SkImageEncoder::kPNG_Type, 100)) {
874 return;
875 }
876 SkAutoDataUnref data(wStream.copyToData());
scroggo@google.com7c9d5392012-12-10 15:40:55 +0000877
scroggo@google.com7c9d5392012-12-10 15:40:55 +0000878 SkBitmap bm;
reedd1146452015-09-25 06:56:57 -0700879 bool installSuccess = SkDEPRECATED_InstallDiscardablePixelRef(data, &bm);
reed@google.combf790232013-12-13 19:45:58 +0000880 REPORTER_ASSERT(reporter, installSuccess);
scroggo@google.com7c9d5392012-12-10 15:40:55 +0000881
882 // Write both bitmaps to pictures, and ensure that the resulting data streams are the same.
883 // Flattening original will follow the old path of performing an encode, while flattening bm
884 // will use the already encoded data.
885 SkAutoDataUnref picture1(serialized_picture_from_bitmap(original));
886 SkAutoDataUnref picture2(serialized_picture_from_bitmap(bm));
887 REPORTER_ASSERT(reporter, picture1->equals(picture2));
msarett8715d472016-02-17 10:02:29 -0800888
scroggo@google.com49ce11b2013-04-25 18:29:32 +0000889 // Now test that a parse error was generated when trying to create a new SkPicture without
890 // providing a function to decode the bitmap.
891 ErrorContext context;
892 context.fErrors = 0;
893 context.fReporter = reporter;
894 SkSetErrorCallback(assert_one_parse_error_cb, &context);
895 SkMemoryStream pictureStream(picture1);
scroggo@google.com49ce11b2013-04-25 18:29:32 +0000896 SkClearLastError();
reedca2622b2016-03-18 07:25:55 -0700897 sk_sp<SkPicture> pictureFromStream(SkPicture::MakeFromStream(&pictureStream, nullptr));
halcanary96fcdcc2015-08-27 07:41:13 -0700898 REPORTER_ASSERT(reporter, pictureFromStream.get() != nullptr);
scroggo@google.com49ce11b2013-04-25 18:29:32 +0000899 SkClearLastError();
halcanary96fcdcc2015-08-27 07:41:13 -0700900 SkSetErrorCallback(nullptr, nullptr);
msarett8715d472016-02-17 10:02:29 -0800901
902 // Test that using the version of CreateFromStream that just takes a stream also decodes the
903 // bitmap. Drawing this picture should look exactly like the original bitmap.
904 SkMD5::Digest referenceDigest;
905 md5(original, &referenceDigest);
906
907 SkBitmap dst;
908 dst.allocPixels(original.info());
909 dst.eraseColor(SK_ColorRED);
910 SkCanvas canvas(dst);
911
912 pictureStream.rewind();
reedca2622b2016-03-18 07:25:55 -0700913 pictureFromStream = SkPicture::MakeFromStream(&pictureStream);
msarett8715d472016-02-17 10:02:29 -0800914 canvas.drawPicture(pictureFromStream.get());
915
916 SkMD5::Digest digest2;
917 md5(dst, &digest2);
918 REPORTER_ASSERT(reporter, referenceDigest == digest2);
scroggo@google.com7c9d5392012-12-10 15:40:55 +0000919}
920
junov@chromium.orgd575eed2013-05-08 15:39:13 +0000921static void test_clip_bound_opt(skiatest::Reporter* reporter) {
922 // Test for crbug.com/229011
923 SkRect rect1 = SkRect::MakeXYWH(SkIntToScalar(4), SkIntToScalar(4),
924 SkIntToScalar(2), SkIntToScalar(2));
925 SkRect rect2 = SkRect::MakeXYWH(SkIntToScalar(7), SkIntToScalar(7),
926 SkIntToScalar(1), SkIntToScalar(1));
927 SkRect rect3 = SkRect::MakeXYWH(SkIntToScalar(6), SkIntToScalar(6),
928 SkIntToScalar(1), SkIntToScalar(1));
929
930 SkPath invPath;
931 invPath.addOval(rect1);
932 invPath.setFillType(SkPath::kInverseEvenOdd_FillType);
933 SkPath path;
934 path.addOval(rect2);
935 SkPath path2;
936 path2.addOval(rect3);
937 SkIRect clipBounds;
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000938 SkPictureRecorder recorder;
reedd9544982014-09-09 18:46:22 -0700939
940 // Testing conservative-raster-clip that is enabled by PictureRecord
junov@chromium.orgd575eed2013-05-08 15:39:13 +0000941 {
robertphillips9f1c2412014-06-09 06:25:34 -0700942 SkCanvas* canvas = recorder.beginRecording(10, 10);
junov@chromium.orgd575eed2013-05-08 15:39:13 +0000943 canvas->clipPath(invPath, SkRegion::kIntersect_Op);
944 bool nonEmpty = canvas->getClipDeviceBounds(&clipBounds);
945 REPORTER_ASSERT(reporter, true == nonEmpty);
946 REPORTER_ASSERT(reporter, 0 == clipBounds.fLeft);
947 REPORTER_ASSERT(reporter, 0 == clipBounds.fTop);
948 REPORTER_ASSERT(reporter, 10 == clipBounds.fBottom);
949 REPORTER_ASSERT(reporter, 10 == clipBounds.fRight);
950 }
951 {
robertphillips9f1c2412014-06-09 06:25:34 -0700952 SkCanvas* canvas = recorder.beginRecording(10, 10);
junov@chromium.orgd575eed2013-05-08 15:39:13 +0000953 canvas->clipPath(path, SkRegion::kIntersect_Op);
954 canvas->clipPath(invPath, SkRegion::kIntersect_Op);
955 bool nonEmpty = canvas->getClipDeviceBounds(&clipBounds);
956 REPORTER_ASSERT(reporter, true == nonEmpty);
957 REPORTER_ASSERT(reporter, 7 == clipBounds.fLeft);
958 REPORTER_ASSERT(reporter, 7 == clipBounds.fTop);
959 REPORTER_ASSERT(reporter, 8 == clipBounds.fBottom);
960 REPORTER_ASSERT(reporter, 8 == clipBounds.fRight);
961 }
962 {
robertphillips9f1c2412014-06-09 06:25:34 -0700963 SkCanvas* canvas = recorder.beginRecording(10, 10);
junov@chromium.orgd575eed2013-05-08 15:39:13 +0000964 canvas->clipPath(path, SkRegion::kIntersect_Op);
965 canvas->clipPath(invPath, SkRegion::kUnion_Op);
966 bool nonEmpty = canvas->getClipDeviceBounds(&clipBounds);
967 REPORTER_ASSERT(reporter, true == nonEmpty);
968 REPORTER_ASSERT(reporter, 0 == clipBounds.fLeft);
969 REPORTER_ASSERT(reporter, 0 == clipBounds.fTop);
970 REPORTER_ASSERT(reporter, 10 == clipBounds.fBottom);
971 REPORTER_ASSERT(reporter, 10 == clipBounds.fRight);
972 }
973 {
robertphillips9f1c2412014-06-09 06:25:34 -0700974 SkCanvas* canvas = recorder.beginRecording(10, 10);
junov@chromium.orgd575eed2013-05-08 15:39:13 +0000975 canvas->clipPath(path, SkRegion::kDifference_Op);
976 bool nonEmpty = canvas->getClipDeviceBounds(&clipBounds);
977 REPORTER_ASSERT(reporter, true == nonEmpty);
978 REPORTER_ASSERT(reporter, 0 == clipBounds.fLeft);
979 REPORTER_ASSERT(reporter, 0 == clipBounds.fTop);
980 REPORTER_ASSERT(reporter, 10 == clipBounds.fBottom);
981 REPORTER_ASSERT(reporter, 10 == clipBounds.fRight);
982 }
983 {
robertphillips9f1c2412014-06-09 06:25:34 -0700984 SkCanvas* canvas = recorder.beginRecording(10, 10);
junov@chromium.orgd575eed2013-05-08 15:39:13 +0000985 canvas->clipPath(path, SkRegion::kReverseDifference_Op);
986 bool nonEmpty = canvas->getClipDeviceBounds(&clipBounds);
987 // True clip is actually empty in this case, but the best
988 // determination we can make using only bounds as input is that the
989 // clip is included in the bounds of 'path'.
990 REPORTER_ASSERT(reporter, true == nonEmpty);
991 REPORTER_ASSERT(reporter, 7 == clipBounds.fLeft);
992 REPORTER_ASSERT(reporter, 7 == clipBounds.fTop);
993 REPORTER_ASSERT(reporter, 8 == clipBounds.fBottom);
994 REPORTER_ASSERT(reporter, 8 == clipBounds.fRight);
995 }
996 {
robertphillips9f1c2412014-06-09 06:25:34 -0700997 SkCanvas* canvas = recorder.beginRecording(10, 10);
junov@chromium.orgd575eed2013-05-08 15:39:13 +0000998 canvas->clipPath(path, SkRegion::kIntersect_Op);
999 canvas->clipPath(path2, SkRegion::kXOR_Op);
1000 bool nonEmpty = canvas->getClipDeviceBounds(&clipBounds);
1001 REPORTER_ASSERT(reporter, true == nonEmpty);
1002 REPORTER_ASSERT(reporter, 6 == clipBounds.fLeft);
1003 REPORTER_ASSERT(reporter, 6 == clipBounds.fTop);
1004 REPORTER_ASSERT(reporter, 8 == clipBounds.fBottom);
1005 REPORTER_ASSERT(reporter, 8 == clipBounds.fRight);
1006 }
1007}
1008
schenneyeeff8bb2015-07-07 14:27:10 -07001009static void test_cull_rect_reset(skiatest::Reporter* reporter) {
1010 SkPictureRecorder recorder;
1011 SkRect bounds = SkRect::MakeWH(10, 10);
1012 SkRTreeFactory factory;
1013 SkCanvas* canvas = recorder.beginRecording(bounds, &factory);
1014 bounds = SkRect::MakeWH(100, 100);
1015 SkPaint paint;
1016 canvas->drawRect(bounds, paint);
1017 canvas->drawRect(bounds, paint);
reedca2622b2016-03-18 07:25:55 -07001018 sk_sp<SkPicture> p(recorder.finishRecordingAsPictureWithCull(bounds));
mtkleineedc3342015-07-08 08:26:39 -07001019 const SkBigPicture* picture = p->asSkBigPicture();
schenneyeeff8bb2015-07-07 14:27:10 -07001020 REPORTER_ASSERT(reporter, picture);
1021
1022 SkRect finalCullRect = picture->cullRect();
1023 REPORTER_ASSERT(reporter, 0 == finalCullRect.fLeft);
1024 REPORTER_ASSERT(reporter, 0 == finalCullRect.fTop);
1025 REPORTER_ASSERT(reporter, 100 == finalCullRect.fBottom);
1026 REPORTER_ASSERT(reporter, 100 == finalCullRect.fRight);
1027
1028 const SkBBoxHierarchy* pictureBBH = picture->bbh();
1029 SkRect bbhCullRect = pictureBBH->getRootBound();
1030 REPORTER_ASSERT(reporter, 0 == bbhCullRect.fLeft);
1031 REPORTER_ASSERT(reporter, 0 == bbhCullRect.fTop);
1032 REPORTER_ASSERT(reporter, 100 == bbhCullRect.fBottom);
1033 REPORTER_ASSERT(reporter, 100 == bbhCullRect.fRight);
1034}
1035
1036
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +00001037/**
1038 * A canvas that records the number of clip commands.
1039 */
1040class ClipCountingCanvas : public SkCanvas {
1041public:
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +00001042 ClipCountingCanvas(int width, int height)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +00001043 : INHERITED(width, height)
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +00001044 , fClipCount(0){
1045 }
1046
skia.committer@gmail.com370a8992014-03-01 03:02:09 +00001047 virtual void onClipRect(const SkRect& r,
1048 SkRegion::Op op,
mtklein36352bf2015-03-25 18:17:31 -07001049 ClipEdgeStyle edgeStyle) override {
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +00001050 fClipCount += 1;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001051 this->INHERITED::onClipRect(r, op, edgeStyle);
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +00001052 }
1053
skia.committer@gmail.com370a8992014-03-01 03:02:09 +00001054 virtual void onClipRRect(const SkRRect& rrect,
1055 SkRegion::Op op,
mtklein36352bf2015-03-25 18:17:31 -07001056 ClipEdgeStyle edgeStyle)override {
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +00001057 fClipCount += 1;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001058 this->INHERITED::onClipRRect(rrect, op, edgeStyle);
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +00001059 }
1060
skia.committer@gmail.com370a8992014-03-01 03:02:09 +00001061 virtual void onClipPath(const SkPath& path,
1062 SkRegion::Op op,
mtklein36352bf2015-03-25 18:17:31 -07001063 ClipEdgeStyle edgeStyle) override {
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +00001064 fClipCount += 1;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001065 this->INHERITED::onClipPath(path, op, edgeStyle);
1066 }
1067
mtklein36352bf2015-03-25 18:17:31 -07001068 void onClipRegion(const SkRegion& deviceRgn, SkRegion::Op op) override {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001069 fClipCount += 1;
1070 this->INHERITED::onClipRegion(deviceRgn, op);
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +00001071 }
1072
1073 unsigned getClipCount() const { return fClipCount; }
1074
1075private:
1076 unsigned fClipCount;
1077
1078 typedef SkCanvas INHERITED;
1079};
1080
1081static void test_clip_expansion(skiatest::Reporter* reporter) {
robertphillips@google.com84b18c72014-04-13 19:09:42 +00001082 SkPictureRecorder recorder;
robertphillips9f1c2412014-06-09 06:25:34 -07001083 SkCanvas* canvas = recorder.beginRecording(10, 10);
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +00001084
1085 canvas->clipRect(SkRect::MakeEmpty(), SkRegion::kReplace_Op);
1086 // The following expanding clip should not be skipped.
1087 canvas->clipRect(SkRect::MakeXYWH(4, 4, 3, 3), SkRegion::kUnion_Op);
1088 // Draw something so the optimizer doesn't just fold the world.
1089 SkPaint p;
1090 p.setColor(SK_ColorBLUE);
1091 canvas->drawPaint(p);
reedca2622b2016-03-18 07:25:55 -07001092 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +00001093
commit-bot@chromium.orge2543102014-01-31 19:42:58 +00001094 ClipCountingCanvas testCanvas(10, 10);
robertphillipsc5ba71d2014-09-04 08:42:50 -07001095 picture->playback(&testCanvas);
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +00001096
1097 // Both clips should be present on playback.
1098 REPORTER_ASSERT(reporter, testCanvas.getClipCount() == 2);
1099}
1100
tomhudson@google.com381010e2013-10-24 11:12:47 +00001101static void test_hierarchical(skiatest::Reporter* reporter) {
1102 SkBitmap bm;
1103 make_bm(&bm, 10, 10, SK_ColorRED, true);
1104
robertphillips@google.com84b18c72014-04-13 19:09:42 +00001105 SkPictureRecorder recorder;
tomhudson@google.com381010e2013-10-24 11:12:47 +00001106
robertphillips9f1c2412014-06-09 06:25:34 -07001107 recorder.beginRecording(10, 10);
reedca2622b2016-03-18 07:25:55 -07001108 sk_sp<SkPicture> childPlain(recorder.finishRecordingAsPicture());
robertphillips@google.com84b18c72014-04-13 19:09:42 +00001109 REPORTER_ASSERT(reporter, !childPlain->willPlayBackBitmaps()); // 0
tomhudson@google.com381010e2013-10-24 11:12:47 +00001110
robertphillips9f1c2412014-06-09 06:25:34 -07001111 recorder.beginRecording(10, 10)->drawBitmap(bm, 0, 0);
reedca2622b2016-03-18 07:25:55 -07001112 sk_sp<SkPicture> childWithBitmap(recorder.finishRecordingAsPicture());
robertphillips@google.com84b18c72014-04-13 19:09:42 +00001113 REPORTER_ASSERT(reporter, childWithBitmap->willPlayBackBitmaps()); // 1
tomhudson@google.com381010e2013-10-24 11:12:47 +00001114
robertphillips@google.com84b18c72014-04-13 19:09:42 +00001115 {
robertphillips9f1c2412014-06-09 06:25:34 -07001116 SkCanvas* canvas = recorder.beginRecording(10, 10);
robertphillips9b14f262014-06-04 05:40:44 -07001117 canvas->drawPicture(childPlain);
reedca2622b2016-03-18 07:25:55 -07001118 sk_sp<SkPicture> parentPP(recorder.finishRecordingAsPicture());
robertphillips@google.com84b18c72014-04-13 19:09:42 +00001119 REPORTER_ASSERT(reporter, !parentPP->willPlayBackBitmaps()); // 0
1120 }
1121 {
robertphillips9f1c2412014-06-09 06:25:34 -07001122 SkCanvas* canvas = recorder.beginRecording(10, 10);
robertphillips9b14f262014-06-04 05:40:44 -07001123 canvas->drawPicture(childWithBitmap);
reedca2622b2016-03-18 07:25:55 -07001124 sk_sp<SkPicture> parentPWB(recorder.finishRecordingAsPicture());
robertphillips@google.com84b18c72014-04-13 19:09:42 +00001125 REPORTER_ASSERT(reporter, parentPWB->willPlayBackBitmaps()); // 1
1126 }
1127 {
robertphillips9f1c2412014-06-09 06:25:34 -07001128 SkCanvas* canvas = recorder.beginRecording(10, 10);
robertphillips@google.com84b18c72014-04-13 19:09:42 +00001129 canvas->drawBitmap(bm, 0, 0);
robertphillips9b14f262014-06-04 05:40:44 -07001130 canvas->drawPicture(childPlain);
reedca2622b2016-03-18 07:25:55 -07001131 sk_sp<SkPicture> parentWBP(recorder.finishRecordingAsPicture());
robertphillips@google.com84b18c72014-04-13 19:09:42 +00001132 REPORTER_ASSERT(reporter, parentWBP->willPlayBackBitmaps()); // 1
1133 }
1134 {
robertphillips9f1c2412014-06-09 06:25:34 -07001135 SkCanvas* canvas = recorder.beginRecording(10, 10);
robertphillips@google.com84b18c72014-04-13 19:09:42 +00001136 canvas->drawBitmap(bm, 0, 0);
robertphillips9b14f262014-06-04 05:40:44 -07001137 canvas->drawPicture(childWithBitmap);
reedca2622b2016-03-18 07:25:55 -07001138 sk_sp<SkPicture> parentWBWB(recorder.finishRecordingAsPicture());
robertphillips@google.com84b18c72014-04-13 19:09:42 +00001139 REPORTER_ASSERT(reporter, parentWBWB->willPlayBackBitmaps()); // 2
1140 }
tomhudson@google.com381010e2013-10-24 11:12:47 +00001141}
1142
robertphillips@google.comd5500882014-04-02 23:51:13 +00001143static void test_gen_id(skiatest::Reporter* reporter) {
1144
Robert Phillipscfaeec42014-07-13 12:00:50 -04001145 SkPictureRecorder recorder;
1146 recorder.beginRecording(0, 0);
reedca2622b2016-03-18 07:25:55 -07001147 sk_sp<SkPicture> empty(recorder.finishRecordingAsPicture());
robertphillips@google.comd5500882014-04-02 23:51:13 +00001148
robertphillips@google.com84b18c72014-04-13 19:09:42 +00001149 // Empty pictures should still have a valid ID
Robert Phillipscfaeec42014-07-13 12:00:50 -04001150 REPORTER_ASSERT(reporter, empty->uniqueID() != SK_InvalidGenID);
robertphillips@google.comd5500882014-04-02 23:51:13 +00001151
robertphillips9f1c2412014-06-09 06:25:34 -07001152 SkCanvas* canvas = recorder.beginRecording(1, 1);
robertphillips@google.com84b18c72014-04-13 19:09:42 +00001153 canvas->drawARGB(255, 255, 255, 255);
reedca2622b2016-03-18 07:25:55 -07001154 sk_sp<SkPicture> hasData(recorder.finishRecordingAsPicture());
robertphillips@google.com84b18c72014-04-13 19:09:42 +00001155 // picture should have a non-zero id after recording
1156 REPORTER_ASSERT(reporter, hasData->uniqueID() != SK_InvalidGenID);
robertphillips@google.comd5500882014-04-02 23:51:13 +00001157
robertphillips@google.com84b18c72014-04-13 19:09:42 +00001158 // both pictures should have different ids
Robert Phillipscfaeec42014-07-13 12:00:50 -04001159 REPORTER_ASSERT(reporter, hasData->uniqueID() != empty->uniqueID());
robertphillips@google.comd5500882014-04-02 23:51:13 +00001160}
1161
caryclark5ef194c2015-08-31 09:22:38 -07001162static void test_typeface(skiatest::Reporter* reporter) {
1163 SkPictureRecorder recorder;
1164 SkCanvas* canvas = recorder.beginRecording(10, 10);
1165 SkPaint paint;
mbocee6a9912016-05-31 11:42:36 -07001166 paint.setTypeface(SkTypeface::MakeFromName("Arial",
1167 SkFontStyle::FromOldStyle(SkTypeface::kItalic)));
caryclark5ef194c2015-08-31 09:22:38 -07001168 canvas->drawText("Q", 1, 0, 10, paint);
reedca2622b2016-03-18 07:25:55 -07001169 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
caryclark5ef194c2015-08-31 09:22:38 -07001170 SkDynamicMemoryWStream stream;
1171 picture->serialize(&stream);
1172}
1173
tfarina@chromium.orge4fafb12013-12-12 21:11:12 +00001174DEF_TEST(Picture, reporter) {
caryclark5ef194c2015-08-31 09:22:38 -07001175 test_typeface(reporter);
scroggo@google.comd614c6a2012-09-14 17:26:37 +00001176#ifdef SK_DEBUG
robertphillipsdb539902014-07-01 08:47:04 -07001177 test_deleting_empty_picture();
scroggo@google.comd614c6a2012-09-14 17:26:37 +00001178 test_serializing_empty_picture();
scroggo@google.com4b90b112012-12-04 15:08:56 +00001179#else
1180 test_bad_bitmap();
scroggo@google.comd614c6a2012-09-14 17:26:37 +00001181#endif
commit-bot@chromium.orgea7d08e2014-02-13 16:00:51 +00001182 test_unbalanced_save_restores(reporter);
sugoi@google.com54f0d1b2013-02-27 19:17:41 +00001183 test_peephole();
robertphillips@google.comb950c6f2014-04-25 00:02:12 +00001184#if SK_SUPPORT_GPU
mtklein8e126562014-10-01 09:29:35 -07001185 test_gpu_veto(reporter);
robertphillips@google.comb950c6f2014-04-25 00:02:12 +00001186#endif
mtkleina16af212015-08-26 08:14:52 -07001187 test_images_are_found_by_willPlayBackBitmaps(reporter);
mtklein8e126562014-10-01 09:29:35 -07001188 test_analysis(reporter);
junov@chromium.orgd575eed2013-05-08 15:39:13 +00001189 test_clip_bound_opt(reporter);
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +00001190 test_clip_expansion(reporter);
tomhudson@google.com381010e2013-10-24 11:12:47 +00001191 test_hierarchical(reporter);
robertphillips@google.comd5500882014-04-02 23:51:13 +00001192 test_gen_id(reporter);
robertphillips82365912014-11-12 09:32:34 -08001193 test_savelayer_extraction(reporter);
schenneyeeff8bb2015-07-07 14:27:10 -07001194 test_cull_rect_reset(reporter);
scroggo@google.comd614c6a2012-09-14 17:26:37 +00001195}
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001196
1197static void draw_bitmaps(const SkBitmap bitmap, SkCanvas* canvas) {
1198 const SkPaint paint;
1199 const SkRect rect = { 5.0f, 5.0f, 8.0f, 8.0f };
1200 const SkIRect irect = { 2, 2, 3, 3 };
1201
1202 // Don't care what these record, as long as they're legal.
1203 canvas->drawBitmap(bitmap, 0.0f, 0.0f, &paint);
reede47829b2015-08-06 10:02:53 -07001204 canvas->drawBitmapRect(bitmap, rect, rect, &paint, SkCanvas::kStrict_SrcRectConstraint);
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001205 canvas->drawBitmapNine(bitmap, irect, rect, &paint);
reedda420b92015-12-16 08:38:15 -08001206 canvas->drawBitmap(bitmap, 1, 1); // drawSprite
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001207}
1208
1209static void test_draw_bitmaps(SkCanvas* canvas) {
1210 SkBitmap empty;
1211 draw_bitmaps(empty, canvas);
commit-bot@chromium.orga3264e52014-05-30 13:26:10 +00001212 empty.setInfo(SkImageInfo::MakeN32Premul(10, 10));
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001213 draw_bitmaps(empty, canvas);
1214}
1215
1216DEF_TEST(Picture_EmptyBitmap, r) {
robertphillips@google.com84b18c72014-04-13 19:09:42 +00001217 SkPictureRecorder recorder;
robertphillips9f1c2412014-06-09 06:25:34 -07001218 test_draw_bitmaps(recorder.beginRecording(10, 10));
reedca2622b2016-03-18 07:25:55 -07001219 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001220}
1221
1222DEF_TEST(Canvas_EmptyBitmap, r) {
1223 SkBitmap dst;
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +00001224 dst.allocN32Pixels(10, 10);
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001225 SkCanvas canvas(dst);
1226
1227 test_draw_bitmaps(&canvas);
1228}
dneto3f22e8c2014-07-30 15:42:22 -07001229
1230DEF_TEST(DontOptimizeSaveLayerDrawDrawRestore, reporter) {
1231 // This test is from crbug.com/344987.
1232 // The commands are:
1233 // saveLayer with paint that modifies alpha
reed84984ef2015-07-17 07:09:43 -07001234 // drawBitmapRect
1235 // drawBitmapRect
dneto3f22e8c2014-07-30 15:42:22 -07001236 // restore
1237 // The bug was that this structure was modified so that:
1238 // - The saveLayer and restore were eliminated
1239 // - The alpha was only applied to the first drawBitmapRectToRect
1240
1241 // This test draws blue and red squares inside a 50% transparent
1242 // layer. Both colours should show up muted.
1243 // When the bug is present, the red square (the second bitmap)
1244 // shows upwith full opacity.
1245
1246 SkBitmap blueBM;
1247 make_bm(&blueBM, 100, 100, SkColorSetARGB(255, 0, 0, 255), true);
1248 SkBitmap redBM;
1249 make_bm(&redBM, 100, 100, SkColorSetARGB(255, 255, 0, 0), true);
1250 SkPaint semiTransparent;
1251 semiTransparent.setAlpha(0x80);
1252
1253 SkPictureRecorder recorder;
1254 SkCanvas* canvas = recorder.beginRecording(100, 100);
1255 canvas->drawARGB(0, 0, 0, 0);
1256
1257 canvas->saveLayer(0, &semiTransparent);
1258 canvas->drawBitmap(blueBM, 25, 25);
1259 canvas->drawBitmap(redBM, 50, 50);
1260 canvas->restore();
1261
reedca2622b2016-03-18 07:25:55 -07001262 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
dneto3f22e8c2014-07-30 15:42:22 -07001263
1264 // Now replay the picture back on another canvas
1265 // and check a couple of its pixels.
1266 SkBitmap replayBM;
1267 make_bm(&replayBM, 100, 100, SK_ColorBLACK, false);
1268 SkCanvas replayCanvas(replayBM);
robertphillipsc5ba71d2014-09-04 08:42:50 -07001269 picture->playback(&replayCanvas);
dneto3f22e8c2014-07-30 15:42:22 -07001270 replayCanvas.flush();
1271
1272 // With the bug present, at (55, 55) we would get a fully opaque red
1273 // intead of a dark red.
1274 REPORTER_ASSERT(reporter, replayBM.getColor(30, 30) == 0xff000080);
1275 REPORTER_ASSERT(reporter, replayBM.getColor(55, 55) == 0xff800000);
1276}
mtklein3e8232b2014-08-18 13:39:11 -07001277
1278struct CountingBBH : public SkBBoxHierarchy {
1279 mutable int searchCalls;
schenney23d85932015-03-06 16:20:28 -08001280 SkRect rootBound;
mtklein3e8232b2014-08-18 13:39:11 -07001281
schenney23d85932015-03-06 16:20:28 -08001282 CountingBBH(const SkRect& bound) : searchCalls(0), rootBound(bound) {}
mtklein3e8232b2014-08-18 13:39:11 -07001283
mtkleinc6ad06a2015-08-19 09:51:00 -07001284 void search(const SkRect& query, SkTDArray<int>* results) const override {
mtklein3e8232b2014-08-18 13:39:11 -07001285 this->searchCalls++;
1286 }
1287
mtklein36352bf2015-03-25 18:17:31 -07001288 void insert(const SkRect[], int) override {}
1289 virtual size_t bytesUsed() const override { return 0; }
1290 SkRect getRootBound() const override { return rootBound; }
mtklein3e8232b2014-08-18 13:39:11 -07001291};
1292
1293class SpoonFedBBHFactory : public SkBBHFactory {
1294public:
1295 explicit SpoonFedBBHFactory(SkBBoxHierarchy* bbh) : fBBH(bbh) {}
mtklein36352bf2015-03-25 18:17:31 -07001296 SkBBoxHierarchy* operator()(const SkRect&) const override {
mtklein3e8232b2014-08-18 13:39:11 -07001297 return SkRef(fBBH);
1298 }
1299private:
1300 SkBBoxHierarchy* fBBH;
1301};
1302
1303// When the canvas clip covers the full picture, we don't need to call the BBH.
1304DEF_TEST(Picture_SkipBBH, r) {
schenney23d85932015-03-06 16:20:28 -08001305 SkRect bound = SkRect::MakeWH(320, 240);
1306 CountingBBH bbh(bound);
mtklein3e8232b2014-08-18 13:39:11 -07001307 SpoonFedBBHFactory factory(&bbh);
1308
1309 SkPictureRecorder recorder;
mtklein9db912c2015-05-19 11:11:26 -07001310 SkCanvas* c = recorder.beginRecording(bound, &factory);
1311 // Record a few ops so we don't hit a small- or empty- picture optimization.
1312 c->drawRect(bound, SkPaint());
1313 c->drawRect(bound, SkPaint());
reedca2622b2016-03-18 07:25:55 -07001314 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
mtklein3e8232b2014-08-18 13:39:11 -07001315
1316 SkCanvas big(640, 480), small(300, 200);
1317
robertphillipsc5ba71d2014-09-04 08:42:50 -07001318 picture->playback(&big);
mtklein3e8232b2014-08-18 13:39:11 -07001319 REPORTER_ASSERT(r, bbh.searchCalls == 0);
1320
robertphillipsc5ba71d2014-09-04 08:42:50 -07001321 picture->playback(&small);
mtklein3e8232b2014-08-18 13:39:11 -07001322 REPORTER_ASSERT(r, bbh.searchCalls == 1);
1323}
mtkleind72094d2014-08-27 12:12:23 -07001324
1325DEF_TEST(Picture_BitmapLeak, r) {
1326 SkBitmap mut, immut;
1327 mut.allocN32Pixels(300, 200);
1328 immut.allocN32Pixels(300, 200);
1329 immut.setImmutable();
1330 SkASSERT(!mut.isImmutable());
1331 SkASSERT(immut.isImmutable());
1332
1333 // No one can hold a ref on our pixels yet.
1334 REPORTER_ASSERT(r, mut.pixelRef()->unique());
1335 REPORTER_ASSERT(r, immut.pixelRef()->unique());
1336
reedca2622b2016-03-18 07:25:55 -07001337 sk_sp<SkPicture> pic;
reed1bdfd3f2014-11-24 14:41:51 -08001338 {
1339 // we want the recorder to go out of scope before our subsequent checks, so we
1340 // place it inside local braces.
1341 SkPictureRecorder rec;
1342 SkCanvas* canvas = rec.beginRecording(1920, 1200);
1343 canvas->drawBitmap(mut, 0, 0);
1344 canvas->drawBitmap(immut, 800, 600);
reedca2622b2016-03-18 07:25:55 -07001345 pic = rec.finishRecordingAsPicture();
reed1bdfd3f2014-11-24 14:41:51 -08001346 }
mtkleind72094d2014-08-27 12:12:23 -07001347
1348 // The picture shares the immutable pixels but copies the mutable ones.
1349 REPORTER_ASSERT(r, mut.pixelRef()->unique());
1350 REPORTER_ASSERT(r, !immut.pixelRef()->unique());
1351
1352 // When the picture goes away, it's just our bitmaps holding the refs.
reedca2622b2016-03-18 07:25:55 -07001353 pic = nullptr;
mtkleind72094d2014-08-27 12:12:23 -07001354 REPORTER_ASSERT(r, mut.pixelRef()->unique());
1355 REPORTER_ASSERT(r, immut.pixelRef()->unique());
1356}
mtkleinfeaadee2015-04-08 11:25:48 -07001357
1358// getRecordingCanvas() should return a SkCanvas when recording, null when not recording.
1359DEF_TEST(Picture_getRecordingCanvas, r) {
1360 SkPictureRecorder rec;
1361 REPORTER_ASSERT(r, !rec.getRecordingCanvas());
1362 for (int i = 0; i < 3; i++) {
1363 rec.beginRecording(100, 100);
1364 REPORTER_ASSERT(r, rec.getRecordingCanvas());
reedca2622b2016-03-18 07:25:55 -07001365 rec.finishRecordingAsPicture();
mtkleinfeaadee2015-04-08 11:25:48 -07001366 REPORTER_ASSERT(r, !rec.getRecordingCanvas());
1367 }
1368}
mtklein9db912c2015-05-19 11:11:26 -07001369
1370DEF_TEST(MiniRecorderLeftHanging, r) {
1371 // Any shader or other ref-counted effect will do just fine here.
1372 SkPaint paint;
reed1a9b9642016-03-13 14:13:58 -07001373 paint.setShader(SkShader::MakeColorShader(SK_ColorRED));
mtklein9db912c2015-05-19 11:11:26 -07001374
1375 SkMiniRecorder rec;
1376 REPORTER_ASSERT(r, rec.drawRect(SkRect::MakeWH(20,30), paint));
1377 // Don't call rec.detachPicture(). Test succeeds by not asserting or leaking the shader.
1378}
fmalita2ecc0002015-07-14 13:12:25 -07001379
1380DEF_TEST(Picture_preserveCullRect, r) {
1381 SkPictureRecorder recorder;
1382
1383 SkCanvas* c = recorder.beginRecording(SkRect::MakeLTRB(1, 2, 3, 4));
1384 c->clear(SK_ColorCYAN);
1385
reedca2622b2016-03-18 07:25:55 -07001386 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
fmalita2ecc0002015-07-14 13:12:25 -07001387 SkDynamicMemoryWStream wstream;
1388 picture->serialize(&wstream);
1389
1390 SkAutoTDelete<SkStream> rstream(wstream.detachAsStream());
reedca2622b2016-03-18 07:25:55 -07001391 sk_sp<SkPicture> deserializedPicture(SkPicture::MakeFromStream(rstream));
fmalita2ecc0002015-07-14 13:12:25 -07001392
mtklein5f939ab2016-03-16 10:28:35 -07001393 REPORTER_ASSERT(r, deserializedPicture != nullptr);
fmalita2ecc0002015-07-14 13:12:25 -07001394 REPORTER_ASSERT(r, deserializedPicture->cullRect().left() == 1);
1395 REPORTER_ASSERT(r, deserializedPicture->cullRect().top() == 2);
1396 REPORTER_ASSERT(r, deserializedPicture->cullRect().right() == 3);
1397 REPORTER_ASSERT(r, deserializedPicture->cullRect().bottom() == 4);
1398}
fmalita796e3652016-05-13 11:40:07 -07001399
1400#if SK_SUPPORT_GPU
1401
1402DEF_TEST(PictureGpuAnalyzer, r) {
1403 SkPictureRecorder recorder;
1404
1405 {
1406 SkCanvas* canvas = recorder.beginRecording(10, 10);
1407 SkPaint paint;
1408 SkScalar intervals [] = { 10, 20 };
1409 paint.setPathEffect(SkDashPathEffect::Make(intervals, 2, 25));
1410
1411 for (int i = 0; i < 50; ++i) {
1412 canvas->drawRect(SkRect::MakeWH(10, 10), paint);
1413 }
1414 }
1415 sk_sp<SkPicture> vetoPicture(recorder.finishRecordingAsPicture());
1416
1417 SkPictureGpuAnalyzer analyzer;
1418 REPORTER_ASSERT(r, analyzer.suitableForGpuRasterization());
1419
fmalita019db3f2016-05-31 06:32:57 -07001420 analyzer.analyzePicture(vetoPicture.get());
fmalita796e3652016-05-13 11:40:07 -07001421 REPORTER_ASSERT(r, !analyzer.suitableForGpuRasterization());
1422
1423 analyzer.reset();
1424 REPORTER_ASSERT(r, analyzer.suitableForGpuRasterization());
1425
1426 recorder.beginRecording(10, 10)->drawPicture(vetoPicture);
1427 sk_sp<SkPicture> nestedVetoPicture(recorder.finishRecordingAsPicture());
1428
fmalita019db3f2016-05-31 06:32:57 -07001429 analyzer.analyzePicture(nestedVetoPicture.get());
fmalita796e3652016-05-13 11:40:07 -07001430 REPORTER_ASSERT(r, !analyzer.suitableForGpuRasterization());
fmalitab5fc58e2016-05-25 11:31:04 -07001431
1432 analyzer.reset();
1433
1434 const SkPath convexClip = make_convex_path();
1435 const SkPath concaveClip = make_concave_path();
1436 for (int i = 0; i < 50; ++i) {
1437 analyzer.analyzeClipPath(convexClip, SkRegion::kIntersect_Op, false);
1438 analyzer.analyzeClipPath(convexClip, SkRegion::kIntersect_Op, true);
1439 analyzer.analyzeClipPath(concaveClip, SkRegion::kIntersect_Op, false);
1440 }
1441 REPORTER_ASSERT(r, analyzer.suitableForGpuRasterization());
1442
1443 for (int i = 0; i < 50; ++i) {
1444 analyzer.analyzeClipPath(concaveClip, SkRegion::kIntersect_Op, true);
1445 }
1446 REPORTER_ASSERT(r, !analyzer.suitableForGpuRasterization());
fmalita796e3652016-05-13 11:40:07 -07001447}
1448
1449#endif // SK_SUPPORT_GPU