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