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