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

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: comments addressed 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 };
msw 2015/02/18 18:58:37 nit: DISALLOW_COPY_AND_ASSIGN
Jun Mukai 2015/02/18 19:55:56 Done.
160
93 } // namespace 161 } // namespace
94 162
95 class RenderTextTest : public testing::Test { 163 class RenderTextTest : public testing::Test {
96 }; 164 };
97 165
98 TEST_F(RenderTextTest, DefaultStyle) { 166 TEST_F(RenderTextTest, DefaultStyle) {
99 // Check the default styles applied to new instances and adjusted text. 167 // Check the default styles applied to new instances and adjusted text.
100 scoped_ptr<RenderText> render_text(RenderText::CreateInstance()); 168 scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
101 EXPECT_TRUE(render_text->text().empty()); 169 EXPECT_TRUE(render_text->text().empty());
102 const wchar_t* const cases[] = { kWeak, kLtr, L"Hello", kRtl, L"", L"" }; 170 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); 1978 EXPECT_GT(render_text.lines_.size(), 1U);
1911 } 1979 }
1912 } 1980 }
1913 1981
1914 // Ensure strings wrap onto multiple lines for a normal available width. 1982 // Ensure strings wrap onto multiple lines for a normal available width.
1915 TEST_F(RenderTextTest, Multiline_NormalWidth) { 1983 TEST_F(RenderTextTest, Multiline_NormalWidth) {
1916 const struct { 1984 const struct {
1917 const wchar_t* const text; 1985 const wchar_t* const text;
1918 const Range first_line_char_range; 1986 const Range first_line_char_range;
1919 const Range second_line_char_range; 1987 const Range second_line_char_range;
1988 bool is_ltr;
1920 } kTestStrings[] = { 1989 } kTestStrings[] = {
1921 { L"abc defg hijkl", Range(0, 9), Range(9, 14) }, 1990 { L"abc defg hijkl", Range(0, 9), Range(9, 14), true },
1922 { L"qwertyzxcvbn", Range(0, 10), Range(10, 12) }, 1991 { L"qwertyzxcvbn", Range(0, 10), Range(10, 12), true },
1992 { L"\x0627\x0644\x0644\x063A\x0629 "
1993 L"\x0627\x0644\x0639\x0631\x0628\x064A\x0629",
1994 Range(0, 6), Range(6, 13), false },
1923 { L"\x062A\x0641\x0627\x062D\x05EA\x05E4\x05D5\x05D6\x05D9" 1995 { L"\x062A\x0641\x0627\x062D\x05EA\x05E4\x05D5\x05D6\x05D9"
1924 L"\x05DA\x05DB\x05DD", Range(4, 12), Range(0, 4) } 1996 L"\x05DA\x05DB\x05DD", Range(0, 4), Range(4, 12), false }
1925 }; 1997 };
1926 1998
1927 RenderTextHarfBuzz render_text; 1999 RenderTextHarfBuzz render_text;
1928 // Specify the fixed width for characters to suppress the possible variations 2000 // Specify the fixed width for characters to suppress the possible variations
1929 // of linebreak results. 2001 // of linebreak results.
1930 render_text.set_glyph_width_for_test(5); 2002 render_text.set_glyph_width_for_test(5);
1931 render_text.SetDisplayRect(Rect(50, 1000)); 2003 render_text.SetDisplayRect(Rect(50, 1000));
1932 render_text.SetMultiline(true); 2004 render_text.SetMultiline(true);
2005 render_text.SetHorizontalAlignment(ALIGN_TO_HEAD);
2006
1933 Canvas canvas; 2007 Canvas canvas;
2008 TestSkiaTextRenderer renderer(&canvas);
1934 2009
1935 for (size_t i = 0; i < arraysize(kTestStrings); ++i) { 2010 for (size_t i = 0; i < arraysize(kTestStrings); ++i) {
1936 SCOPED_TRACE(base::StringPrintf("kTestStrings[%" PRIuS "]", i)); 2011 SCOPED_TRACE(base::StringPrintf("kTestStrings[%" PRIuS "]", i));
1937 render_text.SetText(WideToUTF16(kTestStrings[i].text)); 2012 render_text.SetText(WideToUTF16(kTestStrings[i].text));
1938 render_text.Draw(&canvas); 2013 render_text.EnsureLayout();
2014 render_text.DrawVisualTextInternal(&renderer);
2015
1939 ASSERT_EQ(2U, render_text.lines_.size()); 2016 ASSERT_EQ(2U, render_text.lines_.size());
1940 ASSERT_EQ(1U, render_text.lines_[0].segments.size()); 2017 ASSERT_EQ(1U, render_text.lines_[0].segments.size());
1941 EXPECT_EQ(kTestStrings[i].first_line_char_range, 2018 EXPECT_EQ(kTestStrings[i].first_line_char_range,
1942 render_text.lines_[0].segments[0].char_range); 2019 render_text.lines_[0].segments[0].char_range);
1943 ASSERT_EQ(1U, render_text.lines_[1].segments.size()); 2020 ASSERT_EQ(1U, render_text.lines_[1].segments.size());
1944 EXPECT_EQ(kTestStrings[i].second_line_char_range, 2021 EXPECT_EQ(kTestStrings[i].second_line_char_range,
1945 render_text.lines_[1].segments[0].char_range); 2022 render_text.lines_[1].segments[0].char_range);
2023
2024 std::vector<TestSkiaTextRenderer::TextLog> text_log;
2025 renderer.GetTextLogAndReset(&text_log);
2026 ASSERT_EQ(2U, text_log.size());
2027 // NOTE: this expectation compares the character length and glyph counts,
2028 // which doesn't always equal. This is okay only because the all test
msw 2015/02/18 18:58:37 nit: s/doesn't/isn't/ and s/the all test/all the t
Jun Mukai 2015/02/18 19:55:56 Done.
2029 // strings are simple (like, no compound characters nor UTF16-surrogate
2030 // pairs). Be careful in case more complicated test strings are added.
2031 EXPECT_EQ(kTestStrings[i].first_line_char_range.length(),
2032 text_log[0].glyph_count);
2033 EXPECT_EQ(kTestStrings[i].second_line_char_range.length(),
2034 text_log[1].glyph_count);
2035 EXPECT_LT(text_log[0].origin.y(), text_log[1].origin.y());
2036 if (kTestStrings[i].is_ltr) {
2037 EXPECT_EQ(0, text_log[0].origin.x());
2038 EXPECT_EQ(0, text_log[1].origin.x());
2039 } else {
2040 EXPECT_LT(0, text_log[0].origin.x());
2041 EXPECT_LT(0, text_log[1].origin.x());
2042 }
1946 } 2043 }
1947 } 2044 }
1948 2045
1949 // Ensure strings don't wrap onto multiple lines for a sufficient available 2046 // Ensure strings don't wrap onto multiple lines for a sufficient available
1950 // width. 2047 // width.
1951 TEST_F(RenderTextTest, Multiline_SufficientWidth) { 2048 TEST_F(RenderTextTest, Multiline_SufficientWidth) {
1952 const wchar_t* kTestStrings[] = { L"", L" ", L".", L" . ", L"abc", L"a b c", 2049 const wchar_t* kTestStrings[] = { L"", L" ", L".", L" . ", L"abc", L"a b c",
1953 L"\x62E\x628\x632", L"\x62E \x628 \x632" }; 2050 L"\x62E\x628\x632", L"\x62E \x628 \x632" };
1954 2051
1955 RenderTextHarfBuzz render_text; 2052 RenderTextHarfBuzz render_text;
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
2030 2127
2031 for (size_t i = 0; i < arraysize(kTestStrings); ++i) { 2128 for (size_t i = 0; i < arraysize(kTestStrings); ++i) {
2032 SCOPED_TRACE(base::StringPrintf("kTestStrings[%" PRIuS "]", i)); 2129 SCOPED_TRACE(base::StringPrintf("kTestStrings[%" PRIuS "]", i));
2033 render_text.SetText(WideToUTF16(kTestStrings[i])); 2130 render_text.SetText(WideToUTF16(kTestStrings[i]));
2034 render_text.Draw(&canvas); 2131 render_text.Draw(&canvas);
2035 2132
2036 EXPECT_EQ(1U, render_text.lines_.size()); 2133 EXPECT_EQ(1U, render_text.lines_.size());
2037 } 2134 }
2038 } 2135 }
2039 2136
2137 TEST_F(RenderTextTest, HarfBuzz_RTLDrawingPositions) {
2138 RenderTextHarfBuzz render_text;
2139 render_text.SetText(WideToUTF16(
2140 L"\x062A\x0641\x0627\x062D\x05EA\x05E4\x05D5\x05D6\x05D9"
2141 L"\x05DA\x05DB\x05DD"));
2142
2143 Canvas canvas;
2144 TestSkiaTextRenderer renderer(&canvas);
2145
2146 render_text.EnsureLayout();
2147 render_text.DrawVisualTextInternal(&renderer);
2148
2149 std::vector<TestSkiaTextRenderer::TextLog> text_log;
2150 renderer.GetTextLogAndReset(&text_log);
2151
2152 EXPECT_EQ(2U, text_log.size());
2153
2154 EXPECT_EQ(8U, text_log[0].glyph_count);
2155 EXPECT_EQ(4U, text_log[1].glyph_count);
2156 EXPECT_LT(text_log[0].origin.x(), text_log[1].origin.x());
2157 }
2158
2040 // Test TextRunHarfBuzz's cluster finding logic. 2159 // Test TextRunHarfBuzz's cluster finding logic.
2041 TEST_F(RenderTextTest, HarfBuzz_Clusters) { 2160 TEST_F(RenderTextTest, HarfBuzz_Clusters) {
2042 struct { 2161 struct {
2043 uint32 glyph_to_char[4]; 2162 uint32 glyph_to_char[4];
2044 Range chars[4]; 2163 Range chars[4];
2045 Range glyphs[4]; 2164 Range glyphs[4];
2046 bool is_rtl; 2165 bool is_rtl;
2047 } cases[] = { 2166 } cases[] = {
2048 { // From string "A B C D" to glyphs "a b c d". 2167 { // From string "A B C D" to glyphs "a b c d".
2049 { 0, 1, 2, 3 }, 2168 { 0, 1, 2, 3 },
(...skipping 356 matching lines...) Expand 10 before | Expand all | Expand 10 after
2406 base::StringToLowerASCII(fonts[0].GetActualFontNameForTesting())); 2525 base::StringToLowerASCII(fonts[0].GetActualFontNameForTesting()));
2407 2526
2408 scoped_ptr<RenderText> render_text(RenderText::CreateInstance()); 2527 scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
2409 render_text->SetDisplayRect(Rect(0, 0, 25, 25)); 2528 render_text->SetDisplayRect(Rect(0, 0, 25, 25));
2410 render_text->SetFontList(font_list); 2529 render_text->SetFontList(font_list);
2411 EXPECT_GT(render_text->GetBaseline(), font_list.GetBaseline()); 2530 EXPECT_GT(render_text->GetBaseline(), font_list.GetBaseline());
2412 } 2531 }
2413 #endif 2532 #endif
2414 2533
2415 } // namespace gfx 2534 } // 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