Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
SkFontHost_FreeType.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2006 The Android Open Source Project
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
11#include "include/core/SkData.h"
15#include "include/core/SkPath.h"
26#include "src/base/SkTSearch.h"
29#include "src/core/SkFDot6.h"
32#include "src/core/SkGlyph.h"
33#include "src/core/SkMask.h"
38#include "src/sfnt/SkOTUtils.h"
43
44#include <memory>
45#include <optional>
46#include <tuple>
47
48#include <ft2build.h>
49#include <freetype/ftadvanc.h>
50#include <freetype/ftimage.h>
51#include <freetype/ftbitmap.h>
52#ifdef FT_COLOR_H // 2.10.0
53# include <freetype/ftcolor.h>
54#endif
55#include <freetype/freetype.h>
56#include <freetype/ftlcdfil.h>
57#include <freetype/ftmodapi.h>
58#include <freetype/ftmm.h>
59#include <freetype/ftoutln.h>
60#include <freetype/ftsizes.h>
61#include <freetype/ftsystem.h>
62#include <freetype/tttables.h>
63#include <freetype/t1tables.h>
64#include <freetype/ftfntfmt.h>
65
66using namespace skia_private;
67
68namespace {
69[[maybe_unused]] static inline const constexpr bool kSkShowTextBlitCoverage = false;
70
71using SkUniqueFTFace = std::unique_ptr<FT_FaceRec, SkFunctionObject<FT_Done_Face>>;
72using SkUniqueFTSize = std::unique_ptr<FT_SizeRec, SkFunctionObject<FT_Done_Size>>;
73}
74
75// SK_FREETYPE_MINIMUM_RUNTIME_VERSION 0x<major><minor><patch><flags>
76// Flag SK_FREETYPE_DLOPEN: also try dlopen to get newer features.
77#define SK_FREETYPE_DLOPEN (0x1)
78#ifndef SK_FREETYPE_MINIMUM_RUNTIME_VERSION
79# if defined(SK_BUILD_FOR_ANDROID_FRAMEWORK) || \
80 defined(SK_BUILD_FOR_GOOGLE3) || \
81 defined(SK_FREETYPE_MINIMUM_RUNTIME_VERSION_IS_BUILD_VERSION)
82# define SK_FREETYPE_MINIMUM_RUNTIME_VERSION (((FREETYPE_MAJOR) << 24) | ((FREETYPE_MINOR) << 16) | ((FREETYPE_PATCH) << 8))
83# else
84# define SK_FREETYPE_MINIMUM_RUNTIME_VERSION ((2 << 24) | (8 << 16) | (1 << 8) | (SK_FREETYPE_DLOPEN))
85# endif
86#endif
87#if SK_FREETYPE_MINIMUM_RUNTIME_VERSION & SK_FREETYPE_DLOPEN
88# include <dlfcn.h>
89#endif
90
91#ifdef TT_SUPPORT_COLRV1
92// FT_ClipBox and FT_Get_Color_Glyph_ClipBox introduced VER-2-11-0-18-g47cf8ebf4
93// FT_COLR_COMPOSITE_PLUS and renumbering introduced VER-2-11-0-21-ge40ae7569
94// FT_SIZEOF_LONG_LONG introduced VER-2-11-0-31-gffdac8d67
95// FT_PaintRadialGradient changed size and layout at VER-2-11-0-147-gd3d3ff76d
96// FT_STATIC_CAST introduced VER-2-11-0-172-g9079c5d91
97// So undefine TT_SUPPORT_COLRV1 before 2.11.1 but not if FT_STATIC_CAST is defined.
98#if (((FREETYPE_MAJOR) < 2) || \
99 ((FREETYPE_MAJOR) == 2 && (FREETYPE_MINOR) < 11) || \
100 ((FREETYPE_MAJOR) == 2 && (FREETYPE_MINOR) == 11 && (FREETYPE_PATCH) < 1)) && \
101 !defined(FT_STATIC_CAST)
102# undef TT_SUPPORT_COLRV1
103#endif
104#endif
105
106//#define ENABLE_GLYPH_SPEW // for tracing calls
107//#define DUMP_STRIKE_CREATION
108//#define SK_FONTHOST_FREETYPE_RUNTIME_VERSION
109//#define SK_GAMMA_APPLY_TO_A8
110
111#if 1
112 #define LOG_INFO(...)
113#else
114 #define LOG_INFO SkDEBUGF
115#endif
116
117static bool isLCD(const SkScalerContextRec& rec) {
119}
120
121static SkScalar SkFT_FixedToScalar(FT_Fixed x) {
122 return SkFixedToScalar(x);
123}
124
125//////////////////////////////////////////////////////////////////////////
126
128static_assert(std::is_same<FT_Alloc_size_t, long >::value ||
129 std::is_same<FT_Alloc_size_t, size_t>::value,"");
130
131extern "C" {
132 static void* sk_ft_alloc(FT_Memory, FT_Alloc_size_t size) {
133 return sk_malloc_canfail(size);
134 }
135 static void sk_ft_free(FT_Memory, void* block) {
136 sk_free(block);
137 }
138 static void* sk_ft_realloc(FT_Memory, FT_Alloc_size_t cur_size,
139 FT_Alloc_size_t new_size, void* block) {
140 return sk_realloc_throw(block, new_size);
141 }
142}
143FT_MemoryRec_ gFTMemory = { nullptr, sk_ft_alloc, sk_ft_free, sk_ft_realloc };
144
146public:
147 FreeTypeLibrary() : fLibrary(nullptr) {
148 if (FT_New_Library(&gFTMemory, &fLibrary)) {
149 return;
150 }
151 FT_Add_Default_Modules(fLibrary);
152 FT_Set_Default_Properties(fLibrary);
153
154 // Subpixel anti-aliasing may be unfiltered until the LCD filter is set.
155 // Newer versions may still need this, so this test with side effects must come first.
156 // The default has changed over time, so this doesn't mean the same thing to all users.
157 FT_Library_SetLcdFilter(fLibrary, FT_LCD_FILTER_DEFAULT);
158 }
160 if (fLibrary) {
161 FT_Done_Library(fLibrary);
162 }
163 }
164
165 FT_Library library() { return fLibrary; }
166
167private:
168 FT_Library fLibrary;
169
170 // FT_Library_SetLcdFilterWeights 2.4.0
171 // FT_LOAD_COLOR 2.5.0
172 // FT_Pixel_Mode::FT_PIXEL_MODE_BGRA 2.5.0
173 // Thread safety in 2.6.0
174 // freetype/ftfntfmt.h (rename) 2.6.0
175 // Direct header inclusion 2.6.1
176 // FT_Get_Var_Design_Coordinates 2.7.1
177 // FT_LOAD_BITMAP_METRICS_ONLY 2.7.1
178 // FT_Set_Default_Properties 2.7.2
179 // The 'light' hinting is vertical only from 2.8.0
180 // FT_Get_Var_Axis_Flags 2.8.1
181 // FT_VAR_AXIS_FLAG_HIDDEN was introduced in FreeType 2.8.1
182 // --------------------
183 // FT_Done_MM_Var 2.9.0 (Currenty setting ft_free to a known allocator.)
184 // freetype/ftcolor.h 2.10.0 (Currently assuming if compiled with FT_COLOR_H runtime available.)
185
186 // Ubuntu 18.04 2.8.1
187 // Debian 10 2.9.1
188 // openSUSE Leap 15.2 2.10.1
189 // Fedora 32 2.10.4
190 // RHEL 8 2.9.1
191};
192
193static SkMutex& f_t_mutex() {
194 static SkMutex& mutex = *(new SkMutex);
195 return mutex;
196}
197
199
200///////////////////////////////////////////////////////////////////////////
201
203public:
204 SkUniqueFTFace fFace;
205 FT_StreamRec fFTStream;
206 std::unique_ptr<SkStreamAsset> fSkStream;
207 FT_UShort fFTPaletteEntryCount = 0;
208 std::unique_ptr<SkColor[]> fSkPalette;
209
210 static std::unique_ptr<FaceRec> Make(const SkTypeface_FreeType* typeface);
211 ~FaceRec();
212
213private:
214 FaceRec(std::unique_ptr<SkStreamAsset> stream);
215 void setupAxes(const SkFontData& data);
216 void setupPalette(const SkFontData& data);
217
218 // Private to ref_ft_library and unref_ft_library
219 static int gFTCount;
220
221 // Caller must lock f_t_mutex() before calling this function.
222 static bool ref_ft_library() {
223 f_t_mutex().assertHeld();
224 SkASSERT(gFTCount >= 0);
225
226 if (0 == gFTCount) {
227 SkASSERT(nullptr == gFTLibrary);
229 }
230 ++gFTCount;
231 return gFTLibrary->library();
232 }
233
234 // Caller must lock f_t_mutex() before calling this function.
235 static void unref_ft_library() {
236 f_t_mutex().assertHeld();
237 SkASSERT(gFTCount > 0);
238
239 --gFTCount;
240 if (0 == gFTCount) {
241 SkASSERT(nullptr != gFTLibrary);
242 delete gFTLibrary;
243 SkDEBUGCODE(gFTLibrary = nullptr;)
244 }
245 }
246};
247int SkTypeface_FreeType::FaceRec::gFTCount;
248
249extern "C" {
250 static unsigned long sk_ft_stream_io(FT_Stream ftStream,
251 unsigned long offset,
252 unsigned char* buffer,
253 unsigned long count)
254 {
255 SkStreamAsset* stream = static_cast<SkStreamAsset*>(ftStream->descriptor.pointer);
256
257 if (count) {
258 if (!stream->seek(offset)) {
259 return 0;
260 }
261 count = stream->read(buffer, count);
262 }
263 return count;
264 }
265
267}
268
269SkTypeface_FreeType::FaceRec::FaceRec(std::unique_ptr<SkStreamAsset> stream)
270 : fSkStream(std::move(stream))
271{
272 sk_bzero(&fFTStream, sizeof(fFTStream));
273 fFTStream.size = fSkStream->getLength();
274 fFTStream.descriptor.pointer = fSkStream.get();
275 fFTStream.read = sk_ft_stream_io;
276 fFTStream.close = sk_ft_stream_close;
277
278 f_t_mutex().assertHeld();
279 ref_ft_library();
280}
281
283 f_t_mutex().assertHeld();
284 fFace.reset(); // Must release face before the library, the library frees existing faces.
285 unref_ft_library();
286}
287
288void SkTypeface_FreeType::FaceRec::setupAxes(const SkFontData& data) {
289 if (!(fFace->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS)) {
290 return;
291 }
292
293 // If a named variation is requested, don't overwrite the named variation's position.
294 if (data.getIndex() > 0xFFFF) {
295 return;
296 }
297
299 FT_MM_Var* variations = nullptr;
300 if (FT_Get_MM_Var(fFace.get(), &variations)) {
301 LOG_INFO("INFO: font %s claims variations, but none found.\n",
302 rec->fFace->family_name);
303 return;
304 }
305 UniqueVoidPtr autoFreeVariations(variations);
306
307 if (static_cast<FT_UInt>(data.getAxisCount()) != variations->num_axis) {
308 LOG_INFO("INFO: font %s has %d variations, but %d were specified.\n",
309 rec->fFace->family_name, variations->num_axis, data.getAxisCount());
310 return;
311 }
312 )
313
314 AutoSTMalloc<4, FT_Fixed> coords(data.getAxisCount());
315 for (int i = 0; i < data.getAxisCount(); ++i) {
316 coords[i] = data.getAxis()[i];
317 }
318 if (FT_Set_Var_Design_Coordinates(fFace.get(), data.getAxisCount(), coords.get())) {
319 LOG_INFO("INFO: font %s has variations, but specified variations could not be set.\n",
320 rec->fFace->family_name);
321 return;
322 }
323}
324
325void SkTypeface_FreeType::FaceRec::setupPalette(const SkFontData& data) {
326#ifdef FT_COLOR_H
327 FT_Palette_Data paletteData;
328 if (FT_Palette_Data_Get(fFace.get(), &paletteData)) {
329 return;
330 }
331
332 // Treat out of range values as 0. Still apply overrides.
333 // https://www.w3.org/TR/css-fonts-4/#base-palette-desc
334 FT_UShort basePaletteIndex = 0;
335 if (SkTFitsIn<FT_UShort>(data.getPaletteIndex()) &&
336 SkTo<FT_UShort>(data.getPaletteIndex()) < paletteData.num_palettes)
337 {
338 basePaletteIndex = data.getPaletteIndex();
339 }
340
341 FT_Color* ftPalette = nullptr;
342 if (FT_Palette_Select(fFace.get(), basePaletteIndex, &ftPalette)) {
343 return;
344 }
345 fFTPaletteEntryCount = paletteData.num_palette_entries;
346
347 for (int i = 0; i < data.getPaletteOverrideCount(); ++i) {
348 const SkFontArguments::Palette::Override& paletteOverride = data.getPaletteOverrides()[i];
349 if (paletteOverride.index < fFTPaletteEntryCount) {
350 const SkColor& skColor = paletteOverride.color;
351 FT_Color& ftColor = ftPalette[paletteOverride.index];
352 ftColor.blue = SkColorGetB(skColor);
353 ftColor.green = SkColorGetG(skColor);
354 ftColor.red = SkColorGetR(skColor);
355 ftColor.alpha = SkColorGetA(skColor);
356 }
357 }
358
359 fSkPalette.reset(new SkColor[fFTPaletteEntryCount]);
360 for (int i = 0; i < fFTPaletteEntryCount; ++i) {
361 fSkPalette[i] = SkColorSetARGB(ftPalette[i].alpha,
362 ftPalette[i].red,
363 ftPalette[i].green,
364 ftPalette[i].blue);
365 }
366#endif
367}
368
369// Will return nullptr on failure
370// Caller must lock f_t_mutex() before calling this function.
371std::unique_ptr<SkTypeface_FreeType::FaceRec>
373 f_t_mutex().assertHeld();
374
375 std::unique_ptr<SkFontData> data = typeface->makeFontData();
376 if (nullptr == data || !data->hasStream()) {
377 return nullptr;
378 }
379
380 std::unique_ptr<FaceRec> rec(new FaceRec(data->detachStream()));
381
382 FT_Open_Args args;
383 memset(&args, 0, sizeof(args));
384 const void* memoryBase = rec->fSkStream->getMemoryBase();
385 if (memoryBase) {
386 args.flags = FT_OPEN_MEMORY;
387 args.memory_base = (const FT_Byte*)memoryBase;
388 args.memory_size = rec->fSkStream->getLength();
389 } else {
390 args.flags = FT_OPEN_STREAM;
391 args.stream = &rec->fFTStream;
392 }
393
394 {
395 FT_Face rawFace;
396 FT_Error err = FT_Open_Face(gFTLibrary->library(), &args, data->getIndex(), &rawFace);
397 if (err) {
398 SK_TRACEFTR(err, "unable to open font '%x'", (uint32_t)typeface->uniqueID());
399 return nullptr;
400 }
401 rec->fFace.reset(rawFace);
402 }
403 SkASSERT(rec->fFace);
404
405 rec->setupAxes(*data);
406 rec->setupPalette(*data);
407
408 // FreeType will set the charmap to the "most unicode" cmap if it exists.
409 // If there are no unicode cmaps, the charmap is set to nullptr.
410 // However, "symbol" cmaps should also be considered "fallback unicode" cmaps
411 // because they are effectively private use area only (even if they aren't).
412 // This is the last on the fallback list at
413 // https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6cmap.html
414 if (!rec->fFace->charmap) {
415 FT_Select_Charmap(rec->fFace.get(), FT_ENCODING_MS_SYMBOL);
416 }
417
418 return rec;
419}
420
422public:
423 AutoFTAccess(const SkTypeface_FreeType* tf) : fFaceRec(nullptr) {
424 f_t_mutex().acquire();
425 fFaceRec = tf->getFaceRec();
426 }
427
429 f_t_mutex().release();
430 }
431
432 FT_Face face() { return fFaceRec ? fFaceRec->fFace.get() : nullptr; }
433
434private:
436};
437
438///////////////////////////////////////////////////////////////////////////
439
441public:
444 const SkDescriptor* desc);
445 ~SkScalerContext_FreeType() override;
446
447 bool success() const {
448 return fFTSize != nullptr && fFace != nullptr;
449 }
450
451protected:
452 GlyphMetrics generateMetrics(const SkGlyph&, SkArenaAlloc*) override;
453 void generateImage(const SkGlyph&, void*) override;
454 bool generatePath(const SkGlyph& glyph, SkPath* path) override;
455 sk_sp<SkDrawable> generateDrawable(const SkGlyph&) override;
456 void generateFontMetrics(SkFontMetrics*) override;
457
458private:
459 struct ScalerContextBits {
460 static const constexpr uint32_t COLRv0 = 1;
461 static const constexpr uint32_t COLRv1 = 2;
462 static const constexpr uint32_t SVG = 3;
463 };
464
465 // See http://freetype.sourceforge.net/freetype2/docs/reference/ft2-bitmap_handling.html#FT_Bitmap_Embolden
466 // This value was chosen by eyeballing the result in Firefox and trying to match it.
467 static const FT_Pos kBitmapEmboldenStrength = 1 << 6;
468
469 SkTypeface_FreeType::FaceRec* fFaceRec; // Borrowed face from the typeface's FaceRec.
470 FT_Face fFace; // Borrowed face from fFaceRec.
471 FT_Size fFTSize; // The size to apply to the fFace.
472 FT_Int fStrikeIndex; // The bitmap strike for the fFace (or -1 if none).
473
475
476 /** The rest of the matrix after FreeType handles the size.
477 * With outline font rasterization this is handled by FreeType with FT_Set_Transform.
478 * With bitmap only fonts this matrix must be applied to scale the bitmap.
479 */
480 SkMatrix fMatrix22Scalar;
481 /** Same as fMatrix22Scalar, but in FreeType units and space. */
482 FT_Matrix fMatrix22;
483 /** The actual size requested. */
484 SkVector fScale;
485
486 uint32_t fLoadGlyphFlags;
487 bool fDoLinearMetrics;
488 bool fLCDIsVert;
489
490 FT_Error setupSize();
491 // Caller must lock f_t_mutex() before calling this function.
492 static bool getBoundsOfCurrentOutlineGlyph(FT_GlyphSlot glyph, SkRect* bounds);
493 // Caller must lock f_t_mutex() before calling this function.
494 bool getCBoxForLetter(char letter, FT_BBox* bbox);
495 static void updateGlyphBoundsIfSubpixel(const SkGlyph&, SkRect* bounds, bool subpixel);
496 void updateGlyphBoundsIfLCD(GlyphMetrics* mx);
497 // Caller must lock f_t_mutex() before calling this function.
498 // update FreeType2 glyph slot with glyph emboldened
499 void emboldenIfNeeded(FT_Face face, FT_GlyphSlot glyph, SkGlyphID gid);
500 bool shouldSubpixelBitmap(const SkGlyph&, const SkMatrix&);
501};
502
503///////////////////////////////////////////////////////////////////////////
504
505static bool canEmbed(FT_Face face) {
506 FT_UShort fsType = FT_Get_FSType_Flags(face);
507 return (fsType & (FT_FSTYPE_RESTRICTED_LICENSE_EMBEDDING |
508 FT_FSTYPE_BITMAP_EMBEDDING_ONLY)) == 0;
509}
510
511static bool canSubset(FT_Face face) {
512 FT_UShort fsType = FT_Get_FSType_Flags(face);
513 return (fsType & FT_FSTYPE_NO_SUBSETTING) == 0;
514}
515
517 const char* fontType = FT_Get_X11_Font_Format(face);
518 static struct { const char* s; SkAdvancedTypefaceMetrics::FontType t; } values[] = {
523 };
524 for(const auto& v : values) { if (strcmp(fontType, v.s) == 0) { return v.t; } }
526}
527
529 // FreeType reports TrueType for any data that can be decoded to TrueType or OpenType.
530 // However, there are alternate data formats for OpenType, like wOFF and wOF2.
531 std::unique_ptr<SkStreamAsset> stream = typeface.openStream(nullptr);
532 if (!stream) {
533 return false;
534 }
535 char buffer[4];
536 if (stream->read(buffer, 4) < 4) {
537 return false;
538 }
539
541 SK_OT_ULONG otTag = SkEndian_SwapBE32(tag);
546 otTag == SkTTCFHeader::TAG;
547}
548
549std::unique_ptr<SkAdvancedTypefaceMetrics> SkTypeface_FreeType::onGetAdvancedMetrics() const {
550 AutoFTAccess fta(this);
551 FT_Face face = fta.face();
552 if (!face) {
553 return nullptr;
554 }
555
556 std::unique_ptr<SkAdvancedTypefaceMetrics> info(new SkAdvancedTypefaceMetrics);
557 info->fPostScriptName.set(FT_Get_Postscript_Name(face));
558
559 if (FT_HAS_MULTIPLE_MASTERS(face)) {
561 }
562 if (!canEmbed(face)) {
564 }
565 if (!canSubset(face)) {
567 }
568
569 info->fType = get_font_type(face);
573 {
575 }
576
578 if (FT_IS_FIXED_WIDTH(face)) {
580 }
581 if (face->style_flags & FT_STYLE_FLAG_ITALIC) {
583 }
584
585 PS_FontInfoRec psFontInfo;
586 TT_Postscript* postTable;
587 if (FT_Get_PS_Font_Info(face, &psFontInfo) == 0) {
588 info->fItalicAngle = psFontInfo.italic_angle;
589 } else if ((postTable = (TT_Postscript*)FT_Get_Sfnt_Table(face, ft_sfnt_post)) != nullptr) {
590 info->fItalicAngle = SkFixedFloorToInt(postTable->italicAngle);
591 } else {
592 info->fItalicAngle = 0;
593 }
594
595 info->fAscent = face->ascender;
596 info->fDescent = face->descender;
597
598 TT_PCLT* pcltTable;
599 TT_OS2* os2Table;
600 if ((pcltTable = (TT_PCLT*)FT_Get_Sfnt_Table(face, ft_sfnt_pclt)) != nullptr) {
601 info->fCapHeight = pcltTable->CapHeight;
602 uint8_t serif_style = pcltTable->SerifStyle & 0x3F;
603 if (2 <= serif_style && serif_style <= 6) {
605 } else if (9 <= serif_style && serif_style <= 12) {
607 }
608 } else if (((os2Table = (TT_OS2*)FT_Get_Sfnt_Table(face, ft_sfnt_os2)) != nullptr) &&
609 // sCapHeight is available only when version 2 or later.
610 os2Table->version != 0xFFFF &&
611 os2Table->version >= 2)
612 {
613 info->fCapHeight = os2Table->sCapHeight;
614 }
615 info->fBBox = SkIRect::MakeLTRB(face->bbox.xMin, face->bbox.yMax,
616 face->bbox.xMax, face->bbox.yMin);
617 return info;
618}
619
621 AutoFTAccess fta(this);
622 FT_Face face = fta.face();
623 if (!face) {
624 return;
625 }
626
627 FT_Long numGlyphs = face->num_glyphs;
628 if (!dstArray) { SkASSERT(numGlyphs == 0); }
629 sk_bzero(dstArray, sizeof(SkUnichar) * numGlyphs);
630
631 FT_UInt glyphIndex;
632 SkUnichar charCode = FT_Get_First_Char(face, &glyphIndex);
633 while (glyphIndex) {
634 SkASSERT(glyphIndex < SkToUInt(numGlyphs));
635 // Use the first character that maps to this glyphID. https://crbug.com/359065
636 if (0 == dstArray[glyphIndex]) {
637 dstArray[glyphIndex] = charCode;
638 }
639 charCode = FT_Get_Next_Char(face, charCode, &glyphIndex);
640 }
641}
642
644 AutoFTAccess fta(this);
645 FT_Face face = fta.face();
646 if (!face) {
647 return;
648 }
649
650 FT_Long numGlyphs = face->num_glyphs;
651 if (!dstArray) { SkASSERT(numGlyphs == 0); }
652
653 if (FT_HAS_GLYPH_NAMES(face)) {
654 for (int gID = 0; gID < numGlyphs; ++gID) {
655 char glyphName[128]; // PS limit for names is 127 bytes.
656 FT_Get_Glyph_Name(face, gID, glyphName, 128);
657 dstArray[gID] = glyphName;
658 }
659 }
660}
661
663 AutoFTAccess fta(this);
664 FT_Face face = fta.face();
665 if (!face) {
666 return false;
667 }
668
669 const char* ftPostScriptName = FT_Get_Postscript_Name(face);
670 if (!ftPostScriptName) {
671 return false;
672 }
673 if (skPostScriptName) {
674 *skPostScriptName = ftPostScriptName;
675 }
676 return true;
677}
678
679///////////////////////////////////////////////////////////////////////////
680
681static bool bothZero(SkScalar a, SkScalar b) {
682 return 0 == a && 0 == b;
683}
684
685// returns false if there is any non-90-rotation or skew
686static bool isAxisAligned(const SkScalerContextRec& rec) {
687 return 0 == rec.fPreSkewX &&
688 (bothZero(rec.fPost2x2[0][1], rec.fPost2x2[1][0]) ||
689 bothZero(rec.fPost2x2[0][0], rec.fPost2x2[1][1]));
690}
691
692std::unique_ptr<SkScalerContext> SkTypeface_FreeType::onCreateScalerContext(
693 const SkScalerContextEffects& effects, const SkDescriptor* desc) const
694{
695 auto c = std::make_unique<SkScalerContext_FreeType>(
696 sk_ref_sp(const_cast<SkTypeface_FreeType*>(this)), effects, desc);
697 if (c->success()) {
698 return c;
699 }
701 sk_ref_sp(const_cast<SkTypeface_FreeType*>(this)), effects, desc);
702}
703
704/** Copy the design variation coordinates into 'coordinates'.
705 *
706 * @param coordinates the buffer into which to write the design variation coordinates.
707 * @param coordinateCount the number of entries available through 'coordinates'.
708 *
709 * @return The number of axes, or -1 if there is an error.
710 * If 'coordinates != nullptr' and 'coordinateCount >= numAxes' then 'coordinates' will be
711 * filled with the variation coordinates describing the position of this typeface in design
712 * variation space. It is possible the number of axes can be retrieved but actual position
713 * cannot.
714 */
716 SkFontArguments::VariationPosition::Coordinate coordinates[], int coordinateCount)
717{
718 FT_Face face = fta.face();
719 if (!face) {
720 return -1;
721 }
722
723 if (!(face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS)) {
724 return 0;
725 }
726
727 FT_MM_Var* variations = nullptr;
728 if (FT_Get_MM_Var(face, &variations)) {
729 return -1;
730 }
731 UniqueVoidPtr autoFreeVariations(variations);
732
733 if (!coordinates || coordinateCount < SkToInt(variations->num_axis)) {
734 return variations->num_axis;
735 }
736
737 AutoSTMalloc<4, FT_Fixed> coords(variations->num_axis);
738 if (FT_Get_Var_Design_Coordinates(face, variations->num_axis, coords.get())) {
739 return -1;
740 }
741 for (FT_UInt i = 0; i < variations->num_axis; ++i) {
742 coordinates[i].axis = variations->axis[i].tag;
743 coordinates[i].value = SkFixedToScalar(coords[i]);
744 }
745
746 return variations->num_axis;
747}
748
749std::unique_ptr<SkFontData> SkTypeface_FreeType::cloneFontData(const SkFontArguments& args,
750 SkFontStyle* style) const {
751 AutoFTAccess fta(this);
752 FT_Face face = fta.face();
753 if (!face) {
754 return nullptr;
755 }
756
757 SkFontScanner::AxisDefinitions axisDefinitions;
758 if (!SkFontScanner_FreeType::GetAxes(face, &axisDefinitions)) {
759 return nullptr;
760 }
761 int axisCount = axisDefinitions.size();
762
764 int currentAxisCount = GetVariationDesignPosition(fta, currentPosition, axisCount);
765
767 AutoSTMalloc<4, SkFixed> axisValues(axisCount);
769 axisDefinitions,
770 args.getVariationDesignPosition(),
771 axisValues,
772 name, style,
773 currentAxisCount == axisCount ? currentPosition.get() : nullptr);
774
775 int ttcIndex;
776 std::unique_ptr<SkStreamAsset> stream = this->openStream(&ttcIndex);
777
778 return std::make_unique<SkFontData>(std::move(stream),
779 ttcIndex,
780 args.getPalette().index,
781 axisValues.get(),
782 axisCount,
783 args.getPalette().overrides,
784 args.getPalette().overrideCount);
785}
786
788 //BOGUS: http://code.google.com/p/chromium/issues/detail?id=121119
789 //Cap the requested size as larger sizes give bogus values.
790 //Remove when http://code.google.com/p/skia/issues/detail?id=554 is fixed.
791 //Note that this also currently only protects against large text size requests,
792 //the total matrix is not taken into account here.
793 if (rec->fTextSize > SkIntToScalar(1 << 14)) {
794 rec->fTextSize = SkIntToScalar(1 << 14);
795 }
796
797 SkFontHinting h = rec->getHinting();
798 if (SkFontHinting::kFull == h && !isLCD(*rec)) {
799 // collapse full->normal hinting if we're not doing LCD
801 }
802
803 // rotated text looks bad with hinting, so we disable it as needed
804 if (!isAxisAligned(*rec)) {
806 }
807 rec->setHinting(h);
808
809#ifndef SK_GAMMA_APPLY_TO_A8
810 if (!isLCD(*rec)) {
811 // SRGBTODO: Is this correct? Do we want contrast boost?
812 rec->ignorePreBlend();
813 }
814#endif
815}
816
818 SkASSERT(face);
819
820 SkScalar upem = SkIntToScalar(face->units_per_EM);
821 // At least some versions of FreeType set face->units_per_EM to 0 for bitmap only fonts.
822 if (upem == 0) {
823 TT_Header* ttHeader = (TT_Header*)FT_Get_Sfnt_Table(face, ft_sfnt_head);
824 if (ttHeader) {
825 upem = SkIntToScalar(ttHeader->Units_Per_EM);
826 }
827 }
828 return upem;
829}
830
832 AutoFTAccess fta(this);
833 FT_Face face = fta.face();
834 if (!face) {
835 return 0;
836 }
837 return GetUnitsPerEm(face);
838}
839
841 int count, int32_t adjustments[]) const {
842 AutoFTAccess fta(this);
843 FT_Face face = fta.face();
844 if (!face || !FT_HAS_KERNING(face)) {
845 return false;
846 }
847
848 for (int i = 0; i < count - 1; ++i) {
849 FT_Vector delta;
850 FT_Error err = FT_Get_Kerning(face, glyphs[i], glyphs[i+1],
851 FT_KERNING_UNSCALED, &delta);
852 if (err) {
853 return false;
854 }
855 adjustments[i] = delta.x;
856 }
857 return true;
858}
859
860/** Returns the bitmap strike equal to or just larger than the requested size. */
861static FT_Int chooseBitmapStrike(FT_Face face, FT_F26Dot6 scaleY) {
862 if (face == nullptr) {
863 LOG_INFO("chooseBitmapStrike aborted due to nullptr face.\n");
864 return -1;
865 }
866
867 FT_Pos requestedPPEM = scaleY; // FT_Bitmap_Size::y_ppem is in 26.6 format.
868 FT_Int chosenStrikeIndex = -1;
869 FT_Pos chosenPPEM = 0;
870 for (FT_Int strikeIndex = 0; strikeIndex < face->num_fixed_sizes; ++strikeIndex) {
871 FT_Pos strikePPEM = face->available_sizes[strikeIndex].y_ppem;
872 if (strikePPEM == requestedPPEM) {
873 // exact match - our search stops here
874 return strikeIndex;
875 } else if (chosenPPEM < requestedPPEM) {
876 // attempt to increase chosenPPEM
877 if (chosenPPEM < strikePPEM) {
878 chosenPPEM = strikePPEM;
879 chosenStrikeIndex = strikeIndex;
880 }
881 } else {
882 // attempt to decrease chosenPPEM, but not below requestedPPEM
883 if (requestedPPEM < strikePPEM && strikePPEM < chosenPPEM) {
884 chosenPPEM = strikePPEM;
885 chosenStrikeIndex = strikeIndex;
886 }
887 }
888 }
889 return chosenStrikeIndex;
890}
891
893 const SkScalerContextEffects& effects,
894 const SkDescriptor* desc)
895 : SkScalerContext(std::move(typeface), effects, desc)
896 , fFace(nullptr)
897 , fFTSize(nullptr)
898 , fStrikeIndex(-1)
899{
901 fFaceRec = static_cast<SkTypeface_FreeType*>(this->getTypeface())->getFaceRec();
902
903 // load the font file
904 if (nullptr == fFaceRec) {
905 LOG_INFO("Could not create FT_Face.\n");
906 return;
907 }
908
910
911 // compute the flags we send to Load_Glyph
912 bool linearMetrics = this->isLinearMetrics();
913 {
914 FT_Int32 loadFlags = FT_LOAD_DEFAULT;
915
917 // See http://code.google.com/p/chromium/issues/detail?id=43252#c24
918 loadFlags = FT_LOAD_TARGET_MONO;
920 loadFlags |= FT_LOAD_NO_HINTING;
921 linearMetrics = true;
922 }
923 } else {
924 switch (fRec.getHinting()) {
926 loadFlags = FT_LOAD_NO_HINTING;
927 linearMetrics = true;
928 break;
930 loadFlags = FT_LOAD_TARGET_LIGHT; // This implies FORCE_AUTOHINT
931 linearMetrics = true;
932 break;
934 loadFlags = FT_LOAD_TARGET_NORMAL;
935 break;
937 loadFlags = FT_LOAD_TARGET_NORMAL;
938 if (isLCD(fRec)) {
939 if (fLCDIsVert) {
940 loadFlags = FT_LOAD_TARGET_LCD_V;
941 } else {
942 loadFlags = FT_LOAD_TARGET_LCD;
943 }
944 }
945 break;
946 default:
947 LOG_INFO("---------- UNKNOWN hinting %d\n", fRec.getHinting());
948 break;
949 }
950 }
951
953 loadFlags |= FT_LOAD_FORCE_AUTOHINT;
954#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
955 } else {
956 loadFlags |= FT_LOAD_NO_AUTOHINT;
957#endif
958 }
959
961 loadFlags |= FT_LOAD_NO_BITMAP;
962 }
963
964 // Always using FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH to get correct
965 // advances, as fontconfig and cairo do.
966 // See http://code.google.com/p/skia/issues/detail?id=222.
967 loadFlags |= FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
968
969 // Use vertical layout if requested.
970 if (this->isVertical()) {
971 loadFlags |= FT_LOAD_VERTICAL_LAYOUT;
972 }
973
974 fLoadGlyphFlags = loadFlags;
975 }
976
977 SkUniqueFTSize ftSize([this]() -> FT_Size {
978 FT_Size size;
979 FT_Error err = FT_New_Size(fFaceRec->fFace.get(), &size);
980 if (err != 0) {
981 SK_TRACEFTR(err, "FT_New_Size(%s) failed.", fFaceRec->fFace->family_name);
982 return nullptr;
983 }
984 return size;
985 }());
986 if (nullptr == ftSize) {
987 LOG_INFO("Could not create FT_Size.\n");
988 return;
989 }
990
991 FT_Error err = FT_Activate_Size(ftSize.get());
992 if (err != 0) {
993 SK_TRACEFTR(err, "FT_Activate_Size(%s) failed.", fFaceRec->fFace->family_name);
994 return;
995 }
996
998 FT_F26Dot6 scaleX = SkScalarToFDot6(fScale.fX);
999 FT_F26Dot6 scaleY = SkScalarToFDot6(fScale.fY);
1000
1001 if (FT_IS_SCALABLE(fFaceRec->fFace)) {
1002 err = FT_Set_Char_Size(fFaceRec->fFace.get(), scaleX, scaleY, 72, 72);
1003 if (err != 0) {
1004 SK_TRACEFTR(err, "FT_Set_CharSize(%s, %f, %f) failed.",
1005 fFaceRec->fFace->family_name, fScale.fX, fScale.fY);
1006 return;
1007 }
1008
1009 // Adjust the matrix to reflect the actually chosen scale.
1010 // FreeType currently does not allow requesting sizes less than 1, this allow for scaling.
1011 // Don't do this at all sizes as that will interfere with hinting.
1012 if (fScale.fX < 1 || fScale.fY < 1) {
1013 SkScalar upem = fFaceRec->fFace->units_per_EM;
1014 FT_Size_Metrics& ftmetrics = fFaceRec->fFace->size->metrics;
1015 SkScalar x_ppem = upem * SkFT_FixedToScalar(ftmetrics.x_scale) / 64.0f;
1016 SkScalar y_ppem = upem * SkFT_FixedToScalar(ftmetrics.y_scale) / 64.0f;
1017 fMatrix22Scalar.preScale(fScale.x() / x_ppem, fScale.y() / y_ppem);
1018 }
1019
1020 // FT_LOAD_COLOR with scalable fonts means allow SVG.
1021 // It also implies attempt to render COLR if available, but this is not used.
1022#if defined(FT_CONFIG_OPTION_SVG)
1024 fLoadGlyphFlags |= FT_LOAD_COLOR;
1025 }
1026#endif
1027 } else if (FT_HAS_FIXED_SIZES(fFaceRec->fFace)) {
1028 fStrikeIndex = chooseBitmapStrike(fFaceRec->fFace.get(), scaleY);
1029 if (fStrikeIndex == -1) {
1030 LOG_INFO("No glyphs for font \"%s\" size %f.\n",
1031 fFaceRec->fFace->family_name, fScale.fY);
1032 return;
1033 }
1034
1035 err = FT_Select_Size(fFaceRec->fFace.get(), fStrikeIndex);
1036 if (err != 0) {
1037 SK_TRACEFTR(err, "FT_Select_Size(%s, %d) failed.",
1038 fFaceRec->fFace->family_name, fStrikeIndex);
1039 fStrikeIndex = -1;
1040 return;
1041 }
1042
1043 // Adjust the matrix to reflect the actually chosen scale.
1044 // It is likely that the ppem chosen was not the one requested, this allows for scaling.
1045 fMatrix22Scalar.preScale(fScale.x() / fFaceRec->fFace->size->metrics.x_ppem,
1046 fScale.y() / fFaceRec->fFace->size->metrics.y_ppem);
1047
1048 // FreeType does not provide linear metrics for bitmap fonts.
1049 linearMetrics = false;
1050
1051 // FreeType documentation says:
1052 // FT_LOAD_NO_BITMAP -- Ignore bitmap strikes when loading.
1053 // Bitmap-only fonts ignore this flag.
1054 //
1055 // However, in FreeType 2.5.1 color bitmap only fonts do not ignore this flag.
1056 // Force this flag off for bitmap only fonts.
1057 fLoadGlyphFlags &= ~FT_LOAD_NO_BITMAP;
1058
1059 // Color bitmaps are supported.
1060 fLoadGlyphFlags |= FT_LOAD_COLOR;
1061 } else {
1062 LOG_INFO("Unknown kind of font \"%s\" size %f.\n", fFaceRec->fFace->family_name, fScale.fY);
1063 return;
1064 }
1065
1066 fMatrix22.xx = SkScalarToFixed(fMatrix22Scalar.getScaleX());
1067 fMatrix22.xy = SkScalarToFixed(-fMatrix22Scalar.getSkewX());
1068 fMatrix22.yx = SkScalarToFixed(-fMatrix22Scalar.getSkewY());
1069 fMatrix22.yy = SkScalarToFixed(fMatrix22Scalar.getScaleY());
1070
1071 fFTSize = ftSize.release();
1072 fFace = fFaceRec->fFace.get();
1073 fDoLinearMetrics = linearMetrics;
1075}
1076
1079
1080 if (fFTSize != nullptr) {
1081 FT_Done_Size(fFTSize);
1082 }
1083
1084 fFaceRec = nullptr;
1085}
1086
1087/* We call this before each use of the fFace, since we may be sharing
1088 this face with other context (at different sizes).
1089*/
1090FT_Error SkScalerContext_FreeType::setupSize() {
1091 f_t_mutex().assertHeld();
1092 FT_Error err = FT_Activate_Size(fFTSize);
1093 if (err != 0) {
1094 return err;
1095 }
1096 FT_Set_Transform(fFace, &fMatrix22, nullptr);
1097 return 0;
1098}
1099
1100bool SkScalerContext_FreeType::getBoundsOfCurrentOutlineGlyph(FT_GlyphSlot glyph, SkRect* bounds) {
1101 if (glyph->format != FT_GLYPH_FORMAT_OUTLINE) {
1102 SkASSERT(false);
1103 return false;
1104 }
1105 if (0 == glyph->outline.n_contours) {
1106 return false;
1107 }
1108
1109 FT_BBox bbox;
1110 FT_Outline_Get_CBox(&glyph->outline, &bbox);
1111 *bounds = SkRect::MakeLTRB(SkFDot6ToScalar(bbox.xMin), -SkFDot6ToScalar(bbox.yMax),
1112 SkFDot6ToScalar(bbox.xMax), -SkFDot6ToScalar(bbox.yMin));
1113 return true;
1114}
1115
1116bool SkScalerContext_FreeType::getCBoxForLetter(char letter, FT_BBox* bbox) {
1117 const FT_UInt glyph_id = FT_Get_Char_Index(fFace, letter);
1118 if (!glyph_id) {
1119 return false;
1120 }
1121 if (FT_Load_Glyph(fFace, glyph_id, fLoadGlyphFlags)) {
1122 return false;
1123 }
1124 if (fFace->glyph->format != FT_GLYPH_FORMAT_OUTLINE) {
1125 return false;
1126 }
1127 emboldenIfNeeded(fFace, fFace->glyph, SkTo<SkGlyphID>(glyph_id));
1128 FT_Outline_Get_CBox(&fFace->glyph->outline, bbox);
1129 return true;
1130}
1131
1132void SkScalerContext_FreeType::updateGlyphBoundsIfSubpixel(const SkGlyph& glyph, SkRect* bounds,
1133 bool subpixel) {
1134 if (subpixel && !bounds->isEmpty()) {
1135 bounds->offset(SkFixedToScalar(glyph.getSubXFixed()),
1136 SkFixedToScalar(glyph.getSubYFixed()));
1137 }
1138}
1139
1140void SkScalerContext_FreeType::updateGlyphBoundsIfLCD(GlyphMetrics* mx) {
1141 if (mx->maskFormat == SkMask::kLCD16_Format && !mx->bounds.isEmpty()) {
1142 mx->bounds.roundOut(&mx->bounds);
1143 if (fLCDIsVert) {
1144 mx->bounds.fBottom += 1;
1145 mx->bounds.fTop -= 1;
1146 } else {
1147 mx->bounds.fRight += 1;
1148 mx->bounds.fLeft -= 1;
1149 }
1150 }
1151}
1152
1153bool SkScalerContext_FreeType::shouldSubpixelBitmap(const SkGlyph& glyph, const SkMatrix& matrix) {
1154 // If subpixel rendering of a bitmap *can* be done.
1155 bool mechanism = fFace->glyph->format == FT_GLYPH_FORMAT_BITMAP &&
1156 this->isSubpixel() &&
1157 (glyph.getSubXFixed() || glyph.getSubYFixed());
1158
1159 // If subpixel rendering of a bitmap *should* be done.
1160 // 1. If the face is not scalable then always allow subpixel rendering.
1161 // Otherwise, if the font has an 8ppem strike 7 will subpixel render but 8 won't.
1162 // 2. If the matrix is already not identity the bitmap will already be resampled,
1163 // so resampling slightly differently shouldn't make much difference.
1164 bool policy = !FT_IS_SCALABLE(fFace) || !matrix.isIdentity();
1165
1166 return mechanism && policy;
1167}
1168
1170 SkArenaAlloc* alloc) {
1172
1173 GlyphMetrics mx(glyph.maskFormat());
1174
1175 if (this->setupSize()) {
1176 return mx;
1177 }
1178
1179 FT_Bool haveLayers = false;
1180#ifdef FT_COLOR_H
1181 // See https://skbug.com/12945, if the face isn't marked scalable then paths cannot be loaded.
1182 if (FT_IS_SCALABLE(fFace)) {
1183 SkRect bounds = SkRect::MakeEmpty();
1184#ifdef TT_SUPPORT_COLRV1
1185 FT_OpaquePaint opaqueLayerPaint{nullptr, 1};
1186 if (FT_Get_Color_Glyph_Paint(fFace, glyph.getGlyphID(),
1187 FT_COLOR_INCLUDE_ROOT_TRANSFORM, &opaqueLayerPaint)) {
1188 haveLayers = true;
1189 mx.extraBits = ScalerContextBits::COLRv1;
1190
1191 // COLRv1 optionally provides a ClipBox.
1192 FT_ClipBox clipBox;
1193 if (FT_Get_Color_Glyph_ClipBox(fFace, glyph.getGlyphID(), &clipBox)) {
1194 // Find bounding box of clip box corner points, needed when clipbox is transformed.
1195 FT_BBox bbox;
1196 bbox.xMin = clipBox.bottom_left.x;
1197 bbox.xMax = clipBox.bottom_left.x;
1198 bbox.yMin = clipBox.bottom_left.y;
1199 bbox.yMax = clipBox.bottom_left.y;
1200 for (auto& corner : {clipBox.top_left, clipBox.top_right, clipBox.bottom_right}) {
1201 bbox.xMin = std::min(bbox.xMin, corner.x);
1202 bbox.yMin = std::min(bbox.yMin, corner.y);
1203 bbox.xMax = std::max(bbox.xMax, corner.x);
1204 bbox.yMax = std::max(bbox.yMax, corner.y);
1205 }
1206 bounds = SkRect::MakeLTRB(SkFDot6ToScalar(bbox.xMin), -SkFDot6ToScalar(bbox.yMax),
1207 SkFDot6ToScalar(bbox.xMax), -SkFDot6ToScalar(bbox.yMin));
1208 } else {
1209 // Traverse the glyph graph with a focus on measuring the required bounding box.
1210 // The call to computeColrV1GlyphBoundingBox may modify the face.
1211 // Reset the face to load the base glyph for metrics.
1213 glyph.getGlyphID(),
1214 &bounds) ||
1215 this->setupSize())
1216 {
1217 return mx;
1218 }
1219 }
1220 }
1221#endif // #TT_SUPPORT_COLRV1
1222
1223 if (!haveLayers) {
1224 FT_LayerIterator layerIterator = { 0, 0, nullptr };
1225 FT_UInt layerGlyphIndex;
1226 FT_UInt layerColorIndex;
1227 FT_Int32 flags = fLoadGlyphFlags;
1228 flags |= FT_LOAD_BITMAP_METRICS_ONLY; // Don't decode any bitmaps.
1229 flags |= FT_LOAD_NO_BITMAP; // Ignore embedded bitmaps.
1230 flags &= ~FT_LOAD_RENDER; // Don't scan convert.
1231 flags &= ~FT_LOAD_COLOR; // Ignore SVG.
1232 // For COLRv0 compute the glyph bounding box from the union of layer bounding boxes.
1233 while (FT_Get_Color_Glyph_Layer(fFace, glyph.getGlyphID(), &layerGlyphIndex,
1234 &layerColorIndex, &layerIterator)) {
1235 haveLayers = true;
1236 if (FT_Load_Glyph(fFace, layerGlyphIndex, flags)) {
1237 return mx;
1238 }
1239
1240 SkRect currentBounds;
1241 if (getBoundsOfCurrentOutlineGlyph(fFace->glyph, &currentBounds)) {
1242 bounds.join(currentBounds);
1243 }
1244 }
1245 if (haveLayers) {
1246 mx.extraBits = ScalerContextBits::COLRv0;
1247 }
1248 }
1249
1250 if (haveLayers) {
1252 mx.neverRequestPath = true;
1253 updateGlyphBoundsIfSubpixel(glyph, &bounds, this->isSubpixel());
1254 mx.bounds = bounds;
1255 }
1256 }
1257#endif //FT_COLOR_H
1258
1259 // Even if haveLayers, the base glyph must be loaded to get the metrics.
1260 if (FT_Load_Glyph(fFace, glyph.getGlyphID(), fLoadGlyphFlags | FT_LOAD_BITMAP_METRICS_ONLY)) {
1261 return mx;
1262 }
1263
1264 if (!haveLayers) {
1265 emboldenIfNeeded(fFace, fFace->glyph, glyph.getGlyphID());
1266
1267 if (fFace->glyph->format == FT_GLYPH_FORMAT_OUTLINE) {
1268 getBoundsOfCurrentOutlineGlyph(fFace->glyph, &mx.bounds);
1269 updateGlyphBoundsIfSubpixel(glyph, &mx.bounds, this->isSubpixel());
1270 updateGlyphBoundsIfLCD(&mx);
1271
1272 } else if (fFace->glyph->format == FT_GLYPH_FORMAT_BITMAP) {
1273 mx.neverRequestPath = true;
1274
1275 if (this->isVertical()) {
1276 FT_Vector vector;
1277 vector.x = fFace->glyph->metrics.vertBearingX - fFace->glyph->metrics.horiBearingX;
1278 vector.y = -fFace->glyph->metrics.vertBearingY - fFace->glyph->metrics.horiBearingY;
1279 FT_Vector_Transform(&vector, &fMatrix22);
1280 fFace->glyph->bitmap_left += SkFDot6Floor(vector.x);
1281 fFace->glyph->bitmap_top += SkFDot6Floor(vector.y);
1282 }
1283
1284 if (fFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_BGRA) {
1286 }
1287
1288 mx.bounds = SkRect::MakeXYWH(SkIntToScalar(fFace->glyph->bitmap_left ),
1289 -SkIntToScalar(fFace->glyph->bitmap_top ),
1290 SkIntToScalar(fFace->glyph->bitmap.width),
1291 SkIntToScalar(fFace->glyph->bitmap.rows ));
1292 fMatrix22Scalar.mapRect(&mx.bounds);
1293 updateGlyphBoundsIfSubpixel(glyph, &mx.bounds,
1294 this->shouldSubpixelBitmap(glyph, fMatrix22Scalar));
1295
1296#if defined(FT_CONFIG_OPTION_SVG)
1297 } else if (fFace->glyph->format == FT_GLYPH_FORMAT_SVG) {
1298 mx.extraBits = ScalerContextBits::SVG;
1300 mx.neverRequestPath = true;
1301
1302 SkPictureRecorder recorder;
1306 SkSpan<SkColor> palette(fFaceRec->fSkPalette.get(), fFaceRec->fFTPaletteEntryCount);
1307 SkCanvas* recordingCanvas = recorder.beginRecording(infiniteRect, bboxh);
1308 if (!fUtils.drawSVGGlyph(fFace, glyph, fLoadGlyphFlags, palette, recordingCanvas)) {
1309 return mx;
1310 }
1312 mx.bounds = pic->cullRect();
1313 SkASSERT(mx.bounds.isFinite());
1314 // drawSVGGlyph already applied the subpixel positioning.
1315#endif // FT_CONFIG_OPTION_SVG
1316
1317 } else {
1318 SkDEBUGFAIL("unknown glyph format");
1319 return mx;
1320 }
1321 }
1322
1323 if (this->isVertical()) {
1324 if (fDoLinearMetrics) {
1325 const SkScalar advanceScalar = SkFT_FixedToScalar(fFace->glyph->linearVertAdvance);
1326 mx.advance.fX = fMatrix22Scalar.getSkewX() * advanceScalar;
1327 mx.advance.fY = fMatrix22Scalar.getScaleY() * advanceScalar;
1328 } else {
1329 mx.advance.fX = -SkFDot6ToFloat(fFace->glyph->advance.x);
1330 mx.advance.fY = SkFDot6ToFloat(fFace->glyph->advance.y);
1331 }
1332 } else {
1333 if (fDoLinearMetrics) {
1334 const SkScalar advanceScalar = SkFT_FixedToScalar(fFace->glyph->linearHoriAdvance);
1335 mx.advance.fX = fMatrix22Scalar.getScaleX() * advanceScalar;
1336 mx.advance.fY = fMatrix22Scalar.getSkewY() * advanceScalar;
1337 } else {
1338 mx.advance.fX = SkFDot6ToFloat(fFace->glyph->advance.x);
1339 mx.advance.fY = -SkFDot6ToFloat(fFace->glyph->advance.y);
1340 }
1341 }
1342
1343#ifdef ENABLE_GLYPH_SPEW
1344 LOG_INFO("Metrics(glyph:%d flags:0x%x) w:%d\n", glyph->getGlyphID(), fLoadGlyphFlags, glyph->width());
1345#endif
1346 return mx;
1347}
1348
1349void SkScalerContext_FreeType::generateImage(const SkGlyph& glyph, void* imageBuffer) {
1351
1352 if (this->setupSize()) {
1353 sk_bzero(imageBuffer, glyph.imageSize());
1354 return;
1355 }
1356
1357 if (glyph.extraBits() == ScalerContextBits::COLRv0 ||
1358 glyph.extraBits() == ScalerContextBits::COLRv1 ||
1359 glyph.extraBits() == ScalerContextBits::SVG )
1360 {
1362 SkBitmap dstBitmap;
1363 // TODO: mark this as sRGB when the blits will be sRGB.
1364 dstBitmap.setInfo(SkImageInfo::Make(glyph.width(), glyph.height(),
1365 kN32_SkColorType,
1367 glyph.rowBytes());
1368 dstBitmap.setPixels(imageBuffer);
1369
1370 SkCanvas canvas(dstBitmap);
1371 if constexpr (kSkShowTextBlitCoverage) {
1372 canvas.clear(0x33FF0000);
1373 } else {
1374 canvas.clear(SK_ColorTRANSPARENT);
1375 }
1376 canvas.translate(-glyph.left(), -glyph.top());
1377
1378 SkSpan<SkColor> palette(fFaceRec->fSkPalette.get(), fFaceRec->fFTPaletteEntryCount);
1379 if (glyph.extraBits() == ScalerContextBits::COLRv0) {
1380#ifdef FT_COLOR_H
1381 fUtils.drawCOLRv0Glyph(fFace, glyph, fLoadGlyphFlags, palette, &canvas);
1382#endif
1383 } else if (glyph.extraBits() == ScalerContextBits::COLRv1) {
1384#ifdef TT_SUPPORT_COLRV1
1385 fUtils.drawCOLRv1Glyph(fFace, glyph, fLoadGlyphFlags, palette, &canvas);
1386#endif
1387 } else if (glyph.extraBits() == ScalerContextBits::SVG) {
1388#if defined(FT_CONFIG_OPTION_SVG)
1389 if (FT_Load_Glyph(fFace, glyph.getGlyphID(), fLoadGlyphFlags)) {
1390 return;
1391 }
1392 fUtils.drawSVGGlyph(fFace, glyph, fLoadGlyphFlags, palette, &canvas);
1393#endif
1394 }
1395 return;
1396 }
1397
1398 if (FT_Load_Glyph(fFace, glyph.getGlyphID(), fLoadGlyphFlags)) {
1399 sk_bzero(imageBuffer, glyph.imageSize());
1400 return;
1401 }
1402 emboldenIfNeeded(fFace, fFace->glyph, glyph.getGlyphID());
1403
1404 SkMatrix* bitmapMatrix = &fMatrix22Scalar;
1405 SkMatrix subpixelBitmapMatrix;
1406 if (this->shouldSubpixelBitmap(glyph, *bitmapMatrix)) {
1407 subpixelBitmapMatrix = fMatrix22Scalar;
1408 subpixelBitmapMatrix.postTranslate(SkFixedToScalar(glyph.getSubXFixed()),
1409 SkFixedToScalar(glyph.getSubYFixed()));
1410 bitmapMatrix = &subpixelBitmapMatrix;
1411 }
1412
1413 fUtils.generateGlyphImage(fFace, glyph, imageBuffer, *bitmapMatrix, fPreBlend);
1414}
1415
1417 // Because FreeType's FT_Face is stateful (not thread safe) and the current design of this
1418 // SkTypeface and SkScalerContext does not work around this, it is necessary lock at least the
1419 // FT_Face when using it (this implementation currently locks the whole FT_Library).
1420 // It should be possible to draw the drawable straight out of the FT_Face. However, this would
1421 // mean locking each time any such drawable is drawn. To avoid locking, this implementation
1422 // creates drawables backed as pictures so that they can be played back later without locking.
1424
1425 if (this->setupSize()) {
1426 return nullptr;
1427 }
1428
1429#if defined(FT_COLOR_H) || defined(TT_SUPPORT_COLRV1) || defined(FT_CONFIG_OPTION_SVG)
1430 if (glyph.extraBits() == ScalerContextBits::COLRv0 ||
1431 glyph.extraBits() == ScalerContextBits::COLRv1 ||
1432 glyph.extraBits() == ScalerContextBits::SVG )
1433 {
1434 SkSpan<SkColor> palette(fFaceRec->fSkPalette.get(), fFaceRec->fFTPaletteEntryCount);
1435 SkPictureRecorder recorder;
1436 SkCanvas* recordingCanvas = recorder.beginRecording(SkRect::Make(glyph.mask().fBounds));
1437 if (glyph.extraBits() == ScalerContextBits::COLRv0) {
1438#ifdef FT_COLOR_H
1439 if (!fUtils.drawCOLRv0Glyph(fFace, glyph, fLoadGlyphFlags, palette, recordingCanvas)) {
1440 return nullptr;
1441 }
1442#else
1443 return nullptr;
1444#endif
1445 } else if (glyph.extraBits() == ScalerContextBits::COLRv1) {
1446#ifdef TT_SUPPORT_COLRV1
1447 if (!fUtils.drawCOLRv1Glyph(fFace, glyph, fLoadGlyphFlags, palette, recordingCanvas)) {
1448 return nullptr;
1449 }
1450#else
1451 return nullptr;
1452#endif
1453 } else if (glyph.extraBits() == ScalerContextBits::SVG) {
1454#if defined(FT_CONFIG_OPTION_SVG)
1455 if (FT_Load_Glyph(fFace, glyph.getGlyphID(), fLoadGlyphFlags)) {
1456 return nullptr;
1457 }
1458 if (!fUtils.drawSVGGlyph(fFace, glyph, fLoadGlyphFlags, palette, recordingCanvas)) {
1459 return nullptr;
1460 }
1461#else
1462 return nullptr;
1463#endif
1464 }
1465 return recorder.finishRecordingAsDrawable();
1466 }
1467#endif
1468 return nullptr;
1469}
1470
1472 SkASSERT(path);
1473
1475
1476 SkGlyphID glyphID = glyph.getGlyphID();
1477 // FT_IS_SCALABLE is documented to mean the face contains outline glyphs.
1478 if (!FT_IS_SCALABLE(fFace) || this->setupSize()) {
1479 path->reset();
1480 return false;
1481 }
1482
1483 uint32_t flags = fLoadGlyphFlags;
1484 flags |= FT_LOAD_NO_BITMAP; // ignore embedded bitmaps so we're sure to get the outline
1485 flags &= ~FT_LOAD_RENDER; // don't scan convert (we just want the outline)
1486
1487 FT_Error err = FT_Load_Glyph(fFace, glyphID, flags);
1488 if (err != 0 || fFace->glyph->format != FT_GLYPH_FORMAT_OUTLINE) {
1489 path->reset();
1490 return false;
1491 }
1492 emboldenIfNeeded(fFace, fFace->glyph, glyphID);
1493
1494 if (!fUtils.generateGlyphPath(fFace, path)) {
1495 path->reset();
1496 return false;
1497 }
1498
1499 // The path's origin from FreeType is always the horizontal layout origin.
1500 // Offset the path so that it is relative to the vertical origin if needed.
1501 if (this->isVertical()) {
1502 FT_Vector vector;
1503 vector.x = fFace->glyph->metrics.vertBearingX - fFace->glyph->metrics.horiBearingX;
1504 vector.y = -fFace->glyph->metrics.vertBearingY - fFace->glyph->metrics.horiBearingY;
1505 FT_Vector_Transform(&vector, &fMatrix22);
1506 path->offset(SkFDot6ToScalar(vector.x), -SkFDot6ToScalar(vector.y));
1507 }
1508 return true;
1509}
1510
1512 if (nullptr == metrics) {
1513 return;
1514 }
1515
1517
1518 if (this->setupSize()) {
1519 sk_bzero(metrics, sizeof(*metrics));
1520 return;
1521 }
1522
1523 FT_Face face = fFace;
1524 metrics->fFlags = 0;
1525
1527
1528 // use the os/2 table as a source of reasonable defaults.
1529 SkScalar x_height = 0.0f;
1530 SkScalar avgCharWidth = 0.0f;
1531 SkScalar cap_height = 0.0f;
1532 SkScalar strikeoutThickness = 0.0f, strikeoutPosition = 0.0f;
1533 TT_OS2* os2 = (TT_OS2*) FT_Get_Sfnt_Table(face, ft_sfnt_os2);
1534 if (os2) {
1535 x_height = SkIntToScalar(os2->sxHeight) / upem * fScale.y();
1536 avgCharWidth = SkIntToScalar(os2->xAvgCharWidth) / upem;
1537 strikeoutThickness = SkIntToScalar(os2->yStrikeoutSize) / upem;
1538 strikeoutPosition = -SkIntToScalar(os2->yStrikeoutPosition) / upem;
1541 if (os2->version != 0xFFFF && os2->version >= 2) {
1542 cap_height = SkIntToScalar(os2->sCapHeight) / upem * fScale.y();
1543 }
1544 }
1545
1546 // pull from format-specific metrics as needed
1547 SkScalar ascent, descent, leading, xmin, xmax, ymin, ymax;
1548 SkScalar underlineThickness, underlinePosition;
1549 if (face->face_flags & FT_FACE_FLAG_SCALABLE) { // scalable outline font
1550 // FreeType will always use HHEA metrics if they're not zero.
1551 // It completely ignores the OS/2 fsSelection::UseTypoMetrics bit.
1552 // It also ignores the VDMX tables, which are also of interest here
1553 // (and override everything else when they apply).
1554 static const int kUseTypoMetricsMask = (1 << 7);
1555 if (os2 && os2->version != 0xFFFF && (os2->fsSelection & kUseTypoMetricsMask)) {
1556 ascent = -SkIntToScalar(os2->sTypoAscender) / upem;
1557 descent = -SkIntToScalar(os2->sTypoDescender) / upem;
1558 leading = SkIntToScalar(os2->sTypoLineGap) / upem;
1559 } else {
1560 ascent = -SkIntToScalar(face->ascender) / upem;
1561 descent = -SkIntToScalar(face->descender) / upem;
1562 leading = SkIntToScalar(face->height + (face->descender - face->ascender)) / upem;
1563 }
1564 xmin = SkIntToScalar(face->bbox.xMin) / upem;
1565 xmax = SkIntToScalar(face->bbox.xMax) / upem;
1566 ymin = -SkIntToScalar(face->bbox.yMin) / upem;
1567 ymax = -SkIntToScalar(face->bbox.yMax) / upem;
1568 underlineThickness = SkIntToScalar(face->underline_thickness) / upem;
1569 underlinePosition = -SkIntToScalar(face->underline_position +
1570 face->underline_thickness / 2) / upem;
1571
1574
1575 // we may be able to synthesize x_height and cap_height from outline
1576 if (!x_height) {
1577 FT_BBox bbox;
1578 if (getCBoxForLetter('x', &bbox)) {
1579 x_height = SkIntToScalar(bbox.yMax) / 64.0f;
1580 }
1581 }
1582 if (!cap_height) {
1583 FT_BBox bbox;
1584 if (getCBoxForLetter('H', &bbox)) {
1585 cap_height = SkIntToScalar(bbox.yMax) / 64.0f;
1586 }
1587 }
1588 } else if (fStrikeIndex != -1) { // bitmap strike metrics
1589 SkScalar xppem = SkIntToScalar(face->size->metrics.x_ppem);
1590 SkScalar yppem = SkIntToScalar(face->size->metrics.y_ppem);
1591 ascent = -SkIntToScalar(face->size->metrics.ascender) / (yppem * 64.0f);
1592 descent = -SkIntToScalar(face->size->metrics.descender) / (yppem * 64.0f);
1593 leading = (SkIntToScalar(face->size->metrics.height) / (yppem * 64.0f)) + ascent - descent;
1594
1595 xmin = 0.0f;
1596 xmax = SkIntToScalar(face->available_sizes[fStrikeIndex].width) / xppem;
1597 ymin = descent;
1598 ymax = ascent;
1599 // The actual bitmaps may be any size and placed at any offset.
1601
1602 underlineThickness = 0;
1603 underlinePosition = 0;
1604 metrics->fFlags &= ~SkFontMetrics::kUnderlineThicknessIsValid_Flag;
1605 metrics->fFlags &= ~SkFontMetrics::kUnderlinePositionIsValid_Flag;
1606
1607 TT_Postscript* post = (TT_Postscript*) FT_Get_Sfnt_Table(face, ft_sfnt_post);
1608 if (post) {
1609 underlineThickness = SkIntToScalar(post->underlineThickness) / upem;
1610 underlinePosition = -SkIntToScalar(post->underlinePosition) / upem;
1613 }
1614 } else {
1615 sk_bzero(metrics, sizeof(*metrics));
1616 return;
1617 }
1618
1619 // synthesize elements that were not provided by the os/2 table or format-specific metrics
1620 if (!x_height) {
1621 x_height = -ascent * fScale.y();
1622 }
1623 if (!avgCharWidth) {
1624 avgCharWidth = xmax - xmin;
1625 }
1626 if (!cap_height) {
1627 cap_height = -ascent * fScale.y();
1628 }
1629
1630 // disallow negative linespacing
1631 if (leading < 0.0f) {
1632 leading = 0.0f;
1633 }
1634
1635 metrics->fTop = ymax * fScale.y();
1636 metrics->fAscent = ascent * fScale.y();
1637 metrics->fDescent = descent * fScale.y();
1638 metrics->fBottom = ymin * fScale.y();
1639 metrics->fLeading = leading * fScale.y();
1640 metrics->fAvgCharWidth = avgCharWidth * fScale.y();
1641 metrics->fXMin = xmin * fScale.y();
1642 metrics->fXMax = xmax * fScale.y();
1643 metrics->fMaxCharWidth = metrics->fXMax - metrics->fXMin;
1644 metrics->fXHeight = x_height;
1645 metrics->fCapHeight = cap_height;
1646 metrics->fUnderlineThickness = underlineThickness * fScale.y();
1647 metrics->fUnderlinePosition = underlinePosition * fScale.y();
1648 metrics->fStrikeoutThickness = strikeoutThickness * fScale.y();
1649 metrics->fStrikeoutPosition = strikeoutPosition * fScale.y();
1650
1651 if (face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS
1652#if defined(FT_CONFIG_OPTION_SVG)
1653 || face->face_flags & FT_FACE_FLAG_SVG
1654#endif // FT_CONFIG_OPTION_SVG
1655 ) {
1656 // The bounds are only valid for the default variation of variable glyphs.
1657 // https://docs.microsoft.com/en-us/typography/opentype/spec/head
1658 // For SVG glyphs this number is often incorrect for its non-`glyf` points.
1659 // https://github.com/fonttools/fonttools/issues/2566
1661 }
1662}
1663
1664///////////////////////////////////////////////////////////////////////////////
1665
1666// hand-tuned value to reduce outline embolden strength
1667#ifndef SK_OUTLINE_EMBOLDEN_DIVISOR
1668 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
1669 #define SK_OUTLINE_EMBOLDEN_DIVISOR 34
1670 #else
1671 #define SK_OUTLINE_EMBOLDEN_DIVISOR 24
1672 #endif
1673#endif
1674
1675///////////////////////////////////////////////////////////////////////////////
1676
1677void SkScalerContext_FreeType::emboldenIfNeeded(FT_Face face, FT_GlyphSlot glyph, SkGlyphID gid) {
1678 // check to see if the embolden bit is set
1680 return;
1681 }
1682
1683 switch (glyph->format) {
1684 case FT_GLYPH_FORMAT_OUTLINE:
1685 FT_Pos strength;
1686 strength = FT_MulFix(face->units_per_EM, face->size->metrics.y_scale)
1688 FT_Outline_Embolden(&glyph->outline, strength);
1689 break;
1690 case FT_GLYPH_FORMAT_BITMAP:
1691 if (!fFace->glyph->bitmap.buffer) {
1692 FT_Load_Glyph(fFace, gid, fLoadGlyphFlags);
1693 }
1694 FT_GlyphSlot_Own_Bitmap(glyph);
1695 FT_Bitmap_Embolden(glyph->library, &glyph->bitmap, kBitmapEmboldenStrength, 0);
1696 break;
1697 default:
1698 SkDEBUGFAIL("unknown glyph format");
1699 }
1700}
1701
1702///////////////////////////////////////////////////////////////////////////////
1703
1704#include "src/base/SkUtils.h"
1705
1707 : INHERITED(style, isFixedPitch)
1708{}
1709
1711 if (fFaceRec) {
1713 fFaceRec.reset();
1714 }
1715}
1716
1717// Just made up, so we don't end up storing 1000s of entries
1718constexpr int kMaxC2GCacheCount = 512;
1719
1721 SkGlyphID glyphs[]) const {
1722 // Try the cache first, *before* accessing freetype lib/face, as that
1723 // can be very slow. If we do need to compute a new glyphID, then
1724 // access those freetype objects and continue the loop.
1725
1726 int i;
1727 {
1728 // Optimistically use a shared lock.
1729 SkAutoSharedMutexShared ama(fC2GCacheMutex);
1730 for (i = 0; i < count; ++i) {
1731 int index = fC2GCache.findGlyphIndex(uni[i]);
1732 if (index < 0) {
1733 break;
1734 }
1735 glyphs[i] = SkToU16(index);
1736 }
1737 if (i == count) {
1738 // we're done, no need to access the freetype objects
1739 return;
1740 }
1741 }
1742
1743 // Need to add more so grab an exclusive lock.
1744 SkAutoSharedMutexExclusive ama(fC2GCacheMutex);
1745 AutoFTAccess fta(this);
1746 FT_Face face = fta.face();
1747 if (!face) {
1748 sk_bzero(glyphs, count * sizeof(glyphs[0]));
1749 return;
1750 }
1751
1752 for (; i < count; ++i) {
1753 SkUnichar c = uni[i];
1754 int index = fC2GCache.findGlyphIndex(c);
1755 if (index >= 0) {
1756 glyphs[i] = SkToU16(index);
1757 } else {
1758 glyphs[i] = SkToU16(FT_Get_Char_Index(face, c));
1759 fC2GCache.insertCharAndGlyph(~index, c, glyphs[i]);
1760 }
1761 }
1762
1763 if (fC2GCache.count() > kMaxC2GCacheCount) {
1764 fC2GCache.reset();
1765 }
1766}
1767
1769 AutoFTAccess fta(this);
1770 FT_Face face = fta.face();
1771 return face ? face->num_glyphs : 0;
1772}
1773
1777 if (!nameIter) {
1778 SkString familyName;
1779 this->getFamilyName(&familyName);
1780 SkString language("und"); //undetermined
1781 nameIter = sk_make_sp<SkOTUtils::LocalizedStrings_SingleName>(familyName, language);
1782 }
1783 return nameIter.release();
1784}
1785
1787 fGlyphMasksMayNeedCurrentColorOnce([this]{
1788 static constexpr SkFourByteTag COLRTag = SkSetFourByteTag('C', 'O', 'L', 'R');
1789 fGlyphMasksMayNeedCurrentColor = this->getTableSize(COLRTag) > 0;
1790#if defined(FT_CONFIG_OPTION_SVG)
1791 static constexpr SkFourByteTag SVGTag = SkSetFourByteTag('S', 'V', 'G', ' ');
1792 fGlyphMasksMayNeedCurrentColor |= this->getTableSize(SVGTag) > 0 ;
1793#endif // FT_CONFIG_OPTION_SVG
1794 });
1795 return fGlyphMasksMayNeedCurrentColor;
1796}
1797
1799 SkFontArguments::VariationPosition::Coordinate coordinates[], int coordinateCount) const
1800{
1801 AutoFTAccess fta(this);
1802 return GetVariationDesignPosition(fta, coordinates, coordinateCount);
1803}
1804
1806 SkFontParameters::Variation::Axis parameters[], int parameterCount) const
1807{
1808 AutoFTAccess fta(this);
1809 FT_Face face = fta.face();
1810 if (!face) {
1811 return -1;
1812 }
1813
1814 if (!(face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS)) {
1815 return 0;
1816 }
1817
1818 FT_MM_Var* variations = nullptr;
1819 if (FT_Get_MM_Var(face, &variations)) {
1820 return -1;
1821 }
1822 UniqueVoidPtr autoFreeVariations(variations);
1823
1824 if (!parameters || parameterCount < SkToInt(variations->num_axis)) {
1825 return variations->num_axis;
1826 }
1827
1828 for (FT_UInt i = 0; i < variations->num_axis; ++i) {
1829 parameters[i].tag = variations->axis[i].tag;
1830 parameters[i].min = SkFixedToScalar(variations->axis[i].minimum);
1831 parameters[i].def = SkFixedToScalar(variations->axis[i].def);
1832 parameters[i].max = SkFixedToScalar(variations->axis[i].maximum);
1833 FT_UInt flags = 0;
1834 bool hidden = !FT_Get_Var_Axis_Flags(variations, i, &flags) &&
1835 (flags & FT_VAR_AXIS_FLAG_HIDDEN);
1836 parameters[i].setHidden(hidden);
1837 }
1838
1839 return variations->num_axis;
1840}
1841
1843 AutoFTAccess fta(this);
1844 FT_Face face = fta.face();
1845 if (!face) {
1846 return 0;
1847 }
1848
1849 FT_ULong tableCount = 0;
1850 FT_Error error;
1851
1852 // When 'tag' is nullptr, returns number of tables in 'length'.
1853 error = FT_Sfnt_Table_Info(face, 0, nullptr, &tableCount);
1854 if (error) {
1855 return 0;
1856 }
1857
1858 if (tags) {
1859 for (FT_ULong tableIndex = 0; tableIndex < tableCount; ++tableIndex) {
1860 FT_ULong tableTag;
1861 FT_ULong tablelength;
1862 error = FT_Sfnt_Table_Info(face, tableIndex, &tableTag, &tablelength);
1863 if (error) {
1864 return 0;
1865 }
1866 tags[tableIndex] = static_cast<SkFontTableTag>(tableTag);
1867 }
1868 }
1869 return tableCount;
1870}
1871
1873 size_t length, void* data) const
1874{
1875 AutoFTAccess fta(this);
1876 FT_Face face = fta.face();
1877 if (!face) {
1878 return 0;
1879 }
1880
1881 FT_ULong tableLength = 0;
1882 FT_Error error;
1883
1884 // When 'length' is 0 it is overwritten with the full table length; 'offset' is ignored.
1885 error = FT_Load_Sfnt_Table(face, tag, 0, nullptr, &tableLength);
1886 if (error) {
1887 return 0;
1888 }
1889
1890 if (offset > tableLength) {
1891 return 0;
1892 }
1893 FT_ULong size = std::min((FT_ULong)length, tableLength - (FT_ULong)offset);
1894 if (data) {
1895 error = FT_Load_Sfnt_Table(face, tag, offset, reinterpret_cast<FT_Byte*>(data), &size);
1896 if (error) {
1897 return 0;
1898 }
1899 }
1900
1901 return size;
1902}
1903
1905 AutoFTAccess fta(this);
1906 FT_Face face = fta.face();
1907 if (!face) {
1908 return nullptr;
1909 }
1910
1911 FT_ULong tableLength = 0;
1912 FT_Error error;
1913
1914 // When 'length' is 0 it is overwritten with the full table length; 'offset' is ignored.
1915 error = FT_Load_Sfnt_Table(face, tag, 0, nullptr, &tableLength);
1916 if (error) {
1917 return nullptr;
1918 }
1919
1920 sk_sp<SkData> data = SkData::MakeUninitialized(tableLength);
1921 if (data) {
1922 error = FT_Load_Sfnt_Table(face, tag, 0,
1923 reinterpret_cast<FT_Byte*>(data->writable_data()), &tableLength);
1924 if (error) {
1925 data.reset();
1926 }
1927 }
1928 return data;
1929}
1930
1932 f_t_mutex().assertHeld();
1933 fFTFaceOnce([this]{ fFaceRec = SkTypeface_FreeType::FaceRec::Make(this); });
1934 return fFaceRec.get();
1935}
1936
1937std::unique_ptr<SkFontData> SkTypeface_FreeType::makeFontData() const {
1938 return this->onMakeFontData();
1939}
1940
1942 SkFontDescriptor* desc) {
1943 desc->setPaletteIndex(fontData.getPaletteIndex());
1944 int paletteOverrideCount = fontData.getPaletteOverrideCount();
1945 auto overrides = desc->setPaletteEntryOverrides(paletteOverrideCount);
1946 for (int i = 0; i < paletteOverrideCount; ++i) {
1947 overrides[i] = fontData.getPaletteOverrides()[i];
1948 }
1949}
1950
1951///////////////////////////////////////////////////////////////////////////////
1952///////////////////////////////////////////////////////////////////////////////
1953
1954SkTypeface_FreeTypeStream::SkTypeface_FreeTypeStream(std::unique_ptr<SkFontData> fontData,
1955 const SkString familyName,
1956 const SkFontStyle& style, bool isFixedPitch)
1957 : SkTypeface_FreeType(style, isFixedPitch)
1958 , fFamilyName(std::move(familyName))
1959 , fData(std::move(fontData))
1960{ }
1961
1963
1965 *familyName = fFamilyName;
1966}
1967
1968std::unique_ptr<SkStreamAsset> SkTypeface_FreeTypeStream::onOpenStream(int* ttcIndex) const {
1969 *ttcIndex = fData->getIndex();
1970 return fData->getStream()->duplicate();
1971}
1972
1973std::unique_ptr<SkFontData> SkTypeface_FreeTypeStream::onMakeFontData() const {
1974 return std::make_unique<SkFontData>(*fData);
1975}
1976
1978 SkFontStyle style = this->fontStyle();
1979 std::unique_ptr<SkFontData> data = this->cloneFontData(args, &style);
1980 if (!data) {
1981 return nullptr;
1982 }
1983
1984 SkString familyName;
1985 this->getFamilyName(&familyName);
1986
1987 return sk_make_sp<SkTypeface_FreeTypeStream>(
1988 std::move(data), familyName, style, this->isFixedPitch());
1989}
1990
1992 desc->setFamilyName(fFamilyName.c_str());
1993 desc->setStyle(this->fontStyle());
1996 *serialize = true;
1997}
1998
1999sk_sp<SkTypeface> SkTypeface_FreeType::MakeFromStream(std::unique_ptr<SkStreamAsset> stream,
2000 const SkFontArguments& args) {
2001 static SkFontScanner_FreeType scanner;
2002 bool isFixedPitch;
2003 SkFontStyle style;
2004 SkString name;
2005 SkFontScanner::AxisDefinitions axisDefinitions;
2006 if (!scanner.scanInstance(stream.get(), args.getCollectionIndex(), 0,
2007 &name, &style, &isFixedPitch, &axisDefinitions)) {
2008 return nullptr;
2009 }
2010
2011 const SkFontArguments::VariationPosition position = args.getVariationDesignPosition();
2012 AutoSTMalloc<4, SkFixed> axisValues(axisDefinitions.size());
2013 SkFontScanner_FreeType::computeAxisValues(axisDefinitions, position, axisValues, name, &style);
2014
2015 auto data = std::make_unique<SkFontData>(
2016 std::move(stream), args.getCollectionIndex(), args.getPalette().index,
2017 axisValues.get(), axisDefinitions.size(),
2018 args.getPalette().overrides, args.getPalette().overrideCount);
2019 return sk_make_sp<SkTypeface_FreeTypeStream>(std::move(data), name, style, isFixedPitch);
2020}
2021
2023 if (FT_New_Library(&gFTMemory, &fLibrary)) {
2024 return;
2025 }
2026 FT_Add_Default_Modules(fLibrary);
2027 FT_Set_Default_Properties(fLibrary);
2028}
2029
2031 if (fLibrary) {
2032 FT_Done_Library(fLibrary);
2033 }
2034}
2035
2036FT_Face SkFontScanner_FreeType::openFace(SkStreamAsset* stream, int ttcIndex,
2037 FT_Stream ftStream) const
2038{
2039 if (fLibrary == nullptr || stream == nullptr) {
2040 return nullptr;
2041 }
2042
2043 FT_Open_Args args;
2044 memset(&args, 0, sizeof(args));
2045
2046 const void* memoryBase = stream->getMemoryBase();
2047
2048 if (memoryBase) {
2049 args.flags = FT_OPEN_MEMORY;
2050 args.memory_base = (const FT_Byte*)memoryBase;
2051 args.memory_size = stream->getLength();
2052 } else {
2053 memset(ftStream, 0, sizeof(*ftStream));
2054 ftStream->size = stream->getLength();
2055 ftStream->descriptor.pointer = stream;
2056 ftStream->read = sk_ft_stream_io;
2057 ftStream->close = sk_ft_stream_close;
2058
2059 args.flags = FT_OPEN_STREAM;
2060 args.stream = ftStream;
2061 }
2062
2063 FT_Face face;
2064 if (FT_Open_Face(fLibrary, &args, ttcIndex, &face)) {
2065 return nullptr;
2066 }
2067 return face;
2068}
2069
2070bool SkFontScanner_FreeType::scanFile(SkStreamAsset* stream, int* numFaces) const {
2071 SkAutoMutexExclusive libraryLock(fLibraryMutex);
2072
2073 FT_StreamRec streamRec;
2074 SkUniqueFTFace face(this->openFace(stream, -1, &streamRec));
2075 if (!face) {
2076 return false;
2077 }
2078
2079 *numFaces = face->num_faces;
2080 return true;
2081}
2082
2084 int faceIndex,
2085 int* numInstances) const {
2086 SkAutoMutexExclusive libraryLock(fLibraryMutex);
2087
2088 FT_StreamRec streamRec;
2089 SkUniqueFTFace face(this->openFace(stream, -(faceIndex + 1), &streamRec));
2090 if (!face) {
2091 return false;
2092 }
2093
2094 *numInstances = face->style_flags >> 16;
2095 return true;
2096}
2097
2099 int faceIndex,
2100 int instanceIndex,
2101 SkString* name,
2102 SkFontStyle* style,
2103 bool* isFixedPitch,
2104 AxisDefinitions* axes) const {
2105
2106 SkAutoMutexExclusive libraryLock(fLibraryMutex);
2107
2108 FT_StreamRec streamRec;
2109 SkUniqueFTFace face(this->openFace(stream, (instanceIndex << 16) + faceIndex, &streamRec));
2110 if (!face) {
2111 return false;
2112 }
2113
2114 int weight = SkFontStyle::kNormal_Weight;
2117 if (face->style_flags & FT_STYLE_FLAG_BOLD) {
2119 }
2120 if (face->style_flags & FT_STYLE_FLAG_ITALIC) {
2122 }
2123
2124 bool hasAxes = face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS;
2125 TT_OS2* os2 = static_cast<TT_OS2*>(FT_Get_Sfnt_Table(face.get(), ft_sfnt_os2));
2126 bool hasOs2 = os2 && os2->version != 0xffff;
2127
2128 PS_FontInfoRec psFontInfo;
2129
2130 if (hasOs2) {
2131 weight = os2->usWeightClass;
2132 width = os2->usWidthClass;
2133
2134 // OS/2::fsSelection bit 9 indicates oblique.
2135 if (SkToBool(os2->fsSelection & (1u << 9))) {
2137 }
2138 }
2139
2140 // Let variable axes override properties from the OS/2 table.
2141 if (hasAxes) {
2142 AxisDefinitions axisDefinitions;
2143 if (GetAxes(face.get(), &axisDefinitions)) {
2144 size_t numAxes = axisDefinitions.size();
2145 static constexpr SkFourByteTag wghtTag = SkSetFourByteTag('w', 'g', 'h', 't');
2146 static constexpr SkFourByteTag wdthTag = SkSetFourByteTag('w', 'd', 't', 'h');
2147 static constexpr SkFourByteTag slntTag = SkSetFourByteTag('s', 'l', 'n', 't');
2148 std::optional<size_t> wghtIndex;
2149 std::optional<size_t> wdthIndex;
2150 std::optional<size_t> slntIndex;
2151 for(size_t i = 0; i < numAxes; ++i) {
2152 if (axisDefinitions[i].fTag == wghtTag) {
2153 // Rough validity check, sufficient spread and ranges within 0-1000.
2154 SkScalar wghtRange = axisDefinitions[i].fMaximum - axisDefinitions[i].fMinimum;
2155 if (wghtRange > 5 && wghtRange <= 1000 && axisDefinitions[i].fMaximum <= 1000) {
2156 wghtIndex = i;
2157 }
2158 }
2159 if (axisDefinitions[i].fTag == wdthTag) {
2160 // Rough validity check, sufficient spread and are ranges within 0-500.
2161 SkScalar wdthRange = axisDefinitions[i].fMaximum - axisDefinitions[i].fMinimum;
2162 if (wdthRange > 0 && wdthRange <= 500 && axisDefinitions[i].fMaximum <= 500) {
2163 wdthIndex = i;
2164 }
2165 }
2166 if (axisDefinitions[i].fTag == slntTag) {
2167 slntIndex = i;
2168 }
2169 }
2170 AutoSTMalloc<4, FT_Fixed> coords(numAxes);
2171 if ((wghtIndex || wdthIndex || slntIndex) &&
2172 !FT_Get_Var_Design_Coordinates(face.get(), numAxes, coords.get())) {
2173 if (wghtIndex) {
2174 SkASSERT(*wghtIndex < numAxes);
2175 weight = SkFixedRoundToInt(coords[*wghtIndex]);
2176 }
2177 if (wdthIndex) {
2178 SkASSERT(*wdthIndex < numAxes);
2179 SkScalar wdthValue = SkFixedToScalar(coords[*wdthIndex]);
2181 }
2182 if (slntIndex) {
2183 SkASSERT(*slntIndex < numAxes);
2184 // https://docs.microsoft.com/en-us/typography/opentype/spec/dvaraxistag_slnt
2185 // "Scale interpretation: Values can be interpreted as the angle,
2186 // in counter-clockwise degrees, of oblique slant from whatever
2187 // the designer considers to be upright for that font design."
2188 if (SkFixedToScalar(coords[*slntIndex]) < 0) {
2190 }
2191 }
2192 }
2193 }
2194 }
2195
2196 if (!hasOs2 && !hasAxes && 0 == FT_Get_PS_Font_Info(face.get(), &psFontInfo) && psFontInfo.weight) {
2197 static const struct {
2198 char const * const name;
2199 int const weight;
2200 } commonWeights [] = {
2201 // There are probably more common names, but these are known to exist.
2202 { "all", SkFontStyle::kNormal_Weight }, // Multiple Masters usually default to normal.
2203 { "black", SkFontStyle::kBlack_Weight },
2204 { "bold", SkFontStyle::kBold_Weight },
2207 { "demibold", SkFontStyle::kSemiBold_Weight },
2208 { "extra", SkFontStyle::kExtraBold_Weight },
2209 { "extrabold", SkFontStyle::kExtraBold_Weight },
2210 { "extralight", SkFontStyle::kExtraLight_Weight },
2211 { "hairline", SkFontStyle::kThin_Weight },
2212 { "heavy", SkFontStyle::kBlack_Weight },
2213 { "light", SkFontStyle::kLight_Weight },
2214 { "medium", SkFontStyle::kMedium_Weight },
2215 { "normal", SkFontStyle::kNormal_Weight },
2216 { "plain", SkFontStyle::kNormal_Weight },
2217 { "regular", SkFontStyle::kNormal_Weight },
2218 { "roman", SkFontStyle::kNormal_Weight },
2219 { "semibold", SkFontStyle::kSemiBold_Weight },
2220 { "standard", SkFontStyle::kNormal_Weight },
2221 { "thin", SkFontStyle::kThin_Weight },
2222 { "ultra", SkFontStyle::kExtraBold_Weight },
2223 { "ultrablack", SkFontStyle::kExtraBlack_Weight },
2224 { "ultrabold", SkFontStyle::kExtraBold_Weight },
2225 { "ultraheavy", SkFontStyle::kExtraBlack_Weight },
2226 { "ultralight", SkFontStyle::kExtraLight_Weight },
2227 };
2228 int const index = SkStrLCSearch(&commonWeights[0].name, std::size(commonWeights),
2229 psFontInfo.weight, sizeof(commonWeights[0]));
2230 if (index >= 0) {
2231 weight = commonWeights[index].weight;
2232 } else {
2233 LOG_INFO("Do not know weight for: %s (%s) \n", face->family_name, psFontInfo.weight);
2234 }
2235 }
2236
2237 if (name != nullptr) {
2238 name->set(face->family_name);
2239 }
2240 if (style != nullptr) {
2241 *style = SkFontStyle(weight, width, slant);
2242 }
2243 if (isFixedPitch != nullptr) {
2244 *isFixedPitch = FT_IS_FIXED_WIDTH(face);
2245 }
2246
2247 if (axes != nullptr && !GetAxes(face.get(), axes)) {
2248 return false;
2249 }
2250 return true;
2251}
2252
2254 SkASSERT(face && axes);
2255 if (face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS) {
2256 FT_MM_Var* variations = nullptr;
2257 FT_Error err = FT_Get_MM_Var(face, &variations);
2258 if (err) {
2259 LOG_INFO("INFO: font %s claims to have variations, but none found.\n",
2260 face->family_name);
2261 return false;
2262 }
2263 UniqueVoidPtr autoFreeVariations(variations);
2264
2265 axes->reset(variations->num_axis);
2266 for (FT_UInt i = 0; i < variations->num_axis; ++i) {
2267 const FT_Var_Axis& ftAxis = variations->axis[i];
2268 (*axes)[i].fTag = ftAxis.tag;
2269 (*axes)[i].fMinimum = SkFT_FixedToScalar(ftAxis.minimum);
2270 (*axes)[i].fDefault = SkFT_FixedToScalar(ftAxis.def);
2271 (*axes)[i].fMaximum = SkFT_FixedToScalar(ftAxis.maximum);
2272 }
2273 }
2274 return true;
2275}
2276
2278 AxisDefinitions axisDefinitions,
2280 SkFixed* axisValues,
2281 const SkString& name,
2282 SkFontStyle* style,
2284{
2285 static constexpr SkFourByteTag wghtTag = SkSetFourByteTag('w', 'g', 'h', 't');
2286 static constexpr SkFourByteTag wdthTag = SkSetFourByteTag('w', 'd', 't', 'h');
2287 static constexpr SkFourByteTag slntTag = SkSetFourByteTag('s', 'l', 'n', 't');
2288 int weight = SkFontStyle::kNormal_Weight;
2291 if (style) {
2292 weight = style->weight();
2293 width = style->width();
2294 slant = style->slant();
2295 }
2296
2297 for (int i = 0; i < axisDefinitions.size(); ++i) {
2298 const AxisDefinition& axisDefinition = axisDefinitions[i];
2299 const SkScalar axisMin = axisDefinition.fMinimum;
2300 const SkScalar axisMax = axisDefinition.fMaximum;
2301
2302 // Start with the default value.
2303 axisValues[i] = SkScalarToFixed(axisDefinition.fDefault);
2304
2305 // Then the current value.
2306 if (current) {
2307 for (int j = 0; j < axisDefinitions.size(); ++j) {
2308 const auto& coordinate = current[j];
2309 if (axisDefinition.fTag == coordinate.axis) {
2310 const SkScalar axisValue = SkTPin(coordinate.value, axisMin, axisMax);
2311 axisValues[i] = SkScalarToFixed(axisValue);
2312 break;
2313 }
2314 }
2315 }
2316
2317 // Then the requested value.
2318 // The position may be over specified. If there are multiple values for a given axis,
2319 // use the last one since that's what css-fonts-4 requires.
2320 for (int j = position.coordinateCount; j --> 0;) {
2321 const auto& coordinate = position.coordinates[j];
2322 if (axisDefinition.fTag == coordinate.axis) {
2323 const SkScalar axisValue = SkTPin(coordinate.value, axisMin, axisMax);
2324 if (coordinate.value != axisValue) {
2325 LOG_INFO("Requested font axis value out of range: "
2326 "%s '%c%c%c%c' %f; pinned to %f.\n",
2327 name.c_str(),
2328 (axisDefinition.fTag >> 24) & 0xFF,
2329 (axisDefinition.fTag >> 16) & 0xFF,
2330 (axisDefinition.fTag >> 8) & 0xFF,
2331 (axisDefinition.fTag ) & 0xFF,
2332 SkScalarToDouble(coordinate.value),
2333 SkScalarToDouble(axisValue));
2334 }
2335 axisValues[i] = SkScalarToFixed(axisValue);
2336 break;
2337 }
2338 }
2339
2340 if (style) {
2341 if (axisDefinition.fTag == wghtTag) {
2342 // Rough validity check, is there sufficient spread and are ranges within 0-1000.
2343 SkScalar wghtRange = axisMax - axisMin;
2344 if (wghtRange > 5 && wghtRange <= 1000 && axisMax <= 1000) {
2345 weight = SkFixedRoundToInt(axisValues[i]);
2346 }
2347 }
2348 if (axisDefinition.fTag == wdthTag) {
2349 // Rough validity check, is there a spread and are ranges within 0-500.
2350 SkScalar wdthRange = axisMax - axisMin;
2351 if (wdthRange > 0 && wdthRange <= 500 && axisMax <= 500) {
2352 SkScalar wdthValue = SkFixedToScalar(axisValues[i]);
2354 }
2355 }
2356 if (axisDefinition.fTag == slntTag) {
2357 // https://docs.microsoft.com/en-us/typography/opentype/spec/dvaraxistag_slnt
2358 // "Scale interpretation: Values can be interpreted as the angle,
2359 // in counter-clockwise degrees, of oblique slant from whatever
2360 // the designer considers to be upright for that font design."
2361 if (axisValues[i] == 0) {
2363 } else {
2365 }
2366 }
2367 }
2368 // TODO: warn on defaulted axis?
2369 }
2370
2371 if (style) {
2372 *style = SkFontStyle(weight, width, slant);
2373 }
2374
2376 // Check for axis specified, but not matched in font.
2377 for (int i = 0; i < position.coordinateCount; ++i) {
2378 SkFourByteTag skTag = position.coordinates[i].axis;
2379 bool found = false;
2380 for (int j = 0; j < axisDefinitions.size(); ++j) {
2381 if (skTag == axisDefinitions[j].fTag) {
2382 found = true;
2383 break;
2384 }
2385 }
2386 if (!found) {
2387 LOG_INFO("Requested font axis not found: %s '%c%c%c%c'\n",
2388 name.c_str(),
2389 (skTag >> 24) & 0xFF,
2390 (skTag >> 16) & 0xFF,
2391 (skTag >> 8) & 0xFF,
2392 (skTag) & 0xFF);
2393 }
2394 }
2395 )
2396}
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition DM.cpp:213
uint16_t glyphs[5]
int count
@ kPremul_SkAlphaType
pixel components are premultiplied by alpha
Definition SkAlphaType.h:29
#define SkDEBUGFAIL(message)
Definition SkAssert.h:118
#define SkASSERT(cond)
Definition SkAssert.h:116
#define SkColorGetR(color)
Definition SkColor.h:65
#define SkColorGetG(color)
Definition SkColor.h:69
uint32_t SkColor
Definition SkColor.h:37
constexpr SkColor SK_ColorTRANSPARENT
Definition SkColor.h:99
static constexpr SkColor SkColorSetARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b)
Definition SkColor.h:49
#define SkColorGetA(color)
Definition SkColor.h:61
#define SkColorGetB(color)
Definition SkColor.h:73
#define SkDEBUGCODE(...)
Definition SkDebug.h:23
#define SkEndian_SwapBE32(n)
Definition SkEndian.h:136
#define SkFDot6Floor(x)
Definition SkFDot6.h:52
#define SkFDot6ToScalar(x)
Definition SkFDot6.h:65
#define SkFDot6ToFloat
Definition SkFDot6.h:66
#define SkScalarToFDot6(x)
Definition SkFDot6.h:64
int32_t SkFixed
Definition SkFixed.h:25
#define SkScalarToFixed(x)
Definition SkFixed.h:125
#define SkFixedToScalar(x)
Definition SkFixed.h:124
#define SkFixedFloorToInt(x)
Definition SkFixed.h:78
#define SkFixedRoundToInt(x)
Definition SkFixed.h:76
static void sk_ft_free(FT_Memory, void *block)
static SkAdvancedTypefaceMetrics::FontType get_font_type(FT_Face face)
static bool is_opentype_font_data_standard_format(const SkTypeface &typeface)
static bool canEmbed(FT_Face face)
static int GetVariationDesignPosition(AutoFTAccess &fta, SkFontArguments::VariationPosition::Coordinate coordinates[], int coordinateCount)
#define LOG_INFO(...)
static FreeTypeLibrary * gFTLibrary
SkCallableTraits< FT_Alloc_Func >::argument< 1 >::type FT_Alloc_size_t
static bool isLCD(const SkScalerContextRec &rec)
static bool bothZero(SkScalar a, SkScalar b)
static void sk_ft_stream_close(FT_Stream)
static FT_Int chooseBitmapStrike(FT_Face face, FT_F26Dot6 scaleY)
FT_MemoryRec_ gFTMemory
static void * sk_ft_realloc(FT_Memory, FT_Alloc_size_t cur_size, FT_Alloc_size_t new_size, void *block)
static SkMutex & f_t_mutex()
static bool canSubset(FT_Face face)
static bool isAxisAligned(const SkScalerContextRec &rec)
constexpr int kMaxC2GCacheCount
static SkScalar SkFT_FixedToScalar(FT_Fixed x)
static unsigned long sk_ft_stream_io(FT_Stream ftStream, unsigned long offset, unsigned char *buffer, unsigned long count)
#define SK_OUTLINE_EMBOLDEN_DIVISOR
static void * sk_ft_alloc(FT_Memory, FT_Alloc_size_t size)
#define FT_PIXEL_MODE_BGRA
#define FT_LOAD_COLOR
#define SK_TRACEFTR(ERR,...)
signed long FT_Pos
struct FT_FaceRec_ * FT_Face
SkFontHinting
Definition SkFontTypes.h:18
@ kNormal
glyph outlines modified to improve constrast
@ kNone
glyph outlines unchanged
@ kSlight
minimal modification to improve constrast
@ kFull
modifies glyph outlines for maximum constrast
static void sk_bzero(void *buffer, size_t size)
Definition SkMalloc.h:105
SK_API void sk_free(void *)
static void * sk_malloc_canfail(size_t size)
Definition SkMalloc.h:93
SK_API void * sk_realloc_throw(void *buffer, size_t size)
uint32_t SK_OT_ULONG
sk_sp< T > sk_ref_sp(T *obj)
Definition SkRefCnt.h:381
#define SkScalarToDouble(x)
Definition SkScalar.h:63
#define SkIntToScalar(x)
Definition SkScalar.h:57
#define SK_ScalarInfinity
Definition SkScalar.h:26
static constexpr const T & SkTPin(const T &x, const T &lo, const T &hi)
Definition SkTPin.h:19
int SkStrLCSearch(const char *const *base, int count, const char target[], size_t len, size_t elemSize)
Definition SkTSearch.cpp:64
constexpr uint16_t SkToU16(S x)
Definition SkTo.h:24
constexpr int SkToInt(S x)
Definition SkTo.h:29
static constexpr bool SkToBool(const T &x)
Definition SkTo.h:35
constexpr unsigned SkToUInt(S x)
Definition SkTo.h:30
uint32_t SkFontTableTag
Definition SkTypeface.h:41
struct FT_BBox_ FT_BBox
struct FT_StreamRec_ * FT_Stream
struct FT_FaceRec_ * FT_Face
struct FT_LibraryRec_ * FT_Library
int32_t SkUnichar
Definition SkTypes.h:175
uint16_t SkGlyphID
Definition SkTypes.h:179
uint32_t SkFourByteTag
Definition SkTypes.h:166
static constexpr SkFourByteTag SkSetFourByteTag(char a, char b, char c, char d)
Definition SkTypes.h:167
AutoFTAccess(const SkTypeface_FreeType *tf)
void setPixels(void *pixels)
Definition SkBitmap.cpp:207
bool setInfo(const SkImageInfo &imageInfo, size_t rowBytes=0)
Definition SkBitmap.cpp:114
void translate(SkScalar dx, SkScalar dy)
void clear(SkColor color)
Definition SkCanvas.h:1199
int findGlyphIndex(SkUnichar c) const
void insertCharAndGlyph(int index, SkUnichar, SkGlyphID)
static sk_sp< SkData > MakeUninitialized(size_t length)
Definition SkData.cpp:116
const SkFontArguments::Palette::Override * getPaletteOverrides() const
int getPaletteIndex() const
int getPaletteOverrideCount() const
static SkFontStyle::Width SkFontStyleWidthForWidthAxisValue(SkScalar width)
void setFactoryId(SkTypeface::FactoryId factoryId)
static bool GetAxes(FT_Face face, AxisDefinitions *axes)
bool scanFace(SkStreamAsset *stream, int faceIndex, int *numInstances) const override
static void computeAxisValues(AxisDefinitions axisDefinitions, const SkFontArguments::VariationPosition position, SkFixed *axisValues, const SkString &name, SkFontStyle *style, const SkFontArguments::VariationPosition::Coordinate *currentPosition=nullptr)
bool scanInstance(SkStreamAsset *stream, int faceIndex, int instanceIndex, SkString *name, SkFontStyle *style, bool *isFixedPitch, AxisDefinitions *axes) const override
bool scanFile(SkStreamAsset *stream, int *numFaces) const override
Slant slant() const
Definition SkFontStyle.h:64
int width() const
Definition SkFontStyle.h:63
int weight() const
Definition SkFontStyle.h:62
int top() const
Definition SkGlyph.h:511
size_t rowBytes() const
Definition SkGlyph.cpp:233
uint16_t extraBits() const
Definition SkGlyph.h:519
SkGlyphID getGlyphID() const
Definition SkGlyph.h:429
size_t imageSize() const
Definition SkGlyph.cpp:241
SkMask mask() const
Definition SkGlyph.cpp:125
SkMask::Format maskFormat() const
Definition SkGlyph.h:500
int height() const
Definition SkGlyph.h:513
SkFixed getSubYFixed() const
Definition SkGlyph.h:432
SkFixed getSubXFixed() const
Definition SkGlyph.h:431
int width() const
Definition SkGlyph.h:512
int left() const
Definition SkGlyph.h:510
static OpenTypeSVGDecoderFactory GetOpenTypeSVGDecoderFactory()
SkMatrix & postTranslate(SkScalar dx, SkScalar dy)
Definition SkMatrix.cpp:281
SkScalar getSkewY() const
Definition SkMatrix.h:430
SkScalar getSkewX() const
Definition SkMatrix.h:438
SkScalar getScaleX() const
Definition SkMatrix.h:415
SkScalar getScaleY() const
Definition SkMatrix.h:422
SkMatrix & preScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py)
Definition SkMatrix.cpp:315
bool mapRect(SkRect *dst, const SkRect &src, SkApplyPerspectiveClip pc=SkApplyPerspectiveClip::kYes) const
static sk_sp< LocalizedStrings_NameTable > MakeForFamilyNames(const SkTypeface &typeface)
SkCanvas * beginRecording(const SkRect &bounds, sk_sp< SkBBoxHierarchy > bbh)
sk_sp< SkPicture > finishRecordingAsPicture()
sk_sp< SkDrawable > finishRecordingAsDrawable()
bool generatePath(const SkGlyph &glyph, SkPath *path) override
GlyphMetrics generateMetrics(const SkGlyph &, SkArenaAlloc *) override
SkScalerContext_FreeType(sk_sp< SkTypeface_FreeType >, const SkScalerContextEffects &, const SkDescriptor *desc)
void generateFontMetrics(SkFontMetrics *) override
void generateImage(const SkGlyph &, void *) override
sk_sp< SkDrawable > generateDrawable(const SkGlyph &) override
SkScalerContextRec fRec
const SkMaskGamma::PreBlend fPreBlend
SkTypeface * getTypeface() const
bool isSubpixel() const
static std::unique_ptr< SkScalerContext > MakeEmpty(sk_sp< SkTypeface > typeface, const SkScalerContextEffects &effects, const SkDescriptor *desc)
bool isVertical() const
bool isLinearMetrics() const
const char * c_str() const
Definition SkString.h:133
sk_sp< SkTypeface > onMakeClone(const SkFontArguments &) const override
void onGetFamilyName(SkString *familyName) const override
void onGetFontDescriptor(SkFontDescriptor *, bool *serialize) const override
SkTypeface_FreeTypeStream(std::unique_ptr< SkFontData > fontData, const SkString familyName, const SkFontStyle &style, bool isFixedPitch)
std::unique_ptr< SkStreamAsset > onOpenStream(int *ttcIndex) const override
std::unique_ptr< SkFontData > onMakeFontData() const override
static std::unique_ptr< FaceRec > Make(const SkTypeface_FreeType *typeface)
std::unique_ptr< SkStreamAsset > fSkStream
std::unique_ptr< SkColor[]> fSkPalette
void getPostScriptGlyphNames(SkString *dstArray) const override
sk_sp< SkData > onCopyTableData(SkFontTableTag) const override
std::unique_ptr< SkAdvancedTypefaceMetrics > onGetAdvancedMetrics() const override
void onCharsToGlyphs(const SkUnichar uni[], int count, SkGlyphID glyphs[]) const override
std::unique_ptr< SkScalerContext > onCreateScalerContext(const SkScalerContextEffects &, const SkDescriptor *) const override
int onGetVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[], int coordinateCount) const override
bool onGetKerningPairAdjustments(const uint16_t glyphs[], int count, int32_t adjustments[]) const override
int onGetUPEM() const override
int onGetTableTags(SkFontTableTag tags[]) const override
bool onGlyphMaskNeedsCurrentColor() const override
int onGetVariationDesignParameters(SkFontParameters::Variation::Axis parameters[], int parameterCount) const override
std::unique_ptr< SkFontData > makeFontData() const
std::unique_ptr< SkFontData > cloneFontData(const SkFontArguments &, SkFontStyle *style) const
virtual std::unique_ptr< SkFontData > onMakeFontData() const =0
size_t onGetTableData(SkFontTableTag, size_t offset, size_t length, void *data) const override
void onFilterRec(SkScalerContextRec *) const override
int onCountGlyphs() const override
SkTypeface_FreeType(const SkFontStyle &style, bool isFixedPitch)
LocalizedStrings * onCreateFamilyNameIterator() const override
static sk_sp< SkTypeface > MakeFromStream(std::unique_ptr< SkStreamAsset >, const SkFontArguments &)
static void FontDataPaletteToDescriptorPalette(const SkFontData &, SkFontDescriptor *)
static int GetUnitsPerEm(FT_Face face)
void getGlyphToUnicodeMap(SkUnichar *) const override
bool onGetPostScriptName(SkString *) const override
SkTypefaceID uniqueID() const
Definition SkTypeface.h:101
void getFamilyName(SkString *name) const
SkFontStyle fontStyle() const
Definition SkTypeface.h:55
void serialize(SkWStream *, SerializeBehavior=SerializeBehavior::kIncludeDataIfLocal) const
bool isFixedPitch() const
Definition SkTypeface.h:68
size_t getTableSize(SkFontTableTag) const
std::unique_ptr< SkStreamAsset > openStream(int *ttcIndex) const
SkFourByteTag FactoryId
Definition SkTypeface.h:335
T * release()
Definition SkRefCnt.h:324
void reset(int n)
Definition SkTArray.h:139
int size() const
Definition SkTArray.h:416
float SkScalar
Definition extension.cpp:12
static bool b
struct MyStruct s
struct MyStruct a[10]
FlutterSemanticsFlag flags
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
static const uint8_t buffer[]
const uint8_t uint32_t uint32_t GError ** error
const char * name
Definition fuchsia.cc:50
size_t length
double x
unsigned useCenter Optional< SkMatrix > matrix
Definition SkRecords.h:258
Optional< SkRect > bounds
Definition SkRecords.h:189
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot data
Definition switches.h:41
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network policy
Definition switches.h:248
std::unique_ptr< void, SkOverloadedFunctionObject< void(void *), sk_free > > UniqueVoidPtr
Definition ref_ptr.h:256
SkScalar h
int32_t width
Point offset
@ kNotEmbeddable_FontFlag
May not be embedded.
@ kAltDataFormat_FontFlag
Data compressed. Table access may still work.
@ kNotSubsettable_FontFlag
May not be subset.
@ kVariable_FontFlag
May be true for Type1, CFF, or TrueType fonts.
SkScalar fTop
greatest extent above origin of any glyph bounding box, typically negative; deprecated with variable ...
SkScalar fLeading
distance to add between lines, typically positive or zero
SkScalar fAvgCharWidth
average character width, zero if unknown
SkScalar fStrikeoutPosition
distance from baseline to bottom of stroke, typically negative
SkScalar fStrikeoutThickness
strikeout thickness
SkScalar fMaxCharWidth
maximum character width, zero if unknown
SkScalar fBottom
greatest extent below origin of any glyph bounding box, typically positive; deprecated with variable ...
uint32_t fFlags
FontMetricsFlags indicating which metrics are valid.
SkScalar fAscent
distance to reserve above baseline, typically negative
SkScalar fXHeight
height of lower-case 'x', zero if unknown, typically negative
SkScalar fUnderlineThickness
underline thickness
@ kStrikeoutPositionIsValid_Flag
set if fStrikeoutPosition is valid
@ kStrikeoutThicknessIsValid_Flag
set if fStrikeoutThickness is valid
@ kUnderlinePositionIsValid_Flag
set if fUnderlinePosition is valid
@ kUnderlineThicknessIsValid_Flag
set if fUnderlineThickness is valid
@ kBoundsInvalid_Flag
set if fTop, fBottom, fXMin, fXMax invalid
SkScalar fDescent
distance to reserve below baseline, typically positive
SkScalar fCapHeight
height of an upper-case letter, zero if unknown, typically negative
SkScalar fXMin
greatest extent to left of origin of any glyph bounding box, typically negative; deprecated with vari...
SkScalar fUnderlinePosition
distance from baseline to top of stroke, typically positive
SkScalar fXMax
greatest extent to right of origin of any glyph bounding box, typically positive; deprecated with var...
static constexpr SkIRect MakeLTRB(int32_t l, int32_t t, int32_t r, int32_t b)
Definition SkRect.h:91
static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at)
@ kLCD16_Format
565 alpha for r/g/b
Definition SkMask.h:31
@ kARGB32_Format
SkPMColor.
Definition SkMask.h:30
@ kBW_Format
1bit per pixel mask (e.g. monochrome)
Definition SkMask.h:27
const SkIRect fBounds
Definition SkMask.h:42
float fX
x-axis value
float fY
y-axis value
constexpr float y() const
constexpr float x() const
static SkRect Make(const SkISize &size)
Definition SkRect.h:669
static constexpr SkRect MakeEmpty()
Definition SkRect.h:595
bool isFinite() const
Definition SkRect.h:711
static constexpr SkRect MakeXYWH(float x, float y, float w, float h)
Definition SkRect.h:659
static constexpr SkRect MakeLTRB(float l, float t, float r, float b)
Definition SkRect.h:646
static const SK_OT_ULONG TAG
static const SK_OT_ULONG TAG
static const SK_OT_ULONG TAG
bool drawCOLRv1Glyph(FT_Face, const SkGlyph &, LoadGlyphFlags, SkSpan< SkColor > palette, SkCanvas *) const
bool drawSVGGlyph(FT_Face, const SkGlyph &, LoadGlyphFlags, SkSpan< SkColor > palette, SkCanvas *) const
static bool computeColrV1GlyphBoundingBox(FT_Face, SkGlyphID, SkRect *bounds)
void generateGlyphImage(FT_Face, const SkGlyph &, void *, const SkMatrix &bitmapTransform, const SkMaskGamma::PreBlend &) const
bool generateGlyphPath(FT_Face, SkPath *) const
void init(SkColor fgColor, SkScalerContext::Flags)
bool drawCOLRv0Glyph(FT_Face, const SkGlyph &, LoadGlyphFlags, SkSpan< SkColor > palette, SkCanvas *) const
SkMask::Format fMaskFormat
bool computeMatrices(PreMatrixScale preMatrixScale, SkVector *scale, SkMatrix *remaining, SkMatrix *remainingWithoutRotation=nullptr, SkMatrix *remainingRotation=nullptr, SkMatrix *total=nullptr)
SkScalar fPost2x2[2][2]
SkFontHinting getHinting() const
void setHinting(SkFontHinting)
static const SK_OT_ULONG TAG