blob: 7179e70101f64d6962c85636a2fb3191867979e4 [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
robertphillipsdda54452016-07-13 13:27:16 -07008#include "SkBigPicture.h"
mtklein3e8232b2014-08-18 13:39:11 -07009#include "SkBBoxHierarchy.h"
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +000010#include "SkBlurImageFilter.h"
reed@google.com21b519d2012-10-02 17:42:15 +000011#include "SkCanvas.h"
robertphillipsd8aa7b72014-10-30 16:45:02 -070012#include "SkColorMatrixFilter.h"
reed@google.comfe7b1ed2012-11-29 21:00:39 +000013#include "SkColorPriv.h"
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +000014#include "SkDashPathEffect.h"
reed@google.comfe7b1ed2012-11-29 21:00:39 +000015#include "SkData.h"
reed5965c8a2015-01-07 18:04:45 -080016#include "SkImageGenerator.h"
halcanary@google.com3d50ea12014-01-02 13:15:13 +000017#include "SkImageEncoder.h"
18#include "SkImageGenerator.h"
msarett8715d472016-02-17 10:02:29 -080019#include "SkMD5.h"
reed@google.com21b519d2012-10-02 17:42:15 +000020#include "SkPaint.h"
scroggo@google.comd614c6a2012-09-14 17:26:37 +000021#include "SkPicture.h"
fmalita796e3652016-05-13 11:40:07 -070022#include "SkPictureAnalyzer.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));
Mike Reed627778d2016-09-28 17:13:38 -040084 REPORTER_ASSERT(reporter, paint.getShader()->isAImage());
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
fmalitab5fc58e2016-05-25 11:31:04 -0700137static SkPath make_convex_path() {
138 SkPath path;
139 path.lineTo(100, 0);
140 path.lineTo(50, 100);
141 path.close();
142
143 return path;
144}
145
146static SkPath make_concave_path() {
147 SkPath path;
148 path.lineTo(50, 50);
149 path.lineTo(100, 0);
150 path.lineTo(50, 100);
151 path.close();
152
153 return path;
154}
155
mtklein8e126562014-10-01 09:29:35 -0700156static void test_gpu_veto(skiatest::Reporter* reporter) {
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +0000157 SkPictureRecorder recorder;
158
mtklein8e126562014-10-01 09:29:35 -0700159 SkCanvas* canvas = recorder.beginRecording(100, 100);
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +0000160 {
161 SkPath path;
162 path.moveTo(0, 0);
163 path.lineTo(50, 50);
164
165 SkScalar intervals[] = { 1.0f, 1.0f };
reeda4393342016-03-18 11:22:57 -0700166 sk_sp<SkPathEffect> dash(SkDashPathEffect::Make(intervals, 2, 0));
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +0000167
168 SkPaint paint;
169 paint.setStyle(SkPaint::kStroke_Style);
170 paint.setPathEffect(dash);
171
robertphillips98b03152015-01-26 11:29:36 -0800172 for (int i = 0; i < 50; ++i) {
173 canvas->drawPath(path, paint);
174 }
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +0000175 }
reedca2622b2016-03-18 07:25:55 -0700176 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +0000177 // path effects currently render an SkPicture undesireable for GPU rendering
commit-bot@chromium.orga1ff26a2014-05-30 21:52:52 +0000178
halcanary96fcdcc2015-08-27 07:41:13 -0700179 const char *reason = nullptr;
fmalita796e3652016-05-13 11:40:07 -0700180 REPORTER_ASSERT(reporter,
181 !SkPictureGpuAnalyzer(picture).suitableForGpuRasterization(&reason));
bsalomon49f085d2014-09-05 13:34:00 -0700182 REPORTER_ASSERT(reporter, reason);
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +0000183
mtklein8e126562014-10-01 09:29:35 -0700184 canvas = recorder.beginRecording(100, 100);
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +0000185 {
186 SkPath path;
187
188 path.moveTo(0, 0);
189 path.lineTo(0, 50);
190 path.lineTo(25, 25);
191 path.lineTo(50, 50);
192 path.lineTo(50, 0);
193 path.close();
194 REPORTER_ASSERT(reporter, !path.isConvex());
195
196 SkPaint paint;
197 paint.setAntiAlias(true);
198 for (int i = 0; i < 50; ++i) {
199 canvas->drawPath(path, paint);
200 }
201 }
reedca2622b2016-03-18 07:25:55 -0700202 picture = recorder.finishRecordingAsPicture();
jvanverthd86b07a2014-11-04 08:50:15 -0800203 // A lot of small AA concave paths should be fine for GPU rendering
fmalita796e3652016-05-13 11:40:07 -0700204 REPORTER_ASSERT(reporter, SkPictureGpuAnalyzer(picture).suitableForGpuRasterization());
jvanverthd86b07a2014-11-04 08:50:15 -0800205
206 canvas = recorder.beginRecording(100, 100);
207 {
208 SkPath path;
209
210 path.moveTo(0, 0);
211 path.lineTo(0, 100);
212 path.lineTo(50, 50);
213 path.lineTo(100, 100);
214 path.lineTo(100, 0);
215 path.close();
216 REPORTER_ASSERT(reporter, !path.isConvex());
217
218 SkPaint paint;
219 paint.setAntiAlias(true);
220 for (int i = 0; i < 50; ++i) {
221 canvas->drawPath(path, paint);
222 }
223 }
reedca2622b2016-03-18 07:25:55 -0700224 picture = recorder.finishRecordingAsPicture();
jvanverthd86b07a2014-11-04 08:50:15 -0800225 // A lot of large AA concave paths currently render an SkPicture undesireable for GPU rendering
fmalita796e3652016-05-13 11:40:07 -0700226 REPORTER_ASSERT(reporter, !SkPictureGpuAnalyzer(picture).suitableForGpuRasterization());
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +0000227
mtklein8e126562014-10-01 09:29:35 -0700228 canvas = recorder.beginRecording(100, 100);
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +0000229 {
230 SkPath path;
231
232 path.moveTo(0, 0);
233 path.lineTo(0, 50);
234 path.lineTo(25, 25);
235 path.lineTo(50, 50);
236 path.lineTo(50, 0);
237 path.close();
238 REPORTER_ASSERT(reporter, !path.isConvex());
239
240 SkPaint paint;
241 paint.setAntiAlias(true);
242 paint.setStyle(SkPaint::kStroke_Style);
243 paint.setStrokeWidth(0);
244 for (int i = 0; i < 50; ++i) {
245 canvas->drawPath(path, paint);
246 }
247 }
reedca2622b2016-03-18 07:25:55 -0700248 picture = recorder.finishRecordingAsPicture();
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +0000249 // hairline stroked AA concave paths are fine for GPU rendering
fmalita796e3652016-05-13 11:40:07 -0700250 REPORTER_ASSERT(reporter, SkPictureGpuAnalyzer(picture).suitableForGpuRasterization());
tomhudson3a0f2792014-08-20 05:29:41 -0700251
mtklein8e126562014-10-01 09:29:35 -0700252 canvas = recorder.beginRecording(100, 100);
tomhudson3a0f2792014-08-20 05:29:41 -0700253 {
254 SkPaint paint;
255 SkScalar intervals [] = { 10, 20 };
reeda4393342016-03-18 11:22:57 -0700256 paint.setPathEffect(SkDashPathEffect::Make(intervals, 2, 25));
tomhudson3a0f2792014-08-20 05:29:41 -0700257
258 SkPoint points [2] = { { 0, 0 }, { 100, 0 } };
robertphillips98b03152015-01-26 11:29:36 -0800259
260 for (int i = 0; i < 50; ++i) {
261 canvas->drawPoints(SkCanvas::kLines_PointMode, 2, points, paint);
262 }
tomhudson3a0f2792014-08-20 05:29:41 -0700263 }
reedca2622b2016-03-18 07:25:55 -0700264 picture = recorder.finishRecordingAsPicture();
tomhudson3a0f2792014-08-20 05:29:41 -0700265 // fast-path dashed effects are fine for GPU rendering ...
fmalita796e3652016-05-13 11:40:07 -0700266 REPORTER_ASSERT(reporter, SkPictureGpuAnalyzer(picture).suitableForGpuRasterization());
tomhudson3a0f2792014-08-20 05:29:41 -0700267
mtklein8e126562014-10-01 09:29:35 -0700268 canvas = recorder.beginRecording(100, 100);
tomhudson3a0f2792014-08-20 05:29:41 -0700269 {
270 SkPaint paint;
271 SkScalar intervals [] = { 10, 20 };
reeda4393342016-03-18 11:22:57 -0700272 paint.setPathEffect(SkDashPathEffect::Make(intervals, 2, 25));
tomhudson3a0f2792014-08-20 05:29:41 -0700273
robertphillips98b03152015-01-26 11:29:36 -0800274 for (int i = 0; i < 50; ++i) {
275 canvas->drawRect(SkRect::MakeWH(10, 10), paint);
276 }
tomhudson3a0f2792014-08-20 05:29:41 -0700277 }
reedca2622b2016-03-18 07:25:55 -0700278 picture = recorder.finishRecordingAsPicture();
tomhudson3a0f2792014-08-20 05:29:41 -0700279 // ... but only when applied to drawPoint() calls
fmalita796e3652016-05-13 11:40:07 -0700280 REPORTER_ASSERT(reporter, !SkPictureGpuAnalyzer(picture).suitableForGpuRasterization());
mtklein53fecfb2014-08-21 09:11:37 -0700281
fmalitab5fc58e2016-05-25 11:31:04 -0700282 canvas = recorder.beginRecording(100, 100);
283 {
284 const SkPath convexClip = make_convex_path();
285 const SkPath concaveClip = make_concave_path();
286
287 for (int i = 0; i < 50; ++i) {
288 canvas->clipPath(convexClip);
289 canvas->clipPath(concaveClip);
Mike Reedc1f77742016-12-09 09:00:50 -0500290 canvas->clipPath(convexClip, kIntersect_SkClipOp, true);
fmalitab5fc58e2016-05-25 11:31:04 -0700291 canvas->drawRect(SkRect::MakeWH(100, 100), SkPaint());
292 }
293 }
294 picture = recorder.finishRecordingAsPicture();
295 // Convex clips and non-AA concave clips are fine on the GPU.
296 REPORTER_ASSERT(reporter, SkPictureGpuAnalyzer(picture).suitableForGpuRasterization());
297
298 canvas = recorder.beginRecording(100, 100);
299 {
300 const SkPath concaveClip = make_concave_path();
301 for (int i = 0; i < 50; ++i) {
Mike Reedc1f77742016-12-09 09:00:50 -0500302 canvas->clipPath(concaveClip, kIntersect_SkClipOp, true);
fmalitab5fc58e2016-05-25 11:31:04 -0700303 canvas->drawRect(SkRect::MakeWH(100, 100), SkPaint());
304 }
305 }
306 picture = recorder.finishRecordingAsPicture();
307 // ... but AA concave clips are not.
308 REPORTER_ASSERT(reporter, !SkPictureGpuAnalyzer(picture).suitableForGpuRasterization());
309
mtklein53fecfb2014-08-21 09:11:37 -0700310 // Nest the previous picture inside a new one.
mtklein8e126562014-10-01 09:29:35 -0700311 canvas = recorder.beginRecording(100, 100);
312 {
fmalita796e3652016-05-13 11:40:07 -0700313 canvas->drawPicture(picture);
mtklein53fecfb2014-08-21 09:11:37 -0700314 }
reedca2622b2016-03-18 07:25:55 -0700315 picture = recorder.finishRecordingAsPicture();
fmalita796e3652016-05-13 11:40:07 -0700316 REPORTER_ASSERT(reporter, !SkPictureGpuAnalyzer(picture).suitableForGpuRasterization());
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +0000317}
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +0000318
fmalita796e3652016-05-13 11:40:07 -0700319#endif // SK_SUPPORT_GPU
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +0000320
commit-bot@chromium.orgea7d08e2014-02-13 16:00:51 +0000321static void set_canvas_to_save_count_4(SkCanvas* canvas) {
322 canvas->restoreToCount(1);
323 canvas->save();
324 canvas->save();
325 canvas->save();
326}
327
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000328/**
329 * A canvas that records the number of saves, saveLayers and restores.
330 */
331class SaveCountingCanvas : public SkCanvas {
332public:
333 SaveCountingCanvas(int width, int height)
334 : INHERITED(width, height)
335 , fSaveCount(0)
336 , fSaveLayerCount(0)
337 , fRestoreCount(0){
338 }
339
reed4960eee2015-12-18 07:09:18 -0800340 SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec& rec) override {
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000341 ++fSaveLayerCount;
reed4960eee2015-12-18 07:09:18 -0800342 return this->INHERITED::getSaveLayerStrategy(rec);
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000343 }
344
mtklein36352bf2015-03-25 18:17:31 -0700345 void willSave() override {
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000346 ++fSaveCount;
Florin Malita5f6102d2014-06-30 10:13:28 -0400347 this->INHERITED::willSave();
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000348 }
349
mtklein36352bf2015-03-25 18:17:31 -0700350 void willRestore() override {
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000351 ++fRestoreCount;
352 this->INHERITED::willRestore();
353 }
354
355 unsigned int getSaveCount() const { return fSaveCount; }
356 unsigned int getSaveLayerCount() const { return fSaveLayerCount; }
357 unsigned int getRestoreCount() const { return fRestoreCount; }
358
359private:
360 unsigned int fSaveCount;
361 unsigned int fSaveLayerCount;
362 unsigned int fRestoreCount;
363
364 typedef SkCanvas INHERITED;
365};
366
skia.committer@gmail.com8e7d37d2014-05-28 03:06:06 +0000367void check_save_state(skiatest::Reporter* reporter, SkPicture* picture,
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000368 unsigned int numSaves, unsigned int numSaveLayers,
369 unsigned int numRestores) {
mtklein87c41382014-09-08 07:31:18 -0700370 SaveCountingCanvas canvas(SkScalarCeilToInt(picture->cullRect().width()),
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700371 SkScalarCeilToInt(picture->cullRect().height()));
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000372
robertphillipsc5ba71d2014-09-04 08:42:50 -0700373 picture->playback(&canvas);
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000374
mtklein87c41382014-09-08 07:31:18 -0700375 // Optimizations may have removed these,
376 // so expect to have seen no more than num{Saves,SaveLayers,Restores}.
377 REPORTER_ASSERT(reporter, numSaves >= canvas.getSaveCount());
378 REPORTER_ASSERT(reporter, numSaveLayers >= canvas.getSaveLayerCount());
379 REPORTER_ASSERT(reporter, numRestores >= canvas.getRestoreCount());
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000380}
381
382// This class exists so SkPicture can friend it and give it access to
383// the 'partialReplay' method.
384class SkPictureRecorderReplayTester {
385public:
reedca2622b2016-03-18 07:25:55 -0700386 static sk_sp<SkPicture> Copy(SkPictureRecorder* recorder) {
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000387 SkPictureRecorder recorder2;
388
robertphillips9f1c2412014-06-09 06:25:34 -0700389 SkCanvas* canvas = recorder2.beginRecording(10, 10);
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000390
391 recorder->partialReplay(canvas);
392
reedca2622b2016-03-18 07:25:55 -0700393 return recorder2.finishRecordingAsPicture();
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000394 }
395};
396
robertphillips9058d602014-06-10 11:45:46 -0700397static void create_imbalance(SkCanvas* canvas) {
398 SkRect clipRect = SkRect::MakeWH(2, 2);
399 SkRect drawRect = SkRect::MakeWH(10, 10);
400 canvas->save();
Mike Reedc1f77742016-12-09 09:00:50 -0500401 canvas->clipRect(clipRect, kReplace_SkClipOp);
robertphillips9058d602014-06-10 11:45:46 -0700402 canvas->translate(1.0f, 1.0f);
403 SkPaint p;
404 p.setColor(SK_ColorGREEN);
405 canvas->drawRect(drawRect, p);
406 // no restore
407}
408
409// This tests that replaying a potentially unbalanced picture into a canvas
410// doesn't affect the canvas' save count or matrix/clip state.
411static void check_balance(skiatest::Reporter* reporter, SkPicture* picture) {
412 SkBitmap bm;
413 bm.allocN32Pixels(4, 3);
414 SkCanvas canvas(bm);
415
416 int beforeSaveCount = canvas.getSaveCount();
417
418 SkMatrix beforeMatrix = canvas.getTotalMatrix();
419
Mike Reed918e1442017-01-23 11:39:45 -0500420 SkRect beforeClip = canvas.getLocalClipBounds();
robertphillips9058d602014-06-10 11:45:46 -0700421
422 canvas.drawPicture(picture);
423
424 REPORTER_ASSERT(reporter, beforeSaveCount == canvas.getSaveCount());
425 REPORTER_ASSERT(reporter, beforeMatrix == canvas.getTotalMatrix());
426
Mike Reed918e1442017-01-23 11:39:45 -0500427 SkRect afterClip = canvas.getLocalClipBounds();
robertphillips9058d602014-06-10 11:45:46 -0700428
429 REPORTER_ASSERT(reporter, afterClip == beforeClip);
430}
431
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000432// Test out SkPictureRecorder::partialReplay
433DEF_TEST(PictureRecorder_replay, reporter) {
434 // check save/saveLayer state
435 {
436 SkPictureRecorder recorder;
437
robertphillips9f1c2412014-06-09 06:25:34 -0700438 SkCanvas* canvas = recorder.beginRecording(10, 10);
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000439
halcanary96fcdcc2015-08-27 07:41:13 -0700440 canvas->saveLayer(nullptr, nullptr);
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000441
reedca2622b2016-03-18 07:25:55 -0700442 sk_sp<SkPicture> copy(SkPictureRecorderReplayTester::Copy(&recorder));
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000443
444 // The extra save and restore comes from the Copy process.
reedca2622b2016-03-18 07:25:55 -0700445 check_save_state(reporter, copy.get(), 2, 1, 3);
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000446
halcanary96fcdcc2015-08-27 07:41:13 -0700447 canvas->saveLayer(nullptr, nullptr);
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000448
reedca2622b2016-03-18 07:25:55 -0700449 sk_sp<SkPicture> final(recorder.finishRecordingAsPicture());
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000450
reedca2622b2016-03-18 07:25:55 -0700451 check_save_state(reporter, final.get(), 1, 2, 3);
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000452
453 // The copy shouldn't pick up any operations added after it was made
reedca2622b2016-03-18 07:25:55 -0700454 check_save_state(reporter, copy.get(), 2, 1, 3);
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000455 }
456
457 // (partially) check leakage of draw ops
458 {
459 SkPictureRecorder recorder;
460
robertphillips9f1c2412014-06-09 06:25:34 -0700461 SkCanvas* canvas = recorder.beginRecording(10, 10);
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000462
463 SkRect r = SkRect::MakeWH(5, 5);
464 SkPaint p;
465
466 canvas->drawRect(r, p);
467
reedca2622b2016-03-18 07:25:55 -0700468 sk_sp<SkPicture> copy(SkPictureRecorderReplayTester::Copy(&recorder));
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000469
470 REPORTER_ASSERT(reporter, !copy->willPlayBackBitmaps());
471
472 SkBitmap bm;
473 make_bm(&bm, 10, 10, SK_ColorRED, true);
474
475 r.offset(5.0f, 5.0f);
reede47829b2015-08-06 10:02:53 -0700476 canvas->drawBitmapRect(bm, r, nullptr);
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000477
reedca2622b2016-03-18 07:25:55 -0700478 sk_sp<SkPicture> final(recorder.finishRecordingAsPicture());
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000479 REPORTER_ASSERT(reporter, final->willPlayBackBitmaps());
480
481 REPORTER_ASSERT(reporter, copy->uniqueID() != final->uniqueID());
482
483 // The snapshot shouldn't pick up any operations added after it was made
484 REPORTER_ASSERT(reporter, !copy->willPlayBackBitmaps());
485 }
robertphillips9058d602014-06-10 11:45:46 -0700486
487 // Recreate the Android partialReplay test case
488 {
489 SkPictureRecorder recorder;
490
halcanary96fcdcc2015-08-27 07:41:13 -0700491 SkCanvas* canvas = recorder.beginRecording(4, 3, nullptr, 0);
robertphillips9058d602014-06-10 11:45:46 -0700492 create_imbalance(canvas);
493
494 int expectedSaveCount = canvas->getSaveCount();
495
reedca2622b2016-03-18 07:25:55 -0700496 sk_sp<SkPicture> copy(SkPictureRecorderReplayTester::Copy(&recorder));
497 check_balance(reporter, copy.get());
robertphillips9058d602014-06-10 11:45:46 -0700498
499 REPORTER_ASSERT(reporter, expectedSaveCount = canvas->getSaveCount());
500
501 // End the recording of source to test the picture finalization
502 // process isn't complicated by the partialReplay step
reedca2622b2016-03-18 07:25:55 -0700503 sk_sp<SkPicture> final(recorder.finishRecordingAsPicture());
robertphillips9058d602014-06-10 11:45:46 -0700504 }
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000505}
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000506
commit-bot@chromium.orgea7d08e2014-02-13 16:00:51 +0000507static void test_unbalanced_save_restores(skiatest::Reporter* reporter) {
508 SkCanvas testCanvas(100, 100);
509 set_canvas_to_save_count_4(&testCanvas);
510
511 REPORTER_ASSERT(reporter, 4 == testCanvas.getSaveCount());
512
513 SkPaint paint;
514 SkRect rect = SkRect::MakeLTRB(-10000000, -10000000, 10000000, 10000000);
515
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000516 SkPictureRecorder recorder;
commit-bot@chromium.orgea7d08e2014-02-13 16:00:51 +0000517
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000518 {
519 // Create picture with 2 unbalanced saves
robertphillips9f1c2412014-06-09 06:25:34 -0700520 SkCanvas* canvas = recorder.beginRecording(100, 100);
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000521 canvas->save();
522 canvas->translate(10, 10);
523 canvas->drawRect(rect, paint);
524 canvas->save();
525 canvas->translate(10, 10);
526 canvas->drawRect(rect, paint);
reedca2622b2016-03-18 07:25:55 -0700527 sk_sp<SkPicture> extraSavePicture(recorder.finishRecordingAsPicture());
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000528
robertphillips9b14f262014-06-04 05:40:44 -0700529 testCanvas.drawPicture(extraSavePicture);
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000530 REPORTER_ASSERT(reporter, 4 == testCanvas.getSaveCount());
531 }
commit-bot@chromium.orgea7d08e2014-02-13 16:00:51 +0000532
533 set_canvas_to_save_count_4(&testCanvas);
534
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000535 {
536 // Create picture with 2 unbalanced restores
robertphillips9f1c2412014-06-09 06:25:34 -0700537 SkCanvas* canvas = recorder.beginRecording(100, 100);
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000538 canvas->save();
539 canvas->translate(10, 10);
540 canvas->drawRect(rect, paint);
541 canvas->save();
542 canvas->translate(10, 10);
543 canvas->drawRect(rect, paint);
544 canvas->restore();
545 canvas->restore();
546 canvas->restore();
547 canvas->restore();
reedca2622b2016-03-18 07:25:55 -0700548 sk_sp<SkPicture> extraRestorePicture(recorder.finishRecordingAsPicture());
commit-bot@chromium.orgea7d08e2014-02-13 16:00:51 +0000549
robertphillips9b14f262014-06-04 05:40:44 -0700550 testCanvas.drawPicture(extraRestorePicture);
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000551 REPORTER_ASSERT(reporter, 4 == testCanvas.getSaveCount());
552 }
commit-bot@chromium.orgea7d08e2014-02-13 16:00:51 +0000553
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000554 set_canvas_to_save_count_4(&testCanvas);
commit-bot@chromium.orgea7d08e2014-02-13 16:00:51 +0000555
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000556 {
robertphillips9f1c2412014-06-09 06:25:34 -0700557 SkCanvas* canvas = recorder.beginRecording(100, 100);
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000558 canvas->translate(10, 10);
559 canvas->drawRect(rect, paint);
reedca2622b2016-03-18 07:25:55 -0700560 sk_sp<SkPicture> noSavePicture(recorder.finishRecordingAsPicture());
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000561
robertphillips9b14f262014-06-04 05:40:44 -0700562 testCanvas.drawPicture(noSavePicture);
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000563 REPORTER_ASSERT(reporter, 4 == testCanvas.getSaveCount());
564 REPORTER_ASSERT(reporter, testCanvas.getTotalMatrix().isIdentity());
565 }
commit-bot@chromium.orgea7d08e2014-02-13 16:00:51 +0000566}
567
sugoi@google.com54f0d1b2013-02-27 19:17:41 +0000568static void test_peephole() {
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000569 SkRandom rand;
reed@google.com21b519d2012-10-02 17:42:15 +0000570
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000571 SkPictureRecorder recorder;
572
reed@google.com21b519d2012-10-02 17:42:15 +0000573 for (int j = 0; j < 100; j++) {
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000574 SkRandom rand2(rand); // remember the seed
reed@google.com21b519d2012-10-02 17:42:15 +0000575
robertphillips9f1c2412014-06-09 06:25:34 -0700576 SkCanvas* canvas = recorder.beginRecording(100, 100);
reed@google.com21b519d2012-10-02 17:42:15 +0000577
578 for (int i = 0; i < 1000; ++i) {
579 rand_op(canvas, rand);
580 }
reedca2622b2016-03-18 07:25:55 -0700581 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
jvanverth@google.comc490f802013-03-04 13:56:38 +0000582
583 rand = rand2;
reed@google.com21b519d2012-10-02 17:42:15 +0000584 }
585
586 {
robertphillips9f1c2412014-06-09 06:25:34 -0700587 SkCanvas* canvas = recorder.beginRecording(100, 100);
reed@google.com21b519d2012-10-02 17:42:15 +0000588 SkRect rect = SkRect::MakeWH(50, 50);
skia.committer@gmail.com52c24372012-10-03 02:01:13 +0000589
reed@google.com21b519d2012-10-02 17:42:15 +0000590 for (int i = 0; i < 100; ++i) {
591 canvas->save();
592 }
593 while (canvas->getSaveCount() > 1) {
594 canvas->clipRect(rect);
595 canvas->restore();
596 }
reedca2622b2016-03-18 07:25:55 -0700597 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
reed@google.com21b519d2012-10-02 17:42:15 +0000598 }
599}
600
scroggo@google.com4b90b112012-12-04 15:08:56 +0000601#ifndef SK_DEBUG
602// Only test this is in release mode. We deliberately crash in debug mode, since a valid caller
603// should never do this.
604static void test_bad_bitmap() {
605 // This bitmap has a width and height but no pixels. As a result, attempting to record it will
606 // fail.
607 SkBitmap bm;
commit-bot@chromium.orga3264e52014-05-30 13:26:10 +0000608 bm.setInfo(SkImageInfo::MakeN32Premul(100, 100));
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000609 SkPictureRecorder recorder;
robertphillips9f1c2412014-06-09 06:25:34 -0700610 SkCanvas* recordingCanvas = recorder.beginRecording(100, 100);
scroggo@google.com4b90b112012-12-04 15:08:56 +0000611 recordingCanvas->drawBitmap(bm, 0, 0);
reedca2622b2016-03-18 07:25:55 -0700612 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
scroggo@google.com4b90b112012-12-04 15:08:56 +0000613
614 SkCanvas canvas;
robertphillips9b14f262014-06-04 05:40:44 -0700615 canvas.drawPicture(picture);
scroggo@google.com4b90b112012-12-04 15:08:56 +0000616}
617#endif
618
junov@chromium.orgd575eed2013-05-08 15:39:13 +0000619static void test_clip_bound_opt(skiatest::Reporter* reporter) {
620 // Test for crbug.com/229011
621 SkRect rect1 = SkRect::MakeXYWH(SkIntToScalar(4), SkIntToScalar(4),
622 SkIntToScalar(2), SkIntToScalar(2));
623 SkRect rect2 = SkRect::MakeXYWH(SkIntToScalar(7), SkIntToScalar(7),
624 SkIntToScalar(1), SkIntToScalar(1));
625 SkRect rect3 = SkRect::MakeXYWH(SkIntToScalar(6), SkIntToScalar(6),
626 SkIntToScalar(1), SkIntToScalar(1));
627
628 SkPath invPath;
629 invPath.addOval(rect1);
630 invPath.setFillType(SkPath::kInverseEvenOdd_FillType);
631 SkPath path;
632 path.addOval(rect2);
633 SkPath path2;
634 path2.addOval(rect3);
635 SkIRect clipBounds;
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000636 SkPictureRecorder recorder;
reedd9544982014-09-09 18:46:22 -0700637
638 // Testing conservative-raster-clip that is enabled by PictureRecord
junov@chromium.orgd575eed2013-05-08 15:39:13 +0000639 {
robertphillips9f1c2412014-06-09 06:25:34 -0700640 SkCanvas* canvas = recorder.beginRecording(10, 10);
reed73603f32016-09-20 08:42:38 -0700641 canvas->clipPath(invPath);
Mike Reed918e1442017-01-23 11:39:45 -0500642 clipBounds = canvas->getDeviceClipBounds();
junov@chromium.orgd575eed2013-05-08 15:39:13 +0000643 REPORTER_ASSERT(reporter, 0 == clipBounds.fLeft);
644 REPORTER_ASSERT(reporter, 0 == clipBounds.fTop);
645 REPORTER_ASSERT(reporter, 10 == clipBounds.fBottom);
646 REPORTER_ASSERT(reporter, 10 == clipBounds.fRight);
647 }
648 {
robertphillips9f1c2412014-06-09 06:25:34 -0700649 SkCanvas* canvas = recorder.beginRecording(10, 10);
reed73603f32016-09-20 08:42:38 -0700650 canvas->clipPath(path);
651 canvas->clipPath(invPath);
Mike Reed918e1442017-01-23 11:39:45 -0500652 clipBounds = canvas->getDeviceClipBounds();
junov@chromium.orgd575eed2013-05-08 15:39:13 +0000653 REPORTER_ASSERT(reporter, 7 == clipBounds.fLeft);
654 REPORTER_ASSERT(reporter, 7 == clipBounds.fTop);
655 REPORTER_ASSERT(reporter, 8 == clipBounds.fBottom);
656 REPORTER_ASSERT(reporter, 8 == clipBounds.fRight);
657 }
658 {
robertphillips9f1c2412014-06-09 06:25:34 -0700659 SkCanvas* canvas = recorder.beginRecording(10, 10);
reed73603f32016-09-20 08:42:38 -0700660 canvas->clipPath(path);
Mike Reedc1f77742016-12-09 09:00:50 -0500661 canvas->clipPath(invPath, kUnion_SkClipOp);
Mike Reed918e1442017-01-23 11:39:45 -0500662 clipBounds = canvas->getDeviceClipBounds();
junov@chromium.orgd575eed2013-05-08 15:39:13 +0000663 REPORTER_ASSERT(reporter, 0 == clipBounds.fLeft);
664 REPORTER_ASSERT(reporter, 0 == clipBounds.fTop);
665 REPORTER_ASSERT(reporter, 10 == clipBounds.fBottom);
666 REPORTER_ASSERT(reporter, 10 == clipBounds.fRight);
667 }
668 {
robertphillips9f1c2412014-06-09 06:25:34 -0700669 SkCanvas* canvas = recorder.beginRecording(10, 10);
Mike Reedc1f77742016-12-09 09:00:50 -0500670 canvas->clipPath(path, kDifference_SkClipOp);
Mike Reed918e1442017-01-23 11:39:45 -0500671 clipBounds = canvas->getDeviceClipBounds();
junov@chromium.orgd575eed2013-05-08 15:39:13 +0000672 REPORTER_ASSERT(reporter, 0 == clipBounds.fLeft);
673 REPORTER_ASSERT(reporter, 0 == clipBounds.fTop);
674 REPORTER_ASSERT(reporter, 10 == clipBounds.fBottom);
675 REPORTER_ASSERT(reporter, 10 == clipBounds.fRight);
676 }
677 {
robertphillips9f1c2412014-06-09 06:25:34 -0700678 SkCanvas* canvas = recorder.beginRecording(10, 10);
Mike Reedc1f77742016-12-09 09:00:50 -0500679 canvas->clipPath(path, kReverseDifference_SkClipOp);
Mike Reed918e1442017-01-23 11:39:45 -0500680 clipBounds = canvas->getDeviceClipBounds();
junov@chromium.orgd575eed2013-05-08 15:39:13 +0000681 // True clip is actually empty in this case, but the best
682 // determination we can make using only bounds as input is that the
683 // clip is included in the bounds of 'path'.
junov@chromium.orgd575eed2013-05-08 15:39:13 +0000684 REPORTER_ASSERT(reporter, 7 == clipBounds.fLeft);
685 REPORTER_ASSERT(reporter, 7 == clipBounds.fTop);
686 REPORTER_ASSERT(reporter, 8 == clipBounds.fBottom);
687 REPORTER_ASSERT(reporter, 8 == clipBounds.fRight);
688 }
689 {
robertphillips9f1c2412014-06-09 06:25:34 -0700690 SkCanvas* canvas = recorder.beginRecording(10, 10);
Mike Reedc1f77742016-12-09 09:00:50 -0500691 canvas->clipPath(path, kIntersect_SkClipOp);
692 canvas->clipPath(path2, kXOR_SkClipOp);
Mike Reed918e1442017-01-23 11:39:45 -0500693 clipBounds = canvas->getDeviceClipBounds();
junov@chromium.orgd575eed2013-05-08 15:39:13 +0000694 REPORTER_ASSERT(reporter, 6 == clipBounds.fLeft);
695 REPORTER_ASSERT(reporter, 6 == clipBounds.fTop);
696 REPORTER_ASSERT(reporter, 8 == clipBounds.fBottom);
697 REPORTER_ASSERT(reporter, 8 == clipBounds.fRight);
698 }
699}
700
schenneyeeff8bb2015-07-07 14:27:10 -0700701static void test_cull_rect_reset(skiatest::Reporter* reporter) {
702 SkPictureRecorder recorder;
703 SkRect bounds = SkRect::MakeWH(10, 10);
704 SkRTreeFactory factory;
705 SkCanvas* canvas = recorder.beginRecording(bounds, &factory);
706 bounds = SkRect::MakeWH(100, 100);
707 SkPaint paint;
708 canvas->drawRect(bounds, paint);
709 canvas->drawRect(bounds, paint);
reedca2622b2016-03-18 07:25:55 -0700710 sk_sp<SkPicture> p(recorder.finishRecordingAsPictureWithCull(bounds));
mtkleineedc3342015-07-08 08:26:39 -0700711 const SkBigPicture* picture = p->asSkBigPicture();
schenneyeeff8bb2015-07-07 14:27:10 -0700712 REPORTER_ASSERT(reporter, picture);
713
714 SkRect finalCullRect = picture->cullRect();
715 REPORTER_ASSERT(reporter, 0 == finalCullRect.fLeft);
716 REPORTER_ASSERT(reporter, 0 == finalCullRect.fTop);
717 REPORTER_ASSERT(reporter, 100 == finalCullRect.fBottom);
718 REPORTER_ASSERT(reporter, 100 == finalCullRect.fRight);
719
720 const SkBBoxHierarchy* pictureBBH = picture->bbh();
721 SkRect bbhCullRect = pictureBBH->getRootBound();
722 REPORTER_ASSERT(reporter, 0 == bbhCullRect.fLeft);
723 REPORTER_ASSERT(reporter, 0 == bbhCullRect.fTop);
724 REPORTER_ASSERT(reporter, 100 == bbhCullRect.fBottom);
725 REPORTER_ASSERT(reporter, 100 == bbhCullRect.fRight);
726}
727
728
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000729/**
730 * A canvas that records the number of clip commands.
731 */
732class ClipCountingCanvas : public SkCanvas {
733public:
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000734 ClipCountingCanvas(int width, int height)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000735 : INHERITED(width, height)
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000736 , fClipCount(0){
737 }
738
Mike Reedc1f77742016-12-09 09:00:50 -0500739 void onClipRect(const SkRect& r, SkClipOp op, ClipEdgeStyle edgeStyle) override {
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000740 fClipCount += 1;
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000741 this->INHERITED::onClipRect(r, op, edgeStyle);
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000742 }
743
Mike Reedc1f77742016-12-09 09:00:50 -0500744 void onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle)override {
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000745 fClipCount += 1;
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000746 this->INHERITED::onClipRRect(rrect, op, edgeStyle);
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000747 }
748
Mike Reedc1f77742016-12-09 09:00:50 -0500749 void onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) override {
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000750 fClipCount += 1;
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000751 this->INHERITED::onClipPath(path, op, edgeStyle);
752 }
753
Mike Reedc1f77742016-12-09 09:00:50 -0500754 void onClipRegion(const SkRegion& deviceRgn, SkClipOp op) override {
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000755 fClipCount += 1;
756 this->INHERITED::onClipRegion(deviceRgn, op);
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000757 }
758
759 unsigned getClipCount() const { return fClipCount; }
760
761private:
762 unsigned fClipCount;
763
764 typedef SkCanvas INHERITED;
765};
766
767static void test_clip_expansion(skiatest::Reporter* reporter) {
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000768 SkPictureRecorder recorder;
robertphillips9f1c2412014-06-09 06:25:34 -0700769 SkCanvas* canvas = recorder.beginRecording(10, 10);
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000770
Mike Reedc1f77742016-12-09 09:00:50 -0500771 canvas->clipRect(SkRect::MakeEmpty(), kReplace_SkClipOp);
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000772 // The following expanding clip should not be skipped.
Mike Reedc1f77742016-12-09 09:00:50 -0500773 canvas->clipRect(SkRect::MakeXYWH(4, 4, 3, 3), kUnion_SkClipOp);
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000774 // Draw something so the optimizer doesn't just fold the world.
775 SkPaint p;
776 p.setColor(SK_ColorBLUE);
777 canvas->drawPaint(p);
reedca2622b2016-03-18 07:25:55 -0700778 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000779
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000780 ClipCountingCanvas testCanvas(10, 10);
robertphillipsc5ba71d2014-09-04 08:42:50 -0700781 picture->playback(&testCanvas);
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000782
783 // Both clips should be present on playback.
784 REPORTER_ASSERT(reporter, testCanvas.getClipCount() == 2);
785}
786
tomhudson@google.com381010e2013-10-24 11:12:47 +0000787static void test_hierarchical(skiatest::Reporter* reporter) {
788 SkBitmap bm;
789 make_bm(&bm, 10, 10, SK_ColorRED, true);
790
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000791 SkPictureRecorder recorder;
tomhudson@google.com381010e2013-10-24 11:12:47 +0000792
robertphillips9f1c2412014-06-09 06:25:34 -0700793 recorder.beginRecording(10, 10);
reedca2622b2016-03-18 07:25:55 -0700794 sk_sp<SkPicture> childPlain(recorder.finishRecordingAsPicture());
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000795 REPORTER_ASSERT(reporter, !childPlain->willPlayBackBitmaps()); // 0
tomhudson@google.com381010e2013-10-24 11:12:47 +0000796
robertphillips9f1c2412014-06-09 06:25:34 -0700797 recorder.beginRecording(10, 10)->drawBitmap(bm, 0, 0);
reedca2622b2016-03-18 07:25:55 -0700798 sk_sp<SkPicture> childWithBitmap(recorder.finishRecordingAsPicture());
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000799 REPORTER_ASSERT(reporter, childWithBitmap->willPlayBackBitmaps()); // 1
tomhudson@google.com381010e2013-10-24 11:12:47 +0000800
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000801 {
robertphillips9f1c2412014-06-09 06:25:34 -0700802 SkCanvas* canvas = recorder.beginRecording(10, 10);
robertphillips9b14f262014-06-04 05:40:44 -0700803 canvas->drawPicture(childPlain);
reedca2622b2016-03-18 07:25:55 -0700804 sk_sp<SkPicture> parentPP(recorder.finishRecordingAsPicture());
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000805 REPORTER_ASSERT(reporter, !parentPP->willPlayBackBitmaps()); // 0
806 }
807 {
robertphillips9f1c2412014-06-09 06:25:34 -0700808 SkCanvas* canvas = recorder.beginRecording(10, 10);
robertphillips9b14f262014-06-04 05:40:44 -0700809 canvas->drawPicture(childWithBitmap);
reedca2622b2016-03-18 07:25:55 -0700810 sk_sp<SkPicture> parentPWB(recorder.finishRecordingAsPicture());
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000811 REPORTER_ASSERT(reporter, parentPWB->willPlayBackBitmaps()); // 1
812 }
813 {
robertphillips9f1c2412014-06-09 06:25:34 -0700814 SkCanvas* canvas = recorder.beginRecording(10, 10);
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000815 canvas->drawBitmap(bm, 0, 0);
robertphillips9b14f262014-06-04 05:40:44 -0700816 canvas->drawPicture(childPlain);
reedca2622b2016-03-18 07:25:55 -0700817 sk_sp<SkPicture> parentWBP(recorder.finishRecordingAsPicture());
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000818 REPORTER_ASSERT(reporter, parentWBP->willPlayBackBitmaps()); // 1
819 }
820 {
robertphillips9f1c2412014-06-09 06:25:34 -0700821 SkCanvas* canvas = recorder.beginRecording(10, 10);
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000822 canvas->drawBitmap(bm, 0, 0);
robertphillips9b14f262014-06-04 05:40:44 -0700823 canvas->drawPicture(childWithBitmap);
reedca2622b2016-03-18 07:25:55 -0700824 sk_sp<SkPicture> parentWBWB(recorder.finishRecordingAsPicture());
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000825 REPORTER_ASSERT(reporter, parentWBWB->willPlayBackBitmaps()); // 2
826 }
tomhudson@google.com381010e2013-10-24 11:12:47 +0000827}
828
robertphillips@google.comd5500882014-04-02 23:51:13 +0000829static void test_gen_id(skiatest::Reporter* reporter) {
830
Robert Phillipscfaeec42014-07-13 12:00:50 -0400831 SkPictureRecorder recorder;
832 recorder.beginRecording(0, 0);
reedca2622b2016-03-18 07:25:55 -0700833 sk_sp<SkPicture> empty(recorder.finishRecordingAsPicture());
robertphillips@google.comd5500882014-04-02 23:51:13 +0000834
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000835 // Empty pictures should still have a valid ID
Robert Phillipscfaeec42014-07-13 12:00:50 -0400836 REPORTER_ASSERT(reporter, empty->uniqueID() != SK_InvalidGenID);
robertphillips@google.comd5500882014-04-02 23:51:13 +0000837
robertphillips9f1c2412014-06-09 06:25:34 -0700838 SkCanvas* canvas = recorder.beginRecording(1, 1);
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000839 canvas->drawARGB(255, 255, 255, 255);
reedca2622b2016-03-18 07:25:55 -0700840 sk_sp<SkPicture> hasData(recorder.finishRecordingAsPicture());
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000841 // picture should have a non-zero id after recording
842 REPORTER_ASSERT(reporter, hasData->uniqueID() != SK_InvalidGenID);
robertphillips@google.comd5500882014-04-02 23:51:13 +0000843
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000844 // both pictures should have different ids
Robert Phillipscfaeec42014-07-13 12:00:50 -0400845 REPORTER_ASSERT(reporter, hasData->uniqueID() != empty->uniqueID());
robertphillips@google.comd5500882014-04-02 23:51:13 +0000846}
847
caryclark5ef194c2015-08-31 09:22:38 -0700848static void test_typeface(skiatest::Reporter* reporter) {
849 SkPictureRecorder recorder;
850 SkCanvas* canvas = recorder.beginRecording(10, 10);
851 SkPaint paint;
mbocee6a9912016-05-31 11:42:36 -0700852 paint.setTypeface(SkTypeface::MakeFromName("Arial",
853 SkFontStyle::FromOldStyle(SkTypeface::kItalic)));
caryclark5ef194c2015-08-31 09:22:38 -0700854 canvas->drawText("Q", 1, 0, 10, paint);
reedca2622b2016-03-18 07:25:55 -0700855 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
caryclark5ef194c2015-08-31 09:22:38 -0700856 SkDynamicMemoryWStream stream;
857 picture->serialize(&stream);
858}
859
tfarina@chromium.orge4fafb12013-12-12 21:11:12 +0000860DEF_TEST(Picture, reporter) {
caryclark5ef194c2015-08-31 09:22:38 -0700861 test_typeface(reporter);
scroggo@google.comd614c6a2012-09-14 17:26:37 +0000862#ifdef SK_DEBUG
robertphillipsdb539902014-07-01 08:47:04 -0700863 test_deleting_empty_picture();
scroggo@google.comd614c6a2012-09-14 17:26:37 +0000864 test_serializing_empty_picture();
scroggo@google.com4b90b112012-12-04 15:08:56 +0000865#else
866 test_bad_bitmap();
scroggo@google.comd614c6a2012-09-14 17:26:37 +0000867#endif
commit-bot@chromium.orgea7d08e2014-02-13 16:00:51 +0000868 test_unbalanced_save_restores(reporter);
sugoi@google.com54f0d1b2013-02-27 19:17:41 +0000869 test_peephole();
robertphillips@google.comb950c6f2014-04-25 00:02:12 +0000870#if SK_SUPPORT_GPU
mtklein8e126562014-10-01 09:29:35 -0700871 test_gpu_veto(reporter);
robertphillips@google.comb950c6f2014-04-25 00:02:12 +0000872#endif
mtkleina16af212015-08-26 08:14:52 -0700873 test_images_are_found_by_willPlayBackBitmaps(reporter);
mtklein8e126562014-10-01 09:29:35 -0700874 test_analysis(reporter);
junov@chromium.orgd575eed2013-05-08 15:39:13 +0000875 test_clip_bound_opt(reporter);
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000876 test_clip_expansion(reporter);
tomhudson@google.com381010e2013-10-24 11:12:47 +0000877 test_hierarchical(reporter);
robertphillips@google.comd5500882014-04-02 23:51:13 +0000878 test_gen_id(reporter);
schenneyeeff8bb2015-07-07 14:27:10 -0700879 test_cull_rect_reset(reporter);
scroggo@google.comd614c6a2012-09-14 17:26:37 +0000880}
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +0000881
882static void draw_bitmaps(const SkBitmap bitmap, SkCanvas* canvas) {
883 const SkPaint paint;
884 const SkRect rect = { 5.0f, 5.0f, 8.0f, 8.0f };
885 const SkIRect irect = { 2, 2, 3, 3 };
msarettc573a402016-08-02 08:05:56 -0700886 int divs[] = { 2, 3 };
887 SkCanvas::Lattice lattice;
888 lattice.fXCount = lattice.fYCount = 2;
889 lattice.fXDivs = lattice.fYDivs = divs;
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +0000890
891 // Don't care what these record, as long as they're legal.
892 canvas->drawBitmap(bitmap, 0.0f, 0.0f, &paint);
reede47829b2015-08-06 10:02:53 -0700893 canvas->drawBitmapRect(bitmap, rect, rect, &paint, SkCanvas::kStrict_SrcRectConstraint);
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +0000894 canvas->drawBitmapNine(bitmap, irect, rect, &paint);
reedda420b92015-12-16 08:38:15 -0800895 canvas->drawBitmap(bitmap, 1, 1); // drawSprite
msarettc573a402016-08-02 08:05:56 -0700896 canvas->drawBitmapLattice(bitmap, lattice, rect, &paint);
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +0000897}
898
899static void test_draw_bitmaps(SkCanvas* canvas) {
900 SkBitmap empty;
901 draw_bitmaps(empty, canvas);
commit-bot@chromium.orga3264e52014-05-30 13:26:10 +0000902 empty.setInfo(SkImageInfo::MakeN32Premul(10, 10));
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +0000903 draw_bitmaps(empty, canvas);
904}
905
906DEF_TEST(Picture_EmptyBitmap, r) {
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000907 SkPictureRecorder recorder;
robertphillips9f1c2412014-06-09 06:25:34 -0700908 test_draw_bitmaps(recorder.beginRecording(10, 10));
reedca2622b2016-03-18 07:25:55 -0700909 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +0000910}
911
912DEF_TEST(Canvas_EmptyBitmap, r) {
913 SkBitmap dst;
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +0000914 dst.allocN32Pixels(10, 10);
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +0000915 SkCanvas canvas(dst);
916
917 test_draw_bitmaps(&canvas);
918}
dneto3f22e8c2014-07-30 15:42:22 -0700919
920DEF_TEST(DontOptimizeSaveLayerDrawDrawRestore, reporter) {
921 // This test is from crbug.com/344987.
922 // The commands are:
923 // saveLayer with paint that modifies alpha
reed84984ef2015-07-17 07:09:43 -0700924 // drawBitmapRect
925 // drawBitmapRect
dneto3f22e8c2014-07-30 15:42:22 -0700926 // restore
927 // The bug was that this structure was modified so that:
928 // - The saveLayer and restore were eliminated
929 // - The alpha was only applied to the first drawBitmapRectToRect
930
931 // This test draws blue and red squares inside a 50% transparent
932 // layer. Both colours should show up muted.
933 // When the bug is present, the red square (the second bitmap)
934 // shows upwith full opacity.
935
936 SkBitmap blueBM;
937 make_bm(&blueBM, 100, 100, SkColorSetARGB(255, 0, 0, 255), true);
938 SkBitmap redBM;
939 make_bm(&redBM, 100, 100, SkColorSetARGB(255, 255, 0, 0), true);
940 SkPaint semiTransparent;
941 semiTransparent.setAlpha(0x80);
942
943 SkPictureRecorder recorder;
944 SkCanvas* canvas = recorder.beginRecording(100, 100);
945 canvas->drawARGB(0, 0, 0, 0);
946
947 canvas->saveLayer(0, &semiTransparent);
948 canvas->drawBitmap(blueBM, 25, 25);
949 canvas->drawBitmap(redBM, 50, 50);
950 canvas->restore();
951
reedca2622b2016-03-18 07:25:55 -0700952 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
dneto3f22e8c2014-07-30 15:42:22 -0700953
954 // Now replay the picture back on another canvas
955 // and check a couple of its pixels.
956 SkBitmap replayBM;
957 make_bm(&replayBM, 100, 100, SK_ColorBLACK, false);
958 SkCanvas replayCanvas(replayBM);
robertphillipsc5ba71d2014-09-04 08:42:50 -0700959 picture->playback(&replayCanvas);
dneto3f22e8c2014-07-30 15:42:22 -0700960 replayCanvas.flush();
961
962 // With the bug present, at (55, 55) we would get a fully opaque red
963 // intead of a dark red.
964 REPORTER_ASSERT(reporter, replayBM.getColor(30, 30) == 0xff000080);
965 REPORTER_ASSERT(reporter, replayBM.getColor(55, 55) == 0xff800000);
966}
mtklein3e8232b2014-08-18 13:39:11 -0700967
968struct CountingBBH : public SkBBoxHierarchy {
969 mutable int searchCalls;
schenney23d85932015-03-06 16:20:28 -0800970 SkRect rootBound;
mtklein3e8232b2014-08-18 13:39:11 -0700971
schenney23d85932015-03-06 16:20:28 -0800972 CountingBBH(const SkRect& bound) : searchCalls(0), rootBound(bound) {}
mtklein3e8232b2014-08-18 13:39:11 -0700973
mtkleinc6ad06a2015-08-19 09:51:00 -0700974 void search(const SkRect& query, SkTDArray<int>* results) const override {
mtklein3e8232b2014-08-18 13:39:11 -0700975 this->searchCalls++;
976 }
977
mtklein36352bf2015-03-25 18:17:31 -0700978 void insert(const SkRect[], int) override {}
979 virtual size_t bytesUsed() const override { return 0; }
980 SkRect getRootBound() const override { return rootBound; }
mtklein3e8232b2014-08-18 13:39:11 -0700981};
982
983class SpoonFedBBHFactory : public SkBBHFactory {
984public:
985 explicit SpoonFedBBHFactory(SkBBoxHierarchy* bbh) : fBBH(bbh) {}
mtklein36352bf2015-03-25 18:17:31 -0700986 SkBBoxHierarchy* operator()(const SkRect&) const override {
mtklein3e8232b2014-08-18 13:39:11 -0700987 return SkRef(fBBH);
988 }
989private:
990 SkBBoxHierarchy* fBBH;
991};
992
993// When the canvas clip covers the full picture, we don't need to call the BBH.
994DEF_TEST(Picture_SkipBBH, r) {
schenney23d85932015-03-06 16:20:28 -0800995 SkRect bound = SkRect::MakeWH(320, 240);
996 CountingBBH bbh(bound);
mtklein3e8232b2014-08-18 13:39:11 -0700997 SpoonFedBBHFactory factory(&bbh);
998
999 SkPictureRecorder recorder;
mtklein9db912c2015-05-19 11:11:26 -07001000 SkCanvas* c = recorder.beginRecording(bound, &factory);
1001 // Record a few ops so we don't hit a small- or empty- picture optimization.
1002 c->drawRect(bound, SkPaint());
1003 c->drawRect(bound, SkPaint());
reedca2622b2016-03-18 07:25:55 -07001004 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
mtklein3e8232b2014-08-18 13:39:11 -07001005
1006 SkCanvas big(640, 480), small(300, 200);
1007
robertphillipsc5ba71d2014-09-04 08:42:50 -07001008 picture->playback(&big);
mtklein3e8232b2014-08-18 13:39:11 -07001009 REPORTER_ASSERT(r, bbh.searchCalls == 0);
1010
robertphillipsc5ba71d2014-09-04 08:42:50 -07001011 picture->playback(&small);
mtklein3e8232b2014-08-18 13:39:11 -07001012 REPORTER_ASSERT(r, bbh.searchCalls == 1);
1013}
mtkleind72094d2014-08-27 12:12:23 -07001014
1015DEF_TEST(Picture_BitmapLeak, r) {
1016 SkBitmap mut, immut;
1017 mut.allocN32Pixels(300, 200);
1018 immut.allocN32Pixels(300, 200);
1019 immut.setImmutable();
1020 SkASSERT(!mut.isImmutable());
1021 SkASSERT(immut.isImmutable());
1022
1023 // No one can hold a ref on our pixels yet.
1024 REPORTER_ASSERT(r, mut.pixelRef()->unique());
1025 REPORTER_ASSERT(r, immut.pixelRef()->unique());
1026
reedca2622b2016-03-18 07:25:55 -07001027 sk_sp<SkPicture> pic;
reed1bdfd3f2014-11-24 14:41:51 -08001028 {
1029 // we want the recorder to go out of scope before our subsequent checks, so we
1030 // place it inside local braces.
1031 SkPictureRecorder rec;
1032 SkCanvas* canvas = rec.beginRecording(1920, 1200);
1033 canvas->drawBitmap(mut, 0, 0);
1034 canvas->drawBitmap(immut, 800, 600);
reedca2622b2016-03-18 07:25:55 -07001035 pic = rec.finishRecordingAsPicture();
reed1bdfd3f2014-11-24 14:41:51 -08001036 }
mtkleind72094d2014-08-27 12:12:23 -07001037
1038 // The picture shares the immutable pixels but copies the mutable ones.
1039 REPORTER_ASSERT(r, mut.pixelRef()->unique());
1040 REPORTER_ASSERT(r, !immut.pixelRef()->unique());
1041
1042 // When the picture goes away, it's just our bitmaps holding the refs.
reedca2622b2016-03-18 07:25:55 -07001043 pic = nullptr;
mtkleind72094d2014-08-27 12:12:23 -07001044 REPORTER_ASSERT(r, mut.pixelRef()->unique());
1045 REPORTER_ASSERT(r, immut.pixelRef()->unique());
1046}
mtkleinfeaadee2015-04-08 11:25:48 -07001047
1048// getRecordingCanvas() should return a SkCanvas when recording, null when not recording.
1049DEF_TEST(Picture_getRecordingCanvas, r) {
1050 SkPictureRecorder rec;
1051 REPORTER_ASSERT(r, !rec.getRecordingCanvas());
1052 for (int i = 0; i < 3; i++) {
1053 rec.beginRecording(100, 100);
1054 REPORTER_ASSERT(r, rec.getRecordingCanvas());
reedca2622b2016-03-18 07:25:55 -07001055 rec.finishRecordingAsPicture();
mtkleinfeaadee2015-04-08 11:25:48 -07001056 REPORTER_ASSERT(r, !rec.getRecordingCanvas());
1057 }
1058}
mtklein9db912c2015-05-19 11:11:26 -07001059
1060DEF_TEST(MiniRecorderLeftHanging, r) {
1061 // Any shader or other ref-counted effect will do just fine here.
1062 SkPaint paint;
reed1a9b9642016-03-13 14:13:58 -07001063 paint.setShader(SkShader::MakeColorShader(SK_ColorRED));
mtklein9db912c2015-05-19 11:11:26 -07001064
1065 SkMiniRecorder rec;
1066 REPORTER_ASSERT(r, rec.drawRect(SkRect::MakeWH(20,30), paint));
1067 // Don't call rec.detachPicture(). Test succeeds by not asserting or leaking the shader.
1068}
fmalita2ecc0002015-07-14 13:12:25 -07001069
1070DEF_TEST(Picture_preserveCullRect, r) {
1071 SkPictureRecorder recorder;
1072
1073 SkCanvas* c = recorder.beginRecording(SkRect::MakeLTRB(1, 2, 3, 4));
1074 c->clear(SK_ColorCYAN);
1075
reedca2622b2016-03-18 07:25:55 -07001076 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
fmalita2ecc0002015-07-14 13:12:25 -07001077 SkDynamicMemoryWStream wstream;
1078 picture->serialize(&wstream);
1079
Ben Wagner145dbcd2016-11-03 14:40:50 -04001080 std::unique_ptr<SkStream> rstream(wstream.detachAsStream());
1081 sk_sp<SkPicture> deserializedPicture(SkPicture::MakeFromStream(rstream.get()));
fmalita2ecc0002015-07-14 13:12:25 -07001082
mtklein5f939ab2016-03-16 10:28:35 -07001083 REPORTER_ASSERT(r, deserializedPicture != nullptr);
fmalita2ecc0002015-07-14 13:12:25 -07001084 REPORTER_ASSERT(r, deserializedPicture->cullRect().left() == 1);
1085 REPORTER_ASSERT(r, deserializedPicture->cullRect().top() == 2);
1086 REPORTER_ASSERT(r, deserializedPicture->cullRect().right() == 3);
1087 REPORTER_ASSERT(r, deserializedPicture->cullRect().bottom() == 4);
1088}
fmalita796e3652016-05-13 11:40:07 -07001089
1090#if SK_SUPPORT_GPU
1091
1092DEF_TEST(PictureGpuAnalyzer, r) {
1093 SkPictureRecorder recorder;
1094
1095 {
1096 SkCanvas* canvas = recorder.beginRecording(10, 10);
1097 SkPaint paint;
1098 SkScalar intervals [] = { 10, 20 };
1099 paint.setPathEffect(SkDashPathEffect::Make(intervals, 2, 25));
1100
1101 for (int i = 0; i < 50; ++i) {
1102 canvas->drawRect(SkRect::MakeWH(10, 10), paint);
1103 }
1104 }
1105 sk_sp<SkPicture> vetoPicture(recorder.finishRecordingAsPicture());
1106
1107 SkPictureGpuAnalyzer analyzer;
1108 REPORTER_ASSERT(r, analyzer.suitableForGpuRasterization());
1109
fmalita019db3f2016-05-31 06:32:57 -07001110 analyzer.analyzePicture(vetoPicture.get());
fmalita796e3652016-05-13 11:40:07 -07001111 REPORTER_ASSERT(r, !analyzer.suitableForGpuRasterization());
1112
1113 analyzer.reset();
1114 REPORTER_ASSERT(r, analyzer.suitableForGpuRasterization());
1115
1116 recorder.beginRecording(10, 10)->drawPicture(vetoPicture);
1117 sk_sp<SkPicture> nestedVetoPicture(recorder.finishRecordingAsPicture());
1118
fmalita019db3f2016-05-31 06:32:57 -07001119 analyzer.analyzePicture(nestedVetoPicture.get());
fmalita796e3652016-05-13 11:40:07 -07001120 REPORTER_ASSERT(r, !analyzer.suitableForGpuRasterization());
fmalitab5fc58e2016-05-25 11:31:04 -07001121
1122 analyzer.reset();
1123
1124 const SkPath convexClip = make_convex_path();
1125 const SkPath concaveClip = make_concave_path();
1126 for (int i = 0; i < 50; ++i) {
Mike Reedc1f77742016-12-09 09:00:50 -05001127 analyzer.analyzeClipPath(convexClip, kIntersect_SkClipOp, false);
1128 analyzer.analyzeClipPath(convexClip, kIntersect_SkClipOp, true);
1129 analyzer.analyzeClipPath(concaveClip, kIntersect_SkClipOp, false);
fmalitab5fc58e2016-05-25 11:31:04 -07001130 }
1131 REPORTER_ASSERT(r, analyzer.suitableForGpuRasterization());
1132
1133 for (int i = 0; i < 50; ++i) {
Mike Reedc1f77742016-12-09 09:00:50 -05001134 analyzer.analyzeClipPath(concaveClip, kIntersect_SkClipOp, true);
fmalitab5fc58e2016-05-25 11:31:04 -07001135 }
1136 REPORTER_ASSERT(r, !analyzer.suitableForGpuRasterization());
fmalita796e3652016-05-13 11:40:07 -07001137}
1138
1139#endif // SK_SUPPORT_GPU
reed41c27e12016-07-06 09:29:16 -07001140
1141///////////////////////////////////////////////////////////////////////////////////////////////////
1142
reedde996a02016-07-20 11:24:51 -07001143// Disable until we properly fix https://bugs.chromium.org/p/skia/issues/detail?id=5548
1144#if 0
reed41c27e12016-07-06 09:29:16 -07001145static void empty_ops(SkCanvas* canvas) {
1146}
1147static void clip_ops(SkCanvas* canvas) {
1148 canvas->save();
1149 canvas->clipRect(SkRect::MakeWH(20, 20));
1150 canvas->restore();
1151}
1152static void matrix_ops(SkCanvas* canvas) {
1153 canvas->save();
1154 canvas->scale(2, 3);
1155 canvas->restore();
1156}
1157static void matrixclip_ops(SkCanvas* canvas) {
1158 canvas->save();
1159 canvas->scale(2, 3);
1160 canvas->clipRect(SkRect::MakeWH(20, 20));
1161 canvas->restore();
1162}
1163typedef void (*CanvasProc)(SkCanvas*);
1164
1165// Test the kReturnNullForEmpty_FinishFlag option when recording
1166//
1167DEF_TEST(Picture_RecordEmpty, r) {
1168 const SkRect cull = SkRect::MakeWH(100, 100);
1169
1170 CanvasProc procs[] { empty_ops, clip_ops, matrix_ops, matrixclip_ops };
1171
1172 for (auto proc : procs) {
1173 {
1174 SkPictureRecorder rec;
1175 proc(rec.beginRecording(cull));
1176 sk_sp<SkPicture> pic = rec.finishRecordingAsPicture(0);
1177 REPORTER_ASSERT(r, pic.get());
1178 REPORTER_ASSERT(r, pic->approximateOpCount() == 0);
1179 }
1180 {
1181 SkPictureRecorder rec;
1182 proc(rec.beginRecording(cull));
1183 sk_sp<SkPicture> pic = rec.finishRecordingAsPicture(
1184 SkPictureRecorder::kReturnNullForEmpty_FinishFlag);
1185 REPORTER_ASSERT(r, !pic.get());
1186 }
1187 {
1188 SkPictureRecorder rec;
1189 proc(rec.beginRecording(cull));
1190 sk_sp<SkDrawable> dr = rec.finishRecordingAsDrawable(0);
1191 REPORTER_ASSERT(r, dr.get());
1192 }
1193 {
1194 SkPictureRecorder rec;
1195 proc(rec.beginRecording(cull));
1196 sk_sp<SkDrawable> dr = rec.finishRecordingAsDrawable(
1197 SkPictureRecorder::kReturnNullForEmpty_FinishFlag);
1198 REPORTER_ASSERT(r, !dr.get());
1199 }
1200 }
1201}
reedde996a02016-07-20 11:24:51 -07001202#endif
1203