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