Bug 950559 part.2 nsIMM32Handler should set IME releated windows to left-bottom of focused plugin r=emk

This commit is contained in:
Masayuki Nakano 2013-12-18 10:43:15 +09:00
parent e0ff6eabfe
commit b8cb3cd758
3 changed files with 87 additions and 1 deletions

View File

@ -104,6 +104,18 @@ IMEHandler::ProcessMessage(nsWindow* aWindow, UINT aMessage,
{
#ifdef NS_ENABLE_TSF
if (IsTSFAvailable()) {
if (aMessage == WM_IME_SETCONTEXT) {
// If a windowless plugin had focus and IME was handled on it, composition
// window was set the position. After that, even in TSF mode, WinXP keeps
// to use composition window at the position if the active IME is not
// aware TSF. For avoiding this issue, we need to hide the composition
// window here.
if (aWParam) {
aLParam &= ~ISC_SHOWUICOMPOSITIONWINDOW;
}
return false;
}
if (aMessage == WM_USER_TSF_TEXTCHANGE) {
nsTextStore::OnTextChangeMsg();
aResult.mConsumed = true;

View File

@ -763,6 +763,8 @@ nsIMM32Handler::OnIMEStartCompositionOnPlugin(nsWindow* aWindow,
aWindow->GetWindowHandle(), mIsComposingOnPlugin ? "TRUE" : "FALSE"));
mIsComposingOnPlugin = true;
mComposingWindow = aWindow;
nsIMEContext IMEContext(aWindow->GetWindowHandle());
SetIMERelatedWindowsPosOnPlugin(aWindow, IMEContext);
aResult.mConsumed =
aWindow->DispatchPluginEvent(WM_IME_STARTCOMPOSITION, wParam, lParam,
false);
@ -795,6 +797,8 @@ nsIMM32Handler::OnIMECompositionOnPlugin(nsWindow* aWindow,
if (IS_COMPOSING_LPARAM(lParam)) {
mIsComposingOnPlugin = true;
mComposingWindow = aWindow;
nsIMEContext IMEContext(aWindow->GetWindowHandle());
SetIMERelatedWindowsPosOnPlugin(aWindow, IMEContext);
}
aResult.mConsumed =
aWindow->DispatchPluginEvent(WM_IME_COMPOSITION, wParam, lParam, true);
@ -813,6 +817,12 @@ nsIMM32Handler::OnIMEEndCompositionOnPlugin(nsWindow* aWindow,
mIsComposingOnPlugin = false;
mComposingWindow = nullptr;
if (mNativeCaretIsCreated) {
::DestroyCaret();
mNativeCaretIsCreated = false;
}
aResult.mConsumed =
aWindow->DispatchPluginEvent(WM_IME_ENDCOMPOSITION, wParam, lParam,
false);
@ -1930,6 +1940,68 @@ nsIMM32Handler::SetIMERelatedWindowsPos(nsWindow* aWindow,
return true;
}
void
nsIMM32Handler::SetIMERelatedWindowsPosOnPlugin(nsWindow* aWindow,
const nsIMEContext& aIMEContext)
{
WidgetQueryContentEvent editorRectEvent(true, NS_QUERY_EDITOR_RECT, aWindow);
aWindow->InitEvent(editorRectEvent);
aWindow->DispatchWindowEvent(&editorRectEvent);
if (!editorRectEvent.mSucceeded) {
PR_LOG(gIMM32Log, PR_LOG_ALWAYS,
("IMM32: SetIMERelatedWindowsPosOnPlugin, "
"FAILED (NS_QUERY_EDITOR_RECT)"));
return;
}
// Clip the plugin rect by the client rect of the window because composition
// window needs to be specified the position in the client area.
nsWindow* toplevelWindow = aWindow->GetTopLevelWindow(false);
nsIntRect pluginRectInScreen =
editorRectEvent.mReply.mRect + toplevelWindow->WidgetToScreenOffset();
nsIntRect winRectInScreen;
aWindow->GetClientBounds(winRectInScreen);
// composition window cannot be positioned on the edge of client area.
winRectInScreen.width--;
winRectInScreen.height--;
nsIntRect clippedPluginRect;
clippedPluginRect.x =
std::min(std::max(pluginRectInScreen.x, winRectInScreen.x),
winRectInScreen.XMost());
clippedPluginRect.y =
std::min(std::max(pluginRectInScreen.y, winRectInScreen.y),
winRectInScreen.YMost());
int32_t xMost = std::min(pluginRectInScreen.XMost(), winRectInScreen.XMost());
int32_t yMost = std::min(pluginRectInScreen.YMost(), winRectInScreen.YMost());
clippedPluginRect.width = std::max(0, xMost - clippedPluginRect.x);
clippedPluginRect.height = std::max(0, yMost - clippedPluginRect.y);
clippedPluginRect -= aWindow->WidgetToScreenOffset();
// Cover the plugin with native caret. This prevents IME's window and plugin
// overlap.
if (mNativeCaretIsCreated) {
::DestroyCaret();
}
mNativeCaretIsCreated =
::CreateCaret(aWindow->GetWindowHandle(), nullptr,
clippedPluginRect.width, clippedPluginRect.height);
::SetCaretPos(clippedPluginRect.x, clippedPluginRect.y);
// Set the composition window to bottom-left of the clipped plugin.
// As far as we know, there is no IME for RTL language. Therefore, this code
// must not need to take care of RTL environment.
COMPOSITIONFORM compForm;
compForm.dwStyle = CFS_POINT;
compForm.ptCurrentPos.x = clippedPluginRect.BottomLeft().x;
compForm.ptCurrentPos.y = clippedPluginRect.BottomLeft().y;
if (!::ImmSetCompositionWindow(aIMEContext.get(), &compForm)) {
PR_LOG(gIMM32Log, PR_LOG_ALWAYS,
("IMM32: SetIMERelatedWindowsPosOnPlugin, "
"FAILED to set composition window"));
return;
}
}
void
nsIMM32Handler::ResolveIMECaretPos(nsIWidget* aReferenceWidget,
nsIntRect& aCursorRect,

View File

@ -261,7 +261,9 @@ protected:
nsACString& aANSIStr);
bool SetIMERelatedWindowsPos(nsWindow* aWindow,
const nsIMEContext &aIMEContext);
const nsIMEContext& aIMEContext);
void SetIMERelatedWindowsPosOnPlugin(nsWindow* aWindow,
const nsIMEContext& aIMEContext);
bool GetCharacterRectOfSelectedTextAt(nsWindow* aWindow,
uint32_t aOffset,
nsIntRect &aCharRect);