SerialProcsTest.cpp 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. /*
  2. * Copyright 2017 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/SkCanvas.h"
  8. #include "include/core/SkPicture.h"
  9. #include "include/core/SkPictureRecorder.h"
  10. #include "include/core/SkSerialProcs.h"
  11. #include "include/core/SkSurface.h"
  12. #include "include/effects/SkImageSource.h"
  13. #include "tests/Test.h"
  14. #include "tools/Resources.h"
  15. #include "tools/ToolUtils.h"
  16. static sk_sp<SkImage> picture_to_image(sk_sp<SkPicture> pic) {
  17. SkIRect r = pic->cullRect().round();
  18. auto surf = SkSurface::MakeRasterN32Premul(r.width(), r.height());
  19. surf->getCanvas()->drawPicture(pic);
  20. return surf->makeImageSnapshot();
  21. }
  22. struct State {
  23. const char* fStr;
  24. SkImage* fImg;
  25. };
  26. DEF_TEST(serial_procs_image, reporter) {
  27. auto src_img = GetResourceAsImage("images/mandrill_128.png");
  28. const char magic_str[] = "magic signature";
  29. const SkSerialImageProc sprocs[] = {
  30. [](SkImage* img, void* ctx) -> sk_sp<SkData> { return nullptr; },
  31. [](SkImage* img, void* ctx) { return img->encodeToData(); },
  32. [](SkImage* img, void* ctx) { return SkData::MakeWithCString(((State*)ctx)->fStr); },
  33. };
  34. const SkDeserialImageProc dprocs[] = {
  35. [](const void* data, size_t length, void*) -> sk_sp<SkImage> {
  36. return nullptr;
  37. },
  38. [](const void* data, size_t length, void*) {
  39. return SkImage::MakeFromEncoded(SkData::MakeWithCopy(data, length));
  40. },
  41. [](const void* data, size_t length, void* ctx) -> sk_sp<SkImage> {
  42. State* state = (State*)ctx;
  43. if (length != strlen(state->fStr)+1 || memcmp(data, state->fStr, length)) {
  44. return nullptr;
  45. }
  46. return sk_ref_sp(state->fImg);
  47. },
  48. };
  49. sk_sp<SkPicture> pic;
  50. {
  51. SkPictureRecorder rec;
  52. SkCanvas* canvas = rec.beginRecording(128, 128);
  53. canvas->drawImage(src_img, 0, 0, nullptr);
  54. pic = rec.finishRecordingAsPicture();
  55. }
  56. State state = { magic_str, src_img.get() };
  57. SkSerialProcs sproc;
  58. sproc.fImageCtx = &state;
  59. SkDeserialProcs dproc;
  60. dproc.fImageCtx = &state;
  61. for (size_t i = 0; i < SK_ARRAY_COUNT(sprocs); ++i) {
  62. sproc.fImageProc = sprocs[i];
  63. auto data = pic->serialize(&sproc);
  64. REPORTER_ASSERT(reporter, data);
  65. dproc.fImageProc = dprocs[i];
  66. auto new_pic = SkPicture::MakeFromData(data.get(), &dproc);
  67. REPORTER_ASSERT(reporter, data);
  68. auto dst_img = picture_to_image(new_pic);
  69. REPORTER_ASSERT(reporter, ToolUtils::equal_pixels(src_img.get(), dst_img.get()));
  70. }
  71. }
  72. ///////////////////////////////////////////////////////////////////////////////////////////////////
  73. static sk_sp<SkPicture> make_pic(const std::function<void(SkCanvas*)>& drawer) {
  74. SkPictureRecorder rec;
  75. drawer(rec.beginRecording(128, 128));
  76. return rec.finishRecordingAsPicture();
  77. }
  78. static SkSerialProcs makes(SkSerialPictureProc proc, void* ctx = nullptr) {
  79. SkSerialProcs procs;
  80. procs.fPictureProc = proc;
  81. procs.fPictureCtx = ctx;
  82. return procs;
  83. }
  84. static SkDeserialProcs maked(SkDeserialPictureProc proc, const void* ctx = nullptr) {
  85. SkDeserialProcs procs;
  86. procs.fPictureProc = proc;
  87. procs.fPictureCtx = const_cast<void*>(ctx);
  88. return procs;
  89. }
  90. // packages the picture's point in the skdata, and records it in the ctx as an array
  91. struct Context {
  92. SkTDArray<SkPicture*> fArray;
  93. SkPicture* fSkipMe = nullptr;
  94. };
  95. static sk_sp<SkData> array_serial_proc(SkPicture* pic, void* ctx) {
  96. Context* c = (Context*)ctx;
  97. if (c->fSkipMe == pic) {
  98. return nullptr;
  99. }
  100. *c->fArray.append() = pic;
  101. return SkData::MakeWithCopy(&pic, sizeof(pic));
  102. }
  103. static sk_sp<SkPicture> array_deserial_proc(const void* data, size_t size, void* ctx) {
  104. SkASSERT(sizeof(SkPicture*) == size);
  105. Context* c = (Context*)ctx;
  106. SkPicture* pic;
  107. memcpy(&pic, data, size);
  108. int index = c->fArray.find(pic);
  109. SkASSERT(index >= 0);
  110. c->fArray.removeShuffle(index);
  111. return sk_ref_sp(pic);
  112. }
  113. static void test_pictures(skiatest::Reporter* reporter, sk_sp<SkPicture> p0, int count,
  114. bool skipRoot) {
  115. Context ctx;
  116. if (skipRoot) {
  117. ctx.fSkipMe = p0.get();
  118. }
  119. SkSerialProcs sprocs = makes(array_serial_proc, &ctx);
  120. auto d0 = p0->serialize(&sprocs);
  121. REPORTER_ASSERT(reporter, ctx.fArray.count() == count);
  122. SkDeserialProcs dprocs = maked(array_deserial_proc, &ctx);
  123. p0 = SkPicture::MakeFromData(d0.get(), &dprocs);
  124. REPORTER_ASSERT(reporter, ctx.fArray.count() == 0);
  125. }
  126. DEF_TEST(serial_procs_picture, reporter) {
  127. auto p1 = make_pic([](SkCanvas* c) {
  128. // need to be large enough that drawPictures doesn't "unroll" us
  129. for (int i = 0; i < 20; ++i) {
  130. c->drawColor(SK_ColorRED);
  131. }
  132. });
  133. // now use custom serialization
  134. auto p0 = make_pic([](SkCanvas* c) { c->drawColor(SK_ColorBLUE); });
  135. test_pictures(reporter, p0, 1, false);
  136. // test inside effect
  137. p0 = make_pic([p1](SkCanvas* c) {
  138. SkPaint paint;
  139. SkTileMode tm = SkTileMode::kClamp;
  140. paint.setShader(p1->makeShader(tm, tm));
  141. c->drawPaint(paint);
  142. });
  143. test_pictures(reporter, p0, 1, true);
  144. // test nested picture
  145. p0 = make_pic([p1](SkCanvas* c) {
  146. c->drawColor(SK_ColorRED);
  147. c->drawPicture(p1);
  148. c->drawColor(SK_ColorBLUE);
  149. });
  150. test_pictures(reporter, p0, 1, true);
  151. }
  152. static sk_sp<SkPicture> make_picture(sk_sp<SkTypeface> tf0, sk_sp<SkTypeface> tf1) {
  153. SkPictureRecorder rec;
  154. SkCanvas* canvas = rec.beginRecording(100, 100);
  155. SkPaint paint;
  156. SkFont font;
  157. font.setTypeface(tf0); canvas->drawString("hello", 0, 0, font, paint);
  158. font.setTypeface(tf1); canvas->drawString("hello", 0, 0, font, paint);
  159. font.setTypeface(tf0); canvas->drawString("hello", 0, 0, font, paint);
  160. font.setTypeface(tf1); canvas->drawString("hello", 0, 0, font, paint);
  161. return rec.finishRecordingAsPicture();
  162. }
  163. DEF_TEST(serial_typeface, reporter) {
  164. auto tf0 = MakeResourceAsTypeface("fonts/hintgasp.ttf");
  165. auto tf1 = MakeResourceAsTypeface("fonts/Roboto2-Regular_NoEmbed.ttf");
  166. if (!tf0 || !tf1 || tf0.get() == tf1.get()) {
  167. return; // need two different typefaces for this test to make sense.
  168. }
  169. auto pic = make_picture(tf0, tf1);
  170. int counter = 0;
  171. SkSerialProcs procs;
  172. procs.fTypefaceProc = [](SkTypeface* tf, void* ctx) -> sk_sp<SkData> {
  173. *(int*)ctx += 1;
  174. return nullptr;
  175. };
  176. procs.fTypefaceCtx = &counter;
  177. auto data = pic->serialize(&procs);
  178. // The picture has 2 references to each typeface, but we want the serialized picture to
  179. // only have written the data 1 time per typeface.
  180. REPORTER_ASSERT(reporter, counter == 2);
  181. }