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