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