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