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/memory/scoped_ptr.h" | 10 #include "base/memory/scoped_ptr.h" |
| (...skipping 1992 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2003 | 2003 |
| 2004 render_text->SetText(WideToUTF16(L"x \x25B6 y")); | 2004 render_text->SetText(WideToUTF16(L"x \x25B6 y")); |
| 2005 render_text->EnsureLayout(); | 2005 render_text->EnsureLayout(); |
| 2006 ASSERT_EQ(3U, render_text->runs_.size()); | 2006 ASSERT_EQ(3U, render_text->runs_.size()); |
| 2007 EXPECT_EQ(Range(0, 2), render_text->runs_[0]->range); | 2007 EXPECT_EQ(Range(0, 2), render_text->runs_[0]->range); |
| 2008 EXPECT_EQ(Range(2, 3), render_text->runs_[1]->range); | 2008 EXPECT_EQ(Range(2, 3), render_text->runs_[1]->range); |
| 2009 EXPECT_EQ(Range(3, 5), render_text->runs_[2]->range); | 2009 EXPECT_EQ(Range(3, 5), render_text->runs_[2]->range); |
| 2010 } | 2010 } |
| 2011 #endif // defined(OS_WIN) | 2011 #endif // defined(OS_WIN) |
| 2012 | 2012 |
| 2013 TEST_F(RenderTextTest, HarfBuzz_CharToGlyph) { | 2013 // Test TextRunHarfBuzz's cluster finding logic. |
| 2014 TEST_F(RenderTextTest, HarfBuzz_Clusters) { | |
| 2014 struct { | 2015 struct { |
| 2015 uint32 glyph_to_char[4]; | 2016 uint32 glyph_to_char[4]; |
| 2016 size_t char_to_glyph_expected[4]; | 2017 Range chars[4]; |
| 2017 Range char_range_to_glyph_range_expected[4]; | 2018 Range glyphs[4]; |
| 2018 bool is_rtl; | 2019 bool is_rtl; |
| 2019 } cases[] = { | 2020 } cases[] = { |
| 2020 { // From string "A B C D" to glyphs "a b c d". | 2021 { // From string "A B C D" to glyphs "a b c d". |
| 2021 { 0, 1, 2, 3 }, | 2022 { 0, 1, 2, 3 }, |
| 2022 { 0, 1, 2, 3 }, | 2023 { Range(0, 1), Range(1, 2), Range(2, 3), Range(3, 4) }, |
| 2023 { Range(0, 1), Range(1, 2), Range(2, 3), Range(3, 4) }, | 2024 { Range(0, 1), Range(1, 2), Range(2, 3), Range(3, 4) }, |
| 2024 false | 2025 false |
| 2025 }, | 2026 }, |
| 2026 { // From string "A B C D" to glyphs "d b c a". | 2027 { // From string "A B C D" to glyphs "d c b a". |
| 2027 { 3, 2, 1, 0 }, | 2028 { 3, 2, 1, 0 }, |
| 2028 { 3, 2, 1, 0 }, | 2029 { Range(0, 1), Range(1, 2), Range(2, 3), Range(3, 4) }, |
| 2029 { Range(3, 4), Range(2, 3), Range(1, 2), Range(0, 1) }, | 2030 { Range(3, 4), Range(2, 3), Range(1, 2), Range(0, 1) }, |
| 2030 true | 2031 true |
| 2031 }, | 2032 }, |
| 2032 { // From string "A B C D" to glyphs "ab c c d". | 2033 { // From string "A B C D" to glyphs "ab c c d". |
| 2033 { 0, 2, 2, 3 }, | 2034 { 0, 2, 2, 3 }, |
| 2034 { 0, 0, 1, 3 }, | 2035 { Range(0, 2), Range(0, 2), Range(2, 3), Range(3, 4) }, |
| 2035 { Range(0, 1), Range(0, 1), Range(1, 3), Range(3, 4) }, | 2036 { Range(0, 1), Range(0, 1), Range(1, 3), Range(3, 4) }, |
| 2036 false | 2037 false |
| 2037 }, | 2038 }, |
| 2038 { // From string "A B C D" to glyphs "d c c ba". | 2039 { // From string "A B C D" to glyphs "d c c ba". |
| 2039 { 3, 2, 2, 0 }, | 2040 { 3, 2, 2, 0 }, |
| 2040 { 3, 3, 1, 0 }, | 2041 { Range(0, 2), Range(0, 2), Range(2, 3), Range(3, 4) }, |
| 2041 { Range(3, 4), Range(3, 4), Range(1, 3), Range(0, 1) }, | 2042 { Range(3, 4), Range(3, 4), Range(1, 3), Range(0, 1) }, |
| 2042 true | 2043 true |
| 2043 }, | 2044 }, |
| 2044 }; | 2045 }; |
| 2045 | 2046 |
| 2046 internal::TextRunHarfBuzz run; | 2047 internal::TextRunHarfBuzz run; |
| 2047 run.range = Range(0, 4); | 2048 run.range = Range(0, 4); |
| 2048 run.glyph_count = 4; | 2049 run.glyph_count = 4; |
| 2049 run.glyph_to_char.reset(new uint32[4]); | 2050 run.glyph_to_char.resize(4); |
| 2050 | 2051 |
| 2051 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { | 2052 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { |
| 2052 std::copy(cases[i].glyph_to_char, cases[i].glyph_to_char + 4, | 2053 std::copy(cases[i].glyph_to_char, cases[i].glyph_to_char + 4, |
| 2053 run.glyph_to_char.get()); | 2054 run.glyph_to_char.begin()); |
| 2054 run.is_rtl = cases[i].is_rtl; | 2055 run.is_rtl = cases[i].is_rtl; |
| 2056 | |
| 2055 for (size_t j = 0; j < 4; ++j) { | 2057 for (size_t j = 0; j < 4; ++j) { |
| 2056 SCOPED_TRACE(base::StringPrintf("Case %" PRIuS ", char %" PRIuS, i, j)); | 2058 SCOPED_TRACE(base::StringPrintf("Case %" PRIuS ", char %" PRIuS, i, j)); |
| 2057 EXPECT_EQ(cases[i].char_to_glyph_expected[j], run.CharToGlyph(j)); | 2059 Range chars; |
| 2058 EXPECT_EQ(cases[i].char_range_to_glyph_range_expected[j], | 2060 Range glyphs; |
| 2059 run.CharRangeToGlyphRange(Range(j, j + 1))); | 2061 run.GetClusterAt(j, &chars, &glyphs); |
| 2062 EXPECT_EQ(cases[i].chars[j], chars); | |
| 2063 EXPECT_EQ(cases[i].glyphs[j], glyphs); | |
| 2064 EXPECT_EQ(cases[i].glyphs[j], run.CharRangeToGlyphRange(chars)); | |
| 2060 } | 2065 } |
| 2061 } | 2066 } |
| 2062 } | 2067 } |
| 2068 | |
| 2069 // Ensure that graphemes with multiple code points do not get split. | |
| 2070 TEST_F(RenderTextTest, HarfBuzz_SubglyphGraphemeCases) { | |
| 2071 const base::string16 cases[] = { | |
| 2072 // "A" with a combining umlaut, followed by a "B". | |
| 2073 L"A\x0308" L"B", | |
| 2074 // Devanagari biconsonantal conjunct "ki", followed by an "a". | |
| 2075 L"\x0915\x093f\x0905", | |
| 2076 // Thai consonant and vowel pair "cho chan" + "sara am", followed by Thai | |
| 2077 // digit 0. | |
| 2078 L"\x0e08\x0e33\x0E50", | |
| 2079 }; | |
| 2080 | |
| 2081 RenderTextHarfBuzz render_text; | |
| 2082 | |
| 2083 for (size_t i = 0; i < arraysize(cases); ++i) { | |
| 2084 SCOPED_TRACE(base::StringPrintf("Case %" PRIuS, i)); | |
| 2085 | |
| 2086 render_text.SetText(cases[i]); | |
| 2087 render_text.EnsureLayout(); | |
| 2088 ASSERT_EQ(1U, render_text.runs_.size()); | |
| 2089 internal::TextRunHarfBuzz* run = render_text.runs_[0]; | |
| 2090 | |
| 2091 base::i18n::BreakIterator* iter = render_text.grapheme_iterator(); | |
| 2092 Range first_grapheme_bounds = run->GetGraphemeBounds(cases[i], iter, 0); | |
| 2093 EXPECT_EQ(first_grapheme_bounds, run->GetGraphemeBounds(cases[i], iter, 1)); | |
| 2094 Range second_grapheme_bounds = run->GetGraphemeBounds(cases[i], iter, 2); | |
| 2095 EXPECT_EQ(first_grapheme_bounds.end(), second_grapheme_bounds.start()); | |
| 2096 } | |
| 2097 } | |
| 2098 | |
| 2099 // Test the partition of a multi-grapheme cluster into grapheme ranges. | |
| 2100 TEST_F(RenderTextTest, HarfBuzz_SubglyphGraphemePartition) { | |
| 2101 struct { | |
| 2102 uint32 glyph_to_char[2]; | |
| 2103 Range bounds[4]; | |
| 2104 bool is_rtl; | |
| 2105 } cases[] = { | |
| 2106 { // From string "A B C D" to glyphs "a bcd". | |
| 2107 { 0, 1 }, | |
| 2108 { Range(0, 10), Range(10, 13), Range(13, 17), Range(17, 20) }, | |
| 2109 false | |
| 2110 }, | |
| 2111 { // From string "A B C D" to glyphs "ab cd". | |
| 2112 { 0, 2 }, | |
| 2113 { Range(0, 5), Range(5, 10), Range(10, 15), Range(15, 20) }, | |
| 2114 false | |
| 2115 }, | |
| 2116 { // From string "A B C D" to glyphs "dcb a". | |
|
msw
2014/07/25 00:37:01
nit: maybe add RTL case "dc ba" for good measure?
ckocagil
2014/07/29 23:13:42
Done.
| |
| 2117 { 1, 0 }, | |
| 2118 { Range(10, 20), Range(7, 10), Range(3, 7), Range(0, 3) }, | |
| 2119 true | |
| 2120 }, | |
| 2121 }; | |
| 2122 | |
| 2123 internal::TextRunHarfBuzz run; | |
| 2124 run.range = Range(0, 4); | |
| 2125 run.glyph_count = 2; | |
| 2126 run.glyph_to_char.resize(2); | |
| 2127 run.positions.reset(new SkPoint[4]); | |
| 2128 run.width = 20; | |
| 2129 | |
| 2130 const base::string16 kString = ASCIIToUTF16("abcd"); | |
| 2131 scoped_ptr<base::i18n::BreakIterator> iter(new base::i18n::BreakIterator( | |
| 2132 kString, base::i18n::BreakIterator::BREAK_CHARACTER)); | |
| 2133 if (!iter->Init()) | |
|
msw
2014/07/25 00:37:01
Make this ASSERT_TRUE(iter-Init());
ckocagil
2014/07/29 23:13:42
Done.
| |
| 2134 iter.reset(); | |
| 2135 | |
| 2136 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { | |
| 2137 std::copy(cases[i].glyph_to_char, cases[i].glyph_to_char + 2, | |
| 2138 run.glyph_to_char.begin()); | |
| 2139 run.is_rtl = cases[i].is_rtl; | |
| 2140 for (int j = 0; j < 2; ++j) | |
| 2141 run.positions[j].set(j * 10, 0); | |
| 2142 | |
| 2143 for (size_t j = 0; j < 4; ++j) { | |
| 2144 SCOPED_TRACE(base::StringPrintf("Case %" PRIuS ", char %" PRIuS, i, j)); | |
| 2145 EXPECT_EQ(cases[i].bounds[j], | |
| 2146 run.GetGraphemeBounds(kString, iter.get(), j)); | |
| 2147 } | |
| 2148 } | |
| 2149 } | |
| 2063 | 2150 |
| 2064 TEST_F(RenderTextTest, HarfBuzz_RunDirection) { | 2151 TEST_F(RenderTextTest, HarfBuzz_RunDirection) { |
| 2065 RenderTextHarfBuzz render_text; | 2152 RenderTextHarfBuzz render_text; |
| 2066 const base::string16 mixed = | 2153 const base::string16 mixed = |
| 2067 WideToUTF16(L"\x05D0\x05D1" L"1234" L"\x05D2\x05D3"); | 2154 WideToUTF16(L"\x05D0\x05D1" L"1234" L"\x05D2\x05D3"); |
| 2068 render_text.SetText(mixed); | 2155 render_text.SetText(mixed); |
| 2069 render_text.EnsureLayout(); | 2156 render_text.EnsureLayout(); |
| 2070 ASSERT_EQ(3U, render_text.runs_.size()); | 2157 ASSERT_EQ(3U, render_text.runs_.size()); |
| 2071 EXPECT_TRUE(render_text.runs_[0]->is_rtl); | 2158 EXPECT_TRUE(render_text.runs_[0]->is_rtl); |
| 2072 EXPECT_FALSE(render_text.runs_[1]->is_rtl); | 2159 EXPECT_FALSE(render_text.runs_[1]->is_rtl); |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2120 for (size_t i = 0; i < arraysize(kTestStrings); ++i) { | 2207 for (size_t i = 0; i < arraysize(kTestStrings); ++i) { |
| 2121 render_text->SetText(WideToUTF16(kTestStrings[i])); | 2208 render_text->SetText(WideToUTF16(kTestStrings[i])); |
| 2122 render_text->EnsureLayout(); | 2209 render_text->EnsureLayout(); |
| 2123 | 2210 |
| 2124 for (size_t j = 0; j < render_text->text().length(); ++j) | 2211 for (size_t j = 0; j < render_text->text().length(); ++j) |
| 2125 EXPECT_FALSE(render_text->GetGlyphBounds(j).is_empty()); | 2212 EXPECT_FALSE(render_text->GetGlyphBounds(j).is_empty()); |
| 2126 } | 2213 } |
| 2127 } | 2214 } |
| 2128 | 2215 |
| 2129 } // namespace gfx | 2216 } // namespace gfx |
| OLD | NEW |