1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "third_party/blink/renderer/core/editing/frame_caret.h"
6 
7 #include "third_party/blink/renderer/core/editing/commands/typing_command.h"
8 #include "third_party/blink/renderer/core/editing/frame_selection.h"
9 #include "third_party/blink/renderer/core/editing/selection_template.h"
10 #include "third_party/blink/renderer/core/editing/testing/editing_test_base.h"
11 #include "third_party/blink/renderer/core/frame/local_frame_view.h"
12 #include "third_party/blink/renderer/core/frame/settings.h"
13 #include "third_party/blink/renderer/core/layout/layout_theme.h"
14 #include "third_party/blink/renderer/core/page/focus_controller.h"
15 #include "third_party/blink/renderer/platform/scheduler/test/fake_task_runner.h"
16 #include "third_party/blink/renderer/platform/web_test_support.h"
17 
18 namespace blink {
19 
20 class FrameCaretTest : public EditingTestBase {
21  public:
FrameCaretTest()22   FrameCaretTest() : was_running_web_test_(WebTestSupport::IsRunningWebTest()) {
23     // The caret blink timer doesn't work if IsRunningWebTest() because
24     // LayoutTheme::CaretBlinkInterval() returns 0.
25     WebTestSupport::SetIsRunningWebTest(false);
26   }
~FrameCaretTest()27   ~FrameCaretTest() override {
28     WebTestSupport::SetIsRunningWebTest(was_running_web_test_);
29   }
30 
ShouldBlinkCaret(const FrameCaret & caret)31   static bool ShouldBlinkCaret(const FrameCaret& caret) {
32     return caret.ShouldBlinkCaret();
33   }
34 
35  private:
36   const bool was_running_web_test_;
37 };
38 
TEST_F(FrameCaretTest,BlinkAfterTyping)39 TEST_F(FrameCaretTest, BlinkAfterTyping) {
40   FrameCaret& caret = Selection().FrameCaretForTesting();
41   scoped_refptr<scheduler::FakeTaskRunner> task_runner =
42       base::MakeRefCounted<scheduler::FakeTaskRunner>();
43   task_runner->SetTime(0);
44   caret.RecreateCaretBlinkTimerForTesting(task_runner.get());
45   const double kInterval = 10;
46   LayoutTheme::GetTheme().SetCaretBlinkInterval(
47       base::TimeDelta::FromSecondsD(kInterval));
48   GetDocument().GetPage()->GetFocusController().SetActive(true);
49   GetDocument().GetPage()->GetFocusController().SetFocused(true);
50   GetDocument().body()->setInnerHTML("<textarea>");
51   auto* editor = To<Element>(GetDocument().body()->firstChild());
52   editor->focus();
53   UpdateAllLifecyclePhasesForTest();
54 
55   EXPECT_TRUE(caret.IsActive());
56   EXPECT_FALSE(caret.ShouldShowBlockCursor());
57   EXPECT_TRUE(caret.ShouldPaintCaretForTesting())
58       << "Initially a caret should be in visible cycle.";
59 
60   task_runner->AdvanceTimeAndRun(kInterval);
61   EXPECT_FALSE(caret.ShouldPaintCaretForTesting())
62       << "The caret blinks normally.";
63 
64   TypingCommand::InsertLineBreak(GetDocument());
65   UpdateAllLifecyclePhasesForTest();
66   EXPECT_TRUE(caret.ShouldPaintCaretForTesting())
67       << "The caret should be in visible cycle just after a typing command.";
68 
69   task_runner->AdvanceTimeAndRun(kInterval - 1);
70   UpdateAllLifecyclePhasesForTest();
71   EXPECT_TRUE(caret.ShouldPaintCaretForTesting())
72       << "The typing command reset the timer. The caret is still visible.";
73 
74   task_runner->AdvanceTimeAndRun(1);
75   UpdateAllLifecyclePhasesForTest();
76   EXPECT_FALSE(caret.ShouldPaintCaretForTesting())
77       << "The caret should blink after the typing command.";
78 }
79 
TEST_F(FrameCaretTest,ShouldNotBlinkWhenSelectionLooseFocus)80 TEST_F(FrameCaretTest, ShouldNotBlinkWhenSelectionLooseFocus) {
81   FrameCaret& caret = Selection().FrameCaretForTesting();
82   GetDocument().GetPage()->GetFocusController().SetActive(true);
83   GetDocument().GetPage()->GetFocusController().SetFocused(true);
84   GetDocument().body()->setInnerHTML(
85       "<div id='outer' tabindex='-1'>"
86       "<div id='input' contenteditable>foo</div>"
87       "</div>");
88   Element* input = GetDocument().QuerySelector("#input");
89   input->focus();
90   Element* outer = GetDocument().QuerySelector("#outer");
91   outer->focus();
92   UpdateAllLifecyclePhasesForTest();
93   const SelectionInDOMTree& selection = Selection().GetSelectionInDOMTree();
94   EXPECT_EQ(selection.Base(),
95             Position(input, PositionAnchorType::kBeforeChildren));
96   EXPECT_FALSE(ShouldBlinkCaret(caret));
97 }
98 
TEST_F(FrameCaretTest,ShouldBlinkCaretWhileCaretBrowsing)99 TEST_F(FrameCaretTest, ShouldBlinkCaretWhileCaretBrowsing) {
100   FrameCaret& caret = Selection().FrameCaretForTesting();
101   Selection().SetSelection(SetSelectionTextToBody("<div>a|b</div>"),
102                            SetSelectionOptions());
103   Selection().SetCaretVisible(true);
104   EXPECT_FALSE(ShouldBlinkCaret(caret));
105   GetDocument().GetFrame()->GetSettings()->SetCaretBrowsingEnabled(true);
106   EXPECT_TRUE(ShouldBlinkCaret(caret));
107 }
108 
109 }  // namespace blink
110