1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2007 The Android Open Source Project
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/SkPicture.h"
9cb93a386Sopenharmony_ci
10cb93a386Sopenharmony_ci#include "include/core/SkImageGenerator.h"
11cb93a386Sopenharmony_ci#include "include/core/SkPictureRecorder.h"
12cb93a386Sopenharmony_ci#include "include/core/SkSerialProcs.h"
13cb93a386Sopenharmony_ci#include "include/private/SkTo.h"
14cb93a386Sopenharmony_ci#include "src/core/SkCanvasPriv.h"
15cb93a386Sopenharmony_ci#include "src/core/SkMathPriv.h"
16cb93a386Sopenharmony_ci#include "src/core/SkPictureCommon.h"
17cb93a386Sopenharmony_ci#include "src/core/SkPictureData.h"
18cb93a386Sopenharmony_ci#include "src/core/SkPicturePlayback.h"
19cb93a386Sopenharmony_ci#include "src/core/SkPicturePriv.h"
20cb93a386Sopenharmony_ci#include "src/core/SkPictureRecord.h"
21cb93a386Sopenharmony_ci#include "src/core/SkResourceCache.h"
22cb93a386Sopenharmony_ci#include <atomic>
23cb93a386Sopenharmony_ci
24cb93a386Sopenharmony_ci// When we read/write the SkPictInfo via a stream, we have a sentinel byte right after the info.
25cb93a386Sopenharmony_ci// Note: in the read/write buffer versions, we have a slightly different convention:
26cb93a386Sopenharmony_ci//      We have a sentinel int32_t:
27cb93a386Sopenharmony_ci//          0 : failure
28cb93a386Sopenharmony_ci//          1 : PictureData
29cb93a386Sopenharmony_ci//         <0 : -size of the custom data
30cb93a386Sopenharmony_cienum {
31cb93a386Sopenharmony_ci    kFailure_TrailingStreamByteAfterPictInfo     = 0,   // nothing follows
32cb93a386Sopenharmony_ci    kPictureData_TrailingStreamByteAfterPictInfo = 1,   // SkPictureData follows
33cb93a386Sopenharmony_ci    kCustom_TrailingStreamByteAfterPictInfo      = 2,   // -size32 follows
34cb93a386Sopenharmony_ci};
35cb93a386Sopenharmony_ci
36cb93a386Sopenharmony_ci/* SkPicture impl.  This handles generic responsibilities like unique IDs and serialization. */
37cb93a386Sopenharmony_ci
38cb93a386Sopenharmony_ciSkPicture::SkPicture() {
39cb93a386Sopenharmony_ci    static std::atomic<uint32_t> nextID{1};
40cb93a386Sopenharmony_ci    do {
41cb93a386Sopenharmony_ci        fUniqueID = nextID.fetch_add(+1, std::memory_order_relaxed);
42cb93a386Sopenharmony_ci    } while (fUniqueID == 0);
43cb93a386Sopenharmony_ci}
44cb93a386Sopenharmony_ci
45cb93a386Sopenharmony_ciSkPicture::~SkPicture() {
46cb93a386Sopenharmony_ci    if (fAddedToCache.load()) {
47cb93a386Sopenharmony_ci        SkResourceCache::PostPurgeSharedID(SkPicturePriv::MakeSharedID(fUniqueID));
48cb93a386Sopenharmony_ci    }
49cb93a386Sopenharmony_ci}
50cb93a386Sopenharmony_ci
51cb93a386Sopenharmony_cistatic const char kMagic[] = { 's', 'k', 'i', 'a', 'p', 'i', 'c', 't' };
52cb93a386Sopenharmony_ci
53cb93a386Sopenharmony_ciSkPictInfo SkPicture::createHeader() const {
54cb93a386Sopenharmony_ci    SkPictInfo info;
55cb93a386Sopenharmony_ci    // Copy magic bytes at the beginning of the header
56cb93a386Sopenharmony_ci    static_assert(sizeof(kMagic) == 8, "");
57cb93a386Sopenharmony_ci    static_assert(sizeof(kMagic) == sizeof(info.fMagic), "");
58cb93a386Sopenharmony_ci    memcpy(info.fMagic, kMagic, sizeof(kMagic));
59cb93a386Sopenharmony_ci
60cb93a386Sopenharmony_ci    // Set picture info after magic bytes in the header
61cb93a386Sopenharmony_ci    info.setVersion(SkPicturePriv::kCurrent_Version);
62cb93a386Sopenharmony_ci    info.fCullRect = this->cullRect();
63cb93a386Sopenharmony_ci    return info;
64cb93a386Sopenharmony_ci}
65cb93a386Sopenharmony_ci
66cb93a386Sopenharmony_cibool SkPicture::IsValidPictInfo(const SkPictInfo& info) {
67cb93a386Sopenharmony_ci    if (0 != memcmp(info.fMagic, kMagic, sizeof(kMagic))) {
68cb93a386Sopenharmony_ci        return false;
69cb93a386Sopenharmony_ci    }
70cb93a386Sopenharmony_ci    if (info.getVersion() < SkPicturePriv::kMin_Version ||
71cb93a386Sopenharmony_ci        info.getVersion() > SkPicturePriv::kCurrent_Version) {
72cb93a386Sopenharmony_ci        return false;
73cb93a386Sopenharmony_ci    }
74cb93a386Sopenharmony_ci    return true;
75cb93a386Sopenharmony_ci}
76cb93a386Sopenharmony_ci
77cb93a386Sopenharmony_cibool SkPicture::StreamIsSKP(SkStream* stream, SkPictInfo* pInfo) {
78cb93a386Sopenharmony_ci    if (!stream) {
79cb93a386Sopenharmony_ci        return false;
80cb93a386Sopenharmony_ci    }
81cb93a386Sopenharmony_ci
82cb93a386Sopenharmony_ci    SkPictInfo info;
83cb93a386Sopenharmony_ci    SkASSERT(sizeof(kMagic) == sizeof(info.fMagic));
84cb93a386Sopenharmony_ci    if (stream->read(&info.fMagic, sizeof(kMagic)) != sizeof(kMagic)) {
85cb93a386Sopenharmony_ci        return false;
86cb93a386Sopenharmony_ci    }
87cb93a386Sopenharmony_ci
88cb93a386Sopenharmony_ci    uint32_t version;
89cb93a386Sopenharmony_ci    if (!stream->readU32(&version)) { return false; }
90cb93a386Sopenharmony_ci    info.setVersion(version);
91cb93a386Sopenharmony_ci    if (!stream->readScalar(&info.fCullRect.fLeft  )) { return false; }
92cb93a386Sopenharmony_ci    if (!stream->readScalar(&info.fCullRect.fTop   )) { return false; }
93cb93a386Sopenharmony_ci    if (!stream->readScalar(&info.fCullRect.fRight )) { return false; }
94cb93a386Sopenharmony_ci    if (!stream->readScalar(&info.fCullRect.fBottom)) { return false; }
95cb93a386Sopenharmony_ci
96cb93a386Sopenharmony_ci    if (pInfo) {
97cb93a386Sopenharmony_ci        *pInfo = info;
98cb93a386Sopenharmony_ci    }
99cb93a386Sopenharmony_ci    return IsValidPictInfo(info);
100cb93a386Sopenharmony_ci}
101cb93a386Sopenharmony_ci
102cb93a386Sopenharmony_cibool SkPicture_StreamIsSKP(SkStream* stream, SkPictInfo* pInfo) {
103cb93a386Sopenharmony_ci    return SkPicture::StreamIsSKP(stream, pInfo);
104cb93a386Sopenharmony_ci}
105cb93a386Sopenharmony_ci
106cb93a386Sopenharmony_cibool SkPicture::BufferIsSKP(SkReadBuffer* buffer, SkPictInfo* pInfo) {
107cb93a386Sopenharmony_ci    SkPictInfo info;
108cb93a386Sopenharmony_ci    SkASSERT(sizeof(kMagic) == sizeof(info.fMagic));
109cb93a386Sopenharmony_ci    if (!buffer->readByteArray(&info.fMagic, sizeof(kMagic))) {
110cb93a386Sopenharmony_ci        return false;
111cb93a386Sopenharmony_ci    }
112cb93a386Sopenharmony_ci
113cb93a386Sopenharmony_ci    info.setVersion(buffer->readUInt());
114cb93a386Sopenharmony_ci    buffer->readRect(&info.fCullRect);
115cb93a386Sopenharmony_ci
116cb93a386Sopenharmony_ci    if (IsValidPictInfo(info)) {
117cb93a386Sopenharmony_ci        if (pInfo) { *pInfo = info; }
118cb93a386Sopenharmony_ci        return true;
119cb93a386Sopenharmony_ci    }
120cb93a386Sopenharmony_ci    return false;
121cb93a386Sopenharmony_ci}
122cb93a386Sopenharmony_ci
123cb93a386Sopenharmony_cisk_sp<SkPicture> SkPicture::Forwardport(const SkPictInfo& info,
124cb93a386Sopenharmony_ci                                        const SkPictureData* data,
125cb93a386Sopenharmony_ci                                        SkReadBuffer* buffer) {
126cb93a386Sopenharmony_ci    if (!data) {
127cb93a386Sopenharmony_ci        return nullptr;
128cb93a386Sopenharmony_ci    }
129cb93a386Sopenharmony_ci    if (!data->opData()) {
130cb93a386Sopenharmony_ci        return nullptr;
131cb93a386Sopenharmony_ci    }
132cb93a386Sopenharmony_ci    SkPicturePlayback playback(data);
133cb93a386Sopenharmony_ci    SkPictureRecorder r;
134cb93a386Sopenharmony_ci    playback.draw(r.beginRecording(info.fCullRect), nullptr/*no callback*/, buffer);
135cb93a386Sopenharmony_ci    return r.finishRecordingAsPicture();
136cb93a386Sopenharmony_ci}
137cb93a386Sopenharmony_ci
138cb93a386Sopenharmony_cisk_sp<SkPicture> SkPicture::MakeFromStream(SkStream* stream, const SkDeserialProcs* procs) {
139cb93a386Sopenharmony_ci    return MakeFromStream(stream, procs, nullptr);
140cb93a386Sopenharmony_ci}
141cb93a386Sopenharmony_ci
142cb93a386Sopenharmony_cisk_sp<SkPicture> SkPicture::MakeFromData(const void* data, size_t size,
143cb93a386Sopenharmony_ci                                         const SkDeserialProcs* procs) {
144cb93a386Sopenharmony_ci    if (!data) {
145cb93a386Sopenharmony_ci        return nullptr;
146cb93a386Sopenharmony_ci    }
147cb93a386Sopenharmony_ci    SkMemoryStream stream(data, size);
148cb93a386Sopenharmony_ci    return MakeFromStream(&stream, procs, nullptr);
149cb93a386Sopenharmony_ci}
150cb93a386Sopenharmony_ci
151cb93a386Sopenharmony_cisk_sp<SkPicture> SkPicture::MakeFromData(const SkData* data, const SkDeserialProcs* procs) {
152cb93a386Sopenharmony_ci    if (!data) {
153cb93a386Sopenharmony_ci        return nullptr;
154cb93a386Sopenharmony_ci    }
155cb93a386Sopenharmony_ci    SkMemoryStream stream(data->data(), data->size());
156cb93a386Sopenharmony_ci    return MakeFromStream(&stream, procs, nullptr);
157cb93a386Sopenharmony_ci}
158cb93a386Sopenharmony_ci
159cb93a386Sopenharmony_cisk_sp<SkPicture> SkPicture::MakeFromStream(SkStream* stream, const SkDeserialProcs* procsPtr,
160cb93a386Sopenharmony_ci                                           SkTypefacePlayback* typefaces) {
161cb93a386Sopenharmony_ci    SkPictInfo info;
162cb93a386Sopenharmony_ci    if (!StreamIsSKP(stream, &info)) {
163cb93a386Sopenharmony_ci        return nullptr;
164cb93a386Sopenharmony_ci    }
165cb93a386Sopenharmony_ci
166cb93a386Sopenharmony_ci    SkDeserialProcs procs;
167cb93a386Sopenharmony_ci    if (procsPtr) {
168cb93a386Sopenharmony_ci        procs = *procsPtr;
169cb93a386Sopenharmony_ci    }
170cb93a386Sopenharmony_ci
171cb93a386Sopenharmony_ci    uint8_t trailingStreamByteAfterPictInfo;
172cb93a386Sopenharmony_ci    if (!stream->readU8(&trailingStreamByteAfterPictInfo)) { return nullptr; }
173cb93a386Sopenharmony_ci    switch (trailingStreamByteAfterPictInfo) {
174cb93a386Sopenharmony_ci        case kPictureData_TrailingStreamByteAfterPictInfo: {
175cb93a386Sopenharmony_ci            std::unique_ptr<SkPictureData> data(
176cb93a386Sopenharmony_ci                    SkPictureData::CreateFromStream(stream, info, procs, typefaces));
177cb93a386Sopenharmony_ci            return Forwardport(info, data.get(), nullptr);
178cb93a386Sopenharmony_ci        }
179cb93a386Sopenharmony_ci        case kCustom_TrailingStreamByteAfterPictInfo: {
180cb93a386Sopenharmony_ci            int32_t ssize;
181cb93a386Sopenharmony_ci            if (!stream->readS32(&ssize) || ssize >= 0 || !procs.fPictureProc) {
182cb93a386Sopenharmony_ci                return nullptr;
183cb93a386Sopenharmony_ci            }
184cb93a386Sopenharmony_ci            size_t size = sk_negate_to_size_t(ssize);
185cb93a386Sopenharmony_ci            auto data = SkData::MakeUninitialized(size);
186cb93a386Sopenharmony_ci            if (stream->read(data->writable_data(), size) != size) {
187cb93a386Sopenharmony_ci                return nullptr;
188cb93a386Sopenharmony_ci            }
189cb93a386Sopenharmony_ci            return procs.fPictureProc(data->data(), size, procs.fPictureCtx);
190cb93a386Sopenharmony_ci        }
191cb93a386Sopenharmony_ci        default:    // fall out to error return
192cb93a386Sopenharmony_ci            break;
193cb93a386Sopenharmony_ci    }
194cb93a386Sopenharmony_ci    return nullptr;
195cb93a386Sopenharmony_ci}
196cb93a386Sopenharmony_ci
197cb93a386Sopenharmony_cisk_sp<SkPicture> SkPicturePriv::MakeFromBuffer(SkReadBuffer& buffer) {
198cb93a386Sopenharmony_ci    SkPictInfo info;
199cb93a386Sopenharmony_ci    if (!SkPicture::BufferIsSKP(&buffer, &info)) {
200cb93a386Sopenharmony_ci        return nullptr;
201cb93a386Sopenharmony_ci    }
202cb93a386Sopenharmony_ci    // size should be 0, 1, or negative
203cb93a386Sopenharmony_ci    int32_t ssize = buffer.read32();
204cb93a386Sopenharmony_ci    if (ssize < 0) {
205cb93a386Sopenharmony_ci        const SkDeserialProcs& procs = buffer.getDeserialProcs();
206cb93a386Sopenharmony_ci        if (!procs.fPictureProc) {
207cb93a386Sopenharmony_ci            return nullptr;
208cb93a386Sopenharmony_ci        }
209cb93a386Sopenharmony_ci        size_t size = sk_negate_to_size_t(ssize);
210cb93a386Sopenharmony_ci        return procs.fPictureProc(buffer.skip(size), size, procs.fPictureCtx);
211cb93a386Sopenharmony_ci    }
212cb93a386Sopenharmony_ci    if (ssize != 1) {
213cb93a386Sopenharmony_ci        // 1 is the magic 'size' that means SkPictureData follows
214cb93a386Sopenharmony_ci        return nullptr;
215cb93a386Sopenharmony_ci    }
216cb93a386Sopenharmony_ci   std::unique_ptr<SkPictureData> data(SkPictureData::CreateFromBuffer(buffer, info));
217cb93a386Sopenharmony_ci    return SkPicture::Forwardport(info, data.get(), &buffer);
218cb93a386Sopenharmony_ci}
219cb93a386Sopenharmony_ci
220cb93a386Sopenharmony_ciSkPictureData* SkPicture::backport() const {
221cb93a386Sopenharmony_ci    SkPictInfo info = this->createHeader();
222cb93a386Sopenharmony_ci    SkPictureRecord rec(info.fCullRect.roundOut(), 0/*flags*/);
223cb93a386Sopenharmony_ci    rec.beginRecording();
224cb93a386Sopenharmony_ci        this->playback(&rec);
225cb93a386Sopenharmony_ci    rec.endRecording();
226cb93a386Sopenharmony_ci    return new SkPictureData(rec, info);
227cb93a386Sopenharmony_ci}
228cb93a386Sopenharmony_ci
229cb93a386Sopenharmony_civoid SkPicture::serialize(SkWStream* stream, const SkSerialProcs* procs) const {
230cb93a386Sopenharmony_ci    this->serialize(stream, procs, nullptr);
231cb93a386Sopenharmony_ci}
232cb93a386Sopenharmony_ci
233cb93a386Sopenharmony_cisk_sp<SkData> SkPicture::serialize(const SkSerialProcs* procs) const {
234cb93a386Sopenharmony_ci    SkDynamicMemoryWStream stream;
235cb93a386Sopenharmony_ci    this->serialize(&stream, procs, nullptr);
236cb93a386Sopenharmony_ci    return stream.detachAsData();
237cb93a386Sopenharmony_ci}
238cb93a386Sopenharmony_ci
239cb93a386Sopenharmony_cistatic sk_sp<SkData> custom_serialize(const SkPicture* picture, const SkSerialProcs& procs) {
240cb93a386Sopenharmony_ci    if (procs.fPictureProc) {
241cb93a386Sopenharmony_ci        auto data = procs.fPictureProc(const_cast<SkPicture*>(picture), procs.fPictureCtx);
242cb93a386Sopenharmony_ci        if (data) {
243cb93a386Sopenharmony_ci            size_t size = data->size();
244cb93a386Sopenharmony_ci            if (!SkTFitsIn<int32_t>(size) || size <= 1) {
245cb93a386Sopenharmony_ci                return SkData::MakeEmpty();
246cb93a386Sopenharmony_ci            }
247cb93a386Sopenharmony_ci            return data;
248cb93a386Sopenharmony_ci        }
249cb93a386Sopenharmony_ci    }
250cb93a386Sopenharmony_ci    return nullptr;
251cb93a386Sopenharmony_ci}
252cb93a386Sopenharmony_ci
253cb93a386Sopenharmony_cistatic bool write_pad32(SkWStream* stream, const void* data, size_t size) {
254cb93a386Sopenharmony_ci    if (!stream->write(data, size)) {
255cb93a386Sopenharmony_ci        return false;
256cb93a386Sopenharmony_ci    }
257cb93a386Sopenharmony_ci    if (size & 3) {
258cb93a386Sopenharmony_ci        uint32_t zero = 0;
259cb93a386Sopenharmony_ci        return stream->write(&zero, 4 - (size & 3));
260cb93a386Sopenharmony_ci    }
261cb93a386Sopenharmony_ci    return true;
262cb93a386Sopenharmony_ci}
263cb93a386Sopenharmony_ci
264cb93a386Sopenharmony_ci// Private serialize.
265cb93a386Sopenharmony_ci// SkPictureData::serialize makes a first pass on all subpictures, indicatewd by textBlobsOnly=true,
266cb93a386Sopenharmony_ci// to fill typefaceSet.
267cb93a386Sopenharmony_civoid SkPicture::serialize(SkWStream* stream, const SkSerialProcs* procsPtr,
268cb93a386Sopenharmony_ci                          SkRefCntSet* typefaceSet, bool textBlobsOnly) const {
269cb93a386Sopenharmony_ci    SkSerialProcs procs;
270cb93a386Sopenharmony_ci    if (procsPtr) {
271cb93a386Sopenharmony_ci        procs = *procsPtr;
272cb93a386Sopenharmony_ci    }
273cb93a386Sopenharmony_ci
274cb93a386Sopenharmony_ci    SkPictInfo info = this->createHeader();
275cb93a386Sopenharmony_ci    stream->write(&info, sizeof(info));
276cb93a386Sopenharmony_ci
277cb93a386Sopenharmony_ci    if (auto custom = custom_serialize(this, procs)) {
278cb93a386Sopenharmony_ci        int32_t size = SkToS32(custom->size());
279cb93a386Sopenharmony_ci        if (size == 0) {
280cb93a386Sopenharmony_ci            stream->write8(kFailure_TrailingStreamByteAfterPictInfo);
281cb93a386Sopenharmony_ci            return;
282cb93a386Sopenharmony_ci        }
283cb93a386Sopenharmony_ci        stream->write8(kCustom_TrailingStreamByteAfterPictInfo);
284cb93a386Sopenharmony_ci        stream->write32(-size);    // negative for custom format
285cb93a386Sopenharmony_ci        write_pad32(stream, custom->data(), size);
286cb93a386Sopenharmony_ci        return;
287cb93a386Sopenharmony_ci    }
288cb93a386Sopenharmony_ci
289cb93a386Sopenharmony_ci    std::unique_ptr<SkPictureData> data(this->backport());
290cb93a386Sopenharmony_ci    if (data) {
291cb93a386Sopenharmony_ci        stream->write8(kPictureData_TrailingStreamByteAfterPictInfo);
292cb93a386Sopenharmony_ci        data->serialize(stream, procs, typefaceSet, textBlobsOnly);
293cb93a386Sopenharmony_ci    } else {
294cb93a386Sopenharmony_ci        stream->write8(kFailure_TrailingStreamByteAfterPictInfo);
295cb93a386Sopenharmony_ci    }
296cb93a386Sopenharmony_ci}
297cb93a386Sopenharmony_ci
298cb93a386Sopenharmony_civoid SkPicturePriv::Flatten(const sk_sp<const SkPicture> picture, SkWriteBuffer& buffer) {
299cb93a386Sopenharmony_ci    SkPictInfo info = picture->createHeader();
300cb93a386Sopenharmony_ci    std::unique_ptr<SkPictureData> data(picture->backport());
301cb93a386Sopenharmony_ci
302cb93a386Sopenharmony_ci    buffer.writeByteArray(&info.fMagic, sizeof(info.fMagic));
303cb93a386Sopenharmony_ci    buffer.writeUInt(info.getVersion());
304cb93a386Sopenharmony_ci    buffer.writeRect(info.fCullRect);
305cb93a386Sopenharmony_ci
306cb93a386Sopenharmony_ci    if (auto custom = custom_serialize(picture.get(), buffer.fProcs)) {
307cb93a386Sopenharmony_ci        int32_t size = SkToS32(custom->size());
308cb93a386Sopenharmony_ci        buffer.write32(-size);    // negative for custom format
309cb93a386Sopenharmony_ci        buffer.writePad32(custom->data(), size);
310cb93a386Sopenharmony_ci        return;
311cb93a386Sopenharmony_ci    }
312cb93a386Sopenharmony_ci
313cb93a386Sopenharmony_ci    if (data) {
314cb93a386Sopenharmony_ci        buffer.write32(1); // special size meaning SkPictureData
315cb93a386Sopenharmony_ci        data->flatten(buffer);
316cb93a386Sopenharmony_ci    } else {
317cb93a386Sopenharmony_ci        buffer.write32(0); // signal no content
318cb93a386Sopenharmony_ci    }
319cb93a386Sopenharmony_ci}
320cb93a386Sopenharmony_ci
321cb93a386Sopenharmony_cisk_sp<SkPicture> SkPicture::MakePlaceholder(SkRect cull) {
322cb93a386Sopenharmony_ci    struct Placeholder : public SkPicture {
323cb93a386Sopenharmony_ci          explicit Placeholder(SkRect cull) : fCull(cull) {}
324cb93a386Sopenharmony_ci
325cb93a386Sopenharmony_ci          void playback(SkCanvas*, AbortCallback*) const override { }
326cb93a386Sopenharmony_ci
327cb93a386Sopenharmony_ci          // approximateOpCount() needs to be greater than kMaxPictureOpsToUnrollInsteadOfRef
328cb93a386Sopenharmony_ci          // (SkCanvasPriv.h) to avoid unrolling this into a parent picture.
329cb93a386Sopenharmony_ci          int approximateOpCount(bool) const override {
330cb93a386Sopenharmony_ci              return kMaxPictureOpsToUnrollInsteadOfRef+1;
331cb93a386Sopenharmony_ci          }
332cb93a386Sopenharmony_ci          size_t approximateBytesUsed() const override { return sizeof(*this); }
333cb93a386Sopenharmony_ci          SkRect cullRect()             const override { return fCull; }
334cb93a386Sopenharmony_ci
335cb93a386Sopenharmony_ci          SkRect fCull;
336cb93a386Sopenharmony_ci    };
337cb93a386Sopenharmony_ci    return sk_make_sp<Placeholder>(cull);
338cb93a386Sopenharmony_ci}
339