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