15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/render_text.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include <algorithm>
8a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
9d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "base/format_macros.h"
105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/i18n/break_iterator.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
12a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "base/strings/string_util.h"
13eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/strings/stringprintf.h"
14868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h"
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/gfx/break_list.h"
17a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "ui/gfx/canvas.h"
18f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "ui/gfx/render_text_harfbuzz.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/windows_version.h"
22558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch#include "ui/gfx/render_text_win.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#if defined(OS_LINUX) && !defined(USE_OZONE)
26f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ui/gfx/render_text_pango.h"
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using base::ASCIIToUTF16;
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using base::UTF8ToUTF16;
315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using base::WideToUTF16;
325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace gfx {
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Various weak, LTR, RTL, and Bidi string cases with three characters each.
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const wchar_t kWeak[] =      L" . ";
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const wchar_t kLtr[] =       L"abc";
4068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const wchar_t kRtl[] =       L"\x5d0\x5d1\x5d2";
4168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#if !defined(OS_MACOSX)
42bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdochconst wchar_t kLtrRtl[] =    L"a" L"\x5d0\x5d1";
43bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdochconst wchar_t kLtrRtlLtr[] = L"a" L"\x5d1" L"b";
44bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdochconst wchar_t kRtlLtr[] =    L"\x5d0\x5d1" L"a";
45bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdochconst wchar_t kRtlLtrRtl[] = L"\x5d0" L"a" L"\x5d1";
4668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#endif
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Checks whether |range| contains |index|. This is not the same as calling
49010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)// range.Contains(Range(index)), which returns true if |index| == |range.end()|.
50d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)bool IndexInRange(const Range& range, size_t index) {
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return index >= range.start() && index < range.end();
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
54a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)base::string16 GetSelectedText(RenderText* render_text) {
55a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  return render_text->text().substr(render_text->selection().GetMin(),
56a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)                                    render_text->selection().length());
57a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)}
58a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A test utility function to set the application default text direction.
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SetRTL(bool rtl) {
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Override the current locale/direction.
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::i18n::SetICUDefaultLocale(rtl ? "he" : "en");
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(rtl, base::i18n::IsRTL());
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
66f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#if !defined(OS_MACOSX)
67eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Ensure cursor movement in the specified |direction| yields |expected| values.
68eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid RunMoveCursorLeftRightTest(RenderText* render_text,
69eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                const std::vector<SelectionModel>& expected,
70eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                VisualCursorDirection direction) {
71eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  for (size_t i = 0; i < expected.size(); ++i) {
72eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    SCOPED_TRACE(base::StringPrintf("Going %s; expected value index %d.",
73eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        direction == CURSOR_LEFT ? "left" : "right", static_cast<int>(i)));
74eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    EXPECT_EQ(expected[i], render_text->selection_model());
75eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    render_text->MoveCursor(CHARACTER_BREAK, direction, false);
76eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
77eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Check that cursoring is clamped at the line edge.
78eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(expected.back(), render_text->selection_model());
79eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Check that it is the line edge.
80eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  render_text->MoveCursor(LINE_BREAK, direction, false);
81eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(expected.back(), render_text->selection_model());
82eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
83f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#endif  // !defined(OS_MACOSX)
84eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class RenderTextTest : public testing::Test {
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(RenderTextTest, DefaultStyle) {
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Check the default styles applied to new instances and adjusted text.
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_TRUE(render_text->text().empty());
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const wchar_t* const cases[] = { kWeak, kLtr, L"Hello", kRtl, L"", L"" };
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < arraysize(cases); ++i) {
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    EXPECT_TRUE(render_text->colors().EqualsValueForTesting(SK_ColorBLACK));
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (size_t style = 0; style < NUM_TEXT_STYLES; ++style)
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      EXPECT_TRUE(render_text->styles()[style].EqualsValueForTesting(false));
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    render_text->SetText(WideToUTF16(cases[i]));
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TEST_F(RenderTextTest, SetColorAndStyle) {
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Ensure custom default styles persist across setting and clearing text.
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const SkColor color = SK_ColorRED;
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  render_text->SetColor(color);
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  render_text->SetStyle(BOLD, true);
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  render_text->SetStyle(UNDERLINE, false);
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const wchar_t* const cases[] = { kWeak, kLtr, L"Hello", kRtl, L"", L"" };
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < arraysize(cases); ++i) {
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    EXPECT_TRUE(render_text->colors().EqualsValueForTesting(color));
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    EXPECT_TRUE(render_text->styles()[BOLD].EqualsValueForTesting(true));
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    EXPECT_TRUE(render_text->styles()[UNDERLINE].EqualsValueForTesting(false));
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    render_text->SetText(WideToUTF16(cases[i]));
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Ensure custom default styles can be applied after text has been set.
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (i == 1)
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      render_text->SetStyle(STRIKE, true);
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (i >= 1)
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      EXPECT_TRUE(render_text->styles()[STRIKE].EqualsValueForTesting(true));
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TEST_F(RenderTextTest, ApplyColorAndStyle) {
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  render_text->SetText(ASCIIToUTF16("012345678"));
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Apply a ranged color and style and check the resulting breaks.
130d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  render_text->ApplyColor(SK_ColorRED, Range(1, 4));
131d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  render_text->ApplyStyle(BOLD, true, Range(2, 5));
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<std::pair<size_t, SkColor> > expected_color;
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  expected_color.push_back(std::pair<size_t, SkColor>(0, SK_ColorBLACK));
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  expected_color.push_back(std::pair<size_t, SkColor>(1, SK_ColorRED));
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  expected_color.push_back(std::pair<size_t, SkColor>(4, SK_ColorBLACK));
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_TRUE(render_text->colors().EqualsForTesting(expected_color));
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<std::pair<size_t, bool> > expected_style;
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  expected_style.push_back(std::pair<size_t, bool>(0, false));
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  expected_style.push_back(std::pair<size_t, bool>(2, true));
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  expected_style.push_back(std::pair<size_t, bool>(5, false));
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_TRUE(render_text->styles()[BOLD].EqualsForTesting(expected_style));
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Ensure setting a color and style overrides the ranged colors and styles.
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  render_text->SetColor(SK_ColorBLUE);
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_TRUE(render_text->colors().EqualsValueForTesting(SK_ColorBLUE));
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  render_text->SetStyle(BOLD, false);
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_TRUE(render_text->styles()[BOLD].EqualsValueForTesting(false));
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Apply a color and style over the text end and check the resulting breaks.
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // (INT_MAX should be used instead of the text length for the range end)
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const size_t text_length = render_text->text().length();
152d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  render_text->ApplyColor(SK_ColorRED, Range(0, text_length));
153d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  render_text->ApplyStyle(BOLD, true, Range(2, text_length));
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<std::pair<size_t, SkColor> > expected_color_end;
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  expected_color_end.push_back(std::pair<size_t, SkColor>(0, SK_ColorRED));
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_TRUE(render_text->colors().EqualsForTesting(expected_color_end));
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<std::pair<size_t, bool> > expected_style_end;
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  expected_style_end.push_back(std::pair<size_t, bool>(0, false));
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  expected_style_end.push_back(std::pair<size_t, bool>(2, true));
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_TRUE(render_text->styles()[BOLD].EqualsForTesting(expected_style_end));
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Ensure ranged values adjust to accommodate text length changes.
163d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  render_text->ApplyStyle(ITALIC, true, Range(0, 2));
164d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  render_text->ApplyStyle(ITALIC, true, Range(3, 6));
165d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  render_text->ApplyStyle(ITALIC, true, Range(7, text_length));
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<std::pair<size_t, bool> > expected_italic;
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  expected_italic.push_back(std::pair<size_t, bool>(0, true));
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  expected_italic.push_back(std::pair<size_t, bool>(2, false));
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  expected_italic.push_back(std::pair<size_t, bool>(3, true));
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  expected_italic.push_back(std::pair<size_t, bool>(6, false));
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  expected_italic.push_back(std::pair<size_t, bool>(7, true));
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_TRUE(render_text->styles()[ITALIC].EqualsForTesting(expected_italic));
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Changing the text should clear any breaks except for the first one.
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  render_text->SetText(ASCIIToUTF16("0123456"));
1761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  expected_italic.resize(1);
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_TRUE(render_text->styles()[ITALIC].EqualsForTesting(expected_italic));
1781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  render_text->ApplyStyle(ITALIC, false, Range(2, 4));
1791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  render_text->SetText(ASCIIToUTF16("012345678"));
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_TRUE(render_text->styles()[ITALIC].EqualsForTesting(expected_italic));
1811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  render_text->ApplyStyle(ITALIC, false, Range(0, 1));
1821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  render_text->SetText(ASCIIToUTF16("0123456"));
1831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  expected_italic.begin()->second = false;
1841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  EXPECT_TRUE(render_text->styles()[ITALIC].EqualsForTesting(expected_italic));
1851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  render_text->ApplyStyle(ITALIC, true, Range(2, 4));
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  render_text->SetText(ASCIIToUTF16("012345678"));
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_TRUE(render_text->styles()[ITALIC].EqualsForTesting(expected_italic));
1881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // TODO(tmoniuszko): Enable when RenderTextMac::IsValidCursorIndex is
1901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  //                   implemented.
1911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#if !defined(OS_MACOSX)
1921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Styles shouldn't be changed mid-grapheme.
1931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  render_text->SetText(WideToUTF16(
1941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      L"0" L"\x0915\x093f" L"1" L"\x0915\x093f" L"2"));
1951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  render_text->ApplyStyle(UNDERLINE, true, Range(2, 5));
1961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  std::vector<std::pair<size_t, bool> > expected_underline;
1971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  expected_underline.push_back(std::pair<size_t, bool>(0, false));
1981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  expected_underline.push_back(std::pair<size_t, bool>(1, true));
1991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  expected_underline.push_back(std::pair<size_t, bool>(6, false));
2001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  EXPECT_TRUE(render_text->styles()[UNDERLINE].EqualsForTesting(
2011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      expected_underline));
2021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#endif  // OS_MACOSX
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
205f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#if defined(OS_LINUX) && !defined(USE_OZONE)
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TEST_F(RenderTextTest, PangoAttributes) {
2076e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  scoped_ptr<RenderText> render_text(RenderText::CreateNativeInstance());
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  render_text->SetText(ASCIIToUTF16("012345678"));
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Apply ranged BOLD/ITALIC styles and check the resulting Pango attributes.
211d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  render_text->ApplyStyle(BOLD, true, Range(2, 4));
212d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  render_text->ApplyStyle(ITALIC, true, Range(1, 3));
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  struct {
2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int start;
2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int end;
2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bool bold;
2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bool italic;
2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } cases[] = {
2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    { 0, 1,       false, false },
2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    { 1, 2,       false, true  },
2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    { 2, 3,       true,  true  },
2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    { 3, 4,       true,  false },
2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    { 4, INT_MAX, false, false },
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  };
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int start = 0, end = 0;
228f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  RenderTextPango* rt_linux = static_cast<RenderTextPango*>(render_text.get());
2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  rt_linux->EnsureLayout();
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  PangoAttrList* attributes = pango_layout_get_attributes(rt_linux->layout_);
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  PangoAttrIterator* iter = pango_attr_list_get_iterator(attributes);
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    pango_attr_iterator_range(iter, &start, &end);
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    EXPECT_EQ(cases[i].start, start);
2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    EXPECT_EQ(cases[i].end, end);
2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    PangoFontDescription* font = pango_font_description_new();
2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    pango_attr_iterator_get_font(iter, font, NULL, NULL);
2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    char* description_string = pango_font_description_to_string(font);
239868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const base::string16 desc = ASCIIToUTF16(description_string);
2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const bool bold = desc.find(ASCIIToUTF16("Bold")) != std::string::npos;
2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    EXPECT_EQ(cases[i].bold, bold);
2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const bool italic = desc.find(ASCIIToUTF16("Italic")) != std::string::npos;
2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    EXPECT_EQ(cases[i].italic, italic);
2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    pango_attr_iterator_next(iter);
2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    pango_font_description_free(font);
2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    g_free(description_string);
2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_FALSE(pango_attr_iterator_next(iter));
2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  pango_attr_iterator_destroy(iter);
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(asvitkine): Cursor movements tests disabled on Mac because RenderTextMac
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//                  does not implement this yet. http://crbug.com/131618
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(OS_MACOSX)
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TestVisualCursorMotionInObscuredField(RenderText* render_text,
257868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                           const base::string16& text,
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           bool select) {
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(render_text->obscured());
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  render_text->SetText(text);
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int len = text.length();
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  render_text->MoveCursor(LINE_BREAK, CURSOR_RIGHT, select);
263d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  EXPECT_EQ(SelectionModel(Range(select ? 0 : len, len), CURSOR_FORWARD),
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            render_text->selection_model());
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  render_text->MoveCursor(LINE_BREAK, CURSOR_LEFT, select);
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(SelectionModel(0, CURSOR_BACKWARD), render_text->selection_model());
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int j = 1; j <= len; ++j) {
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    render_text->MoveCursor(CHARACTER_BREAK, CURSOR_RIGHT, select);
269d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    EXPECT_EQ(SelectionModel(Range(select ? 0 : j, j), CURSOR_BACKWARD),
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              render_text->selection_model());
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int j = len - 1; j >= 0; --j) {
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    render_text->MoveCursor(CHARACTER_BREAK, CURSOR_LEFT, select);
274d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    EXPECT_EQ(SelectionModel(Range(select ? 0 : j, j), CURSOR_FORWARD),
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              render_text->selection_model());
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  render_text->MoveCursor(WORD_BREAK, CURSOR_RIGHT, select);
278d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  EXPECT_EQ(SelectionModel(Range(select ? 0 : len, len), CURSOR_FORWARD),
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            render_text->selection_model());
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  render_text->MoveCursor(WORD_BREAK, CURSOR_LEFT, select);
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(SelectionModel(0, CURSOR_BACKWARD), render_text->selection_model());
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(RenderTextTest, ObscuredText) {
285868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  const base::string16 seuss = ASCIIToUTF16("hop on pop");
286868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  const base::string16 no_seuss = ASCIIToUTF16("**********");
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // GetLayoutText() returns asterisks when the obscured bit is set.
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  render_text->SetText(seuss);
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  render_text->SetObscured(true);
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(seuss, render_text->text());
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(no_seuss, render_text->GetLayoutText());
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  render_text->SetObscured(false);
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(seuss, render_text->text());
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(seuss, render_text->GetLayoutText());
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  render_text->SetObscured(true);
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Surrogate pairs are counted as one code point.
3015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const base::char16 invalid_surrogates[] = {0xDC00, 0xD800, 0};
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  render_text->SetText(invalid_surrogates);
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(ASCIIToUTF16("**"), render_text->GetLayoutText());
3045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const base::char16 valid_surrogates[] = {0xD800, 0xDC00, 0};
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  render_text->SetText(valid_surrogates);
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(ASCIIToUTF16("*"), render_text->GetLayoutText());
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(0U, render_text->cursor_position());
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  render_text->MoveCursor(CHARACTER_BREAK, CURSOR_RIGHT, false);
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(2U, render_text->cursor_position());
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Test index conversion and cursor validity with a valid surrogate pair.
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(0U, render_text->TextIndexToLayoutIndex(0U));
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(1U, render_text->TextIndexToLayoutIndex(1U));
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(1U, render_text->TextIndexToLayoutIndex(2U));
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(0U, render_text->LayoutIndexToTextIndex(0U));
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(2U, render_text->LayoutIndexToTextIndex(1U));
317010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  EXPECT_TRUE(render_text->IsValidCursorIndex(0U));
318010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  EXPECT_FALSE(render_text->IsValidCursorIndex(1U));
319010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  EXPECT_TRUE(render_text->IsValidCursorIndex(2U));
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // FindCursorPosition() should not return positions between a surrogate pair.
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  render_text->SetDisplayRect(Rect(0, 0, 20, 20));
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(render_text->FindCursorPosition(Point(0, 0)).caret_pos(), 0U);
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(render_text->FindCursorPosition(Point(20, 0)).caret_pos(), 2U);
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int x = -1; x <= 20; ++x) {
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SelectionModel selection = render_text->FindCursorPosition(Point(x, 0));
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_TRUE(selection.caret_pos() == 0U || selection.caret_pos() == 2U);
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // GetGlyphBounds() should yield the entire string bounds for text index 0.
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(render_text->GetStringSize().width(),
33290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            static_cast<int>(render_text->GetGlyphBounds(0U).length()));
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Cursoring is independent of underlying characters when text is obscured.
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const wchar_t* const texts[] = {
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    kWeak, kLtr, kLtrRtl, kLtrRtlLtr, kRtl, kRtlLtr, kRtlLtrRtl,
3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    L"hop on pop",                              // Check LTR word boundaries.
3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    L"\x05d0\x05d1 \x05d0\x05d2 \x05d1\x05d2",  // Check RTL word boundaries.
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < arraysize(texts); ++i) {
341868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    base::string16 text = WideToUTF16(texts[i]);
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TestVisualCursorMotionInObscuredField(render_text.get(), text, false);
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TestVisualCursorMotionInObscuredField(render_text.get(), text, true);
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
347868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)TEST_F(RenderTextTest, RevealObscuredText) {
348868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  const base::string16 seuss = ASCIIToUTF16("hop on pop");
349868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  const base::string16 no_seuss = ASCIIToUTF16("**********");
350868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
351868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
352868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  render_text->SetText(seuss);
353868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  render_text->SetObscured(true);
354868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  EXPECT_EQ(seuss, render_text->text());
355868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  EXPECT_EQ(no_seuss, render_text->GetLayoutText());
356868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
357868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Valid reveal index and new revealed index clears previous one.
358868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  render_text->RenderText::SetObscuredRevealIndex(0);
359868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  EXPECT_EQ(ASCIIToUTF16("h*********"), render_text->GetLayoutText());
360868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  render_text->RenderText::SetObscuredRevealIndex(1);
361868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  EXPECT_EQ(ASCIIToUTF16("*o********"), render_text->GetLayoutText());
362868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  render_text->RenderText::SetObscuredRevealIndex(2);
363868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  EXPECT_EQ(ASCIIToUTF16("**p*******"), render_text->GetLayoutText());
364868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
365868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Invalid reveal index.
366868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  render_text->RenderText::SetObscuredRevealIndex(-1);
367868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  EXPECT_EQ(no_seuss, render_text->GetLayoutText());
368868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  render_text->RenderText::SetObscuredRevealIndex(seuss.length() + 1);
369868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  EXPECT_EQ(no_seuss, render_text->GetLayoutText());
370868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
371868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // SetObscured clears the revealed index.
372868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  render_text->RenderText::SetObscuredRevealIndex(0);
373868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  EXPECT_EQ(ASCIIToUTF16("h*********"), render_text->GetLayoutText());
374868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  render_text->SetObscured(false);
375868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  EXPECT_EQ(seuss, render_text->GetLayoutText());
376868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  render_text->SetObscured(true);
377868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  EXPECT_EQ(no_seuss, render_text->GetLayoutText());
378868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
379868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // SetText clears the revealed index.
380868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  render_text->SetText(ASCIIToUTF16("new"));
381868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  EXPECT_EQ(ASCIIToUTF16("***"), render_text->GetLayoutText());
382868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  render_text->RenderText::SetObscuredRevealIndex(2);
383868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  EXPECT_EQ(ASCIIToUTF16("**w"), render_text->GetLayoutText());
384868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  render_text->SetText(ASCIIToUTF16("new longer"));
385868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  EXPECT_EQ(ASCIIToUTF16("**********"), render_text->GetLayoutText());
386868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
387868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Text with invalid surrogates.
3885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const base::char16 invalid_surrogates[] = {0xDC00, 0xD800, 'h', 'o', 'p', 0};
389868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  render_text->SetText(invalid_surrogates);
390868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  EXPECT_EQ(ASCIIToUTF16("*****"), render_text->GetLayoutText());
391868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  render_text->RenderText::SetObscuredRevealIndex(0);
3925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const base::char16 invalid_expect_0[] = {0xDC00, '*', '*', '*', '*', 0};
393868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  EXPECT_EQ(invalid_expect_0, render_text->GetLayoutText());
394868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  render_text->RenderText::SetObscuredRevealIndex(1);
3955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const base::char16 invalid_expect_1[] = {'*', 0xD800, '*', '*', '*', 0};
396868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  EXPECT_EQ(invalid_expect_1, render_text->GetLayoutText());
397868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  render_text->RenderText::SetObscuredRevealIndex(2);
398868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  EXPECT_EQ(ASCIIToUTF16("**h**"), render_text->GetLayoutText());
399868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
400868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Text with valid surrogates before and after the reveal index.
4015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const base::char16 valid_surrogates[] =
402868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      {0xD800, 0xDC00, 'h', 'o', 'p', 0xD800, 0xDC00, 0};
403868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  render_text->SetText(valid_surrogates);
404868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  EXPECT_EQ(ASCIIToUTF16("*****"), render_text->GetLayoutText());
405868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  render_text->RenderText::SetObscuredRevealIndex(0);
4065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const base::char16 valid_expect_0_and_1[] =
4075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      {0xD800, 0xDC00, '*', '*', '*', '*', 0};
408868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  EXPECT_EQ(valid_expect_0_and_1, render_text->GetLayoutText());
409868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  render_text->RenderText::SetObscuredRevealIndex(1);
410868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  EXPECT_EQ(valid_expect_0_and_1, render_text->GetLayoutText());
411868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  render_text->RenderText::SetObscuredRevealIndex(2);
412868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  EXPECT_EQ(ASCIIToUTF16("*h***"), render_text->GetLayoutText());
413868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  render_text->RenderText::SetObscuredRevealIndex(5);
4145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const base::char16 valid_expect_5_and_6[] =
4155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      {'*', '*', '*', '*', 0xD800, 0xDC00, 0};
416868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  EXPECT_EQ(valid_expect_5_and_6, render_text->GetLayoutText());
417868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  render_text->RenderText::SetObscuredRevealIndex(6);
418868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  EXPECT_EQ(valid_expect_5_and_6, render_text->GetLayoutText());
419868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
420868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
4215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(RenderTextTest, ElidedText) {
4225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // TODO(skanuj) : Add more test cases for following
4235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // - RenderText styles.
4245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // - Cross interaction of truncate, elide and obscure.
4255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // - ElideText tests from text_elider.cc.
4265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  struct {
4275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const wchar_t* text;
4285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const wchar_t* layout_text;
4295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const bool elision_expected;
4305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  } cases[] = {
4315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Strings shorter than the elision width should be laid out in full.
4325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    { L"",        L""       , false },
433a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    { L"M",       L""       , false },
434a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    { L" . ",     L" . "    , false },
4355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    { kWeak,      kWeak     , false },
4365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    { kLtr,       kLtr      , false },
4375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    { kLtrRtl,    kLtrRtl   , false },
4385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    { kLtrRtlLtr, kLtrRtlLtr, false },
4395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    { kRtl,       kRtl      , false },
4405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    { kRtlLtr,    kRtlLtr   , false },
4415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    { kRtlLtrRtl, kRtlLtrRtl, false },
4425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Strings as long as the elision width should be laid out in full.
4435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    { L"012ab",   L"012ab"  , false },
4445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Long strings should be elided with an ellipsis appended at the end.
4455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    { L"012abc",              L"012a\x2026", true },
4465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    { L"012ab" L"\x5d0\x5d1", L"012a\x2026", true },
4475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    { L"012a" L"\x5d1" L"b",  L"012a\x2026", true },
4485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // No RLM marker added as digits (012) have weak directionality.
4495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    { L"01" L"\x5d0\x5d1\x5d2", L"01\x5d0\x5d1\x2026", true },
4505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // RLM marker added as "ab" have strong LTR directionality.
4515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    { L"ab" L"\x5d0\x5d1\x5d2", L"ab\x5d0\x5d1\x2026\x200f", true },
4525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Complex script is not handled. In this example, the "\x0915\x093f" is a
4535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // compound glyph, but only half of it is elided.
4545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    { L"0123\x0915\x093f", L"0123\x0915\x2026", true },
4555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Surrogate pairs should be elided reasonably enough.
4565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    { L"0\x05e9\x05bc\x05c1\x05b8",   L"0\x05e9\x05bc\x05c1\x05b8", false },
4575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    { L"0\x05e9\x05bc\x05c1\x05b8",   L"0\x05e9\x05bc\x2026"      , true  },
4585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    { L"01\x05e9\x05bc\x05c1\x05b8",  L"01\x05e9\x2026"           , true  },
459a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    { L"012\x05e9\x05bc\x05c1\x05b8", L"012\x2026\x200E"          , true  },
4605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    { L"012\xF0\x9D\x84\x9E",         L"012\xF0\x2026"            , true  },
4615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  };
4625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<RenderText> expected_render_text(RenderText::CreateInstance());
4645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  expected_render_text->SetFontList(FontList("serif, Sans serif, 12px"));
465010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  expected_render_text->SetDisplayRect(Rect(0, 0, 9999, 100));
4665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
4685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  render_text->SetFontList(FontList("serif, Sans serif, 12px"));
46946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  render_text->SetElideBehavior(ELIDE_TAIL);
4705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) {
4725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Compute expected width
4735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    expected_render_text->SetText(WideToUTF16(cases[i].layout_text));
4745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int expected_width = expected_render_text->GetContentWidth();
4755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::string16 input = WideToUTF16(cases[i].text);
4775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Extend the input text to ensure that it is wider than the layout_text,
4785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // and so it will get elided.
4795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (cases[i].elision_expected)
4805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      input.append(WideToUTF16(L" MMMMMMMMMMM"));
4815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    render_text->SetText(input);
483010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    render_text->SetDisplayRect(Rect(0, 0, expected_width, 100));
484a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    EXPECT_EQ(input, render_text->text())
485a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        << "->For case " << i << ": " << cases[i].text << "\n";
4865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EXPECT_EQ(WideToUTF16(cases[i].layout_text), render_text->GetLayoutText())
4875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        << "->For case " << i << ": " << cases[i].text << "\n";
4885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    expected_render_text->SetText(base::string16());
4895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
4905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
4915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(RenderTextTest, ElidedObscuredText) {
4935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<RenderText> expected_render_text(RenderText::CreateInstance());
4945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  expected_render_text->SetFontList(FontList("serif, Sans serif, 12px"));
495010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  expected_render_text->SetDisplayRect(Rect(0, 0, 9999, 100));
4965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  expected_render_text->SetText(WideToUTF16(L"**\x2026"));
4975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
4995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  render_text->SetFontList(FontList("serif, Sans serif, 12px"));
50046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  render_text->SetElideBehavior(ELIDE_TAIL);
5015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  render_text->SetDisplayRect(
502010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      Rect(0, 0, expected_render_text->GetContentWidth(), 100));
5035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  render_text->SetObscured(true);
5045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  render_text->SetText(WideToUTF16(L"abcdef"));
5055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(WideToUTF16(L"abcdef"), render_text->text());
5065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(WideToUTF16(L"**\x2026"), render_text->GetLayoutText());
5075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
5085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
509eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochTEST_F(RenderTextTest, TruncatedText) {
510eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  struct {
511eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const wchar_t* text;
512eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const wchar_t* layout_text;
513eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  } cases[] = {
514eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // Strings shorter than the truncation length should be laid out in full.
515eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    { L"",        L""        },
516eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    { kWeak,      kWeak      },
517eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    { kLtr,       kLtr       },
518eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    { kLtrRtl,    kLtrRtl    },
519eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    { kLtrRtlLtr, kLtrRtlLtr },
520eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    { kRtl,       kRtl       },
521eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    { kRtlLtr,    kRtlLtr    },
522eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    { kRtlLtrRtl, kRtlLtrRtl },
523eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // Strings as long as the truncation length should be laid out in full.
524eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    { L"01234",   L"01234"   },
525eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // Long strings should be truncated with an ellipsis appended at the end.
526eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    { L"012345",                  L"0123\x2026"     },
527558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    { L"012" L" . ",              L"012 \x2026"     },
528558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    { L"012" L"abc",              L"012a\x2026"     },
529558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    { L"012" L"a" L"\x5d0\x5d1",  L"012a\x2026"     },
530558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    { L"012" L"a" L"\x5d1" L"b",  L"012a\x2026"     },
531558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    { L"012" L"\x5d0\x5d1\x5d2",  L"012\x5d0\x2026" },
532558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    { L"012" L"\x5d0\x5d1" L"a",  L"012\x5d0\x2026" },
533558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    { L"012" L"\x5d0" L"a" L"\x5d1",    L"012\x5d0\x2026" },
534eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // Surrogate pairs should be truncated reasonably enough.
535eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    { L"0123\x0915\x093f",              L"0123\x2026"                },
536eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    { L"0\x05e9\x05bc\x05c1\x05b8",     L"0\x05e9\x05bc\x05c1\x05b8" },
537eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    { L"01\x05e9\x05bc\x05c1\x05b8",    L"01\x05e9\x05bc\x2026"      },
538eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    { L"012\x05e9\x05bc\x05c1\x05b8",   L"012\x05e9\x2026"           },
539eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    { L"0123\x05e9\x05bc\x05c1\x05b8",  L"0123\x2026"                },
540eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    { L"01234\x05e9\x05bc\x05c1\x05b8", L"0123\x2026"                },
541eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    { L"012\xF0\x9D\x84\x9E",           L"012\xF0\x2026"             },
542eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  };
543eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
544eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
545eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  render_text->set_truncate_length(5);
546eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) {
547eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    render_text->SetText(WideToUTF16(cases[i].text));
548eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    EXPECT_EQ(WideToUTF16(cases[i].text), render_text->text());
549eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    EXPECT_EQ(WideToUTF16(cases[i].layout_text), render_text->GetLayoutText())
550eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        << "For case " << i << ": " << cases[i].text;
551eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
552eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
553eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
554eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochTEST_F(RenderTextTest, TruncatedObscuredText) {
555eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
556eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  render_text->set_truncate_length(3);
557eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  render_text->SetObscured(true);
558eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  render_text->SetText(WideToUTF16(L"abcdef"));
559eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(WideToUTF16(L"abcdef"), render_text->text());
560eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(WideToUTF16(L"**\x2026"), render_text->GetLayoutText());
561eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
562eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
563eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochTEST_F(RenderTextTest, TruncatedCursorMovementLTR) {
564eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
565eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  render_text->set_truncate_length(2);
566eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  render_text->SetText(WideToUTF16(L"abcd"));
567eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
568eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(SelectionModel(0, CURSOR_BACKWARD), render_text->selection_model());
569eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  render_text->MoveCursor(LINE_BREAK, CURSOR_RIGHT, false);
570eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(SelectionModel(4, CURSOR_FORWARD), render_text->selection_model());
571eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  render_text->MoveCursor(LINE_BREAK, CURSOR_LEFT, false);
572eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(SelectionModel(0, CURSOR_BACKWARD), render_text->selection_model());
573eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
574eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::vector<SelectionModel> expected;
575eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  expected.push_back(SelectionModel(0, CURSOR_BACKWARD));
576eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  expected.push_back(SelectionModel(1, CURSOR_BACKWARD));
577558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  // The cursor hops over the ellipsis and elided text to the line end.
578558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  expected.push_back(SelectionModel(4, CURSOR_BACKWARD));
579eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  expected.push_back(SelectionModel(4, CURSOR_FORWARD));
580eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  RunMoveCursorLeftRightTest(render_text.get(), expected, CURSOR_RIGHT);
581eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
582eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  expected.clear();
583eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  expected.push_back(SelectionModel(4, CURSOR_FORWARD));
584eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // The cursor hops over the elided text to preceeding text.
585eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  expected.push_back(SelectionModel(1, CURSOR_FORWARD));
586eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  expected.push_back(SelectionModel(0, CURSOR_FORWARD));
587eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  expected.push_back(SelectionModel(0, CURSOR_BACKWARD));
588eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  RunMoveCursorLeftRightTest(render_text.get(), expected, CURSOR_LEFT);
589eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
590eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
591eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochTEST_F(RenderTextTest, TruncatedCursorMovementRTL) {
592eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
593eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  render_text->set_truncate_length(2);
594eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  render_text->SetText(WideToUTF16(L"\x5d0\x5d1\x5d2\x5d3"));
595eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
596eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(SelectionModel(0, CURSOR_BACKWARD), render_text->selection_model());
597eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  render_text->MoveCursor(LINE_BREAK, CURSOR_LEFT, false);
598eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(SelectionModel(4, CURSOR_FORWARD), render_text->selection_model());
599eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  render_text->MoveCursor(LINE_BREAK, CURSOR_RIGHT, false);
600eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(SelectionModel(0, CURSOR_BACKWARD), render_text->selection_model());
601eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
602eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::vector<SelectionModel> expected;
603eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  expected.push_back(SelectionModel(0, CURSOR_BACKWARD));
604eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  expected.push_back(SelectionModel(1, CURSOR_BACKWARD));
605558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  // The cursor hops over the ellipsis and elided text to the line end.
606558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  expected.push_back(SelectionModel(4, CURSOR_BACKWARD));
607eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  expected.push_back(SelectionModel(4, CURSOR_FORWARD));
608eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  RunMoveCursorLeftRightTest(render_text.get(), expected, CURSOR_LEFT);
609eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
610eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  expected.clear();
611eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  expected.push_back(SelectionModel(4, CURSOR_FORWARD));
612eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // The cursor hops over the elided text to preceeding text.
613eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  expected.push_back(SelectionModel(1, CURSOR_FORWARD));
614eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  expected.push_back(SelectionModel(0, CURSOR_FORWARD));
615eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  expected.push_back(SelectionModel(0, CURSOR_BACKWARD));
616eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  RunMoveCursorLeftRightTest(render_text.get(), expected, CURSOR_RIGHT);
617eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
618eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(RenderTextTest, GetTextDirection) {
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct {
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const wchar_t* text;
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const base::i18n::TextDirection text_direction;
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } cases[] = {
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Blank strings and those with no/weak directionality default to LTR.
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { L"",        base::i18n::LEFT_TO_RIGHT },
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { kWeak,      base::i18n::LEFT_TO_RIGHT },
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Strings that begin with strong LTR characters.
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { kLtr,       base::i18n::LEFT_TO_RIGHT },
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { kLtrRtl,    base::i18n::LEFT_TO_RIGHT },
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { kLtrRtlLtr, base::i18n::LEFT_TO_RIGHT },
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Strings that begin with strong RTL characters.
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { kRtl,       base::i18n::RIGHT_TO_LEFT },
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { kRtlLtr,    base::i18n::RIGHT_TO_LEFT },
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { kRtlLtrRtl, base::i18n::RIGHT_TO_LEFT },
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const bool was_rtl = base::i18n::IsRTL();
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < 2; ++i) {
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Toggle the application default text direction (to try each direction).
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetRTL(!base::i18n::IsRTL());
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const base::i18n::TextDirection ui_direction = base::i18n::IsRTL() ?
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::i18n::RIGHT_TO_LEFT : base::i18n::LEFT_TO_RIGHT;
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Ensure that directionality modes yield the correct text directions.
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (size_t j = 0; j < ARRAYSIZE_UNSAFE(cases); j++) {
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      render_text->SetText(WideToUTF16(cases[j].text));
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      render_text->SetDirectionalityMode(DIRECTIONALITY_FROM_TEXT);
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      EXPECT_EQ(render_text->GetTextDirection(), cases[j].text_direction);
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      render_text->SetDirectionalityMode(DIRECTIONALITY_FROM_UI);
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      EXPECT_EQ(render_text->GetTextDirection(), ui_direction);
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      render_text->SetDirectionalityMode(DIRECTIONALITY_FORCE_LTR);
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      EXPECT_EQ(render_text->GetTextDirection(), base::i18n::LEFT_TO_RIGHT);
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      render_text->SetDirectionalityMode(DIRECTIONALITY_FORCE_RTL);
6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      EXPECT_EQ(render_text->GetTextDirection(), base::i18n::RIGHT_TO_LEFT);
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(was_rtl, base::i18n::IsRTL());
6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Ensure that text changes update the direction for DIRECTIONALITY_FROM_TEXT.
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  render_text->SetDirectionalityMode(DIRECTIONALITY_FROM_TEXT);
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  render_text->SetText(WideToUTF16(kLtr));
6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(render_text->GetTextDirection(), base::i18n::LEFT_TO_RIGHT);
6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  render_text->SetText(WideToUTF16(kRtl));
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(render_text->GetTextDirection(), base::i18n::RIGHT_TO_LEFT);
6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(RenderTextTest, MoveCursorLeftRightInLtr) {
6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Pure LTR.
6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  render_text->SetText(ASCIIToUTF16("abc"));
6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |expected| saves the expected SelectionModel when moving cursor from left
6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // to right.
6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<SelectionModel> expected;
6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(0, CURSOR_BACKWARD));
6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(1, CURSOR_BACKWARD));
6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(2, CURSOR_BACKWARD));
6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(3, CURSOR_BACKWARD));
6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(3, CURSOR_FORWARD));
6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RunMoveCursorLeftRightTest(render_text.get(), expected, CURSOR_RIGHT);
6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.clear();
6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(3, CURSOR_FORWARD));
6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(2, CURSOR_FORWARD));
6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(1, CURSOR_FORWARD));
6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(0, CURSOR_FORWARD));
6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(0, CURSOR_BACKWARD));
6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RunMoveCursorLeftRightTest(render_text.get(), expected, CURSOR_LEFT);
6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(RenderTextTest, MoveCursorLeftRightInLtrRtl) {
6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // LTR-RTL
6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  render_text->SetText(WideToUTF16(L"abc\x05d0\x05d1\x05d2"));
6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The last one is the expected END position.
6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<SelectionModel> expected;
7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(0, CURSOR_BACKWARD));
7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(1, CURSOR_BACKWARD));
7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(2, CURSOR_BACKWARD));
7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(3, CURSOR_BACKWARD));
7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(5, CURSOR_FORWARD));
7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(4, CURSOR_FORWARD));
7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(3, CURSOR_FORWARD));
7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(6, CURSOR_FORWARD));
7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RunMoveCursorLeftRightTest(render_text.get(), expected, CURSOR_RIGHT);
7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.clear();
7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(6, CURSOR_FORWARD));
7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(4, CURSOR_BACKWARD));
7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(5, CURSOR_BACKWARD));
7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(6, CURSOR_BACKWARD));
7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(2, CURSOR_FORWARD));
7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(1, CURSOR_FORWARD));
7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(0, CURSOR_FORWARD));
7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(0, CURSOR_BACKWARD));
7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RunMoveCursorLeftRightTest(render_text.get(), expected, CURSOR_LEFT);
7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(RenderTextTest, MoveCursorLeftRightInLtrRtlLtr) {
7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // LTR-RTL-LTR.
725558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  render_text->SetText(WideToUTF16(L"a" L"\x05d1" L"b"));
7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<SelectionModel> expected;
7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(0, CURSOR_BACKWARD));
7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(1, CURSOR_BACKWARD));
7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(1, CURSOR_FORWARD));
7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(3, CURSOR_BACKWARD));
7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(3, CURSOR_FORWARD));
7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RunMoveCursorLeftRightTest(render_text.get(), expected, CURSOR_RIGHT);
7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.clear();
7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(3, CURSOR_FORWARD));
7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(2, CURSOR_FORWARD));
7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(2, CURSOR_BACKWARD));
7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(0, CURSOR_FORWARD));
7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(0, CURSOR_BACKWARD));
7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RunMoveCursorLeftRightTest(render_text.get(), expected, CURSOR_LEFT);
7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(RenderTextTest, MoveCursorLeftRightInRtl) {
7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Pure RTL.
7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  render_text->SetText(WideToUTF16(L"\x05d0\x05d1\x05d2"));
7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  render_text->MoveCursor(LINE_BREAK, CURSOR_RIGHT, false);
7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<SelectionModel> expected;
7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(0, CURSOR_BACKWARD));
7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(1, CURSOR_BACKWARD));
7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(2, CURSOR_BACKWARD));
7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(3, CURSOR_BACKWARD));
7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(3, CURSOR_FORWARD));
7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RunMoveCursorLeftRightTest(render_text.get(), expected, CURSOR_LEFT);
7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.clear();
7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(3, CURSOR_FORWARD));
7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(2, CURSOR_FORWARD));
7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(1, CURSOR_FORWARD));
7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(0, CURSOR_FORWARD));
7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(0, CURSOR_BACKWARD));
7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RunMoveCursorLeftRightTest(render_text.get(), expected, CURSOR_RIGHT);
7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(RenderTextTest, MoveCursorLeftRightInRtlLtr) {
7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // RTL-LTR
770558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  render_text->SetText(WideToUTF16(L"\x05d0\x05d1\x05d2" L"abc"));
7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  render_text->MoveCursor(LINE_BREAK, CURSOR_RIGHT, false);
7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<SelectionModel> expected;
7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(0, CURSOR_BACKWARD));
7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(1, CURSOR_BACKWARD));
7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(2, CURSOR_BACKWARD));
7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(3, CURSOR_BACKWARD));
7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(5, CURSOR_FORWARD));
7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(4, CURSOR_FORWARD));
7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(3, CURSOR_FORWARD));
7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(6, CURSOR_FORWARD));
7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RunMoveCursorLeftRightTest(render_text.get(), expected, CURSOR_LEFT);
7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.clear();
7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(6, CURSOR_FORWARD));
7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(4, CURSOR_BACKWARD));
7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(5, CURSOR_BACKWARD));
7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(6, CURSOR_BACKWARD));
7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(2, CURSOR_FORWARD));
7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(1, CURSOR_FORWARD));
7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(0, CURSOR_FORWARD));
7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(0, CURSOR_BACKWARD));
7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RunMoveCursorLeftRightTest(render_text.get(), expected, CURSOR_RIGHT);
7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(RenderTextTest, MoveCursorLeftRightInRtlLtrRtl) {
7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // RTL-LTR-RTL.
798558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  render_text->SetText(WideToUTF16(L"\x05d0" L"a" L"\x05d1"));
7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  render_text->MoveCursor(LINE_BREAK, CURSOR_RIGHT, false);
8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<SelectionModel> expected;
8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(0, CURSOR_BACKWARD));
8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(1, CURSOR_BACKWARD));
8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(1, CURSOR_FORWARD));
8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(3, CURSOR_BACKWARD));
8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(3, CURSOR_FORWARD));
8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RunMoveCursorLeftRightTest(render_text.get(), expected, CURSOR_LEFT);
8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.clear();
8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(3, CURSOR_FORWARD));
8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(2, CURSOR_FORWARD));
8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(2, CURSOR_BACKWARD));
8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(0, CURSOR_FORWARD));
8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  expected.push_back(SelectionModel(0, CURSOR_BACKWARD));
8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RunMoveCursorLeftRightTest(render_text.get(), expected, CURSOR_RIGHT);
8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(xji): temporarily disable in platform Win since the complex script
8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// characters turned into empty square due to font regression. So, not able
8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// to test 2 characters belong to the same grapheme.
8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_LINUX)
8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(RenderTextTest, MoveCursorLeftRight_ComplexScript) {
8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  render_text->SetText(WideToUTF16(L"\x0915\x093f\x0915\x094d\x0915"));
8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(0U, render_text->cursor_position());
8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  render_text->MoveCursor(CHARACTER_BREAK, CURSOR_RIGHT, false);
8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(2U, render_text->cursor_position());
8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  render_text->MoveCursor(CHARACTER_BREAK, CURSOR_RIGHT, false);
8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(4U, render_text->cursor_position());
8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  render_text->MoveCursor(CHARACTER_BREAK, CURSOR_RIGHT, false);
8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(5U, render_text->cursor_position());
8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  render_text->MoveCursor(CHARACTER_BREAK, CURSOR_RIGHT, false);
8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(5U, render_text->cursor_position());
8345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  render_text->MoveCursor(CHARACTER_BREAK, CURSOR_LEFT, false);
8365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(4U, render_text->cursor_position());
8375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  render_text->MoveCursor(CHARACTER_BREAK, CURSOR_LEFT, false);
8385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(2U, render_text->cursor_position());
8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  render_text->MoveCursor(CHARACTER_BREAK, CURSOR_LEFT, false);
8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(0U, render_text->cursor_position());
8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  render_text->MoveCursor(CHARACTER_BREAK, CURSOR_LEFT, false);
8425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(0U, render_text->cursor_position());
8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// TODO(ckocagil): Enable for RenderTextHarfBuzz. http://crbug.com/383265
8477d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)TEST_F(RenderTextTest, MoveCursorLeftRight_MeiryoUILigatures) {
8485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  scoped_ptr<RenderText> render_text(RenderText::CreateNativeInstance());
8497d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // Meiryo UI uses single-glyph ligatures for 'ff' and 'ffi', but each letter
8507d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  // (code point) has unique bounds, so mid-glyph cursoring should be possible.
8515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  render_text->SetFontList(FontList("Meiryo UI, 12px"));
8527d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  render_text->SetText(WideToUTF16(L"ff ffi"));
8537d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  EXPECT_EQ(0U, render_text->cursor_position());
8547d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  for (size_t i = 0; i < render_text->text().length(); ++i) {
8557d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    render_text->MoveCursor(CHARACTER_BREAK, CURSOR_RIGHT, false);
8567d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    EXPECT_EQ(i + 1, render_text->cursor_position());
8577d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  }
8587d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  EXPECT_EQ(6U, render_text->cursor_position());
8597d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)}
8607d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(RenderTextTest, GraphemePositions) {
8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // LTR 2-character grapheme, LTR abc, LTR 2-character grapheme.
863868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  const base::string16 kText1 =
864558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      WideToUTF16(L"\x0915\x093f" L"abc" L"\x0915\x093f");
8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // LTR ab, LTR 2-character grapheme, LTR cd.
867558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  const base::string16 kText2 = WideToUTF16(L"ab" L"\x0915\x093f" L"cd");
8685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The below is 'MUSICAL SYMBOL G CLEF', which is represented in UTF-16 as
8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // two characters forming the surrogate pair 0x0001D11E.
8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const std::string kSurrogate = "\xF0\x9D\x84\x9E";
8725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // LTR ab, UTF16 surrogate pair, LTR cd.
874868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  const base::string16 kText3 = UTF8ToUTF16("ab" + kSurrogate + "cd");
8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct {
877868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    base::string16 text;
8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    size_t index;
8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    size_t expected_previous;
8805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    size_t expected_next;
8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } cases[] = {
882868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    { base::string16(), 0, 0, 0 },
883868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    { base::string16(), 1, 0, 0 },
884868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    { base::string16(), 50, 0, 0 },
8855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { kText1, 0, 0, 2 },
8865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { kText1, 1, 0, 2 },
8875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { kText1, 2, 0, 3 },
8885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { kText1, 3, 2, 4 },
8895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { kText1, 4, 3, 5 },
8905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { kText1, 5, 4, 7 },
8915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { kText1, 6, 5, 7 },
8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { kText1, 7, 5, 7 },
8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { kText1, 8, 7, 7 },
8945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { kText1, 50, 7, 7 },
8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { kText2, 0, 0, 1 },
8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { kText2, 1, 0, 2 },
8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { kText2, 2, 1, 4 },
8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { kText2, 3, 2, 4 },
8995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { kText2, 4, 2, 5 },
9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { kText2, 5, 4, 6 },
9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { kText2, 6, 5, 6 },
9025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { kText2, 7, 6, 6 },
9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { kText2, 50, 6, 6 },
9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { kText3, 0, 0, 1 },
9055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { kText3, 1, 0, 2 },
9065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { kText3, 2, 1, 4 },
9075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { kText3, 3, 2, 4 },
9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { kText3, 4, 2, 5 },
9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { kText3, 5, 4, 6 },
9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { kText3, 6, 5, 6 },
9115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { kText3, 7, 6, 6 },
9125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    { kText3, 50, 6, 6 },
9135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
9145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
916010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // TODO(msw): XP fails due to lack of font support: http://crbug.com/106450
9175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (base::win::GetVersion() < base::win::VERSION_VISTA)
9185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
9195821806d5e7f356e8fa4b058a389a808ea183019