Add SkShaper::PurgeCaches.

Allows the user to signal that any global outstanding cached data should
be cleaned up to free resources.

Change-Id: I59d4bb2bbb4356920dea8caf912d9cb5f13014cf
Bug: skia:10763
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/360079
Commit-Queue: Ben Wagner <bungeman@google.com>
Reviewed-by: Julia Lavrova <jlavrova@google.com>
This commit is contained in:
Ben Wagner 2021-01-26 19:25:39 -05:00 committed by Skia Commit-Bot
parent 0ca2f599dd
commit dd9449c23b
5 changed files with 54 additions and 11 deletions

View File

@ -3,6 +3,7 @@
#include "modules/skparagraph/include/FontCollection.h"
#include "modules/skparagraph/include/Paragraph.h"
#include "modules/skparagraph/src/ParagraphImpl.h"
#include "modules/skshaper/include/SkShaper.h"
namespace skia {
namespace textlayout {
@ -150,6 +151,7 @@ void FontCollection::enableFontFallback() { fEnableFontFallback = true; }
void FontCollection::clearCaches() {
fParagraphCache.reset();
fTypefaces.reset();
SkShaper::PurgeCaches();
}
} // namespace textlayout

View File

@ -41,12 +41,6 @@ class SkFont;
class SkFontMgr;
class SkUnicode;
/**
Shapes text using HarfBuzz and places the shaped text into a
client-managed buffer.
If compiled without HarfBuzz, fall back on SkPaint::textToGlyphs.
*/
class SKSHAPER_API SkShaper {
public:
static std::unique_ptr<SkShaper> MakePrimitive();
@ -54,12 +48,14 @@ public:
static std::unique_ptr<SkShaper> MakeShaperDrivenWrapper(sk_sp<SkFontMgr> = nullptr);
static std::unique_ptr<SkShaper> MakeShapeThenWrap(sk_sp<SkFontMgr> = nullptr);
static std::unique_ptr<SkShaper> MakeShapeDontWrapOrReorder(sk_sp<SkFontMgr> = nullptr);
static void PurgeHarfBuzzCache();
#endif
#ifdef SK_SHAPER_CORETEXT_AVAILABLE
static std::unique_ptr<SkShaper> MakeCoreText();
#endif
static std::unique_ptr<SkShaper> Make(sk_sp<SkFontMgr> = nullptr);
static void PurgeCaches();
SkShaper();
virtual ~SkShaper();

View File

@ -36,6 +36,12 @@ std::unique_ptr<SkShaper> SkShaper::Make(sk_sp<SkFontMgr> fontmgr) {
return SkShaper::MakePrimitive();
}
void SkShaper::PurgeCaches() {
#ifdef SK_SHAPER_HARFBUZZ_AVAILABLE
PurgeHarfBuzzCache();
#endif
}
std::unique_ptr<SkShaper::BiDiRunIterator>
SkShaper::MakeBiDiRunIterator(const char* utf8, size_t utf8Bytes, uint8_t bidiLevel) {
#ifdef SK_UNICODE_AVAILABLE

View File

@ -1256,6 +1256,41 @@ void ShapeDontWrapOrReorder::wrap(char const * const utf8, size_t utf8Bytes,
handler->commitLine();
}
class HBLockedFaceCache {
public:
HBLockedFaceCache(SkLRUCache<SkFontID, HBFace>& lruCache, SkMutex& mutex)
: fLRUCache(lruCache), fMutex(mutex)
{
fMutex.acquire();
}
HBLockedFaceCache(const HBLockedFaceCache&) = delete;
HBLockedFaceCache& operator=(const HBLockedFaceCache&) = delete;
HBLockedFaceCache(HBLockedFaceCache&&) = delete;
HBLockedFaceCache& operator=(HBLockedFaceCache&&) = delete;
~HBLockedFaceCache() {
fMutex.release();
}
HBFace* find(SkFontID fontId) {
return fLRUCache.find(fontId);
}
HBFace* insert(SkFontID fontId, HBFace hbFace) {
return fLRUCache.insert(fontId, std::move(hbFace));
}
void reset() {
fLRUCache.reset();
}
private:
SkLRUCache<SkFontID, HBFace>& fLRUCache;
SkMutex& fMutex;
};
static HBLockedFaceCache get_hbFace_cache() {
static SkMutex gHBFaceCacheMutex;
static SkLRUCache<SkFontID, HBFace> gHBFaceCache(100);
return HBLockedFaceCache(gHBFaceCache, gHBFaceCacheMutex);
}
ShapedRun ShaperHarfBuzz::shape(char const * const utf8,
size_t const utf8Bytes,
char const * const utf8Start,
@ -1312,16 +1347,14 @@ ShapedRun ShaperHarfBuzz::shape(char const * const utf8,
// An HBFont is fairly inexpensive.
// An HBFace is actually tied to the data, not the typeface.
// The size of 100 here is completely arbitrary and used to match libtxt.
static SkLRUCache<SkFontID, HBFace> gHBFaceCache(100);
static SkMutex gHBFaceCacheMutex;
HBFont hbFont;
{
SkAutoMutexExclusive lock(gHBFaceCacheMutex);
HBLockedFaceCache cache = get_hbFace_cache();
SkFontID dataId = font.currentFont().getTypeface()->uniqueID();
HBFace* hbFaceCached = gHBFaceCache.find(dataId);
HBFace* hbFaceCached = cache.find(dataId);
if (!hbFaceCached) {
HBFace hbFace(create_hb_face(*font.currentFont().getTypeface()));
hbFaceCached = gHBFaceCache.insert(dataId, std::move(hbFace));
hbFaceCached = cache.insert(dataId, std::move(hbFace));
}
hbFont = create_hb_font(font.currentFont(), *hbFaceCached);
}
@ -1478,3 +1511,8 @@ std::unique_ptr<SkShaper> SkShaper::MakeShapeDontWrapOrReorder(sk_sp<SkFontMgr>
return std::make_unique<ShapeDontWrapOrReorder>
(std::move(unicode), nullptr, nullptr, std::move(buffer), std::move(fontmgr));
}
void SkShaper::PurgeHarfBuzzCache() {
HBLockedFaceCache cache = get_hbFace_cache();
cache.reset();
}

View File

@ -56,6 +56,7 @@ protected:
paint.setColor(fg);
for (int i = 9; i < 24; i += 2) {
SkShaper::PurgeCaches();
SkTextBlobBuilderRunHandler builder(gText, { margin, margin });
SkFont srcFont(nullptr, SkIntToScalar(i));
srcFont.setEdging(SkFont::Edging::kSubpixelAntiAlias);