Bug 1208944 - Part 10-b. Call DefaultProc When CompositionEvent isn't handled correctly by plugin. r=masayuki

This commit is contained in:
Makoto Kato 2015-12-29 22:57:38 +09:00
parent 3317a4cbfe
commit 648e3da9ac
7 changed files with 182 additions and 36 deletions

View File

@ -62,6 +62,7 @@ using mozilla::DefaultXDisplay;
#include "nsPIWindowRoot.h"
#include "mozilla/IMEStateManager.h"
#include "mozilla/TextComposition.h"
#include "mozilla/AutoRestore.h"
#include "nsContentCID.h"
#include "nsWidgetsCID.h"
@ -368,6 +369,11 @@ nsPluginInstanceOwner::nsPluginInstanceOwner()
mFullScreen = false;
mJavaView = nullptr;
#endif
#ifdef XP_WIN
mGotCompositionData = false;
mSentStartComposition = false;
#endif
}
nsPluginInstanceOwner::~nsPluginInstanceOwner()
@ -799,6 +805,9 @@ nsPluginInstanceOwner::GetCompositionString(uint32_t aType,
nsTArray<uint8_t>* aDist,
int32_t* aLength)
{
// Mark pkugin calls ImmGetCompositionStringW correctly
mGotCompositionData = true;
RefPtr<TextComposition> composition = GetTextComposition();
if (NS_WARN_IF(!composition)) {
return false;
@ -1660,10 +1669,10 @@ nsresult nsPluginInstanceOwner::DispatchFocusToPlugin(nsIDOMEvent* aFocusEvent)
if (theEvent) {
WidgetGUIEvent focusEvent(theEvent->mFlags.mIsTrusted, theEvent->mMessage,
nullptr);
nsEventStatus rv = ProcessEvent(focusEvent);
if (nsEventStatus_eConsumeNoDefault == rv) {
nsEventStatus status = ProcessEvent(focusEvent);
if (nsEventStatus_eConsumeNoDefault == status) {
aFocusEvent->PreventDefault();
aFocusEvent->StopPropagation();
aFocusEvent->StopImmediatePropagation();
}
}
@ -1775,6 +1784,28 @@ nsresult nsPluginInstanceOwner::DispatchMouseToPlugin(nsIDOMEvent* aMouseEvent,
}
#ifdef XP_WIN
void
nsPluginInstanceOwner::CallDefaultProc(const WidgetGUIEvent* aEvent)
{
nsCOMPtr<nsIWidget> widget = GetContainingWidgetIfOffset();
if (!widget) {
widget = GetRootWidgetForPluginFrame(mPluginFrame);
if (NS_WARN_IF(!widget)) {
return;
}
}
const NPEvent* npEvent =
static_cast<const NPEvent*>(aEvent->mPluginEvent);
if (NS_WARN_IF(!npEvent)) {
return;
}
WidgetPluginEvent pluginEvent(true, ePluginInputEvent, widget);
pluginEvent.mPluginEvent.Copy(*npEvent);
widget->DefaultProcOfPluginEvent(pluginEvent);
}
already_AddRefed<TextComposition>
nsPluginInstanceOwner::GetTextComposition()
{
@ -1824,13 +1855,79 @@ nsPluginInstanceOwner::DispatchCompositionToPlugin(nsIDOMEvent* aEvent)
compositionChangeEventHandlingMarker(composition, compositionEvent);
}
// Protected mode Flash returns noDefault by NPP_HandleEvent, but
// composition information into plugin is invalid because plugin's bug.
// So if plugin doesn't get composition data by WM_IME_COMPOSITION, we
// recongnize it isn't handled
AutoRestore<bool> restore(mGotCompositionData);
mGotCompositionData = false;
nsEventStatus rv = ProcessEvent(*compositionEvent);
// XXX This isn't e10s aware.
// If the event isn't consumed, we cannot post result to chrome process.
if (nsEventStatus_eConsumeNoDefault == rv) {
aEvent->StopImmediatePropagation();
aEvent->StopImmediatePropagation();
// Composition event isn't handled by plugin, so we have to call default proc.
const NPEvent* pPluginEvent =
static_cast<const NPEvent*>(compositionEvent->mPluginEvent);
if (NS_WARN_IF(!pPluginEvent)) {
return NS_OK;
}
#endif
if (pPluginEvent->event == WM_IME_STARTCOMPOSITION) {
// Flash's protected mode lies that composition event is handled, but it
// cannot do it well. So even if handled, we should post this message when
// no IMM API calls during WM_IME_COMPOSITION.
if (nsEventStatus_eConsumeNoDefault != rv) {
CallDefaultProc(compositionEvent);
mSentStartComposition = true;
} else {
mSentStartComposition = false;
}
return NS_OK;
}
if (pPluginEvent->event == WM_IME_ENDCOMPOSITION) {
// Always post WM_END_COMPOSITION to default proc. Because Flash may lie
// that it doesn't handle composition well, but event is handled.
// Even if posting this message, default proc do nothing if unnecessary.
CallDefaultProc(compositionEvent);
return NS_OK;
}
if (pPluginEvent->event == WM_IME_COMPOSITION && !mGotCompositionData) {
nsCOMPtr<nsIWidget> widget = GetContainingWidgetIfOffset();
if (!widget) {
widget = GetRootWidgetForPluginFrame(mPluginFrame);
}
if (pPluginEvent->lParam & GCS_RESULTSTR) {
// GCS_RESULTSTR's default proc will generate WM_CHAR. So emulate it.
for (size_t i = 0; i < compositionEvent->mData.Length(); i++) {
WidgetPluginEvent charEvent(true, ePluginInputEvent, widget);
NPEvent event;
event.event = WM_CHAR;
event.wParam = compositionEvent->mData[i];
event.lParam = 0;
charEvent.mPluginEvent.Copy(event);
ProcessEvent(charEvent);
}
return NS_OK;
}
if (!mSentStartComposition) {
// We post WM_IME_COMPOSITION to default proc, but
// WM_IME_STARTCOMPOSITION isn't post yet. We should post it at first.
WidgetPluginEvent event(true, ePluginInputEvent, widget);
NPEvent npevent;
npevent.event = WM_IME_STARTCOMPOSITION;
npevent.wParam = 0;
npevent.lParam = 0;
event.mPluginEvent.Copy(npevent);
CallDefaultProc(&event);
mSentStartComposition = true;
}
CallDefaultProc(compositionEvent);
}
#endif // #ifdef XP_WIN
return NS_OK;
}

View File

@ -289,6 +289,9 @@ private:
#if defined(XP_WIN)
nsIWidget* GetContainingWidgetIfOffset();
already_AddRefed<mozilla::TextComposition> GetTextComposition();
bool mGotCompositionData;
bool mSentStartComposition;
#endif
nsPluginNativeWindow *mPluginWindow;
@ -342,6 +345,10 @@ private:
nsresult DispatchFocusToPlugin(nsIDOMEvent* aFocusEvent);
nsresult DispatchCompositionToPlugin(nsIDOMEvent* aEvent);
#ifdef XP_WIN
void CallDefaultProc(const mozilla::WidgetGUIEvent* aEvent);
#endif
#ifdef XP_MACOSX
static NPBool ConvertPointPuppet(PuppetWidget *widget, nsPluginFrame* pluginFrame,
double sourceX, double sourceY, NPCoordinateSpace sourceSpace,

View File

@ -1088,11 +1088,10 @@ IMMHandler::OnChar(nsWindow* aWindow,
* message handlers for plug-in
****************************************************************************/
bool
void
IMMHandler::OnIMEStartCompositionOnPlugin(nsWindow* aWindow,
WPARAM wParam,
LPARAM lParam,
MSGResult& aResult)
LPARAM lParam)
{
MOZ_LOG(gIMMLog, LogLevel::Info,
("IMM: OnIMEStartCompositionOnPlugin, hWnd=%08x, mIsComposingOnPlugin=%s",
@ -1104,17 +1103,12 @@ IMMHandler::OnIMEStartCompositionOnPlugin(nsWindow* aWindow,
// On widnowless plugin, we should assume that the focused editor is always
// in horizontal writing mode.
AdjustCompositionFont(aWindow, context, WritingMode());
aResult.mConsumed =
aWindow->DispatchPluginEvent(WM_IME_STARTCOMPOSITION, wParam, lParam,
false);
return true;
}
bool
void
IMMHandler::OnIMECompositionOnPlugin(nsWindow* aWindow,
WPARAM wParam,
LPARAM lParam,
MSGResult& aResult)
LPARAM lParam)
{
MOZ_LOG(gIMMLog, LogLevel::Info,
("IMM: OnIMECompositionOnPlugin, hWnd=%08x, lParam=%08x, "
@ -1128,6 +1122,7 @@ IMMHandler::OnIMECompositionOnPlugin(nsWindow* aWindow,
if (IS_COMMITTING_LPARAM(lParam)) {
mIsComposingOnPlugin = false;
mComposingWindow = nullptr;
return;
}
// Continue composition if there is still a string being composed.
if (IS_COMPOSING_LPARAM(lParam)) {
@ -1136,16 +1131,12 @@ IMMHandler::OnIMECompositionOnPlugin(nsWindow* aWindow,
IMEContext context(aWindow);
SetIMERelatedWindowsPosOnPlugin(aWindow, context);
}
aResult.mConsumed =
aWindow->DispatchPluginEvent(WM_IME_COMPOSITION, wParam, lParam, true);
return true;
}
bool
void
IMMHandler::OnIMEEndCompositionOnPlugin(nsWindow* aWindow,
WPARAM wParam,
LPARAM lParam,
MSGResult& aResult)
LPARAM lParam)
{
MOZ_LOG(gIMMLog, LogLevel::Info,
("IMM: OnIMEEndCompositionOnPlugin, hWnd=%08x, mIsComposingOnPlugin=%s",
@ -1158,11 +1149,6 @@ IMMHandler::OnIMEEndCompositionOnPlugin(nsWindow* aWindow,
::DestroyCaret();
mNativeCaretIsCreated = false;
}
aResult.mConsumed =
aWindow->DispatchPluginEvent(WM_IME_ENDCOMPOSITION, wParam, lParam,
false);
return true;
}
bool
@ -1231,6 +1217,12 @@ IMMHandler::OnCharOnPlugin(nsWindow* aWindow,
LPARAM lParam,
MSGResult& aResult)
{
NS_WARNING("OnCharOnPlugin");
if (mIsComposing) {
aWindow->NotifyIME(REQUEST_TO_COMMIT_COMPOSITION);
return true;
}
// We should never consume char message on windowless plugin.
aResult.mConsumed = false;
if (IsIMECharRecordsEmpty()) {
@ -2757,6 +2749,33 @@ IMMHandler::SetCandidateWindow(nsWindow* aWindow, CANDIDATEFORM* aForm)
ImmSetCandidateWindow(context.get(), aForm);
}
// staitc
void
IMMHandler::DefaultProcOfPluginEvent(nsWindow* aWindow, const NPEvent* aEvent)
{
switch (aEvent->event) {
case WM_IME_STARTCOMPOSITION:
EnsureHandlerInstance();
gIMMHandler->OnIMEStartCompositionOnPlugin(aWindow, aEvent->wParam,
aEvent->lParam);
break;
case WM_IME_COMPOSITION:
if (gIMMHandler) {
gIMMHandler->OnIMECompositionOnPlugin(aWindow, aEvent->wParam,
aEvent->lParam);
}
break;
case WM_IME_ENDCOMPOSITION:
if (gIMMHandler) {
gIMMHandler->OnIMEEndCompositionOnPlugin(aWindow, aEvent->wParam,
aEvent->lParam);
}
break;
}
}
/******************************************************************************
* IMMHandler::Selection
******************************************************************************/

View File

@ -15,6 +15,7 @@
#include "mozilla/EventForwards.h"
#include "nsRect.h"
#include "WritingModes.h"
#include "npapi.h"
class nsWindow;
@ -151,6 +152,8 @@ public:
static nsresult OnMouseButtonEvent(nsWindow* aWindow,
const IMENotification& aIMENotification);
static void SetCandidateWindow(nsWindow* aWindow, CANDIDATEFORM* aForm);
static void DefaultProcOfPluginEvent(nsWindow* aWindow,
const NPEvent* aEvent);
protected:
static void EnsureHandlerInstance();
@ -192,16 +195,15 @@ protected:
MSGResult& aResult);
bool OnIMEStartComposition(nsWindow* aWindow, MSGResult& aResult);
bool OnIMEStartCompositionOnPlugin(nsWindow* aWindow,
WPARAM wParam, LPARAM lParam,
MSGResult& aResult);
void OnIMEStartCompositionOnPlugin(nsWindow* aWindow,
WPARAM wParam, LPARAM lParam);
bool OnIMEComposition(nsWindow* aWindow, WPARAM wParam, LPARAM lParam,
MSGResult& aResult);
bool OnIMECompositionOnPlugin(nsWindow* aWindow, WPARAM wParam, LPARAM lParam,
MSGResult& aResult);
void OnIMECompositionOnPlugin(nsWindow* aWindow, WPARAM wParam,
LPARAM lParam);
bool OnIMEEndComposition(nsWindow* aWindow, MSGResult& aResult);
bool OnIMEEndCompositionOnPlugin(nsWindow* aWindow, WPARAM wParam,
LPARAM lParam, MSGResult& aResult);
void OnIMEEndCompositionOnPlugin(nsWindow* aWindow, WPARAM wParam,
LPARAM lParam);
bool OnIMERequest(nsWindow* aWindow, WPARAM wParam, LPARAM lParam,
MSGResult& aResult);
bool OnIMECharOnPlugin(nsWindow* aWindow, WPARAM wParam, LPARAM lParam,

View File

@ -959,5 +959,16 @@ IMEHandler::SetCandidateWindow(nsWindow* aWindow, CANDIDATEFORM* aForm)
IMMHandler::SetCandidateWindow(aWindow, aForm);
}
// static
void
IMEHandler::DefaultProcOfPluginEvent(nsWindow* aWindow,
const NPEvent* aPluginEvent)
{
if (!sPluginHasFocus) {
return;
}
IMMHandler::DefaultProcOfPluginEvent(aWindow, aPluginEvent);
}
} // namespace widget
} // namespace mozilla

View File

@ -8,6 +8,7 @@
#include "nscore.h"
#include "nsIWidget.h"
#include "npapi.h"
#include <windows.h>
#include <inputscope.h>
@ -108,6 +109,12 @@ public:
*/
static void SetCandidateWindow(nsWindow* aWindow, CANDIDATEFORM* aForm);
/*
* For WM_IME_*COMPOSITION messages and e10s with windowless plugin
*/
static void DefaultProcOfPluginEvent(nsWindow* aWindow,
const NPEvent* aPluginEvent);
#ifdef DEBUG
/**
* Returns true when current keyboard layout has IME. Otherwise, false.

View File

@ -7777,6 +7777,9 @@ nsWindow::DefaultProcOfPluginEvent(const WidgetPluginEvent& aEvent)
return;
}
// For WM_IME_*COMPOSITION
IMEHandler::DefaultProcOfPluginEvent(this, pPluginEvent);
CallWindowProcW(GetPrevWindowProc(), mWnd, pPluginEvent->event,
pPluginEvent->wParam, pPluginEvent->lParam);
}