Flutter Engine
The Flutter Engine
Public Types | Public Member Functions | Static Public Member Functions | Public Attributes | List of all members
SkScalerContextFTUtils Struct Reference

#include <SkFontHost_FreeType_common.h>

Public Types

using LoadGlyphFlags = uint32_t
 

Public Member Functions

void init (SkColor fgColor, SkScalerContext::Flags)
 
bool isSubpixel () const
 
bool isLinearMetrics () const
 
bool drawCOLRv0Glyph (FT_Face, const SkGlyph &, LoadGlyphFlags, SkSpan< SkColor > palette, SkCanvas *) const
 
bool drawCOLRv1Glyph (FT_Face, const SkGlyph &, LoadGlyphFlags, SkSpan< SkColor > palette, SkCanvas *) const
 
bool drawSVGGlyph (FT_Face, const SkGlyph &, LoadGlyphFlags, SkSpan< SkColor > palette, SkCanvas *) const
 
void generateGlyphImage (FT_Face, const SkGlyph &, void *, const SkMatrix &bitmapTransform, const SkMaskGamma::PreBlend &) const
 
bool generateGlyphPath (FT_Face, SkPath *) const
 

Static Public Member Functions

static bool computeColrV1GlyphBoundingBox (FT_Face, SkGlyphID, SkRect *bounds)
 

Public Attributes

SkColor fForegroundColor
 
SkScalerContext::Flags fFlags
 

Detailed Description

Definition at line 34 of file SkFontHost_FreeType_common.h.

Member Typedef Documentation

◆ LoadGlyphFlags

Definition at line 38 of file SkFontHost_FreeType_common.h.

Member Function Documentation

◆ computeColrV1GlyphBoundingBox()

static bool SkScalerContextFTUtils::computeColrV1GlyphBoundingBox ( FT_Face  ,
SkGlyphID  ,
SkRect bounds 
)
static

Computes a bounding box for a COLRv1 glyph.

This method may change the configured size and transforms on FT_Face. Make sure to configure size, matrix and load glyphs as needed after using this function to restore the state of FT_Face.

◆ drawCOLRv0Glyph()

bool SkScalerContextFTUtils::drawCOLRv0Glyph ( FT_Face  ,
const SkGlyph ,
LoadGlyphFlags  ,
SkSpan< SkColor palette,
SkCanvas  
) const

◆ drawCOLRv1Glyph()

bool SkScalerContextFTUtils::drawCOLRv1Glyph ( FT_Face  ,
const SkGlyph ,
LoadGlyphFlags  ,
SkSpan< SkColor palette,
SkCanvas  
) const

◆ drawSVGGlyph()

bool SkScalerContextFTUtils::drawSVGGlyph ( FT_Face  ,
const SkGlyph ,
LoadGlyphFlags  ,
SkSpan< SkColor palette,
SkCanvas  
) const

◆ generateGlyphImage()

void SkScalerContextFTUtils::generateGlyphImage ( FT_Face  face,
const SkGlyph glyph,
void *  imageBuffer,
const SkMatrix bitmapTransform,
const SkMaskGamma::PreBlend preBlend 
) const

Definition at line 1647 of file SkFontHost_FreeType_common.cpp.

