9#if defined(SK_BUILD_FOR_WIN)
49static inline const constexpr bool kSkShowTextBlitCoverage =
false;
52static void (*gEnsureLOGFONTAccessibleProc)(
const LOGFONT&);
54void SkTypeface_SetEnsureLOGFONTAccessibleProc(
void (*proc)(
const LOGFONT&)) {
55 gEnsureLOGFONTAccessibleProc = proc;
58static void call_ensure_accessible(
const LOGFONT& lf) {
59 if (gEnsureLOGFONTAccessibleProc) {
60 gEnsureLOGFONTAccessibleProc(lf);
67typedef uint32_t SkGdiRGB;
79 return 0 ==
a && 0 ==
b;
90#ifdef SK_ENFORCE_ROTATED_TEXT_AA_ON_WINDOWS
103static void tchar_to_skstring(
const TCHAR t[],
SkString*
s) {
105 size_t sSize = WideCharToMultiByte(CP_UTF8, 0, t, -1,
nullptr, 0,
nullptr,
nullptr);
107 WideCharToMultiByte(CP_UTF8, 0, t, -1,
s->data(), sSize,
nullptr,
nullptr);
113static void dcfontname_to_skstring(HDC deviceContext,
const LOGFONT& lf,
SkString* familyName) {
115 if (0 == (fontNameLen = GetTextFace(deviceContext, 0,
nullptr))) {
116 call_ensure_accessible(lf);
117 if (0 == (fontNameLen = GetTextFace(deviceContext, 0,
nullptr))) {
123 if (0 == GetTextFace(deviceContext, fontNameLen, fontName.get())) {
124 call_ensure_accessible(lf);
125 if (0 == GetTextFace(deviceContext, fontNameLen, fontName.get())) {
130 tchar_to_skstring(fontName.get(), familyName);
133static void make_canonical(
LOGFONT* lf) {
136 lf->lfQuality = CLEARTYPE_QUALITY;
137 lf->lfCharSet = DEFAULT_CHARSET;
147static inline FIXED SkFixedToFIXED(
SkFixed x) {
148 return *(FIXED*)(&
x);
150static inline SkFixed SkFIXEDToFixed(FIXED
x) {
154static inline FIXED SkScalarToFIXED(
SkScalar x) {
158static inline SkScalar SkFIXEDToScalar(FIXED
x) {
162static unsigned calculateGlyphCount(HDC hdc,
const LOGFONT& lf) {
163 TEXTMETRIC textMetric;
164 if (0 == GetTextMetrics(hdc, &textMetric)) {
165 textMetric.tmPitchAndFamily = TMPF_VECTOR;
166 call_ensure_accessible(lf);
167 GetTextMetrics(hdc, &textMetric);
170 if (!(textMetric.tmPitchAndFamily & TMPF_VECTOR)) {
171 return textMetric.tmLastChar;
181 static const MAT2 mat2 = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
182 int32_t
max = UINT16_MAX + 1;
187 if (GetGlyphOutlineW(hdc, mid, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0,
188 nullptr, &mat2) == GDI_ERROR) {
198static unsigned calculateUPEM(HDC hdc,
const LOGFONT& lf) {
199 TEXTMETRIC textMetric;
200 if (0 == GetTextMetrics(hdc, &textMetric)) {
201 textMetric.tmPitchAndFamily = TMPF_VECTOR;
202 call_ensure_accessible(lf);
203 GetTextMetrics(hdc, &textMetric);
206 if (!(textMetric.tmPitchAndFamily & TMPF_VECTOR)) {
207 return textMetric.tmMaxCharWidth;
210 OUTLINETEXTMETRIC otm;
211 unsigned int otmRet = GetOutlineTextMetrics(hdc,
sizeof(otm), &otm);
213 call_ensure_accessible(lf);
214 otmRet = GetOutlineTextMetrics(hdc,
sizeof(otm), &otm);
217 return (0 == otmRet) ? 0 : otm.otmEMSquare;
222 explicit SkAutoHDC(
const LOGFONT& lf)
223 : fHdc(::CreateCompatibleDC(nullptr))
224 , fFont(::CreateFontIndirect(&lf))
225 , fSavefont((HFONT)::SelectObject(fHdc, fFont))
229 ::SelectObject(fHdc, fSavefont);
233 ::DeleteObject(fFont);
236 operator HDC() {
return fHdc; }
248 , fSerializeAsStream(serializeAsStream)
250 SkAutoHDC hdc(fLogFont);
251 TEXTMETRIC textMetric;
252 if (0 == GetTextMetrics(hdc, &textMetric)) {
253 call_ensure_accessible(lf);
254 if (0 == GetTextMetrics(hdc, &textMetric)) {
255 textMetric.tmPitchAndFamily = TMPF_TRUETYPE;
260 this->
setIsFixedPitch((textMetric.tmPitchAndFamily & TMPF_FIXED_PITCH) == 0);
266 fCanBeLCD = !((textMetric.tmPitchAndFamily & TMPF_VECTOR) &&
267 (textMetric.tmPitchAndFamily & TMPF_DEVICE));
271 bool fSerializeAsStream;
278 static void EnsureAccessible(
const SkTypeface* face) {
279 call_ensure_accessible(
static_cast<const LogFontTypeface*
>(face)->fLogFont);
283 std::unique_ptr<SkStreamAsset>
onOpenStream(
int* ttcIndex)
const override;
300 int coordinateCount)
const override
305 int parameterCount)
const override
314class FontMemResourceTypeface :
public LogFontTypeface {
321 new FontMemResourceTypeface(get_style(lf), lf, fontMemResource));
325 void weak_dispose()
const override {
326 RemoveFontMemResourceEx(fFontMemResource);
327 INHERITED::weak_dispose();
335 : LogFontTypeface(style, lf,
true), fFontMemResource(fontMemResource)
343static const LOGFONT& get_default_font() {
348static bool FindByLogFont(
SkTypeface* face,
void* ctx) {
349 LogFontTypeface* lface =
static_cast<LogFontTypeface*
>(face);
352 return !memcmp(&lface->fLogFont, lf,
sizeof(
LOGFONT));
384 if (
nullptr == face) {
385 *lf = get_default_font();
387 *lf =
static_cast<const LogFontTypeface*
>(face)->fLogFont;
397static void populate_glyph_to_unicode(HDC fontHdc,
const unsigned glyphCount,
400 DWORD glyphSetBufferSize = GetFontUnicodeRanges(fontHdc,
nullptr);
401 if (!glyphSetBufferSize) {
405 std::unique_ptr<BYTE[]> glyphSetBuffer(
new BYTE[glyphSetBufferSize]);
407 reinterpret_cast<LPGLYPHSET
>(glyphSetBuffer.get());
408 if (GetFontUnicodeRanges(fontHdc, glyphSet) != glyphSetBufferSize) {
412 for (
DWORD i = 0;
i < glyphSet->cRanges; ++
i) {
417 int count = glyphSet->ranges[
i].cGlyphs;
421 for (USHORT j = 0; j <
count; ++j) {
422 chars[j] = glyphSet->ranges[
i].wcLow + j;
424 GetGlyphIndicesW(fontHdc, chars.get(),
count, glyph.get(),
425 GGI_MARK_NONEXISTING_GLYPHS);
433 for (USHORT j = 0; j <
count; ++j) {
434 if (glyph[j] != 0xFFFF && glyph[j] < glyphCount && glyphToUnicode[glyph[j]] == 0) {
435 glyphToUnicode[glyph[j]] = chars[j];
443static int alignTo32(
int n) {
444 return (n + 31) & ~31;
447struct MyBitmapInfo :
public BITMAPINFO {
448 RGBQUAD fMoreSpaceForColors[1];
453 HDCOffscreen() =
default;
457 ::SelectObject(fDC, fSavefont);
465 void init(HFONT
font,
const XFORM& xform) {
470 void*
draw(
const SkGlyph&,
bool isBW,
size_t* srcRBPtr);
474 HFONT fSavefont{
nullptr};
475 HBITMAP fBM{
nullptr};
476 HFONT fFont{
nullptr};
477 XFORM fXform{1, 0, 0, 1, 0, 0};
478 void* fBits{
nullptr};
487 if (
nullptr == fDC) {
488 fDC = CreateCompatibleDC(0);
489 if (
nullptr == fDC) {
492 SetGraphicsMode(fDC, GM_ADVANCED);
493 SetBkMode(fDC, TRANSPARENT);
494 SetTextAlign(fDC, TA_LEFT | TA_BASELINE);
495 fSavefont = (HFONT)SelectObject(fDC, fFont);
497 COLORREF
color = 0x00FFFFFF;
502 if (fBM && (fIsBW != isBW || fWidth < glyph.
width() || fHeight < glyph.
height())) {
511 int biWidth = isBW ? alignTo32(fWidth) : fWidth;
513 if (
nullptr == fBM) {
517 RGBQUAD blackQuad = { 0, 0, 0, 0 };
518 RGBQUAD whiteQuad = { 0xFF, 0xFF, 0xFF, 0 };
519 info.bmiColors[0] = blackQuad;
520 info.bmiColors[1] = whiteQuad;
522 info.bmiHeader.biSize =
sizeof(
info.bmiHeader);
523 info.bmiHeader.biWidth = biWidth;
524 info.bmiHeader.biHeight = fHeight;
525 info.bmiHeader.biPlanes = 1;
526 info.bmiHeader.biBitCount = isBW ? 1 : 32;
527 info.bmiHeader.biCompression = BI_RGB;
529 info.bmiHeader.biClrUsed = 2;
531 fBM = CreateDIBSection(fDC, &
info, DIB_RGB_COLORS, &fBits, 0, 0);
532 if (
nullptr == fBM) {
535 SelectObject(fDC, fBM);
539 size_t srcRB = isBW ? (biWidth >> 3) : (fWidth << 2);
540 size_t size = fHeight * srcRB;
541 memset(fBits, 0,
size);
543 XFORM xform = fXform;
546 SetWorldTransform(fDC, &xform);
549 BOOL ret = ExtTextOutW(fDC, 0, 0, ETO_GLYPH_INDEX,
nullptr,
reinterpret_cast<LPCWSTR
>(&glyphID),
557 return (
char*)fBits + (fHeight - glyph.
height()) * srcRB;
561#define BUFFERSIZE (1 << 13)
568 ~SkScalerContext_GDI()
override;
572 bool isValid()
const;
583 template<
bool APPLY_PREBLEND>
584 static void RGBToA8(
const SkGdiRGB*
SK_RESTRICT src,
size_t srcRB,
585 const SkGlyph& glyph,
void* imageBuffer,
const uint8_t* table8);
587 template<
bool APPLY_PREBLEND>
590 const uint8_t* tableR,
const uint8_t* tableG,
const uint8_t* tableB);
592 HDCOffscreen fOffscreen;
613 kTrueType_Type, kBitmap_Type, kLine_Type
618static FIXED SkFloatToFIXED(
float x) {
622static inline float SkFIXEDToFloat(FIXED
x) {
629 return NONANTIALIASED_QUALITY;
631 return CLEARTYPE_QUALITY;
634 return CLEARTYPE_QUALITY;
636 return ANTIALIASED_QUALITY;
650 LogFontTypeface* typeface =
static_cast<LogFontTypeface*
>(this->getTypeface());
652 fDDC = ::CreateCompatibleDC(
nullptr);
656 SetGraphicsMode(fDDC, GM_ADVANCED);
657 SetBkMode(fDDC, TRANSPARENT);
669 fRec.computeMatrices(scaleConstraints, &
scale, &sA, &GsA, &fG_inv, &
A);
689 if (gdiTextSize == 0) {
693 LOGFONT lf = typeface->fLogFont;
695 lf.lfQuality = compute_quality(fRec);
696 fFont = CreateFontIndirect(&lf);
701 fSavefont = (HFONT)SelectObject(fDDC, fFont);
703 if (0 == GetTextMetrics(fDDC, &fTM)) {
704 call_ensure_accessible(lf);
705 if (0 == GetTextMetrics(fDDC, &fTM)) {
706 fTM.tmPitchAndFamily = TMPF_TRUETYPE;
711 if (fTM.tmPitchAndFamily & TMPF_VECTOR) {
720 if (fTM.tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_DEVICE)) {
722 fType = SkScalerContext_GDI::kTrueType_Type;
725 fType = SkScalerContext_GDI::kLine_Type;
738 fMat22.eM11 = SkFloatToFIXED(xform.eM11);
739 fMat22.eM12 = SkFloatToFIXED(-xform.eM12);
740 fMat22.eM21 = SkFloatToFIXED(-xform.eM21);
741 fMat22.eM22 = SkFloatToFIXED(xform.eM22);
743 if (needToRenderWithSkia(fRec)) {
744 this->forceGenerateImageFromPath();
748 if (this->isLinearMetrics()) {
749 OUTLINETEXTMETRIC otm;
750 UINT success = GetOutlineTextMetrics(fDDC,
sizeof(otm), &otm);
752 call_ensure_accessible(lf);
753 success = GetOutlineTextMetrics(fDDC,
sizeof(otm), &otm);
758 SkScalar gdiTextSizeToEMScale = upem / gdiTextSize;
759 fHighResMat22.eM11 = SkScalarToFIXED(gdiTextSizeToEMScale);
760 fHighResMat22.eM12 = SkScalarToFIXED(0);
761 fHighResMat22.eM21 = SkScalarToFIXED(0);
762 fHighResMat22.eM22 = SkScalarToFIXED(gdiTextSizeToEMScale);
766 fHiResMatrix.preScale(removeEMScale, removeEMScale);
772 fType = SkScalerContext_GDI::kBitmap_Type;
783 fMat22.eM11 = SkScalarToFIXED(fRec.fPost2x2[0][0]);
784 fMat22.eM12 = SkScalarToFIXED(-fRec.fPost2x2[1][0]);
785 fMat22.eM21 = SkScalarToFIXED(-fRec.fPost2x2[0][1]);
786 fMat22.eM22 = SkScalarToFIXED(fRec.fPost2x2[1][1]);
789 fOffscreen.init(fFont, xform);
792SkScalerContext_GDI::~SkScalerContext_GDI() {
794 ::SelectObject(fDDC, fSavefont);
798 ::DeleteObject(fFont);
801 ::ScriptFreeCache(&fSC);
805bool SkScalerContext_GDI::isValid()
const {
806 return fDDC && fFont;
815 if (fType == SkScalerContext_GDI::kBitmap_Type || fType == SkScalerContext_GDI::kLine_Type) {
819 if (0 == GetTextExtentPointI(fDDC, &
glyphs, 1, &
size)) {
820 width = fTM.tmMaxCharWidth;
830 int top = -fTM.tmAscent;
836 if (fType == SkScalerContext_GDI::kLine_Type) {
839 m.setAll(SkFIXEDToScalar(fMat22.eM11), -SkFIXEDToScalar(fMat22.eM21), 0,
840 -SkFIXEDToScalar(fMat22.eM12), SkFIXEDToScalar(fMat22.eM22), 0,
843 bounds.roundOut(&mx.bounds);
847 mx.advance.fY = -SkFIXEDToFloat(fMat22.eM12) * mx.advance.fX;
848 mx.advance.fX *= SkFIXEDToFloat(fMat22.eM11);
851 mx.neverRequestPath =
true;
860 DWORD status = GetGlyphOutlineW(fDDC, glyphId, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0,
nullptr, &fMat22);
861 if (GDI_ERROR == status) {
862 LogFontTypeface::EnsureAccessible(this->getTypeface());
863 status = GetGlyphOutlineW(fDDC, glyphId, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0,
nullptr, &fMat22);
864 if (GDI_ERROR == status) {
873 if (1 == gm.gmBlackBoxX && 1 == gm.gmBlackBoxY) {
875 DWORD bufferSize = GetGlyphOutlineW(fDDC, glyphId, GGO_NATIVE | GGO_GLYPH_INDEX, &gm, 0,
nullptr, &fMat22);
876 empty = (0 == bufferSize);
881 int y = -gm.gmptGlyphOrigin.y;
882 int x = gm.gmptGlyphOrigin.x;
890 mx.advance.fX = (
float)((
int)gm.gmCellIncX);
891 mx.advance.fY = (
float)((
int)gm.gmCellIncY);
893 if ((fTM.tmPitchAndFamily & TMPF_VECTOR) && this->isLinearMetrics()) {
895 status = GetGlyphOutlineW(fDDC, glyphId, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0,
nullptr, &fHighResMat22);
896 if (GDI_ERROR != status) {
897 mx.advance = fHiResMatrix.mapXY(
SkIntToScalar(gm.gmCellIncX),
901 status = GetGlyphOutlineW(fDDC, glyphId, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0,
nullptr, &fGsA);
902 if (GDI_ERROR != status) {
909static const MAT2 gMat2Identity = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
910void SkScalerContext_GDI::generateFontMetrics(
SkFontMetrics* metrics) {
911 if (
nullptr == metrics) {
914 sk_bzero(metrics,
sizeof(*metrics));
918#ifndef SK_GDI_ALWAYS_USE_TEXTMETRICS_FOR_FONT_METRICS
919 if (fType == SkScalerContext_GDI::kBitmap_Type || fType == SkScalerContext_GDI::kLine_Type) {
931#ifndef SK_GDI_ALWAYS_USE_TEXTMETRICS_FOR_FONT_METRICS
936 OUTLINETEXTMETRIC otm;
938 uint32_t ret = GetOutlineTextMetrics(fDDC,
sizeof(otm), &otm);
940 LogFontTypeface::EnsureAccessible(this->getTypeface());
941 ret = GetOutlineTextMetrics(fDDC,
sizeof(otm), &otm);
947#ifndef SK_GDI_ALWAYS_USE_TEXTMETRICS_FOR_FONT_METRICS
967 DWORD len = GetGlyphOutlineW(fDDC,
'x', GGO_METRICS, &gm, 0,
nullptr, &gMat2Identity);
968 if (
len != GDI_ERROR && gm.gmBlackBoxY > 0) {
975static void build_power_table(uint8_t
table[],
float ee) {
976 for (
int i = 0;
i < 256;
i++) {
995static const uint8_t* getInverseGammaTableGDI() {
997 static uint8_t gTableGdi[256];
999 build_power_table(gTableGdi, 2.3f);
1011static const uint8_t* getInverseGammaTableClearType() {
1013 static uint8_t gTableClearType[256];
1016 if (!SystemParametersInfo(SPI_GETFONTSMOOTHINGCONTRAST, 0, &
level, 0) || !
level) {
1020 build_power_table(gTableClearType,
level / 1000.0f);
1022 return gTableClearType;
1028template<
bool APPLY_PREBLEND>
1029static inline uint8_t rgb_to_a8(SkGdiRGB rgb,
const uint8_t* table8) {
1030 U8CPU r = (rgb >> 16) & 0xFF;
1031 U8CPU g = (rgb >> 8) & 0xFF;
1032 U8CPU b = (rgb >> 0) & 0xFF;
1036template<
bool APPLY_PREBLEND>
1037static inline uint16_t rgb_to_lcd16(SkGdiRGB rgb,
const uint8_t* tableR,
1038 const uint8_t* tableG,
1039 const uint8_t* tableB) {
1040 U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 16) & 0xFF, tableR);
1041 U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 8) & 0xFF, tableG);
1042 U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 0) & 0xFF, tableB);
1043 if constexpr (kSkShowTextBlitCoverage) {
1051template<
bool APPLY_PREBLEND>
1052void SkScalerContext_GDI::RGBToA8(
const SkGdiRGB*
SK_RESTRICT src,
size_t srcRB,
1053 const SkGlyph& glyph,
void* imageBuffer,
const uint8_t* table8) {
1054 const size_t dstRB = glyph.
rowBytes();
1058 for (
int y = 0;
y < glyph.
height();
y++) {
1060 dst[
i] = rgb_to_a8<APPLY_PREBLEND>(
src[
i], table8);
1061 if constexpr (kSkShowTextBlitCoverage) {
1062 dst[
i] = std::max<uint8_t>(
dst[
i], 10u);
1065 src = SkTAddOffset<const SkGdiRGB>(
src, srcRB);
1070template<
bool APPLY_PREBLEND>
1071void SkScalerContext_GDI::RGBToLcd16(
1073 const uint8_t* tableR,
const uint8_t* tableG,
const uint8_t* tableB) {
1074 const size_t dstRB = glyph.
rowBytes();
1078 for (
int y = 0;
y < glyph.
height();
y++) {
1080 dst[
i] = rgb_to_lcd16<APPLY_PREBLEND>(
src[
i], tableR, tableG, tableB);
1082 src = SkTAddOffset<const SkGdiRGB>(
src, srcRB);
1083 dst = (uint16_t*)((
char*)
dst - dstRB);
1087void SkScalerContext_GDI::generateImage(
const SkGlyph& glyph,
void* imageBuffer) {
1091 const bool isAA = !
isLCD(fRec);
1094 void*
bits = fOffscreen.draw(glyph, isBW, &srcRB);
1095 if (
nullptr ==
bits) {
1096 LogFontTypeface::EnsureAccessible(this->getTypeface());
1097 bits = fOffscreen.draw(glyph, isBW, &srcRB);
1098 if (
nullptr ==
bits) {
1105 const uint8_t*
table;
1109 table = getInverseGammaTableGDI();
1111 table = getInverseGammaTableClearType();
1119 for (
int y = 0;
y < glyph.
height(); ++
y) {
1120 for (
int x = 0;
x < glyph.
width(); ++
x) {
1121 int r = (
addr[
x] >> 16) & 0xFF;
1122 int g = (
addr[
x] >> 8) & 0xFF;
1123 int b = (
addr[
x] >> 0) & 0xFF;
1126 addr = SkTAddOffset<SkGdiRGB>(
addr, srcRB);
1132 const uint8_t*
src = (
const uint8_t*)
bits;
1133 uint8_t*
dst = (uint8_t*)((
char*)imageBuffer + (glyph.
height() - 1) * dstRB);
1134 for (
int y = 0;
y < glyph.
height();
y++) {
1139 if constexpr (kSkShowTextBlitCoverage) {
1141 int bitCount = glyph.
width() & 7;
1142 uint8_t* first = (uint8_t*)imageBuffer;
1143 uint8_t* last = first + glyph.
height() * dstRB - 1;
1145 *last |= bitCount == 0 ? 1 : 1 << (8 - bitCount);
1151 const SkGdiRGB*
src = (
const SkGdiRGB*)
bits;
1152 if (fPreBlend.isApplicable()) {
1153 RGBToA8<true>(
src, srcRB, glyph, imageBuffer, fPreBlend.fG);
1155 RGBToA8<false>(
src, srcRB, glyph, imageBuffer, fPreBlend.fG);
1158 const SkGdiRGB*
src = (
const SkGdiRGB*)
bits;
1160 if (fPreBlend.isApplicable()) {
1161 RGBToLcd16<true>(
src, srcRB, glyph, imageBuffer,
1162 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
1164 RGBToLcd16<false>(
src, srcRB, glyph, imageBuffer,
1165 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
1172class GDIGlyphbufferPointIter {
1175 : fHeaderIter(glyphbuf,
total_size), fCurveIter(), fPointIter()
1178 POINTFX
const *
next() {
1180 if (!fCurveIter.isSet()) {
1181 const TTPOLYGONHEADER*
header = fHeaderIter.next();
1186 const TTPOLYCURVE* curve = fCurveIter.next();
1187 if (
nullptr == curve) {
1190 fPointIter.set(curve);
1191 return &
header->pfxStart;
1194 const POINTFX* nextPoint = fPointIter.next();
1195 if (
nullptr == nextPoint) {
1196 const TTPOLYCURVE* curve = fCurveIter.next();
1197 if (
nullptr == curve) {
1201 fPointIter.set(curve);
1203 nextPoint = fPointIter.next();
1208 WORD currentCurveType() {
1209 return fPointIter.fCurveType;
1214 class GDIPolygonHeaderIter {
1217 : fCurPolygon(reinterpret_cast<const TTPOLYGONHEADER*>(glyphbuf))
1221 const TTPOLYGONHEADER*
next() {
1222 if (fCurPolygon >= fEndPolygon) {
1225 const TTPOLYGONHEADER* thisPolygon = fCurPolygon;
1226 fCurPolygon = SkTAddOffset<const TTPOLYGONHEADER>(fCurPolygon, fCurPolygon->cb);
1230 const TTPOLYGONHEADER* fCurPolygon;
1231 const TTPOLYGONHEADER* fEndPolygon;
1235 class GDIPolygonCurveIter {
1237 GDIPolygonCurveIter() : fCurCurve(nullptr), fEndCurve(nullptr) { }
1239 GDIPolygonCurveIter(
const TTPOLYGONHEADER* curPolygon)
1240 : fCurCurve(
SkTAddOffset<const TTPOLYCURVE>(curPolygon, sizeof(TTPOLYGONHEADER)))
1241 , fEndCurve(
SkTAddOffset<const TTPOLYCURVE>(curPolygon, curPolygon->cb))
1244 bool isSet() {
return fCurCurve !=
nullptr; }
1246 void set(
const TTPOLYGONHEADER* curPolygon) {
1247 fCurCurve = SkTAddOffset<const TTPOLYCURVE>(curPolygon,
sizeof(TTPOLYGONHEADER));
1248 fEndCurve = SkTAddOffset<const TTPOLYCURVE>(curPolygon, curPolygon->cb);
1251 fCurCurve =
nullptr;
1252 fEndCurve =
nullptr;
1255 const TTPOLYCURVE*
next() {
1256 if (fCurCurve >= fEndCurve) {
1259 const TTPOLYCURVE* thisCurve = fCurCurve;
1260 fCurCurve = SkTAddOffset<const TTPOLYCURVE>(fCurCurve, size_of_TTPOLYCURVE(*fCurCurve));
1264 size_t size_of_TTPOLYCURVE(
const TTPOLYCURVE& curve) {
1265 return 2*
sizeof(
WORD) + curve.cpfx*
sizeof(POINTFX);
1267 const TTPOLYCURVE* fCurCurve;
1268 const TTPOLYCURVE* fEndCurve;
1272 class GDIPolygonCurvePointIter {
1274 GDIPolygonCurvePointIter() : fCurveType(0), fCurPoint(nullptr), fEndPoint(nullptr) { }
1276 GDIPolygonCurvePointIter(
const TTPOLYCURVE* curPolygon)
1277 : fCurveType(curPolygon->wType)
1278 , fCurPoint(&curPolygon->apfx[0])
1279 , fEndPoint(&curPolygon->apfx[curPolygon->cpfx])
1282 bool isSet() {
return fCurPoint !=
nullptr; }
1284 void set(
const TTPOLYCURVE* curPolygon) {
1285 fCurveType = curPolygon->wType;
1286 fCurPoint = &curPolygon->apfx[0];
1287 fEndPoint = &curPolygon->apfx[curPolygon->cpfx];
1290 fCurPoint =
nullptr;
1291 fEndPoint =
nullptr;
1294 const POINTFX*
next() {
1295 if (fCurPoint >= fEndPoint) {
1298 const POINTFX* thisPoint = fCurPoint;
1305 const POINTFX* fCurPoint;
1306 const POINTFX* fEndPoint;
1309 GDIPolygonHeaderIter fHeaderIter;
1310 GDIPolygonCurveIter fCurveIter;
1311 GDIPolygonCurvePointIter fPointIter;
1314class SkGDIGeometrySink {
1316 bool fStarted =
false;
1319 void goingTo(
const POINTFX pt) {
1323 -SkFIXEDToScalar(fCurrent.y));
1328 bool currentIsNot(
const POINTFX pt) {
1329 return fCurrent.x.value != pt.x.value || fCurrent.x.fract != pt.x.fract ||
1330 fCurrent.y.value != pt.y.value || fCurrent.y.fract != pt.y.fract;
1345 const uint8_t* cur_glyph = glyphbuf;
1346 const uint8_t* end_glyph = glyphbuf +
total_size;
1348 while (cur_glyph < end_glyph) {
1349 const TTPOLYGONHEADER* th = (
const TTPOLYGONHEADER*)cur_glyph;
1351 const uint8_t* end_poly = cur_glyph + th->cb;
1352 const uint8_t* cur_poly = cur_glyph +
sizeof(TTPOLYGONHEADER);
1355 fCurrent = th->pfxStart;
1357 while (cur_poly < end_poly) {
1358 const TTPOLYCURVE* pc = (
const TTPOLYCURVE*)cur_poly;
1359 const POINTFX* apfx = pc->apfx;
1360 const WORD cpfx = pc->cpfx;
1362 if (pc->wType == TT_PRIM_LINE) {
1363 for (uint16_t
i = 0;
i < cpfx;
i++) {
1364 POINTFX pnt_b = apfx[
i];
1365 if (this->currentIsNot(pnt_b)) {
1366 this->goingTo(pnt_b);
1368 -SkFIXEDToScalar(pnt_b.y));
1373 if (pc->wType == TT_PRIM_QSPLINE) {
1374 for (uint16_t u = 0; u < cpfx - 1; u++) {
1375 POINTFX pnt_b = apfx[u];
1376 POINTFX pnt_c = apfx[u+1];
1379 pnt_c.x = SkFixedToFIXED(
SkFixedAve(SkFIXEDToFixed(pnt_b.x),
1380 SkFIXEDToFixed(pnt_c.x)));
1381 pnt_c.y = SkFixedToFIXED(
SkFixedAve(SkFIXEDToFixed(pnt_b.y),
1382 SkFIXEDToFixed(pnt_c.y)));
1386 if (this->currentIsNot(pnt_b) || this->currentIsNot(pnt_c)) {
1387 this->goingTo(pnt_c);
1389 -SkFIXEDToScalar(pnt_b.y),
1390 SkFIXEDToScalar(pnt_c.x),
1391 -SkFIXEDToScalar(pnt_c.y));
1397 cur_poly +=
sizeof(
WORD) * 2 +
sizeof(POINTFX) * cpfx;
1399 cur_glyph += th->cb;
1400 if (this->fStarted) {
1406#define move_next_expected_hinted_point(iter, pElem) do {\
1407 pElem = iter.next(); \
1408 if (nullptr == pElem) return false; \
1412 GDIGlyphbufferPointIter hintedYs) {
1413 const uint8_t* cur_glyph = glyphbuf;
1414 const uint8_t* end_glyph = glyphbuf +
total_size;
1416 POINTFX
const * hintedPoint;
1418 while (cur_glyph < end_glyph) {
1419 const TTPOLYGONHEADER* th = (
const TTPOLYGONHEADER*)cur_glyph;
1421 const uint8_t* end_poly = cur_glyph + th->cb;
1422 const uint8_t* cur_poly = cur_glyph +
sizeof(TTPOLYGONHEADER);
1424 move_next_expected_hinted_point(hintedYs, hintedPoint);
1426 fCurrent = {th->pfxStart.x, hintedPoint->y};
1428 while (cur_poly < end_poly) {
1429 const TTPOLYCURVE* pc = (
const TTPOLYCURVE*)cur_poly;
1430 const POINTFX* apfx = pc->apfx;
1431 const WORD cpfx = pc->cpfx;
1433 if (pc->wType == TT_PRIM_LINE) {
1434 for (uint16_t
i = 0;
i < cpfx;
i++) {
1435 move_next_expected_hinted_point(hintedYs, hintedPoint);
1436 POINTFX pnt_b = {apfx[
i].x, hintedPoint->y};
1437 if (this->currentIsNot(pnt_b)) {
1438 this->goingTo(pnt_b);
1440 -SkFIXEDToScalar(pnt_b.y));
1445 if (pc->wType == TT_PRIM_QSPLINE) {
1446 POINTFX currentPoint = apfx[0];
1447 move_next_expected_hinted_point(hintedYs, hintedPoint);
1449 if (hintedYs.currentCurveType() == TT_PRIM_QSPLINE) {
1450 currentPoint.y = hintedPoint->y;
1452 for (uint16_t u = 0; u < cpfx - 1; u++) {
1453 POINTFX pnt_b = currentPoint;
1454 POINTFX pnt_c = apfx[u+1];
1455 move_next_expected_hinted_point(hintedYs, hintedPoint);
1457 if (hintedYs.currentCurveType() == TT_PRIM_QSPLINE) {
1458 pnt_c.y = hintedPoint->y;
1460 currentPoint.x = pnt_c.x;
1461 currentPoint.y = pnt_c.y;
1464 pnt_c.x = SkFixedToFIXED(
SkFixedAve(SkFIXEDToFixed(pnt_b.x),
1465 SkFIXEDToFixed(pnt_c.x)));
1466 pnt_c.y = SkFixedToFIXED(
SkFixedAve(SkFIXEDToFixed(pnt_b.y),
1467 SkFIXEDToFixed(pnt_c.y)));
1470 if (this->currentIsNot(pnt_b) || this->currentIsNot(pnt_c)) {
1471 this->goingTo(pnt_c);
1473 -SkFIXEDToScalar(pnt_b.y),
1474 SkFIXEDToScalar(pnt_c.x),
1475 -SkFIXEDToScalar(pnt_c.y));
1481 cur_poly +=
sizeof(
WORD) * 2 +
sizeof(POINTFX) * cpfx;
1483 cur_glyph += th->cb;
1484 if (this->fStarted) {
1504 total_size = GetGlyphOutlineW(fDDC, glyph,
flags, &gm, 0,
nullptr, &fMat22);
1506 LogFontTypeface::EnsureAccessible(this->getTypeface());
1507 total_size = GetGlyphOutlineW(fDDC, glyph,
flags, &gm, 0,
nullptr, &fMat22);
1518 if (GDI_ERROR == ret) {
1519 LogFontTypeface::EnsureAccessible(this->getTypeface());
1520 ret = GetGlyphOutlineW(fDDC, glyph,
flags, &gm,
total_size, glyphbuf->
get(), &fMat22);
1521 if (GDI_ERROR == ret) {
1558 SkGDIGeometrySink sink(
path);
1563 DWORD hinted_total_size = getGDIGlyphPath(glyphID, GGO_NATIVE | GGO_GLYPH_INDEX,
1565 if (0 == hinted_total_size) {
1569 SkGDIGeometrySink sinkXBufYIter(
path);
1570 if (!sinkXBufYIter.process(glyphbuf,
total_size,
1571 GDIGlyphbufferPointIter(hintedGlyphbuf, hinted_total_size)))
1575 SkGDIGeometrySink sink(
path);
1582static void logfont_for_name(
const char* familyName,
LOGFONT* lf) {
1586 size_t str_len = ::MultiByteToWideChar(CP_UTF8, 0, familyName,
1590 wchar_t *wideFamilyName =
new wchar_t[str_len];
1592 ::MultiByteToWideChar(CP_UTF8, 0, familyName, -1,
1593 wideFamilyName, str_len);
1594 ::wcsncpy(lf->lfFaceName, wideFamilyName, LF_FACESIZE - 1);
1595 delete [] wideFamilyName;
1596 lf->lfFaceName[LF_FACESIZE-1] =
L'\0';
1598 ::strncpy(lf->lfFaceName, familyName, LF_FACESIZE - 1);
1599 lf->lfFaceName[LF_FACESIZE - 1] =
'\0';
1603void LogFontTypeface::onGetFamilyName(
SkString* familyName)
const {
1605 SkAutoHDC hdc(fLogFont);
1606 dcfontname_to_skstring(hdc, fLogFont, familyName);
1610 bool* isLocalStream)
const {
1612 this->onGetFamilyName(&familyName);
1613 desc->setFamilyName(familyName.
c_str());
1614 desc->setStyle(this->fontStyle());
1615 *isLocalStream = this->fSerializeAsStream;
1618void LogFontTypeface::getGlyphToUnicodeMap(
SkUnichar* dstArray)
const {
1619 SkAutoHDC hdc(fLogFont);
1620 unsigned int glyphCount = calculateGlyphCount(hdc, fLogFont);
1621 populate_glyph_to_unicode(hdc, glyphCount, dstArray);
1624std::unique_ptr<SkAdvancedTypefaceMetrics> LogFontTypeface::onGetAdvancedMetrics()
const {
1626 std::unique_ptr<SkAdvancedTypefaceMetrics>
info(
nullptr);
1630 std::unique_ptr<HFONT_T, SkFunctionObject<DeleteObject>> designFont;
1633 const char stem_chars[] = {
'i',
'I',
'!',
'1'};
1635 unsigned glyphCount;
1639 OUTLINETEXTMETRIC otm;
1640 unsigned int otmRet = GetOutlineTextMetrics(hdc,
sizeof(otm), &otm);
1642 call_ensure_accessible(lf);
1643 otmRet = GetOutlineTextMetrics(hdc,
sizeof(otm), &otm);
1645 if (!otmRet || !GetTextFace(hdc, LF_FACESIZE, lf.lfFaceName)) {
1648 lf.lfHeight = -
SkToS32(otm.otmEMSquare);
1649 designFont.reset(CreateFontIndirect(&lf));
1650 SelectObject(hdc, designFont.get());
1651 if (!GetOutlineTextMetrics(hdc,
sizeof(otm), &otm)) {
1654 glyphCount = calculateGlyphCount(hdc, fLogFont);
1668 if (otm.otmfsType & 0x1) {
1673 if (glyphCount == 0 || (otm.otmTextMetrics.tmPitchAndFamily & TMPF_TRUETYPE) == 0) {
1679 if (!(otm.otmTextMetrics.tmPitchAndFamily & TMPF_FIXED_PITCH)) {
1682 if (otm.otmTextMetrics.tmItalic) {
1685 if (otm.otmTextMetrics.tmPitchAndFamily & FF_ROMAN) {
1687 }
else if (otm.otmTextMetrics.tmPitchAndFamily & FF_SCRIPT) {
1693 info->fItalicAngle = otm.otmItalicAngle / 10;
1694 info->fAscent =
SkToS16(otm.otmTextMetrics.tmAscent);
1695 info->fDescent =
SkToS16(-otm.otmTextMetrics.tmDescent);
1699 info->fCapHeight = otm.otmsCapEmHeight;
1702 otm.otmrcFontBox.right, otm.otmrcFontBox.bottom);
1706 min_width = SHRT_MAX;
1710 if (GetCharABCWidths(hdc, stem_chars[
i], stem_chars[
i], &abcWidths)) {
1711 int16_t
width = abcWidths.abcB;
1714 info->fStemV = min_width;
1723#define BASE64_GUID_ID "XXXXXXXXXXXXXXXXXXXXXXXX"
1725#define BASE64_GUID_ID_LEN std::size(BASE64_GUID_ID)
1727static_assert(BASE64_GUID_ID_LEN < LF_FACESIZE,
"GUID_longer_than_facesize");
1736static const char postscript_safe_base64_encode[] =
1737 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
1738 "abcdefghijklmnopqrstuvwxyz"
1747static void format_guid_b64(
const GUID& guid,
char*
buffer,
size_t bufferSize) {
1748 SkASSERT(bufferSize >= BASE64_GUID_ID_LEN);
1760static HRESULT create_unique_font_name(
char*
buffer,
size_t bufferSize) {
1762 if (
FAILED(CoCreateGuid(&guid))) {
1763 return E_UNEXPECTED;
1765 format_guid_b64(guid,
buffer, bufferSize);
1777 HANDLE fontHandle = AddFontMemResourceEx(
const_cast<void*
>(fontData->
data()),
1782 if (fontHandle !=
nullptr && numFonts < 1) {
1783 RemoveFontMemResourceEx(fontHandle);
1794 char familyName[BASE64_GUID_ID_LEN];
1795 const int familyNameSize =
std::size(familyName);
1796 if (
FAILED(create_unique_font_name(familyName, familyNameSize))) {
1802 if (
nullptr == rewrittenFontData.get()) {
1807 HANDLE fontReference = activate_font(rewrittenFontData.get());
1808 if (
nullptr == fontReference) {
1814 logfont_for_name(familyName, &lf);
1816 return sk_sp<SkTypeface>(SkCreateFontMemResourceTypefaceFromLOGFONT(lf, fontReference));
1819std::unique_ptr<SkStreamAsset> LogFontTypeface::onOpenStream(
int* ttcIndex)
const {
1827 std::unique_ptr<SkStreamAsset>
stream;
1828 DWORD tables[2] = {kTTCTag, 0};
1830 DWORD bufferSize = GetFontData(hdc, tables[
i], 0,
nullptr, 0);
1831 if (bufferSize == GDI_ERROR) {
1832 call_ensure_accessible(lf);
1833 bufferSize = GetFontData(hdc, tables[
i], 0,
nullptr, 0);
1835 if (bufferSize != GDI_ERROR) {
1837 if (GetFontData(hdc, tables[
i], 0, streamData->
writable_data(), bufferSize)) {
1852static void bmpCharsToGlyphs(HDC hdc,
const WCHAR* bmpChars,
int count, uint16_t*
glyphs,
1871 if (GDI_ERROR ==
result) {
1893static uint16_t nonBmpCharToGlyph(HDC hdc, SCRIPT_CACHE* scriptCache,
const WCHAR utf16[2]) {
1896 static const int numWCHAR = 2;
1897 static const int maxItems = 2;
1899 SCRIPT_CONTROL scriptControl;
1900 memset(&scriptControl, 0,
sizeof(scriptControl));
1903 SCRIPT_ITEM si[maxItems + 1];
1905 HRZM(ScriptItemize(utf16, numWCHAR, maxItems, &scriptControl,
nullptr, si, &numItems),
1906 "Could not itemize character.");
1909 static const int maxGlyphs = 2;
1910 SCRIPT_VISATTR vsa[maxGlyphs];
1911 WORD outGlyphs[maxGlyphs];
1912 WORD logClust[numWCHAR];
1914 SCRIPT_ANALYSIS&
script = si[0].a;
1915 script.eScript = SCRIPT_UNDEFINED;
1923 script.s.fOverrideDirection = 0;
1932 script.s.fEngineReserved = 0;
1934 HRZM(ScriptShape(hdc, scriptCache, utf16, numWCHAR, maxGlyphs, &
script,
1935 outGlyphs, logClust, vsa, &numGlyphs),
1936 "Could not shape character.");
1937 if (1 == numGlyphs) {
1938 index = outGlyphs[0];
1943void LogFontTypeface::onCharsToGlyphs(
const SkUnichar* uni,
int glyphCount,
1946 SkAutoHDC hdc(fLogFont);
1949 if (0 == GetTextMetrics(hdc, &tm)) {
1950 call_ensure_accessible(fLogFont);
1951 if (0 == GetTextMetrics(hdc, &tm)) {
1952 tm.tmPitchAndFamily = TMPF_TRUETYPE;
1955 bool Ox1FHack = !(tm.tmPitchAndFamily & TMPF_VECTOR) ;
1957 SCRIPT_CACHE sc =
nullptr;
1958 static const int scratchCount = 256;
1959 WCHAR scratch[scratchCount];
1961 const uint32_t* utf32 =
reinterpret_cast<const uint32_t*
>(uni);
1962 while (glyphIndex < glyphCount) {
1964 int glyphsLeft =
std::min(glyphCount - glyphIndex, scratchCount);
1966 while (runLength < glyphsLeft && utf32[glyphIndex + runLength] <= 0xFFFF) {
1967 scratch[runLength] =
static_cast<WCHAR
>(utf32[glyphIndex + runLength]);
1971 bmpCharsToGlyphs(hdc, scratch, runLength, &
glyphs[glyphIndex], Ox1FHack);
1972 glyphIndex += runLength;
1976 while (glyphIndex < glyphCount && utf32[glyphIndex] > 0xFFFF) {
1977 SkUTF::ToUTF16(utf32[glyphIndex],
reinterpret_cast<uint16_t*
>(scratch));
1978 glyphs[glyphIndex] = nonBmpCharToGlyph(hdc, &sc, scratch);
1984 ::ScriptFreeCache(&sc);
1988int LogFontTypeface::onCountGlyphs()
const {
1989 SkAutoHDC hdc(fLogFont);
1990 return calculateGlyphCount(hdc, fLogFont);
1993void LogFontTypeface::getPostScriptGlyphNames(
SkString*)
const {}
1995int LogFontTypeface::onGetUPEM()
const {
1996 SkAutoHDC hdc(fLogFont);
1997 return calculateUPEM(hdc, fLogFont);
2005 this->getFamilyName(&familyName);
2007 nameIter = sk_make_sp<SkOTUtils::LocalizedStrings_SingleName>(familyName, language);
2012int LogFontTypeface::onGetTableTags(
SkFontTableTag tags[])
const {
2027 for (
int i = 0;
i < numTables; ++
i) {
2041 if (
nullptr ==
data) {
2045 if (bufferSize == GDI_ERROR) {
2046 call_ensure_accessible(lf);
2049 return bufferSize == GDI_ERROR ? 0 : bufferSize;
2057 DWORD size = GetFontData(hdc, tag, 0,
nullptr, 0);
2058 if (
size == GDI_ERROR) {
2059 call_ensure_accessible(lf);
2060 size = GetFontData(hdc, tag, 0,
nullptr, 0);
2064 if (
size != GDI_ERROR) {
2066 if (GetFontData(hdc, tag, 0,
data->writable_data(),
size) == GDI_ERROR) {
2073std::unique_ptr<SkScalerContext> LogFontTypeface::onCreateScalerContext(
2076 auto ctx = std::make_unique<SkScalerContext_GDI>(
2077 sk_ref_sp(
const_cast<LogFontTypeface*
>(
this)), effects,
desc);
2078 if (ctx->isValid()) {
2079 return std::move(ctx);
2084 ctx = std::make_unique<SkScalerContext_GDI>(
2085 sk_ref_sp(
const_cast<LogFontTypeface*
>(
this)), effects,
desc);
2086 if (ctx->isValid()) {
2087 return std::move(ctx);
2091 sk_ref_sp(
const_cast<LogFontTypeface*
>(
this)), effects,
desc);
2107 rec->
fFlags &= ~flagsWeDontSupport;
2141 if (!fCanBeLCD &&
isLCD(*rec)) {
2152static bool valid_logfont_for_enum(
const LOGFONT& lf) {
2156 lf.lfFaceName[0] && lf.lfFaceName[0] !=
'@'
2160 && ANSI_CHARSET == lf.lfCharSet
2168static int CALLBACK enum_family_proc(
const LOGFONT* lf,
const TEXTMETRIC*,
2170 if (valid_logfont_for_enum(*lf)) {
2172 *array->
append() = *(
const ENUMLOGFONTEX*)lf;
2179 SkFontStyleSetGDI(
const TCHAR familyName[]) {
2182 lf.lfCharSet = DEFAULT_CHARSET;
2183 _tcscpy_s(lf.lfFaceName, familyName);
2185 HDC hdc = ::CreateCompatibleDC(
nullptr);
2186 ::EnumFontFamiliesEx(hdc, &lf, enum_family_proc, (
LPARAM)&fArray, 0);
2190 int count()
override {
2191 return fArray.size();
2196 *fs = get_style(fArray[index].elfLogFont);
2199 const ENUMLOGFONTEX& ref = fArray[index];
2206 SkASSERT(
sizeof(TCHAR) ==
sizeof(ref.elfStyle[0]));
2207 tchar_to_skstring((
const TCHAR*)ref.elfStyle, styleName);
2212 return SkCreateTypefaceFromLOGFONT(fArray[index].elfLogFont);
2228 lf.lfCharSet = DEFAULT_CHARSET;
2230 HDC hdc = ::CreateCompatibleDC(
nullptr);
2231 ::EnumFontFamiliesEx(hdc, &lf, enum_family_proc, (
LPARAM)&fLogFontArray, 0);
2237 return fLogFontArray.size();
2241 SkASSERT(index < fLogFontArray.size());
2242 tchar_to_skstring(fLogFontArray[index].elfLogFont.lfFaceName, familyName);
2246 SkASSERT(index < fLogFontArray.size());
2248 new SkFontStyleSetGDI(fLogFontArray[index].elfLogFont.lfFaceName));
2252 if (
nullptr == familyName) {
2256 logfont_for_name(familyName, &lf);
2264 return sset->matchStyle(fontstyle);
2268 const char* bcp47[],
int bcp47Count,
2274 int ttcIndex)
const override {
2275 if (ttcIndex != 0) {
2278 return create_from_stream(std::move(
stream));
2300 if (
nullptr == familyName) {
2301 lf = get_default_font();
2303 logfont_for_name(familyName, &lf);
2306 lf.lfWeight = style.
weight();
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
sk_bzero(glyphs, sizeof(glyphs))
static float next(float f)
static float prev(float f)
#define SkDEBUGFAIL(message)
static size_t total_size(SkSBlockAllocator< N > &pool)
static U8CPU SkComputeLuminance(U8CPU r, U8CPU g, U8CPU b)
static U16CPU SkPack888ToRGB16(U8CPU r, U8CPU g, U8CPU b)
#define SkEndian_SwapBE32(n)
#define SkEndian_SwapBE16(n)
#define SkTEndian_SwapBE32(n)
#define SkScalarToFixed(x)
#define SkFixedToScalar(x)
#define SkFixedToFloat(x)
#define SkFloatToFixed(x)
static bool isLCD(const SkScalerContextRec &rec)
static bool bothZero(SkScalar a, SkScalar b)
static bool isAxisAligned(const SkScalerContextRec &rec)
@ 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 bool left(const SkPoint &p0, const SkPoint &p1)
#define INHERITED(method,...)
sk_sp< T > sk_ref_sp(T *obj)
#define SkScalarInvert(x)
#define SkScalarTruncToInt(x)
#define SkScalarToFloat(x)
#define SkScalarRoundToInt(x)
#define SkScalarRoundToScalar(x)
D * SkTAddOffset(S *ptr, ptrdiff_t byteOffset)
SkDEBUGCODE(SK_SPI) SkThreadID SkGetThreadID()
constexpr int32_t SkToS32(S x)
constexpr uint8_t SkToU8(S x)
constexpr int16_t SkToS16(S x)
static constexpr SkFourByteTag SkSetFourByteTag(char a, char b, char c, char d)
static void draw(SkCanvas *canvas, SkRect &target, int x, int y)
static sk_sp< SkData > MakeUninitialized(size_t length)
const void * data() const
virtual void onGetFamilyName(int index, SkString *familyName) const =0
sk_sp< SkTypeface > makeFromStream(std::unique_ptr< SkStreamAsset >, int ttcIndex=0) const
sk_sp< SkFontStyleSet > matchFamily(const char familyName[]) const
virtual sk_sp< SkTypeface > onMakeFromData(sk_sp< SkData >, int ttcIndex) const =0
virtual sk_sp< SkFontStyleSet > onCreateStyleSet(int index) const =0
virtual sk_sp< SkTypeface > onMatchFamilyStyleCharacter(const char familyName[], const SkFontStyle &, const char *bcp47[], int bcp47Count, SkUnichar character) const =0
virtual sk_sp< SkFontStyleSet > onMatchFamily(const char familyName[]) const =0
virtual sk_sp< SkTypeface > onMakeFromStreamIndex(std::unique_ptr< SkStreamAsset >, int ttcIndex) const =0
virtual sk_sp< SkTypeface > onMakeFromStreamArgs(std::unique_ptr< SkStreamAsset >, const SkFontArguments &) const =0
virtual sk_sp< SkTypeface > onMatchFamilyStyle(const char familyName[], const SkFontStyle &) const =0
virtual sk_sp< SkTypeface > onLegacyMakeTypeface(const char familyName[], SkFontStyle) const =0
virtual sk_sp< SkTypeface > onMakeFromFile(const char path[], int ttcIndex) const =0
virtual int onCountFamilies() const =0
sk_sp< SkTypeface > matchStyleCSS3(const SkFontStyle &pattern)
virtual sk_sp< SkTypeface > createTypeface(int index)=0
virtual sk_sp< SkTypeface > matchStyle(const SkFontStyle &pattern)=0
virtual void getStyle(int index, SkFontStyle *, SkString *style)=0
SkGlyphID getGlyphID() const
SkMask::Format maskFormat() const
static constexpr int kMScaleX
horizontal scale factor
static constexpr int kMSkewY
vertical skew factor
SkScalar get(int index) const
static constexpr int kMScaleY
vertical scale factor
static constexpr int kMSkewX
horizontal skew factor
SkPath & moveTo(SkScalar x, SkScalar y)
SkPath & lineTo(SkScalar x, SkScalar y)
SkPath & quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2)
virtual void generateFontMetrics(SkFontMetrics *)=0
@ kEmbeddedBitmapText_Flag
virtual void generateImage(const SkGlyph &glyph, void *imageBuffer)=0
virtual GlyphMetrics generateMetrics(const SkGlyph &, SkArenaAlloc *)=0
virtual bool generatePath(const SkGlyph &, SkPath *)=0
static std::unique_ptr< SkScalerContext > MakeEmpty(sk_sp< SkTypeface > typeface, const SkScalerContextEffects &effects, const SkDescriptor *desc)
static std::unique_ptr< SkStreamAsset > MakeFromFile(const char path[])
const char * c_str() const
static sk_sp< SkTypeface > FindByProcAndRef(FindProc proc, void *ctx)
static void Add(sk_sp< SkTypeface >)
virtual sk_sp< SkData > onCopyTableData(SkFontTableTag) const
virtual void getPostScriptGlyphNames(SkString *) const =0
virtual std::unique_ptr< SkAdvancedTypefaceMetrics > onGetAdvancedMetrics() const =0
void setFontStyle(SkFontStyle style)
virtual void getGlyphToUnicodeMap(SkUnichar *dstArray) const =0
void setIsFixedPitch(bool isFixedPitch)
virtual std::unique_ptr< SkScalerContext > onCreateScalerContext(const SkScalerContextEffects &, const SkDescriptor *) const =0
virtual int onCountGlyphs() const =0
virtual int onGetTableTags(SkFontTableTag tags[]) const =0
virtual std::unique_ptr< SkStreamAsset > onOpenStream(int *ttcIndex) const =0
virtual void onGetFontDescriptor(SkFontDescriptor *, bool *isLocal) const =0
virtual sk_sp< SkTypeface > onMakeClone(const SkFontArguments &) const =0
virtual size_t onGetTableData(SkFontTableTag, size_t offset, size_t length, void *data) const =0
virtual bool onGetPostScriptName(SkString *) const =0
virtual void onGetFamilyName(SkString *familyName) const =0
virtual void onFilterRec(SkScalerContextRec *) const =0
virtual bool onGlyphMaskNeedsCurrentColor() const =0
virtual LocalizedStrings * onCreateFamilyNameIterator() const =0
virtual int onGetVariationDesignParameters(SkFontParameters::Variation::Axis parameters[], int parameterCount) const =0
virtual void onCharsToGlyphs(const SkUnichar *chars, int count, SkGlyphID glyphs[]) const =0
virtual int onGetUPEM() const =0
virtual int onGetVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[], int coordinateCount) const =0
EMSCRIPTEN_KEEPALIVE void empty()
FlutterSemanticsFlag flags
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
uint32_t uint32_t * format
static float max(float r, float g, float b)
static float min(float r, float g, float b)
SK_API sk_sp< SkDocument > Make(SkWStream *dst, const SkSerialProcs *=nullptr, std::function< void(const SkPicture *)> onEndPage=nullptr)
Optional< SkRect > bounds
SK_SPI size_t ToUTF16(SkUnichar uni, uint16_t utf16[2]=nullptr)
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
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 to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace Enable an endless trace buffer The default is a ring buffer This is useful when very old events need to viewed For during application launch Memory usage will continue to grow indefinitely however Start app with an specific route defined on the framework flutter assets dir
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 to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
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
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 to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not set
font
Font Metadata and Metrics.
static const char header[]
static void process(const char *inPath, const char *lexer, const char *token, const char *hPath, const char *cppPath)
@ kNotEmbeddable_FontFlag
May not be embedded.
static size_t Encode(const void *src, size_t length, void *dst, const char *encode=nullptr)
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 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
@ kUnderlinePositionIsValid_Flag
set if fUnderlinePosition is valid
@ kUnderlineThicknessIsValid_Flag
set if fUnderlineThickness is valid
SkScalar fDescent
distance to reserve below baseline, typically positive
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)
@ kA8_Format
8bits per pixel mask (e.g. antialiasing)
@ kLCD16_Format
565 alpha for r/g/b
@ kBW_Format
1bit per pixel mask (e.g. monochrome)
static const SK_OT_ULONG TAG
static constexpr SK_OT_ULONG TAG
static SkData * RenameFont(SkStreamAsset *fontData, const char *fontName, int fontNameLen)
static void SetAdvancedTypefaceFlags(SkOTTableOS2_V4::Type fsType, SkAdvancedTypefaceMetrics *info)
SkRect makeOutset(float dx, float dy) const
static constexpr SkRect MakeXYWH(float x, float y, float w, float h)
SkMask::Format fMaskFormat
SkFontHinting getHinting() const
void setHinting(SkFontHinting)
std::shared_ptr< const fml::Mapping > data