2
* Copyright (C) 2011 Igalia S.L.
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.
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.
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
21
#include "WebEditorClient.h"
24
#include "FrameDestructionObserver.h"
25
#include "PlatformKeyboardEvent.h"
27
#include "WebPageProxyMessages.h"
28
#include "WebProcess.h"
29
#include <WebCore/DataObjectGtk.h>
30
#include <WebCore/KeyboardEvent.h>
31
#include <WebCore/PasteboardHelper.h>
32
#include <WebCore/NotImplemented.h>
34
using namespace WebCore;
38
void WebEditorClient::getEditorCommandsForKeyEvent(const KeyboardEvent* event, Vector<WTF::String>& pendingEditorCommands)
40
ASSERT(event->type() == eventNames().keydownEvent || event->type() == eventNames().keypressEvent);
42
/* First try to interpret the command in the UI and get the commands.
43
UI needs to receive event type because only knows current NativeWebKeyboardEvent.*/
44
WebProcess::shared().connection()->sendSync(Messages::WebPageProxy::GetEditorCommandsForKeyEvent(event->type()),
45
Messages::WebPageProxy::GetEditorCommandsForKeyEvent::Reply(pendingEditorCommands),
46
m_page->pageID(), CoreIPC::Connection::NoTimeout);
49
bool WebEditorClient::executePendingEditorCommands(Frame* frame, Vector<WTF::String> pendingEditorCommands, bool allowTextInsertion)
51
Vector<Editor::Command> commands;
52
for (size_t i = 0; i < pendingEditorCommands.size(); i++) {
53
Editor::Command command = frame->editor()->command(pendingEditorCommands.at(i).utf8().data());
54
if (command.isTextInsertion() && !allowTextInsertion)
57
commands.append(command);
60
for (size_t i = 0; i < commands.size(); i++) {
61
if (!commands.at(i).execute())
68
void WebEditorClient::handleKeyboardEvent(KeyboardEvent* event)
70
Node* node = event->target()->toNode();
72
Frame* frame = node->document()->frame();
75
const PlatformKeyboardEvent* platformEvent = event->keyEvent();
79
Vector<WTF::String> pendingEditorCommands;
80
getEditorCommandsForKeyEvent(event, pendingEditorCommands);
81
if (!pendingEditorCommands.isEmpty()) {
83
// During RawKeyDown events if an editor command will insert text, defer
84
// the insertion until the keypress event. We want keydown to bubble up
85
// through the DOM first.
86
if (platformEvent->type() == PlatformEvent::RawKeyDown) {
87
if (executePendingEditorCommands(frame, pendingEditorCommands, false))
88
event->setDefaultHandled();
93
// Only allow text insertion commands if the current node is editable.
94
if (executePendingEditorCommands(frame, pendingEditorCommands, frame->editor()->canEdit())) {
95
event->setDefaultHandled();
100
// Don't allow text insertion for nodes that cannot edit.
101
if (!frame->editor()->canEdit())
104
// This is just a normal text insertion, so wait to execute the insertion
105
// until a keypress event happens. This will ensure that the insertion will not
106
// be reflected in the contents of the field until the keyup DOM event.
107
if (event->type() == eventNames().keypressEvent) {
109
// FIXME: Add IM support
110
// https://bugs.webkit.org/show_bug.cgi?id=55946
111
frame->editor()->insertText(platformEvent->text(), event);
112
event->setDefaultHandled();
115
// Don't insert null or control characters as they can result in unexpected behaviour
116
if (event->charCode() < ' ')
119
// Don't insert anything if a modifier is pressed
120
if (platformEvent->ctrlKey() || platformEvent->altKey())
123
if (frame->editor()->insertText(platformEvent->text(), event))
124
event->setDefaultHandled();
128
void WebEditorClient::handleInputMethodKeydown(KeyboardEvent*)
134
class EditorClientFrameDestructionObserver : FrameDestructionObserver {
136
EditorClientFrameDestructionObserver(Frame* frame, GClosure* closure)
137
: FrameDestructionObserver(frame)
140
g_closure_add_finalize_notifier(m_closure, this, destroyOnClosureFinalization);
143
void frameDestroyed()
145
g_closure_invalidate(m_closure);
146
FrameDestructionObserver::frameDestroyed();
151
static void destroyOnClosureFinalization(gpointer data, GClosure* closure)
153
// Calling delete void* will free the memory but won't invoke
154
// the destructor, something that is a must for us.
155
EditorClientFrameDestructionObserver* observer = static_cast<EditorClientFrameDestructionObserver*>(data);
160
static Frame* frameSettingClipboard;
162
static void collapseSelection(GtkClipboard* clipboard, Frame* frame)
164
if (frameSettingClipboard && frameSettingClipboard == frame)
167
// Collapse the selection without clearing it.
169
frame->selection()->setBase(frame->selection()->extent(), frame->selection()->affinity());
173
void WebEditorClient::updateGlobalSelection(Frame* frame)
176
GtkClipboard* clipboard = PasteboardHelper::defaultPasteboardHelper()->getPrimarySelectionClipboard(frame);
177
DataObjectGtk* dataObject = DataObjectGtk::forClipboard(clipboard);
179
if (!frame->selection()->isRange())
182
dataObject->clearAll();
183
dataObject->setRange(frame->selection()->toNormalizedRange());
185
frameSettingClipboard = frame;
186
GClosure* callback = g_cclosure_new(G_CALLBACK(collapseSelection), frame, 0);
187
// This observer will be self-destroyed on closure finalization,
188
// that will happen either after closure execution or after
189
// closure invalidation.
190
new EditorClientFrameDestructionObserver(frame, callback);
191
g_closure_set_marshal(callback, g_cclosure_marshal_VOID__VOID);
192
PasteboardHelper::defaultPasteboardHelper()->writeClipboardContents(clipboard, PasteboardHelper::DoNotIncludeSmartPaste, callback);
193
frameSettingClipboard = 0;
197
bool WebEditorClient::shouldShowUnicodeMenu()