Index: src/ports/SkFontHost_mac.cpp |
diff --git a/src/ports/SkFontHost_mac.cpp b/src/ports/SkFontHost_mac.cpp |
index 5eaf7df6036b281fe08560d07baeef9e418fa7fe..4b8316afd3f9139940255e55dcd4e3765c2bf63f 100755 |
--- a/src/ports/SkFontHost_mac.cpp |
+++ b/src/ports/SkFontHost_mac.cpp |
@@ -466,6 +466,7 @@ public: |
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; |
@@ -1764,6 +1765,111 @@ 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* c = static_cast<NonDefaultAxesContext*>(context); |
+ |
+ // 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; |
+ if (CFGetTypeID(key) == CFStringGetTypeID()) { |
+ CFStringRef keyString = static_cast<CFStringRef>(key); |
+ for (CFIndex i = 0; i < CFArrayGetCount(c->cgAxes); ++i) { |
+ CFTypeRef cgAxis = CFArrayGetValueAtIndex(c->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; |
+ } |
+ |
+ if (CFGetTypeID(value) == CFNumberGetTypeID()) { |
+ CFNumberRef valueNumber = static_cast<CFNumberRef>(value); |
+ double valueDouble; |
+ if (CFNumberGetValue(valueNumber, CFNumberType::kCFNumberDoubleType, &valueDouble) |
+ && SkFixedToDouble(SK_FixedMin) <= valueDouble && valueDouble <= SkFixedToDouble(SK_FixedMax)) // better check? |
+ { |
+ c->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, &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)) { |
+ //axisValues[0] = 4 * SK_Fixed1; // TODO:remove, for testing out of bound values |
+ return new SkFontData(stream.detach(), index, cgAxisCount, axisValues.get()); |
+ } |
+ return new SkFontData(stream.detach(), index, 0, NULL); |
+} |
+ |
/////////////////////////////////////////////////////////////////////////////// |
/////////////////////////////////////////////////////////////////////////////// |
@@ -2267,6 +2373,67 @@ 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 (axisCount != fontData->getAxisCount()) { |
+ return NULL; |
+ } |
+ |
+ SkAutoSTMalloc<4, CFTypeRef> keys(fontData->getAxisCount()); |
+ SkAutoSTMalloc<4, CFTypeRef> values(fontData->getAxisCount()); |
+ 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; |
+ } |
+ keys[i] = axisName; |
+ |
+ //CFNumberRef min = static_cast<CFNumberRef>(CFDictionaryGetValue(axisInfo, kCGFontVariationAxisMinValue)); |
+ //CFNumberRef max = static_cast<CFNumberRef>(CFDictionaryGetValue(axisInfo, kCGFontVariationAxisMaxValue)); |
+ //TODO: should the value be pinned? |
+ double value = SkFixedToDouble(fontData->getAxis()[i]); |
+ values[i] = CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &value); |
+ } |
+ |
+ return CFDictionaryCreate(kCFAllocatorDefault, keys.get(), values.get(), fontData->getAxisCount(), |
+ &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); |
+ |
+ } |
+ SkTypeface* onCreateFromFontData(SkFontData* fontData) const override { |
+ AutoCFRelease<CGDataProviderRef> provider(SkCreateDataProviderFromStream(fontData->transferStream())); |
+ if (NULL == provider) { |
+ return NULL; |
+ } |
+ AutoCFRelease<CGFontRef> cg(CGFontCreateWithDataProvider(provider)); |
+ if (NULL == cg) { |
+ return NULL; |
+ } |
+ |
+ AutoCFRelease<CFDictionaryRef> cgVariations(get_axes(cg, fontData)); |
+ AutoCFRelease<CGFontRef> cgVariant(cgVariations ? CGFontCreateCopyWithVariations(cg, cgVariations) : cg); |
+ |
+ CTFontRef ct = CTFontCreateWithGraphicsFont(cgVariant, 0, NULL, NULL); |
+ if (!ct) { |
+ return NULL; |
+ } |
+ //SkTypeface* typeface = NewFromFontRef(ct, NULL, true); |
+ //SkFontData* fontData1 = typeface->createFontData(); |
+ //delete fontData1; |
+ //return typeface; |
+ return NewFromFontRef(ct, NULL, true); |
+ } |
+ |
SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const override { |
AutoCFRelease<CGDataProviderRef> pr(CGDataProviderCreateWithFilename(path)); |
if (NULL == pr) { |