Bug 685395 part.4 IME open state should be able to set/get by InputContext r=roc, sr=matspal
authorMasayuki Nakano <masayuki@d-toybox.com>
Sun, 27 Nov 2011 20:51:53 +0900
changeset 82494 029a09f71d7936e96ab6f018355f79949434dcbb
parent 82493 a1b2a561db2bb7896d322b8ef9a7910c642cdc6e
child 82495 98c4d6ce4b9eb22340405fc8eb7b5a9131635dba
push idunknown
push userunknown
push dateunknown
reviewersroc, matspal
bugs685395
milestone11.0a1
Bug 685395 part.4 IME open state should be able to set/get by InputContext r=roc, sr=matspal
content/base/public/nsContentUtils.h
content/base/src/nsContentUtils.cpp
content/events/src/nsIMEStateManager.cpp
content/events/src/nsIMEStateManager.h
dom/base/nsDOMWindowUtils.cpp
dom/ipc/PBrowser.ipdl
dom/ipc/TabParent.cpp
dom/ipc/TabParent.h
widget/public/nsIWidget.h
widget/src/android/nsWindow.cpp
widget/src/cocoa/nsChildView.h
widget/src/cocoa/nsChildView.mm
widget/src/gtk2/nsGtkIMModule.cpp
widget/src/gtk2/nsWindow.cpp
widget/src/qt/nsWindow.cpp
widget/src/windows/nsTextStore.cpp
widget/src/windows/nsTextStore.h
widget/src/windows/nsWindow.cpp
widget/src/windows/nsWindow.h
widget/src/xpwidgets/PuppetWidget.cpp
widget/src/xpwidgets/PuppetWidget.h
widget/src/xpwidgets/nsBaseWidget.h
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -1285,21 +1285,16 @@ public:
 #endif
     }
   }
   static void ReleaseWrapper(nsISupports* aScriptObjectHolder,
                              nsWrapperCache* aCache);
   static void TraceWrapper(nsWrapperCache* aCache, TraceCallback aCallback,
                            void *aClosure);
 
-  /**
-   * Convert nsIContent::IME_STATUS_* to nsIWidget::IME_STATUS_*
-   */
-  static PRUint32 GetWidgetStatusFromIMEStatus(PRUint32 aState);
-
   /*
    * Notify when the first XUL menu is opened and when the all XUL menus are
    * closed. At opening, aInstalling should be TRUE, otherwise, it should be
    * FALSE.
    */
   static void NotifyInstalledMenuKeyboardListener(bool aInstalling);
 
   /**
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -4023,35 +4023,16 @@ nsContentUtils::DropJSObjects(void* aScr
   nsresult rv = sXPConnect->RemoveJSHolder(aScriptObjectHolder);
   if (--sJSGCThingRootCount == 0) {
     nsLayoutStatics::Release();
   }
   return rv;
 }
 
 /* static */
