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