diff options
-rw-r--r-- | include/minikin/Layout.h | 10 | ||||
-rw-r--r-- | libs/minikin/Layout.cpp | 158 |
2 files changed, 94 insertions, 74 deletions
diff --git a/include/minikin/Layout.h b/include/minikin/Layout.h index 7e8adc3..4f22918 100644 --- a/include/minikin/Layout.h +++ b/include/minikin/Layout.h @@ -111,11 +111,11 @@ public: // Get advances, copying into caller-provided buffer. The size of this // buffer must match the length of the string (count arg to doLayout). - void getAdvances(float* advances); + void getAdvances(float* advances) const; // Get extents, copying into caller-provided buffer. The size of this buffer must match the // length of the string (count arg to doLayout). - void getExtents(MinikinExtent* extents); + void getExtents(MinikinExtent* extents) const; // The i parameter is an offset within the buf relative to start, it is < count, where // start and count are the parameters to doLayout @@ -137,6 +137,7 @@ public: private: friend class LayoutCacheKey; + friend class LayoutCache; // TODO: Remove friend class with decoupling building logic from Layout. friend class LayoutCompositer; @@ -171,7 +172,7 @@ private: LayoutContext* ctx, StartHyphenEdit startHyphen, EndHyphenEdit endHyphen); // Append another layout (for example, cached value) into this one - void appendLayout(Layout* src, size_t start, float extraAdvance); + void appendLayout(const Layout& src, size_t start, float extraAdvance); std::vector<LayoutGlyph> mGlyphs; @@ -207,8 +208,7 @@ public: } void append(const Layout& layout, uint32_t start, float extraAdvance) { - // TODO: remove const cast. - mLayout.appendLayout(const_cast<Layout*>(&layout), start, extraAdvance); + mLayout.appendLayout(layout, start, extraAdvance); } Layout build() { return std::move(mLayout); } diff --git a/libs/minikin/Layout.cpp b/libs/minikin/Layout.cpp index f5fe89f..a641fae 100644 --- a/libs/minikin/Layout.cpp +++ b/libs/minikin/Layout.cpp @@ -20,6 +20,7 @@ #include <cmath> #include <iostream> +#include <mutex> #include <string> #include <vector> @@ -144,12 +145,12 @@ struct LayoutContext { class LayoutCacheKey { public: - LayoutCacheKey(const MinikinPaint& paint, const uint16_t* chars, size_t start, size_t count, - size_t nchars, bool dir, StartHyphenEdit startHyphen, EndHyphenEdit endHyphen) - : mChars(chars), - mNchars(nchars), - mStart(start), - mCount(count), + LayoutCacheKey(const U16StringPiece& text, const Range& range, const MinikinPaint& paint, + bool dir, StartHyphenEdit startHyphen, EndHyphenEdit endHyphen) + : mChars(text.data()), + mNchars(text.size()), + mStart(range.getStart()), + mCount(range.getLength()), mId(paint.font->getId()), mStyle(paint.fontStyle), mSize(paint.size), @@ -214,20 +215,50 @@ public: mCache.setOnEntryRemovedListener(this); } - void clear() { mCache.clear(); } + void clear() { + std::lock_guard<std::mutex> lock(mMutex); + mCache.clear(); + } + + // Do not use any LayoutCache function in callback. + float getOrCreateAndAppend(const U16StringPiece& text, const Range& range, LayoutContext* ctx, + bool dir, StartHyphenEdit startHyphen, EndHyphenEdit endHyphen, + Layout* outLayout, // nullptr if not necessary + float* outAdvances, // nullptr if not necessary + MinikinExtent* outExtents, // nullptr if not necessary + LayoutPieces* outLayoutPiece, // nullptr if not necessary + uint32_t outIndex, // outputStarting index + float wordSpacing) { // additional wordSpacing + LayoutCacheKey key(text, range, ctx->paint, dir, startHyphen, endHyphen); + if (ctx->paint.skipCache()) { + Layout layoutForWord; + key.doLayout(&layoutForWord, ctx); + return appendTo(layoutForWord, outLayout, outAdvances, outExtents, outLayoutPiece, + outIndex, wordSpacing); + } - Layout* get(LayoutCacheKey& key, LayoutContext* ctx) { - Layout* layout = mCache.get(key); mRequestCount++; - if (layout == NULL) { - key.copyText(); - layout = new Layout(); - key.doLayout(layout, ctx); - mCache.put(key, layout); - } else { - mCacheHitCount++; + { + std::lock_guard<std::mutex> lock(mMutex); + Layout* layout = mCache.get(key); + if (layout != nullptr) { + mCacheHitCount++; + return appendTo(*layout, outLayout, outAdvances, outExtents, outLayoutPiece, + outIndex, wordSpacing); + } + } + // Doing text layout takes long time, so releases the mutex during doing layout. + // Don't care even if we do the same layout in other thred. + key.copyText(); + std::unique_ptr<Layout> layout = std::make_unique<Layout>(); + key.doLayout(layout.get(), ctx); + float result = appendTo(*layout, outLayout, outAdvances, outExtents, outLayoutPiece, + outIndex, wordSpacing); + { + std::lock_guard<std::mutex> lock(mMutex); + mCache.put(key, layout.release()); } - return layout; + return result; } void dumpStats(int fd) { @@ -249,7 +280,26 @@ private: delete value; } - android::LruCache<LayoutCacheKey, Layout*> mCache; + // Returns advance of the layout. + float appendTo(const Layout& layoutForWord, Layout* outLayout, float* outAdvances, + MinikinExtent* outExtents, LayoutPieces* outLayoutPiece, uint32_t outIndex, + float wordSpacing) { + if (outLayout) { + outLayout->appendLayout(layoutForWord, outIndex, wordSpacing); + } + if (outAdvances) { + layoutForWord.getAdvances(outAdvances); + } + if (outExtents) { + layoutForWord.getExtents(outExtents); + } + if (outLayoutPiece) { + outLayoutPiece->offsetMap.insert(std::make_pair(outIndex, layoutForWord)); + } + return layoutForWord.getAdvance(); + } + + android::LruCache<LayoutCacheKey, Layout*> mCache; // Guarded by mCache. int32_t mRequestCount; int32_t mCacheHitCount; @@ -259,6 +309,10 @@ private: // TODO: eviction based on memory footprint; for now, we just use a constant // number of strings static const size_t kMaxEntries = 5000; + + // To avoid dead-locking, need to acquire gMinikinLock before acquiring mMutex. + // TODO: Remove gMinikinLock + std::mutex mMutex; }; bool LayoutCacheKey::operator==(const LayoutCacheKey& other) const { @@ -679,44 +733,10 @@ float Layout::doLayoutWord(const uint16_t* buf, size_t start, size_t count, size bool isRtl, LayoutContext* ctx, size_t bufStart, StartHyphenEdit startHyphen, EndHyphenEdit endHyphen, Layout* layout, float* advances, MinikinExtent* extents, LayoutPieces* lpOut) { - LayoutCache& cache = LayoutCache::getInstance(); - LayoutCacheKey key(ctx->paint, buf, start, count, bufSize, isRtl, startHyphen, endHyphen); - float wordSpacing = count == 1 && isWordSpace(buf[start]) ? ctx->paint.wordSpacing : 0; - - float advance; - if (ctx->paint.skipCache()) { - Layout layoutForWord; - key.doLayout(&layoutForWord, ctx); - if (layout) { - layout->appendLayout(&layoutForWord, bufStart, wordSpacing); - } - if (advances) { - layoutForWord.getAdvances(advances); - } - if (extents) { - layoutForWord.getExtents(extents); - } - advance = layoutForWord.getAdvance(); - if (lpOut != nullptr) { - lpOut->offsetMap.insert(std::make_pair(bufStart, layoutForWord)); - } - } else { - Layout* layoutForWord = cache.get(key, ctx); - if (layout) { - layout->appendLayout(layoutForWord, bufStart, wordSpacing); - } - if (advances) { - layoutForWord->getAdvances(advances); - } - if (extents) { - layoutForWord->getExtents(extents); - } - advance = layoutForWord->getAdvance(); - if (lpOut != nullptr) { - lpOut->offsetMap.insert(std::make_pair(bufStart, *layoutForWord)); - } - } + float advance = LayoutCache::getInstance().getOrCreateAndAppend( + U16StringPiece(buf, bufSize), Range(start, start + count), ctx, isRtl, startHyphen, + endHyphen, layout, advances, extents, lpOut, bufStart, wordSpacing); if (wordSpacing != 0) { advance += wordSpacing; @@ -1044,21 +1064,21 @@ void Layout::doLayoutRun(const uint16_t* buf, size_t start, size_t count, size_t mAdvance = x; } -void Layout::appendLayout(Layout* src, size_t start, float extraAdvance) { +void Layout::appendLayout(const Layout& src, size_t start, float extraAdvance) { int fontMapStack[16]; int* fontMap; - if (src->mFaces.size() < sizeof(fontMapStack) / sizeof(fontMapStack[0])) { + if (src.mFaces.size() < sizeof(fontMapStack) / sizeof(fontMapStack[0])) { fontMap = fontMapStack; } else { - fontMap = new int[src->mFaces.size()]; + fontMap = new int[src.mFaces.size()]; } - for (size_t i = 0; i < src->mFaces.size(); i++) { - int font_ix = findOrPushBackFace(src->mFaces[i], nullptr); + for (size_t i = 0; i < src.mFaces.size(); i++) { + int font_ix = findOrPushBackFace(src.mFaces[i], nullptr); fontMap[i] = font_ix; } int x0 = mAdvance; - for (size_t i = 0; i < src->mGlyphs.size(); i++) { - LayoutGlyph& srcGlyph = src->mGlyphs[i]; + for (size_t i = 0; i < src.mGlyphs.size(); i++) { + const LayoutGlyph& srcGlyph = src.mGlyphs[i]; int font_ix = fontMap[srcGlyph.font_ix]; unsigned int glyph_id = srcGlyph.glyph_id; float x = x0 + srcGlyph.x; @@ -1066,17 +1086,17 @@ void Layout::appendLayout(Layout* src, size_t start, float extraAdvance) { LayoutGlyph glyph = {font_ix, glyph_id, x, y}; mGlyphs.push_back(glyph); } - for (size_t i = 0; i < src->mAdvances.size(); i++) { - mAdvances[i + start] = src->mAdvances[i]; + for (size_t i = 0; i < src.mAdvances.size(); i++) { + mAdvances[i + start] = src.mAdvances[i]; if (i == 0) { mAdvances[start] += extraAdvance; } - mExtents[i + start] = src->mExtents[i]; + mExtents[i + start] = src.mExtents[i]; } - MinikinRect srcBounds(src->mBounds); + MinikinRect srcBounds(src.mBounds); srcBounds.offset(x0, 0); mBounds.join(srcBounds); - mAdvance += src->mAdvance + extraAdvance; + mAdvance += src.mAdvance + extraAdvance; if (fontMap != fontMapStack) { delete[] fontMap; @@ -1116,11 +1136,11 @@ float Layout::getAdvance() const { return mAdvance; } -void Layout::getAdvances(float* advances) { +void Layout::getAdvances(float* advances) const { memcpy(advances, &mAdvances[0], mAdvances.size() * sizeof(float)); } -void Layout::getExtents(MinikinExtent* extents) { +void Layout::getExtents(MinikinExtent* extents) const { memcpy(extents, &mExtents[0], mExtents.size() * sizeof(MinikinExtent)); } |