SkFontHost_win.cpp revision 292b1d4903a770a77282508054917b48fb989d49
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 "SkMaskGamma.h" 18#include "SkOTUtils.h" 19#include "SkPath.h" 20#include "SkStream.h" 21#include "SkString.h" 22#include "SkThread.h" 23#include "SkTypeface_win.h" 24#include "SkTypefaceCache.h" 25#include "SkUtils.h" 26 27#include "SkTypes.h" 28#include <tchar.h> 29#include <usp10.h> 30#include <objbase.h> 31 32static void (*gEnsureLOGFONTAccessibleProc)(const LOGFONT&); 33 34void SkTypeface_SetEnsureLOGFONTAccessibleProc(void (*proc)(const LOGFONT&)) { 35 gEnsureLOGFONTAccessibleProc = proc; 36} 37 38static void call_ensure_accessible(const LOGFONT& lf) { 39 if (gEnsureLOGFONTAccessibleProc) { 40 gEnsureLOGFONTAccessibleProc(lf); 41 } 42} 43 44/////////////////////////////////////////////////////////////////////////////// 45 46// always packed xxRRGGBB 47typedef uint32_t SkGdiRGB; 48 49template <typename T> T* SkTAddByteOffset(T* ptr, size_t byteOffset) { 50 return (T*)((char*)ptr + byteOffset); 51} 52 53// define this in your Makefile or .gyp to enforce AA requests 54// which GDI ignores at small sizes. This flag guarantees AA 55// for rotated text, regardless of GDI's notions. 56//#define SK_ENFORCE_ROTATED_TEXT_AA_ON_WINDOWS 57 58// client3d has to undefine this for now 59#define CAN_USE_LOGFONT_NAME 60 61static bool isLCD(const SkScalerContext::Rec& rec) { 62 return SkMask::kLCD16_Format == rec.fMaskFormat || 63 SkMask::kLCD32_Format == rec.fMaskFormat; 64} 65 66static bool bothZero(SkScalar a, SkScalar b) { 67 return 0 == a && 0 == b; 68} 69 70// returns false if there is any non-90-rotation or skew 71static bool isAxisAligned(const SkScalerContext::Rec& rec) { 72 return 0 == rec.fPreSkewX && 73 (bothZero(rec.fPost2x2[0][1], rec.fPost2x2[1][0]) || 74 bothZero(rec.fPost2x2[0][0], rec.fPost2x2[1][1])); 75} 76 77static bool needToRenderWithSkia(const SkScalerContext::Rec& rec) { 78#ifdef SK_ENFORCE_ROTATED_TEXT_AA_ON_WINDOWS 79 // What we really want to catch is when GDI will ignore the AA request and give 80 // us BW instead. Smallish rotated text is one heuristic, so this code is just 81 // an approximation. We shouldn't need to do this for larger sizes, but at those 82 // sizes, the quality difference gets less and less between our general 83 // scanconverter and GDI's. 84 if (SkMask::kA8_Format == rec.fMaskFormat && !isAxisAligned(rec)) { 85 return true; 86 } 87#endif 88 // false means allow GDI to generate the bits 89 return false; 90} 91 92using namespace skia_advanced_typeface_metrics_utils; 93 94static const uint16_t BUFFERSIZE = (16384 - 32); 95static uint8_t glyphbuf[BUFFERSIZE]; 96 97/** 98 * Since LOGFONT wants its textsize as an int, and we support fractional sizes, 99 * and since we have a cache of LOGFONTs for our tyepfaces, we always set the 100 * lfHeight to a canonical size, and then we use the 2x2 matrix to achieve the 101 * actual requested size. 102 */ 103static const int gCanonicalTextSize = 64; 104 105static void make_canonical(LOGFONT* lf) { 106 lf->lfHeight = -gCanonicalTextSize; 107 lf->lfQuality = CLEARTYPE_QUALITY;//PROOF_QUALITY; 108 lf->lfCharSet = DEFAULT_CHARSET; 109// lf->lfClipPrecision = 64; 110} 111 112static SkTypeface::Style get_style(const LOGFONT& lf) { 113 unsigned style = 0; 114 if (lf.lfWeight >= FW_BOLD) { 115 style |= SkTypeface::kBold; 116 } 117 if (lf.lfItalic) { 118 style |= SkTypeface::kItalic; 119 } 120 return static_cast<SkTypeface::Style>(style); 121} 122 123static void setStyle(LOGFONT* lf, SkTypeface::Style style) { 124 lf->lfWeight = (style & SkTypeface::kBold) != 0 ? FW_BOLD : FW_NORMAL ; 125 lf->lfItalic = ((style & SkTypeface::kItalic) != 0); 126} 127 128static inline FIXED SkFixedToFIXED(SkFixed x) { 129 return *(FIXED*)(&x); 130} 131static inline SkFixed SkFIXEDToFixed(FIXED x) { 132 return *(SkFixed*)(&x); 133} 134 135static inline FIXED SkScalarToFIXED(SkScalar x) { 136 return SkFixedToFIXED(SkScalarToFixed(x)); 137} 138 139static unsigned calculateOutlineGlyphCount(HDC hdc) { 140 // The 'maxp' table stores the number of glyphs at offset 4, in 2 bytes. 141 const DWORD maxpTag = 142 SkEndian_SwapBE32(SkSetFourByteTag('m', 'a', 'x', 'p')); 143 uint16_t glyphs; 144 if (GetFontData(hdc, maxpTag, 4, &glyphs, sizeof(glyphs)) != GDI_ERROR) { 145 return SkEndian_SwapBE16(glyphs); 146 } 147 148 // Binary search for glyph count. 149 static const MAT2 mat2 = {{0, 1}, {0, 0}, {0, 0}, {0, 1}}; 150 int32_t max = SK_MaxU16 + 1; 151 int32_t min = 0; 152 GLYPHMETRICS gm; 153 while (min < max) { 154 int32_t mid = min + ((max - min) / 2); 155 if (GetGlyphOutlineW(hdc, mid, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, 156 NULL, &mat2) == GDI_ERROR) { 157 max = mid; 158 } else { 159 min = mid + 1; 160 } 161 } 162 SkASSERT(min == max); 163 return min; 164} 165 166class LogFontTypeface : public SkTypeface { 167public: 168 LogFontTypeface(SkTypeface::Style style, SkFontID fontID, const LOGFONT& lf, bool serializeAsStream = false) : 169 SkTypeface(style, fontID, false), fLogFont(lf), fSerializeAsStream(serializeAsStream) { 170 171 // If the font has cubic outlines, it will not be rendered with ClearType. 172 HFONT font = CreateFontIndirect(&lf); 173 174 HDC deviceContext = ::CreateCompatibleDC(NULL); 175 HFONT savefont = (HFONT)SelectObject(deviceContext, font); 176 177 TEXTMETRIC textMetric; 178 if (0 == GetTextMetrics(deviceContext, &textMetric)) { 179 call_ensure_accessible(lf); 180 if (0 == GetTextMetrics(deviceContext, &textMetric)) { 181 textMetric.tmPitchAndFamily = TMPF_TRUETYPE; 182 } 183 } 184 if (deviceContext) { 185 ::SelectObject(deviceContext, savefont); 186 ::DeleteDC(deviceContext); 187 } 188 if (font) { 189 ::DeleteObject(font); 190 } 191 192 // Used a logfont on a memory context, should never get a device font. 193 // Therefore all TMPF_DEVICE will be PostScript (cubic) fonts. 194 fCanBeLCD = !((textMetric.tmPitchAndFamily & TMPF_VECTOR) && 195 (textMetric.tmPitchAndFamily & TMPF_DEVICE)); 196 } 197 198 LOGFONT fLogFont; 199 bool fSerializeAsStream; 200 bool fCanBeLCD; 201 202 static LogFontTypeface* Create(const LOGFONT& lf) { 203 SkTypeface::Style style = get_style(lf); 204 SkFontID fontID = SkTypefaceCache::NewFontID(); 205 return new LogFontTypeface(style, fontID, lf); 206 } 207 208 static void EnsureAccessible(const SkTypeface* face) { 209 call_ensure_accessible(static_cast<const LogFontTypeface*>(face)->fLogFont); 210 } 211 212protected: 213 virtual SkStream* onOpenStream(int* ttcIndex) const SK_OVERRIDE; 214 virtual SkScalerContext* onCreateScalerContext(const SkDescriptor*) const SK_OVERRIDE; 215 virtual void onFilterRec(SkScalerContextRec*) const SK_OVERRIDE; 216 virtual SkAdvancedTypefaceMetrics* onGetAdvancedTypefaceMetrics( 217 SkAdvancedTypefaceMetrics::PerGlyphInfo, 218 const uint32_t*, uint32_t) const SK_OVERRIDE; 219}; 220 221class FontMemResourceTypeface : public LogFontTypeface { 222public: 223 /** 224 * Takes ownership of fontMemResource. 225 */ 226 FontMemResourceTypeface(SkTypeface::Style style, SkFontID fontID, const LOGFONT& lf, HANDLE fontMemResource) : 227 LogFontTypeface(style, fontID, lf, true), fFontMemResource(fontMemResource) { 228 } 229 230 HANDLE fFontMemResource; 231 232 /** 233 * The created FontMemResourceTypeface takes ownership of fontMemResource. 234 */ 235 static FontMemResourceTypeface* Create(const LOGFONT& lf, HANDLE fontMemResource) { 236 SkTypeface::Style style = get_style(lf); 237 SkFontID fontID = SkTypefaceCache::NewFontID(); 238 return new FontMemResourceTypeface(style, fontID, lf, fontMemResource); 239 } 240 241protected: 242 virtual void weak_dispose() const SK_OVERRIDE { 243 RemoveFontMemResourceEx(fFontMemResource); 244 //SkTypefaceCache::Remove(this); 245 INHERITED::weak_dispose(); 246 } 247 248private: 249 typedef LogFontTypeface INHERITED; 250}; 251 252static const LOGFONT& get_default_font() { 253 static LOGFONT gDefaultFont; 254 return gDefaultFont; 255} 256 257static bool FindByLogFont(SkTypeface* face, SkTypeface::Style requestedStyle, void* ctx) { 258 LogFontTypeface* lface = static_cast<LogFontTypeface*>(face); 259 const LOGFONT* lf = reinterpret_cast<const LOGFONT*>(ctx); 260 261 return lface && 262 get_style(lface->fLogFont) == requestedStyle && 263 !memcmp(&lface->fLogFont, lf, sizeof(LOGFONT)); 264} 265 266/** 267 * This guy is public. It first searches the cache, and if a match is not found, 268 * it creates a new face. 269 */ 270SkTypeface* SkCreateTypefaceFromLOGFONT(const LOGFONT& origLF) { 271 LOGFONT lf = origLF; 272 make_canonical(&lf); 273 SkTypeface* face = SkTypefaceCache::FindByProcAndRef(FindByLogFont, &lf); 274 if (NULL == face) { 275 face = LogFontTypeface::Create(lf); 276 SkTypefaceCache::Add(face, get_style(lf)); 277 } 278 return face; 279} 280 281/** 282 * The created SkTypeface takes ownership of fontMemResource. 283 */ 284SkTypeface* SkCreateFontMemResourceTypefaceFromLOGFONT(const LOGFONT& origLF, HANDLE fontMemResource) { 285 LOGFONT lf = origLF; 286 make_canonical(&lf); 287 FontMemResourceTypeface* face = FontMemResourceTypeface::Create(lf, fontMemResource); 288 SkTypefaceCache::Add(face, get_style(lf), false); 289 return face; 290} 291 292/** 293 * This guy is public 294 */ 295void SkLOGFONTFromTypeface(const SkTypeface* face, LOGFONT* lf) { 296 if (NULL == face) { 297 *lf = get_default_font(); 298 } else { 299 *lf = static_cast<const LogFontTypeface*>(face)->fLogFont; 300 } 301} 302 303SkTypeface* SkFontHost::NextLogicalTypeface(SkFontID currFontID, SkFontID origFontID) { 304 // Zero means that we don't have any fallback fonts for this fontID. 305 // This function is implemented on Android, but doesn't have much 306 // meaning here. 307 return NULL; 308} 309 310static void GetLogFontByID(SkFontID fontID, LOGFONT* lf) { 311 LogFontTypeface* face = static_cast<LogFontTypeface*>(SkTypefaceCache::FindByID(fontID)); 312 if (face) { 313 *lf = face->fLogFont; 314 } else { 315 sk_bzero(lf, sizeof(LOGFONT)); 316 } 317} 318 319// Construct Glyph to Unicode table. 320// Unicode code points that require conjugate pairs in utf16 are not 321// supported. 322// TODO(arthurhsu): Add support for conjugate pairs. It looks like that may 323// require parsing the TTF cmap table (platform 4, encoding 12) directly instead 324// of calling GetFontUnicodeRange(). 325static void populate_glyph_to_unicode(HDC fontHdc, const unsigned glyphCount, 326 SkTDArray<SkUnichar>* glyphToUnicode) { 327 DWORD glyphSetBufferSize = GetFontUnicodeRanges(fontHdc, NULL); 328 if (!glyphSetBufferSize) { 329 return; 330 } 331 332 SkAutoTDeleteArray<BYTE> glyphSetBuffer(new BYTE[glyphSetBufferSize]); 333 GLYPHSET* glyphSet = 334 reinterpret_cast<LPGLYPHSET>(glyphSetBuffer.get()); 335 if (GetFontUnicodeRanges(fontHdc, glyphSet) != glyphSetBufferSize) { 336 return; 337 } 338 339 glyphToUnicode->setCount(glyphCount); 340 memset(glyphToUnicode->begin(), 0, glyphCount * sizeof(SkUnichar)); 341 for (DWORD i = 0; i < glyphSet->cRanges; ++i) { 342 // There is no guarantee that within a Unicode range, the corresponding 343 // glyph id in a font file are continuous. So, even if we have ranges, 344 // we can't just use the first and last entry of the range to compute 345 // result. We need to enumerate them one by one. 346 int count = glyphSet->ranges[i].cGlyphs; 347 SkAutoTArray<WCHAR> chars(count + 1); 348 chars[count] = 0; // termintate string 349 SkAutoTArray<WORD> glyph(count); 350 for (USHORT j = 0; j < count; ++j) { 351 chars[j] = glyphSet->ranges[i].wcLow + j; 352 } 353 GetGlyphIndicesW(fontHdc, chars.get(), count, glyph.get(), 354 GGI_MARK_NONEXISTING_GLYPHS); 355 // If the glyph ID is valid, and the glyph is not mapped, then we will 356 // fill in the char id into the vector. If the glyph is mapped already, 357 // skip it. 358 // TODO(arthurhsu): better improve this. e.g. Get all used char ids from 359 // font cache, then generate this mapping table from there. It's 360 // unlikely to have collisions since glyph reuse happens mostly for 361 // different Unicode pages. 362 for (USHORT j = 0; j < count; ++j) { 363 if (glyph[j] != 0xffff && glyph[j] < glyphCount && 364 (*glyphToUnicode)[glyph[j]] == 0) { 365 (*glyphToUnicode)[glyph[j]] = chars[j]; 366 } 367 } 368 } 369} 370 371////////////////////////////////////////////////////////////////////////////////////// 372 373static int alignTo32(int n) { 374 return (n + 31) & ~31; 375} 376 377struct MyBitmapInfo : public BITMAPINFO { 378 RGBQUAD fMoreSpaceForColors[1]; 379}; 380 381class HDCOffscreen { 382public: 383 HDCOffscreen() { 384 fFont = 0; 385 fDC = 0; 386 fBM = 0; 387 fBits = NULL; 388 fWidth = fHeight = 0; 389 fIsBW = false; 390 } 391 392 ~HDCOffscreen() { 393 if (fDC) { 394 DeleteDC(fDC); 395 } 396 if (fBM) { 397 DeleteObject(fBM); 398 } 399 } 400 401 void init(HFONT font, const XFORM& xform) { 402 fFont = font; 403 fXform = xform; 404 } 405 406 const void* draw(const SkGlyph&, bool isBW, size_t* srcRBPtr); 407 408private: 409 HDC fDC; 410 HBITMAP fBM; 411 HFONT fFont; 412 XFORM fXform; 413 void* fBits; // points into fBM 414 int fWidth; 415 int fHeight; 416 bool fIsBW; 417 418 enum { 419 // will always trigger us to reset the color, since we 420 // should only store 0 or 0x00FFFFFF or gray (0x007F7F7F) 421 kInvalid_Color = 12345 422 }; 423}; 424 425const void* HDCOffscreen::draw(const SkGlyph& glyph, bool isBW, 426 size_t* srcRBPtr) { 427 if (0 == fDC) { 428 fDC = CreateCompatibleDC(0); 429 if (0 == fDC) { 430 return NULL; 431 } 432 SetGraphicsMode(fDC, GM_ADVANCED); 433 SetBkMode(fDC, TRANSPARENT); 434 SetTextAlign(fDC, TA_LEFT | TA_BASELINE); 435 SelectObject(fDC, fFont); 436 437 COLORREF color = 0x00FFFFFF; 438 SkDEBUGCODE(COLORREF prev =) SetTextColor(fDC, color); 439 SkASSERT(prev != CLR_INVALID); 440 } 441 442 if (fBM && (fIsBW != isBW || fWidth < glyph.fWidth || fHeight < glyph.fHeight)) { 443 DeleteObject(fBM); 444 fBM = 0; 445 } 446 fIsBW = isBW; 447 448 fWidth = SkMax32(fWidth, glyph.fWidth); 449 fHeight = SkMax32(fHeight, glyph.fHeight); 450 451 int biWidth = isBW ? alignTo32(fWidth) : fWidth; 452 453 if (0 == fBM) { 454 MyBitmapInfo info; 455 sk_bzero(&info, sizeof(info)); 456 if (isBW) { 457 RGBQUAD blackQuad = { 0, 0, 0, 0 }; 458 RGBQUAD whiteQuad = { 0xFF, 0xFF, 0xFF, 0 }; 459 info.bmiColors[0] = blackQuad; 460 info.bmiColors[1] = whiteQuad; 461 } 462 info.bmiHeader.biSize = sizeof(info.bmiHeader); 463 info.bmiHeader.biWidth = biWidth; 464 info.bmiHeader.biHeight = fHeight; 465 info.bmiHeader.biPlanes = 1; 466 info.bmiHeader.biBitCount = isBW ? 1 : 32; 467 info.bmiHeader.biCompression = BI_RGB; 468 if (isBW) { 469 info.bmiHeader.biClrUsed = 2; 470 } 471 fBM = CreateDIBSection(fDC, &info, DIB_RGB_COLORS, &fBits, 0, 0); 472 if (0 == fBM) { 473 return NULL; 474 } 475 SelectObject(fDC, fBM); 476 } 477 478 // erase 479 size_t srcRB = isBW ? (biWidth >> 3) : (fWidth << 2); 480 size_t size = fHeight * srcRB; 481 memset(fBits, 0, size); 482 483 XFORM xform = fXform; 484 xform.eDx = (float)-glyph.fLeft; 485 xform.eDy = (float)-glyph.fTop; 486 SetWorldTransform(fDC, &xform); 487 488 uint16_t glyphID = glyph.getGlyphID(); 489 BOOL ret = ExtTextOutW(fDC, 0, 0, ETO_GLYPH_INDEX, NULL, reinterpret_cast<LPCWSTR>(&glyphID), 1, NULL); 490 GdiFlush(); 491 if (0 == ret) { 492 return NULL; 493 } 494 *srcRBPtr = srcRB; 495 // offset to the start of the image 496 return (const char*)fBits + (fHeight - glyph.fHeight) * srcRB; 497} 498 499////////////////////////////////////////////////////////////////////////////// 500 501class SkScalerContext_Windows : public SkScalerContext { 502public: 503 SkScalerContext_Windows(SkTypeface*, const SkDescriptor* desc); 504 virtual ~SkScalerContext_Windows(); 505 506protected: 507 virtual unsigned generateGlyphCount() SK_OVERRIDE; 508 virtual uint16_t generateCharToGlyph(SkUnichar uni) SK_OVERRIDE; 509 virtual void generateAdvance(SkGlyph* glyph) SK_OVERRIDE; 510 virtual void generateMetrics(SkGlyph* glyph) SK_OVERRIDE; 511 virtual void generateImage(const SkGlyph& glyph) SK_OVERRIDE; 512 virtual void generatePath(const SkGlyph& glyph, SkPath* path) SK_OVERRIDE; 513 virtual void generateFontMetrics(SkPaint::FontMetrics* mX, 514 SkPaint::FontMetrics* mY) SK_OVERRIDE; 515 516private: 517 HDCOffscreen fOffscreen; 518 SkScalar fScale; // to get from canonical size to real size 519 MAT2 fMat22; 520 HDC fDDC; 521 HFONT fSavefont; 522 HFONT fFont; 523 SCRIPT_CACHE fSC; 524 int fGlyphCount; 525 526 HFONT fHiResFont; 527 MAT2 fMat22Identity; 528 SkMatrix fHiResMatrix; 529 enum Type { 530 kTrueType_Type, kBitmap_Type, 531 } fType; 532 TEXTMETRIC fTM; 533}; 534 535static float mul2float(SkScalar a, SkScalar b) { 536 return SkScalarToFloat(SkScalarMul(a, b)); 537} 538 539static FIXED float2FIXED(float x) { 540 return SkFixedToFIXED(SkFloatToFixed(x)); 541} 542 543SK_DECLARE_STATIC_MUTEX(gFTMutex); 544 545#define HIRES_TEXTSIZE 2048 546#define HIRES_SHIFT 11 547static inline SkFixed HiResToFixed(int value) { 548 return value << (16 - HIRES_SHIFT); 549} 550 551static bool needHiResMetrics(const SkScalar mat[2][2]) { 552 return mat[1][0] || mat[0][1]; 553} 554 555static BYTE compute_quality(const SkScalerContext::Rec& rec) { 556 switch (rec.fMaskFormat) { 557 case SkMask::kBW_Format: 558 return NONANTIALIASED_QUALITY; 559 case SkMask::kLCD16_Format: 560 case SkMask::kLCD32_Format: 561 return CLEARTYPE_QUALITY; 562 default: 563 if (rec.fFlags & SkScalerContext::kGenA8FromLCD_Flag) { 564 return CLEARTYPE_QUALITY; 565 } else { 566 return ANTIALIASED_QUALITY; 567 } 568 } 569} 570 571SkScalerContext_Windows::SkScalerContext_Windows(SkTypeface* rawTypeface, 572 const SkDescriptor* desc) 573 : SkScalerContext(rawTypeface, desc) 574 , fDDC(0) 575 , fFont(0) 576 , fSavefont(0) 577 , fSC(0) 578 , fGlyphCount(-1) { 579 SkAutoMutexAcquire ac(gFTMutex); 580 581 LogFontTypeface* typeface = reinterpret_cast<LogFontTypeface*>(rawTypeface); 582 583 fDDC = ::CreateCompatibleDC(NULL); 584 SetGraphicsMode(fDDC, GM_ADVANCED); 585 SetBkMode(fDDC, TRANSPARENT); 586 587 // Scaling by the DPI is inconsistent with how Skia draws elsewhere 588 //SkScalar height = -(fRec.fTextSize * GetDeviceCaps(ddc, LOGPIXELSY) / 72); 589 LOGFONT lf = typeface->fLogFont; 590 lf.lfHeight = -gCanonicalTextSize; 591 lf.lfQuality = compute_quality(fRec); 592 fFont = CreateFontIndirect(&lf); 593 594 // if we're rotated, or want fractional widths, create a hires font 595 fHiResFont = 0; 596 if (needHiResMetrics(fRec.fPost2x2)) { 597 lf.lfHeight = -HIRES_TEXTSIZE; 598 fHiResFont = CreateFontIndirect(&lf); 599 600 fMat22Identity.eM11 = fMat22Identity.eM22 = SkFixedToFIXED(SK_Fixed1); 601 fMat22Identity.eM12 = fMat22Identity.eM21 = SkFixedToFIXED(0); 602 603 // construct a matrix to go from HIRES logical units to our device units 604 fRec.getSingleMatrix(&fHiResMatrix); 605 SkScalar scale = SkScalarInvert(SkIntToScalar(HIRES_TEXTSIZE)); 606 fHiResMatrix.preScale(scale, scale); 607 } 608 fSavefont = (HFONT)SelectObject(fDDC, fFont); 609 610 if (0 == GetTextMetrics(fDDC, &fTM)) { 611 call_ensure_accessible(lf); 612 if (0 == GetTextMetrics(fDDC, &fTM)) { 613 fTM.tmPitchAndFamily = TMPF_TRUETYPE; 614 } 615 } 616 // Used a logfont on a memory context, should never get a device font. 617 // Therefore all TMPF_DEVICE will be PostScript fonts. 618 619 // If TMPF_VECTOR is set, one of TMPF_TRUETYPE or TMPF_DEVICE must be set, 620 // otherwise we have a vector FON, which we don't support. 621 // This was determined by testing with Type1 PFM/PFB and OpenTypeCFF OTF, 622 // as well as looking at Wine bugs and sources. 623 SkASSERT(!(fTM.tmPitchAndFamily & TMPF_VECTOR) || 624 (fTM.tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_DEVICE))); 625 626 XFORM xform; 627 if (fTM.tmPitchAndFamily & TMPF_VECTOR) { 628 // Truetype or PostScript. 629 // Stroked FON also gets here (TMPF_VECTOR), but we don't handle it. 630 fType = SkScalerContext_Windows::kTrueType_Type; 631 fScale = fRec.fTextSize / gCanonicalTextSize; 632 633 // fPost2x2 is column-major, left handed (y down). 634 // XFORM 2x2 is row-major, left handed (y down). 635 xform.eM11 = mul2float(fScale, fRec.fPost2x2[0][0]); 636 xform.eM12 = mul2float(fScale, fRec.fPost2x2[1][0]); 637 xform.eM21 = mul2float(fScale, fRec.fPost2x2[0][1]); 638 xform.eM22 = mul2float(fScale, fRec.fPost2x2[1][1]); 639 xform.eDx = 0; 640 xform.eDy = 0; 641 642 // MAT2 is row major, right handed (y up). 643 fMat22.eM11 = float2FIXED(xform.eM11); 644 fMat22.eM12 = float2FIXED(-xform.eM12); 645 fMat22.eM21 = float2FIXED(-xform.eM21); 646 fMat22.eM22 = float2FIXED(xform.eM22); 647 648 if (needToRenderWithSkia(fRec)) { 649 this->forceGenerateImageFromPath(); 650 } 651 652 } else { 653 // Assume bitmap 654 fType = SkScalerContext_Windows::kBitmap_Type; 655 fScale = SK_Scalar1; 656 657 xform.eM11 = 1.0f; 658 xform.eM12 = 0.0f; 659 xform.eM21 = 0.0f; 660 xform.eM22 = 1.0f; 661 xform.eDx = 0.0f; 662 xform.eDy = 0.0f; 663 664 // fPost2x2 is column-major, left handed (y down). 665 // MAT2 is row major, right handed (y up). 666 fMat22.eM11 = SkScalarToFIXED(fRec.fPost2x2[0][0]); 667 fMat22.eM12 = SkScalarToFIXED(-fRec.fPost2x2[1][0]); 668 fMat22.eM21 = SkScalarToFIXED(-fRec.fPost2x2[0][1]); 669 fMat22.eM22 = SkScalarToFIXED(fRec.fPost2x2[1][1]); 670 671 lf.lfHeight = -SkScalarCeilToInt(fRec.fTextSize); 672 HFONT bitmapFont = CreateFontIndirect(&lf); 673 SelectObject(fDDC, bitmapFont); 674 ::DeleteObject(fFont); 675 fFont = bitmapFont; 676 677 if (0 == GetTextMetrics(fDDC, &fTM)) { 678 call_ensure_accessible(lf); 679 //if the following fails, we'll just draw at gCanonicalTextSize. 680 GetTextMetrics(fDDC, &fTM); 681 } 682 } 683 684 fOffscreen.init(fFont, xform); 685} 686 687SkScalerContext_Windows::~SkScalerContext_Windows() { 688 if (fDDC) { 689 ::SelectObject(fDDC, fSavefont); 690 ::DeleteDC(fDDC); 691 } 692 if (fFont) { 693 ::DeleteObject(fFont); 694 } 695 if (fHiResFont) { 696 ::DeleteObject(fHiResFont); 697 } 698 if (fSC) { 699 ::ScriptFreeCache(&fSC); 700 } 701} 702 703unsigned SkScalerContext_Windows::generateGlyphCount() { 704 if (fGlyphCount < 0) { 705 if (fType == SkScalerContext_Windows::kBitmap_Type) { 706 return fTM.tmLastChar; 707 } 708 fGlyphCount = calculateOutlineGlyphCount(fDDC); 709 } 710 return fGlyphCount; 711} 712 713uint16_t SkScalerContext_Windows::generateCharToGlyph(SkUnichar uni) { 714 uint16_t index = 0; 715 WCHAR c[2]; 716 // TODO(ctguil): Support characters that generate more than one glyph. 717 if (SkUTF16_FromUnichar(uni, (uint16_t*)c) == 1) { 718 // Type1 fonts fail with uniscribe API. Use GetGlyphIndices for plane 0. 719 SkAssertResult(GetGlyphIndicesW(fDDC, c, 1, &index, 0)); 720 } else { 721 // Use uniscribe to detemine glyph index for non-BMP characters. 722 // Need to add extra item to SCRIPT_ITEM to work around a bug in older 723 // windows versions. https://bugzilla.mozilla.org/show_bug.cgi?id=366643 724 SCRIPT_ITEM si[2 + 1]; 725 int items; 726 SkAssertResult( 727 SUCCEEDED(ScriptItemize(c, 2, 2, NULL, NULL, si, &items))); 728 729 WORD log[2]; 730 SCRIPT_VISATTR vsa; 731 int glyphs; 732 SkAssertResult(SUCCEEDED(ScriptShape( 733 fDDC, &fSC, c, 2, 1, &si[0].a, &index, log, &vsa, &glyphs))); 734 } 735 return index; 736} 737 738void SkScalerContext_Windows::generateAdvance(SkGlyph* glyph) { 739 this->generateMetrics(glyph); 740} 741 742void SkScalerContext_Windows::generateMetrics(SkGlyph* glyph) { 743 SkASSERT(fDDC); 744 745 if (fType == SkScalerContext_Windows::kBitmap_Type) { 746 SIZE size; 747 WORD glyphs = glyph->getGlyphID(0); 748 if (0 == GetTextExtentPointI(fDDC, &glyphs, 1, &size)) { 749 glyph->fWidth = SkToS16(fTM.tmMaxCharWidth); 750 } else { 751 glyph->fWidth = SkToS16(size.cx); 752 } 753 glyph->fHeight = SkToS16(size.cy); 754 755 glyph->fTop = SkToS16(-fTM.tmAscent); 756 glyph->fLeft = SkToS16(0); 757 glyph->fAdvanceX = SkIntToFixed(glyph->fWidth); 758 glyph->fAdvanceY = 0; 759 760 // Apply matrix to advance. 761 glyph->fAdvanceY = SkFixedMul(SkFIXEDToFixed(fMat22.eM21), glyph->fAdvanceX); 762 glyph->fAdvanceX = SkFixedMul(SkFIXEDToFixed(fMat22.eM11), glyph->fAdvanceX); 763 764 return; 765 } 766 767 UINT glyphId = glyph->getGlyphID(0); 768 769 GLYPHMETRICS gm; 770 sk_bzero(&gm, sizeof(gm)); 771 772 DWORD status = GetGlyphOutlineW(fDDC, glyphId, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &fMat22); 773 if (GDI_ERROR == status) { 774 LogFontTypeface::EnsureAccessible(this->getTypeface()); 775 status = GetGlyphOutlineW(fDDC, glyphId, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &fMat22); 776 if (GDI_ERROR == status) { 777 glyph->zeroMetrics(); 778 return; 779 } 780 } 781 782 bool empty = false; 783 // The black box is either the embedded bitmap size or the outline extent. 784 // It is 1x1 if nothing is to be drawn, but will also be 1x1 if something very small 785 // is to be drawn, like a '.'. We need to outset '.' but do not wish to outset ' '. 786 if (1 == gm.gmBlackBoxX && 1 == gm.gmBlackBoxY) { 787 // If GetGlyphOutline with GGO_NATIVE returns 0, we know there was no outline. 788 DWORD bufferSize = GetGlyphOutlineW(fDDC, glyphId, GGO_NATIVE | GGO_GLYPH_INDEX, &gm, 0, NULL, &fMat22); 789 empty = (0 == bufferSize); 790 } 791 792 glyph->fTop = SkToS16(-gm.gmptGlyphOrigin.y); 793 glyph->fLeft = SkToS16(gm.gmptGlyphOrigin.x); 794 if (empty) { 795 glyph->fWidth = 0; 796 glyph->fHeight = 0; 797 } else { 798 // Outset, since the image may bleed out of the black box. 799 // For embedded bitmaps the black box should be exact. 800 // For outlines we need to outset by 1 in all directions for bleed. 801 // For ClearType we need to outset by 2 for bleed. 802 glyph->fWidth = gm.gmBlackBoxX + 4; 803 glyph->fHeight = gm.gmBlackBoxY + 4; 804 glyph->fTop -= 2; 805 glyph->fLeft -= 2; 806 } 807 glyph->fAdvanceX = SkIntToFixed(gm.gmCellIncX); 808 glyph->fAdvanceY = SkIntToFixed(gm.gmCellIncY); 809 glyph->fRsbDelta = 0; 810 glyph->fLsbDelta = 0; 811 812 if (fHiResFont) { 813 SelectObject(fDDC, fHiResFont); 814 sk_bzero(&gm, sizeof(gm)); 815 status = GetGlyphOutlineW(fDDC, glyphId, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &fMat22Identity); 816 if (GDI_ERROR != status) { 817 SkPoint advance; 818 fHiResMatrix.mapXY(SkIntToScalar(gm.gmCellIncX), SkIntToScalar(gm.gmCellIncY), &advance); 819 glyph->fAdvanceX = SkScalarToFixed(advance.fX); 820 glyph->fAdvanceY = SkScalarToFixed(advance.fY); 821 } 822 SelectObject(fDDC, fFont); 823 } 824} 825 826void SkScalerContext_Windows::generateFontMetrics(SkPaint::FontMetrics* mx, SkPaint::FontMetrics* my) { 827// Note: This code was borrowed from generateLineHeight, which has a note 828// stating that it may be incorrect. 829 if (!(mx || my)) 830 return; 831 832 SkASSERT(fDDC); 833 834 if (fType == SkScalerContext_Windows::kBitmap_Type) { 835 if (mx) { 836 mx->fTop = SkIntToScalar(-fTM.tmAscent); 837 mx->fAscent = SkIntToScalar(-fTM.tmAscent); 838 mx->fDescent = -SkIntToScalar(fTM.tmDescent); 839 mx->fBottom = SkIntToScalar(fTM.tmDescent); 840 mx->fLeading = SkIntToScalar(fTM.tmInternalLeading 841 + fTM.tmExternalLeading); 842 } 843 844 if (my) { 845 my->fTop = SkIntToScalar(-fTM.tmAscent); 846 my->fAscent = SkIntToScalar(-fTM.tmAscent); 847 my->fDescent = SkIntToScalar(-fTM.tmDescent); 848 my->fBottom = SkIntToScalar(fTM.tmDescent); 849 my->fLeading = SkIntToScalar(fTM.tmInternalLeading 850 + fTM.tmExternalLeading); 851 } 852 return; 853 } 854 855 OUTLINETEXTMETRIC otm; 856 857 uint32_t ret = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm); 858 if (GDI_ERROR == ret) { 859 LogFontTypeface::EnsureAccessible(this->getTypeface()); 860 ret = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm); 861 } 862 if (sizeof(otm) != ret) { 863 return; 864 } 865 866 if (mx) { 867 mx->fTop = -fScale * otm.otmTextMetrics.tmAscent; 868 mx->fAscent = -fScale * otm.otmAscent; 869 mx->fDescent = -fScale * otm.otmDescent; 870 mx->fBottom = fScale * otm.otmTextMetrics.tmDescent; 871 mx->fLeading = fScale * (otm.otmTextMetrics.tmInternalLeading 872 + otm.otmTextMetrics.tmExternalLeading); 873 } 874 875 if (my) { 876 my->fTop = -fScale * otm.otmTextMetrics.tmAscent; 877 my->fAscent = -fScale * otm.otmAscent; 878 my->fDescent = -fScale * otm.otmDescent; 879 my->fBottom = fScale * otm.otmTextMetrics.tmDescent; 880 my->fLeading = fScale * (otm.otmTextMetrics.tmInternalLeading 881 + otm.otmTextMetrics.tmExternalLeading); 882 } 883} 884 885//////////////////////////////////////////////////////////////////////////////////////// 886 887static void build_power_table(uint8_t table[], float ee) { 888 for (int i = 0; i < 256; i++) { 889 float x = i / 255.f; 890 x = sk_float_pow(x, ee); 891 int xx = SkScalarRound(SkFloatToScalar(x * 255)); 892 table[i] = SkToU8(xx); 893 } 894} 895 896/** 897 * This will invert the gamma applied by GDI (gray-scale antialiased), so we 898 * can get linear values. 899 * 900 * GDI grayscale appears to use a hard-coded gamma of 2.3. 901 * 902 * GDI grayscale appears to draw using the black and white rasterizer at four 903 * times the size and then downsamples to compute the coverage mask. As a 904 * result there are only seventeen total grays. This lack of fidelity means 905 * that shifting into other color spaces is imprecise. 906 */ 907static const uint8_t* getInverseGammaTableGDI() { 908 static bool gInited; 909 static uint8_t gTableGdi[256]; 910 if (!gInited) { 911 build_power_table(gTableGdi, 2.3f); 912 gInited = true; 913 } 914 return gTableGdi; 915} 916 917/** 918 * This will invert the gamma applied by GDI ClearType, so we can get linear 919 * values. 920 * 921 * GDI ClearType uses SPI_GETFONTSMOOTHINGCONTRAST / 1000 as the gamma value. 922 * If this value is not specified, the default is a gamma of 1.4. 923 */ 924static const uint8_t* getInverseGammaTableClearType() { 925 static bool gInited; 926 static uint8_t gTableClearType[256]; 927 if (!gInited) { 928 UINT level = 0; 929 if (!SystemParametersInfo(SPI_GETFONTSMOOTHINGCONTRAST, 0, &level, 0) || !level) { 930 // can't get the data, so use a default 931 level = 1400; 932 } 933 build_power_table(gTableClearType, level / 1000.0f); 934 gInited = true; 935 } 936 return gTableClearType; 937} 938 939#include "SkColorPriv.h" 940 941//Cannot assume that the input rgb is gray due to possible setting of kGenA8FromLCD_Flag. 942template<bool APPLY_PREBLEND> 943static inline uint8_t rgb_to_a8(SkGdiRGB rgb, const uint8_t* table8) { 944 U8CPU r = (rgb >> 16) & 0xFF; 945 U8CPU g = (rgb >> 8) & 0xFF; 946 U8CPU b = (rgb >> 0) & 0xFF; 947 return sk_apply_lut_if<APPLY_PREBLEND>(SkComputeLuminance(r, g, b), table8); 948} 949 950template<bool APPLY_PREBLEND> 951static inline uint16_t rgb_to_lcd16(SkGdiRGB rgb, const uint8_t* tableR, 952 const uint8_t* tableG, 953 const uint8_t* tableB) { 954 U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 16) & 0xFF, tableR); 955 U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 8) & 0xFF, tableG); 956 U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 0) & 0xFF, tableB); 957 return SkPack888ToRGB16(r, g, b); 958} 959 960template<bool APPLY_PREBLEND> 961static inline SkPMColor rgb_to_lcd32(SkGdiRGB rgb, const uint8_t* tableR, 962 const uint8_t* tableG, 963 const uint8_t* tableB) { 964 U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 16) & 0xFF, tableR); 965 U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 8) & 0xFF, tableG); 966 U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 0) & 0xFF, tableB); 967 return SkPackARGB32(0xFF, r, g, b); 968} 969 970// Is this GDI color neither black nor white? If so, we have to keep this 971// image as is, rather than smashing it down to a BW mask. 972// 973// returns int instead of bool, since we don't want/have to pay to convert 974// the zero/non-zero value into a bool 975static int is_not_black_or_white(SkGdiRGB c) { 976 // same as (but faster than) 977 // c &= 0x00FFFFFF; 978 // return 0 == c || 0x00FFFFFF == c; 979 return (c + (c & 1)) & 0x00FFFFFF; 980} 981 982static bool is_rgb_really_bw(const SkGdiRGB* src, int width, int height, int srcRB) { 983 for (int y = 0; y < height; ++y) { 984 for (int x = 0; x < width; ++x) { 985 if (is_not_black_or_white(src[x])) { 986 return false; 987 } 988 } 989 src = SkTAddByteOffset(src, srcRB); 990 } 991 return true; 992} 993 994// gdi's bitmap is upside-down, so we reverse dst walking in Y 995// whenever we copy it into skia's buffer 996static void rgb_to_bw(const SkGdiRGB* SK_RESTRICT src, size_t srcRB, 997 const SkGlyph& glyph) { 998 const int width = glyph.fWidth; 999 const size_t dstRB = (width + 7) >> 3; 1000 uint8_t* SK_RESTRICT dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB); 1001 1002 int byteCount = width >> 3; 1003 int bitCount = width & 7; 1004 1005 // adjust srcRB to skip the values in our byteCount loop, 1006 // since we increment src locally there 1007 srcRB -= byteCount * 8 * sizeof(SkGdiRGB); 1008 1009 for (int y = 0; y < glyph.fHeight; ++y) { 1010 if (byteCount > 0) { 1011 for (int i = 0; i < byteCount; ++i) { 1012 unsigned byte = 0; 1013 byte |= src[0] & (1 << 7); 1014 byte |= src[1] & (1 << 6); 1015 byte |= src[2] & (1 << 5); 1016 byte |= src[3] & (1 << 4); 1017 byte |= src[4] & (1 << 3); 1018 byte |= src[5] & (1 << 2); 1019 byte |= src[6] & (1 << 1); 1020 byte |= src[7] & (1 << 0); 1021 dst[i] = byte; 1022 src += 8; 1023 } 1024 } 1025 if (bitCount > 0) { 1026 unsigned byte = 0; 1027 unsigned mask = 0x80; 1028 for (int i = 0; i < bitCount; i++) { 1029 byte |= src[i] & mask; 1030 mask >>= 1; 1031 } 1032 dst[byteCount] = byte; 1033 } 1034 src = SkTAddByteOffset(src, srcRB); 1035 dst -= dstRB; 1036 } 1037} 1038 1039template<bool APPLY_PREBLEND> 1040static void rgb_to_a8(const SkGdiRGB* SK_RESTRICT src, size_t srcRB, 1041 const SkGlyph& glyph, const uint8_t* table8) { 1042 const size_t dstRB = glyph.rowBytes(); 1043 const int width = glyph.fWidth; 1044 uint8_t* SK_RESTRICT dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB); 1045 1046 for (int y = 0; y < glyph.fHeight; y++) { 1047 for (int i = 0; i < width; i++) { 1048 dst[i] = rgb_to_a8<APPLY_PREBLEND>(src[i], table8); 1049 } 1050 src = SkTAddByteOffset(src, srcRB); 1051 dst -= dstRB; 1052 } 1053} 1054 1055template<bool APPLY_PREBLEND> 1056static void rgb_to_lcd16(const SkGdiRGB* SK_RESTRICT src, size_t srcRB, const SkGlyph& glyph, 1057 const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) { 1058 const size_t dstRB = glyph.rowBytes(); 1059 const int width = glyph.fWidth; 1060 uint16_t* SK_RESTRICT dst = (uint16_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB); 1061 1062 for (int y = 0; y < glyph.fHeight; y++) { 1063 for (int i = 0; i < width; i++) { 1064 dst[i] = rgb_to_lcd16<APPLY_PREBLEND>(src[i], tableR, tableG, tableB); 1065 } 1066 src = SkTAddByteOffset(src, srcRB); 1067 dst = (uint16_t*)((char*)dst - dstRB); 1068 } 1069} 1070 1071template<bool APPLY_PREBLEND> 1072static void rgb_to_lcd32(const SkGdiRGB* SK_RESTRICT src, size_t srcRB, const SkGlyph& glyph, 1073 const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) { 1074 const size_t dstRB = glyph.rowBytes(); 1075 const int width = glyph.fWidth; 1076 uint32_t* SK_RESTRICT dst = (uint32_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB); 1077 1078 for (int y = 0; y < glyph.fHeight; y++) { 1079 for (int i = 0; i < width; i++) { 1080 dst[i] = rgb_to_lcd32<APPLY_PREBLEND>(src[i], tableR, tableG, tableB); 1081 } 1082 src = SkTAddByteOffset(src, srcRB); 1083 dst = (uint32_t*)((char*)dst - dstRB); 1084 } 1085} 1086 1087static inline unsigned clamp255(unsigned x) { 1088 SkASSERT(x <= 256); 1089 return x - (x >> 8); 1090} 1091 1092void SkScalerContext_Windows::generateImage(const SkGlyph& glyph) { 1093 SkAutoMutexAcquire ac(gFTMutex); 1094 SkASSERT(fDDC); 1095 1096 const bool isBW = SkMask::kBW_Format == fRec.fMaskFormat; 1097 const bool isAA = !isLCD(fRec); 1098 1099 size_t srcRB; 1100 const void* bits = fOffscreen.draw(glyph, isBW, &srcRB); 1101 if (NULL == bits) { 1102 LogFontTypeface::EnsureAccessible(this->getTypeface()); 1103 bits = fOffscreen.draw(glyph, isBW, &srcRB); 1104 if (NULL == bits) { 1105 sk_bzero(glyph.fImage, glyph.computeImageSize()); 1106 return; 1107 } 1108 } 1109 1110 if (!isBW) { 1111 const uint8_t* table; 1112 //The offscreen contains a GDI blit if isAA and kGenA8FromLCD_Flag is not set. 1113 //Otherwise the offscreen contains a ClearType blit. 1114 if (isAA && !(fRec.fFlags & SkScalerContext::kGenA8FromLCD_Flag)) { 1115 table = getInverseGammaTableGDI(); 1116 } else { 1117 table = getInverseGammaTableClearType(); 1118 } 1119 //Note that the following cannot really be integrated into the 1120 //pre-blend, since we may not be applying the pre-blend; when we aren't 1121 //applying the pre-blend it means that a filter wants linear anyway. 1122 //Other code may also be applying the pre-blend, so we'd need another 1123 //one with this and one without. 1124 SkGdiRGB* addr = (SkGdiRGB*)bits; 1125 for (int y = 0; y < glyph.fHeight; ++y) { 1126 for (int x = 0; x < glyph.fWidth; ++x) { 1127 int r = (addr[x] >> 16) & 0xFF; 1128 int g = (addr[x] >> 8) & 0xFF; 1129 int b = (addr[x] >> 0) & 0xFF; 1130 addr[x] = (table[r] << 16) | (table[g] << 8) | table[b]; 1131 } 1132 addr = SkTAddByteOffset(addr, srcRB); 1133 } 1134 } 1135 1136 int width = glyph.fWidth; 1137 size_t dstRB = glyph.rowBytes(); 1138 if (isBW) { 1139 const uint8_t* src = (const uint8_t*)bits; 1140 uint8_t* dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB); 1141 for (int y = 0; y < glyph.fHeight; y++) { 1142 memcpy(dst, src, dstRB); 1143 src += srcRB; 1144 dst -= dstRB; 1145 } 1146 } else if (isAA) { 1147 // since the caller may require A8 for maskfilters, we can't check for BW 1148 // ... until we have the caller tell us that explicitly 1149 const SkGdiRGB* src = (const SkGdiRGB*)bits; 1150 if (fPreBlend.isApplicable()) { 1151 rgb_to_a8<true>(src, srcRB, glyph, fPreBlend.fG); 1152 } else { 1153 rgb_to_a8<false>(src, srcRB, glyph, fPreBlend.fG); 1154 } 1155 } else { // LCD16 1156 const SkGdiRGB* src = (const SkGdiRGB*)bits; 1157 if (is_rgb_really_bw(src, width, glyph.fHeight, srcRB)) { 1158 rgb_to_bw(src, srcRB, glyph); 1159 ((SkGlyph*)&glyph)->fMaskFormat = SkMask::kBW_Format; 1160 } else { 1161 if (SkMask::kLCD16_Format == glyph.fMaskFormat) { 1162 if (fPreBlend.isApplicable()) { 1163 rgb_to_lcd16<true>(src, srcRB, glyph, 1164 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB); 1165 } else { 1166 rgb_to_lcd16<false>(src, srcRB, glyph, 1167 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB); 1168 } 1169 } else { 1170 SkASSERT(SkMask::kLCD32_Format == glyph.fMaskFormat); 1171 if (fPreBlend.isApplicable()) { 1172 rgb_to_lcd32<true>(src, srcRB, glyph, 1173 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB); 1174 } else { 1175 rgb_to_lcd32<false>(src, srcRB, glyph, 1176 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB); 1177 } 1178 } 1179 } 1180 } 1181} 1182 1183void SkScalerContext_Windows::generatePath(const SkGlyph& glyph, SkPath* path) { 1184 1185 SkAutoMutexAcquire ac(gFTMutex); 1186 1187 SkASSERT(&glyph && path); 1188 SkASSERT(fDDC); 1189 1190 path->reset(); 1191 1192 GLYPHMETRICS gm; 1193 uint32_t total_size = GetGlyphOutlineW(fDDC, glyph.fID, GGO_NATIVE | GGO_GLYPH_INDEX, &gm, BUFFERSIZE, glyphbuf, &fMat22); 1194 if (GDI_ERROR == total_size) { 1195 LogFontTypeface::EnsureAccessible(this->getTypeface()); 1196 total_size = GetGlyphOutlineW(fDDC, glyph.fID, GGO_NATIVE | GGO_GLYPH_INDEX, &gm, BUFFERSIZE, glyphbuf, &fMat22); 1197 if (GDI_ERROR == total_size) { 1198 SkASSERT(false); 1199 return; 1200 } 1201 } 1202 1203 const uint8_t* cur_glyph = glyphbuf; 1204 const uint8_t* end_glyph = glyphbuf + total_size; 1205 1206 while (cur_glyph < end_glyph) { 1207 const TTPOLYGONHEADER* th = (TTPOLYGONHEADER*)cur_glyph; 1208 1209 const uint8_t* end_poly = cur_glyph + th->cb; 1210 const uint8_t* cur_poly = cur_glyph + sizeof(TTPOLYGONHEADER); 1211 1212 path->moveTo(SkFixedToScalar( SkFIXEDToFixed(th->pfxStart.x)), 1213 SkFixedToScalar(-SkFIXEDToFixed(th->pfxStart.y))); 1214 1215 while (cur_poly < end_poly) { 1216 const TTPOLYCURVE* pc = (const TTPOLYCURVE*)cur_poly; 1217 1218 if (pc->wType == TT_PRIM_LINE) { 1219 for (uint16_t i = 0; i < pc->cpfx; i++) { 1220 path->lineTo(SkFixedToScalar( SkFIXEDToFixed(pc->apfx[i].x)), 1221 SkFixedToScalar(-SkFIXEDToFixed(pc->apfx[i].y))); 1222 } 1223 } 1224 1225 if (pc->wType == TT_PRIM_QSPLINE) { 1226 for (uint16_t u = 0; u < pc->cpfx - 1; u++) { // Walk through points in spline 1227 POINTFX pnt_b = pc->apfx[u]; // B is always the current point 1228 POINTFX pnt_c = pc->apfx[u+1]; 1229 1230 if (u < pc->cpfx - 2) { // If not on last spline, compute C 1231 pnt_c.x = SkFixedToFIXED(SkFixedAve(SkFIXEDToFixed(pnt_b.x), 1232 SkFIXEDToFixed(pnt_c.x))); 1233 pnt_c.y = SkFixedToFIXED(SkFixedAve(SkFIXEDToFixed(pnt_b.y), 1234 SkFIXEDToFixed(pnt_c.y))); 1235 } 1236 1237 path->quadTo(SkFixedToScalar( SkFIXEDToFixed(pnt_b.x)), 1238 SkFixedToScalar(-SkFIXEDToFixed(pnt_b.y)), 1239 SkFixedToScalar( SkFIXEDToFixed(pnt_c.x)), 1240 SkFixedToScalar(-SkFIXEDToFixed(pnt_c.y))); 1241 } 1242 } 1243 // Advance past this TTPOLYCURVE. 1244 cur_poly += sizeof(WORD) * 2 + sizeof(POINTFX) * pc->cpfx; 1245 } 1246 cur_glyph += th->cb; 1247 path->close(); 1248 } 1249} 1250 1251static void logfont_for_name(const char* familyName, LOGFONT& lf) { 1252 memset(&lf, 0, sizeof(LOGFONT)); 1253#ifdef UNICODE 1254 // Get the buffer size needed first. 1255 size_t str_len = ::MultiByteToWideChar(CP_UTF8, 0, familyName, 1256 -1, NULL, 0); 1257 // Allocate a buffer (str_len already has terminating null 1258 // accounted for). 1259 wchar_t *wideFamilyName = new wchar_t[str_len]; 1260 // Now actually convert the string. 1261 ::MultiByteToWideChar(CP_UTF8, 0, familyName, -1, 1262 wideFamilyName, str_len); 1263 ::wcsncpy(lf.lfFaceName, wideFamilyName, LF_FACESIZE - 1); 1264 delete [] wideFamilyName; 1265 lf.lfFaceName[LF_FACESIZE-1] = L'\0'; 1266#else 1267 ::strncpy(lf.lfFaceName, familyName, LF_FACESIZE - 1); 1268 lf.lfFaceName[LF_FACESIZE - 1] = '\0'; 1269#endif 1270} 1271 1272static void tchar_to_skstring(const TCHAR* t, SkString* s) { 1273#ifdef UNICODE 1274 size_t sSize = WideCharToMultiByte(CP_UTF8, 0, t, -1, NULL, 0, NULL, NULL); 1275 s->resize(sSize); 1276 WideCharToMultiByte(CP_UTF8, 0, t, -1, s->writable_str(), sSize, NULL, NULL); 1277#else 1278 s->set(t); 1279#endif 1280} 1281 1282void SkFontHost::Serialize(const SkTypeface* rawFace, SkWStream* stream) { 1283 const LogFontTypeface* face = static_cast<const LogFontTypeface*>(rawFace); 1284 SkFontDescriptor descriptor(face->style()); 1285 1286 // Get the actual name of the typeface. The logfont may not know this. 1287 HFONT font = CreateFontIndirect(&face->fLogFont); 1288 1289 HDC deviceContext = ::CreateCompatibleDC(NULL); 1290 HFONT savefont = (HFONT)SelectObject(deviceContext, font); 1291 1292 int fontNameLen; //length of fontName in TCHARS. 1293 if (0 == (fontNameLen = GetTextFace(deviceContext, 0, NULL))) { 1294 LogFontTypeface::EnsureAccessible(rawFace); 1295 if (0 == (fontNameLen = GetTextFace(deviceContext, 0, NULL))) { 1296 fontNameLen = 0; 1297 } 1298 } 1299 1300 SkAutoSTArray<LF_FULLFACESIZE, TCHAR> fontName(fontNameLen+1); 1301 if (0 == GetTextFace(deviceContext, fontNameLen, fontName.get())) { 1302 LogFontTypeface::EnsureAccessible(rawFace); 1303 if (0 == GetTextFace(deviceContext, fontNameLen, fontName.get())) { 1304 fontName[0] = 0; 1305 } 1306 } 1307 1308 if (deviceContext) { 1309 ::SelectObject(deviceContext, savefont); 1310 ::DeleteDC(deviceContext); 1311 } 1312 if (font) { 1313 ::DeleteObject(font); 1314 } 1315 1316 SkString familyName; 1317 tchar_to_skstring(fontName.get(), &familyName); 1318 descriptor.setFamilyName(familyName.c_str()); 1319 //TODO: FileName and PostScriptName currently unsupported. 1320 1321 descriptor.serialize(stream); 1322 1323 if (face->fSerializeAsStream) { 1324 // store the entire font in the fontData 1325 SkAutoTUnref<SkStream> fontStream(face->openStream(NULL)); 1326 if (fontStream.get()) { 1327 const uint32_t length = fontStream->getLength(); 1328 stream->writePackedUInt(length); 1329 stream->writeStream(fontStream, length); 1330 } else { 1331 stream->writePackedUInt(0); 1332 } 1333 } else { 1334 stream->writePackedUInt(0); 1335 } 1336} 1337 1338SkTypeface* SkFontHost::Deserialize(SkStream* stream) { 1339 SkFontDescriptor descriptor(stream); 1340 1341 const uint32_t customFontDataLength = stream->readPackedUInt(); 1342 if (customFontDataLength > 0) { 1343 // generate a new stream to store the custom typeface 1344 SkAutoTUnref<SkMemoryStream> fontStream(SkNEW_ARGS(SkMemoryStream, (customFontDataLength - 1))); 1345 stream->read((void*)fontStream->getMemoryBase(), customFontDataLength - 1); 1346 1347 return CreateTypefaceFromStream(fontStream.get()); 1348 } 1349 1350 return SkFontHost::CreateTypeface(NULL, descriptor.getFamilyName(), descriptor.getStyle()); 1351} 1352 1353static bool getWidthAdvance(HDC hdc, int gId, int16_t* advance) { 1354 // Initialize the MAT2 structure to the identify transformation matrix. 1355 static const MAT2 mat2 = {SkScalarToFIXED(1), SkScalarToFIXED(0), 1356 SkScalarToFIXED(0), SkScalarToFIXED(1)}; 1357 int flags = GGO_METRICS | GGO_GLYPH_INDEX; 1358 GLYPHMETRICS gm; 1359 if (GDI_ERROR == GetGlyphOutline(hdc, gId, flags, &gm, 0, NULL, &mat2)) { 1360 return false; 1361 } 1362 SkASSERT(advance); 1363 *advance = gm.gmCellIncX; 1364 return true; 1365} 1366 1367SkAdvancedTypefaceMetrics* LogFontTypeface::onGetAdvancedTypefaceMetrics( 1368 SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo, 1369 const uint32_t* glyphIDs, 1370 uint32_t glyphIDsCount) const { 1371 LOGFONT lf = fLogFont; 1372 SkAdvancedTypefaceMetrics* info = NULL; 1373 1374 HDC hdc = CreateCompatibleDC(NULL); 1375 HFONT font = CreateFontIndirect(&lf); 1376 HFONT savefont = (HFONT)SelectObject(hdc, font); 1377 HFONT designFont = NULL; 1378 1379 const char stem_chars[] = {'i', 'I', '!', '1'}; 1380 int16_t min_width; 1381 unsigned glyphCount; 1382 1383 // To request design units, create a logical font whose height is specified 1384 // as unitsPerEm. 1385 OUTLINETEXTMETRIC otm; 1386 unsigned int otmRet = GetOutlineTextMetrics(hdc, sizeof(otm), &otm); 1387 if (0 == otmRet) { 1388 call_ensure_accessible(lf); 1389 otmRet = GetOutlineTextMetrics(hdc, sizeof(otm), &otm); 1390 } 1391 if (!otmRet || !GetTextFace(hdc, LF_FACESIZE, lf.lfFaceName)) { 1392 goto Error; 1393 } 1394 lf.lfHeight = -SkToS32(otm.otmEMSquare); 1395 designFont = CreateFontIndirect(&lf); 1396 SelectObject(hdc, designFont); 1397 if (!GetOutlineTextMetrics(hdc, sizeof(otm), &otm)) { 1398 goto Error; 1399 } 1400 glyphCount = calculateOutlineGlyphCount(hdc); 1401 1402 info = new SkAdvancedTypefaceMetrics; 1403 info->fEmSize = otm.otmEMSquare; 1404 info->fMultiMaster = false; 1405 info->fLastGlyphID = SkToU16(glyphCount - 1); 1406 info->fStyle = 0; 1407 tchar_to_skstring(lf.lfFaceName, &info->fFontName); 1408 1409 if (perGlyphInfo & SkAdvancedTypefaceMetrics::kToUnicode_PerGlyphInfo) { 1410 populate_glyph_to_unicode(hdc, glyphCount, &(info->fGlyphToUnicode)); 1411 } 1412 1413 if (glyphCount > 0 && 1414 (otm.otmTextMetrics.tmPitchAndFamily & TMPF_TRUETYPE)) { 1415 info->fType = SkAdvancedTypefaceMetrics::kTrueType_Font; 1416 } else { 1417 info->fType = SkAdvancedTypefaceMetrics::kOther_Font; 1418 info->fItalicAngle = 0; 1419 info->fAscent = 0; 1420 info->fDescent = 0; 1421 info->fStemV = 0; 1422 info->fCapHeight = 0; 1423 info->fBBox = SkIRect::MakeEmpty(); 1424 return info; 1425 } 1426 1427 // If this bit is clear the font is a fixed pitch font. 1428 if (!(otm.otmTextMetrics.tmPitchAndFamily & TMPF_FIXED_PITCH)) { 1429 info->fStyle |= SkAdvancedTypefaceMetrics::kFixedPitch_Style; 1430 } 1431 if (otm.otmTextMetrics.tmItalic) { 1432 info->fStyle |= SkAdvancedTypefaceMetrics::kItalic_Style; 1433 } 1434 if (otm.otmTextMetrics.tmPitchAndFamily & FF_ROMAN) { 1435 info->fStyle |= SkAdvancedTypefaceMetrics::kSerif_Style; 1436 } else if (otm.otmTextMetrics.tmPitchAndFamily & FF_SCRIPT) { 1437 info->fStyle |= SkAdvancedTypefaceMetrics::kScript_Style; 1438 } 1439 1440 // The main italic angle of the font, in tenths of a degree counterclockwise 1441 // from vertical. 1442 info->fItalicAngle = otm.otmItalicAngle / 10; 1443 info->fAscent = SkToS16(otm.otmTextMetrics.tmAscent); 1444 info->fDescent = SkToS16(-otm.otmTextMetrics.tmDescent); 1445 // TODO(ctguil): Use alternate cap height calculation. 1446 // MSDN says otmsCapEmHeight is not support but it is returning a value on 1447 // my Win7 box. 1448 info->fCapHeight = otm.otmsCapEmHeight; 1449 info->fBBox = 1450 SkIRect::MakeLTRB(otm.otmrcFontBox.left, otm.otmrcFontBox.top, 1451 otm.otmrcFontBox.right, otm.otmrcFontBox.bottom); 1452 1453 // Figure out a good guess for StemV - Min width of i, I, !, 1. 1454 // This probably isn't very good with an italic font. 1455 min_width = SHRT_MAX; 1456 info->fStemV = 0; 1457 for (size_t i = 0; i < SK_ARRAY_COUNT(stem_chars); i++) { 1458 ABC abcWidths; 1459 if (GetCharABCWidths(hdc, stem_chars[i], stem_chars[i], &abcWidths)) { 1460 int16_t width = abcWidths.abcB; 1461 if (width > 0 && width < min_width) { 1462 min_width = width; 1463 info->fStemV = min_width; 1464 } 1465 } 1466 } 1467 1468 // If bit 1 is set, the font may not be embedded in a document. 1469 // If bit 1 is clear, the font can be embedded. 1470 // If bit 2 is set, the embedding is read-only. 1471 if (otm.otmfsType & 0x1) { 1472 info->fType = SkAdvancedTypefaceMetrics::kNotEmbeddable_Font; 1473 } else if (perGlyphInfo & 1474 SkAdvancedTypefaceMetrics::kHAdvance_PerGlyphInfo) { 1475 if (info->fStyle & SkAdvancedTypefaceMetrics::kFixedPitch_Style) { 1476 appendRange(&info->fGlyphWidths, 0); 1477 info->fGlyphWidths->fAdvance.append(1, &min_width); 1478 finishRange(info->fGlyphWidths.get(), 0, 1479 SkAdvancedTypefaceMetrics::WidthRange::kDefault); 1480 } else { 1481 info->fGlyphWidths.reset( 1482 getAdvanceData(hdc, 1483 glyphCount, 1484 glyphIDs, 1485 glyphIDsCount, 1486 &getWidthAdvance)); 1487 } 1488 } 1489 1490Error: 1491 SelectObject(hdc, savefont); 1492 DeleteObject(designFont); 1493 DeleteObject(font); 1494 DeleteDC(hdc); 1495 1496 return info; 1497} 1498 1499//Dummy representation of a Base64 encoded GUID from create_unique_font_name. 1500#define BASE64_GUID_ID "XXXXXXXXXXXXXXXXXXXXXXXX" 1501//Length of GUID representation from create_id, including NULL terminator. 1502#define BASE64_GUID_ID_LEN SK_ARRAY_COUNT(BASE64_GUID_ID) 1503 1504SK_COMPILE_ASSERT(BASE64_GUID_ID_LEN < LF_FACESIZE, GUID_longer_than_facesize); 1505 1506/** 1507 NameID 6 Postscript names cannot have the character '/'. 1508 It would be easier to hex encode the GUID, but that is 32 bytes, 1509 and many systems have issues with names longer than 28 bytes. 1510 The following need not be any standard base64 encoding. 1511 The encoded value is never decoded. 1512*/ 1513static const char postscript_safe_base64_encode[] = 1514 "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 1515 "abcdefghijklmnopqrstuvwxyz" 1516 "0123456789-_="; 1517 1518/** 1519 Formats a GUID into Base64 and places it into buffer. 1520 buffer should have space for at least BASE64_GUID_ID_LEN characters. 1521 The string will always be null terminated. 1522 XXXXXXXXXXXXXXXXXXXXXXXX0 1523 */ 1524static void format_guid_b64(const GUID& guid, char* buffer, size_t bufferSize) { 1525 SkASSERT(bufferSize >= BASE64_GUID_ID_LEN); 1526 size_t written = SkBase64::Encode(&guid, sizeof(guid), buffer, postscript_safe_base64_encode); 1527 SkASSERT(written < LF_FACESIZE); 1528 buffer[written] = '\0'; 1529} 1530 1531/** 1532 Creates a Base64 encoded GUID and places it into buffer. 1533 buffer should have space for at least BASE64_GUID_ID_LEN characters. 1534 The string will always be null terminated. 1535 XXXXXXXXXXXXXXXXXXXXXXXX0 1536 */ 1537static HRESULT create_unique_font_name(char* buffer, size_t bufferSize) { 1538 GUID guid = {}; 1539 if (FAILED(CoCreateGuid(&guid))) { 1540 return E_UNEXPECTED; 1541 } 1542 format_guid_b64(guid, buffer, bufferSize); 1543 1544 return S_OK; 1545} 1546 1547/** 1548 Introduces a font to GDI. On failure will return NULL. The returned handle 1549 should eventually be passed to RemoveFontMemResourceEx. 1550*/ 1551static HANDLE activate_font(SkData* fontData) { 1552 DWORD numFonts = 0; 1553 //AddFontMemResourceEx just copies the data, but does not specify const. 1554 HANDLE fontHandle = AddFontMemResourceEx(const_cast<void*>(fontData->data()), 1555 fontData->size(), 1556 0, 1557 &numFonts); 1558 1559 if (fontHandle != NULL && numFonts < 1) { 1560 RemoveFontMemResourceEx(fontHandle); 1561 return NULL; 1562 } 1563 1564 return fontHandle; 1565} 1566 1567SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) { 1568 // Create a unique and unpredictable font name. 1569 // Avoids collisions and access from CSS. 1570 char familyName[BASE64_GUID_ID_LEN]; 1571 const int familyNameSize = SK_ARRAY_COUNT(familyName); 1572 if (FAILED(create_unique_font_name(familyName, familyNameSize))) { 1573 return NULL; 1574 } 1575 1576 // Change the name of the font. 1577 SkAutoTUnref<SkData> rewrittenFontData(SkOTUtils::RenameFont(stream, familyName, familyNameSize-1)); 1578 if (NULL == rewrittenFontData.get()) { 1579 return NULL; 1580 } 1581 1582 // Register the font with GDI. 1583 HANDLE fontReference = activate_font(rewrittenFontData.get()); 1584 if (NULL == fontReference) { 1585 return NULL; 1586 } 1587 1588 // Create the typeface. 1589 LOGFONT lf; 1590 logfont_for_name(familyName, lf); 1591 1592 return SkCreateFontMemResourceTypefaceFromLOGFONT(lf, fontReference); 1593} 1594 1595SkStream* LogFontTypeface::onOpenStream(int* ttcIndex) const { 1596 *ttcIndex = 0; 1597 1598 const DWORD kTTCTag = 1599 SkEndian_SwapBE32(SkSetFourByteTag('t', 't', 'c', 'f')); 1600 LOGFONT lf = fLogFont; 1601 1602 HDC hdc = ::CreateCompatibleDC(NULL); 1603 HFONT font = CreateFontIndirect(&lf); 1604 HFONT savefont = (HFONT)SelectObject(hdc, font); 1605 1606 SkMemoryStream* stream = NULL; 1607 DWORD tables[2] = {kTTCTag, 0}; 1608 for (int i = 0; i < SK_ARRAY_COUNT(tables); i++) { 1609 size_t bufferSize = GetFontData(hdc, tables[i], 0, NULL, 0); 1610 if (bufferSize == GDI_ERROR) { 1611 call_ensure_accessible(lf); 1612 bufferSize = GetFontData(hdc, tables[i], 0, NULL, 0); 1613 } 1614 if (bufferSize != GDI_ERROR) { 1615 stream = new SkMemoryStream(bufferSize); 1616 if (GetFontData(hdc, tables[i], 0, (void*)stream->getMemoryBase(), 1617 bufferSize)) { 1618 break; 1619 } else { 1620 delete stream; 1621 stream = NULL; 1622 } 1623 } 1624 } 1625 1626 SelectObject(hdc, savefont); 1627 DeleteObject(font); 1628 DeleteDC(hdc); 1629 1630 return stream; 1631} 1632 1633SkScalerContext* LogFontTypeface::onCreateScalerContext(const SkDescriptor* desc) const { 1634 return SkNEW_ARGS(SkScalerContext_Windows, (const_cast<LogFontTypeface*>(this), desc)); 1635} 1636 1637/** Return the closest matching typeface given either an existing family 1638 (specified by a typeface in that family) or by a familyName, and a 1639 requested style. 1640 1) If familyFace is null, use familyName. 1641 2) If familyName is null, use familyFace. 1642 3) If both are null, return the default font that best matches style 1643 This MUST not return NULL. 1644 */ 1645 1646SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace, 1647 const char familyName[], 1648 SkTypeface::Style style) { 1649 LOGFONT lf; 1650 if (NULL == familyFace && NULL == familyName) { 1651 lf = get_default_font(); 1652 } else if (familyFace) { 1653 LogFontTypeface* face = (LogFontTypeface*)familyFace; 1654 lf = face->fLogFont; 1655 } else { 1656 logfont_for_name(familyName, lf); 1657 } 1658 setStyle(&lf, style); 1659 return SkCreateTypefaceFromLOGFONT(lf); 1660} 1661 1662SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) { 1663 SkAutoTUnref<SkStream> stream(SkStream::NewFromFile(path)); 1664 return stream.get() ? CreateTypefaceFromStream(stream) : NULL; 1665} 1666 1667void LogFontTypeface::onFilterRec(SkScalerContextRec* rec) const { 1668 unsigned flagsWeDontSupport = SkScalerContext::kDevKernText_Flag | 1669 SkScalerContext::kAutohinting_Flag | 1670 SkScalerContext::kEmbeddedBitmapText_Flag | 1671 SkScalerContext::kEmbolden_Flag | 1672 SkScalerContext::kSubpixelPositioning_Flag | 1673 SkScalerContext::kLCD_BGROrder_Flag | 1674 SkScalerContext::kLCD_Vertical_Flag; 1675 rec->fFlags &= ~flagsWeDontSupport; 1676 1677 SkPaint::Hinting h = rec->getHinting(); 1678 1679 // I think we can support no-hinting, if we get hires outlines and just 1680 // use skia to rasterize into a gray-scale mask... 1681#if 0 1682 switch (h) { 1683 case SkPaint::kNo_Hinting: 1684 case SkPaint::kSlight_Hinting: 1685 h = SkPaint::kNo_Hinting; 1686 break; 1687 case SkPaint::kNormal_Hinting: 1688 case SkPaint::kFull_Hinting: 1689 h = SkPaint::kNormal_Hinting; 1690 break; 1691 default: 1692 SkDEBUGFAIL("unknown hinting"); 1693 } 1694#else 1695 h = SkPaint::kNormal_Hinting; 1696#endif 1697 rec->setHinting(h); 1698 1699// turn this off since GDI might turn A8 into BW! Need a bigger fix. 1700#if 0 1701 // Disable LCD when rotated, since GDI's output is ugly 1702 if (isLCD(*rec) && !isAxisAligned(*rec)) { 1703 rec->fMaskFormat = SkMask::kA8_Format; 1704 } 1705#endif 1706 1707 if (!fCanBeLCD && isLCD(*rec)) { 1708 rec->fMaskFormat = SkMask::kA8_Format; 1709 rec->fFlags &= ~SkScalerContext::kGenA8FromLCD_Flag; 1710 } 1711} 1712