Bug 532738 - Do not open the virtual keyboard on untrusted focus (caused by content page scripts) [r=masayuki]

This commit is contained in:
Vivien Nicolas 2011-04-20 14:47:40 +02:00
parent 34bb38d9d1
commit 9d29efb784
13 changed files with 118 additions and 21 deletions

View File

@ -89,7 +89,7 @@ nsIMEStateManager::OnDestroyPresContext(nsPresContext* aPresContext)
nsCOMPtr<nsIWidget> widget = GetWidget(sPresContext);
if (widget) {
PRUint32 newState = GetNewIMEState(sPresContext, nsnull);
SetIMEState(newState, nsnull, widget);
SetIMEState(newState, nsnull, widget, IMEContext::FOCUS_REMOVED);
}
sContent = nsnull;
sPresContext = nsnull;
@ -114,7 +114,7 @@ nsIMEStateManager::OnRemoveContent(nsPresContext* aPresContext,
if (NS_FAILED(rv))
widget->ResetInputState();
PRUint32 newState = GetNewIMEState(sPresContext, nsnull);
SetIMEState(newState, nsnull, widget);
SetIMEState(newState, nsnull, widget, IMEContext::FOCUS_REMOVED);
}
sContent = nsnull;
@ -125,7 +125,8 @@ nsIMEStateManager::OnRemoveContent(nsPresContext* aPresContext,
nsresult
nsIMEStateManager::OnChangeFocus(nsPresContext* aPresContext,
nsIContent* aContent)
nsIContent* aContent,
PRUint32 aReason)
{
NS_ENSURE_ARG_POINTER(aPresContext);
@ -191,7 +192,7 @@ nsIMEStateManager::OnChangeFocus(nsPresContext* aPresContext,
if (newState != nsIContent::IME_STATUS_NONE) {
// Update IME state for new focus widget
SetIMEState(newState, aContent, widget);
SetIMEState(newState, aContent, widget, aReason);
}
sPresContext = aPresContext;
@ -204,7 +205,10 @@ void
nsIMEStateManager::OnInstalledMenuKeyboardListener(PRBool aInstalling)
{
sInstalledMenuKeyboardListener = aInstalling;
OnChangeFocus(sPresContext, sContent);
PRUint32 reason = aInstalling ? IMEContext::FOCUS_MOVED_TO_MENU
: IMEContext::FOCUS_MOVED_FROM_MENU;
OnChangeFocus(sPresContext, sContent, reason);
}
void
@ -236,7 +240,7 @@ nsIMEStateManager::UpdateIMEState(PRUint32 aNewIMEState, nsIContent* aContent)
// commit current composition
widget->ResetInputState();
SetIMEState(aNewIMEState, aContent, widget);
SetIMEState(aNewIMEState, aContent, widget, IMEContext::EDITOR_STATE_MODIFIED);
}
PRUint32
@ -289,7 +293,8 @@ private:
void
nsIMEStateManager::SetIMEState(PRUint32 aState,
nsIContent* aContent,
nsIWidget* aWidget)
nsIWidget* aWidget,
PRUint32 aReason)
{
if (aState & nsIContent::IME_STATUS_MASK_ENABLED) {
if (!aWidget)
@ -327,6 +332,12 @@ nsIMEStateManager::SetIMEState(PRUint32 aState,
}
}
if (XRE_GetProcessType() == GeckoProcessType_Content) {
context.mReason = aReason | IMEContext::FOCUS_FROM_CONTENT_PROCESS;
} else {
context.mReason = aReason;
}
aWidget->SetInputMode(context);
nsContentUtils::AddScriptRunner(new IMEEnabledStateChangedEvent(state));

View File

@ -59,7 +59,8 @@ public:
static nsresult OnRemoveContent(nsPresContext* aPresContext,
nsIContent* aContent);
static nsresult OnChangeFocus(nsPresContext* aPresContext,
nsIContent* aContent);
nsIContent* aContent,
PRUint32 aReason);
static void OnInstalledMenuKeyboardListener(PRBool aInstalling);
// These two methods manage focus and selection/text observers.
@ -90,7 +91,7 @@ public:
protected:
static void SetIMEState(PRUint32 aState, nsIContent* aContent,
nsIWidget* aWidget);
nsIWidget* aWidget, PRUint32 aReason);
static PRUint32 GetNewIMEState(nsPresContext* aPresContext,
nsIContent* aContent);

