Flutter Engine
The Flutter Engine
Classes | Public Member Functions | Protected Member Functions | List of all members
SkScalerContext_FreeType Class Reference
Inheritance diagram for SkScalerContext_FreeType:
SkScalerContext

Public Member Functions

 SkScalerContext_FreeType (sk_sp< SkTypeface_FreeType >, const SkScalerContextEffects &, const SkDescriptor *desc)
 
 ~SkScalerContext_FreeType () override
 
bool success () const
 
- Public Member Functions inherited from SkScalerContext
 SkScalerContext (sk_sp< SkTypeface >, const SkScalerContextEffects &, const SkDescriptor *)
 
virtual ~SkScalerContext ()
 
SkTypefacegetTypeface () const
 
SkMask::Format getMaskFormat () const
 
bool isSubpixel () const
 
bool isLinearMetrics () const
 
bool isVertical () const
 
SkGlyph makeGlyph (SkPackedGlyphID, SkArenaAlloc *)
 
void getImage (const SkGlyph &)
 
void getPath (SkGlyph &, SkArenaAlloc *)
 
sk_sp< SkDrawablegetDrawable (SkGlyph &)
 
void getFontMetrics (SkFontMetrics *)
 
const SkScalerContextRecgetRec () const
 
SkScalerContextEffects getEffects () const
 
SkAxisAlignment computeAxisAlignmentForHText () const
 

Protected Member Functions

GlyphMetrics generateMetrics (const SkGlyph &, SkArenaAlloc *) override
 
void generateImage (const SkGlyph &, void *) override
 
bool generatePath (const SkGlyph &glyph, SkPath *path) override
 
sk_sp< SkDrawablegenerateDrawable (const SkGlyph &) override
 
void generateFontMetrics (SkFontMetrics *) override
 
- Protected Member Functions inherited from SkScalerContext
virtual GlyphMetrics generateMetrics (const SkGlyph &, SkArenaAlloc *)=0
 
virtual void generateImage (const SkGlyph &glyph, void *imageBuffer)=0
 
virtual bool generatePath (const SkGlyph &, SkPath *)=0
 
virtual sk_sp< SkDrawablegenerateDrawable (const SkGlyph &)
 
virtual void generateFontMetrics (SkFontMetrics *)=0
 
void forceGenerateImageFromPath ()
 
void forceOffGenerateImageFromPath ()
 

Additional Inherited Members

- Public Types inherited from SkScalerContext
enum  Flags {
  kFrameAndFill_Flag = 0x0001 , kUnused = 0x0002 , kEmbeddedBitmapText_Flag = 0x0004 , kEmbolden_Flag = 0x0008 ,
  kSubpixelPositioning_Flag = 0x0010 , kForceAutohinting_Flag = 0x0020 , kHinting_Shift = 7 , kHintingBit1_Flag = 0x0080 ,
  kHintingBit2_Flag = 0x0100 , kLCD_Vertical_Flag = 0x0200 , kLCD_BGROrder_Flag = 0x0400 , kGenA8FromLCD_Flag = 0x0800 ,
  kLinearMetrics_Flag = 0x1000 , kBaselineSnap_Flag = 0x2000 , kNeedsForegroundColor_Flag = 0x4000
}
 
enum  { kHinting_Mask = kHintingBit1_Flag | kHintingBit2_Flag }
 
- Static Public Member Functions inherited from SkScalerContext
static size_t GetGammaLUTSize (SkScalar contrast, SkScalar deviceGamma, int *width, int *height)
 
static bool GetGammaLUTData (SkScalar contrast, SkScalar deviceGamma, uint8_t *data)
 
static void MakeRecAndEffects (const SkFont &font, const SkPaint &paint, const SkSurfaceProps &surfaceProps, SkScalerContextFlags scalerContextFlags, const SkMatrix &deviceMatrix, SkScalerContextRec *rec, SkScalerContextEffects *effects)
 
static void MakeRecAndEffectsFromFont (const SkFont &font, SkScalerContextRec *rec, SkScalerContextEffects *effects)
 
