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