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