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 #include <vector> 10 #ifdef SK_BUILD_FOR_MAC 11 #import <ApplicationServices/ApplicationServices.h> 12 #endif 13 14 #ifdef SK_BUILD_FOR_IOS 15 #include <CoreText/CoreText.h> 16 #include <CoreText/CTFontManager.h> 17 #include <CoreGraphics/CoreGraphics.h> 18 #include <CoreFoundation/CoreFoundation.h> 19 #endif 20 21 #include "SkFontHost.h" 22 #include "SkCGUtils.h" 23 #include "SkColorPriv.h" 24 #include "SkDescriptor.h" 25 #include "SkEndian.h" 26 #include "SkFontDescriptor.h" 27 #include "SkFloatingPoint.h" 28 #include "SkGlyph.h" 29 #include "SkMaskGamma.h" 30 #include "SkSFNTHeader.h" 31 #include "SkOTTable_glyf.h" 32 #include "SkOTTable_head.h" 33 #include "SkOTTable_hhea.h" 34 #include "SkOTTable_loca.h" 35 #include "SkOTUtils.h" 36 #include "SkPaint.h" 37 #include "SkPath.h" 38 #include "SkString.h" 39 #include "SkStream.h" 40 #include "SkThread.h" 41 #include "SkTypeface_mac.h" 42 #include "SkUtils.h" 43 #include "SkTypefaceCache.h" 44 #include "SkFontMgr.h" 45 #include "SkUtils.h" 46 47 //#define HACK_COLORGLYPHS 48 49 class SkScalerContext_Mac; 50 51 // CTFontManagerCopyAvailableFontFamilyNames() is not always available, so we 52 // provide a wrapper here that will return an empty array if need be. 53 static CFArrayRef SkCTFontManagerCopyAvailableFontFamilyNames() { 54 #ifdef SK_BUILD_FOR_IOS 55 return CFArrayCreate(NULL, NULL, 0, NULL); 56 #else 57 return CTFontManagerCopyAvailableFontFamilyNames(); 58 #endif 59 } 60 61 62 // Being templated and taking const T* prevents calling 63 // CFSafeRelease(autoCFRelease) through implicit conversion. 64 template <typename T> static void CFSafeRelease(/*CFTypeRef*/const T* cfTypeRef) { 65 if (cfTypeRef) { 66 CFRelease(cfTypeRef); 67 } 68 } 69 70 // Being templated and taking const T* prevents calling 71 // CFSafeRetain(autoCFRelease) through implicit conversion. 72 template <typename T> static void CFSafeRetain(/*CFTypeRef*/const T* cfTypeRef) { 73 if (cfTypeRef) { 74 CFRetain(cfTypeRef); 75 } 76 } 77 78 /** Acts like a CFRef, but calls CFSafeRelease when it goes out of scope. */ 79 template<typename CFRef> class AutoCFRelease : private SkNoncopyable { 80 public: 81 explicit AutoCFRelease(CFRef cfRef = NULL) : fCFRef(cfRef) { } 82 ~AutoCFRelease() { CFSafeRelease(fCFRef); } 83 84 void reset(CFRef that = NULL) { 85 CFSafeRetain(that); 86 CFSafeRelease(fCFRef); 87 fCFRef = that; 88 } 89 90 AutoCFRelease& operator =(CFRef that) { 91 reset(that); 92 return *this; 93 } 94 95 operator CFRef() const { return fCFRef; } 96 CFRef get() const { return fCFRef; } 97 98 CFRef* operator&() { SkASSERT(fCFRef == NULL); return &fCFRef; } 99 private: 100 CFRef fCFRef; 101 }; 102 103 static CFStringRef make_CFString(const char str[]) { 104 return CFStringCreateWithCString(NULL, str, kCFStringEncodingUTF8); 105 } 106 107 template<typename T> class AutoCGTable : SkNoncopyable { 108 public: 109 AutoCGTable(CGFontRef font) 110 //Undocumented: the tag parameter in this call is expected in machine order and not BE order. 111 : fCFData(CGFontCopyTableForTag(font, SkSetFourByteTag(T::TAG0, T::TAG1, T::TAG2, T::TAG3))) 112 , fData(fCFData ? reinterpret_cast<const T*>(CFDataGetBytePtr(fCFData)) : NULL) 113 { } 114 115 const T* operator->() const { return fData; } 116 117 private: 118 AutoCFRelease<CFDataRef> fCFData; 119 public: 120 const T* fData; 121 }; 122 123 // inline versions of these rect helpers 124 125 static bool CGRectIsEmpty_inline(const CGRect& rect) { 126 return rect.size.width <= 0 || rect.size.height <= 0; 127 } 128 129 static CGFloat CGRectGetMinX_inline(const CGRect& rect) { 130 return rect.origin.x; 131 } 132 133 static CGFloat CGRectGetMaxX_inline(const CGRect& rect) { 134 return rect.origin.x + rect.size.width; 135 } 136 137 static CGFloat CGRectGetMinY_inline(const CGRect& rect) { 138 return rect.origin.y; 139 } 140 141 static CGFloat CGRectGetMaxY_inline(const CGRect& rect) { 142 return rect.origin.y + rect.size.height; 143 } 144 145 static CGFloat CGRectGetWidth_inline(const CGRect& rect) { 146 return rect.size.width; 147 } 148 149 /////////////////////////////////////////////////////////////////////////////// 150 151 static void sk_memset_rect32(uint32_t* ptr, uint32_t value, 152 size_t width, size_t height, size_t rowBytes) { 153 SkASSERT(width); 154 SkASSERT(width * sizeof(uint32_t) <= rowBytes); 155 156 if (width >= 32) { 157 while (height) { 158 sk_memset32(ptr, value, width); 159 ptr = (uint32_t*)((char*)ptr + rowBytes); 160 height -= 1; 161 } 162 return; 163 } 164 165 rowBytes -= width * sizeof(uint32_t); 166 167 if (width >= 8) { 168 while (height) { 169 int w = width; 170 do { 171 *ptr++ = value; *ptr++ = value; 172 *ptr++ = value; *ptr++ = value; 173 *ptr++ = value; *ptr++ = value; 174 *ptr++ = value; *ptr++ = value; 175 w -= 8; 176 } while (w >= 8); 177 while (--w >= 0) { 178 *ptr++ = value; 179 } 180 ptr = (uint32_t*)((char*)ptr + rowBytes); 181 height -= 1; 182 } 183 } else { 184 while (height) { 185 int w = width; 186 do { 187 *ptr++ = value; 188 } while (--w > 0); 189 ptr = (uint32_t*)((char*)ptr + rowBytes); 190 height -= 1; 191 } 192 } 193 } 194 195 #include <sys/utsname.h> 196 197 typedef uint32_t CGRGBPixel; 198 199 static unsigned CGRGBPixel_getAlpha(CGRGBPixel pixel) { 200 return pixel & 0xFF; 201 } 202 203 // The calls to support subpixel are present in 10.5, but are not included in 204 // the 10.5 SDK. The needed calls have been extracted from the 10.6 SDK and are 205 // included below. To verify that CGContextSetShouldSubpixelQuantizeFonts, for 206 // instance, is present in the 10.5 CoreGraphics libary, use: 207 // cd /Developer/SDKs/MacOSX10.5.sdk/System/Library/Frameworks/ 208 // cd ApplicationServices.framework/Frameworks/CoreGraphics.framework/ 209 // nm CoreGraphics | grep CGContextSetShouldSubpixelQuantizeFonts 210 211 #if !defined(MAC_OS_X_VERSION_10_6) || (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6) 212 CG_EXTERN void CGContextSetAllowsFontSmoothing(CGContextRef context, bool value); 213 CG_EXTERN void CGContextSetAllowsFontSubpixelPositioning(CGContextRef context, bool value); 214 CG_EXTERN void CGContextSetShouldSubpixelPositionFonts(CGContextRef context, bool value); 215 CG_EXTERN void CGContextSetAllowsFontSubpixelQuantization(CGContextRef context, bool value); 216 CG_EXTERN void CGContextSetShouldSubpixelQuantizeFonts(CGContextRef context, bool value); 217 #endif 218 219 static const char FONT_DEFAULT_NAME[] = "Lucida Sans"; 220 221 // See Source/WebKit/chromium/base/mac/mac_util.mm DarwinMajorVersionInternal for original source. 222 static int readVersion() { 223 struct utsname info; 224 if (uname(&info) != 0) { 225 SkDebugf("uname failed\n"); 226 return 0; 227 } 228 if (strcmp(info.sysname, "Darwin") != 0) { 229 SkDebugf("unexpected uname sysname %s\n", info.sysname); 230 return 0; 231 } 232 char* dot = strchr(info.release, '.'); 233 if (!dot) { 234 SkDebugf("expected dot in uname release %s\n", info.release); 235 return 0; 236 } 237 int version = atoi(info.release); 238 if (version == 0) { 239 SkDebugf("could not parse uname release %s\n", info.release); 240 } 241 return version; 242 } 243 244 static int darwinVersion() { 245 static int darwin_version = readVersion(); 246 return darwin_version; 247 } 248 249 static bool isSnowLeopard() { 250 return darwinVersion() == 10; 251 } 252 253 static bool isLion() { 254 return darwinVersion() == 11; 255 } 256 257 static bool isMountainLion() { 258 return darwinVersion() == 12; 259 } 260 261 static bool isLCDFormat(unsigned format) { 262 return SkMask::kLCD16_Format == format || SkMask::kLCD32_Format == format; 263 } 264 265 static CGFloat ScalarToCG(SkScalar scalar) { 266 if (sizeof(CGFloat) == sizeof(float)) { 267 return SkScalarToFloat(scalar); 268 } else { 269 SkASSERT(sizeof(CGFloat) == sizeof(double)); 270 return (CGFloat) SkScalarToDouble(scalar); 271 } 272 } 273 274 static SkScalar CGToScalar(CGFloat cgFloat) { 275 if (sizeof(CGFloat) == sizeof(float)) { 276 return SkFloatToScalar(cgFloat); 277 } else { 278 SkASSERT(sizeof(CGFloat) == sizeof(double)); 279 return SkDoubleToScalar(cgFloat); 280 } 281 } 282 283 static CGAffineTransform MatrixToCGAffineTransform(const SkMatrix& matrix, 284 SkScalar sx = SK_Scalar1, 285 SkScalar sy = SK_Scalar1) { 286 return CGAffineTransformMake( ScalarToCG(matrix[SkMatrix::kMScaleX] * sx), 287 -ScalarToCG(matrix[SkMatrix::kMSkewY] * sy), 288 -ScalarToCG(matrix[SkMatrix::kMSkewX] * sx), 289 ScalarToCG(matrix[SkMatrix::kMScaleY] * sy), 290 ScalarToCG(matrix[SkMatrix::kMTransX] * sx), 291 ScalarToCG(matrix[SkMatrix::kMTransY] * sy)); 292 } 293 294 /////////////////////////////////////////////////////////////////////////////// 295 296 #define BITMAP_INFO_RGB (kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host) 297 #define BITMAP_INFO_GRAY (kCGImageAlphaNone) 298 299 /** 300 * There does not appear to be a publicly accessable API for determining if lcd 301 * font smoothing will be applied if we request it. The main issue is that if 302 * smoothing is applied a gamma of 2.0 will be used, if not a gamma of 1.0. 303 */ 304 static bool supports_LCD() { 305 static int gSupportsLCD = -1; 306 if (gSupportsLCD >= 0) { 307 return (bool) gSupportsLCD; 308 } 309 uint32_t rgb = 0; 310 AutoCFRelease<CGColorSpaceRef> colorspace(CGColorSpaceCreateDeviceRGB()); 311 AutoCFRelease<CGContextRef> cgContext(CGBitmapContextCreate(&rgb, 1, 1, 8, 4, 312 colorspace, BITMAP_INFO_RGB)); 313 CGContextSelectFont(cgContext, "Helvetica", 16, kCGEncodingMacRoman); 314 CGContextSetShouldSmoothFonts(cgContext, true); 315 CGContextSetShouldAntialias(cgContext, true); 316 CGContextSetTextDrawingMode(cgContext, kCGTextFill); 317 CGContextSetGrayFillColor(cgContext, 1, 1); 318 CGContextShowTextAtPoint(cgContext, -1, 0, "|", 1); 319 uint32_t r = (rgb >> 16) & 0xFF; 320 uint32_t g = (rgb >> 8) & 0xFF; 321 uint32_t b = (rgb >> 0) & 0xFF; 322 gSupportsLCD = (r != g || r != b); 323 return (bool) gSupportsLCD; 324 } 325 326 class Offscreen { 327 public: 328 Offscreen(); 329 330 CGRGBPixel* getCG(const SkScalerContext_Mac& context, const SkGlyph& glyph, 331 CGGlyph glyphID, size_t* rowBytesPtr, 332 bool generateA8FromLCD); 333 334 private: 335 enum { 336 kSize = 32 * 32 * sizeof(CGRGBPixel) 337 }; 338 SkAutoSMalloc<kSize> fImageStorage; 339 AutoCFRelease<CGColorSpaceRef> fRGBSpace; 340 341 // cached state 342 AutoCFRelease<CGContextRef> fCG; 343 SkISize fSize; 344 bool fDoAA; 345 bool fDoLCD; 346 347 static int RoundSize(int dimension) { 348 return SkNextPow2(dimension); 349 } 350 }; 351 352 Offscreen::Offscreen() : fRGBSpace(NULL), fCG(NULL), 353 fDoAA(false), fDoLCD(false) { 354 fSize.set(0, 0); 355 } 356 357 /////////////////////////////////////////////////////////////////////////////// 358 359 static SkTypeface::Style computeStyleBits(CTFontRef font, bool* isFixedPitch) { 360 unsigned style = SkTypeface::kNormal; 361 CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(font); 362 363 if (traits & kCTFontBoldTrait) { 364 style |= SkTypeface::kBold; 365 } 366 if (traits & kCTFontItalicTrait) { 367 style |= SkTypeface::kItalic; 368 } 369 if (isFixedPitch) { 370 *isFixedPitch = (traits & kCTFontMonoSpaceTrait) != 0; 371 } 372 return (SkTypeface::Style)style; 373 } 374 375 static SkFontID CTFontRef_to_SkFontID(CTFontRef fontRef) { 376 SkFontID id = 0; 377 // CTFontGetPlatformFont and ATSFontRef are not supported on iOS, so we have to 378 // bracket this to be Mac only. 379 #ifdef SK_BUILD_FOR_MAC 380 ATSFontRef ats = CTFontGetPlatformFont(fontRef, NULL); 381 id = (SkFontID)ats; 382 if (id != 0) { 383 id &= 0x3FFFFFFF; // make top two bits 00 384 return id; 385 } 386 #endif 387 // CTFontGetPlatformFont returns NULL if the font is local 388 // (e.g., was created by a CSS3 @font-face rule). 389 AutoCFRelease<CGFontRef> cgFont(CTFontCopyGraphicsFont(fontRef, NULL)); 390 AutoCGTable<SkOTTableHead> headTable(cgFont); 391 if (headTable.fData) { 392 id = (SkFontID) headTable->checksumAdjustment; 393 id = (id & 0x3FFFFFFF) | 0x40000000; // make top two bits 01 394 } 395 // well-formed fonts have checksums, but as a last resort, use the pointer. 396 if (id == 0) { 397 id = (SkFontID) (uintptr_t) fontRef; 398 id = (id & 0x3FFFFFFF) | 0x80000000; // make top two bits 10 399 } 400 return id; 401 } 402 403 static SkFontStyle stylebits2fontstyle(SkTypeface::Style styleBits) { 404 return SkFontStyle((styleBits & SkTypeface::kBold) 405 ? SkFontStyle::kBold_Weight 406 : SkFontStyle::kNormal_Weight, 407 SkFontStyle::kNormal_Width, 408 (styleBits & SkTypeface::kItalic) 409 ? SkFontStyle::kItalic_Slant 410 : SkFontStyle::kUpright_Slant); 411 } 412 413 #define WEIGHT_THRESHOLD ((SkFontStyle::kNormal_Weight + SkFontStyle::kBold_Weight)/2) 414 415 static SkTypeface::Style fontstyle2stylebits(const SkFontStyle& fs) { 416 unsigned style = 0; 417 if (fs.width() >= WEIGHT_THRESHOLD) { 418 style |= SkTypeface::kBold; 419 } 420 if (fs.isItalic()) { 421 style |= SkTypeface::kItalic; 422 } 423 return (SkTypeface::Style)style; 424 } 425 426 class SkTypeface_Mac : public SkTypeface { 427 public: 428 SkTypeface_Mac(SkTypeface::Style style, SkFontID fontID, bool isFixedPitch, 429 CTFontRef fontRef, const char name[]) 430 : SkTypeface(style, fontID, isFixedPitch) 431 , fName(name) 432 , fFontRef(fontRef) // caller has already called CFRetain for us 433 , fFontStyle(stylebits2fontstyle(style)) 434 { 435 SkASSERT(fontRef); 436 } 437 438 SkTypeface_Mac(const SkFontStyle& fs, SkFontID fontID, bool isFixedPitch, 439 CTFontRef fontRef, const char name[]) 440 : SkTypeface(fontstyle2stylebits(fs), fontID, isFixedPitch) 441 , fName(name) 442 , fFontRef(fontRef) // caller has already called CFRetain for us 443 , fFontStyle(fs) 444 { 445 SkASSERT(fontRef); 446 } 447 448 SkString fName; 449 AutoCFRelease<CTFontRef> fFontRef; 450 SkFontStyle fFontStyle; 451 452 protected: 453 friend class SkFontHost; // to access our protected members for deprecated methods 454 455 virtual int onGetUPEM() const SK_OVERRIDE; 456 virtual SkStream* onOpenStream(int* ttcIndex) const SK_OVERRIDE; 457 virtual SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const SK_OVERRIDE; 458 virtual int onGetTableTags(SkFontTableTag tags[]) const SK_OVERRIDE; 459 virtual size_t onGetTableData(SkFontTableTag, size_t offset, 460 size_t length, void* data) const SK_OVERRIDE; 461 virtual SkScalerContext* onCreateScalerContext(const SkDescriptor*) const SK_OVERRIDE; 462 virtual void onFilterRec(SkScalerContextRec*) const SK_OVERRIDE; 463 virtual void onGetFontDescriptor(SkFontDescriptor*, bool*) const SK_OVERRIDE; 464 virtual SkAdvancedTypefaceMetrics* onGetAdvancedTypefaceMetrics( 465 SkAdvancedTypefaceMetrics::PerGlyphInfo, 466 const uint32_t*, uint32_t) const SK_OVERRIDE; 467 virtual int onCharsToGlyphs(const void* chars, Encoding, uint16_t glyphs[], 468 int glyphCount) const SK_OVERRIDE; 469 virtual int onCountGlyphs() const SK_OVERRIDE; 470 virtual SkTypeface* onRefMatchingStyle(Style) const SK_OVERRIDE; 471 472 private: 473 474 typedef SkTypeface INHERITED; 475 }; 476 477 static SkTypeface* NewFromFontRef(CTFontRef fontRef, const char name[]) { 478 SkASSERT(fontRef); 479 bool isFixedPitch; 480 SkTypeface::Style style = computeStyleBits(fontRef, &isFixedPitch); 481 SkFontID fontID = CTFontRef_to_SkFontID(fontRef); 482 483 return new SkTypeface_Mac(style, fontID, isFixedPitch, fontRef, name); 484 } 485 486 static SkTypeface* NewFromName(const char familyName[], SkTypeface::Style theStyle) { 487 CTFontRef ctFont = NULL; 488 489 CTFontSymbolicTraits ctFontTraits = 0; 490 if (theStyle & SkTypeface::kBold) { 491 ctFontTraits |= kCTFontBoldTrait; 492 } 493 if (theStyle & SkTypeface::kItalic) { 494 ctFontTraits |= kCTFontItalicTrait; 495 } 496 497 // Create the font info 498 AutoCFRelease<CFStringRef> cfFontName(make_CFString(familyName)); 499 500 AutoCFRelease<CFNumberRef> cfFontTraits( 501 CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &ctFontTraits)); 502 503 AutoCFRelease<CFMutableDictionaryRef> cfAttributes( 504 CFDictionaryCreateMutable(kCFAllocatorDefault, 0, 505 &kCFTypeDictionaryKeyCallBacks, 506 &kCFTypeDictionaryValueCallBacks)); 507 508 AutoCFRelease<CFMutableDictionaryRef> cfTraits( 509 CFDictionaryCreateMutable(kCFAllocatorDefault, 0, 510 &kCFTypeDictionaryKeyCallBacks, 511 &kCFTypeDictionaryValueCallBacks)); 512 513 // Create the font 514 if (cfFontName != NULL && cfFontTraits != NULL && cfAttributes != NULL && cfTraits != NULL) { 515 CFDictionaryAddValue(cfTraits, kCTFontSymbolicTrait, cfFontTraits); 516 517 CFDictionaryAddValue(cfAttributes, kCTFontFamilyNameAttribute, cfFontName); 518 CFDictionaryAddValue(cfAttributes, kCTFontTraitsAttribute, cfTraits); 519 520 AutoCFRelease<CTFontDescriptorRef> ctFontDesc( 521 CTFontDescriptorCreateWithAttributes(cfAttributes)); 522 523 if (ctFontDesc != NULL) { 524 ctFont = CTFontCreateWithFontDescriptor(ctFontDesc, 0, NULL); 525 } 526 } 527 528 return ctFont ? NewFromFontRef(ctFont, familyName) : NULL; 529 } 530 531 static SkTypeface* GetDefaultFace() { 532 SK_DECLARE_STATIC_MUTEX(gMutex); 533 SkAutoMutexAcquire ma(gMutex); 534 535 static SkTypeface* gDefaultFace; 536 537 if (NULL == gDefaultFace) { 538 gDefaultFace = NewFromName(FONT_DEFAULT_NAME, SkTypeface::kNormal); 539 SkTypefaceCache::Add(gDefaultFace, SkTypeface::kNormal); 540 } 541 return gDefaultFace; 542 } 543 544 /////////////////////////////////////////////////////////////////////////////// 545 546 extern CTFontRef SkTypeface_GetCTFontRef(const SkTypeface* face); 547 CTFontRef SkTypeface_GetCTFontRef(const SkTypeface* face) { 548 const SkTypeface_Mac* macface = (const SkTypeface_Mac*)face; 549 return macface ? macface->fFontRef.get() : NULL; 550 } 551 552 /* This function is visible on the outside. It first searches the cache, and if 553 * not found, returns a new entry (after adding it to the cache). 554 */ 555 SkTypeface* SkCreateTypefaceFromCTFont(CTFontRef fontRef) { 556 SkFontID fontID = CTFontRef_to_SkFontID(fontRef); 557 SkTypeface* face = SkTypefaceCache::FindByID(fontID); 558 if (face) { 559 face->ref(); 560 } else { 561 face = NewFromFontRef(fontRef, NULL); 562 SkTypefaceCache::Add(face, face->style()); 563 // NewFromFontRef doesn't retain the parameter, but the typeface it 564 // creates does release it in its destructor, so we balance that with 565 // a retain call here. 566 CFRetain(fontRef); 567 } 568 SkASSERT(face->getRefCnt() > 1); 569 return face; 570 } 571 572 struct NameStyleRec { 573 const char* fName; 574 SkTypeface::Style fStyle; 575 }; 576 577 static bool FindByNameStyle(SkTypeface* face, SkTypeface::Style style, 578 void* ctx) { 579 const SkTypeface_Mac* mface = reinterpret_cast<SkTypeface_Mac*>(face); 580 const NameStyleRec* rec = reinterpret_cast<const NameStyleRec*>(ctx); 581 582 return rec->fStyle == style && mface->fName.equals(rec->fName); 583 } 584 585 static const char* map_css_names(const char* name) { 586 static const struct { 587 const char* fFrom; // name the caller specified 588 const char* fTo; // "canonical" name we map to 589 } gPairs[] = { 590 { "sans-serif", "Helvetica" }, 591 { "serif", "Times" }, 592 { "monospace", "Courier" } 593 }; 594 595 for (size_t i = 0; i < SK_ARRAY_COUNT(gPairs); i++) { 596 if (strcmp(name, gPairs[i].fFrom) == 0) { 597 return gPairs[i].fTo; 598 } 599 } 600 return name; // no change 601 } 602 603 static SkTypeface* create_typeface(const SkTypeface* familyFace, 604 const char familyName[], 605 SkTypeface::Style style) { 606 if (familyName) { 607 familyName = map_css_names(familyName); 608 } 609 610 // Clone an existing typeface 611 // TODO: only clone if style matches the familyFace's style... 612 if (familyName == NULL && familyFace != NULL) { 613 familyFace->ref(); 614 return const_cast<SkTypeface*>(familyFace); 615 } 616 617 if (!familyName || !*familyName) { 618 familyName = FONT_DEFAULT_NAME; 619 } 620 621 NameStyleRec rec = { familyName, style }; 622 SkTypeface* face = SkTypefaceCache::FindByProcAndRef(FindByNameStyle, &rec); 623 624 if (NULL == face) { 625 face = NewFromName(familyName, style); 626 if (face) { 627 SkTypefaceCache::Add(face, style); 628 } else { 629 face = GetDefaultFace(); 630 face->ref(); 631 } 632 } 633 return face; 634 } 635 636 SkTypeface* SkTypeface_Mac::onRefMatchingStyle(Style styleBits) const { 637 return create_typeface(this, NULL, styleBits); 638 } 639 640 /////////////////////////////////////////////////////////////////////////////// 641 642 /** GlyphRect is in FUnits (em space, y up). */ 643 struct GlyphRect { 644 int16_t fMinX; 645 int16_t fMinY; 646 int16_t fMaxX; 647 int16_t fMaxY; 648 }; 649 650 class SkScalerContext_Mac : public SkScalerContext { 651 public: 652 SkScalerContext_Mac(SkTypeface_Mac*, const SkDescriptor*); 653 654 protected: 655 unsigned generateGlyphCount(void) SK_OVERRIDE; 656 uint16_t generateCharToGlyph(SkUnichar uni) SK_OVERRIDE; 657 void generateAdvance(SkGlyph* glyph) SK_OVERRIDE; 658 void generateMetrics(SkGlyph* glyph) SK_OVERRIDE; 659 void generateImage(const SkGlyph& glyph) SK_OVERRIDE; 660 void generatePath(const SkGlyph& glyph, SkPath* path) SK_OVERRIDE; 661 void generateFontMetrics(SkPaint::FontMetrics* mX, SkPaint::FontMetrics* mY) SK_OVERRIDE; 662 663 private: 664 static void CTPathElement(void *info, const CGPathElement *element); 665 666 /** Returns the offset from the horizontal origin to the vertical origin in SkGlyph units. */ 667 void getVerticalOffset(CGGlyph glyphID, SkPoint* offset) const; 668 669 /** Initializes and returns the value of fFBoundingBoxesGlyphOffset. 670 * 671 * For use with (and must be called before) generateBBoxes. 672 */ 673 uint16_t getFBoundingBoxesGlyphOffset(); 674 675 /** Initializes fFBoundingBoxes and returns true on success. 676 * 677 * On Lion and Mountain Lion, CTFontGetBoundingRectsForGlyphs has a bug which causes it to 678 * return a bad value in bounds.origin.x for SFNT fonts whose hhea::numberOfHMetrics is 679 * less than its maxp::numGlyphs. When this is the case we try to read the bounds from the 680 * font directly. 681 * 682 * This routine initializes fFBoundingBoxes to an array of 683 * fGlyphCount - fFBoundingBoxesGlyphOffset GlyphRects which contain the bounds in FUnits 684 * (em space, y up) of glyphs with ids in the range [fFBoundingBoxesGlyphOffset, fGlyphCount). 685 * 686 * Returns true if fFBoundingBoxes is properly initialized. The table can only be properly 687 * initialized for a TrueType font with 'head', 'loca', and 'glyf' tables. 688 * 689 * TODO: A future optimization will compute fFBoundingBoxes once per fCTFont. 690 */ 691 bool generateBBoxes(); 692 693 /** Converts from FUnits (em space, y up) to SkGlyph units (pixels, y down). 694 * 695 * Used on Snow Leopard to correct CTFontGetVerticalTranslationsForGlyphs. 696 * Used on Lion to correct CTFontGetBoundingRectsForGlyphs. 697 */ 698 SkMatrix fFUnitMatrix; 699 700 Offscreen fOffscreen; 701 AutoCFRelease<CTFontRef> fCTFont; 702 703 /** Vertical variant of fCTFont. 704 * 705 * CT vertical metrics are pre-rotated (in em space, before transform) 90deg clock-wise. 706 * This makes kCTFontDefaultOrientation dangerous, because the metrics from 707 * kCTFontHorizontalOrientation are in a different space from kCTFontVerticalOrientation. 708 * Use fCTVerticalFont with kCTFontVerticalOrientation to get metrics in the same space. 709 */ 710 AutoCFRelease<CTFontRef> fCTVerticalFont; 711 712 AutoCFRelease<CGFontRef> fCGFont; 713 SkAutoTMalloc<GlyphRect> fFBoundingBoxes; 714 uint16_t fFBoundingBoxesGlyphOffset; 715 uint16_t fGlyphCount; 716 bool fGeneratedFBoundingBoxes; 717 const bool fDoSubPosition; 718 const bool fVertical; 719 720 friend class Offscreen; 721 722 typedef SkScalerContext INHERITED; 723 }; 724 725 SkScalerContext_Mac::SkScalerContext_Mac(SkTypeface_Mac* typeface, 726 const SkDescriptor* desc) 727 : INHERITED(typeface, desc) 728 , fFBoundingBoxes() 729 , fFBoundingBoxesGlyphOffset(0) 730 , fGeneratedFBoundingBoxes(false) 731 , fDoSubPosition(SkToBool(fRec.fFlags & kSubpixelPositioning_Flag)) 732 , fVertical(SkToBool(fRec.fFlags & kVertical_Flag)) 733 734 { 735 CTFontRef ctFont = typeface->fFontRef.get(); 736 CFIndex numGlyphs = CTFontGetGlyphCount(ctFont); 737 SkASSERT(numGlyphs >= 1 && numGlyphs <= 0xFFFF); 738 fGlyphCount = SkToU16(numGlyphs); 739 740 fRec.getSingleMatrix(&fFUnitMatrix); 741 CGAffineTransform transform = MatrixToCGAffineTransform(fFUnitMatrix); 742 743 AutoCFRelease<CTFontDescriptorRef> ctFontDesc; 744 if (fVertical) { 745 AutoCFRelease<CFMutableDictionaryRef> cfAttributes(CFDictionaryCreateMutable( 746 kCFAllocatorDefault, 0, 747 &kCFTypeDictionaryKeyCallBacks, 748 &kCFTypeDictionaryValueCallBacks)); 749 if (cfAttributes) { 750 CTFontOrientation ctOrientation = kCTFontVerticalOrientation; 751 AutoCFRelease<CFNumberRef> cfVertical(CFNumberCreate( 752 kCFAllocatorDefault, kCFNumberSInt32Type, &ctOrientation)); 753 CFDictionaryAddValue(cfAttributes, kCTFontOrientationAttribute, cfVertical); 754 ctFontDesc = CTFontDescriptorCreateWithAttributes(cfAttributes); 755 } 756 } 757 // Since our matrix includes everything, we pass 1 for size. 758 fCTFont = CTFontCreateCopyWithAttributes(ctFont, 1, &transform, ctFontDesc); 759 fCGFont = CTFontCopyGraphicsFont(fCTFont, NULL); 760 if (fVertical) { 761 CGAffineTransform rotateLeft = CGAffineTransformMake(0, -1, 1, 0, 0, 0); 762 transform = CGAffineTransformConcat(rotateLeft, transform); 763 fCTVerticalFont = CTFontCreateCopyWithAttributes(ctFont, 1, &transform, NULL); 764 } 765 766 SkScalar emPerFUnit = SkScalarInvert(SkIntToScalar(CGFontGetUnitsPerEm(fCGFont))); 767 fFUnitMatrix.preScale(emPerFUnit, -emPerFUnit); 768 } 769 770 CGRGBPixel* Offscreen::getCG(const SkScalerContext_Mac& context, const SkGlyph& glyph, 771 CGGlyph glyphID, size_t* rowBytesPtr, 772 bool generateA8FromLCD) { 773 if (!fRGBSpace) { 774 //It doesn't appear to matter what color space is specified. 775 //Regular blends and antialiased text are always (s*a + d*(1-a)) 776 //and smoothed text is always g=2.0. 777 fRGBSpace = CGColorSpaceCreateDeviceRGB(); 778 } 779 780 // default to kBW_Format 781 bool doAA = false; 782 bool doLCD = false; 783 784 if (SkMask::kBW_Format != glyph.fMaskFormat) { 785 doLCD = true; 786 doAA = true; 787 } 788 789 // FIXME: lcd smoothed un-hinted rasterization unsupported. 790 if (!generateA8FromLCD && SkMask::kA8_Format == glyph.fMaskFormat) { 791 doLCD = false; 792 doAA = true; 793 } 794 795 size_t rowBytes = fSize.fWidth * sizeof(CGRGBPixel); 796 if (!fCG || fSize.fWidth < glyph.fWidth || fSize.fHeight < glyph.fHeight) { 797 if (fSize.fWidth < glyph.fWidth) { 798 fSize.fWidth = RoundSize(glyph.fWidth); 799 } 800 if (fSize.fHeight < glyph.fHeight) { 801 fSize.fHeight = RoundSize(glyph.fHeight); 802 } 803 804 rowBytes = fSize.fWidth * sizeof(CGRGBPixel); 805 void* image = fImageStorage.reset(rowBytes * fSize.fHeight); 806 fCG = CGBitmapContextCreate(image, fSize.fWidth, fSize.fHeight, 8, 807 rowBytes, fRGBSpace, BITMAP_INFO_RGB); 808 809 // skia handles quantization itself, so we disable this for cg to get 810 // full fractional data from them. 811 CGContextSetAllowsFontSubpixelQuantization(fCG, false); 812 CGContextSetShouldSubpixelQuantizeFonts(fCG, false); 813 814 CGContextSetTextDrawingMode(fCG, kCGTextFill); 815 CGContextSetFont(fCG, context.fCGFont); 816 CGContextSetFontSize(fCG, 1 /*CTFontGetSize(context.fCTFont)*/); 817 CGContextSetTextMatrix(fCG, CTFontGetMatrix(context.fCTFont)); 818 819 // Because CG always draws from the horizontal baseline, 820 // if there is a non-integral translation from the horizontal origin to the vertical origin, 821 // then CG cannot draw the glyph in the correct location without subpixel positioning. 822 CGContextSetAllowsFontSubpixelPositioning(fCG, context.fDoSubPosition || context.fVertical); 823 CGContextSetShouldSubpixelPositionFonts(fCG, context.fDoSubPosition || context.fVertical); 824 825 // Draw white on black to create mask. 826 // TODO: Draw black on white and invert, CG has a special case codepath. 827 CGContextSetGrayFillColor(fCG, 1.0f, 1.0f); 828 829 // force our checks below to happen 830 fDoAA = !doAA; 831 fDoLCD = !doLCD; 832 } 833 834 if (fDoAA != doAA) { 835 CGContextSetShouldAntialias(fCG, doAA); 836 fDoAA = doAA; 837 } 838 if (fDoLCD != doLCD) { 839 CGContextSetShouldSmoothFonts(fCG, doLCD); 840 fDoLCD = doLCD; 841 } 842 843 CGRGBPixel* image = (CGRGBPixel*)fImageStorage.get(); 844 // skip rows based on the glyph's height 845 image += (fSize.fHeight - glyph.fHeight) * fSize.fWidth; 846 847 // erase to black 848 sk_memset_rect32(image, 0, glyph.fWidth, glyph.fHeight, rowBytes); 849 850 float subX = 0; 851 float subY = 0; 852 if (context.fDoSubPosition) { 853 subX = SkFixedToFloat(glyph.getSubXFixed()); 854 subY = SkFixedToFloat(glyph.getSubYFixed()); 855 } 856 857 // CGContextShowGlyphsAtPoint always draws using the horizontal baseline origin. 858 if (context.fVertical) { 859 SkPoint offset; 860 context.getVerticalOffset(glyphID, &offset); 861 subX += offset.fX; 862 subY += offset.fY; 863 } 864 865 CGContextShowGlyphsAtPoint(fCG, -glyph.fLeft + subX, 866 glyph.fTop + glyph.fHeight - subY, 867 &glyphID, 1); 868 869 SkASSERT(rowBytesPtr); 870 *rowBytesPtr = rowBytes; 871 return image; 872 } 873 874 void SkScalerContext_Mac::getVerticalOffset(CGGlyph glyphID, SkPoint* offset) const { 875 // Snow Leopard returns cgVertOffset in completely un-transformed FUnits (em space, y up). 876 // Lion and Leopard return cgVertOffset in CG units (pixels, y up). 877 CGSize cgVertOffset; 878 CTFontGetVerticalTranslationsForGlyphs(fCTFont, &glyphID, &cgVertOffset, 1); 879 880 SkPoint skVertOffset = { CGToScalar(cgVertOffset.width), CGToScalar(cgVertOffset.height) }; 881 if (isSnowLeopard()) { 882 // From FUnits (em space, y up) to SkGlyph units (pixels, y down). 883 fFUnitMatrix.mapPoints(&skVertOffset, 1); 884 } else { 885 // From CG units (pixels, y up) to SkGlyph units (pixels, y down). 886 skVertOffset.fY = -skVertOffset.fY; 887 } 888 889 *offset = skVertOffset; 890 } 891 892 uint16_t SkScalerContext_Mac::getFBoundingBoxesGlyphOffset() { 893 if (fFBoundingBoxesGlyphOffset) { 894 return fFBoundingBoxesGlyphOffset; 895 } 896 fFBoundingBoxesGlyphOffset = fGlyphCount; // fallback for all fonts 897 AutoCGTable<SkOTTableHorizontalHeader> hheaTable(fCGFont); 898 if (hheaTable.fData) { 899 fFBoundingBoxesGlyphOffset = SkEndian_SwapBE16(hheaTable->numberOfHMetrics); 900 } 901 return fFBoundingBoxesGlyphOffset; 902 } 903 904 bool SkScalerContext_Mac::generateBBoxes() { 905 if (fGeneratedFBoundingBoxes) { 906 return NULL != fFBoundingBoxes.get(); 907 } 908 fGeneratedFBoundingBoxes = true; 909 910 AutoCGTable<SkOTTableHead> headTable(fCGFont); 911 if (!headTable.fData) { 912 return false; 913 } 914 915 AutoCGTable<SkOTTableIndexToLocation> locaTable(fCGFont); 916 if (!locaTable.fData) { 917 return false; 918 } 919 920 AutoCGTable<SkOTTableGlyph> glyfTable(fCGFont); 921 if (!glyfTable.fData) { 922 return false; 923 } 924 925 uint16_t entries = fGlyphCount - fFBoundingBoxesGlyphOffset; 926 fFBoundingBoxes.reset(entries); 927 928 SkOTTableHead::IndexToLocFormat locaFormat = headTable->indexToLocFormat; 929 SkOTTableGlyph::Iterator glyphDataIter(*glyfTable.fData, *locaTable.fData, locaFormat); 930 glyphDataIter.advance(fFBoundingBoxesGlyphOffset); 931 for (uint16_t boundingBoxesIndex = 0; boundingBoxesIndex < entries; ++boundingBoxesIndex) { 932 const SkOTTableGlyphData* glyphData = glyphDataIter.next(); 933 GlyphRect& rect = fFBoundingBoxes[boundingBoxesIndex]; 934 rect.fMinX = SkEndian_SwapBE16(glyphData->xMin); 935 rect.fMinY = SkEndian_SwapBE16(glyphData->yMin); 936 rect.fMaxX = SkEndian_SwapBE16(glyphData->xMax); 937 rect.fMaxY = SkEndian_SwapBE16(glyphData->yMax); 938 } 939 940 return true; 941 } 942 943 unsigned SkScalerContext_Mac::generateGlyphCount(void) { 944 return fGlyphCount; 945 } 946 947 uint16_t SkScalerContext_Mac::generateCharToGlyph(SkUnichar uni) { 948 CGGlyph cgGlyph; 949 UniChar theChar; 950 951 // Validate our parameters and state 952 SkASSERT(uni <= 0x0000FFFF); 953 SkASSERT(sizeof(CGGlyph) <= sizeof(uint16_t)); 954 955 // Get the glyph 956 theChar = (UniChar) uni; 957 958 if (!CTFontGetGlyphsForCharacters(fCTFont, &theChar, &cgGlyph, 1)) { 959 cgGlyph = 0; 960 } 961 962 return cgGlyph; 963 } 964 965 void SkScalerContext_Mac::generateAdvance(SkGlyph* glyph) { 966 this->generateMetrics(glyph); 967 } 968 969 void SkScalerContext_Mac::generateMetrics(SkGlyph* glyph) { 970 const CGGlyph cgGlyph = (CGGlyph) glyph->getGlyphID(fBaseGlyphCount); 971 glyph->zeroMetrics(); 972 973 // The following block produces cgAdvance in CG units (pixels, y up). 974 CGSize cgAdvance; 975 if (fVertical) { 976 CTFontGetAdvancesForGlyphs(fCTVerticalFont, kCTFontVerticalOrientation, 977 &cgGlyph, &cgAdvance, 1); 978 } else { 979 CTFontGetAdvancesForGlyphs(fCTFont, kCTFontHorizontalOrientation, 980 &cgGlyph, &cgAdvance, 1); 981 } 982 glyph->fAdvanceX = SkFloatToFixed_Check(cgAdvance.width); 983 glyph->fAdvanceY = -SkFloatToFixed_Check(cgAdvance.height); 984 985 // The following produces skBounds in SkGlyph units (pixels, y down), 986 // or returns early if skBounds would be empty. 987 SkRect skBounds; 988 989 // On Mountain Lion, CTFontGetBoundingRectsForGlyphs with kCTFontVerticalOrientation and 990 // CTFontGetVerticalTranslationsForGlyphs do not agree when using OTF CFF fonts. 991 // For TTF fonts these two do agree and we can use CTFontGetBoundingRectsForGlyphs to get 992 // the bounding box and CTFontGetVerticalTranslationsForGlyphs to then draw the glyph 993 // inside that bounding box. However, with OTF CFF fonts this does not work. It appears that 994 // CTFontGetBoundingRectsForGlyphs with kCTFontVerticalOrientation on OTF CFF fonts tries 995 // to center the glyph along the vertical baseline and also perform some mysterious shift 996 // along the baseline. CTFontGetVerticalTranslationsForGlyphs does not appear to perform 997 // these steps. 998 // 999 // It is not known which is correct (or if either is correct). However, we must always draw 1000 // from the horizontal origin and must use CTFontGetVerticalTranslationsForGlyphs to draw. 1001 // As a result, we do not call CTFontGetBoundingRectsForGlyphs for vertical glyphs. 1002 1003 // On Snow Leopard, CTFontGetBoundingRectsForGlyphs ignores kCTFontVerticalOrientation and 1004 // returns horizontal bounds. 1005 1006 // On Lion and Mountain Lion, CTFontGetBoundingRectsForGlyphs has a bug which causes it to 1007 // return a bad value in cgBounds.origin.x for SFNT fonts whose hhea::numberOfHMetrics is 1008 // less than its maxp::numGlyphs. When this is the case we try to read the bounds from the 1009 // font directly. 1010 if ((isLion() || isMountainLion()) && 1011 (cgGlyph < fGlyphCount && cgGlyph >= getFBoundingBoxesGlyphOffset() && generateBBoxes())) 1012 { 1013 const GlyphRect& gRect = fFBoundingBoxes[cgGlyph - fFBoundingBoxesGlyphOffset]; 1014 if (gRect.fMinX >= gRect.fMaxX || gRect.fMinY >= gRect.fMaxY) { 1015 return; 1016 } 1017 skBounds = SkRect::MakeLTRB(gRect.fMinX, gRect.fMinY, gRect.fMaxX, gRect.fMaxY); 1018 // From FUnits (em space, y up) to SkGlyph units (pixels, y down). 1019 fFUnitMatrix.mapRect(&skBounds); 1020 1021 } else { 1022 // CTFontGetBoundingRectsForGlyphs produces cgBounds in CG units (pixels, y up). 1023 CGRect cgBounds; 1024 CTFontGetBoundingRectsForGlyphs(fCTFont, kCTFontHorizontalOrientation, 1025 &cgGlyph, &cgBounds, 1); 1026 1027 // BUG? 1028 // 0x200B (zero-advance space) seems to return a huge (garbage) bounds, when 1029 // it should be empty. So, if we see a zero-advance, we check if it has an 1030 // empty path or not, and if so, we jam the bounds to 0. Hopefully a zero-advance 1031 // is rare, so we won't incur a big performance cost for this extra check. 1032 if (0 == cgAdvance.width && 0 == cgAdvance.height) { 1033 AutoCFRelease<CGPathRef> path(CTFontCreatePathForGlyph(fCTFont, cgGlyph, NULL)); 1034 if (NULL == path || CGPathIsEmpty(path)) { 1035 return; 1036 } 1037 } 1038 1039 if (CGRectIsEmpty_inline(cgBounds)) { 1040 return; 1041 } 1042 1043 // Convert cgBounds to SkGlyph units (pixels, y down). 1044 skBounds = SkRect::MakeXYWH(cgBounds.origin.x, -cgBounds.origin.y - cgBounds.size.height, 1045 cgBounds.size.width, cgBounds.size.height); 1046 } 1047 1048 if (fVertical) { 1049 // Due to all of the vertical bounds bugs, skBounds is always the horizontal bounds. 1050 // Convert these horizontal bounds into vertical bounds. 1051 SkPoint offset; 1052 getVerticalOffset(cgGlyph, &offset); 1053 skBounds.offset(offset); 1054 } 1055 1056 // Currently the bounds are based on being rendered at (0,0). 1057 // The top left must not move, since that is the base from which subpixel positioning is offset. 1058 if (fDoSubPosition) { 1059 skBounds.fRight += SkFixedToFloat(glyph->getSubXFixed()); 1060 skBounds.fBottom += SkFixedToFloat(glyph->getSubYFixed()); 1061 } 1062 1063 SkIRect skIBounds; 1064 skBounds.roundOut(&skIBounds); 1065 // Expand the bounds by 1 pixel, to give CG room for anti-aliasing. 1066 // Note that this outset is to allow room for LCD smoothed glyphs. However, the correct outset 1067 // is not currently known, as CG dilates the outlines by some percentage. 1068 // Note that if this context is A8 and not back-forming from LCD, there is no need to outset. 1069 skIBounds.outset(1, 1); 1070 glyph->fLeft = SkToS16(skIBounds.fLeft); 1071 glyph->fTop = SkToS16(skIBounds.fTop); 1072 glyph->fWidth = SkToU16(skIBounds.width()); 1073 glyph->fHeight = SkToU16(skIBounds.height()); 1074 1075 #ifdef HACK_COLORGLYPHS 1076 glyph->fMaskFormat = SkMask::kARGB32_Format; 1077 #endif 1078 } 1079 1080 #include "SkColorPriv.h" 1081 1082 static void build_power_table(uint8_t table[], float ee) { 1083 for (int i = 0; i < 256; i++) { 1084 float x = i / 255.f; 1085 x = sk_float_pow(x, ee); 1086 int xx = SkScalarRoundToInt(SkFloatToScalar(x * 255)); 1087 table[i] = SkToU8(xx); 1088 } 1089 } 1090 1091 /** 1092 * This will invert the gamma applied by CoreGraphics, so we can get linear 1093 * values. 1094 * 1095 * CoreGraphics obscurely defaults to 2.0 as the smoothing gamma value. 1096 * The color space used does not appear to affect this choice. 1097 */ 1098 static const uint8_t* getInverseGammaTableCoreGraphicSmoothing() { 1099 static bool gInited; 1100 static uint8_t gTableCoreGraphicsSmoothing[256]; 1101 if (!gInited) { 1102 build_power_table(gTableCoreGraphicsSmoothing, 2.0f); 1103 gInited = true; 1104 } 1105 return gTableCoreGraphicsSmoothing; 1106 } 1107 1108 static void cgpixels_to_bits(uint8_t dst[], const CGRGBPixel src[], int count) { 1109 while (count > 0) { 1110 uint8_t mask = 0; 1111 for (int i = 7; i >= 0; --i) { 1112 mask |= (CGRGBPixel_getAlpha(*src++) >> 7) << i; 1113 if (0 == --count) { 1114 break; 1115 } 1116 } 1117 *dst++ = mask; 1118 } 1119 } 1120 1121 template<bool APPLY_PREBLEND> 1122 static inline uint8_t rgb_to_a8(CGRGBPixel rgb, const uint8_t* table8) { 1123 U8CPU r = (rgb >> 16) & 0xFF; 1124 U8CPU g = (rgb >> 8) & 0xFF; 1125 U8CPU b = (rgb >> 0) & 0xFF; 1126 return sk_apply_lut_if<APPLY_PREBLEND>(SkComputeLuminance(r, g, b), table8); 1127 } 1128 template<bool APPLY_PREBLEND> 1129 static void rgb_to_a8(const CGRGBPixel* SK_RESTRICT cgPixels, size_t cgRowBytes, 1130 const SkGlyph& glyph, const uint8_t* table8) { 1131 const int width = glyph.fWidth; 1132 size_t dstRB = glyph.rowBytes(); 1133 uint8_t* SK_RESTRICT dst = (uint8_t*)glyph.fImage; 1134 1135 for (int y = 0; y < glyph.fHeight; y++) { 1136 for (int i = 0; i < width; ++i) { 1137 dst[i] = rgb_to_a8<APPLY_PREBLEND>(cgPixels[i], table8); 1138 } 1139 cgPixels = (CGRGBPixel*)((char*)cgPixels + cgRowBytes); 1140 dst += dstRB; 1141 } 1142 } 1143 1144 template<bool APPLY_PREBLEND> 1145 static inline uint16_t rgb_to_lcd16(CGRGBPixel rgb, const uint8_t* tableR, 1146 const uint8_t* tableG, 1147 const uint8_t* tableB) { 1148 U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 16) & 0xFF, tableR); 1149 U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 8) & 0xFF, tableG); 1150 U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 0) & 0xFF, tableB); 1151 return SkPack888ToRGB16(r, g, b); 1152 } 1153 template<bool APPLY_PREBLEND> 1154 static void rgb_to_lcd16(const CGRGBPixel* SK_RESTRICT cgPixels, size_t cgRowBytes, const SkGlyph& glyph, 1155 const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) { 1156 const int width = glyph.fWidth; 1157 size_t dstRB = glyph.rowBytes(); 1158 uint16_t* SK_RESTRICT dst = (uint16_t*)glyph.fImage; 1159 1160 for (int y = 0; y < glyph.fHeight; y++) { 1161 for (int i = 0; i < width; i++) { 1162 dst[i] = rgb_to_lcd16<APPLY_PREBLEND>(cgPixels[i], tableR, tableG, tableB); 1163 } 1164 cgPixels = (CGRGBPixel*)((char*)cgPixels + cgRowBytes); 1165 dst = (uint16_t*)((char*)dst + dstRB); 1166 } 1167 } 1168 1169 template<bool APPLY_PREBLEND> 1170 static inline uint32_t rgb_to_lcd32(CGRGBPixel rgb, const uint8_t* tableR, 1171 const uint8_t* tableG, 1172 const uint8_t* tableB) { 1173 U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 16) & 0xFF, tableR); 1174 U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 8) & 0xFF, tableG); 1175 U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 0) & 0xFF, tableB); 1176 return SkPackARGB32(0xFF, r, g, b); 1177 } 1178 template<bool APPLY_PREBLEND> 1179 static void rgb_to_lcd32(const CGRGBPixel* SK_RESTRICT cgPixels, size_t cgRowBytes, const SkGlyph& glyph, 1180 const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) { 1181 const int width = glyph.fWidth; 1182 size_t dstRB = glyph.rowBytes(); 1183 uint32_t* SK_RESTRICT dst = (uint32_t*)glyph.fImage; 1184 for (int y = 0; y < glyph.fHeight; y++) { 1185 for (int i = 0; i < width; i++) { 1186 dst[i] = rgb_to_lcd32<APPLY_PREBLEND>(cgPixels[i], tableR, tableG, tableB); 1187 } 1188 cgPixels = (CGRGBPixel*)((char*)cgPixels + cgRowBytes); 1189 dst = (uint32_t*)((char*)dst + dstRB); 1190 } 1191 } 1192 1193 #ifdef HACK_COLORGLYPHS 1194 // hack to colorize the output for testing kARGB32_Format 1195 static SkPMColor cgpixels_to_pmcolor(CGRGBPixel rgb, const SkGlyph& glyph, 1196 int x, int y) { 1197 U8CPU r = (rgb >> 16) & 0xFF; 1198 U8CPU g = (rgb >> 8) & 0xFF; 1199 U8CPU b = (rgb >> 0) & 0xFF; 1200 unsigned a = SkComputeLuminance(r, g, b); 1201 1202 // compute gradient from x,y 1203 r = x * 255 / glyph.fWidth; 1204 g = 0; 1205 b = (glyph.fHeight - y) * 255 / glyph.fHeight; 1206 return SkPreMultiplyARGB(a, r, g, b); // red 1207 } 1208 #endif 1209 1210 template <typename T> T* SkTAddByteOffset(T* ptr, size_t byteOffset) { 1211 return (T*)((char*)ptr + byteOffset); 1212 } 1213 1214 void SkScalerContext_Mac::generateImage(const SkGlyph& glyph) { 1215 CGGlyph cgGlyph = (CGGlyph) glyph.getGlyphID(fBaseGlyphCount); 1216 1217 // FIXME: lcd smoothed un-hinted rasterization unsupported. 1218 bool generateA8FromLCD = fRec.getHinting() != SkPaint::kNo_Hinting; 1219 1220 // Draw the glyph 1221 size_t cgRowBytes; 1222 CGRGBPixel* cgPixels = fOffscreen.getCG(*this, glyph, cgGlyph, &cgRowBytes, generateA8FromLCD); 1223 if (cgPixels == NULL) { 1224 return; 1225 } 1226 1227 //TODO: see if drawing black on white and inverting is faster (at least in 1228 //lcd case) as core graphics appears to have special case code for drawing 1229 //black text. 1230 1231 // Fix the glyph 1232 const bool isLCD = isLCDFormat(glyph.fMaskFormat); 1233 if (isLCD || (glyph.fMaskFormat == SkMask::kA8_Format && supports_LCD() && generateA8FromLCD)) { 1234 const uint8_t* table = getInverseGammaTableCoreGraphicSmoothing(); 1235 1236 //Note that the following cannot really be integrated into the 1237 //pre-blend, since we may not be applying the pre-blend; when we aren't 1238 //applying the pre-blend it means that a filter wants linear anyway. 1239 //Other code may also be applying the pre-blend, so we'd need another 1240 //one with this and one without. 1241 CGRGBPixel* addr = cgPixels; 1242 for (int y = 0; y < glyph.fHeight; ++y) { 1243 for (int x = 0; x < glyph.fWidth; ++x) { 1244 int r = (addr[x] >> 16) & 0xFF; 1245 int g = (addr[x] >> 8) & 0xFF; 1246 int b = (addr[x] >> 0) & 0xFF; 1247 addr[x] = (table[r] << 16) | (table[g] << 8) | table[b]; 1248 } 1249 addr = SkTAddByteOffset(addr, cgRowBytes); 1250 } 1251 } 1252 1253 // Convert glyph to mask 1254 switch (glyph.fMaskFormat) { 1255 case SkMask::kLCD32_Format: { 1256 if (fPreBlend.isApplicable()) { 1257 rgb_to_lcd32<true>(cgPixels, cgRowBytes, glyph, 1258 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB); 1259 } else { 1260 rgb_to_lcd32<false>(cgPixels, cgRowBytes, glyph, 1261 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB); 1262 } 1263 } break; 1264 case SkMask::kLCD16_Format: { 1265 if (fPreBlend.isApplicable()) { 1266 rgb_to_lcd16<true>(cgPixels, cgRowBytes, glyph, 1267 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB); 1268 } else { 1269 rgb_to_lcd16<false>(cgPixels, cgRowBytes, glyph, 1270 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB); 1271 } 1272 } break; 1273 case SkMask::kA8_Format: { 1274 if (fPreBlend.isApplicable()) { 1275 rgb_to_a8<true>(cgPixels, cgRowBytes, glyph, fPreBlend.fG); 1276 } else { 1277 rgb_to_a8<false>(cgPixels, cgRowBytes, glyph, fPreBlend.fG); 1278 } 1279 } break; 1280 case SkMask::kBW_Format: { 1281 const int width = glyph.fWidth; 1282 size_t dstRB = glyph.rowBytes(); 1283 uint8_t* dst = (uint8_t*)glyph.fImage; 1284 for (int y = 0; y < glyph.fHeight; y++) { 1285 cgpixels_to_bits(dst, cgPixels, width); 1286 cgPixels = (CGRGBPixel*)((char*)cgPixels + cgRowBytes); 1287 dst += dstRB; 1288 } 1289 } break; 1290 #ifdef HACK_COLORGLYPHS 1291 case SkMask::kARGB32_Format: { 1292 const int width = glyph.fWidth; 1293 size_t dstRB = glyph.rowBytes(); 1294 SkPMColor* dst = (SkPMColor*)glyph.fImage; 1295 for (int y = 0; y < glyph.fHeight; y++) { 1296 for (int x = 0; x < width; ++x) { 1297 dst[x] = cgpixels_to_pmcolor(cgPixels[x], glyph, x, y); 1298 } 1299 cgPixels = (CGRGBPixel*)((char*)cgPixels + cgRowBytes); 1300 dst = (SkPMColor*)((char*)dst + dstRB); 1301 } 1302 } break; 1303 #endif 1304 default: 1305 SkDEBUGFAIL("unexpected mask format"); 1306 break; 1307 } 1308 } 1309 1310 /* 1311 * Our subpixel resolution is only 2 bits in each direction, so a scale of 4 1312 * seems sufficient, and possibly even correct, to allow the hinted outline 1313 * to be subpixel positioned. 1314 */ 1315 #define kScaleForSubPixelPositionHinting (4.0f) 1316 1317 void SkScalerContext_Mac::generatePath(const SkGlyph& glyph, SkPath* path) { 1318 CTFontRef font = fCTFont; 1319 SkScalar scaleX = SK_Scalar1; 1320 SkScalar scaleY = SK_Scalar1; 1321 1322 /* 1323 * For subpixel positioning, we want to return an unhinted outline, so it 1324 * can be positioned nicely at fractional offsets. However, we special-case 1325 * if the baseline of the (horizontal) text is axis-aligned. In those cases 1326 * we want to retain hinting in the direction orthogonal to the baseline. 1327 * e.g. for horizontal baseline, we want to retain hinting in Y. 1328 * The way we remove hinting is to scale the font by some value (4) in that 1329 * direction, ask for the path, and then scale the path back down. 1330 */ 1331 if (fRec.fFlags & SkScalerContext::kSubpixelPositioning_Flag) { 1332 SkMatrix m; 1333 fRec.getSingleMatrix(&m); 1334 1335 // start out by assuming that we want no hining in X and Y 1336 scaleX = scaleY = SkFloatToScalar(kScaleForSubPixelPositionHinting); 1337 // now see if we need to restore hinting for axis-aligned baselines 1338 switch (SkComputeAxisAlignmentForHText(m)) { 1339 case kX_SkAxisAlignment: 1340 scaleY = SK_Scalar1; // want hinting in the Y direction 1341 break; 1342 case kY_SkAxisAlignment: 1343 scaleX = SK_Scalar1; // want hinting in the X direction 1344 break; 1345 default: 1346 break; 1347 } 1348 1349 CGAffineTransform xform = MatrixToCGAffineTransform(m, scaleX, scaleY); 1350 // need to release font when we're done 1351 font = CTFontCreateCopyWithAttributes(fCTFont, 1, &xform, NULL); 1352 } 1353 1354 CGGlyph cgGlyph = (CGGlyph)glyph.getGlyphID(fBaseGlyphCount); 1355 AutoCFRelease<CGPathRef> cgPath(CTFontCreatePathForGlyph(font, cgGlyph, NULL)); 1356 1357 path->reset(); 1358 if (cgPath != NULL) { 1359 CGPathApply(cgPath, path, SkScalerContext_Mac::CTPathElement); 1360 } 1361 1362 if (fDoSubPosition) { 1363 SkMatrix m; 1364 m.setScale(SkScalarInvert(scaleX), SkScalarInvert(scaleY)); 1365 path->transform(m); 1366 // balance the call to CTFontCreateCopyWithAttributes 1367 CFSafeRelease(font); 1368 } 1369 if (fVertical) { 1370 SkPoint offset; 1371 getVerticalOffset(cgGlyph, &offset); 1372 path->offset(offset.fX, offset.fY); 1373 } 1374 } 1375 1376 void SkScalerContext_Mac::generateFontMetrics(SkPaint::FontMetrics* mx, 1377 SkPaint::FontMetrics* my) { 1378 CGRect theBounds = CTFontGetBoundingBox(fCTFont); 1379 1380 SkPaint::FontMetrics theMetrics; 1381 theMetrics.fTop = CGToScalar(-CGRectGetMaxY_inline(theBounds)); 1382 theMetrics.fAscent = CGToScalar(-CTFontGetAscent(fCTFont)); 1383 theMetrics.fDescent = CGToScalar( CTFontGetDescent(fCTFont)); 1384 theMetrics.fBottom = CGToScalar(-CGRectGetMinY_inline(theBounds)); 1385 theMetrics.fLeading = CGToScalar( CTFontGetLeading(fCTFont)); 1386 theMetrics.fAvgCharWidth = CGToScalar( CGRectGetWidth_inline(theBounds)); 1387 theMetrics.fXMin = CGToScalar( CGRectGetMinX_inline(theBounds)); 1388 theMetrics.fXMax = CGToScalar( CGRectGetMaxX_inline(theBounds)); 1389 theMetrics.fXHeight = CGToScalar( CTFontGetXHeight(fCTFont)); 1390 1391 if (mx != NULL) { 1392 *mx = theMetrics; 1393 } 1394 if (my != NULL) { 1395 *my = theMetrics; 1396 } 1397 } 1398 1399 void SkScalerContext_Mac::CTPathElement(void *info, const CGPathElement *element) { 1400 SkPath* skPath = (SkPath*)info; 1401 1402 // Process the path element 1403 switch (element->type) { 1404 case kCGPathElementMoveToPoint: 1405 skPath->moveTo(element->points[0].x, -element->points[0].y); 1406 break; 1407 1408 case kCGPathElementAddLineToPoint: 1409 skPath->lineTo(element->points[0].x, -element->points[0].y); 1410 break; 1411 1412 case kCGPathElementAddQuadCurveToPoint: 1413 skPath->quadTo(element->points[0].x, -element->points[0].y, 1414 element->points[1].x, -element->points[1].y); 1415 break; 1416 1417 case kCGPathElementAddCurveToPoint: 1418 skPath->cubicTo(element->points[0].x, -element->points[0].y, 1419 element->points[1].x, -element->points[1].y, 1420 element->points[2].x, -element->points[2].y); 1421 break; 1422 1423 case kCGPathElementCloseSubpath: 1424 skPath->close(); 1425 break; 1426 1427 default: 1428 SkDEBUGFAIL("Unknown path element!"); 1429 break; 1430 } 1431 } 1432 1433 1434 /////////////////////////////////////////////////////////////////////////////// 1435 1436 // Returns NULL on failure 1437 // Call must still manage its ownership of provider 1438 static SkTypeface* create_from_dataProvider(CGDataProviderRef provider) { 1439 AutoCFRelease<CGFontRef> cg(CGFontCreateWithDataProvider(provider)); 1440 if (NULL == cg) { 1441 return NULL; 1442 } 1443 CTFontRef ct = CTFontCreateWithGraphicsFont(cg, 0, NULL, NULL); 1444 return cg ? SkCreateTypefaceFromCTFont(ct) : NULL; 1445 } 1446 1447 // Web fonts added to the the CTFont registry do not return their character set. 1448 // Iterate through the font in this case. The existing caller caches the result, 1449 // so the performance impact isn't too bad. 1450 static void populate_glyph_to_unicode_slow(CTFontRef ctFont, CFIndex glyphCount, 1451 SkTDArray<SkUnichar>* glyphToUnicode) { 1452 glyphToUnicode->setCount(glyphCount); 1453 SkUnichar* out = glyphToUnicode->begin(); 1454 sk_bzero(out, glyphCount * sizeof(SkUnichar)); 1455 UniChar unichar = 0; 1456 while (glyphCount > 0) { 1457 CGGlyph glyph; 1458 if (CTFontGetGlyphsForCharacters(ctFont, &unichar, &glyph, 1)) { 1459 out[glyph] = unichar; 1460 --glyphCount; 1461 } 1462 if (++unichar == 0) { 1463 break; 1464 } 1465 } 1466 } 1467 1468 // Construct Glyph to Unicode table. 1469 // Unicode code points that require conjugate pairs in utf16 are not 1470 // supported. 1471 static void populate_glyph_to_unicode(CTFontRef ctFont, CFIndex glyphCount, 1472 SkTDArray<SkUnichar>* glyphToUnicode) { 1473 AutoCFRelease<CFCharacterSetRef> charSet(CTFontCopyCharacterSet(ctFont)); 1474 if (!charSet) { 1475 populate_glyph_to_unicode_slow(ctFont, glyphCount, glyphToUnicode); 1476 return; 1477 } 1478 1479 AutoCFRelease<CFDataRef> bitmap(CFCharacterSetCreateBitmapRepresentation(kCFAllocatorDefault, 1480 charSet)); 1481 if (!bitmap) { 1482 return; 1483 } 1484 CFIndex length = CFDataGetLength(bitmap); 1485 if (!length) { 1486 return; 1487 } 1488 if (length > 8192) { 1489 // TODO: Add support for Unicode above 0xFFFF 1490 // Consider only the BMP portion of the Unicode character points. 1491 // The bitmap may contain other planes, up to plane 16. 1492 // See http://developer.apple.com/library/ios/#documentation/CoreFoundation/Reference/CFCharacterSetRef/Reference/reference.html 1493 length = 8192; 1494 } 1495 const UInt8* bits = CFDataGetBytePtr(bitmap); 1496 glyphToUnicode->setCount(glyphCount); 1497 SkUnichar* out = glyphToUnicode->begin(); 1498 sk_bzero(out, glyphCount * sizeof(SkUnichar)); 1499 for (int i = 0; i < length; i++) { 1500 int mask = bits[i]; 1501 if (!mask) { 1502 continue; 1503 } 1504 for (int j = 0; j < 8; j++) { 1505 CGGlyph glyph; 1506 UniChar unichar = static_cast<UniChar>((i << 3) + j); 1507 if (mask & (1 << j) && CTFontGetGlyphsForCharacters(ctFont, &unichar, &glyph, 1)) { 1508 out[glyph] = unichar; 1509 } 1510 } 1511 } 1512 } 1513 1514 static bool getWidthAdvance(CTFontRef ctFont, int gId, int16_t* data) { 1515 CGSize advance; 1516 advance.width = 0; 1517 CGGlyph glyph = gId; 1518 CTFontGetAdvancesForGlyphs(ctFont, kCTFontHorizontalOrientation, &glyph, &advance, 1); 1519 *data = sk_float_round2int(advance.width); 1520 return true; 1521 } 1522 1523 // we might move this into our CGUtils... 1524 static void CFStringToSkString(CFStringRef src, SkString* dst) { 1525 // Reserve enough room for the worst-case string, 1526 // plus 1 byte for the trailing null. 1527 CFIndex length = CFStringGetMaximumSizeForEncoding(CFStringGetLength(src), 1528 kCFStringEncodingUTF8) + 1; 1529 dst->resize(length); 1530 CFStringGetCString(src, dst->writable_str(), length, kCFStringEncodingUTF8); 1531 // Resize to the actual UTF-8 length used, stripping the null character. 1532 dst->resize(strlen(dst->c_str())); 1533 } 1534 1535 SkAdvancedTypefaceMetrics* SkTypeface_Mac::onGetAdvancedTypefaceMetrics( 1536 SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo, 1537 const uint32_t* glyphIDs, 1538 uint32_t glyphIDsCount) const { 1539 1540 CTFontRef originalCTFont = fFontRef.get(); 1541 AutoCFRelease<CTFontRef> ctFont(CTFontCreateCopyWithAttributes( 1542 originalCTFont, CTFontGetUnitsPerEm(originalCTFont), NULL, NULL)); 1543 SkAdvancedTypefaceMetrics* info = new SkAdvancedTypefaceMetrics; 1544 1545 { 1546 AutoCFRelease<CFStringRef> fontName(CTFontCopyPostScriptName(ctFont)); 1547 CFStringToSkString(fontName, &info->fFontName); 1548 } 1549 1550 info->fMultiMaster = false; 1551 CFIndex glyphCount = CTFontGetGlyphCount(ctFont); 1552 info->fLastGlyphID = SkToU16(glyphCount - 1); 1553 info->fEmSize = CTFontGetUnitsPerEm(ctFont); 1554 1555 if (perGlyphInfo & SkAdvancedTypefaceMetrics::kToUnicode_PerGlyphInfo) { 1556 populate_glyph_to_unicode(ctFont, glyphCount, &info->fGlyphToUnicode); 1557 } 1558 1559 info->fStyle = 0; 1560 1561 // If it's not a truetype font, mark it as 'other'. Assume that TrueType 1562 // fonts always have both glyf and loca tables. At the least, this is what 1563 // sfntly needs to subset the font. CTFontCopyAttribute() does not always 1564 // succeed in determining this directly. 1565 if (!this->getTableSize('glyf') || !this->getTableSize('loca')) { 1566 info->fType = SkAdvancedTypefaceMetrics::kOther_Font; 1567 info->fItalicAngle = 0; 1568 info->fAscent = 0; 1569 info->fDescent = 0; 1570 info->fStemV = 0; 1571 info->fCapHeight = 0; 1572 info->fBBox = SkIRect::MakeEmpty(); 1573 return info; 1574 } 1575 1576 info->fType = SkAdvancedTypefaceMetrics::kTrueType_Font; 1577 CTFontSymbolicTraits symbolicTraits = CTFontGetSymbolicTraits(ctFont); 1578 if (symbolicTraits & kCTFontMonoSpaceTrait) { 1579 info->fStyle |= SkAdvancedTypefaceMetrics::kFixedPitch_Style; 1580 } 1581 if (symbolicTraits & kCTFontItalicTrait) { 1582 info->fStyle |= SkAdvancedTypefaceMetrics::kItalic_Style; 1583 } 1584 CTFontStylisticClass stylisticClass = symbolicTraits & kCTFontClassMaskTrait; 1585 if (stylisticClass >= kCTFontOldStyleSerifsClass && stylisticClass <= kCTFontSlabSerifsClass) { 1586 info->fStyle |= SkAdvancedTypefaceMetrics::kSerif_Style; 1587 } else if (stylisticClass & kCTFontScriptsClass) { 1588 info->fStyle |= SkAdvancedTypefaceMetrics::kScript_Style; 1589 } 1590 info->fItalicAngle = (int16_t) CTFontGetSlantAngle(ctFont); 1591 info->fAscent = (int16_t) CTFontGetAscent(ctFont); 1592 info->fDescent = (int16_t) CTFontGetDescent(ctFont); 1593 info->fCapHeight = (int16_t) CTFontGetCapHeight(ctFont); 1594 CGRect bbox = CTFontGetBoundingBox(ctFont); 1595 1596 SkRect r; 1597 r.set( CGToScalar(CGRectGetMinX_inline(bbox)), // Left 1598 CGToScalar(CGRectGetMaxY_inline(bbox)), // Top 1599 CGToScalar(CGRectGetMaxX_inline(bbox)), // Right 1600 CGToScalar(CGRectGetMinY_inline(bbox))); // Bottom 1601 1602 r.roundOut(&(info->fBBox)); 1603 1604 // Figure out a good guess for StemV - Min width of i, I, !, 1. 1605 // This probably isn't very good with an italic font. 1606 int16_t min_width = SHRT_MAX; 1607 info->fStemV = 0; 1608 static const UniChar stem_chars[] = {'i', 'I', '!', '1'}; 1609 const size_t count = sizeof(stem_chars) / sizeof(stem_chars[0]); 1610 CGGlyph glyphs[count]; 1611 CGRect boundingRects[count]; 1612 if (CTFontGetGlyphsForCharacters(ctFont, stem_chars, glyphs, count)) { 1613 CTFontGetBoundingRectsForGlyphs(ctFont, kCTFontHorizontalOrientation, 1614 glyphs, boundingRects, count); 1615 for (size_t i = 0; i < count; i++) { 1616 int16_t width = (int16_t) boundingRects[i].size.width; 1617 if (width > 0 && width < min_width) { 1618 min_width = width; 1619 info->fStemV = min_width; 1620 } 1621 } 1622 } 1623 1624 if (false) { // TODO: haven't figured out how to know if font is embeddable 1625 // (information is in the OS/2 table) 1626 info->fType = SkAdvancedTypefaceMetrics::kNotEmbeddable_Font; 1627 } else if (perGlyphInfo & SkAdvancedTypefaceMetrics::kHAdvance_PerGlyphInfo) { 1628 if (info->fStyle & SkAdvancedTypefaceMetrics::kFixedPitch_Style) { 1629 skia_advanced_typeface_metrics_utils::appendRange(&info->fGlyphWidths, 0); 1630 info->fGlyphWidths->fAdvance.append(1, &min_width); 1631 skia_advanced_typeface_metrics_utils::finishRange(info->fGlyphWidths.get(), 0, 1632 SkAdvancedTypefaceMetrics::WidthRange::kDefault); 1633 } else { 1634 info->fGlyphWidths.reset( 1635 skia_advanced_typeface_metrics_utils::getAdvanceData(ctFont.get(), 1636 glyphCount, 1637 glyphIDs, 1638 glyphIDsCount, 1639 &getWidthAdvance)); 1640 } 1641 } 1642 return info; 1643 } 1644 1645 /////////////////////////////////////////////////////////////////////////////// 1646 1647 static SK_SFNT_ULONG get_font_type_tag(const SkTypeface_Mac* typeface) { 1648 CTFontRef ctFont = typeface->fFontRef.get(); 1649 AutoCFRelease<CFNumberRef> fontFormatRef( 1650 static_cast<CFNumberRef>(CTFontCopyAttribute(ctFont, kCTFontFormatAttribute))); 1651 if (!fontFormatRef) { 1652 return 0; 1653 } 1654 1655 SInt32 fontFormatValue; 1656 if (!CFNumberGetValue(fontFormatRef, kCFNumberSInt32Type, &fontFormatValue)) { 1657 return 0; 1658 } 1659 1660 switch (fontFormatValue) { 1661 case kCTFontFormatOpenTypePostScript: 1662 return SkSFNTHeader::fontType_OpenTypeCFF::TAG; 1663 case kCTFontFormatOpenTypeTrueType: 1664 return SkSFNTHeader::fontType_WindowsTrueType::TAG; 1665 case kCTFontFormatTrueType: 1666 return SkSFNTHeader::fontType_MacTrueType::TAG; 1667 case kCTFontFormatPostScript: 1668 return SkSFNTHeader::fontType_PostScript::TAG; 1669 case kCTFontFormatBitmap: 1670 return SkSFNTHeader::fontType_MacTrueType::TAG; 1671 case kCTFontFormatUnrecognized: 1672 default: 1673 //CT seems to be unreliable in being able to obtain the type, 1674 //even if all we want is the first four bytes of the font resource. 1675 //Just the presence of the FontForge 'FFTM' table seems to throw it off. 1676 return SkSFNTHeader::fontType_WindowsTrueType::TAG; 1677 } 1678 } 1679 1680 SkStream* SkTypeface_Mac::onOpenStream(int* ttcIndex) const { 1681 SK_SFNT_ULONG fontType = get_font_type_tag(this); 1682 if (0 == fontType) { 1683 return NULL; 1684 } 1685 1686 // get table tags 1687 int numTables = this->countTables(); 1688 SkTDArray<SkFontTableTag> tableTags; 1689 tableTags.setCount(numTables); 1690 this->getTableTags(tableTags.begin()); 1691 1692 // calc total size for font, save sizes 1693 SkTDArray<size_t> tableSizes; 1694 size_t totalSize = sizeof(SkSFNTHeader) + sizeof(SkSFNTHeader::TableDirectoryEntry) * numTables; 1695 for (int tableIndex = 0; tableIndex < numTables; ++tableIndex) { 1696 size_t tableSize = this->getTableSize(tableTags[tableIndex]); 1697 totalSize += (tableSize + 3) & ~3; 1698 *tableSizes.append() = tableSize; 1699 } 1700 1701 // reserve memory for stream, and zero it (tables must be zero padded) 1702 SkMemoryStream* stream = new SkMemoryStream(totalSize); 1703 char* dataStart = (char*)stream->getMemoryBase(); 1704 sk_bzero(dataStart, totalSize); 1705 char* dataPtr = dataStart; 1706 1707 // compute font header entries 1708 uint16_t entrySelector = 0; 1709 uint16_t searchRange = 1; 1710 while (searchRange < numTables >> 1) { 1711 entrySelector++; 1712 searchRange <<= 1; 1713 } 1714 searchRange <<= 4; 1715 uint16_t rangeShift = (numTables << 4) - searchRange; 1716 1717 // write font header 1718 SkSFNTHeader* header = (SkSFNTHeader*)dataPtr; 1719 header->fontType = fontType; 1720 header->numTables = SkEndian_SwapBE16(numTables); 1721 header->searchRange = SkEndian_SwapBE16(searchRange); 1722 header->entrySelector = SkEndian_SwapBE16(entrySelector); 1723 header->rangeShift = SkEndian_SwapBE16(rangeShift); 1724 dataPtr += sizeof(SkSFNTHeader); 1725 1726 // write tables 1727 SkSFNTHeader::TableDirectoryEntry* entry = (SkSFNTHeader::TableDirectoryEntry*)dataPtr; 1728 dataPtr += sizeof(SkSFNTHeader::TableDirectoryEntry) * numTables; 1729 for (int tableIndex = 0; tableIndex < numTables; ++tableIndex) { 1730 size_t tableSize = tableSizes[tableIndex]; 1731 this->getTableData(tableTags[tableIndex], 0, tableSize, dataPtr); 1732 entry->tag = SkEndian_SwapBE32(tableTags[tableIndex]); 1733 entry->checksum = SkEndian_SwapBE32(SkOTUtils::CalcTableChecksum((SK_OT_ULONG*)dataPtr, 1734 tableSize)); 1735 entry->offset = SkEndian_SwapBE32(dataPtr - dataStart); 1736 entry->logicalLength = SkEndian_SwapBE32(tableSize); 1737 1738 dataPtr += (tableSize + 3) & ~3; 1739 ++entry; 1740 } 1741 1742 return stream; 1743 } 1744 1745 /////////////////////////////////////////////////////////////////////////////// 1746 /////////////////////////////////////////////////////////////////////////////// 1747 1748 int SkTypeface_Mac::onGetUPEM() const { 1749 AutoCFRelease<CGFontRef> cgFont(CTFontCopyGraphicsFont(fFontRef, NULL)); 1750 return CGFontGetUnitsPerEm(cgFont); 1751 } 1752 1753 SkTypeface::LocalizedStrings* SkTypeface_Mac::onCreateFamilyNameIterator() const { 1754 SkTypeface::LocalizedStrings* nameIter = 1755 SkOTUtils::LocalizedStrings_NameTable::CreateForFamilyNames(*this); 1756 if (NULL == nameIter) { 1757 AutoCFRelease<CFStringRef> cfLanguage; 1758 AutoCFRelease<CFStringRef> cfFamilyName( 1759 CTFontCopyLocalizedName(fFontRef, kCTFontFamilyNameKey, &cfLanguage)); 1760 1761 SkString skLanguage; 1762 SkString skFamilyName; 1763 if (cfLanguage.get()) { 1764 CFStringToSkString(cfLanguage.get(), &skLanguage); 1765 } else { 1766 skLanguage = "und"; //undetermined 1767 } 1768 if (cfFamilyName.get()) { 1769 CFStringToSkString(cfFamilyName.get(), &skFamilyName); 1770 } 1771 1772 nameIter = new SkOTUtils::LocalizedStrings_SingleName(skFamilyName, skLanguage); 1773 } 1774 return nameIter; 1775 } 1776 1777 // If, as is the case with web fonts, the CTFont data isn't available, 1778 // the CGFont data may work. While the CGFont may always provide the 1779 // right result, leave the CTFont code path to minimize disruption. 1780 static CFDataRef copyTableFromFont(CTFontRef ctFont, SkFontTableTag tag) { 1781 CFDataRef data = CTFontCopyTable(ctFont, (CTFontTableTag) tag, 1782 kCTFontTableOptionNoOptions); 1783 if (NULL == data) { 1784 AutoCFRelease<CGFontRef> cgFont(CTFontCopyGraphicsFont(ctFont, NULL)); 1785 data = CGFontCopyTableForTag(cgFont, tag); 1786 } 1787 return data; 1788 } 1789 1790 int SkTypeface_Mac::onGetTableTags(SkFontTableTag tags[]) const { 1791 AutoCFRelease<CFArrayRef> cfArray(CTFontCopyAvailableTables(fFontRef, 1792 kCTFontTableOptionNoOptions)); 1793 if (NULL == cfArray) { 1794 return 0; 1795 } 1796 int count = CFArrayGetCount(cfArray); 1797 if (tags) { 1798 for (int i = 0; i < count; ++i) { 1799 uintptr_t fontTag = reinterpret_cast<uintptr_t>(CFArrayGetValueAtIndex(cfArray, i)); 1800 tags[i] = static_cast<SkFontTableTag>(fontTag); 1801 } 1802 } 1803 return count; 1804 } 1805 1806 size_t SkTypeface_Mac::onGetTableData(SkFontTableTag tag, size_t offset, 1807 size_t length, void* dstData) const { 1808 AutoCFRelease<CFDataRef> srcData(copyTableFromFont(fFontRef, tag)); 1809 if (NULL == srcData) { 1810 return 0; 1811 } 1812 1813 size_t srcSize = CFDataGetLength(srcData); 1814 if (offset >= srcSize) { 1815 return 0; 1816 } 1817 if (length > srcSize - offset) { 1818 length = srcSize - offset; 1819 } 1820 if (dstData) { 1821 memcpy(dstData, CFDataGetBytePtr(srcData) + offset, length); 1822 } 1823 return length; 1824 } 1825 1826 SkScalerContext* SkTypeface_Mac::onCreateScalerContext(const SkDescriptor* desc) const { 1827 return new SkScalerContext_Mac(const_cast<SkTypeface_Mac*>(this), desc); 1828 } 1829 1830 void SkTypeface_Mac::onFilterRec(SkScalerContextRec* rec) const { 1831 if (rec->fFlags & SkScalerContext::kLCD_BGROrder_Flag || 1832 rec->fFlags & SkScalerContext::kLCD_Vertical_Flag) 1833 { 1834 rec->fMaskFormat = SkMask::kA8_Format; 1835 // Render the glyphs as close as possible to what was requested. 1836 // The above turns off subpixel rendering, but the user requested it. 1837 // Normal hinting will cause the A8 masks to be generated from CoreGraphics subpixel masks. 1838 // See comments below for more details. 1839 rec->setHinting(SkPaint::kNormal_Hinting); 1840 } 1841 1842 unsigned flagsWeDontSupport = SkScalerContext::kDevKernText_Flag | 1843 SkScalerContext::kAutohinting_Flag | 1844 SkScalerContext::kLCD_BGROrder_Flag | 1845 SkScalerContext::kLCD_Vertical_Flag; 1846 1847 rec->fFlags &= ~flagsWeDontSupport; 1848 1849 bool lcdSupport = supports_LCD(); 1850 1851 // Only two levels of hinting are supported. 1852 // kNo_Hinting means avoid CoreGraphics outline dilation. 1853 // kNormal_Hinting means CoreGraphics outline dilation is allowed. 1854 // If there is no lcd support, hinting (dilation) cannot be supported. 1855 SkPaint::Hinting hinting = rec->getHinting(); 1856 if (SkPaint::kSlight_Hinting == hinting || !lcdSupport) { 1857 hinting = SkPaint::kNo_Hinting; 1858 } else if (SkPaint::kFull_Hinting == hinting) { 1859 hinting = SkPaint::kNormal_Hinting; 1860 } 1861 rec->setHinting(hinting); 1862 1863 // FIXME: lcd smoothed un-hinted rasterization unsupported. 1864 // Tracked by http://code.google.com/p/skia/issues/detail?id=915 . 1865 // There is no current means to honor a request for unhinted lcd, 1866 // so arbitrarilly ignore the hinting request and honor lcd. 1867 1868 // Hinting and smoothing should be orthogonal, but currently they are not. 1869 // CoreGraphics has no API to influence hinting. However, its lcd smoothed 1870 // output is drawn from auto-dilated outlines (the amount of which is 1871 // determined by AppleFontSmoothing). Its regular anti-aliased output is 1872 // drawn from un-dilated outlines. 1873 1874 // The behavior of Skia is as follows: 1875 // [AA][no-hint]: generate AA using CoreGraphic's AA output. 1876 // [AA][yes-hint]: use CoreGraphic's LCD output and reduce it to a single 1877 // channel. This matches [LCD][yes-hint] in weight. 1878 // [LCD][no-hint]: curently unable to honor, and must pick which to respect. 1879 // Currenly side with LCD, effectively ignoring the hinting setting. 1880 // [LCD][yes-hint]: generate LCD using CoreGraphic's LCD output. 1881 1882 if (isLCDFormat(rec->fMaskFormat)) { 1883 if (lcdSupport) { 1884 //CoreGraphics creates 555 masks for smoothed text anyway. 1885 rec->fMaskFormat = SkMask::kLCD16_Format; 1886 rec->setHinting(SkPaint::kNormal_Hinting); 1887 } else { 1888 rec->fMaskFormat = SkMask::kA8_Format; 1889 } 1890 } 1891 1892 // Unhinted A8 masks (those not derived from LCD masks) must respect SK_GAMMA_APPLY_TO_A8. 1893 // All other masks can use regular gamma. 1894 if (SkMask::kA8_Format == rec->fMaskFormat && SkPaint::kNo_Hinting == hinting) { 1895 #ifndef SK_GAMMA_APPLY_TO_A8 1896 rec->ignorePreBlend(); 1897 #endif 1898 } else { 1899 //CoreGraphics dialates smoothed text as needed. 1900 rec->setContrast(0); 1901 } 1902 } 1903 1904 // we take ownership of the ref 1905 static const char* get_str(CFStringRef ref, SkString* str) { 1906 CFStringToSkString(ref, str); 1907 CFSafeRelease(ref); 1908 return str->c_str(); 1909 } 1910 1911 void SkTypeface_Mac::onGetFontDescriptor(SkFontDescriptor* desc, 1912 bool* isLocalStream) const { 1913 SkString tmpStr; 1914 1915 desc->setFamilyName(get_str(CTFontCopyFamilyName(fFontRef), &tmpStr)); 1916 desc->setFullName(get_str(CTFontCopyFullName(fFontRef), &tmpStr)); 1917 desc->setPostscriptName(get_str(CTFontCopyPostScriptName(fFontRef), &tmpStr)); 1918 // TODO: need to add support for local-streams (here and openStream) 1919 *isLocalStream = false; 1920 } 1921 1922 int SkTypeface_Mac::onCharsToGlyphs(const void* chars, Encoding encoding, 1923 uint16_t glyphs[], int glyphCount) const { 1924 // UniChar is utf16 1925 SkAutoSTMalloc<1024, UniChar> charStorage; 1926 const UniChar* src; 1927 switch (encoding) { 1928 case kUTF8_Encoding: { 1929 const char* u8 = (const char*)chars; 1930 const UniChar* u16 = src = charStorage.reset(2 * glyphCount); 1931 for (int i = 0; i < glyphCount; ++i) { 1932 SkUnichar uni = SkUTF8_NextUnichar(&u8); 1933 int n = SkUTF16_FromUnichar(uni, (uint16_t*)u16); 1934 u16 += n; 1935 } 1936 break; 1937 } 1938 case kUTF16_Encoding: 1939 src = (const UniChar*)chars; 1940 break; 1941 case kUTF32_Encoding: { 1942 const SkUnichar* u32 = (const SkUnichar*)chars; 1943 const UniChar* u16 = src = charStorage.reset(2 * glyphCount); 1944 for (int i = 0; i < glyphCount; ++i) { 1945 int n = SkUTF16_FromUnichar(u32[i], (uint16_t*)u16); 1946 u16 += n; 1947 } 1948 break; 1949 } 1950 } 1951 1952 // Our caller may not want glyphs for output, but we need to give that 1953 // storage to CT, so we can walk it looking for the first non-zero. 1954 SkAutoSTMalloc<1024, uint16_t> glyphStorage; 1955 uint16_t* macGlyphs = glyphs; 1956 if (NULL == macGlyphs) { 1957 macGlyphs = glyphStorage.reset(glyphCount); 1958 } 1959 1960 if (CTFontGetGlyphsForCharacters(fFontRef, src, macGlyphs, glyphCount)) { 1961 return glyphCount; 1962 } 1963 // If we got false, then we need to manually look for first failure 1964 for (int i = 0; i < glyphCount; ++i) { 1965 if (0 == macGlyphs[i]) { 1966 return i; 1967 } 1968 } 1969 // odd to get here, as we expected CT to have returned true up front. 1970 return glyphCount; 1971 } 1972 1973 int SkTypeface_Mac::onCountGlyphs() const { 1974 return CTFontGetGlyphCount(fFontRef); 1975 } 1976 1977 /////////////////////////////////////////////////////////////////////////////// 1978 /////////////////////////////////////////////////////////////////////////////// 1979 #if 1 1980 1981 static bool find_desc_str(CTFontDescriptorRef desc, CFStringRef name, SkString* value) { 1982 AutoCFRelease<CFStringRef> ref((CFStringRef)CTFontDescriptorCopyAttribute(desc, name)); 1983 if (NULL == ref.get()) { 1984 return false; 1985 } 1986 CFStringToSkString(ref, value); 1987 return true; 1988 } 1989 1990 static bool find_dict_float(CFDictionaryRef dict, CFStringRef name, float* value) { 1991 CFNumberRef num; 1992 return CFDictionaryGetValueIfPresent(dict, name, (const void**)&num) 1993 && CFNumberIsFloatType(num) 1994 && CFNumberGetValue(num, kCFNumberFloatType, value); 1995 } 1996 1997 #include "SkFontMgr.h" 1998 1999 static int unit_weight_to_fontstyle(float unit) { 2000 float value; 2001 if (unit < 0) { 2002 value = 100 + (1 + unit) * 300; 2003 } else { 2004 value = 400 + unit * 500; 2005 } 2006 return sk_float_round2int(value); 2007 } 2008 2009 static int unit_width_to_fontstyle(float unit) { 2010 float value; 2011 if (unit < 0) { 2012 value = 1 + (1 + unit) * 4; 2013 } else { 2014 value = 5 + unit * 4; 2015 } 2016 return sk_float_round2int(value); 2017 } 2018 2019 static inline int sqr(int value) { 2020 SkASSERT(SkAbs32(value) < 0x7FFF); // check for overflow 2021 return value * value; 2022 } 2023 2024 // We normalize each axis (weight, width, italic) to be base-900 2025 static int compute_metric(const SkFontStyle& a, const SkFontStyle& b) { 2026 return sqr(a.weight() - b.weight()) + 2027 sqr((a.width() - b.width()) * 100) + 2028 sqr((a.isItalic() != b.isItalic()) * 900); 2029 } 2030 2031 static SkFontStyle desc2fontstyle(CTFontDescriptorRef desc) { 2032 AutoCFRelease<CFDictionaryRef> dict( 2033 (CFDictionaryRef)CTFontDescriptorCopyAttribute(desc, 2034 kCTFontTraitsAttribute)); 2035 if (NULL == dict.get()) { 2036 return SkFontStyle(); 2037 } 2038 2039 float weight, width, slant; 2040 if (!find_dict_float(dict, kCTFontWeightTrait, &weight)) { 2041 weight = 0; 2042 } 2043 if (!find_dict_float(dict, kCTFontWidthTrait, &width)) { 2044 width = 0; 2045 } 2046 if (!find_dict_float(dict, kCTFontSlantTrait, &slant)) { 2047 slant = 0; 2048 } 2049 2050 return SkFontStyle(unit_weight_to_fontstyle(weight), 2051 unit_width_to_fontstyle(width), 2052 slant ? SkFontStyle::kItalic_Slant 2053 : SkFontStyle::kUpright_Slant); 2054 } 2055 2056 struct NameFontStyleRec { 2057 SkString fFamilyName; 2058 SkFontStyle fFontStyle; 2059 }; 2060 2061 static bool nameFontStyleProc(SkTypeface* face, SkTypeface::Style, 2062 void* ctx) { 2063 SkTypeface_Mac* macFace = (SkTypeface_Mac*)face; 2064 const NameFontStyleRec* rec = (const NameFontStyleRec*)ctx; 2065 2066 return macFace->fFontStyle == rec->fFontStyle && 2067 macFace->fName == rec->fFamilyName; 2068 } 2069 2070 static SkTypeface* createFromDesc(CFStringRef cfFamilyName, 2071 CTFontDescriptorRef desc) { 2072 NameFontStyleRec rec; 2073 CFStringToSkString(cfFamilyName, &rec.fFamilyName); 2074 rec.fFontStyle = desc2fontstyle(desc); 2075 2076 SkTypeface* face = SkTypefaceCache::FindByProcAndRef(nameFontStyleProc, 2077 &rec); 2078 if (face) { 2079 return face; 2080 } 2081 2082 AutoCFRelease<CTFontRef> ctNamed(CTFontCreateWithName(cfFamilyName, 1, NULL)); 2083 CTFontRef ctFont = CTFontCreateCopyWithAttributes(ctNamed, 1, NULL, desc); 2084 if (NULL == ctFont) { 2085 return NULL; 2086 } 2087 2088 SkString str; 2089 CFStringToSkString(cfFamilyName, &str); 2090 2091 bool isFixedPitch; 2092 (void)computeStyleBits(ctFont, &isFixedPitch); 2093 SkFontID fontID = CTFontRef_to_SkFontID(ctFont); 2094 2095 face = SkNEW_ARGS(SkTypeface_Mac, (rec.fFontStyle, fontID, isFixedPitch, 2096 ctFont, str.c_str())); 2097 SkTypefaceCache::Add(face, face->style()); 2098 return face; 2099 } 2100 2101 class SkFontStyleSet_Mac : public SkFontStyleSet { 2102 public: 2103 SkFontStyleSet_Mac(CFStringRef familyName, CTFontDescriptorRef desc) 2104 : fArray(CTFontDescriptorCreateMatchingFontDescriptors(desc, NULL)) 2105 , fFamilyName(familyName) 2106 , fCount(0) { 2107 CFRetain(familyName); 2108 if (NULL == fArray) { 2109 fArray = CFArrayCreate(NULL, NULL, 0, NULL); 2110 } 2111 fCount = CFArrayGetCount(fArray); 2112 } 2113 2114 virtual ~SkFontStyleSet_Mac() { 2115 CFRelease(fArray); 2116 CFRelease(fFamilyName); 2117 } 2118 2119 virtual int count() SK_OVERRIDE { 2120 return fCount; 2121 } 2122 2123 virtual void getStyle(int index, SkFontStyle* style, 2124 SkString* name) SK_OVERRIDE { 2125 SkASSERT((unsigned)index < (unsigned)fCount); 2126 CTFontDescriptorRef desc = (CTFontDescriptorRef)CFArrayGetValueAtIndex(fArray, index); 2127 if (style) { 2128 *style = desc2fontstyle(desc); 2129 } 2130 if (name) { 2131 if (!find_desc_str(desc, kCTFontStyleNameAttribute, name)) { 2132 name->reset(); 2133 } 2134 } 2135 } 2136 2137 virtual SkTypeface* createTypeface(int index) SK_OVERRIDE { 2138 SkASSERT((unsigned)index < (unsigned)CFArrayGetCount(fArray)); 2139 CTFontDescriptorRef desc = (CTFontDescriptorRef)CFArrayGetValueAtIndex(fArray, index); 2140 2141 return createFromDesc(fFamilyName, desc); 2142 } 2143 2144 virtual SkTypeface* matchStyle(const SkFontStyle& pattern) SK_OVERRIDE { 2145 if (0 == fCount) { 2146 return NULL; 2147 } 2148 return createFromDesc(fFamilyName, findMatchingDesc(pattern)); 2149 } 2150 2151 private: 2152 CFArrayRef fArray; 2153 CFStringRef fFamilyName; 2154 int fCount; 2155 2156 CTFontDescriptorRef findMatchingDesc(const SkFontStyle& pattern) const { 2157 int bestMetric = SK_MaxS32; 2158 CTFontDescriptorRef bestDesc = NULL; 2159 2160 for (int i = 0; i < fCount; ++i) { 2161 CTFontDescriptorRef desc = (CTFontDescriptorRef)CFArrayGetValueAtIndex(fArray, i); 2162 int metric = compute_metric(pattern, desc2fontstyle(desc)); 2163 if (0 == metric) { 2164 return desc; 2165 } 2166 if (metric < bestMetric) { 2167 bestMetric = metric; 2168 bestDesc = desc; 2169 } 2170 } 2171 SkASSERT(bestDesc); 2172 return bestDesc; 2173 } 2174 }; 2175 2176 class SkFontMgr_Mac : public SkFontMgr { 2177 int fCount; 2178 CFArrayRef fNames; 2179 2180 CFStringRef stringAt(int index) const { 2181 SkASSERT((unsigned)index < (unsigned)fCount); 2182 return (CFStringRef)CFArrayGetValueAtIndex(fNames, index); 2183 } 2184 2185 void lazyInit() { 2186 if (NULL == fNames) { 2187 fNames = SkCTFontManagerCopyAvailableFontFamilyNames(); 2188 fCount = fNames ? CFArrayGetCount(fNames) : 0; 2189 } 2190 } 2191 2192 static SkFontStyleSet* CreateSet(CFStringRef cfFamilyName) { 2193 AutoCFRelease<CFMutableDictionaryRef> cfAttr( 2194 CFDictionaryCreateMutable(kCFAllocatorDefault, 0, 2195 &kCFTypeDictionaryKeyCallBacks, 2196 &kCFTypeDictionaryValueCallBacks)); 2197 2198 CFDictionaryAddValue(cfAttr, kCTFontFamilyNameAttribute, cfFamilyName); 2199 2200 AutoCFRelease<CTFontDescriptorRef> desc( 2201 CTFontDescriptorCreateWithAttributes(cfAttr)); 2202 return SkNEW_ARGS(SkFontStyleSet_Mac, (cfFamilyName, desc)); 2203 } 2204 2205 public: 2206 SkFontMgr_Mac() : fCount(0), fNames(NULL) {} 2207 2208 virtual ~SkFontMgr_Mac() { 2209 CFSafeRelease(fNames); 2210 } 2211 2212 protected: 2213 virtual int onCountFamilies() SK_OVERRIDE { 2214 this->lazyInit(); 2215 return fCount; 2216 } 2217 2218 virtual void onGetFamilyName(int index, SkString* familyName) SK_OVERRIDE { 2219 this->lazyInit(); 2220 if ((unsigned)index < (unsigned)fCount) { 2221 CFStringToSkString(this->stringAt(index), familyName); 2222 } else { 2223 familyName->reset(); 2224 } 2225 } 2226 2227 virtual SkFontStyleSet* onCreateStyleSet(int index) SK_OVERRIDE { 2228 this->lazyInit(); 2229 if ((unsigned)index >= (unsigned)fCount) { 2230 return NULL; 2231 } 2232 return CreateSet(this->stringAt(index)); 2233 } 2234 2235 virtual SkFontStyleSet* onMatchFamily(const char familyName[]) SK_OVERRIDE { 2236 AutoCFRelease<CFStringRef> cfName(make_CFString(familyName)); 2237 return CreateSet(cfName); 2238 } 2239 2240 virtual SkTypeface* onMatchFamilyStyle(const char familyName[], 2241 const SkFontStyle&) SK_OVERRIDE { 2242 return NULL; 2243 } 2244 2245 virtual SkTypeface* onMatchFaceStyle(const SkTypeface* familyMember, 2246 const SkFontStyle&) SK_OVERRIDE { 2247 return NULL; 2248 } 2249 2250 virtual SkTypeface* onCreateFromData(SkData* data, 2251 int ttcIndex) SK_OVERRIDE { 2252 AutoCFRelease<CGDataProviderRef> pr(SkCreateDataProviderFromData(data)); 2253 if (NULL == pr) { 2254 return NULL; 2255 } 2256 return create_from_dataProvider(pr); 2257 } 2258 2259 virtual SkTypeface* onCreateFromStream(SkStream* stream, 2260 int ttcIndex) SK_OVERRIDE { 2261 AutoCFRelease<CGDataProviderRef> pr(SkCreateDataProviderFromStream(stream)); 2262 if (NULL == pr) { 2263 return NULL; 2264 } 2265 return create_from_dataProvider(pr); 2266 } 2267 2268 virtual SkTypeface* onCreateFromFile(const char path[], 2269 int ttcIndex) SK_OVERRIDE { 2270 AutoCFRelease<CGDataProviderRef> pr(CGDataProviderCreateWithFilename(path)); 2271 if (NULL == pr) { 2272 return NULL; 2273 } 2274 return create_from_dataProvider(pr); 2275 } 2276 2277 virtual SkTypeface* onLegacyCreateTypeface(const char familyName[], 2278 unsigned styleBits) SK_OVERRIDE { 2279 return create_typeface(NULL, familyName, (SkTypeface::Style)styleBits); 2280 } 2281 }; 2282 2283 /////////////////////////////////////////////////////////////////////////////// 2284 2285 #ifndef SK_FONTHOST_USES_FONTMGR 2286 2287 SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace, 2288 const char familyName[], 2289 SkTypeface::Style style) { 2290 return create_typeface(familyFace, familyName, style); 2291 } 2292 2293 SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) { 2294 AutoCFRelease<CGDataProviderRef> provider(SkCreateDataProviderFromStream(stream)); 2295 if (NULL == provider) { 2296 return NULL; 2297 } 2298 return create_from_dataProvider(provider); 2299 } 2300 2301 SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) { 2302 AutoCFRelease<CGDataProviderRef> provider(CGDataProviderCreateWithFilename(path)); 2303 if (NULL == provider) { 2304 return NULL; 2305 } 2306 return create_from_dataProvider(provider); 2307 } 2308 2309 #endif 2310 2311 SkFontMgr* SkFontMgr::Factory() { 2312 return SkNEW(SkFontMgr_Mac); 2313 } 2314 #endif 2315