static std::unique_ptr< SkScalerContextMakeEmpty (sk_sp< SkTypeface > typeface, const SkScalerContextEffects &effects, const SkDescriptor *desc)
 
static SkDescriptorAutoDescriptorGivenRecAndEffects (const SkScalerContextRec &rec, const SkScalerContextEffects &effects, SkAutoDescriptor *ad)
 
static std::unique_ptr< SkDescriptorDescriptorGivenRecAndEffects (const SkScalerContextRec &rec, const SkScalerContextEffects &effects)
 
static void DescriptorBufferGiveRec (const SkScalerContextRec &rec, void *buffer)
 
static bool CheckBufferSizeForRec (const SkScalerContextRec &rec, const SkScalerContextEffects &effects, size_t size)
 
static SkMaskGamma::PreBlend GetMaskPreBlend (const SkScalerContextRec &rec)
 
static SkDescriptorCreateDescriptorAndEffectsUsingPaint (const SkFont &, const SkPaint &, const SkSurfaceProps &, SkScalerContextFlags scalerContextFlags, const SkMatrix &deviceMatrix, SkAutoDescriptor *ad, SkScalerContextEffects *effects)
 
- Static Protected Member Functions inherited from SkScalerContext
static void GenerateMetricsFromPath (SkGlyph *glyph, const SkPath &path, SkMask::Format format, bool verticalLCD, bool a8FromLCD, bool hairline)
 
static void SaturateGlyphBounds (SkGlyph *glyph, SkRect &&)
 
static void SaturateGlyphBounds (SkGlyph *glyph, SkIRect const &)
 
static void GenerateImageFromPath (SkMaskBuilder &dst, const SkPath &path, const SkMaskGamma::PreBlend &maskPreBlend, bool doBGR, bool verticalLCD, bool a8FromLCD, bool hairline)
 
- Protected Attributes inherited from SkScalerContext
SkScalerContextRec fRec
 
const SkMaskGamma::PreBlend fPreBlend
 

Detailed Description

Definition at line 440 of file SkFontHost_FreeType.cpp.

Constructor & Destructor Documentation

◆ SkScalerContext_FreeType()

SkScalerContext_FreeType::SkScalerContext_FreeType ( sk_sp< SkTypeface_FreeType typeface,
const SkScalerContextEffects effects,
const SkDescriptor desc 
)

Definition at line 892 of file SkFontHost_FreeType.cpp.

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}
#define SkScalarToFDot6(x)
Definition: SkFDot6.h:64
#define SkScalarToFixed(x)
Definition: SkFixed.h:125
#define LOG_INFO(...)
static bool isLCD(const SkScalerContextRec &rec)
static FT_Int chooseBitmapStrike(FT_Face face, FT_F26Dot6 scaleY)
static SkMutex & f_t_mutex()
static SkScalar SkFT_FixedToScalar(FT_Fixed x)
#define FT_LOAD_COLOR
#define SK_TRACEFTR(ERR,...)
@ 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 constexpr bool SkToBool(const T &x)
Definition: SkTo.h:35
static OpenTypeSVGDecoderFactory GetOpenTypeSVGDecoderFactory()
Definition: SkGraphics.cpp:102
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
SkScalerContext(sk_sp< SkTypeface >, const SkScalerContextEffects &, const SkDescriptor *)
SkScalerContextRec fRec
SkTypeface * getTypeface() const
bool isVertical() const
bool isLinearMetrics() const
float SkScalar
Definition: extension.cpp:12
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 JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
@ kBW_Format
1bit per pixel mask (e.g. monochrome)
Definition: SkMask.h:27
float fX
x-axis value
Definition: SkPoint_impl.h:164
float fY
y-axis value
Definition: SkPoint_impl.h:165
constexpr float y() const
Definition: SkPoint_impl.h:187
constexpr float x() const
Definition: SkPoint_impl.h:181
void init(SkColor fgColor, SkScalerContext::Flags)
SkMask::Format fMaskFormat
bool computeMatrices(PreMatrixScale preMatrixScale, SkVector *scale, SkMatrix *remaining, SkMatrix *remainingWithoutRotation=nullptr, SkMatrix *remainingRotation=nullptr, SkMatrix *total=nullptr)
SkFontHinting getHinting() const

