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>
diff --git a/modules/skparagraph/src/FontCollection.cpp b/modules/skparagraph/src/FontCollection.cpp
index adc21dc..73fffae 100644
--- a/modules/skparagraph/src/FontCollection.cpp
+++ b/modules/skparagraph/src/FontCollection.cpp
@@ -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::clearCaches() {
fParagraphCache.reset();
fTypefaces.reset();
+ SkShaper::PurgeCaches();
}
} // namespace textlayout
diff --git a/modules/skshaper/include/SkShaper.h b/modules/skshaper/include/SkShaper.h
index 6e57ecb..2b6d587 100644
--- a/modules/skshaper/include/SkShaper.h
+++ b/modules/skshaper/include/SkShaper.h
@@ -41,12 +41,6 @@
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 @@
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();
diff --git a/modules/skshaper/src/SkShaper.cpp b/modules/skshaper/src/SkShaper.cpp
index c47e3ad..d52a722 100644
--- a/modules/skshaper/src/SkShaper.cpp
+++ b/modules/skshaper/src/SkShaper.cpp
@@ -36,6 +36,12 @@
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
diff --git a/modules/skshaper/src/SkShaper_harfbuzz.cpp b/modules/skshaper/src/SkShaper_harfbuzz.cpp
index ca4e298..3f0fb21 100644
--- a/modules/skshaper/src/SkShaper_harfbuzz.cpp
+++ b/modules/skshaper/src/SkShaper_harfbuzz.cpp
@@ -1256,6 +1256,41 @@
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 @@
// 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 @@
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();
+}
diff --git a/samplecode/SampleTextBox.cpp b/samplecode/SampleTextBox.cpp
index 23cdf30..d929cad 100644
--- a/samplecode/SampleTextBox.cpp
+++ b/samplecode/SampleTextBox.cpp
@@ -56,6 +56,7 @@
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);