OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |