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
8 #include <cmath>
9 #include "SkBuffer.h"
10 #include "SkData.h"
11 #include "SkMath.h"
12 #include "SkPathPriv.h"
13 #include "SkPathRef.h"
14 #include "SkRRect.h"
15 #include "SkSafeMath.h"
16
17 enum SerializationOffsets {
18 kType_SerializationShift = 28, // requires 4 bits
19 kDirection_SerializationShift = 26, // requires 2 bits
20 kFillType_SerializationShift = 8, // requires 8 bits
21 // low-8-bits are version
22 kVersion_SerializationMask = 0xFF,
23 };
24
25 enum SerializationVersions {
26 // kPathPrivFirstDirection_Version = 1,
27 kPathPrivLastMoveToIndex_Version = 2,
28 kPathPrivTypeEnumVersion = 3,
29 kJustPublicData_Version = 4, // introduced Feb/2018
30
31 kCurrent_Version = kJustPublicData_Version
32 };
33
34 enum SerializationType {
35 kGeneral = 0,
36 kRRect = 1
37 };
38
extract_version(uint32_t packed)39 static unsigned extract_version(uint32_t packed) {
40 return packed & kVersion_SerializationMask;
41 }
42
extract_filltype(uint32_t packed)43 static SkPath::FillType extract_filltype(uint32_t packed) {
44 return static_cast<SkPath::FillType>((packed >> kFillType_SerializationShift) & 0x3);
45 }
46
extract_serializationtype(uint32_t packed)47 static SerializationType extract_serializationtype(uint32_t packed) {
48 return static_cast<SerializationType>((packed >> kType_SerializationShift) & 0xF);
49 }
50
51 ///////////////////////////////////////////////////////////////////////////////////////////////////
52
writeToMemoryAsRRect(void * storage) const53 size_t SkPath::writeToMemoryAsRRect(void* storage) const {
54 SkRect oval;
55 SkRRect rrect;
56 bool isCCW;
57 unsigned start;
58 if (fPathRef->isOval(&oval, &isCCW, &start)) {
59 rrect.setOval(oval);
60 // Convert to rrect start indices.
61 start *= 2;
62 } else if (!fPathRef->isRRect(&rrect, &isCCW, &start)) {
63 return 0;
64 }
65
66 // packed header, rrect, start index.
67 const size_t sizeNeeded = sizeof(int32_t) + SkRRect::kSizeInMemory + sizeof(int32_t);
68 if (!storage) {
69 return sizeNeeded;
70 }
71
72 int firstDir = isCCW ? SkPathPriv::kCCW_FirstDirection : SkPathPriv::kCW_FirstDirection;
73 int32_t packed = (fFillType << kFillType_SerializationShift) |
74 (firstDir << kDirection_SerializationShift) |
75 (SerializationType::kRRect << kType_SerializationShift) |
76 kCurrent_Version;
77
78 SkWBuffer buffer(storage);
79 buffer.write32(packed);
80 rrect.writeToBuffer(&buffer);
81 buffer.write32(SkToS32(start));
82 buffer.padToAlign4();
83 SkASSERT(sizeNeeded == buffer.pos());
84 return buffer.pos();
85 }
86
writeToMemory(void * storage) const87 size_t SkPath::writeToMemory(void* storage) const {
88 SkDEBUGCODE(this->validate();)
89
90 if (size_t bytes = this->writeToMemoryAsRRect(storage)) {
91 return bytes;
92 }
93
94 int32_t packed = (fFillType << kFillType_SerializationShift) |
95 (SerializationType::kGeneral << kType_SerializationShift) |
96 kCurrent_Version;
97
98 int32_t pts = fPathRef->countPoints();
99 int32_t cnx = fPathRef->countWeights();
100 int32_t vbs = fPathRef->countVerbs();
101
102 SkSafeMath safe;
103 size_t size = 4 * sizeof(int32_t);
104 size = safe.add(size, safe.mul(pts, sizeof(SkPoint)));
105 size = safe.add(size, safe.mul(cnx, sizeof(SkScalar)));
106 size = safe.add(size, safe.mul(vbs, sizeof(uint8_t)));
107 size = safe.alignUp(size, 4);
108 if (!safe) {
109 return 0;
110 }
111 if (!storage) {
112 return size;
113 }
114
115 SkWBuffer buffer(storage);
116 buffer.write32(packed);
117 buffer.write32(pts);
118 buffer.write32(cnx);
119 buffer.write32(vbs);
120 buffer.write(fPathRef->points(), pts * sizeof(SkPoint));
121 buffer.write(fPathRef->conicWeights(), cnx * sizeof(SkScalar));
122 buffer.write(fPathRef->verbsMemBegin(), vbs * sizeof(uint8_t));
123 buffer.padToAlign4();
124
125 SkASSERT(buffer.pos() == size);
126 return size;
127 }
128
serialize() const129 sk_sp<SkData> SkPath::serialize() const {
130 size_t size = this->writeToMemory(nullptr);
131 sk_sp<SkData> data = SkData::MakeUninitialized(size);
132 this->writeToMemory(data->writable_data());
133 return data;
134 }
135
136 //////////////////////////////////////////////////////////////////////////////////////////////////
137 // reading
138
readFromMemory(const void * storage,size_t length)139 size_t SkPath::readFromMemory(const void* storage, size_t length) {
140 SkRBuffer buffer(storage, length);
141 uint32_t packed;
142 if (!buffer.readU32(&packed)) {
143 return 0;
144 }
145 unsigned version = extract_version(packed);
146 if (version <= kPathPrivTypeEnumVersion) {
147 return this->readFromMemory_LE3(storage, length);
148 }
149 if (version == kJustPublicData_Version) {
150 return this->readFromMemory_EQ4(storage, length);
151 }
152 return 0;
153 }
154
readAsRRect(const void * storage,size_t length)155 size_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
162 SkASSERT(extract_serializationtype(packed) == SerializationType::kRRect);
163
164 uint8_t dir = (packed >> kDirection_SerializationShift) & 0x3;
165 FillType fillType = extract_filltype(packed);
166
167 Direction rrectDir;
168 SkRRect rrect;
169 int32_t start;
170 switch (dir) {
171 case SkPathPriv::kCW_FirstDirection:
172 rrectDir = kCW_Direction;
173 break;
174 case SkPathPriv::kCCW_FirstDirection:
175 rrectDir = kCCW_Direction;
176 break;
177 default:
178 return 0;
179 }
180 if (!rrect.readFromBuffer(&buffer)) {
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
readFromMemory_EQ4(const void * storage,size_t length)193 size_t SkPath::readFromMemory_EQ4(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
200 SkASSERT(extract_version(packed) == 4);
201
202 switch (extract_serializationtype(packed)) {
203 case SerializationType::kRRect:
204 return this->readAsRRect(storage, length);
205 case SerializationType::kGeneral:
206 break; // fall through
207 default:
208 return 0;
209 }
210
211 int32_t pts, cnx, vbs;
212 if (!buffer.readS32(&pts) || !buffer.readS32(&cnx) || !buffer.readS32(&vbs)) {
213 return 0;
214 }
215
216 const SkPoint* points = buffer.skipCount<SkPoint>(pts);
217 const SkScalar* conics = buffer.skipCount<SkScalar>(cnx);
218 const uint8_t* verbs = buffer.skipCount<uint8_t>(vbs);
219 buffer.skipToAlign4();
220 if (!buffer.isValid()) {
221 return 0;
222 }
223 SkASSERT(buffer.pos() <= length);
224
225 #define CHECK_POINTS_CONICS(p, c) \
226 do { \
227 if (p && ((pts -= p) < 0)) { \
228 return 0; \
229 } \
230 if (c && ((cnx -= c) < 0)) { \
231 return 0; \
232 } \
233 } while (0)
234
235 SkPath tmp;
236 tmp.setFillType(extract_filltype(packed));
237 tmp.incReserve(pts);
238 for (int i = vbs - 1; i >= 0; --i) {
239 switch (verbs[i]) {
240 case kMove_Verb:
241 CHECK_POINTS_CONICS(1, 0);
242 tmp.moveTo(*points++);
243 break;
244 case kLine_Verb:
245 CHECK_POINTS_CONICS(1, 0);
246 tmp.lineTo(*points++);
247 break;
248 case kQuad_Verb:
249 CHECK_POINTS_CONICS(2, 0);
250 tmp.quadTo(points[0], points[1]);
251 points += 2;
252 break;
253 case kConic_Verb:
254 CHECK_POINTS_CONICS(2, 1);
255 tmp.conicTo(points[0], points[1], *conics++);
256 points += 2;
257 break;
258 case kCubic_Verb:
259 CHECK_POINTS_CONICS(3, 0);
260 tmp.cubicTo(points[0], points[1], points[2]);
261 points += 3;
262 break;
263 case kClose_Verb:
264 tmp.close();
265 break;
266 default:
267 return 0; // bad verb
268 }
269 }
270 #undef CHECK_POINTS_CONICS
271 if (pts || cnx) {
272 return 0; // leftover points and/or conics
273 }
274
275 *this = std::move(tmp);
276 return buffer.pos();
277 }
278
readFromMemory_LE3(const void * storage,size_t length)279 size_t SkPath::readFromMemory_LE3(const void* storage, size_t length) {
280 SkRBuffer buffer(storage, length);
281
282 int32_t packed;
283 if (!buffer.readS32(&packed)) {
284 return 0;
285 }
286
287 unsigned version = extract_version(packed);
288 SkASSERT(version <= 3);
289
290 FillType fillType = extract_filltype(packed);
291 if (version >= kPathPrivTypeEnumVersion) {
292 switch (extract_serializationtype(packed)) {
293 case SerializationType::kRRect:
294 return this->readAsRRect(storage, length);
295 case SerializationType::kGeneral:
296 // Fall through to general path deserialization
297 break;
298 default:
299 return 0;
300 }
301 }
302 if (version >= kPathPrivLastMoveToIndex_Version && !buffer.readS32(&fLastMoveToIndex)) {
303 return 0;
304 }
305
306 // These are written into the serialized data but we no longer use them in the deserialized
307 // path. If convexity is corrupted it may cause the GPU backend to make incorrect
308 // rendering choices, possibly crashing. We set them to unknown so that they'll be recomputed if
309 // requested.
310 fConvexity = kUnknown_Convexity;
311 fFirstDirection = SkPathPriv::kUnknown_FirstDirection;
312
313 fFillType = fillType;
314 fIsVolatile = 0;
315 SkPathRef* pathRef = SkPathRef::CreateFromBuffer(&buffer);
316 if (!pathRef) {
317 return 0;
318 }
319
320 fPathRef.reset(pathRef);
321 SkDEBUGCODE(this->validate();)
322 buffer.skipToAlign4();
323 return buffer.pos();
324 }
325
326