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