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 <cmath> 9#include "SkBuffer.h" 10#include "SkData.h" 11#include "SkMath.h" 12#include "SkPathPriv.h" 13#include "SkPathRef.h" 14#include "SkRRect.h" 15#include "SkSafeMath.h" 16 17enum SerializationOffsets { 18 kType_SerializationShift = 28, // requires 4 bits 19 kDirection_SerializationShift = 26, // requires 2 bits 20 kFillType_SerializationShift = 8, // requires 8 bits 21 // low-8-bits are version 22 kVersion_SerializationMask = 0xFF, 23}; 24 25enum SerializationVersions { 26 // kPathPrivFirstDirection_Version = 1, 27 kPathPrivLastMoveToIndex_Version = 2, 28 kPathPrivTypeEnumVersion = 3, 29 kJustPublicData_Version = 4, // introduced Feb/2018 30 31 kCurrent_Version = kJustPublicData_Version 32}; 33 34enum SerializationType { 35 kGeneral = 0, 36 kRRect = 1 37}; 38 39static unsigned extract_version(uint32_t packed) { 40 return packed & kVersion_SerializationMask; 41} 42 43static SkPath::FillType extract_filltype(uint32_t packed) { 44 return static_cast<SkPath::FillType>((packed >> kFillType_SerializationShift) & 0x3); 45} 46 47static SerializationType extract_serializationtype(uint32_t packed) { 48 return static_cast<SerializationType>((packed >> kType_SerializationShift) & 0xF); 49} 50 51/////////////////////////////////////////////////////////////////////////////////////////////////// 52 53size_t SkPath::writeToMemoryAsRRect(void* storage) const { 54 SkRect oval; 55 SkRRect rrect; 56 bool isCCW; 57 unsigned start; 58 if (fPathRef->isOval(&oval, &isCCW, &start)) { 59 rrect.setOval(oval); 60 // Convert to rrect start indices. 61 start *= 2; 62 } else if (!fPathRef->isRRect(&rrect, &isCCW, &start)) { 63 return 0; 64 } 65 66 // packed header, rrect, start index. 67 const size_t sizeNeeded = sizeof(int32_t) + SkRRect::kSizeInMemory + sizeof(int32_t); 68 if (!storage) { 69 return sizeNeeded; 70 } 71 72 int firstDir = isCCW ? SkPathPriv::kCCW_FirstDirection : SkPathPriv::kCW_FirstDirection; 73 int32_t packed = (fFillType << kFillType_SerializationShift) | 74 (firstDir << kDirection_SerializationShift) | 75 (SerializationType::kRRect << kType_SerializationShift) | 76 kCurrent_Version; 77 78 SkWBuffer buffer(storage); 79 buffer.write32(packed); 80 rrect.writeToBuffer(&buffer); 81 buffer.write32(SkToS32(start)); 82 buffer.padToAlign4(); 83 SkASSERT(sizeNeeded == buffer.pos()); 84 return buffer.pos(); 85} 86 87size_t SkPath::writeToMemory(void* storage) const { 88 SkDEBUGCODE(this->validate();) 89 90 if (size_t bytes = this->writeToMemoryAsRRect(storage)) { 91 return bytes; 92 } 93 94 int32_t packed = (fFillType << kFillType_SerializationShift) | 95 (SerializationType::kGeneral << kType_SerializationShift) | 96 kCurrent_Version; 97 98 int32_t pts = fPathRef->countPoints(); 99 int32_t cnx = fPathRef->countWeights(); 100 int32_t vbs = fPathRef->countVerbs(); 101 102 SkSafeMath safe; 103 size_t size = 4 * sizeof(int32_t); 104 size = safe.add(size, safe.mul(pts, sizeof(SkPoint))); 105 size = safe.add(size, safe.mul(cnx, sizeof(SkScalar))); 106 size = safe.add(size, safe.mul(vbs, sizeof(uint8_t))); 107 size = safe.alignUp(size, 4); 108 if (!safe) { 109 return 0; 110 } 111 if (!storage) { 112 return size; 113 } 114 115 SkWBuffer buffer(storage); 116 buffer.write32(packed); 117 buffer.write32(pts); 118 buffer.write32(cnx); 119 buffer.write32(vbs); 120 buffer.write(fPathRef->points(), pts * sizeof(SkPoint)); 121 buffer.write(fPathRef->conicWeights(), cnx * sizeof(SkScalar)); 122 buffer.write(fPathRef->verbsMemBegin(), vbs * sizeof(uint8_t)); 123 buffer.padToAlign4(); 124 125 SkASSERT(buffer.pos() == size); 126 return size; 127} 128 129sk_sp<SkData> SkPath::serialize() const { 130 size_t size = this->writeToMemory(nullptr); 131 sk_sp<SkData> data = SkData::MakeUninitialized(size); 132 this->writeToMemory(data->writable_data()); 133 return data; 134} 135 136////////////////////////////////////////////////////////////////////////////////////////////////// 137// reading 138 139size_t SkPath::readFromMemory(const void* storage, size_t length) { 140 SkRBuffer buffer(storage, length); 141 uint32_t packed; 142 if (!buffer.readU32(&packed)) { 143 return 0; 144 } 145 unsigned version = extract_version(packed); 146 if (version <= kPathPrivTypeEnumVersion) { 147 return this->readFromMemory_LE3(storage, length); 148 } 149 if (version == kJustPublicData_Version) { 150 return this->readFromMemory_EQ4(storage, length); 151 } 152 return 0; 153} 154 155size_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 FillType fillType = extract_filltype(packed); 166 167 Direction rrectDir; 168 SkRRect rrect; 169 int32_t start; 170 switch (dir) { 171 case SkPathPriv::kCW_FirstDirection: 172 rrectDir = kCW_Direction; 173 break; 174 case SkPathPriv::kCCW_FirstDirection: 175 rrectDir = kCCW_Direction; 176 break; 177 default: 178 return 0; 179 } 180 if (!rrect.readFromBuffer(&buffer)) { 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 193size_t SkPath::readFromMemory_EQ4(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 200 SkASSERT(extract_version(packed) == 4); 201 202 switch (extract_serializationtype(packed)) { 203 case SerializationType::kRRect: 204 return this->readAsRRect(storage, length); 205 case SerializationType::kGeneral: 206 break; // fall through 207 default: 208 return 0; 209 } 210 211 int32_t pts, cnx, vbs; 212 if (!buffer.readS32(&pts) || !buffer.readS32(&cnx) || !buffer.readS32(&vbs)) { 213 return 0; 214 } 215 216 const SkPoint* points = buffer.skipCount<SkPoint>(pts); 217 const SkScalar* conics = buffer.skipCount<SkScalar>(cnx); 218 const uint8_t* verbs = buffer.skipCount<uint8_t>(vbs); 219 buffer.skipToAlign4(); 220 if (!buffer.isValid()) { 221 return 0; 222 } 223 SkASSERT(buffer.pos() <= length); 224 225#define CHECK_POINTS_CONICS(p, c) \ 226 do { \ 227 if (p && ((pts -= p) < 0)) { \ 228 return 0; \ 229 } \ 230 if (c && ((cnx -= c) < 0)) { \ 231 return 0; \ 232 } \ 233 } while (0) 234 235 SkPath tmp; 236 tmp.setFillType(extract_filltype(packed)); 237 tmp.incReserve(pts); 238 for (int i = vbs - 1; i >= 0; --i) { 239 switch (verbs[i]) { 240 case kMove_Verb: 241 CHECK_POINTS_CONICS(1, 0); 242 tmp.moveTo(*points++); 243 break; 244 case kLine_Verb: 245 CHECK_POINTS_CONICS(1, 0); 246 tmp.lineTo(*points++); 247 break; 248 case kQuad_Verb: 249 CHECK_POINTS_CONICS(2, 0); 250 tmp.quadTo(points[0], points[1]); 251 points += 2; 252 break; 253 case kConic_Verb: 254 CHECK_POINTS_CONICS(2, 1); 255 tmp.conicTo(points[0], points[1], *conics++); 256 points += 2; 257 break; 258 case kCubic_Verb: 259 CHECK_POINTS_CONICS(3, 0); 260 tmp.cubicTo(points[0], points[1], points[2]); 261 points += 3; 262 break; 263 case kClose_Verb: 264 tmp.close(); 265 break; 266 default: 267 return 0; // bad verb 268 } 269 } 270#undef CHECK_POINTS_CONICS 271 if (pts || cnx) { 272 return 0; // leftover points and/or conics 273 } 274 275 *this = std::move(tmp); 276 return buffer.pos(); 277} 278 279size_t SkPath::readFromMemory_LE3(const void* storage, size_t length) { 280 SkRBuffer buffer(storage, length); 281 282 int32_t packed; 283 if (!buffer.readS32(&packed)) { 284 return 0; 285 } 286 287 unsigned version = extract_version(packed); 288 SkASSERT(version <= 3); 289 290 FillType fillType = extract_filltype(packed); 291 if (version >= kPathPrivTypeEnumVersion) { 292 switch (extract_serializationtype(packed)) { 293 case SerializationType::kRRect: 294 return this->readAsRRect(storage, length); 295 case SerializationType::kGeneral: 296 // Fall through to general path deserialization 297 break; 298 default: 299 return 0; 300 } 301 } 302 if (version >= kPathPrivLastMoveToIndex_Version && !buffer.readS32(&fLastMoveToIndex)) { 303 return 0; 304 } 305 306 // These are written into the serialized data but we no longer use them in the deserialized 307 // path. If convexity is corrupted it may cause the GPU backend to make incorrect 308 // rendering choices, possibly crashing. We set them to unknown so that they'll be recomputed if 309 // requested. 310 fConvexity = kUnknown_Convexity; 311 fFirstDirection = SkPathPriv::kUnknown_FirstDirection; 312 313 fFillType = fillType; 314 fIsVolatile = 0; 315 SkPathRef* pathRef = SkPathRef::CreateFromBuffer(&buffer); 316 if (!pathRef) { 317 return 0; 318 } 319 320 fPathRef.reset(pathRef); 321 SkDEBUGCODE(this->validate();) 322 buffer.skipToAlign4(); 323 return buffer.pos(); 324} 325 326