Bug 1051842 - Part 2 - crash in -[ChildView keyDown:]. r=masayuki

In e10s, each nsFocusManger (main/chrome and content/tab) operates on its own content tree with its own InputContext.  They also communicate their InputContexts with the OS widget (nsChildView on mac, nsWindow on Windows).  Prior to this patch, the OS widgets didn't distinguish between main and content InputContexts.  When GetInputContext was called on the OS widget, it would return whatever InputContext it had set last.  This patch distinguishes between InputContexts in the widget.
This commit is contained in:
David Parks 2014-08-27 22:06:41 -07:00
parent 0dfc51d9ff
commit e3be37acfb
3 changed files with 69 additions and 3 deletions

View File

@ -17,6 +17,7 @@
#include "mozilla/TextComposition.h"
#include "mozilla/TextEvents.h"
#include "mozilla/dom/HTMLFormElement.h"
#include "mozilla/dom/TabParent.h"
#include "HTMLInputElement.h"
#include "IMEContentObserver.h"
@ -394,6 +395,27 @@ IMEStateManager::OnChangeFocusInternal(nsPresContext* aPresContext,
}
IMEState newState = GetNewIMEState(aPresContext, aContent);
// In e10s, remote content may have IME focus. The main process (i.e. this process)
// would attempt to set state to DISABLED if, for example, the user clicks
// some other remote content. The content process would later re-ENABLE IME, meaning
// that all state-changes were unnecessary.
// Here we filter the common case where the main process knows that the remote
// process controls IME focus. The DISABLED->re-ENABLED progression can
// still happen since remote content may be concurrently communicating its claim
// on focus to the main process... but this cannot cause bugs like missed keypresses.
// (It just means a lot of needless IPC.)
if ((newState.mEnabled == IMEState::DISABLED) && TabParent::GetIMETabParent()) {
PR_LOG(sISMLog, PR_LOG_DEBUG,
("ISM: IMEStateManager::OnChangeFocusInternal(), "
"Parent process cancels to set DISABLED state because the content process "
"has IME focus and has already sets IME state"));
MOZ_ASSERT(XRE_IsParentProcess(),
"TabParent::GetIMETabParent() should never return non-null value "
"in the content process");
return NS_OK;
}
if (!focusActuallyChanging) {
// actual focus isn't changing, but if IME enabled state is changing,
// we should do it.

View File

@ -1925,14 +1925,25 @@ TabParent::RecvSetInputContext(const int32_t& aIMEEnabled,
const int32_t& aCause,
const int32_t& aFocusChange)
{
nsCOMPtr<nsIWidget> widget = GetWidget();
if (!widget || !AllowContentIME()) {
return true;
}
InputContext oldContext = widget->GetInputContext();
// Ignore if current widget IME setting is not DISABLED and didn't come
// from remote content. Chrome content may have taken over.
if (oldContext.mIMEState.mEnabled != IMEState::DISABLED &&
oldContext.IsOriginMainProcess()) {
return true;
}
// mIMETabParent (which is actually static) tracks which if any TabParent has IMEFocus
// When the input mode is set to anything but IMEState::DISABLED,
// mIMETabParent should be set to this
mIMETabParent =
aIMEEnabled != static_cast<int32_t>(IMEState::DISABLED) ? this : nullptr;
nsCOMPtr<nsIWidget> widget = GetWidget();
if (!widget || !AllowContentIME())
return true;
InputContext context;
context.mIMEState.mEnabled = static_cast<IMEState::Enabled>(aIMEEnabled);
@ -1940,6 +1951,8 @@ TabParent::RecvSetInputContext(const int32_t& aIMEEnabled,
context.mHTMLInputType.Assign(aType);
context.mHTMLInputInputmode.Assign(aInputmode);
context.mActionHint.Assign(aActionHint);
context.mOrigin = InputContext::ORIGIN_CONTENT;
InputContextAction action(
static_cast<InputContextAction::Cause>(aCause),
static_cast<InputContextAction::FocusChange>(aFocusChange));

View File

@ -411,6 +411,7 @@ struct InputContext {
InputContext()
: mNativeIMEContext(nullptr)
, mMayBeIMEUnaware(false)
, mOrigin(XRE_IsParentProcess() ? ORIGIN_MAIN : ORIGIN_CONTENT)
{}
bool IsPasswordEditor() const
@ -438,6 +439,36 @@ struct InputContext {
* composiion events. This enables a key-events-only mode on Android for
* compatibility with webapps relying on key listeners. */
bool mMayBeIMEUnaware;
/**
* mOrigin indicates whether this focus event refers to main or remote content.
*/
enum Origin
{
// Adjusting focus of content on the main process
ORIGIN_MAIN,
// Adjusting focus of content in a remote process
ORIGIN_CONTENT
};
Origin mOrigin;
bool IsOriginMainProcess() const
{
return mOrigin == ORIGIN_MAIN;
}
bool IsOriginContentProcess() const
{
return mOrigin == ORIGIN_CONTENT;
}
bool IsOriginCurrentProcess() const
{
if (XRE_IsParentProcess()) {
return IsOriginMainProcess();
}
return IsOriginContentProcess();
}
};
struct InputContextAction {