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

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 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
83 // Test utility for Multiline_Newline test case. Empty |expected_range| means 83 // Test utility for Multiline_Newline test case. Empty |expected_range| means
84 // the blank line which has no segments. Otherwise |segments| should contain 84 // the blank line which has no segments. Otherwise |segments| should contain
85 // exactly one line segment whose range equals to |expected_range|. 85 // exactly one line segment whose range equals to |expected_range|.
86 void VerifyLineSegments(const Range& expected_range, 86 void VerifyLineSegments(const Range& expected_range,
87 const std::vector<internal::LineSegment>& segments) { 87 const std::vector<internal::LineSegment>& segments) {
88 EXPECT_EQ(expected_range.is_empty() ? 0ul : 1ul, segments.size()); 88 EXPECT_EQ(expected_range.is_empty() ? 0ul : 1ul, segments.size());
89 if (!expected_range.is_empty()) 89 if (!expected_range.is_empty())
90 EXPECT_EQ(expected_range, segments[0].char_range); 90 EXPECT_EQ(expected_range, segments[0].char_range);
91 } 91 }
92 92
93 // The class which records the drawing operations so that the test case can
94 // verify where exactly the glyphs are drawn.
95 class TestSkiaTextRenderer : public internal::SkiaTextRenderer {
96 public:
97 struct TextLog {
98 TextLog() : glyph_count(0u) {}
99 PointF origin;
100 size_t glyph_count;
101 };
102
103 struct DecorationLog {
104 DecorationLog(int x, int y, int width, bool underline, bool strike,
105 bool diagonal_strike)
106 : x(x), y(y), width(width), underline(underline), strike(strike),
107 diagonal_strike(diagonal_strike) {}
108 int x;
109 int y;
110 int width;
111 bool underline;
112 bool strike;
113 bool diagonal_strike;
114 };
115
116 explicit TestSkiaTextRenderer(Canvas* canvas)
117 : internal::SkiaTextRenderer(canvas) {}
118 ~TestSkiaTextRenderer() override {}
119
120 void GetTextLogAndReset(std::vector<TextLog>* text_log) {
121 text_log_.swap(*text_log);
122 text_log_.clear();
123 }
124
125 void GetDecorationLogAndReset(std::vector<DecorationLog>* decoration_log) {
126 decoration_log_.swap(*decoration_log);
127 decoration_log_.clear();
128 }
129
130 private:
131 // internal::SkiaTextRenderer:
132 void DrawPosText(const SkPoint* pos,
133 const uint16* glyphs,
134 size_t glyph_count) override {
135 TextLog log_entry;
136 log_entry.glyph_count = glyph_count;
137 if (glyph_count > 0) {
138 log_entry.origin =
139 PointF(SkScalarToFloat(pos[0].x()), SkScalarToFloat(pos[0].y()));
140 for (size_t i = 1U; i < glyph_count; ++i) {
141 log_entry.origin.SetToMin(
142 PointF(SkScalarToFloat(pos[i].x()), SkScalarToFloat(pos[i].y())));
143 }
144 }
145 text_log_.push_back(log_entry);
146 internal::SkiaTextRenderer::DrawPosText(pos, glyphs, glyph_count);
147 }
148
149 void DrawDecorations(int x, int y, int width, bool underline, bool strike,
150 bool diagonal_strike) override {
151 decoration_log_.push_back(
152 DecorationLog(x, y, width, underline, strike, diagonal_strike));
153 internal::SkiaTextRenderer::DrawDecorations(
154 x, y, width, underline, strike, diagonal_strike);
155 }
156
157 std::vector<TextLog> text_log_;
158 std::vector<DecorationLog> decoration_log_;
159
160 DISALLOW_COPY_AND_ASSIGN(TestSkiaTextRenderer);
161 };
162
93 } // namespace 163 } // namespace
94 164
95 class RenderTextTest : public testing::Test { 165 class RenderTextTest : public testing::Test {
96 }; 166 };
97 167
98 TEST_F(RenderTextTest, DefaultStyle) { 168 TEST_F(RenderTextTest, DefaultStyle) {
99 // Check the default styles applied to new instances and adjusted text. 169 // Check the default styles applied to new instances and adjusted text.
100 scoped_ptr<RenderText> render_text(RenderText::CreateInstance()); 170 scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
101 EXPECT_TRUE(render_text->text().empty()); 171 EXPECT_TRUE(render_text->text().empty());
102 const wchar_t* const cases[] = { kWeak, kLtr, L"Hello", kRtl, L"", L"" }; 172 const wchar_t* const cases[] = { kWeak, kLtr, L"Hello", kRtl, L"", L"" };
(...skipping 1807 matching lines...) Expand 10 before | Expand all | Expand 10 after
1910 EXPECT_GT(render_text.lines_.size(), 1U); 1980 EXPECT_GT(render_text.lines_.size(), 1U);
1911 } 1981 }
1912 } 1982 }
1913 1983
1914 // Ensure strings wrap onto multiple lines for a normal available width. 1984 // Ensure strings wrap onto multiple lines for a normal available width.
1915 TEST_F(RenderTextTest, Multiline_NormalWidth) { 1985 TEST_F(RenderTextTest, Multiline_NormalWidth) {
1916 const struct { 1986 const struct {
1917 const wchar_t* const text; 1987 const wchar_t* const text;
1918 const Range first_line_char_range; 1988 const Range first_line_char_range;
1919 const Range second_line_char_range; 1989 const Range second_line_char_range;
1990 bool is_ltr;
1920 } kTestStrings[] = { 1991 } kTestStrings[] = {
1921 { L"abc defg hijkl", Range(0, 9), Range(9, 14) }, 1992 { L"abc defg hijkl", Range(0, 9), Range(9, 14), true },
1922 { L"qwertyzxcvbn", Range(0, 10), Range(10, 12) }, 1993 { L"qwertyzxcvbn", Range(0, 10), Range(10, 12), true },
1994 { L"\x0627\x0644\x0644\x063A\x0629 "
1995 L"\x0627\x0644\x0639\x0631\x0628\x064A\x0629",
1996 Range(0, 6), Range(6, 13), false },
1923 { L"\x062A\x0641\x0627\x062D\x05EA\x05E4\x05D5\x05D6\x05D9" 1997 { L"\x062A\x0641\x0627\x062D\x05EA\x05E4\x05D5\x05D6\x05D9"
1924 L"\x05DA\x05DB\x05DD", Range(4, 12), Range(0, 4) } 1998 L"\x05DA\x05DB\x05DD", Range(0, 4), Range(4, 12), false }
1925 }; 1999 };
1926 2000
1927 RenderTextHarfBuzz render_text; 2001 RenderTextHarfBuzz render_text;
1928 // Specify the fixed width for characters to suppress the possible variations 2002 // Specify the fixed width for characters to suppress the possible variations
1929 // of linebreak results. 2003 // of linebreak results.
1930 render_text.set_glyph_width_for_test(5); 2004 render_text.set_glyph_width_for_test(5);
1931 render_text.SetDisplayRect(Rect(50, 1000)); 2005 render_text.SetDisplayRect(Rect(50, 1000));
1932 render_text.SetMultiline(true); 2006 render_text.SetMultiline(true);
2007 render_text.SetHorizontalAlignment(ALIGN_TO_HEAD);
2008
1933 Canvas canvas; 2009 Canvas canvas;
2010 TestSkiaTextRenderer renderer(&canvas);
1934 2011
1935 for (size_t i = 0; i < arraysize(kTestStrings); ++i) { 2012 for (size_t i = 0; i < arraysize(kTestStrings); ++i) {
1936 SCOPED_TRACE(base::StringPrintf("kTestStrings[%" PRIuS "]", i)); 2013 SCOPED_TRACE(base::StringPrintf("kTestStrings[%" PRIuS "]", i));
1937 render_text.SetText(WideToUTF16(kTestStrings[i].text)); 2014 render_text.SetText(WideToUTF16(kTestStrings[i].text));
1938 render_text.Draw(&canvas); 2015 render_text.EnsureLayout();
2016 render_text.DrawVisualTextInternal(&renderer);
2017
1939 ASSERT_EQ(2U, render_text.lines_.size()); 2018 ASSERT_EQ(2U, render_text.lines_.size());
1940 ASSERT_EQ(1U, render_text.lines_[0].segments.size()); 2019 ASSERT_EQ(1U, render_text.lines_[0].segments.size());
1941 EXPECT_EQ(kTestStrings[i].first_line_char_range, 2020 EXPECT_EQ(kTestStrings[i].first_line_char_range,
1942 render_text.lines_[0].segments[0].char_range); 2021 render_text.lines_[0].segments[0].char_range);
1943 ASSERT_EQ(1U, render_text.lines_[1].segments.size()); 2022 ASSERT_EQ(1U, render_text.lines_[1].segments.size());
1944 EXPECT_EQ(kTestStrings[i].second_line_char_range, 2023 EXPECT_EQ(kTestStrings[i].second_line_char_range,
1945 render_text.lines_[1].segments[0].char_range); 2024 render_text.lines_[1].segments[0].char_range);
2025
2026 std::vector<TestSkiaTextRenderer::TextLog> text_log;
2027 renderer.GetTextLogAndReset(&text_log);
2028 ASSERT_EQ(2U, text_log.size());
2029 // NOTE: this expectation compares the character length and glyph counts,
2030 // which isn't always equal. This is okay only because all the test
2031 // strings are simple (like, no compound characters nor UTF16-surrogate
2032 // pairs). Be careful in case more complicated test strings are added.
2033 EXPECT_EQ(kTestStrings[i].first_line_char_range.length(),
2034 text_log[0].glyph_count);
2035 EXPECT_EQ(kTestStrings[i].second_line_char_range.length(),
2036 text_log[1].glyph_count);
2037 EXPECT_LT(text_log[0].origin.y(), text_log[1].origin.y());
2038 if (kTestStrings[i].is_ltr) {
2039 EXPECT_EQ(0, text_log[0].origin.x());
2040 EXPECT_EQ(0, text_log[1].origin.x());
2041 } else {
2042 EXPECT_LT(0, text_log[0].origin.x());
2043 EXPECT_LT(0, text_log[1].origin.x());
2044 }
1946 } 2045 }
1947 } 2046 }
1948 2047
1949 // Ensure strings don't wrap onto multiple lines for a sufficient available 2048 // Ensure strings don't wrap onto multiple lines for a sufficient available
1950 // width. 2049 // width.
1951 TEST_F(RenderTextTest, Multiline_SufficientWidth) { 2050 TEST_F(RenderTextTest, Multiline_SufficientWidth) {
1952 const wchar_t* kTestStrings[] = { L"", L" ", L".", L" . ", L"abc", L"a b c", 2051 const wchar_t* kTestStrings[] = { L"", L" ", L".", L" . ", L"abc", L"a b c",
1953 L"\x62E\x628\x632", L"\x62E \x628 \x632" }; 2052 L"\x62E\x628\x632", L"\x62E \x628 \x632" };
1954 2053
1955 RenderTextHarfBuzz render_text; 2054 RenderTextHarfBuzz render_text;
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
2030 2129
2031 for (size_t i = 0; i < arraysize(kTestStrings); ++i) { 2130 for (size_t i = 0; i < arraysize(kTestStrings); ++i) {
2032 SCOPED_TRACE(base::StringPrintf("kTestStrings[%" PRIuS "]", i)); 2131 SCOPED_TRACE(base::StringPrintf("kTestStrings[%" PRIuS "]", i));
2033 render_text.SetText(WideToUTF16(kTestStrings[i])); 2132 render_text.SetText(WideToUTF16(kTestStrings[i]));
2034 render_text.Draw(&canvas); 2133 render_text.Draw(&canvas);
2035 2134
2036 EXPECT_EQ(1U, render_text.lines_.size()); 2135 EXPECT_EQ(1U, render_text.lines_.size());
2037 } 2136 }
2038 } 2137 }
2039 2138
2139 // Make sure two RTL runs are drawn in RTL order (logically first run appears
msw 2015/02/18 20:08:52 nit: update this comment as the test now covers LT
Jun Mukai 2015/02/18 23:53:37 Done.
2140 // right).
2141 TEST_F(RenderTextTest, HarfBuzz_HorizontalPositions) {
2142 const struct {
2143 const wchar_t* const text;
2144 const Range first_run_char_range;
2145 const Range second_run_char_range;
2146 bool is_rtl;
2147 } kTestStrings[] = {
2148 { L"abc\x3042\x3044\x3046\x3048\x304A", Range(0, 3), Range(3, 8), false },
2149 { L"\x062A\x0641\x0627\x062D"
2150 L"\x05EA\x05E4\x05D5\x05D6\x05D9\x05DA\x05DB\x05DD",
2151 Range(0, 4), Range(4, 12), true },
2152 };
2153
2154 RenderTextHarfBuzz render_text;
2155 Canvas canvas;
2156 TestSkiaTextRenderer renderer(&canvas);
2157
2158 for (size_t i = 0; i < arraysize(kTestStrings); ++i) {
2159 SCOPED_TRACE(base::StringPrintf("kTestStrings[%" PRIuS "]", i));
2160 render_text.SetText(WideToUTF16(kTestStrings[i].text));
2161
2162 render_text.EnsureLayout();
2163 const internal::TextRunList* run_list = render_text.GetRunList();
2164 EXPECT_EQ(2U, run_list->runs().size());
2165 if (run_list->runs().size() != 2U)
msw 2015/02/18 20:08:52 nit: make the above an ASSERT_EQ and remove this (
Jun Mukai 2015/02/18 23:53:37 Done.
2166 continue;
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
2040 // Test TextRunHarfBuzz's cluster finding logic. 2196 // Test TextRunHarfBuzz's cluster finding logic.
2041 TEST_F(RenderTextTest, HarfBuzz_Clusters) { 2197 TEST_F(RenderTextTest, HarfBuzz_Clusters) {
2042 struct { 2198 struct {
2043 uint32 glyph_to_char[4]; 2199 uint32 glyph_to_char[4];
2044 Range chars[4]; 2200 Range chars[4];
2045 Range glyphs[4]; 2201 Range glyphs[4];
2046 bool is_rtl; 2202 bool is_rtl;
2047 } cases[] = { 2203 } cases[] = {
2048 { // 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".
2049 { 0, 1, 2, 3 }, 2205 { 0, 1, 2, 3 },
(...skipping 356 matching lines...) Expand 10 before | Expand all | Expand 10 after
2406 base::StringToLowerASCII(fonts[0].GetActualFontNameForTesting())); 2562 base::StringToLowerASCII(fonts[0].GetActualFontNameForTesting()));
2407 2563
2408 scoped_ptr<RenderText> render_text(RenderText::CreateInstance()); 2564 scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
2409 render_text->SetDisplayRect(Rect(0, 0, 25, 25)); 2565 render_text->SetDisplayRect(Rect(0, 0, 25, 25));
2410 render_text->SetFontList(font_list); 2566 render_text->SetFontList(font_list);
2411 EXPECT_GT(render_text->GetBaseline(), font_list.GetBaseline()); 2567 EXPECT_GT(render_text->GetBaseline(), font_list.GetBaseline());
2412 } 2568 }
2413 #endif 2569 #endif
2414 2570
2415 } // 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