Bug 1110888 - Always do plugin IME in main process, even with e10s. r=masayuki,smaug

This commit is contained in:
Steven Michaud 2015-02-20 10:37:02 -06:00
parent 757247b3e9
commit 22c83aa50a
19 changed files with 377 additions and 92 deletions

View File

@ -20,6 +20,10 @@
#include "nsNPAPIPluginInstance.h" #include "nsNPAPIPluginInstance.h"
#include "nsIWidget.h" #include "nsIWidget.h"
#include "nsContentUtils.h" #include "nsContentUtils.h"
#ifdef XP_MACOSX
#include "mozilla/EventDispatcher.h"
#include "mozilla/dom/Event.h"
#endif
namespace mozilla { namespace mozilla {
namespace dom { namespace dom {
@ -104,6 +108,55 @@ NS_IMPL_ELEMENT_CLONE(HTMLObjectElement)
// nsIConstraintValidation // nsIConstraintValidation
NS_IMPL_NSICONSTRAINTVALIDATION(HTMLObjectElement) NS_IMPL_NSICONSTRAINTVALIDATION(HTMLObjectElement)
#ifdef XP_MACOSX
static nsIWidget* GetWidget(Element* aElement)
{
nsIWidget* retval = NULL;
nsIFrame* frame = aElement->GetPrimaryFrame();
if (frame) {
retval = frame->GetNearestWidget();
}
return retval;
}
static void OnFocusBlurPlugin(Element* aElement, bool aFocus)
{
nsIWidget* widget = GetWidget(aElement);
if (widget) {
bool value = aFocus;
widget->SetPluginFocused(value);
}
}
void
HTMLObjectElement::HandleFocusBlurPlugin(Element* aElement,
WidgetEvent* aEvent)
{
if (!aEvent->mFlags.mIsTrusted) {
return;
}
switch (aEvent->message) {
case NS_FOCUS_CONTENT: {
OnFocusBlurPlugin(aElement, true);
break;
}
case NS_BLUR_CONTENT: {
OnFocusBlurPlugin(aElement, false);
break;
}
}
}
NS_IMETHODIMP
HTMLObjectElement::PostHandleEvent(EventChainPostVisitor& aVisitor)
{
HandleFocusBlurPlugin(this, aVisitor.mEvent);
return NS_OK;
}
#endif // #ifdef XP_MACOSX
NS_IMETHODIMP NS_IMETHODIMP
HTMLObjectElement::GetForm(nsIDOMHTMLFormElement **aForm) HTMLObjectElement::GetForm(nsIDOMHTMLFormElement **aForm)
{ {

View File

@ -30,6 +30,12 @@ public:
virtual int32_t TabIndexDefault() MOZ_OVERRIDE; virtual int32_t TabIndexDefault() MOZ_OVERRIDE;
#ifdef XP_MACOSX
// nsIDOMEventTarget
NS_IMETHOD PostHandleEvent(EventChainPostVisitor& aVisitor) MOZ_OVERRIDE;
static void HandleFocusBlurPlugin(Element* aElement, WidgetEvent* aEvent);
#endif
// Element // Element
virtual bool IsInteractiveHTMLContent() const MOZ_OVERRIDE; virtual bool IsInteractiveHTMLContent() const MOZ_OVERRIDE;

View File

@ -17,6 +17,11 @@
#include "nsIScriptError.h" #include "nsIScriptError.h"
#include "nsIWidget.h" #include "nsIWidget.h"
#include "nsContentUtils.h" #include "nsContentUtils.h"
#ifdef XP_MACOSX
#include "mozilla/EventDispatcher.h"
#include "mozilla/dom/Event.h"
#include "mozilla/dom/HTMLObjectElement.h"
#endif
NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(SharedObject) NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(SharedObject)
@ -108,6 +113,17 @@ NS_INTERFACE_MAP_END_INHERITING(nsGenericHTMLElement)
NS_IMPL_ELEMENT_CLONE(HTMLSharedObjectElement) NS_IMPL_ELEMENT_CLONE(HTMLSharedObjectElement)
#ifdef XP_MACOSX
NS_IMETHODIMP
HTMLSharedObjectElement::PostHandleEvent(EventChainPostVisitor& aVisitor)
{
HTMLObjectElement::HandleFocusBlurPlugin(this, aVisitor.mEvent);
return NS_OK;
}
#endif // #ifdef XP_MACOSX
nsresult nsresult
HTMLSharedObjectElement::BindToTree(nsIDocument *aDocument, HTMLSharedObjectElement::BindToTree(nsIDocument *aDocument,
nsIContent *aParent, nsIContent *aParent,

View File

@ -32,6 +32,11 @@ public:
virtual int32_t TabIndexDefault() MOZ_OVERRIDE; virtual int32_t TabIndexDefault() MOZ_OVERRIDE;
#ifdef XP_MACOSX
// nsIDOMEventTarget
NS_IMETHOD PostHandleEvent(EventChainPostVisitor& aVisitor) MOZ_OVERRIDE;
#endif
// nsIDOMHTMLAppletElement // nsIDOMHTMLAppletElement
NS_DECL_NSIDOMHTMLAPPLETELEMENT NS_DECL_NSIDOMHTMLAPPLETELEMENT

View File

@ -280,6 +280,28 @@ parent:
prio(urgent) sync EndIMEComposition(bool cancel) prio(urgent) sync EndIMEComposition(bool cancel)
returns (bool noCompositionEvent, nsString composition); returns (bool noCompositionEvent, nsString composition);
/**
* Tells chrome to start plugin IME. If this results in a string getting
* committed, the result is in aCommitted (otherwise aCommitted is empty).
*
* aKeyboardEvent The event with which plugin IME is to be started
* panelX and panelY Location in screen coordinates of the IME input panel
* (should be just under the plugin)
* aCommitted The string committed during IME -- otherwise empty
*/
prio(urgent) sync StartPluginIME(WidgetKeyboardEvent aKeyboardEvent,
int32_t panelX, int32_t panelY)
returns (nsString aCommitted);
/**
* Tells chrome (and specifically the appropriate widget) whether or not
* a plugin (inside the widget) has the keyboard focus. Should be sent
* when the keyboard focus changes too or from a plugin.
*
* aFocused Whether or not a plugin is focused
*/
prio(urgent) async SetPluginFocused(bool aFocused);
/** /**
* Request that the parent process move focus to the browser's frame. If * Request that the parent process move focus to the browser's frame. If
* canRaise is true, the window can be raised if it is inactive. * canRaise is true, the window can be raised if it is inactive.

View File

@ -2103,6 +2103,33 @@ TabParent::RecvEndIMEComposition(const bool& aCancel,
return true; return true;
} }
bool
TabParent::RecvStartPluginIME(const WidgetKeyboardEvent& aKeyboardEvent,
const int32_t& aPanelX, const int32_t& aPanelY,
nsString* aCommitted)
{
nsCOMPtr<nsIWidget> widget = GetWidget();
if (!widget) {
return true;
}
widget->StartPluginIME(aKeyboardEvent,
(int32_t&)aPanelX,
(int32_t&)aPanelY,
*aCommitted);
return true;
}
bool
TabParent::RecvSetPluginFocused(const bool& aFocused)
{
nsCOMPtr<nsIWidget> widget = GetWidget();
if (!widget) {
return true;
}
widget->SetPluginFocused((bool&)aFocused);
return true;
}
bool bool
TabParent::RecvGetInputContext(int32_t* aIMEEnabled, TabParent::RecvGetInputContext(int32_t* aIMEEnabled,
int32_t* aIMEOpen, int32_t* aIMEOpen,

View File

@ -192,6 +192,11 @@ public:
virtual bool RecvEndIMEComposition(const bool& aCancel, virtual bool RecvEndIMEComposition(const bool& aCancel,
bool* aNoCompositionEvent, bool* aNoCompositionEvent,
nsString* aComposition) MOZ_OVERRIDE; nsString* aComposition) MOZ_OVERRIDE;
virtual bool RecvStartPluginIME(const WidgetKeyboardEvent& aKeyboardEvent,
const int32_t& aPanelX,
const int32_t& aPanelY,
nsString* aCommitted) MOZ_OVERRIDE;
virtual bool RecvSetPluginFocused(const bool& aFocused) MOZ_OVERRIDE;
virtual bool RecvGetInputContext(int32_t* aIMEEnabled, virtual bool RecvGetInputContext(int32_t* aIMEEnabled,
int32_t* aIMEOpen, int32_t* aIMEOpen,
intptr_t* aNativeIMEContext) MOZ_OVERRIDE; intptr_t* aNativeIMEContext) MOZ_OVERRIDE;

View File

@ -1837,19 +1837,30 @@ TranslateToNPCocoaEvent(WidgetGUIEvent* anEvent, nsIFrame* aObjectFrame)
{ {
WidgetKeyboardEvent* keyEvent = anEvent->AsKeyboardEvent(); WidgetKeyboardEvent* keyEvent = anEvent->AsKeyboardEvent();
cocoaEvent.data.key.keyCode = keyEvent->mNativeKeyCode; // That keyEvent->mPluginTextEventString is non-empty is a signal that we should
cocoaEvent.data.key.isARepeat = keyEvent->mIsRepeat; // create a text event for the plugin, instead of a key event.
cocoaEvent.data.key.modifierFlags = keyEvent->mNativeModifierFlags; if ((anEvent->message == NS_KEY_DOWN) && !keyEvent->mPluginTextEventString.IsEmpty()) {
const char16_t* nativeChars = keyEvent->mNativeCharacters.get(); cocoaEvent.type = NPCocoaEventTextInput;
cocoaEvent.data.key.characters = const char16_t* pluginTextEventString = keyEvent->mPluginTextEventString.get();
(NPNSString*)::CFStringCreateWithCharacters(NULL, cocoaEvent.data.text.text = (NPNSString*)
reinterpret_cast<const UniChar*>(nativeChars), ::CFStringCreateWithCharacters(NULL,
keyEvent->mNativeCharacters.Length()); reinterpret_cast<const UniChar*>(pluginTextEventString),
const char16_t* nativeCharsIgnoringModifiers = keyEvent->mNativeCharactersIgnoringModifiers.get(); keyEvent->mPluginTextEventString.Length());
cocoaEvent.data.key.charactersIgnoringModifiers = } else {
(NPNSString*)::CFStringCreateWithCharacters(NULL, cocoaEvent.data.key.keyCode = keyEvent->mNativeKeyCode;
reinterpret_cast<const UniChar*>(nativeCharsIgnoringModifiers), cocoaEvent.data.key.isARepeat = keyEvent->mIsRepeat;
keyEvent->mNativeCharactersIgnoringModifiers.Length()); cocoaEvent.data.key.modifierFlags = keyEvent->mNativeModifierFlags;
const char16_t* nativeChars = keyEvent->mNativeCharacters.get();
cocoaEvent.data.key.characters = (NPNSString*)
::CFStringCreateWithCharacters(NULL,
reinterpret_cast<const UniChar*>(nativeChars),
keyEvent->mNativeCharacters.Length());
const char16_t* nativeCharsIgnoringModifiers = keyEvent->mNativeCharactersIgnoringModifiers.get();
cocoaEvent.data.key.charactersIgnoringModifiers = (NPNSString*)
::CFStringCreateWithCharacters(NULL,
reinterpret_cast<const UniChar*>(nativeCharsIgnoringModifiers),
keyEvent->mNativeCharactersIgnoringModifiers.Length());
}
break; break;
} }
case NS_FOCUS_CONTENT: case NS_FOCUS_CONTENT:
@ -1921,56 +1932,37 @@ nsEventStatus nsPluginInstanceOwner::ProcessEvent(const WidgetGUIEvent& anEvent)
return nsEventStatus_eIgnore; return nsEventStatus_eIgnore;
} }
if (cocoaEvent.type == NPCocoaEventKeyDown) { if (cocoaEvent.type == NPCocoaEventTextInput) {
ComplexTextInputPanel* ctiPanel = ComplexTextInputPanel::GetSharedComplexTextInputPanel(); mInstance->HandleEvent(&cocoaEvent, nullptr);
if (ctiPanel && ctiPanel->IsInComposition()) { return nsEventStatus_eConsumeNoDefault;
nsAutoString outText;
ctiPanel->InterpretKeyEvent(&cocoaEvent, outText);
if (!outText.IsEmpty()) {
CFStringRef cfString = ::CFStringCreateWithCharacters(kCFAllocatorDefault,
reinterpret_cast<const UniChar*>(outText.get()),
outText.Length());
NPCocoaEvent textEvent;
InitializeNPCocoaEvent(&textEvent);
textEvent.type = NPCocoaEventTextInput;
textEvent.data.text.text = (NPNSString*)cfString;
mInstance->HandleEvent(&textEvent, nullptr);
}
return nsEventStatus_eConsumeNoDefault;
}
} }
int16_t response = kNPEventNotHandled; int16_t response = kNPEventNotHandled;
mInstance->HandleEvent(&cocoaEvent, mInstance->HandleEvent(&cocoaEvent,
&response, &response,
NS_PLUGIN_CALL_SAFE_TO_REENTER_GECKO); NS_PLUGIN_CALL_SAFE_TO_REENTER_GECKO);
if (response == kNPEventStartIME) { if ((response == kNPEventStartIME) && (cocoaEvent.type == NPCocoaEventKeyDown)) {
nsAutoString outText; nsIWidget* widget = mPluginFrame->GetNearestWidget();
ComplexTextInputPanel* ctiPanel = ComplexTextInputPanel::GetSharedComplexTextInputPanel(); if (widget) {
const WidgetKeyboardEvent* keyEvent = anEvent.AsKeyboardEvent();
// Place ctiPanel by passing the coordinates of the bottom-left of the plugin, double screenX, screenY;
// in screen-coordinates. ConvertPoint(0.0, mPluginFrame->GetScreenRect().height,
double screenX, screenY; NPCoordinateSpacePlugin, &screenX, &screenY,
ConvertPoint(0.0, mPluginFrame->GetScreenRect().height, NPCoordinateSpacePlugin, NPCoordinateSpaceScreen);
&screenX, &screenY, NPCoordinateSpaceScreen); nsAutoString outText;
if (NS_SUCCEEDED(widget->StartPluginIME(*keyEvent, screenX, screenY, outText)) &&
ctiPanel->PlacePanel(screenX, screenY); !outText.IsEmpty()) {
ctiPanel->InterpretKeyEvent(&cocoaEvent, outText); CFStringRef cfString =
::CFStringCreateWithCharacters(kCFAllocatorDefault,
if (!outText.IsEmpty()) { reinterpret_cast<const UniChar*>(outText.get()),
CFStringRef cfString = ::CFStringCreateWithCharacters(kCFAllocatorDefault, outText.Length());
reinterpret_cast<const UniChar*>(outText.get()), NPCocoaEvent textEvent;
outText.Length()); InitializeNPCocoaEvent(&textEvent);
textEvent.type = NPCocoaEventTextInput;
NPCocoaEvent textEvent; textEvent.data.text.text = (NPNSString*)cfString;
InitializeNPCocoaEvent(&textEvent); mInstance->HandleEvent(&textEvent, nullptr);
textEvent.type = NPCocoaEventTextInput; }
textEvent.data.text.text = (NPNSString*)cfString; }
mInstance->HandleEvent(&textEvent, nullptr);
}
} }
bool handled = (response == kNPEventHandled || response == kNPEventStartIME); bool handled = (response == kNPEventHandled || response == kNPEventStartIME);

View File

@ -439,6 +439,28 @@ PuppetWidget::NotifyIMEInternal(const IMENotification& aIMENotification)
} }
} }
NS_IMETHODIMP
PuppetWidget::StartPluginIME(const mozilla::WidgetKeyboardEvent& aKeyboardEvent,
int32_t aPanelX, int32_t aPanelY,
nsString& aCommitted)
{
if (!mTabChild ||
!mTabChild->SendStartPluginIME(aKeyboardEvent, aPanelX,
aPanelY, &aCommitted)) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
NS_IMETHODIMP
PuppetWidget::SetPluginFocused(bool& aFocused)
{
if (!mTabChild || !mTabChild->SendSetPluginFocused(aFocused)) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
NS_IMETHODIMP_(void) NS_IMETHODIMP_(void)
PuppetWidget::SetInputContext(const InputContext& aContext, PuppetWidget::SetInputContext(const InputContext& aContext,
const InputContextAction& aAction) const InputContextAction& aAction)

View File

@ -196,6 +196,12 @@ public:
// Get the screen position of the application window. // Get the screen position of the application window.
nsIntPoint GetWindowPosition(); nsIntPoint GetWindowPosition();
NS_IMETHOD StartPluginIME(const mozilla::WidgetKeyboardEvent& aKeyboardEvent,
int32_t aPanelX, int32_t aPanelY,
nsString& aCommitted) MOZ_OVERRIDE;
NS_IMETHOD SetPluginFocused(bool& aFocused) MOZ_OVERRIDE;
protected: protected:
bool mEnabled; bool mEnabled;
bool mVisible; bool mVisible;

View File

@ -165,6 +165,9 @@ public:
uint32_t mNativeModifierFlags; uint32_t mNativeModifierFlags;
nsString mNativeCharacters; nsString mNativeCharacters;
nsString mNativeCharactersIgnoringModifiers; nsString mNativeCharactersIgnoringModifiers;
// If this is non-empty, create a text event for plugins instead of a
// keyboard event.
nsString mPluginTextEventString;
#endif #endif
// If the key should cause keypress events, this returns true. // If the key should cause keypress events, this returns true.
@ -251,6 +254,14 @@ public:
// is destroyed. // is destroyed.
mNativeKeyEvent = nullptr; mNativeKeyEvent = nullptr;
mUniqueId = aEvent.mUniqueId; mUniqueId = aEvent.mUniqueId;
#ifdef XP_MACOSX
mNativeKeyCode = aEvent.mNativeKeyCode;
mNativeModifierFlags = aEvent.mNativeModifierFlags;
mNativeCharacters.Assign(aEvent.mNativeCharacters);
mNativeCharactersIgnoringModifiers.
Assign(aEvent.mNativeCharactersIgnoringModifiers);
mPluginTextEventString.Assign(aEvent.mPluginTextEventString);
#endif
} }
private: private:

View File

@ -36,8 +36,10 @@ class ComplexTextInputPanel
public: public:
static ComplexTextInputPanel* GetSharedComplexTextInputPanel(); static ComplexTextInputPanel* GetSharedComplexTextInputPanel();
virtual void PlacePanel(int32_t x, int32_t y) = 0; // Bottom left coordinate of plugin in screen coords virtual void PlacePanel(int32_t x, int32_t y) = 0; // Bottom left coordinate of plugin in screen coords
virtual void InterpretKeyEvent(NPCocoaEvent* aEvent, nsAString& aOutText) = 0; virtual void InterpretKeyEvent(void* aEvent, nsAString& aOutText) = 0;
virtual bool IsInComposition() = 0; virtual bool IsInComposition() = 0;
virtual void* GetInputContext() = 0;
virtual void CancelComposition() = 0;
protected: protected:
virtual ~ComplexTextInputPanel() {}; virtual ~ComplexTextInputPanel() {};

View File

@ -132,23 +132,8 @@ extern "C" OSStatus TSMProcessRawKeyEvent(EventRef anEvent);
{ {
*string = nil; *string = nil;
if (!nsCocoaFeatures::OnMountainLionOrLater()) { if (![[mInputTextView inputContext] handleEvent:event]) {
// This "works" on OS X 10.7 and below, but at the cost of breaking plugin return;
// IME, even in non-e10s mode: In an IME like Kotoeri Hiragana, every key
// gets sent to the plugin individually.
if (![[mInputTextView inputContext] handleEvent:event]) {
return;
}
} else {
// On OS X 10.8 and above we can't use -[NSTextInputContext handleEvent:]
// -- it doesn't work with a synthesized event. We need to activate the
// input context and call TSMProcessRawKeyEvent instead. This also allows
// plugin IME to work properly in non-e10s mode.
[[mInputTextView inputContext] activate];
OSErr err = TSMProcessRawKeyEvent((EventRef)[event eventRef]);
if (err != noErr) {
return;
}
} }
if ([mInputTextView hasMarkedText]) { if ([mInputTextView hasMarkedText]) {
@ -222,9 +207,12 @@ class ComplexTextInputPanelPrivate : public ComplexTextInputPanel
public: public:
ComplexTextInputPanelPrivate(); ComplexTextInputPanelPrivate();
virtual void InterpretKeyEvent(NPCocoaEvent* aEvent, nsAString& aOutText); virtual void InterpretKeyEvent(void* aEvent, nsAString& aOutText);
virtual bool IsInComposition(); virtual bool IsInComposition();
virtual void PlacePanel(int32_t x, int32_t y); virtual void PlacePanel(int32_t x, int32_t y);
virtual void* GetInputContext() { return [mPanel inputContext]; }
virtual void CancelComposition() { [mPanel cancelComposition]; }
private: private:
~ComplexTextInputPanelPrivate(); ~ComplexTextInputPanelPrivate();
ComplexTextInputPanelImpl* mPanel; ComplexTextInputPanelImpl* mPanel;
@ -251,21 +239,10 @@ ComplexTextInputPanel::GetSharedComplexTextInputPanel()
} }
void void
ComplexTextInputPanelPrivate::InterpretKeyEvent(NPCocoaEvent* aEvent, nsAString& aOutText) ComplexTextInputPanelPrivate::InterpretKeyEvent(void* aEvent, nsAString& aOutText)
{ {
NSEvent* nativeEvent = [NSEvent keyEventWithType:NSKeyDown
location:NSMakePoint(0,0)
modifierFlags:aEvent->data.key.modifierFlags
timestamp:0
windowNumber:[mPanel windowNumber]
context:[mPanel graphicsContext]
characters:(NSString*)aEvent->data.key.characters
charactersIgnoringModifiers:(NSString*)aEvent->data.key.charactersIgnoringModifiers
isARepeat:aEvent->data.key.isARepeat
keyCode:aEvent->data.key.keyCode];
NSString* textString = nil; NSString* textString = nil;
[mPanel interpretKeyEvent:nativeEvent string:&textString]; [mPanel interpretKeyEvent:(NSEvent*)aEvent string:&textString];
if (textString) { if (textString) {
nsCocoaUtils::GetStringForNSString(textString, aOutText); nsCocoaUtils::GetStringForNSString(textString, aOutText);

View File

@ -1523,7 +1523,20 @@ TextInputHandler::HandleKeyDownEvent(NSEvent* aNativeEvent)
KeyEventState* currentKeyEvent = PushKeyEvent(aNativeEvent); KeyEventState* currentKeyEvent = PushKeyEvent(aNativeEvent);
AutoKeyEventStateCleaner remover(this); AutoKeyEventStateCleaner remover(this);
if (!IsIMEComposing()) { ComplexTextInputPanel* ctiPanel = ComplexTextInputPanel::GetSharedComplexTextInputPanel();
if (ctiPanel && ctiPanel->IsInComposition()) {
nsAutoString committed;
ctiPanel->InterpretKeyEvent(aNativeEvent, committed);
if (!committed.IsEmpty()) {
WidgetKeyboardEvent imeEvent(true, NS_KEY_DOWN, mWidget);
InitKeyEvent(aNativeEvent, imeEvent);
imeEvent.mPluginTextEventString.Assign(committed);
DispatchEvent(imeEvent);
}
return true;
}
if (mWidget->IsPluginFocused() || !IsIMEComposing()) {
NSResponder* firstResponder = [[mView window] firstResponder]; NSResponder* firstResponder = [[mView window] firstResponder];
WidgetKeyboardEvent keydownEvent(true, NS_KEY_DOWN, mWidget); WidgetKeyboardEvent keydownEvent(true, NS_KEY_DOWN, mWidget);
@ -1555,6 +1568,14 @@ TextInputHandler::HandleKeyDownEvent(NSEvent* aNativeEvent)
} }
} }
// None of what follows is needed for plugin keyboard input. In fact it
// may cause trouble -- for example the call to [mView interpretKeyEvents:]
// can, in e10s mode, cause each key typed to appear twice in an IME
// composition.
if (mWidget->IsPluginFocused()) {
return true;
}
// Let Cocoa interpret the key events, caching IsIMEComposing first. // Let Cocoa interpret the key events, caching IsIMEComposing first.
bool wasComposing = IsIMEComposing(); bool wasComposing = IsIMEComposing();
bool interpretKeyEventsCalled = false; bool interpretKeyEventsCalled = false;

View File

@ -183,6 +183,9 @@ typedef NSInteger NSEventGestureAxis;
// when mouseDown: is called, we store its event here (strong) // when mouseDown: is called, we store its event here (strong)
NSEvent* mLastMouseDownEvent; NSEvent* mLastMouseDownEvent;
// Needed for IME support in e10s mode. Strong.
NSEvent* mLastKeyDownEvent;
// Whether the last mouse down event was blocked from Gecko. // Whether the last mouse down event was blocked from Gecko.
BOOL mBlockedLastMouseDown; BOOL mBlockedLastMouseDown;
@ -312,6 +315,8 @@ typedef NSInteger NSEventGestureAxis;
#endif #endif
- (void)setUsingOMTCompositor:(BOOL)aUseOMTC; - (void)setUsingOMTCompositor:(BOOL)aUseOMTC;
- (NSEvent*)lastKeyDownEvent;
@end @end
class ChildViewMouseTracker { class ChildViewMouseTracker {
@ -527,6 +532,14 @@ public:
APZCTreeManager* APZCTM() { return mAPZC ; } APZCTreeManager* APZCTM() { return mAPZC ; }
NS_IMETHOD StartPluginIME(const mozilla::WidgetKeyboardEvent& aKeyboardEvent,
int32_t aPanelX, int32_t aPanelY,
nsString& aCommitted) MOZ_OVERRIDE;
NS_IMETHOD SetPluginFocused(bool& aFocused);
bool IsPluginFocused() { return mPluginFocused; }
protected: protected:
virtual ~nsChildView(); virtual ~nsChildView();
@ -627,6 +640,8 @@ protected:
bool mDrawing; bool mDrawing;
bool mIsDispatchPaint; // Is a paint event being dispatched bool mIsDispatchPaint; // Is a paint event being dispatched
bool mPluginFocused;
// Used in OMTC BasicLayers mode. Presents the BasicCompositor result // Used in OMTC BasicLayers mode. Presents the BasicCompositor result
// surface to the screen using an OpenGL context. // surface to the screen using an OpenGL context.
nsAutoPtr<GLPresenter> mGLPresenter; nsAutoPtr<GLPresenter> mGLPresenter;

View File

@ -44,6 +44,7 @@
#include "nsMenuUtilsX.h" #include "nsMenuUtilsX.h"
#include "nsMenuBarX.h" #include "nsMenuBarX.h"
#include "NativeKeyBindings.h" #include "NativeKeyBindings.h"
#include "ComplexTextInputPanel.h"
#include "gfxContext.h" #include "gfxContext.h"
#include "gfxQuartzSurface.h" #include "gfxQuartzSurface.h"
@ -543,6 +544,8 @@ nsresult nsChildView::Create(nsIWidget *aParent,
NS_ASSERTION(!mTextInputHandler, "mTextInputHandler has already existed"); NS_ASSERTION(!mTextInputHandler, "mTextInputHandler has already existed");
mTextInputHandler = new TextInputHandler(this, mView); mTextInputHandler = new TextInputHandler(this, mView);
mPluginFocused = false;
return NS_OK; return NS_OK;
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
@ -1617,6 +1620,48 @@ nsChildView::NotifyIMEInternal(const IMENotification& aIMENotification)
} }
} }
NS_IMETHODIMP
nsChildView::StartPluginIME(const mozilla::WidgetKeyboardEvent& aKeyboardEvent,
int32_t aPanelX, int32_t aPanelY,
nsString& aCommitted)
{
NS_ENSURE_TRUE(mView, NS_ERROR_NOT_AVAILABLE);
ComplexTextInputPanel* ctiPanel =
ComplexTextInputPanel::GetSharedComplexTextInputPanel();
ctiPanel->PlacePanel(aPanelX, aPanelY);
// We deliberately don't use TextInputHandler::GetCurrentKeyEvent() to
// obtain the NSEvent* we pass to InterpretKeyEvent(). This works fine in
// non-e10s mode. But in e10s mode TextInputHandler::HandleKeyDownEvent()
// has already returned, so the relevant KeyEventState* (and its NSEvent*)
// is already out of scope. Furthermore we don't *need* to use it.
// StartPluginIME() is only ever called to start a new IME session when none
// currently exists. So nested IME should never reach here, and so it should
// be fine to use the last key-down event received by -[ChildView keyDown:]
// (as we currently do).
ctiPanel->InterpretKeyEvent([mView lastKeyDownEvent], aCommitted);
return NS_OK;
}
NS_IMETHODIMP
nsChildView::SetPluginFocused(bool& aFocused)
{
if (aFocused == mPluginFocused) {
return NS_OK;
}
if (!aFocused) {
ComplexTextInputPanel* ctiPanel =
ComplexTextInputPanel::GetSharedComplexTextInputPanel();
if (ctiPanel) {
ctiPanel->CancelComposition();
}
}
mPluginFocused = aFocused;
return NS_OK;
}
NS_IMETHODIMP_(void) NS_IMETHODIMP_(void)
nsChildView::SetInputContext(const InputContext& aContext, nsChildView::SetInputContext(const InputContext& aContext,
const InputContextAction& aAction) const InputContextAction& aAction)
@ -2901,6 +2946,7 @@ NSEvent* gLastDragMouseDownEvent = nil;
mExpectingWheelStop = NO; mExpectingWheelStop = NO;
mLastMouseDownEvent = nil; mLastMouseDownEvent = nil;
mLastKeyDownEvent = nil;
mClickThroughMouseDownEvent = nil; mClickThroughMouseDownEvent = nil;
mDragService = nullptr; mDragService = nullptr;
@ -2955,6 +3001,26 @@ NSEvent* gLastDragMouseDownEvent = nil;
NS_OBJC_END_TRY_ABORT_BLOCK_NIL; NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
} }
// ComplexTextInputPanel's interpretKeyEvent hack won't work without this.
// It makes calls to +[NSTextInputContext currentContext], deep in system
// code, return the appropriate context.
- (NSTextInputContext *)inputContext
{
NSTextInputContext* pluginContext = NULL;
if (mGeckoChild && mGeckoChild->IsPluginFocused()) {
ComplexTextInputPanel* ctiPanel =
ComplexTextInputPanel::GetSharedComplexTextInputPanel();
if (ctiPanel) {
pluginContext = (NSTextInputContext*) ctiPanel->GetInputContext();
}
}
if (pluginContext) {
return pluginContext;
} else {
return [super inputContext];
}
}
- (void)installTextInputHandler:(TextInputHandler*)aHandler - (void)installTextInputHandler:(TextInputHandler*)aHandler
{ {
mTextInputHandler = aHandler; mTextInputHandler = aHandler;
@ -3032,6 +3098,7 @@ NSEvent* gLastDragMouseDownEvent = nil;
[mGLContext release]; [mGLContext release];
[mPendingDirtyRects release]; [mPendingDirtyRects release];
[mLastMouseDownEvent release]; [mLastMouseDownEvent release];
[mLastKeyDownEvent release];
[mClickThroughMouseDownEvent release]; [mClickThroughMouseDownEvent release];
CGImageRelease(mTopLeftCornerMask); CGImageRelease(mTopLeftCornerMask);
ChildViewMouseTracker::OnDestroyView(self); ChildViewMouseTracker::OnDestroyView(self);
@ -5281,10 +5348,18 @@ static int32_t RoundUp(double aDouble)
return YES; return YES;
} }
- (NSEvent*)lastKeyDownEvent
{
return mLastKeyDownEvent;
}
- (void)keyDown:(NSEvent*)theEvent - (void)keyDown:(NSEvent*)theEvent
{ {
NS_OBJC_BEGIN_TRY_ABORT_BLOCK; NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
[mLastKeyDownEvent release];
mLastKeyDownEvent = [theEvent retain];
// Weird things can happen on keyboard input if the key window isn't in the // Weird things can happen on keyboard input if the key window isn't in the
// current space. For example see bug 1056251. To get around this, always // current space. For example see bug 1056251. To get around this, always
// make sure that, if our window is key, it's also made frontmost. Doing // make sure that, if our window is key, it's also made frontmost. Doing

View File

@ -200,6 +200,12 @@ public:
virtual nsresult ActivateNativeMenuItemAt(const nsAString& indexString) MOZ_OVERRIDE { return NS_ERROR_NOT_IMPLEMENTED; } virtual nsresult ActivateNativeMenuItemAt(const nsAString& indexString) MOZ_OVERRIDE { return NS_ERROR_NOT_IMPLEMENTED; }
virtual nsresult ForceUpdateNativeMenuAt(const nsAString& indexString) MOZ_OVERRIDE { return NS_ERROR_NOT_IMPLEMENTED; } virtual nsresult ForceUpdateNativeMenuAt(const nsAString& indexString) MOZ_OVERRIDE { return NS_ERROR_NOT_IMPLEMENTED; }
NS_IMETHOD NotifyIME(const IMENotification& aIMENotification) MOZ_OVERRIDE MOZ_FINAL; NS_IMETHOD NotifyIME(const IMENotification& aIMENotification) MOZ_OVERRIDE MOZ_FINAL;
NS_IMETHOD StartPluginIME(const mozilla::WidgetKeyboardEvent& aKeyboardEvent,
int32_t aPanelX, int32_t aPanelY,
nsString& aCommitted) MOZ_OVERRIDE
{ return NS_ERROR_NOT_IMPLEMENTED; }
NS_IMETHOD SetPluginFocused(bool& aFocused) MOZ_OVERRIDE
{ return NS_ERROR_NOT_IMPLEMENTED; }
NS_IMETHOD AttachNativeKeyEvent(mozilla::WidgetKeyboardEvent& aEvent) MOZ_OVERRIDE { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHOD AttachNativeKeyEvent(mozilla::WidgetKeyboardEvent& aEvent) MOZ_OVERRIDE { return NS_ERROR_NOT_IMPLEMENTED; }
NS_IMETHOD_(bool) ExecuteNativeKeyBinding( NS_IMETHOD_(bool) ExecuteNativeKeyBinding(
NativeKeyBindingsType aType, NativeKeyBindingsType aType,

View File

@ -335,6 +335,7 @@ struct ParamTraits<mozilla::WidgetKeyboardEvent>
WriteParam(aMsg, aParam.mNativeModifierFlags); WriteParam(aMsg, aParam.mNativeModifierFlags);
WriteParam(aMsg, aParam.mNativeCharacters); WriteParam(aMsg, aParam.mNativeCharacters);
WriteParam(aMsg, aParam.mNativeCharactersIgnoringModifiers); WriteParam(aMsg, aParam.mNativeCharactersIgnoringModifiers);
WriteParam(aMsg, aParam.mPluginTextEventString);
#endif #endif
// An OS-specific native event might be attached in |mNativeKeyEvent|, but // An OS-specific native event might be attached in |mNativeKeyEvent|, but
// that cannot be copied across process boundaries. // that cannot be copied across process boundaries.
@ -361,6 +362,7 @@ struct ParamTraits<mozilla::WidgetKeyboardEvent>
&& ReadParam(aMsg, aIter, &aResult->mNativeModifierFlags) && ReadParam(aMsg, aIter, &aResult->mNativeModifierFlags)
&& ReadParam(aMsg, aIter, &aResult->mNativeCharacters) && ReadParam(aMsg, aIter, &aResult->mNativeCharacters)
&& ReadParam(aMsg, aIter, &aResult->mNativeCharactersIgnoringModifiers) && ReadParam(aMsg, aIter, &aResult->mNativeCharactersIgnoringModifiers)
&& ReadParam(aMsg, aIter, &aResult->mPluginTextEventString)
#endif #endif
) )
{ {

View File

@ -113,8 +113,8 @@ typedef void* nsNativeWidget;
#define NS_NATIVE_PLUGIN_ID 105 #define NS_NATIVE_PLUGIN_ID 105
#define NS_IWIDGET_IID \ #define NS_IWIDGET_IID \
{ 0xa7db3e01, 0xb8fe, 0x4122, \ { 0x316E4600, 0x15DB, 0x47AE, \
{ 0xbe, 0xa6, 0x45, 0x6c, 0xdd, 0x85, 0x30, 0x64 } }; { 0xBF, 0xE4, 0x5B, 0xCD, 0xFF, 0x80, 0x80, 0x83 } };
/* /*
* Window shadow styles * Window shadow styles
@ -2008,6 +2008,28 @@ public:
*/ */
NS_IMETHOD NotifyIME(const IMENotification& aIMENotification) = 0; NS_IMETHOD NotifyIME(const IMENotification& aIMENotification) = 0;
/**
* Start plugin IME. If this results in a string getting committed, the
* result is in aCommitted (otherwise aCommitted is empty).
*
* aKeyboardEvent The event with which plugin IME is to be started
* panelX and panelY Location in screen coordinates of the IME input panel
* (should be just under the plugin)
* aCommitted The string committed during IME -- otherwise empty
*/
NS_IMETHOD StartPluginIME(const mozilla::WidgetKeyboardEvent& aKeyboardEvent,
int32_t aPanelX, int32_t aPanelY,
nsString& aCommitted) = 0;
/**
* Tells the widget whether or not a plugin (inside the widget) has the
* keyboard focus. Should be sent when the keyboard focus changes too or
* from a plugin.
*
* aFocused Whether or not a plugin is focused
*/
NS_IMETHOD SetPluginFocused(bool& aFocused) = 0;
/* /*
* Notifies the input context changes. * Notifies the input context changes.
*/ */