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