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