Home | History | Annotate | Download | only in ports
      1 /*
      2  * Copyright 2008 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 "SkFontDescriptor.h"
     11 #include "SkStream.h"
     12 #include "SkTemplates.h"
     13 #include "SkTypeface.h"
     14 #include "SkTypefaceCache.h"
     15 #include "SkResourceCache.h"
     16 
     17 ///////////////////////////////////////////////////////////////////////////////
     18 ///////////////////////////////////////////////////////////////////////////////
     19 
     20 SK_DECLARE_STATIC_MUTEX(gFontConfigInterfaceMutex);
     21 static SkFontConfigInterface* gFontConfigInterface;
     22 
     23 SkFontConfigInterface* SkFontConfigInterface::RefGlobal() {
     24     SkAutoMutexAcquire ac(gFontConfigInterfaceMutex);
     25 
     26     return SkSafeRef(gFontConfigInterface);
     27 }
     28 
     29 SkFontConfigInterface* SkFontConfigInterface::SetGlobal(SkFontConfigInterface* fc) {
     30     SkAutoMutexAcquire ac(gFontConfigInterfaceMutex);
     31 
     32     SkRefCnt_SafeAssign(gFontConfigInterface, fc);
     33     return fc;
     34 }
     35 
     36 ///////////////////////////////////////////////////////////////////////////////
     37 ///////////////////////////////////////////////////////////////////////////////
     38 
     39 // convenience function to create the direct interface if none is installed.
     40 extern SkFontConfigInterface* SkCreateDirectFontConfigInterface();
     41 
     42 static SkFontConfigInterface* RefFCI() {
     43     for (;;) {
     44         SkFontConfigInterface* fci = SkFontConfigInterface::RefGlobal();
     45         if (fci) {
     46             return fci;
     47         }
     48         fci = SkFontConfigInterface::GetSingletonDirectInterface(&gFontConfigInterfaceMutex);
     49         SkFontConfigInterface::SetGlobal(fci);
     50     }
     51 }
     52 
     53 // export this to SkFontMgr_fontconfig.cpp until this file just goes away.
     54 SkFontConfigInterface* SkFontHost_fontconfig_ref_global();
     55 SkFontConfigInterface* SkFontHost_fontconfig_ref_global() {
     56     return RefFCI();
     57 }
     58 
     59 ///////////////////////////////////////////////////////////////////////////////
     60 
     61 static bool find_by_FontIdentity(SkTypeface* cachedTypeface, const SkFontStyle&, void* ctx) {
     62     typedef SkFontConfigInterface::FontIdentity FontIdentity;
     63     FontConfigTypeface* cachedFCTypeface = static_cast<FontConfigTypeface*>(cachedTypeface);
     64     FontIdentity* identity = static_cast<FontIdentity*>(ctx);
     65 
     66     return cachedFCTypeface->getIdentity() == *identity;
     67 }
     68 
     69 SK_DECLARE_STATIC_MUTEX(gSkFontHostRequestCacheMutex);
     70 class SkFontHostRequestCache {
     71 
     72     // The value of maxSize here is a compromise between cache hits and cache size.
     73     static const size_t gMaxSize = 1 << 12;
     74 
     75     static SkFontHostRequestCache& Get() {
     76         gSkFontHostRequestCacheMutex.assertHeld();
     77         static SkFontHostRequestCache gCache(gMaxSize);
     78         return gCache;
     79     }
     80 
     81 public:
     82     struct Request : public SkResourceCache::Key {
     83     private:
     84         Request(const char* name, size_t nameLen, const SkFontStyle& style) : fStyle(style) {
     85             /** Pointer to just after the last field of this class. */
     86             char* content = const_cast<char*>(SkTAfter<const char>(&this->fStyle));
     87 
     88             // No holes.
     89             SkASSERT(SkTAddOffset<char>(this, sizeof(SkResourceCache::Key) + keySize) == content);
     90 
     91             // Has a size divisible by size of uint32_t.
     92             SkASSERT((content - reinterpret_cast<char*>(this)) % sizeof(uint32_t) == 0);
     93 
     94             size_t contentLen = SkAlign4(nameLen);
     95             sk_careful_memcpy(content, name, nameLen);
     96             sk_bzero(content + nameLen, contentLen - nameLen);
     97             this->init(&gSkFontHostRequestCacheMutex, 0, keySize + contentLen);
     98         }
     99         const SkFontStyle fStyle;
    100         /** The sum of the sizes of the fields of this class. */
    101         static const size_t keySize = sizeof(fStyle);
    102 
    103     public:
    104         static Request* Create(const char* name, const SkFontStyle& style) {
    105             size_t nameLen = name ? strlen(name) : 0;
    106             size_t contentLen = SkAlign4(nameLen);
    107             char* storage = new char[sizeof(Request) + contentLen];
    108             return new (storage) Request(name, nameLen, style);
    109         }
    110         void operator delete(void* storage) {
    111             delete[] reinterpret_cast<char*>(storage);
    112         }
    113     };
    114 
    115 
    116 private:
    117     struct Result : public SkResourceCache::Rec {
    118         Result(Request* request, SkTypeface* typeface)
    119             : fRequest(request)
    120             , fFace(SkSafeRef(typeface)) {}
    121         Result(Result&&) = default;
    122         Result& operator=(Result&&) = default;
    123 
    124         const Key& getKey() const override { return *fRequest; }
    125         size_t bytesUsed() const override { return fRequest->size() + sizeof(fFace); }
    126         const char* getCategory() const override { return "request_cache"; }
    127         SkDiscardableMemory* diagnostic_only_getDiscardable() const override { return nullptr; }
    128 
    129         SkAutoTDelete<Request> fRequest;
    130         SkAutoTUnref<SkTypeface> fFace;
    131     };
    132 
    133     SkResourceCache fCachedResults;
    134 
    135 public:
    136     SkFontHostRequestCache(size_t maxSize) : fCachedResults(maxSize) {}
    137 
    138     /** Takes ownership of request. It will be deleted when no longer needed. */
    139     void add(SkTypeface* face, Request* request) {
    140         fCachedResults.add(new Result(request, face));
    141     }
    142     /** Does not take ownership of request. */
    143     SkTypeface* findAndRef(Request* request) {
    144         SkTypeface* face = nullptr;
    145         fCachedResults.find(*request, [](const SkResourceCache::Rec& rec, void* context) -> bool {
    146             const Result& result = static_cast<const Result&>(rec);
    147             SkTypeface** face = static_cast<SkTypeface**>(context);
    148 
    149             *face = result.fFace;
    150             return true;
    151         }, &face);
    152         return SkSafeRef(face);
    153     }
    154 
    155     /** Takes ownership of request. It will be deleted when no longer needed. */
    156     static void Add(SkTypeface* face, Request* request) {
    157         SkAutoMutexAcquire ama(gSkFontHostRequestCacheMutex);
    158         Get().add(face, request);
    159     }
    160 
    161     /** Does not take ownership of request. */
    162     static SkTypeface* FindAndRef(Request* request) {
    163         SkAutoMutexAcquire ama(gSkFontHostRequestCacheMutex);
    164         return Get().findAndRef(request);
    165     }
    166 };
    167 
    168 SkTypeface* FontConfigTypeface::LegacyCreateTypeface(const char requestedFamilyName[],
    169                                                      SkTypeface::Style requestedOldStyle)
    170 {
    171     SkAutoTUnref<SkFontConfigInterface> fci(RefFCI());
    172     if (nullptr == fci.get()) {
    173         return nullptr;
    174     }
    175 
    176     // Check if this request is already in the request cache.
    177     using Request = SkFontHostRequestCache::Request;
    178     SkFontStyle requestedStyle(requestedOldStyle);
    179     SkAutoTDelete<Request> request(Request::Create(requestedFamilyName, requestedStyle));
    180     SkTypeface* face = SkFontHostRequestCache::FindAndRef(request);
    181     if (face) {
    182         return face;
    183     }
    184 
    185     SkFontConfigInterface::FontIdentity identity;
    186     SkString outFamilyName;
    187     SkTypeface::Style outOldStyle;
    188     if (!fci->matchFamilyName(requestedFamilyName, requestedOldStyle,
    189                               &identity, &outFamilyName, &outOldStyle))
    190     {
    191         return nullptr;
    192     }
    193 
    194     // Check if a typeface with this FontIdentity is already in the FontIdentity cache.
    195     face = SkTypefaceCache::FindByProcAndRef(find_by_FontIdentity, &identity);
    196     if (!face) {
    197         face = FontConfigTypeface::Create(SkFontStyle(outOldStyle), identity, outFamilyName);
    198         // Add this FontIdentity to the FontIdentity cache.
    199         SkTypefaceCache::Add(face, SkFontStyle(outOldStyle));
    200     }
    201     // Add this request to the request cache.
    202     SkFontHostRequestCache::Add(face, request.release());
    203 
    204     return face;
    205 }
    206 
    207 ///////////////////////////////////////////////////////////////////////////////
    208 
    209 SkStreamAsset* FontConfigTypeface::onOpenStream(int* ttcIndex) const {
    210     SkStreamAsset* stream = this->getLocalStream();
    211     if (stream) {
    212         // TODO: should have been provided by CreateFromStream()
    213         *ttcIndex = 0;
    214         return stream->duplicate();
    215     }
    216 
    217     SkAutoTUnref<SkFontConfigInterface> fci(RefFCI());
    218     if (nullptr == fci.get()) {
    219         return nullptr;
    220     }
    221 
    222     *ttcIndex = this->getIdentity().fTTCIndex;
    223     return fci->openStream(this->getIdentity());
    224 }
    225 
    226 void FontConfigTypeface::onGetFamilyName(SkString* familyName) const {
    227     *familyName = fFamilyName;
    228 }
    229 
    230 void FontConfigTypeface::onGetFontDescriptor(SkFontDescriptor* desc,
    231                                              bool* isLocalStream) const {
    232     SkString name;
    233     this->getFamilyName(&name);
    234     desc->setFamilyName(name.c_str());
    235     *isLocalStream = SkToBool(this->getLocalStream());
    236 }
    237