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