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 "SkFontHost.h"
     12 #include "SkFontHost_FreeType_common.h"
     13 #include "SkFontStream.h"
     14 #include "SkStream.h"
     15 #include "SkTypeface.h"
     16 #include "SkTypefaceCache.h"
     17 
     18 SK_DECLARE_STATIC_MUTEX(gFontConfigInterfaceMutex);
     19 static SkFontConfigInterface* gFontConfigInterface;
     20 
     21 SkFontConfigInterface* SkFontConfigInterface::RefGlobal() {
     22     SkAutoMutexAcquire ac(gFontConfigInterfaceMutex);
     23 
     24     return SkSafeRef(gFontConfigInterface);
     25 }
     26 
     27 SkFontConfigInterface* SkFontConfigInterface::SetGlobal(SkFontConfigInterface* fc) {
     28     SkAutoMutexAcquire ac(gFontConfigInterfaceMutex);
     29 
     30     SkRefCnt_SafeAssign(gFontConfigInterface, fc);
     31     return fc;
     32 }
     33 
     34 ///////////////////////////////////////////////////////////////////////////////
     35 ///////////////////////////////////////////////////////////////////////////////
     36 
     37 // convenience function to create the direct interface if none is installed.
     38 extern SkFontConfigInterface* SkCreateDirectFontConfigInterface();
     39 
     40 static SkFontConfigInterface* RefFCI() {
     41     for (;;) {
     42         SkFontConfigInterface* fci = SkFontConfigInterface::RefGlobal();
     43         if (fci) {
     44             return fci;
     45         }
     46         fci = SkFontConfigInterface::GetSingletonDirectInterface();
     47         SkFontConfigInterface::SetGlobal(fci);
     48     }
     49 }
     50 
     51 // export this to SkFontMgr_fontconfig.cpp until this file just goes away.
     52 SkFontConfigInterface* SkFontHost_fontconfig_ref_global();
     53 SkFontConfigInterface* SkFontHost_fontconfig_ref_global() {
     54     return RefFCI();
     55 }
     56 
     57 ///////////////////////////////////////////////////////////////////////////////
     58 
     59 struct FindRec {
     60     FindRec(const char* name, SkTypeface::Style style)
     61         : fFamilyName(name)  // don't need to make a deep copy
     62         , fStyle(style) {}
     63 
     64     const char* fFamilyName;
     65     SkTypeface::Style fStyle;
     66 };
     67 
     68 static bool find_proc(SkTypeface* face, SkTypeface::Style style, void* ctx) {
     69     FontConfigTypeface* fci = (FontConfigTypeface*)face;
     70     const FindRec* rec = (const FindRec*)ctx;
     71 
     72     return rec->fStyle == style && fci->isFamilyName(rec->fFamilyName);
     73 }
     74 
     75 SkTypeface* FontConfigTypeface::LegacyCreateTypeface(
     76                 const SkTypeface* familyFace,
     77                 const char familyName[],
     78                 SkTypeface::Style style) {
     79     SkAutoTUnref<SkFontConfigInterface> fci(RefFCI());
     80     if (NULL == fci.get()) {
     81         return NULL;
     82     }
     83 
     84     if (familyFace) {
     85         FontConfigTypeface* fct = (FontConfigTypeface*)familyFace;
     86         familyName = fct->getFamilyName();
     87     }
     88 
     89     FindRec rec(familyName, style);
     90     SkTypeface* face = SkTypefaceCache::FindByProcAndRef(find_proc, &rec);
     91     if (face) {
     92 //        SkDebugf("found cached face <%s> <%s> %p [%d]\n", familyName, ((FontConfigTypeface*)face)->getFamilyName(), face, face->getRefCnt());
     93         return face;
     94     }
     95 
     96     SkFontConfigInterface::FontIdentity indentity;
     97     SkString                            outFamilyName;
     98     SkTypeface::Style                   outStyle;
     99 
    100     if (!fci->matchFamilyName(familyName, style,
    101                               &indentity, &outFamilyName, &outStyle)) {
    102         return NULL;
    103     }
    104 
    105     // check if we, in fact, already have this. perhaps fontconfig aliased the
    106     // requested name to some other name we actually have...
    107     rec.fFamilyName = outFamilyName.c_str();
    108     rec.fStyle = outStyle;
    109     face = SkTypefaceCache::FindByProcAndRef(find_proc, &rec);
    110     if (face) {
    111         return face;
    112     }
    113 
    114     face = SkNEW_ARGS(FontConfigTypeface, (outStyle, indentity, outFamilyName));
    115     SkTypefaceCache::Add(face, style);
    116 //    SkDebugf("add face <%s> <%s> %p [%d]\n", familyName, outFamilyName.c_str(), face, face->getRefCnt());
    117     return face;
    118 }
    119 
    120 #ifndef SK_FONTHOST_USES_FONTMGR
    121 
    122 SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace,
    123                                        const char familyName[],
    124                                        SkTypeface::Style style) {
    125     return FontConfigTypeface::LegacyCreateTypeface(familyFace, familyName,
    126                                                     style);
    127 }
    128 
    129 SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) {
    130     if (!stream) {
    131         return NULL;
    132     }
    133     const size_t length = stream->getLength();
    134     if (!length) {
    135         return NULL;
    136     }
    137     if (length >= 1024 * 1024 * 1024) {
    138         return NULL;  // don't accept too large fonts (>= 1GB) for safety.
    139     }
    140 
    141     // TODO should the caller give us the style?
    142     SkTypeface::Style style = SkTypeface::kNormal;
    143     SkTypeface* face = SkNEW_ARGS(FontConfigTypeface, (style, stream));
    144     return face;
    145 }
    146 
    147 SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) {
    148     SkAutoTUnref<SkStream> stream(SkStream::NewFromFile(path));
    149     return stream.get() ? CreateTypefaceFromStream(stream) : NULL;
    150 }
    151 
    152 #endif
    153 
    154 ///////////////////////////////////////////////////////////////////////////////
    155 
    156 SkStream* FontConfigTypeface::onOpenStream(int* ttcIndex) const {
    157     SkStream* stream = this->getLocalStream();
    158     if (stream) {
    159         // should have been provided by CreateFromStream()
    160         *ttcIndex = 0;
    161 
    162         SkAutoTUnref<SkStream> dupStream(stream->duplicate());
    163         if (dupStream) {
    164             return dupStream.detach();
    165         }
    166 
    167         // TODO: update interface use, remove the following code in this block.
    168         size_t length = stream->getLength();
    169 
    170         const void* memory = stream->getMemoryBase();
    171         if (NULL != memory) {
    172             return new SkMemoryStream(memory, length, true);
    173         }
    174 
    175         SkAutoTMalloc<uint8_t> allocMemory(length);
    176         stream->rewind();
    177         if (length == stream->read(allocMemory.get(), length)) {
    178             SkAutoTUnref<SkMemoryStream> copyStream(new SkMemoryStream());
    179             copyStream->setMemoryOwned(allocMemory.detach(), length);
    180             return copyStream.detach();
    181         }
    182 
    183         stream->rewind();
    184         stream->ref();
    185     } else {
    186         SkAutoTUnref<SkFontConfigInterface> fci(RefFCI());
    187         if (NULL == fci.get()) {
    188             return NULL;
    189         }
    190         stream = fci->openStream(this->getIdentity());
    191         *ttcIndex = this->getIdentity().fTTCIndex;
    192     }
    193     return stream;
    194 }
    195 
    196 void FontConfigTypeface::onGetFontDescriptor(SkFontDescriptor* desc,
    197                                              bool* isLocalStream) const {
    198     desc->setFamilyName(this->getFamilyName());
    199     *isLocalStream = SkToBool(this->getLocalStream());
    200 }
    201 
    202 SkTypeface* FontConfigTypeface::onRefMatchingStyle(Style style) const {
    203     return LegacyCreateTypeface(this, NULL, style);
    204 }
    205