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 "SkFontConfigInterface.h" 9#include "SkFontConfigTypeface.h" 10#include "SkFontMgr.h" 11#include "SkFontStyle.h" 12#include "SkMath.h" 13#include "SkMutex.h" 14#include "SkString.h" 15#include "SkTDArray.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 : nullptr; 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 nullptr; 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 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 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 = new 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() { delete[] fRecs; } 192 193void SkFontStyleSet_FC::getStyle(int index, SkFontStyle* style, 194 SkString* styleName) { 195 SkASSERT((unsigned)index < (unsigned)fRecCount); 196 if (style) { 197 *style = fRecs[index].fStyle; 198 } 199 if (styleName) { 200 *styleName = fRecs[index].fStyleName; 201 } 202} 203 204SkTypeface* SkFontStyleSet_FC::createTypeface(int index) { 205 return nullptr; 206} 207 208SkTypeface* SkFontStyleSet_FC::matchStyle(const SkFontStyle& pattern) { 209 return nullptr; 210} 211 212class SkFontMgr_fontconfig : public SkFontMgr { 213 SkAutoTUnref<SkFontConfigInterface> fFCI; 214 SkDataTable* fFamilyNames; 215 SkTypeface_FreeType::Scanner fScanner; 216 217public: 218 SkFontMgr_fontconfig(SkFontConfigInterface* fci) 219 : fFCI(fci) 220 , fFamilyNames(fFCI->getFamilyNames()) {} 221 222 virtual ~SkFontMgr_fontconfig() { 223 SkSafeUnref(fFamilyNames); 224 } 225 226protected: 227 int onCountFamilies() const override { 228 return fFamilyNames->count(); 229 } 230 231 void onGetFamilyName(int index, SkString* familyName) const override { 232 familyName->set(fFamilyNames->atStr(index)); 233 } 234 235 SkFontStyleSet* onCreateStyleSet(int index) const override { 236 return this->onMatchFamily(fFamilyNames->atStr(index)); 237 } 238 239 SkFontStyleSet* onMatchFamily(const char familyName[]) const override { 240 FCLocker lock; 241 242 FcPattern* pattern = FcPatternCreate(); 243 244 FcPatternAddString(pattern, FC_FAMILY, (FcChar8*)familyName); 245#if 0 246 FcPatternAddBool(pattern, FC_SCALABLE, FcTrue); 247#endif 248 FcConfigSubstitute(nullptr, pattern, FcMatchPattern); 249 FcDefaultSubstitute(pattern); 250 251 const char* post_config_family = get_name(pattern, FC_FAMILY); 252 253 FcResult result; 254 FcFontSet* font_set = FcFontSort(0, pattern, 0, 0, &result); 255 if (!font_set) { 256 FcPatternDestroy(pattern); 257 return nullptr; 258 } 259 260 int count; 261 FcPattern** match = MatchFont(font_set, post_config_family, &count); 262 if (!match) { 263 FcPatternDestroy(pattern); 264 FcFontSetDestroy(font_set); 265 return nullptr; 266 } 267 268 FcPatternDestroy(pattern); 269 270 SkTDArray<FcPattern*> trimmedMatches; 271 for (int i = 0; i < count; ++i) { 272 const char* justName = find_just_name(get_name(match[i], FC_FILE)); 273 if (!is_lower(*justName)) { 274 *trimmedMatches.append() = match[i]; 275 } 276 } 277 278 SkFontStyleSet_FC* sset = 279 new SkFontStyleSet_FC(trimmedMatches.begin(), trimmedMatches.count()); 280 return sset; 281 } 282 283 SkTypeface* onMatchFamilyStyle(const char familyName[], 284 const SkFontStyle&) const override { return nullptr; } 285 SkTypeface* onMatchFamilyStyleCharacter(const char familyName[], const SkFontStyle&, 286 const char* bcp47[], int bcp47Count, 287 SkUnichar character) const override { 288 return nullptr; 289 } 290 SkTypeface* onMatchFaceStyle(const SkTypeface*, 291 const SkFontStyle&) const override { return nullptr; } 292 293 SkTypeface* onCreateFromData(SkData*, int ttcIndex) const override { return nullptr; } 294 295 SkTypeface* onCreateFromStream(SkStreamAsset* bareStream, int ttcIndex) const override { 296 SkAutoTDelete<SkStreamAsset> stream(bareStream); 297 const size_t length = stream->getLength(); 298 if (!length) { 299 return nullptr; 300 } 301 if (length >= 1024 * 1024 * 1024) { 302 return nullptr; // don't accept too large fonts (>= 1GB) for safety. 303 } 304 305 // TODO should the caller give us the style or should we get it from freetype? 306 SkFontStyle style; 307 bool isFixedWidth = false; 308 if (!fScanner.scanFont(stream, 0, nullptr, &style, &isFixedWidth, nullptr)) { 309 return nullptr; 310 } 311 312 SkTypeface* face = FontConfigTypeface::Create(style, isFixedWidth, stream.detach()); 313 return face; 314 } 315 316 SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const override { 317 SkAutoTDelete<SkStreamAsset> stream(SkStream::NewFromFile(path)); 318 return stream.get() ? this->createFromStream(stream.detach(), ttcIndex) : nullptr; 319 } 320 321 SkTypeface* onLegacyCreateTypeface(const char familyName[], 322 unsigned styleBits) const override { 323 FCLocker lock; 324 return FontConfigTypeface::LegacyCreateTypeface(familyName, (SkTypeface::Style)styleBits); 325 } 326}; 327 328SkFontMgr* SkFontMgr::Factory() { 329 SkFontConfigInterface* fci = RefFCI(); 330 return fci ? new SkFontMgr_fontconfig(fci) : nullptr; 331} 332