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)