SkFontHost_win.cpp revision 5aa937b300475c956bfad0c34a6daa71d166f6fa
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 "SkString.h"
11#include "SkEndian.h"
12#include "SkFontHost.h"
13#include "SkDescriptor.h"
14#include "SkAdvancedTypefaceMetrics.h"
15#include "SkStream.h"
16#include "SkThread.h"
17#include "SkTypeface_win.h"
18#include "SkTypefaceCache.h"
19#include "SkUtils.h"
20
21#ifdef WIN32
22#include "windows.h"
23#include "tchar.h"
24#include "Usp10.h"
25
26// client3d has to undefine this for now
27#define CAN_USE_LOGFONT_NAME
28
29static bool isLCD(const SkScalerContext::Rec& rec) {
30    return SkMask::kLCD16_Format == rec.fMaskFormat ||
31           SkMask::kLCD32_Format == rec.fMaskFormat;
32}
33
34using namespace skia_advanced_typeface_metrics_utils;
35
36static const uint16_t BUFFERSIZE = (16384 - 32);
37static uint8_t glyphbuf[BUFFERSIZE];
38
39// Give 1MB font cache budget
40#define FONT_CACHE_MEMORY_BUDGET    (1024 * 1024)
41
42/**
43 *  Since LOGFONT wants its textsize as an int, and we support fractional sizes,
44 *  and since we have a cache of LOGFONTs for our tyepfaces, we always set the
45 *  lfHeight to a canonical size, and then we use the 2x2 matrix to achieve the
46 *  actual requested size.
47 */
48static const int gCanonicalTextSize = 64;
49
50static void make_canonical(LOGFONT* lf) {
51    lf->lfHeight = -gCanonicalTextSize;
52    lf->lfQuality = CLEARTYPE_QUALITY;//PROOF_QUALITY;
53    lf->lfCharSet = DEFAULT_CHARSET;
54//    lf->lfClipPrecision = 64;
55}
56
57static SkTypeface::Style getStyle(const LOGFONT& lf) {
58    unsigned style = 0;
59    if (lf.lfWeight >= FW_BOLD) {
60        style |= SkTypeface::kBold;
61    }
62    if (lf.lfItalic) {
63        style |= SkTypeface::kItalic;
64    }
65    return (SkTypeface::Style)style;
66}
67
68static void setStyle(LOGFONT* lf, SkTypeface::Style style) {
69    lf->lfWeight = (style & SkTypeface::kBold) != 0 ? FW_BOLD : FW_NORMAL ;
70    lf->lfItalic = ((style & SkTypeface::kItalic) != 0);
71}
72
73static inline FIXED SkFixedToFIXED(SkFixed x) {
74    return *(FIXED*)(&x);
75}
76
77static inline FIXED SkScalarToFIXED(SkScalar x) {
78    return SkFixedToFIXED(SkScalarToFixed(x));
79}
80
81static unsigned calculateGlyphCount(HDC hdc) {
82    // The 'maxp' table stores the number of glyphs at offset 4, in 2 bytes.
83    const DWORD maxpTag =
84        SkEndian_SwapBE32(SkSetFourByteTag('m', 'a', 'x', 'p'));
85    uint16_t glyphs;
86    if (GetFontData(hdc, maxpTag, 4, &glyphs, sizeof(glyphs)) != GDI_ERROR) {
87        return SkEndian_SwapBE16(glyphs);
88    }
89
90    // Binary search for glyph count.
91    static const MAT2 mat2 = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
92    int32_t max = SK_MaxU16 + 1;
93    int32_t min = 0;
94    GLYPHMETRICS gm;
95    while (min < max) {
96        int32_t mid = min + ((max - min) / 2);
97        if (GetGlyphOutlineW(hdc, mid, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0,
98                             NULL, &mat2) == GDI_ERROR) {
99            max = mid;
100        } else {
101            min = mid + 1;
102        }
103    }
104    SkASSERT(min == max);
105    return min;
106}
107
108static SkTypeface::Style GetFontStyle(const LOGFONT& lf) {
109    int style = SkTypeface::kNormal;
110    if (lf.lfWeight == FW_SEMIBOLD || lf.lfWeight == FW_DEMIBOLD || lf.lfWeight == FW_BOLD)
111        style |= SkTypeface::kBold;
112    if (lf.lfItalic)
113        style |= SkTypeface::kItalic;
114
115    return (SkTypeface::Style)style;
116}
117
118class LogFontTypeface : public SkTypeface {
119public:
120    LogFontTypeface(SkTypeface::Style style, SkFontID fontID, const LOGFONT& lf) :
121      SkTypeface(style, fontID, false), fLogFont(lf) {}
122
123    LOGFONT fLogFont;
124
125    static LogFontTypeface* Create(const LOGFONT& lf) {
126        SkTypeface::Style style = GetFontStyle(lf);
127        SkFontID fontID = SkTypefaceCache::NewFontID();
128        return new LogFontTypeface(style, fontID, lf);
129    }
130};
131
132static const LOGFONT& get_default_font() {
133    static LOGFONT gDefaultFont;
134    return gDefaultFont;
135}
136
137static bool FindByLogFont(SkTypeface* face, SkTypeface::Style requestedStyle, void* ctx) {
138    LogFontTypeface* lface = reinterpret_cast<LogFontTypeface*>(face);
139    const LOGFONT* lf = reinterpret_cast<const LOGFONT*>(ctx);
140
141    return getStyle(lface->fLogFont) == requestedStyle &&
142           !memcmp(&lface->fLogFont, lf, sizeof(LOGFONT));
143}
144
145/**
146 *  This guy is public. It first searches the cache, and if a match is not found,
147 *  it creates a new face.
148 */
149SkTypeface* SkCreateTypefaceFromLOGFONT(const LOGFONT& origLF) {
150    LOGFONT lf = origLF;
151    make_canonical(&lf);
152    SkTypeface* face = SkTypefaceCache::FindByProc(FindByLogFont, &lf);
153    if (face) {
154        face->ref();
155    } else {
156        face = LogFontTypeface::Create(lf);
157        SkTypefaceCache::Add(face, getStyle(lf));
158    }
159    return face;
160}
161
162/**
163 *  This guy is public
164 */
165void SkLOGFONTFromTypeface(const SkTypeface* face, LOGFONT* lf) {
166    if (NULL == face) {
167        *lf = get_default_font();
168    } else {
169        *lf = ((const LogFontTypeface*)face)->fLogFont;
170    }
171}
172
173SkFontID SkFontHost::NextLogicalFont(SkFontID currFontID, SkFontID origFontID) {
174  // Zero means that we don't have any fallback fonts for this fontID.
175  // This function is implemented on Android, but doesn't have much
176  // meaning here.
177  return 0;
178}
179
180static void GetLogFontByID(SkFontID fontID, LOGFONT* lf) {
181    LogFontTypeface* face = (LogFontTypeface*)SkTypefaceCache::FindByID(fontID);
182    if (face) {
183        *lf = face->fLogFont;
184    } else {
185        sk_bzero(lf, sizeof(LOGFONT));
186    }
187}
188
189// Construct Glyph to Unicode table.
190// Unicode code points that require conjugate pairs in utf16 are not
191// supported.
192// TODO(arthurhsu): Add support for conjugate pairs. It looks like that may
193// require parsing the TTF cmap table (platform 4, encoding 12) directly instead
194// of calling GetFontUnicodeRange().
195static void populate_glyph_to_unicode(HDC fontHdc, const unsigned glyphCount,
196                                      SkTDArray<SkUnichar>* glyphToUnicode) {
197    DWORD glyphSetBufferSize = GetFontUnicodeRanges(fontHdc, NULL);
198    if (!glyphSetBufferSize) {
199        return;
200    }
201
202    SkAutoTDeleteArray<BYTE> glyphSetBuffer(new BYTE[glyphSetBufferSize]);
203    GLYPHSET* glyphSet =
204        reinterpret_cast<LPGLYPHSET>(glyphSetBuffer.get());
205    if (GetFontUnicodeRanges(fontHdc, glyphSet) != glyphSetBufferSize) {
206        return;
207    }
208
209    glyphToUnicode->setCount(glyphCount);
210    memset(glyphToUnicode->begin(), 0, glyphCount * sizeof(SkUnichar));
211    for (DWORD i = 0; i < glyphSet->cRanges; ++i) {
212        // There is no guarantee that within a Unicode range, the corresponding
213        // glyph id in a font file are continuous. So, even if we have ranges,
214        // we can't just use the first and last entry of the range to compute
215        // result. We need to enumerate them one by one.
216        int count = glyphSet->ranges[i].cGlyphs;
217        SkAutoTArray<WCHAR> chars(count + 1);
218        chars[count] = 0;  // termintate string
219        SkAutoTArray<WORD> glyph(count);
220        for (USHORT j = 0; j < count; ++j) {
221            chars[j] = glyphSet->ranges[i].wcLow + j;
222        }
223        GetGlyphIndicesW(fontHdc, chars.get(), count, glyph.get(),
224                         GGI_MARK_NONEXISTING_GLYPHS);
225        // If the glyph ID is valid, and the glyph is not mapped, then we will
226        // fill in the char id into the vector. If the glyph is mapped already,
227        // skip it.
228        // TODO(arthurhsu): better improve this. e.g. Get all used char ids from
229        // font cache, then generate this mapping table from there. It's
230        // unlikely to have collisions since glyph reuse happens mostly for
231        // different Unicode pages.
232        for (USHORT j = 0; j < count; ++j) {
233            if (glyph[j] != 0xffff && glyph[j] < glyphCount &&
234                (*glyphToUnicode)[glyph[j]] == 0) {
235                (*glyphToUnicode)[glyph[j]] = chars[j];
236            }
237        }
238    }
239}
240
241//////////////////////////////////////////////////////////////////////////////////////////////
242
243class SkScalerContext_Windows : public SkScalerContext {
244public:
245    SkScalerContext_Windows(const SkDescriptor* desc);
246    virtual ~SkScalerContext_Windows();
247
248protected:
249    virtual unsigned generateGlyphCount();
250    virtual uint16_t generateCharToGlyph(SkUnichar uni);
251    virtual void generateAdvance(SkGlyph* glyph);
252    virtual void generateMetrics(SkGlyph* glyph);
253    virtual void generateImage(const SkGlyph& glyph);
254    virtual void generatePath(const SkGlyph& glyph, SkPath* path);
255    virtual void generateFontMetrics(SkPaint::FontMetrics* mX, SkPaint::FontMetrics* mY);
256    //virtual SkDeviceContext getDC() {return ddc;}
257private:
258    SkScalar     fScale;  // to get from canonical size to real size
259    MAT2         fMat22;
260    XFORM        fXform;
261    HDC          fDDC;
262    HFONT        fSavefont;
263    HFONT        fFont;
264    SCRIPT_CACHE fSC;
265    int          fGlyphCount;
266
267    HFONT        fHiResFont;
268    MAT2         fMat22Identity;
269    SkMatrix     fHiResMatrix;
270};
271
272static float mul2float(SkScalar a, SkScalar b) {
273    return SkScalarToFloat(SkScalarMul(a, b));
274}
275
276static FIXED float2FIXED(float x) {
277    return SkFixedToFIXED(SkFloatToFixed(x));
278}
279
280static SkMutex gFTMutex;
281
282#define HIRES_TEXTSIZE  2048
283#define HIRES_SHIFT     11
284static inline SkFixed HiResToFixed(int value) {
285    return value << (16 - HIRES_SHIFT);
286}
287
288static bool needHiResMetrics(const SkScalar mat[2][2]) {
289    return mat[1][0] || mat[0][1];
290}
291
292static BYTE compute_quality(const SkScalerContext::Rec& rec) {
293    switch (rec.fMaskFormat) {
294        case SkMask::kBW_Format:
295            return NONANTIALIASED_QUALITY;
296        case SkMask::kLCD16_Format:
297        case SkMask::kLCD32_Format:
298            return CLEARTYPE_QUALITY;
299        default:
300            return ANTIALIASED_QUALITY;
301    }
302}
303
304SkScalerContext_Windows::SkScalerContext_Windows(const SkDescriptor* desc)
305        : SkScalerContext(desc), fDDC(0), fFont(0), fSavefont(0), fSC(0)
306        , fGlyphCount(-1) {
307    SkAutoMutexAcquire  ac(gFTMutex);
308
309    fScale = fRec.fTextSize / gCanonicalTextSize;
310
311    fXform.eM11 = mul2float(fScale, fRec.fPost2x2[0][0]);
312    fXform.eM12 = mul2float(fScale, fRec.fPost2x2[1][0]);
313    fXform.eM21 = mul2float(fScale, fRec.fPost2x2[0][1]);
314    fXform.eM22 = mul2float(fScale, fRec.fPost2x2[1][1]);
315    fXform.eDx = 0;
316    fXform.eDy = 0;
317
318    fMat22.eM11 = float2FIXED(fXform.eM11);
319    fMat22.eM12 = float2FIXED(fXform.eM12);
320    fMat22.eM21 = float2FIXED(-fXform.eM21);
321    fMat22.eM22 = float2FIXED(-fXform.eM22);
322
323    fDDC = ::CreateCompatibleDC(NULL);
324    SetGraphicsMode(fDDC, GM_ADVANCED);
325    SetBkMode(fDDC, TRANSPARENT);
326
327    // Scaling by the DPI is inconsistent with how Skia draws elsewhere
328    //SkScalar height = -(fRec.fTextSize * GetDeviceCaps(ddc, LOGPIXELSY) / 72);
329    LOGFONT lf;
330    GetLogFontByID(fRec.fFontID, &lf);
331    lf.lfHeight = -gCanonicalTextSize;
332    lf.lfQuality = compute_quality(fRec);
333    fFont = CreateFontIndirect(&lf);
334
335    // if we're rotated, or want fractional widths, create a hires font
336    fHiResFont = 0;
337    if (needHiResMetrics(fRec.fPost2x2) || (fRec.fFlags & kSubpixelPositioning_Flag)) {
338        lf.lfHeight = -HIRES_TEXTSIZE;
339        fHiResFont = CreateFontIndirect(&lf);
340
341        fMat22Identity.eM11 = fMat22Identity.eM22 = SkFixedToFIXED(SK_Fixed1);
342        fMat22Identity.eM12 = fMat22Identity.eM21 = SkFixedToFIXED(0);
343
344        // construct a matrix to go from HIRES logical units to our device units
345        fRec.getSingleMatrix(&fHiResMatrix);
346        SkScalar scale = SkScalarInvert(SkIntToScalar(HIRES_TEXTSIZE));
347        fHiResMatrix.preScale(scale, scale);
348    }
349    fSavefont = (HFONT)SelectObject(fDDC, fFont);
350}
351
352SkScalerContext_Windows::~SkScalerContext_Windows() {
353    if (fDDC) {
354        ::SelectObject(fDDC, fSavefont);
355        ::DeleteDC(fDDC);
356    }
357    if (fFont) {
358        ::DeleteObject(fFont);
359    }
360    if (fHiResFont) {
361        ::DeleteObject(fHiResFont);
362    }
363    if (fSC) {
364        ::ScriptFreeCache(&fSC);
365    }
366}
367
368unsigned SkScalerContext_Windows::generateGlyphCount() {
369    if (fGlyphCount < 0) {
370        fGlyphCount = calculateGlyphCount(fDDC);
371    }
372    return fGlyphCount;
373}
374
375uint16_t SkScalerContext_Windows::generateCharToGlyph(SkUnichar uni) {
376    uint16_t index = 0;
377    WCHAR c[2];
378    // TODO(ctguil): Support characters that generate more than one glyph.
379    if (SkUTF16_FromUnichar(uni, (uint16_t*)c) == 1) {
380        // Type1 fonts fail with uniscribe API. Use GetGlyphIndices for plane 0.
381        SkAssertResult(GetGlyphIndicesW(fDDC, c, 1, &index, 0));
382    } else {
383        // Use uniscribe to detemine glyph index for non-BMP characters.
384        // Need to add extra item to SCRIPT_ITEM to work around a bug in older
385        // windows versions. https://bugzilla.mozilla.org/show_bug.cgi?id=366643
386        SCRIPT_ITEM si[2 + 1];
387        int items;
388        SkAssertResult(
389            SUCCEEDED(ScriptItemize(c, 2, 2, NULL, NULL, si, &items)));
390
391        WORD log[2];
392        SCRIPT_VISATTR vsa;
393        int glyphs;
394        SkAssertResult(SUCCEEDED(ScriptShape(
395            fDDC, &fSC, c, 2, 1, &si[0].a, &index, log, &vsa, &glyphs)));
396    }
397    return index;
398}
399
400void SkScalerContext_Windows::generateAdvance(SkGlyph* glyph) {
401    this->generateMetrics(glyph);
402}
403
404void SkScalerContext_Windows::generateMetrics(SkGlyph* glyph) {
405
406    SkASSERT(fDDC);
407
408    GLYPHMETRICS gm;
409    sk_bzero(&gm, sizeof(gm));
410
411    glyph->fRsbDelta = 0;
412    glyph->fLsbDelta = 0;
413
414    // Note: need to use GGO_GRAY8_BITMAP instead of GGO_METRICS because GGO_METRICS returns a smaller
415    // BlackBlox; we need the bigger one in case we need the image.  fAdvance is the same.
416    uint32_t ret = GetGlyphOutlineW(fDDC, glyph->getGlyphID(0), GGO_GRAY8_BITMAP | GGO_GLYPH_INDEX, &gm, 0, NULL, &fMat22);
417
418    if (GDI_ERROR != ret) {
419        if (ret == 0) {
420            // for white space, ret is zero and gmBlackBoxX, gmBlackBoxY are 1 incorrectly!
421            gm.gmBlackBoxX = gm.gmBlackBoxY = 0;
422        }
423        glyph->fWidth   = gm.gmBlackBoxX;
424        glyph->fHeight  = gm.gmBlackBoxY;
425        glyph->fTop     = SkToS16(gm.gmptGlyphOrigin.y - gm.gmBlackBoxY);
426        glyph->fLeft    = SkToS16(gm.gmptGlyphOrigin.x);
427        glyph->fAdvanceX = SkIntToFixed(gm.gmCellIncX);
428        glyph->fAdvanceY = -SkIntToFixed(gm.gmCellIncY);
429
430        // we outset by 1 in all dimensions, since the image may bleed outside
431        // of the computed bounds returned by GetGlyphOutline.
432        // This was deduced by trial and error for small text (e.g. 8pt), so there
433        // maybe a more precise way to make this adjustment...
434        glyph->fWidth += 2;
435        glyph->fHeight += 2;
436        glyph->fTop -= 1;
437        glyph->fLeft -= 1;
438
439        if (fHiResFont) {
440            SelectObject(fDDC, fHiResFont);
441            sk_bzero(&gm, sizeof(gm));
442            ret = GetGlyphOutlineW(fDDC, glyph->getGlyphID(0), GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &fMat22Identity);
443            if (GDI_ERROR != ret) {
444                SkPoint advance;
445                fHiResMatrix.mapXY(SkIntToScalar(gm.gmCellIncX), SkIntToScalar(gm.gmCellIncY), &advance);
446                glyph->fAdvanceX = SkScalarToFixed(advance.fX);
447                glyph->fAdvanceY = SkScalarToFixed(advance.fY);
448            }
449            SelectObject(fDDC, fFont);
450        }
451    } else {
452        glyph->fWidth = 0;
453    }
454}
455
456void SkScalerContext_Windows::generateFontMetrics(SkPaint::FontMetrics* mx, SkPaint::FontMetrics* my) {
457// Note: This code was borrowed from generateLineHeight, which has a note
458// stating that it may be incorrect.
459    if (!(mx || my))
460      return;
461
462    SkASSERT(fDDC);
463
464    OUTLINETEXTMETRIC otm;
465
466    uint32_t ret = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm);
467    if (sizeof(otm) != ret) {
468      return;
469    }
470
471    if (mx) {
472        mx->fTop = -fScale * otm.otmTextMetrics.tmAscent;
473        mx->fAscent = -fScale * otm.otmAscent;
474        mx->fDescent = -fScale * otm.otmDescent;
475        mx->fBottom = fScale * otm.otmTextMetrics.tmDescent;
476        mx->fLeading = fScale * (otm.otmTextMetrics.tmInternalLeading
477                                 + otm.otmTextMetrics.tmExternalLeading);
478    }
479
480    if (my) {
481        my->fTop = -fScale * otm.otmTextMetrics.tmAscent;
482        my->fAscent = -fScale * otm.otmAscent;
483        my->fDescent = -fScale * otm.otmDescent;
484        my->fBottom = fScale * otm.otmTextMetrics.tmDescent;
485        my->fLeading = fScale * (otm.otmTextMetrics.tmInternalLeading
486                                 + otm.otmTextMetrics.tmExternalLeading);
487    }
488}
489
490#include "SkColorPriv.h"
491
492static inline uint8_t rgb_to_a8(uint32_t rgb) {
493    // can pick any component, since we're grayscale
494    int r = (rgb >> 16) & 0xFF;
495    // invert, since we draw black-on-white, but we want the original
496    // src mask values.
497    return 255 - r;
498}
499
500static inline uint16_t rgb_to_lcd16(uint32_t rgb) {
501    int r = (rgb >> 16) & 0xFF;
502    int g = (rgb >>  8) & 0xFF;
503    int b = (rgb >>  0) & 0xFF;
504
505    // invert, since we draw black-on-white, but we want the original
506    // src mask values.
507    r = 255 - r;
508    g = 255 - g;
509    b = 255 - b;
510    return SkPackRGB16(SkR32ToR16(r), SkG32ToG16(g), SkB32ToB16(b));
511}
512
513static int alignTo32(int n) {
514    return (n + 31) & ~31;
515}
516
517struct MyBitmapInfo : public BITMAPINFO {
518    RGBQUAD fMoreSpaceForColors[1];
519};
520
521void SkScalerContext_Windows::generateImage(const SkGlyph& glyph) {
522
523    SkAutoMutexAcquire  ac(gFTMutex);
524
525    SkASSERT(fDDC);
526
527    const bool isBW = SkMask::kBW_Format == fRec.fMaskFormat;
528    const bool isAA = !isLCD(fRec);
529    HDC dc = CreateCompatibleDC(0);
530    void* bits = 0;
531    int biWidth = isBW ? alignTo32(glyph.fWidth) : glyph.fWidth;
532
533    MyBitmapInfo info;
534    sk_bzero(&info, sizeof(info));
535    if (isBW) {
536        RGBQUAD blackQuad = { 0, 0, 0, 0 };
537        RGBQUAD whiteQuad = { 0xFF, 0xFF, 0xFF, 0 };
538        info.bmiColors[0] = blackQuad;
539        info.bmiColors[1] = whiteQuad;
540    }
541    info.bmiHeader.biSize = sizeof(info.bmiHeader);
542    info.bmiHeader.biWidth = biWidth;
543    info.bmiHeader.biHeight = glyph.fHeight;
544    info.bmiHeader.biPlanes = 1;
545    info.bmiHeader.biBitCount = isBW ? 1 : 32;
546    info.bmiHeader.biCompression = BI_RGB;
547    if (isBW) {
548        info.bmiHeader.biClrUsed = 2;
549    }
550    HBITMAP bm = CreateDIBSection(dc, &info, DIB_RGB_COLORS, &bits, 0, 0);
551    SelectObject(dc, bm);
552
553    // erase to white
554    size_t srcRB = isBW ? (biWidth >> 3) : (glyph.fWidth << 2);
555    size_t size = glyph.fHeight * srcRB;
556    memset(bits, isBW ? 0 : 0xFF, size);
557
558    SetGraphicsMode(dc, GM_ADVANCED);
559    SetBkMode(dc, TRANSPARENT);
560    SetTextAlign(dc, TA_LEFT | TA_BASELINE);
561
562    XFORM xform = fXform;
563    xform.eDx = (float)-glyph.fLeft;
564    xform.eDy = (float)-glyph.fTop;
565    SetWorldTransform(dc, &xform);
566
567    HGDIOBJ prevFont = SelectObject(dc, fFont);
568    COLORREF color = SetTextColor(dc, isBW ? 0xFFFFFF : 0);
569    SkASSERT(color != CLR_INVALID);
570    uint16_t glyphID = glyph.getGlyphID();
571#if defined(UNICODE)
572    ExtTextOut(dc, 0, 0, ETO_GLYPH_INDEX, NULL, (LPCWSTR)&glyphID, 1, NULL);
573#else
574    ExtTextOut(dc, 0, 0, ETO_GLYPH_INDEX, NULL, (LPCSTR)&glyphID, 1, NULL);
575#endif
576    GdiFlush();
577
578    // downsample from rgba to rgb565
579    int width = glyph.fWidth;
580    size_t dstRB = glyph.rowBytes();
581    if (isBW) {
582        const uint8_t* src = (const uint8_t*)bits;
583        // gdi's bitmap is upside-down, so we reverse dst walking in Y
584        uint8_t* dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
585        for (int y = 0; y < glyph.fHeight; y++) {
586            memcpy(dst, src, dstRB);
587            src += srcRB;
588            dst -= dstRB;
589        }
590    } else if (isAA) {
591        const uint32_t* src = (const uint32_t*)bits;
592        // gdi's bitmap is upside-down, so we reverse dst walking in Y
593        uint8_t* dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
594        for (int y = 0; y < glyph.fHeight; y++) {
595            for (int i = 0; i < width; i++) {
596                dst[i] = rgb_to_a8(src[i]);
597            }
598            src = (const uint32_t*)((const char*)src + srcRB);
599            dst -= dstRB;
600        }
601    } else {    // LCD16
602        const uint32_t* src = (const uint32_t*)bits;
603        // gdi's bitmap is upside-down, so we reverse dst walking in Y
604        uint16_t* dst = (uint16_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
605        for (int y = 0; y < glyph.fHeight; y++) {
606            for (int i = 0; i < width; i++) {
607                dst[i] = rgb_to_lcd16(src[i]);
608            }
609            src = (const uint32_t*)((const char*)src + srcRB);
610            dst = (uint16_t*)((char*)dst - dstRB);
611        }
612    }
613
614    DeleteDC(dc);
615    DeleteObject(bm);
616}
617
618void SkScalerContext_Windows::generatePath(const SkGlyph& glyph, SkPath* path) {
619
620    SkAutoMutexAcquire  ac(gFTMutex);
621
622    SkASSERT(&glyph && path);
623    SkASSERT(fDDC);
624
625    path->reset();
626
627#if 0
628    char buf[1024];
629    sprintf(buf, "generatePath: id:%d, w=%d, h=%d, font:%s,fh:%d\n", glyph.fID, glyph.fWidth, glyph.fHeight, lf.lfFaceName, lf.lfHeight);
630    OutputDebugString(buf);
631#endif
632
633    GLYPHMETRICS gm;
634    uint32_t total_size = GetGlyphOutlineW(fDDC, glyph.fID, GGO_NATIVE | GGO_GLYPH_INDEX, &gm, BUFFERSIZE, glyphbuf, &fMat22);
635
636    if (GDI_ERROR != total_size) {
637
638        const uint8_t* cur_glyph = glyphbuf;
639        const uint8_t* end_glyph = glyphbuf + total_size;
640
641        while(cur_glyph < end_glyph) {
642            const TTPOLYGONHEADER* th = (TTPOLYGONHEADER*)cur_glyph;
643
644            const uint8_t* end_poly = cur_glyph + th->cb;
645            const uint8_t* cur_poly = cur_glyph + sizeof(TTPOLYGONHEADER);
646
647            path->moveTo(SkFixedToScalar(*(SkFixed*)(&th->pfxStart.x)), SkFixedToScalar(*(SkFixed*)(&th->pfxStart.y)));
648
649            while(cur_poly < end_poly) {
650                const TTPOLYCURVE* pc = (const TTPOLYCURVE*)cur_poly;
651
652                if (pc->wType == TT_PRIM_LINE) {
653                    for (uint16_t i = 0; i < pc->cpfx; i++) {
654                        path->lineTo(SkFixedToScalar(*(SkFixed*)(&pc->apfx[i].x)), SkFixedToScalar(*(SkFixed*)(&pc->apfx[i].y)));
655                    }
656                }
657
658                if (pc->wType == TT_PRIM_QSPLINE) {
659                    for (uint16_t u = 0; u < pc->cpfx - 1; u++) { // Walk through points in spline
660                        POINTFX pnt_b = pc->apfx[u];    // B is always the current point
661                        POINTFX pnt_c = pc->apfx[u+1];
662
663                        if (u < pc->cpfx - 2) {          // If not on last spline, compute C
664                            pnt_c.x = SkFixedToFIXED(SkFixedAve(*(SkFixed*)(&pnt_b.x), *(SkFixed*)(&pnt_c.x)));
665                            pnt_c.y = SkFixedToFIXED(SkFixedAve(*(SkFixed*)(&pnt_b.y), *(SkFixed*)(&pnt_c.y)));
666                        }
667
668                        path->quadTo(SkFixedToScalar(*(SkFixed*)(&pnt_b.x)), SkFixedToScalar(*(SkFixed*)(&pnt_b.y)), SkFixedToScalar(*(SkFixed*)(&pnt_c.x)), SkFixedToScalar(*(SkFixed*)(&pnt_c.y)));
669                    }
670                }
671                cur_poly += sizeof(uint16_t) * 2 + sizeof(POINTFX) * pc->cpfx;
672            }
673            cur_glyph += th->cb;
674            path->close();
675        }
676    }
677    else {
678        SkASSERT(false);
679    }
680    //char buf[1024];
681    //sprintf(buf, "generatePath: count:%d\n", count);
682    //OutputDebugString(buf);
683}
684
685void SkFontHost::Serialize(const SkTypeface* face, SkWStream* stream) {
686    SkASSERT(!"SkFontHost::Serialize unimplemented");
687}
688
689SkTypeface* SkFontHost::Deserialize(SkStream* stream) {
690    SkASSERT(!"SkFontHost::Deserialize unimplemented");
691    return NULL;
692}
693
694static bool getWidthAdvance(HDC hdc, int gId, int16_t* advance) {
695    // Initialize the MAT2 structure to the identify transformation matrix.
696    static const MAT2 mat2 = {SkScalarToFIXED(1), SkScalarToFIXED(0),
697                        SkScalarToFIXED(0), SkScalarToFIXED(1)};
698    int flags = GGO_METRICS | GGO_GLYPH_INDEX;
699    GLYPHMETRICS gm;
700    if (GDI_ERROR == GetGlyphOutline(hdc, gId, flags, &gm, 0, NULL, &mat2)) {
701        return false;
702    }
703    SkASSERT(advance);
704    *advance = gm.gmCellIncX;
705    return true;
706}
707
708// static
709SkAdvancedTypefaceMetrics* SkFontHost::GetAdvancedTypefaceMetrics(
710        uint32_t fontID,
711        SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo) {
712    LOGFONT lf;
713    GetLogFontByID(fontID, &lf);
714    SkAdvancedTypefaceMetrics* info = NULL;
715
716    HDC hdc = CreateCompatibleDC(NULL);
717    HFONT font = CreateFontIndirect(&lf);
718    HFONT savefont = (HFONT)SelectObject(hdc, font);
719    HFONT designFont = NULL;
720
721    // To request design units, create a logical font whose height is specified
722    // as unitsPerEm.
723    OUTLINETEXTMETRIC otm;
724    if (!GetOutlineTextMetrics(hdc, sizeof(otm), &otm) ||
725        !GetTextFace(hdc, LF_FACESIZE, lf.lfFaceName)) {
726        goto Error;
727    }
728    lf.lfHeight = -SkToS32(otm.otmEMSquare);
729    designFont = CreateFontIndirect(&lf);
730    SelectObject(hdc, designFont);
731    if (!GetOutlineTextMetrics(hdc, sizeof(otm), &otm)) {
732        goto Error;
733    }
734    const unsigned glyphCount = calculateGlyphCount(hdc);
735
736    info = new SkAdvancedTypefaceMetrics;
737    info->fEmSize = otm.otmEMSquare;
738    info->fMultiMaster = false;
739    info->fLastGlyphID = SkToU16(glyphCount - 1);
740    info->fStyle = 0;
741#ifdef UNICODE
742    // Get the buffer size needed first.
743    size_t str_len = WideCharToMultiByte(CP_UTF8, 0, lf.lfFaceName, -1, NULL,
744                                         0, NULL, NULL);
745    // Allocate a buffer (str_len already has terminating null accounted for).
746    char *familyName = new char[str_len];
747    // Now actually convert the string.
748    WideCharToMultiByte(CP_UTF8, 0, lf.lfFaceName, -1, familyName, str_len,
749                          NULL, NULL);
750    info->fFontName.set(familyName);
751    delete [] familyName;
752#else
753    info->fFontName.set(lf.lfFaceName);
754#endif
755
756    if (perGlyphInfo & SkAdvancedTypefaceMetrics::kToUnicode_PerGlyphInfo) {
757        populate_glyph_to_unicode(hdc, glyphCount, &(info->fGlyphToUnicode));
758    }
759
760    if (otm.otmTextMetrics.tmPitchAndFamily & TMPF_TRUETYPE) {
761        info->fType = SkAdvancedTypefaceMetrics::kTrueType_Font;
762    } else {
763        info->fType = SkAdvancedTypefaceMetrics::kOther_Font;
764        info->fItalicAngle = 0;
765        info->fAscent = 0;
766        info->fDescent = 0;
767        info->fStemV = 0;
768        info->fCapHeight = 0;
769        info->fBBox = SkIRect::MakeEmpty();
770        return info;
771    }
772
773    // If this bit is clear the font is a fixed pitch font.
774    if (!(otm.otmTextMetrics.tmPitchAndFamily & TMPF_FIXED_PITCH)) {
775        info->fStyle |= SkAdvancedTypefaceMetrics::kFixedPitch_Style;
776    }
777    if (otm.otmTextMetrics.tmItalic) {
778        info->fStyle |= SkAdvancedTypefaceMetrics::kItalic_Style;
779    }
780    // Setting symbolic style by default for now.
781    info->fStyle |= SkAdvancedTypefaceMetrics::kSymbolic_Style;
782    if (otm.otmTextMetrics.tmPitchAndFamily & FF_ROMAN) {
783        info->fStyle |= SkAdvancedTypefaceMetrics::kSerif_Style;
784    } else if (otm.otmTextMetrics.tmPitchAndFamily & FF_SCRIPT) {
785            info->fStyle |= SkAdvancedTypefaceMetrics::kScript_Style;
786    }
787
788    // The main italic angle of the font, in tenths of a degree counterclockwise
789    // from vertical.
790    info->fItalicAngle = otm.otmItalicAngle / 10;
791    info->fAscent = SkToS16(otm.otmTextMetrics.tmAscent);
792    info->fDescent = SkToS16(-otm.otmTextMetrics.tmDescent);
793    // TODO(ctguil): Use alternate cap height calculation.
794    // MSDN says otmsCapEmHeight is not support but it is returning a value on
795    // my Win7 box.
796    info->fCapHeight = otm.otmsCapEmHeight;
797    info->fBBox =
798        SkIRect::MakeLTRB(otm.otmrcFontBox.left, otm.otmrcFontBox.top,
799                          otm.otmrcFontBox.right, otm.otmrcFontBox.bottom);
800
801    // Figure out a good guess for StemV - Min width of i, I, !, 1.
802    // This probably isn't very good with an italic font.
803    int16_t min_width = SHRT_MAX;
804    info->fStemV = 0;
805    char stem_chars[] = {'i', 'I', '!', '1'};
806    for (size_t i = 0; i < SK_ARRAY_COUNT(stem_chars); i++) {
807        ABC abcWidths;
808        if (GetCharABCWidths(hdc, stem_chars[i], stem_chars[i], &abcWidths)) {
809            int16_t width = abcWidths.abcB;
810            if (width > 0 && width < min_width) {
811                min_width = width;
812                info->fStemV = min_width;
813            }
814        }
815    }
816
817    // If bit 1 is set, the font may not be embedded in a document.
818    // If bit 1 is clear, the font can be embedded.
819    // If bit 2 is set, the embedding is read-only.
820    if (otm.otmfsType & 0x1) {
821        info->fType = SkAdvancedTypefaceMetrics::kNotEmbeddable_Font;
822    } else if (perGlyphInfo &
823               SkAdvancedTypefaceMetrics::kHAdvance_PerGlyphInfo) {
824        if (info->fStyle & SkAdvancedTypefaceMetrics::kFixedPitch_Style) {
825            appendRange(&info->fGlyphWidths, 0);
826            info->fGlyphWidths->fAdvance.append(1, &min_width);
827            finishRange(info->fGlyphWidths.get(), 0,
828                        SkAdvancedTypefaceMetrics::WidthRange::kDefault);
829        } else {
830            info->fGlyphWidths.reset(
831                getAdvanceData(hdc, glyphCount, &getWidthAdvance));
832        }
833    }
834
835Error:
836    SelectObject(hdc, savefont);
837    DeleteObject(designFont);
838    DeleteObject(font);
839    DeleteDC(hdc);
840
841    return info;
842}
843
844SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) {
845
846    //Should not be used on Windows, keep linker happy
847    SkASSERT(false);
848    return SkCreateTypefaceFromLOGFONT(get_default_font());
849}
850
851SkStream* SkFontHost::OpenStream(SkFontID uniqueID) {
852    const DWORD kTTCTag =
853        SkEndian_SwapBE32(SkSetFourByteTag('t', 't', 'c', 'f'));
854    LOGFONT lf;
855    GetLogFontByID(uniqueID, &lf);
856
857    HDC hdc = ::CreateCompatibleDC(NULL);
858    HFONT font = CreateFontIndirect(&lf);
859    HFONT savefont = (HFONT)SelectObject(hdc, font);
860
861    SkMemoryStream* stream = NULL;
862    DWORD tables[2] = {kTTCTag, 0};
863    for (int i = 0; i < SK_ARRAY_COUNT(tables); i++) {
864        size_t bufferSize = GetFontData(hdc, tables[i], 0, NULL, 0);
865        if (bufferSize != GDI_ERROR) {
866            stream = new SkMemoryStream(bufferSize);
867            if (GetFontData(hdc, tables[i], 0, (void*)stream->getMemoryBase(),
868                            bufferSize)) {
869                break;
870            } else {
871                delete stream;
872                stream = NULL;
873            }
874        }
875    }
876
877    SelectObject(hdc, savefont);
878    DeleteObject(font);
879    DeleteDC(hdc);
880
881    return stream;
882}
883
884SkScalerContext* SkFontHost::CreateScalerContext(const SkDescriptor* desc) {
885    return SkNEW_ARGS(SkScalerContext_Windows, (desc));
886}
887
888/** Return the closest matching typeface given either an existing family
889 (specified by a typeface in that family) or by a familyName, and a
890 requested style.
891 1) If familyFace is null, use famillyName.
892 2) If famillyName is null, use familyFace.
893 3) If both are null, return the default font that best matches style
894 This MUST not return NULL.
895 */
896
897SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace,
898                                       const char familyName[],
899                                       const void* data, size_t bytelength,
900                                       SkTypeface::Style style) {
901    LOGFONT lf;
902    if (NULL == familyFace && NULL == familyName) {
903        lf = get_default_font();
904    } else if (familyFace) {
905        LogFontTypeface* face = (LogFontTypeface*)familyFace;
906        lf = face->fLogFont;
907    } else {
908        memset(&lf, 0, sizeof(LOGFONT));
909#ifdef UNICODE
910        // Get the buffer size needed first.
911        size_t str_len = ::MultiByteToWideChar(CP_UTF8, 0, familyName,
912                                                -1, NULL, 0);
913        // Allocate a buffer (str_len already has terminating null
914        // accounted for).
915        wchar_t *wideFamilyName = new wchar_t[str_len];
916        // Now actually convert the string.
917        ::MultiByteToWideChar(CP_UTF8, 0, familyName, -1,
918                                wideFamilyName, str_len);
919        ::wcsncpy(lf.lfFaceName, wideFamilyName, LF_FACESIZE);
920        delete [] wideFamilyName;
921#else
922        ::strncpy(lf.lfFaceName, familyName, LF_FACESIZE);
923#endif
924        lf.lfFaceName[LF_FACESIZE-1] = '\0';
925    }
926    setStyle(&lf, style);
927    return SkCreateTypefaceFromLOGFONT(lf);
928}
929
930size_t SkFontHost::ShouldPurgeFontCache(size_t sizeAllocatedSoFar) {
931    if (sizeAllocatedSoFar > FONT_CACHE_MEMORY_BUDGET)
932        return sizeAllocatedSoFar - FONT_CACHE_MEMORY_BUDGET;
933    else
934        return 0;   // nothing to do
935}
936
937int SkFontHost::ComputeGammaFlag(const SkPaint& paint) {
938    return 0;
939}
940
941void SkFontHost::GetGammaTables(const uint8_t* tables[2]) {
942    tables[0] = NULL;   // black gamma (e.g. exp=1.4)
943    tables[1] = NULL;   // white gamma (e.g. exp= 1/1.4)
944}
945
946SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) {
947    printf("SkFontHost::CreateTypefaceFromFile unimplemented");
948    return NULL;
949}
950
951static bool bothZero(SkScalar a, SkScalar b) {
952    return 0 == a && 0 == b;
953}
954
955// returns false if there is any non-90-rotation or skew
956static bool isAxisAligned(const SkScalerContext::Rec& rec) {
957    return 0 == rec.fPreSkewX &&
958           (bothZero(rec.fPost2x2[0][1], rec.fPost2x2[1][0]) ||
959            bothZero(rec.fPost2x2[0][0], rec.fPost2x2[1][1]));
960}
961
962void SkFontHost::FilterRec(SkScalerContext::Rec* rec) {
963    unsigned flagsWeDontSupport = SkScalerContext::kDevKernText_Flag |
964                                  SkScalerContext::kAutohinting_Flag |
965                                  SkScalerContext::kEmbeddedBitmapText_Flag |
966                                  SkScalerContext::kEmbolden_Flag |
967                                  SkScalerContext::kLCD_BGROrder_Flag |
968                                  SkScalerContext::kLCD_Vertical_Flag;
969    rec->fFlags &= ~flagsWeDontSupport;
970
971    SkPaint::Hinting h = rec->getHinting();
972
973    // I think we can support no-hinting, if we get hires outlines and just
974    // use skia to rasterize into a gray-scale mask...
975#if 0
976    switch (h) {
977        case SkPaint::kNo_Hinting:
978        case SkPaint::kSlight_Hinting:
979            h = SkPaint::kNo_Hinting;
980            break;
981        case SkPaint::kNormal_Hinting:
982        case SkPaint::kFull_Hinting:
983            h = SkPaint::kNormal_Hinting;
984            break;
985        default:
986            SkASSERT(!"unknown hinting");
987    }
988#else
989    h = SkPaint::kNormal_Hinting;
990#endif
991    rec->setHinting(h);
992
993    // Disable LCD when rotated, since GDI's output is ugly
994    if (isLCD(*rec) && !isAxisAligned(*rec)) {
995        rec->fMaskFormat = SkMask::kA8_Format;
996    }
997}
998
999#endif // WIN32
1000