• 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/SkGraphics.h"
11 #include "include/core/SkPath.h"
12 #include "include/core/SkTypeface.h"
13 #include "include/private/SkMutex.h"
14 #include "include/private/SkOnce.h"
15 #include "include/private/SkTemplates.h"
16 #include "src/core/SkMakeUnique.h"
17 #include <cctype>
18 
SkStrike(const SkDescriptor & desc,std::unique_ptr<SkScalerContext> scaler,const SkFontMetrics & fontMetrics)19 SkStrike::SkStrike(
20     const SkDescriptor& desc,
21     std::unique_ptr<SkScalerContext> scaler,
22     const SkFontMetrics& fontMetrics)
23     : fDesc{desc}
24     , fScalerContext{std::move(scaler)}
25     , fFontMetrics{fontMetrics}
26     , fIsSubpixel{fScalerContext->isSubpixel()}
27     , fAxisAlignment{fScalerContext->computeAxisAlignmentForHText()}
28 {
29     SkASSERT(fScalerContext != nullptr);
30     fMemoryUsed = sizeof(*this);
31 }
32 
33 #ifdef SK_DEBUG
34 #define VALIDATE()  AutoValidate av(this)
35 #else
36 #define VALIDATE()
37 #endif
38 
39 // -- glyph creation -------------------------------------------------------------------------------
makeGlyph(SkPackedGlyphID packedGlyphID)40 SkGlyph* SkStrike::makeGlyph(SkPackedGlyphID packedGlyphID) {
41     fMemoryUsed += sizeof(SkGlyph);
42     SkGlyph* glyph = fAlloc.make<SkGlyph>(packedGlyphID);
43     fGlyphMap.set(glyph);
44     return glyph;
45 }
46 
glyph(SkPackedGlyphID packedGlyphID)47 SkGlyph* SkStrike::glyph(SkPackedGlyphID packedGlyphID) {
48     VALIDATE();
49     SkGlyph* glyph = fGlyphMap.findOrNull(packedGlyphID);
50     if (glyph == nullptr) {
51         glyph = this->makeGlyph(packedGlyphID);
52         fScalerContext->getMetrics(glyph);
53     }
54     return glyph;
55 }
56 
glyph(SkGlyphID glyphID)57 SkGlyph* SkStrike::glyph(SkGlyphID glyphID) {
58     return this->glyph(SkPackedGlyphID{glyphID});
59 }
60 
glyph(SkGlyphID glyphID,SkPoint position)61 SkGlyph* SkStrike::glyph(SkGlyphID glyphID, SkPoint position) {
62     const SkFixed maskX = (!fIsSubpixel || fAxisAlignment == kY_SkAxisAlignment) ? 0 : ~0;
63     const SkFixed maskY = (!fIsSubpixel || fAxisAlignment == kX_SkAxisAlignment) ? 0 : ~0;
64     SkFixed subX = SkScalarToFixed(position.x()) & maskX,
65             subY = SkScalarToFixed(position.y()) & maskY;
66     return this->glyph(SkPackedGlyphID{glyphID, subX, subY});
67 }
68 
glyphFromPrototype(const SkGlyphPrototype & p,void * image)69 SkGlyph* SkStrike::glyphFromPrototype(const SkGlyphPrototype& p, void* image) {
70     SkGlyph* glyph = fGlyphMap.findOrNull(p.id);
71     if (glyph == nullptr) {
72         fMemoryUsed += sizeof(SkGlyph);
73         glyph = fAlloc.make<SkGlyph>(p);
74         fGlyphMap.set(glyph);
75     }
76     if (glyph->setImage(&fAlloc, image)) {
77         fMemoryUsed += glyph->imageSize();
78     }
79     return glyph;
80 }
81 
glyphOrNull(SkPackedGlyphID id) const82 SkGlyph* SkStrike::glyphOrNull(SkPackedGlyphID id) const {
83     return fGlyphMap.findOrNull(id);
84 }
85 
preparePath(SkGlyph * glyph)86 const SkPath* SkStrike::preparePath(SkGlyph* glyph) {
87     if (glyph->setPath(&fAlloc, fScalerContext.get())) {
88         fMemoryUsed += glyph->path()->approximateBytesUsed();
89     }
90     return glyph->path();
91 }
92 
preparePath(SkGlyph * glyph,const SkPath * path)93 const SkPath* SkStrike::preparePath(SkGlyph* glyph, const SkPath* path) {
94     if (glyph->setPath(&fAlloc, path)) {
95         fMemoryUsed += glyph->path()->approximateBytesUsed();
96     }
97     return glyph->path();
98 }
99 
getDescriptor() const100 const SkDescriptor& SkStrike::getDescriptor() const {
101     return *fDesc.getDesc();
102 }
103 
getGlyphCount() const104 unsigned SkStrike::getGlyphCount() const {
105     return fScalerContext->getGlyphCount();
106 }
107 
countCachedGlyphs() const108 int SkStrike::countCachedGlyphs() const {
109     return fGlyphMap.count();
110 }
111 
internalPrepare(SkSpan<const SkGlyphID> glyphIDs,PathDetail pathDetail,const SkGlyph ** results)112 SkSpan<const SkGlyph*> SkStrike::internalPrepare(
113         SkSpan<const SkGlyphID> glyphIDs, PathDetail pathDetail, const SkGlyph** results) {
114     const SkGlyph** cursor = results;
115     for (auto glyphID : glyphIDs) {
116         SkGlyph* glyphPtr = this->glyph(glyphID);
117         if (pathDetail == kMetricsAndPath) {
118             this->preparePath(glyphPtr);
119         }
120         *cursor++ = glyphPtr;
121     }
122 
123     return {results, glyphIDs.size()};
124 }
125 
prepareImage(SkGlyph * glyph)126 const void* SkStrike::prepareImage(SkGlyph* glyph) {
127     if (glyph->setImage(&fAlloc, fScalerContext.get())) {
128         fMemoryUsed += glyph->imageSize();
129     }
130     return glyph->image();
131 }
132 
mergeGlyphAndImage(SkPackedGlyphID toID,const SkGlyph & from)133 SkGlyph* SkStrike::mergeGlyphAndImage(SkPackedGlyphID toID, const SkGlyph& from) {
134     SkGlyph* glyph = fGlyphMap.findOrNull(toID);
135     if (glyph == nullptr) {
136         glyph = this->makeGlyph(toID);
137     }
138     if (glyph->setMetricsAndImage(&fAlloc, from)) {
139         fMemoryUsed += glyph->imageSize();
140     }
141     return glyph;
142 }
143 
belongsToCache(const SkGlyph * glyph) const144 bool SkStrike::belongsToCache(const SkGlyph* glyph) const {
145     return glyph && fGlyphMap.findOrNull(glyph->getPackedID()) == glyph;
146 }
147 
getCachedGlyphAnySubPix(SkGlyphID glyphID,SkPackedGlyphID vetoID) const148 const SkGlyph* SkStrike::getCachedGlyphAnySubPix(SkGlyphID glyphID,
149                                                      SkPackedGlyphID vetoID) const {
150     for (SkFixed subY = 0; subY < SK_Fixed1; subY += SK_FixedQuarter) {
151         for (SkFixed subX = 0; subX < SK_Fixed1; subX += SK_FixedQuarter) {
152             SkPackedGlyphID packedGlyphID{glyphID, subX, subY};
153             if (packedGlyphID == vetoID) continue;
154             if (SkGlyph* glyphPtr = fGlyphMap.findOrNull(packedGlyphID)) {
155                 return glyphPtr;
156             }
157         }
158     }
159 
160     return nullptr;
161 }
162 
rounding() const163 SkVector SkStrike::rounding() const {
164     return SkStrikeCommon::PixelRounding(fIsSubpixel, fAxisAlignment);
165 }
166 
metrics(SkSpan<const SkGlyphID> glyphIDs,const SkGlyph * results[])167 SkSpan<const SkGlyph*> SkStrike::metrics(SkSpan<const SkGlyphID> glyphIDs,
168                                          const SkGlyph* results[]) {
169     return this->internalPrepare(glyphIDs, kMetricsOnly, results);
170 }
171 
preparePaths(SkSpan<const SkGlyphID> glyphIDs,const SkGlyph * results[])172 SkSpan<const SkGlyph*> SkStrike::preparePaths(SkSpan<const SkGlyphID> glyphIDs,
173                                               const SkGlyph* results[]) {
174     return this->internalPrepare(glyphIDs, kMetricsAndPath, results);
175 }
176 
177 SkSpan<const SkGlyph*>
prepareImages(SkSpan<const SkPackedGlyphID> glyphIDs,const SkGlyph * results[])178 SkStrike::prepareImages(SkSpan<const SkPackedGlyphID> glyphIDs, const SkGlyph* results[]) {
179     const SkGlyph** cursor = results;
180     for (auto glyphID : glyphIDs) {
181         SkGlyph* glyphPtr = this->glyph(glyphID);
182         (void)this->prepareImage(glyphPtr);
183         *cursor++ = glyphPtr;
184     }
185 
186     return {results, glyphIDs.size()};
187 }
188 
189 // N.B. This glyphMetrics call culls all the glyphs which will not display based on a non-finite
190 // position or that there are no mask pixels.
191 SkSpan<const SkGlyphPos>
prepareForDrawingRemoveEmpty(const SkPackedGlyphID packedGlyphIDs[],const SkPoint positions[],size_t n,int maxDimension,PreparationDetail detail,SkGlyphPos results[])192 SkStrike::prepareForDrawingRemoveEmpty(const SkPackedGlyphID packedGlyphIDs[],
193                                        const SkPoint positions[],
194                                        size_t n,
195                                        int maxDimension,
196                                        PreparationDetail detail,
197                                        SkGlyphPos results[]) {
198     size_t drawableGlyphCount = 0;
199     for (size_t i = 0; i < n; i++) {
200         SkPoint pos = positions[i];
201         if (SkScalarsAreFinite(pos.x(), pos.y())) {
202             SkGlyph* glyphPtr = this->glyph(packedGlyphIDs[i]);
203             if (!glyphPtr->isEmpty()) {
204                 results[drawableGlyphCount++] = {i, glyphPtr, pos};
205                 if (glyphPtr->maxDimension() <= maxDimension) {
206                     // The glyph fits; ensure the image if needed.
207                     if (detail == SkStrikeInterface::kImageIfNeeded) {
208                         this->prepareImage(glyphPtr);
209                     }
210                 } else if (!glyphPtr->isColor()) {
211                     // The out of atlas glyph is not color so we can draw it using paths.
212                     this->preparePath(glyphPtr);
213                 } else {
214                     // This will be handled by the fallback strike.
215                     SkASSERT(glyphPtr->maxDimension() > maxDimension && glyphPtr->isColor());
216                 }
217             }
218         }
219     }
220 
221     return SkSpan<const SkGlyphPos>{results, drawableGlyphCount};
222 }
223 
findIntercepts(const SkScalar bounds[2],SkScalar scale,SkScalar xPos,SkGlyph * glyph,SkScalar * array,int * count)224 void SkStrike::findIntercepts(const SkScalar bounds[2], SkScalar scale, SkScalar xPos,
225         SkGlyph* glyph, SkScalar* array, int* count) {
226     glyph->ensureIntercepts(bounds, scale, xPos, array, count, &fAlloc);
227 }
228 
dump() const229 void SkStrike::dump() const {
230     const SkTypeface* face = fScalerContext->getTypeface();
231     const SkScalerContextRec& rec = fScalerContext->getRec();
232     SkMatrix matrix;
233     rec.getSingleMatrix(&matrix);
234     matrix.preScale(SkScalarInvert(rec.fTextSize), SkScalarInvert(rec.fTextSize));
235     SkString name;
236     face->getFamilyName(&name);
237 
238     SkString msg;
239     SkFontStyle style = face->fontStyle();
240     msg.printf("cache typeface:%x %25s:(%d,%d,%d)\n %s glyphs:%3d",
241                face->uniqueID(), name.c_str(), style.weight(), style.width(), style.slant(),
242                rec.dump().c_str(), fGlyphMap.count());
243     SkDebugf("%s\n", msg.c_str());
244 }
245 
onAboutToExitScope()246 void SkStrike::onAboutToExitScope() { }
247 
248 #ifdef SK_DEBUG
forceValidate() const249 void SkStrike::forceValidate() const {
250     size_t memoryUsed = sizeof(*this);
251     fGlyphMap.foreach ([&memoryUsed](const SkGlyph* glyphPtr) {
252         memoryUsed += sizeof(SkGlyph);
253         if (glyphPtr->setImageHasBeenCalled()) {
254             memoryUsed += glyphPtr->imageSize();
255         }
256         if (glyphPtr->setPathHasBeenCalled() && glyphPtr->path() != nullptr) {
257             memoryUsed += glyphPtr->path()->approximateBytesUsed();
258         }
259     });
260     SkASSERT(fMemoryUsed == memoryUsed);
261 }
262 
validate() const263 void SkStrike::validate() const {
264 #ifdef SK_DEBUG_GLYPH_CACHE
265     forceValidate();
266 #endif
267 }
268 #endif  // SK_DEBUG
269 
270 
271