• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2014 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 "SkAdvancedTypefaceMetrics.h"
9 #include "SkBitmap.h"
10 #include "SkCanvas.h"
11 #include "SkDescriptor.h"
12 #include "SkFontDescriptor.h"
13 #include "SkGlyph.h"
14 #include "SkMakeUnique.h"
15 #include "SkMask.h"
16 #include "SkPaintPriv.h"
17 #include "SkScalerContext.h"
18 #include "SkTestScalerContext.h"
19 #include "SkTypefaceCache.h"
20 
SkTestFont(const SkTestFontData & fontData)21 SkTestFont::SkTestFont(const SkTestFontData& fontData)
22     : INHERITED()
23     , fCharCodes(fontData.fCharCodes)
24     , fCharCodesCount(fontData.fCharCodes ? fontData.fCharCodesCount : 0)
25     , fWidths(fontData.fWidths)
26     , fMetrics(fontData.fMetrics)
27     , fName(fontData.fName)
28     , fPaths(nullptr)
29 {
30     init(fontData.fPoints, fontData.fVerbs);
31 #ifdef SK_DEBUG
32     sk_bzero(fDebugBits, sizeof(fDebugBits));
33     sk_bzero(fDebugOverage, sizeof(fDebugOverage));
34 #endif
35 }
36 
~SkTestFont()37 SkTestFont::~SkTestFont() {
38     for (unsigned index = 0; index < fCharCodesCount; ++index) {
39         delete fPaths[index];
40     }
41     delete[] fPaths;
42 }
43 
44 #ifdef SK_DEBUG
45 
46 #include "SkMutex.h"
47 SK_DECLARE_STATIC_MUTEX(gUsedCharsMutex);
48 
49 #endif
50 
codeToIndex(SkUnichar charCode) const51 int SkTestFont::codeToIndex(SkUnichar charCode) const {
52 #ifdef SK_DEBUG  // detect missing test font data
53     {
54         SkAutoMutexAcquire ac(gUsedCharsMutex);
55         if (charCode >= ' ' && charCode <= '~') {
56             int bitOffset = charCode - ' ';
57             fDebugBits[bitOffset >> 3] |= 1 << (bitOffset & 7);
58         } else {
59             int index = 0;
60             while (fDebugOverage[index] != 0 && fDebugOverage[index] != charCode
61                     && index < (int) sizeof(fDebugOverage)) {
62                 ++index;
63             }
64             SkASSERT(index < (int) sizeof(fDebugOverage));
65             if (fDebugOverage[index] == 0) {
66                 fDebugOverage[index] = charCode;
67             }
68         }
69     }
70 #endif
71     for (unsigned index = 0; index < fCharCodesCount; ++index) {
72         if (fCharCodes[index] == (unsigned) charCode) {
73             return (int) index;
74         }
75     }
76 
77     SkDEBUGF(("missing '%c' (%d) from %s (weight %d, width %d, slant %d)\n",
78               (char) charCode, charCode, fDebugName,
79               fDebugStyle.weight(), fDebugStyle.width(), fDebugStyle.slant()));
80     return 0;
81 }
82 
init(const SkScalar * pts,const unsigned char * verbs)83 void SkTestFont::init(const SkScalar* pts, const unsigned char* verbs) {
84     fPaths = new SkPath* [fCharCodesCount];
85     for (unsigned index = 0; index < fCharCodesCount; ++index) {
86         SkPath* path = new SkPath;
87         SkPath::Verb verb;
88         while ((verb = (SkPath::Verb) *verbs++) != SkPath::kDone_Verb) {
89             switch (verb) {
90                 case SkPath::kMove_Verb:
91                     path->moveTo(pts[0], pts[1]);
92                     pts += 2;
93                     break;
94                 case SkPath::kLine_Verb:
95                     path->lineTo(pts[0], pts[1]);
96                     pts += 2;
97                     break;
98                 case SkPath::kQuad_Verb:
99                     path->quadTo(pts[0], pts[1], pts[2], pts[3]);
100                     pts += 4;
101                     break;
102                 case SkPath::kCubic_Verb:
103                     path->cubicTo(pts[0], pts[1], pts[2], pts[3], pts[4], pts[5]);
104                     pts += 6;
105                     break;
106                 case SkPath::kClose_Verb:
107                     path->close();
108                     break;
109                 default:
110                     SkDEBUGFAIL("bad verb");
111                     return;
112             }
113         }
114         // This should make SkPath::getBounds() queries threadsafe.
115         path->updateBoundsCache();
116         fPaths[index] = path;
117     }
118 }
119 
SkTestTypeface(sk_sp<SkTestFont> testFont,const SkFontStyle & style)120 SkTestTypeface::SkTestTypeface(sk_sp<SkTestFont> testFont, const SkFontStyle& style)
121     : SkTypeface(style, false)
122     , fTestFont(std::move(testFont)) {
123 }
124 
getAdvance(SkGlyph * glyph)125 void SkTestTypeface::getAdvance(SkGlyph* glyph) {
126     // TODO(benjaminwagner): Update users to use floats.
127     glyph->fAdvanceX = SkFixedToFloat(fTestFont->fWidths[glyph->getGlyphID()]);
128     glyph->fAdvanceY = 0;
129 }
130 
getFontMetrics(SkPaint::FontMetrics * metrics)131 void SkTestTypeface::getFontMetrics(SkPaint::FontMetrics* metrics) {
132     *metrics = fTestFont->fMetrics;
133 }
134 
getMetrics(SkGlyph * glyph)135 void SkTestTypeface::getMetrics(SkGlyph* glyph) {
136     // TODO(benjaminwagner): Update users to use floats.
137     glyph->fAdvanceX = SkFixedToFloat(fTestFont->fWidths[glyph->getGlyphID()]);
138     glyph->fAdvanceY = 0;
139 }
140 
getPath(SkGlyphID glyph,SkPath * path)141 void SkTestTypeface::getPath(SkGlyphID glyph, SkPath* path) {
142     *path = *fTestFont->fPaths[glyph];
143 }
144 
onFilterRec(SkScalerContextRec * rec) const145 void SkTestTypeface::onFilterRec(SkScalerContextRec* rec) const {
146     rec->setHinting(SkPaint::kNo_Hinting);
147 }
148 
onGetAdvancedTypefaceMetrics(PerGlyphInfo,const uint32_t * glyphIDs,uint32_t glyphIDsCount) const149 SkAdvancedTypefaceMetrics* SkTestTypeface::onGetAdvancedTypefaceMetrics(
150                                 PerGlyphInfo ,
151                                 const uint32_t* glyphIDs,
152                                 uint32_t glyphIDsCount) const {
153 // pdf only
154     SkAdvancedTypefaceMetrics* info = new SkAdvancedTypefaceMetrics;
155     info->fFontName.set(fTestFont->fName);
156     int glyphCount = this->onCountGlyphs();
157 
158     SkTDArray<SkUnichar>& toUnicode = info->fGlyphToUnicode;
159     toUnicode.setCount(glyphCount);
160     SkASSERT(glyphCount == SkToInt(fTestFont->fCharCodesCount));
161     for (int gid = 0; gid < glyphCount; ++gid) {
162         toUnicode[gid] = SkToS32(fTestFont->fCharCodes[gid]);
163     }
164     return info;
165 }
166 
onGetFontDescriptor(SkFontDescriptor * desc,bool * isLocal) const167 void SkTestTypeface::onGetFontDescriptor(SkFontDescriptor* desc, bool* isLocal) const {
168     desc->setFamilyName(fTestFont->fName);
169     desc->setStyle(this->fontStyle());
170     *isLocal = false;
171 }
172 
onCharsToGlyphs(const void * chars,Encoding encoding,uint16_t glyphs[],int glyphCount) const173 int SkTestTypeface::onCharsToGlyphs(const void* chars, Encoding encoding,
174                                     uint16_t glyphs[], int glyphCount) const {
175     SkASSERT(encoding == kUTF32_Encoding);
176     for (int index = 0; index < glyphCount; ++index) {
177         SkUnichar ch = ((SkUnichar*) chars)[index];
178         glyphs[index] = fTestFont->codeToIndex(ch);
179     }
180     return glyphCount;
181 }
182 
onGetFamilyName(SkString * familyName) const183 void SkTestTypeface::onGetFamilyName(SkString* familyName) const {
184     *familyName = fTestFont->fName;
185 }
186 
onCreateFamilyNameIterator() const187 SkTypeface::LocalizedStrings* SkTestTypeface::onCreateFamilyNameIterator() const {
188     SkString familyName(fTestFont->fName);
189     SkString language("und"); //undetermined
190 //SkASSERT(0);  // incomplete
191     return nullptr;
192 //     return new SkOTUtils::LocalizedStrings_SingleName(familyName, language);
193 }
194 
195 class SkTestScalerContext : public SkScalerContext {
196 public:
SkTestScalerContext(sk_sp<SkTestTypeface> face,const SkScalerContextEffects & effects,const SkDescriptor * desc)197     SkTestScalerContext(sk_sp<SkTestTypeface> face, const SkScalerContextEffects& effects,
198                         const SkDescriptor* desc)
199         : SkScalerContext(std::move(face), effects, desc)
200     {
201         fRec.getSingleMatrix(&fMatrix);
202         this->forceGenerateImageFromPath();
203     }
204 
205 protected:
getTestTypeface() const206     SkTestTypeface* getTestTypeface() const {
207         return static_cast<SkTestTypeface*>(this->getTypeface());
208     }
209 
generateGlyphCount()210     unsigned generateGlyphCount() override {
211         return this->getTestTypeface()->onCountGlyphs();
212     }
213 
generateCharToGlyph(SkUnichar uni)214     uint16_t generateCharToGlyph(SkUnichar uni) override {
215         uint16_t glyph;
216         (void) this->getTestTypeface()->onCharsToGlyphs((const void *) &uni,
217                                                         SkTypeface::kUTF32_Encoding, &glyph, 1);
218         return glyph;
219     }
220 
generateAdvance(SkGlyph * glyph)221     void generateAdvance(SkGlyph* glyph) override {
222         this->getTestTypeface()->getAdvance(glyph);
223 
224         const SkVector advance = fMatrix.mapXY(SkFloatToScalar(glyph->fAdvanceX),
225                                                SkFloatToScalar(glyph->fAdvanceY));
226         glyph->fAdvanceX = SkScalarToFloat(advance.fX);
227         glyph->fAdvanceY = SkScalarToFloat(advance.fY);
228     }
229 
generateMetrics(SkGlyph * glyph)230     void generateMetrics(SkGlyph* glyph) override {
231         this->getTestTypeface()->getMetrics(glyph);
232 
233         const SkVector advance = fMatrix.mapXY(SkFloatToScalar(glyph->fAdvanceX),
234                                                SkFloatToScalar(glyph->fAdvanceY));
235         glyph->fAdvanceX = SkScalarToFloat(advance.fX);
236         glyph->fAdvanceY = SkScalarToFloat(advance.fY);
237 
238         SkPath path;
239         this->getTestTypeface()->getPath(glyph->getGlyphID(), &path);
240         path.transform(fMatrix);
241 
242         SkRect storage;
243         const SkPaint paint;
244         const SkRect& newBounds = paint.doComputeFastBounds(path.getBounds(),
245                                                             &storage,
246                                                             SkPaint::kFill_Style);
247         SkIRect ibounds;
248         newBounds.roundOut(&ibounds);
249         glyph->fLeft = ibounds.fLeft;
250         glyph->fTop = ibounds.fTop;
251         glyph->fWidth = ibounds.width();
252         glyph->fHeight = ibounds.height();
253     }
254 
generateImage(const SkGlyph & glyph)255     void generateImage(const SkGlyph& glyph) override {
256         SkPath path;
257         this->getTestTypeface()->getPath(glyph.getGlyphID(), &path);
258 
259         SkBitmap bm;
260         bm.installPixels(SkImageInfo::MakeN32Premul(glyph.fWidth, glyph.fHeight),
261                             glyph.fImage, glyph.rowBytes());
262         bm.eraseColor(0);
263 
264         SkCanvas canvas(bm);
265         canvas.translate(-SkIntToScalar(glyph.fLeft),
266                             -SkIntToScalar(glyph.fTop));
267         canvas.concat(fMatrix);
268         SkPaint paint;
269         paint.setAntiAlias(true);
270         canvas.drawPath(path, paint);
271     }
272 
generatePath(SkGlyphID glyph,SkPath * path)273     void generatePath(SkGlyphID glyph, SkPath* path) override {
274         this->getTestTypeface()->getPath(glyph, path);
275         path->transform(fMatrix);
276     }
277 
generateFontMetrics(SkPaint::FontMetrics * metrics)278     void generateFontMetrics(SkPaint::FontMetrics* metrics) override {
279         this->getTestTypeface()->getFontMetrics(metrics);
280         SkPaintPriv::ScaleFontMetrics(metrics, fMatrix.getScaleY());
281     }
282 
283 private:
284     SkMatrix         fMatrix;
285 };
286 
onCreateScalerContext(const SkScalerContextEffects & effects,const SkDescriptor * desc) const287 SkScalerContext* SkTestTypeface::onCreateScalerContext(
288     const SkScalerContextEffects& effects, const SkDescriptor* desc) const
289 {
290     return new SkTestScalerContext(sk_ref_sp(const_cast<SkTestTypeface*>(this)), effects, desc);
291 }
292