Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
SkPicture.cpp
Go to the documentation of this file.
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
9
10#include "include/core/SkData.h"
16#include "src/base/SkMathPriv.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
37enum {
41};
42
43/* SkPicture impl. This handles generic responsibilities like unique IDs and serialization. */
44
45SkPicture::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
53 if (fAddedToCache.load()) {
55 }
56}
57
58static const char kMagic[] = { 's', 'k', 'i', 'a', 'p', 'i', 'c', 't' };
59
60SkPictInfo SkPicture::createHeader() const {
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
69 info.fCullRect = this->cullRect();
70 return info;
71}
72
73bool 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 ||
79 return false;
80 }
81 return true;
82}
83
84bool SkPicture::StreamIsSKP(SkStream* stream, SkPictInfo* pInfo) {
85 if (!stream) {
86 return false;
87 }
88
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
110 return SkPicture::StreamIsSKP(stream, pInfo);
111}
112
113bool SkPicture::BufferIsSKP(SkReadBuffer* buffer, SkPictInfo* pInfo) {
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
130sk_sp<SkPicture> SkPicture::Forwardport(const SkPictInfo& info,
131 const SkPictureData* data,
133 if (!data) {
134 return nullptr;
135 }
136 if (!data->opData()) {
137 return nullptr;
138 }
141 playback.draw(r.beginRecording(info.fCullRect), nullptr/*no callback*/, buffer);
142 return r.finishRecordingAsPicture();
143}
144
145static const int kNestedSKPLimit = 100; // Arbitrarily set
146
148 return MakeFromStreamPriv(stream, procs, nullptr, kNestedSKPLimit);
149}
150
151sk_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
161 if (!data) {
162 return nullptr;
163 }
164 SkMemoryStream stream(data->data(), data->size());
165 return MakeFromStreamPriv(&stream, procs, nullptr, kNestedSKPLimit);
166}
167
168sk_sp<SkPicture> SkPicture::MakeFromStreamPriv(SkStream* stream, const SkDeserialProcs* procsPtr,
169 SkTypefacePlayback* typefaces, int recursionLimit) {
170 if (recursionLimit <= 0) {
171 return nullptr;
172 }
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) {
187 std::unique_ptr<SkPictureData> data(
188 SkPictureData::CreateFromStream(stream, info, procs, typefaces,
189 recursionLimit));
190 return Forwardport(info, data.get(), nullptr);
191 }
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
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
236SkPictureData* 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
245void SkPicture::serialize(SkWStream* stream, const SkSerialProcs* procs) const {
246 this->serialize(stream, procs, nullptr);
247}
248
251 this->serialize(&stream, procs, nullptr);
252 return stream.detachAsData();
253}
254
255static 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
269static 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.
283void 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) {
297 return;
298 }
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) {
308 data->serialize(stream, procs, typefaceSet, textBlobsOnly);
309 } else {
311 }
312}
313
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
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 {
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}
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition DM.cpp:213
#define SkASSERT(cond)
Definition SkAssert.h:116
constexpr int kMaxPictureOpsToUnrollInsteadOfRef
static size_t sk_negate_to_size_t(int32_t value)
Definition SkMathPriv.h:76
static bool write_pad32(SkWStream *stream, const void *data, size_t size)
@ kCustom_TrailingStreamByteAfterPictInfo
Definition SkPicture.cpp:40
@ kFailure_TrailingStreamByteAfterPictInfo
Definition SkPicture.cpp:38
@ kPictureData_TrailingStreamByteAfterPictInfo
Definition SkPicture.cpp:39
bool SkPicture_StreamIsSKP(SkStream *stream, SkPictInfo *pInfo)
static sk_sp< SkData > custom_serialize(const SkPicture *picture, const SkSerialProcs &procs)
static const int kNestedSKPLimit
static const char kMagic[]
Definition SkPicture.cpp:58
bool StreamRemainingLengthIsBelow(SkStream *stream, size_t len)
Definition SkStream.cpp:976
constexpr int32_t SkToS32(S x)
Definition SkTo.h:25
static sk_sp< SkData > MakeUninitialized(size_t length)
Definition SkData.cpp:116
static sk_sp< SkData > MakeEmpty()
Definition SkData.cpp:94
static SkPictureData * CreateFromStream(SkStream *, const SkPictInfo &, const SkDeserialProcs &, SkTypefacePlayback *, int recursionLimit)
static SkPictureData * CreateFromBuffer(SkReadBuffer &, const SkPictInfo &)
static uint64_t MakeSharedID(uint32_t pictureID)
static void Flatten(const sk_sp< const SkPicture >, SkWriteBuffer &buffer)
static sk_sp< SkPicture > MakeFromBuffer(SkReadBuffer &buffer)
SkCanvas * beginRecording(const SkRect &bounds, sk_sp< SkBBoxHierarchy > bbh)
sk_sp< SkPicture > finishRecordingAsPicture()
friend class SkPictureData
Definition SkPicture.h:262
sk_sp< SkData > serialize(const SkSerialProcs *procs=nullptr) const
virtual SkRect cullRect() const =0
static sk_sp< SkPicture > MakeFromData(const SkData *data, const SkDeserialProcs *procs=nullptr)
virtual void playback(SkCanvas *canvas, AbortCallback *callback=nullptr) const =0
~SkPicture() override
Definition SkPicture.cpp:52
static sk_sp< SkPicture > MakePlaceholder(SkRect cull)
static sk_sp< SkPicture > MakeFromStream(SkStream *stream, const SkDeserialProcs *procs=nullptr)
static void PostPurgeSharedID(uint64_t sharedID)
T * get() const
Definition SkRefCnt.h:303
static const uint8_t buffer[]
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot data
Definition switches.h:41
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition switches.h:259
SkDeserialPictureProc fPictureProc
SkSerialPictureProc fPictureProc