SkFontHost_win.cpp revision 127c3be42b5f07c5ae2f87760a6855c9efecf8a8
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 10#include "SkColorFilter.h" 11#include "SkString.h" 12#include "SkEndian.h" 13#include "SkFontHost.h" 14#include "SkDescriptor.h" 15#include "SkAdvancedTypefaceMetrics.h" 16#include "SkStream.h" 17#include "SkThread.h" 18#include "SkTypeface_win.h" 19#include "SkTypefaceCache.h" 20#include "SkUtils.h" 21 22#ifdef WIN32 23#include "windows.h" 24#include "tchar.h" 25#include "Usp10.h" 26 27// always packed xxRRGGBB 28typedef uint32_t SkGdiRGB; 29 30template <typename T> T* SkTAddByteOffset(T* ptr, size_t byteOffset) { 31 return (T*)((char*)ptr + byteOffset); 32} 33 34// define this in your Makefile or .gyp to enforce AA requests 35// which GDI ignores at small sizes. This flag guarantees AA 36// for rotated text, regardless of GDI's notions. 37//#define SK_ENFORCE_ROTATED_TEXT_AA_ON_WINDOWS 38 39// client3d has to undefine this for now 40#define CAN_USE_LOGFONT_NAME 41 42static bool isLCD(const SkScalerContext::Rec& rec) { 43 return SkMask::kLCD16_Format == rec.fMaskFormat || 44 SkMask::kLCD32_Format == rec.fMaskFormat; 45} 46 47static bool bothZero(SkScalar a, SkScalar b) { 48 return 0 == a && 0 == b; 49} 50 51// returns false if there is any non-90-rotation or skew 52static bool isAxisAligned(const SkScalerContext::Rec& rec) { 53 return 0 == rec.fPreSkewX && 54 (bothZero(rec.fPost2x2[0][1], rec.fPost2x2[1][0]) || 55 bothZero(rec.fPost2x2[0][0], rec.fPost2x2[1][1])); 56} 57 58static bool needToRenderWithSkia(const SkScalerContext::Rec& rec) { 59#ifdef SK_ENFORCE_ROTATED_TEXT_AA_ON_WINDOWS 60 // What we really want to catch is when GDI will ignore the AA request and give 61 // us BW instead. Smallish rotated text is one heuristic, so this code is just 62 // an approximation. We shouldn't need to do this for larger sizes, but at those 63 // sizes, the quality difference gets less and less between our general 64 // scanconverter and GDI's. 65 if (SkMask::kA8_Format == rec.fMaskFormat && !isAxisAligned(rec)) { 66 return true; 67 } 68#endif 69 // false means allow GDI to generate the bits 70 return false; 71} 72 73using namespace skia_advanced_typeface_metrics_utils; 74 75static const uint16_t BUFFERSIZE = (16384 - 32); 76static uint8_t glyphbuf[BUFFERSIZE]; 77 78// Give 1MB font cache budget 79#define FONT_CACHE_MEMORY_BUDGET (1024 * 1024) 80 81/** 82 * Since LOGFONT wants its textsize as an int, and we support fractional sizes, 83 * and since we have a cache of LOGFONTs for our tyepfaces, we always set the 84 * lfHeight to a canonical size, and then we use the 2x2 matrix to achieve the 85 * actual requested size. 86 */ 87static const int gCanonicalTextSize = 64; 88 89static void make_canonical(LOGFONT* lf) { 90 lf->lfHeight = -gCanonicalTextSize; 91 lf->lfQuality = CLEARTYPE_QUALITY;//PROOF_QUALITY; 92 lf->lfCharSet = DEFAULT_CHARSET; 93// lf->lfClipPrecision = 64; 94} 95 96static SkTypeface::Style getStyle(const LOGFONT& lf) { 97 unsigned style = 0; 98 if (lf.lfWeight >= FW_BOLD) { 99 style |= SkTypeface::kBold; 100 } 101 if (lf.lfItalic) { 102 style |= SkTypeface::kItalic; 103 } 104 return (SkTypeface::Style)style; 105} 106 107static void setStyle(LOGFONT* lf, SkTypeface::Style style) { 108 lf->lfWeight = (style & SkTypeface::kBold) != 0 ? FW_BOLD : FW_NORMAL ; 109 lf->lfItalic = ((style & SkTypeface::kItalic) != 0); 110} 111 112static inline FIXED SkFixedToFIXED(SkFixed x) { 113 return *(FIXED*)(&x); 114} 115 116static inline FIXED SkScalarToFIXED(SkScalar x) { 117 return SkFixedToFIXED(SkScalarToFixed(x)); 118} 119 120static unsigned calculateGlyphCount(HDC hdc) { 121 // The 'maxp' table stores the number of glyphs at offset 4, in 2 bytes. 122 const DWORD maxpTag = 123 SkEndian_SwapBE32(SkSetFourByteTag('m', 'a', 'x', 'p')); 124 uint16_t glyphs; 125 if (GetFontData(hdc, maxpTag, 4, &glyphs, sizeof(glyphs)) != GDI_ERROR) { 126 return SkEndian_SwapBE16(glyphs); 127 } 128 129 // Binary search for glyph count. 130 static const MAT2 mat2 = {{0, 1}, {0, 0}, {0, 0}, {0, 1}}; 131 int32_t max = SK_MaxU16 + 1; 132 int32_t min = 0; 133 GLYPHMETRICS gm; 134 while (min < max) { 135 int32_t mid = min + ((max - min) / 2); 136 if (GetGlyphOutlineW(hdc, mid, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, 137 NULL, &mat2) == GDI_ERROR) { 138 max = mid; 139 } else { 140 min = mid + 1; 141 } 142 } 143 SkASSERT(min == max); 144 return min; 145} 146 147static SkTypeface::Style GetFontStyle(const LOGFONT& lf) { 148 int style = SkTypeface::kNormal; 149 if (lf.lfWeight == FW_SEMIBOLD || lf.lfWeight == FW_DEMIBOLD || lf.lfWeight == FW_BOLD) 150 style |= SkTypeface::kBold; 151 if (lf.lfItalic) 152 style |= SkTypeface::kItalic; 153 154 return (SkTypeface::Style)style; 155} 156 157class LogFontTypeface : public SkTypeface { 158public: 159 LogFontTypeface(SkTypeface::Style style, SkFontID fontID, const LOGFONT& lf) : 160 SkTypeface(style, fontID, false), fLogFont(lf) {} 161 162 LOGFONT fLogFont; 163 164 static LogFontTypeface* Create(const LOGFONT& lf) { 165 SkTypeface::Style style = GetFontStyle(lf); 166 SkFontID fontID = SkTypefaceCache::NewFontID(); 167 return new LogFontTypeface(style, fontID, lf); 168 } 169}; 170 171static const LOGFONT& get_default_font() { 172 static LOGFONT gDefaultFont; 173 return gDefaultFont; 174} 175 176static bool FindByLogFont(SkTypeface* face, SkTypeface::Style requestedStyle, void* ctx) { 177 LogFontTypeface* lface = reinterpret_cast<LogFontTypeface*>(face); 178 const LOGFONT* lf = reinterpret_cast<const LOGFONT*>(ctx); 179 180 return getStyle(lface->fLogFont) == requestedStyle && 181 !memcmp(&lface->fLogFont, lf, sizeof(LOGFONT)); 182} 183 184/** 185 * This guy is public. It first searches the cache, and if a match is not found, 186 * it creates a new face. 187 */ 188SkTypeface* SkCreateTypefaceFromLOGFONT(const LOGFONT& origLF) { 189 LOGFONT lf = origLF; 190 make_canonical(&lf); 191 SkTypeface* face = SkTypefaceCache::FindByProc(FindByLogFont, &lf); 192 if (face) { 193 face->ref(); 194 } else { 195 face = LogFontTypeface::Create(lf); 196 SkTypefaceCache::Add(face, getStyle(lf)); 197 } 198 return face; 199} 200 201/** 202 * This guy is public 203 */ 204void SkLOGFONTFromTypeface(const SkTypeface* face, LOGFONT* lf) { 205 if (NULL == face) { 206 *lf = get_default_font(); 207 } else { 208 *lf = ((const LogFontTypeface*)face)->fLogFont; 209 } 210} 211 212SkFontID SkFontHost::NextLogicalFont(SkFontID currFontID, SkFontID origFontID) { 213 // Zero means that we don't have any fallback fonts for this fontID. 214 // This function is implemented on Android, but doesn't have much 215 // meaning here. 216 return 0; 217} 218 219static void GetLogFontByID(SkFontID fontID, LOGFONT* lf) { 220 LogFontTypeface* face = (LogFontTypeface*)SkTypefaceCache::FindByID(fontID); 221 if (face) { 222 *lf = face->fLogFont; 223 } else { 224 sk_bzero(lf, sizeof(LOGFONT)); 225 } 226} 227 228// Construct Glyph to Unicode table. 229// Unicode code points that require conjugate pairs in utf16 are not 230// supported. 231// TODO(arthurhsu): Add support for conjugate pairs. It looks like that may 232// require parsing the TTF cmap table (platform 4, encoding 12) directly instead 233// of calling GetFontUnicodeRange(). 234static void populate_glyph_to_unicode(HDC fontHdc, const unsigned glyphCount, 235 SkTDArray<SkUnichar>* glyphToUnicode) { 236 DWORD glyphSetBufferSize = GetFontUnicodeRanges(fontHdc, NULL); 237 if (!glyphSetBufferSize) { 238 return; 239 } 240 241 SkAutoTDeleteArray<BYTE> glyphSetBuffer(new BYTE[glyphSetBufferSize]); 242 GLYPHSET* glyphSet = 243 reinterpret_cast<LPGLYPHSET>(glyphSetBuffer.get()); 244 if (GetFontUnicodeRanges(fontHdc, glyphSet) != glyphSetBufferSize) { 245 return; 246 } 247 248 glyphToUnicode->setCount(glyphCount); 249 memset(glyphToUnicode->begin(), 0, glyphCount * sizeof(SkUnichar)); 250 for (DWORD i = 0; i < glyphSet->cRanges; ++i) { 251 // There is no guarantee that within a Unicode range, the corresponding 252 // glyph id in a font file are continuous. So, even if we have ranges, 253 // we can't just use the first and last entry of the range to compute 254 // result. We need to enumerate them one by one. 255 int count = glyphSet->ranges[i].cGlyphs; 256 SkAutoTArray<WCHAR> chars(count + 1); 257 chars[count] = 0; // termintate string 258 SkAutoTArray<WORD> glyph(count); 259 for (USHORT j = 0; j < count; ++j) { 260 chars[j] = glyphSet->ranges[i].wcLow + j; 261 } 262 GetGlyphIndicesW(fontHdc, chars.get(), count, glyph.get(), 263 GGI_MARK_NONEXISTING_GLYPHS); 264 // If the glyph ID is valid, and the glyph is not mapped, then we will 265 // fill in the char id into the vector. If the glyph is mapped already, 266 // skip it. 267 // TODO(arthurhsu): better improve this. e.g. Get all used char ids from 268 // font cache, then generate this mapping table from there. It's 269 // unlikely to have collisions since glyph reuse happens mostly for 270 // different Unicode pages. 271 for (USHORT j = 0; j < count; ++j) { 272 if (glyph[j] != 0xffff && glyph[j] < glyphCount && 273 (*glyphToUnicode)[glyph[j]] == 0) { 274 (*glyphToUnicode)[glyph[j]] = chars[j]; 275 } 276 } 277 } 278} 279 280////////////////////////////////////////////////////////////////////////////////////// 281 282static int alignTo32(int n) { 283 return (n + 31) & ~31; 284} 285 286struct MyBitmapInfo : public BITMAPINFO { 287 RGBQUAD fMoreSpaceForColors[1]; 288}; 289 290class HDCOffscreen { 291public: 292 HDCOffscreen() { 293 fFont = 0; 294 fDC = 0; 295 fBM = 0; 296 fBits = NULL; 297 fWidth = fHeight = 0; 298 fIsBW = false; 299 fColor = kInvalid_Color; 300 } 301 302 ~HDCOffscreen() { 303 if (fDC) { 304 DeleteDC(fDC); 305 } 306 if (fBM) { 307 DeleteObject(fBM); 308 } 309 } 310 311 void init(HFONT font, const XFORM& xform) { 312 fFont = font; 313 fXform = xform; 314 } 315 316 const void* draw(const SkGlyph&, bool isBW, SkGdiRGB fgColor, 317 size_t* srcRBPtr); 318 319private: 320 HDC fDC; 321 HBITMAP fBM; 322 HFONT fFont; 323 XFORM fXform; 324 void* fBits; // points into fBM 325 COLORREF fColor; 326 int fWidth; 327 int fHeight; 328 bool fIsBW; 329 330 enum { 331 // will always trigger us to reset the color, since we 332 // should only store 0 or 0x00FFFFFF or gray (0x007F7F7F) 333 kInvalid_Color = 12345 334 }; 335}; 336 337const void* HDCOffscreen::draw(const SkGlyph& glyph, bool isBW, 338 SkGdiRGB fgColor, size_t* srcRBPtr) { 339 if (0 == fDC) { 340 fDC = CreateCompatibleDC(0); 341 if (0 == fDC) { 342 return NULL; 343 } 344 SetGraphicsMode(fDC, GM_ADVANCED); 345 SetBkMode(fDC, TRANSPARENT); 346 SetTextAlign(fDC, TA_LEFT | TA_BASELINE); 347 SelectObject(fDC, fFont); 348 fColor = kInvalid_Color; 349 } 350 351 if (fBM && (fIsBW != isBW || fWidth < glyph.fWidth || fHeight < glyph.fHeight)) { 352 DeleteObject(fBM); 353 fBM = 0; 354 } 355 fIsBW = isBW; 356 357 COLORREF color = fgColor; 358 if (fIsBW) { 359 color = 0xFFFFFF; 360 } 361 if (fColor != color) { 362 fColor = color; 363 COLORREF prev = SetTextColor(fDC, color); 364 SkASSERT(prev != CLR_INVALID); 365 } 366 367 fWidth = SkMax32(fWidth, glyph.fWidth); 368 fHeight = SkMax32(fHeight, glyph.fHeight); 369 370 int biWidth = isBW ? alignTo32(fWidth) : fWidth; 371 372 if (0 == fBM) { 373 MyBitmapInfo info; 374 sk_bzero(&info, sizeof(info)); 375 if (isBW) { 376 RGBQUAD blackQuad = { 0, 0, 0, 0 }; 377 RGBQUAD whiteQuad = { 0xFF, 0xFF, 0xFF, 0 }; 378 info.bmiColors[0] = blackQuad; 379 info.bmiColors[1] = whiteQuad; 380 } 381 info.bmiHeader.biSize = sizeof(info.bmiHeader); 382 info.bmiHeader.biWidth = biWidth; 383 info.bmiHeader.biHeight = fHeight; 384 info.bmiHeader.biPlanes = 1; 385 info.bmiHeader.biBitCount = isBW ? 1 : 32; 386 info.bmiHeader.biCompression = BI_RGB; 387 if (isBW) { 388 info.bmiHeader.biClrUsed = 2; 389 } 390 fBM = CreateDIBSection(fDC, &info, DIB_RGB_COLORS, &fBits, 0, 0); 391 if (0 == fBM) { 392 return NULL; 393 } 394 SelectObject(fDC, fBM); 395 } 396 397 // erase 398 size_t srcRB = isBW ? (biWidth >> 3) : (fWidth << 2); 399 size_t size = fHeight * srcRB; 400 unsigned bg = (0 == color) ? 0xFF : 0; 401 memset(fBits, bg, size); 402 403 XFORM xform = fXform; 404 xform.eDx = (float)-glyph.fLeft; 405 xform.eDy = (float)-glyph.fTop; 406 SetWorldTransform(fDC, &xform); 407 408 uint16_t glyphID = glyph.getGlyphID(); 409#if defined(UNICODE) 410 ExtTextOut(fDC, 0, 0, ETO_GLYPH_INDEX, NULL, (LPCWSTR)&glyphID, 1, NULL); 411#else 412 ExtTextOut(fDC, 0, 0, ETO_GLYPH_INDEX, NULL, (LPCSTR)&glyphID, 1, NULL); 413#endif 414 GdiFlush(); 415 416 *srcRBPtr = srcRB; 417 // offset to the start of the image 418 return (const char*)fBits + (fHeight - glyph.fHeight) * srcRB; 419} 420 421////////////////////////////////////////////////////////////////////////////////////// 422 423class SkScalerContext_Windows : public SkScalerContext { 424public: 425 SkScalerContext_Windows(const SkDescriptor* desc); 426 virtual ~SkScalerContext_Windows(); 427 428protected: 429 virtual unsigned generateGlyphCount(); 430 virtual uint16_t generateCharToGlyph(SkUnichar uni); 431 virtual void generateAdvance(SkGlyph* glyph); 432 virtual void generateMetrics(SkGlyph* glyph); 433 virtual void generateImage(const SkGlyph& glyph); 434 virtual void generatePath(const SkGlyph& glyph, SkPath* path); 435 virtual void generateFontMetrics(SkPaint::FontMetrics* mX, SkPaint::FontMetrics* mY); 436 437private: 438 HDCOffscreen fOffscreen; 439 SkScalar fScale; // to get from canonical size to real size 440 MAT2 fMat22; 441 XFORM fXform; 442 HDC fDDC; 443 HFONT fSavefont; 444 HFONT fFont; 445 SCRIPT_CACHE fSC; 446 int fGlyphCount; 447 448 HFONT fHiResFont; 449 MAT2 fMat22Identity; 450 SkMatrix fHiResMatrix; 451}; 452 453static float mul2float(SkScalar a, SkScalar b) { 454 return SkScalarToFloat(SkScalarMul(a, b)); 455} 456 457static FIXED float2FIXED(float x) { 458 return SkFixedToFIXED(SkFloatToFixed(x)); 459} 460 461static SkMutex gFTMutex; 462 463#define HIRES_TEXTSIZE 2048 464#define HIRES_SHIFT 11 465static inline SkFixed HiResToFixed(int value) { 466 return value << (16 - HIRES_SHIFT); 467} 468 469static bool needHiResMetrics(const SkScalar mat[2][2]) { 470 return mat[1][0] || mat[0][1]; 471} 472 473static BYTE compute_quality(const SkScalerContext::Rec& rec) { 474 switch (rec.fMaskFormat) { 475 case SkMask::kBW_Format: 476 return NONANTIALIASED_QUALITY; 477 case SkMask::kLCD16_Format: 478 case SkMask::kLCD32_Format: 479 return CLEARTYPE_QUALITY; 480 default: 481 // here we just want AA, but we may have to force the issue 482 // since sometimes GDI will instead really give us BW 483 // (for some fonts and some sizes) 484 if (rec.fFlags & SkScalerContext::kForceAA_Flag) { 485 return CLEARTYPE_QUALITY; 486 } else { 487 return ANTIALIASED_QUALITY; 488 } 489 break; 490 } 491} 492 493SkScalerContext_Windows::SkScalerContext_Windows(const SkDescriptor* desc) 494 : SkScalerContext(desc), fDDC(0), fFont(0), fSavefont(0), fSC(0) 495 , fGlyphCount(-1) { 496 SkAutoMutexAcquire ac(gFTMutex); 497 498 fScale = fRec.fTextSize / gCanonicalTextSize; 499 500 fXform.eM11 = mul2float(fScale, fRec.fPost2x2[0][0]); 501 fXform.eM12 = mul2float(fScale, fRec.fPost2x2[1][0]); 502 fXform.eM21 = mul2float(fScale, fRec.fPost2x2[0][1]); 503 fXform.eM22 = mul2float(fScale, fRec.fPost2x2[1][1]); 504 fXform.eDx = 0; 505 fXform.eDy = 0; 506 507 fMat22.eM11 = float2FIXED(fXform.eM11); 508 fMat22.eM12 = float2FIXED(fXform.eM12); 509 fMat22.eM21 = float2FIXED(-fXform.eM21); 510 fMat22.eM22 = float2FIXED(-fXform.eM22); 511 512 fDDC = ::CreateCompatibleDC(NULL); 513 SetGraphicsMode(fDDC, GM_ADVANCED); 514 SetBkMode(fDDC, TRANSPARENT); 515 516 // Scaling by the DPI is inconsistent with how Skia draws elsewhere 517 //SkScalar height = -(fRec.fTextSize * GetDeviceCaps(ddc, LOGPIXELSY) / 72); 518 LOGFONT lf; 519 GetLogFontByID(fRec.fFontID, &lf); 520 lf.lfHeight = -gCanonicalTextSize; 521 lf.lfQuality = compute_quality(fRec); 522 fFont = CreateFontIndirect(&lf); 523 524 // if we're rotated, or want fractional widths, create a hires font 525 fHiResFont = 0; 526 if (needHiResMetrics(fRec.fPost2x2) || (fRec.fFlags & kSubpixelPositioning_Flag)) { 527 lf.lfHeight = -HIRES_TEXTSIZE; 528 fHiResFont = CreateFontIndirect(&lf); 529 530 fMat22Identity.eM11 = fMat22Identity.eM22 = SkFixedToFIXED(SK_Fixed1); 531 fMat22Identity.eM12 = fMat22Identity.eM21 = SkFixedToFIXED(0); 532 533 // construct a matrix to go from HIRES logical units to our device units 534 fRec.getSingleMatrix(&fHiResMatrix); 535 SkScalar scale = SkScalarInvert(SkIntToScalar(HIRES_TEXTSIZE)); 536 fHiResMatrix.preScale(scale, scale); 537 } 538 fSavefont = (HFONT)SelectObject(fDDC, fFont); 539 540 if (needToRenderWithSkia(fRec)) { 541 this->forceGenerateImageFromPath(); 542 } 543 544 fOffscreen.init(fFont, fXform); 545} 546 547SkScalerContext_Windows::~SkScalerContext_Windows() { 548 if (fDDC) { 549 ::SelectObject(fDDC, fSavefont); 550 ::DeleteDC(fDDC); 551 } 552 if (fFont) { 553 ::DeleteObject(fFont); 554 } 555 if (fHiResFont) { 556 ::DeleteObject(fHiResFont); 557 } 558 if (fSC) { 559 ::ScriptFreeCache(&fSC); 560 } 561} 562 563unsigned SkScalerContext_Windows::generateGlyphCount() { 564 if (fGlyphCount < 0) { 565 fGlyphCount = calculateGlyphCount(fDDC); 566 } 567 return fGlyphCount; 568} 569 570uint16_t SkScalerContext_Windows::generateCharToGlyph(SkUnichar uni) { 571 uint16_t index = 0; 572 WCHAR c[2]; 573 // TODO(ctguil): Support characters that generate more than one glyph. 574 if (SkUTF16_FromUnichar(uni, (uint16_t*)c) == 1) { 575 // Type1 fonts fail with uniscribe API. Use GetGlyphIndices for plane 0. 576 SkAssertResult(GetGlyphIndicesW(fDDC, c, 1, &index, 0)); 577 } else { 578 // Use uniscribe to detemine glyph index for non-BMP characters. 579 // Need to add extra item to SCRIPT_ITEM to work around a bug in older 580 // windows versions. https://bugzilla.mozilla.org/show_bug.cgi?id=366643 581 SCRIPT_ITEM si[2 + 1]; 582 int items; 583 SkAssertResult( 584 SUCCEEDED(ScriptItemize(c, 2, 2, NULL, NULL, si, &items))); 585 586 WORD log[2]; 587 SCRIPT_VISATTR vsa; 588 int glyphs; 589 SkAssertResult(SUCCEEDED(ScriptShape( 590 fDDC, &fSC, c, 2, 1, &si[0].a, &index, log, &vsa, &glyphs))); 591 } 592 return index; 593} 594 595void SkScalerContext_Windows::generateAdvance(SkGlyph* glyph) { 596 this->generateMetrics(glyph); 597} 598 599void SkScalerContext_Windows::generateMetrics(SkGlyph* glyph) { 600 601 SkASSERT(fDDC); 602 603 GLYPHMETRICS gm; 604 sk_bzero(&gm, sizeof(gm)); 605 606 glyph->fRsbDelta = 0; 607 glyph->fLsbDelta = 0; 608 609 // Note: need to use GGO_GRAY8_BITMAP instead of GGO_METRICS because GGO_METRICS returns a smaller 610 // BlackBlox; we need the bigger one in case we need the image. fAdvance is the same. 611 uint32_t ret = GetGlyphOutlineW(fDDC, glyph->getGlyphID(0), GGO_GRAY8_BITMAP | GGO_GLYPH_INDEX, &gm, 0, NULL, &fMat22); 612 613 if (GDI_ERROR != ret) { 614 if (ret == 0) { 615 // for white space, ret is zero and gmBlackBoxX, gmBlackBoxY are 1 incorrectly! 616 gm.gmBlackBoxX = gm.gmBlackBoxY = 0; 617 } 618 glyph->fWidth = gm.gmBlackBoxX; 619 glyph->fHeight = gm.gmBlackBoxY; 620 glyph->fTop = SkToS16(gm.gmptGlyphOrigin.y - gm.gmBlackBoxY); 621 glyph->fLeft = SkToS16(gm.gmptGlyphOrigin.x); 622 glyph->fAdvanceX = SkIntToFixed(gm.gmCellIncX); 623 glyph->fAdvanceY = -SkIntToFixed(gm.gmCellIncY); 624 625 // we outset in all dimensions, since the image may bleed outside 626 // of the computed bounds returned by GetGlyphOutline. 627 // This was deduced by trial and error for small text (e.g. 8pt), so there 628 // maybe a more precise way to make this adjustment... 629 // 630 // This test shows us clipping the tops of some of the CJK fonts unless we 631 // increase the top of the box by 2, hence the height by 4. This seems to 632 // correspond to an embedded bitmap font, but not sure. 633 // LayoutTests/fast/text/backslash-to-yen-sign-euc.html 634 // 635 if (glyph->fWidth) { // don't outset an empty glyph 636 glyph->fWidth += 4; 637 glyph->fHeight += 4; 638 glyph->fTop -= 2; 639 glyph->fLeft -= 2; 640 } 641 642 if (fHiResFont) { 643 SelectObject(fDDC, fHiResFont); 644 sk_bzero(&gm, sizeof(gm)); 645 ret = GetGlyphOutlineW(fDDC, glyph->getGlyphID(0), GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &fMat22Identity); 646 if (GDI_ERROR != ret) { 647 SkPoint advance; 648 fHiResMatrix.mapXY(SkIntToScalar(gm.gmCellIncX), SkIntToScalar(gm.gmCellIncY), &advance); 649 glyph->fAdvanceX = SkScalarToFixed(advance.fX); 650 glyph->fAdvanceY = SkScalarToFixed(advance.fY); 651 } 652 SelectObject(fDDC, fFont); 653 } 654 } else { 655 glyph->fWidth = 0; 656 } 657} 658 659void SkScalerContext_Windows::generateFontMetrics(SkPaint::FontMetrics* mx, SkPaint::FontMetrics* my) { 660// Note: This code was borrowed from generateLineHeight, which has a note 661// stating that it may be incorrect. 662 if (!(mx || my)) 663 return; 664 665 SkASSERT(fDDC); 666 667 OUTLINETEXTMETRIC otm; 668 669 uint32_t ret = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm); 670 if (sizeof(otm) != ret) { 671 return; 672 } 673 674 if (mx) { 675 mx->fTop = -fScale * otm.otmTextMetrics.tmAscent; 676 mx->fAscent = -fScale * otm.otmAscent; 677 mx->fDescent = -fScale * otm.otmDescent; 678 mx->fBottom = fScale * otm.otmTextMetrics.tmDescent; 679 mx->fLeading = fScale * (otm.otmTextMetrics.tmInternalLeading 680 + otm.otmTextMetrics.tmExternalLeading); 681 } 682 683 if (my) { 684 my->fTop = -fScale * otm.otmTextMetrics.tmAscent; 685 my->fAscent = -fScale * otm.otmAscent; 686 my->fDescent = -fScale * otm.otmDescent; 687 my->fBottom = fScale * otm.otmTextMetrics.tmDescent; 688 my->fLeading = fScale * (otm.otmTextMetrics.tmInternalLeading 689 + otm.otmTextMetrics.tmExternalLeading); 690 } 691} 692 693//////////////////////////////////////////////////////////////////////////////////////// 694 695static void build_power_table(uint8_t table[], float ee) { 696 for (int i = 0; i < 256; i++) { 697 float x = i / 255.f; 698 x = powf(x, ee); 699 int xx = SkScalarRound(SkFloatToScalar(x * 255)); 700 table[i] = SkToU8(xx); 701 } 702} 703 704// This will invert the gamma applied by GDI, so we can sort-of get linear values. 705// Needed when we draw non-black, non-white text, and don't know how to bias it. 706static const uint8_t* getInverseGammaTable() { 707 static bool gInited; 708 static uint8_t gTable[256]; 709 if (!gInited) { 710 UINT level = 0; 711 if (!SystemParametersInfo(SPI_GETFONTSMOOTHINGCONTRAST, 0, &level, 0) || !level) { 712 // can't get the data, so use a default 713 level = 1400; 714 } 715 build_power_table(gTable, level / 1000.0f); 716 gInited = true; 717 } 718 return gTable; 719} 720 721#include "SkColorPriv.h" 722 723// gdi's bitmap is upside-down, so we reverse dst walking in Y 724// whenever we copy it into skia's buffer 725 726static inline uint8_t rgb_to_a8(SkGdiRGB rgb) { 727 int r = (rgb >> 16) & 0xFF; 728 int g = (rgb >> 8) & 0xFF; 729 int b = (rgb >> 0) & 0xFF; 730 731 return (r * 2 + g * 5 + b) >> 3; // luminance 732} 733 734static inline uint16_t rgb_to_lcd16(SkGdiRGB rgb) { 735 int r = (rgb >> 16) & 0xFF; 736 int g = (rgb >> 8) & 0xFF; 737 int b = (rgb >> 0) & 0xFF; 738 return SkPackRGB16(SkR32ToR16(r), SkG32ToG16(g), SkB32ToB16(b)); 739} 740 741static inline SkPMColor rgb_to_lcd32(SkGdiRGB rgb) { 742 int r = (rgb >> 16) & 0xFF; 743 int g = (rgb >> 8) & 0xFF; 744 int b = (rgb >> 0) & 0xFF; 745 int a = SkMax32(r, SkMax32(g, b)); 746 return SkPackARGB32(a, r, g, b); 747} 748 749// Is this GDI color neither black nor white? If so, we have to keep this 750// image as is, rather than smashing it down to a BW mask. 751// 752// returns int instead of bool, since we don't want/have to pay to convert 753// the zero/non-zero value into a bool 754static int is_not_black_or_white(SkGdiRGB c) { 755 // same as (but faster than) 756 // c &= 0x00FFFFFF; 757 // return 0 == c || 0x00FFFFFF == c; 758 return (c + (c & 1)) & 0x00FFFFFF; 759} 760 761static bool is_rgb_really_bw(const SkGdiRGB* src, int width, int height, int srcRB) { 762 for (int y = 0; y < height; ++y) { 763 for (int x = 0; x < width; ++x) { 764 if (is_not_black_or_white(src[x])) { 765 return false; 766 } 767 } 768 src = SkTAddByteOffset(src, srcRB); 769 } 770 return true; 771} 772 773static void rgb_to_bw(const SkGdiRGB* SK_RESTRICT src, size_t srcRB, 774 const SkGlyph& glyph, int32_t xorMask) { 775 const int width = glyph.fWidth; 776 const size_t dstRB = (width + 7) >> 3; 777 uint8_t* SK_RESTRICT dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB); 778 779 int byteCount = width >> 3; 780 int bitCount = width & 7; 781 782 // adjust srcRB to skip the values in our byteCount loop, 783 // since we increment src locally there 784 srcRB -= byteCount * 8 * sizeof(SkGdiRGB); 785 786 for (int y = 0; y < glyph.fHeight; ++y) { 787 if (byteCount > 0) { 788 for (int i = 0; i < byteCount; ++i) { 789 unsigned byte = 0; 790 byte |= (src[0] ^ xorMask) & (1 << 7); 791 byte |= (src[1] ^ xorMask) & (1 << 6); 792 byte |= (src[2] ^ xorMask) & (1 << 5); 793 byte |= (src[3] ^ xorMask) & (1 << 4); 794 byte |= (src[4] ^ xorMask) & (1 << 3); 795 byte |= (src[5] ^ xorMask) & (1 << 2); 796 byte |= (src[6] ^ xorMask) & (1 << 1); 797 byte |= (src[7] ^ xorMask) & (1 << 0); 798 dst[i] = byte; 799 src += 8; 800 } 801 } 802 if (bitCount > 0) { 803 unsigned byte = 0; 804 unsigned mask = 0x80; 805 for (int i = 0; i < bitCount; i++) { 806 byte |= (src[i] ^ xorMask) & mask; 807 mask >>= 1; 808 } 809 dst[byteCount] = byte; 810 } 811 src = SkTAddByteOffset(src, srcRB); 812 dst -= dstRB; 813 } 814} 815 816static void rgb_to_a8(const SkGdiRGB* SK_RESTRICT src, size_t srcRB, 817 const SkGlyph& glyph, int32_t xorMask) { 818 const size_t dstRB = glyph.rowBytes(); 819 const int width = glyph.fWidth; 820 uint8_t* SK_RESTRICT dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB); 821 822 for (int y = 0; y < glyph.fHeight; y++) { 823 for (int i = 0; i < width; i++) { 824 dst[i] = rgb_to_a8(src[i] ^ xorMask); 825 } 826 src = SkTAddByteOffset(src, srcRB); 827 dst -= dstRB; 828 } 829} 830 831static void rgb_to_lcd16(const SkGdiRGB* SK_RESTRICT src, size_t srcRB, 832 const SkGlyph& glyph, int32_t xorMask) { 833 const size_t dstRB = glyph.rowBytes(); 834 const int width = glyph.fWidth; 835 uint16_t* SK_RESTRICT dst = (uint16_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB); 836 837 for (int y = 0; y < glyph.fHeight; y++) { 838 for (int i = 0; i < width; i++) { 839 dst[i] = rgb_to_lcd16(src[i] ^ xorMask); 840 } 841 src = SkTAddByteOffset(src, srcRB); 842 dst = (uint16_t*)((char*)dst - dstRB); 843 } 844} 845 846static void rgb_to_lcd32(const SkGdiRGB* SK_RESTRICT src, size_t srcRB, 847 const SkGlyph& glyph, int32_t xorMask) { 848 const size_t dstRB = glyph.rowBytes(); 849 const int width = glyph.fWidth; 850 SkPMColor* SK_RESTRICT dst = (SkPMColor*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB); 851 852 for (int y = 0; y < glyph.fHeight; y++) { 853 for (int i = 0; i < width; i++) { 854 dst[i] = rgb_to_lcd32(src[i] ^ xorMask); 855 } 856 src = SkTAddByteOffset(src, srcRB); 857 dst = (SkPMColor*)((char*)dst - dstRB); 858 } 859} 860 861static inline unsigned clamp255(unsigned x) { 862 SkASSERT(x <= 256); 863 return x - (x >> 8); 864} 865 866void SkScalerContext_Windows::generateImage(const SkGlyph& glyph) { 867 SkAutoMutexAcquire ac(gFTMutex); 868 869 SkASSERT(fDDC); 870 871 const bool isBW = SkMask::kBW_Format == fRec.fMaskFormat; 872 const bool isAA = !isLCD(fRec); 873 874 bool isWhite = SkToBool(fRec.fFlags & SkScalerContext::kGammaForWhite_Flag); 875 bool isBlack = SkToBool(fRec.fFlags & SkScalerContext::kGammaForBlack_Flag); 876 SkASSERT(!(isWhite && isBlack)); 877 SkASSERT(!isBW || (!isWhite && !isBlack)); 878 879 SkGdiRGB fgColor; 880 uint32_t rgbXOR; 881 const uint8_t* table = NULL; 882 if (isBW || isWhite) { 883 fgColor = 0x00FFFFFF; 884 rgbXOR = 0; 885 } else if (isBlack) { 886 fgColor = 0; 887 rgbXOR = ~0; 888 } else { 889 table = getInverseGammaTable(); 890 fgColor = 0x00FFFFFF; 891 rgbXOR = 0; 892 } 893 894 size_t srcRB; 895 const void* bits = fOffscreen.draw(glyph, isBW, fgColor, &srcRB); 896 if (!bits) { 897 sk_bzero(glyph.fImage, glyph.computeImageSize()); 898 return; 899 } 900 901 if (table) { 902 SkGdiRGB* addr = (SkGdiRGB*)bits; 903 for (int y = 0; y < glyph.fHeight; ++y) { 904 for (int x = 0; x < glyph.fWidth; ++x) { 905 int r = (addr[x] >> 16) & 0xFF; 906 int g = (addr[x] >> 8) & 0xFF; 907 int b = (addr[x] >> 0) & 0xFF; 908 addr[x] = (table[r] << 16) | (table[g] << 8) | table[b]; 909 } 910 addr = SkTAddByteOffset(addr, srcRB); 911 } 912 } 913 914 int width = glyph.fWidth; 915 size_t dstRB = glyph.rowBytes(); 916 if (isBW) { 917 const uint8_t* src = (const uint8_t*)bits; 918 uint8_t* dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB); 919 for (int y = 0; y < glyph.fHeight; y++) { 920 memcpy(dst, src, dstRB); 921 src += srcRB; 922 dst -= dstRB; 923 } 924 } else if (isAA) { 925 // since the caller may require A8 for maskfilters, we can't check for BW 926 // ... until we have the caller tell us that explicitly 927 const SkGdiRGB* src = (const SkGdiRGB*)bits; 928 rgb_to_a8(src, srcRB, glyph, rgbXOR); 929 } else { // LCD16 930 const SkGdiRGB* src = (const SkGdiRGB*)bits; 931 if (is_rgb_really_bw(src, width, glyph.fHeight, srcRB)) { 932 rgb_to_bw(src, srcRB, glyph, rgbXOR); 933 ((SkGlyph*)&glyph)->fMaskFormat = SkMask::kBW_Format; 934 } else { 935 if (SkMask::kLCD16_Format == glyph.fMaskFormat) { 936 rgb_to_lcd16(src, srcRB, glyph, rgbXOR); 937 } else { 938 SkASSERT(SkMask::kLCD32_Format == glyph.fMaskFormat); 939 rgb_to_lcd32(src, srcRB, glyph, rgbXOR); 940 } 941 } 942 } 943} 944 945void SkScalerContext_Windows::generatePath(const SkGlyph& glyph, SkPath* path) { 946 947 SkAutoMutexAcquire ac(gFTMutex); 948 949 SkASSERT(&glyph && path); 950 SkASSERT(fDDC); 951 952 path->reset(); 953 954#if 0 955 char buf[1024]; 956 sprintf(buf, "generatePath: id:%d, w=%d, h=%d, font:%s,fh:%d\n", glyph.fID, glyph.fWidth, glyph.fHeight, lf.lfFaceName, lf.lfHeight); 957 OutputDebugString(buf); 958#endif 959 960 GLYPHMETRICS gm; 961 uint32_t total_size = GetGlyphOutlineW(fDDC, glyph.fID, GGO_NATIVE | GGO_GLYPH_INDEX, &gm, BUFFERSIZE, glyphbuf, &fMat22); 962 963 if (GDI_ERROR != total_size) { 964 965 const uint8_t* cur_glyph = glyphbuf; 966 const uint8_t* end_glyph = glyphbuf + total_size; 967 968 while(cur_glyph < end_glyph) { 969 const TTPOLYGONHEADER* th = (TTPOLYGONHEADER*)cur_glyph; 970 971 const uint8_t* end_poly = cur_glyph + th->cb; 972 const uint8_t* cur_poly = cur_glyph + sizeof(TTPOLYGONHEADER); 973 974 path->moveTo(SkFixedToScalar(*(SkFixed*)(&th->pfxStart.x)), SkFixedToScalar(*(SkFixed*)(&th->pfxStart.y))); 975 976 while(cur_poly < end_poly) { 977 const TTPOLYCURVE* pc = (const TTPOLYCURVE*)cur_poly; 978 979 if (pc->wType == TT_PRIM_LINE) { 980 for (uint16_t i = 0; i < pc->cpfx; i++) { 981 path->lineTo(SkFixedToScalar(*(SkFixed*)(&pc->apfx[i].x)), SkFixedToScalar(*(SkFixed*)(&pc->apfx[i].y))); 982 } 983 } 984 985 if (pc->wType == TT_PRIM_QSPLINE) { 986 for (uint16_t u = 0; u < pc->cpfx - 1; u++) { // Walk through points in spline 987 POINTFX pnt_b = pc->apfx[u]; // B is always the current point 988 POINTFX pnt_c = pc->apfx[u+1]; 989 990 if (u < pc->cpfx - 2) { // If not on last spline, compute C 991 pnt_c.x = SkFixedToFIXED(SkFixedAve(*(SkFixed*)(&pnt_b.x), *(SkFixed*)(&pnt_c.x))); 992 pnt_c.y = SkFixedToFIXED(SkFixedAve(*(SkFixed*)(&pnt_b.y), *(SkFixed*)(&pnt_c.y))); 993 } 994 995 path->quadTo(SkFixedToScalar(*(SkFixed*)(&pnt_b.x)), SkFixedToScalar(*(SkFixed*)(&pnt_b.y)), SkFixedToScalar(*(SkFixed*)(&pnt_c.x)), SkFixedToScalar(*(SkFixed*)(&pnt_c.y))); 996 } 997 } 998 cur_poly += sizeof(uint16_t) * 2 + sizeof(POINTFX) * pc->cpfx; 999 } 1000 cur_glyph += th->cb; 1001 path->close(); 1002 } 1003 } 1004 else { 1005 SkASSERT(false); 1006 } 1007 //char buf[1024]; 1008 //sprintf(buf, "generatePath: count:%d\n", count); 1009 //OutputDebugString(buf); 1010} 1011 1012void SkFontHost::Serialize(const SkTypeface* face, SkWStream* stream) { 1013 SkASSERT(!"SkFontHost::Serialize unimplemented"); 1014} 1015 1016SkTypeface* SkFontHost::Deserialize(SkStream* stream) { 1017 SkASSERT(!"SkFontHost::Deserialize unimplemented"); 1018 return NULL; 1019} 1020 1021static bool getWidthAdvance(HDC hdc, int gId, int16_t* advance) { 1022 // Initialize the MAT2 structure to the identify transformation matrix. 1023 static const MAT2 mat2 = {SkScalarToFIXED(1), SkScalarToFIXED(0), 1024 SkScalarToFIXED(0), SkScalarToFIXED(1)}; 1025 int flags = GGO_METRICS | GGO_GLYPH_INDEX; 1026 GLYPHMETRICS gm; 1027 if (GDI_ERROR == GetGlyphOutline(hdc, gId, flags, &gm, 0, NULL, &mat2)) { 1028 return false; 1029 } 1030 SkASSERT(advance); 1031 *advance = gm.gmCellIncX; 1032 return true; 1033} 1034 1035// static 1036SkAdvancedTypefaceMetrics* SkFontHost::GetAdvancedTypefaceMetrics( 1037 uint32_t fontID, 1038 SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo, 1039 const uint32_t* glyphIDs, 1040 uint32_t glyphIDsCount) { 1041 LOGFONT lf; 1042 GetLogFontByID(fontID, &lf); 1043 SkAdvancedTypefaceMetrics* info = NULL; 1044 1045 HDC hdc = CreateCompatibleDC(NULL); 1046 HFONT font = CreateFontIndirect(&lf); 1047 HFONT savefont = (HFONT)SelectObject(hdc, font); 1048 HFONT designFont = NULL; 1049 1050 // To request design units, create a logical font whose height is specified 1051 // as unitsPerEm. 1052 OUTLINETEXTMETRIC otm; 1053 if (!GetOutlineTextMetrics(hdc, sizeof(otm), &otm) || 1054 !GetTextFace(hdc, LF_FACESIZE, lf.lfFaceName)) { 1055 goto Error; 1056 } 1057 lf.lfHeight = -SkToS32(otm.otmEMSquare); 1058 designFont = CreateFontIndirect(&lf); 1059 SelectObject(hdc, designFont); 1060 if (!GetOutlineTextMetrics(hdc, sizeof(otm), &otm)) { 1061 goto Error; 1062 } 1063 const unsigned glyphCount = calculateGlyphCount(hdc); 1064 1065 info = new SkAdvancedTypefaceMetrics; 1066 info->fEmSize = otm.otmEMSquare; 1067 info->fMultiMaster = false; 1068 info->fLastGlyphID = SkToU16(glyphCount - 1); 1069 info->fStyle = 0; 1070#ifdef UNICODE 1071 // Get the buffer size needed first. 1072 size_t str_len = WideCharToMultiByte(CP_UTF8, 0, lf.lfFaceName, -1, NULL, 1073 0, NULL, NULL); 1074 // Allocate a buffer (str_len already has terminating null accounted for). 1075 char *familyName = new char[str_len]; 1076 // Now actually convert the string. 1077 WideCharToMultiByte(CP_UTF8, 0, lf.lfFaceName, -1, familyName, str_len, 1078 NULL, NULL); 1079 info->fFontName.set(familyName); 1080 delete [] familyName; 1081#else 1082 info->fFontName.set(lf.lfFaceName); 1083#endif 1084 1085 if (perGlyphInfo & SkAdvancedTypefaceMetrics::kToUnicode_PerGlyphInfo) { 1086 populate_glyph_to_unicode(hdc, glyphCount, &(info->fGlyphToUnicode)); 1087 } 1088 1089 if (otm.otmTextMetrics.tmPitchAndFamily & TMPF_TRUETYPE) { 1090 info->fType = SkAdvancedTypefaceMetrics::kTrueType_Font; 1091 } else { 1092 info->fType = SkAdvancedTypefaceMetrics::kOther_Font; 1093 info->fItalicAngle = 0; 1094 info->fAscent = 0; 1095 info->fDescent = 0; 1096 info->fStemV = 0; 1097 info->fCapHeight = 0; 1098 info->fBBox = SkIRect::MakeEmpty(); 1099 return info; 1100 } 1101 1102 // If this bit is clear the font is a fixed pitch font. 1103 if (!(otm.otmTextMetrics.tmPitchAndFamily & TMPF_FIXED_PITCH)) { 1104 info->fStyle |= SkAdvancedTypefaceMetrics::kFixedPitch_Style; 1105 } 1106 if (otm.otmTextMetrics.tmItalic) { 1107 info->fStyle |= SkAdvancedTypefaceMetrics::kItalic_Style; 1108 } 1109 // Setting symbolic style by default for now. 1110 info->fStyle |= SkAdvancedTypefaceMetrics::kSymbolic_Style; 1111 if (otm.otmTextMetrics.tmPitchAndFamily & FF_ROMAN) { 1112 info->fStyle |= SkAdvancedTypefaceMetrics::kSerif_Style; 1113 } else if (otm.otmTextMetrics.tmPitchAndFamily & FF_SCRIPT) { 1114 info->fStyle |= SkAdvancedTypefaceMetrics::kScript_Style; 1115 } 1116 1117 // The main italic angle of the font, in tenths of a degree counterclockwise 1118 // from vertical. 1119 info->fItalicAngle = otm.otmItalicAngle / 10; 1120 info->fAscent = SkToS16(otm.otmTextMetrics.tmAscent); 1121 info->fDescent = SkToS16(-otm.otmTextMetrics.tmDescent); 1122 // TODO(ctguil): Use alternate cap height calculation. 1123 // MSDN says otmsCapEmHeight is not support but it is returning a value on 1124 // my Win7 box. 1125 info->fCapHeight = otm.otmsCapEmHeight; 1126 info->fBBox = 1127 SkIRect::MakeLTRB(otm.otmrcFontBox.left, otm.otmrcFontBox.top, 1128 otm.otmrcFontBox.right, otm.otmrcFontBox.bottom); 1129 1130 // Figure out a good guess for StemV - Min width of i, I, !, 1. 1131 // This probably isn't very good with an italic font. 1132 int16_t min_width = SHRT_MAX; 1133 info->fStemV = 0; 1134 char stem_chars[] = {'i', 'I', '!', '1'}; 1135 for (size_t i = 0; i < SK_ARRAY_COUNT(stem_chars); i++) { 1136 ABC abcWidths; 1137 if (GetCharABCWidths(hdc, stem_chars[i], stem_chars[i], &abcWidths)) { 1138 int16_t width = abcWidths.abcB; 1139 if (width > 0 && width < min_width) { 1140 min_width = width; 1141 info->fStemV = min_width; 1142 } 1143 } 1144 } 1145 1146 // If bit 1 is set, the font may not be embedded in a document. 1147 // If bit 1 is clear, the font can be embedded. 1148 // If bit 2 is set, the embedding is read-only. 1149 if (otm.otmfsType & 0x1) { 1150 info->fType = SkAdvancedTypefaceMetrics::kNotEmbeddable_Font; 1151 } else if (perGlyphInfo & 1152 SkAdvancedTypefaceMetrics::kHAdvance_PerGlyphInfo) { 1153 if (info->fStyle & SkAdvancedTypefaceMetrics::kFixedPitch_Style) { 1154 appendRange(&info->fGlyphWidths, 0); 1155 info->fGlyphWidths->fAdvance.append(1, &min_width); 1156 finishRange(info->fGlyphWidths.get(), 0, 1157 SkAdvancedTypefaceMetrics::WidthRange::kDefault); 1158 } else { 1159 info->fGlyphWidths.reset( 1160 getAdvanceData(hdc, 1161 glyphCount, 1162 glyphIDs, 1163 glyphIDsCount, 1164 &getWidthAdvance)); 1165 } 1166 } 1167 1168Error: 1169 SelectObject(hdc, savefont); 1170 DeleteObject(designFont); 1171 DeleteObject(font); 1172 DeleteDC(hdc); 1173 1174 return info; 1175} 1176 1177SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) { 1178 1179 //Should not be used on Windows, keep linker happy 1180 SkASSERT(false); 1181 return SkCreateTypefaceFromLOGFONT(get_default_font()); 1182} 1183 1184SkStream* SkFontHost::OpenStream(SkFontID uniqueID) { 1185 const DWORD kTTCTag = 1186 SkEndian_SwapBE32(SkSetFourByteTag('t', 't', 'c', 'f')); 1187 LOGFONT lf; 1188 GetLogFontByID(uniqueID, &lf); 1189 1190 HDC hdc = ::CreateCompatibleDC(NULL); 1191 HFONT font = CreateFontIndirect(&lf); 1192 HFONT savefont = (HFONT)SelectObject(hdc, font); 1193 1194 SkMemoryStream* stream = NULL; 1195 DWORD tables[2] = {kTTCTag, 0}; 1196 for (int i = 0; i < SK_ARRAY_COUNT(tables); i++) { 1197 size_t bufferSize = GetFontData(hdc, tables[i], 0, NULL, 0); 1198 if (bufferSize != GDI_ERROR) { 1199 stream = new SkMemoryStream(bufferSize); 1200 if (GetFontData(hdc, tables[i], 0, (void*)stream->getMemoryBase(), 1201 bufferSize)) { 1202 break; 1203 } else { 1204 delete stream; 1205 stream = NULL; 1206 } 1207 } 1208 } 1209 1210 SelectObject(hdc, savefont); 1211 DeleteObject(font); 1212 DeleteDC(hdc); 1213 1214 return stream; 1215} 1216 1217SkScalerContext* SkFontHost::CreateScalerContext(const SkDescriptor* desc) { 1218 return SkNEW_ARGS(SkScalerContext_Windows, (desc)); 1219} 1220 1221/** Return the closest matching typeface given either an existing family 1222 (specified by a typeface in that family) or by a familyName, and a 1223 requested style. 1224 1) If familyFace is null, use famillyName. 1225 2) If famillyName is null, use familyFace. 1226 3) If both are null, return the default font that best matches style 1227 This MUST not return NULL. 1228 */ 1229 1230SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace, 1231 const char familyName[], 1232 const void* data, size_t bytelength, 1233 SkTypeface::Style style) { 1234 LOGFONT lf; 1235 if (NULL == familyFace && NULL == familyName) { 1236 lf = get_default_font(); 1237 } else if (familyFace) { 1238 LogFontTypeface* face = (LogFontTypeface*)familyFace; 1239 lf = face->fLogFont; 1240 } else { 1241 memset(&lf, 0, sizeof(LOGFONT)); 1242#ifdef UNICODE 1243 // Get the buffer size needed first. 1244 size_t str_len = ::MultiByteToWideChar(CP_UTF8, 0, familyName, 1245 -1, NULL, 0); 1246 // Allocate a buffer (str_len already has terminating null 1247 // accounted for). 1248 wchar_t *wideFamilyName = new wchar_t[str_len]; 1249 // Now actually convert the string. 1250 ::MultiByteToWideChar(CP_UTF8, 0, familyName, -1, 1251 wideFamilyName, str_len); 1252 ::wcsncpy(lf.lfFaceName, wideFamilyName, LF_FACESIZE); 1253 delete [] wideFamilyName; 1254#else 1255 ::strncpy(lf.lfFaceName, familyName, LF_FACESIZE); 1256#endif 1257 lf.lfFaceName[LF_FACESIZE-1] = '\0'; 1258 } 1259 setStyle(&lf, style); 1260 return SkCreateTypefaceFromLOGFONT(lf); 1261} 1262 1263size_t SkFontHost::ShouldPurgeFontCache(size_t sizeAllocatedSoFar) { 1264 if (sizeAllocatedSoFar > FONT_CACHE_MEMORY_BUDGET) 1265 return sizeAllocatedSoFar - FONT_CACHE_MEMORY_BUDGET; 1266 else 1267 return 0; // nothing to do 1268} 1269 1270SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) { 1271 printf("SkFontHost::CreateTypefaceFromFile unimplemented"); 1272 return NULL; 1273} 1274 1275void SkFontHost::FilterRec(SkScalerContext::Rec* rec) { 1276 unsigned flagsWeDontSupport = SkScalerContext::kDevKernText_Flag | 1277 SkScalerContext::kAutohinting_Flag | 1278 SkScalerContext::kEmbeddedBitmapText_Flag | 1279 SkScalerContext::kEmbolden_Flag | 1280 SkScalerContext::kLCD_BGROrder_Flag | 1281 SkScalerContext::kLCD_Vertical_Flag; 1282 rec->fFlags &= ~flagsWeDontSupport; 1283 1284 SkPaint::Hinting h = rec->getHinting(); 1285 1286 // I think we can support no-hinting, if we get hires outlines and just 1287 // use skia to rasterize into a gray-scale mask... 1288#if 0 1289 switch (h) { 1290 case SkPaint::kNo_Hinting: 1291 case SkPaint::kSlight_Hinting: 1292 h = SkPaint::kNo_Hinting; 1293 break; 1294 case SkPaint::kNormal_Hinting: 1295 case SkPaint::kFull_Hinting: 1296 h = SkPaint::kNormal_Hinting; 1297 break; 1298 default: 1299 SkASSERT(!"unknown hinting"); 1300 } 1301#else 1302 h = SkPaint::kNormal_Hinting; 1303#endif 1304 rec->setHinting(h); 1305 1306// turn this off since GDI might turn A8 into BW! Need a bigger fix. 1307#if 0 1308 // Disable LCD when rotated, since GDI's output is ugly 1309 if (isLCD(*rec) && !isAxisAligned(*rec)) { 1310 rec->fMaskFormat = SkMask::kA8_Format; 1311 } 1312#endif 1313 1314#if 0 1315 if (SkMask::kLCD16_Format == rec->fMaskFormat) { 1316 rec->fMaskFormat = SkMask::kLCD32_Format; 1317 } 1318#endif 1319 // don't specify gamma if we BW (perhaps caller should do this check) 1320 if (SkMask::kBW_Format == rec->fMaskFormat) { 1321 rec->fFlags &= ~(SkScalerContext::kGammaForBlack_Flag | 1322 SkScalerContext::kGammaForWhite_Flag); 1323 } 1324} 1325 1326////////////////////////////////////////////////////////////////////////// 1327 1328void SkFontHost::GetGammaTables(const uint8_t* tables[2]) { 1329 tables[0] = NULL; 1330 tables[1] = NULL; 1331} 1332 1333static bool justAColor(const SkPaint& paint, SkColor* color) { 1334 if (paint.getShader()) { 1335 return false; 1336 } 1337 SkColor c = paint.getColor(); 1338 if (paint.getColorFilter()) { 1339 c = paint.getColorFilter()->filterColor(c); 1340 } 1341 if (color) { 1342 *color = c; 1343 } 1344 return true; 1345} 1346 1347#define BLACK_GAMMA_THRESHOLD 0x40 1348#define WHITE_GAMMA_THRESHOLD 0xA0 1349 1350int SkFontHost::ComputeGammaFlag(const SkPaint& paint) { 1351 SkColor c; 1352 if (justAColor(paint, &c)) { 1353 int r = SkColorGetR(c); 1354 int g = SkColorGetG(c); 1355 int b = SkColorGetB(c); 1356 int luminance = (r * 2 + g * 5 + b) >> 3; 1357 1358 if (luminance <= BLACK_GAMMA_THRESHOLD) { 1359 return SkScalerContext::kGammaForBlack_Flag; 1360 } 1361 if (luminance >= WHITE_GAMMA_THRESHOLD) { 1362 return SkScalerContext::kGammaForWhite_Flag; 1363 } 1364 } 1365 return 0; 1366} 1367 1368#endif // WIN32 1369