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