View File

@ -337,6 +337,22 @@ nsFocusManager::GetRedirectedFocus(nsIContent* aContent)
return nsnull;
}
// static
PRUint32
nsFocusManager::GetFocusMoveReason(PRUint32 aFlags)
{
PRUint32 reason = IMEContext::FOCUS_MOVED_UNKNOWN;
if (aFlags & nsIFocusManager::FLAG_BYMOUSE) {
reason = IMEContext::FOCUS_MOVED_BY_MOUSE;
} else if (aFlags & nsIFocusManager::FLAG_BYKEY) {
reason = IMEContext::FOCUS_MOVED_BY_KEY;
} else if (aFlags & nsIFocusManager::FLAG_BYMOVEFOCUS) {
reason = IMEContext::FOCUS_MOVED_BY_MOVEFOCUS;
}
return reason;
}
NS_IMETHODIMP
nsFocusManager::GetActiveWindow(nsIDOMWindow** aWindow)
{
@ -943,7 +959,7 @@ nsFocusManager::WindowHidden(nsIDOMWindow* aWindow)
nsIMEStateManager::OnTextStateBlur(nsnull, nsnull);
if (presShell) {
nsIMEStateManager::OnChangeFocus(presShell->GetPresContext(), nsnull);
nsIMEStateManager::OnChangeFocus(presShell->GetPresContext(), nsnull, IMEContext::FOCUS_REMOVED);
SetCaretVisible(presShell, PR_FALSE, nsnull);
}
@ -1484,7 +1500,7 @@ nsFocusManager::Blur(nsPIDOMWindow* aWindowToClear,
// compositionend event won't get fired at the element being blurred.
nsIMEStateManager::OnTextStateBlur(nsnull, nsnull);
if (mActiveWindow)
nsIMEStateManager::OnChangeFocus(presShell->GetPresContext(), nsnull);
nsIMEStateManager::OnChangeFocus(presShell->GetPresContext(), nsnull, IMEContext::FOCUS_REMOVED);
// now adjust the actual focus, by clearing the fields in the focus manager
// and in the window.
@ -1727,7 +1743,8 @@ nsFocusManager::Focus(nsPIDOMWindow* aWindow,
objectFrameWidget->SetFocus(PR_FALSE);
}
nsIMEStateManager::OnChangeFocus(presContext, aContent);
PRUint32 reason = GetFocusMoveReason(aFlags);
nsIMEStateManager::OnChangeFocus(presContext, aContent, reason);
// as long as this focus wasn't because a window was raised, update the
// commands
@ -1743,7 +1760,7 @@ nsFocusManager::Focus(nsPIDOMWindow* aWindow,
nsIMEStateManager::OnTextStateFocus(presContext, aContent);
} else {
nsIMEStateManager::OnTextStateBlur(presContext, nsnull);
nsIMEStateManager::OnChangeFocus(presContext, nsnull);
nsIMEStateManager::OnChangeFocus(presContext, nsnull, IMEContext::FOCUS_REMOVED);
if (!aWindowRaised) {
aWindow->UpdateCommands(NS_LITERAL_STRING("focus"));
}
@ -1766,7 +1783,7 @@ nsFocusManager::Focus(nsPIDOMWindow* aWindow,
nsPresContext* presContext = presShell->GetPresContext();
nsIMEStateManager::OnTextStateBlur(presContext, nsnull);
nsIMEStateManager::OnChangeFocus(presContext, nsnull);
nsIMEStateManager::OnChangeFocus(presContext, nsnull, IMEContext::FOCUS_REMOVED);
if (!aWindowRaised)
aWindow->UpdateCommands(NS_LITERAL_STRING("focus"));

View File

@ -123,6 +123,13 @@ public:
*/
static nsIContent* GetRedirectedFocus(nsIContent* aContent);
/**
* Returns a flag indicating the source and/or reason of the focus change.
* This is used to indicate to the IME code if the focus come from a user
* input or a script for example.
*/
static PRUint32 GetFocusMoveReason(PRUint32 aFlags);
static PRBool sMouseFocusesFormControl;
protected:

View File

@ -169,7 +169,7 @@ parent:
sync GetIMEEnabled() returns (PRUint32 value);
SetInputMode(PRUint32 value, nsString type, nsString actionHint);
SetInputMode(PRUint32 value, nsString type, nsString actionHint, PRUint32 reason);
sync GetIMEOpenState() returns (PRBool value);

View File

@ -525,7 +525,7 @@ TabParent::RecvGetIMEEnabled(PRUint32* aValue)
}
bool
TabParent::RecvSetInputMode(const PRUint32& aValue, const nsString& aType, const nsString& aAction)
TabParent::RecvSetInputMode(const PRUint32& aValue, const nsString& aType, const nsString& aAction, const PRUint32& aReason)
{
nsCOMPtr<nsIWidget> widget = GetWidget();
if (!widget || !AllowContentIME())
@ -535,6 +535,7 @@ TabParent::RecvSetInputMode(const PRUint32& aValue, const nsString& aType, const
context.mStatus = aValue;
context.mHTMLInputType.Assign(aType);
context.mActionHint.Assign(aAction);
context.mReason = aReason;
widget->SetInputMode(context);
nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService();

View File

@ -104,7 +104,7 @@ public:
virtual bool RecvEndIMEComposition(const PRBool& aCancel,
nsString* aComposition);
virtual bool RecvGetIMEEnabled(PRUint32* aValue);
virtual bool RecvSetInputMode(const PRUint32& aValue, const nsString& aType, const nsString& aAction);
virtual bool RecvSetInputMode(const PRUint32& aValue, const nsString& aType, const nsString& aAction, const PRUint32& aReason);
virtual bool RecvGetIMEOpenState(PRBool* aValue);
virtual bool RecvSetIMEOpenState(const PRBool& aValue);
virtual bool RecvGetDPI(float* aValue);

View File

@ -474,8 +474,9 @@ public class GeckoAppShell
if (!mEnable)
return;
if (GeckoApp.surfaceView.mIMEState !=
GeckoSurfaceView.IME_STATE_DISABLED)
int state = GeckoApp.surfaceView.mIMEState;
if (state != GeckoSurfaceView.IME_STATE_DISABLED &&
state != GeckoSurfaceView.IME_STATE_PLUGIN)
imm.showSoftInput(GeckoApp.surfaceView, 0);
else
imm.hideSoftInputFromWindow(

View File

@ -619,6 +619,7 @@ class GeckoSurfaceView
public static final int IME_STATE_DISABLED = 0;
public static final int IME_STATE_ENABLED = 1;
public static final int IME_STATE_PASSWORD = 2;
public static final int IME_STATE_PLUGIN = 3;
GeckoInputConnection inputConnection;
KeyListener mKeyListener;

View File

@ -233,6 +233,29 @@ struct nsIMEUpdatePreference {
struct IMEContext {
PRUint32 mStatus;
/* Does the change come from a trusted source */
enum {
FOCUS_REMOVED = 0x0001,
FOCUS_MOVED_UNKNOWN = 0x0002,
FOCUS_MOVED_BY_MOVEFOCUS = 0x0004,
FOCUS_MOVED_BY_MOUSE = 0x0008,
FOCUS_MOVED_BY_KEY = 0x0010,
FOCUS_MOVED_TO_MENU = 0x0020,
FOCUS_MOVED_FROM_MENU = 0x0040,
EDITOR_STATE_MODIFIED = 0x0080,
FOCUS_FROM_CONTENT_PROCESS = 0x0100
};
PRBool FocusMovedByUser() const {
return (mReason & FOCUS_MOVED_BY_MOUSE) || (mReason & FOCUS_MOVED_BY_KEY);
};
PRBool FocusMovedInContentProcess() const {
return (mReason & FOCUS_FROM_CONTENT_PROCESS);
};
PRUint32 mReason;
/* The type of the input if the input is a html input field */
nsString mHTMLInputType;

View File

@ -52,6 +52,7 @@ using mozilla::unused;
#include "nsIdleService.h"
#include "nsWindow.h"
#include "nsIObserverService.h"
#include "nsIPrefService.h"
#include "nsRenderingContext.h"
#include "nsIDOMSimpleGestureEvent.h"
@ -1740,9 +1741,25 @@ nsWindow::ResetInputState()
NS_IMETHODIMP
nsWindow::SetInputMode(const IMEContext& aContext)
{
ALOGIME("IME: SetInputMode: s=%d", aContext.mStatus);
ALOGIME("IME: SetInputMode: s=%d trusted=%d", aContext.mStatus, aContext.mReason);
mIMEContext = aContext;
// Ensure that opening the virtual keyboard is allowed for this specific
// IMEContext depending on the content.ime.strict.policy pref
if (aContext.mStatus != nsIWidget::IME_STATUS_DISABLED &&
aContext.mStatus != nsIWidget::IME_STATUS_PLUGIN) {
nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID));
PRBool useStrictPolicy = PR_FALSE;
if (NS_SUCCEEDED(prefs->GetBoolPref("content.ime.strict_policy", &useStrictPolicy))) {
if (useStrictPolicy && !aContext.FocusMovedByUser() &&
aContext.FocusMovedInContentProcess()) {
return NS_OK;
}
}
}
AndroidBridge::NotifyIMEEnabled(int(aContext.mStatus), aContext.mHTMLInputType, aContext.mActionHint);
return NS_OK;
}

View File

@ -53,6 +53,7 @@
#ifdef MOZ_PLATFORM_MAEMO
#include "nsServiceManagerUtils.h"
#include "nsIObserverService.h"
#include "nsIPrefService.h"
#include "mozilla/Services.h"
#endif
@ -588,6 +589,22 @@ nsGtkIMModule::SetInputMode(nsWindow* aCaller, const IMEContext* aContext)
GtkIMContext *im = GetContext();
if (im) {
if (IsEnabled()) {
// Ensure that opening the virtual keyboard is allowed for this specific
// IMEContext depending on the content.ime.strict.policy pref
if (mIMEContext.mStatus != nsIWidget::IME_STATUS_DISABLED &&
mIMEContext.mStatus != nsIWidget::IME_STATUS_PLUGIN) {
nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID));
PRBool useStrictPolicy = PR_FALSE;
if (NS_SUCCEEDED(prefs->GetBoolPref("content.ime.strict_policy", &useStrictPolicy))) {
if (useStrictPolicy && !mIMEContext.FocusMovedByUser() &&
mIMEContext.FocusMovedInContentProcess()) {
return NS_OK;
}
}
}
// It is not desired that the hildon's autocomplete mechanism displays
// user previous entered passwds, so lets make completions invisible
// in these cases.

View File

@ -398,7 +398,8 @@ NS_IMETHODIMP
PuppetWidget::SetInputMode(const IMEContext& aContext)
{
if (mTabChild &&
mTabChild->SendSetInputMode(aContext.mStatus, aContext.mHTMLInputType, aContext.mActionHint))
mTabChild->SendSetInputMode(aContext.mStatus, aContext.mHTMLInputType,
aContext.mActionHint, aContext.mReason))
return NS_OK;
return NS_ERROR_FAILURE;
}