1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2013 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 * This test confirms that a MultiPictureDocument can be serialized and deserailzied without error. 8cb93a386Sopenharmony_ci * And that the pictures within it are re-created accurately 9cb93a386Sopenharmony_ci */ 10cb93a386Sopenharmony_ci 11cb93a386Sopenharmony_ci#include "include/core/SkCanvas.h" 12cb93a386Sopenharmony_ci#include "include/core/SkColorPriv.h" 13cb93a386Sopenharmony_ci#include "include/core/SkColorSpace.h" 14cb93a386Sopenharmony_ci#include "include/core/SkDocument.h" 15cb93a386Sopenharmony_ci#include "include/core/SkFont.h" 16cb93a386Sopenharmony_ci#include "include/core/SkImage.h" 17cb93a386Sopenharmony_ci#include "include/core/SkPicture.h" 18cb93a386Sopenharmony_ci#include "include/core/SkPictureRecorder.h" 19cb93a386Sopenharmony_ci#include "include/core/SkString.h" 20cb93a386Sopenharmony_ci#include "include/core/SkSurface.h" 21cb93a386Sopenharmony_ci#include "include/core/SkTextBlob.h" 22cb93a386Sopenharmony_ci#include "src/gpu/GrCaps.h" 23cb93a386Sopenharmony_ci#include "src/utils/SkMultiPictureDocument.h" 24cb93a386Sopenharmony_ci#include "tests/Test.h" 25cb93a386Sopenharmony_ci#include "tools/SkSharingProc.h" 26cb93a386Sopenharmony_ci#include "tools/ToolUtils.h" 27cb93a386Sopenharmony_ci 28cb93a386Sopenharmony_ci// Covers rects, ovals, paths, images, text 29cb93a386Sopenharmony_cistatic void draw_basic(SkCanvas* canvas, int seed, sk_sp<SkImage> image) { 30cb93a386Sopenharmony_ci canvas->drawColor(SK_ColorWHITE); 31cb93a386Sopenharmony_ci 32cb93a386Sopenharmony_ci SkPaint paint; 33cb93a386Sopenharmony_ci paint.setStyle(SkPaint::kStroke_Style); 34cb93a386Sopenharmony_ci paint.setStrokeWidth(seed); 35cb93a386Sopenharmony_ci paint.setColor(SK_ColorRED); 36cb93a386Sopenharmony_ci 37cb93a386Sopenharmony_ci SkRect rect = SkRect::MakeXYWH(50+seed, 50+seed, 4*seed, 60); 38cb93a386Sopenharmony_ci canvas->drawRect(rect, paint); 39cb93a386Sopenharmony_ci 40cb93a386Sopenharmony_ci SkRRect oval; 41cb93a386Sopenharmony_ci oval.setOval(rect); 42cb93a386Sopenharmony_ci oval.offset(40, 60+seed); 43cb93a386Sopenharmony_ci paint.setColor(SK_ColorBLUE); 44cb93a386Sopenharmony_ci canvas->drawRRect(oval, paint); 45cb93a386Sopenharmony_ci 46cb93a386Sopenharmony_ci paint.setColor(SK_ColorCYAN); 47cb93a386Sopenharmony_ci canvas->drawCircle(180, 50, 5*seed, paint); 48cb93a386Sopenharmony_ci 49cb93a386Sopenharmony_ci rect.offset(80, 0); 50cb93a386Sopenharmony_ci paint.setColor(SK_ColorYELLOW); 51cb93a386Sopenharmony_ci canvas->drawRoundRect(rect, 10, 10, paint); 52cb93a386Sopenharmony_ci 53cb93a386Sopenharmony_ci SkPath path; 54cb93a386Sopenharmony_ci path.cubicTo(768, 0, -512, 256, 256, 256); 55cb93a386Sopenharmony_ci paint.setColor(SK_ColorGREEN); 56cb93a386Sopenharmony_ci canvas->drawPath(path, paint); 57cb93a386Sopenharmony_ci 58cb93a386Sopenharmony_ci canvas->drawImage(image, 128-seed, 128, SkSamplingOptions(), &paint); 59cb93a386Sopenharmony_ci 60cb93a386Sopenharmony_ci if (seed % 2 == 0) { 61cb93a386Sopenharmony_ci SkRect rect2 = SkRect::MakeXYWH(0, 0, 40, 60); 62cb93a386Sopenharmony_ci canvas->drawImageRect(image, rect2, SkSamplingOptions(), &paint); 63cb93a386Sopenharmony_ci } 64cb93a386Sopenharmony_ci 65cb93a386Sopenharmony_ci SkPaint paint2; 66cb93a386Sopenharmony_ci auto text = SkTextBlob::MakeFromString( 67cb93a386Sopenharmony_ci SkStringPrintf("Frame %d", seed).c_str(), SkFont(nullptr, 2+seed)); 68cb93a386Sopenharmony_ci canvas->drawTextBlob(text.get(), 50, 25, paint2); 69cb93a386Sopenharmony_ci} 70cb93a386Sopenharmony_ci 71cb93a386Sopenharmony_ci// Covers all of the above and drawing nested sub-pictures. 72cb93a386Sopenharmony_cistatic void draw_advanced(SkCanvas* canvas, int seed, sk_sp<SkImage> image, sk_sp<SkPicture> sub) { 73cb93a386Sopenharmony_ci draw_basic(canvas, seed, image); 74cb93a386Sopenharmony_ci 75cb93a386Sopenharmony_ci // Use subpicture twice in different places 76cb93a386Sopenharmony_ci canvas->drawPicture(sub); 77cb93a386Sopenharmony_ci canvas->save(); 78cb93a386Sopenharmony_ci canvas->translate(seed, seed); 79cb93a386Sopenharmony_ci canvas->drawPicture(sub); 80cb93a386Sopenharmony_ci canvas->restore(); 81cb93a386Sopenharmony_ci} 82cb93a386Sopenharmony_ci 83cb93a386Sopenharmony_ci// Test serialization and deserialization of multi picture document 84cb93a386Sopenharmony_ciDEF_TEST(SkMultiPictureDocument_Serialize_and_deserialize, reporter) { 85cb93a386Sopenharmony_ci // Create the stream we will serialize into. 86cb93a386Sopenharmony_ci SkDynamicMemoryWStream stream; 87cb93a386Sopenharmony_ci 88cb93a386Sopenharmony_ci // Create the image sharing proc. 89cb93a386Sopenharmony_ci SkSharingSerialContext ctx; 90cb93a386Sopenharmony_ci SkSerialProcs procs; 91cb93a386Sopenharmony_ci procs.fImageProc = SkSharingSerialContext::serializeImage; 92cb93a386Sopenharmony_ci procs.fImageCtx = &ctx; 93cb93a386Sopenharmony_ci 94cb93a386Sopenharmony_ci // Create the multi picture document used for recording frames. 95cb93a386Sopenharmony_ci sk_sp<SkDocument> multipic = SkMakeMultiPictureDocument(&stream, &procs); 96cb93a386Sopenharmony_ci 97cb93a386Sopenharmony_ci static const int NUM_FRAMES = 12; 98cb93a386Sopenharmony_ci static const int WIDTH = 256; 99cb93a386Sopenharmony_ci static const int HEIGHT = 256; 100cb93a386Sopenharmony_ci 101cb93a386Sopenharmony_ci // Make an image to be used in a later step. 102cb93a386Sopenharmony_ci auto surface(SkSurface::MakeRasterN32Premul(100, 100)); 103cb93a386Sopenharmony_ci surface->getCanvas()->clear(SK_ColorGREEN); 104cb93a386Sopenharmony_ci sk_sp<SkImage> image(surface->makeImageSnapshot()); 105cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, image); 106cb93a386Sopenharmony_ci 107cb93a386Sopenharmony_ci // Make a subpicture to be used in a later step 108cb93a386Sopenharmony_ci SkPictureRecorder pr; 109cb93a386Sopenharmony_ci SkCanvas* subCanvas = pr.beginRecording(100, 100); 110cb93a386Sopenharmony_ci draw_basic(subCanvas, 42, image); 111cb93a386Sopenharmony_ci sk_sp<SkPicture> sub = pr.finishRecordingAsPicture(); 112cb93a386Sopenharmony_ci 113cb93a386Sopenharmony_ci const SkImageInfo info = SkImageInfo::MakeN32Premul(WIDTH, HEIGHT); 114cb93a386Sopenharmony_ci std::vector<sk_sp<SkImage>> expectedImages; 115cb93a386Sopenharmony_ci 116cb93a386Sopenharmony_ci for (int i=0; i<NUM_FRAMES; i++) { 117cb93a386Sopenharmony_ci SkCanvas* pictureCanvas = multipic->beginPage(WIDTH, HEIGHT); 118cb93a386Sopenharmony_ci draw_advanced(pictureCanvas, i, image, sub); 119cb93a386Sopenharmony_ci multipic->endPage(); 120cb93a386Sopenharmony_ci // Also draw the picture to an image for later comparison 121cb93a386Sopenharmony_ci auto surf = SkSurface::MakeRaster(info); 122cb93a386Sopenharmony_ci draw_advanced(surf->getCanvas(), i, image, sub); 123cb93a386Sopenharmony_ci expectedImages.push_back(surf->makeImageSnapshot()); 124cb93a386Sopenharmony_ci } 125cb93a386Sopenharmony_ci // Finalize 126cb93a386Sopenharmony_ci multipic->close(); 127cb93a386Sopenharmony_ci 128cb93a386Sopenharmony_ci // Confirm written data is at least as large as the magic word 129cb93a386Sopenharmony_ci std::unique_ptr<SkStreamAsset> writtenStream = stream.detachAsStream(); 130cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, writtenStream->getLength() > 24, 131cb93a386Sopenharmony_ci "Written data length too short (%zu)", writtenStream->getLength()); 132cb93a386Sopenharmony_ci // SkDebugf("Multi Frame file size = %zu\n", writtenStream->getLength()); 133cb93a386Sopenharmony_ci 134cb93a386Sopenharmony_ci // Set up deserialization 135cb93a386Sopenharmony_ci SkSharingDeserialContext deserialContext; 136cb93a386Sopenharmony_ci SkDeserialProcs dprocs; 137cb93a386Sopenharmony_ci dprocs.fImageProc = SkSharingDeserialContext::deserializeImage; 138cb93a386Sopenharmony_ci dprocs.fImageCtx = &deserialContext; 139cb93a386Sopenharmony_ci 140cb93a386Sopenharmony_ci // Confirm data is a MultiPictureDocument 141cb93a386Sopenharmony_ci int frame_count = SkMultiPictureDocumentReadPageCount(writtenStream.get()); 142cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, frame_count == NUM_FRAMES, 143cb93a386Sopenharmony_ci "Expected %d frames, got %d. \n 0 frames may indicate the written file was not a " 144cb93a386Sopenharmony_ci "MultiPictureDocument.", NUM_FRAMES, frame_count); 145cb93a386Sopenharmony_ci 146cb93a386Sopenharmony_ci // Deserailize 147cb93a386Sopenharmony_ci std::vector<SkDocumentPage> frames(frame_count); 148cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 149cb93a386Sopenharmony_ci SkMultiPictureDocumentRead(writtenStream.get(), frames.data(), frame_count, &dprocs), 150cb93a386Sopenharmony_ci "Failed while reading MultiPictureDocument"); 151cb93a386Sopenharmony_ci 152cb93a386Sopenharmony_ci // Examine each frame. 153cb93a386Sopenharmony_ci int i=0; 154cb93a386Sopenharmony_ci for (const auto& frame : frames) { 155cb93a386Sopenharmony_ci SkRect bounds = frame.fPicture->cullRect(); 156cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, bounds.width() == WIDTH, 157cb93a386Sopenharmony_ci "Page width: expected (%d) got (%d)", WIDTH, (int)bounds.width()); 158cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, bounds.height() == HEIGHT, 159cb93a386Sopenharmony_ci "Page height: expected (%d) got (%d)", HEIGHT, (int)bounds.height()); 160cb93a386Sopenharmony_ci 161cb93a386Sopenharmony_ci auto surf = SkSurface::MakeRaster(info); 162cb93a386Sopenharmony_ci surf->getCanvas()->drawPicture(frame.fPicture); 163cb93a386Sopenharmony_ci auto img = surf->makeImageSnapshot(); 164cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, ToolUtils::equal_pixels(img.get(), expectedImages[i].get())); 165cb93a386Sopenharmony_ci 166cb93a386Sopenharmony_ci i++; 167cb93a386Sopenharmony_ci } 168cb93a386Sopenharmony_ci} 169cb93a386Sopenharmony_ci 170cb93a386Sopenharmony_ci 171cb93a386Sopenharmony_ci#if SK_SUPPORT_GPU && defined(SK_BUILD_FOR_ANDROID) && __ANDROID_API__ >= 26 172cb93a386Sopenharmony_ci 173cb93a386Sopenharmony_ci#include "include/gpu/GrDirectContext.h" 174cb93a386Sopenharmony_ci#include "src/gpu/GrAHardwareBufferUtils.h" 175cb93a386Sopenharmony_ci#include "src/gpu/GrDirectContextPriv.h" 176cb93a386Sopenharmony_ci 177cb93a386Sopenharmony_ci#include <android/hardware_buffer.h> 178cb93a386Sopenharmony_ci 179cb93a386Sopenharmony_cistatic const int DEV_W = 16, DEV_H = 16; 180cb93a386Sopenharmony_ci 181cb93a386Sopenharmony_cistatic SkPMColor get_src_color(int x, int y) { 182cb93a386Sopenharmony_ci SkASSERT(x >= 0 && x < DEV_W); 183cb93a386Sopenharmony_ci SkASSERT(y >= 0 && y < DEV_H); 184cb93a386Sopenharmony_ci 185cb93a386Sopenharmony_ci U8CPU r = x; 186cb93a386Sopenharmony_ci U8CPU g = y; 187cb93a386Sopenharmony_ci U8CPU b = 0xc; 188cb93a386Sopenharmony_ci 189cb93a386Sopenharmony_ci U8CPU a = 0xff; 190cb93a386Sopenharmony_ci switch ((x+y) % 5) { 191cb93a386Sopenharmony_ci case 0: 192cb93a386Sopenharmony_ci a = 0xff; 193cb93a386Sopenharmony_ci break; 194cb93a386Sopenharmony_ci case 1: 195cb93a386Sopenharmony_ci a = 0x80; 196cb93a386Sopenharmony_ci break; 197cb93a386Sopenharmony_ci case 2: 198cb93a386Sopenharmony_ci a = 0xCC; 199cb93a386Sopenharmony_ci break; 200cb93a386Sopenharmony_ci case 4: 201cb93a386Sopenharmony_ci a = 0x01; 202cb93a386Sopenharmony_ci break; 203cb93a386Sopenharmony_ci case 3: 204cb93a386Sopenharmony_ci a = 0x00; 205cb93a386Sopenharmony_ci break; 206cb93a386Sopenharmony_ci } 207cb93a386Sopenharmony_ci a = 0xff; 208cb93a386Sopenharmony_ci return SkPremultiplyARGBInline(a, r, g, b); 209cb93a386Sopenharmony_ci} 210cb93a386Sopenharmony_ci 211cb93a386Sopenharmony_cistatic SkBitmap make_src_bitmap() { 212cb93a386Sopenharmony_ci static SkBitmap bmp; 213cb93a386Sopenharmony_ci if (bmp.isNull()) { 214cb93a386Sopenharmony_ci bmp.allocN32Pixels(DEV_W, DEV_H); 215cb93a386Sopenharmony_ci intptr_t pixels = reinterpret_cast<intptr_t>(bmp.getPixels()); 216cb93a386Sopenharmony_ci for (int y = 0; y < DEV_H; ++y) { 217cb93a386Sopenharmony_ci for (int x = 0; x < DEV_W; ++x) { 218cb93a386Sopenharmony_ci SkPMColor* pixel = reinterpret_cast<SkPMColor*>( 219cb93a386Sopenharmony_ci pixels + y * bmp.rowBytes() + x * bmp.bytesPerPixel()); 220cb93a386Sopenharmony_ci *pixel = get_src_color(x, y); 221cb93a386Sopenharmony_ci } 222cb93a386Sopenharmony_ci } 223cb93a386Sopenharmony_ci } 224cb93a386Sopenharmony_ci return bmp; 225cb93a386Sopenharmony_ci} 226cb93a386Sopenharmony_ci 227cb93a386Sopenharmony_cistatic void cleanup_resources(AHardwareBuffer* buffer) { 228cb93a386Sopenharmony_ci if (buffer) { 229cb93a386Sopenharmony_ci AHardwareBuffer_release(buffer); 230cb93a386Sopenharmony_ci } 231cb93a386Sopenharmony_ci} 232cb93a386Sopenharmony_ci 233cb93a386Sopenharmony_cistatic sk_sp<SkImage> makeAHardwareBufferTestImage( 234cb93a386Sopenharmony_ci skiatest::Reporter* reporter, GrDirectContext* context, AHardwareBuffer* buffer) { 235cb93a386Sopenharmony_ci 236cb93a386Sopenharmony_ci const SkBitmap srcBitmap = make_src_bitmap(); 237cb93a386Sopenharmony_ci 238cb93a386Sopenharmony_ci AHardwareBuffer_Desc hwbDesc; 239cb93a386Sopenharmony_ci hwbDesc.width = DEV_W; 240cb93a386Sopenharmony_ci hwbDesc.height = DEV_H; 241cb93a386Sopenharmony_ci hwbDesc.layers = 1; 242cb93a386Sopenharmony_ci hwbDesc.usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN | 243cb93a386Sopenharmony_ci AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN | 244cb93a386Sopenharmony_ci AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE; 245cb93a386Sopenharmony_ci hwbDesc.format = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM; 246cb93a386Sopenharmony_ci // The following three are not used in the allocate 247cb93a386Sopenharmony_ci hwbDesc.stride = 0; 248cb93a386Sopenharmony_ci hwbDesc.rfu0= 0; 249cb93a386Sopenharmony_ci hwbDesc.rfu1= 0; 250cb93a386Sopenharmony_ci 251cb93a386Sopenharmony_ci if (int error = AHardwareBuffer_allocate(&hwbDesc, &buffer)) { 252cb93a386Sopenharmony_ci ERRORF(reporter, "Failed to allocated hardware buffer, error: %d", error); 253cb93a386Sopenharmony_ci cleanup_resources(buffer); 254cb93a386Sopenharmony_ci return nullptr; 255cb93a386Sopenharmony_ci } 256cb93a386Sopenharmony_ci 257cb93a386Sopenharmony_ci // Get actual desc for allocated buffer so we know the stride for uploading cpu data. 258cb93a386Sopenharmony_ci AHardwareBuffer_describe(buffer, &hwbDesc); 259cb93a386Sopenharmony_ci 260cb93a386Sopenharmony_ci void* bufferAddr; 261cb93a386Sopenharmony_ci if (AHardwareBuffer_lock(buffer, AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN, -1, nullptr, 262cb93a386Sopenharmony_ci &bufferAddr)) { 263cb93a386Sopenharmony_ci ERRORF(reporter, "Failed to lock hardware buffer"); 264cb93a386Sopenharmony_ci cleanup_resources(buffer); 265cb93a386Sopenharmony_ci return nullptr; 266cb93a386Sopenharmony_ci } 267cb93a386Sopenharmony_ci 268cb93a386Sopenharmony_ci // fill buffer 269cb93a386Sopenharmony_ci int bbp = srcBitmap.bytesPerPixel(); 270cb93a386Sopenharmony_ci uint32_t* src = (uint32_t*)srcBitmap.getPixels(); 271cb93a386Sopenharmony_ci int nextLineStep = DEV_W; 272cb93a386Sopenharmony_ci uint32_t* dst = static_cast<uint32_t*>(bufferAddr); 273cb93a386Sopenharmony_ci for (int y = 0; y < DEV_H; ++y) { 274cb93a386Sopenharmony_ci memcpy(dst, src, DEV_W * bbp); 275cb93a386Sopenharmony_ci src += nextLineStep; 276cb93a386Sopenharmony_ci dst += hwbDesc.stride; 277cb93a386Sopenharmony_ci } 278cb93a386Sopenharmony_ci AHardwareBuffer_unlock(buffer, nullptr); 279cb93a386Sopenharmony_ci 280cb93a386Sopenharmony_ci // Make SkImage from buffer in a way that mimics libs/hwui/AutoBackendTextureRelease 281cb93a386Sopenharmony_ci GrBackendFormat backendFormat = 282cb93a386Sopenharmony_ci GrAHardwareBufferUtils::GetBackendFormat(context, buffer, hwbDesc.format, false); 283cb93a386Sopenharmony_ci GrAHardwareBufferUtils::DeleteImageProc deleteProc; 284cb93a386Sopenharmony_ci GrAHardwareBufferUtils::UpdateImageProc updateProc; 285cb93a386Sopenharmony_ci GrAHardwareBufferUtils::TexImageCtx imageCtx; 286cb93a386Sopenharmony_ci GrBackendTexture texture = GrAHardwareBufferUtils::MakeBackendTexture( 287cb93a386Sopenharmony_ci context, buffer, hwbDesc.width, hwbDesc.height, 288cb93a386Sopenharmony_ci &deleteProc, // set by MakeBackendTexture 289cb93a386Sopenharmony_ci &updateProc, // set by MakeBackendTexture 290cb93a386Sopenharmony_ci &imageCtx, // set by MakeBackendTexture 291cb93a386Sopenharmony_ci false, // don't make protected image 292cb93a386Sopenharmony_ci backendFormat, 293cb93a386Sopenharmony_ci false // isRenderable 294cb93a386Sopenharmony_ci ); 295cb93a386Sopenharmony_ci SkColorType colorType = GrAHardwareBufferUtils::GetSkColorTypeFromBufferFormat(hwbDesc.format); 296cb93a386Sopenharmony_ci sk_sp<SkImage> image = SkImage::MakeFromTexture( 297cb93a386Sopenharmony_ci context, texture, kTopLeft_GrSurfaceOrigin, colorType, kPremul_SkAlphaType, 298cb93a386Sopenharmony_ci SkColorSpace::MakeSRGB(), 299cb93a386Sopenharmony_ci nullptr, // no release proc 300cb93a386Sopenharmony_ci nullptr // context for release proc 301cb93a386Sopenharmony_ci ); 302cb93a386Sopenharmony_ci 303cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, image); 304cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, image->isTextureBacked()); 305cb93a386Sopenharmony_ci return image; 306cb93a386Sopenharmony_ci} 307cb93a386Sopenharmony_ci 308cb93a386Sopenharmony_ci// Test the onEndPage callback's intended use by processing an mskp containing AHardwareBuffer-backed SkImages 309cb93a386Sopenharmony_ci// Expected behavior is that the callback is called while the AHardwareBuffer is still valid and the 310cb93a386Sopenharmony_ci// images are copied so .close() can still access them. 311cb93a386Sopenharmony_ci// Confirm deserialized file contains images with correct data. 312cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkMultiPictureDocument_AHardwarebuffer, 313cb93a386Sopenharmony_ci reporter, ctx_info) { 314cb93a386Sopenharmony_ci auto context = ctx_info.directContext(); 315cb93a386Sopenharmony_ci if (!context->priv().caps()->supportsAHardwareBufferImages()) { 316cb93a386Sopenharmony_ci return; 317cb93a386Sopenharmony_ci } 318cb93a386Sopenharmony_ci 319cb93a386Sopenharmony_ci // Create the stream we will serialize into. 320cb93a386Sopenharmony_ci SkDynamicMemoryWStream stream; 321cb93a386Sopenharmony_ci 322cb93a386Sopenharmony_ci // Create the image sharing proc. 323cb93a386Sopenharmony_ci SkSharingSerialContext ctx; 324cb93a386Sopenharmony_ci SkSerialProcs procs; 325cb93a386Sopenharmony_ci procs.fImageProc = SkSharingSerialContext::serializeImage; 326cb93a386Sopenharmony_ci procs.fImageCtx = &ctx; 327cb93a386Sopenharmony_ci 328cb93a386Sopenharmony_ci // Create the multi picture document used for recording frames. 329cb93a386Sopenharmony_ci // Pass a lambda as the onEndPage callback that captures our sharing context 330cb93a386Sopenharmony_ci sk_sp<SkDocument> multipic = SkMakeMultiPictureDocument(&stream, &procs, 331cb93a386Sopenharmony_ci [sharingCtx = &ctx](const SkPicture* pic) { 332cb93a386Sopenharmony_ci SkSharingSerialContext::collectNonTextureImagesFromPicture(pic, sharingCtx); 333cb93a386Sopenharmony_ci }); 334cb93a386Sopenharmony_ci 335cb93a386Sopenharmony_ci static const int WIDTH = 256; 336cb93a386Sopenharmony_ci static const int HEIGHT = 256; 337cb93a386Sopenharmony_ci 338cb93a386Sopenharmony_ci // Make an image to be used in a later step. 339cb93a386Sopenharmony_ci AHardwareBuffer* ahbuffer = nullptr; 340cb93a386Sopenharmony_ci sk_sp<SkImage> image = makeAHardwareBufferTestImage(reporter, context, ahbuffer); 341cb93a386Sopenharmony_ci 342cb93a386Sopenharmony_ci const SkImageInfo info = SkImageInfo::MakeN32Premul(WIDTH, HEIGHT); 343cb93a386Sopenharmony_ci std::vector<sk_sp<SkImage>> expectedImages; 344cb93a386Sopenharmony_ci 345cb93a386Sopenharmony_ci // Record single frame 346cb93a386Sopenharmony_ci SkCanvas* pictureCanvas = multipic->beginPage(WIDTH, HEIGHT); 347cb93a386Sopenharmony_ci draw_basic(pictureCanvas, 0, image); 348cb93a386Sopenharmony_ci multipic->endPage(); 349cb93a386Sopenharmony_ci // Also draw the picture to an image for later comparison 350cb93a386Sopenharmony_ci auto surf = SkSurface::MakeRaster(info); 351cb93a386Sopenharmony_ci draw_basic(surf->getCanvas(), 0, image); 352cb93a386Sopenharmony_ci expectedImages.push_back(surf->makeImageSnapshot()); 353cb93a386Sopenharmony_ci 354cb93a386Sopenharmony_ci // Release Ahardwarebuffer. If the code under test has not copied it already, 355cb93a386Sopenharmony_ci // close() will fail. 356cb93a386Sopenharmony_ci // Note that this only works because we're doing one frame only. If this test were recording 357cb93a386Sopenharmony_ci // two or more frames, it would have change the buffer contents instead. 358cb93a386Sopenharmony_ci cleanup_resources(ahbuffer); 359cb93a386Sopenharmony_ci 360cb93a386Sopenharmony_ci // Finalize 361cb93a386Sopenharmony_ci multipic->close(); 362cb93a386Sopenharmony_ci 363cb93a386Sopenharmony_ci // Confirm written data is at least as large as the magic word 364cb93a386Sopenharmony_ci std::unique_ptr<SkStreamAsset> writtenStream = stream.detachAsStream(); 365cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, writtenStream->getLength() > 24, 366cb93a386Sopenharmony_ci "Written data length too short (%zu)", writtenStream->getLength()); 367cb93a386Sopenharmony_ci 368cb93a386Sopenharmony_ci // Set up deserialization 369cb93a386Sopenharmony_ci SkSharingDeserialContext deserialContext; 370cb93a386Sopenharmony_ci SkDeserialProcs dprocs; 371cb93a386Sopenharmony_ci dprocs.fImageProc = SkSharingDeserialContext::deserializeImage; 372cb93a386Sopenharmony_ci dprocs.fImageCtx = &deserialContext; 373cb93a386Sopenharmony_ci 374cb93a386Sopenharmony_ci // Confirm data is a MultiPictureDocument 375cb93a386Sopenharmony_ci int frame_count = SkMultiPictureDocumentReadPageCount(writtenStream.get()); 376cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, frame_count == 1, 377cb93a386Sopenharmony_ci "Expected 1 frame, got %d. \n 0 frames may indicate the written file was not a " 378cb93a386Sopenharmony_ci "MultiPictureDocument.", frame_count); 379cb93a386Sopenharmony_ci 380cb93a386Sopenharmony_ci // Deserialize 381cb93a386Sopenharmony_ci std::vector<SkDocumentPage> frames(frame_count); 382cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 383cb93a386Sopenharmony_ci SkMultiPictureDocumentRead(writtenStream.get(), frames.data(), frame_count, &dprocs), 384cb93a386Sopenharmony_ci "Failed while reading MultiPictureDocument"); 385cb93a386Sopenharmony_ci 386cb93a386Sopenharmony_ci // Examine frame. 387cb93a386Sopenharmony_ci SkRect bounds = frames[0].fPicture->cullRect(); 388cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, bounds.width() == WIDTH, 389cb93a386Sopenharmony_ci "Page width: expected (%d) got (%d)", WIDTH, (int)bounds.width()); 390cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, bounds.height() == HEIGHT, 391cb93a386Sopenharmony_ci "Page height: expected (%d) got (%d)", HEIGHT, (int)bounds.height()); 392cb93a386Sopenharmony_ci 393cb93a386Sopenharmony_ci auto surf2 = SkSurface::MakeRaster(info); 394cb93a386Sopenharmony_ci surf2->getCanvas()->drawPicture(frames[0].fPicture); 395cb93a386Sopenharmony_ci auto img = surf2->makeImageSnapshot(); 396cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, ToolUtils::equal_pixels(img.get(), expectedImages[0].get())); 397cb93a386Sopenharmony_ci} 398cb93a386Sopenharmony_ci 399cb93a386Sopenharmony_ci#endif // android compilation 400