Index: trunk/src/ports/SkFontConfigInterface_direct.cpp |
=================================================================== |
--- trunk/src/ports/SkFontConfigInterface_direct.cpp (revision 8807) |
+++ trunk/src/ports/SkFontConfigInterface_direct.cpp (working copy) |
@@ -13,9 +13,91 @@ |
#include <fontconfig/fontconfig.h> |
+#include "SkBuffer.h" |
#include "SkFontConfigInterface.h" |
#include "SkStream.h" |
+size_t SkFontConfigInterface::FontIdentity::writeToMemory(void* addr) const { |
+ size_t size = sizeof(fID) + sizeof(fTTCIndex); |
+ size += sizeof(int32_t) + sizeof(int32_t) + sizeof(uint8_t); // weight, width, italic |
+ size += sizeof(int32_t) + fString.size(); // store length+data |
+ if (addr) { |
+ SkWBuffer buffer(addr, size); |
+ |
+ buffer.write32(fID); |
+ buffer.write32(fTTCIndex); |
+ buffer.write32(fString.size()); |
+ buffer.write32(fStyle.weight()); |
+ buffer.write32(fStyle.width()); |
+ buffer.write8(fStyle.slant()); |
+ buffer.write(fString.c_str(), fString.size()); |
+ buffer.padToAlign4(); |
+ |
+ SkASSERT(buffer.pos() == size); |
+ } |
+ return size; |
+} |
+ |
+size_t SkFontConfigInterface::FontIdentity::readFromMemory(const void* addr, |
+ size_t size) { |
+ SkRBuffer buffer(addr, size); |
+ |
+ fID = buffer.readU32(); |
+ fTTCIndex = buffer.readU32(); |
+ size_t strLen = buffer.readU32(); |
+ int weight = buffer.readU32(); |
+ int width = buffer.readU32(); |
+ SkFontStyle::Slant slant = (SkFontStyle::Slant)buffer.readU8(); |
+ fStyle = SkFontStyle(weight, width, slant); |
+ fString.resize(strLen); |
+ buffer.read(fString.writable_str(), strLen); |
+ buffer.skipToAlign4(); |
+ |
+ return buffer.pos(); // the actual number of bytes read |
+} |
+ |
+#ifdef SK_DEBUG |
+static void make_iden(SkFontConfigInterface::FontIdentity* iden) { |
+ iden->fID = 10; |
+ iden->fTTCIndex = 2; |
+ iden->fString.set("Hello world"); |
+ iden->fStyle = SkFontStyle(300, 6, SkFontStyle::kItalic_Slant); |
+} |
+ |
+static void test_writeToMemory(const SkFontConfigInterface::FontIdentity& iden0, |
+ int initValue) { |
+ SkFontConfigInterface::FontIdentity iden1; |
+ |
+ size_t size0 = iden0.writeToMemory(NULL); |
+ |
+ SkAutoMalloc storage(size0); |
+ memset(storage.get(), initValue, size0); |
+ |
+ size_t size1 = iden0.writeToMemory(storage.get()); |
+ SkASSERT(size0 == size1); |
+ |
+ SkASSERT(iden0 != iden1); |
+ size_t size2 = iden1.readFromMemory(storage.get(), size1); |
+ SkASSERT(size2 == size1); |
+ SkASSERT(iden0 == iden1); |
+} |
+ |
+static void fontconfiginterface_unittest() { |
+ SkFontConfigInterface::FontIdentity iden0, iden1; |
+ |
+ SkASSERT(iden0 == iden1); |
+ |
+ make_iden(&iden0); |
+ SkASSERT(iden0 != iden1); |
+ |
+ make_iden(&iden1); |
+ SkASSERT(iden0 == iden1); |
+ |
+ test_writeToMemory(iden0, 0); |
+ test_writeToMemory(iden0, 0); |
+} |
+#endif |
+ |
class SkFontConfigInterfaceDirect : public SkFontConfigInterface { |
public: |
SkFontConfigInterfaceDirect(); |
@@ -51,23 +133,6 @@ |
return gDirect; |
} |
-#if 0 |
-int SkFontConfigInterface::countFamilies() { return 0; } |
- |
-int SkFontConfigInterface::getFamilySet(int index, SkString* outFamilyName, |
- FontIdentity outIdentities[], |
- int maxCount) { |
- return 0; |
-} |
- |
-int SkFontConfigInterface::matchFamilySet(const char familyName[], |
- SkString* outFamilyName, |
- FontIdentity outIdentities[], |
- int maxCount) { |
- return 0; |
-} |
-#endif |
- |
/////////////////////////////////////////////////////////////////////////////// |
// Returns the string from the pattern, or NULL |
@@ -354,7 +419,11 @@ |
#define kMaxFontFamilyLength 2048 |
SkFontConfigInterfaceDirect::SkFontConfigInterfaceDirect() { |
+ SkAutoMutexAcquire ac(mutex_); |
+ |
FcInit(); |
+ |
+ SkDEBUGCODE(fontconfiginterface_unittest();) |
} |
SkFontConfigInterfaceDirect::~SkFontConfigInterfaceDirect() { |
@@ -490,6 +559,8 @@ |
} |
SkDataTable* SkFontConfigInterfaceDirect::getFamilyNames() { |
+ SkAutoMutexAcquire ac(mutex_); |
+ |
FcPattern* pat = FcPatternCreate(); |
FcObjectSet* os = FcObjectSetBuild (FC_FAMILY, (char *) 0); |
if (NULL == os) { |
@@ -523,5 +594,130 @@ |
bool SkFontConfigInterfaceDirect::matchFamilySet(const char inFamilyName[], |
SkString* outFamilyName, |
SkTArray<FontIdentity>* ids) { |
+ SkAutoMutexAcquire ac(mutex_); |
+ |
+#if 0 |
+ std::string familyStr(familyName ? familyName : ""); |
+ if (familyStr.length() > kMaxFontFamilyLength) { |
+ return false; |
+ } |
+ |
+ SkAutoMutexAcquire ac(mutex_); |
+ |
+ FcPattern* pattern = FcPatternCreate(); |
+ |
+ if (familyName) { |
+ FcPatternAddString(pattern, FC_FAMILY, (FcChar8*)familyName); |
+ } |
+ FcPatternAddBool(pattern, FC_SCALABLE, FcTrue); |
+ |
+ FcConfigSubstitute(NULL, pattern, FcMatchPattern); |
+ FcDefaultSubstitute(pattern); |
+ |
+ // Font matching: |
+ // CSS often specifies a fallback list of families: |
+ // font-family: a, b, c, serif; |
+ // However, fontconfig will always do its best to find *a* font when asked |
+ // for something so we need a way to tell if the match which it has found is |
+ // "good enough" for us. Otherwise, we can return NULL which gets piped up |
+ // and lets WebKit know to try the next CSS family name. However, fontconfig |
+ // configs allow substitutions (mapping "Arial -> Helvetica" etc) and we |
+ // wish to support that. |
+ // |
+ // Thus, if a specific family is requested we set @family_requested. Then we |
+ // record two strings: the family name after config processing and the |
+ // family name after resolving. If the two are equal, it's a good match. |
+ // |
+ // So consider the case where a user has mapped Arial to Helvetica in their |
+ // config. |
+ // requested family: "Arial" |
+ // post_config_family: "Helvetica" |
+ // post_match_family: "Helvetica" |
+ // -> good match |
+ // |
+ // and for a missing font: |
+ // requested family: "Monaco" |
+ // post_config_family: "Monaco" |
+ // post_match_family: "Times New Roman" |
+ // -> BAD match |
+ // |
+ // However, we special-case fallback fonts; see IsFallbackFontAllowed(). |
+ |
+ const char* post_config_family = get_name(pattern, FC_FAMILY); |
+ |
+ FcResult result; |
+ FcFontSet* font_set = FcFontSort(0, pattern, 0, 0, &result); |
+ if (!font_set) { |
+ FcPatternDestroy(pattern); |
+ return false; |
+ } |
+ |
+ FcPattern* match = MatchFont(font_set, post_config_family, familyStr); |
+ if (!match) { |
+ FcPatternDestroy(pattern); |
+ FcFontSetDestroy(font_set); |
+ return false; |
+ } |
+ |
+ 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; |
+ } |
+ |
+ FcFontSetDestroy(font_set); |
+ |
+ if (outIdentity) { |
+ outIdentity->fTTCIndex = face_index; |
+ outIdentity->fString.set((const char*)c_filename); |
+ } |
+ if (outFamilyName) { |
+ outFamilyName->set((const char*)post_config_family); |
+ } |
+ if (outStyle) { |
+ *outStyle = GetFontStyle(match); |
+ } |
+ return true; |
+ |
+//////////////////// |
+ |
+ int count; |
+ FcPattern** match = MatchFont(font_set, post_config_family, &count); |
+ if (!match) { |
+ FcPatternDestroy(pattern); |
+ FcFontSetDestroy(font_set); |
+ return NULL; |
+ } |
+ |
+ FcPatternDestroy(pattern); |
+ |
+ SkTDArray<FcPattern*> trimmedMatches; |
+ for (int i = 0; i < count; ++i) { |
+ const char* justName = find_just_name(get_name(match[i], FC_FILE)); |
+ if (!is_lower(*justName)) { |
+ *trimmedMatches.append() = match[i]; |
+ } |
+ } |
+ |
+ SkFontStyleSet_FC* sset = SkNEW_ARGS(SkFontStyleSet_FC, |
+ (trimmedMatches.begin(), |
+ trimmedMatches.count())); |
+#endif |
return false; |
} |
+ |