• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
MakeMask(const SkFont & font,const SkPaint & paint,const SkSurfaceProps & surfaceProps,SkScalerContextFlags scalerContextFlags,const SkMatrix & deviceMatrix)16 SkStrikeSpec SkStrikeSpec::MakeMask(const SkFont& font, const SkPaint& paint,
17                                     const SkSurfaceProps& surfaceProps,
18                                     SkScalerContextFlags scalerContextFlags,
19                                     const SkMatrix& deviceMatrix) {
20     SkStrikeSpec storage;
21 
22     storage.commonSetup(font, paint, surfaceProps, scalerContextFlags, deviceMatrix);
23 
24     return storage;
25 }
26 
MakePath(const SkFont & font,const SkPaint & paint,const SkSurfaceProps & surfaceProps,SkScalerContextFlags scalerContextFlags)27 SkStrikeSpec SkStrikeSpec::MakePath(const SkFont& font, const SkPaint& paint,
28                                     const SkSurfaceProps& surfaceProps,
29                                     SkScalerContextFlags scalerContextFlags) {
30     SkStrikeSpec storage;
31 
32     // setup our std runPaint, in hopes of getting hits in the cache
33     SkPaint pathPaint{paint};
34     SkFont pathFont{font};
35 
36     // The factor to get from the size stored in the strike to the size needed for
37     // the source.
38     storage.fStrikeToSourceRatio = pathFont.setupForAsPaths(&pathPaint);
39 
40     // The sub-pixel position will always happen when transforming to the screen.
41     pathFont.setSubpixel(false);
42 
43     storage.commonSetup(pathFont, pathPaint, surfaceProps, scalerContextFlags, SkMatrix::I());
44 
45     return storage;
46 }
47 
MakeSourceFallback(const SkFont & font,const SkPaint & paint,const SkSurfaceProps & surfaceProps,SkScalerContextFlags scalerContextFlags,SkScalar maxSourceGlyphDimension)48 SkStrikeSpec SkStrikeSpec::MakeSourceFallback(
49         const SkFont& font,
50         const SkPaint& paint,
51         const SkSurfaceProps& surfaceProps,
52         SkScalerContextFlags scalerContextFlags,
53         SkScalar maxSourceGlyphDimension) {
54     SkStrikeSpec storage;
55 
56     // Subtract 2 to account for the bilerp pad around the glyph
57     SkScalar maxAtlasDimension = SkStrikeCommon::kSkSideTooBigForAtlas - 2;
58 
59     SkScalar runFontTextSize = font.getSize();
60 
61     // Scale the text size down so the long side of all the glyphs will fit in the atlas.
62     SkScalar fallbackTextSize = SkScalarFloorToScalar(
63             (maxAtlasDimension / maxSourceGlyphDimension) * runFontTextSize);
64 
65     SkFont fallbackFont{font};
66     fallbackFont.setSize(fallbackTextSize);
67 
68     // No sub-pixel needed. The transform to the screen will take care of sub-pixel positioning.
69     fallbackFont.setSubpixel(false);
70 
71     // The scale factor to go from strike size to the source size for glyphs.
72     storage.fStrikeToSourceRatio = runFontTextSize / fallbackTextSize;
73 
74     storage.commonSetup(fallbackFont, paint, surfaceProps, scalerContextFlags, SkMatrix::I());
75 
76     return storage;
77 }
78 
MakeCanonicalized(const SkFont & font,const SkPaint * paint)79 SkStrikeSpec SkStrikeSpec::MakeCanonicalized(const SkFont& font, const SkPaint* paint) {
80     SkStrikeSpec storage;
81 
82     SkPaint canonicalizedPaint;
83     if (paint != nullptr) {
84         canonicalizedPaint = *paint;
85     }
86 
87     const SkFont* canonicalizedFont = &font;
88     SkTLazy<SkFont> pathFont;
89     if (ShouldDrawAsPath(canonicalizedPaint, font, SkMatrix::I())) {
90         canonicalizedFont = pathFont.set(font);
91         storage.fStrikeToSourceRatio = pathFont->setupForAsPaths(nullptr);
92         canonicalizedPaint.reset();
93     }
94 
95     storage.commonSetup(*canonicalizedFont,
96                         canonicalizedPaint,
97                         SkSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType),
98                         kFakeGammaAndBoostContrast,
99                         SkMatrix::I());
100     return storage;
101 }
102 
MakeWithNoDevice(const SkFont & font,const SkPaint * paint)103 SkStrikeSpec SkStrikeSpec::MakeWithNoDevice(const SkFont& font, const SkPaint* paint) {
104     SkStrikeSpec storage;
105 
106     SkPaint setupPaint;
107     if (paint != nullptr) {
108         setupPaint = *paint;
109     }
110 
111     storage.commonSetup(font,
112                         setupPaint,
113                         SkSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType),
114                         kFakeGammaAndBoostContrast,
115                         SkMatrix::I());
116 
117     return storage;
118 
119 }
120 
MakeDefault()121 SkStrikeSpec SkStrikeSpec::MakeDefault() {
122     SkFont defaultFont;
123     return MakeCanonicalized(defaultFont);
124 }
125 
ShouldDrawAsPath(const SkPaint & paint,const SkFont & font,const SkMatrix & viewMatrix)126 bool SkStrikeSpec::ShouldDrawAsPath(
127         const SkPaint& paint, const SkFont& font, const SkMatrix& viewMatrix) {
128 
129     // hairline glyphs are fast enough so we don't need to cache them
130     if (SkPaint::kStroke_Style == paint.getStyle() && 0 == paint.getStrokeWidth()) {
131         return true;
132     }
133 
134     // we don't cache perspective
135     if (viewMatrix.hasPerspective()) {
136         return true;
137     }
138 
139     SkMatrix textMatrix = SkFontPriv::MakeTextMatrix(font);
140     textMatrix.postConcat(viewMatrix);
141 
142     // we have a self-imposed maximum, just for memory-usage sanity
143     SkScalar limit = SkMinScalar(SkGraphics::GetFontCachePointSizeLimit(), 1024);
144     SkScalar maxSizeSquared = limit * limit;
145 
146     auto distance = [&textMatrix](int XIndex, int YIndex) {
147         return textMatrix[XIndex] * textMatrix[XIndex] + textMatrix[YIndex] * textMatrix[YIndex];
148     };
149 
150     return distance(SkMatrix::kMScaleX, SkMatrix::kMSkewY ) > maxSizeSquared
151         || distance(SkMatrix::kMSkewX,  SkMatrix::kMScaleY) > maxSizeSquared;
152 }
153 
MakePDFVector(const SkTypeface & typeface,int * size)154 SkStrikeSpec SkStrikeSpec::MakePDFVector(const SkTypeface& typeface, int* size) {
155     SkFont font;
156     font.setHinting(SkFontHinting::kNone);
157     font.setEdging(SkFont::Edging::kAlias);
158     font.setTypeface(sk_ref_sp(&typeface));
159     int unitsPerEm = typeface.getUnitsPerEm();
160     if (unitsPerEm <= 0) {
161         unitsPerEm = 1024;
162     }
163     if (size) {
164         *size = unitsPerEm;
165     }
166     font.setSize((SkScalar)unitsPerEm);
167 
168     SkStrikeSpec storage;
169     storage.commonSetup(font,
170                         SkPaint(),
171                         SkSurfaceProps(0, kUnknown_SkPixelGeometry),
172                         kFakeGammaAndBoostContrast,
173                         SkMatrix::I());
174 
175     return storage;
176 }
177 
178 #if SK_SUPPORT_GPU
179 std::tuple<SkStrikeSpec, SkScalar, SkScalar>
MakeSDFT(const SkFont & font,const SkPaint & paint,const SkSurfaceProps & surfaceProps,const SkMatrix & deviceMatrix,const GrTextContext::Options & options)180 SkStrikeSpec::MakeSDFT(const SkFont& font, const SkPaint& paint,
181                        const SkSurfaceProps& surfaceProps, const SkMatrix& deviceMatrix,
182                        const GrTextContext::Options& options) {
183     SkStrikeSpec storage;
184 
185     SkPaint dfPaint = GrTextContext::InitDistanceFieldPaint(paint);
186     SkFont dfFont = GrTextContext::InitDistanceFieldFont(
187             font, deviceMatrix, options, &storage.fStrikeToSourceRatio);
188 
189     // Fake-gamma and subpixel antialiasing are applied in the shader, so we ignore the
190     // passed-in scaler context flags. (It's only used when we fall-back to bitmap text).
191     SkScalerContextFlags flags = SkScalerContextFlags::kNone;
192 
193     SkScalar minScale, maxScale;
194     std::tie(minScale, maxScale) = GrTextContext::InitDistanceFieldMinMaxScale(
195             font.getSize(), deviceMatrix, options);
196 
197     storage.commonSetup(dfFont, dfPaint, surfaceProps, flags, SkMatrix::I());
198 
199     return std::tie(storage, minScale, maxScale);
200 }
201 
findOrCreateGrStrike(GrStrikeCache * cache) const202 sk_sp<GrTextStrike> SkStrikeSpec::findOrCreateGrStrike(GrStrikeCache* cache) const {
203     return cache->getStrike(*fAutoDescriptor.getDesc());
204 }
205 #endif
206 
commonSetup(const SkFont & font,const SkPaint & paint,const SkSurfaceProps & surfaceProps,SkScalerContextFlags scalerContextFlags,const SkMatrix & deviceMatrix)207 void SkStrikeSpec::commonSetup(const SkFont& font, const SkPaint& paint,
208                                const SkSurfaceProps& surfaceProps,
209                                SkScalerContextFlags scalerContextFlags,
210                                const SkMatrix& deviceMatrix) {
211     SkScalerContextEffects effects;
212 
213     SkScalerContext::CreateDescriptorAndEffectsUsingPaint(
214             font, paint, surfaceProps, scalerContextFlags, deviceMatrix,
215             &fAutoDescriptor, &effects);
216 
217     fMaskFilter = sk_ref_sp(effects.fMaskFilter);
218     fPathEffect = sk_ref_sp(effects.fPathEffect);
219     fTypeface = font.refTypefaceOrDefault();
220 }
221 
findOrCreateScopedStrike(SkStrikeCacheInterface * cache) const222 SkScopedStrike SkStrikeSpec::findOrCreateScopedStrike(SkStrikeCacheInterface* cache) const {
223     SkScalerContextEffects effects{fPathEffect.get(), fMaskFilter.get()};
224     return cache->findOrCreateScopedStrike(*fAutoDescriptor.getDesc(), effects, *fTypeface);
225 }
226 
findOrCreateExclusiveStrike(SkStrikeCache * cache) const227 SkExclusiveStrikePtr SkStrikeSpec::findOrCreateExclusiveStrike(SkStrikeCache* cache) const {
228     SkScalerContextEffects effects{fPathEffect.get(), fMaskFilter.get()};
229     return cache->findOrCreateStrikeExclusive(*fAutoDescriptor.getDesc(), effects, *fTypeface);
230 }
231 
SkBulkGlyphMetrics(const SkStrikeSpec & spec)232 SkBulkGlyphMetrics::SkBulkGlyphMetrics(const SkStrikeSpec& spec)
233     : fStrike{spec.findOrCreateExclusiveStrike()} { }
234 
glyphs(SkSpan<const SkGlyphID> glyphIDs)235 SkSpan<const SkGlyph*> SkBulkGlyphMetrics::glyphs(SkSpan<const SkGlyphID> glyphIDs) {
236     fGlyphs.reset(glyphIDs.size());
237     return fStrike->metrics(glyphIDs, fGlyphs.get());
238 }
239 
SkBulkGlyphMetricsAndPaths(const SkStrikeSpec & spec)240 SkBulkGlyphMetricsAndPaths::SkBulkGlyphMetricsAndPaths(const SkStrikeSpec& spec)
241     : fStrike{spec.findOrCreateExclusiveStrike()} { }
242 
glyphs(SkSpan<const SkGlyphID> glyphIDs)243 SkSpan<const SkGlyph*> SkBulkGlyphMetricsAndPaths::glyphs(SkSpan<const SkGlyphID> glyphIDs) {
244     fGlyphs.reset(glyphIDs.size());
245     return fStrike->preparePaths(glyphIDs, fGlyphs.get());
246 }
247 
SkBulkGlyphMetricsAndImages(const SkStrikeSpec & spec)248 SkBulkGlyphMetricsAndImages::SkBulkGlyphMetricsAndImages(const SkStrikeSpec& spec)
249         : fStrike{spec.findOrCreateExclusiveStrike()} { }
250 
glyphs(SkSpan<const SkPackedGlyphID> glyphIDs)251 SkSpan<const SkGlyph*> SkBulkGlyphMetricsAndImages::glyphs(SkSpan<const SkPackedGlyphID> glyphIDs) {
252     fGlyphs.reset(glyphIDs.size());
253     return fStrike->prepareImages(glyphIDs, fGlyphs.get());
254 }
255