Home | History | Annotate | Download | only in renderer_host
      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