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