summaryrefslogtreecommitdiff
path: root/libs/minikin
diff options
context:
space:
mode:
authorTreehugger Robot <android-test-infra-autosubmit@system.gserviceaccount.com>2023-07-29 05:14:56 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2023-07-29 05:14:56 +0000
commit25c952f037413c9a5efe42bbae947b93f5af6d23 (patch)
treebe092a5f1a4d28e74b56e53678aad7eda766cf29 /libs/minikin
parent449a3da391bd09be201eef20f4df3b96190217ef (diff)
parent3e28061881b2c2c81720ceae067d1f42410aa9c1 (diff)
downloadminikin-25c952f037413c9a5efe42bbae947b93f5af6d23.tar.gz
Merge "Revert "Compute bounding box and use it during line break"" into main
Diffstat (limited to 'libs/minikin')
-rw-r--r--libs/minikin/Android.bp1
-rw-r--r--libs/minikin/BoundsCache.cpp43
-rw-r--r--libs/minikin/Debug.cpp3
-rw-r--r--libs/minikin/GreedyLineBreaker.cpp84
-rw-r--r--libs/minikin/GreedyLineBreaker.h2
-rw-r--r--libs/minikin/Layout.cpp63
-rw-r--r--libs/minikin/LayoutCore.cpp34
-rw-r--r--libs/minikin/LineBreaker.cpp8
-rw-r--r--libs/minikin/LineBreakerUtil.h9
-rw-r--r--libs/minikin/MeasuredText.cpp139
-rw-r--r--libs/minikin/Measurement.cpp26
-rw-r--r--libs/minikin/OptimalLineBreaker.cpp74
-rw-r--r--libs/minikin/OptimalLineBreaker.h3
13 files changed, 182 insertions, 307 deletions
diff --git a/libs/minikin/Android.bp b/libs/minikin/Android.bp
index c406015..f5af693 100644
--- a/libs/minikin/Android.bp
+++ b/libs/minikin/Android.bp
@@ -28,6 +28,7 @@ cc_library {
host_supported: true,
srcs: [
"BidiUtils.cpp",
+ "BoundsCache.cpp",
"CmapCoverage.cpp",
"Emoji.cpp",
"Font.cpp",
diff --git a/libs/minikin/BoundsCache.cpp b/libs/minikin/BoundsCache.cpp
new file mode 100644
index 0000000..95b453b
--- /dev/null
+++ b/libs/minikin/BoundsCache.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#include "minikin/BoundsCache.h"
+
+namespace minikin {
+
+void ValueExtractor::operator()(const LayoutPiece& layoutPiece, const MinikinPaint& paint) {
+ value.reset(new BoundsValue);
+ value->rect = BoundsCache::getBounds(layoutPiece, paint);
+ value->advance = layoutPiece.advance();
+}
+
+// static
+MinikinRect BoundsCache::getBounds(const LayoutPiece& layoutPiece, const MinikinPaint& paint) {
+ MinikinRect pieceBounds;
+ MinikinRect tmpRect;
+ for (uint32_t i = 0; i < layoutPiece.glyphCount(); ++i) {
+ const FakedFont& font = layoutPiece.fontAt(i);
+ const Point& point = layoutPiece.pointAt(i);
+
+ MinikinFont* minikinFont = font.typeface().get();
+ minikinFont->GetBounds(&tmpRect, layoutPiece.glyphIdAt(i), paint, font.fakery);
+ tmpRect.offset(point.x, point.y);
+ pieceBounds.join(tmpRect);
+ }
+ return pieceBounds;
+}
+
+} // namespace minikin
diff --git a/libs/minikin/Debug.cpp b/libs/minikin/Debug.cpp
index 42d6d8e..6c48a39 100644
--- a/libs/minikin/Debug.cpp
+++ b/libs/minikin/Debug.cpp
@@ -81,8 +81,7 @@ std::string toString(const MinikinExtent& extent) {
std::string toString(const LayoutPiece& layout) {
std::stringstream ss;
- ss << "{advance=" << layout.advance() << ", extent=" << toString(layout.extent())
- << ", glyphs=";
+ ss << "advance=" << layout.advance() << ", extent=" << toString(layout.extent()) << ", glyphs=";
for (uint32_t i = 0; i < layout.glyphCount(); ++i) {
ss << "{id:" << layout.glyphIdAt(i) << ", pos = " << toString(layout.pointAt(i))
diff --git a/libs/minikin/GreedyLineBreaker.cpp b/libs/minikin/GreedyLineBreaker.cpp
index ecaf895..bb2f91c 100644
--- a/libs/minikin/GreedyLineBreaker.cpp
+++ b/libs/minikin/GreedyLineBreaker.cpp
@@ -40,14 +40,13 @@ public:
// destructed.
GreedyLineBreaker(const U16StringPiece& textBuf, const MeasuredText& measured,
const LineWidth& lineWidthLimits, const TabStops& tabStops,
- bool enableHyphenation, bool useBoundsForWidth)
+ bool enableHyphenation)
: mLineWidthLimit(lineWidthLimits.getAt(0)),
mTextBuf(textBuf),
mMeasuredText(measured),
mLineWidthLimits(lineWidthLimits),
mTabStops(tabStops),
- mEnableHyphenation(enableHyphenation),
- mUseBoundsForWidth(useBoundsForWidth) {}
+ mEnableHyphenation(enableHyphenation) {}
void process();
@@ -100,8 +99,6 @@ private:
// This method return true if there is no characters to be processed.
bool doLineBreakWithGraphemeBounds(const Range& range);
- bool overhangExceedLineLimit(const Range& range);
-
// Info about the line currently processing.
uint32_t mLineNum = 0;
double mLineWidth = 0;
@@ -124,7 +121,6 @@ private:
const LineWidth& mLineWidthLimits;
const TabStops& mTabStops;
bool mEnableHyphenation;
- bool mUseBoundsForWidth;
// The result of line breaking.
std::vector<BreakPoint> mBreakPoints;
@@ -267,8 +263,7 @@ bool GreedyLineBreaker::doLineBreakWithGraphemeBounds(const Range& range) {
if (w == 0) {
continue; // w == 0 means here is not a grapheme bounds. Don't break here.
}
- if (width + w > mLineWidthLimit ||
- overhangExceedLineLimit(Range(range.getStart(), i + 1))) {
+ if (width + w > mLineWidthLimit) {
// Okay, here is the longest position.
breakLineAt(i, width, mLineWidth - width, mSumOfCharWidths - width,
EndHyphenEdit::NO_EDIT, StartHyphenEdit::NO_EDIT);
@@ -299,44 +294,18 @@ void GreedyLineBreaker::updateLineWidth(uint16_t c, float width) {
}
}
-bool GreedyLineBreaker::overhangExceedLineLimit(const Range& range) {
- if (!mUseBoundsForWidth) {
- return false;
- }
- if (!mMeasuredText.hasOverhang(range)) {
- return false;
- }
-
- uint32_t i;
- for (i = 0; i < range.getLength(); ++i) {
- uint16_t ch = mTextBuf[range.getEnd() - i - 1];
- if (!isLineEndSpace(ch)) {
- break;
- }
- }
- if (i == range.getLength()) {
- return false;
- }
-
- return mMeasuredText.getBounds(mTextBuf, Range(range.getStart(), range.getEnd() - i)).width() >
- mLineWidthLimit;
-}
-
void GreedyLineBreaker::processLineBreak(uint32_t offset, WordBreaker* breaker,
bool doHyphenation) {
- while (mLineWidth > mLineWidthLimit ||
- overhangExceedLineLimit(Range(getPrevLineBreakOffset(), offset))) {
+ while (mLineWidth > mLineWidthLimit) {
+ const Range lineRange(getPrevLineBreakOffset(), offset); // The range we need to address.
if (tryLineBreakWithWordBreak()) {
continue; // The word in the new line may still be too long for the line limit.
- }
-
- if (doHyphenation &&
- tryLineBreakWithHyphenation(Range(getPrevLineBreakOffset(), offset), breaker)) {
+ } else if (doHyphenation && tryLineBreakWithHyphenation(lineRange, breaker)) {
continue; // TODO: we may be able to return here.
- }
-
- if (doLineBreakWithGraphemeBounds(Range(getPrevLineBreakOffset(), offset))) {
- return;
+ } else {
+ if (doLineBreakWithGraphemeBounds(lineRange)) {
+ return;
+ }
}
}
@@ -402,32 +371,12 @@ LineBreakResult GreedyLineBreaker::getResult() const {
hasTabChar |= mTextBuf[i] == CHAR_TAB;
}
- if (mUseBoundsForWidth) {
- Range range = Range(prevBreakOffset, breakPoint.offset);
- Range actualRange = trimTrailingLineEndSpaces(mTextBuf, range);
- if (actualRange.isEmpty()) {
- // No characters before the line-end-spaces.
- MinikinExtent extent = mMeasuredText.getExtent(mTextBuf, range);
- out.ascents.push_back(extent.ascent);
- out.descents.push_back(extent.descent);
- out.bounds.emplace_back(0, extent.ascent, breakPoint.lineWidth, extent.descent);
- } else {
- LineMetrics metrics = mMeasuredText.getLineMetrics(mTextBuf, actualRange);
- out.ascents.push_back(metrics.extent.ascent);
- out.descents.push_back(metrics.extent.descent);
- out.bounds.emplace_back(metrics.bounds);
- }
- } else {
- MinikinExtent extent =
- mMeasuredText.getExtent(mTextBuf, Range(prevBreakOffset, breakPoint.offset));
- out.ascents.push_back(extent.ascent);
- out.descents.push_back(extent.descent);
- // We don't have bounding box if mUseBoundsForWidth is false. Use line ascent/descent
- // and linew width for the bounding box.
- out.bounds.emplace_back(0, extent.ascent, breakPoint.lineWidth, extent.descent);
- }
+ MinikinExtent extent =
+ mMeasuredText.getExtent(mTextBuf, Range(prevBreakOffset, breakPoint.offset));
out.breakPoints.push_back(breakPoint.offset);
out.widths.push_back(breakPoint.lineWidth);
+ out.ascents.push_back(extent.ascent);
+ out.descents.push_back(extent.descent);
out.flags.push_back((hasTabChar ? TAB_BIT : 0) | static_cast<int>(breakPoint.hyphenEdit));
prevBreakOffset = breakPoint.offset;
@@ -439,12 +388,11 @@ LineBreakResult GreedyLineBreaker::getResult() const {
LineBreakResult breakLineGreedy(const U16StringPiece& textBuf, const MeasuredText& measured,
const LineWidth& lineWidthLimits, const TabStops& tabStops,
- bool enableHyphenation, bool useBoundsForWidth) {
+ bool enableHyphenation) {
if (textBuf.size() == 0) {
return LineBreakResult();
}
- GreedyLineBreaker lineBreaker(textBuf, measured, lineWidthLimits, tabStops, enableHyphenation,
- useBoundsForWidth);
+ GreedyLineBreaker lineBreaker(textBuf, measured, lineWidthLimits, tabStops, enableHyphenation);
lineBreaker.process();
return lineBreaker.getResult();
}
diff --git a/libs/minikin/GreedyLineBreaker.h b/libs/minikin/GreedyLineBreaker.h
index 9d17ec2..ead93e4 100644
--- a/libs/minikin/GreedyLineBreaker.h
+++ b/libs/minikin/GreedyLineBreaker.h
@@ -27,7 +27,7 @@ namespace minikin {
LineBreakResult breakLineGreedy(const U16StringPiece& textBuf, const MeasuredText& measured,
const LineWidth& lineWidthLimits, const TabStops& tabStops,
- bool enableHyphenation, bool useBoundsForWidth);
+ bool enableHyphenation);
} // namespace minikin
diff --git a/libs/minikin/Layout.cpp b/libs/minikin/Layout.cpp
index ad16796..e7d41c8 100644
--- a/libs/minikin/Layout.cpp
+++ b/libs/minikin/Layout.cpp
@@ -53,27 +53,19 @@ void Layout::doLayout(const U16StringPiece& textBuf, const Range& range, Bidi bi
mGlyphs.reserve(count);
for (const BidiText::RunInfo& runInfo : BidiText(textBuf, range, bidiFlags)) {
doLayoutRunCached(textBuf, runInfo.range, runInfo.isRtl, paint, range.getStart(),
- startHyphen, endHyphen, this, nullptr, nullptr);
+ startHyphen, endHyphen, this, nullptr);
}
}
float Layout::measureText(const U16StringPiece& textBuf, const Range& range, Bidi bidiFlags,
const MinikinPaint& paint, StartHyphenEdit startHyphen,
- EndHyphenEdit endHyphen, float* advances, MinikinRect* bounds) {
+ EndHyphenEdit endHyphen, float* advances) {
float advance = 0;
-
- MinikinRect tmpBounds;
for (const BidiText::RunInfo& runInfo : BidiText(textBuf, range, bidiFlags)) {
const size_t offset = range.toRangeOffset(runInfo.range.getStart());
float* advancesForRun = advances ? advances + offset : nullptr;
- tmpBounds.setEmpty();
- float run_advance = doLayoutRunCached(textBuf, runInfo.range, runInfo.isRtl, paint, 0,
- startHyphen, endHyphen, nullptr, advancesForRun,
- bounds ? &tmpBounds : nullptr);
- if (bounds) {
- bounds->join(tmpBounds, advance, 0);
- }
- advance += run_advance;
+ advance += doLayoutRunCached(textBuf, runInfo.range, runInfo.isRtl, paint, 0, startHyphen,
+ endHyphen, nullptr, advancesForRun);
}
return advance;
}
@@ -81,12 +73,11 @@ float Layout::measureText(const U16StringPiece& textBuf, const Range& range, Bid
float Layout::doLayoutRunCached(const U16StringPiece& textBuf, const Range& range, bool isRtl,
const MinikinPaint& paint, size_t dstStart,
StartHyphenEdit startHyphen, EndHyphenEdit endHyphen,
- Layout* layout, float* advances, MinikinRect* bounds) {
+ Layout* layout, float* advances) {
if (!range.isValid()) {
return 0.0f; // ICU failed to retrieve the bidi run?
}
float advance = 0;
- MinikinRect tmpBounds;
for (const auto[context, piece] : LayoutSplitter(textBuf, range, isRtl)) {
// Hyphenation only applies to the start/end of run.
const StartHyphenEdit pieceStartHyphen =
@@ -95,32 +86,25 @@ float Layout::doLayoutRunCached(const U16StringPiece& textBuf, const Range& rang
(piece.getEnd() == range.getEnd()) ? endHyphen : EndHyphenEdit::NO_EDIT;
float* advancesForRun =
advances ? advances + (piece.getStart() - range.getStart()) : nullptr;
- tmpBounds.setEmpty();
- float word_advance = doLayoutWord(
- textBuf.data() + context.getStart(), piece.getStart() - context.getStart(),
- piece.getLength(), context.getLength(), isRtl, paint, piece.getStart() - dstStart,
- pieceStartHyphen, pieceEndHyphen, layout, advancesForRun,
- bounds ? &tmpBounds : nullptr);
- if (bounds) {
- bounds->join(tmpBounds, advance, 0);
- }
- advance += word_advance;
+ advance += doLayoutWord(textBuf.data() + context.getStart(),
+ piece.getStart() - context.getStart(), piece.getLength(),
+ context.getLength(), isRtl, paint, piece.getStart() - dstStart,
+ pieceStartHyphen, pieceEndHyphen, layout, advancesForRun);
}
return advance;
}
class LayoutAppendFunctor {
public:
- LayoutAppendFunctor(Layout* layout, float* advances, uint32_t outOffset, float wordSpacing,
- MinikinRect* bounds)
+ LayoutAppendFunctor(Layout* layout, float* advances, float* totalAdvance, uint32_t outOffset,
+ float wordSpacing)
: mLayout(layout),
mAdvances(advances),
+ mTotalAdvance(totalAdvance),
mOutOffset(outOffset),
- mWordSpacing(wordSpacing),
- mBounds(bounds) {}
+ mWordSpacing(wordSpacing) {}
- void operator()(const LayoutPiece& layoutPiece, const MinikinPaint& /* paint */,
- const MinikinRect& bounds) {
+ void operator()(const LayoutPiece& layoutPiece, const MinikinPaint& /* paint */) {
if (mLayout) {
mLayout->appendLayout(layoutPiece, mOutOffset, mWordSpacing);
}
@@ -128,37 +112,30 @@ public:
const std::vector<float>& advances = layoutPiece.advances();
std::copy(advances.begin(), advances.end(), mAdvances);
}
- if (mBounds) {
- mBounds->join(bounds, mTotalAdvance, 0);
+ if (mTotalAdvance) {
+ *mTotalAdvance = layoutPiece.advance();
}
- mTotalAdvance += layoutPiece.advance();
}
- float getTotalAdvance() { return mTotalAdvance; }
-
private:
Layout* mLayout;
float* mAdvances;
- float mTotalAdvance;
+ float* mTotalAdvance;
const uint32_t mOutOffset;
const float mWordSpacing;
- MinikinRect* mBounds;
};
float Layout::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, Layout* layout,
- float* advances, MinikinRect* bounds) {
+ float* advances) {
float wordSpacing = count == 1 && isWordSpace(buf[start]) ? paint.wordSpacing : 0;
float totalAdvance = 0;
- const bool boundsCalculation = bounds != nullptr;
const U16StringPiece textBuf(buf, bufSize);
const Range range(start, start + count);
- LayoutAppendFunctor f(layout, advances, bufStart, wordSpacing, bounds);
- LayoutCache::getInstance().getOrCreate(textBuf, range, paint, isRtl, startHyphen, endHyphen,
- boundsCalculation, f);
- totalAdvance = f.getTotalAdvance();
+ LayoutAppendFunctor f(layout, advances, &totalAdvance, bufStart, wordSpacing);
+ LayoutCache::getInstance().getOrCreate(textBuf, range, paint, isRtl, startHyphen, endHyphen, f);
if (wordSpacing != 0) {
totalAdvance += wordSpacing;
diff --git a/libs/minikin/LayoutCore.cpp b/libs/minikin/LayoutCore.cpp
index bc907fd..6ba6491 100644
--- a/libs/minikin/LayoutCore.cpp
+++ b/libs/minikin/LayoutCore.cpp
@@ -332,11 +332,17 @@ LayoutPiece::LayoutPiece(const U16StringPiece& textBuf, const Range& range, bool
const size_t bufSize = textBuf.size();
mAdvances.resize(count, 0); // Need zero filling.
+#ifdef FEATURE_HORIZONTAL_CLIPPING
+ mFlags.resize(count, 0);
+#endif // FEATURE_HORIZONTAL_CLIPPING
// Usually the number of glyphs are less than number of code units.
mFontIndices.reserve(count);
mGlyphIds.reserve(count);
mPoints.reserve(count);
+#ifdef FEATURE_HORIZONTAL_CLIPPING
+ mGlyphBounds.reserve(count);
+#endif // FEATURE_HORIZONTAL_CLIPPING
HbBufferUniquePtr buffer(hb_buffer_create());
U16StringPiece substr = textBuf.substr(range);
@@ -475,8 +481,18 @@ LayoutPiece::LayoutPiece(const U16StringPiece& textBuf, const Range& range, bool
mPoints.emplace_back(x + xoff, y + yoff);
float xAdvance = HBFixedToFloat(positions[i].x_advance);
+#ifdef FEATURE_HORIZONTAL_CLIPPING
+ MinikinRect bounds;
+ fakedFont.font->typeface()->GetBounds(&bounds, glyph_ix, paint, fakedFont.fakery);
+ bounds.offset(x + xoff, y + yoff);
+
+ mGlyphBounds.emplace_back(bounds.mLeft, bounds.mTop, bounds.mRight, bounds.mBottom);
+#endif // FEATURE_HORIZONTAL_CLIPPING
if (clusterBaseIndex < count) {
mAdvances[clusterBaseIndex] += xAdvance;
+#ifdef FEATURE_HORIZONTAL_CLIPPING
+ mFlags[clusterBaseIndex] = bounds.mLeft < x || bounds.mRight > x + xAdvance;
+#endif // FEATURE_HORIZONTAL_CLIPPING
} else {
ALOGE("cluster %zu (start %zu) out of bounds of count %zu", clusterBaseIndex,
start, count);
@@ -492,24 +508,12 @@ LayoutPiece::LayoutPiece(const U16StringPiece& textBuf, const Range& range, bool
mFontIndices.shrink_to_fit();
mGlyphIds.shrink_to_fit();
mPoints.shrink_to_fit();
+#ifdef FEATURE_HORIZONTAL_CLIPPING
+ mGlyphBounds.shrink_to_fit();
+#endif // FEATURE_HORIZONTAL_CLIPPING
mAdvance = x;
}
-// static
-MinikinRect LayoutPiece::calculateBounds(const LayoutPiece& layout, const MinikinPaint& paint) {
- MinikinRect out;
- for (uint32_t i = 0; i < layout.glyphCount(); ++i) {
- MinikinRect bounds;
- uint32_t glyphId = layout.glyphIdAt(i);
- const FakedFont& fakedFont = layout.fontAt(i);
- const Point& pos = layout.pointAt(i);
-
- fakedFont.typeface()->GetBounds(&bounds, glyphId, paint, fakedFont.fakery);
- out.join(bounds, pos);
- }
- return out;
-}
-
LayoutPiece::~LayoutPiece() {}
} // namespace minikin
diff --git a/libs/minikin/LineBreaker.cpp b/libs/minikin/LineBreaker.cpp
index 20a075c..12cf9bd 100644
--- a/libs/minikin/LineBreaker.cpp
+++ b/libs/minikin/LineBreaker.cpp
@@ -24,13 +24,13 @@ namespace minikin {
LineBreakResult breakIntoLines(const U16StringPiece& textBuffer, BreakStrategy strategy,
HyphenationFrequency frequency, bool justified,
const MeasuredText& measuredText, const LineWidth& lineWidth,
- const TabStops& tabStops, bool useBoundsForWidth) {
+ const TabStops& tabStops) {
if (strategy == BreakStrategy::Greedy || textBuffer.hasChar(CHAR_TAB)) {
return breakLineGreedy(textBuffer, measuredText, lineWidth, tabStops,
- frequency != HyphenationFrequency::None, useBoundsForWidth);
+ frequency != HyphenationFrequency::None);
} else {
- return breakLineOptimal(textBuffer, measuredText, lineWidth, strategy, frequency, justified,
- useBoundsForWidth);
+ return breakLineOptimal(textBuffer, measuredText, lineWidth, strategy, frequency,
+ justified);
}
}
diff --git a/libs/minikin/LineBreakerUtil.h b/libs/minikin/LineBreakerUtil.h
index 6e572f1..5764c5e 100644
--- a/libs/minikin/LineBreakerUtil.h
+++ b/libs/minikin/LineBreakerUtil.h
@@ -55,15 +55,6 @@ inline bool isLineEndSpace(uint16_t c) {
|| c == 0x3000;
}
-inline Range trimTrailingLineEndSpaces(const U16StringPiece& textBuf, const Range& range) {
- for (uint32_t i = 0; i < range.getLength(); i++) {
- if (!isLineEndSpace(textBuf[range.getEnd() - i - 1])) {
- return Range(range.getStart(), range.getEnd() - i);
- }
- }
- return Range(range.getStart(), range.getStart());
-}
-
inline Locale getEffectiveLocale(uint32_t localeListId) {
const LocaleList& localeList = LocaleListCache::getById(localeListId);
return localeList.empty() ? Locale() : localeList[0];
diff --git a/libs/minikin/MeasuredText.cpp b/libs/minikin/MeasuredText.cpp
index 3ae19a0..ad9e622 100644
--- a/libs/minikin/MeasuredText.cpp
+++ b/libs/minikin/MeasuredText.cpp
@@ -17,40 +17,32 @@
#define LOG_TAG "Minikin"
#include "minikin/MeasuredText.h"
+#include "minikin/Layout.h"
+
#include "BidiUtils.h"
#include "LayoutSplitter.h"
#include "LayoutUtils.h"
#include "LineBreakerUtil.h"
-#include "minikin/Characters.h"
-#include "minikin/Layout.h"
namespace minikin {
// Helper class for composing character advances.
class AdvancesCompositor {
public:
- AdvancesCompositor(std::vector<float>* outAdvances, std::vector<uint8_t>* flags,
- LayoutPieces* outPieces)
- : mOutAdvances(outAdvances), mFlags(flags), mOutPieces(outPieces) {}
+ AdvancesCompositor(std::vector<float>* outAdvances, LayoutPieces* outPieces)
+ : mOutAdvances(outAdvances), mOutPieces(outPieces) {}
void setNextRange(const Range& range, bool dir) {
mRange = range;
mDir = dir;
}
- void operator()(const LayoutPiece& layoutPiece, const MinikinPaint& paint,
- const MinikinRect& bounds) {
+ void operator()(const LayoutPiece& layoutPiece, const MinikinPaint& paint) {
const std::vector<float>& advances = layoutPiece.advances();
std::copy(advances.begin(), advances.end(), mOutAdvances->begin() + mRange.getStart());
- if (bounds.mLeft < 0 || bounds.mRight > layoutPiece.advance()) {
- for (uint32_t i : mRange) {
- (*mFlags)[i] |= MeasuredText::MAY_OVERHANG_BIT;
- }
- }
-
if (mOutPieces != nullptr) {
- mOutPieces->insert(mRange, 0 /* no edit */, layoutPiece, mDir, paint, bounds);
+ mOutPieces->insert(mRange, 0 /* no edit */, layoutPiece, mDir, paint);
}
}
@@ -58,14 +50,12 @@ private:
Range mRange;
bool mDir;
std::vector<float>* mOutAdvances;
- std::vector<uint8_t>* mFlags;
LayoutPieces* mOutPieces;
};
void StyleRun::getMetrics(const U16StringPiece& textBuf, std::vector<float>* advances,
- std::vector<uint8_t>* flags, LayoutPieces* precomputed,
- bool boundsCalculation, LayoutPieces* outPieces) const {
- AdvancesCompositor compositor(advances, flags, outPieces);
+ LayoutPieces* precomputed, LayoutPieces* outPieces) const {
+ AdvancesCompositor compositor(advances, outPieces);
const Bidi bidiFlag = mIsRtl ? Bidi::FORCE_RTL : Bidi::FORCE_LTR;
const uint32_t paintId =
(precomputed == nullptr) ? LayoutPieces::kNoPaintId : precomputed->findPaintId(mPaint);
@@ -75,12 +65,11 @@ void StyleRun::getMetrics(const U16StringPiece& textBuf, std::vector<float>* adv
if (paintId == LayoutPieces::kNoPaintId) {
LayoutCache::getInstance().getOrCreate(
textBuf.substr(context), piece - context.getStart(), mPaint, info.isRtl,
- StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT, boundsCalculation,
- compositor);
+ StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT, compositor);
} else {
precomputed->getOrCreate(textBuf, piece, context, mPaint, info.isRtl,
StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT, paintId,
- boundsCalculation, compositor);
+ compositor);
}
}
}
@@ -91,7 +80,7 @@ class TotalAdvancesCompositor {
public:
TotalAdvancesCompositor() : mOut(0) {}
- void operator()(const LayoutPiece& layoutPiece, const MinikinPaint&, const MinikinRect&) {
+ void operator()(const LayoutPiece& layoutPiece, const MinikinPaint&) {
for (float w : layoutPiece.advances()) {
mOut += w;
}
@@ -111,7 +100,7 @@ float StyleRun::measureText(const U16StringPiece& textBuf) const {
for (const auto [context, piece] : LayoutSplitter(textBuf, info.range, info.isRtl)) {
layoutCache.getOrCreate(textBuf.substr(context), piece - context.getStart(), mPaint,
info.isRtl, StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT,
- false /* bounds calculation */, compositor);
+ compositor);
}
}
return compositor.getTotalAdvance();
@@ -128,11 +117,10 @@ public:
mDir = dir;
}
- void operator()(const LayoutPiece& layoutPiece, const MinikinPaint& paint,
- const MinikinRect& bounds) {
+ void operator()(const LayoutPiece& layoutPiece, const MinikinPaint& paint) {
mTotalAdvance += layoutPiece.advance();
if (mOutPieces != nullptr) {
- mOutPieces->insert(mRange, mEdit, layoutPiece, mDir, paint, bounds);
+ mOutPieces->insert(mRange, mEdit, layoutPiece, mDir, paint);
}
}
@@ -159,17 +147,16 @@ float StyleRun::measureHyphenPiece(const U16StringPiece& textBuf, const Range& r
piece.getEnd() == range.getEnd() ? endHyphen : EndHyphenEdit::NO_EDIT;
compositor.setNextContext(piece, packHyphenEdit(startEdit, endEdit), info.isRtl);
- LayoutCache::getInstance().getOrCreate(
- textBuf.substr(context), piece - context.getStart(), mPaint, info.isRtl,
- startEdit, endEdit, false /* bounds calculation */, compositor);
+ LayoutCache::getInstance().getOrCreate(textBuf.substr(context),
+ piece - context.getStart(), mPaint, info.isRtl,
+ startEdit, endEdit, compositor);
}
}
return compositor.advance();
}
void MeasuredText::measure(const U16StringPiece& textBuf, bool computeHyphenation,
- bool computeLayout, bool computeBounds, bool ignoreHyphenKerning,
- MeasuredText* hint) {
+ bool computeLayout, bool ignoreHyphenKerning, MeasuredText* hint) {
if (textBuf.size() == 0) {
return;
}
@@ -178,8 +165,7 @@ void MeasuredText::measure(const U16StringPiece& textBuf, bool computeHyphenatio
CharProcessor proc(textBuf);
for (const auto& run : runs) {
const Range& range = run->getRange();
- run->getMetrics(textBuf, &widths, &flags, hint ? &hint->layoutPieces : nullptr,
- computeBounds, piecesOut);
+ run->getMetrics(textBuf, &widths, hint ? &hint->layoutPieces : nullptr, piecesOut);
if (!computeHyphenation || !run->canBreak()) {
continue;
@@ -212,8 +198,7 @@ public:
void setOutOffset(uint32_t outOffset) { mOutOffset = outOffset; }
- void operator()(const LayoutPiece& layoutPiece, const MinikinPaint& /* paint */,
- const MinikinRect&) {
+ void operator()(const LayoutPiece& layoutPiece, const MinikinPaint& /* paint */) {
mOutLayout->appendLayout(layoutPiece, mOutOffset, mExtraAdvance);
}
@@ -227,7 +212,6 @@ void StyleRun::appendLayout(const U16StringPiece& textBuf, const Range& range,
const MinikinPaint& paint, uint32_t outOrigin,
StartHyphenEdit startHyphen, EndHyphenEdit endHyphen,
Layout* outLayout) const {
- bool boundsCalculation = false;
float wordSpacing = range.getLength() == 1 && isWordSpace(textBuf[range.getStart()])
? mPaint.wordSpacing
: 0;
@@ -246,11 +230,11 @@ void StyleRun::appendLayout(const U16StringPiece& textBuf, const Range& range,
if (canUsePrecomputedResult) {
pieces.getOrCreate(textBuf, piece, context, mPaint, info.isRtl, startEdit, endEdit,
- paintId, boundsCalculation, compositor);
+ paintId, compositor);
} else {
- LayoutCache::getInstance().getOrCreate(
- textBuf.substr(context), piece - context.getStart(), paint, info.isRtl,
- startEdit, endEdit, boundsCalculation, compositor);
+ LayoutCache::getInstance().getOrCreate(textBuf.substr(context),
+ piece - context.getStart(), paint,
+ info.isRtl, startEdit, endEdit, compositor);
}
}
}
@@ -261,9 +245,20 @@ class BoundsCompositor {
public:
BoundsCompositor() : mAdvance(0) {}
- void operator()(const LayoutPiece& layoutPiece, const MinikinPaint& /* paint */,
- const MinikinRect& bounds) {
- mBounds.join(bounds, mAdvance, 0);
+ void operator()(const LayoutPiece& layoutPiece, const MinikinPaint& paint) {
+ MinikinRect pieceBounds;
+ MinikinRect tmpRect;
+ for (uint32_t i = 0; i < layoutPiece.glyphCount(); ++i) {
+ const FakedFont& font = layoutPiece.fontAt(i);
+ const Point& point = layoutPiece.pointAt(i);
+
+ MinikinFont* minikinFont = font.typeface().get();
+ minikinFont->GetBounds(&tmpRect, layoutPiece.glyphIdAt(i), paint, font.fakery);
+ tmpRect.offset(point.x, point.y);
+ pieceBounds.join(tmpRect);
+ }
+ pieceBounds.offset(mAdvance, 0);
+ mBounds.join(pieceBounds);
mAdvance += layoutPiece.advance();
}
@@ -284,7 +279,7 @@ std::pair<float, MinikinRect> StyleRun::getBounds(const U16StringPiece& textBuf,
for (const auto[context, piece] : LayoutSplitter(textBuf, info.range, info.isRtl)) {
pieces.getOrCreate(textBuf, piece, context, mPaint, info.isRtl,
StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT, paintId,
- true /* bounds calculation */, compositor);
+ compositor);
}
}
return std::make_pair(compositor.advance(), compositor.bounds());
@@ -295,8 +290,7 @@ class ExtentCompositor {
public:
ExtentCompositor() {}
- void operator()(const LayoutPiece& layoutPiece, const MinikinPaint& /* paint */,
- const MinikinRect&) {
+ void operator()(const LayoutPiece& layoutPiece, const MinikinPaint& /* paint */) {
mExtent.extendBy(layoutPiece.extent());
}
@@ -315,42 +309,12 @@ MinikinExtent StyleRun::getExtent(const U16StringPiece& textBuf, const Range& ra
for (const auto[context, piece] : LayoutSplitter(textBuf, info.range, info.isRtl)) {
pieces.getOrCreate(textBuf, piece, context, mPaint, info.isRtl,
StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT, paintId,
- false /* bounds calculation */, compositor);
+ compositor);
}
}
return compositor.extent();
}
-class LineMetricsCompositor {
-public:
- LineMetricsCompositor() {}
-
- void operator()(const LayoutPiece& layoutPiece, const MinikinPaint& /* paint */,
- const MinikinRect& bounds) {
- mMetrics.append(layoutPiece.extent(), bounds, layoutPiece.advance());
- }
-
- const LineMetrics& metrics() const { return mMetrics; }
-
-private:
- LineMetrics mMetrics;
-};
-
-LineMetrics StyleRun::getLineMetrics(const U16StringPiece& textBuf, const Range& range,
- const LayoutPieces& pieces) const {
- LineMetricsCompositor compositor;
- Bidi bidiFlag = mIsRtl ? Bidi::FORCE_RTL : Bidi::FORCE_LTR;
- const uint32_t paintId = pieces.findPaintId(mPaint);
- for (const BidiText::RunInfo info : BidiText(textBuf, range, bidiFlag)) {
- for (const auto [context, piece] : LayoutSplitter(textBuf, info.range, info.isRtl)) {
- pieces.getOrCreate(textBuf, piece, context, mPaint, info.isRtl,
- StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT, paintId,
- true /* bounds calculation */, compositor);
- }
- }
- return compositor.metrics();
-}
-
Layout MeasuredText::buildLayout(const U16StringPiece& textBuf, const Range& range,
const Range& contextRange, const MinikinPaint& paint,
StartHyphenEdit startHyphen, EndHyphenEdit endHyphen) {
@@ -382,7 +346,8 @@ MinikinRect MeasuredText::getBounds(const U16StringPiece& textBuf, const Range&
}
auto[advance, bounds] =
run->getBounds(textBuf, Range::intersection(runRange, range), layoutPieces);
- rect.join(bounds, totalAdvance, 0);
+ bounds.offset(totalAdvance, 0);
+ rect.join(bounds);
totalAdvance += advance;
}
return rect;
@@ -395,23 +360,11 @@ MinikinExtent MeasuredText::getExtent(const U16StringPiece& textBuf, const Range
if (!Range::intersects(range, runRange)) {
continue;
}
- extent.extendBy(
- run->getExtent(textBuf, Range::intersection(runRange, range), layoutPieces));
+ MinikinExtent runExtent =
+ run->getExtent(textBuf, Range::intersection(runRange, range), layoutPieces);
+ extent.extendBy(runExtent);
}
return extent;
}
-LineMetrics MeasuredText::getLineMetrics(const U16StringPiece& textBuf, const Range& range) const {
- LineMetrics metrics;
- for (const auto& run : runs) {
- const Range& runRange = run->getRange();
- if (!Range::intersects(range, runRange)) {
- continue;
- }
- metrics.append(
- run->getLineMetrics(textBuf, Range::intersection(runRange, range), layoutPieces));
- }
- return metrics;
-}
-
} // namespace minikin
diff --git a/libs/minikin/Measurement.cpp b/libs/minikin/Measurement.cpp
index 7797faa..968ab6f 100644
--- a/libs/minikin/Measurement.cpp
+++ b/libs/minikin/Measurement.cpp
@@ -21,8 +21,8 @@
#include "BidiUtils.h"
#include "LayoutSplitter.h"
+#include "minikin/BoundsCache.h"
#include "minikin/GraphemeBreak.h"
-#include "minikin/LayoutCache.h"
namespace {
bool isAsciiOrBidiControlCharacter(uint16_t c) {
@@ -194,10 +194,11 @@ size_t getOffsetForAdvance(const float* advances, const uint16_t* buf, size_t st
struct BoundsComposer {
BoundsComposer() : mAdvance(0) {}
- void operator()(const LayoutPiece& layoutPiece, const MinikinPaint& /* paint */,
- const MinikinRect& bounds) {
- mBounds.join(bounds, mAdvance, 0);
- mAdvance += layoutPiece.advance();
+ void operator()(const MinikinRect& rect, float advance) {
+ MinikinRect tmp = rect;
+ tmp.offset(mAdvance, 0);
+ mBounds.join(tmp);
+ mAdvance += advance;
}
float mAdvance;
@@ -214,9 +215,9 @@ void getBounds(const U16StringPiece& str, const Range& range, Bidi bidiFlag,
(piece.getStart() == range.getStart()) ? startHyphen : StartHyphenEdit::NO_EDIT;
const EndHyphenEdit pieceEndHyphen =
(piece.getEnd() == range.getEnd()) ? endHyphen : EndHyphenEdit::NO_EDIT;
- LayoutCache::getInstance().getOrCreate(
- str.substr(context), piece - context.getStart(), paint, info.isRtl,
- pieceStartHyphen, pieceEndHyphen, true /* bounds calculation */, bc);
+ BoundsCache::getInstance().getOrCreate(str.substr(context), piece - context.getStart(),
+ paint, info.isRtl, pieceStartHyphen,
+ pieceEndHyphen, bc);
// Increment word spacing for spacer
if (piece.getLength() == 1 && isWordSpace(str[piece.getStart()])) {
bc.mAdvance += paint.wordSpacing;
@@ -229,7 +230,7 @@ void getBounds(const U16StringPiece& str, const Range& range, Bidi bidiFlag,
struct ExtentComposer {
ExtentComposer() {}
- void operator()(const LayoutPiece& layoutPiece, const MinikinPaint&, const MinikinRect&) {
+ void operator()(const LayoutPiece& layoutPiece, const MinikinPaint&) {
extent.extendBy(layoutPiece.extent());
}
@@ -241,10 +242,9 @@ MinikinExtent getFontExtent(const U16StringPiece& textBuf, const Range& range, B
ExtentComposer composer;
for (const BidiText::RunInfo info : BidiText(textBuf, range, bidiFlag)) {
for (const auto [context, piece] : LayoutSplitter(textBuf, info.range, info.isRtl)) {
- LayoutCache::getInstance().getOrCreate(textBuf.substr(context),
- piece - context.getStart(), paint, info.isRtl,
- StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT,
- false /* bounds calculation */, composer);
+ LayoutCache::getInstance().getOrCreate(
+ textBuf.substr(context), piece - context.getStart(), paint, info.isRtl,
+ StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT, composer);
}
}
return composer.extent;
diff --git a/libs/minikin/OptimalLineBreaker.cpp b/libs/minikin/OptimalLineBreaker.cpp
index adc7b66..b05a94d 100644
--- a/libs/minikin/OptimalLineBreaker.cpp
+++ b/libs/minikin/OptimalLineBreaker.cpp
@@ -19,6 +19,11 @@
#include <algorithm>
#include <limits>
+#include "minikin/Characters.h"
+#include "minikin/Layout.h"
+#include "minikin/Range.h"
+#include "minikin/U16StringPiece.h"
+
#include "HyphenatorMap.h"
#include "LayoutUtils.h"
#include "LineBreakerUtil.h"
@@ -26,10 +31,6 @@
#include "LocaleListCache.h"
#include "MinikinInternal.h"
#include "WordBreaker.h"
-#include "minikin/Characters.h"
-#include "minikin/Layout.h"
-#include "minikin/Range.h"
-#include "minikin/U16StringPiece.h"
namespace minikin {
@@ -275,7 +276,7 @@ public:
LineBreakResult computeBreaks(const OptimizeContext& context, const U16StringPiece& textBuf,
const MeasuredText& measuredText, const LineWidth& lineWidth,
- BreakStrategy strategy, bool justified, bool useBoundsForWidth);
+ BreakStrategy strategy, bool justified);
private:
// Data used to compute optimal line breaks
@@ -286,15 +287,14 @@ private:
};
LineBreakResult finishBreaksOptimal(const U16StringPiece& textBuf, const MeasuredText& measured,
const std::vector<OptimalBreaksData>& breaksData,
- const std::vector<Candidate>& candidates,
- bool useBoundsForWidth);
+ const std::vector<Candidate>& candidates);
};
// Follow "prev" links in candidates array, and copy to result arrays.
LineBreakResult LineBreakOptimizer::finishBreaksOptimal(
const U16StringPiece& textBuf, const MeasuredText& measured,
- const std::vector<OptimalBreaksData>& breaksData, const std::vector<Candidate>& candidates,
- bool useBoundsForWidth) {
+ const std::vector<OptimalBreaksData>& breaksData,
+ const std::vector<Candidate>& candidates) {
LineBreakResult result;
const uint32_t nCand = candidates.size();
uint32_t prevIndex;
@@ -305,28 +305,9 @@ LineBreakResult LineBreakOptimizer::finishBreaksOptimal(
result.breakPoints.push_back(cand.offset);
result.widths.push_back(cand.postBreak - prev.preBreak);
- if (useBoundsForWidth) {
- Range range = Range(prev.offset, cand.offset);
- Range actualRange = trimTrailingLineEndSpaces(textBuf, range);
- if (actualRange.isEmpty()) {
- MinikinExtent extent = measured.getExtent(textBuf, range);
- result.ascents.push_back(extent.ascent);
- result.descents.push_back(extent.descent);
- result.bounds.emplace_back(0, extent.ascent, cand.postBreak - prev.preBreak,
- extent.descent);
- } else {
- LineMetrics metrics = measured.getLineMetrics(textBuf, actualRange);
- result.ascents.push_back(metrics.extent.ascent);
- result.descents.push_back(metrics.extent.descent);
- result.bounds.emplace_back(metrics.bounds);
- }
- } else {
- MinikinExtent extent = measured.getExtent(textBuf, Range(prev.offset, cand.offset));
- result.ascents.push_back(extent.ascent);
- result.descents.push_back(extent.descent);
- result.bounds.emplace_back(0, extent.ascent, cand.postBreak - prev.preBreak,
- extent.descent);
- }
+ MinikinExtent extent = measured.getExtent(textBuf, Range(prev.offset, cand.offset));
+ result.ascents.push_back(extent.ascent);
+ result.descents.push_back(extent.descent);
const HyphenEdit edit =
packHyphenEdit(editForNextLine(prev.hyphenType), editForThisLine(cand.hyphenType));
@@ -340,8 +321,7 @@ LineBreakResult LineBreakOptimizer::computeBreaks(const OptimizeContext& context
const U16StringPiece& textBuf,
const MeasuredText& measured,
const LineWidth& lineWidth,
- BreakStrategy strategy, bool justified,
- bool useBoundsForWidth) {
+ BreakStrategy strategy, bool justified) {
const std::vector<Candidate>& candidates = context.candidates;
uint32_t active = 0;
const uint32_t nCand = candidates.size();
@@ -377,25 +357,7 @@ LineBreakResult LineBreakOptimizer::computeBreaks(const OptimizeContext& context
}
const float jScore = breaksData[j].score;
if (jScore + bestHope >= best) continue;
- float delta = candidates[j].preBreak - leftEdge;
-
- if (useBoundsForWidth) {
- // FIXME: Support bounds based line break for hyphenated break point.
- if (candidates[i].hyphenType == HyphenationType::DONT_BREAK &&
- candidates[j].hyphenType == HyphenationType::DONT_BREAK) {
- if (delta >= 0) {
- Range range = Range(candidates[j].offset, candidates[i].offset);
- Range actualRange = trimTrailingLineEndSpaces(textBuf, range);
- if (!actualRange.isEmpty() && measured.hasOverhang(range)) {
- float boundsDelta =
- width - measured.getBounds(textBuf, actualRange).width();
- if (boundsDelta < 0) {
- delta = boundsDelta;
- }
- }
- }
- }
- }
+ const float delta = candidates[j].preBreak - leftEdge;
// compute width score for line
@@ -437,23 +399,21 @@ LineBreakResult LineBreakOptimizer::computeBreaks(const OptimizeContext& context
bestPrev, // prev
breaksData[bestPrev].lineNumber + 1}); // lineNumber
}
- return finishBreaksOptimal(textBuf, measured, breaksData, candidates, useBoundsForWidth);
+ return finishBreaksOptimal(textBuf, measured, breaksData, candidates);
}
} // namespace
LineBreakResult breakLineOptimal(const U16StringPiece& textBuf, const MeasuredText& measured,
const LineWidth& lineWidth, BreakStrategy strategy,
- HyphenationFrequency frequency, bool justified,
- bool useBoundsForWidth) {
+ HyphenationFrequency frequency, bool justified) {
if (textBuf.size() == 0) {
return LineBreakResult();
}
const OptimizeContext context =
populateCandidates(textBuf, measured, lineWidth, frequency, justified);
LineBreakOptimizer optimizer;
- return optimizer.computeBreaks(context, textBuf, measured, lineWidth, strategy, justified,
- useBoundsForWidth);
+ return optimizer.computeBreaks(context, textBuf, measured, lineWidth, strategy, justified);
}
} // namespace minikin
diff --git a/libs/minikin/OptimalLineBreaker.h b/libs/minikin/OptimalLineBreaker.h
index da7798d..f13e2a8 100644
--- a/libs/minikin/OptimalLineBreaker.h
+++ b/libs/minikin/OptimalLineBreaker.h
@@ -25,8 +25,7 @@ namespace minikin {
LineBreakResult breakLineOptimal(const U16StringPiece& textBuf, const MeasuredText& measured,
const LineWidth& lineWidthLimits, BreakStrategy strategy,
- HyphenationFrequency frequency, bool justified,
- bool useBoundsForWidth);
+ HyphenationFrequency frequency, bool justified);
} // namespace minikin