Flutter Engine
The Flutter Engine
SkPath_serial.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2018 Google Inc.
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
12#include "include/core/SkRect.h"
22#include "src/base/SkBuffer.h"
23#include "src/base/SkSafeMath.h"
25#include "src/core/SkPathPriv.h"
27
28#include <cstddef>
29#include <cstdint>
30
32 kType_SerializationShift = 28, // requires 4 bits
33 kDirection_SerializationShift = 26, // requires 2 bits
34 kFillType_SerializationShift = 8, // requires 8 bits
35 // low-8-bits are version
37};
38
40 // kPathPrivFirstDirection_Version = 1,
41 // kPathPrivLastMoveToIndex_Version = 2,
42 // kPathPrivTypeEnumVersion = 3,
43 kJustPublicData_Version = 4, // introduced Feb/2018
44 kVerbsAreStoredForward_Version = 5, // introduced Sept/2019
45
48};
49
52 kRRect = 1
53};
54
55static unsigned extract_version(uint32_t packed) {
56 return packed & kVersion_SerializationMask;
57}
58
59static SkPathFillType extract_filltype(uint32_t packed) {
60 return static_cast<SkPathFillType>((packed >> kFillType_SerializationShift) & 0x3);
61}
62
64 return static_cast<SerializationType>((packed >> kType_SerializationShift) & 0xF);
65}
66
67///////////////////////////////////////////////////////////////////////////////////////////////////
68
69size_t SkPath::writeToMemoryAsRRect(void* storage) const {
72 bool isCCW;
73 unsigned start;
74 if (fPathRef->isOval(&oval, &isCCW, &start)) {
76 // Convert to rrect start indices.
77 start *= 2;
78 } else if (!fPathRef->isRRect(&rrect, &isCCW, &start)) {
79 return 0;
80 }
81
82 // packed header, rrect, start index.
83 const size_t sizeNeeded = sizeof(int32_t) + SkRRect::kSizeInMemory + sizeof(int32_t);
84 if (!storage) {
85 return sizeNeeded;
86 }
87
88 int firstDir = isCCW ? (int)SkPathFirstDirection::kCCW : (int)SkPathFirstDirection::kCW;
89 int32_t packed = (fFillType << kFillType_SerializationShift) |
90 (firstDir << kDirection_SerializationShift) |
93
94 SkWBuffer buffer(storage);
95 buffer.write32(packed);
97 buffer.write32(SkToS32(start));
98 buffer.padToAlign4();
99 SkASSERT(sizeNeeded == buffer.pos());
100 return buffer.pos();
101}
102
103size_t SkPath::writeToMemory(void* storage) const {
104 SkDEBUGCODE(this->validate();)
105
106 if (size_t bytes = this->writeToMemoryAsRRect(storage)) {
107 return bytes;
108 }
109
110 int32_t packed = (fFillType << kFillType_SerializationShift) |
113
114 int32_t pts = fPathRef->countPoints();
115 int32_t cnx = fPathRef->countWeights();
116 int32_t vbs = fPathRef->countVerbs();
117
118 SkSafeMath safe;
119 size_t size = 4 * sizeof(int32_t);
120 size = safe.add(size, safe.mul(pts, sizeof(SkPoint)));
121 size = safe.add(size, safe.mul(cnx, sizeof(SkScalar)));
122 size = safe.add(size, safe.mul(vbs, sizeof(uint8_t)));
123 size = safe.alignUp(size, 4);
124 if (!safe) {
125 return 0;
126 }
127 if (!storage) {
128 return size;
129 }
130
131 SkWBuffer buffer(storage);
132 buffer.write32(packed);
133 buffer.write32(pts);
134 buffer.write32(cnx);
135 buffer.write32(vbs);
136 buffer.write(fPathRef->points(), pts * sizeof(SkPoint));
137 buffer.write(fPathRef->conicWeights(), cnx * sizeof(SkScalar));
138 buffer.write(fPathRef->verbsBegin(), vbs * sizeof(uint8_t));
139 buffer.padToAlign4();
140
141 SkASSERT(buffer.pos() == size);
142 return size;
143}
144
146 size_t size = this->writeToMemory(nullptr);
148 this->writeToMemory(data->writable_data());
149 return data;
150}
151
152//////////////////////////////////////////////////////////////////////////////////////////////////
153// reading
154
155size_t SkPath::readAsRRect(const void* storage, size_t length) {
156 SkRBuffer buffer(storage, length);
157 uint32_t packed;
158 if (!buffer.readU32(&packed)) {
159 return 0;
160 }
161
163
164 uint8_t dir = (packed >> kDirection_SerializationShift) & 0x3;
165 SkPathFillType fillType = extract_filltype(packed);
166
167 SkPathDirection rrectDir;
169 int32_t start;
170 switch (dir) {
172 rrectDir = SkPathDirection::kCW;
173 break;
175 rrectDir = SkPathDirection::kCCW;
176 break;
177 default:
178 return 0;
179 }
181 return 0;
182 }
183 if (!buffer.readS32(&start) || start != SkTPin(start, 0, 7)) {
184 return 0;
185 }
186 this->reset();
187 this->addRRect(rrect, rrectDir, SkToUInt(start));
188 this->setFillType(fillType);
189 buffer.skipToAlign4();
190 return buffer.pos();
191}
192
193size_t SkPath::readFromMemory(const void* storage, size_t length) {
194 SkRBuffer buffer(storage, length);
195 uint32_t packed;
196 if (!buffer.readU32(&packed)) {
197 return 0;
198 }
199 unsigned version = extract_version(packed);
200
201 const bool verbsAreForward = (version == kVerbsAreStoredForward_Version);
202 if (!verbsAreForward && version != kJustPublicData_Version) SK_UNLIKELY {
203 // Old/unsupported version.
204 return 0;
205 }
206
207 switch (extract_serializationtype(packed)) {
209 return this->readAsRRect(storage, length);
211 break; // fall out
212 default:
213 return 0;
214 }
215
216 // To minimize the number of reads done a structure with the counts is used.
217 struct {
218 int32_t pts, cnx, vbs;
219 } counts;
220 if (!buffer.read(&counts, sizeof(counts))) {
221 return 0;
222 }
223
224 const SkPoint* points = buffer.skipCount<SkPoint>(counts.pts);
225 const SkScalar* conics = buffer.skipCount<SkScalar>(counts.cnx);
226 const uint8_t* verbs = buffer.skipCount<uint8_t>(counts.vbs);
227 buffer.skipToAlign4();
228 if (!buffer.isValid()) {
229 return 0;
230 }
231 SkASSERT(buffer.pos() <= length);
232
233 if (counts.vbs == 0) {
234 if (counts.pts == 0 && counts.cnx == 0) {
235 reset();
237 return buffer.pos();
238 }
239 // No verbs but points and/or conic weights is a not a valid path.
240 return 0;
241 }
242
243 SkAutoMalloc reversedStorage;
244 if (!verbsAreForward) SK_UNLIKELY {
245 uint8_t* tmpVerbs = (uint8_t*)reversedStorage.reset(counts.vbs);
246 for (int i = 0; i < counts.vbs; ++i) {
247 tmpVerbs[i] = verbs[counts.vbs - i - 1];
248 }
249 verbs = tmpVerbs;
250 }
251
252 SkPathVerbAnalysis analysis = sk_path_analyze_verbs(verbs, counts.vbs);
253 if (!analysis.valid || analysis.points != counts.pts || analysis.weights != counts.cnx) {
254 return 0;
255 }
256 *this = SkPathPriv::MakePath(analysis, points, verbs, counts.vbs, conics,
257 extract_filltype(packed), false);
258 return buffer.pos();
259}
static const int points[]
#define SkASSERT(cond)
Definition: SkAssert.h:116
#define SK_UNLIKELY
Definition: SkAssert.h:28
SkPathVerbAnalysis sk_path_analyze_verbs(const uint8_t verbs[], int count)
Definition: SkPath.cpp:3515
SkPathDirection
Definition: SkPathTypes.h:34
SkPathFillType
Definition: SkPathTypes.h:11
static unsigned extract_version(uint32_t packed)
SerializationType
@ kGeneral
@ kRRect
static SkPathFillType extract_filltype(uint32_t packed)
SerializationVersions
@ kJustPublicData_Version
@ kMin_Version
@ kCurrent_Version
@ kVerbsAreStoredForward_Version
SerializationOffsets
@ kType_SerializationShift
@ kFillType_SerializationShift
@ kDirection_SerializationShift
@ kVersion_SerializationMask
static SerializationType extract_serializationtype(uint32_t packed)
static constexpr const T & SkTPin(const T &x, const T &lo, const T &hi)
Definition: SkTPin.h:19
SkDEBUGCODE(SK_SPI) SkThreadID SkGetThreadID()
constexpr int32_t SkToS32(S x)
Definition: SkTo.h:25
constexpr unsigned SkToUInt(S x)
Definition: SkTo.h:30
void * reset(size_t size=0, OnShrink shrink=kAlloc_OnShrink)
Definition: SkAutoMalloc.h:53
static sk_sp< SkData > MakeUninitialized(size_t length)
Definition: SkData.cpp:116
void * writable_data()
Definition: SkData.h:52
static SkPath MakePath(const SkPathVerbAnalysis &analysis, const SkPoint points[], const uint8_t verbs[], int verbCount, const SkScalar conics[], SkPathFillType fillType, bool isVolatile)
Definition: SkPathPriv.h:425
int countWeights() const
Definition: SkPathRef.h:309
const SkPoint * points() const
Definition: SkPathRef.h:326
const SkScalar * conicWeights() const
Definition: SkPathRef.h:333
bool isRRect(SkRRect *rrect, bool *isCCW, unsigned *start) const
Definition: SkPathRef.cpp:522
int countPoints() const
Definition: SkPathRef.h:307
const uint8_t * verbsBegin() const
Definition: SkPathRef.h:316
int countVerbs() const
Definition: SkPathRef.h:308
bool isOval(SkRect *rect, bool *isCCW, unsigned *start) const
Definition: SkPathRef.h:244
size_t readFromMemory(const void *buffer, size_t length)
void setFillType(SkPathFillType ft)
Definition: SkPath.h:235
SkPath & addRRect(const SkRRect &rrect, SkPathDirection dir=SkPathDirection::kCW)
Definition: SkPath.cpp:1000
SkPath & reset()
Definition: SkPath.cpp:370
sk_sp< SkData > serialize() const
size_t writeToMemory(void *buffer) const
static bool ReadFromBuffer(SkRBuffer *buffer, SkRRect *rr)
Definition: SkRRect.cpp:623
static void WriteToBuffer(const SkRRect &rr, SkWBuffer *buffer)
Definition: SkRRect.cpp:605
void setOval(const SkRect &oval)
Definition: SkRRect.cpp:30
static constexpr size_t kSizeInMemory
Definition: SkRRect.h:422
size_t add(size_t x, size_t y)
Definition: SkSafeMath.h:33
size_t alignUp(size_t x, size_t alignment)
Definition: SkSafeMath.h:54
size_t mul(size_t x, size_t y)
Definition: SkSafeMath.h:29
float SkScalar
Definition: extension.cpp:12
size_t length
SkRRect rrect
Definition: SkRecords.h:232
SkRect oval
Definition: SkRecords.h:249
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 counts
Definition: switches.h:239
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 Enable an endless trace buffer The default is a ring buffer This is useful when very old events need to viewed For during application launch Memory usage will continue to grow indefinitely however Start app with an specific route defined on the framework flutter assets dir
Definition: switches.h:145
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
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:63