OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * Copyright 2013 Google Inc. |
| 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. |
| 6 */ |
| 7 |
| 8 #include "SkFontMgr.h" |
| 9 #include "SkFontStyle.h" |
| 10 #include "SkFontConfigInterface.h" |
| 11 #include "SkMath.h" |
| 12 #include "SkString.h" |
| 13 #include "SkTDArray.h" |
| 14 |
| 15 // for now we pull these in directly. eventually we will solely rely on the |
| 16 // SkFontConfigInterface instance. |
| 17 #include <fontconfig/fontconfig.h> |
| 18 #include <unistd.h> |
| 19 |
| 20 // borrow this global from SkFontHost_fontconfig. eventually that file should |
| 21 // go away, and be replaced with this one. |
| 22 extern SkFontConfigInterface* SkFontHost_fontconfig_ref_global(); |
| 23 static SkFontConfigInterface* RefFCI() { |
| 24 return SkFontHost_fontconfig_ref_global(); |
| 25 } |
| 26 |
| 27 // look for the last substring after a '/' and return that, or return null. |
| 28 static const char* find_just_name(const char* str) { |
| 29 const char* last = strrchr(str, '/'); |
| 30 return last ? last + 1 : NULL; |
| 31 } |
| 32 |
| 33 static bool is_lower(char c) { |
| 34 return c >= 'a' && c <= 'z'; |
| 35 } |
| 36 |
| 37 static int get_int(FcPattern* pattern, const char field[]) { |
| 38 int value; |
| 39 if (FcPatternGetInteger(pattern, field, 0, &value) != FcResultMatch) { |
| 40 value = SK_MinS32; |
| 41 } |
| 42 return value; |
| 43 } |
| 44 |
| 45 static const char* get_name(FcPattern* pattern, const char field[]) { |
| 46 const char* name; |
| 47 if (FcPatternGetString(pattern, field, 0, (FcChar8**)&name) != FcResultMatch
) { |
| 48 name = ""; |
| 49 } |
| 50 return name; |
| 51 } |
| 52 |
| 53 static bool valid_pattern(FcPattern* pattern) { |
| 54 FcBool is_scalable; |
| 55 if (FcPatternGetBool(pattern, FC_SCALABLE, 0, &is_scalable) != FcResultMatch
|| !is_scalable) { |
| 56 return false; |
| 57 } |
| 58 |
| 59 // fontconfig can also return fonts which are unreadable |
| 60 const char* c_filename = get_name(pattern, FC_FILE); |
| 61 if (0 == *c_filename) { |
| 62 return false; |
| 63 } |
| 64 if (access(c_filename, R_OK) != 0) { |
| 65 return false; |
| 66 } |
| 67 return true; |
| 68 } |
| 69 |
| 70 static bool match_name(FcPattern* pattern, const char family_name[]) { |
| 71 return !strcasecmp(family_name, get_name(pattern, FC_FAMILY)); |
| 72 } |
| 73 |
| 74 static FcPattern** MatchFont(FcFontSet* font_set, |
| 75 const char post_config_family[], |
| 76 int* count) { |
| 77 // Older versions of fontconfig have a bug where they cannot select |
| 78 // only scalable fonts so we have to manually filter the results. |
| 79 |
| 80 FcPattern** iter = font_set->fonts; |
| 81 FcPattern** stop = iter + font_set->nfont; |
| 82 // find the first good match |
| 83 for (; iter < stop; ++iter) { |
| 84 if (valid_pattern(*iter)) { |
| 85 break; |
| 86 } |
| 87 } |
| 88 |
| 89 if (iter == stop || !match_name(*iter, post_config_family)) { |
| 90 return NULL; |
| 91 } |
| 92 |
| 93 FcPattern** firstIter = iter++; |
| 94 for (; iter < stop; ++iter) { |
| 95 if (!valid_pattern(*iter) || !match_name(*iter, post_config_family)) { |
| 96 break; |
| 97 } |
| 98 } |
| 99 |
| 100 *count = iter - firstIter; |
| 101 return firstIter; |
| 102 } |
| 103 |
| 104 class SkFontStyleSet_FC : public SkFontStyleSet { |
| 105 public: |
| 106 SkFontStyleSet_FC(FcPattern** matches, int count); |
| 107 virtual ~SkFontStyleSet_FC(); |
| 108 |
| 109 virtual int count() SK_OVERRIDE { return fRecCount; } |
| 110 virtual void getStyle(int index, SkFontStyle*, SkString* style) SK_OVERRIDE; |
| 111 virtual SkTypeface* createTypeface(int index) SK_OVERRIDE; |
| 112 virtual SkTypeface* matchStyle(const SkFontStyle& pattern) SK_OVERRIDE; |
| 113 |
| 114 private: |
| 115 struct Rec { |
| 116 SkString fStyleName; |
| 117 SkString fFileName; |
| 118 SkFontStyle fStyle; |
| 119 }; |
| 120 Rec* fRecs; |
| 121 int fRecCount; |
| 122 }; |
| 123 |
| 124 static int map_range(int value, |
| 125 int old_min, int old_max, int new_min, int new_max) { |
| 126 SkASSERT(old_min < old_max); |
| 127 SkASSERT(new_min < new_max); |
| 128 return new_min + SkMulDiv(value - old_min, |
| 129 new_max - new_min, old_max - old_min); |
| 130 } |
| 131 |
| 132 static SkFontStyle make_fontconfig_style(FcPattern* match) { |
| 133 int weight = get_int(match, FC_WEIGHT); |
| 134 int width = get_int(match, FC_WIDTH); |
| 135 int slant = get_int(match, FC_SLANT); |
| 136 // SkDebugf("old weight %d new weight %d\n", weight, map_range(weight, 0, 80,
0, 400)); |
| 137 |
| 138 // fontconfig weight seems to be 0..200 or so, so we remap it here |
| 139 weight = map_range(weight, 0, 80, 0, 400); |
| 140 width = map_range(width, 0, 200, 0, 9); |
| 141 return SkFontStyle(weight, width, slant > 0 ? SkFontStyle::kItalic_Slant |
| 142 : SkFontStyle::kUpright_Slant); |
| 143 } |
| 144 |
| 145 SkFontStyleSet_FC::SkFontStyleSet_FC(FcPattern** matches, int count) { |
| 146 fRecCount = count; |
| 147 fRecs = SkNEW_ARRAY(Rec, count); |
| 148 for (int i = 0; i < count; ++i) { |
| 149 fRecs[i].fStyleName.set(get_name(matches[i], FC_STYLE)); |
| 150 fRecs[i].fFileName.set(get_name(matches[i], FC_FILE)); |
| 151 fRecs[i].fStyle = make_fontconfig_style(matches[i]); |
| 152 } |
| 153 } |
| 154 |
| 155 SkFontStyleSet_FC::~SkFontStyleSet_FC() { |
| 156 SkDELETE_ARRAY(fRecs); |
| 157 } |
| 158 |
| 159 void SkFontStyleSet_FC::getStyle(int index, SkFontStyle* style, |
| 160 SkString* styleName) { |
| 161 SkASSERT((unsigned)index < (unsigned)fRecCount); |
| 162 if (style) { |
| 163 *style = fRecs[index].fStyle; |
| 164 } |
| 165 if (styleName) { |
| 166 *styleName = fRecs[index].fStyleName; |
| 167 } |
| 168 } |
| 169 |
| 170 SkTypeface* SkFontStyleSet_FC::createTypeface(int index) { |
| 171 return NULL; |
| 172 } |
| 173 |
| 174 SkTypeface* SkFontStyleSet_FC::matchStyle(const SkFontStyle& pattern) { |
| 175 return NULL; |
| 176 } |
| 177 |
| 178 class SkFontMgr_fontconfig : public SkFontMgr { |
| 179 SkAutoTUnref<SkFontConfigInterface> fFCI; |
| 180 SkDataTable* fFamilyNames; |
| 181 |
| 182 void init() { |
| 183 if (!fFamilyNames) { |
| 184 fFamilyNames = fFCI->getFamilyNames(); |
| 185 } |
| 186 } |
| 187 |
| 188 public: |
| 189 SkFontMgr_fontconfig(SkFontConfigInterface* fci) |
| 190 : fFCI(fci) |
| 191 , fFamilyNames(NULL) {} |
| 192 |
| 193 virtual ~SkFontMgr_fontconfig() { |
| 194 SkSafeUnref(fFamilyNames); |
| 195 } |
| 196 |
| 197 protected: |
| 198 virtual int onCountFamilies() { |
| 199 this->init(); |
| 200 return fFamilyNames->count(); |
| 201 } |
| 202 |
| 203 virtual void onGetFamilyName(int index, SkString* familyName) { |
| 204 this->init(); |
| 205 familyName->set(fFamilyNames->atStr(index)); |
| 206 } |
| 207 |
| 208 virtual SkFontStyleSet* onCreateStyleSet(int index) { |
| 209 this->init(); |
| 210 return this->onMatchFamily(fFamilyNames->atStr(index)); |
| 211 } |
| 212 |
| 213 virtual SkFontStyleSet* onMatchFamily(const char familyName[]) { |
| 214 this->init(); |
| 215 |
| 216 FcPattern* pattern = FcPatternCreate(); |
| 217 |
| 218 FcPatternAddString(pattern, FC_FAMILY, (FcChar8*)familyName); |
| 219 #if 0 |
| 220 FcPatternAddBool(pattern, FC_SCALABLE, FcTrue); |
| 221 #endif |
| 222 FcConfigSubstitute(NULL, pattern, FcMatchPattern); |
| 223 FcDefaultSubstitute(pattern); |
| 224 |
| 225 const char* post_config_family = get_name(pattern, FC_FAMILY); |
| 226 |
| 227 FcResult result; |
| 228 FcFontSet* font_set = FcFontSort(0, pattern, 0, 0, &result); |
| 229 if (!font_set) { |
| 230 FcPatternDestroy(pattern); |
| 231 return NULL; |
| 232 } |
| 233 |
| 234 int count; |
| 235 FcPattern** match = MatchFont(font_set, post_config_family, &count); |
| 236 if (!match) { |
| 237 FcPatternDestroy(pattern); |
| 238 FcFontSetDestroy(font_set); |
| 239 return NULL; |
| 240 } |
| 241 |
| 242 FcPatternDestroy(pattern); |
| 243 |
| 244 SkTDArray<FcPattern*> trimmedMatches; |
| 245 for (int i = 0; i < count; ++i) { |
| 246 const char* justName = find_just_name(get_name(match[i], FC_FILE)); |
| 247 if (!is_lower(*justName)) { |
| 248 *trimmedMatches.append() = match[i]; |
| 249 } |
| 250 } |
| 251 |
| 252 SkFontStyleSet_FC* sset = SkNEW_ARGS(SkFontStyleSet_FC, |
| 253 (trimmedMatches.begin(), |
| 254 trimmedMatches.count())); |
| 255 return sset; |
| 256 } |
| 257 |
| 258 virtual SkTypeface* onMatchFamilyStyle(const char familyName[], |
| 259 const SkFontStyle&) { return NULL; } |
| 260 virtual SkTypeface* onMatchFaceStyle(const SkTypeface*, |
| 261 const SkFontStyle&) { return NULL; } |
| 262 |
| 263 virtual SkTypeface* onCreateFromData(SkData*, int ttcIndex) { return NULL; } |
| 264 virtual SkTypeface* onCreateFromStream(SkStream*, int ttcIndex) { |
| 265 return NULL; |
| 266 } |
| 267 virtual SkTypeface* onCreateFromFile(const char path[], int ttcIndex) { |
| 268 return NULL; |
| 269 } |
| 270 }; |
| 271 |
| 272 SkFontMgr* SkFontMgr::Factory() { |
| 273 SkFontConfigInterface* fci = RefFCI(); |
| 274 return fci ? SkNEW_ARGS(SkFontMgr_fontconfig, (fci)) : NULL; |
| 275 } |
| 276 |
OLD | NEW |