• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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