Bug 1179632 part.1 native IME context should not be stored in InputContext but should be able to retrieve with nsIWidget::GetNativeData() r=smaug

This commit is contained in:
Masayuki Nakano 2015-12-11 15:15:57 +09:00
parent 7f3300e643
commit 24944df82e
21 changed files with 146 additions and 87 deletions

View File

@ -40,7 +40,7 @@ TextComposition::TextComposition(nsPresContext* aPresContext,
, mNode(aNode)
, mTabParent(aTabParent)
, mNativeContext(
aCompositionEvent->widget->GetInputContext().mNativeIMEContext)
aCompositionEvent->widget->GetNativeData(NS_NATIVE_IME_CONTEXT))
, mCompositionStartOffset(0)
, mCompositionTargetOffset(0)
, mIsSynthesizedForTests(aCompositionEvent->mFlags.mIsSynthesizedForTests)
@ -69,7 +69,7 @@ TextComposition::Destroy()
bool
TextComposition::MatchesNativeContext(nsIWidget* aWidget) const
{
return mNativeContext == aWidget->GetInputContext().mNativeIMEContext;
return mNativeContext == aWidget->GetNativeData(NS_NATIVE_IME_CONTEXT);
}
bool

View File

@ -296,8 +296,7 @@ parent:
nsCString[] disabledCommands);
prio(urgent) sync GetInputContext() returns (int32_t IMEEnabled,
int32_t IMEOpen,
intptr_t NativeIMEContext);
int32_t IMEOpen);
prio(urgent) async SetInputContext(int32_t IMEEnabled,
int32_t IMEOpen,

View File

@ -2363,21 +2363,18 @@ TabParent::RecvSetPluginFocused(const bool& aFocused)
bool
TabParent::RecvGetInputContext(int32_t* aIMEEnabled,
int32_t* aIMEOpen,
intptr_t* aNativeIMEContext)
int32_t* aIMEOpen)
{
nsCOMPtr<nsIWidget> widget = GetWidget();
if (!widget) {
*aIMEEnabled = IMEState::DISABLED;
*aIMEOpen = IMEState::OPEN_STATE_NOT_SUPPORTED;
*aNativeIMEContext = 0;
return true;
}
InputContext context = widget->GetInputContext();
*aIMEEnabled = static_cast<int32_t>(context.mIMEState.mEnabled);
*aIMEOpen = static_cast<int32_t>(context.mIMEState.mOpen);
*aNativeIMEContext = reinterpret_cast<intptr_t>(context.mNativeIMEContext);
return true;
}

View File

