Flutter Engine
The Flutter Engine
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
152 const SkDeserialProcs* procs) {
153 if (!data) {
154 return nullptr;
155 }
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(
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);
199 return nullptr;
200 }
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
246 this->serialize(stream, procs, nullptr);
247}
248
251 this->serialize(&stream, procs, nullptr);
252 return stream.detachAsData();
253}
254
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.
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
Definition: SkCanvasPriv.h:108
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)
Definition: SkPicture.cpp:269
bool SkPicture_StreamIsSKP(SkStream *stream, SkPictInfo *pInfo)
Definition: SkPicture.cpp:109
@ kCustom_TrailingStreamByteAfterPictInfo
Definition: SkPicture.cpp:40
@ kFailure_TrailingStreamByteAfterPictInfo
Definition: SkPicture.cpp:38
@ kPictureData_TrailingStreamByteAfterPictInfo
Definition: SkPicture.cpp:39
static sk_sp< SkData > custom_serialize(const SkPicture *picture, const SkSerialProcs &procs)
Definition: SkPicture.cpp:255
static const int kNestedSKPLimit
Definition: SkPicture.cpp:145
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
Definition: SkData.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)
Definition: SkPicturePriv.h:40
static void Flatten(const sk_sp< const SkPicture >, SkWriteBuffer &buffer)
Definition: SkPicture.cpp:314
static sk_sp< SkPicture > MakeFromBuffer(SkReadBuffer &buffer)
Definition: SkPicture.cpp:213
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
Definition: SkPicture.cpp:249
virtual SkRect cullRect() const =0
static sk_sp< SkPicture > MakeFromData(const SkData *data, const SkDeserialProcs *procs=nullptr)
Definition: SkPicture.cpp:160
virtual void playback(SkCanvas *canvas, AbortCallback *callback=nullptr) const =0
virtual size_t approximateBytesUsed() const =0
~SkPicture() override
Definition: SkPicture.cpp:52
static sk_sp< SkPicture > MakePlaceholder(SkRect cull)
Definition: SkPicture.cpp:337
static sk_sp< SkPicture > MakeFromStream(SkStream *stream, const SkDeserialProcs *procs=nullptr)
Definition: SkPicture.cpp:147
virtual int approximateOpCount(bool nested=false) const =0
static void PostPurgeSharedID(uint64_t sharedID)
T * get() const
Definition: SkRefCnt.h:303
sk_sp< const SkPicture > picture
Definition: SkRecords.h:299
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
Definition: switches.h:126
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
Definition: SkSerialProcs.h:98
void * fPictureCtx
Definition: SkSerialProcs.h:88
SkSerialPictureProc fPictureProc
Definition: SkSerialProcs.h:87
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:63