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