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