Index: skia/ext/SkFontHost_fontconfig_direct.cpp |
diff --git a/skia/ext/SkFontHost_fontconfig_direct.cpp b/skia/ext/SkFontHost_fontconfig_direct.cpp |
index a055c2f6beeac89947fec792fbe66a7abaabb81b..549bb92e5a33ea3063b2445b91931932b0792236 100644 |
--- a/skia/ext/SkFontHost_fontconfig_direct.cpp |
+++ b/skia/ext/SkFontHost_fontconfig_direct.cpp |
@@ -27,6 +27,76 @@ FontConfigDirect::FontConfigDirect() |
FcInit(); |
} |
+bool FontConfigDirect::IsMetricCompatibleReplacement(const char* font_a, |
+ const char* font_b) |
+{ |
+ // It would be nice for fontconfig to tell us whether a given suggested |
+ // replacement is a "strong" match (that is, an equivalent font) or |
+ // a "weak" match (that is, fontconfig's next-best attempt at finding a |
+ // substitute). However, I played around with the fontconfig API for |
+ // a good few hours and could not make it reveal this information. |
+ // |
+ // So instead, we hardcode. These are from |
+ // /etc/fonts/conf.d/30-metric-aliases.conf on my Ubuntu Karmic |
+ // system. |
+ |
+ // We represent the data with a table. Two names with the same |
+ // id are in the same class. |
+ struct FontEquivClass { |
+ char id; |
+ const char name[20]; |
+ }; |
+ static const FontEquivClass kFontEquivClasses[] = { |
+ { 0, "Arial" }, |
+ { 0, "Liberation Sans" }, |
+ { 0, "Albany" }, |
+ { 0, "Albany Amt" }, |
+ |
+ { 1, "Times New Roman" }, |
+ { 1, "Liberation Serif" }, |
+ { 1, "Thorndale" }, |
+ { 1, "Thorndale AMT" }, |
+ |
+ // Note that Liberation Mono doesn't much *look* like Courier New, |
+ // but it's reportedly metric-compatible. |
+ { 2, "Courier New" }, |
+ { 2, "Liberation Mono" }, |
+ { 2, "Cumberland" }, |
+ { 2, "Cumberland AMT" }, |
+ |
+ { 3, "Helvetica" }, |
+ { 3, "Nimbus Sans L" }, |
+ |
+ { 4, "Times" }, |
+ { 4, "Nimbus Roman No9 L" }, |
+ |
+ { 5, "Courier" }, |
+ { 5, "Nimbus Mono L" }, |
+ }; |
+ static const int kClassCount = |
agl
2010/03/08 18:31:40
s/int/size_t/
|
+ sizeof(kFontEquivClasses)/sizeof(kFontEquivClasses[0]); |
+ |
+ int class_a = -1; |
+ for (size_t i = 0; i < kClassCount; ++i) { |
+ if (strcasecmp(kFontEquivClasses[i].name, font_a) == 0) { |
+ class_a = kFontEquivClasses[i].id; |
+ break; |
+ } |
+ } |
+ if (class_a == -1) |
+ return false; |
+ |
+ int class_b = -1; |
+ for (size_t i = 0; i < kClassCount; ++i) { |
+ if (strcasecmp(kFontEquivClasses[i].name, font_b) == 0) { |
+ class_b = kFontEquivClasses[i].id; |
+ break; |
+ } |
+ } |
+ |
+ return class_a == class_b; |
+} |
+ |
// ----------------------------------------------------------------------------- |
// Normally we only return exactly the font asked for. In last-resort cases, |
// the request is for one of the basic font names "Sans", "Serif" or |
@@ -54,7 +124,6 @@ bool FontConfigDirect::Match(std::string* result_family, |
SkAutoMutexAcquire ac(mutex_); |
FcPattern* pattern = FcPatternCreate(); |
- FcValue fcvalue; |
if (fileid_valid) { |
const std::map<unsigned, std::string>::const_iterator |
i = fileid_to_filename_.find(fileid); |
@@ -63,29 +132,21 @@ bool FontConfigDirect::Match(std::string* result_family, |
return false; |
} |
- fcvalue.type = FcTypeString; |
- fcvalue.u.s = (FcChar8*) i->second.c_str(); |
- FcPatternAdd(pattern, FC_FILE, fcvalue, 0); |
+ FcPatternAddString(pattern, FC_FILE, (FcChar8*) i->second.c_str()); |
} |
if (!family.empty()) { |
- fcvalue.type = FcTypeString; |
- fcvalue.u.s = (FcChar8*) family.c_str(); |
- FcPatternAdd(pattern, FC_FAMILY, fcvalue, 0); |
+ FcPatternAddString(pattern, FC_FAMILY, (FcChar8*) family.c_str()); |
} |
- fcvalue.type = FcTypeInteger; |
- fcvalue.u.i = is_bold && *is_bold ? FC_WEIGHT_BOLD : FC_WEIGHT_NORMAL; |
- FcPatternAdd(pattern, FC_WEIGHT, fcvalue, 0); |
- |
- fcvalue.type = FcTypeInteger; |
- fcvalue.u.i = is_italic && *is_italic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN; |
- FcPatternAdd(pattern, FC_SLANT, fcvalue, 0); |
- |
- fcvalue.type = FcTypeBool; |
- fcvalue.u.b = FcTrue; |
- FcPatternAdd(pattern, FC_SCALABLE, fcvalue, 0); |
+ FcPatternAddInteger(pattern, FC_WEIGHT, |
+ is_bold && *is_bold ? FC_WEIGHT_BOLD |
+ : FC_WEIGHT_NORMAL); |
+ FcPatternAddInteger(pattern, FC_SLANT, |
+ is_italic && *is_italic ? FC_SLANT_ITALIC |
+ : FC_SLANT_ROMAN); |
+ FcPatternAddBool(pattern, FC_SCALABLE, FcTrue); |
- FcConfigSubstitute(0, pattern, FcMatchPattern); |
+ FcConfigSubstitute(NULL, pattern, FcMatchPattern); |
FcDefaultSubstitute(pattern); |
// Font matching: |
@@ -158,13 +219,13 @@ bool FontConfigDirect::Match(std::string* result_family, |
} |
if (!IsFallbackFontAllowed(family)) { |
- bool family_names_match = false; |
+ bool acceptable_substitute = false; |
for (int id = 0; id < 255; ++id) { |
FcChar8* post_match_family; |
if (FcPatternGetString(match, FC_FAMILY, id, &post_match_family) != |
FcResultMatch) |
break; |
- family_names_match = |
+ acceptable_substitute = |
family.empty() ? |
true : |
(strcasecmp((char *)post_config_family, |
@@ -175,11 +236,13 @@ bool FontConfigDirect::Match(std::string* result_family, |
// post_match_family: "Bitstream Vera Sans" |
// -> We should treat this case as a good match. |
strcasecmp(family.c_str(), |
- (char *)post_match_family) == 0); |
- if (family_names_match) |
+ (char *)post_match_family) == 0) || |
+ IsMetricCompatibleReplacement(family.c_str(), |
+ (char*)post_match_family); |
+ if (acceptable_substitute) |
break; |
} |
- if (!family.empty() && !family_names_match) { |
+ if (!acceptable_substitute) { |
FcPatternDestroy(pattern); |
FcFontSetDestroy(font_set); |
return false; |