/src/skia/tools/fonts/RandomScalerContext.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright 2015 Google Inc. |
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 "tools/fonts/RandomScalerContext.h" |
9 | | |
10 | | #include "include/core/SkBitmap.h" |
11 | | #include "include/core/SkCanvas.h" |
12 | | #include "include/core/SkDrawable.h" |
13 | | #include "include/core/SkPath.h" |
14 | | #include "include/core/SkStream.h" |
15 | | #include "src/core/SkAdvancedTypefaceMetrics.h" |
16 | | #include "src/core/SkGlyph.h" |
17 | | #include "src/core/SkRectPriv.h" |
18 | | #include "src/core/SkTHash.h" |
19 | | |
20 | | using namespace skia_private; |
21 | | |
22 | | class SkDescriptor; |
23 | | |
24 | | class RandomScalerContext : public SkScalerContext { |
25 | | public: |
26 | | RandomScalerContext(sk_sp<SkRandomTypeface>, |
27 | | const SkScalerContextEffects&, |
28 | | const SkDescriptor*, |
29 | | bool fFakeIt); |
30 | | |
31 | | protected: |
32 | | GlyphMetrics generateMetrics(const SkGlyph&, SkArenaAlloc*) override; |
33 | | void generateImage(const SkGlyph&, void*) override; |
34 | | bool generatePath(const SkGlyph&, SkPath*) override; |
35 | | sk_sp<SkDrawable> generateDrawable(const SkGlyph&) override; |
36 | | void generateFontMetrics(SkFontMetrics*) override; |
37 | | |
38 | | private: |
39 | 0 | SkRandomTypeface* getRandomTypeface() const { |
40 | 0 | return static_cast<SkRandomTypeface*>(this->getTypeface()); |
41 | 0 | } |
42 | | std::unique_ptr<SkScalerContext> fProxy; |
43 | | // Many of the SkGlyphs returned are the same as those created by the fProxy. |
44 | | // When they are not, the originals are kept here. |
45 | | THashMap<SkPackedGlyphID, SkGlyph> fProxyGlyphs; |
46 | | bool fFakeIt; |
47 | | }; |
48 | | |
49 | | RandomScalerContext::RandomScalerContext(sk_sp<SkRandomTypeface> face, |
50 | | const SkScalerContextEffects& effects, |
51 | | const SkDescriptor* desc, |
52 | | bool fakeIt) |
53 | | : SkScalerContext(std::move(face), effects, desc) |
54 | | , fProxy(getRandomTypeface()->proxy()->createScalerContext(SkScalerContextEffects(), desc)) |
55 | 0 | , fFakeIt(fakeIt) { |
56 | 0 | fProxy->forceGenerateImageFromPath(); |
57 | 0 | } |
58 | | |
59 | | SkScalerContext::GlyphMetrics RandomScalerContext::generateMetrics(const SkGlyph& origGlyph, |
60 | 0 | SkArenaAlloc* alloc) { |
61 | | // Here we will change the mask format of the glyph |
62 | | // NOTE: this may be overridden by the base class (e.g. if a mask filter is applied). |
63 | 0 | SkMask::Format format = SkMask::kA8_Format; |
64 | 0 | switch (origGlyph.getGlyphID() % 4) { |
65 | 0 | case 0: format = SkMask::kLCD16_Format; break; |
66 | 0 | case 1: format = SkMask::kA8_Format; break; |
67 | 0 | case 2: format = SkMask::kARGB32_Format; break; |
68 | 0 | case 3: format = SkMask::kBW_Format; break; |
69 | 0 | } |
70 | | |
71 | 0 | auto glyph = fProxy->internalMakeGlyph(origGlyph.getPackedID(), format, alloc); |
72 | |
|
73 | 0 | GlyphMetrics mx(SkMask::kA8_Format); |
74 | 0 | mx.advance = glyph.advanceVector(); |
75 | 0 | mx.bounds = glyph.rect(); |
76 | 0 | mx.maskFormat = glyph.maskFormat(); |
77 | 0 | mx.extraBits = glyph.extraBits(); |
78 | |
|
79 | 0 | if (fFakeIt || (glyph.getGlyphID() % 4) != 2) { |
80 | 0 | mx.neverRequestPath = glyph.setPathHasBeenCalled() && !glyph.path(); |
81 | 0 | mx.computeFromPath = !mx.neverRequestPath; |
82 | 0 | return mx; |
83 | 0 | } |
84 | | |
85 | 0 | fProxy->getPath(glyph, alloc); |
86 | 0 | if (!glyph.path()) { |
87 | 0 | mx.neverRequestPath = true; |
88 | 0 | return mx; |
89 | 0 | } |
90 | | |
91 | | // The proxy glyph has a path, but this glyph does not. |
92 | | // Stash the proxy glyph so it can be used later. |
93 | 0 | const auto packedID = glyph.getPackedID(); |
94 | 0 | const SkGlyph* proxyGlyph = fProxyGlyphs.set(packedID, std::move(glyph)); |
95 | 0 | const SkPath& proxyPath = *proxyGlyph->path(); |
96 | |
|
97 | 0 | mx.neverRequestPath = true; |
98 | 0 | mx.maskFormat = SkMask::kARGB32_Format; |
99 | 0 | mx.advance = proxyGlyph->advanceVector(); |
100 | 0 | mx.extraBits = proxyGlyph->extraBits(); |
101 | |
|
102 | 0 | SkRect storage; |
103 | 0 | const SkPaint& paint = this->getRandomTypeface()->paint(); |
104 | 0 | const SkRect& newBounds = |
105 | 0 | paint.doComputeFastBounds(proxyPath.getBounds(), &storage, SkPaint::kFill_Style); |
106 | 0 | newBounds.roundOut(&mx.bounds); |
107 | |
|
108 | 0 | return mx; |
109 | 0 | } |
110 | | |
111 | 0 | void RandomScalerContext::generateImage(const SkGlyph& glyph, void* imageBuffer) { |
112 | 0 | if (fFakeIt) { |
113 | 0 | sk_bzero(imageBuffer, glyph.imageSize()); |
114 | 0 | return; |
115 | 0 | } |
116 | | |
117 | 0 | SkGlyph* proxyGlyph = fProxyGlyphs.find(glyph.getPackedID()); |
118 | 0 | if (!proxyGlyph || !proxyGlyph->path()) { |
119 | 0 | fProxy->getImage(glyph); |
120 | 0 | return; |
121 | 0 | } |
122 | 0 | const SkPath& path = *proxyGlyph->path(); |
123 | 0 | const bool hairline = proxyGlyph->pathIsHairline(); |
124 | |
|
125 | 0 | SkBitmap bm; |
126 | 0 | bm.installPixels(SkImageInfo::MakeN32Premul(glyph.width(), glyph.height()), |
127 | 0 | imageBuffer, glyph.rowBytes()); |
128 | 0 | bm.eraseColor(0); |
129 | |
|
130 | 0 | SkCanvas canvas(bm); |
131 | 0 | canvas.translate(-SkIntToScalar(glyph.left()), -SkIntToScalar(glyph.top())); |
132 | 0 | SkPaint paint = this->getRandomTypeface()->paint(); |
133 | 0 | if (hairline) { |
134 | | // We have a device path with effects already applied which is normally a fill path. |
135 | | // However here we do not have a fill path and there is no area to fill. |
136 | 0 | paint.setStyle(SkPaint::kStroke_Style); |
137 | 0 | paint.setStroke(0); |
138 | 0 | } |
139 | 0 | canvas.drawPath(path, paint); //Need to modify the paint if the devPath is hairline |
140 | 0 | } |
141 | | |
142 | 0 | bool RandomScalerContext::generatePath(const SkGlyph& glyph, SkPath* path) { |
143 | 0 | SkGlyph* shadowProxyGlyph = fProxyGlyphs.find(glyph.getPackedID()); |
144 | 0 | if (shadowProxyGlyph && shadowProxyGlyph->path()) { |
145 | 0 | path->reset(); |
146 | 0 | return false; |
147 | 0 | } |
148 | 0 | return fProxy->generatePath(glyph, path); |
149 | 0 | } |
150 | | |
151 | 0 | sk_sp<SkDrawable> RandomScalerContext::generateDrawable(const SkGlyph& glyph) { |
152 | 0 | SkGlyph* shadowProxyGlyph = fProxyGlyphs.find(glyph.getPackedID()); |
153 | 0 | if (shadowProxyGlyph && shadowProxyGlyph->path()) { |
154 | 0 | return nullptr; |
155 | 0 | } |
156 | 0 | return fProxy->generateDrawable(glyph); |
157 | 0 | } |
158 | | |
159 | 0 | void RandomScalerContext::generateFontMetrics(SkFontMetrics* metrics) { |
160 | 0 | fProxy->getFontMetrics(metrics); |
161 | 0 | } |
162 | | |
163 | | /////////////////////////////////////////////////////////////////////////////// |
164 | | |
165 | | SkRandomTypeface::SkRandomTypeface(sk_sp<SkTypeface> proxy, const SkPaint& paint, bool fakeIt) |
166 | | : SkTypeface(proxy->fontStyle(), false) |
167 | | , fProxy(std::move(proxy)) |
168 | | , fPaint(paint) |
169 | 0 | , fFakeIt(fakeIt) {} |
170 | | |
171 | | std::unique_ptr<SkScalerContext> SkRandomTypeface::onCreateScalerContext( |
172 | | const SkScalerContextEffects& effects, const SkDescriptor* desc) const |
173 | 0 | { |
174 | 0 | return std::make_unique<RandomScalerContext>( |
175 | 0 | sk_ref_sp(const_cast<SkRandomTypeface*>(this)), effects, desc, fFakeIt); |
176 | 0 | } |
177 | | |
178 | 0 | void SkRandomTypeface::onFilterRec(SkScalerContextRec* rec) const { |
179 | 0 | fProxy->filterRec(rec); |
180 | 0 | rec->setHinting(SkFontHinting::kNone); |
181 | 0 | rec->fMaskFormat = SkMask::kARGB32_Format; |
182 | 0 | } |
183 | | |
184 | 0 | void SkRandomTypeface::getGlyphToUnicodeMap(SkUnichar* glyphToUnicode) const { |
185 | 0 | fProxy->getGlyphToUnicodeMap(glyphToUnicode); |
186 | 0 | } |
187 | | |
188 | 0 | std::unique_ptr<SkAdvancedTypefaceMetrics> SkRandomTypeface::onGetAdvancedMetrics() const { |
189 | 0 | return fProxy->getAdvancedMetrics(); |
190 | 0 | } |
191 | | |
192 | 0 | std::unique_ptr<SkStreamAsset> SkRandomTypeface::onOpenStream(int* ttcIndex) const { |
193 | 0 | return fProxy->openStream(ttcIndex); |
194 | 0 | } |
195 | | |
196 | 0 | sk_sp<SkTypeface> SkRandomTypeface::onMakeClone(const SkFontArguments& args) const { |
197 | 0 | sk_sp<SkTypeface> proxy = fProxy->makeClone(args); |
198 | 0 | if (!proxy) { |
199 | 0 | return nullptr; |
200 | 0 | } |
201 | 0 | return sk_make_sp<SkRandomTypeface>(proxy, fPaint, fFakeIt); |
202 | 0 | } |
203 | | |
204 | 0 | void SkRandomTypeface::onGetFontDescriptor(SkFontDescriptor* desc, bool* isLocal) const { |
205 | | // TODO: anything that uses this typeface isn't correctly serializable, since this typeface |
206 | | // cannot be deserialized. |
207 | 0 | fProxy->getFontDescriptor(desc, isLocal); |
208 | 0 | } |
209 | | |
210 | 0 | void SkRandomTypeface::onCharsToGlyphs(const SkUnichar* uni, int count, SkGlyphID glyphs[]) const { |
211 | 0 | fProxy->unicharsToGlyphs(uni, count, glyphs); |
212 | 0 | } |
213 | | |
214 | 0 | int SkRandomTypeface::onCountGlyphs() const { return fProxy->countGlyphs(); } |
215 | | |
216 | 0 | int SkRandomTypeface::onGetUPEM() const { return fProxy->getUnitsPerEm(); } |
217 | | |
218 | 0 | void SkRandomTypeface::onGetFamilyName(SkString* familyName) const { |
219 | 0 | fProxy->getFamilyName(familyName); |
220 | 0 | } |
221 | | |
222 | 0 | bool SkRandomTypeface::onGetPostScriptName(SkString* postScriptName) const { |
223 | 0 | return fProxy->getPostScriptName(postScriptName); |
224 | 0 | } |
225 | | |
226 | 0 | SkTypeface::LocalizedStrings* SkRandomTypeface::onCreateFamilyNameIterator() const { |
227 | 0 | return fProxy->createFamilyNameIterator(); |
228 | 0 | } |
229 | | |
230 | 0 | void SkRandomTypeface::getPostScriptGlyphNames(SkString* names) const { |
231 | 0 | return fProxy->getPostScriptGlyphNames(names); |
232 | 0 | } |
233 | | |
234 | 0 | bool SkRandomTypeface::onGlyphMaskNeedsCurrentColor() const { |
235 | 0 | return fProxy->glyphMaskNeedsCurrentColor(); |
236 | 0 | } |
237 | | |
238 | | int SkRandomTypeface::onGetVariationDesignPosition( |
239 | | SkFontArguments::VariationPosition::Coordinate coordinates[], |
240 | 0 | int coordinateCount) const { |
241 | 0 | return fProxy->onGetVariationDesignPosition(coordinates, coordinateCount); |
242 | 0 | } |
243 | | |
244 | | int SkRandomTypeface::onGetVariationDesignParameters(SkFontParameters::Variation::Axis parameters[], |
245 | 0 | int parameterCount) const { |
246 | 0 | return fProxy->onGetVariationDesignParameters(parameters, parameterCount); |
247 | 0 | } |
248 | | |
249 | 0 | int SkRandomTypeface::onGetTableTags(SkFontTableTag tags[]) const { |
250 | 0 | return fProxy->getTableTags(tags); |
251 | 0 | } |
252 | | |
253 | | size_t SkRandomTypeface::onGetTableData(SkFontTableTag tag, |
254 | | size_t offset, |
255 | | size_t length, |
256 | 0 | void* data) const { |
257 | 0 | return fProxy->getTableData(tag, offset, length, data); |
258 | 0 | } |