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