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 22namespace { 23 24// Fontconfig is not threadsafe before 2.10.91. Before that, we lock with a global mutex. 25// See skia:1497 for background. 26SK_DECLARE_STATIC_MUTEX(gFCMutex); 27static bool gFCSafeToUse; 28 29struct 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 47private: 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. 55extern SkFontConfigInterface* SkFontHost_fontconfig_ref_global(); 56static SkFontConfigInterface* RefFCI() { 57 return SkFontHost_fontconfig_ref_global(); 58} 59 60// look for the last substring after a '/' and return that, or return null. 61static const char* find_just_name(const char* str) { 62 const char* last = strrchr(str, '/'); 63 return last ? last + 1 : NULL; 64} 65 66static bool is_lower(char c) { 67 return c >= 'a' && c <= 'z'; 68} 69 70static 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 79static 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 88static 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 106static bool match_name(FcPattern* pattern, const char family_name[]) { 107 return !strcasecmp(family_name, get_name(pattern, FC_FAMILY)); 108} 109 110static 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 140class SkFontStyleSet_FC : public SkFontStyleSet { 141public: 142 SkFontStyleSet_FC(FcPattern** matches, int count); 143 virtual ~SkFontStyleSet_FC(); 144 145 virtual int count() SK_OVERRIDE { return fRecCount; } 146 virtual void getStyle(int index, SkFontStyle*, SkString* style) SK_OVERRIDE; 147 virtual SkTypeface* createTypeface(int index) SK_OVERRIDE; 148 virtual SkTypeface* matchStyle(const SkFontStyle& pattern) SK_OVERRIDE; 149 150private: 151 struct Rec { 152 SkString fStyleName; 153 SkString fFileName; 154 SkFontStyle fStyle; 155 }; 156 Rec* fRecs; 157 int fRecCount; 158}; 159 160static 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 168static 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 181SkFontStyleSet_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 191SkFontStyleSet_FC::~SkFontStyleSet_FC() { 192 SkDELETE_ARRAY(fRecs); 193} 194 195void 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 206SkTypeface* SkFontStyleSet_FC::createTypeface(int index) { 207 return NULL; 208} 209 210SkTypeface* SkFontStyleSet_FC::matchStyle(const SkFontStyle& pattern) { 211 return NULL; 212} 213 214class SkFontMgr_fontconfig : public SkFontMgr { 215 SkAutoTUnref<SkFontConfigInterface> fFCI; 216 SkDataTable* fFamilyNames; 217 218 219public: 220 SkFontMgr_fontconfig(SkFontConfigInterface* fci) 221 : fFCI(fci) 222 , fFamilyNames(fFCI->getFamilyNames()) {} 223 224 virtual ~SkFontMgr_fontconfig() { 225 SkSafeUnref(fFamilyNames); 226 } 227 228protected: 229 virtual int onCountFamilies() const SK_OVERRIDE { 230 return fFamilyNames->count(); 231 } 232 233 virtual void onGetFamilyName(int index, SkString* familyName) const SK_OVERRIDE { 234 familyName->set(fFamilyNames->atStr(index)); 235 } 236 237 virtual SkFontStyleSet* onCreateStyleSet(int index) const SK_OVERRIDE { 238 return this->onMatchFamily(fFamilyNames->atStr(index)); 239 } 240 241 virtual SkFontStyleSet* onMatchFamily(const char familyName[]) const SK_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 virtual SkTypeface* onMatchFamilyStyle(const char familyName[], 287 const SkFontStyle&) const SK_OVERRIDE { return NULL; } 288 virtual SkTypeface* onMatchFaceStyle(const SkTypeface*, 289 const SkFontStyle&) const SK_OVERRIDE { return NULL; } 290 291 virtual SkTypeface* onCreateFromData(SkData*, int ttcIndex) const SK_OVERRIDE { return NULL; } 292 293 virtual SkTypeface* onCreateFromStream(SkStream* stream, int ttcIndex) const SK_OVERRIDE { 294 const size_t length = stream->getLength(); 295 if (!length) { 296 return NULL; 297 } 298 if (length >= 1024 * 1024 * 1024) { 299 return NULL; // don't accept too large fonts (>= 1GB) for safety. 300 } 301 302 // TODO should the caller give us the style or should we get it from freetype? 303 SkTypeface::Style style = SkTypeface::kNormal; 304 bool isFixedWidth = false; 305 if (!SkTypeface_FreeType::ScanFont(stream, 0, NULL, &style, &isFixedWidth)) { 306 return NULL; 307 } 308 309 SkTypeface* face = FontConfigTypeface::Create(style, isFixedWidth, stream); 310 return face; 311 } 312 313 virtual SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const SK_OVERRIDE { 314 SkAutoTUnref<SkStream> stream(SkStream::NewFromFile(path)); 315 return stream.get() ? this->createFromStream(stream, ttcIndex) : NULL; 316 } 317 318 virtual SkTypeface* onLegacyCreateTypeface(const char familyName[], 319 unsigned styleBits) const SK_OVERRIDE { 320 FCLocker lock; 321 return FontConfigTypeface::LegacyCreateTypeface(NULL, familyName, 322 (SkTypeface::Style)styleBits); 323 } 324}; 325 326SkFontMgr* SkFontMgr::Factory() { 327 SkFontConfigInterface* fci = RefFCI(); 328 return fci ? SkNEW_ARGS(SkFontMgr_fontconfig, (fci)) : NULL; 329} 330