• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2006 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/SkStrike.h"
9 
10 #include "include/core/SkDrawable.h"
11 #include "include/core/SkGraphics.h"
12 #include "include/core/SkPath.h"
13 #include "include/core/SkTraceMemoryDump.h"
14 #include "include/core/SkTypeface.h"
15 #include "src/core/SkDistanceFieldGen.h"
16 #include "src/core/SkEnumerate.h"
17 #include "src/core/SkGlyph.h"
18 #include "src/core/SkGlyphBuffer.h"
19 #include "src/core/SkScalerContext.h"
20 #include "src/core/SkStrikeCache.h"
21 #include "src/text/StrikeForGPU.h"
22 
23 #if defined(SK_GANESH)
24     #include "src/text/gpu/StrikeCache.h"
25 #endif
26 
27 using namespace skglyph;
28 
use_or_generate_metrics(const SkFontMetrics * metrics,SkScalerContext * context)29 static SkFontMetrics use_or_generate_metrics(
30         const SkFontMetrics* metrics, SkScalerContext* context) {
31     SkFontMetrics answer;
32     if (metrics) {
33         answer = *metrics;
34     } else {
35         context->getFontMetrics(&answer);
36     }
37     return answer;
38 }
39 
SkStrike(SkStrikeCache * strikeCache,const SkStrikeSpec & strikeSpec,std::unique_ptr<SkScalerContext> scaler,const SkFontMetrics * metrics,std::unique_ptr<SkStrikePinner> pinner)40 SkStrike::SkStrike(SkStrikeCache* strikeCache,
41                    const SkStrikeSpec& strikeSpec,
42                    std::unique_ptr<SkScalerContext> scaler,
43                    const SkFontMetrics* metrics,
44                    std::unique_ptr<SkStrikePinner> pinner)
45         : fFontMetrics{use_or_generate_metrics(metrics, scaler.get())}
46         , fRoundingSpec{scaler->isSubpixel(),
47                         scaler->computeAxisAlignmentForHText()}
48         , fStrikeSpec{strikeSpec}
49         , fStrikeCache{strikeCache}
50         , fScalerContext{std::move(scaler)}
51         , fPinner{std::move(pinner)} {
52     SkASSERT(fScalerContext != nullptr);
53 }
54 
55 class SK_SCOPED_CAPABILITY SkStrike::Monitor {
56 public:
57     Monitor(SkStrike* strike) SK_ACQUIRE(strike->fStrikeLock)
58             : fStrike{strike} {
59         fStrike->lock();
60     }
61 
SK_RELEASE_CAPABILITY()62     ~Monitor() SK_RELEASE_CAPABILITY() {
63         fStrike->unlock();
64     }
65 
66 private:
67     SkStrike* const fStrike;
68 };
69 
lock()70 void SkStrike::lock() {
71     fStrikeLock.acquire();
72     fMemoryIncrease = 0;
73 }
74 
unlock()75 void SkStrike::unlock() {
76     const size_t memoryIncrease = fMemoryIncrease;
77     fStrikeLock.release();
78     this->updateMemoryUsage(memoryIncrease);
79 }
80 
mergeGlyphAndImage(SkPackedGlyphID toID,const SkGlyph & fromGlyph)81 SkGlyph* SkStrike::mergeGlyphAndImage(SkPackedGlyphID toID, const SkGlyph& fromGlyph) {
82     Monitor m{this};
83     // TODO(herb): remove finding the glyph when setting the metrics and image are separated
84     SkGlyphDigest* digest = fDigestForPackedGlyphID.find(toID);
85     if (digest != nullptr) {
86         SkGlyph* glyph = fGlyphForIndex[digest->index()];
87         if (fromGlyph.setImageHasBeenCalled()) {
88             if (glyph->setImageHasBeenCalled()) {
89                 // Should never set an image on a glyph which already has an image.
90                 SkDEBUGFAIL("Re-adding image to existing glyph. This should not happen.");
91             }
92             // TODO: assert that any metrics on fromGlyph are the same.
93             fMemoryIncrease += glyph->setMetricsAndImage(&fAlloc, fromGlyph);
94         }
95         return glyph;
96     } else {
97         SkGlyph* glyph = fAlloc.make<SkGlyph>(toID);
98         fMemoryIncrease += glyph->setMetricsAndImage(&fAlloc, fromGlyph) + sizeof(SkGlyph);
99         (void)this->addGlyphAndDigest(glyph);
100         return glyph;
101     }
102 }
103 
mergePath(SkGlyph * glyph,const SkPath * path,bool hairline)104 const SkPath* SkStrike::mergePath(SkGlyph* glyph, const SkPath* path, bool hairline) {
105     Monitor m{this};
106     if (glyph->setPathHasBeenCalled()) {
107         SkDEBUGFAIL("Re-adding path to existing glyph. This should not happen.");
108     }
109     if (glyph->setPath(&fAlloc, path, hairline)) {
110         fMemoryIncrease += glyph->path()->approximateBytesUsed();
111     }
112 
113     return glyph->path();
114 }
115 
mergeDrawable(SkGlyph * glyph,sk_sp<SkDrawable> drawable)116 const SkDrawable* SkStrike::mergeDrawable(SkGlyph* glyph, sk_sp<SkDrawable> drawable) {
117     Monitor m{this};
118     if (glyph->setDrawableHasBeenCalled()) {
119         SkDEBUGFAIL("Re-adding drawable to existing glyph. This should not happen.");
120     }
121     if (glyph->setDrawable(&fAlloc, std::move(drawable))) {
122         fMemoryIncrease += glyph->drawable()->approximateBytesUsed();
123         SkASSERT(fMemoryIncrease > 0);
124     }
125 
126     return glyph->drawable();
127 }
128 
findIntercepts(const SkScalar bounds[2],SkScalar scale,SkScalar xPos,SkGlyph * glyph,SkScalar * array,int * count)129 void SkStrike::findIntercepts(const SkScalar bounds[2], SkScalar scale, SkScalar xPos,
130                               SkGlyph* glyph, SkScalar* array, int* count) {
131     SkAutoMutexExclusive lock{fStrikeLock};
132     glyph->ensureIntercepts(bounds, scale, xPos, array, count, &fAlloc);
133 }
134 
metrics(SkSpan<const SkGlyphID> glyphIDs,const SkGlyph * results[])135 SkSpan<const SkGlyph*> SkStrike::metrics(
136         SkSpan<const SkGlyphID> glyphIDs, const SkGlyph* results[]) {
137     Monitor m{this};
138     return this->internalPrepare(glyphIDs, kMetricsOnly, results);
139 }
140 
preparePaths(SkSpan<const SkGlyphID> glyphIDs,const SkGlyph * results[])141 SkSpan<const SkGlyph*> SkStrike::preparePaths(
142         SkSpan<const SkGlyphID> glyphIDs, const SkGlyph* results[]) {
143     Monitor m{this};
144     return this->internalPrepare(glyphIDs, kMetricsAndPath, results);
145 }
146 
prepareImages(SkSpan<const SkPackedGlyphID> glyphIDs,const SkGlyph * results[])147 SkSpan<const SkGlyph*> SkStrike::prepareImages(
148         SkSpan<const SkPackedGlyphID> glyphIDs, const SkGlyph* results[]) {
149     const SkGlyph** cursor = results;
150     Monitor m{this};
151     for (auto glyphID : glyphIDs) {
152         SkGlyph* glyph = this->glyph(glyphID);
153         this->prepareForImage(glyph);
154         *cursor++ = glyph;
155     }
156 
157     return {results, glyphIDs.size()};
158 }
159 
prepareDrawables(SkSpan<const SkGlyphID> glyphIDs,const SkGlyph * results[])160 SkSpan<const SkGlyph*> SkStrike::prepareDrawables(
161         SkSpan<const SkGlyphID> glyphIDs, const SkGlyph* results[]) {
162     const SkGlyph** cursor = results;
163     {
164         Monitor m{this};
165         for (auto glyphID : glyphIDs) {
166             SkGlyph* glyph = this->glyph(SkPackedGlyphID{glyphID});
167             this->prepareForDrawable(glyph);
168             *cursor++ = glyph;
169         }
170     }
171 
172     return {results, glyphIDs.size()};
173 }
174 
glyphIDsToPaths(SkSpan<sktext::IDOrPath> idsOrPaths)175 void SkStrike::glyphIDsToPaths(SkSpan<sktext::IDOrPath> idsOrPaths) {
176     Monitor m{this};
177     for (sktext::IDOrPath& idOrPath : idsOrPaths) {
178         SkGlyph* glyph = this->glyph(SkPackedGlyphID{idOrPath.fGlyphID});
179         this->prepareForPath(glyph);
180         new (&idOrPath.fPath) SkPath{*glyph->path()};
181     }
182 }
183 
glyphIDsToDrawables(SkSpan<sktext::IDOrDrawable> idsOrDrawables)184 void SkStrike::glyphIDsToDrawables(SkSpan<sktext::IDOrDrawable> idsOrDrawables) {
185     Monitor m{this};
186     for (sktext::IDOrDrawable& idOrDrawable : idsOrDrawables) {
187         SkGlyph* glyph = this->glyph(SkPackedGlyphID{idOrDrawable.fGlyphID});
188         this->prepareForDrawable(glyph);
189         SkASSERT(glyph->drawable() != nullptr);
190         idOrDrawable.fDrawable = glyph->drawable();
191     }
192 }
193 
dump() const194 void SkStrike::dump() const {
195     SkAutoMutexExclusive lock{fStrikeLock};
196     const SkTypeface* face = fScalerContext->getTypeface();
197     const SkScalerContextRec& rec = fScalerContext->getRec();
198     SkMatrix matrix;
199     rec.getSingleMatrix(&matrix);
200     matrix.preScale(SkScalarInvert(rec.fTextSize), SkScalarInvert(rec.fTextSize));
201     SkString name;
202     face->getFamilyName(&name);
203 
204     SkString msg;
205     SkFontStyle style = face->fontStyle();
206     msg.printf("cache typeface:%x %25s:(%d,%d,%d)\n %s glyphs:%3d",
207                face->uniqueID(), name.c_str(), style.weight(), style.width(), style.slant(),
208                rec.dump().c_str(), fDigestForPackedGlyphID.count());
209     SkDebugf("%s\n", msg.c_str());
210 }
211 
dumpMemoryStatistics(SkTraceMemoryDump * dump) const212 void SkStrike::dumpMemoryStatistics(SkTraceMemoryDump* dump) const {
213     SkAutoMutexExclusive lock{fStrikeLock};
214     const SkTypeface* face = fScalerContext->getTypeface();
215     const SkScalerContextRec& rec = fScalerContext->getRec();
216 
217     SkString fontName;
218     face->getFamilyName(&fontName);
219     // Replace all special characters with '_'.
220     for (size_t index = 0; index < fontName.size(); ++index) {
221         if (!std::isalnum(fontName[index])) {
222             fontName[index] = '_';
223         }
224     }
225 
226     SkString dumpName = SkStringPrintf("%s/%s_%d/%p",
227                                        SkStrikeCache::kGlyphCacheDumpName,
228                                        fontName.c_str(),
229                                        rec.fTypefaceID,
230                                        this);
231 
232     dump->dumpNumericValue(dumpName.c_str(), "size", "bytes", fMemoryUsed);
233     dump->dumpNumericValue(dumpName.c_str(),
234                            "glyph_count", "objects",
235                            fDigestForPackedGlyphID.count());
236     dump->setMemoryBacking(dumpName.c_str(), "malloc", nullptr);
237 }
238 
glyph(SkGlyphDigest digest)239 SkGlyph* SkStrike::glyph(SkGlyphDigest digest) {
240     return fGlyphForIndex[digest.index()];
241 }
242 
glyph(SkPackedGlyphID packedGlyphID)243 SkGlyph* SkStrike::glyph(SkPackedGlyphID packedGlyphID) {
244     SkGlyphDigest digest = this->digestFor(kDirectMask, packedGlyphID);
245     return this->glyph(digest);
246 }
247 
digestFor(ActionType actionType,SkPackedGlyphID packedGlyphID)248 SkGlyphDigest SkStrike::digestFor(ActionType actionType, SkPackedGlyphID packedGlyphID) {
249     SkGlyphDigest* digestPtr = fDigestForPackedGlyphID.find(packedGlyphID);
250     if (digestPtr != nullptr && digestPtr->actionFor(actionType) != GlyphAction::kUnset) {
251         return *digestPtr;
252     }
253 
254     SkGlyph* glyph;
255     if (digestPtr != nullptr) {
256         glyph = fGlyphForIndex[digestPtr->index()];
257     } else {
258         glyph = fAlloc.make<SkGlyph>(fScalerContext->makeGlyph(packedGlyphID, &fAlloc));
259         fMemoryIncrease += sizeof(SkGlyph);
260         digestPtr = this->addGlyphAndDigest(glyph);
261     }
262 
263     digestPtr->setActionFor(actionType, glyph, this);
264 
265     return *digestPtr;
266 }
267 
addGlyphAndDigest(SkGlyph * glyph)268 SkGlyphDigest* SkStrike::addGlyphAndDigest(SkGlyph* glyph) {
269     size_t index = fGlyphForIndex.size();
270     SkGlyphDigest digest = SkGlyphDigest{index, *glyph};
271     SkGlyphDigest* newDigest = fDigestForPackedGlyphID.set(glyph->getPackedID(), digest);
272     fGlyphForIndex.push_back(glyph);
273     return newDigest;
274 }
275 
prepareForImage(SkGlyph * glyph)276 bool SkStrike::prepareForImage(SkGlyph* glyph) {
277     if (glyph->setImage(&fAlloc, fScalerContext.get())) {
278         fMemoryIncrease += glyph->imageSize();
279     }
280     return glyph->image() != nullptr;
281 }
282 
prepareForPath(SkGlyph * glyph)283 bool SkStrike::prepareForPath(SkGlyph* glyph) {
284     if (glyph->setPath(&fAlloc, fScalerContext.get())) {
285         fMemoryIncrease += glyph->path()->approximateBytesUsed();
286     }
287     return glyph->path() !=nullptr;
288 }
289 
prepareForDrawable(SkGlyph * glyph)290 bool SkStrike::prepareForDrawable(SkGlyph* glyph) {
291     if (glyph->setDrawable(&fAlloc, fScalerContext.get())) {
292         size_t increase = glyph->drawable()->approximateBytesUsed();
293         SkASSERT(increase > 0);
294         fMemoryIncrease += increase;
295     }
296     return glyph->drawable() != nullptr;
297 }
298 
internalPrepare(SkSpan<const SkGlyphID> glyphIDs,PathDetail pathDetail,const SkGlyph ** results)299 SkSpan<const SkGlyph*> SkStrike::internalPrepare(
300         SkSpan<const SkGlyphID> glyphIDs, PathDetail pathDetail, const SkGlyph** results) {
301     const SkGlyph** cursor = results;
302     for (auto glyphID : glyphIDs) {
303         SkGlyph* glyph = this->glyph(SkPackedGlyphID{glyphID});
304         if (pathDetail == kMetricsAndPath) {
305             this->prepareForPath(glyph);
306         }
307         *cursor++ = glyph;
308     }
309 
310     return {results, glyphIDs.size()};
311 }
312 
updateMemoryUsage(size_t increase)313 void SkStrike::updateMemoryUsage(size_t increase) {
314     if (increase > 0) {
315         // fRemoved and the cache's total memory are managed under the cache's lock. This allows
316         // them to be accessed under LRU operation.
317         SkAutoMutexExclusive lock{fStrikeCache->fLock};
318         fMemoryUsed += increase;
319         if (!fRemoved) {
320             fStrikeCache->fTotalMemoryUsed += increase;
321         }
322     }
323 }
324