Coverage Report

Created: 2021-08-22 09:07

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