Replace CGFontCreate with CTFontManagerCreate.
Replaces calls to CGFontCreateWithDataProvider with calls to CTFontManagerCreateFontDescriptorFromData. Note that this means Skia will not create CTFonts based on CGFonts, however SkCreateTypefaceFromCTFont allows the user to create CTFonts from CGFonts and introduce them to Skia. Bug: skia:4043,skia:9627 Change-Id: I8eb72c0e4eb257149f1f6a78ca34da4fbfafccab TBR: reed@google.com Reviewed-on: https://skia-review.googlesource.com/c/skia/+/254181 Commit-Queue: Ben Wagner <bungeman@google.com> Reviewed-by: Dominik Röttsches <drott@google.com>
This commit is contained in:
parent
4d6c84bf89
commit
f1d4f00fda
1
BUILD.gn
1
BUILD.gn
@ -924,7 +924,6 @@ component("skia") {
|
||||
"src/ports/SkOSFile_stdio.cpp",
|
||||
"src/sfnt/SkOTTable_name.cpp",
|
||||
"src/sfnt/SkOTUtils.cpp",
|
||||
"src/utils/mac/SkStream_mac.cpp",
|
||||
]
|
||||
|
||||
defines = []
|
||||
|
@ -74,13 +74,5 @@ static inline CGImageRef SkCreateCGImageRef(const SkBitmap& bm) {
|
||||
*/
|
||||
void SkCGDrawBitmap(CGContextRef, const SkBitmap&, float x, float y);
|
||||
|
||||
/**
|
||||
* Return a provider that wraps the specified stream.
|
||||
* When the provider is finally deleted, it will delete the stream.
|
||||
*/
|
||||
CGDataProviderRef SkCreateDataProviderFromStream(std::unique_ptr<SkStreamRewindable>);
|
||||
|
||||
CGDataProviderRef SkCreateDataProviderFromData(sk_sp<SkData>);
|
||||
|
||||
#endif // defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS)
|
||||
#endif // SkCGUtils_DEFINED
|
||||
|
@ -386,13 +386,12 @@ static SmoothBehavior smooth_behavior() {
|
||||
CGBitmapContextCreate(&smoothBitmap, 16, 16, 8, 16*4,
|
||||
colorspace.get(), BITMAP_INFO_RGB));
|
||||
|
||||
SkUniqueCFRef<CGDataProviderRef> data(
|
||||
CGDataProviderCreateWithData(nullptr, kSpiderSymbol_ttf,
|
||||
SK_ARRAY_COUNT(kSpiderSymbol_ttf), nullptr));
|
||||
SkUniqueCFRef<CGFontRef> cgFont(CGFontCreateWithDataProvider(data.get()));
|
||||
SkASSERT(cgFont);
|
||||
SkUniqueCFRef<CTFontRef> ctFont(
|
||||
CTFontCreateWithGraphicsFont(cgFont.get(), 16, nullptr, nullptr));
|
||||
SkUniqueCFRef<CFDataRef> data(CFDataCreateWithBytesNoCopy(
|
||||
kCFAllocatorDefault, kSpiderSymbol_ttf, SK_ARRAY_COUNT(kSpiderSymbol_ttf),
|
||||
kCFAllocatorNull));
|
||||
SkUniqueCFRef<CTFontDescriptorRef> desc(
|
||||
CTFontManagerCreateFontDescriptorFromData(data.get()));
|
||||
SkUniqueCFRef<CTFontRef> ctFont(CTFontCreateWithFontDescriptor(desc.get(), 16, nullptr));
|
||||
SkASSERT(ctFont);
|
||||
|
||||
CGContextSetShouldSmoothFonts(noSmoothContext.get(), false);
|
||||
@ -1617,24 +1616,6 @@ void SkScalerContext_Mac::CTPathElement(void *info, const CGPathElement *element
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Returns nullptr on failure
|
||||
static sk_sp<SkTypeface> create_from_dataProvider(SkUniqueCFRef<CGDataProviderRef> provider,
|
||||
std::unique_ptr<SkStreamAsset> providedData,
|
||||
int ttcIndex) {
|
||||
if (ttcIndex != 0) {
|
||||
return nullptr;
|
||||
}
|
||||
SkUniqueCFRef<CGFontRef> cg(CGFontCreateWithDataProvider(provider.get()));
|
||||
if (!cg) {
|
||||
return nullptr;
|
||||
}
|
||||
SkUniqueCFRef<CTFontRef> ct(CTFontCreateWithGraphicsFont(cg.get(), 0, nullptr, nullptr));
|
||||
if (!ct) {
|
||||
return nullptr;
|
||||
}
|
||||
return create_from_CTFontRef(std::move(ct), nullptr, OpszVariation(), std::move(providedData));
|
||||
}
|
||||
|
||||
// Web fonts added to the CTFont registry do not return their character set.
|
||||
// Iterate through the font in this case. The existing caller caches the result,
|
||||
// so the performance impact isn't too bad.
|
||||
@ -2115,7 +2096,7 @@ std::unique_ptr<SkFontData> SkTypeface_Mac::onMakeFontData() const {
|
||||
static SkUniqueCFRef<CFDictionaryRef> ct_variation_from_cg_variation(CFDictionaryRef cgVariations,
|
||||
CFArrayRef ctAxes) {
|
||||
|
||||
SkUniqueCFRef<CFMutableDictionaryRef> ctVariations(
|
||||
SkUniqueCFRef<CFMutableDictionaryRef> ctVariation(
|
||||
CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
|
||||
&kCFTypeDictionaryKeyCallBacks,
|
||||
&kCFTypeDictionaryValueCallBacks));
|
||||
@ -2145,9 +2126,9 @@ static SkUniqueCFRef<CFDictionaryRef> ct_variation_from_cg_variation(CFDictionar
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CFDictionaryAddValue(ctVariations.get(), axisTag, axisValue);
|
||||
CFDictionaryAddValue(ctVariation.get(), axisTag, axisValue);
|
||||
}
|
||||
return ctVariations;
|
||||
return ctVariation;
|
||||
}
|
||||
|
||||
int SkTypeface_Mac::onGetVariationDesignPosition(
|
||||
@ -2169,8 +2150,8 @@ int SkTypeface_Mac::onGetVariationDesignPosition(
|
||||
// This call always returns nullptr on 10.11 and under for CGFontCreateWithDataProvider fonts.
|
||||
// When this happens, try converting the CG variation to a CT variation.
|
||||
// On 10.12 and later, this only returns non-default variations.
|
||||
SkUniqueCFRef<CFDictionaryRef> ctVariations(CTFontCopyVariation(fFontRef.get()));
|
||||
if (!ctVariations) {
|
||||
SkUniqueCFRef<CFDictionaryRef> ctVariation(CTFontCopyVariation(fFontRef.get()));
|
||||
if (!ctVariation) {
|
||||
// When 10.11 and earlier are no longer supported, the following code can be replaced with
|
||||
// return -1 and ct_variation_from_cg_variation can be removed.
|
||||
SkUniqueCFRef<CGFontRef> cgFont(CTFontCopyGraphicsFont(fFontRef.get(), nullptr));
|
||||
@ -2181,8 +2162,8 @@ int SkTypeface_Mac::onGetVariationDesignPosition(
|
||||
if (!cgVariations) {
|
||||
return -1;
|
||||
}
|
||||
ctVariations = ct_variation_from_cg_variation(cgVariations.get(), ctAxes.get());
|
||||
if (!ctVariations) {
|
||||
ctVariation = ct_variation_from_cg_variation(cgVariations.get(), ctAxes.get());
|
||||
if (!ctVariation) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@ -2206,7 +2187,7 @@ int SkTypeface_Mac::onGetVariationDesignPosition(
|
||||
coordinates[i].axis = tagLong;
|
||||
|
||||
CGFloat variationCGFloat;
|
||||
CFTypeRef variationValue = CFDictionaryGetValue(ctVariations.get(), tagNumber);
|
||||
CFTypeRef variationValue = CFDictionaryGetValue(ctVariation.get(), tagNumber);
|
||||
if (variationValue) {
|
||||
if (CFGetTypeID(variationValue) != CFNumberGetTypeID()) {
|
||||
return -1;
|
||||
@ -2696,45 +2677,52 @@ protected:
|
||||
}
|
||||
|
||||
sk_sp<SkTypeface> onMakeFromData(sk_sp<SkData> data, int ttcIndex) const override {
|
||||
SkUniqueCFRef<CGDataProviderRef> pr(SkCreateDataProviderFromData(data));
|
||||
if (!pr) {
|
||||
if (ttcIndex != 0) {
|
||||
return nullptr;
|
||||
}
|
||||
return create_from_dataProvider(std::move(pr), SkMemoryStream::Make(std::move(data)),
|
||||
ttcIndex);
|
||||
|
||||
SkUniqueCFRef<CTFontRef> ct = ctfont_from_skdata(data, ttcIndex);
|
||||
if (!ct) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return create_from_CTFontRef(std::move(ct), nullptr, OpszVariation(),
|
||||
SkMemoryStream::Make(std::move(data)));
|
||||
}
|
||||
|
||||
sk_sp<SkTypeface> onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset> stream,
|
||||
int ttcIndex) const override {
|
||||
SkUniqueCFRef<CGDataProviderRef> pr(SkCreateDataProviderFromStream(stream->duplicate()));
|
||||
if (!pr) {
|
||||
if (ttcIndex != 0) {
|
||||
return nullptr;
|
||||
}
|
||||
return create_from_dataProvider(std::move(pr), std::move(stream), ttcIndex);
|
||||
|
||||
sk_sp<SkData> data = skdata_from_skstreamasset(stream->duplicate());
|
||||
if (!data) {
|
||||
return nullptr;
|
||||
}
|
||||
SkUniqueCFRef<CTFontRef> ct = ctfont_from_skdata(std::move(data), ttcIndex);
|
||||
if (!ct) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return create_from_CTFontRef(std::move(ct), nullptr, OpszVariation(), std::move(stream));
|
||||
}
|
||||
|
||||
/** Creates a dictionary suitable for setting the axes on a CGFont. */
|
||||
struct CGFontVariations {
|
||||
struct CTFontVariation {
|
||||
SkUniqueCFRef<CFDictionaryRef> dict;
|
||||
OpszVariation opsz;
|
||||
};
|
||||
static CGFontVariations copy_axes(CGFontRef cg, const SkFontArguments& args) {
|
||||
// In macOS 10.15 CTFontCreate* overrides any 'opsz' variation with the 'size'.
|
||||
// Track the 'opsz' and return it, since it is an out of band axis.
|
||||
|
||||
/** Creates a dictionary suitable for setting the axes on a CTFont. */
|
||||
static CTFontVariation ctvariation_from_skfontarguments(CTFontRef ct,
|
||||
const SkFontArguments& args)
|
||||
{
|
||||
OpszVariation opsz;
|
||||
constexpr const SkFourByteTag opszTag = SkSetFourByteTag('o','p','s','z');
|
||||
|
||||
// The CGFont variation data is keyed by name, but lacks the tag.
|
||||
// The CTFont variation data is keyed by tag, and also has the name.
|
||||
// We would like to work with CTFont variations, but creating a CTFont font with
|
||||
// CTFont variation dictionary runs into bugs. So use the CTFont variation data
|
||||
// to match names to tags to create the appropriate CGFont.
|
||||
SkUniqueCFRef<CTFontRef> ct(CTFontCreateWithGraphicsFont(cg, 0, nullptr, nullptr));
|
||||
// CTFontCopyVariationAxes returns nullptr for CGFontCreateWithDataProvider fonts with
|
||||
// macOS 10.10 and iOS 9 or earlier. When this happens, there is no API to provide the tag.
|
||||
SkUniqueCFRef<CFArrayRef> ctAxes(CTFontCopyVariationAxes(ct.get()));
|
||||
SkUniqueCFRef<CFArrayRef> ctAxes(CTFontCopyVariationAxes(ct));
|
||||
if (!ctAxes) {
|
||||
return CGFontVariations();
|
||||
return CTFontVariation();
|
||||
}
|
||||
CFIndex axisCount = CFArrayGetCount(ctAxes.get());
|
||||
|
||||
@ -2748,26 +2736,18 @@ protected:
|
||||
for (int i = 0; i < axisCount; ++i) {
|
||||
CFTypeRef axisInfo = CFArrayGetValueAtIndex(ctAxes.get(), i);
|
||||
if (CFDictionaryGetTypeID() != CFGetTypeID(axisInfo)) {
|
||||
return CGFontVariations();
|
||||
return CTFontVariation();
|
||||
}
|
||||
CFDictionaryRef axisInfoDict = static_cast<CFDictionaryRef>(axisInfo);
|
||||
|
||||
// The assumption is that values produced by kCTFontVariationAxisNameKey and
|
||||
// kCGFontVariationAxisName will always be equal.
|
||||
// If they are ever not, seach the project history for "get_tag_for_name".
|
||||
CFTypeRef axisName = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisNameKey);
|
||||
if (!axisName || CFGetTypeID(axisName) != CFStringGetTypeID()) {
|
||||
return CGFontVariations();
|
||||
}
|
||||
|
||||
CFTypeRef tag = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisIdentifierKey);
|
||||
if (!tag || CFGetTypeID(tag) != CFNumberGetTypeID()) {
|
||||
return CGFontVariations();
|
||||
return CTFontVariation();
|
||||
}
|
||||
CFNumberRef tagNumber = static_cast<CFNumberRef>(tag);
|
||||
int64_t tagLong;
|
||||
if (!CFNumberGetValue(tagNumber, kCFNumberSInt64Type, &tagLong)) {
|
||||
return CGFontVariations();
|
||||
return CTFontVariation();
|
||||
}
|
||||
|
||||
// The variation axes can be set to any value, but cg will effectively pin them.
|
||||
@ -2779,7 +2759,7 @@ protected:
|
||||
!max || CFGetTypeID(max) != CFNumberGetTypeID() ||
|
||||
!def || CFGetTypeID(def) != CFNumberGetTypeID())
|
||||
{
|
||||
return CGFontVariations();
|
||||
return CTFontVariation();
|
||||
}
|
||||
CFNumberRef minNumber = static_cast<CFNumberRef>(min);
|
||||
CFNumberRef maxNumber = static_cast<CFNumberRef>(max);
|
||||
@ -2791,7 +2771,7 @@ protected:
|
||||
!CFNumberGetValue(maxNumber, kCFNumberDoubleType, &maxDouble) ||
|
||||
!CFNumberGetValue(defNumber, kCFNumberDoubleType, &defDouble))
|
||||
{
|
||||
return CGFontVariations();
|
||||
return CTFontVariation();
|
||||
}
|
||||
|
||||
double value = defDouble;
|
||||
@ -2812,73 +2792,115 @@ protected:
|
||||
}
|
||||
SkUniqueCFRef<CFNumberRef> valueNumber(
|
||||
CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &value));
|
||||
CFDictionaryAddValue(dict.get(), axisName, valueNumber.get());
|
||||
CFDictionaryAddValue(dict.get(), tagNumber, valueNumber.get());
|
||||
}
|
||||
return { SkUniqueCFRef<CFDictionaryRef>(std::move(dict)), opsz };
|
||||
}
|
||||
sk_sp<SkTypeface> onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset> s,
|
||||
const SkFontArguments& args) const override {
|
||||
if (args.getCollectionIndex() != 0) {
|
||||
return nullptr;
|
||||
|
||||
static sk_sp<SkData> skdata_from_skstreamasset(std::unique_ptr<SkStreamAsset> stream) {
|
||||
size_t size = stream->getLength();
|
||||
if (const void* base = stream->getMemoryBase()) {
|
||||
return SkData::MakeWithProc(base, size,
|
||||
[](const void*, void* ctx) -> void {
|
||||
delete (SkStreamAsset*)ctx;
|
||||
}, stream.release());
|
||||
}
|
||||
SkUniqueCFRef<CGDataProviderRef> provider(SkCreateDataProviderFromStream(s->duplicate()));
|
||||
if (!provider) {
|
||||
return nullptr;
|
||||
}
|
||||
SkUniqueCFRef<CGFontRef> cg(CGFontCreateWithDataProvider(provider.get()));
|
||||
if (!cg) {
|
||||
return SkData::MakeFromStream(stream.get(), size);
|
||||
}
|
||||
|
||||
static SkUniqueCFRef<CFDataRef> cfdata_from_skdata(sk_sp<SkData> data) {
|
||||
void const * const addr = data->data();
|
||||
size_t const size = data->size();
|
||||
|
||||
CFAllocatorContext ctx = {
|
||||
0, // CFIndex version
|
||||
data.release(), // void* info
|
||||
nullptr, // const void *(*retain)(const void *info);
|
||||
nullptr, // void (*release)(const void *info);
|
||||
nullptr, // CFStringRef (*copyDescription)(const void *info);
|
||||
nullptr, // void * (*allocate)(CFIndex size, CFOptionFlags hint, void *info);
|
||||
nullptr, // void*(*reallocate)(void* ptr,CFIndex newsize,CFOptionFlags hint,void* info);
|
||||
[](void*,void* info) -> void { // void (*deallocate)(void *ptr, void *info);
|
||||
SkASSERT(info);
|
||||
((SkData*)info)->unref();
|
||||
},
|
||||
nullptr, // CFIndex (*preferredSize)(CFIndex size, CFOptionFlags hint, void *info);
|
||||
};
|
||||
SkUniqueCFRef<CFAllocatorRef> alloc(CFAllocatorCreate(kCFAllocatorDefault, &ctx));
|
||||
return SkUniqueCFRef<CFDataRef>(CFDataCreateWithBytesNoCopy(
|
||||
kCFAllocatorDefault, (const UInt8 *)addr, size, alloc.get()));
|
||||
}
|
||||
|
||||
static SkUniqueCFRef<CTFontRef> ctfont_from_skdata(sk_sp<SkData> data, int ttcIndex) {
|
||||
// TODO: Use CTFontManagerCreateFontDescriptorsFromData when available.
|
||||
if (ttcIndex != 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CGFontVariations cgVariations = copy_axes(cg.get(), args);
|
||||
// The CGFontRef returned by CGFontCreateCopyWithVariations when the passed CGFontRef was
|
||||
// created from a data provider does not appear to have any ownership of the underlying
|
||||
// data. The original CGFontRef must be kept alive until the copy will no longer be used.
|
||||
SkUniqueCFRef<CGFontRef> cgVariant;
|
||||
if (cgVariations.dict) {
|
||||
cgVariant.reset(CGFontCreateCopyWithVariations(cg.get(), cgVariations.dict.get()));
|
||||
} else {
|
||||
cgVariant.reset(cg.release());
|
||||
SkUniqueCFRef<CFDataRef> cfData(cfdata_from_skdata(std::move(data)));
|
||||
|
||||
SkUniqueCFRef<CTFontDescriptorRef> desc(
|
||||
CTFontManagerCreateFontDescriptorFromData(cfData.get()));
|
||||
if (!desc) {
|
||||
return nullptr;
|
||||
}
|
||||
return SkUniqueCFRef<CTFontRef>(CTFontCreateWithFontDescriptor(desc.get(), 0, nullptr));
|
||||
}
|
||||
|
||||
sk_sp<SkTypeface> onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset> stream,
|
||||
const SkFontArguments& args) const override
|
||||
{
|
||||
// TODO: Use CTFontManagerCreateFontDescriptorsFromData when available.
|
||||
int ttcIndex = args.getCollectionIndex();
|
||||
if (ttcIndex != 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SkUniqueCFRef<CTFontDescriptorRef> desc;
|
||||
if (cgVariations.opsz.isSet) {
|
||||
desc = create_opsz_descriptor(cgVariations.opsz.value);
|
||||
sk_sp<SkData> data = skdata_from_skstreamasset(stream->duplicate());
|
||||
if (!data) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SkUniqueCFRef<CTFontRef> ct(
|
||||
CTFontCreateWithGraphicsFont(cgVariant.get(), 0, nullptr, desc.get()));
|
||||
SkUniqueCFRef<CTFontRef> ct = ctfont_from_skdata(std::move(data), ttcIndex);
|
||||
if (!ct) {
|
||||
return nullptr;
|
||||
}
|
||||
return create_from_CTFontRef(std::move(ct), std::move(cg), cgVariations.opsz, std::move(s));
|
||||
|
||||
CTFontVariation ctVariation = ctvariation_from_skfontarguments(ct.get(), args);
|
||||
|
||||
SkUniqueCFRef<CTFontRef> ctVariant;
|
||||
if (ctVariation.dict) {
|
||||
SkUniqueCFRef<CFMutableDictionaryRef> attributes(
|
||||
CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
|
||||
&kCFTypeDictionaryKeyCallBacks,
|
||||
&kCFTypeDictionaryValueCallBacks));
|
||||
CFDictionaryAddValue(attributes.get(),
|
||||
kCTFontVariationAttribute, ctVariation.dict.get());
|
||||
SkUniqueCFRef<CTFontDescriptorRef> varDesc(
|
||||
CTFontDescriptorCreateWithAttributes(attributes.get()));
|
||||
ctVariant.reset(CTFontCreateCopyWithAttributes(ct.get(), 0, nullptr, varDesc.get()));
|
||||
} else {
|
||||
ctVariant.reset(ct.release());
|
||||
}
|
||||
if (!ctVariant) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return create_from_CTFontRef(std::move(ctVariant), nullptr, ctVariation.opsz,
|
||||
std::move(stream));
|
||||
}
|
||||
|
||||
/** Creates a dictionary suitable for setting the axes on a CGFont. */
|
||||
static CGFontVariations copy_axes(CGFontRef cg, SkFontData* fontData) {
|
||||
/** Creates a dictionary suitable for setting the axes on a CTFont. */
|
||||
static CTFontVariation ctvariation_from_skfontdata(CTFontRef ct, SkFontData* fontData) {
|
||||
// In macOS 10.15 CTFontCreate* overrides any 'opsz' variation with the 'size'.
|
||||
// Track the 'opsz' and return it, since it is an out of band axis.
|
||||
OpszVariation opsz;
|
||||
constexpr const SkFourByteTag opszTag = SkSetFourByteTag('o','p','s','z');
|
||||
|
||||
// The CGFont variation data is keyed by name, but lacks the tag.
|
||||
// The CTFont variation data is keyed by tag, and also has the name.
|
||||
// We would like to work with CTFont variations, but creating a CTFont font with
|
||||
// CTFont variation dictionary runs into bugs. So use the CTFont variation data
|
||||
// to match names to tags to create the appropriate CGFont.
|
||||
SkUniqueCFRef<CTFontRef> ct(CTFontCreateWithGraphicsFont(cg, 0, nullptr, nullptr));
|
||||
// CTFontCopyVariationAxes returns nullptr for CGFontCreateWithDataProvider fonts with
|
||||
// macOS 10.10 and iOS 9 or earlier. When this happens, there is no API to provide the tag.
|
||||
SkUniqueCFRef<CFArrayRef> ctAxes(CTFontCopyVariationAxes(ct.get()));
|
||||
SkUniqueCFRef<CFArrayRef> ctAxes(CTFontCopyVariationAxes(ct));
|
||||
|
||||
SkUniqueCFRef<CFArrayRef> cgAxes(CGFontCopyVariationAxes(cg));
|
||||
if (!cgAxes) {
|
||||
return CGFontVariations();
|
||||
}
|
||||
|
||||
CFIndex axisCount = CFArrayGetCount(cgAxes.get());
|
||||
CFIndex axisCount = CFArrayGetCount(ctAxes.get());
|
||||
if (0 == axisCount || axisCount != fontData->getAxisCount()) {
|
||||
return CGFontVariations();
|
||||
return CTFontVariation();
|
||||
}
|
||||
|
||||
SkUniqueCFRef<CFMutableDictionaryRef> dict(
|
||||
@ -2887,25 +2909,31 @@ protected:
|
||||
&kCFTypeDictionaryValueCallBacks));
|
||||
|
||||
for (int i = 0; i < fontData->getAxisCount(); ++i) {
|
||||
CFTypeRef axisInfo = CFArrayGetValueAtIndex(cgAxes.get(), i);
|
||||
CFTypeRef axisInfo = CFArrayGetValueAtIndex(ctAxes.get(), i);
|
||||
if (CFDictionaryGetTypeID() != CFGetTypeID(axisInfo)) {
|
||||
return CGFontVariations();
|
||||
return CTFontVariation();
|
||||
}
|
||||
CFDictionaryRef axisInfoDict = static_cast<CFDictionaryRef>(axisInfo);
|
||||
|
||||
CFTypeRef axisName = CFDictionaryGetValue(axisInfoDict, kCGFontVariationAxisName);
|
||||
if (!axisName || CFGetTypeID(axisName) != CFStringGetTypeID()) {
|
||||
return CGFontVariations();
|
||||
CFTypeRef tag = CFDictionaryGetValue(axisInfoDict,
|
||||
kCTFontVariationAxisIdentifierKey);
|
||||
if (!tag || CFGetTypeID(tag) != CFNumberGetTypeID()) {
|
||||
return CTFontVariation();
|
||||
}
|
||||
CFNumberRef tagNumber = static_cast<CFNumberRef>(tag);
|
||||
int64_t tagLong;
|
||||
if (!CFNumberGetValue(tagNumber, kCFNumberSInt64Type, &tagLong)) {
|
||||
return CTFontVariation();
|
||||
}
|
||||
|
||||
// The variation axes can be set to any value, but cg will effectively pin them.
|
||||
// Pin them here to normalize.
|
||||
CFTypeRef min = CFDictionaryGetValue(axisInfoDict, kCGFontVariationAxisMinValue);
|
||||
CFTypeRef max = CFDictionaryGetValue(axisInfoDict, kCGFontVariationAxisMaxValue);
|
||||
CFTypeRef min = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisMinimumValueKey);
|
||||
CFTypeRef max = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisMaximumValueKey);
|
||||
if (!min || CFGetTypeID(min) != CFNumberGetTypeID() ||
|
||||
!max || CFGetTypeID(max) != CFNumberGetTypeID())
|
||||
{
|
||||
return CGFontVariations();
|
||||
return CTFontVariation();
|
||||
}
|
||||
CFNumberRef minNumber = static_cast<CFNumberRef>(min);
|
||||
CFNumberRef maxNumber = static_cast<CFNumberRef>(max);
|
||||
@ -2914,87 +2942,71 @@ protected:
|
||||
if (!CFNumberGetValue(minNumber, kCFNumberDoubleType, &minDouble) ||
|
||||
!CFNumberGetValue(maxNumber, kCFNumberDoubleType, &maxDouble))
|
||||
{
|
||||
return CGFontVariations();
|
||||
return CTFontVariation();
|
||||
}
|
||||
double value = SkTPin(SkFixedToDouble(fontData->getAxis()[i]), minDouble, maxDouble);
|
||||
|
||||
// If this is the opsz axis, set the opsz return value.
|
||||
// Note that ctAxes will be nullptr on macOS 10.10 and iOS 9 and earlier.
|
||||
if (ctAxes) {
|
||||
CFTypeRef axisInfo = CFArrayGetValueAtIndex(ctAxes.get(), i);
|
||||
if (CFDictionaryGetTypeID() != CFGetTypeID(axisInfo)) {
|
||||
return CGFontVariations();
|
||||
}
|
||||
CFDictionaryRef axisInfoDict = static_cast<CFDictionaryRef>(axisInfo);
|
||||
|
||||
CFTypeRef tag = CFDictionaryGetValue(axisInfoDict,
|
||||
kCTFontVariationAxisIdentifierKey);
|
||||
if (!tag || CFGetTypeID(tag) != CFNumberGetTypeID()) {
|
||||
return CGFontVariations();
|
||||
}
|
||||
CFNumberRef tagNumber = static_cast<CFNumberRef>(tag);
|
||||
int64_t tagLong;
|
||||
if (!CFNumberGetValue(tagNumber, kCFNumberSInt64Type, &tagLong)) {
|
||||
return CGFontVariations();
|
||||
}
|
||||
|
||||
if (tagLong == opszTag) {
|
||||
opsz.isSet = true;
|
||||
opsz.value = value;
|
||||
}
|
||||
if (tagLong == opszTag) {
|
||||
opsz.isSet = true;
|
||||
opsz.value = value;
|
||||
}
|
||||
|
||||
SkUniqueCFRef<CFNumberRef> valueNumber(
|
||||
CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &value));
|
||||
CFDictionaryAddValue(dict.get(), axisName, valueNumber.get());
|
||||
CFDictionaryAddValue(dict.get(), tagNumber, valueNumber.get());
|
||||
}
|
||||
return { SkUniqueCFRef<CFDictionaryRef>(std::move(dict)), opsz };
|
||||
}
|
||||
sk_sp<SkTypeface> onMakeFromFontData(std::unique_ptr<SkFontData> fontData) const override {
|
||||
// TODO: Use CTFontManagerCreateFontDescriptorsFromData when available.
|
||||
if (fontData->getIndex() != 0) {
|
||||
return nullptr;
|
||||
}
|
||||
SkUniqueCFRef<CGDataProviderRef> provider(
|
||||
SkCreateDataProviderFromStream(fontData->getStream()->duplicate()));
|
||||
if (!provider) {
|
||||
|
||||
sk_sp<SkData> data = skdata_from_skstreamasset(fontData->getStream()->duplicate());
|
||||
if (!data) {
|
||||
return nullptr;
|
||||
}
|
||||
SkUniqueCFRef<CGFontRef> cg(CGFontCreateWithDataProvider(provider.get()));
|
||||
if (!cg) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CGFontVariations cgVariations = copy_axes(cg.get(), fontData.get());
|
||||
// The CGFontRef returned by CGFontCreateCopyWithVariations when the passed CGFontRef was
|
||||
// created from a data provider does not appear to have any ownership of the underlying
|
||||
// data. The original CGFontRef must be kept alive until the copy will no longer be used.
|
||||
SkUniqueCFRef<CGFontRef> cgVariant;
|
||||
if (cgVariations.dict) {
|
||||
cgVariant.reset(CGFontCreateCopyWithVariations(cg.get(), cgVariations.dict.get()));
|
||||
} else {
|
||||
cgVariant.reset(cg.release());
|
||||
}
|
||||
|
||||
SkUniqueCFRef<CTFontDescriptorRef> desc;
|
||||
if (cgVariations.opsz.isSet) {
|
||||
desc = create_opsz_descriptor(cgVariations.opsz.value);
|
||||
}
|
||||
|
||||
SkUniqueCFRef<CTFontRef> ct(
|
||||
CTFontCreateWithGraphicsFont(cgVariant.get(), 0, nullptr, desc.get()));
|
||||
SkUniqueCFRef<CTFontRef> ct = ctfont_from_skdata(std::move(data), fontData->getIndex());
|
||||
if (!ct) {
|
||||
return nullptr;
|
||||
}
|
||||
return create_from_CTFontRef(std::move(ct), std::move(cg),
|
||||
cgVariations.opsz, fontData->detachStream());
|
||||
|
||||
CTFontVariation ctVariation = ctvariation_from_skfontdata(ct.get(), fontData.get());
|
||||
|
||||
SkUniqueCFRef<CTFontRef> ctVariant;
|
||||
if (ctVariation.dict) {
|
||||
SkUniqueCFRef<CFMutableDictionaryRef> attributes(
|
||||
CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
|
||||
&kCFTypeDictionaryKeyCallBacks,
|
||||
&kCFTypeDictionaryValueCallBacks));
|
||||
CFDictionaryAddValue(attributes.get(),
|
||||
kCTFontVariationAttribute, ctVariation.dict.get());
|
||||
SkUniqueCFRef<CTFontDescriptorRef> varDesc(
|
||||
CTFontDescriptorCreateWithAttributes(attributes.get()));
|
||||
ctVariant.reset(CTFontCreateCopyWithAttributes(ct.get(), 0, nullptr, varDesc.get()));
|
||||
} else {
|
||||
ctVariant.reset(ct.release());
|
||||
}
|
||||
if (!ctVariant) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return create_from_CTFontRef(std::move(ctVariant), nullptr,
|
||||
ctVariation.opsz, fontData->detachStream());
|
||||
}
|
||||
|
||||
sk_sp<SkTypeface> onMakeFromFile(const char path[], int ttcIndex) const override {
|
||||
SkUniqueCFRef<CGDataProviderRef> pr(CGDataProviderCreateWithFilename(path));
|
||||
if (!pr) {
|
||||
if (ttcIndex != 0) {
|
||||
return nullptr;
|
||||
}
|
||||
return create_from_dataProvider(std::move(pr), SkFILEStream::Make(path), ttcIndex);
|
||||
|
||||
sk_sp<SkData> data = SkData::MakeFromFileName(path);
|
||||
if (!data) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return this->onMakeFromData(std::move(data), ttcIndex);
|
||||
}
|
||||
|
||||
sk_sp<SkTypeface> onLegacyMakeTypeface(const char familyName[], SkFontStyle style) const override {
|
||||
|
@ -5,79 +5,4 @@
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "include/core/SkTypes.h"
|
||||
|
||||
#if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS)
|
||||
|
||||
#include "include/core/SkStream.h"
|
||||
#include "include/private/SkMalloc.h"
|
||||
#include "include/utils/mac/SkCGUtils.h"
|
||||
|
||||
// These are used by CGDataProviderCreateWithData
|
||||
|
||||
static void unref_proc(void* info, const void* addr, size_t size) {
|
||||
SkASSERT(info);
|
||||
((SkRefCnt*)info)->unref();
|
||||
}
|
||||
|
||||
static void delete_stream_proc(void* info, const void* addr, size_t size) {
|
||||
SkASSERT(info);
|
||||
SkStream* stream = (SkStream*)info;
|
||||
SkASSERT(stream->getMemoryBase() == addr);
|
||||
SkASSERT(stream->getLength() == size);
|
||||
delete stream;
|
||||
}
|
||||
|
||||
// These are used by CGDataProviderSequentialCallbacks
|
||||
|
||||
static size_t get_bytes_proc(void* info, void* buffer, size_t bytes) {
|
||||
SkASSERT(info);
|
||||
return ((SkStream*)info)->read(buffer, bytes);
|
||||
}
|
||||
|
||||
static off_t skip_forward_proc(void* info, off_t bytes) {
|
||||
return ((SkStream*)info)->skip((size_t) bytes);
|
||||
}
|
||||
|
||||
static void rewind_proc(void* info) {
|
||||
SkASSERT(info);
|
||||
((SkStream*)info)->rewind();
|
||||
}
|
||||
|
||||
// Used when info is an SkStream.
|
||||
static void release_info_proc(void* info) {
|
||||
SkASSERT(info);
|
||||
delete (SkStream*)info;
|
||||
}
|
||||
|
||||
CGDataProviderRef SkCreateDataProviderFromStream(std::unique_ptr<SkStreamRewindable> stream) {
|
||||
// TODO: Replace with SkStream::getData() when that is added. Then we only
|
||||
// have one version of CGDataProviderCreateWithData (i.e. same release proc)
|
||||
const void* addr = stream->getMemoryBase();
|
||||
if (addr) {
|
||||
// special-case when the stream is just a block of ram
|
||||
size_t size = stream->getLength();
|
||||
return CGDataProviderCreateWithData(stream.release(), addr, size, delete_stream_proc);
|
||||
}
|
||||
|
||||
CGDataProviderSequentialCallbacks rec;
|
||||
sk_bzero(&rec, sizeof(rec));
|
||||
rec.version = 0;
|
||||
rec.getBytes = get_bytes_proc;
|
||||
rec.skipForward = skip_forward_proc;
|
||||
rec.rewind = rewind_proc;
|
||||
rec.releaseInfo = release_info_proc;
|
||||
return CGDataProviderCreateSequential(stream.release(), &rec);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "include/core/SkData.h"
|
||||
|
||||
CGDataProviderRef SkCreateDataProviderFromData(sk_sp<SkData> data) {
|
||||
const void* addr = data->data();
|
||||
size_t size = data->size();
|
||||
return CGDataProviderCreateWithData(data.release(), addr, size, unref_proc);
|
||||
}
|
||||
|
||||
#endif//defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS)
|
||||
// Remove file after it is removed from downstream builds.
|
||||
|
Loading…
Reference in New Issue
Block a user