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