blob: 0dc3bfe7b6374ac86a20b6424cf91da79bd89073 [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"
mtkleind72094d2014-08-27 12:12:23 -070024#include "SkPixelRef.h"
scroggo895c43b2014-12-11 10:53:58 -080025#include "SkPixelSerializer.h"
mtklein9db912c2015-05-19 11:11:26 -070026#include "SkMiniRecorder.h"
reed@google.com72aa79c2013-01-24 18:27:42 +000027#include "SkRRect.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000028#include "SkRandom.h"
tomhudson158fcaa2014-11-19 10:41:14 -080029#include "SkRecord.h"
reed@google.comfe7b1ed2012-11-29 21:00:39 +000030#include "SkShader.h"
scroggo@google.comd614c6a2012-09-14 17:26:37 +000031#include "SkStream.h"
robertphillips3e5c2b12015-03-23 05:46:51 -070032#include "sk_tool_utils.h"
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +000033
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000034#include "Test.h"
scroggo@google.comd614c6a2012-09-14 17:26:37 +000035
reed@google.com47b679b2014-05-14 18:58:16 +000036#include "SkLumaColorFilter.h"
37#include "SkColorFilterImageFilter.h"
38
reed@google.comfe7b1ed2012-11-29 21:00:39 +000039static void make_bm(SkBitmap* bm, int w, int h, SkColor color, bool immutable) {
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +000040 bm->allocN32Pixels(w, h);
reed@google.comfe7b1ed2012-11-29 21:00:39 +000041 bm->eraseColor(color);
42 if (immutable) {
43 bm->setImmutable();
44 }
45}
46
mtkleina16af212015-08-26 08:14:52 -070047// For a while willPlayBackBitmaps() ignored SkImages and just looked for SkBitmaps.
48static void test_images_are_found_by_willPlayBackBitmaps(skiatest::Reporter* reporter) {
reede3b38ce2016-01-08 09:18:44 -080049 // We just need _some_ SkImage
50 const SkPMColor pixel = 0;
51 const SkImageInfo info = SkImageInfo::MakeN32Premul(1, 1);
reed9ce9d672016-03-17 10:51:11 -070052 sk_sp<SkImage> image(SkImage::MakeRasterCopy(SkPixmap(info, &pixel, sizeof(pixel))));
mtkleina16af212015-08-26 08:14:52 -070053
54 SkPictureRecorder recorder;
reede3b38ce2016-01-08 09:18:44 -080055 recorder.beginRecording(100,100)->drawImage(image, 0,0);
reedca2622b2016-03-18 07:25:55 -070056 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
mtkleina16af212015-08-26 08:14:52 -070057
58 REPORTER_ASSERT(reporter, picture->willPlayBackBitmaps());
59}
60
tomhudson3a0f2792014-08-20 05:29:41 -070061/* Hit a few SkPicture::Analysis cases not handled elsewhere. */
mtklein8e126562014-10-01 09:29:35 -070062static void test_analysis(skiatest::Reporter* reporter) {
tomhudson3a0f2792014-08-20 05:29:41 -070063 SkPictureRecorder recorder;
64
mtklein8e126562014-10-01 09:29:35 -070065 SkCanvas* canvas = recorder.beginRecording(100, 100);
tomhudson3a0f2792014-08-20 05:29:41 -070066 {
67 canvas->drawRect(SkRect::MakeWH(10, 10), SkPaint ());
68 }
reedca2622b2016-03-18 07:25:55 -070069 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
tomhudson3a0f2792014-08-20 05:29:41 -070070 REPORTER_ASSERT(reporter, !picture->willPlayBackBitmaps());
71
mtklein8e126562014-10-01 09:29:35 -070072 canvas = recorder.beginRecording(100, 100);
tomhudson3a0f2792014-08-20 05:29:41 -070073 {
74 SkPaint paint;
75 // CreateBitmapShader is too smart for us; an empty (or 1x1) bitmap shader
76 // gets optimized into a non-bitmap form, so we create a 2x2 bitmap here.
77 SkBitmap bitmap;
78 bitmap.allocPixels(SkImageInfo::MakeN32Premul(2, 2));
79 bitmap.eraseColor(SK_ColorBLUE);
80 *(bitmap.getAddr32(0, 0)) = SK_ColorGREEN;
reed1a9b9642016-03-13 14:13:58 -070081 paint.setShader(SkShader::MakeBitmapShader(bitmap, SkShader::kClamp_TileMode,
82 SkShader::kClamp_TileMode));
Mike Reed627778d2016-09-28 17:13:38 -040083 REPORTER_ASSERT(reporter, paint.getShader()->isAImage());
tomhudson3a0f2792014-08-20 05:29:41 -070084
85 canvas->drawRect(SkRect::MakeWH(10, 10), paint);
86 }
reedca2622b2016-03-18 07:25:55 -070087 REPORTER_ASSERT(reporter, recorder.finishRecordingAsPicture()->willPlayBackBitmaps());
tomhudson3a0f2792014-08-20 05:29:41 -070088}
89
90
scroggo@google.comd614c6a2012-09-14 17:26:37 +000091#ifdef SK_DEBUG
mtklein3e8232b2014-08-18 13:39:11 -070092// Ensure that deleting an empty SkPicture does not assert. Asserts only fire
robertphillipsdb539902014-07-01 08:47:04 -070093// in debug mode, so only run in debug mode.
94static void test_deleting_empty_picture() {
robertphillips@google.com84b18c72014-04-13 19:09:42 +000095 SkPictureRecorder recorder;
scroggo@google.comd614c6a2012-09-14 17:26:37 +000096 // Creates an SkPictureRecord
robertphillips9f1c2412014-06-09 06:25:34 -070097 recorder.beginRecording(0, 0);
robertphillipsdb539902014-07-01 08:47:04 -070098 // Turns that into an SkPicture
reedca2622b2016-03-18 07:25:55 -070099 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
robertphillipsdb539902014-07-01 08:47:04 -0700100 // Ceates a new SkPictureRecord
robertphillips9f1c2412014-06-09 06:25:34 -0700101 recorder.beginRecording(0, 0);
scroggo@google.comd614c6a2012-09-14 17:26:37 +0000102}
103
104// Ensure that serializing an empty picture does not assert. Likewise only runs in debug mode.
105static void test_serializing_empty_picture() {
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000106 SkPictureRecorder recorder;
robertphillips9f1c2412014-06-09 06:25:34 -0700107 recorder.beginRecording(0, 0);
reedca2622b2016-03-18 07:25:55 -0700108 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
scroggo@google.comd614c6a2012-09-14 17:26:37 +0000109 SkDynamicMemoryWStream stream;
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000110 picture->serialize(&stream);
scroggo@google.comd614c6a2012-09-14 17:26:37 +0000111}
112#endif
113
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000114static void rand_op(SkCanvas* canvas, SkRandom& rand) {
reed@google.com21b519d2012-10-02 17:42:15 +0000115 SkPaint paint;
116 SkRect rect = SkRect::MakeWH(50, 50);
117
118 SkScalar unit = rand.nextUScalar1();
119 if (unit <= 0.3) {
120// SkDebugf("save\n");
121 canvas->save();
122 } else if (unit <= 0.6) {
123// SkDebugf("restore\n");
124 canvas->restore();
125 } else if (unit <= 0.9) {
126// SkDebugf("clip\n");
127 canvas->clipRect(rect);
128 } else {
129// SkDebugf("draw\n");
130 canvas->drawPaint(paint);
131 }
132}
133
robertphillips@google.comb950c6f2014-04-25 00:02:12 +0000134#if SK_SUPPORT_GPU
tomhudson3a0f2792014-08-20 05:29:41 -0700135
fmalitab5fc58e2016-05-25 11:31:04 -0700136static SkPath make_convex_path() {
137 SkPath path;
138 path.lineTo(100, 0);
139 path.lineTo(50, 100);
140 path.close();
141
142 return path;
143}
144
145static SkPath make_concave_path() {
146 SkPath path;
147 path.lineTo(50, 50);
148 path.lineTo(100, 0);
149 path.lineTo(50, 100);
150 path.close();
151
152 return path;
153}
154
mtklein8e126562014-10-01 09:29:35 -0700155static void test_gpu_veto(skiatest::Reporter* reporter) {
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +0000156 SkPictureRecorder recorder;
157
mtklein8e126562014-10-01 09:29:35 -0700158 SkCanvas* canvas = recorder.beginRecording(100, 100);
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +0000159 {
160 SkPath path;
161 path.moveTo(0, 0);
162 path.lineTo(50, 50);
163
164 SkScalar intervals[] = { 1.0f, 1.0f };
reeda4393342016-03-18 11:22:57 -0700165 sk_sp<SkPathEffect> dash(SkDashPathEffect::Make(intervals, 2, 0));
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +0000166
167 SkPaint paint;
168 paint.setStyle(SkPaint::kStroke_Style);
169 paint.setPathEffect(dash);
170
robertphillips98b03152015-01-26 11:29:36 -0800171 for (int i = 0; i < 50; ++i) {
172 canvas->drawPath(path, paint);
173 }
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +0000174 }
reedca2622b2016-03-18 07:25:55 -0700175 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +0000176 // path effects currently render an SkPicture undesireable for GPU rendering
commit-bot@chromium.orga1ff26a2014-05-30 21:52:52 +0000177
halcanary96fcdcc2015-08-27 07:41:13 -0700178 const char *reason = nullptr;
fmalita796e3652016-05-13 11:40:07 -0700179 REPORTER_ASSERT(reporter,
180 !SkPictureGpuAnalyzer(picture).suitableForGpuRasterization(&reason));
bsalomon49f085d2014-09-05 13:34:00 -0700181 REPORTER_ASSERT(reporter, reason);
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +0000182
mtklein8e126562014-10-01 09:29:35 -0700183 canvas = recorder.beginRecording(100, 100);
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +0000184 {
185 SkPath path;
186
187 path.moveTo(0, 0);
188 path.lineTo(0, 50);
189 path.lineTo(25, 25);
190 path.lineTo(50, 50);
191 path.lineTo(50, 0);
192 path.close();
193 REPORTER_ASSERT(reporter, !path.isConvex());
194
195 SkPaint paint;
196 paint.setAntiAlias(true);
197 for (int i = 0; i < 50; ++i) {
198 canvas->drawPath(path, paint);
199 }
200 }
reedca2622b2016-03-18 07:25:55 -0700201 picture = recorder.finishRecordingAsPicture();
jvanverthd86b07a2014-11-04 08:50:15 -0800202 // A lot of small AA concave paths should be fine for GPU rendering
fmalita796e3652016-05-13 11:40:07 -0700203 REPORTER_ASSERT(reporter, SkPictureGpuAnalyzer(picture).suitableForGpuRasterization());
jvanverthd86b07a2014-11-04 08:50:15 -0800204
205 canvas = recorder.beginRecording(100, 100);
206 {
207 SkPath path;
208
209 path.moveTo(0, 0);
210 path.lineTo(0, 100);
211 path.lineTo(50, 50);
212 path.lineTo(100, 100);
213 path.lineTo(100, 0);
214 path.close();
215 REPORTER_ASSERT(reporter, !path.isConvex());
216
217 SkPaint paint;
218 paint.setAntiAlias(true);
219 for (int i = 0; i < 50; ++i) {
220 canvas->drawPath(path, paint);
221 }
222 }
reedca2622b2016-03-18 07:25:55 -0700223 picture = recorder.finishRecordingAsPicture();
jvanverthd86b07a2014-11-04 08:50:15 -0800224 // A lot of large AA concave paths currently render an SkPicture undesireable for GPU rendering
fmalita796e3652016-05-13 11:40:07 -0700225 REPORTER_ASSERT(reporter, !SkPictureGpuAnalyzer(picture).suitableForGpuRasterization());
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +0000226
mtklein8e126562014-10-01 09:29:35 -0700227 canvas = recorder.beginRecording(100, 100);
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +0000228 {
229 SkPath path;
230
231 path.moveTo(0, 0);
232 path.lineTo(0, 50);
233 path.lineTo(25, 25);
234 path.lineTo(50, 50);
235 path.lineTo(50, 0);
236 path.close();
237 REPORTER_ASSERT(reporter, !path.isConvex());
238
239 SkPaint paint;
240 paint.setAntiAlias(true);
241 paint.setStyle(SkPaint::kStroke_Style);
242 paint.setStrokeWidth(0);
243 for (int i = 0; i < 50; ++i) {
244 canvas->drawPath(path, paint);
245 }
246 }
reedca2622b2016-03-18 07:25:55 -0700247 picture = recorder.finishRecordingAsPicture();
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +0000248 // hairline stroked AA concave paths are fine for GPU rendering
fmalita796e3652016-05-13 11:40:07 -0700249 REPORTER_ASSERT(reporter, SkPictureGpuAnalyzer(picture).suitableForGpuRasterization());
tomhudson3a0f2792014-08-20 05:29:41 -0700250
mtklein8e126562014-10-01 09:29:35 -0700251 canvas = recorder.beginRecording(100, 100);
tomhudson3a0f2792014-08-20 05:29:41 -0700252 {
253 SkPaint paint;
254 SkScalar intervals [] = { 10, 20 };
reeda4393342016-03-18 11:22:57 -0700255 paint.setPathEffect(SkDashPathEffect::Make(intervals, 2, 25));
tomhudson3a0f2792014-08-20 05:29:41 -0700256
257 SkPoint points [2] = { { 0, 0 }, { 100, 0 } };
robertphillips98b03152015-01-26 11:29:36 -0800258
259 for (int i = 0; i < 50; ++i) {
260 canvas->drawPoints(SkCanvas::kLines_PointMode, 2, points, paint);
261 }
tomhudson3a0f2792014-08-20 05:29:41 -0700262 }
reedca2622b2016-03-18 07:25:55 -0700263 picture = recorder.finishRecordingAsPicture();
tomhudson3a0f2792014-08-20 05:29:41 -0700264 // fast-path dashed effects are fine for GPU rendering ...
fmalita796e3652016-05-13 11:40:07 -0700265 REPORTER_ASSERT(reporter, SkPictureGpuAnalyzer(picture).suitableForGpuRasterization());
tomhudson3a0f2792014-08-20 05:29:41 -0700266
mtklein8e126562014-10-01 09:29:35 -0700267 canvas = recorder.beginRecording(100, 100);
tomhudson3a0f2792014-08-20 05:29:41 -0700268 {
269 SkPaint paint;
270 SkScalar intervals [] = { 10, 20 };
reeda4393342016-03-18 11:22:57 -0700271 paint.setPathEffect(SkDashPathEffect::Make(intervals, 2, 25));
tomhudson3a0f2792014-08-20 05:29:41 -0700272
robertphillips98b03152015-01-26 11:29:36 -0800273 for (int i = 0; i < 50; ++i) {
274 canvas->drawRect(SkRect::MakeWH(10, 10), paint);
275 }
tomhudson3a0f2792014-08-20 05:29:41 -0700276 }
reedca2622b2016-03-18 07:25:55 -0700277 picture = recorder.finishRecordingAsPicture();
tomhudson3a0f2792014-08-20 05:29:41 -0700278 // ... but only when applied to drawPoint() calls
fmalita796e3652016-05-13 11:40:07 -0700279 REPORTER_ASSERT(reporter, !SkPictureGpuAnalyzer(picture).suitableForGpuRasterization());
mtklein53fecfb2014-08-21 09:11:37 -0700280
fmalitab5fc58e2016-05-25 11:31:04 -0700281 canvas = recorder.beginRecording(100, 100);
282 {
283 const SkPath convexClip = make_convex_path();
284 const SkPath concaveClip = make_concave_path();
285
286 for (int i = 0; i < 50; ++i) {
287 canvas->clipPath(convexClip);
288 canvas->clipPath(concaveClip);
Mike Reedc1f77742016-12-09 09:00:50 -0500289 canvas->clipPath(convexClip, kIntersect_SkClipOp, true);
fmalitab5fc58e2016-05-25 11:31:04 -0700290 canvas->drawRect(SkRect::MakeWH(100, 100), SkPaint());
291 }
292 }
293 picture = recorder.finishRecordingAsPicture();
294 // Convex clips and non-AA concave clips are fine on the GPU.
295 REPORTER_ASSERT(reporter, SkPictureGpuAnalyzer(picture).suitableForGpuRasterization());
296
297 canvas = recorder.beginRecording(100, 100);
298 {
299 const SkPath concaveClip = make_concave_path();
300 for (int i = 0; i < 50; ++i) {
Mike Reedc1f77742016-12-09 09:00:50 -0500301 canvas->clipPath(concaveClip, kIntersect_SkClipOp, true);
fmalitab5fc58e2016-05-25 11:31:04 -0700302 canvas->drawRect(SkRect::MakeWH(100, 100), SkPaint());
303 }
304 }
305 picture = recorder.finishRecordingAsPicture();
306 // ... but AA concave clips are not.
307 REPORTER_ASSERT(reporter, !SkPictureGpuAnalyzer(picture).suitableForGpuRasterization());
308
mtklein53fecfb2014-08-21 09:11:37 -0700309 // Nest the previous picture inside a new one.
mtklein8e126562014-10-01 09:29:35 -0700310 canvas = recorder.beginRecording(100, 100);
311 {
fmalita796e3652016-05-13 11:40:07 -0700312 canvas->drawPicture(picture);
mtklein53fecfb2014-08-21 09:11:37 -0700313 }
reedca2622b2016-03-18 07:25:55 -0700314 picture = recorder.finishRecordingAsPicture();
fmalita796e3652016-05-13 11:40:07 -0700315 REPORTER_ASSERT(reporter, !SkPictureGpuAnalyzer(picture).suitableForGpuRasterization());
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +0000316}
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +0000317
fmalita796e3652016-05-13 11:40:07 -0700318#endif // SK_SUPPORT_GPU
commit-bot@chromium.org0205aba2014-05-06 12:02:22 +0000319
commit-bot@chromium.orgea7d08e2014-02-13 16:00:51 +0000320static void set_canvas_to_save_count_4(SkCanvas* canvas) {
321 canvas->restoreToCount(1);
322 canvas->save();
323 canvas->save();
324 canvas->save();
325}
326
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000327/**
328 * A canvas that records the number of saves, saveLayers and restores.
329 */
330class SaveCountingCanvas : public SkCanvas {
331public:
332 SaveCountingCanvas(int width, int height)
333 : INHERITED(width, height)
334 , fSaveCount(0)
335 , fSaveLayerCount(0)
336 , fRestoreCount(0){
337 }
338
reed4960eee2015-12-18 07:09:18 -0800339 SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec& rec) override {
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000340 ++fSaveLayerCount;
reed4960eee2015-12-18 07:09:18 -0800341 return this->INHERITED::getSaveLayerStrategy(rec);
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000342 }
343
mtklein36352bf2015-03-25 18:17:31 -0700344 void willSave() override {
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000345 ++fSaveCount;
Florin Malita5f6102d2014-06-30 10:13:28 -0400346 this->INHERITED::willSave();
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000347 }
348
mtklein36352bf2015-03-25 18:17:31 -0700349 void willRestore() override {
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000350 ++fRestoreCount;
351 this->INHERITED::willRestore();
352 }
353
354 unsigned int getSaveCount() const { return fSaveCount; }
355 unsigned int getSaveLayerCount() const { return fSaveLayerCount; }
356 unsigned int getRestoreCount() const { return fRestoreCount; }
357
358private:
359 unsigned int fSaveCount;
360 unsigned int fSaveLayerCount;
361 unsigned int fRestoreCount;
362
363 typedef SkCanvas INHERITED;
364};
365
skia.committer@gmail.com8e7d37d2014-05-28 03:06:06 +0000366void check_save_state(skiatest::Reporter* reporter, SkPicture* picture,
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000367 unsigned int numSaves, unsigned int numSaveLayers,
368 unsigned int numRestores) {
mtklein87c41382014-09-08 07:31:18 -0700369 SaveCountingCanvas canvas(SkScalarCeilToInt(picture->cullRect().width()),
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700370 SkScalarCeilToInt(picture->cullRect().height()));
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000371
robertphillipsc5ba71d2014-09-04 08:42:50 -0700372 picture->playback(&canvas);
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000373
mtklein87c41382014-09-08 07:31:18 -0700374 // Optimizations may have removed these,
375 // so expect to have seen no more than num{Saves,SaveLayers,Restores}.
376 REPORTER_ASSERT(reporter, numSaves >= canvas.getSaveCount());
377 REPORTER_ASSERT(reporter, numSaveLayers >= canvas.getSaveLayerCount());
378 REPORTER_ASSERT(reporter, numRestores >= canvas.getRestoreCount());
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000379}
380
381// This class exists so SkPicture can friend it and give it access to
382// the 'partialReplay' method.
383class SkPictureRecorderReplayTester {
384public:
reedca2622b2016-03-18 07:25:55 -0700385 static sk_sp<SkPicture> Copy(SkPictureRecorder* recorder) {
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000386 SkPictureRecorder recorder2;
387
robertphillips9f1c2412014-06-09 06:25:34 -0700388 SkCanvas* canvas = recorder2.beginRecording(10, 10);
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000389
390 recorder->partialReplay(canvas);
391
reedca2622b2016-03-18 07:25:55 -0700392 return recorder2.finishRecordingAsPicture();
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000393 }
394};
395
robertphillips9058d602014-06-10 11:45:46 -0700396static void create_imbalance(SkCanvas* canvas) {
397 SkRect clipRect = SkRect::MakeWH(2, 2);
398 SkRect drawRect = SkRect::MakeWH(10, 10);
399 canvas->save();
Mike Reedc1f77742016-12-09 09:00:50 -0500400 canvas->clipRect(clipRect, kReplace_SkClipOp);
robertphillips9058d602014-06-10 11:45:46 -0700401 canvas->translate(1.0f, 1.0f);
402 SkPaint p;
403 p.setColor(SK_ColorGREEN);
404 canvas->drawRect(drawRect, p);
405 // no restore
406}
407
408// This tests that replaying a potentially unbalanced picture into a canvas
409// doesn't affect the canvas' save count or matrix/clip state.
410static void check_balance(skiatest::Reporter* reporter, SkPicture* picture) {
411 SkBitmap bm;
412 bm.allocN32Pixels(4, 3);
413 SkCanvas canvas(bm);
414
415 int beforeSaveCount = canvas.getSaveCount();
416
417 SkMatrix beforeMatrix = canvas.getTotalMatrix();
418
Mike Reed918e1442017-01-23 11:39:45 -0500419 SkRect beforeClip = canvas.getLocalClipBounds();
robertphillips9058d602014-06-10 11:45:46 -0700420
421 canvas.drawPicture(picture);
422
423 REPORTER_ASSERT(reporter, beforeSaveCount == canvas.getSaveCount());
424 REPORTER_ASSERT(reporter, beforeMatrix == canvas.getTotalMatrix());
425
Mike Reed918e1442017-01-23 11:39:45 -0500426 SkRect afterClip = canvas.getLocalClipBounds();
robertphillips9058d602014-06-10 11:45:46 -0700427
428 REPORTER_ASSERT(reporter, afterClip == beforeClip);
429}
430
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000431// Test out SkPictureRecorder::partialReplay
432DEF_TEST(PictureRecorder_replay, reporter) {
433 // check save/saveLayer state
434 {
435 SkPictureRecorder recorder;
436
robertphillips9f1c2412014-06-09 06:25:34 -0700437 SkCanvas* canvas = recorder.beginRecording(10, 10);
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000438
halcanary96fcdcc2015-08-27 07:41:13 -0700439 canvas->saveLayer(nullptr, nullptr);
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000440
reedca2622b2016-03-18 07:25:55 -0700441 sk_sp<SkPicture> copy(SkPictureRecorderReplayTester::Copy(&recorder));
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000442
443 // The extra save and restore comes from the Copy process.
reedca2622b2016-03-18 07:25:55 -0700444 check_save_state(reporter, copy.get(), 2, 1, 3);
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000445
halcanary96fcdcc2015-08-27 07:41:13 -0700446 canvas->saveLayer(nullptr, nullptr);
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000447
reedca2622b2016-03-18 07:25:55 -0700448 sk_sp<SkPicture> final(recorder.finishRecordingAsPicture());
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000449
reedca2622b2016-03-18 07:25:55 -0700450 check_save_state(reporter, final.get(), 1, 2, 3);
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000451
452 // The copy shouldn't pick up any operations added after it was made
reedca2622b2016-03-18 07:25:55 -0700453 check_save_state(reporter, copy.get(), 2, 1, 3);
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000454 }
455
456 // (partially) check leakage of draw ops
457 {
458 SkPictureRecorder recorder;
459
robertphillips9f1c2412014-06-09 06:25:34 -0700460 SkCanvas* canvas = recorder.beginRecording(10, 10);
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000461
462 SkRect r = SkRect::MakeWH(5, 5);
463 SkPaint p;
464
465 canvas->drawRect(r, p);
466
reedca2622b2016-03-18 07:25:55 -0700467 sk_sp<SkPicture> copy(SkPictureRecorderReplayTester::Copy(&recorder));
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000468
469 REPORTER_ASSERT(reporter, !copy->willPlayBackBitmaps());
470
471 SkBitmap bm;
472 make_bm(&bm, 10, 10, SK_ColorRED, true);
473
474 r.offset(5.0f, 5.0f);
reede47829b2015-08-06 10:02:53 -0700475 canvas->drawBitmapRect(bm, r, nullptr);
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000476
reedca2622b2016-03-18 07:25:55 -0700477 sk_sp<SkPicture> final(recorder.finishRecordingAsPicture());
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000478 REPORTER_ASSERT(reporter, final->willPlayBackBitmaps());
479
480 REPORTER_ASSERT(reporter, copy->uniqueID() != final->uniqueID());
481
482 // The snapshot shouldn't pick up any operations added after it was made
483 REPORTER_ASSERT(reporter, !copy->willPlayBackBitmaps());
484 }
robertphillips9058d602014-06-10 11:45:46 -0700485
486 // Recreate the Android partialReplay test case
487 {
488 SkPictureRecorder recorder;
489
halcanary96fcdcc2015-08-27 07:41:13 -0700490 SkCanvas* canvas = recorder.beginRecording(4, 3, nullptr, 0);
robertphillips9058d602014-06-10 11:45:46 -0700491 create_imbalance(canvas);
492
493 int expectedSaveCount = canvas->getSaveCount();
494
reedca2622b2016-03-18 07:25:55 -0700495 sk_sp<SkPicture> copy(SkPictureRecorderReplayTester::Copy(&recorder));
496 check_balance(reporter, copy.get());
robertphillips9058d602014-06-10 11:45:46 -0700497
498 REPORTER_ASSERT(reporter, expectedSaveCount = canvas->getSaveCount());
499
500 // End the recording of source to test the picture finalization
501 // process isn't complicated by the partialReplay step
reedca2622b2016-03-18 07:25:55 -0700502 sk_sp<SkPicture> final(recorder.finishRecordingAsPicture());
robertphillips9058d602014-06-10 11:45:46 -0700503 }
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000504}
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000505
commit-bot@chromium.orgea7d08e2014-02-13 16:00:51 +0000506static void test_unbalanced_save_restores(skiatest::Reporter* reporter) {
507 SkCanvas testCanvas(100, 100);
508 set_canvas_to_save_count_4(&testCanvas);
509
510 REPORTER_ASSERT(reporter, 4 == testCanvas.getSaveCount());
511
512 SkPaint paint;
513 SkRect rect = SkRect::MakeLTRB(-10000000, -10000000, 10000000, 10000000);
514
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000515 SkPictureRecorder recorder;
commit-bot@chromium.orgea7d08e2014-02-13 16:00:51 +0000516
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000517 {
518 // Create picture with 2 unbalanced saves
robertphillips9f1c2412014-06-09 06:25:34 -0700519 SkCanvas* canvas = recorder.beginRecording(100, 100);
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000520 canvas->save();
521 canvas->translate(10, 10);
522 canvas->drawRect(rect, paint);
523 canvas->save();
524 canvas->translate(10, 10);
525 canvas->drawRect(rect, paint);
reedca2622b2016-03-18 07:25:55 -0700526 sk_sp<SkPicture> extraSavePicture(recorder.finishRecordingAsPicture());
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000527
robertphillips9b14f262014-06-04 05:40:44 -0700528 testCanvas.drawPicture(extraSavePicture);
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000529 REPORTER_ASSERT(reporter, 4 == testCanvas.getSaveCount());
530 }
commit-bot@chromium.orgea7d08e2014-02-13 16:00:51 +0000531
532 set_canvas_to_save_count_4(&testCanvas);
533
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000534 {
535 // Create picture with 2 unbalanced restores
robertphillips9f1c2412014-06-09 06:25:34 -0700536 SkCanvas* canvas = recorder.beginRecording(100, 100);
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000537 canvas->save();
538 canvas->translate(10, 10);
539 canvas->drawRect(rect, paint);
540 canvas->save();
541 canvas->translate(10, 10);
542 canvas->drawRect(rect, paint);
543 canvas->restore();
544 canvas->restore();
545 canvas->restore();
546 canvas->restore();
reedca2622b2016-03-18 07:25:55 -0700547 sk_sp<SkPicture> extraRestorePicture(recorder.finishRecordingAsPicture());
commit-bot@chromium.orgea7d08e2014-02-13 16:00:51 +0000548
robertphillips9b14f262014-06-04 05:40:44 -0700549 testCanvas.drawPicture(extraRestorePicture);
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000550 REPORTER_ASSERT(reporter, 4 == testCanvas.getSaveCount());
551 }
commit-bot@chromium.orgea7d08e2014-02-13 16:00:51 +0000552
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000553 set_canvas_to_save_count_4(&testCanvas);
commit-bot@chromium.orgea7d08e2014-02-13 16:00:51 +0000554
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000555 {
robertphillips9f1c2412014-06-09 06:25:34 -0700556 SkCanvas* canvas = recorder.beginRecording(100, 100);
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000557 canvas->translate(10, 10);
558 canvas->drawRect(rect, paint);
reedca2622b2016-03-18 07:25:55 -0700559 sk_sp<SkPicture> noSavePicture(recorder.finishRecordingAsPicture());
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000560
robertphillips9b14f262014-06-04 05:40:44 -0700561 testCanvas.drawPicture(noSavePicture);
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000562 REPORTER_ASSERT(reporter, 4 == testCanvas.getSaveCount());
563 REPORTER_ASSERT(reporter, testCanvas.getTotalMatrix().isIdentity());
564 }
commit-bot@chromium.orgea7d08e2014-02-13 16:00:51 +0000565}
566
sugoi@google.com54f0d1b2013-02-27 19:17:41 +0000567static void test_peephole() {
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000568 SkRandom rand;
reed@google.com21b519d2012-10-02 17:42:15 +0000569
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000570 SkPictureRecorder recorder;
571
reed@google.com21b519d2012-10-02 17:42:15 +0000572 for (int j = 0; j < 100; j++) {
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000573 SkRandom rand2(rand); // remember the seed
reed@google.com21b519d2012-10-02 17:42:15 +0000574
robertphillips9f1c2412014-06-09 06:25:34 -0700575 SkCanvas* canvas = recorder.beginRecording(100, 100);
reed@google.com21b519d2012-10-02 17:42:15 +0000576
577 for (int i = 0; i < 1000; ++i) {
578 rand_op(canvas, rand);
579 }
reedca2622b2016-03-18 07:25:55 -0700580 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
jvanverth@google.comc490f802013-03-04 13:56:38 +0000581
582 rand = rand2;
reed@google.com21b519d2012-10-02 17:42:15 +0000583 }
584
585 {
robertphillips9f1c2412014-06-09 06:25:34 -0700586 SkCanvas* canvas = recorder.beginRecording(100, 100);
reed@google.com21b519d2012-10-02 17:42:15 +0000587 SkRect rect = SkRect::MakeWH(50, 50);
skia.committer@gmail.com52c24372012-10-03 02:01:13 +0000588
reed@google.com21b519d2012-10-02 17:42:15 +0000589 for (int i = 0; i < 100; ++i) {
590 canvas->save();
591 }
592 while (canvas->getSaveCount() > 1) {
593 canvas->clipRect(rect);
594 canvas->restore();
595 }
reedca2622b2016-03-18 07:25:55 -0700596 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
reed@google.com21b519d2012-10-02 17:42:15 +0000597 }
598}
599
scroggo@google.com4b90b112012-12-04 15:08:56 +0000600#ifndef SK_DEBUG
601// Only test this is in release mode. We deliberately crash in debug mode, since a valid caller
602// should never do this.
603static void test_bad_bitmap() {
604 // This bitmap has a width and height but no pixels. As a result, attempting to record it will
605 // fail.
606 SkBitmap bm;
commit-bot@chromium.orga3264e52014-05-30 13:26:10 +0000607 bm.setInfo(SkImageInfo::MakeN32Premul(100, 100));
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000608 SkPictureRecorder recorder;
robertphillips9f1c2412014-06-09 06:25:34 -0700609 SkCanvas* recordingCanvas = recorder.beginRecording(100, 100);
scroggo@google.com4b90b112012-12-04 15:08:56 +0000610 recordingCanvas->drawBitmap(bm, 0, 0);
reedca2622b2016-03-18 07:25:55 -0700611 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
scroggo@google.com4b90b112012-12-04 15:08:56 +0000612
613 SkCanvas canvas;
robertphillips9b14f262014-06-04 05:40:44 -0700614 canvas.drawPicture(picture);
scroggo@google.com4b90b112012-12-04 15:08:56 +0000615}
616#endif
617
junov@chromium.orgd575eed2013-05-08 15:39:13 +0000618static void test_clip_bound_opt(skiatest::Reporter* reporter) {
619 // Test for crbug.com/229011
620 SkRect rect1 = SkRect::MakeXYWH(SkIntToScalar(4), SkIntToScalar(4),
621 SkIntToScalar(2), SkIntToScalar(2));
622 SkRect rect2 = SkRect::MakeXYWH(SkIntToScalar(7), SkIntToScalar(7),
623 SkIntToScalar(1), SkIntToScalar(1));
624 SkRect rect3 = SkRect::MakeXYWH(SkIntToScalar(6), SkIntToScalar(6),
625 SkIntToScalar(1), SkIntToScalar(1));
626
627 SkPath invPath;
628 invPath.addOval(rect1);
629 invPath.setFillType(SkPath::kInverseEvenOdd_FillType);
630 SkPath path;
631 path.addOval(rect2);
632 SkPath path2;
633 path2.addOval(rect3);
634 SkIRect clipBounds;
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000635 SkPictureRecorder recorder;
reedd9544982014-09-09 18:46:22 -0700636
637 // Testing conservative-raster-clip that is enabled by PictureRecord
junov@chromium.orgd575eed2013-05-08 15:39:13 +0000638 {
robertphillips9f1c2412014-06-09 06:25:34 -0700639 SkCanvas* canvas = recorder.beginRecording(10, 10);
reed73603f32016-09-20 08:42:38 -0700640 canvas->clipPath(invPath);
Mike Reed918e1442017-01-23 11:39:45 -0500641 clipBounds = canvas->getDeviceClipBounds();
junov@chromium.orgd575eed2013-05-08 15:39:13 +0000642 REPORTER_ASSERT(reporter, 0 == clipBounds.fLeft);
643 REPORTER_ASSERT(reporter, 0 == clipBounds.fTop);
644 REPORTER_ASSERT(reporter, 10 == clipBounds.fBottom);
645 REPORTER_ASSERT(reporter, 10 == clipBounds.fRight);
646 }
647 {
robertphillips9f1c2412014-06-09 06:25:34 -0700648 SkCanvas* canvas = recorder.beginRecording(10, 10);
reed73603f32016-09-20 08:42:38 -0700649 canvas->clipPath(path);
650 canvas->clipPath(invPath);
Mike Reed918e1442017-01-23 11:39:45 -0500651 clipBounds = canvas->getDeviceClipBounds();
junov@chromium.orgd575eed2013-05-08 15:39:13 +0000652 REPORTER_ASSERT(reporter, 7 == clipBounds.fLeft);
653 REPORTER_ASSERT(reporter, 7 == clipBounds.fTop);
654 REPORTER_ASSERT(reporter, 8 == clipBounds.fBottom);
655 REPORTER_ASSERT(reporter, 8 == clipBounds.fRight);
656 }
657 {
robertphillips9f1c2412014-06-09 06:25:34 -0700658 SkCanvas* canvas = recorder.beginRecording(10, 10);
reed73603f32016-09-20 08:42:38 -0700659 canvas->clipPath(path);
Mike Reedc1f77742016-12-09 09:00:50 -0500660 canvas->clipPath(invPath, kUnion_SkClipOp);
Mike Reed918e1442017-01-23 11:39:45 -0500661 clipBounds = canvas->getDeviceClipBounds();
junov@chromium.orgd575eed2013-05-08 15:39:13 +0000662 REPORTER_ASSERT(reporter, 0 == clipBounds.fLeft);
663 REPORTER_ASSERT(reporter, 0 == clipBounds.fTop);
664 REPORTER_ASSERT(reporter, 10 == clipBounds.fBottom);
665 REPORTER_ASSERT(reporter, 10 == clipBounds.fRight);
666 }
667 {
robertphillips9f1c2412014-06-09 06:25:34 -0700668 SkCanvas* canvas = recorder.beginRecording(10, 10);
Mike Reedc1f77742016-12-09 09:00:50 -0500669 canvas->clipPath(path, kDifference_SkClipOp);
Mike Reed918e1442017-01-23 11:39:45 -0500670 clipBounds = canvas->getDeviceClipBounds();
junov@chromium.orgd575eed2013-05-08 15:39:13 +0000671 REPORTER_ASSERT(reporter, 0 == clipBounds.fLeft);
672 REPORTER_ASSERT(reporter, 0 == clipBounds.fTop);
673 REPORTER_ASSERT(reporter, 10 == clipBounds.fBottom);
674 REPORTER_ASSERT(reporter, 10 == clipBounds.fRight);
675 }
676 {
robertphillips9f1c2412014-06-09 06:25:34 -0700677 SkCanvas* canvas = recorder.beginRecording(10, 10);
Mike Reedc1f77742016-12-09 09:00:50 -0500678 canvas->clipPath(path, kReverseDifference_SkClipOp);
Mike Reed918e1442017-01-23 11:39:45 -0500679 clipBounds = canvas->getDeviceClipBounds();
junov@chromium.orgd575eed2013-05-08 15:39:13 +0000680 // True clip is actually empty in this case, but the best
681 // determination we can make using only bounds as input is that the
682 // clip is included in the bounds of 'path'.
junov@chromium.orgd575eed2013-05-08 15:39:13 +0000683 REPORTER_ASSERT(reporter, 7 == clipBounds.fLeft);
684 REPORTER_ASSERT(reporter, 7 == clipBounds.fTop);
685 REPORTER_ASSERT(reporter, 8 == clipBounds.fBottom);
686 REPORTER_ASSERT(reporter, 8 == clipBounds.fRight);
687 }
688 {
robertphillips9f1c2412014-06-09 06:25:34 -0700689 SkCanvas* canvas = recorder.beginRecording(10, 10);
Mike Reedc1f77742016-12-09 09:00:50 -0500690 canvas->clipPath(path, kIntersect_SkClipOp);
691 canvas->clipPath(path2, kXOR_SkClipOp);
Mike Reed918e1442017-01-23 11:39:45 -0500692 clipBounds = canvas->getDeviceClipBounds();
junov@chromium.orgd575eed2013-05-08 15:39:13 +0000693 REPORTER_ASSERT(reporter, 6 == clipBounds.fLeft);
694 REPORTER_ASSERT(reporter, 6 == clipBounds.fTop);
695 REPORTER_ASSERT(reporter, 8 == clipBounds.fBottom);
696 REPORTER_ASSERT(reporter, 8 == clipBounds.fRight);
697 }
698}
699
schenneyeeff8bb2015-07-07 14:27:10 -0700700static void test_cull_rect_reset(skiatest::Reporter* reporter) {
701 SkPictureRecorder recorder;
702 SkRect bounds = SkRect::MakeWH(10, 10);
703 SkRTreeFactory factory;
704 SkCanvas* canvas = recorder.beginRecording(bounds, &factory);
705 bounds = SkRect::MakeWH(100, 100);
706 SkPaint paint;
707 canvas->drawRect(bounds, paint);
708 canvas->drawRect(bounds, paint);
reedca2622b2016-03-18 07:25:55 -0700709 sk_sp<SkPicture> p(recorder.finishRecordingAsPictureWithCull(bounds));
mtkleineedc3342015-07-08 08:26:39 -0700710 const SkBigPicture* picture = p->asSkBigPicture();
schenneyeeff8bb2015-07-07 14:27:10 -0700711 REPORTER_ASSERT(reporter, picture);
712
713 SkRect finalCullRect = picture->cullRect();
714 REPORTER_ASSERT(reporter, 0 == finalCullRect.fLeft);
715 REPORTER_ASSERT(reporter, 0 == finalCullRect.fTop);
716 REPORTER_ASSERT(reporter, 100 == finalCullRect.fBottom);
717 REPORTER_ASSERT(reporter, 100 == finalCullRect.fRight);
718
719 const SkBBoxHierarchy* pictureBBH = picture->bbh();
720 SkRect bbhCullRect = pictureBBH->getRootBound();
721 REPORTER_ASSERT(reporter, 0 == bbhCullRect.fLeft);
722 REPORTER_ASSERT(reporter, 0 == bbhCullRect.fTop);
723 REPORTER_ASSERT(reporter, 100 == bbhCullRect.fBottom);
724 REPORTER_ASSERT(reporter, 100 == bbhCullRect.fRight);
725}
726
727
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000728/**
729 * A canvas that records the number of clip commands.
730 */
731class ClipCountingCanvas : public SkCanvas {
732public:
commit-bot@chromium.org6d3eaea2014-05-27 23:41:45 +0000733 ClipCountingCanvas(int width, int height)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000734 : INHERITED(width, height)
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000735 , fClipCount(0){
736 }
737
Mike Reedc1f77742016-12-09 09:00:50 -0500738 void onClipRect(const SkRect& r, SkClipOp op, ClipEdgeStyle edgeStyle) override {
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000739 fClipCount += 1;
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000740 this->INHERITED::onClipRect(r, op, edgeStyle);
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000741 }
742
Mike Reedc1f77742016-12-09 09:00:50 -0500743 void onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle)override {
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000744 fClipCount += 1;
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000745 this->INHERITED::onClipRRect(rrect, op, edgeStyle);
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000746 }
747
Mike Reedc1f77742016-12-09 09:00:50 -0500748 void onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) override {
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000749 fClipCount += 1;
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000750 this->INHERITED::onClipPath(path, op, edgeStyle);
751 }
752
Mike Reedc1f77742016-12-09 09:00:50 -0500753 void onClipRegion(const SkRegion& deviceRgn, SkClipOp op) override {
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000754 fClipCount += 1;
755 this->INHERITED::onClipRegion(deviceRgn, op);
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000756 }
757
758 unsigned getClipCount() const { return fClipCount; }
759
760private:
761 unsigned fClipCount;
762
763 typedef SkCanvas INHERITED;
764};
765
766static void test_clip_expansion(skiatest::Reporter* reporter) {
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000767 SkPictureRecorder recorder;
robertphillips9f1c2412014-06-09 06:25:34 -0700768 SkCanvas* canvas = recorder.beginRecording(10, 10);
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000769
Mike Reedc1f77742016-12-09 09:00:50 -0500770 canvas->clipRect(SkRect::MakeEmpty(), kReplace_SkClipOp);
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000771 // The following expanding clip should not be skipped.
Mike Reedc1f77742016-12-09 09:00:50 -0500772 canvas->clipRect(SkRect::MakeXYWH(4, 4, 3, 3), kUnion_SkClipOp);
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000773 // Draw something so the optimizer doesn't just fold the world.
774 SkPaint p;
775 p.setColor(SK_ColorBLUE);
776 canvas->drawPaint(p);
reedca2622b2016-03-18 07:25:55 -0700777 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000778
commit-bot@chromium.orge2543102014-01-31 19:42:58 +0000779 ClipCountingCanvas testCanvas(10, 10);
robertphillipsc5ba71d2014-09-04 08:42:50 -0700780 picture->playback(&testCanvas);
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000781
782 // Both clips should be present on playback.
783 REPORTER_ASSERT(reporter, testCanvas.getClipCount() == 2);
784}
785
tomhudson@google.com381010e2013-10-24 11:12:47 +0000786static void test_hierarchical(skiatest::Reporter* reporter) {
787 SkBitmap bm;
788 make_bm(&bm, 10, 10, SK_ColorRED, true);
789
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000790 SkPictureRecorder recorder;
tomhudson@google.com381010e2013-10-24 11:12:47 +0000791
robertphillips9f1c2412014-06-09 06:25:34 -0700792 recorder.beginRecording(10, 10);
reedca2622b2016-03-18 07:25:55 -0700793 sk_sp<SkPicture> childPlain(recorder.finishRecordingAsPicture());
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000794 REPORTER_ASSERT(reporter, !childPlain->willPlayBackBitmaps()); // 0
tomhudson@google.com381010e2013-10-24 11:12:47 +0000795
robertphillips9f1c2412014-06-09 06:25:34 -0700796 recorder.beginRecording(10, 10)->drawBitmap(bm, 0, 0);
reedca2622b2016-03-18 07:25:55 -0700797 sk_sp<SkPicture> childWithBitmap(recorder.finishRecordingAsPicture());
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000798 REPORTER_ASSERT(reporter, childWithBitmap->willPlayBackBitmaps()); // 1
tomhudson@google.com381010e2013-10-24 11:12:47 +0000799
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000800 {
robertphillips9f1c2412014-06-09 06:25:34 -0700801 SkCanvas* canvas = recorder.beginRecording(10, 10);
robertphillips9b14f262014-06-04 05:40:44 -0700802 canvas->drawPicture(childPlain);
reedca2622b2016-03-18 07:25:55 -0700803 sk_sp<SkPicture> parentPP(recorder.finishRecordingAsPicture());
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000804 REPORTER_ASSERT(reporter, !parentPP->willPlayBackBitmaps()); // 0
805 }
806 {
robertphillips9f1c2412014-06-09 06:25:34 -0700807 SkCanvas* canvas = recorder.beginRecording(10, 10);
robertphillips9b14f262014-06-04 05:40:44 -0700808 canvas->drawPicture(childWithBitmap);
reedca2622b2016-03-18 07:25:55 -0700809 sk_sp<SkPicture> parentPWB(recorder.finishRecordingAsPicture());
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000810 REPORTER_ASSERT(reporter, parentPWB->willPlayBackBitmaps()); // 1
811 }
812 {
robertphillips9f1c2412014-06-09 06:25:34 -0700813 SkCanvas* canvas = recorder.beginRecording(10, 10);
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000814 canvas->drawBitmap(bm, 0, 0);
robertphillips9b14f262014-06-04 05:40:44 -0700815 canvas->drawPicture(childPlain);
reedca2622b2016-03-18 07:25:55 -0700816 sk_sp<SkPicture> parentWBP(recorder.finishRecordingAsPicture());
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000817 REPORTER_ASSERT(reporter, parentWBP->willPlayBackBitmaps()); // 1
818 }
819 {
robertphillips9f1c2412014-06-09 06:25:34 -0700820 SkCanvas* canvas = recorder.beginRecording(10, 10);
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000821 canvas->drawBitmap(bm, 0, 0);
robertphillips9b14f262014-06-04 05:40:44 -0700822 canvas->drawPicture(childWithBitmap);
reedca2622b2016-03-18 07:25:55 -0700823 sk_sp<SkPicture> parentWBWB(recorder.finishRecordingAsPicture());
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000824 REPORTER_ASSERT(reporter, parentWBWB->willPlayBackBitmaps()); // 2
825 }
tomhudson@google.com381010e2013-10-24 11:12:47 +0000826}
827
robertphillips@google.comd5500882014-04-02 23:51:13 +0000828static void test_gen_id(skiatest::Reporter* reporter) {
829
Robert Phillipscfaeec42014-07-13 12:00:50 -0400830 SkPictureRecorder recorder;
831 recorder.beginRecording(0, 0);
reedca2622b2016-03-18 07:25:55 -0700832 sk_sp<SkPicture> empty(recorder.finishRecordingAsPicture());
robertphillips@google.comd5500882014-04-02 23:51:13 +0000833
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000834 // Empty pictures should still have a valid ID
Robert Phillipscfaeec42014-07-13 12:00:50 -0400835 REPORTER_ASSERT(reporter, empty->uniqueID() != SK_InvalidGenID);
robertphillips@google.comd5500882014-04-02 23:51:13 +0000836
robertphillips9f1c2412014-06-09 06:25:34 -0700837 SkCanvas* canvas = recorder.beginRecording(1, 1);
Mike Reed3661bc92017-02-22 13:21:42 -0500838 canvas->drawColor(SK_ColorWHITE);
reedca2622b2016-03-18 07:25:55 -0700839 sk_sp<SkPicture> hasData(recorder.finishRecordingAsPicture());
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000840 // picture should have a non-zero id after recording
841 REPORTER_ASSERT(reporter, hasData->uniqueID() != SK_InvalidGenID);
robertphillips@google.comd5500882014-04-02 23:51:13 +0000842
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000843 // both pictures should have different ids
Robert Phillipscfaeec42014-07-13 12:00:50 -0400844 REPORTER_ASSERT(reporter, hasData->uniqueID() != empty->uniqueID());
robertphillips@google.comd5500882014-04-02 23:51:13 +0000845}
846
caryclark5ef194c2015-08-31 09:22:38 -0700847static void test_typeface(skiatest::Reporter* reporter) {
848 SkPictureRecorder recorder;
849 SkCanvas* canvas = recorder.beginRecording(10, 10);
850 SkPaint paint;
mbocee6a9912016-05-31 11:42:36 -0700851 paint.setTypeface(SkTypeface::MakeFromName("Arial",
852 SkFontStyle::FromOldStyle(SkTypeface::kItalic)));
Cary Clark2a475ea2017-04-28 15:35:12 -0400853 canvas->drawString("Q", 0, 10, paint);
reedca2622b2016-03-18 07:25:55 -0700854 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
caryclark5ef194c2015-08-31 09:22:38 -0700855 SkDynamicMemoryWStream stream;
856 picture->serialize(&stream);
857}
858
tfarina@chromium.orge4fafb12013-12-12 21:11:12 +0000859DEF_TEST(Picture, reporter) {
caryclark5ef194c2015-08-31 09:22:38 -0700860 test_typeface(reporter);
scroggo@google.comd614c6a2012-09-14 17:26:37 +0000861#ifdef SK_DEBUG
robertphillipsdb539902014-07-01 08:47:04 -0700862 test_deleting_empty_picture();
scroggo@google.comd614c6a2012-09-14 17:26:37 +0000863 test_serializing_empty_picture();
scroggo@google.com4b90b112012-12-04 15:08:56 +0000864#else
865 test_bad_bitmap();
scroggo@google.comd614c6a2012-09-14 17:26:37 +0000866#endif
commit-bot@chromium.orgea7d08e2014-02-13 16:00:51 +0000867 test_unbalanced_save_restores(reporter);
sugoi@google.com54f0d1b2013-02-27 19:17:41 +0000868 test_peephole();
robertphillips@google.comb950c6f2014-04-25 00:02:12 +0000869#if SK_SUPPORT_GPU
mtklein8e126562014-10-01 09:29:35 -0700870 test_gpu_veto(reporter);
robertphillips@google.comb950c6f2014-04-25 00:02:12 +0000871#endif
mtkleina16af212015-08-26 08:14:52 -0700872 test_images_are_found_by_willPlayBackBitmaps(reporter);
mtklein8e126562014-10-01 09:29:35 -0700873 test_analysis(reporter);
junov@chromium.orgd575eed2013-05-08 15:39:13 +0000874 test_clip_bound_opt(reporter);
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000875 test_clip_expansion(reporter);
tomhudson@google.com381010e2013-10-24 11:12:47 +0000876 test_hierarchical(reporter);
robertphillips@google.comd5500882014-04-02 23:51:13 +0000877 test_gen_id(reporter);
schenneyeeff8bb2015-07-07 14:27:10 -0700878 test_cull_rect_reset(reporter);
scroggo@google.comd614c6a2012-09-14 17:26:37 +0000879}
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +0000880
881static void draw_bitmaps(const SkBitmap bitmap, SkCanvas* canvas) {
882 const SkPaint paint;
883 const SkRect rect = { 5.0f, 5.0f, 8.0f, 8.0f };
884 const SkIRect irect = { 2, 2, 3, 3 };
msarettc573a402016-08-02 08:05:56 -0700885 int divs[] = { 2, 3 };
886 SkCanvas::Lattice lattice;
887 lattice.fXCount = lattice.fYCount = 2;
888 lattice.fXDivs = lattice.fYDivs = divs;
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +0000889
890 // Don't care what these record, as long as they're legal.
891 canvas->drawBitmap(bitmap, 0.0f, 0.0f, &paint);
reede47829b2015-08-06 10:02:53 -0700892 canvas->drawBitmapRect(bitmap, rect, rect, &paint, SkCanvas::kStrict_SrcRectConstraint);
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +0000893 canvas->drawBitmapNine(bitmap, irect, rect, &paint);
reedda420b92015-12-16 08:38:15 -0800894 canvas->drawBitmap(bitmap, 1, 1); // drawSprite
msarettc573a402016-08-02 08:05:56 -0700895 canvas->drawBitmapLattice(bitmap, lattice, rect, &paint);
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +0000896}
897
898static void test_draw_bitmaps(SkCanvas* canvas) {
899 SkBitmap empty;
900 draw_bitmaps(empty, canvas);
commit-bot@chromium.orga3264e52014-05-30 13:26:10 +0000901 empty.setInfo(SkImageInfo::MakeN32Premul(10, 10));
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +0000902 draw_bitmaps(empty, canvas);
903}
904
905DEF_TEST(Picture_EmptyBitmap, r) {
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000906 SkPictureRecorder recorder;
robertphillips9f1c2412014-06-09 06:25:34 -0700907 test_draw_bitmaps(recorder.beginRecording(10, 10));
reedca2622b2016-03-18 07:25:55 -0700908 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +0000909}
910
911DEF_TEST(Canvas_EmptyBitmap, r) {
912 SkBitmap dst;
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +0000913 dst.allocN32Pixels(10, 10);
commit-bot@chromium.org50b393a2014-02-10 18:29:10 +0000914 SkCanvas canvas(dst);
915
916 test_draw_bitmaps(&canvas);
917}
dneto3f22e8c2014-07-30 15:42:22 -0700918
919DEF_TEST(DontOptimizeSaveLayerDrawDrawRestore, reporter) {
920 // This test is from crbug.com/344987.
921 // The commands are:
922 // saveLayer with paint that modifies alpha
reed84984ef2015-07-17 07:09:43 -0700923 // drawBitmapRect
924 // drawBitmapRect
dneto3f22e8c2014-07-30 15:42:22 -0700925 // restore
926 // The bug was that this structure was modified so that:
927 // - The saveLayer and restore were eliminated
928 // - The alpha was only applied to the first drawBitmapRectToRect
929
930 // This test draws blue and red squares inside a 50% transparent
931 // layer. Both colours should show up muted.
932 // When the bug is present, the red square (the second bitmap)
933 // shows upwith full opacity.
934
935 SkBitmap blueBM;
936 make_bm(&blueBM, 100, 100, SkColorSetARGB(255, 0, 0, 255), true);
937 SkBitmap redBM;
938 make_bm(&redBM, 100, 100, SkColorSetARGB(255, 255, 0, 0), true);
939 SkPaint semiTransparent;
940 semiTransparent.setAlpha(0x80);
941
942 SkPictureRecorder recorder;
943 SkCanvas* canvas = recorder.beginRecording(100, 100);
Mike Reed3661bc92017-02-22 13:21:42 -0500944 canvas->drawColor(0);
dneto3f22e8c2014-07-30 15:42:22 -0700945
946 canvas->saveLayer(0, &semiTransparent);
947 canvas->drawBitmap(blueBM, 25, 25);
948 canvas->drawBitmap(redBM, 50, 50);
949 canvas->restore();
950
reedca2622b2016-03-18 07:25:55 -0700951 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
dneto3f22e8c2014-07-30 15:42:22 -0700952
953 // Now replay the picture back on another canvas
954 // and check a couple of its pixels.
955 SkBitmap replayBM;
956 make_bm(&replayBM, 100, 100, SK_ColorBLACK, false);
957 SkCanvas replayCanvas(replayBM);
robertphillipsc5ba71d2014-09-04 08:42:50 -0700958 picture->playback(&replayCanvas);
dneto3f22e8c2014-07-30 15:42:22 -0700959 replayCanvas.flush();
960
961 // With the bug present, at (55, 55) we would get a fully opaque red
962 // intead of a dark red.
963 REPORTER_ASSERT(reporter, replayBM.getColor(30, 30) == 0xff000080);
964 REPORTER_ASSERT(reporter, replayBM.getColor(55, 55) == 0xff800000);
965}
mtklein3e8232b2014-08-18 13:39:11 -0700966
967struct CountingBBH : public SkBBoxHierarchy {
968 mutable int searchCalls;
schenney23d85932015-03-06 16:20:28 -0800969 SkRect rootBound;
mtklein3e8232b2014-08-18 13:39:11 -0700970
schenney23d85932015-03-06 16:20:28 -0800971 CountingBBH(const SkRect& bound) : searchCalls(0), rootBound(bound) {}
mtklein3e8232b2014-08-18 13:39:11 -0700972
mtkleinc6ad06a2015-08-19 09:51:00 -0700973 void search(const SkRect& query, SkTDArray<int>* results) const override {
mtklein3e8232b2014-08-18 13:39:11 -0700974 this->searchCalls++;
975 }
976
mtklein36352bf2015-03-25 18:17:31 -0700977 void insert(const SkRect[], int) override {}
978 virtual size_t bytesUsed() const override { return 0; }
979 SkRect getRootBound() const override { return rootBound; }
mtklein3e8232b2014-08-18 13:39:11 -0700980};
981
982class SpoonFedBBHFactory : public SkBBHFactory {
983public:
984 explicit SpoonFedBBHFactory(SkBBoxHierarchy* bbh) : fBBH(bbh) {}
mtklein36352bf2015-03-25 18:17:31 -0700985 SkBBoxHierarchy* operator()(const SkRect&) const override {
mtklein3e8232b2014-08-18 13:39:11 -0700986 return SkRef(fBBH);
987 }
988private:
989 SkBBoxHierarchy* fBBH;
990};
991
992// When the canvas clip covers the full picture, we don't need to call the BBH.
993DEF_TEST(Picture_SkipBBH, r) {
schenney23d85932015-03-06 16:20:28 -0800994 SkRect bound = SkRect::MakeWH(320, 240);
995 CountingBBH bbh(bound);
mtklein3e8232b2014-08-18 13:39:11 -0700996 SpoonFedBBHFactory factory(&bbh);
997
998 SkPictureRecorder recorder;
mtklein9db912c2015-05-19 11:11:26 -0700999 SkCanvas* c = recorder.beginRecording(bound, &factory);
1000 // Record a few ops so we don't hit a small- or empty- picture optimization.
1001 c->drawRect(bound, SkPaint());
1002 c->drawRect(bound, SkPaint());
reedca2622b2016-03-18 07:25:55 -07001003 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
mtklein3e8232b2014-08-18 13:39:11 -07001004
1005 SkCanvas big(640, 480), small(300, 200);
1006
robertphillipsc5ba71d2014-09-04 08:42:50 -07001007 picture->playback(&big);
mtklein3e8232b2014-08-18 13:39:11 -07001008 REPORTER_ASSERT(r, bbh.searchCalls == 0);
1009
robertphillipsc5ba71d2014-09-04 08:42:50 -07001010 picture->playback(&small);
mtklein3e8232b2014-08-18 13:39:11 -07001011 REPORTER_ASSERT(r, bbh.searchCalls == 1);
1012}
mtkleind72094d2014-08-27 12:12:23 -07001013
1014DEF_TEST(Picture_BitmapLeak, r) {
1015 SkBitmap mut, immut;
1016 mut.allocN32Pixels(300, 200);
1017 immut.allocN32Pixels(300, 200);
1018 immut.setImmutable();
1019 SkASSERT(!mut.isImmutable());
1020 SkASSERT(immut.isImmutable());
1021
1022 // No one can hold a ref on our pixels yet.
1023 REPORTER_ASSERT(r, mut.pixelRef()->unique());
1024 REPORTER_ASSERT(r, immut.pixelRef()->unique());
1025
reedca2622b2016-03-18 07:25:55 -07001026 sk_sp<SkPicture> pic;
reed1bdfd3f2014-11-24 14:41:51 -08001027 {
1028 // we want the recorder to go out of scope before our subsequent checks, so we
1029 // place it inside local braces.
1030 SkPictureRecorder rec;
1031 SkCanvas* canvas = rec.beginRecording(1920, 1200);
1032 canvas->drawBitmap(mut, 0, 0);
1033 canvas->drawBitmap(immut, 800, 600);
reedca2622b2016-03-18 07:25:55 -07001034 pic = rec.finishRecordingAsPicture();
reed1bdfd3f2014-11-24 14:41:51 -08001035 }
mtkleind72094d2014-08-27 12:12:23 -07001036
1037 // The picture shares the immutable pixels but copies the mutable ones.
1038 REPORTER_ASSERT(r, mut.pixelRef()->unique());
1039 REPORTER_ASSERT(r, !immut.pixelRef()->unique());
1040
1041 // When the picture goes away, it's just our bitmaps holding the refs.
reedca2622b2016-03-18 07:25:55 -07001042 pic = nullptr;
mtkleind72094d2014-08-27 12:12:23 -07001043 REPORTER_ASSERT(r, mut.pixelRef()->unique());
1044 REPORTER_ASSERT(r, immut.pixelRef()->unique());
1045}
mtkleinfeaadee2015-04-08 11:25:48 -07001046
1047// getRecordingCanvas() should return a SkCanvas when recording, null when not recording.
1048DEF_TEST(Picture_getRecordingCanvas, r) {
1049 SkPictureRecorder rec;
1050 REPORTER_ASSERT(r, !rec.getRecordingCanvas());
1051 for (int i = 0; i < 3; i++) {
1052 rec.beginRecording(100, 100);
1053 REPORTER_ASSERT(r, rec.getRecordingCanvas());
reedca2622b2016-03-18 07:25:55 -07001054 rec.finishRecordingAsPicture();
mtkleinfeaadee2015-04-08 11:25:48 -07001055 REPORTER_ASSERT(r, !rec.getRecordingCanvas());
1056 }
1057}
mtklein9db912c2015-05-19 11:11:26 -07001058
1059DEF_TEST(MiniRecorderLeftHanging, r) {
1060 // Any shader or other ref-counted effect will do just fine here.
1061 SkPaint paint;
reed1a9b9642016-03-13 14:13:58 -07001062 paint.setShader(SkShader::MakeColorShader(SK_ColorRED));
mtklein9db912c2015-05-19 11:11:26 -07001063
1064 SkMiniRecorder rec;
1065 REPORTER_ASSERT(r, rec.drawRect(SkRect::MakeWH(20,30), paint));
1066 // Don't call rec.detachPicture(). Test succeeds by not asserting or leaking the shader.
1067}
fmalita2ecc0002015-07-14 13:12:25 -07001068
1069DEF_TEST(Picture_preserveCullRect, r) {
1070 SkPictureRecorder recorder;
1071
1072 SkCanvas* c = recorder.beginRecording(SkRect::MakeLTRB(1, 2, 3, 4));
1073 c->clear(SK_ColorCYAN);
1074
reedca2622b2016-03-18 07:25:55 -07001075 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
fmalita2ecc0002015-07-14 13:12:25 -07001076 SkDynamicMemoryWStream wstream;
1077 picture->serialize(&wstream);
1078
Ben Wagner145dbcd2016-11-03 14:40:50 -04001079 std::unique_ptr<SkStream> rstream(wstream.detachAsStream());
1080 sk_sp<SkPicture> deserializedPicture(SkPicture::MakeFromStream(rstream.get()));
fmalita2ecc0002015-07-14 13:12:25 -07001081
mtklein5f939ab2016-03-16 10:28:35 -07001082 REPORTER_ASSERT(r, deserializedPicture != nullptr);
fmalita2ecc0002015-07-14 13:12:25 -07001083 REPORTER_ASSERT(r, deserializedPicture->cullRect().left() == 1);
1084 REPORTER_ASSERT(r, deserializedPicture->cullRect().top() == 2);
1085 REPORTER_ASSERT(r, deserializedPicture->cullRect().right() == 3);
1086 REPORTER_ASSERT(r, deserializedPicture->cullRect().bottom() == 4);
1087}
fmalita796e3652016-05-13 11:40:07 -07001088
1089#if SK_SUPPORT_GPU
1090
1091DEF_TEST(PictureGpuAnalyzer, r) {
1092 SkPictureRecorder recorder;
1093
1094 {
1095 SkCanvas* canvas = recorder.beginRecording(10, 10);
1096 SkPaint paint;
1097 SkScalar intervals [] = { 10, 20 };
1098 paint.setPathEffect(SkDashPathEffect::Make(intervals, 2, 25));
1099
1100 for (int i = 0; i < 50; ++i) {
1101 canvas->drawRect(SkRect::MakeWH(10, 10), paint);
1102 }
1103 }
1104 sk_sp<SkPicture> vetoPicture(recorder.finishRecordingAsPicture());
1105
1106 SkPictureGpuAnalyzer analyzer;
1107 REPORTER_ASSERT(r, analyzer.suitableForGpuRasterization());
1108
fmalita019db3f2016-05-31 06:32:57 -07001109 analyzer.analyzePicture(vetoPicture.get());
fmalita796e3652016-05-13 11:40:07 -07001110 REPORTER_ASSERT(r, !analyzer.suitableForGpuRasterization());
1111
1112 analyzer.reset();
1113 REPORTER_ASSERT(r, analyzer.suitableForGpuRasterization());
1114
1115 recorder.beginRecording(10, 10)->drawPicture(vetoPicture);
1116 sk_sp<SkPicture> nestedVetoPicture(recorder.finishRecordingAsPicture());
1117
fmalita019db3f2016-05-31 06:32:57 -07001118 analyzer.analyzePicture(nestedVetoPicture.get());
fmalita796e3652016-05-13 11:40:07 -07001119 REPORTER_ASSERT(r, !analyzer.suitableForGpuRasterization());
fmalitab5fc58e2016-05-25 11:31:04 -07001120
1121 analyzer.reset();
1122
1123 const SkPath convexClip = make_convex_path();
1124 const SkPath concaveClip = make_concave_path();
1125 for (int i = 0; i < 50; ++i) {
Mike Reedc1f77742016-12-09 09:00:50 -05001126 analyzer.analyzeClipPath(convexClip, kIntersect_SkClipOp, false);
1127 analyzer.analyzeClipPath(convexClip, kIntersect_SkClipOp, true);
1128 analyzer.analyzeClipPath(concaveClip, kIntersect_SkClipOp, false);
fmalitab5fc58e2016-05-25 11:31:04 -07001129 }
1130 REPORTER_ASSERT(r, analyzer.suitableForGpuRasterization());
1131
1132 for (int i = 0; i < 50; ++i) {
Mike Reedc1f77742016-12-09 09:00:50 -05001133 analyzer.analyzeClipPath(concaveClip, kIntersect_SkClipOp, true);
fmalitab5fc58e2016-05-25 11:31:04 -07001134 }
1135 REPORTER_ASSERT(r, !analyzer.suitableForGpuRasterization());
fmalita796e3652016-05-13 11:40:07 -07001136}
1137
1138#endif // SK_SUPPORT_GPU
Mike Klein26eb16f2017-04-10 09:50:25 -04001139
1140// If we record bounded ops into a picture with a big cull and calculate the
1141// bounds of those ops, we should trim down the picture cull to the ops' bounds.
1142// If we're not using an SkBBH, we shouldn't change it.
1143DEF_TEST(Picture_UpdatedCull_1, r) {
1144 // Testing 1 draw exercises SkMiniPicture.
1145 SkRTreeFactory factory;
1146 SkPictureRecorder recorder;
1147
1148 auto canvas = recorder.beginRecording(SkRect::MakeLargest(), &factory);
1149 canvas->drawRect(SkRect::MakeWH(20,20), SkPaint{});
1150 auto pic = recorder.finishRecordingAsPicture();
1151 REPORTER_ASSERT(r, pic->cullRect() == SkRect::MakeWH(20,20));
1152
1153 canvas = recorder.beginRecording(SkRect::MakeLargest());
1154 canvas->drawRect(SkRect::MakeWH(20,20), SkPaint{});
1155 pic = recorder.finishRecordingAsPicture();
1156 REPORTER_ASSERT(r, pic->cullRect() == SkRect::MakeLargest());
1157}
1158DEF_TEST(Picture_UpdatedCull_2, r) {
1159 // Testing >1 draw exercises SkBigPicture.
1160 SkRTreeFactory factory;
1161 SkPictureRecorder recorder;
1162
1163 auto canvas = recorder.beginRecording(SkRect::MakeLargest(), &factory);
1164 canvas->drawRect(SkRect::MakeWH(20,20), SkPaint{});
1165 canvas->drawRect(SkRect::MakeWH(10,40), SkPaint{});
1166 auto pic = recorder.finishRecordingAsPicture();
1167 REPORTER_ASSERT(r, pic->cullRect() == SkRect::MakeWH(20,40));
1168
1169 canvas = recorder.beginRecording(SkRect::MakeLargest());
1170 canvas->drawRect(SkRect::MakeWH(20,20), SkPaint{});
1171 canvas->drawRect(SkRect::MakeWH(10,40), SkPaint{});
1172 pic = recorder.finishRecordingAsPicture();
1173 REPORTER_ASSERT(r, pic->cullRect() == SkRect::MakeLargest());
1174}