PictureTest.cpp 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881
  1. /*
  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 "include/core/SkBBHFactory.h"
  8. #include "include/core/SkBitmap.h"
  9. #include "include/core/SkCanvas.h"
  10. #include "include/core/SkClipOp.h"
  11. #include "include/core/SkColor.h"
  12. #include "include/core/SkData.h"
  13. #include "include/core/SkFontStyle.h"
  14. #include "include/core/SkImageInfo.h"
  15. #include "include/core/SkMatrix.h"
  16. #include "include/core/SkPaint.h"
  17. #include "include/core/SkPath.h"
  18. #include "include/core/SkPictureRecorder.h"
  19. #include "include/core/SkPixelRef.h"
  20. #include "include/core/SkRect.h"
  21. #include "include/core/SkRefCnt.h"
  22. #include "include/core/SkScalar.h"
  23. #include "include/core/SkShader.h"
  24. #include "include/core/SkStream.h"
  25. #include "include/core/SkTypeface.h"
  26. #include "include/core/SkTypes.h"
  27. #include "include/utils/SkRandom.h"
  28. #include "src/core/SkBBoxHierarchy.h"
  29. #include "src/core/SkBigPicture.h"
  30. #include "src/core/SkClipOpPriv.h"
  31. #include "src/core/SkMiniRecorder.h"
  32. #include "src/core/SkPicturePriv.h"
  33. #include "src/core/SkRectPriv.h"
  34. #include "tests/Test.h"
  35. #include <memory>
  36. class SkRRect;
  37. class SkRegion;
  38. template <typename T> class SkTDArray;
  39. static void make_bm(SkBitmap* bm, int w, int h, SkColor color, bool immutable) {
  40. bm->allocN32Pixels(w, h);
  41. bm->eraseColor(color);
  42. if (immutable) {
  43. bm->setImmutable();
  44. }
  45. }
  46. #ifdef SK_DEBUG
  47. // Ensure that deleting an empty SkPicture does not assert. Asserts only fire
  48. // in debug mode, so only run in debug mode.
  49. static void test_deleting_empty_picture() {
  50. SkPictureRecorder recorder;
  51. // Creates an SkPictureRecord
  52. recorder.beginRecording(0, 0);
  53. // Turns that into an SkPicture
  54. sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
  55. // Ceates a new SkPictureRecord
  56. recorder.beginRecording(0, 0);
  57. }
  58. // Ensure that serializing an empty picture does not assert. Likewise only runs in debug mode.
  59. static void test_serializing_empty_picture() {
  60. SkPictureRecorder recorder;
  61. recorder.beginRecording(0, 0);
  62. sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
  63. SkDynamicMemoryWStream stream;
  64. picture->serialize(&stream);
  65. }
  66. #endif
  67. static void rand_op(SkCanvas* canvas, SkRandom& rand) {
  68. SkPaint paint;
  69. SkRect rect = SkRect::MakeWH(50, 50);
  70. SkScalar unit = rand.nextUScalar1();
  71. if (unit <= 0.3) {
  72. // SkDebugf("save\n");
  73. canvas->save();
  74. } else if (unit <= 0.6) {
  75. // SkDebugf("restore\n");
  76. canvas->restore();
  77. } else if (unit <= 0.9) {
  78. // SkDebugf("clip\n");
  79. canvas->clipRect(rect);
  80. } else {
  81. // SkDebugf("draw\n");
  82. canvas->drawPaint(paint);
  83. }
  84. }
  85. static void set_canvas_to_save_count_4(SkCanvas* canvas) {
  86. canvas->restoreToCount(1);
  87. canvas->save();
  88. canvas->save();
  89. canvas->save();
  90. }
  91. /**
  92. * A canvas that records the number of saves, saveLayers and restores.
  93. */
  94. class SaveCountingCanvas : public SkCanvas {
  95. public:
  96. SaveCountingCanvas(int width, int height)
  97. : INHERITED(width, height)
  98. , fSaveCount(0)
  99. , fSaveLayerCount(0)
  100. , fSaveBehindCount(0)
  101. , fRestoreCount(0){
  102. }
  103. SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec& rec) override {
  104. ++fSaveLayerCount;
  105. return this->INHERITED::getSaveLayerStrategy(rec);
  106. }
  107. bool onDoSaveBehind(const SkRect* subset) override {
  108. ++fSaveBehindCount;
  109. return this->INHERITED::onDoSaveBehind(subset);
  110. }
  111. void willSave() override {
  112. ++fSaveCount;
  113. this->INHERITED::willSave();
  114. }
  115. void willRestore() override {
  116. ++fRestoreCount;
  117. this->INHERITED::willRestore();
  118. }
  119. unsigned int getSaveCount() const { return fSaveCount; }
  120. unsigned int getSaveLayerCount() const { return fSaveLayerCount; }
  121. unsigned int getSaveBehindCount() const { return fSaveBehindCount; }
  122. unsigned int getRestoreCount() const { return fRestoreCount; }
  123. private:
  124. unsigned int fSaveCount;
  125. unsigned int fSaveLayerCount;
  126. unsigned int fSaveBehindCount;
  127. unsigned int fRestoreCount;
  128. typedef SkCanvas INHERITED;
  129. };
  130. void check_save_state(skiatest::Reporter* reporter, SkPicture* picture,
  131. unsigned int numSaves, unsigned int numSaveLayers,
  132. unsigned int numRestores) {
  133. SaveCountingCanvas canvas(SkScalarCeilToInt(picture->cullRect().width()),
  134. SkScalarCeilToInt(picture->cullRect().height()));
  135. picture->playback(&canvas);
  136. // Optimizations may have removed these,
  137. // so expect to have seen no more than num{Saves,SaveLayers,Restores}.
  138. REPORTER_ASSERT(reporter, numSaves >= canvas.getSaveCount());
  139. REPORTER_ASSERT(reporter, numSaveLayers >= canvas.getSaveLayerCount());
  140. REPORTER_ASSERT(reporter, numRestores >= canvas.getRestoreCount());
  141. }
  142. // This class exists so SkPicture can friend it and give it access to
  143. // the 'partialReplay' method.
  144. class SkPictureRecorderReplayTester {
  145. public:
  146. static sk_sp<SkPicture> Copy(SkPictureRecorder* recorder) {
  147. SkPictureRecorder recorder2;
  148. SkCanvas* canvas = recorder2.beginRecording(10, 10);
  149. recorder->partialReplay(canvas);
  150. return recorder2.finishRecordingAsPicture();
  151. }
  152. };
  153. static void create_imbalance(SkCanvas* canvas) {
  154. SkRect clipRect = SkRect::MakeWH(2, 2);
  155. SkRect drawRect = SkRect::MakeWH(10, 10);
  156. canvas->save();
  157. canvas->clipRect(clipRect, kReplace_SkClipOp);
  158. canvas->translate(1.0f, 1.0f);
  159. SkPaint p;
  160. p.setColor(SK_ColorGREEN);
  161. canvas->drawRect(drawRect, p);
  162. // no restore
  163. }
  164. // This tests that replaying a potentially unbalanced picture into a canvas
  165. // doesn't affect the canvas' save count or matrix/clip state.
  166. static void check_balance(skiatest::Reporter* reporter, SkPicture* picture) {
  167. SkBitmap bm;
  168. bm.allocN32Pixels(4, 3);
  169. SkCanvas canvas(bm);
  170. int beforeSaveCount = canvas.getSaveCount();
  171. SkMatrix beforeMatrix = canvas.getTotalMatrix();
  172. SkRect beforeClip = canvas.getLocalClipBounds();
  173. canvas.drawPicture(picture);
  174. REPORTER_ASSERT(reporter, beforeSaveCount == canvas.getSaveCount());
  175. REPORTER_ASSERT(reporter, beforeMatrix == canvas.getTotalMatrix());
  176. SkRect afterClip = canvas.getLocalClipBounds();
  177. REPORTER_ASSERT(reporter, afterClip == beforeClip);
  178. }
  179. // Test out SkPictureRecorder::partialReplay
  180. DEF_TEST(PictureRecorder_replay, reporter) {
  181. // check save/saveLayer state
  182. {
  183. SkPictureRecorder recorder;
  184. SkCanvas* canvas = recorder.beginRecording(10, 10);
  185. canvas->saveLayer(nullptr, nullptr);
  186. sk_sp<SkPicture> copy(SkPictureRecorderReplayTester::Copy(&recorder));
  187. // The extra save and restore comes from the Copy process.
  188. check_save_state(reporter, copy.get(), 2, 1, 3);
  189. canvas->saveLayer(nullptr, nullptr);
  190. sk_sp<SkPicture> final(recorder.finishRecordingAsPicture());
  191. check_save_state(reporter, final.get(), 1, 2, 3);
  192. // The copy shouldn't pick up any operations added after it was made
  193. check_save_state(reporter, copy.get(), 2, 1, 3);
  194. }
  195. // Recreate the Android partialReplay test case
  196. {
  197. SkPictureRecorder recorder;
  198. SkCanvas* canvas = recorder.beginRecording(4, 3, nullptr, 0);
  199. create_imbalance(canvas);
  200. int expectedSaveCount = canvas->getSaveCount();
  201. sk_sp<SkPicture> copy(SkPictureRecorderReplayTester::Copy(&recorder));
  202. check_balance(reporter, copy.get());
  203. REPORTER_ASSERT(reporter, expectedSaveCount = canvas->getSaveCount());
  204. // End the recording of source to test the picture finalization
  205. // process isn't complicated by the partialReplay step
  206. sk_sp<SkPicture> final(recorder.finishRecordingAsPicture());
  207. }
  208. }
  209. static void test_unbalanced_save_restores(skiatest::Reporter* reporter) {
  210. SkCanvas testCanvas(100, 100);
  211. set_canvas_to_save_count_4(&testCanvas);
  212. REPORTER_ASSERT(reporter, 4 == testCanvas.getSaveCount());
  213. SkPaint paint;
  214. SkRect rect = SkRect::MakeLTRB(-10000000, -10000000, 10000000, 10000000);
  215. SkPictureRecorder recorder;
  216. {
  217. // Create picture with 2 unbalanced saves
  218. SkCanvas* canvas = recorder.beginRecording(100, 100);
  219. canvas->save();
  220. canvas->translate(10, 10);
  221. canvas->drawRect(rect, paint);
  222. canvas->save();
  223. canvas->translate(10, 10);
  224. canvas->drawRect(rect, paint);
  225. sk_sp<SkPicture> extraSavePicture(recorder.finishRecordingAsPicture());
  226. testCanvas.drawPicture(extraSavePicture);
  227. REPORTER_ASSERT(reporter, 4 == testCanvas.getSaveCount());
  228. }
  229. set_canvas_to_save_count_4(&testCanvas);
  230. {
  231. // Create picture with 2 unbalanced restores
  232. SkCanvas* canvas = recorder.beginRecording(100, 100);
  233. canvas->save();
  234. canvas->translate(10, 10);
  235. canvas->drawRect(rect, paint);
  236. canvas->save();
  237. canvas->translate(10, 10);
  238. canvas->drawRect(rect, paint);
  239. canvas->restore();
  240. canvas->restore();
  241. canvas->restore();
  242. canvas->restore();
  243. sk_sp<SkPicture> extraRestorePicture(recorder.finishRecordingAsPicture());
  244. testCanvas.drawPicture(extraRestorePicture);
  245. REPORTER_ASSERT(reporter, 4 == testCanvas.getSaveCount());
  246. }
  247. set_canvas_to_save_count_4(&testCanvas);
  248. {
  249. SkCanvas* canvas = recorder.beginRecording(100, 100);
  250. canvas->translate(10, 10);
  251. canvas->drawRect(rect, paint);
  252. sk_sp<SkPicture> noSavePicture(recorder.finishRecordingAsPicture());
  253. testCanvas.drawPicture(noSavePicture);
  254. REPORTER_ASSERT(reporter, 4 == testCanvas.getSaveCount());
  255. REPORTER_ASSERT(reporter, testCanvas.getTotalMatrix().isIdentity());
  256. }
  257. }
  258. static void test_peephole() {
  259. SkRandom rand;
  260. SkPictureRecorder recorder;
  261. for (int j = 0; j < 100; j++) {
  262. SkRandom rand2(rand); // remember the seed
  263. SkCanvas* canvas = recorder.beginRecording(100, 100);
  264. for (int i = 0; i < 1000; ++i) {
  265. rand_op(canvas, rand);
  266. }
  267. sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
  268. rand = rand2;
  269. }
  270. {
  271. SkCanvas* canvas = recorder.beginRecording(100, 100);
  272. SkRect rect = SkRect::MakeWH(50, 50);
  273. for (int i = 0; i < 100; ++i) {
  274. canvas->save();
  275. }
  276. while (canvas->getSaveCount() > 1) {
  277. canvas->clipRect(rect);
  278. canvas->restore();
  279. }
  280. sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
  281. }
  282. }
  283. #ifndef SK_DEBUG
  284. // Only test this is in release mode. We deliberately crash in debug mode, since a valid caller
  285. // should never do this.
  286. static void test_bad_bitmap() {
  287. // This bitmap has a width and height but no pixels. As a result, attempting to record it will
  288. // fail.
  289. SkBitmap bm;
  290. bm.setInfo(SkImageInfo::MakeN32Premul(100, 100));
  291. SkPictureRecorder recorder;
  292. SkCanvas* recordingCanvas = recorder.beginRecording(100, 100);
  293. recordingCanvas->drawBitmap(bm, 0, 0);
  294. sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
  295. SkCanvas canvas;
  296. canvas.drawPicture(picture);
  297. }
  298. #endif
  299. static void test_clip_bound_opt(skiatest::Reporter* reporter) {
  300. // Test for crbug.com/229011
  301. SkRect rect1 = SkRect::MakeXYWH(SkIntToScalar(4), SkIntToScalar(4),
  302. SkIntToScalar(2), SkIntToScalar(2));
  303. SkRect rect2 = SkRect::MakeXYWH(SkIntToScalar(7), SkIntToScalar(7),
  304. SkIntToScalar(1), SkIntToScalar(1));
  305. SkRect rect3 = SkRect::MakeXYWH(SkIntToScalar(6), SkIntToScalar(6),
  306. SkIntToScalar(1), SkIntToScalar(1));
  307. SkPath invPath;
  308. invPath.addOval(rect1);
  309. invPath.setFillType(SkPath::kInverseEvenOdd_FillType);
  310. SkPath path;
  311. path.addOval(rect2);
  312. SkPath path2;
  313. path2.addOval(rect3);
  314. SkIRect clipBounds;
  315. SkPictureRecorder recorder;
  316. // Testing conservative-raster-clip that is enabled by PictureRecord
  317. {
  318. SkCanvas* canvas = recorder.beginRecording(10, 10);
  319. canvas->clipPath(invPath);
  320. clipBounds = canvas->getDeviceClipBounds();
  321. REPORTER_ASSERT(reporter, 0 == clipBounds.fLeft);
  322. REPORTER_ASSERT(reporter, 0 == clipBounds.fTop);
  323. REPORTER_ASSERT(reporter, 10 == clipBounds.fBottom);
  324. REPORTER_ASSERT(reporter, 10 == clipBounds.fRight);
  325. }
  326. {
  327. SkCanvas* canvas = recorder.beginRecording(10, 10);
  328. canvas->clipPath(path);
  329. canvas->clipPath(invPath);
  330. clipBounds = canvas->getDeviceClipBounds();
  331. REPORTER_ASSERT(reporter, 7 == clipBounds.fLeft);
  332. REPORTER_ASSERT(reporter, 7 == clipBounds.fTop);
  333. REPORTER_ASSERT(reporter, 8 == clipBounds.fBottom);
  334. REPORTER_ASSERT(reporter, 8 == clipBounds.fRight);
  335. }
  336. {
  337. SkCanvas* canvas = recorder.beginRecording(10, 10);
  338. canvas->clipPath(path);
  339. canvas->clipPath(invPath, kUnion_SkClipOp);
  340. clipBounds = canvas->getDeviceClipBounds();
  341. REPORTER_ASSERT(reporter, 0 == clipBounds.fLeft);
  342. REPORTER_ASSERT(reporter, 0 == clipBounds.fTop);
  343. REPORTER_ASSERT(reporter, 10 == clipBounds.fBottom);
  344. REPORTER_ASSERT(reporter, 10 == clipBounds.fRight);
  345. }
  346. {
  347. SkCanvas* canvas = recorder.beginRecording(10, 10);
  348. canvas->clipPath(path, kDifference_SkClipOp);
  349. clipBounds = canvas->getDeviceClipBounds();
  350. REPORTER_ASSERT(reporter, 0 == clipBounds.fLeft);
  351. REPORTER_ASSERT(reporter, 0 == clipBounds.fTop);
  352. REPORTER_ASSERT(reporter, 10 == clipBounds.fBottom);
  353. REPORTER_ASSERT(reporter, 10 == clipBounds.fRight);
  354. }
  355. {
  356. SkCanvas* canvas = recorder.beginRecording(10, 10);
  357. canvas->clipPath(path, kReverseDifference_SkClipOp);
  358. clipBounds = canvas->getDeviceClipBounds();
  359. // True clip is actually empty in this case, but the best
  360. // determination we can make using only bounds as input is that the
  361. // clip is included in the bounds of 'path'.
  362. REPORTER_ASSERT(reporter, 7 == clipBounds.fLeft);
  363. REPORTER_ASSERT(reporter, 7 == clipBounds.fTop);
  364. REPORTER_ASSERT(reporter, 8 == clipBounds.fBottom);
  365. REPORTER_ASSERT(reporter, 8 == clipBounds.fRight);
  366. }
  367. {
  368. SkCanvas* canvas = recorder.beginRecording(10, 10);
  369. canvas->clipPath(path, kIntersect_SkClipOp);
  370. canvas->clipPath(path2, kXOR_SkClipOp);
  371. clipBounds = canvas->getDeviceClipBounds();
  372. REPORTER_ASSERT(reporter, 6 == clipBounds.fLeft);
  373. REPORTER_ASSERT(reporter, 6 == clipBounds.fTop);
  374. REPORTER_ASSERT(reporter, 8 == clipBounds.fBottom);
  375. REPORTER_ASSERT(reporter, 8 == clipBounds.fRight);
  376. }
  377. }
  378. static void test_cull_rect_reset(skiatest::Reporter* reporter) {
  379. SkPictureRecorder recorder;
  380. SkRect bounds = SkRect::MakeWH(10, 10);
  381. SkRTreeFactory factory;
  382. SkCanvas* canvas = recorder.beginRecording(bounds, &factory);
  383. bounds = SkRect::MakeWH(100, 100);
  384. SkPaint paint;
  385. canvas->drawRect(bounds, paint);
  386. canvas->drawRect(bounds, paint);
  387. sk_sp<SkPicture> p(recorder.finishRecordingAsPictureWithCull(bounds));
  388. const SkBigPicture* picture = SkPicturePriv::AsSkBigPicture(p);
  389. REPORTER_ASSERT(reporter, picture);
  390. SkRect finalCullRect = picture->cullRect();
  391. REPORTER_ASSERT(reporter, 0 == finalCullRect.fLeft);
  392. REPORTER_ASSERT(reporter, 0 == finalCullRect.fTop);
  393. REPORTER_ASSERT(reporter, 100 == finalCullRect.fBottom);
  394. REPORTER_ASSERT(reporter, 100 == finalCullRect.fRight);
  395. const SkBBoxHierarchy* pictureBBH = picture->bbh();
  396. SkRect bbhCullRect = pictureBBH->getRootBound();
  397. REPORTER_ASSERT(reporter, 0 == bbhCullRect.fLeft);
  398. REPORTER_ASSERT(reporter, 0 == bbhCullRect.fTop);
  399. REPORTER_ASSERT(reporter, 100 == bbhCullRect.fBottom);
  400. REPORTER_ASSERT(reporter, 100 == bbhCullRect.fRight);
  401. }
  402. /**
  403. * A canvas that records the number of clip commands.
  404. */
  405. class ClipCountingCanvas : public SkCanvas {
  406. public:
  407. ClipCountingCanvas(int width, int height)
  408. : INHERITED(width, height)
  409. , fClipCount(0){
  410. }
  411. void onClipRect(const SkRect& r, SkClipOp op, ClipEdgeStyle edgeStyle) override {
  412. fClipCount += 1;
  413. this->INHERITED::onClipRect(r, op, edgeStyle);
  414. }
  415. void onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle)override {
  416. fClipCount += 1;
  417. this->INHERITED::onClipRRect(rrect, op, edgeStyle);
  418. }
  419. void onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) override {
  420. fClipCount += 1;
  421. this->INHERITED::onClipPath(path, op, edgeStyle);
  422. }
  423. void onClipRegion(const SkRegion& deviceRgn, SkClipOp op) override {
  424. fClipCount += 1;
  425. this->INHERITED::onClipRegion(deviceRgn, op);
  426. }
  427. unsigned getClipCount() const { return fClipCount; }
  428. private:
  429. unsigned fClipCount;
  430. typedef SkCanvas INHERITED;
  431. };
  432. static void test_clip_expansion(skiatest::Reporter* reporter) {
  433. SkPictureRecorder recorder;
  434. SkCanvas* canvas = recorder.beginRecording(10, 10);
  435. canvas->clipRect(SkRect::MakeEmpty(), kReplace_SkClipOp);
  436. // The following expanding clip should not be skipped.
  437. canvas->clipRect(SkRect::MakeXYWH(4, 4, 3, 3), kUnion_SkClipOp);
  438. // Draw something so the optimizer doesn't just fold the world.
  439. SkPaint p;
  440. p.setColor(SK_ColorBLUE);
  441. canvas->drawPaint(p);
  442. sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
  443. ClipCountingCanvas testCanvas(10, 10);
  444. picture->playback(&testCanvas);
  445. // Both clips should be present on playback.
  446. REPORTER_ASSERT(reporter, testCanvas.getClipCount() == 2);
  447. }
  448. static void test_gen_id(skiatest::Reporter* reporter) {
  449. SkPictureRecorder recorder;
  450. recorder.beginRecording(0, 0);
  451. sk_sp<SkPicture> empty(recorder.finishRecordingAsPicture());
  452. // Empty pictures should still have a valid ID
  453. REPORTER_ASSERT(reporter, empty->uniqueID() != SK_InvalidGenID);
  454. SkCanvas* canvas = recorder.beginRecording(1, 1);
  455. canvas->drawColor(SK_ColorWHITE);
  456. sk_sp<SkPicture> hasData(recorder.finishRecordingAsPicture());
  457. // picture should have a non-zero id after recording
  458. REPORTER_ASSERT(reporter, hasData->uniqueID() != SK_InvalidGenID);
  459. // both pictures should have different ids
  460. REPORTER_ASSERT(reporter, hasData->uniqueID() != empty->uniqueID());
  461. }
  462. static void test_typeface(skiatest::Reporter* reporter) {
  463. SkPictureRecorder recorder;
  464. SkCanvas* canvas = recorder.beginRecording(10, 10);
  465. SkFont font(SkTypeface::MakeFromName("Arial", SkFontStyle::Italic()));
  466. canvas->drawString("Q", 0, 10, font, SkPaint());
  467. sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
  468. SkDynamicMemoryWStream stream;
  469. picture->serialize(&stream);
  470. }
  471. DEF_TEST(Picture, reporter) {
  472. test_typeface(reporter);
  473. #ifdef SK_DEBUG
  474. test_deleting_empty_picture();
  475. test_serializing_empty_picture();
  476. #else
  477. test_bad_bitmap();
  478. #endif
  479. test_unbalanced_save_restores(reporter);
  480. test_peephole();
  481. test_clip_bound_opt(reporter);
  482. test_clip_expansion(reporter);
  483. test_gen_id(reporter);
  484. test_cull_rect_reset(reporter);
  485. }
  486. static void draw_bitmaps(const SkBitmap bitmap, SkCanvas* canvas) {
  487. const SkPaint paint;
  488. const SkRect rect = { 5.0f, 5.0f, 8.0f, 8.0f };
  489. const SkIRect irect = { 2, 2, 3, 3 };
  490. int divs[] = { 2, 3 };
  491. SkCanvas::Lattice lattice;
  492. lattice.fXCount = lattice.fYCount = 2;
  493. lattice.fXDivs = lattice.fYDivs = divs;
  494. // Don't care what these record, as long as they're legal.
  495. canvas->drawBitmap(bitmap, 0.0f, 0.0f, &paint);
  496. canvas->drawBitmapRect(bitmap, rect, rect, &paint, SkCanvas::kStrict_SrcRectConstraint);
  497. canvas->drawBitmapNine(bitmap, irect, rect, &paint);
  498. canvas->drawBitmap(bitmap, 1, 1); // drawSprite
  499. canvas->drawBitmapLattice(bitmap, lattice, rect, &paint);
  500. }
  501. static void test_draw_bitmaps(SkCanvas* canvas) {
  502. SkBitmap empty;
  503. draw_bitmaps(empty, canvas);
  504. empty.setInfo(SkImageInfo::MakeN32Premul(10, 10));
  505. draw_bitmaps(empty, canvas);
  506. }
  507. DEF_TEST(Picture_EmptyBitmap, r) {
  508. SkPictureRecorder recorder;
  509. test_draw_bitmaps(recorder.beginRecording(10, 10));
  510. sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
  511. }
  512. DEF_TEST(Canvas_EmptyBitmap, r) {
  513. SkBitmap dst;
  514. dst.allocN32Pixels(10, 10);
  515. SkCanvas canvas(dst);
  516. test_draw_bitmaps(&canvas);
  517. }
  518. DEF_TEST(DontOptimizeSaveLayerDrawDrawRestore, reporter) {
  519. // This test is from crbug.com/344987.
  520. // The commands are:
  521. // saveLayer with paint that modifies alpha
  522. // drawBitmapRect
  523. // drawBitmapRect
  524. // restore
  525. // The bug was that this structure was modified so that:
  526. // - The saveLayer and restore were eliminated
  527. // - The alpha was only applied to the first drawBitmapRectToRect
  528. // This test draws blue and red squares inside a 50% transparent
  529. // layer. Both colours should show up muted.
  530. // When the bug is present, the red square (the second bitmap)
  531. // shows upwith full opacity.
  532. SkBitmap blueBM;
  533. make_bm(&blueBM, 100, 100, SkColorSetARGB(255, 0, 0, 255), true);
  534. SkBitmap redBM;
  535. make_bm(&redBM, 100, 100, SkColorSetARGB(255, 255, 0, 0), true);
  536. SkPaint semiTransparent;
  537. semiTransparent.setAlpha(0x80);
  538. SkPictureRecorder recorder;
  539. SkCanvas* canvas = recorder.beginRecording(100, 100);
  540. canvas->drawColor(0);
  541. canvas->saveLayer(nullptr, &semiTransparent);
  542. canvas->drawBitmap(blueBM, 25, 25);
  543. canvas->drawBitmap(redBM, 50, 50);
  544. canvas->restore();
  545. sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
  546. // Now replay the picture back on another canvas
  547. // and check a couple of its pixels.
  548. SkBitmap replayBM;
  549. make_bm(&replayBM, 100, 100, SK_ColorBLACK, false);
  550. SkCanvas replayCanvas(replayBM);
  551. picture->playback(&replayCanvas);
  552. // With the bug present, at (55, 55) we would get a fully opaque red
  553. // intead of a dark red.
  554. REPORTER_ASSERT(reporter, replayBM.getColor(30, 30) == 0xff000080);
  555. REPORTER_ASSERT(reporter, replayBM.getColor(55, 55) == 0xff800000);
  556. }
  557. struct CountingBBH : public SkBBoxHierarchy {
  558. mutable int searchCalls;
  559. SkRect rootBound;
  560. CountingBBH(const SkRect& bound) : searchCalls(0), rootBound(bound) {}
  561. void search(const SkRect& query, SkTDArray<int>* results) const override {
  562. this->searchCalls++;
  563. }
  564. void insert(const SkRect[], int) override {}
  565. virtual size_t bytesUsed() const override { return 0; }
  566. SkRect getRootBound() const override { return rootBound; }
  567. };
  568. class SpoonFedBBHFactory : public SkBBHFactory {
  569. public:
  570. explicit SpoonFedBBHFactory(SkBBoxHierarchy* bbh) : fBBH(bbh) {}
  571. SkBBoxHierarchy* operator()() const override {
  572. return SkRef(fBBH);
  573. }
  574. private:
  575. SkBBoxHierarchy* fBBH;
  576. };
  577. // When the canvas clip covers the full picture, we don't need to call the BBH.
  578. DEF_TEST(Picture_SkipBBH, r) {
  579. SkRect bound = SkRect::MakeWH(320, 240);
  580. CountingBBH bbh(bound);
  581. SpoonFedBBHFactory factory(&bbh);
  582. SkPictureRecorder recorder;
  583. SkCanvas* c = recorder.beginRecording(bound, &factory);
  584. // Record a few ops so we don't hit a small- or empty- picture optimization.
  585. c->drawRect(bound, SkPaint());
  586. c->drawRect(bound, SkPaint());
  587. sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
  588. SkCanvas big(640, 480), small(300, 200);
  589. picture->playback(&big);
  590. REPORTER_ASSERT(r, bbh.searchCalls == 0);
  591. picture->playback(&small);
  592. REPORTER_ASSERT(r, bbh.searchCalls == 1);
  593. }
  594. DEF_TEST(Picture_BitmapLeak, r) {
  595. SkBitmap mut, immut;
  596. mut.allocN32Pixels(300, 200);
  597. immut.allocN32Pixels(300, 200);
  598. immut.setImmutable();
  599. SkASSERT(!mut.isImmutable());
  600. SkASSERT(immut.isImmutable());
  601. // No one can hold a ref on our pixels yet.
  602. REPORTER_ASSERT(r, mut.pixelRef()->unique());
  603. REPORTER_ASSERT(r, immut.pixelRef()->unique());
  604. sk_sp<SkPicture> pic;
  605. {
  606. // we want the recorder to go out of scope before our subsequent checks, so we
  607. // place it inside local braces.
  608. SkPictureRecorder rec;
  609. SkCanvas* canvas = rec.beginRecording(1920, 1200);
  610. canvas->drawBitmap(mut, 0, 0);
  611. canvas->drawBitmap(immut, 800, 600);
  612. pic = rec.finishRecordingAsPicture();
  613. }
  614. // The picture shares the immutable pixels but copies the mutable ones.
  615. REPORTER_ASSERT(r, mut.pixelRef()->unique());
  616. REPORTER_ASSERT(r, !immut.pixelRef()->unique());
  617. // When the picture goes away, it's just our bitmaps holding the refs.
  618. pic = nullptr;
  619. REPORTER_ASSERT(r, mut.pixelRef()->unique());
  620. REPORTER_ASSERT(r, immut.pixelRef()->unique());
  621. }
  622. // getRecordingCanvas() should return a SkCanvas when recording, null when not recording.
  623. DEF_TEST(Picture_getRecordingCanvas, r) {
  624. SkPictureRecorder rec;
  625. REPORTER_ASSERT(r, !rec.getRecordingCanvas());
  626. for (int i = 0; i < 3; i++) {
  627. rec.beginRecording(100, 100);
  628. REPORTER_ASSERT(r, rec.getRecordingCanvas());
  629. rec.finishRecordingAsPicture();
  630. REPORTER_ASSERT(r, !rec.getRecordingCanvas());
  631. }
  632. }
  633. DEF_TEST(MiniRecorderLeftHanging, r) {
  634. // Any shader or other ref-counted effect will do just fine here.
  635. SkPaint paint;
  636. paint.setShader(SkShaders::Color(SK_ColorRED));
  637. SkMiniRecorder rec;
  638. REPORTER_ASSERT(r, rec.drawRect(SkRect::MakeWH(20,30), paint));
  639. // Don't call rec.detachPicture(). Test succeeds by not asserting or leaking the shader.
  640. }
  641. DEF_TEST(Picture_preserveCullRect, r) {
  642. SkPictureRecorder recorder;
  643. SkCanvas* c = recorder.beginRecording(SkRect::MakeLTRB(1, 2, 3, 4));
  644. c->clear(SK_ColorCYAN);
  645. sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
  646. SkDynamicMemoryWStream wstream;
  647. picture->serialize(&wstream);
  648. std::unique_ptr<SkStream> rstream(wstream.detachAsStream());
  649. sk_sp<SkPicture> deserializedPicture(SkPicture::MakeFromStream(rstream.get()));
  650. REPORTER_ASSERT(r, deserializedPicture != nullptr);
  651. REPORTER_ASSERT(r, deserializedPicture->cullRect().left() == 1);
  652. REPORTER_ASSERT(r, deserializedPicture->cullRect().top() == 2);
  653. REPORTER_ASSERT(r, deserializedPicture->cullRect().right() == 3);
  654. REPORTER_ASSERT(r, deserializedPicture->cullRect().bottom() == 4);
  655. }
  656. // If we record bounded ops into a picture with a big cull and calculate the
  657. // bounds of those ops, we should trim down the picture cull to the ops' bounds.
  658. // If we're not using an SkBBH, we shouldn't change it.
  659. DEF_TEST(Picture_UpdatedCull_1, r) {
  660. // Testing 1 draw exercises SkMiniPicture.
  661. SkRTreeFactory factory;
  662. SkPictureRecorder recorder;
  663. auto canvas = recorder.beginRecording(SkRectPriv::MakeLargest(), &factory);
  664. canvas->drawRect(SkRect::MakeWH(20,20), SkPaint{});
  665. auto pic = recorder.finishRecordingAsPicture();
  666. REPORTER_ASSERT(r, pic->cullRect() == SkRect::MakeWH(20,20));
  667. canvas = recorder.beginRecording(SkRectPriv::MakeLargest());
  668. canvas->drawRect(SkRect::MakeWH(20,20), SkPaint{});
  669. pic = recorder.finishRecordingAsPicture();
  670. REPORTER_ASSERT(r, pic->cullRect() == SkRectPriv::MakeLargest());
  671. }
  672. DEF_TEST(Picture_UpdatedCull_2, r) {
  673. // Testing >1 draw exercises SkBigPicture.
  674. SkRTreeFactory factory;
  675. SkPictureRecorder recorder;
  676. auto canvas = recorder.beginRecording(SkRectPriv::MakeLargest(), &factory);
  677. canvas->drawRect(SkRect::MakeWH(20,20), SkPaint{});
  678. canvas->drawRect(SkRect::MakeWH(10,40), SkPaint{});
  679. auto pic = recorder.finishRecordingAsPicture();
  680. REPORTER_ASSERT(r, pic->cullRect() == SkRect::MakeWH(20,40));
  681. canvas = recorder.beginRecording(SkRectPriv::MakeLargest());
  682. canvas->drawRect(SkRect::MakeWH(20,20), SkPaint{});
  683. canvas->drawRect(SkRect::MakeWH(10,40), SkPaint{});
  684. pic = recorder.finishRecordingAsPicture();
  685. REPORTER_ASSERT(r, pic->cullRect() == SkRectPriv::MakeLargest());
  686. }
  687. DEF_TEST(Picture_RecordsFlush, r) {
  688. SkPictureRecorder recorder;
  689. auto canvas = recorder.beginRecording(SkRect::MakeWH(100,100));
  690. for (int i = 0; i < 10; i++) {
  691. canvas->clear(0);
  692. for (int j = 0; j < 10; j++) {
  693. canvas->drawRect(SkRect::MakeXYWH(i*10,j*10,10,10), SkPaint());
  694. }
  695. canvas->flush();
  696. }
  697. // Did we record the flushes?
  698. auto pic = recorder.finishRecordingAsPicture();
  699. REPORTER_ASSERT(r, pic->approximateOpCount() == 120); // 10 clears, 100 draws, 10 flushes
  700. // Do we serialize and deserialize flushes?
  701. auto skp = pic->serialize();
  702. auto back = SkPicture::MakeFromData(skp->data(), skp->size());
  703. REPORTER_ASSERT(r, back->approximateOpCount() == pic->approximateOpCount());
  704. }
  705. DEF_TEST(Placeholder, r) {
  706. SkRect cull = { 0,0, 10,20 };
  707. // Each placeholder is unique.
  708. sk_sp<SkPicture> p1 = SkPicture::MakePlaceholder(cull),
  709. p2 = SkPicture::MakePlaceholder(cull);
  710. REPORTER_ASSERT(r, p1->cullRect() == p2->cullRect());
  711. REPORTER_ASSERT(r, p1->cullRect() == cull);
  712. REPORTER_ASSERT(r, p1->uniqueID() != p2->uniqueID());
  713. // Placeholders are never unrolled by SkCanvas (while other small pictures may be).
  714. SkPictureRecorder recorder;
  715. SkCanvas* canvas = recorder.beginRecording(cull);
  716. canvas->drawPicture(p1);
  717. canvas->drawPicture(p2);
  718. sk_sp<SkPicture> pic = recorder.finishRecordingAsPicture();
  719. REPORTER_ASSERT(r, pic->approximateOpCount() == 2);
  720. }
  721. DEF_TEST(Picture_empty_serial, reporter) {
  722. SkPictureRecorder rec;
  723. (void)rec.beginRecording(10, 10);
  724. auto pic = rec.finishRecordingAsPicture();
  725. REPORTER_ASSERT(reporter, pic);
  726. auto data = pic->serialize();
  727. REPORTER_ASSERT(reporter, data);
  728. auto pic2 = SkPicture::MakeFromData(data->data(), data->size());
  729. REPORTER_ASSERT(reporter, pic2);
  730. }