Index: src/ports/SkFontHost_mac.cpp |
diff --git a/src/ports/SkFontHost_mac.cpp b/src/ports/SkFontHost_mac.cpp |
index 68668c248e8ab5a084e511df8ed108b82c06ea19..41cb52b660d29f034ed3103368957c4cc077a57b 100644 |
--- a/src/ports/SkFontHost_mac.cpp |
+++ b/src/ports/SkFontHost_mac.cpp |
@@ -370,31 +370,90 @@ private: |
/////////////////////////////////////////////////////////////////////////////// |
-static bool find_dict_float(CFDictionaryRef dict, CFStringRef name, float* value) { |
+static bool find_dict_CGFloat(CFDictionaryRef dict, CFStringRef name, CGFloat* value) { |
CFNumberRef num; |
return CFDictionaryGetValueIfPresent(dict, name, (const void**)&num) |
&& CFNumberIsFloatType(num) |
- && CFNumberGetValue(num, kCFNumberFloatType, value); |
+ && CFNumberGetValue(num, kCFNumberCGFloatType, value); |
} |
-static int unit_weight_to_fontstyle(float unit) { |
- float value; |
- if (unit < 0) { |
- value = 100 + (1 + unit) * 300; |
- } else { |
- value = 400 + unit * 500; |
+template <typename S, typename D, typename C> struct LinearInterpolater { |
+ struct Mapping { |
+ S src_val; |
+ D dst_val; |
+ }; |
+ constexpr LinearInterpolater(Mapping const mapping[], int mappingCount) |
+ : fMapping(mapping), fMappingCount(mappingCount) {} |
+ |
+ static D map(S value, S src_min, S src_max, D dst_min, D dst_max) { |
+ SkASSERT(src_min < src_max); |
+ SkASSERT(dst_min <= dst_max); |
+ return C()(dst_min + (((value - src_min) * (dst_max - dst_min)) / (src_max - src_min))); |
} |
- return sk_float_round2int(value); |
-} |
-static int unit_width_to_fontstyle(float unit) { |
- float value; |
- if (unit < 0) { |
- value = 1 + (1 + unit) * 4; |
- } else { |
- value = 5 + unit * 4; |
+ int map(S val) const { |
+ // -Inf to [0] |
+ if (val < fMapping[0].src_val) { |
+ return fMapping[0].dst_val; |
+ } |
+ |
+ // Linear from [i] to [i+1] |
+ for (int i = 0; i < fMappingCount - 1; ++i) { |
+ if (val < fMapping[i+1].src_val) { |
+ return map(val, fMapping[i].src_val, fMapping[i+1].src_val, |
+ fMapping[i].dst_val, fMapping[i+1].dst_val); |
+ } |
+ } |
+ |
+ // From [n] to +Inf |
+ // if (fcweight < Inf) |
+ return fMapping[fMappingCount - 1].dst_val; |
} |
- return sk_float_round2int(value); |
+ |
+ Mapping const * fMapping; |
+ int fMappingCount; |
+}; |
+ |
+struct RoundCGFloatToInt { |
+ int operator()(CGFloat s) { return s + 0.5; } |
+}; |
+ |
+static int ct_weight_to_fontstyle(CGFloat cgWeight) { |
+ using Interpolator = LinearInterpolater<CGFloat, int, RoundCGFloatToInt>; |
+ |
+ // Values determined by creating font data with every weight, creating a CTFont, |
+ // and asking the CTFont for its weight. See TypefaceStyle test for basics. |
+ |
+ // Note that Mac supports the old OS2 version A so 0 through 10 are as if multiplied by 100. |
+ // However, on this end we can't tell. |
+ static constexpr Interpolator::Mapping weightMappings[] = { |
+ { -1.00, 0 }, |
+ { -0.70, 100 }, |
+ { -0.50, 200 }, |
+ { -0.23, 300 }, |
+ { 0.00, 400 }, |
+ { 0.20, 500 }, |
+ { 0.30, 600 }, |
+ { 0.40, 700 }, |
+ { 0.60, 800 }, |
+ { 0.80, 900 }, |
+ { 1.00, 1000 }, |
+ }; |
+ static constexpr Interpolator interpolater(weightMappings, SK_ARRAY_COUNT(weightMappings)); |
+ return interpolater.map(cgWeight); |
+} |
+ |
+static int ct_width_to_fontstyle(CGFloat cgWidth) { |
+ using Interpolator = LinearInterpolater<CGFloat, int, RoundCGFloatToInt>; |
+ |
+ // Values determined by creating font data with every width, creating a CTFont, |
+ // and asking the CTFont for its width. See TypefaceStyle test for basics. |
+ static constexpr Interpolator::Mapping widthMappings[] = { |
+ { -0.5, 0 }, |
+ { 0.5, 10 }, |
+ }; |
+ static constexpr Interpolator interpolater(widthMappings, SK_ARRAY_COUNT(widthMappings)); |
+ return interpolater.map(cgWidth); |
} |
static SkFontStyle fontstyle_from_descriptor(CTFontDescriptorRef desc) { |
@@ -404,19 +463,19 @@ static SkFontStyle fontstyle_from_descriptor(CTFontDescriptorRef desc) { |
return SkFontStyle(); |
} |
- float weight, width, slant; |
- if (!find_dict_float(dict, kCTFontWeightTrait, &weight)) { |
+ CGFloat weight, width, slant; |
+ if (!find_dict_CGFloat(dict, kCTFontWeightTrait, &weight)) { |
weight = 0; |
} |
- if (!find_dict_float(dict, kCTFontWidthTrait, &width)) { |
+ if (!find_dict_CGFloat(dict, kCTFontWidthTrait, &width)) { |
width = 0; |
} |
- if (!find_dict_float(dict, kCTFontSlantTrait, &slant)) { |
+ if (!find_dict_CGFloat(dict, kCTFontSlantTrait, &slant)) { |
slant = 0; |
} |
- return SkFontStyle(unit_weight_to_fontstyle(weight), |
- unit_width_to_fontstyle(width), |
+ return SkFontStyle(ct_weight_to_fontstyle(weight), |
+ ct_width_to_fontstyle(width), |
slant ? SkFontStyle::kItalic_Slant |
: SkFontStyle::kUpright_Slant); |
} |