gfx/skia/trunk/src/ports/SkFontHost_win.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/skia/trunk/src/ports/SkFontHost_win.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,2648 @@
     1.4 +
     1.5 +/*
     1.6 + * Copyright 2006 The Android Open Source Project
     1.7 + *
     1.8 + * Use of this source code is governed by a BSD-style license that can be
     1.9 + * found in the LICENSE file.
    1.10 + */
    1.11 +
    1.12 +#include "SkAdvancedTypefaceMetrics.h"
    1.13 +#include "SkBase64.h"
    1.14 +#include "SkColorPriv.h"
    1.15 +#include "SkData.h"
    1.16 +#include "SkDescriptor.h"
    1.17 +#include "SkFontDescriptor.h"
    1.18 +#include "SkFontHost.h"
    1.19 +#include "SkGlyph.h"
    1.20 +#include "SkHRESULT.h"
    1.21 +#include "SkMaskGamma.h"
    1.22 +#include "SkOTTable_maxp.h"
    1.23 +#include "SkOTTable_name.h"
    1.24 +#include "SkOTUtils.h"
    1.25 +#include "SkPath.h"
    1.26 +#include "SkSFNTHeader.h"
    1.27 +#include "SkStream.h"
    1.28 +#include "SkString.h"
    1.29 +#include "SkTemplates.h"
    1.30 +#include "SkThread.h"
    1.31 +#include "SkTypeface_win.h"
    1.32 +#include "SkTypefaceCache.h"
    1.33 +#include "SkUtils.h"
    1.34 +
    1.35 +#include "SkTypes.h"
    1.36 +#include <tchar.h>
    1.37 +#include <usp10.h>
    1.38 +#include <objbase.h>
    1.39 +
    1.40 +static void (*gEnsureLOGFONTAccessibleProc)(const LOGFONT&);
    1.41 +
    1.42 +void SkTypeface_SetEnsureLOGFONTAccessibleProc(void (*proc)(const LOGFONT&)) {
    1.43 +    gEnsureLOGFONTAccessibleProc = proc;
    1.44 +}
    1.45 +
    1.46 +static void call_ensure_accessible(const LOGFONT& lf) {
    1.47 +    if (gEnsureLOGFONTAccessibleProc) {
    1.48 +        gEnsureLOGFONTAccessibleProc(lf);
    1.49 +    }
    1.50 +}
    1.51 +
    1.52 +///////////////////////////////////////////////////////////////////////////////
    1.53 +
    1.54 +// always packed xxRRGGBB
    1.55 +typedef uint32_t SkGdiRGB;
    1.56 +
    1.57 +// define this in your Makefile or .gyp to enforce AA requests
    1.58 +// which GDI ignores at small sizes. This flag guarantees AA
    1.59 +// for rotated text, regardless of GDI's notions.
    1.60 +//#define SK_ENFORCE_ROTATED_TEXT_AA_ON_WINDOWS
    1.61 +
    1.62 +static bool isLCD(const SkScalerContext::Rec& rec) {
    1.63 +    return SkMask::kLCD16_Format == rec.fMaskFormat ||
    1.64 +           SkMask::kLCD32_Format == rec.fMaskFormat;
    1.65 +}
    1.66 +
    1.67 +static bool bothZero(SkScalar a, SkScalar b) {
    1.68 +    return 0 == a && 0 == b;
    1.69 +}
    1.70 +
    1.71 +// returns false if there is any non-90-rotation or skew
    1.72 +static bool isAxisAligned(const SkScalerContext::Rec& rec) {
    1.73 +    return 0 == rec.fPreSkewX &&
    1.74 +           (bothZero(rec.fPost2x2[0][1], rec.fPost2x2[1][0]) ||
    1.75 +            bothZero(rec.fPost2x2[0][0], rec.fPost2x2[1][1]));
    1.76 +}
    1.77 +
    1.78 +static bool needToRenderWithSkia(const SkScalerContext::Rec& rec) {
    1.79 +#ifdef SK_ENFORCE_ROTATED_TEXT_AA_ON_WINDOWS
    1.80 +    // What we really want to catch is when GDI will ignore the AA request and give
    1.81 +    // us BW instead. Smallish rotated text is one heuristic, so this code is just
    1.82 +    // an approximation. We shouldn't need to do this for larger sizes, but at those
    1.83 +    // sizes, the quality difference gets less and less between our general
    1.84 +    // scanconverter and GDI's.
    1.85 +    if (SkMask::kA8_Format == rec.fMaskFormat && !isAxisAligned(rec)) {
    1.86 +        return true;
    1.87 +    }
    1.88 +#endif
    1.89 +    return rec.getHinting() == SkPaint::kNo_Hinting || rec.getHinting() == SkPaint::kSlight_Hinting;
    1.90 +}
    1.91 +
    1.92 +using namespace skia_advanced_typeface_metrics_utils;
    1.93 +
    1.94 +static void tchar_to_skstring(const TCHAR t[], SkString* s) {
    1.95 +#ifdef UNICODE
    1.96 +    size_t sSize = WideCharToMultiByte(CP_UTF8, 0, t, -1, NULL, 0, NULL, NULL);
    1.97 +    s->resize(sSize);
    1.98 +    WideCharToMultiByte(CP_UTF8, 0, t, -1, s->writable_str(), sSize, NULL, NULL);
    1.99 +#else
   1.100 +    s->set(t);
   1.101 +#endif
   1.102 +}
   1.103 +
   1.104 +static void dcfontname_to_skstring(HDC deviceContext, const LOGFONT& lf, SkString* familyName) {
   1.105 +    int fontNameLen; //length of fontName in TCHARS.
   1.106 +    if (0 == (fontNameLen = GetTextFace(deviceContext, 0, NULL))) {
   1.107 +        call_ensure_accessible(lf);
   1.108 +        if (0 == (fontNameLen = GetTextFace(deviceContext, 0, NULL))) {
   1.109 +            fontNameLen = 0;
   1.110 +        }
   1.111 +    }
   1.112 +
   1.113 +    SkAutoSTArray<LF_FULLFACESIZE, TCHAR> fontName(fontNameLen+1);
   1.114 +    if (0 == GetTextFace(deviceContext, fontNameLen, fontName.get())) {
   1.115 +        call_ensure_accessible(lf);
   1.116 +        if (0 == GetTextFace(deviceContext, fontNameLen, fontName.get())) {
   1.117 +            fontName[0] = 0;
   1.118 +        }
   1.119 +    }
   1.120 +
   1.121 +    tchar_to_skstring(fontName.get(), familyName);
   1.122 +}
   1.123 +
   1.124 +static void make_canonical(LOGFONT* lf) {
   1.125 +    lf->lfHeight = -64;
   1.126 +    lf->lfQuality = CLEARTYPE_QUALITY;//PROOF_QUALITY;
   1.127 +    lf->lfCharSet = DEFAULT_CHARSET;
   1.128 +//    lf->lfClipPrecision = 64;
   1.129 +}
   1.130 +
   1.131 +static SkTypeface::Style get_style(const LOGFONT& lf) {
   1.132 +    unsigned style = 0;
   1.133 +    if (lf.lfWeight >= FW_BOLD) {
   1.134 +        style |= SkTypeface::kBold;
   1.135 +    }
   1.136 +    if (lf.lfItalic) {
   1.137 +        style |= SkTypeface::kItalic;
   1.138 +    }
   1.139 +    return static_cast<SkTypeface::Style>(style);
   1.140 +}
   1.141 +
   1.142 +static void setStyle(LOGFONT* lf, SkTypeface::Style style) {
   1.143 +    lf->lfWeight = (style & SkTypeface::kBold) != 0 ? FW_BOLD : FW_NORMAL ;
   1.144 +    lf->lfItalic = ((style & SkTypeface::kItalic) != 0);
   1.145 +}
   1.146 +
   1.147 +static inline FIXED SkFixedToFIXED(SkFixed x) {
   1.148 +    return *(FIXED*)(&x);
   1.149 +}
   1.150 +static inline SkFixed SkFIXEDToFixed(FIXED x) {
   1.151 +    return *(SkFixed*)(&x);
   1.152 +}
   1.153 +
   1.154 +static inline FIXED SkScalarToFIXED(SkScalar x) {
   1.155 +    return SkFixedToFIXED(SkScalarToFixed(x));
   1.156 +}
   1.157 +
   1.158 +static inline SkScalar SkFIXEDToScalar(FIXED x) {
   1.159 +    return SkFixedToScalar(SkFIXEDToFixed(x));
   1.160 +}
   1.161 +
   1.162 +static unsigned calculateGlyphCount(HDC hdc, const LOGFONT& lf) {
   1.163 +    TEXTMETRIC textMetric;
   1.164 +    if (0 == GetTextMetrics(hdc, &textMetric)) {
   1.165 +        textMetric.tmPitchAndFamily = TMPF_VECTOR;
   1.166 +        call_ensure_accessible(lf);
   1.167 +        GetTextMetrics(hdc, &textMetric);
   1.168 +    }
   1.169 +
   1.170 +    if (!(textMetric.tmPitchAndFamily & TMPF_VECTOR)) {
   1.171 +        return textMetric.tmLastChar;
   1.172 +    }
   1.173 +
   1.174 +    // The 'maxp' table stores the number of glyphs at offset 4, in 2 bytes.
   1.175 +    uint16_t glyphs;
   1.176 +    if (GDI_ERROR != GetFontData(hdc, SkOTTableMaximumProfile::TAG, 4, &glyphs, sizeof(glyphs))) {
   1.177 +        return SkEndian_SwapBE16(glyphs);
   1.178 +    }
   1.179 +
   1.180 +    // Binary search for glyph count.
   1.181 +    static const MAT2 mat2 = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
   1.182 +    int32_t max = SK_MaxU16 + 1;
   1.183 +    int32_t min = 0;
   1.184 +    GLYPHMETRICS gm;
   1.185 +    while (min < max) {
   1.186 +        int32_t mid = min + ((max - min) / 2);
   1.187 +        if (GetGlyphOutlineW(hdc, mid, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0,
   1.188 +                             NULL, &mat2) == GDI_ERROR) {
   1.189 +            max = mid;
   1.190 +        } else {
   1.191 +            min = mid + 1;
   1.192 +        }
   1.193 +    }
   1.194 +    SkASSERT(min == max);
   1.195 +    return min;
   1.196 +}
   1.197 +
   1.198 +static unsigned calculateUPEM(HDC hdc, const LOGFONT& lf) {
   1.199 +    TEXTMETRIC textMetric;
   1.200 +    if (0 == GetTextMetrics(hdc, &textMetric)) {
   1.201 +        textMetric.tmPitchAndFamily = TMPF_VECTOR;
   1.202 +        call_ensure_accessible(lf);
   1.203 +        GetTextMetrics(hdc, &textMetric);
   1.204 +    }
   1.205 +
   1.206 +    if (!(textMetric.tmPitchAndFamily & TMPF_VECTOR)) {
   1.207 +        return textMetric.tmMaxCharWidth;
   1.208 +    }
   1.209 +
   1.210 +    OUTLINETEXTMETRIC otm;
   1.211 +    unsigned int otmRet = GetOutlineTextMetrics(hdc, sizeof(otm), &otm);
   1.212 +    if (0 == otmRet) {
   1.213 +        call_ensure_accessible(lf);
   1.214 +        otmRet = GetOutlineTextMetrics(hdc, sizeof(otm), &otm);
   1.215 +    }
   1.216 +
   1.217 +    return (0 == otmRet) ? 0 : otm.otmEMSquare;
   1.218 +}
   1.219 +
   1.220 +class LogFontTypeface : public SkTypeface {
   1.221 +public:
   1.222 +    LogFontTypeface(SkTypeface::Style style, SkFontID fontID, const LOGFONT& lf, bool serializeAsStream = false) :
   1.223 +        SkTypeface(style, fontID, false), fLogFont(lf), fSerializeAsStream(serializeAsStream) {
   1.224 +
   1.225 +        // If the font has cubic outlines, it will not be rendered with ClearType.
   1.226 +        HFONT font = CreateFontIndirect(&lf);
   1.227 +
   1.228 +        HDC deviceContext = ::CreateCompatibleDC(NULL);
   1.229 +        HFONT savefont = (HFONT)SelectObject(deviceContext, font);
   1.230 +
   1.231 +        TEXTMETRIC textMetric;
   1.232 +        if (0 == GetTextMetrics(deviceContext, &textMetric)) {
   1.233 +            call_ensure_accessible(lf);
   1.234 +            if (0 == GetTextMetrics(deviceContext, &textMetric)) {
   1.235 +                textMetric.tmPitchAndFamily = TMPF_TRUETYPE;
   1.236 +            }
   1.237 +        }
   1.238 +        if (deviceContext) {
   1.239 +            ::SelectObject(deviceContext, savefont);
   1.240 +            ::DeleteDC(deviceContext);
   1.241 +        }
   1.242 +        if (font) {
   1.243 +            ::DeleteObject(font);
   1.244 +        }
   1.245 +
   1.246 +        // The fixed pitch bit is set if the font is *not* fixed pitch.
   1.247 +        this->setIsFixedPitch((textMetric.tmPitchAndFamily & TMPF_FIXED_PITCH) == 0);
   1.248 +
   1.249 +        // Used a logfont on a memory context, should never get a device font.
   1.250 +        // Therefore all TMPF_DEVICE will be PostScript (cubic) fonts.
   1.251 +        fCanBeLCD = !((textMetric.tmPitchAndFamily & TMPF_VECTOR) &&
   1.252 +                      (textMetric.tmPitchAndFamily & TMPF_DEVICE));
   1.253 +    }
   1.254 +
   1.255 +    LOGFONT fLogFont;
   1.256 +    bool fSerializeAsStream;
   1.257 +    bool fCanBeLCD;
   1.258 +
   1.259 +    static LogFontTypeface* Create(const LOGFONT& lf) {
   1.260 +        SkTypeface::Style style = get_style(lf);
   1.261 +        SkFontID fontID = SkTypefaceCache::NewFontID();
   1.262 +        return new LogFontTypeface(style, fontID, lf);
   1.263 +    }
   1.264 +
   1.265 +    static void EnsureAccessible(const SkTypeface* face) {
   1.266 +        call_ensure_accessible(static_cast<const LogFontTypeface*>(face)->fLogFont);
   1.267 +    }
   1.268 +
   1.269 +protected:
   1.270 +    virtual SkStream* onOpenStream(int* ttcIndex) const SK_OVERRIDE;
   1.271 +    virtual SkScalerContext* onCreateScalerContext(const SkDescriptor*) const SK_OVERRIDE;
   1.272 +    virtual void onFilterRec(SkScalerContextRec*) const SK_OVERRIDE;
   1.273 +    virtual SkAdvancedTypefaceMetrics* onGetAdvancedTypefaceMetrics(
   1.274 +                                SkAdvancedTypefaceMetrics::PerGlyphInfo,
   1.275 +                                const uint32_t*, uint32_t) const SK_OVERRIDE;
   1.276 +    virtual void onGetFontDescriptor(SkFontDescriptor*, bool*) const SK_OVERRIDE;
   1.277 +    virtual int onCharsToGlyphs(const void* chars, Encoding encoding,
   1.278 +                                uint16_t glyphs[], int glyphCount) const SK_OVERRIDE;
   1.279 +    virtual int onCountGlyphs() const SK_OVERRIDE;
   1.280 +    virtual int onGetUPEM() const SK_OVERRIDE;
   1.281 +    virtual SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const SK_OVERRIDE;
   1.282 +    virtual int onGetTableTags(SkFontTableTag tags[]) const SK_OVERRIDE;
   1.283 +    virtual size_t onGetTableData(SkFontTableTag, size_t offset,
   1.284 +                                  size_t length, void* data) const SK_OVERRIDE;
   1.285 +};
   1.286 +
   1.287 +class FontMemResourceTypeface : public LogFontTypeface {
   1.288 +public:
   1.289 +    /**
   1.290 +     *  Takes ownership of fontMemResource.
   1.291 +     */
   1.292 +    FontMemResourceTypeface(SkTypeface::Style style, SkFontID fontID, const LOGFONT& lf, HANDLE fontMemResource) :
   1.293 +        LogFontTypeface(style, fontID, lf, true), fFontMemResource(fontMemResource) {
   1.294 +    }
   1.295 +
   1.296 +    HANDLE fFontMemResource;
   1.297 +
   1.298 +    /**
   1.299 +     *  The created FontMemResourceTypeface takes ownership of fontMemResource.
   1.300 +     */
   1.301 +    static FontMemResourceTypeface* Create(const LOGFONT& lf, HANDLE fontMemResource) {
   1.302 +        SkTypeface::Style style = get_style(lf);
   1.303 +        SkFontID fontID = SkTypefaceCache::NewFontID();
   1.304 +        return new FontMemResourceTypeface(style, fontID, lf, fontMemResource);
   1.305 +    }
   1.306 +
   1.307 +protected:
   1.308 +    virtual void weak_dispose() const SK_OVERRIDE {
   1.309 +        RemoveFontMemResourceEx(fFontMemResource);
   1.310 +        //SkTypefaceCache::Remove(this);
   1.311 +        INHERITED::weak_dispose();
   1.312 +    }
   1.313 +
   1.314 +private:
   1.315 +    typedef LogFontTypeface INHERITED;
   1.316 +};
   1.317 +
   1.318 +static const LOGFONT& get_default_font() {
   1.319 +    static LOGFONT gDefaultFont;
   1.320 +    return gDefaultFont;
   1.321 +}
   1.322 +
   1.323 +static bool FindByLogFont(SkTypeface* face, SkTypeface::Style requestedStyle, void* ctx) {
   1.324 +    LogFontTypeface* lface = static_cast<LogFontTypeface*>(face);
   1.325 +    const LOGFONT* lf = reinterpret_cast<const LOGFONT*>(ctx);
   1.326 +
   1.327 +    return lface &&
   1.328 +           get_style(lface->fLogFont) == requestedStyle &&
   1.329 +           !memcmp(&lface->fLogFont, lf, sizeof(LOGFONT));
   1.330 +}
   1.331 +
   1.332 +/**
   1.333 + *  This guy is public. It first searches the cache, and if a match is not found,
   1.334 + *  it creates a new face.
   1.335 + */
   1.336 +SkTypeface* SkCreateTypefaceFromLOGFONT(const LOGFONT& origLF) {
   1.337 +    LOGFONT lf = origLF;
   1.338 +    make_canonical(&lf);
   1.339 +    SkTypeface* face = SkTypefaceCache::FindByProcAndRef(FindByLogFont, &lf);
   1.340 +    if (NULL == face) {
   1.341 +        face = LogFontTypeface::Create(lf);
   1.342 +        SkTypefaceCache::Add(face, get_style(lf));
   1.343 +    }
   1.344 +    return face;
   1.345 +}
   1.346 +
   1.347 +/**
   1.348 + *  The created SkTypeface takes ownership of fontMemResource.
   1.349 + */
   1.350 +SkTypeface* SkCreateFontMemResourceTypefaceFromLOGFONT(const LOGFONT& origLF, HANDLE fontMemResource) {
   1.351 +    LOGFONT lf = origLF;
   1.352 +    make_canonical(&lf);
   1.353 +    FontMemResourceTypeface* face = FontMemResourceTypeface::Create(lf, fontMemResource);
   1.354 +    SkTypefaceCache::Add(face, get_style(lf), false);
   1.355 +    return face;
   1.356 +}
   1.357 +
   1.358 +/**
   1.359 + *  This guy is public
   1.360 + */
   1.361 +void SkLOGFONTFromTypeface(const SkTypeface* face, LOGFONT* lf) {
   1.362 +    if (NULL == face) {
   1.363 +        *lf = get_default_font();
   1.364 +    } else {
   1.365 +        *lf = static_cast<const LogFontTypeface*>(face)->fLogFont;
   1.366 +    }
   1.367 +}
   1.368 +
   1.369 +// Construct Glyph to Unicode table.
   1.370 +// Unicode code points that require conjugate pairs in utf16 are not
   1.371 +// supported.
   1.372 +// TODO(arthurhsu): Add support for conjugate pairs. It looks like that may
   1.373 +// require parsing the TTF cmap table (platform 4, encoding 12) directly instead
   1.374 +// of calling GetFontUnicodeRange().
   1.375 +static void populate_glyph_to_unicode(HDC fontHdc, const unsigned glyphCount,
   1.376 +                                      SkTDArray<SkUnichar>* glyphToUnicode) {
   1.377 +    DWORD glyphSetBufferSize = GetFontUnicodeRanges(fontHdc, NULL);
   1.378 +    if (!glyphSetBufferSize) {
   1.379 +        return;
   1.380 +    }
   1.381 +
   1.382 +    SkAutoTDeleteArray<BYTE> glyphSetBuffer(new BYTE[glyphSetBufferSize]);
   1.383 +    GLYPHSET* glyphSet =
   1.384 +        reinterpret_cast<LPGLYPHSET>(glyphSetBuffer.get());
   1.385 +    if (GetFontUnicodeRanges(fontHdc, glyphSet) != glyphSetBufferSize) {
   1.386 +        return;
   1.387 +    }
   1.388 +
   1.389 +    glyphToUnicode->setCount(glyphCount);
   1.390 +    memset(glyphToUnicode->begin(), 0, glyphCount * sizeof(SkUnichar));
   1.391 +    for (DWORD i = 0; i < glyphSet->cRanges; ++i) {
   1.392 +        // There is no guarantee that within a Unicode range, the corresponding
   1.393 +        // glyph id in a font file are continuous. So, even if we have ranges,
   1.394 +        // we can't just use the first and last entry of the range to compute
   1.395 +        // result. We need to enumerate them one by one.
   1.396 +        int count = glyphSet->ranges[i].cGlyphs;
   1.397 +        SkAutoTArray<WCHAR> chars(count + 1);
   1.398 +        chars[count] = 0;  // termintate string
   1.399 +        SkAutoTArray<WORD> glyph(count);
   1.400 +        for (USHORT j = 0; j < count; ++j) {
   1.401 +            chars[j] = glyphSet->ranges[i].wcLow + j;
   1.402 +        }
   1.403 +        GetGlyphIndicesW(fontHdc, chars.get(), count, glyph.get(),
   1.404 +                         GGI_MARK_NONEXISTING_GLYPHS);
   1.405 +        // If the glyph ID is valid, and the glyph is not mapped, then we will
   1.406 +        // fill in the char id into the vector. If the glyph is mapped already,
   1.407 +        // skip it.
   1.408 +        // TODO(arthurhsu): better improve this. e.g. Get all used char ids from
   1.409 +        // font cache, then generate this mapping table from there. It's
   1.410 +        // unlikely to have collisions since glyph reuse happens mostly for
   1.411 +        // different Unicode pages.
   1.412 +        for (USHORT j = 0; j < count; ++j) {
   1.413 +            if (glyph[j] != 0xffff && glyph[j] < glyphCount &&
   1.414 +                (*glyphToUnicode)[glyph[j]] == 0) {
   1.415 +                (*glyphToUnicode)[glyph[j]] = chars[j];
   1.416 +            }
   1.417 +        }
   1.418 +    }
   1.419 +}
   1.420 +
   1.421 +//////////////////////////////////////////////////////////////////////////////////////
   1.422 +
   1.423 +static int alignTo32(int n) {
   1.424 +    return (n + 31) & ~31;
   1.425 +}
   1.426 +
   1.427 +struct MyBitmapInfo : public BITMAPINFO {
   1.428 +    RGBQUAD fMoreSpaceForColors[1];
   1.429 +};
   1.430 +
   1.431 +class HDCOffscreen {
   1.432 +public:
   1.433 +    HDCOffscreen() {
   1.434 +        fFont = 0;
   1.435 +        fDC = 0;
   1.436 +        fBM = 0;
   1.437 +        fBits = NULL;
   1.438 +        fWidth = fHeight = 0;
   1.439 +        fIsBW = false;
   1.440 +    }
   1.441 +
   1.442 +    ~HDCOffscreen() {
   1.443 +        if (fDC) {
   1.444 +            DeleteDC(fDC);
   1.445 +        }
   1.446 +        if (fBM) {
   1.447 +            DeleteObject(fBM);
   1.448 +        }
   1.449 +    }
   1.450 +
   1.451 +    void init(HFONT font, const XFORM& xform) {
   1.452 +        fFont = font;
   1.453 +        fXform = xform;
   1.454 +    }
   1.455 +
   1.456 +    const void* draw(const SkGlyph&, bool isBW, size_t* srcRBPtr);
   1.457 +
   1.458 +private:
   1.459 +    HDC     fDC;
   1.460 +    HBITMAP fBM;
   1.461 +    HFONT   fFont;
   1.462 +    XFORM   fXform;
   1.463 +    void*   fBits;  // points into fBM
   1.464 +    int     fWidth;
   1.465 +    int     fHeight;
   1.466 +    bool    fIsBW;
   1.467 +};
   1.468 +
   1.469 +const void* HDCOffscreen::draw(const SkGlyph& glyph, bool isBW,
   1.470 +                               size_t* srcRBPtr) {
   1.471 +    // Can we share the scalercontext's fDDC, so we don't need to create
   1.472 +    // a separate fDC here?
   1.473 +    if (0 == fDC) {
   1.474 +        fDC = CreateCompatibleDC(0);
   1.475 +        if (0 == fDC) {
   1.476 +            return NULL;
   1.477 +        }
   1.478 +        SetGraphicsMode(fDC, GM_ADVANCED);
   1.479 +        SetBkMode(fDC, TRANSPARENT);
   1.480 +        SetTextAlign(fDC, TA_LEFT | TA_BASELINE);
   1.481 +        SelectObject(fDC, fFont);
   1.482 +
   1.483 +        COLORREF color = 0x00FFFFFF;
   1.484 +        SkDEBUGCODE(COLORREF prev =) SetTextColor(fDC, color);
   1.485 +        SkASSERT(prev != CLR_INVALID);
   1.486 +    }
   1.487 +
   1.488 +    if (fBM && (fIsBW != isBW || fWidth < glyph.fWidth || fHeight < glyph.fHeight)) {
   1.489 +        DeleteObject(fBM);
   1.490 +        fBM = 0;
   1.491 +    }
   1.492 +    fIsBW = isBW;
   1.493 +
   1.494 +    fWidth = SkMax32(fWidth, glyph.fWidth);
   1.495 +    fHeight = SkMax32(fHeight, glyph.fHeight);
   1.496 +
   1.497 +    int biWidth = isBW ? alignTo32(fWidth) : fWidth;
   1.498 +
   1.499 +    if (0 == fBM) {
   1.500 +        MyBitmapInfo info;
   1.501 +        sk_bzero(&info, sizeof(info));
   1.502 +        if (isBW) {
   1.503 +            RGBQUAD blackQuad = { 0, 0, 0, 0 };
   1.504 +            RGBQUAD whiteQuad = { 0xFF, 0xFF, 0xFF, 0 };
   1.505 +            info.bmiColors[0] = blackQuad;
   1.506 +            info.bmiColors[1] = whiteQuad;
   1.507 +        }
   1.508 +        info.bmiHeader.biSize = sizeof(info.bmiHeader);
   1.509 +        info.bmiHeader.biWidth = biWidth;
   1.510 +        info.bmiHeader.biHeight = fHeight;
   1.511 +        info.bmiHeader.biPlanes = 1;
   1.512 +        info.bmiHeader.biBitCount = isBW ? 1 : 32;
   1.513 +        info.bmiHeader.biCompression = BI_RGB;
   1.514 +        if (isBW) {
   1.515 +            info.bmiHeader.biClrUsed = 2;
   1.516 +        }
   1.517 +        fBM = CreateDIBSection(fDC, &info, DIB_RGB_COLORS, &fBits, 0, 0);
   1.518 +        if (0 == fBM) {
   1.519 +            return NULL;
   1.520 +        }
   1.521 +        SelectObject(fDC, fBM);
   1.522 +    }
   1.523 +
   1.524 +    // erase
   1.525 +    size_t srcRB = isBW ? (biWidth >> 3) : (fWidth << 2);
   1.526 +    size_t size = fHeight * srcRB;
   1.527 +    memset(fBits, 0, size);
   1.528 +
   1.529 +    XFORM xform = fXform;
   1.530 +    xform.eDx = (float)-glyph.fLeft;
   1.531 +    xform.eDy = (float)-glyph.fTop;
   1.532 +    SetWorldTransform(fDC, &xform);
   1.533 +
   1.534 +    uint16_t glyphID = glyph.getGlyphID();
   1.535 +    BOOL ret = ExtTextOutW(fDC, 0, 0, ETO_GLYPH_INDEX, NULL, reinterpret_cast<LPCWSTR>(&glyphID), 1, NULL);
   1.536 +    GdiFlush();
   1.537 +    if (0 == ret) {
   1.538 +        return NULL;
   1.539 +    }
   1.540 +    *srcRBPtr = srcRB;
   1.541 +    // offset to the start of the image
   1.542 +    return (const char*)fBits + (fHeight - glyph.fHeight) * srcRB;
   1.543 +}
   1.544 +
   1.545 +//////////////////////////////////////////////////////////////////////////////
   1.546 +#define BUFFERSIZE (1 << 13)
   1.547 +
   1.548 +class SkScalerContext_GDI : public SkScalerContext {
   1.549 +public:
   1.550 +    SkScalerContext_GDI(SkTypeface*, const SkDescriptor* desc);
   1.551 +    virtual ~SkScalerContext_GDI();
   1.552 +
   1.553 +    // Returns true if the constructor was able to complete all of its
   1.554 +    // initializations (which may include calling GDI).
   1.555 +    bool isValid() const;
   1.556 +
   1.557 +protected:
   1.558 +    virtual unsigned generateGlyphCount() SK_OVERRIDE;
   1.559 +    virtual uint16_t generateCharToGlyph(SkUnichar uni) SK_OVERRIDE;
   1.560 +    virtual void generateAdvance(SkGlyph* glyph) SK_OVERRIDE;
   1.561 +    virtual void generateMetrics(SkGlyph* glyph) SK_OVERRIDE;
   1.562 +    virtual void generateImage(const SkGlyph& glyph) SK_OVERRIDE;
   1.563 +    virtual void generatePath(const SkGlyph& glyph, SkPath* path) SK_OVERRIDE;
   1.564 +    virtual void generateFontMetrics(SkPaint::FontMetrics* mX,
   1.565 +                                     SkPaint::FontMetrics* mY) SK_OVERRIDE;
   1.566 +
   1.567 +private:
   1.568 +    DWORD getGDIGlyphPath(const SkGlyph& glyph, UINT flags,
   1.569 +                          SkAutoSTMalloc<BUFFERSIZE, uint8_t>* glyphbuf);
   1.570 +
   1.571 +    HDCOffscreen fOffscreen;
   1.572 +    /** fGsA is the non-rotational part of total matrix without the text height scale.
   1.573 +     *  Used to find the magnitude of advances.
   1.574 +     */
   1.575 +    MAT2         fGsA;
   1.576 +    /** The total matrix without the textSize. */
   1.577 +    MAT2         fMat22;
   1.578 +    /** Scales font to EM size. */
   1.579 +    MAT2         fHighResMat22;
   1.580 +    HDC          fDDC;
   1.581 +    HFONT        fSavefont;
   1.582 +    HFONT        fFont;
   1.583 +    SCRIPT_CACHE fSC;
   1.584 +    int          fGlyphCount;
   1.585 +
   1.586 +    /** The total matrix which also removes EM scale. */
   1.587 +    SkMatrix     fHiResMatrix;
   1.588 +    /** fG_inv is the inverse of the rotational part of the total matrix.
   1.589 +     *  Used to set the direction of advances.
   1.590 +     */
   1.591 +    SkMatrix     fG_inv;
   1.592 +    enum Type {
   1.593 +        kTrueType_Type, kBitmap_Type, kLine_Type
   1.594 +    } fType;
   1.595 +    TEXTMETRIC fTM;
   1.596 +};
   1.597 +
   1.598 +static FIXED float2FIXED(float x) {
   1.599 +    return SkFixedToFIXED(SkFloatToFixed(x));
   1.600 +}
   1.601 +
   1.602 +static BYTE compute_quality(const SkScalerContext::Rec& rec) {
   1.603 +    switch (rec.fMaskFormat) {
   1.604 +        case SkMask::kBW_Format:
   1.605 +            return NONANTIALIASED_QUALITY;
   1.606 +        case SkMask::kLCD16_Format:
   1.607 +        case SkMask::kLCD32_Format:
   1.608 +            return CLEARTYPE_QUALITY;
   1.609 +        default:
   1.610 +            if (rec.fFlags & SkScalerContext::kGenA8FromLCD_Flag) {
   1.611 +                return CLEARTYPE_QUALITY;
   1.612 +            } else {
   1.613 +                return ANTIALIASED_QUALITY;
   1.614 +            }
   1.615 +    }
   1.616 +}
   1.617 +
   1.618 +SkScalerContext_GDI::SkScalerContext_GDI(SkTypeface* rawTypeface,
   1.619 +                                                 const SkDescriptor* desc)
   1.620 +        : SkScalerContext(rawTypeface, desc)
   1.621 +        , fDDC(0)
   1.622 +        , fSavefont(0)
   1.623 +        , fFont(0)
   1.624 +        , fSC(0)
   1.625 +        , fGlyphCount(-1)
   1.626 +{
   1.627 +    LogFontTypeface* typeface = reinterpret_cast<LogFontTypeface*>(rawTypeface);
   1.628 +
   1.629 +    fDDC = ::CreateCompatibleDC(NULL);
   1.630 +    if (!fDDC) {
   1.631 +        return;
   1.632 +    }
   1.633 +    SetGraphicsMode(fDDC, GM_ADVANCED);
   1.634 +    SetBkMode(fDDC, TRANSPARENT);
   1.635 +
   1.636 +    SkPoint h = SkPoint::Make(SK_Scalar1, 0);
   1.637 +    // A is the total matrix.
   1.638 +    SkMatrix A;
   1.639 +    fRec.getSingleMatrix(&A);
   1.640 +    A.mapPoints(&h, 1);
   1.641 +
   1.642 +    // Find the Given's matrix [[c, -s],[s, c]] which rotates the baseline vector h
   1.643 +    // (where the baseline is mapped to) to the positive horizontal axis.
   1.644 +    const SkScalar& a = h.fX;
   1.645 +    const SkScalar& b = h.fY;
   1.646 +    SkScalar c, s;
   1.647 +    if (0 == b) {
   1.648 +        c = SkDoubleToScalar(_copysign(SK_Scalar1, a));
   1.649 +        s = 0;
   1.650 +    } else if (0 == a) {
   1.651 +        c = 0;
   1.652 +        s = SkDoubleToScalar(-_copysign(SK_Scalar1, b));
   1.653 +    } else if (SkScalarAbs(b) > SkScalarAbs(a)) {
   1.654 +        SkScalar t = a / b;
   1.655 +        SkScalar u = SkDoubleToScalar(_copysign(SkScalarSqrt(SK_Scalar1 + t*t), b));
   1.656 +        s = -1 / u;
   1.657 +        c = -s * t;
   1.658 +    } else {
   1.659 +        SkScalar t = b / a;
   1.660 +        SkScalar u = SkDoubleToScalar(_copysign(SkScalarSqrt(SK_Scalar1 + t*t), a));
   1.661 +        c = 1 / u;
   1.662 +        s = -c * t;
   1.663 +    }
   1.664 +
   1.665 +    // G is the Given's Matrix for A (rotational matrix such that GA[0][1] == 0).
   1.666 +    SkMatrix G;
   1.667 +    G.setAll(c, -s, 0,
   1.668 +             s,  c, 0,
   1.669 +             0,  0, SkScalarToPersp(SK_Scalar1));
   1.670 +
   1.671 +    // GA is the matrix A with rotation removed.
   1.672 +    SkMatrix GA(G);
   1.673 +    GA.preConcat(A);
   1.674 +
   1.675 +    // realTextSize is the actual device size we want (as opposed to the size the user requested).
   1.676 +    // gdiTextSide is the size we request from GDI.
   1.677 +    // If the scale is negative, this means the matrix will do the flip anyway.
   1.678 +    SkScalar realTextSize = SkScalarAbs(GA.get(SkMatrix::kMScaleY));
   1.679 +    SkScalar gdiTextSize = SkScalarRoundToScalar(realTextSize);
   1.680 +    if (gdiTextSize == 0) {
   1.681 +        gdiTextSize = SK_Scalar1;
   1.682 +    }
   1.683 +
   1.684 +    // When not hinting, remove only the gdiTextSize scale which will be applied by GDI.
   1.685 +    // When GDI hinting, remove the entire Y scale to prevent 'subpixel' metrics.
   1.686 +    SkScalar scale = (fRec.getHinting() == SkPaint::kNo_Hinting ||
   1.687 +                      fRec.getHinting() == SkPaint::kSlight_Hinting)
   1.688 +                   ? SkScalarInvert(gdiTextSize)
   1.689 +                   : SkScalarInvert(realTextSize);
   1.690 +
   1.691 +    // sA is the total matrix A without the textSize (so GDI knows the text size separately).
   1.692 +    // When this matrix is used with GetGlyphOutline, no further processing is needed.
   1.693 +    SkMatrix sA(A);
   1.694 +    sA.preScale(scale, scale); //remove text size
   1.695 +
   1.696 +    // GsA is the non-rotational part of A without the text height scale.
   1.697 +    // This is what is used to find the magnitude of advances.
   1.698 +    SkMatrix GsA(GA);
   1.699 +    GsA.preScale(scale, scale); //remove text size, G is rotational so reorders with the scale.
   1.700 +
   1.701 +    fGsA.eM11 = SkScalarToFIXED(GsA.get(SkMatrix::kMScaleX));
   1.702 +    fGsA.eM12 = SkScalarToFIXED(-GsA.get(SkMatrix::kMSkewY)); // This should be ~0.
   1.703 +    fGsA.eM21 = SkScalarToFIXED(-GsA.get(SkMatrix::kMSkewX));
   1.704 +    fGsA.eM22 = SkScalarToFIXED(GsA.get(SkMatrix::kMScaleY));
   1.705 +
   1.706 +    // fG_inv is G inverse, which is fairly simple since G is 2x2 rotational.
   1.707 +    fG_inv.setAll(G.get(SkMatrix::kMScaleX), -G.get(SkMatrix::kMSkewX), G.get(SkMatrix::kMTransX),
   1.708 +                  -G.get(SkMatrix::kMSkewY), G.get(SkMatrix::kMScaleY), G.get(SkMatrix::kMTransY),
   1.709 +                  G.get(SkMatrix::kMPersp0), G.get(SkMatrix::kMPersp1), G.get(SkMatrix::kMPersp2));
   1.710 +
   1.711 +    LOGFONT lf = typeface->fLogFont;
   1.712 +    lf.lfHeight = -SkScalarTruncToInt(gdiTextSize);
   1.713 +    lf.lfQuality = compute_quality(fRec);
   1.714 +    fFont = CreateFontIndirect(&lf);
   1.715 +    if (!fFont) {
   1.716 +        return;
   1.717 +    }
   1.718 +
   1.719 +    fSavefont = (HFONT)SelectObject(fDDC, fFont);
   1.720 +
   1.721 +    if (0 == GetTextMetrics(fDDC, &fTM)) {
   1.722 +        call_ensure_accessible(lf);
   1.723 +        if (0 == GetTextMetrics(fDDC, &fTM)) {
   1.724 +            fTM.tmPitchAndFamily = TMPF_TRUETYPE;
   1.725 +        }
   1.726 +    }
   1.727 +
   1.728 +    XFORM xform;
   1.729 +    if (fTM.tmPitchAndFamily & TMPF_VECTOR) {
   1.730 +        // Used a logfont on a memory context, should never get a device font.
   1.731 +        // Therefore all TMPF_DEVICE will be PostScript fonts.
   1.732 +
   1.733 +        // If TMPF_VECTOR is set, one of TMPF_TRUETYPE or TMPF_DEVICE means that
   1.734 +        // we have an outline font. Otherwise we have a vector FON, which is
   1.735 +        // scalable, but not an outline font.
   1.736 +        // This was determined by testing with Type1 PFM/PFB and
   1.737 +        // OpenTypeCFF OTF, as well as looking at Wine bugs and sources.
   1.738 +        if (fTM.tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_DEVICE)) {
   1.739 +            // Truetype or PostScript.
   1.740 +            fType = SkScalerContext_GDI::kTrueType_Type;
   1.741 +        } else {
   1.742 +            // Stroked FON.
   1.743 +            fType = SkScalerContext_GDI::kLine_Type;
   1.744 +        }
   1.745 +
   1.746 +        // fPost2x2 is column-major, left handed (y down).
   1.747 +        // XFORM 2x2 is row-major, left handed (y down).
   1.748 +        xform.eM11 = SkScalarToFloat(sA.get(SkMatrix::kMScaleX));
   1.749 +        xform.eM12 = SkScalarToFloat(sA.get(SkMatrix::kMSkewY));
   1.750 +        xform.eM21 = SkScalarToFloat(sA.get(SkMatrix::kMSkewX));
   1.751 +        xform.eM22 = SkScalarToFloat(sA.get(SkMatrix::kMScaleY));
   1.752 +        xform.eDx = 0;
   1.753 +        xform.eDy = 0;
   1.754 +
   1.755 +        // MAT2 is row major, right handed (y up).
   1.756 +        fMat22.eM11 = float2FIXED(xform.eM11);
   1.757 +        fMat22.eM12 = float2FIXED(-xform.eM12);
   1.758 +        fMat22.eM21 = float2FIXED(-xform.eM21);
   1.759 +        fMat22.eM22 = float2FIXED(xform.eM22);
   1.760 +
   1.761 +        if (needToRenderWithSkia(fRec)) {
   1.762 +            this->forceGenerateImageFromPath();
   1.763 +        }
   1.764 +
   1.765 +        // Create a hires matrix if we need linear metrics.
   1.766 +        if (this->isSubpixel()) {
   1.767 +            OUTLINETEXTMETRIC otm;
   1.768 +            UINT success = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm);
   1.769 +            if (0 == success) {
   1.770 +                call_ensure_accessible(lf);
   1.771 +                success = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm);
   1.772 +            }
   1.773 +            if (0 != success) {
   1.774 +                SkScalar upem = SkIntToScalar(otm.otmEMSquare);
   1.775 +
   1.776 +                SkScalar gdiTextSizeToEMScale = upem / gdiTextSize;
   1.777 +                fHighResMat22.eM11 = float2FIXED(gdiTextSizeToEMScale);
   1.778 +                fHighResMat22.eM12 = float2FIXED(0);
   1.779 +                fHighResMat22.eM21 = float2FIXED(0);
   1.780 +                fHighResMat22.eM22 = float2FIXED(gdiTextSizeToEMScale);
   1.781 +
   1.782 +                SkScalar removeEMScale = SkScalarInvert(upem);
   1.783 +                fHiResMatrix = A;
   1.784 +                fHiResMatrix.preScale(removeEMScale, removeEMScale);
   1.785 +            }
   1.786 +        }
   1.787 +
   1.788 +    } else {
   1.789 +        // Assume bitmap
   1.790 +        fType = SkScalerContext_GDI::kBitmap_Type;
   1.791 +
   1.792 +        xform.eM11 = 1.0f;
   1.793 +        xform.eM12 = 0.0f;
   1.794 +        xform.eM21 = 0.0f;
   1.795 +        xform.eM22 = 1.0f;
   1.796 +        xform.eDx = 0.0f;
   1.797 +        xform.eDy = 0.0f;
   1.798 +
   1.799 +        // fPost2x2 is column-major, left handed (y down).
   1.800 +        // MAT2 is row major, right handed (y up).
   1.801 +        fMat22.eM11 = SkScalarToFIXED(fRec.fPost2x2[0][0]);
   1.802 +        fMat22.eM12 = SkScalarToFIXED(-fRec.fPost2x2[1][0]);
   1.803 +        fMat22.eM21 = SkScalarToFIXED(-fRec.fPost2x2[0][1]);
   1.804 +        fMat22.eM22 = SkScalarToFIXED(fRec.fPost2x2[1][1]);
   1.805 +    }
   1.806 +
   1.807 +    fOffscreen.init(fFont, xform);
   1.808 +}
   1.809 +
   1.810 +SkScalerContext_GDI::~SkScalerContext_GDI() {
   1.811 +    if (fDDC) {
   1.812 +        ::SelectObject(fDDC, fSavefont);
   1.813 +        ::DeleteDC(fDDC);
   1.814 +    }
   1.815 +    if (fFont) {
   1.816 +        ::DeleteObject(fFont);
   1.817 +    }
   1.818 +    if (fSC) {
   1.819 +        ::ScriptFreeCache(&fSC);
   1.820 +    }
   1.821 +}
   1.822 +
   1.823 +bool SkScalerContext_GDI::isValid() const {
   1.824 +    return fDDC && fFont;
   1.825 +}
   1.826 +
   1.827 +unsigned SkScalerContext_GDI::generateGlyphCount() {
   1.828 +    if (fGlyphCount < 0) {
   1.829 +        fGlyphCount = calculateGlyphCount(
   1.830 +                          fDDC, static_cast<const LogFontTypeface*>(this->getTypeface())->fLogFont);
   1.831 +    }
   1.832 +    return fGlyphCount;
   1.833 +}
   1.834 +
   1.835 +uint16_t SkScalerContext_GDI::generateCharToGlyph(SkUnichar utf32) {
   1.836 +    uint16_t index = 0;
   1.837 +    WCHAR utf16[2];
   1.838 +    // TODO(ctguil): Support characters that generate more than one glyph.
   1.839 +    if (SkUTF16_FromUnichar(utf32, (uint16_t*)utf16) == 1) {
   1.840 +        // Type1 fonts fail with uniscribe API. Use GetGlyphIndices for plane 0.
   1.841 +
   1.842 +        /** Real documentation for GetGlyphIndiciesW:
   1.843 +         *
   1.844 +         *  When GGI_MARK_NONEXISTING_GLYPHS is not specified and a character does not map to a
   1.845 +         *  glyph, then the 'default character's glyph is returned instead. The 'default character'
   1.846 +         *  is available in fTM.tmDefaultChar. FON fonts have a default character, and there exists
   1.847 +         *  a usDefaultChar in the 'OS/2' table, version 2 and later. If there is no
   1.848 +         *  'default character' specified by the font, then often the first character found is used.
   1.849 +         *
   1.850 +         *  When GGI_MARK_NONEXISTING_GLYPHS is specified and a character does not map to a glyph,
   1.851 +         *  then the glyph 0xFFFF is used. In Windows XP and earlier, Bitmap/Vector FON usually use
   1.852 +         *  glyph 0x1F instead ('Terminal' appears to be special, returning 0xFFFF).
   1.853 +         *  Type1 PFM/PFB, TT, OT TT, OT CFF all appear to use 0xFFFF, even on XP.
   1.854 +         */
   1.855 +        DWORD result = GetGlyphIndicesW(fDDC, utf16, 1, &index, GGI_MARK_NONEXISTING_GLYPHS);
   1.856 +        if (result == GDI_ERROR
   1.857 +            || 0xFFFF == index
   1.858 +            || (0x1F == index &&
   1.859 +               (fType == SkScalerContext_GDI::kBitmap_Type ||
   1.860 +                fType == SkScalerContext_GDI::kLine_Type)
   1.861 +               /*&& winVer < Vista */)
   1.862 +           )
   1.863 +        {
   1.864 +            index = 0;
   1.865 +        }
   1.866 +    } else {
   1.867 +        // Use uniscribe to detemine glyph index for non-BMP characters.
   1.868 +        static const int numWCHAR = 2;
   1.869 +        static const int maxItems = 2;
   1.870 +        // MSDN states that this can be NULL, but some things don't work then.
   1.871 +        SCRIPT_CONTROL sc = { 0 };
   1.872 +        // Add extra item to SCRIPT_ITEM to work around a bug (now documented).
   1.873 +        // https://bugzilla.mozilla.org/show_bug.cgi?id=366643
   1.874 +        SCRIPT_ITEM si[maxItems + 1];
   1.875 +        int numItems;
   1.876 +        HRZM(ScriptItemize(utf16, numWCHAR, maxItems, &sc, NULL, si, &numItems),
   1.877 +             "Could not itemize character.");
   1.878 +
   1.879 +        // Sometimes ScriptShape cannot find a glyph for a non-BMP and returns 2 space glyphs.
   1.880 +        static const int maxGlyphs = 2;
   1.881 +        SCRIPT_VISATTR vsa[maxGlyphs];
   1.882 +        WORD outGlyphs[maxGlyphs];
   1.883 +        WORD logClust[numWCHAR];
   1.884 +        int numGlyphs;
   1.885 +        HRZM(ScriptShape(fDDC, &fSC, utf16, numWCHAR, maxGlyphs, &si[0].a,
   1.886 +                         outGlyphs, logClust, vsa, &numGlyphs),
   1.887 +             "Could not shape character.");
   1.888 +        if (1 == numGlyphs) {
   1.889 +            index = outGlyphs[0];
   1.890 +        }
   1.891 +    }
   1.892 +    return index;
   1.893 +}
   1.894 +
   1.895 +void SkScalerContext_GDI::generateAdvance(SkGlyph* glyph) {
   1.896 +    this->generateMetrics(glyph);
   1.897 +}
   1.898 +
   1.899 +void SkScalerContext_GDI::generateMetrics(SkGlyph* glyph) {
   1.900 +    SkASSERT(fDDC);
   1.901 +
   1.902 +    if (fType == SkScalerContext_GDI::kBitmap_Type || fType == SkScalerContext_GDI::kLine_Type) {
   1.903 +        SIZE size;
   1.904 +        WORD glyphs = glyph->getGlyphID(0);
   1.905 +        if (0 == GetTextExtentPointI(fDDC, &glyphs, 1, &size)) {
   1.906 +            glyph->fWidth = SkToS16(fTM.tmMaxCharWidth);
   1.907 +        } else {
   1.908 +            glyph->fWidth = SkToS16(size.cx);
   1.909 +        }
   1.910 +        glyph->fHeight = SkToS16(size.cy);
   1.911 +
   1.912 +        glyph->fTop = SkToS16(-fTM.tmAscent);
   1.913 +        // Bitmap FON cannot underhang, but vector FON may.
   1.914 +        // There appears no means of determining underhang of vector FON.
   1.915 +        glyph->fLeft = SkToS16(0);
   1.916 +        glyph->fAdvanceX = SkIntToFixed(glyph->fWidth);
   1.917 +        glyph->fAdvanceY = 0;
   1.918 +
   1.919 +        // Vector FON will transform nicely, but bitmap FON do not.
   1.920 +        if (fType == SkScalerContext_GDI::kLine_Type) {
   1.921 +            SkRect bounds = SkRect::MakeXYWH(glyph->fLeft, glyph->fTop,
   1.922 +                                             glyph->fWidth, glyph->fHeight);
   1.923 +            SkMatrix m;
   1.924 +            m.setAll(SkFIXEDToScalar(fMat22.eM11), -SkFIXEDToScalar(fMat22.eM21), 0,
   1.925 +                     -SkFIXEDToScalar(fMat22.eM12), SkFIXEDToScalar(fMat22.eM22), 0,
   1.926 +                     0,  0, SkScalarToPersp(SK_Scalar1));
   1.927 +            m.mapRect(&bounds);
   1.928 +            bounds.roundOut();
   1.929 +            glyph->fLeft = SkScalarTruncToInt(bounds.fLeft);
   1.930 +            glyph->fTop = SkScalarTruncToInt(bounds.fTop);
   1.931 +            glyph->fWidth = SkScalarTruncToInt(bounds.width());
   1.932 +            glyph->fHeight = SkScalarTruncToInt(bounds.height());
   1.933 +        }
   1.934 +
   1.935 +        // Apply matrix to advance.
   1.936 +        glyph->fAdvanceY = SkFixedMul(-SkFIXEDToFixed(fMat22.eM12), glyph->fAdvanceX);
   1.937 +        glyph->fAdvanceX = SkFixedMul(SkFIXEDToFixed(fMat22.eM11), glyph->fAdvanceX);
   1.938 +
   1.939 +        return;
   1.940 +    }
   1.941 +
   1.942 +    UINT glyphId = glyph->getGlyphID(0);
   1.943 +
   1.944 +    GLYPHMETRICS gm;
   1.945 +    sk_bzero(&gm, sizeof(gm));
   1.946 +
   1.947 +    DWORD status = GetGlyphOutlineW(fDDC, glyphId, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &fMat22);
   1.948 +    if (GDI_ERROR == status) {
   1.949 +        LogFontTypeface::EnsureAccessible(this->getTypeface());
   1.950 +        status = GetGlyphOutlineW(fDDC, glyphId, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &fMat22);
   1.951 +        if (GDI_ERROR == status) {
   1.952 +            glyph->zeroMetrics();
   1.953 +            return;
   1.954 +        }
   1.955 +    }
   1.956 +
   1.957 +    bool empty = false;
   1.958 +    // The black box is either the embedded bitmap size or the outline extent.
   1.959 +    // It is 1x1 if nothing is to be drawn, but will also be 1x1 if something very small
   1.960 +    // is to be drawn, like a '.'. We need to outset '.' but do not wish to outset ' '.
   1.961 +    if (1 == gm.gmBlackBoxX && 1 == gm.gmBlackBoxY) {
   1.962 +        // If GetGlyphOutline with GGO_NATIVE returns 0, we know there was no outline.
   1.963 +        DWORD bufferSize = GetGlyphOutlineW(fDDC, glyphId, GGO_NATIVE | GGO_GLYPH_INDEX, &gm, 0, NULL, &fMat22);
   1.964 +        empty = (0 == bufferSize);
   1.965 +    }
   1.966 +
   1.967 +    glyph->fTop = SkToS16(-gm.gmptGlyphOrigin.y);
   1.968 +    glyph->fLeft = SkToS16(gm.gmptGlyphOrigin.x);
   1.969 +    if (empty) {
   1.970 +        glyph->fWidth = 0;
   1.971 +        glyph->fHeight = 0;
   1.972 +    } else {
   1.973 +        // Outset, since the image may bleed out of the black box.
   1.974 +        // For embedded bitmaps the black box should be exact.
   1.975 +        // For outlines we need to outset by 1 in all directions for bleed.
   1.976 +        // For ClearType we need to outset by 2 for bleed.
   1.977 +        glyph->fWidth = gm.gmBlackBoxX + 4;
   1.978 +        glyph->fHeight = gm.gmBlackBoxY + 4;
   1.979 +        glyph->fTop -= 2;
   1.980 +        glyph->fLeft -= 2;
   1.981 +    }
   1.982 +    glyph->fAdvanceX = SkIntToFixed(gm.gmCellIncX);
   1.983 +    glyph->fAdvanceY = SkIntToFixed(gm.gmCellIncY);
   1.984 +    glyph->fRsbDelta = 0;
   1.985 +    glyph->fLsbDelta = 0;
   1.986 +
   1.987 +    if (this->isSubpixel()) {
   1.988 +        sk_bzero(&gm, sizeof(gm));
   1.989 +        status = GetGlyphOutlineW(fDDC, glyphId, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &fHighResMat22);
   1.990 +        if (GDI_ERROR != status) {
   1.991 +            SkPoint advance;
   1.992 +            fHiResMatrix.mapXY(SkIntToScalar(gm.gmCellIncX), SkIntToScalar(gm.gmCellIncY), &advance);
   1.993 +            glyph->fAdvanceX = SkScalarToFixed(advance.fX);
   1.994 +            glyph->fAdvanceY = SkScalarToFixed(advance.fY);
   1.995 +        }
   1.996 +    } else if (!isAxisAligned(this->fRec)) {
   1.997 +        status = GetGlyphOutlineW(fDDC, glyphId, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &fGsA);
   1.998 +        if (GDI_ERROR != status) {
   1.999 +            SkPoint advance;
  1.1000 +            fG_inv.mapXY(SkIntToScalar(gm.gmCellIncX), SkIntToScalar(gm.gmCellIncY), &advance);
  1.1001 +            glyph->fAdvanceX = SkScalarToFixed(advance.fX);
  1.1002 +            glyph->fAdvanceY = SkScalarToFixed(advance.fY);
  1.1003 +        }
  1.1004 +    }
  1.1005 +}
  1.1006 +
  1.1007 +static const MAT2 gMat2Identity = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
  1.1008 +void SkScalerContext_GDI::generateFontMetrics(SkPaint::FontMetrics* mx, SkPaint::FontMetrics* my) {
  1.1009 +    if (!(mx || my)) {
  1.1010 +      return;
  1.1011 +    }
  1.1012 +
  1.1013 +    if (mx) {
  1.1014 +        sk_bzero(mx, sizeof(*mx));
  1.1015 +    }
  1.1016 +    if (my) {
  1.1017 +        sk_bzero(my, sizeof(*my));
  1.1018 +    }
  1.1019 +
  1.1020 +    SkASSERT(fDDC);
  1.1021 +
  1.1022 +#ifndef SK_GDI_ALWAYS_USE_TEXTMETRICS_FOR_FONT_METRICS
  1.1023 +    if (fType == SkScalerContext_GDI::kBitmap_Type || fType == SkScalerContext_GDI::kLine_Type) {
  1.1024 +#endif
  1.1025 +        if (mx) {
  1.1026 +            mx->fTop = SkIntToScalar(-fTM.tmAscent);
  1.1027 +            mx->fAscent = SkIntToScalar(-fTM.tmAscent);
  1.1028 +            mx->fDescent = SkIntToScalar(fTM.tmDescent);
  1.1029 +            mx->fBottom = SkIntToScalar(fTM.tmDescent);
  1.1030 +            mx->fLeading = SkIntToScalar(fTM.tmExternalLeading);
  1.1031 +        }
  1.1032 +
  1.1033 +        if (my) {
  1.1034 +            my->fTop = SkIntToScalar(-fTM.tmAscent);
  1.1035 +            my->fAscent = SkIntToScalar(-fTM.tmAscent);
  1.1036 +            my->fDescent = SkIntToScalar(fTM.tmDescent);
  1.1037 +            my->fBottom = SkIntToScalar(fTM.tmDescent);
  1.1038 +            my->fLeading = SkIntToScalar(fTM.tmExternalLeading);
  1.1039 +            my->fAvgCharWidth = SkIntToScalar(fTM.tmAveCharWidth);
  1.1040 +            my->fMaxCharWidth = SkIntToScalar(fTM.tmMaxCharWidth);
  1.1041 +            my->fXMin = 0;
  1.1042 +            my->fXMax = my->fMaxCharWidth;
  1.1043 +            //my->fXHeight = 0;
  1.1044 +        }
  1.1045 +#ifndef SK_GDI_ALWAYS_USE_TEXTMETRICS_FOR_FONT_METRICS
  1.1046 +        return;
  1.1047 +    }
  1.1048 +#endif
  1.1049 +
  1.1050 +    OUTLINETEXTMETRIC otm;
  1.1051 +
  1.1052 +    uint32_t ret = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm);
  1.1053 +    if (0 == ret) {
  1.1054 +        LogFontTypeface::EnsureAccessible(this->getTypeface());
  1.1055 +        ret = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm);
  1.1056 +    }
  1.1057 +    if (0 == ret) {
  1.1058 +        return;
  1.1059 +    }
  1.1060 +
  1.1061 +    if (mx) {
  1.1062 +        mx->fTop = SkIntToScalar(-otm.otmrcFontBox.left);
  1.1063 +        mx->fAscent = SkIntToScalar(-otm.otmAscent);
  1.1064 +        mx->fDescent = SkIntToScalar(-otm.otmDescent);
  1.1065 +        mx->fBottom = SkIntToScalar(otm.otmrcFontBox.right);
  1.1066 +        mx->fLeading = SkIntToScalar(otm.otmLineGap);
  1.1067 +        mx->fUnderlineThickness = SkIntToScalar(otm.otmsUnderscoreSize);
  1.1068 +        mx->fUnderlinePosition = -SkIntToScalar(otm.otmsUnderscorePosition);
  1.1069 +
  1.1070 +        mx->fFlags |= SkPaint::FontMetrics::kUnderlineThinknessIsValid_Flag;
  1.1071 +        mx->fFlags |= SkPaint::FontMetrics::kUnderlinePositionIsValid_Flag;
  1.1072 +    }
  1.1073 +
  1.1074 +    if (my) {
  1.1075 +#ifndef SK_GDI_ALWAYS_USE_TEXTMETRICS_FOR_FONT_METRICS
  1.1076 +        my->fTop = SkIntToScalar(-otm.otmrcFontBox.top);
  1.1077 +        my->fAscent = SkIntToScalar(-otm.otmAscent);
  1.1078 +        my->fDescent = SkIntToScalar(-otm.otmDescent);
  1.1079 +        my->fBottom = SkIntToScalar(-otm.otmrcFontBox.bottom);
  1.1080 +        my->fLeading = SkIntToScalar(otm.otmLineGap);
  1.1081 +        my->fAvgCharWidth = SkIntToScalar(otm.otmTextMetrics.tmAveCharWidth);
  1.1082 +        my->fMaxCharWidth = SkIntToScalar(otm.otmTextMetrics.tmMaxCharWidth);
  1.1083 +        my->fXMin = SkIntToScalar(otm.otmrcFontBox.left);
  1.1084 +        my->fXMax = SkIntToScalar(otm.otmrcFontBox.right);
  1.1085 +        my->fUnderlineThickness = SkIntToScalar(otm.otmsUnderscoreSize);
  1.1086 +        my->fUnderlinePosition = -SkIntToScalar(otm.otmsUnderscorePosition);
  1.1087 +
  1.1088 +        my->fFlags |= SkPaint::FontMetrics::kUnderlineThinknessIsValid_Flag;
  1.1089 +        my->fFlags |= SkPaint::FontMetrics::kUnderlinePositionIsValid_Flag;
  1.1090 +#endif
  1.1091 +        my->fXHeight = SkIntToScalar(otm.otmsXHeight);
  1.1092 +
  1.1093 +        GLYPHMETRICS gm;
  1.1094 +        sk_bzero(&gm, sizeof(gm));
  1.1095 +        DWORD len = GetGlyphOutlineW(fDDC, 'x', GGO_METRICS, &gm, 0, 0, &gMat2Identity);
  1.1096 +        if (len != GDI_ERROR && gm.gmBlackBoxY > 0) {
  1.1097 +            my->fXHeight = SkIntToScalar(gm.gmBlackBoxY);
  1.1098 +        }
  1.1099 +    }
  1.1100 +}
  1.1101 +
  1.1102 +////////////////////////////////////////////////////////////////////////////////////////
  1.1103 +
  1.1104 +#define SK_SHOW_TEXT_BLIT_COVERAGE 0
  1.1105 +
  1.1106 +static void build_power_table(uint8_t table[], float ee) {
  1.1107 +    for (int i = 0; i < 256; i++) {
  1.1108 +        float x = i / 255.f;
  1.1109 +        x = sk_float_pow(x, ee);
  1.1110 +        int xx = SkScalarRoundToInt(x * 255);
  1.1111 +        table[i] = SkToU8(xx);
  1.1112 +    }
  1.1113 +}
  1.1114 +
  1.1115 +/**
  1.1116 + *  This will invert the gamma applied by GDI (gray-scale antialiased), so we
  1.1117 + *  can get linear values.
  1.1118 + *
  1.1119 + *  GDI grayscale appears to use a hard-coded gamma of 2.3.
  1.1120 + *
  1.1121 + *  GDI grayscale appears to draw using the black and white rasterizer at four
  1.1122 + *  times the size and then downsamples to compute the coverage mask. As a
  1.1123 + *  result there are only seventeen total grays. This lack of fidelity means
  1.1124 + *  that shifting into other color spaces is imprecise.
  1.1125 + */
  1.1126 +static const uint8_t* getInverseGammaTableGDI() {
  1.1127 +    // Since build_power_table is idempotent, many threads can build gTableGdi
  1.1128 +    // simultaneously.
  1.1129 +
  1.1130 +    // Microsoft Specific:
  1.1131 +    // Making gInited volatile provides read-aquire and write-release in vc++.
  1.1132 +    // In VS2012, see compiler option /volatile:(ms|iso).
  1.1133 +    // Replace with C++11 atomics when possible.
  1.1134 +    static volatile bool gInited;
  1.1135 +    static uint8_t gTableGdi[256];
  1.1136 +    if (gInited) {
  1.1137 +        // Need a L/L (read) barrier (full acquire not needed). If gInited is observed
  1.1138 +        // true then gTableGdi is observable, but it must be requested.
  1.1139 +    } else {
  1.1140 +        build_power_table(gTableGdi, 2.3f);
  1.1141 +        // Need a S/S (write) barrier (full release not needed) here so that this
  1.1142 +        // write to gInited becomes observable after gTableGdi.
  1.1143 +        gInited = true;
  1.1144 +    }
  1.1145 +    return gTableGdi;
  1.1146 +}
  1.1147 +
  1.1148 +/**
  1.1149 + *  This will invert the gamma applied by GDI ClearType, so we can get linear
  1.1150 + *  values.
  1.1151 + *
  1.1152 + *  GDI ClearType uses SPI_GETFONTSMOOTHINGCONTRAST / 1000 as the gamma value.
  1.1153 + *  If this value is not specified, the default is a gamma of 1.4.
  1.1154 + */
  1.1155 +static const uint8_t* getInverseGammaTableClearType() {
  1.1156 +    // We don't expect SPI_GETFONTSMOOTHINGCONTRAST to ever change, so building
  1.1157 +    // gTableClearType with build_power_table is effectively idempotent.
  1.1158 +
  1.1159 +    // Microsoft Specific:
  1.1160 +    // Making gInited volatile provides read-aquire and write-release in vc++.
  1.1161 +    // In VS2012, see compiler option /volatile:(ms|iso).
  1.1162 +    // Replace with C++11 atomics when possible.
  1.1163 +    static volatile bool gInited;
  1.1164 +    static uint8_t gTableClearType[256];
  1.1165 +    if (gInited) {
  1.1166 +        // Need a L/L (read) barrier (acquire not needed). If gInited is observed
  1.1167 +        // true then gTableClearType is observable, but it must be requested.
  1.1168 +    } else {
  1.1169 +        UINT level = 0;
  1.1170 +        if (!SystemParametersInfo(SPI_GETFONTSMOOTHINGCONTRAST, 0, &level, 0) || !level) {
  1.1171 +            // can't get the data, so use a default
  1.1172 +            level = 1400;
  1.1173 +        }
  1.1174 +        build_power_table(gTableClearType, level / 1000.0f);
  1.1175 +        // Need a S/S (write) barrier (release not needed) here so that this
  1.1176 +        // write to gInited becomes observable after gTableClearType.
  1.1177 +        gInited = true;
  1.1178 +    }
  1.1179 +    return gTableClearType;
  1.1180 +}
  1.1181 +
  1.1182 +#include "SkColorPriv.h"
  1.1183 +
  1.1184 +//Cannot assume that the input rgb is gray due to possible setting of kGenA8FromLCD_Flag.
  1.1185 +template<bool APPLY_PREBLEND>
  1.1186 +static inline uint8_t rgb_to_a8(SkGdiRGB rgb, const uint8_t* table8) {
  1.1187 +    U8CPU r = (rgb >> 16) & 0xFF;
  1.1188 +    U8CPU g = (rgb >>  8) & 0xFF;
  1.1189 +    U8CPU b = (rgb >>  0) & 0xFF;
  1.1190 +    return sk_apply_lut_if<APPLY_PREBLEND>(SkComputeLuminance(r, g, b), table8);
  1.1191 +}
  1.1192 +
  1.1193 +template<bool APPLY_PREBLEND>
  1.1194 +static inline uint16_t rgb_to_lcd16(SkGdiRGB rgb, const uint8_t* tableR,
  1.1195 +                                                  const uint8_t* tableG,
  1.1196 +                                                  const uint8_t* tableB) {
  1.1197 +    U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 16) & 0xFF, tableR);
  1.1198 +    U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>((rgb >>  8) & 0xFF, tableG);
  1.1199 +    U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>((rgb >>  0) & 0xFF, tableB);
  1.1200 +#if SK_SHOW_TEXT_BLIT_COVERAGE
  1.1201 +    r = SkMax32(r, 10); g = SkMax32(g, 10); b = SkMax32(b, 10);
  1.1202 +#endif
  1.1203 +    return SkPack888ToRGB16(r, g, b);
  1.1204 +}
  1.1205 +
  1.1206 +template<bool APPLY_PREBLEND>
  1.1207 +static inline SkPMColor rgb_to_lcd32(SkGdiRGB rgb, const uint8_t* tableR,
  1.1208 +                                                   const uint8_t* tableG,
  1.1209 +                                                   const uint8_t* tableB) {
  1.1210 +    U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 16) & 0xFF, tableR);
  1.1211 +    U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>((rgb >>  8) & 0xFF, tableG);
  1.1212 +    U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>((rgb >>  0) & 0xFF, tableB);
  1.1213 +#if SK_SHOW_TEXT_BLIT_COVERAGE
  1.1214 +    r = SkMax32(r, 10); g = SkMax32(g, 10); b = SkMax32(b, 10);
  1.1215 +#endif
  1.1216 +    return SkPackARGB32(0xFF, r, g, b);
  1.1217 +}
  1.1218 +
  1.1219 +// Is this GDI color neither black nor white? If so, we have to keep this
  1.1220 +// image as is, rather than smashing it down to a BW mask.
  1.1221 +//
  1.1222 +// returns int instead of bool, since we don't want/have to pay to convert
  1.1223 +// the zero/non-zero value into a bool
  1.1224 +static int is_not_black_or_white(SkGdiRGB c) {
  1.1225 +    // same as (but faster than)
  1.1226 +    //      c &= 0x00FFFFFF;
  1.1227 +    //      return 0 == c || 0x00FFFFFF == c;
  1.1228 +    return (c + (c & 1)) & 0x00FFFFFF;
  1.1229 +}
  1.1230 +
  1.1231 +static bool is_rgb_really_bw(const SkGdiRGB* src, int width, int height, size_t srcRB) {
  1.1232 +    for (int y = 0; y < height; ++y) {
  1.1233 +        for (int x = 0; x < width; ++x) {
  1.1234 +            if (is_not_black_or_white(src[x])) {
  1.1235 +                return false;
  1.1236 +            }
  1.1237 +        }
  1.1238 +        src = SkTAddOffset<const SkGdiRGB>(src, srcRB);
  1.1239 +    }
  1.1240 +    return true;
  1.1241 +}
  1.1242 +
  1.1243 +// gdi's bitmap is upside-down, so we reverse dst walking in Y
  1.1244 +// whenever we copy it into skia's buffer
  1.1245 +static void rgb_to_bw(const SkGdiRGB* SK_RESTRICT src, size_t srcRB,
  1.1246 +                      const SkGlyph& glyph) {
  1.1247 +    const int width = glyph.fWidth;
  1.1248 +    const size_t dstRB = (width + 7) >> 3;
  1.1249 +    uint8_t* SK_RESTRICT dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
  1.1250 +
  1.1251 +    int byteCount = width >> 3;
  1.1252 +    int bitCount = width & 7;
  1.1253 +
  1.1254 +    // adjust srcRB to skip the values in our byteCount loop,
  1.1255 +    // since we increment src locally there
  1.1256 +    srcRB -= byteCount * 8 * sizeof(SkGdiRGB);
  1.1257 +
  1.1258 +    for (int y = 0; y < glyph.fHeight; ++y) {
  1.1259 +        if (byteCount > 0) {
  1.1260 +            for (int i = 0; i < byteCount; ++i) {
  1.1261 +                unsigned byte = 0;
  1.1262 +                byte |= src[0] & (1 << 7);
  1.1263 +                byte |= src[1] & (1 << 6);
  1.1264 +                byte |= src[2] & (1 << 5);
  1.1265 +                byte |= src[3] & (1 << 4);
  1.1266 +                byte |= src[4] & (1 << 3);
  1.1267 +                byte |= src[5] & (1 << 2);
  1.1268 +                byte |= src[6] & (1 << 1);
  1.1269 +                byte |= src[7] & (1 << 0);
  1.1270 +                dst[i] = byte;
  1.1271 +                src += 8;
  1.1272 +            }
  1.1273 +        }
  1.1274 +        if (bitCount > 0) {
  1.1275 +            unsigned byte = 0;
  1.1276 +            unsigned mask = 0x80;
  1.1277 +            for (int i = 0; i < bitCount; i++) {
  1.1278 +                byte |= src[i] & mask;
  1.1279 +                mask >>= 1;
  1.1280 +            }
  1.1281 +            dst[byteCount] = byte;
  1.1282 +        }
  1.1283 +        src = SkTAddOffset<const SkGdiRGB>(src, srcRB);
  1.1284 +        dst -= dstRB;
  1.1285 +    }
  1.1286 +#if SK_SHOW_TEXT_BLIT_COVERAGE
  1.1287 +    if (glyph.fWidth > 0 && glyph.fHeight > 0) {
  1.1288 +        uint8_t* first = (uint8_t*)glyph.fImage;
  1.1289 +        uint8_t* last = (uint8_t*)((char*)glyph.fImage + glyph.fHeight * dstRB - 1);
  1.1290 +        *first |= 1 << 7;
  1.1291 +        *last |= bitCount == 0 ? 1 : 1 << (8 - bitCount);
  1.1292 +    }
  1.1293 +#endif
  1.1294 +}
  1.1295 +
  1.1296 +template<bool APPLY_PREBLEND>
  1.1297 +static void rgb_to_a8(const SkGdiRGB* SK_RESTRICT src, size_t srcRB,
  1.1298 +                      const SkGlyph& glyph, const uint8_t* table8) {
  1.1299 +    const size_t dstRB = glyph.rowBytes();
  1.1300 +    const int width = glyph.fWidth;
  1.1301 +    uint8_t* SK_RESTRICT dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
  1.1302 +
  1.1303 +    for (int y = 0; y < glyph.fHeight; y++) {
  1.1304 +        for (int i = 0; i < width; i++) {
  1.1305 +            dst[i] = rgb_to_a8<APPLY_PREBLEND>(src[i], table8);
  1.1306 +#if SK_SHOW_TEXT_BLIT_COVERAGE
  1.1307 +            dst[i] = SkMax32(dst[i], 10);
  1.1308 +#endif
  1.1309 +        }
  1.1310 +        src = SkTAddOffset<const SkGdiRGB>(src, srcRB);
  1.1311 +        dst -= dstRB;
  1.1312 +    }
  1.1313 +}
  1.1314 +
  1.1315 +template<bool APPLY_PREBLEND>
  1.1316 +static void rgb_to_lcd16(const SkGdiRGB* SK_RESTRICT src, size_t srcRB, const SkGlyph& glyph,
  1.1317 +                         const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) {
  1.1318 +    const size_t dstRB = glyph.rowBytes();
  1.1319 +    const int width = glyph.fWidth;
  1.1320 +    uint16_t* SK_RESTRICT dst = (uint16_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
  1.1321 +
  1.1322 +    for (int y = 0; y < glyph.fHeight; y++) {
  1.1323 +        for (int i = 0; i < width; i++) {
  1.1324 +            dst[i] = rgb_to_lcd16<APPLY_PREBLEND>(src[i], tableR, tableG, tableB);
  1.1325 +        }
  1.1326 +        src = SkTAddOffset<const SkGdiRGB>(src, srcRB);
  1.1327 +        dst = (uint16_t*)((char*)dst - dstRB);
  1.1328 +    }
  1.1329 +}
  1.1330 +
  1.1331 +template<bool APPLY_PREBLEND>
  1.1332 +static void rgb_to_lcd32(const SkGdiRGB* SK_RESTRICT src, size_t srcRB, const SkGlyph& glyph,
  1.1333 +                         const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) {
  1.1334 +    const size_t dstRB = glyph.rowBytes();
  1.1335 +    const int width = glyph.fWidth;
  1.1336 +    uint32_t* SK_RESTRICT dst = (uint32_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
  1.1337 +
  1.1338 +    for (int y = 0; y < glyph.fHeight; y++) {
  1.1339 +        for (int i = 0; i < width; i++) {
  1.1340 +            dst[i] = rgb_to_lcd32<APPLY_PREBLEND>(src[i], tableR, tableG, tableB);
  1.1341 +        }
  1.1342 +        src = SkTAddOffset<const SkGdiRGB>(src, srcRB);
  1.1343 +        dst = (uint32_t*)((char*)dst - dstRB);
  1.1344 +    }
  1.1345 +}
  1.1346 +
  1.1347 +static inline unsigned clamp255(unsigned x) {
  1.1348 +    SkASSERT(x <= 256);
  1.1349 +    return x - (x >> 8);
  1.1350 +}
  1.1351 +
  1.1352 +void SkScalerContext_GDI::generateImage(const SkGlyph& glyph) {
  1.1353 +    SkASSERT(fDDC);
  1.1354 +
  1.1355 +    const bool isBW = SkMask::kBW_Format == fRec.fMaskFormat;
  1.1356 +    const bool isAA = !isLCD(fRec);
  1.1357 +
  1.1358 +    size_t srcRB;
  1.1359 +    const void* bits = fOffscreen.draw(glyph, isBW, &srcRB);
  1.1360 +    if (NULL == bits) {
  1.1361 +        LogFontTypeface::EnsureAccessible(this->getTypeface());
  1.1362 +        bits = fOffscreen.draw(glyph, isBW, &srcRB);
  1.1363 +        if (NULL == bits) {
  1.1364 +            sk_bzero(glyph.fImage, glyph.computeImageSize());
  1.1365 +            return;
  1.1366 +        }
  1.1367 +    }
  1.1368 +
  1.1369 +    if (!isBW) {
  1.1370 +        const uint8_t* table;
  1.1371 +        //The offscreen contains a GDI blit if isAA and kGenA8FromLCD_Flag is not set.
  1.1372 +        //Otherwise the offscreen contains a ClearType blit.
  1.1373 +        if (isAA && !(fRec.fFlags & SkScalerContext::kGenA8FromLCD_Flag)) {
  1.1374 +            table = getInverseGammaTableGDI();
  1.1375 +        } else {
  1.1376 +            table = getInverseGammaTableClearType();
  1.1377 +        }
  1.1378 +        //Note that the following cannot really be integrated into the
  1.1379 +        //pre-blend, since we may not be applying the pre-blend; when we aren't
  1.1380 +        //applying the pre-blend it means that a filter wants linear anyway.
  1.1381 +        //Other code may also be applying the pre-blend, so we'd need another
  1.1382 +        //one with this and one without.
  1.1383 +        SkGdiRGB* addr = (SkGdiRGB*)bits;
  1.1384 +        for (int y = 0; y < glyph.fHeight; ++y) {
  1.1385 +            for (int x = 0; x < glyph.fWidth; ++x) {
  1.1386 +                int r = (addr[x] >> 16) & 0xFF;
  1.1387 +                int g = (addr[x] >>  8) & 0xFF;
  1.1388 +                int b = (addr[x] >>  0) & 0xFF;
  1.1389 +                addr[x] = (table[r] << 16) | (table[g] << 8) | table[b];
  1.1390 +            }
  1.1391 +            addr = SkTAddOffset<SkGdiRGB>(addr, srcRB);
  1.1392 +        }
  1.1393 +    }
  1.1394 +
  1.1395 +    int width = glyph.fWidth;
  1.1396 +    size_t dstRB = glyph.rowBytes();
  1.1397 +    if (isBW) {
  1.1398 +        const uint8_t* src = (const uint8_t*)bits;
  1.1399 +        uint8_t* dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
  1.1400 +        for (int y = 0; y < glyph.fHeight; y++) {
  1.1401 +            memcpy(dst, src, dstRB);
  1.1402 +            src += srcRB;
  1.1403 +            dst -= dstRB;
  1.1404 +        }
  1.1405 +#if SK_SHOW_TEXT_BLIT_COVERAGE
  1.1406 +            if (glyph.fWidth > 0 && glyph.fHeight > 0) {
  1.1407 +                int bitCount = width & 7;
  1.1408 +                uint8_t* first = (uint8_t*)glyph.fImage;
  1.1409 +                uint8_t* last = (uint8_t*)((char*)glyph.fImage + glyph.fHeight * dstRB - 1);
  1.1410 +                *first |= 1 << 7;
  1.1411 +                *last |= bitCount == 0 ? 1 : 1 << (8 - bitCount);
  1.1412 +            }
  1.1413 +#endif
  1.1414 +    } else if (isAA) {
  1.1415 +        // since the caller may require A8 for maskfilters, we can't check for BW
  1.1416 +        // ... until we have the caller tell us that explicitly
  1.1417 +        const SkGdiRGB* src = (const SkGdiRGB*)bits;
  1.1418 +        if (fPreBlend.isApplicable()) {
  1.1419 +            rgb_to_a8<true>(src, srcRB, glyph, fPreBlend.fG);
  1.1420 +        } else {
  1.1421 +            rgb_to_a8<false>(src, srcRB, glyph, fPreBlend.fG);
  1.1422 +        }
  1.1423 +    } else {    // LCD16
  1.1424 +        const SkGdiRGB* src = (const SkGdiRGB*)bits;
  1.1425 +        if (is_rgb_really_bw(src, width, glyph.fHeight, srcRB)) {
  1.1426 +            rgb_to_bw(src, srcRB, glyph);
  1.1427 +            ((SkGlyph*)&glyph)->fMaskFormat = SkMask::kBW_Format;
  1.1428 +        } else {
  1.1429 +            if (SkMask::kLCD16_Format == glyph.fMaskFormat) {
  1.1430 +                if (fPreBlend.isApplicable()) {
  1.1431 +                    rgb_to_lcd16<true>(src, srcRB, glyph,
  1.1432 +                                       fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
  1.1433 +                } else {
  1.1434 +                    rgb_to_lcd16<false>(src, srcRB, glyph,
  1.1435 +                                        fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
  1.1436 +                }
  1.1437 +            } else {
  1.1438 +                SkASSERT(SkMask::kLCD32_Format == glyph.fMaskFormat);
  1.1439 +                if (fPreBlend.isApplicable()) {
  1.1440 +                    rgb_to_lcd32<true>(src, srcRB, glyph,
  1.1441 +                                       fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
  1.1442 +                } else {
  1.1443 +                    rgb_to_lcd32<false>(src, srcRB, glyph,
  1.1444 +                                        fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
  1.1445 +                }
  1.1446 +            }
  1.1447 +        }
  1.1448 +    }
  1.1449 +}
  1.1450 +
  1.1451 +class GDIGlyphbufferPointIter {
  1.1452 +public:
  1.1453 +    GDIGlyphbufferPointIter(const uint8_t* glyphbuf, DWORD total_size)
  1.1454 +        : fHeaderIter(glyphbuf, total_size), fCurveIter(), fPointIter()
  1.1455 +    { }
  1.1456 +
  1.1457 +    POINTFX const * next() {
  1.1458 +nextHeader:
  1.1459 +        if (!fCurveIter.isSet()) {
  1.1460 +            const TTPOLYGONHEADER* header = fHeaderIter.next();
  1.1461 +            if (NULL == header) {
  1.1462 +                return NULL;
  1.1463 +            }
  1.1464 +            fCurveIter.set(header);
  1.1465 +            const TTPOLYCURVE* curve = fCurveIter.next();
  1.1466 +            if (NULL == curve) {
  1.1467 +                return NULL;
  1.1468 +            }
  1.1469 +            fPointIter.set(curve);
  1.1470 +            return &header->pfxStart;
  1.1471 +        }
  1.1472 +
  1.1473 +        const POINTFX* nextPoint = fPointIter.next();
  1.1474 +        if (NULL == nextPoint) {
  1.1475 +            const TTPOLYCURVE* curve = fCurveIter.next();
  1.1476 +            if (NULL == curve) {
  1.1477 +                fCurveIter.set();
  1.1478 +                goto nextHeader;
  1.1479 +            } else {
  1.1480 +                fPointIter.set(curve);
  1.1481 +            }
  1.1482 +            nextPoint = fPointIter.next();
  1.1483 +        }
  1.1484 +        return nextPoint;
  1.1485 +    }
  1.1486 +
  1.1487 +    WORD currentCurveType() {
  1.1488 +        return fPointIter.fCurveType;
  1.1489 +    }
  1.1490 +
  1.1491 +private:
  1.1492 +    /** Iterates over all of the polygon headers in a glyphbuf. */
  1.1493 +    class GDIPolygonHeaderIter {
  1.1494 +    public:
  1.1495 +        GDIPolygonHeaderIter(const uint8_t* glyphbuf, DWORD total_size)
  1.1496 +            : fCurPolygon(reinterpret_cast<const TTPOLYGONHEADER*>(glyphbuf))
  1.1497 +            , fEndPolygon(SkTAddOffset<const TTPOLYGONHEADER>(glyphbuf, total_size))
  1.1498 +        { }
  1.1499 +
  1.1500 +        const TTPOLYGONHEADER* next() {
  1.1501 +            if (fCurPolygon >= fEndPolygon) {
  1.1502 +                return NULL;
  1.1503 +            }
  1.1504 +            const TTPOLYGONHEADER* thisPolygon = fCurPolygon;
  1.1505 +            fCurPolygon = SkTAddOffset<const TTPOLYGONHEADER>(fCurPolygon, fCurPolygon->cb);
  1.1506 +            return thisPolygon;
  1.1507 +        }
  1.1508 +    private:
  1.1509 +        const TTPOLYGONHEADER* fCurPolygon;
  1.1510 +        const TTPOLYGONHEADER* fEndPolygon;
  1.1511 +    };
  1.1512 +
  1.1513 +    /** Iterates over all of the polygon curves in a polygon header. */
  1.1514 +    class GDIPolygonCurveIter {
  1.1515 +    public:
  1.1516 +        GDIPolygonCurveIter() : fCurCurve(NULL), fEndCurve(NULL) { }
  1.1517 +
  1.1518 +        GDIPolygonCurveIter(const TTPOLYGONHEADER* curPolygon)
  1.1519 +            : fCurCurve(SkTAddOffset<const TTPOLYCURVE>(curPolygon, sizeof(TTPOLYGONHEADER)))
  1.1520 +            , fEndCurve(SkTAddOffset<const TTPOLYCURVE>(curPolygon, curPolygon->cb))
  1.1521 +        { }
  1.1522 +
  1.1523 +        bool isSet() { return fCurCurve != NULL; }
  1.1524 +
  1.1525 +        void set(const TTPOLYGONHEADER* curPolygon) {
  1.1526 +            fCurCurve = SkTAddOffset<const TTPOLYCURVE>(curPolygon, sizeof(TTPOLYGONHEADER));
  1.1527 +            fEndCurve = SkTAddOffset<const TTPOLYCURVE>(curPolygon, curPolygon->cb);
  1.1528 +        }
  1.1529 +        void set() {
  1.1530 +            fCurCurve = NULL;
  1.1531 +            fEndCurve = NULL;
  1.1532 +        }
  1.1533 +
  1.1534 +        const TTPOLYCURVE* next() {
  1.1535 +            if (fCurCurve >= fEndCurve) {
  1.1536 +                return NULL;
  1.1537 +            }
  1.1538 +            const TTPOLYCURVE* thisCurve = fCurCurve;
  1.1539 +            fCurCurve = SkTAddOffset<const TTPOLYCURVE>(fCurCurve, size_of_TTPOLYCURVE(*fCurCurve));
  1.1540 +            return thisCurve;
  1.1541 +        }
  1.1542 +    private:
  1.1543 +        size_t size_of_TTPOLYCURVE(const TTPOLYCURVE& curve) {
  1.1544 +            return 2*sizeof(WORD) + curve.cpfx*sizeof(POINTFX);
  1.1545 +        }
  1.1546 +        const TTPOLYCURVE* fCurCurve;
  1.1547 +        const TTPOLYCURVE* fEndCurve;
  1.1548 +    };
  1.1549 +
  1.1550 +    /** Iterates over all of the polygon points in a polygon curve. */
  1.1551 +    class GDIPolygonCurvePointIter {
  1.1552 +    public:
  1.1553 +        GDIPolygonCurvePointIter() : fCurveType(0), fCurPoint(NULL), fEndPoint(NULL) { }
  1.1554 +
  1.1555 +        GDIPolygonCurvePointIter(const TTPOLYCURVE* curPolygon)
  1.1556 +            : fCurveType(curPolygon->wType)
  1.1557 +            , fCurPoint(&curPolygon->apfx[0])
  1.1558 +            , fEndPoint(&curPolygon->apfx[curPolygon->cpfx])
  1.1559 +        { }
  1.1560 +
  1.1561 +        bool isSet() { return fCurPoint != NULL; }
  1.1562 +
  1.1563 +        void set(const TTPOLYCURVE* curPolygon) {
  1.1564 +            fCurveType = curPolygon->wType;
  1.1565 +            fCurPoint = &curPolygon->apfx[0];
  1.1566 +            fEndPoint = &curPolygon->apfx[curPolygon->cpfx];
  1.1567 +        }
  1.1568 +        void set() {
  1.1569 +            fCurPoint = NULL;
  1.1570 +            fEndPoint = NULL;
  1.1571 +        }
  1.1572 +
  1.1573 +        const POINTFX* next() {
  1.1574 +            if (fCurPoint >= fEndPoint) {
  1.1575 +                return NULL;
  1.1576 +            }
  1.1577 +            const POINTFX* thisPoint = fCurPoint;
  1.1578 +            ++fCurPoint;
  1.1579 +            return thisPoint;
  1.1580 +        }
  1.1581 +
  1.1582 +        WORD fCurveType;
  1.1583 +    private:
  1.1584 +        const POINTFX* fCurPoint;
  1.1585 +        const POINTFX* fEndPoint;
  1.1586 +    };
  1.1587 +
  1.1588 +    GDIPolygonHeaderIter fHeaderIter;
  1.1589 +    GDIPolygonCurveIter fCurveIter;
  1.1590 +    GDIPolygonCurvePointIter fPointIter;
  1.1591 +};
  1.1592 +
  1.1593 +static void sk_path_from_gdi_path(SkPath* path, const uint8_t* glyphbuf, DWORD total_size) {
  1.1594 +    const uint8_t* cur_glyph = glyphbuf;
  1.1595 +    const uint8_t* end_glyph = glyphbuf + total_size;
  1.1596 +
  1.1597 +    while (cur_glyph < end_glyph) {
  1.1598 +        const TTPOLYGONHEADER* th = (TTPOLYGONHEADER*)cur_glyph;
  1.1599 +
  1.1600 +        const uint8_t* end_poly = cur_glyph + th->cb;
  1.1601 +        const uint8_t* cur_poly = cur_glyph + sizeof(TTPOLYGONHEADER);
  1.1602 +
  1.1603 +        path->moveTo(SkFixedToScalar( SkFIXEDToFixed(th->pfxStart.x)),
  1.1604 +                     SkFixedToScalar(-SkFIXEDToFixed(th->pfxStart.y)));
  1.1605 +
  1.1606 +        while (cur_poly < end_poly) {
  1.1607 +            const TTPOLYCURVE* pc = (const TTPOLYCURVE*)cur_poly;
  1.1608 +
  1.1609 +            if (pc->wType == TT_PRIM_LINE) {
  1.1610 +                for (uint16_t i = 0; i < pc->cpfx; i++) {
  1.1611 +                    path->lineTo(SkFixedToScalar( SkFIXEDToFixed(pc->apfx[i].x)),
  1.1612 +                                 SkFixedToScalar(-SkFIXEDToFixed(pc->apfx[i].y)));
  1.1613 +                }
  1.1614 +            }
  1.1615 +
  1.1616 +            if (pc->wType == TT_PRIM_QSPLINE) {
  1.1617 +                for (uint16_t u = 0; u < pc->cpfx - 1; u++) { // Walk through points in spline
  1.1618 +                    POINTFX pnt_b = pc->apfx[u];    // B is always the current point
  1.1619 +                    POINTFX pnt_c = pc->apfx[u+1];
  1.1620 +
  1.1621 +                    if (u < pc->cpfx - 2) {          // If not on last spline, compute C
  1.1622 +                        pnt_c.x = SkFixedToFIXED(SkFixedAve(SkFIXEDToFixed(pnt_b.x),
  1.1623 +                                                            SkFIXEDToFixed(pnt_c.x)));
  1.1624 +                        pnt_c.y = SkFixedToFIXED(SkFixedAve(SkFIXEDToFixed(pnt_b.y),
  1.1625 +                                                            SkFIXEDToFixed(pnt_c.y)));
  1.1626 +                    }
  1.1627 +
  1.1628 +                    path->quadTo(SkFixedToScalar( SkFIXEDToFixed(pnt_b.x)),
  1.1629 +                                 SkFixedToScalar(-SkFIXEDToFixed(pnt_b.y)),
  1.1630 +                                 SkFixedToScalar( SkFIXEDToFixed(pnt_c.x)),
  1.1631 +                                 SkFixedToScalar(-SkFIXEDToFixed(pnt_c.y)));
  1.1632 +                }
  1.1633 +            }
  1.1634 +            // Advance past this TTPOLYCURVE.
  1.1635 +            cur_poly += sizeof(WORD) * 2 + sizeof(POINTFX) * pc->cpfx;
  1.1636 +        }
  1.1637 +        cur_glyph += th->cb;
  1.1638 +        path->close();
  1.1639 +    }
  1.1640 +}
  1.1641 +
  1.1642 +#define move_next_expected_hinted_point(iter, pElem) do {\
  1.1643 +    pElem = iter.next(); \
  1.1644 +    if (NULL == pElem) return false; \
  1.1645 +} while(0)
  1.1646 +
  1.1647 +// It is possible for the hinted and unhinted versions of the same path to have
  1.1648 +// a different number of points due to GDI's handling of flipped points.
  1.1649 +// If this is detected, this will return false.
  1.1650 +static bool sk_path_from_gdi_paths(SkPath* path, const uint8_t* glyphbuf, DWORD total_size,
  1.1651 +                                   GDIGlyphbufferPointIter hintedYs) {
  1.1652 +    const uint8_t* cur_glyph = glyphbuf;
  1.1653 +    const uint8_t* end_glyph = glyphbuf + total_size;
  1.1654 +
  1.1655 +    POINTFX const * hintedPoint;
  1.1656 +
  1.1657 +    while (cur_glyph < end_glyph) {
  1.1658 +        const TTPOLYGONHEADER* th = (TTPOLYGONHEADER*)cur_glyph;
  1.1659 +
  1.1660 +        const uint8_t* end_poly = cur_glyph + th->cb;
  1.1661 +        const uint8_t* cur_poly = cur_glyph + sizeof(TTPOLYGONHEADER);
  1.1662 +
  1.1663 +        move_next_expected_hinted_point(hintedYs, hintedPoint);
  1.1664 +        path->moveTo(SkFixedToScalar( SkFIXEDToFixed(th->pfxStart.x)),
  1.1665 +                     SkFixedToScalar(-SkFIXEDToFixed(hintedPoint->y)));
  1.1666 +
  1.1667 +        while (cur_poly < end_poly) {
  1.1668 +            const TTPOLYCURVE* pc = (const TTPOLYCURVE*)cur_poly;
  1.1669 +
  1.1670 +            if (pc->wType == TT_PRIM_LINE) {
  1.1671 +                for (uint16_t i = 0; i < pc->cpfx; i++) {
  1.1672 +                    move_next_expected_hinted_point(hintedYs, hintedPoint);
  1.1673 +                    path->lineTo(SkFixedToScalar( SkFIXEDToFixed(pc->apfx[i].x)),
  1.1674 +                                 SkFixedToScalar(-SkFIXEDToFixed(hintedPoint->y)));
  1.1675 +                }
  1.1676 +            }
  1.1677 +
  1.1678 +            if (pc->wType == TT_PRIM_QSPLINE) {
  1.1679 +                POINTFX currentPoint = pc->apfx[0];
  1.1680 +                move_next_expected_hinted_point(hintedYs, hintedPoint);
  1.1681 +                // only take the hinted y if it wasn't flipped
  1.1682 +                if (hintedYs.currentCurveType() == TT_PRIM_QSPLINE) {
  1.1683 +                    currentPoint.y = hintedPoint->y;
  1.1684 +                }
  1.1685 +                for (uint16_t u = 0; u < pc->cpfx - 1; u++) { // Walk through points in spline
  1.1686 +                    POINTFX pnt_b = currentPoint;//pc->apfx[u]; // B is always the current point
  1.1687 +                    POINTFX pnt_c = pc->apfx[u+1];
  1.1688 +                    move_next_expected_hinted_point(hintedYs, hintedPoint);
  1.1689 +                    // only take the hinted y if it wasn't flipped
  1.1690 +                    if (hintedYs.currentCurveType() == TT_PRIM_QSPLINE) {
  1.1691 +                        pnt_c.y = hintedPoint->y;
  1.1692 +                    }
  1.1693 +                    currentPoint.x = pnt_c.x;
  1.1694 +                    currentPoint.y = pnt_c.y;
  1.1695 +
  1.1696 +                    if (u < pc->cpfx - 2) {          // If not on last spline, compute C
  1.1697 +                        pnt_c.x = SkFixedToFIXED(SkFixedAve(SkFIXEDToFixed(pnt_b.x),
  1.1698 +                                                            SkFIXEDToFixed(pnt_c.x)));
  1.1699 +                        pnt_c.y = SkFixedToFIXED(SkFixedAve(SkFIXEDToFixed(pnt_b.y),
  1.1700 +                                                            SkFIXEDToFixed(pnt_c.y)));
  1.1701 +                    }
  1.1702 +
  1.1703 +                    path->quadTo(SkFixedToScalar( SkFIXEDToFixed(pnt_b.x)),
  1.1704 +                                 SkFixedToScalar(-SkFIXEDToFixed(pnt_b.y)),
  1.1705 +                                 SkFixedToScalar( SkFIXEDToFixed(pnt_c.x)),
  1.1706 +                                 SkFixedToScalar(-SkFIXEDToFixed(pnt_c.y)));
  1.1707 +                }
  1.1708 +            }
  1.1709 +            // Advance past this TTPOLYCURVE.
  1.1710 +            cur_poly += sizeof(WORD) * 2 + sizeof(POINTFX) * pc->cpfx;
  1.1711 +        }
  1.1712 +        cur_glyph += th->cb;
  1.1713 +        path->close();
  1.1714 +    }
  1.1715 +    return true;
  1.1716 +}
  1.1717 +
  1.1718 +DWORD SkScalerContext_GDI::getGDIGlyphPath(const SkGlyph& glyph, UINT flags,
  1.1719 +                                               SkAutoSTMalloc<BUFFERSIZE, uint8_t>* glyphbuf)
  1.1720 +{
  1.1721 +    GLYPHMETRICS gm;
  1.1722 +
  1.1723 +    DWORD total_size = GetGlyphOutlineW(fDDC, glyph.fID, flags, &gm, BUFFERSIZE, glyphbuf->get(), &fMat22);
  1.1724 +    // Sometimes GetGlyphOutlineW returns a number larger than BUFFERSIZE even if BUFFERSIZE > 0.
  1.1725 +    // It has been verified that this does not involve a buffer overrun.
  1.1726 +    if (GDI_ERROR == total_size || total_size > BUFFERSIZE) {
  1.1727 +        // GDI_ERROR because the BUFFERSIZE was too small, or because the data was not accessible.
  1.1728 +        // When the data is not accessable GetGlyphOutlineW fails rather quickly,
  1.1729 +        // so just try to get the size. If that fails then ensure the data is accessible.
  1.1730 +        total_size = GetGlyphOutlineW(fDDC, glyph.fID, flags, &gm, 0, NULL, &fMat22);
  1.1731 +        if (GDI_ERROR == total_size) {
  1.1732 +            LogFontTypeface::EnsureAccessible(this->getTypeface());
  1.1733 +            total_size = GetGlyphOutlineW(fDDC, glyph.fID, flags, &gm, 0, NULL, &fMat22);
  1.1734 +            if (GDI_ERROR == total_size) {
  1.1735 +                SkASSERT(false);
  1.1736 +                return 0;
  1.1737 +            }
  1.1738 +        }
  1.1739 +
  1.1740 +        glyphbuf->reset(total_size);
  1.1741 +
  1.1742 +        DWORD ret = GetGlyphOutlineW(fDDC, glyph.fID, flags, &gm, total_size, glyphbuf->get(), &fMat22);
  1.1743 +        if (GDI_ERROR == ret) {
  1.1744 +            LogFontTypeface::EnsureAccessible(this->getTypeface());
  1.1745 +            ret = GetGlyphOutlineW(fDDC, glyph.fID, flags, &gm, total_size, glyphbuf->get(), &fMat22);
  1.1746 +            if (GDI_ERROR == ret) {
  1.1747 +                SkASSERT(false);
  1.1748 +                return 0;
  1.1749 +            }
  1.1750 +        }
  1.1751 +    }
  1.1752 +    return total_size;
  1.1753 +}
  1.1754 +
  1.1755 +void SkScalerContext_GDI::generatePath(const SkGlyph& glyph, SkPath* path) {
  1.1756 +    SkASSERT(&glyph && path);
  1.1757 +    SkASSERT(fDDC);
  1.1758 +
  1.1759 +    path->reset();
  1.1760 +
  1.1761 +    // Out of all the fonts on a typical Windows box,
  1.1762 +    // 25% of glyphs require more than 2KB.
  1.1763 +    // 1% of glyphs require more than 4KB.
  1.1764 +    // 0.01% of glyphs require more than 8KB.
  1.1765 +    // 8KB is less than 1% of the normal 1MB stack on Windows.
  1.1766 +    // Note that some web fonts glyphs require more than 20KB.
  1.1767 +    //static const DWORD BUFFERSIZE = (1 << 13);
  1.1768 +
  1.1769 +    //GDI only uses hinted outlines when axis aligned.
  1.1770 +    UINT format = GGO_NATIVE | GGO_GLYPH_INDEX;
  1.1771 +    if (fRec.getHinting() == SkPaint::kNo_Hinting || fRec.getHinting() == SkPaint::kSlight_Hinting){
  1.1772 +        format |= GGO_UNHINTED;
  1.1773 +    }
  1.1774 +    SkAutoSTMalloc<BUFFERSIZE, uint8_t> glyphbuf(BUFFERSIZE);
  1.1775 +    DWORD total_size = getGDIGlyphPath(glyph, format, &glyphbuf);
  1.1776 +    if (0 == total_size) {
  1.1777 +        return;
  1.1778 +    }
  1.1779 +
  1.1780 +    if (fRec.getHinting() != SkPaint::kSlight_Hinting) {
  1.1781 +        sk_path_from_gdi_path(path, glyphbuf, total_size);
  1.1782 +    } else {
  1.1783 +        //GDI only uses hinted outlines when axis aligned.
  1.1784 +        UINT format = GGO_NATIVE | GGO_GLYPH_INDEX;
  1.1785 +
  1.1786 +        SkAutoSTMalloc<BUFFERSIZE, uint8_t> hintedGlyphbuf(BUFFERSIZE);
  1.1787 +        DWORD hinted_total_size = getGDIGlyphPath(glyph, format, &hintedGlyphbuf);
  1.1788 +        if (0 == hinted_total_size) {
  1.1789 +            return;
  1.1790 +        }
  1.1791 +
  1.1792 +        if (!sk_path_from_gdi_paths(path, glyphbuf, total_size,
  1.1793 +                                    GDIGlyphbufferPointIter(hintedGlyphbuf, hinted_total_size)))
  1.1794 +        {
  1.1795 +            path->reset();
  1.1796 +            sk_path_from_gdi_path(path, glyphbuf, total_size);
  1.1797 +        }
  1.1798 +    }
  1.1799 +}
  1.1800 +
  1.1801 +static void logfont_for_name(const char* familyName, LOGFONT* lf) {
  1.1802 +    sk_bzero(lf, sizeof(LOGFONT));
  1.1803 +#ifdef UNICODE
  1.1804 +    // Get the buffer size needed first.
  1.1805 +    size_t str_len = ::MultiByteToWideChar(CP_UTF8, 0, familyName,
  1.1806 +                                            -1, NULL, 0);
  1.1807 +    // Allocate a buffer (str_len already has terminating null
  1.1808 +    // accounted for).
  1.1809 +    wchar_t *wideFamilyName = new wchar_t[str_len];
  1.1810 +    // Now actually convert the string.
  1.1811 +    ::MultiByteToWideChar(CP_UTF8, 0, familyName, -1,
  1.1812 +                            wideFamilyName, str_len);
  1.1813 +    ::wcsncpy(lf->lfFaceName, wideFamilyName, LF_FACESIZE - 1);
  1.1814 +    delete [] wideFamilyName;
  1.1815 +    lf->lfFaceName[LF_FACESIZE-1] = L'\0';
  1.1816 +#else
  1.1817 +    ::strncpy(lf->lfFaceName, familyName, LF_FACESIZE - 1);
  1.1818 +    lf->lfFaceName[LF_FACESIZE - 1] = '\0';
  1.1819 +#endif
  1.1820 +}
  1.1821 +
  1.1822 +void LogFontTypeface::onGetFontDescriptor(SkFontDescriptor* desc,
  1.1823 +                                          bool* isLocalStream) const {
  1.1824 +    // Get the actual name of the typeface. The logfont may not know this.
  1.1825 +    HFONT font = CreateFontIndirect(&fLogFont);
  1.1826 +
  1.1827 +    HDC deviceContext = ::CreateCompatibleDC(NULL);
  1.1828 +    HFONT savefont = (HFONT)SelectObject(deviceContext, font);
  1.1829 +
  1.1830 +    SkString familyName;
  1.1831 +    dcfontname_to_skstring(deviceContext, fLogFont, &familyName);
  1.1832 +
  1.1833 +    if (deviceContext) {
  1.1834 +        ::SelectObject(deviceContext, savefont);
  1.1835 +        ::DeleteDC(deviceContext);
  1.1836 +    }
  1.1837 +    if (font) {
  1.1838 +        ::DeleteObject(font);
  1.1839 +    }
  1.1840 +
  1.1841 +    desc->setFamilyName(familyName.c_str());
  1.1842 +    *isLocalStream = this->fSerializeAsStream;
  1.1843 +}
  1.1844 +
  1.1845 +static bool getWidthAdvance(HDC hdc, int gId, int16_t* advance) {
  1.1846 +    // Initialize the MAT2 structure to the identify transformation matrix.
  1.1847 +    static const MAT2 mat2 = {SkScalarToFIXED(1), SkScalarToFIXED(0),
  1.1848 +                        SkScalarToFIXED(0), SkScalarToFIXED(1)};
  1.1849 +    int flags = GGO_METRICS | GGO_GLYPH_INDEX;
  1.1850 +    GLYPHMETRICS gm;
  1.1851 +    if (GDI_ERROR == GetGlyphOutline(hdc, gId, flags, &gm, 0, NULL, &mat2)) {
  1.1852 +        return false;
  1.1853 +    }
  1.1854 +    SkASSERT(advance);
  1.1855 +    *advance = gm.gmCellIncX;
  1.1856 +    return true;
  1.1857 +}
  1.1858 +
  1.1859 +SkAdvancedTypefaceMetrics* LogFontTypeface::onGetAdvancedTypefaceMetrics(
  1.1860 +        SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo,
  1.1861 +        const uint32_t* glyphIDs,
  1.1862 +        uint32_t glyphIDsCount) const {
  1.1863 +    LOGFONT lf = fLogFont;
  1.1864 +    SkAdvancedTypefaceMetrics* info = NULL;
  1.1865 +
  1.1866 +    HDC hdc = CreateCompatibleDC(NULL);
  1.1867 +    HFONT font = CreateFontIndirect(&lf);
  1.1868 +    HFONT savefont = (HFONT)SelectObject(hdc, font);
  1.1869 +    HFONT designFont = NULL;
  1.1870 +
  1.1871 +    const char stem_chars[] = {'i', 'I', '!', '1'};
  1.1872 +    int16_t min_width;
  1.1873 +    unsigned glyphCount;
  1.1874 +
  1.1875 +    // To request design units, create a logical font whose height is specified
  1.1876 +    // as unitsPerEm.
  1.1877 +    OUTLINETEXTMETRIC otm;
  1.1878 +    unsigned int otmRet = GetOutlineTextMetrics(hdc, sizeof(otm), &otm);
  1.1879 +    if (0 == otmRet) {
  1.1880 +        call_ensure_accessible(lf);
  1.1881 +        otmRet = GetOutlineTextMetrics(hdc, sizeof(otm), &otm);
  1.1882 +    }
  1.1883 +    if (!otmRet || !GetTextFace(hdc, LF_FACESIZE, lf.lfFaceName)) {
  1.1884 +        goto Error;
  1.1885 +    }
  1.1886 +    lf.lfHeight = -SkToS32(otm.otmEMSquare);
  1.1887 +    designFont = CreateFontIndirect(&lf);
  1.1888 +    SelectObject(hdc, designFont);
  1.1889 +    if (!GetOutlineTextMetrics(hdc, sizeof(otm), &otm)) {
  1.1890 +        goto Error;
  1.1891 +    }
  1.1892 +    glyphCount = calculateGlyphCount(hdc, fLogFont);
  1.1893 +
  1.1894 +    info = new SkAdvancedTypefaceMetrics;
  1.1895 +    info->fEmSize = otm.otmEMSquare;
  1.1896 +    info->fMultiMaster = false;
  1.1897 +    info->fLastGlyphID = SkToU16(glyphCount - 1);
  1.1898 +    info->fStyle = 0;
  1.1899 +    tchar_to_skstring(lf.lfFaceName, &info->fFontName);
  1.1900 +
  1.1901 +    if (perGlyphInfo & SkAdvancedTypefaceMetrics::kToUnicode_PerGlyphInfo) {
  1.1902 +        populate_glyph_to_unicode(hdc, glyphCount, &(info->fGlyphToUnicode));
  1.1903 +    }
  1.1904 +
  1.1905 +    if (glyphCount > 0 &&
  1.1906 +        (otm.otmTextMetrics.tmPitchAndFamily & TMPF_TRUETYPE)) {
  1.1907 +        info->fType = SkAdvancedTypefaceMetrics::kTrueType_Font;
  1.1908 +    } else {
  1.1909 +        info->fType = SkAdvancedTypefaceMetrics::kOther_Font;
  1.1910 +        info->fItalicAngle = 0;
  1.1911 +        info->fAscent = 0;
  1.1912 +        info->fDescent = 0;
  1.1913 +        info->fStemV = 0;
  1.1914 +        info->fCapHeight = 0;
  1.1915 +        info->fBBox = SkIRect::MakeEmpty();
  1.1916 +        goto ReturnInfo;
  1.1917 +    }
  1.1918 +
  1.1919 +    // If this bit is clear the font is a fixed pitch font.
  1.1920 +    if (!(otm.otmTextMetrics.tmPitchAndFamily & TMPF_FIXED_PITCH)) {
  1.1921 +        info->fStyle |= SkAdvancedTypefaceMetrics::kFixedPitch_Style;
  1.1922 +    }
  1.1923 +    if (otm.otmTextMetrics.tmItalic) {
  1.1924 +        info->fStyle |= SkAdvancedTypefaceMetrics::kItalic_Style;
  1.1925 +    }
  1.1926 +    if (otm.otmTextMetrics.tmPitchAndFamily & FF_ROMAN) {
  1.1927 +        info->fStyle |= SkAdvancedTypefaceMetrics::kSerif_Style;
  1.1928 +    } else if (otm.otmTextMetrics.tmPitchAndFamily & FF_SCRIPT) {
  1.1929 +            info->fStyle |= SkAdvancedTypefaceMetrics::kScript_Style;
  1.1930 +    }
  1.1931 +
  1.1932 +    // The main italic angle of the font, in tenths of a degree counterclockwise
  1.1933 +    // from vertical.
  1.1934 +    info->fItalicAngle = otm.otmItalicAngle / 10;
  1.1935 +    info->fAscent = SkToS16(otm.otmTextMetrics.tmAscent);
  1.1936 +    info->fDescent = SkToS16(-otm.otmTextMetrics.tmDescent);
  1.1937 +    // TODO(ctguil): Use alternate cap height calculation.
  1.1938 +    // MSDN says otmsCapEmHeight is not support but it is returning a value on
  1.1939 +    // my Win7 box.
  1.1940 +    info->fCapHeight = otm.otmsCapEmHeight;
  1.1941 +    info->fBBox =
  1.1942 +        SkIRect::MakeLTRB(otm.otmrcFontBox.left, otm.otmrcFontBox.top,
  1.1943 +                          otm.otmrcFontBox.right, otm.otmrcFontBox.bottom);
  1.1944 +
  1.1945 +    // Figure out a good guess for StemV - Min width of i, I, !, 1.
  1.1946 +    // This probably isn't very good with an italic font.
  1.1947 +    min_width = SHRT_MAX;
  1.1948 +    info->fStemV = 0;
  1.1949 +    for (size_t i = 0; i < SK_ARRAY_COUNT(stem_chars); i++) {
  1.1950 +        ABC abcWidths;
  1.1951 +        if (GetCharABCWidths(hdc, stem_chars[i], stem_chars[i], &abcWidths)) {
  1.1952 +            int16_t width = abcWidths.abcB;
  1.1953 +            if (width > 0 && width < min_width) {
  1.1954 +                min_width = width;
  1.1955 +                info->fStemV = min_width;
  1.1956 +            }
  1.1957 +        }
  1.1958 +    }
  1.1959 +
  1.1960 +    // If bit 1 is set, the font may not be embedded in a document.
  1.1961 +    // If bit 1 is clear, the font can be embedded.
  1.1962 +    // If bit 2 is set, the embedding is read-only.
  1.1963 +    if (otm.otmfsType & 0x1) {
  1.1964 +        info->fType = SkAdvancedTypefaceMetrics::kNotEmbeddable_Font;
  1.1965 +    } else if (perGlyphInfo &
  1.1966 +               SkAdvancedTypefaceMetrics::kHAdvance_PerGlyphInfo) {
  1.1967 +        if (info->fStyle & SkAdvancedTypefaceMetrics::kFixedPitch_Style) {
  1.1968 +            appendRange(&info->fGlyphWidths, 0);
  1.1969 +            info->fGlyphWidths->fAdvance.append(1, &min_width);
  1.1970 +            finishRange(info->fGlyphWidths.get(), 0,
  1.1971 +                        SkAdvancedTypefaceMetrics::WidthRange::kDefault);
  1.1972 +        } else {
  1.1973 +            info->fGlyphWidths.reset(
  1.1974 +                getAdvanceData(hdc,
  1.1975 +                               glyphCount,
  1.1976 +                               glyphIDs,
  1.1977 +                               glyphIDsCount,
  1.1978 +                               &getWidthAdvance));
  1.1979 +        }
  1.1980 +    }
  1.1981 +
  1.1982 +Error:
  1.1983 +ReturnInfo:
  1.1984 +    SelectObject(hdc, savefont);
  1.1985 +    DeleteObject(designFont);
  1.1986 +    DeleteObject(font);
  1.1987 +    DeleteDC(hdc);
  1.1988 +
  1.1989 +    return info;
  1.1990 +}
  1.1991 +
  1.1992 +//Dummy representation of a Base64 encoded GUID from create_unique_font_name.
  1.1993 +#define BASE64_GUID_ID "XXXXXXXXXXXXXXXXXXXXXXXX"
  1.1994 +//Length of GUID representation from create_id, including NULL terminator.
  1.1995 +#define BASE64_GUID_ID_LEN SK_ARRAY_COUNT(BASE64_GUID_ID)
  1.1996 +
  1.1997 +SK_COMPILE_ASSERT(BASE64_GUID_ID_LEN < LF_FACESIZE, GUID_longer_than_facesize);
  1.1998 +
  1.1999 +/**
  1.2000 +   NameID 6 Postscript names cannot have the character '/'.
  1.2001 +   It would be easier to hex encode the GUID, but that is 32 bytes,
  1.2002 +   and many systems have issues with names longer than 28 bytes.
  1.2003 +   The following need not be any standard base64 encoding.
  1.2004 +   The encoded value is never decoded.
  1.2005 +*/
  1.2006 +static const char postscript_safe_base64_encode[] =
  1.2007 +    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  1.2008 +    "abcdefghijklmnopqrstuvwxyz"
  1.2009 +    "0123456789-_=";
  1.2010 +
  1.2011 +/**
  1.2012 +   Formats a GUID into Base64 and places it into buffer.
  1.2013 +   buffer should have space for at least BASE64_GUID_ID_LEN characters.
  1.2014 +   The string will always be null terminated.
  1.2015 +   XXXXXXXXXXXXXXXXXXXXXXXX0
  1.2016 + */
  1.2017 +static void format_guid_b64(const GUID& guid, char* buffer, size_t bufferSize) {
  1.2018 +    SkASSERT(bufferSize >= BASE64_GUID_ID_LEN);
  1.2019 +    size_t written = SkBase64::Encode(&guid, sizeof(guid), buffer, postscript_safe_base64_encode);
  1.2020 +    SkASSERT(written < LF_FACESIZE);
  1.2021 +    buffer[written] = '\0';
  1.2022 +}
  1.2023 +
  1.2024 +/**
  1.2025 +   Creates a Base64 encoded GUID and places it into buffer.
  1.2026 +   buffer should have space for at least BASE64_GUID_ID_LEN characters.
  1.2027 +   The string will always be null terminated.
  1.2028 +   XXXXXXXXXXXXXXXXXXXXXXXX0
  1.2029 + */
  1.2030 +static HRESULT create_unique_font_name(char* buffer, size_t bufferSize) {
  1.2031 +    GUID guid = {};
  1.2032 +    if (FAILED(CoCreateGuid(&guid))) {
  1.2033 +        return E_UNEXPECTED;
  1.2034 +    }
  1.2035 +    format_guid_b64(guid, buffer, bufferSize);
  1.2036 +
  1.2037 +    return S_OK;
  1.2038 +}
  1.2039 +
  1.2040 +/**
  1.2041 +   Introduces a font to GDI. On failure will return NULL. The returned handle
  1.2042 +   should eventually be passed to RemoveFontMemResourceEx.
  1.2043 +*/
  1.2044 +static HANDLE activate_font(SkData* fontData) {
  1.2045 +    DWORD numFonts = 0;
  1.2046 +    //AddFontMemResourceEx just copies the data, but does not specify const.
  1.2047 +    HANDLE fontHandle = AddFontMemResourceEx(const_cast<void*>(fontData->data()),
  1.2048 +                                             static_cast<DWORD>(fontData->size()),
  1.2049 +                                             0,
  1.2050 +                                             &numFonts);
  1.2051 +
  1.2052 +    if (fontHandle != NULL && numFonts < 1) {
  1.2053 +        RemoveFontMemResourceEx(fontHandle);
  1.2054 +        return NULL;
  1.2055 +    }
  1.2056 +
  1.2057 +    return fontHandle;
  1.2058 +}
  1.2059 +
  1.2060 +static SkTypeface* create_from_stream(SkStream* stream) {
  1.2061 +    // Create a unique and unpredictable font name.
  1.2062 +    // Avoids collisions and access from CSS.
  1.2063 +    char familyName[BASE64_GUID_ID_LEN];
  1.2064 +    const int familyNameSize = SK_ARRAY_COUNT(familyName);
  1.2065 +    if (FAILED(create_unique_font_name(familyName, familyNameSize))) {
  1.2066 +        return NULL;
  1.2067 +    }
  1.2068 +
  1.2069 +    // Change the name of the font.
  1.2070 +    SkAutoTUnref<SkData> rewrittenFontData(SkOTUtils::RenameFont(stream, familyName, familyNameSize-1));
  1.2071 +    if (NULL == rewrittenFontData.get()) {
  1.2072 +        return NULL;
  1.2073 +    }
  1.2074 +
  1.2075 +    // Register the font with GDI.
  1.2076 +    HANDLE fontReference = activate_font(rewrittenFontData.get());
  1.2077 +    if (NULL == fontReference) {
  1.2078 +        return NULL;
  1.2079 +    }
  1.2080 +
  1.2081 +    // Create the typeface.
  1.2082 +    LOGFONT lf;
  1.2083 +    logfont_for_name(familyName, &lf);
  1.2084 +
  1.2085 +    return SkCreateFontMemResourceTypefaceFromLOGFONT(lf, fontReference);
  1.2086 +}
  1.2087 +
  1.2088 +SkStream* LogFontTypeface::onOpenStream(int* ttcIndex) const {
  1.2089 +    *ttcIndex = 0;
  1.2090 +
  1.2091 +    const DWORD kTTCTag =
  1.2092 +        SkEndian_SwapBE32(SkSetFourByteTag('t', 't', 'c', 'f'));
  1.2093 +    LOGFONT lf = fLogFont;
  1.2094 +
  1.2095 +    HDC hdc = ::CreateCompatibleDC(NULL);
  1.2096 +    HFONT font = CreateFontIndirect(&lf);
  1.2097 +    HFONT savefont = (HFONT)SelectObject(hdc, font);
  1.2098 +
  1.2099 +    SkMemoryStream* stream = NULL;
  1.2100 +    DWORD tables[2] = {kTTCTag, 0};
  1.2101 +    for (int i = 0; i < SK_ARRAY_COUNT(tables); i++) {
  1.2102 +        DWORD bufferSize = GetFontData(hdc, tables[i], 0, NULL, 0);
  1.2103 +        if (bufferSize == GDI_ERROR) {
  1.2104 +            call_ensure_accessible(lf);
  1.2105 +            bufferSize = GetFontData(hdc, tables[i], 0, NULL, 0);
  1.2106 +        }
  1.2107 +        if (bufferSize != GDI_ERROR) {
  1.2108 +            stream = new SkMemoryStream(bufferSize);
  1.2109 +            if (GetFontData(hdc, tables[i], 0, (void*)stream->getMemoryBase(), bufferSize)) {
  1.2110 +                break;
  1.2111 +            } else {
  1.2112 +                delete stream;
  1.2113 +                stream = NULL;
  1.2114 +            }
  1.2115 +        }
  1.2116 +    }
  1.2117 +
  1.2118 +    SelectObject(hdc, savefont);
  1.2119 +    DeleteObject(font);
  1.2120 +    DeleteDC(hdc);
  1.2121 +
  1.2122 +    return stream;
  1.2123 +}
  1.2124 +
  1.2125 +static void bmpCharsToGlyphs(HDC hdc, const WCHAR* bmpChars, int count, uint16_t* glyphs,
  1.2126 +                             bool Ox1FHack)
  1.2127 +{
  1.2128 +    DWORD result = GetGlyphIndicesW(hdc, bmpChars, count, glyphs, GGI_MARK_NONEXISTING_GLYPHS);
  1.2129 +    if (GDI_ERROR == result) {
  1.2130 +        for (int i = 0; i < count; ++i) {
  1.2131 +            glyphs[i] = 0;
  1.2132 +        }
  1.2133 +        return;
  1.2134 +    }
  1.2135 +
  1.2136 +    if (Ox1FHack) {
  1.2137 +        for (int i = 0; i < count; ++i) {
  1.2138 +            if (0xFFFF == glyphs[i] || 0x1F == glyphs[i]) {
  1.2139 +                glyphs[i] = 0;
  1.2140 +            }
  1.2141 +        }
  1.2142 +    } else {
  1.2143 +        for (int i = 0; i < count; ++i) {
  1.2144 +            if (0xFFFF == glyphs[i]){
  1.2145 +                glyphs[i] = 0;
  1.2146 +            }
  1.2147 +        }
  1.2148 +    }
  1.2149 +}
  1.2150 +
  1.2151 +static uint16_t nonBmpCharToGlyph(HDC hdc, SCRIPT_CACHE* scriptCache, const WCHAR utf16[2]) {
  1.2152 +    uint16_t index = 0;
  1.2153 +    // Use uniscribe to detemine glyph index for non-BMP characters.
  1.2154 +    static const int numWCHAR = 2;
  1.2155 +    static const int maxItems = 2;
  1.2156 +    // MSDN states that this can be NULL, but some things don't work then.
  1.2157 +    SCRIPT_CONTROL scriptControl = { 0 };
  1.2158 +    // Add extra item to SCRIPT_ITEM to work around a bug (now documented).
  1.2159 +    // https://bugzilla.mozilla.org/show_bug.cgi?id=366643
  1.2160 +    SCRIPT_ITEM si[maxItems + 1];
  1.2161 +    int numItems;
  1.2162 +    HRZM(ScriptItemize(utf16, numWCHAR, maxItems, &scriptControl, NULL, si, &numItems),
  1.2163 +         "Could not itemize character.");
  1.2164 +
  1.2165 +    // Sometimes ScriptShape cannot find a glyph for a non-BMP and returns 2 space glyphs.
  1.2166 +    static const int maxGlyphs = 2;
  1.2167 +    SCRIPT_VISATTR vsa[maxGlyphs];
  1.2168 +    WORD outGlyphs[maxGlyphs];
  1.2169 +    WORD logClust[numWCHAR];
  1.2170 +    int numGlyphs;
  1.2171 +    HRZM(ScriptShape(hdc, scriptCache, utf16, numWCHAR, maxGlyphs, &si[0].a,
  1.2172 +                     outGlyphs, logClust, vsa, &numGlyphs),
  1.2173 +         "Could not shape character.");
  1.2174 +    if (1 == numGlyphs) {
  1.2175 +        index = outGlyphs[0];
  1.2176 +    }
  1.2177 +    return index;
  1.2178 +}
  1.2179 +
  1.2180 +class SkAutoHDC {
  1.2181 +public:
  1.2182 +    SkAutoHDC(const LOGFONT& lf)
  1.2183 +        : fHdc(::CreateCompatibleDC(NULL))
  1.2184 +        , fFont(::CreateFontIndirect(&lf))
  1.2185 +        , fSavefont((HFONT)SelectObject(fHdc, fFont))
  1.2186 +    { }
  1.2187 +    ~SkAutoHDC() {
  1.2188 +        SelectObject(fHdc, fSavefont);
  1.2189 +        DeleteObject(fFont);
  1.2190 +        DeleteDC(fHdc);
  1.2191 +    }
  1.2192 +    operator HDC() { return fHdc; }
  1.2193 +private:
  1.2194 +    HDC fHdc;
  1.2195 +    HFONT fFont;
  1.2196 +    HFONT fSavefont;
  1.2197 +};
  1.2198 +#define SkAutoHDC(...) SK_REQUIRE_LOCAL_VAR(SkAutoHDC)
  1.2199 +
  1.2200 +int LogFontTypeface::onCharsToGlyphs(const void* chars, Encoding encoding,
  1.2201 +                                     uint16_t userGlyphs[], int glyphCount) const
  1.2202 +{
  1.2203 +    SkAutoHDC hdc(fLogFont);
  1.2204 +
  1.2205 +    TEXTMETRIC tm;
  1.2206 +    if (0 == GetTextMetrics(hdc, &tm)) {
  1.2207 +        call_ensure_accessible(fLogFont);
  1.2208 +        if (0 == GetTextMetrics(hdc, &tm)) {
  1.2209 +            tm.tmPitchAndFamily = TMPF_TRUETYPE;
  1.2210 +        }
  1.2211 +    }
  1.2212 +    bool Ox1FHack = !(tm.tmPitchAndFamily & TMPF_VECTOR) /*&& winVer < Vista */;
  1.2213 +
  1.2214 +    SkAutoSTMalloc<256, uint16_t> scratchGlyphs;
  1.2215 +    uint16_t* glyphs;
  1.2216 +    if (userGlyphs != NULL) {
  1.2217 +        glyphs = userGlyphs;
  1.2218 +    } else {
  1.2219 +        glyphs = scratchGlyphs.reset(glyphCount);
  1.2220 +    }
  1.2221 +
  1.2222 +    SCRIPT_CACHE sc = 0;
  1.2223 +    switch (encoding) {
  1.2224 +    case SkTypeface::kUTF8_Encoding: {
  1.2225 +        static const int scratchCount = 256;
  1.2226 +        WCHAR scratch[scratchCount];
  1.2227 +        int glyphIndex = 0;
  1.2228 +        const char* currentUtf8 = reinterpret_cast<const char*>(chars);
  1.2229 +        SkUnichar currentChar;
  1.2230 +        if (glyphCount) {
  1.2231 +            currentChar = SkUTF8_NextUnichar(&currentUtf8);
  1.2232 +        }
  1.2233 +        while (glyphIndex < glyphCount) {
  1.2234 +            // Try a run of bmp.
  1.2235 +            int glyphsLeft = SkTMin(glyphCount - glyphIndex, scratchCount);
  1.2236 +            int runLength = 0;
  1.2237 +            while (runLength < glyphsLeft && currentChar <= 0xFFFF) {
  1.2238 +                scratch[runLength] = static_cast<WCHAR>(currentChar);
  1.2239 +                ++runLength;
  1.2240 +                if (runLength < glyphsLeft) {
  1.2241 +                    currentChar = SkUTF8_NextUnichar(&currentUtf8);
  1.2242 +                }
  1.2243 +            }
  1.2244 +            if (runLength) {
  1.2245 +                bmpCharsToGlyphs(hdc, scratch, runLength, &glyphs[glyphIndex], Ox1FHack);
  1.2246 +                glyphIndex += runLength;
  1.2247 +            }
  1.2248 +
  1.2249 +            // Try a run of non-bmp.
  1.2250 +            while (glyphIndex < glyphCount && currentChar > 0xFFFF) {
  1.2251 +                SkUTF16_FromUnichar(currentChar, reinterpret_cast<uint16_t*>(scratch));
  1.2252 +                glyphs[glyphIndex] = nonBmpCharToGlyph(hdc, &sc, scratch);
  1.2253 +                ++glyphIndex;
  1.2254 +                if (glyphIndex < glyphCount) {
  1.2255 +                    currentChar = SkUTF8_NextUnichar(&currentUtf8);
  1.2256 +                }
  1.2257 +            }
  1.2258 +        }
  1.2259 +        break;
  1.2260 +    }
  1.2261 +    case SkTypeface::kUTF16_Encoding: {
  1.2262 +        int glyphIndex = 0;
  1.2263 +        const WCHAR* currentUtf16 = reinterpret_cast<const WCHAR*>(chars);
  1.2264 +        while (glyphIndex < glyphCount) {
  1.2265 +            // Try a run of bmp.
  1.2266 +            int glyphsLeft = glyphCount - glyphIndex;
  1.2267 +            int runLength = 0;
  1.2268 +            while (runLength < glyphsLeft && !SkUTF16_IsHighSurrogate(currentUtf16[runLength])) {
  1.2269 +                ++runLength;
  1.2270 +            }
  1.2271 +            if (runLength) {
  1.2272 +                bmpCharsToGlyphs(hdc, currentUtf16, runLength, &glyphs[glyphIndex], Ox1FHack);
  1.2273 +                glyphIndex += runLength;
  1.2274 +                currentUtf16 += runLength;
  1.2275 +            }
  1.2276 +
  1.2277 +            // Try a run of non-bmp.
  1.2278 +            while (glyphIndex < glyphCount && SkUTF16_IsHighSurrogate(*currentUtf16)) {
  1.2279 +                glyphs[glyphIndex] = nonBmpCharToGlyph(hdc, &sc, currentUtf16);
  1.2280 +                ++glyphIndex;
  1.2281 +                currentUtf16 += 2;
  1.2282 +            }
  1.2283 +        }
  1.2284 +        break;
  1.2285 +    }
  1.2286 +    case SkTypeface::kUTF32_Encoding: {
  1.2287 +        static const int scratchCount = 256;
  1.2288 +        WCHAR scratch[scratchCount];
  1.2289 +        int glyphIndex = 0;
  1.2290 +        const uint32_t* utf32 = reinterpret_cast<const uint32_t*>(chars);
  1.2291 +        while (glyphIndex < glyphCount) {
  1.2292 +            // Try a run of bmp.
  1.2293 +            int glyphsLeft = SkTMin(glyphCount - glyphIndex, scratchCount);
  1.2294 +            int runLength = 0;
  1.2295 +            while (runLength < glyphsLeft && utf32[glyphIndex + runLength] <= 0xFFFF) {
  1.2296 +                scratch[runLength] = static_cast<WCHAR>(utf32[glyphIndex + runLength]);
  1.2297 +                ++runLength;
  1.2298 +            }
  1.2299 +            if (runLength) {
  1.2300 +                bmpCharsToGlyphs(hdc, scratch, runLength, &glyphs[glyphIndex], Ox1FHack);
  1.2301 +                glyphIndex += runLength;
  1.2302 +            }
  1.2303 +
  1.2304 +            // Try a run of non-bmp.
  1.2305 +            while (glyphIndex < glyphCount && utf32[glyphIndex] > 0xFFFF) {
  1.2306 +                SkUTF16_FromUnichar(utf32[glyphIndex], reinterpret_cast<uint16_t*>(scratch));
  1.2307 +                glyphs[glyphIndex] = nonBmpCharToGlyph(hdc, &sc, scratch);
  1.2308 +                ++glyphIndex;
  1.2309 +            }
  1.2310 +        }
  1.2311 +        break;
  1.2312 +    }
  1.2313 +    default:
  1.2314 +        SK_CRASH();
  1.2315 +    }
  1.2316 +
  1.2317 +    if (sc) {
  1.2318 +        ::ScriptFreeCache(&sc);
  1.2319 +    }
  1.2320 +
  1.2321 +    for (int i = 0; i < glyphCount; ++i) {
  1.2322 +        if (0 == glyphs[i]) {
  1.2323 +            return i;
  1.2324 +        }
  1.2325 +    }
  1.2326 +    return glyphCount;
  1.2327 +}
  1.2328 +
  1.2329 +int LogFontTypeface::onCountGlyphs() const {
  1.2330 +    HDC hdc = ::CreateCompatibleDC(NULL);
  1.2331 +    HFONT font = CreateFontIndirect(&fLogFont);
  1.2332 +    HFONT savefont = (HFONT)SelectObject(hdc, font);
  1.2333 +
  1.2334 +    unsigned int glyphCount = calculateGlyphCount(hdc, fLogFont);
  1.2335 +
  1.2336 +    SelectObject(hdc, savefont);
  1.2337 +    DeleteObject(font);
  1.2338 +    DeleteDC(hdc);
  1.2339 +
  1.2340 +    return glyphCount;
  1.2341 +}
  1.2342 +
  1.2343 +int LogFontTypeface::onGetUPEM() const {
  1.2344 +    HDC hdc = ::CreateCompatibleDC(NULL);
  1.2345 +    HFONT font = CreateFontIndirect(&fLogFont);
  1.2346 +    HFONT savefont = (HFONT)SelectObject(hdc, font);
  1.2347 +
  1.2348 +    unsigned int upem = calculateUPEM(hdc, fLogFont);
  1.2349 +
  1.2350 +    SelectObject(hdc, savefont);
  1.2351 +    DeleteObject(font);
  1.2352 +    DeleteDC(hdc);
  1.2353 +
  1.2354 +    return upem;
  1.2355 +}
  1.2356 +
  1.2357 +SkTypeface::LocalizedStrings* LogFontTypeface::onCreateFamilyNameIterator() const {
  1.2358 +    SkTypeface::LocalizedStrings* nameIter =
  1.2359 +        SkOTUtils::LocalizedStrings_NameTable::CreateForFamilyNames(*this);
  1.2360 +    if (NULL == nameIter) {
  1.2361 +        SkString familyName;
  1.2362 +        this->getFamilyName(&familyName);
  1.2363 +        SkString language("und"); //undetermined
  1.2364 +        nameIter = new SkOTUtils::LocalizedStrings_SingleName(familyName, language);
  1.2365 +    }
  1.2366 +    return nameIter;
  1.2367 +}
  1.2368 +
  1.2369 +int LogFontTypeface::onGetTableTags(SkFontTableTag tags[]) const {
  1.2370 +    SkSFNTHeader header;
  1.2371 +    if (sizeof(header) != this->onGetTableData(0, 0, sizeof(header), &header)) {
  1.2372 +        return 0;
  1.2373 +    }
  1.2374 +
  1.2375 +    int numTables = SkEndian_SwapBE16(header.numTables);
  1.2376 +
  1.2377 +    if (tags) {
  1.2378 +        size_t size = numTables * sizeof(SkSFNTHeader::TableDirectoryEntry);
  1.2379 +        SkAutoSTMalloc<0x20, SkSFNTHeader::TableDirectoryEntry> dir(numTables);
  1.2380 +        if (size != this->onGetTableData(0, sizeof(header), size, dir.get())) {
  1.2381 +            return 0;
  1.2382 +        }
  1.2383 +
  1.2384 +        for (int i = 0; i < numTables; ++i) {
  1.2385 +            tags[i] = SkEndian_SwapBE32(dir[i].tag);
  1.2386 +        }
  1.2387 +    }
  1.2388 +    return numTables;
  1.2389 +}
  1.2390 +
  1.2391 +size_t LogFontTypeface::onGetTableData(SkFontTableTag tag, size_t offset,
  1.2392 +                                       size_t length, void* data) const
  1.2393 +{
  1.2394 +    LOGFONT lf = fLogFont;
  1.2395 +
  1.2396 +    HDC hdc = ::CreateCompatibleDC(NULL);
  1.2397 +    HFONT font = CreateFontIndirect(&lf);
  1.2398 +    HFONT savefont = (HFONT)SelectObject(hdc, font);
  1.2399 +
  1.2400 +    tag = SkEndian_SwapBE32(tag);
  1.2401 +    if (NULL == data) {
  1.2402 +        length = 0;
  1.2403 +    }
  1.2404 +    DWORD bufferSize = GetFontData(hdc, tag, (DWORD) offset, data, (DWORD) length);
  1.2405 +    if (bufferSize == GDI_ERROR) {
  1.2406 +        call_ensure_accessible(lf);
  1.2407 +        bufferSize = GetFontData(hdc, tag, (DWORD) offset, data, (DWORD) length);
  1.2408 +    }
  1.2409 +
  1.2410 +    SelectObject(hdc, savefont);
  1.2411 +    DeleteObject(font);
  1.2412 +    DeleteDC(hdc);
  1.2413 +
  1.2414 +    return bufferSize == GDI_ERROR ? 0 : bufferSize;
  1.2415 +}
  1.2416 +
  1.2417 +SkScalerContext* LogFontTypeface::onCreateScalerContext(const SkDescriptor* desc) const {
  1.2418 +    SkScalerContext_GDI* ctx = SkNEW_ARGS(SkScalerContext_GDI,
  1.2419 +                                                (const_cast<LogFontTypeface*>(this), desc));
  1.2420 +    if (!ctx->isValid()) {
  1.2421 +        SkDELETE(ctx);
  1.2422 +        ctx = NULL;
  1.2423 +    }
  1.2424 +    return ctx;
  1.2425 +}
  1.2426 +
  1.2427 +void LogFontTypeface::onFilterRec(SkScalerContextRec* rec) const {
  1.2428 +    if (rec->fFlags & SkScalerContext::kLCD_BGROrder_Flag ||
  1.2429 +        rec->fFlags & SkScalerContext::kLCD_Vertical_Flag)
  1.2430 +    {
  1.2431 +        rec->fMaskFormat = SkMask::kA8_Format;
  1.2432 +        rec->fFlags |= SkScalerContext::kGenA8FromLCD_Flag;
  1.2433 +    }
  1.2434 +
  1.2435 +    unsigned flagsWeDontSupport = SkScalerContext::kDevKernText_Flag |
  1.2436 +                                  SkScalerContext::kForceAutohinting_Flag |
  1.2437 +                                  SkScalerContext::kEmbeddedBitmapText_Flag |
  1.2438 +                                  SkScalerContext::kEmbolden_Flag |
  1.2439 +                                  SkScalerContext::kLCD_BGROrder_Flag |
  1.2440 +                                  SkScalerContext::kLCD_Vertical_Flag;
  1.2441 +    rec->fFlags &= ~flagsWeDontSupport;
  1.2442 +
  1.2443 +    SkPaint::Hinting h = rec->getHinting();
  1.2444 +    switch (h) {
  1.2445 +        case SkPaint::kNo_Hinting:
  1.2446 +            break;
  1.2447 +        case SkPaint::kSlight_Hinting:
  1.2448 +            // Only do slight hinting when axis aligned.
  1.2449 +            // TODO: re-enable slight hinting when FontHostTest can pass.
  1.2450 +            //if (!isAxisAligned(*rec)) {
  1.2451 +                h = SkPaint::kNo_Hinting;
  1.2452 +            //}
  1.2453 +            break;
  1.2454 +        case SkPaint::kNormal_Hinting:
  1.2455 +        case SkPaint::kFull_Hinting:
  1.2456 +            // TODO: need to be able to distinguish subpixel positioned glyphs
  1.2457 +            // and linear metrics.
  1.2458 +            //rec->fFlags &= ~SkScalerContext::kSubpixelPositioning_Flag;
  1.2459 +            h = SkPaint::kNormal_Hinting;
  1.2460 +            break;
  1.2461 +        default:
  1.2462 +            SkDEBUGFAIL("unknown hinting");
  1.2463 +    }
  1.2464 +    //TODO: if this is a bitmap font, squash hinting and subpixel.
  1.2465 +    rec->setHinting(h);
  1.2466 +
  1.2467 +// turn this off since GDI might turn A8 into BW! Need a bigger fix.
  1.2468 +#if 0
  1.2469 +    // Disable LCD when rotated, since GDI's output is ugly
  1.2470 +    if (isLCD(*rec) && !isAxisAligned(*rec)) {
  1.2471 +        rec->fMaskFormat = SkMask::kA8_Format;
  1.2472 +    }
  1.2473 +#endif
  1.2474 +
  1.2475 +    if (!fCanBeLCD && isLCD(*rec)) {
  1.2476 +        rec->fMaskFormat = SkMask::kA8_Format;
  1.2477 +        rec->fFlags &= ~SkScalerContext::kGenA8FromLCD_Flag;
  1.2478 +    }
  1.2479 +}
  1.2480 +
  1.2481 +///////////////////////////////////////////////////////////////////////////////
  1.2482 +
  1.2483 +#include "SkFontMgr.h"
  1.2484 +#include "SkDataTable.h"
  1.2485 +
  1.2486 +static bool valid_logfont_for_enum(const LOGFONT& lf) {
  1.2487 +    // TODO: Vector FON is unsupported and should not be listed.
  1.2488 +    return
  1.2489 +        // Ignore implicit vertical variants.
  1.2490 +        lf.lfFaceName[0] && lf.lfFaceName[0] != '@'
  1.2491 +
  1.2492 +        // DEFAULT_CHARSET is used to get all fonts, but also implies all
  1.2493 +        // character sets. Filter assuming all fonts support ANSI_CHARSET.
  1.2494 +        && ANSI_CHARSET == lf.lfCharSet
  1.2495 +    ;
  1.2496 +}
  1.2497 +
  1.2498 +/** An EnumFontFamExProc implementation which interprets builderParam as
  1.2499 + *  an SkTDArray<ENUMLOGFONTEX>* and appends logfonts which
  1.2500 + *  pass the valid_logfont_for_enum predicate.
  1.2501 + */
  1.2502 +static int CALLBACK enum_family_proc(const LOGFONT* lf, const TEXTMETRIC*,
  1.2503 +                                     DWORD fontType, LPARAM builderParam) {
  1.2504 +    if (valid_logfont_for_enum(*lf)) {
  1.2505 +        SkTDArray<ENUMLOGFONTEX>* array = (SkTDArray<ENUMLOGFONTEX>*)builderParam;
  1.2506 +        *array->append() = *(ENUMLOGFONTEX*)lf;
  1.2507 +    }
  1.2508 +    return 1; // non-zero means continue
  1.2509 +}
  1.2510 +
  1.2511 +static SkFontStyle compute_fontstyle(const LOGFONT& lf) {
  1.2512 +    return SkFontStyle(lf.lfWeight, SkFontStyle::kNormal_Width,
  1.2513 +                       lf.lfItalic ? SkFontStyle::kItalic_Slant
  1.2514 +                                   : SkFontStyle::kUpright_Slant);
  1.2515 +}
  1.2516 +
  1.2517 +class SkFontStyleSetGDI : public SkFontStyleSet {
  1.2518 +public:
  1.2519 +    SkFontStyleSetGDI(const TCHAR familyName[]) {
  1.2520 +        LOGFONT lf;
  1.2521 +        sk_bzero(&lf, sizeof(lf));
  1.2522 +        lf.lfCharSet = DEFAULT_CHARSET;
  1.2523 +        _tcscpy_s(lf.lfFaceName, familyName);
  1.2524 +
  1.2525 +        HDC hdc = ::CreateCompatibleDC(NULL);
  1.2526 +        ::EnumFontFamiliesEx(hdc, &lf, enum_family_proc, (LPARAM)&fArray, 0);
  1.2527 +        ::DeleteDC(hdc);
  1.2528 +    }
  1.2529 +
  1.2530 +    virtual int count() SK_OVERRIDE {
  1.2531 +        return fArray.count();
  1.2532 +    }
  1.2533 +
  1.2534 +    virtual void getStyle(int index, SkFontStyle* fs, SkString* styleName) SK_OVERRIDE {
  1.2535 +        if (fs) {
  1.2536 +            *fs = compute_fontstyle(fArray[index].elfLogFont);
  1.2537 +        }
  1.2538 +        if (styleName) {
  1.2539 +            const ENUMLOGFONTEX& ref = fArray[index];
  1.2540 +            // For some reason, ENUMLOGFONTEX and LOGFONT disagree on their type in the
  1.2541 +            // non-unicode version.
  1.2542 +            //      ENUMLOGFONTEX uses BYTE
  1.2543 +            //      LOGFONT uses CHAR
  1.2544 +            // Here we assert they that the style name is logically the same (size) as
  1.2545 +            // a TCHAR, so we can use the same converter function.
  1.2546 +            SkASSERT(sizeof(TCHAR) == sizeof(ref.elfStyle[0]));
  1.2547 +            tchar_to_skstring((const TCHAR*)ref.elfStyle, styleName);
  1.2548 +        }
  1.2549 +    }
  1.2550 +
  1.2551 +    virtual SkTypeface* createTypeface(int index) SK_OVERRIDE {
  1.2552 +        return SkCreateTypefaceFromLOGFONT(fArray[index].elfLogFont);
  1.2553 +    }
  1.2554 +
  1.2555 +    virtual SkTypeface* matchStyle(const SkFontStyle& pattern) SK_OVERRIDE {
  1.2556 +        // todo:
  1.2557 +        return SkCreateTypefaceFromLOGFONT(fArray[0].elfLogFont);
  1.2558 +    }
  1.2559 +
  1.2560 +private:
  1.2561 +    SkTDArray<ENUMLOGFONTEX> fArray;
  1.2562 +};
  1.2563 +
  1.2564 +class SkFontMgrGDI : public SkFontMgr {
  1.2565 +public:
  1.2566 +    SkFontMgrGDI() {
  1.2567 +        LOGFONT lf;
  1.2568 +        sk_bzero(&lf, sizeof(lf));
  1.2569 +        lf.lfCharSet = DEFAULT_CHARSET;
  1.2570 +
  1.2571 +        HDC hdc = ::CreateCompatibleDC(NULL);
  1.2572 +        ::EnumFontFamiliesEx(hdc, &lf, enum_family_proc, (LPARAM)&fLogFontArray, 0);
  1.2573 +        ::DeleteDC(hdc);
  1.2574 +    }
  1.2575 +
  1.2576 +protected:
  1.2577 +    virtual int onCountFamilies() const SK_OVERRIDE {
  1.2578 +        return fLogFontArray.count();
  1.2579 +    }
  1.2580 +
  1.2581 +    virtual void onGetFamilyName(int index, SkString* familyName) const SK_OVERRIDE {
  1.2582 +        SkASSERT((unsigned)index < (unsigned)fLogFontArray.count());
  1.2583 +        tchar_to_skstring(fLogFontArray[index].elfLogFont.lfFaceName, familyName);
  1.2584 +    }
  1.2585 +
  1.2586 +    virtual SkFontStyleSet* onCreateStyleSet(int index) const SK_OVERRIDE {
  1.2587 +        SkASSERT((unsigned)index < (unsigned)fLogFontArray.count());
  1.2588 +        return SkNEW_ARGS(SkFontStyleSetGDI, (fLogFontArray[index].elfLogFont.lfFaceName));
  1.2589 +    }
  1.2590 +
  1.2591 +    virtual SkFontStyleSet* onMatchFamily(const char familyName[]) const SK_OVERRIDE {
  1.2592 +        if (NULL == familyName) {
  1.2593 +            familyName = "";    // do we need this check???
  1.2594 +        }
  1.2595 +        LOGFONT lf;
  1.2596 +        logfont_for_name(familyName, &lf);
  1.2597 +        return SkNEW_ARGS(SkFontStyleSetGDI, (lf.lfFaceName));
  1.2598 +    }
  1.2599 +
  1.2600 +    virtual SkTypeface* onMatchFamilyStyle(const char familyName[],
  1.2601 +                                           const SkFontStyle& fontstyle) const SK_OVERRIDE {
  1.2602 +        // could be in base impl
  1.2603 +        SkAutoTUnref<SkFontStyleSet> sset(this->matchFamily(familyName));
  1.2604 +        return sset->matchStyle(fontstyle);
  1.2605 +    }
  1.2606 +
  1.2607 +    virtual SkTypeface* onMatchFaceStyle(const SkTypeface* familyMember,
  1.2608 +                                         const SkFontStyle& fontstyle) const SK_OVERRIDE {
  1.2609 +        // could be in base impl
  1.2610 +        SkString familyName;
  1.2611 +        ((LogFontTypeface*)familyMember)->getFamilyName(&familyName);
  1.2612 +        return this->matchFamilyStyle(familyName.c_str(), fontstyle);
  1.2613 +    }
  1.2614 +
  1.2615 +    virtual SkTypeface* onCreateFromStream(SkStream* stream, int ttcIndex) const SK_OVERRIDE {
  1.2616 +        return create_from_stream(stream);
  1.2617 +    }
  1.2618 +
  1.2619 +    virtual SkTypeface* onCreateFromData(SkData* data, int ttcIndex) const SK_OVERRIDE {
  1.2620 +        // could be in base impl
  1.2621 +        SkAutoTUnref<SkStream> stream(SkNEW_ARGS(SkMemoryStream, (data)));
  1.2622 +        return this->createFromStream(stream);
  1.2623 +    }
  1.2624 +
  1.2625 +    virtual SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const SK_OVERRIDE {
  1.2626 +        // could be in base impl
  1.2627 +        SkAutoTUnref<SkStream> stream(SkStream::NewFromFile(path));
  1.2628 +        return this->createFromStream(stream);
  1.2629 +    }
  1.2630 +
  1.2631 +    virtual SkTypeface* onLegacyCreateTypeface(const char familyName[],
  1.2632 +                                               unsigned styleBits) const SK_OVERRIDE {
  1.2633 +        LOGFONT lf;
  1.2634 +        if (NULL == familyName) {
  1.2635 +            lf = get_default_font();
  1.2636 +        } else {
  1.2637 +            logfont_for_name(familyName, &lf);
  1.2638 +        }
  1.2639 +        setStyle(&lf, (SkTypeface::Style)styleBits);
  1.2640 +        return SkCreateTypefaceFromLOGFONT(lf);
  1.2641 +    }
  1.2642 +
  1.2643 +private:
  1.2644 +    SkTDArray<ENUMLOGFONTEX> fLogFontArray;
  1.2645 +};
  1.2646 +
  1.2647 +///////////////////////////////////////////////////////////////////////////////
  1.2648 +
  1.2649 +SkFontMgr* SkFontMgr_New_GDI() {
  1.2650 +    return SkNEW(SkFontMgrGDI);
  1.2651 +}

mercurial