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