1// Copyright 2014 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 "config.h"
6#include "core/editing/FrameSelection.h"
7
8#include "bindings/core/v8/ExceptionStatePlaceholder.h"
9#include "core/dom/Document.h"
10#include "core/dom/Element.h"
11#include "core/dom/Text.h"
12#include "core/frame/FrameView.h"
13#include "core/html/HTMLBodyElement.h"
14#include "core/html/HTMLDocument.h"
15#include "core/testing/DummyPageHolder.h"
16#include "wtf/OwnPtr.h"
17#include "wtf/PassRefPtr.h"
18#include "wtf/RefPtr.h"
19#include "wtf/StdLibExtras.h"
20#include "wtf/testing/WTFTestHelpers.h"
21#include <gtest/gtest.h>
22
23using namespace blink;
24
25namespace {
26
27class FrameSelectionTest : public ::testing::Test {
28protected:
29    virtual void SetUp() OVERRIDE;
30
31    DummyPageHolder& dummyPageHolder() const { return *m_dummyPageHolder; }
32    HTMLDocument& document() const;
33    void setSelection(const VisibleSelection&);
34    FrameSelection& selection() const;
35    Text* textNode() { return m_textNode.get(); }
36    int layoutCount() const { return m_dummyPageHolder->frameView().layoutCount(); }
37
38private:
39    OwnPtr<DummyPageHolder> m_dummyPageHolder;
40    RawPtr<HTMLDocument> m_document;
41    RefPtrWillBePersistent<Text> m_textNode;
42};
43
44void FrameSelectionTest::SetUp()
45{
46    m_dummyPageHolder = DummyPageHolder::create(IntSize(800, 600));
47    m_document = toHTMLDocument(&m_dummyPageHolder->document());
48    ASSERT(m_document);
49    m_textNode = m_document->createTextNode("Hello, World!");
50    m_document->body()->appendChild(m_textNode.get());
51}
52
53HTMLDocument& FrameSelectionTest::document() const
54{
55    return *m_document;
56}
57
58void FrameSelectionTest::setSelection(const VisibleSelection& newSelection)
59{
60    m_dummyPageHolder->frame().selection().setSelection(newSelection);
61}
62
63FrameSelection& FrameSelectionTest::selection() const
64{
65    return m_dummyPageHolder->frame().selection();
66}
67
68TEST_F(FrameSelectionTest, SetValidSelection)
69{
70    VisibleSelection validSelection(Position(textNode(), 0), Position(textNode(), 5));
71    EXPECT_FALSE(validSelection.isNone());
72    setSelection(validSelection);
73    EXPECT_FALSE(selection().isNone());
74}
75
76TEST_F(FrameSelectionTest, SetInvalidSelection)
77{
78    // Create a new document without frame by using DOMImplementation.
79    DocumentInit dummy;
80    RefPtrWillBeRawPtr<Document> documentWithoutFrame = Document::create();
81    RefPtrWillBeRawPtr<Element> body = documentWithoutFrame->createElement(HTMLNames::bodyTag, false);
82    documentWithoutFrame->appendChild(body);
83    RefPtrWillBeRawPtr<Text> anotherText = documentWithoutFrame->createTextNode("Hello, another world");
84    body->appendChild(anotherText);
85
86    // Create a new VisibleSelection for the new document without frame and
87    // update FrameSelection with the selection.
88    VisibleSelection invalidSelection;
89    invalidSelection.setWithoutValidation(Position(anotherText, 0), Position(anotherText, 5));
90    setSelection(invalidSelection);
91
92    EXPECT_TRUE(selection().isNone());
93}
94
95TEST_F(FrameSelectionTest, InvalidateCaretRect)
96{
97    document().view()->updateLayoutAndStyleIfNeededRecursive();
98
99    VisibleSelection validSelection(Position(textNode(), 0), Position(textNode(), 0));
100    setSelection(validSelection);
101    selection().setCaretRectNeedsUpdate();
102    EXPECT_TRUE(selection().isCaretBoundsDirty());
103    selection().invalidateCaretRect();
104    EXPECT_FALSE(selection().isCaretBoundsDirty());
105
106    document().body()->removeChild(textNode());
107    document().updateLayoutIgnorePendingStylesheets();
108    selection().setCaretRectNeedsUpdate();
109    EXPECT_TRUE(selection().isCaretBoundsDirty());
110    selection().invalidateCaretRect();
111    EXPECT_FALSE(selection().isCaretBoundsDirty());
112}
113
114TEST_F(FrameSelectionTest, PaintCaretShouldNotLayout)
115{
116    document().view()->updateLayoutAndStyleIfNeededRecursive();
117
118    document().body()->setContentEditable("true", ASSERT_NO_EXCEPTION);
119    document().body()->focus();
120    EXPECT_TRUE(document().body()->focused());
121
122    VisibleSelection validSelection(Position(textNode(), 0), Position(textNode(), 0));
123    selection().setCaretVisible(true);
124    setSelection(validSelection);
125    EXPECT_TRUE(selection().isCaret());
126    EXPECT_TRUE(selection().ShouldPaintCaretForTesting());
127
128    int startCount = layoutCount();
129    {
130        // To force layout in next updateLayout calling, widen view.
131        FrameView& frameView = dummyPageHolder().frameView();
132        IntRect frameRect = frameView.frameRect();
133        frameRect.setWidth(frameRect.width() + 1);
134        frameRect.setHeight(frameRect.height() + 1);
135        dummyPageHolder().frameView().setFrameRect(frameRect);
136    }
137    selection().paintCaret(nullptr, LayoutPoint(), LayoutRect());
138    EXPECT_EQ(startCount, layoutCount());
139}
140
141}
142