render_text_unittest.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// found in the LICENSE file.
446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "ui/gfx/render_text.h"
646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "base/memory/scoped_ptr.h"
846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "base/utf_string_conversions.h"
946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h"
1046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "ui/base/l10n/l10n_util.h"
1146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "ui/gfx/text_constants.h"
1246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
1346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#if defined(OS_WIN)
1446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "base/win/windows_version.h"
1546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#endif
1646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
1746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#if defined(TOOLKIT_GTK)
1846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include <gtk/gtk.h>
1946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#endif
2046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
2146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)namespace gfx {
2246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
2346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)namespace {
24f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
251675a649fd7a8b3cb80ffddae2dc181f122353c5Ben Murdoch// Various weak, LTR, RTL, and Bidi string cases with three characters each.
26f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)const wchar_t kWeak[] =      L" . ";
271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciconst wchar_t kLtr[] =       L"abc";
281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciconst wchar_t kLtrRtl[] =    L"a"L"\x5d0\x5d1";
291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciconst wchar_t kLtrRtlLtr[] = L"a"L"\x5d1"L"b";
3046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)const wchar_t kRtl[] =       L"\x5d0\x5d1\x5d2";
3146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)const wchar_t kRtlLtr[] =    L"\x5d0\x5d1"L"a";
3246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)const wchar_t kRtlLtrRtl[] = L"\x5d0"L"a"L"\x5d1";
3346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
34f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Checks whether |range| contains |index|. This is not the same as calling
3546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// |range.Contains(ui::Range(index))| - as that would return true when
3646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// |index| == |range.end()|.
3746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)bool IndexInRange(const ui::Range& range, size_t index) {
3846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  return index >= range.start() && index < range.end();
3903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
4003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
4103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#if !defined(OS_MACOSX)
4246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// A test utility function to set the application default text direction.
4346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void SetRTL(bool rtl) {
4446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // Override the current locale/direction.
4546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  base::i18n::SetICUDefaultLocale(rtl ? "he" : "en");
4646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#if defined(TOOLKIT_GTK)
4746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // Do the same for GTK, which does not rely on the ICU default locale.
4846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  gtk_widget_set_default_direction(rtl ? GTK_TEXT_DIR_RTL : GTK_TEXT_DIR_LTR);
4946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#endif
5046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  EXPECT_EQ(rtl, base::i18n::IsRTL());
5146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
5246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#endif
5346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
5446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}  // namespace
5546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
5646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)class RenderTextTest : public testing::Test {
5746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)};
5846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
5946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)TEST_F(RenderTextTest, DefaultStyle) {
6046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // Defaults to empty text with no styles.
61  scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
62  EXPECT_TRUE(render_text->text().empty());
63  EXPECT_TRUE(render_text->style_ranges().empty());
64
65  // Test that the built-in default style is applied for new text.
66  render_text->SetText(ASCIIToUTF16("abc"));
67  EXPECT_EQ(1U, render_text->style_ranges().size());
68  StyleRange style;
69  EXPECT_EQ(style.foreground, render_text->style_ranges()[0].foreground);
70  EXPECT_EQ(ui::Range(0, 3), render_text->style_ranges()[0].range);
71  EXPECT_EQ(style.strike, render_text->style_ranges()[0].strike);
72  EXPECT_EQ(style.underline, render_text->style_ranges()[0].underline);
73
74  // Test that clearing the text also clears the styles.
75  render_text->SetText(string16());
76  EXPECT_TRUE(render_text->text().empty());
77  EXPECT_TRUE(render_text->style_ranges().empty());
78}
79
80TEST_F(RenderTextTest, CustomDefaultStyle) {
81  // Test a custom default style.
82  scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
83  StyleRange color;
84  color.foreground = SK_ColorRED;
85  render_text->set_default_style(color);
86  render_text->SetText(ASCIIToUTF16("abc"));
87  EXPECT_EQ(1U, render_text->style_ranges().size());
88  EXPECT_EQ(color.foreground, render_text->style_ranges()[0].foreground);
89
90  // Test that the custom default style persists across clearing text.
91  render_text->SetText(string16());
92  EXPECT_TRUE(render_text->style_ranges().empty());
93  render_text->SetText(ASCIIToUTF16("abc"));
94  EXPECT_EQ(1U, render_text->style_ranges().size());
95  EXPECT_EQ(color.foreground, render_text->style_ranges()[0].foreground);
96
97  // Test ApplyDefaultStyle after setting a new default.
98  StyleRange strike;
99  strike.strike = true;
100  render_text->set_default_style(strike);
101  render_text->ApplyDefaultStyle();
102  EXPECT_EQ(1U, render_text->style_ranges().size());
103  EXPECT_TRUE(render_text->style_ranges()[0].strike);
104  EXPECT_EQ(strike.foreground, render_text->style_ranges()[0].foreground);
105}
106
107TEST_F(RenderTextTest, ApplyStyleRange) {
108  scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
109  render_text->SetText(ASCIIToUTF16("01234"));
110  EXPECT_EQ(1U, render_text->style_ranges().size());
111
112  // Test ApplyStyleRange (no-op on empty range).
113  StyleRange empty;
114  empty.range = ui::Range(1, 1);
115  render_text->ApplyStyleRange(empty);
116  EXPECT_EQ(1U, render_text->style_ranges().size());
117
118  // Test ApplyStyleRange (no-op on invalid range).
119  StyleRange invalid;
120  invalid.range = ui::Range::InvalidRange();
121  render_text->ApplyStyleRange(invalid);
122  EXPECT_EQ(1U, render_text->style_ranges().size());
123
124  // Apply a style with a range contained by an existing range.
125  StyleRange underline;
126  underline.underline = true;
127  underline.range = ui::Range(2, 3);
128  render_text->ApplyStyleRange(underline);
129  EXPECT_EQ(3U, render_text->style_ranges().size());
130  EXPECT_EQ(ui::Range(0, 2), render_text->style_ranges()[0].range);
131  EXPECT_FALSE(render_text->style_ranges()[0].underline);
132  EXPECT_EQ(ui::Range(2, 3), render_text->style_ranges()[1].range);
133  EXPECT_TRUE(render_text->style_ranges()[1].underline);
134  EXPECT_EQ(ui::Range(3, 5), render_text->style_ranges()[2].range);
135  EXPECT_FALSE(render_text->style_ranges()[2].underline);
136
137  // Apply a style with a range equal to another range.
138  StyleRange color;
139  color.foreground = SK_ColorWHITE;
140  color.range = ui::Range(2, 3);
141  render_text->ApplyStyleRange(color);
142  EXPECT_EQ(3U, render_text->style_ranges().size());
143  EXPECT_EQ(ui::Range(0, 2), render_text->style_ranges()[0].range);
144  EXPECT_NE(SK_ColorWHITE, render_text->style_ranges()[0].foreground);
145  EXPECT_FALSE(render_text->style_ranges()[0].underline);
146  EXPECT_EQ(ui::Range(2, 3), render_text->style_ranges()[1].range);
147  EXPECT_EQ(SK_ColorWHITE, render_text->style_ranges()[1].foreground);
148  EXPECT_FALSE(render_text->style_ranges()[1].underline);
149  EXPECT_EQ(ui::Range(3, 5), render_text->style_ranges()[2].range);
150  EXPECT_NE(SK_ColorWHITE, render_text->style_ranges()[2].foreground);
151  EXPECT_FALSE(render_text->style_ranges()[2].underline);
152
153  // Apply a style with a range containing an existing range.
154  // This new style also overlaps portions of neighboring ranges.
155  StyleRange strike;
156  strike.strike = true;
157  strike.range = ui::Range(1, 4);
158  render_text->ApplyStyleRange(strike);
159  EXPECT_EQ(3U, render_text->style_ranges().size());
160  EXPECT_EQ(ui::Range(0, 1), render_text->style_ranges()[0].range);
161  EXPECT_FALSE(render_text->style_ranges()[0].strike);
162  EXPECT_EQ(ui::Range(1, 4), render_text->style_ranges()[1].range);
163  EXPECT_TRUE(render_text->style_ranges()[1].strike);
164  EXPECT_EQ(ui::Range(4, 5), render_text->style_ranges()[2].range);
165  EXPECT_FALSE(render_text->style_ranges()[2].strike);
166
167  // Apply a style overlapping all ranges.
168  StyleRange strike_underline;
169  strike_underline.strike = true;
170  strike_underline.underline = true;
171  strike_underline.range = ui::Range(0, render_text->text().length());
172  render_text->ApplyStyleRange(strike_underline);
173  EXPECT_EQ(1U, render_text->style_ranges().size());
174  EXPECT_EQ(ui::Range(0, 5), render_text->style_ranges()[0].range);
175  EXPECT_TRUE(render_text->style_ranges()[0].underline);
176  EXPECT_TRUE(render_text->style_ranges()[0].strike);
177
178  // Apply the default style.
179  render_text->ApplyDefaultStyle();
180  EXPECT_EQ(1U, render_text->style_ranges().size());
181  EXPECT_EQ(ui::Range(0, 5), render_text->style_ranges()[0].range);
182  EXPECT_FALSE(render_text->style_ranges()[0].underline);
183  EXPECT_FALSE(render_text->style_ranges()[0].strike);
184
185  // Apply new style range that contains the 2nd last old style range.
186  render_text->SetText(ASCIIToUTF16("abcdefghi"));
187  underline.range = ui::Range(0, 3);
188  render_text->ApplyStyleRange(underline);
189  color.range = ui::Range(3, 6);
190  render_text->ApplyStyleRange(color);
191  strike.range = ui::Range(6, 9);
192  render_text->ApplyStyleRange(strike);
193  EXPECT_EQ(3U, render_text->style_ranges().size());
194
195  color.foreground = SK_ColorRED;
196  color.range = ui::Range(2, 8);
197  render_text->ApplyStyleRange(color);
198  EXPECT_EQ(3U, render_text->style_ranges().size());
199  EXPECT_EQ(ui::Range(0, 2), render_text->style_ranges()[0].range);
200  EXPECT_TRUE(render_text->style_ranges()[0].underline);
201  EXPECT_EQ(ui::Range(2, 8), render_text->style_ranges()[1].range);
202  EXPECT_EQ(SK_ColorRED, render_text->style_ranges()[1].foreground);
203  EXPECT_EQ(ui::Range(8, 9), render_text->style_ranges()[2].range);
204  EXPECT_TRUE(render_text->style_ranges()[2].strike);
205
206  // Apply new style range that contains multiple old style ranges.
207  render_text->SetText(ASCIIToUTF16("abcdefghiopq"));
208  underline.range = ui::Range(0, 3);
209  render_text->ApplyStyleRange(underline);
210  color.range = ui::Range(3, 6);
211  render_text->ApplyStyleRange(color);
212  strike.range = ui::Range(6, 9);
213  render_text->ApplyStyleRange(strike);
214  strike_underline.range = ui::Range(9, 12);
215  render_text->ApplyStyleRange(strike_underline);
216  EXPECT_EQ(4U, render_text->style_ranges().size());
217
218  color.foreground = SK_ColorRED;
219  color.range = ui::Range(2, 10);
220  render_text->ApplyStyleRange(color);
221  EXPECT_EQ(3U, render_text->style_ranges().size());
222  EXPECT_EQ(ui::Range(0, 2), render_text->style_ranges()[0].range);
223  EXPECT_TRUE(render_text->style_ranges()[0].underline);
224  EXPECT_EQ(ui::Range(2, 10), render_text->style_ranges()[1].range);
225  EXPECT_EQ(SK_ColorRED, render_text->style_ranges()[1].foreground);
226  EXPECT_EQ(ui::Range(10, 12), render_text->style_ranges()[2].range);
227  EXPECT_TRUE(render_text->style_ranges()[2].underline);
228  EXPECT_TRUE(render_text->style_ranges()[2].strike);
229}
230
231static void SetTextWith2ExtraStyles(RenderText* render_text) {
232  render_text->SetText(ASCIIToUTF16("abcdefghi"));
233
234  StyleRange strike;
235  strike.strike = true;
236  strike.range = ui::Range(0, 3);
237  render_text->ApplyStyleRange(strike);
238
239  StyleRange underline;
240  underline.underline = true;
241  underline.range = ui::Range(3, 6);
242  render_text->ApplyStyleRange(underline);
243}
244
245TEST_F(RenderTextTest, StyleRangesAdjust) {
246  // Test that style ranges adjust to the text size.
247  scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
248  render_text->SetText(ASCIIToUTF16("abcdef"));
249  EXPECT_EQ(1U, render_text->style_ranges().size());
250  EXPECT_EQ(ui::Range(0, 6), render_text->style_ranges()[0].range);
251
252  // Test that the range is clipped to the length of shorter text.
253  render_text->SetText(ASCIIToUTF16("abc"));
254  EXPECT_EQ(1U, render_text->style_ranges().size());
255  EXPECT_EQ(ui::Range(0, 3), render_text->style_ranges()[0].range);
256
257  // Test that the last range extends to the length of longer text.
258  StyleRange strike;
259  strike.strike = true;
260  strike.range = ui::Range(2, 3);
261  render_text->ApplyStyleRange(strike);
262  render_text->SetText(ASCIIToUTF16("abcdefghi"));
263  EXPECT_EQ(2U, render_text->style_ranges().size());
264  EXPECT_EQ(ui::Range(0, 2), render_text->style_ranges()[0].range);
265  EXPECT_EQ(ui::Range(2, 9), render_text->style_ranges()[1].range);
266  EXPECT_TRUE(render_text->style_ranges()[1].strike);
267
268  // Test that ranges are removed if they're outside the range of shorter text.
269  render_text->SetText(ASCIIToUTF16("ab"));
270  EXPECT_EQ(1U, render_text->style_ranges().size());
271  EXPECT_EQ(ui::Range(0, 2), render_text->style_ranges()[0].range);
272  EXPECT_FALSE(render_text->style_ranges()[0].strike);
273
274  // Test that previously removed ranges don't return.
275  render_text->SetText(ASCIIToUTF16("abcdef"));
276  EXPECT_EQ(1U, render_text->style_ranges().size());
277  EXPECT_EQ(ui::Range(0, 6), render_text->style_ranges()[0].range);
278  EXPECT_FALSE(render_text->style_ranges()[0].strike);
279
280  // Test that ranges are removed correctly if they are outside the range of
281  // shorter text.
282  SetTextWith2ExtraStyles(render_text.get());
283  EXPECT_EQ(3U, render_text->style_ranges().size());
284
285  render_text->SetText(ASCIIToUTF16("abcdefg"));
286  EXPECT_EQ(3U, render_text->style_ranges().size());
287  EXPECT_EQ(ui::Range(0, 3), render_text->style_ranges()[0].range);
288  EXPECT_EQ(ui::Range(3, 6), render_text->style_ranges()[1].range);
289  EXPECT_EQ(ui::Range(6, 7), render_text->style_ranges()[2].range);
290
291  SetTextWith2ExtraStyles(render_text.get());
292  EXPECT_EQ(3U, render_text->style_ranges().size());
293
294  render_text->SetText(ASCIIToUTF16("abcdef"));
295  EXPECT_EQ(2U, render_text->style_ranges().size());
296  EXPECT_EQ(ui::Range(0, 3), render_text->style_ranges()[0].range);
297  EXPECT_EQ(ui::Range(3, 6), render_text->style_ranges()[1].range);
298
299  SetTextWith2ExtraStyles(render_text.get());
300  EXPECT_EQ(3U, render_text->style_ranges().size());
301
302  render_text->SetText(ASCIIToUTF16("abcde"));
303  EXPECT_EQ(2U, render_text->style_ranges().size());
304  EXPECT_EQ(ui::Range(0, 3), render_text->style_ranges()[0].range);
305  EXPECT_EQ(ui::Range(3, 5), render_text->style_ranges()[1].range);
306
307  SetTextWith2ExtraStyles(render_text.get());
308  EXPECT_EQ(3U, render_text->style_ranges().size());
309
310  render_text->SetText(ASCIIToUTF16("abc"));
311  EXPECT_EQ(1U, render_text->style_ranges().size());
312  EXPECT_EQ(ui::Range(0, 3), render_text->style_ranges()[0].range);
313
314  SetTextWith2ExtraStyles(render_text.get());
315  EXPECT_EQ(3U, render_text->style_ranges().size());
316
317  render_text->SetText(ASCIIToUTF16("a"));
318  EXPECT_EQ(1U, render_text->style_ranges().size());
319  EXPECT_EQ(ui::Range(0, 1), render_text->style_ranges()[0].range);
320}
321
322// TODO(asvitkine): Cursor movements tests disabled on Mac because RenderTextMac
323//                  does not implement this yet. http://crbug.com/131618
324#if !defined(OS_MACOSX)
325void TestVisualCursorMotionInObscuredField(RenderText* render_text,
326                                           const string16& text,
327                                           bool select) {
328  ASSERT_TRUE(render_text->obscured());
329  render_text->SetText(text);
330  int len = text.length();
331  render_text->MoveCursor(LINE_BREAK, CURSOR_RIGHT, select);
332  EXPECT_EQ(SelectionModel(ui::Range(select ? 0 : len, len), CURSOR_FORWARD),
333            render_text->selection_model());
334  render_text->MoveCursor(LINE_BREAK, CURSOR_LEFT, select);
335  EXPECT_EQ(SelectionModel(0, CURSOR_BACKWARD), render_text->selection_model());
336  for (int j = 1; j <= len; ++j) {
337    render_text->MoveCursor(CHARACTER_BREAK, CURSOR_RIGHT, select);
338    EXPECT_EQ(SelectionModel(ui::Range(select ? 0 : j, j), CURSOR_BACKWARD),
339              render_text->selection_model());
340  }
341  for (int j = len - 1; j >= 0; --j) {
342    render_text->MoveCursor(CHARACTER_BREAK, CURSOR_LEFT, select);
343    EXPECT_EQ(SelectionModel(ui::Range(select ? 0 : j, j), CURSOR_FORWARD),
344              render_text->selection_model());
345  }
346  render_text->MoveCursor(WORD_BREAK, CURSOR_RIGHT, select);
347  EXPECT_EQ(SelectionModel(ui::Range(select ? 0 : len, len), CURSOR_FORWARD),
348            render_text->selection_model());
349  render_text->MoveCursor(WORD_BREAK, CURSOR_LEFT, select);
350  EXPECT_EQ(SelectionModel(0, CURSOR_BACKWARD), render_text->selection_model());
351}
352
353TEST_F(RenderTextTest, ObscuredText) {
354  const string16 seuss = ASCIIToUTF16("hop on pop");
355  const string16 no_seuss = ASCIIToUTF16("**********");
356  scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
357
358  // GetLayoutText() returns asterisks when the obscured bit is set.
359  render_text->SetText(seuss);
360  render_text->SetObscured(true);
361  EXPECT_EQ(seuss, render_text->text());
362  EXPECT_EQ(no_seuss, render_text->GetLayoutText());
363  render_text->SetObscured(false);
364  EXPECT_EQ(seuss, render_text->text());
365  EXPECT_EQ(seuss, render_text->GetLayoutText());
366
367  render_text->SetObscured(true);
368
369  // Surrogate pairs are counted as one code point.
370  const char16 invalid_surrogates[] = {0xDC00, 0xD800, 0};
371  render_text->SetText(invalid_surrogates);
372  EXPECT_EQ(ASCIIToUTF16("**"), render_text->GetLayoutText());
373  const char16 valid_surrogates[] = {0xD800, 0xDC00, 0};
374  render_text->SetText(valid_surrogates);
375  EXPECT_EQ(ASCIIToUTF16("*"), render_text->GetLayoutText());
376  EXPECT_EQ(0U, render_text->cursor_position());
377  render_text->MoveCursor(CHARACTER_BREAK, CURSOR_RIGHT, false);
378  EXPECT_EQ(2U, render_text->cursor_position());
379
380  // Test index conversion and cursor validity with a valid surrogate pair.
381  EXPECT_EQ(0U, render_text->TextIndexToLayoutIndex(0U));
382  EXPECT_EQ(1U, render_text->TextIndexToLayoutIndex(1U));
383  EXPECT_EQ(1U, render_text->TextIndexToLayoutIndex(2U));
384  EXPECT_EQ(0U, render_text->LayoutIndexToTextIndex(0U));
385  EXPECT_EQ(2U, render_text->LayoutIndexToTextIndex(1U));
386  EXPECT_TRUE(render_text->IsCursorablePosition(0U));
387  EXPECT_FALSE(render_text->IsCursorablePosition(1U));
388  EXPECT_TRUE(render_text->IsCursorablePosition(2U));
389
390  // FindCursorPosition() should not return positions between a surrogate pair.
391  render_text->SetDisplayRect(Rect(0, 0, 20, 20));
392  EXPECT_EQ(render_text->FindCursorPosition(Point(0, 0)).caret_pos(), 0U);
393  EXPECT_EQ(render_text->FindCursorPosition(Point(20, 0)).caret_pos(), 2U);
394  for (int x = -1; x <= 20; ++x) {
395    SelectionModel selection = render_text->FindCursorPosition(Point(x, 0));
396    EXPECT_TRUE(selection.caret_pos() == 0U || selection.caret_pos() == 2U);
397  }
398
399  // GetGlyphBounds() should yield the entire string bounds for text index 0.
400  int height = 0;
401  ui::Range bounds;
402  render_text->GetGlyphBounds(0U, &bounds, &height);
403  EXPECT_EQ(render_text->GetStringSize().width(),
404            static_cast<int>(bounds.length()));
405
406  // Cursoring is independent of underlying characters when text is obscured.
407  const wchar_t* const texts[] = {
408    kWeak, kLtr, kLtrRtl, kLtrRtlLtr, kRtl, kRtlLtr, kRtlLtrRtl,
409    L"hop on pop",                             // Check LTR word boundaries.
410    L"\x05d0\x05d1 \x05d0\x05d2 \x05d1\x05d2", // Check RTL word boundaries.
411  };
412  for (size_t i = 0; i < arraysize(texts); ++i) {
413    string16 text = WideToUTF16(texts[i]);
414    TestVisualCursorMotionInObscuredField(render_text.get(), text, false);
415    TestVisualCursorMotionInObscuredField(render_text.get(), text, true);
416  }
417}
418
419TEST_F(RenderTextTest, GetTextDirection) {
420  struct {
421    const wchar_t* text;
422    const base::i18n::TextDirection text_direction;
423  } cases[] = {
424    // Blank strings and those with no/weak directionality default to LTR.
425    { L"",        base::i18n::LEFT_TO_RIGHT },
426    { kWeak,      base::i18n::LEFT_TO_RIGHT },
427    // Strings that begin with strong LTR characters.
428    { kLtr,       base::i18n::LEFT_TO_RIGHT },
429    { kLtrRtl,    base::i18n::LEFT_TO_RIGHT },
430    { kLtrRtlLtr, base::i18n::LEFT_TO_RIGHT },
431    // Strings that begin with strong RTL characters.
432    { kRtl,       base::i18n::RIGHT_TO_LEFT },
433    { kRtlLtr,    base::i18n::RIGHT_TO_LEFT },
434    { kRtlLtrRtl, base::i18n::RIGHT_TO_LEFT },
435  };
436
437  scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
438  const bool was_rtl = base::i18n::IsRTL();
439
440  for (size_t i = 0; i < 2; ++i) {
441    // Toggle the application default text direction (to try each direction).
442    SetRTL(!base::i18n::IsRTL());
443    const base::i18n::TextDirection ui_direction = base::i18n::IsRTL() ?
444        base::i18n::RIGHT_TO_LEFT : base::i18n::LEFT_TO_RIGHT;
445
446    // Ensure that directionality modes yield the correct text directions.
447    for (size_t j = 0; j < ARRAYSIZE_UNSAFE(cases); j++) {
448      render_text->SetText(WideToUTF16(cases[j].text));
449      render_text->SetDirectionalityMode(DIRECTIONALITY_FROM_TEXT);
450      EXPECT_EQ(render_text->GetTextDirection(), cases[j].text_direction);
451      render_text->SetDirectionalityMode(DIRECTIONALITY_FROM_UI);
452      EXPECT_EQ(render_text->GetTextDirection(), ui_direction);
453      render_text->SetDirectionalityMode(DIRECTIONALITY_FORCE_LTR);
454      EXPECT_EQ(render_text->GetTextDirection(), base::i18n::LEFT_TO_RIGHT);
455      render_text->SetDirectionalityMode(DIRECTIONALITY_FORCE_RTL);
456      EXPECT_EQ(render_text->GetTextDirection(), base::i18n::RIGHT_TO_LEFT);
457    }
458  }
459
460  EXPECT_EQ(was_rtl, base::i18n::IsRTL());
461
462  // Ensure that text changes update the direction for DIRECTIONALITY_FROM_TEXT.
463  render_text->SetDirectionalityMode(DIRECTIONALITY_FROM_TEXT);
464  render_text->SetText(WideToUTF16(kLtr));
465  EXPECT_EQ(render_text->GetTextDirection(), base::i18n::LEFT_TO_RIGHT);
466  render_text->SetText(WideToUTF16(kRtl));
467  EXPECT_EQ(render_text->GetTextDirection(), base::i18n::RIGHT_TO_LEFT);
468}
469
470void RunMoveCursorLeftRightTest(RenderText* render_text,
471    const std::vector<SelectionModel>& expected,
472    VisualCursorDirection direction) {
473  for (size_t i = 0; i < expected.size(); ++i) {
474    EXPECT_EQ(expected[i], render_text->selection_model());
475    render_text->MoveCursor(CHARACTER_BREAK, direction, false);
476  }
477  // Check that cursoring is clamped at the line edge.
478  EXPECT_EQ(expected.back(), render_text->selection_model());
479  // Check that it is the line edge.
480  render_text->MoveCursor(LINE_BREAK, direction, false);
481  EXPECT_EQ(expected.back(), render_text->selection_model());
482}
483
484TEST_F(RenderTextTest, MoveCursorLeftRightInLtr) {
485  scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
486
487  // Pure LTR.
488  render_text->SetText(ASCIIToUTF16("abc"));
489  // |expected| saves the expected SelectionModel when moving cursor from left
490  // to right.
491  std::vector<SelectionModel> expected;
492  expected.push_back(SelectionModel(0, CURSOR_BACKWARD));
493  expected.push_back(SelectionModel(1, CURSOR_BACKWARD));
494  expected.push_back(SelectionModel(2, CURSOR_BACKWARD));
495  expected.push_back(SelectionModel(3, CURSOR_BACKWARD));
496  expected.push_back(SelectionModel(3, CURSOR_FORWARD));
497  RunMoveCursorLeftRightTest(render_text.get(), expected, CURSOR_RIGHT);
498
499  expected.clear();
500  expected.push_back(SelectionModel(3, CURSOR_FORWARD));
501  expected.push_back(SelectionModel(2, CURSOR_FORWARD));
502  expected.push_back(SelectionModel(1, CURSOR_FORWARD));
503  expected.push_back(SelectionModel(0, CURSOR_FORWARD));
504  expected.push_back(SelectionModel(0, CURSOR_BACKWARD));
505  RunMoveCursorLeftRightTest(render_text.get(), expected, CURSOR_LEFT);
506}
507
508TEST_F(RenderTextTest, MoveCursorLeftRightInLtrRtl) {
509  scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
510  // LTR-RTL
511  render_text->SetText(WideToUTF16(L"abc\x05d0\x05d1\x05d2"));
512  // The last one is the expected END position.
513  std::vector<SelectionModel> expected;
514  expected.push_back(SelectionModel(0, CURSOR_BACKWARD));
515  expected.push_back(SelectionModel(1, CURSOR_BACKWARD));
516  expected.push_back(SelectionModel(2, CURSOR_BACKWARD));
517  expected.push_back(SelectionModel(3, CURSOR_BACKWARD));
518  expected.push_back(SelectionModel(5, CURSOR_FORWARD));
519  expected.push_back(SelectionModel(4, CURSOR_FORWARD));
520  expected.push_back(SelectionModel(3, CURSOR_FORWARD));
521  expected.push_back(SelectionModel(6, CURSOR_FORWARD));
522  RunMoveCursorLeftRightTest(render_text.get(), expected, CURSOR_RIGHT);
523
524  expected.clear();
525  expected.push_back(SelectionModel(6, CURSOR_FORWARD));
526  expected.push_back(SelectionModel(4, CURSOR_BACKWARD));
527  expected.push_back(SelectionModel(5, CURSOR_BACKWARD));
528  expected.push_back(SelectionModel(6, CURSOR_BACKWARD));
529  expected.push_back(SelectionModel(2, CURSOR_FORWARD));
530  expected.push_back(SelectionModel(1, CURSOR_FORWARD));
531  expected.push_back(SelectionModel(0, CURSOR_FORWARD));
532  expected.push_back(SelectionModel(0, CURSOR_BACKWARD));
533  RunMoveCursorLeftRightTest(render_text.get(), expected, CURSOR_LEFT);
534}
535
536TEST_F(RenderTextTest, MoveCursorLeftRightInLtrRtlLtr) {
537  scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
538  // LTR-RTL-LTR.
539  render_text->SetText(WideToUTF16(L"a"L"\x05d1"L"b"));
540  std::vector<SelectionModel> expected;
541  expected.push_back(SelectionModel(0, CURSOR_BACKWARD));
542  expected.push_back(SelectionModel(1, CURSOR_BACKWARD));
543  expected.push_back(SelectionModel(1, CURSOR_FORWARD));
544  expected.push_back(SelectionModel(3, CURSOR_BACKWARD));
545  expected.push_back(SelectionModel(3, CURSOR_FORWARD));
546  RunMoveCursorLeftRightTest(render_text.get(), expected, CURSOR_RIGHT);
547
548  expected.clear();
549  expected.push_back(SelectionModel(3, CURSOR_FORWARD));
550  expected.push_back(SelectionModel(2, CURSOR_FORWARD));
551  expected.push_back(SelectionModel(2, CURSOR_BACKWARD));
552  expected.push_back(SelectionModel(0, CURSOR_FORWARD));
553  expected.push_back(SelectionModel(0, CURSOR_BACKWARD));
554  RunMoveCursorLeftRightTest(render_text.get(), expected, CURSOR_LEFT);
555}
556
557TEST_F(RenderTextTest, MoveCursorLeftRightInRtl) {
558  scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
559  // Pure RTL.
560  render_text->SetText(WideToUTF16(L"\x05d0\x05d1\x05d2"));
561  render_text->MoveCursor(LINE_BREAK, CURSOR_RIGHT, false);
562  std::vector<SelectionModel> expected;
563
564  expected.push_back(SelectionModel(0, CURSOR_BACKWARD));
565  expected.push_back(SelectionModel(1, CURSOR_BACKWARD));
566  expected.push_back(SelectionModel(2, CURSOR_BACKWARD));
567  expected.push_back(SelectionModel(3, CURSOR_BACKWARD));
568  expected.push_back(SelectionModel(3, CURSOR_FORWARD));
569  RunMoveCursorLeftRightTest(render_text.get(), expected, CURSOR_LEFT);
570
571  expected.clear();
572
573  expected.push_back(SelectionModel(3, CURSOR_FORWARD));
574  expected.push_back(SelectionModel(2, CURSOR_FORWARD));
575  expected.push_back(SelectionModel(1, CURSOR_FORWARD));
576  expected.push_back(SelectionModel(0, CURSOR_FORWARD));
577  expected.push_back(SelectionModel(0, CURSOR_BACKWARD));
578  RunMoveCursorLeftRightTest(render_text.get(), expected, CURSOR_RIGHT);
579}
580
581TEST_F(RenderTextTest, MoveCursorLeftRightInRtlLtr) {
582  scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
583  // RTL-LTR
584  render_text->SetText(WideToUTF16(L"\x05d0\x05d1\x05d2"L"abc"));
585  render_text->MoveCursor(LINE_BREAK, CURSOR_RIGHT, false);
586  std::vector<SelectionModel> expected;
587  expected.push_back(SelectionModel(0, CURSOR_BACKWARD));
588  expected.push_back(SelectionModel(1, CURSOR_BACKWARD));
589  expected.push_back(SelectionModel(2, CURSOR_BACKWARD));
590  expected.push_back(SelectionModel(3, CURSOR_BACKWARD));
591  expected.push_back(SelectionModel(5, CURSOR_FORWARD));
592  expected.push_back(SelectionModel(4, CURSOR_FORWARD));
593  expected.push_back(SelectionModel(3, CURSOR_FORWARD));
594  expected.push_back(SelectionModel(6, CURSOR_FORWARD));
595  RunMoveCursorLeftRightTest(render_text.get(), expected, CURSOR_LEFT);
596
597  expected.clear();
598  expected.push_back(SelectionModel(6, CURSOR_FORWARD));
599  expected.push_back(SelectionModel(4, CURSOR_BACKWARD));
600  expected.push_back(SelectionModel(5, CURSOR_BACKWARD));
601  expected.push_back(SelectionModel(6, CURSOR_BACKWARD));
602  expected.push_back(SelectionModel(2, CURSOR_FORWARD));
603  expected.push_back(SelectionModel(1, CURSOR_FORWARD));
604  expected.push_back(SelectionModel(0, CURSOR_FORWARD));
605  expected.push_back(SelectionModel(0, CURSOR_BACKWARD));
606  RunMoveCursorLeftRightTest(render_text.get(), expected, CURSOR_RIGHT);
607}
608
609TEST_F(RenderTextTest, MoveCursorLeftRightInRtlLtrRtl) {
610  scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
611  // RTL-LTR-RTL.
612  render_text->SetText(WideToUTF16(L"\x05d0"L"a"L"\x05d1"));
613  render_text->MoveCursor(LINE_BREAK, CURSOR_RIGHT, false);
614  std::vector<SelectionModel> expected;
615  expected.push_back(SelectionModel(0, CURSOR_BACKWARD));
616  expected.push_back(SelectionModel(1, CURSOR_BACKWARD));
617  expected.push_back(SelectionModel(1, CURSOR_FORWARD));
618  expected.push_back(SelectionModel(3, CURSOR_BACKWARD));
619  expected.push_back(SelectionModel(3, CURSOR_FORWARD));
620  RunMoveCursorLeftRightTest(render_text.get(), expected, CURSOR_LEFT);
621
622  expected.clear();
623  expected.push_back(SelectionModel(3, CURSOR_FORWARD));
624  expected.push_back(SelectionModel(2, CURSOR_FORWARD));
625  expected.push_back(SelectionModel(2, CURSOR_BACKWARD));
626  expected.push_back(SelectionModel(0, CURSOR_FORWARD));
627  expected.push_back(SelectionModel(0, CURSOR_BACKWARD));
628  RunMoveCursorLeftRightTest(render_text.get(), expected, CURSOR_RIGHT);
629}
630
631// TODO(xji): temporarily disable in platform Win since the complex script
632// characters turned into empty square due to font regression. So, not able
633// to test 2 characters belong to the same grapheme.
634#if defined(OS_LINUX)
635TEST_F(RenderTextTest, MoveCursorLeftRight_ComplexScript) {
636  scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
637
638  render_text->SetText(WideToUTF16(L"\x0915\x093f\x0915\x094d\x0915"));
639  EXPECT_EQ(0U, render_text->cursor_position());
640  render_text->MoveCursor(CHARACTER_BREAK, CURSOR_RIGHT, false);
641  EXPECT_EQ(2U, render_text->cursor_position());
642  render_text->MoveCursor(CHARACTER_BREAK, CURSOR_RIGHT, false);
643  EXPECT_EQ(4U, render_text->cursor_position());
644  render_text->MoveCursor(CHARACTER_BREAK, CURSOR_RIGHT, false);
645  EXPECT_EQ(5U, render_text->cursor_position());
646  render_text->MoveCursor(CHARACTER_BREAK, CURSOR_RIGHT, false);
647  EXPECT_EQ(5U, render_text->cursor_position());
648
649  render_text->MoveCursor(CHARACTER_BREAK, CURSOR_LEFT, false);
650  EXPECT_EQ(4U, render_text->cursor_position());
651  render_text->MoveCursor(CHARACTER_BREAK, CURSOR_LEFT, false);
652  EXPECT_EQ(2U, render_text->cursor_position());
653  render_text->MoveCursor(CHARACTER_BREAK, CURSOR_LEFT, false);
654  EXPECT_EQ(0U, render_text->cursor_position());
655  render_text->MoveCursor(CHARACTER_BREAK, CURSOR_LEFT, false);
656  EXPECT_EQ(0U, render_text->cursor_position());
657}
658#endif
659
660TEST_F(RenderTextTest, GraphemePositions) {
661  // LTR 2-character grapheme, LTR abc, LTR 2-character grapheme.
662  const string16 kText1 = WideToUTF16(L"\x0915\x093f"L"abc"L"\x0915\x093f");
663
664  // LTR ab, LTR 2-character grapheme, LTR cd.
665  const string16 kText2 = WideToUTF16(L"ab"L"\x0915\x093f"L"cd");
666
667  // The below is 'MUSICAL SYMBOL G CLEF', which is represented in UTF-16 as
668  // two characters forming the surrogate pair 0x0001D11E.
669  const std::string kSurrogate = "\xF0\x9D\x84\x9E";
670
671  // LTR ab, UTF16 surrogate pair, LTR cd.
672  const string16 kText3 = UTF8ToUTF16("ab" + kSurrogate + "cd");
673
674  struct {
675    string16 text;
676    size_t index;
677    size_t expected_previous;
678    size_t expected_next;
679  } cases[] = {
680    { string16(), 0, 0, 0 },
681    { string16(), 1, 0, 0 },
682    { string16(), 50, 0, 0 },
683    { kText1, 0, 0, 2 },
684    { kText1, 1, 0, 2 },
685    { kText1, 2, 0, 3 },
686    { kText1, 3, 2, 4 },
687    { kText1, 4, 3, 5 },
688    { kText1, 5, 4, 7 },
689    { kText1, 6, 5, 7 },
690    { kText1, 7, 5, 7 },
691    { kText1, 8, 7, 7 },
692    { kText1, 50, 7, 7 },
693    { kText2, 0, 0, 1 },
694    { kText2, 1, 0, 2 },
695    { kText2, 2, 1, 4 },
696    { kText2, 3, 2, 4 },
697    { kText2, 4, 2, 5 },
698    { kText2, 5, 4, 6 },
699    { kText2, 6, 5, 6 },
700    { kText2, 7, 6, 6 },
701    { kText2, 50, 6, 6 },
702    { kText3, 0, 0, 1 },
703    { kText3, 1, 0, 2 },
704    { kText3, 2, 1, 4 },
705    { kText3, 3, 2, 4 },
706    { kText3, 4, 2, 5 },
707    { kText3, 5, 4, 6 },
708    { kText3, 6, 5, 6 },
709    { kText3, 7, 6, 6 },
710    { kText3, 50, 6, 6 },
711  };
712
713  // TODO(asvitkine): Disable tests that fail on XP bots due to lack of complete
714  //                  font support for some scripts - http://crbug.com/106450
715#if defined(OS_WIN)
716  if (base::win::GetVersion() < base::win::VERSION_VISTA)
717    return;
718#endif
719
720  scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
721  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) {
722    render_text->SetText(cases[i].text);
723
724    size_t next = render_text->IndexOfAdjacentGrapheme(cases[i].index,
725                                                       CURSOR_FORWARD);
726    EXPECT_EQ(cases[i].expected_next, next);
727    EXPECT_TRUE(render_text->IsCursorablePosition(next));
728
729    size_t previous = render_text->IndexOfAdjacentGrapheme(cases[i].index,
730                                                           CURSOR_BACKWARD);
731    EXPECT_EQ(cases[i].expected_previous, previous);
732    EXPECT_TRUE(render_text->IsCursorablePosition(previous));
733  }
734}
735
736TEST_F(RenderTextTest, EdgeSelectionModels) {
737  // Simple Latin text.
738  const string16 kLatin = WideToUTF16(L"abc");
739  // LTR 2-character grapheme.
740  const string16 kLTRGrapheme = WideToUTF16(L"\x0915\x093f");
741  // LTR 2-character grapheme, LTR a, LTR 2-character grapheme.
742  const string16 kHindiLatin = WideToUTF16(L"\x0915\x093f"L"a"L"\x0915\x093f");
743  // RTL 2-character grapheme.
744  const string16 kRTLGrapheme = WideToUTF16(L"\x05e0\x05b8");
745  // RTL 2-character grapheme, LTR a, RTL 2-character grapheme.
746  const string16 kHebrewLatin = WideToUTF16(L"\x05e0\x05b8"L"a"L"\x05e0\x05b8");
747
748  struct {
749    string16 text;
750    base::i18n::TextDirection expected_text_direction;
751  } cases[] = {
752    { string16(),   base::i18n::LEFT_TO_RIGHT },
753    { kLatin,       base::i18n::LEFT_TO_RIGHT },
754    { kLTRGrapheme, base::i18n::LEFT_TO_RIGHT },
755    { kHindiLatin,  base::i18n::LEFT_TO_RIGHT },
756    { kRTLGrapheme, base::i18n::RIGHT_TO_LEFT },
757    { kHebrewLatin, base::i18n::RIGHT_TO_LEFT },
758  };
759
760  // TODO(asvitkine): Disable tests that fail on XP bots due to lack of complete
761  //                  font support for some scripts - http://crbug.com/106450
762#if defined(OS_WIN)
763  if (base::win::GetVersion() < base::win::VERSION_VISTA)
764    return;
765#endif
766
767  scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
768  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) {
769    render_text->SetText(cases[i].text);
770    bool ltr = (cases[i].expected_text_direction == base::i18n::LEFT_TO_RIGHT);
771
772    SelectionModel start_edge =
773        render_text->EdgeSelectionModel(ltr ? CURSOR_LEFT : CURSOR_RIGHT);
774    EXPECT_EQ(start_edge, SelectionModel(0, CURSOR_BACKWARD));
775
776    SelectionModel end_edge =
777        render_text->EdgeSelectionModel(ltr ? CURSOR_RIGHT : CURSOR_LEFT);
778    EXPECT_EQ(end_edge, SelectionModel(cases[i].text.length(), CURSOR_FORWARD));
779  }
780}
781
782TEST_F(RenderTextTest, SelectAll) {
783  const wchar_t* const cases[] =
784      { kWeak, kLtr, kLtrRtl, kLtrRtlLtr, kRtl, kRtlLtr, kRtlLtrRtl };
785
786  // Ensure that SelectAll respects the |reversed| argument regardless of
787  // application locale and text content directionality.
788  scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
789  const SelectionModel expected_reversed(ui::Range(3, 0), CURSOR_FORWARD);
790  const SelectionModel expected_forwards(ui::Range(0, 3), CURSOR_BACKWARD);
791  const bool was_rtl = base::i18n::IsRTL();
792
793  for (size_t i = 0; i < 2; ++i) {
794    SetRTL(!base::i18n::IsRTL());
795    // Test that an empty string produces an empty selection model.
796    render_text->SetText(string16());
797    EXPECT_EQ(render_text->selection_model(), SelectionModel());
798
799    // Test the weak, LTR, RTL, and Bidi string cases.
800    for (size_t j = 0; j < ARRAYSIZE_UNSAFE(cases); j++) {
801      render_text->SetText(WideToUTF16(cases[j]));
802      render_text->SelectAll(false);
803      EXPECT_EQ(render_text->selection_model(), expected_forwards);
804      render_text->SelectAll(true);
805      EXPECT_EQ(render_text->selection_model(), expected_reversed);
806    }
807  }
808
809  EXPECT_EQ(was_rtl, base::i18n::IsRTL());
810}
811
812  TEST_F(RenderTextTest, MoveCursorLeftRightWithSelection) {
813  scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
814  render_text->SetText(WideToUTF16(L"abc\x05d0\x05d1\x05d2"));
815  // Left arrow on select ranging (6, 4).
816  render_text->MoveCursor(LINE_BREAK, CURSOR_RIGHT, false);
817  EXPECT_EQ(ui::Range(6), render_text->selection());
818  render_text->MoveCursor(CHARACTER_BREAK, CURSOR_LEFT, false);
819  EXPECT_EQ(ui::Range(4), render_text->selection());
820  render_text->MoveCursor(CHARACTER_BREAK, CURSOR_LEFT, false);
821  EXPECT_EQ(ui::Range(5), render_text->selection());
822  render_text->MoveCursor(CHARACTER_BREAK, CURSOR_LEFT, false);
823  EXPECT_EQ(ui::Range(6), render_text->selection());
824  render_text->MoveCursor(CHARACTER_BREAK, CURSOR_RIGHT, true);
825  EXPECT_EQ(ui::Range(6, 5), render_text->selection());
826  render_text->MoveCursor(CHARACTER_BREAK, CURSOR_RIGHT, true);
827  EXPECT_EQ(ui::Range(6, 4), render_text->selection());
828  render_text->MoveCursor(CHARACTER_BREAK, CURSOR_LEFT, false);
829  EXPECT_EQ(ui::Range(6), render_text->selection());
830
831  // Right arrow on select ranging (4, 6).
832  render_text->MoveCursor(LINE_BREAK, CURSOR_LEFT, false);
833  EXPECT_EQ(ui::Range(0), render_text->selection());
834  render_text->MoveCursor(CHARACTER_BREAK, CURSOR_RIGHT, false);
835  EXPECT_EQ(ui::Range(1), render_text->selection());
836  render_text->MoveCursor(CHARACTER_BREAK, CURSOR_RIGHT, false);
837  EXPECT_EQ(ui::Range(2), render_text->selection());
838  render_text->MoveCursor(CHARACTER_BREAK, CURSOR_RIGHT, false);
839  EXPECT_EQ(ui::Range(3), render_text->selection());
840  render_text->MoveCursor(CHARACTER_BREAK, CURSOR_RIGHT, false);
841  EXPECT_EQ(ui::Range(5), render_text->selection());
842  render_text->MoveCursor(CHARACTER_BREAK, CURSOR_RIGHT, false);
843  EXPECT_EQ(ui::Range(4), render_text->selection());
844  render_text->MoveCursor(CHARACTER_BREAK, CURSOR_LEFT, true);
845  EXPECT_EQ(ui::Range(4, 5), render_text->selection());
846  render_text->MoveCursor(CHARACTER_BREAK, CURSOR_LEFT, true);
847  EXPECT_EQ(ui::Range(4, 6), render_text->selection());
848  render_text->MoveCursor(CHARACTER_BREAK, CURSOR_RIGHT, false);
849  EXPECT_EQ(ui::Range(4), render_text->selection());
850}
851#endif  // !defined(OS_MACOSX)
852
853// TODO(xji): Make these work on Windows.
854#if defined(OS_LINUX)
855void MoveLeftRightByWordVerifier(RenderText* render_text,
856                                 const wchar_t* str) {
857  render_text->SetText(WideToUTF16(str));
858
859  // Test moving by word from left ro right.
860  render_text->MoveCursor(LINE_BREAK, CURSOR_LEFT, false);
861  bool first_word = true;
862  while (true) {
863    // First, test moving by word from a word break position, such as from
864    // "|abc def" to "abc| def".
865    SelectionModel start = render_text->selection_model();
866    render_text->MoveCursor(WORD_BREAK, CURSOR_RIGHT, false);
867    SelectionModel end = render_text->selection_model();
868    if (end == start)  // reach the end.
869      break;
870
871    // For testing simplicity, each word is a 3-character word.
872    int num_of_character_moves = first_word ? 3 : 4;
873    first_word = false;
874    render_text->MoveCursorTo(start);
875    for (int j = 0; j < num_of_character_moves; ++j)
876      render_text->MoveCursor(CHARACTER_BREAK, CURSOR_RIGHT, false);
877    EXPECT_EQ(end, render_text->selection_model());
878
879    // Then, test moving by word from positions inside the word, such as from
880    // "a|bc def" to "abc| def", and from "ab|c def" to "abc| def".
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_RIGHT, false);
885      render_text->MoveCursor(WORD_BREAK, CURSOR_RIGHT, false);
886      EXPECT_EQ(end, render_text->selection_model());
887    }
888  }
889
890  // Test moving by word from right to left.
891  render_text->MoveCursor(LINE_BREAK, CURSOR_RIGHT, false);
892  first_word = true;
893  while (true) {
894    SelectionModel start = render_text->selection_model();
895    render_text->MoveCursor(WORD_BREAK, CURSOR_LEFT, false);
896    SelectionModel end = render_text->selection_model();
897    if (end == start)  // reach the end.
898      break;
899
900    int num_of_character_moves = first_word ? 3 : 4;
901    first_word = false;
902    render_text->MoveCursorTo(start);
903    for (int j = 0; j < num_of_character_moves; ++j)
904      render_text->MoveCursor(CHARACTER_BREAK, CURSOR_LEFT, false);
905    EXPECT_EQ(end, render_text->selection_model());
906
907    for (int j = 1; j < num_of_character_moves; ++j) {
908      render_text->MoveCursorTo(start);
909      for (int k = 0; k < j; ++k)
910        render_text->MoveCursor(CHARACTER_BREAK, CURSOR_LEFT, false);
911      render_text->MoveCursor(WORD_BREAK, CURSOR_LEFT, false);
912      EXPECT_EQ(end, render_text->selection_model());
913    }
914  }
915}
916
917TEST_F(RenderTextTest, MoveLeftRightByWordInBidiText) {
918  scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
919
920  // For testing simplicity, each word is a 3-character word.
921  std::vector<const wchar_t*> test;
922  test.push_back(L"abc");
923  test.push_back(L"abc def");
924  test.push_back(L"\x05E1\x05E2\x05E3");
925  test.push_back(L"\x05E1\x05E2\x05E3 \x05E4\x05E5\x05E6");
926  test.push_back(L"abc \x05E1\x05E2\x05E3");
927  test.push_back(L"abc def \x05E1\x05E2\x05E3 \x05E4\x05E5\x05E6");
928  test.push_back(L"abc def hij \x05E1\x05E2\x05E3 \x05E4\x05E5\x05E6"
929                 L" \x05E7\x05E8\x05E9");
930
931  test.push_back(L"abc \x05E1\x05E2\x05E3 hij");
932  test.push_back(L"abc def \x05E1\x05E2\x05E3 \x05E4\x05E5\x05E6 hij opq");
933  test.push_back(L"abc def hij \x05E1\x05E2\x05E3 \x05E4\x05E5\x05E6"
934                 L" \x05E7\x05E8\x05E9"L" opq rst uvw");
935
936  test.push_back(L"\x05E1\x05E2\x05E3 abc");
937  test.push_back(L"\x05E1\x05E2\x05E3 \x05E4\x05E5\x05E6 abc def");
938  test.push_back(L"\x05E1\x05E2\x05E3 \x05E4\x05E5\x05E6 \x05E7\x05E8\x05E9"
939                 L" abc def hij");
940
941  test.push_back(L"\x05D1\x05D2\x05D3 abc \x05E1\x05E2\x05E3");
942  test.push_back(L"\x05D1\x05D2\x05D3 \x05D4\x05D5\x05D6 abc def"
943                 L" \x05E1\x05E2\x05E3 \x05E4\x05E5\x05E6");
944  test.push_back(L"\x05D1\x05D2\x05D3 \x05D4\x05D5\x05D6 \x05D7\x05D8\x05D9"
945                 L" abc def hij \x05E1\x05E2\x05E3 \x05E4\x05E5\x05E6"
946                 L" \x05E7\x05E8\x05E9");
947
948  for (size_t i = 0; i < test.size(); ++i)
949    MoveLeftRightByWordVerifier(render_text.get(), test[i]);
950}
951
952TEST_F(RenderTextTest, MoveLeftRightByWordInBidiText_TestEndOfText) {
953  scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
954
955  render_text->SetText(WideToUTF16(L"ab\x05E1"));
956  // Moving the cursor by word from "abC|" to the left should return "|abC".
957  // But since end of text is always treated as a word break, it returns
958  // position "ab|C".
959  // TODO(xji): Need to make it work as expected.
960  render_text->MoveCursor(LINE_BREAK, CURSOR_RIGHT, false);
961  render_text->MoveCursor(WORD_BREAK, CURSOR_LEFT, false);
962  // EXPECT_EQ(SelectionModel(), render_text->selection_model());
963
964  // Moving the cursor by word from "|abC" to the right returns "abC|".
965  render_text->MoveCursor(LINE_BREAK, CURSOR_LEFT, false);
966  render_text->MoveCursor(WORD_BREAK, CURSOR_RIGHT, false);
967  EXPECT_EQ(SelectionModel(3, CURSOR_FORWARD), render_text->selection_model());
968
969  render_text->SetText(WideToUTF16(L"\x05E1\x05E2"L"a"));
970  // For logical text "BCa", moving the cursor by word from "aCB|" to the left
971  // returns "|aCB".
972  render_text->MoveCursor(LINE_BREAK, CURSOR_RIGHT, false);
973  render_text->MoveCursor(WORD_BREAK, CURSOR_LEFT, false);
974  EXPECT_EQ(SelectionModel(3, CURSOR_FORWARD), render_text->selection_model());
975
976  // Moving the cursor by word from "|aCB" to the right should return "aCB|".
977  // But since end of text is always treated as a word break, it returns
978  // position "a|CB".
979  // TODO(xji): Need to make it work as expected.
980  render_text->MoveCursor(LINE_BREAK, CURSOR_LEFT, false);
981  render_text->MoveCursor(WORD_BREAK, CURSOR_RIGHT, false);
982  // EXPECT_EQ(SelectionModel(), render_text->selection_model());
983}
984
985TEST_F(RenderTextTest, MoveLeftRightByWordInTextWithMultiSpaces) {
986  scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
987  render_text->SetText(WideToUTF16(L"abc     def"));
988  render_text->MoveCursorTo(SelectionModel(5, CURSOR_FORWARD));
989  render_text->MoveCursor(WORD_BREAK, CURSOR_RIGHT, false);
990  EXPECT_EQ(11U, render_text->cursor_position());
991
992  render_text->MoveCursorTo(SelectionModel(5, CURSOR_FORWARD));
993  render_text->MoveCursor(WORD_BREAK, CURSOR_LEFT, false);
994  EXPECT_EQ(0U, render_text->cursor_position());
995}
996
997TEST_F(RenderTextTest, MoveLeftRightByWordInChineseText) {
998  scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
999  render_text->SetText(WideToUTF16(L"\x6211\x4EEC\x53BB\x516C\x56ED\x73A9"));
1000  render_text->MoveCursor(LINE_BREAK, CURSOR_LEFT, false);
1001  EXPECT_EQ(0U, render_text->cursor_position());
1002  render_text->MoveCursor(WORD_BREAK, CURSOR_RIGHT, false);
1003  EXPECT_EQ(2U, render_text->cursor_position());
1004  render_text->MoveCursor(WORD_BREAK, CURSOR_RIGHT, false);
1005  EXPECT_EQ(3U, render_text->cursor_position());
1006  render_text->MoveCursor(WORD_BREAK, CURSOR_RIGHT, false);
1007  EXPECT_EQ(5U, render_text->cursor_position());
1008  render_text->MoveCursor(WORD_BREAK, CURSOR_RIGHT, false);
1009  EXPECT_EQ(6U, render_text->cursor_position());
1010  render_text->MoveCursor(WORD_BREAK, CURSOR_RIGHT, false);
1011  EXPECT_EQ(6U, render_text->cursor_position());
1012}
1013#endif
1014
1015TEST_F(RenderTextTest, StringSizeSanity) {
1016  scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
1017  render_text->SetText(UTF8ToUTF16("Hello World"));
1018  const Size string_size = render_text->GetStringSize();
1019  EXPECT_GT(string_size.width(), 0);
1020  EXPECT_GT(string_size.height(), 0);
1021}
1022
1023// TODO(asvitkine): This test fails because PlatformFontMac uses point font
1024//                  sizes instead of pixel sizes like other implementations.
1025#if !defined(OS_MACOSX)
1026TEST_F(RenderTextTest, StringSizeEmptyString) {
1027  const Font font;
1028  scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
1029  render_text->SetFont(font);
1030
1031  render_text->SetText(string16());
1032  EXPECT_EQ(font.GetHeight(), render_text->GetStringSize().height());
1033  EXPECT_EQ(0, render_text->GetStringSize().width());
1034
1035  render_text->SetText(UTF8ToUTF16(" "));
1036  EXPECT_EQ(font.GetHeight(), render_text->GetStringSize().height());
1037}
1038#endif  // !defined(OS_MACOSX)
1039
1040TEST_F(RenderTextTest, SetFont) {
1041  scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
1042  render_text->SetFont(Font("Arial", 12));
1043  EXPECT_EQ("Arial", render_text->GetFont().GetFontName());
1044  EXPECT_EQ(12, render_text->GetFont().GetFontSize());
1045}
1046
1047TEST_F(RenderTextTest, StringSizeBoldWidth) {
1048  scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
1049  render_text->SetText(UTF8ToUTF16("Hello World"));
1050
1051  const int plain_width = render_text->GetStringSize().width();
1052  EXPECT_GT(plain_width, 0);
1053
1054  // Apply a bold style and check that the new width is greater.
1055  StyleRange bold;
1056  bold.font_style |= Font::BOLD;
1057  render_text->set_default_style(bold);
1058  render_text->ApplyDefaultStyle();
1059
1060  const int bold_width = render_text->GetStringSize().width();
1061  EXPECT_GT(bold_width, plain_width);
1062
1063  // Now, apply a plain style over the first word only.
1064  StyleRange plain;
1065  plain.font_style = Font::NORMAL;
1066  plain.range = ui::Range(0, 5);
1067  render_text->ApplyStyleRange(plain);
1068
1069  const int plain_bold_width = render_text->GetStringSize().width();
1070  EXPECT_GT(plain_bold_width, plain_width);
1071  EXPECT_LT(plain_bold_width, bold_width);
1072}
1073
1074TEST_F(RenderTextTest, StringSizeHeight) {
1075  struct {
1076    string16 text;
1077  } cases[] = {
1078    { WideToUTF16(L"Hello World!") },  // English
1079    { WideToUTF16(L"\x6328\x62f6") },  // Japanese
1080    { WideToUTF16(L"\x0915\x093f") },  // Hindi
1081    { WideToUTF16(L"\x05e0\x05b8") },  // Hebrew
1082  };
1083
1084  Font default_font;
1085  Font larger_font = default_font.DeriveFont(24, default_font.GetStyle());
1086  EXPECT_GT(larger_font.GetHeight(), default_font.GetHeight());
1087
1088  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) {
1089    scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
1090    render_text->SetFont(default_font);
1091    render_text->SetText(cases[i].text);
1092
1093    const int height1 = render_text->GetStringSize().height();
1094    EXPECT_GT(height1, 0);
1095
1096    // Check that setting the larger font increases the height.
1097    render_text->SetFont(larger_font);
1098    const int height2 = render_text->GetStringSize().height();
1099    EXPECT_GT(height2, height1);
1100  }
1101}
1102
1103TEST_F(RenderTextTest, GetBaselineSanity) {
1104  scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
1105  render_text->SetText(UTF8ToUTF16("Hello World"));
1106  const int baseline = render_text->GetBaseline();
1107  EXPECT_GT(baseline, 0);
1108}
1109
1110TEST_F(RenderTextTest, CursorBoundsInReplacementMode) {
1111  scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
1112  render_text->SetText(ASCIIToUTF16("abcdefg"));
1113  render_text->SetDisplayRect(Rect(100, 17));
1114  SelectionModel sel_b(1, CURSOR_FORWARD);
1115  SelectionModel sel_c(2, CURSOR_FORWARD);
1116  Rect cursor_around_b = render_text->GetCursorBounds(sel_b, false);
1117  Rect cursor_before_b = render_text->GetCursorBounds(sel_b, true);
1118  Rect cursor_before_c = render_text->GetCursorBounds(sel_c, true);
1119  EXPECT_EQ(cursor_around_b.x(), cursor_before_b.x());
1120  EXPECT_EQ(cursor_around_b.right(), cursor_before_c.x());
1121}
1122
1123TEST_F(RenderTextTest, OriginForDrawing) {
1124  scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
1125  render_text->SetText(ASCIIToUTF16("abcdefg"));
1126  render_text->SetFontList(FontList("Arial, 13px"));
1127
1128  // Set display area's height equals to font height.
1129  const int font_height = render_text->GetStringSize().height();
1130  Rect display_rect(0, 0, 100, font_height);
1131  render_text->SetDisplayRect(display_rect);
1132
1133  Vector2d offset = render_text->GetOffsetForDrawing();
1134  EXPECT_TRUE(offset.IsZero());
1135
1136  // Set display area's height greater than font height.
1137  const int kEnlargement = 2;
1138  display_rect = Rect(0, 0, 100, font_height + kEnlargement);
1139  render_text->SetDisplayRect(display_rect);
1140
1141  // Text should be vertically centered.
1142  offset = render_text->GetOffsetForDrawing();
1143  EXPECT_EQ(offset.x(), 0);
1144  EXPECT_EQ(offset.y(), kEnlargement / 2);
1145}
1146
1147TEST_F(RenderTextTest, SameFontForParentheses) {
1148  struct {
1149    const char16 left_char;
1150    const char16 right_char;
1151  } punctuation_pairs[] = {
1152    { '(', ')' },
1153    { '{', '}' },
1154    { '<', '>' },
1155  };
1156  struct {
1157    string16 text;
1158  } cases[] = {
1159    // English(English)
1160    { WideToUTF16(L"Hello World(a)") },
1161    // English(English)English
1162    { WideToUTF16(L"Hello World(a)Hello World") },
1163
1164    // Japanese(English)
1165    { WideToUTF16(L"\x6328\x62f6(a)") },
1166    // Japanese(English)Japanese
1167    { WideToUTF16(L"\x6328\x62f6(a)\x6328\x62f6") },
1168    // English(Japanese)English
1169    { WideToUTF16(L"Hello World(\x6328\x62f6)Hello World") },
1170
1171    // Hindi(English)
1172    { WideToUTF16(L"\x0915\x093f(a)") },
1173    // Hindi(English)Hindi
1174    { WideToUTF16(L"\x0915\x093f(a)\x0915\x093f") },
1175    // English(Hindi)English
1176    { WideToUTF16(L"Hello World(\x0915\x093f)Hello World") },
1177
1178    // Hebrew(English)
1179    { WideToUTF16(L"\x05e0\x05b8(a)") },
1180    // Hebrew(English)Hebrew
1181    { WideToUTF16(L"\x05e0\x05b8(a)\x05e0\x05b8") },
1182    // English(Hebrew)English
1183    { WideToUTF16(L"Hello World(\x05e0\x05b8)Hello World") },
1184  };
1185
1186  scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
1187  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
1188    string16 text = cases[i].text;
1189    const size_t start_paren_char_index = text.find('(');
1190    ASSERT_NE(string16::npos, start_paren_char_index);
1191    const size_t end_paren_char_index = text.find(')');
1192    ASSERT_NE(string16::npos, end_paren_char_index);
1193
1194    for (size_t j = 0; j < ARRAYSIZE_UNSAFE(punctuation_pairs); ++j) {
1195      text[start_paren_char_index] = punctuation_pairs[j].left_char;
1196      text[end_paren_char_index] = punctuation_pairs[j].right_char;
1197      render_text->SetText(text);
1198
1199      const std::vector<RenderText::FontSpan> spans =
1200          render_text->GetFontSpansForTesting();
1201
1202      int start_paren_span_index = -1;
1203      int end_paren_span_index = -1;
1204      for (size_t k = 0; k < spans.size(); ++k) {
1205        if (IndexInRange(spans[k].second, start_paren_char_index))
1206          start_paren_span_index = k;
1207        if (IndexInRange(spans[k].second, end_paren_char_index))
1208          end_paren_span_index = k;
1209      }
1210      ASSERT_NE(-1, start_paren_span_index);
1211      ASSERT_NE(-1, end_paren_span_index);
1212
1213      const Font& start_font = spans[start_paren_span_index].first;
1214      const Font& end_font = spans[end_paren_span_index].first;
1215      EXPECT_EQ(start_font.GetFontName(), end_font.GetFontName());
1216      EXPECT_EQ(start_font.GetFontSize(), end_font.GetFontSize());
1217      EXPECT_EQ(start_font.GetStyle(), end_font.GetStyle());
1218    }
1219  }
1220}
1221
1222// TODO(asvitkine): Cursor movements tests disabled on Mac because RenderTextMac
1223//                  does not implement this yet. http://crbug.com/131618
1224#if !defined(OS_MACOSX)
1225TEST_F(RenderTextTest, DisplayRectShowsCursorLTR) {
1226  scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
1227  render_text->SetText(WideToUTF16(L"abcdefghijklmnopqrstuvwxzyabcdefg"));
1228  render_text->MoveCursorTo(SelectionModel(render_text->text().length(),
1229                                           CURSOR_FORWARD));
1230  int width = render_text->GetStringSize().width();
1231  ASSERT_GT(width, 10);
1232
1233  // Ensure that the cursor is placed at the width of its preceding text.
1234  render_text->SetDisplayRect(Rect(width + 10, 1));
1235  EXPECT_EQ(width, render_text->GetUpdatedCursorBounds().x());
1236
1237  // Ensure that shrinking the display rectangle keeps the cursor in view.
1238  render_text->SetDisplayRect(Rect(width - 10, 1));
1239  EXPECT_EQ(render_text->display_rect().width() - 1,
1240            render_text->GetUpdatedCursorBounds().x());
1241
1242  // Ensure that the text will pan to fill its expanding display rectangle.
1243  render_text->SetDisplayRect(Rect(width - 5, 1));
1244  EXPECT_EQ(render_text->display_rect().width() - 1,
1245            render_text->GetUpdatedCursorBounds().x());
1246
1247  // Ensure that a sufficiently large display rectangle shows all the text.
1248  render_text->SetDisplayRect(Rect(width + 10, 1));
1249  EXPECT_EQ(width, render_text->GetUpdatedCursorBounds().x());
1250
1251  // Repeat the test with RTL text.
1252  render_text->SetText(WideToUTF16(L"\x5d0\x5d1\x5d2\x5d3\x5d4\x5d5\x5d6\x5d7"
1253      L"\x5d8\x5d9\x5da\x5db\x5dc\x5dd\x5de\x5df"));
1254  render_text->MoveCursorTo(SelectionModel(0, CURSOR_FORWARD));
1255  width = render_text->GetStringSize().width();
1256  ASSERT_GT(width, 10);
1257
1258  // Ensure that the cursor is placed at the width of its preceding text.
1259  render_text->SetDisplayRect(Rect(width + 10, 1));
1260  EXPECT_EQ(width, render_text->GetUpdatedCursorBounds().x());
1261
1262  // Ensure that shrinking the display rectangle keeps the cursor in view.
1263  render_text->SetDisplayRect(Rect(width - 10, 1));
1264  EXPECT_EQ(render_text->display_rect().width() - 1,
1265            render_text->GetUpdatedCursorBounds().x());
1266
1267  // Ensure that the text will pan to fill its expanding display rectangle.
1268  render_text->SetDisplayRect(Rect(width - 5, 1));
1269  EXPECT_EQ(render_text->display_rect().width() - 1,
1270            render_text->GetUpdatedCursorBounds().x());
1271
1272  // Ensure that a sufficiently large display rectangle shows all the text.
1273  render_text->SetDisplayRect(Rect(width + 10, 1));
1274  EXPECT_EQ(width, render_text->GetUpdatedCursorBounds().x());
1275}
1276
1277TEST_F(RenderTextTest, DisplayRectShowsCursorRTL) {
1278  // Set the application default text direction to RTL.
1279  const bool was_rtl = base::i18n::IsRTL();
1280  SetRTL(true);
1281
1282  scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
1283  render_text->SetText(WideToUTF16(L"abcdefghijklmnopqrstuvwxzyabcdefg"));
1284  render_text->MoveCursorTo(SelectionModel(0, CURSOR_FORWARD));
1285  int width = render_text->GetStringSize().width();
1286  ASSERT_GT(width, 10);
1287
1288  // Ensure that the cursor is placed at the width of its preceding text.
1289  render_text->SetDisplayRect(Rect(width + 10, 1));
1290  EXPECT_EQ(render_text->display_rect().width() - width - 1,
1291            render_text->GetUpdatedCursorBounds().x());
1292
1293  // Ensure that shrinking the display rectangle keeps the cursor in view.
1294  render_text->SetDisplayRect(Rect(width - 10, 1));
1295  EXPECT_EQ(0, render_text->GetUpdatedCursorBounds().x());
1296
1297  // Ensure that the text will pan to fill its expanding display rectangle.
1298  render_text->SetDisplayRect(Rect(width - 5, 1));
1299  EXPECT_EQ(0, render_text->GetUpdatedCursorBounds().x());
1300
1301  // Ensure that a sufficiently large display rectangle shows all the text.
1302  render_text->SetDisplayRect(Rect(width + 10, 1));
1303  EXPECT_EQ(render_text->display_rect().width() - width - 1,
1304            render_text->GetUpdatedCursorBounds().x());
1305
1306  // Repeat the test with RTL text.
1307  render_text->SetText(WideToUTF16(L"\x5d0\x5d1\x5d2\x5d3\x5d4\x5d5\x5d6\x5d7"
1308      L"\x5d8\x5d9\x5da\x5db\x5dc\x5dd\x5de\x5df"));
1309  render_text->MoveCursorTo(SelectionModel(render_text->text().length(),
1310                                           CURSOR_FORWARD));
1311  width = render_text->GetStringSize().width();
1312  ASSERT_GT(width, 10);
1313
1314  // Ensure that the cursor is placed at the width of its preceding text.
1315  render_text->SetDisplayRect(Rect(width + 10, 1));
1316  EXPECT_EQ(render_text->display_rect().width() - width - 1,
1317            render_text->GetUpdatedCursorBounds().x());
1318
1319  // Ensure that shrinking the display rectangle keeps the cursor in view.
1320  render_text->SetDisplayRect(Rect(width - 10, 1));
1321  EXPECT_EQ(0, render_text->GetUpdatedCursorBounds().x());
1322
1323  // Ensure that the text will pan to fill its expanding display rectangle.
1324  render_text->SetDisplayRect(Rect(width - 5, 1));
1325  EXPECT_EQ(0, render_text->GetUpdatedCursorBounds().x());
1326
1327  // Ensure that a sufficiently large display rectangle shows all the text.
1328  render_text->SetDisplayRect(Rect(width + 10, 1));
1329  EXPECT_EQ(render_text->display_rect().width() - width - 1,
1330            render_text->GetUpdatedCursorBounds().x());
1331
1332  // Reset the application default text direction to LTR.
1333  SetRTL(was_rtl);
1334  EXPECT_EQ(was_rtl, base::i18n::IsRTL());
1335}
1336#endif  // !defined(OS_MACOSX)
1337
1338}  // namespace gfx
1339