xref: /aosp_15_r20/external/skia/src/core/SkPath_serial.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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/SkPath.h"
10 #include "include/core/SkPathTypes.h"
11 #include "include/core/SkRRect.h"
12 #include "include/core/SkRect.h"
13 #include "include/core/SkRefCnt.h"
14 #include "include/core/SkScalar.h"
15 #include "include/private/SkPathRef.h"
16 #include "include/private/base/SkAssert.h"
17 #include "include/private/base/SkDebug.h"
18 #include "include/private/base/SkPoint_impl.h"
19 #include "include/private/base/SkTPin.h"
20 #include "include/private/base/SkTo.h"
21 #include "src/base/SkAutoMalloc.h"
22 #include "src/base/SkBuffer.h"
23 #include "src/base/SkSafeMath.h"
24 #include "src/core/SkPathEnums.h"
25 #include "src/core/SkPathPriv.h"
26 #include "src/core/SkRRectPriv.h"
27 
28 #include <cstddef>
29 #include <cstdint>
30 
31 enum SerializationOffsets {
32     kType_SerializationShift = 28,       // requires 4 bits
33     kDirection_SerializationShift = 26,  // requires 2 bits
34     kFillType_SerializationShift = 8,    // requires 8 bits
35     // low-8-bits are version
36     kVersion_SerializationMask = 0xFF,
37 };
38 
39 enum SerializationVersions {
40     // kPathPrivFirstDirection_Version = 1,
41     // kPathPrivLastMoveToIndex_Version = 2,
42     // kPathPrivTypeEnumVersion = 3,
43     kJustPublicData_Version = 4,            // introduced Feb/2018
44     kVerbsAreStoredForward_Version = 5,     // introduced Sept/2019
45 
46     kMin_Version     = kJustPublicData_Version,
47     kCurrent_Version = kVerbsAreStoredForward_Version
48 };
49 
50 enum SerializationType {
51     kGeneral = 0,
52     kRRect = 1
53 };
54 
extract_version(uint32_t packed)55 static unsigned extract_version(uint32_t packed) {
56     return packed & kVersion_SerializationMask;
57 }
58 
extract_filltype(uint32_t packed)59 static SkPathFillType extract_filltype(uint32_t packed) {
60     return static_cast<SkPathFillType>((packed >> kFillType_SerializationShift) & 0x3);
61 }
62 
extract_serializationtype(uint32_t packed)63 static SerializationType extract_serializationtype(uint32_t packed) {
64     return static_cast<SerializationType>((packed >> kType_SerializationShift) & 0xF);
65 }
66 
67 ///////////////////////////////////////////////////////////////////////////////////////////////////
68 
writeToMemoryAsRRect(void * storage) const69 size_t SkPath::writeToMemoryAsRRect(void* storage) const {
70     SkRect oval;
71     SkRRect rrect;
72     bool isCCW;
73     unsigned start;
74     if (fPathRef->isOval(&oval, &isCCW, &start)) {
75         rrect.setOval(oval);
76         // Convert to rrect start indices.
77         start *= 2;
78     } else if (!fPathRef->isRRect(&rrect, &isCCW, &start)) {
79         return 0;
80     }
81 
82     // packed header, rrect, start index.
83     const size_t sizeNeeded = sizeof(int32_t) + SkRRect::kSizeInMemory + sizeof(int32_t);
84     if (!storage) {
85         return sizeNeeded;
86     }
87 
88     int firstDir = isCCW ? (int)SkPathFirstDirection::kCCW : (int)SkPathFirstDirection::kCW;
89     int32_t packed = (fFillType << kFillType_SerializationShift) |
90                      (firstDir << kDirection_SerializationShift) |
91                      (SerializationType::kRRect << kType_SerializationShift) |
92                      kCurrent_Version;
93 
94     SkWBuffer buffer(storage);
95     buffer.write32(packed);
96     SkRRectPriv::WriteToBuffer(rrect, &buffer);
97     buffer.write32(SkToS32(start));
98     buffer.padToAlign4();
99     SkASSERT(sizeNeeded == buffer.pos());
100     return buffer.pos();
101 }
102 
writeToMemory(void * storage) const103 size_t SkPath::writeToMemory(void* storage) const {
104     SkDEBUGCODE(this->validate();)
105 
106     if (size_t bytes = this->writeToMemoryAsRRect(storage)) {
107         return bytes;
108     }
109 
110     int32_t packed = (fFillType << kFillType_SerializationShift) |
111                      (SerializationType::kGeneral << kType_SerializationShift) |
112                      kCurrent_Version;
113 
114     int32_t pts = fPathRef->countPoints();
115     int32_t cnx = fPathRef->countWeights();
116     int32_t vbs = fPathRef->countVerbs();
117 
118     SkSafeMath safe;
119     size_t size = 4 * sizeof(int32_t);
120     size = safe.add(size, safe.mul(pts, sizeof(SkPoint)));
121     size = safe.add(size, safe.mul(cnx, sizeof(SkScalar)));
122     size = safe.add(size, safe.mul(vbs, sizeof(uint8_t)));
123     size = safe.alignUp(size, 4);
124     if (!safe) {
125         return 0;
126     }
127     if (!storage) {
128         return size;
129     }
130 
131     SkWBuffer buffer(storage);
132     buffer.write32(packed);
133     buffer.write32(pts);
134     buffer.write32(cnx);
135     buffer.write32(vbs);
136     buffer.write(fPathRef->points(), pts * sizeof(SkPoint));
137     buffer.write(fPathRef->conicWeights(), cnx * sizeof(SkScalar));
138     buffer.write(fPathRef->verbsBegin(), vbs * sizeof(uint8_t));
139     buffer.padToAlign4();
140 
141     SkASSERT(buffer.pos() == size);
142     return size;
143 }
144 
serialize() const145 sk_sp<SkData> SkPath::serialize() const {
146     size_t size = this->writeToMemory(nullptr);
147     sk_sp<SkData> data = SkData::MakeUninitialized(size);
148     this->writeToMemory(data->writable_data());
149     return data;
150 }
151 
152 //////////////////////////////////////////////////////////////////////////////////////////////////
153 // reading
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     SkPathFillType fillType = extract_filltype(packed);
166 
167     SkPathDirection rrectDir;
168     SkRRect rrect;
169     int32_t start;
170     switch (dir) {
171         case (int)SkPathFirstDirection::kCW:
172             rrectDir = SkPathDirection::kCW;
173             break;
174         case (int)SkPathFirstDirection::kCCW:
175             rrectDir = SkPathDirection::kCCW;
176             break;
177         default:
178             return 0;
179     }
180     if (!SkRRectPriv::ReadFromBuffer(&buffer, &rrect)) {
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(const void * storage,size_t length)193 size_t SkPath::readFromMemory(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     unsigned version = extract_version(packed);
200 
201     const bool verbsAreForward = (version == kVerbsAreStoredForward_Version);
202     if (!verbsAreForward && version != kJustPublicData_Version) SK_UNLIKELY {
203         // Old/unsupported version.
204         return 0;
205     }
206 
207     switch (extract_serializationtype(packed)) {
208         case SerializationType::kRRect:
209             return this->readAsRRect(storage, length);
210         case SerializationType::kGeneral:
211             break;  // fall out
212         default:
213             return 0;
214     }
215 
216     // To minimize the number of reads done a structure with the counts is used.
217     struct {
218       int32_t pts, cnx, vbs;
219     } counts;
220     if (!buffer.read(&counts, sizeof(counts))) {
221         return 0;
222     }
223 
224     const SkPoint* points = buffer.skipCount<SkPoint>(counts.pts);
225     const SkScalar* conics = buffer.skipCount<SkScalar>(counts.cnx);
226     const uint8_t* verbs = buffer.skipCount<uint8_t>(counts.vbs);
227     buffer.skipToAlign4();
228     if (!buffer.isValid()) {
229         return 0;
230     }
231     SkASSERT(buffer.pos() <= length);
232 
233     if (counts.vbs == 0) {
234         if (counts.pts == 0 && counts.cnx == 0) {
235             reset();
236             setFillType(extract_filltype(packed));
237             return buffer.pos();
238         }
239         // No verbs but points and/or conic weights is a not a valid path.
240         return 0;
241     }
242 
243     SkAutoMalloc reversedStorage;
244     if (!verbsAreForward) SK_UNLIKELY {
245       uint8_t* tmpVerbs = (uint8_t*)reversedStorage.reset(counts.vbs);
246         for (int i = 0; i < counts.vbs; ++i) {
247             tmpVerbs[i] = verbs[counts.vbs - i - 1];
248         }
249         verbs = tmpVerbs;
250     }
251 
252     SkPathVerbAnalysis analysis = SkPathPriv::AnalyzeVerbs(verbs, counts.vbs);
253     if (!analysis.valid || analysis.points != counts.pts || analysis.weights != counts.cnx) {
254         return 0;
255     }
256     *this = SkPathPriv::MakePath(analysis, points, verbs, counts.vbs, conics,
257                                  extract_filltype(packed), false);
258     return buffer.pos();
259 }
260