blob: 23ff6893c0f4d867fb7d1754c5ba6e75d1e2d99f [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 */
7#include "Test.h"
reed@google.com21b519d2012-10-02 17:42:15 +00008#include "SkCanvas.h"
reed@google.comfe7b1ed2012-11-29 21:00:39 +00009#include "SkColorPriv.h"
10#include "SkData.h"
scroggo@google.com49ce11b2013-04-25 18:29:32 +000011#include "SkError.h"
reed@google.com21b519d2012-10-02 17:42:15 +000012#include "SkPaint.h"
scroggo@google.comd614c6a2012-09-14 17:26:37 +000013#include "SkPicture.h"
reed@google.com21b519d2012-10-02 17:42:15 +000014#include "SkRandom.h"
reed@google.com72aa79c2013-01-24 18:27:42 +000015#include "SkRRect.h"
reed@google.comfe7b1ed2012-11-29 21:00:39 +000016#include "SkShader.h"
scroggo@google.comd614c6a2012-09-14 17:26:37 +000017#include "SkStream.h"
18
reed@google.comfe7b1ed2012-11-29 21:00:39 +000019#include "SkPictureUtils.h"
20
21static void make_bm(SkBitmap* bm, int w, int h, SkColor color, bool immutable) {
22 bm->setConfig(SkBitmap::kARGB_8888_Config, w, h);
23 bm->allocPixels();
24 bm->eraseColor(color);
25 if (immutable) {
26 bm->setImmutable();
27 }
28}
29
30typedef void (*DrawBitmapProc)(SkCanvas*, const SkBitmap&, const SkPoint&);
31
32static void drawbitmap_proc(SkCanvas* canvas, const SkBitmap& bm,
33 const SkPoint& pos) {
34 canvas->drawBitmap(bm, pos.fX, pos.fY, NULL);
35}
36
37static void drawbitmaprect_proc(SkCanvas* canvas, const SkBitmap& bm,
38 const SkPoint& pos) {
39 SkRect r = {
40 0, 0, SkIntToScalar(bm.width()), SkIntToScalar(bm.height())
41 };
42 r.offset(pos.fX, pos.fY);
43 canvas->drawBitmapRectToRect(bm, NULL, r, NULL);
44}
45
46static void drawshader_proc(SkCanvas* canvas, const SkBitmap& bm,
47 const SkPoint& pos) {
48 SkRect r = {
49 0, 0, SkIntToScalar(bm.width()), SkIntToScalar(bm.height())
50 };
51 r.offset(pos.fX, pos.fY);
52
53 SkShader* s = SkShader::CreateBitmapShader(bm,
54 SkShader::kClamp_TileMode,
55 SkShader::kClamp_TileMode);
56 SkPaint paint;
57 paint.setShader(s)->unref();
58 canvas->drawRect(r, paint);
reed@google.com72aa79c2013-01-24 18:27:42 +000059 canvas->drawOval(r, paint);
60 SkRRect rr;
61 rr.setRectXY(r, 10, 10);
62 canvas->drawRRect(rr, paint);
reed@google.comfe7b1ed2012-11-29 21:00:39 +000063}
64
65// Return a picture with the bitmaps drawn at the specified positions.
66static SkPicture* record_bitmaps(const SkBitmap bm[], const SkPoint pos[],
67 int count, DrawBitmapProc proc) {
68 SkPicture* pic = new SkPicture;
69 SkCanvas* canvas = pic->beginRecording(1000, 1000);
70 for (int i = 0; i < count; ++i) {
71 proc(canvas, bm[i], pos[i]);
72 }
73 pic->endRecording();
74 return pic;
75}
76
jvanverth@google.comc490f802013-03-04 13:56:38 +000077static void rand_rect(SkRect* rect, SkMWCRandom& rand, SkScalar W, SkScalar H) {
reed@google.comfe7b1ed2012-11-29 21:00:39 +000078 rect->fLeft = rand.nextRangeScalar(-W, 2*W);
79 rect->fTop = rand.nextRangeScalar(-H, 2*H);
80 rect->fRight = rect->fLeft + rand.nextRangeScalar(0, W);
81 rect->fBottom = rect->fTop + rand.nextRangeScalar(0, H);
82
83 // we integralize rect to make our tests more predictable, since Gather is
84 // a little sloppy.
85 SkIRect ir;
86 rect->round(&ir);
87 rect->set(ir);
88}
89
90// Allocate result to be large enough to hold subset, and then draw the picture
91// into it, offsetting by subset's top/left corner.
92static void draw(SkPicture* pic, const SkRect& subset, SkBitmap* result) {
93 SkIRect ir;
94 subset.roundOut(&ir);
95 int w = ir.width();
96 int h = ir.height();
97 make_bm(result, w, h, 0, false);
98
99 SkCanvas canvas(*result);
100 canvas.translate(-SkIntToScalar(ir.left()), -SkIntToScalar(ir.top()));
101 canvas.drawPicture(*pic);
102}
103
104template <typename T> int find_index(const T* array, T elem, int count) {
105 for (int i = 0; i < count; ++i) {
106 if (array[i] == elem) {
107 return i;
108 }
109 }
110 return -1;
111}
112
113// Return true if 'ref' is found in array[]
114static bool find(SkPixelRef const * const * array, SkPixelRef const * ref, int count) {
115 return find_index<const SkPixelRef*>(array, ref, count) >= 0;
116}
117
118// Look at each pixel in bm, and if its color appears in colors[], find the
119// corresponding value in refs[] and append that ref into array, skipping
120// duplicates of the same value.
121static void gather_from_colors(const SkBitmap& bm, SkPixelRef* const refs[],
122 int count, SkTDArray<SkPixelRef*>* array) {
123 // Since we only want to return unique values in array, when we scan we just
124 // set a bit for each index'd color found. In practice we only have a few
125 // distinct colors, so we just use an int's bits as our array. Hence the
126 // assert that count <= number-of-bits-in-our-int.
127 SkASSERT((unsigned)count <= 32);
128 uint32_t bitarray = 0;
129
130 SkAutoLockPixels alp(bm);
131
132 for (int y = 0; y < bm.height(); ++y) {
133 for (int x = 0; x < bm.width(); ++x) {
134 SkPMColor pmc = *bm.getAddr32(x, y);
135 // the only good case where the color is not found would be if
136 // the color is transparent, meaning no bitmap was drawn in that
137 // pixel.
138 if (pmc) {
bsalomon@google.comc3d753e2013-01-08 17:24:44 +0000139 uint32_t index = SkGetPackedR32(pmc);
reed@google.comfe7b1ed2012-11-29 21:00:39 +0000140 SkASSERT(SkGetPackedG32(pmc) == index);
141 SkASSERT(SkGetPackedB32(pmc) == index);
bsalomon@google.com5f429b02013-01-08 18:42:20 +0000142 SkASSERT(static_cast<int>(index) < count);
reed@google.comfe7b1ed2012-11-29 21:00:39 +0000143 bitarray |= 1 << index;
144 }
145 }
146 }
147
148 for (int i = 0; i < count; ++i) {
149 if (bitarray & (1 << i)) {
150 *array->append() = refs[i];
151 }
152 }
153}
154
155static void test_gatherpixelrefs(skiatest::Reporter* reporter) {
156 const int IW = 8;
157 const int IH = IW;
158 const SkScalar W = SkIntToScalar(IW);
159 const SkScalar H = W;
160
161 static const int N = 4;
162 SkBitmap bm[N];
reed@google.comfe7b1ed2012-11-29 21:00:39 +0000163 SkPixelRef* refs[N];
164
165 const SkPoint pos[] = {
166 { 0, 0 }, { W, 0 }, { 0, H }, { W, H }
167 };
168
169 // Our convention is that the color components contain the index of their
170 // corresponding bitmap/pixelref
171 for (int i = 0; i < N; ++i) {
172 make_bm(&bm[i], IW, IH, SkColorSetARGB(0xFF, i, i, i), true);
173 refs[i] = bm[i].pixelRef();
174 }
175
176 static const DrawBitmapProc procs[] = {
177 drawbitmap_proc, drawbitmaprect_proc, drawshader_proc
178 };
179
jvanverth@google.comc490f802013-03-04 13:56:38 +0000180 SkMWCRandom rand;
reed@google.comfe7b1ed2012-11-29 21:00:39 +0000181 for (size_t k = 0; k < SK_ARRAY_COUNT(procs); ++k) {
182 SkAutoTUnref<SkPicture> pic(record_bitmaps(bm, pos, N, procs[k]));
183
184 // quick check for a small piece of each quadrant, which should just
185 // contain 1 bitmap.
186 for (size_t i = 0; i < SK_ARRAY_COUNT(pos); ++i) {
187 SkRect r;
188 r.set(2, 2, W - 2, H - 2);
189 r.offset(pos[i].fX, pos[i].fY);
190 SkAutoDataUnref data(SkPictureUtils::GatherPixelRefs(pic, r));
191 REPORTER_ASSERT(reporter, data);
192 int count = data->size() / sizeof(SkPixelRef*);
193 REPORTER_ASSERT(reporter, 1 == count);
194 REPORTER_ASSERT(reporter, *(SkPixelRef**)data->data() == refs[i]);
195 }
196
197 // Test a bunch of random (mostly) rects, and compare the gather results
198 // with a deduced list of refs by looking at the colors drawn.
199 for (int j = 0; j < 100; ++j) {
200 SkRect r;
201 rand_rect(&r, rand, 2*W, 2*H);
202
203 SkBitmap result;
204 draw(pic, r, &result);
205 SkTDArray<SkPixelRef*> array;
206
207 SkData* data = SkPictureUtils::GatherPixelRefs(pic, r);
208 size_t dataSize = data ? data->size() : 0;
209 int gatherCount = dataSize / sizeof(SkPixelRef*);
210 SkASSERT(gatherCount * sizeof(SkPixelRef*) == dataSize);
211 SkPixelRef** gatherRefs = data ? (SkPixelRef**)(data->data()) : NULL;
212 SkAutoDataUnref adu(data);
213
214 gather_from_colors(result, refs, N, &array);
skia.committer@gmail.comc3d7d902012-11-30 02:01:24 +0000215
reed@google.comfe7b1ed2012-11-29 21:00:39 +0000216 /*
217 * GatherPixelRefs is conservative, so it can return more bitmaps
218 * that we actually can see (usually because of conservative bounds
219 * inflation for antialiasing). Thus our check here is only that
220 * Gather didn't miss any that we actually saw. Even that isn't
221 * a strict requirement on Gather, which is meant to be quick and
222 * only mostly-correct, but at the moment this test should work.
223 */
224 for (int i = 0; i < array.count(); ++i) {
225 bool found = find(gatherRefs, array[i], gatherCount);
226 REPORTER_ASSERT(reporter, found);
227#if 0
228 // enable this block of code to debug failures, as it will rerun
229 // the case that failed.
230 if (!found) {
231 SkData* data = SkPictureUtils::GatherPixelRefs(pic, r);
232 size_t dataSize = data ? data->size() : 0;
233 }
234#endif
235 }
236 }
237 }
238}
239
scroggo@google.comd614c6a2012-09-14 17:26:37 +0000240#ifdef SK_DEBUG
241// Ensure that deleting SkPicturePlayback does not assert. Asserts only fire in debug mode, so only
242// run in debug mode.
243static void test_deleting_empty_playback() {
244 SkPicture picture;
245 // Creates an SkPictureRecord
246 picture.beginRecording(0, 0);
247 // Turns that into an SkPicturePlayback
248 picture.endRecording();
249 // Deletes the old SkPicturePlayback, and creates a new SkPictureRecord
250 picture.beginRecording(0, 0);
251}
252
253// Ensure that serializing an empty picture does not assert. Likewise only runs in debug mode.
254static void test_serializing_empty_picture() {
255 SkPicture picture;
256 picture.beginRecording(0, 0);
257 picture.endRecording();
258 SkDynamicMemoryWStream stream;
259 picture.serialize(&stream);
260}
261#endif
262
jvanverth@google.comc490f802013-03-04 13:56:38 +0000263static void rand_op(SkCanvas* canvas, SkMWCRandom& rand) {
reed@google.com21b519d2012-10-02 17:42:15 +0000264 SkPaint paint;
265 SkRect rect = SkRect::MakeWH(50, 50);
266
267 SkScalar unit = rand.nextUScalar1();
268 if (unit <= 0.3) {
269// SkDebugf("save\n");
270 canvas->save();
271 } else if (unit <= 0.6) {
272// SkDebugf("restore\n");
273 canvas->restore();
274 } else if (unit <= 0.9) {
275// SkDebugf("clip\n");
276 canvas->clipRect(rect);
277 } else {
278// SkDebugf("draw\n");
279 canvas->drawPaint(paint);
280 }
281}
282
sugoi@google.com54f0d1b2013-02-27 19:17:41 +0000283static void test_peephole() {
jvanverth@google.comc490f802013-03-04 13:56:38 +0000284 SkMWCRandom rand;
reed@google.com21b519d2012-10-02 17:42:15 +0000285
286 for (int j = 0; j < 100; j++) {
jvanverth@google.comc490f802013-03-04 13:56:38 +0000287 SkMWCRandom rand2(rand); // remember the seed
reed@google.com21b519d2012-10-02 17:42:15 +0000288
289 SkPicture picture;
290 SkCanvas* canvas = picture.beginRecording(100, 100);
291
292 for (int i = 0; i < 1000; ++i) {
293 rand_op(canvas, rand);
294 }
295 picture.endRecording();
jvanverth@google.comc490f802013-03-04 13:56:38 +0000296
297 rand = rand2;
reed@google.com21b519d2012-10-02 17:42:15 +0000298 }
299
300 {
301 SkPicture picture;
302 SkCanvas* canvas = picture.beginRecording(100, 100);
303 SkRect rect = SkRect::MakeWH(50, 50);
skia.committer@gmail.com52c24372012-10-03 02:01:13 +0000304
reed@google.com21b519d2012-10-02 17:42:15 +0000305 for (int i = 0; i < 100; ++i) {
306 canvas->save();
307 }
308 while (canvas->getSaveCount() > 1) {
309 canvas->clipRect(rect);
310 canvas->restore();
311 }
312 picture.endRecording();
313 }
314}
315
scroggo@google.com4b90b112012-12-04 15:08:56 +0000316#ifndef SK_DEBUG
317// Only test this is in release mode. We deliberately crash in debug mode, since a valid caller
318// should never do this.
319static void test_bad_bitmap() {
320 // This bitmap has a width and height but no pixels. As a result, attempting to record it will
321 // fail.
322 SkBitmap bm;
323 bm.setConfig(SkBitmap::kARGB_8888_Config, 100, 100);
324 SkPicture picture;
325 SkCanvas* recordingCanvas = picture.beginRecording(100, 100);
326 recordingCanvas->drawBitmap(bm, 0, 0);
327 picture.endRecording();
328
329 SkCanvas canvas;
330 canvas.drawPicture(picture);
331}
332#endif
333
scroggo@google.com7c9d5392012-12-10 15:40:55 +0000334#include "SkData.h"
335#include "SkImageRef_GlobalPool.h"
336// Class to test SkPixelRef::onRefEncodedData, since there are currently no implementations in skia.
337class SkDataImageRef : public SkImageRef_GlobalPool {
338
339public:
340 SkDataImageRef(SkMemoryStream* stream)
341 : SkImageRef_GlobalPool(stream, SkBitmap::kNo_Config) {
342 SkASSERT(stream != NULL);
343 fData = stream->copyToData();
344 this->setImmutable();
345 }
346
347 ~SkDataImageRef() {
348 fData->unref();
349 }
350
351 virtual SkData* onRefEncodedData() SK_OVERRIDE {
352 fData->ref();
353 return fData;
354 }
355
356private:
357 SkData* fData;
358};
359
360#include "SkImageEncoder.h"
361
scroggo@google.com1b1bcc32013-05-21 20:31:23 +0000362static SkData* encode_bitmap_to_data(size_t* offset, const SkBitmap& bm) {
363 *offset = 0;
364 return SkImageEncoder::EncodeData(bm, SkImageEncoder::kPNG_Type, 100);
scroggo@google.com7c9d5392012-12-10 15:40:55 +0000365}
366
367static SkData* serialized_picture_from_bitmap(const SkBitmap& bitmap) {
368 SkPicture picture;
369 SkCanvas* canvas = picture.beginRecording(bitmap.width(), bitmap.height());
370 canvas->drawBitmap(bitmap, 0, 0);
371 SkDynamicMemoryWStream wStream;
scroggo@google.com1b1bcc32013-05-21 20:31:23 +0000372 picture.serialize(&wStream, &encode_bitmap_to_data);
scroggo@google.com7c9d5392012-12-10 15:40:55 +0000373 return wStream.copyToData();
374}
375
scroggo@google.com49ce11b2013-04-25 18:29:32 +0000376struct ErrorContext {
377 int fErrors;
378 skiatest::Reporter* fReporter;
379};
380
381static void assert_one_parse_error_cb(SkError error, void* context) {
382 ErrorContext* errorContext = static_cast<ErrorContext*>(context);
383 errorContext->fErrors++;
384 // This test only expects one error, and that is a kParseError. If there are others,
385 // there is some unknown problem.
386 REPORTER_ASSERT_MESSAGE(errorContext->fReporter, 1 == errorContext->fErrors,
387 "This threw more errors than expected.");
388 REPORTER_ASSERT_MESSAGE(errorContext->fReporter, kParseError_SkError == error,
389 SkGetLastErrorString());
390}
391
scroggo@google.com7c9d5392012-12-10 15:40:55 +0000392static void test_bitmap_with_encoded_data(skiatest::Reporter* reporter) {
393 // Create a bitmap that will be encoded.
394 SkBitmap original;
395 make_bm(&original, 100, 100, SK_ColorBLUE, true);
396 SkDynamicMemoryWStream wStream;
397 if (!SkImageEncoder::EncodeStream(&wStream, original, SkImageEncoder::kPNG_Type, 100)) {
398 return;
399 }
400 SkAutoDataUnref data(wStream.copyToData());
401 SkMemoryStream memStream;
402 memStream.setData(data);
403
404 // Use the encoded bitmap as the data for an image ref.
405 SkBitmap bm;
406 SkAutoTUnref<SkDataImageRef> imageRef(SkNEW_ARGS(SkDataImageRef, (&memStream)));
407 imageRef->getInfo(&bm);
408 bm.setPixelRef(imageRef);
409
410 // Write both bitmaps to pictures, and ensure that the resulting data streams are the same.
411 // Flattening original will follow the old path of performing an encode, while flattening bm
412 // will use the already encoded data.
413 SkAutoDataUnref picture1(serialized_picture_from_bitmap(original));
414 SkAutoDataUnref picture2(serialized_picture_from_bitmap(bm));
415 REPORTER_ASSERT(reporter, picture1->equals(picture2));
scroggo@google.com49ce11b2013-04-25 18:29:32 +0000416 // Now test that a parse error was generated when trying to create a new SkPicture without
417 // providing a function to decode the bitmap.
418 ErrorContext context;
419 context.fErrors = 0;
420 context.fReporter = reporter;
421 SkSetErrorCallback(assert_one_parse_error_cb, &context);
422 SkMemoryStream pictureStream(picture1);
423 bool success;
424 SkClearLastError();
425 SkPicture pictureFromStream(&pictureStream, &success, NULL);
426 REPORTER_ASSERT(reporter, success);
427 SkClearLastError();
428 SkSetErrorCallback(NULL, NULL);
scroggo@google.com7c9d5392012-12-10 15:40:55 +0000429}
430
junov@chromium.org94f20dc2013-01-28 21:04:44 +0000431static void test_clone_empty(skiatest::Reporter* reporter) {
432 // This is a regression test for crbug.com/172062
433 // Before the fix, we used to crash accessing a null pointer when we
434 // had a picture with no paints. This test passes by not crashing.
435 {
436 SkPicture picture;
437 picture.beginRecording(1, 1);
438 picture.endRecording();
439 SkPicture* destPicture = picture.clone();
440 REPORTER_ASSERT(reporter, NULL != destPicture);
441 destPicture->unref();
442 }
443 {
444 // Test without call to endRecording
445 SkPicture picture;
446 picture.beginRecording(1, 1);
447 SkPicture* destPicture = picture.clone();
448 REPORTER_ASSERT(reporter, NULL != destPicture);
449 destPicture->unref();
450 }
451}
452
junov@chromium.orgd575eed2013-05-08 15:39:13 +0000453static void test_clip_bound_opt(skiatest::Reporter* reporter) {
454 // Test for crbug.com/229011
455 SkRect rect1 = SkRect::MakeXYWH(SkIntToScalar(4), SkIntToScalar(4),
456 SkIntToScalar(2), SkIntToScalar(2));
457 SkRect rect2 = SkRect::MakeXYWH(SkIntToScalar(7), SkIntToScalar(7),
458 SkIntToScalar(1), SkIntToScalar(1));
459 SkRect rect3 = SkRect::MakeXYWH(SkIntToScalar(6), SkIntToScalar(6),
460 SkIntToScalar(1), SkIntToScalar(1));
461
462 SkPath invPath;
463 invPath.addOval(rect1);
464 invPath.setFillType(SkPath::kInverseEvenOdd_FillType);
465 SkPath path;
466 path.addOval(rect2);
467 SkPath path2;
468 path2.addOval(rect3);
469 SkIRect clipBounds;
470 // Minimalist test set for 100% code coverage of
471 // SkPictureRecord::updateClipConservativelyUsingBounds
472 {
473 SkPicture picture;
474 SkCanvas* canvas = picture.beginRecording(10, 10,
475 SkPicture::kUsePathBoundsForClip_RecordingFlag);
476 canvas->clipPath(invPath, SkRegion::kIntersect_Op);
477 bool nonEmpty = canvas->getClipDeviceBounds(&clipBounds);
478 REPORTER_ASSERT(reporter, true == nonEmpty);
479 REPORTER_ASSERT(reporter, 0 == clipBounds.fLeft);
480 REPORTER_ASSERT(reporter, 0 == clipBounds.fTop);
481 REPORTER_ASSERT(reporter, 10 == clipBounds.fBottom);
482 REPORTER_ASSERT(reporter, 10 == clipBounds.fRight);
483 }
484 {
485 SkPicture picture;
486 SkCanvas* canvas = picture.beginRecording(10, 10,
487 SkPicture::kUsePathBoundsForClip_RecordingFlag);
488 canvas->clipPath(path, SkRegion::kIntersect_Op);
489 canvas->clipPath(invPath, SkRegion::kIntersect_Op);
490 bool nonEmpty = canvas->getClipDeviceBounds(&clipBounds);
491 REPORTER_ASSERT(reporter, true == nonEmpty);
492 REPORTER_ASSERT(reporter, 7 == clipBounds.fLeft);
493 REPORTER_ASSERT(reporter, 7 == clipBounds.fTop);
494 REPORTER_ASSERT(reporter, 8 == clipBounds.fBottom);
495 REPORTER_ASSERT(reporter, 8 == clipBounds.fRight);
496 }
497 {
498 SkPicture picture;
499 SkCanvas* canvas = picture.beginRecording(10, 10,
500 SkPicture::kUsePathBoundsForClip_RecordingFlag);
501 canvas->clipPath(path, SkRegion::kIntersect_Op);
502 canvas->clipPath(invPath, SkRegion::kUnion_Op);
503 bool nonEmpty = canvas->getClipDeviceBounds(&clipBounds);
504 REPORTER_ASSERT(reporter, true == nonEmpty);
505 REPORTER_ASSERT(reporter, 0 == clipBounds.fLeft);
506 REPORTER_ASSERT(reporter, 0 == clipBounds.fTop);
507 REPORTER_ASSERT(reporter, 10 == clipBounds.fBottom);
508 REPORTER_ASSERT(reporter, 10 == clipBounds.fRight);
509 }
510 {
511 SkPicture picture;
512 SkCanvas* canvas = picture.beginRecording(10, 10,
513 SkPicture::kUsePathBoundsForClip_RecordingFlag);
514 canvas->clipPath(path, SkRegion::kDifference_Op);
515 bool nonEmpty = canvas->getClipDeviceBounds(&clipBounds);
516 REPORTER_ASSERT(reporter, true == nonEmpty);
517 REPORTER_ASSERT(reporter, 0 == clipBounds.fLeft);
518 REPORTER_ASSERT(reporter, 0 == clipBounds.fTop);
519 REPORTER_ASSERT(reporter, 10 == clipBounds.fBottom);
520 REPORTER_ASSERT(reporter, 10 == clipBounds.fRight);
521 }
522 {
523 SkPicture picture;
524 SkCanvas* canvas = picture.beginRecording(10, 10,
525 SkPicture::kUsePathBoundsForClip_RecordingFlag);
526 canvas->clipPath(path, SkRegion::kReverseDifference_Op);
527 bool nonEmpty = canvas->getClipDeviceBounds(&clipBounds);
528 // True clip is actually empty in this case, but the best
529 // determination we can make using only bounds as input is that the
530 // clip is included in the bounds of 'path'.
531 REPORTER_ASSERT(reporter, true == nonEmpty);
532 REPORTER_ASSERT(reporter, 7 == clipBounds.fLeft);
533 REPORTER_ASSERT(reporter, 7 == clipBounds.fTop);
534 REPORTER_ASSERT(reporter, 8 == clipBounds.fBottom);
535 REPORTER_ASSERT(reporter, 8 == clipBounds.fRight);
536 }
537 {
538 SkPicture picture;
539 SkCanvas* canvas = picture.beginRecording(10, 10,
540 SkPicture::kUsePathBoundsForClip_RecordingFlag);
541 canvas->clipPath(path, SkRegion::kIntersect_Op);
542 canvas->clipPath(path2, SkRegion::kXOR_Op);
543 bool nonEmpty = canvas->getClipDeviceBounds(&clipBounds);
544 REPORTER_ASSERT(reporter, true == nonEmpty);
545 REPORTER_ASSERT(reporter, 6 == clipBounds.fLeft);
546 REPORTER_ASSERT(reporter, 6 == clipBounds.fTop);
547 REPORTER_ASSERT(reporter, 8 == clipBounds.fBottom);
548 REPORTER_ASSERT(reporter, 8 == clipBounds.fRight);
549 }
550}
551
scroggo@google.comd614c6a2012-09-14 17:26:37 +0000552static void TestPicture(skiatest::Reporter* reporter) {
553#ifdef SK_DEBUG
554 test_deleting_empty_playback();
555 test_serializing_empty_picture();
scroggo@google.com4b90b112012-12-04 15:08:56 +0000556#else
557 test_bad_bitmap();
scroggo@google.comd614c6a2012-09-14 17:26:37 +0000558#endif
sugoi@google.com54f0d1b2013-02-27 19:17:41 +0000559 test_peephole();
reed@google.comfe7b1ed2012-11-29 21:00:39 +0000560 test_gatherpixelrefs(reporter);
scroggo@google.com7c9d5392012-12-10 15:40:55 +0000561 test_bitmap_with_encoded_data(reporter);
junov@chromium.org94f20dc2013-01-28 21:04:44 +0000562 test_clone_empty(reporter);
junov@chromium.orgd575eed2013-05-08 15:39:13 +0000563 test_clip_bound_opt(reporter);
scroggo@google.comd614c6a2012-09-14 17:26:37 +0000564}
565
566#include "TestClassDef.h"
reed@google.com21b519d2012-10-02 17:42:15 +0000567DEFINE_TESTCLASS("Pictures", PictureTestClass, TestPicture)