| Index: src/ports/SkFontHost_mac.cpp
|
| diff --git a/src/ports/SkFontHost_mac.cpp b/src/ports/SkFontHost_mac.cpp
|
| index 3c7be463643b7ceb73a1bcac141777be8bf6428a..ff23b99905117c486e4c682bfbe3339aee5d4ad7 100755
|
| --- a/src/ports/SkFontHost_mac.cpp
|
| +++ b/src/ports/SkFontHost_mac.cpp
|
| @@ -428,10 +428,12 @@ static const uint32_t SkCTFontColorGlyphsTrait = (1 << 13);
|
| class SkTypeface_Mac : public SkTypeface {
|
| public:
|
| SkTypeface_Mac(const SkFontStyle& fs, bool isFixedPitch,
|
| - CTFontRef fontRef, const char requestedName[], bool isLocalStream)
|
| + CTFontRef fontRef, const char requestedName[], bool isLocalStream,
|
| + CGFontRef originatingCGFontRef = NULL)
|
| : SkTypeface(fs, SkTypefaceCache::NewFontID(), isFixedPitch)
|
| , fRequestedName(requestedName)
|
| , fFontRef(fontRef) // caller has already called CFRetain for us
|
| + , fOriginatingCGFontRef(originatingCGFontRef)
|
| , fHasColorGlyphs(SkToBool(CTFontGetSymbolicTraits(fFontRef) & SkCTFontColorGlyphsTrait))
|
| , fIsLocalStream(isLocalStream)
|
| {
|
| @@ -440,11 +442,13 @@ public:
|
|
|
| SkString fRequestedName;
|
| AutoCFRelease<CTFontRef> fFontRef;
|
| + AutoCFRelease<CGFontRef> fOriginatingCGFontRef;
|
| const bool fHasColorGlyphs;
|
|
|
| protected:
|
| int onGetUPEM() const override;
|
| SkStreamAsset* onOpenStream(int* ttcIndex) const override;
|
| + SkFontData* onCreateFontData() const override;
|
| void onGetFamilyName(SkString* familyName) const override;
|
| SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const override;
|
| int onGetTableTags(SkFontTableTag tags[]) const override;
|
| @@ -467,12 +471,15 @@ private:
|
| };
|
|
|
| /** Creates a typeface without searching the cache. Takes ownership of the CTFontRef. */
|
| -static SkTypeface* NewFromFontRef(CTFontRef fontRef, const char name[], bool isLocalStream) {
|
| +static SkTypeface* NewFromFontRef(CTFontRef fontRef, const char name[], bool isLocalStream,
|
| + CGFontRef originatingCGFontRef = NULL)
|
| +{
|
| SkASSERT(fontRef);
|
| bool isFixedPitch;
|
| SkFontStyle style = SkFontStyle(computeStyleBits(fontRef, &isFixedPitch));
|
|
|
| - return new SkTypeface_Mac(style, isFixedPitch, fontRef, name, isLocalStream);
|
| + return new SkTypeface_Mac(style, isFixedPitch, fontRef, name, isLocalStream,
|
| + originatingCGFontRef);
|
| }
|
|
|
| static bool find_by_CTFontRef(SkTypeface* cached, const SkFontStyle&, void* context) {
|
| @@ -1752,6 +1759,115 @@ SkStreamAsset* SkTypeface_Mac::onOpenStream(int* ttcIndex) const {
|
| return stream;
|
| }
|
|
|
| +struct NonDefaultAxesContext {
|
| + SkFixed* axisValue;
|
| + CFArrayRef cgAxes;
|
| +};
|
| +static void set_non_default_axes(CFTypeRef key, CFTypeRef value, void* context) {
|
| + NonDefaultAxesContext* self = static_cast<NonDefaultAxesContext*>(context);
|
| +
|
| + if (CFGetTypeID(key) != CFStringGetTypeID() || CFGetTypeID(value) != CFNumberGetTypeID()) {
|
| + return;
|
| + }
|
| +
|
| + // The key is a CFString which is a string from the 'name' table.
|
| + // Search the cgAxes for an axis with this name, and use its index to store the value.
|
| + CFIndex keyIndex = -1;
|
| + CFStringRef keyString = static_cast<CFStringRef>(key);
|
| + for (CFIndex i = 0; i < CFArrayGetCount(self->cgAxes); ++i) {
|
| + CFTypeRef cgAxis = CFArrayGetValueAtIndex(self->cgAxes, i);
|
| + if (CFGetTypeID(cgAxis) != CFDictionaryGetTypeID()) {
|
| + continue;
|
| + }
|
| +
|
| + CFDictionaryRef cgAxisDict = static_cast<CFDictionaryRef>(cgAxis);
|
| + CFTypeRef cgAxisName = CFDictionaryGetValue(cgAxisDict, kCGFontVariationAxisName);
|
| + if (!cgAxisName || CFGetTypeID(cgAxisName) != CFStringGetTypeID()) {
|
| + continue;
|
| + }
|
| + CFStringRef cgAxisNameString = static_cast<CFStringRef>(cgAxisName);
|
| + if (CFStringCompare(keyString, cgAxisNameString, 0) == kCFCompareEqualTo) {
|
| + keyIndex = i;
|
| + break;
|
| + }
|
| + }
|
| + if (keyIndex == -1) {
|
| + return;
|
| + }
|
| +
|
| + CFNumberRef valueNumber = static_cast<CFNumberRef>(value);
|
| + double valueDouble;
|
| + if (!CFNumberGetValue(valueNumber, kCFNumberDoubleType, &valueDouble) ||
|
| + valueDouble < SkFixedToDouble(SK_FixedMin) || SkFixedToDouble(SK_FixedMax) < valueDouble)
|
| + {
|
| + return;
|
| + }
|
| + self->axisValue[keyIndex] = SkDoubleToFixed(valueDouble);
|
| +}
|
| +static bool get_variations(CTFontRef fFontRef, CFIndex* cgAxisCount,
|
| + SkAutoSTMalloc<4, SkFixed>* axisValues)
|
| +{
|
| + // CTFontCopyVariationAxes and CTFontCopyVariation do not work when applied to fonts which
|
| + // started life with CGFontCreateWithDataProvider (they simply always return NULL).
|
| + // As a result, we are limited to CGFontCopyVariationAxes and CGFontCopyVariations.
|
| + AutoCFRelease<CGFontRef> cgFont(CTFontCopyGraphicsFont(fFontRef, NULL));
|
| +
|
| + AutoCFRelease<CFDictionaryRef> cgVariations(CGFontCopyVariations(cgFont));
|
| + // If a font has no variations CGFontCopyVariations returns NULL (instead of an empty dict).
|
| + if (!cgVariations.get()) {
|
| + return false;
|
| + }
|
| +
|
| + AutoCFRelease<CFArrayRef> cgAxes(CGFontCopyVariationAxes(cgFont));
|
| + *cgAxisCount = CFArrayGetCount(cgAxes);
|
| + axisValues->reset(*cgAxisCount);
|
| +
|
| + // Set all of the axes to their default values.
|
| + // Fail if any default value cannot be determined.
|
| + for (CFIndex i = 0; i < *cgAxisCount; ++i) {
|
| + CFTypeRef cgAxis = CFArrayGetValueAtIndex(cgAxes, i);
|
| + if (CFGetTypeID(cgAxis) != CFDictionaryGetTypeID()) {
|
| + return false;
|
| + }
|
| +
|
| + CFDictionaryRef cgAxisDict = static_cast<CFDictionaryRef>(cgAxis);
|
| + CFTypeRef axisDefaultValue = CFDictionaryGetValue(cgAxisDict,
|
| + kCGFontVariationAxisDefaultValue);
|
| + if (!axisDefaultValue || CFGetTypeID(axisDefaultValue) != CFNumberGetTypeID()) {
|
| + return false;
|
| + }
|
| + CFNumberRef axisDefaultValueNumber = static_cast<CFNumberRef>(axisDefaultValue);
|
| + double axisDefaultValueDouble;
|
| + if (!CFNumberGetValue(axisDefaultValueNumber, kCFNumberDoubleType, &axisDefaultValueDouble))
|
| + {
|
| + return false;
|
| + }
|
| + if (axisDefaultValueDouble < SkFixedToDouble(SK_FixedMin) ||
|
| + SkFixedToDouble(SK_FixedMax) < axisDefaultValueDouble)
|
| + {
|
| + return false;
|
| + }
|
| + (*axisValues)[(int)i] = SkDoubleToFixed(axisDefaultValueDouble);
|
| + }
|
| +
|
| + // Override the default values with the given font's stated axis values.
|
| + NonDefaultAxesContext c = { axisValues->get(), cgAxes.get() };
|
| + CFDictionaryApplyFunction(cgVariations, set_non_default_axes, &c);
|
| +
|
| + return true;
|
| +}
|
| +SkFontData* SkTypeface_Mac::onCreateFontData() const {
|
| + int index;
|
| + SkAutoTDelete<SkStreamAsset> stream(this->onOpenStream(&index));
|
| +
|
| + CFIndex cgAxisCount;
|
| + SkAutoSTMalloc<4, SkFixed> axisValues;
|
| + if (get_variations(fFontRef, &cgAxisCount, &axisValues)) {
|
| + return new SkFontData(stream.detach(), index, axisValues.get(), cgAxisCount);
|
| + }
|
| + return new SkFontData(stream.detach(), index, NULL, 0);
|
| +}
|
| +
|
| ///////////////////////////////////////////////////////////////////////////////
|
| ///////////////////////////////////////////////////////////////////////////////
|
|
|
| @@ -2247,6 +2363,89 @@ protected:
|
| return create_from_dataProvider(pr);
|
| }
|
|
|
| + static CFDictionaryRef get_axes(CGFontRef cg, SkFontData* fontData) {
|
| + AutoCFRelease<CFArrayRef> cgAxes(CGFontCopyVariationAxes(cg));
|
| + if (!cgAxes) {
|
| + return NULL;
|
| + }
|
| +
|
| + CFIndex axisCount = CFArrayGetCount(cgAxes);
|
| + if (0 == axisCount || axisCount != fontData->getAxisCount()) {
|
| + return NULL;
|
| + }
|
| +
|
| + CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorDefault, axisCount,
|
| + &kCFTypeDictionaryKeyCallBacks,
|
| + &kCFTypeDictionaryValueCallBacks);
|
| + for (int i = 0; i < fontData->getAxisCount(); ++i) {
|
| + CFTypeRef axisInfo = CFArrayGetValueAtIndex(cgAxes, i);
|
| + if (CFDictionaryGetTypeID() != CFGetTypeID(axisInfo)) {
|
| + return NULL;
|
| + }
|
| + CFDictionaryRef axisInfoDict = static_cast<CFDictionaryRef>(axisInfo);
|
| +
|
| + CFTypeRef axisName = CFDictionaryGetValue(axisInfoDict, kCGFontVariationAxisName);
|
| + if (!axisName || CFGetTypeID(axisName) != CFStringGetTypeID()) {
|
| + return NULL;
|
| + }
|
| +
|
| + // 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);
|
| + if (!min || CFGetTypeID(min) != CFNumberGetTypeID() ||
|
| + !max || CFGetTypeID(max) != CFNumberGetTypeID())
|
| + {
|
| + return NULL;
|
| + }
|
| + CFNumberRef minNumber = static_cast<CFNumberRef>(min);
|
| + CFNumberRef maxNumber = static_cast<CFNumberRef>(max);
|
| + double minDouble;
|
| + double maxDouble;
|
| + if (!CFNumberGetValue(minNumber, kCFNumberDoubleType, &minDouble) ||
|
| + !CFNumberGetValue(maxNumber, kCFNumberDoubleType, &maxDouble))
|
| + {
|
| + return NULL;
|
| + }
|
| + double value = SkTPin(SkFixedToDouble(fontData->getAxis()[i]), minDouble, maxDouble);
|
| + CFNumberRef valueNumber = CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType,
|
| + &value);
|
| +
|
| + CFDictionaryAddValue(dict, axisName, valueNumber);
|
| + CFRelease(valueNumber);
|
| + }
|
| + return dict;
|
| + }
|
| + SkTypeface* onCreateFromFontData(SkFontData* data) const override {
|
| + SkAutoTDelete<SkFontData> fontData(data);
|
| + SkStreamAsset* stream = fontData->detachStream();
|
| + AutoCFRelease<CGDataProviderRef> provider(SkCreateDataProviderFromStream(stream));
|
| + if (NULL == provider) {
|
| + return NULL;
|
| + }
|
| + AutoCFRelease<CGFontRef> cg(CGFontCreateWithDataProvider(provider));
|
| + if (NULL == cg) {
|
| + return NULL;
|
| + }
|
| +
|
| + AutoCFRelease<CFDictionaryRef> cgVariations(get_axes(cg, fontData));
|
| + // 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.
|
| + AutoCFRelease<CGFontRef> cgVariant;
|
| + if (cgVariations) {
|
| + cgVariant.reset(CGFontCreateCopyWithVariations(cg, cgVariations));
|
| + } else {
|
| + cgVariant.reset(cg.detach());
|
| + }
|
| +
|
| + CTFontRef ct = CTFontCreateWithGraphicsFont(cgVariant, 0, NULL, NULL);
|
| + if (!ct) {
|
| + return NULL;
|
| + }
|
| + return NewFromFontRef(ct, NULL, true, cg.detach());
|
| + }
|
| +
|
| SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const override {
|
| AutoCFRelease<CGDataProviderRef> pr(CGDataProviderCreateWithFilename(path));
|
| if (NULL == pr) {
|
|
|