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