SkPath_serial.cpp (9098B)
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 #include <optional> 31 32 enum SerializationOffsets { 33 kType_SerializationShift = 28, // requires 4 bits 34 kDirection_SerializationShift = 26, // requires 2 bits 35 kFillType_SerializationShift = 8, // requires 8 bits 36 // low-8-bits are version 37 kVersion_SerializationMask = 0xFF, 38 }; 39 40 enum SerializationVersions { 41 // kPathPrivFirstDirection_Version = 1, 42 // kPathPrivLastMoveToIndex_Version = 2, 43 // kPathPrivTypeEnumVersion = 3, 44 kJustPublicData_Version = 4, // introduced Feb/2018 45 kVerbsAreStoredForward_Version = 5, // introduced Sept/2019 46 47 kMin_Version = kJustPublicData_Version, 48 kCurrent_Version = kVerbsAreStoredForward_Version 49 }; 50 51 enum SerializationType { 52 kGeneral = 0, 53 kRRect = 1 54 }; 55 56 static unsigned extract_version(uint32_t packed) { 57 return packed & kVersion_SerializationMask; 58 } 59 60 static SkPathFillType extract_filltype(uint32_t packed) { 61 return static_cast<SkPathFillType>((packed >> kFillType_SerializationShift) & 0x3); 62 } 63 64 static SerializationType extract_serializationtype(uint32_t packed) { 65 return static_cast<SerializationType>((packed >> kType_SerializationShift) & 0xF); 66 } 67 68 /////////////////////////////////////////////////////////////////////////////////////////////////// 69 70 size_t SkPath::writeToMemoryAsRRect(void* storage) const { 71 SkRRect rrect; 72 SkPathDirection firstDir; 73 unsigned start; 74 75 if (auto oinfo = fPathRef->isOval()) { 76 rrect.setOval(oinfo->fBounds); 77 firstDir = oinfo->fDirection; 78 // Convert to rrect start indices. 79 start = oinfo->fStartIndex * 2; 80 } else if (auto rinfo = fPathRef->isRRect()) { 81 rrect = rinfo->fRRect; 82 firstDir = rinfo->fDirection; 83 start = rinfo->fStartIndex; 84 } else { 85 return 0; 86 } 87 88 // packed header, rrect, start index. 89 const size_t sizeNeeded = sizeof(int32_t) + SkRRect::kSizeInMemory + sizeof(int32_t); 90 if (!storage) { 91 return sizeNeeded; 92 } 93 94 int32_t packed = (fFillType << kFillType_SerializationShift) | 95 ((int)firstDir << kDirection_SerializationShift) | 96 (SerializationType::kRRect << kType_SerializationShift) | 97 kCurrent_Version; 98 99 SkWBuffer buffer(storage); 100 buffer.write32(packed); 101 SkRRectPriv::WriteToBuffer(rrect, &buffer); 102 buffer.write32(SkToS32(start)); 103 buffer.padToAlign4(); 104 SkASSERT(sizeNeeded == buffer.pos()); 105 return buffer.pos(); 106 } 107 108 size_t SkPath::writeToMemory(void* storage) const { 109 SkDEBUGCODE(this->validate();) 110 111 if (size_t bytes = this->writeToMemoryAsRRect(storage)) { 112 return bytes; 113 } 114 115 int32_t packed = (fFillType << kFillType_SerializationShift) | 116 (SerializationType::kGeneral << kType_SerializationShift) | 117 kCurrent_Version; 118 119 int32_t pts = fPathRef->countPoints(); 120 int32_t cnx = fPathRef->countWeights(); 121 int32_t vbs = fPathRef->countVerbs(); 122 123 SkSafeMath safe; 124 size_t size = 4 * sizeof(int32_t); 125 size = safe.add(size, safe.mul(pts, sizeof(SkPoint))); 126 size = safe.add(size, safe.mul(cnx, sizeof(SkScalar))); 127 size = safe.add(size, safe.mul(vbs, sizeof(uint8_t))); 128 size = safe.alignUp(size, 4); 129 if (!safe) { 130 return 0; 131 } 132 if (!storage) { 133 return size; 134 } 135 136 SkWBuffer buffer(storage); 137 buffer.write32(packed); 138 buffer.write32(pts); 139 buffer.write32(cnx); 140 buffer.write32(vbs); 141 buffer.write(fPathRef->points(), pts * sizeof(SkPoint)); 142 buffer.write(fPathRef->conicWeights(), cnx * sizeof(SkScalar)); 143 buffer.write(fPathRef->verbsBegin(), vbs * sizeof(uint8_t)); 144 buffer.padToAlign4(); 145 146 SkASSERT(buffer.pos() == size); 147 return size; 148 } 149 150 sk_sp<SkData> SkPath::serialize() const { 151 size_t size = this->writeToMemory(nullptr); 152 sk_sp<SkData> data = SkData::MakeUninitialized(size); 153 this->writeToMemory(data->writable_data()); 154 return data; 155 } 156 157 ////////////////////////////////////////////////////////////////////////////////////////////////// 158 // reading 159 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 SkPathFillType fillType = extract_filltype(packed); 171 172 SkPathDirection rrectDir; 173 SkRRect rrect; 174 int32_t start; 175 switch (dir) { 176 case (int)SkPathFirstDirection::kCW: 177 rrectDir = SkPathDirection::kCW; 178 break; 179 case (int)SkPathFirstDirection::kCCW: 180 rrectDir = SkPathDirection::kCCW; 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 198 #ifndef SK_HIDE_PATH_EDIT_METHODS 199 size_t SkPath::readFromMemory(const void* storage, size_t length) { 200 size_t bytesRead = 0; 201 if (auto path = SkPath::ReadFromMemory(storage, length, &bytesRead)) { 202 *this = path.value(); 203 } 204 return bytesRead; 205 } 206 #endif 207 208 #define RETURN_PATH_AND_BYTES(p, b) \ 209 do { if (bytesRead) { *bytesRead = b; }; return p; } while (0) 210 211 std::optional<SkPath> SkPath::ReadFromMemory(const void* storage, size_t length, size_t* bytesRead) { 212 SkRBuffer buffer(storage, length); 213 uint32_t packed; 214 if (!buffer.readU32(&packed)) { 215 RETURN_PATH_AND_BYTES(std::nullopt, 0); 216 } 217 unsigned version = extract_version(packed); 218 219 const bool verbsAreForward = (version == kVerbsAreStoredForward_Version); 220 if (!verbsAreForward && version != kJustPublicData_Version) SK_UNLIKELY { 221 // Old/unsupported version. 222 RETURN_PATH_AND_BYTES(std::nullopt, 0); 223 } 224 225 SkPath path; 226 size_t tmp; 227 switch (extract_serializationtype(packed)) { 228 case SerializationType::kRRect: 229 tmp = path.readAsRRect(storage, length); 230 RETURN_PATH_AND_BYTES(path, tmp); 231 case SerializationType::kGeneral: 232 break; // fall out 233 default: 234 RETURN_PATH_AND_BYTES(std::nullopt, 0); 235 } 236 237 // To minimize the number of reads done a structure with the counts is used. 238 struct { 239 uint32_t pts, cnx, vbs; 240 } counts; 241 if (!buffer.read(&counts, sizeof(counts))) { 242 RETURN_PATH_AND_BYTES(std::nullopt, 0); 243 } 244 245 const SkPoint* points = buffer.skipCount<SkPoint>(counts.pts); 246 const SkScalar* conics = buffer.skipCount<SkScalar>(counts.cnx); 247 const SkPathVerb* verbs = buffer.skipCount<SkPathVerb>(counts.vbs); 248 buffer.skipToAlign4(); 249 if (!buffer.isValid()) { 250 RETURN_PATH_AND_BYTES(std::nullopt, 0); 251 } 252 SkASSERT(buffer.pos() <= length); 253 254 if (counts.vbs == 0) { 255 if (counts.pts == 0 && counts.cnx == 0) { 256 path.setFillType(extract_filltype(packed)); 257 if (bytesRead) { 258 *bytesRead = buffer.pos(); 259 } 260 return path; 261 } 262 // No verbs but points and/or conic weights is a not a valid path. 263 RETURN_PATH_AND_BYTES(std::nullopt, 0); 264 } 265 266 SkAutoMalloc reversedStorage; 267 if (!verbsAreForward) SK_UNLIKELY { 268 SkPathVerb* tmpVerbs = (SkPathVerb*)reversedStorage.reset(counts.vbs); 269 for (unsigned i = 0; i < counts.vbs; ++i) { 270 tmpVerbs[i] = verbs[counts.vbs - i - 1]; 271 } 272 verbs = tmpVerbs; 273 } 274 275 SkSpan<const SkPathVerb> verbSpan{verbs, counts.vbs}; 276 SkPathVerbAnalysis analysis = SkPathPriv::AnalyzeVerbs(verbSpan); 277 278 if (!analysis.valid || analysis.points != counts.pts || analysis.weights != counts.cnx) { 279 RETURN_PATH_AND_BYTES(std::nullopt, 0); 280 } 281 path = SkPathPriv::MakePath(analysis, points, verbSpan, conics, 282 extract_filltype(packed), false); 283 284 RETURN_PATH_AND_BYTES(path,buffer.pos()); 285 } 286 287 #undef RETURN_PATH_AND_BYTES