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