Home | History | Annotate | Download | only in core
      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 
     17 enum 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 
     25 enum 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 
     34 enum SerializationType {
     35     kGeneral = 0,
     36     kRRect = 1
     37 };
     38 
     39 static unsigned extract_version(uint32_t packed) {
     40     return packed & kVersion_SerializationMask;
     41 }
     42 
     43 static SkPath::FillType extract_filltype(uint32_t packed) {
     44     return static_cast<SkPath::FillType>((packed >> kFillType_SerializationShift) & 0x3);
     45 }
     46 
     47 static SerializationType extract_serializationtype(uint32_t packed) {
     48     return static_cast<SerializationType>((packed >> kType_SerializationShift) & 0xF);
     49 }
     50 
     51 ///////////////////////////////////////////////////////////////////////////////////////////////////
     52 
     53 size_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 
     87 size_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 
    129 sk_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 
    139 size_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 
    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     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 
    193 size_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 
    279 size_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