Reland "Replace CGFontCreate with CTFontManagerCreate."
This is a reland of f1d4f00fda
Original change's description:
> 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>
Bug: skia:4043, skia:9627
Change-Id: Ic265f2ce52b816831e6402c5ffd21dac065049dd
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/257052
Reviewed-by: Dominik Röttsches <drott@chromium.org>
Commit-Queue: Ben Wagner <bungeman@google.com>
This commit is contained in:
parent
2a490bc769
commit
c96f5108df
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,118 @@ 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> cgAxes(CGFontCopyVariationAxes(cg));
|
||||
if (!cgAxes) {
|
||||
return CGFontVariations();
|
||||
SkUniqueCFRef<CFArrayRef> ctAxes(CTFontCopyVariationAxes(ct));
|
||||
if (!ctAxes) {
|
||||
return CTFontVariation();
|
||||
}
|
||||
|
||||
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 +2912,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 +2945,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