• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 /*
3  * Copyright 2006 The Android Open Source Project
4  *
5  * Use of this source code is governed by a BSD-style license that can be
6  * found in the LICENSE file.
7  */
8 
9 
10 #include "SkColorFilter.h"
11 #include "SkString.h"
12 #include "SkEndian.h"
13 #include "SkFontHost.h"
14 #include "SkDescriptor.h"
15 #include "SkAdvancedTypefaceMetrics.h"
16 #include "SkStream.h"
17 #include "SkThread.h"
18 #include "SkTypeface_win.h"
19 #include "SkTypefaceCache.h"
20 #include "SkUtils.h"
21 
22 #ifdef WIN32
23 #include "windows.h"
24 #include "tchar.h"
25 #include "usp10.h"
26 
27 // always packed xxRRGGBB
28 typedef uint32_t SkGdiRGB;
29 
SkTAddByteOffset(T * ptr,size_t byteOffset)30 template <typename T> T* SkTAddByteOffset(T* ptr, size_t byteOffset) {
31     return (T*)((char*)ptr + byteOffset);
32 }
33 
34 // define this in your Makefile or .gyp to enforce AA requests
35 // which GDI ignores at small sizes. This flag guarantees AA
36 // for rotated text, regardless of GDI's notions.
37 //#define SK_ENFORCE_ROTATED_TEXT_AA_ON_WINDOWS
38 
39 // client3d has to undefine this for now
40 #define CAN_USE_LOGFONT_NAME
41 
isLCD(const SkScalerContext::Rec & rec)42 static bool isLCD(const SkScalerContext::Rec& rec) {
43     return SkMask::kLCD16_Format == rec.fMaskFormat ||
44            SkMask::kLCD32_Format == rec.fMaskFormat;
45 }
46 
bothZero(SkScalar a,SkScalar b)47 static bool bothZero(SkScalar a, SkScalar b) {
48     return 0 == a && 0 == b;
49 }
50 
51 // returns false if there is any non-90-rotation or skew
isAxisAligned(const SkScalerContext::Rec & rec)52 static bool isAxisAligned(const SkScalerContext::Rec& rec) {
53     return 0 == rec.fPreSkewX &&
54            (bothZero(rec.fPost2x2[0][1], rec.fPost2x2[1][0]) ||
55             bothZero(rec.fPost2x2[0][0], rec.fPost2x2[1][1]));
56 }
57 
needToRenderWithSkia(const SkScalerContext::Rec & rec)58 static bool needToRenderWithSkia(const SkScalerContext::Rec& rec) {
59 #ifdef SK_ENFORCE_ROTATED_TEXT_AA_ON_WINDOWS
60     // What we really want to catch is when GDI will ignore the AA request and give
61     // us BW instead. Smallish rotated text is one heuristic, so this code is just
62     // an approximation. We shouldn't need to do this for larger sizes, but at those
63     // sizes, the quality difference gets less and less between our general
64     // scanconverter and GDI's.
65     if (SkMask::kA8_Format == rec.fMaskFormat && !isAxisAligned(rec)) {
66         return true;
67     }
68 #endif
69     // false means allow GDI to generate the bits
70     return false;
71 }
72 
73 using namespace skia_advanced_typeface_metrics_utils;
74 
75 static const uint16_t BUFFERSIZE = (16384 - 32);
76 static uint8_t glyphbuf[BUFFERSIZE];
77 
78 /**
79  *  Since LOGFONT wants its textsize as an int, and we support fractional sizes,
80  *  and since we have a cache of LOGFONTs for our tyepfaces, we always set the
81  *  lfHeight to a canonical size, and then we use the 2x2 matrix to achieve the
82  *  actual requested size.
83  */
84 static const int gCanonicalTextSize = 64;
85 
make_canonical(LOGFONT * lf)86 static void make_canonical(LOGFONT* lf) {
87     lf->lfHeight = -gCanonicalTextSize;
88     lf->lfQuality = CLEARTYPE_QUALITY;//PROOF_QUALITY;
89     lf->lfCharSet = DEFAULT_CHARSET;
90 //    lf->lfClipPrecision = 64;
91 }
92 
get_style(const LOGFONT & lf)93 static SkTypeface::Style get_style(const LOGFONT& lf) {
94     unsigned style = 0;
95     if (lf.lfWeight >= FW_BOLD) {
96         style |= SkTypeface::kBold;
97     }
98     if (lf.lfItalic) {
99         style |= SkTypeface::kItalic;
100     }
101     return static_cast<SkTypeface::Style>(style);
102 }
103 
setStyle(LOGFONT * lf,SkTypeface::Style style)104 static void setStyle(LOGFONT* lf, SkTypeface::Style style) {
105     lf->lfWeight = (style & SkTypeface::kBold) != 0 ? FW_BOLD : FW_NORMAL ;
106     lf->lfItalic = ((style & SkTypeface::kItalic) != 0);
107 }
108 
SkFixedToFIXED(SkFixed x)109 static inline FIXED SkFixedToFIXED(SkFixed x) {
110     return *(FIXED*)(&x);
111 }
112 
SkScalarToFIXED(SkScalar x)113 static inline FIXED SkScalarToFIXED(SkScalar x) {
114     return SkFixedToFIXED(SkScalarToFixed(x));
115 }
116 
calculateGlyphCount(HDC hdc)117 static unsigned calculateGlyphCount(HDC hdc) {
118     // The 'maxp' table stores the number of glyphs at offset 4, in 2 bytes.
119     const DWORD maxpTag =
120         SkEndian_SwapBE32(SkSetFourByteTag('m', 'a', 'x', 'p'));
121     uint16_t glyphs;
122     if (GetFontData(hdc, maxpTag, 4, &glyphs, sizeof(glyphs)) != GDI_ERROR) {
123         return SkEndian_SwapBE16(glyphs);
124     }
125 
126     // Binary search for glyph count.
127     static const MAT2 mat2 = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
128     int32_t max = SK_MaxU16 + 1;
129     int32_t min = 0;
130     GLYPHMETRICS gm;
131     while (min < max) {
132         int32_t mid = min + ((max - min) / 2);
133         if (GetGlyphOutlineW(hdc, mid, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0,
134                              NULL, &mat2) == GDI_ERROR) {
135             max = mid;
136         } else {
137             min = mid + 1;
138         }
139     }
140     SkASSERT(min == max);
141     return min;
142 }
143 
144 class LogFontTypeface : public SkTypeface {
145 public:
LogFontTypeface(SkTypeface::Style style,SkFontID fontID,const LOGFONT & lf)146     LogFontTypeface(SkTypeface::Style style, SkFontID fontID, const LOGFONT& lf) :
147       SkTypeface(style, fontID, false), fLogFont(lf) {}
148 
149     LOGFONT fLogFont;
150 
Create(const LOGFONT & lf)151     static LogFontTypeface* Create(const LOGFONT& lf) {
152         SkTypeface::Style style = get_style(lf);
153         SkFontID fontID = SkTypefaceCache::NewFontID();
154         return new LogFontTypeface(style, fontID, lf);
155     }
156 };
157 
get_default_font()158 static const LOGFONT& get_default_font() {
159     static LOGFONT gDefaultFont;
160     return gDefaultFont;
161 }
162 
FindByLogFont(SkTypeface * face,SkTypeface::Style requestedStyle,void * ctx)163 static bool FindByLogFont(SkTypeface* face, SkTypeface::Style requestedStyle, void* ctx) {
164     LogFontTypeface* lface = reinterpret_cast<LogFontTypeface*>(face);
165     const LOGFONT* lf = reinterpret_cast<const LOGFONT*>(ctx);
166 
167     return get_style(lface->fLogFont) == requestedStyle &&
168            !memcmp(&lface->fLogFont, lf, sizeof(LOGFONT));
169 }
170 
171 /**
172  *  This guy is public. It first searches the cache, and if a match is not found,
173  *  it creates a new face.
174  */
SkCreateTypefaceFromLOGFONT(const LOGFONT & origLF)175 SkTypeface* SkCreateTypefaceFromLOGFONT(const LOGFONT& origLF) {
176     LOGFONT lf = origLF;
177     make_canonical(&lf);
178     SkTypeface* face = SkTypefaceCache::FindByProcAndRef(FindByLogFont, &lf);
179     if (NULL == face) {
180         face = LogFontTypeface::Create(lf);
181         SkTypefaceCache::Add(face, get_style(lf));
182     }
183     return face;
184 }
185 
186 /**
187  *  This guy is public
188  */
SkLOGFONTFromTypeface(const SkTypeface * face,LOGFONT * lf)189 void SkLOGFONTFromTypeface(const SkTypeface* face, LOGFONT* lf) {
190     if (NULL == face) {
191         *lf = get_default_font();
192     } else {
193         *lf = ((const LogFontTypeface*)face)->fLogFont;
194     }
195 }
196 
NextLogicalFont(SkFontID currFontID,SkFontID origFontID)197 SkFontID SkFontHost::NextLogicalFont(SkFontID currFontID, SkFontID origFontID) {
198   // Zero means that we don't have any fallback fonts for this fontID.
199   // This function is implemented on Android, but doesn't have much
200   // meaning here.
201   return 0;
202 }
203 
ensure_typeface_accessible(SkFontID fontID)204 static void ensure_typeface_accessible(SkFontID fontID) {
205     LogFontTypeface* face = (LogFontTypeface*)SkTypefaceCache::FindByID(fontID);
206     if (face) {
207         SkFontHost::EnsureTypefaceAccessible(*face);
208     }
209 }
210 
GetLogFontByID(SkFontID fontID,LOGFONT * lf)211 static void GetLogFontByID(SkFontID fontID, LOGFONT* lf) {
212     LogFontTypeface* face = (LogFontTypeface*)SkTypefaceCache::FindByID(fontID);
213     if (face) {
214         *lf = face->fLogFont;
215     } else {
216         sk_bzero(lf, sizeof(LOGFONT));
217     }
218 }
219 
220 // Construct Glyph to Unicode table.
221 // Unicode code points that require conjugate pairs in utf16 are not
222 // supported.
223 // TODO(arthurhsu): Add support for conjugate pairs. It looks like that may
224 // require parsing the TTF cmap table (platform 4, encoding 12) directly instead
225 // of calling GetFontUnicodeRange().
populate_glyph_to_unicode(HDC fontHdc,const unsigned glyphCount,SkTDArray<SkUnichar> * glyphToUnicode)226 static void populate_glyph_to_unicode(HDC fontHdc, const unsigned glyphCount,
227                                       SkTDArray<SkUnichar>* glyphToUnicode) {
228     DWORD glyphSetBufferSize = GetFontUnicodeRanges(fontHdc, NULL);
229     if (!glyphSetBufferSize) {
230         return;
231     }
232 
233     SkAutoTDeleteArray<BYTE> glyphSetBuffer(new BYTE[glyphSetBufferSize]);
234     GLYPHSET* glyphSet =
235         reinterpret_cast<LPGLYPHSET>(glyphSetBuffer.get());
236     if (GetFontUnicodeRanges(fontHdc, glyphSet) != glyphSetBufferSize) {
237         return;
238     }
239 
240     glyphToUnicode->setCount(glyphCount);
241     memset(glyphToUnicode->begin(), 0, glyphCount * sizeof(SkUnichar));
242     for (DWORD i = 0; i < glyphSet->cRanges; ++i) {
243         // There is no guarantee that within a Unicode range, the corresponding
244         // glyph id in a font file are continuous. So, even if we have ranges,
245         // we can't just use the first and last entry of the range to compute
246         // result. We need to enumerate them one by one.
247         int count = glyphSet->ranges[i].cGlyphs;
248         SkAutoTArray<WCHAR> chars(count + 1);
249         chars[count] = 0;  // termintate string
250         SkAutoTArray<WORD> glyph(count);
251         for (USHORT j = 0; j < count; ++j) {
252             chars[j] = glyphSet->ranges[i].wcLow + j;
253         }
254         GetGlyphIndicesW(fontHdc, chars.get(), count, glyph.get(),
255                          GGI_MARK_NONEXISTING_GLYPHS);
256         // If the glyph ID is valid, and the glyph is not mapped, then we will
257         // fill in the char id into the vector. If the glyph is mapped already,
258         // skip it.
259         // TODO(arthurhsu): better improve this. e.g. Get all used char ids from
260         // font cache, then generate this mapping table from there. It's
261         // unlikely to have collisions since glyph reuse happens mostly for
262         // different Unicode pages.
263         for (USHORT j = 0; j < count; ++j) {
264             if (glyph[j] != 0xffff && glyph[j] < glyphCount &&
265                 (*glyphToUnicode)[glyph[j]] == 0) {
266                 (*glyphToUnicode)[glyph[j]] = chars[j];
267             }
268         }
269     }
270 }
271 
272 //////////////////////////////////////////////////////////////////////////////////////
273 
alignTo32(int n)274 static int alignTo32(int n) {
275     return (n + 31) & ~31;
276 }
277 
278 struct MyBitmapInfo : public BITMAPINFO {
279     RGBQUAD fMoreSpaceForColors[1];
280 };
281 
282 class HDCOffscreen {
283 public:
HDCOffscreen()284     HDCOffscreen() {
285         fFont = 0;
286         fDC = 0;
287         fBM = 0;
288         fBits = NULL;
289         fWidth = fHeight = 0;
290         fIsBW = false;
291         fColor = kInvalid_Color;
292     }
293 
~HDCOffscreen()294     ~HDCOffscreen() {
295         if (fDC) {
296             DeleteDC(fDC);
297         }
298         if (fBM) {
299             DeleteObject(fBM);
300         }
301     }
302 
init(HFONT font,const XFORM & xform)303     void init(HFONT font, const XFORM& xform) {
304         fFont = font;
305         fXform = xform;
306     }
307 
308     const void* draw(const SkGlyph&, bool isBW, SkGdiRGB fgColor,
309                      size_t* srcRBPtr);
310 
311 private:
312     HDC     fDC;
313     HBITMAP fBM;
314     HFONT   fFont;
315     XFORM   fXform;
316     void*   fBits;  // points into fBM
317     COLORREF fColor;
318     int     fWidth;
319     int     fHeight;
320     bool    fIsBW;
321 
322     enum {
323         // will always trigger us to reset the color, since we
324         // should only store 0 or 0x00FFFFFF or gray (0x007F7F7F)
325         kInvalid_Color = 12345
326     };
327 };
328 
draw(const SkGlyph & glyph,bool isBW,SkGdiRGB fgColor,size_t * srcRBPtr)329 const void* HDCOffscreen::draw(const SkGlyph& glyph, bool isBW,
330                                SkGdiRGB fgColor, size_t* srcRBPtr) {
331     if (0 == fDC) {
332         fDC = CreateCompatibleDC(0);
333         if (0 == fDC) {
334             return NULL;
335         }
336         SetGraphicsMode(fDC, GM_ADVANCED);
337         SetBkMode(fDC, TRANSPARENT);
338         SetTextAlign(fDC, TA_LEFT | TA_BASELINE);
339         SelectObject(fDC, fFont);
340         fColor = kInvalid_Color;
341     }
342 
343     if (fBM && (fIsBW != isBW || fWidth < glyph.fWidth || fHeight < glyph.fHeight)) {
344         DeleteObject(fBM);
345         fBM = 0;
346     }
347     fIsBW = isBW;
348 
349     COLORREF color = fgColor;
350     if (fIsBW) {
351         color = 0xFFFFFF;
352     }
353     if (fColor != color) {
354         fColor = color;
355         COLORREF prev = SetTextColor(fDC, color);
356         SkASSERT(prev != CLR_INVALID);
357     }
358 
359     fWidth = SkMax32(fWidth, glyph.fWidth);
360     fHeight = SkMax32(fHeight, glyph.fHeight);
361 
362     int biWidth = isBW ? alignTo32(fWidth) : fWidth;
363 
364     if (0 == fBM) {
365         MyBitmapInfo info;
366         sk_bzero(&info, sizeof(info));
367         if (isBW) {
368             RGBQUAD blackQuad = { 0, 0, 0, 0 };
369             RGBQUAD whiteQuad = { 0xFF, 0xFF, 0xFF, 0 };
370             info.bmiColors[0] = blackQuad;
371             info.bmiColors[1] = whiteQuad;
372         }
373         info.bmiHeader.biSize = sizeof(info.bmiHeader);
374         info.bmiHeader.biWidth = biWidth;
375         info.bmiHeader.biHeight = fHeight;
376         info.bmiHeader.biPlanes = 1;
377         info.bmiHeader.biBitCount = isBW ? 1 : 32;
378         info.bmiHeader.biCompression = BI_RGB;
379         if (isBW) {
380             info.bmiHeader.biClrUsed = 2;
381         }
382         fBM = CreateDIBSection(fDC, &info, DIB_RGB_COLORS, &fBits, 0, 0);
383         if (0 == fBM) {
384             return NULL;
385         }
386         SelectObject(fDC, fBM);
387     }
388 
389     // erase
390     size_t srcRB = isBW ? (biWidth >> 3) : (fWidth << 2);
391     size_t size = fHeight * srcRB;
392     unsigned bg = (0 == color) ? 0xFF : 0;
393     memset(fBits, bg, size);
394 
395     XFORM xform = fXform;
396     xform.eDx = (float)-glyph.fLeft;
397     xform.eDy = (float)-glyph.fTop;
398     SetWorldTransform(fDC, &xform);
399 
400     uint16_t glyphID = glyph.getGlyphID();
401     BOOL ret = ExtTextOutW(fDC, 0, 0, ETO_GLYPH_INDEX, NULL, reinterpret_cast<LPCWSTR>(&glyphID), 1, NULL);
402     GdiFlush();
403     if (0 == ret) {
404         return NULL;
405     }
406     *srcRBPtr = srcRB;
407     // offset to the start of the image
408     return (const char*)fBits + (fHeight - glyph.fHeight) * srcRB;
409 }
410 
411 //////////////////////////////////////////////////////////////////////////////////////
412 
413 class SkScalerContext_Windows : public SkScalerContext {
414 public:
415     SkScalerContext_Windows(const SkDescriptor* desc);
416     virtual ~SkScalerContext_Windows();
417 
418 protected:
419     virtual unsigned generateGlyphCount();
420     virtual uint16_t generateCharToGlyph(SkUnichar uni);
421     virtual void generateAdvance(SkGlyph* glyph);
422     virtual void generateMetrics(SkGlyph* glyph);
423     virtual void generateImage(const SkGlyph& glyph);
424     virtual void generatePath(const SkGlyph& glyph, SkPath* path);
425     virtual void generateFontMetrics(SkPaint::FontMetrics* mX, SkPaint::FontMetrics* mY);
426 
427 private:
428     HDCOffscreen fOffscreen;
429     SkScalar     fScale;  // to get from canonical size to real size
430     MAT2         fMat22;
431     XFORM        fXform;
432     HDC          fDDC;
433     HFONT        fSavefont;
434     HFONT        fFont;
435     SCRIPT_CACHE fSC;
436     int          fGlyphCount;
437 
438     HFONT        fHiResFont;
439     MAT2         fMat22Identity;
440     SkMatrix     fHiResMatrix;
441 };
442 
mul2float(SkScalar a,SkScalar b)443 static float mul2float(SkScalar a, SkScalar b) {
444     return SkScalarToFloat(SkScalarMul(a, b));
445 }
446 
float2FIXED(float x)447 static FIXED float2FIXED(float x) {
448     return SkFixedToFIXED(SkFloatToFixed(x));
449 }
450 
451 SK_DECLARE_STATIC_MUTEX(gFTMutex);
452 
453 #define HIRES_TEXTSIZE  2048
454 #define HIRES_SHIFT     11
HiResToFixed(int value)455 static inline SkFixed HiResToFixed(int value) {
456     return value << (16 - HIRES_SHIFT);
457 }
458 
needHiResMetrics(const SkScalar mat[2][2])459 static bool needHiResMetrics(const SkScalar mat[2][2]) {
460     return mat[1][0] || mat[0][1];
461 }
462 
compute_quality(const SkScalerContext::Rec & rec)463 static BYTE compute_quality(const SkScalerContext::Rec& rec) {
464     switch (rec.fMaskFormat) {
465         case SkMask::kBW_Format:
466             return NONANTIALIASED_QUALITY;
467         case SkMask::kLCD16_Format:
468         case SkMask::kLCD32_Format:
469             return CLEARTYPE_QUALITY;
470         default:
471             if (rec.fFlags & SkScalerContext::kGenA8FromLCD_Flag) {
472                 return CLEARTYPE_QUALITY;
473             } else {
474                 return ANTIALIASED_QUALITY;
475             }
476     }
477 }
478 
SkScalerContext_Windows(const SkDescriptor * desc)479 SkScalerContext_Windows::SkScalerContext_Windows(const SkDescriptor* desc)
480         : SkScalerContext(desc), fDDC(0), fFont(0), fSavefont(0), fSC(0)
481         , fGlyphCount(-1) {
482     SkAutoMutexAcquire  ac(gFTMutex);
483 
484     fScale = fRec.fTextSize / gCanonicalTextSize;
485 
486     fXform.eM11 = mul2float(fScale, fRec.fPost2x2[0][0]);
487     fXform.eM12 = mul2float(fScale, fRec.fPost2x2[1][0]);
488     fXform.eM21 = mul2float(fScale, fRec.fPost2x2[0][1]);
489     fXform.eM22 = mul2float(fScale, fRec.fPost2x2[1][1]);
490     fXform.eDx = 0;
491     fXform.eDy = 0;
492 
493     fMat22.eM11 = float2FIXED(fXform.eM11);
494     fMat22.eM12 = float2FIXED(fXform.eM12);
495     fMat22.eM21 = float2FIXED(-fXform.eM21);
496     fMat22.eM22 = float2FIXED(-fXform.eM22);
497 
498     fDDC = ::CreateCompatibleDC(NULL);
499     SetGraphicsMode(fDDC, GM_ADVANCED);
500     SetBkMode(fDDC, TRANSPARENT);
501 
502     // Scaling by the DPI is inconsistent with how Skia draws elsewhere
503     //SkScalar height = -(fRec.fTextSize * GetDeviceCaps(ddc, LOGPIXELSY) / 72);
504     LOGFONT lf;
505     GetLogFontByID(fRec.fFontID, &lf);
506     lf.lfHeight = -gCanonicalTextSize;
507     lf.lfQuality = compute_quality(fRec);
508     fFont = CreateFontIndirect(&lf);
509 
510     // if we're rotated, or want fractional widths, create a hires font
511     fHiResFont = 0;
512     if (needHiResMetrics(fRec.fPost2x2)) {
513         lf.lfHeight = -HIRES_TEXTSIZE;
514         fHiResFont = CreateFontIndirect(&lf);
515 
516         fMat22Identity.eM11 = fMat22Identity.eM22 = SkFixedToFIXED(SK_Fixed1);
517         fMat22Identity.eM12 = fMat22Identity.eM21 = SkFixedToFIXED(0);
518 
519         // construct a matrix to go from HIRES logical units to our device units
520         fRec.getSingleMatrix(&fHiResMatrix);
521         SkScalar scale = SkScalarInvert(SkIntToScalar(HIRES_TEXTSIZE));
522         fHiResMatrix.preScale(scale, scale);
523     }
524     fSavefont = (HFONT)SelectObject(fDDC, fFont);
525 
526     if (needToRenderWithSkia(fRec)) {
527         this->forceGenerateImageFromPath();
528     }
529 
530     fOffscreen.init(fFont, fXform);
531 }
532 
~SkScalerContext_Windows()533 SkScalerContext_Windows::~SkScalerContext_Windows() {
534     if (fDDC) {
535         ::SelectObject(fDDC, fSavefont);
536         ::DeleteDC(fDDC);
537     }
538     if (fFont) {
539         ::DeleteObject(fFont);
540     }
541     if (fHiResFont) {
542         ::DeleteObject(fHiResFont);
543     }
544     if (fSC) {
545         ::ScriptFreeCache(&fSC);
546     }
547 }
548 
generateGlyphCount()549 unsigned SkScalerContext_Windows::generateGlyphCount() {
550     if (fGlyphCount < 0) {
551         fGlyphCount = calculateGlyphCount(fDDC);
552     }
553     return fGlyphCount;
554 }
555 
generateCharToGlyph(SkUnichar uni)556 uint16_t SkScalerContext_Windows::generateCharToGlyph(SkUnichar uni) {
557     uint16_t index = 0;
558     WCHAR c[2];
559     // TODO(ctguil): Support characters that generate more than one glyph.
560     if (SkUTF16_FromUnichar(uni, (uint16_t*)c) == 1) {
561         // Type1 fonts fail with uniscribe API. Use GetGlyphIndices for plane 0.
562         SkAssertResult(GetGlyphIndicesW(fDDC, c, 1, &index, 0));
563     } else {
564         // Use uniscribe to detemine glyph index for non-BMP characters.
565         // Need to add extra item to SCRIPT_ITEM to work around a bug in older
566         // windows versions. https://bugzilla.mozilla.org/show_bug.cgi?id=366643
567         SCRIPT_ITEM si[2 + 1];
568         int items;
569         SkAssertResult(
570             SUCCEEDED(ScriptItemize(c, 2, 2, NULL, NULL, si, &items)));
571 
572         WORD log[2];
573         SCRIPT_VISATTR vsa;
574         int glyphs;
575         SkAssertResult(SUCCEEDED(ScriptShape(
576             fDDC, &fSC, c, 2, 1, &si[0].a, &index, log, &vsa, &glyphs)));
577     }
578     return index;
579 }
580 
generateAdvance(SkGlyph * glyph)581 void SkScalerContext_Windows::generateAdvance(SkGlyph* glyph) {
582     this->generateMetrics(glyph);
583 }
584 
generateMetrics(SkGlyph * glyph)585 void SkScalerContext_Windows::generateMetrics(SkGlyph* glyph) {
586 
587     SkASSERT(fDDC);
588 
589     GLYPHMETRICS gm;
590     sk_bzero(&gm, sizeof(gm));
591 
592     glyph->fRsbDelta = 0;
593     glyph->fLsbDelta = 0;
594 
595     // Note: need to use GGO_GRAY8_BITMAP instead of GGO_METRICS because GGO_METRICS returns a smaller
596     // BlackBlox; we need the bigger one in case we need the image.  fAdvance is the same.
597     uint32_t ret = GetGlyphOutlineW(fDDC, glyph->getGlyphID(0), GGO_GRAY8_BITMAP | GGO_GLYPH_INDEX, &gm, 0, NULL, &fMat22);
598     if (GDI_ERROR == ret) {
599         ensure_typeface_accessible(fRec.fFontID);
600         ret = GetGlyphOutlineW(fDDC, glyph->getGlyphID(0), GGO_GRAY8_BITMAP | GGO_GLYPH_INDEX, &gm, 0, NULL, &fMat22);
601     }
602 
603     if (GDI_ERROR != ret) {
604         if (ret == 0) {
605             // for white space, ret is zero and gmBlackBoxX, gmBlackBoxY are 1 incorrectly!
606             gm.gmBlackBoxX = gm.gmBlackBoxY = 0;
607         }
608         glyph->fWidth   = gm.gmBlackBoxX;
609         glyph->fHeight  = gm.gmBlackBoxY;
610         glyph->fTop     = SkToS16(gm.gmptGlyphOrigin.y - gm.gmBlackBoxY);
611         glyph->fLeft    = SkToS16(gm.gmptGlyphOrigin.x);
612         glyph->fAdvanceX = SkIntToFixed(gm.gmCellIncX);
613         glyph->fAdvanceY = -SkIntToFixed(gm.gmCellIncY);
614 
615         // we outset in all dimensions, since the image may bleed outside
616         // of the computed bounds returned by GetGlyphOutline.
617         // This was deduced by trial and error for small text (e.g. 8pt), so there
618         // maybe a more precise way to make this adjustment...
619         //
620         // This test shows us clipping the tops of some of the CJK fonts unless we
621         // increase the top of the box by 2, hence the height by 4. This seems to
622         // correspond to an embedded bitmap font, but not sure.
623         //     LayoutTests/fast/text/backslash-to-yen-sign-euc.html
624         //
625         if (glyph->fWidth) {    // don't outset an empty glyph
626             glyph->fWidth += 4;
627             glyph->fHeight += 4;
628             glyph->fTop -= 2;
629             glyph->fLeft -= 2;
630         }
631 
632         if (fHiResFont) {
633             SelectObject(fDDC, fHiResFont);
634             sk_bzero(&gm, sizeof(gm));
635             ret = GetGlyphOutlineW(fDDC, glyph->getGlyphID(0), GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &fMat22Identity);
636             if (GDI_ERROR != ret) {
637                 SkPoint advance;
638                 fHiResMatrix.mapXY(SkIntToScalar(gm.gmCellIncX), SkIntToScalar(gm.gmCellIncY), &advance);
639                 glyph->fAdvanceX = SkScalarToFixed(advance.fX);
640                 glyph->fAdvanceY = SkScalarToFixed(advance.fY);
641             }
642             SelectObject(fDDC, fFont);
643         }
644     } else {
645         glyph->fWidth = 0;
646     }
647 }
648 
generateFontMetrics(SkPaint::FontMetrics * mx,SkPaint::FontMetrics * my)649 void SkScalerContext_Windows::generateFontMetrics(SkPaint::FontMetrics* mx, SkPaint::FontMetrics* my) {
650 // Note: This code was borrowed from generateLineHeight, which has a note
651 // stating that it may be incorrect.
652     if (!(mx || my))
653       return;
654 
655     SkASSERT(fDDC);
656 
657     OUTLINETEXTMETRIC otm;
658 
659     uint32_t ret = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm);
660     if (GDI_ERROR == ret) {
661         ensure_typeface_accessible(fRec.fFontID);
662         ret = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm);
663     }
664     if (sizeof(otm) != ret) {
665       return;
666     }
667 
668     if (mx) {
669         mx->fTop = -fScale * otm.otmTextMetrics.tmAscent;
670         mx->fAscent = -fScale * otm.otmAscent;
671         mx->fDescent = -fScale * otm.otmDescent;
672         mx->fBottom = fScale * otm.otmTextMetrics.tmDescent;
673         mx->fLeading = fScale * (otm.otmTextMetrics.tmInternalLeading
674                                  + otm.otmTextMetrics.tmExternalLeading);
675     }
676 
677     if (my) {
678         my->fTop = -fScale * otm.otmTextMetrics.tmAscent;
679         my->fAscent = -fScale * otm.otmAscent;
680         my->fDescent = -fScale * otm.otmDescent;
681         my->fBottom = fScale * otm.otmTextMetrics.tmDescent;
682         my->fLeading = fScale * (otm.otmTextMetrics.tmInternalLeading
683                                  + otm.otmTextMetrics.tmExternalLeading);
684     }
685 }
686 
687 ////////////////////////////////////////////////////////////////////////////////////////
688 
build_power_table(uint8_t table[],float ee)689 static void build_power_table(uint8_t table[], float ee) {
690     for (int i = 0; i < 256; i++) {
691         float x = i / 255.f;
692         x = powf(x, ee);
693         int xx = SkScalarRound(SkFloatToScalar(x * 255));
694         table[i] = SkToU8(xx);
695     }
696 }
697 
698 // This will invert the gamma applied by GDI, so we can sort-of get linear values.
699 // Needed when we draw non-black, non-white text, and don't know how to bias it.
getInverseGammaTable()700 static const uint8_t* getInverseGammaTable() {
701     static bool gInited;
702     static uint8_t gTable[256];
703     if (!gInited) {
704         UINT level = 0;
705         if (!SystemParametersInfo(SPI_GETFONTSMOOTHINGCONTRAST, 0, &level, 0) || !level) {
706             // can't get the data, so use a default
707             level = 1400;
708         }
709         build_power_table(gTable, level / 1000.0f);
710         gInited = true;
711     }
712     return gTable;
713 }
714 
715 #include "SkColorPriv.h"
716 
717 // gdi's bitmap is upside-down, so we reverse dst walking in Y
718 // whenever we copy it into skia's buffer
719 
compute_luminance(int r,int g,int b)720 static int compute_luminance(int r, int g, int b) {
721 //    return (r * 2 + g * 5 + b) >> 3;
722     return (r * 27 + g * 92 + b * 9) >> 7;
723 }
724 
rgb_to_a8(SkGdiRGB rgb)725 static inline uint8_t rgb_to_a8(SkGdiRGB rgb) {
726     int r = (rgb >> 16) & 0xFF;
727     int g = (rgb >>  8) & 0xFF;
728     int b = (rgb >>  0) & 0xFF;
729     return compute_luminance(r, g, b);
730 }
731 
rgb_to_lcd16(SkGdiRGB rgb)732 static inline uint16_t rgb_to_lcd16(SkGdiRGB rgb) {
733     int r = (rgb >> 16) & 0xFF;
734     int g = (rgb >>  8) & 0xFF;
735     int b = (rgb >>  0) & 0xFF;
736     return SkPackRGB16(SkR32ToR16(r), SkG32ToG16(g), SkB32ToB16(b));
737 }
738 
rgb_to_lcd32(SkGdiRGB rgb)739 static inline SkPMColor rgb_to_lcd32(SkGdiRGB rgb) {
740     int r = (rgb >> 16) & 0xFF;
741     int g = (rgb >>  8) & 0xFF;
742     int b = (rgb >>  0) & 0xFF;
743     int a = SkMax32(r, SkMax32(g, b));
744     return SkPackARGB32(a, r, g, b);
745 }
746 
747 // Is this GDI color neither black nor white? If so, we have to keep this
748 // image as is, rather than smashing it down to a BW mask.
749 //
750 // returns int instead of bool, since we don't want/have to pay to convert
751 // the zero/non-zero value into a bool
is_not_black_or_white(SkGdiRGB c)752 static int is_not_black_or_white(SkGdiRGB c) {
753     // same as (but faster than)
754     //      c &= 0x00FFFFFF;
755     //      return 0 == c || 0x00FFFFFF == c;
756     return (c + (c & 1)) & 0x00FFFFFF;
757 }
758 
is_rgb_really_bw(const SkGdiRGB * src,int width,int height,int srcRB)759 static bool is_rgb_really_bw(const SkGdiRGB* src, int width, int height, int srcRB) {
760     for (int y = 0; y < height; ++y) {
761         for (int x = 0; x < width; ++x) {
762             if (is_not_black_or_white(src[x])) {
763                 return false;
764             }
765         }
766         src = SkTAddByteOffset(src, srcRB);
767     }
768     return true;
769 }
770 
rgb_to_bw(const SkGdiRGB * SK_RESTRICT src,size_t srcRB,const SkGlyph & glyph,int32_t xorMask)771 static void rgb_to_bw(const SkGdiRGB* SK_RESTRICT src, size_t srcRB,
772                       const SkGlyph& glyph, int32_t xorMask) {
773     const int width = glyph.fWidth;
774     const size_t dstRB = (width + 7) >> 3;
775     uint8_t* SK_RESTRICT dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
776 
777     int byteCount = width >> 3;
778     int bitCount = width & 7;
779 
780     // adjust srcRB to skip the values in our byteCount loop,
781     // since we increment src locally there
782     srcRB -= byteCount * 8 * sizeof(SkGdiRGB);
783 
784     for (int y = 0; y < glyph.fHeight; ++y) {
785         if (byteCount > 0) {
786             for (int i = 0; i < byteCount; ++i) {
787                 unsigned byte = 0;
788                 byte |= (src[0] ^ xorMask) & (1 << 7);
789                 byte |= (src[1] ^ xorMask) & (1 << 6);
790                 byte |= (src[2] ^ xorMask) & (1 << 5);
791                 byte |= (src[3] ^ xorMask) & (1 << 4);
792                 byte |= (src[4] ^ xorMask) & (1 << 3);
793                 byte |= (src[5] ^ xorMask) & (1 << 2);
794                 byte |= (src[6] ^ xorMask) & (1 << 1);
795                 byte |= (src[7] ^ xorMask) & (1 << 0);
796                 dst[i] = byte;
797                 src += 8;
798             }
799         }
800         if (bitCount > 0) {
801             unsigned byte = 0;
802             unsigned mask = 0x80;
803             for (int i = 0; i < bitCount; i++) {
804                 byte |= (src[i] ^ xorMask) & mask;
805                 mask >>= 1;
806             }
807             dst[byteCount] = byte;
808         }
809         src = SkTAddByteOffset(src, srcRB);
810         dst -= dstRB;
811     }
812 }
813 
rgb_to_a8(const SkGdiRGB * SK_RESTRICT src,size_t srcRB,const SkGlyph & glyph,int32_t xorMask)814 static void rgb_to_a8(const SkGdiRGB* SK_RESTRICT src, size_t srcRB,
815                       const SkGlyph& glyph, int32_t xorMask) {
816     const size_t dstRB = glyph.rowBytes();
817     const int width = glyph.fWidth;
818     uint8_t* SK_RESTRICT dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
819 
820     for (int y = 0; y < glyph.fHeight; y++) {
821         for (int i = 0; i < width; i++) {
822             dst[i] = rgb_to_a8(src[i] ^ xorMask);
823         }
824         src = SkTAddByteOffset(src, srcRB);
825         dst -= dstRB;
826     }
827 }
828 
rgb_to_lcd16(const SkGdiRGB * SK_RESTRICT src,size_t srcRB,const SkGlyph & glyph,int32_t xorMask)829 static void rgb_to_lcd16(const SkGdiRGB* SK_RESTRICT src, size_t srcRB,
830                          const SkGlyph& glyph, int32_t xorMask) {
831     const size_t dstRB = glyph.rowBytes();
832     const int width = glyph.fWidth;
833     uint16_t* SK_RESTRICT dst = (uint16_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
834 
835     for (int y = 0; y < glyph.fHeight; y++) {
836         for (int i = 0; i < width; i++) {
837             dst[i] = rgb_to_lcd16(src[i] ^ xorMask);
838         }
839         src = SkTAddByteOffset(src, srcRB);
840         dst = (uint16_t*)((char*)dst - dstRB);
841     }
842 }
843 
rgb_to_lcd32(const SkGdiRGB * SK_RESTRICT src,size_t srcRB,const SkGlyph & glyph,int32_t xorMask)844 static void rgb_to_lcd32(const SkGdiRGB* SK_RESTRICT src, size_t srcRB,
845                          const SkGlyph& glyph, int32_t xorMask) {
846     const size_t dstRB = glyph.rowBytes();
847     const int width = glyph.fWidth;
848     SkPMColor* SK_RESTRICT dst = (SkPMColor*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
849 
850     for (int y = 0; y < glyph.fHeight; y++) {
851         for (int i = 0; i < width; i++) {
852             dst[i] = rgb_to_lcd32(src[i] ^ xorMask);
853         }
854         src = SkTAddByteOffset(src, srcRB);
855         dst = (SkPMColor*)((char*)dst - dstRB);
856     }
857 }
858 
clamp255(unsigned x)859 static inline unsigned clamp255(unsigned x) {
860     SkASSERT(x <= 256);
861     return x - (x >> 8);
862 }
863 
864 #define WHITE_LUMINANCE_LIMIT   0xA0
865 #define BLACK_LUMINANCE_LIMIT   0x40
866 
generateImage(const SkGlyph & glyph)867 void SkScalerContext_Windows::generateImage(const SkGlyph& glyph) {
868     SkAutoMutexAcquire  ac(gFTMutex);
869 
870     SkASSERT(fDDC);
871 
872     const bool isBW = SkMask::kBW_Format == fRec.fMaskFormat;
873     const bool isAA = !isLCD(fRec);
874     bool isWhite = fRec.getLuminanceByte() >= WHITE_LUMINANCE_LIMIT;
875     bool isBlack = fRec.getLuminanceByte() <= BLACK_LUMINANCE_LIMIT;
876 
877     SkGdiRGB fgColor;
878     uint32_t rgbXOR;
879     const uint8_t* table = NULL;
880     if (isBW || isWhite) {
881         fgColor = 0x00FFFFFF;
882         rgbXOR = 0;
883     } else if (isBlack) {
884         fgColor = 0;
885         rgbXOR = ~0;
886     } else {
887         table = getInverseGammaTable();
888         fgColor = 0x00FFFFFF;
889         rgbXOR = 0;
890     }
891 
892     size_t srcRB;
893     const void* bits = fOffscreen.draw(glyph, isBW, fgColor, &srcRB);
894     if (NULL == bits) {
895         ensure_typeface_accessible(fRec.fFontID);
896         bits = fOffscreen.draw(glyph, isBW, fgColor, &srcRB);
897         if (NULL == bits) {
898             sk_bzero(glyph.fImage, glyph.computeImageSize());
899             return;
900         }
901     }
902 
903     if (table) {
904         SkGdiRGB* addr = (SkGdiRGB*)bits;
905         for (int y = 0; y < glyph.fHeight; ++y) {
906             for (int x = 0; x < glyph.fWidth; ++x) {
907                 int r = (addr[x] >> 16) & 0xFF;
908                 int g = (addr[x] >>  8) & 0xFF;
909                 int b = (addr[x] >>  0) & 0xFF;
910                 addr[x] = (table[r] << 16) | (table[g] << 8) | table[b];
911             }
912             addr = SkTAddByteOffset(addr, srcRB);
913         }
914     }
915 
916     int width = glyph.fWidth;
917     size_t dstRB = glyph.rowBytes();
918     if (isBW) {
919         const uint8_t* src = (const uint8_t*)bits;
920         uint8_t* dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
921         for (int y = 0; y < glyph.fHeight; y++) {
922             memcpy(dst, src, dstRB);
923             src += srcRB;
924             dst -= dstRB;
925         }
926     } else if (isAA) {
927         // since the caller may require A8 for maskfilters, we can't check for BW
928         // ... until we have the caller tell us that explicitly
929         const SkGdiRGB* src = (const SkGdiRGB*)bits;
930         rgb_to_a8(src, srcRB, glyph, rgbXOR);
931     } else {    // LCD16
932         const SkGdiRGB* src = (const SkGdiRGB*)bits;
933         if (is_rgb_really_bw(src, width, glyph.fHeight, srcRB)) {
934             rgb_to_bw(src, srcRB, glyph, rgbXOR);
935             ((SkGlyph*)&glyph)->fMaskFormat = SkMask::kBW_Format;
936         } else {
937             if (SkMask::kLCD16_Format == glyph.fMaskFormat) {
938                 rgb_to_lcd16(src, srcRB, glyph, rgbXOR);
939             } else {
940                 SkASSERT(SkMask::kLCD32_Format == glyph.fMaskFormat);
941                 rgb_to_lcd32(src, srcRB, glyph, rgbXOR);
942             }
943         }
944     }
945 }
946 
generatePath(const SkGlyph & glyph,SkPath * path)947 void SkScalerContext_Windows::generatePath(const SkGlyph& glyph, SkPath* path) {
948 
949     SkAutoMutexAcquire  ac(gFTMutex);
950 
951     SkASSERT(&glyph && path);
952     SkASSERT(fDDC);
953 
954     path->reset();
955 
956 #if 0
957     char buf[1024];
958     sprintf(buf, "generatePath: id:%d, w=%d, h=%d, font:%s,fh:%d\n", glyph.fID, glyph.fWidth, glyph.fHeight, lf.lfFaceName, lf.lfHeight);
959     OutputDebugString(buf);
960 #endif
961 
962     GLYPHMETRICS gm;
963     uint32_t total_size = GetGlyphOutlineW(fDDC, glyph.fID, GGO_NATIVE | GGO_GLYPH_INDEX, &gm, BUFFERSIZE, glyphbuf, &fMat22);
964     if (GDI_ERROR == total_size) {
965         ensure_typeface_accessible(fRec.fFontID);
966         total_size = GetGlyphOutlineW(fDDC, glyph.fID, GGO_NATIVE | GGO_GLYPH_INDEX, &gm, BUFFERSIZE, glyphbuf, &fMat22);
967     }
968 
969     if (GDI_ERROR != total_size) {
970 
971         const uint8_t* cur_glyph = glyphbuf;
972         const uint8_t* end_glyph = glyphbuf + total_size;
973 
974         while(cur_glyph < end_glyph) {
975             const TTPOLYGONHEADER* th = (TTPOLYGONHEADER*)cur_glyph;
976 
977             const uint8_t* end_poly = cur_glyph + th->cb;
978             const uint8_t* cur_poly = cur_glyph + sizeof(TTPOLYGONHEADER);
979 
980             path->moveTo(SkFixedToScalar(*(SkFixed*)(&th->pfxStart.x)), SkFixedToScalar(*(SkFixed*)(&th->pfxStart.y)));
981 
982             while(cur_poly < end_poly) {
983                 const TTPOLYCURVE* pc = (const TTPOLYCURVE*)cur_poly;
984 
985                 if (pc->wType == TT_PRIM_LINE) {
986                     for (uint16_t i = 0; i < pc->cpfx; i++) {
987                         path->lineTo(SkFixedToScalar(*(SkFixed*)(&pc->apfx[i].x)), SkFixedToScalar(*(SkFixed*)(&pc->apfx[i].y)));
988                     }
989                 }
990 
991                 if (pc->wType == TT_PRIM_QSPLINE) {
992                     for (uint16_t u = 0; u < pc->cpfx - 1; u++) { // Walk through points in spline
993                         POINTFX pnt_b = pc->apfx[u];    // B is always the current point
994                         POINTFX pnt_c = pc->apfx[u+1];
995 
996                         if (u < pc->cpfx - 2) {          // If not on last spline, compute C
997                             pnt_c.x = SkFixedToFIXED(SkFixedAve(*(SkFixed*)(&pnt_b.x), *(SkFixed*)(&pnt_c.x)));
998                             pnt_c.y = SkFixedToFIXED(SkFixedAve(*(SkFixed*)(&pnt_b.y), *(SkFixed*)(&pnt_c.y)));
999                         }
1000 
1001                         path->quadTo(SkFixedToScalar(*(SkFixed*)(&pnt_b.x)), SkFixedToScalar(*(SkFixed*)(&pnt_b.y)), SkFixedToScalar(*(SkFixed*)(&pnt_c.x)), SkFixedToScalar(*(SkFixed*)(&pnt_c.y)));
1002                     }
1003                 }
1004                 cur_poly += sizeof(uint16_t) * 2 + sizeof(POINTFX) * pc->cpfx;
1005             }
1006             cur_glyph += th->cb;
1007             path->close();
1008         }
1009     }
1010     else {
1011         SkASSERT(false);
1012     }
1013     //char buf[1024];
1014     //sprintf(buf, "generatePath: count:%d\n", count);
1015     //OutputDebugString(buf);
1016 }
1017 
Serialize(const SkTypeface * face,SkWStream * stream)1018 void SkFontHost::Serialize(const SkTypeface* face, SkWStream* stream) {
1019     SkDEBUGFAIL("SkFontHost::Serialize unimplemented");
1020 }
1021 
Deserialize(SkStream * stream)1022 SkTypeface* SkFontHost::Deserialize(SkStream* stream) {
1023     SkDEBUGFAIL("SkFontHost::Deserialize unimplemented");
1024     return NULL;
1025 }
1026 
getWidthAdvance(HDC hdc,int gId,int16_t * advance)1027 static bool getWidthAdvance(HDC hdc, int gId, int16_t* advance) {
1028     // Initialize the MAT2 structure to the identify transformation matrix.
1029     static const MAT2 mat2 = {SkScalarToFIXED(1), SkScalarToFIXED(0),
1030                         SkScalarToFIXED(0), SkScalarToFIXED(1)};
1031     int flags = GGO_METRICS | GGO_GLYPH_INDEX;
1032     GLYPHMETRICS gm;
1033     if (GDI_ERROR == GetGlyphOutline(hdc, gId, flags, &gm, 0, NULL, &mat2)) {
1034         return false;
1035     }
1036     SkASSERT(advance);
1037     *advance = gm.gmCellIncX;
1038     return true;
1039 }
1040 
1041 // static
GetAdvancedTypefaceMetrics(uint32_t fontID,SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo,const uint32_t * glyphIDs,uint32_t glyphIDsCount)1042 SkAdvancedTypefaceMetrics* SkFontHost::GetAdvancedTypefaceMetrics(
1043         uint32_t fontID,
1044         SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo,
1045         const uint32_t* glyphIDs,
1046         uint32_t glyphIDsCount) {
1047     LOGFONT lf;
1048     GetLogFontByID(fontID, &lf);
1049     SkAdvancedTypefaceMetrics* info = NULL;
1050 
1051     HDC hdc = CreateCompatibleDC(NULL);
1052     HFONT font = CreateFontIndirect(&lf);
1053     HFONT savefont = (HFONT)SelectObject(hdc, font);
1054     HFONT designFont = NULL;
1055 
1056     const char stem_chars[] = {'i', 'I', '!', '1'};
1057     int16_t min_width;
1058     unsigned glyphCount;
1059 
1060     // To request design units, create a logical font whose height is specified
1061     // as unitsPerEm.
1062     OUTLINETEXTMETRIC otm;
1063     unsigned int otmRet = GetOutlineTextMetrics(hdc, sizeof(otm), &otm);
1064     if (0 == otmRet) {
1065         ensure_typeface_accessible(fontID);
1066         otmRet = GetOutlineTextMetrics(hdc, sizeof(otm), &otm);
1067     }
1068     if (!otmRet || !GetTextFace(hdc, LF_FACESIZE, lf.lfFaceName)) {
1069         goto Error;
1070     }
1071     lf.lfHeight = -SkToS32(otm.otmEMSquare);
1072     designFont = CreateFontIndirect(&lf);
1073     SelectObject(hdc, designFont);
1074     if (!GetOutlineTextMetrics(hdc, sizeof(otm), &otm)) {
1075         goto Error;
1076     }
1077     glyphCount = calculateGlyphCount(hdc);
1078 
1079     info = new SkAdvancedTypefaceMetrics;
1080     info->fEmSize = otm.otmEMSquare;
1081     info->fMultiMaster = false;
1082     info->fLastGlyphID = SkToU16(glyphCount - 1);
1083     info->fStyle = 0;
1084 #ifdef UNICODE
1085     // Get the buffer size needed first.
1086     size_t str_len = WideCharToMultiByte(CP_UTF8, 0, lf.lfFaceName, -1, NULL,
1087                                          0, NULL, NULL);
1088     // Allocate a buffer (str_len already has terminating null accounted for).
1089     char *familyName = new char[str_len];
1090     // Now actually convert the string.
1091     WideCharToMultiByte(CP_UTF8, 0, lf.lfFaceName, -1, familyName, str_len,
1092                           NULL, NULL);
1093     info->fFontName.set(familyName);
1094     delete [] familyName;
1095 #else
1096     info->fFontName.set(lf.lfFaceName);
1097 #endif
1098 
1099     if (perGlyphInfo & SkAdvancedTypefaceMetrics::kToUnicode_PerGlyphInfo) {
1100         populate_glyph_to_unicode(hdc, glyphCount, &(info->fGlyphToUnicode));
1101     }
1102 
1103     if (otm.otmTextMetrics.tmPitchAndFamily & TMPF_TRUETYPE) {
1104         info->fType = SkAdvancedTypefaceMetrics::kTrueType_Font;
1105     } else {
1106         info->fType = SkAdvancedTypefaceMetrics::kOther_Font;
1107         info->fItalicAngle = 0;
1108         info->fAscent = 0;
1109         info->fDescent = 0;
1110         info->fStemV = 0;
1111         info->fCapHeight = 0;
1112         info->fBBox = SkIRect::MakeEmpty();
1113         return info;
1114     }
1115 
1116     // If this bit is clear the font is a fixed pitch font.
1117     if (!(otm.otmTextMetrics.tmPitchAndFamily & TMPF_FIXED_PITCH)) {
1118         info->fStyle |= SkAdvancedTypefaceMetrics::kFixedPitch_Style;
1119     }
1120     if (otm.otmTextMetrics.tmItalic) {
1121         info->fStyle |= SkAdvancedTypefaceMetrics::kItalic_Style;
1122     }
1123     // Setting symbolic style by default for now.
1124     info->fStyle |= SkAdvancedTypefaceMetrics::kSymbolic_Style;
1125     if (otm.otmTextMetrics.tmPitchAndFamily & FF_ROMAN) {
1126         info->fStyle |= SkAdvancedTypefaceMetrics::kSerif_Style;
1127     } else if (otm.otmTextMetrics.tmPitchAndFamily & FF_SCRIPT) {
1128             info->fStyle |= SkAdvancedTypefaceMetrics::kScript_Style;
1129     }
1130 
1131     // The main italic angle of the font, in tenths of a degree counterclockwise
1132     // from vertical.
1133     info->fItalicAngle = otm.otmItalicAngle / 10;
1134     info->fAscent = SkToS16(otm.otmTextMetrics.tmAscent);
1135     info->fDescent = SkToS16(-otm.otmTextMetrics.tmDescent);
1136     // TODO(ctguil): Use alternate cap height calculation.
1137     // MSDN says otmsCapEmHeight is not support but it is returning a value on
1138     // my Win7 box.
1139     info->fCapHeight = otm.otmsCapEmHeight;
1140     info->fBBox =
1141         SkIRect::MakeLTRB(otm.otmrcFontBox.left, otm.otmrcFontBox.top,
1142                           otm.otmrcFontBox.right, otm.otmrcFontBox.bottom);
1143 
1144     // Figure out a good guess for StemV - Min width of i, I, !, 1.
1145     // This probably isn't very good with an italic font.
1146     min_width = SHRT_MAX;
1147     info->fStemV = 0;
1148     for (size_t i = 0; i < SK_ARRAY_COUNT(stem_chars); i++) {
1149         ABC abcWidths;
1150         if (GetCharABCWidths(hdc, stem_chars[i], stem_chars[i], &abcWidths)) {
1151             int16_t width = abcWidths.abcB;
1152             if (width > 0 && width < min_width) {
1153                 min_width = width;
1154                 info->fStemV = min_width;
1155             }
1156         }
1157     }
1158 
1159     // If bit 1 is set, the font may not be embedded in a document.
1160     // If bit 1 is clear, the font can be embedded.
1161     // If bit 2 is set, the embedding is read-only.
1162     if (otm.otmfsType & 0x1) {
1163         info->fType = SkAdvancedTypefaceMetrics::kNotEmbeddable_Font;
1164     } else if (perGlyphInfo &
1165                SkAdvancedTypefaceMetrics::kHAdvance_PerGlyphInfo) {
1166         if (info->fStyle & SkAdvancedTypefaceMetrics::kFixedPitch_Style) {
1167             appendRange(&info->fGlyphWidths, 0);
1168             info->fGlyphWidths->fAdvance.append(1, &min_width);
1169             finishRange(info->fGlyphWidths.get(), 0,
1170                         SkAdvancedTypefaceMetrics::WidthRange::kDefault);
1171         } else {
1172             info->fGlyphWidths.reset(
1173                 getAdvanceData(hdc,
1174                                glyphCount,
1175                                glyphIDs,
1176                                glyphIDsCount,
1177                                &getWidthAdvance));
1178         }
1179     }
1180 
1181 Error:
1182     SelectObject(hdc, savefont);
1183     DeleteObject(designFont);
1184     DeleteObject(font);
1185     DeleteDC(hdc);
1186 
1187     return info;
1188 }
1189 
CreateTypefaceFromStream(SkStream * stream)1190 SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) {
1191 
1192     //Should not be used on Windows, keep linker happy
1193     SkASSERT(false);
1194     return SkCreateTypefaceFromLOGFONT(get_default_font());
1195 }
1196 
OpenStream(SkFontID uniqueID)1197 SkStream* SkFontHost::OpenStream(SkFontID uniqueID) {
1198     const DWORD kTTCTag =
1199         SkEndian_SwapBE32(SkSetFourByteTag('t', 't', 'c', 'f'));
1200     LOGFONT lf;
1201     GetLogFontByID(uniqueID, &lf);
1202 
1203     HDC hdc = ::CreateCompatibleDC(NULL);
1204     HFONT font = CreateFontIndirect(&lf);
1205     HFONT savefont = (HFONT)SelectObject(hdc, font);
1206 
1207     SkMemoryStream* stream = NULL;
1208     DWORD tables[2] = {kTTCTag, 0};
1209     for (int i = 0; i < SK_ARRAY_COUNT(tables); i++) {
1210         size_t bufferSize = GetFontData(hdc, tables[i], 0, NULL, 0);
1211         if (bufferSize == GDI_ERROR) {
1212             ensure_typeface_accessible(uniqueID);
1213             bufferSize = GetFontData(hdc, tables[i], 0, NULL, 0);
1214         }
1215         if (bufferSize != GDI_ERROR) {
1216             stream = new SkMemoryStream(bufferSize);
1217             if (GetFontData(hdc, tables[i], 0, (void*)stream->getMemoryBase(),
1218                             bufferSize)) {
1219                 break;
1220             } else {
1221                 delete stream;
1222                 stream = NULL;
1223             }
1224         }
1225     }
1226 
1227     SelectObject(hdc, savefont);
1228     DeleteObject(font);
1229     DeleteDC(hdc);
1230 
1231     return stream;
1232 }
1233 
CreateScalerContext(const SkDescriptor * desc)1234 SkScalerContext* SkFontHost::CreateScalerContext(const SkDescriptor* desc) {
1235     return SkNEW_ARGS(SkScalerContext_Windows, (desc));
1236 }
1237 
1238 /** Return the closest matching typeface given either an existing family
1239  (specified by a typeface in that family) or by a familyName, and a
1240  requested style.
1241  1) If familyFace is null, use familyName.
1242  2) If familyName is null, use familyFace.
1243  3) If both are null, return the default font that best matches style
1244  This MUST not return NULL.
1245  */
1246 
CreateTypeface(const SkTypeface * familyFace,const char familyName[],const void * data,size_t bytelength,SkTypeface::Style style)1247 SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace,
1248                                        const char familyName[],
1249                                        const void* data, size_t bytelength,
1250                                        SkTypeface::Style style) {
1251     LOGFONT lf;
1252     if (NULL == familyFace && NULL == familyName) {
1253         lf = get_default_font();
1254     } else if (familyFace) {
1255         LogFontTypeface* face = (LogFontTypeface*)familyFace;
1256         lf = face->fLogFont;
1257     } else {
1258         memset(&lf, 0, sizeof(LOGFONT));
1259 #ifdef UNICODE
1260         // Get the buffer size needed first.
1261         size_t str_len = ::MultiByteToWideChar(CP_UTF8, 0, familyName,
1262                                                 -1, NULL, 0);
1263         // Allocate a buffer (str_len already has terminating null
1264         // accounted for).
1265         wchar_t *wideFamilyName = new wchar_t[str_len];
1266         // Now actually convert the string.
1267         ::MultiByteToWideChar(CP_UTF8, 0, familyName, -1,
1268                                 wideFamilyName, str_len);
1269         ::wcsncpy(lf.lfFaceName, wideFamilyName, LF_FACESIZE);
1270         delete [] wideFamilyName;
1271 #else
1272         ::strncpy(lf.lfFaceName, familyName, LF_FACESIZE);
1273 #endif
1274         lf.lfFaceName[LF_FACESIZE-1] = '\0';
1275     }
1276     setStyle(&lf, style);
1277     return SkCreateTypefaceFromLOGFONT(lf);
1278 }
1279 
CreateTypefaceFromFile(const char path[])1280 SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) {
1281     printf("SkFontHost::CreateTypefaceFromFile unimplemented");
1282     return NULL;
1283 }
1284 
FilterRec(SkScalerContext::Rec * rec)1285 void SkFontHost::FilterRec(SkScalerContext::Rec* rec) {
1286     unsigned flagsWeDontSupport = SkScalerContext::kDevKernText_Flag |
1287                                   SkScalerContext::kAutohinting_Flag |
1288                                   SkScalerContext::kEmbeddedBitmapText_Flag |
1289                                   SkScalerContext::kEmbolden_Flag |
1290                                   SkScalerContext::kSubpixelPositioning_Flag |
1291                                   SkScalerContext::kLCD_BGROrder_Flag |
1292                                   SkScalerContext::kLCD_Vertical_Flag;
1293     rec->fFlags &= ~flagsWeDontSupport;
1294 
1295     SkPaint::Hinting h = rec->getHinting();
1296 
1297     // I think we can support no-hinting, if we get hires outlines and just
1298     // use skia to rasterize into a gray-scale mask...
1299 #if 0
1300     switch (h) {
1301         case SkPaint::kNo_Hinting:
1302         case SkPaint::kSlight_Hinting:
1303             h = SkPaint::kNo_Hinting;
1304             break;
1305         case SkPaint::kNormal_Hinting:
1306         case SkPaint::kFull_Hinting:
1307             h = SkPaint::kNormal_Hinting;
1308             break;
1309         default:
1310             SkDEBUGFAIL("unknown hinting");
1311     }
1312 #else
1313     h = SkPaint::kNormal_Hinting;
1314 #endif
1315     rec->setHinting(h);
1316 
1317     // for compatibility at the moment, discretize luminance to 3 settings
1318     // black, white, gray. This helps with fontcache utilization, since we
1319     // won't create multiple entries that in the end map to the same results.
1320     {
1321         unsigned lum = rec->getLuminanceByte();
1322         if (lum <= BLACK_LUMINANCE_LIMIT) {
1323             lum = 0;
1324         } else if (lum >= WHITE_LUMINANCE_LIMIT) {
1325             lum = SkScalerContext::kLuminance_Max;
1326         } else {
1327             lum = SkScalerContext::kLuminance_Max >> 1;
1328         }
1329         rec->setLuminanceBits(lum);
1330     }
1331 
1332 // turn this off since GDI might turn A8 into BW! Need a bigger fix.
1333 #if 0
1334     // Disable LCD when rotated, since GDI's output is ugly
1335     if (isLCD(*rec) && !isAxisAligned(*rec)) {
1336         rec->fMaskFormat = SkMask::kA8_Format;
1337     }
1338 #endif
1339 
1340 #if 0
1341     if (SkMask::kLCD16_Format == rec->fMaskFormat) {
1342         rec->fMaskFormat = SkMask::kLCD32_Format;
1343     }
1344 #endif
1345 }
1346 
1347 #endif // WIN32
1348