1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2019 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 "tools/SkSharingProc.h"
9cb93a386Sopenharmony_ci
10cb93a386Sopenharmony_ci#include "include/core/SkBitmap.h"
11cb93a386Sopenharmony_ci#include "include/core/SkData.h"
12cb93a386Sopenharmony_ci#include "include/core/SkImage.h"
13cb93a386Sopenharmony_ci#include "include/core/SkSerialProcs.h"
14cb93a386Sopenharmony_ci
15cb93a386Sopenharmony_cinamespace {
16cb93a386Sopenharmony_ci    sk_sp<SkData> collectNonTextureImagesProc(SkImage* img, void* ctx) {
17cb93a386Sopenharmony_ci        SkSharingSerialContext* context = reinterpret_cast<SkSharingSerialContext*>(ctx);
18cb93a386Sopenharmony_ci        uint32_t originalId = img->uniqueID();
19cb93a386Sopenharmony_ci        auto it = context->fNonTexMap.find(originalId);
20cb93a386Sopenharmony_ci        if (it == context->fNonTexMap.end()) {
21cb93a386Sopenharmony_ci            context->fNonTexMap[originalId] = img->makeNonTextureImage();
22cb93a386Sopenharmony_ci        }
23cb93a386Sopenharmony_ci        return SkData::MakeEmpty();
24cb93a386Sopenharmony_ci    }
25cb93a386Sopenharmony_ci}
26cb93a386Sopenharmony_ci
27cb93a386Sopenharmony_ciSK_API void SkSharingSerialContext::collectNonTextureImagesFromPicture(
28cb93a386Sopenharmony_ci    const SkPicture* pic, SkSharingSerialContext* sharingCtx) {
29cb93a386Sopenharmony_ci    SkSerialProcs tempProc;
30cb93a386Sopenharmony_ci    tempProc.fImageCtx = sharingCtx;
31cb93a386Sopenharmony_ci    tempProc.fImageProc = collectNonTextureImagesProc;
32cb93a386Sopenharmony_ci    SkNullWStream ns;
33cb93a386Sopenharmony_ci    pic->serialize(&ns, &tempProc);
34cb93a386Sopenharmony_ci}
35cb93a386Sopenharmony_ci
36cb93a386Sopenharmony_ciSK_API sk_sp<SkData> SkSharingSerialContext::serializeImage(SkImage* img, void* ctx) {
37cb93a386Sopenharmony_ci    SkSharingSerialContext* context = reinterpret_cast<SkSharingSerialContext*>(ctx);
38cb93a386Sopenharmony_ci    uint32_t id = img->uniqueID(); // get this process's id for the image. these are not hashes.
39cb93a386Sopenharmony_ci    // find out if we have already serialized this, and if so, what its in-file id is.
40cb93a386Sopenharmony_ci    auto iter = context->fImageMap.find(id);
41cb93a386Sopenharmony_ci    if (iter == context->fImageMap.end()) {
42cb93a386Sopenharmony_ci        // When not present, add its id to the map and return its usual serialized form.
43cb93a386Sopenharmony_ci        context->fImageMap[id] = context->fImageMap.size(); // Next in-file id
44cb93a386Sopenharmony_ci        // encode the image or it's non-texture replacement if one was collected
45cb93a386Sopenharmony_ci        auto iter2 = context->fNonTexMap.find(id);
46cb93a386Sopenharmony_ci        if (iter2 != context->fNonTexMap.end()) {
47cb93a386Sopenharmony_ci            img = iter2->second.get();
48cb93a386Sopenharmony_ci        }
49cb93a386Sopenharmony_ci        return img->encodeToData();
50cb93a386Sopenharmony_ci    }
51cb93a386Sopenharmony_ci    uint32_t fid = context->fImageMap[id];
52cb93a386Sopenharmony_ci    // if present, return only the in-file id we registered the first time we serialized it.
53cb93a386Sopenharmony_ci    return SkData::MakeWithCopy(&fid, sizeof(fid));
54cb93a386Sopenharmony_ci}
55cb93a386Sopenharmony_ci
56cb93a386Sopenharmony_ciSK_API sk_sp<SkImage> SkSharingDeserialContext::deserializeImage(
57cb93a386Sopenharmony_ci  const void* data, size_t length, void* ctx) {
58cb93a386Sopenharmony_ci    if (!data || !length || !ctx) {
59cb93a386Sopenharmony_ci        SkDebugf("SkSharingDeserialContext::deserializeImage arguments invalid %p %zu %p.\n",
60cb93a386Sopenharmony_ci            data, length, ctx);
61cb93a386Sopenharmony_ci        // Return something so the rest of the debugger can proceed.
62cb93a386Sopenharmony_ci        SkBitmap bm;
63cb93a386Sopenharmony_ci        bm.allocPixels(SkImageInfo::MakeN32Premul(1, 1));
64cb93a386Sopenharmony_ci        return bm.asImage();
65cb93a386Sopenharmony_ci    }
66cb93a386Sopenharmony_ci    SkSharingDeserialContext* context = reinterpret_cast<SkSharingDeserialContext*>(ctx);
67cb93a386Sopenharmony_ci    uint32_t fid;
68cb93a386Sopenharmony_ci    // If the data is an image fid, look up an already deserialized image from our map
69cb93a386Sopenharmony_ci    if (length == sizeof(fid)) {
70cb93a386Sopenharmony_ci        memcpy(&fid, data, sizeof(fid));
71cb93a386Sopenharmony_ci        if (fid >= context->fImages.size()) {
72cb93a386Sopenharmony_ci            SkDebugf("Cannot deserialize using id, We do not have the data for image %d.\n", fid);
73cb93a386Sopenharmony_ci            return nullptr;
74cb93a386Sopenharmony_ci        }
75cb93a386Sopenharmony_ci        return context->fImages[fid];
76cb93a386Sopenharmony_ci    }
77cb93a386Sopenharmony_ci    // Otherwise, the data is an image, deserialise it, store it in our map at its fid.
78cb93a386Sopenharmony_ci    // TODO(nifong): make DeserialProcs accept sk_sp<SkData> so we don't have to copy this.
79cb93a386Sopenharmony_ci    sk_sp<SkData> dataView = SkData::MakeWithCopy(data, length);
80cb93a386Sopenharmony_ci    const sk_sp<SkImage> image = SkImage::MakeFromEncoded(std::move(dataView));
81cb93a386Sopenharmony_ci    context->fImages.push_back(image);
82cb93a386Sopenharmony_ci    return image;
83cb93a386Sopenharmony_ci}
84