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