18e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project/*
28e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *  Copyright (C) 2007 Alp Toker <alp@atoker.com>
38e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *  Copyright (C) 2008 Nuanti Ltd.
40bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch *  Copyright (C) 2009 Diego Escalante Urrelo <diegoe@gnome.org>
50bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch *  Copyright (C) 2006, 2007 Apple Inc.  All rights reserved.
606ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen *  Copyright (C) 2009, 2010 Igalia S.L.
7dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block *  Copyright (C) 2010, Martin Robinson <mrobinson@webkit.org>
88e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
98e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *  This library is free software; you can redistribute it and/or
108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *  modify it under the terms of the GNU Lesser General Public
118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *  License as published by the Free Software Foundation; either
128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *  version 2 of the License, or (at your option) any later version.
138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *  This library is distributed in the hope that it will be useful,
158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *  but WITHOUT ANY WARRANTY; without even the implied warranty of
168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *  Lesser General Public License for more details.
188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *  You should have received a copy of the GNU Lesser General Public
208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *  License along with this library; if not, write to the Free Software
218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project */
238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "config.h"
258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "EditorClientGtk.h"
268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
27d0825bca7fe65beaee391d30da42e937db621564Steve Block#include "DataObjectGtk.h"
2881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch#include "DumpRenderTreeSupportGtk.h"
298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "EditCommand.h"
308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "Editor.h"
310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#include "EventNames.h"
328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "FocusController.h"
338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "Frame.h"
340bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#include <glib.h>
358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "KeyboardEvent.h"
36dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#include "markup.h"
378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "NotImplemented.h"
388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "Page.h"
39d0825bca7fe65beaee391d30da42e937db621564Steve Block#include "PasteboardHelperGtk.h"
408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "PlatformKeyboardEvent.h"
414576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang#include "WebKitDOMBinding.h"
424576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang#include "WebKitDOMCSSStyleDeclarationPrivate.h"
434576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang#include "WebKitDOMHTMLElementPrivate.h"
444576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang#include "WebKitDOMNodePrivate.h"
454576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang#include "WebKitDOMRangePrivate.h"
46dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#include "WindowsKeyboardCodes.h"
47cad810f21b803229eb11403f9209855525a25d57Steve Block#include "webkitglobalsprivate.h"
48dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#include "webkitmarshal.h"
49f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch#include "webkitwebsettingsprivate.h"
50f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch#include "webkitwebviewprivate.h"
51dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#include <wtf/text/CString.h>
528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
530bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch// Arbitrary depth limit for the undo stack, to keep it from using
540bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch// unbounded memory.  This is the maximum number of distinct undoable
550bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch// actions -- unbroken stretches of typed characters are coalesced
560bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch// into a single action.
570bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#define maximumUndoStackDepth 1000
580bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectusing namespace WebCore;
608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectnamespace WebKit {
628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
63dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockstatic void imContextCommitted(GtkIMContext* context, const gchar* compositionString, EditorClient* client)
64231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{
65dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    Frame* frame = core(client->webView())->focusController()->focusedOrMainFrame();
66dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    if (!frame || !frame->editor()->canEdit())
67dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        return;
688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
69dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // If this signal fires during a keydown event when we are not in the middle
70dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // of a composition, then treat this 'commit' as a normal key event and just
71dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // change the editable area right before the keypress event.
72dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    if (client->treatContextCommitAsKeyEvent()) {
73dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        client->updatePendingComposition(compositionString);
74dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        return;
75dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    }
768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
77f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    // If this signal fires during a mousepress event when we are in the middle
78f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    // of a composition, skip this 'commit' because the composition is already confirmed.
79f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    if (client->preventNextCompositionCommit())
80f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick        return;
81f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick
82dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    frame->editor()->confirmComposition(String::fromUTF8(compositionString));
83dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    client->clearPendingComposition();
848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic void imContextPreeditChanged(GtkIMContext* context, EditorClient* client)
878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
88dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    Frame* frame = core(client->webView())->focusController()->focusedOrMainFrame();
89dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    if (!frame || !frame->editor()->canEdit())
90dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        return;
91dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // We ignore the provided PangoAttrList for now.
93dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    GOwnPtr<gchar> newPreedit(0);
94dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    gtk_im_context_get_preedit_string(context, &newPreedit.outPtr(), 0, 0);
95dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
96dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    String preeditString = String::fromUTF8(newPreedit.get());
97dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    Vector<CompositionUnderline> underlines;
98dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    underlines.append(CompositionUnderline(0, preeditString.length(), Color(0, 0, 0), false));
99dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    frame->editor()->setComposition(preeditString, underlines, 0, 0);
100dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block}
101dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
1026c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsenstatic void backspaceCallback(GtkWidget* widget, EditorClient* client)
1036c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen{
1046c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    g_signal_stop_emission_by_name(widget, "backspace");
1056c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    client->addPendingEditorCommand("DeleteBackward");
1066c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen}
1076c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen
1086c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsenstatic void selectAllCallback(GtkWidget* widget, gboolean select, EditorClient* client)
1096c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen{
1106c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    g_signal_stop_emission_by_name(widget, "select-all");
1116c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    client->addPendingEditorCommand(select ? "SelectAll" : "Unselect");
1126c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen}
1136c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen
1146c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsenstatic void cutClipboardCallback(GtkWidget* widget, EditorClient* client)
1156c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen{
1166c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    g_signal_stop_emission_by_name(widget, "cut-clipboard");
1176c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    client->addPendingEditorCommand("Cut");
1186c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen}
1196c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen
1206c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsenstatic void copyClipboardCallback(GtkWidget* widget, EditorClient* client)
1216c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen{
1226c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    g_signal_stop_emission_by_name(widget, "copy-clipboard");
1236c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    client->addPendingEditorCommand("Copy");
1246c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen}
1256c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen
1266c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsenstatic void pasteClipboardCallback(GtkWidget* widget, EditorClient* client)
1276c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen{
1286c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    g_signal_stop_emission_by_name(widget, "paste-clipboard");
1296c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    client->addPendingEditorCommand("Paste");
1306c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen}
1316c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen
1326b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brennerstatic void toggleOverwriteCallback(GtkWidget* widget, EditorClient*)
13368513a70bcd92384395513322f1b801e7bf9c729Steve Block{
13468513a70bcd92384395513322f1b801e7bf9c729Steve Block    // We don't support toggling the overwrite mode, but the default callback expects
13568513a70bcd92384395513322f1b801e7bf9c729Steve Block    // the GtkTextView to have a layout, so we handle this signal just to stop it.
13668513a70bcd92384395513322f1b801e7bf9c729Steve Block    g_signal_stop_emission_by_name(widget, "toggle-overwrite");
13768513a70bcd92384395513322f1b801e7bf9c729Steve Block}
13868513a70bcd92384395513322f1b801e7bf9c729Steve Block
1396b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner// GTK+ will still send these signals to the web view. So we can safely stop signal
1406b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner// emission without breaking accessibility.
1416b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brennerstatic void popupMenuCallback(GtkWidget* widget, EditorClient*)
1426b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner{
1436b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    g_signal_stop_emission_by_name(widget, "popup-menu");
1446b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner}
1456b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner
1466b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brennerstatic void showHelpCallback(GtkWidget* widget, EditorClient*)
1476b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner{
1486b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    g_signal_stop_emission_by_name(widget, "show-help");
1496b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner}
1506b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner
1516c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsenstatic const char* const gtkDeleteCommands[][2] = {
1526c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    { "DeleteBackward",               "DeleteForward"                        }, // Characters
1536c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    { "DeleteWordBackward",           "DeleteWordForward"                    }, // Word ends
1546c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    { "DeleteWordBackward",           "DeleteWordForward"                    }, // Words
1556c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    { "DeleteToBeginningOfLine",      "DeleteToEndOfLine"                    }, // Lines
1566c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    { "DeleteToBeginningOfLine",      "DeleteToEndOfLine"                    }, // Line ends
1576c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    { "DeleteToBeginningOfParagraph", "DeleteToEndOfParagraph"               }, // Paragraph ends
1586c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    { "DeleteToBeginningOfParagraph", "DeleteToEndOfParagraph"               }, // Paragraphs
1596c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    { 0,                              0                                      } // Whitespace (M-\ in Emacs)
1606c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen};
1616c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen
1626c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsenstatic void deleteFromCursorCallback(GtkWidget* widget, GtkDeleteType deleteType, gint count, EditorClient* client)
1636c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen{
1646c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    g_signal_stop_emission_by_name(widget, "delete-from-cursor");
1656c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    int direction = count > 0 ? 1 : 0;
1666c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen
1676c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    // Ensuring that deleteType <= G_N_ELEMENTS here results in a compiler warning
1686c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    // that the condition is always true.
1696c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen
1706c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    if (deleteType == GTK_DELETE_WORDS) {
1716c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen        if (!direction) {
1726c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen            client->addPendingEditorCommand("MoveWordForward");
1736c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen            client->addPendingEditorCommand("MoveWordBackward");
1746c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen        } else {
1756c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen            client->addPendingEditorCommand("MoveWordBackward");
1766c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen            client->addPendingEditorCommand("MoveWordForward");
1776c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen        }
1786c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    } else if (deleteType == GTK_DELETE_DISPLAY_LINES) {
1796c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen        if (!direction)
1806c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen            client->addPendingEditorCommand("MoveToBeginningOfLine");
1816c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen        else
1826c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen            client->addPendingEditorCommand("MoveToEndOfLine");
1836c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    } else if (deleteType == GTK_DELETE_PARAGRAPHS) {
1846c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen        if (!direction)
1856c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen            client->addPendingEditorCommand("MoveToBeginningOfParagraph");
1866c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen        else
1876c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen            client->addPendingEditorCommand("MoveToEndOfParagraph");
1886c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    }
1896c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen
1906c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    const char* rawCommand = gtkDeleteCommands[deleteType][direction];
1916c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    if (!rawCommand)
1926c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen      return;
1936c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen
1946c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    for (int i = 0; i < abs(count); i++)
1956c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen        client->addPendingEditorCommand(rawCommand);
1966c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen}
1976c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen
1986c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsenstatic const char* const gtkMoveCommands[][4] = {
1996c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    { "MoveBackward",                                   "MoveForward",
2006c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen      "MoveBackwardAndModifySelection",                 "MoveForwardAndModifySelection"             }, // Forward/backward grapheme
201f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    { "MoveLeft",                                       "MoveRight",
2026c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen      "MoveBackwardAndModifySelection",                 "MoveForwardAndModifySelection"             }, // Left/right grapheme
2036c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    { "MoveWordBackward",                               "MoveWordForward",
2046c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen      "MoveWordBackwardAndModifySelection",             "MoveWordForwardAndModifySelection"         }, // Forward/backward word
2056c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    { "MoveUp",                                         "MoveDown",
2066c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen      "MoveUpAndModifySelection",                       "MoveDownAndModifySelection"                }, // Up/down line
2076c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    { "MoveToBeginningOfLine",                          "MoveToEndOfLine",
2086c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen      "MoveToBeginningOfLineAndModifySelection",        "MoveToEndOfLineAndModifySelection"         }, // Up/down line ends
2096c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    { "MoveParagraphForward",                           "MoveParagraphBackward",
2106c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen      "MoveParagraphForwardAndModifySelection",         "MoveParagraphBackwardAndModifySelection"   }, // Up/down paragraphs
2116c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    { "MoveToBeginningOfParagraph",                     "MoveToEndOfParagraph",
2126c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen      "MoveToBeginningOfParagraphAndModifySelection",   "MoveToEndOfParagraphAndModifySelection"    }, // Up/down paragraph ends.
2136c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    { "MovePageUp",                                     "MovePageDown",
2146c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen      "MovePageUpAndModifySelection",                   "MovePageDownAndModifySelection"            }, // Up/down page
2156c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    { "MoveToBeginningOfDocument",                      "MoveToEndOfDocument",
2166c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen      "MoveToBeginningOfDocumentAndModifySelection",    "MoveToEndOfDocumentAndModifySelection"     }, // Begin/end of buffer
2176c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    { 0,                                                0,
2186c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen      0,                                                0                                           } // Horizontal page movement
2196c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen};
2206c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen
2216c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsenstatic void moveCursorCallback(GtkWidget* widget, GtkMovementStep step, gint count, gboolean extendSelection, EditorClient* client)
2226c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen{
2236c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    g_signal_stop_emission_by_name(widget, "move-cursor");
2246c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    int direction = count > 0 ? 1 : 0;
2256c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    if (extendSelection)
2266c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen        direction += 2;
2276c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen
2286c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    if (static_cast<unsigned>(step) >= G_N_ELEMENTS(gtkMoveCommands))
2296c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen        return;
2306c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen
2316c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    const char* rawCommand = gtkMoveCommands[step][direction];
2326c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    if (!rawCommand)
2336c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen        return;
2346c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen
2356c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    for (int i = 0; i < abs(count); i++)
2366c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen        client->addPendingEditorCommand(rawCommand);
2376c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen}
2386c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen
239dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockvoid EditorClient::updatePendingComposition(const gchar* newComposition)
240dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block{
241dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // The IMContext may signal more than one completed composition in a row,
242dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // in which case we want to append them, rather than overwrite the old one.
243dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    if (!m_pendingComposition)
244dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        m_pendingComposition.set(g_strdup(newComposition));
245dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    else
246dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        m_pendingComposition.set(g_strconcat(m_pendingComposition.get(), newComposition, NULL));
2478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
249967717af5423377c967781471ee106e2bb4e11c8Ben Murdochvoid EditorClient::willSetInputMethodState()
250967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch{
251967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch}
252967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch
2538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid EditorClient::setInputMethodState(bool active)
2548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
2558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    WebKitWebViewPrivate* priv = m_webView->priv;
2568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (active)
25868513a70bcd92384395513322f1b801e7bf9c729Steve Block        gtk_im_context_focus_in(priv->imContext.get());
2598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    else
26068513a70bcd92384395513322f1b801e7bf9c729Steve Block        gtk_im_context_focus_out(priv->imContext.get());
2618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#ifdef MAEMO_CHANGES
2638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (active)
26468513a70bcd92384395513322f1b801e7bf9c729Steve Block        hildon_gtk_im_context_show(priv->imContext.get());
2658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    else
26668513a70bcd92384395513322f1b801e7bf9c729Steve Block        hildon_gtk_im_context_hide(priv->imContext.get());
2678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#endif
2688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2704576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wangbool EditorClient::shouldDeleteRange(Range* range)
2718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
2724576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    gboolean accept = TRUE;
273cad810f21b803229eb11403f9209855525a25d57Steve Block    GRefPtr<WebKitDOMRange> kitRange(adoptGRef(kit(range)));
2744576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    g_signal_emit_by_name(m_webView, "should-delete-range", kitRange.get(), &accept);
2754576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    return accept;
2768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2784576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wangbool EditorClient::shouldShowDeleteInterface(HTMLElement* element)
2798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
2804576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    gboolean accept = TRUE;
281cad810f21b803229eb11403f9209855525a25d57Steve Block    GRefPtr<WebKitDOMHTMLElement> kitElement(adoptGRef(kit(element)));
2824576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    g_signal_emit_by_name(m_webView, "should-show-delete-interface-for-element", kitElement.get(), &accept);
2834576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    return accept;
2848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectbool EditorClient::isContinuousSpellCheckingEnabled()
2878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
2880bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    WebKitWebSettings* settings = webkit_web_view_get_settings(m_webView);
2890bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
2900bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    gboolean enabled;
2910bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    g_object_get(settings, "enable-spell-checking", &enabled, NULL);
2920bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
2930bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    return enabled;
2948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectbool EditorClient::isGrammarCheckingEnabled()
2978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
2988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    notImplemented();
2998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return false;
3008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectint EditorClient::spellCheckerDocumentTag()
3038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
3048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    notImplemented();
3058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return 0;
3068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3084576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wangbool EditorClient::shouldBeginEditing(WebCore::Range* range)
3098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
310dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    clearPendingComposition();
311231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
3124576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    gboolean accept = TRUE;
313cad810f21b803229eb11403f9209855525a25d57Steve Block    GRefPtr<WebKitDOMRange> kitRange(adoptGRef(kit(range)));
3144576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    g_signal_emit_by_name(m_webView, "should-begin-editing", kitRange.get(), &accept);
3154576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    return accept;
3168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3184576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wangbool EditorClient::shouldEndEditing(WebCore::Range* range)
3198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
320dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    clearPendingComposition();
321231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
3224576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    gboolean accept = TRUE;
323cad810f21b803229eb11403f9209855525a25d57Steve Block    GRefPtr<WebKitDOMRange> kitRange(adoptGRef(kit(range)));
3244576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    g_signal_emit_by_name(m_webView, "should-end-editing", kitRange.get(), &accept);
3254576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    return accept;
3268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3284576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wangstatic WebKitInsertAction kit(EditorInsertAction action)
3298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
3304576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    switch (action) {
3314576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    case EditorInsertActionTyped:
3324576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang        return WEBKIT_INSERT_ACTION_TYPED;
3334576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    case EditorInsertActionPasted:
3344576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang        return WEBKIT_INSERT_ACTION_PASTED;
3354576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    case EditorInsertActionDropped:
3364576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang        return WEBKIT_INSERT_ACTION_DROPPED;
3374576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    }
3384576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    ASSERT_NOT_REACHED();
3394576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    return WEBKIT_INSERT_ACTION_TYPED;
3408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3424576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wangbool EditorClient::shouldInsertText(const String& string, Range* range, EditorInsertAction action)
3438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
3444576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    gboolean accept = TRUE;
345cad810f21b803229eb11403f9209855525a25d57Steve Block    GRefPtr<WebKitDOMRange> kitRange(adoptGRef(kit(range)));
3464576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    g_signal_emit_by_name(m_webView, "should-insert-text", string.utf8().data(), kitRange.get(), kit(action), &accept);
3474576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    return accept;
3488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3504576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wangstatic WebKitSelectionAffinity kit(EAffinity affinity)
3518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
3524576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    switch (affinity) {
3534576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    case UPSTREAM:
3544576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang        return WEBKIT_SELECTION_AFFINITY_UPSTREAM;
3554576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    case DOWNSTREAM:
3564576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang        return WEBKIT_SELECTION_AFFINITY_DOWNSTREAM;
3574576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    }
3584576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    ASSERT_NOT_REACHED();
3594576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    return WEBKIT_SELECTION_AFFINITY_UPSTREAM;
3604576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang}
3614576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang
3624576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wangbool EditorClient::shouldChangeSelectedRange(Range* fromRange, Range* toRange, EAffinity affinity, bool stillSelecting)
3634576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang{
3644576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    gboolean accept = TRUE;
365cad810f21b803229eb11403f9209855525a25d57Steve Block    GRefPtr<WebKitDOMRange> kitFromRange(fromRange ? adoptGRef(kit(fromRange)) : 0);
366cad810f21b803229eb11403f9209855525a25d57Steve Block    GRefPtr<WebKitDOMRange> kitToRange(toRange ? adoptGRef(kit(toRange)) : 0);
3674576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    g_signal_emit_by_name(m_webView, "should-change-selected-range", kitFromRange.get(), kitToRange.get(),
3684576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang                          kit(affinity), stillSelecting, &accept);
3694576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    return accept;
3704576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang}
3714576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang
3724576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wangbool EditorClient::shouldApplyStyle(WebCore::CSSStyleDeclaration* declaration, WebCore::Range* range)
3734576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang{
3744576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    gboolean accept = TRUE;
375cad810f21b803229eb11403f9209855525a25d57Steve Block    GRefPtr<WebKitDOMCSSStyleDeclaration> kitDeclaration(kit(declaration));
376cad810f21b803229eb11403f9209855525a25d57Steve Block    GRefPtr<WebKitDOMRange> kitRange(adoptGRef(kit(range)));
3774576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    g_signal_emit_by_name(m_webView, "should-apply-style", kitDeclaration.get(), kitRange.get(), &accept);
3784576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    return accept;
3798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectbool EditorClient::shouldMoveRangeAfterDelete(WebCore::Range*, WebCore::Range*)
3828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
3838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    notImplemented();
3848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return true;
3858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid EditorClient::didBeginEditing()
3888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
3894576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    g_signal_emit_by_name(m_webView, "editing-began");
3908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid EditorClient::respondToChangedContents()
3938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
3944576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    g_signal_emit_by_name(m_webView, "user-changed-contents");
3958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
397dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockstatic WebKitWebView* viewSettingClipboard = 0;
398dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockstatic void collapseSelection(GtkClipboard* clipboard, WebKitWebView* webView)
399dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block{
400dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    if (viewSettingClipboard && viewSettingClipboard == webView)
401dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        return;
402dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
403dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    WebCore::Page* corePage = core(webView);
404dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    if (!corePage || !corePage->focusController())
405dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        return;
406dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
407dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    Frame* frame = corePage->focusController()->focusedOrMainFrame();
408dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
409dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // Collapse the selection without clearing it
410dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    ASSERT(frame);
411dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    frame->selection()->setBase(frame->selection()->extent(), frame->selection()->affinity());
412dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block}
413dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
41468513a70bcd92384395513322f1b801e7bf9c729Steve Block#if PLATFORM(X11)
41568513a70bcd92384395513322f1b801e7bf9c729Steve Blockstatic void setSelectionPrimaryClipboardIfNeeded(WebKitWebView* webView)
41668513a70bcd92384395513322f1b801e7bf9c729Steve Block{
41768513a70bcd92384395513322f1b801e7bf9c729Steve Block    if (!gtk_widget_has_screen(GTK_WIDGET(webView)))
41868513a70bcd92384395513322f1b801e7bf9c729Steve Block        return;
41968513a70bcd92384395513322f1b801e7bf9c729Steve Block
42068513a70bcd92384395513322f1b801e7bf9c729Steve Block    GtkClipboard* clipboard = gtk_widget_get_clipboard(GTK_WIDGET(webView), GDK_SELECTION_PRIMARY);
42168513a70bcd92384395513322f1b801e7bf9c729Steve Block    DataObjectGtk* dataObject = DataObjectGtk::forClipboard(clipboard);
42268513a70bcd92384395513322f1b801e7bf9c729Steve Block    WebCore::Page* corePage = core(webView);
42368513a70bcd92384395513322f1b801e7bf9c729Steve Block    Frame* targetFrame = corePage->focusController()->focusedOrMainFrame();
42468513a70bcd92384395513322f1b801e7bf9c729Steve Block
42568513a70bcd92384395513322f1b801e7bf9c729Steve Block    if (!targetFrame->selection()->isRange())
42668513a70bcd92384395513322f1b801e7bf9c729Steve Block        return;
42768513a70bcd92384395513322f1b801e7bf9c729Steve Block
42868513a70bcd92384395513322f1b801e7bf9c729Steve Block    dataObject->clear();
42968513a70bcd92384395513322f1b801e7bf9c729Steve Block    dataObject->setRange(targetFrame->selection()->toNormalizedRange());
43068513a70bcd92384395513322f1b801e7bf9c729Steve Block
43168513a70bcd92384395513322f1b801e7bf9c729Steve Block    viewSettingClipboard = webView;
43268513a70bcd92384395513322f1b801e7bf9c729Steve Block    GClosure* callback = g_cclosure_new_object(G_CALLBACK(collapseSelection), G_OBJECT(webView));
43368513a70bcd92384395513322f1b801e7bf9c729Steve Block    g_closure_set_marshal(callback, g_cclosure_marshal_VOID__VOID);
43468513a70bcd92384395513322f1b801e7bf9c729Steve Block    pasteboardHelperInstance()->writeClipboardContents(clipboard, callback);
43568513a70bcd92384395513322f1b801e7bf9c729Steve Block    viewSettingClipboard = 0;
43668513a70bcd92384395513322f1b801e7bf9c729Steve Block}
43768513a70bcd92384395513322f1b801e7bf9c729Steve Block#endif
43868513a70bcd92384395513322f1b801e7bf9c729Steve Block
4398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid EditorClient::respondToChangedSelection()
4408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
4414576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    g_signal_emit_by_name(m_webView, "selection-changed");
4424576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang
4438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    WebKitWebViewPrivate* priv = m_webView->priv;
444d0825bca7fe65beaee391d30da42e937db621564Steve Block    WebCore::Page* corePage = core(m_webView);
445d0825bca7fe65beaee391d30da42e937db621564Steve Block    Frame* targetFrame = corePage->focusController()->focusedOrMainFrame();
4468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!targetFrame)
4488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
4498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (targetFrame->editor()->ignoreCompositionSelectionChange())
4518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
4528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
453d0825bca7fe65beaee391d30da42e937db621564Steve Block#if PLATFORM(X11)
45468513a70bcd92384395513322f1b801e7bf9c729Steve Block    setSelectionPrimaryClipboardIfNeeded(m_webView);
455d0825bca7fe65beaee391d30da42e937db621564Steve Block#endif
4568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!targetFrame->editor()->hasComposition())
4588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
4598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    unsigned start;
4618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    unsigned end;
4628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!targetFrame->editor()->getCompositionSelection(start, end)) {
4638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // gtk_im_context_reset() clears the composition for us.
46468513a70bcd92384395513322f1b801e7bf9c729Steve Block        gtk_im_context_reset(priv->imContext.get());
4658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        targetFrame->editor()->confirmCompositionWithoutDisturbingSelection();
4668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
4678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
4688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid EditorClient::didEndEditing()
4708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
4714576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    g_signal_emit_by_name(m_webView, "editing-ended");
4728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
4738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid EditorClient::didWriteSelectionToPasteboard()
4758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
4768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    notImplemented();
4778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
4788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid EditorClient::didSetSelectionTypesForPasteboard()
4808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
4818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    notImplemented();
4828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
4838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4840bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochvoid EditorClient::registerCommandForUndo(WTF::PassRefPtr<WebCore::EditCommand> command)
4858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
4860bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if (undoStack.size() == maximumUndoStackDepth)
4870bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        undoStack.removeFirst();
4880bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if (!m_isInRedo)
4890bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        redoStack.clear();
4900bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    undoStack.append(command);
4918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
4928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4930bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochvoid EditorClient::registerCommandForRedo(WTF::PassRefPtr<WebCore::EditCommand> command)
4948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
4950bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    redoStack.append(command);
4968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
4978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid EditorClient::clearUndoRedoOperations()
4998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
5000bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    undoStack.clear();
5010bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    redoStack.clear();
5028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
5038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
50481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdochbool EditorClient::canCopyCut(bool defaultValue) const
50581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch{
50681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    return defaultValue;
50781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch}
50881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
50981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdochbool EditorClient::canPaste(bool defaultValue) const
51081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch{
51181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    return defaultValue;
51281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch}
51381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
5148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectbool EditorClient::canUndo() const
5158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
5160bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    return !undoStack.isEmpty();
5178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
5188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectbool EditorClient::canRedo() const
5208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
5210bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    return !redoStack.isEmpty();
5228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
5238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid EditorClient::undo()
5258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
5260bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if (canUndo()) {
5270bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        RefPtr<WebCore::EditCommand> command(*(--undoStack.end()));
5280bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        undoStack.remove(--undoStack.end());
5290bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        // unapply will call us back to push this command onto the redo stack.
5300bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        command->unapply();
5310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    }
5328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
5338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid EditorClient::redo()
5358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
5360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if (canRedo()) {
5370bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        RefPtr<WebCore::EditCommand> command(*(--redoStack.end()));
5380bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        redoStack.remove(--redoStack.end());
5390bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
5400bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        ASSERT(!m_isInRedo);
5410bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        m_isInRedo = true;
5420bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        // reapply will call us back to push this command onto the undo stack.
5430bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        command->reapply();
5440bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        m_isInRedo = false;
5450bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    }
5468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
5478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5484576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wangbool EditorClient::shouldInsertNode(Node* node, Range* range, EditorInsertAction action)
5498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
5504576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    gboolean accept = TRUE;
551cad810f21b803229eb11403f9209855525a25d57Steve Block    GRefPtr<WebKitDOMRange> kitRange(adoptGRef(kit(range)));
552cad810f21b803229eb11403f9209855525a25d57Steve Block    GRefPtr<WebKitDOMNode> kitNode(adoptGRef(kit(node)));
5534576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    g_signal_emit_by_name(m_webView, "should-insert-node", kitNode.get(), kitRange.get(), kit(action), &accept);
5544576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    return accept;
5558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
5568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid EditorClient::pageDestroyed()
5588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
5598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    delete this;
5608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
5618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectbool EditorClient::smartInsertDeleteEnabled()
5638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
5648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    notImplemented();
5658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return false;
5668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
5678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
568635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectbool EditorClient::isSelectTrailingWhitespaceEnabled()
569635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
57081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    if (!DumpRenderTreeSupportGtk::dumpRenderTreeModeEnabled())
57181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        return false;
57281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    return DumpRenderTreeSupportGtk::selectTrailingWhitespaceEnabled();
573635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
574635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
5758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid EditorClient::toggleContinuousSpellChecking()
5768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
5770bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    WebKitWebSettings* settings = webkit_web_view_get_settings(m_webView);
5780bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
5790bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    gboolean enabled;
5800bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    g_object_get(settings, "enable-spell-checking", &enabled, NULL);
5810bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
5820bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    g_object_set(settings, "enable-spell-checking", !enabled, NULL);
5838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
5848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid EditorClient::toggleGrammarChecking()
5868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
5878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
5888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5890bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochstatic const unsigned CtrlKey = 1 << 0;
5900bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochstatic const unsigned AltKey = 1 << 1;
5910bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochstatic const unsigned ShiftKey = 1 << 2;
5920bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
5930bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochstruct KeyDownEntry {
5940bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    unsigned virtualKey;
5950bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    unsigned modifiers;
5960bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    const char* name;
5970bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch};
5980bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
5990bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochstruct KeyPressEntry {
6000bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    unsigned charCode;
6010bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    unsigned modifiers;
6020bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    const char* name;
6030bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch};
6040bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
6050bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochstatic const KeyDownEntry keyDownEntries[] = {
6060bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    { 'B',       CtrlKey,            "ToggleBold"                                  },
6070bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    { 'I',       CtrlKey,            "ToggleItalic"                                },
6080bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    { VK_ESCAPE, 0,                  "Cancel"                                      },
6090bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    { VK_OEM_PERIOD, CtrlKey,        "Cancel"                                      },
6100bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    { VK_TAB,    0,                  "InsertTab"                                   },
6110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    { VK_TAB,    ShiftKey,           "InsertBacktab"                               },
6120bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    { VK_RETURN, 0,                  "InsertNewline"                               },
6130bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    { VK_RETURN, CtrlKey,            "InsertNewline"                               },
6140bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    { VK_RETURN, AltKey,             "InsertNewline"                               },
6150bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    { VK_RETURN, AltKey | ShiftKey,  "InsertNewline"                               },
6160bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch};
6170bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
6180bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochstatic const KeyPressEntry keyPressEntries[] = {
6190bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    { '\t',   0,                  "InsertTab"                                   },
6200bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    { '\t',   ShiftKey,           "InsertBacktab"                               },
6210bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    { '\r',   0,                  "InsertNewline"                               },
6220bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    { '\r',   CtrlKey,            "InsertNewline"                               },
6230bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    { '\r',   AltKey,             "InsertNewline"                               },
6240bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    { '\r',   AltKey | ShiftKey,  "InsertNewline"                               },
6250bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch};
6260bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
6276c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsenvoid EditorClient::generateEditorCommands(const KeyboardEvent* event)
6280bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch{
6296c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    ASSERT(event->type() == eventNames().keydownEvent || event->type() == eventNames().keypressEvent);
6300bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
6316c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    m_pendingEditorCommands.clear();
6326c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen
6336c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    // First try to interpret the command as a native GTK+ key binding.
634a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#ifdef GTK_API_VERSION_2
6356c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    gtk_bindings_activate_event(GTK_OBJECT(m_nativeWidget.get()), event->keyEvent()->gdkEventKey());
636a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#else
637a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    gtk_bindings_activate_event(G_OBJECT(m_nativeWidget.get()), event->keyEvent()->gdkEventKey());
638a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#endif
6396c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    if (m_pendingEditorCommands.size() > 0)
6406c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen        return;
6410bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
6426c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    static HashMap<int, const char*> keyDownCommandsMap;
6436c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    static HashMap<int, const char*> keyPressCommandsMap;
6440bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
6456c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    if (keyDownCommandsMap.isEmpty()) {
6460bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        for (unsigned i = 0; i < G_N_ELEMENTS(keyDownEntries); i++)
6476c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen            keyDownCommandsMap.set(keyDownEntries[i].modifiers << 16 | keyDownEntries[i].virtualKey, keyDownEntries[i].name);
6480bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
6490bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        for (unsigned i = 0; i < G_N_ELEMENTS(keyPressEntries); i++)
6506c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen            keyPressCommandsMap.set(keyPressEntries[i].modifiers << 16 | keyPressEntries[i].charCode, keyPressEntries[i].name);
6510bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    }
6528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6530bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    unsigned modifiers = 0;
6546c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    if (event->shiftKey())
6550bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        modifiers |= ShiftKey;
6566c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    if (event->altKey())
6570bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        modifiers |= AltKey;
6586c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    if (event->ctrlKey())
6590bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        modifiers |= CtrlKey;
6600bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
661cad810f21b803229eb11403f9209855525a25d57Steve Block    // For keypress events, we want charCode(), but keyCode() does that.
662cad810f21b803229eb11403f9209855525a25d57Steve Block    int mapKey = modifiers << 16 | event->keyCode();
663cad810f21b803229eb11403f9209855525a25d57Steve Block    if (!mapKey)
6646c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen        return;
665cad810f21b803229eb11403f9209855525a25d57Steve Block    HashMap<int, const char*>* commandMap = event->type() == eventNames().keydownEvent ?
666cad810f21b803229eb11403f9209855525a25d57Steve Block        &keyDownCommandsMap : &keyPressCommandsMap;
667cad810f21b803229eb11403f9209855525a25d57Steve Block    if (const char* commandString = commandMap->get(mapKey))
668cad810f21b803229eb11403f9209855525a25d57Steve Block        m_pendingEditorCommands.append(commandString);
6696c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen}
6706c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen
6716c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsenbool EditorClient::executePendingEditorCommands(Frame* frame, bool allowTextInsertion)
6726c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen{
6736c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    Vector<Editor::Command> commands;
6746c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    for (size_t i = 0; i < m_pendingEditorCommands.size(); i++) {
675cad810f21b803229eb11403f9209855525a25d57Steve Block        const char* commandString = m_pendingEditorCommands.at(i);
676cad810f21b803229eb11403f9209855525a25d57Steve Block        ASSERT(commandString);
677cad810f21b803229eb11403f9209855525a25d57Steve Block        Editor::Command command = frame->editor()->command(commandString);
6786c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen        if (command.isTextInsertion() && !allowTextInsertion)
6796c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen            return false;
6806c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen
6816c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen        commands.append(command);
6826c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    }
6836c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen
6846c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    bool success = true;
6856c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    for (size_t i = 0; i < commands.size(); i++) {
6866c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen        if (!commands.at(i).execute()) {
6876c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen            success = false;
6886c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen            break;
6896c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen        }
6906c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    }
6916c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen
6926c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    m_pendingEditorCommands.clear();
6936c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen
6946c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    // If we successfully completed all editor commands, then
6956c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    // this signals a canceling of the composition.
6966c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    if (success)
6976c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen        clearPendingComposition();
6986c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen
6996c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    return success;
7000bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch}
7010bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
702231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockvoid EditorClient::handleKeyboardEvent(KeyboardEvent* event)
7030bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch{
704231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    Node* node = event->target()->toNode();
7050bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ASSERT(node);
7060bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Frame* frame = node->document()->frame();
7070bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ASSERT(frame);
7080bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
709231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    const PlatformKeyboardEvent* platformEvent = event->keyEvent();
710231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    if (!platformEvent)
711231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        return;
712231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
7136c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    generateEditorCommands(event);
7146c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    if (m_pendingEditorCommands.size() > 0) {
715231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
7166c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen        // During RawKeyDown events if an editor command will insert text, defer
7176c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen        // the insertion until the keypress event. We want keydown to bubble up
7186c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen        // through the DOM first.
719231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        if (platformEvent->type() == PlatformKeyboardEvent::RawKeyDown) {
7206c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen            if (executePendingEditorCommands(frame, false))
721231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block                event->setDefaultHandled();
722231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
723231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            return;
724dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        }
725dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
72606ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen        // Only allow text insertion commands if the current node is editable.
72706ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen        if (executePendingEditorCommands(frame, frame->editor()->canEdit())) {
728231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            event->setDefaultHandled();
729231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            return;
7308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
7318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
7320bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
73306ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen    // Don't allow text insertion for nodes that cannot edit.
73406ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen    if (!frame->editor()->canEdit())
73506ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen        return;
73606ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen
737231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    // This is just a normal text insertion, so wait to execute the insertion
738231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    // until a keypress event happens. This will ensure that the insertion will not
739231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    // be reflected in the contents of the field until the keyup DOM event.
740231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    if (event->type() == eventNames().keypressEvent) {
7410bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
742dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        // If we have a pending composition at this point, it happened while
743dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        // filtering a keypress, so we treat it as a normal text insertion.
744dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        // This will also ensure that if the keypress event handler changed the
745dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        // currently focused node, the text is still inserted into the original
746dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        // node (insertText() has this logic, but confirmComposition() does not).
747dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        if (m_pendingComposition) {
748dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            frame->editor()->insertText(String::fromUTF8(m_pendingComposition.get()), event);
749dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            clearPendingComposition();
750231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            event->setDefaultHandled();
7510bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
752231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        } else {
753231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            // Don't insert null or control characters as they can result in unexpected behaviour
754231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            if (event->charCode() < ' ')
755231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block                return;
756231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
757231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            // Don't insert anything if a modifier is pressed
758231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            if (platformEvent->ctrlKey() || platformEvent->altKey())
759231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block                return;
760231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
761231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            if (frame->editor()->insertText(platformEvent->text(), event))
762231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block                event->setDefaultHandled();
763231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        }
764231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    }
7658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
7668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid EditorClient::handleInputMethodKeydown(KeyboardEvent* event)
7688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
769563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    Frame* targetFrame = core(m_webView)->focusController()->focusedOrMainFrame();
770563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    if (!targetFrame || !targetFrame->editor()->canEdit())
771563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark        return;
7728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
773563af33bc48281d19dce701398dbb88cb54fd7ecCary Clark    WebKitWebViewPrivate* priv = m_webView->priv;
774dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
775f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    m_preventNextCompositionCommit = false;
776dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
777dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // Some IM contexts (e.g. 'simple') will act as if they filter every
778dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // keystroke and just issue a 'commit' signal during handling. In situations
779dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // where the 'commit' signal happens during filtering and there is no active
780dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // composition, act as if the keystroke was not filtered. The one exception to
781dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // this is when the keyval parameter of the GdkKeyEvent is 0, which is often
782dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // a key event sent by the IM context for committing the current composition.
783dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
784dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // Here is a typical sequence of events for the 'simple' context:
785dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // 1. GDK key press event -> webkit_web_view_key_press_event
786dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // 2. Keydown event -> EditorClient::handleInputMethodKeydown
787dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    //     gtk_im_context_filter_keypress returns true, but there is a pending
788dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    //     composition so event->preventDefault is not called (below).
789dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // 3. Keydown event bubbles through the DOM
790dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // 4. Keydown event -> EditorClient::handleKeyboardEvent
791dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    //     No action taken.
792dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // 4. GDK key release event -> webkit_web_view_key_release_event
793dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // 5. gtk_im_context_filter_keypress is called on the release event.
794dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    //     Simple does not filter most key releases, so the event continues.
795dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // 6. Keypress event bubbles through the DOM.
796dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // 7. Keypress event -> EditorClient::handleKeyboardEvent
797dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    //     pending composition is inserted.
798dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // 8. Keyup event bubbles through the DOM.
799dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // 9. Keyup event -> EditorClient::handleKeyboardEvent
800dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    //     No action taken.
801dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
802dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // There are two situations where we do filter the keystroke:
803dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // 1. The IMContext instructed us to filter and we have no pending composition.
804dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // 2. The IMContext did not instruct us to filter, but the keystroke caused a
805dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    //    composition in progress to finish. It seems that sometimes SCIM will finish
806dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    //    a composition and not mark the keystroke as filtered.
807dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    m_treatContextCommitAsKeyEvent = (!targetFrame->editor()->hasComposition())
808dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block         && event->keyEvent()->gdkEventKey()->keyval;
809dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    clearPendingComposition();
81068513a70bcd92384395513322f1b801e7bf9c729Steve Block    if ((gtk_im_context_filter_keypress(priv->imContext.get(), event->keyEvent()->gdkEventKey()) && !m_pendingComposition)
811dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        || (!m_treatContextCommitAsKeyEvent && !targetFrame->editor()->hasComposition()))
812dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        event->preventDefault();
813dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
814dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    m_treatContextCommitAsKeyEvent = false;
8158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
8168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
817f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrickvoid EditorClient::handleInputMethodMousePress()
818f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick{
819f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    Frame* targetFrame = core(m_webView)->focusController()->focusedOrMainFrame();
820f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick
821f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    if (!targetFrame || !targetFrame->editor()->canEdit())
822f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick        return;
823f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick
824f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    WebKitWebViewPrivate* priv = m_webView->priv;
825f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick
826f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    // When a mouse press fires, the commit signal happens during a composition.
827f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    // In this case, if the focused node is changed, the commit signal happens in a diffrent node.
828f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    // Therefore, we need to confirm the current compositon and ignore the next commit signal.
829f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    GOwnPtr<gchar> newPreedit(0);
83068513a70bcd92384395513322f1b801e7bf9c729Steve Block    gtk_im_context_get_preedit_string(priv->imContext.get(), &newPreedit.outPtr(), 0, 0);
831f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick
832f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    if (g_utf8_strlen(newPreedit.get(), -1)) {
833f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick        targetFrame->editor()->confirmComposition();
834f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick        m_preventNextCompositionCommit = true;
83568513a70bcd92384395513322f1b801e7bf9c729Steve Block        gtk_im_context_reset(priv->imContext.get());
836f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    }
837f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick}
838f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick
8398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectEditorClient::EditorClient(WebKitWebView* webView)
8400bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    : m_isInRedo(false)
84181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch#if ENABLE(SPELLCHECK)
84281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    , m_textCheckerClient(webView)
84381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch#endif
8440bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    , m_webView(webView)
845f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    , m_preventNextCompositionCommit(false)
846dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    , m_treatContextCommitAsKeyEvent(false)
8476c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    , m_nativeWidget(gtk_text_view_new())
8488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
8498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    WebKitWebViewPrivate* priv = m_webView->priv;
85068513a70bcd92384395513322f1b801e7bf9c729Steve Block    g_signal_connect(priv->imContext.get(), "commit", G_CALLBACK(imContextCommitted), this);
85168513a70bcd92384395513322f1b801e7bf9c729Steve Block    g_signal_connect(priv->imContext.get(), "preedit-changed", G_CALLBACK(imContextPreeditChanged), this);
8526c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen
8536c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    g_signal_connect(m_nativeWidget.get(), "backspace", G_CALLBACK(backspaceCallback), this);
8546c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    g_signal_connect(m_nativeWidget.get(), "cut-clipboard", G_CALLBACK(cutClipboardCallback), this);
8556c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    g_signal_connect(m_nativeWidget.get(), "copy-clipboard", G_CALLBACK(copyClipboardCallback), this);
8566c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    g_signal_connect(m_nativeWidget.get(), "paste-clipboard", G_CALLBACK(pasteClipboardCallback), this);
8576c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    g_signal_connect(m_nativeWidget.get(), "select-all", G_CALLBACK(selectAllCallback), this);
8586c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    g_signal_connect(m_nativeWidget.get(), "move-cursor", G_CALLBACK(moveCursorCallback), this);
8596c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen    g_signal_connect(m_nativeWidget.get(), "delete-from-cursor", G_CALLBACK(deleteFromCursorCallback), this);
86068513a70bcd92384395513322f1b801e7bf9c729Steve Block    g_signal_connect(m_nativeWidget.get(), "toggle-overwrite", G_CALLBACK(toggleOverwriteCallback), this);
8616b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    g_signal_connect(m_nativeWidget.get(), "popup-menu", G_CALLBACK(popupMenuCallback), this);
8626b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner    g_signal_connect(m_nativeWidget.get(), "show-help", G_CALLBACK(showHelpCallback), this);
8638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
8648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectEditorClient::~EditorClient()
8668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
8678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    WebKitWebViewPrivate* priv = m_webView->priv;
86868513a70bcd92384395513322f1b801e7bf9c729Steve Block    g_signal_handlers_disconnect_by_func(priv->imContext.get(), (gpointer)imContextCommitted, this);
86968513a70bcd92384395513322f1b801e7bf9c729Steve Block    g_signal_handlers_disconnect_by_func(priv->imContext.get(), (gpointer)imContextPreeditChanged, this);
8708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
8718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid EditorClient::textFieldDidBeginEditing(Element*)
8738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
8748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
8758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid EditorClient::textFieldDidEndEditing(Element*)
8778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
8788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
8798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid EditorClient::textDidChangeInTextField(Element*)
8818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
8828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
8838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectbool EditorClient::doTextFieldCommandFromEvent(Element*, KeyboardEvent*)
8858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
8868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return false;
8878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
8888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid EditorClient::textWillBeDeletedInTextField(Element*)
8908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
8918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    notImplemented();
8928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
8938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid EditorClient::textDidChangeInTextArea(Element*)
8958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
8968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    notImplemented();
8978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
8988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid EditorClient::updateSpellingUIWithGrammarString(const String&, const GrammarDetail&)
9008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
9018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    notImplemented();
9028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
9038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid EditorClient::updateSpellingUIWithMisspelledWord(const String&)
9058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
9068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    notImplemented();
9078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
9088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid EditorClient::showSpellingUI(bool)
9108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
9118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    notImplemented();
9128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
9138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectbool EditorClient::spellingUIIsShowing()
9158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
9168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    notImplemented();
9178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return false;
9188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
9198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
921