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

Side by Side Diff: ui/gfx/render_text_unittest.cc

Issue 351963002: RenderTextHarfBuzz: Allow mid-glyph cursors in multi-grapheme clusters (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: compile fix Created 6 years, 4 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 | Annotate | Revision Log
« 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/memory/scoped_ptr.h" 11 #include "base/memory/scoped_ptr.h"
11 #include "base/strings/string_util.h" 12 #include "base/strings/string_util.h"
12 #include "base/strings/stringprintf.h" 13 #include "base/strings/stringprintf.h"
13 #include "base/strings/utf_string_conversions.h" 14 #include "base/strings/utf_string_conversions.h"
14 #include "testing/gtest/include/gtest/gtest.h" 15 #include "testing/gtest/include/gtest/gtest.h"
15 #include "ui/gfx/break_list.h" 16 #include "ui/gfx/break_list.h"
16 #include "ui/gfx/canvas.h" 17 #include "ui/gfx/canvas.h"
17 #include "ui/gfx/render_text_harfbuzz.h" 18 #include "ui/gfx/render_text_harfbuzz.h"
18 19
19 #if defined(OS_WIN) 20 #if defined(OS_WIN)
(...skipping 2027 matching lines...) Expand 10 before | Expand all | Expand 10 after
2047 2048
2048 render_text->SetText(WideToUTF16(L"x \x25B6 y")); 2049 render_text->SetText(WideToUTF16(L"x \x25B6 y"));
2049 render_text->EnsureLayout(); 2050 render_text->EnsureLayout();
2050 ASSERT_EQ(3U, render_text->runs_.size()); 2051 ASSERT_EQ(3U, render_text->runs_.size());
2051 EXPECT_EQ(Range(0, 2), render_text->runs_[0]->range); 2052 EXPECT_EQ(Range(0, 2), render_text->runs_[0]->range);
2052 EXPECT_EQ(Range(2, 3), render_text->runs_[1]->range); 2053 EXPECT_EQ(Range(2, 3), render_text->runs_[1]->range);
2053 EXPECT_EQ(Range(3, 5), render_text->runs_[2]->range); 2054 EXPECT_EQ(Range(3, 5), render_text->runs_[2]->range);
2054 } 2055 }
2055 #endif // defined(OS_WIN) 2056 #endif // defined(OS_WIN)
2056 2057
2057 TEST_F(RenderTextTest, HarfBuzz_CharToGlyph) { 2058 // Test TextRunHarfBuzz's cluster finding logic.
2059 TEST_F(RenderTextTest, HarfBuzz_Clusters) {
2058 struct { 2060 struct {
2059 uint32 glyph_to_char[4]; 2061 uint32 glyph_to_char[4];
2060 size_t char_to_glyph_expected[4]; 2062 Range chars[4];
2061 Range char_range_to_glyph_range_expected[4]; 2063 Range glyphs[4];
2062 bool is_rtl; 2064 bool is_rtl;
2063 } cases[] = { 2065 } cases[] = {
2064 { // From string "A B C D" to glyphs "a b c d". 2066 { // From string "A B C D" to glyphs "a b c d".
2065 { 0, 1, 2, 3 }, 2067 { 0, 1, 2, 3 },
2066 { 0, 1, 2, 3 }, 2068 { Range(0, 1), Range(1, 2), Range(2, 3), Range(3, 4) },
2067 { Range(0, 1), Range(1, 2), Range(2, 3), Range(3, 4) }, 2069 { Range(0, 1), Range(1, 2), Range(2, 3), Range(3, 4) },
2068 false 2070 false
2069 }, 2071 },
2070 { // From string "A B C D" to glyphs "d b c a". 2072 { // From string "A B C D" to glyphs "d c b a".
2071 { 3, 2, 1, 0 }, 2073 { 3, 2, 1, 0 },
2072 { 3, 2, 1, 0 }, 2074 { Range(0, 1), Range(1, 2), Range(2, 3), Range(3, 4) },
2073 { Range(3, 4), Range(2, 3), Range(1, 2), Range(0, 1) }, 2075 { Range(3, 4), Range(2, 3), Range(1, 2), Range(0, 1) },
2074 true 2076 true
2075 }, 2077 },
2076 { // From string "A B C D" to glyphs "ab c c d". 2078 { // From string "A B C D" to glyphs "ab c c d".
2077 { 0, 2, 2, 3 }, 2079 { 0, 2, 2, 3 },
2078 { 0, 0, 1, 3 }, 2080 { Range(0, 2), Range(0, 2), Range(2, 3), Range(3, 4) },
2079 { Range(0, 1), Range(0, 1), Range(1, 3), Range(3, 4) }, 2081 { Range(0, 1), Range(0, 1), Range(1, 3), Range(3, 4) },
2080 false 2082 false
2081 }, 2083 },
2082 { // From string "A B C D" to glyphs "d c c ba". 2084 { // From string "A B C D" to glyphs "d c c ba".
2083 { 3, 2, 2, 0 }, 2085 { 3, 2, 2, 0 },
2084 { 3, 3, 1, 0 }, 2086 { Range(0, 2), Range(0, 2), Range(2, 3), Range(3, 4) },
2085 { Range(3, 4), Range(3, 4), Range(1, 3), Range(0, 1) }, 2087 { Range(3, 4), Range(3, 4), Range(1, 3), Range(0, 1) },
2086 true 2088 true
2087 }, 2089 },
2088 }; 2090 };
2089 2091
2090 internal::TextRunHarfBuzz run; 2092 internal::TextRunHarfBuzz run;
2091 run.range = Range(0, 4); 2093 run.range = Range(0, 4);
2092 run.glyph_count = 4; 2094 run.glyph_count = 4;
2093 run.glyph_to_char.reset(new uint32[4]); 2095 run.glyph_to_char.resize(4);
2094 2096
2095 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { 2097 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
2096 std::copy(cases[i].glyph_to_char, cases[i].glyph_to_char + 4, 2098 std::copy(cases[i].glyph_to_char, cases[i].glyph_to_char + 4,
2097 run.glyph_to_char.get()); 2099 run.glyph_to_char.begin());
2098 run.is_rtl = cases[i].is_rtl; 2100 run.is_rtl = cases[i].is_rtl;
2101
2099 for (size_t j = 0; j < 4; ++j) { 2102 for (size_t j = 0; j < 4; ++j) {
2100 SCOPED_TRACE(base::StringPrintf("Case %" PRIuS ", char %" PRIuS, i, j)); 2103 SCOPED_TRACE(base::StringPrintf("Case %" PRIuS ", char %" PRIuS, i, j));
2101 EXPECT_EQ(cases[i].char_to_glyph_expected[j], run.CharToGlyph(j)); 2104 Range chars;
2102 EXPECT_EQ(cases[i].char_range_to_glyph_range_expected[j], 2105 Range glyphs;
2103 run.CharRangeToGlyphRange(Range(j, j + 1))); 2106 run.GetClusterAt(j, &chars, &glyphs);
2107 EXPECT_EQ(cases[i].chars[j], chars);
2108 EXPECT_EQ(cases[i].glyphs[j], glyphs);
2109 EXPECT_EQ(cases[i].glyphs[j], run.CharRangeToGlyphRange(chars));
2104 } 2110 }
2105 } 2111 }
2106 } 2112 }
2113
2114 // Ensure that graphemes with multiple code points do not get split.
2115 TEST_F(RenderTextTest, HarfBuzz_SubglyphGraphemeCases) {
2116 const wchar_t* cases[] = {
2117 // "A" with a combining umlaut, followed by a "B".
2118 L"A\x0308" L"B",
2119 // Devanagari biconsonantal conjunct "ki", followed by an "a".
2120 L"\x0915\x093f\x0905",
2121 // Thai consonant and vowel pair "cho chan" + "sara am", followed by Thai
2122 // digit 0.
2123 L"\x0e08\x0e33\x0E50",
2124 };
2125
2126 RenderTextHarfBuzz render_text;
2127
2128 for (size_t i = 0; i < arraysize(cases); ++i) {
2129 SCOPED_TRACE(base::StringPrintf("Case %" PRIuS, i));
2130
2131 base::string16 text = WideToUTF16(cases[i]);
2132 render_text.SetText(text);
2133 render_text.EnsureLayout();
2134 ASSERT_EQ(1U, render_text.runs_.size());
2135 internal::TextRunHarfBuzz* run = render_text.runs_[0];
2136
2137 base::i18n::BreakIterator* iter = render_text.grapheme_iterator_.get();
2138 Range first_grapheme_bounds = run->GetGraphemeBounds(iter, 0);
2139 EXPECT_EQ(first_grapheme_bounds, run->GetGraphemeBounds(iter, 1));
2140 Range second_grapheme_bounds = run->GetGraphemeBounds(iter, 2);
2141 EXPECT_EQ(first_grapheme_bounds.end(), second_grapheme_bounds.start());
2142 }
2143 }
2144
2145 // Test the partition of a multi-grapheme cluster into grapheme ranges.
2146 TEST_F(RenderTextTest, HarfBuzz_SubglyphGraphemePartition) {
2147 struct {
2148 uint32 glyph_to_char[2];
2149 Range bounds[4];
2150 bool is_rtl;
2151 } cases[] = {
2152 { // From string "A B C D" to glyphs "a bcd".
2153 { 0, 1 },
2154 { Range(0, 10), Range(10, 13), Range(13, 17), Range(17, 20) },
2155 false
2156 },
2157 { // From string "A B C D" to glyphs "ab cd".
2158 { 0, 2 },
2159 { Range(0, 5), Range(5, 10), Range(10, 15), Range(15, 20) },
2160 false
2161 },
2162 { // From string "A B C D" to glyphs "dcb a".
2163 { 1, 0 },
2164 { Range(10, 20), Range(7, 10), Range(3, 7), Range(0, 3) },
2165 true
2166 },
2167 { // From string "A B C D" to glyphs "dc ba".
2168 { 2, 0 },
2169 { Range(15, 20), Range(10, 15), Range(5, 10), Range(0, 5) },
2170 true
2171 },
2172 };
2173
2174 internal::TextRunHarfBuzz run;
2175 run.range = Range(0, 4);
2176 run.glyph_count = 2;
2177 run.glyph_to_char.resize(2);
2178 run.positions.reset(new SkPoint[4]);
2179 run.width = 20;
2180
2181 const base::string16 kString = ASCIIToUTF16("abcd");
2182 scoped_ptr<base::i18n::BreakIterator> iter(new base::i18n::BreakIterator(
2183 kString, base::i18n::BreakIterator::BREAK_CHARACTER));
2184 ASSERT_TRUE(iter->Init());
2185
2186 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
2187 std::copy(cases[i].glyph_to_char, cases[i].glyph_to_char + 2,
2188 run.glyph_to_char.begin());
2189 run.is_rtl = cases[i].is_rtl;
2190 for (int j = 0; j < 2; ++j)
2191 run.positions[j].set(j * 10, 0);
2192
2193 for (size_t j = 0; j < 4; ++j) {
2194 SCOPED_TRACE(base::StringPrintf("Case %" PRIuS ", char %" PRIuS, i, j));
2195 EXPECT_EQ(cases[i].bounds[j], run.GetGraphemeBounds(iter.get(), j));
2196 }
2197 }
2198 }
2107 2199
2108 TEST_F(RenderTextTest, HarfBuzz_RunDirection) { 2200 TEST_F(RenderTextTest, HarfBuzz_RunDirection) {
2109 RenderTextHarfBuzz render_text; 2201 RenderTextHarfBuzz render_text;
2110 const base::string16 mixed = 2202 const base::string16 mixed =
2111 WideToUTF16(L"\x05D0\x05D1" L"1234" L"\x05D2\x05D3"); 2203 WideToUTF16(L"\x05D0\x05D1" L"1234" L"\x05D2\x05D3");
2112 render_text.SetText(mixed); 2204 render_text.SetText(mixed);
2113 render_text.EnsureLayout(); 2205 render_text.EnsureLayout();
2114 ASSERT_EQ(3U, render_text.runs_.size()); 2206 ASSERT_EQ(3U, render_text.runs_.size());
2115 EXPECT_TRUE(render_text.runs_[0]->is_rtl); 2207 EXPECT_TRUE(render_text.runs_[0]->is_rtl);
2116 EXPECT_FALSE(render_text.runs_[1]->is_rtl); 2208 EXPECT_FALSE(render_text.runs_[1]->is_rtl);
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
2164 for (size_t i = 0; i < arraysize(kTestStrings); ++i) { 2256 for (size_t i = 0; i < arraysize(kTestStrings); ++i) {
2165 render_text->SetText(WideToUTF16(kTestStrings[i])); 2257 render_text->SetText(WideToUTF16(kTestStrings[i]));
2166 render_text->EnsureLayout(); 2258 render_text->EnsureLayout();
2167 2259
2168 for (size_t j = 0; j < render_text->text().length(); ++j) 2260 for (size_t j = 0; j < render_text->text().length(); ++j)
2169 EXPECT_FALSE(render_text->GetGlyphBounds(j).is_empty()); 2261 EXPECT_FALSE(render_text->GetGlyphBounds(j).is_empty());
2170 } 2262 }
2171 } 2263 }
2172 2264
2173 } // namespace gfx 2265 } // 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