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