summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSeigo Nonaka <nona@google.com>2018-03-08 13:12:33 -0800
committerSeigo Nonaka <nona@google.com>2018-03-08 13:15:04 -0800
commit0385197086b0f08a39e7f6c9cee6f178ecb2746f (patch)
treece912b44c5813f9ab9384d73c960cbb6f1989463
parent705f31eef365439e3fe6b3eb60df77d6af1dec70 (diff)
downloadminikin-0385197086b0f08a39e7f6c9cee6f178ecb2746f.tar.gz
Fix infinity loop due to negative width
Due to combination of large indents and small width, the resulting width constraints may be negative. The previous implementation handles negative width but new implementation doesn't. It is good to put this non-negative regulation to getAt() interface rather than supporting negative width case in line breaker since negative width doesn't make sense. Bug: 74053423 Test: minikin_tests Test: atest CtsTextTestCases:StaticLayoutTest#testNegativeWidth Change-Id: Ie608dcdd560b3f81b48538a5706ff48344e027aa
-rw-r--r--include/minikin/AndroidLineBreakerHelper.h4
-rw-r--r--include/minikin/LineBreaker.h4
-rw-r--r--tests/unittest/Android.bp1
-rw-r--r--tests/unittest/AndroidLineBreakerHelperTest.cpp58
4 files changed, 64 insertions, 3 deletions
diff --git a/include/minikin/AndroidLineBreakerHelper.h b/include/minikin/AndroidLineBreakerHelper.h
index a9b4914..462644d 100644
--- a/include/minikin/AndroidLineBreakerHelper.h
+++ b/include/minikin/AndroidLineBreakerHelper.h
@@ -17,6 +17,8 @@
#ifndef MINIKIN_ANDROID_LINE_BREAKER_HELPERS_H
#define MINIKIN_ANDROID_LINE_BREAKER_HELPERS_H
+#include <algorithm>
+
#include "minikin/LineBreaker.h"
namespace minikin {
@@ -37,7 +39,7 @@ public:
float getAt(size_t lineNo) const override {
const float width = ((ssize_t)lineNo < (ssize_t)mFirstLineCount) ? mFirstWidth : mRestWidth;
- return width - get(mIndents, lineNo);
+ return std::max(0.0f, width - get(mIndents, lineNo));
}
float getMin() const override {
diff --git a/include/minikin/LineBreaker.h b/include/minikin/LineBreaker.h
index 7d59c63..2974c20 100644
--- a/include/minikin/LineBreaker.h
+++ b/include/minikin/LineBreaker.h
@@ -78,10 +78,10 @@ class LineWidth {
public:
virtual ~LineWidth() {}
- // Called to find out the width for the line.
+ // Called to find out the width for the line. This must not return negative values.
virtual float getAt(size_t lineNo) const = 0;
- // Called to find out the minimum line width.
+ // Called to find out the minimum line width. This mut not return negative values.
virtual float getMin() const = 0;
// Called to find out the available left-side padding for the line.
diff --git a/tests/unittest/Android.bp b/tests/unittest/Android.bp
index ba593a5..fcaab69 100644
--- a/tests/unittest/Android.bp
+++ b/tests/unittest/Android.bp
@@ -39,6 +39,7 @@ cc_test {
],
srcs: [
+ "AndroidLineBreakerHelperTest.cpp",
"BidiUtilsTest.cpp",
"CmapCoverageTest.cpp",
"EmojiTest.cpp",
diff --git a/tests/unittest/AndroidLineBreakerHelperTest.cpp b/tests/unittest/AndroidLineBreakerHelperTest.cpp
new file mode 100644
index 0000000..ea977c0
--- /dev/null
+++ b/tests/unittest/AndroidLineBreakerHelperTest.cpp
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+#include "minikin/AndroidLineBreakerHelper.h"
+
+#include <gtest/gtest.h>
+
+namespace minikin {
+namespace android {
+
+TEST(AndroidLineWidth, negativeWidthTest) {
+ const int LINE_COUNT = 10;
+ const std::vector<float> EMPTY;
+ {
+ AndroidLineWidth lineWidth(-10 /* first width */, 1 /* first count */, 0 /* rest width */,
+ EMPTY, EMPTY, EMPTY, 0);
+
+ EXPECT_LE(0.0f, lineWidth.getMin());
+ for (int i = 0; i < LINE_COUNT; ++i) {
+ EXPECT_LE(0.0f, lineWidth.getAt(i));
+ }
+ }
+ {
+ AndroidLineWidth lineWidth(0 /* first width */, 0 /* first count */, -10 /* rest width */,
+ EMPTY, EMPTY, EMPTY, 0);
+
+ EXPECT_LE(0.0f, lineWidth.getMin());
+ for (int i = 0; i < LINE_COUNT; ++i) {
+ EXPECT_LE(0.0f, lineWidth.getAt(i));
+ }
+ }
+ {
+ std::vector<float> indents = {10};
+ AndroidLineWidth lineWidth(0 /* first width */, 0 /* first count */, 0 /* rest width */,
+ indents, EMPTY, EMPTY, 0);
+
+ EXPECT_LE(0.0f, lineWidth.getMin());
+ for (int i = 0; i < LINE_COUNT; ++i) {
+ EXPECT_LE(0.0f, lineWidth.getAt(i));
+ }
+ }
+}
+
+} // namespace android
+} // namespace minikin