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