• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  // Copyright (c) 2010 The Chromium Authors. All rights reserved.
2  // Use of this source code is governed by a BSD-style license that can be
3  // found in the LICENSE file.
4  
5  #ifndef CHROME_BROWSER_RENDERER_HOST_GTK_IM_CONTEXT_WRAPPER_H_
6  #define CHROME_BROWSER_RENDERER_HOST_GTK_IM_CONTEXT_WRAPPER_H_
7  #pragma once
8  
9  #include <gdk/gdk.h>
10  #include <pango/pango-attributes.h>
11  #include <vector>
12  
13  #include "base/basictypes.h"
14  #include "base/gtest_prod_util.h"
15  #include "base/string16.h"
16  #include "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.h"
17  #include "third_party/WebKit/Source/WebKit/chromium/public/WebTextInputType.h"
18  #include "ui/base/ime/composition_text.h"
19  
20  namespace gfx {
21  class Rect;
22  }
23  
24  #if !defined(TOOLKIT_VIEWS)
25  class MenuGtk;
26  #endif
27  class RenderWidgetHostViewGtk;
28  struct NativeWebKeyboardEvent;
29  typedef struct _GtkIMContext GtkIMContext;
30  typedef struct _GtkWidget GtkWidget;
31  
32  // This class is a convenience wrapper for GtkIMContext.
33  // It creates and manages two GtkIMContext instances, one is GtkIMMulticontext,
34  // for plain text input box, another is GtkIMContextSimple, for password input
35  // box.
36  //
37  // This class is in charge of dispatching key events to these two GtkIMContext
38  // instances and handling signals emitted by them. Key events then will be
39  // forwarded to renderer along with input method results via corresponding host
40  // view.
41  //
42  // This class is used solely by RenderWidgetHostViewGtk.
43  class GtkIMContextWrapper {
44   public:
45    explicit GtkIMContextWrapper(RenderWidgetHostViewGtk* host_view);
46    ~GtkIMContextWrapper();
47  
48    // Processes a gdk key event received by |host_view|.
49    void ProcessKeyEvent(GdkEventKey* event);
50  
51    void UpdateInputMethodState(WebKit::WebTextInputType type,
52                                const gfx::Rect& caret_rect);
53    void OnFocusIn();
54    void OnFocusOut();
55  
56  #if !defined(TOOLKIT_VIEWS)
57    // Not defined for views because the views context menu doesn't
58    // implement input methods yet.
59    void AppendInputMethodsContextMenu(MenuGtk* menu);
60  #endif
61  
62    void CancelComposition();
63  
64    void ConfirmComposition();
65  
66   private:
67    // Check if a text needs commit by forwarding a char event instead of
68    // by confirming as a composition text.
69    bool NeedCommitByForwardingCharEvent() const;
70  
71    // Check if the input method returned any result, eg. preedit and commit text.
72    bool HasInputMethodResult() const;
73  
74    void ProcessFilteredKeyPressEvent(NativeWebKeyboardEvent* wke);
75    void ProcessUnfilteredKeyPressEvent(NativeWebKeyboardEvent* wke);
76  
77    // Processes result returned from input method after filtering a key event.
78    // |filtered| indicates if the key event was filtered by the input method.
79    void ProcessInputMethodResult(const GdkEventKey* event, bool filtered);
80  
81    // Real code of "commit" signal handler.
82    void HandleCommit(const string16& text);
83  
84    // Real code of "preedit-start" signal handler.
85    void HandlePreeditStart();
86  
87    // Real code of "preedit-changed" signal handler.
88    void HandlePreeditChanged(const gchar* text,
89                              PangoAttrList* attrs,
90                              int cursor_position);
91  
92    // Real code of "preedit-end" signal handler.
93    void HandlePreeditEnd();
94  
95    // Real code of "realize" signal handler, used for setting im context's client
96    // window.
97    void HandleHostViewRealize(GtkWidget* widget);
98  
99    // Real code of "unrealize" signal handler, used for unsetting im context's
100    // client window.
101    void HandleHostViewUnrealize();
102  
103    // Sends a fake composition key event with specified event type. A composition
104    // key event is a key event with special key code 229.
105    void SendFakeCompositionKeyEvent(WebKit::WebInputEvent::Type type);
106  
107    // Signal handlers of GtkIMContext object.
108    static void HandleCommitThunk(GtkIMContext* context, gchar* text,
109                                  GtkIMContextWrapper* self);
110    static void HandlePreeditStartThunk(GtkIMContext* context,
111                                        GtkIMContextWrapper* self);
112    static void HandlePreeditChangedThunk(GtkIMContext* context,
113                                          GtkIMContextWrapper* self);
114    static void HandlePreeditEndThunk(GtkIMContext* context,
115                                      GtkIMContextWrapper* self);
116  
117    // Signal handlers connecting to |host_view_|'s native view widget.
118    static void HandleHostViewRealizeThunk(GtkWidget* widget,
119                                           GtkIMContextWrapper* self);
120    static void HandleHostViewUnrealizeThunk(GtkWidget* widget,
121                                             GtkIMContextWrapper* self);
122  
123    // The parent object.
124    RenderWidgetHostViewGtk* host_view_;
125  
126    // The GtkIMContext object.
127    // In terms of the DOM event specification Appendix A
128    //   <http://www.w3.org/TR/DOM-Level-3-Events/keyset.html>,
129    // GTK uses a GtkIMContext object for the following two purposes:
130    //  1. Composing Latin characters (A.1.2), and;
131    //  2. Composing CJK characters with an IME (A.1.3).
132    // Many JavaScript pages assume composed Latin characters are dispatched to
133    // their onkeypress() handlers but not dispatched CJK characters composed
134    // with an IME. To emulate this behavior, we should monitor the status of
135    // this GtkIMContext object and prevent sending Char events when a
136    // GtkIMContext object sends a "commit" signal with the CJK characters
137    // composed by an IME.
138    GtkIMContext* context_;
139  
140    // A GtkIMContextSimple object, for supporting dead/compose keys when input
141    // method is disabled, eg. in password input box.
142    GtkIMContext* context_simple_;
143  
144    // Whether or not this widget is focused.
145    bool is_focused_;
146  
147    // Whether or not the above GtkIMContext is composing a text with an IME.
148    // This flag is used in "commit" signal handler of the GtkIMContext object,
149    // which determines how to submit the result text to WebKit according to this
150    // flag.
151    // If this flag is true or there are more than one characters in the result,
152    // then the result text will be committed to WebKit as a confirmed
153    // composition. Otherwise, it'll be forwarded as a key event.
154    //
155    // The GtkIMContext object sends a "preedit_start" before it starts composing
156    // a text and a "preedit_end" signal after it finishes composing it.
157    // "preedit_start" signal is monitored to turn it on.
158    // We don't monitor "preedit_end" signal to turn it off, because an input
159    // method may fire "preedit_end" signal before "commit" signal.
160    // A buggy input method may not fire "preedit_start" and/or "preedit_end"
161    // at all, so this flag will also be set to true when "preedit_changed" signal
162    // is fired with non-empty preedit text.
163    bool is_composing_text_;
164  
165    // Whether or not the IME is enabled.
166    bool is_enabled_;
167  
168    // Whether or not it's currently running inside key event handler.
169    // If it's true, then preedit-changed and commit handler will backup the
170    // preedit or commit text instead of sending them down to webkit.
171    // key event handler will send them later.
172    bool is_in_key_event_handler_;
173  
174    // The most recent composition text information retrieved from context_;
175    ui::CompositionText composition_;
176  
177    // Whether or not the composition has been changed since last key event.
178    bool is_composition_changed_;
179  
180    // Stores a copy of the most recent commit text received by commit signal
181    // handler.
182    string16 commit_text_;
183  
184    // If it's true then the next "commit" signal will be suppressed.
185    // It's only used to workaround http://crbug.com/50485.
186    // TODO(suzhe): Remove it after input methods get fixed.
187    bool suppress_next_commit_;
188  
189    // Information of the last key event, for working around
190    // http://crosbug.com/6582
191    int last_key_code_;
192    bool last_key_was_up_;
193    bool last_key_filtered_no_result_;
194  
195    DISALLOW_COPY_AND_ASSIGN(GtkIMContextWrapper);
196  };
197  
198  #endif  // CHROME_BROWSER_RENDERER_HOST_GTK_IM_CONTEXT_WRAPPER_H_
199