1649 {
1650 switch ( face->glyph->format ) {
1651 case FT_GLYPH_FORMAT_OUTLINE: {
1652 FT_Outline* outline = &face->glyph->outline;
1653
1654 int dx = 0, dy = 0;
1655 if (this->isSubpixel()) {
1656 dx = SkFixedToFDot6(glyph.getSubXFixed());
1657 dy = SkFixedToFDot6(glyph.getSubYFixed());
1658 // negate dy since freetype-y-goes-up and skia-y-goes-down
1659 dy = -dy;
1660 }
1661
1662 memset(imageBuffer, 0, glyph.rowBytes() * glyph.height());
1663
1664 if (SkMask::kLCD16_Format == glyph.maskFormat()) {
1667
1668 FT_Outline_Translate(outline, dx, dy);
1669 FT_Error err = FT_Render_Glyph(face->glyph, doVert ? FT_RENDER_MODE_LCD_V :
1670 FT_RENDER_MODE_LCD);
1671 if (err) {
1672 SK_TRACEFTR(err, "Could not render glyph %p.", face->glyph);
1673 return;
1674 }
1675
1676 SkMaskBuilder mask(static_cast<uint8_t*>(imageBuffer),
1677 glyph.iRect(), glyph.rowBytes(), glyph.maskFormat());
1678
1679 if constexpr (kSkShowTextBlitCoverage) {
1680 memset(mask.image(), 0x80, mask.fBounds.height() * mask.fRowBytes);
1681 }
1682 FT_GlyphSlotRec& ftGlyph = *face->glyph;
1683
1684 if (!SkIRect::Intersects(mask.fBounds,
1685 SkIRect::MakeXYWH( ftGlyph.bitmap_left,
1686 -ftGlyph.bitmap_top,
1687 ftGlyph.bitmap.width,
1688 ftGlyph.bitmap.rows)))
1689 {
1690 return;
1691 }
1692
1693 // If the FT_Bitmap extent is larger, discard bits of the bitmap outside the mask.
1694 // If the SkMask extent is larger, shrink mask to fit bitmap (clearing discarded).
1695 unsigned char* origBuffer = ftGlyph.bitmap.buffer;
1696 // First align the top left (origin).
1697 if (-ftGlyph.bitmap_top < mask.fBounds.fTop) {
1698 int32_t topDiff = mask.fBounds.fTop - (-ftGlyph.bitmap_top);
1699 ftGlyph.bitmap.buffer += ftGlyph.bitmap.pitch * topDiff;
1700 ftGlyph.bitmap.rows -= topDiff;
1701 ftGlyph.bitmap_top = -mask.fBounds.fTop;
1702 }
1703 if (ftGlyph.bitmap_left < mask.fBounds.fLeft) {
1704 int32_t leftDiff = mask.fBounds.fLeft - ftGlyph.bitmap_left;
1705 ftGlyph.bitmap.buffer += leftDiff;
1706 ftGlyph.bitmap.width -= leftDiff;
1707 ftGlyph.bitmap_left = mask.fBounds.fLeft;
1708 }
1709 if (mask.fBounds.fTop < -ftGlyph.bitmap_top) {
1710 mask.image() += mask.fRowBytes * (-ftGlyph.bitmap_top - mask.fBounds.fTop);
1711 mask.bounds().fTop = -ftGlyph.bitmap_top;
1712 }
1713 if (mask.fBounds.fLeft < ftGlyph.bitmap_left) {
1714 mask.image() += sizeof(uint16_t) * (ftGlyph.bitmap_left - mask.fBounds.fLeft);
1715 mask.bounds().fLeft = ftGlyph.bitmap_left;
1716 }
1717 // Origins aligned, clean up the width and height.
1718 int ftVertScale = (doVert ? 3 : 1);
1719 int ftHoriScale = (doVert ? 1 : 3);
1720 if (mask.fBounds.height() * ftVertScale < SkToInt(ftGlyph.bitmap.rows)) {
1721 ftGlyph.bitmap.rows = mask.fBounds.height() * ftVertScale;
1722 }
1723 if (mask.fBounds.width() * ftHoriScale < SkToInt(ftGlyph.bitmap.width)) {
1724 ftGlyph.bitmap.width = mask.fBounds.width() * ftHoriScale;
1725 }
1726 if (SkToInt(ftGlyph.bitmap.rows) < mask.fBounds.height() * ftVertScale) {
1727 mask.bounds().fBottom = mask.fBounds.fTop + ftGlyph.bitmap.rows / ftVertScale;
1728 }
1729 if (SkToInt(ftGlyph.bitmap.width) < mask.fBounds.width() * ftHoriScale) {
1730 mask.bounds().fRight = mask.fBounds.fLeft + ftGlyph.bitmap.width / ftHoriScale;
1731 }
1732 if (preBlend.isApplicable()) {
1733 copyFT2LCD16<true>(ftGlyph.bitmap, &mask, doBGR,
1734 preBlend.fR, preBlend.fG, preBlend.fB);
1735 } else {
1736 copyFT2LCD16<false>(ftGlyph.bitmap, &mask, doBGR,
1737 preBlend.fR, preBlend.fG, preBlend.fB);
1738 }
1739 // Restore the buffer pointer so FreeType can properly free it.
1740 ftGlyph.bitmap.buffer = origBuffer;
1741 } else {
1742 FT_BBox bbox;
1743 FT_Bitmap target;
1744 FT_Outline_Get_CBox(outline, &bbox);
1745 /*
1746 what we really want to do for subpixel is
1747 offset(dx, dy)
1748 compute_bounds
1749 offset(bbox & !63)
1750 but that is two calls to offset, so we do the following, which
1751 achieves the same thing with only one offset call.
1752 */
1753 FT_Outline_Translate(outline, dx - ((bbox.xMin + dx) & ~63),
1754 dy - ((bbox.yMin + dy) & ~63));
1755
1756 target.width = glyph.width();
1757 target.rows = glyph.height();
1758 target.pitch = glyph.rowBytes();
1759 target.buffer = static_cast<uint8_t*>(imageBuffer);
1760 target.pixel_mode = compute_pixel_mode(glyph.maskFormat());
1761 target.num_grays = 256;
1762
1763 FT_Outline_Get_Bitmap(face->glyph->library, outline, &target);
1764 if constexpr (kSkShowTextBlitCoverage) {
1765 if (glyph.maskFormat() == SkMask::kBW_Format) {
1766 for (unsigned y = 0; y < target.rows; y += 2) {
1767 for (unsigned x = (y & 0x2); x < target.width; x+=4) {
1768 uint8_t& b = target.buffer[(target.pitch * y) + (x >> 3)];
1769 b = b ^ (1 << (0x7 - (x & 0x7)));
1770 }
1771 }
1772 } else {
1773 for (unsigned y = 0; y < target.rows; ++y) {
1774 for (unsigned x = 0; x < target.width; ++x) {
1775 uint8_t& a = target.buffer[(target.pitch * y) + x];
1776 a = std::max<uint8_t>(a, 0x20);
1777 }
1778 }
1779 }
1780 }
1781 }
1782 } break;
1783
1784 case FT_GLYPH_FORMAT_BITMAP: {
1785 FT_Pixel_Mode pixel_mode = static_cast<FT_Pixel_Mode>(face->glyph->bitmap.pixel_mode);
1786 SkMask::Format maskFormat = glyph.maskFormat();
1787
1788 // Assume that the other formats do not exist.
1789 SkASSERT(FT_PIXEL_MODE_MONO == pixel_mode ||
1790 FT_PIXEL_MODE_GRAY == pixel_mode ||
1791 FT_PIXEL_MODE_BGRA == pixel_mode);
1792
1793 // These are the only formats this ScalerContext should request.
1794 SkASSERT(SkMask::kBW_Format == maskFormat ||
1795 SkMask::kA8_Format == maskFormat ||
1796 SkMask::kARGB32_Format == maskFormat ||
1797 SkMask::kLCD16_Format == maskFormat);
1798
1799 // If no scaling needed, directly copy glyph bitmap.
1800 if (bitmapTransform.isIdentity()) {
1801 SkMaskBuilder dstMask = SkMaskBuilder(static_cast<uint8_t*>(imageBuffer),
1802 glyph.iRect(), glyph.rowBytes(),
1803 glyph.maskFormat());
1804 copyFTBitmap(face->glyph->bitmap, &dstMask);
1805 break;
1806 }
1807
1808 // Otherwise, scale the bitmap.
1809
1810 // Copy the FT_Bitmap into an SkBitmap (either A8 or ARGB)
1811 SkBitmap unscaledBitmap;
1812 // TODO: mark this as sRGB when the blits will be sRGB.
1813 unscaledBitmap.setInfo(SkImageInfo::Make(face->glyph->bitmap.width,
1814 face->glyph->bitmap.rows,
1815 SkColorType_for_FTPixelMode(pixel_mode),
1817 if (!unscaledBitmap.tryAllocPixels()) {
1818 // TODO: set the imageBuffer to indicate "missing"
1819 memset(imageBuffer, 0, glyph.rowBytes() * glyph.height());
1820 return;
1821 }
1822
1823 SkMaskBuilder unscaledBitmapAlias(
1824 reinterpret_cast<uint8_t*>(unscaledBitmap.getPixels()),
1825 SkIRect::MakeWH(unscaledBitmap.width(), unscaledBitmap.height()),
1826 unscaledBitmap.rowBytes(),
1827 SkMaskFormat_for_SkColorType(unscaledBitmap.colorType()));
1828 copyFTBitmap(face->glyph->bitmap, &unscaledBitmapAlias);
1829
1830 // Wrap the glyph's mask in a bitmap, unless the glyph's mask is BW or LCD.
1831 // BW requires an A8 target for resizing, which can then be down sampled.
1832 // LCD should use a 4x A8 target, which will then be down sampled.
1833 // For simplicity, LCD uses A8 and is replicated.
1834 int bitmapRowBytes = 0;
1835 if (SkMask::kBW_Format != maskFormat && SkMask::kLCD16_Format != maskFormat) {
1836 bitmapRowBytes = glyph.rowBytes();
1837 }
1838 SkBitmap dstBitmap;
1839 // TODO: mark this as sRGB when the blits will be sRGB.
1840 dstBitmap.setInfo(SkImageInfo::Make(glyph.width(), glyph.height(),
1841 SkColorType_for_SkMaskFormat(maskFormat),
1843 bitmapRowBytes);
1844 if (SkMask::kBW_Format == maskFormat || SkMask::kLCD16_Format == maskFormat) {
1845 if (!dstBitmap.tryAllocPixels()) {
1846 // TODO: set the fImage to indicate "missing"
1847 memset(imageBuffer, 0, glyph.rowBytes() * glyph.height());
1848 return;
1849 }
1850 } else {
1851 dstBitmap.setPixels(imageBuffer);
1852 }
1853
1854 // Scale unscaledBitmap into dstBitmap.
1855 SkCanvas canvas(dstBitmap);
1856 if constexpr (kSkShowTextBlitCoverage) {
1857 canvas.clear(0x33FF0000);
1858 } else {
1859 canvas.clear(SK_ColorTRANSPARENT);
1860 }
1861 canvas.translate(-glyph.left(), -glyph.top());
1862 canvas.concat(bitmapTransform);
1863 canvas.translate(face->glyph->bitmap_left, -face->glyph->bitmap_top);
1864
1866 canvas.drawImage(unscaledBitmap.asImage().get(), 0, 0, sampling, nullptr);
1867
1868 // If the destination is BW or LCD, convert from A8.
1869 if (SkMask::kBW_Format == maskFormat) {
1870 // Copy the A8 dstBitmap into the A1 imageBuffer.
1871 SkMaskBuilder dstMask(static_cast<uint8_t*>(imageBuffer),
1872 glyph.iRect(), glyph.rowBytes(), glyph.maskFormat());
1873 packA8ToA1(&dstMask, dstBitmap.getAddr8(0, 0), dstBitmap.rowBytes());
1874 } else if (SkMask::kLCD16_Format == maskFormat) {
1875 // Copy the A8 dstBitmap into the LCD16 imageBuffer.
1876 uint8_t* src = dstBitmap.getAddr8(0, 0);
1877 uint16_t* dst = reinterpret_cast<uint16_t*>(imageBuffer);
1878 for (int y = dstBitmap.height(); y --> 0;) {
1879 for (int x = 0; x < dstBitmap.width(); ++x) {
1880 dst[x] = grayToRGB16(src[x]);
1881 }
1882 dst = (uint16_t*)((char*)dst + glyph.rowBytes());
1883 src += dstBitmap.rowBytes();
1884 }
1885 }
1886 } break;
1887
1888 default:
1889 SkDEBUGFAIL("unknown glyph format");
1890 memset(imageBuffer, 0, glyph.rowBytes() * glyph.height());
1891 return;
1892 }
1893
1894// We used to always do this pre-USE_COLOR_LUMINANCE, but with colorlum,
1895// it is optional
1896#if defined(SK_GAMMA_APPLY_TO_A8)
1897 if (SkMask::kA8_Format == glyph.maskFormat() && preBlend.isApplicable()) {
1898 uint8_t* SK_RESTRICT dst = (uint8_t*)imageBuffer;
1899 unsigned rowBytes = glyph.rowBytes();
1900
1901 for (int y = glyph.height() - 1; y >= 0; --y) {
1902 for (int x = glyph.width() - 1; x >= 0; --x) {
1903 dst[x] = preBlend.fG[dst[x]];
1904 }
1905 dst += rowBytes;
1906 }
1907 }
1908#endif
1909}
@ 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
constexpr SkColor SK_ColorTRANSPARENT
Definition: SkColor.h:99
#define SkFixedToFDot6(x)
Definition: SkFDot6.h:56
#define SK_RESTRICT
Definition: SkFeatures.h:42
#define FT_PIXEL_MODE_BGRA
#define SK_TRACEFTR(ERR,...)
static void packA8ToA1(SkMaskBuilder &dstMask, const uint8_t *src, size_t srcRB)
constexpr int SkToInt(S x)
Definition: SkTo.h:29
static constexpr bool SkToBool(const T &x)
Definition: SkTo.h:35
struct FT_BBox_ FT_BBox
sk_sp< SkImage > asImage() const
Definition: SkBitmap.cpp:645
uint8_t * getAddr8(int x, int y) const
Definition: SkBitmap.h:1270
int width() const
Definition: SkBitmap.h:149
size_t rowBytes() const
Definition: SkBitmap.h:238
SkColorType colorType() const
Definition: SkBitmap.h:160
void setPixels(void *pixels)
Definition: SkBitmap.cpp:207
void * getPixels() const
Definition: SkBitmap.h:283
bool setInfo(const SkImageInfo &imageInfo, size_t rowBytes=0)
Definition: SkBitmap.cpp:114
int height() const
Definition: SkBitmap.h:158
bool tryAllocPixels(const SkImageInfo &info, size_t rowBytes)
Definition: SkBitmap.cpp:271
int top() const
Definition: SkGlyph.h:511
size_t rowBytes() const
Definition: SkGlyph.cpp:233
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
SkIRect iRect() const
Definition: SkGlyph.h:505
int width() const
Definition: SkGlyph.h:512
int left() const
Definition: SkGlyph.h:510
bool isIdentity() const
Definition: SkMatrix.h:223
const uint8_t * fG
Definition: SkMaskGamma.h:203
const uint8_t * fB
Definition: SkMaskGamma.h:204
bool isApplicable() const
Definition: SkMaskGamma.h:200
const uint8_t * fR
Definition: SkMaskGamma.h:202
T * get() const
Definition: SkRefCnt.h:303
static bool b
struct MyStruct a[10]
uint32_t * target
double y
double x
SkSamplingOptions sampling
Definition: SkRecords.h:337
skia_private::AutoTArray< sk_sp< SkImageFilter > > filters TypedMatrix matrix TypedMatrix matrix SkScalar dx
Definition: SkRecords.h:208
dst
Definition: cp.py:12
static bool Intersects(const SkIRect &a, const SkIRect &b)
Definition: SkRect.h:535
static constexpr SkIRect MakeWH(int32_t w, int32_t h)
Definition: SkRect.h:56
static constexpr SkIRect MakeXYWH(int32_t x, int32_t y, int32_t w, int32_t h)
Definition: SkRect.h:104
static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at)
Format
Definition: SkMask.h:26
@ kA8_Format
8bits per pixel mask (e.g. antialiasing)
Definition: SkMask.h:28
@ 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
SkScalerContext::Flags fFlags

◆ generateGlyphPath()

bool SkScalerContextFTUtils::generateGlyphPath ( FT_Face  face,
SkPath path 
) const

Definition at line 2076 of file SkFontHost_FreeType_common.cpp.

2076 {
2077 if (!generateGlyphPathStatic(face, path)) {
2078 return false;
2079 }
2080 if (face->glyph->outline.flags & FT_OUTLINE_OVERLAP) {
2081 Simplify(*path, path);
2082 // Simplify will return an even-odd path.
2083 // A stroke+fill (for fake bold) may be incorrect for even-odd.
2084 // https://github.com/flutter/flutter/issues/112546
2085 AsWinding(*path, path);
2086 }
2087 return true;
2088}
#define FT_OUTLINE_OVERLAP
bool SK_API AsWinding(const SkPath &path, SkPath *result)
bool SK_API Simplify(const SkPath &path, SkPath *result)
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

◆ init()

void SkScalerContextFTUtils::init ( SkColor  fgColor,
SkScalerContext::Flags  flags 
)

Definition at line 1560 of file SkFontHost_FreeType_common.cpp.

1560 {
1561 fForegroundColor = fgColor;
1562 fFlags = flags;
1563}
FlutterSemanticsFlag flags

◆ isLinearMetrics()

bool SkScalerContextFTUtils::isLinearMetrics ( ) const
inline

Definition at line 46 of file SkFontHost_FreeType_common.h.

◆ isSubpixel()

bool SkScalerContextFTUtils::isSubpixel ( ) const
inline

Member Data Documentation

◆ fFlags

SkScalerContext::Flags SkScalerContextFTUtils::fFlags

Definition at line 36 of file SkFontHost_FreeType_common.h.

◆ fForegroundColor

SkColor SkScalerContextFTUtils::fForegroundColor

Definition at line 35 of file SkFontHost_FreeType_common.h.


The documentation for this struct was generated from the following files: