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>
72static CFStringRef getCTFontPaletteAttribute() {
73 static CFStringRef* kCTFontPaletteAttributePtr =
74 static_cast<CFStringRef*
>(dlsym(RTLD_DEFAULT,
"kCTFontPaletteAttribute"));
75 return *kCTFontPaletteAttributePtr;
77static CFStringRef getCTFontPaletteColorsAttribute() {
78 static CFStringRef* kCTFontPaletteColorsAttributePtr =
79 static_cast<CFStringRef*
>(dlsym(RTLD_DEFAULT,
"kCTFontPaletteColorsAttribute"));
80 return *kCTFontPaletteColorsAttributePtr;
87 CFIndex
length = CFStringGetMaximumSizeForEncoding(CFStringGetLength(
src),
88 kCFStringEncodingUTF8) + 1;
90 CFStringGetCString(
src,
dst->data(),
length, kCFStringEncodingUTF8);
92 dst->resize(strlen(
dst->c_str()));
95SkString SkCFTypeIDDescription(CFTypeID
id) {
96 SkUniqueCFRef<CFStringRef> typeDescription(CFCopyTypeIDDescription(
id));
98 SkStringFromCFString(typeDescription.get(), &skTypeDescription);
99 return skTypeDescription;
102template<
typename CF> CFTypeID SkCFGetTypeID();
103#define SK_GETCFTYPEID(cf) \
104template<> CFTypeID SkCFGetTypeID<cf##Ref>() { return cf##GetTypeID(); }
105SK_GETCFTYPEID(CFBoolean);
106SK_GETCFTYPEID(CFDictionary);
107SK_GETCFTYPEID(CFNumber);
108SK_GETCFTYPEID(CGColor);
117template <
typename CF>
118static bool SkCFDynamicCast(CFTypeRef cf, CF* cfAsCF,
char const*
name) {
128 if (CFGetTypeID(cf) != SkCFGetTypeID<CF>()) {
131 SkCFTypeIDDescription( CFGetTypeID(cf) ).c_str(),
132 SkCFTypeIDDescription(SkCFGetTypeID<CF>()).c_str());
137 *cfAsCF =
static_cast<CF
>(
const_cast<void*
>(cf));
141template<
typename T>
struct SkCFNumberTypeFor {};
142#define SK_CFNUMBERTYPE_FOR(c, cf) \
143template<> struct SkCFNumberTypeFor<c> : std::integral_constant<CFNumberType, cf> {};
144SK_CFNUMBERTYPE_FOR(
char , kCFNumberCharType );
145SK_CFNUMBERTYPE_FOR(
short , kCFNumberShortType );
146SK_CFNUMBERTYPE_FOR(
int , kCFNumberIntType );
147SK_CFNUMBERTYPE_FOR(
long , kCFNumberLongType );
148SK_CFNUMBERTYPE_FOR(
long long, kCFNumberLongLongType);
149SK_CFNUMBERTYPE_FOR(
float , kCFNumberFloatType );
150SK_CFNUMBERTYPE_FOR(
double , kCFNumberDoubleType );
153static bool SkCFNumberDynamicCast(CFTypeRef cf,
T* number, CFNumberRef* cfNumber,
char const*
name){
154 CFNumberRef cfAsCFNumber;
155 if (!SkCFDynamicCast(cf, &cfAsCFNumber,
name)) {
165 *cfNumber = cfAsCFNumber;
170CTFontRef SkTypeface_GetCTFontRef(
const SkTypeface* face) {
174static bool find_by_CTFontRef(
SkTypeface* cached,
void* context) {
175 CTFontRef
self = (CTFontRef)context;
178 return CFEqual(
self, other);
183 OpszVariation opszVariation,
184 std::unique_ptr<SkStreamAsset> providedData) {
185 static SkMutex gTFCacheMutex;
189 const bool isFromStream(providedData);
191 auto makeTypeface = [&]() {
192 SkUniqueCFRef<CTFontDescriptorRef>
desc(CTFontCopyFontDescriptor(
font.get()));
193 SkFontStyle style = SkCTFontDescriptorGetSkFontStyle(
desc.get(), isFromStream);
194 CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(
font.get());
195 bool isFixedPitch =
SkToBool(traits & kCTFontMonoSpaceTrait);
198 opszVariation, std::move(providedData)));
202 return makeTypeface();
208 face = makeTypeface();
226static bool find_dict_CGFloat(CFDictionaryRef dict, CFStringRef
name, CGFloat*
value) {
228 return CFDictionaryGetValueIfPresent(dict,
name, (
const void**)&num)
229 && CFNumberIsFloatType(num)
230 && CFNumberGetValue(num, kCFNumberCGFloatType,
value);
233template <
typename S,
typename D,
typename C>
struct LinearInterpolater {
238 constexpr LinearInterpolater(Mapping
const mapping[],
int mappingCount)
239 : fMapping(mapping), fMappingCount(mappingCount) {}
241 static D map(
S value,
S src_min,
S src_max,
D dst_min,
D dst_max) {
244 return C()(dst_min + (((
value - src_min) * (dst_max - dst_min)) / (src_max - src_min)));
249 if (val < fMapping[0].src_val) {
250 return fMapping[0].dst_val;
254 for (
int i = 0;
i < fMappingCount - 1; ++
i) {
255 if (val < fMapping[
i+1].src_val) {
256 return map(val, fMapping[
i].src_val, fMapping[
i+1].src_val,
257 fMapping[
i].dst_val, fMapping[
i+1].dst_val);
263 return fMapping[fMappingCount - 1].dst_val;
266 Mapping
const * fMapping;
270struct RoundCGFloatToInt {
271 int operator()(CGFloat
s) {
return s + 0.5; }
273struct CGFloatIdentity {
274 CGFloat operator()(CGFloat
s) {
return s; }
282CGFloat SkCTFontCTWeightForCSSWeight(
int fontstyleWeight) {
283 using Interpolator = LinearInterpolater<int, CGFloat, CGFloatIdentity>;
288 static Interpolator::Mapping nativeWeightMappings[11];
291 const CGFloat(&nsFontWeights)[11] = SkCTFontGetNSFontWeightMapping();
292 for (
int i = 0;
i < 11; ++
i) {
293 nativeWeightMappings[
i].src_val =
i * 100;
294 nativeWeightMappings[
i].dst_val = nsFontWeights[
i];
297 static constexpr Interpolator nativeInterpolator(
298 nativeWeightMappings,
std::size(nativeWeightMappings));
300 return nativeInterpolator.map(fontstyleWeight);
308static int ct_weight_to_fontstyle(CGFloat cgWeight,
bool fromDataProvider) {
309 using Interpolator = LinearInterpolater<CGFloat, int, RoundCGFloatToInt>;
314 static Interpolator::Mapping nativeWeightMappings[11];
315 static Interpolator::Mapping dataProviderWeightMappings[11];
318 const CGFloat(&nsFontWeights)[11] = SkCTFontGetNSFontWeightMapping();
319 const CGFloat(&userFontWeights)[11] = SkCTFontGetDataFontWeightMapping();
320 for (
int i = 0;
i < 11; ++
i) {
321 nativeWeightMappings[
i].src_val = nsFontWeights[
i];
322 nativeWeightMappings[
i].dst_val =
i * 100;
324 dataProviderWeightMappings[
i].src_val = userFontWeights[
i];
325 dataProviderWeightMappings[
i].dst_val =
i * 100;
328 static constexpr Interpolator nativeInterpolator(
329 nativeWeightMappings,
std::size(nativeWeightMappings));
330 static constexpr Interpolator dataProviderInterpolator(
331 dataProviderWeightMappings,
std::size(dataProviderWeightMappings));
333 return fromDataProvider ? dataProviderInterpolator.map(cgWeight)
334 : nativeInterpolator.map(cgWeight);
338CGFloat SkCTFontCTWidthForCSSWidth(
int fontstyleWidth) {
339 using Interpolator = LinearInterpolater<int, CGFloat, CGFloatIdentity>;
343 static constexpr Interpolator::Mapping widthMappings[] = {
347 static constexpr Interpolator interpolator(widthMappings,
std::size(widthMappings));
348 return interpolator.map(fontstyleWidth);
352static int ct_width_to_fontstyle(CGFloat cgWidth) {
353 using Interpolator = LinearInterpolater<CGFloat, int, RoundCGFloatToInt>;
357 static constexpr Interpolator::Mapping widthMappings[] = {
361 static constexpr Interpolator interpolator(widthMappings,
std::size(widthMappings));
362 return interpolator.map(cgWidth);
365SkFontStyle SkCTFontDescriptorGetSkFontStyle(CTFontDescriptorRef
desc,
bool fromDataProvider) {
366 SkUniqueCFRef<CFTypeRef> traits(CTFontDescriptorCopyAttribute(
desc, kCTFontTraitsAttribute));
367 CFDictionaryRef fontTraitsDict;
368 if (!SkCFDynamicCast(traits.get(), &fontTraitsDict,
"Font traits")) {
372 CGFloat weight,
width, slant;
373 if (!find_dict_CGFloat(fontTraitsDict, kCTFontWeightTrait, &weight)) {
376 if (!find_dict_CGFloat(fontTraitsDict, kCTFontWidthTrait, &
width)) {
379 if (!find_dict_CGFloat(fontTraitsDict, kCTFontSlantTrait, &slant)) {
383 return SkFontStyle(ct_weight_to_fontstyle(weight, fromDataProvider),
384 ct_width_to_fontstyle(
width),
393static void populate_glyph_to_unicode_slow(CTFontRef ctFont, CFIndex glyphCount,
397 while (glyphCount > 0) {
399 if (CTFontGetGlyphsForCharacters(ctFont, &unichar, &glyph, 1)) {
400 if (
out[glyph] == 0) {
401 out[glyph] = unichar;
405 if (++unichar == 0) {
411static constexpr uint16_t kPlaneSize = 1 << 13;
413static void get_plane_glyph_map(
const uint8_t*
bits,
417 uint8_t planeIndex) {
419 for (uint16_t
i = 0;
i < kPlaneSize;
i++) {
420 uint8_t mask =
bits[
i];
424 for (uint8_t j = 0; j < 8; j++) {
425 if (0 == (mask & ((uint8_t)1 << j))) {
428 uint16_t planeOffset = (
i << 3) | j;
430 uint16_t utf16[2] = {planeOffset, 0};
432 if (planeOrigin != 0) {
435 CGGlyph
glyphs[2] = {0, 0};
436 if (CTFontGetGlyphsForCharacters(ctFont, utf16,
glyphs,
count)) {
442 if (glyphToUnicode[
glyphs[0]] < 0x20) {
443 glyphToUnicode[
glyphs[0]] = codepoint;
450static void populate_glyph_to_unicode(CTFontRef ctFont, CFIndex glyphCount,
453 SkUniqueCFRef<CFCharacterSetRef> charSet(CTFontCopyCharacterSet(ctFont));
455 populate_glyph_to_unicode_slow(ctFont, glyphCount, glyphToUnicode);
459 SkUniqueCFRef<CFDataRef>
bitmap(
460 CFCharacterSetCreateBitmapRepresentation(
nullptr, charSet.get()));
464 CFIndex dataLength = CFDataGetLength(
bitmap.get());
469 const UInt8*
bits = CFDataGetBytePtr(
bitmap.get());
471 get_plane_glyph_map(
bits, ctFont, glyphCount, glyphToUnicode, 0);
483 if (dataLength <= kPlaneSize) {
486 int extraPlaneCount = (dataLength - kPlaneSize) / (1 + kPlaneSize);
487 SkASSERT(dataLength == kPlaneSize + extraPlaneCount * (1 + kPlaneSize));
488 while (extraPlaneCount-- > 0) {
490 uint8_t planeIndex = *
bits++;
493 get_plane_glyph_map(
bits, ctFont, glyphCount, glyphToUnicode, planeIndex);
497void SkTypeface_Mac::getGlyphToUnicodeMap(
SkUnichar* dstArray)
const {
498 SkUniqueCFRef<CTFontRef> ctFont =
499 SkCTFontCreateExactCopy(fFontRef.get(), CTFontGetUnitsPerEm(fFontRef.get()),
501 CFIndex glyphCount = CTFontGetGlyphCount(ctFont.get());
502 populate_glyph_to_unicode(ctFont.get(), glyphCount, dstArray);
505std::unique_ptr<SkAdvancedTypefaceMetrics> SkTypeface_Mac::onGetAdvancedMetrics()
const {
507 SkUniqueCFRef<CTFontRef> ctFont =
508 SkCTFontCreateExactCopy(fFontRef.get(), CTFontGetUnitsPerEm(fFontRef.get()),
514 SkUniqueCFRef<CFStringRef> fontName(CTFontCopyPostScriptName(ctFont.get()));
515 if (fontName.get()) {
516 SkStringFromCFString(fontName.get(), &
info->fPostScriptName);
520 CFArrayRef ctAxes = this->getVariationAxes();
521 if (ctAxes && CFArrayGetCount(ctAxes) > 0) {
540 if (this->getTableSize(glyf) && this->getTableSize(loca)) {
542 }
else if (this->getTableSize(CFF)) {
548 CTFontSymbolicTraits symbolicTraits = CTFontGetSymbolicTraits(ctFont.get());
549 if (symbolicTraits & kCTFontMonoSpaceTrait) {
552 if (symbolicTraits & kCTFontItalicTrait) {
555 CTFontStylisticClass stylisticClass = symbolicTraits & kCTFontClassMaskTrait;
556 if (stylisticClass >= kCTFontOldStyleSerifsClass && stylisticClass <= kCTFontSlabSerifsClass) {
558 }
else if (stylisticClass & kCTFontScriptsClass) {
561 info->fItalicAngle = (int16_t) CTFontGetSlantAngle(ctFont.get());
562 info->fAscent = (int16_t) CTFontGetAscent(ctFont.get());
563 info->fDescent = (int16_t) CTFontGetDescent(ctFont.get());
564 info->fCapHeight = (int16_t) CTFontGetCapHeight(ctFont.get());
565 CGRect bbox = CTFontGetBoundingBox(ctFont.get());
568 r.
setLTRB(SkScalarFromCGFloat(SkCGRectGetMinX(bbox)),
569 SkScalarFromCGFloat(SkCGRectGetMaxY(bbox)),
570 SkScalarFromCGFloat(SkCGRectGetMaxX(bbox)),
571 SkScalarFromCGFloat(SkCGRectGetMinY(bbox)));
577 int16_t min_width = SHRT_MAX;
579 static const UniChar stem_chars[] = {
'i',
'I',
'!',
'1'};
580 const size_t count =
sizeof(stem_chars) /
sizeof(stem_chars[0]);
582 CGRect boundingRects[
count];
583 if (CTFontGetGlyphsForCharacters(ctFont.get(), stem_chars,
glyphs,
count)) {
584 CTFontGetBoundingRectsForGlyphs(ctFont.get(), kCTFontOrientationHorizontal,
586 for (
size_t i = 0;
i <
count;
i++) {
587 int16_t
width = (int16_t) boundingRects[
i].
size.width;
590 info->fStemV = min_width;
598 SkUniqueCFRef<CFNumberRef> fontFormatRef(
599 static_cast<CFNumberRef
>(CTFontCopyAttribute(ctFont, kCTFontFormatAttribute)));
600 if (!fontFormatRef) {
604 SInt32 fontFormatValue;
605 if (!CFNumberGetValue(fontFormatRef.get(), kCFNumberSInt32Type, &fontFormatValue)) {
609 switch (fontFormatValue) {
610 case kCTFontFormatOpenTypePostScript:
612 case kCTFontFormatOpenTypeTrueType:
614 case kCTFontFormatTrueType:
616 case kCTFontFormatPostScript:
618 case kCTFontFormatBitmap:
620 case kCTFontFormatUnrecognized:
626std::unique_ptr<SkStreamAsset> SkTypeface_Mac::onOpenStream(
int* ttcIndex)
const {
637 int numTables = this->countTables();
639 tableTags.
resize(numTables);
640 this->getTableTags(tableTags.
begin());
649 bool couldBeCFF =
false;
652 for (
int tableIndex = 0; tableIndex < numTables; ++tableIndex) {
653 if (CFFTag == tableTags[tableIndex] || CFF2Tag == tableTags[tableIndex]) {
667 bool couldBeTyp1 =
false;
670 for (
int tableIndex = 0; tableIndex < numTables; ++tableIndex) {
671 if (TYPE1Tag == tableTags[tableIndex] || CIDTag == tableTags[tableIndex]) {
683 for (
int tableIndex = 0; tableIndex < numTables; ++tableIndex) {
684 size_t tableSize = this->getTableSize(tableTags[tableIndex]);
685 totalSize += (tableSize + 3) & ~3;
686 *tableSizes.
append() = tableSize;
692 char* dataPtr = dataStart;
695 uint16_t entrySelector = 0;
696 uint16_t searchRange = 1;
697 while (searchRange < numTables >> 1) {
702 uint16_t rangeShift = (numTables << 4) - searchRange;
706 header->fontType = fontType;
716 for (
int tableIndex = 0; tableIndex < numTables; ++tableIndex) {
717 size_t tableSize = tableSizes[tableIndex];
718 this->getTableData(tableTags[tableIndex], 0, tableSize, dataPtr);
725 dataPtr += (tableSize + 3) & ~3;
728 fStream = std::make_unique<SkMemoryStream>(std::move(streamData));
730 return fStream->duplicate();
733std::unique_ptr<SkStreamAsset> SkTypeface_Mac::onOpenExistingStream(
int* ttcIndex)
const {
735 return fStream ? fStream->duplicate() :
nullptr;
738bool SkTypeface_Mac::onGlyphMaskNeedsCurrentColor()
const {
742 return this->fHasColorGlyphs;
745CFArrayRef SkTypeface_Mac::getVariationAxes()
const {
746 fInitVariationAxes([
this]{
747 fVariationAxes.reset(CTFontCopyVariationAxes(fFontRef.get()));
749 return fVariationAxes.get();
752int SkTypeface_Mac::onGetVariationDesignPosition(
755 CFArrayRef ctAxes = this->getVariationAxes();
759 CFIndex axisCount = CFArrayGetCount(ctAxes);
760 if (!coordinates || coordinateCount < axisCount) {
765 SkUniqueCFRef<CFDictionaryRef> ctVariation(CTFontCopyVariation(fFontRef.get()));
770 for (
int i = 0;
i < axisCount; ++
i) {
771 CFDictionaryRef axisInfoDict;
772 if (!SkCFDynamicCast(CFArrayGetValueAtIndex(ctAxes,
i), &axisInfoDict,
"Axis")) {
777 CFNumberRef tagNumber;
778 CFTypeRef tag = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisIdentifierKey);
779 if (!SkCFNumberDynamicCast(tag, &tagLong, &tagNumber,
"Axis tag")) {
782 coordinates[
i].
axis = tagLong;
784 CGFloat valueCGFloat;
785 CFTypeRef
value = CFDictionaryGetValue(ctVariation.get(), tagNumber);
787 if (!SkCFNumberDynamicCast(
value, &valueCGFloat,
nullptr,
"Variation value")) {
791 CFTypeRef def = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisDefaultValueKey);
792 if (!SkCFNumberDynamicCast(def, &valueCGFloat,
nullptr,
"Axis default value")) {
796 coordinates[
i].
value = SkScalarFromCGFloat(valueCGFloat);
801int SkTypeface_Mac::onGetUPEM()
const {
802 SkUniqueCFRef<CGFontRef> cgFont(CTFontCopyGraphicsFont(fFontRef.get(),
nullptr));
803 return CGFontGetUnitsPerEm(cgFont.get());
810 CFStringRef cfLanguageRaw;
811 SkUniqueCFRef<CFStringRef> cfFamilyName(
812 CTFontCopyLocalizedName(fFontRef.get(), kCTFontFamilyNameKey, &cfLanguageRaw));
813 SkUniqueCFRef<CFStringRef> cfLanguage(cfLanguageRaw);
818 SkStringFromCFString(cfLanguage.get(), &skLanguage);
823 SkStringFromCFString(cfFamilyName.get(), &skFamilyName);
826 nameIter = sk_make_sp<SkOTUtils::LocalizedStrings_SingleName>(skFamilyName, skLanguage);
832 SkUniqueCFRef<CFArrayRef> cfArray(
833 CTFontCopyAvailableTables(fFontRef.get(), kCTFontTableOptionNoOptions));
837 CFIndex
count = CFArrayGetCount(cfArray.get());
839 for (CFIndex
i = 0;
i <
count; ++
i) {
840 uintptr_t fontTag =
reinterpret_cast<uintptr_t
>(
841 CFArrayGetValueAtIndex(cfArray.get(),
i));
851static SkUniqueCFRef<CFDataRef> copy_table_from_font(CTFontRef ctFont,
SkFontTableTag tag) {
852 SkUniqueCFRef<CFDataRef>
data(CTFontCopyTable(ctFont, (CTFontTableTag) tag,
853 kCTFontTableOptionNoOptions));
855 SkUniqueCFRef<CGFontRef> cgFont(CTFontCopyGraphicsFont(ctFont,
nullptr));
856 data.reset(CGFontCopyTableForTag(cgFont.get(), tag));
862 size_t length,
void* dstData)
const {
863 SkUniqueCFRef<CFDataRef> srcData = copy_table_from_font(fFontRef.get(), tag);
868 size_t srcSize = CFDataGetLength(srcData.get());
876 memcpy(dstData, CFDataGetBytePtr(srcData.get()) +
offset,
length);
882 SkUniqueCFRef<CFDataRef> srcData = copy_table_from_font(fFontRef.get(), tag);
886 const UInt8*
data = CFDataGetBytePtr(srcData.get());
887 CFIndex
length = CFDataGetLength(srcData.get());
889 [](
const void*,
void* ctx) {
890 CFRelease((CFDataRef)ctx);
891 }, (
void*)srcData.release());
894std::unique_ptr<SkScalerContext> SkTypeface_Mac::onCreateScalerContext(
897 return std::make_unique<SkScalerContext_Mac>(
898 sk_ref_sp(
const_cast<SkTypeface_Mac*
>(
this)), effects,
desc);
917 rec->
fFlags &= ~flagsWeDontSupport;
919 const SkCTFontSmoothBehavior smoothBehavior = SkCTFontGetSmoothBehavior();
928 if (smoothBehavior == SkCTFontSmoothBehavior::none) {
951 if (smoothBehavior == SkCTFontSmoothBehavior::subpixel) {
957 if (smoothBehavior != SkCTFontSmoothBehavior::none) {
966 if (fHasColorGlyphs) {
973#ifndef SK_GAMMA_APPLY_TO_A8
979 if (smoothBehavior == SkCTFontSmoothBehavior::some) {
986 }
else if (smoothBehavior == SkCTFontSmoothBehavior::subpixel) {
1002static const char* get_str(CFStringRef ref,
SkString* str) {
1003 if (
nullptr == ref) {
1006 SkStringFromCFString(ref, str);
1008 return str->
c_str();
1011void SkTypeface_Mac::onGetFamilyName(
SkString* familyName)
const {
1012 get_str(CTFontCopyFamilyName(fFontRef.get()), familyName);
1015bool SkTypeface_Mac::onGetPostScriptName(
SkString* skPostScriptName)
const {
1016 SkUniqueCFRef<CFStringRef> ctPostScriptName(CTFontCopyPostScriptName(fFontRef.get()));
1017 if (!ctPostScriptName) {
1020 if (skPostScriptName) {
1021 SkStringFromCFString(ctPostScriptName.get(), skPostScriptName);
1027 bool* isLocalStream)
const {
1030 desc->setFamilyName(get_str(CTFontCopyFamilyName(fFontRef.get()), &tmpStr));
1031 desc->setFullName(get_str(CTFontCopyFullName(fFontRef.get()), &tmpStr));
1032 desc->setPostscriptName(get_str(CTFontCopyPostScriptName(fFontRef.get()), &tmpStr));
1033 desc->setStyle(this->fontStyle());
1034 desc->setFactoryId(FactoryId);
1036 SkUniqueCFRef<CTFontDescriptorRef> ctDesc(CTFontCopyFontDescriptor(fFontRef.get()));
1037 SkUniqueCFRef<CFDictionaryRef> attributes(CTFontDescriptorCopyAttributes(ctDesc.get()));
1040 CFNumberRef paletteNumber;
1041 CFTypeRef paletteRef = CFDictionaryGetValue(attributes.get(), getCTFontPaletteAttribute());
1043 desc->setPaletteIndex(0);
1044 }
else if (SkCFNumberDynamicCast(paletteRef, &palette, &paletteNumber,
"Palette index")) {
1045 desc->setPaletteIndex(palette);
1048 CFTypeRef paletteOverrides = CFDictionaryGetValue(attributes.get(),
1049 getCTFontPaletteColorsAttribute());
1050 if (paletteOverrides) {
1051 CFDictionaryRef paletteOverrideDict;
1052 if (SkCFDynamicCast(paletteOverrides, &paletteOverrideDict,
"Palette")) {
1053 CFIndex overrideCount = CFDictionaryGetCount(paletteOverrideDict);
1057 size_t currentOverride;
1058 } context{
desc->setPaletteEntryOverrides(overrideCount), 0 };
1059 CFDictionaryApplyFunction(paletteOverrideDict,
1060 [](
const void*
key,
const void*
value,
void* ctx) ->
void {
1063 CFNumberRef indexNumber;
1064 CFTypeRef indexRef =
static_cast<CFTypeRef
>(
key);
1065 if (!SkCFNumberDynamicCast(indexRef, &indexInt, &indexNumber,
"Override index")) {
1068 if (!SkTFitsIn<uint16_t>(indexInt)) {
1071 index = SkTo<uint16_t>(indexInt);
1074 CFTypeRef colorRef =
static_cast<CFTypeRef
>(
value);
1075 if (!SkCFDynamicCast(colorRef, &cgColor,
"Palette color")) {
1078 if (CGColorGetNumberOfComponents(cgColor) != 4) {
1081 const CGFloat* components = CGColorGetComponents(cgColor);
1083 (
float)components[2], (
float)components[3]};
1087 context.overrides[context.currentOverride] = { index,
color};
1088 ++context.currentOverride;
1091 for (
size_t i = context.currentOverride;
i <
SkToSizeT(overrideCount); ++
i) {
1097 *isLocalStream = fIsFromStream;
1109 UniChar* utf16 = charStorage.
reset(2 *
count);
1118 uint16_t* macGlyphs =
glyphs;
1119 if (srcCount >
count) {
1120 macGlyphs = glyphStorage.
reset(srcCount);
1123 CTFontGetGlyphsForCharacters(fFontRef.get(),
src, macGlyphs, srcCount);
1128 if (srcCount >
count) {
1142int SkTypeface_Mac::onCountGlyphs()
const {
1143 return SkToInt(CTFontGetGlyphCount(fFontRef.get()));
1147static CTFontVariation ctvariation_from_SkFontArguments(CTFontRef ct, CFArrayRef ctAxes,
1153 return CTFontVariation();
1155 CFIndex axisCount = CFArrayGetCount(ctAxes);
1158 SkUniqueCFRef<CFDictionaryRef> oldCtVariation(CTFontCopyVariation(ct));
1162 SkUniqueCFRef<CFMutableDictionaryRef> newCtVariation(
1163 CFDictionaryCreateMutable(kCFAllocatorDefault, axisCount,
1164 &kCFTypeDictionaryKeyCallBacks,
1165 &kCFTypeDictionaryValueCallBacks));
1166 SkUniqueCFRef<CFMutableDictionaryRef> wrongOpszVariation;
1168 for (
int i = 0;
i < axisCount; ++
i) {
1169 CFDictionaryRef axisInfoDict;
1170 if (!SkCFDynamicCast(CFArrayGetValueAtIndex(ctAxes,
i), &axisInfoDict,
"Axis")) {
1171 return CTFontVariation();
1175 CFNumberRef tagNumber;
1176 CFTypeRef tag = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisIdentifierKey);
1177 if (!SkCFNumberDynamicCast(tag, &tagLong, &tagNumber,
"Axis tag")) {
1178 return CTFontVariation();
1186 CFTypeRef
min = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisMinimumValueKey);
1187 CFTypeRef
max = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisMaximumValueKey);
1188 CFTypeRef def = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisDefaultValueKey);
1189 if (!SkCFNumberDynamicCast(
min, &minDouble,
nullptr,
"Axis min") ||
1190 !SkCFNumberDynamicCast(
max, &maxDouble,
nullptr,
"Axis max") ||
1191 !SkCFNumberDynamicCast(def, &defDouble,
nullptr,
"Axis def"))
1193 return CTFontVariation();
1197 double value = defDouble;
1200 bool haveCurrentDouble =
false;
1201 double currentDouble = 0;
1202 if (oldCtVariation) {
1203 CFTypeRef currentNumber = CFDictionaryGetValue(oldCtVariation.get(), tagNumber);
1204 if (currentNumber) {
1205 if (!SkCFNumberDynamicCast(currentNumber, &
value,
nullptr,
"Variation value")) {
1206 return CTFontVariation();
1208 currentDouble =
value;
1209 haveCurrentDouble =
true;
1219 if (tagLong == opszTag) {
1225 if (tagLong == opszTag) {
1227 if (haveCurrentDouble &&
value == currentDouble) {
1229 double wrongOpszDouble = ((maxDouble - minDouble) / 2.0) + minDouble;
1230 if (wrongOpszDouble == currentDouble) {
1231 wrongOpszDouble = ((maxDouble - minDouble) / 4.0) + minDouble;
1233 wrongOpszVariation.reset(
1234 CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
1235 &kCFTypeDictionaryKeyCallBacks,
1236 &kCFTypeDictionaryValueCallBacks));
1237 SkUniqueCFRef<CFNumberRef> wrongOpszNumber(
1238 CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &wrongOpszDouble));
1239 CFDictionarySetValue(wrongOpszVariation.get(), tagNumber, wrongOpszNumber.get());
1242 SkUniqueCFRef<CFNumberRef> valueNumber(
1243 CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &
value));
1244 CFDictionaryAddValue(newCtVariation.get(), tagNumber, valueNumber.get());
1246 return { SkUniqueCFRef<CFDictionaryRef>(std::move(newCtVariation)),
1247 SkUniqueCFRef<CFDictionaryRef>(std::move(wrongOpszVariation)),
1251static CGColorRef CGColorForSkColor(CGColorSpaceRef rgbcs,
SkColor color) {
1253 CGFloat components[4] = {
1254 (CGFloat)color4f.fR,
1255 (CGFloat)color4f.fG,
1256 (CGFloat)color4f.fB,
1257 (CGFloat)color4f.fA,
1259 return CGColorCreate(rgbcs, components);
1262static bool apply_palette(CFMutableDictionaryRef attributes,
1264 bool changedAttributes =
false;
1266 SkUniqueCFRef<CFNumberRef> paletteIndex(
1267 CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &palette.
index));
1268 CFDictionarySetValue(attributes, getCTFontPaletteAttribute(), paletteIndex.get());
1269 changedAttributes =
true;
1273 SkUniqueCFRef<CFMutableDictionaryRef> overrides(
1274 CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
1275 &kCFTypeDictionaryKeyCallBacks,
1276 &kCFTypeDictionaryValueCallBacks));
1277 SkUniqueCFRef<CGColorSpaceRef> rgb(CGColorSpaceCreateDeviceRGB());
1279 int paletteOverrideIndex = paletteOverride.index;
1280 SkUniqueCFRef<CFNumberRef> index(
1281 CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt16Type, &paletteOverrideIndex));
1282 SkUniqueCFRef<CGColorRef>
color(CGColorForSkColor(rgb.get(), paletteOverride.color));
1283 CFDictionarySetValue(overrides.get(), index.get(),
color.get());
1285 if (CFDictionaryGetCount(overrides.get())) {
1286 CFDictionarySetValue(attributes, getCTFontPaletteColorsAttribute(), overrides.get());
1287 changedAttributes =
true;
1291 return changedAttributes;
1295 SkUniqueCFRef<CFMutableDictionaryRef> attributes(
1296 CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
1297 &kCFTypeDictionaryKeyCallBacks,
1298 &kCFTypeDictionaryValueCallBacks));
1300 bool changedAttributes = apply_palette(attributes.get(),
args.getPalette());
1302 CTFontVariation ctVariation = ctvariation_from_SkFontArguments(fFontRef.get(),
1303 this->getVariationAxes(),
1305 CTFontRef ctFont = fFontRef.get();
1306 SkUniqueCFRef<CTFontRef> wrongOpszFont;
1307 if (ctVariation.variation) {
1308 if (ctVariation.wrongOpszVariation) {
1319 CFDictionarySetValue(attributes.get(),
1320 kCTFontVariationAttribute, ctVariation.wrongOpszVariation.get());
1321 SkUniqueCFRef<CTFontDescriptorRef> varDesc(
1322 CTFontDescriptorCreateWithAttributes(attributes.get()));
1323 wrongOpszFont.reset(CTFontCreateCopyWithAttributes(ctFont, 0,
nullptr, varDesc.get()));
1324 ctFont = wrongOpszFont.get();
1326 CFDictionarySetValue(attributes.get(),
1327 kCTFontVariationAttribute, ctVariation.variation.get());
1328 changedAttributes =
true;
1331 SkUniqueCFRef<CTFontRef> ctVariant;
1332 if (changedAttributes) {
1333 SkUniqueCFRef<CTFontDescriptorRef>
desc(
1334 CTFontDescriptorCreateWithAttributes(attributes.get()));
1335 ctVariant.reset(CTFontCreateCopyWithAttributes(ctFont, 0,
nullptr,
desc.get()));
1337 ctVariant.reset((CTFontRef)CFRetain(fFontRef.get()));
1344 fStream ? fStream->duplicate() :
nullptr);
1349 if (
const void*
base =
stream->getMemoryBase()) {
1351 [](
const void*,
void* ctx) ->
void {
1359 void const *
const addr =
data->data();
1362 CFAllocatorContext ctx = {
1370 [](
void*,
void*
info) ->
void {
1376 SkUniqueCFRef<CFAllocatorRef> alloc(CFAllocatorCreate(kCFAllocatorDefault, &ctx));
1377 return SkUniqueCFRef<CFDataRef>(CFDataCreateWithBytesNoCopy(
1378 kCFAllocatorDefault, (
const UInt8 *)
addr,
size, alloc.get()));
1381static SkUniqueCFRef<CTFontRef> ctfont_from_skdata(
sk_sp<SkData> data,
int ttcIndex) {
1383 if (ttcIndex != 0) {
1387 SkUniqueCFRef<CFDataRef> cfData(cfdata_from_skdata(std::move(
data)));
1389 SkUniqueCFRef<CTFontDescriptorRef>
desc(
1390 CTFontManagerCreateFontDescriptorFromData(cfData.get()));
1394 return SkUniqueCFRef<CTFontRef>(CTFontCreateWithFontDescriptor(
desc.get(), 0,
nullptr));
1401 int ttcIndex =
args.getCollectionIndex();
1402 if (ttcIndex != 0) {
1410 SkUniqueCFRef<CTFontRef> ct = ctfont_from_skdata(std::move(
data), ttcIndex);
1415 SkUniqueCFRef<CFMutableDictionaryRef> attributes(
1416 CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
1417 &kCFTypeDictionaryKeyCallBacks,
1418 &kCFTypeDictionaryValueCallBacks));
1420 bool changedAttributes = apply_palette(attributes.get(),
args.getPalette());
1422 SkUniqueCFRef<CTFontRef> ctVariant;
1423 CTFontVariation ctVariation;
1424 if (
args.getVariationDesignPosition().coordinateCount != 0) {
1425 SkUniqueCFRef<CFArrayRef> axes(CTFontCopyVariationAxes(ct.get()));
1426 ctVariation = ctvariation_from_SkFontArguments(ct.get(), axes.get(),
args);
1428 if (ctVariation.variation) {
1429 CFDictionaryAddValue(attributes.get(),
1430 kCTFontVariationAttribute, ctVariation.variation.get());
1431 changedAttributes =
true;
1434 if (changedAttributes) {
1435 SkUniqueCFRef<CTFontDescriptorRef>
desc(
1436 CTFontDescriptorCreateWithAttributes(attributes.get()));
1437 ctVariant.reset(CTFontCreateCopyWithAttributes(ct.get(), 0,
nullptr,
desc.get()));
1439 ctVariant = std::move(ct);
1449 int parameterCount)
const
1451 CFArrayRef ctAxes = this->getVariationAxes();
1455 CFIndex axisCount = CFArrayGetCount(ctAxes);
1457 if (!parameters || parameterCount < axisCount) {
1462 static CFStringRef* kCTFontVariationAxisHiddenKeyPtr =
1463 static_cast<CFStringRef*
>(dlsym(RTLD_DEFAULT,
"kCTFontVariationAxisHiddenKey"));
1465 for (
int i = 0;
i < axisCount; ++
i) {
1466 CFDictionaryRef axisInfoDict;
1467 if (!SkCFDynamicCast(CFArrayGetValueAtIndex(ctAxes,
i), &axisInfoDict,
"Axis")) {
1472 CFTypeRef tag = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisIdentifierKey);
1473 if (!SkCFNumberDynamicCast(tag, &tagLong,
nullptr,
"Axis tag")) {
1480 CFTypeRef
min = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisMinimumValueKey);
1481 CFTypeRef
max = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisMaximumValueKey);
1482 CFTypeRef def = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisDefaultValueKey);
1483 if (!SkCFNumberDynamicCast(
min, &minDouble,
nullptr,
"Axis min") ||
1484 !SkCFNumberDynamicCast(
max, &maxDouble,
nullptr,
"Axis max") ||
1485 !SkCFNumberDynamicCast(def, &defDouble,
nullptr,
"Axis def"))
1491 skAxis.
tag = tagLong;
1492 skAxis.
min = minDouble;
1493 skAxis.
max = maxDouble;
1494 skAxis.
def = defDouble;
1496 if (kCTFontVariationAxisHiddenKeyPtr) {
1497 CFTypeRef hidden = CFDictionaryGetValue(axisInfoDict,*kCTFontVariationAxisHiddenKeyPtr);
1501 CFBooleanRef hiddenBoolean;
1503 if (SkCFDynamicCast(hidden, &hiddenBoolean,
nullptr)) {
1504 skAxis.
setHidden(CFBooleanGetValue(hiddenBoolean));
1505 }
else if (SkCFNumberDynamicCast(hidden, &hiddenInt,
nullptr,
"Axis hidden")) {
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
sk_bzero(glyphs, sizeof(glyphs))
#define SkColorGetR(color)
#define SkColorGetG(color)
#define SkColorSetRGB(r, g, b)
constexpr SkColor SK_ColorBLACK
#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
sk_sp< T > sk_ref_sp(T *obj)
SkSpan(Container &&) -> SkSpan< std::remove_pointer_t< decltype(std::data(std::declval< Container >()))> >
constexpr size_t SkToSizeT(S x)
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)
std::unique_ptr< SkCodec > MakeFromStream(std::unique_ptr< SkStream > stream, SkCodec::SelectionPolicy selectionPolicy, SkCodec::Result *result)
SK_API sk_sp< SkDocument > Make(SkWStream *dst, const SkSerialProcs *=nullptr, std::function< void(const SkPicture *)> onEndPage=nullptr)
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
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 Override * overrides
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)
std::shared_ptr< const fml::Mapping > data