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