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