tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

SkFontHost_win.cpp (86881B)


      1 /*
      2 * Copyright 2006 The Android Open Source Project
      3 *
      4 * Use of this source code is governed by a BSD-style license that can be
      5 * found in the LICENSE file.
      6 */
      7 
      8 #include "include/core/SkTypes.h"
      9 #if defined(SK_BUILD_FOR_WIN)
     10 
     11 #include "include/core/SkData.h"
     12 #include "include/core/SkFontMetrics.h"
     13 #include "include/core/SkFontTypes.h"
     14 #include "include/core/SkPath.h"
     15 #include "include/core/SkPathBuilder.h"
     16 #include "include/core/SkStream.h"
     17 #include "include/core/SkString.h"
     18 #include "include/ports/SkTypeface_win.h"
     19 #include "src/ports/SkTypeface_win_dw.h"
     20 #include "include/private/base/SkMacros.h"
     21 #include "include/private/base/SkOnce.h"
     22 #include "include/private/base/SkTDArray.h"
     23 #include "include/private/base/SkTemplates.h"
     24 #include "include/private/base/SkTo.h"
     25 #include "src/base/SkBase64.h"
     26 #include "src/base/SkLeanWindows.h"
     27 #include "src/base/SkUTF.h"
     28 #include "src/core/SkAdvancedTypefaceMetrics.h"
     29 #include "src/core/SkColorData.h"
     30 #include "src/core/SkDescriptor.h"
     31 #include "src/core/SkFontDescriptor.h"
     32 #include "src/core/SkGlyph.h"
     33 #include "src/core/SkMaskGamma.h"
     34 #include "src/core/SkStrikeCache.h"
     35 #include "src/core/SkTypefaceCache.h"
     36 #include "src/sfnt/SkOTTable_OS_2.h"
     37 #include "src/sfnt/SkOTTable_maxp.h"
     38 #include "src/sfnt/SkOTTable_name.h"
     39 #include "src/sfnt/SkOTUtils.h"
     40 #include "src/sfnt/SkSFNTHeader.h"
     41 #include "src/utils/SkMatrix22.h"
     42 #include "src/utils/win/SkHRESULT.h"
     43 
     44 #include <tchar.h>
     45 #include <usp10.h>
     46 #include <objbase.h>
     47 
     48 using namespace skia_private;
     49 
     50 namespace {
     51 static inline const constexpr bool kSkShowTextBlitCoverage = false;
     52 }
     53 
     54 static void (*gEnsureLOGFONTAccessibleProc)(const LOGFONT&);
     55 
     56 void SkTypeface_SetEnsureLOGFONTAccessibleProc(void (*proc)(const LOGFONT&)) {
     57    gEnsureLOGFONTAccessibleProc = proc;
     58 }
     59 
     60 static void call_ensure_accessible(const LOGFONT& lf) {
     61    if (gEnsureLOGFONTAccessibleProc) {
     62        gEnsureLOGFONTAccessibleProc(lf);
     63    }
     64 }
     65 
     66 ///////////////////////////////////////////////////////////////////////////////
     67 
     68 // always packed xxRRGGBB
     69 typedef uint32_t SkGdiRGB;
     70 
     71 // define this in your Makefile or .gyp to enforce AA requests
     72 // which GDI ignores at small sizes. This flag guarantees AA
     73 // for rotated text, regardless of GDI's notions.
     74 //#define SK_ENFORCE_ROTATED_TEXT_AA_ON_WINDOWS
     75 
     76 static bool isLCD(const SkScalerContextRec& rec) {
     77    return SkMask::kLCD16_Format == rec.fMaskFormat;
     78 }
     79 
     80 static bool bothZero(SkScalar a, SkScalar b) {
     81    return 0 == a && 0 == b;
     82 }
     83 
     84 // returns false if there is any non-90-rotation or skew
     85 static bool isAxisAligned(const SkScalerContextRec& rec) {
     86    return 0 == rec.fPreSkewX &&
     87           (bothZero(rec.fPost2x2[0][1], rec.fPost2x2[1][0]) ||
     88            bothZero(rec.fPost2x2[0][0], rec.fPost2x2[1][1]));
     89 }
     90 
     91 static bool needToRenderWithSkia(const SkScalerContextRec& rec) {
     92 #ifdef SK_ENFORCE_ROTATED_TEXT_AA_ON_WINDOWS
     93    // What we really want to catch is when GDI will ignore the AA request and give
     94    // us BW instead. Smallish rotated text is one heuristic, so this code is just
     95    // an approximation. We shouldn't need to do this for larger sizes, but at those
     96    // sizes, the quality difference gets less and less between our general
     97    // scanconverter and GDI's.
     98    if (SkMask::kA8_Format == rec.fMaskFormat && !isAxisAligned(rec)) {
     99        return true;
    100    }
    101 #endif
    102    return rec.getHinting() == SkFontHinting::kNone || rec.getHinting() == SkFontHinting::kSlight;
    103 }
    104 
    105 static void tchar_to_skstring(const TCHAR t[], SkString* s) {
    106 #ifdef UNICODE
    107    size_t sSize = WideCharToMultiByte(CP_UTF8, 0, t, -1, nullptr, 0, nullptr, nullptr);
    108    s->resize(sSize);
    109    WideCharToMultiByte(CP_UTF8, 0, t, -1, s->data(), sSize, nullptr, nullptr);
    110 #else
    111    s->set(t);
    112 #endif
    113 }
    114 
    115 static void dcfontname_to_skstring(HDC deviceContext, const LOGFONT& lf, SkString* familyName) {
    116    int fontNameLen; //length of fontName in TCHARS.
    117    if (0 == (fontNameLen = GetTextFace(deviceContext, 0, nullptr))) {
    118        call_ensure_accessible(lf);
    119        if (0 == (fontNameLen = GetTextFace(deviceContext, 0, nullptr))) {
    120            fontNameLen = 0;
    121        }
    122    }
    123 
    124    AutoSTArray<LF_FULLFACESIZE, TCHAR> fontName(fontNameLen+1);
    125    if (0 == GetTextFace(deviceContext, fontNameLen, fontName.get())) {
    126        call_ensure_accessible(lf);
    127        if (0 == GetTextFace(deviceContext, fontNameLen, fontName.get())) {
    128            fontName[0] = 0;
    129        }
    130    }
    131 
    132    tchar_to_skstring(fontName.get(), familyName);
    133 }
    134 
    135 static void make_canonical(LOGFONT* lf) {
    136    lf->lfHeight = -64;
    137    lf->lfWidth = 0;  // lfWidth is related to lfHeight, not to the OS/2::usWidthClass.
    138    lf->lfQuality = CLEARTYPE_QUALITY;//PROOF_QUALITY;
    139    lf->lfCharSet = DEFAULT_CHARSET;
    140 //    lf->lfClipPrecision = 64;
    141 }
    142 
    143 static SkFontStyle get_style(const LOGFONT& lf) {
    144    return SkFontStyle(lf.lfWeight,
    145                       SkFontStyle::kNormal_Width,
    146                       lf.lfItalic ? SkFontStyle::kItalic_Slant : SkFontStyle::kUpright_Slant);
    147 }
    148 
    149 static inline FIXED SkFixedToFIXED(SkFixed x) {
    150    return *(FIXED*)(&x);
    151 }
    152 static inline SkFixed SkFIXEDToFixed(FIXED x) {
    153    return *(SkFixed*)(&x);
    154 }
    155 
    156 static inline FIXED SkScalarToFIXED(SkScalar x) {
    157    return SkFixedToFIXED(SkScalarToFixed(x));
    158 }
    159 
    160 static inline SkScalar SkFIXEDToScalar(FIXED x) {
    161    return SkFixedToScalar(SkFIXEDToFixed(x));
    162 }
    163 
    164 static unsigned calculateGlyphCount(HDC hdc, const LOGFONT& lf) {
    165    TEXTMETRIC textMetric;
    166    if (0 == GetTextMetrics(hdc, &textMetric)) {
    167        textMetric.tmPitchAndFamily = TMPF_VECTOR;
    168        call_ensure_accessible(lf);
    169        GetTextMetrics(hdc, &textMetric);
    170    }
    171 
    172    if (!(textMetric.tmPitchAndFamily & TMPF_VECTOR)) {
    173        return textMetric.tmLastChar;
    174    }
    175 
    176    // The 'maxp' table stores the number of glyphs at offset 4, in 2 bytes.
    177    uint16_t glyphs;
    178    if (GDI_ERROR != GetFontData(hdc, SkOTTableMaximumProfile::TAG, 4, &glyphs, sizeof(glyphs))) {
    179        return SkEndian_SwapBE16(glyphs);
    180    }
    181 
    182    // Binary search for glyph count.
    183    static const MAT2 mat2 = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
    184    int32_t max = UINT16_MAX + 1;
    185    int32_t min = 0;
    186    GLYPHMETRICS gm;
    187    while (min < max) {
    188        int32_t mid = min + ((max - min) / 2);
    189        if (GetGlyphOutlineW(hdc, mid, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0,
    190                             nullptr, &mat2) == GDI_ERROR) {
    191            max = mid;
    192        } else {
    193            min = mid + 1;
    194        }
    195    }
    196    SkASSERT(min == max);
    197    return min;
    198 }
    199 
    200 static unsigned calculateUPEM(HDC hdc, const LOGFONT& lf) {
    201    TEXTMETRIC textMetric;
    202    if (0 == GetTextMetrics(hdc, &textMetric)) {
    203        textMetric.tmPitchAndFamily = TMPF_VECTOR;
    204        call_ensure_accessible(lf);
    205        GetTextMetrics(hdc, &textMetric);
    206    }
    207 
    208    if (!(textMetric.tmPitchAndFamily & TMPF_VECTOR)) {
    209        return textMetric.tmMaxCharWidth;
    210    }
    211 
    212    OUTLINETEXTMETRIC otm;
    213    unsigned int otmRet = GetOutlineTextMetrics(hdc, sizeof(otm), &otm);
    214    if (0 == otmRet) {
    215        call_ensure_accessible(lf);
    216        otmRet = GetOutlineTextMetrics(hdc, sizeof(otm), &otm);
    217    }
    218 
    219    return (0 == otmRet) ? 0 : otm.otmEMSquare;
    220 }
    221 
    222 class SkAutoHDC {
    223 public:
    224    explicit SkAutoHDC(const LOGFONT& lf)
    225        : fHdc(::CreateCompatibleDC(nullptr))
    226        , fFont(::CreateFontIndirect(&lf))
    227        , fSavefont((HFONT)::SelectObject(fHdc, fFont))
    228    { }
    229    ~SkAutoHDC() {
    230        if (fHdc) {
    231            ::SelectObject(fHdc, fSavefont);
    232            ::DeleteDC(fHdc);
    233        }
    234        if (fFont) {
    235            ::DeleteObject(fFont);
    236        }
    237    }
    238    operator HDC() { return fHdc; }
    239 private:
    240    HDC fHdc;
    241    HFONT fFont;
    242    HFONT fSavefont;
    243 };
    244 
    245 class LogFontTypeface : public SkTypeface {
    246 public:
    247    LogFontTypeface(const SkFontStyle& style, const LOGFONT& lf, bool serializeAsStream)
    248        : SkTypeface(style, false)
    249        , fLogFont(lf)
    250        , fSerializeAsStream(serializeAsStream)
    251    {
    252        SkAutoHDC hdc(fLogFont);
    253        TEXTMETRIC textMetric;
    254        if (0 == GetTextMetrics(hdc, &textMetric)) {
    255            call_ensure_accessible(lf);
    256            if (0 == GetTextMetrics(hdc, &textMetric)) {
    257                textMetric.tmPitchAndFamily = TMPF_TRUETYPE;
    258            }
    259        }
    260 
    261        // The fixed pitch bit is set if the font is *not* fixed pitch.
    262        this->setIsFixedPitch((textMetric.tmPitchAndFamily & TMPF_FIXED_PITCH) == 0);
    263        this->setFontStyle(SkFontStyle(textMetric.tmWeight, style.width(), style.slant()));
    264 
    265        // Used a logfont on a memory context, should never get a device font.
    266        // Therefore all TMPF_DEVICE will be PostScript (cubic) fonts.
    267        // If the font has cubic outlines, it will not be rendered with ClearType.
    268        fCanBeLCD = !((textMetric.tmPitchAndFamily & TMPF_VECTOR) &&
    269                      (textMetric.tmPitchAndFamily & TMPF_DEVICE));
    270    }
    271 
    272    LOGFONT fLogFont;
    273    bool fSerializeAsStream;
    274    bool fCanBeLCD;
    275 
    276    static sk_sp<LogFontTypeface> Make(const LOGFONT& lf) {
    277        return sk_sp<LogFontTypeface>(new LogFontTypeface(get_style(lf), lf, false));
    278    }
    279 
    280    static void EnsureAccessible(const SkTypeface* face) {
    281        call_ensure_accessible(static_cast<const LogFontTypeface*>(face)->fLogFont);
    282    }
    283 
    284 protected:
    285    std::unique_ptr<SkStreamAsset> onOpenStream(int* ttcIndex) const override;
    286    sk_sp<SkTypeface> onMakeClone(const SkFontArguments& args) const override;
    287    std::unique_ptr<SkScalerContext> onCreateScalerContext(const SkScalerContextEffects&,
    288                                                           const SkDescriptor*) const override;
    289    void onFilterRec(SkScalerContextRec*) const override;
    290    void getGlyphToUnicodeMap(SkSpan<SkUnichar>) const override;
    291    std::unique_ptr<SkAdvancedTypefaceMetrics> onGetAdvancedMetrics() const override;
    292    void onGetFontDescriptor(SkFontDescriptor*, bool*) const override;
    293    void onCharsToGlyphs(SkSpan<const SkUnichar>, SkSpan<SkGlyphID>) const override;
    294    int onCountGlyphs() const override;
    295    void getPostScriptGlyphNames(SkString*) const override;
    296    int onGetUPEM() const override;
    297    void onGetFamilyName(SkString* familyName) const override;
    298    bool onGetPostScriptName(SkString*) const override { return false; }
    299    SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const override;
    300    bool onGlyphMaskNeedsCurrentColor() const override { return false; }
    301    int onGetVariationDesignPosition(
    302                             SkSpan<SkFontArguments::VariationPosition::Coordinate>) const override
    303    {
    304        return -1;
    305    }
    306    int onGetVariationDesignParameters(SkSpan<SkFontParameters::Variation::Axis>) const override
    307    {
    308        return -1;
    309    }
    310    int onGetTableTags(SkSpan<SkFontTableTag>) const override;
    311    size_t onGetTableData(SkFontTableTag, size_t offset, size_t length, void* data) const override;
    312    sk_sp<SkData> onCopyTableData(SkFontTableTag) const override;
    313 };
    314 
    315 class FontMemResourceTypeface : public LogFontTypeface {
    316 public:
    317    /**
    318     *  The created FontMemResourceTypeface takes ownership of fontMemResource.
    319     */
    320    static sk_sp<FontMemResourceTypeface> Make(const LOGFONT& lf, HANDLE fontMemResource) {
    321        return sk_sp<FontMemResourceTypeface>(
    322            new FontMemResourceTypeface(get_style(lf), lf, fontMemResource));
    323    }
    324 
    325 protected:
    326    void weak_dispose() const override {
    327        RemoveFontMemResourceEx(fFontMemResource);
    328        INHERITED::weak_dispose();
    329    }
    330 
    331 private:
    332    /**
    333     *  Takes ownership of fontMemResource.
    334     */
    335    FontMemResourceTypeface(const SkFontStyle& style, const LOGFONT& lf, HANDLE fontMemResource)
    336        : LogFontTypeface(style, lf, true), fFontMemResource(fontMemResource)
    337    { }
    338 
    339    HANDLE fFontMemResource;
    340 
    341    using INHERITED = LogFontTypeface;
    342 };
    343 
    344 static const LOGFONT& get_default_font() {
    345    static LOGFONT gDefaultFont;
    346    return gDefaultFont;
    347 }
    348 
    349 static bool FindByLogFont(SkTypeface* face, void* ctx) {
    350    LogFontTypeface* lface = static_cast<LogFontTypeface*>(face);
    351    const LOGFONT* lf = reinterpret_cast<const LOGFONT*>(ctx);
    352 
    353    return !memcmp(&lface->fLogFont, lf, sizeof(LOGFONT));
    354 }
    355 
    356 /**
    357 *  This is public. It first searches the cache, and if a match is not found,
    358 *  it creates a new face.
    359 */
    360 sk_sp<SkTypeface> SkCreateTypefaceFromLOGFONT(const LOGFONT& origLF) {
    361    LOGFONT lf = origLF;
    362    make_canonical(&lf);
    363    sk_sp<SkTypeface> face = SkTypefaceCache::FindByProcAndRef(FindByLogFont, &lf);
    364    if (!face) {
    365        face = LogFontTypeface::Make(lf);
    366        SkTypefaceCache::Add(face);
    367    }
    368    return face;
    369 }
    370 
    371 /***
    372 * This guy is public.
    373 */
    374 SkTypeface* SkCreateTypefaceFromDWriteFont(IDWriteFactory* aFactory,
    375                                           IDWriteFontFace* aFontFace,
    376                                           IDWriteFont* aFont,
    377                                           IDWriteFontFamily* aFontFamily,
    378                                           SkFontStyle aStyle,
    379                                           int aRenderingMode,
    380                                           float aGamma,
    381                                           float aContrast,
    382                                           float aClearTypeLevel)
    383 {
    384  return DWriteFontTypeface::Create(aFactory, aFontFace, aFont, aFontFamily,
    385                                    aStyle,
    386                                    (DWRITE_RENDERING_MODE)aRenderingMode,
    387                                    aGamma, aContrast, aClearTypeLevel);
    388 }
    389 
    390 /**
    391 *  The created SkTypeface takes ownership of fontMemResource.
    392 */
    393 sk_sp<SkTypeface> SkCreateFontMemResourceTypefaceFromLOGFONT(const LOGFONT& origLF, HANDLE fontMemResource) {
    394    LOGFONT lf = origLF;
    395    make_canonical(&lf);
    396    // We'll never get a cache hit, so no point in putting this in SkTypefaceCache.
    397    return FontMemResourceTypeface::Make(lf, fontMemResource);
    398 }
    399 
    400 /**
    401 *  This is public
    402 */
    403 void SkLOGFONTFromTypeface(const SkTypeface* face, LOGFONT* lf) {
    404    if (nullptr == face) {
    405        *lf = get_default_font();
    406    } else {
    407        *lf = static_cast<const LogFontTypeface*>(face)->fLogFont;
    408    }
    409 }
    410 
    411 // Construct Glyph to Unicode table.
    412 // Unicode code points that require conjugate pairs in utf16 are not
    413 // supported.
    414 // TODO(arthurhsu): Add support for conjugate pairs. It looks like that may
    415 // require parsing the TTF cmap table (platform 4, encoding 12) directly instead
    416 // of calling GetFontUnicodeRange().
    417 static void populate_glyph_to_unicode(HDC fontHdc, const unsigned glyphCount,
    418                                      SkSpan<SkUnichar> glyphToUnicode) {
    419    sk_bzero(glyphToUnicode.data(), glyphToUnicode.size_bytes());
    420    DWORD glyphSetBufferSize = GetFontUnicodeRanges(fontHdc, nullptr);
    421    if (!glyphSetBufferSize) {
    422        return;
    423    }
    424 
    425    std::unique_ptr<BYTE[]> glyphSetBuffer(new BYTE[glyphSetBufferSize]);
    426    GLYPHSET* glyphSet =
    427        reinterpret_cast<LPGLYPHSET>(glyphSetBuffer.get());
    428    if (GetFontUnicodeRanges(fontHdc, glyphSet) != glyphSetBufferSize) {
    429        return;
    430    }
    431 
    432    for (DWORD i = 0; i < glyphSet->cRanges; ++i) {
    433        // There is no guarantee that within a Unicode range, the corresponding
    434        // glyph id in a font file are continuous. So, even if we have ranges,
    435        // we can't just use the first and last entry of the range to compute
    436        // result. We need to enumerate them one by one.
    437        int count = glyphSet->ranges[i].cGlyphs;
    438        AutoTArray<WCHAR> chars(count + 1);
    439        chars[count] = 0;  // termintate string
    440        AutoTArray<WORD> glyph(count);
    441        for (USHORT j = 0; j < count; ++j) {
    442            chars[j] = glyphSet->ranges[i].wcLow + j;
    443        }
    444        GetGlyphIndicesW(fontHdc, chars.get(), count, glyph.get(),
    445                         GGI_MARK_NONEXISTING_GLYPHS);
    446        // If the glyph ID is valid, and the glyph is not mapped, then we will
    447        // fill in the char id into the vector. If the glyph is mapped already,
    448        // skip it.
    449        // TODO(arthurhsu): better improve this. e.g. Get all used char ids from
    450        // font cache, then generate this mapping table from there. It's
    451        // unlikely to have collisions since glyph reuse happens mostly for
    452        // different Unicode pages.
    453        for (USHORT j = 0; j < count; ++j) {
    454            if (glyph[j] != 0xFFFF && glyph[j] < glyphCount && glyphToUnicode[glyph[j]] == 0) {
    455                glyphToUnicode[glyph[j]] = chars[j];
    456            }
    457        }
    458    }
    459 }
    460 
    461 //////////////////////////////////////////////////////////////////////////////////////
    462 
    463 static int alignTo32(int n) {
    464    return (n + 31) & ~31;
    465 }
    466 
    467 struct MyBitmapInfo : public BITMAPINFO {
    468    RGBQUAD fMoreSpaceForColors[1];
    469 };
    470 
    471 class HDCOffscreen {
    472 public:
    473    HDCOffscreen() = default;
    474 
    475    ~HDCOffscreen() {
    476        if (fDC) {
    477            ::SelectObject(fDC, fSavefont);
    478            ::DeleteDC(fDC);
    479        }
    480        if (fBM) {
    481            DeleteObject(fBM);
    482        }
    483    }
    484 
    485    void init(HFONT font, const XFORM& xform) {
    486        fFont = font;
    487        fXform = xform;
    488    }
    489 
    490    void* draw(const SkGlyph&, bool isBW, size_t* srcRBPtr);
    491 
    492 private:
    493    HDC     fDC{nullptr};
    494    HFONT   fSavefont{nullptr};
    495    HBITMAP fBM{nullptr};
    496    HFONT   fFont{nullptr};
    497    XFORM   fXform{1, 0, 0, 1, 0, 0};
    498    void*   fBits{nullptr};  // points into fBM
    499    int     fWidth{0};
    500    int     fHeight{0};
    501    bool    fIsBW{false};
    502 };
    503 
    504 void* HDCOffscreen::draw(const SkGlyph& glyph, bool isBW, size_t* srcRBPtr) {
    505    // Can we share the scalercontext's fDDC, so we don't need to create
    506    // a separate fDC here?
    507    if (nullptr == fDC) {
    508        fDC = CreateCompatibleDC(0);
    509        if (nullptr == fDC) {
    510            return nullptr;
    511        }
    512        SetGraphicsMode(fDC, GM_ADVANCED);
    513        SetBkMode(fDC, TRANSPARENT);
    514        SetTextAlign(fDC, TA_LEFT | TA_BASELINE);
    515        fSavefont = (HFONT)SelectObject(fDC, fFont);
    516 
    517        COLORREF color = 0x00FFFFFF;
    518        SkDEBUGCODE(COLORREF prev =) SetTextColor(fDC, color);
    519        SkASSERT(prev != CLR_INVALID);
    520    }
    521 
    522    if (fBM && (fIsBW != isBW || fWidth < glyph.width() || fHeight < glyph.height())) {
    523        DeleteObject(fBM);
    524        fBM = nullptr;
    525    }
    526    fIsBW = isBW;
    527 
    528    fWidth = std::max(fWidth, glyph.width());
    529    fHeight = std::max(fHeight, glyph.height());
    530 
    531    int biWidth = isBW ? alignTo32(fWidth) : fWidth;
    532 
    533    if (nullptr == fBM) {
    534        MyBitmapInfo info;
    535        sk_bzero(&info, sizeof(info));
    536        if (isBW) {
    537            RGBQUAD blackQuad = { 0, 0, 0, 0 };
    538            RGBQUAD whiteQuad = { 0xFF, 0xFF, 0xFF, 0 };
    539            info.bmiColors[0] = blackQuad;
    540            info.bmiColors[1] = whiteQuad;
    541        }
    542        info.bmiHeader.biSize = sizeof(info.bmiHeader);
    543        info.bmiHeader.biWidth = biWidth;
    544        info.bmiHeader.biHeight = fHeight;
    545        info.bmiHeader.biPlanes = 1;
    546        info.bmiHeader.biBitCount = isBW ? 1 : 32;
    547        info.bmiHeader.biCompression = BI_RGB;
    548        if (isBW) {
    549            info.bmiHeader.biClrUsed = 2;
    550        }
    551        fBM = CreateDIBSection(fDC, &info, DIB_RGB_COLORS, &fBits, 0, 0);
    552        if (nullptr == fBM) {
    553            return nullptr;
    554        }
    555        SelectObject(fDC, fBM);
    556    }
    557 
    558    // erase
    559    size_t srcRB = isBW ? (biWidth >> 3) : (fWidth << 2);
    560    size_t size = fHeight * srcRB;
    561    memset(fBits, 0, size);
    562 
    563    XFORM xform = fXform;
    564    xform.eDx = (float)-glyph.left();
    565    xform.eDy = (float)-glyph.top();
    566    SetWorldTransform(fDC, &xform);
    567 
    568    uint16_t glyphID = glyph.getGlyphID();
    569    BOOL ret = ExtTextOutW(fDC, 0, 0, ETO_GLYPH_INDEX, nullptr, reinterpret_cast<LPCWSTR>(&glyphID),
    570                           1, nullptr);
    571    GdiFlush();
    572    if (0 == ret) {
    573        return nullptr;
    574    }
    575    *srcRBPtr = srcRB;
    576    // offset to the start of the image
    577    return (char*)fBits + (fHeight - glyph.height()) * srcRB;
    578 }
    579 
    580 //////////////////////////////////////////////////////////////////////////////
    581 #define BUFFERSIZE (1 << 13)
    582 
    583 class SkScalerContext_GDI : public SkScalerContext {
    584 public:
    585    SkScalerContext_GDI(LogFontTypeface&,
    586                        const SkScalerContextEffects&,
    587                        const SkDescriptor* desc);
    588    ~SkScalerContext_GDI() override;
    589 
    590    // Returns true if the constructor was able to complete all of its
    591    // initializations (which may include calling GDI).
    592    bool isValid() const;
    593 
    594 protected:
    595    GlyphMetrics generateMetrics(const SkGlyph&, SkArenaAlloc*) override;
    596    void generateImage(const SkGlyph&, void* imageBuffer) override;
    597    std::optional<GeneratedPath> generatePath(const SkGlyph&) override;
    598    void generateFontMetrics(SkFontMetrics*) override;
    599 
    600 private:
    601    DWORD getGDIGlyphPath(SkGlyphID glyph, UINT flags,
    602                          AutoSTMalloc<BUFFERSIZE, uint8_t>* glyphbuf);
    603    template<bool APPLY_PREBLEND>
    604    static void RGBToA8(const SkGdiRGB* SK_RESTRICT src, size_t srcRB,
    605                        const SkGlyph& glyph, void* imageBuffer, const uint8_t* table8);
    606 
    607    template<bool APPLY_PREBLEND>
    608    static void RGBToLcd16(const SkGdiRGB* SK_RESTRICT src, size_t srcRB, const SkGlyph& glyph,
    609                           void* imageBuffer,
    610                           const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB);
    611 
    612    HDCOffscreen fOffscreen;
    613    /** fGsA is the non-rotational part of total matrix without the text height scale.
    614     *  Used to find the magnitude of advances.
    615     */
    616    MAT2         fGsA;
    617    /** The total matrix without the textSize. */
    618    MAT2         fMat22;
    619    /** Scales font to EM size. */
    620    MAT2         fHighResMat22;
    621    HDC          fDDC;
    622    HFONT        fSavefont;
    623    HFONT        fFont;
    624    SCRIPT_CACHE fSC;
    625 
    626    /** The total matrix which also removes EM scale. */
    627    SkMatrix     fHiResMatrix;
    628    /** fG_inv is the inverse of the rotational part of the total matrix.
    629     *  Used to set the direction of advances.
    630     */
    631    SkMatrix     fG_inv;
    632    enum Type {
    633        kTrueType_Type, kBitmap_Type, kLine_Type
    634    } fType;
    635    bool fGenerateFromPath;
    636    TEXTMETRIC fTM;
    637 };
    638 
    639 static FIXED SkFloatToFIXED(float x) {
    640    return SkFixedToFIXED(SkFloatToFixed(x));
    641 }
    642 
    643 static inline float SkFIXEDToFloat(FIXED x) {
    644    return SkFixedToFloat(SkFIXEDToFixed(x));
    645 }
    646 
    647 static BYTE compute_quality(const SkScalerContextRec& rec) {
    648    switch (rec.fMaskFormat) {
    649        case SkMask::kBW_Format:
    650            return NONANTIALIASED_QUALITY;
    651        case SkMask::kLCD16_Format:
    652            return CLEARTYPE_QUALITY;
    653        default:
    654            if (rec.fFlags & SkScalerContext::kGenA8FromLCD_Flag) {
    655                return CLEARTYPE_QUALITY;
    656            } else {
    657                return ANTIALIASED_QUALITY;
    658            }
    659    }
    660 }
    661 
    662 SkScalerContext_GDI::SkScalerContext_GDI(LogFontTypeface& rawTypeface,
    663                                         const SkScalerContextEffects& effects,
    664                                         const SkDescriptor* desc)
    665        : SkScalerContext(rawTypeface, effects, desc)
    666        , fDDC(nullptr)
    667        , fSavefont(nullptr)
    668        , fFont(nullptr)
    669        , fSC(nullptr)
    670        , fGenerateFromPath(false)
    671 {
    672    LogFontTypeface* typeface = static_cast<LogFontTypeface*>(this->getTypeface());
    673 
    674    fDDC = ::CreateCompatibleDC(nullptr);
    675    if (!fDDC) {
    676        return;
    677    }
    678    SetGraphicsMode(fDDC, GM_ADVANCED);
    679    SetBkMode(fDDC, TRANSPARENT);
    680 
    681    // When GDI hinting, remove the entire Y scale from sA and GsA. (Prevents 'linear' metrics.)
    682    // When not hinting, remove only the integer Y scale from sA and GsA. (Applied by GDI.)
    683    SkScalerContextRec::PreMatrixScale scaleConstraints =
    684        (fRec.getHinting() == SkFontHinting::kNone || fRec.getHinting() == SkFontHinting::kSlight)
    685                   ? SkScalerContextRec::PreMatrixScale::kVerticalInteger
    686                   : SkScalerContextRec::PreMatrixScale::kVertical;
    687    SkVector scale;
    688    SkMatrix sA;
    689    SkMatrix GsA;
    690    SkMatrix A;
    691    fRec.computeMatrices(scaleConstraints, &scale, &sA, &GsA, &fG_inv, &A);
    692 
    693    fGsA.eM11 = SkScalarToFIXED(GsA.get(SkMatrix::kMScaleX));
    694    fGsA.eM12 = SkScalarToFIXED(-GsA.get(SkMatrix::kMSkewY)); // This should be ~0.
    695    fGsA.eM21 = SkScalarToFIXED(-GsA.get(SkMatrix::kMSkewX));
    696    fGsA.eM22 = SkScalarToFIXED(GsA.get(SkMatrix::kMScaleY));
    697 
    698    // When not hinting, scale was computed with kVerticalInteger, so is already an integer.
    699    // The sA and GsA transforms will be used to create 'linear' metrics.
    700 
    701    // When hinting, scale was computed with kVertical, stating that our port can handle
    702    // non-integer scales. This is done so that sA and GsA are computed without any 'residual'
    703    // scale in them, preventing 'linear' metrics. However, GDI cannot actually handle non-integer
    704    // scales so we need to round in this case. This is fine, since all of the scale has been
    705    // removed from sA and GsA, so GDI will be handling the scale completely.
    706    SkScalar gdiTextSize = SkScalarRoundToScalar(scale.fY);
    707 
    708    // GDI will not accept a size of zero, so round the range [0, 1] to 1.
    709    // If the size was non-zero, the scale factors will also be non-zero and 1px tall text is drawn.
    710    // If the size actually was zero, the scale factors will also be zero, so GDI will draw nothing.
    711    if (gdiTextSize == 0) {
    712        gdiTextSize = SK_Scalar1;
    713    }
    714 
    715    LOGFONT lf = typeface->fLogFont;
    716    lf.lfHeight = -SkScalarTruncToInt(gdiTextSize);
    717    lf.lfQuality = compute_quality(fRec);
    718    fFont = CreateFontIndirect(&lf);
    719    if (!fFont) {
    720        return;
    721    }
    722 
    723    fSavefont = (HFONT)SelectObject(fDDC, fFont);
    724 
    725    if (0 == GetTextMetrics(fDDC, &fTM)) {
    726        call_ensure_accessible(lf);
    727        if (0 == GetTextMetrics(fDDC, &fTM)) {
    728            fTM.tmPitchAndFamily = TMPF_TRUETYPE;
    729        }
    730    }
    731 
    732    XFORM xform;
    733    if (fTM.tmPitchAndFamily & TMPF_VECTOR) {
    734        // Used a logfont on a memory context, should never get a device font.
    735        // Therefore all TMPF_DEVICE will be PostScript fonts.
    736 
    737        // If TMPF_VECTOR is set, one of TMPF_TRUETYPE or TMPF_DEVICE means that
    738        // we have an outline font. Otherwise we have a vector FON, which is
    739        // scalable, but not an outline font.
    740        // This was determined by testing with Type1 PFM/PFB and
    741        // OpenTypeCFF OTF, as well as looking at Wine bugs and sources.
    742        if (fTM.tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_DEVICE)) {
    743            // Truetype or PostScript.
    744            fType = SkScalerContext_GDI::kTrueType_Type;
    745        } else {
    746            // Stroked FON.
    747            fType = SkScalerContext_GDI::kLine_Type;
    748        }
    749 
    750        // fPost2x2 is column-major, left handed (y down).
    751        // XFORM 2x2 is row-major, left handed (y down).
    752        xform.eM11 = SkScalarToFloat(sA.get(SkMatrix::kMScaleX));
    753        xform.eM12 = SkScalarToFloat(sA.get(SkMatrix::kMSkewY));
    754        xform.eM21 = SkScalarToFloat(sA.get(SkMatrix::kMSkewX));
    755        xform.eM22 = SkScalarToFloat(sA.get(SkMatrix::kMScaleY));
    756        xform.eDx = 0;
    757        xform.eDy = 0;
    758 
    759        // MAT2 is row major, right handed (y up).
    760        fMat22.eM11 = SkFloatToFIXED(xform.eM11);
    761        fMat22.eM12 = SkFloatToFIXED(-xform.eM12);
    762        fMat22.eM21 = SkFloatToFIXED(-xform.eM21);
    763        fMat22.eM22 = SkFloatToFIXED(xform.eM22);
    764 
    765        if (needToRenderWithSkia(fRec)) {
    766            fGenerateFromPath = true;
    767        }
    768 
    769        // Create a hires matrix if we need linear metrics.
    770        if (this->isLinearMetrics()) {
    771            OUTLINETEXTMETRIC otm;
    772            UINT success = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm);
    773            if (0 == success) {
    774                call_ensure_accessible(lf);
    775                success = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm);
    776            }
    777            if (0 != success) {
    778                SkScalar upem = SkIntToScalar(otm.otmEMSquare);
    779 
    780                SkScalar gdiTextSizeToEMScale = upem / gdiTextSize;
    781                fHighResMat22.eM11 = SkScalarToFIXED(gdiTextSizeToEMScale);
    782                fHighResMat22.eM12 = SkScalarToFIXED(0);
    783                fHighResMat22.eM21 = SkScalarToFIXED(0);
    784                fHighResMat22.eM22 = SkScalarToFIXED(gdiTextSizeToEMScale);
    785 
    786                SkScalar removeEMScale = SkScalarInvert(upem);
    787                fHiResMatrix = A;
    788                fHiResMatrix.preScale(removeEMScale, removeEMScale);
    789            }
    790        }
    791 
    792    } else {
    793        // Assume bitmap
    794        fType = SkScalerContext_GDI::kBitmap_Type;
    795 
    796        xform.eM11 = 1.0f;
    797        xform.eM12 = 0.0f;
    798        xform.eM21 = 0.0f;
    799        xform.eM22 = 1.0f;
    800        xform.eDx = 0.0f;
    801        xform.eDy = 0.0f;
    802 
    803        // fPost2x2 is column-major, left handed (y down).
    804        // MAT2 is row major, right handed (y up).
    805        fMat22.eM11 = SkScalarToFIXED(fRec.fPost2x2[0][0]);
    806        fMat22.eM12 = SkScalarToFIXED(-fRec.fPost2x2[1][0]);
    807        fMat22.eM21 = SkScalarToFIXED(-fRec.fPost2x2[0][1]);
    808        fMat22.eM22 = SkScalarToFIXED(fRec.fPost2x2[1][1]);
    809    }
    810 
    811    fOffscreen.init(fFont, xform);
    812 }
    813 
    814 SkScalerContext_GDI::~SkScalerContext_GDI() {
    815    if (fDDC) {
    816        ::SelectObject(fDDC, fSavefont);
    817        ::DeleteDC(fDDC);
    818    }
    819    if (fFont) {
    820        ::DeleteObject(fFont);
    821    }
    822    if (fSC) {
    823        ::ScriptFreeCache(&fSC);
    824    }
    825 }
    826 
    827 bool SkScalerContext_GDI::isValid() const {
    828    return fDDC && fFont;
    829 }
    830 
    831 SkScalerContext::GlyphMetrics SkScalerContext_GDI::generateMetrics(const SkGlyph& glyph,
    832                                                                   SkArenaAlloc*) {
    833    SkASSERT(fDDC);
    834 
    835    GlyphMetrics mx(glyph.maskFormat());
    836 
    837    if (fType == SkScalerContext_GDI::kBitmap_Type || fType == SkScalerContext_GDI::kLine_Type) {
    838        SIZE size;
    839        WORD glyphs = glyph.getGlyphID();
    840        int width, height;
    841        if (0 == GetTextExtentPointI(fDDC, &glyphs, 1, &size)) {
    842            width = fTM.tmMaxCharWidth;
    843            height = fTM.tmHeight;
    844        } else {
    845            width = size.cx;
    846            height = size.cy;
    847        }
    848 
    849        // Bitmap FON cannot underhang, but vector FON may.
    850        // There appears no means of determining underhang of vector FON.
    851        int left = 0;
    852        int top = -fTM.tmAscent;
    853 
    854        mx.bounds = SkRect::MakeXYWH(left, top, width, height);
    855        mx.advance = SkVector{(float)width, 0};
    856 
    857        // Vector FON will transform nicely, but bitmap FON do not.
    858        if (fType == SkScalerContext_GDI::kLine_Type) {
    859            SkRect bounds = SkRect::MakeXYWH(left, top, width, height);
    860            SkMatrix m;
    861            m.setAll(SkFIXEDToScalar(fMat22.eM11), -SkFIXEDToScalar(fMat22.eM21), 0,
    862                     -SkFIXEDToScalar(fMat22.eM12), SkFIXEDToScalar(fMat22.eM22), 0,
    863                     0,  0, 1);
    864            m.mapRect(&bounds);
    865            bounds.roundOut(&mx.bounds);
    866        }
    867 
    868        // Apply matrix to advance.
    869        mx.advance.fY = -SkFIXEDToFloat(fMat22.eM12) * mx.advance.fX;
    870        mx.advance.fX *= SkFIXEDToFloat(fMat22.eM11);
    871 
    872        // These do not have an outline path at all.
    873        mx.neverRequestPath = true;
    874        return mx;
    875    }
    876 
    877    UINT glyphId = glyph.getGlyphID();
    878 
    879    GLYPHMETRICS gm;
    880    sk_bzero(&gm, sizeof(gm));
    881 
    882    DWORD status = GetGlyphOutlineW(fDDC, glyphId, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, nullptr, &fMat22);
    883    if (GDI_ERROR == status) {
    884        LogFontTypeface::EnsureAccessible(this->getTypeface());
    885        status = GetGlyphOutlineW(fDDC, glyphId, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, nullptr, &fMat22);
    886        if (GDI_ERROR == status) {
    887            return mx;
    888        }
    889    }
    890 
    891    bool empty = false;
    892    // The black box is either the embedded bitmap size or the outline extent.
    893    // It is 1x1 if nothing is to be drawn, but will also be 1x1 if something very small
    894    // is to be drawn, like a '.'. We need to outset '.' but do not wish to outset ' '.
    895    if (1 == gm.gmBlackBoxX && 1 == gm.gmBlackBoxY) {
    896        // If GetGlyphOutline with GGO_NATIVE returns 0, we know there was no outline.
    897        DWORD bufferSize = GetGlyphOutlineW(fDDC, glyphId, GGO_NATIVE | GGO_GLYPH_INDEX, &gm, 0, nullptr, &fMat22);
    898        empty = (0 == bufferSize);
    899    }
    900 
    901 
    902    if (!empty) {
    903        int y  = -gm.gmptGlyphOrigin.y;
    904        int x =  gm.gmptGlyphOrigin.x;
    905        // Outset, since the image may bleed out of the black box.
    906        // For embedded bitmaps the black box should be exact.
    907        // For outlines we need to outset by 1 in all directions for bleed.
    908        // For ClearType we need to outset by 2 for bleed.
    909        mx.bounds = SkRect::MakeXYWH(x, y, gm.gmBlackBoxX, gm.gmBlackBoxY).makeOutset(2, 2);
    910    }
    911    // TODO(benjaminwagner): What is the type of gm.gmCellInc[XY]?
    912    mx.advance.fX = (float)((int)gm.gmCellIncX);
    913    mx.advance.fY = (float)((int)gm.gmCellIncY);
    914 
    915    if ((fTM.tmPitchAndFamily & TMPF_VECTOR) && this->isLinearMetrics()) {
    916        sk_bzero(&gm, sizeof(gm));
    917        status = GetGlyphOutlineW(fDDC, glyphId, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, nullptr, &fHighResMat22);
    918        if (GDI_ERROR != status) {
    919            mx.advance = fHiResMatrix.mapPoint({SkIntToScalar(gm.gmCellIncX),
    920                                                SkIntToScalar(gm.gmCellIncY)});
    921        }
    922    } else if (!isAxisAligned(this->fRec)) {
    923        status = GetGlyphOutlineW(fDDC, glyphId, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, nullptr, &fGsA);
    924        if (GDI_ERROR != status) {
    925            mx.advance = fG_inv.mapPoint({SkIntToScalar(gm.gmCellIncX), SkIntToScalar(gm.gmCellIncY)});
    926        }
    927    }
    928 
    929    mx.computeFromPath = fGenerateFromPath;
    930    return mx;
    931 }
    932 
    933 static const MAT2 gMat2Identity = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
    934 void SkScalerContext_GDI::generateFontMetrics(SkFontMetrics* metrics) {
    935    if (nullptr == metrics) {
    936        return;
    937    }
    938    sk_bzero(metrics, sizeof(*metrics));
    939 
    940    SkASSERT(fDDC);
    941 
    942 #ifndef SK_GDI_ALWAYS_USE_TEXTMETRICS_FOR_FONT_METRICS
    943    if (fType == SkScalerContext_GDI::kBitmap_Type || fType == SkScalerContext_GDI::kLine_Type) {
    944 #endif
    945        metrics->fTop = SkIntToScalar(-fTM.tmAscent);
    946        metrics->fAscent = SkIntToScalar(-fTM.tmAscent);
    947        metrics->fDescent = SkIntToScalar(fTM.tmDescent);
    948        metrics->fBottom = SkIntToScalar(fTM.tmDescent);
    949        metrics->fLeading = SkIntToScalar(fTM.tmExternalLeading);
    950        metrics->fAvgCharWidth = SkIntToScalar(fTM.tmAveCharWidth);
    951        metrics->fMaxCharWidth = SkIntToScalar(fTM.tmMaxCharWidth);
    952        metrics->fXMin = 0;
    953        metrics->fXMax = metrics->fMaxCharWidth;
    954        //metrics->fXHeight = 0;
    955 #ifndef SK_GDI_ALWAYS_USE_TEXTMETRICS_FOR_FONT_METRICS
    956        return;
    957    }
    958 #endif
    959 
    960    OUTLINETEXTMETRIC otm;
    961 
    962    uint32_t ret = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm);
    963    if (0 == ret) {
    964        LogFontTypeface::EnsureAccessible(this->getTypeface());
    965        ret = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm);
    966    }
    967    if (0 == ret) {
    968        return;
    969    }
    970 
    971 #ifndef SK_GDI_ALWAYS_USE_TEXTMETRICS_FOR_FONT_METRICS
    972    metrics->fTop = SkIntToScalar(-otm.otmrcFontBox.top);
    973    metrics->fAscent = SkIntToScalar(-otm.otmAscent);
    974    metrics->fDescent = SkIntToScalar(-otm.otmDescent);
    975    metrics->fBottom = SkIntToScalar(-otm.otmrcFontBox.bottom);
    976    metrics->fLeading = SkIntToScalar(otm.otmLineGap);
    977    metrics->fAvgCharWidth = SkIntToScalar(otm.otmTextMetrics.tmAveCharWidth);
    978    metrics->fMaxCharWidth = SkIntToScalar(otm.otmTextMetrics.tmMaxCharWidth);
    979    metrics->fXMin = SkIntToScalar(otm.otmrcFontBox.left);
    980    metrics->fXMax = SkIntToScalar(otm.otmrcFontBox.right);
    981 #endif
    982    metrics->fUnderlineThickness = SkIntToScalar(otm.otmsUnderscoreSize);
    983    metrics->fUnderlinePosition = -SkIntToScalar(otm.otmsUnderscorePosition);
    984 
    985    metrics->fFlags |= SkFontMetrics::kUnderlineThicknessIsValid_Flag;
    986    metrics->fFlags |= SkFontMetrics::kUnderlinePositionIsValid_Flag;
    987 
    988    metrics->fXHeight = SkIntToScalar(otm.otmsXHeight);
    989    GLYPHMETRICS gm;
    990    sk_bzero(&gm, sizeof(gm));
    991    DWORD len = GetGlyphOutlineW(fDDC, 'x', GGO_METRICS, &gm, 0, nullptr, &gMat2Identity);
    992    if (len != GDI_ERROR && gm.gmBlackBoxY > 0) {
    993        metrics->fXHeight = SkIntToScalar(gm.gmBlackBoxY);
    994    }
    995 }
    996 
    997 ////////////////////////////////////////////////////////////////////////////////////////
    998 
    999 static void build_power_table(uint8_t table[], float ee) {
   1000    for (int i = 0; i < 256; i++) {
   1001        float x = i / 255.f;
   1002        x = std::pow(x, ee);
   1003        int xx = SkScalarRoundToInt(x * 255);
   1004        table[i] = SkToU8(xx);
   1005    }
   1006 }
   1007 
   1008 /**
   1009 *  This will invert the gamma applied by GDI (gray-scale antialiased), so we
   1010 *  can get linear values.
   1011 *
   1012 *  GDI grayscale appears to use a hard-coded gamma of 2.3.
   1013 *
   1014 *  GDI grayscale appears to draw using the black and white rasterizer at four
   1015 *  times the size and then downsamples to compute the coverage mask. As a
   1016 *  result there are only seventeen total grays. This lack of fidelity means
   1017 *  that shifting into other color spaces is imprecise.
   1018 */
   1019 static const uint8_t* getInverseGammaTableGDI() {
   1020    static SkOnce once;
   1021    static uint8_t gTableGdi[256];
   1022    once([]{
   1023        build_power_table(gTableGdi, 2.3f);
   1024    });
   1025    return gTableGdi;
   1026 }
   1027 
   1028 /**
   1029 *  This will invert the gamma applied by GDI ClearType, so we can get linear
   1030 *  values.
   1031 *
   1032 *  GDI ClearType uses SPI_GETFONTSMOOTHINGCONTRAST / 1000 as the gamma value.
   1033 *  If this value is not specified, the default is a gamma of 1.4.
   1034 */
   1035 static const uint8_t* getInverseGammaTableClearType() {
   1036    static SkOnce once;
   1037    static uint8_t gTableClearType[256];
   1038    once([]{
   1039        UINT level = 0;
   1040        if (!SystemParametersInfo(SPI_GETFONTSMOOTHINGCONTRAST, 0, &level, 0) || !level) {
   1041            // can't get the data, so use a default
   1042            level = 1400;
   1043        }
   1044        build_power_table(gTableClearType, level / 1000.0f);
   1045    });
   1046    return gTableClearType;
   1047 }
   1048 
   1049 #include "src/core/SkColorData.h"
   1050 
   1051 //Cannot assume that the input rgb is gray due to possible setting of kGenA8FromLCD_Flag.
   1052 template<bool APPLY_PREBLEND>
   1053 static inline uint8_t rgb_to_a8(SkGdiRGB rgb, const uint8_t* table8) {
   1054    U8CPU r = (rgb >> 16) & 0xFF;
   1055    U8CPU g = (rgb >>  8) & 0xFF;
   1056    U8CPU b = (rgb >>  0) & 0xFF;
   1057    return sk_apply_lut_if<APPLY_PREBLEND>(SkComputeLuminance(r, g, b), table8);
   1058 }
   1059 
   1060 template<bool APPLY_PREBLEND>
   1061 static inline uint16_t rgb_to_lcd16(SkGdiRGB rgb, const uint8_t* tableR,
   1062                                                  const uint8_t* tableG,
   1063                                                  const uint8_t* tableB) {
   1064    U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 16) & 0xFF, tableR);
   1065    U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>((rgb >>  8) & 0xFF, tableG);
   1066    U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>((rgb >>  0) & 0xFF, tableB);
   1067    if constexpr (kSkShowTextBlitCoverage) {
   1068        r = std::max(r, 10u);
   1069        g = std::max(g, 10u);
   1070        b = std::max(b, 10u);
   1071    }
   1072    return SkPack888ToRGB16(r, g, b);
   1073 }
   1074 
   1075 template<bool APPLY_PREBLEND>
   1076 void SkScalerContext_GDI::RGBToA8(const SkGdiRGB* SK_RESTRICT src, size_t srcRB,
   1077                                  const SkGlyph& glyph, void* imageBuffer, const uint8_t* table8) {
   1078    const size_t dstRB = glyph.rowBytes();
   1079    const int width = glyph.width();
   1080    uint8_t* SK_RESTRICT dst = (uint8_t*)((char*)imageBuffer + (glyph.height() - 1) * dstRB);
   1081 
   1082    for (int y = 0; y < glyph.height(); y++) {
   1083        for (int i = 0; i < width; i++) {
   1084            dst[i] = rgb_to_a8<APPLY_PREBLEND>(src[i], table8);
   1085            if constexpr (kSkShowTextBlitCoverage) {
   1086                dst[i] = std::max<uint8_t>(dst[i], 10u);
   1087            }
   1088        }
   1089        src = SkTAddOffset<const SkGdiRGB>(src, srcRB);
   1090        dst -= dstRB;
   1091    }
   1092 }
   1093 
   1094 template<bool APPLY_PREBLEND>
   1095 void SkScalerContext_GDI::RGBToLcd16(
   1096        const SkGdiRGB* SK_RESTRICT src, size_t srcRB, const SkGlyph& glyph, void* imageBuffer,
   1097        const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) {
   1098    const size_t dstRB = glyph.rowBytes();
   1099    const int width = glyph.width();
   1100    uint16_t* SK_RESTRICT dst = (uint16_t*)((char*)imageBuffer + (glyph.height() - 1) * dstRB);
   1101 
   1102    for (int y = 0; y < glyph.height(); y++) {
   1103        for (int i = 0; i < width; i++) {
   1104            dst[i] = rgb_to_lcd16<APPLY_PREBLEND>(src[i], tableR, tableG, tableB);
   1105        }
   1106        src = SkTAddOffset<const SkGdiRGB>(src, srcRB);
   1107        dst = (uint16_t*)((char*)dst - dstRB);
   1108    }
   1109 }
   1110 
   1111 void SkScalerContext_GDI::generateImage(const SkGlyph& glyph, void* imageBuffer) {
   1112    SkASSERT(fDDC);
   1113 
   1114    if (fGenerateFromPath && glyph.path()) {
   1115        this->generateImageFromPath(glyph, imageBuffer);
   1116        return;
   1117    }
   1118 
   1119    const bool isBW = SkMask::kBW_Format == fRec.fMaskFormat;
   1120    const bool isAA = !isLCD(fRec);
   1121 
   1122    size_t srcRB;
   1123    void* bits = fOffscreen.draw(glyph, isBW, &srcRB);
   1124    if (nullptr == bits) {
   1125        LogFontTypeface::EnsureAccessible(this->getTypeface());
   1126        bits = fOffscreen.draw(glyph, isBW, &srcRB);
   1127        if (nullptr == bits) {
   1128            sk_bzero(imageBuffer, glyph.imageSize());
   1129            return;
   1130        }
   1131    }
   1132 
   1133    if (!isBW) {
   1134        const uint8_t* table;
   1135        //The offscreen contains a GDI blit if isAA and kGenA8FromLCD_Flag is not set.
   1136        //Otherwise the offscreen contains a ClearType blit.
   1137        if (isAA && !(fRec.fFlags & SkScalerContext::kGenA8FromLCD_Flag)) {
   1138            table = getInverseGammaTableGDI();
   1139        } else {
   1140            table = getInverseGammaTableClearType();
   1141        }
   1142        //Note that the following cannot really be integrated into the
   1143        //pre-blend, since we may not be applying the pre-blend; when we aren't
   1144        //applying the pre-blend it means that a filter wants linear anyway.
   1145        //Other code may also be applying the pre-blend, so we'd need another
   1146        //one with this and one without.
   1147        SkGdiRGB* addr = (SkGdiRGB*)bits;
   1148        for (int y = 0; y < glyph.height(); ++y) {
   1149            for (int x = 0; x < glyph.width(); ++x) {
   1150                int r = (addr[x] >> 16) & 0xFF;
   1151                int g = (addr[x] >>  8) & 0xFF;
   1152                int b = (addr[x] >>  0) & 0xFF;
   1153                addr[x] = (table[r] << 16) | (table[g] << 8) | table[b];
   1154            }
   1155            addr = SkTAddOffset<SkGdiRGB>(addr, srcRB);
   1156        }
   1157    }
   1158 
   1159    size_t dstRB = glyph.rowBytes();
   1160    if (isBW) {
   1161        const uint8_t* src = (const uint8_t*)bits;
   1162        uint8_t* dst = (uint8_t*)((char*)imageBuffer + (glyph.height() - 1) * dstRB);
   1163        for (int y = 0; y < glyph.height(); y++) {
   1164            memcpy(dst, src, dstRB);
   1165            src += srcRB;
   1166            dst -= dstRB;
   1167        }
   1168        if constexpr (kSkShowTextBlitCoverage) {
   1169            if (glyph.width() > 0 && glyph.height() > 0) {
   1170                int bitCount = glyph.width() & 7;
   1171                uint8_t* first = (uint8_t*)imageBuffer;
   1172                uint8_t* last = first + glyph.height() * dstRB - 1;
   1173                *first |= 1 << 7;
   1174                *last |= bitCount == 0 ? 1 : 1 << (8 - bitCount);
   1175            }
   1176        }
   1177    } else if (isAA) {
   1178        // since the caller may require A8 for maskfilters, we can't check for BW
   1179        // ... until we have the caller tell us that explicitly
   1180        const SkGdiRGB* src = (const SkGdiRGB*)bits;
   1181        if (fPreBlend.isApplicable()) {
   1182            RGBToA8<true>(src, srcRB, glyph, imageBuffer, fPreBlend.fG);
   1183        } else {
   1184            RGBToA8<false>(src, srcRB, glyph, imageBuffer, fPreBlend.fG);
   1185        }
   1186    } else {    // LCD16
   1187        const SkGdiRGB* src = (const SkGdiRGB*)bits;
   1188        SkASSERT(SkMask::kLCD16_Format == glyph.maskFormat());
   1189        if (fPreBlend.isApplicable()) {
   1190            RGBToLcd16<true>(src, srcRB, glyph, imageBuffer,
   1191                             fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
   1192        } else {
   1193            RGBToLcd16<false>(src, srcRB, glyph, imageBuffer,
   1194                              fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
   1195        }
   1196    }
   1197 }
   1198 
   1199 namespace {
   1200 
   1201 class GDIGlyphbufferPointIter {
   1202 public:
   1203    GDIGlyphbufferPointIter(const uint8_t* glyphbuf, DWORD total_size)
   1204        : fHeaderIter(glyphbuf, total_size), fCurveIter(), fPointIter()
   1205    { }
   1206 
   1207    POINTFX const * next() {
   1208 nextHeader:
   1209        if (!fCurveIter.isSet()) {
   1210            const TTPOLYGONHEADER* header = fHeaderIter.next();
   1211            if (nullptr == header) {
   1212                return nullptr;
   1213            }
   1214            fCurveIter.set(header);
   1215            const TTPOLYCURVE* curve = fCurveIter.next();
   1216            if (nullptr == curve) {
   1217                return nullptr;
   1218            }
   1219            fPointIter.set(curve);
   1220            return &header->pfxStart;
   1221        }
   1222 
   1223        const POINTFX* nextPoint = fPointIter.next();
   1224        if (nullptr == nextPoint) {
   1225            const TTPOLYCURVE* curve = fCurveIter.next();
   1226            if (nullptr == curve) {
   1227                fCurveIter.set();
   1228                goto nextHeader;
   1229            } else {
   1230                fPointIter.set(curve);
   1231            }
   1232            nextPoint = fPointIter.next();
   1233        }
   1234        return nextPoint;
   1235    }
   1236 
   1237    WORD currentCurveType() {
   1238        return fPointIter.fCurveType;
   1239    }
   1240 
   1241 private:
   1242    /** Iterates over all of the polygon headers in a glyphbuf. */
   1243    class GDIPolygonHeaderIter {
   1244    public:
   1245        GDIPolygonHeaderIter(const uint8_t* glyphbuf, DWORD total_size)
   1246            : fCurPolygon(reinterpret_cast<const TTPOLYGONHEADER*>(glyphbuf))
   1247            , fEndPolygon(SkTAddOffset<const TTPOLYGONHEADER>(glyphbuf, total_size))
   1248        { }
   1249 
   1250        const TTPOLYGONHEADER* next() {
   1251            if (fCurPolygon >= fEndPolygon) {
   1252                return nullptr;
   1253            }
   1254            const TTPOLYGONHEADER* thisPolygon = fCurPolygon;
   1255            fCurPolygon = SkTAddOffset<const TTPOLYGONHEADER>(fCurPolygon, fCurPolygon->cb);
   1256            return thisPolygon;
   1257        }
   1258    private:
   1259        const TTPOLYGONHEADER* fCurPolygon;
   1260        const TTPOLYGONHEADER* fEndPolygon;
   1261    };
   1262 
   1263    /** Iterates over all of the polygon curves in a polygon header. */
   1264    class GDIPolygonCurveIter {
   1265    public:
   1266        GDIPolygonCurveIter() : fCurCurve(nullptr), fEndCurve(nullptr) { }
   1267 
   1268        GDIPolygonCurveIter(const TTPOLYGONHEADER* curPolygon)
   1269            : fCurCurve(SkTAddOffset<const TTPOLYCURVE>(curPolygon, sizeof(TTPOLYGONHEADER)))
   1270            , fEndCurve(SkTAddOffset<const TTPOLYCURVE>(curPolygon, curPolygon->cb))
   1271        { }
   1272 
   1273        bool isSet() { return fCurCurve != nullptr; }
   1274 
   1275        void set(const TTPOLYGONHEADER* curPolygon) {
   1276            fCurCurve = SkTAddOffset<const TTPOLYCURVE>(curPolygon, sizeof(TTPOLYGONHEADER));
   1277            fEndCurve = SkTAddOffset<const TTPOLYCURVE>(curPolygon, curPolygon->cb);
   1278        }
   1279        void set() {
   1280            fCurCurve = nullptr;
   1281            fEndCurve = nullptr;
   1282        }
   1283 
   1284        const TTPOLYCURVE* next() {
   1285            if (fCurCurve >= fEndCurve) {
   1286                return nullptr;
   1287            }
   1288            const TTPOLYCURVE* thisCurve = fCurCurve;
   1289            fCurCurve = SkTAddOffset<const TTPOLYCURVE>(fCurCurve, size_of_TTPOLYCURVE(*fCurCurve));
   1290            return thisCurve;
   1291        }
   1292    private:
   1293        size_t size_of_TTPOLYCURVE(const TTPOLYCURVE& curve) {
   1294            return 2*sizeof(WORD) + curve.cpfx*sizeof(POINTFX);
   1295        }
   1296        const TTPOLYCURVE* fCurCurve;
   1297        const TTPOLYCURVE* fEndCurve;
   1298    };
   1299 
   1300    /** Iterates over all of the polygon points in a polygon curve. */
   1301    class GDIPolygonCurvePointIter {
   1302    public:
   1303        GDIPolygonCurvePointIter() : fCurveType(0), fCurPoint(nullptr), fEndPoint(nullptr) { }
   1304 
   1305        GDIPolygonCurvePointIter(const TTPOLYCURVE* curPolygon)
   1306            : fCurveType(curPolygon->wType)
   1307            , fCurPoint(&curPolygon->apfx[0])
   1308            , fEndPoint(&curPolygon->apfx[curPolygon->cpfx])
   1309        { }
   1310 
   1311        bool isSet() { return fCurPoint != nullptr; }
   1312 
   1313        void set(const TTPOLYCURVE* curPolygon) {
   1314            fCurveType = curPolygon->wType;
   1315            fCurPoint = &curPolygon->apfx[0];
   1316            fEndPoint = &curPolygon->apfx[curPolygon->cpfx];
   1317        }
   1318        void set() {
   1319            fCurPoint = nullptr;
   1320            fEndPoint = nullptr;
   1321        }
   1322 
   1323        const POINTFX* next() {
   1324            if (fCurPoint >= fEndPoint) {
   1325                return nullptr;
   1326            }
   1327            const POINTFX* thisPoint = fCurPoint;
   1328            ++fCurPoint;
   1329            return thisPoint;
   1330        }
   1331 
   1332        WORD fCurveType;
   1333    private:
   1334        const POINTFX* fCurPoint;
   1335        const POINTFX* fEndPoint;
   1336    };
   1337 
   1338    GDIPolygonHeaderIter fHeaderIter;
   1339    GDIPolygonCurveIter fCurveIter;
   1340    GDIPolygonCurvePointIter fPointIter;
   1341 };
   1342 
   1343 class SkGDIGeometrySink {
   1344    SkPathBuilder* fBuilder;
   1345    bool fStarted = false;
   1346    POINTFX fCurrent;
   1347 
   1348    void goingTo(const POINTFX pt) {
   1349        if (!fStarted) {
   1350            fStarted = true;
   1351            fBuilder->moveTo( SkFIXEDToScalar(fCurrent.x),
   1352                             -SkFIXEDToScalar(fCurrent.y));
   1353        }
   1354        fCurrent = pt;
   1355    }
   1356 
   1357    bool currentIsNot(const POINTFX pt) {
   1358        return fCurrent.x.value != pt.x.value || fCurrent.x.fract != pt.x.fract ||
   1359               fCurrent.y.value != pt.y.value || fCurrent.y.fract != pt.y.fract;
   1360    }
   1361 
   1362 public:
   1363    SkGDIGeometrySink(SkPathBuilder* builder) : fBuilder(builder) {}
   1364    void process(const uint8_t* glyphbuf, DWORD total_size);
   1365 
   1366    /** It is possible for the hinted and unhinted versions of the same path to have
   1367     *  a different number of points due to GDI's handling of flipped points.
   1368     *  If this is detected, this will return false.
   1369     */
   1370    bool process(const uint8_t* glyphbuf, DWORD total_size, GDIGlyphbufferPointIter hintedYs);
   1371 };
   1372 
   1373 void SkGDIGeometrySink::process(const uint8_t* glyphbuf, DWORD total_size) {
   1374    const uint8_t* cur_glyph = glyphbuf;
   1375    const uint8_t* end_glyph = glyphbuf + total_size;
   1376 
   1377    while (cur_glyph < end_glyph) {
   1378        const TTPOLYGONHEADER* th = (const TTPOLYGONHEADER*)cur_glyph;
   1379 
   1380        const uint8_t* end_poly = cur_glyph + th->cb;
   1381        const uint8_t* cur_poly = cur_glyph + sizeof(TTPOLYGONHEADER);
   1382 
   1383        fStarted = false;
   1384        fCurrent = th->pfxStart;
   1385 
   1386        while (cur_poly < end_poly) {
   1387            const TTPOLYCURVE* pc = (const TTPOLYCURVE*)cur_poly;
   1388            const POINTFX* apfx = pc->apfx;
   1389            const WORD cpfx = pc->cpfx;
   1390 
   1391            if (pc->wType == TT_PRIM_LINE) {
   1392                for (uint16_t i = 0; i < cpfx; i++) {
   1393                    POINTFX pnt_b = apfx[i];
   1394                    if (this->currentIsNot(pnt_b)) {
   1395                        this->goingTo(pnt_b);
   1396                        fBuilder->lineTo( SkFIXEDToScalar(pnt_b.x),
   1397                                      -SkFIXEDToScalar(pnt_b.y));
   1398                    }
   1399                }
   1400            }
   1401 
   1402            if (pc->wType == TT_PRIM_QSPLINE) {
   1403                for (uint16_t u = 0; u < cpfx - 1; u++) { // Walk through points in spline
   1404                    POINTFX pnt_b = apfx[u];    // B is always the current point
   1405                    POINTFX pnt_c = apfx[u+1];
   1406 
   1407                    if (u < cpfx - 2) {          // If not on last spline, compute C
   1408                        pnt_c.x = SkFixedToFIXED(SkFixedAve(SkFIXEDToFixed(pnt_b.x),
   1409                                                            SkFIXEDToFixed(pnt_c.x)));
   1410                        pnt_c.y = SkFixedToFIXED(SkFixedAve(SkFIXEDToFixed(pnt_b.y),
   1411                                                            SkFIXEDToFixed(pnt_c.y)));
   1412                    }
   1413 
   1414 
   1415                    if (this->currentIsNot(pnt_b) || this->currentIsNot(pnt_c)) {
   1416                        this->goingTo(pnt_c);
   1417                        fBuilder->quadTo( SkFIXEDToScalar(pnt_b.x),
   1418                                         -SkFIXEDToScalar(pnt_b.y),
   1419                                          SkFIXEDToScalar(pnt_c.x),
   1420                                         -SkFIXEDToScalar(pnt_c.y));
   1421                    }
   1422                }
   1423            }
   1424 
   1425            // Advance past this TTPOLYCURVE.
   1426            cur_poly += sizeof(WORD) * 2 + sizeof(POINTFX) * cpfx;
   1427        }
   1428        cur_glyph += th->cb;
   1429        if (this->fStarted) {
   1430            fBuilder->close();
   1431        }
   1432    }
   1433 }
   1434 
   1435 #define move_next_expected_hinted_point(iter, pElem) do {\
   1436    pElem = iter.next(); \
   1437    if (nullptr == pElem) return false; \
   1438 } while(0)
   1439 
   1440 bool SkGDIGeometrySink::process(const uint8_t* glyphbuf, DWORD total_size,
   1441                                GDIGlyphbufferPointIter hintedYs) {
   1442    const uint8_t* cur_glyph = glyphbuf;
   1443    const uint8_t* end_glyph = glyphbuf + total_size;
   1444 
   1445    POINTFX const * hintedPoint;
   1446 
   1447    while (cur_glyph < end_glyph) {
   1448        const TTPOLYGONHEADER* th = (const TTPOLYGONHEADER*)cur_glyph;
   1449 
   1450        const uint8_t* end_poly = cur_glyph + th->cb;
   1451        const uint8_t* cur_poly = cur_glyph + sizeof(TTPOLYGONHEADER);
   1452 
   1453        move_next_expected_hinted_point(hintedYs, hintedPoint);
   1454        fStarted = false;
   1455        fCurrent = {th->pfxStart.x, hintedPoint->y};
   1456 
   1457        while (cur_poly < end_poly) {
   1458            const TTPOLYCURVE* pc = (const TTPOLYCURVE*)cur_poly;
   1459            const POINTFX* apfx = pc->apfx;
   1460            const WORD cpfx = pc->cpfx;
   1461 
   1462            if (pc->wType == TT_PRIM_LINE) {
   1463                for (uint16_t i = 0; i < cpfx; i++) {
   1464                    move_next_expected_hinted_point(hintedYs, hintedPoint);
   1465                    POINTFX pnt_b = {apfx[i].x, hintedPoint->y};
   1466                    if (this->currentIsNot(pnt_b)) {
   1467                        this->goingTo(pnt_b);
   1468                        fBuilder->lineTo( SkFIXEDToScalar(pnt_b.x),
   1469                                         -SkFIXEDToScalar(pnt_b.y));
   1470                    }
   1471                }
   1472            }
   1473 
   1474            if (pc->wType == TT_PRIM_QSPLINE) {
   1475                POINTFX currentPoint = apfx[0];
   1476                move_next_expected_hinted_point(hintedYs, hintedPoint);
   1477                // only take the hinted y if it wasn't flipped
   1478                if (hintedYs.currentCurveType() == TT_PRIM_QSPLINE) {
   1479                    currentPoint.y = hintedPoint->y;
   1480                }
   1481                for (uint16_t u = 0; u < cpfx - 1; u++) { // Walk through points in spline
   1482                    POINTFX pnt_b = currentPoint;//pc->apfx[u]; // B is always the current point
   1483                    POINTFX pnt_c = apfx[u+1];
   1484                    move_next_expected_hinted_point(hintedYs, hintedPoint);
   1485                    // only take the hinted y if it wasn't flipped
   1486                    if (hintedYs.currentCurveType() == TT_PRIM_QSPLINE) {
   1487                        pnt_c.y = hintedPoint->y;
   1488                    }
   1489                    currentPoint.x = pnt_c.x;
   1490                    currentPoint.y = pnt_c.y;
   1491 
   1492                    if (u < cpfx - 2) {          // If not on last spline, compute C
   1493                        pnt_c.x = SkFixedToFIXED(SkFixedAve(SkFIXEDToFixed(pnt_b.x),
   1494                                                            SkFIXEDToFixed(pnt_c.x)));
   1495                        pnt_c.y = SkFixedToFIXED(SkFixedAve(SkFIXEDToFixed(pnt_b.y),
   1496                                                            SkFIXEDToFixed(pnt_c.y)));
   1497                    }
   1498 
   1499                    if (this->currentIsNot(pnt_b) || this->currentIsNot(pnt_c)) {
   1500                        this->goingTo(pnt_c);
   1501                        fBuilder->quadTo( SkFIXEDToScalar(pnt_b.x),
   1502                                         -SkFIXEDToScalar(pnt_b.y),
   1503                                          SkFIXEDToScalar(pnt_c.x),
   1504                                         -SkFIXEDToScalar(pnt_c.y));
   1505                    }
   1506                }
   1507            }
   1508 
   1509            // Advance past this TTPOLYCURVE.
   1510            cur_poly += sizeof(WORD) * 2 + sizeof(POINTFX) * cpfx;
   1511        }
   1512        cur_glyph += th->cb;
   1513        if (this->fStarted) {
   1514            fBuilder->close();
   1515        }
   1516    }
   1517    return true;
   1518 }
   1519 } // namespace
   1520 
   1521 DWORD SkScalerContext_GDI::getGDIGlyphPath(SkGlyphID glyph, UINT flags,
   1522                                           AutoSTMalloc<BUFFERSIZE, uint8_t>* glyphbuf)
   1523 {
   1524    GLYPHMETRICS gm;
   1525 
   1526    DWORD total_size = GetGlyphOutlineW(fDDC, glyph, flags, &gm, BUFFERSIZE, glyphbuf->get(), &fMat22);
   1527    // Sometimes GetGlyphOutlineW returns a number larger than BUFFERSIZE even if BUFFERSIZE > 0.
   1528    // It has been verified that this does not involve a buffer overrun.
   1529    if (GDI_ERROR == total_size || total_size > BUFFERSIZE) {
   1530        // GDI_ERROR because the BUFFERSIZE was too small, or because the data was not accessible.
   1531        // When the data is not accessable GetGlyphOutlineW fails rather quickly,
   1532        // so just try to get the size. If that fails then ensure the data is accessible.
   1533        total_size = GetGlyphOutlineW(fDDC, glyph, flags, &gm, 0, nullptr, &fMat22);
   1534        if (GDI_ERROR == total_size) {
   1535            LogFontTypeface::EnsureAccessible(this->getTypeface());
   1536            total_size = GetGlyphOutlineW(fDDC, glyph, flags, &gm, 0, nullptr, &fMat22);
   1537            if (GDI_ERROR == total_size) {
   1538                // GetGlyphOutlineW is known to fail for some characters, such as spaces.
   1539                // In these cases, just return that the glyph does not have a shape.
   1540                return 0;
   1541            }
   1542        }
   1543 
   1544        glyphbuf->reset(total_size);
   1545 
   1546        DWORD ret = GetGlyphOutlineW(fDDC, glyph, flags, &gm, total_size, glyphbuf->get(), &fMat22);
   1547        if (GDI_ERROR == ret) {
   1548            LogFontTypeface::EnsureAccessible(this->getTypeface());
   1549            ret = GetGlyphOutlineW(fDDC, glyph, flags, &gm, total_size, glyphbuf->get(), &fMat22);
   1550            if (GDI_ERROR == ret) {
   1551                SkASSERT(false);
   1552                return 0;
   1553            }
   1554        }
   1555    }
   1556    return total_size;
   1557 }
   1558 
   1559 std::optional<SkScalerContext::GeneratedPath>
   1560 SkScalerContext_GDI::generatePath(const SkGlyph& glyph) {
   1561    SkASSERT(fDDC);
   1562 
   1563    SkGlyphID glyphID = glyph.getGlyphID();
   1564 
   1565    // Out of all the fonts on a typical Windows box,
   1566    // 25% of glyphs require more than 2KB.
   1567    // 1% of glyphs require more than 4KB.
   1568    // 0.01% of glyphs require more than 8KB.
   1569    // 8KB is less than 1% of the normal 1MB stack on Windows.
   1570    // Note that some web fonts glyphs require more than 20KB.
   1571    //static const DWORD BUFFERSIZE = (1 << 13);
   1572 
   1573    //GDI only uses hinted outlines when axis aligned.
   1574    UINT format = GGO_NATIVE | GGO_GLYPH_INDEX;
   1575    if (fRec.getHinting() == SkFontHinting::kNone || fRec.getHinting() == SkFontHinting::kSlight){
   1576        format |= GGO_UNHINTED;
   1577    }
   1578    AutoSTMalloc<BUFFERSIZE, uint8_t> glyphbuf(BUFFERSIZE);
   1579    DWORD total_size = getGDIGlyphPath(glyphID, format, &glyphbuf);
   1580    if (0 == total_size) {
   1581        return {};
   1582    }
   1583 
   1584    SkPathBuilder builder;
   1585    if (fRec.getHinting() != SkFontHinting::kSlight) {
   1586        SkGDIGeometrySink sink(&builder);
   1587        sink.process(glyphbuf, total_size);
   1588    } else {
   1589        AutoSTMalloc<BUFFERSIZE, uint8_t> hintedGlyphbuf(BUFFERSIZE);
   1590        //GDI only uses hinted outlines when axis aligned.
   1591        DWORD hinted_total_size = getGDIGlyphPath(glyphID, GGO_NATIVE | GGO_GLYPH_INDEX,
   1592                                                  &hintedGlyphbuf);
   1593        if (0 == hinted_total_size) {
   1594            return {};
   1595        }
   1596 
   1597        SkGDIGeometrySink sinkXBufYIter(&builder);
   1598        if (!sinkXBufYIter.process(glyphbuf, total_size,
   1599                                   GDIGlyphbufferPointIter(hintedGlyphbuf, hinted_total_size)))
   1600        {
   1601            // Both path and sinkXBufYIter are in the state they were in at the time of failure.
   1602            builder.reset();
   1603            SkGDIGeometrySink sink(&builder);
   1604            sink.process(glyphbuf, total_size);
   1605        }
   1606    }
   1607    return {{builder.detach(), false}};
   1608 }
   1609 
   1610 static void logfont_for_name(const char* familyName, LOGFONT* lf) {
   1611    sk_bzero(lf, sizeof(LOGFONT));
   1612 #ifdef UNICODE
   1613    // Get the buffer size needed first.
   1614    size_t str_len = ::MultiByteToWideChar(CP_UTF8, 0, familyName,
   1615                                            -1, nullptr, 0);
   1616    // Allocate a buffer (str_len already has terminating null
   1617    // accounted for).
   1618    wchar_t *wideFamilyName = new wchar_t[str_len];
   1619    // Now actually convert the string.
   1620    ::MultiByteToWideChar(CP_UTF8, 0, familyName, -1,
   1621                            wideFamilyName, str_len);
   1622    ::wcsncpy(lf->lfFaceName, wideFamilyName, LF_FACESIZE - 1);
   1623    delete [] wideFamilyName;
   1624    lf->lfFaceName[LF_FACESIZE-1] = L'\0';
   1625 #else
   1626    ::strncpy(lf->lfFaceName, familyName, LF_FACESIZE - 1);
   1627    lf->lfFaceName[LF_FACESIZE - 1] = '\0';
   1628 #endif
   1629 }
   1630 
   1631 void LogFontTypeface::onGetFamilyName(SkString* familyName) const {
   1632    // Get the actual name of the typeface. The logfont may not know this.
   1633    SkAutoHDC hdc(fLogFont);
   1634    dcfontname_to_skstring(hdc, fLogFont, familyName);
   1635 }
   1636 
   1637 void LogFontTypeface::onGetFontDescriptor(SkFontDescriptor* desc,
   1638                                          bool* isLocalStream) const {
   1639    SkString familyName;
   1640    this->onGetFamilyName(&familyName);
   1641    desc->setFamilyName(familyName.c_str());
   1642    desc->setStyle(this->fontStyle());
   1643    *isLocalStream = this->fSerializeAsStream;
   1644 }
   1645 
   1646 void LogFontTypeface::getGlyphToUnicodeMap(SkSpan<SkUnichar> dstArray) const {
   1647    SkAutoHDC hdc(fLogFont);
   1648    unsigned int glyphCount = calculateGlyphCount(hdc, fLogFont);
   1649    populate_glyph_to_unicode(hdc, std::min<unsigned>(glyphCount, dstArray.size()), dstArray);
   1650 }
   1651 
   1652 std::unique_ptr<SkAdvancedTypefaceMetrics> LogFontTypeface::onGetAdvancedMetrics() const {
   1653    LOGFONT lf = fLogFont;
   1654    std::unique_ptr<SkAdvancedTypefaceMetrics> info(nullptr);
   1655 
   1656    // The design HFONT must be destroyed after the HDC
   1657    using HFONT_T = typename std::remove_pointer<HFONT>::type;
   1658    std::unique_ptr<HFONT_T, SkFunctionObject<DeleteObject>> designFont;
   1659    SkAutoHDC hdc(lf);
   1660 
   1661    const char stem_chars[] = {'i', 'I', '!', '1'};
   1662    int16_t min_width;
   1663    unsigned glyphCount;
   1664 
   1665    // To request design units, create a logical font whose height is specified
   1666    // as unitsPerEm.
   1667    OUTLINETEXTMETRIC otm;
   1668    unsigned int otmRet = GetOutlineTextMetrics(hdc, sizeof(otm), &otm);
   1669    if (0 == otmRet) {
   1670        call_ensure_accessible(lf);
   1671        otmRet = GetOutlineTextMetrics(hdc, sizeof(otm), &otm);
   1672    }
   1673    if (!otmRet || !GetTextFace(hdc, LF_FACESIZE, lf.lfFaceName)) {
   1674        return info;
   1675    }
   1676    lf.lfHeight = -SkToS32(otm.otmEMSquare);
   1677    designFont.reset(CreateFontIndirect(&lf));
   1678    SelectObject(hdc, designFont.get());
   1679    if (!GetOutlineTextMetrics(hdc, sizeof(otm), &otm)) {
   1680        return info;
   1681    }
   1682    glyphCount = calculateGlyphCount(hdc, fLogFont);
   1683 
   1684    info.reset(new SkAdvancedTypefaceMetrics);
   1685 
   1686    SkOTTableOS2_V4::Type fsType;
   1687    if (sizeof(fsType) == this->getTableData(SkTEndian_SwapBE32(SkOTTableOS2::TAG),
   1688                                             offsetof(SkOTTableOS2_V4, fsType),
   1689                                             sizeof(fsType),
   1690                                             &fsType)) {
   1691        SkOTUtils::SetAdvancedTypefaceFlags(fsType, info.get());
   1692    } else {
   1693        // If bit 1 is set, the font may not be embedded in a document.
   1694        // If bit 1 is clear, the font can be embedded.
   1695        // If bit 2 is set, the embedding is read-only.
   1696        if (otm.otmfsType & 0x1) {
   1697            info->fFlags |= SkAdvancedTypefaceMetrics::kNotEmbeddable_FontFlag;
   1698        }
   1699    }
   1700 
   1701    if (glyphCount == 0 || (otm.otmTextMetrics.tmPitchAndFamily & TMPF_TRUETYPE) == 0) {
   1702        return info;
   1703    }
   1704    info->fType = SkAdvancedTypefaceMetrics::kTrueType_Font;
   1705 
   1706    // If this bit is clear the font is a fixed pitch font.
   1707    if (!(otm.otmTextMetrics.tmPitchAndFamily & TMPF_FIXED_PITCH)) {
   1708        info->fStyle |= SkAdvancedTypefaceMetrics::kFixedPitch_Style;
   1709    }
   1710    if (otm.otmTextMetrics.tmItalic) {
   1711        info->fStyle |= SkAdvancedTypefaceMetrics::kItalic_Style;
   1712    }
   1713    if (otm.otmTextMetrics.tmPitchAndFamily & FF_ROMAN) {
   1714        info->fStyle |= SkAdvancedTypefaceMetrics::kSerif_Style;
   1715    } else if (otm.otmTextMetrics.tmPitchAndFamily & FF_SCRIPT) {
   1716            info->fStyle |= SkAdvancedTypefaceMetrics::kScript_Style;
   1717    }
   1718 
   1719    // The main italic angle of the font, in tenths of a degree counterclockwise
   1720    // from vertical.
   1721    info->fItalicAngle = otm.otmItalicAngle / 10;
   1722    info->fAscent = SkToS16(otm.otmTextMetrics.tmAscent);
   1723    info->fDescent = SkToS16(-otm.otmTextMetrics.tmDescent);
   1724    // TODO(ctguil): Use alternate cap height calculation.
   1725    // MSDN says otmsCapEmHeight is not support but it is returning a value on
   1726    // my Win7 box.
   1727    info->fCapHeight = otm.otmsCapEmHeight;
   1728    info->fBBox =
   1729        SkIRect::MakeLTRB(otm.otmrcFontBox.left, otm.otmrcFontBox.top,
   1730                          otm.otmrcFontBox.right, otm.otmrcFontBox.bottom);
   1731 
   1732    // Figure out a good guess for StemV - Min width of i, I, !, 1.
   1733    // This probably isn't very good with an italic font.
   1734    min_width = SHRT_MAX;
   1735    info->fStemV = 0;
   1736    for (size_t i = 0; i < std::size(stem_chars); i++) {
   1737        ABC abcWidths;
   1738        if (GetCharABCWidths(hdc, stem_chars[i], stem_chars[i], &abcWidths)) {
   1739            int16_t width = abcWidths.abcB;
   1740            if (width > 0 && width < min_width) {
   1741                min_width = width;
   1742                info->fStemV = min_width;
   1743            }
   1744        }
   1745    }
   1746 
   1747    return info;
   1748 }
   1749 
   1750 //Placeholder representation of a Base64 encoded GUID from create_unique_font_name.
   1751 #define BASE64_GUID_ID "XXXXXXXXXXXXXXXXXXXXXXXX"
   1752 //Length of GUID representation from create_id, including nullptr terminator.
   1753 #define BASE64_GUID_ID_LEN std::size(BASE64_GUID_ID)
   1754 
   1755 static_assert(BASE64_GUID_ID_LEN < LF_FACESIZE, "GUID_longer_than_facesize");
   1756 
   1757 /**
   1758   NameID 6 Postscript names cannot have the character '/'.
   1759   It would be easier to hex encode the GUID, but that is 32 bytes,
   1760   and many systems have issues with names longer than 28 bytes.
   1761   The following need not be any standard base64 encoding.
   1762   The encoded value is never decoded.
   1763 */
   1764 static const char postscript_safe_base64_encode[] =
   1765    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
   1766    "abcdefghijklmnopqrstuvwxyz"
   1767    "0123456789-_=";
   1768 
   1769 /**
   1770   Formats a GUID into Base64 and places it into buffer.
   1771   buffer should have space for at least BASE64_GUID_ID_LEN characters.
   1772   The string will always be null terminated.
   1773   XXXXXXXXXXXXXXXXXXXXXXXX0
   1774 */
   1775 static void format_guid_b64(const GUID& guid, char* buffer, size_t bufferSize) {
   1776    SkASSERT(bufferSize >= BASE64_GUID_ID_LEN);
   1777    size_t written = SkBase64::Encode(&guid, sizeof(guid), buffer, postscript_safe_base64_encode);
   1778    SkASSERT(written < LF_FACESIZE);
   1779    buffer[written] = '\0';
   1780 }
   1781 
   1782 /**
   1783   Creates a Base64 encoded GUID and places it into buffer.
   1784   buffer should have space for at least BASE64_GUID_ID_LEN characters.
   1785   The string will always be null terminated.
   1786   XXXXXXXXXXXXXXXXXXXXXXXX0
   1787 */
   1788 static HRESULT create_unique_font_name(char* buffer, size_t bufferSize) {
   1789    GUID guid = {};
   1790    if (FAILED(CoCreateGuid(&guid))) {
   1791        return E_UNEXPECTED;
   1792    }
   1793    format_guid_b64(guid, buffer, bufferSize);
   1794 
   1795    return S_OK;
   1796 }
   1797 
   1798 /**
   1799   Introduces a font to GDI. On failure will return nullptr. The returned handle
   1800   should eventually be passed to RemoveFontMemResourceEx.
   1801 */
   1802 static HANDLE activate_font(const SkData* fontData) {
   1803    DWORD numFonts = 0;
   1804    //AddFontMemResourceEx just copies the data, but does not specify const.
   1805    HANDLE fontHandle = AddFontMemResourceEx(const_cast<void*>(fontData->data()),
   1806                                             static_cast<DWORD>(fontData->size()),
   1807                                             nullptr,
   1808                                             &numFonts);
   1809 
   1810    if (fontHandle != nullptr && numFonts < 1) {
   1811        RemoveFontMemResourceEx(fontHandle);
   1812        return nullptr;
   1813    }
   1814 
   1815    return fontHandle;
   1816 }
   1817 
   1818 // Does not affect ownership of stream.
   1819 static sk_sp<SkTypeface> create_from_stream(std::unique_ptr<SkStreamAsset> stream) {
   1820    // Create a unique and unpredictable font name.
   1821    // Avoids collisions and access from CSS.
   1822    char familyName[BASE64_GUID_ID_LEN];
   1823    const int familyNameSize = std::size(familyName);
   1824    if (FAILED(create_unique_font_name(familyName, familyNameSize))) {
   1825        return nullptr;
   1826    }
   1827 
   1828    // Change the name of the font.
   1829    sk_sp<SkData> rewrittenFontData(SkOTUtils::RenameFont(stream.get(), familyName, familyNameSize-1));
   1830    if (nullptr == rewrittenFontData.get()) {
   1831        return nullptr;
   1832    }
   1833 
   1834    // Register the font with GDI.
   1835    HANDLE fontReference = activate_font(rewrittenFontData.get());
   1836    if (nullptr == fontReference) {
   1837        return nullptr;
   1838    }
   1839 
   1840    // Create the typeface.
   1841    LOGFONT lf;
   1842    logfont_for_name(familyName, &lf);
   1843 
   1844    return sk_sp<SkTypeface>(SkCreateFontMemResourceTypefaceFromLOGFONT(lf, fontReference));
   1845 }
   1846 
   1847 std::unique_ptr<SkStreamAsset> LogFontTypeface::onOpenStream(int* ttcIndex) const {
   1848    *ttcIndex = 0;
   1849 
   1850    const DWORD kTTCTag = SkEndian_SwapBE32(SkSetFourByteTag('t', 't', 'c', 'f'));
   1851    LOGFONT lf = fLogFont;
   1852 
   1853    SkAutoHDC hdc(lf);
   1854 
   1855    std::unique_ptr<SkStreamAsset> stream;
   1856    DWORD tables[2] = {kTTCTag, 0};
   1857    for (size_t i = 0; i < std::size(tables); i++) {
   1858        DWORD bufferSize = GetFontData(hdc, tables[i], 0, nullptr, 0);
   1859        if (bufferSize == GDI_ERROR) {
   1860            call_ensure_accessible(lf);
   1861            bufferSize = GetFontData(hdc, tables[i], 0, nullptr, 0);
   1862        }
   1863        if (bufferSize != GDI_ERROR) {
   1864            sk_sp<SkData> streamData = SkData::MakeUninitialized(bufferSize);
   1865            if (GetFontData(hdc, tables[i], 0, streamData->writable_data(), bufferSize)) {
   1866                stream.reset(new SkMemoryStream(std::move(streamData)));
   1867                break;
   1868            } else {
   1869                stream.reset();
   1870            }
   1871        }
   1872    }
   1873    return stream;
   1874 }
   1875 
   1876 sk_sp<SkTypeface> LogFontTypeface::onMakeClone(const SkFontArguments& args) const {
   1877    return sk_ref_sp(this);
   1878 }
   1879 
   1880 static void bmpCharsToGlyphs(HDC hdc, const WCHAR* bmpChars, int count, uint16_t* glyphs,
   1881                             bool Ox1FHack)
   1882 {
   1883    // Type1 fonts fail with uniscribe API. Use GetGlyphIndices for plane 0.
   1884 
   1885    /** Real documentation for GetGlyphIndicesW:
   1886     *
   1887     *  When GGI_MARK_NONEXISTING_GLYPHS is not specified and a character does not map to a
   1888     *  glyph, then the 'default character's glyph is returned instead. The 'default character'
   1889     *  is available in fTM.tmDefaultChar. FON fonts have a default character, and there exists
   1890     *  a usDefaultChar in the 'OS/2' table, version 2 and later. If there is no
   1891     *  'default character' specified by the font, then often the first character found is used.
   1892     *
   1893     *  When GGI_MARK_NONEXISTING_GLYPHS is specified and a character does not map to a glyph,
   1894     *  then the glyph 0xFFFF is used. In Windows XP and earlier, Bitmap/Vector FON usually use
   1895     *  glyph 0x1F instead ('Terminal' appears to be special, returning 0xFFFF).
   1896     *  Type1 PFM/PFB, TT, OT TT, OT CFF all appear to use 0xFFFF, even on XP.
   1897     */
   1898    DWORD result = GetGlyphIndicesW(hdc, bmpChars, count, glyphs, GGI_MARK_NONEXISTING_GLYPHS);
   1899    if (GDI_ERROR == result) {
   1900        for (int i = 0; i < count; ++i) {
   1901            glyphs[i] = 0;
   1902        }
   1903        return;
   1904    }
   1905 
   1906    if (Ox1FHack) {
   1907        for (int i = 0; i < count; ++i) {
   1908            if (0xFFFF == glyphs[i] || 0x1F == glyphs[i]) {
   1909                glyphs[i] = 0;
   1910            }
   1911        }
   1912    } else {
   1913        for (int i = 0; i < count; ++i) {
   1914            if (0xFFFF == glyphs[i]){
   1915                glyphs[i] = 0;
   1916            }
   1917        }
   1918    }
   1919 }
   1920 
   1921 static uint16_t nonBmpCharToGlyph(HDC hdc, SCRIPT_CACHE* scriptCache, const WCHAR utf16[2]) {
   1922    uint16_t index = 0;
   1923    // Use uniscribe to detemine glyph index for non-BMP characters.
   1924    static const int numWCHAR = 2;
   1925    static const int maxItems = 2;
   1926    // MSDN states that this can be nullptr, but some things don't work then.
   1927    SCRIPT_CONTROL scriptControl;
   1928    memset(&scriptControl, 0, sizeof(scriptControl));
   1929    // Add extra item to SCRIPT_ITEM to work around a bug (now documented).
   1930    // https://bugzilla.mozilla.org/show_bug.cgi?id=366643
   1931    SCRIPT_ITEM si[maxItems + 1];
   1932    int numItems;
   1933    HRZM(ScriptItemize(utf16, numWCHAR, maxItems, &scriptControl, nullptr, si, &numItems),
   1934         "Could not itemize character.");
   1935 
   1936    // Sometimes ScriptShape cannot find a glyph for a non-BMP and returns 2 space glyphs.
   1937    static const int maxGlyphs = 2;
   1938    SCRIPT_VISATTR vsa[maxGlyphs];
   1939    WORD outGlyphs[maxGlyphs];
   1940    WORD logClust[numWCHAR];
   1941    int numGlyphs;
   1942    SCRIPT_ANALYSIS& script = si[0].a;
   1943    script.eScript = SCRIPT_UNDEFINED;
   1944    script.fRTL = FALSE;
   1945    script.fLayoutRTL = FALSE;
   1946    script.fLinkBefore = FALSE;
   1947    script.fLinkAfter = FALSE;
   1948    script.fLogicalOrder = FALSE;
   1949    script.fNoGlyphIndex = FALSE;
   1950    script.s.uBidiLevel = 0;
   1951    script.s.fOverrideDirection = 0;
   1952    script.s.fInhibitSymSwap = TRUE;
   1953    script.s.fCharShape = FALSE;
   1954    script.s.fDigitSubstitute = FALSE;
   1955    script.s.fInhibitLigate = FALSE;
   1956    script.s.fDisplayZWG = TRUE;
   1957    script.s.fArabicNumContext = FALSE;
   1958    script.s.fGcpClusters = FALSE;
   1959    script.s.fReserved = 0;
   1960    script.s.fEngineReserved = 0;
   1961    // For the future, 0x80040200 from here is USP_E_SCRIPT_NOT_IN_FONT
   1962    HRZM(ScriptShape(hdc, scriptCache, utf16, numWCHAR, maxGlyphs, &script,
   1963                     outGlyphs, logClust, vsa, &numGlyphs),
   1964         "Could not shape character.");
   1965    if (1 == numGlyphs) {
   1966        index = outGlyphs[0];
   1967    }
   1968    return index;
   1969 }
   1970 
   1971 void LogFontTypeface::onCharsToGlyphs(SkSpan<const SkUnichar> uni, SkSpan<SkGlyphID> glyphs) const {
   1972    SkASSERT(uni.size() == glyphs.size());
   1973 
   1974    SkAutoHDC hdc(fLogFont);
   1975 
   1976    TEXTMETRIC tm;
   1977    if (0 == GetTextMetrics(hdc, &tm)) {
   1978        call_ensure_accessible(fLogFont);
   1979        if (0 == GetTextMetrics(hdc, &tm)) {
   1980            tm.tmPitchAndFamily = TMPF_TRUETYPE;
   1981        }
   1982    }
   1983    bool Ox1FHack = !(tm.tmPitchAndFamily & TMPF_VECTOR) /*&& winVer < Vista */;
   1984 
   1985    SCRIPT_CACHE sc = nullptr;
   1986    static const int scratchCount = 256;
   1987    WCHAR scratch[scratchCount];
   1988    int glyphIndex = 0;
   1989    const int glyphCount = SkToInt(glyphs.size());
   1990    const uint32_t* utf32 = reinterpret_cast<const uint32_t*>(uni.data());
   1991    while (glyphIndex < glyphCount) {
   1992        // Try a run of bmp.
   1993        int glyphsLeft = std::min(glyphCount - glyphIndex, scratchCount);
   1994        int runLength = 0;
   1995        while (runLength < glyphsLeft && utf32[glyphIndex + runLength] <= 0xFFFF) {
   1996            scratch[runLength] = static_cast<WCHAR>(utf32[glyphIndex + runLength]);
   1997            ++runLength;
   1998        }
   1999        if (runLength) {
   2000            bmpCharsToGlyphs(hdc, scratch, runLength, &glyphs[glyphIndex], Ox1FHack);
   2001            glyphIndex += runLength;
   2002        }
   2003 
   2004        // Try a run of non-bmp.
   2005        while (glyphIndex < glyphCount && utf32[glyphIndex] > 0xFFFF) {
   2006            SkUTF::ToUTF16(utf32[glyphIndex], reinterpret_cast<uint16_t*>(scratch));
   2007            glyphs[glyphIndex] = nonBmpCharToGlyph(hdc, &sc, scratch);
   2008            ++glyphIndex;
   2009        }
   2010    }
   2011 
   2012    if (sc) {
   2013        ::ScriptFreeCache(&sc);
   2014    }
   2015 }
   2016 
   2017 int LogFontTypeface::onCountGlyphs() const {
   2018    SkAutoHDC hdc(fLogFont);
   2019    return calculateGlyphCount(hdc, fLogFont);
   2020 }
   2021 
   2022 void LogFontTypeface::getPostScriptGlyphNames(SkString*) const {}
   2023 
   2024 int LogFontTypeface::onGetUPEM() const {
   2025    SkAutoHDC hdc(fLogFont);
   2026    return calculateUPEM(hdc, fLogFont);
   2027 }
   2028 
   2029 SkTypeface::LocalizedStrings* LogFontTypeface::onCreateFamilyNameIterator() const {
   2030    sk_sp<SkTypeface::LocalizedStrings> nameIter =
   2031        SkOTUtils::LocalizedStrings_NameTable::MakeForFamilyNames(*this);
   2032    if (!nameIter) {
   2033        SkString familyName;
   2034        this->getFamilyName(&familyName);
   2035        SkString language("und"); //undetermined
   2036        nameIter = sk_make_sp<SkOTUtils::LocalizedStrings_SingleName>(familyName, language);
   2037    }
   2038    return nameIter.release();
   2039 }
   2040 
   2041 int LogFontTypeface::onGetTableTags(SkSpan<SkFontTableTag> tags) const {
   2042    SkSFNTHeader header;
   2043    if (sizeof(header) != this->onGetTableData(0, 0, sizeof(header), &header)) {
   2044        return 0;
   2045    }
   2046 
   2047    size_t numTables = SkEndian_SwapBE16(header.numTables);
   2048 
   2049    if (!tags.empty()) {
   2050        size_t size = numTables * sizeof(SkSFNTHeader::TableDirectoryEntry);
   2051        AutoSTMalloc<0x20, SkSFNTHeader::TableDirectoryEntry> dir(numTables);
   2052        if (size != this->onGetTableData(0, sizeof(header), size, dir.get())) {
   2053            return 0;
   2054        }
   2055 
   2056        const size_t n = std::min(numTables, tags.size());
   2057        for (size_t i = 0; i < n; ++i) {
   2058            tags[i] = SkEndian_SwapBE32(dir[i].tag);
   2059        }
   2060    }
   2061    return numTables;
   2062 }
   2063 
   2064 size_t LogFontTypeface::onGetTableData(SkFontTableTag tag, size_t offset,
   2065                                       size_t length, void* data) const
   2066 {
   2067    LOGFONT lf = fLogFont;
   2068    SkAutoHDC hdc(lf);
   2069 
   2070    tag = SkEndian_SwapBE32(tag);
   2071    if (nullptr == data) {
   2072        length = 0;
   2073    }
   2074    DWORD bufferSize = GetFontData(hdc, tag, (DWORD) offset, data, (DWORD) length);
   2075    if (bufferSize == GDI_ERROR) {
   2076        call_ensure_accessible(lf);
   2077        bufferSize = GetFontData(hdc, tag, (DWORD) offset, data, (DWORD) length);
   2078    }
   2079    return bufferSize == GDI_ERROR ? 0 : bufferSize;
   2080 }
   2081 
   2082 sk_sp<SkData> LogFontTypeface::onCopyTableData(SkFontTableTag tag) const {
   2083    LOGFONT lf = fLogFont;
   2084    SkAutoHDC hdc(lf);
   2085 
   2086    tag = SkEndian_SwapBE32(tag);
   2087    DWORD size = GetFontData(hdc, tag, 0, nullptr, 0);
   2088    if (size == GDI_ERROR) {
   2089        call_ensure_accessible(lf);
   2090        size = GetFontData(hdc, tag, 0, nullptr, 0);
   2091    }
   2092 
   2093    sk_sp<SkData> data;
   2094    if (size != GDI_ERROR) {
   2095        data = SkData::MakeUninitialized(size);
   2096        if (GetFontData(hdc, tag, 0, data->writable_data(), size) == GDI_ERROR) {
   2097            data.reset();
   2098        }
   2099    }
   2100    return data;
   2101 }
   2102 
   2103 std::unique_ptr<SkScalerContext> LogFontTypeface::onCreateScalerContext(
   2104    const SkScalerContextEffects& effects, const SkDescriptor* desc) const
   2105 {
   2106    auto ctx = std::make_unique<SkScalerContext_GDI>(
   2107            *const_cast<LogFontTypeface*>(this), effects, desc);
   2108    if (ctx->isValid()) {
   2109        return std::move(ctx);
   2110    }
   2111 
   2112    ctx.reset();
   2113    SkStrikeCache::PurgeAll();
   2114    ctx = std::make_unique<SkScalerContext_GDI>(
   2115            *const_cast<LogFontTypeface*>(this), effects, desc);
   2116    if (ctx->isValid()) {
   2117        return std::move(ctx);
   2118    }
   2119 
   2120    return SkScalerContext::MakeEmpty(
   2121            *const_cast<LogFontTypeface*>(this), effects, desc);
   2122 }
   2123 
   2124 void LogFontTypeface::onFilterRec(SkScalerContextRec* rec) const {
   2125    rec->useStrokeForFakeBold();
   2126 
   2127    if (rec->fFlags & SkScalerContext::kLCD_BGROrder_Flag ||
   2128        rec->fFlags & SkScalerContext::kLCD_Vertical_Flag)
   2129    {
   2130        rec->fMaskFormat = SkMask::kA8_Format;
   2131        rec->fFlags |= SkScalerContext::kGenA8FromLCD_Flag;
   2132    }
   2133 
   2134    unsigned flagsWeDontSupport = SkScalerContext::kForceAutohinting_Flag |
   2135                                  SkScalerContext::kEmbeddedBitmapText_Flag |
   2136                                  SkScalerContext::kEmbolden_Flag |
   2137                                  SkScalerContext::kLCD_BGROrder_Flag |
   2138                                  SkScalerContext::kLCD_Vertical_Flag;
   2139    rec->fFlags &= ~flagsWeDontSupport;
   2140 
   2141    SkFontHinting h = rec->getHinting();
   2142    switch (h) {
   2143        case SkFontHinting::kNone:
   2144            break;
   2145        case SkFontHinting::kSlight:
   2146            // Only do slight hinting when axis aligned.
   2147            // TODO: re-enable slight hinting when FontHostTest can pass.
   2148            //if (!isAxisAligned(*rec)) {
   2149                h = SkFontHinting::kNone;
   2150            //}
   2151            break;
   2152        case SkFontHinting::kNormal:
   2153        case SkFontHinting::kFull:
   2154            // TODO: need to be able to distinguish subpixel positioned glyphs
   2155            // and linear metrics.
   2156            //rec->fFlags &= ~SkScalerContext::kSubpixelPositioning_Flag;
   2157            h = SkFontHinting::kNormal;
   2158            break;
   2159        default:
   2160            SkDEBUGFAIL("unknown hinting");
   2161    }
   2162    //TODO: if this is a bitmap font, squash hinting and subpixel.
   2163    rec->setHinting(h);
   2164 
   2165 // turn this off since GDI might turn A8 into BW! Need a bigger fix.
   2166 #if 0
   2167    // Disable LCD when rotated, since GDI's output is ugly
   2168    if (isLCD(*rec) && !isAxisAligned(*rec)) {
   2169        rec->fMaskFormat = SkMask::kA8_Format;
   2170    }
   2171 #endif
   2172 
   2173    if (!fCanBeLCD && isLCD(*rec)) {
   2174        rec->fMaskFormat = SkMask::kA8_Format;
   2175        rec->fFlags &= ~SkScalerContext::kGenA8FromLCD_Flag;
   2176    } else if (rec->fMaskFormat == SkMask::kA8_Format) {
   2177        // Bug 1277404
   2178        // If we have non LCD GDI text, render the fonts as cleartype and convert them
   2179        // to grayscale. This seems to be what Chrome and IE are doing on Windows 7.
   2180        // This also applies if cleartype is disabled system wide.
   2181        rec->fFlags |= SkScalerContext::kGenA8FromLCD_Flag;
   2182    }
   2183 }
   2184 
   2185 ///////////////////////////////////////////////////////////////////////////////
   2186 
   2187 #include "include/core/SkDataTable.h"
   2188 #include "include/core/SkFontMgr.h"
   2189 
   2190 static bool valid_logfont_for_enum(const LOGFONT& lf) {
   2191    // TODO: Vector FON is unsupported and should not be listed.
   2192    return
   2193        // Ignore implicit vertical variants.
   2194        lf.lfFaceName[0] && lf.lfFaceName[0] != '@'
   2195 
   2196        // DEFAULT_CHARSET is used to get all fonts, but also implies all
   2197        // character sets. Filter assuming all fonts support ANSI_CHARSET.
   2198        && ANSI_CHARSET == lf.lfCharSet
   2199    ;
   2200 }
   2201 
   2202 /** An EnumFontFamExProc implementation which interprets builderParam as
   2203 *  an SkTDArray<ENUMLOGFONTEX>* and appends logfonts which
   2204 *  pass the valid_logfont_for_enum predicate.
   2205 */
   2206 static int CALLBACK enum_family_proc(const LOGFONT* lf, const TEXTMETRIC*,
   2207                                     DWORD fontType, LPARAM builderParam) {
   2208    if (valid_logfont_for_enum(*lf)) {
   2209        SkTDArray<ENUMLOGFONTEX>* array = (SkTDArray<ENUMLOGFONTEX>*)builderParam;
   2210        *array->append() = *(const ENUMLOGFONTEX*)lf;
   2211    }
   2212    return 1; // non-zero means continue
   2213 }
   2214 
   2215 class SkFontStyleSetGDI : public SkFontStyleSet {
   2216 public:
   2217    SkFontStyleSetGDI(const TCHAR familyName[]) {
   2218        LOGFONT lf;
   2219        sk_bzero(&lf, sizeof(lf));
   2220        lf.lfCharSet = DEFAULT_CHARSET;
   2221        _tcscpy_s(lf.lfFaceName, familyName);
   2222 
   2223        HDC hdc = ::CreateCompatibleDC(nullptr);
   2224        ::EnumFontFamiliesEx(hdc, &lf, enum_family_proc, (LPARAM)&fArray, 0);
   2225        ::DeleteDC(hdc);
   2226    }
   2227 
   2228    int count() override {
   2229        return fArray.size();
   2230    }
   2231 
   2232    void getStyle(int index, SkFontStyle* fs, SkString* styleName) override {
   2233        if (fs) {
   2234            *fs = get_style(fArray[index].elfLogFont);
   2235        }
   2236        if (styleName) {
   2237            const ENUMLOGFONTEX& ref = fArray[index];
   2238            // For some reason, ENUMLOGFONTEX and LOGFONT disagree on their type in the
   2239            // non-unicode version.
   2240            //      ENUMLOGFONTEX uses BYTE
   2241            //      LOGFONT uses CHAR
   2242            // Here we assert they that the style name is logically the same (size) as
   2243            // a TCHAR, so we can use the same converter function.
   2244            SkASSERT(sizeof(TCHAR) == sizeof(ref.elfStyle[0]));
   2245            tchar_to_skstring((const TCHAR*)ref.elfStyle, styleName);
   2246        }
   2247    }
   2248 
   2249    sk_sp<SkTypeface> createTypeface(int index) override {
   2250        return SkCreateTypefaceFromLOGFONT(fArray[index].elfLogFont);
   2251    }
   2252 
   2253    sk_sp<SkTypeface> matchStyle(const SkFontStyle& pattern) override {
   2254        return this->matchStyleCSS3(pattern);
   2255    }
   2256 
   2257 private:
   2258    SkTDArray<ENUMLOGFONTEX> fArray;
   2259 };
   2260 
   2261 class SkFontMgrGDI : public SkFontMgr {
   2262 public:
   2263    SkFontMgrGDI() {
   2264        LOGFONT lf;
   2265        sk_bzero(&lf, sizeof(lf));
   2266        lf.lfCharSet = DEFAULT_CHARSET;
   2267 
   2268        HDC hdc = ::CreateCompatibleDC(nullptr);
   2269        ::EnumFontFamiliesEx(hdc, &lf, enum_family_proc, (LPARAM)&fLogFontArray, 0);
   2270        ::DeleteDC(hdc);
   2271    }
   2272 
   2273 protected:
   2274    int onCountFamilies() const override {
   2275        return fLogFontArray.size();
   2276    }
   2277 
   2278    void onGetFamilyName(int index, SkString* familyName) const override {
   2279        SkASSERT(index < fLogFontArray.size());
   2280        tchar_to_skstring(fLogFontArray[index].elfLogFont.lfFaceName, familyName);
   2281    }
   2282 
   2283    sk_sp<SkFontStyleSet> onCreateStyleSet(int index) const override {
   2284        SkASSERT(index < fLogFontArray.size());
   2285        return sk_sp<SkFontStyleSet>(
   2286            new SkFontStyleSetGDI(fLogFontArray[index].elfLogFont.lfFaceName));
   2287    }
   2288 
   2289    sk_sp<SkFontStyleSet> onMatchFamily(const char familyName[]) const override {
   2290        if (nullptr == familyName) {
   2291            familyName = "";    // do we need this check???
   2292        }
   2293        LOGFONT lf;
   2294        logfont_for_name(familyName, &lf);
   2295        return sk_sp<SkFontStyleSet>(new SkFontStyleSetGDI(lf.lfFaceName));
   2296    }
   2297 
   2298    sk_sp<SkTypeface> onMatchFamilyStyle(const char familyName[],
   2299                                         const SkFontStyle& fontstyle) const override {
   2300        // could be in base impl
   2301        sk_sp<SkFontStyleSet> sset(this->matchFamily(familyName));
   2302        return sset->matchStyle(fontstyle);
   2303    }
   2304 
   2305    sk_sp<SkTypeface> onMatchFamilyStyleCharacter(const char familyName[], const SkFontStyle&,
   2306                                                  const char* bcp47[], int bcp47Count,
   2307                                                  SkUnichar character) const override {
   2308        return nullptr;
   2309    }
   2310 
   2311    sk_sp<SkTypeface> onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset> stream,
   2312                                            int ttcIndex) const override {
   2313        if (ttcIndex != 0) {
   2314            return nullptr;
   2315        }
   2316        return create_from_stream(std::move(stream));
   2317    }
   2318 
   2319    sk_sp<SkTypeface> onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset> stream,
   2320                                           const SkFontArguments& args) const override {
   2321        return this->makeFromStream(std::move(stream), args.getCollectionIndex());
   2322    }
   2323 
   2324    sk_sp<SkTypeface> onMakeFromData(sk_sp<SkData> data, int ttcIndex) const override {
   2325        // could be in base impl
   2326        return this->makeFromStream(std::unique_ptr<SkStreamAsset>(new SkMemoryStream(std::move(data))),
   2327                                    ttcIndex);
   2328    }
   2329 
   2330    sk_sp<SkTypeface> onMakeFromFile(const char path[], int ttcIndex) const override {
   2331        // could be in base impl
   2332        auto stream = SkStream::MakeFromFile(path);
   2333        return stream ? this->makeFromStream(std::move(stream), ttcIndex) : nullptr;
   2334    }
   2335 
   2336    sk_sp<SkTypeface> onLegacyMakeTypeface(const char familyName[], SkFontStyle style) const override {
   2337        LOGFONT lf;
   2338        if (nullptr == familyName) {
   2339            lf = get_default_font();
   2340        } else {
   2341            logfont_for_name(familyName, &lf);
   2342        }
   2343 
   2344        lf.lfWeight = style.weight();
   2345        lf.lfItalic = style.slant() == SkFontStyle::kUpright_Slant ? FALSE : TRUE;
   2346        return sk_sp<SkTypeface>(SkCreateTypefaceFromLOGFONT(lf));
   2347    }
   2348 
   2349 private:
   2350    SkTDArray<ENUMLOGFONTEX> fLogFontArray;
   2351 };
   2352 
   2353 ///////////////////////////////////////////////////////////////////////////////
   2354 
   2355 sk_sp<SkFontMgr> SkFontMgr_New_GDI() { return sk_make_sp<SkFontMgrGDI>(); }
   2356 
   2357 #endif//defined(SK_BUILD_FOR_WIN)