Don't crash when SimpleCache index is corrupt.
[chromium-blink-merge.git] / ui / gfx / render_text_unittest.cc
blob151be2aa0a82f0091e9a93d3fd599e69a3978900
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
3 // found in the LICENSE file.
5 #include "ui/gfx/render_text.h"
7 #include "base/memory/scoped_ptr.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "testing/gtest/include/gtest/gtest.h"
10 #include "ui/gfx/break_list.h"
12 #if defined(OS_WIN)
13 #include "base/win/windows_version.h"
14 #endif
16 #if defined(OS_LINUX)
17 #include "ui/gfx/render_text_linux.h"
18 #endif
20 #if defined(TOOLKIT_GTK)
21 #include <gtk/gtk.h>
22 #endif
24 namespace gfx {
26 namespace {
28 // Various weak, LTR, RTL, and Bidi string cases with three characters each.
29 const wchar_t kWeak[] = L" . ";
30 const wchar_t kLtr[] = L"abc";
31 const wchar_t kLtrRtl[] = L"a"L"\x5d0\x5d1";
32 const wchar_t kLtrRtlLtr[] = L"a"L"\x5d1"L"b";
33 const wchar_t kRtl[] = L"\x5d0\x5d1\x5d2";
34 const wchar_t kRtlLtr[] = L"\x5d0\x5d1"L"a";
35 const wchar_t kRtlLtrRtl[] = L"\x5d0"L"a"L"\x5d1";
37 // Checks whether |range| contains |index|. This is not the same as calling
38 // |range.Contains(ui::Range(index))| - as that would return true when
39 // |index| == |range.end()|.
40 bool IndexInRange(const ui::Range& range, size_t index) {
41 return index >= range.start() && index < range.end();
44 base::string16 GetSelectedText(RenderText* render_text) {
45 return render_text->text().substr(render_text->selection().GetMin(),
46 render_text->selection().length());
49 // A test utility function to set the application default text direction.
50 void SetRTL(bool rtl) {
51 // Override the current locale/direction.
52 base::i18n::SetICUDefaultLocale(rtl ? "he" : "en");
53 #if defined(TOOLKIT_GTK)
54 // Do the same for GTK, which does not rely on the ICU default locale.
55 gtk_widget_set_default_direction(rtl ? GTK_TEXT_DIR_RTL : GTK_TEXT_DIR_LTR);
56 #endif
57 EXPECT_EQ(rtl, base::i18n::IsRTL());
60 } // namespace
62 class RenderTextTest : public testing::Test {
65 TEST_F(RenderTextTest, DefaultStyle) {
66 // Check the default styles applied to new instances and adjusted text.
67 scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
68 EXPECT_TRUE(render_text->text().empty());
69 const wchar_t* const cases[] = { kWeak, kLtr, L"Hello", kRtl, L"", L"" };
70 for (size_t i = 0; i < arraysize(cases); ++i) {
71 EXPECT_TRUE(render_text->colors().EqualsValueForTesting(SK_ColorBLACK));
72 for (size_t style = 0; style < NUM_TEXT_STYLES; ++style)
73 EXPECT_TRUE(render_text->styles()[style].EqualsValueForTesting(false));
74 render_text->SetText(WideToUTF16(cases[i]));
78 TEST_F(RenderTextTest, SetColorAndStyle) {
79 // Ensure custom default styles persist across setting and clearing text.
80 scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
81 const SkColor color = SK_ColorRED;
82 render_text->SetColor(color);
83 render_text->SetStyle(BOLD, true);
84 render_text->SetStyle(UNDERLINE, false);
85 const wchar_t* const cases[] = { kWeak, kLtr, L"Hello", kRtl, L"", L"" };
86 for (size_t i = 0; i < arraysize(cases); ++i) {
87 EXPECT_TRUE(render_text->colors().EqualsValueForTesting(color));
88 EXPECT_TRUE(render_text->styles()[BOLD].EqualsValueForTesting(true));
89 EXPECT_TRUE(render_text->styles()[UNDERLINE].EqualsValueForTesting(false));
90 render_text->SetText(WideToUTF16(cases[i]));
92 // Ensure custom default styles can be applied after text has been set.
93 if (i == 1)
94 render_text->SetStyle(STRIKE, true);
95 if (i >= 1)
96 EXPECT_TRUE(render_text->styles()[STRIKE].EqualsValueForTesting(true));
100 TEST_F(RenderTextTest, ApplyColorAndStyle) {
101 scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
102 render_text->SetText(ASCIIToUTF16("012345678"));
104 // Apply a ranged color and style and check the resulting breaks.
105 render_text->ApplyColor(SK_ColorRED, ui::Range(1, 4));
106 render_text->ApplyStyle(BOLD, true, ui::Range(2, 5));
107 std::vector<std::pair<size_t, SkColor> > expected_color;
108 expected_color.push_back(std::pair<size_t, SkColor>(0, SK_ColorBLACK));
109 expected_color.push_back(std::pair<size_t, SkColor>(1, SK_ColorRED));
110 expected_color.push_back(std::pair<size_t, SkColor>(4, SK_ColorBLACK));
111 EXPECT_TRUE(render_text->colors().EqualsForTesting(expected_color));
112 std::vector<std::pair<size_t, bool> > expected_style;
113 expected_style.push_back(std::pair<size_t, bool>(0, false));
114 expected_style.push_back(std::pair<size_t, bool>(2, true));
115 expected_style.push_back(std::pair<size_t, bool>(5, false));
116 EXPECT_TRUE(render_text->styles()[BOLD].EqualsForTesting(expected_style));
118 // Ensure setting a color and style overrides the ranged colors and styles.
119 render_text->SetColor(SK_ColorBLUE);
120 EXPECT_TRUE(render_text->colors().EqualsValueForTesting(SK_ColorBLUE));
121 render_text->SetStyle(BOLD, false);
122 EXPECT_TRUE(render_text->styles()[BOLD].EqualsValueForTesting(false));
124 // Apply a color and style over the text end and check the resulting breaks.
125 // (INT_MAX should be used instead of the text length for the range end)
126 const size_t text_length = render_text->text().length();
127 render_text->ApplyColor(SK_ColorRED, ui::Range(0, text_length));
128 render_text->ApplyStyle(BOLD, true, ui::Range(2, text_length));
129 std::vector<std::pair<size_t, SkColor> > expected_color_end;
130 expected_color_end.push_back(std::pair<size_t, SkColor>(0, SK_ColorRED));
131 EXPECT_TRUE(render_text->colors().EqualsForTesting(expected_color_end));
132 std::vector<std::pair<size_t, bool> > expected_style_end;
133 expected_style_end.push_back(std::pair<size_t, bool>(0, false));
134 expected_style_end.push_back(std::pair<size_t, bool>(2, true));
135 EXPECT_TRUE(render_text->styles()[BOLD].EqualsForTesting(expected_style_end));
137 // Ensure ranged values adjust to accommodate text length changes.
138 render_text->ApplyStyle(ITALIC, true, ui::Range(0, 2));
139 render_text->ApplyStyle(ITALIC, true, ui::Range(3, 6));
140 render_text->ApplyStyle(ITALIC, true, ui::Range(7, text_length));
141 std::vector<std::pair<size_t, bool> > expected_italic;
142 expected_italic.push_back(std::pair<size_t, bool>(0, true));
143 expected_italic.push_back(std::pair<size_t, bool>(2, false));
144 expected_italic.push_back(std::pair<size_t, bool>(3, true));
145 expected_italic.push_back(std::pair<size_t, bool>(6, false));
146 expected_italic.push_back(std::pair<size_t, bool>(7, true));
147 EXPECT_TRUE(render_text->styles()[ITALIC].EqualsForTesting(expected_italic));
149 // Truncating the text should trim any corresponding breaks.
150 render_text->SetText(ASCIIToUTF16("0123456"));
151 expected_italic.resize(4);
152 EXPECT_TRUE(render_text->styles()[ITALIC].EqualsForTesting(expected_italic));
153 render_text->SetText(ASCIIToUTF16("01234"));
154 expected_italic.resize(3);
155 EXPECT_TRUE(render_text->styles()[ITALIC].EqualsForTesting(expected_italic));
157 // Appending text should extend the terminal styles without changing breaks.
158 render_text->SetText(ASCIIToUTF16("012345678"));
159 EXPECT_TRUE(render_text->styles()[ITALIC].EqualsForTesting(expected_italic));
162 #if defined(OS_LINUX)
163 TEST_F(RenderTextTest, PangoAttributes) {
164 scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
165 render_text->SetText(ASCIIToUTF16("012345678"));
167 // Apply ranged BOLD/ITALIC styles and check the resulting Pango attributes.
168 render_text->ApplyStyle(BOLD, true, ui::Range(2, 4));
169 render_text->ApplyStyle(ITALIC, true, ui::Range(1, 3));
171 struct {
172 int start;
173 int end;
174 bool bold;
175 bool italic;
176 } cases[] = {
177 { 0, 1, false, false },
178 { 1, 2, false, true },
179 { 2, 3, true, true },
180 { 3, 4, true, false },
181 { 4, INT_MAX, false, false },
184 int start = 0, end = 0;
185 RenderTextLinux* rt_linux = static_cast<RenderTextLinux*>(render_text.get());
186 rt_linux->EnsureLayout();
187 PangoAttrList* attributes = pango_layout_get_attributes(rt_linux->layout_);
188 PangoAttrIterator* iter = pango_attr_list_get_iterator(attributes);
189 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
190 pango_attr_iterator_range(iter, &start, &end);
191 EXPECT_EQ(cases[i].start, start);
192 EXPECT_EQ(cases[i].end, end);
193 PangoFontDescription* font = pango_font_description_new();
194 pango_attr_iterator_get_font(iter, font, NULL, NULL);
195 char* description_string = pango_font_description_to_string(font);
196 const base::string16 desc = ASCIIToUTF16(description_string);
197 const bool bold = desc.find(ASCIIToUTF16("Bold")) != std::string::npos;
198 EXPECT_EQ(cases[i].bold, bold);
199 const bool italic = desc.find(ASCIIToUTF16("Italic")) != std::string::npos;
200 EXPECT_EQ(cases[i].italic, italic);
201 pango_attr_iterator_next(iter);
202 pango_font_description_free(font);
203 g_free(description_string);
205 EXPECT_FALSE(pango_attr_iterator_next(iter));
206 pango_attr_iterator_destroy(iter);
208 #endif
210 // TODO(asvitkine): Cursor movements tests disabled on Mac because RenderTextMac
211 // does not implement this yet. http://crbug.com/131618
212 #if !defined(OS_MACOSX)
213 void TestVisualCursorMotionInObscuredField(RenderText* render_text,
214 const base::string16& text,
215 bool select) {
216 ASSERT_TRUE(render_text->obscured());
217 render_text->SetText(text);
218 int len = text.length();
219 render_text->MoveCursor(LINE_BREAK, CURSOR_RIGHT, select);
220 EXPECT_EQ(SelectionModel(ui::Range(select ? 0 : len, len), CURSOR_FORWARD),
221 render_text->selection_model());
222 render_text->MoveCursor(LINE_BREAK, CURSOR_LEFT, select);
223 EXPECT_EQ(SelectionModel(0, CURSOR_BACKWARD), render_text->selection_model());
224 for (int j = 1; j <= len; ++j) {
225 render_text->MoveCursor(CHARACTER_BREAK, CURSOR_RIGHT, select);
226 EXPECT_EQ(SelectionModel(ui::Range(select ? 0 : j, j), CURSOR_BACKWARD),
227 render_text->selection_model());
229 for (int j = len - 1; j >= 0; --j) {
230 render_text->MoveCursor(CHARACTER_BREAK, CURSOR_LEFT, select);
231 EXPECT_EQ(SelectionModel(ui::Range(select ? 0 : j, j), CURSOR_FORWARD),
232 render_text->selection_model());
234 render_text->MoveCursor(WORD_BREAK, CURSOR_RIGHT, select);
235 EXPECT_EQ(SelectionModel(ui::Range(select ? 0 : len, len), CURSOR_FORWARD),
236 render_text->selection_model());
237 render_text->MoveCursor(WORD_BREAK, CURSOR_LEFT, select);
238 EXPECT_EQ(SelectionModel(0, CURSOR_BACKWARD), render_text->selection_model());
241 TEST_F(RenderTextTest, ObscuredText) {
242 const base::string16 seuss = ASCIIToUTF16("hop on pop");
243 const base::string16 no_seuss = ASCIIToUTF16("**********");
244 scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
246 // GetLayoutText() returns asterisks when the obscured bit is set.
247 render_text->SetText(seuss);
248 render_text->SetObscured(true);
249 EXPECT_EQ(seuss, render_text->text());
250 EXPECT_EQ(no_seuss, render_text->GetLayoutText());
251 render_text->SetObscured(false);
252 EXPECT_EQ(seuss, render_text->text());
253 EXPECT_EQ(seuss, render_text->GetLayoutText());
255 render_text->SetObscured(true);
257 // Surrogate pairs are counted as one code point.
258 const char16 invalid_surrogates[] = {0xDC00, 0xD800, 0};
259 render_text->SetText(invalid_surrogates);
260 EXPECT_EQ(ASCIIToUTF16("**"), render_text->GetLayoutText());
261 const char16 valid_surrogates[] = {0xD800, 0xDC00, 0};
262 render_text->SetText(valid_surrogates);
263 EXPECT_EQ(ASCIIToUTF16("*"), render_text->GetLayoutText());
264 EXPECT_EQ(0U, render_text->cursor_position());
265 render_text->MoveCursor(CHARACTER_BREAK, CURSOR_RIGHT, false);
266 EXPECT_EQ(2U, render_text->cursor_position());
268 // Test index conversion and cursor validity with a valid surrogate pair.
269 EXPECT_EQ(0U, render_text->TextIndexToLayoutIndex(0U));
270 EXPECT_EQ(1U, render_text->TextIndexToLayoutIndex(1U));
271 EXPECT_EQ(1U, render_text->TextIndexToLayoutIndex(2U));
272 EXPECT_EQ(0U, render_text->LayoutIndexToTextIndex(0U));
273 EXPECT_EQ(2U, render_text->LayoutIndexToTextIndex(1U));
274 EXPECT_TRUE(render_text->IsCursorablePosition(0U));
275 EXPECT_FALSE(render_text->IsCursorablePosition(1U));
276 EXPECT_TRUE(render_text->IsCursorablePosition(2U));
278 // FindCursorPosition() should not return positions between a surrogate pair.
279 render_text->SetDisplayRect(Rect(0, 0, 20, 20));
280 EXPECT_EQ(render_text->FindCursorPosition(Point(0, 0)).caret_pos(), 0U);
281 EXPECT_EQ(render_text->FindCursorPosition(Point(20, 0)).caret_pos(), 2U);
282 for (int x = -1; x <= 20; ++x) {
283 SelectionModel selection = render_text->FindCursorPosition(Point(x, 0));
284 EXPECT_TRUE(selection.caret_pos() == 0U || selection.caret_pos() == 2U);
287 // GetGlyphBounds() should yield the entire string bounds for text index 0.
288 EXPECT_EQ(render_text->GetStringSize().width(),
289 static_cast<int>(render_text->GetGlyphBounds(0U).length()));
291 // Cursoring is independent of underlying characters when text is obscured.
292 const wchar_t* const texts[] = {
293 kWeak, kLtr, kLtrRtl, kLtrRtlLtr, kRtl, kRtlLtr, kRtlLtrRtl,
294 L"hop on pop", // Check LTR word boundaries.
295 L"\x05d0\x05d1 \x05d0\x05d2 \x05d1\x05d2", // Check RTL word boundaries.
297 for (size_t i = 0; i < arraysize(texts); ++i) {
298 base::string16 text = WideToUTF16(texts[i]);
299 TestVisualCursorMotionInObscuredField(render_text.get(), text, false);
300 TestVisualCursorMotionInObscuredField(render_text.get(), text, true);
304 TEST_F(RenderTextTest, RevealObscuredText) {
305 const base::string16 seuss = ASCIIToUTF16("hop on pop");
306 const base::string16 no_seuss = ASCIIToUTF16("**********");
307 scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
309 render_text->SetText(seuss);
310 render_text->SetObscured(true);
311 EXPECT_EQ(seuss, render_text->text());
312 EXPECT_EQ(no_seuss, render_text->GetLayoutText());
314 // Valid reveal index and new revealed index clears previous one.
315 render_text->RenderText::SetObscuredRevealIndex(0);
316 EXPECT_EQ(ASCIIToUTF16("h*********"), render_text->GetLayoutText());
317 render_text->RenderText::SetObscuredRevealIndex(1);
318 EXPECT_EQ(ASCIIToUTF16("*o********"), render_text->GetLayoutText());
319 render_text->RenderText::SetObscuredRevealIndex(2);
320 EXPECT_EQ(ASCIIToUTF16("**p*******"), render_text->GetLayoutText());
322 // Invalid reveal index.
323 render_text->RenderText::SetObscuredRevealIndex(-1);
324 EXPECT_EQ(no_seuss, render_text->GetLayoutText());
325 render_text->RenderText::SetObscuredRevealIndex(seuss.length() + 1);
326 EXPECT_EQ(no_seuss, render_text->GetLayoutText());
328 // SetObscured clears the revealed index.
329 render_text->RenderText::SetObscuredRevealIndex(0);
330 EXPECT_EQ(ASCIIToUTF16("h*********"), render_text->GetLayoutText());
331 render_text->SetObscured(false);
332 EXPECT_EQ(seuss, render_text->GetLayoutText());
333 render_text->SetObscured(true);
334 EXPECT_EQ(no_seuss, render_text->GetLayoutText());
336 // SetText clears the revealed index.
337 render_text->SetText(ASCIIToUTF16("new"));
338 EXPECT_EQ(ASCIIToUTF16("***"), render_text->GetLayoutText());
339 render_text->RenderText::SetObscuredRevealIndex(2);
340 EXPECT_EQ(ASCIIToUTF16("**w"), render_text->GetLayoutText());
341 render_text->SetText(ASCIIToUTF16("new longer"));
342 EXPECT_EQ(ASCIIToUTF16("**********"), render_text->GetLayoutText());
344 // Text with invalid surrogates.
345 const char16 invalid_surrogates[] = {0xDC00, 0xD800, 'h', 'o', 'p', 0};
346 render_text->SetText(invalid_surrogates);
347 EXPECT_EQ(ASCIIToUTF16("*****"), render_text->GetLayoutText());
348 render_text->RenderText::SetObscuredRevealIndex(0);
349 const char16 invalid_expect_0[] = {0xDC00, '*', '*', '*', '*', 0};
350 EXPECT_EQ(invalid_expect_0, render_text->GetLayoutText());
351 render_text->RenderText::SetObscuredRevealIndex(1);
352 const char16 invalid_expect_1[] = {'*', 0xD800, '*', '*', '*', 0};
353 EXPECT_EQ(invalid_expect_1, render_text->GetLayoutText());
354 render_text->RenderText::SetObscuredRevealIndex(2);
355 EXPECT_EQ(ASCIIToUTF16("**h**"), render_text->GetLayoutText());
357 // Text with valid surrogates before and after the reveal index.
358 const char16 valid_surrogates[] =
359 {0xD800, 0xDC00, 'h', 'o', 'p', 0xD800, 0xDC00, 0};
360 render_text->SetText(valid_surrogates);
361 EXPECT_EQ(ASCIIToUTF16("*****"), render_text->GetLayoutText());
362 render_text->RenderText::SetObscuredRevealIndex(0);
363 const char16 valid_expect_0_and_1[] = {0xD800, 0xDC00, '*', '*', '*', '*', 0};
364 EXPECT_EQ(valid_expect_0_and_1, render_text->GetLayoutText());
365 render_text->RenderText::SetObscuredRevealIndex(1);
366 EXPECT_EQ(valid_expect_0_and_1, render_text->GetLayoutText());
367 render_text->RenderText::SetObscuredRevealIndex(2);
368 EXPECT_EQ(ASCIIToUTF16("*h***"), render_text->GetLayoutText());
369 render_text->RenderText::SetObscuredRevealIndex(5);
370 const char16 valid_expect_5_and_6[] = {'*', '*', '*', '*', 0xD800, 0xDC00, 0};
371 EXPECT_EQ(valid_expect_5_and_6, render_text->GetLayoutText());
372 render_text->RenderText::SetObscuredRevealIndex(6);
373 EXPECT_EQ(valid_expect_5_and_6, render_text->GetLayoutText());
376 TEST_F(RenderTextTest, GetTextDirection) {
377 struct {
378 const wchar_t* text;
379 const base::i18n::TextDirection text_direction;
380 } cases[] = {
381 // Blank strings and those with no/weak directionality default to LTR.
382 { L"", base::i18n::LEFT_TO_RIGHT },
383 { kWeak, base::i18n::LEFT_TO_RIGHT },
384 // Strings that begin with strong LTR characters.
385 { kLtr, base::i18n::LEFT_TO_RIGHT },
386 { kLtrRtl, base::i18n::LEFT_TO_RIGHT },
387 { kLtrRtlLtr, base::i18n::LEFT_TO_RIGHT },
388 // Strings that begin with strong RTL characters.
389 { kRtl, base::i18n::RIGHT_TO_LEFT },
390 { kRtlLtr, base::i18n::RIGHT_TO_LEFT },
391 { kRtlLtrRtl, base::i18n::RIGHT_TO_LEFT },
394 scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
395 const bool was_rtl = base::i18n::IsRTL();
397 for (size_t i = 0; i < 2; ++i) {
398 // Toggle the application default text direction (to try each direction).
399 SetRTL(!base::i18n::IsRTL());
400 const base::i18n::TextDirection ui_direction = base::i18n::IsRTL() ?
401 base::i18n::RIGHT_TO_LEFT : base::i18n::LEFT_TO_RIGHT;
403 // Ensure that directionality modes yield the correct text directions.
404 for (size_t j = 0; j < ARRAYSIZE_UNSAFE(cases); j++) {
405 render_text->SetText(WideToUTF16(cases[j].text));
406 render_text->SetDirectionalityMode(DIRECTIONALITY_FROM_TEXT);
407 EXPECT_EQ(render_text->GetTextDirection(), cases[j].text_direction);
408 render_text->SetDirectionalityMode(DIRECTIONALITY_FROM_UI);
409 EXPECT_EQ(render_text->GetTextDirection(), ui_direction);
410 render_text->SetDirectionalityMode(DIRECTIONALITY_FORCE_LTR);
411 EXPECT_EQ(render_text->GetTextDirection(), base::i18n::LEFT_TO_RIGHT);
412 render_text->SetDirectionalityMode(DIRECTIONALITY_FORCE_RTL);
413 EXPECT_EQ(render_text->GetTextDirection(), base::i18n::RIGHT_TO_LEFT);
417 EXPECT_EQ(was_rtl, base::i18n::IsRTL());
419 // Ensure that text changes update the direction for DIRECTIONALITY_FROM_TEXT.
420 render_text->SetDirectionalityMode(DIRECTIONALITY_FROM_TEXT);
421 render_text->SetText(WideToUTF16(kLtr));
422 EXPECT_EQ(render_text->GetTextDirection(), base::i18n::LEFT_TO_RIGHT);
423 render_text->SetText(WideToUTF16(kRtl));
424 EXPECT_EQ(render_text->GetTextDirection(), base::i18n::RIGHT_TO_LEFT);
427 void RunMoveCursorLeftRightTest(RenderText* render_text,
428 const std::vector<SelectionModel>& expected,
429 VisualCursorDirection direction) {
430 for (size_t i = 0; i < expected.size(); ++i) {
431 EXPECT_EQ(expected[i], render_text->selection_model());
432 render_text->MoveCursor(CHARACTER_BREAK, direction, false);
434 // Check that cursoring is clamped at the line edge.
435 EXPECT_EQ(expected.back(), render_text->selection_model());
436 // Check that it is the line edge.
437 render_text->MoveCursor(LINE_BREAK, direction, false);
438 EXPECT_EQ(expected.back(), render_text->selection_model());
441 TEST_F(RenderTextTest, MoveCursorLeftRightInLtr) {
442 scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
444 // Pure LTR.
445 render_text->SetText(ASCIIToUTF16("abc"));
446 // |expected| saves the expected SelectionModel when moving cursor from left
447 // to right.
448 std::vector<SelectionModel> expected;
449 expected.push_back(SelectionModel(0, CURSOR_BACKWARD));
450 expected.push_back(SelectionModel(1, CURSOR_BACKWARD));
451 expected.push_back(SelectionModel(2, CURSOR_BACKWARD));
452 expected.push_back(SelectionModel(3, CURSOR_BACKWARD));
453 expected.push_back(SelectionModel(3, CURSOR_FORWARD));
454 RunMoveCursorLeftRightTest(render_text.get(), expected, CURSOR_RIGHT);
456 expected.clear();
457 expected.push_back(SelectionModel(3, CURSOR_FORWARD));
458 expected.push_back(SelectionModel(2, CURSOR_FORWARD));
459 expected.push_back(SelectionModel(1, CURSOR_FORWARD));
460 expected.push_back(SelectionModel(0, CURSOR_FORWARD));
461 expected.push_back(SelectionModel(0, CURSOR_BACKWARD));
462 RunMoveCursorLeftRightTest(render_text.get(), expected, CURSOR_LEFT);
465 TEST_F(RenderTextTest, MoveCursorLeftRightInLtrRtl) {
466 scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
467 // LTR-RTL
468 render_text->SetText(WideToUTF16(L"abc\x05d0\x05d1\x05d2"));
469 // The last one is the expected END position.
470 std::vector<SelectionModel> expected;
471 expected.push_back(SelectionModel(0, CURSOR_BACKWARD));
472 expected.push_back(SelectionModel(1, CURSOR_BACKWARD));
473 expected.push_back(SelectionModel(2, CURSOR_BACKWARD));
474 expected.push_back(SelectionModel(3, CURSOR_BACKWARD));
475 expected.push_back(SelectionModel(5, CURSOR_FORWARD));
476 expected.push_back(SelectionModel(4, CURSOR_FORWARD));
477 expected.push_back(SelectionModel(3, CURSOR_FORWARD));
478 expected.push_back(SelectionModel(6, CURSOR_FORWARD));
479 RunMoveCursorLeftRightTest(render_text.get(), expected, CURSOR_RIGHT);
481 expected.clear();
482 expected.push_back(SelectionModel(6, CURSOR_FORWARD));
483 expected.push_back(SelectionModel(4, CURSOR_BACKWARD));
484 expected.push_back(SelectionModel(5, CURSOR_BACKWARD));
485 expected.push_back(SelectionModel(6, CURSOR_BACKWARD));
486 expected.push_back(SelectionModel(2, CURSOR_FORWARD));
487 expected.push_back(SelectionModel(1, CURSOR_FORWARD));
488 expected.push_back(SelectionModel(0, CURSOR_FORWARD));
489 expected.push_back(SelectionModel(0, CURSOR_BACKWARD));
490 RunMoveCursorLeftRightTest(render_text.get(), expected, CURSOR_LEFT);
493 TEST_F(RenderTextTest, MoveCursorLeftRightInLtrRtlLtr) {
494 scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
495 // LTR-RTL-LTR.
496 render_text->SetText(WideToUTF16(L"a"L"\x05d1"L"b"));
497 std::vector<SelectionModel> expected;
498 expected.push_back(SelectionModel(0, CURSOR_BACKWARD));
499 expected.push_back(SelectionModel(1, CURSOR_BACKWARD));
500 expected.push_back(SelectionModel(1, CURSOR_FORWARD));
501 expected.push_back(SelectionModel(3, CURSOR_BACKWARD));
502 expected.push_back(SelectionModel(3, CURSOR_FORWARD));
503 RunMoveCursorLeftRightTest(render_text.get(), expected, CURSOR_RIGHT);
505 expected.clear();
506 expected.push_back(SelectionModel(3, CURSOR_FORWARD));
507 expected.push_back(SelectionModel(2, CURSOR_FORWARD));
508 expected.push_back(SelectionModel(2, CURSOR_BACKWARD));
509 expected.push_back(SelectionModel(0, CURSOR_FORWARD));
510 expected.push_back(SelectionModel(0, CURSOR_BACKWARD));
511 RunMoveCursorLeftRightTest(render_text.get(), expected, CURSOR_LEFT);
514 TEST_F(RenderTextTest, MoveCursorLeftRightInRtl) {
515 scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
516 // Pure RTL.
517 render_text->SetText(WideToUTF16(L"\x05d0\x05d1\x05d2"));
518 render_text->MoveCursor(LINE_BREAK, CURSOR_RIGHT, false);
519 std::vector<SelectionModel> expected;
521 expected.push_back(SelectionModel(0, CURSOR_BACKWARD));
522 expected.push_back(SelectionModel(1, CURSOR_BACKWARD));
523 expected.push_back(SelectionModel(2, CURSOR_BACKWARD));
524 expected.push_back(SelectionModel(3, CURSOR_BACKWARD));
525 expected.push_back(SelectionModel(3, CURSOR_FORWARD));
526 RunMoveCursorLeftRightTest(render_text.get(), expected, CURSOR_LEFT);
528 expected.clear();
530 expected.push_back(SelectionModel(3, CURSOR_FORWARD));
531 expected.push_back(SelectionModel(2, CURSOR_FORWARD));
532 expected.push_back(SelectionModel(1, CURSOR_FORWARD));
533 expected.push_back(SelectionModel(0, CURSOR_FORWARD));
534 expected.push_back(SelectionModel(0, CURSOR_BACKWARD));
535 RunMoveCursorLeftRightTest(render_text.get(), expected, CURSOR_RIGHT);
538 TEST_F(RenderTextTest, MoveCursorLeftRightInRtlLtr) {
539 scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
540 // RTL-LTR
541 render_text->SetText(WideToUTF16(L"\x05d0\x05d1\x05d2"L"abc"));
542 render_text->MoveCursor(LINE_BREAK, CURSOR_RIGHT, false);
543 std::vector<SelectionModel> expected;
544 expected.push_back(SelectionModel(0, CURSOR_BACKWARD));
545 expected.push_back(SelectionModel(1, CURSOR_BACKWARD));
546 expected.push_back(SelectionModel(2, CURSOR_BACKWARD));
547 expected.push_back(SelectionModel(3, CURSOR_BACKWARD));
548 expected.push_back(SelectionModel(5, CURSOR_FORWARD));
549 expected.push_back(SelectionModel(4, CURSOR_FORWARD));
550 expected.push_back(SelectionModel(3, CURSOR_FORWARD));
551 expected.push_back(SelectionModel(6, CURSOR_FORWARD));
552 RunMoveCursorLeftRightTest(render_text.get(), expected, CURSOR_LEFT);
554 expected.clear();
555 expected.push_back(SelectionModel(6, CURSOR_FORWARD));
556 expected.push_back(SelectionModel(4, CURSOR_BACKWARD));
557 expected.push_back(SelectionModel(5, CURSOR_BACKWARD));
558 expected.push_back(SelectionModel(6, CURSOR_BACKWARD));
559 expected.push_back(SelectionModel(2, CURSOR_FORWARD));
560 expected.push_back(SelectionModel(1, CURSOR_FORWARD));
561 expected.push_back(SelectionModel(0, CURSOR_FORWARD));
562 expected.push_back(SelectionModel(0, CURSOR_BACKWARD));
563 RunMoveCursorLeftRightTest(render_text.get(), expected, CURSOR_RIGHT);
566 TEST_F(RenderTextTest, MoveCursorLeftRightInRtlLtrRtl) {
567 scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
568 // RTL-LTR-RTL.
569 render_text->SetText(WideToUTF16(L"\x05d0"L"a"L"\x05d1"));
570 render_text->MoveCursor(LINE_BREAK, CURSOR_RIGHT, false);
571 std::vector<SelectionModel> expected;
572 expected.push_back(SelectionModel(0, CURSOR_BACKWARD));
573 expected.push_back(SelectionModel(1, CURSOR_BACKWARD));
574 expected.push_back(SelectionModel(1, CURSOR_FORWARD));
575 expected.push_back(SelectionModel(3, CURSOR_BACKWARD));
576 expected.push_back(SelectionModel(3, CURSOR_FORWARD));
577 RunMoveCursorLeftRightTest(render_text.get(), expected, CURSOR_LEFT);
579 expected.clear();
580 expected.push_back(SelectionModel(3, CURSOR_FORWARD));
581 expected.push_back(SelectionModel(2, CURSOR_FORWARD));
582 expected.push_back(SelectionModel(2, CURSOR_BACKWARD));
583 expected.push_back(SelectionModel(0, CURSOR_FORWARD));
584 expected.push_back(SelectionModel(0, CURSOR_BACKWARD));
585 RunMoveCursorLeftRightTest(render_text.get(), expected, CURSOR_RIGHT);
588 // TODO(xji): temporarily disable in platform Win since the complex script
589 // characters turned into empty square due to font regression. So, not able
590 // to test 2 characters belong to the same grapheme.
591 #if defined(OS_LINUX)
592 TEST_F(RenderTextTest, MoveCursorLeftRight_ComplexScript) {
593 scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
595 render_text->SetText(WideToUTF16(L"\x0915\x093f\x0915\x094d\x0915"));
596 EXPECT_EQ(0U, render_text->cursor_position());
597 render_text->MoveCursor(CHARACTER_BREAK, CURSOR_RIGHT, false);
598 EXPECT_EQ(2U, render_text->cursor_position());
599 render_text->MoveCursor(CHARACTER_BREAK, CURSOR_RIGHT, false);
600 EXPECT_EQ(4U, render_text->cursor_position());
601 render_text->MoveCursor(CHARACTER_BREAK, CURSOR_RIGHT, false);
602 EXPECT_EQ(5U, render_text->cursor_position());
603 render_text->MoveCursor(CHARACTER_BREAK, CURSOR_RIGHT, false);
604 EXPECT_EQ(5U, render_text->cursor_position());
606 render_text->MoveCursor(CHARACTER_BREAK, CURSOR_LEFT, false);
607 EXPECT_EQ(4U, render_text->cursor_position());
608 render_text->MoveCursor(CHARACTER_BREAK, CURSOR_LEFT, false);
609 EXPECT_EQ(2U, render_text->cursor_position());
610 render_text->MoveCursor(CHARACTER_BREAK, CURSOR_LEFT, false);
611 EXPECT_EQ(0U, render_text->cursor_position());
612 render_text->MoveCursor(CHARACTER_BREAK, CURSOR_LEFT, false);
613 EXPECT_EQ(0U, render_text->cursor_position());
615 #endif
617 TEST_F(RenderTextTest, MoveCursorLeftRight_MeiryoUILigatures) {
618 scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
619 // Meiryo UI uses single-glyph ligatures for 'ff' and 'ffi', but each letter
620 // (code point) has unique bounds, so mid-glyph cursoring should be possible.
621 render_text->SetFont(Font("Meiryo UI", 12));
622 render_text->SetText(WideToUTF16(L"ff ffi"));
623 EXPECT_EQ(0U, render_text->cursor_position());
624 for (size_t i = 0; i < render_text->text().length(); ++i) {
625 render_text->MoveCursor(CHARACTER_BREAK, CURSOR_RIGHT, false);
626 EXPECT_EQ(i + 1, render_text->cursor_position());
628 EXPECT_EQ(6U, render_text->cursor_position());
631 TEST_F(RenderTextTest, GraphemePositions) {
632 // LTR 2-character grapheme, LTR abc, LTR 2-character grapheme.
633 const base::string16 kText1 =
634 WideToUTF16(L"\x0915\x093f"L"abc"L"\x0915\x093f");
636 // LTR ab, LTR 2-character grapheme, LTR cd.
637 const base::string16 kText2 = WideToUTF16(L"ab"L"\x0915\x093f"L"cd");
639 // The below is 'MUSICAL SYMBOL G CLEF', which is represented in UTF-16 as
640 // two characters forming the surrogate pair 0x0001D11E.
641 const std::string kSurrogate = "\xF0\x9D\x84\x9E";
643 // LTR ab, UTF16 surrogate pair, LTR cd.
644 const base::string16 kText3 = UTF8ToUTF16("ab" + kSurrogate + "cd");
646 struct {
647 base::string16 text;
648 size_t index;
649 size_t expected_previous;
650 size_t expected_next;
651 } cases[] = {
652 { base::string16(), 0, 0, 0 },
653 { base::string16(), 1, 0, 0 },
654 { base::string16(), 50, 0, 0 },
655 { kText1, 0, 0, 2 },
656 { kText1, 1, 0, 2 },
657 { kText1, 2, 0, 3 },
658 { kText1, 3, 2, 4 },
659 { kText1, 4, 3, 5 },
660 { kText1, 5, 4, 7 },
661 { kText1, 6, 5, 7 },
662 { kText1, 7, 5, 7 },
663 { kText1, 8, 7, 7 },
664 { kText1, 50, 7, 7 },
665 { kText2, 0, 0, 1 },
666 { kText2, 1, 0, 2 },
667 { kText2, 2, 1, 4 },
668 { kText2, 3, 2, 4 },
669 { kText2, 4, 2, 5 },
670 { kText2, 5, 4, 6 },
671 { kText2, 6, 5, 6 },
672 { kText2, 7, 6, 6 },
673 { kText2, 50, 6, 6 },
674 { kText3, 0, 0, 1 },
675 { kText3, 1, 0, 2 },
676 { kText3, 2, 1, 4 },
677 { kText3, 3, 2, 4 },
678 { kText3, 4, 2, 5 },
679 { kText3, 5, 4, 6 },
680 { kText3, 6, 5, 6 },
681 { kText3, 7, 6, 6 },
682 { kText3, 50, 6, 6 },
685 // TODO(asvitkine): Disable tests that fail on XP bots due to lack of complete
686 // font support for some scripts - http://crbug.com/106450
687 #if defined(OS_WIN)
688 if (base::win::GetVersion() < base::win::VERSION_VISTA)
689 return;
690 #endif
692 scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
693 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) {
694 render_text->SetText(cases[i].text);
696 size_t next = render_text->IndexOfAdjacentGrapheme(cases[i].index,
697 CURSOR_FORWARD);
698 EXPECT_EQ(cases[i].expected_next, next);
699 EXPECT_TRUE(render_text->IsCursorablePosition(next));
701 size_t previous = render_text->IndexOfAdjacentGrapheme(cases[i].index,
702 CURSOR_BACKWARD);
703 EXPECT_EQ(cases[i].expected_previous, previous);
704 EXPECT_TRUE(render_text->IsCursorablePosition(previous));
708 TEST_F(RenderTextTest, EdgeSelectionModels) {
709 // Simple Latin text.
710 const base::string16 kLatin = WideToUTF16(L"abc");
711 // LTR 2-character grapheme.
712 const base::string16 kLTRGrapheme = WideToUTF16(L"\x0915\x093f");
713 // LTR 2-character grapheme, LTR a, LTR 2-character grapheme.
714 const base::string16 kHindiLatin =
715 WideToUTF16(L"\x0915\x093f"L"a"L"\x0915\x093f");
716 // RTL 2-character grapheme.
717 const base::string16 kRTLGrapheme = WideToUTF16(L"\x05e0\x05b8");
718 // RTL 2-character grapheme, LTR a, RTL 2-character grapheme.
719 const base::string16 kHebrewLatin =
720 WideToUTF16(L"\x05e0\x05b8"L"a"L"\x05e0\x05b8");
722 struct {
723 base::string16 text;
724 base::i18n::TextDirection expected_text_direction;
725 } cases[] = {
726 { base::string16(), base::i18n::LEFT_TO_RIGHT },
727 { kLatin, base::i18n::LEFT_TO_RIGHT },
728 { kLTRGrapheme, base::i18n::LEFT_TO_RIGHT },
729 { kHindiLatin, base::i18n::LEFT_TO_RIGHT },
730 { kRTLGrapheme, base::i18n::RIGHT_TO_LEFT },
731 { kHebrewLatin, base::i18n::RIGHT_TO_LEFT },
734 // TODO(asvitkine): Disable tests that fail on XP bots due to lack of complete
735 // font support for some scripts - http://crbug.com/106450
736 #if defined(OS_WIN)
737 if (base::win::GetVersion() < base::win::VERSION_VISTA)
738 return;
739 #endif
741 scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
742 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) {
743 render_text->SetText(cases[i].text);
744 bool ltr = (cases[i].expected_text_direction == base::i18n::LEFT_TO_RIGHT);
746 SelectionModel start_edge =
747 render_text->EdgeSelectionModel(ltr ? CURSOR_LEFT : CURSOR_RIGHT);
748 EXPECT_EQ(start_edge, SelectionModel(0, CURSOR_BACKWARD));
750 SelectionModel end_edge =
751 render_text->EdgeSelectionModel(ltr ? CURSOR_RIGHT : CURSOR_LEFT);
752 EXPECT_EQ(end_edge, SelectionModel(cases[i].text.length(), CURSOR_FORWARD));
756 TEST_F(RenderTextTest, SelectAll) {
757 const wchar_t* const cases[] =
758 { kWeak, kLtr, kLtrRtl, kLtrRtlLtr, kRtl, kRtlLtr, kRtlLtrRtl };
760 // Ensure that SelectAll respects the |reversed| argument regardless of
761 // application locale and text content directionality.
762 scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
763 const SelectionModel expected_reversed(ui::Range(3, 0), CURSOR_FORWARD);
764 const SelectionModel expected_forwards(ui::Range(0, 3), CURSOR_BACKWARD);
765 const bool was_rtl = base::i18n::IsRTL();
767 for (size_t i = 0; i < 2; ++i) {
768 SetRTL(!base::i18n::IsRTL());
769 // Test that an empty string produces an empty selection model.
770 render_text->SetText(base::string16());
771 EXPECT_EQ(render_text->selection_model(), SelectionModel());
773 // Test the weak, LTR, RTL, and Bidi string cases.
774 for (size_t j = 0; j < ARRAYSIZE_UNSAFE(cases); j++) {
775 render_text->SetText(WideToUTF16(cases[j]));
776 render_text->SelectAll(false);
777 EXPECT_EQ(render_text->selection_model(), expected_forwards);
778 render_text->SelectAll(true);
779 EXPECT_EQ(render_text->selection_model(), expected_reversed);
783 EXPECT_EQ(was_rtl, base::i18n::IsRTL());
786 TEST_F(RenderTextTest, MoveCursorLeftRightWithSelection) {
787 scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
788 render_text->SetText(WideToUTF16(L"abc\x05d0\x05d1\x05d2"));
789 // Left arrow on select ranging (6, 4).
790 render_text->MoveCursor(LINE_BREAK, CURSOR_RIGHT, false);
791 EXPECT_EQ(ui::Range(6), render_text->selection());
792 render_text->MoveCursor(CHARACTER_BREAK, CURSOR_LEFT, false);
793 EXPECT_EQ(ui::Range(4), render_text->selection());
794 render_text->MoveCursor(CHARACTER_BREAK, CURSOR_LEFT, false);
795 EXPECT_EQ(ui::Range(5), render_text->selection());
796 render_text->MoveCursor(CHARACTER_BREAK, CURSOR_LEFT, false);
797 EXPECT_EQ(ui::Range(6), render_text->selection());
798 render_text->MoveCursor(CHARACTER_BREAK, CURSOR_RIGHT, true);
799 EXPECT_EQ(ui::Range(6, 5), render_text->selection());
800 render_text->MoveCursor(CHARACTER_BREAK, CURSOR_RIGHT, true);
801 EXPECT_EQ(ui::Range(6, 4), render_text->selection());
802 render_text->MoveCursor(CHARACTER_BREAK, CURSOR_LEFT, false);
803 EXPECT_EQ(ui::Range(6), render_text->selection());
805 // Right arrow on select ranging (4, 6).
806 render_text->MoveCursor(LINE_BREAK, CURSOR_LEFT, false);
807 EXPECT_EQ(ui::Range(0), render_text->selection());
808 render_text->MoveCursor(CHARACTER_BREAK, CURSOR_RIGHT, false);
809 EXPECT_EQ(ui::Range(1), render_text->selection());
810 render_text->MoveCursor(CHARACTER_BREAK, CURSOR_RIGHT, false);
811 EXPECT_EQ(ui::Range(2), render_text->selection());
812 render_text->MoveCursor(CHARACTER_BREAK, CURSOR_RIGHT, false);
813 EXPECT_EQ(ui::Range(3), render_text->selection());
814 render_text->MoveCursor(CHARACTER_BREAK, CURSOR_RIGHT, false);
815 EXPECT_EQ(ui::Range(5), render_text->selection());
816 render_text->MoveCursor(CHARACTER_BREAK, CURSOR_RIGHT, false);
817 EXPECT_EQ(ui::Range(4), render_text->selection());
818 render_text->MoveCursor(CHARACTER_BREAK, CURSOR_LEFT, true);
819 EXPECT_EQ(ui::Range(4, 5), render_text->selection());
820 render_text->MoveCursor(CHARACTER_BREAK, CURSOR_LEFT, true);
821 EXPECT_EQ(ui::Range(4, 6), render_text->selection());
822 render_text->MoveCursor(CHARACTER_BREAK, CURSOR_RIGHT, false);
823 EXPECT_EQ(ui::Range(4), render_text->selection());
825 #endif // !defined(OS_MACOSX)
827 // TODO(xji): Make these work on Windows.
828 #if defined(OS_LINUX)
829 void MoveLeftRightByWordVerifier(RenderText* render_text,
830 const wchar_t* str) {
831 render_text->SetText(WideToUTF16(str));
833 // Test moving by word from left ro right.
834 render_text->MoveCursor(LINE_BREAK, CURSOR_LEFT, false);
835 bool first_word = true;
836 while (true) {
837 // First, test moving by word from a word break position, such as from
838 // "|abc def" to "abc| def".
839 SelectionModel start = render_text->selection_model();
840 render_text->MoveCursor(WORD_BREAK, CURSOR_RIGHT, false);
841 SelectionModel end = render_text->selection_model();
842 if (end == start) // reach the end.
843 break;
845 // For testing simplicity, each word is a 3-character word.
846 int num_of_character_moves = first_word ? 3 : 4;
847 first_word = false;
848 render_text->MoveCursorTo(start);
849 for (int j = 0; j < num_of_character_moves; ++j)
850 render_text->MoveCursor(CHARACTER_BREAK, CURSOR_RIGHT, false);
851 EXPECT_EQ(end, render_text->selection_model());
853 // Then, test moving by word from positions inside the word, such as from
854 // "a|bc def" to "abc| def", and from "ab|c def" to "abc| def".
855 for (int j = 1; j < num_of_character_moves; ++j) {
856 render_text->MoveCursorTo(start);
857 for (int k = 0; k < j; ++k)
858 render_text->MoveCursor(CHARACTER_BREAK, CURSOR_RIGHT, false);
859 render_text->MoveCursor(WORD_BREAK, CURSOR_RIGHT, false);
860 EXPECT_EQ(end, render_text->selection_model());
864 // Test moving by word from right to left.
865 render_text->MoveCursor(LINE_BREAK, CURSOR_RIGHT, false);
866 first_word = true;
867 while (true) {
868 SelectionModel start = render_text->selection_model();
869 render_text->MoveCursor(WORD_BREAK, CURSOR_LEFT, false);
870 SelectionModel end = render_text->selection_model();
871 if (end == start) // reach the end.
872 break;
874 int num_of_character_moves = first_word ? 3 : 4;
875 first_word = false;
876 render_text->MoveCursorTo(start);
877 for (int j = 0; j < num_of_character_moves; ++j)
878 render_text->MoveCursor(CHARACTER_BREAK, CURSOR_LEFT, false);
879 EXPECT_EQ(end, render_text->selection_model());
881 for (int j = 1; j < num_of_character_moves; ++j) {
882 render_text->MoveCursorTo(start);
883 for (int k = 0; k < j; ++k)
884 render_text->MoveCursor(CHARACTER_BREAK, CURSOR_LEFT, false);
885 render_text->MoveCursor(WORD_BREAK, CURSOR_LEFT, false);
886 EXPECT_EQ(end, render_text->selection_model());
891 TEST_F(RenderTextTest, MoveLeftRightByWordInBidiText) {
892 scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
894 // For testing simplicity, each word is a 3-character word.
895 std::vector<const wchar_t*> test;
896 test.push_back(L"abc");
897 test.push_back(L"abc def");
898 test.push_back(L"\x05E1\x05E2\x05E3");
899 test.push_back(L"\x05E1\x05E2\x05E3 \x05E4\x05E5\x05E6");
900 test.push_back(L"abc \x05E1\x05E2\x05E3");
901 test.push_back(L"abc def \x05E1\x05E2\x05E3 \x05E4\x05E5\x05E6");
902 test.push_back(L"abc def hij \x05E1\x05E2\x05E3 \x05E4\x05E5\x05E6"
903 L" \x05E7\x05E8\x05E9");
905 test.push_back(L"abc \x05E1\x05E2\x05E3 hij");
906 test.push_back(L"abc def \x05E1\x05E2\x05E3 \x05E4\x05E5\x05E6 hij opq");
907 test.push_back(L"abc def hij \x05E1\x05E2\x05E3 \x05E4\x05E5\x05E6"
908 L" \x05E7\x05E8\x05E9"L" opq rst uvw");
910 test.push_back(L"\x05E1\x05E2\x05E3 abc");
911 test.push_back(L"\x05E1\x05E2\x05E3 \x05E4\x05E5\x05E6 abc def");
912 test.push_back(L"\x05E1\x05E2\x05E3 \x05E4\x05E5\x05E6 \x05E7\x05E8\x05E9"
913 L" abc def hij");
915 test.push_back(L"\x05D1\x05D2\x05D3 abc \x05E1\x05E2\x05E3");
916 test.push_back(L"\x05D1\x05D2\x05D3 \x05D4\x05D5\x05D6 abc def"
917 L" \x05E1\x05E2\x05E3 \x05E4\x05E5\x05E6");
918 test.push_back(L"\x05D1\x05D2\x05D3 \x05D4\x05D5\x05D6 \x05D7\x05D8\x05D9"
919 L" abc def hij \x05E1\x05E2\x05E3 \x05E4\x05E5\x05E6"
920 L" \x05E7\x05E8\x05E9");
922 for (size_t i = 0; i < test.size(); ++i)
923 MoveLeftRightByWordVerifier(render_text.get(), test[i]);
926 TEST_F(RenderTextTest, MoveLeftRightByWordInBidiText_TestEndOfText) {
927 scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
929 render_text->SetText(WideToUTF16(L"ab\x05E1"));
930 // Moving the cursor by word from "abC|" to the left should return "|abC".
931 // But since end of text is always treated as a word break, it returns
932 // position "ab|C".
933 // TODO(xji): Need to make it work as expected.
934 render_text->MoveCursor(LINE_BREAK, CURSOR_RIGHT, false);
935 render_text->MoveCursor(WORD_BREAK, CURSOR_LEFT, false);
936 // EXPECT_EQ(SelectionModel(), render_text->selection_model());
938 // Moving the cursor by word from "|abC" to the right returns "abC|".
939 render_text->MoveCursor(LINE_BREAK, CURSOR_LEFT, false);
940 render_text->MoveCursor(WORD_BREAK, CURSOR_RIGHT, false);
941 EXPECT_EQ(SelectionModel(3, CURSOR_FORWARD), render_text->selection_model());
943 render_text->SetText(WideToUTF16(L"\x05E1\x05E2"L"a"));
944 // For logical text "BCa", moving the cursor by word from "aCB|" to the left
945 // returns "|aCB".
946 render_text->MoveCursor(LINE_BREAK, CURSOR_RIGHT, false);
947 render_text->MoveCursor(WORD_BREAK, CURSOR_LEFT, false);
948 EXPECT_EQ(SelectionModel(3, CURSOR_FORWARD), render_text->selection_model());
950 // Moving the cursor by word from "|aCB" to the right should return "aCB|".
951 // But since end of text is always treated as a word break, it returns
952 // position "a|CB".
953 // TODO(xji): Need to make it work as expected.
954 render_text->MoveCursor(LINE_BREAK, CURSOR_LEFT, false);
955 render_text->MoveCursor(WORD_BREAK, CURSOR_RIGHT, false);
956 // EXPECT_EQ(SelectionModel(), render_text->selection_model());
959 TEST_F(RenderTextTest, MoveLeftRightByWordInTextWithMultiSpaces) {
960 scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
961 render_text->SetText(WideToUTF16(L"abc def"));
962 render_text->MoveCursorTo(SelectionModel(5, CURSOR_FORWARD));
963 render_text->MoveCursor(WORD_BREAK, CURSOR_RIGHT, false);
964 EXPECT_EQ(11U, render_text->cursor_position());
966 render_text->MoveCursorTo(SelectionModel(5, CURSOR_FORWARD));
967 render_text->MoveCursor(WORD_BREAK, CURSOR_LEFT, false);
968 EXPECT_EQ(0U, render_text->cursor_position());
971 TEST_F(RenderTextTest, MoveLeftRightByWordInChineseText) {
972 scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
973 render_text->SetText(WideToUTF16(L"\x6211\x4EEC\x53BB\x516C\x56ED\x73A9"));
974 render_text->MoveCursor(LINE_BREAK, CURSOR_LEFT, false);
975 EXPECT_EQ(0U, render_text->cursor_position());
976 render_text->MoveCursor(WORD_BREAK, CURSOR_RIGHT, false);
977 EXPECT_EQ(2U, render_text->cursor_position());
978 render_text->MoveCursor(WORD_BREAK, CURSOR_RIGHT, false);
979 EXPECT_EQ(3U, render_text->cursor_position());
980 render_text->MoveCursor(WORD_BREAK, CURSOR_RIGHT, false);
981 EXPECT_EQ(5U, render_text->cursor_position());
982 render_text->MoveCursor(WORD_BREAK, CURSOR_RIGHT, false);
983 EXPECT_EQ(6U, render_text->cursor_position());
984 render_text->MoveCursor(WORD_BREAK, CURSOR_RIGHT, false);
985 EXPECT_EQ(6U, render_text->cursor_position());
987 #endif
989 TEST_F(RenderTextTest, StringSizeSanity) {
990 scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
991 render_text->SetText(UTF8ToUTF16("Hello World"));
992 const Size string_size = render_text->GetStringSize();
993 EXPECT_GT(string_size.width(), 0);
994 EXPECT_GT(string_size.height(), 0);
997 // TODO(asvitkine): This test fails because PlatformFontMac uses point font
998 // sizes instead of pixel sizes like other implementations.
999 #if !defined(OS_MACOSX)
1000 TEST_F(RenderTextTest, StringSizeEmptyString) {
1001 const Font font;
1002 scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
1003 render_text->SetFont(font);
1005 render_text->SetText(base::string16());
1006 EXPECT_EQ(font.GetHeight(), render_text->GetStringSize().height());
1007 EXPECT_EQ(0, render_text->GetStringSize().width());
1009 render_text->SetText(UTF8ToUTF16(" "));
1010 EXPECT_EQ(font.GetHeight(), render_text->GetStringSize().height());
1012 #endif // !defined(OS_MACOSX)
1014 TEST_F(RenderTextTest, SetFont) {
1015 scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
1016 render_text->SetFont(Font("Arial", 12));
1017 EXPECT_EQ("Arial", render_text->GetFont().GetFontName());
1018 EXPECT_EQ(12, render_text->GetFont().GetFontSize());
1021 TEST_F(RenderTextTest, StringSizeBoldWidth) {
1022 scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
1023 render_text->SetText(UTF8ToUTF16("Hello World"));
1025 const int plain_width = render_text->GetStringSize().width();
1026 EXPECT_GT(plain_width, 0);
1028 // Apply a bold style and check that the new width is greater.
1029 render_text->SetStyle(BOLD, true);
1030 const int bold_width = render_text->GetStringSize().width();
1031 EXPECT_GT(bold_width, plain_width);
1033 // Now, apply a plain style over the first word only.
1034 render_text->ApplyStyle(BOLD, false, ui::Range(0, 5));
1035 const int plain_bold_width = render_text->GetStringSize().width();
1036 EXPECT_GT(plain_bold_width, plain_width);
1037 EXPECT_LT(plain_bold_width, bold_width);
1040 TEST_F(RenderTextTest, StringSizeHeight) {
1041 base::string16 cases[] = {
1042 WideToUTF16(L"Hello World!"), // English
1043 WideToUTF16(L"\x6328\x62f6"), // Japanese
1044 WideToUTF16(L"\x0915\x093f"), // Hindi
1045 WideToUTF16(L"\x05e0\x05b8"), // Hebrew
1048 Font default_font;
1049 Font larger_font = default_font.DeriveFont(24, default_font.GetStyle());
1050 EXPECT_GT(larger_font.GetHeight(), default_font.GetHeight());
1052 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) {
1053 scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
1054 render_text->SetFont(default_font);
1055 render_text->SetText(cases[i]);
1057 const int height1 = render_text->GetStringSize().height();
1058 EXPECT_GT(height1, 0);
1060 // Check that setting the larger font increases the height.
1061 render_text->SetFont(larger_font);
1062 const int height2 = render_text->GetStringSize().height();
1063 EXPECT_GT(height2, height1);
1067 TEST_F(RenderTextTest, GetBaselineSanity) {
1068 scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
1069 render_text->SetText(UTF8ToUTF16("Hello World"));
1070 const int baseline = render_text->GetBaseline();
1071 EXPECT_GT(baseline, 0);
1074 TEST_F(RenderTextTest, CursorBoundsInReplacementMode) {
1075 scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
1076 render_text->SetText(ASCIIToUTF16("abcdefg"));
1077 render_text->SetDisplayRect(Rect(100, 17));
1078 SelectionModel sel_b(1, CURSOR_FORWARD);
1079 SelectionModel sel_c(2, CURSOR_FORWARD);
1080 Rect cursor_around_b = render_text->GetCursorBounds(sel_b, false);
1081 Rect cursor_before_b = render_text->GetCursorBounds(sel_b, true);
1082 Rect cursor_before_c = render_text->GetCursorBounds(sel_c, true);
1083 EXPECT_EQ(cursor_around_b.x(), cursor_before_b.x());
1084 EXPECT_EQ(cursor_around_b.right(), cursor_before_c.x());
1087 TEST_F(RenderTextTest, GetTextOffset) {
1088 // The default horizontal text offset differs for LTR and RTL, and is only set
1089 // when the RenderText object is created. This test will check the default in
1090 // LTR mode, and the next test will check the RTL default.
1091 const bool was_rtl = base::i18n::IsRTL();
1092 SetRTL(false);
1093 scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
1094 render_text->SetText(ASCIIToUTF16("abcdefg"));
1095 render_text->SetFontList(FontList("Arial, 13px"));
1097 // Set display area's size equal to the font size.
1098 const Size font_size(render_text->GetContentWidth(),
1099 render_text->GetStringSize().height());
1100 Rect display_rect(font_size);
1101 render_text->SetDisplayRect(display_rect);
1103 Vector2d offset = render_text->GetTextOffset();
1104 EXPECT_TRUE(offset.IsZero());
1106 // Set display area's size greater than font size.
1107 const int kEnlargement = 2;
1108 display_rect.Inset(0, 0, -kEnlargement, -kEnlargement);
1109 render_text->SetDisplayRect(display_rect);
1111 // Check the default horizontal and vertical alignment.
1112 offset = render_text->GetTextOffset();
1113 EXPECT_EQ(kEnlargement / 2, offset.y());
1114 EXPECT_EQ(0, offset.x());
1116 // Check explicitly setting the horizontal alignment.
1117 render_text->SetHorizontalAlignment(ALIGN_LEFT);
1118 offset = render_text->GetTextOffset();
1119 EXPECT_EQ(0, offset.x());
1120 render_text->SetHorizontalAlignment(ALIGN_CENTER);
1121 offset = render_text->GetTextOffset();
1122 EXPECT_EQ(kEnlargement / 2, offset.x());
1123 render_text->SetHorizontalAlignment(ALIGN_RIGHT);
1124 offset = render_text->GetTextOffset();
1125 EXPECT_EQ(kEnlargement, offset.x());
1127 // Check explicitly setting the vertical alignment.
1128 render_text->SetVerticalAlignment(ALIGN_TOP);
1129 offset = render_text->GetTextOffset();
1130 EXPECT_EQ(0, offset.y());
1131 render_text->SetVerticalAlignment(ALIGN_VCENTER);
1132 offset = render_text->GetTextOffset();
1133 EXPECT_EQ(kEnlargement / 2, offset.y());
1134 render_text->SetVerticalAlignment(ALIGN_BOTTOM);
1135 offset = render_text->GetTextOffset();
1136 EXPECT_EQ(kEnlargement, offset.y());
1138 SetRTL(was_rtl);
1141 TEST_F(RenderTextTest, GetTextOffsetHorizontalDefaultInRTL) {
1142 // This only checks the default horizontal alignment in RTL mode; all other
1143 // GetTextOffset() attributes are checked by the test above.
1144 const bool was_rtl = base::i18n::IsRTL();
1145 SetRTL(true);
1146 scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
1147 render_text->SetText(ASCIIToUTF16("abcdefg"));
1148 render_text->SetFontList(FontList("Arial, 13px"));
1149 const int kEnlargement = 2;
1150 const Size font_size(render_text->GetContentWidth() + kEnlargement,
1151 render_text->GetStringSize().height());
1152 Rect display_rect(font_size);
1153 render_text->SetDisplayRect(display_rect);
1154 Vector2d offset = render_text->GetTextOffset();
1155 EXPECT_EQ(kEnlargement, offset.x());
1156 SetRTL(was_rtl);
1159 TEST_F(RenderTextTest, SameFontForParentheses) {
1160 struct {
1161 const char16 left_char;
1162 const char16 right_char;
1163 } punctuation_pairs[] = {
1164 { '(', ')' },
1165 { '{', '}' },
1166 { '<', '>' },
1168 struct {
1169 base::string16 text;
1170 } cases[] = {
1171 // English(English)
1172 { WideToUTF16(L"Hello World(a)") },
1173 // English(English)English
1174 { WideToUTF16(L"Hello World(a)Hello World") },
1176 // Japanese(English)
1177 { WideToUTF16(L"\x6328\x62f6(a)") },
1178 // Japanese(English)Japanese
1179 { WideToUTF16(L"\x6328\x62f6(a)\x6328\x62f6") },
1180 // English(Japanese)English
1181 { WideToUTF16(L"Hello World(\x6328\x62f6)Hello World") },
1183 // Hindi(English)
1184 { WideToUTF16(L"\x0915\x093f(a)") },
1185 // Hindi(English)Hindi
1186 { WideToUTF16(L"\x0915\x093f(a)\x0915\x093f") },
1187 // English(Hindi)English
1188 { WideToUTF16(L"Hello World(\x0915\x093f)Hello World") },
1190 // Hebrew(English)
1191 { WideToUTF16(L"\x05e0\x05b8(a)") },
1192 // Hebrew(English)Hebrew
1193 { WideToUTF16(L"\x05e0\x05b8(a)\x05e0\x05b8") },
1194 // English(Hebrew)English
1195 { WideToUTF16(L"Hello World(\x05e0\x05b8)Hello World") },
1198 scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
1199 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
1200 base::string16 text = cases[i].text;
1201 const size_t start_paren_char_index = text.find('(');
1202 ASSERT_NE(base::string16::npos, start_paren_char_index);
1203 const size_t end_paren_char_index = text.find(')');
1204 ASSERT_NE(base::string16::npos, end_paren_char_index);
1206 for (size_t j = 0; j < ARRAYSIZE_UNSAFE(punctuation_pairs); ++j) {
1207 text[start_paren_char_index] = punctuation_pairs[j].left_char;
1208 text[end_paren_char_index] = punctuation_pairs[j].right_char;
1209 render_text->SetText(text);
1211 const std::vector<RenderText::FontSpan> spans =
1212 render_text->GetFontSpansForTesting();
1214 int start_paren_span_index = -1;
1215 int end_paren_span_index = -1;
1216 for (size_t k = 0; k < spans.size(); ++k) {
1217 if (IndexInRange(spans[k].second, start_paren_char_index))
1218 start_paren_span_index = k;
1219 if (IndexInRange(spans[k].second, end_paren_char_index))
1220 end_paren_span_index = k;
1222 ASSERT_NE(-1, start_paren_span_index);
1223 ASSERT_NE(-1, end_paren_span_index);
1225 const Font& start_font = spans[start_paren_span_index].first;
1226 const Font& end_font = spans[end_paren_span_index].first;
1227 EXPECT_EQ(start_font.GetFontName(), end_font.GetFontName());
1228 EXPECT_EQ(start_font.GetFontSize(), end_font.GetFontSize());
1229 EXPECT_EQ(start_font.GetStyle(), end_font.GetStyle());
1234 // Make sure the caret width is always >=1 so that the correct
1235 // caret is drawn at high DPI. crbug.com/164100.
1236 TEST_F(RenderTextTest, CaretWidth) {
1237 scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
1238 render_text->SetText(ASCIIToUTF16("abcdefg"));
1239 EXPECT_GE(render_text->GetUpdatedCursorBounds().width(), 1);
1242 // Make sure the last word is selected when the cursor is at text.length().
1243 TEST_F(RenderTextTest, LastWordSelected) {
1244 const std::string kTestURL1 = "http://www.google.com";
1245 const std::string kTestURL2 = "http://www.google.com/something/";
1247 scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
1249 render_text->SetText(ASCIIToUTF16(kTestURL1));
1250 render_text->SetCursorPosition(kTestURL1.length());
1251 render_text->SelectWord();
1252 EXPECT_EQ(ASCIIToUTF16("com"), GetSelectedText(render_text.get()));
1253 EXPECT_FALSE(render_text->selection().is_reversed());
1255 render_text->SetText(ASCIIToUTF16(kTestURL2));
1256 render_text->SetCursorPosition(kTestURL2.length());
1257 render_text->SelectWord();
1258 EXPECT_EQ(ASCIIToUTF16("/"), GetSelectedText(render_text.get()));
1259 EXPECT_FALSE(render_text->selection().is_reversed());
1262 // When given a non-empty selection, SelectWord should expand the selection to
1263 // nearest word boundaries.
1264 TEST_F(RenderTextTest, SelectMultipleWords) {
1265 const std::string kTestURL = "http://www.google.com";
1267 scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
1269 render_text->SetText(ASCIIToUTF16(kTestURL));
1270 render_text->SelectRange(ui::Range(16, 20));
1271 render_text->SelectWord();
1272 EXPECT_EQ(ASCIIToUTF16("google.com"), GetSelectedText(render_text.get()));
1273 EXPECT_FALSE(render_text->selection().is_reversed());
1275 // SelectWord should preserve the selection direction.
1276 render_text->SelectRange(ui::Range(20, 16));
1277 render_text->SelectWord();
1278 EXPECT_EQ(ASCIIToUTF16("google.com"), GetSelectedText(render_text.get()));
1279 EXPECT_TRUE(render_text->selection().is_reversed());
1282 // TODO(asvitkine): Cursor movements tests disabled on Mac because RenderTextMac
1283 // does not implement this yet. http://crbug.com/131618
1284 #if !defined(OS_MACOSX)
1285 TEST_F(RenderTextTest, DisplayRectShowsCursorLTR) {
1286 ASSERT_FALSE(base::i18n::IsRTL());
1287 ASSERT_FALSE(base::i18n::ICUIsRTL());
1289 scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
1290 render_text->SetText(WideToUTF16(L"abcdefghijklmnopqrstuvwxzyabcdefg"));
1291 render_text->MoveCursorTo(SelectionModel(render_text->text().length(),
1292 CURSOR_FORWARD));
1293 int width = render_text->GetStringSize().width();
1294 ASSERT_GT(width, 10);
1296 // Ensure that the cursor is placed at the width of its preceding text.
1297 render_text->SetDisplayRect(Rect(width + 10, 1));
1298 EXPECT_EQ(width, render_text->GetUpdatedCursorBounds().x());
1300 // Ensure that shrinking the display rectangle keeps the cursor in view.
1301 render_text->SetDisplayRect(Rect(width - 10, 1));
1302 EXPECT_EQ(render_text->display_rect().width() - 1,
1303 render_text->GetUpdatedCursorBounds().right());
1305 // TODO(msw): Investigate why this test passes with
1306 // |GetUpdateCursorBounds().x()|, while the above have to use
1307 // |.right()|.
1308 // Ensure that the text will pan to fill its expanding display rectangle.
1309 render_text->SetDisplayRect(Rect(width - 5, 1));
1310 EXPECT_EQ(render_text->display_rect().width() - 1,
1311 render_text->GetUpdatedCursorBounds().x());
1313 // Ensure that a sufficiently large display rectangle shows all the text.
1314 render_text->SetDisplayRect(Rect(width + 10, 1));
1315 EXPECT_EQ(width, render_text->GetUpdatedCursorBounds().x());
1317 // Repeat the test with RTL text.
1318 render_text->SetText(WideToUTF16(L"\x5d0\x5d1\x5d2\x5d3\x5d4\x5d5\x5d6\x5d7"
1319 L"\x5d8\x5d9\x5da\x5db\x5dc\x5dd\x5de\x5df"));
1320 render_text->MoveCursorTo(SelectionModel(0, CURSOR_FORWARD));
1321 width = render_text->GetStringSize().width();
1322 ASSERT_GT(width, 10);
1324 // Ensure that the cursor is placed at the width of its preceding text.
1325 render_text->SetDisplayRect(Rect(width + 10, 1));
1326 EXPECT_EQ(width, render_text->GetUpdatedCursorBounds().x());
1328 // Ensure that shrinking the display rectangle keeps the cursor in view.
1329 render_text->SetDisplayRect(Rect(width - 10, 1));
1330 EXPECT_EQ(render_text->display_rect().width() - 1,
1331 render_text->GetUpdatedCursorBounds().right());
1333 // Ensure that the text will pan to fill its expanding display rectangle.
1334 render_text->SetDisplayRect(Rect(width - 5, 1));
1335 EXPECT_EQ(render_text->display_rect().width() - 1,
1336 render_text->GetUpdatedCursorBounds().x());
1338 // Ensure that a sufficiently large display rectangle shows all the text.
1339 render_text->SetDisplayRect(Rect(width + 10, 1));
1340 EXPECT_EQ(width, render_text->GetUpdatedCursorBounds().x());
1343 TEST_F(RenderTextTest, DisplayRectShowsCursorRTL) {
1344 // Set the application default text direction to RTL.
1345 const bool was_rtl = base::i18n::IsRTL();
1346 SetRTL(true);
1348 scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
1349 render_text->SetText(WideToUTF16(L"abcdefghijklmnopqrstuvwxzyabcdefg"));
1350 render_text->MoveCursorTo(SelectionModel(0, CURSOR_FORWARD));
1351 int width = render_text->GetStringSize().width();
1352 ASSERT_GT(width, 10);
1354 // Ensure that the cursor is placed at the width of its preceding text.
1355 render_text->SetDisplayRect(Rect(width + 10, 1));
1356 EXPECT_EQ(render_text->display_rect().width() - width - 1,
1357 render_text->GetUpdatedCursorBounds().x());
1359 // Ensure that shrinking the display rectangle keeps the cursor in view.
1360 render_text->SetDisplayRect(Rect(width - 10, 1));
1361 EXPECT_EQ(0, render_text->GetUpdatedCursorBounds().x());
1363 // Ensure that the text will pan to fill its expanding display rectangle.
1364 render_text->SetDisplayRect(Rect(width - 5, 1));
1365 EXPECT_EQ(0, render_text->GetUpdatedCursorBounds().x());
1367 // Ensure that a sufficiently large display rectangle shows all the text.
1368 render_text->SetDisplayRect(Rect(width + 10, 1));
1369 EXPECT_EQ(render_text->display_rect().width() - width - 1,
1370 render_text->GetUpdatedCursorBounds().x());
1372 // Repeat the test with RTL text.
1373 render_text->SetText(WideToUTF16(L"\x5d0\x5d1\x5d2\x5d3\x5d4\x5d5\x5d6\x5d7"
1374 L"\x5d8\x5d9\x5da\x5db\x5dc\x5dd\x5de\x5df"));
1375 render_text->MoveCursorTo(SelectionModel(render_text->text().length(),
1376 CURSOR_FORWARD));
1377 width = render_text->GetStringSize().width();
1378 ASSERT_GT(width, 10);
1380 // Ensure that the cursor is placed at the width of its preceding text.
1381 render_text->SetDisplayRect(Rect(width + 10, 1));
1382 EXPECT_EQ(render_text->display_rect().width() - width - 1,
1383 render_text->GetUpdatedCursorBounds().x());
1385 // Ensure that shrinking the display rectangle keeps the cursor in view.
1386 render_text->SetDisplayRect(Rect(width - 10, 1));
1387 EXPECT_EQ(0, render_text->GetUpdatedCursorBounds().x());
1389 // Ensure that the text will pan to fill its expanding display rectangle.
1390 render_text->SetDisplayRect(Rect(width - 5, 1));
1391 EXPECT_EQ(0, render_text->GetUpdatedCursorBounds().x());
1393 // Ensure that a sufficiently large display rectangle shows all the text.
1394 render_text->SetDisplayRect(Rect(width + 10, 1));
1395 EXPECT_EQ(render_text->display_rect().width() - width - 1,
1396 render_text->GetUpdatedCursorBounds().x());
1398 // Reset the application default text direction to LTR.
1399 SetRTL(was_rtl);
1400 EXPECT_EQ(was_rtl, base::i18n::IsRTL());
1402 #endif // !defined(OS_MACOSX)
1404 } // namespace gfx