summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorandroid-build-team Robot <android-build-team-robot@google.com>2021-01-13 23:57:55 +0000
committerandroid-build-team Robot <android-build-team-robot@google.com>2021-01-13 23:57:55 +0000
commitd6af8672e7d181fec8aa4a6c98d0d78f8ac41cce (patch)
treecc760592822d295652a6f09cc869fbcd02b0a04e
parentd26e5a84987f46b1c8f726b068dbce438b9073a3 (diff)
parentc3bd9a03ecb1a19393046c522f5b6c91d615f7c5 (diff)
downloadminikin-android11-mainline-networkstack-release.tar.gz
Snap for 7080740 from c3bd9a03ecb1a19393046c522f5b6c91d615f7c5 to mainline-networkstack-releaseandroid-mainline-11.0.0_r41android-mainline-11.0.0_r34android-mainline-11.0.0_r17android11-mainline-networkstack-release
Change-Id: I1cdf0ff40ebe101fbd25d4f45ff701d2fbe29c85
-rw-r--r--libs/minikin/LayoutUtils.cpp5
-rw-r--r--tests/unittest/LayoutSplitterTest.cpp35
2 files changed, 40 insertions, 0 deletions
diff --git a/libs/minikin/LayoutUtils.cpp b/libs/minikin/LayoutUtils.cpp
index 3c258cf..acf07e2 100644
--- a/libs/minikin/LayoutUtils.cpp
+++ b/libs/minikin/LayoutUtils.cpp
@@ -36,6 +36,11 @@ static bool isWordBreakAfter(uint16_t c) {
// spaces
return true;
}
+ // Break layout context before and after BiDi control character.
+ if ((0x2066 <= c && c <= 0x2069) || (0x202A <= c && c <= 0x202E) || c == 0x200E ||
+ c == 0x200F) {
+ return true;
+ }
// Note: kana is not included, as sophisticated fonts may kern kana
return false;
}
diff --git a/tests/unittest/LayoutSplitterTest.cpp b/tests/unittest/LayoutSplitterTest.cpp
index 4b75d9c..9b88de0 100644
--- a/tests/unittest/LayoutSplitterTest.cpp
+++ b/tests/unittest/LayoutSplitterTest.cpp
@@ -323,5 +323,40 @@ TEST(LayoutSplitterTest, RTL_CJK) {
}
}
+TEST(LayoutSplitterTest, BidiCtrl) {
+ struct TestCase {
+ std::string testStr;
+ std::vector<std::string> expects;
+ } testCases[] = {
+ {// Repeated Bidi sequence
+ "(a\u2066\u2069\u202A\u202E\u200E\u200Fb)",
+ {
+ "[(a)]\u2066\u2069\u202A\u202E\u200E\u200Fb",
+ "a[(\u2066)]\u2069\u202A\u202E\u200E\u200Fb",
+ "a\u2066[(\u2069)]\u202A\u202E\u200E\u200Fb",
+ "a\u2066\u2069[(\u202A)]\u202E\u200E\u200Fb",
+ "a\u2066\u2069\u202A[(\u202E)]\u200E\u200Fb",
+ "a\u2066\u2069\u202A\u202E[(\u200E)]\u200Fb",
+ "a\u2066\u2069\u202A\u202E\u200E[(\u200F)]b",
+ "a\u2066\u2069\u202A\u202E\u200E\u200F[(b)]",
+ }},
+ };
+
+ for (const auto& testCase : testCases) {
+ auto [text, range] = parseTestString(testCase.testStr);
+ uint32_t expectationIndex = 0;
+ for (auto [acContext, acPiece] : LayoutSplitter(text, range, false /* isRtl */)) {
+ ASSERT_NE(expectationIndex, testCase.expects.size());
+ const std::string expectString = testCase.expects[expectationIndex++];
+ auto [exContext, exPiece] = parseExpectString(expectString);
+ EXPECT_EQ(acContext, exContext)
+ << expectString << " vs " << buildDebugString(text, acContext, acPiece);
+ EXPECT_EQ(acPiece, exPiece)
+ << expectString << " vs " << buildDebugString(text, acContext, acPiece);
+ }
+ EXPECT_EQ(expectationIndex, testCase.expects.size()) << "Expectations Remains";
+ }
+}
+
} // namespace
} // namespace minikin