1/*
2 * Copyright (C) 2012 Igalia S.L.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2,1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public License
15 * along with this library; see the file COPYING.LIB.  If not, write to
16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 */
19
20#include "config.h"
21#include "WebViewTest.h"
22#include <wtf/gobject/GRefPtr.h>
23
24class EditorTest: public WebViewTest {
25public:
26    MAKE_GLIB_TEST_FIXTURE(EditorTest);
27
28    static const unsigned int kClipboardWaitTimeout = 50;
29    static const unsigned int kClipboardWaitMaxTries = 2;
30
31    EditorTest()
32        : m_clipboard(gtk_clipboard_get(GDK_SELECTION_CLIPBOARD))
33        , m_canExecuteEditingCommand(false)
34        , m_triesCount(0)
35    {
36        gtk_clipboard_clear(m_clipboard);
37    }
38
39    static void canExecuteEditingCommandReadyCallback(GObject*, GAsyncResult* result, EditorTest* test)
40    {
41        GOwnPtr<GError> error;
42        test->m_canExecuteEditingCommand = webkit_web_view_can_execute_editing_command_finish(test->m_webView, result, &error.outPtr());
43        g_assert(!error.get());
44        g_main_loop_quit(test->m_mainLoop);
45    }
46
47    bool canExecuteEditingCommand(const char* command)
48    {
49        m_canExecuteEditingCommand = false;
50        webkit_web_view_can_execute_editing_command(m_webView, command, 0, reinterpret_cast<GAsyncReadyCallback>(canExecuteEditingCommandReadyCallback), this);
51        g_main_loop_run(m_mainLoop);
52        return m_canExecuteEditingCommand;
53    }
54
55    static gboolean waitForClipboardText(EditorTest* test)
56    {
57        test->m_triesCount++;
58        if (gtk_clipboard_wait_is_text_available(test->m_clipboard) || test->m_triesCount > kClipboardWaitMaxTries) {
59            g_main_loop_quit(test->m_mainLoop);
60            return FALSE;
61        }
62
63        return TRUE;
64    }
65
66    void copyClipboard()
67    {
68        webkit_web_view_execute_editing_command(m_webView, WEBKIT_EDITING_COMMAND_COPY);
69        // There's no way to know when the selection has been copied to
70        // the clipboard, so use a timeout source to query the clipboard.
71        m_triesCount = 0;
72        g_timeout_add(kClipboardWaitTimeout, reinterpret_cast<GSourceFunc>(waitForClipboardText), this);
73        g_main_loop_run(m_mainLoop);
74    }
75
76    GtkClipboard* m_clipboard;
77    bool m_canExecuteEditingCommand;
78    size_t m_triesCount;
79};
80
81static void testWebViewEditorCutCopyPasteNonEditable(EditorTest* test, gconstpointer)
82{
83    static const char* selectedSpanHTML = "<html><body contentEditable=\"false\">"
84        "<span id=\"mainspan\">All work and no play <span id=\"subspan\">make Jack a dull</span> boy.</span>"
85        "<script>document.getSelection().collapse();\n"
86        "document.getSelection().selectAllChildren(document.getElementById('subspan'));\n"
87        "</script></body></html>";
88
89    // Nothing loaded yet.
90    g_assert(!test->canExecuteEditingCommand(WEBKIT_EDITING_COMMAND_CUT));
91    g_assert(!test->canExecuteEditingCommand(WEBKIT_EDITING_COMMAND_COPY));
92    g_assert(!test->canExecuteEditingCommand(WEBKIT_EDITING_COMMAND_PASTE));
93
94    test->loadHtml(selectedSpanHTML, 0);
95    test->waitUntilLoadFinished();
96
97    g_assert(test->canExecuteEditingCommand(WEBKIT_EDITING_COMMAND_COPY));
98    // It's not possible to cut and paste when content is not editable
99    // even if there's a selection.
100    g_assert(!test->canExecuteEditingCommand(WEBKIT_EDITING_COMMAND_CUT));
101    g_assert(!test->canExecuteEditingCommand(WEBKIT_EDITING_COMMAND_PASTE));
102
103    test->copyClipboard();
104    GOwnPtr<char> clipboardText(gtk_clipboard_wait_for_text(test->m_clipboard));
105    g_assert_cmpstr(clipboardText.get(), ==, "make Jack a dull");
106}
107
108static void testWebViewEditorCutCopyPasteEditable(EditorTest* test, gconstpointer)
109{
110    static const char* selectedSpanHTML = "<html><body contentEditable=\"true\">"
111        "<span id=\"mainspan\">All work and no play <span>make Jack a dull</span> boy.</span>"
112        "<script>document.getSelection().collapse();\n"
113        "document.getSelection().selectAllChildren(document.getElementById('mainspan'));\n"
114        "</script></body></html>";
115
116    // Nothing loaded yet.
117    g_assert(!test->canExecuteEditingCommand(WEBKIT_EDITING_COMMAND_CUT));
118    g_assert(!test->canExecuteEditingCommand(WEBKIT_EDITING_COMMAND_COPY));
119    g_assert(!test->canExecuteEditingCommand(WEBKIT_EDITING_COMMAND_PASTE));
120
121    test->loadHtml(selectedSpanHTML, 0);
122    test->waitUntilLoadFinished();
123
124    // There's a selection.
125    g_assert(test->canExecuteEditingCommand(WEBKIT_EDITING_COMMAND_CUT));
126    g_assert(test->canExecuteEditingCommand(WEBKIT_EDITING_COMMAND_COPY));
127    g_assert(test->canExecuteEditingCommand(WEBKIT_EDITING_COMMAND_PASTE));
128
129    test->copyClipboard();
130    GOwnPtr<char> clipboardText(gtk_clipboard_wait_for_text(test->m_clipboard));
131    g_assert_cmpstr(clipboardText.get(), ==, "All work and no play make Jack a dull boy.");
132}
133
134static void testWebViewEditorSelectAllNonEditable(EditorTest* test, gconstpointer)
135{
136    static const char* selectedSpanHTML = "<html><body contentEditable=\"false\">"
137        "<span id=\"mainspan\">All work and no play <span id=\"subspan\">make Jack a dull</span> boy.</span>"
138        "<script>document.getSelection().collapse();\n"
139        "document.getSelection().selectAllChildren(document.getElementById('subspan'));\n"
140        "</script></body></html>";
141
142    g_assert(test->canExecuteEditingCommand(WEBKIT_EDITING_COMMAND_SELECT_ALL));
143
144    test->loadHtml(selectedSpanHTML, 0);
145    test->waitUntilLoadFinished();
146
147    g_assert(test->canExecuteEditingCommand(WEBKIT_EDITING_COMMAND_SELECT_ALL));
148
149    test->copyClipboard();
150    GOwnPtr<char> clipboardText(gtk_clipboard_wait_for_text(test->m_clipboard));
151
152    // Initially only the subspan is selected.
153    g_assert_cmpstr(clipboardText.get(), ==, "make Jack a dull");
154
155    webkit_web_view_execute_editing_command(test->m_webView, WEBKIT_EDITING_COMMAND_SELECT_ALL);
156    test->copyClipboard();
157    clipboardText.set(gtk_clipboard_wait_for_text(test->m_clipboard));
158
159    // The mainspan should be selected after calling SELECT_ALL.
160    g_assert_cmpstr(clipboardText.get(), ==, "All work and no play make Jack a dull boy.");
161}
162
163static void testWebViewEditorSelectAllEditable(EditorTest* test, gconstpointer)
164{
165    static const char* selectedSpanHTML = "<html><body contentEditable=\"true\">"
166        "<span id=\"mainspan\">All work and no play <span id=\"subspan\">make Jack a dull</span> boy.</span>"
167        "<script>document.getSelection().collapse();\n"
168        "document.getSelection().selectAllChildren(document.getElementById('subspan'));\n"
169        "</script></body></html>";
170
171    g_assert(test->canExecuteEditingCommand(WEBKIT_EDITING_COMMAND_SELECT_ALL));
172
173    test->loadHtml(selectedSpanHTML, 0);
174    test->waitUntilLoadFinished();
175
176    g_assert(test->canExecuteEditingCommand(WEBKIT_EDITING_COMMAND_SELECT_ALL));
177
178    test->copyClipboard();
179    GOwnPtr<char> clipboardText(gtk_clipboard_wait_for_text(test->m_clipboard));
180
181    // Initially only the subspan is selected.
182    g_assert_cmpstr(clipboardText.get(), ==, "make Jack a dull");
183
184    webkit_web_view_execute_editing_command(test->m_webView, WEBKIT_EDITING_COMMAND_SELECT_ALL);
185    test->copyClipboard();
186    clipboardText.set(gtk_clipboard_wait_for_text(test->m_clipboard));
187
188    // The mainspan should be selected after calling SELECT_ALL.
189    g_assert_cmpstr(clipboardText.get(), ==, "All work and no play make Jack a dull boy.");
190}
191
192void beforeAll()
193{
194    EditorTest::add("WebKitWebView", "cut-copy-paste/non-editable", testWebViewEditorCutCopyPasteNonEditable);
195    EditorTest::add("WebKitWebView", "cut-copy-paste/editable", testWebViewEditorCutCopyPasteEditable);
196    EditorTest::add("WebKitWebView", "select-all/non-editable", testWebViewEditorSelectAllNonEditable);
197    EditorTest::add("WebKitWebView", "select-all/editable", testWebViewEditorSelectAllEditable);
198}
199
200void afterAll()
201{
202}
203