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 22bool 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. 27extern SkFontConfigInterface* SkFontHost_fontconfig_ref_global(); 28static SkFontConfigInterface* RefFCI() { 29 return SkFontHost_fontconfig_ref_global(); 30} 31 32// look for the last substring after a '/' and return that, or return null. 33static const char* find_just_name(const char* str) { 34 const char* last = strrchr(str, '/'); 35 return last ? last + 1 : NULL; 36} 37 38static bool is_lower(char c) { 39 return c >= 'a' && c <= 'z'; 40} 41 42static 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 50static 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 58static 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 75static bool match_name(FcPattern* pattern, const char family_name[]) { 76 return !strcasecmp(family_name, get_name(pattern, FC_FAMILY)); 77} 78 79static 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 109class SkFontStyleSet_FC : public SkFontStyleSet { 110public: 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 119private: 120 struct Rec { 121 SkString fStyleName; 122 SkString fFileName; 123 SkFontStyle fStyle; 124 }; 125 Rec* fRecs; 126 int fRecCount; 127}; 128 129static 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 137static 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 150SkFontStyleSet_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 160SkFontStyleSet_FC::~SkFontStyleSet_FC() { 161 SkDELETE_ARRAY(fRecs); 162} 163 164void 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 175SkTypeface* SkFontStyleSet_FC::createTypeface(int index) { 176 return NULL; 177} 178 179SkTypeface* SkFontStyleSet_FC::matchStyle(const SkFontStyle& pattern) { 180 return NULL; 181} 182 183class 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 193public: 194 SkFontMgr_fontconfig(SkFontConfigInterface* fci) 195 : fFCI(fci) 196 , fFamilyNames(NULL) {} 197 198 virtual ~SkFontMgr_fontconfig() { 199 SkSafeUnref(fFamilyNames); 200 } 201 202protected: 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 302SkFontMgr* SkFontMgr::Factory() { 303 SkFontConfigInterface* fci = RefFCI(); 304 return fci ? SkNEW_ARGS(SkFontMgr_fontconfig, (fci)) : NULL; 305} 306