summaryrefslogtreecommitdiff
path: root/include/minikin/LayoutCache.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/minikin/LayoutCache.h')
-rw-r--r--include/minikin/LayoutCache.h76
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;