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