SkFontHost_win.cpp revision 97efada074e4806479f1350ab1508939c2fdcb53
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#include "SkAdvancedTypefaceMetrics.h"
10#include "SkBase64.h"
11#include "SkData.h"
12#include "SkDescriptor.h"
13#include "SkFontDescriptor.h"
14#include "SkFontHost.h"
15#include "SkGlyph.h"
16#include "SkMaskGamma.h"
17#include "SkOTUtils.h"
18#include "SkStream.h"
19#include "SkString.h"
20#include "SkThread.h"
21#include "SkTypeface_win.h"
22#include "SkTypefaceCache.h"
23#include "SkUtils.h"
24
25#include "SkTypes.h"
26#include <tchar.h>
27#include <usp10.h>
28#include <objbase.h>
29
30static bool compute_bounds_outset(const LOGFONT& lf, SkIRect* outset) {
31
32    static const struct {
33        const char* fUCName;    // UTF8 encoded, ascii is upper-case
34        SkIRect     fOutset;    // these are deltas for the glyph's bounds
35    } gData[] = {
36        // http://code.google.com/p/chromium/issues/detail?id=130842
37        { "DOTUM", { 0, 0, 0, 1 } },
38        { "DOTUMCHE", { 0, 0, 0, 1 } },
39        { "\xEB\x8F\x8B\xEC\x9B\x80", { 0, 0, 0, 1 } },
40        { "\xEB\x8F\x8B\xEC\x9B\x80\xEC\xB2\xB4", { 0, 0, 0, 1 } },
41        { "MS UI GOTHIC", { 1, 0, 0, 0 } },
42    };
43
44    /**
45     *  We convert the target name into upper-case (for ascii chars) UTF8.
46     *  Our database is already stored in this fashion, and it allows us to
47     *  search it with straight memcmp, since everyone is in this canonical
48     *  form.
49     */
50
51    // temp storage is max # TCHARs * max expantion for UTF8 + null
52    char name[kMaxBytesInUTF8Sequence * LF_FACESIZE + 1];
53    int index = 0;
54    for (int i = 0; i < LF_FACESIZE; ++i) {
55        uint16_t c = lf.lfFaceName[i];
56        if (c >= 'a' && c <= 'z') {
57            c = c - 'a' + 'A';
58        }
59        size_t n = SkUTF16_ToUTF8(&c, 1, &name[index]);
60        index += n;
61        if (0 == c) {
62            break;
63        }
64    }
65
66    for (size_t j = 0; j < SK_ARRAY_COUNT(gData); ++j) {
67        if (!strcmp(gData[j].fUCName, name)) {
68            *outset = gData[j].fOutset;
69            return true;
70        }
71    }
72    return false;
73}
74
75// outset isn't really a rect, but 4 (non-negative) values to outset the
76// glyph's metrics by. For "normal" fonts, all these values should be 0.
77static void apply_outset(SkGlyph* glyph, const SkIRect& outset) {
78    SkASSERT(outset.fLeft >= 0);
79    SkASSERT(outset.fTop >= 0);
80    SkASSERT(outset.fRight >= 0);
81    SkASSERT(outset.fBottom >= 0);
82
83    glyph->fLeft -= outset.fLeft;
84    glyph->fTop -= outset.fTop;
85    glyph->fWidth += outset.fLeft + outset.fRight;
86    glyph->fHeight += outset.fTop + outset.fBottom;
87}
88
89// always packed xxRRGGBB
90typedef uint32_t SkGdiRGB;
91
92template <typename T> T* SkTAddByteOffset(T* ptr, size_t byteOffset) {
93    return (T*)((char*)ptr + byteOffset);
94}
95
96// define this in your Makefile or .gyp to enforce AA requests
97// which GDI ignores at small sizes. This flag guarantees AA
98// for rotated text, regardless of GDI's notions.
99//#define SK_ENFORCE_ROTATED_TEXT_AA_ON_WINDOWS
100
101// client3d has to undefine this for now
102#define CAN_USE_LOGFONT_NAME
103
104static bool isLCD(const SkScalerContext::Rec& rec) {
105    return SkMask::kLCD16_Format == rec.fMaskFormat ||
106           SkMask::kLCD32_Format == rec.fMaskFormat;
107}
108
109static bool bothZero(SkScalar a, SkScalar b) {
110    return 0 == a && 0 == b;
111}
112
113// returns false if there is any non-90-rotation or skew
114static bool isAxisAligned(const SkScalerContext::Rec& rec) {
115    return 0 == rec.fPreSkewX &&
116           (bothZero(rec.fPost2x2[0][1], rec.fPost2x2[1][0]) ||
117            bothZero(rec.fPost2x2[0][0], rec.fPost2x2[1][1]));
118}
119
120static bool needToRenderWithSkia(const SkScalerContext::Rec& rec) {
121#ifdef SK_ENFORCE_ROTATED_TEXT_AA_ON_WINDOWS
122    // What we really want to catch is when GDI will ignore the AA request and give
123    // us BW instead. Smallish rotated text is one heuristic, so this code is just
124    // an approximation. We shouldn't need to do this for larger sizes, but at those
125    // sizes, the quality difference gets less and less between our general
126    // scanconverter and GDI's.
127    if (SkMask::kA8_Format == rec.fMaskFormat && !isAxisAligned(rec)) {
128        return true;
129    }
130#endif
131    // false means allow GDI to generate the bits
132    return false;
133}
134
135using namespace skia_advanced_typeface_metrics_utils;
136
137static const uint16_t BUFFERSIZE = (16384 - 32);
138static uint8_t glyphbuf[BUFFERSIZE];
139
140/**
141 *  Since LOGFONT wants its textsize as an int, and we support fractional sizes,
142 *  and since we have a cache of LOGFONTs for our tyepfaces, we always set the
143 *  lfHeight to a canonical size, and then we use the 2x2 matrix to achieve the
144 *  actual requested size.
145 */
146static const int gCanonicalTextSize = 64;
147
148static void make_canonical(LOGFONT* lf) {
149    lf->lfHeight = -gCanonicalTextSize;
150    lf->lfQuality = CLEARTYPE_QUALITY;//PROOF_QUALITY;
151    lf->lfCharSet = DEFAULT_CHARSET;
152//    lf->lfClipPrecision = 64;
153}
154
155static SkTypeface::Style get_style(const LOGFONT& lf) {
156    unsigned style = 0;
157    if (lf.lfWeight >= FW_BOLD) {
158        style |= SkTypeface::kBold;
159    }
160    if (lf.lfItalic) {
161        style |= SkTypeface::kItalic;
162    }
163    return static_cast<SkTypeface::Style>(style);
164}
165
166static void setStyle(LOGFONT* lf, SkTypeface::Style style) {
167    lf->lfWeight = (style & SkTypeface::kBold) != 0 ? FW_BOLD : FW_NORMAL ;
168    lf->lfItalic = ((style & SkTypeface::kItalic) != 0);
169}
170
171static inline FIXED SkFixedToFIXED(SkFixed x) {
172    return *(FIXED*)(&x);
173}
174static inline SkFixed SkFIXEDToFixed(FIXED x) {
175    return *(SkFixed*)(&x);
176}
177
178static inline FIXED SkScalarToFIXED(SkScalar x) {
179    return SkFixedToFIXED(SkScalarToFixed(x));
180}
181
182static unsigned calculateOutlineGlyphCount(HDC hdc) {
183    // The 'maxp' table stores the number of glyphs at offset 4, in 2 bytes.
184    const DWORD maxpTag =
185        SkEndian_SwapBE32(SkSetFourByteTag('m', 'a', 'x', 'p'));
186    uint16_t glyphs;
187    if (GetFontData(hdc, maxpTag, 4, &glyphs, sizeof(glyphs)) != GDI_ERROR) {
188        return SkEndian_SwapBE16(glyphs);
189    }
190
191    // Binary search for glyph count.
192    static const MAT2 mat2 = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
193    int32_t max = SK_MaxU16 + 1;
194    int32_t min = 0;
195    GLYPHMETRICS gm;
196    while (min < max) {
197        int32_t mid = min + ((max - min) / 2);
198        if (GetGlyphOutlineW(hdc, mid, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0,
199                             NULL, &mat2) == GDI_ERROR) {
200            max = mid;
201        } else {
202            min = mid + 1;
203        }
204    }
205    SkASSERT(min == max);
206    return min;
207}
208
209class LogFontTypeface : public SkTypeface {
210public:
211    LogFontTypeface(SkTypeface::Style style, SkFontID fontID, const LOGFONT& lf) :
212      SkTypeface(style, fontID, false), fLogFont(lf), fSerializeAsStream(false) {}
213
214    LOGFONT fLogFont;
215    bool fSerializeAsStream;
216
217    static LogFontTypeface* Create(const LOGFONT& lf) {
218        SkTypeface::Style style = get_style(lf);
219        SkFontID fontID = SkTypefaceCache::NewFontID();
220        return new LogFontTypeface(style, fontID, lf);
221    }
222};
223
224class FontMemResourceTypeface : public LogFontTypeface {
225public:
226    /**
227     *  Takes ownership of fontMemResource.
228     */
229    FontMemResourceTypeface(SkTypeface::Style style, SkFontID fontID, const LOGFONT& lf, HANDLE fontMemResource) :
230      LogFontTypeface(style, fontID, lf), fFontMemResource(fontMemResource) {
231      fSerializeAsStream = true;
232    }
233
234    HANDLE fFontMemResource;
235
236    /**
237     *  The created FontMemResourceTypeface takes ownership of fontMemResource.
238     */
239    static FontMemResourceTypeface* Create(const LOGFONT& lf, HANDLE fontMemResource) {
240        SkTypeface::Style style = get_style(lf);
241        SkFontID fontID = SkTypefaceCache::NewFontID();
242        return new FontMemResourceTypeface(style, fontID, lf, fontMemResource);
243    }
244
245protected:
246    virtual void weak_dispose() const SK_OVERRIDE {
247        RemoveFontMemResourceEx(fFontMemResource);
248        //SkTypefaceCache::Remove(this);
249        INHERITED::weak_dispose();
250    }
251
252private:
253    typedef LogFontTypeface INHERITED;
254};
255
256static const LOGFONT& get_default_font() {
257    static LOGFONT gDefaultFont;
258    return gDefaultFont;
259}
260
261static bool FindByLogFont(SkTypeface* face, SkTypeface::Style requestedStyle, void* ctx) {
262    LogFontTypeface* lface = static_cast<LogFontTypeface*>(face);
263    const LOGFONT* lf = reinterpret_cast<const LOGFONT*>(ctx);
264
265    return lface &&
266           get_style(lface->fLogFont) == requestedStyle &&
267           !memcmp(&lface->fLogFont, lf, sizeof(LOGFONT));
268}
269
270/**
271 *  This guy is public. It first searches the cache, and if a match is not found,
272 *  it creates a new face.
273 */
274SkTypeface* SkCreateTypefaceFromLOGFONT(const LOGFONT& origLF) {
275    LOGFONT lf = origLF;
276    make_canonical(&lf);
277    SkTypeface* face = SkTypefaceCache::FindByProcAndRef(FindByLogFont, &lf);
278    if (NULL == face) {
279        face = LogFontTypeface::Create(lf);
280        SkTypefaceCache::Add(face, get_style(lf));
281    }
282    return face;
283}
284
285/**
286 *  The created SkTypeface takes ownership of fontMemResource.
287 */
288SkTypeface* SkCreateFontMemResourceTypefaceFromLOGFONT(const LOGFONT& origLF, HANDLE fontMemResource) {
289    LOGFONT lf = origLF;
290    make_canonical(&lf);
291    FontMemResourceTypeface* face = FontMemResourceTypeface::Create(lf, fontMemResource);
292    SkTypefaceCache::Add(face, get_style(lf), false);
293    return face;
294}
295
296/**
297 *  This guy is public
298 */
299void SkLOGFONTFromTypeface(const SkTypeface* face, LOGFONT* lf) {
300    if (NULL == face) {
301        *lf = get_default_font();
302    } else {
303        *lf = static_cast<const LogFontTypeface*>(face)->fLogFont;
304    }
305}
306
307SkFontID SkFontHost::NextLogicalFont(SkFontID currFontID, SkFontID origFontID) {
308  // Zero means that we don't have any fallback fonts for this fontID.
309  // This function is implemented on Android, but doesn't have much
310  // meaning here.
311  return 0;
312}
313
314static void ensure_typeface_accessible(SkFontID fontID) {
315    LogFontTypeface* face = static_cast<LogFontTypeface*>(SkTypefaceCache::FindByID(fontID));
316    if (face) {
317        SkFontHost::EnsureTypefaceAccessible(*face);
318    }
319}
320
321static void GetLogFontByID(SkFontID fontID, LOGFONT* lf) {
322    LogFontTypeface* face = static_cast<LogFontTypeface*>(SkTypefaceCache::FindByID(fontID));
323    if (face) {
324        *lf = face->fLogFont;
325    } else {
326        sk_bzero(lf, sizeof(LOGFONT));
327    }
328}
329
330// Construct Glyph to Unicode table.
331// Unicode code points that require conjugate pairs in utf16 are not
332// supported.
333// TODO(arthurhsu): Add support for conjugate pairs. It looks like that may
334// require parsing the TTF cmap table (platform 4, encoding 12) directly instead
335// of calling GetFontUnicodeRange().
336static void populate_glyph_to_unicode(HDC fontHdc, const unsigned glyphCount,
337                                      SkTDArray<SkUnichar>* glyphToUnicode) {
338    DWORD glyphSetBufferSize = GetFontUnicodeRanges(fontHdc, NULL);
339    if (!glyphSetBufferSize) {
340        return;
341    }
342
343    SkAutoTDeleteArray<BYTE> glyphSetBuffer(new BYTE[glyphSetBufferSize]);
344    GLYPHSET* glyphSet =
345        reinterpret_cast<LPGLYPHSET>(glyphSetBuffer.get());
346    if (GetFontUnicodeRanges(fontHdc, glyphSet) != glyphSetBufferSize) {
347        return;
348    }
349
350    glyphToUnicode->setCount(glyphCount);
351    memset(glyphToUnicode->begin(), 0, glyphCount * sizeof(SkUnichar));
352    for (DWORD i = 0; i < glyphSet->cRanges; ++i) {
353        // There is no guarantee that within a Unicode range, the corresponding
354        // glyph id in a font file are continuous. So, even if we have ranges,
355        // we can't just use the first and last entry of the range to compute
356        // result. We need to enumerate them one by one.
357        int count = glyphSet->ranges[i].cGlyphs;
358        SkAutoTArray<WCHAR> chars(count + 1);
359        chars[count] = 0;  // termintate string
360        SkAutoTArray<WORD> glyph(count);
361        for (USHORT j = 0; j < count; ++j) {
362            chars[j] = glyphSet->ranges[i].wcLow + j;
363        }
364        GetGlyphIndicesW(fontHdc, chars.get(), count, glyph.get(),
365                         GGI_MARK_NONEXISTING_GLYPHS);
366        // If the glyph ID is valid, and the glyph is not mapped, then we will
367        // fill in the char id into the vector. If the glyph is mapped already,
368        // skip it.
369        // TODO(arthurhsu): better improve this. e.g. Get all used char ids from
370        // font cache, then generate this mapping table from there. It's
371        // unlikely to have collisions since glyph reuse happens mostly for
372        // different Unicode pages.
373        for (USHORT j = 0; j < count; ++j) {
374            if (glyph[j] != 0xffff && glyph[j] < glyphCount &&
375                (*glyphToUnicode)[glyph[j]] == 0) {
376                (*glyphToUnicode)[glyph[j]] = chars[j];
377            }
378        }
379    }
380}
381
382//////////////////////////////////////////////////////////////////////////////////////
383
384static int alignTo32(int n) {
385    return (n + 31) & ~31;
386}
387
388struct MyBitmapInfo : public BITMAPINFO {
389    RGBQUAD fMoreSpaceForColors[1];
390};
391
392class HDCOffscreen {
393public:
394    HDCOffscreen() {
395        fFont = 0;
396        fDC = 0;
397        fBM = 0;
398        fBits = NULL;
399        fWidth = fHeight = 0;
400        fIsBW = false;
401    }
402
403    ~HDCOffscreen() {
404        if (fDC) {
405            DeleteDC(fDC);
406        }
407        if (fBM) {
408            DeleteObject(fBM);
409        }
410    }
411
412    void init(HFONT font, const XFORM& xform) {
413        fFont = font;
414        fXform = xform;
415    }
416
417    const void* draw(const SkGlyph&, bool isBW, size_t* srcRBPtr);
418
419private:
420    HDC     fDC;
421    HBITMAP fBM;
422    HFONT   fFont;
423    XFORM   fXform;
424    void*   fBits;  // points into fBM
425    int     fWidth;
426    int     fHeight;
427    bool    fIsBW;
428
429    enum {
430        // will always trigger us to reset the color, since we
431        // should only store 0 or 0x00FFFFFF or gray (0x007F7F7F)
432        kInvalid_Color = 12345
433    };
434};
435
436const void* HDCOffscreen::draw(const SkGlyph& glyph, bool isBW,
437                               size_t* srcRBPtr) {
438    if (0 == fDC) {
439        fDC = CreateCompatibleDC(0);
440        if (0 == fDC) {
441            return NULL;
442        }
443        SetGraphicsMode(fDC, GM_ADVANCED);
444        SetBkMode(fDC, TRANSPARENT);
445        SetTextAlign(fDC, TA_LEFT | TA_BASELINE);
446        SelectObject(fDC, fFont);
447
448        COLORREF color = 0x00FFFFFF;
449        COLORREF prev = SetTextColor(fDC, color);
450        SkASSERT(prev != CLR_INVALID);
451    }
452
453    if (fBM && (fIsBW != isBW || fWidth < glyph.fWidth || fHeight < glyph.fHeight)) {
454        DeleteObject(fBM);
455        fBM = 0;
456    }
457    fIsBW = isBW;
458
459    fWidth = SkMax32(fWidth, glyph.fWidth);
460    fHeight = SkMax32(fHeight, glyph.fHeight);
461
462    int biWidth = isBW ? alignTo32(fWidth) : fWidth;
463
464    if (0 == fBM) {
465        MyBitmapInfo info;
466        sk_bzero(&info, sizeof(info));
467        if (isBW) {
468            RGBQUAD blackQuad = { 0, 0, 0, 0 };
469            RGBQUAD whiteQuad = { 0xFF, 0xFF, 0xFF, 0 };
470            info.bmiColors[0] = blackQuad;
471            info.bmiColors[1] = whiteQuad;
472        }
473        info.bmiHeader.biSize = sizeof(info.bmiHeader);
474        info.bmiHeader.biWidth = biWidth;
475        info.bmiHeader.biHeight = fHeight;
476        info.bmiHeader.biPlanes = 1;
477        info.bmiHeader.biBitCount = isBW ? 1 : 32;
478        info.bmiHeader.biCompression = BI_RGB;
479        if (isBW) {
480            info.bmiHeader.biClrUsed = 2;
481        }
482        fBM = CreateDIBSection(fDC, &info, DIB_RGB_COLORS, &fBits, 0, 0);
483        if (0 == fBM) {
484            return NULL;
485        }
486        SelectObject(fDC, fBM);
487    }
488
489    // erase
490    size_t srcRB = isBW ? (biWidth >> 3) : (fWidth << 2);
491    size_t size = fHeight * srcRB;
492    memset(fBits, 0, size);
493
494    XFORM xform = fXform;
495    xform.eDx = (float)-glyph.fLeft;
496    xform.eDy = (float)-glyph.fTop;
497    SetWorldTransform(fDC, &xform);
498
499    uint16_t glyphID = glyph.getGlyphID();
500    BOOL ret = ExtTextOutW(fDC, 0, 0, ETO_GLYPH_INDEX, NULL, reinterpret_cast<LPCWSTR>(&glyphID), 1, NULL);
501    GdiFlush();
502    if (0 == ret) {
503        return NULL;
504    }
505    *srcRBPtr = srcRB;
506    // offset to the start of the image
507    return (const char*)fBits + (fHeight - glyph.fHeight) * srcRB;
508}
509
510//////////////////////////////////////////////////////////////////////////////
511
512class SkScalerContext_Windows : public SkScalerContext {
513public:
514    SkScalerContext_Windows(const SkDescriptor* desc);
515    virtual ~SkScalerContext_Windows();
516
517protected:
518    virtual unsigned generateGlyphCount() SK_OVERRIDE;
519    virtual uint16_t generateCharToGlyph(SkUnichar uni) SK_OVERRIDE;
520    virtual void generateAdvance(SkGlyph* glyph) SK_OVERRIDE;
521    virtual void generateMetrics(SkGlyph* glyph) SK_OVERRIDE;
522    virtual void generateImage(const SkGlyph& glyph, SkMaskGamma::PreBlend* maskPreBlend) SK_OVERRIDE;
523    virtual void generatePath(const SkGlyph& glyph, SkPath* path) SK_OVERRIDE;
524    virtual void generateFontMetrics(SkPaint::FontMetrics* mX, SkPaint::FontMetrics* mY) SK_OVERRIDE;
525
526private:
527    HDCOffscreen fOffscreen;
528    SkScalar     fScale;  // to get from canonical size to real size
529    MAT2         fMat22;
530    XFORM        fXform;
531    HDC          fDDC;
532    HFONT        fSavefont;
533    HFONT        fFont;
534    SCRIPT_CACHE fSC;
535    int          fGlyphCount;
536
537    /**
538     *  Some fonts need extra pixels added to avoid clipping, as the bounds
539     *  returned by getOutlineMetrics does not match what GDI draws. Since
540     *  this costs more RAM and therefore slower blits, we have a table to
541     *  only do this for known "bad" fonts.
542     */
543    SkIRect      fOutset;
544
545    HFONT        fHiResFont;
546    MAT2         fMat22Identity;
547    SkMatrix     fHiResMatrix;
548    enum Type {
549        kTrueType_Type, kBitmap_Type,
550    } fType;
551    TEXTMETRIC fTM;
552};
553
554static float mul2float(SkScalar a, SkScalar b) {
555    return SkScalarToFloat(SkScalarMul(a, b));
556}
557
558static FIXED float2FIXED(float x) {
559    return SkFixedToFIXED(SkFloatToFixed(x));
560}
561
562SK_DECLARE_STATIC_MUTEX(gFTMutex);
563
564#define HIRES_TEXTSIZE  2048
565#define HIRES_SHIFT     11
566static inline SkFixed HiResToFixed(int value) {
567    return value << (16 - HIRES_SHIFT);
568}
569
570static bool needHiResMetrics(const SkScalar mat[2][2]) {
571    return mat[1][0] || mat[0][1];
572}
573
574static BYTE compute_quality(const SkScalerContext::Rec& rec) {
575    switch (rec.fMaskFormat) {
576        case SkMask::kBW_Format:
577            return NONANTIALIASED_QUALITY;
578        case SkMask::kLCD16_Format:
579        case SkMask::kLCD32_Format:
580            return CLEARTYPE_QUALITY;
581        default:
582            if (rec.fFlags & SkScalerContext::kGenA8FromLCD_Flag) {
583                return CLEARTYPE_QUALITY;
584            } else {
585                return ANTIALIASED_QUALITY;
586            }
587    }
588}
589
590SkScalerContext_Windows::SkScalerContext_Windows(const SkDescriptor* desc)
591        : SkScalerContext(desc), fDDC(0), fFont(0), fSavefont(0), fSC(0)
592        , fGlyphCount(-1) {
593    SkAutoMutexAcquire  ac(gFTMutex);
594
595    fDDC = ::CreateCompatibleDC(NULL);
596    SetGraphicsMode(fDDC, GM_ADVANCED);
597    SetBkMode(fDDC, TRANSPARENT);
598
599    // Scaling by the DPI is inconsistent with how Skia draws elsewhere
600    //SkScalar height = -(fRec.fTextSize * GetDeviceCaps(ddc, LOGPIXELSY) / 72);
601    LOGFONT lf;
602    GetLogFontByID(fRec.fFontID, &lf);
603    lf.lfHeight = -gCanonicalTextSize;
604    lf.lfQuality = compute_quality(fRec);
605    fFont = CreateFontIndirect(&lf);
606
607    if (!compute_bounds_outset(lf, &fOutset)) {
608        fOutset.setEmpty();
609    }
610
611    // if we're rotated, or want fractional widths, create a hires font
612    fHiResFont = 0;
613    if (needHiResMetrics(fRec.fPost2x2)) {
614        lf.lfHeight = -HIRES_TEXTSIZE;
615        fHiResFont = CreateFontIndirect(&lf);
616
617        fMat22Identity.eM11 = fMat22Identity.eM22 = SkFixedToFIXED(SK_Fixed1);
618        fMat22Identity.eM12 = fMat22Identity.eM21 = SkFixedToFIXED(0);
619
620        // construct a matrix to go from HIRES logical units to our device units
621        fRec.getSingleMatrix(&fHiResMatrix);
622        SkScalar scale = SkScalarInvert(SkIntToScalar(HIRES_TEXTSIZE));
623        fHiResMatrix.preScale(scale, scale);
624    }
625    fSavefont = (HFONT)SelectObject(fDDC, fFont);
626
627    if (0 == GetTextMetrics(fDDC, &fTM)) {
628        ensure_typeface_accessible(fRec.fFontID);
629        if (0 == GetTextMetrics(fDDC, &fTM)) {
630            fTM.tmPitchAndFamily = TMPF_TRUETYPE;
631        }
632    }
633    // Used a logfont on a memory context, should never get a device font.
634    // Therefore all TMPF_DEVICE will be PostScript fonts.
635
636    // If TMPF_VECTOR is set, one of TMPF_TRUETYPE or TMPF_DEVICE must be set,
637    // otherwise we have a vector FON, which we don't support.
638    // This was determined by testing with Type1 PFM/PFB and OpenTypeCFF OTF,
639    // as well as looking at Wine bugs and sources.
640    SkASSERT(!(fTM.tmPitchAndFamily & TMPF_VECTOR) ||
641              (fTM.tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_DEVICE)));
642
643    if (fTM.tmPitchAndFamily & TMPF_VECTOR) {
644        // Truetype or PostScript.
645        // Stroked FON also gets here (TMPF_VECTOR), but we don't handle it.
646        fType = SkScalerContext_Windows::kTrueType_Type;
647        fScale = fRec.fTextSize / gCanonicalTextSize;
648
649        fXform.eM11 = mul2float(fScale, fRec.fPost2x2[0][0]);
650        fXform.eM12 = mul2float(fScale, fRec.fPost2x2[1][0]);
651        fXform.eM21 = mul2float(fScale, fRec.fPost2x2[0][1]);
652        fXform.eM22 = mul2float(fScale, fRec.fPost2x2[1][1]);
653        fXform.eDx = 0;
654        fXform.eDy = 0;
655
656        fMat22.eM11 = float2FIXED(fXform.eM11);
657        fMat22.eM12 = float2FIXED(fXform.eM12);
658        fMat22.eM21 = float2FIXED(-fXform.eM21);
659        fMat22.eM22 = float2FIXED(-fXform.eM22);
660
661        if (needToRenderWithSkia(fRec)) {
662            this->forceGenerateImageFromPath();
663        }
664
665    } else {
666        // Assume bitmap
667        fType = SkScalerContext_Windows::kBitmap_Type;
668        fScale = SK_Scalar1;
669
670        fXform.eM11 = 1.0f;
671        fXform.eM12 = 0.0f;
672        fXform.eM21 = 0.0f;
673        fXform.eM22 = 1.0f;
674        fXform.eDx = 0.0f;
675        fXform.eDy = 0.0f;
676
677        fMat22.eM11 = SkScalarToFIXED(fRec.fPost2x2[0][0]);
678        fMat22.eM12 = SkScalarToFIXED(fRec.fPost2x2[1][0]);
679        fMat22.eM21 = SkScalarToFIXED(-fRec.fPost2x2[0][1]);
680        fMat22.eM22 = SkScalarToFIXED(-fRec.fPost2x2[1][1]);
681
682        lf.lfHeight = -SkScalarCeilToInt(fRec.fTextSize);
683        HFONT bitmapFont = CreateFontIndirect(&lf);
684        SelectObject(fDDC, bitmapFont);
685        ::DeleteObject(fFont);
686        fFont = bitmapFont;
687
688        if (0 == GetTextMetrics(fDDC, &fTM)) {
689            ensure_typeface_accessible(fRec.fFontID);
690            //if the following fails, we'll just draw at gCanonicalTextSize.
691            GetTextMetrics(fDDC, &fTM);
692        }
693    }
694
695    fOffscreen.init(fFont, fXform);
696}
697
698SkScalerContext_Windows::~SkScalerContext_Windows() {
699    if (fDDC) {
700        ::SelectObject(fDDC, fSavefont);
701        ::DeleteDC(fDDC);
702    }
703    if (fFont) {
704        ::DeleteObject(fFont);
705    }
706    if (fHiResFont) {
707        ::DeleteObject(fHiResFont);
708    }
709    if (fSC) {
710        ::ScriptFreeCache(&fSC);
711    }
712}
713
714unsigned SkScalerContext_Windows::generateGlyphCount() {
715    if (fGlyphCount < 0) {
716        if (fType == SkScalerContext_Windows::kBitmap_Type) {
717           return fTM.tmLastChar;
718        }
719        fGlyphCount = calculateOutlineGlyphCount(fDDC);
720    }
721    return fGlyphCount;
722}
723
724uint16_t SkScalerContext_Windows::generateCharToGlyph(SkUnichar uni) {
725    uint16_t index = 0;
726    WCHAR c[2];
727    // TODO(ctguil): Support characters that generate more than one glyph.
728    if (SkUTF16_FromUnichar(uni, (uint16_t*)c) == 1) {
729        // Type1 fonts fail with uniscribe API. Use GetGlyphIndices for plane 0.
730        SkAssertResult(GetGlyphIndicesW(fDDC, c, 1, &index, 0));
731    } else {
732        // Use uniscribe to detemine glyph index for non-BMP characters.
733        // Need to add extra item to SCRIPT_ITEM to work around a bug in older
734        // windows versions. https://bugzilla.mozilla.org/show_bug.cgi?id=366643
735        SCRIPT_ITEM si[2 + 1];
736        int items;
737        SkAssertResult(
738            SUCCEEDED(ScriptItemize(c, 2, 2, NULL, NULL, si, &items)));
739
740        WORD log[2];
741        SCRIPT_VISATTR vsa;
742        int glyphs;
743        SkAssertResult(SUCCEEDED(ScriptShape(
744            fDDC, &fSC, c, 2, 1, &si[0].a, &index, log, &vsa, &glyphs)));
745    }
746    return index;
747}
748
749void SkScalerContext_Windows::generateAdvance(SkGlyph* glyph) {
750    this->generateMetrics(glyph);
751}
752
753void SkScalerContext_Windows::generateMetrics(SkGlyph* glyph) {
754
755    SkASSERT(fDDC);
756
757    if (fType == SkScalerContext_Windows::kBitmap_Type) {
758        SIZE size;
759        WORD glyphs = glyph->getGlyphID(0);
760        if (0 == GetTextExtentPointI(fDDC, &glyphs, 1, &size)) {
761            glyph->fWidth = SkToS16(fTM.tmMaxCharWidth);
762        } else {
763            glyph->fWidth = SkToS16(size.cx);
764        }
765        glyph->fHeight = SkToS16(size.cy);
766
767        glyph->fTop = SkToS16(-fTM.tmAscent);
768        glyph->fLeft = SkToS16(0);
769        glyph->fAdvanceX = SkIntToFixed(glyph->fWidth);
770        glyph->fAdvanceY = 0;
771
772        //Apply matrix to values.
773        glyph->fAdvanceY = SkFixedMul(SkFIXEDToFixed(fMat22.eM21), glyph->fAdvanceX);
774        glyph->fAdvanceX = SkFixedMul(SkFIXEDToFixed(fMat22.eM11), glyph->fAdvanceX);
775
776        apply_outset(glyph, fOutset);
777        return;
778    }
779
780    GLYPHMETRICS gm;
781    sk_bzero(&gm, sizeof(gm));
782
783    glyph->fRsbDelta = 0;
784    glyph->fLsbDelta = 0;
785
786    // Note: need to use GGO_GRAY8_BITMAP instead of GGO_METRICS because GGO_METRICS returns a smaller
787    // BlackBlox; we need the bigger one in case we need the image.  fAdvance is the same.
788    uint32_t ret = GetGlyphOutlineW(fDDC, glyph->getGlyphID(0), GGO_GRAY8_BITMAP | GGO_GLYPH_INDEX, &gm, 0, NULL, &fMat22);
789    if (GDI_ERROR == ret) {
790        ensure_typeface_accessible(fRec.fFontID);
791        ret = GetGlyphOutlineW(fDDC, glyph->getGlyphID(0), GGO_GRAY8_BITMAP | GGO_GLYPH_INDEX, &gm, 0, NULL, &fMat22);
792    }
793
794    if (GDI_ERROR != ret) {
795        if (ret == 0) {
796            // for white space, ret is zero and gmBlackBoxX, gmBlackBoxY are 1 incorrectly!
797            gm.gmBlackBoxX = gm.gmBlackBoxY = 0;
798        }
799        glyph->fWidth   = gm.gmBlackBoxX;
800        glyph->fHeight  = gm.gmBlackBoxY;
801        glyph->fTop     = SkToS16(gm.gmptGlyphOrigin.y - gm.gmBlackBoxY);
802        glyph->fLeft    = SkToS16(gm.gmptGlyphOrigin.x);
803        glyph->fAdvanceX = SkIntToFixed(gm.gmCellIncX);
804        glyph->fAdvanceY = -SkIntToFixed(gm.gmCellIncY);
805
806        // we outset in all dimensions, since the image may bleed outside
807        // of the computed bounds returned by GetGlyphOutline.
808        // This was deduced by trial and error for small text (e.g. 8pt), so there
809        // maybe a more precise way to make this adjustment...
810        //
811        // This test shows us clipping the tops of some of the CJK fonts unless we
812        // increase the top of the box by 2, hence the height by 4. This seems to
813        // correspond to an embedded bitmap font, but not sure.
814        //     LayoutTests/fast/text/backslash-to-yen-sign-euc.html
815        //
816        if (glyph->fWidth) {    // don't outset an empty glyph
817            glyph->fWidth += 4;
818            glyph->fHeight += 4;
819            glyph->fTop -= 2;
820            glyph->fLeft -= 2;
821
822            apply_outset(glyph, fOutset);
823        }
824
825        if (fHiResFont) {
826            SelectObject(fDDC, fHiResFont);
827            sk_bzero(&gm, sizeof(gm));
828            ret = GetGlyphOutlineW(fDDC, glyph->getGlyphID(0), GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &fMat22Identity);
829            if (GDI_ERROR != ret) {
830                SkPoint advance;
831                fHiResMatrix.mapXY(SkIntToScalar(gm.gmCellIncX), SkIntToScalar(gm.gmCellIncY), &advance);
832                glyph->fAdvanceX = SkScalarToFixed(advance.fX);
833                glyph->fAdvanceY = SkScalarToFixed(advance.fY);
834            }
835            SelectObject(fDDC, fFont);
836        }
837    } else {
838        glyph->zeroMetrics();
839    }
840}
841
842void SkScalerContext_Windows::generateFontMetrics(SkPaint::FontMetrics* mx, SkPaint::FontMetrics* my) {
843// Note: This code was borrowed from generateLineHeight, which has a note
844// stating that it may be incorrect.
845    if (!(mx || my))
846      return;
847
848    SkASSERT(fDDC);
849
850    if (fType == SkScalerContext_Windows::kBitmap_Type) {
851        if (mx) {
852            mx->fTop = SkIntToScalar(-fTM.tmAscent);
853            mx->fAscent = SkIntToScalar(-fTM.tmAscent);
854            mx->fDescent = -SkIntToScalar(fTM.tmDescent);
855            mx->fBottom = SkIntToScalar(fTM.tmDescent);
856            mx->fLeading = SkIntToScalar(fTM.tmInternalLeading
857                                         + fTM.tmExternalLeading);
858        }
859
860        if (my) {
861            my->fTop = SkIntToScalar(-fTM.tmAscent);
862            my->fAscent = SkIntToScalar(-fTM.tmAscent);
863            my->fDescent = SkIntToScalar(-fTM.tmDescent);
864            my->fBottom = SkIntToScalar(fTM.tmDescent);
865            my->fLeading = SkIntToScalar(fTM.tmInternalLeading
866                                         + fTM.tmExternalLeading);
867        }
868        return;
869    }
870
871    OUTLINETEXTMETRIC otm;
872
873    uint32_t ret = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm);
874    if (GDI_ERROR == ret) {
875        ensure_typeface_accessible(fRec.fFontID);
876        ret = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm);
877    }
878    if (sizeof(otm) != ret) {
879        return;
880    }
881
882    if (mx) {
883        mx->fTop = -fScale * otm.otmTextMetrics.tmAscent;
884        mx->fAscent = -fScale * otm.otmAscent;
885        mx->fDescent = -fScale * otm.otmDescent;
886        mx->fBottom = fScale * otm.otmTextMetrics.tmDescent;
887        mx->fLeading = fScale * (otm.otmTextMetrics.tmInternalLeading
888                                 + otm.otmTextMetrics.tmExternalLeading);
889    }
890
891    if (my) {
892        my->fTop = -fScale * otm.otmTextMetrics.tmAscent;
893        my->fAscent = -fScale * otm.otmAscent;
894        my->fDescent = -fScale * otm.otmDescent;
895        my->fBottom = fScale * otm.otmTextMetrics.tmDescent;
896        my->fLeading = fScale * (otm.otmTextMetrics.tmInternalLeading
897                                 + otm.otmTextMetrics.tmExternalLeading);
898    }
899}
900
901////////////////////////////////////////////////////////////////////////////////////////
902
903static void build_power_table(uint8_t table[], float ee) {
904    for (int i = 0; i < 256; i++) {
905        float x = i / 255.f;
906        x = sk_float_pow(x, ee);
907        int xx = SkScalarRound(SkFloatToScalar(x * 255));
908        table[i] = SkToU8(xx);
909    }
910}
911
912/**
913 *  This will invert the gamma applied by GDI (gray-scale antialiased), so we
914 *  can get linear values.
915 *
916 *  GDI grayscale appears to use a hard-coded gamma of 2.3.
917 *
918 *  GDI grayscale appears to draw using the black and white rasterizer at four
919 *  times the size and then downsamples to compute the coverage mask. As a
920 *  result there are only seventeen total grays. This lack of fidelity means
921 *  that shifting into other color spaces is imprecise.
922 */
923static const uint8_t* getInverseGammaTableGDI() {
924    static bool gInited;
925    static uint8_t gTableGdi[256];
926    if (!gInited) {
927        build_power_table(gTableGdi, 2.3f);
928        gInited = true;
929    }
930    return gTableGdi;
931}
932
933/**
934 *  This will invert the gamma applied by GDI ClearType, so we can get linear
935 *  values.
936 *
937 *  GDI ClearType uses SPI_GETFONTSMOOTHINGCONTRAST / 1000 as the gamma value.
938 *  If this value is not specified, the default is a gamma of 1.4.
939 */
940static const uint8_t* getInverseGammaTableClearType() {
941    static bool gInited;
942    static uint8_t gTableClearType[256];
943    if (!gInited) {
944        UINT level = 0;
945        if (!SystemParametersInfo(SPI_GETFONTSMOOTHINGCONTRAST, 0, &level, 0) || !level) {
946            // can't get the data, so use a default
947            level = 1400;
948        }
949        build_power_table(gTableClearType, level / 1000.0f);
950        gInited = true;
951    }
952    return gTableClearType;
953}
954
955#include "SkColorPriv.h"
956
957template<bool APPLY_PREBLEND>
958static inline uint8_t rgb_to_a8(SkGdiRGB rgb, const uint8_t* table8) {
959    SkASSERT( ((rgb >> 16) & 0xFF) == ((rgb >> 8) & 0xFF) &&
960              ((rgb >> 16) & 0xFF) == ((rgb >> 0) & 0xFF) );
961    return sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 16) & 0xFF, table8);
962}
963
964template<bool APPLY_PREBLEND>
965static inline uint16_t rgb_to_lcd16(SkGdiRGB rgb, const uint8_t* tableR,
966                                                  const uint8_t* tableG,
967                                                  const uint8_t* tableB) {
968    U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 16) & 0xFF, tableR);
969    U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>((rgb >>  8) & 0xFF, tableG);
970    U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>((rgb >>  0) & 0xFF, tableB);
971    return SkPack888ToRGB16(r, g, b);
972}
973
974template<bool APPLY_PREBLEND>
975static inline SkPMColor rgb_to_lcd32(SkGdiRGB rgb, const uint8_t* tableR,
976                                                   const uint8_t* tableG,
977                                                   const uint8_t* tableB) {
978    U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 16) & 0xFF, tableR);
979    U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>((rgb >>  8) & 0xFF, tableG);
980    U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>((rgb >>  0) & 0xFF, tableB);
981    return SkPackARGB32(0xFF, r, g, b);
982}
983
984// Is this GDI color neither black nor white? If so, we have to keep this
985// image as is, rather than smashing it down to a BW mask.
986//
987// returns int instead of bool, since we don't want/have to pay to convert
988// the zero/non-zero value into a bool
989static int is_not_black_or_white(SkGdiRGB c) {
990    // same as (but faster than)
991    //      c &= 0x00FFFFFF;
992    //      return 0 == c || 0x00FFFFFF == c;
993    return (c + (c & 1)) & 0x00FFFFFF;
994}
995
996static bool is_rgb_really_bw(const SkGdiRGB* src, int width, int height, int srcRB) {
997    for (int y = 0; y < height; ++y) {
998        for (int x = 0; x < width; ++x) {
999            if (is_not_black_or_white(src[x])) {
1000                return false;
1001            }
1002        }
1003        src = SkTAddByteOffset(src, srcRB);
1004    }
1005    return true;
1006}
1007
1008// gdi's bitmap is upside-down, so we reverse dst walking in Y
1009// whenever we copy it into skia's buffer
1010static void rgb_to_bw(const SkGdiRGB* SK_RESTRICT src, size_t srcRB,
1011                      const SkGlyph& glyph) {
1012    const int width = glyph.fWidth;
1013    const size_t dstRB = (width + 7) >> 3;
1014    uint8_t* SK_RESTRICT dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
1015
1016    int byteCount = width >> 3;
1017    int bitCount = width & 7;
1018
1019    // adjust srcRB to skip the values in our byteCount loop,
1020    // since we increment src locally there
1021    srcRB -= byteCount * 8 * sizeof(SkGdiRGB);
1022
1023    for (int y = 0; y < glyph.fHeight; ++y) {
1024        if (byteCount > 0) {
1025            for (int i = 0; i < byteCount; ++i) {
1026                unsigned byte = 0;
1027                byte |= src[0] & (1 << 7);
1028                byte |= src[1] & (1 << 6);
1029                byte |= src[2] & (1 << 5);
1030                byte |= src[3] & (1 << 4);
1031                byte |= src[4] & (1 << 3);
1032                byte |= src[5] & (1 << 2);
1033                byte |= src[6] & (1 << 1);
1034                byte |= src[7] & (1 << 0);
1035                dst[i] = byte;
1036                src += 8;
1037            }
1038        }
1039        if (bitCount > 0) {
1040            unsigned byte = 0;
1041            unsigned mask = 0x80;
1042            for (int i = 0; i < bitCount; i++) {
1043                byte |= src[i] & mask;
1044                mask >>= 1;
1045            }
1046            dst[byteCount] = byte;
1047        }
1048        src = SkTAddByteOffset(src, srcRB);
1049        dst -= dstRB;
1050    }
1051}
1052
1053template<bool APPLY_PREBLEND>
1054static void rgb_to_a8(const SkGdiRGB* SK_RESTRICT src, size_t srcRB,
1055                      const SkGlyph& glyph, const uint8_t* table8) {
1056    const size_t dstRB = glyph.rowBytes();
1057    const int width = glyph.fWidth;
1058    uint8_t* SK_RESTRICT dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
1059
1060    for (int y = 0; y < glyph.fHeight; y++) {
1061        for (int i = 0; i < width; i++) {
1062            dst[i] = rgb_to_a8<APPLY_PREBLEND>(src[i], table8);
1063        }
1064        src = SkTAddByteOffset(src, srcRB);
1065        dst -= dstRB;
1066    }
1067}
1068
1069template<bool APPLY_PREBLEND>
1070static void rgb_to_lcd16(const SkGdiRGB* SK_RESTRICT src, size_t srcRB, const SkGlyph& glyph,
1071                         const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) {
1072    const size_t dstRB = glyph.rowBytes();
1073    const int width = glyph.fWidth;
1074    uint16_t* SK_RESTRICT dst = (uint16_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
1075
1076    for (int y = 0; y < glyph.fHeight; y++) {
1077        for (int i = 0; i < width; i++) {
1078            dst[i] = rgb_to_lcd16<APPLY_PREBLEND>(src[i], tableR, tableG, tableB);
1079        }
1080        src = SkTAddByteOffset(src, srcRB);
1081        dst = (uint16_t*)((char*)dst - dstRB);
1082    }
1083}
1084
1085template<bool APPLY_PREBLEND>
1086static void rgb_to_lcd32(const SkGdiRGB* SK_RESTRICT src, size_t srcRB, const SkGlyph& glyph,
1087                         const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) {
1088    const size_t dstRB = glyph.rowBytes();
1089    const int width = glyph.fWidth;
1090    uint32_t* SK_RESTRICT dst = (uint32_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
1091
1092    for (int y = 0; y < glyph.fHeight; y++) {
1093        for (int i = 0; i < width; i++) {
1094            dst[i] = rgb_to_lcd32<APPLY_PREBLEND>(src[i], tableR, tableG, tableB);
1095        }
1096        src = SkTAddByteOffset(src, srcRB);
1097        dst = (uint32_t*)((char*)dst - dstRB);
1098    }
1099}
1100
1101static inline unsigned clamp255(unsigned x) {
1102    SkASSERT(x <= 256);
1103    return x - (x >> 8);
1104}
1105
1106void SkScalerContext_Windows::generateImage(const SkGlyph& glyph, SkMaskGamma::PreBlend* maskPreBlend) {
1107    SkAutoMutexAcquire ac(gFTMutex);
1108    SkASSERT(fDDC);
1109
1110    //Must be careful not to use these if maskPreBlend == NULL
1111    const uint8_t* tableR = NULL;
1112    const uint8_t* tableG = NULL;
1113    const uint8_t* tableB = NULL;
1114    if (maskPreBlend) {
1115        tableR = maskPreBlend->fR;
1116        tableG = maskPreBlend->fG;
1117        tableB = maskPreBlend->fB;
1118    }
1119
1120    const bool isBW = SkMask::kBW_Format == fRec.fMaskFormat;
1121    const bool isAA = !isLCD(fRec);
1122
1123    size_t srcRB;
1124    const void* bits = fOffscreen.draw(glyph, isBW, &srcRB);
1125    if (NULL == bits) {
1126        ensure_typeface_accessible(fRec.fFontID);
1127        bits = fOffscreen.draw(glyph, isBW, &srcRB);
1128        if (NULL == bits) {
1129            sk_bzero(glyph.fImage, glyph.computeImageSize());
1130            return;
1131        }
1132    }
1133
1134    if (!isBW) {
1135        const uint8_t* table = getInverseGammaTableClearType();
1136        if (isAA) {
1137          table = getInverseGammaTableGDI();
1138        }
1139        //Note that the following cannot really be integrated into the
1140        //pre-blend, since we may not be applying the pre-blend; when we aren't
1141        //applying the pre-blend it means that a filter wants linear anyway.
1142        //Other code may also be applying the pre-blend, so we'd need another
1143        //one with this and one without.
1144        SkGdiRGB* addr = (SkGdiRGB*)bits;
1145        for (int y = 0; y < glyph.fHeight; ++y) {
1146            for (int x = 0; x < glyph.fWidth; ++x) {
1147                int r = (addr[x] >> 16) & 0xFF;
1148                int g = (addr[x] >>  8) & 0xFF;
1149                int b = (addr[x] >>  0) & 0xFF;
1150                addr[x] = (table[r] << 16) | (table[g] << 8) | table[b];
1151            }
1152            addr = SkTAddByteOffset(addr, srcRB);
1153        }
1154    }
1155
1156    int width = glyph.fWidth;
1157    size_t dstRB = glyph.rowBytes();
1158    if (isBW) {
1159        const uint8_t* src = (const uint8_t*)bits;
1160        uint8_t* dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
1161        for (int y = 0; y < glyph.fHeight; y++) {
1162            memcpy(dst, src, dstRB);
1163            src += srcRB;
1164            dst -= dstRB;
1165        }
1166    } else if (isAA) {
1167        // since the caller may require A8 for maskfilters, we can't check for BW
1168        // ... until we have the caller tell us that explicitly
1169        const SkGdiRGB* src = (const SkGdiRGB*)bits;
1170        if (maskPreBlend) {
1171            rgb_to_a8<true>(src, srcRB, glyph, tableG);
1172        } else {
1173            rgb_to_a8<false>(src, srcRB, glyph, tableG);
1174        }
1175    } else {    // LCD16
1176        const SkGdiRGB* src = (const SkGdiRGB*)bits;
1177        if (is_rgb_really_bw(src, width, glyph.fHeight, srcRB)) {
1178            rgb_to_bw(src, srcRB, glyph);
1179            ((SkGlyph*)&glyph)->fMaskFormat = SkMask::kBW_Format;
1180        } else {
1181            if (SkMask::kLCD16_Format == glyph.fMaskFormat) {
1182                if (maskPreBlend) {
1183                    rgb_to_lcd16<true>(src, srcRB, glyph, tableR, tableG, tableB);
1184                } else {
1185                    rgb_to_lcd16<false>(src, srcRB, glyph, tableR, tableG, tableB);
1186                }
1187            } else {
1188                SkASSERT(SkMask::kLCD32_Format == glyph.fMaskFormat);
1189                if (maskPreBlend) {
1190                    rgb_to_lcd32<true>(src, srcRB, glyph, tableR, tableG, tableB);
1191                } else {
1192                    rgb_to_lcd32<false>(src, srcRB, glyph, tableR, tableG, tableB);
1193                }
1194            }
1195        }
1196    }
1197}
1198
1199void SkScalerContext_Windows::generatePath(const SkGlyph& glyph, SkPath* path) {
1200
1201    SkAutoMutexAcquire  ac(gFTMutex);
1202
1203    SkASSERT(&glyph && path);
1204    SkASSERT(fDDC);
1205
1206    path->reset();
1207
1208#if 0
1209    char buf[1024];
1210    sprintf(buf, "generatePath: id:%d, w=%d, h=%d, font:%s,fh:%d\n", glyph.fID, glyph.fWidth, glyph.fHeight, lf.lfFaceName, lf.lfHeight);
1211    OutputDebugString(buf);
1212#endif
1213
1214    GLYPHMETRICS gm;
1215    uint32_t total_size = GetGlyphOutlineW(fDDC, glyph.fID, GGO_NATIVE | GGO_GLYPH_INDEX, &gm, BUFFERSIZE, glyphbuf, &fMat22);
1216    if (GDI_ERROR == total_size) {
1217        ensure_typeface_accessible(fRec.fFontID);
1218        total_size = GetGlyphOutlineW(fDDC, glyph.fID, GGO_NATIVE | GGO_GLYPH_INDEX, &gm, BUFFERSIZE, glyphbuf, &fMat22);
1219    }
1220
1221    if (GDI_ERROR != total_size) {
1222
1223        const uint8_t* cur_glyph = glyphbuf;
1224        const uint8_t* end_glyph = glyphbuf + total_size;
1225
1226        while(cur_glyph < end_glyph) {
1227            const TTPOLYGONHEADER* th = (TTPOLYGONHEADER*)cur_glyph;
1228
1229            const uint8_t* end_poly = cur_glyph + th->cb;
1230            const uint8_t* cur_poly = cur_glyph + sizeof(TTPOLYGONHEADER);
1231
1232            path->moveTo(SkFixedToScalar(*(SkFixed*)(&th->pfxStart.x)), SkFixedToScalar(*(SkFixed*)(&th->pfxStart.y)));
1233
1234            while(cur_poly < end_poly) {
1235                const TTPOLYCURVE* pc = (const TTPOLYCURVE*)cur_poly;
1236
1237                if (pc->wType == TT_PRIM_LINE) {
1238                    for (uint16_t i = 0; i < pc->cpfx; i++) {
1239                        path->lineTo(SkFixedToScalar(*(SkFixed*)(&pc->apfx[i].x)), SkFixedToScalar(*(SkFixed*)(&pc->apfx[i].y)));
1240                    }
1241                }
1242
1243                if (pc->wType == TT_PRIM_QSPLINE) {
1244                    for (uint16_t u = 0; u < pc->cpfx - 1; u++) { // Walk through points in spline
1245                        POINTFX pnt_b = pc->apfx[u];    // B is always the current point
1246                        POINTFX pnt_c = pc->apfx[u+1];
1247
1248                        if (u < pc->cpfx - 2) {          // If not on last spline, compute C
1249                            pnt_c.x = SkFixedToFIXED(SkFixedAve(*(SkFixed*)(&pnt_b.x), *(SkFixed*)(&pnt_c.x)));
1250                            pnt_c.y = SkFixedToFIXED(SkFixedAve(*(SkFixed*)(&pnt_b.y), *(SkFixed*)(&pnt_c.y)));
1251                        }
1252
1253                        path->quadTo(SkFixedToScalar(*(SkFixed*)(&pnt_b.x)), SkFixedToScalar(*(SkFixed*)(&pnt_b.y)), SkFixedToScalar(*(SkFixed*)(&pnt_c.x)), SkFixedToScalar(*(SkFixed*)(&pnt_c.y)));
1254                    }
1255                }
1256                cur_poly += sizeof(uint16_t) * 2 + sizeof(POINTFX) * pc->cpfx;
1257            }
1258            cur_glyph += th->cb;
1259            path->close();
1260        }
1261    }
1262    else {
1263        SkASSERT(false);
1264    }
1265    //char buf[1024];
1266    //sprintf(buf, "generatePath: count:%d\n", count);
1267    //OutputDebugString(buf);
1268}
1269
1270static void logfont_for_name(const char* familyName, LOGFONT& lf) {
1271        memset(&lf, 0, sizeof(LOGFONT));
1272#ifdef UNICODE
1273        // Get the buffer size needed first.
1274        size_t str_len = ::MultiByteToWideChar(CP_UTF8, 0, familyName,
1275                                                -1, NULL, 0);
1276        // Allocate a buffer (str_len already has terminating null
1277        // accounted for).
1278        wchar_t *wideFamilyName = new wchar_t[str_len];
1279        // Now actually convert the string.
1280        ::MultiByteToWideChar(CP_UTF8, 0, familyName, -1,
1281                                wideFamilyName, str_len);
1282        ::wcsncpy(lf.lfFaceName, wideFamilyName, LF_FACESIZE - 1);
1283        delete [] wideFamilyName;
1284        lf.lfFaceName[LF_FACESIZE-1] = L'\0';
1285#else
1286        ::strncpy(lf.lfFaceName, familyName, LF_FACESIZE - 1);
1287        lf.lfFaceName[LF_FACESIZE - 1] = '\0';
1288#endif
1289}
1290
1291static void logfont_to_name(const LOGFONT& lf, SkString* s) {
1292#ifdef UNICODE
1293    // Get the buffer size needed first.
1294    size_t str_len = WideCharToMultiByte(CP_UTF8, 0, lf.lfFaceName, -1, NULL,
1295                                         0, NULL, NULL);
1296    // Allocate a buffer (str_len already has terminating null accounted for).
1297    s->resize(str_len);
1298    // Now actually convert the string.
1299    WideCharToMultiByte(CP_UTF8, 0, lf.lfFaceName, -1,
1300                        s->writable_str(), str_len,
1301                        NULL, NULL);
1302#else
1303    s->set(lf.lfFaceName);
1304#endif
1305}
1306
1307void SkFontHost::Serialize(const SkTypeface* rawFace, SkWStream* stream) {
1308    const LogFontTypeface* face = static_cast<const LogFontTypeface*>(rawFace);
1309    SkFontDescriptor descriptor(face->style());
1310
1311    SkString familyName;
1312    logfont_to_name(face->fLogFont, &familyName);
1313    descriptor.setFamilyName(familyName.c_str());
1314    //TODO: FileName and PostScriptName currently unsupported.
1315
1316    descriptor.serialize(stream);
1317
1318    if (face->fSerializeAsStream) {
1319        // store the entire font in the fontData
1320        SkAutoTUnref<SkStream> fontStream(SkFontHost::OpenStream(face->uniqueID()));
1321        const uint32_t length = fontStream->getLength();
1322
1323        stream->writePackedUInt(length);
1324        stream->writeStream(fontStream, length);
1325    } else {
1326        stream->writePackedUInt(0);
1327    }
1328}
1329
1330SkTypeface* SkFontHost::Deserialize(SkStream* stream) {
1331    SkFontDescriptor descriptor(stream);
1332
1333    const uint32_t customFontDataLength = stream->readPackedUInt();
1334    if (customFontDataLength > 0) {
1335        // generate a new stream to store the custom typeface
1336        SkAutoTUnref<SkMemoryStream> fontStream(SkNEW_ARGS(SkMemoryStream, (customFontDataLength - 1)));
1337        stream->read((void*)fontStream->getMemoryBase(), customFontDataLength - 1);
1338
1339        return CreateTypefaceFromStream(fontStream.get());
1340    }
1341
1342    return SkFontHost::CreateTypeface(NULL, descriptor.getFamilyName(), descriptor.getStyle());
1343}
1344
1345static bool getWidthAdvance(HDC hdc, int gId, int16_t* advance) {
1346    // Initialize the MAT2 structure to the identify transformation matrix.
1347    static const MAT2 mat2 = {SkScalarToFIXED(1), SkScalarToFIXED(0),
1348                        SkScalarToFIXED(0), SkScalarToFIXED(1)};
1349    int flags = GGO_METRICS | GGO_GLYPH_INDEX;
1350    GLYPHMETRICS gm;
1351    if (GDI_ERROR == GetGlyphOutline(hdc, gId, flags, &gm, 0, NULL, &mat2)) {
1352        return false;
1353    }
1354    SkASSERT(advance);
1355    *advance = gm.gmCellIncX;
1356    return true;
1357}
1358
1359// static
1360SkAdvancedTypefaceMetrics* SkFontHost::GetAdvancedTypefaceMetrics(
1361        uint32_t fontID,
1362        SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo,
1363        const uint32_t* glyphIDs,
1364        uint32_t glyphIDsCount) {
1365    LOGFONT lf;
1366    GetLogFontByID(fontID, &lf);
1367    SkAdvancedTypefaceMetrics* info = NULL;
1368
1369    HDC hdc = CreateCompatibleDC(NULL);
1370    HFONT font = CreateFontIndirect(&lf);
1371    HFONT savefont = (HFONT)SelectObject(hdc, font);
1372    HFONT designFont = NULL;
1373
1374    const char stem_chars[] = {'i', 'I', '!', '1'};
1375    int16_t min_width;
1376    unsigned glyphCount;
1377
1378    // To request design units, create a logical font whose height is specified
1379    // as unitsPerEm.
1380    OUTLINETEXTMETRIC otm;
1381    unsigned int otmRet = GetOutlineTextMetrics(hdc, sizeof(otm), &otm);
1382    if (0 == otmRet) {
1383        ensure_typeface_accessible(fontID);
1384        otmRet = GetOutlineTextMetrics(hdc, sizeof(otm), &otm);
1385    }
1386    if (!otmRet || !GetTextFace(hdc, LF_FACESIZE, lf.lfFaceName)) {
1387        goto Error;
1388    }
1389    lf.lfHeight = -SkToS32(otm.otmEMSquare);
1390    designFont = CreateFontIndirect(&lf);
1391    SelectObject(hdc, designFont);
1392    if (!GetOutlineTextMetrics(hdc, sizeof(otm), &otm)) {
1393        goto Error;
1394    }
1395    glyphCount = calculateOutlineGlyphCount(hdc);
1396
1397    info = new SkAdvancedTypefaceMetrics;
1398    info->fEmSize = otm.otmEMSquare;
1399    info->fMultiMaster = false;
1400    info->fLastGlyphID = SkToU16(glyphCount - 1);
1401    info->fStyle = 0;
1402    logfont_to_name(lf, &info->fFontName);
1403
1404    if (perGlyphInfo & SkAdvancedTypefaceMetrics::kToUnicode_PerGlyphInfo) {
1405        populate_glyph_to_unicode(hdc, glyphCount, &(info->fGlyphToUnicode));
1406    }
1407
1408    if (glyphCount > 0 &&
1409        (otm.otmTextMetrics.tmPitchAndFamily & TMPF_TRUETYPE)) {
1410        info->fType = SkAdvancedTypefaceMetrics::kTrueType_Font;
1411    } else {
1412        info->fType = SkAdvancedTypefaceMetrics::kOther_Font;
1413        info->fItalicAngle = 0;
1414        info->fAscent = 0;
1415        info->fDescent = 0;
1416        info->fStemV = 0;
1417        info->fCapHeight = 0;
1418        info->fBBox = SkIRect::MakeEmpty();
1419        return info;
1420    }
1421
1422    // If this bit is clear the font is a fixed pitch font.
1423    if (!(otm.otmTextMetrics.tmPitchAndFamily & TMPF_FIXED_PITCH)) {
1424        info->fStyle |= SkAdvancedTypefaceMetrics::kFixedPitch_Style;
1425    }
1426    if (otm.otmTextMetrics.tmItalic) {
1427        info->fStyle |= SkAdvancedTypefaceMetrics::kItalic_Style;
1428    }
1429    // Setting symbolic style by default for now.
1430    info->fStyle |= SkAdvancedTypefaceMetrics::kSymbolic_Style;
1431    if (otm.otmTextMetrics.tmPitchAndFamily & FF_ROMAN) {
1432        info->fStyle |= SkAdvancedTypefaceMetrics::kSerif_Style;
1433    } else if (otm.otmTextMetrics.tmPitchAndFamily & FF_SCRIPT) {
1434            info->fStyle |= SkAdvancedTypefaceMetrics::kScript_Style;
1435    }
1436
1437    // The main italic angle of the font, in tenths of a degree counterclockwise
1438    // from vertical.
1439    info->fItalicAngle = otm.otmItalicAngle / 10;
1440    info->fAscent = SkToS16(otm.otmTextMetrics.tmAscent);
1441    info->fDescent = SkToS16(-otm.otmTextMetrics.tmDescent);
1442    // TODO(ctguil): Use alternate cap height calculation.
1443    // MSDN says otmsCapEmHeight is not support but it is returning a value on
1444    // my Win7 box.
1445    info->fCapHeight = otm.otmsCapEmHeight;
1446    info->fBBox =
1447        SkIRect::MakeLTRB(otm.otmrcFontBox.left, otm.otmrcFontBox.top,
1448                          otm.otmrcFontBox.right, otm.otmrcFontBox.bottom);
1449
1450    // Figure out a good guess for StemV - Min width of i, I, !, 1.
1451    // This probably isn't very good with an italic font.
1452    min_width = SHRT_MAX;
1453    info->fStemV = 0;
1454    for (size_t i = 0; i < SK_ARRAY_COUNT(stem_chars); i++) {
1455        ABC abcWidths;
1456        if (GetCharABCWidths(hdc, stem_chars[i], stem_chars[i], &abcWidths)) {
1457            int16_t width = abcWidths.abcB;
1458            if (width > 0 && width < min_width) {
1459                min_width = width;
1460                info->fStemV = min_width;
1461            }
1462        }
1463    }
1464
1465    // If bit 1 is set, the font may not be embedded in a document.
1466    // If bit 1 is clear, the font can be embedded.
1467    // If bit 2 is set, the embedding is read-only.
1468    if (otm.otmfsType & 0x1) {
1469        info->fType = SkAdvancedTypefaceMetrics::kNotEmbeddable_Font;
1470    } else if (perGlyphInfo &
1471               SkAdvancedTypefaceMetrics::kHAdvance_PerGlyphInfo) {
1472        if (info->fStyle & SkAdvancedTypefaceMetrics::kFixedPitch_Style) {
1473            appendRange(&info->fGlyphWidths, 0);
1474            info->fGlyphWidths->fAdvance.append(1, &min_width);
1475            finishRange(info->fGlyphWidths.get(), 0,
1476                        SkAdvancedTypefaceMetrics::WidthRange::kDefault);
1477        } else {
1478            info->fGlyphWidths.reset(
1479                getAdvanceData(hdc,
1480                               glyphCount,
1481                               glyphIDs,
1482                               glyphIDsCount,
1483                               &getWidthAdvance));
1484        }
1485    }
1486
1487Error:
1488    SelectObject(hdc, savefont);
1489    DeleteObject(designFont);
1490    DeleteObject(font);
1491    DeleteDC(hdc);
1492
1493    return info;
1494}
1495
1496//Dummy representation of a Base64 encoded GUID from create_unique_font_name.
1497#define BASE64_GUID_ID "XXXXXXXXXXXXXXXXXXXXXXXX"
1498//Length of GUID representation from create_id, including NULL terminator.
1499#define BASE64_GUID_ID_LEN SK_ARRAY_COUNT(BASE64_GUID_ID)
1500
1501SK_COMPILE_ASSERT(BASE64_GUID_ID_LEN < LF_FACESIZE, GUID_longer_than_facesize);
1502
1503/**
1504   NameID 6 Postscript names cannot have the character '/'.
1505   It would be easier to hex encode the GUID, but that is 32 bytes,
1506   and many systems have issues with names longer than 28 bytes.
1507   The following need not be any standard base64 encoding.
1508   The encoded value is never decoded.
1509*/
1510static const char postscript_safe_base64_encode[] =
1511    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
1512    "abcdefghijklmnopqrstuvwxyz"
1513    "0123456789-_=";
1514
1515/**
1516   Formats a GUID into Base64 and places it into buffer.
1517   buffer should have space for at least BASE64_GUID_ID_LEN characters.
1518   The string will always be null terminated.
1519   XXXXXXXXXXXXXXXXXXXXXXXX0
1520 */
1521static void format_guid_b64(const GUID& guid, char* buffer, size_t bufferSize) {
1522    SkASSERT(bufferSize >= BASE64_GUID_ID_LEN);
1523    size_t written = SkBase64::Encode(&guid, sizeof(guid), buffer, postscript_safe_base64_encode);
1524    SkASSERT(written < LF_FACESIZE);
1525    buffer[written] = '\0';
1526}
1527
1528/**
1529   Creates a Base64 encoded GUID and places it into buffer.
1530   buffer should have space for at least BASE64_GUID_ID_LEN characters.
1531   The string will always be null terminated.
1532   XXXXXXXXXXXXXXXXXXXXXXXX0
1533 */
1534static HRESULT create_unique_font_name(char* buffer, size_t bufferSize) {
1535    GUID guid = {};
1536    if (FAILED(CoCreateGuid(&guid))) {
1537        return E_UNEXPECTED;
1538    }
1539    format_guid_b64(guid, buffer, bufferSize);
1540
1541    return S_OK;
1542}
1543
1544/**
1545   Introduces a font to GDI. On failure will return NULL. The returned handle
1546   should eventually be passed to RemoveFontMemResourceEx.
1547*/
1548static HANDLE activate_font(SkData* fontData) {
1549    DWORD numFonts = 0;
1550    //AddFontMemResourceEx just copies the data, but does not specify const.
1551    HANDLE fontHandle = AddFontMemResourceEx(const_cast<void*>(fontData->data()),
1552                                             fontData->size(),
1553                                             0,
1554                                             &numFonts);
1555
1556    if (fontHandle != NULL && numFonts < 1) {
1557        RemoveFontMemResourceEx(fontHandle);
1558        return NULL;
1559    }
1560
1561    return fontHandle;
1562}
1563
1564SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) {
1565    // Create a unique and unpredictable font name.
1566    // Avoids collisions and access from CSS.
1567    char familyName[BASE64_GUID_ID_LEN];
1568    const int familyNameSize = SK_ARRAY_COUNT(familyName);
1569    if (FAILED(create_unique_font_name(familyName, familyNameSize))) {
1570        return NULL;
1571    }
1572
1573    // Change the name of the font.
1574    SkAutoTUnref<SkData> rewrittenFontData(SkOTUtils::RenameFont(stream, familyName, familyNameSize-1));
1575    if (NULL == rewrittenFontData.get()) {
1576        return NULL;
1577    }
1578
1579    // Register the font with GDI.
1580    HANDLE fontReference = activate_font(rewrittenFontData.get());
1581    if (NULL == fontReference) {
1582        return NULL;
1583    }
1584
1585    // Create the typeface.
1586    LOGFONT lf;
1587    logfont_for_name(familyName, lf);
1588
1589    return SkCreateFontMemResourceTypefaceFromLOGFONT(lf, fontReference);
1590}
1591
1592SkStream* SkFontHost::OpenStream(SkFontID uniqueID) {
1593    const DWORD kTTCTag =
1594        SkEndian_SwapBE32(SkSetFourByteTag('t', 't', 'c', 'f'));
1595    LOGFONT lf;
1596    GetLogFontByID(uniqueID, &lf);
1597
1598    HDC hdc = ::CreateCompatibleDC(NULL);
1599    HFONT font = CreateFontIndirect(&lf);
1600    HFONT savefont = (HFONT)SelectObject(hdc, font);
1601
1602    SkMemoryStream* stream = NULL;
1603    DWORD tables[2] = {kTTCTag, 0};
1604    for (int i = 0; i < SK_ARRAY_COUNT(tables); i++) {
1605        size_t bufferSize = GetFontData(hdc, tables[i], 0, NULL, 0);
1606        if (bufferSize == GDI_ERROR) {
1607            ensure_typeface_accessible(uniqueID);
1608            bufferSize = GetFontData(hdc, tables[i], 0, NULL, 0);
1609        }
1610        if (bufferSize != GDI_ERROR) {
1611            stream = new SkMemoryStream(bufferSize);
1612            if (GetFontData(hdc, tables[i], 0, (void*)stream->getMemoryBase(),
1613                            bufferSize)) {
1614                break;
1615            } else {
1616                delete stream;
1617                stream = NULL;
1618            }
1619        }
1620    }
1621
1622    SelectObject(hdc, savefont);
1623    DeleteObject(font);
1624    DeleteDC(hdc);
1625
1626    return stream;
1627}
1628
1629SkScalerContext* SkFontHost::CreateScalerContext(const SkDescriptor* desc) {
1630    return SkNEW_ARGS(SkScalerContext_Windows, (desc));
1631}
1632
1633/** Return the closest matching typeface given either an existing family
1634 (specified by a typeface in that family) or by a familyName, and a
1635 requested style.
1636 1) If familyFace is null, use familyName.
1637 2) If familyName is null, use familyFace.
1638 3) If both are null, return the default font that best matches style
1639 This MUST not return NULL.
1640 */
1641
1642SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace,
1643                                       const char familyName[],
1644                                       SkTypeface::Style style) {
1645    LOGFONT lf;
1646    if (NULL == familyFace && NULL == familyName) {
1647        lf = get_default_font();
1648    } else if (familyFace) {
1649        LogFontTypeface* face = (LogFontTypeface*)familyFace;
1650        lf = face->fLogFont;
1651    } else {
1652        logfont_for_name(familyName, lf);
1653    }
1654    setStyle(&lf, style);
1655    return SkCreateTypefaceFromLOGFONT(lf);
1656}
1657
1658SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) {
1659    printf("SkFontHost::CreateTypefaceFromFile unimplemented");
1660    return NULL;
1661}
1662
1663void SkFontHost::FilterRec(SkScalerContext::Rec* rec) {
1664    unsigned flagsWeDontSupport = SkScalerContext::kDevKernText_Flag |
1665                                  SkScalerContext::kAutohinting_Flag |
1666                                  SkScalerContext::kEmbeddedBitmapText_Flag |
1667                                  SkScalerContext::kEmbolden_Flag |
1668                                  SkScalerContext::kSubpixelPositioning_Flag |
1669                                  SkScalerContext::kLCD_BGROrder_Flag |
1670                                  SkScalerContext::kLCD_Vertical_Flag;
1671    rec->fFlags &= ~flagsWeDontSupport;
1672
1673    SkPaint::Hinting h = rec->getHinting();
1674
1675    // I think we can support no-hinting, if we get hires outlines and just
1676    // use skia to rasterize into a gray-scale mask...
1677#if 0
1678    switch (h) {
1679        case SkPaint::kNo_Hinting:
1680        case SkPaint::kSlight_Hinting:
1681            h = SkPaint::kNo_Hinting;
1682            break;
1683        case SkPaint::kNormal_Hinting:
1684        case SkPaint::kFull_Hinting:
1685            h = SkPaint::kNormal_Hinting;
1686            break;
1687        default:
1688            SkDEBUGFAIL("unknown hinting");
1689    }
1690#else
1691    h = SkPaint::kNormal_Hinting;
1692#endif
1693    rec->setHinting(h);
1694
1695// turn this off since GDI might turn A8 into BW! Need a bigger fix.
1696#if 0
1697    // Disable LCD when rotated, since GDI's output is ugly
1698    if (isLCD(*rec) && !isAxisAligned(*rec)) {
1699        rec->fMaskFormat = SkMask::kA8_Format;
1700    }
1701#endif
1702
1703#if 0
1704    if (SkMask::kLCD16_Format == rec->fMaskFormat) {
1705        rec->fMaskFormat = SkMask::kLCD32_Format;
1706    }
1707#endif
1708}
1709