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