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