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