Coverage Report

Created: 2021-08-22 09:07

/src/skia/src/core/SkStrikeSpec.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 2019 The Android Open Source Project
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/SkStrikeSpec.h"
9
10
#include "include/core/SkGraphics.h"
11
#include "src/core/SkDraw.h"
12
#include "src/core/SkFontPriv.h"
13
#include "src/core/SkStrikeCache.h"
14
#include "src/core/SkTLazy.h"
15
16
#if SK_SUPPORT_GPU
17
#include "src/gpu/text/GrSDFMaskFilter.h"
18
#include "src/gpu/text/GrSDFTControl.h"
19
#include "src/gpu/text/GrStrikeCache.h"
20
#endif
21
22
SkStrikeSpec SkStrikeSpec::MakeMask(const SkFont& font, const SkPaint& paint,
23
                                    const SkSurfaceProps& surfaceProps,
24
                                    SkScalerContextFlags scalerContextFlags,
25
157k
                                    const SkMatrix& deviceMatrix) {
26
27
157k
    return SkStrikeSpec(font, paint, surfaceProps, scalerContextFlags, deviceMatrix, 1);
28
157k
}
29
30
SkStrikeSpec SkStrikeSpec::MakePath(const SkFont& font, const SkPaint& paint,
31
                                    const SkSurfaceProps& surfaceProps,
32
56.7k
                                    SkScalerContextFlags scalerContextFlags) {
33
34
    // setup our std runPaint, in hopes of getting hits in the cache
35
56.7k
    SkPaint pathPaint{paint};
36
56.7k
    SkFont pathFont{font};
37
38
    // The factor to get from the size stored in the strike to the size needed for
39
    // the source.
40
56.7k
    SkScalar strikeToSourceRatio = pathFont.setupForAsPaths(&pathPaint);
41
42
    // The sub-pixel position will always happen when transforming to the screen.
43
56.7k
    pathFont.setSubpixel(false);
44
45
56.7k
    return SkStrikeSpec(pathFont, pathPaint, surfaceProps, scalerContextFlags,
46
56.7k
                        SkMatrix::I(), strikeToSourceRatio);
47
56.7k
}
48
49
SkStrikeSpec SkStrikeSpec::MakeSourceFallback(
50
        const SkFont& font,
51
        const SkPaint& paint,
52
        const SkSurfaceProps& surfaceProps,
53
        SkScalerContextFlags scalerContextFlags,
54
2
        SkScalar maxSourceGlyphDimension) {
55
56
    // Subtract 2 to account for the bilerp pad around the glyph
57
2
    SkScalar maxAtlasDimension = SkStrikeCommon::kSkSideTooBigForAtlas - 2;
58
59
2
    SkScalar runFontTextSize = font.getSize();
60
2
    SkScalar fallbackTextSize = runFontTextSize;
61
2
    if (maxSourceGlyphDimension > maxAtlasDimension) {
62
        // Scale the text size down so the long side of all the glyphs will fit in the atlas.
63
2
        fallbackTextSize = SkScalarFloorToScalar(
64
2
                (maxAtlasDimension / maxSourceGlyphDimension) * runFontTextSize);
65
2
    }
66
67
2
    SkFont fallbackFont{font};
68
2
    fallbackFont.setSize(fallbackTextSize);
69
70
    // No sub-pixel needed. The transform to the screen will take care of sub-pixel positioning.
71
2
    fallbackFont.setSubpixel(false);
72
73
    // The scale factor to go from strike size to the source size for glyphs.
74
2
    SkScalar strikeToSourceRatio = runFontTextSize / fallbackTextSize;
75
76
2
    return SkStrikeSpec(fallbackFont, paint, surfaceProps, scalerContextFlags,
77
2
                        SkMatrix::I(), strikeToSourceRatio);
78
2
}
79
80
9.58M
SkStrikeSpec SkStrikeSpec::MakeCanonicalized(const SkFont& font, const SkPaint* paint) {
81
9.58M
    SkPaint canonicalizedPaint;
82
9.58M
    if (paint != nullptr) {
83
8.55M
        canonicalizedPaint = *paint;
84
8.55M
    }
85
86
9.58M
    const SkFont* canonicalizedFont = &font;
87
9.58M
    SkTLazy<SkFont> pathFont;
88
9.58M
    SkScalar strikeToSourceRatio = 1;
89
9.58M
    if (ShouldDrawAsPath(canonicalizedPaint, font, SkMatrix::I())) {
90
1.19M
        canonicalizedFont = pathFont.set(font);
91
1.19M
        strikeToSourceRatio = pathFont->setupForAsPaths(nullptr);
92
1.19M
        canonicalizedPaint.reset();
93
1.19M
    }
94
95
9.58M
    return SkStrikeSpec(*canonicalizedFont, canonicalizedPaint,
96
9.58M
                        SkSurfaceProps(), kFakeGammaAndBoostContrast,
97
9.58M
                        SkMatrix::I(), strikeToSourceRatio);
98
9.58M
}
99
100
104k
SkStrikeSpec SkStrikeSpec::MakeWithNoDevice(const SkFont& font, const SkPaint* paint) {
101
104k
    SkPaint setupPaint;
102
104k
    if (paint != nullptr) {
103
0
        setupPaint = *paint;
104
0
    }
105
106
104k
    return SkStrikeSpec(font, setupPaint, SkSurfaceProps(), kFakeGammaAndBoostContrast,
107
104k
                        SkMatrix::I(), 1);
108
104k
}
109
110
0
SkStrikeSpec SkStrikeSpec::MakeDefault() {
111
0
    SkFont defaultFont;
112
0
    return MakeCanonicalized(defaultFont);
113
0
}
114
115
bool SkStrikeSpec::ShouldDrawAsPath(
116
9.79M
        const SkPaint& paint, const SkFont& font, const SkMatrix& viewMatrix) {
117
118
    // hairline glyphs are fast enough so we don't need to cache them
119
9.79M
    if (SkPaint::kStroke_Style == paint.getStyle() && 0 == paint.getStrokeWidth()) {
120
1.06k
        return true;
121
1.06k
    }
122
123
    // we don't cache perspective
124
9.79M
    if (viewMatrix.hasPerspective()) {
125
59
        return true;
126
59
    }
127
128
9.79M
    SkMatrix textMatrix = SkFontPriv::MakeTextMatrix(font);
129
9.79M
    textMatrix.postConcat(viewMatrix);
130
131
    // we have a self-imposed maximum, just to limit memory-usage
132
9.79M
    constexpr SkScalar memoryLimit = 256;
133
9.79M
    constexpr SkScalar maxSizeSquared = memoryLimit * memoryLimit;
134
135
18.3M
    auto distance = [&textMatrix](int XIndex, int YIndex) {
136
18.3M
        return textMatrix[XIndex] * textMatrix[XIndex] + textMatrix[YIndex] * textMatrix[YIndex];
137
18.3M
    };
138
139
9.79M
    return distance(SkMatrix::kMScaleX, SkMatrix::kMSkewY ) > maxSizeSquared
140
8.55M
        || distance(SkMatrix::kMSkewX,  SkMatrix::kMScaleY) > maxSizeSquared;
141
9.79M
}
142
143
0
SkString SkStrikeSpec::dump() const {
144
0
    return fAutoDescriptor.getDesc()->dumpRec();
145
0
}
146
147
0
SkStrikeSpec SkStrikeSpec::MakePDFVector(const SkTypeface& typeface, int* size) {
148
0
    SkFont font;
149
0
    font.setHinting(SkFontHinting::kNone);
150
0
    font.setEdging(SkFont::Edging::kAlias);
151
0
    font.setTypeface(sk_ref_sp(&typeface));
152
0
    int unitsPerEm = typeface.getUnitsPerEm();
153
0
    if (unitsPerEm <= 0) {
154
0
        unitsPerEm = 1024;
155
0
    }
156
0
    if (size) {
157
0
        *size = unitsPerEm;
158
0
    }
159
0
    font.setSize((SkScalar)unitsPerEm);
160
161
0
    return SkStrikeSpec(font, SkPaint(),
162
0
                        SkSurfaceProps(0, kUnknown_SkPixelGeometry), kFakeGammaAndBoostContrast,
163
0
                        SkMatrix::I(), 1);
164
0
}
165
166
#if SK_SUPPORT_GPU
167
std::tuple<SkStrikeSpec, SkScalar, SkScalar>
168
SkStrikeSpec::MakeSDFT(const SkFont& font, const SkPaint& paint,
169
                       const SkSurfaceProps& surfaceProps, const SkMatrix& deviceMatrix,
170
132
                       const GrSDFTControl& control) {
171
132
    SkPaint dfPaint{paint};
172
132
    dfPaint.setMaskFilter(GrSDFMaskFilter::Make());
173
132
    SkScalar strikeToSourceRatio;
174
132
    SkFont dfFont = control.getSDFFont(font, deviceMatrix, &strikeToSourceRatio);
175
176
    // Fake-gamma and subpixel antialiasing are applied in the shader, so we ignore the
177
    // passed-in scaler context flags. (It's only used when we fall-back to bitmap text).
178
132
    SkScalerContextFlags flags = SkScalerContextFlags::kNone;
179
180
132
    SkScalar minScale, maxScale;
181
132
    std::tie(minScale, maxScale) = control.computeSDFMinMaxScale(font.getSize(), deviceMatrix);
182
183
132
    SkStrikeSpec strikeSpec(dfFont, dfPaint, surfaceProps, flags,
184
132
                            SkMatrix::I(), strikeToSourceRatio);
185
186
132
    return std::make_tuple(std::move(strikeSpec), minScale, maxScale);
187
132
}
188
189
508
sk_sp<GrTextStrike> SkStrikeSpec::findOrCreateGrStrike(GrStrikeCache* cache) const {
190
508
    return cache->findOrCreateStrike(*fAutoDescriptor.getDesc());
191
508
}
192
#endif
193
194
SkStrikeSpec::SkStrikeSpec(const SkFont& font, const SkPaint& paint,
195
                           const SkSurfaceProps& surfaceProps,
196
                           SkScalerContextFlags scalerContextFlags,
197
                           const SkMatrix& deviceMatrix,
198
                           SkScalar strikeToSourceRatio)
199
    : fStrikeToSourceRatio(strikeToSourceRatio)
200
9.90M
{
201
9.90M
    SkScalerContextEffects effects;
202
203
9.90M
    SkScalerContext::CreateDescriptorAndEffectsUsingPaint(
204
9.90M
            font, paint, surfaceProps, scalerContextFlags, deviceMatrix,
205
9.90M
            &fAutoDescriptor, &effects);
206
207
9.90M
    fMaskFilter = sk_ref_sp(effects.fMaskFilter);
208
9.90M
    fPathEffect = sk_ref_sp(effects.fPathEffect);
209
9.90M
    fTypeface = font.refTypefaceOrDefault();
210
9.90M
}
211
212
5.31k
SkScopedStrikeForGPU SkStrikeSpec::findOrCreateScopedStrike(SkStrikeForGPUCacheInterface* cache) const {
213
5.31k
    SkScalerContextEffects effects{fPathEffect.get(), fMaskFilter.get()};
214
5.31k
    return cache->findOrCreateScopedStrike(*fAutoDescriptor.getDesc(), effects, *fTypeface);
215
5.31k
}
216
217
9.89M
sk_sp<SkStrike> SkStrikeSpec::findOrCreateStrike(SkStrikeCache* cache) const {
218
9.89M
    SkScalerContextEffects effects{fPathEffect.get(), fMaskFilter.get()};
219
9.89M
    return cache->findOrCreateStrike(*fAutoDescriptor.getDesc(), effects, *fTypeface);
220
9.89M
}
221
222
SkBulkGlyphMetrics::SkBulkGlyphMetrics(const SkStrikeSpec& spec)
223
9.62M
    : fStrike{spec.findOrCreateStrike()} { }
224
225
9.62M
SkSpan<const SkGlyph*> SkBulkGlyphMetrics::glyphs(SkSpan<const SkGlyphID> glyphIDs) {
226
9.62M
    fGlyphs.reset(glyphIDs.size());
227
9.62M
    return fStrike->metrics(glyphIDs, fGlyphs.get());
228
9.62M
}
229
230
0
const SkGlyph* SkBulkGlyphMetrics::glyph(SkGlyphID glyphID) {
231
0
    return this->glyphs(SkSpan<const SkGlyphID>{&glyphID, 1})[0];
232
0
}
233
234
SkBulkGlyphMetricsAndPaths::SkBulkGlyphMetricsAndPaths(const SkStrikeSpec& spec)
235
53.6k
    : fStrike{spec.findOrCreateStrike()} { }
236
237
SkBulkGlyphMetricsAndPaths::SkBulkGlyphMetricsAndPaths(sk_sp<SkStrike>&& strike)
238
0
        : fStrike{std::move(strike)} { }
239
240
53.6k
SkSpan<const SkGlyph*> SkBulkGlyphMetricsAndPaths::glyphs(SkSpan<const SkGlyphID> glyphIDs) {
241
53.6k
    fGlyphs.reset(glyphIDs.size());
242
53.6k
    return fStrike->preparePaths(glyphIDs, fGlyphs.get());
243
53.6k
}
244
245
0
const SkGlyph* SkBulkGlyphMetricsAndPaths::glyph(SkGlyphID glyphID) {
246
0
    return this->glyphs(SkSpan<const SkGlyphID>{&glyphID, 1})[0];
247
0
}
248
249
void SkBulkGlyphMetricsAndPaths::findIntercepts(
250
    const SkScalar* bounds, SkScalar scale, SkScalar xPos,
251
0
    const SkGlyph* glyph, SkScalar* array, int* count) {
252
    // TODO(herb): remove this abominable const_cast. Do the intercepts really need to be on the
253
    //  glyph?
254
0
    fStrike->findIntercepts(bounds, scale, xPos, const_cast<SkGlyph*>(glyph), array, count);
255
0
}
256
257
SkBulkGlyphMetricsAndImages::SkBulkGlyphMetricsAndImages(const SkStrikeSpec& spec)
258
508
        : fStrike{spec.findOrCreateStrike()} { }
259
260
SkBulkGlyphMetricsAndImages::SkBulkGlyphMetricsAndImages(sk_sp<SkStrike>&& strike)
261
0
        : fStrike{std::move(strike)} { }
262
263
715
SkSpan<const SkGlyph*> SkBulkGlyphMetricsAndImages::glyphs(SkSpan<const SkPackedGlyphID> glyphIDs) {
264
715
    fGlyphs.reset(glyphIDs.size());
265
715
    return fStrike->prepareImages(glyphIDs, fGlyphs.get());
266
715
}
267
268
715
const SkGlyph* SkBulkGlyphMetricsAndImages::glyph(SkPackedGlyphID packedID) {
269
715
    return this->glyphs(SkSpan<const SkPackedGlyphID>{&packedID, 1})[0];
270
715
}
271
272
0
const SkDescriptor& SkBulkGlyphMetricsAndImages::descriptor() const {
273
0
    return fStrike->getDescriptor();
274
0
}