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