-PRUint32
-nsContentUtils::GetWidgetStatusFromIMEStatus(PRUint32 aState)
-{
-  switch (aState & nsIContent::IME_STATUS_MASK_ENABLED) {
-    case nsIContent::IME_STATUS_DISABLE:
-      return InputContext::IME_DISABLED;
-    case nsIContent::IME_STATUS_ENABLE:
-      return InputContext::IME_ENABLED;
-    case nsIContent::IME_STATUS_PASSWORD:
-      return InputContext::IME_PASSWORD;
-    case nsIContent::IME_STATUS_PLUGIN:
-      return InputContext::IME_PLUGIN;
-    default:
-      NS_ERROR("The given state doesn't have valid enable state");
-      return InputContext::IME_ENABLED;
-  }
-}
-
-/* static */
 void
 nsContentUtils::NotifyInstalledMenuKeyboardListener(bool aInstalling)
 {
   nsIMEStateManager::OnInstalledMenuKeyboardListener(aInstalling);
 }
 
 static bool SchemeIs(nsIURI* aURI, const char* aScheme)
 {
--- a/content/events/src/nsIMEStateManager.cpp
+++ b/content/events/src/nsIMEStateManager.cpp
@@ -64,16 +64,36 @@
 #include "nsIObserverService.h"
 #include "mozilla/Services.h"
 #include "nsIFormControl.h"
 #include "nsIForm.h"
 #include "nsHTMLFormElement.h"
 
 using namespace mozilla::widget;
 
+static
+/* static */
+IMEState::Enabled
+GetWidgetStatusFromIMEStatus(PRUint32 aState)
+{
+  switch (aState & nsIContent::IME_STATUS_MASK_ENABLED) {
+    case nsIContent::IME_STATUS_DISABLE:
+      return IMEState::DISABLED;
+    case nsIContent::IME_STATUS_ENABLE:
+      return IMEState::ENABLED;
+    case nsIContent::IME_STATUS_PASSWORD:
+      return IMEState::PASSWORD;
+    case nsIContent::IME_STATUS_PLUGIN:
+      return IMEState::PLUGIN;
+    default:
+      NS_ERROR("The given state doesn't have valid enable state");
+      return IMEState::ENABLED;
+  }
+}
+
 /******************************************************************/
 /* nsIMEStateManager                                              */
 /******************************************************************/
 
 nsIContent*    nsIMEStateManager::sContent      = nsnull;
 nsPresContext* nsIMEStateManager::sPresContext  = nsnull;
 bool           nsIMEStateManager::sInstalledMenuKeyboardListener = false;
 bool           nsIMEStateManager::sInSecureInputMode = false;
@@ -176,18 +196,18 @@ nsIMEStateManager::OnChangeFocusInternal
     // actual focus isn't changing, but if IME enabled state is changing,
     // we should do it.
     PRUint32 newEnabledState = newState & nsIContent::IME_STATUS_MASK_ENABLED;
     if (newEnabledState == 0) {
       // the enabled state isn't changing, we should do nothing.
       return NS_OK;
     }
     InputContext context = widget->GetInputContext();
-    if (context.mIMEEnabled ==
-        nsContentUtils::GetWidgetStatusFromIMEStatus(newEnabledState)) {
+    if (context.mIMEState.mEnabled ==
+          GetWidgetStatusFromIMEStatus(newEnabledState)) {
       // the enabled state isn't changing.
       return NS_OK;
     }
     aAction.mFocusChange = InputContextAction::FOCUS_NOT_CHANGED;
   } else if (aAction.mFocusChange == InputContextAction::FOCUS_NOT_CHANGED) {
     // If aContent isn't null or aContent is null but editable, somebody gets
     // focus.
     bool gotFocus = aContent || (newState & nsIContent::IME_STATUS_ENABLE);
@@ -240,18 +260,18 @@ nsIMEStateManager::UpdateIMEState(PRUint
   if (!widget) {
     NS_WARNING("focused widget is not found");
     return;
   }
 
   // Don't update IME state when enabled state isn't actually changed.
   InputContext context = widget->GetInputContext();
   PRUint32 newEnabledState = aNewIMEState & nsIContent::IME_STATUS_MASK_ENABLED;
-  if (context.mIMEEnabled ==
-        nsContentUtils::GetWidgetStatusFromIMEStatus(newEnabledState)) {
+  if (context.mIMEState.mEnabled ==
+        GetWidgetStatusFromIMEStatus(newEnabledState)) {
     return;
   }
 
   // commit current composition
   widget->ResetInputState();
 
   InputContextAction action(InputContextAction::CAUSE_UNKNOWN,
                             InputContextAction::FOCUS_NOT_CHANGED);
@@ -306,71 +326,70 @@ private:
 };
 
 void
 nsIMEStateManager::SetIMEState(PRUint32 aState,
                                nsIContent* aContent,
                                nsIWidget* aWidget,
                                InputContextAction aAction)
 {
-  if (aState & nsIContent::IME_STATUS_MASK_ENABLED) {
-    if (!aWidget)
-      return;
+  NS_ENSURE_TRUE(aWidget, );
 
-    PRUint32 state = nsContentUtils::GetWidgetStatusFromIMEStatus(aState);
-    InputContext context;
-    context.mIMEEnabled = state;
+  InputContext context;
+  context.mIMEState.mEnabled = GetWidgetStatusFromIMEStatus(aState);
 
-    if (aContent && aContent->GetNameSpaceID() == kNameSpaceID_XHTML &&
-        (aContent->Tag() == nsGkAtoms::input ||
-         aContent->Tag() == nsGkAtoms::textarea)) {
-      aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::type,
-                        context.mHTMLInputType);
-      aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::moz_action_hint,
-                        context.mActionHint);
+  if (aContent && aContent->GetNameSpaceID() == kNameSpaceID_XHTML &&
+      (aContent->Tag() == nsGkAtoms::input ||
+       aContent->Tag() == nsGkAtoms::textarea)) {
+    aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::type,
+                      context.mHTMLInputType);
+    aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::moz_action_hint,
+                      context.mActionHint);
 
-      // if we don't have an action hint and  return won't submit the form use "next"
-      if (context.mActionHint.IsEmpty() && aContent->Tag() == nsGkAtoms::input) {
-        bool willSubmit = false;
-        nsCOMPtr<nsIFormControl> control(do_QueryInterface(aContent));
-        mozilla::dom::Element* formElement = control->GetFormElement();
-        nsCOMPtr<nsIForm> form;
-        if (control) {
-          // is this a form and does it have a default submit element?
-          if ((form = do_QueryInterface(formElement)) && form->GetDefaultSubmitElement()) {
-            willSubmit = true;
-          // is this an html form and does it only have a single text input element?
-          } else if (formElement && formElement->Tag() == nsGkAtoms::form && formElement->IsHTML() &&
-                     static_cast<nsHTMLFormElement*>(formElement)->HasSingleTextControl()) {
-            willSubmit = true;
-          }
+    // if we don't have an action hint and  return won't submit the form use "next"
+    if (context.mActionHint.IsEmpty() && aContent->Tag() == nsGkAtoms::input) {
+      bool willSubmit = false;
+      nsCOMPtr<nsIFormControl> control(do_QueryInterface(aContent));
+      mozilla::dom::Element* formElement = control->GetFormElement();
+      nsCOMPtr<nsIForm> form;
+      if (control) {
+        // is this a form and does it have a default submit element?
+        if ((form = do_QueryInterface(formElement)) && form->GetDefaultSubmitElement()) {
+          willSubmit = true;
+        // is this an html form and does it only have a single text input element?
+        } else if (formElement && formElement->Tag() == nsGkAtoms::form && formElement->IsHTML() &&
+                   static_cast<nsHTMLFormElement*>(formElement)->HasSingleTextControl()) {
+          willSubmit = true;
         }
-        context.mActionHint.Assign(willSubmit ? control->GetType() == NS_FORM_INPUT_SEARCH
-                                                  ? NS_LITERAL_STRING("search")
-                                                  : NS_LITERAL_STRING("go")
-                                              : formElement
-                                                  ? NS_LITERAL_STRING("next")
-                                                  : EmptyString());
       }
+      context.mActionHint.Assign(willSubmit ? control->GetType() == NS_FORM_INPUT_SEARCH
+                                                ? NS_LITERAL_STRING("search")
+                                                : NS_LITERAL_STRING("go")
+                                            : formElement
+                                                ? NS_LITERAL_STRING("next")
+                                                : EmptyString());
     }
+  }
 
-    // XXX I think that we should use nsContentUtils::IsCallerChrome() instead
-    //     of the process type.
-    if (aAction.mCause == InputContextAction::CAUSE_UNKNOWN &&
-        XRE_GetProcessType() != GeckoProcessType_Content) {
-      aAction.mCause = InputContextAction::CAUSE_UNKNOWN_CHROME;
-    }
+  // XXX I think that we should use nsContentUtils::IsCallerChrome() instead
+  //     of the process type.
+  if (aAction.mCause == InputContextAction::CAUSE_UNKNOWN &&
+      XRE_GetProcessType() != GeckoProcessType_Content) {
+    aAction.mCause = InputContextAction::CAUSE_UNKNOWN_CHROME;
+  }
 
-    aWidget->SetInputContext(context, aAction);
-
-    nsContentUtils::AddScriptRunner(new IMEEnabledStateChangedEvent(state));
-  }
   if (aState & nsIContent::IME_STATUS_MASK_OPENED) {
     bool open = !!(aState & nsIContent::IME_STATUS_OPEN);
-    aWidget->SetIMEOpenState(open);
+    context.mIMEState.mOpen = open ? IMEState::OPEN : IMEState::CLOSED;
+  }
+
+  aWidget->SetInputContext(context, aAction);
+  if (aState & nsIContent::IME_STATUS_MASK_ENABLED) {
+    nsContentUtils::AddScriptRunner(
+      new IMEEnabledStateChangedEvent(context.mIMEState.mEnabled));
   }
 }
 
 nsIWidget*
 nsIMEStateManager::GetWidget(nsPresContext* aPresContext)
 {
   nsIPresShell* shell = aPresContext->GetPresShell();
   NS_ENSURE_TRUE(shell, nsnull);
--- a/content/events/src/nsIMEStateManager.h
+++ b/content/events/src/nsIMEStateManager.h
@@ -50,16 +50,17 @@ class nsISelection;
 
 /*
  * IME state manager
  */
 
 class nsIMEStateManager
 {
 protected:
+  typedef mozilla::widget::IMEState IMEState;
   typedef mozilla::widget::InputContext InputContext;
   typedef mozilla::widget::InputContextAction InputContextAction;
 
 public:
   static nsresult OnDestroyPresContext(nsPresContext* aPresContext);
   static nsresult OnRemoveContent(nsPresContext* aPresContext,
                                   nsIContent* aContent);
   /**
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -1036,34 +1036,38 @@ nsDOMWindowUtils::GetIMEIsOpen(bool *aSt
   NS_ENSURE_ARG_POINTER(aState);
 
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (!widget)
     return NS_ERROR_FAILURE;
 
   // Open state should not be available when IME is not enabled.
   InputContext context = widget->GetInputContext();
-  if (context.mIMEEnabled != InputContext::IME_ENABLED) {
+  if (context.mIMEState.mEnabled != IMEState::ENABLED) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
-  return widget->GetIMEOpenState(aState);
+  if (context.mIMEState.mOpen == IMEState::OPEN_STATE_NOT_SUPPORTED) {
+    return NS_ERROR_NOT_IMPLEMENTED;
+  }
+  *aState = (context.mIMEState.mOpen == IMEState::OPEN);
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::GetIMEStatus(PRUint32 *aState)
 {
   NS_ENSURE_ARG_POINTER(aState);
 
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (!widget)
     return NS_ERROR_FAILURE;
 
   InputContext context = widget->GetInputContext();
-  *aState = context.mIMEEnabled;
+  *aState = static_cast<PRUint32>(context.mIMEState.mEnabled);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::GetFocusedInputType(char** aType)
 {
   NS_ENSURE_ARG_POINTER(aType);
 
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -167,28 +167,25 @@ parent:
      *
      *  if cancel is PR_TRUE,
      *    widget should return empty string for composition
      *  if cancel is PR_FALSE,
      *    widget should return the current composition text
      */
     sync EndIMEComposition(bool cancel) returns (nsString composition);
 
-    sync GetInputContext() returns (PRUint32 value);
+    sync GetInputContext() returns (PRInt32 IMEEnabled, PRInt32 IMEOpen);
 
-    SetInputContext(PRUint32 value,
+    SetInputContext(PRInt32 IMEEnabled,
+                    PRInt32 IMEOpen,
                     nsString type,
                     nsString actionHint,
                     PRInt32 cause,
                     PRInt32 focusChange);
 
-    sync GetIMEOpenState() returns (bool value);
-
-    SetIMEOpenState(bool value);
-
     /**
      * Gets the DPI of the screen corresponding to this browser.
      */
     sync GetDPI() returns (float value);
 
     /**
      * Return native data of root widget
      */
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -559,82 +559,71 @@ TabParent::RecvEndIMEComposition(const b
 
   mIMECompositionEnding = false;
   *aComposition = mIMECompositionText;
   mIMECompositionText.Truncate(0);  
   return true;
 }
 
 bool
-TabParent::RecvGetInputContext(PRUint32* aValue)
+TabParent::RecvGetInputContext(PRInt32* aIMEEnabled,
+                               PRInt32* aIMEOpen)
 {
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (!widget) {
-    *aValue = InputContext::IME_DISABLED;
+    *aIMEEnabled = IMEState::DISABLED;
+    *aIMEOpen = IMEState::OPEN_STATE_NOT_SUPPORTED;
     return true;
   }
 
   InputContext context = widget->GetInputContext();
-  *aValue = context.mIMEEnabled;
+  *aIMEEnabled = static_cast<PRInt32>(context.mIMEState.mEnabled);
+  *aIMEOpen = static_cast<PRInt32>(context.mIMEState.mOpen);
   return true;
 }
 
 bool
-TabParent::RecvSetInputContext(const PRUint32& aValue,
+TabParent::RecvSetInputContext(const PRInt32& aIMEEnabled,
+                               const PRInt32& aIMEOpen,
                                const nsString& aType,
                                const nsString& aActionHint,
                                const PRInt32& aCause,
                                const PRInt32& aFocusChange)
 {
   // mIMETabParent (which is actually static) tracks which if any TabParent has IMEFocus
-  // When the input mode is set to anything but IME_STATUS_NONE, mIMETabParent should be set to this
-  mIMETabParent = aValue & nsIContent::IME_STATUS_MASK_ENABLED ? this : nsnull;
+  // When the input mode is set to anything but IMEState::DISABLED,
+  // mIMETabParent should be set to this
+  mIMETabParent =
+    aIMEEnabled != static_cast<PRInt32>(IMEState::DISABLED) ? this : nsnull;
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (!widget || !AllowContentIME())
     return true;
 
   InputContext context;
-  context.mIMEEnabled = aValue;
+  context.mIMEState.mEnabled = static_cast<IMEState::Enabled>(aIMEEnabled);
+  context.mIMEState.mOpen = static_cast<IMEState::Open>(aIMEOpen);
   context.mHTMLInputType.Assign(aType);
   context.mActionHint.Assign(aActionHint);
   InputContextAction action(
     static_cast<InputContextAction::Cause>(aCause),
     static_cast<InputContextAction::FocusChange>(aFocusChange));
   widget->SetInputContext(context, action);
 
   nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService();
   if (!observerService)
     return true;
 
   nsAutoString state;
-  state.AppendInt(aValue);
+  state.AppendInt(aIMEEnabled);
   observerService->NotifyObservers(nsnull, "ime-enabled-state-changed", state.get());
 
   return true;
 }
 
 bool
-TabParent::RecvGetIMEOpenState(bool* aValue)
-{
-  nsCOMPtr<nsIWidget> widget = GetWidget();
-  if (widget)
-    widget->GetIMEOpenState(aValue);
-  return true;
-}
-
-bool
-TabParent::RecvSetIMEOpenState(const bool& aValue)
-{
-  nsCOMPtr<nsIWidget> widget = GetWidget();
-  if (widget && AllowContentIME())
-    widget->SetIMEOpenState(aValue);
-  return true;
-}
-
-bool
 TabParent::RecvGetDPI(float* aValue)
 {
   NS_ABORT_IF_FALSE(mDPI > 0, 
                     "Must not ask for DPI before OwnerElement is received!");
   *aValue = mDPI;
   return true;
 }
 
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -98,24 +98,24 @@ public:
                                          const PRUint32& aEnd,
                                          const PRUint32& aNewEnd);
     virtual bool RecvNotifyIMESelection(const PRUint32& aSeqno,
                                         const PRUint32& aAnchor,
                                         const PRUint32& aFocus);
     virtual bool RecvNotifyIMETextHint(const nsString& aText);
     virtual bool RecvEndIMEComposition(const bool& aCancel,
                                        nsString* aComposition);
-    virtual bool RecvGetInputContext(PRUint32* aValue);
-    virtual bool RecvSetInputContext(const PRUint32& aValue,
+    virtual bool RecvGetInputContext(PRInt32* aIMEEnabled,
+                                     PRInt32* aIMEOpen);
+    virtual bool RecvSetInputContext(const PRInt32& aIMEEnabled,
+                                     const PRInt32& aIMEOpen,
                                      const nsString& aType,
                                      const nsString& aActionHint,
                                      const PRInt32& aCause,
                                      const PRInt32& aFocusChange);
-    virtual bool RecvGetIMEOpenState(bool* aValue);
-    virtual bool RecvSetIMEOpenState(const bool& aValue);
     virtual bool RecvSetCursor(const PRUint32& aValue);
     virtual bool RecvSetBackgroundColor(const nscolor& aValue);
     virtual bool RecvGetDPI(float* aValue);
     virtual bool RecvGetWidgetNativeData(WindowsHandle* aValue);
     virtual PContentDialogParent* AllocPContentDialog(const PRUint32& aType,
                                                       const nsCString& aName,
                                                       const nsCString& aFeatures,
                                                       const InfallibleTArray<int>& aIntParams,
--- a/widget/public/nsIWidget.h
+++ b/widget/public/nsIWidget.h
@@ -113,19 +113,18 @@ typedef nsEventStatus (* EVENT_CALLBACK)
 #endif
 #ifdef XP_WIN
 #define NS_NATIVE_TSF_THREAD_MGR       100
 #define NS_NATIVE_TSF_CATEGORY_MGR     101
 #define NS_NATIVE_TSF_DISPLAY_ATTR_MGR 102
 #endif
 
 #define NS_IWIDGET_IID \
-  { 0xb4fa00ae, 0x913c, 0x42b1, \
-    { 0x93, 0xc8, 0x41, 0x57, 0x1e, 0x3d, 0x94, 0x99 } }
-
+  { 0x34460b01, 0x3dc2, 0x4b58, \
+    { 0x8e, 0xd3, 0x7e, 0x7c, 0x33, 0xb5, 0x78, 0x8b } }
 /*
  * Window shadow styles
  * Also used for the -moz-window-shadow CSS property
  */
 
 #define NS_STYLE_WINDOW_SHADOW_NONE             0
 #define NS_STYLE_WINDOW_SHADOW_DEFAULT          1
 #define NS_STYLE_WINDOW_SHADOW_MENU             2
@@ -230,65 +229,97 @@ struct nsIMEUpdatePreference {
 /* 
  * Contains IMEStatus plus information about the current 
  * input context that the IME can use as hints if desired.
  */
 
 namespace mozilla {
 namespace widget {
 
-struct InputContext {
+struct IMEState {
   /**
-   * IME enabled states, the mIMEEnabled value of
+   * IME enabled states, the mEnabled value of
    * SetInputContext()/GetInputContext() should be one value of following
    * values.
    *
    * WARNING: If you change these values, you also need to edit:
    *   nsIDOMWindowUtils.idl
    *   nsContentUtils::GetWidgetStatusFromIMEStatus
    */
-  enum {
+  enum Enabled {
     /**
      * 'Disabled' means the user cannot use IME. So, the IME open state should
      * be 'closed' during 'disabled'.
      */
-    IME_DISABLED = 0,
+    DISABLED,
     /**
      * 'Enabled' means the user can use IME.
      */
-    IME_ENABLED = 1,
+    ENABLED,
     /**
      * 'Password' state is a special case for the password editors.
      * E.g., on mac, the password editors should disable the non-Roman
      * keyboard layouts at getting focus. Thus, the password editor may have
      * special rules on some platforms.
      */
-    IME_PASSWORD = 2,
+    PASSWORD,
     /**
      * This state is used when a plugin is focused.
      * When a plug-in is focused content, we should send native events
      * directly. Because we don't process some native events, but they may
      * be needed by the plug-in.
      */
-    IME_PLUGIN = 3,
+    PLUGIN
+  };
+  Enabled mEnabled;
+
+  /**
+   * IME open states the mOpen value of SetInputContext() should be one value of
+   * OPEN, CLOSE or DONT_CHANGE_OPEN_STATE.  GetInputContext() should return
+   * OPEN, CLOSE or OPEN_STATE_NOT_SUPPORTED.
+   */
+  enum Open {
     /**
-     * IME enabled state mask.
+     * 'Unsupported' means the platform cannot return actual IME open state.
+     * This value is used only by GetInputContext().
+     */
+    OPEN_STATE_NOT_SUPPORTED,
+    /**
+     * 'Don't change' means the widget shouldn't change IME open state when
+     * SetInputContext() is called.
      */
-    IME_ENABLED_STATE_MASK = 0xF
+    DONT_CHANGE_OPEN_STATE = OPEN_STATE_NOT_SUPPORTED,
+    /**
+     * 'Open' means that IME should compose in its primary language (or latest
+     * input mode except direct ASCII character input mode).  Even if IME is
+     * opened by this value, users should be able to close IME by theirselves.
+     * Web contents can specify this value by |ime-mode: active;|.
+     */
+    OPEN,
+    /**
+     * 'Closed' means that IME shouldn't handle key events (or should handle
+     * as ASCII character inputs on mobile device).  Even if IME is closed by
+     * this value, users should be able to open IME by theirselves.
+     * Web contents can specify this value by |ime-mode: inactive;|.
+     */
+    CLOSED
   };
+  Open mOpen;
 
-  PRUint32 mIMEEnabled;
+  IMEState() : mEnabled(ENABLED), mOpen(DONT_CHANGE_OPEN_STATE) { }
+};
+
+struct InputContext {
+  IMEState mIMEState;
 
   /* The type of the input if the input is a html input field */
   nsString mHTMLInputType;
 
   /* A hint for the action that is performed when the input is submitted */
   nsString mActionHint;
-
-  InputContext() : mIMEEnabled(IME_ENABLED) {}
 };
 
 struct InputContextAction {
   /**
    * mCause indicates what action causes calling nsIWidget::SetInputContext().
    * It must be one of following values.
    */
   enum Cause {
@@ -350,16 +381,17 @@ struct InputContextAction {
 class nsIWidget : public nsISupports {
   protected:
     typedef mozilla::dom::PBrowserChild PBrowserChild;
 
   public:
     typedef mozilla::layers::LayerManager LayerManager;
     typedef LayerManager::LayersBackend LayersBackend;
     typedef mozilla::layers::PLayersChild PLayersChild;
+    typedef mozilla::widget::IMEState IMEState;
     typedef mozilla::widget::InputContext InputContext;
     typedef mozilla::widget::InputContextAction InputContextAction;
 
     // Used in UpdateThemeGeometries.
     struct ThemeGeometry {
       // The -moz-appearance value for the themed widget
       PRUint8 mWidgetType;
       // The device-pixel rect within the window for the themed widget
@@ -1322,30 +1354,16 @@ class nsIWidget : public nsISupports {
      * and other characters. The user can change the state to 'Closed'.
      * 'Closed' means the user can input ASCII characters only. This is the same as a
      * non-IME environment. The user can change the state to 'Opened'.
      * For more information is here.
      * http://bugzilla.mozilla.org/show_bug.cgi?id=16940#c48
      */
 
     /*
-     * Set the state to 'Opened' or 'Closed'.
-     * If aState is TRUE, IME open state is set to 'Opened'.
-     * If aState is FALSE, set to 'Closed'.
-     */
-    NS_IMETHOD SetIMEOpenState(bool aState) = 0;
-
-    /*
-     * Get IME is 'Opened' or 'Closed'.
-     * If IME is 'Opened', aState is set true.
-     * If IME is 'Closed', aState is set false.
-     */
-    NS_IMETHOD GetIMEOpenState(bool* aState) = 0;
-
-    /*
      * Destruct and don't commit the IME composition string.
      */
     NS_IMETHOD CancelIMEComposition() = 0;
 
     /*
      * Notifies the input context changes.
      */
     NS_IMETHOD_(void) SetInputContext(const InputContext& aContext,
--- a/widget/src/android/nsWindow.cpp
+++ b/widget/src/android/nsWindow.cpp
@@ -2045,38 +2045,40 @@ nsWindow::ResetInputState()
     AndroidBridge::NotifyIME(AndroidBridge::NOTIFY_IME_RESETINPUTSTATE, 0);
     return NS_OK;
 }
 
 NS_IMETHODIMP_(void)
 nsWindow::SetInputContext(const InputContext& aContext,
                           const InputContextAction& aAction)
 {
-    ALOGIME("IME: SetInputContext: s=%d action=0x%X, 0x%X",
-            aContext.mIMEEnabled, aAction.mCause, aAction.mFocusChange);
+    ALOGIME("IME: SetInputContext: s=0x%X, 0x%X, action=0x%X, 0x%X",
+            aContext.mIMEState.mEnabled, aContext.mIMEState.mOpen,
+            aAction.mCause, aAction.mFocusChange);
 
     mInputContext = aContext;
 
     // Ensure that opening the virtual keyboard is allowed for this specific
     // InputContext depending on the content.ime.strict.policy pref
-    if (aContext.mIMEEnabled != InputContext::IME_DISABLED && 
-        aContext.mIMEEnabled != InputContext::IME_PLUGIN &&
+    if (aContext.mIMEState.mEnabled != IMEState::DISABLED && 
+        aContext.mIMEState.mEnabled != IMEState::PLUGIN &&
         Preferences::GetBool("content.ime.strict_policy", false) &&
         !aAction.ContentGotFocusByTrustedCause()) {
         return;
     }
 
-    AndroidBridge::NotifyIMEEnabled(int(aContext.mIMEEnabled),
+    AndroidBridge::NotifyIMEEnabled(int(aContext.mIMEState.mEnabled),
                                     aContext.mHTMLInputType,
                                     aContext.mActionHint);
 }
 
 NS_IMETHODIMP_(InputContext)
 nsWindow::GetInputContext()
 {
+    mInputContext.mIMEState.mOpen = IMEState::OPEN_STATE_NOT_SUPPORTED;
     return mInputContext;
 }
 
 NS_IMETHODIMP
 nsWindow::CancelIMEComposition()
 {
     ALOGIME("IME: CancelIMEComposition");
 
--- a/widget/src/cocoa/nsChildView.h
+++ b/widget/src/cocoa/nsChildView.h
@@ -441,18 +441,16 @@ public:
   NS_IMETHOD        GetAttention(PRInt32 aCycleCount);
 
   virtual bool HasPendingInputEvent();
 
   NS_IMETHOD        ActivateNativeMenuItemAt(const nsAString& indexString);
   NS_IMETHOD        ForceUpdateNativeMenuAt(const nsAString& indexString);
 
   NS_IMETHOD        ResetInputState();
-  NS_IMETHOD        SetIMEOpenState(bool aState);
-  NS_IMETHOD        GetIMEOpenState(bool* aState);
   NS_IMETHOD_(void) SetInputContext(const InputContext& aContext,
                                     const InputContextAction& aAction);
   NS_IMETHOD_(InputContext) GetInputContext();
   NS_IMETHOD        CancelIMEComposition();
   NS_IMETHOD        GetToggledKeyState(PRUint32 aKeyCode,
                                        bool* aLEDState);
   NS_IMETHOD        OnIMEFocusChange(bool aFocus);
 
--- a/widget/src/cocoa/nsChildView.mm
+++ b/widget/src/cocoa/nsChildView.mm
@@ -1668,60 +1668,61 @@ bool nsChildView::HasPendingInputEvent()
 // get called on the same ChildView that input is going through.
 NS_IMETHODIMP nsChildView::ResetInputState()
 {
   NS_ENSURE_TRUE(mTextInputHandler, NS_ERROR_NOT_AVAILABLE);
   mTextInputHandler->CommitIMEComposition();
   return NS_OK;
 }
 
-// 'open' means that it can take non-ASCII chars
-NS_IMETHODIMP nsChildView::SetIMEOpenState(bool aState)
-{
-  NS_ENSURE_TRUE(mTextInputHandler, NS_ERROR_NOT_AVAILABLE);
-  mTextInputHandler->SetIMEOpenState(aState);
-  return NS_OK;
-}
-
-// 'open' means that it can take non-ASCII chars
-NS_IMETHODIMP nsChildView::GetIMEOpenState(bool* aState)
-{
-  NS_ENSURE_TRUE(mTextInputHandler, NS_ERROR_NOT_AVAILABLE);
-  *aState = mTextInputHandler->IsIMEOpened();
-  return NS_OK;
-}
-
 NS_IMETHODIMP_(void)
 nsChildView::SetInputContext(const InputContext& aContext,
                              const InputContextAction& aAction)
 {
   NS_ENSURE_TRUE(mTextInputHandler, );
   mInputContext = aContext;
-  switch (aContext.mIMEEnabled) {
-    case InputContext::IME_ENABLED:
-    case InputContext::IME_PLUGIN:
+  switch (aContext.mIMEState.mEnabled) {
+    case IMEState::ENABLED:
+    case IMEState::PLUGIN:
       mTextInputHandler->SetASCIICapableOnly(false);
       mTextInputHandler->EnableIME(true);
+      if (mInputContext.mIMEState.mOpen != IMEState::DONT_CHANGE_OPEN_STATE) {
+        mTextInputHandler->SetIMEOpenState(
+          mInputContext.mIMEState.mOpen == IMEState::OPEN);
+      }
       break;
-    case InputContext::IME_DISABLED:
+    case IMEState::DISABLED:
       mTextInputHandler->SetASCIICapableOnly(false);
       mTextInputHandler->EnableIME(false);
       break;
-    case InputContext::IME_PASSWORD:
+    case IMEState::PASSWORD:
       mTextInputHandler->SetASCIICapableOnly(true);
       mTextInputHandler->EnableIME(false);
       break;
     default:
       NS_ERROR("not implemented!");
   }
 }
 
 NS_IMETHODIMP_(InputContext)
 nsChildView::GetInputContext()
 {
+  switch (mInputContext.mIMEState.mEnabled) {
+    case IMEState::ENABLED:
+    case IMEState::PLUGIN:
+      if (mTextInputHandler) {
+        mInputContext.mIMEState.mOpen =
+          mTextInputHandler->IsIMEOpened() ? IMEState::OPEN : IMEState::CLOSED;
+        break;
+      }
+      // If mTextInputHandler is null, set CLOSED instead...
+    default:
+      mInputContext.mIMEState.mOpen = IMEState::CLOSED;
+      break;
+  }
   return mInputContext;
 }
 
 // Destruct and don't commit the IME composition string.
 NS_IMETHODIMP nsChildView::CancelIMEComposition()
 {
   NS_ENSURE_TRUE(mTextInputHandler, NS_ERROR_NOT_AVAILABLE);
   mTextInputHandler->CancelIMEComposition();
--- a/widget/src/gtk2/nsGtkIMModule.cpp
+++ b/widget/src/gtk2/nsGtkIMModule.cpp
@@ -81,23 +81,23 @@ GetRangeTypeName(PRUint32 aRangeType)
             return "UNKNOWN SELECTION TYPE!!";
     }
 }
 
 static const char*
 GetEnabledStateName(PRUint32 aState)
 {
     switch (aState) {
-        case InputContext::IME_DISABLED:
+        case IMEState::DISABLED:
             return "DISABLED";
-        case InputContext::IME_ENABLED:
+        case IMEState::ENABLED:
             return "ENABLED";
-        case InputContext::IME_PASSWORD:
+        case IMEState::PASSWORD:
             return "PASSWORD";
-        case InputContext::IME_PLUGIN:
+        case IMEState::PLUGIN:
             return "PLUG_IN";
         default:
             return "UNKNOWN ENABLED STATUS!!";
     }
 }
 #endif
 
 nsGtkIMModule* nsGtkIMModule::sLastFocusedModule = nsnull;
@@ -117,17 +117,16 @@ nsGtkIMModule::nsGtkIMModule(nsWindow* a
     mIsComposing(false), mIsIMFocused(false),
     mIgnoreNativeCompositionEvent(false)
 {
 #ifdef PR_LOGGING
     if (!gGtkIMLog) {
         gGtkIMLog = PR_NewLogModule("nsGtkIMModuleWidgets");
     }
 #endif
-    mInputContext.mIMEEnabled = InputContext::IME_ENABLED;
     Init();
 }
 
 void
 nsGtkIMModule::Init()
 {
     PR_LOG(gGtkIMLog, PR_LOG_ALWAYS,
         ("GtkIMModule(%p): Init, mOwnerWindow=%p",
@@ -253,17 +252,17 @@ nsGtkIMModule::OnDestroyWindow(nsWindow*
         // so no need for another workaround_gtk_im_display_closed.
         gtk_im_context_set_client_window(mDummyContext, nsnull);
         g_object_unref(mDummyContext);
         mDummyContext = nsnull;
     }
 
     mOwnerWindow = nsnull;
     mLastFocusedWindow = nsnull;
-    mInputContext.mIMEEnabled = InputContext::IME_DISABLED;
+    mInputContext.mIMEState.mEnabled = IMEState::DISABLED;
 
     PR_LOG(gGtkIMLog, PR_LOG_ALWAYS,
         ("    SUCCEEDED, Completely destroyed"));
 }
 
 // Work around gtk bug http://bugzilla.gnome.org/show_bug.cgi?id=483223:
 // (and the similar issue of GTK+ IIIM)
 // The GTK+ XIM and IIIM modules register handlers for the "closed" signal
@@ -542,24 +541,24 @@ nsGtkIMModule::CancelIMEComposition(nsWi
     return NS_OK;
 }
 
 void
 nsGtkIMModule::SetInputContext(nsWindow* aCaller,
                                const InputContext* aContext,
                                const InputContextAction* aAction)
 {
-    if (aContext->mIMEEnabled == mInputContext.mIMEEnabled ||
+    if (aContext->mIMEState.mEnabled == mInputContext.mIMEState.mEnabled ||
         NS_UNLIKELY(IsDestroyed())) {
         return;
     }
 
     PR_LOG(gGtkIMLog, PR_LOG_ALWAYS,
         ("GtkIMModule(%p): SetInputContext, aCaller=%p, aState=%s mHTMLInputType=%s",
-         this, aCaller, GetEnabledStateName(aContext->mIMEEnabled),
+         this, aCaller, GetEnabledStateName(aContext->mIMEState.mEnabled),
          NS_ConvertUTF16toUTF8(aContext->mHTMLInputType).get()));
 
     if (aCaller != mLastFocusedWindow) {
         PR_LOG(gGtkIMLog, PR_LOG_ALWAYS,
             ("    FAILED, the caller isn't focused window, mLastFocusedWindow=%p",
              mLastFocusedWindow));
         return;
     }
@@ -593,33 +592,33 @@ nsGtkIMModule::SetInputContext(nsWindow*
     Focus();
 
 #if (MOZ_PLATFORM_MAEMO == 5)
     GtkIMContext *im = GetContext();
     if (im) {
         if (IsEnabled()) {
             // Ensure that opening the virtual keyboard is allowed for this specific
             // InputContext depending on the content.ime.strict.policy pref
-            if (mInputContext.mIMEEnabled != InputContext::IME_DISABLED && 
-                mInputContext.mIMEEnabled != InputContext::IME_PLUGIN &&
+            if (mInputContext.mIMEState.mEnabled != IMEState::DISABLED && 
+                mInputContext.mIMEState.mEnabled != IMEState::PLUGIN &&
                 Preferences::GetBool("content.ime.strict_policy", false) &&
                 !aAction->ContentGotFocusByTrustedCause()) {
                 return;
             }
 
             // It is not desired that the hildon's autocomplete mechanism displays
             // user previous entered passwds, so lets make completions invisible
             // in these cases.
             int mode;
             g_object_get(im, "hildon-input-mode", &mode, NULL);
 
-            if (mInputContext.mIMEEnabled == InputContext::IME_ENABLED ||
-                mInputContext.mIMEEnabled == InputContext::IME_PLUGIN) {
+            if (mInputContext.mIMEState.mEnabled == IMEState::ENABLED ||
+                mInputContext.mIMEState.mEnabled == IMEState::PLUGIN) {
                 mode &= ~HILDON_GTK_INPUT_MODE_INVISIBLE;
-            } else if (mInputContext.mIMEEnabled == InputContext::IME_PASSWORD) {
+            } else if (mInputContext.mIMEState.mEnabled == IMEState::PASSWORD) {
                mode |= HILDON_GTK_INPUT_MODE_INVISIBLE;
             }
 
             // Turn off auto-capitalization for editboxes
             mode &= ~HILDON_GTK_INPUT_MODE_AUTOCAP;
 
             // Turn off predictive dictionaries for editboxes
             mode &= ~HILDON_GTK_INPUT_MODE_DICTIONARY;
@@ -654,16 +653,17 @@ nsGtkIMModule::SetInputContext(nsWindow*
                                          rectBuf.get());
     }
 #endif
 }
 
 InputContext
 nsGtkIMModule::GetInputContext()
 {
+    mInputContext.mIMEState.mOpen = IMEState::OPEN_STATE_NOT_SUPPORTED;
     return mInputContext;
 }
 
 /* static */
 bool
 nsGtkIMModule::IsVirtualKeyboardOpened()
 {
 #ifdef MOZ_PLATFORM_MAEMO
@@ -676,40 +676,40 @@ nsGtkIMModule::IsVirtualKeyboardOpened()
 GtkIMContext*
 nsGtkIMModule::GetContext()
 {
     if (IsEnabled()) {
         return mContext;
     }
 
 #ifndef NS_IME_ENABLED_ON_PASSWORD_FIELD
-    if (mInputContext.mIMEEnabled == InputContext::IME_PASSWORD) {
+    if (mInputContext.mIMEState.mEnabled == IMEState::PASSWORD) {
         return mSimpleContext;
     }
 #endif // NS_IME_ENABLED_ON_PASSWORD_FIELD
 
     return mDummyContext;
 }
 
 bool
 nsGtkIMModule::IsEnabled()
 {
-    return mInputContext.mIMEEnabled == InputContext::IME_ENABLED ||
+    return mInputContext.mIMEState.mEnabled == IMEState::ENABLED ||
 #ifdef NS_IME_ENABLED_ON_PASSWORD_FIELD
-           mInputContext.mIMEEnabled == InputContext::IME_PASSWORD ||
+           mInputContext.mIMEState.mEnabled == IMEState::PASSWORD ||
 #endif // NS_IME_ENABLED_ON_PASSWORD_FIELD
-           mInputContext.mIMEEnabled == InputContext::IME_PLUGIN;
+           mInputContext.mIMEState.mEnabled == IMEState::PLUGIN;
 }
 
 bool
 nsGtkIMModule::IsEditable()
 {
-    return mInputContext.mIMEEnabled == InputContext::IME_ENABLED ||
-           mInputContext.mIMEEnabled == InputContext::IME_PLUGIN ||
-           mInputContext.mIMEEnabled == InputContext::IME_PASSWORD;
+    return mInputContext.mIMEState.mEnabled == IMEState::ENABLED ||
+           mInputContext.mIMEState.mEnabled == IMEState::PLUGIN ||
+           mInputContext.mIMEState.mEnabled == IMEState::PASSWORD;
 }
 
 void
 nsGtkIMModule::Focus()
 {
     PR_LOG(gGtkIMLog, PR_LOG_ALWAYS,
         ("GtkIMModule(%p): Focus, sLastFocusedModule=%p",
          this, sLastFocusedModule));
--- a/widget/src/gtk2/nsWindow.cpp
+++ b/widget/src/gtk2/nsWindow.cpp
@@ -6586,17 +6586,18 @@ nsWindow::SetInputContext(const InputCon
     mIMModule->SetInputContext(this, &aContext, &aAction);
 }
 
 NS_IMETHODIMP_(InputContext)
 nsWindow::GetInputContext()
 {
   InputContext context;
   if (!mIMModule) {
-      context.mIMEEnabled = InputContext::IME_DISABLED;
+      context.mIMEState.mEnabled = IMEState::DISABLED;
+      context.mIMEState.mOpen = IMEState::OPEN_STATE_NOT_SUPPORTED;
   } else {
       context = mIMModule->GetInputContext();
   }
   return context;
 }
 
 NS_IMETHODIMP
 nsWindow::CancelIMEComposition()
--- a/widget/src/qt/nsWindow.cpp
+++ b/widget/src/qt/nsWindow.cpp
@@ -3223,64 +3223,64 @@ nsWindow::SetInputContext(const InputCon
 
     // SetSoftwareKeyboardState uses mInputContext,
     // so, before calling that, record aContext in mInputContext.
     mInputContext = aContext;
 
 #if defined(MOZ_X11) && (MOZ_PLATFORM_MAEMO == 6)
     if (sPluginIMEAtom) {
         static QCoreApplication::EventFilter currentEventFilter = NULL;
-        if (mInputContext.mIMEEnabled == InputContext::IME_PLUGIN &&
+        if (mInputContext.mIMEState.mEnabled == IMEState::PLUGIN &&
             currentEventFilter != x11EventFilter) {
             // Install event filter for listening Plugin IME state changes
             previousEventFilter = QCoreApplication::instance()->setEventFilter(x11EventFilter);
             currentEventFilter = x11EventFilter;
-        } else if (mInputContext.mIMEEnabled != InputContext::IME_PLUGIN &&
+        } else if (mInputContext.mIMEState.mEnabled != IMEState::PLUGIN &&
                    currentEventFilter == x11EventFilter) {
             // Remove event filter
             QCoreApplication::instance()->setEventFilter(previousEventFilter);
             currentEventFilter = previousEventFilter;
             previousEventFilter = NULL;
             QWidget* view = GetViewWidget();
             if (view) {
                 SetVKBState(view->winId(), VKBUndefined);
             }
         }
     }
 #endif
 
-    switch (mInputContext.mIMEEnabled) {
-        case InputContext::IME_ENABLED:
-        case InputContext::IME_PASSWORD:
-        case InputContext::IME_PLUGIN:
+    switch (mInputContext.mIMEState.mEnabled) {
+        case IMEState::ENABLED:
+        case IMEState::PASSWORD:
+        case IMEState::PLUGIN:
             SetSoftwareKeyboardState(true, aAction);
             break;
         default:
             SetSoftwareKeyboardState(false, aAction);
             break;
     }
 }
 
 NS_IMETHODIMP_(InputContext)
 nsWindow::GetInputContext()
 {
+    mInputContext.mIMEState.mOpen = IMEState::OPEN_STATE_NOT_SUPPORTED;
     return mInputContext;
 }
 
 void
 nsWindow::SetSoftwareKeyboardState(bool aOpen,
                                    const InputContextAction& aAction)
 {
     if (aOpen) {
-        NS_ENSURE_TRUE(mInputContext.mIMEEnabled !=
-                           InputContext::IME_DISABLED, );
+        NS_ENSURE_TRUE(mInputContext.mIMEState.mEnabled != IMEState::DISABLED,);
 
         // Ensure that opening the virtual keyboard is allowed for this specific
         // InputContext depending on the content.ime.strict.policy pref
-        if (mInputContext.mIMEEnabled != InputContext::IME_PLUGIN &&
+        if (mInputContext.mIMEState.mEnabled != IMEState::PLUGIN &&
             Preferences::GetBool("content.ime.strict_policy", false) &&
             !aAction.ContentGotFocusByTrustedCause()) {
             return;
         }
 #if defined(MOZ_X11) && (MOZ_PLATFORM_MAEMO == 6)
         // doen't open VKB if plugin did set closed state
         else if (sPluginIMEAtom) {
             QWidget* view = GetViewWidget();
--- a/widget/src/windows/nsTextStore.cpp
+++ b/widget/src/windows/nsTextStore.cpp
@@ -83,30 +83,30 @@ nsTextStore::~nsTextStore()
     mCompositionTimer->Cancel();
     mCompositionTimer = nsnull;
   }
   SaveTextEvent(nsnull);
 }
 
 bool
 nsTextStore::Create(nsWindow* aWindow,
-                    PRUint32 aIMEState)
+                    IMEState::Enabled aIMEEnabled)
 {
   if (!mDocumentMgr) {
     // Create document manager
     HRESULT hr = sTsfThreadMgr->CreateDocumentMgr(
                                     getter_AddRefs(mDocumentMgr));
     NS_ENSURE_TRUE(SUCCEEDED(hr), false);
     mWindow = aWindow;
     // Create context and add it to document manager
     hr = mDocumentMgr->CreateContext(sTsfClientId, 0,
                                      static_cast<ITextStoreACP*>(this),
                                      getter_AddRefs(mContext), &mEditCookie);
     if (SUCCEEDED(hr)) {
-      SetInputContextInternal(aIMEState);
+      SetInputContextInternal(aIMEEnabled);
       hr = mDocumentMgr->Push(mContext);
     }
     if (SUCCEEDED(hr)) {
       PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
              ("TSF: Created, window=%08x\n", aWindow));
       return true;
     }
     mContext = NULL;
@@ -1473,17 +1473,17 @@ nsTextStore::OnEndComposition(ITfComposi
   // Maintain selection
   SetSelectionInternal(&mCompositionSelection);
   return S_OK;
 }
 
 nsresult
 nsTextStore::OnFocusChange(bool aFocus,
                            nsWindow* aWindow,
-                           PRUint32 aIMEEnabled)
+                           IMEState::Enabled aIMEEnabled)
 {
   // no change notifications if TSF is disabled
   if (!sTsfThreadMgr || !sTsfTextStore)
     return NS_ERROR_NOT_AVAILABLE;
 
   if (aFocus) {
     bool bRet = sTsfTextStore->Create(aWindow, aIMEEnabled);
     NS_ENSURE_TRUE(bRet, NS_ERROR_FAILURE);
@@ -1626,24 +1626,24 @@ nsTextStore::GetIMEOpenState(void)
   if (SUCCEEDED(comp->GetValue(&variant)) && variant.vt == VT_I4)
     return variant.lVal != 0;
 
   ::VariantClear(&variant); // clear up in case variant.vt != VT_I4
   return false;
 }
 
 void
-nsTextStore::SetInputContextInternal(PRUint32 aState)
+nsTextStore::SetInputContextInternal(IMEState::Enabled aState)
 {
   PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
-         ("TSF: SetInputContext, state=%lu\n", aState));
+         ("TSF: SetInputContext, state=%ld\n", static_cast<PRInt32>(aState)));
 
   VARIANT variant;
   variant.vt = VT_I4;
-  variant.lVal = aState != InputContext::IME_ENABLED;
+  variant.lVal = (aState != IMEState::ENABLED);
 
   // Set two contexts, the base context (mContext) and the top
   // if the top context is not the same as the base context
   nsRefPtr<ITfContext> context = mContext;
   nsRefPtr<ITfCompartment> comp;
   do {
     if (GetCompartment(context, GUID_COMPARTMENT_KEYBOARD_DISABLED,
                        getter_AddRefs(comp)))
--- a/widget/src/windows/nsTextStore.h
+++ b/widget/src/windows/nsTextStore.h
@@ -106,16 +106,17 @@ public: /*ITextStoreACP*/
                                          TS_TEXTCHANGE*);
 
 public: /*ITfContextOwnerCompositionSink*/
   STDMETHODIMP OnStartComposition(ITfCompositionView*, BOOL*);
   STDMETHODIMP OnUpdateComposition(ITfCompositionView*, ITfRange*);
   STDMETHODIMP OnEndComposition(ITfCompositionView*);
 
 protected:
+  typedef mozilla::widget::IMEState IMEState;
   typedef mozilla::widget::InputContext InputContext;
 
 public:
   static void     Initialize(void);
   static void     Terminate(void);
   static void     SetIMEOpenState(bool);
   static bool     GetIMEOpenState(void);
 
@@ -123,20 +124,20 @@ public:
   {
     if (!sTsfTextStore) return;
     sTsfTextStore->CommitCompositionInternal(aDiscard);
   }
 
   static void     SetInputContext(const InputContext& aContext)
   {
     if (!sTsfTextStore) return;
-    sTsfTextStore->SetInputContextInternal(aContext.mIMEEnabled);
+    sTsfTextStore->SetInputContextInternal(aContext.mIMEState.mEnabled);
   }
 
-  static nsresult OnFocusChange(bool, nsWindow*, PRUint32);
+  static nsresult OnFocusChange(bool, nsWindow*, IMEState::Enabled);
 
   static nsresult OnTextChange(PRUint32 aStart,
                                PRUint32 aOldEnd,
                                PRUint32 aNewEnd)
   {
     if (!sTsfTextStore) return NS_OK;
     return sTsfTextStore->OnTextChangeInternal(aStart, aOldEnd, aNewEnd);
   }
@@ -178,28 +179,28 @@ public:
   {
     return (void*) & sDisplayAttrMgr;
   }
 
 protected:
   nsTextStore();
   ~nsTextStore();
 
-  bool     Create(nsWindow*, PRUint32);
+  bool     Create(nsWindow*, IMEState::Enabled);
   bool     Destroy(void);
 
   // If aDispatchTextEvent is true, this method will dispatch text event if
   // this is called during IME composing.  aDispatchTextEvent should be true
   // only when this is called from SetSelection.  Because otherwise, the text
   // event should not be sent from here.
   HRESULT  SetSelectionInternal(const TS_SELECTION_ACP*,
                                 bool aDispatchTextEvent = false);
   HRESULT  OnStartCompositionInternal(ITfCompositionView*, ITfRange*, bool);
   void     CommitCompositionInternal(bool);
-  void     SetInputContextInternal(PRUint32 aState);
+  void     SetInputContextInternal(IMEState::Enabled aState);
   nsresult OnTextChangeInternal(PRUint32, PRUint32, PRUint32);
   void     OnTextChangeMsgInternal(void);
   nsresult OnSelectionChangeInternal(void);
   HRESULT  GetDisplayAttribute(ITfProperty* aProperty,
                                ITfRange* aRange,
                                TF_DISPLAYATTRIBUTE* aResult);
   HRESULT  UpdateCompositionExtent(ITfRange* pRangeNew);
   HRESULT  SendTextEventForCompositionString();
--- a/widget/src/windows/nsWindow.cpp
+++ b/widget/src/windows/nsWindow.cpp
@@ -401,17 +401,16 @@ nsWindow::nsWindow() : nsBaseWidget()
   mLastSize.width       = 0;
   mLastSize.height      = 0;
   mOldStyle             = 0;
   mOldExStyle           = 0;
   mPainting             = 0;
   mLastKeyboardLayout   = 0;
   mAssumeWheelIsZoomUntil = 0;
   mBlurSuppressLevel    = 0;
-  mInputContext.mIMEEnabled = InputContext::IME_ENABLED;
 #ifdef MOZ_XUL
   mTransparentSurface   = nsnull;
   mMemoryDC             = nsnull;
   mTransparencyMode     = eTransparencyOpaque;
 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
   memset(&mGlassMargins, 0, sizeof mGlassMargins);
 #endif // #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
 #endif
@@ -8026,82 +8025,66 @@ NS_IMETHODIMP nsWindow::ResetInputState(
 #ifdef NS_ENABLE_TSF
   nsTextStore::CommitComposition(false);
 #endif //NS_ENABLE_TSF
 
   nsIMM32Handler::CommitComposition(this);
   return NS_OK;
 }
 
-NS_IMETHODIMP nsWindow::SetIMEOpenState(bool aState)
-{
-#ifdef DEBUG_KBSTATE
-  PR_LOG(gWindowsLog, PR_LOG_ALWAYS, 
-         ("SetIMEOpenState %s\n", (aState ? "Open" : "Close")));
-#endif 
-
-#ifdef NS_ENABLE_TSF
-  nsTextStore::SetIMEOpenState(aState);
-#endif //NS_ENABLE_TSF
-
-  nsIMEContext IMEContext(mWnd);
-  if (IMEContext.IsValid()) {
-    ::ImmSetOpenStatus(IMEContext.get(), aState ? TRUE : FALSE);
-  }
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsWindow::GetIMEOpenState(bool* aState)
-{
-  nsIMEContext IMEContext(mWnd);
-  if (IMEContext.IsValid()) {
-    BOOL isOpen = ::ImmGetOpenStatus(IMEContext.get());
-    *aState = isOpen ? true : false;
-  } else 
-    *aState = false;
-
-#ifdef NS_ENABLE_TSF
-  *aState |= nsTextStore::GetIMEOpenState();
-#endif //NS_ENABLE_TSF
-
-  return NS_OK;
-}
-
 NS_IMETHODIMP_(void)
 nsWindow::SetInputContext(const InputContext& aContext,
                           const InputContextAction& aAction)
 {
-  PRUint32 status = aContext.mIMEEnabled;
 #ifdef NS_ENABLE_TSF
   nsTextStore::SetInputContext(aContext);
 #endif //NS_ENABLE_TSF
-#ifdef DEBUG_KBSTATE
-  PR_LOG(gWindowsLog, PR_LOG_ALWAYS, 
-         ("SetInputMode: %s\n", (status == InputContext::IME_ENABLED ||
-                                 status == InputContext::IME_PLUGIN) ? 
-                                 "Enabled" : "Disabled"));
-#endif 
   if (nsIMM32Handler::IsComposing()) {
     ResetInputState();
   }
   mInputContext = aContext;
-  bool enable = (status == InputContext::IME_ENABLED ||
-                 status == InputContext::IME_PLUGIN);
+  bool enable = (mInputContext.mIMEState.mEnabled == IMEState::ENABLED ||
+                 mInputContext.mIMEState.mEnabled == IMEState::PLUGIN);
 
   AssociateDefaultIMC(enable);
+
+  if (enable &&
+      mInputContext.mIMEState.mOpen != IMEState::DONT_CHANGE_OPEN_STATE) {
+    bool open = (mInputContext.mIMEState.mOpen == IMEState::OPEN);
+#ifdef NS_ENABLE_TSF
+    nsTextStore::SetIMEOpenState(open);
+#endif //NS_ENABLE_TSF
+    nsIMEContext IMEContext(mWnd);
+    if (IMEContext.IsValid()) {
+      ::ImmSetOpenStatus(IMEContext.get(), open);
+    }
+  }
 }
 
 NS_IMETHODIMP_(InputContext)
 nsWindow::GetInputContext()
 {
-#ifdef DEBUG_KBSTATE
-  PR_LOG(gWindowsLog, PR_LOG_ALWAYS, 
-         ("GetInputMode: %s\n", mInputContext.mIMEEnabled ?
-           "Enabled" : "Disabled");
-#endif 
+  mInputContext.mIMEState.mOpen = IMEState::CLOSED;
+  switch (mInputContext.mIMEState.mEnabled) {
+    case IMEState::ENABLED:
+    case IMEState::PLUGIN: {
+      nsIMEContext IMEContext(mWnd);
+      if (IMEContext.IsValid()) {
+        mInputContext.mIMEState.mOpen =
+          ::ImmGetOpenStatus(IMEContext.get()) ? IMEState::OPEN :
+                                                 IMEState::CLOSED;
+      }
+#ifdef NS_ENABLE_TSF
+      if (mInputContext.mIMEState.mOpen == IMEState::CLOSED &&
+          nsTextStore::GetIMEOpenState()) {
+        mInputContext.mIMEState.mOpen = IMEState::OPEN;
+      }
+#endif //NS_ENABLE_TSF
+    }
+  }
   return mInputContext;
 }
 
 NS_IMETHODIMP nsWindow::CancelIMEComposition()
 {
 #ifdef DEBUG_KBSTATE
   PR_LOG(gWindowsLog, PR_LOG_ALWAYS, ("CancelIMEComposition\n"));
 #endif 
@@ -8125,17 +8108,17 @@ nsWindow::GetToggledKeyState(PRUint32 aK
   return NS_OK;
 }
 
 #ifdef NS_ENABLE_TSF
 NS_IMETHODIMP
 nsWindow::OnIMEFocusChange(bool aFocus)
 {
   nsresult rv = nsTextStore::OnFocusChange(aFocus, this,
-                                           mInputContext.mIMEEnabled);
+                                           mInputContext.mIMEState.mEnabled);
   if (rv == NS_ERROR_NOT_AVAILABLE)
     rv = NS_ERROR_NOT_IMPLEMENTED; // TSF is not enabled, maybe.
   return rv;
 }
 
 NS_IMETHODIMP
 nsWindow::OnIMETextChange(PRUint32 aStart,
                           PRUint32 aOldEnd,
--- a/widget/src/windows/nsWindow.h
+++ b/widget/src/windows/nsWindow.h
@@ -174,18 +174,16 @@ public:
                                                    PRInt32 aNativeKeyCode,
                                                    PRUint32 aModifierFlags,
                                                    const nsAString& aCharacters,
                                                    const nsAString& aUnmodifiedCharacters);
   virtual nsresult        SynthesizeNativeMouseEvent(nsIntPoint aPoint,
                                                      PRUint32 aNativeMessage,
                                                      PRUint32 aModifierFlags);
   NS_IMETHOD              ResetInputState();
-  NS_IMETHOD              SetIMEOpenState(bool aState);
-  NS_IMETHOD              GetIMEOpenState(bool* aState);
   NS_IMETHOD_(void)       SetInputContext(const InputContext& aContext,
                                           const InputContextAction& aAction);
   NS_IMETHOD_(InputContext) GetInputContext();
   NS_IMETHOD              CancelIMEComposition();
   NS_IMETHOD              GetToggledKeyState(PRUint32 aKeyCode, bool* aLEDState);
   NS_IMETHOD              RegisterTouchWindow();
   NS_IMETHOD              UnregisterTouchWindow();
 #ifdef MOZ_XUL
@@ -260,17 +258,17 @@ public:
   /**
    * Misc.
    */
   virtual bool            AutoErase(HDC dc);
   nsIntPoint*             GetLastPoint() { return &mLastPoint; }
   // needed in nsIMM32Handler.cpp
   bool                    PluginHasFocus()
   {
-    return mInputContext.mIMEEnabled == InputContext::IME_PLUGIN;
+    return (mInputContext.mIMEState.mEnabled == IMEState::PLUGIN);
   }
   bool                    IsTopLevelWidget() { return mIsTopWidgetWindow; }
   /**
    * Start allowing Direct3D9 to be used by widgets when GetLayerManager is
    * called.
    *
    * @param aReinitialize Call GetLayerManager on widgets to ensure D3D9 is
    *                      initialized, this is usually called when this function
--- a/widget/src/xpwidgets/PuppetWidget.cpp
+++ b/widget/src/xpwidgets/PuppetWidget.cpp
@@ -394,54 +394,41 @@ PuppetWidget::ResetInputState()
 }
 
 NS_IMETHODIMP
 PuppetWidget::CancelComposition()
 {
   return IMEEndComposition(true);
 }
 
-NS_IMETHODIMP
-PuppetWidget::SetIMEOpenState(bool aState)
-{
-  if (mTabChild &&
-      mTabChild->SendSetIMEOpenState(aState))
-    return NS_OK;
-  return NS_ERROR_FAILURE;
-}
-
 NS_IMETHODIMP_(void)
 PuppetWidget::SetInputContext(const InputContext& aContext,
                               const InputContextAction& aAction)
 {
   if (!mTabChild) {
     return;
   }
-  mTabChild->SendSetInputContext(aContext.mIMEEnabled,
-                                 aContext.mHTMLInputType,
-                                 aContext.mActionHint,
-                                 static_cast<PRInt32>(aAction.mCause),
-                                 static_cast<PRInt32>(aAction.mFocusChange));
-}
-
-NS_IMETHODIMP
-PuppetWidget::GetIMEOpenState(bool *aState)
-{
-  if (mTabChild &&
-      mTabChild->SendGetIMEOpenState(aState))
-    return NS_OK;
-  return NS_ERROR_FAILURE;
+  mTabChild->SendSetInputContext(
+    static_cast<PRInt32>(aContext.mIMEState.mEnabled),
+    static_cast<PRInt32>(aContext.mIMEState.mOpen),
+    aContext.mHTMLInputType,
+    aContext.mActionHint,
+    static_cast<PRInt32>(aAction.mCause),
+    static_cast<PRInt32>(aAction.mFocusChange));
 }
 
 NS_IMETHODIMP_(InputContext)
 PuppetWidget::GetInputContext()
 {
   InputContext context;
   if (mTabChild) {
-    mTabChild->SendGetInputContext(&context.mIMEEnabled);
+    PRInt32 enabled, open;
+    mTabChild->SendGetInputContext(&enabled, &open);
+    context.mIMEState.mEnabled = static_cast<IMEState::Enabled>(enabled);
+    context.mIMEState.mOpen = static_cast<IMEState::Open>(open);
   }
   return context;
 }
 
 NS_IMETHODIMP
 PuppetWidget::OnIMEFocusChange(bool aFocus)
 {
   if (!mTabChild)
--- a/widget/src/xpwidgets/PuppetWidget.h
+++ b/widget/src/xpwidgets/PuppetWidget.h
@@ -163,18 +163,16 @@ public:
   GetLayerManager(PLayersChild* aShadowManager = nsnull,
                   LayersBackend aBackendHint = LayerManager::LAYERS_NONE,
                   LayerManagerPersistence aPersistence = LAYER_MANAGER_CURRENT,
                   bool* aAllowRetaining = nsnull);
 //  virtual nsDeviceContext* GetDeviceContext();
   virtual gfxASurface*      GetThebesSurface();
 
   NS_IMETHOD ResetInputState();
-  NS_IMETHOD SetIMEOpenState(bool aState);
-  NS_IMETHOD GetIMEOpenState(bool *aState);
   NS_IMETHOD_(void) SetInputContext(const InputContext& aContext,
                                     const InputContextAction& aAction);
   NS_IMETHOD_(InputContext) GetInputContext();
   NS_IMETHOD CancelComposition();
   NS_IMETHOD OnIMEFocusChange(bool aFocus);
   NS_IMETHOD OnIMETextChange(PRUint32 aOffset, PRUint32 aEnd,
                              PRUint32 aNewEnd);
   NS_IMETHOD OnIMESelectionChange(void);
--- a/widget/src/xpwidgets/nsBaseWidget.h
+++ b/widget/src/xpwidgets/nsBaseWidget.h
@@ -137,18 +137,16 @@ public:
   virtual void            SetDrawsInTitlebar(bool aState) {}
   virtual bool            ShowsResizeIndicator(nsIntRect* aResizerRect);
   virtual void            FreeNativeData(void * data, PRUint32 aDataType) {}
   NS_IMETHOD              BeginResizeDrag(nsGUIEvent* aEvent, PRInt32 aHorizontal, PRInt32 aVertical);
   NS_IMETHOD              BeginMoveDrag(nsMouseEvent* aEvent);
   virtual nsresult        ActivateNativeMenuItemAt(const nsAString& indexString) { return NS_ERROR_NOT_IMPLEMENTED; }
   virtual nsresult        ForceUpdateNativeMenuAt(const nsAString& indexString) { return NS_ERROR_NOT_IMPLEMENTED; }
   NS_IMETHOD              ResetInputState() { return NS_OK; }
-  NS_IMETHOD              SetIMEOpenState(bool aState) { return NS_ERROR_NOT_IMPLEMENTED; }
-  NS_IMETHOD              GetIMEOpenState(bool* aState) { return NS_ERROR_NOT_IMPLEMENTED; }
   NS_IMETHOD              CancelIMEComposition() { return NS_OK; }
   NS_IMETHOD              SetAcceleratedRendering(bool aEnabled);
   virtual bool            GetAcceleratedRendering();
   virtual bool            GetShouldAccelerate();
   NS_IMETHOD              GetToggledKeyState(PRUint32 aKeyCode, bool* aLEDState) { return NS_ERROR_NOT_IMPLEMENTED; }
   NS_IMETHOD              OnIMEFocusChange(bool aFocus) { return NS_ERROR_NOT_IMPLEMENTED; }
   NS_IMETHOD              OnIMETextChange(PRUint32 aStart, PRUint32 aOldEnd, PRUint32 aNewEnd) { return NS_ERROR_NOT_IMPLEMENTED; }
   NS_IMETHOD              OnIMESelectionChange(void) { return NS_ERROR_NOT_IMPLEMENTED; }