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