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