diff options
Diffstat (limited to 'src/fonts/SkFontMgr_fontconfig.cpp')
-rw-r--r-- | src/fonts/SkFontMgr_fontconfig.cpp | 381 |
1 files changed, 149 insertions, 232 deletions
diff --git a/src/fonts/SkFontMgr_fontconfig.cpp b/src/fonts/SkFontMgr_fontconfig.cpp index 90511702bf..937696468e 100644 --- a/src/fonts/SkFontMgr_fontconfig.cpp +++ b/src/fonts/SkFontMgr_fontconfig.cpp @@ -7,226 +7,154 @@ #include "SkFontConfigInterface.h" #include "SkFontConfigTypeface.h" +#include "SkFontDescriptor.h" #include "SkFontMgr.h" #include "SkFontStyle.h" -#include "SkMath.h" #include "SkMutex.h" #include "SkString.h" -#include "SkTDArray.h" - -// for now we pull these in directly. eventually we will solely rely on the -// SkFontConfigInterface instance. -#include <fontconfig/fontconfig.h> -#include <unistd.h> - -namespace { - -// Fontconfig is not threadsafe before 2.10.91. Before that, we lock with a global mutex. -// See skia:1497 for background. -SK_DECLARE_STATIC_MUTEX(gFCMutex); -static bool gFCSafeToUse; - -struct FCLocker { - FCLocker() { - if (FcGetVersion() < 21091) { // We assume FcGetVersion() has always been thread safe. - gFCMutex.acquire(); - fUnlock = true; - } else { - fUnlock = false; - } - gFCSafeToUse = true; - } - - ~FCLocker() { - if (fUnlock) { - gFCSafeToUse = false; - gFCMutex.release(); - } - } +#include "SkTypeface.h" +#include "SkTypefaceCache.h" +#include "SkResourceCache.h" -private: - bool fUnlock; -}; - -} // namespace - -// borrow this global from SkFontHost_fontconfig. eventually that file should -// go away, and be replaced with this one. -extern SkFontConfigInterface* SkFontHost_fontconfig_ref_global(); -static SkFontConfigInterface* RefFCI() { - return SkFontHost_fontconfig_ref_global(); -} +SkStreamAsset* SkTypeface_FCI::onOpenStream(int* ttcIndex) const { + *ttcIndex = this->getIdentity().fTTCIndex; -// look for the last substring after a '/' and return that, or return null. -static const char* find_just_name(const char* str) { - const char* last = strrchr(str, '/'); - return last ? last + 1 : nullptr; -} - -static bool is_lower(char c) { - return c >= 'a' && c <= 'z'; -} - -static int get_int(FcPattern* pattern, const char field[]) { - SkASSERT(gFCSafeToUse); - int value; - if (FcPatternGetInteger(pattern, field, 0, &value) != FcResultMatch) { - value = SK_MinS32; + SkStreamAsset* stream = this->getLocalStream(); + if (stream) { + return stream->duplicate(); } - return value; -} -static const char* get_name(FcPattern* pattern, const char field[]) { - SkASSERT(gFCSafeToUse); - const char* name; - if (FcPatternGetString(pattern, field, 0, (FcChar8**)&name) != FcResultMatch) { - name = ""; - } - return name; + return fFCI->openStream(this->getIdentity()); } -static bool valid_pattern(FcPattern* pattern) { - SkASSERT(gFCSafeToUse); - FcBool is_scalable; - if (FcPatternGetBool(pattern, FC_SCALABLE, 0, &is_scalable) != FcResultMatch || !is_scalable) { - return false; - } - - // fontconfig can also return fonts which are unreadable - const char* c_filename = get_name(pattern, FC_FILE); - if (0 == *c_filename) { - return false; - } - if (access(c_filename, R_OK) != 0) { - return false; - } - return true; -} - -static bool match_name(FcPattern* pattern, const char family_name[]) { - return !strcasecmp(family_name, get_name(pattern, FC_FAMILY)); +void SkTypeface_FCI::onGetFontDescriptor(SkFontDescriptor* desc, bool* isLocalStream) const { + SkString name; + this->getFamilyName(&name); + desc->setFamilyName(name.c_str()); + *isLocalStream = SkToBool(this->getLocalStream()); } -static FcPattern** MatchFont(FcFontSet* font_set, - const char post_config_family[], - int* count) { - // Older versions of fontconfig have a bug where they cannot select - // only scalable fonts so we have to manually filter the results. - - FcPattern** iter = font_set->fonts; - FcPattern** stop = iter + font_set->nfont; - // find the first good match - for (; iter < stop; ++iter) { - if (valid_pattern(*iter)) { - break; - } - } +/////////////////////////////////////////////////////////////////////////////// - if (iter == stop || !match_name(*iter, post_config_family)) { - return nullptr; - } +class SkFontStyleSet_FCI : public SkFontStyleSet { +public: + SkFontStyleSet_FCI() {} - FcPattern** firstIter = iter++; - for (; iter < stop; ++iter) { - if (!valid_pattern(*iter) || !match_name(*iter, post_config_family)) { - break; - } - } + int count() override { return 0; } + void getStyle(int index, SkFontStyle*, SkString* style) override { SkASSERT(false); } + SkTypeface* createTypeface(int index) override { SkASSERT(false); return nullptr; } + SkTypeface* matchStyle(const SkFontStyle& pattern) override { return nullptr; } +}; - *count = iter - firstIter; - return firstIter; -} +/////////////////////////////////////////////////////////////////////////////// -class SkFontStyleSet_FC : public SkFontStyleSet { +class SkFontRequestCache { public: - SkFontStyleSet_FC(FcPattern** matches, int count); - virtual ~SkFontStyleSet_FC(); + struct Request : public SkResourceCache::Key { + private: + Request(const char* name, size_t nameLen, const SkFontStyle& style) : fStyle(style) { + /** Pointer to just after the last field of this class. */ + char* content = const_cast<char*>(SkTAfter<const char>(&this->fStyle)); + + // No holes. + SkASSERT(SkTAddOffset<char>(this, sizeof(SkResourceCache::Key) + keySize) == content); + + // Has a size divisible by size of uint32_t. + SkASSERT((content - reinterpret_cast<char*>(this)) % sizeof(uint32_t) == 0); + + size_t contentLen = SkAlign4(nameLen); + sk_careful_memcpy(content, name, nameLen); + sk_bzero(content + nameLen, contentLen - nameLen); + this->init(nullptr, 0, keySize + contentLen); + } + const SkFontStyle fStyle; + /** The sum of the sizes of the fields of this class. */ + static const size_t keySize = sizeof(fStyle); + + public: + static Request* Create(const char* name, const SkFontStyle& style) { + size_t nameLen = name ? strlen(name) : 0; + size_t contentLen = SkAlign4(nameLen); + char* storage = new char[sizeof(Request) + contentLen]; + return new (storage) Request(name, nameLen, style); + } + void operator delete(void* storage) { + delete[] reinterpret_cast<char*>(storage); + } + }; - int count() override { return fRecCount; } - void getStyle(int index, SkFontStyle*, SkString* style) override; - SkTypeface* createTypeface(int index) override; - SkTypeface* matchStyle(const SkFontStyle& pattern) override; private: - struct Rec { - SkString fStyleName; - SkString fFileName; - SkFontStyle fStyle; + struct Result : public SkResourceCache::Rec { + Result(Request* request, SkTypeface* typeface) + : fRequest(request) + , fFace(SkSafeRef(typeface)) {} + Result(Result&&) = default; + Result& operator=(Result&&) = default; + + const Key& getKey() const override { return *fRequest; } + size_t bytesUsed() const override { return fRequest->size() + sizeof(fFace); } + const char* getCategory() const override { return "request_cache"; } + SkDiscardableMemory* diagnostic_only_getDiscardable() const override { return nullptr; } + + SkAutoTDelete<Request> fRequest; + SkAutoTUnref<SkTypeface> fFace; }; - Rec* fRecs; - int fRecCount; -}; -static int map_range(int value, - int old_min, int old_max, int new_min, int new_max) { - SkASSERT(old_min < old_max); - SkASSERT(new_min < new_max); - return new_min + SkMulDiv(value - old_min, - new_max - new_min, old_max - old_min); -} + SkResourceCache fCachedResults; -static SkFontStyle make_fontconfig_style(FcPattern* match) { - int weight = get_int(match, FC_WEIGHT); - int width = get_int(match, FC_WIDTH); - int fcSlant = get_int(match, FC_SLANT); - - // fontconfig weight seems to be 0..200 or so, so we remap it here - weight = map_range(weight, 0, 80, 0, 400); - width = map_range(width, 0, 200, 0, 9); - SkFontStyle::Slant skSlant = SkFontStyle::kUpright_Slant; - switch (fcSlant) { - case FC_SLANT_ROMAN: skSlant = SkFontStyle::kUpright_Slant; break; - case FC_SLANT_ITALIC : skSlant = SkFontStyle::kItalic_Slant ; break; - case FC_SLANT_OBLIQUE: skSlant = SkFontStyle::kOblique_Slant; break; - default: SkASSERT(false); break; +public: + SkFontRequestCache(size_t maxSize) : fCachedResults(maxSize) {} + + /** Takes ownership of request. It will be deleted when no longer needed. */ + void add(SkTypeface* face, Request* request) { + fCachedResults.add(new Result(request, face)); } - return SkFontStyle(weight, width, skSlant); -} + /** Does not take ownership of request. */ + SkTypeface* findAndRef(Request* request) { + SkTypeface* face = nullptr; + fCachedResults.find(*request, [](const SkResourceCache::Rec& rec, void* context) -> bool { + const Result& result = static_cast<const Result&>(rec); + SkTypeface** face = static_cast<SkTypeface**>(context); -SkFontStyleSet_FC::SkFontStyleSet_FC(FcPattern** matches, int count) { - fRecCount = count; - fRecs = new Rec[count]; - for (int i = 0; i < count; ++i) { - fRecs[i].fStyleName.set(get_name(matches[i], FC_STYLE)); - fRecs[i].fFileName.set(get_name(matches[i], FC_FILE)); - fRecs[i].fStyle = make_fontconfig_style(matches[i]); + *face = result.fFace; + return true; + }, &face); + return SkSafeRef(face); } -} +}; -SkFontStyleSet_FC::~SkFontStyleSet_FC() { delete[] fRecs; } +/////////////////////////////////////////////////////////////////////////////// -void SkFontStyleSet_FC::getStyle(int index, SkFontStyle* style, - SkString* styleName) { - SkASSERT((unsigned)index < (unsigned)fRecCount); - if (style) { - *style = fRecs[index].fStyle; - } - if (styleName) { - *styleName = fRecs[index].fStyleName; - } -} +static bool find_by_FontIdentity(SkTypeface* cachedTypeface, void* ctx) { + typedef SkFontConfigInterface::FontIdentity FontIdentity; + SkTypeface_FCI* cachedFCTypeface = static_cast<SkTypeface_FCI*>(cachedTypeface); + FontIdentity* identity = static_cast<FontIdentity*>(ctx); -SkTypeface* SkFontStyleSet_FC::createTypeface(int index) { - return nullptr; + return cachedFCTypeface->getIdentity() == *identity; } -SkTypeface* SkFontStyleSet_FC::matchStyle(const SkFontStyle& pattern) { - return nullptr; -} +/////////////////////////////////////////////////////////////////////////////// -class SkFontMgr_fontconfig : public SkFontMgr { +class SkFontMgr_FCI : public SkFontMgr { SkAutoTUnref<SkFontConfigInterface> fFCI; - SkDataTable* fFamilyNames; + SkAutoTUnref<SkDataTable> fFamilyNames; SkTypeface_FreeType::Scanner fScanner; + mutable SkMutex fMutex; + mutable SkTypefaceCache fTFCache; + + // The value of maxSize here is a compromise between cache hits and cache size. + // See https://crbug.com/424082#63 for reason for current size. + static const size_t kMaxSize = 1 << 15; + mutable SkFontRequestCache fCache; + public: - SkFontMgr_fontconfig(SkFontConfigInterface* fci) + SkFontMgr_FCI(SkFontConfigInterface* fci) : fFCI(fci) - , fFamilyNames(fFCI->getFamilyNames()) {} - - virtual ~SkFontMgr_fontconfig() { - SkSafeUnref(fFamilyNames); - } + , fFamilyNames(fFCI->getFamilyNames()) + , fCache(kMaxSize) + {} protected: int onCountFamilies() const override { @@ -242,47 +170,7 @@ protected: } SkFontStyleSet* onMatchFamily(const char familyName[]) const override { - FCLocker lock; - - FcPattern* pattern = FcPatternCreate(); - - FcPatternAddString(pattern, FC_FAMILY, (FcChar8*)familyName); -#if 0 - FcPatternAddBool(pattern, FC_SCALABLE, FcTrue); -#endif - FcConfigSubstitute(nullptr, pattern, FcMatchPattern); - FcDefaultSubstitute(pattern); - - 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 nullptr; - } - - int count; - FcPattern** match = MatchFont(font_set, post_config_family, &count); - if (!match) { - FcPatternDestroy(pattern); - FcFontSetDestroy(font_set); - return nullptr; - } - - 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 = - new SkFontStyleSet_FC(trimmedMatches.begin(), trimmedMatches.count()); - return sset; + return new SkFontStyleSet_FCI(); } SkTypeface* onMatchFamilyStyle(const char familyName[], @@ -314,8 +202,7 @@ protected: return nullptr; } - SkTypeface* face = FontConfigTypeface::Create(style, isFixedWidth, stream.release()); - return face; + return SkTypeface_FCI::Create(style, isFixedWidth, stream.release(), ttcIndex); } SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const override { @@ -323,13 +210,43 @@ protected: return stream.get() ? this->createFromStream(stream.release(), ttcIndex) : nullptr; } - SkTypeface* onLegacyCreateTypeface(const char familyName[], SkFontStyle style) const override { - FCLocker lock; - return FontConfigTypeface::LegacyCreateTypeface(familyName, style); + SkTypeface* onLegacyCreateTypeface(const char requestedFamilyName[], + SkFontStyle requestedStyle) const override + { + SkAutoMutexAcquire ama(fMutex); + + // Check if this request is already in the request cache. + using Request = SkFontRequestCache::Request; + SkAutoTDelete<Request> request(Request::Create(requestedFamilyName, requestedStyle)); + SkTypeface* face = fCache.findAndRef(request); + if (face) { + return face; + } + + SkFontConfigInterface::FontIdentity identity; + SkString outFamilyName; + SkFontStyle outStyle; + if (!fFCI->matchFamilyName(requestedFamilyName, requestedStyle, + &identity, &outFamilyName, &outStyle)) + { + return nullptr; + } + + // Check if a typeface with this FontIdentity is already in the FontIdentity cache. + face = fTFCache.findByProcAndRef(find_by_FontIdentity, &identity); + if (!face) { + face = SkTypeface_FCI::Create(fFCI, identity, outFamilyName, outStyle); + // Add this FontIdentity to the FontIdentity cache. + fTFCache.add(face); + } + // Add this request to the request cache. + fCache.add(face, request.release()); + + return face; } }; -SkFontMgr* SkFontMgr::Factory() { - SkFontConfigInterface* fci = RefFCI(); - return fci ? new SkFontMgr_fontconfig(fci) : nullptr; +SK_API SkFontMgr* SkFontMgr_New_FCI(SkFontConfigInterface* fci) { + SkASSERT(fci); + return new SkFontMgr_FCI(fci); } |