summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBehdad Esfahbod <behdad@google.com>2014-08-20 17:41:51 -0400
committerBehdad Esfahbod <behdad@google.com>2014-08-21 14:00:25 -0400
commit288c915963b3500c7efb958ba613650e2ecdfdfa (patch)
tree78cc7881807605f278d6ffbd75e8e688f97fe6d9
parentf952161b874fd2e9af474b9fd2ebcca1f3bb4555 (diff)
downloadandroid_frameworks_minikin-288c915963b3500c7efb958ba613650e2ecdfdfa.tar.gz
android_frameworks_minikin-288c915963b3500c7efb958ba613650e2ecdfdfa.tar.bz2
android_frameworks_minikin-288c915963b3500c7efb958ba613650e2ecdfdfa.zip
Speed up cache lookup
Avoid copying the string for cache lookup. Bug: 17111260 Change-Id: Ic220bfc991fc6b3dada197304aabdf72a8941bd7
-rw-r--r--include/minikin/Layout.h2
-rw-r--r--libs/minikin/Layout.cpp99
2 files changed, 66 insertions, 35 deletions
diff --git a/include/minikin/Layout.h b/include/minikin/Layout.h
index 1a0df99..c88d087 100644
--- a/include/minikin/Layout.h
+++ b/include/minikin/Layout.h
@@ -97,6 +97,8 @@ public:
static void purgeCaches();
private:
+ friend class LayoutCacheKey;
+
// Find a face in the mFaces vector, or create a new entry
int findFace(FakedFont face, LayoutContext* ctx);
diff --git a/libs/minikin/Layout.cpp b/libs/minikin/Layout.cpp
index aaac186..e355730 100644
--- a/libs/minikin/Layout.cpp
+++ b/libs/minikin/Layout.cpp
@@ -56,6 +56,19 @@ enum {
const int kDirection_Mask = 0x1;
+struct LayoutContext {
+ MinikinPaint paint;
+ FontStyle style;
+ std::vector<hb_font_t*> hbFonts; // parallel to mFaces
+
+ void clearHbFonts() {
+ for (size_t i = 0; i < hbFonts.size(); i++) {
+ hb_font_destroy(hbFonts[i]);
+ }
+ hbFonts.clear();
+ }
+};
+
// Layout cache datatypes
class LayoutCacheKey {
@@ -65,16 +78,32 @@ public:
: mStart(start), mCount(count), mId(collection->getId()), mStyle(style),
mSize(paint.size), mScaleX(paint.scaleX), mSkewX(paint.skewX),
mLetterSpacing(paint.letterSpacing),
- mPaintFlags(paint.paintFlags), mIsRtl(dir) {
- mText.setTo(chars, nchars);
+ mPaintFlags(paint.paintFlags), mIsRtl(dir),
+ mChars(chars), mNchars(nchars) {
}
bool operator==(const LayoutCacheKey &other) const;
hash_t hash() const;
- // This is present to avoid having to copy the text more than once.
- const uint16_t* textBuf() { return mText.string(); }
+ void copyText() {
+ uint16_t* charsCopy = new uint16_t[mNchars];
+ memcpy(charsCopy, mChars, mNchars * sizeof(uint16_t));
+ mChars = charsCopy;
+ }
+ void freeText() {
+ delete[] mChars;
+ mChars = NULL;
+ }
+
+ void doLayout(Layout* layout, LayoutContext* ctx, const FontCollection* collection) const {
+ layout->setFontCollection(collection);
+ layout->mAdvances.resize(mCount, 0);
+ ctx->clearHbFonts();
+ layout->doLayoutRun(mChars, mStart, mCount, mNchars, mIsRtl, ctx);
+ }
+
private:
- String16 mText;
+ const uint16_t* mChars;
+ size_t mNchars;
size_t mStart;
size_t mCount;
uint32_t mId; // for the font collection
@@ -95,13 +124,30 @@ public:
mCache.setOnEntryRemovedListener(this);
}
+ void clear() {
+ mCache.clear();
+ }
+
+ Layout* get(LayoutCacheKey& key, LayoutContext* ctx, const FontCollection* collection) {
+ Layout* layout = mCache.get(key);
+ if (layout == NULL) {
+ key.copyText();
+ layout = new Layout();
+ key.doLayout(layout, ctx, collection);
+ mCache.put(key, layout);
+ }
+ return layout;
+ }
+
+private:
// callback for OnEntryRemoved
void operator()(LayoutCacheKey& key, Layout*& value) {
+ key.freeText();
delete value;
}
LruCache<LayoutCacheKey, Layout*> mCache;
-private:
+
//static const size_t kMaxEntries = LruCache<LayoutCacheKey, Layout*>::kUnlimitedCapacity;
// TODO: eviction based on memory footprint; for now, we just use a constant
@@ -149,7 +195,8 @@ bool LayoutCacheKey::operator==(const LayoutCacheKey& other) const {
&& mLetterSpacing == other.mLetterSpacing
&& mPaintFlags == other.mPaintFlags
&& mIsRtl == other.mIsRtl
- && mText == other.mText;
+ && mNchars == other.mNchars
+ && !memcmp(mChars, other.mChars, mNchars * sizeof(uint16_t));
}
hash_t LayoutCacheKey::hash() const {
@@ -163,16 +210,10 @@ hash_t LayoutCacheKey::hash() const {
hash = JenkinsHashMix(hash, hash_type(mLetterSpacing));
hash = JenkinsHashMix(hash, hash_type(mPaintFlags));
hash = JenkinsHashMix(hash, hash_type(mIsRtl));
- hash = JenkinsHashMixShorts(hash, mText.string(), mText.size());
+ hash = JenkinsHashMixShorts(hash, mChars, mNchars);
return JenkinsHashWhiten(hash);
}
-struct LayoutContext {
- MinikinPaint paint;
- FontStyle style;
- std::vector<hb_font_t*> hbFonts; // parallel to mFaces
-};
-
hash_t hash_type(const LayoutCacheKey& key) {
return key.hash();
}
@@ -467,13 +508,6 @@ static size_t getNextWordBreak(const uint16_t* chars, size_t offset, size_t len)
return len;
}
-static void clearHbFonts(LayoutContext* ctx) {
- for (size_t i = 0; i < ctx->hbFonts.size(); i++) {
- hb_font_destroy(ctx->hbFonts[i]);
- }
- ctx->hbFonts.clear();
-}
-
void Layout::doLayout(const uint16_t* buf, size_t start, size_t count, size_t bufSize,
int bidiFlags, const FontStyle &style, const MinikinPaint &paint) {
AutoMutex _l(gMinikinLock);
@@ -543,7 +577,7 @@ void Layout::doLayout(const uint16_t* buf, size_t start, size_t count, size_t bu
if (doSingleRun) {
doLayoutRunCached(buf, start, count, bufSize, isRtl, &ctx, start);
}
- clearHbFonts(&ctx);
+ ctx.clearHbFonts();
}
void Layout::doLayoutRunCached(const uint16_t* buf, size_t start, size_t count, size_t bufSize,
@@ -579,19 +613,14 @@ void Layout::doLayoutWord(const uint16_t* buf, size_t start, size_t count, size_
LayoutCache& cache = LayoutEngine::getInstance().layoutCache;
LayoutCacheKey key(mCollection, ctx->paint, ctx->style, buf, start, count, bufSize, isRtl);
bool skipCache = ctx->paint.skipCache();
- Layout* value = skipCache ? NULL : cache.mCache.get(key);
- if (value == NULL) {
- value = new Layout();
- value->setFontCollection(mCollection);
- value->mAdvances.resize(count, 0);
- clearHbFonts(ctx);
- // Note: we do the layout from the copy stored in the key, in case a
- // badly-behaved client is mutating the buffer in a separate thread.
- value->doLayoutRun(key.textBuf(), start, count, bufSize, isRtl, ctx);
+ if (skipCache) {
+ Layout layout;
+ key.doLayout(&layout, ctx, mCollection);
+ appendLayout(&layout, bufStart);
+ } else {
+ Layout* layout = cache.get(key, ctx, mCollection);
+ appendLayout(layout, bufStart);
}
- appendLayout(value, bufStart);
- if (!skipCache)
- cache.mCache.put(key, value);
}
static void addFeatures(const string &str, vector<hb_feature_t>* features) {
@@ -821,7 +850,7 @@ void Layout::getBounds(MinikinRect* bounds) {
void Layout::purgeCaches() {
AutoMutex _l(gMinikinLock);
LayoutCache& layoutCache = LayoutEngine::getInstance().layoutCache;
- layoutCache.mCache.clear();
+ layoutCache.clear();
HbFaceCache& hbCache = LayoutEngine::getInstance().hbFaceCache;
hbCache.mCache.clear();
}