From 0265707c191a31dfde08dd1cd7011c1fe5b8e643 Mon Sep 17 00:00:00 2001 From: bungeman Date: Mon, 2 May 2016 11:54:13 -0700 Subject: [PATCH] Clean up SkFontConfigInterface implementation. Renames some classes to avoid confusion with FontConfig. Removed direct calls to FontConfig instead of calling FCI. Moves the globals and factory to one (optional) file. Moves font management code from typeface to font manager. Adds index to fonts created from streams. Associates FCI typefaces with the FCI instance which provides its identity. Simplifies the singleton initialization. Review-Url: https://codereview.chromium.org/1936213002 --- gyp/ports.gyp | 1 - include/ports/SkFontConfigInterface.h | 7 +- src/fonts/SkFontMgr_fontconfig.cpp | 381 ++++++++------------- src/ports/SkFontConfigInterface_direct.cpp | 56 ++- src/ports/SkFontConfigInterface_direct.h | 3 - src/ports/SkFontConfigInterface_direct_factory.cpp | 14 +- ...kFontConfigInterface_direct_google3_factory.cpp | 14 +- src/ports/SkFontConfigTypeface.h | 43 ++- src/ports/SkFontHost_fontconfig.cpp | 216 +----------- tools/tsan.supp | 1 - 10 files changed, 254 insertions(+), 482 deletions(-) diff --git a/gyp/ports.gyp b/gyp/ports.gyp index fa3db46..2c9f4c2 100644 --- a/gyp/ports.gyp +++ b/gyp/ports.gyp @@ -133,7 +133,6 @@ }, 'sources': [ '../src/ports/SkFontMgr_fontconfig.cpp', - '../src/ports/SkFontHost_fontconfig.cpp', '../src/ports/SkFontConfigInterface_direct.cpp', '../src/ports/SkFontConfigInterface_direct_factory.cpp', ], diff --git a/include/ports/SkFontConfigInterface.h b/include/ports/SkFontConfigInterface.h index 3c68a24..72cad0a 100644 --- a/include/ports/SkFontConfigInterface.h +++ b/include/ports/SkFontConfigInterface.h @@ -14,6 +14,7 @@ #include "SkTypeface.h" struct SkBaseMutex; +class SkFontMgr; /** * \class SkFontConfigInterface @@ -23,7 +24,6 @@ struct SkBaseMutex; */ class SK_API SkFontConfigInterface : public SkRefCnt { public: - /** * Returns the global SkFontConfigInterface instance, and if it is not @@ -110,7 +110,7 @@ public: * libfontconfig. This does not affect the refcnt of the returned instance. * The mutex may be used to guarantee the singleton is only constructed once. */ - static SkFontConfigInterface* GetSingletonDirectInterface(SkBaseMutex* mutex = NULL); + static SkFontConfigInterface* GetSingletonDirectInterface(); // New APIS, which have default impls for now (which do nothing) @@ -118,4 +118,7 @@ public: typedef SkRefCnt INHERITED; }; +/** Creates a SkFontMgr which wraps a SkFontConfigInterface. */ +SK_API SkFontMgr* SkFontMgr_New_FCI(SkFontConfigInterface* fci); + #endif diff --git a/src/fonts/SkFontMgr_fontconfig.cpp b/src/fonts/SkFontMgr_fontconfig.cpp index 9051170..9376964 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 -#include - -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(SkTAfter(&this->fStyle)); + + // No holes. + SkASSERT(SkTAddOffset(this, sizeof(SkResourceCache::Key) + keySize) == content); + + // Has a size divisible by size of uint32_t. + SkASSERT((content - reinterpret_cast(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(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 fRequest; + SkAutoTUnref 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(rec); + SkTypeface** face = static_cast(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(cachedTypeface); + FontIdentity* identity = static_cast(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 fFCI; - SkDataTable* fFamilyNames; + SkAutoTUnref 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 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::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); } diff --git a/src/ports/SkFontConfigInterface_direct.cpp b/src/ports/SkFontConfigInterface_direct.cpp index d384f70..d6fa96a 100644 --- a/src/ports/SkFontConfigInterface_direct.cpp +++ b/src/ports/SkFontConfigInterface_direct.cpp @@ -24,6 +24,56 @@ #include #include +#ifdef SK_DEBUG +# include "SkTLS.h" +#endif + +namespace { + +// Fontconfig is not threadsafe before 2.10.91. Before that, we lock with a global mutex. +// See https://bug.skia.org/1497 for background. +SK_DECLARE_STATIC_MUTEX(gFCMutex); + +#ifdef SK_DEBUG +void* CreateThreadFcLocked() { return new bool(false); } +void DeleteThreadFcLocked(void* v) { delete static_cast(v); } +# define THREAD_FC_LOCKED \ + static_cast(SkTLS::Get(CreateThreadFcLocked, DeleteThreadFcLocked)) +#endif + +struct FCLocker { + // Assume FcGetVersion() has always been thread safe. + + FCLocker() { + if (FcGetVersion() < 21091) { + gFCMutex.acquire(); + } else { + SkDEBUGCODE(bool* threadLocked = THREAD_FC_LOCKED); + SkASSERT(false == *threadLocked); + SkDEBUGCODE(*threadLocked = true); + } + } + + ~FCLocker() { + AssertHeld(); + if (FcGetVersion() < 21091) { + gFCMutex.release(); + } else { + SkDEBUGCODE(*THREAD_FC_LOCKED = false); + } + } + + static void AssertHeld() { SkDEBUGCODE( + if (FcGetVersion() < 21091) { + gFCMutex.assertHeld(); + } else { + SkASSERT(true == *THREAD_FC_LOCKED); + } + ) } +}; + +} // namespace + 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 @@ -448,7 +498,7 @@ static void fcpattern_from_skfontstyle(SkFontStyle style, FcPattern* pattern) { #define kMaxFontFamilyLength 2048 SkFontConfigInterfaceDirect::SkFontConfigInterfaceDirect() { - SkAutoMutexAcquire ac(mutex_); + FCLocker lock; FcInit(); @@ -532,7 +582,7 @@ bool SkFontConfigInterfaceDirect::matchFamilyName(const char familyName[], return false; } - SkAutoMutexAcquire ac(mutex_); + FCLocker lock; FcPattern* pattern = FcPatternCreate(); @@ -649,7 +699,7 @@ static bool find_name(const SkTDArray& list, const char* str) { } SkDataTable* SkFontConfigInterfaceDirect::getFamilyNames() { - SkAutoMutexAcquire ac(mutex_); + FCLocker lock; FcPattern* pat = FcPatternCreate(); SkAutoTCallVProc autoDestroyPat(pat); diff --git a/src/ports/SkFontConfigInterface_direct.h b/src/ports/SkFontConfigInterface_direct.h index 3f0af82..3ccb390 100644 --- a/src/ports/SkFontConfigInterface_direct.h +++ b/src/ports/SkFontConfigInterface_direct.h @@ -8,7 +8,6 @@ /* migrated from chrome/src/skia/ext/SkFontHost_fontconfig_direct.cpp */ #include "SkFontConfigInterface.h" -#include "SkMutex.h" #include @@ -32,8 +31,6 @@ protected: virtual bool isAccessible(const char* filename); private: - SkMutex mutex_; - bool isValidPattern(FcPattern* pattern); FcPattern* MatchFont(FcFontSet* font_set, const char* post_config_family, const SkString& family); diff --git a/src/ports/SkFontConfigInterface_direct_factory.cpp b/src/ports/SkFontConfigInterface_direct_factory.cpp index 58dddab..116ba83 100644 --- a/src/ports/SkFontConfigInterface_direct_factory.cpp +++ b/src/ports/SkFontConfigInterface_direct_factory.cpp @@ -5,16 +5,12 @@ * found in the LICENSE file. */ -/* migrated from chrome/src/skia/ext/SkFontHost_fontconfig_direct.cpp */ - #include "SkFontConfigInterface_direct.h" -#include "SkMutex.h" +#include "SkOnce.h" -SkFontConfigInterface* SkFontConfigInterface::GetSingletonDirectInterface(SkBaseMutex* mutex) { - SkAutoMutexAcquire ac(mutex); - static SkFontConfigInterfaceDirect* singleton = nullptr; - if (singleton == nullptr) { - singleton = new SkFontConfigInterfaceDirect; - } +SkFontConfigInterface* SkFontConfigInterface::GetSingletonDirectInterface() { + static SkFontConfigInterface* singleton; + static SkOnce once; + once([]{ singleton = new SkFontConfigInterfaceDirect(); }); return singleton; } diff --git a/src/ports/SkFontConfigInterface_direct_google3_factory.cpp b/src/ports/SkFontConfigInterface_direct_google3_factory.cpp index f0ac53f..9e863d4 100644 --- a/src/ports/SkFontConfigInterface_direct_google3_factory.cpp +++ b/src/ports/SkFontConfigInterface_direct_google3_factory.cpp @@ -5,16 +5,12 @@ * found in the LICENSE file. */ -/* migrated from chrome/src/skia/ext/SkFontHost_fontconfig_direct.cpp */ - #include "SkFontConfigInterface_direct_google3.h" -#include "SkMutex.h" +#include "SkOnce.h" -SkFontConfigInterface* SkFontConfigInterface::GetSingletonDirectInterface(SkBaseMutex* mutex) { - SkAutoMutexAcquire ac(mutex); - static SkFontConfigInterfaceDirectGoogle3* singleton = nullptr; - if (singleton == nullptr) { - singleton = new SkFontConfigInterfaceDirectGoogle3; - } +SkFontConfigInterface* SkFontConfigInterface::GetSingletonDirectInterface() { + static SkFontConfigInterface* singleton; + static SkOnce once; + once([]{ singleton = new SkFontConfigInterfaceDirectGoogle3(); }); return singleton; } diff --git a/src/ports/SkFontConfigTypeface.h b/src/ports/SkFontConfigTypeface.h index 00e00cf..eb5db94 100644 --- a/src/ports/SkFontConfigTypeface.h +++ b/src/ports/SkFontConfigTypeface.h @@ -12,51 +12,58 @@ class SkFontDescriptor; -class FontConfigTypeface : public SkTypeface_FreeType { +class SkTypeface_FCI : public SkTypeface_FreeType { + SkAutoTUnref fFCI; SkFontConfigInterface::FontIdentity fIdentity; SkString fFamilyName; SkAutoTDelete fLocalStream; public: - static FontConfigTypeface* Create(const SkFontStyle& style, - const SkFontConfigInterface::FontIdentity& fi, - const SkString& familyName) { - return new FontConfigTypeface(style, fi, familyName); + static SkTypeface_FCI* Create(SkFontConfigInterface* fci, + const SkFontConfigInterface::FontIdentity& fi, + const SkString& familyName, + const SkFontStyle& style) + { + return new SkTypeface_FCI(fci, fi, familyName, style); } - static FontConfigTypeface* Create(const SkFontStyle& style, bool fixedWidth, - SkStreamAsset* localStream) { - return new FontConfigTypeface(style, fixedWidth, localStream); + static SkTypeface_FCI* Create(const SkFontStyle& style, bool fixedWidth, + SkStreamAsset* localStream, int index) + { + return new SkTypeface_FCI(style, fixedWidth, localStream, index); } const SkFontConfigInterface::FontIdentity& getIdentity() const { return fIdentity; } - SkStreamAsset* getLocalStream() const { return fLocalStream.get(); } + SkStreamAsset* getLocalStream() const { + return fLocalStream.get(); + } bool isFamilyName(const char* name) const { return fFamilyName.equals(name); } - static SkTypeface* LegacyCreateTypeface(const char familyName[], SkFontStyle); - protected: - FontConfigTypeface(const SkFontStyle& style, - const SkFontConfigInterface::FontIdentity& fi, - const SkString& familyName) + SkTypeface_FCI(SkFontConfigInterface* fci, + const SkFontConfigInterface::FontIdentity& fi, + const SkString& familyName, + const SkFontStyle& style) : INHERITED(style, SkTypefaceCache::NewFontID(), false) + , fFCI(SkRef(fci)) , fIdentity(fi) , fFamilyName(familyName) , fLocalStream(nullptr) {} - FontConfigTypeface(const SkFontStyle& style, bool fixedWidth, SkStreamAsset* localStream) + SkTypeface_FCI(const SkFontStyle& style, bool fixedWidth, SkStreamAsset* localStream, int index) : INHERITED(style, SkTypefaceCache::NewFontID(), fixedWidth) - , fLocalStream(localStream) { - // we default to empty fFamilyName and fIdentity + , fLocalStream(localStream) + { + fIdentity.fTTCIndex = index; } - void onGetFamilyName(SkString* familyName) const override; + void onGetFamilyName(SkString* familyName) const override { *familyName = fFamilyName; } void onGetFontDescriptor(SkFontDescriptor*, bool*) const override; SkStreamAsset* onOpenStream(int* ttcIndex) const override; diff --git a/src/ports/SkFontHost_fontconfig.cpp b/src/ports/SkFontHost_fontconfig.cpp index 1394efd..0ffc261 100644 --- a/src/ports/SkFontHost_fontconfig.cpp +++ b/src/ports/SkFontHost_fontconfig.cpp @@ -6,16 +6,9 @@ */ #include "SkFontConfigInterface.h" -#include "SkFontConfigTypeface.h" -#include "SkFontDescriptor.h" -#include "SkStream.h" -#include "SkTemplates.h" -#include "SkTypeface.h" -#include "SkTypefaceCache.h" -#include "SkResourceCache.h" - -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// +#include "SkFontMgr.h" +#include "SkMutex.h" +#include "SkRefCnt.h" SK_DECLARE_STATIC_MUTEX(gFontConfigInterfaceMutex); static SkFontConfigInterface* gFontConfigInterface; @@ -34,203 +27,18 @@ SkFontConfigInterface* SkFontConfigInterface::SetGlobal(SkFontConfigInterface* f } /////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// - -// convenience function to create the direct interface if none is installed. -extern SkFontConfigInterface* SkCreateDirectFontConfigInterface(); - -static SkFontConfigInterface* RefFCI() { - for (;;) { - SkFontConfigInterface* fci = SkFontConfigInterface::RefGlobal(); - if (fci) { - return fci; - } - fci = SkFontConfigInterface::GetSingletonDirectInterface(&gFontConfigInterfaceMutex); - SkFontConfigInterface::SetGlobal(fci); - } -} - -// export this to SkFontMgr_fontconfig.cpp until this file just goes away. -SkFontConfigInterface* SkFontHost_fontconfig_ref_global(); -SkFontConfigInterface* SkFontHost_fontconfig_ref_global() { - return RefFCI(); -} - -/////////////////////////////////////////////////////////////////////////////// - -static bool find_by_FontIdentity(SkTypeface* cachedTypeface, void* ctx) { - typedef SkFontConfigInterface::FontIdentity FontIdentity; - FontConfigTypeface* cachedFCTypeface = static_cast(cachedTypeface); - FontIdentity* identity = static_cast(ctx); - - return cachedFCTypeface->getIdentity() == *identity; -} - -SK_DECLARE_STATIC_MUTEX(gSkFontHostRequestCacheMutex); -class SkFontHostRequestCache { - - // 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 gMaxSize = 1 << 15; - - static SkFontHostRequestCache& Get() { - gSkFontHostRequestCacheMutex.assertHeld(); - static SkFontHostRequestCache gCache(gMaxSize); - return gCache; - } - -public: - 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(SkTAfter(&this->fStyle)); - - // No holes. - SkASSERT(SkTAddOffset(this, sizeof(SkResourceCache::Key) + keySize) == content); - - // Has a size divisible by size of uint32_t. - SkASSERT((content - reinterpret_cast(this)) % sizeof(uint32_t) == 0); - - size_t contentLen = SkAlign4(nameLen); - sk_careful_memcpy(content, name, nameLen); - sk_bzero(content + nameLen, contentLen - nameLen); - this->init(&gSkFontHostRequestCacheMutex, 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(storage); - } - }; - - -private: - 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 fRequest; - SkAutoTUnref fFace; - }; - SkResourceCache fCachedResults; - -public: - SkFontHostRequestCache(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)); - } - /** 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(rec); - SkTypeface** face = static_cast(context); - - *face = result.fFace; - return true; - }, &face); - return SkSafeRef(face); - } - - /** Takes ownership of request. It will be deleted when no longer needed. */ - static void Add(SkTypeface* face, Request* request) { - SkAutoMutexAcquire ama(gSkFontHostRequestCacheMutex); - Get().add(face, request); - } - - /** Does not take ownership of request. */ - static SkTypeface* FindAndRef(Request* request) { - SkAutoMutexAcquire ama(gSkFontHostRequestCacheMutex); - return Get().findAndRef(request); - } -}; - -SkTypeface* FontConfigTypeface::LegacyCreateTypeface(const char requestedFamilyName[], - SkFontStyle requestedStyle) -{ - SkAutoTUnref fci(RefFCI()); - if (nullptr == fci.get()) { - return nullptr; - } - - // Check if this request is already in the request cache. - using Request = SkFontHostRequestCache::Request; - SkAutoTDelete request(Request::Create(requestedFamilyName, requestedStyle)); - SkTypeface* face = SkFontHostRequestCache::FindAndRef(request); - if (face) { - return face; - } - - SkFontConfigInterface::FontIdentity identity; - SkString outFamilyName; - SkFontStyle outStyle; - if (!fci->matchFamilyName(requestedFamilyName, requestedStyle, - &identity, &outFamilyName, &outStyle)) - { - return nullptr; - } - - // Check if a typeface with this FontIdentity is already in the FontIdentity cache. - face = SkTypefaceCache::FindByProcAndRef(find_by_FontIdentity, &identity); - if (!face) { - face = FontConfigTypeface::Create(outStyle, identity, outFamilyName); - // Add this FontIdentity to the FontIdentity cache. - SkTypefaceCache::Add(face); - } - // Add this request to the request cache. - SkFontHostRequestCache::Add(face, request.release()); - - return face; -} - -/////////////////////////////////////////////////////////////////////////////// - -SkStreamAsset* FontConfigTypeface::onOpenStream(int* ttcIndex) const { - SkStreamAsset* stream = this->getLocalStream(); - if (stream) { - // TODO: should have been provided by CreateFromStream() - *ttcIndex = 0; - return stream->duplicate(); - } +static SkFontConfigInterface* init_FCI() { + SkAutoMutexAcquire ac(gFontConfigInterfaceMutex); - SkAutoTUnref fci(RefFCI()); - if (nullptr == fci.get()) { - return nullptr; + if (gFontConfigInterface) { + return SkRef(gFontConfigInterface); } - - *ttcIndex = this->getIdentity().fTTCIndex; - return fci->openStream(this->getIdentity()); -} - -void FontConfigTypeface::onGetFamilyName(SkString* familyName) const { - *familyName = fFamilyName; + gFontConfigInterface = SkRef(SkFontConfigInterface::GetSingletonDirectInterface()); + return gFontConfigInterface; } -void FontConfigTypeface::onGetFontDescriptor(SkFontDescriptor* desc, - bool* isLocalStream) const { - SkString name; - this->getFamilyName(&name); - desc->setFamilyName(name.c_str()); - *isLocalStream = SkToBool(this->getLocalStream()); +SkFontMgr* SkFontMgr::Factory() { + SkFontConfigInterface* fci = init_FCI(); + return fci ? SkFontMgr_New_FCI(fci) : nullptr; } diff --git a/tools/tsan.supp b/tools/tsan.supp index 4333ec2..f903781 100644 --- a/tools/tsan.supp +++ b/tools/tsan.supp @@ -13,5 +13,4 @@ race:third_party/externals/libwebp race:SkGLContextHelper # Not threadsafe, should be fixed. -race:RefFCI race:SkString -- 2.7.4