◆ ~SkScalerContext_FreeType()

SkScalerContext_FreeType::~SkScalerContext_FreeType ( )
override

Definition at line 1077 of file SkFontHost_FreeType.cpp.

1077 {
1079
1080 if (fFTSize != nullptr) {
1081 FT_Done_Size(fFTSize);
1082 }
1083
1084 fFaceRec = nullptr;
1085}

Member Function Documentation

◆ generateDrawable()

sk_sp< SkDrawable > SkScalerContext_FreeType::generateDrawable ( const SkGlyph )
overrideprotectedvirtual

Returns the drawable for the glyph (if any).

The generated drawable will be lifetime scoped to the lifetime of this scaler context. This means the drawable may refer to the scaler context and associated font data.

The drawable does not need to be flattenable (e.g. implement getFactory and getTypeName). Any necessary serialization will be done with makePictureSnapshot.

Reimplemented from SkScalerContext.

Definition at line 1416 of file SkFontHost_FreeType.cpp.

1416 {
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}
SkCanvas * beginRecording(const SkRect &bounds, sk_sp< SkBBoxHierarchy > bbh)
sk_sp< SkDrawable > finishRecordingAsDrawable()
std::unique_ptr< SkColor[]> fSkPalette
static SkRect Make(const SkISize &size)
Definition: SkRect.h:669
bool drawCOLRv1Glyph(FT_Face, const SkGlyph &, LoadGlyphFlags, SkSpan< SkColor > palette, SkCanvas *) const
bool drawSVGGlyph(FT_Face, const SkGlyph &, LoadGlyphFlags, SkSpan< SkColor > palette, SkCanvas *) const
bool drawCOLRv0Glyph(FT_Face, const SkGlyph &, LoadGlyphFlags, SkSpan< SkColor > palette, SkCanvas *) const

◆ generateFontMetrics()

void SkScalerContext_FreeType::generateFontMetrics ( SkFontMetrics )
overrideprotectedvirtual

Retrieves font metrics.

Implements SkScalerContext.

Definition at line 1511 of file SkFontHost_FreeType.cpp.

1511 {
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.
1600 metrics->fFlags |= SkFontMetrics::kBoundsInvalid_Flag;
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
1660 metrics->fFlags |= SkFontMetrics::kBoundsInvalid_Flag;
1661 }
1662}
sk_bzero(glyphs, sizeof(glyphs))
struct FT_FaceRec_ * FT_Face
#define SkIntToScalar(x)
Definition: SkScalar.h:57
struct FT_BBox_ FT_BBox
static int GetUnitsPerEm(FT_Face face)
uint32_t fFlags
FontMetricsFlags indicating which metrics are valid.
Definition: SkFontMetrics.h:52
@ kStrikeoutPositionIsValid_Flag
set if fStrikeoutPosition is valid
Definition: SkFontMetrics.h:48
@ kStrikeoutThicknessIsValid_Flag
set if fStrikeoutThickness is valid
Definition: SkFontMetrics.h:47
@ kUnderlinePositionIsValid_Flag
set if fUnderlinePosition is valid
Definition: SkFontMetrics.h:46
@ kUnderlineThicknessIsValid_Flag
set if fUnderlineThickness is valid
Definition: SkFontMetrics.h:45
@ kBoundsInvalid_Flag
set if fTop, fBottom, fXMin, fXMax invalid
Definition: SkFontMetrics.h:49

◆ generateImage()

void SkScalerContext_FreeType::generateImage ( const SkGlyph glyph,
void *  imageBuffer 
)
overrideprotectedvirtual

