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