xref: /aosp_15_r20/external/skia/src/ports/SkFontHost_win.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2006 The Android Open Source Project
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "include/core/SkTypes.h"
9 #if defined(SK_BUILD_FOR_WIN)
10 
11 #include "include/core/SkData.h"
12 #include "include/core/SkFontMetrics.h"
13 #include "include/core/SkFontTypes.h"
14 #include "include/core/SkPath.h"
15 #include "include/core/SkStream.h"
16 #include "include/core/SkString.h"
17 #include "include/ports/SkTypeface_win.h"
18 #include "include/private/SkColorData.h"
19 #include "include/private/base/SkMacros.h"
20 #include "include/private/base/SkOnce.h"
21 #include "include/private/base/SkTDArray.h"
22 #include "include/private/base/SkTemplates.h"
23 #include "include/private/base/SkTo.h"
24 #include "src/base/SkBase64.h"
25 #include "src/base/SkLeanWindows.h"
26 #include "src/base/SkUTF.h"
27 #include "src/core/SkAdvancedTypefaceMetrics.h"
28 #include "src/core/SkDescriptor.h"
29 #include "src/core/SkFontDescriptor.h"
30 #include "src/core/SkGlyph.h"
31 #include "src/core/SkMaskGamma.h"
32 #include "src/core/SkStrikeCache.h"
33 #include "src/core/SkTypefaceCache.h"
34 #include "src/sfnt/SkOTTable_OS_2.h"
35 #include "src/sfnt/SkOTTable_maxp.h"
36 #include "src/sfnt/SkOTTable_name.h"
37 #include "src/sfnt/SkOTUtils.h"
38 #include "src/sfnt/SkSFNTHeader.h"
39 #include "src/utils/SkMatrix22.h"
40 #include "src/utils/win/SkHRESULT.h"
41 
42 #include <tchar.h>
43 #include <usp10.h>
44 #include <objbase.h>
45 
46 using namespace skia_private;
47 
48 namespace {
49 static inline const constexpr bool kSkShowTextBlitCoverage = false;
50 }
51 
52 static void (*gEnsureLOGFONTAccessibleProc)(const LOGFONT&);
53 
SkTypeface_SetEnsureLOGFONTAccessibleProc(void (* proc)(const LOGFONT &))54 void SkTypeface_SetEnsureLOGFONTAccessibleProc(void (*proc)(const LOGFONT&)) {
55     gEnsureLOGFONTAccessibleProc = proc;
56 }
57 
call_ensure_accessible(const LOGFONT & lf)58 static void call_ensure_accessible(const LOGFONT& lf) {
59     if (gEnsureLOGFONTAccessibleProc) {
60         gEnsureLOGFONTAccessibleProc(lf);
61     }
62 }
63 
64 ///////////////////////////////////////////////////////////////////////////////
65 
66 // always packed xxRRGGBB
67 typedef uint32_t SkGdiRGB;
68 
69 // define this in your Makefile or .gyp to enforce AA requests
70 // which GDI ignores at small sizes. This flag guarantees AA
71 // for rotated text, regardless of GDI's notions.
72 //#define SK_ENFORCE_ROTATED_TEXT_AA_ON_WINDOWS
73 
isLCD(const SkScalerContextRec & rec)74 static bool isLCD(const SkScalerContextRec& rec) {
75     return SkMask::kLCD16_Format == rec.fMaskFormat;
76 }
77 
bothZero(SkScalar a,SkScalar b)78 static bool bothZero(SkScalar a, SkScalar b) {
79     return 0 == a && 0 == b;
80 }
81 
82 // returns false if there is any non-90-rotation or skew
isAxisAligned(const SkScalerContextRec & rec)83 static bool isAxisAligned(const SkScalerContextRec& rec) {
84     return 0 == rec.fPreSkewX &&
85            (bothZero(rec.fPost2x2[0][1], rec.fPost2x2[1][0]) ||
86             bothZero(rec.fPost2x2[0][0], rec.fPost2x2[1][1]));
87 }
88 
needToRenderWithSkia(const SkScalerContextRec & rec)89 static bool needToRenderWithSkia(const SkScalerContextRec& rec) {
90 #ifdef SK_ENFORCE_ROTATED_TEXT_AA_ON_WINDOWS
91     // What we really want to catch is when GDI will ignore the AA request and give
92     // us BW instead. Smallish rotated text is one heuristic, so this code is just
93     // an approximation. We shouldn't need to do this for larger sizes, but at those
94     // sizes, the quality difference gets less and less between our general
95     // scanconverter and GDI's.
96     if (SkMask::kA8_Format == rec.fMaskFormat && !isAxisAligned(rec)) {
97         return true;
98     }
99 #endif
100     return rec.getHinting() == SkFontHinting::kNone || rec.getHinting() == SkFontHinting::kSlight;
101 }
102 
tchar_to_skstring(const TCHAR t[],SkString * s)103 static void tchar_to_skstring(const TCHAR t[], SkString* s) {
104 #ifdef UNICODE
105     size_t sSize = WideCharToMultiByte(CP_UTF8, 0, t, -1, nullptr, 0, nullptr, nullptr);
106     s->resize(sSize);
107     WideCharToMultiByte(CP_UTF8, 0, t, -1, s->data(), sSize, nullptr, nullptr);
108 #else
109     s->set(t);
110 #endif
111 }
112 
dcfontname_to_skstring(HDC deviceContext,const LOGFONT & lf,SkString * familyName)113 static void dcfontname_to_skstring(HDC deviceContext, const LOGFONT& lf, SkString* familyName) {
114     int fontNameLen; //length of fontName in TCHARS.
115     if (0 == (fontNameLen = GetTextFace(deviceContext, 0, nullptr))) {
116         call_ensure_accessible(lf);
117         if (0 == (fontNameLen = GetTextFace(deviceContext, 0, nullptr))) {
118             fontNameLen = 0;
119         }
120     }
121 
122     AutoSTArray<LF_FULLFACESIZE, TCHAR> fontName(fontNameLen+1);
123     if (0 == GetTextFace(deviceContext, fontNameLen, fontName.get())) {
124         call_ensure_accessible(lf);
125         if (0 == GetTextFace(deviceContext, fontNameLen, fontName.get())) {
126             fontName[0] = 0;
127         }
128     }
129 
130     tchar_to_skstring(fontName.get(), familyName);
131 }
132 
make_canonical(LOGFONT * lf)133 static void make_canonical(LOGFONT* lf) {
134     lf->lfHeight = -64;
135     lf->lfWidth = 0;  // lfWidth is related to lfHeight, not to the OS/2::usWidthClass.
136     lf->lfQuality = CLEARTYPE_QUALITY;//PROOF_QUALITY;
137     lf->lfCharSet = DEFAULT_CHARSET;
138 //    lf->lfClipPrecision = 64;
139 }
140 
get_style(const LOGFONT & lf)141 static SkFontStyle get_style(const LOGFONT& lf) {
142     return SkFontStyle(lf.lfWeight,
143                        SkFontStyle::kNormal_Width,
144                        lf.lfItalic ? SkFontStyle::kItalic_Slant : SkFontStyle::kUpright_Slant);
145 }
146 
SkFixedToFIXED(SkFixed x)147 static inline FIXED SkFixedToFIXED(SkFixed x) {
148     return *(FIXED*)(&x);
149 }
SkFIXEDToFixed(FIXED x)150 static inline SkFixed SkFIXEDToFixed(FIXED x) {
151     return *(SkFixed*)(&x);
152 }
153 
SkScalarToFIXED(SkScalar x)154 static inline FIXED SkScalarToFIXED(SkScalar x) {
155     return SkFixedToFIXED(SkScalarToFixed(x));
156 }
157 
SkFIXEDToScalar(FIXED x)158 static inline SkScalar SkFIXEDToScalar(FIXED x) {
159     return SkFixedToScalar(SkFIXEDToFixed(x));
160 }
161 
calculateGlyphCount(HDC hdc,const LOGFONT & lf)162 static 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);
168     }
169 
170     if (!(textMetric.tmPitchAndFamily & TMPF_VECTOR)) {
171         return textMetric.tmLastChar;
172     }
173 
174     // The 'maxp' table stores the number of glyphs at offset 4, in 2 bytes.
175     uint16_t glyphs;
176     if (GDI_ERROR != GetFontData(hdc, SkOTTableMaximumProfile::TAG, 4, &glyphs, sizeof(glyphs))) {
177         return SkEndian_SwapBE16(glyphs);
178     }
179 
180     // Binary search for glyph count.
181     static const MAT2 mat2 = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
182     int32_t max = UINT16_MAX + 1;
183     int32_t min = 0;
184     GLYPHMETRICS gm;
185     while (min < max) {
186         int32_t mid = min + ((max - min) / 2);
187         if (GetGlyphOutlineW(hdc, mid, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0,
188                              nullptr, &mat2) == GDI_ERROR) {
189             max = mid;
190         } else {
191             min = mid + 1;
192         }
193     }
194     SkASSERT(min == max);
195     return min;
196 }
197 
calculateUPEM(HDC hdc,const LOGFONT & lf)198 static 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);
204     }
205 
206     if (!(textMetric.tmPitchAndFamily & TMPF_VECTOR)) {
207         return textMetric.tmMaxCharWidth;
208     }
209 
210     OUTLINETEXTMETRIC otm;
211     unsigned int otmRet = GetOutlineTextMetrics(hdc, sizeof(otm), &otm);
212     if (0 == otmRet) {
213         call_ensure_accessible(lf);
214         otmRet = GetOutlineTextMetrics(hdc, sizeof(otm), &otm);
215     }
216 
217     return (0 == otmRet) ? 0 : otm.otmEMSquare;
218 }
219 
220 class SkAutoHDC {
221 public:
SkAutoHDC(const LOGFONT & lf)222     explicit SkAutoHDC(const LOGFONT& lf)
223         : fHdc(::CreateCompatibleDC(nullptr))
224         , fFont(::CreateFontIndirect(&lf))
225         , fSavefont((HFONT)::SelectObject(fHdc, fFont))
226     { }
~SkAutoHDC()227     ~SkAutoHDC() {
228         if (fHdc) {
229             ::SelectObject(fHdc, fSavefont);
230             ::DeleteDC(fHdc);
231         }
232         if (fFont) {
233             ::DeleteObject(fFont);
234         }
235     }
operator HDC()236     operator HDC() { return fHdc; }
237 private:
238     HDC fHdc;
239     HFONT fFont;
240     HFONT fSavefont;
241 };
242 
243 class LogFontTypeface : public SkTypeface {
244 public:
LogFontTypeface(const SkFontStyle & style,const LOGFONT & lf,bool serializeAsStream)245     LogFontTypeface(const SkFontStyle& style, const LOGFONT& lf, bool serializeAsStream)
246         : SkTypeface(style, false)
247         , fLogFont(lf)
248         , fSerializeAsStream(serializeAsStream)
249     {
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;
256             }
257         }
258 
259         // The fixed pitch bit is set if the font is *not* fixed pitch.
260         this->setIsFixedPitch((textMetric.tmPitchAndFamily & TMPF_FIXED_PITCH) == 0);
261         this->setFontStyle(SkFontStyle(textMetric.tmWeight, style.width(), style.slant()));
262 
263         // Used a logfont on a memory context, should never get a device font.
264         // Therefore all TMPF_DEVICE will be PostScript (cubic) fonts.
265         // If the font has cubic outlines, it will not be rendered with ClearType.
266         fCanBeLCD = !((textMetric.tmPitchAndFamily & TMPF_VECTOR) &&
267                       (textMetric.tmPitchAndFamily & TMPF_DEVICE));
268     }
269 
270     LOGFONT fLogFont;
271     bool fSerializeAsStream;
272     bool fCanBeLCD;
273 
Make(const LOGFONT & lf)274     static sk_sp<LogFontTypeface> Make(const LOGFONT& lf) {
275         return sk_sp<LogFontTypeface>(new LogFontTypeface(get_style(lf), lf, false));
276     }
277 
EnsureAccessible(const SkTypeface * face)278     static void EnsureAccessible(const SkTypeface* face) {
279         call_ensure_accessible(static_cast<const LogFontTypeface*>(face)->fLogFont);
280     }
281 
282 protected:
283     std::unique_ptr<SkStreamAsset> onOpenStream(int* ttcIndex) const override;
284     sk_sp<SkTypeface> onMakeClone(const SkFontArguments& args) const override;
285     std::unique_ptr<SkScalerContext> onCreateScalerContext(const SkScalerContextEffects&,
286                                                            const SkDescriptor*) const override;
287     void onFilterRec(SkScalerContextRec*) const override;
288     void getGlyphToUnicodeMap(SkUnichar*) const override;
289     std::unique_ptr<SkAdvancedTypefaceMetrics> onGetAdvancedMetrics() const override;
290     void onGetFontDescriptor(SkFontDescriptor*, bool*) const override;
291     void onCharsToGlyphs(const SkUnichar* chars, int count, SkGlyphID glyphs[]) const override;
292     int onCountGlyphs() const override;
293     void getPostScriptGlyphNames(SkString*) const override;
294     int onGetUPEM() const override;
295     void onGetFamilyName(SkString* familyName) const override;
onGetPostScriptName(SkString *) const296     bool onGetPostScriptName(SkString*) const override { return false; }
297     SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const override;
onGlyphMaskNeedsCurrentColor() const298     bool onGlyphMaskNeedsCurrentColor() const override { return false; }
onGetVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[],int coordinateCount) const299     int onGetVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[],
300                                      int coordinateCount) const override
301     {
302         return -1;
303     }
onGetVariationDesignParameters(SkFontParameters::Variation::Axis parameters[],int parameterCount) const304     int onGetVariationDesignParameters(SkFontParameters::Variation::Axis parameters[],
305                                        int parameterCount) const override
306     {
307         return -1;
308     }
309     int onGetTableTags(SkFontTableTag tags[]) const override;
310     size_t onGetTableData(SkFontTableTag, size_t offset, size_t length, void* data) const override;
311     sk_sp<SkData> onCopyTableData(SkFontTableTag) const override;
312 };
313 
314 class FontMemResourceTypeface : public LogFontTypeface {
315 public:
316     /**
317      *  The created FontMemResourceTypeface takes ownership of fontMemResource.
318      */
Make(const LOGFONT & lf,HANDLE fontMemResource)319     static sk_sp<FontMemResourceTypeface> Make(const LOGFONT& lf, HANDLE fontMemResource) {
320         return sk_sp<FontMemResourceTypeface>(
321             new FontMemResourceTypeface(get_style(lf), lf, fontMemResource));
322     }
323 
324 protected:
weak_dispose() const325     void weak_dispose() const override {
326         RemoveFontMemResourceEx(fFontMemResource);
327         INHERITED::weak_dispose();
328     }
329 
330 private:
331     /**
332      *  Takes ownership of fontMemResource.
333      */
FontMemResourceTypeface(const SkFontStyle & style,const LOGFONT & lf,HANDLE fontMemResource)334     FontMemResourceTypeface(const SkFontStyle& style, const LOGFONT& lf, HANDLE fontMemResource)
335         : LogFontTypeface(style, lf, true), fFontMemResource(fontMemResource)
336     { }
337 
338     HANDLE fFontMemResource;
339 
340     using INHERITED = LogFontTypeface;
341 };
342 
get_default_font()343 static const LOGFONT& get_default_font() {
344     static LOGFONT gDefaultFont;
345     return gDefaultFont;
346 }
347 
FindByLogFont(SkTypeface * face,void * ctx)348 static bool FindByLogFont(SkTypeface* face, void* ctx) {
349     LogFontTypeface* lface = static_cast<LogFontTypeface*>(face);
350     const LOGFONT* lf = reinterpret_cast<const LOGFONT*>(ctx);
351 
352     return !memcmp(&lface->fLogFont, lf, sizeof(LOGFONT));
353 }
354 
355 /**
356  *  This is public. It first searches the cache, and if a match is not found,
357  *  it creates a new face.
358  */
SkCreateTypefaceFromLOGFONT(const LOGFONT & origLF)359 sk_sp<SkTypeface> SkCreateTypefaceFromLOGFONT(const LOGFONT& origLF) {
360     LOGFONT lf = origLF;
361     make_canonical(&lf);
362     sk_sp<SkTypeface> face = SkTypefaceCache::FindByProcAndRef(FindByLogFont, &lf);
363     if (!face) {
364         face = LogFontTypeface::Make(lf);
365         SkTypefaceCache::Add(face);
366     }
367     return face;
368 }
369 
370 /**
371  *  The created SkTypeface takes ownership of fontMemResource.
372  */
SkCreateFontMemResourceTypefaceFromLOGFONT(const LOGFONT & origLF,HANDLE fontMemResource)373 sk_sp<SkTypeface> SkCreateFontMemResourceTypefaceFromLOGFONT(const LOGFONT& origLF, HANDLE fontMemResource) {
374     LOGFONT lf = origLF;
375     make_canonical(&lf);
376     // We'll never get a cache hit, so no point in putting this in SkTypefaceCache.
377     return FontMemResourceTypeface::Make(lf, fontMemResource);
378 }
379 
380 /**
381  *  This is public
382  */
SkLOGFONTFromTypeface(const SkTypeface * face,LOGFONT * lf)383 void SkLOGFONTFromTypeface(const SkTypeface* face, LOGFONT* lf) {
384     if (nullptr == face) {
385         *lf = get_default_font();
386     } else {
387         *lf = static_cast<const LogFontTypeface*>(face)->fLogFont;
388     }
389 }
390 
391 // Construct Glyph to Unicode table.
392 // Unicode code points that require conjugate pairs in utf16 are not
393 // supported.
394 // TODO(arthurhsu): Add support for conjugate pairs. It looks like that may
395 // require parsing the TTF cmap table (platform 4, encoding 12) directly instead
396 // of calling GetFontUnicodeRange().
populate_glyph_to_unicode(HDC fontHdc,const unsigned glyphCount,SkUnichar * glyphToUnicode)397 static void populate_glyph_to_unicode(HDC fontHdc, const unsigned glyphCount,
398                                       SkUnichar* glyphToUnicode) {
399     sk_bzero(glyphToUnicode, sizeof(SkUnichar) * glyphCount);
400     DWORD glyphSetBufferSize = GetFontUnicodeRanges(fontHdc, nullptr);
401     if (!glyphSetBufferSize) {
402         return;
403     }
404 
405     std::unique_ptr<BYTE[]> glyphSetBuffer(new BYTE[glyphSetBufferSize]);
406     GLYPHSET* glyphSet =
407         reinterpret_cast<LPGLYPHSET>(glyphSetBuffer.get());
408     if (GetFontUnicodeRanges(fontHdc, glyphSet) != glyphSetBufferSize) {
409         return;
410     }
411 
412     for (DWORD i = 0; i < glyphSet->cRanges; ++i) {
413         // There is no guarantee that within a Unicode range, the corresponding
414         // glyph id in a font file are continuous. So, even if we have ranges,
415         // we can't just use the first and last entry of the range to compute
416         // result. We need to enumerate them one by one.
417         int count = glyphSet->ranges[i].cGlyphs;
418         AutoTArray<WCHAR> chars(count + 1);
419         chars[count] = 0;  // termintate string
420         AutoTArray<WORD> glyph(count);
421         for (USHORT j = 0; j < count; ++j) {
422             chars[j] = glyphSet->ranges[i].wcLow + j;
423         }
424         GetGlyphIndicesW(fontHdc, chars.get(), count, glyph.get(),
425                          GGI_MARK_NONEXISTING_GLYPHS);
426         // If the glyph ID is valid, and the glyph is not mapped, then we will
427         // fill in the char id into the vector. If the glyph is mapped already,
428         // skip it.
429         // TODO(arthurhsu): better improve this. e.g. Get all used char ids from
430         // font cache, then generate this mapping table from there. It's
431         // unlikely to have collisions since glyph reuse happens mostly for
432         // different Unicode pages.
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];
436             }
437         }
438     }
439 }
440 
441 //////////////////////////////////////////////////////////////////////////////////////
442 
alignTo32(int n)443 static int alignTo32(int n) {
444     return (n + 31) & ~31;
445 }
446 
447 struct MyBitmapInfo : public BITMAPINFO {
448     RGBQUAD fMoreSpaceForColors[1];
449 };
450 
451 class HDCOffscreen {
452 public:
453     HDCOffscreen() = default;
454 
~HDCOffscreen()455     ~HDCOffscreen() {
456         if (fDC) {
457             ::SelectObject(fDC, fSavefont);
458             ::DeleteDC(fDC);
459         }
460         if (fBM) {
461             DeleteObject(fBM);
462         }
463     }
464 
init(HFONT font,const XFORM & xform)465     void init(HFONT font, const XFORM& xform) {
466         fFont = font;
467         fXform = xform;
468     }
469 
470     void* draw(const SkGlyph&, bool isBW, size_t* srcRBPtr);
471 
472 private:
473     HDC     fDC{nullptr};
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};  // points into fBM
479     int     fWidth{0};
480     int     fHeight{0};
481     bool    fIsBW{false};
482 };
483 
draw(const SkGlyph & glyph,bool isBW,size_t * srcRBPtr)484 void* HDCOffscreen::draw(const SkGlyph& glyph, bool isBW, size_t* srcRBPtr) {
485     // Can we share the scalercontext's fDDC, so we don't need to create
486     // a separate fDC here?
487     if (nullptr == fDC) {
488         fDC = CreateCompatibleDC(0);
489         if (nullptr == fDC) {
490             return nullptr;
491         }
492         SetGraphicsMode(fDC, GM_ADVANCED);
493         SetBkMode(fDC, TRANSPARENT);
494         SetTextAlign(fDC, TA_LEFT | TA_BASELINE);
495         fSavefont = (HFONT)SelectObject(fDC, fFont);
496 
497         COLORREF color = 0x00FFFFFF;
498         SkDEBUGCODE(COLORREF prev =) SetTextColor(fDC, color);
499         SkASSERT(prev != CLR_INVALID);
500     }
501 
502     if (fBM && (fIsBW != isBW || fWidth < glyph.width() || fHeight < glyph.height())) {
503         DeleteObject(fBM);
504         fBM = nullptr;
505     }
506     fIsBW = isBW;
507 
508     fWidth = std::max(fWidth, glyph.width());
509     fHeight = std::max(fHeight, glyph.height());
510 
511     int biWidth = isBW ? alignTo32(fWidth) : fWidth;
512 
513     if (nullptr == fBM) {
514         MyBitmapInfo info;
515         sk_bzero(&info, sizeof(info));
516         if (isBW) {
517             RGBQUAD blackQuad = { 0, 0, 0, 0 };
518             RGBQUAD whiteQuad = { 0xFF, 0xFF, 0xFF, 0 };
519             info.bmiColors[0] = blackQuad;
520             info.bmiColors[1] = whiteQuad;
521         }
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;
528         if (isBW) {
529             info.bmiHeader.biClrUsed = 2;
530         }
531         fBM = CreateDIBSection(fDC, &info, DIB_RGB_COLORS, &fBits, 0, 0);
532         if (nullptr == fBM) {
533             return nullptr;
534         }
535         SelectObject(fDC, fBM);
536     }
537 
538     // erase
539     size_t srcRB = isBW ? (biWidth >> 3) : (fWidth << 2);
540     size_t size = fHeight * srcRB;
541     memset(fBits, 0, size);
542 
543     XFORM xform = fXform;
544     xform.eDx = (float)-glyph.left();
545     xform.eDy = (float)-glyph.top();
546     SetWorldTransform(fDC, &xform);
547 
548     uint16_t glyphID = glyph.getGlyphID();
549     BOOL ret = ExtTextOutW(fDC, 0, 0, ETO_GLYPH_INDEX, nullptr, reinterpret_cast<LPCWSTR>(&glyphID),
550                            1, nullptr);
551     GdiFlush();
552     if (0 == ret) {
553         return nullptr;
554     }
555     *srcRBPtr = srcRB;
556     // offset to the start of the image
557     return (char*)fBits + (fHeight - glyph.height()) * srcRB;
558 }
559 
560 //////////////////////////////////////////////////////////////////////////////
561 #define BUFFERSIZE (1 << 13)
562 
563 class SkScalerContext_GDI : public SkScalerContext {
564 public:
565     SkScalerContext_GDI(sk_sp<LogFontTypeface>,
566                         const SkScalerContextEffects&,
567                         const SkDescriptor* desc);
568     ~SkScalerContext_GDI() override;
569 
570     // Returns true if the constructor was able to complete all of its
571     // initializations (which may include calling GDI).
572     bool isValid() const;
573 
574 protected:
575     GlyphMetrics generateMetrics(const SkGlyph&, SkArenaAlloc*) override;
576     void generateImage(const SkGlyph&, void* imageBuffer) override;
577     bool generatePath(const SkGlyph& glyph, SkPath* path, bool* modified) override;
578     void generateFontMetrics(SkFontMetrics*) override;
579 
580 private:
581     DWORD getGDIGlyphPath(SkGlyphID glyph, UINT flags,
582                           AutoSTMalloc<BUFFERSIZE, uint8_t>* glyphbuf);
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);
586 
587     template<bool APPLY_PREBLEND>
588     static void RGBToLcd16(const SkGdiRGB* SK_RESTRICT src, size_t srcRB, const SkGlyph& glyph,
589                            void* imageBuffer,
590                            const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB);
591 
592     HDCOffscreen fOffscreen;
593     /** fGsA is the non-rotational part of total matrix without the text height scale.
594      *  Used to find the magnitude of advances.
595      */
596     MAT2         fGsA;
597     /** The total matrix without the textSize. */
598     MAT2         fMat22;
599     /** Scales font to EM size. */
600     MAT2         fHighResMat22;
601     HDC          fDDC;
602     HFONT        fSavefont;
603     HFONT        fFont;
604     SCRIPT_CACHE fSC;
605 
606     /** The total matrix which also removes EM scale. */
607     SkMatrix     fHiResMatrix;
608     /** fG_inv is the inverse of the rotational part of the total matrix.
609      *  Used to set the direction of advances.
610      */
611     SkMatrix     fG_inv;
612     enum Type {
613         kTrueType_Type, kBitmap_Type, kLine_Type
614     } fType;
615     TEXTMETRIC fTM;
616 };
617 
SkFloatToFIXED(float x)618 static FIXED SkFloatToFIXED(float x) {
619     return SkFixedToFIXED(SkFloatToFixed(x));
620 }
621 
SkFIXEDToFloat(FIXED x)622 static inline float SkFIXEDToFloat(FIXED x) {
623     return SkFixedToFloat(SkFIXEDToFixed(x));
624 }
625 
compute_quality(const SkScalerContextRec & rec)626 static BYTE compute_quality(const SkScalerContextRec& rec) {
627     switch (rec.fMaskFormat) {
628         case SkMask::kBW_Format:
629             return NONANTIALIASED_QUALITY;
630         case SkMask::kLCD16_Format:
631             return CLEARTYPE_QUALITY;
632         default:
633             if (rec.fFlags & SkScalerContext::kGenA8FromLCD_Flag) {
634                 return CLEARTYPE_QUALITY;
635             } else {
636                 return ANTIALIASED_QUALITY;
637             }
638     }
639 }
640 
SkScalerContext_GDI(sk_sp<LogFontTypeface> rawTypeface,const SkScalerContextEffects & effects,const SkDescriptor * desc)641 SkScalerContext_GDI::SkScalerContext_GDI(sk_sp<LogFontTypeface> rawTypeface,
642                                          const SkScalerContextEffects& effects,
643                                          const SkDescriptor* desc)
644         : SkScalerContext(std::move(rawTypeface), effects, desc)
645         , fDDC(nullptr)
646         , fSavefont(nullptr)
647         , fFont(nullptr)
648         , fSC(nullptr)
649 {
650     LogFontTypeface* typeface = static_cast<LogFontTypeface*>(this->getTypeface());
651 
652     fDDC = ::CreateCompatibleDC(nullptr);
653     if (!fDDC) {
654         return;
655     }
656     SetGraphicsMode(fDDC, GM_ADVANCED);
657     SetBkMode(fDDC, TRANSPARENT);
658 
659     // When GDI hinting, remove the entire Y scale from sA and GsA. (Prevents 'linear' metrics.)
660     // When not hinting, remove only the integer Y scale from sA and GsA. (Applied by GDI.)
661     SkScalerContextRec::PreMatrixScale scaleConstraints =
662         (fRec.getHinting() == SkFontHinting::kNone || fRec.getHinting() == SkFontHinting::kSlight)
663                    ? SkScalerContextRec::PreMatrixScale::kVerticalInteger
664                    : SkScalerContextRec::PreMatrixScale::kVertical;
665     SkVector scale;
666     SkMatrix sA;
667     SkMatrix GsA;
668     SkMatrix A;
669     fRec.computeMatrices(scaleConstraints, &scale, &sA, &GsA, &fG_inv, &A);
670 
671     fGsA.eM11 = SkScalarToFIXED(GsA.get(SkMatrix::kMScaleX));
672     fGsA.eM12 = SkScalarToFIXED(-GsA.get(SkMatrix::kMSkewY)); // This should be ~0.
673     fGsA.eM21 = SkScalarToFIXED(-GsA.get(SkMatrix::kMSkewX));
674     fGsA.eM22 = SkScalarToFIXED(GsA.get(SkMatrix::kMScaleY));
675 
676     // When not hinting, scale was computed with kVerticalInteger, so is already an integer.
677     // The sA and GsA transforms will be used to create 'linear' metrics.
678 
679     // When hinting, scale was computed with kVertical, stating that our port can handle
680     // non-integer scales. This is done so that sA and GsA are computed without any 'residual'
681     // scale in them, preventing 'linear' metrics. However, GDI cannot actually handle non-integer
682     // scales so we need to round in this case. This is fine, since all of the scale has been
683     // removed from sA and GsA, so GDI will be handling the scale completely.
684     SkScalar gdiTextSize = SkScalarRoundToScalar(scale.fY);
685 
686     // GDI will not accept a size of zero, so round the range [0, 1] to 1.
687     // If the size was non-zero, the scale factors will also be non-zero and 1px tall text is drawn.
688     // If the size actually was zero, the scale factors will also be zero, so GDI will draw nothing.
689     if (gdiTextSize == 0) {
690         gdiTextSize = SK_Scalar1;
691     }
692 
693     LOGFONT lf = typeface->fLogFont;
694     lf.lfHeight = -SkScalarTruncToInt(gdiTextSize);
695     lf.lfQuality = compute_quality(fRec);
696     fFont = CreateFontIndirect(&lf);
697     if (!fFont) {
698         return;
699     }
700 
701     fSavefont = (HFONT)SelectObject(fDDC, fFont);
702 
703     if (0 == GetTextMetrics(fDDC, &fTM)) {
704         call_ensure_accessible(lf);
705         if (0 == GetTextMetrics(fDDC, &fTM)) {
706             fTM.tmPitchAndFamily = TMPF_TRUETYPE;
707         }
708     }
709 
710     XFORM xform;
711     if (fTM.tmPitchAndFamily & TMPF_VECTOR) {
712         // Used a logfont on a memory context, should never get a device font.
713         // Therefore all TMPF_DEVICE will be PostScript fonts.
714 
715         // If TMPF_VECTOR is set, one of TMPF_TRUETYPE or TMPF_DEVICE means that
716         // we have an outline font. Otherwise we have a vector FON, which is
717         // scalable, but not an outline font.
718         // This was determined by testing with Type1 PFM/PFB and
719         // OpenTypeCFF OTF, as well as looking at Wine bugs and sources.
720         if (fTM.tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_DEVICE)) {
721             // Truetype or PostScript.
722             fType = SkScalerContext_GDI::kTrueType_Type;
723         } else {
724             // Stroked FON.
725             fType = SkScalerContext_GDI::kLine_Type;
726         }
727 
728         // fPost2x2 is column-major, left handed (y down).
729         // XFORM 2x2 is row-major, left handed (y down).
730         xform.eM11 = SkScalarToFloat(sA.get(SkMatrix::kMScaleX));
731         xform.eM12 = SkScalarToFloat(sA.get(SkMatrix::kMSkewY));
732         xform.eM21 = SkScalarToFloat(sA.get(SkMatrix::kMSkewX));
733         xform.eM22 = SkScalarToFloat(sA.get(SkMatrix::kMScaleY));
734         xform.eDx = 0;
735         xform.eDy = 0;
736 
737         // MAT2 is row major, right handed (y up).
738         fMat22.eM11 = SkFloatToFIXED(xform.eM11);
739         fMat22.eM12 = SkFloatToFIXED(-xform.eM12);
740         fMat22.eM21 = SkFloatToFIXED(-xform.eM21);
741         fMat22.eM22 = SkFloatToFIXED(xform.eM22);
742 
743         if (needToRenderWithSkia(fRec)) {
744             this->forceGenerateImageFromPath();
745         }
746 
747         // Create a hires matrix if we need linear metrics.
748         if (this->isLinearMetrics()) {
749             OUTLINETEXTMETRIC otm;
750             UINT success = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm);
751             if (0 == success) {
752                 call_ensure_accessible(lf);
753                 success = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm);
754             }
755             if (0 != success) {
756                 SkScalar upem = SkIntToScalar(otm.otmEMSquare);
757 
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);
763 
764                 SkScalar removeEMScale = SkScalarInvert(upem);
765                 fHiResMatrix = A;
766                 fHiResMatrix.preScale(removeEMScale, removeEMScale);
767             }
768         }
769 
770     } else {
771         // Assume bitmap
772         fType = SkScalerContext_GDI::kBitmap_Type;
773 
774         xform.eM11 = 1.0f;
775         xform.eM12 = 0.0f;
776         xform.eM21 = 0.0f;
777         xform.eM22 = 1.0f;
778         xform.eDx = 0.0f;
779         xform.eDy = 0.0f;
780 
781         // fPost2x2 is column-major, left handed (y down).
782         // MAT2 is row major, right handed (y up).
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]);
787     }
788 
789     fOffscreen.init(fFont, xform);
790 }
791 
~SkScalerContext_GDI()792 SkScalerContext_GDI::~SkScalerContext_GDI() {
793     if (fDDC) {
794         ::SelectObject(fDDC, fSavefont);
795         ::DeleteDC(fDDC);
796     }
797     if (fFont) {
798         ::DeleteObject(fFont);
799     }
800     if (fSC) {
801         ::ScriptFreeCache(&fSC);
802     }
803 }
804 
isValid() const805 bool SkScalerContext_GDI::isValid() const {
806     return fDDC && fFont;
807 }
808 
generateMetrics(const SkGlyph & glyph,SkArenaAlloc *)809 SkScalerContext::GlyphMetrics SkScalerContext_GDI::generateMetrics(const SkGlyph& glyph,
810                                                                    SkArenaAlloc*) {
811     SkASSERT(fDDC);
812 
813     GlyphMetrics mx(glyph.maskFormat());
814 
815     if (fType == SkScalerContext_GDI::kBitmap_Type || fType == SkScalerContext_GDI::kLine_Type) {
816         SIZE size;
817         WORD glyphs = glyph.getGlyphID();
818         int width, height;
819         if (0 == GetTextExtentPointI(fDDC, &glyphs, 1, &size)) {
820             width = fTM.tmMaxCharWidth;
821             height = fTM.tmHeight;
822         } else {
823             width = size.cx;
824             height = size.cy;
825         }
826 
827         // Bitmap FON cannot underhang, but vector FON may.
828         // There appears no means of determining underhang of vector FON.
829         int left = 0;
830         int top = -fTM.tmAscent;
831 
832         mx.bounds = SkRect::MakeXYWH(left, top, width, height);
833         mx.advance = SkVector{(float)width, 0};
834 
835         // Vector FON will transform nicely, but bitmap FON do not.
836         if (fType == SkScalerContext_GDI::kLine_Type) {
837             SkRect bounds = SkRect::MakeXYWH(left, top, width, height);
838             SkMatrix m;
839             m.setAll(SkFIXEDToScalar(fMat22.eM11), -SkFIXEDToScalar(fMat22.eM21), 0,
840                      -SkFIXEDToScalar(fMat22.eM12), SkFIXEDToScalar(fMat22.eM22), 0,
841                      0,  0, 1);
842             m.mapRect(&bounds);
843             bounds.roundOut(&mx.bounds);
844         }
845 
846         // Apply matrix to advance.
847         mx.advance.fY = -SkFIXEDToFloat(fMat22.eM12) * mx.advance.fX;
848         mx.advance.fX *= SkFIXEDToFloat(fMat22.eM11);
849 
850         // These do not have an outline path at all.
851         mx.neverRequestPath = true;
852         return mx;
853     }
854 
855     UINT glyphId = glyph.getGlyphID();
856 
857     GLYPHMETRICS gm;
858     sk_bzero(&gm, sizeof(gm));
859 
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) {
865             return mx;
866         }
867     }
868 
869     bool empty = false;
870     // The black box is either the embedded bitmap size or the outline extent.
871     // It is 1x1 if nothing is to be drawn, but will also be 1x1 if something very small
872     // is to be drawn, like a '.'. We need to outset '.' but do not wish to outset ' '.
873     if (1 == gm.gmBlackBoxX && 1 == gm.gmBlackBoxY) {
874         // If GetGlyphOutline with GGO_NATIVE returns 0, we know there was no outline.
875         DWORD bufferSize = GetGlyphOutlineW(fDDC, glyphId, GGO_NATIVE | GGO_GLYPH_INDEX, &gm, 0, nullptr, &fMat22);
876         empty = (0 == bufferSize);
877     }
878 
879 
880     if (!empty) {
881         int y  = -gm.gmptGlyphOrigin.y;
882         int x =  gm.gmptGlyphOrigin.x;
883         // Outset, since the image may bleed out of the black box.
884         // For embedded bitmaps the black box should be exact.
885         // For outlines we need to outset by 1 in all directions for bleed.
886         // For ClearType we need to outset by 2 for bleed.
887         mx.bounds = SkRect::MakeXYWH(x, y, gm.gmBlackBoxX, gm.gmBlackBoxY).makeOutset(2, 2);
888     }
889     // TODO(benjaminwagner): What is the type of gm.gmCellInc[XY]?
890     mx.advance.fX = (float)((int)gm.gmCellIncX);
891     mx.advance.fY = (float)((int)gm.gmCellIncY);
892 
893     if ((fTM.tmPitchAndFamily & TMPF_VECTOR) && this->isLinearMetrics()) {
894         sk_bzero(&gm, sizeof(gm));
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),
898                                             SkIntToScalar(gm.gmCellIncY));
899         }
900     } else if (!isAxisAligned(this->fRec)) {
901         status = GetGlyphOutlineW(fDDC, glyphId, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, nullptr, &fGsA);
902         if (GDI_ERROR != status) {
903             mx.advance = fG_inv.mapXY(SkIntToScalar(gm.gmCellIncX), SkIntToScalar(gm.gmCellIncY));
904         }
905     }
906     return mx;
907 }
908 
909 static const MAT2 gMat2Identity = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
generateFontMetrics(SkFontMetrics * metrics)910 void SkScalerContext_GDI::generateFontMetrics(SkFontMetrics* metrics) {
911     if (nullptr == metrics) {
912         return;
913     }
914     sk_bzero(metrics, sizeof(*metrics));
915 
916     SkASSERT(fDDC);
917 
918 #ifndef SK_GDI_ALWAYS_USE_TEXTMETRICS_FOR_FONT_METRICS
919     if (fType == SkScalerContext_GDI::kBitmap_Type || fType == SkScalerContext_GDI::kLine_Type) {
920 #endif
921         metrics->fTop = SkIntToScalar(-fTM.tmAscent);
922         metrics->fAscent = SkIntToScalar(-fTM.tmAscent);
923         metrics->fDescent = SkIntToScalar(fTM.tmDescent);
924         metrics->fBottom = SkIntToScalar(fTM.tmDescent);
925         metrics->fLeading = SkIntToScalar(fTM.tmExternalLeading);
926         metrics->fAvgCharWidth = SkIntToScalar(fTM.tmAveCharWidth);
927         metrics->fMaxCharWidth = SkIntToScalar(fTM.tmMaxCharWidth);
928         metrics->fXMin = 0;
929         metrics->fXMax = metrics->fMaxCharWidth;
930         //metrics->fXHeight = 0;
931 #ifndef SK_GDI_ALWAYS_USE_TEXTMETRICS_FOR_FONT_METRICS
932         return;
933     }
934 #endif
935 
936     OUTLINETEXTMETRIC otm;
937 
938     uint32_t ret = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm);
939     if (0 == ret) {
940         LogFontTypeface::EnsureAccessible(this->getTypeface());
941         ret = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm);
942     }
943     if (0 == ret) {
944         return;
945     }
946 
947 #ifndef SK_GDI_ALWAYS_USE_TEXTMETRICS_FOR_FONT_METRICS
948     metrics->fTop = SkIntToScalar(-otm.otmrcFontBox.top);
949     metrics->fAscent = SkIntToScalar(-otm.otmAscent);
950     metrics->fDescent = SkIntToScalar(-otm.otmDescent);
951     metrics->fBottom = SkIntToScalar(-otm.otmrcFontBox.bottom);
952     metrics->fLeading = SkIntToScalar(otm.otmLineGap);
953     metrics->fAvgCharWidth = SkIntToScalar(otm.otmTextMetrics.tmAveCharWidth);
954     metrics->fMaxCharWidth = SkIntToScalar(otm.otmTextMetrics.tmMaxCharWidth);
955     metrics->fXMin = SkIntToScalar(otm.otmrcFontBox.left);
956     metrics->fXMax = SkIntToScalar(otm.otmrcFontBox.right);
957 #endif
958     metrics->fUnderlineThickness = SkIntToScalar(otm.otmsUnderscoreSize);
959     metrics->fUnderlinePosition = -SkIntToScalar(otm.otmsUnderscorePosition);
960 
961     metrics->fFlags |= SkFontMetrics::kUnderlineThicknessIsValid_Flag;
962     metrics->fFlags |= SkFontMetrics::kUnderlinePositionIsValid_Flag;
963 
964     metrics->fXHeight = SkIntToScalar(otm.otmsXHeight);
965     GLYPHMETRICS gm;
966     sk_bzero(&gm, sizeof(gm));
967     DWORD len = GetGlyphOutlineW(fDDC, 'x', GGO_METRICS, &gm, 0, nullptr, &gMat2Identity);
968     if (len != GDI_ERROR && gm.gmBlackBoxY > 0) {
969         metrics->fXHeight = SkIntToScalar(gm.gmBlackBoxY);
970     }
971 }
972 
973 ////////////////////////////////////////////////////////////////////////////////////////
974 
build_power_table(uint8_t table[],float ee)975 static void build_power_table(uint8_t table[], float ee) {
976     for (int i = 0; i < 256; i++) {
977         float x = i / 255.f;
978         x = std::pow(x, ee);
979         int xx = SkScalarRoundToInt(x * 255);
980         table[i] = SkToU8(xx);
981     }
982 }
983 
984 /**
985  *  This will invert the gamma applied by GDI (gray-scale antialiased), so we
986  *  can get linear values.
987  *
988  *  GDI grayscale appears to use a hard-coded gamma of 2.3.
989  *
990  *  GDI grayscale appears to draw using the black and white rasterizer at four
991  *  times the size and then downsamples to compute the coverage mask. As a
992  *  result there are only seventeen total grays. This lack of fidelity means
993  *  that shifting into other color spaces is imprecise.
994  */
getInverseGammaTableGDI()995 static const uint8_t* getInverseGammaTableGDI() {
996     static SkOnce once;
997     static uint8_t gTableGdi[256];
998     once([]{
999         build_power_table(gTableGdi, 2.3f);
1000     });
1001     return gTableGdi;
1002 }
1003 
1004 /**
1005  *  This will invert the gamma applied by GDI ClearType, so we can get linear
1006  *  values.
1007  *
1008  *  GDI ClearType uses SPI_GETFONTSMOOTHINGCONTRAST / 1000 as the gamma value.
1009  *  If this value is not specified, the default is a gamma of 1.4.
1010  */
getInverseGammaTableClearType()1011 static const uint8_t* getInverseGammaTableClearType() {
1012     static SkOnce once;
1013     static uint8_t gTableClearType[256];
1014     once([]{
1015         UINT level = 0;
1016         if (!SystemParametersInfo(SPI_GETFONTSMOOTHINGCONTRAST, 0, &level, 0) || !level) {
1017             // can't get the data, so use a default
1018             level = 1400;
1019         }
1020         build_power_table(gTableClearType, level / 1000.0f);
1021     });
1022     return gTableClearType;
1023 }
1024 
1025 #include "include/private/SkColorData.h"
1026 
1027 //Cannot assume that the input rgb is gray due to possible setting of kGenA8FromLCD_Flag.
1028 template<bool APPLY_PREBLEND>
rgb_to_a8(SkGdiRGB rgb,const uint8_t * table8)1029 static 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;
1033     return sk_apply_lut_if<APPLY_PREBLEND>(SkComputeLuminance(r, g, b), table8);
1034 }
1035 
1036 template<bool APPLY_PREBLEND>
rgb_to_lcd16(SkGdiRGB rgb,const uint8_t * tableR,const uint8_t * tableG,const uint8_t * tableB)1037 static 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) {
1044         r = std::max(r, 10u);
1045         g = std::max(g, 10u);
1046         b = std::max(b, 10u);
1047     }
1048     return SkPack888ToRGB16(r, g, b);
1049 }
1050 
1051 template<bool APPLY_PREBLEND>
RGBToA8(const SkGdiRGB * SK_RESTRICT src,size_t srcRB,const SkGlyph & glyph,void * imageBuffer,const uint8_t * table8)1052 void 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();
1055     const int width = glyph.width();
1056     uint8_t* SK_RESTRICT dst = (uint8_t*)((char*)imageBuffer + (glyph.height() - 1) * dstRB);
1057 
1058     for (int y = 0; y < glyph.height(); y++) {
1059         for (int i = 0; i < width; i++) {
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);
1063             }
1064         }
1065         src = SkTAddOffset<const SkGdiRGB>(src, srcRB);
1066         dst -= dstRB;
1067     }
1068 }
1069 
1070 template<bool APPLY_PREBLEND>
RGBToLcd16(const SkGdiRGB * SK_RESTRICT src,size_t srcRB,const SkGlyph & glyph,void * imageBuffer,const uint8_t * tableR,const uint8_t * tableG,const uint8_t * tableB)1071 void SkScalerContext_GDI::RGBToLcd16(
1072         const SkGdiRGB* SK_RESTRICT src, size_t srcRB, const SkGlyph& glyph, void* imageBuffer,
1073         const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) {
1074     const size_t dstRB = glyph.rowBytes();
1075     const int width = glyph.width();
1076     uint16_t* SK_RESTRICT dst = (uint16_t*)((char*)imageBuffer + (glyph.height() - 1) * dstRB);
1077 
1078     for (int y = 0; y < glyph.height(); y++) {
1079         for (int i = 0; i < width; i++) {
1080             dst[i] = rgb_to_lcd16<APPLY_PREBLEND>(src[i], tableR, tableG, tableB);
1081         }
1082         src = SkTAddOffset<const SkGdiRGB>(src, srcRB);
1083         dst = (uint16_t*)((char*)dst - dstRB);
1084     }
1085 }
1086 
generateImage(const SkGlyph & glyph,void * imageBuffer)1087 void SkScalerContext_GDI::generateImage(const SkGlyph& glyph, void* imageBuffer) {
1088     SkASSERT(fDDC);
1089 
1090     const bool isBW = SkMask::kBW_Format == fRec.fMaskFormat;
1091     const bool isAA = !isLCD(fRec);
1092 
1093     size_t srcRB;
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) {
1099             sk_bzero(imageBuffer, glyph.imageSize());
1100             return;
1101         }
1102     }
1103 
1104     if (!isBW) {
1105         const uint8_t* table;
1106         //The offscreen contains a GDI blit if isAA and kGenA8FromLCD_Flag is not set.
1107         //Otherwise the offscreen contains a ClearType blit.
1108         if (isAA && !(fRec.fFlags & SkScalerContext::kGenA8FromLCD_Flag)) {
1109             table = getInverseGammaTableGDI();
1110         } else {
1111             table = getInverseGammaTableClearType();
1112         }
1113         //Note that the following cannot really be integrated into the
1114         //pre-blend, since we may not be applying the pre-blend; when we aren't
1115         //applying the pre-blend it means that a filter wants linear anyway.
1116         //Other code may also be applying the pre-blend, so we'd need another
1117         //one with this and one without.
1118         SkGdiRGB* addr = (SkGdiRGB*)bits;
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;
1124                 addr[x] = (table[r] << 16) | (table[g] << 8) | table[b];
1125             }
1126             addr = SkTAddOffset<SkGdiRGB>(addr, srcRB);
1127         }
1128     }
1129 
1130     size_t dstRB = glyph.rowBytes();
1131     if (isBW) {
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++) {
1135             memcpy(dst, src, dstRB);
1136             src += srcRB;
1137             dst -= dstRB;
1138         }
1139         if constexpr (kSkShowTextBlitCoverage) {
1140             if (glyph.width() > 0 && glyph.height() > 0) {
1141                 int bitCount = glyph.width() & 7;
1142                 uint8_t* first = (uint8_t*)imageBuffer;
1143                 uint8_t* last = first + glyph.height() * dstRB - 1;
1144                 *first |= 1 << 7;
1145                 *last |= bitCount == 0 ? 1 : 1 << (8 - bitCount);
1146             }
1147         }
1148     } else if (isAA) {
1149         // since the caller may require A8 for maskfilters, we can't check for BW
1150         // ... until we have the caller tell us that explicitly
1151         const SkGdiRGB* src = (const SkGdiRGB*)bits;
1152         if (fPreBlend.isApplicable()) {
1153             RGBToA8<true>(src, srcRB, glyph, imageBuffer, fPreBlend.fG);
1154         } else {
1155             RGBToA8<false>(src, srcRB, glyph, imageBuffer, fPreBlend.fG);
1156         }
1157     } else {    // LCD16
1158         const SkGdiRGB* src = (const SkGdiRGB*)bits;
1159         SkASSERT(SkMask::kLCD16_Format == glyph.maskFormat());
1160         if (fPreBlend.isApplicable()) {
1161             RGBToLcd16<true>(src, srcRB, glyph, imageBuffer,
1162                              fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
1163         } else {
1164             RGBToLcd16<false>(src, srcRB, glyph, imageBuffer,
1165                               fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
1166         }
1167     }
1168 }
1169 
1170 namespace {
1171 
1172 class GDIGlyphbufferPointIter {
1173 public:
GDIGlyphbufferPointIter(const uint8_t * glyphbuf,DWORD total_size)1174     GDIGlyphbufferPointIter(const uint8_t* glyphbuf, DWORD total_size)
1175         : fHeaderIter(glyphbuf, total_size), fCurveIter(), fPointIter()
1176     { }
1177 
next()1178     POINTFX const * next() {
1179 nextHeader:
1180         if (!fCurveIter.isSet()) {
1181             const TTPOLYGONHEADER* header = fHeaderIter.next();
1182             if (nullptr == header) {
1183                 return nullptr;
1184             }
1185             fCurveIter.set(header);
1186             const TTPOLYCURVE* curve = fCurveIter.next();
1187             if (nullptr == curve) {
1188                 return nullptr;
1189             }
1190             fPointIter.set(curve);
1191             return &header->pfxStart;
1192         }
1193 
1194         const POINTFX* nextPoint = fPointIter.next();
1195         if (nullptr == nextPoint) {
1196             const TTPOLYCURVE* curve = fCurveIter.next();
1197             if (nullptr == curve) {
1198                 fCurveIter.set();
1199                 goto nextHeader;
1200             } else {
1201                 fPointIter.set(curve);
1202             }
1203             nextPoint = fPointIter.next();
1204         }
1205         return nextPoint;
1206     }
1207 
currentCurveType()1208     WORD currentCurveType() {
1209         return fPointIter.fCurveType;
1210     }
1211 
1212 private:
1213     /** Iterates over all of the polygon headers in a glyphbuf. */
1214     class GDIPolygonHeaderIter {
1215     public:
GDIPolygonHeaderIter(const uint8_t * glyphbuf,DWORD total_size)1216         GDIPolygonHeaderIter(const uint8_t* glyphbuf, DWORD total_size)
1217             : fCurPolygon(reinterpret_cast<const TTPOLYGONHEADER*>(glyphbuf))
1218             , fEndPolygon(SkTAddOffset<const TTPOLYGONHEADER>(glyphbuf, total_size))
1219         { }
1220 
next()1221         const TTPOLYGONHEADER* next() {
1222             if (fCurPolygon >= fEndPolygon) {
1223                 return nullptr;
1224             }
1225             const TTPOLYGONHEADER* thisPolygon = fCurPolygon;
1226             fCurPolygon = SkTAddOffset<const TTPOLYGONHEADER>(fCurPolygon, fCurPolygon->cb);
1227             return thisPolygon;
1228         }
1229     private:
1230         const TTPOLYGONHEADER* fCurPolygon;
1231         const TTPOLYGONHEADER* fEndPolygon;
1232     };
1233 
1234     /** Iterates over all of the polygon curves in a polygon header. */
1235     class GDIPolygonCurveIter {
1236     public:
GDIPolygonCurveIter()1237         GDIPolygonCurveIter() : fCurCurve(nullptr), fEndCurve(nullptr) { }
1238 
GDIPolygonCurveIter(const TTPOLYGONHEADER * curPolygon)1239         GDIPolygonCurveIter(const TTPOLYGONHEADER* curPolygon)
1240             : fCurCurve(SkTAddOffset<const TTPOLYCURVE>(curPolygon, sizeof(TTPOLYGONHEADER)))
1241             , fEndCurve(SkTAddOffset<const TTPOLYCURVE>(curPolygon, curPolygon->cb))
1242         { }
1243 
isSet()1244         bool isSet() { return fCurCurve != nullptr; }
1245 
set(const TTPOLYGONHEADER * curPolygon)1246         void set(const TTPOLYGONHEADER* curPolygon) {
1247             fCurCurve = SkTAddOffset<const TTPOLYCURVE>(curPolygon, sizeof(TTPOLYGONHEADER));
1248             fEndCurve = SkTAddOffset<const TTPOLYCURVE>(curPolygon, curPolygon->cb);
1249         }
set()1250         void set() {
1251             fCurCurve = nullptr;
1252             fEndCurve = nullptr;
1253         }
1254 
next()1255         const TTPOLYCURVE* next() {
1256             if (fCurCurve >= fEndCurve) {
1257                 return nullptr;
1258             }
1259             const TTPOLYCURVE* thisCurve = fCurCurve;
1260             fCurCurve = SkTAddOffset<const TTPOLYCURVE>(fCurCurve, size_of_TTPOLYCURVE(*fCurCurve));
1261             return thisCurve;
1262         }
1263     private:
size_of_TTPOLYCURVE(const TTPOLYCURVE & curve)1264         size_t size_of_TTPOLYCURVE(const TTPOLYCURVE& curve) {
1265             return 2*sizeof(WORD) + curve.cpfx*sizeof(POINTFX);
1266         }
1267         const TTPOLYCURVE* fCurCurve;
1268         const TTPOLYCURVE* fEndCurve;
1269     };
1270 
1271     /** Iterates over all of the polygon points in a polygon curve. */
1272     class GDIPolygonCurvePointIter {
1273     public:
GDIPolygonCurvePointIter()1274         GDIPolygonCurvePointIter() : fCurveType(0), fCurPoint(nullptr), fEndPoint(nullptr) { }
1275 
GDIPolygonCurvePointIter(const TTPOLYCURVE * curPolygon)1276         GDIPolygonCurvePointIter(const TTPOLYCURVE* curPolygon)
1277             : fCurveType(curPolygon->wType)
1278             , fCurPoint(&curPolygon->apfx[0])
1279             , fEndPoint(&curPolygon->apfx[curPolygon->cpfx])
1280         { }
1281 
isSet()1282         bool isSet() { return fCurPoint != nullptr; }
1283 
set(const TTPOLYCURVE * curPolygon)1284         void set(const TTPOLYCURVE* curPolygon) {
1285             fCurveType = curPolygon->wType;
1286             fCurPoint = &curPolygon->apfx[0];
1287             fEndPoint = &curPolygon->apfx[curPolygon->cpfx];
1288         }
set()1289         void set() {
1290             fCurPoint = nullptr;
1291             fEndPoint = nullptr;
1292         }
1293 
next()1294         const POINTFX* next() {
1295             if (fCurPoint >= fEndPoint) {
1296                 return nullptr;
1297             }
1298             const POINTFX* thisPoint = fCurPoint;
1299             ++fCurPoint;
1300             return thisPoint;
1301         }
1302 
1303         WORD fCurveType;
1304     private:
1305         const POINTFX* fCurPoint;
1306         const POINTFX* fEndPoint;
1307     };
1308 
1309     GDIPolygonHeaderIter fHeaderIter;
1310     GDIPolygonCurveIter fCurveIter;
1311     GDIPolygonCurvePointIter fPointIter;
1312 };
1313 
1314 class SkGDIGeometrySink {
1315     SkPath* fPath;
1316     bool fStarted = false;
1317     POINTFX fCurrent;
1318 
goingTo(const POINTFX pt)1319     void goingTo(const POINTFX pt) {
1320         if (!fStarted) {
1321             fStarted = true;
1322             fPath->moveTo( SkFIXEDToScalar(fCurrent.x),
1323                           -SkFIXEDToScalar(fCurrent.y));
1324         }
1325         fCurrent = pt;
1326     }
1327 
currentIsNot(const POINTFX pt)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;
1331     }
1332 
1333 public:
SkGDIGeometrySink(SkPath * path)1334     SkGDIGeometrySink(SkPath* path) : fPath(path) {}
1335     void process(const uint8_t* glyphbuf, DWORD total_size);
1336 
1337     /** It is possible for the hinted and unhinted versions of the same path to have
1338      *  a different number of points due to GDI's handling of flipped points.
1339      *  If this is detected, this will return false.
1340      */
1341     bool process(const uint8_t* glyphbuf, DWORD total_size, GDIGlyphbufferPointIter hintedYs);
1342 };
1343 
process(const uint8_t * glyphbuf,DWORD total_size)1344 void SkGDIGeometrySink::process(const uint8_t* glyphbuf, DWORD total_size) {
1345     const uint8_t* cur_glyph = glyphbuf;
1346     const uint8_t* end_glyph = glyphbuf + total_size;
1347 
1348     while (cur_glyph < end_glyph) {
1349         const TTPOLYGONHEADER* th = (const TTPOLYGONHEADER*)cur_glyph;
1350 
1351         const uint8_t* end_poly = cur_glyph + th->cb;
1352         const uint8_t* cur_poly = cur_glyph + sizeof(TTPOLYGONHEADER);
1353 
1354         fStarted = false;
1355         fCurrent = th->pfxStart;
1356 
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;
1361 
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);
1367                         fPath->lineTo( SkFIXEDToScalar(pnt_b.x),
1368                                       -SkFIXEDToScalar(pnt_b.y));
1369                     }
1370                 }
1371             }
1372 
1373             if (pc->wType == TT_PRIM_QSPLINE) {
1374                 for (uint16_t u = 0; u < cpfx - 1; u++) { // Walk through points in spline
1375                     POINTFX pnt_b = apfx[u];    // B is always the current point
1376                     POINTFX pnt_c = apfx[u+1];
1377 
1378                     if (u < cpfx - 2) {          // If not on last spline, compute C
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)));
1383                     }
1384 
1385 
1386                     if (this->currentIsNot(pnt_b) || this->currentIsNot(pnt_c)) {
1387                         this->goingTo(pnt_c);
1388                         fPath->quadTo( SkFIXEDToScalar(pnt_b.x),
1389                                       -SkFIXEDToScalar(pnt_b.y),
1390                                        SkFIXEDToScalar(pnt_c.x),
1391                                       -SkFIXEDToScalar(pnt_c.y));
1392                     }
1393                 }
1394             }
1395 
1396             // Advance past this TTPOLYCURVE.
1397             cur_poly += sizeof(WORD) * 2 + sizeof(POINTFX) * cpfx;
1398         }
1399         cur_glyph += th->cb;
1400         if (this->fStarted) {
1401             fPath->close();
1402         }
1403     }
1404 }
1405 
1406 #define move_next_expected_hinted_point(iter, pElem) do {\
1407     pElem = iter.next(); \
1408     if (nullptr == pElem) return false; \
1409 } while(0)
1410 
process(const uint8_t * glyphbuf,DWORD total_size,GDIGlyphbufferPointIter hintedYs)1411 bool SkGDIGeometrySink::process(const uint8_t* glyphbuf, DWORD total_size,
1412                                 GDIGlyphbufferPointIter hintedYs) {
1413     const uint8_t* cur_glyph = glyphbuf;
1414     const uint8_t* end_glyph = glyphbuf + total_size;
1415 
1416     POINTFX const * hintedPoint;
1417 
1418     while (cur_glyph < end_glyph) {
1419         const TTPOLYGONHEADER* th = (const TTPOLYGONHEADER*)cur_glyph;
1420 
1421         const uint8_t* end_poly = cur_glyph + th->cb;
1422         const uint8_t* cur_poly = cur_glyph + sizeof(TTPOLYGONHEADER);
1423 
1424         move_next_expected_hinted_point(hintedYs, hintedPoint);
1425         fStarted = false;
1426         fCurrent = {th->pfxStart.x, hintedPoint->y};
1427 
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;
1432 
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);
1439                         fPath->lineTo( SkFIXEDToScalar(pnt_b.x),
1440                                       -SkFIXEDToScalar(pnt_b.y));
1441                     }
1442                 }
1443             }
1444 
1445             if (pc->wType == TT_PRIM_QSPLINE) {
1446                 POINTFX currentPoint = apfx[0];
1447                 move_next_expected_hinted_point(hintedYs, hintedPoint);
1448                 // only take the hinted y if it wasn't flipped
1449                 if (hintedYs.currentCurveType() == TT_PRIM_QSPLINE) {
1450                     currentPoint.y = hintedPoint->y;
1451                 }
1452                 for (uint16_t u = 0; u < cpfx - 1; u++) { // Walk through points in spline
1453                     POINTFX pnt_b = currentPoint;//pc->apfx[u]; // B is always the current point
1454                     POINTFX pnt_c = apfx[u+1];
1455                     move_next_expected_hinted_point(hintedYs, hintedPoint);
1456                     // only take the hinted y if it wasn't flipped
1457                     if (hintedYs.currentCurveType() == TT_PRIM_QSPLINE) {
1458                         pnt_c.y = hintedPoint->y;
1459                     }
1460                     currentPoint.x = pnt_c.x;
1461                     currentPoint.y = pnt_c.y;
1462 
1463                     if (u < cpfx - 2) {          // If not on last spline, compute C
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)));
1468                     }
1469 
1470                     if (this->currentIsNot(pnt_b) || this->currentIsNot(pnt_c)) {
1471                         this->goingTo(pnt_c);
1472                         fPath->quadTo( SkFIXEDToScalar(pnt_b.x),
1473                                       -SkFIXEDToScalar(pnt_b.y),
1474                                        SkFIXEDToScalar(pnt_c.x),
1475                                       -SkFIXEDToScalar(pnt_c.y));
1476                     }
1477                 }
1478             }
1479 
1480             // Advance past this TTPOLYCURVE.
1481             cur_poly += sizeof(WORD) * 2 + sizeof(POINTFX) * cpfx;
1482         }
1483         cur_glyph += th->cb;
1484         if (this->fStarted) {
1485             fPath->close();
1486         }
1487     }
1488     return true;
1489 }
1490 } // namespace
1491 
getGDIGlyphPath(SkGlyphID glyph,UINT flags,AutoSTMalloc<BUFFERSIZE,uint8_t> * glyphbuf)1492 DWORD SkScalerContext_GDI::getGDIGlyphPath(SkGlyphID glyph, UINT flags,
1493                                            AutoSTMalloc<BUFFERSIZE, uint8_t>* glyphbuf)
1494 {
1495     GLYPHMETRICS gm;
1496 
1497     DWORD total_size = GetGlyphOutlineW(fDDC, glyph, flags, &gm, BUFFERSIZE, glyphbuf->get(), &fMat22);
1498     // Sometimes GetGlyphOutlineW returns a number larger than BUFFERSIZE even if BUFFERSIZE > 0.
1499     // It has been verified that this does not involve a buffer overrun.
1500     if (GDI_ERROR == total_size || total_size > BUFFERSIZE) {
1501         // GDI_ERROR because the BUFFERSIZE was too small, or because the data was not accessible.
1502         // When the data is not accessable GetGlyphOutlineW fails rather quickly,
1503         // so just try to get the size. If that fails then ensure the data is accessible.
1504         total_size = GetGlyphOutlineW(fDDC, glyph, flags, &gm, 0, nullptr, &fMat22);
1505         if (GDI_ERROR == total_size) {
1506             LogFontTypeface::EnsureAccessible(this->getTypeface());
1507             total_size = GetGlyphOutlineW(fDDC, glyph, flags, &gm, 0, nullptr, &fMat22);
1508             if (GDI_ERROR == total_size) {
1509                 // GetGlyphOutlineW is known to fail for some characters, such as spaces.
1510                 // In these cases, just return that the glyph does not have a shape.
1511                 return 0;
1512             }
1513         }
1514 
1515         glyphbuf->reset(total_size);
1516 
1517         DWORD ret = GetGlyphOutlineW(fDDC, glyph, flags, &gm, total_size, glyphbuf->get(), &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) {
1522                 SkASSERT(false);
1523                 return 0;
1524             }
1525         }
1526     }
1527     return total_size;
1528 }
1529 
generatePath(const SkGlyph & glyph,SkPath * path,bool * modified)1530 bool SkScalerContext_GDI::generatePath(const SkGlyph& glyph, SkPath* path, bool* modified) {
1531     SkASSERT(path);
1532     SkASSERT(fDDC);
1533 
1534     path->reset();
1535 
1536     SkGlyphID glyphID = glyph.getGlyphID();
1537 
1538     // Out of all the fonts on a typical Windows box,
1539     // 25% of glyphs require more than 2KB.
1540     // 1% of glyphs require more than 4KB.
1541     // 0.01% of glyphs require more than 8KB.
1542     // 8KB is less than 1% of the normal 1MB stack on Windows.
1543     // Note that some web fonts glyphs require more than 20KB.
1544     //static const DWORD BUFFERSIZE = (1 << 13);
1545 
1546     //GDI only uses hinted outlines when axis aligned.
1547     UINT format = GGO_NATIVE | GGO_GLYPH_INDEX;
1548     if (fRec.getHinting() == SkFontHinting::kNone || fRec.getHinting() == SkFontHinting::kSlight){
1549         format |= GGO_UNHINTED;
1550     }
1551     AutoSTMalloc<BUFFERSIZE, uint8_t> glyphbuf(BUFFERSIZE);
1552     DWORD total_size = getGDIGlyphPath(glyphID, format, &glyphbuf);
1553     if (0 == total_size) {
1554         return false;
1555     }
1556 
1557     if (fRec.getHinting() != SkFontHinting::kSlight) {
1558         SkGDIGeometrySink sink(path);
1559         sink.process(glyphbuf, total_size);
1560     } else {
1561         AutoSTMalloc<BUFFERSIZE, uint8_t> hintedGlyphbuf(BUFFERSIZE);
1562         //GDI only uses hinted outlines when axis aligned.
1563         DWORD hinted_total_size = getGDIGlyphPath(glyphID, GGO_NATIVE | GGO_GLYPH_INDEX,
1564                                                   &hintedGlyphbuf);
1565         if (0 == hinted_total_size) {
1566             return false;
1567         }
1568 
1569         SkGDIGeometrySink sinkXBufYIter(path);
1570         if (!sinkXBufYIter.process(glyphbuf, total_size,
1571                                    GDIGlyphbufferPointIter(hintedGlyphbuf, hinted_total_size)))
1572         {
1573             // Both path and sinkXBufYIter are in the state they were in at the time of failure.
1574             path->reset();
1575             SkGDIGeometrySink sink(path);
1576             sink.process(glyphbuf, total_size);
1577         }
1578     }
1579     return true;
1580 }
1581 
logfont_for_name(const char * familyName,LOGFONT * lf)1582 static void logfont_for_name(const char* familyName, LOGFONT* lf) {
1583     sk_bzero(lf, sizeof(LOGFONT));
1584 #ifdef UNICODE
1585     // Get the buffer size needed first.
1586     size_t str_len = ::MultiByteToWideChar(CP_UTF8, 0, familyName,
1587                                             -1, nullptr, 0);
1588     // Allocate a buffer (str_len already has terminating null
1589     // accounted for).
1590     wchar_t *wideFamilyName = new wchar_t[str_len];
1591     // Now actually convert the string.
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';
1597 #else
1598     ::strncpy(lf->lfFaceName, familyName, LF_FACESIZE - 1);
1599     lf->lfFaceName[LF_FACESIZE - 1] = '\0';
1600 #endif
1601 }
1602 
onGetFamilyName(SkString * familyName) const1603 void LogFontTypeface::onGetFamilyName(SkString* familyName) const {
1604     // Get the actual name of the typeface. The logfont may not know this.
1605     SkAutoHDC hdc(fLogFont);
1606     dcfontname_to_skstring(hdc, fLogFont, familyName);
1607 }
1608 
onGetFontDescriptor(SkFontDescriptor * desc,bool * isLocalStream) const1609 void LogFontTypeface::onGetFontDescriptor(SkFontDescriptor* desc,
1610                                           bool* isLocalStream) const {
1611     SkString familyName;
1612     this->onGetFamilyName(&familyName);
1613     desc->setFamilyName(familyName.c_str());
1614     desc->setStyle(this->fontStyle());
1615     *isLocalStream = this->fSerializeAsStream;
1616 }
1617 
getGlyphToUnicodeMap(SkUnichar * dstArray) const1618 void LogFontTypeface::getGlyphToUnicodeMap(SkUnichar* dstArray) const {
1619     SkAutoHDC hdc(fLogFont);
1620     unsigned int glyphCount = calculateGlyphCount(hdc, fLogFont);
1621     populate_glyph_to_unicode(hdc, glyphCount, dstArray);
1622 }
1623 
onGetAdvancedMetrics() const1624 std::unique_ptr<SkAdvancedTypefaceMetrics> LogFontTypeface::onGetAdvancedMetrics() const {
1625     LOGFONT lf = fLogFont;
1626     std::unique_ptr<SkAdvancedTypefaceMetrics> info(nullptr);
1627 
1628     // The design HFONT must be destroyed after the HDC
1629     using HFONT_T = typename std::remove_pointer<HFONT>::type;
1630     std::unique_ptr<HFONT_T, SkFunctionObject<DeleteObject>> designFont;
1631     SkAutoHDC hdc(lf);
1632 
1633     const char stem_chars[] = {'i', 'I', '!', '1'};
1634     int16_t min_width;
1635     unsigned glyphCount;
1636 
1637     // To request design units, create a logical font whose height is specified
1638     // as unitsPerEm.
1639     OUTLINETEXTMETRIC otm;
1640     unsigned int otmRet = GetOutlineTextMetrics(hdc, sizeof(otm), &otm);
1641     if (0 == otmRet) {
1642         call_ensure_accessible(lf);
1643         otmRet = GetOutlineTextMetrics(hdc, sizeof(otm), &otm);
1644     }
1645     if (!otmRet || !GetTextFace(hdc, LF_FACESIZE, lf.lfFaceName)) {
1646         return info;
1647     }
1648     lf.lfHeight = -SkToS32(otm.otmEMSquare);
1649     designFont.reset(CreateFontIndirect(&lf));
1650     SelectObject(hdc, designFont.get());
1651     if (!GetOutlineTextMetrics(hdc, sizeof(otm), &otm)) {
1652         return info;
1653     }
1654     glyphCount = calculateGlyphCount(hdc, fLogFont);
1655 
1656     info.reset(new SkAdvancedTypefaceMetrics);
1657 
1658     SkOTTableOS2_V4::Type fsType;
1659     if (sizeof(fsType) == this->getTableData(SkTEndian_SwapBE32(SkOTTableOS2::TAG),
1660                                              offsetof(SkOTTableOS2_V4, fsType),
1661                                              sizeof(fsType),
1662                                              &fsType)) {
1663         SkOTUtils::SetAdvancedTypefaceFlags(fsType, info.get());
1664     } else {
1665         // If bit 1 is set, the font may not be embedded in a document.
1666         // If bit 1 is clear, the font can be embedded.
1667         // If bit 2 is set, the embedding is read-only.
1668         if (otm.otmfsType & 0x1) {
1669             info->fFlags |= SkAdvancedTypefaceMetrics::kNotEmbeddable_FontFlag;
1670         }
1671     }
1672 
1673     if (glyphCount == 0 || (otm.otmTextMetrics.tmPitchAndFamily & TMPF_TRUETYPE) == 0) {
1674         return info;
1675     }
1676     info->fType = SkAdvancedTypefaceMetrics::kTrueType_Font;
1677 
1678     // If this bit is clear the font is a fixed pitch font.
1679     if (!(otm.otmTextMetrics.tmPitchAndFamily & TMPF_FIXED_PITCH)) {
1680         info->fStyle |= SkAdvancedTypefaceMetrics::kFixedPitch_Style;
1681     }
1682     if (otm.otmTextMetrics.tmItalic) {
1683         info->fStyle |= SkAdvancedTypefaceMetrics::kItalic_Style;
1684     }
1685     if (otm.otmTextMetrics.tmPitchAndFamily & FF_ROMAN) {
1686         info->fStyle |= SkAdvancedTypefaceMetrics::kSerif_Style;
1687     } else if (otm.otmTextMetrics.tmPitchAndFamily & FF_SCRIPT) {
1688             info->fStyle |= SkAdvancedTypefaceMetrics::kScript_Style;
1689     }
1690 
1691     // The main italic angle of the font, in tenths of a degree counterclockwise
1692     // from vertical.
1693     info->fItalicAngle = otm.otmItalicAngle / 10;
1694     info->fAscent = SkToS16(otm.otmTextMetrics.tmAscent);
1695     info->fDescent = SkToS16(-otm.otmTextMetrics.tmDescent);
1696     // TODO(ctguil): Use alternate cap height calculation.
1697     // MSDN says otmsCapEmHeight is not support but it is returning a value on
1698     // my Win7 box.
1699     info->fCapHeight = otm.otmsCapEmHeight;
1700     info->fBBox =
1701         SkIRect::MakeLTRB(otm.otmrcFontBox.left, otm.otmrcFontBox.top,
1702                           otm.otmrcFontBox.right, otm.otmrcFontBox.bottom);
1703 
1704     // Figure out a good guess for StemV - Min width of i, I, !, 1.
1705     // This probably isn't very good with an italic font.
1706     min_width = SHRT_MAX;
1707     info->fStemV = 0;
1708     for (size_t i = 0; i < std::size(stem_chars); i++) {
1709         ABC abcWidths;
1710         if (GetCharABCWidths(hdc, stem_chars[i], stem_chars[i], &abcWidths)) {
1711             int16_t width = abcWidths.abcB;
1712             if (width > 0 && width < min_width) {
1713                 min_width = width;
1714                 info->fStemV = min_width;
1715             }
1716         }
1717     }
1718 
1719     return info;
1720 }
1721 
1722 //Placeholder representation of a Base64 encoded GUID from create_unique_font_name.
1723 #define BASE64_GUID_ID "XXXXXXXXXXXXXXXXXXXXXXXX"
1724 //Length of GUID representation from create_id, including nullptr terminator.
1725 #define BASE64_GUID_ID_LEN std::size(BASE64_GUID_ID)
1726 
1727 static_assert(BASE64_GUID_ID_LEN < LF_FACESIZE, "GUID_longer_than_facesize");
1728 
1729 /**
1730    NameID 6 Postscript names cannot have the character '/'.
1731    It would be easier to hex encode the GUID, but that is 32 bytes,
1732    and many systems have issues with names longer than 28 bytes.
1733    The following need not be any standard base64 encoding.
1734    The encoded value is never decoded.
1735 */
1736 static const char postscript_safe_base64_encode[] =
1737     "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
1738     "abcdefghijklmnopqrstuvwxyz"
1739     "0123456789-_=";
1740 
1741 /**
1742    Formats a GUID into Base64 and places it into buffer.
1743    buffer should have space for at least BASE64_GUID_ID_LEN characters.
1744    The string will always be null terminated.
1745    XXXXXXXXXXXXXXXXXXXXXXXX0
1746  */
format_guid_b64(const GUID & guid,char * buffer,size_t bufferSize)1747 static void format_guid_b64(const GUID& guid, char* buffer, size_t bufferSize) {
1748     SkASSERT(bufferSize >= BASE64_GUID_ID_LEN);
1749     size_t written = SkBase64::Encode(&guid, sizeof(guid), buffer, postscript_safe_base64_encode);
1750     SkASSERT(written < LF_FACESIZE);
1751     buffer[written] = '\0';
1752 }
1753 
1754 /**
1755    Creates a Base64 encoded GUID and places it into buffer.
1756    buffer should have space for at least BASE64_GUID_ID_LEN characters.
1757    The string will always be null terminated.
1758    XXXXXXXXXXXXXXXXXXXXXXXX0
1759  */
create_unique_font_name(char * buffer,size_t bufferSize)1760 static HRESULT create_unique_font_name(char* buffer, size_t bufferSize) {
1761     GUID guid = {};
1762     if (FAILED(CoCreateGuid(&guid))) {
1763         return E_UNEXPECTED;
1764     }
1765     format_guid_b64(guid, buffer, bufferSize);
1766 
1767     return S_OK;
1768 }
1769 
1770 /**
1771    Introduces a font to GDI. On failure will return nullptr. The returned handle
1772    should eventually be passed to RemoveFontMemResourceEx.
1773 */
activate_font(SkData * fontData)1774 static HANDLE activate_font(SkData* fontData) {
1775     DWORD numFonts = 0;
1776     //AddFontMemResourceEx just copies the data, but does not specify const.
1777     HANDLE fontHandle = AddFontMemResourceEx(const_cast<void*>(fontData->data()),
1778                                              static_cast<DWORD>(fontData->size()),
1779                                              nullptr,
1780                                              &numFonts);
1781 
1782     if (fontHandle != nullptr && numFonts < 1) {
1783         RemoveFontMemResourceEx(fontHandle);
1784         return nullptr;
1785     }
1786 
1787     return fontHandle;
1788 }
1789 
1790 // Does not affect ownership of stream.
create_from_stream(std::unique_ptr<SkStreamAsset> stream)1791 static sk_sp<SkTypeface> create_from_stream(std::unique_ptr<SkStreamAsset> stream) {
1792     // Create a unique and unpredictable font name.
1793     // Avoids collisions and access from CSS.
1794     char familyName[BASE64_GUID_ID_LEN];
1795     const int familyNameSize = std::size(familyName);
1796     if (FAILED(create_unique_font_name(familyName, familyNameSize))) {
1797         return nullptr;
1798     }
1799 
1800     // Change the name of the font.
1801     sk_sp<SkData> rewrittenFontData(SkOTUtils::RenameFont(stream.get(), familyName, familyNameSize-1));
1802     if (nullptr == rewrittenFontData.get()) {
1803         return nullptr;
1804     }
1805 
1806     // Register the font with GDI.
1807     HANDLE fontReference = activate_font(rewrittenFontData.get());
1808     if (nullptr == fontReference) {
1809         return nullptr;
1810     }
1811 
1812     // Create the typeface.
1813     LOGFONT lf;
1814     logfont_for_name(familyName, &lf);
1815 
1816     return sk_sp<SkTypeface>(SkCreateFontMemResourceTypefaceFromLOGFONT(lf, fontReference));
1817 }
1818 
onOpenStream(int * ttcIndex) const1819 std::unique_ptr<SkStreamAsset> LogFontTypeface::onOpenStream(int* ttcIndex) const {
1820     *ttcIndex = 0;
1821 
1822     const DWORD kTTCTag = SkEndian_SwapBE32(SkSetFourByteTag('t', 't', 'c', 'f'));
1823     LOGFONT lf = fLogFont;
1824 
1825     SkAutoHDC hdc(lf);
1826 
1827     std::unique_ptr<SkStreamAsset> stream;
1828     DWORD tables[2] = {kTTCTag, 0};
1829     for (size_t i = 0; i < std::size(tables); i++) {
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);
1834         }
1835         if (bufferSize != GDI_ERROR) {
1836             sk_sp<SkData> streamData = SkData::MakeUninitialized(bufferSize);
1837             if (GetFontData(hdc, tables[i], 0, streamData->writable_data(), bufferSize)) {
1838                 stream.reset(new SkMemoryStream(std::move(streamData)));
1839                 break;
1840             } else {
1841                 stream.reset();
1842             }
1843         }
1844     }
1845     return stream;
1846 }
1847 
onMakeClone(const SkFontArguments & args) const1848 sk_sp<SkTypeface> LogFontTypeface::onMakeClone(const SkFontArguments& args) const {
1849     return sk_ref_sp(this);
1850 }
1851 
bmpCharsToGlyphs(HDC hdc,const WCHAR * bmpChars,int count,uint16_t * glyphs,bool Ox1FHack)1852 static void bmpCharsToGlyphs(HDC hdc, const WCHAR* bmpChars, int count, uint16_t* glyphs,
1853                              bool Ox1FHack)
1854 {
1855     // Type1 fonts fail with uniscribe API. Use GetGlyphIndices for plane 0.
1856 
1857     /** Real documentation for GetGlyphIndicesW:
1858      *
1859      *  When GGI_MARK_NONEXISTING_GLYPHS is not specified and a character does not map to a
1860      *  glyph, then the 'default character's glyph is returned instead. The 'default character'
1861      *  is available in fTM.tmDefaultChar. FON fonts have a default character, and there exists
1862      *  a usDefaultChar in the 'OS/2' table, version 2 and later. If there is no
1863      *  'default character' specified by the font, then often the first character found is used.
1864      *
1865      *  When GGI_MARK_NONEXISTING_GLYPHS is specified and a character does not map to a glyph,
1866      *  then the glyph 0xFFFF is used. In Windows XP and earlier, Bitmap/Vector FON usually use
1867      *  glyph 0x1F instead ('Terminal' appears to be special, returning 0xFFFF).
1868      *  Type1 PFM/PFB, TT, OT TT, OT CFF all appear to use 0xFFFF, even on XP.
1869      */
1870     DWORD result = GetGlyphIndicesW(hdc, bmpChars, count, glyphs, GGI_MARK_NONEXISTING_GLYPHS);
1871     if (GDI_ERROR == result) {
1872         for (int i = 0; i < count; ++i) {
1873             glyphs[i] = 0;
1874         }
1875         return;
1876     }
1877 
1878     if (Ox1FHack) {
1879         for (int i = 0; i < count; ++i) {
1880             if (0xFFFF == glyphs[i] || 0x1F == glyphs[i]) {
1881                 glyphs[i] = 0;
1882             }
1883         }
1884     } else {
1885         for (int i = 0; i < count; ++i) {
1886             if (0xFFFF == glyphs[i]){
1887                 glyphs[i] = 0;
1888             }
1889         }
1890     }
1891 }
1892 
nonBmpCharToGlyph(HDC hdc,SCRIPT_CACHE * scriptCache,const WCHAR utf16[2])1893 static uint16_t nonBmpCharToGlyph(HDC hdc, SCRIPT_CACHE* scriptCache, const WCHAR utf16[2]) {
1894     uint16_t index = 0;
1895     // Use uniscribe to detemine glyph index for non-BMP characters.
1896     static const int numWCHAR = 2;
1897     static const int maxItems = 2;
1898     // MSDN states that this can be nullptr, but some things don't work then.
1899     SCRIPT_CONTROL scriptControl;
1900     memset(&scriptControl, 0, sizeof(scriptControl));
1901     // Add extra item to SCRIPT_ITEM to work around a bug (now documented).
1902     // https://bugzilla.mozilla.org/show_bug.cgi?id=366643
1903     SCRIPT_ITEM si[maxItems + 1];
1904     int numItems;
1905     HRZM(ScriptItemize(utf16, numWCHAR, maxItems, &scriptControl, nullptr, si, &numItems),
1906          "Could not itemize character.");
1907 
1908     // Sometimes ScriptShape cannot find a glyph for a non-BMP and returns 2 space glyphs.
1909     static const int maxGlyphs = 2;
1910     SCRIPT_VISATTR vsa[maxGlyphs];
1911     WORD outGlyphs[maxGlyphs];
1912     WORD logClust[numWCHAR];
1913     int numGlyphs;
1914     SCRIPT_ANALYSIS& script = si[0].a;
1915     script.eScript = SCRIPT_UNDEFINED;
1916     script.fRTL = FALSE;
1917     script.fLayoutRTL = FALSE;
1918     script.fLinkBefore = FALSE;
1919     script.fLinkAfter = FALSE;
1920     script.fLogicalOrder = FALSE;
1921     script.fNoGlyphIndex = FALSE;
1922     script.s.uBidiLevel = 0;
1923     script.s.fOverrideDirection = 0;
1924     script.s.fInhibitSymSwap = TRUE;
1925     script.s.fCharShape = FALSE;
1926     script.s.fDigitSubstitute = FALSE;
1927     script.s.fInhibitLigate = FALSE;
1928     script.s.fDisplayZWG = TRUE;
1929     script.s.fArabicNumContext = FALSE;
1930     script.s.fGcpClusters = FALSE;
1931     script.s.fReserved = 0;
1932     script.s.fEngineReserved = 0;
1933     // For the future, 0x80040200 from here is USP_E_SCRIPT_NOT_IN_FONT
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];
1939     }
1940     return index;
1941 }
1942 
onCharsToGlyphs(const SkUnichar * uni,int glyphCount,SkGlyphID glyphs[]) const1943 void LogFontTypeface::onCharsToGlyphs(const SkUnichar* uni, int glyphCount,
1944                                       SkGlyphID glyphs[]) const
1945 {
1946     SkAutoHDC hdc(fLogFont);
1947 
1948     TEXTMETRIC tm;
1949     if (0 == GetTextMetrics(hdc, &tm)) {
1950         call_ensure_accessible(fLogFont);
1951         if (0 == GetTextMetrics(hdc, &tm)) {
1952             tm.tmPitchAndFamily = TMPF_TRUETYPE;
1953         }
1954     }
1955     bool Ox1FHack = !(tm.tmPitchAndFamily & TMPF_VECTOR) /*&& winVer < Vista */;
1956 
1957     SCRIPT_CACHE sc = nullptr;
1958     static const int scratchCount = 256;
1959     WCHAR scratch[scratchCount];
1960     int glyphIndex = 0;
1961     const uint32_t* utf32 = reinterpret_cast<const uint32_t*>(uni);
1962     while (glyphIndex < glyphCount) {
1963         // Try a run of bmp.
1964         int glyphsLeft = std::min(glyphCount - glyphIndex, scratchCount);
1965         int runLength = 0;
1966         while (runLength < glyphsLeft && utf32[glyphIndex + runLength] <= 0xFFFF) {
1967             scratch[runLength] = static_cast<WCHAR>(utf32[glyphIndex + runLength]);
1968             ++runLength;
1969         }
1970         if (runLength) {
1971             bmpCharsToGlyphs(hdc, scratch, runLength, &glyphs[glyphIndex], Ox1FHack);
1972             glyphIndex += runLength;
1973         }
1974 
1975         // Try a run of non-bmp.
1976         while (glyphIndex < glyphCount && utf32[glyphIndex] > 0xFFFF) {
1977             SkUTF::ToUTF16(utf32[glyphIndex], reinterpret_cast<uint16_t*>(scratch));
1978             glyphs[glyphIndex] = nonBmpCharToGlyph(hdc, &sc, scratch);
1979             ++glyphIndex;
1980         }
1981     }
1982 
1983     if (sc) {
1984         ::ScriptFreeCache(&sc);
1985     }
1986 }
1987 
onCountGlyphs() const1988 int LogFontTypeface::onCountGlyphs() const {
1989     SkAutoHDC hdc(fLogFont);
1990     return calculateGlyphCount(hdc, fLogFont);
1991 }
1992 
getPostScriptGlyphNames(SkString *) const1993 void LogFontTypeface::getPostScriptGlyphNames(SkString*) const {}
1994 
onGetUPEM() const1995 int LogFontTypeface::onGetUPEM() const {
1996     SkAutoHDC hdc(fLogFont);
1997     return calculateUPEM(hdc, fLogFont);
1998 }
1999 
onCreateFamilyNameIterator() const2000 SkTypeface::LocalizedStrings* LogFontTypeface::onCreateFamilyNameIterator() const {
2001     sk_sp<SkTypeface::LocalizedStrings> nameIter =
2002         SkOTUtils::LocalizedStrings_NameTable::MakeForFamilyNames(*this);
2003     if (!nameIter) {
2004         SkString familyName;
2005         this->getFamilyName(&familyName);
2006         SkString language("und"); //undetermined
2007         nameIter = sk_make_sp<SkOTUtils::LocalizedStrings_SingleName>(familyName, language);
2008     }
2009     return nameIter.release();
2010 }
2011 
onGetTableTags(SkFontTableTag tags[]) const2012 int LogFontTypeface::onGetTableTags(SkFontTableTag tags[]) const {
2013     SkSFNTHeader header;
2014     if (sizeof(header) != this->onGetTableData(0, 0, sizeof(header), &header)) {
2015         return 0;
2016     }
2017 
2018     int numTables = SkEndian_SwapBE16(header.numTables);
2019 
2020     if (tags) {
2021         size_t size = numTables * sizeof(SkSFNTHeader::TableDirectoryEntry);
2022         AutoSTMalloc<0x20, SkSFNTHeader::TableDirectoryEntry> dir(numTables);
2023         if (size != this->onGetTableData(0, sizeof(header), size, dir.get())) {
2024             return 0;
2025         }
2026 
2027         for (int i = 0; i < numTables; ++i) {
2028             tags[i] = SkEndian_SwapBE32(dir[i].tag);
2029         }
2030     }
2031     return numTables;
2032 }
2033 
onGetTableData(SkFontTableTag tag,size_t offset,size_t length,void * data) const2034 size_t LogFontTypeface::onGetTableData(SkFontTableTag tag, size_t offset,
2035                                        size_t length, void* data) const
2036 {
2037     LOGFONT lf = fLogFont;
2038     SkAutoHDC hdc(lf);
2039 
2040     tag = SkEndian_SwapBE32(tag);
2041     if (nullptr == data) {
2042         length = 0;
2043     }
2044     DWORD bufferSize = GetFontData(hdc, tag, (DWORD) offset, data, (DWORD) length);
2045     if (bufferSize == GDI_ERROR) {
2046         call_ensure_accessible(lf);
2047         bufferSize = GetFontData(hdc, tag, (DWORD) offset, data, (DWORD) length);
2048     }
2049     return bufferSize == GDI_ERROR ? 0 : bufferSize;
2050 }
2051 
onCopyTableData(SkFontTableTag tag) const2052 sk_sp<SkData> LogFontTypeface::onCopyTableData(SkFontTableTag tag) const {
2053     LOGFONT lf = fLogFont;
2054     SkAutoHDC hdc(lf);
2055 
2056     tag = SkEndian_SwapBE32(tag);
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);
2061     }
2062 
2063     sk_sp<SkData> data;
2064     if (size != GDI_ERROR) {
2065         data = SkData::MakeUninitialized(size);
2066         if (GetFontData(hdc, tag, 0, data->writable_data(), size) == GDI_ERROR) {
2067             data.reset();
2068         }
2069     }
2070     return data;
2071 }
2072 
onCreateScalerContext(const SkScalerContextEffects & effects,const SkDescriptor * desc) const2073 std::unique_ptr<SkScalerContext> LogFontTypeface::onCreateScalerContext(
2074     const SkScalerContextEffects& effects, const SkDescriptor* desc) const
2075 {
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);
2080     }
2081 
2082     ctx.reset();
2083     SkStrikeCache::PurgeAll();
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);
2088     }
2089 
2090     return SkScalerContext::MakeEmpty(
2091             sk_ref_sp(const_cast<LogFontTypeface*>(this)), effects, desc);
2092 }
2093 
onFilterRec(SkScalerContextRec * rec) const2094 void LogFontTypeface::onFilterRec(SkScalerContextRec* rec) const {
2095     rec->useStrokeForFakeBold();
2096 
2097     if (rec->fFlags & SkScalerContext::kLCD_BGROrder_Flag ||
2098         rec->fFlags & SkScalerContext::kLCD_Vertical_Flag)
2099     {
2100         rec->fMaskFormat = SkMask::kA8_Format;
2101         rec->fFlags |= SkScalerContext::kGenA8FromLCD_Flag;
2102     }
2103 
2104     unsigned flagsWeDontSupport = SkScalerContext::kForceAutohinting_Flag |
2105                                   SkScalerContext::kEmbeddedBitmapText_Flag |
2106                                   SkScalerContext::kEmbolden_Flag |
2107                                   SkScalerContext::kLCD_BGROrder_Flag |
2108                                   SkScalerContext::kLCD_Vertical_Flag;
2109     rec->fFlags &= ~flagsWeDontSupport;
2110 
2111     SkFontHinting h = rec->getHinting();
2112     switch (h) {
2113         case SkFontHinting::kNone:
2114             break;
2115         case SkFontHinting::kSlight:
2116             // Only do slight hinting when axis aligned.
2117             // TODO: re-enable slight hinting when FontHostTest can pass.
2118             //if (!isAxisAligned(*rec)) {
2119                 h = SkFontHinting::kNone;
2120             //}
2121             break;
2122         case SkFontHinting::kNormal:
2123         case SkFontHinting::kFull:
2124             // TODO: need to be able to distinguish subpixel positioned glyphs
2125             // and linear metrics.
2126             //rec->fFlags &= ~SkScalerContext::kSubpixelPositioning_Flag;
2127             h = SkFontHinting::kNormal;
2128             break;
2129         default:
2130             SkDEBUGFAIL("unknown hinting");
2131     }
2132     //TODO: if this is a bitmap font, squash hinting and subpixel.
2133     rec->setHinting(h);
2134 
2135 // turn this off since GDI might turn A8 into BW! Need a bigger fix.
2136 #if 0
2137     // Disable LCD when rotated, since GDI's output is ugly
2138     if (isLCD(*rec) && !isAxisAligned(*rec)) {
2139         rec->fMaskFormat = SkMask::kA8_Format;
2140     }
2141 #endif
2142 
2143     if (!fCanBeLCD && isLCD(*rec)) {
2144         rec->fMaskFormat = SkMask::kA8_Format;
2145         rec->fFlags &= ~SkScalerContext::kGenA8FromLCD_Flag;
2146     }
2147 }
2148 
2149 ///////////////////////////////////////////////////////////////////////////////
2150 
2151 #include "include/core/SkDataTable.h"
2152 #include "include/core/SkFontMgr.h"
2153 
valid_logfont_for_enum(const LOGFONT & lf)2154 static bool valid_logfont_for_enum(const LOGFONT& lf) {
2155     // TODO: Vector FON is unsupported and should not be listed.
2156     return
2157         // Ignore implicit vertical variants.
2158         lf.lfFaceName[0] && lf.lfFaceName[0] != '@'
2159 
2160         // DEFAULT_CHARSET is used to get all fonts, but also implies all
2161         // character sets. Filter assuming all fonts support ANSI_CHARSET.
2162         && ANSI_CHARSET == lf.lfCharSet
2163     ;
2164 }
2165 
2166 /** An EnumFontFamExProc implementation which interprets builderParam as
2167  *  an SkTDArray<ENUMLOGFONTEX>* and appends logfonts which
2168  *  pass the valid_logfont_for_enum predicate.
2169  */
enum_family_proc(const LOGFONT * lf,const TEXTMETRIC *,DWORD fontType,LPARAM builderParam)2170 static int CALLBACK enum_family_proc(const LOGFONT* lf, const TEXTMETRIC*,
2171                                      DWORD fontType, LPARAM builderParam) {
2172     if (valid_logfont_for_enum(*lf)) {
2173         SkTDArray<ENUMLOGFONTEX>* array = (SkTDArray<ENUMLOGFONTEX>*)builderParam;
2174         *array->append() = *(const ENUMLOGFONTEX*)lf;
2175     }
2176     return 1; // non-zero means continue
2177 }
2178 
2179 class SkFontStyleSetGDI : public SkFontStyleSet {
2180 public:
SkFontStyleSetGDI(const TCHAR familyName[])2181     SkFontStyleSetGDI(const TCHAR familyName[]) {
2182         LOGFONT lf;
2183         sk_bzero(&lf, sizeof(lf));
2184         lf.lfCharSet = DEFAULT_CHARSET;
2185         _tcscpy_s(lf.lfFaceName, familyName);
2186 
2187         HDC hdc = ::CreateCompatibleDC(nullptr);
2188         ::EnumFontFamiliesEx(hdc, &lf, enum_family_proc, (LPARAM)&fArray, 0);
2189         ::DeleteDC(hdc);
2190     }
2191 
count()2192     int count() override {
2193         return fArray.size();
2194     }
2195 
getStyle(int index,SkFontStyle * fs,SkString * styleName)2196     void getStyle(int index, SkFontStyle* fs, SkString* styleName) override {
2197         if (fs) {
2198             *fs = get_style(fArray[index].elfLogFont);
2199         }
2200         if (styleName) {
2201             const ENUMLOGFONTEX& ref = fArray[index];
2202             // For some reason, ENUMLOGFONTEX and LOGFONT disagree on their type in the
2203             // non-unicode version.
2204             //      ENUMLOGFONTEX uses BYTE
2205             //      LOGFONT uses CHAR
2206             // Here we assert they that the style name is logically the same (size) as
2207             // a TCHAR, so we can use the same converter function.
2208             SkASSERT(sizeof(TCHAR) == sizeof(ref.elfStyle[0]));
2209             tchar_to_skstring((const TCHAR*)ref.elfStyle, styleName);
2210         }
2211     }
2212 
createTypeface(int index)2213     sk_sp<SkTypeface> createTypeface(int index) override {
2214         return SkCreateTypefaceFromLOGFONT(fArray[index].elfLogFont);
2215     }
2216 
matchStyle(const SkFontStyle & pattern)2217     sk_sp<SkTypeface> matchStyle(const SkFontStyle& pattern) override {
2218         return this->matchStyleCSS3(pattern);
2219     }
2220 
2221 private:
2222     SkTDArray<ENUMLOGFONTEX> fArray;
2223 };
2224 
2225 class SkFontMgrGDI : public SkFontMgr {
2226 public:
SkFontMgrGDI()2227     SkFontMgrGDI() {
2228         LOGFONT lf;
2229         sk_bzero(&lf, sizeof(lf));
2230         lf.lfCharSet = DEFAULT_CHARSET;
2231 
2232         HDC hdc = ::CreateCompatibleDC(nullptr);
2233         ::EnumFontFamiliesEx(hdc, &lf, enum_family_proc, (LPARAM)&fLogFontArray, 0);
2234         ::DeleteDC(hdc);
2235     }
2236 
2237 protected:
onCountFamilies() const2238     int onCountFamilies() const override {
2239         return fLogFontArray.size();
2240     }
2241 
onGetFamilyName(int index,SkString * familyName) const2242     void onGetFamilyName(int index, SkString* familyName) const override {
2243         SkASSERT(index < fLogFontArray.size());
2244         tchar_to_skstring(fLogFontArray[index].elfLogFont.lfFaceName, familyName);
2245     }
2246 
onCreateStyleSet(int index) const2247     sk_sp<SkFontStyleSet> onCreateStyleSet(int index) const override {
2248         SkASSERT(index < fLogFontArray.size());
2249         return sk_sp<SkFontStyleSet>(
2250             new SkFontStyleSetGDI(fLogFontArray[index].elfLogFont.lfFaceName));
2251     }
2252 
onMatchFamily(const char familyName[]) const2253     sk_sp<SkFontStyleSet> onMatchFamily(const char familyName[]) const override {
2254         if (nullptr == familyName) {
2255             familyName = "";    // do we need this check???
2256         }
2257         LOGFONT lf;
2258         logfont_for_name(familyName, &lf);
2259         return sk_sp<SkFontStyleSet>(new SkFontStyleSetGDI(lf.lfFaceName));
2260     }
2261 
onMatchFamilyStyle(const char familyName[],const SkFontStyle & fontstyle) const2262     sk_sp<SkTypeface> onMatchFamilyStyle(const char familyName[],
2263                                          const SkFontStyle& fontstyle) const override {
2264         // could be in base impl
2265         sk_sp<SkFontStyleSet> sset(this->matchFamily(familyName));
2266         return sset->matchStyle(fontstyle);
2267     }
2268 
onMatchFamilyStyleCharacter(const char familyName[],const SkFontStyle &,const char * bcp47[],int bcp47Count,SkUnichar character) const2269     sk_sp<SkTypeface> onMatchFamilyStyleCharacter(const char familyName[], const SkFontStyle&,
2270                                                   const char* bcp47[], int bcp47Count,
2271                                                   SkUnichar character) const override {
2272         return nullptr;
2273     }
2274 
onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset> stream,int ttcIndex) const2275     sk_sp<SkTypeface> onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset> stream,
2276                                             int ttcIndex) const override {
2277         if (ttcIndex != 0) {
2278             return nullptr;
2279         }
2280         return create_from_stream(std::move(stream));
2281     }
2282 
onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset> stream,const SkFontArguments & args) const2283     sk_sp<SkTypeface> onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset> stream,
2284                                            const SkFontArguments& args) const override {
2285         return this->makeFromStream(std::move(stream), args.getCollectionIndex());
2286     }
2287 
onMakeFromData(sk_sp<SkData> data,int ttcIndex) const2288     sk_sp<SkTypeface> onMakeFromData(sk_sp<SkData> data, int ttcIndex) const override {
2289         // could be in base impl
2290         return this->makeFromStream(std::unique_ptr<SkStreamAsset>(new SkMemoryStream(std::move(data))),
2291                                     ttcIndex);
2292     }
2293 
onMakeFromFile(const char path[],int ttcIndex) const2294     sk_sp<SkTypeface> onMakeFromFile(const char path[], int ttcIndex) const override {
2295         // could be in base impl
2296         auto stream = SkStream::MakeFromFile(path);
2297         return stream ? this->makeFromStream(std::move(stream), ttcIndex) : nullptr;
2298     }
2299 
onLegacyMakeTypeface(const char familyName[],SkFontStyle style) const2300     sk_sp<SkTypeface> onLegacyMakeTypeface(const char familyName[], SkFontStyle style) const override {
2301         LOGFONT lf;
2302         if (nullptr == familyName) {
2303             lf = get_default_font();
2304         } else {
2305             logfont_for_name(familyName, &lf);
2306         }
2307 
2308         lf.lfWeight = style.weight();
2309         lf.lfItalic = style.slant() == SkFontStyle::kUpright_Slant ? FALSE : TRUE;
2310         return sk_sp<SkTypeface>(SkCreateTypefaceFromLOGFONT(lf));
2311     }
2312 
2313 private:
2314     SkTDArray<ENUMLOGFONTEX> fLogFontArray;
2315 };
2316 
2317 ///////////////////////////////////////////////////////////////////////////////
2318 
SkFontMgr_New_GDI()2319 sk_sp<SkFontMgr> SkFontMgr_New_GDI() { return sk_make_sp<SkFontMgrGDI>(); }
2320 
2321 #endif//defined(SK_BUILD_FOR_WIN)
2322