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/SkPath.h"
10 #include "include/core/SkPathTypes.h"
11 #include "include/core/SkRRect.h"
12 #include "include/core/SkRect.h"
13 #include "include/core/SkRefCnt.h"
14 #include "include/core/SkScalar.h"
15 #include "include/private/SkPathRef.h"
16 #include "include/private/base/SkAssert.h"
17 #include "include/private/base/SkDebug.h"
18 #include "include/private/base/SkPoint_impl.h"
19 #include "include/private/base/SkTPin.h"
20 #include "include/private/base/SkTo.h"
21 #include "src/base/SkAutoMalloc.h"
22 #include "src/base/SkBuffer.h"
23 #include "src/base/SkSafeMath.h"
24 #include "src/core/SkPathEnums.h"
25 #include "src/core/SkPathPriv.h"
26 #include "src/core/SkRRectPriv.h"
27
28 #include <cstddef>
29 #include <cstdint>
30
31 enum SerializationOffsets {
32 kType_SerializationShift = 28, // requires 4 bits
33 kDirection_SerializationShift = 26, // requires 2 bits
34 kFillType_SerializationShift = 8, // requires 8 bits
35 // low-8-bits are version
36 kVersion_SerializationMask = 0xFF,
37 };
38
39 enum SerializationVersions {
40 // kPathPrivFirstDirection_Version = 1,
41 // kPathPrivLastMoveToIndex_Version = 2,
42 // kPathPrivTypeEnumVersion = 3,
43 kJustPublicData_Version = 4, // introduced Feb/2018
44 kVerbsAreStoredForward_Version = 5, // introduced Sept/2019
45
46 kMin_Version = kJustPublicData_Version,
47 kCurrent_Version = kVerbsAreStoredForward_Version
48 };
49
50 enum SerializationType {
51 kGeneral = 0,
52 kRRect = 1
53 };
54
extract_version(uint32_t packed)55 static unsigned extract_version(uint32_t packed) {
56 return packed & kVersion_SerializationMask;
57 }
58
extract_filltype(uint32_t packed)59 static SkPathFillType extract_filltype(uint32_t packed) {
60 return static_cast<SkPathFillType>((packed >> kFillType_SerializationShift) & 0x3);
61 }
62
extract_serializationtype(uint32_t packed)63 static SerializationType extract_serializationtype(uint32_t packed) {
64 return static_cast<SerializationType>((packed >> kType_SerializationShift) & 0xF);
65 }
66
67 ///////////////////////////////////////////////////////////////////////////////////////////////////
68
writeToMemoryAsRRect(void * storage) const69 size_t SkPath::writeToMemoryAsRRect(void* storage) const {
70 SkRect oval;
71 SkRRect rrect;
72 bool isCCW;
73 unsigned start;
74 if (fPathRef->isOval(&oval, &isCCW, &start)) {
75 rrect.setOval(oval);
76 // Convert to rrect start indices.
77 start *= 2;
78 } else if (!fPathRef->isRRect(&rrect, &isCCW, &start)) {
79 return 0;
80 }
81
82 // packed header, rrect, start index.
83 const size_t sizeNeeded = sizeof(int32_t) + SkRRect::kSizeInMemory + sizeof(int32_t);
84 if (!storage) {
85 return sizeNeeded;
86 }
87
88 int firstDir = isCCW ? (int)SkPathFirstDirection::kCCW : (int)SkPathFirstDirection::kCW;
89 int32_t packed = (fFillType << kFillType_SerializationShift) |
90 (firstDir << kDirection_SerializationShift) |
91 (SerializationType::kRRect << kType_SerializationShift) |
92 kCurrent_Version;
93
94 SkWBuffer buffer(storage);
95 buffer.write32(packed);
96 SkRRectPriv::WriteToBuffer(rrect, &buffer);
97 buffer.write32(SkToS32(start));
98 buffer.padToAlign4();
99 SkASSERT(sizeNeeded == buffer.pos());
100 return buffer.pos();
101 }
102
writeToMemory(void * storage) const103 size_t SkPath::writeToMemory(void* storage) const {
104 SkDEBUGCODE(this->validate();)
105
106 if (size_t bytes = this->writeToMemoryAsRRect(storage)) {
107 return bytes;
108 }
109
110 int32_t packed = (fFillType << kFillType_SerializationShift) |
111 (SerializationType::kGeneral << kType_SerializationShift) |
112 kCurrent_Version;
113
114 int32_t pts = fPathRef->countPoints();
115 int32_t cnx = fPathRef->countWeights();
116 int32_t vbs = fPathRef->countVerbs();
117
118 SkSafeMath safe;
119 size_t size = 4 * sizeof(int32_t);
120 size = safe.add(size, safe.mul(pts, sizeof(SkPoint)));
121 size = safe.add(size, safe.mul(cnx, sizeof(SkScalar)));
122 size = safe.add(size, safe.mul(vbs, sizeof(uint8_t)));
123 size = safe.alignUp(size, 4);
124 if (!safe) {
125 return 0;
126 }
127 if (!storage) {
128 return size;
129 }
130
131 SkWBuffer buffer(storage);
132 buffer.write32(packed);
133 buffer.write32(pts);
134 buffer.write32(cnx);
135 buffer.write32(vbs);
136 buffer.write(fPathRef->points(), pts * sizeof(SkPoint));
137 buffer.write(fPathRef->conicWeights(), cnx * sizeof(SkScalar));
138 buffer.write(fPathRef->verbsBegin(), vbs * sizeof(uint8_t));
139 buffer.padToAlign4();
140
141 SkASSERT(buffer.pos() == size);
142 return size;
143 }
144
serialize() const145 sk_sp<SkData> SkPath::serialize() const {
146 size_t size = this->writeToMemory(nullptr);
147 sk_sp<SkData> data = SkData::MakeUninitialized(size);
148 this->writeToMemory(data->writable_data());
149 return data;
150 }
151
152 //////////////////////////////////////////////////////////////////////////////////////////////////
153 // reading
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 SkPathFillType fillType = extract_filltype(packed);
166
167 SkPathDirection rrectDir;
168 SkRRect rrect;
169 int32_t start;
170 switch (dir) {
171 case (int)SkPathFirstDirection::kCW:
172 rrectDir = SkPathDirection::kCW;
173 break;
174 case (int)SkPathFirstDirection::kCCW:
175 rrectDir = SkPathDirection::kCCW;
176 break;
177 default:
178 return 0;
179 }
180 if (!SkRRectPriv::ReadFromBuffer(&buffer, &rrect)) {
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(const void * storage,size_t length)193 size_t SkPath::readFromMemory(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 unsigned version = extract_version(packed);
200
201 const bool verbsAreForward = (version == kVerbsAreStoredForward_Version);
202 if (!verbsAreForward && version != kJustPublicData_Version) SK_UNLIKELY {
203 // Old/unsupported version.
204 return 0;
205 }
206
207 switch (extract_serializationtype(packed)) {
208 case SerializationType::kRRect:
209 return this->readAsRRect(storage, length);
210 case SerializationType::kGeneral:
211 break; // fall out
212 default:
213 return 0;
214 }
215
216 // To minimize the number of reads done a structure with the counts is used.
217 struct {
218 int32_t pts, cnx, vbs;
219 } counts;
220 if (!buffer.read(&counts, sizeof(counts))) {
221 return 0;
222 }
223
224 const SkPoint* points = buffer.skipCount<SkPoint>(counts.pts);
225 const SkScalar* conics = buffer.skipCount<SkScalar>(counts.cnx);
226 const uint8_t* verbs = buffer.skipCount<uint8_t>(counts.vbs);
227 buffer.skipToAlign4();
228 if (!buffer.isValid()) {
229 return 0;
230 }
231 SkASSERT(buffer.pos() <= length);
232
233 if (counts.vbs == 0) {
234 if (counts.pts == 0 && counts.cnx == 0) {
235 reset();
236 setFillType(extract_filltype(packed));
237 return buffer.pos();
238 }
239 // No verbs but points and/or conic weights is a not a valid path.
240 return 0;
241 }
242
243 SkAutoMalloc reversedStorage;
244 if (!verbsAreForward) SK_UNLIKELY {
245 uint8_t* tmpVerbs = (uint8_t*)reversedStorage.reset(counts.vbs);
246 for (int i = 0; i < counts.vbs; ++i) {
247 tmpVerbs[i] = verbs[counts.vbs - i - 1];
248 }
249 verbs = tmpVerbs;
250 }
251
252 SkPathVerbAnalysis analysis = SkPathPriv::AnalyzeVerbs(verbs, counts.vbs);
253 if (!analysis.valid || analysis.points != counts.pts || analysis.weights != counts.cnx) {
254 return 0;
255 }
256 *this = SkPathPriv::MakePath(analysis, points, verbs, counts.vbs, conics,
257 extract_filltype(packed), false);
258 return buffer.pos();
259 }
260