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