Coverage Report

Created: 2021-08-22 09:07

/src/skia/src/core/SkGlyph.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 "src/core/SkGlyph.h"
9
10
#include "src/core/SkArenaAlloc.h"
11
#include "src/core/SkScalerContext.h"
12
#include "src/pathops/SkPathOpsCubic.h"
13
#include "src/pathops/SkPathOpsQuad.h"
14
15
constexpr SkIPoint SkPackedGlyphID::kXYFieldMask;
16
17
59.9k
SkMask SkGlyph::mask() const {
18
59.9k
    SkMask mask;
19
59.9k
    mask.fImage = (uint8_t*)fImage;
20
59.9k
    mask.fBounds.setXYWH(fLeft, fTop, fWidth, fHeight);
21
59.9k
    mask.fRowBytes = this->rowBytes();
22
59.9k
    mask.fFormat = fMaskFormat;
23
59.9k
    return mask;
24
59.9k
}
25
26
32.1k
SkMask SkGlyph::mask(SkPoint position) const {
27
32.1k
    SkMask answer = this->mask();
28
32.1k
    answer.fBounds.offset(SkScalarFloorToInt(position.x()), SkScalarFloorToInt(position.y()));
29
32.1k
    return answer;
30
32.1k
}
31
32
2.38k
void SkGlyph::zeroMetrics() {
33
2.38k
    fAdvanceX = 0;
34
2.38k
    fAdvanceY = 0;
35
2.38k
    fWidth    = 0;
36
2.38k
    fHeight   = 0;
37
2.38k
    fTop      = 0;
38
2.38k
    fLeft     = 0;
39
2.38k
}
40
41
28.7k
static size_t bits_to_bytes(size_t bits) {
42
28.7k
    return (bits + 7) >> 3;
43
28.7k
}
44
45
102k
static size_t format_alignment(SkMask::Format format) {
46
102k
    switch (format) {
47
5.30k
        case SkMask::kBW_Format:
48
102k
        case SkMask::kA8_Format:
49
102k
        case SkMask::k3D_Format:
50
102k
        case SkMask::kSDF_Format:
51
102k
            return alignof(uint8_t);
52
147
        case SkMask::kARGB32_Format:
53
147
            return alignof(uint32_t);
54
0
        case SkMask::kLCD16_Format:
55
0
            return alignof(uint16_t);
56
0
        default:
57
0
            SK_ABORT("Unknown mask format.");
58
0
            break;
59
0
    }
60
0
    return 0;
61
0
}
62
63
108k
static size_t format_rowbytes(int width, SkMask::Format format) {
64
28.7k
    return format == SkMask::kBW_Format ? bits_to_bytes(width)
65
79.6k
                                        : width * format_alignment(format);
66
108k
}
67
68
23.1k
size_t SkGlyph::formatAlignment() const {
69
23.1k
    return format_alignment(this->maskFormat());
70
23.1k
}
71
72
23.1k
size_t SkGlyph::allocImage(SkArenaAlloc* alloc) {
73
23.1k
    SkASSERT(!this->isEmpty());
74
23.1k
    auto size = this->imageSize();
75
23.1k
    fImage = alloc->makeBytesAlignedTo(size, this->formatAlignment());
76
77
23.1k
    return size;
78
23.1k
}
79
80
41.7k
bool SkGlyph::setImage(SkArenaAlloc* alloc, SkScalerContext* scalerContext) {
81
41.7k
    if (!this->setImageHasBeenCalled()) {
82
        // It used to be that getImage() could change the fMaskFormat. Extra checking to make
83
        // sure there are no regressions.
84
23.1k
        SkDEBUGCODE(SkMask::Format oldFormat = this->maskFormat());
85
23.1k
        this->allocImage(alloc);
86
23.1k
        scalerContext->getImage(*this);
87
23.1k
        SkASSERT(oldFormat == this->maskFormat());
88
23.1k
        return true;
89
23.1k
    }
90
18.5k
    return false;
91
18.5k
}
92
93
0
bool SkGlyph::setImage(SkArenaAlloc* alloc, const void* image) {
94
0
    if (!this->setImageHasBeenCalled()) {
95
0
        this->allocImage(alloc);
96
0
        memcpy(fImage, image, this->imageSize());
97
0
        return true;
98
0
    }
99
0
    return false;
100
0
}
101
102
0
size_t SkGlyph::setMetricsAndImage(SkArenaAlloc* alloc, const SkGlyph& from) {
103
    // Since the code no longer tries to find replacement glyphs, the image should always be
104
    // nullptr.
105
0
    SkASSERT(fImage == nullptr);
106
107
    // TODO(herb): remove "if" when we are sure there are no colliding glyphs.
108
0
    if (fImage == nullptr) {
109
0
        fAdvanceX = from.fAdvanceX;
110
0
        fAdvanceY = from.fAdvanceY;
111
0
        fWidth = from.fWidth;
112
0
        fHeight = from.fHeight;
113
0
        fTop = from.fTop;
114
0
        fLeft = from.fLeft;
115
0
        fForceBW = from.fForceBW;
116
0
        fMaskFormat = from.fMaskFormat;
117
118
        // From glyph may not have an image because the glyph is too large.
119
0
        if (from.fImage != nullptr && this->setImage(alloc, from.image())) {
120
0
            return this->imageSize();
121
0
        }
122
0
    }
123
0
    return 0;
124
0
}
Unexecuted instantiation: SkGlyph::setMetricsAndImage(SkArenaAlloc*, SkGlyph const&)
Unexecuted instantiation: SkGlyph::setMetricsAndImage(SkArenaAlloc*, SkGlyph const&)
125
126
108k
size_t SkGlyph::rowBytes() const {
127
108k
    return format_rowbytes(fWidth, fMaskFormat);
128
108k
}
129
130
0
size_t SkGlyph::rowBytesUsingFormat(SkMask::Format format) const {
131
0
    return format_rowbytes(fWidth, format);
132
0
}
133
134
47.6k
size_t SkGlyph::imageSize() const {
135
47.6k
    if (this->isEmpty() || this->imageTooLarge()) { return 0; }
136
137
47.6k
    size_t size = this->rowBytes() * fHeight;
138
139
47.6k
    if (fMaskFormat == SkMask::k3D_Format) {
140
0
        size *= 3;
141
0
    }
142
143
47.6k
    return size;
144
47.6k
}
145
146
22.1k
void SkGlyph::installPath(SkArenaAlloc* alloc, const SkPath* path) {
147
22.1k
    SkASSERT(fPathData == nullptr);
148
22.1k
    SkASSERT(!this->setPathHasBeenCalled());
149
22.1k
    fPathData = alloc->make<SkGlyph::PathData>();
150
22.1k
    if (path != nullptr) {
151
22.1k
        fPathData->fPath = *path;
152
22.1k
        fPathData->fPath.updateBoundsCache();
153
22.1k
        fPathData->fPath.getGenerationID();
154
22.1k
        fPathData->fHasPath = true;
155
22.1k
    }
156
22.1k
}
157
158
406k
bool SkGlyph::setPath(SkArenaAlloc* alloc, SkScalerContext* scalerContext) {
159
406k
    if (!this->setPathHasBeenCalled()) {
160
22.1k
        SkPath path;
161
22.1k
        if (scalerContext->getPath(this->getPackedID(), &path)) {
162
22.1k
            this->installPath(alloc, &path);
163
24
        } else {
164
24
            this->installPath(alloc, nullptr);
165
24
        }
166
22.1k
        return this->path() != nullptr;
167
22.1k
    }
168
169
384k
    return false;
170
384k
}
171
172
0
bool SkGlyph::setPath(SkArenaAlloc* alloc, const SkPath* path) {
173
0
    if (!this->setPathHasBeenCalled()) {
174
0
        this->installPath(alloc, path);
175
0
        return this->path() != nullptr;
176
0
    }
177
0
    return false;
178
0
}
179
180
748k
const SkPath* SkGlyph::path() const {
181
    // setPath must have been called previously.
182
748k
    SkASSERT(this->setPathHasBeenCalled());
183
748k
    if (fPathData->fHasPath) {
184
175k
        return &fPathData->fPath;
185
175k
    }
186
573k
    return nullptr;
187
573k
}
188
189
static std::tuple<SkScalar, SkScalar> calculate_path_gap(
190
0
        SkScalar topOffset, SkScalar bottomOffset, const SkPath& path) {
191
192
    // Left and Right of an ever expanding gap around the path.
193
0
    SkScalar left  = SK_ScalarMax,
194
0
             right = SK_ScalarMin;
195
0
    auto expandGap = [&left, &right](SkScalar v) {
196
0
        left  = std::min(left, v);
197
0
        right = std::max(right, v);
198
0
    };
Unexecuted instantiation: SkGlyph.cpp:calculate_path_gap(float, float, SkPath const&)::$_2::operator()(float) const
Unexecuted instantiation: SkGlyph.cpp:calculate_path_gap(float, float, SkPath const&)::$_8::operator()(float) const
199
200
    // Handle all the different verbs for the path.
201
0
    SkPoint pts[4];
202
0
    auto addLine = [&expandGap, &pts](SkScalar offset) {
203
0
        SkScalar t = sk_ieee_float_divide(offset - pts[0].fY, pts[1].fY - pts[0].fY);
204
0
        if (0 <= t && t < 1) {   // this handles divide by zero above
205
0
            expandGap(pts[0].fX + t * (pts[1].fX - pts[0].fX));
206
0
        }
207
0
    };
Unexecuted instantiation: SkGlyph.cpp:calculate_path_gap(float, float, SkPath const&)::$_3::operator()(float) const
Unexecuted instantiation: SkGlyph.cpp:calculate_path_gap(float, float, SkPath const&)::$_9::operator()(float) const
208
209
0
    auto addQuad = [&expandGap, &pts](SkScalar offset) {
210
0
        SkDQuad quad;
211
0
        quad.set(pts);
212
0
        double roots[2];
213
0
        int count = quad.horizontalIntersect(offset, roots);
214
0
        while (--count >= 0) {
215
0
            expandGap(quad.ptAtT(roots[count]).asSkPoint().fX);
216
0
        }
217
0
    };
Unexecuted instantiation: SkGlyph.cpp:calculate_path_gap(float, float, SkPath const&)::$_4::operator()(float) const
Unexecuted instantiation: SkGlyph.cpp:calculate_path_gap(float, float, SkPath const&)::$_10::operator()(float) const
218
219
0
    auto addCubic = [&expandGap, &pts](SkScalar offset) {
220
0
        SkDCubic cubic;
221
0
        cubic.set(pts);
222
0
        double roots[3];
223
0
        int count = cubic.horizontalIntersect(offset, roots);
224
0
        while (--count >= 0) {
225
0
            expandGap(cubic.ptAtT(roots[count]).asSkPoint().fX);
226
0
        }
227
0
    };
Unexecuted instantiation: SkGlyph.cpp:calculate_path_gap(float, float, SkPath const&)::$_5::operator()(float) const
Unexecuted instantiation: SkGlyph.cpp:calculate_path_gap(float, float, SkPath const&)::$_11::operator()(float) const
228
229
    // Handle when a verb's points are in the gap between top and bottom.
230
0
    auto addPts = [&expandGap, &pts, topOffset, bottomOffset](int ptCount) {
231
0
        for (int i = 0; i < ptCount; ++i) {
232
0
            if (topOffset < pts[i].fY && pts[i].fY < bottomOffset) {
233
0
                expandGap(pts[i].fX);
234
0
            }
235
0
        }
236
0
    };
Unexecuted instantiation: SkGlyph.cpp:calculate_path_gap(float, float, SkPath const&)::$_6::operator()(int) const
Unexecuted instantiation: SkGlyph.cpp:calculate_path_gap(float, float, SkPath const&)::$_12::operator()(int) const
237
238
0
    SkPath::Iter iter(path, false);
239
0
    SkPath::Verb verb;
240
0
    while (SkPath::kDone_Verb != (verb = iter.next(pts))) {
241
0
        switch (verb) {
242
0
            case SkPath::kMove_Verb: {
243
0
                break;
244
0
            }
245
0
            case SkPath::kLine_Verb: {
246
0
                addLine(topOffset);
247
0
                addLine(bottomOffset);
248
0
                addPts(2);
249
0
                break;
250
0
            }
251
0
            case SkPath::kQuad_Verb: {
252
0
                SkScalar quadTop = std::min(std::min(pts[0].fY, pts[1].fY), pts[2].fY);
253
0
                if (bottomOffset < quadTop) { break; }
254
0
                SkScalar quadBottom = std::max(std::max(pts[0].fY, pts[1].fY), pts[2].fY);
255
0
                if (topOffset > quadBottom) { break; }
256
0
                addQuad(topOffset);
257
0
                addQuad(bottomOffset);
258
0
                addPts(3);
259
0
                break;
260
0
            }
261
0
            case SkPath::kConic_Verb: {
262
0
                SkASSERT(0);  // no support for text composed of conics
263
0
                break;
264
0
            }
265
0
            case SkPath::kCubic_Verb: {
266
0
                SkScalar quadTop =
267
0
                        std::min(std::min(std::min(pts[0].fY, pts[1].fY), pts[2].fY), pts[3].fY);
268
0
                if (bottomOffset < quadTop) { break; }
269
0
                SkScalar quadBottom =
270
0
                        std::max(std::max(std::max(pts[0].fY, pts[1].fY), pts[2].fY), pts[3].fY);
271
0
                if (topOffset > quadBottom) { break; }
272
0
                addCubic(topOffset);
273
0
                addCubic(bottomOffset);
274
0
                addPts(4);
275
0
                break;
276
0
            }
277
0
            case SkPath::kClose_Verb: {
278
0
                break;
279
0
            }
280
0
            default: {
281
0
                SkASSERT(0);
282
0
                break;
283
0
            }
284
0
        }
285
0
    }
286
287
0
    return std::tie(left, right);
288
0
}
Unexecuted instantiation: SkGlyph.cpp:calculate_path_gap(float, float, SkPath const&)
Unexecuted instantiation: SkGlyph.cpp:calculate_path_gap(float, float, SkPath const&)
289
290
void SkGlyph::ensureIntercepts(const SkScalar* bounds, SkScalar scale, SkScalar xPos,
291
0
                               SkScalar* array, int* count, SkArenaAlloc* alloc) {
292
293
0
    auto offsetResults = [scale, xPos](
294
0
            const SkGlyph::Intercept* intercept,SkScalar* array, int* count) {
295
0
        if (array) {
296
0
            array += *count;
297
0
            for (int index = 0; index < 2; index++) {
298
0
                *array++ = intercept->fInterval[index] * scale + xPos;
299
0
            }
300
0
        }
301
0
        *count += 2;
302
0
    };
Unexecuted instantiation: SkGlyph.cpp:SkGlyph::ensureIntercepts(float const*, float, float, float*, int*, SkArenaAlloc*)::$_0::operator()(SkGlyph::Intercept const*, float*, int*) const
Unexecuted instantiation: SkGlyph.cpp:SkGlyph::ensureIntercepts(float const*, float, float, float*, int*, SkArenaAlloc*)::$_6::operator()(SkGlyph::Intercept const*, float*, int*) const
303
304
0
    const SkGlyph::Intercept* match =
305
0
            [this](const SkScalar bounds[2]) -> const SkGlyph::Intercept* {
306
0
                if (!fPathData) {
307
0
                    return nullptr;
308
0
                }
309
0
                const SkGlyph::Intercept* intercept = fPathData->fIntercept;
310
0
                while (intercept) {
311
0
                    if (bounds[0] == intercept->fBounds[0] && bounds[1] == intercept->fBounds[1]) {
312
0
                        return intercept;
313
0
                    }
314
0
                    intercept = intercept->fNext;
315
0
                }
316
0
                return nullptr;
317
0
            }(bounds);
Unexecuted instantiation: SkGlyph.cpp:SkGlyph::ensureIntercepts(float const*, float, float, float*, int*, SkArenaAlloc*)::$_1::operator()(float const*) const
Unexecuted instantiation: SkGlyph.cpp:SkGlyph::ensureIntercepts(float const*, float, float, float*, int*, SkArenaAlloc*)::$_7::operator()(float const*) const
318
319
0
    if (match) {
320
0
        if (match->fInterval[0] < match->fInterval[1]) {
321
0
            offsetResults(match, array, count);
322
0
        }
323
0
        return;
324
0
    }
325
326
0
    SkGlyph::Intercept* intercept = alloc->make<SkGlyph::Intercept>();
327
0
    intercept->fNext = fPathData->fIntercept;
328
0
    intercept->fBounds[0] = bounds[0];
329
0
    intercept->fBounds[1] = bounds[1];
330
0
    intercept->fInterval[0] = SK_ScalarMax;
331
0
    intercept->fInterval[1] = SK_ScalarMin;
332
0
    fPathData->fIntercept = intercept;
333
0
    const SkPath* path = &(fPathData->fPath);
334
0
    const SkRect& pathBounds = path->getBounds();
335
0
    if (pathBounds.fBottom < bounds[0] || bounds[1] < pathBounds.fTop) {
336
0
        return;
337
0
    }
338
339
0
    std::tie(intercept->fInterval[0], intercept->fInterval[1])
340
0
            = calculate_path_gap(bounds[0], bounds[1], *path);
341
342
0
    if (intercept->fInterval[0] >= intercept->fInterval[1]) {
343
0
        intercept->fInterval[0] = SK_ScalarMax;
344
0
        intercept->fInterval[1] = SK_ScalarMin;
345
0
        return;
346
0
    }
347
0
    offsetResults(intercept, array, count);
348
0
}