Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
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
const uint8_t * fB
bool isApplicable() const
const uint8_t * fR
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

◆ 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)

◆ 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

◆ 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: