xref: /aosp_15_r20/external/skia/src/core/SkStrikeSpec.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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/SkFont.h"
11 #include "include/core/SkMatrix.h"
12 #include "include/core/SkPaint.h"
13 #include "include/core/SkPathEffect.h"
14 #include "include/core/SkSurfaceProps.h"
15 #include "src/base/SkTLazy.h"
16 #include "src/core/SkFontPriv.h"
17 #include "src/core/SkGlyph.h"
18 #include "src/core/SkStrike.h"
19 #include "src/core/SkStrikeCache.h"
20 #include "src/text/StrikeForGPU.h"
21 
22 #include <utility>
23 
SkStrikeSpec(const SkDescriptor & descriptor,sk_sp<SkTypeface> typeface)24 SkStrikeSpec::SkStrikeSpec(const SkDescriptor& descriptor, sk_sp<SkTypeface> typeface)
25     : fAutoDescriptor{descriptor}
26     , fTypeface{std::move(typeface)} {}
27 
28 SkStrikeSpec::SkStrikeSpec(const SkStrikeSpec&) = default;
29 SkStrikeSpec::SkStrikeSpec(SkStrikeSpec&&) = default;
30 SkStrikeSpec::~SkStrikeSpec() = default;
31 
MakeMask(const SkFont & font,const SkPaint & paint,const SkSurfaceProps & surfaceProps,SkScalerContextFlags scalerContextFlags,const SkMatrix & deviceMatrix)32 SkStrikeSpec SkStrikeSpec::MakeMask(const SkFont& font, const SkPaint& paint,
33                                     const SkSurfaceProps& surfaceProps,
34                                     SkScalerContextFlags scalerContextFlags,
35                                     const SkMatrix& deviceMatrix) {
36 
37     return SkStrikeSpec(font, paint, surfaceProps, scalerContextFlags, deviceMatrix);
38 }
39 
MakeTransformMask(const SkFont & font,const SkPaint & paint,const SkSurfaceProps & surfaceProps,SkScalerContextFlags scalerContextFlags,const SkMatrix & deviceMatrix)40 SkStrikeSpec SkStrikeSpec::MakeTransformMask(const SkFont& font,
41                                              const SkPaint& paint,
42                                              const SkSurfaceProps& surfaceProps,
43                                              SkScalerContextFlags scalerContextFlags,
44                                              const SkMatrix& deviceMatrix) {
45     SkFont sourceFont{font};
46     sourceFont.setSubpixel(false);
47     return SkStrikeSpec(sourceFont, paint, surfaceProps, scalerContextFlags, deviceMatrix);
48 }
49 
MakePath(const SkFont & font,const SkPaint & paint,const SkSurfaceProps & surfaceProps,SkScalerContextFlags scalerContextFlags)50 std::tuple<SkStrikeSpec, SkScalar> SkStrikeSpec::MakePath(
51         const SkFont& font, const SkPaint& paint,
52         const SkSurfaceProps& surfaceProps,
53         SkScalerContextFlags scalerContextFlags) {
54 
55     // setup our std runPaint, in hopes of getting hits in the cache
56     SkPaint pathPaint{paint};
57     SkFont pathFont{font};
58 
59     // The sub-pixel position will always happen when transforming to the screen.
60     pathFont.setSubpixel(false);
61 
62     // The factor to get from the size stored in the strike to the size needed for
63     // the source.
64     SkScalar strikeToSourceScale = pathFont.setupForAsPaths(&pathPaint);
65 
66     return {SkStrikeSpec(pathFont, pathPaint, surfaceProps, scalerContextFlags, SkMatrix::I()),
67             strikeToSourceScale};
68 }
69 
MakeCanonicalized(const SkFont & font,const SkPaint * paint)70 std::tuple<SkStrikeSpec, SkScalar> SkStrikeSpec::MakeCanonicalized(
71         const SkFont& font, const SkPaint* paint) {
72     SkPaint canonicalizedPaint;
73     if (paint != nullptr) {
74         canonicalizedPaint = *paint;
75     }
76 
77     const SkFont* canonicalizedFont = &font;
78     SkTLazy<SkFont> pathFont;
79     SkScalar strikeToSourceScale = 1;
80     if (ShouldDrawAsPath(canonicalizedPaint, font, SkMatrix::I())) {
81         canonicalizedFont = pathFont.set(font);
82         strikeToSourceScale = pathFont->setupForAsPaths(nullptr);
83         canonicalizedPaint.reset();
84     }
85 
86     return {SkStrikeSpec(*canonicalizedFont, canonicalizedPaint, SkSurfaceProps(),
87                          SkScalerContextFlags::kFakeGammaAndBoostContrast, SkMatrix::I()),
88             strikeToSourceScale};
89 }
90 
MakeWithNoDevice(const SkFont & font,const SkPaint * paint)91 SkStrikeSpec SkStrikeSpec::MakeWithNoDevice(const SkFont& font, const SkPaint* paint) {
92     SkPaint setupPaint;
93     if (paint != nullptr) {
94         setupPaint = *paint;
95     }
96 
97     return SkStrikeSpec(font, setupPaint, SkSurfaceProps(),
98                         SkScalerContextFlags::kFakeGammaAndBoostContrast, SkMatrix::I());
99 }
100 
ShouldDrawAsPath(const SkPaint & paint,const SkFont & font,const SkMatrix & viewMatrix)101 bool SkStrikeSpec::ShouldDrawAsPath(
102         const SkPaint& paint, const SkFont& font, const SkMatrix& viewMatrix) {
103 
104     // hairline glyphs are fast enough, so we don't need to cache them
105     if (SkPaint::kStroke_Style == paint.getStyle() && 0 == paint.getStrokeWidth()) {
106         return true;
107     }
108 
109     // we don't cache perspective
110     if (viewMatrix.hasPerspective()) {
111         return true;
112     }
113 
114     SkMatrix textMatrix = SkFontPriv::MakeTextMatrix(font);
115     textMatrix.postConcat(viewMatrix);
116 
117     // we have a self-imposed maximum, just to limit memory-usage
118     constexpr SkScalar memoryLimit = 256;
119     constexpr SkScalar maxSizeSquared = memoryLimit * memoryLimit;
120 
121     auto distance = [&textMatrix](int XIndex, int YIndex) {
122         return textMatrix[XIndex] * textMatrix[XIndex] + textMatrix[YIndex] * textMatrix[YIndex];
123     };
124 
125     return distance(SkMatrix::kMScaleX, SkMatrix::kMSkewY ) > maxSizeSquared
126         || distance(SkMatrix::kMSkewX,  SkMatrix::kMScaleY) > maxSizeSquared;
127 }
128 
dump() const129 SkString SkStrikeSpec::dump() const {
130     return fAutoDescriptor.getDesc()->dumpRec();
131 }
132 
SkStrikeSpec(const SkFont & font,const SkPaint & paint,const SkSurfaceProps & surfaceProps,SkScalerContextFlags scalerContextFlags,const SkMatrix & deviceMatrix)133 SkStrikeSpec::SkStrikeSpec(const SkFont& font, const SkPaint& paint,
134                            const SkSurfaceProps& surfaceProps,
135                            SkScalerContextFlags scalerContextFlags,
136                            const SkMatrix& deviceMatrix) {
137     SkScalerContextEffects effects;
138 
139     SkScalerContext::CreateDescriptorAndEffectsUsingPaint(
140             font, paint, surfaceProps, scalerContextFlags, deviceMatrix,
141             &fAutoDescriptor, &effects);
142 
143     fMaskFilter = sk_ref_sp(effects.fMaskFilter);
144     fPathEffect = sk_ref_sp(effects.fPathEffect);
145     fTypeface = font.refTypeface();
146 }
147 
findOrCreateScopedStrike(sktext::StrikeForGPUCacheInterface * cache) const148 sk_sp<sktext::StrikeForGPU> SkStrikeSpec::findOrCreateScopedStrike(
149         sktext::StrikeForGPUCacheInterface* cache) const {
150     return cache->findOrCreateScopedStrike(*this);
151 }
152 
findOrCreateStrike() const153 sk_sp<SkStrike> SkStrikeSpec::findOrCreateStrike() const {
154     return SkStrikeCache::GlobalStrikeCache()->findOrCreateStrike(*this);
155 }
156 
findOrCreateStrike(SkStrikeCache * cache) const157 sk_sp<SkStrike> SkStrikeSpec::findOrCreateStrike(SkStrikeCache* cache) const {
158     return cache->findOrCreateStrike(*this);
159 }
160 
SkBulkGlyphMetrics(const SkStrikeSpec & spec)161 SkBulkGlyphMetrics::SkBulkGlyphMetrics(const SkStrikeSpec& spec)
162     : fStrike{spec.findOrCreateStrike()} { }
163 
164 SkBulkGlyphMetrics::~SkBulkGlyphMetrics() = default;
165 
glyphs(SkSpan<const SkGlyphID> glyphIDs)166 SkSpan<const SkGlyph*> SkBulkGlyphMetrics::glyphs(SkSpan<const SkGlyphID> glyphIDs) {
167     fGlyphs.reset(glyphIDs.size());
168     return fStrike->metrics(glyphIDs, fGlyphs.get());
169 }
170 
glyph(SkGlyphID glyphID)171 const SkGlyph* SkBulkGlyphMetrics::glyph(SkGlyphID glyphID) {
172     return this->glyphs(SkSpan<const SkGlyphID>{&glyphID, 1})[0];
173 }
174 
SkBulkGlyphMetricsAndPaths(const SkStrikeSpec & spec)175 SkBulkGlyphMetricsAndPaths::SkBulkGlyphMetricsAndPaths(const SkStrikeSpec& spec)
176     : fStrike{spec.findOrCreateStrike()} { }
177 
SkBulkGlyphMetricsAndPaths(sk_sp<SkStrike> && strike)178 SkBulkGlyphMetricsAndPaths::SkBulkGlyphMetricsAndPaths(sk_sp<SkStrike>&& strike)
179         : fStrike{std::move(strike)} { }
180 
181 SkBulkGlyphMetricsAndPaths::~SkBulkGlyphMetricsAndPaths() = default;
182 
glyphs(SkSpan<const SkGlyphID> glyphIDs)183 SkSpan<const SkGlyph*> SkBulkGlyphMetricsAndPaths::glyphs(SkSpan<const SkGlyphID> glyphIDs) {
184     fGlyphs.reset(glyphIDs.size());
185     return fStrike->preparePaths(glyphIDs, fGlyphs.get());
186 }
187 
glyph(SkGlyphID glyphID)188 const SkGlyph* SkBulkGlyphMetricsAndPaths::glyph(SkGlyphID glyphID) {
189     return this->glyphs(SkSpan<const SkGlyphID>{&glyphID, 1})[0];
190 }
191 
findIntercepts(const SkScalar * bounds,SkScalar scale,SkScalar xPos,const SkGlyph * glyph,SkScalar * array,int * count)192 void SkBulkGlyphMetricsAndPaths::findIntercepts(
193     const SkScalar* bounds, SkScalar scale, SkScalar xPos,
194     const SkGlyph* glyph, SkScalar* array, int* count) {
195     // TODO(herb): remove this abominable const_cast. Do the intercepts really need to be on the
196     //  glyph?
197     fStrike->findIntercepts(bounds, scale, xPos, const_cast<SkGlyph*>(glyph), array, count);
198 }
199 
SkBulkGlyphMetricsAndDrawables(const SkStrikeSpec & spec)200 SkBulkGlyphMetricsAndDrawables::SkBulkGlyphMetricsAndDrawables(const SkStrikeSpec& spec)
201         : fStrike{spec.findOrCreateStrike()} { }
202 
SkBulkGlyphMetricsAndDrawables(sk_sp<SkStrike> && strike)203 SkBulkGlyphMetricsAndDrawables::SkBulkGlyphMetricsAndDrawables(sk_sp<SkStrike>&& strike)
204         : fStrike{std::move(strike)} { }
205 
206 SkBulkGlyphMetricsAndDrawables::~SkBulkGlyphMetricsAndDrawables() = default;
207 
glyphs(SkSpan<const SkGlyphID> glyphIDs)208 SkSpan<const SkGlyph*> SkBulkGlyphMetricsAndDrawables::glyphs(SkSpan<const SkGlyphID> glyphIDs) {
209     fGlyphs.reset(glyphIDs.size());
210     return fStrike->prepareDrawables(glyphIDs, fGlyphs.get());
211 }
212 
glyph(SkGlyphID glyphID)213 const SkGlyph* SkBulkGlyphMetricsAndDrawables::glyph(SkGlyphID glyphID) {
214     return this->glyphs(SkSpan<const SkGlyphID>{&glyphID, 1})[0];
215 }
216 
SkBulkGlyphMetricsAndImages(const SkStrikeSpec & spec)217 SkBulkGlyphMetricsAndImages::SkBulkGlyphMetricsAndImages(const SkStrikeSpec& spec)
218         : fStrike{spec.findOrCreateStrike()} { }
219 
SkBulkGlyphMetricsAndImages(sk_sp<SkStrike> && strike)220 SkBulkGlyphMetricsAndImages::SkBulkGlyphMetricsAndImages(sk_sp<SkStrike>&& strike)
221         : fStrike{std::move(strike)} { }
222 
223 SkBulkGlyphMetricsAndImages::~SkBulkGlyphMetricsAndImages() = default;
224 
glyphs(SkSpan<const SkPackedGlyphID> glyphIDs)225 SkSpan<const SkGlyph*> SkBulkGlyphMetricsAndImages::glyphs(SkSpan<const SkPackedGlyphID> glyphIDs) {
226     fGlyphs.reset(glyphIDs.size());
227     return fStrike->prepareImages(glyphIDs, fGlyphs.get());
228 }
229 
glyph(SkPackedGlyphID packedID)230 const SkGlyph* SkBulkGlyphMetricsAndImages::glyph(SkPackedGlyphID packedID) {
231     return this->glyphs(SkSpan<const SkPackedGlyphID>{&packedID, 1})[0];
232 }
233 
descriptor() const234 const SkDescriptor& SkBulkGlyphMetricsAndImages::descriptor() const {
235     return fStrike->getDescriptor();
236 }
237