• 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 "include/core/SkData.h"
9 #include "include/private/SkPathRef.h"
10 #include "include/private/base/SkMath.h"
11 #include "include/private/base/SkPathEnums.h"
12 #include "include/private/base/SkTPin.h"
13 #include "include/private/base/SkTo.h"
14 #include "src/base/SkBuffer.h"
15 #include "src/base/SkSafeMath.h"
16 #include "src/core/SkPathPriv.h"
17 #include "src/core/SkRRectPriv.h"
18 
19 #include <cmath>
20 
21 enum SerializationOffsets {
22     kType_SerializationShift = 28,       // requires 4 bits
23     kDirection_SerializationShift = 26,  // requires 2 bits
24     kFillType_SerializationShift = 8,    // requires 8 bits
25     // low-8-bits are version
26     kVersion_SerializationMask = 0xFF,
27 };
28 
29 enum SerializationVersions {
30     // kPathPrivFirstDirection_Version = 1,
31     // kPathPrivLastMoveToIndex_Version = 2,
32     // kPathPrivTypeEnumVersion = 3,
33     kJustPublicData_Version = 4,            // introduced Feb/2018
34     kVerbsAreStoredForward_Version = 5,     // introduced Sept/2019
35 
36     kMin_Version     = kJustPublicData_Version,
37     kCurrent_Version = kVerbsAreStoredForward_Version
38 };
39 
40 enum SerializationType {
41     kGeneral = 0,
42     kRRect = 1
43 };
44 
extract_version(uint32_t packed)45 static unsigned extract_version(uint32_t packed) {
46     return packed & kVersion_SerializationMask;
47 }
48 
extract_filltype(uint32_t packed)49 static SkPathFillType extract_filltype(uint32_t packed) {
50     return static_cast<SkPathFillType>((packed >> kFillType_SerializationShift) & 0x3);
51 }
52 
extract_serializationtype(uint32_t packed)53 static SerializationType extract_serializationtype(uint32_t packed) {
54     return static_cast<SerializationType>((packed >> kType_SerializationShift) & 0xF);
55 }
56 
57 ///////////////////////////////////////////////////////////////////////////////////////////////////
58 
writeToMemoryAsRRect(void * storage) const59 size_t SkPath::writeToMemoryAsRRect(void* storage) const {
60     SkRect oval;
61     SkRRect rrect;
62     bool isCCW;
63     unsigned start;
64     if (fPathRef->isOval(&oval, &isCCW, &start)) {
65         rrect.setOval(oval);
66         // Convert to rrect start indices.
67         start *= 2;
68     } else if (!fPathRef->isRRect(&rrect, &isCCW, &start)) {
69         return 0;
70     }
71 
72     // packed header, rrect, start index.
73     const size_t sizeNeeded = sizeof(int32_t) + SkRRect::kSizeInMemory + sizeof(int32_t);
74     if (!storage) {
75         return sizeNeeded;
76     }
77 
78     int firstDir = isCCW ? (int)SkPathFirstDirection::kCCW : (int)SkPathFirstDirection::kCW;
79     int32_t packed = (fFillType << kFillType_SerializationShift) |
80                      (firstDir << kDirection_SerializationShift) |
81                      (SerializationType::kRRect << kType_SerializationShift) |
82                      kCurrent_Version;
83 
84     SkWBuffer buffer(storage);
85     buffer.write32(packed);
86     SkRRectPriv::WriteToBuffer(rrect, &buffer);
87     buffer.write32(SkToS32(start));
88     buffer.padToAlign4();
89     SkASSERT(sizeNeeded == buffer.pos());
90     return buffer.pos();
91 }
92 
writeToMemory(void * storage) const93 size_t SkPath::writeToMemory(void* storage) const {
94     SkDEBUGCODE(this->validate();)
95 
96     if (size_t bytes = this->writeToMemoryAsRRect(storage)) {
97         return bytes;
98     }
99 
100     int32_t packed = (fFillType << kFillType_SerializationShift) |
101                      (SerializationType::kGeneral << kType_SerializationShift) |
102                      kCurrent_Version;
103 
104     int32_t pts = fPathRef->countPoints();
105     int32_t cnx = fPathRef->countWeights();
106     int32_t vbs = fPathRef->countVerbs();
107 
108     SkSafeMath safe;
109     size_t size = 4 * sizeof(int32_t);
110     size = safe.add(size, safe.mul(pts, sizeof(SkPoint)));
111     size = safe.add(size, safe.mul(cnx, sizeof(SkScalar)));
112     size = safe.add(size, safe.mul(vbs, sizeof(uint8_t)));
113     size = safe.alignUp(size, 4);
114     if (!safe) {
115         return 0;
116     }
117     if (!storage) {
118         return size;
119     }
120 
121     SkWBuffer buffer(storage);
122     buffer.write32(packed);
123     buffer.write32(pts);
124     buffer.write32(cnx);
125     buffer.write32(vbs);
126     buffer.write(fPathRef->points(), pts * sizeof(SkPoint));
127     buffer.write(fPathRef->conicWeights(), cnx * sizeof(SkScalar));
128     buffer.write(fPathRef->verbsBegin(), vbs * sizeof(uint8_t));
129     buffer.padToAlign4();
130 
131     SkASSERT(buffer.pos() == size);
132     return size;
133 }
134 
serialize() const135 sk_sp<SkData> SkPath::serialize() const {
136     size_t size = this->writeToMemory(nullptr);
137     sk_sp<SkData> data = SkData::MakeUninitialized(size);
138     this->writeToMemory(data->writable_data());
139     return data;
140 }
141 
142 //////////////////////////////////////////////////////////////////////////////////////////////////
143 // reading
144 
readFromMemory(const void * storage,size_t length)145 size_t SkPath::readFromMemory(const void* storage, size_t length) {
146     SkRBuffer buffer(storage, length);
147     uint32_t packed;
148     if (!buffer.readU32(&packed)) {
149         return 0;
150     }
151     unsigned version = extract_version(packed);
152     if (version < kMin_Version || version > kCurrent_Version) {
153         return 0;
154     }
155 
156     if (version == kJustPublicData_Version || version == kVerbsAreStoredForward_Version) {
157         return this->readFromMemory_EQ4Or5(storage, length);
158     }
159     return 0;
160 }
161 
readAsRRect(const void * storage,size_t length)162 size_t SkPath::readAsRRect(const void* storage, size_t length) {
163     SkRBuffer buffer(storage, length);
164     uint32_t packed;
165     if (!buffer.readU32(&packed)) {
166         return 0;
167     }
168 
169     SkASSERT(extract_serializationtype(packed) == SerializationType::kRRect);
170 
171     uint8_t dir = (packed >> kDirection_SerializationShift) & 0x3;
172     SkPathFillType fillType = extract_filltype(packed);
173 
174     SkPathDirection rrectDir;
175     SkRRect rrect;
176     int32_t start;
177     switch (dir) {
178         case (int)SkPathFirstDirection::kCW:
179             rrectDir = SkPathDirection::kCW;
180             break;
181         case (int)SkPathFirstDirection::kCCW:
182             rrectDir = SkPathDirection::kCCW;
183             break;
184         default:
185             return 0;
186     }
187     if (!SkRRectPriv::ReadFromBuffer(&buffer, &rrect)) {
188         return 0;
189     }
190     if (!buffer.readS32(&start) || start != SkTPin(start, 0, 7)) {
191         return 0;
192     }
193     this->reset();
194     this->addRRect(rrect, rrectDir, SkToUInt(start));
195     this->setFillType(fillType);
196     buffer.skipToAlign4();
197     return buffer.pos();
198 }
199 
readFromMemory_EQ4Or5(const void * storage,size_t length)200 size_t SkPath::readFromMemory_EQ4Or5(const void* storage, size_t length) {
201     SkRBuffer buffer(storage, length);
202     uint32_t packed;
203     if (!buffer.readU32(&packed)) {
204         return 0;
205     }
206 
207     bool verbsAreReversed = true;
208     if (extract_version(packed) == kVerbsAreStoredForward_Version) {
209         verbsAreReversed = false;
210     }
211 
212     switch (extract_serializationtype(packed)) {
213         case SerializationType::kRRect:
214             return this->readAsRRect(storage, length);
215         case SerializationType::kGeneral:
216             break;  // fall out
217         default:
218             return 0;
219     }
220 
221     int32_t pts, cnx, vbs;
222     if (!buffer.readS32(&pts) || !buffer.readS32(&cnx) || !buffer.readS32(&vbs)) {
223         return 0;
224     }
225 
226     const SkPoint* points = buffer.skipCount<SkPoint>(pts);
227     const SkScalar* conics = buffer.skipCount<SkScalar>(cnx);
228     const uint8_t* verbs = buffer.skipCount<uint8_t>(vbs);
229     buffer.skipToAlign4();
230     if (!buffer.isValid()) {
231         return 0;
232     }
233     SkASSERT(buffer.pos() <= length);
234 
235 #define CHECK_POINTS_CONICS(p, c)       \
236     do {                                \
237         if (p && ((pts -= p) < 0)) {    \
238             return 0;                   \
239         }                               \
240         if (c && ((cnx -= c) < 0)) {    \
241             return 0;                   \
242         }                               \
243     } while (0)
244 
245     int verbsStep = 1;
246     if (verbsAreReversed) {
247         verbs += vbs - 1;
248         verbsStep = -1;
249     }
250 
251     SkPath tmp;
252     tmp.setFillType(extract_filltype(packed));
253     tmp.incReserve(pts);
254     for (int i = 0; i < vbs; ++i) {
255         switch (*verbs) {
256             case kMove_Verb:
257                 CHECK_POINTS_CONICS(1, 0);
258                 tmp.moveTo(*points++);
259                 break;
260             case kLine_Verb:
261                 CHECK_POINTS_CONICS(1, 0);
262                 tmp.lineTo(*points++);
263                 break;
264             case kQuad_Verb:
265                 CHECK_POINTS_CONICS(2, 0);
266                 tmp.quadTo(points[0], points[1]);
267                 points += 2;
268                 break;
269             case kConic_Verb:
270                 CHECK_POINTS_CONICS(2, 1);
271                 tmp.conicTo(points[0], points[1], *conics++);
272                 points += 2;
273                 break;
274             case kCubic_Verb:
275                 CHECK_POINTS_CONICS(3, 0);
276                 tmp.cubicTo(points[0], points[1], points[2]);
277                 points += 3;
278                 break;
279             case kClose_Verb:
280                 tmp.close();
281                 break;
282             default:
283                 return 0;   // bad verb
284         }
285         verbs += verbsStep;
286     }
287 #undef CHECK_POINTS_CONICS
288     if (pts || cnx) {
289         return 0;   // leftover points and/or conics
290     }
291 
292     *this = std::move(tmp);
293     return buffer.pos();
294 }
295