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