9#if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS)
11#ifdef SK_BUILD_FOR_MAC
12#import <ApplicationServices/ApplicationServices.h>
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>
71void SkStringFromCFString(CFStringRef src,
SkString* dst) {
74 CFIndex
length = CFStringGetMaximumSizeForEncoding(CFStringGetLength(src),
75 kCFStringEncodingUTF8) + 1;
77 CFStringGetCString(src,
dst->data(),
length, kCFStringEncodingUTF8);
79 dst->resize(strlen(
dst->c_str()));
82SkString SkCFTypeIDDescription(CFTypeID
id) {
83 SkUniqueCFRef<CFStringRef> typeDescription(CFCopyTypeIDDescription(
id));
85 SkStringFromCFString(typeDescription.get(), &skTypeDescription);
86 return skTypeDescription;
89template<
typename CF> CFTypeID SkCFGetTypeID();
90#define SK_GETCFTYPEID(cf) \
91template<> CFTypeID SkCFGetTypeID<cf##Ref>() { return cf##GetTypeID(); }
92SK_GETCFTYPEID(CFBoolean);
93SK_GETCFTYPEID(CFDictionary);
94SK_GETCFTYPEID(CFNumber);
103template <
typename CF>
104static bool SkCFDynamicCast(CFTypeRef cf, CF* cfAsCF,
char const*
name) {
114 if (CFGetTypeID(cf) != SkCFGetTypeID<CF>()) {
117 SkCFTypeIDDescription( CFGetTypeID(cf) ).c_str(),
118 SkCFTypeIDDescription(SkCFGetTypeID<CF>()).c_str());
122 *cfAsCF =
static_cast<CF
>(cf);
126template<
typename T>
struct SkCFNumberTypeFor {};
127#define SK_CFNUMBERTYPE_FOR(c, cf) \
128template<> struct SkCFNumberTypeFor<c> : std::integral_constant<CFNumberType, cf> {};
129SK_CFNUMBERTYPE_FOR(
char , kCFNumberCharType );
130SK_CFNUMBERTYPE_FOR(
short , kCFNumberShortType );
131SK_CFNUMBERTYPE_FOR(
int , kCFNumberIntType );
132SK_CFNUMBERTYPE_FOR(
long , kCFNumberLongType );
133SK_CFNUMBERTYPE_FOR(
long long, kCFNumberLongLongType);
134SK_CFNUMBERTYPE_FOR(
float , kCFNumberFloatType );
135SK_CFNUMBERTYPE_FOR(
double , kCFNumberDoubleType );
138static bool SkCFNumberDynamicCast(CFTypeRef cf,
T* number, CFNumberRef* cfNumber,
char const*
name){
139 CFNumberRef cfAsCFNumber;
140 if (!SkCFDynamicCast(cf, &cfAsCFNumber,
name)) {
143 if (!CFNumberGetValue(cfAsCFNumber, SkCFNumberTypeFor<T>::value, number)) {
150 *cfNumber = cfAsCFNumber;
155CTFontRef SkTypeface_GetCTFontRef(
const SkTypeface* face) {
159static bool find_by_CTFontRef(
SkTypeface* cached,
void* context) {
160 CTFontRef
self = (CTFontRef)context;
163 return CFEqual(
self, other);
168 OpszVariation opszVariation,
169 std::unique_ptr<SkStreamAsset> providedData) {
170 static SkMutex gTFCacheMutex;
174 const bool isFromStream(providedData);
176 auto makeTypeface = [&]() {
177 SkUniqueCFRef<CTFontDescriptorRef>
desc(CTFontCopyFontDescriptor(
font.get()));
178 SkFontStyle style = SkCTFontDescriptorGetSkFontStyle(
desc.get(), isFromStream);
179 CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(
font.get());
180 bool isFixedPitch =
SkToBool(traits & kCTFontMonoSpaceTrait);
182 return sk_sp<SkTypeface>(
new SkTypeface_Mac(std::move(font), style, isFixedPitch,
183 opszVariation, std::move(providedData)));
187 return makeTypeface();
193 face = makeTypeface();
206 return SkTypeface_Mac::Make(SkUniqueCFRef<CTFontRef>(font),
211static bool find_dict_CGFloat(CFDictionaryRef dict, CFStringRef
name, CGFloat* value) {
213 return CFDictionaryGetValueIfPresent(dict,
name, (
const void**)&num)
214 && CFNumberIsFloatType(num)
215 && CFNumberGetValue(num, kCFNumberCGFloatType, value);
218template <
typename S,
typename D,
typename C>
struct LinearInterpolater {
223 constexpr LinearInterpolater(Mapping
const mapping[],
int mappingCount)
224 : fMapping(mapping), fMappingCount(mappingCount) {}
226 static D map(S value, S src_min, S src_max,
D dst_min,
D dst_max) {
229 return C()(dst_min + (((
value - src_min) * (dst_max - dst_min)) / (src_max - src_min)));
234 if (val < fMapping[0].src_val) {
235 return fMapping[0].dst_val;
239 for (
int i = 0; i < fMappingCount - 1; ++i) {
240 if (val < fMapping[i+1].src_val) {
241 return map(val, fMapping[i].src_val, fMapping[i+1].src_val,
242 fMapping[i].dst_val, fMapping[i+1].dst_val);
248 return fMapping[fMappingCount - 1].dst_val;
251 Mapping
const * fMapping;
255struct RoundCGFloatToInt {
256 int operator()(CGFloat
s) {
return s + 0.5; }
258struct CGFloatIdentity {
259 CGFloat operator()(CGFloat
s) {
return s; }
267CGFloat SkCTFontCTWeightForCSSWeight(
int fontstyleWeight) {
268 using Interpolator = LinearInterpolater<int, CGFloat, CGFloatIdentity>;
273 static Interpolator::Mapping nativeWeightMappings[11];
276 const CGFloat(&nsFontWeights)[11] = SkCTFontGetNSFontWeightMapping();
277 for (
int i = 0; i < 11; ++i) {
278 nativeWeightMappings[i].src_val = i * 100;
279 nativeWeightMappings[i].dst_val = nsFontWeights[i];
282 static constexpr Interpolator nativeInterpolator(
283 nativeWeightMappings, std::size(nativeWeightMappings));
285 return nativeInterpolator.map(fontstyleWeight);
293static int ct_weight_to_fontstyle(CGFloat cgWeight,
bool fromDataProvider) {
294 using Interpolator = LinearInterpolater<CGFloat, int, RoundCGFloatToInt>;
299 static Interpolator::Mapping nativeWeightMappings[11];
300 static Interpolator::Mapping dataProviderWeightMappings[11];
303 const CGFloat(&nsFontWeights)[11] = SkCTFontGetNSFontWeightMapping();
304 const CGFloat(&userFontWeights)[11] = SkCTFontGetDataFontWeightMapping();
305 for (
int i = 0; i < 11; ++i) {
306 nativeWeightMappings[i].src_val = nsFontWeights[i];
307 nativeWeightMappings[i].dst_val = i * 100;
309 dataProviderWeightMappings[i].src_val = userFontWeights[i];
310 dataProviderWeightMappings[i].dst_val = i * 100;
313 static constexpr Interpolator nativeInterpolator(
314 nativeWeightMappings, std::size(nativeWeightMappings));
315 static constexpr Interpolator dataProviderInterpolator(
316 dataProviderWeightMappings, std::size(dataProviderWeightMappings));
318 return fromDataProvider ? dataProviderInterpolator.map(cgWeight)
319 : nativeInterpolator.map(cgWeight);
323CGFloat SkCTFontCTWidthForCSSWidth(
int fontstyleWidth) {
324 using Interpolator = LinearInterpolater<int, CGFloat, CGFloatIdentity>;
328 static constexpr Interpolator::Mapping widthMappings[] = {
332 static constexpr Interpolator interpolator(widthMappings, std::size(widthMappings));
333 return interpolator.map(fontstyleWidth);
337static int ct_width_to_fontstyle(CGFloat cgWidth) {
338 using Interpolator = LinearInterpolater<CGFloat, int, RoundCGFloatToInt>;
342 static constexpr Interpolator::Mapping widthMappings[] = {
346 static constexpr Interpolator interpolator(widthMappings, std::size(widthMappings));
347 return interpolator.map(cgWidth);
350SkFontStyle SkCTFontDescriptorGetSkFontStyle(CTFontDescriptorRef desc,
bool fromDataProvider) {
351 SkUniqueCFRef<CFTypeRef> traits(CTFontDescriptorCopyAttribute(desc, kCTFontTraitsAttribute));
352 CFDictionaryRef fontTraitsDict;
353 if (!SkCFDynamicCast(traits.get(), &fontTraitsDict,
"Font traits")) {
357 CGFloat weight,
width, slant;
358 if (!find_dict_CGFloat(fontTraitsDict, kCTFontWeightTrait, &weight)) {
361 if (!find_dict_CGFloat(fontTraitsDict, kCTFontWidthTrait, &
width)) {
364 if (!find_dict_CGFloat(fontTraitsDict, kCTFontSlantTrait, &slant)) {
368 return SkFontStyle(ct_weight_to_fontstyle(weight, fromDataProvider),
369 ct_width_to_fontstyle(
width),
378static void populate_glyph_to_unicode_slow(CTFontRef ctFont, CFIndex glyphCount,
382 while (glyphCount > 0) {
384 if (CTFontGetGlyphsForCharacters(ctFont, &unichar, &glyph, 1)) {
385 if (out[glyph] == 0) {
386 out[glyph] = unichar;
390 if (++unichar == 0) {
396static constexpr uint16_t kPlaneSize = 1 << 13;
398static void get_plane_glyph_map(
const uint8_t* bits,
402 uint8_t planeIndex) {
404 for (uint16_t i = 0; i < kPlaneSize; i++) {
405 uint8_t mask =
bits[i];
409 for (uint8_t j = 0; j < 8; j++) {
410 if (0 == (mask & ((uint8_t)1 << j))) {
413 uint16_t planeOffset = (i << 3) | j;
415 uint16_t utf16[2] = {planeOffset, 0};
417 if (planeOrigin != 0) {
420 CGGlyph
glyphs[2] = {0, 0};
421 if (CTFontGetGlyphsForCharacters(ctFont, utf16,
glyphs,
count)) {
427 if (glyphToUnicode[
glyphs[0]] < 0x20) {
428 glyphToUnicode[
glyphs[0]] = codepoint;
435static void populate_glyph_to_unicode(CTFontRef ctFont, CFIndex glyphCount,
438 SkUniqueCFRef<CFCharacterSetRef> charSet(CTFontCopyCharacterSet(ctFont));
440 populate_glyph_to_unicode_slow(ctFont, glyphCount, glyphToUnicode);
444 SkUniqueCFRef<CFDataRef>
bitmap(
445 CFCharacterSetCreateBitmapRepresentation(
nullptr, charSet.get()));
449 CFIndex dataLength = CFDataGetLength(
bitmap.get());
454 const UInt8*
bits = CFDataGetBytePtr(
bitmap.get());
456 get_plane_glyph_map(bits, ctFont, glyphCount, glyphToUnicode, 0);
468 if (dataLength <= kPlaneSize) {
471 int extraPlaneCount = (dataLength - kPlaneSize) / (1 + kPlaneSize);
472 SkASSERT(dataLength == kPlaneSize + extraPlaneCount * (1 + kPlaneSize));
473 while (extraPlaneCount-- > 0) {
475 uint8_t planeIndex = *
bits++;
478 get_plane_glyph_map(bits, ctFont, glyphCount, glyphToUnicode, planeIndex);
482void SkTypeface_Mac::getGlyphToUnicodeMap(
SkUnichar* dstArray)
const {
483 SkUniqueCFRef<CTFontRef> ctFont =
484 SkCTFontCreateExactCopy(fFontRef.get(), CTFontGetUnitsPerEm(fFontRef.get()),
486 CFIndex glyphCount = CTFontGetGlyphCount(ctFont.get());
487 populate_glyph_to_unicode(ctFont.get(), glyphCount, dstArray);
490std::unique_ptr<SkAdvancedTypefaceMetrics> SkTypeface_Mac::onGetAdvancedMetrics()
const {
492 SkUniqueCFRef<CTFontRef> ctFont =
493 SkCTFontCreateExactCopy(fFontRef.get(), CTFontGetUnitsPerEm(fFontRef.get()),
499 SkUniqueCFRef<CFStringRef> fontName(CTFontCopyPostScriptName(ctFont.get()));
500 if (fontName.get()) {
501 SkStringFromCFString(fontName.get(), &
info->fPostScriptName);
505 CFArrayRef ctAxes = this->getVariationAxes();
506 if (ctAxes && CFArrayGetCount(ctAxes) > 0) {
525 if (!((this->getTableSize(glyf) && this->getTableSize(loca)) ||
526 this->getTableSize(CFF)))
532 CTFontSymbolicTraits symbolicTraits = CTFontGetSymbolicTraits(ctFont.get());
533 if (symbolicTraits & kCTFontMonoSpaceTrait) {
536 if (symbolicTraits & kCTFontItalicTrait) {
539 CTFontStylisticClass stylisticClass = symbolicTraits & kCTFontClassMaskTrait;
540 if (stylisticClass >= kCTFontOldStyleSerifsClass && stylisticClass <= kCTFontSlabSerifsClass) {
542 }
else if (stylisticClass & kCTFontScriptsClass) {
545 info->fItalicAngle = (int16_t) CTFontGetSlantAngle(ctFont.get());
546 info->fAscent = (int16_t) CTFontGetAscent(ctFont.get());
547 info->fDescent = (int16_t) CTFontGetDescent(ctFont.get());
548 info->fCapHeight = (int16_t) CTFontGetCapHeight(ctFont.get());
549 CGRect bbox = CTFontGetBoundingBox(ctFont.get());
552 r.
setLTRB(SkScalarFromCGFloat(SkCGRectGetMinX(bbox)),
553 SkScalarFromCGFloat(SkCGRectGetMaxY(bbox)),
554 SkScalarFromCGFloat(SkCGRectGetMaxX(bbox)),
555 SkScalarFromCGFloat(SkCGRectGetMinY(bbox)));
561 int16_t min_width = SHRT_MAX;
563 static const UniChar stem_chars[] = {
'i',
'I',
'!',
'1'};
564 const size_t count =
sizeof(stem_chars) /
sizeof(stem_chars[0]);
566 CGRect boundingRects[
count];
567 if (CTFontGetGlyphsForCharacters(ctFont.get(), stem_chars,
glyphs,
count)) {
568 CTFontGetBoundingRectsForGlyphs(ctFont.get(), kCTFontOrientationHorizontal,
570 for (
size_t i = 0; i <
count; i++) {
571 int16_t
width = (int16_t) boundingRects[i].
size.width;
574 info->fStemV = min_width;
582 SkUniqueCFRef<CFNumberRef> fontFormatRef(
583 static_cast<CFNumberRef
>(CTFontCopyAttribute(ctFont, kCTFontFormatAttribute)));
584 if (!fontFormatRef) {
588 SInt32 fontFormatValue;
589 if (!CFNumberGetValue(fontFormatRef.get(), kCFNumberSInt32Type, &fontFormatValue)) {
593 switch (fontFormatValue) {
594 case kCTFontFormatOpenTypePostScript:
596 case kCTFontFormatOpenTypeTrueType:
598 case kCTFontFormatTrueType:
600 case kCTFontFormatPostScript:
602 case kCTFontFormatBitmap:
604 case kCTFontFormatUnrecognized:
610std::unique_ptr<SkStreamAsset> SkTypeface_Mac::onOpenStream(
int* ttcIndex)
const {
621 int numTables = this->countTables();
623 tableTags.
resize(numTables);
624 this->getTableTags(tableTags.
begin());
633 bool couldBeCFF =
false;
636 for (
int tableIndex = 0; tableIndex < numTables; ++tableIndex) {
637 if (CFFTag == tableTags[tableIndex] || CFF2Tag == tableTags[tableIndex]) {
651 bool couldBeTyp1 =
false;
654 for (
int tableIndex = 0; tableIndex < numTables; ++tableIndex) {
655 if (TYPE1Tag == tableTags[tableIndex] || CIDTag == tableTags[tableIndex]) {
667 for (
int tableIndex = 0; tableIndex < numTables; ++tableIndex) {
668 size_t tableSize = this->getTableSize(tableTags[tableIndex]);
669 totalSize += (tableSize + 3) & ~3;
670 *tableSizes.
append() = tableSize;
675 char* dataStart = (
char*)streamData->writable_data();
676 char* dataPtr = dataStart;
679 uint16_t entrySelector = 0;
680 uint16_t searchRange = 1;
681 while (searchRange < numTables >> 1) {
686 uint16_t rangeShift = (numTables << 4) - searchRange;
700 for (
int tableIndex = 0; tableIndex < numTables; ++tableIndex) {
701 size_t tableSize = tableSizes[tableIndex];
702 this->getTableData(tableTags[tableIndex], 0, tableSize, dataPtr);
709 dataPtr += (tableSize + 3) & ~3;
712 fStream = std::make_unique<SkMemoryStream>(std::move(streamData));
714 return fStream->duplicate();
717std::unique_ptr<SkStreamAsset> SkTypeface_Mac::onOpenExistingStream(
int* ttcIndex)
const {
719 return fStream ? fStream->duplicate() :
nullptr;
722bool SkTypeface_Mac::onGlyphMaskNeedsCurrentColor()
const {
726 return this->fHasColorGlyphs;
729CFArrayRef SkTypeface_Mac::getVariationAxes()
const {
730 fInitVariationAxes([
this]{
731 fVariationAxes.reset(CTFontCopyVariationAxes(fFontRef.get()));
733 return fVariationAxes.get();
736int SkTypeface_Mac::onGetVariationDesignPosition(
739 CFArrayRef ctAxes = this->getVariationAxes();
743 CFIndex axisCount = CFArrayGetCount(ctAxes);
744 if (!coordinates || coordinateCount < axisCount) {
749 SkUniqueCFRef<CFDictionaryRef> ctVariation(CTFontCopyVariation(fFontRef.get()));
754 for (
int i = 0; i < axisCount; ++i) {
755 CFDictionaryRef axisInfoDict;
756 if (!SkCFDynamicCast(CFArrayGetValueAtIndex(ctAxes, i), &axisInfoDict,
"Axis")) {
761 CFNumberRef tagNumber;
762 CFTypeRef tag = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisIdentifierKey);
763 if (!SkCFNumberDynamicCast(tag, &tagLong, &tagNumber,
"Axis tag")) {
766 coordinates[i].
axis = tagLong;
768 CGFloat valueCGFloat;
769 CFTypeRef
value = CFDictionaryGetValue(ctVariation.get(), tagNumber);
771 if (!SkCFNumberDynamicCast(value, &valueCGFloat,
nullptr,
"Variation value")) {
775 CFTypeRef def = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisDefaultValueKey);
776 if (!SkCFNumberDynamicCast(def, &valueCGFloat,
nullptr,
"Axis default value")) {
780 coordinates[i].
value = SkScalarFromCGFloat(valueCGFloat);
785int SkTypeface_Mac::onGetUPEM()
const {
786 SkUniqueCFRef<CGFontRef> cgFont(CTFontCopyGraphicsFont(fFontRef.get(),
nullptr));
787 return CGFontGetUnitsPerEm(cgFont.get());
794 CFStringRef cfLanguageRaw;
795 SkUniqueCFRef<CFStringRef> cfFamilyName(
796 CTFontCopyLocalizedName(fFontRef.get(), kCTFontFamilyNameKey, &cfLanguageRaw));
797 SkUniqueCFRef<CFStringRef> cfLanguage(cfLanguageRaw);
802 SkStringFromCFString(cfLanguage.get(), &skLanguage);
807 SkStringFromCFString(cfFamilyName.get(), &skFamilyName);
810 nameIter = sk_make_sp<SkOTUtils::LocalizedStrings_SingleName>(skFamilyName, skLanguage);
816 SkUniqueCFRef<CFArrayRef> cfArray(
817 CTFontCopyAvailableTables(fFontRef.get(), kCTFontTableOptionNoOptions));
821 CFIndex
count = CFArrayGetCount(cfArray.get());
823 for (CFIndex i = 0; i <
count; ++i) {
824 uintptr_t fontTag =
reinterpret_cast<uintptr_t
>(
825 CFArrayGetValueAtIndex(cfArray.get(), i));
835static SkUniqueCFRef<CFDataRef> copy_table_from_font(CTFontRef ctFont,
SkFontTableTag tag) {
836 SkUniqueCFRef<CFDataRef>
data(CTFontCopyTable(ctFont, (CTFontTableTag) tag,
837 kCTFontTableOptionNoOptions));
839 SkUniqueCFRef<CGFontRef> cgFont(CTFontCopyGraphicsFont(ctFont,
nullptr));
840 data.reset(CGFontCopyTableForTag(cgFont.get(), tag));
846 size_t length,
void* dstData)
const {
847 SkUniqueCFRef<CFDataRef> srcData = copy_table_from_font(fFontRef.get(), tag);
852 size_t srcSize = CFDataGetLength(srcData.get());
860 memcpy(dstData, CFDataGetBytePtr(srcData.get()) +
offset,
length);
866 SkUniqueCFRef<CFDataRef> srcData = copy_table_from_font(fFontRef.get(), tag);
870 const UInt8*
data = CFDataGetBytePtr(srcData.get());
871 CFIndex
length = CFDataGetLength(srcData.get());
873 [](
const void*,
void* ctx) {
874 CFRelease((CFDataRef)ctx);
875 }, (
void*)srcData.release());
878std::unique_ptr<SkScalerContext> SkTypeface_Mac::onCreateScalerContext(
881 return std::make_unique<SkScalerContext_Mac>(
882 sk_ref_sp(
const_cast<SkTypeface_Mac*
>(
this)), effects, desc);
901 rec->
fFlags &= ~flagsWeDontSupport;
903 const SkCTFontSmoothBehavior smoothBehavior = SkCTFontGetSmoothBehavior();
912 if (smoothBehavior == SkCTFontSmoothBehavior::none) {
935 if (smoothBehavior == SkCTFontSmoothBehavior::subpixel) {
941 if (smoothBehavior != SkCTFontSmoothBehavior::none) {
950 if (fHasColorGlyphs) {
957#ifndef SK_GAMMA_APPLY_TO_A8
963 if (smoothBehavior == SkCTFontSmoothBehavior::some) {
970 }
else if (smoothBehavior == SkCTFontSmoothBehavior::subpixel) {
986static const char* get_str(CFStringRef ref,
SkString* str) {
987 if (
nullptr == ref) {
990 SkStringFromCFString(ref, str);
995void SkTypeface_Mac::onGetFamilyName(
SkString* familyName)
const {
996 get_str(CTFontCopyFamilyName(fFontRef.get()), familyName);
999bool SkTypeface_Mac::onGetPostScriptName(
SkString* skPostScriptName)
const {
1000 SkUniqueCFRef<CFStringRef> ctPostScriptName(CTFontCopyPostScriptName(fFontRef.get()));
1001 if (!ctPostScriptName) {
1004 if (skPostScriptName) {
1005 SkStringFromCFString(ctPostScriptName.get(), skPostScriptName);
1011 bool* isLocalStream)
const {
1014 desc->setFamilyName(get_str(CTFontCopyFamilyName(fFontRef.get()), &tmpStr));
1015 desc->setFullName(get_str(CTFontCopyFullName(fFontRef.get()), &tmpStr));
1016 desc->setPostscriptName(get_str(CTFontCopyPostScriptName(fFontRef.get()), &tmpStr));
1017 desc->setStyle(this->fontStyle());
1018 desc->setFactoryId(FactoryId);
1019 *isLocalStream = fIsFromStream;
1031 UniChar* utf16 = charStorage.
reset(2 *
count);
1033 for (
int i = 0; i <
count; ++i) {
1036 srcCount =
SkToInt(utf16 - src);
1040 uint16_t* macGlyphs =
glyphs;
1041 if (srcCount >
count) {
1042 macGlyphs = glyphStorage.
reset(srcCount);
1045 CTFontGetGlyphsForCharacters(fFontRef.get(), src, macGlyphs, srcCount);
1050 if (srcCount >
count) {
1053 for (
int i = 0; i <
count; ++i) {
1054 glyphs[i] = macGlyphs[i + extra];
1064int SkTypeface_Mac::onCountGlyphs()
const {
1065 return SkToInt(CTFontGetGlyphCount(fFontRef.get()));
1069static CTFontVariation ctvariation_from_SkFontArguments(CTFontRef ct, CFArrayRef ctAxes,
1075 return CTFontVariation();
1077 CFIndex axisCount = CFArrayGetCount(ctAxes);
1080 SkUniqueCFRef<CFDictionaryRef> oldCtVariation(CTFontCopyVariation(ct));
1084 SkUniqueCFRef<CFMutableDictionaryRef> newCtVariation(
1085 CFDictionaryCreateMutable(kCFAllocatorDefault, axisCount,
1086 &kCFTypeDictionaryKeyCallBacks,
1087 &kCFTypeDictionaryValueCallBacks));
1088 SkUniqueCFRef<CFMutableDictionaryRef> wrongOpszVariation;
1090 for (
int i = 0; i < axisCount; ++i) {
1091 CFDictionaryRef axisInfoDict;
1092 if (!SkCFDynamicCast(CFArrayGetValueAtIndex(ctAxes, i), &axisInfoDict,
"Axis")) {
1093 return CTFontVariation();
1097 CFNumberRef tagNumber;
1098 CFTypeRef tag = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisIdentifierKey);
1099 if (!SkCFNumberDynamicCast(tag, &tagLong, &tagNumber,
"Axis tag")) {
1100 return CTFontVariation();
1108 CFTypeRef
min = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisMinimumValueKey);
1109 CFTypeRef
max = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisMaximumValueKey);
1110 CFTypeRef def = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisDefaultValueKey);
1111 if (!SkCFNumberDynamicCast(
min, &minDouble,
nullptr,
"Axis min") ||
1112 !SkCFNumberDynamicCast(
max, &maxDouble,
nullptr,
"Axis max") ||
1113 !SkCFNumberDynamicCast(def, &defDouble,
nullptr,
"Axis def"))
1115 return CTFontVariation();
1119 double value = defDouble;
1122 bool haveCurrentDouble =
false;
1123 double currentDouble = 0;
1124 if (oldCtVariation) {
1125 CFTypeRef currentNumber = CFDictionaryGetValue(oldCtVariation.get(), tagNumber);
1126 if (currentNumber) {
1127 if (!SkCFNumberDynamicCast(currentNumber, &value,
nullptr,
"Variation value")) {
1128 return CTFontVariation();
1130 currentDouble =
value;
1131 haveCurrentDouble =
true;
1141 if (tagLong == opszTag) {
1147 if (tagLong == opszTag) {
1149 if (haveCurrentDouble && value == currentDouble) {
1151 double wrongOpszDouble = ((maxDouble - minDouble) / 2.0) + minDouble;
1152 if (wrongOpszDouble == currentDouble) {
1153 wrongOpszDouble = ((maxDouble - minDouble) / 4.0) + minDouble;
1155 wrongOpszVariation.reset(
1156 CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
1157 &kCFTypeDictionaryKeyCallBacks,
1158 &kCFTypeDictionaryValueCallBacks));
1159 SkUniqueCFRef<CFNumberRef> wrongOpszNumber(
1160 CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &wrongOpszDouble));
1161 CFDictionarySetValue(wrongOpszVariation.get(), tagNumber, wrongOpszNumber.get());
1164 SkUniqueCFRef<CFNumberRef> valueNumber(
1165 CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &value));
1166 CFDictionaryAddValue(newCtVariation.get(), tagNumber, valueNumber.get());
1168 return { SkUniqueCFRef<CFDictionaryRef>(std::move(newCtVariation)),
1169 SkUniqueCFRef<CFDictionaryRef>(std::move(wrongOpszVariation)),
1174 CTFontVariation ctVariation = ctvariation_from_SkFontArguments(fFontRef.get(),
1175 this->getVariationAxes(),
1178 SkUniqueCFRef<CTFontRef> ctVariant;
1179 if (ctVariation.variation) {
1180 SkUniqueCFRef<CFMutableDictionaryRef> attributes(
1181 CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
1182 &kCFTypeDictionaryKeyCallBacks,
1183 &kCFTypeDictionaryValueCallBacks));
1185 CTFontRef ctFont = fFontRef.get();
1186 SkUniqueCFRef<CTFontRef> wrongOpszFont;
1187 if (ctVariation.wrongOpszVariation) {
1198 CFDictionarySetValue(attributes.get(),
1199 kCTFontVariationAttribute, ctVariation.wrongOpszVariation.get());
1200 SkUniqueCFRef<CTFontDescriptorRef> varDesc(
1201 CTFontDescriptorCreateWithAttributes(attributes.get()));
1202 wrongOpszFont.reset(CTFontCreateCopyWithAttributes(ctFont, 0,
nullptr, varDesc.get()));
1203 ctFont = wrongOpszFont.get();
1206 CFDictionarySetValue(attributes.get(),
1207 kCTFontVariationAttribute, ctVariation.variation.get());
1208 SkUniqueCFRef<CTFontDescriptorRef> varDesc(
1209 CTFontDescriptorCreateWithAttributes(attributes.get()));
1210 ctVariant.reset(CTFontCreateCopyWithAttributes(ctFont, 0,
nullptr, varDesc.get()));
1212 ctVariant.reset((CTFontRef)CFRetain(fFontRef.get()));
1218 return SkTypeface_Mac::Make(std::move(ctVariant), ctVariation.opsz,
1219 fStream ? fStream->duplicate() : nullptr);
1222static sk_sp<SkData> skdata_from_skstreamasset(std::unique_ptr<SkStreamAsset> stream) {
1224 if (
const void*
base =
stream->getMemoryBase()) {
1226 [](
const void*,
void* ctx) ->
void {
1233static SkUniqueCFRef<CFDataRef> cfdata_from_skdata(
sk_sp<SkData> data) {
1234 void const *
const addr =
data->data();
1237 CFAllocatorContext ctx = {
1245 [](
void*,
void*
info) ->
void {
1251 SkUniqueCFRef<CFAllocatorRef> alloc(CFAllocatorCreate(kCFAllocatorDefault, &ctx));
1252 return SkUniqueCFRef<CFDataRef>(CFDataCreateWithBytesNoCopy(
1253 kCFAllocatorDefault, (
const UInt8 *)addr, size, alloc.get()));
1256static SkUniqueCFRef<CTFontRef> ctfont_from_skdata(
sk_sp<SkData> data,
int ttcIndex) {
1258 if (ttcIndex != 0) {
1262 SkUniqueCFRef<CFDataRef> cfData(cfdata_from_skdata(std::move(data)));
1264 SkUniqueCFRef<CTFontDescriptorRef>
desc(
1265 CTFontManagerCreateFontDescriptorFromData(cfData.get()));
1269 return SkUniqueCFRef<CTFontRef>(CTFontCreateWithFontDescriptor(
desc.get(), 0,
nullptr));
1272sk_sp<SkTypeface> SkTypeface_Mac::MakeFromStream(std::unique_ptr<SkStreamAsset> stream,
1276 int ttcIndex =
args.getCollectionIndex();
1277 if (ttcIndex != 0) {
1285 SkUniqueCFRef<CTFontRef> ct = ctfont_from_skdata(std::move(data), ttcIndex);
1290 SkUniqueCFRef<CTFontRef> ctVariant;
1291 CTFontVariation ctVariation;
1292 if (
args.getVariationDesignPosition().coordinateCount == 0) {
1293 ctVariant = std::move(ct);
1295 SkUniqueCFRef<CFArrayRef> axes(CTFontCopyVariationAxes(ct.get()));
1296 ctVariation = ctvariation_from_SkFontArguments(ct.get(), axes.get(),
args);
1298 if (ctVariation.variation) {
1299 SkUniqueCFRef<CFMutableDictionaryRef> attributes(
1300 CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
1301 &kCFTypeDictionaryKeyCallBacks,
1302 &kCFTypeDictionaryValueCallBacks));
1303 CFDictionaryAddValue(attributes.get(),
1304 kCTFontVariationAttribute, ctVariation.variation.get());
1305 SkUniqueCFRef<CTFontDescriptorRef> varDesc(
1306 CTFontDescriptorCreateWithAttributes(attributes.get()));
1307 ctVariant.reset(CTFontCreateCopyWithAttributes(ct.get(), 0,
nullptr, varDesc.get()));
1309 ctVariant = std::move(ct);
1316 return SkTypeface_Mac::Make(std::move(ctVariant), ctVariation.opsz, std::move(stream));
1320 int parameterCount)
const
1322 CFArrayRef ctAxes = this->getVariationAxes();
1326 CFIndex axisCount = CFArrayGetCount(ctAxes);
1328 if (!parameters || parameterCount < axisCount) {
1333 static CFStringRef* kCTFontVariationAxisHiddenKeyPtr =
1334 static_cast<CFStringRef*
>(dlsym(RTLD_DEFAULT,
"kCTFontVariationAxisHiddenKey"));
1336 for (
int i = 0; i < axisCount; ++i) {
1337 CFDictionaryRef axisInfoDict;
1338 if (!SkCFDynamicCast(CFArrayGetValueAtIndex(ctAxes, i), &axisInfoDict,
"Axis")) {
1343 CFTypeRef tag = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisIdentifierKey);
1344 if (!SkCFNumberDynamicCast(tag, &tagLong,
nullptr,
"Axis tag")) {
1351 CFTypeRef
min = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisMinimumValueKey);
1352 CFTypeRef
max = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisMaximumValueKey);
1353 CFTypeRef def = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisDefaultValueKey);
1354 if (!SkCFNumberDynamicCast(
min, &minDouble,
nullptr,
"Axis min") ||
1355 !SkCFNumberDynamicCast(
max, &maxDouble,
nullptr,
"Axis max") ||
1356 !SkCFNumberDynamicCast(def, &defDouble,
nullptr,
"Axis def"))
1362 skAxis.
tag = tagLong;
1363 skAxis.
min = minDouble;
1364 skAxis.
max = maxDouble;
1365 skAxis.
def = defDouble;
1367 if (kCTFontVariationAxisHiddenKeyPtr) {
1368 CFTypeRef hidden = CFDictionaryGetValue(axisInfoDict,*kCTFontVariationAxisHiddenKeyPtr);
1372 CFBooleanRef hiddenBoolean;
1374 if (SkCFDynamicCast(hidden, &hiddenBoolean,
nullptr)) {
1375 skAxis.
setHidden(CFBooleanGetValue(hiddenBoolean));
1376 }
else if (SkCFNumberDynamicCast(hidden, &hiddenInt,
nullptr,
"Axis hidden")) {
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
#define SkColorGetR(color)
#define SkColorGetG(color)
#define SkColorSetRGB(r, g, b)
#define SkColorGetB(color)
#define SkEndian_SwapBE32(n)
#define SkEndian_SwapBE16(n)
#define SkTEndian_SwapBE32(n)
@ kNormal
glyph outlines modified to improve constrast
@ kNone
glyph outlines unchanged
static void sk_bzero(void *buffer, size_t size)
sk_sp< T > sk_ref_sp(T *obj)
constexpr int SkToInt(S x)
static constexpr bool SkToBool(const T &x)
constexpr uint32_t SkToU32(S x)
static constexpr SkFourByteTag SkSetFourByteTag(char a, char b, char c, char d)
static sk_sp< SkData > MakeWithProc(const void *ptr, size_t length, ReleaseProc proc, void *ctx)
static sk_sp< SkData > MakeFromStream(SkStream *, size_t size)
static sk_sp< SkData > MakeZeroInitialized(size_t length)
const char * c_str() const
sk_sp< SkTypeface > findByProcAndRef(FindProc proc, void *ctx) const
void add(sk_sp< SkTypeface >)
void * internal_private_getCTFontRef() const
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
static float max(float r, float g, float b)
static float min(float r, float g, float b)
SK_SPI size_t ToUTF16(SkUnichar uni, uint16_t utf16[2]=nullptr)
static bool IsLeadingSurrogateUTF16(uint16_t c)
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot data
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
font
Font Metadata and Metrics.
SI auto map(std::index_sequence< I... >, Fn &&fn, const Args &... args) -> skvx::Vec< sizeof...(I), decltype(fn(args[0]...))>
static const char header[]
@ kVariable_FontFlag
May be true for Type1, CFF, or TrueType fonts.
const Coordinate * coordinates
void setHidden(bool hidden)
@ kA8_Format
8bits per pixel mask (e.g. antialiasing)
@ kLCD16_Format
565 alpha for r/g/b
@ kARGB32_Format
SkPMColor.
static constexpr SK_OT_ULONG TAG
static uint32_t CalcTableChecksum(SK_OT_ULONG *data, size_t length)
static void SetAdvancedTypefaceFlags(SkOTTableOS2_V4::Type fsType, SkAdvancedTypefaceMetrics *info)
void roundOut(SkIRect *dst) const
void setLTRB(float left, float top, float right, float bottom)
SkMask::Format fMaskFormat
void setContrast(SkScalar c)
SkColor getLuminanceColor() const
SkFontHinting getHinting() const
void setHinting(SkFontHinting)
void setLuminanceColor(SkColor c)