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 "include/core/SkData.h"
9 #include "include/private/SkPathRef.h"
10 #include "include/private/base/SkMath.h"
11 #include "include/private/base/SkPathEnums.h"
12 #include "include/private/base/SkTPin.h"
13 #include "include/private/base/SkTo.h"
14 #include "src/base/SkBuffer.h"
15 #include "src/base/SkSafeMath.h"
16 #include "src/core/SkPathPriv.h"
17 #include "src/core/SkRRectPriv.h"
18
19 #include <cmath>
20
21 enum SerializationOffsets {
22 kType_SerializationShift = 28, // requires 4 bits
23 kDirection_SerializationShift = 26, // requires 2 bits
24 kFillType_SerializationShift = 8, // requires 8 bits
25 // low-8-bits are version
26 kVersion_SerializationMask = 0xFF,
27 };
28
29 enum SerializationVersions {
30 // kPathPrivFirstDirection_Version = 1,
31 // kPathPrivLastMoveToIndex_Version = 2,
32 // kPathPrivTypeEnumVersion = 3,
33 kJustPublicData_Version = 4, // introduced Feb/2018
34 kVerbsAreStoredForward_Version = 5, // introduced Sept/2019
35
36 kMin_Version = kJustPublicData_Version,
37 kCurrent_Version = kVerbsAreStoredForward_Version
38 };
39
40 enum SerializationType {
41 kGeneral = 0,
42 kRRect = 1
43 };
44
extract_version(uint32_t packed)45 static unsigned extract_version(uint32_t packed) {
46 return packed & kVersion_SerializationMask;
47 }
48
extract_filltype(uint32_t packed)49 static SkPathFillType extract_filltype(uint32_t packed) {
50 return static_cast<SkPathFillType>((packed >> kFillType_SerializationShift) & 0x3);
51 }
52
extract_serializationtype(uint32_t packed)53 static SerializationType extract_serializationtype(uint32_t packed) {
54 return static_cast<SerializationType>((packed >> kType_SerializationShift) & 0xF);
55 }
56
57 ///////////////////////////////////////////////////////////////////////////////////////////////////
58
writeToMemoryAsRRect(void * storage) const59 size_t SkPath::writeToMemoryAsRRect(void* storage) const {
60 SkRect oval;
61 SkRRect rrect;
62 bool isCCW;
63 unsigned start;
64 if (fPathRef->isOval(&oval, &isCCW, &start)) {
65 rrect.setOval(oval);
66 // Convert to rrect start indices.
67 start *= 2;
68 } else if (!fPathRef->isRRect(&rrect, &isCCW, &start)) {
69 return 0;
70 }
71
72 // packed header, rrect, start index.
73 const size_t sizeNeeded = sizeof(int32_t) + SkRRect::kSizeInMemory + sizeof(int32_t);
74 if (!storage) {
75 return sizeNeeded;
76 }
77
78 int firstDir = isCCW ? (int)SkPathFirstDirection::kCCW : (int)SkPathFirstDirection::kCW;
79 int32_t packed = (fFillType << kFillType_SerializationShift) |
80 (firstDir << kDirection_SerializationShift) |
81 (SerializationType::kRRect << kType_SerializationShift) |
82 kCurrent_Version;
83
84 SkWBuffer buffer(storage);
85 buffer.write32(packed);
86 SkRRectPriv::WriteToBuffer(rrect, &buffer);
87 buffer.write32(SkToS32(start));
88 buffer.padToAlign4();
89 SkASSERT(sizeNeeded == buffer.pos());
90 return buffer.pos();
91 }
92
writeToMemory(void * storage) const93 size_t SkPath::writeToMemory(void* storage) const {
94 SkDEBUGCODE(this->validate();)
95
96 if (size_t bytes = this->writeToMemoryAsRRect(storage)) {
97 return bytes;
98 }
99
100 int32_t packed = (fFillType << kFillType_SerializationShift) |
101 (SerializationType::kGeneral << kType_SerializationShift) |
102 kCurrent_Version;
103
104 int32_t pts = fPathRef->countPoints();
105 int32_t cnx = fPathRef->countWeights();
106 int32_t vbs = fPathRef->countVerbs();
107
108 SkSafeMath safe;
109 size_t size = 4 * sizeof(int32_t);
110 size = safe.add(size, safe.mul(pts, sizeof(SkPoint)));
111 size = safe.add(size, safe.mul(cnx, sizeof(SkScalar)));
112 size = safe.add(size, safe.mul(vbs, sizeof(uint8_t)));
113 size = safe.alignUp(size, 4);
114 if (!safe) {
115 return 0;
116 }
117 if (!storage) {
118 return size;
119 }
120
121 SkWBuffer buffer(storage);
122 buffer.write32(packed);
123 buffer.write32(pts);
124 buffer.write32(cnx);
125 buffer.write32(vbs);
126 buffer.write(fPathRef->points(), pts * sizeof(SkPoint));
127 buffer.write(fPathRef->conicWeights(), cnx * sizeof(SkScalar));
128 buffer.write(fPathRef->verbsBegin(), vbs * sizeof(uint8_t));
129 buffer.padToAlign4();
130
131 SkASSERT(buffer.pos() == size);
132 return size;
133 }
134
serialize() const135 sk_sp<SkData> SkPath::serialize() const {
136 size_t size = this->writeToMemory(nullptr);
137 sk_sp<SkData> data = SkData::MakeUninitialized(size);
138 this->writeToMemory(data->writable_data());
139 return data;
140 }
141
142 //////////////////////////////////////////////////////////////////////////////////////////////////
143 // reading
144
readFromMemory(const void * storage,size_t length)145 size_t SkPath::readFromMemory(const void* storage, size_t length) {
146 SkRBuffer buffer(storage, length);
147 uint32_t packed;
148 if (!buffer.readU32(&packed)) {
149 return 0;
150 }
151 unsigned version = extract_version(packed);
152 if (version < kMin_Version || version > kCurrent_Version) {
153 return 0;
154 }
155
156 if (version == kJustPublicData_Version || version == kVerbsAreStoredForward_Version) {
157 return this->readFromMemory_EQ4Or5(storage, length);
158 }
159 return 0;
160 }
161
readAsRRect(const void * storage,size_t length)162 size_t SkPath::readAsRRect(const void* storage, size_t length) {
163 SkRBuffer buffer(storage, length);
164 uint32_t packed;
165 if (!buffer.readU32(&packed)) {
166 return 0;
167 }
168
169 SkASSERT(extract_serializationtype(packed) == SerializationType::kRRect);
170
171 uint8_t dir = (packed >> kDirection_SerializationShift) & 0x3;
172 SkPathFillType fillType = extract_filltype(packed);
173
174 SkPathDirection rrectDir;
175 SkRRect rrect;
176 int32_t start;
177 switch (dir) {
178 case (int)SkPathFirstDirection::kCW:
179 rrectDir = SkPathDirection::kCW;
180 break;
181 case (int)SkPathFirstDirection::kCCW:
182 rrectDir = SkPathDirection::kCCW;
183 break;
184 default:
185 return 0;
186 }
187 if (!SkRRectPriv::ReadFromBuffer(&buffer, &rrect)) {
188 return 0;
189 }
190 if (!buffer.readS32(&start) || start != SkTPin(start, 0, 7)) {
191 return 0;
192 }
193 this->reset();
194 this->addRRect(rrect, rrectDir, SkToUInt(start));
195 this->setFillType(fillType);
196 buffer.skipToAlign4();
197 return buffer.pos();
198 }
199
readFromMemory_EQ4Or5(const void * storage,size_t length)200 size_t SkPath::readFromMemory_EQ4Or5(const void* storage, size_t length) {
201 SkRBuffer buffer(storage, length);
202 uint32_t packed;
203 if (!buffer.readU32(&packed)) {
204 return 0;
205 }
206
207 bool verbsAreReversed = true;
208 if (extract_version(packed) == kVerbsAreStoredForward_Version) {
209 verbsAreReversed = false;
210 }
211
212 switch (extract_serializationtype(packed)) {
213 case SerializationType::kRRect:
214 return this->readAsRRect(storage, length);
215 case SerializationType::kGeneral:
216 break; // fall out
217 default:
218 return 0;
219 }
220
221 int32_t pts, cnx, vbs;
222 if (!buffer.readS32(&pts) || !buffer.readS32(&cnx) || !buffer.readS32(&vbs)) {
223 return 0;
224 }
225
226 const SkPoint* points = buffer.skipCount<SkPoint>(pts);
227 const SkScalar* conics = buffer.skipCount<SkScalar>(cnx);
228 const uint8_t* verbs = buffer.skipCount<uint8_t>(vbs);
229 buffer.skipToAlign4();
230 if (!buffer.isValid()) {
231 return 0;
232 }
233 SkASSERT(buffer.pos() <= length);
234
235 #define CHECK_POINTS_CONICS(p, c) \
236 do { \
237 if (p && ((pts -= p) < 0)) { \
238 return 0; \
239 } \
240 if (c && ((cnx -= c) < 0)) { \
241 return 0; \
242 } \
243 } while (0)
244
245 int verbsStep = 1;
246 if (verbsAreReversed) {
247 verbs += vbs - 1;
248 verbsStep = -1;
249 }
250
251 SkPath tmp;
252 tmp.setFillType(extract_filltype(packed));
253 tmp.incReserve(pts);
254 for (int i = 0; i < vbs; ++i) {
255 switch (*verbs) {
256 case kMove_Verb:
257 CHECK_POINTS_CONICS(1, 0);
258 tmp.moveTo(*points++);
259 break;
260 case kLine_Verb:
261 CHECK_POINTS_CONICS(1, 0);
262 tmp.lineTo(*points++);
263 break;
264 case kQuad_Verb:
265 CHECK_POINTS_CONICS(2, 0);
266 tmp.quadTo(points[0], points[1]);
267 points += 2;
268 break;
269 case kConic_Verb:
270 CHECK_POINTS_CONICS(2, 1);
271 tmp.conicTo(points[0], points[1], *conics++);
272 points += 2;
273 break;
274 case kCubic_Verb:
275 CHECK_POINTS_CONICS(3, 0);
276 tmp.cubicTo(points[0], points[1], points[2]);
277 points += 3;
278 break;
279 case kClose_Verb:
280 tmp.close();
281 break;
282 default:
283 return 0; // bad verb
284 }
285 verbs += verbsStep;
286 }
287 #undef CHECK_POINTS_CONICS
288 if (pts || cnx) {
289 return 0; // leftover points and/or conics
290 }
291
292 *this = std::move(tmp);
293 return buffer.pos();
294 }
295