diff options
Diffstat (limited to 'include/minikin/LayoutCache.h')
-rw-r--r-- | include/minikin/LayoutCache.h | 76 |
1 files changed, 64 insertions, 12 deletions
diff --git a/include/minikin/LayoutCache.h b/include/minikin/LayoutCache.h index a1cc34a..fa572fb 100644 --- a/include/minikin/LayoutCache.h +++ b/include/minikin/LayoutCache.h @@ -55,6 +55,7 @@ public: mStartHyphen(startHyphen), mEndHyphen(endHyphen), mIsRtl(dir), + mFontFeatureSettings(paint.fontFeatureSettings), mHash(computeHash()) {} bool operator==(const LayoutCacheKey& o) const { @@ -64,6 +65,7 @@ public: mFontFlags == o.mFontFlags && mLocaleListId == o.mLocaleListId && mFamilyVariant == o.mFamilyVariant && mStartHyphen == o.mStartHyphen && mEndHyphen == o.mEndHyphen && mIsRtl == o.mIsRtl && mNchars == o.mNchars && + mFontFeatureSettings == o.mFontFeatureSettings && !memcmp(mChars, o.mChars, mNchars * sizeof(uint16_t)); } @@ -77,6 +79,7 @@ public: void freeText() { delete[] mChars; mChars = NULL; + mFontFeatureSettings.clear(); } uint32_t getMemoryUsage() const { return sizeof(LayoutCacheKey) + sizeof(uint16_t) * mNchars; } @@ -99,6 +102,7 @@ private: StartHyphenEdit mStartHyphen; EndHyphenEdit mEndHyphen; bool mIsRtl; + std::vector<FontFeature> mFontFeatureSettings; // Note: any fields added to MinikinPaint must also be reflected here. // TODO: language matching (possibly integrate into style) android::hash_t mHash; @@ -120,11 +124,33 @@ private: .update(packHyphenEdit(mStartHyphen, mEndHyphen)) .update(mIsRtl) .updateShorts(mChars, mNchars) + .update(mFontFeatureSettings) .hash(); } }; -class LayoutCache : private android::OnEntryRemoved<LayoutCacheKey, LayoutPiece*> { +// A class holds a layout information and bounding box of it. The bounding box can be invalid if not +// calculated. +class LayoutSlot { +public: + LayoutSlot(LayoutPiece&& layout) + : mLayout(std::move(layout)), mBounds(MinikinRect::makeInvalid()) {} + LayoutSlot(LayoutPiece&& layout, MinikinRect&& bounds) + : mLayout(std::move(layout)), mBounds(std::move(bounds)) {} + LayoutSlot(const LayoutPiece& layout, const MinikinRect& bounds) + : mLayout(layout), mBounds(bounds) {} + + const LayoutPiece mLayout; + MinikinRect mBounds; + +private: + LayoutSlot(const LayoutSlot&) = delete; + LayoutSlot& operator=(const LayoutSlot&) = delete; + LayoutSlot(LayoutSlot&&) = delete; + LayoutSlot& operator=(LayoutSlot&&) = delete; +}; + +class LayoutCache : private android::OnEntryRemoved<LayoutCacheKey, LayoutSlot*> { public: void clear() { std::lock_guard<std::mutex> lock(mMutex); @@ -134,29 +160,55 @@ public: // Do not use LayoutCache inside the callback function, otherwise dead-lock may happen. template <typename F> void getOrCreate(const U16StringPiece& text, const Range& range, const MinikinPaint& paint, - bool dir, StartHyphenEdit startHyphen, EndHyphenEdit endHyphen, F& f) { + bool dir, StartHyphenEdit startHyphen, EndHyphenEdit endHyphen, + bool boundsCalculation, F& f) { LayoutCacheKey key(text, range, paint, dir, startHyphen, endHyphen); if (paint.skipCache() || range.getLength() >= LENGTH_LIMIT_CACHE) { - f(LayoutPiece(text, range, dir, paint, startHyphen, endHyphen), paint); + LayoutPiece piece(text, range, dir, paint, startHyphen, endHyphen); + if (boundsCalculation) { + f(piece, paint, LayoutPiece::calculateBounds(piece, paint)); + } else { + f(piece, paint, MinikinRect::makeInvalid()); + } return; } + + LayoutSlot* cachedSlot; { std::lock_guard<std::mutex> lock(mMutex); - LayoutPiece* layout = mCache.get(key); - if (layout != nullptr) { - f(*layout, paint); + cachedSlot = mCache.get(key); + + if (cachedSlot != nullptr) { + if (boundsCalculation && !cachedSlot->mBounds.isValid()) { + MinikinRect bounds = LayoutPiece::calculateBounds(cachedSlot->mLayout, paint); + LayoutPiece lp = cachedSlot->mLayout; + f(lp, paint, bounds); + cachedSlot->mBounds = bounds; + } else { + f(cachedSlot->mLayout, paint, cachedSlot->mBounds); + } return; } } // 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<LayoutPiece> layout = - std::make_unique<LayoutPiece>(text, range, dir, paint, startHyphen, endHyphen); - f(*layout, paint); + + std::unique_ptr<LayoutSlot> slot; + if (boundsCalculation) { + LayoutPiece lp = LayoutPiece(text, range, dir, paint, startHyphen, endHyphen); + MinikinRect rect = LayoutPiece::calculateBounds(lp, paint); + + slot = std::make_unique<LayoutSlot>(std::move(lp), std::move(rect)); + } else { + slot = std::make_unique<LayoutSlot>( + LayoutPiece(text, range, dir, paint, startHyphen, endHyphen)); + } + + f(slot->mLayout, paint, slot->mBounds); { std::lock_guard<std::mutex> lock(mMutex); - mCache.put(key, layout.release()); + mCache.put(key, slot.release()); } } @@ -177,12 +229,12 @@ protected: private: // callback for OnEntryRemoved - void operator()(LayoutCacheKey& key, LayoutPiece*& value) { + void operator()(LayoutCacheKey& key, LayoutSlot*& value) { key.freeText(); delete value; } - android::LruCache<LayoutCacheKey, LayoutPiece*> mCache GUARDED_BY(mMutex); + android::LruCache<LayoutCacheKey, LayoutSlot*> mCache GUARDED_BY(mMutex); // static const size_t kMaxEntries = LruCache<LayoutCacheKey, Layout*>::kUnlimitedCapacity; |