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