Generates the contents of glyph.fImage. When called, glyph.fImage will be pointing to a pre-allocated, uninitialized region of memory of size glyph.imageSize(). This method may not change glyph.fMaskFormat.

Because glyph.imageSize() will determine the size of fImage, generateMetrics will be called before generateImage.

Implements SkScalerContext.

Definition at line 1349 of file SkFontHost_FreeType.cpp.

1349 {
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}
@ kPremul_SkAlphaType
pixel components are premultiplied by alpha
Definition: SkAlphaType.h:29
#define SkASSERT(cond)
Definition: SkAssert.h:116
constexpr SkColor SK_ColorTRANSPARENT
Definition: SkColor.h:99
#define SkFixedToScalar(x)
Definition: SkFixed.h:124
void setPixels(void *pixels)
Definition: SkBitmap.cpp:207
bool setInfo(const SkImageInfo &imageInfo, size_t rowBytes=0)
Definition: SkBitmap.cpp:114
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::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
SkMatrix & postTranslate(SkScalar dx, SkScalar dy)
Definition: SkMatrix.cpp:281
const SkMaskGamma::PreBlend fPreBlend
static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at)
@ kARGB32_Format
SkPMColor.
Definition: SkMask.h:30
void generateGlyphImage(FT_Face, const SkGlyph &, void *, const SkMatrix &bitmapTransform, const SkMaskGamma::PreBlend &) const

◆ generateMetrics()

SkScalerContext::GlyphMetrics SkScalerContext_FreeType::generateMetrics ( const SkGlyph glyph,
SkArenaAlloc alloc 
)
overrideprotectedvirtual

Implements SkScalerContext.

Definition at line 1169 of file SkFontHost_FreeType.cpp.

1170 {
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)) {
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) {
1251 mx.maskFormat = SkMask::kARGB32_Format;
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) {
1285 mx.maskFormat = SkMask::kARGB32_Format;
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;
1299 mx.maskFormat = SkMask::kARGB32_Format;
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}
#define SkDEBUGFAIL(message)
Definition: SkAssert.h:118
#define SkFDot6Floor(x)
Definition: SkFDot6.h:52
#define SkFDot6ToScalar(x)
Definition: SkFDot6.h:65
#define SkFDot6ToFloat
Definition: SkFDot6.h:66
#define FT_PIXEL_MODE_BGRA
#define SK_ScalarInfinity
Definition: SkScalar.h:26
bool mapRect(SkRect *dst, const SkRect &src, SkApplyPerspectiveClip pc=SkApplyPerspectiveClip::kYes) const
Definition: SkMatrix.cpp:1141
sk_sp< SkPicture > finishRecordingAsPicture()
virtual SkRect cullRect() const =0
bool isSubpixel() const
FlutterSemanticsFlag flags
static float max(float r, float g, float b)
Definition: hsl.cpp:49
static float min(float r, float g, float b)
Definition: hsl.cpp:48
Optional< SkRect > bounds
Definition: SkRecords.h:189
static constexpr SkRect MakeEmpty()
Definition: SkRect.h:595
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 bool computeColrV1GlyphBoundingBox(FT_Face, SkGlyphID, SkRect *bounds)

◆ generatePath()

bool SkScalerContext_FreeType::generatePath ( const SkGlyph ,
SkPath  
)
overrideprotectedvirtual

Sets the passed path to the glyph outline. If this cannot be done the path is set to empty; Does not apply subpixel positioning to the path.

Returns
false if this glyph does not have any path.

Implements SkScalerContext.

Definition at line 1471 of file SkFontHost_FreeType.cpp.

1471 {
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}
uint16_t SkGlyphID
Definition: SkTypes.h:179
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
Definition: switches.h:57
bool generateGlyphPath(FT_Face, SkPath *) const

◆ success()

bool SkScalerContext_FreeType::success ( ) const
inline

Definition at line 447 of file SkFontHost_FreeType.cpp.

447 {
448 return fFTSize != nullptr && fFace != nullptr;
449 }

The documentation for this class was generated from the following file: