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