• 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/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