Home | History | Annotate | Download | only in linux
      1 /*
      2  * Copyright (C) 2009 Google Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions are
      6  * met:
      7  *
      8  *     * Redistributions of source code must retain the above copyright
      9  * notice, this list of conditions and the following disclaimer.
     10  *     * Redistributions in binary form must reproduce the above
     11  * copyright notice, this list of conditions and the following disclaimer
     12  * in the documentation and/or other materials provided with the
     13  * distribution.
     14  *     * Neither the name of Google Inc. nor the names of its
     15  * contributors may be used to endorse or promote products derived from
     16  * this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 #include "config.h"
     32 #include "public/platform/linux/WebFontInfo.h"
     33 
     34 #include "public/platform/linux/WebFallbackFont.h"
     35 #include "wtf/HashMap.h"
     36 #include "wtf/Noncopyable.h"
     37 #include "wtf/OwnPtr.h"
     38 #include "wtf/PassOwnPtr.h"
     39 #include "wtf/Vector.h"
     40 #include "wtf/text/AtomicString.h"
     41 #include "wtf/text/AtomicStringHash.h"
     42 #include <fontconfig/fontconfig.h>
     43 #include <string.h>
     44 #include <unicode/utf16.h>
     45 
     46 namespace blink {
     47 
     48 class CachedFont {
     49 public:
     50     // Note: We pass the charset explicitly as callers
     51     // should not create CachedFont entries without knowing
     52     // that the FcPattern contains a valid charset.
     53     CachedFont(FcPattern* pattern, FcCharSet* charSet)
     54         : m_supportedCharacters(charSet)
     55     {
     56         ASSERT(pattern);
     57         ASSERT(charSet);
     58         m_fallbackFont.name = fontName(pattern);
     59         m_fallbackFont.filename = fontFilename(pattern);
     60         m_fallbackFont.ttcIndex = fontTtcIndex(pattern);
     61         m_fallbackFont.isBold = fontIsBold(pattern);
     62         m_fallbackFont.isItalic = fontIsItalic(pattern);
     63     }
     64     const WebFallbackFont& fallbackFont() const { return m_fallbackFont; }
     65     bool hasGlyphForCharacter(WebUChar32 c)
     66     {
     67         return m_supportedCharacters && FcCharSetHasChar(m_supportedCharacters, c);
     68     }
     69 
     70 private:
     71     static WebCString fontName(FcPattern* pattern)
     72     {
     73         FcChar8* familyName = nullptr;
     74         if (FcPatternGetString(pattern, FC_FAMILY, 0, &familyName) != FcResultMatch)
     75             return WebCString();
     76 
     77         // FCChar8 is unsigned char, so we cast to char for WebCString.
     78         const char* charFamily = reinterpret_cast<char*>(familyName);
     79         return WebCString(charFamily, strlen(charFamily));
     80     }
     81 
     82     static WebCString fontFilename(FcPattern* pattern)
     83     {
     84         FcChar8* cFilename = nullptr;
     85         if (FcPatternGetString(pattern, FC_FILE, 0, &cFilename) != FcResultMatch)
     86             return WebCString();
     87         const char* fontFilename = reinterpret_cast<char*>(cFilename);
     88         return WebCString(fontFilename, strlen(fontFilename));
     89     }
     90 
     91     static int fontTtcIndex(FcPattern* pattern)
     92     {
     93         int ttcIndex = -1;
     94         if (FcPatternGetInteger(pattern, FC_INDEX, 0, &ttcIndex) != FcResultMatch || ttcIndex < 0)
     95             return 0;
     96         return ttcIndex;
     97     }
     98 
     99     static bool fontIsBold(FcPattern* pattern)
    100     {
    101         int weight = 0;
    102         if (FcPatternGetInteger(pattern, FC_WEIGHT, 0, &weight) != FcResultMatch)
    103             return false;
    104         return weight >= FC_WEIGHT_BOLD;
    105     }
    106 
    107     static bool fontIsItalic(FcPattern* pattern)
    108     {
    109         int slant = 0;
    110         if (FcPatternGetInteger(pattern, FC_SLANT, 0, &slant) != FcResultMatch)
    111             return false;
    112         return slant != FC_SLANT_ROMAN;
    113     }
    114 
    115     WebFallbackFont m_fallbackFont;
    116     // m_supportedCharaters is owned by the parent
    117     // FcFontSet and should never be freed.
    118     FcCharSet* m_supportedCharacters;
    119 };
    120 
    121 
    122 class CachedFontSet {
    123     WTF_MAKE_NONCOPYABLE(CachedFontSet);
    124 public:
    125     // CachedFontSet takes ownership of the passed FcFontSet.
    126     static PassOwnPtr<CachedFontSet> createForLocale(const char* locale)
    127     {
    128         FcFontSet* fontSet = createFcFontSetForLocale(locale);
    129         return adoptPtr(new CachedFontSet(fontSet));
    130     }
    131 
    132     ~CachedFontSet()
    133     {
    134         m_fallbackList.clear();
    135         FcFontSetDestroy(m_fontSet);
    136     }
    137 
    138     WebFallbackFont fallbackFontForChar(WebUChar32 c)
    139     {
    140         Vector<CachedFont>::iterator itr = m_fallbackList.begin();
    141         for (; itr != m_fallbackList.end(); itr++) {
    142             if (itr->hasGlyphForCharacter(c))
    143                 return itr->fallbackFont();
    144         }
    145         // The previous code just returned garbage if the user didn't
    146         // have the necessary fonts, this seems better than garbage.
    147         // Current callers happen to ignore any values with an empty family string.
    148         return WebFallbackFont();
    149     }
    150 
    151 private:
    152     static FcFontSet* createFcFontSetForLocale(const char* locale)
    153     {
    154         FcPattern* pattern = FcPatternCreate();
    155 
    156         if (locale) {
    157             // FcChar* is unsigned char* so we have to cast.
    158             FcPatternAddString(pattern, FC_LANG, reinterpret_cast<const FcChar8*>(locale));
    159         }
    160 
    161         FcValue fcvalue;
    162         fcvalue.type = FcTypeBool;
    163         fcvalue.u.b = FcTrue;
    164         FcPatternAdd(pattern, FC_SCALABLE, fcvalue, FcFalse);
    165 
    166         FcConfigSubstitute(0, pattern, FcMatchPattern);
    167         FcDefaultSubstitute(pattern);
    168 
    169         if (!locale)
    170             FcPatternDel(pattern, FC_LANG);
    171 
    172         // The result parameter returns if any fonts were found.
    173         // We already handle 0 fonts correctly, so we ignore the param.
    174         FcResult result;
    175         FcFontSet* fontSet = FcFontSort(0, pattern, 0, 0, &result);
    176         FcPatternDestroy(pattern);
    177 
    178         // The caller will take ownership of this FcFontSet.
    179         return fontSet;
    180     }
    181 
    182     CachedFontSet(FcFontSet* fontSet)
    183         : m_fontSet(fontSet)
    184     {
    185         fillFallbackList();
    186     }
    187 
    188     void fillFallbackList()
    189     {
    190         ASSERT(m_fallbackList.isEmpty());
    191         if (!m_fontSet)
    192             return;
    193 
    194         for (int i = 0; i < m_fontSet->nfont; ++i) {
    195             FcPattern* pattern = m_fontSet->fonts[i];
    196 
    197             // Ignore any bitmap fonts users may still have installed from last century.
    198             FcBool isScalable;
    199             if (FcPatternGetBool(pattern, FC_SCALABLE, 0, &isScalable) != FcResultMatch || !isScalable)
    200                 continue;
    201 
    202             // Ignore any fonts FontConfig knows about, but that we don't have permission to read.
    203             FcChar8* cFilename;
    204             if (FcPatternGetString(pattern, FC_FILE, 0, &cFilename) != FcResultMatch)
    205                 continue;
    206             if (access(reinterpret_cast<char*>(cFilename), R_OK))
    207                 continue;
    208 
    209             // Make sure this font can tell us what characters it has glyphs for.
    210             FcCharSet* charSet;
    211             if (FcPatternGetCharSet(pattern, FC_CHARSET, 0, &charSet) != FcResultMatch)
    212                 continue;
    213 
    214             m_fallbackList.append(CachedFont(pattern, charSet));
    215         }
    216     }
    217 
    218     FcFontSet* m_fontSet; // Owned by this object.
    219     // CachedFont has a FcCharset* which points into the FcFontSet.
    220     // If the FcFontSet is ever destroyed, the fallbackList
    221     // must be cleared first.
    222     Vector<CachedFont> m_fallbackList;
    223 };
    224 
    225 class FontSetCache {
    226 public:
    227     static FontSetCache& shared()
    228     {
    229         DEFINE_STATIC_LOCAL(FontSetCache, cache, ());
    230         return cache;
    231     }
    232 
    233     WebFallbackFont fallbackFontForCharInLocale(WebUChar32 c, const char* locale)
    234     {
    235         DEFINE_STATIC_LOCAL(AtomicString, kNoLocale, ("NO_LOCALE_SPECIFIED", AtomicString::ConstructFromLiteral));
    236         AtomicString localeKey;
    237         if (locale && strlen(locale)) {
    238             localeKey = AtomicString(locale);
    239         } else {
    240             // String hash computation the m_setsByLocale map needs
    241             // a non-empty string.
    242             localeKey = kNoLocale;
    243         }
    244 
    245         LocaleToCachedFont::iterator itr = m_setsByLocale.find(localeKey);
    246         if (itr == m_setsByLocale.end()) {
    247             OwnPtr<CachedFontSet> newEntry = CachedFontSet::createForLocale(strlen(locale) ? locale : 0);
    248             return m_setsByLocale.add(localeKey, newEntry.release()).storedValue->value->fallbackFontForChar(c);
    249         }
    250         return itr.get()->value->fallbackFontForChar(c);
    251     }
    252     // FIXME: We may wish to add a way to prune the cache at a later time.
    253 
    254 private:
    255     // FIXME: This shouldn't need to be AtomicString, but
    256     // currently HashTraits<const char*> isn't smart enough
    257     // to hash the string (only does pointer compares).
    258     typedef HashMap<AtomicString, OwnPtr<CachedFontSet> > LocaleToCachedFont;
    259     LocaleToCachedFont m_setsByLocale;
    260 };
    261 
    262 void WebFontInfo::fallbackFontForChar(WebUChar32 c, const char* locale, WebFallbackFont* fallbackFont)
    263 {
    264     *fallbackFont = FontSetCache::shared().fallbackFontForCharInLocale(c, locale);
    265 }
    266 
    267 } // namespace blink
    268