Chromium Code Reviews| Index: src/ports/SkFontHost_mac.cpp |
| diff --git a/src/ports/SkFontHost_mac.cpp b/src/ports/SkFontHost_mac.cpp |
| index 3c7be463643b7ceb73a1bcac141777be8bf6428a..2ef5f4991362d631997fd3d5a83449ba17111ad4 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,116 @@ 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, CFNumberType::kCFNumberDoubleType, &valueDouble) || |
|
bungeman-skia
2015/05/13 23:04:44
This should have just been just kCFNumberDoubleTyp
|
| + 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, CFNumberType::kCFNumberDoubleType, |
|
bungeman-skia
2015/05/13 23:04:44
Same here.
|
| + &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 +2364,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) { |