Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(171)

Side by Side Diff: ui/gfx/render_text_unittest.cc

Issue 924773002: Fix multiline behaviors for RTL text. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fix Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « ui/gfx/render_text_harfbuzz.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "ui/gfx/render_text.h" 5 #include "ui/gfx/render_text.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "base/format_macros.h" 9 #include "base/format_macros.h"
10 #include "base/i18n/break_iterator.h" 10 #include "base/i18n/break_iterator.h"
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
85 // Test utility for Multiline_Newline test case. Empty |expected_range| means 85 // Test utility for Multiline_Newline test case. Empty |expected_range| means
86 // the blank line which has no segments. Otherwise |segments| should contain 86 // the blank line which has no segments. Otherwise |segments| should contain
87 // exactly one line segment whose range equals to |expected_range|. 87 // exactly one line segment whose range equals to |expected_range|.
88 void VerifyLineSegments(const Range& expected_range, 88 void VerifyLineSegments(const Range& expected_range,
89 const std::vector<internal::LineSegment>& segments) { 89 const std::vector<internal::LineSegment>& segments) {
90 EXPECT_EQ(expected_range.is_empty() ? 0ul : 1ul, segments.size()); 90 EXPECT_EQ(expected_range.is_empty() ? 0ul : 1ul, segments.size());
91 if (!expected_range.is_empty()) 91 if (!expected_range.is_empty())
92 EXPECT_EQ(expected_range, segments[0].char_range); 92 EXPECT_EQ(expected_range, segments[0].char_range);
93 } 93 }
94 94
95 // The class which records the drawing operations so that the test case can
96 // verify where exactly the glyphs are drawn.
97 class TestSkiaTextRenderer : public internal::SkiaTextRenderer {
98 public:
99 struct TextLog {
100 TextLog() : glyph_count(0u) {}
101 PointF origin;
102 size_t glyph_count;
103 };
104
105 struct DecorationLog {
106 DecorationLog(int x, int y, int width, bool underline, bool strike,
107 bool diagonal_strike)
108 : x(x), y(y), width(width), underline(underline), strike(strike),
109 diagonal_strike(diagonal_strike) {}
110 int x;
111 int y;
112 int width;
113 bool underline;
114 bool strike;
115 bool diagonal_strike;
116 };
117
118 explicit TestSkiaTextRenderer(Canvas* canvas)
119 : internal::SkiaTextRenderer(canvas) {}
120 ~TestSkiaTextRenderer() override {}
121
122 void GetTextLogAndReset(std::vector<TextLog>* text_log) {
123 text_log_.swap(*text_log);
124 text_log_.clear();
125 }
126
127 void GetDecorationLogAndReset(std::vector<DecorationLog>* decoration_log) {
128 decoration_log_.swap(*decoration_log);
129 decoration_log_.clear();
130 }
131
132 private:
133 // internal::SkiaTextRenderer:
134 void DrawPosText(const SkPoint* pos,
135 const uint16* glyphs,
136 size_t glyph_count) override {
137 TextLog log_entry;
138 log_entry.glyph_count = glyph_count;
139 if (glyph_count > 0) {
140 log_entry.origin =
141 PointF(SkScalarToFloat(pos[0].x()), SkScalarToFloat(pos[0].y()));
142 for (size_t i = 1U; i < glyph_count; ++i) {
143 log_entry.origin.SetToMin(
144 PointF(SkScalarToFloat(pos[i].x()), SkScalarToFloat(pos[i].y())));
145 }
146 }
147 text_log_.push_back(log_entry);
148 internal::SkiaTextRenderer::DrawPosText(pos, glyphs, glyph_count);
149 }
150
151 void DrawDecorations(int x, int y, int width, bool underline, bool strike,
152 bool diagonal_strike) override {
153 decoration_log_.push_back(
154 DecorationLog(x, y, width, underline, strike, diagonal_strike));
155 internal::SkiaTextRenderer::DrawDecorations(
156 x, y, width, underline, strike, diagonal_strike);
157 }
158
159 std::vector<TextLog> text_log_;
160 std::vector<DecorationLog> decoration_log_;
161
162 DISALLOW_COPY_AND_ASSIGN(TestSkiaTextRenderer);
163 };
164
95 } // namespace 165 } // namespace
96 166
97 class RenderTextTest : public testing::Test { 167 class RenderTextTest : public testing::Test {
98 }; 168 };
99 169
100 TEST_F(RenderTextTest, DefaultStyle) { 170 TEST_F(RenderTextTest, DefaultStyle) {
101 // Check the default styles applied to new instances and adjusted text. 171 // Check the default styles applied to new instances and adjusted text.
102 scoped_ptr<RenderText> render_text(RenderText::CreateInstance()); 172 scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
103 EXPECT_TRUE(render_text->text().empty()); 173 EXPECT_TRUE(render_text->text().empty());
104 const wchar_t* const cases[] = { kWeak, kLtr, L"Hello", kRtl, L"", L"" }; 174 const wchar_t* const cases[] = { kWeak, kLtr, L"Hello", kRtl, L"", L"" };
(...skipping 1807 matching lines...) Expand 10 before | Expand all | Expand 10 after
1912 EXPECT_GT(render_text.lines_.size(), 1U); 1982 EXPECT_GT(render_text.lines_.size(), 1U);
1913 } 1983 }
1914 } 1984 }
1915 1985
1916 // Ensure strings wrap onto multiple lines for a normal available width. 1986 // Ensure strings wrap onto multiple lines for a normal available width.
1917 TEST_F(RenderTextTest, Multiline_NormalWidth) { 1987 TEST_F(RenderTextTest, Multiline_NormalWidth) {
1918 const struct { 1988 const struct {
1919 const wchar_t* const text; 1989 const wchar_t* const text;
1920 const Range first_line_char_range; 1990 const Range first_line_char_range;
1921 const Range second_line_char_range; 1991 const Range second_line_char_range;
1992 bool is_ltr;
1922 } kTestStrings[] = { 1993 } kTestStrings[] = {
1923 { L"abc defg hijkl", Range(0, 9), Range(9, 14) }, 1994 { L"abc defg hijkl", Range(0, 9), Range(9, 14), true },
1924 { L"qwertyzxcvbn", Range(0, 10), Range(10, 12) }, 1995 { L"qwertyzxcvbn", Range(0, 10), Range(10, 12), true },
1996 { L"\x0627\x0644\x0644\x063A\x0629 "
1997 L"\x0627\x0644\x0639\x0631\x0628\x064A\x0629",
1998 Range(0, 6), Range(6, 13), false },
1925 { L"\x062A\x0641\x0627\x062D\x05EA\x05E4\x05D5\x05D6\x05D9" 1999 { L"\x062A\x0641\x0627\x062D\x05EA\x05E4\x05D5\x05D6\x05D9"
1926 L"\x05DA\x05DB\x05DD", Range(4, 12), Range(0, 4) } 2000 L"\x05DA\x05DB\x05DD", Range(0, 4), Range(4, 12), false }
1927 }; 2001 };
1928 2002
1929 RenderTextHarfBuzz render_text; 2003 RenderTextHarfBuzz render_text;
1930 // Specify the fixed width for characters to suppress the possible variations 2004 // Specify the fixed width for characters to suppress the possible variations
1931 // of linebreak results. 2005 // of linebreak results.
1932 render_text.set_glyph_width_for_test(5); 2006 render_text.set_glyph_width_for_test(5);
1933 render_text.SetDisplayRect(Rect(50, 1000)); 2007 render_text.SetDisplayRect(Rect(50, 1000));
1934 render_text.SetMultiline(true); 2008 render_text.SetMultiline(true);
2009 render_text.SetHorizontalAlignment(ALIGN_TO_HEAD);
2010
1935 Canvas canvas; 2011 Canvas canvas;
2012 TestSkiaTextRenderer renderer(&canvas);
1936 2013
1937 for (size_t i = 0; i < arraysize(kTestStrings); ++i) { 2014 for (size_t i = 0; i < arraysize(kTestStrings); ++i) {
1938 SCOPED_TRACE(base::StringPrintf("kTestStrings[%" PRIuS "]", i)); 2015 SCOPED_TRACE(base::StringPrintf("kTestStrings[%" PRIuS "]", i));
1939 render_text.SetText(WideToUTF16(kTestStrings[i].text)); 2016 render_text.SetText(WideToUTF16(kTestStrings[i].text));
1940 render_text.Draw(&canvas); 2017 render_text.EnsureLayout();
2018 render_text.DrawVisualTextInternal(&renderer);
2019
1941 ASSERT_EQ(2U, render_text.lines_.size()); 2020 ASSERT_EQ(2U, render_text.lines_.size());
1942 ASSERT_EQ(1U, render_text.lines_[0].segments.size()); 2021 ASSERT_EQ(1U, render_text.lines_[0].segments.size());
1943 EXPECT_EQ(kTestStrings[i].first_line_char_range, 2022 EXPECT_EQ(kTestStrings[i].first_line_char_range,
1944 render_text.lines_[0].segments[0].char_range); 2023 render_text.lines_[0].segments[0].char_range);
1945 ASSERT_EQ(1U, render_text.lines_[1].segments.size()); 2024 ASSERT_EQ(1U, render_text.lines_[1].segments.size());
1946 EXPECT_EQ(kTestStrings[i].second_line_char_range, 2025 EXPECT_EQ(kTestStrings[i].second_line_char_range,
1947 render_text.lines_[1].segments[0].char_range); 2026 render_text.lines_[1].segments[0].char_range);
2027
2028 std::vector<TestSkiaTextRenderer::TextLog> text_log;
2029 renderer.GetTextLogAndReset(&text_log);
2030 ASSERT_EQ(2U, text_log.size());
2031 // NOTE: this expectation compares the character length and glyph counts,
2032 // which isn't always equal. This is okay only because all the test
2033 // strings are simple (like, no compound characters nor UTF16-surrogate
2034 // pairs). Be careful in case more complicated test strings are added.
2035 EXPECT_EQ(kTestStrings[i].first_line_char_range.length(),
2036 text_log[0].glyph_count);
2037 EXPECT_EQ(kTestStrings[i].second_line_char_range.length(),
2038 text_log[1].glyph_count);
2039 EXPECT_LT(text_log[0].origin.y(), text_log[1].origin.y());
2040 if (kTestStrings[i].is_ltr) {
2041 EXPECT_EQ(0, text_log[0].origin.x());
2042 EXPECT_EQ(0, text_log[1].origin.x());
2043 } else {
2044 EXPECT_LT(0, text_log[0].origin.x());
2045 EXPECT_LT(0, text_log[1].origin.x());
2046 }
1948 } 2047 }
1949 } 2048 }
1950 2049
1951 // Ensure strings don't wrap onto multiple lines for a sufficient available 2050 // Ensure strings don't wrap onto multiple lines for a sufficient available
1952 // width. 2051 // width.
1953 TEST_F(RenderTextTest, Multiline_SufficientWidth) { 2052 TEST_F(RenderTextTest, Multiline_SufficientWidth) {
1954 const wchar_t* kTestStrings[] = { L"", L" ", L".", L" . ", L"abc", L"a b c", 2053 const wchar_t* kTestStrings[] = { L"", L" ", L".", L" . ", L"abc", L"a b c",
1955 L"\x62E\x628\x632", L"\x62E \x628 \x632" }; 2054 L"\x62E\x628\x632", L"\x62E \x628 \x632" };
1956 2055
1957 RenderTextHarfBuzz render_text; 2056 RenderTextHarfBuzz render_text;
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
2032 2131
2033 for (size_t i = 0; i < arraysize(kTestStrings); ++i) { 2132 for (size_t i = 0; i < arraysize(kTestStrings); ++i) {
2034 SCOPED_TRACE(base::StringPrintf("kTestStrings[%" PRIuS "]", i)); 2133 SCOPED_TRACE(base::StringPrintf("kTestStrings[%" PRIuS "]", i));
2035 render_text.SetText(WideToUTF16(kTestStrings[i])); 2134 render_text.SetText(WideToUTF16(kTestStrings[i]));
2036 render_text.Draw(&canvas); 2135 render_text.Draw(&canvas);
2037 2136
2038 EXPECT_EQ(1U, render_text.lines_.size()); 2137 EXPECT_EQ(1U, render_text.lines_.size());
2039 } 2138 }
2040 } 2139 }
2041 2140
2141 // Make sure the horizontal positions of runs in a line (left-to-right for
2142 // LTR languages and right-to-left for RTL languages).
2143 TEST_F(RenderTextTest, HarfBuzz_HorizontalPositions) {
2144 const struct {
2145 const wchar_t* const text;
2146 const Range first_run_char_range;
2147 const Range second_run_char_range;
2148 bool is_rtl;
2149 } kTestStrings[] = {
2150 { L"abc\x3042\x3044\x3046\x3048\x304A", Range(0, 3), Range(3, 8), false },
2151 { L"\x062A\x0641\x0627\x062D"
2152 L"\x05EA\x05E4\x05D5\x05D6\x05D9\x05DA\x05DB\x05DD",
2153 Range(0, 4), Range(4, 12), true },
2154 };
2155
2156 RenderTextHarfBuzz render_text;
2157 Canvas canvas;
2158 TestSkiaTextRenderer renderer(&canvas);
2159
2160 for (size_t i = 0; i < arraysize(kTestStrings); ++i) {
2161 SCOPED_TRACE(base::StringPrintf("kTestStrings[%" PRIuS "]", i));
2162 render_text.SetText(WideToUTF16(kTestStrings[i].text));
2163
2164 render_text.EnsureLayout();
2165 const internal::TextRunList* run_list = render_text.GetRunList();
2166 ASSERT_EQ(2U, run_list->runs().size());
2167 EXPECT_EQ(kTestStrings[i].first_run_char_range, run_list->runs()[0]->range);
2168 EXPECT_EQ(kTestStrings[i].second_run_char_range,
2169 run_list->runs()[1]->range);
2170 // If it's RTL, the visual order is reversed.
2171 if (kTestStrings[i].is_rtl) {
2172 EXPECT_EQ(1U, run_list->logical_to_visual(0));
2173 EXPECT_EQ(0U, run_list->logical_to_visual(1));
2174 } else {
2175 EXPECT_EQ(0U, run_list->logical_to_visual(0));
2176 EXPECT_EQ(1U, run_list->logical_to_visual(1));
2177 }
2178
2179 render_text.DrawVisualTextInternal(&renderer);
2180
2181 std::vector<TestSkiaTextRenderer::TextLog> text_log;
2182 renderer.GetTextLogAndReset(&text_log);
2183
2184 EXPECT_EQ(2U, text_log.size());
2185
2186 // Verifies the DrawText happens in the visual order and left-to-right.
2187 // If the text is RTL, the logically first run should be drawn at last.
2188 EXPECT_EQ(run_list->runs()[run_list->logical_to_visual(0)]->glyph_count,
2189 text_log[0].glyph_count);
2190 EXPECT_EQ(run_list->runs()[run_list->logical_to_visual(1)]->glyph_count,
2191 text_log[1].glyph_count);
2192 EXPECT_LT(text_log[0].origin.x(), text_log[1].origin.x());
2193 }
2194 }
2195
2042 // Test TextRunHarfBuzz's cluster finding logic. 2196 // Test TextRunHarfBuzz's cluster finding logic.
2043 TEST_F(RenderTextTest, HarfBuzz_Clusters) { 2197 TEST_F(RenderTextTest, HarfBuzz_Clusters) {
2044 struct { 2198 struct {
2045 uint32 glyph_to_char[4]; 2199 uint32 glyph_to_char[4];
2046 Range chars[4]; 2200 Range chars[4];
2047 Range glyphs[4]; 2201 Range glyphs[4];
2048 bool is_rtl; 2202 bool is_rtl;
2049 } cases[] = { 2203 } cases[] = {
2050 { // From string "A B C D" to glyphs "a b c d". 2204 { // From string "A B C D" to glyphs "a b c d".
2051 { 0, 1, 2, 3 }, 2205 { 0, 1, 2, 3 },
(...skipping 356 matching lines...) Expand 10 before | Expand all | Expand 10 after
2408 base::StringToLowerASCII(fonts[0].GetActualFontNameForTesting())); 2562 base::StringToLowerASCII(fonts[0].GetActualFontNameForTesting()));
2409 2563
2410 scoped_ptr<RenderText> render_text(RenderText::CreateInstance()); 2564 scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
2411 render_text->SetDisplayRect(Rect(0, 0, 25, 25)); 2565 render_text->SetDisplayRect(Rect(0, 0, 25, 25));
2412 render_text->SetFontList(font_list); 2566 render_text->SetFontList(font_list);
2413 EXPECT_GT(render_text->GetBaseline(), font_list.GetBaseline()); 2567 EXPECT_GT(render_text->GetBaseline(), font_list.GetBaseline());
2414 } 2568 }
2415 #endif 2569 #endif
2416 2570
2417 } // namespace gfx 2571 } // namespace gfx
OLDNEW
« no previous file with comments | « ui/gfx/render_text_harfbuzz.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698