Add WTF::move()
[WebKit-https.git] / Source / WebKit2 / WebProcess / WebCoreSupport / gtk / WebEditorClientGtk.cpp
1 /*
2  *  Copyright (C) 2011 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 License
6  *  as published by the Free Software Foundation; either version 2 of
7  *  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  *  Lesser General Public License for more details.
13  *
14  *  You should have received a copy of the GNU Lesser General Public
15  *  License along with this library; if not, write to the Free
16  *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  *  Boston, MA 02110-1301 USA
18  */
19
20 #include "config.h"
21 #include "WebEditorClient.h"
22
23 #include "Frame.h"
24 #include "FrameDestructionObserver.h"
25 #include "PlatformKeyboardEvent.h"
26 #include "WebPage.h"
27 #include "WebPageProxyMessages.h"
28 #include "WebProcess.h"
29 #include <WebCore/DataObjectGtk.h>
30 #include <WebCore/Document.h>
31 #include <WebCore/KeyboardEvent.h>
32 #include <WebCore/PasteboardHelper.h>
33 #include <WebCore/WindowsKeyboardCodes.h>
34
35 using namespace WebCore;
36
37 namespace WebKit {
38
39 void WebEditorClient::getEditorCommandsForKeyEvent(const KeyboardEvent* event, Vector<WTF::String>& pendingEditorCommands)
40 {
41     ASSERT(event->type() == eventNames().keydownEvent || event->type() == eventNames().keypressEvent);
42
43     /* First try to interpret the command in the UI and get the commands.
44        UI needs to receive event type because only knows current NativeWebKeyboardEvent.*/
45     WebProcess::shared().parentProcessConnection()->sendSync(Messages::WebPageProxy::GetEditorCommandsForKeyEvent(event->type()),
46                                                 Messages::WebPageProxy::GetEditorCommandsForKeyEvent::Reply(pendingEditorCommands),
47                                                 m_page->pageID(), std::chrono::milliseconds::max());
48 }
49
50 bool WebEditorClient::executePendingEditorCommands(Frame* frame, const Vector<WTF::String>& pendingEditorCommands, bool allowTextInsertion)
51 {
52     Vector<Editor::Command> commands;
53     for (auto& commandString : pendingEditorCommands) {
54         Editor::Command command = frame->editor().command(commandString.utf8().data());
55         if (command.isTextInsertion() && !allowTextInsertion)
56             return false;
57
58         commands.append(WTF::move(command));
59     }
60
61     for (auto& command : commands) {
62         if (!command.execute())
63             return false;
64     }
65
66     return true;
67 }
68
69 void WebEditorClient::handleKeyboardEvent(KeyboardEvent* event)
70 {
71     Node* node = event->target()->toNode();
72     ASSERT(node);
73     Frame* frame = node->document().frame();
74     ASSERT(frame);
75
76     const PlatformKeyboardEvent* platformEvent = event->keyEvent();
77     if (!platformEvent)
78         return;
79
80     // If this was an IME event don't do anything.
81     if (platformEvent->windowsVirtualKeyCode() == VK_PROCESSKEY)
82         return;
83
84     Vector<WTF::String> pendingEditorCommands;
85     getEditorCommandsForKeyEvent(event, pendingEditorCommands);
86     if (!pendingEditorCommands.isEmpty()) {
87
88         // During RawKeyDown events if an editor command will insert text, defer
89         // the insertion until the keypress event. We want keydown to bubble up
90         // through the DOM first.
91         if (platformEvent->type() == PlatformEvent::RawKeyDown) {
92             if (executePendingEditorCommands(frame, pendingEditorCommands, false))
93                 event->setDefaultHandled();
94
95             return;
96         }
97
98         // Only allow text insertion commands if the current node is editable.
99         if (executePendingEditorCommands(frame, pendingEditorCommands, frame->editor().canEdit())) {
100             event->setDefaultHandled();
101             return;
102         }
103     }
104
105     // Don't allow text insertion for nodes that cannot edit.
106     if (!frame->editor().canEdit())
107         return;
108
109     // This is just a normal text insertion, so wait to execute the insertion
110     // until a keypress event happens. This will ensure that the insertion will not
111     // be reflected in the contents of the field until the keyup DOM event.
112     if (event->type() != eventNames().keypressEvent)
113         return;
114
115     // Don't insert null or control characters as they can result in unexpected behaviour
116     if (event->charCode() < ' ')
117         return;
118
119     // Don't insert anything if a modifier is pressed
120     if (platformEvent->ctrlKey() || platformEvent->altKey())
121         return;
122
123     if (frame->editor().insertText(platformEvent->text(), event))
124         event->setDefaultHandled();
125 }
126
127 void WebEditorClient::handleInputMethodKeydown(KeyboardEvent* event)
128 {
129     const PlatformKeyboardEvent* platformEvent = event->keyEvent();
130     if (platformEvent && platformEvent->windowsVirtualKeyCode() == VK_PROCESSKEY)
131         event->preventDefault();
132 }
133
134 #if PLATFORM(X11)
135 class EditorClientFrameDestructionObserver : FrameDestructionObserver {
136 public:
137     EditorClientFrameDestructionObserver(Frame* frame, GClosure* closure)
138         : FrameDestructionObserver(frame)
139         , m_closure(closure)
140     {
141         g_closure_add_finalize_notifier(m_closure, this, destroyOnClosureFinalization);
142     }
143
144     void frameDestroyed()
145     {
146         g_closure_invalidate(m_closure);
147         FrameDestructionObserver::frameDestroyed();
148     }
149 private:
150     GClosure* m_closure;
151
152     static void destroyOnClosureFinalization(gpointer data, GClosure*)
153     {
154         // Calling delete void* will free the memory but won't invoke
155         // the destructor, something that is a must for us.
156         EditorClientFrameDestructionObserver* observer = static_cast<EditorClientFrameDestructionObserver*>(data);
157         delete observer;
158     }
159 };
160
161 static Frame* frameSettingClipboard;
162
163 static void collapseSelection(GtkClipboard*, Frame* frame)
164 {
165     if (frameSettingClipboard && frameSettingClipboard == frame)
166         return;
167
168     // Collapse the selection without clearing it.
169     ASSERT(frame);
170     const VisibleSelection& selection = frame->selection().selection();
171     frame->selection().setBase(selection.extent(), selection.affinity());
172 }
173 #endif
174
175 void WebEditorClient::updateGlobalSelection(Frame* frame)
176 {
177 #if PLATFORM(X11)
178     GtkClipboard* clipboard = PasteboardHelper::defaultPasteboardHelper()->getPrimarySelectionClipboard(frame);
179     DataObjectGtk* dataObject = DataObjectGtk::forClipboard(clipboard);
180
181     if (!frame->selection().isRange())
182         return;
183
184     dataObject->clearAll();
185     dataObject->setRange(frame->selection().toNormalizedRange());
186
187     frameSettingClipboard = frame;
188     GClosure* callback = g_cclosure_new(G_CALLBACK(collapseSelection), frame, 0);
189     // This observer will be self-destroyed on closure finalization,
190     // that will happen either after closure execution or after
191     // closure invalidation.
192     new EditorClientFrameDestructionObserver(frame, callback);
193     g_closure_set_marshal(callback, g_cclosure_marshal_VOID__VOID);
194     PasteboardHelper::defaultPasteboardHelper()->writeClipboardContents(clipboard, PasteboardHelper::DoNotIncludeSmartPaste, callback);
195     frameSettingClipboard = 0;
196 #endif
197 }
198
199 bool WebEditorClient::shouldShowUnicodeMenu()
200 {
201     return true;
202 }
203
204 }