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