@ -196,8 +196,7 @@ public:
nsString* aCommitted) override;
virtual bool RecvSetPluginFocused(const bool& aFocused) override;
virtual bool RecvGetInputContext(int32_t* aIMEEnabled,
int32_t* aIMEOpen,
intptr_t* aNativeIMEContext) override;
int32_t* aIMEOpen) override;
virtual bool RecvSetInputContext(const int32_t& aIMEEnabled,
const int32_t& aIMEOpen,
const nsString& aType,

View File

@ -223,11 +223,15 @@ struct IMEState final
}
};
// NS_ONLY_ONE_NATIVE_IME_CONTEXT is a special value of native IME context.
// If there can be only one IME composition in a process, this can be used.
#define NS_ONLY_ONE_NATIVE_IME_CONTEXT \
(reinterpret_cast<void*>(static_cast<intptr_t>(-1)))
struct InputContext final
{
InputContext()
: mNativeIMEContext(nullptr)
, mOrigin(XRE_IsParentProcess() ? ORIGIN_MAIN : ORIGIN_CONTENT)
: mOrigin(XRE_IsParentProcess() ? ORIGIN_MAIN : ORIGIN_CONTENT)
, mMayBeIMEUnaware(false)
{
}
@ -248,11 +252,6 @@ struct InputContext final
/* A hint for the action that is performed when the input is submitted */
nsString mActionHint;
/* Native IME context for the widget. This doesn't come from the argument of
SetInputContext(). If there is only one context in the process, this may
be nullptr. */
void* mNativeIMEContext;
/**
* mOrigin indicates whether this focus event refers to main or remote
* content.

View File

@ -675,11 +675,10 @@ PuppetWidget::GetInputContext()
InputContext context;
if (mTabChild) {
int32_t enabled, open;
intptr_t nativeIMEContext;
mTabChild->SendGetInputContext(&enabled, &open, &nativeIMEContext);
// TODO: This is too expensive. PuppetWidget should cache IMEState.
mTabChild->SendGetInputContext(&enabled, &open);
context.mIMEState.mEnabled = static_cast<IMEState::Enabled>(enabled);
context.mIMEState.mOpen = static_cast<IMEState::Open>(open);
context.mNativeIMEContext = reinterpret_cast<void*>(nativeIMEContext);
}
return context;
}
@ -1121,6 +1120,9 @@ PuppetWidget::GetNativeData(uint32_t aDataType)
case NS_NATIVE_DISPLAY:
// These types are ignored (see bug 1183828).
break;
case NS_NATIVE_IME_CONTEXT:
// TODO: Implement this in next patch.
return nullptr;
case NS_NATIVE_WINDOW:
case NS_NATIVE_PLUGIN_PORT:
case NS_NATIVE_GRAPHIC:

View File

@ -1263,6 +1263,11 @@ nsWindow::GetNativeData(uint32_t aDataType)
case NS_NATIVE_WIDGET:
return (void *) this;
case NS_NATIVE_IME_CONTEXT:
// We assume that there is only one context per process on Android
return NS_ONLY_ONE_NATIVE_IME_CONTEXT;
}
return nullptr;
@ -2244,8 +2249,6 @@ nsWindow::Natives::GetInputContext()
{
InputContext context = mInputContext;
context.mIMEState.mOpen = IMEState::OPEN_STATE_NOT_SUPPORTED;
// We assume that there is only one context per process on Android
context.mNativeIMEContext = nullptr;
return context;
}

View File

@ -684,6 +684,17 @@ void* nsChildView::GetNativeData(uint32_t aDataType)
case NS_NATIVE_OFFSETY:
retVal = 0;
break;
case NS_NATIVE_IME_CONTEXT:
retVal = [mView inputContext];
// If input context isn't available on this widget, we should set |this|
// instead of nullptr since if this returns nullptr, IMEStateManager
// cannot manage composition with TextComposition instance. Although,
// this case shouldn't occur.
if (NS_WARN_IF(!retVal)) {
retVal = this;
}
break;
}
return retVal;
@ -1769,13 +1780,6 @@ nsChildView::GetInputContext()
mInputContext.mIMEState.mOpen = IMEState::CLOSED;
break;
}
mInputContext.mNativeIMEContext = [mView inputContext];
// If input context isn't available on this widget, we should set |this|
// instead of nullptr since nullptr means that the platform has only one
// context per process.
if (!mInputContext.mNativeIMEContext) {
mInputContext.mNativeIMEContext = this;
}
return mInputContext;
}

View File

@ -365,16 +365,6 @@ public:
const InputContextAction& aAction) override;
NS_IMETHOD_(InputContext) GetInputContext() override
{
NSView* view = mWindow ? [mWindow contentView] : nil;
if (view) {
mInputContext.mNativeIMEContext = [view inputContext];
}
// If inputContext isn't available on this window, returns this window's
// pointer since nullptr means the platform has only one context per
// process.
if (!mInputContext.mNativeIMEContext) {
mInputContext.mNativeIMEContext = this;
}
return mInputContext;
}
NS_IMETHOD_(bool) ExecuteNativeKeyBinding(

View File

@ -592,6 +592,20 @@ void* nsCocoaWindow::GetNativeData(uint32_t aDataType)
// and it doesn't matter so just return nullptr.
NS_ERROR("Requesting NS_NATIVE_GRAPHIC on a top-level window!");
break;
case NS_NATIVE_IME_CONTEXT: {
NSView* view = mWindow ? [mWindow contentView] : nil;
if (view) {
retVal = [view inputContext];
}
// If inputContext isn't available on this window, return this window's
// pointer instead of nullptr since if this returns nullptr,
// IMEStateManager cannot manage composition with TextComposition
// instance. Although, this case shouldn't occur.
if (NS_WARN_IF(!retVal)) {
retVal = this;
}
break;
}
}
return retVal;

View File

@ -539,6 +539,9 @@ nsWindow::GetNativeData(uint32_t aDataType)
return mScreen->GetNativeWindow();
case NS_NATIVE_OPENGL_CONTEXT:
return mScreen->GetGLContext().take();
case NS_NATIVE_IME_CONTEXT:
// There is only one IME context on Gonk.
return NS_ONLY_ONE_NATIVE_IME_CONTEXT;
}
return nullptr;
@ -582,8 +585,6 @@ nsWindow::SetInputContext(const InputContext& aContext,
NS_IMETHODIMP_(InputContext)
nsWindow::GetInputContext()
{
// There is only one IME context on Gonk.
mInputContext.mNativeIMEContext = nullptr;
return mInputContext;
}

View File

@ -1737,6 +1737,15 @@ nsWindow::GetNativeData(uint32_t aDataType)
return (void *) GDK_WINDOW_XID(gdk_window_get_toplevel(mGdkWindow));
case NS_NATIVE_PLUGIN_OBJECT_PTR:
return (void *) mPluginNativeWindow;
case NS_NATIVE_IME_CONTEXT:
// If IME context isn't available on this widget, we should set |this|
// instead of nullptr since if we return nullptr, IMEStateManager
// cannot manage composition with TextComposition instance. Although,
// this case shouldn't occur.
if (NS_WARN_IF(!mIMContext)) {
return this;
}
return mIMContext.get();
default:
NS_WARNING("nsWindow::GetNativeData called with bad value");
return nullptr;
@ -6295,13 +6304,8 @@ nsWindow::GetInputContext()
if (!mIMContext) {
context.mIMEState.mEnabled = IMEState::DISABLED;
context.mIMEState.mOpen = IMEState::OPEN_STATE_NOT_SUPPORTED;
// If IME context isn't available on this widget, we should set |this|
// instead of nullptr since nullptr means that the platform has only one
// context per process.
context.mNativeIMEContext = this;
} else {
context = mIMContext->GetInputContext();
context.mNativeIMEContext = mIMContext;
}
return context;
}

View File

@ -104,7 +104,12 @@ typedef void* nsNativeWidget;
#define NS_NATIVE_SHAREABLE_WINDOW 11
#define NS_NATIVE_OPENGL_CONTEXT 12
// See RegisterPluginWindowForRemoteUpdates
#define NS_NATIVE_PLUGIN_ID 13
#define NS_NATIVE_PLUGIN_ID 13
// This is available only with GetNativeData(). Anybody shouldn't access this
// pointer as a valid pointer since the result may be special value like
// NS_ONLY_ONE_NATIVE_IME_CONTEXT. So, the result is just an identifier of
// distinguishing a text composition is caused by which native IME context.
#define NS_NATIVE_IME_CONTEXT 14
#ifdef XP_MACOSX
#define NS_NATIVE_PLUGIN_PORT_QD 100
#define NS_NATIVE_PLUGIN_PORT_CG 101

View File

@ -664,6 +664,10 @@ nsWindow::GetNativeData(uint32_t aDataType)
case NS_NATIVE_SHELLWIDGET: {
break;
}
case NS_NATIVE_IME_CONTEXT:
// Our qt widget looks like using only one context per process.
// However, it's better to set the context's pointer.
return qApp->inputMethod();
default:
NS_WARNING("nsWindow::GetNativeData called with bad value");
return nullptr;
@ -716,10 +720,6 @@ NS_IMETHODIMP_(InputContext)
nsWindow::GetInputContext()
{
mInputContext.mIMEState.mOpen = IMEState::OPEN_STATE_NOT_SUPPORTED;
// Our qt widget looks like using only one context per process.
// However, it's better to set the context's pointer.
mInputContext.mNativeIMEContext = qApp->inputMethod();
return mInputContext;
}

View File

@ -836,7 +836,6 @@ nsWindow::SetInputContext(const InputContext& aContext,
NS_IMETHODIMP_(mozilla::widget::InputContext)
nsWindow::GetInputContext()
{
mInputContext.mNativeIMEContext = nullptr;
return mInputContext;
}
@ -879,6 +878,10 @@ void* nsWindow::GetNativeData(uint32_t aDataType)
case NS_NATIVE_PLUGIN_PORT:
// not implemented
break;
case NS_NATIVE_IME_CONTEXT:
retVal = NS_ONLY_ONE_NATIVE_IME_CONTEXT;
break;
}
return retVal;

View File

@ -186,6 +186,30 @@ IMEContext::IMEContext(nsWindow* aWindow)
{
}
void
IMEContext::Init(HWND aWnd)
{
Clear();
mWnd = aWnd;
mIMC = ::ImmGetContext(mWnd);
}
void
IMEContext::Init(nsWindow* aWindow)
{
Init(aWindow->GetWindowHandle());
}
void
IMEContext::Clear()
{
if (mWnd && mIMC) {
::ImmReleaseContext(mWnd, mIMC);
}
mWnd = nullptr;
mIMC = nullptr;
}
/******************************************************************************
* IMMHandler
******************************************************************************/

View File

@ -26,15 +26,18 @@ struct MSGResult;
class IMEContext final
{
public:
IMEContext()
: mWnd(nullptr)
, mIMC(nullptr)
{
}
explicit IMEContext(HWND aWnd);
explicit IMEContext(nsWindow* aWindow);
~IMEContext()
{
if (mIMC) {
::ImmReleaseContext(mWnd, mIMC);
mIMC = nullptr;
}
Clear();
}
HIMC get() const
@ -42,6 +45,10 @@ public:
return mIMC;
}
void Init(HWND aWnd);
void Init(nsWindow* aWindow);
void Clear();
bool IsValid() const
{
return !!mIMC;
@ -90,11 +97,6 @@ public:
}
protected:
IMEContext()
{
MOZ_CRASH("Don't create IMEContext without window handle");
}
IMEContext(const IMEContext& aOther)
{
MOZ_CRASH("Don't copy IMEContext");

View File

@ -94,8 +94,31 @@ IMEHandler::Terminate()
// static
void*
IMEHandler::GetNativeData(uint32_t aDataType)
IMEHandler::GetNativeData(nsWindow* aWindow, uint32_t aDataType)
{
if (aDataType == NS_NATIVE_IME_CONTEXT) {
#ifdef NS_ENABLE_TSF
if (IsTSFAvailable()) {
return TSFTextStore::GetThreadManager();
}
#endif // #ifdef NS_ENABLE_TSF
IMEContext context(aWindow);
if (context.IsValid()) {
return context.get();
}
// If IMC isn't associated with the window, IME is disabled on the window
// now. In such case, we should return default IMC instead.
const IMEContext& defaultIMC = aWindow->DefaultIMC();
if (defaultIMC.IsValid()) {
return defaultIMC.get();
}
// If there is no default IMC, we should return the pointer to the window
// since if we return nullptr, IMEStateManager cannot manage composition
// with TextComposition instance. This is possible if no IME is installed,
// but composition may occur with dead key sequence.
return aWindow;
}
#ifdef NS_ENABLE_TSF
void* result = TSFTextStore::GetNativeData(aDataType);
if (!result || !(*(static_cast<void**>(result)))) {
@ -380,14 +403,11 @@ IMEHandler::SetInputContext(nsWindow* aWindow,
bool open = (adjustOpenState &&
aInputContext.mIMEState.mOpen == IMEState::OPEN);
aInputContext.mNativeIMEContext = nullptr;
#ifdef NS_ENABLE_TSF
// Note that even while a plugin has focus, we need to notify TSF of that.
if (sIsInTSFMode) {
TSFTextStore::SetInputContext(aWindow, aInputContext, aAction);
if (IsTSFAvailable()) {
aInputContext.mNativeIMEContext = TSFTextStore::GetThreadManager();
if (sIsIMMEnabled) {
// Associate IME context for IMM-IMEs.
AssociateIMEContext(aWindow, enable);
@ -413,15 +433,6 @@ IMEHandler::SetInputContext(nsWindow* aWindow,
if (adjustOpenState) {
context.SetOpenState(open);
}
if (aInputContext.mNativeIMEContext) {
return;
}
// The old InputContext must store the default IMC or old TextStore.
// When IME context is disassociated from the window, use it.
aInputContext.mNativeIMEContext = enable ?
static_cast<void*>(context.get()) : oldInputContext.mNativeIMEContext;
}
// static
@ -452,8 +463,6 @@ IMEHandler::InitInputContext(nsWindow* aWindow, InputContext& aInputContext)
TSFTextStore::SetInputContext(aWindow, aInputContext,
InputContextAction(InputContextAction::CAUSE_UNKNOWN,
InputContextAction::GOT_FOCUS));
aInputContext.mNativeIMEContext = TSFTextStore::GetThreadManager();
MOZ_ASSERT(aInputContext.mNativeIMEContext);
// IME context isn't necessary in pure TSF mode.
if (!sIsIMMEnabled) {
AssociateIMEContext(aWindow, false);
@ -462,15 +471,11 @@ IMEHandler::InitInputContext(nsWindow* aWindow, InputContext& aInputContext)
}
#endif // #ifdef NS_ENABLE_TSF
// NOTE: mNativeIMEContext may be null if IMM module isn't installed.
#ifdef DEBUG
// NOTE: IMC may be null if IMM module isn't installed.
IMEContext context(aWindow);
aInputContext.mNativeIMEContext = static_cast<void*>(context.get());
MOZ_ASSERT(aInputContext.mNativeIMEContext || !CurrentKeyboardLayoutHasIME());
// If no IME context is available, we should set the widget's pointer since
// nullptr indicates there is only one context per process on the platform.
if (!aInputContext.mNativeIMEContext) {
aInputContext.mNativeIMEContext = static_cast<void*>(aWindow);
}
MOZ_ASSERT(context.IsValid() || !CurrentKeyboardLayoutHasIME());
#endif // #ifdef DEBUG
}
#ifdef DEBUG

View File

@ -34,9 +34,9 @@ public:
static void Terminate();
/**
* Returns TSF related native data.
* Returns TSF related native data or native IME context.
*/
static void* GetNativeData(uint32_t aDataType);
static void* GetNativeData(nsWindow* aWindow, uint32_t aDataType);
/**
* ProcessRawKeyMessage() message is called before calling TranslateMessage()

View File

@ -656,6 +656,7 @@ nsWindow::Create(nsIWidget* aParent,
NOTIFY_FOR_THIS_SESSION);
NS_ASSERTION(wtsRegistered, "WTSRegisterSessionNotification failed!\n");
mDefaultIMC.Init(this);
IMEHandler::InitInputContext(this, mInputContext);
// If the internal variable set by the config.trim_on_minimize pref has not
@ -3149,10 +3150,11 @@ void* nsWindow::GetNativeData(uint32_t aDataType)
return (void*)::GetDC(mWnd);
#endif
case NS_NATIVE_IME_CONTEXT:
case NS_NATIVE_TSF_THREAD_MGR:
case NS_NATIVE_TSF_CATEGORY_MGR:
case NS_NATIVE_TSF_DISPLAY_ATTR_MGR:
return IMEHandler::GetNativeData(aDataType);
return IMEHandler::GetNativeData(this, aDataType);
default:
break;

View File

@ -44,6 +44,8 @@
#include "nsIDOMMouseEvent.h"
#include "nsIIdleServiceInternal.h"
#include "IMMHandler.h"
/**
* Forward class definitions
*/
@ -71,6 +73,7 @@ class nsWindow : public nsWindowBase
typedef mozilla::widget::TaskbarWindowPreview TaskbarWindowPreview;
typedef mozilla::widget::NativeKey NativeKey;
typedef mozilla::widget::MSGResult MSGResult;
typedef mozilla::widget::IMEContext IMEContext;
public:
nsWindow();
@ -292,6 +295,8 @@ public:
bool CaptureWidgetOnScreen(RefPtr<mozilla::gfx::DrawTarget> aDT);
const IMEContext& DefaultIMC() const { return mDefaultIMC; }
protected:
virtual ~nsWindow();
@ -472,6 +477,7 @@ protected:
HWND mTransitionWnd;
WNDPROC mPrevWndProc;
HBRUSH mBrush;
IMEContext mDefaultIMC;
bool mIsTopWidgetWindow;
bool mInDtor;
bool mIsVisible;