aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/ports
diff options
context:
space:
mode:
authorGravatar bungeman <bungeman@google.com>2016-02-17 10:13:49 -0800
committerGravatar Commit bot <commit-bot@chromium.org>2016-02-17 10:13:49 -0800
commit70bb80802198b7fedee58f79d0d68d5f8aba8b62 (patch)
tree3363569b449e26baef43a28fa2fed1ff33cabe0f /src/ports
parent8715d47e247bf890ee78af0774ae7e8698146b67 (diff)
Add request cache to SkFontHost_fontconfig.
The current code deduplicates SkTypeface instances as all font lookups should for better use of the glyph cache. This adds a request cache as well, so that repeated recent requests will return the cached result instead of doing a full lookup. BUG=chromium:424082, chromium:444894 Review URL: https://codereview.chromium.org/1683883002
Diffstat (limited to 'src/ports')
-rw-r--r--src/ports/SkFontHost_fontconfig.cpp161
1 files changed, 120 insertions, 41 deletions
diff --git a/src/ports/SkFontHost_fontconfig.cpp b/src/ports/SkFontHost_fontconfig.cpp
index 5c9e896617..f91b7a0c2c 100644
--- a/src/ports/SkFontHost_fontconfig.cpp
+++ b/src/ports/SkFontHost_fontconfig.cpp
@@ -9,8 +9,10 @@
#include "SkFontConfigTypeface.h"
#include "SkFontDescriptor.h"
#include "SkStream.h"
+#include "SkTemplates.h"
#include "SkTypeface.h"
#include "SkTypefaceCache.h"
+#include "SkResourceCache.h"
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
@@ -56,72 +58,149 @@ SkFontConfigInterface* SkFontHost_fontconfig_ref_global() {
///////////////////////////////////////////////////////////////////////////////
-struct NameStyle {
- NameStyle(const char* name, const SkFontStyle& style)
- : fFamilyName(name) // don't need to make a deep copy
- , fStyle(style) {}
-
- const char* fFamilyName;
- SkFontStyle fStyle;
-};
-
-static bool find_by_NameStyle(SkTypeface* cachedTypeface,
- const SkFontStyle& cachedStyle,
- void* ctx)
-{
- FontConfigTypeface* cachedFCTypeface = static_cast<FontConfigTypeface*>(cachedTypeface);
- const NameStyle* nameStyle = static_cast<const NameStyle*>(ctx);
-
- return nameStyle->fStyle == cachedStyle &&
- cachedFCTypeface->isFamilyName(nameStyle->fFamilyName);
-}
-
static bool find_by_FontIdentity(SkTypeface* cachedTypeface, const SkFontStyle&, void* ctx) {
typedef SkFontConfigInterface::FontIdentity FontIdentity;
FontConfigTypeface* cachedFCTypeface = static_cast<FontConfigTypeface*>(cachedTypeface);
- FontIdentity* indentity = static_cast<FontIdentity*>(ctx);
+ FontIdentity* identity = static_cast<FontIdentity*>(ctx);
- return cachedFCTypeface->getIdentity() == *indentity;
+ return cachedFCTypeface->getIdentity() == *identity;
}
-SkTypeface* FontConfigTypeface::LegacyCreateTypeface(const char familyName[],
- SkTypeface::Style style)
+SK_DECLARE_STATIC_MUTEX(gSkFontHostRequestCacheMutex);
+class SkFontHostRequestCache {
+
+ // The value of maxSize here is a compromise between cache hits and cache size.
+ static const size_t gMaxSize = 1 << 12;
+
+ 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<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(&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<char*>(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<Request> fRequest;
+ SkAutoTUnref<SkTypeface> 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<const Result&>(rec);
+ SkTypeface** face = static_cast<SkTypeface**>(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[],
+ SkTypeface::Style requestedOldStyle)
{
SkAutoTUnref<SkFontConfigInterface> fci(RefFCI());
if (nullptr == fci.get()) {
return nullptr;
}
- // Check if requested NameStyle is in the NameStyle cache.
- SkFontStyle requestedStyle(style);
- NameStyle nameStyle(familyName, requestedStyle);
- SkTypeface* face = SkTypefaceCache::FindByProcAndRef(find_by_NameStyle, &nameStyle);
+ // Check if this request is already in the request cache.
+ using Request = SkFontHostRequestCache::Request;
+ SkFontStyle requestedStyle(requestedOldStyle);
+ SkAutoTDelete<Request> request(Request::Create(requestedFamilyName, requestedStyle));
+ SkTypeface* face = SkFontHostRequestCache::FindAndRef(request);
if (face) {
- //SkDebugf("found cached face <%s> <%s> %p [%d]\n",
- // familyName, ((FontConfigTypeface*)face)->getFamilyName(),
- // face, face->getRefCnt());
return face;
}
- SkFontConfigInterface::FontIdentity indentity;
+ SkFontConfigInterface::FontIdentity identity;
SkString outFamilyName;
- SkTypeface::Style outStyle;
- if (!fci->matchFamilyName(familyName, style, &indentity, &outFamilyName, &outStyle)) {
+ SkTypeface::Style outOldStyle;
+ if (!fci->matchFamilyName(requestedFamilyName, requestedOldStyle,
+ &identity, &outFamilyName, &outOldStyle))
+ {
return nullptr;
}
// Check if a typeface with this FontIdentity is already in the FontIdentity cache.
- face = SkTypefaceCache::FindByProcAndRef(find_by_FontIdentity, &indentity);
+ face = SkTypefaceCache::FindByProcAndRef(find_by_FontIdentity, &identity);
if (!face) {
- face = FontConfigTypeface::Create(SkFontStyle(outStyle), indentity, outFamilyName);
+ face = FontConfigTypeface::Create(SkFontStyle(outOldStyle), identity, outFamilyName);
// Add this FontIdentity to the FontIdentity cache.
- SkTypefaceCache::Add(face, requestedStyle);
+ SkTypefaceCache::Add(face, SkFontStyle(outOldStyle));
}
- // TODO: Ensure requested NameStyle and resolved NameStyle are both in the NameStyle cache.
+ // Add this request to the request cache.
+ SkFontHostRequestCache::Add(face, request.release());
- //SkDebugf("add face <%s> <%s> %p [%d]\n",
- // familyName, outFamilyName.c_str(),
- // face, face->getRefCnt());
return face;
}