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