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 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |