SkFontHost_win.cpp revision c8ad63e5e42637c65c6b4e0adfacce55730b722d
1/* 2 ** Copyright 2006, The Android Open Source Project 3 ** 4 ** Licensed under the Apache License, Version 2.0 (the "License"); 5 ** you may not use this file except in compliance with the License. 6 ** You may obtain a copy of the License at 7 ** 8 ** http://www.apache.org/licenses/LICENSE-2.0 9 ** 10 ** Unless required by applicable law or agreed to in writing, software 11 ** distributed under the License is distributed on an "AS IS" BASIS, 12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 ** See the License for the specific language governing permissions and 14 ** limitations under the License. 15 */ 16 17#include "SkString.h" 18//#include "SkStream.h" 19 20#include "SkEndian.h" 21#include "SkFontHost.h" 22#include "SkDescriptor.h" 23#include "SkAdvancedTypefaceMetrics.h" 24#include "SkStream.h" 25#include "SkThread.h" 26#include "SkTypeface_win.h" 27#include "SkUtils.h" 28 29#ifdef WIN32 30#include "windows.h" 31#include "tchar.h" 32#include "Usp10.h" 33 34// client3d has to undefine this for now 35#define CAN_USE_LOGFONT_NAME 36 37using namespace skia_advanced_typeface_metrics_utils; 38 39static SkMutex gFTMutex; 40 41static const uint16_t BUFFERSIZE = (16384 - 32); 42static uint8_t glyphbuf[BUFFERSIZE]; 43 44// Give 1MB font cache budget 45#define FONT_CACHE_MEMORY_BUDGET (1024 * 1024) 46 47/** 48 * Since LOGFONT wants its textsize as an int, and we support fractional sizes, 49 * and since we have a cache of LOGFONTs for our tyepfaces, we always set the 50 * lfHeight to a canonical size, and then we use the 2x2 matrix to achieve the 51 * actual requested size. 52 */ 53static const int gCanonicalTextSize = 64; 54 55static void make_canonical(LOGFONT* lf) { 56 lf->lfHeight = -gCanonicalTextSize; 57} 58 59static inline FIXED SkFixedToFIXED(SkFixed x) { 60 return *(FIXED*)(&x); 61} 62 63static inline FIXED SkScalarToFIXED(SkScalar x) { 64 return SkFixedToFIXED(SkScalarToFixed(x)); 65} 66 67static unsigned calculateGlyphCount(HDC hdc) { 68 // The 'maxp' table stores the number of glyphs at offset 4, in 2 bytes. 69 const DWORD maxpTag = *(DWORD*) "maxp"; 70 uint16_t glyphs; 71 if (GetFontData(hdc, maxpTag, 4, &glyphs, sizeof(glyphs)) != GDI_ERROR) { 72 return SkEndian_SwapBE16(glyphs); 73 } 74 75 // Binary search for glyph count. 76 static const MAT2 mat2 = {{0, 1}, {0, 0}, {0, 0}, {0, 1}}; 77 int32_t max = SK_MaxU16 + 1; 78 int32_t min = 0; 79 GLYPHMETRICS gm; 80 while (min < max) { 81 int32_t mid = min + ((max - min) / 2); 82 if (GetGlyphOutlineW(hdc, mid, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, 83 NULL, &mat2) == GDI_ERROR) { 84 max = mid; 85 } else { 86 min = mid + 1; 87 } 88 } 89 SkASSERT(min == max); 90 return min; 91} 92 93static SkTypeface::Style GetFontStyle(const LOGFONT& lf) { 94 int style = SkTypeface::kNormal; 95 if (lf.lfWeight == FW_SEMIBOLD || lf.lfWeight == FW_DEMIBOLD || lf.lfWeight == FW_BOLD) 96 style |= SkTypeface::kBold; 97 if (lf.lfItalic) 98 style |= SkTypeface::kItalic; 99 100 return (SkTypeface::Style)style; 101} 102 103// have to do this because SkTypeface::SkTypeface() is protected 104class LogFontTypeface : public SkTypeface { 105private: 106 static SkMutex gMutex; 107 static LogFontTypeface* gHead; 108 static int32_t gCurrId; 109 110 LogFontTypeface* fNext; 111 LOGFONT fLogFont; 112 113public: 114 115 LogFontTypeface(Style style, const LOGFONT& logFont) : 116 SkTypeface(style, sk_atomic_inc(&gCurrId)+1), // 0 id is reserved so add 1 117 fLogFont(logFont) 118 { 119 make_canonical(&fLogFont); 120 121 SkAutoMutexAcquire am(gMutex); 122 fNext = gHead; 123 gHead = this; 124 } 125 126 const LOGFONT& logFont() const { return fLogFont; } 127 128 virtual ~LogFontTypeface() { 129 SkAutoMutexAcquire am(gMutex); 130 if (gHead == this) { 131 gHead = fNext; 132 return; 133 } 134 135 LogFontTypeface* prev = gHead; 136 SkASSERT(prev); 137 while (prev->fNext != this) { 138 prev = prev->fNext; 139 SkASSERT(prev); 140 } 141 prev->fNext = fNext; 142 } 143 144 static LogFontTypeface* FindById(uint32_t id){ 145 SkASSERT(gHead); 146 LogFontTypeface* curr = gHead; 147 while (curr->uniqueID() != id) { 148 curr = curr->fNext; 149 SkASSERT(curr); 150 } 151 return curr; 152 } 153 154 static LogFontTypeface* FindByLogFont(const LOGFONT& lf) 155 { 156 LOGFONT canonical = lf; 157 make_canonical(&canonical); 158 159 LogFontTypeface* curr = gHead; 160 while (curr && memcmp(&curr->fLogFont, &canonical, sizeof(LOGFONT))) { 161 curr = curr->fNext; 162 } 163 return curr; 164 } 165}; 166 167LogFontTypeface* LogFontTypeface::gHead; 168int32_t LogFontTypeface::gCurrId; 169SkMutex LogFontTypeface::gMutex; 170 171static const LOGFONT& get_default_font() { 172 static LOGFONT gDefaultFont; 173 // don't hardcode on Windows, Win2000, XP, Vista, and international all have different default 174 // and the user could change too 175 176 177// lfMessageFont is garbage on my XP, so skip for now 178#if 0 179 if (gDefaultFont.lfFaceName[0] != 0) { 180 return gDefaultFont; 181 } 182 183 NONCLIENTMETRICS ncm; 184 ncm.cbSize = sizeof(NONCLIENTMETRICS); 185 SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0); 186 187 //memcpy(&gDefaultFont, &(ncm.lfMessageFont), sizeof(LOGFONT)); 188#endif 189 190 return gDefaultFont; 191} 192 193SkTypeface* SkCreateTypefaceFromLOGFONT(const LOGFONT& lf) { 194 LogFontTypeface* ptypeface = LogFontTypeface::FindByLogFont(lf); 195 196 if (NULL == ptypeface) { 197 SkTypeface::Style style = GetFontStyle(lf); 198 ptypeface = new LogFontTypeface(style, lf); 199 } else { 200 ptypeface->ref(); 201 } 202 return ptypeface; 203} 204 205uint32_t SkFontHost::NextLogicalFont(uint32_t fontID) { 206 // Zero means that we don't have any fallback fonts for this fontID. 207 // This function is implemented on Android, but doesn't have much 208 // meaning here. 209 return 0; 210} 211 212class SkScalerContext_Windows : public SkScalerContext { 213public: 214 SkScalerContext_Windows(const SkDescriptor* desc); 215 virtual ~SkScalerContext_Windows(); 216 217protected: 218 virtual unsigned generateGlyphCount(); 219 virtual uint16_t generateCharToGlyph(SkUnichar uni); 220 virtual void generateAdvance(SkGlyph* glyph); 221 virtual void generateMetrics(SkGlyph* glyph); 222 virtual void generateImage(const SkGlyph& glyph); 223 virtual void generatePath(const SkGlyph& glyph, SkPath* path); 224 virtual void generateFontMetrics(SkPaint::FontMetrics* mX, SkPaint::FontMetrics* mY); 225 //virtual SkDeviceContext getDC() {return ddc;} 226private: 227 SkScalar fScale; // to get from canonical size to real size 228 MAT2 fMat22; 229 XFORM fXform; 230 HDC fDDC; 231 HFONT fSavefont; 232 HFONT fFont; 233 SCRIPT_CACHE fSC; 234 int fGlyphCount; 235}; 236 237static float mul2float(SkScalar a, SkScalar b) { 238 return SkScalarToFloat(SkScalarMul(a, b)); 239} 240 241static FIXED float2FIXED(float x) { 242 return SkFixedToFIXED(SkFloatToFixed(x)); 243} 244 245SkScalerContext_Windows::SkScalerContext_Windows(const SkDescriptor* desc) 246 : SkScalerContext(desc), fDDC(0), fFont(0), fSavefont(0), fSC(0) 247 , fGlyphCount(-1) { 248 SkAutoMutexAcquire ac(gFTMutex); 249 250 fScale = fRec.fTextSize / gCanonicalTextSize; 251 252 fXform.eM11 = mul2float(fScale, fRec.fPost2x2[0][0]); 253 fXform.eM12 = mul2float(fScale, fRec.fPost2x2[1][0]); 254 fXform.eM21 = mul2float(fScale, fRec.fPost2x2[0][1]); 255 fXform.eM22 = mul2float(fScale, fRec.fPost2x2[1][1]); 256 fXform.eDx = 0; 257 fXform.eDy = 0; 258 259 fMat22.eM11 = float2FIXED(fXform.eM11); 260 fMat22.eM12 = float2FIXED(fXform.eM12); 261 fMat22.eM21 = float2FIXED(-fXform.eM21); 262 fMat22.eM22 = float2FIXED(-fXform.eM22); 263 264 fDDC = ::CreateCompatibleDC(NULL); 265 SetBkMode(fDDC, TRANSPARENT); 266 267 // Scaling by the DPI is inconsistent with how Skia draws elsewhere 268 //SkScalar height = -(fRec.fTextSize * GetDeviceCaps(ddc, LOGPIXELSY) / 72); 269 LOGFONT lf = LogFontTypeface::FindById(fRec.fFontID)->logFont(); 270 lf.lfHeight = -gCanonicalTextSize; 271 fFont = CreateFontIndirect(&lf); 272 fSavefont = (HFONT)SelectObject(fDDC, fFont); 273} 274 275SkScalerContext_Windows::~SkScalerContext_Windows() { 276 if (fDDC) { 277 ::SelectObject(fDDC, fSavefont); 278 ::DeleteDC(fDDC); 279 } 280 if (fFont) { 281 ::DeleteObject(fFont); 282 } 283 if (fSC) { 284 ::ScriptFreeCache(&fSC); 285 } 286} 287 288unsigned SkScalerContext_Windows::generateGlyphCount() { 289 if (fGlyphCount < 0) { 290 fGlyphCount = calculateGlyphCount(fDDC); 291 } 292 return fGlyphCount; 293} 294 295uint16_t SkScalerContext_Windows::generateCharToGlyph(SkUnichar uni) { 296 uint16_t index = 0; 297 WCHAR c[2]; 298 // TODO(ctguil): Support characters that generate more than one glyph. 299 if (SkUTF16_FromUnichar(uni, (uint16_t*)c) == 1) { 300 // Type1 fonts fail with uniscribe API. Use GetGlyphIndices for plane 0. 301 SkAssertResult(GetGlyphIndicesW(fDDC, c, 1, &index, 0)); 302 } else { 303 // Use uniscribe to detemine glyph index for non-BMP characters. 304 // Need to add extra item to SCRIPT_ITEM to work around a bug in older 305 // windows versions. https://bugzilla.mozilla.org/show_bug.cgi?id=366643 306 SCRIPT_ITEM si[2 + 1]; 307 int items; 308 SkAssertResult( 309 SUCCEEDED(ScriptItemize(c, 2, 2, NULL, NULL, si, &items))); 310 311 WORD log[2]; 312 SCRIPT_VISATTR vsa; 313 int glyphs; 314 SkAssertResult(SUCCEEDED(ScriptShape( 315 fDDC, &fSC, c, 2, 1, &si[0].a, &index, log, &vsa, &glyphs))); 316 } 317 return index; 318} 319 320void SkScalerContext_Windows::generateAdvance(SkGlyph* glyph) { 321 this->generateMetrics(glyph); 322} 323 324void SkScalerContext_Windows::generateMetrics(SkGlyph* glyph) { 325 326 SkASSERT(fDDC); 327 328 GLYPHMETRICS gm; 329 memset(&gm, 0, sizeof(gm)); 330 331 glyph->fRsbDelta = 0; 332 glyph->fLsbDelta = 0; 333 334 // Note: need to use GGO_GRAY8_BITMAP instead of GGO_METRICS because GGO_METRICS returns a smaller 335 // BlackBlox; we need the bigger one in case we need the image. fAdvance is the same. 336 uint32_t ret = GetGlyphOutlineW(fDDC, glyph->getGlyphID(0), GGO_GRAY8_BITMAP | GGO_GLYPH_INDEX, &gm, 0, NULL, &fMat22); 337 338 if (GDI_ERROR != ret) { 339 if (ret == 0) { 340 // for white space, ret is zero and gmBlackBoxX, gmBlackBoxY are 1 incorrectly! 341 gm.gmBlackBoxX = gm.gmBlackBoxY = 0; 342 } 343 glyph->fWidth = gm.gmBlackBoxX; 344 glyph->fHeight = gm.gmBlackBoxY; 345 glyph->fTop = SkToS16(gm.gmptGlyphOrigin.y - gm.gmBlackBoxY); 346 glyph->fLeft = SkToS16(gm.gmptGlyphOrigin.x); 347 glyph->fAdvanceX = SkIntToFixed(gm.gmCellIncX); 348 glyph->fAdvanceY = -SkIntToFixed(gm.gmCellIncY); 349 350 // we outset by 1 in all dimensions, since the lcd image may bleed outside 351 // of the computed bounds returned by GetGlyphOutline. 352 // This was deduced by trial and error for small text (e.g. 8pt), so there 353 // maybe a more precise way to make this adjustment... 354 if (SkMask::kLCD16_Format == fRec.fMaskFormat) { 355 glyph->fWidth += 2; 356 glyph->fHeight += 2; 357 glyph->fTop -= 1; 358 glyph->fLeft -= 1; 359 } 360 } else { 361 glyph->fWidth = 0; 362 } 363} 364 365void SkScalerContext_Windows::generateFontMetrics(SkPaint::FontMetrics* mx, SkPaint::FontMetrics* my) { 366// Note: This code was borrowed from generateLineHeight, which has a note 367// stating that it may be incorrect. 368 if (!(mx || my)) 369 return; 370 371 SkASSERT(fDDC); 372 373 OUTLINETEXTMETRIC otm; 374 375 uint32_t ret = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm); 376 if (sizeof(otm) != ret) { 377 return; 378 } 379 380 if (mx) { 381 mx->fTop = -fScale * otm.otmTextMetrics.tmAscent; 382 mx->fAscent = -fScale * otm.otmAscent; 383 mx->fDescent = -fScale * otm.otmDescent; 384 mx->fBottom = fScale * otm.otmTextMetrics.tmDescent; 385 mx->fLeading = fScale * (otm.otmTextMetrics.tmInternalLeading 386 + otm.otmTextMetrics.tmExternalLeading); 387 } 388 389 if (my) { 390 my->fTop = -fScale * otm.otmTextMetrics.tmAscent; 391 my->fAscent = -fScale * otm.otmAscent; 392 my->fDescent = -fScale * otm.otmDescent; 393 my->fBottom = fScale * otm.otmTextMetrics.tmDescent; 394 my->fLeading = fScale * (otm.otmTextMetrics.tmInternalLeading 395 + otm.otmTextMetrics.tmExternalLeading); 396 } 397} 398 399#include "SkColorPriv.h" 400 401static inline uint16_t rgb_to_lcd16(uint32_t rgb) { 402 int r = (rgb >> 16) & 0xFF; 403 int g = (rgb >> 8) & 0xFF; 404 int b = (rgb >> 0) & 0xFF; 405 406 // invert, since we draw black-on-white, but we want the original 407 // src mask values. 408 r = 255 - r; 409 g = 255 - g; 410 b = 255 - b; 411 return SkPackRGB16(SkR32ToR16(r), SkG32ToG16(g), SkB32ToB16(b)); 412} 413 414void SkScalerContext_Windows::generateImage(const SkGlyph& glyph) { 415 416 SkAutoMutexAcquire ac(gFTMutex); 417 418 SkASSERT(fDDC); 419 420 if (SkMask::kLCD16_Format == fRec.fMaskFormat) { 421 HDC dc = CreateCompatibleDC(0); 422 void* bits = 0; 423 BITMAPINFO info; 424 sk_bzero(&info, sizeof(info)); 425 info.bmiHeader.biSize = sizeof(info.bmiHeader); 426 info.bmiHeader.biWidth = glyph.fWidth; 427 info.bmiHeader.biHeight = glyph.fHeight; 428 info.bmiHeader.biPlanes = 1; 429 info.bmiHeader.biBitCount = 32; 430 info.bmiHeader.biCompression = BI_RGB; 431 HBITMAP bm = CreateDIBSection(dc, &info, DIB_RGB_COLORS, &bits, 0, 0); 432 SelectObject(dc, bm); 433 434 // erase to white 435 size_t srcRB = glyph.fWidth << 2; 436 size_t size = glyph.fHeight * srcRB; 437 memset(bits, 0xFF, size); 438 439 SetBkMode(dc, TRANSPARENT); 440 SetTextAlign(dc, TA_LEFT | TA_BASELINE); 441 SetGraphicsMode(dc, GM_ADVANCED); 442 443 XFORM xform = fXform; 444 xform.eDx = (float)-glyph.fLeft; 445 xform.eDy = (float)-glyph.fTop; 446 SetWorldTransform(dc, &xform); 447 448 HGDIOBJ prevFont = SelectObject(dc, fFont); 449 COLORREF color = SetTextColor(dc, 0); // black 450 SkASSERT(color != CLR_INVALID); 451 uint16_t glyphID = glyph.getGlyphID(); 452#if defined(UNICODE) 453 ExtTextOut(dc, 0, 0, ETO_GLYPH_INDEX, NULL, (LPCWSTR)&glyphID, 1, NULL); 454#else 455 ExtTextOut(dc, 0, 0, ETO_GLYPH_INDEX, NULL, (LPCSTR)&glyphID, 1, NULL); 456#endif 457 GdiFlush(); 458 459 // downsample from rgba to rgb565 460 int width = glyph.fWidth; 461 size_t dstRB = glyph.rowBytes(); 462 const uint32_t* src = (const uint32_t*)bits; 463 // gdi's bitmap is upside-down, so we reverse dst walking in Y 464 uint16_t* dst = (uint16_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB); 465 for (int y = 0; y < glyph.fHeight; y++) { 466 for (int i = 0; i < width; i++) { 467 dst[i] = rgb_to_lcd16(src[i]); 468 } 469 src = (const uint32_t*)((const char*)src + srcRB); 470 dst = (uint16_t*)((char*)dst - dstRB); 471 } 472 473 DeleteDC(dc); 474 DeleteObject(bm); 475 return; 476 } 477 478 GLYPHMETRICS gm; 479 memset(&gm, 0, sizeof(gm)); 480 uint32_t bytecount = 0; 481 uint32_t total_size = GetGlyphOutlineW(fDDC, glyph.fID, GGO_GRAY8_BITMAP | GGO_GLYPH_INDEX, &gm, 0, NULL, &fMat22); 482 if (GDI_ERROR != total_size && total_size > 0) { 483 uint8_t *pBuff = new uint8_t[total_size]; 484 if (NULL != pBuff) { 485 total_size = GetGlyphOutlineW(fDDC, glyph.fID, GGO_GRAY8_BITMAP | GGO_GLYPH_INDEX, &gm, total_size, pBuff, &fMat22); 486 487 SkASSERT(total_size != GDI_ERROR); 488 489 SkASSERT(glyph.fWidth == gm.gmBlackBoxX); 490 SkASSERT(glyph.fHeight == gm.gmBlackBoxY); 491 492 uint8_t* dst = (uint8_t*)glyph.fImage; 493 uint32_t pitch = (gm.gmBlackBoxX + 3) & ~0x3; 494 if (pitch != glyph.rowBytes()) { 495 SkASSERT(false); // glyph.fImage has different rowsize!? 496 } 497 498 for (int32_t y = gm.gmBlackBoxY - 1; y >= 0; y--) { 499 uint8_t* src = pBuff + pitch * y; 500 501 for (uint32_t x = 0; x < gm.gmBlackBoxX; x++) { 502 if (*src > 63) { 503 *dst = 0xFF; 504 } 505 else { 506 *dst = *src << 2; // scale to 0-255 507 } 508 dst++; 509 src++; 510 bytecount++; 511 } 512 memset(dst, 0, glyph.rowBytes() - glyph.fWidth); 513 dst += glyph.rowBytes() - glyph.fWidth; 514 } 515 516 delete[] pBuff; 517 } 518 } 519 520 SkASSERT(GDI_ERROR != total_size && total_size >= 0); 521 522} 523 524void SkScalerContext_Windows::generatePath(const SkGlyph& glyph, SkPath* path) { 525 526 SkAutoMutexAcquire ac(gFTMutex); 527 528 SkASSERT(&glyph && path); 529 SkASSERT(fDDC); 530 531 path->reset(); 532 533#if 0 534 char buf[1024]; 535 sprintf(buf, "generatePath: id:%d, w=%d, h=%d, font:%s,fh:%d\n", glyph.fID, glyph.fWidth, glyph.fHeight, lf.lfFaceName, lf.lfHeight); 536 OutputDebugString(buf); 537#endif 538 539 GLYPHMETRICS gm; 540 uint32_t total_size = GetGlyphOutlineW(fDDC, glyph.fID, GGO_NATIVE | GGO_GLYPH_INDEX, &gm, BUFFERSIZE, glyphbuf, &fMat22); 541 542 if (GDI_ERROR != total_size) { 543 544 const uint8_t* cur_glyph = glyphbuf; 545 const uint8_t* end_glyph = glyphbuf + total_size; 546 547 while(cur_glyph < end_glyph) { 548 const TTPOLYGONHEADER* th = (TTPOLYGONHEADER*)cur_glyph; 549 550 const uint8_t* end_poly = cur_glyph + th->cb; 551 const uint8_t* cur_poly = cur_glyph + sizeof(TTPOLYGONHEADER); 552 553 path->moveTo(SkFixedToScalar(*(SkFixed*)(&th->pfxStart.x)), SkFixedToScalar(*(SkFixed*)(&th->pfxStart.y))); 554 555 while(cur_poly < end_poly) { 556 const TTPOLYCURVE* pc = (const TTPOLYCURVE*)cur_poly; 557 558 if (pc->wType == TT_PRIM_LINE) { 559 for (uint16_t i = 0; i < pc->cpfx; i++) { 560 path->lineTo(SkFixedToScalar(*(SkFixed*)(&pc->apfx[i].x)), SkFixedToScalar(*(SkFixed*)(&pc->apfx[i].y))); 561 } 562 } 563 564 if (pc->wType == TT_PRIM_QSPLINE) { 565 for (uint16_t u = 0; u < pc->cpfx - 1; u++) { // Walk through points in spline 566 POINTFX pnt_b = pc->apfx[u]; // B is always the current point 567 POINTFX pnt_c = pc->apfx[u+1]; 568 569 if (u < pc->cpfx - 2) { // If not on last spline, compute C 570 pnt_c.x = SkFixedToFIXED(SkFixedAve(*(SkFixed*)(&pnt_b.x), *(SkFixed*)(&pnt_c.x))); 571 pnt_c.y = SkFixedToFIXED(SkFixedAve(*(SkFixed*)(&pnt_b.y), *(SkFixed*)(&pnt_c.y))); 572 } 573 574 path->quadTo(SkFixedToScalar(*(SkFixed*)(&pnt_b.x)), SkFixedToScalar(*(SkFixed*)(&pnt_b.y)), SkFixedToScalar(*(SkFixed*)(&pnt_c.x)), SkFixedToScalar(*(SkFixed*)(&pnt_c.y))); 575 } 576 } 577 cur_poly += sizeof(uint16_t) * 2 + sizeof(POINTFX) * pc->cpfx; 578 } 579 cur_glyph += th->cb; 580 path->close(); 581 } 582 } 583 else { 584 SkASSERT(false); 585 } 586 //char buf[1024]; 587 //sprintf(buf, "generatePath: count:%d\n", count); 588 //OutputDebugString(buf); 589} 590 591void SkFontHost::Serialize(const SkTypeface* face, SkWStream* stream) { 592 SkASSERT(!"SkFontHost::Serialize unimplemented"); 593} 594 595SkTypeface* SkFontHost::Deserialize(SkStream* stream) { 596 SkASSERT(!"SkFontHost::Deserialize unimplemented"); 597 return NULL; 598} 599 600static bool getWidthAdvance(HDC hdc, int gId, int16_t* advance) { 601 // Initialize the MAT2 structure to the identify transformation matrix. 602 static const MAT2 mat2 = {SkScalarToFIXED(1), SkScalarToFIXED(0), 603 SkScalarToFIXED(0), SkScalarToFIXED(1)}; 604 int flags = GGO_METRICS | GGO_GLYPH_INDEX; 605 GLYPHMETRICS gm; 606 if (GDI_ERROR == GetGlyphOutline(hdc, gId, flags, &gm, 0, NULL, &mat2)) { 607 return false; 608 } 609 SkASSERT(advance); 610 *advance = gm.gmCellIncX; 611 return true; 612} 613 614// static 615SkAdvancedTypefaceMetrics* SkFontHost::GetAdvancedTypefaceMetrics( 616 uint32_t fontID, bool perGlyphInfo) { 617 SkAutoMutexAcquire ac(gFTMutex); 618 LogFontTypeface* rec = LogFontTypeface::FindById(fontID); 619 LOGFONT lf = rec->logFont(); 620 SkAdvancedTypefaceMetrics* info = NULL; 621 622 HDC hdc = CreateCompatibleDC(NULL); 623 HFONT font = CreateFontIndirect(&lf); 624 HFONT savefont = (HFONT)SelectObject(hdc, font); 625 HFONT designFont = NULL; 626 627 // To request design units, create a logical font whose height is specified 628 // as unitsPerEm. 629 OUTLINETEXTMETRIC otm; 630 if (!GetOutlineTextMetrics(hdc, sizeof(otm), &otm) || 631 !GetTextFace(hdc, LF_FACESIZE, lf.lfFaceName)) { 632 goto Error; 633 } 634 lf.lfHeight = -SkToS32(otm.otmEMSquare); 635 designFont = CreateFontIndirect(&lf); 636 SelectObject(hdc, designFont); 637 if (!GetOutlineTextMetrics(hdc, sizeof(otm), &otm)) { 638 goto Error; 639 } 640 const unsigned glyphCount = calculateGlyphCount(hdc); 641 642 info = new SkAdvancedTypefaceMetrics; 643 info->fEmSize = otm.otmEMSquare; 644 info->fMultiMaster = false; 645 info->fLastGlyphID = SkToU16(glyphCount - 1); 646 info->fStyle = 0; 647#ifdef UNICODE 648 // Get the buffer size needed first. 649 size_t str_len = WideCharToMultiByte(CP_UTF8, 0, lf.lfFaceName, -1, NULL, 650 0, NULL, NULL); 651 // Allocate a buffer (str_len already has terminating null accounted for). 652 char *familyName = new char[str_len]; 653 // Now actually convert the string. 654 WideCharToMultiByte(CP_UTF8, 0, lf.lfFaceName, -1, familyName, str_len, 655 NULL, NULL); 656 info->fFontName.set(familyName); 657 delete [] familyName; 658#else 659 info->fFontName.set(lf.lfFaceName); 660#endif 661 662 if (otm.otmTextMetrics.tmPitchAndFamily & TMPF_TRUETYPE) { 663 info->fType = SkAdvancedTypefaceMetrics::kTrueType_Font; 664 } else { 665 info->fType = SkAdvancedTypefaceMetrics::kOther_Font; 666 info->fItalicAngle = 0; 667 info->fAscent = 0; 668 info->fDescent = 0; 669 info->fStemV = 0; 670 info->fCapHeight = 0; 671 info->fBBox = SkIRect::MakeEmpty(); 672 return info; 673 } 674 675 // If this bit is clear the font is a fixed pitch font. 676 if (!(otm.otmTextMetrics.tmPitchAndFamily & TMPF_FIXED_PITCH)) { 677 info->fStyle |= SkAdvancedTypefaceMetrics::kFixedPitch_Style; 678 } 679 if (otm.otmTextMetrics.tmItalic) { 680 info->fStyle |= SkAdvancedTypefaceMetrics::kItalic_Style; 681 } 682 // Setting symbolic style by default for now. 683 info->fStyle |= SkAdvancedTypefaceMetrics::kSymbolic_Style; 684 if (otm.otmTextMetrics.tmPitchAndFamily & FF_ROMAN) { 685 info->fStyle |= SkAdvancedTypefaceMetrics::kSerif_Style; 686 } else if (otm.otmTextMetrics.tmPitchAndFamily & FF_SCRIPT) { 687 info->fStyle |= SkAdvancedTypefaceMetrics::kScript_Style; 688 } 689 690 // The main italic angle of the font, in tenths of a degree counterclockwise 691 // from vertical. 692 info->fItalicAngle = otm.otmItalicAngle / 10; 693 info->fAscent = SkToS16(otm.otmTextMetrics.tmAscent); 694 info->fDescent = SkToS16(-otm.otmTextMetrics.tmDescent); 695 // TODO(ctguil): Use alternate cap height calculation. 696 // MSDN says otmsCapEmHeight is not support but it is returning a value on 697 // my Win7 box. 698 info->fCapHeight = otm.otmsCapEmHeight; 699 info->fBBox = 700 SkIRect::MakeLTRB(otm.otmrcFontBox.left, otm.otmrcFontBox.top, 701 otm.otmrcFontBox.right, otm.otmrcFontBox.bottom); 702 703 // Figure out a good guess for StemV - Min width of i, I, !, 1. 704 // This probably isn't very good with an italic font. 705 int16_t min_width = SHRT_MAX; 706 info->fStemV = 0; 707 char stem_chars[] = {'i', 'I', '!', '1'}; 708 for (size_t i = 0; i < SK_ARRAY_COUNT(stem_chars); i++) { 709 ABC abcWidths; 710 if (GetCharABCWidths(hdc, stem_chars[i], stem_chars[i], &abcWidths)) { 711 int16_t width = abcWidths.abcB; 712 if (width > 0 && width < min_width) { 713 min_width = width; 714 info->fStemV = min_width; 715 } 716 } 717 } 718 719 // If bit 1 is set, the font may not be embedded in a document. 720 // If bit 1 is clear, the font can be embedded. 721 // If bit 2 is set, the embedding is read-only. 722 if (otm.otmfsType & 0x1) { 723 info->fType = SkAdvancedTypefaceMetrics::kNotEmbeddable_Font; 724 } else if (perGlyphInfo) { 725 info->fGlyphWidths.reset( 726 getAdvanceData(hdc, glyphCount, &getWidthAdvance)); 727 } 728 729Error: 730 SelectObject(hdc, savefont); 731 DeleteObject(designFont); 732 DeleteObject(font); 733 DeleteDC(hdc); 734 735 return info; 736} 737 738SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) { 739 740 //Should not be used on Windows, keep linker happy 741 SkASSERT(false); 742 return SkCreateTypefaceFromLOGFONT(get_default_font()); 743} 744 745SkStream* SkFontHost::OpenStream(SkFontID uniqueID) { 746 SkAutoMutexAcquire ac(gFTMutex); 747 LogFontTypeface* rec = LogFontTypeface::FindById(uniqueID); 748 749 HDC hdc = ::CreateCompatibleDC(NULL); 750 HFONT font = CreateFontIndirect(&rec->logFont()); 751 HFONT savefont = (HFONT)SelectObject(hdc, font); 752 753 size_t bufferSize = GetFontData(hdc, 0, 0, NULL, 0); 754 SkMemoryStream* stream = new SkMemoryStream(bufferSize); 755 if (!GetFontData(hdc, 0, 0, (void*)stream->getMemoryBase(), bufferSize)) { 756 delete stream; 757 stream = NULL; 758 } 759 760 SelectObject(hdc, savefont); 761 DeleteObject(font); 762 DeleteDC(hdc); 763 764 return stream; 765} 766 767SkScalerContext* SkFontHost::CreateScalerContext(const SkDescriptor* desc) { 768 return SkNEW_ARGS(SkScalerContext_Windows, (desc)); 769} 770 771/** Return the closest matching typeface given either an existing family 772 (specified by a typeface in that family) or by a familyName, and a 773 requested style. 774 1) If familyFace is null, use famillyName. 775 2) If famillyName is null, use familyFace. 776 3) If both are null, return the default font that best matches style 777 This MUST not return NULL. 778 */ 779 780SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace, 781 const char familyName[], 782 const void* data, size_t bytelength, 783 SkTypeface::Style style) { 784 785 static SkTypeface* gDefaultTypeface; 786 SkAutoMutexAcquire ac(gFTMutex); 787 788#ifndef CAN_USE_LOGFONT_NAME 789 familyName = NULL; 790 familyFace = NULL; 791#endif 792 793 // clip to legal style bits 794 style = (SkTypeface::Style)(style & SkTypeface::kBoldItalic); 795 796 SkTypeface* tf = NULL; 797 if (NULL == familyFace && NULL == familyName) { 798 LOGFONT lf = get_default_font(); 799 lf.lfWeight = (style & SkTypeface::kBold) != 0 ? FW_BOLD : FW_NORMAL ; 800 lf.lfItalic = ((style & SkTypeface::kItalic) != 0); 801 // hack until we figure out if SkTypeface should cache this itself 802 if (style == SkTypeface::kNormal) { 803 if (NULL == gDefaultTypeface) { 804 gDefaultTypeface = SkCreateTypefaceFromLOGFONT(lf); 805 } 806 tf = gDefaultTypeface; 807 tf->ref(); 808 } else { 809 tf = SkCreateTypefaceFromLOGFONT(lf); 810 } 811 } else { 812#ifdef CAN_USE_LOGFONT_NAME 813 LOGFONT lf; 814 if (NULL != familyFace) { 815 uint32_t id = familyFace->uniqueID(); 816 LogFontTypeface* rec = LogFontTypeface::FindById(id); 817 if (!rec) { 818 SkASSERT(false); 819 lf = get_default_font(); 820 } 821 else { 822 lf = rec->logFont(); 823 } 824 } 825 else { 826 memset(&lf, 0, sizeof(LOGFONT)); 827 828 lf.lfHeight = -11; // default 829 lf.lfQuality = PROOF_QUALITY; 830 lf.lfCharSet = DEFAULT_CHARSET; 831 832#ifdef UNICODE 833 // Get the buffer size needed first. 834 size_t str_len = ::MultiByteToWideChar(CP_UTF8, 0, familyName, 835 -1, NULL, 0); 836 // Allocate a buffer (str_len already has terminating null 837 // accounted for). 838 wchar_t *wideFamilyName = new wchar_t[str_len]; 839 // Now actually convert the string. 840 ::MultiByteToWideChar(CP_UTF8, 0, familyName, -1, 841 wideFamilyName, str_len); 842 ::wcsncpy(lf.lfFaceName, wideFamilyName, LF_FACESIZE); 843 delete [] wideFamilyName; 844#else 845 ::strncpy(lf.lfFaceName, familyName, LF_FACESIZE); 846#endif 847 lf.lfFaceName[LF_FACESIZE-1] = '\0'; 848 } 849 850 // use the style desired 851 lf.lfWeight = (style & SkTypeface::kBold) != 0 ? FW_BOLD : FW_NORMAL ; 852 lf.lfItalic = ((style & SkTypeface::kItalic) != 0); 853 tf = SkCreateTypefaceFromLOGFONT(lf); 854#endif 855 } 856 857 if (NULL == tf) { 858 tf = SkCreateTypefaceFromLOGFONT(get_default_font()); 859 } 860 return tf; 861} 862 863size_t SkFontHost::ShouldPurgeFontCache(size_t sizeAllocatedSoFar) { 864 if (sizeAllocatedSoFar > FONT_CACHE_MEMORY_BUDGET) 865 return sizeAllocatedSoFar - FONT_CACHE_MEMORY_BUDGET; 866 else 867 return 0; // nothing to do 868} 869 870int SkFontHost::ComputeGammaFlag(const SkPaint& paint) { 871 return 0; 872} 873 874void SkFontHost::GetGammaTables(const uint8_t* tables[2]) { 875 tables[0] = NULL; // black gamma (e.g. exp=1.4) 876 tables[1] = NULL; // white gamma (e.g. exp= 1/1.4) 877} 878 879SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) { 880 printf("SkFontHost::CreateTypefaceFromFile unimplemented"); 881 return NULL; 882} 883 884void SkFontHost::FilterRec(SkScalerContext::Rec* rec) { 885 // We don't control the hinting nor ClearType settings here 886 rec->setHinting(SkPaint::kNormal_Hinting); 887 888 // we do support LCD16 889 if (SkMask::kLCD16_Format == rec->fMaskFormat) { 890 return; 891 } 892 893 if (SkMask::FormatIsLCD((SkMask::Format)rec->fMaskFormat)) { 894 rec->fMaskFormat = SkMask::kA8_Format; 895 } 896} 897 898#endif // WIN32 899