aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/fonts
diff options
context:
space:
mode:
authorGravatar bungeman <bungeman@google.com>2016-05-02 11:54:13 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2016-05-02 11:54:13 -0700
commit0265707c191a31dfde08dd1cd7011c1fe5b8e643 (patch)
tree919635b2cf13cc3c639126c42e6098130e2e2c30 /src/fonts
parentc5091b5b6c4b8a7aef8c12db9ea2a85e907b01c4 (diff)
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
Diffstat (limited to 'src/fonts')
-rw-r--r--src/fonts/SkFontMgr_fontconfig.cpp381
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);
}