SkGlyphCache - update core routines.
- Allows different methods for creating SkGlyphCaches - Enables passing FontMetrics for cache creation. - Removes VisitCache - Removes VisitAll - Introduces SkExclusiveStrikePtr which should replaces SkAutoGlyphCache with simpler mechanism. BUG=skia:7515 Change-Id: Ibada35e3985335179d2cc8284a837fc525224c92 Reviewed-on: https://skia-review.googlesource.com/111063 Reviewed-by: Ben Wagner <bungeman@google.com> Reviewed-by: Herb Derby <herb@google.com> Commit-Queue: Herb Derby <herb@google.com>
This commit is contained in:
parent
2a4f983c94
commit
dfeb2aa13b
@ -365,6 +365,9 @@ private:
|
|||||||
};
|
};
|
||||||
static SkFontStyle FromOldStyle(Style oldStyle);
|
static SkFontStyle FromOldStyle(Style oldStyle);
|
||||||
static SkTypeface* GetDefaultTypeface(Style style = SkTypeface::kNormal);
|
static SkTypeface* GetDefaultTypeface(Style style = SkTypeface::kNormal);
|
||||||
|
static SkTypeface* NormalizeTypeface(SkTypeface* typeface) {
|
||||||
|
return typeface != nullptr ? typeface : SkTypeface::GetDefaultTypeface();
|
||||||
|
}
|
||||||
friend class GrPathRendering; // GetDefaultTypeface
|
friend class GrPathRendering; // GetDefaultTypeface
|
||||||
friend class SkGlyphCache; // GetDefaultTypeface
|
friend class SkGlyphCache; // GetDefaultTypeface
|
||||||
friend class SkPaint; // GetDefaultTypeface
|
friend class SkPaint; // GetDefaultTypeface
|
||||||
|
@ -7,7 +7,6 @@
|
|||||||
|
|
||||||
|
|
||||||
#include "SkGlyphCache.h"
|
#include "SkGlyphCache.h"
|
||||||
#include "SkGlyphCache_Globals.h"
|
|
||||||
#include "SkGraphics.h"
|
#include "SkGraphics.h"
|
||||||
#include "SkOnce.h"
|
#include "SkOnce.h"
|
||||||
#include "SkPath.h"
|
#include "SkPath.h"
|
||||||
@ -34,14 +33,12 @@ static SkGlyphCache_Globals& get_globals() {
|
|||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
SkGlyphCache::SkGlyphCache(const SkDescriptor* desc, std::unique_ptr<SkScalerContext> ctx)
|
SkGlyphCache::SkGlyphCache(const SkDescriptor& desc, std::unique_ptr<SkScalerContext> ctx)
|
||||||
: fDesc(desc->copy())
|
: fDesc(desc.copy())
|
||||||
, fScalerContext(std::move(ctx)) {
|
, fScalerContext(std::move(ctx))
|
||||||
SkASSERT(desc);
|
{
|
||||||
SkASSERT(fScalerContext);
|
SkASSERT(fScalerContext);
|
||||||
|
|
||||||
fPrev = fNext = nullptr;
|
|
||||||
|
|
||||||
fScalerContext->getFontMetrics(&fFontMetrics);
|
fScalerContext->getFontMetrics(&fFontMetrics);
|
||||||
|
|
||||||
fMemoryUsed = sizeof(*this);
|
fMemoryUsed = sizeof(*this);
|
||||||
@ -55,6 +52,10 @@ SkGlyphCache::~SkGlyphCache() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SkGlyphCache::PurgeAll() {
|
||||||
|
get_globals().purgeAll();
|
||||||
|
}
|
||||||
|
|
||||||
SkGlyphCache::CharGlyphRec* SkGlyphCache::getCharGlyphRec(SkPackedUnicharID packedUnicharID) {
|
SkGlyphCache::CharGlyphRec* SkGlyphCache::getCharGlyphRec(SkPackedUnicharID packedUnicharID) {
|
||||||
if (!fPackedUnicharIDToPackedGlyphID) {
|
if (!fPackedUnicharIDToPackedGlyphID) {
|
||||||
fPackedUnicharIDToPackedGlyphID.reset(new CharGlyphRec[kHashCount]);
|
fPackedUnicharIDToPackedGlyphID.reset(new CharGlyphRec[kHashCount]);
|
||||||
@ -102,6 +103,15 @@ int SkGlyphCache::countCachedGlyphs() const {
|
|||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
bool SkGlyphCache::isGlyphCached(SkGlyphID glyphID, SkFixed x, SkFixed y) const {
|
||||||
|
SkPackedGlyphID packedGlyphID{glyphID, x, y};
|
||||||
|
return fGlyphMap.find(packedGlyphID) != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
SkGlyph* SkGlyphCache::getRawGlyphByID(SkPackedGlyphID id) {
|
||||||
|
return lookupByPackedGlyphID(id, kNothing_MetricsType);
|
||||||
|
}
|
||||||
|
|
||||||
const SkGlyph& SkGlyphCache::getUnicharAdvance(SkUnichar charCode) {
|
const SkGlyph& SkGlyphCache::getUnicharAdvance(SkUnichar charCode) {
|
||||||
VALIDATE();
|
VALIDATE();
|
||||||
return *this->lookupByChar(charCode, kJustAdvance_MetricsType);
|
return *this->lookupByChar(charCode, kJustAdvance_MetricsType);
|
||||||
@ -170,7 +180,9 @@ SkGlyph* SkGlyphCache::allocateNewGlyph(SkPackedGlyphID packedGlyphID, MetricsTy
|
|||||||
glyphPtr = fGlyphMap.set(glyph);
|
glyphPtr = fGlyphMap.set(glyph);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kJustAdvance_MetricsType == mtype) {
|
if (kNothing_MetricsType == mtype) {
|
||||||
|
return glyphPtr;
|
||||||
|
} else if (kJustAdvance_MetricsType == mtype) {
|
||||||
fScalerContext->getAdvance(glyphPtr);
|
fScalerContext->getAdvance(glyphPtr);
|
||||||
} else {
|
} else {
|
||||||
SkASSERT(kFull_MetricsType == mtype);
|
SkASSERT(kFull_MetricsType == mtype);
|
||||||
@ -469,92 +481,43 @@ void SkGlyphCache_Globals::purgeAll() {
|
|||||||
this->internalPurge(fTotalMemoryUsed);
|
this->internalPurge(fTotalMemoryUsed);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This guy calls the visitor from within the mutext lock, so the visitor
|
SkExclusiveStrikePtr SkGlyphCache::FindStrikeExclusive(const SkDescriptor& desc) {
|
||||||
cannot:
|
|
||||||
- take too much time
|
|
||||||
- try to acquire the mutext again
|
|
||||||
- call a fontscaler (which might call into the cache)
|
|
||||||
*/
|
|
||||||
SkGlyphCache* SkGlyphCache::VisitCache(SkTypeface* typeface,
|
|
||||||
const SkScalerContextEffects& effects,
|
|
||||||
const SkDescriptor* desc,
|
|
||||||
bool (*proc)(const SkGlyphCache*, void*),
|
|
||||||
void* context) {
|
|
||||||
if (!typeface) {
|
|
||||||
typeface = SkTypeface::GetDefaultTypeface();
|
|
||||||
}
|
|
||||||
SkASSERT(desc);
|
|
||||||
|
|
||||||
// Precondition: the typeface id must be the fFontID in the descriptor
|
|
||||||
SkDEBUGCODE(
|
|
||||||
uint32_t length = 0;
|
|
||||||
const SkScalerContextRec* rec = static_cast<const SkScalerContextRec*>(
|
|
||||||
desc->findEntry(kRec_SkDescriptorTag, &length));
|
|
||||||
SkASSERT(rec);
|
|
||||||
SkASSERT(length == sizeof(*rec));
|
|
||||||
SkASSERT(typeface->uniqueID() == rec->fFontID);
|
|
||||||
)
|
|
||||||
|
|
||||||
SkGlyphCache_Globals& globals = get_globals();
|
SkGlyphCache_Globals& globals = get_globals();
|
||||||
SkGlyphCache* cache;
|
SkGlyphCache* cache;
|
||||||
|
SkAutoExclusive ac(globals.fLock);
|
||||||
|
|
||||||
{
|
for (cache = globals.internalGetHead(); cache != nullptr; cache = cache->fNext) {
|
||||||
SkAutoExclusive ac(globals.fLock);
|
if (*cache->fDesc == desc) {
|
||||||
|
globals.internalDetachCache(cache);
|
||||||
globals.validate();
|
return SkExclusiveStrikePtr(cache);
|
||||||
|
|
||||||
for (cache = globals.internalGetHead(); cache != nullptr; cache = cache->fNext) {
|
|
||||||
if (*cache->fDesc == *desc) {
|
|
||||||
globals.internalDetachCache(cache);
|
|
||||||
if (!proc(cache, context)) {
|
|
||||||
globals.internalAttachCacheToHead(cache);
|
|
||||||
cache = nullptr;
|
|
||||||
}
|
|
||||||
return cache;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if we can create a scaler-context before creating the glyphcache.
|
return SkExclusiveStrikePtr(nullptr);
|
||||||
// If not, we may have exhausted OS/font resources, so try purging the
|
}
|
||||||
// cache once and try again.
|
|
||||||
{
|
|
||||||
// pass true the first time, to notice if the scalercontext failed,
|
|
||||||
// so we can try the purge.
|
|
||||||
std::unique_ptr<SkScalerContext> ctx = typeface->createScalerContext(effects, desc, true);
|
|
||||||
if (!ctx) {
|
|
||||||
get_globals().purgeAll();
|
|
||||||
ctx = typeface->createScalerContext(effects, desc, false);
|
|
||||||
SkASSERT(ctx);
|
|
||||||
}
|
|
||||||
cache = new SkGlyphCache(desc, std::move(ctx));
|
|
||||||
}
|
|
||||||
|
|
||||||
AutoValidate av(cache);
|
SkExclusiveStrikePtr SkGlyphCache::FindOrCreateStrikeExclusive(
|
||||||
|
const SkDescriptor& desc, const SkScalerContextEffects& effects, const SkTypeface& typeface) {
|
||||||
if (!proc(cache, context)) { // need to reattach
|
auto creator = [&effects, &typeface](const SkDescriptor& descriptor, bool canFail) {
|
||||||
globals.attachCacheToHead(cache);
|
return typeface.createScalerContext(effects, &descriptor, canFail);
|
||||||
cache = nullptr;
|
};
|
||||||
}
|
return FindOrCreateStrikeExclusive(desc, creator);
|
||||||
return cache;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkGlyphCache::AttachCache(SkGlyphCache* cache) {
|
void SkGlyphCache::AttachCache(SkGlyphCache* cache) {
|
||||||
SkASSERT(cache);
|
SkGlyphCache_Globals::AttachCache(cache);
|
||||||
SkASSERT(cache->fNext == nullptr);
|
|
||||||
|
|
||||||
get_globals().attachCacheToHead(cache);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dump_visitor(const SkGlyphCache& cache, void* context) {
|
void SkGlyphCache::ForEachStrike(std::function<void(const SkGlyphCache&)> visitor) {
|
||||||
int* counter = (int*)context;
|
SkGlyphCache_Globals& globals = get_globals();
|
||||||
int index = *counter;
|
SkAutoExclusive ac(globals.fLock);
|
||||||
*counter += 1;
|
SkGlyphCache* cache;
|
||||||
|
|
||||||
const SkScalerContextRec& rec = cache.getScalerContext()->getRec();
|
globals.validate();
|
||||||
|
|
||||||
SkDebugf("index %d\n", index);
|
for (cache = globals.internalGetHead(); cache != nullptr; cache = cache->fNext) {
|
||||||
SkDebugf("%s", rec.dump().c_str());
|
visitor(*cache);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkGlyphCache::Dump() {
|
void SkGlyphCache::Dump() {
|
||||||
@ -565,30 +528,16 @@ void SkGlyphCache::Dump() {
|
|||||||
SkGraphics::GetFontCacheCountUsed(), SkGraphics::GetFontCacheCountLimit());
|
SkGraphics::GetFontCacheCountUsed(), SkGraphics::GetFontCacheCountLimit());
|
||||||
|
|
||||||
int counter = 0;
|
int counter = 0;
|
||||||
SkGlyphCache::VisitAll(dump_visitor, &counter);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void sk_trace_dump_visitor(const SkGlyphCache& cache, void* context) {
|
auto visitor = [&counter](const SkGlyphCache& cache) {
|
||||||
SkTraceMemoryDump* dump = static_cast<SkTraceMemoryDump*>(context);
|
const SkScalerContextRec& rec = cache.getScalerContext()->getRec();
|
||||||
|
|
||||||
const SkTypeface* face = cache.getScalerContext()->getTypeface();
|
SkDebugf("index %d\n", counter);
|
||||||
const SkScalerContextRec& rec = cache.getScalerContext()->getRec();
|
SkDebugf("%s", rec.dump().c_str());
|
||||||
|
counter += 1;
|
||||||
|
};
|
||||||
|
|
||||||
SkString fontName;
|
ForEachStrike(visitor);
|
||||||
face->getFamilyName(&fontName);
|
|
||||||
// Replace all special characters with '_'.
|
|
||||||
for (size_t index = 0; index < fontName.size(); ++index) {
|
|
||||||
if (!std::isalnum(fontName[index])) {
|
|
||||||
fontName[index] = '_';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SkString dumpName = SkStringPrintf("%s/%s_%d/%p",
|
|
||||||
gGlyphCacheDumpName, fontName.c_str(), rec.fFontID, &cache);
|
|
||||||
|
|
||||||
dump->dumpNumericValue(dumpName.c_str(), "size", "bytes", cache.getMemoryUsed());
|
|
||||||
dump->dumpNumericValue(dumpName.c_str(), "glyph_count", "objects", cache.countCachedGlyphs());
|
|
||||||
dump->setMemoryBacking(dumpName.c_str(), "malloc", nullptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkGlyphCache::DumpMemoryStatistics(SkTraceMemoryDump* dump) {
|
void SkGlyphCache::DumpMemoryStatistics(SkTraceMemoryDump* dump) {
|
||||||
@ -605,23 +554,53 @@ void SkGlyphCache::DumpMemoryStatistics(SkTraceMemoryDump* dump) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SkGlyphCache::VisitAll(sk_trace_dump_visitor, dump);
|
auto visitor = [&dump](const SkGlyphCache& cache) {
|
||||||
}
|
const SkTypeface* face = cache.getScalerContext()->getTypeface();
|
||||||
|
const SkScalerContextRec& rec = cache.getScalerContext()->getRec();
|
||||||
|
|
||||||
void SkGlyphCache::VisitAll(Visitor visitor, void* context) {
|
SkString fontName;
|
||||||
SkGlyphCache_Globals& globals = get_globals();
|
face->getFamilyName(&fontName);
|
||||||
SkAutoExclusive ac(globals.fLock);
|
// Replace all special characters with '_'.
|
||||||
SkGlyphCache* cache;
|
for (size_t index = 0; index < fontName.size(); ++index) {
|
||||||
|
if (!std::isalnum(fontName[index])) {
|
||||||
|
fontName[index] = '_';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
globals.validate();
|
SkString dumpName = SkStringPrintf(
|
||||||
|
"%s/%s_%d/%p", gGlyphCacheDumpName, fontName.c_str(), rec.fFontID, &cache);
|
||||||
|
|
||||||
for (cache = globals.internalGetHead(); cache != nullptr; cache = cache->fNext) {
|
dump->dumpNumericValue(dumpName.c_str(),
|
||||||
visitor(*cache, context);
|
"size", "bytes", cache.getMemoryUsed());
|
||||||
}
|
dump->dumpNumericValue(dumpName.c_str(),
|
||||||
|
"glyph_count", "objects", cache.countCachedGlyphs());
|
||||||
|
dump->setMemoryBacking(dumpName.c_str(), "malloc", nullptr);
|
||||||
|
};
|
||||||
|
|
||||||
|
ForEachStrike(visitor);
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
SkGlyphCache_Globals::~SkGlyphCache_Globals() {
|
||||||
|
SkGlyphCache* cache = fHead;
|
||||||
|
while (cache) {
|
||||||
|
SkGlyphCache* next = cache->fNext;
|
||||||
|
delete cache;
|
||||||
|
cache = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SkGlyphCache_Globals::AttachCache(SkGlyphCache* cache) {
|
||||||
|
if (cache == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SkASSERT(cache->fNext == nullptr);
|
||||||
|
|
||||||
|
get_globals().attachCacheToHead(cache);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void SkGlyphCache_Globals::attachCacheToHead(SkGlyphCache* cache) {
|
void SkGlyphCache_Globals::attachCacheToHead(SkGlyphCache* cache) {
|
||||||
SkAutoExclusive ac(fLock);
|
SkAutoExclusive ac(fLock);
|
||||||
|
|
||||||
@ -806,6 +785,15 @@ void SkGraphics::PurgeFontCache() {
|
|||||||
size_t SkGraphics::GetTLSFontCacheLimit() { return 0; }
|
size_t SkGraphics::GetTLSFontCacheLimit() { return 0; }
|
||||||
void SkGraphics::SetTLSFontCacheLimit(size_t bytes) { }
|
void SkGraphics::SetTLSFontCacheLimit(size_t bytes) { }
|
||||||
|
|
||||||
|
SkGlyphCache* SkGlyphCache::DetachCache(
|
||||||
|
SkTypeface* typeface, const SkScalerContextEffects& effects, const SkDescriptor* desc)
|
||||||
|
{
|
||||||
|
|
||||||
|
auto cache = FindOrCreateStrikeExclusive(
|
||||||
|
*desc, effects, *SkTypeface::NormalizeTypeface(typeface));
|
||||||
|
return cache.release();
|
||||||
|
}
|
||||||
|
|
||||||
SkGlyphCache* SkGlyphCache::DetachCacheUsingPaint(const SkPaint& paint,
|
SkGlyphCache* SkGlyphCache::DetachCacheUsingPaint(const SkPaint& paint,
|
||||||
const SkSurfaceProps* surfaceProps,
|
const SkSurfaceProps* surfaceProps,
|
||||||
SkScalerContextFlags scalerContextFlags,
|
SkScalerContextFlags scalerContextFlags,
|
||||||
|
@ -8,19 +8,21 @@
|
|||||||
#define SkGlyphCache_DEFINED
|
#define SkGlyphCache_DEFINED
|
||||||
|
|
||||||
#include "SkArenaAlloc.h"
|
#include "SkArenaAlloc.h"
|
||||||
#include "SkBitmap.h"
|
|
||||||
#include "SkDescriptor.h"
|
#include "SkDescriptor.h"
|
||||||
#include "SkGlyph.h"
|
#include "SkGlyph.h"
|
||||||
|
#include "SkGlyphCache_Globals.h"
|
||||||
#include "SkPaint.h"
|
#include "SkPaint.h"
|
||||||
#include "SkTHash.h"
|
#include "SkTHash.h"
|
||||||
#include "SkScalerContext.h"
|
#include "SkScalerContext.h"
|
||||||
#include "SkTemplates.h"
|
#include "SkTemplates.h"
|
||||||
#include "SkTDArray.h"
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
class SkTraceMemoryDump;
|
class SkTraceMemoryDump;
|
||||||
|
|
||||||
class SkGlyphCache_Globals;
|
class SkGlyphCache;
|
||||||
|
using SkExclusiveStrikePtr = std::unique_ptr<
|
||||||
|
SkGlyphCache,
|
||||||
|
SkFunctionWrapper<void, SkGlyphCache, SkGlyphCache_Globals::AttachCache>>;
|
||||||
|
|
||||||
/** \class SkGlyphCache
|
/** \class SkGlyphCache
|
||||||
|
|
||||||
@ -30,10 +32,19 @@ class SkGlyphCache_Globals;
|
|||||||
it and then adding it to the strike.
|
it and then adding it to the strike.
|
||||||
|
|
||||||
The strikes are held in a global list, available to all threads. To interact with one, call
|
The strikes are held in a global list, available to all threads. To interact with one, call
|
||||||
either VisitCache() or DetachCache().
|
either Find*() or (Deprecated)DetachCache().
|
||||||
|
|
||||||
|
The Find*Exclusive() method returns SkExclusiveStrikePtr, which releases exclusive ownership
|
||||||
|
when they go out of scope.
|
||||||
*/
|
*/
|
||||||
class SkGlyphCache {
|
class SkGlyphCache {
|
||||||
public:
|
public:
|
||||||
|
/** Return true if glyph is cached. */
|
||||||
|
bool isGlyphCached(SkGlyphID glyphID, SkFixed x, SkFixed y) const;
|
||||||
|
|
||||||
|
/** Return a glyph that has no information if it is not already filled out. */
|
||||||
|
SkGlyph* getRawGlyphByID(SkPackedGlyphID);
|
||||||
|
|
||||||
/** Returns a glyph with valid fAdvance and fDevKern fields. The remaining fields may be
|
/** Returns a glyph with valid fAdvance and fDevKern fields. The remaining fields may be
|
||||||
valid, but that is not guaranteed. If you require those, call getUnicharMetrics or
|
valid, but that is not guaranteed. If you require those, call getUnicharMetrics or
|
||||||
getGlyphIDMetrics instead.
|
getGlyphIDMetrics instead.
|
||||||
@ -112,19 +123,49 @@ public:
|
|||||||
|
|
||||||
SkScalerContext* getScalerContext() const { return fScalerContext.get(); }
|
SkScalerContext* getScalerContext() const { return fScalerContext.get(); }
|
||||||
|
|
||||||
/** Find a matching cache entry, and call proc() with it. If none is found create a new one.
|
|
||||||
If the proc() returns true, detach the cache and return it, otherwise leave it and return
|
|
||||||
nullptr.
|
|
||||||
*/
|
|
||||||
static SkGlyphCache* VisitCache(SkTypeface*, const SkScalerContextEffects&, const SkDescriptor*,
|
|
||||||
bool (*proc)(const SkGlyphCache*, void*),
|
|
||||||
void* context);
|
|
||||||
|
|
||||||
/** Given a strike that was returned by either VisitCache() or DetachCache() add it back into
|
/** Given a strike that was returned by DetachCache() add it back into
|
||||||
the global cache list (after which the caller should not reference it anymore.
|
the global cache list (after which the caller should not reference it anymore.
|
||||||
|
DEPRECATED - Use Find* and rely on RAII.
|
||||||
*/
|
*/
|
||||||
static void AttachCache(SkGlyphCache*);
|
static void AttachCache(SkGlyphCache*);
|
||||||
using AttachCacheFunctor = SkFunctionWrapper<void, SkGlyphCache, AttachCache>;
|
|
||||||
|
static SkExclusiveStrikePtr FindStrikeExclusive(const SkDescriptor& desc);
|
||||||
|
|
||||||
|
template <typename ScalerContextCreator>
|
||||||
|
static SkExclusiveStrikePtr FindOrCreateStrikeExclusive(
|
||||||
|
const SkDescriptor& desc, ScalerContextCreator&& creator)
|
||||||
|
{
|
||||||
|
auto cache = FindStrikeExclusive(desc);
|
||||||
|
if (cache == nullptr) {
|
||||||
|
cache = CreateStrikeExclusive(desc, creator);
|
||||||
|
}
|
||||||
|
return cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
static SkExclusiveStrikePtr FindOrCreateStrikeExclusive(
|
||||||
|
const SkDescriptor& desc,
|
||||||
|
const SkScalerContextEffects& effects,
|
||||||
|
const SkTypeface& typeface);
|
||||||
|
|
||||||
|
template <typename ScalerContextCreator>
|
||||||
|
static SkExclusiveStrikePtr CreateStrikeExclusive(
|
||||||
|
const SkDescriptor& desc, ScalerContextCreator creator)
|
||||||
|
{
|
||||||
|
// Check if we can create a scaler-context before creating the glyphcache.
|
||||||
|
// If not, we may have exhausted OS/font resources, so try purging the
|
||||||
|
// cache once and try again
|
||||||
|
// pass true the first time, to notice if the scalercontext failed,
|
||||||
|
// so we can try the purge.
|
||||||
|
auto context = creator(desc, true/* can fail */);
|
||||||
|
if (!context) {
|
||||||
|
PurgeAll();
|
||||||
|
context = creator(desc, false/* must succeed */);
|
||||||
|
SkASSERT(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
return SkExclusiveStrikePtr(new SkGlyphCache(desc, std::move(context)));
|
||||||
|
}
|
||||||
|
|
||||||
/** Detach a strike from the global cache matching the specified descriptor. Once detached,
|
/** Detach a strike from the global cache matching the specified descriptor. Once detached,
|
||||||
it can be queried/modified by the current thread, and when finished, be reattached to the
|
it can be queried/modified by the current thread, and when finished, be reattached to the
|
||||||
@ -132,11 +173,10 @@ public:
|
|||||||
descriptor, a different strike will be generated. This is fine. It does mean we can have
|
descriptor, a different strike will be generated. This is fine. It does mean we can have
|
||||||
more than 1 strike for the same descriptor, but that will eventually get purged, and the
|
more than 1 strike for the same descriptor, but that will eventually get purged, and the
|
||||||
win is that different thread will never block each other while a strike is being used.
|
win is that different thread will never block each other while a strike is being used.
|
||||||
|
DEPRECATED
|
||||||
*/
|
*/
|
||||||
static SkGlyphCache* DetachCache(SkTypeface* typeface, const SkScalerContextEffects& effects,
|
static SkGlyphCache* DetachCache(
|
||||||
const SkDescriptor* desc) {
|
SkTypeface* typeface, const SkScalerContextEffects& effects, const SkDescriptor* desc);
|
||||||
return VisitCache(typeface, effects, desc, DetachProc, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
static SkGlyphCache* DetachCacheUsingPaint(const SkPaint& paint,
|
static SkGlyphCache* DetachCacheUsingPaint(const SkPaint& paint,
|
||||||
const SkSurfaceProps* surfaceProps,
|
const SkSurfaceProps* surfaceProps,
|
||||||
@ -150,8 +190,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
static void DumpMemoryStatistics(SkTraceMemoryDump* dump);
|
static void DumpMemoryStatistics(SkTraceMemoryDump* dump);
|
||||||
|
|
||||||
typedef void (*Visitor)(const SkGlyphCache&, void* context);
|
static void ForEachStrike(std::function<void(const SkGlyphCache&)> visitor);
|
||||||
static void VisitAll(Visitor, void* context);
|
|
||||||
|
|
||||||
#ifdef SK_DEBUG
|
#ifdef SK_DEBUG
|
||||||
void validate() const;
|
void validate() const;
|
||||||
@ -182,14 +221,15 @@ private:
|
|||||||
friend class SkGlyphCache_Globals;
|
friend class SkGlyphCache_Globals;
|
||||||
|
|
||||||
enum MetricsType {
|
enum MetricsType {
|
||||||
|
kNothing_MetricsType,
|
||||||
kJustAdvance_MetricsType,
|
kJustAdvance_MetricsType,
|
||||||
kFull_MetricsType
|
kFull_MetricsType
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
kHashBits = 8,
|
kHashBits = 8,
|
||||||
kHashCount = 1 << kHashBits,
|
kHashCount = 1 << kHashBits,
|
||||||
kHashMask = kHashCount - 1
|
kHashMask = kHashCount - 1
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CharGlyphRec {
|
struct CharGlyphRec {
|
||||||
@ -197,9 +237,12 @@ private:
|
|||||||
SkPackedGlyphID fPackedGlyphID;
|
SkPackedGlyphID fPackedGlyphID;
|
||||||
};
|
};
|
||||||
|
|
||||||
SkGlyphCache(const SkDescriptor*, std::unique_ptr<SkScalerContext>);
|
SkGlyphCache(const SkDescriptor& desc, std::unique_ptr<SkScalerContext> scaler);
|
||||||
~SkGlyphCache();
|
~SkGlyphCache();
|
||||||
|
|
||||||
|
// Purge all the things.
|
||||||
|
static void PurgeAll();
|
||||||
|
|
||||||
// Return the SkGlyph* associated with MakeID. The id parameter is the
|
// Return the SkGlyph* associated with MakeID. The id parameter is the
|
||||||
// combined glyph/x/y id generated by MakeID. If it is just a glyph id
|
// combined glyph/x/y id generated by MakeID. If it is just a glyph id
|
||||||
// then x and y are assumed to be zero.
|
// then x and y are assumed to be zero.
|
||||||
@ -212,8 +255,6 @@ private:
|
|||||||
// of work using type.
|
// of work using type.
|
||||||
SkGlyph* allocateNewGlyph(SkPackedGlyphID packedGlyphID, MetricsType type);
|
SkGlyph* allocateNewGlyph(SkPackedGlyphID packedGlyphID, MetricsType type);
|
||||||
|
|
||||||
static bool DetachProc(const SkGlyphCache*, void*) { return true; }
|
|
||||||
|
|
||||||
// The id arg is a combined id generated by MakeID.
|
// The id arg is a combined id generated by MakeID.
|
||||||
CharGlyphRec* getCharGlyphRec(SkPackedUnicharID id);
|
CharGlyphRec* getCharGlyphRec(SkPackedUnicharID id);
|
||||||
|
|
||||||
@ -231,8 +272,8 @@ private:
|
|||||||
static const SkGlyph::Intercept* MatchBounds(const SkGlyph* glyph,
|
static const SkGlyph::Intercept* MatchBounds(const SkGlyph* glyph,
|
||||||
const SkScalar bounds[2]);
|
const SkScalar bounds[2]);
|
||||||
|
|
||||||
SkGlyphCache* fNext;
|
SkGlyphCache* fNext{nullptr};
|
||||||
SkGlyphCache* fPrev;
|
SkGlyphCache* fPrev{nullptr};
|
||||||
const std::unique_ptr<SkDescriptor> fDesc;
|
const std::unique_ptr<SkDescriptor> fDesc;
|
||||||
const std::unique_ptr<SkScalerContext> fScalerContext;
|
const std::unique_ptr<SkScalerContext> fScalerContext;
|
||||||
SkPaint::FontMetrics fFontMetrics;
|
SkPaint::FontMetrics fFontMetrics;
|
||||||
@ -253,7 +294,7 @@ private:
|
|||||||
size_t fMemoryUsed;
|
size_t fMemoryUsed;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SkAutoGlyphCache : public std::unique_ptr<SkGlyphCache, SkGlyphCache::AttachCacheFunctor> {
|
class SkAutoGlyphCache : public SkExclusiveStrikePtr {
|
||||||
public:
|
public:
|
||||||
/** deprecated: use get() */
|
/** deprecated: use get() */
|
||||||
SkGlyphCache* getCache() const { return this->get(); }
|
SkGlyphCache* getCache() const { return this->get(); }
|
||||||
@ -280,7 +321,7 @@ public:
|
|||||||
SkGlyphCache::DetachCacheUsingPaint(paint, surfaceProps, scalerContextFlags, matrix))
|
SkGlyphCache::DetachCacheUsingPaint(paint, surfaceProps, scalerContextFlags, matrix))
|
||||||
{}
|
{}
|
||||||
private:
|
private:
|
||||||
using INHERITED = std::unique_ptr<SkGlyphCache, SkGlyphCache::AttachCacheFunctor>;
|
using INHERITED = SkExclusiveStrikePtr;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SkAutoGlyphCacheNoGamma : public SkAutoGlyphCache {
|
class SkAutoGlyphCacheNoGamma : public SkAutoGlyphCache {
|
||||||
|
@ -8,10 +8,10 @@
|
|||||||
#ifndef SkGlyphCache_Globals_DEFINED
|
#ifndef SkGlyphCache_Globals_DEFINED
|
||||||
#define SkGlyphCache_Globals_DEFINED
|
#define SkGlyphCache_Globals_DEFINED
|
||||||
|
|
||||||
#include "SkGlyphCache.h"
|
|
||||||
#include "SkMutex.h"
|
#include "SkMutex.h"
|
||||||
#include "SkSpinlock.h"
|
#include "SkSpinlock.h"
|
||||||
#include "SkTLS.h"
|
|
||||||
|
class SkGlyphCache;
|
||||||
|
|
||||||
#ifndef SK_DEFAULT_FONT_CACHE_COUNT_LIMIT
|
#ifndef SK_DEFAULT_FONT_CACHE_COUNT_LIMIT
|
||||||
#define SK_DEFAULT_FONT_CACHE_COUNT_LIMIT 2048
|
#define SK_DEFAULT_FONT_CACHE_COUNT_LIMIT 2048
|
||||||
@ -38,14 +38,9 @@ public:
|
|||||||
fPointSizeLimit = SK_DEFAULT_FONT_CACHE_POINT_SIZE_LIMIT;
|
fPointSizeLimit = SK_DEFAULT_FONT_CACHE_POINT_SIZE_LIMIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
~SkGlyphCache_Globals() {
|
~SkGlyphCache_Globals();
|
||||||
SkGlyphCache* cache = fHead;
|
|
||||||
while (cache) {
|
static void AttachCache(SkGlyphCache* cache);
|
||||||
SkGlyphCache* next = cache->fNext;
|
|
||||||
delete cache;
|
|
||||||
cache = next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mutable SkSpinlock fLock;
|
mutable SkSpinlock fLock;
|
||||||
|
|
||||||
|
@ -905,11 +905,6 @@ size_t SkPaint::breakText(const void* textD, size_t length, SkScalar maxWidth,
|
|||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
static bool FontMetricsCacheProc(const SkGlyphCache* cache, void* context) {
|
|
||||||
*(SkPaint::FontMetrics*)context = cache->getFontMetrics();
|
|
||||||
return false; // don't detach the cache
|
|
||||||
}
|
|
||||||
|
|
||||||
SkScalar SkPaint::getFontMetrics(FontMetrics* metrics, SkScalar zoom) const {
|
SkScalar SkPaint::getFontMetrics(FontMetrics* metrics, SkScalar zoom) const {
|
||||||
SkCanonicalizePaint canon(*this);
|
SkCanonicalizePaint canon(*this);
|
||||||
const SkPaint& paint = canon.getPaint();
|
const SkPaint& paint = canon.getPaint();
|
||||||
@ -932,7 +927,11 @@ SkScalar SkPaint::getFontMetrics(FontMetrics* metrics, SkScalar zoom) const {
|
|||||||
auto desc = SkScalerContext::CreateDescriptorAndEffectsUsingPaint(
|
auto desc = SkScalerContext::CreateDescriptorAndEffectsUsingPaint(
|
||||||
paint, nullptr, SkScalerContextFlags::kNone, zoomPtr, &ad, &effects);
|
paint, nullptr, SkScalerContextFlags::kNone, zoomPtr, &ad, &effects);
|
||||||
|
|
||||||
SkGlyphCache::VisitCache(paint.getTypeface(), effects, desc, FontMetricsCacheProc, metrics);
|
{
|
||||||
|
auto typeface = SkTypeface::NormalizeTypeface(paint.getTypeface());
|
||||||
|
auto cache = SkGlyphCache::FindOrCreateStrikeExclusive(*desc, effects, *typeface);
|
||||||
|
*metrics = cache->getFontMetrics();
|
||||||
|
}
|
||||||
|
|
||||||
if (scale) {
|
if (scale) {
|
||||||
SkPaintPriv::ScaleFontMetrics(metrics, scale);
|
SkPaintPriv::ScaleFontMetrics(metrics, scale);
|
||||||
|
Loading…
Reference in New Issue
Block a user