Index: trunk/src/ports/SkFontHost_fontconfig.cpp |
=================================================================== |
--- trunk/src/ports/SkFontHost_fontconfig.cpp (revision 7879) |
+++ trunk/src/ports/SkFontHost_fontconfig.cpp (working copy) |
@@ -5,23 +5,13 @@ |
* found in the LICENSE file. |
*/ |
-/* Derived from chromium's skia/ext/SkFontHost_fontconfig.cpp */ |
- |
-#include <map> |
-#include <string> |
- |
-#include <sys/mman.h> |
-#include <sys/stat.h> |
-#include <unistd.h> |
- |
#include "SkFontConfigInterface.h" |
#include "SkFontDescriptor.h" |
#include "SkFontHost.h" |
#include "SkStream.h" |
#include "SkTypeface.h" |
+#include "SkTypefaceCache.h" |
-extern SkFontConfigInterface* SkCreateDirectFontConfigInterface(); |
- |
SK_DECLARE_STATIC_MUTEX(gFontConfigInterfaceMutex); |
static SkFontConfigInterface* gFontConfigInterface; |
@@ -39,7 +29,11 @@ |
} |
/////////////////////////////////////////////////////////////////////////////// |
+/////////////////////////////////////////////////////////////////////////////// |
+// convenience function to create the direct interface if none is installed. |
+extern SkFontConfigInterface* SkCreateDirectFontConfigInterface(); |
+ |
static SkFontConfigInterface* RefFCI() { |
for (;;) { |
SkFontConfigInterface* fci = SkFontConfigInterface::RefGlobal(); |
@@ -51,73 +45,61 @@ |
} |
} |
-/////////////////////////////////////////////////////////////////////////////// |
+class FontConfigTypeface : public SkTypeface { |
+ SkFontConfigInterface::FontIdentity fIdentity; |
+ SkString fFamilyName; |
+ SkStream* fLocalStream; |
-SK_DECLARE_STATIC_MUTEX(global_remote_font_map_lock); |
-static std::map<uint32_t, std::pair<uint8_t*, size_t> >* global_remote_fonts; |
+public: |
+ FontConfigTypeface(Style style, |
+ const SkFontConfigInterface::FontIdentity& fi, |
+ const SkString& familyName) |
+ : SkTypeface(style, SkTypefaceCache::NewFontID()) |
+ , fIdentity(fi) |
+ , fFamilyName(familyName) |
+ , fLocalStream(NULL) {} |
-// Initialize the map declared above. Note that its corresponding mutex must be |
-// locked before calling this function. |
-static void AllocateGlobalRemoteFontsMapOnce() { |
- if (!global_remote_fonts) { |
- global_remote_fonts = |
- new std::map<uint32_t, std::pair<uint8_t*, size_t> >(); |
+ FontConfigTypeface(Style style, SkStream* localStream) |
+ : SkTypeface(style, SkTypefaceCache::NewFontID()) { |
+ // we default to empty fFamilyName and fIdentity |
+ fLocalStream = localStream; |
+ SkSafeRef(localStream); |
} |
-} |
-static unsigned global_next_remote_font_id; |
+ virtual ~FontConfigTypeface() { |
+ SkSafeUnref(fLocalStream); |
+ } |
-// This is the maximum size of the font cache. |
-static const unsigned kFontCacheMemoryBudget = 2 * 1024 * 1024; // 2MB |
+ const SkFontConfigInterface::FontIdentity& getIdentity() const { |
+ return fIdentity; |
+ } |
-// UniqueIds are encoded as (filefaceid << 8) | style |
-// For system fonts, filefaceid = (fileid << 4) | face_index. |
-// For remote fonts, filefaceid = fileid. |
+ const char* getFamilyName() const { return fFamilyName.c_str(); } |
+ SkStream* getLocalStream() const { return fLocalStream; } |
-static unsigned UniqueIdToFileFaceId(unsigned uniqueid) |
-{ |
- return uniqueid >> 8; |
-} |
+ bool isFamilyName(const char* name) const { |
+ return fFamilyName.equals(name); |
+ } |
+}; |
-static SkTypeface::Style UniqueIdToStyle(unsigned uniqueid) |
-{ |
- return static_cast<SkTypeface::Style>(uniqueid & 0xff); |
-} |
+/////////////////////////////////////////////////////////////////////////////// |
-static unsigned FileFaceIdAndStyleToUniqueId(unsigned filefaceid, |
- SkTypeface::Style style) |
-{ |
- SkASSERT((style & 0xff) == style); |
- return (filefaceid << 8) | static_cast<int>(style); |
-} |
+struct FindRec { |
+ FindRec(const char* name, SkTypeface::Style style) |
+ : fFamilyName(name) // don't need to make a deep copy |
+ , fStyle(style) {} |
-static const unsigned kRemoteFontMask = 0x00800000u; |
+ const char* fFamilyName; |
+ SkTypeface::Style fStyle; |
+}; |
-static bool IsRemoteFont(unsigned filefaceid) |
-{ |
- return filefaceid & kRemoteFontMask; |
+static bool find_proc(SkTypeface* face, SkTypeface::Style style, void* ctx) { |
+ FontConfigTypeface* fci = (FontConfigTypeface*)face; |
+ const FindRec* rec = (const FindRec*)ctx; |
+ |
+ return rec->fStyle == style && fci->isFamilyName(rec->fFamilyName); |
} |
-class FontConfigTypeface : public SkTypeface { |
-public: |
- FontConfigTypeface(Style style, uint32_t id) |
- : SkTypeface(style, id) {} |
- |
- virtual ~FontConfigTypeface() { |
- const uint32_t id = uniqueID(); |
- if (IsRemoteFont(UniqueIdToFileFaceId(id))) { |
- SkAutoMutexAcquire ac(global_remote_font_map_lock); |
- AllocateGlobalRemoteFontsMapOnce(); |
- std::map<uint32_t, std::pair<uint8_t*, size_t> >::iterator iter |
- = global_remote_fonts->find(id); |
- if (iter != global_remote_fonts->end()) { |
- sk_free(iter->second.first); // remove the font on memory. |
- global_remote_fonts->erase(iter); |
- } |
- } |
- } |
-}; |
- |
SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace, |
const char familyName[], |
SkTypeface::Style style) { |
@@ -126,32 +108,42 @@ |
return NULL; |
} |
- SkString familyNameStr; |
+#if 1 // HACK, remove me when we can rebaseline skia's gms |
+ if (NULL == familyName) { |
+ familyName = "Arial"; |
+ } |
+#endif |
if (familyFace) { |
- // Given the fileid we can ask fontconfig for the familyname of the |
- // font. |
- const unsigned filefaceid = UniqueIdToFileFaceId(familyFace->uniqueID()); |
- if (!fci->getFamilyName(filefaceid, &familyNameStr)) { |
- return NULL; |
- } |
- familyName = familyNameStr.c_str(); |
+ FontConfigTypeface* fct = (FontConfigTypeface*)familyFace; |
+ familyName = fct->getFamilyName(); |
} |
- unsigned filefaceid; |
- if (!fci->match(familyName, style, &filefaceid, &style)) { |
+ FindRec rec(familyName, style); |
+ SkTypeface* face = SkTypefaceCache::FindByProcAndRef(find_proc, &rec); |
+ if (face) { |
+ return face; |
+ } |
+ |
+ SkFontConfigInterface::FontIdentity indentity; |
+ SkString outFamilyName; |
+ SkTypeface::Style outStyle; |
+ |
+ if (!fci->matchFamilyName(familyName, style, |
+ &indentity, &outFamilyName, &outStyle)) { |
return NULL; |
} |
- const unsigned id = FileFaceIdAndStyleToUniqueId(filefaceid, style); |
- return SkNEW_ARGS(FontConfigTypeface, (style, id)); |
+ face = SkNEW_ARGS(FontConfigTypeface, (outStyle, indentity, outFamilyName)); |
+ SkTypefaceCache::Add(face, style); |
+ return face; |
} |
SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) { |
if (!stream) { |
return NULL; |
} |
- const size_t length = stream->read(0, 0); |
+ const size_t length = stream->getLength(); |
if (!length) { |
return NULL; |
} |
@@ -159,31 +151,11 @@ |
return NULL; // don't accept too large fonts (>= 1GB) for safety. |
} |
- uint8_t* font = (uint8_t*)sk_malloc_throw(length); |
- if (stream->read(font, length) != length) { |
- sk_free(font); |
- return NULL; |
- } |
- |
- SkTypeface::Style style = static_cast<SkTypeface::Style>(0); |
- unsigned id = 0; |
- { |
- SkAutoMutexAcquire ac(global_remote_font_map_lock); |
- AllocateGlobalRemoteFontsMapOnce(); |
- id = FileFaceIdAndStyleToUniqueId( |
- global_next_remote_font_id | kRemoteFontMask, style); |
- |
- if (++global_next_remote_font_id >= kRemoteFontMask) |
- global_next_remote_font_id = 0; |
- |
- if (!global_remote_fonts->insert( |
- std::make_pair(id, std::make_pair(font, length))).second) { |
- sk_free(font); |
- return NULL; |
- } |
- } |
- |
- return SkNEW_ARGS(FontConfigTypeface, (style, id)); |
+ // TODO should the caller give us the style? |
+ SkTypeface::Style style = SkTypeface::kNormal; |
+ SkTypeface* face = SkNEW_ARGS(FontConfigTypeface, (style, stream)); |
+ SkTypefaceCache::Add(face, style); |
+ return face; |
} |
SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) { |
@@ -208,20 +180,10 @@ |
// of SkFontDescriptor. |
void SkFontHost::Serialize(const SkTypeface* face, SkWStream* stream) { |
- SkAutoTUnref<SkFontConfigInterface> fci(RefFCI()); |
+ FontConfigTypeface* fct = (FontConfigTypeface*)face; |
SkFontDescriptor desc(face->style()); |
- SkString familyName; |
- const unsigned filefaceid = UniqueIdToFileFaceId(face->uniqueID()); |
- if (fci.get() && fci->getFamilyName(filefaceid, &familyName)) { |
- desc.setFamilyName(familyName.c_str()); |
- } else { |
- desc.setFamilyName("sans-serif"); |
- } |
- |
-//SkDebugf("Serialize: <%s>\n", desc.getFamilyName()); |
- // would also like other names (see SkFontDescriptor.h) |
- |
+ desc.setFamilyName(fct->getFamilyName()); |
desc.serialize(stream); |
// by convention, we also write out the actual sfnt data, preceeded by |
@@ -234,74 +196,60 @@ |
const char* familyName = descriptor.getFamilyName(); |
const SkTypeface::Style style = descriptor.getStyle(); |
- const uint32_t customFontDataLength = stream->readPackedUInt(); |
- if (customFontDataLength > 0) { |
-#if 0 // need to support inline data... |
- |
- // generate a new stream to store the custom typeface |
- SkMemoryStream* fontStream = new SkMemoryStream(customFontDataLength - 1); |
- stream->read((void*)fontStream->getMemoryBase(), customFontDataLength - 1); |
- |
- SkTypeface* face = CreateTypefaceFromStream(fontStream); |
- |
- fontStream->unref(); |
- return face; |
-#else |
- stream->skip(customFontDataLength); |
- return NULL; |
-#endif |
- } else { |
-//SkDebugf("Deserialize:<%s> %d\n", familyName, style); |
- return SkFontHost::CreateTypeface(NULL, familyName, style); |
+ size_t length = stream->readPackedUInt(); |
+ if (length > 0) { |
+ void* addr = sk_malloc_flags(length, 0); |
+ if (addr) { |
+ SkAutoTUnref<SkStream> localStream(SkNEW_ARGS(SkMemoryStream, |
+ (addr, length, false))); |
+ return SkFontHost::CreateTypefaceFromStream(localStream.get()); |
+ } |
+ // failed to allocate, so just skip and create-from-name |
+ stream->skip(length); |
} |
+ |
+ return SkFontHost::CreateTypeface(NULL, familyName, style); |
} |
/////////////////////////////////////////////////////////////////////////////// |
SkStream* SkFontHost::OpenStream(uint32_t id) { |
- const unsigned filefaceid = UniqueIdToFileFaceId(id); |
- |
- if (IsRemoteFont(filefaceid)) { |
- // remote font |
- SkAutoMutexAcquire ac(global_remote_font_map_lock); |
- AllocateGlobalRemoteFontsMapOnce(); |
- std::map<uint32_t, std::pair<uint8_t*, size_t> >::const_iterator iter |
- = global_remote_fonts->find(id); |
- if (iter == global_remote_fonts->end()) |
- return NULL; |
- return SkNEW_ARGS( |
- SkMemoryStream, (iter->second.first, iter->second.second)); |
- } |
- |
- // system font |
- |
- SkAutoTUnref<SkFontConfigInterface> fci(RefFCI()); |
- if (NULL == fci.get()) { |
+ FontConfigTypeface* face = (FontConfigTypeface*)SkTypefaceCache::FindByID(id); |
+ if (NULL == face) { |
return NULL; |
} |
- return fci->openStream(filefaceid); |
+ |
+ SkStream* stream = face->getLocalStream(); |
+ if (stream) { |
+ stream->ref(); |
+ } else { |
+ SkAutoTUnref<SkFontConfigInterface> fci(RefFCI()); |
+ if (NULL == fci.get()) { |
+ return NULL; |
+ } |
+ stream = fci->openStream(face->getIdentity()); |
+ } |
+ return stream; |
} |
size_t SkFontHost::GetFileName(SkFontID fontID, char path[], size_t length, |
int32_t* index) { |
- const unsigned filefaceid = UniqueIdToFileFaceId(fontID); |
- |
- if (IsRemoteFont(filefaceid)) |
+ FontConfigTypeface* face = (FontConfigTypeface*)SkTypefaceCache::FindByID(fontID); |
+ if (NULL == face || face->getLocalStream()) { |
return 0; |
+ } |
+ // Here we cheat, and "know" what is in the identity fields. |
+ |
+ const SkString& filename = face->getIdentity().fString; |
if (index) { |
- *index = filefaceid & 0xfu; |
- // 1 is a bogus return value. |
- // We had better change the signature of this function in Skia |
- // to return bool to indicate success/failure and have another |
- // out param for fileName length. |
- if (!path) |
- return 1; |
+ *index = (int32_t)face->getIdentity().fIntPtr; |
} |
+ if (path) { |
+ size_t len = SkMin32(length, filename.size()); |
+ memcpy(path, filename.c_str(), len); |
+ } |
+ return filename.size(); |
+} |
- if (path) |
- SkASSERT(!"SkFontHost::GetFileName does not support the font path " |
- "retrieval."); |
- return 0; |
-} |