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