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"
13 #include "base/win/windows_version.h"
17 #include "ui/gfx/render_text_linux.h"
20 #if defined(TOOLKIT_GTK)
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
);
57 EXPECT_EQ(rtl
, base::i18n::IsRTL());
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.
94 render_text
->SetStyle(STRIKE
, true);
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));
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
);
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
,
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
) {
379 const base::i18n::TextDirection text_direction
;
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());
445 render_text
->SetText(ASCIIToUTF16("abc"));
446 // |expected| saves the expected SelectionModel when moving cursor from left
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
);
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());
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
);
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());
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
);
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());
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
);
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());
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
);
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());
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
);
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());
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");
649 size_t expected_previous
;
650 size_t expected_next
;
652 { base::string16(), 0, 0, 0 },
653 { base::string16(), 1, 0, 0 },
654 { base::string16(), 50, 0, 0 },
664 { kText1
, 50, 7, 7 },
673 { kText2
, 50, 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
688 if (base::win::GetVersion() < base::win::VERSION_VISTA
)
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
,
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
,
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");
724 base::i18n::TextDirection expected_text_direction
;
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
737 if (base::win::GetVersion() < base::win::VERSION_VISTA
)
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;
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.
845 // For testing simplicity, each word is a 3-character word.
846 int num_of_character_moves
= first_word
? 3 : 4;
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);
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.
874 int num_of_character_moves
= first_word
? 3 : 4;
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"
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
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
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
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());
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
) {
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
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();
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());
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();
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());
1159 TEST_F(RenderTextTest
, SameFontForParentheses
) {
1161 const char16 left_char
;
1162 const char16 right_char
;
1163 } punctuation_pairs
[] = {
1169 base::string16 text
;
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") },
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") },
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(),
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
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();
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(),
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.
1400 EXPECT_EQ(was_rtl
, base::i18n::IsRTL());
1402 #endif // !defined(OS_MACOSX)