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