use fontconfig fonthost for skia (in prep for using in chrome)
Review URL: https://codereview.chromium.org/12319150
git-svn-id: http://skia.googlecode.com/svn/trunk@7887 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/ports/SkFontConfigInterface_direct.cpp b/src/ports/SkFontConfigInterface_direct.cpp
index 84555a2..d073747 100644
--- a/src/ports/SkFontConfigInterface_direct.cpp
+++ b/src/ports/SkFontConfigInterface_direct.cpp
@@ -7,7 +7,6 @@
/* migrated from chrome/src/skia/ext/SkFontHost_fontconfig_direct.cpp */
-#include <map>
#include <string>
#include <unistd.h>
#include <fcntl.h>
@@ -15,7 +14,6 @@
#include <fontconfig/fontconfig.h>
#include "SkFontConfigInterface.h"
-//#include "SkUtils.h"
#include "SkStream.h"
class SkFontConfigInterfaceDirect : public SkFontConfigInterface {
@@ -23,28 +21,15 @@
SkFontConfigInterfaceDirect();
virtual ~SkFontConfigInterfaceDirect();
- virtual bool match(const char familyName[], SkTypeface::Style requested,
- unsigned* fileFaceID, SkTypeface::Style* outStyle) SK_OVERRIDE;
- virtual bool getFamilyName(unsigned fileFaceID, SkString* name) SK_OVERRIDE;
- virtual SkStream* openStream(unsigned fileFaceID) SK_OVERRIDE;
+ virtual bool matchFamilyName(const char familyName[],
+ SkTypeface::Style requested,
+ FontIdentity* outFontIdentifier,
+ SkString* outFamilyName,
+ SkTypeface::Style* outStyle) SK_OVERRIDE;
+ virtual SkStream* openStream(const FontIdentity&) SK_OVERRIDE;
private:
SkMutex mutex_;
-
- // fileid stored in two maps below are unique per font file.
- std::map<unsigned, std::string> fileid_to_filename_;
- std::map<std::string, unsigned> filename_to_fileid_;
-
- // Cache of |family,style| to |FontMatch| to minimize querying FontConfig.
- typedef std::pair<std::string, int> FontMatchKey;
- struct FontMatch {
- std::string family;
- SkTypeface::Style style;
- unsigned filefaceid;
- };
- std::map<FontMatchKey, FontMatch> font_match_cache_;
-
- unsigned next_file_id_;
};
SkFontConfigInterface* SkCreateDirectFontConfigInterface();
@@ -290,13 +275,7 @@
}
// Retrieves |is_bold|, |is_italic| and |font_family| properties from |font|.
-bool GetFontProperties(FcPattern* font,
- std::string* font_family,
- SkTypeface::Style* style) {
- FcChar8* c_family;
- if (FcPatternGetString(font, FC_FAMILY, 0, &c_family))
- return false;
-
+SkTypeface::Style GetFontStyle(FcPattern* font) {
int resulting_bold;
if (FcPatternGetInteger(font, FC_WEIGHT, 0, &resulting_bold))
resulting_bold = FC_WEIGHT_NORMAL;
@@ -325,28 +304,27 @@
styleBits |= SkTypeface::kItalic;
}
- *font_family = reinterpret_cast<char*>(c_family);
- *style = (SkTypeface::Style)styleBits;
- return true;
+ return (SkTypeface::Style)styleBits;
}
} // anonymous namespace
///////////////////////////////////////////////////////////////////////////////
-#define kMaxFontFamilyLength 1024
+#define kMaxFontFamilyLength 2048
-SkFontConfigInterfaceDirect::SkFontConfigInterfaceDirect() : next_file_id_(0) {
+SkFontConfigInterfaceDirect::SkFontConfigInterfaceDirect() {
FcInit();
}
SkFontConfigInterfaceDirect::~SkFontConfigInterfaceDirect() {
}
-bool SkFontConfigInterfaceDirect::match(const char familyName[],
- SkTypeface::Style style,
- unsigned* result_filefaceid,
- SkTypeface::Style* result_style) {
+bool SkFontConfigInterfaceDirect::matchFamilyName(const char familyName[],
+ SkTypeface::Style style,
+ FontIdentity* outIdentity,
+ SkString* outFamilyName,
+ SkTypeface::Style* outStyle) {
std::string familyStr(familyName ? familyName : "");
if (familyStr.length() > kMaxFontFamilyLength) {
return false;
@@ -354,18 +332,6 @@
SkAutoMutexAcquire ac(mutex_);
- // search our cache
- {
- FontMatchKey key = FontMatchKey(familyStr, style);
- const std::map<FontMatchKey, FontMatch>::const_iterator i =
- font_match_cache_.find(key);
- if (i != font_match_cache_.end()) {
- *result_style = i->second.style;
- *result_filefaceid = i->second.filefaceid;
- return true;
- }
- }
-
FcPattern* pattern = FcPatternCreate();
if (familyName) {
@@ -429,133 +395,43 @@
FcPatternDestroy(pattern);
+ // From here out we just extract our results from 'match'
+
+ if (FcPatternGetString(match, FC_FAMILY, 0, &post_config_family) != FcResultMatch) {
+ FcFontSetDestroy(font_set);
+ return false;
+ }
+
FcChar8* c_filename;
if (FcPatternGetString(match, FC_FILE, 0, &c_filename) != FcResultMatch) {
FcFontSetDestroy(font_set);
return false;
}
+
int face_index;
if (FcPatternGetInteger(match, FC_INDEX, 0, &face_index) != FcResultMatch) {
FcFontSetDestroy(font_set);
return false;
}
- FontMatch font_match;
- {
- unsigned out_fileid;
- const std::string filename(reinterpret_cast<char*>(c_filename));
- const std::map<std::string, unsigned>::const_iterator
- i = filename_to_fileid_.find(filename);
- if (i == filename_to_fileid_.end()) {
- out_fileid = next_file_id_++;
- filename_to_fileid_[filename] = out_fileid;
- fileid_to_filename_[out_fileid] = filename;
- } else {
- out_fileid = i->second;
- }
- // fileid stored in filename_to_fileid_ and fileid_to_filename_ is
- // unique only up to the font file. We have to encode face_index for
- // the out param.
- font_match.filefaceid =
- FileIdAndFaceIndexToFileFaceId(out_fileid, face_index);
- }
-
- bool success = GetFontProperties(match,
- &font_match.family,
- &font_match.style);
FcFontSetDestroy(font_set);
- if (success) {
- font_match_cache_[FontMatchKey(familyStr, style)] = font_match;
- *result_filefaceid = font_match.filefaceid;
- *result_style = font_match.style;
+ if (outIdentity) {
+ outIdentity->fIntPtr = face_index;
+ outIdentity->fString.set((const char*)c_filename);
}
-
- return success;
-}
-
-#include <fontconfig/fcfreetype.h>
-
-bool SkFontConfigInterfaceDirect::getFamilyName(unsigned filefaceid,
- SkString* result_family) {
- SkAutoMutexAcquire ac(mutex_);
-
-#if 0
- FcPattern* pattern = FcPatternCreate();
- SkString filename;
-
- {
- const std::map<unsigned, std::string>::const_iterator
- i = fileid_to_filename_.find(FileFaceIdToFileId(filefaceid));
- if (i == fileid_to_filename_.end()) {
- FcPatternDestroy(pattern);
- return false;
- }
- int face_index = filefaceid & 0xfu;
- filename.set(i->second.c_str());
- FcPatternAddString(pattern, FC_FILE,
- reinterpret_cast<const FcChar8*>(i->second.c_str()));
- FcPatternAddInteger(pattern, FC_INDEX, face_index);
+ if (outFamilyName) {
+ outFamilyName->set((const char*)post_config_family);
}
-
- FcPatternAddBool(pattern, FC_SCALABLE, FcTrue);
-
- FcConfigSubstitute(NULL, pattern, FcMatchPattern);
- FcDefaultSubstitute(pattern);
-
- FcResult result;
- FcFontSet* font_set = FcFontSort(0, pattern, 0, 0, &result);
- if (!font_set || font_set->nfont <= 0) {
- FcPatternDestroy(pattern);
- return false;
+ if (outStyle) {
+ *outStyle = GetFontStyle(match);
}
-
- bool found = false;
- for (int i = 0; i < font_set->nfont; ++i) {
- FcChar8* file;
- FcPatternGetString(font_set->fonts[i], FC_FILE, 0, &file);
- if (filename.equals((const char*)file)) {
- FcChar8* family;
- FcPatternGetString(font_set->fonts[i], FC_FAMILY, 0, &family);
- result_family->set((const char*)family);
- found = true;
- break;
- }
- }
-
- FcPatternDestroy(pattern);
- FcFontSetDestroy(font_set);
- return found;
-#else
- const std::map<unsigned, std::string>::const_iterator
- i = fileid_to_filename_.find(FileFaceIdToFileId(filefaceid));
- if (i == fileid_to_filename_.end()) {
- return false;
- }
-
- int face_index = filefaceid & 0xfu;
- int count;
- FcPattern* pattern = FcFreeTypeQuery((const FcChar8*)i->second.c_str(),
- face_index, NULL, &count);
- if (!pattern || count <= 0) {
- return false;
- }
-
- FcChar8* family;
- FcPatternGetString(pattern, FC_FAMILY, 0, &family);
-
- result_family->set((const char*)family);
return true;
-#endif
}
-SkStream* SkFontConfigInterfaceDirect::openStream(unsigned filefaceid) {
- SkAutoMutexAcquire ac(mutex_);
- const std::map<unsigned, std::string>::const_iterator
- i = fileid_to_filename_.find(FileFaceIdToFileId(filefaceid));
- if (i == fileid_to_filename_.end()) {
- return NULL;
- }
- int fd = open(i->second.c_str(), O_RDONLY);
+SkStream* SkFontConfigInterfaceDirect::openStream(const FontIdentity& identity) {
+ int fd = open(identity.fString.c_str(), O_RDONLY);
return (fd >= 0) ? SkNEW_ARGS(SkFDStream, (fd, true)) : NULL;
}
+
+
diff --git a/src/ports/SkFontHost_fontconfig.cpp b/src/ports/SkFontHost_fontconfig.cpp
index ccf2eb0..8144cc9 100644
--- a/src/ports/SkFontHost_fontconfig.cpp
+++ b/src/ports/SkFontHost_fontconfig.cpp
@@ -5,22 +5,12 @@
* 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"
-
-extern SkFontConfigInterface* SkCreateDirectFontConfigInterface();
+#include "SkTypefaceCache.h"
SK_DECLARE_STATIC_MUTEX(gFontConfigInterfaceMutex);
static SkFontConfigInterface* gFontConfigInterface;
@@ -39,6 +29,10 @@
}
///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+
+// convenience function to create the direct interface if none is installed.
+extern SkFontConfigInterface* SkCreateDirectFontConfigInterface();
static SkFontConfigInterface* RefFCI() {
for (;;) {
@@ -51,73 +45,61 @@
}
}
-///////////////////////////////////////////////////////////////////////////////
-
-SK_DECLARE_STATIC_MUTEX(global_remote_font_map_lock);
-static std::map<uint32_t, std::pair<uint8_t*, size_t> >* global_remote_fonts;
-
-// 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> >();
- }
-}
-
-static unsigned global_next_remote_font_id;
-
-// This is the maximum size of the font cache.
-static const unsigned kFontCacheMemoryBudget = 2 * 1024 * 1024; // 2MB
-
-// UniqueIds are encoded as (filefaceid << 8) | style
-// For system fonts, filefaceid = (fileid << 4) | face_index.
-// For remote fonts, filefaceid = fileid.
-
-static unsigned UniqueIdToFileFaceId(unsigned uniqueid)
-{
- return uniqueid >> 8;
-}
-
-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);
-}
-
-static const unsigned kRemoteFontMask = 0x00800000u;
-
-static bool IsRemoteFont(unsigned filefaceid)
-{
- return filefaceid & kRemoteFontMask;
-}
-
class FontConfigTypeface : public SkTypeface {
+ SkFontConfigInterface::FontIdentity fIdentity;
+ SkString fFamilyName;
+ SkStream* fLocalStream;
+
public:
- FontConfigTypeface(Style style, uint32_t id)
- : SkTypeface(style, id) {}
+ FontConfigTypeface(Style style,
+ const SkFontConfigInterface::FontIdentity& fi,
+ const SkString& familyName)
+ : SkTypeface(style, SkTypefaceCache::NewFontID())
+ , fIdentity(fi)
+ , fFamilyName(familyName)
+ , fLocalStream(NULL) {}
+
+ FontConfigTypeface(Style style, SkStream* localStream)
+ : SkTypeface(style, SkTypefaceCache::NewFontID()) {
+ // we default to empty fFamilyName and fIdentity
+ fLocalStream = localStream;
+ SkSafeRef(localStream);
+ }
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);
- }
- }
+ SkSafeUnref(fLocalStream);
+ }
+
+ const SkFontConfigInterface::FontIdentity& getIdentity() const {
+ return fIdentity;
+ }
+
+ const char* getFamilyName() const { return fFamilyName.c_str(); }
+ SkStream* getLocalStream() const { return fLocalStream; }
+
+ bool isFamilyName(const char* name) const {
+ return fFamilyName.equals(name);
}
};
+///////////////////////////////////////////////////////////////////////////////
+
+struct FindRec {
+ FindRec(const char* name, SkTypeface::Style style)
+ : fFamilyName(name) // don't need to make a deep copy
+ , fStyle(style) {}
+
+ const char* fFamilyName;
+ SkTypeface::Style fStyle;
+};
+
+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);
+}
+
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;
-
- 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;
}
- if (path)
- SkASSERT(!"SkFontHost::GetFileName does not support the font path "
- "retrieval.");
+ // Here we cheat, and "know" what is in the identity fields.
- return 0;
+ const SkString& filename = face->getIdentity().fString;
+ if (index) {
+ *index = (int32_t)face->getIdentity().fIntPtr;
+ }
+ if (path) {
+ size_t len = SkMin32(length, filename.size());
+ memcpy(path, filename.c_str(), len);
+ }
+ return filename.size();
}
+
+