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