diff options
author | Seigo Nonaka <nona@google.com> | 2018-04-02 21:39:34 -0700 |
---|---|---|
committer | Seigo Nonaka <nona@google.com> | 2018-04-04 14:23:08 -0700 |
commit | 3da4269e6097e0dafdb438c760dafdde13feda95 (patch) | |
tree | 0fb4bdaab0a92603e032e416a16ede258946c27c | |
parent | 2adb04f8edb61857a2c53c16ced533df47be67c3 (diff) | |
download | minikin-3da4269e6097e0dafdb438c760dafdde13feda95.tar.gz |
Include MinikinPaint into cache key
MeasruedText::buildLayout can not be used for acquiring bounding box since
the input range can across the style boundary. To make things correctly,
include MinikinPaint as the key of the LayoutPiece. This is totally same as the
LayoutCacheKey in LayoutCache, so reuses LayoutCacheKey instead of self defined
key class in LayoutPiece.
This increases the memory usage and ideally run index can be used for layout cache
key instead of full MinikinPaint, but let me make thing correct first.
Here is a raw performance result.
android.text.PrecomputedTextMemoryUsageTest:
MemoryUsage
Hyphenation : 50,873 -> 59,721: (+17.4%)
Hyphenation WidthOnly : 8,856 -> 8,856: (+0.0%)
NoHyphenation : 26,386 -> 29,242: (+10.8%)
NoHyphenation WidthOnly : 8,000 -> 8,000: (+0.0%)
android.text.PrecomputedTextPerfTest:
create
NoStyle Hyphenation : 18,378,988 -> 18,332,327: (-0.3%)
NoStyle Hyphenation WidthOnly : 18,332,392 -> 18,397,337: (+0.4%)
NoStyle NoHyphenation : 7,385,258 -> 7,390,699: (+0.1%)
NoStyle NoHyphenation WidthOnly : 7,403,445 -> 7,388,476: (-0.2%)
Style Hyphenation : 12,637,464 -> 12,624,799: (-0.1%)
Style Hyphenation WidthOnly : 12,667,559 -> 12,642,056: (-0.2%)
Style NoHyphenation : 12,348,519 -> 12,241,291: (-0.9%)
Style NoHyphenation WidthOnly : 12,325,515 -> 12,317,746: (-0.1%)
android.text.StaticLayoutPerfTest:
create
PrecomputedText
Balanced Hyphenation : 691,388 -> 680,137: (-1.6%)
Balanced NoHyphenation : 502,038 -> 495,980: (-1.2%)
Greedy Hyphenation : 451,619 -> 446,380: (-1.2%)
Greedy NoHyphenation : 449,011 -> 444,621: (-1.0%)
RandomText
Balanced Hyphenation : 17,639,029 -> 17,609,190: (-0.2%)
Balanced NoHyphenation : 7,295,497 -> 7,251,221: (-0.6%)
Greedy Hyphenation : 7,268,452 -> 7,201,506: (-0.9%)
Greedy NoHyphenation : 7,215,397 -> 7,225,217: (+0.1%)
draw
PrecomputedText
NoStyle : 588,349 -> 620,041: (+5.4%)
NoStyle WithoutCache : 613,312 -> 645,161: (+5.2%)
Style : 911,309 -> 938,200: (+3.0%)
Style WithoutCache : 920,240 -> 955,410: (+3.8%)
RandomText
NoStyle : 542,517 -> 555,951: (+2.5%)
NoStyle WithoutCache : 6,747,436 -> 6,723,770: (-0.4%)
Style : 1,022,591 -> 1,034,170: (+1.1%)
Style WithoutCache : 2,862,071 -> 2,835,226: (-0.9%)
android.widget.TextViewPrecomputedTextPerfTest:
newLayout
PrecomputedText : 791,018 -> 785,320: (-0.7%)
PrecomputedText Selectable : 1,569,428 -> 1,190,267: (-24.2%)
RandomText : 17,146,396 -> 17,064,908: (-0.5%)
RandomText Selectable : 18,239,348 -> 18,225,575: (-0.1%)
onDraw
PrecomputedText : 1,263,842 -> 1,286,294: (+1.8%)
PrecomputedText Selectable : 1,380,186 -> 1,303,995: (-5.5%)
RandomText : 17,734,725 -> 17,823,735: (+0.5%)
RandomText Selectable : 18,549,828 -> 18,610,101: (+0.3%)
onMeasure
PrecomputedText : 799,962 -> 809,164: (+1.2%)
PrecomputedText Selectable : 1,747,993 -> 1,358,504: (-22.3%)
RandomText : 17,155,624 -> 17,087,524: (-0.4%)
RandomText Selectable : 18,435,408 -> 18,515,944: (+0.4%)
setText
PrecomputedText : 136,250 -> 133,602: (-1.9%)
PrecomputedText Selectable : 213,980 -> 205,610: (-3.9%)
RandomText : 16,512 -> 16,599: (+0.5%)
RandomText Selectable : 56,143 -> 56,239: (+0.2%)
Bug: 77495049
Test: atest CtsWidgetTestCases:EditTextTest
CtsWidgetTestCases:TextViewFadingEdgeTest
FrameworksCoreTests:TextViewFallbackLineSpacingTest
FrameworksCoreTests:TextViewTest FrameworksCoreTests:TypefaceTest
CtsGraphicsTestCases:TypefaceTest CtsWidgetTestCases:TextViewTest
CtsTextTestCases FrameworksCoreTests:android.text
CtsWidgetTestCases:TextViewPrecomputedTextTest
Change-Id: I20d7cdd2f11960e334a1f2cd816679bb8f84e6cb
-rw-r--r-- | include/minikin/Layout.h | 78 | ||||
-rw-r--r-- | include/minikin/LayoutCache.h (renamed from libs/minikin/LayoutCache.h) | 4 | ||||
-rw-r--r-- | include/minikin/LayoutPieces.h | 76 | ||||
-rw-r--r-- | include/minikin/MeasuredText.h | 18 | ||||
-rw-r--r-- | include/minikin/Range.h | 3 | ||||
-rw-r--r-- | libs/minikin/Layout.cpp | 73 | ||||
-rw-r--r-- | libs/minikin/MeasuredText.cpp | 18 | ||||
-rw-r--r-- | tests/unittest/LayoutCacheTest.cpp | 4 | ||||
-rw-r--r-- | tests/unittest/LayoutTest.cpp | 17 | ||||
-rw-r--r-- | tests/unittest/LineBreakerTestHelper.h | 6 |
10 files changed, 195 insertions, 102 deletions
diff --git a/include/minikin/Layout.h b/include/minikin/Layout.h index 0676c8c..ba32d98 100644 --- a/include/minikin/Layout.h +++ b/include/minikin/Layout.h @@ -92,6 +92,11 @@ public: Bidi bidiFlags, const MinikinPaint& paint, StartHyphenEdit startHyphen, EndHyphenEdit endHyphen, const LayoutPieces& pieces); + static std::pair<float, MinikinRect> getBoundsWithPrecomputedPieces(const U16StringPiece& str, + const Range& range, + Bidi bidiFlags, + const MinikinPaint& paint, + const LayoutPieces& pieces); static float measureText(const U16StringPiece& str, const Range& range, Bidi bidiFlags, const MinikinPaint& paint, StartHyphenEdit startHyphen, @@ -123,6 +128,7 @@ public: float getCharAdvance(size_t i) const { return mAdvances[i]; } void getBounds(MinikinRect* rect) const; + const MinikinRect& getBounds() const { return mBounds; } // Purge all caches, useful in low memory conditions static void purgeCaches(); @@ -158,14 +164,15 @@ private: const MinikinPaint& paint, size_t dstStart, StartHyphenEdit startHyphen, EndHyphenEdit endHyphen, const LayoutPieces* lpIn, Layout* layout, float* advances, - MinikinExtent* extents, LayoutPieces* lpOut); + MinikinExtent* extents, MinikinRect* bounds, + LayoutPieces* lpOut); // Lay out a single word static float doLayoutWord(const uint16_t* buf, size_t start, size_t count, size_t bufSize, bool isRtl, const MinikinPaint& paint, size_t bufStart, StartHyphenEdit startHyphen, EndHyphenEdit endHyphen, const LayoutPieces* lpIn, Layout* layout, float* advances, - MinikinExtent* extents, LayoutPieces* lpOut); + MinikinExtent* extents, MinikinRect* bounds, LayoutPieces* lpOut); // Lay out a single bidi run void doLayoutRun(const uint16_t* buf, size_t start, size_t count, size_t bufSize, bool isRtl, @@ -184,73 +191,6 @@ private: MinikinRect mBounds; }; -struct LayoutPieces { - struct Key { - Key(const U16StringPiece& textBuf, const Range& range, HyphenEdit edit) - : text(textBuf.data()), length(textBuf.length()), range(range), hyphenEdit(edit) {} - - void makePersistent() { - uint16_t* copied = new uint16_t[length]; - std::copy(text, text + length, copied); - text = copied; - } - - inline bool operator==(const Key& o) const { - return length == o.length && hyphenEdit == o.hyphenEdit && range == o.range && - (text == o.text || memcmp(text, o.text, sizeof(uint16_t) * length) == 0); - } - - const uint16_t* text; - const uint32_t length; - Range range; - HyphenEdit hyphenEdit; - }; - - struct KeyHasher { - std::size_t operator()(const Key& key) const { - uint32_t hash = android::JenkinsHashMix(0, static_cast<uint8_t>(key.hyphenEdit)); - hash = android::JenkinsHashMix(hash, key.range.getStart()); - hash = android::JenkinsHashMix(hash, key.range.getEnd()); - hash = android::JenkinsHashMixShorts(hash, key.text, key.length); - return android::JenkinsHashWhiten(hash); - } - }; - - LayoutPieces() {} - - ~LayoutPieces() { - for (const auto it : offsetMap) { - delete[] it.first.text; - } - } - - std::unordered_map<Key, Layout, KeyHasher> offsetMap; - - void insert(const U16StringPiece& textBuf, const Range& range, HyphenEdit edit, - const Layout& layout) { - Key key(textBuf, range, edit); - key.makePersistent(); - offsetMap.insert(std::make_pair(key, layout)); - } - - const Layout* get(const U16StringPiece& textBuf, const Range& range, HyphenEdit edit) const { - auto it = offsetMap.find(Key(textBuf, range, edit)); - if (it == offsetMap.end()) { - return nullptr; - } - return &it->second; - } - - uint32_t getMemoryUsage() const { - uint32_t result = 0; - for (const auto& i : offsetMap) { - result += sizeof(Key) + sizeof(uint16_t) * i.first.length; - result += i.second.getMemoryUsage(); - } - return result; - } -}; - } // namespace minikin #endif // MINIKIN_LAYOUT_H diff --git a/libs/minikin/LayoutCache.h b/include/minikin/LayoutCache.h index 5b87fcc..e99fbe4 100644 --- a/libs/minikin/LayoutCache.h +++ b/include/minikin/LayoutCache.h @@ -24,8 +24,6 @@ #include <utils/JenkinsHash.h> #include <utils/LruCache.h> -#include "LocaleListCache.h" - namespace minikin { // Layout cache datatypes @@ -81,6 +79,8 @@ public: mEndHyphen); } + uint32_t getMemoryUsage() const { return sizeof(LayoutCacheKey) + sizeof(uint16_t) * mNchars; } + private: const uint16_t* mChars; size_t mNchars; diff --git a/include/minikin/LayoutPieces.h b/include/minikin/LayoutPieces.h new file mode 100644 index 0000000..f581372 --- /dev/null +++ b/include/minikin/LayoutPieces.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MINIKIN_LAYOUT_PIECES_H +#define MINIKIN_LAYOUT_PIECES_H + +#include <unordered_map> + +#include "minikin/Layout.h" +#include "minikin/LayoutCache.h" + +namespace minikin { + +struct LayoutPieces { + struct KeyHasher { + std::size_t operator()(const LayoutCacheKey& key) const { return key.hash(); } + }; + + LayoutPieces() {} + + ~LayoutPieces() { + for (const auto it : offsetMap) { + const_cast<LayoutCacheKey*>(&it.first)->freeText(); + } + } + + std::unordered_map<LayoutCacheKey, Layout, KeyHasher> offsetMap; + + void insert(const U16StringPiece& textBuf, const Range& range, const MinikinPaint& paint, + bool dir, StartHyphenEdit startEdit, EndHyphenEdit endEdit, const Layout& layout) { + auto result = offsetMap.emplace( + std::piecewise_construct, + std::forward_as_tuple(textBuf, range, paint, dir, startEdit, endEdit), + std::forward_as_tuple(layout)); + if (result.second) { + const_cast<LayoutCacheKey*>(&result.first->first)->copyText(); + } + } + + template <typename F> + void getOrCreate(const U16StringPiece& textBuf, const Range& range, const MinikinPaint& paint, + bool dir, StartHyphenEdit startEdit, EndHyphenEdit endEdit, F& f) const { + auto it = offsetMap.find(LayoutCacheKey(textBuf, range, paint, dir, startEdit, endEdit)); + if (it == offsetMap.end()) { + LayoutCache::getInstance().getOrCreate(textBuf, range, paint, dir, startEdit, endEdit, + f); + } else { + f(it->second); + } + } + + uint32_t getMemoryUsage() const { + uint32_t result = 0; + for (const auto& i : offsetMap) { + result += i.first.getMemoryUsage() + i.second.getMemoryUsage(); + } + return result; + } +}; + +} // namespace minikin + +#endif // MINIKIN_LAYOUT_PIECES_H diff --git a/include/minikin/MeasuredText.h b/include/minikin/MeasuredText.h index 474cdf3..d33a1ca 100644 --- a/include/minikin/MeasuredText.h +++ b/include/minikin/MeasuredText.h @@ -22,6 +22,7 @@ #include "minikin/FontCollection.h" #include "minikin/Layout.h" +#include "minikin/LayoutPieces.h" #include "minikin/Macros.h" #include "minikin/MinikinFont.h" #include "minikin/Range.h" @@ -47,6 +48,9 @@ public: virtual void getMetrics(const U16StringPiece& text, float* advances, MinikinExtent* extents, LayoutPieces* piece) const = 0; + virtual std::pair<float, MinikinRect> getBounds(const U16StringPiece& text, const Range& range, + const LayoutPieces& pieces) const = 0; + // Following two methods are only called when the implementation returns true for // canHyphenate method. @@ -85,6 +89,12 @@ public: EndHyphenEdit::NO_EDIT, advances, extents, pieces); } + std::pair<float, MinikinRect> getBounds(const U16StringPiece& text, const Range& range, + const LayoutPieces& pieces) const override { + Bidi bidiFlag = mIsRtl ? Bidi::FORCE_RTL : Bidi::FORCE_LTR; + return Layout::getBoundsWithPrecomputedPieces(text, range, bidiFlag, mPaint, pieces); + } + const MinikinPaint* getPaint() const override { return &mPaint; } float measureHyphenPiece(const U16StringPiece& text, const Range& range, @@ -115,6 +125,13 @@ public: // TODO: Get the extents information from the caller. } + std::pair<float, MinikinRect> getBounds(const U16StringPiece& /* text */, + const Range& /* range */, + const LayoutPieces& /* pieces */) const override { + // Bounding Box is not used in replacement run. + return std::make_pair(mWidth, MinikinRect()); + } + private: const float mWidth; const uint32_t mLocaleListId; @@ -165,6 +182,7 @@ public: void buildLayout(const U16StringPiece& textBuf, const Range& range, const MinikinPaint& paint, Bidi bidiFlag, StartHyphenEdit startHyphen, EndHyphenEdit endHyphen, Layout* layout); + MinikinRect getBounds(const U16StringPiece& textBuf, const Range& range); MeasuredText(MeasuredText&&) = default; MeasuredText& operator=(MeasuredText&&) = default; diff --git a/include/minikin/Range.h b/include/minikin/Range.h index 2efde7e..4c7fbfa 100644 --- a/include/minikin/Range.h +++ b/include/minikin/Range.h @@ -73,6 +73,9 @@ public: return left.isValid() && right.isValid() && left.mStart < right.mEnd && right.mStart < left.mEnd; } + inline static Range intersection(const Range& left, const Range& right) { + return Range(std::max(left.mStart, right.mStart), std::min(left.mEnd, right.mEnd)); + } // Returns merged range. This method assumes left and right are not invalid ranges and they have // an intersection. diff --git a/libs/minikin/Layout.cpp b/libs/minikin/Layout.cpp index 4383d60..1b05274 100644 --- a/libs/minikin/Layout.cpp +++ b/libs/minikin/Layout.cpp @@ -34,10 +34,11 @@ #include "minikin/Emoji.h" #include "minikin/HbUtils.h" +#include "minikin/LayoutCache.h" +#include "minikin/LayoutPieces.h" #include "minikin/Macros.h" #include "BidiUtils.h" -#include "LayoutCache.h" #include "LayoutUtils.h" #include "LocaleListCache.h" #include "MinikinInternal.h" @@ -234,7 +235,8 @@ void Layout::doLayout(const U16StringPiece& textBuf, const Range& range, Bidi bi for (const BidiText::RunInfo& runInfo : BidiText(textBuf, range, bidiFlags)) { doLayoutRunCached(textBuf, runInfo.range, runInfo.isRtl, paint, range.getStart(), - startHyphen, endHyphen, nullptr, this, nullptr, nullptr, nullptr); + startHyphen, endHyphen, nullptr, this, nullptr, nullptr, nullptr, + nullptr); } } @@ -249,10 +251,25 @@ void Layout::doLayoutWithPrecomputedPieces(const U16StringPiece& textBuf, const for (const BidiText::RunInfo& runInfo : BidiText(textBuf, range, bidiFlags)) { doLayoutRunCached(textBuf, runInfo.range, runInfo.isRtl, paint, range.getStart(), - startHyphen, endHyphen, &lpIn, this, nullptr, nullptr, nullptr); + startHyphen, endHyphen, &lpIn, this, nullptr, nullptr, nullptr, nullptr); } } +std::pair<float, MinikinRect> Layout::getBoundsWithPrecomputedPieces(const U16StringPiece& textBuf, + const Range& range, + Bidi bidiFlags, + const MinikinPaint& paint, + const LayoutPieces& pieces) { + MinikinRect rect; + float advance = 0; + for (const BidiText::RunInfo& runInfo : BidiText(textBuf, range, bidiFlags)) { + advance += doLayoutRunCached(textBuf, runInfo.range, runInfo.isRtl, paint, 0, + StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT, &pieces, + nullptr, nullptr, nullptr, &rect, nullptr); + } + return std::make_pair(advance, rect); +} + float Layout::measureText(const U16StringPiece& textBuf, const Range& range, Bidi bidiFlags, const MinikinPaint& paint, StartHyphenEdit startHyphen, EndHyphenEdit endHyphen, float* advances, MinikinExtent* extents, @@ -264,7 +281,7 @@ float Layout::measureText(const U16StringPiece& textBuf, const Range& range, Bid MinikinExtent* extentsForRun = extents ? extents + offset : nullptr; advance += doLayoutRunCached(textBuf, runInfo.range, runInfo.isRtl, paint, 0, startHyphen, endHyphen, nullptr, nullptr, advancesForRun, extentsForRun, - pieces); + nullptr, pieces); } return advance; } @@ -273,7 +290,7 @@ float Layout::doLayoutRunCached(const U16StringPiece& textBuf, const Range& rang const MinikinPaint& paint, size_t dstStart, StartHyphenEdit startHyphen, EndHyphenEdit endHyphen, const LayoutPieces* lpIn, Layout* layout, float* advances, - MinikinExtent* extents, LayoutPieces* lpOut) { + MinikinExtent* extents, MinikinRect* bounds, LayoutPieces* lpOut) { if (!range.isValid()) { return 0.0f; // ICU failed to retrieve the bidi run? } @@ -297,7 +314,7 @@ float Layout::doLayoutRunCached(const U16StringPiece& textBuf, const Range& rang iter == start ? startHyphen : StartHyphenEdit::NO_EDIT, wordend >= end ? endHyphen : EndHyphenEdit::NO_EDIT, lpIn, layout, advances ? advances + offset : nullptr, - extents ? extents + offset : nullptr, lpOut); + extents ? extents + offset : nullptr, bounds, lpOut); wordstart = wordend; } } else { @@ -315,7 +332,7 @@ float Layout::doLayoutRunCached(const U16StringPiece& textBuf, const Range& rang wordstart <= start ? startHyphen : StartHyphenEdit::NO_EDIT, iter == end ? endHyphen : EndHyphenEdit::NO_EDIT, lpIn, layout, advances ? advances + offset : nullptr, - extents ? extents + offset : nullptr, lpOut); + extents ? extents + offset : nullptr, bounds, lpOut); wordend = wordstart; } } @@ -324,18 +341,23 @@ float Layout::doLayoutRunCached(const U16StringPiece& textBuf, const Range& rang class LayoutAppendFunctor { public: - LayoutAppendFunctor(const U16StringPiece& textBuf, const Range& range, HyphenEdit hyphenEdit, - Layout* layout, float* advances, MinikinExtent* extents, - LayoutPieces* pieces, float* totalAdvance, uint32_t outOffset, - float wordSpacing) + LayoutAppendFunctor(const U16StringPiece& textBuf, const Range& range, + const MinikinPaint& paint, bool dir, StartHyphenEdit startEdit, + EndHyphenEdit endEdit, Layout* layout, float* advances, + MinikinExtent* extents, LayoutPieces* pieces, float* totalAdvance, + MinikinRect* bounds, uint32_t outOffset, float wordSpacing) : mTextBuf(textBuf), mRange(range), - mHyphenEdit(hyphenEdit), + mPaint(paint), + mDir(dir), + mStartEdit(startEdit), + mEndEdit(endEdit), mLayout(layout), mAdvances(advances), mExtents(extents), mPieces(pieces), mTotalAdvance(totalAdvance), + mBounds(bounds), mOutOffset(outOffset), mWordSpacing(wordSpacing) {} @@ -352,20 +374,27 @@ public: if (mExtents) { layout.getExtents(mExtents); } + if (mBounds) { + mBounds->join(layout.getBounds()); + } if (mPieces) { - mPieces->insert(mTextBuf, mRange, mHyphenEdit, layout); + mPieces->insert(mTextBuf, mRange, mPaint, mDir, mStartEdit, mEndEdit, layout); } } private: const U16StringPiece& mTextBuf; const Range& mRange; - HyphenEdit mHyphenEdit; + const MinikinPaint& mPaint; + bool mDir; + StartHyphenEdit mStartEdit; + EndHyphenEdit mEndEdit; Layout* mLayout; float* mAdvances; MinikinExtent* mExtents; LayoutPieces* mPieces; float* mTotalAdvance; + MinikinRect* mBounds; const uint32_t mOutOffset; const float mWordSpacing; }; @@ -374,22 +403,16 @@ float Layout::doLayoutWord(const uint16_t* buf, size_t start, size_t count, size bool isRtl, const MinikinPaint& paint, size_t bufStart, StartHyphenEdit startHyphen, EndHyphenEdit endHyphen, const LayoutPieces* lpIn, Layout* layout, float* advances, - MinikinExtent* extents, LayoutPieces* lpOut) { + MinikinExtent* extents, MinikinRect* bounds, LayoutPieces* lpOut) { float wordSpacing = count == 1 && isWordSpace(buf[start]) ? paint.wordSpacing : 0; float totalAdvance; const U16StringPiece textBuf(buf, bufSize); const Range range(start, start + count); - HyphenEdit hyphenEdit = packHyphenEdit(startHyphen, endHyphen); - - LayoutAppendFunctor f(textBuf, range, hyphenEdit, layout, advances, extents, lpOut, - &totalAdvance, bufStart, wordSpacing); - - const Layout* layoutInPieces = - lpIn == nullptr ? nullptr : lpIn->get(textBuf, range, hyphenEdit); - - if (layoutInPieces != nullptr) { - f(*layoutInPieces); + LayoutAppendFunctor f(textBuf, range, paint, isRtl, startHyphen, endHyphen, layout, advances, + extents, lpOut, &totalAdvance, bounds, bufStart, wordSpacing); + if (lpIn != nullptr) { + lpIn->getOrCreate(textBuf, range, paint, isRtl, startHyphen, endHyphen, f); } else { LayoutCache::getInstance().getOrCreate(textBuf, range, paint, isRtl, startHyphen, endHyphen, f); diff --git a/libs/minikin/MeasuredText.cpp b/libs/minikin/MeasuredText.cpp index 7be949b..bbc6091 100644 --- a/libs/minikin/MeasuredText.cpp +++ b/libs/minikin/MeasuredText.cpp @@ -63,4 +63,22 @@ void MeasuredText::buildLayout(const U16StringPiece& textBuf, const Range& range layoutPieces); } +MinikinRect MeasuredText::getBounds(const U16StringPiece& textBuf, const Range& range) { + MinikinRect rect; + float advance = 0.0f; + for (const auto& run : runs) { + const Range& runRange = run->getRange(); + if (!Range::intersects(range, runRange)) { + continue; + } + std::pair<float, MinikinRect> next = + run->getBounds(textBuf, Range::intersection(runRange, range), layoutPieces); + MinikinRect nextRect = next.second; + nextRect.offset(advance, 0); + rect.join(nextRect); + advance += next.first; + } + return rect; +} + } // namespace minikin diff --git a/tests/unittest/LayoutCacheTest.cpp b/tests/unittest/LayoutCacheTest.cpp index 8235556..b7ad0ba 100644 --- a/tests/unittest/LayoutCacheTest.cpp +++ b/tests/unittest/LayoutCacheTest.cpp @@ -18,8 +18,10 @@ #include <gtest/gtest.h> +#include "minikin/LayoutCache.h" + #include "FontTestUtils.h" -#include "LayoutCache.h" +#include "LocaleListCache.h" #include "UnicodeUtils.h" namespace minikin { diff --git a/tests/unittest/LayoutTest.cpp b/tests/unittest/LayoutTest.cpp index 830dc92..21109cb 100644 --- a/tests/unittest/LayoutTest.cpp +++ b/tests/unittest/LayoutTest.cpp @@ -19,6 +19,7 @@ #include <gtest/gtest.h> #include "minikin/FontCollection.h" +#include "minikin/LayoutPieces.h" #include "FontTestUtils.h" #include "UnicodeUtils.h" @@ -554,12 +555,14 @@ TEST_F(LayoutTest, doLayoutWithPrecomputedPiecesTest) { float MARKER1 = 1e+16; float MARKER2 = 1e+17; auto fc = buildFontCollection("LayoutTestFont.ttf"); + MinikinPaint paint(fc); { LayoutPieces pieces; Layout inLayout = doLayout("I", MinikinPaint(fc)); inLayout.mAdvances[0] = MARKER1; // Modify the advance to make sure this layout is used. - pieces.insert(utf8ToUtf16("I"), Range(0, 1), 0 /* hyphen edit */, inLayout); + pieces.insert(utf8ToUtf16("I"), Range(0, 1), paint, false /* dir */, + StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT, inLayout); Layout outLayout = doLayoutWithPrecomputedPieces("I", MinikinPaint(fc), pieces); EXPECT_EQ(MARKER1, outLayout.mAdvances[0]); @@ -569,7 +572,8 @@ TEST_F(LayoutTest, doLayoutWithPrecomputedPiecesTest) { Layout inLayout = doLayout("I", MinikinPaint(fc)); inLayout.mAdvances[0] = MARKER1; - pieces.insert(utf8ToUtf16("I"), Range(0, 1), 0 /* hyphen edit */, inLayout); + pieces.insert(utf8ToUtf16("I"), Range(0, 1), paint, false /* dir */, + StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT, inLayout); Layout outLayout = doLayoutWithPrecomputedPieces("II", MinikinPaint(fc), pieces); // The layout pieces are used in word units. Should not be used "I" for "II". @@ -581,7 +585,8 @@ TEST_F(LayoutTest, doLayoutWithPrecomputedPiecesTest) { Layout inLayout = doLayout("I", MinikinPaint(fc)); inLayout.mAdvances[0] = MARKER1; - pieces.insert(utf8ToUtf16("I"), Range(0, 1), 0 /* hyphen edit */, inLayout); + pieces.insert(utf8ToUtf16("I"), Range(0, 1), paint, false /* dir */, + StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT, inLayout); Layout outLayout = doLayoutWithPrecomputedPieces("I I", MinikinPaint(fc), pieces); EXPECT_EQ(MARKER1, outLayout.mAdvances[0]); @@ -592,11 +597,13 @@ TEST_F(LayoutTest, doLayoutWithPrecomputedPiecesTest) { Layout inLayout = doLayout("I", MinikinPaint(fc)); inLayout.mAdvances[0] = MARKER1; // Modify the advance to make sure this layout is used. - pieces.insert(utf8ToUtf16("I"), Range(0, 1), 0 /* hyphen edit */, inLayout); + pieces.insert(utf8ToUtf16("I"), Range(0, 1), paint, false /* dir */, + StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT, inLayout); inLayout = doLayout("V", MinikinPaint(fc)); inLayout.mAdvances[0] = MARKER2; // Modify the advance to make sure this layout is used. - pieces.insert(utf8ToUtf16("V"), Range(0, 1), 0 /* hyphen edit */, inLayout); + pieces.insert(utf8ToUtf16("V"), Range(0, 1), paint, false /* dir */, + StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT, inLayout); Layout outLayout = doLayoutWithPrecomputedPieces("I V", MinikinPaint(fc), pieces); EXPECT_EQ(MARKER1, outLayout.mAdvances[0]); diff --git a/tests/unittest/LineBreakerTestHelper.h b/tests/unittest/LineBreakerTestHelper.h index d6ab740..70d6521 100644 --- a/tests/unittest/LineBreakerTestHelper.h +++ b/tests/unittest/LineBreakerTestHelper.h @@ -57,6 +57,12 @@ public: std::fill(advances, advances + mRange.getLength(), mWidth); } + virtual std::pair<float, MinikinRect> getBounds(const U16StringPiece& /* text */, + const Range& /* range */, + const LayoutPieces& /* pieces */) const { + return std::make_pair(mWidth, MinikinRect()); + } + virtual const MinikinPaint* getPaint() const { return &mPaint; } virtual float measureHyphenPiece(const U16StringPiece&, const Range& range, |