Chromium Code Reviews| 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 |