1 /* 2 * Copyright 2006 The Android Open Source Project 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "SkTypes.h" // Keep this before any #ifdef ... 9 #if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) 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 "SkAutoMalloc.h" 24 #include "SkCGUtils.h" 25 #include "SkColorData.h" 26 #include "SkDescriptor.h" 27 #include "SkEndian.h" 28 #include "SkFloatingPoint.h" 29 #include "SkFontDescriptor.h" 30 #include "SkFontMgr.h" 31 #include "SkGlyph.h" 32 #include "SkMakeUnique.h" 33 #include "SkMaskGamma.h" 34 #include "SkMathPriv.h" 35 #include "SkMutex.h" 36 #include "SkOTTable_OS_2.h" 37 #include "SkOTUtils.h" 38 #include "SkOnce.h" 39 #include "SkPaint.h" 40 #include "SkPath.h" 41 #include "SkSFNTHeader.h" 42 #include "SkStream.h" 43 #include "SkString.h" 44 #include "SkTemplates.h" 45 #include "SkTypefaceCache.h" 46 #include "SkTypeface_mac.h" 47 #include "SkUtils.h" 48 49 #include <dlfcn.h> 50 51 // Experimental code to use a global lock whenever we access CG, to see if this reduces 52 // crashes in Chrome 53 #define USE_GLOBAL_MUTEX_FOR_CG_ACCESS 54 55 #ifdef USE_GLOBAL_MUTEX_FOR_CG_ACCESS 56 SK_DECLARE_STATIC_MUTEX(gCGMutex); 57 #define AUTO_CG_LOCK() SkAutoMutexAcquire amc(gCGMutex) 58 #else 59 #define AUTO_CG_LOCK() 60 #endif 61 62 // Set to make glyph bounding boxes visible. 63 #define SK_SHOW_TEXT_BLIT_COVERAGE 0 64 65 CTFontRef SkTypeface_GetCTFontRef(const SkTypeface* face) { 66 return face ? (CTFontRef)face->internal_private_getCTFontRef() : nullptr; 67 } 68 69 class SkScalerContext_Mac; 70 71 struct CFSafeRelease { 72 void operator()(CFTypeRef cfTypeRef) { 73 if (cfTypeRef) { 74 CFRelease(cfTypeRef); 75 } 76 } 77 }; 78 template <typename CFRef> using UniqueCFRef = 79 std::unique_ptr<skstd::remove_pointer_t<CFRef>, CFSafeRelease>; 80 81 static UniqueCFRef<CFStringRef> make_CFString(const char str[]) { 82 return UniqueCFRef<CFStringRef>(CFStringCreateWithCString(nullptr, str, kCFStringEncodingUTF8)); 83 } 84 85 // inline versions of these rect helpers 86 87 static bool CGRectIsEmpty_inline(const CGRect& rect) { 88 return rect.size.width <= 0 || rect.size.height <= 0; 89 } 90 91 static CGFloat CGRectGetMinX_inline(const CGRect& rect) { 92 return rect.origin.x; 93 } 94 95 static CGFloat CGRectGetMaxX_inline(const CGRect& rect) { 96 return rect.origin.x + rect.size.width; 97 } 98 99 static CGFloat CGRectGetMinY_inline(const CGRect& rect) { 100 return rect.origin.y; 101 } 102 103 static CGFloat CGRectGetMaxY_inline(const CGRect& rect) { 104 return rect.origin.y + rect.size.height; 105 } 106 107 static CGFloat CGRectGetWidth_inline(const CGRect& rect) { 108 return rect.size.width; 109 } 110 111 /////////////////////////////////////////////////////////////////////////////// 112 113 static void sk_memset_rect32(uint32_t* ptr, uint32_t value, 114 int width, int height, size_t rowBytes) { 115 SkASSERT(width); 116 SkASSERT(width * sizeof(uint32_t) <= rowBytes); 117 118 if (width >= 32) { 119 while (height) { 120 sk_memset32(ptr, value, width); 121 ptr = (uint32_t*)((char*)ptr + rowBytes); 122 height -= 1; 123 } 124 return; 125 } 126 127 rowBytes -= width * sizeof(uint32_t); 128 129 if (width >= 8) { 130 while (height) { 131 int w = width; 132 do { 133 *ptr++ = value; *ptr++ = value; 134 *ptr++ = value; *ptr++ = value; 135 *ptr++ = value; *ptr++ = value; 136 *ptr++ = value; *ptr++ = value; 137 w -= 8; 138 } while (w >= 8); 139 while (--w >= 0) { 140 *ptr++ = value; 141 } 142 ptr = (uint32_t*)((char*)ptr + rowBytes); 143 height -= 1; 144 } 145 } else { 146 while (height) { 147 int w = width; 148 do { 149 *ptr++ = value; 150 } while (--w > 0); 151 ptr = (uint32_t*)((char*)ptr + rowBytes); 152 height -= 1; 153 } 154 } 155 } 156 157 typedef uint32_t CGRGBPixel; 158 159 static unsigned CGRGBPixel_getAlpha(CGRGBPixel pixel) { 160 return pixel & 0xFF; 161 } 162 163 static CGFloat ScalarToCG(SkScalar scalar) { 164 if (sizeof(CGFloat) == sizeof(float)) { 165 return SkScalarToFloat(scalar); 166 } else { 167 SkASSERT(sizeof(CGFloat) == sizeof(double)); 168 return (CGFloat) SkScalarToDouble(scalar); 169 } 170 } 171 172 static SkScalar CGToScalar(CGFloat cgFloat) { 173 if (sizeof(CGFloat) == sizeof(float)) { 174 return SkFloatToScalar(cgFloat); 175 } else { 176 SkASSERT(sizeof(CGFloat) == sizeof(double)); 177 return SkDoubleToScalar(cgFloat); 178 } 179 } 180 181 static float CGToFloat(CGFloat cgFloat) { 182 if (sizeof(CGFloat) == sizeof(float)) { 183 return cgFloat; 184 } else { 185 SkASSERT(sizeof(CGFloat) == sizeof(double)); 186 return static_cast<float>(cgFloat); 187 } 188 } 189 190 static CGAffineTransform MatrixToCGAffineTransform(const SkMatrix& matrix) { 191 return CGAffineTransformMake( ScalarToCG(matrix[SkMatrix::kMScaleX]), 192 -ScalarToCG(matrix[SkMatrix::kMSkewY] ), 193 -ScalarToCG(matrix[SkMatrix::kMSkewX] ), 194 ScalarToCG(matrix[SkMatrix::kMScaleY]), 195 ScalarToCG(matrix[SkMatrix::kMTransX]), 196 ScalarToCG(matrix[SkMatrix::kMTransY])); 197 } 198 199 /////////////////////////////////////////////////////////////////////////////// 200 201 #define BITMAP_INFO_RGB (kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host) 202 203 /** 204 * There does not appear to be a publicly accessable API for determining if lcd 205 * font smoothing will be applied if we request it. The main issue is that if 206 * smoothing is applied a gamma of 2.0 will be used, if not a gamma of 1.0. 207 */ 208 static bool supports_LCD() { 209 static bool gSupportsLCD = []{ 210 uint32_t rgb = 0; 211 UniqueCFRef<CGColorSpaceRef> colorspace(CGColorSpaceCreateDeviceRGB()); 212 UniqueCFRef<CGContextRef> cgContext( 213 CGBitmapContextCreate(&rgb, 1, 1, 8, 4, colorspace.get(), BITMAP_INFO_RGB)); 214 UniqueCFRef<CTFontRef> ctFont(CTFontCreateWithName(CFSTR("Helvetica"), 16, nullptr)); 215 CGContextSetShouldSmoothFonts(cgContext.get(), true); 216 CGContextSetShouldAntialias(cgContext.get(), true); 217 CGContextSetTextDrawingMode(cgContext.get(), kCGTextFill); 218 CGContextSetGrayFillColor(cgContext.get(), 1, 1); 219 CGPoint point = CGPointMake(-1, 0); 220 static const UniChar pipeChar = '|'; 221 CGGlyph pipeGlyph; 222 CTFontGetGlyphsForCharacters(ctFont.get(), &pipeChar, &pipeGlyph, 1); 223 CTFontDrawGlyphs(ctFont.get(), &pipeGlyph, &point, 1, cgContext.get()); 224 225 uint32_t r = (rgb >> 16) & 0xFF; 226 uint32_t g = (rgb >> 8) & 0xFF; 227 uint32_t b = (rgb >> 0) & 0xFF; 228 return (r != g || r != b); 229 }(); 230 return gSupportsLCD; 231 } 232 233 class Offscreen { 234 public: 235 Offscreen() 236 : fRGBSpace(nullptr) 237 , fCG(nullptr) 238 , fDoAA(false) 239 , fDoLCD(false) 240 { 241 fSize.set(0, 0); 242 } 243 244 CGRGBPixel* getCG(const SkScalerContext_Mac& context, const SkGlyph& glyph, 245 CGGlyph glyphID, size_t* rowBytesPtr, bool generateA8FromLCD); 246 247 private: 248 enum { 249 kSize = 32 * 32 * sizeof(CGRGBPixel) 250 }; 251 SkAutoSMalloc<kSize> fImageStorage; 252 UniqueCFRef<CGColorSpaceRef> fRGBSpace; 253 254 // cached state 255 UniqueCFRef<CGContextRef> fCG; 256 SkISize fSize; 257 bool fDoAA; 258 bool fDoLCD; 259 260 static int RoundSize(int dimension) { 261 return SkNextPow2(dimension); 262 } 263 }; 264 265 /////////////////////////////////////////////////////////////////////////////// 266 267 static bool find_dict_CGFloat(CFDictionaryRef dict, CFStringRef name, CGFloat* value) { 268 CFNumberRef num; 269 return CFDictionaryGetValueIfPresent(dict, name, (const void**)&num) 270 && CFNumberIsFloatType(num) 271 && CFNumberGetValue(num, kCFNumberCGFloatType, value); 272 } 273 274 template <typename S, typename D, typename C> struct LinearInterpolater { 275 struct Mapping { 276 S src_val; 277 D dst_val; 278 }; 279 constexpr LinearInterpolater(Mapping const mapping[], int mappingCount) 280 : fMapping(mapping), fMappingCount(mappingCount) {} 281 282 static D map(S value, S src_min, S src_max, D dst_min, D dst_max) { 283 SkASSERT(src_min < src_max); 284 SkASSERT(dst_min <= dst_max); 285 return C()(dst_min + (((value - src_min) * (dst_max - dst_min)) / (src_max - src_min))); 286 } 287 288 D map(S val) const { 289 // -Inf to [0] 290 if (val < fMapping[0].src_val) { 291 return fMapping[0].dst_val; 292 } 293 294 // Linear from [i] to [i+1] 295 for (int i = 0; i < fMappingCount - 1; ++i) { 296 if (val < fMapping[i+1].src_val) { 297 return map(val, fMapping[i].src_val, fMapping[i+1].src_val, 298 fMapping[i].dst_val, fMapping[i+1].dst_val); 299 } 300 } 301 302 // From [n] to +Inf 303 // if (fcweight < Inf) 304 return fMapping[fMappingCount - 1].dst_val; 305 } 306 307 Mapping const * fMapping; 308 int fMappingCount; 309 }; 310 311 struct RoundCGFloatToInt { 312 int operator()(CGFloat s) { return s + 0.5; } 313 }; 314 struct CGFloatIdentity { 315 CGFloat operator()(CGFloat s) { return s; } 316 }; 317 318 /** Returns the [-1, 1] CTFontDescriptor weights for the 319 * <0, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000> CSS weights. 320 * 321 * It is assumed that the values will be interpolated linearly between these points. 322 * NSFontWeightXXX were added in 10.11, appear in 10.10, but do not appear in 10.9. 323 * The actual values appear to be stable, but they may change in the future without notice. 324 */ 325 static CGFloat(&get_NSFontWeight_mapping())[11] { 326 327 // Declarations in <AppKit/AppKit.h> on macOS, <UIKit/UIKit.h> on iOS 328 #ifdef SK_BUILD_FOR_MAC 329 # define SK_KIT_FONT_WEIGHT_PREFIX "NS" 330 #endif 331 #ifdef SK_BUILD_FOR_IOS 332 # define SK_KIT_FONT_WEIGHT_PREFIX "UI" 333 #endif 334 static constexpr struct { 335 CGFloat defaultValue; 336 const char* name; 337 } nsFontWeightLoaderInfos[] = { 338 { -0.80f, SK_KIT_FONT_WEIGHT_PREFIX "FontWeightUltraLight" }, 339 { -0.60f, SK_KIT_FONT_WEIGHT_PREFIX "FontWeightThin" }, 340 { -0.40f, SK_KIT_FONT_WEIGHT_PREFIX "FontWeightLight" }, 341 { 0.00f, SK_KIT_FONT_WEIGHT_PREFIX "FontWeightRegular" }, 342 { 0.23f, SK_KIT_FONT_WEIGHT_PREFIX "FontWeightMedium" }, 343 { 0.30f, SK_KIT_FONT_WEIGHT_PREFIX "FontWeightSemibold" }, 344 { 0.40f, SK_KIT_FONT_WEIGHT_PREFIX "FontWeightBold" }, 345 { 0.56f, SK_KIT_FONT_WEIGHT_PREFIX "FontWeightHeavy" }, 346 { 0.62f, SK_KIT_FONT_WEIGHT_PREFIX "FontWeightBlack" }, 347 }; 348 349 static_assert(SK_ARRAY_COUNT(nsFontWeightLoaderInfos) == 9, ""); 350 static CGFloat nsFontWeights[11]; 351 static SkOnce once; 352 once([&] { 353 size_t i = 0; 354 nsFontWeights[i++] = -1.00; 355 for (const auto& nsFontWeightLoaderInfo : nsFontWeightLoaderInfos) { 356 void* nsFontWeightValuePtr = dlsym(RTLD_DEFAULT, nsFontWeightLoaderInfo.name); 357 if (nsFontWeightValuePtr) { 358 nsFontWeights[i++] = *(static_cast<CGFloat*>(nsFontWeightValuePtr)); 359 } else { 360 nsFontWeights[i++] = nsFontWeightLoaderInfo.defaultValue; 361 } 362 } 363 nsFontWeights[i++] = 1.00; 364 }); 365 return nsFontWeights; 366 } 367 368 /** Convert the [0, 1000] CSS weight to [-1, 1] CTFontDescriptor weight (for system fonts). 369 * 370 * The -1 to 1 weights reported by CTFontDescriptors have different mappings depending on if the 371 * CTFont is native or created from a CGDataProvider. 372 */ 373 static CGFloat fontstyle_to_ct_weight(int fontstyleWeight) { 374 using Interpolator = LinearInterpolater<int, CGFloat, CGFloatIdentity>; 375 376 // Note that Mac supports the old OS2 version A so 0 through 10 are as if multiplied by 100. 377 // However, on this end we can't tell, so this is ignored. 378 379 static Interpolator::Mapping nativeWeightMappings[11]; 380 static SkOnce once; 381 once([&] { 382 CGFloat(&nsFontWeights)[11] = get_NSFontWeight_mapping(); 383 for (int i = 0; i < 11; ++i) { 384 nativeWeightMappings[i].src_val = i * 100; 385 nativeWeightMappings[i].dst_val = nsFontWeights[i]; 386 } 387 }); 388 static constexpr Interpolator nativeInterpolator( 389 nativeWeightMappings, SK_ARRAY_COUNT(nativeWeightMappings)); 390 391 return nativeInterpolator.map(fontstyleWeight); 392 } 393 394 395 /** Convert the [-1, 1] CTFontDescriptor weight to [0, 1000] CSS weight. 396 * 397 * The -1 to 1 weights reported by CTFontDescriptors have different mappings depending on if the 398 * CTFont is native or created from a CGDataProvider. 399 */ 400 static int ct_weight_to_fontstyle(CGFloat cgWeight, bool fromDataProvider) { 401 using Interpolator = LinearInterpolater<CGFloat, int, RoundCGFloatToInt>; 402 403 // Note that Mac supports the old OS2 version A so 0 through 10 are as if multiplied by 100. 404 // However, on this end we can't tell, so this is ignored. 405 406 /** This mapping for CGDataProvider created fonts is determined by creating font data with every 407 * weight, creating a CTFont, and asking the CTFont for its weight. See the TypefaceStyle test 408 * in tests/TypefaceTest.cpp for the code used to determine these values. 409 */ 410 static constexpr Interpolator::Mapping dataProviderWeightMappings[] = { 411 { -1.00, 0 }, 412 { -0.70, 100 }, 413 { -0.50, 200 }, 414 { -0.23, 300 }, 415 { 0.00, 400 }, 416 { 0.20, 500 }, 417 { 0.30, 600 }, 418 { 0.40, 700 }, 419 { 0.60, 800 }, 420 { 0.80, 900 }, 421 { 1.00, 1000 }, 422 }; 423 static constexpr Interpolator dataProviderInterpolator( 424 dataProviderWeightMappings, SK_ARRAY_COUNT(dataProviderWeightMappings)); 425 426 static Interpolator::Mapping nativeWeightMappings[11]; 427 static SkOnce once; 428 once([&] { 429 CGFloat(&nsFontWeights)[11] = get_NSFontWeight_mapping(); 430 for (int i = 0; i < 11; ++i) { 431 nativeWeightMappings[i].src_val = nsFontWeights[i]; 432 nativeWeightMappings[i].dst_val = i * 100; 433 } 434 }); 435 static constexpr Interpolator nativeInterpolator( 436 nativeWeightMappings, SK_ARRAY_COUNT(nativeWeightMappings)); 437 438 return fromDataProvider ? dataProviderInterpolator.map(cgWeight) 439 : nativeInterpolator.map(cgWeight); 440 } 441 442 /** Convert the [0, 10] CSS weight to [-1, 1] CTFontDescriptor width. */ 443 static int fontstyle_to_ct_width(int fontstyleWidth) { 444 using Interpolator = LinearInterpolater<int, CGFloat, CGFloatIdentity>; 445 446 // Values determined by creating font data with every width, creating a CTFont, 447 // and asking the CTFont for its width. See TypefaceStyle test for basics. 448 static constexpr Interpolator::Mapping widthMappings[] = { 449 { 0, -0.5 }, 450 { 10, 0.5 }, 451 }; 452 static constexpr Interpolator interpolator(widthMappings, SK_ARRAY_COUNT(widthMappings)); 453 return interpolator.map(fontstyleWidth); 454 } 455 456 /** Convert the [-1, 1] CTFontDescriptor width to [0, 10] CSS weight. */ 457 static int ct_width_to_fontstyle(CGFloat cgWidth) { 458 using Interpolator = LinearInterpolater<CGFloat, int, RoundCGFloatToInt>; 459 460 // Values determined by creating font data with every width, creating a CTFont, 461 // and asking the CTFont for its width. See TypefaceStyle test for basics. 462 static constexpr Interpolator::Mapping widthMappings[] = { 463 { -0.5, 0 }, 464 { 0.5, 10 }, 465 }; 466 static constexpr Interpolator interpolator(widthMappings, SK_ARRAY_COUNT(widthMappings)); 467 return interpolator.map(cgWidth); 468 } 469 470 static SkFontStyle fontstyle_from_descriptor(CTFontDescriptorRef desc, bool fromDataProvider) { 471 UniqueCFRef<CFTypeRef> fontTraits(CTFontDescriptorCopyAttribute(desc, kCTFontTraitsAttribute)); 472 if (!fontTraits || CFDictionaryGetTypeID() != CFGetTypeID(fontTraits.get())) { 473 return SkFontStyle(); 474 } 475 UniqueCFRef<CFDictionaryRef> fontTraitsDict(static_cast<CFDictionaryRef>(fontTraits.release())); 476 477 CGFloat weight, width, slant; 478 if (!find_dict_CGFloat(fontTraitsDict.get(), kCTFontWeightTrait, &weight)) { 479 weight = 0; 480 } 481 if (!find_dict_CGFloat(fontTraitsDict.get(), kCTFontWidthTrait, &width)) { 482 width = 0; 483 } 484 if (!find_dict_CGFloat(fontTraitsDict.get(), kCTFontSlantTrait, &slant)) { 485 slant = 0; 486 } 487 488 return SkFontStyle(ct_weight_to_fontstyle(weight, fromDataProvider), 489 ct_width_to_fontstyle(width), 490 slant ? SkFontStyle::kItalic_Slant 491 : SkFontStyle::kUpright_Slant); 492 } 493 494 class SkTypeface_Mac : public SkTypeface { 495 public: 496 SkTypeface_Mac(UniqueCFRef<CTFontRef> fontRef, UniqueCFRef<CFTypeRef> resourceRef, 497 const SkFontStyle& fs, bool isFixedPitch, 498 bool isLocalStream) 499 : SkTypeface(fs, isFixedPitch) 500 , fFontRef(std::move(fontRef)) 501 , fOriginatingCFTypeRef(std::move(resourceRef)) 502 , fHasColorGlyphs( 503 SkToBool(CTFontGetSymbolicTraits(fFontRef.get()) & kCTFontColorGlyphsTrait)) 504 , fIsLocalStream(isLocalStream) 505 { 506 SkASSERT(fFontRef); 507 } 508 509 UniqueCFRef<CTFontRef> fFontRef; 510 UniqueCFRef<CFTypeRef> fOriginatingCFTypeRef; 511 const bool fHasColorGlyphs; 512 513 protected: 514 int onGetUPEM() const override; 515 SkStreamAsset* onOpenStream(int* ttcIndex) const override; 516 std::unique_ptr<SkFontData> onMakeFontData() const override; 517 int onGetVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[], 518 int coordinateCount) const override; 519 void onGetFamilyName(SkString* familyName) const override; 520 SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const override; 521 int onGetTableTags(SkFontTableTag tags[]) const override; 522 size_t onGetTableData(SkFontTableTag, size_t offset, size_t length, void* data) const override; 523 SkScalerContext* onCreateScalerContext(const SkScalerContextEffects&, 524 const SkDescriptor*) const override; 525 void onFilterRec(SkScalerContextRec*) const override; 526 void onGetFontDescriptor(SkFontDescriptor*, bool*) const override; 527 std::unique_ptr<SkAdvancedTypefaceMetrics> onGetAdvancedMetrics() const override; 528 int onCharsToGlyphs(const void* chars, Encoding, 529 uint16_t glyphs[], int glyphCount) const override; 530 int onCountGlyphs() const override; 531 532 void* onGetCTFontRef() const override { return (void*)fFontRef.get(); } 533 534 private: 535 bool fIsLocalStream; 536 537 typedef SkTypeface INHERITED; 538 }; 539 540 static bool find_by_CTFontRef(SkTypeface* cached, void* context) { 541 CTFontRef self = (CTFontRef)context; 542 CTFontRef other = (CTFontRef)cached->internal_private_getCTFontRef(); 543 544 return CFEqual(self, other); 545 } 546 547 /** Creates a typeface, searching the cache if isLocalStream is false. */ 548 static sk_sp<SkTypeface> create_from_CTFontRef(UniqueCFRef<CTFontRef> font, 549 UniqueCFRef<CFTypeRef> resource, 550 bool isLocalStream) { 551 SkASSERT(font); 552 553 if (!isLocalStream) { 554 SkTypeface* face = SkTypefaceCache::FindByProcAndRef(find_by_CTFontRef, (void*)font.get()); 555 if (face) { 556 return sk_sp<SkTypeface>(face); 557 } 558 } 559 560 UniqueCFRef<CTFontDescriptorRef> desc(CTFontCopyFontDescriptor(font.get())); 561 SkFontStyle style = fontstyle_from_descriptor(desc.get(), isLocalStream); 562 CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(font.get()); 563 bool isFixedPitch = SkToBool(traits & kCTFontMonoSpaceTrait); 564 565 SkTypeface* face = new SkTypeface_Mac(std::move(font), std::move(resource), 566 style, isFixedPitch, isLocalStream); 567 if (!isLocalStream) { 568 SkTypefaceCache::Add(face); 569 } 570 return sk_sp<SkTypeface>(face); 571 } 572 573 /** Creates a typeface from a descriptor, searching the cache. */ 574 static sk_sp<SkTypeface> create_from_desc(CTFontDescriptorRef desc) { 575 UniqueCFRef<CTFontRef> ctFont(CTFontCreateWithFontDescriptor(desc, 0, nullptr)); 576 if (!ctFont) { 577 return nullptr; 578 } 579 580 return create_from_CTFontRef(std::move(ctFont), nullptr, false); 581 } 582 583 static UniqueCFRef<CTFontDescriptorRef> create_descriptor(const char familyName[], 584 const SkFontStyle& style) { 585 UniqueCFRef<CFMutableDictionaryRef> cfAttributes( 586 CFDictionaryCreateMutable(kCFAllocatorDefault, 0, 587 &kCFTypeDictionaryKeyCallBacks, 588 &kCFTypeDictionaryValueCallBacks)); 589 590 UniqueCFRef<CFMutableDictionaryRef> cfTraits( 591 CFDictionaryCreateMutable(kCFAllocatorDefault, 0, 592 &kCFTypeDictionaryKeyCallBacks, 593 &kCFTypeDictionaryValueCallBacks)); 594 595 if (!cfAttributes || !cfTraits) { 596 return nullptr; 597 } 598 599 // CTFontTraits (symbolic) 600 CTFontSymbolicTraits ctFontTraits = 0; 601 if (style.weight() >= SkFontStyle::kBold_Weight) { 602 ctFontTraits |= kCTFontBoldTrait; 603 } 604 if (style.slant() != SkFontStyle::kUpright_Slant) { 605 ctFontTraits |= kCTFontItalicTrait; 606 } 607 UniqueCFRef<CFNumberRef> cfFontTraits( 608 CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &ctFontTraits)); 609 if (cfFontTraits) { 610 CFDictionaryAddValue(cfTraits.get(), kCTFontSymbolicTrait, cfFontTraits.get()); 611 } 612 // CTFontTraits (weight) 613 CGFloat ctWeight = fontstyle_to_ct_weight(style.weight()); 614 UniqueCFRef<CFNumberRef> cfFontWeight( 615 CFNumberCreate(kCFAllocatorDefault, kCFNumberCGFloatType, &ctWeight)); 616 if (cfFontWeight) { 617 CFDictionaryAddValue(cfTraits.get(), kCTFontWeightTrait, cfFontWeight.get()); 618 } 619 // CTFontTraits (width) 620 CGFloat ctWidth = fontstyle_to_ct_width(style.weight()); 621 UniqueCFRef<CFNumberRef> cfFontWidth( 622 CFNumberCreate(kCFAllocatorDefault, kCFNumberCGFloatType, &ctWidth)); 623 if (cfFontWidth) { 624 CFDictionaryAddValue(cfTraits.get(), kCTFontWidthTrait, cfFontWidth.get()); 625 } 626 // CTFontTraits (slant) 627 CGFloat ctSlant = style.slant() == SkFontStyle::kUpright_Slant ? 0 : 1; 628 UniqueCFRef<CFNumberRef> cfFontSlant( 629 CFNumberCreate(kCFAllocatorDefault, kCFNumberCGFloatType, &ctSlant)); 630 if (cfFontSlant) { 631 CFDictionaryAddValue(cfTraits.get(), kCTFontSlantTrait, cfFontSlant.get()); 632 } 633 // CTFontTraits 634 CFDictionaryAddValue(cfAttributes.get(), kCTFontTraitsAttribute, cfTraits.get()); 635 636 // CTFontFamilyName 637 if (familyName) { 638 UniqueCFRef<CFStringRef> cfFontName = make_CFString(familyName); 639 if (cfFontName) { 640 CFDictionaryAddValue(cfAttributes.get(), kCTFontFamilyNameAttribute, cfFontName.get()); 641 } 642 } 643 644 return UniqueCFRef<CTFontDescriptorRef>( 645 CTFontDescriptorCreateWithAttributes(cfAttributes.get())); 646 } 647 648 /** Creates a typeface from a name, searching the cache. */ 649 static sk_sp<SkTypeface> create_from_name(const char familyName[], const SkFontStyle& style) { 650 UniqueCFRef<CTFontDescriptorRef> desc = create_descriptor(familyName, style); 651 if (!desc) { 652 return nullptr; 653 } 654 return create_from_desc(desc.get()); 655 } 656 657 /////////////////////////////////////////////////////////////////////////////// 658 659 /* This function is visible on the outside. It first searches the cache, and if 660 * not found, returns a new entry (after adding it to the cache). 661 */ 662 SkTypeface* SkCreateTypefaceFromCTFont(CTFontRef font, CFTypeRef resource) { 663 CFRetain(font); 664 if (resource) { 665 CFRetain(resource); 666 } 667 return create_from_CTFontRef(UniqueCFRef<CTFontRef>(font), 668 UniqueCFRef<CFTypeRef>(resource), 669 false).release(); 670 } 671 672 static const char* map_css_names(const char* name) { 673 static const struct { 674 const char* fFrom; // name the caller specified 675 const char* fTo; // "canonical" name we map to 676 } gPairs[] = { 677 { "sans-serif", "Helvetica" }, 678 { "serif", "Times" }, 679 { "monospace", "Courier" } 680 }; 681 682 for (size_t i = 0; i < SK_ARRAY_COUNT(gPairs); i++) { 683 if (strcmp(name, gPairs[i].fFrom) == 0) { 684 return gPairs[i].fTo; 685 } 686 } 687 return name; // no change 688 } 689 690 /////////////////////////////////////////////////////////////////////////////// 691 692 class SkScalerContext_Mac : public SkScalerContext { 693 public: 694 SkScalerContext_Mac(sk_sp<SkTypeface_Mac>, const SkScalerContextEffects&, const SkDescriptor*); 695 696 protected: 697 unsigned generateGlyphCount(void) override; 698 uint16_t generateCharToGlyph(SkUnichar uni) override; 699 void generateAdvance(SkGlyph* glyph) override; 700 void generateMetrics(SkGlyph* glyph) override; 701 void generateImage(const SkGlyph& glyph) override; 702 void generatePath(SkGlyphID glyph, SkPath* path) override; 703 void generateFontMetrics(SkPaint::FontMetrics*) override; 704 705 private: 706 static void CTPathElement(void *info, const CGPathElement *element); 707 708 /** Returns the offset from the horizontal origin to the vertical origin in SkGlyph units. */ 709 void getVerticalOffset(CGGlyph glyphID, SkPoint* offset) const; 710 711 Offscreen fOffscreen; 712 713 /** Unrotated variant of fCTFont. 714 * 715 * In 10.10.1 CTFontGetAdvancesForGlyphs applies the font transform to the width of the 716 * advances, but always sets the height to 0. This font is used to get the advances of the 717 * unrotated glyph, and then the rotation is applied separately. 718 * 719 * CT vertical metrics are pre-rotated (in em space, before transform) 90deg clock-wise. 720 * This makes kCTFontOrientationDefault dangerous, because the metrics from 721 * kCTFontOrientationHorizontal are in a different space from kCTFontOrientationVertical. 722 * With kCTFontOrientationVertical the advances must be unrotated. 723 * 724 * Sometimes, creating a copy of a CTFont with the same size but different trasform will select 725 * different underlying font data. As a result, avoid ever creating more than one CTFont per 726 * SkScalerContext to ensure that only one CTFont is used. 727 * 728 * As a result of the above (and other constraints) this font contains the size, but not the 729 * transform. The transform must always be applied separately. 730 */ 731 UniqueCFRef<CTFontRef> fCTFont; 732 733 /** The transform without the font size. */ 734 CGAffineTransform fTransform; 735 CGAffineTransform fInvTransform; 736 737 UniqueCFRef<CGFontRef> fCGFont; 738 uint16_t fGlyphCount; 739 const bool fDoSubPosition; 740 const bool fVertical; 741 742 friend class Offscreen; 743 744 typedef SkScalerContext INHERITED; 745 }; 746 747 // CTFontCreateCopyWithAttributes or CTFontCreateCopyWithSymbolicTraits cannot be used on 10.10 748 // and later, as they will return different underlying fonts depending on the size requested. 749 // It is not possible to use descriptors with CTFontCreateWithFontDescriptor, since that does not 750 // work with non-system fonts. As a result, create the strike specific CTFonts from the underlying 751 // CGFont. 752 static UniqueCFRef<CTFontRef> ctfont_create_exact_copy(CTFontRef baseFont, CGFloat textSize, 753 const CGAffineTransform* transform) 754 { 755 UniqueCFRef<CGFontRef> baseCGFont(CTFontCopyGraphicsFont(baseFont, nullptr)); 756 757 // The last parameter (CTFontDescriptorRef attributes) *must* be nullptr. 758 // If non-nullptr then with fonts with variation axes, the copy will fail in 759 // CGFontVariationFromDictCallback when it assumes kCGFontVariationAxisName is CFNumberRef 760 // which it quite obviously is not. 761 762 // Because we cannot setup the CTFont descriptor to match, the same restriction applies here 763 // as other uses of CTFontCreateWithGraphicsFont which is that such CTFonts should not escape 764 // the scaler context, since they aren't 'normal'. 765 return UniqueCFRef<CTFontRef>( 766 CTFontCreateWithGraphicsFont(baseCGFont.get(), textSize, transform, nullptr)); 767 } 768 769 SkScalerContext_Mac::SkScalerContext_Mac(sk_sp<SkTypeface_Mac> typeface, 770 const SkScalerContextEffects& effects, 771 const SkDescriptor* desc) 772 : INHERITED(std::move(typeface), effects, desc) 773 , fDoSubPosition(SkToBool(fRec.fFlags & kSubpixelPositioning_Flag)) 774 , fVertical(SkToBool(fRec.fFlags & kVertical_Flag)) 775 776 { 777 AUTO_CG_LOCK(); 778 779 CTFontRef ctFont = (CTFontRef)this->getTypeface()->internal_private_getCTFontRef(); 780 CFIndex numGlyphs = CTFontGetGlyphCount(ctFont); 781 SkASSERT(numGlyphs >= 1 && numGlyphs <= 0xFFFF); 782 fGlyphCount = SkToU16(numGlyphs); 783 784 // CT on (at least) 10.9 will size color glyphs down from the requested size, but not up. 785 // As a result, it is necessary to know the actual device size and request that. 786 SkVector scale; 787 SkMatrix skTransform; 788 bool invertible = fRec.computeMatrices(SkScalerContextRec::kVertical_PreMatrixScale, 789 &scale, &skTransform, nullptr, nullptr, nullptr); 790 fTransform = MatrixToCGAffineTransform(skTransform); 791 // CGAffineTransformInvert documents that if the transform is non-invertible it will return the 792 // passed transform unchanged. It does so, but then also prints a message to stdout. Avoid this. 793 if (invertible) { 794 fInvTransform = CGAffineTransformInvert(fTransform); 795 } else { 796 fInvTransform = fTransform; 797 } 798 799 // The transform contains everything except the requested text size. 800 // Some properties, like 'trak', are based on the text size (before applying the matrix). 801 CGFloat textSize = ScalarToCG(scale.y()); 802 fCTFont = ctfont_create_exact_copy(ctFont, textSize, nullptr); 803 fCGFont.reset(CTFontCopyGraphicsFont(fCTFont.get(), nullptr)); 804 } 805 806 CGRGBPixel* Offscreen::getCG(const SkScalerContext_Mac& context, const SkGlyph& glyph, 807 CGGlyph glyphID, size_t* rowBytesPtr, 808 bool generateA8FromLCD) { 809 if (!fRGBSpace) { 810 //It doesn't appear to matter what color space is specified. 811 //Regular blends and antialiased text are always (s*a + d*(1-a)) 812 //and smoothed text is always g=2.0. 813 fRGBSpace.reset(CGColorSpaceCreateDeviceRGB()); 814 } 815 816 // default to kBW_Format 817 bool doAA = false; 818 bool doLCD = false; 819 820 if (SkMask::kBW_Format != glyph.fMaskFormat) { 821 doLCD = true; 822 doAA = true; 823 } 824 825 // FIXME: lcd smoothed un-hinted rasterization unsupported. 826 if (!generateA8FromLCD && SkMask::kA8_Format == glyph.fMaskFormat) { 827 doLCD = false; 828 doAA = true; 829 } 830 831 // If this font might have color glyphs, disable LCD as there's no way to support it. 832 // CoreText doesn't tell us which format it ended up using, so we can't detect it. 833 // A8 will end up black on transparent, but TODO: we can detect gray and set to A8. 834 if (SkMask::kARGB32_Format == glyph.fMaskFormat) { 835 doLCD = false; 836 } 837 838 size_t rowBytes = fSize.fWidth * sizeof(CGRGBPixel); 839 if (!fCG || fSize.fWidth < glyph.fWidth || fSize.fHeight < glyph.fHeight) { 840 if (fSize.fWidth < glyph.fWidth) { 841 fSize.fWidth = RoundSize(glyph.fWidth); 842 } 843 if (fSize.fHeight < glyph.fHeight) { 844 fSize.fHeight = RoundSize(glyph.fHeight); 845 } 846 847 rowBytes = fSize.fWidth * sizeof(CGRGBPixel); 848 void* image = fImageStorage.reset(rowBytes * fSize.fHeight); 849 const CGImageAlphaInfo alpha = (SkMask::kARGB32_Format == glyph.fMaskFormat) 850 ? kCGImageAlphaPremultipliedFirst 851 : kCGImageAlphaNoneSkipFirst; 852 const CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Host | alpha; 853 fCG.reset(CGBitmapContextCreate(image, fSize.fWidth, fSize.fHeight, 8, 854 rowBytes, fRGBSpace.get(), bitmapInfo)); 855 856 // Skia handles quantization and subpixel positioning, 857 // so disable quantization and enabe subpixel positioning in CG. 858 CGContextSetAllowsFontSubpixelQuantization(fCG.get(), false); 859 CGContextSetShouldSubpixelQuantizeFonts(fCG.get(), false); 860 861 // Because CG always draws from the horizontal baseline, 862 // if there is a non-integral translation from the horizontal origin to the vertical origin, 863 // then CG cannot draw the glyph in the correct location without subpixel positioning. 864 CGContextSetAllowsFontSubpixelPositioning(fCG.get(), true); 865 CGContextSetShouldSubpixelPositionFonts(fCG.get(), true); 866 867 CGContextSetTextDrawingMode(fCG.get(), kCGTextFill); 868 869 // Draw black on white to create mask. (Special path exists to speed this up in CG.) 870 CGContextSetGrayFillColor(fCG.get(), 0.0f, 1.0f); 871 872 // force our checks below to happen 873 fDoAA = !doAA; 874 fDoLCD = !doLCD; 875 876 CGContextSetTextMatrix(fCG.get(), context.fTransform); 877 } 878 879 if (fDoAA != doAA) { 880 CGContextSetShouldAntialias(fCG.get(), doAA); 881 fDoAA = doAA; 882 } 883 if (fDoLCD != doLCD) { 884 CGContextSetShouldSmoothFonts(fCG.get(), doLCD); 885 fDoLCD = doLCD; 886 } 887 888 CGRGBPixel* image = (CGRGBPixel*)fImageStorage.get(); 889 // skip rows based on the glyph's height 890 image += (fSize.fHeight - glyph.fHeight) * fSize.fWidth; 891 892 // Erase to white (or transparent black if it's a color glyph, to not composite against white). 893 uint32_t bgColor = (SkMask::kARGB32_Format != glyph.fMaskFormat) ? 0xFFFFFFFF : 0x00000000; 894 sk_memset_rect32(image, bgColor, glyph.fWidth, glyph.fHeight, rowBytes); 895 896 float subX = 0; 897 float subY = 0; 898 if (context.fDoSubPosition) { 899 subX = SkFixedToFloat(glyph.getSubXFixed()); 900 subY = SkFixedToFloat(glyph.getSubYFixed()); 901 } 902 903 // CoreText and CoreGraphics always draw using the horizontal baseline origin. 904 if (context.fVertical) { 905 SkPoint offset; 906 context.getVerticalOffset(glyphID, &offset); 907 subX += offset.fX; 908 subY += offset.fY; 909 } 910 911 CGPoint point = CGPointMake(-glyph.fLeft + subX, glyph.fTop + glyph.fHeight - subY); 912 // Prior to 10.10, CTFontDrawGlyphs acted like CGContextShowGlyphsAtPositions and took 913 // 'positions' which are in text space. The glyph location (in device space) must be 914 // mapped into text space, so that CG can convert it back into device space. 915 // In 10.10.1, this is handled directly in CTFontDrawGlyphs. 916 // 917 // However, in 10.10.2 color glyphs no longer rotate based on the font transform. 918 // So always make the font transform identity and place the transform on the context. 919 point = CGPointApplyAffineTransform(point, context.fInvTransform); 920 921 CTFontDrawGlyphs(context.fCTFont.get(), &glyphID, &point, 1, fCG.get()); 922 923 SkASSERT(rowBytesPtr); 924 *rowBytesPtr = rowBytes; 925 return image; 926 } 927 928 void SkScalerContext_Mac::getVerticalOffset(CGGlyph glyphID, SkPoint* offset) const { 929 // CTFontGetVerticalTranslationsForGlyphs produces cgVertOffset in CG units (pixels, y up). 930 CGSize cgVertOffset; 931 CTFontGetVerticalTranslationsForGlyphs(fCTFont.get(), &glyphID, &cgVertOffset, 1); 932 cgVertOffset = CGSizeApplyAffineTransform(cgVertOffset, fTransform); 933 SkPoint skVertOffset = { CGToScalar(cgVertOffset.width), CGToScalar(cgVertOffset.height) }; 934 // From CG units (pixels, y up) to SkGlyph units (pixels, y down). 935 skVertOffset.fY = -skVertOffset.fY; 936 *offset = skVertOffset; 937 } 938 939 unsigned SkScalerContext_Mac::generateGlyphCount(void) { 940 return fGlyphCount; 941 } 942 943 uint16_t SkScalerContext_Mac::generateCharToGlyph(SkUnichar uni) { 944 AUTO_CG_LOCK(); 945 946 CGGlyph cgGlyph[2]; 947 UniChar theChar[2]; // UniChar is a UTF-16 16-bit code unit. 948 949 // Get the glyph 950 size_t numUniChar = SkUTF16_FromUnichar(uni, theChar); 951 SkASSERT(sizeof(CGGlyph) <= sizeof(uint16_t)); 952 953 // Undocumented behavior of CTFontGetGlyphsForCharacters with non-bmp code points: 954 // When a surrogate pair is detected, the glyph index used is the index of the high surrogate. 955 // It is documented that if a mapping is unavailable, the glyph will be set to 0. 956 CTFontGetGlyphsForCharacters(fCTFont.get(), theChar, cgGlyph, numUniChar); 957 return cgGlyph[0]; 958 } 959 960 void SkScalerContext_Mac::generateAdvance(SkGlyph* glyph) { 961 this->generateMetrics(glyph); 962 } 963 964 void SkScalerContext_Mac::generateMetrics(SkGlyph* glyph) { 965 AUTO_CG_LOCK(); 966 967 const CGGlyph cgGlyph = (CGGlyph) glyph->getGlyphID(); 968 glyph->zeroMetrics(); 969 970 // The following block produces cgAdvance in CG units (pixels, y up). 971 CGSize cgAdvance; 972 if (fVertical) { 973 CTFontGetAdvancesForGlyphs(fCTFont.get(), kCTFontOrientationVertical, 974 &cgGlyph, &cgAdvance, 1); 975 // Vertical advances are returned as widths instead of heights. 976 SkTSwap(cgAdvance.height, cgAdvance.width); 977 cgAdvance.height = -cgAdvance.height; 978 } else { 979 CTFontGetAdvancesForGlyphs(fCTFont.get(), kCTFontOrientationHorizontal, 980 &cgGlyph, &cgAdvance, 1); 981 } 982 cgAdvance = CGSizeApplyAffineTransform(cgAdvance, fTransform); 983 glyph->fAdvanceX = CGToFloat(cgAdvance.width); 984 glyph->fAdvanceY = -CGToFloat(cgAdvance.height); 985 986 // The following produces skBounds in SkGlyph units (pixels, y down), 987 // or returns early if skBounds would be empty. 988 SkRect skBounds; 989 990 // Glyphs are always drawn from the horizontal origin. The caller must manually use the result 991 // of CTFontGetVerticalTranslationsForGlyphs to calculate where to draw the glyph for vertical 992 // glyphs. As a result, always get the horizontal bounds of a glyph and translate it if the 993 // glyph is vertical. This avoids any diagreement between the various means of retrieving 994 // vertical metrics. 995 { 996 // CTFontGetBoundingRectsForGlyphs produces cgBounds in CG units (pixels, y up). 997 CGRect cgBounds; 998 CTFontGetBoundingRectsForGlyphs(fCTFont.get(), kCTFontOrientationHorizontal, 999 &cgGlyph, &cgBounds, 1); 1000 cgBounds = CGRectApplyAffineTransform(cgBounds, fTransform); 1001 1002 // BUG? 1003 // 0x200B (zero-advance space) seems to return a huge (garbage) bounds, when 1004 // it should be empty. So, if we see a zero-advance, we check if it has an 1005 // empty path or not, and if so, we jam the bounds to 0. Hopefully a zero-advance 1006 // is rare, so we won't incur a big performance cost for this extra check. 1007 if (0 == cgAdvance.width && 0 == cgAdvance.height) { 1008 UniqueCFRef<CGPathRef> path(CTFontCreatePathForGlyph(fCTFont.get(), cgGlyph, nullptr)); 1009 if (!path || CGPathIsEmpty(path.get())) { 1010 return; 1011 } 1012 } 1013 1014 if (CGRectIsEmpty_inline(cgBounds)) { 1015 return; 1016 } 1017 1018 // Convert cgBounds to SkGlyph units (pixels, y down). 1019 skBounds = SkRect::MakeXYWH(cgBounds.origin.x, -cgBounds.origin.y - cgBounds.size.height, 1020 cgBounds.size.width, cgBounds.size.height); 1021 } 1022 1023 if (fVertical) { 1024 // Due to possible vertical bounds bugs and simplicity, skBounds is the horizontal bounds. 1025 // Convert these horizontal bounds into vertical bounds. 1026 SkPoint offset; 1027 this->getVerticalOffset(cgGlyph, &offset); 1028 skBounds.offset(offset); 1029 } 1030 1031 // Currently the bounds are based on being rendered at (0,0). 1032 // The top left must not move, since that is the base from which subpixel positioning is offset. 1033 if (fDoSubPosition) { 1034 skBounds.fRight += SkFixedToFloat(glyph->getSubXFixed()); 1035 skBounds.fBottom += SkFixedToFloat(glyph->getSubYFixed()); 1036 } 1037 1038 // We're trying to pack left and top into int16_t, 1039 // and width and height into uint16_t, after outsetting by 1. 1040 if (!SkRect::MakeXYWH(-32767, -32767, 65535, 65535).contains(skBounds)) { 1041 return; 1042 } 1043 1044 SkIRect skIBounds; 1045 skBounds.roundOut(&skIBounds); 1046 // Expand the bounds by 1 pixel, to give CG room for anti-aliasing. 1047 // Note that this outset is to allow room for LCD smoothed glyphs. However, the correct outset 1048 // is not currently known, as CG dilates the outlines by some percentage. 1049 // Note that if this context is A8 and not back-forming from LCD, there is no need to outset. 1050 skIBounds.outset(1, 1); 1051 glyph->fLeft = SkToS16(skIBounds.fLeft); 1052 glyph->fTop = SkToS16(skIBounds.fTop); 1053 glyph->fWidth = SkToU16(skIBounds.width()); 1054 glyph->fHeight = SkToU16(skIBounds.height()); 1055 } 1056 1057 #include "SkColorData.h" 1058 1059 static constexpr uint8_t sk_pow2_table(size_t i) { 1060 return SkToU8(((i * i + 128) / 255)); 1061 } 1062 1063 /** 1064 * This will invert the gamma applied by CoreGraphics, so we can get linear 1065 * values. 1066 * 1067 * CoreGraphics obscurely defaults to 2.0 as the smoothing gamma value. 1068 * The color space used does not appear to affect this choice. 1069 */ 1070 static constexpr auto gLinearCoverageFromCGLCDValue = SkMakeArray<256>(sk_pow2_table); 1071 1072 static void cgpixels_to_bits(uint8_t dst[], const CGRGBPixel src[], int count) { 1073 while (count > 0) { 1074 uint8_t mask = 0; 1075 for (int i = 7; i >= 0; --i) { 1076 mask |= ((CGRGBPixel_getAlpha(*src++) >> 7) ^ 0x1) << i; 1077 if (0 == --count) { 1078 break; 1079 } 1080 } 1081 *dst++ = mask; 1082 } 1083 } 1084 1085 template<bool APPLY_PREBLEND> 1086 static inline uint8_t rgb_to_a8(CGRGBPixel rgb, const uint8_t* table8) { 1087 U8CPU r = 0xFF - ((rgb >> 16) & 0xFF); 1088 U8CPU g = 0xFF - ((rgb >> 8) & 0xFF); 1089 U8CPU b = 0xFF - ((rgb >> 0) & 0xFF); 1090 U8CPU lum = sk_apply_lut_if<APPLY_PREBLEND>(SkComputeLuminance(r, g, b), table8); 1091 #if SK_SHOW_TEXT_BLIT_COVERAGE 1092 lum = SkTMax(lum, (U8CPU)0x30); 1093 #endif 1094 return lum; 1095 } 1096 template<bool APPLY_PREBLEND> 1097 static void rgb_to_a8(const CGRGBPixel* SK_RESTRICT cgPixels, size_t cgRowBytes, 1098 const SkGlyph& glyph, const uint8_t* table8) { 1099 const int width = glyph.fWidth; 1100 size_t dstRB = glyph.rowBytes(); 1101 uint8_t* SK_RESTRICT dst = (uint8_t*)glyph.fImage; 1102 1103 for (int y = 0; y < glyph.fHeight; y++) { 1104 for (int i = 0; i < width; ++i) { 1105 dst[i] = rgb_to_a8<APPLY_PREBLEND>(cgPixels[i], table8); 1106 } 1107 cgPixels = SkTAddOffset<const CGRGBPixel>(cgPixels, cgRowBytes); 1108 dst = SkTAddOffset<uint8_t>(dst, dstRB); 1109 } 1110 } 1111 1112 template<bool APPLY_PREBLEND> 1113 static inline uint16_t rgb_to_lcd16(CGRGBPixel rgb, const uint8_t* tableR, 1114 const uint8_t* tableG, 1115 const uint8_t* tableB) { 1116 U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>(0xFF - ((rgb >> 16) & 0xFF), tableR); 1117 U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>(0xFF - ((rgb >> 8) & 0xFF), tableG); 1118 U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>(0xFF - ((rgb >> 0) & 0xFF), tableB); 1119 #if SK_SHOW_TEXT_BLIT_COVERAGE 1120 r = SkTMax(r, (U8CPU)0x30); 1121 g = SkTMax(g, (U8CPU)0x30); 1122 b = SkTMax(b, (U8CPU)0x30); 1123 #endif 1124 return SkPack888ToRGB16(r, g, b); 1125 } 1126 template<bool APPLY_PREBLEND> 1127 static void rgb_to_lcd16(const CGRGBPixel* SK_RESTRICT cgPixels, size_t cgRowBytes, const SkGlyph& glyph, 1128 const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) { 1129 const int width = glyph.fWidth; 1130 size_t dstRB = glyph.rowBytes(); 1131 uint16_t* SK_RESTRICT dst = (uint16_t*)glyph.fImage; 1132 1133 for (int y = 0; y < glyph.fHeight; y++) { 1134 for (int i = 0; i < width; i++) { 1135 dst[i] = rgb_to_lcd16<APPLY_PREBLEND>(cgPixels[i], tableR, tableG, tableB); 1136 } 1137 cgPixels = SkTAddOffset<const CGRGBPixel>(cgPixels, cgRowBytes); 1138 dst = SkTAddOffset<uint16_t>(dst, dstRB); 1139 } 1140 } 1141 1142 static SkPMColor cgpixels_to_pmcolor(CGRGBPixel rgb) { 1143 U8CPU a = (rgb >> 24) & 0xFF; 1144 U8CPU r = (rgb >> 16) & 0xFF; 1145 U8CPU g = (rgb >> 8) & 0xFF; 1146 U8CPU b = (rgb >> 0) & 0xFF; 1147 #if SK_SHOW_TEXT_BLIT_COVERAGE 1148 a = SkTMax(a, (U8CPU)0x30); 1149 #endif 1150 return SkPackARGB32(a, r, g, b); 1151 } 1152 1153 void SkScalerContext_Mac::generateImage(const SkGlyph& glyph) { 1154 CGGlyph cgGlyph = SkTo<CGGlyph>(glyph.getGlyphID()); 1155 1156 // FIXME: lcd smoothed un-hinted rasterization unsupported. 1157 bool generateA8FromLCD = fRec.getHinting() != SkPaint::kNo_Hinting; 1158 1159 // Draw the glyph 1160 size_t cgRowBytes; 1161 CGRGBPixel* cgPixels = fOffscreen.getCG(*this, glyph, cgGlyph, &cgRowBytes, generateA8FromLCD); 1162 if (cgPixels == nullptr) { 1163 return; 1164 } 1165 1166 // Fix the glyph 1167 if ((glyph.fMaskFormat == SkMask::kLCD16_Format) || 1168 (glyph.fMaskFormat == SkMask::kA8_Format && supports_LCD() && generateA8FromLCD)) 1169 { 1170 const uint8_t* linear = gLinearCoverageFromCGLCDValue.data(); 1171 1172 //Note that the following cannot really be integrated into the 1173 //pre-blend, since we may not be applying the pre-blend; when we aren't 1174 //applying the pre-blend it means that a filter wants linear anyway. 1175 //Other code may also be applying the pre-blend, so we'd need another 1176 //one with this and one without. 1177 CGRGBPixel* addr = cgPixels; 1178 for (int y = 0; y < glyph.fHeight; ++y) { 1179 for (int x = 0; x < glyph.fWidth; ++x) { 1180 int r = (addr[x] >> 16) & 0xFF; 1181 int g = (addr[x] >> 8) & 0xFF; 1182 int b = (addr[x] >> 0) & 0xFF; 1183 addr[x] = (linear[r] << 16) | (linear[g] << 8) | linear[b]; 1184 } 1185 addr = SkTAddOffset<CGRGBPixel>(addr, cgRowBytes); 1186 } 1187 } 1188 1189 // Convert glyph to mask 1190 switch (glyph.fMaskFormat) { 1191 case SkMask::kLCD16_Format: { 1192 if (fPreBlend.isApplicable()) { 1193 rgb_to_lcd16<true>(cgPixels, cgRowBytes, glyph, 1194 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB); 1195 } else { 1196 rgb_to_lcd16<false>(cgPixels, cgRowBytes, glyph, 1197 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB); 1198 } 1199 } break; 1200 case SkMask::kA8_Format: { 1201 if (fPreBlend.isApplicable()) { 1202 rgb_to_a8<true>(cgPixels, cgRowBytes, glyph, fPreBlend.fG); 1203 } else { 1204 rgb_to_a8<false>(cgPixels, cgRowBytes, glyph, fPreBlend.fG); 1205 } 1206 } break; 1207 case SkMask::kBW_Format: { 1208 const int width = glyph.fWidth; 1209 size_t dstRB = glyph.rowBytes(); 1210 uint8_t* dst = (uint8_t*)glyph.fImage; 1211 for (int y = 0; y < glyph.fHeight; y++) { 1212 cgpixels_to_bits(dst, cgPixels, width); 1213 cgPixels = SkTAddOffset<CGRGBPixel>(cgPixels, cgRowBytes); 1214 dst = SkTAddOffset<uint8_t>(dst, dstRB); 1215 } 1216 } break; 1217 case SkMask::kARGB32_Format: { 1218 const int width = glyph.fWidth; 1219 size_t dstRB = glyph.rowBytes(); 1220 SkPMColor* dst = (SkPMColor*)glyph.fImage; 1221 for (int y = 0; y < glyph.fHeight; y++) { 1222 for (int x = 0; x < width; ++x) { 1223 dst[x] = cgpixels_to_pmcolor(cgPixels[x]); 1224 } 1225 cgPixels = SkTAddOffset<CGRGBPixel>(cgPixels, cgRowBytes); 1226 dst = SkTAddOffset<SkPMColor>(dst, dstRB); 1227 } 1228 } break; 1229 default: 1230 SkDEBUGFAIL("unexpected mask format"); 1231 break; 1232 } 1233 } 1234 1235 /* 1236 * Our subpixel resolution is only 2 bits in each direction, so a scale of 4 1237 * seems sufficient, and possibly even correct, to allow the hinted outline 1238 * to be subpixel positioned. 1239 */ 1240 #define kScaleForSubPixelPositionHinting (4.0f) 1241 1242 void SkScalerContext_Mac::generatePath(SkGlyphID glyph, SkPath* path) { 1243 AUTO_CG_LOCK(); 1244 1245 SkScalar scaleX = SK_Scalar1; 1246 SkScalar scaleY = SK_Scalar1; 1247 1248 CGAffineTransform xform = fTransform; 1249 /* 1250 * For subpixel positioning, we want to return an unhinted outline, so it 1251 * can be positioned nicely at fractional offsets. However, we special-case 1252 * if the baseline of the (horizontal) text is axis-aligned. In those cases 1253 * we want to retain hinting in the direction orthogonal to the baseline. 1254 * e.g. for horizontal baseline, we want to retain hinting in Y. 1255 * The way we remove hinting is to scale the font by some value (4) in that 1256 * direction, ask for the path, and then scale the path back down. 1257 */ 1258 if (fDoSubPosition) { 1259 // start out by assuming that we want no hining in X and Y 1260 scaleX = scaleY = kScaleForSubPixelPositionHinting; 1261 // now see if we need to restore hinting for axis-aligned baselines 1262 switch (this->computeAxisAlignmentForHText()) { 1263 case kX_SkAxisAlignment: 1264 scaleY = SK_Scalar1; // want hinting in the Y direction 1265 break; 1266 case kY_SkAxisAlignment: 1267 scaleX = SK_Scalar1; // want hinting in the X direction 1268 break; 1269 default: 1270 break; 1271 } 1272 1273 CGAffineTransform scale(CGAffineTransformMakeScale(ScalarToCG(scaleX), ScalarToCG(scaleY))); 1274 xform = CGAffineTransformConcat(fTransform, scale); 1275 } 1276 1277 CGGlyph cgGlyph = SkTo<CGGlyph>(glyph); 1278 UniqueCFRef<CGPathRef> cgPath(CTFontCreatePathForGlyph(fCTFont.get(), cgGlyph, &xform)); 1279 1280 path->reset(); 1281 if (cgPath != nullptr) { 1282 CGPathApply(cgPath.get(), path, SkScalerContext_Mac::CTPathElement); 1283 } 1284 1285 if (fDoSubPosition) { 1286 SkMatrix m; 1287 m.setScale(SkScalarInvert(scaleX), SkScalarInvert(scaleY)); 1288 path->transform(m); 1289 } 1290 if (fVertical) { 1291 SkPoint offset; 1292 getVerticalOffset(cgGlyph, &offset); 1293 path->offset(offset.fX, offset.fY); 1294 } 1295 } 1296 1297 void SkScalerContext_Mac::generateFontMetrics(SkPaint::FontMetrics* metrics) { 1298 if (nullptr == metrics) { 1299 return; 1300 } 1301 1302 AUTO_CG_LOCK(); 1303 1304 CGRect theBounds = CTFontGetBoundingBox(fCTFont.get()); 1305 1306 metrics->fTop = CGToScalar(-CGRectGetMaxY_inline(theBounds)); 1307 metrics->fAscent = CGToScalar(-CTFontGetAscent(fCTFont.get())); 1308 metrics->fDescent = CGToScalar( CTFontGetDescent(fCTFont.get())); 1309 metrics->fBottom = CGToScalar(-CGRectGetMinY_inline(theBounds)); 1310 metrics->fLeading = CGToScalar( CTFontGetLeading(fCTFont.get())); 1311 metrics->fAvgCharWidth = CGToScalar( CGRectGetWidth_inline(theBounds)); 1312 metrics->fXMin = CGToScalar( CGRectGetMinX_inline(theBounds)); 1313 metrics->fXMax = CGToScalar( CGRectGetMaxX_inline(theBounds)); 1314 metrics->fMaxCharWidth = metrics->fXMax - metrics->fXMin; 1315 metrics->fXHeight = CGToScalar( CTFontGetXHeight(fCTFont.get())); 1316 metrics->fCapHeight = CGToScalar( CTFontGetCapHeight(fCTFont.get())); 1317 metrics->fUnderlineThickness = CGToScalar( CTFontGetUnderlineThickness(fCTFont.get())); 1318 metrics->fUnderlinePosition = -CGToScalar( CTFontGetUnderlinePosition(fCTFont.get())); 1319 1320 metrics->fFlags = 0; 1321 metrics->fFlags |= SkPaint::FontMetrics::kUnderlineThicknessIsValid_Flag; 1322 metrics->fFlags |= SkPaint::FontMetrics::kUnderlinePositionIsValid_Flag; 1323 1324 // See https://bugs.chromium.org/p/skia/issues/detail?id=6203 1325 // At least on 10.12.3 with memory based fonts the x-height is always 0.6666 of the ascent and 1326 // the cap-height is always 0.8888 of the ascent. It appears that the values from the 'OS/2' 1327 // table are read, but then overwritten if the font is not a system font. As a result, if there 1328 // is a valid 'OS/2' table available use the values from the table if they aren't too strange. 1329 struct OS2HeightMetrics { 1330 SK_OT_SHORT sxHeight; 1331 SK_OT_SHORT sCapHeight; 1332 } heights; 1333 size_t bytesRead = this->getTypeface()->getTableData( 1334 SkTEndian_SwapBE32(SkOTTableOS2::TAG), offsetof(SkOTTableOS2, version.v2.sxHeight), 1335 sizeof(heights), &heights); 1336 if (bytesRead == sizeof(heights)) { 1337 // 'fontSize' is correct because the entire resolved size is set by the constructor. 1338 CGFloat fontSize = CTFontGetSize(this->fCTFont.get()); 1339 unsigned upem = CTFontGetUnitsPerEm(this->fCTFont.get()); 1340 unsigned maxSaneHeight = upem * 2; 1341 uint16_t xHeight = SkEndian_SwapBE16(heights.sxHeight); 1342 if (xHeight && xHeight < maxSaneHeight) { 1343 metrics->fXHeight = CGToScalar(xHeight * fontSize / upem); 1344 } 1345 uint16_t capHeight = SkEndian_SwapBE16(heights.sCapHeight); 1346 if (capHeight && capHeight < maxSaneHeight) { 1347 metrics->fCapHeight = CGToScalar(capHeight * fontSize / upem); 1348 } 1349 } 1350 } 1351 1352 void SkScalerContext_Mac::CTPathElement(void *info, const CGPathElement *element) { 1353 SkPath* skPath = (SkPath*)info; 1354 1355 // Process the path element 1356 switch (element->type) { 1357 case kCGPathElementMoveToPoint: 1358 skPath->moveTo(element->points[0].x, -element->points[0].y); 1359 break; 1360 1361 case kCGPathElementAddLineToPoint: 1362 skPath->lineTo(element->points[0].x, -element->points[0].y); 1363 break; 1364 1365 case kCGPathElementAddQuadCurveToPoint: 1366 skPath->quadTo(element->points[0].x, -element->points[0].y, 1367 element->points[1].x, -element->points[1].y); 1368 break; 1369 1370 case kCGPathElementAddCurveToPoint: 1371 skPath->cubicTo(element->points[0].x, -element->points[0].y, 1372 element->points[1].x, -element->points[1].y, 1373 element->points[2].x, -element->points[2].y); 1374 break; 1375 1376 case kCGPathElementCloseSubpath: 1377 skPath->close(); 1378 break; 1379 1380 default: 1381 SkDEBUGFAIL("Unknown path element!"); 1382 break; 1383 } 1384 } 1385 1386 1387 /////////////////////////////////////////////////////////////////////////////// 1388 1389 // Returns nullptr on failure 1390 // Call must still manage its ownership of provider 1391 static sk_sp<SkTypeface> create_from_dataProvider(UniqueCFRef<CGDataProviderRef> provider, 1392 int ttcIndex) { 1393 if (ttcIndex != 0) { 1394 return nullptr; 1395 } 1396 UniqueCFRef<CGFontRef> cg(CGFontCreateWithDataProvider(provider.get())); 1397 if (!cg) { 1398 return nullptr; 1399 } 1400 UniqueCFRef<CTFontRef> ct(CTFontCreateWithGraphicsFont(cg.get(), 0, nullptr, nullptr)); 1401 if (!ct) { 1402 return nullptr; 1403 } 1404 return create_from_CTFontRef(std::move(ct), nullptr, true); 1405 } 1406 1407 // Web fonts added to the CTFont registry do not return their character set. 1408 // Iterate through the font in this case. The existing caller caches the result, 1409 // so the performance impact isn't too bad. 1410 static void populate_glyph_to_unicode_slow(CTFontRef ctFont, CFIndex glyphCount, 1411 SkTDArray<SkUnichar>* glyphToUnicode) { 1412 glyphToUnicode->setCount(SkToInt(glyphCount)); 1413 SkUnichar* out = glyphToUnicode->begin(); 1414 sk_bzero(out, glyphCount * sizeof(SkUnichar)); 1415 UniChar unichar = 0; 1416 while (glyphCount > 0) { 1417 CGGlyph glyph; 1418 if (CTFontGetGlyphsForCharacters(ctFont, &unichar, &glyph, 1)) { 1419 if (out[glyph] != 0) { 1420 out[glyph] = unichar; 1421 --glyphCount; 1422 } 1423 } 1424 if (++unichar == 0) { 1425 break; 1426 } 1427 } 1428 } 1429 1430 // Construct Glyph to Unicode table. 1431 // Unicode code points that require conjugate pairs in utf16 are not 1432 // supported. 1433 static void populate_glyph_to_unicode(CTFontRef ctFont, CFIndex glyphCount, 1434 SkTDArray<SkUnichar>* glyphToUnicode) { 1435 UniqueCFRef<CFCharacterSetRef> charSet(CTFontCopyCharacterSet(ctFont)); 1436 if (!charSet) { 1437 populate_glyph_to_unicode_slow(ctFont, glyphCount, glyphToUnicode); 1438 return; 1439 } 1440 1441 UniqueCFRef<CFDataRef> bitmap(CFCharacterSetCreateBitmapRepresentation(nullptr, charSet.get())); 1442 if (!bitmap) { 1443 return; 1444 } 1445 CFIndex length = CFDataGetLength(bitmap.get()); 1446 if (!length) { 1447 return; 1448 } 1449 if (length > 8192) { 1450 // TODO: Add support for Unicode above 0xFFFF 1451 // Consider only the BMP portion of the Unicode character points. 1452 // The bitmap may contain other planes, up to plane 16. 1453 // See http://developer.apple.com/library/ios/#documentation/CoreFoundation/Reference/CFCharacterSetRef/Reference/reference.html 1454 length = 8192; 1455 } 1456 const UInt8* bits = CFDataGetBytePtr(bitmap.get()); 1457 glyphToUnicode->setCount(SkToInt(glyphCount)); 1458 SkUnichar* out = glyphToUnicode->begin(); 1459 sk_bzero(out, glyphCount * sizeof(SkUnichar)); 1460 for (int i = 0; i < length; i++) { 1461 int mask = bits[i]; 1462 if (!mask) { 1463 continue; 1464 } 1465 for (int j = 0; j < 8; j++) { 1466 CGGlyph glyph; 1467 UniChar unichar = static_cast<UniChar>((i << 3) + j); 1468 if (mask & (1 << j) && CTFontGetGlyphsForCharacters(ctFont, &unichar, &glyph, 1)) { 1469 out[glyph] = unichar; 1470 } 1471 } 1472 } 1473 } 1474 1475 /** Assumes src and dst are not nullptr. */ 1476 static void CFStringToSkString(CFStringRef src, SkString* dst) { 1477 // Reserve enough room for the worst-case string, 1478 // plus 1 byte for the trailing null. 1479 CFIndex length = CFStringGetMaximumSizeForEncoding(CFStringGetLength(src), 1480 kCFStringEncodingUTF8) + 1; 1481 dst->resize(length); 1482 CFStringGetCString(src, dst->writable_str(), length, kCFStringEncodingUTF8); 1483 // Resize to the actual UTF-8 length used, stripping the null character. 1484 dst->resize(strlen(dst->c_str())); 1485 } 1486 1487 std::unique_ptr<SkAdvancedTypefaceMetrics> SkTypeface_Mac::onGetAdvancedMetrics() const { 1488 1489 AUTO_CG_LOCK(); 1490 1491 UniqueCFRef<CTFontRef> ctFont = 1492 ctfont_create_exact_copy(fFontRef.get(), CTFontGetUnitsPerEm(fFontRef.get()), nullptr); 1493 1494 std::unique_ptr<SkAdvancedTypefaceMetrics> info(new SkAdvancedTypefaceMetrics); 1495 1496 { 1497 UniqueCFRef<CFStringRef> fontName(CTFontCopyPostScriptName(ctFont.get())); 1498 if (fontName.get()) { 1499 CFStringToSkString(fontName.get(), &info->fFontName); 1500 } 1501 } 1502 1503 // In 10.10 and earlier, CTFontCopyVariationAxes and CTFontCopyVariation do not work when 1504 // applied to fonts which started life with CGFontCreateWithDataProvider (they simply always 1505 // return nullptr). As a result, we are limited to CGFontCopyVariationAxes and 1506 // CGFontCopyVariations here until support for 10.10 and earlier is removed. 1507 UniqueCFRef<CGFontRef> cgFont(CTFontCopyGraphicsFont(ctFont.get(), nullptr)); 1508 if (cgFont) { 1509 UniqueCFRef<CFArrayRef> cgAxes(CGFontCopyVariationAxes(cgFont.get())); 1510 if (cgAxes && CFArrayGetCount(cgAxes.get()) > 0) { 1511 info->fFlags |= SkAdvancedTypefaceMetrics::kMultiMaster_FontFlag; 1512 } 1513 } 1514 1515 CFIndex glyphCount = CTFontGetGlyphCount(ctFont.get()); 1516 1517 populate_glyph_to_unicode(ctFont.get(), glyphCount, &info->fGlyphToUnicode); 1518 1519 SkOTTableOS2_V4::Type fsType; 1520 if (sizeof(fsType) == this->getTableData(SkTEndian_SwapBE32(SkOTTableOS2::TAG), 1521 offsetof(SkOTTableOS2_V4, fsType), 1522 sizeof(fsType), 1523 &fsType)) { 1524 SkOTUtils::SetAdvancedTypefaceFlags(fsType, info.get()); 1525 } 1526 1527 // If it's not a truetype font, mark it as 'other'. Assume that TrueType 1528 // fonts always have both glyf and loca tables. At the least, this is what 1529 // sfntly needs to subset the font. CTFontCopyAttribute() does not always 1530 // succeed in determining this directly. 1531 if (!this->getTableSize('glyf') || !this->getTableSize('loca')) { 1532 return info; 1533 } 1534 1535 info->fType = SkAdvancedTypefaceMetrics::kTrueType_Font; 1536 CTFontSymbolicTraits symbolicTraits = CTFontGetSymbolicTraits(ctFont.get()); 1537 if (symbolicTraits & kCTFontMonoSpaceTrait) { 1538 info->fStyle |= SkAdvancedTypefaceMetrics::kFixedPitch_Style; 1539 } 1540 if (symbolicTraits & kCTFontItalicTrait) { 1541 info->fStyle |= SkAdvancedTypefaceMetrics::kItalic_Style; 1542 } 1543 CTFontStylisticClass stylisticClass = symbolicTraits & kCTFontClassMaskTrait; 1544 if (stylisticClass >= kCTFontOldStyleSerifsClass && stylisticClass <= kCTFontSlabSerifsClass) { 1545 info->fStyle |= SkAdvancedTypefaceMetrics::kSerif_Style; 1546 } else if (stylisticClass & kCTFontScriptsClass) { 1547 info->fStyle |= SkAdvancedTypefaceMetrics::kScript_Style; 1548 } 1549 info->fItalicAngle = (int16_t) CTFontGetSlantAngle(ctFont.get()); 1550 info->fAscent = (int16_t) CTFontGetAscent(ctFont.get()); 1551 info->fDescent = (int16_t) CTFontGetDescent(ctFont.get()); 1552 info->fCapHeight = (int16_t) CTFontGetCapHeight(ctFont.get()); 1553 CGRect bbox = CTFontGetBoundingBox(ctFont.get()); 1554 1555 SkRect r; 1556 r.set( CGToScalar(CGRectGetMinX_inline(bbox)), // Left 1557 CGToScalar(CGRectGetMaxY_inline(bbox)), // Top 1558 CGToScalar(CGRectGetMaxX_inline(bbox)), // Right 1559 CGToScalar(CGRectGetMinY_inline(bbox))); // Bottom 1560 1561 r.roundOut(&(info->fBBox)); 1562 1563 // Figure out a good guess for StemV - Min width of i, I, !, 1. 1564 // This probably isn't very good with an italic font. 1565 int16_t min_width = SHRT_MAX; 1566 info->fStemV = 0; 1567 static const UniChar stem_chars[] = {'i', 'I', '!', '1'}; 1568 const size_t count = sizeof(stem_chars) / sizeof(stem_chars[0]); 1569 CGGlyph glyphs[count]; 1570 CGRect boundingRects[count]; 1571 if (CTFontGetGlyphsForCharacters(ctFont.get(), stem_chars, glyphs, count)) { 1572 CTFontGetBoundingRectsForGlyphs(ctFont.get(), kCTFontOrientationHorizontal, 1573 glyphs, boundingRects, count); 1574 for (size_t i = 0; i < count; i++) { 1575 int16_t width = (int16_t) boundingRects[i].size.width; 1576 if (width > 0 && width < min_width) { 1577 min_width = width; 1578 info->fStemV = min_width; 1579 } 1580 } 1581 } 1582 return info; 1583 } 1584 1585 /////////////////////////////////////////////////////////////////////////////// 1586 1587 static SK_SFNT_ULONG get_font_type_tag(const SkTypeface_Mac* typeface) { 1588 CTFontRef ctFont = typeface->fFontRef.get(); 1589 UniqueCFRef<CFNumberRef> fontFormatRef( 1590 static_cast<CFNumberRef>(CTFontCopyAttribute(ctFont, kCTFontFormatAttribute))); 1591 if (!fontFormatRef) { 1592 return 0; 1593 } 1594 1595 SInt32 fontFormatValue; 1596 if (!CFNumberGetValue(fontFormatRef.get(), kCFNumberSInt32Type, &fontFormatValue)) { 1597 return 0; 1598 } 1599 1600 switch (fontFormatValue) { 1601 case kCTFontFormatOpenTypePostScript: 1602 return SkSFNTHeader::fontType_OpenTypeCFF::TAG; 1603 case kCTFontFormatOpenTypeTrueType: 1604 return SkSFNTHeader::fontType_WindowsTrueType::TAG; 1605 case kCTFontFormatTrueType: 1606 return SkSFNTHeader::fontType_MacTrueType::TAG; 1607 case kCTFontFormatPostScript: 1608 return SkSFNTHeader::fontType_PostScript::TAG; 1609 case kCTFontFormatBitmap: 1610 return SkSFNTHeader::fontType_MacTrueType::TAG; 1611 case kCTFontFormatUnrecognized: 1612 default: 1613 //CT seems to be unreliable in being able to obtain the type, 1614 //even if all we want is the first four bytes of the font resource. 1615 //Just the presence of the FontForge 'FFTM' table seems to throw it off. 1616 return SkSFNTHeader::fontType_WindowsTrueType::TAG; 1617 } 1618 } 1619 1620 SkStreamAsset* SkTypeface_Mac::onOpenStream(int* ttcIndex) const { 1621 SK_SFNT_ULONG fontType = get_font_type_tag(this); 1622 if (0 == fontType) { 1623 return nullptr; 1624 } 1625 1626 // get table tags 1627 int numTables = this->countTables(); 1628 SkTDArray<SkFontTableTag> tableTags; 1629 tableTags.setCount(numTables); 1630 this->getTableTags(tableTags.begin()); 1631 1632 // calc total size for font, save sizes 1633 SkTDArray<size_t> tableSizes; 1634 size_t totalSize = sizeof(SkSFNTHeader) + sizeof(SkSFNTHeader::TableDirectoryEntry) * numTables; 1635 for (int tableIndex = 0; tableIndex < numTables; ++tableIndex) { 1636 size_t tableSize = this->getTableSize(tableTags[tableIndex]); 1637 totalSize += (tableSize + 3) & ~3; 1638 *tableSizes.append() = tableSize; 1639 } 1640 1641 // reserve memory for stream, and zero it (tables must be zero padded) 1642 SkMemoryStream* stream = new SkMemoryStream(totalSize); 1643 char* dataStart = (char*)stream->getMemoryBase(); 1644 sk_bzero(dataStart, totalSize); 1645 char* dataPtr = dataStart; 1646 1647 // compute font header entries 1648 uint16_t entrySelector = 0; 1649 uint16_t searchRange = 1; 1650 while (searchRange < numTables >> 1) { 1651 entrySelector++; 1652 searchRange <<= 1; 1653 } 1654 searchRange <<= 4; 1655 uint16_t rangeShift = (numTables << 4) - searchRange; 1656 1657 // write font header 1658 SkSFNTHeader* header = (SkSFNTHeader*)dataPtr; 1659 header->fontType = fontType; 1660 header->numTables = SkEndian_SwapBE16(numTables); 1661 header->searchRange = SkEndian_SwapBE16(searchRange); 1662 header->entrySelector = SkEndian_SwapBE16(entrySelector); 1663 header->rangeShift = SkEndian_SwapBE16(rangeShift); 1664 dataPtr += sizeof(SkSFNTHeader); 1665 1666 // write tables 1667 SkSFNTHeader::TableDirectoryEntry* entry = (SkSFNTHeader::TableDirectoryEntry*)dataPtr; 1668 dataPtr += sizeof(SkSFNTHeader::TableDirectoryEntry) * numTables; 1669 for (int tableIndex = 0; tableIndex < numTables; ++tableIndex) { 1670 size_t tableSize = tableSizes[tableIndex]; 1671 this->getTableData(tableTags[tableIndex], 0, tableSize, dataPtr); 1672 entry->tag = SkEndian_SwapBE32(tableTags[tableIndex]); 1673 entry->checksum = SkEndian_SwapBE32(SkOTUtils::CalcTableChecksum((SK_OT_ULONG*)dataPtr, 1674 tableSize)); 1675 entry->offset = SkEndian_SwapBE32(SkToU32(dataPtr - dataStart)); 1676 entry->logicalLength = SkEndian_SwapBE32(SkToU32(tableSize)); 1677 1678 dataPtr += (tableSize + 3) & ~3; 1679 ++entry; 1680 } 1681 1682 *ttcIndex = 0; 1683 return stream; 1684 } 1685 1686 struct NonDefaultAxesContext { 1687 SkFixed* axisValue; 1688 CFArrayRef cgAxes; 1689 }; 1690 static void set_non_default_axes(CFTypeRef key, CFTypeRef value, void* context) { 1691 NonDefaultAxesContext* self = static_cast<NonDefaultAxesContext*>(context); 1692 1693 if (CFGetTypeID(key) != CFStringGetTypeID() || CFGetTypeID(value) != CFNumberGetTypeID()) { 1694 return; 1695 } 1696 1697 // The key is a CFString which is a string from the 'name' table. 1698 // Search the cgAxes for an axis with this name, and use its index to store the value. 1699 CFIndex keyIndex = -1; 1700 CFStringRef keyString = static_cast<CFStringRef>(key); 1701 for (CFIndex i = 0; i < CFArrayGetCount(self->cgAxes); ++i) { 1702 CFTypeRef cgAxis = CFArrayGetValueAtIndex(self->cgAxes, i); 1703 if (CFGetTypeID(cgAxis) != CFDictionaryGetTypeID()) { 1704 continue; 1705 } 1706 1707 CFDictionaryRef cgAxisDict = static_cast<CFDictionaryRef>(cgAxis); 1708 CFTypeRef cgAxisName = CFDictionaryGetValue(cgAxisDict, kCGFontVariationAxisName); 1709 if (!cgAxisName || CFGetTypeID(cgAxisName) != CFStringGetTypeID()) { 1710 continue; 1711 } 1712 CFStringRef cgAxisNameString = static_cast<CFStringRef>(cgAxisName); 1713 if (CFStringCompare(keyString, cgAxisNameString, 0) == kCFCompareEqualTo) { 1714 keyIndex = i; 1715 break; 1716 } 1717 } 1718 if (keyIndex == -1) { 1719 return; 1720 } 1721 1722 CFNumberRef valueNumber = static_cast<CFNumberRef>(value); 1723 double valueDouble; 1724 if (!CFNumberGetValue(valueNumber, kCFNumberDoubleType, &valueDouble) || 1725 valueDouble < SkFixedToDouble(SK_FixedMin) || SkFixedToDouble(SK_FixedMax) < valueDouble) 1726 { 1727 return; 1728 } 1729 self->axisValue[keyIndex] = SkDoubleToFixed(valueDouble); 1730 } 1731 static bool get_variations(CTFontRef ctFont, CFIndex* cgAxisCount, 1732 SkAutoSTMalloc<4, SkFixed>* axisValues) 1733 { 1734 // In 10.10 and earlier, CTFontCopyVariationAxes and CTFontCopyVariation do not work when 1735 // applied to fonts which started life with CGFontCreateWithDataProvider (they simply always 1736 // return nullptr). As a result, we are limited to CGFontCopyVariationAxes and 1737 // CGFontCopyVariations here until support for 10.10 and earlier is removed. 1738 UniqueCFRef<CGFontRef> cgFont(CTFontCopyGraphicsFont(ctFont, nullptr)); 1739 if (!cgFont) { 1740 return false; 1741 } 1742 1743 UniqueCFRef<CFDictionaryRef> cgVariations(CGFontCopyVariations(cgFont.get())); 1744 // If a font has no variations CGFontCopyVariations returns nullptr (instead of an empty dict). 1745 if (!cgVariations) { 1746 return false; 1747 } 1748 1749 UniqueCFRef<CFArrayRef> cgAxes(CGFontCopyVariationAxes(cgFont.get())); 1750 if (!cgAxes) { 1751 return false; 1752 } 1753 *cgAxisCount = CFArrayGetCount(cgAxes.get()); 1754 axisValues->reset(*cgAxisCount); 1755 1756 // Set all of the axes to their default values. 1757 // Fail if any default value cannot be determined. 1758 for (CFIndex i = 0; i < *cgAxisCount; ++i) { 1759 CFTypeRef cgAxis = CFArrayGetValueAtIndex(cgAxes.get(), i); 1760 if (CFGetTypeID(cgAxis) != CFDictionaryGetTypeID()) { 1761 return false; 1762 } 1763 1764 CFDictionaryRef cgAxisDict = static_cast<CFDictionaryRef>(cgAxis); 1765 CFTypeRef axisDefaultValue = CFDictionaryGetValue(cgAxisDict, 1766 kCGFontVariationAxisDefaultValue); 1767 if (!axisDefaultValue || CFGetTypeID(axisDefaultValue) != CFNumberGetTypeID()) { 1768 return false; 1769 } 1770 CFNumberRef axisDefaultValueNumber = static_cast<CFNumberRef>(axisDefaultValue); 1771 double axisDefaultValueDouble; 1772 if (!CFNumberGetValue(axisDefaultValueNumber, kCFNumberDoubleType, &axisDefaultValueDouble)) 1773 { 1774 return false; 1775 } 1776 if (axisDefaultValueDouble < SkFixedToDouble(SK_FixedMin) || 1777 SkFixedToDouble(SK_FixedMax) < axisDefaultValueDouble) 1778 { 1779 return false; 1780 } 1781 (*axisValues)[(int)i] = SkDoubleToFixed(axisDefaultValueDouble); 1782 } 1783 1784 // Override the default values with the given font's stated axis values. 1785 NonDefaultAxesContext c = { axisValues->get(), cgAxes.get() }; 1786 CFDictionaryApplyFunction(cgVariations.get(), set_non_default_axes, &c); 1787 1788 return true; 1789 } 1790 std::unique_ptr<SkFontData> SkTypeface_Mac::onMakeFontData() const { 1791 int index; 1792 std::unique_ptr<SkStreamAsset> stream(this->onOpenStream(&index)); 1793 1794 CFIndex cgAxisCount; 1795 SkAutoSTMalloc<4, SkFixed> axisValues; 1796 if (get_variations(fFontRef.get(), &cgAxisCount, &axisValues)) { 1797 return skstd::make_unique<SkFontData>(std::move(stream), index, 1798 axisValues.get(), cgAxisCount); 1799 } 1800 return skstd::make_unique<SkFontData>(std::move(stream), index, nullptr, 0); 1801 } 1802 1803 /** Creates a CT variation dictionary {tag, value} from a CG variation dictionary {name, value}. */ 1804 static UniqueCFRef<CFDictionaryRef> ct_variation_from_cg_variation(CFDictionaryRef cgVariations, 1805 CFArrayRef ctAxes) { 1806 1807 UniqueCFRef<CFMutableDictionaryRef> ctVariations( 1808 CFDictionaryCreateMutable(kCFAllocatorDefault, 0, 1809 &kCFTypeDictionaryKeyCallBacks, 1810 &kCFTypeDictionaryValueCallBacks)); 1811 1812 CFIndex axisCount = CFArrayGetCount(ctAxes); 1813 for (CFIndex i = 0; i < axisCount; ++i) { 1814 CFTypeRef axisInfo = CFArrayGetValueAtIndex(ctAxes, i); 1815 if (CFDictionaryGetTypeID() != CFGetTypeID(axisInfo)) { 1816 return nullptr; 1817 } 1818 CFDictionaryRef axisInfoDict = static_cast<CFDictionaryRef>(axisInfo); 1819 1820 // The assumption is that values produced by kCTFontVariationAxisNameKey and 1821 // kCGFontVariationAxisName will always be equal. 1822 CFTypeRef axisName = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisNameKey); 1823 if (!axisName || CFGetTypeID(axisName) != CFStringGetTypeID()) { 1824 return nullptr; 1825 } 1826 1827 CFTypeRef axisValue = CFDictionaryGetValue(cgVariations, axisName); 1828 if (!axisValue || CFGetTypeID(axisValue) != CFNumberGetTypeID()) { 1829 return nullptr; 1830 } 1831 1832 CFTypeRef axisTag = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisIdentifierKey); 1833 if (!axisTag || CFGetTypeID(axisTag) != CFNumberGetTypeID()) { 1834 return nullptr; 1835 } 1836 1837 CFDictionaryAddValue(ctVariations.get(), axisTag, axisValue); 1838 } 1839 return std::move(ctVariations); 1840 } 1841 1842 int SkTypeface_Mac::onGetVariationDesignPosition( 1843 SkFontArguments::VariationPosition::Coordinate coordinates[], int coordinateCount) const 1844 { 1845 // The CGFont variation data does not contain the tag. 1846 1847 // CTFontCopyVariationAxes returns nullptr for CGFontCreateWithDataProvider fonts with 1848 // macOS 10.10 and iOS 9 or earlier. When this happens, there is no API to provide the tag. 1849 UniqueCFRef<CFArrayRef> ctAxes(CTFontCopyVariationAxes(fFontRef.get())); 1850 if (!ctAxes) { 1851 return -1; 1852 } 1853 CFIndex axisCount = CFArrayGetCount(ctAxes.get()); 1854 if (!coordinates || coordinateCount < axisCount) { 1855 return axisCount; 1856 } 1857 1858 // This call always returns nullptr on 10.11 and under for CGFontCreateWithDataProvider fonts. 1859 // When this happens, try converting the CG variation to a CT variation. 1860 // On 10.12 and later, this only returns non-default variations. 1861 UniqueCFRef<CFDictionaryRef> ctVariations(CTFontCopyVariation(fFontRef.get())); 1862 if (!ctVariations) { 1863 // When 10.11 and earlier are no longer supported, the following code can be replaced with 1864 // return -1 and ct_variation_from_cg_variation can be removed. 1865 UniqueCFRef<CGFontRef> cgFont(CTFontCopyGraphicsFont(fFontRef.get(), nullptr)); 1866 if (!cgFont) { 1867 return -1; 1868 } 1869 UniqueCFRef<CFDictionaryRef> cgVariations(CGFontCopyVariations(cgFont.get())); 1870 if (!cgVariations) { 1871 return -1; 1872 } 1873 ctVariations = ct_variation_from_cg_variation(cgVariations.get(), ctAxes.get()); 1874 if (!ctVariations) { 1875 return -1; 1876 } 1877 } 1878 1879 for (int i = 0; i < axisCount; ++i) { 1880 CFTypeRef axisInfo = CFArrayGetValueAtIndex(ctAxes.get(), i); 1881 if (CFDictionaryGetTypeID() != CFGetTypeID(axisInfo)) { 1882 return -1; 1883 } 1884 CFDictionaryRef axisInfoDict = static_cast<CFDictionaryRef>(axisInfo); 1885 1886 CFTypeRef tag = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisIdentifierKey); 1887 if (!tag || CFGetTypeID(tag) != CFNumberGetTypeID()) { 1888 return -1; 1889 } 1890 CFNumberRef tagNumber = static_cast<CFNumberRef>(tag); 1891 int64_t tagLong; 1892 if (!CFNumberGetValue(tagNumber, kCFNumberSInt64Type, &tagLong)) { 1893 return -1; 1894 } 1895 coordinates[i].axis = tagLong; 1896 1897 CGFloat variationCGFloat; 1898 CFTypeRef variationValue = CFDictionaryGetValue(ctVariations.get(), tagNumber); 1899 if (variationValue) { 1900 if (CFGetTypeID(variationValue) != CFNumberGetTypeID()) { 1901 return -1; 1902 } 1903 CFNumberRef variationNumber = static_cast<CFNumberRef>(variationValue); 1904 if (!CFNumberGetValue(variationNumber, kCFNumberCGFloatType, &variationCGFloat)) { 1905 return -1; 1906 } 1907 } else { 1908 CFTypeRef def = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisDefaultValueKey); 1909 if (!def || CFGetTypeID(def) != CFNumberGetTypeID()) { 1910 return -1; 1911 } 1912 CFNumberRef defNumber = static_cast<CFNumberRef>(def); 1913 if (!CFNumberGetValue(defNumber, kCFNumberCGFloatType, &variationCGFloat)) { 1914 return -1; 1915 } 1916 } 1917 coordinates[i].value = CGToScalar(variationCGFloat); 1918 1919 } 1920 return axisCount; 1921 } 1922 1923 /////////////////////////////////////////////////////////////////////////////// 1924 /////////////////////////////////////////////////////////////////////////////// 1925 1926 int SkTypeface_Mac::onGetUPEM() const { 1927 UniqueCFRef<CGFontRef> cgFont(CTFontCopyGraphicsFont(fFontRef.get(), nullptr)); 1928 return CGFontGetUnitsPerEm(cgFont.get()); 1929 } 1930 1931 SkTypeface::LocalizedStrings* SkTypeface_Mac::onCreateFamilyNameIterator() const { 1932 SkTypeface::LocalizedStrings* nameIter = 1933 SkOTUtils::LocalizedStrings_NameTable::CreateForFamilyNames(*this); 1934 if (nullptr == nameIter) { 1935 CFStringRef cfLanguageRaw; 1936 UniqueCFRef<CFStringRef> cfFamilyName( 1937 CTFontCopyLocalizedName(fFontRef.get(), kCTFontFamilyNameKey, &cfLanguageRaw)); 1938 UniqueCFRef<CFStringRef> cfLanguage(cfLanguageRaw); 1939 1940 SkString skLanguage; 1941 SkString skFamilyName; 1942 if (cfLanguage) { 1943 CFStringToSkString(cfLanguage.get(), &skLanguage); 1944 } else { 1945 skLanguage = "und"; //undetermined 1946 } 1947 if (cfFamilyName) { 1948 CFStringToSkString(cfFamilyName.get(), &skFamilyName); 1949 } 1950 1951 nameIter = new SkOTUtils::LocalizedStrings_SingleName(skFamilyName, skLanguage); 1952 } 1953 return nameIter; 1954 } 1955 1956 int SkTypeface_Mac::onGetTableTags(SkFontTableTag tags[]) const { 1957 UniqueCFRef<CFArrayRef> cfArray( 1958 CTFontCopyAvailableTables(fFontRef.get(), kCTFontTableOptionNoOptions)); 1959 if (!cfArray) { 1960 return 0; 1961 } 1962 int count = SkToInt(CFArrayGetCount(cfArray.get())); 1963 if (tags) { 1964 for (int i = 0; i < count; ++i) { 1965 uintptr_t fontTag = reinterpret_cast<uintptr_t>( 1966 CFArrayGetValueAtIndex(cfArray.get(), i)); 1967 tags[i] = static_cast<SkFontTableTag>(fontTag); 1968 } 1969 } 1970 return count; 1971 } 1972 1973 // If, as is the case with web fonts, the CTFont data isn't available, 1974 // the CGFont data may work. While the CGFont may always provide the 1975 // right result, leave the CTFont code path to minimize disruption. 1976 static UniqueCFRef<CFDataRef> copy_table_from_font(CTFontRef ctFont, SkFontTableTag tag) { 1977 UniqueCFRef<CFDataRef> data(CTFontCopyTable(ctFont, (CTFontTableTag) tag, 1978 kCTFontTableOptionNoOptions)); 1979 if (!data) { 1980 UniqueCFRef<CGFontRef> cgFont(CTFontCopyGraphicsFont(ctFont, nullptr)); 1981 data.reset(CGFontCopyTableForTag(cgFont.get(), tag)); 1982 } 1983 return data; 1984 } 1985 1986 size_t SkTypeface_Mac::onGetTableData(SkFontTableTag tag, size_t offset, 1987 size_t length, void* dstData) const { 1988 UniqueCFRef<CFDataRef> srcData = copy_table_from_font(fFontRef.get(), tag); 1989 if (!srcData) { 1990 return 0; 1991 } 1992 1993 size_t srcSize = CFDataGetLength(srcData.get()); 1994 if (offset >= srcSize) { 1995 return 0; 1996 } 1997 if (length > srcSize - offset) { 1998 length = srcSize - offset; 1999 } 2000 if (dstData) { 2001 memcpy(dstData, CFDataGetBytePtr(srcData.get()) + offset, length); 2002 } 2003 return length; 2004 } 2005 2006 SkScalerContext* SkTypeface_Mac::onCreateScalerContext(const SkScalerContextEffects& effects, 2007 const SkDescriptor* desc) const { 2008 return new SkScalerContext_Mac(sk_ref_sp(const_cast<SkTypeface_Mac*>(this)), effects, desc); 2009 } 2010 2011 void SkTypeface_Mac::onFilterRec(SkScalerContextRec* rec) const { 2012 if (rec->fFlags & SkScalerContext::kLCD_BGROrder_Flag || 2013 rec->fFlags & SkScalerContext::kLCD_Vertical_Flag) 2014 { 2015 rec->fMaskFormat = SkMask::kA8_Format; 2016 // Render the glyphs as close as possible to what was requested. 2017 // The above turns off subpixel rendering, but the user requested it. 2018 // Normal hinting will cause the A8 masks to be generated from CoreGraphics subpixel masks. 2019 // See comments below for more details. 2020 rec->setHinting(SkPaint::kNormal_Hinting); 2021 } 2022 2023 unsigned flagsWeDontSupport = SkScalerContext::kDevKernText_Flag | 2024 SkScalerContext::kForceAutohinting_Flag | 2025 SkScalerContext::kLCD_BGROrder_Flag | 2026 SkScalerContext::kLCD_Vertical_Flag; 2027 2028 rec->fFlags &= ~flagsWeDontSupport; 2029 2030 bool lcdSupport = supports_LCD(); 2031 2032 // Only two levels of hinting are supported. 2033 // kNo_Hinting means avoid CoreGraphics outline dilation. 2034 // kNormal_Hinting means CoreGraphics outline dilation is allowed. 2035 // If there is no lcd support, hinting (dilation) cannot be supported. 2036 SkPaint::Hinting hinting = rec->getHinting(); 2037 if (SkPaint::kSlight_Hinting == hinting || !lcdSupport) { 2038 hinting = SkPaint::kNo_Hinting; 2039 } else if (SkPaint::kFull_Hinting == hinting) { 2040 hinting = SkPaint::kNormal_Hinting; 2041 } 2042 rec->setHinting(hinting); 2043 2044 // FIXME: lcd smoothed un-hinted rasterization unsupported. 2045 // Tracked by http://code.google.com/p/skia/issues/detail?id=915 . 2046 // There is no current means to honor a request for unhinted lcd, 2047 // so arbitrarilly ignore the hinting request and honor lcd. 2048 2049 // Hinting and smoothing should be orthogonal, but currently they are not. 2050 // CoreGraphics has no API to influence hinting. However, its lcd smoothed 2051 // output is drawn from auto-dilated outlines (the amount of which is 2052 // determined by AppleFontSmoothing). Its regular anti-aliased output is 2053 // drawn from un-dilated outlines. 2054 2055 // The behavior of Skia is as follows: 2056 // [AA][no-hint]: generate AA using CoreGraphic's AA output. 2057 // [AA][yes-hint]: use CoreGraphic's LCD output and reduce it to a single 2058 // channel. This matches [LCD][yes-hint] in weight. 2059 // [LCD][no-hint]: curently unable to honor, and must pick which to respect. 2060 // Currenly side with LCD, effectively ignoring the hinting setting. 2061 // [LCD][yes-hint]: generate LCD using CoreGraphic's LCD output. 2062 2063 if (rec->fMaskFormat == SkMask::kLCD16_Format) { 2064 if (lcdSupport) { 2065 //CoreGraphics creates 555 masks for smoothed text anyway. 2066 rec->fMaskFormat = SkMask::kLCD16_Format; 2067 rec->setHinting(SkPaint::kNormal_Hinting); 2068 } else { 2069 rec->fMaskFormat = SkMask::kA8_Format; 2070 } 2071 } 2072 2073 // CoreText provides no information as to whether a glyph will be color or not. 2074 // Fonts may mix outlines and bitmaps, so information is needed on a glyph by glyph basis. 2075 // If a font contains an 'sbix' table, consider it to be a color font, and disable lcd. 2076 if (fHasColorGlyphs) { 2077 rec->fMaskFormat = SkMask::kARGB32_Format; 2078 } 2079 2080 // Unhinted A8 masks (those not derived from LCD masks) must respect SK_GAMMA_APPLY_TO_A8. 2081 // All other masks can use regular gamma. 2082 if (SkMask::kA8_Format == rec->fMaskFormat && SkPaint::kNo_Hinting == hinting) { 2083 #ifndef SK_GAMMA_APPLY_TO_A8 2084 // SRGBTODO: Is this correct? Do we want contrast boost? 2085 rec->ignorePreBlend(); 2086 #endif 2087 } else { 2088 //CoreGraphics dialates smoothed text as needed. 2089 rec->setContrast(0); 2090 } 2091 } 2092 2093 /** Takes ownership of the CFStringRef. */ 2094 static const char* get_str(CFStringRef ref, SkString* str) { 2095 if (nullptr == ref) { 2096 return nullptr; 2097 } 2098 CFStringToSkString(ref, str); 2099 CFRelease(ref); 2100 return str->c_str(); 2101 } 2102 2103 void SkTypeface_Mac::onGetFamilyName(SkString* familyName) const { 2104 get_str(CTFontCopyFamilyName(fFontRef.get()), familyName); 2105 } 2106 2107 void SkTypeface_Mac::onGetFontDescriptor(SkFontDescriptor* desc, 2108 bool* isLocalStream) const { 2109 SkString tmpStr; 2110 2111 desc->setFamilyName(get_str(CTFontCopyFamilyName(fFontRef.get()), &tmpStr)); 2112 desc->setFullName(get_str(CTFontCopyFullName(fFontRef.get()), &tmpStr)); 2113 desc->setPostscriptName(get_str(CTFontCopyPostScriptName(fFontRef.get()), &tmpStr)); 2114 desc->setStyle(this->fontStyle()); 2115 *isLocalStream = fIsLocalStream; 2116 } 2117 2118 int SkTypeface_Mac::onCharsToGlyphs(const void* chars, Encoding encoding, 2119 uint16_t glyphs[], int glyphCount) const 2120 { 2121 // Undocumented behavior of CTFontGetGlyphsForCharacters with non-bmp code points: 2122 // When a surrogate pair is detected, the glyph index used is the index of the high surrogate. 2123 // It is documented that if a mapping is unavailable, the glyph will be set to 0. 2124 2125 SkAutoSTMalloc<1024, UniChar> charStorage; 2126 const UniChar* src; // UniChar is a UTF-16 16-bit code unit. 2127 int srcCount; 2128 switch (encoding) { 2129 case kUTF8_Encoding: { 2130 const char* utf8 = reinterpret_cast<const char*>(chars); 2131 UniChar* utf16 = charStorage.reset(2 * glyphCount); 2132 src = utf16; 2133 for (int i = 0; i < glyphCount; ++i) { 2134 SkUnichar uni = SkUTF8_NextUnichar(&utf8); 2135 utf16 += SkUTF16_FromUnichar(uni, utf16); 2136 } 2137 srcCount = SkToInt(utf16 - src); 2138 break; 2139 } 2140 case kUTF16_Encoding: { 2141 src = reinterpret_cast<const UniChar*>(chars); 2142 int extra = 0; 2143 for (int i = 0; i < glyphCount; ++i) { 2144 if (SkUTF16_IsHighSurrogate(src[i + extra])) { 2145 ++extra; 2146 } 2147 } 2148 srcCount = glyphCount + extra; 2149 break; 2150 } 2151 case kUTF32_Encoding: { 2152 const SkUnichar* utf32 = reinterpret_cast<const SkUnichar*>(chars); 2153 UniChar* utf16 = charStorage.reset(2 * glyphCount); 2154 src = utf16; 2155 for (int i = 0; i < glyphCount; ++i) { 2156 utf16 += SkUTF16_FromUnichar(utf32[i], utf16); 2157 } 2158 srcCount = SkToInt(utf16 - src); 2159 break; 2160 } 2161 } 2162 2163 // If glyphs is nullptr, CT still needs glyph storage for finding the first failure. 2164 // Also, if there are any non-bmp code points, the provided 'glyphs' storage will be inadequate. 2165 SkAutoSTMalloc<1024, uint16_t> glyphStorage; 2166 uint16_t* macGlyphs = glyphs; 2167 if (nullptr == macGlyphs || srcCount > glyphCount) { 2168 macGlyphs = glyphStorage.reset(srcCount); 2169 } 2170 2171 bool allEncoded = CTFontGetGlyphsForCharacters(fFontRef.get(), src, macGlyphs, srcCount); 2172 2173 // If there were any non-bmp, then copy and compact. 2174 // If 'glyphs' is nullptr, then compact glyphStorage in-place. 2175 // If all are bmp and 'glyphs' is non-nullptr, 'glyphs' already contains the compact glyphs. 2176 // If some are non-bmp and 'glyphs' is non-nullptr, copy and compact into 'glyphs'. 2177 uint16_t* compactedGlyphs = glyphs; 2178 if (nullptr == compactedGlyphs) { 2179 compactedGlyphs = macGlyphs; 2180 } 2181 if (srcCount > glyphCount) { 2182 int extra = 0; 2183 for (int i = 0; i < glyphCount; ++i) { 2184 compactedGlyphs[i] = macGlyphs[i + extra]; 2185 if (SkUTF16_IsHighSurrogate(src[i + extra])) { 2186 ++extra; 2187 } 2188 } 2189 } 2190 2191 if (allEncoded) { 2192 return glyphCount; 2193 } 2194 2195 // If we got false, then we need to manually look for first failure. 2196 for (int i = 0; i < glyphCount; ++i) { 2197 if (0 == compactedGlyphs[i]) { 2198 return i; 2199 } 2200 } 2201 // Odd to get here, as we expected CT to have returned true up front. 2202 return glyphCount; 2203 } 2204 2205 int SkTypeface_Mac::onCountGlyphs() const { 2206 return SkToInt(CTFontGetGlyphCount(fFontRef.get())); 2207 } 2208 2209 /////////////////////////////////////////////////////////////////////////////// 2210 /////////////////////////////////////////////////////////////////////////////// 2211 2212 static bool find_desc_str(CTFontDescriptorRef desc, CFStringRef name, SkString* value) { 2213 UniqueCFRef<CFStringRef> ref((CFStringRef)CTFontDescriptorCopyAttribute(desc, name)); 2214 if (!ref) { 2215 return false; 2216 } 2217 CFStringToSkString(ref.get(), value); 2218 return true; 2219 } 2220 2221 #include "SkFontMgr.h" 2222 2223 static inline int sqr(int value) { 2224 SkASSERT(SkAbs32(value) < 0x7FFF); // check for overflow 2225 return value * value; 2226 } 2227 2228 // We normalize each axis (weight, width, italic) to be base-900 2229 static int compute_metric(const SkFontStyle& a, const SkFontStyle& b) { 2230 return sqr(a.weight() - b.weight()) + 2231 sqr((a.width() - b.width()) * 100) + 2232 sqr((a.slant() != b.slant()) * 900); 2233 } 2234 2235 class SkFontStyleSet_Mac : public SkFontStyleSet { 2236 public: 2237 SkFontStyleSet_Mac(CTFontDescriptorRef desc) 2238 : fArray(CTFontDescriptorCreateMatchingFontDescriptors(desc, nullptr)) 2239 , fCount(0) 2240 { 2241 if (!fArray) { 2242 fArray.reset(CFArrayCreate(nullptr, nullptr, 0, nullptr)); 2243 } 2244 fCount = SkToInt(CFArrayGetCount(fArray.get())); 2245 } 2246 2247 int count() override { 2248 return fCount; 2249 } 2250 2251 void getStyle(int index, SkFontStyle* style, SkString* name) override { 2252 SkASSERT((unsigned)index < (unsigned)fCount); 2253 CTFontDescriptorRef desc = (CTFontDescriptorRef)CFArrayGetValueAtIndex(fArray.get(), index); 2254 if (style) { 2255 *style = fontstyle_from_descriptor(desc, false); 2256 } 2257 if (name) { 2258 if (!find_desc_str(desc, kCTFontStyleNameAttribute, name)) { 2259 name->reset(); 2260 } 2261 } 2262 } 2263 2264 SkTypeface* createTypeface(int index) override { 2265 SkASSERT((unsigned)index < (unsigned)CFArrayGetCount(fArray.get())); 2266 CTFontDescriptorRef desc = (CTFontDescriptorRef)CFArrayGetValueAtIndex(fArray.get(), index); 2267 2268 return create_from_desc(desc).release(); 2269 } 2270 2271 SkTypeface* matchStyle(const SkFontStyle& pattern) override { 2272 if (0 == fCount) { 2273 return nullptr; 2274 } 2275 return create_from_desc(findMatchingDesc(pattern)).release(); 2276 } 2277 2278 private: 2279 UniqueCFRef<CFArrayRef> fArray; 2280 int fCount; 2281 2282 CTFontDescriptorRef findMatchingDesc(const SkFontStyle& pattern) const { 2283 int bestMetric = SK_MaxS32; 2284 CTFontDescriptorRef bestDesc = nullptr; 2285 2286 for (int i = 0; i < fCount; ++i) { 2287 CTFontDescriptorRef desc = (CTFontDescriptorRef)CFArrayGetValueAtIndex(fArray.get(), i); 2288 int metric = compute_metric(pattern, fontstyle_from_descriptor(desc, false)); 2289 if (0 == metric) { 2290 return desc; 2291 } 2292 if (metric < bestMetric) { 2293 bestMetric = metric; 2294 bestDesc = desc; 2295 } 2296 } 2297 SkASSERT(bestDesc); 2298 return bestDesc; 2299 } 2300 }; 2301 2302 class SkFontMgr_Mac : public SkFontMgr { 2303 UniqueCFRef<CFArrayRef> fNames; 2304 int fCount; 2305 2306 CFStringRef getFamilyNameAt(int index) const { 2307 SkASSERT((unsigned)index < (unsigned)fCount); 2308 return (CFStringRef)CFArrayGetValueAtIndex(fNames.get(), index); 2309 } 2310 2311 static SkFontStyleSet* CreateSet(CFStringRef cfFamilyName) { 2312 UniqueCFRef<CFMutableDictionaryRef> cfAttr( 2313 CFDictionaryCreateMutable(kCFAllocatorDefault, 0, 2314 &kCFTypeDictionaryKeyCallBacks, 2315 &kCFTypeDictionaryValueCallBacks)); 2316 2317 CFDictionaryAddValue(cfAttr.get(), kCTFontFamilyNameAttribute, cfFamilyName); 2318 2319 UniqueCFRef<CTFontDescriptorRef> desc( 2320 CTFontDescriptorCreateWithAttributes(cfAttr.get())); 2321 return new SkFontStyleSet_Mac(desc.get()); 2322 } 2323 2324 /** CTFontManagerCopyAvailableFontFamilyNames() is not always available, so we 2325 * provide a wrapper here that will return an empty array if need be. 2326 */ 2327 static UniqueCFRef<CFArrayRef> CopyAvailableFontFamilyNames() { 2328 #ifdef SK_BUILD_FOR_IOS 2329 return UniqueCFRef<CFArrayRef>(CFArrayCreate(nullptr, nullptr, 0, nullptr)); 2330 #else 2331 return UniqueCFRef<CFArrayRef>(CTFontManagerCopyAvailableFontFamilyNames()); 2332 #endif 2333 } 2334 2335 public: 2336 SkFontMgr_Mac() 2337 : fNames(CopyAvailableFontFamilyNames()) 2338 , fCount(fNames ? SkToInt(CFArrayGetCount(fNames.get())) : 0) {} 2339 2340 protected: 2341 int onCountFamilies() const override { 2342 return fCount; 2343 } 2344 2345 void onGetFamilyName(int index, SkString* familyName) const override { 2346 if ((unsigned)index < (unsigned)fCount) { 2347 CFStringToSkString(this->getFamilyNameAt(index), familyName); 2348 } else { 2349 familyName->reset(); 2350 } 2351 } 2352 2353 SkFontStyleSet* onCreateStyleSet(int index) const override { 2354 if ((unsigned)index >= (unsigned)fCount) { 2355 return nullptr; 2356 } 2357 return CreateSet(this->getFamilyNameAt(index)); 2358 } 2359 2360 SkFontStyleSet* onMatchFamily(const char familyName[]) const override { 2361 if (!familyName) { 2362 return nullptr; 2363 } 2364 UniqueCFRef<CFStringRef> cfName = make_CFString(familyName); 2365 return CreateSet(cfName.get()); 2366 } 2367 2368 SkTypeface* onMatchFamilyStyle(const char familyName[], 2369 const SkFontStyle& style) const override { 2370 UniqueCFRef<CTFontDescriptorRef> desc = create_descriptor(familyName, style); 2371 return create_from_desc(desc.get()).release(); 2372 } 2373 2374 SkTypeface* onMatchFamilyStyleCharacter(const char familyName[], 2375 const SkFontStyle& style, 2376 const char* bcp47[], int bcp47Count, 2377 SkUnichar character) const override { 2378 UniqueCFRef<CTFontDescriptorRef> desc = create_descriptor(familyName, style); 2379 UniqueCFRef<CTFontRef> currentFont(CTFontCreateWithFontDescriptor(desc.get(), 0, nullptr)); 2380 2381 // kCFStringEncodingUTF32 is BE unless there is a BOM. 2382 // Since there is no machine endian option, explicitly state machine endian. 2383 #ifdef SK_CPU_LENDIAN 2384 constexpr CFStringEncoding encoding = kCFStringEncodingUTF32LE; 2385 #else 2386 constexpr CFStringEncoding encoding = kCFStringEncodingUTF32BE; 2387 #endif 2388 UniqueCFRef<CFStringRef> string(CFStringCreateWithBytes( 2389 kCFAllocatorDefault, reinterpret_cast<const UInt8 *>(&character), sizeof(character), 2390 encoding, false)); 2391 CFRange range = CFRangeMake(0, CFStringGetLength(string.get())); // in UniChar units. 2392 UniqueCFRef<CTFontRef> fallbackFont( 2393 CTFontCreateForString(currentFont.get(), string.get(), range)); 2394 return create_from_CTFontRef(std::move(fallbackFont), nullptr, false).release(); 2395 } 2396 2397 SkTypeface* onMatchFaceStyle(const SkTypeface* familyMember, 2398 const SkFontStyle&) const override { 2399 return nullptr; 2400 } 2401 2402 sk_sp<SkTypeface> onMakeFromData(sk_sp<SkData> data, int ttcIndex) const override { 2403 UniqueCFRef<CGDataProviderRef> pr(SkCreateDataProviderFromData(std::move(data))); 2404 if (!pr) { 2405 return nullptr; 2406 } 2407 return create_from_dataProvider(std::move(pr), ttcIndex); 2408 } 2409 2410 sk_sp<SkTypeface> onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset> stream, 2411 int ttcIndex) const override { 2412 UniqueCFRef<CGDataProviderRef> pr(SkCreateDataProviderFromStream(std::move(stream))); 2413 if (!pr) { 2414 return nullptr; 2415 } 2416 return create_from_dataProvider(std::move(pr), ttcIndex); 2417 } 2418 2419 /** Creates a dictionary suitable for setting the axes on a CGFont. */ 2420 static UniqueCFRef<CFDictionaryRef> copy_axes(CGFontRef cg, const SkFontArguments& args) { 2421 // The CGFont variation data is keyed by name, but lacks the tag. 2422 // The CTFont variation data is keyed by tag, and also has the name. 2423 // We would like to work with CTFont variations, but creating a CTFont font with 2424 // CTFont variation dictionary runs into bugs. So use the CTFont variation data 2425 // to match names to tags to create the appropriate CGFont. 2426 UniqueCFRef<CTFontRef> ct(CTFontCreateWithGraphicsFont(cg, 0, nullptr, nullptr)); 2427 // CTFontCopyVariationAxes returns nullptr for CGFontCreateWithDataProvider fonts with 2428 // macOS 10.10 and iOS 9 or earlier. When this happens, there is no API to provide the tag. 2429 UniqueCFRef<CFArrayRef> ctAxes(CTFontCopyVariationAxes(ct.get())); 2430 if (!ctAxes) { 2431 return nullptr; 2432 } 2433 CFIndex axisCount = CFArrayGetCount(ctAxes.get()); 2434 2435 const SkFontArguments::VariationPosition position = args.getVariationDesignPosition(); 2436 2437 UniqueCFRef<CFMutableDictionaryRef> dict( 2438 CFDictionaryCreateMutable(kCFAllocatorDefault, axisCount, 2439 &kCFTypeDictionaryKeyCallBacks, 2440 &kCFTypeDictionaryValueCallBacks)); 2441 2442 for (int i = 0; i < axisCount; ++i) { 2443 CFTypeRef axisInfo = CFArrayGetValueAtIndex(ctAxes.get(), i); 2444 if (CFDictionaryGetTypeID() != CFGetTypeID(axisInfo)) { 2445 return nullptr; 2446 } 2447 CFDictionaryRef axisInfoDict = static_cast<CFDictionaryRef>(axisInfo); 2448 2449 // The assumption is that values produced by kCTFontVariationAxisNameKey and 2450 // kCGFontVariationAxisName will always be equal. 2451 // If they are ever not, seach the project history for "get_tag_for_name". 2452 CFTypeRef axisName = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisNameKey); 2453 if (!axisName || CFGetTypeID(axisName) != CFStringGetTypeID()) { 2454 return nullptr; 2455 } 2456 2457 CFTypeRef tag = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisIdentifierKey); 2458 if (!tag || CFGetTypeID(tag) != CFNumberGetTypeID()) { 2459 return nullptr; 2460 } 2461 CFNumberRef tagNumber = static_cast<CFNumberRef>(tag); 2462 int64_t tagLong; 2463 if (!CFNumberGetValue(tagNumber, kCFNumberSInt64Type, &tagLong)) { 2464 return nullptr; 2465 } 2466 2467 // The variation axes can be set to any value, but cg will effectively pin them. 2468 // Pin them here to normalize. 2469 CFTypeRef min = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisMinimumValueKey); 2470 CFTypeRef max = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisMaximumValueKey); 2471 CFTypeRef def = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisDefaultValueKey); 2472 if (!min || CFGetTypeID(min) != CFNumberGetTypeID() || 2473 !max || CFGetTypeID(max) != CFNumberGetTypeID() || 2474 !def || CFGetTypeID(def) != CFNumberGetTypeID()) 2475 { 2476 return nullptr; 2477 } 2478 CFNumberRef minNumber = static_cast<CFNumberRef>(min); 2479 CFNumberRef maxNumber = static_cast<CFNumberRef>(max); 2480 CFNumberRef defNumber = static_cast<CFNumberRef>(def); 2481 double minDouble; 2482 double maxDouble; 2483 double defDouble; 2484 if (!CFNumberGetValue(minNumber, kCFNumberDoubleType, &minDouble) || 2485 !CFNumberGetValue(maxNumber, kCFNumberDoubleType, &maxDouble) || 2486 !CFNumberGetValue(defNumber, kCFNumberDoubleType, &defDouble)) 2487 { 2488 return nullptr; 2489 } 2490 2491 double value = defDouble; 2492 // The position may be over specified. If there are multiple values for a given axis, 2493 // use the last one since that's what css-fonts-4 requires. 2494 for (int j = position.coordinateCount; j --> 0;) { 2495 if (position.coordinates[j].axis == tagLong) { 2496 value = SkTPin(SkScalarToDouble(position.coordinates[j].value), 2497 minDouble, maxDouble); 2498 break; 2499 } 2500 } 2501 UniqueCFRef<CFNumberRef> valueNumber( 2502 CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &value)); 2503 CFDictionaryAddValue(dict.get(), axisName, valueNumber.get()); 2504 } 2505 return std::move(dict); 2506 } 2507 sk_sp<SkTypeface> onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset> s, 2508 const SkFontArguments& args) const override { 2509 if (args.getCollectionIndex() != 0) { 2510 return nullptr; 2511 } 2512 UniqueCFRef<CGDataProviderRef> provider(SkCreateDataProviderFromStream(std::move(s))); 2513 if (!provider) { 2514 return nullptr; 2515 } 2516 UniqueCFRef<CGFontRef> cg(CGFontCreateWithDataProvider(provider.get())); 2517 if (!cg) { 2518 return nullptr; 2519 } 2520 2521 UniqueCFRef<CFDictionaryRef> cgVariations = copy_axes(cg.get(), args); 2522 // The CGFontRef returned by CGFontCreateCopyWithVariations when the passed CGFontRef was 2523 // created from a data provider does not appear to have any ownership of the underlying 2524 // data. The original CGFontRef must be kept alive until the copy will no longer be used. 2525 UniqueCFRef<CGFontRef> cgVariant; 2526 if (cgVariations) { 2527 cgVariant.reset(CGFontCreateCopyWithVariations(cg.get(), cgVariations.get())); 2528 } else { 2529 cgVariant.reset(cg.release()); 2530 } 2531 2532 UniqueCFRef<CTFontRef> ct( 2533 CTFontCreateWithGraphicsFont(cgVariant.get(), 0, nullptr, nullptr)); 2534 if (!ct) { 2535 return nullptr; 2536 } 2537 return create_from_CTFontRef(std::move(ct), std::move(cg), true); 2538 } 2539 2540 /** Creates a dictionary suitable for setting the axes on a CGFont. */ 2541 static UniqueCFRef<CFDictionaryRef> copy_axes(CGFontRef cg, SkFontData* fontData) { 2542 UniqueCFRef<CFArrayRef> cgAxes(CGFontCopyVariationAxes(cg)); 2543 if (!cgAxes) { 2544 return nullptr; 2545 } 2546 2547 CFIndex axisCount = CFArrayGetCount(cgAxes.get()); 2548 if (0 == axisCount || axisCount != fontData->getAxisCount()) { 2549 return nullptr; 2550 } 2551 2552 UniqueCFRef<CFMutableDictionaryRef> dict( 2553 CFDictionaryCreateMutable(kCFAllocatorDefault, axisCount, 2554 &kCFTypeDictionaryKeyCallBacks, 2555 &kCFTypeDictionaryValueCallBacks)); 2556 2557 for (int i = 0; i < fontData->getAxisCount(); ++i) { 2558 CFTypeRef axisInfo = CFArrayGetValueAtIndex(cgAxes.get(), i); 2559 if (CFDictionaryGetTypeID() != CFGetTypeID(axisInfo)) { 2560 return nullptr; 2561 } 2562 CFDictionaryRef axisInfoDict = static_cast<CFDictionaryRef>(axisInfo); 2563 2564 CFTypeRef axisName = CFDictionaryGetValue(axisInfoDict, kCGFontVariationAxisName); 2565 if (!axisName || CFGetTypeID(axisName) != CFStringGetTypeID()) { 2566 return nullptr; 2567 } 2568 2569 // The variation axes can be set to any value, but cg will effectively pin them. 2570 // Pin them here to normalize. 2571 CFTypeRef min = CFDictionaryGetValue(axisInfoDict, kCGFontVariationAxisMinValue); 2572 CFTypeRef max = CFDictionaryGetValue(axisInfoDict, kCGFontVariationAxisMaxValue); 2573 if (!min || CFGetTypeID(min) != CFNumberGetTypeID() || 2574 !max || CFGetTypeID(max) != CFNumberGetTypeID()) 2575 { 2576 return nullptr; 2577 } 2578 CFNumberRef minNumber = static_cast<CFNumberRef>(min); 2579 CFNumberRef maxNumber = static_cast<CFNumberRef>(max); 2580 double minDouble; 2581 double maxDouble; 2582 if (!CFNumberGetValue(minNumber, kCFNumberDoubleType, &minDouble) || 2583 !CFNumberGetValue(maxNumber, kCFNumberDoubleType, &maxDouble)) 2584 { 2585 return nullptr; 2586 } 2587 double value = SkTPin(SkFixedToDouble(fontData->getAxis()[i]), minDouble, maxDouble); 2588 UniqueCFRef<CFNumberRef> valueNumber( 2589 CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &value)); 2590 CFDictionaryAddValue(dict.get(), axisName, valueNumber.get()); 2591 } 2592 return std::move(dict); 2593 } 2594 sk_sp<SkTypeface> onMakeFromFontData(std::unique_ptr<SkFontData> fontData) const override { 2595 if (fontData->getIndex() != 0) { 2596 return nullptr; 2597 } 2598 UniqueCFRef<CGDataProviderRef> provider( 2599 SkCreateDataProviderFromStream(fontData->detachStream())); 2600 if (!provider) { 2601 return nullptr; 2602 } 2603 UniqueCFRef<CGFontRef> cg(CGFontCreateWithDataProvider(provider.get())); 2604 if (!cg) { 2605 return nullptr; 2606 } 2607 2608 UniqueCFRef<CFDictionaryRef> cgVariations = copy_axes(cg.get(), fontData.get()); 2609 // The CGFontRef returned by CGFontCreateCopyWithVariations when the passed CGFontRef was 2610 // created from a data provider does not appear to have any ownership of the underlying 2611 // data. The original CGFontRef must be kept alive until the copy will no longer be used. 2612 UniqueCFRef<CGFontRef> cgVariant; 2613 if (cgVariations) { 2614 cgVariant.reset(CGFontCreateCopyWithVariations(cg.get(), cgVariations.get())); 2615 } else { 2616 cgVariant.reset(cg.release()); 2617 } 2618 2619 UniqueCFRef<CTFontRef> ct( 2620 CTFontCreateWithGraphicsFont(cgVariant.get(), 0, nullptr, nullptr)); 2621 if (!ct) { 2622 return nullptr; 2623 } 2624 return create_from_CTFontRef(std::move(ct), std::move(cg), true); 2625 } 2626 2627 sk_sp<SkTypeface> onMakeFromFile(const char path[], int ttcIndex) const override { 2628 UniqueCFRef<CGDataProviderRef> pr(CGDataProviderCreateWithFilename(path)); 2629 if (!pr) { 2630 return nullptr; 2631 } 2632 return create_from_dataProvider(std::move(pr), ttcIndex); 2633 } 2634 2635 sk_sp<SkTypeface> onLegacyMakeTypeface(const char familyName[], SkFontStyle style) const override { 2636 if (familyName) { 2637 familyName = map_css_names(familyName); 2638 } 2639 2640 sk_sp<SkTypeface> face = create_from_name(familyName, style); 2641 if (face) { 2642 return face; 2643 } 2644 2645 static SkTypeface* gDefaultFace; 2646 static SkOnce lookupDefault; 2647 static const char FONT_DEFAULT_NAME[] = "Lucida Sans"; 2648 lookupDefault([]{ 2649 gDefaultFace = create_from_name(FONT_DEFAULT_NAME, SkFontStyle()).release(); 2650 }); 2651 return sk_ref_sp(gDefaultFace); 2652 } 2653 }; 2654 2655 /////////////////////////////////////////////////////////////////////////////// 2656 2657 sk_sp<SkFontMgr> SkFontMgr::Factory() { return sk_make_sp<SkFontMgr_Mac>(); } 2658 2659 #endif//defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) 2660