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