• 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 <cmath>
9 #include "SkBuffer.h"
10 #include "SkData.h"
11 #include "SkMath.h"
12 #include "SkPathPriv.h"
13 #include "SkPathRef.h"
14 #include "SkRRect.h"
15 #include "SkSafeMath.h"
16 
17 enum SerializationOffsets {
18     kType_SerializationShift = 28,       // requires 4 bits
19     kDirection_SerializationShift = 26,  // requires 2 bits
20     kFillType_SerializationShift = 8,    // requires 8 bits
21     // low-8-bits are version
22     kVersion_SerializationMask = 0xFF,
23 };
24 
25 enum SerializationVersions {
26     // kPathPrivFirstDirection_Version = 1,
27     kPathPrivLastMoveToIndex_Version = 2,
28     kPathPrivTypeEnumVersion = 3,
29     kJustPublicData_Version = 4,    // introduced Feb/2018
30 
31     kCurrent_Version = kJustPublicData_Version
32 };
33 
34 enum SerializationType {
35     kGeneral = 0,
36     kRRect = 1
37 };
38 
extract_version(uint32_t packed)39 static unsigned extract_version(uint32_t packed) {
40     return packed & kVersion_SerializationMask;
41 }
42 
extract_filltype(uint32_t packed)43 static SkPath::FillType extract_filltype(uint32_t packed) {
44     return static_cast<SkPath::FillType>((packed >> kFillType_SerializationShift) & 0x3);
45 }
46 
extract_serializationtype(uint32_t packed)47 static SerializationType extract_serializationtype(uint32_t packed) {
48     return static_cast<SerializationType>((packed >> kType_SerializationShift) & 0xF);
49 }
50 
51 ///////////////////////////////////////////////////////////////////////////////////////////////////
52 
writeToMemoryAsRRect(void * storage) const53 size_t SkPath::writeToMemoryAsRRect(void* storage) const {
54     SkRect oval;
55     SkRRect rrect;
56     bool isCCW;
57     unsigned start;
58     if (fPathRef->isOval(&oval, &isCCW, &start)) {
59         rrect.setOval(oval);
60         // Convert to rrect start indices.
61         start *= 2;
62     } else if (!fPathRef->isRRect(&rrect, &isCCW, &start)) {
63         return 0;
64     }
65 
66     // packed header, rrect, start index.
67     const size_t sizeNeeded = sizeof(int32_t) + SkRRect::kSizeInMemory + sizeof(int32_t);
68     if (!storage) {
69         return sizeNeeded;
70     }
71 
72     int firstDir = isCCW ? SkPathPriv::kCCW_FirstDirection : SkPathPriv::kCW_FirstDirection;
73     int32_t packed = (fFillType << kFillType_SerializationShift) |
74                      (firstDir << kDirection_SerializationShift) |
75                      (SerializationType::kRRect << kType_SerializationShift) |
76                      kCurrent_Version;
77 
78     SkWBuffer buffer(storage);
79     buffer.write32(packed);
80     rrect.writeToBuffer(&buffer);
81     buffer.write32(SkToS32(start));
82     buffer.padToAlign4();
83     SkASSERT(sizeNeeded == buffer.pos());
84     return buffer.pos();
85 }
86 
writeToMemory(void * storage) const87 size_t SkPath::writeToMemory(void* storage) const {
88     SkDEBUGCODE(this->validate();)
89 
90     if (size_t bytes = this->writeToMemoryAsRRect(storage)) {
91         return bytes;
92     }
93 
94     int32_t packed = (fFillType << kFillType_SerializationShift) |
95                      (SerializationType::kGeneral << kType_SerializationShift) |
96                      kCurrent_Version;
97 
98     int32_t pts = fPathRef->countPoints();
99     int32_t cnx = fPathRef->countWeights();
100     int32_t vbs = fPathRef->countVerbs();
101 
102     SkSafeMath safe;
103     size_t size = 4 * sizeof(int32_t);
104     size = safe.add(size, safe.mul(pts, sizeof(SkPoint)));
105     size = safe.add(size, safe.mul(cnx, sizeof(SkScalar)));
106     size = safe.add(size, safe.mul(vbs, sizeof(uint8_t)));
107     size = safe.alignUp(size, 4);
108     if (!safe) {
109         return 0;
110     }
111     if (!storage) {
112         return size;
113     }
114 
115     SkWBuffer buffer(storage);
116     buffer.write32(packed);
117     buffer.write32(pts);
118     buffer.write32(cnx);
119     buffer.write32(vbs);
120     buffer.write(fPathRef->points(), pts * sizeof(SkPoint));
121     buffer.write(fPathRef->conicWeights(), cnx * sizeof(SkScalar));
122     buffer.write(fPathRef->verbsMemBegin(), vbs * sizeof(uint8_t));
123     buffer.padToAlign4();
124 
125     SkASSERT(buffer.pos() == size);
126     return size;
127 }
128 
serialize() const129 sk_sp<SkData> SkPath::serialize() const {
130     size_t size = this->writeToMemory(nullptr);
131     sk_sp<SkData> data = SkData::MakeUninitialized(size);
132     this->writeToMemory(data->writable_data());
133     return data;
134 }
135 
136 //////////////////////////////////////////////////////////////////////////////////////////////////
137 // reading
138 
readFromMemory(const void * storage,size_t length)139 size_t SkPath::readFromMemory(const void* storage, size_t length) {
140     SkRBuffer buffer(storage, length);
141     uint32_t packed;
142     if (!buffer.readU32(&packed)) {
143         return 0;
144     }
145     unsigned version = extract_version(packed);
146     if (version <= kPathPrivTypeEnumVersion) {
147         return this->readFromMemory_LE3(storage, length);
148     }
149     if (version == kJustPublicData_Version) {
150         return this->readFromMemory_EQ4(storage, length);
151     }
152     return 0;
153 }
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     FillType fillType = extract_filltype(packed);
166 
167     Direction rrectDir;
168     SkRRect rrect;
169     int32_t start;
170     switch (dir) {
171         case SkPathPriv::kCW_FirstDirection:
172             rrectDir = kCW_Direction;
173             break;
174         case SkPathPriv::kCCW_FirstDirection:
175             rrectDir = kCCW_Direction;
176             break;
177         default:
178             return 0;
179     }
180     if (!rrect.readFromBuffer(&buffer)) {
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_EQ4(const void * storage,size_t length)193 size_t SkPath::readFromMemory_EQ4(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 
200     SkASSERT(extract_version(packed) == 4);
201 
202     switch (extract_serializationtype(packed)) {
203         case SerializationType::kRRect:
204             return this->readAsRRect(storage, length);
205         case SerializationType::kGeneral:
206             break;  // fall through
207         default:
208             return 0;
209     }
210 
211     int32_t pts, cnx, vbs;
212     if (!buffer.readS32(&pts) || !buffer.readS32(&cnx) || !buffer.readS32(&vbs)) {
213         return 0;
214     }
215 
216     const SkPoint* points = buffer.skipCount<SkPoint>(pts);
217     const SkScalar* conics = buffer.skipCount<SkScalar>(cnx);
218     const uint8_t* verbs = buffer.skipCount<uint8_t>(vbs);
219     buffer.skipToAlign4();
220     if (!buffer.isValid()) {
221         return 0;
222     }
223     SkASSERT(buffer.pos() <= length);
224 
225 #define CHECK_POINTS_CONICS(p, c)       \
226     do {                                \
227         if (p && ((pts -= p) < 0)) {    \
228             return 0;                   \
229         }                               \
230         if (c && ((cnx -= c) < 0)) {    \
231             return 0;                   \
232         }                               \
233     } while (0)
234 
235     SkPath tmp;
236     tmp.setFillType(extract_filltype(packed));
237     tmp.incReserve(pts);
238     for (int i = vbs - 1; i >= 0; --i) {
239         switch (verbs[i]) {
240             case kMove_Verb:
241                 CHECK_POINTS_CONICS(1, 0);
242                 tmp.moveTo(*points++);
243                 break;
244             case kLine_Verb:
245                 CHECK_POINTS_CONICS(1, 0);
246                 tmp.lineTo(*points++);
247                 break;
248             case kQuad_Verb:
249                 CHECK_POINTS_CONICS(2, 0);
250                 tmp.quadTo(points[0], points[1]);
251                 points += 2;
252                 break;
253             case kConic_Verb:
254                 CHECK_POINTS_CONICS(2, 1);
255                 tmp.conicTo(points[0], points[1], *conics++);
256                 points += 2;
257                 break;
258             case kCubic_Verb:
259                 CHECK_POINTS_CONICS(3, 0);
260                 tmp.cubicTo(points[0], points[1], points[2]);
261                 points += 3;
262                 break;
263             case kClose_Verb:
264                 tmp.close();
265                 break;
266             default:
267                 return 0;   // bad verb
268         }
269     }
270 #undef CHECK_POINTS_CONICS
271     if (pts || cnx) {
272         return 0;   // leftover points and/or conics
273     }
274 
275     *this = std::move(tmp);
276     return buffer.pos();
277 }
278 
readFromMemory_LE3(const void * storage,size_t length)279 size_t SkPath::readFromMemory_LE3(const void* storage, size_t length) {
280     SkRBuffer buffer(storage, length);
281 
282     int32_t packed;
283     if (!buffer.readS32(&packed)) {
284         return 0;
285     }
286 
287     unsigned version = extract_version(packed);
288     SkASSERT(version <= 3);
289 
290     FillType fillType = extract_filltype(packed);
291     if (version >= kPathPrivTypeEnumVersion) {
292         switch (extract_serializationtype(packed)) {
293             case SerializationType::kRRect:
294                 return this->readAsRRect(storage, length);
295             case SerializationType::kGeneral:
296                 // Fall through to general path deserialization
297                 break;
298             default:
299                 return 0;
300         }
301     }
302     if (version >= kPathPrivLastMoveToIndex_Version && !buffer.readS32(&fLastMoveToIndex)) {
303         return 0;
304     }
305 
306     // These are written into the serialized data but we no longer use them in the deserialized
307     // path. If convexity is corrupted it may cause the GPU backend to make incorrect
308     // rendering choices, possibly crashing. We set them to unknown so that they'll be recomputed if
309     // requested.
310     fConvexity = kUnknown_Convexity;
311     fFirstDirection = SkPathPriv::kUnknown_FirstDirection;
312 
313     fFillType = fillType;
314     fIsVolatile = 0;
315     SkPathRef* pathRef = SkPathRef::CreateFromBuffer(&buffer);
316     if (!pathRef) {
317         return 0;
318     }
319 
320     fPathRef.reset(pathRef);
321     SkDEBUGCODE(this->validate();)
322     buffer.skipToAlign4();
323     return buffer.pos();
324 }
325 
326