Implement LineBreaker callback and fix indent repeating.
The last indent should be repeated, so we need to pass an int array
instead of null even if the indent offset is out of array length.
Bug: 65024629
Test: bit CtsTextTestCases:android.text.cts.StaticLayoutTest
Test: bit CtsTextTestCases:android.text.cts.DynamicLayoutTest
Test: bit CtsWidgetTestCases:android.widget.cts.TextViewTest
Bug: 65024629
Change-Id: Ic1274d797db27ae1921135a27bab55e475369710
diff --git a/core/jni/android_text_StaticLayout.cpp b/core/jni/android_text_StaticLayout.cpp
index 15ab8f7..7442fa2 100644
--- a/core/jni/android_text_StaticLayout.cpp
+++ b/core/jni/android_text_StaticLayout.cpp
@@ -52,17 +52,46 @@
static jclass gLineBreaks_class;
static JLineBreaksID gLineBreaks_fieldID;
+class JNILineBreakerLineWidth : public minikin::LineBreaker::LineWidthDelegate {
+ public:
+ JNILineBreakerLineWidth(float firstWidth, int32_t firstLineCount, float restWidth,
+ std::vector<float>&& indents, int32_t indentsOffset)
+ : mFirstWidth(firstWidth), mFirstLineCount(firstLineCount), mRestWidth(restWidth),
+ mIndents(std::move(indents)), mIndentsOffset(indentsOffset) {}
+
+ float getLineWidth(size_t lineNo) override {
+ const float width = ((ssize_t)lineNo < (ssize_t)mFirstLineCount)
+ ? mFirstWidth : mRestWidth;
+ if (mIndents.empty()) {
+ return width;
+ }
+
+ const size_t indentIndex = lineNo + mIndentsOffset;
+ if (indentIndex < mIndents.size()) {
+ return width - mIndents[indentIndex];
+ } else {
+ return width - mIndents.back();
+ }
+ }
+
+ private:
+ const float mFirstWidth;
+ const int32_t mFirstLineCount;
+ const float mRestWidth;
+ const std::vector<float> mIndents;
+ const int32_t mIndentsOffset;
+};
+
// set text and set a number of parameters for creating a layout (width, tabstops, strategy,
// hyphenFrequency)
static void nSetupParagraph(JNIEnv* env, jclass, jlong nativePtr, jcharArray text, jint length,
jfloat firstWidth, jint firstWidthLineLimit, jfloat restWidth,
jintArray variableTabStops, jint defaultTabStop, jint strategy, jint hyphenFrequency,
- jboolean isJustified, jintArray indents, jint insetsOffset) {
+ jboolean isJustified, jintArray indents, jint indentsOffset) {
minikin::LineBreaker* b = reinterpret_cast<minikin::LineBreaker*>(nativePtr);
b->resize(length);
env->GetCharArrayRegion(text, 0, length, b->buffer());
b->setText();
- b->setLineWidths(firstWidth, firstWidthLineLimit, restWidth);
if (variableTabStops == nullptr) {
b->setTabStops(nullptr, 0, defaultTabStop);
} else {
@@ -73,17 +102,14 @@
b->setHyphenationFrequency(static_cast<minikin::HyphenationFrequency>(hyphenFrequency));
b->setJustified(isJustified);
+ std::vector<float> indentVec;
// TODO: copy indents only once when LineBreaker is started to be used.
if (indents != nullptr) {
- // If indents is not null, it is guaranteed that lineOffset is less than the size of array.
ScopedIntArrayRO indentArr(env, indents);
- std::vector<float> indentVec(
- indentArr.get() + insetsOffset, indentArr.get() + indentArr.size());
- b->setIndents(indentVec);
- } else {
- b->setIndents(std::vector<float>());
+ indentVec.assign(indentArr.get(), indentArr.get() + indentArr.size());
}
-
+ b->setLineWidthDelegate(std::make_unique<JNILineBreakerLineWidth>(
+ firstWidth, firstWidthLineLimit, restWidth, std::move(indentVec), indentsOffset));
}
static void recycleCopy(JNIEnv* env, jobject recycle, jintArray recycleBreaks,