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 
extract_version(uint32_t packed)43 static unsigned extract_version(uint32_t packed) {
44     return packed & kVersion_SerializationMask;
45 }
46 
extract_filltype(uint32_t packed)47 static SkPath::FillType extract_filltype(uint32_t packed) {
48     return static_cast<SkPath::FillType>((packed >> kFillType_SerializationShift) & 0x3);
49 }
50 
extract_serializationtype(uint32_t packed)51 static SerializationType extract_serializationtype(uint32_t packed) {
52     return static_cast<SerializationType>((packed >> kType_SerializationShift) & 0xF);
53 }
54 
55 ///////////////////////////////////////////////////////////////////////////////////////////////////
56 
writeToMemoryAsRRect(void * storage) const57 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 
writeToMemory(void * storage) const91 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 
serialize() const133 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 
readFromMemory(const void * storage,size_t length)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 
readAsRRect(const void * storage,size_t length)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     FillType fillType = extract_filltype(packed);
171 
172     Direction rrectDir;
173     SkRRect rrect;
174     int32_t start;
175     switch (dir) {
176         case SkPathPriv::kCW_FirstDirection:
177             rrectDir = kCW_Direction;
178             break;
179         case SkPathPriv::kCCW_FirstDirection:
180             rrectDir = kCCW_Direction;
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 
readFromMemory_EQ4Or5(const void * storage,size_t length)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