• 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 "include/core/SkPaint.h"
9 #include "include/core/SkPath.h"
10 #include "include/core/SkTypeface.h"
11 #include "include/private/base/SkTemplates.h"
12 #include "include/private/base/SkTo.h"
13 #include "src/base/SkTLazy.h"
14 #include "src/base/SkUTF.h"
15 #include "src/base/SkUtils.h"
16 #include "src/core/SkDraw.h"
17 #include "src/core/SkFontPriv.h"
18 #include "src/core/SkMatrixPriv.h"
19 #include "src/core/SkPaintDefaults.h"
20 #include "src/core/SkScalerContext.h"
21 #include "src/core/SkStrike.h"
22 #include "src/core/SkStrikeCache.h"
23 #include "src/core/SkStrikeSpec.h"
24 
25 using namespace skia_private;
26 
27 #define kDefault_Size       SkPaintDefaults_TextSize
28 #define kDefault_Flags      SkFont::kBaselineSnap_PrivFlag
29 #define kDefault_Edging     SkFont::Edging::kAntiAlias
30 #define kDefault_Hinting    SkPaintDefaults_Hinting
31 
valid_size(SkScalar size)32 static inline SkScalar valid_size(SkScalar size) {
33     return std::max<SkScalar>(0, size);
34 }
35 
SkFont(sk_sp<SkTypeface> face,SkScalar size,SkScalar scaleX,SkScalar skewX)36 SkFont::SkFont(sk_sp<SkTypeface> face, SkScalar size, SkScalar scaleX, SkScalar skewX)
37     : fTypeface(std::move(face))
38     , fSize(valid_size(size))
39     , fScaleX(scaleX)
40     , fSkewX(skewX)
41     , fFlags(kDefault_Flags)
42     , fEdging(static_cast<unsigned>(kDefault_Edging))
43     , fHinting(static_cast<unsigned>(kDefault_Hinting))
44 {}
45 
SkFont(sk_sp<SkTypeface> face,SkScalar size)46 SkFont::SkFont(sk_sp<SkTypeface> face, SkScalar size) : SkFont(std::move(face), size, 1, 0) {}
47 
SkFont(sk_sp<SkTypeface> face)48 SkFont::SkFont(sk_sp<SkTypeface> face) : SkFont(std::move(face), kDefault_Size, 1, 0) {}
49 
SkFont()50 SkFont::SkFont() : SkFont(nullptr, kDefault_Size) {}
51 
operator ==(const SkFont & b) const52 bool SkFont::operator==(const SkFont& b) const {
53     return  fTypeface.get() == b.fTypeface.get() &&
54             fSize           == b.fSize &&
55             fScaleX         == b.fScaleX &&
56             fSkewX          == b.fSkewX &&
57             fFlags          == b.fFlags &&
58             fEdging         == b.fEdging &&
59             fHinting        == b.fHinting;
60 }
61 
dump() const62 void SkFont::dump() const {
63     SkDebugf("typeface %p\n", fTypeface.get());
64     SkDebugf("size %g\n", fSize);
65     SkDebugf("skewx %g\n", fSkewX);
66     SkDebugf("scalex %g\n", fScaleX);
67     SkDebugf("flags 0x%X\n", fFlags);
68     SkDebugf("edging %d\n", (unsigned)fEdging);
69     SkDebugf("hinting %d\n", (unsigned)fHinting);
70 }
71 
72 ///////////////////////////////////////////////////////////////////////////////////////////////////
73 
set_clear_mask(uint32_t bits,bool cond,uint32_t mask)74 static inline uint32_t set_clear_mask(uint32_t bits, bool cond, uint32_t mask) {
75     return cond ? bits | mask : bits & ~mask;
76 }
77 
setForceAutoHinting(bool predicate)78 void SkFont::setForceAutoHinting(bool predicate) {
79     fFlags = set_clear_mask(fFlags, predicate, kForceAutoHinting_PrivFlag);
80 }
setEmbeddedBitmaps(bool predicate)81 void SkFont::setEmbeddedBitmaps(bool predicate) {
82     fFlags = set_clear_mask(fFlags, predicate, kEmbeddedBitmaps_PrivFlag);
83 }
setSubpixel(bool predicate)84 void SkFont::setSubpixel(bool predicate) {
85     fFlags = set_clear_mask(fFlags, predicate, kSubpixel_PrivFlag);
86 }
setLinearMetrics(bool predicate)87 void SkFont::setLinearMetrics(bool predicate) {
88     fFlags = set_clear_mask(fFlags, predicate, kLinearMetrics_PrivFlag);
89 }
setEmbolden(bool predicate)90 void SkFont::setEmbolden(bool predicate) {
91     fFlags = set_clear_mask(fFlags, predicate, kEmbolden_PrivFlag);
92 }
setBaselineSnap(bool predicate)93 void SkFont::setBaselineSnap(bool predicate) {
94     fFlags = set_clear_mask(fFlags, predicate, kBaselineSnap_PrivFlag);
95 }
setEdging(Edging e)96 void SkFont::setEdging(Edging e) {
97     fEdging = SkToU8(e);
98 }
99 
setHinting(SkFontHinting h)100 void SkFont::setHinting(SkFontHinting h) {
101     fHinting = SkToU8(h);
102 }
103 
setSize(SkScalar size)104 void SkFont::setSize(SkScalar size) {
105     fSize = valid_size(size);
106 }
setScaleX(SkScalar scale)107 void SkFont::setScaleX(SkScalar scale) {
108     fScaleX = scale;
109 }
setSkewX(SkScalar skew)110 void SkFont::setSkewX(SkScalar skew) {
111     fSkewX = skew;
112 }
113 
makeWithSize(SkScalar newSize) const114 SkFont SkFont::makeWithSize(SkScalar newSize) const {
115     SkFont font = *this;
116     font.setSize(newSize);
117     return font;
118 }
119 
120 ///////////////////////////////////////////////////////////////////////////////////////////////////
121 
setupForAsPaths(SkPaint * paint)122 SkScalar SkFont::setupForAsPaths(SkPaint* paint) {
123     constexpr uint32_t flagsToIgnore = kEmbeddedBitmaps_PrivFlag |
124                                        kForceAutoHinting_PrivFlag;
125 
126     fFlags = (fFlags & ~flagsToIgnore) | kSubpixel_PrivFlag;
127     this->setHinting(SkFontHinting::kNone);
128 
129     if (this->getEdging() == Edging::kSubpixelAntiAlias) {
130         this->setEdging(Edging::kAntiAlias);
131     }
132 
133     if (paint) {
134         paint->setStyle(SkPaint::kFill_Style);
135         paint->setPathEffect(nullptr);
136     }
137     SkScalar textSize = fSize;
138     this->setSize(SkIntToScalar(SkFontPriv::kCanonicalTextSizeForPaths));
139     return textSize / SkFontPriv::kCanonicalTextSizeForPaths;
140 }
141 
hasSomeAntiAliasing() const142 bool SkFont::hasSomeAntiAliasing() const {
143     Edging edging = this->getEdging();
144     return edging == SkFont::Edging::kAntiAlias
145         || edging == SkFont::Edging::kSubpixelAntiAlias;
146 }
147 
unicharToGlyph(SkUnichar uni) const148 SkGlyphID SkFont::unicharToGlyph(SkUnichar uni) const {
149     return this->getTypefaceOrDefault()->unicharToGlyph(uni);
150 }
151 
unicharsToGlyphs(const SkUnichar uni[],int count,SkGlyphID glyphs[]) const152 void SkFont::unicharsToGlyphs(const SkUnichar uni[], int count, SkGlyphID glyphs[]) const {
153     this->getTypefaceOrDefault()->unicharsToGlyphs(uni, count, glyphs);
154 }
155 
textToGlyphs(const void * text,size_t byteLength,SkTextEncoding encoding,SkGlyphID glyphs[],int maxGlyphCount) const156 int SkFont::textToGlyphs(const void* text, size_t byteLength, SkTextEncoding encoding,
157                          SkGlyphID glyphs[], int maxGlyphCount) const {
158     return this->getTypefaceOrDefault()->textToGlyphs(text, byteLength, encoding,
159                                                       glyphs, maxGlyphCount);
160 }
161 
measureText(const void * text,size_t length,SkTextEncoding encoding,SkRect * bounds,const SkPaint * paint) const162 SkScalar SkFont::measureText(const void* text, size_t length, SkTextEncoding encoding,
163                              SkRect* bounds, const SkPaint* paint) const {
164 
165     SkAutoToGlyphs atg(*this, text, length, encoding);
166     const int glyphCount = atg.count();
167     if (glyphCount == 0) {
168         if (bounds) {
169             bounds->setEmpty();
170         }
171         return 0;
172     }
173     const SkGlyphID* glyphIDs = atg.glyphs();
174 
175     auto [strikeSpec, strikeToSourceScale] = SkStrikeSpec::MakeCanonicalized(*this, paint);
176     SkBulkGlyphMetrics metrics{strikeSpec};
177     SkSpan<const SkGlyph*> glyphs = metrics.glyphs(SkSpan(glyphIDs, glyphCount));
178 
179     SkScalar width = 0;
180     if (bounds) {
181         *bounds = glyphs[0]->rect();
182         width = glyphs[0]->advanceX();
183         for (int i = 1; i < glyphCount; ++i) {
184             SkRect r = glyphs[i]->rect();
185             r.offset(width, 0);
186             bounds->join(r);
187             width += glyphs[i]->advanceX();
188         }
189     } else {
190         for (auto glyph : glyphs) {
191             width += glyph->advanceX();
192         }
193     }
194 
195     if (strikeToSourceScale != 1) {
196         width *= strikeToSourceScale;
197         if (bounds) {
198             bounds->fLeft   *= strikeToSourceScale;
199             bounds->fTop    *= strikeToSourceScale;
200             bounds->fRight  *= strikeToSourceScale;
201             bounds->fBottom *= strikeToSourceScale;
202         }
203     }
204 
205     return width;
206 }
207 
getWidthsBounds(const SkGlyphID glyphIDs[],int count,SkScalar widths[],SkRect bounds[],const SkPaint * paint) const208 void SkFont::getWidthsBounds(const SkGlyphID glyphIDs[],
209                              int count,
210                              SkScalar widths[],
211                              SkRect bounds[],
212                              const SkPaint* paint) const {
213     auto [strikeSpec, strikeToSourceScale] = SkStrikeSpec::MakeCanonicalized(*this, paint);
214     SkBulkGlyphMetrics metrics{strikeSpec};
215     SkSpan<const SkGlyph*> glyphs = metrics.glyphs(SkSpan(glyphIDs, count));
216 
217     if (bounds) {
218         SkMatrix scaleMat = SkMatrix::Scale(strikeToSourceScale, strikeToSourceScale);
219         SkRect* cursor = bounds;
220         for (auto glyph : glyphs) {
221             scaleMat.mapRectScaleTranslate(cursor++, glyph->rect());
222         }
223     }
224 
225     if (widths) {
226         SkScalar* cursor = widths;
227         for (auto glyph : glyphs) {
228             *cursor++ = glyph->advanceX() * strikeToSourceScale;
229         }
230     }
231 }
232 
getPos(const SkGlyphID glyphIDs[],int count,SkPoint pos[],SkPoint origin) const233 void SkFont::getPos(const SkGlyphID glyphIDs[], int count, SkPoint pos[], SkPoint origin) const {
234     auto [strikeSpec, strikeToSourceScale] = SkStrikeSpec::MakeCanonicalized(*this);
235     SkBulkGlyphMetrics metrics{strikeSpec};
236     SkSpan<const SkGlyph*> glyphs = metrics.glyphs(SkSpan(glyphIDs, count));
237 
238     SkPoint sum = origin;
239     for (auto glyph : glyphs) {
240         *pos++ = sum;
241         sum += glyph->advanceVector() * strikeToSourceScale;
242     }
243 }
244 
getXPos(const SkGlyphID glyphIDs[],int count,SkScalar xpos[],SkScalar origin) const245 void SkFont::getXPos(
246         const SkGlyphID glyphIDs[], int count, SkScalar xpos[], SkScalar origin) const {
247 
248     auto [strikeSpec, strikeToSourceScale] = SkStrikeSpec::MakeCanonicalized(*this);
249     SkBulkGlyphMetrics metrics{strikeSpec};
250     SkSpan<const SkGlyph*> glyphs = metrics.glyphs(SkSpan(glyphIDs, count));
251 
252     SkScalar loc = origin;
253     SkScalar* cursor = xpos;
254     for (auto glyph : glyphs) {
255         *cursor++ = loc;
256         loc += glyph->advanceX() * strikeToSourceScale;
257     }
258 }
259 
getPaths(const SkGlyphID glyphIDs[],int count,void (* proc)(const SkPath *,const SkMatrix &,void *),void * ctx) const260 void SkFont::getPaths(const SkGlyphID glyphIDs[], int count,
261                       void (*proc)(const SkPath*, const SkMatrix&, void*), void* ctx) const {
262     SkFont font(*this);
263     SkScalar scale = font.setupForAsPaths(nullptr);
264     const SkMatrix mx = SkMatrix::Scale(scale, scale);
265 
266     SkStrikeSpec strikeSpec = SkStrikeSpec::MakeWithNoDevice(font);
267     SkBulkGlyphMetricsAndPaths paths{strikeSpec};
268     SkSpan<const SkGlyph*> glyphs = paths.glyphs(SkSpan(glyphIDs, count));
269 
270     for (auto glyph : glyphs) {
271         proc(glyph->path(), mx, ctx);
272     }
273 }
274 
getPath(SkGlyphID glyphID,SkPath * path) const275 bool SkFont::getPath(SkGlyphID glyphID, SkPath* path) const {
276     struct Pair {
277         SkPath* fPath;
278         bool    fWasSet;
279     } pair = { path, false };
280 
281     this->getPaths(&glyphID, 1, [](const SkPath* orig, const SkMatrix& mx, void* ctx) {
282         Pair* pair = static_cast<Pair*>(ctx);
283         if (orig) {
284             orig->transform(mx, pair->fPath);
285             pair->fWasSet = true;
286         }
287     }, &pair);
288     return pair.fWasSet;
289 }
290 
getMetrics(SkFontMetrics * metrics) const291 SkScalar SkFont::getMetrics(SkFontMetrics* metrics) const {
292 
293     auto [strikeSpec, strikeToSourceScale] = SkStrikeSpec::MakeCanonicalized(*this, nullptr);
294 
295     SkFontMetrics storage;
296     if (nullptr == metrics) {
297         metrics = &storage;
298     }
299 
300     auto cache = strikeSpec.findOrCreateStrike();
301     *metrics = cache->getFontMetrics();
302 
303     if (strikeToSourceScale != 1) {
304         SkFontPriv::ScaleFontMetrics(metrics, strikeToSourceScale);
305     }
306     return metrics->fDescent - metrics->fAscent + metrics->fLeading;
307 }
308 
getTypefaceOrDefault() const309 SkTypeface* SkFont::getTypefaceOrDefault() const {
310     return fTypeface ? fTypeface.get() : SkTypeface::GetDefaultTypeface();
311 }
312 
refTypefaceOrDefault() const313 sk_sp<SkTypeface> SkFont::refTypefaceOrDefault() const {
314     return fTypeface ? fTypeface : SkTypeface::MakeDefault();
315 }
316 
317 //////////////////////////////////////////////////////////////////////////////////////////////////
318 
ScaleFontMetrics(SkFontMetrics * metrics,SkScalar scale)319 void SkFontPriv::ScaleFontMetrics(SkFontMetrics* metrics, SkScalar scale) {
320     metrics->fTop *= scale;
321     metrics->fAscent *= scale;
322     metrics->fDescent *= scale;
323     metrics->fBottom *= scale;
324     metrics->fLeading *= scale;
325     metrics->fAvgCharWidth *= scale;
326     metrics->fMaxCharWidth *= scale;
327     metrics->fXMin *= scale;
328     metrics->fXMax *= scale;
329     metrics->fXHeight *= scale;
330     metrics->fCapHeight *= scale;
331     metrics->fUnderlineThickness *= scale;
332     metrics->fUnderlinePosition *= scale;
333     metrics->fStrikeoutThickness *= scale;
334     metrics->fStrikeoutPosition *= scale;
335 }
336 
GetFontBounds(const SkFont & font)337 SkRect SkFontPriv::GetFontBounds(const SkFont& font) {
338     SkMatrix m;
339     m.setScale(font.getSize() * font.getScaleX(), font.getSize());
340     m.postSkew(font.getSkewX(), 0);
341 
342     SkTypeface* typeface = font.getTypefaceOrDefault();
343 
344     SkRect bounds;
345     m.mapRect(&bounds, typeface->getBounds());
346     return bounds;
347 }
348 
ApproximateTransformedTextSize(const SkFont & font,const SkMatrix & matrix,const SkPoint & textLocation)349 SkScalar SkFontPriv::ApproximateTransformedTextSize(const SkFont& font, const SkMatrix& matrix,
350                                                     const SkPoint& textLocation) {
351     if (!matrix.hasPerspective()) {
352         return font.getSize() * matrix.getMaxScale();
353     } else {
354         // approximate the scale since we can't get it directly from the matrix
355         SkScalar maxScaleSq = SkMatrixPriv::DifferentialAreaScale(matrix, textLocation);
356         if (SkScalarIsFinite(maxScaleSq) && !SkScalarNearlyZero(maxScaleSq)) {
357             return font.getSize() * SkScalarSqrt(maxScaleSq);
358         } else {
359             return -font.getSize();
360         }
361     }
362 }
363 
CountTextElements(const void * text,size_t byteLength,SkTextEncoding encoding)364 int SkFontPriv::CountTextElements(const void* text, size_t byteLength, SkTextEncoding encoding) {
365     switch (encoding) {
366         case SkTextEncoding::kUTF8:
367             return SkUTF::CountUTF8(reinterpret_cast<const char*>(text), byteLength);
368         case SkTextEncoding::kUTF16:
369             return SkUTF::CountUTF16(reinterpret_cast<const uint16_t*>(text), byteLength);
370         case SkTextEncoding::kUTF32:
371             return byteLength >> 2;
372         case SkTextEncoding::kGlyphID:
373             return byteLength >> 1;
374     }
375     SkASSERT(false);
376     return 0;
377 }
378 
GlyphsToUnichars(const SkFont & font,const SkGlyphID glyphs[],int count,SkUnichar text[])379 void SkFontPriv::GlyphsToUnichars(const SkFont& font, const SkGlyphID glyphs[], int count,
380                                   SkUnichar text[]) {
381     if (count <= 0) {
382         return;
383     }
384 
385     auto typeface = font.getTypefaceOrDefault();
386     const unsigned numGlyphsInTypeface = typeface->countGlyphs();
387     AutoTArray<SkUnichar> unichars(numGlyphsInTypeface);
388     typeface->getGlyphToUnicodeMap(unichars.get());
389 
390     for (int i = 0; i < count; ++i) {
391         unsigned id = glyphs[i];
392         text[i] = (id < numGlyphsInTypeface) ? unichars[id] : 0xFFFD;
393     }
394 }
395