blob: f6ed59e81a9af0e82a2491a7c4e8cfc8918e2954 [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"
robertphillips@google.com770963f2014-04-18 18:04:41 +000023#include "SkPictureRecorder.h"
robertphillips@google.com1f2f3382013-08-29 11:54:56 +000024#include "SkPictureUtils.h"
mtkleind72094d2014-08-27 12:12:23 -070025#include "SkPixelRef.h"
scroggo895c43b2014-12-11 10:53:58 -080026#include "SkPixelSerializer.h"
mtklein9db912c2015-05-19 11:11:26 -070027#include "SkMiniRecorder.h"
reed@google.com72aa79c2013-01-24 18:27:42 +000028#include "SkRRect.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000029#include "SkRandom.h"
tomhudson158fcaa2014-11-19 10:41:14 -080030#include "SkRecord.h"
reed@google.comfe7b1ed2012-11-29 21:00:39 +000031#include "SkShader.h"
scroggo@google.comd614c6a2012-09-14 17:26:37 +000032#include "SkStream.h"
robertphillips3e5c2b12015-03-23 05:46:51 -070033#include "sk_tool_utils.h"
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +000034
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000035#include "Test.h"
scroggo@google.comd614c6a2012-09-14 17:26:37 +000036
reed@google.com47b679b2014-05-14 18:58:16 +000037#include "SkLumaColorFilter.h"
38#include "SkColorFilterImageFilter.h"
39
reed@google.comfe7b1ed2012-11-29 21:00:39 +000040static void make_bm(SkBitmap* bm, int w, int h, SkColor color, bool immutable) {
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +000041 bm->allocN32Pixels(w, h);
reed@google.comfe7b1ed2012-11-29 21:00:39 +000042 bm->eraseColor(color);
43 if (immutable) {
44 bm->setImmutable();
45 }
46}
47
mtkleina16af212015-08-26 08:14:52 -070048// For a while willPlayBackBitmaps() ignored SkImages and just looked for SkBitmaps.
49static void test_images_are_found_by_willPlayBackBitmaps(skiatest::Reporter* reporter) {
reede3b38ce2016-01-08 09:18:44 -080050 // We just need _some_ SkImage
51 const SkPMColor pixel = 0;
52 const SkImageInfo info = SkImageInfo::MakeN32Premul(1, 1);
reed9ce9d672016-03-17 10:51:11 -070053 sk_sp<SkImage> image(SkImage::MakeRasterCopy(SkPixmap(info, &pixel, sizeof(pixel))));
mtkleina16af212015-08-26 08:14:52 -070054
55 SkPictureRecorder recorder;
reede3b38ce2016-01-08 09:18:44 -080056 recorder.beginRecording(100,100)->drawImage(image, 0,0);
reedca2622b2016-03-18 07:25:55 -070057 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
mtkleina16af212015-08-26 08:14:52 -070058
59 REPORTER_ASSERT(reporter, picture->willPlayBackBitmaps());
60}
61
tomhudson3a0f2792014-08-20 05:29:41 -070062/* Hit a few SkPicture::Analysis cases not handled elsewhere. */
mtklein8e126562014-10-01 09:29:35 -070063static void test_analysis(skiatest::Reporter* reporter) {
tomhudson3a0f2792014-08-20 05:29:41 -070064 SkPictureRecorder recorder;
65
mtklein8e126562014-10-01 09:29:35 -070066 SkCanvas* canvas = recorder.beginRecording(100, 100);
tomhudson3a0f2792014-08-20 05:29:41 -070067 {
68 canvas->drawRect(SkRect::MakeWH(10, 10), SkPaint ());
69 }
reedca2622b2016-03-18 07:25:55 -070070 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
tomhudson3a0f2792014-08-20 05:29:41 -070071 REPORTER_ASSERT(reporter, !picture->willPlayBackBitmaps());
72
mtklein8e126562014-10-01 09:29:35 -070073 canvas = recorder.beginRecording(100, 100);
tomhudson3a0f2792014-08-20 05:29:41 -070074 {
75 SkPaint paint;
76 // CreateBitmapShader is too smart for us; an empty (or 1x1) bitmap shader
77 // gets optimized into a non-bitmap form, so we create a 2x2 bitmap here.
78 SkBitmap bitmap;
79 bitmap.allocPixels(SkImageInfo::MakeN32Premul(2, 2));
80 bitmap.eraseColor(SK_ColorBLUE);
81 *(bitmap.getAddr32(0, 0)) = SK_ColorGREEN;
reed1a9b9642016-03-13 14:13:58 -070082 paint.setShader(SkShader::MakeBitmapShader(bitmap, SkShader::kClamp_TileMode,
83 SkShader::kClamp_TileMode));
84 REPORTER_ASSERT(reporter, paint.getShader()->isABitmap());
tomhudson3a0f2792014-08-20 05:29:41 -070085
86 canvas->drawRect(SkRect::MakeWH(10, 10), paint);
87 }
reedca2622b2016-03-18 07:25:55 -070088 REPORTER_ASSERT(reporter, recorder.finishRecordingAsPicture()->willPlayBackBitmaps());
tomhudson3a0f2792014-08-20 05:29:41 -070089}
90
91
scroggo@google.comd614c6a2012-09-14 17:26:37 +000092#ifdef SK_DEBUG
mtklein3e8232b2014-08-18 13:39:11 -070093// Ensure that deleting an empty SkPicture does not assert. Asserts only fire
robertphillipsdb539902014-07-01 08:47:04 -070094// in debug mode, so only run in debug mode.
95static void test_deleting_empty_picture() {
robertphillips@google.com84b18c72014-04-13 19:09:42 +000096 SkPictureRecorder recorder;
scroggo@google.comd614c6a2012-09-14 17:26:37 +000097 // Creates an SkPictureRecord
robertphillips9f1c2412014-06-09 06:25:34 -070098 recorder.beginRecording(0, 0);
robertphillipsdb539902014-07-01 08:47:04 -070099 // Turns that into an SkPicture
reedca2622b2016-03-18 07:25:55 -0700100 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
robertphillipsdb539902014-07-01 08:47:04 -0700101 // Ceates a new SkPictureRecord
robertphillips9f1c2412014-06-09 06:25:34 -0700102 recorder.beginRecording(0, 0);
scroggo@google.comd614c6a2012-09-14 17:26:37 +0000103}
104
105// Ensure that serializing an empty picture does not assert. Likewise only runs in debug mode.
106static void test_serializing_empty_picture() {
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000107 SkPictureRecorder recorder;
robertphillips9f1c2412014-06-09 06:25:34 -0700108 recorder.beginRecording(0, 0);
reedca2622b2016-03-18 07:25:55 -0700109 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
scroggo@google.comd614c6a2012-09-14 17:26:37 +0000110 SkDynamicMemoryWStream stream;
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000111 picture->serialize(&stream);
scroggo@google.comd614c6a2012-09-14 17:26:37 +0000112}
113#endif
114
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000115static void rand_op(SkCanvas* canvas, SkRandom& rand) {
reed@google.com21b519d2012-10-02 17:42:15 +0000116 SkPaint paint;
117 SkRect rect = SkRect::MakeWH(50, 50);
118
119 SkScalar unit = rand.nextUScalar1();
120 if (unit <= 0.3) {
121// SkDebugf("save\n");
122 canvas->save();
123 } else if (unit <= 0.6) {
124// SkDebugf("restore\n");
125 canvas->restore();
126 } else if (unit <= 0.9) {
127// SkDebugf("clip\n");
128 canvas->clipRect(rect);
129 } else {
130// SkDebugf("draw\n");
131 canvas->drawPaint(paint);
132 }
133}
134
robertphillips@google.comb950c6f2014-04-25 00:02:12 +0000135#if SK_SUPPORT_GPU
tomhudson3a0f2792014-08-20 05:29:41 -0700136
mtklein8e126562014-10-01 09:29:35 -0700137static void test_gpu_veto(skiatest::Reporter* reporter) {
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +0000138 SkPictureRecorder recorder;
139
mtklein8e126562014-10-01 09:29:35 -0700140 SkCanvas* canvas = recorder.beginRecording(100, 100);
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +0000141 {
142 SkPath path;
143 path.moveTo(0, 0);
144 path.lineTo(50, 50);
145
146 SkScalar intervals[] = { 1.0f, 1.0f };
reeda4393342016-03-18 11:22:57 -0700147 sk_sp<SkPathEffect> dash(SkDashPathEffect::Make(intervals, 2, 0));
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +0000148
149 SkPaint paint;
150 paint.setStyle(SkPaint::kStroke_Style);
151 paint.setPathEffect(dash);
152
robertphillips98b03152015-01-26 11:29:36 -0800153 for (int i = 0; i < 50; ++i) {
154 canvas->drawPath(path, paint);
155 }
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +0000156 }
reedca2622b2016-03-18 07:25:55 -0700157 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +0000158 // path effects currently render an SkPicture undesireable for GPU rendering
commit-bot@chromium.orga1ff26a2014-05-30 21:52:52 +0000159
halcanary96fcdcc2015-08-27 07:41:13 -0700160 const char *reason = nullptr;
161 REPORTER_ASSERT(reporter, !picture->suitableForGpuRasterization(nullptr, &reason));
bsalomon49f085d2014-09-05 13:34:00 -0700162 REPORTER_ASSERT(reporter, reason);
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +0000163
mtklein8e126562014-10-01 09:29:35 -0700164 canvas = recorder.beginRecording(100, 100);
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +0000165 {
166 SkPath path;
167
168 path.moveTo(0, 0);
169 path.lineTo(0, 50);
170 path.lineTo(25, 25);
171 path.lineTo(50, 50);
172 path.lineTo(50, 0);
173 path.close();
174 REPORTER_ASSERT(reporter, !path.isConvex());
175
176 SkPaint paint;
177 paint.setAntiAlias(true);
178 for (int i = 0; i < 50; ++i) {
179 canvas->drawPath(path, paint);
180 }
181 }
reedca2622b2016-03-18 07:25:55 -0700182 picture = recorder.finishRecordingAsPicture();
jvanverthd86b07a2014-11-04 08:50:15 -0800183 // A lot of small AA concave paths should be fine for GPU rendering
halcanary96fcdcc2015-08-27 07:41:13 -0700184 REPORTER_ASSERT(reporter, picture->suitableForGpuRasterization(nullptr));
jvanverthd86b07a2014-11-04 08:50:15 -0800185
186 canvas = recorder.beginRecording(100, 100);
187 {
188 SkPath path;
189
190 path.moveTo(0, 0);
191 path.lineTo(0, 100);
192 path.lineTo(50, 50);
193 path.lineTo(100, 100);
194 path.lineTo(100, 0);
195 path.close();
196 REPORTER_ASSERT(reporter, !path.isConvex());
197
198 SkPaint paint;
199 paint.setAntiAlias(true);
200 for (int i = 0; i < 50; ++i) {
201 canvas->drawPath(path, paint);
202 }
203 }
reedca2622b2016-03-18 07:25:55 -0700204 picture = recorder.finishRecordingAsPicture();
jvanverthd86b07a2014-11-04 08:50:15 -0800205 // A lot of large AA concave paths currently render an SkPicture undesireable for GPU rendering
halcanary96fcdcc2015-08-27 07:41:13 -0700206 REPORTER_ASSERT(reporter, !picture->suitableForGpuRasterization(nullptr));
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +0000207
mtklein8e126562014-10-01 09:29:35 -0700208 canvas = recorder.beginRecording(100, 100);
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +0000209 {
210 SkPath path;
211
212 path.moveTo(0, 0);
213 path.lineTo(0, 50);
214 path.lineTo(25, 25);
215 path.lineTo(50, 50);
216 path.lineTo(50, 0);
217 path.close();
218 REPORTER_ASSERT(reporter, !path.isConvex());
219
220 SkPaint paint;
221 paint.setAntiAlias(true);
222 paint.setStyle(SkPaint::kStroke_Style);
223 paint.setStrokeWidth(0);
224 for (int i = 0; i < 50; ++i) {
225 canvas->drawPath(path, paint);
226 }
227 }
reedca2622b2016-03-18 07:25:55 -0700228 picture = recorder.finishRecordingAsPicture();
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +0000229 // hairline stroked AA concave paths are fine for GPU rendering
halcanary96fcdcc2015-08-27 07:41:13 -0700230 REPORTER_ASSERT(reporter, picture->suitableForGpuRasterization(nullptr));
tomhudson3a0f2792014-08-20 05:29:41 -0700231
mtklein8e126562014-10-01 09:29:35 -0700232 canvas = recorder.beginRecording(100, 100);
tomhudson3a0f2792014-08-20 05:29:41 -0700233 {
234 SkPaint paint;
235 SkScalar intervals [] = { 10, 20 };
reeda4393342016-03-18 11:22:57 -0700236 paint.setPathEffect(SkDashPathEffect::Make(intervals, 2, 25));
tomhudson3a0f2792014-08-20 05:29:41 -0700237
238 SkPoint points [2] = { { 0, 0 }, { 100, 0 } };
robertphillips98b03152015-01-26 11:29:36 -0800239
240 for (int i = 0; i < 50; ++i) {
241 canvas->drawPoints(SkCanvas::kLines_PointMode, 2, points, paint);
242 }
tomhudson3a0f2792014-08-20 05:29:41 -0700243 }
reedca2622b2016-03-18 07:25:55 -0700244 picture = recorder.finishRecordingAsPicture();
tomhudson3a0f2792014-08-20 05:29:41 -0700245 // fast-path dashed effects are fine for GPU rendering ...
halcanary96fcdcc2015-08-27 07:41:13 -0700246 REPORTER_ASSERT(reporter, picture->suitableForGpuRasterization(nullptr));
tomhudson3a0f2792014-08-20 05:29:41 -0700247
mtklein8e126562014-10-01 09:29:35 -0700248 canvas = recorder.beginRecording(100, 100);
tomhudson3a0f2792014-08-20 05:29:41 -0700249 {
250 SkPaint paint;
251 SkScalar intervals [] = { 10, 20 };
reeda4393342016-03-18 11:22:57 -0700252 paint.setPathEffect(SkDashPathEffect::Make(intervals, 2, 25));
tomhudson3a0f2792014-08-20 05:29:41 -0700253
robertphillips98b03152015-01-26 11:29:36 -0800254 for (int i = 0; i < 50; ++i) {
255 canvas->drawRect(SkRect::MakeWH(10, 10), paint);
256 }
tomhudson3a0f2792014-08-20 05:29:41 -0700257 }
reedca2622b2016-03-18 07:25:55 -0700258 picture = recorder.finishRecordingAsPicture();
tomhudson3a0f2792014-08-20 05:29:41 -0700259 // ... but only when applied to drawPoint() calls
halcanary96fcdcc2015-08-27 07:41:13 -0700260 REPORTER_ASSERT(reporter, !picture->suitableForGpuRasterization(nullptr));
mtklein53fecfb2014-08-21 09:11:37 -0700261
262 // Nest the previous picture inside a new one.
mtklein8e126562014-10-01 09:29:35 -0700263 canvas = recorder.beginRecording(100, 100);
264 {
265 canvas->drawPicture(picture.get());
mtklein53fecfb2014-08-21 09:11:37 -0700266 }
reedca2622b2016-03-18 07:25:55 -0700267 picture = recorder.finishRecordingAsPicture();
halcanary96fcdcc2015-08-27 07:41:13 -0700268 REPORTER_ASSERT(reporter, !picture->suitableForGpuRasterization(nullptr));
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +0000269}
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +0000270
robertphillips82365912014-11-12 09:32:34 -0800271#endif
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +0000272
robertphillips82365912014-11-12 09:32:34 -0800273static void test_savelayer_extraction(skiatest::Reporter* reporter) {
274 static const int kWidth = 100;
275 static const int kHeight = 100;
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +0000276
robertphillips82365912014-11-12 09:32:34 -0800277 // Create complex paint that the bounding box computation code can't
278 // optimize away
279 SkScalar blueToRedMatrix[20] = { 0 };
280 blueToRedMatrix[2] = blueToRedMatrix[18] = SK_Scalar1;
robertphillips5605b562016-04-05 11:50:42 -0700281 sk_sp<SkColorFilter> blueToRed(SkColorFilter::MakeMatrixFilterRowMajor255(blueToRedMatrix));
282 sk_sp<SkImageFilter> filter(SkColorFilterImageFilter::Make(std::move(blueToRed), nullptr));
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +0000283
robertphillips82365912014-11-12 09:32:34 -0800284 SkPaint complexPaint;
robertphillips5605b562016-04-05 11:50:42 -0700285 complexPaint.setImageFilter(std::move(filter));
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +0000286
reedca2622b2016-03-18 07:25:55 -0700287 sk_sp<SkPicture> pict, child;
robertphillips82365912014-11-12 09:32:34 -0800288 SkRTreeFactory bbhFactory;
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +0000289
robertphillips82365912014-11-12 09:32:34 -0800290 {
291 SkPictureRecorder recorder;
robertphillipsd8aa7b72014-10-30 16:45:02 -0700292
robertphillips82365912014-11-12 09:32:34 -0800293 SkCanvas* c = recorder.beginRecording(SkIntToScalar(kWidth), SkIntToScalar(kHeight),
294 &bbhFactory,
295 SkPictureRecorder::kComputeSaveLayerInfo_RecordFlag);
robertphillipsd8aa7b72014-10-30 16:45:02 -0700296
halcanary96fcdcc2015-08-27 07:41:13 -0700297 c->saveLayer(nullptr, &complexPaint);
robertphillips82365912014-11-12 09:32:34 -0800298 c->restore();
robertphillipsd6283302014-08-27 11:53:28 -0700299
reedca2622b2016-03-18 07:25:55 -0700300 child = recorder.finishRecordingAsPicture();
robertphillips82365912014-11-12 09:32:34 -0800301 }
robertphillipsd6283302014-08-27 11:53:28 -0700302
robertphillips82365912014-11-12 09:32:34 -0800303 // create a picture with the structure:
304 // 1)
305 // SaveLayer
306 // Restore
307 // 2)
308 // SaveLayer
309 // Translate
310 // SaveLayer w/ bound
311 // Restore
312 // Restore
313 // 3)
314 // SaveLayer w/ copyable paint
315 // Restore
316 // 4)
317 // SaveLayer
318 // DrawPicture (which has a SaveLayer/Restore pair)
319 // Restore
320 // 5)
321 // SaveLayer
322 // DrawPicture with Matrix & Paint (with SaveLayer/Restore pair)
323 // Restore
324 {
325 SkPictureRecorder recorder;
robertphillipsd6283302014-08-27 11:53:28 -0700326
robertphillips82365912014-11-12 09:32:34 -0800327 SkCanvas* c = recorder.beginRecording(SkIntToScalar(kWidth),
328 SkIntToScalar(kHeight),
329 &bbhFactory,
330 SkPictureRecorder::kComputeSaveLayerInfo_RecordFlag);
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +0000331 // 1)
halcanary96fcdcc2015-08-27 07:41:13 -0700332 c->saveLayer(nullptr, &complexPaint); // layer #0
robertphillips82365912014-11-12 09:32:34 -0800333 c->restore();
334
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +0000335 // 2)
halcanary96fcdcc2015-08-27 07:41:13 -0700336 c->saveLayer(nullptr, nullptr); // layer #1
robertphillips01d6e5f2014-12-01 09:09:27 -0800337 c->translate(kWidth / 2.0f, kHeight / 2.0f);
robertphillips82365912014-11-12 09:32:34 -0800338 SkRect r = SkRect::MakeXYWH(0, 0, kWidth/2, kHeight/2);
339 c->saveLayer(&r, &complexPaint); // layer #2
340 c->restore();
341 c->restore();
342
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +0000343 // 3)
robertphillips82365912014-11-12 09:32:34 -0800344 {
halcanary96fcdcc2015-08-27 07:41:13 -0700345 c->saveLayer(nullptr, &complexPaint); // layer #3
robertphillips82365912014-11-12 09:32:34 -0800346 c->restore();
347 }
348
349 SkPaint layerPaint;
350 layerPaint.setColor(SK_ColorRED); // Non-alpha only to avoid SaveLayerDrawRestoreNooper
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +0000351 // 4)
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +0000352 {
halcanary96fcdcc2015-08-27 07:41:13 -0700353 c->saveLayer(nullptr, &layerPaint); // layer #4
robertphillips82365912014-11-12 09:32:34 -0800354 c->drawPicture(child); // layer #5 inside picture
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +0000355 c->restore();
robertphillips82365912014-11-12 09:32:34 -0800356 }
357 // 5
358 {
359 SkPaint picturePaint;
360 SkMatrix trans;
361 trans.setTranslate(10, 10);
bsalomone904c092014-07-17 10:50:59 -0700362
halcanary96fcdcc2015-08-27 07:41:13 -0700363 c->saveLayer(nullptr, &layerPaint); // layer #6
robertphillips82365912014-11-12 09:32:34 -0800364 c->drawPicture(child, &trans, &picturePaint); // layer #7 inside picture
bsalomone904c092014-07-17 10:50:59 -0700365 c->restore();
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +0000366 }
367
reedca2622b2016-03-18 07:25:55 -0700368 pict = recorder.finishRecordingAsPicture();
robertphillips82365912014-11-12 09:32:34 -0800369 }
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +0000370
robertphillips82365912014-11-12 09:32:34 -0800371 // Now test out the SaveLayer extraction
reedd990e2f2014-12-22 11:58:30 -0800372 if (!SkCanvas::Internal_Private_GetIgnoreSaveLayerBounds()) {
mtklein9db912c2015-05-19 11:11:26 -0700373 const SkBigPicture* bp = pict->asSkBigPicture();
374 REPORTER_ASSERT(reporter, bp);
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +0000375
mtklein9db912c2015-05-19 11:11:26 -0700376 const SkBigPicture::AccelData* data = bp->accelData();
robertphillips82365912014-11-12 09:32:34 -0800377 REPORTER_ASSERT(reporter, data);
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +0000378
robertphillips82365912014-11-12 09:32:34 -0800379 const SkLayerInfo *gpuData = static_cast<const SkLayerInfo*>(data);
380 REPORTER_ASSERT(reporter, 8 == gpuData->numBlocks());
robertphillipsd6283302014-08-27 11:53:28 -0700381
robertphillips82365912014-11-12 09:32:34 -0800382 const SkLayerInfo::BlockInfo& info0 = gpuData->block(0);
383 // The parent/child layers appear in reverse order
384 const SkLayerInfo::BlockInfo& info1 = gpuData->block(2);
385 const SkLayerInfo::BlockInfo& info2 = gpuData->block(1);
robertphillipsd6283302014-08-27 11:53:28 -0700386
robertphillips82365912014-11-12 09:32:34 -0800387 const SkLayerInfo::BlockInfo& info3 = gpuData->block(3);
robertphillipsd6283302014-08-27 11:53:28 -0700388
robertphillips82365912014-11-12 09:32:34 -0800389 // The parent/child layers appear in reverse order
390 const SkLayerInfo::BlockInfo& info4 = gpuData->block(5);
391 const SkLayerInfo::BlockInfo& info5 = gpuData->block(4);
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +0000392
robertphillips82365912014-11-12 09:32:34 -0800393 // The parent/child layers appear in reverse order
394 const SkLayerInfo::BlockInfo& info6 = gpuData->block(7);
395 const SkLayerInfo::BlockInfo& info7 = gpuData->block(6);
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +0000396
halcanary96fcdcc2015-08-27 07:41:13 -0700397 REPORTER_ASSERT(reporter, nullptr == info0.fPicture);
robertphillips82365912014-11-12 09:32:34 -0800398 REPORTER_ASSERT(reporter, kWidth == info0.fBounds.width() &&
399 kHeight == info0.fBounds.height());
400 REPORTER_ASSERT(reporter, info0.fLocalMat.isIdentity());
401 REPORTER_ASSERT(reporter, info0.fPreMat.isIdentity());
402 REPORTER_ASSERT(reporter, 0 == info0.fBounds.fLeft && 0 == info0.fBounds.fTop);
halcanary96fcdcc2015-08-27 07:41:13 -0700403 REPORTER_ASSERT(reporter, nullptr != info0.fPaint);
robertphillips82365912014-11-12 09:32:34 -0800404 REPORTER_ASSERT(reporter, !info0.fIsNested && !info0.fHasNestedLayers);
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +0000405
halcanary96fcdcc2015-08-27 07:41:13 -0700406 REPORTER_ASSERT(reporter, nullptr == info1.fPicture);
robertphillips82365912014-11-12 09:32:34 -0800407 REPORTER_ASSERT(reporter, kWidth/2.0 == info1.fBounds.width() &&
408 kHeight/2.0 == info1.fBounds.height());
409 REPORTER_ASSERT(reporter, info1.fLocalMat.isIdentity());
410 REPORTER_ASSERT(reporter, info1.fPreMat.isIdentity());
mtklein04c96952014-11-24 08:20:57 -0800411 REPORTER_ASSERT(reporter, kWidth/2.0 == info1.fBounds.fLeft &&
robertphillips82365912014-11-12 09:32:34 -0800412 kHeight/2.0 == info1.fBounds.fTop);
halcanary96fcdcc2015-08-27 07:41:13 -0700413 REPORTER_ASSERT(reporter, nullptr == info1.fPaint);
robertphillips82365912014-11-12 09:32:34 -0800414 REPORTER_ASSERT(reporter, !info1.fIsNested &&
415 info1.fHasNestedLayers); // has a nested SL
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +0000416
halcanary96fcdcc2015-08-27 07:41:13 -0700417 REPORTER_ASSERT(reporter, nullptr == info2.fPicture);
robertphillips82365912014-11-12 09:32:34 -0800418 REPORTER_ASSERT(reporter, kWidth / 2 == info2.fBounds.width() &&
419 kHeight / 2 == info2.fBounds.height()); // bound reduces size
420 REPORTER_ASSERT(reporter, !info2.fLocalMat.isIdentity());
421 REPORTER_ASSERT(reporter, info2.fPreMat.isIdentity());
422 REPORTER_ASSERT(reporter, kWidth / 2 == info2.fBounds.fLeft && // translated
423 kHeight / 2 == info2.fBounds.fTop);
halcanary96fcdcc2015-08-27 07:41:13 -0700424 REPORTER_ASSERT(reporter, nullptr != info2.fPaint);
robertphillips82365912014-11-12 09:32:34 -0800425 REPORTER_ASSERT(reporter, info2.fIsNested && !info2.fHasNestedLayers); // is nested
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +0000426
halcanary96fcdcc2015-08-27 07:41:13 -0700427 REPORTER_ASSERT(reporter, nullptr == info3.fPicture);
robertphillips82365912014-11-12 09:32:34 -0800428 REPORTER_ASSERT(reporter, kWidth == info3.fBounds.width() &&
429 kHeight == info3.fBounds.height());
430 REPORTER_ASSERT(reporter, info3.fLocalMat.isIdentity());
431 REPORTER_ASSERT(reporter, info3.fPreMat.isIdentity());
432 REPORTER_ASSERT(reporter, 0 == info3.fBounds.fLeft && 0 == info3.fBounds.fTop);
433 REPORTER_ASSERT(reporter, info3.fPaint);
434 REPORTER_ASSERT(reporter, !info3.fIsNested && !info3.fHasNestedLayers);
robertphillipsd6283302014-08-27 11:53:28 -0700435
halcanary96fcdcc2015-08-27 07:41:13 -0700436 REPORTER_ASSERT(reporter, nullptr == info4.fPicture);
robertphillips82365912014-11-12 09:32:34 -0800437 REPORTER_ASSERT(reporter, kWidth == info4.fBounds.width() &&
438 kHeight == info4.fBounds.height());
439 REPORTER_ASSERT(reporter, 0 == info4.fBounds.fLeft && 0 == info4.fBounds.fTop);
440 REPORTER_ASSERT(reporter, info4.fLocalMat.isIdentity());
441 REPORTER_ASSERT(reporter, info4.fPreMat.isIdentity());
442 REPORTER_ASSERT(reporter, info4.fPaint);
443 REPORTER_ASSERT(reporter, !info4.fIsNested &&
444 info4.fHasNestedLayers); // has a nested SL
robertphillipsd6283302014-08-27 11:53:28 -0700445
reedca2622b2016-03-18 07:25:55 -0700446 REPORTER_ASSERT(reporter, child.get() == info5.fPicture); // in a child picture
robertphillips82365912014-11-12 09:32:34 -0800447 REPORTER_ASSERT(reporter, kWidth == info5.fBounds.width() &&
448 kHeight == info5.fBounds.height());
449 REPORTER_ASSERT(reporter, 0 == info5.fBounds.fLeft && 0 == info5.fBounds.fTop);
450 REPORTER_ASSERT(reporter, info5.fLocalMat.isIdentity());
451 REPORTER_ASSERT(reporter, info5.fPreMat.isIdentity());
halcanary96fcdcc2015-08-27 07:41:13 -0700452 REPORTER_ASSERT(reporter, nullptr != info5.fPaint);
robertphillips82365912014-11-12 09:32:34 -0800453 REPORTER_ASSERT(reporter, info5.fIsNested && !info5.fHasNestedLayers); // is nested
robertphillipsd6283302014-08-27 11:53:28 -0700454
halcanary96fcdcc2015-08-27 07:41:13 -0700455 REPORTER_ASSERT(reporter, nullptr == info6.fPicture);
robertphillips82365912014-11-12 09:32:34 -0800456 REPORTER_ASSERT(reporter, kWidth-10 == info6.fBounds.width() &&
457 kHeight-10 == info6.fBounds.height());
458 REPORTER_ASSERT(reporter, 10 == info6.fBounds.fLeft && 10 == info6.fBounds.fTop);
459 REPORTER_ASSERT(reporter, info6.fLocalMat.isIdentity());
460 REPORTER_ASSERT(reporter, info6.fPreMat.isIdentity());
461 REPORTER_ASSERT(reporter, info6.fPaint);
462 REPORTER_ASSERT(reporter, !info6.fIsNested &&
463 info6.fHasNestedLayers); // has a nested SL
464
reedca2622b2016-03-18 07:25:55 -0700465 REPORTER_ASSERT(reporter, child.get() == info7.fPicture); // in a child picture
robertphillips82365912014-11-12 09:32:34 -0800466 REPORTER_ASSERT(reporter, kWidth == info7.fBounds.width() &&
467 kHeight == info7.fBounds.height());
468 REPORTER_ASSERT(reporter, 0 == info7.fBounds.fLeft && 0 == info7.fBounds.fTop);
469 REPORTER_ASSERT(reporter, info7.fLocalMat.isIdentity());
470 REPORTER_ASSERT(reporter, info7.fPreMat.isIdentity());
halcanary96fcdcc2015-08-27 07:41:13 -0700471 REPORTER_ASSERT(reporter, nullptr != info7.fPaint);
robertphillips82365912014-11-12 09:32:34 -0800472 REPORTER_ASSERT(reporter, info7.fIsNested && !info7.fHasNestedLayers); // is nested
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +0000473 }
474}
475
mtklein8e126562014-10-01 09:29:35 -0700476static void test_has_text(skiatest::Reporter* reporter) {
ajuma750ae262014-08-18 12:59:55 -0700477 SkPictureRecorder recorder;
ajuma750ae262014-08-18 12:59:55 -0700478
mtklein8e126562014-10-01 09:29:35 -0700479 SkCanvas* canvas = recorder.beginRecording(100,100);
ajuma750ae262014-08-18 12:59:55 -0700480 {
mtkleinc551d9f2014-08-20 08:09:46 -0700481 canvas->drawRect(SkRect::MakeWH(20, 20), SkPaint());
ajuma750ae262014-08-18 12:59:55 -0700482 }
reedca2622b2016-03-18 07:25:55 -0700483 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
ajuma750ae262014-08-18 12:59:55 -0700484 REPORTER_ASSERT(reporter, !picture->hasText());
485
mtkleinc551d9f2014-08-20 08:09:46 -0700486 SkPoint point = SkPoint::Make(10, 10);
mtklein8e126562014-10-01 09:29:35 -0700487 canvas = recorder.beginRecording(100,100);
ajuma750ae262014-08-18 12:59:55 -0700488 {
mtkleinc551d9f2014-08-20 08:09:46 -0700489 canvas->drawText("Q", 1, point.fX, point.fY, SkPaint());
ajuma750ae262014-08-18 12:59:55 -0700490 }
reedca2622b2016-03-18 07:25:55 -0700491 picture = recorder.finishRecordingAsPicture();
ajuma750ae262014-08-18 12:59:55 -0700492 REPORTER_ASSERT(reporter, picture->hasText());
493
mtklein8e126562014-10-01 09:29:35 -0700494 canvas = recorder.beginRecording(100,100);
ajuma750ae262014-08-18 12:59:55 -0700495 {
mtkleinc551d9f2014-08-20 08:09:46 -0700496 canvas->drawPosText("Q", 1, &point, SkPaint());
ajuma750ae262014-08-18 12:59:55 -0700497 }
reedca2622b2016-03-18 07:25:55 -0700498 picture = recorder.finishRecordingAsPicture();
ajuma750ae262014-08-18 12:59:55 -0700499 REPORTER_ASSERT(reporter, picture->hasText());
500
mtklein8e126562014-10-01 09:29:35 -0700501 canvas = recorder.beginRecording(100,100);
ajuma750ae262014-08-18 12:59:55 -0700502 {
mtkleinc551d9f2014-08-20 08:09:46 -0700503 canvas->drawPosTextH("Q", 1, &point.fX, point.fY, SkPaint());
ajuma750ae262014-08-18 12:59:55 -0700504 }
reedca2622b2016-03-18 07:25:55 -0700505 picture = recorder.finishRecordingAsPicture();
ajuma750ae262014-08-18 12:59:55 -0700506 REPORTER_ASSERT(reporter, picture->hasText());
507
mtklein8e126562014-10-01 09:29:35 -0700508 canvas = recorder.beginRecording(100,100);
ajuma750ae262014-08-18 12:59:55 -0700509 {
510 SkPath path;
511 path.moveTo(0, 0);
512 path.lineTo(50, 50);
513
mtkleinc551d9f2014-08-20 08:09:46 -0700514 canvas->drawTextOnPathHV("Q", 1, path, point.fX, point.fY, SkPaint());
ajuma750ae262014-08-18 12:59:55 -0700515 }
reedca2622b2016-03-18 07:25:55 -0700516 picture = recorder.finishRecordingAsPicture();
ajuma750ae262014-08-18 12:59:55 -0700517 REPORTER_ASSERT(reporter, picture->hasText());
518
mtklein8e126562014-10-01 09:29:35 -0700519 canvas = recorder.beginRecording(100,100);
ajuma750ae262014-08-18 12:59:55 -0700520 {
521 SkPath path;
522 path.moveTo(0, 0);
523 path.lineTo(50, 50);
524
halcanary96fcdcc2015-08-27 07:41:13 -0700525 canvas->drawTextOnPath("Q", 1, path, nullptr, SkPaint());
ajuma750ae262014-08-18 12:59:55 -0700526 }
reedca2622b2016-03-18 07:25:55 -0700527 picture = recorder.finishRecordingAsPicture();
ajuma750ae262014-08-18 12:59:55 -0700528 REPORTER_ASSERT(reporter, picture->hasText());
mtklein53fecfb2014-08-21 09:11:37 -0700529
530 // Nest the previous picture inside a new one.
mtklein8e126562014-10-01 09:29:35 -0700531 canvas = recorder.beginRecording(100,100);
532 {
533 canvas->drawPicture(picture.get());
mtklein53fecfb2014-08-21 09:11:37 -0700534 }
reedca2622b2016-03-18 07:25:55 -0700535 picture = recorder.finishRecordingAsPicture();
mtklein8e126562014-10-01 09:29:35 -0700536 REPORTER_ASSERT(reporter, picture->hasText());
ajuma750ae262014-08-18 12:59:55 -0700537}
538
commit-bot@chromium.orgea7d08e2014-02-13 16:00:51 +0000539static void set_canvas_to_save_count_4(SkCanvas* canvas) {
540 canvas->restoreToCount(1);
541 canvas->save();
542 canvas->save();
543 canvas->save();
544}
545
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000546/**
547 * A canvas that records the number of saves, saveLayers and restores.
548 */
549class SaveCountingCanvas : public SkCanvas {
550public:
551 SaveCountingCanvas(int width, int height)
552 : INHERITED(width, height)
553 , fSaveCount(0)
554 , fSaveLayerCount(0)
555 , fRestoreCount(0){
556 }
557
reed4960eee2015-12-18 07:09:18 -0800558 SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec& rec) override {
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000559 ++fSaveLayerCount;
reed4960eee2015-12-18 07:09:18 -0800560 return this->INHERITED::getSaveLayerStrategy(rec);
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000561 }
562
mtklein36352bf2015-03-25 18:17:31 -0700563 void willSave() override {
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000564 ++fSaveCount;
Florin Malita5f6102d2014-06-30 10:13:28 -0400565 this->INHERITED::willSave();
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000566 }
567
mtklein36352bf2015-03-25 18:17:31 -0700568 void willRestore() override {
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000569 ++fRestoreCount;
570 this->INHERITED::willRestore();
571 }
572
573 unsigned int getSaveCount() const { return fSaveCount; }
574 unsigned int getSaveLayerCount() const { return fSaveLayerCount; }
575 unsigned int getRestoreCount() const { return fRestoreCount; }
576
577private:
578 unsigned int fSaveCount;
579 unsigned int fSaveLayerCount;
580 unsigned int fRestoreCount;
581
582 typedef SkCanvas INHERITED;
583};
584
skia.committer@gmail.com8e7d37d2014-05-28 03:06:06 +0000585void check_save_state(skiatest::Reporter* reporter, SkPicture* picture,
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000586 unsigned int numSaves, unsigned int numSaveLayers,
587 unsigned int numRestores) {
mtklein87c41382014-09-08 07:31:18 -0700588 SaveCountingCanvas canvas(SkScalarCeilToInt(picture->cullRect().width()),
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700589 SkScalarCeilToInt(picture->cullRect().height()));
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000590
robertphillipsc5ba71d2014-09-04 08:42:50 -0700591 picture->playback(&canvas);
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000592
mtklein87c41382014-09-08 07:31:18 -0700593 // Optimizations may have removed these,
594 // so expect to have seen no more than num{Saves,SaveLayers,Restores}.
595 REPORTER_ASSERT(reporter, numSaves >= canvas.getSaveCount());
596 REPORTER_ASSERT(reporter, numSaveLayers >= canvas.getSaveLayerCount());
597 REPORTER_ASSERT(reporter, numRestores >= canvas.getRestoreCount());
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000598}
599
600// This class exists so SkPicture can friend it and give it access to
601// the 'partialReplay' method.
602class SkPictureRecorderReplayTester {
603public:
reedca2622b2016-03-18 07:25:55 -0700604 static sk_sp<SkPicture> Copy(SkPictureRecorder* recorder) {
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000605 SkPictureRecorder recorder2;
606
robertphillips9f1c2412014-06-09 06:25:34 -0700607 SkCanvas* canvas = recorder2.beginRecording(10, 10);
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000608
609 recorder->partialReplay(canvas);
610
reedca2622b2016-03-18 07:25:55 -0700611 return recorder2.finishRecordingAsPicture();
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000612 }
613};
614
robertphillips9058d602014-06-10 11:45:46 -0700615static void create_imbalance(SkCanvas* canvas) {
616 SkRect clipRect = SkRect::MakeWH(2, 2);
617 SkRect drawRect = SkRect::MakeWH(10, 10);
618 canvas->save();
619 canvas->clipRect(clipRect, SkRegion::kReplace_Op);
620 canvas->translate(1.0f, 1.0f);
621 SkPaint p;
622 p.setColor(SK_ColorGREEN);
623 canvas->drawRect(drawRect, p);
624 // no restore
625}
626
627// This tests that replaying a potentially unbalanced picture into a canvas
628// doesn't affect the canvas' save count or matrix/clip state.
629static void check_balance(skiatest::Reporter* reporter, SkPicture* picture) {
630 SkBitmap bm;
631 bm.allocN32Pixels(4, 3);
632 SkCanvas canvas(bm);
633
634 int beforeSaveCount = canvas.getSaveCount();
635
636 SkMatrix beforeMatrix = canvas.getTotalMatrix();
637
638 SkRect beforeClip;
639
640 canvas.getClipBounds(&beforeClip);
641
642 canvas.drawPicture(picture);
643
644 REPORTER_ASSERT(reporter, beforeSaveCount == canvas.getSaveCount());
645 REPORTER_ASSERT(reporter, beforeMatrix == canvas.getTotalMatrix());
646
647 SkRect afterClip;
648
649 canvas.getClipBounds(&afterClip);
650
651 REPORTER_ASSERT(reporter, afterClip == beforeClip);
652}
653
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000654// Test out SkPictureRecorder::partialReplay
655DEF_TEST(PictureRecorder_replay, reporter) {
656 // check save/saveLayer state
657 {
658 SkPictureRecorder recorder;
659
robertphillips9f1c2412014-06-09 06:25:34 -0700660 SkCanvas* canvas = recorder.beginRecording(10, 10);
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000661
halcanary96fcdcc2015-08-27 07:41:13 -0700662 canvas->saveLayer(nullptr, nullptr);
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000663
reedca2622b2016-03-18 07:25:55 -0700664 sk_sp<SkPicture> copy(SkPictureRecorderReplayTester::Copy(&recorder));
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000665
666 // The extra save and restore comes from the Copy process.
reedca2622b2016-03-18 07:25:55 -0700667 check_save_state(reporter, copy.get(), 2, 1, 3);
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000668
halcanary96fcdcc2015-08-27 07:41:13 -0700669 canvas->saveLayer(nullptr, nullptr);
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000670
reedca2622b2016-03-18 07:25:55 -0700671 sk_sp<SkPicture> final(recorder.finishRecordingAsPicture());
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000672
reedca2622b2016-03-18 07:25:55 -0700673 check_save_state(reporter, final.get(), 1, 2, 3);
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000674
675 // The copy shouldn't pick up any operations added after it was made
reedca2622b2016-03-18 07:25:55 -0700676 check_save_state(reporter, copy.get(), 2, 1, 3);
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000677 }
678
679 // (partially) check leakage of draw ops
680 {
681 SkPictureRecorder recorder;
682
robertphillips9f1c2412014-06-09 06:25:34 -0700683 SkCanvas* canvas = recorder.beginRecording(10, 10);
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000684
685 SkRect r = SkRect::MakeWH(5, 5);
686 SkPaint p;
687
688 canvas->drawRect(r, p);
689
reedca2622b2016-03-18 07:25:55 -0700690 sk_sp<SkPicture> copy(SkPictureRecorderReplayTester::Copy(&recorder));
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000691
692 REPORTER_ASSERT(reporter, !copy->willPlayBackBitmaps());
693
694 SkBitmap bm;
695 make_bm(&bm, 10, 10, SK_ColorRED, true);
696
697 r.offset(5.0f, 5.0f);
reede47829b2015-08-06 10:02:53 -0700698 canvas->drawBitmapRect(bm, r, nullptr);
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000699
reedca2622b2016-03-18 07:25:55 -0700700 sk_sp<SkPicture> final(recorder.finishRecordingAsPicture());
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000701 REPORTER_ASSERT(reporter, final->willPlayBackBitmaps());
702
703 REPORTER_ASSERT(reporter, copy->uniqueID() != final->uniqueID());
704
705 // The snapshot shouldn't pick up any operations added after it was made
706 REPORTER_ASSERT(reporter, !copy->willPlayBackBitmaps());
707 }
robertphillips9058d602014-06-10 11:45:46 -0700708
709 // Recreate the Android partialReplay test case
710 {
711 SkPictureRecorder recorder;
712
halcanary96fcdcc2015-08-27 07:41:13 -0700713 SkCanvas* canvas = recorder.beginRecording(4, 3, nullptr, 0);
robertphillips9058d602014-06-10 11:45:46 -0700714 create_imbalance(canvas);
715
716 int expectedSaveCount = canvas->getSaveCount();
717
reedca2622b2016-03-18 07:25:55 -0700718 sk_sp<SkPicture> copy(SkPictureRecorderReplayTester::Copy(&recorder));
719 check_balance(reporter, copy.get());
robertphillips9058d602014-06-10 11:45:46 -0700720
721 REPORTER_ASSERT(reporter, expectedSaveCount = canvas->getSaveCount());
722
723 // End the recording of source to test the picture finalization
724 // process isn't complicated by the partialReplay step
reedca2622b2016-03-18 07:25:55 -0700725 sk_sp<SkPicture> final(recorder.finishRecordingAsPicture());
robertphillips9058d602014-06-10 11:45:46 -0700726 }
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000727}
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000728
commit-bot@chromium.orgea7d08e2014-02-13 16:00:51 +0000729static void test_unbalanced_save_restores(skiatest::Reporter* reporter) {
730 SkCanvas testCanvas(100, 100);
731 set_canvas_to_save_count_4(&testCanvas);
732
733 REPORTER_ASSERT(reporter, 4 == testCanvas.getSaveCount());
734
735 SkPaint paint;
736 SkRect rect = SkRect::MakeLTRB(-10000000, -10000000, 10000000, 10000000);
737
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000738 SkPictureRecorder recorder;
commit-bot@chromium.orgea7d08e2014-02-13 16:00:51 +0000739
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000740 {
741 // Create picture with 2 unbalanced saves
robertphillips9f1c2412014-06-09 06:25:34 -0700742 SkCanvas* canvas = recorder.beginRecording(100, 100);
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000743 canvas->save();
744 canvas->translate(10, 10);
745 canvas->drawRect(rect, paint);
746 canvas->save();
747 canvas->translate(10, 10);
748 canvas->drawRect(rect, paint);
reedca2622b2016-03-18 07:25:55 -0700749 sk_sp<SkPicture> extraSavePicture(recorder.finishRecordingAsPicture());
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000750
robertphillips9b14f262014-06-04 05:40:44 -0700751 testCanvas.drawPicture(extraSavePicture);
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000752 REPORTER_ASSERT(reporter, 4 == testCanvas.getSaveCount());
753 }
commit-bot@chromium.orgea7d08e2014-02-13 16:00:51 +0000754
755 set_canvas_to_save_count_4(&testCanvas);
756
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000757 {
758 // Create picture with 2 unbalanced restores
robertphillips9f1c2412014-06-09 06:25:34 -0700759 SkCanvas* canvas = recorder.beginRecording(100, 100);
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000760 canvas->save();
761 canvas->translate(10, 10);
762 canvas->drawRect(rect, paint);
763 canvas->save();
764 canvas->translate(10, 10);
765 canvas->drawRect(rect, paint);
766 canvas->restore();
767 canvas->restore();
768 canvas->restore();
769 canvas->restore();
reedca2622b2016-03-18 07:25:55 -0700770 sk_sp<SkPicture> extraRestorePicture(recorder.finishRecordingAsPicture());
commit-bot@chromium.orgea7d08e2014-02-13 16:00:51 +0000771
robertphillips9b14f262014-06-04 05:40:44 -0700772 testCanvas.drawPicture(extraRestorePicture);
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000773 REPORTER_ASSERT(reporter, 4 == testCanvas.getSaveCount());
774 }
commit-bot@chromium.orgea7d08e2014-02-13 16:00:51 +0000775
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000776 set_canvas_to_save_count_4(&testCanvas);
commit-bot@chromium.orgea7d08e2014-02-13 16:00:51 +0000777
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000778 {
robertphillips9f1c2412014-06-09 06:25:34 -0700779 SkCanvas* canvas = recorder.beginRecording(100, 100);
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000780 canvas->translate(10, 10);
781 canvas->drawRect(rect, paint);
reedca2622b2016-03-18 07:25:55 -0700782 sk_sp<SkPicture> noSavePicture(recorder.finishRecordingAsPicture());
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000783
robertphillips9b14f262014-06-04 05:40:44 -0700784 testCanvas.drawPicture(noSavePicture);
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000785 REPORTER_ASSERT(reporter, 4 == testCanvas.getSaveCount());
786 REPORTER_ASSERT(reporter, testCanvas.getTotalMatrix().isIdentity());
787 }
commit-bot@chromium.orgea7d08e2014-02-13 16:00:51 +0000788}
789
sugoi@google.com54f0d1b2013-02-27 19:17:41 +0000790static void test_peephole() {
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000791 SkRandom rand;
reed@google.com21b519d2012-10-02 17:42:15 +0000792
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000793 SkPictureRecorder recorder;
794
reed@google.com21b519d2012-10-02 17:42:15 +0000795 for (int j = 0; j < 100; j++) {
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000796 SkRandom rand2(rand); // remember the seed
reed@google.com21b519d2012-10-02 17:42:15 +0000797
robertphillips9f1c2412014-06-09 06:25:34 -0700798 SkCanvas* canvas = recorder.beginRecording(100, 100);
reed@google.com21b519d2012-10-02 17:42:15 +0000799
800 for (int i = 0; i < 1000; ++i) {
801 rand_op(canvas, rand);
802 }
reedca2622b2016-03-18 07:25:55 -0700803 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
jvanverth@google.comc490f802013-03-04 13:56:38 +0000804
805 rand = rand2;
reed@google.com21b519d2012-10-02 17:42:15 +0000806 }
807
808 {
robertphillips9f1c2412014-06-09 06:25:34 -0700809 SkCanvas* canvas = recorder.beginRecording(100, 100);
reed@google.com21b519d2012-10-02 17:42:15 +0000810 SkRect rect = SkRect::MakeWH(50, 50);
skia.committer@gmail.com52c24372012-10-03 02:01:13 +0000811
reed@google.com21b519d2012-10-02 17:42:15 +0000812 for (int i = 0; i < 100; ++i) {
813 canvas->save();
814 }
815 while (canvas->getSaveCount() > 1) {
816 canvas->clipRect(rect);
817 canvas->restore();
818 }
reedca2622b2016-03-18 07:25:55 -0700819 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
reed@google.com21b519d2012-10-02 17:42:15 +0000820 }
821}
822
scroggo@google.com4b90b112012-12-04 15:08:56 +0000823#ifndef SK_DEBUG
824// Only test this is in release mode. We deliberately crash in debug mode, since a valid caller
825// should never do this.
826static void test_bad_bitmap() {
827 // This bitmap has a width and height but no pixels. As a result, attempting to record it will
828 // fail.
829 SkBitmap bm;
commit-bot@chromium.orga3264e52014-05-30 13:26:10 +0000830 bm.setInfo(SkImageInfo::MakeN32Premul(100, 100));
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000831 SkPictureRecorder recorder;
robertphillips9f1c2412014-06-09 06:25:34 -0700832 SkCanvas* recordingCanvas = recorder.beginRecording(100, 100);
scroggo@google.com4b90b112012-12-04 15:08:56 +0000833 recordingCanvas->drawBitmap(bm, 0, 0);
reedca2622b2016-03-18 07:25:55 -0700834 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
scroggo@google.com4b90b112012-12-04 15:08:56 +0000835
836 SkCanvas canvas;
robertphillips9b14f262014-06-04 05:40:44 -0700837 canvas.drawPicture(picture);
scroggo@google.com4b90b112012-12-04 15:08:56 +0000838}
839#endif
840
scroggo@google.com7c9d5392012-12-10 15:40:55 +0000841static SkData* serialized_picture_from_bitmap(const SkBitmap& bitmap) {
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000842 SkPictureRecorder recorder;
mtklein87c41382014-09-08 07:31:18 -0700843 SkCanvas* canvas = recorder.beginRecording(SkIntToScalar(bitmap.width()),
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700844 SkIntToScalar(bitmap.height()));
scroggo@google.com7c9d5392012-12-10 15:40:55 +0000845 canvas->drawBitmap(bitmap, 0, 0);
reedca2622b2016-03-18 07:25:55 -0700846 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000847
scroggo@google.com7c9d5392012-12-10 15:40:55 +0000848 SkDynamicMemoryWStream wStream;
halcanaryf2848b62015-12-10 12:40:23 -0800849 SkAutoTUnref<SkPixelSerializer> serializer(
850 SkImageEncoder::CreatePixelSerializer());
851 picture->serialize(&wStream, serializer);
scroggo@google.com7c9d5392012-12-10 15:40:55 +0000852 return wStream.copyToData();
853}
854
scroggo@google.com49ce11b2013-04-25 18:29:32 +0000855struct ErrorContext {
856 int fErrors;
857 skiatest::Reporter* fReporter;
858};
859
860static void assert_one_parse_error_cb(SkError error, void* context) {
861 ErrorContext* errorContext = static_cast<ErrorContext*>(context);
862 errorContext->fErrors++;
863 // This test only expects one error, and that is a kParseError. If there are others,
864 // there is some unknown problem.
865 REPORTER_ASSERT_MESSAGE(errorContext->fReporter, 1 == errorContext->fErrors,
866 "This threw more errors than expected.");
867 REPORTER_ASSERT_MESSAGE(errorContext->fReporter, kParseError_SkError == error,
868 SkGetLastErrorString());
869}
870
msarett8715d472016-02-17 10:02:29 -0800871static void md5(const SkBitmap& bm, SkMD5::Digest* digest) {
872 SkAutoLockPixels autoLockPixels(bm);
873 SkASSERT(bm.getPixels());
874 SkMD5 md5;
875 size_t rowLen = bm.info().bytesPerPixel() * bm.width();
876 for (int y = 0; y < bm.height(); ++y) {
877 md5.update(static_cast<uint8_t*>(bm.getAddr(0, y)), rowLen);
878 }
879 md5.finish(*digest);
880}
881
882DEF_TEST(Picture_EncodedData, reporter) {
scroggo@google.com7c9d5392012-12-10 15:40:55 +0000883 // Create a bitmap that will be encoded.
884 SkBitmap original;
885 make_bm(&original, 100, 100, SK_ColorBLUE, true);
886 SkDynamicMemoryWStream wStream;
887 if (!SkImageEncoder::EncodeStream(&wStream, original, SkImageEncoder::kPNG_Type, 100)) {
888 return;
889 }
890 SkAutoDataUnref data(wStream.copyToData());
scroggo@google.com7c9d5392012-12-10 15:40:55 +0000891
scroggo@google.com7c9d5392012-12-10 15:40:55 +0000892 SkBitmap bm;
reedd1146452015-09-25 06:56:57 -0700893 bool installSuccess = SkDEPRECATED_InstallDiscardablePixelRef(data, &bm);
reed@google.combf790232013-12-13 19:45:58 +0000894 REPORTER_ASSERT(reporter, installSuccess);
scroggo@google.com7c9d5392012-12-10 15:40:55 +0000895
896 // Write both bitmaps to pictures, and ensure that the resulting data streams are the same.
897 // Flattening original will follow the old path of performing an encode, while flattening bm
898 // will use the already encoded data.
899 SkAutoDataUnref picture1(serialized_picture_from_bitmap(original));
900 SkAutoDataUnref picture2(serialized_picture_from_bitmap(bm));
901 REPORTER_ASSERT(reporter, picture1->equals(picture2));
msarett8715d472016-02-17 10:02:29 -0800902
scroggo@google.com49ce11b2013-04-25 18:29:32 +0000903 // Now test that a parse error was generated when trying to create a new SkPicture without
904 // providing a function to decode the bitmap.
905 ErrorContext context;
906 context.fErrors = 0;
907 context.fReporter = reporter;
908 SkSetErrorCallback(assert_one_parse_error_cb, &context);
909 SkMemoryStream pictureStream(picture1);
scroggo@google.com49ce11b2013-04-25 18:29:32 +0000910 SkClearLastError();
reedca2622b2016-03-18 07:25:55 -0700911 sk_sp<SkPicture> pictureFromStream(SkPicture::MakeFromStream(&pictureStream, nullptr));
halcanary96fcdcc2015-08-27 07:41:13 -0700912 REPORTER_ASSERT(reporter, pictureFromStream.get() != nullptr);
scroggo@google.com49ce11b2013-04-25 18:29:32 +0000913 SkClearLastError();
halcanary96fcdcc2015-08-27 07:41:13 -0700914 SkSetErrorCallback(nullptr, nullptr);
msarett8715d472016-02-17 10:02:29 -0800915
916 // Test that using the version of CreateFromStream that just takes a stream also decodes the
917 // bitmap. Drawing this picture should look exactly like the original bitmap.
918 SkMD5::Digest referenceDigest;
919 md5(original, &referenceDigest);
920
921 SkBitmap dst;
922 dst.allocPixels(original.info());
923 dst.eraseColor(SK_ColorRED);
924 SkCanvas canvas(dst);
925
926 pictureStream.rewind();
reedca2622b2016-03-18 07:25:55 -0700927 pictureFromStream = SkPicture::MakeFromStream(&pictureStream);
msarett8715d472016-02-17 10:02:29 -0800928 canvas.drawPicture(pictureFromStream.get());
929
930 SkMD5::Digest digest2;
931 md5(dst, &digest2);
932 REPORTER_ASSERT(reporter, referenceDigest == digest2);
scroggo@google.com7c9d5392012-12-10 15:40:55 +0000933}
934
junov@chromium.orgd575eed2013-05-08 15:39:13 +0000935static void test_clip_bound_opt(skiatest::Reporter* reporter) {
936 // Test for crbug.com/229011
937 SkRect rect1 = SkRect::MakeXYWH(SkIntToScalar(4), SkIntToScalar(4),
938 SkIntToScalar(2), SkIntToScalar(2));
939 SkRect rect2 = SkRect::MakeXYWH(SkIntToScalar(7), SkIntToScalar(7),
940 SkIntToScalar(1), SkIntToScalar(1));
941 SkRect rect3 = SkRect::MakeXYWH(SkIntToScalar(6), SkIntToScalar(6),
942 SkIntToScalar(1), SkIntToScalar(1));
943
944 SkPath invPath;
945 invPath.addOval(rect1);
946 invPath.setFillType(SkPath::kInverseEvenOdd_FillType);
947 SkPath path;
948 path.addOval(rect2);
949 SkPath path2;
950 path2.addOval(rect3);
951 SkIRect clipBounds;
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000952 SkPictureRecorder recorder;
reedd9544982014-09-09 18:46:22 -0700953
954 // Testing conservative-raster-clip that is enabled by PictureRecord
junov@chromium.orgd575eed2013-05-08 15:39:13 +0000955 {
robertphillips9f1c2412014-06-09 06:25:34 -0700956 SkCanvas* canvas = recorder.beginRecording(10, 10);
junov@chromium.orgd575eed2013-05-08 15:39:13 +0000957 canvas->clipPath(invPath, SkRegion::kIntersect_Op);
958 bool nonEmpty = canvas->getClipDeviceBounds(&clipBounds);
959 REPORTER_ASSERT(reporter, true == nonEmpty);
960 REPORTER_ASSERT(reporter, 0 == clipBounds.fLeft);
961 REPORTER_ASSERT(reporter, 0 == clipBounds.fTop);
962 REPORTER_ASSERT(reporter, 10 == clipBounds.fBottom);
963 REPORTER_ASSERT(reporter, 10 == clipBounds.fRight);
964 }
965 {
robertphillips9f1c2412014-06-09 06:25:34 -0700966 SkCanvas* canvas = recorder.beginRecording(10, 10);
junov@chromium.orgd575eed2013-05-08 15:39:13 +0000967 canvas->clipPath(path, SkRegion::kIntersect_Op);
968 canvas->clipPath(invPath, SkRegion::kIntersect_Op);
969 bool nonEmpty = canvas->getClipDeviceBounds(&clipBounds);
970 REPORTER_ASSERT(reporter, true == nonEmpty);
971 REPORTER_ASSERT(reporter, 7 == clipBounds.fLeft);
972 REPORTER_ASSERT(reporter, 7 == clipBounds.fTop);
973 REPORTER_ASSERT(reporter, 8 == clipBounds.fBottom);
974 REPORTER_ASSERT(reporter, 8 == clipBounds.fRight);
975 }
976 {
robertphillips9f1c2412014-06-09 06:25:34 -0700977 SkCanvas* canvas = recorder.beginRecording(10, 10);
junov@chromium.orgd575eed2013-05-08 15:39:13 +0000978 canvas->clipPath(path, SkRegion::kIntersect_Op);
979 canvas->clipPath(invPath, SkRegion::kUnion_Op);
980 bool nonEmpty = canvas->getClipDeviceBounds(&clipBounds);
981 REPORTER_ASSERT(reporter, true == nonEmpty);
982 REPORTER_ASSERT(reporter, 0 == clipBounds.fLeft);
983 REPORTER_ASSERT(reporter, 0 == clipBounds.fTop);
984 REPORTER_ASSERT(reporter, 10 == clipBounds.fBottom);
985 REPORTER_ASSERT(reporter, 10 == clipBounds.fRight);
986 }
987 {
robertphillips9f1c2412014-06-09 06:25:34 -0700988 SkCanvas* canvas = recorder.beginRecording(10, 10);
junov@chromium.orgd575eed2013-05-08 15:39:13 +0000989 canvas->clipPath(path, SkRegion::kDifference_Op);
990 bool nonEmpty = canvas->getClipDeviceBounds(&clipBounds);
991 REPORTER_ASSERT(reporter, true == nonEmpty);
992 REPORTER_ASSERT(reporter, 0 == clipBounds.fLeft);
993 REPORTER_ASSERT(reporter, 0 == clipBounds.fTop);
994 REPORTER_ASSERT(reporter, 10 == clipBounds.fBottom);
995 REPORTER_ASSERT(reporter, 10 == clipBounds.fRight);
996 }
997 {
robertphillips9f1c2412014-06-09 06:25:34 -0700998 SkCanvas* canvas = recorder.beginRecording(10, 10);
junov@chromium.orgd575eed2013-05-08 15:39:13 +0000999 canvas->clipPath(path, SkRegion::kReverseDifference_Op);
1000 bool nonEmpty = canvas->getClipDeviceBounds(&clipBounds);
1001 // True clip is actually empty in this case, but the best
1002 // determination we can make using only bounds as input is that the
1003 // clip is included in the bounds of 'path'.
1004 REPORTER_ASSERT(reporter, true == nonEmpty);
1005 REPORTER_ASSERT(reporter, 7 == clipBounds.fLeft);
1006 REPORTER_ASSERT(reporter, 7 == clipBounds.fTop);
1007 REPORTER_ASSERT(reporter, 8 == clipBounds.fBottom);
1008 REPORTER_ASSERT(reporter, 8 == clipBounds.fRight);
1009 }
1010 {
robertphillips9f1c2412014-06-09 06:25:34 -07001011 SkCanvas* canvas = recorder.beginRecording(10, 10);
junov@chromium.orgd575eed2013-05-08 15:39:13 +00001012 canvas->clipPath(path, SkRegion::kIntersect_Op);
1013 canvas->clipPath(path2, SkRegion::kXOR_Op);
1014 bool nonEmpty = canvas->getClipDeviceBounds(&clipBounds);
1015 REPORTER_ASSERT(reporter, true == nonEmpty);
1016 REPORTER_ASSERT(reporter, 6 == clipBounds.fLeft);
1017 REPORTER_ASSERT(reporter, 6 == clipBounds.fTop);
1018 REPORTER_ASSERT(reporter, 8 == clipBounds.fBottom);
1019 REPORTER_ASSERT(reporter, 8 == clipBounds.fRight);
1020 }
1021}
1022
schenneyeeff8bb2015-07-07 14:27:10 -07001023static void test_cull_rect_reset(skiatest::Reporter* reporter) {
1024 SkPictureRecorder recorder;
1025 SkRect bounds = SkRect::MakeWH(10, 10);
1026 SkRTreeFactory factory;
1027 SkCanvas* canvas = recorder.beginRecording(bounds, &factory);
1028 bounds = SkRect::MakeWH(100, 100);
1029 SkPaint paint;
1030 canvas->drawRect(bounds, paint);
1031 canvas->drawRect(bounds, paint);
reedca2622b2016-03-18 07:25:55 -07001032 sk_sp<SkPicture> p(recorder.finishRecordingAsPictureWithCull(bounds));
mtkleineedc3342015-07-08 08:26:39 -07001033 const SkBigPicture* picture = p->asSkBigPicture();
schenneyeeff8bb2015-07-07 14:27:10 -07001034 REPORTER_ASSERT(reporter, picture);
1035
1036 SkRect finalCullRect = picture->cullRect();
1037 REPORTER_ASSERT(reporter, 0 == finalCullRect.fLeft);
1038 REPORTER_ASSERT(reporter, 0 == finalCullRect.fTop);
1039 REPORTER_ASSERT(reporter, 100 == finalCullRect.fBottom);
1040 REPORTER_ASSERT(reporter, 100 == finalCullRect.fRight);
1041
1042 const SkBBoxHierarchy* pictureBBH = picture->bbh();
1043 SkRect bbhCullRect = pictureBBH->getRootBound();
1044 REPORTER_ASSERT(reporter, 0 == bbhCullRect.fLeft);
1045 REPORTER_ASSERT(reporter, 0 == bbhCullRect.fTop);
1046 REPORTER_ASSERT(reporter, 100 == bbhCullRect.fBottom);
1047 REPORTER_ASSERT(reporter, 100 == bbhCullRect.fRight);
1048}
1049
1050
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +00001051/**
1052 * A canvas that records the number of clip commands.
1053 */
1054class ClipCountingCanvas : public SkCanvas {
1055public:
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +00001056 ClipCountingCanvas(int width, int height)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +00001057 : INHERITED(width, height)
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +00001058 , fClipCount(0){
1059 }
1060
skia.committer@gmail.com370a8992014-03-01 03:02:09 +00001061 virtual void onClipRect(const SkRect& r,
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::onClipRect(r, op, edgeStyle);
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +00001066 }
1067
skia.committer@gmail.com370a8992014-03-01 03:02:09 +00001068 virtual void onClipRRect(const SkRRect& rrect,
1069 SkRegion::Op op,
mtklein36352bf2015-03-25 18:17:31 -07001070 ClipEdgeStyle edgeStyle)override {
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +00001071 fClipCount += 1;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001072 this->INHERITED::onClipRRect(rrect, op, edgeStyle);
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +00001073 }
1074
skia.committer@gmail.com370a8992014-03-01 03:02:09 +00001075 virtual void onClipPath(const SkPath& path,
1076 SkRegion::Op op,
mtklein36352bf2015-03-25 18:17:31 -07001077 ClipEdgeStyle edgeStyle) override {
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +00001078 fClipCount += 1;
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001079 this->INHERITED::onClipPath(path, op, edgeStyle);
1080 }
1081
mtklein36352bf2015-03-25 18:17:31 -07001082 void onClipRegion(const SkRegion& deviceRgn, SkRegion::Op op) override {
robertphillips@google.com8f90a892014-02-28 18:19:39 +00001083 fClipCount += 1;
1084 this->INHERITED::onClipRegion(deviceRgn, op);
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +00001085 }
1086
1087 unsigned getClipCount() const { return fClipCount; }
1088
1089private:
1090 unsigned fClipCount;
1091
1092 typedef SkCanvas INHERITED;
1093};
1094
1095static void test_clip_expansion(skiatest::Reporter* reporter) {
robertphillips@google.com84b18c72014-04-13 19:09:42 +00001096 SkPictureRecorder recorder;
robertphillips9f1c2412014-06-09 06:25:34 -07001097 SkCanvas* canvas = recorder.beginRecording(10, 10);
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +00001098
1099 canvas->clipRect(SkRect::MakeEmpty(), SkRegion::kReplace_Op);
1100 // The following expanding clip should not be skipped.
1101 canvas->clipRect(SkRect::MakeXYWH(4, 4, 3, 3), SkRegion::kUnion_Op);
1102 // Draw something so the optimizer doesn't just fold the world.
1103 SkPaint p;
1104 p.setColor(SK_ColorBLUE);
1105 canvas->drawPaint(p);
reedca2622b2016-03-18 07:25:55 -07001106 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +00001107
commit-bot@chromium.orge2543102014-01-31 19:42:58 +00001108 ClipCountingCanvas testCanvas(10, 10);
robertphillipsc5ba71d2014-09-04 08:42:50 -07001109 picture->playback(&testCanvas);
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +00001110
1111 // Both clips should be present on playback.
1112 REPORTER_ASSERT(reporter, testCanvas.getClipCount() == 2);
1113}
1114
tomhudson@google.com381010e2013-10-24 11:12:47 +00001115static void test_hierarchical(skiatest::Reporter* reporter) {
1116 SkBitmap bm;
1117 make_bm(&bm, 10, 10, SK_ColorRED, true);
1118
robertphillips@google.com84b18c72014-04-13 19:09:42 +00001119 SkPictureRecorder recorder;
tomhudson@google.com381010e2013-10-24 11:12:47 +00001120
robertphillips9f1c2412014-06-09 06:25:34 -07001121 recorder.beginRecording(10, 10);
reedca2622b2016-03-18 07:25:55 -07001122 sk_sp<SkPicture> childPlain(recorder.finishRecordingAsPicture());
robertphillips@google.com84b18c72014-04-13 19:09:42 +00001123 REPORTER_ASSERT(reporter, !childPlain->willPlayBackBitmaps()); // 0
tomhudson@google.com381010e2013-10-24 11:12:47 +00001124
robertphillips9f1c2412014-06-09 06:25:34 -07001125 recorder.beginRecording(10, 10)->drawBitmap(bm, 0, 0);
reedca2622b2016-03-18 07:25:55 -07001126 sk_sp<SkPicture> childWithBitmap(recorder.finishRecordingAsPicture());
robertphillips@google.com84b18c72014-04-13 19:09:42 +00001127 REPORTER_ASSERT(reporter, childWithBitmap->willPlayBackBitmaps()); // 1
tomhudson@google.com381010e2013-10-24 11:12:47 +00001128
robertphillips@google.com84b18c72014-04-13 19:09:42 +00001129 {
robertphillips9f1c2412014-06-09 06:25:34 -07001130 SkCanvas* canvas = recorder.beginRecording(10, 10);
robertphillips9b14f262014-06-04 05:40:44 -07001131 canvas->drawPicture(childPlain);
reedca2622b2016-03-18 07:25:55 -07001132 sk_sp<SkPicture> parentPP(recorder.finishRecordingAsPicture());
robertphillips@google.com84b18c72014-04-13 19:09:42 +00001133 REPORTER_ASSERT(reporter, !parentPP->willPlayBackBitmaps()); // 0
1134 }
1135 {
robertphillips9f1c2412014-06-09 06:25:34 -07001136 SkCanvas* canvas = recorder.beginRecording(10, 10);
robertphillips9b14f262014-06-04 05:40:44 -07001137 canvas->drawPicture(childWithBitmap);
reedca2622b2016-03-18 07:25:55 -07001138 sk_sp<SkPicture> parentPWB(recorder.finishRecordingAsPicture());
robertphillips@google.com84b18c72014-04-13 19:09:42 +00001139 REPORTER_ASSERT(reporter, parentPWB->willPlayBackBitmaps()); // 1
1140 }
1141 {
robertphillips9f1c2412014-06-09 06:25:34 -07001142 SkCanvas* canvas = recorder.beginRecording(10, 10);
robertphillips@google.com84b18c72014-04-13 19:09:42 +00001143 canvas->drawBitmap(bm, 0, 0);
robertphillips9b14f262014-06-04 05:40:44 -07001144 canvas->drawPicture(childPlain);
reedca2622b2016-03-18 07:25:55 -07001145 sk_sp<SkPicture> parentWBP(recorder.finishRecordingAsPicture());
robertphillips@google.com84b18c72014-04-13 19:09:42 +00001146 REPORTER_ASSERT(reporter, parentWBP->willPlayBackBitmaps()); // 1
1147 }
1148 {
robertphillips9f1c2412014-06-09 06:25:34 -07001149 SkCanvas* canvas = recorder.beginRecording(10, 10);
robertphillips@google.com84b18c72014-04-13 19:09:42 +00001150 canvas->drawBitmap(bm, 0, 0);
robertphillips9b14f262014-06-04 05:40:44 -07001151 canvas->drawPicture(childWithBitmap);
reedca2622b2016-03-18 07:25:55 -07001152 sk_sp<SkPicture> parentWBWB(recorder.finishRecordingAsPicture());
robertphillips@google.com84b18c72014-04-13 19:09:42 +00001153 REPORTER_ASSERT(reporter, parentWBWB->willPlayBackBitmaps()); // 2
1154 }
tomhudson@google.com381010e2013-10-24 11:12:47 +00001155}
1156
robertphillips@google.comd5500882014-04-02 23:51:13 +00001157static void test_gen_id(skiatest::Reporter* reporter) {
1158
Robert Phillipscfaeec42014-07-13 12:00:50 -04001159 SkPictureRecorder recorder;
1160 recorder.beginRecording(0, 0);
reedca2622b2016-03-18 07:25:55 -07001161 sk_sp<SkPicture> empty(recorder.finishRecordingAsPicture());
robertphillips@google.comd5500882014-04-02 23:51:13 +00001162
robertphillips@google.com84b18c72014-04-13 19:09:42 +00001163 // Empty pictures should still have a valid ID
Robert Phillipscfaeec42014-07-13 12:00:50 -04001164 REPORTER_ASSERT(reporter, empty->uniqueID() != SK_InvalidGenID);
robertphillips@google.comd5500882014-04-02 23:51:13 +00001165
robertphillips9f1c2412014-06-09 06:25:34 -07001166 SkCanvas* canvas = recorder.beginRecording(1, 1);
robertphillips@google.com84b18c72014-04-13 19:09:42 +00001167 canvas->drawARGB(255, 255, 255, 255);
reedca2622b2016-03-18 07:25:55 -07001168 sk_sp<SkPicture> hasData(recorder.finishRecordingAsPicture());
robertphillips@google.com84b18c72014-04-13 19:09:42 +00001169 // picture should have a non-zero id after recording
1170 REPORTER_ASSERT(reporter, hasData->uniqueID() != SK_InvalidGenID);
robertphillips@google.comd5500882014-04-02 23:51:13 +00001171
robertphillips@google.com84b18c72014-04-13 19:09:42 +00001172 // both pictures should have different ids
Robert Phillipscfaeec42014-07-13 12:00:50 -04001173 REPORTER_ASSERT(reporter, hasData->uniqueID() != empty->uniqueID());
robertphillips@google.comd5500882014-04-02 23:51:13 +00001174}
1175
caryclark5ef194c2015-08-31 09:22:38 -07001176static void test_typeface(skiatest::Reporter* reporter) {
1177 SkPictureRecorder recorder;
1178 SkCanvas* canvas = recorder.beginRecording(10, 10);
1179 SkPaint paint;
1180 paint.setTypeface(SkTypeface::CreateFromName("Arial", SkTypeface::kItalic));
1181 canvas->drawText("Q", 1, 0, 10, paint);
reedca2622b2016-03-18 07:25:55 -07001182 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
caryclark5ef194c2015-08-31 09:22:38 -07001183 REPORTER_ASSERT(reporter, picture->hasText());
1184 SkDynamicMemoryWStream stream;
1185 picture->serialize(&stream);
1186}
1187
tfarina@chromium.orge4fafb12013-12-12 21:11:12 +00001188DEF_TEST(Picture, reporter) {
caryclark5ef194c2015-08-31 09:22:38 -07001189 test_typeface(reporter);
scroggo@google.comd614c6a2012-09-14 17:26:37 +00001190#ifdef SK_DEBUG
robertphillipsdb539902014-07-01 08:47:04 -07001191 test_deleting_empty_picture();
scroggo@google.comd614c6a2012-09-14 17:26:37 +00001192 test_serializing_empty_picture();
scroggo@google.com4b90b112012-12-04 15:08:56 +00001193#else
1194 test_bad_bitmap();
scroggo@google.comd614c6a2012-09-14 17:26:37 +00001195#endif
commit-bot@chromium.orgea7d08e2014-02-13 16:00:51 +00001196 test_unbalanced_save_restores(reporter);
sugoi@google.com54f0d1b2013-02-27 19:17:41 +00001197 test_peephole();
robertphillips@google.comb950c6f2014-04-25 00:02:12 +00001198#if SK_SUPPORT_GPU
mtklein8e126562014-10-01 09:29:35 -07001199 test_gpu_veto(reporter);
robertphillips@google.comb950c6f2014-04-25 00:02:12 +00001200#endif
mtklein8e126562014-10-01 09:29:35 -07001201 test_has_text(reporter);
mtkleina16af212015-08-26 08:14:52 -07001202 test_images_are_found_by_willPlayBackBitmaps(reporter);
mtklein8e126562014-10-01 09:29:35 -07001203 test_analysis(reporter);
junov@chromium.orgd575eed2013-05-08 15:39:13 +00001204 test_clip_bound_opt(reporter);
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +00001205 test_clip_expansion(reporter);
tomhudson@google.com381010e2013-10-24 11:12:47 +00001206 test_hierarchical(reporter);
robertphillips@google.comd5500882014-04-02 23:51:13 +00001207 test_gen_id(reporter);
robertphillips82365912014-11-12 09:32:34 -08001208 test_savelayer_extraction(reporter);
schenneyeeff8bb2015-07-07 14:27:10 -07001209 test_cull_rect_reset(reporter);
scroggo@google.comd614c6a2012-09-14 17:26:37 +00001210}
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001211
1212static void draw_bitmaps(const SkBitmap bitmap, SkCanvas* canvas) {
1213 const SkPaint paint;
1214 const SkRect rect = { 5.0f, 5.0f, 8.0f, 8.0f };
1215 const SkIRect irect = { 2, 2, 3, 3 };
1216
1217 // Don't care what these record, as long as they're legal.
1218 canvas->drawBitmap(bitmap, 0.0f, 0.0f, &paint);
reede47829b2015-08-06 10:02:53 -07001219 canvas->drawBitmapRect(bitmap, rect, rect, &paint, SkCanvas::kStrict_SrcRectConstraint);
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001220 canvas->drawBitmapNine(bitmap, irect, rect, &paint);
reedda420b92015-12-16 08:38:15 -08001221 canvas->drawBitmap(bitmap, 1, 1); // drawSprite
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001222}
1223
1224static void test_draw_bitmaps(SkCanvas* canvas) {
1225 SkBitmap empty;
1226 draw_bitmaps(empty, canvas);
commit-bot@chromium.orga3264e52014-05-30 13:26:10 +00001227 empty.setInfo(SkImageInfo::MakeN32Premul(10, 10));
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001228 draw_bitmaps(empty, canvas);
1229}
1230
1231DEF_TEST(Picture_EmptyBitmap, r) {
robertphillips@google.com84b18c72014-04-13 19:09:42 +00001232 SkPictureRecorder recorder;
robertphillips9f1c2412014-06-09 06:25:34 -07001233 test_draw_bitmaps(recorder.beginRecording(10, 10));
reedca2622b2016-03-18 07:25:55 -07001234 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001235}
1236
1237DEF_TEST(Canvas_EmptyBitmap, r) {
1238 SkBitmap dst;
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +00001239 dst.allocN32Pixels(10, 10);
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +00001240 SkCanvas canvas(dst);
1241
1242 test_draw_bitmaps(&canvas);
1243}
dneto3f22e8c2014-07-30 15:42:22 -07001244
1245DEF_TEST(DontOptimizeSaveLayerDrawDrawRestore, reporter) {
1246 // This test is from crbug.com/344987.
1247 // The commands are:
1248 // saveLayer with paint that modifies alpha
reed84984ef2015-07-17 07:09:43 -07001249 // drawBitmapRect
1250 // drawBitmapRect
dneto3f22e8c2014-07-30 15:42:22 -07001251 // restore
1252 // The bug was that this structure was modified so that:
1253 // - The saveLayer and restore were eliminated
1254 // - The alpha was only applied to the first drawBitmapRectToRect
1255
1256 // This test draws blue and red squares inside a 50% transparent
1257 // layer. Both colours should show up muted.
1258 // When the bug is present, the red square (the second bitmap)
1259 // shows upwith full opacity.
1260
1261 SkBitmap blueBM;
1262 make_bm(&blueBM, 100, 100, SkColorSetARGB(255, 0, 0, 255), true);
1263 SkBitmap redBM;
1264 make_bm(&redBM, 100, 100, SkColorSetARGB(255, 255, 0, 0), true);
1265 SkPaint semiTransparent;
1266 semiTransparent.setAlpha(0x80);
1267
1268 SkPictureRecorder recorder;
1269 SkCanvas* canvas = recorder.beginRecording(100, 100);
1270 canvas->drawARGB(0, 0, 0, 0);
1271
1272 canvas->saveLayer(0, &semiTransparent);
1273 canvas->drawBitmap(blueBM, 25, 25);
1274 canvas->drawBitmap(redBM, 50, 50);
1275 canvas->restore();
1276
reedca2622b2016-03-18 07:25:55 -07001277 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
dneto3f22e8c2014-07-30 15:42:22 -07001278
1279 // Now replay the picture back on another canvas
1280 // and check a couple of its pixels.
1281 SkBitmap replayBM;
1282 make_bm(&replayBM, 100, 100, SK_ColorBLACK, false);
1283 SkCanvas replayCanvas(replayBM);
robertphillipsc5ba71d2014-09-04 08:42:50 -07001284 picture->playback(&replayCanvas);
dneto3f22e8c2014-07-30 15:42:22 -07001285 replayCanvas.flush();
1286
1287 // With the bug present, at (55, 55) we would get a fully opaque red
1288 // intead of a dark red.
1289 REPORTER_ASSERT(reporter, replayBM.getColor(30, 30) == 0xff000080);
1290 REPORTER_ASSERT(reporter, replayBM.getColor(55, 55) == 0xff800000);
1291}
mtklein3e8232b2014-08-18 13:39:11 -07001292
1293struct CountingBBH : public SkBBoxHierarchy {
1294 mutable int searchCalls;
schenney23d85932015-03-06 16:20:28 -08001295 SkRect rootBound;
mtklein3e8232b2014-08-18 13:39:11 -07001296
schenney23d85932015-03-06 16:20:28 -08001297 CountingBBH(const SkRect& bound) : searchCalls(0), rootBound(bound) {}
mtklein3e8232b2014-08-18 13:39:11 -07001298
mtkleinc6ad06a2015-08-19 09:51:00 -07001299 void search(const SkRect& query, SkTDArray<int>* results) const override {
mtklein3e8232b2014-08-18 13:39:11 -07001300 this->searchCalls++;
1301 }
1302
mtklein36352bf2015-03-25 18:17:31 -07001303 void insert(const SkRect[], int) override {}
1304 virtual size_t bytesUsed() const override { return 0; }
1305 SkRect getRootBound() const override { return rootBound; }
mtklein3e8232b2014-08-18 13:39:11 -07001306};
1307
1308class SpoonFedBBHFactory : public SkBBHFactory {
1309public:
1310 explicit SpoonFedBBHFactory(SkBBoxHierarchy* bbh) : fBBH(bbh) {}
mtklein36352bf2015-03-25 18:17:31 -07001311 SkBBoxHierarchy* operator()(const SkRect&) const override {
mtklein3e8232b2014-08-18 13:39:11 -07001312 return SkRef(fBBH);
1313 }
1314private:
1315 SkBBoxHierarchy* fBBH;
1316};
1317
1318// When the canvas clip covers the full picture, we don't need to call the BBH.
1319DEF_TEST(Picture_SkipBBH, r) {
schenney23d85932015-03-06 16:20:28 -08001320 SkRect bound = SkRect::MakeWH(320, 240);
1321 CountingBBH bbh(bound);
mtklein3e8232b2014-08-18 13:39:11 -07001322 SpoonFedBBHFactory factory(&bbh);
1323
1324 SkPictureRecorder recorder;
mtklein9db912c2015-05-19 11:11:26 -07001325 SkCanvas* c = recorder.beginRecording(bound, &factory);
1326 // Record a few ops so we don't hit a small- or empty- picture optimization.
1327 c->drawRect(bound, SkPaint());
1328 c->drawRect(bound, SkPaint());
reedca2622b2016-03-18 07:25:55 -07001329 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
mtklein3e8232b2014-08-18 13:39:11 -07001330
1331 SkCanvas big(640, 480), small(300, 200);
1332
robertphillipsc5ba71d2014-09-04 08:42:50 -07001333 picture->playback(&big);
mtklein3e8232b2014-08-18 13:39:11 -07001334 REPORTER_ASSERT(r, bbh.searchCalls == 0);
1335
robertphillipsc5ba71d2014-09-04 08:42:50 -07001336 picture->playback(&small);
mtklein3e8232b2014-08-18 13:39:11 -07001337 REPORTER_ASSERT(r, bbh.searchCalls == 1);
1338}
mtkleind72094d2014-08-27 12:12:23 -07001339
1340DEF_TEST(Picture_BitmapLeak, r) {
1341 SkBitmap mut, immut;
1342 mut.allocN32Pixels(300, 200);
1343 immut.allocN32Pixels(300, 200);
1344 immut.setImmutable();
1345 SkASSERT(!mut.isImmutable());
1346 SkASSERT(immut.isImmutable());
1347
1348 // No one can hold a ref on our pixels yet.
1349 REPORTER_ASSERT(r, mut.pixelRef()->unique());
1350 REPORTER_ASSERT(r, immut.pixelRef()->unique());
1351
reedca2622b2016-03-18 07:25:55 -07001352 sk_sp<SkPicture> pic;
reed1bdfd3f2014-11-24 14:41:51 -08001353 {
1354 // we want the recorder to go out of scope before our subsequent checks, so we
1355 // place it inside local braces.
1356 SkPictureRecorder rec;
1357 SkCanvas* canvas = rec.beginRecording(1920, 1200);
1358 canvas->drawBitmap(mut, 0, 0);
1359 canvas->drawBitmap(immut, 800, 600);
reedca2622b2016-03-18 07:25:55 -07001360 pic = rec.finishRecordingAsPicture();
reed1bdfd3f2014-11-24 14:41:51 -08001361 }
mtkleind72094d2014-08-27 12:12:23 -07001362
1363 // The picture shares the immutable pixels but copies the mutable ones.
1364 REPORTER_ASSERT(r, mut.pixelRef()->unique());
1365 REPORTER_ASSERT(r, !immut.pixelRef()->unique());
1366
1367 // When the picture goes away, it's just our bitmaps holding the refs.
reedca2622b2016-03-18 07:25:55 -07001368 pic = nullptr;
mtkleind72094d2014-08-27 12:12:23 -07001369 REPORTER_ASSERT(r, mut.pixelRef()->unique());
1370 REPORTER_ASSERT(r, immut.pixelRef()->unique());
1371}
mtkleinfeaadee2015-04-08 11:25:48 -07001372
1373// getRecordingCanvas() should return a SkCanvas when recording, null when not recording.
1374DEF_TEST(Picture_getRecordingCanvas, r) {
1375 SkPictureRecorder rec;
1376 REPORTER_ASSERT(r, !rec.getRecordingCanvas());
1377 for (int i = 0; i < 3; i++) {
1378 rec.beginRecording(100, 100);
1379 REPORTER_ASSERT(r, rec.getRecordingCanvas());
reedca2622b2016-03-18 07:25:55 -07001380 rec.finishRecordingAsPicture();
mtkleinfeaadee2015-04-08 11:25:48 -07001381 REPORTER_ASSERT(r, !rec.getRecordingCanvas());
1382 }
1383}
mtklein9db912c2015-05-19 11:11:26 -07001384
1385DEF_TEST(MiniRecorderLeftHanging, r) {
1386 // Any shader or other ref-counted effect will do just fine here.
1387 SkPaint paint;
reed1a9b9642016-03-13 14:13:58 -07001388 paint.setShader(SkShader::MakeColorShader(SK_ColorRED));
mtklein9db912c2015-05-19 11:11:26 -07001389
1390 SkMiniRecorder rec;
1391 REPORTER_ASSERT(r, rec.drawRect(SkRect::MakeWH(20,30), paint));
1392 // Don't call rec.detachPicture(). Test succeeds by not asserting or leaking the shader.
1393}
fmalita2ecc0002015-07-14 13:12:25 -07001394
1395DEF_TEST(Picture_preserveCullRect, r) {
1396 SkPictureRecorder recorder;
1397
1398 SkCanvas* c = recorder.beginRecording(SkRect::MakeLTRB(1, 2, 3, 4));
1399 c->clear(SK_ColorCYAN);
1400
reedca2622b2016-03-18 07:25:55 -07001401 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
fmalita2ecc0002015-07-14 13:12:25 -07001402 SkDynamicMemoryWStream wstream;
1403 picture->serialize(&wstream);
1404
1405 SkAutoTDelete<SkStream> rstream(wstream.detachAsStream());
reedca2622b2016-03-18 07:25:55 -07001406 sk_sp<SkPicture> deserializedPicture(SkPicture::MakeFromStream(rstream));
fmalita2ecc0002015-07-14 13:12:25 -07001407
mtklein5f939ab2016-03-16 10:28:35 -07001408 REPORTER_ASSERT(r, deserializedPicture != nullptr);
fmalita2ecc0002015-07-14 13:12:25 -07001409 REPORTER_ASSERT(r, deserializedPicture->cullRect().left() == 1);
1410 REPORTER_ASSERT(r, deserializedPicture->cullRect().top() == 2);
1411 REPORTER_ASSERT(r, deserializedPicture->cullRect().right() == 3);
1412 REPORTER_ASSERT(r, deserializedPicture->cullRect().bottom() == 4);
1413}