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