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