diff options
author | stuartmorgan@chromium.org <stuartmorgan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-01-21 21:15:13 +0000 |
---|---|---|
committer | stuartmorgan@chromium.org <stuartmorgan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-01-21 21:15:13 +0000 |
commit | b7f75868cb53eb45d3e15263a663327e381d40db (patch) | |
tree | bc2faeff6b2f1137e79be528168a26decc646231 | |
parent | db5523bcb7e0419955172709c241a188ab94e8e0 (diff) | |
download | chromium_src-b7f75868cb53eb45d3e15263a663327e381d40db.zip chromium_src-b7f75868cb53eb45d3e15263a663327e381d40db.tar.gz chromium_src-b7f75868cb53eb45d3e15263a663327e381d40db.tar.bz2 |
Update Mac plugin IME handling to match updated spec
This changes IME handling per the recent NPAPI spec clarification, and adds the new bool to indicate conformance to the new model.
Also:
- Fixes an existing bug where the initial key down would be sent to the wrong IME system (since it happens before plugin IME starts) by having the render widget track whether a plugin is focused.
- Changes ComplexTextInputPanel to match recent upstream changes.
BUG=70427
TEST=None (plugins have not yet implemented Cocoa IME).
Review URL: http://codereview.chromium.org/6259013
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@72190 0039d316-1c4b-4281-b951-d872f2087c98
24 files changed, 248 insertions, 121 deletions
diff --git a/chrome/browser/renderer_host/render_widget_host.cc b/chrome/browser/renderer_host/render_widget_host.cc index b97923f..8985d44 100644 --- a/chrome/browser/renderer_host/render_widget_host.cc +++ b/chrome/browser/renderer_host/render_widget_host.cc @@ -173,8 +173,10 @@ bool RenderWidgetHost::OnMessageReceived(const IPC::Message &msg) { IPC_MESSAGE_HANDLER(ViewHostMsg_GetScreenInfo, OnMsgGetScreenInfo) IPC_MESSAGE_HANDLER(ViewHostMsg_GetWindowRect, OnMsgGetWindowRect) IPC_MESSAGE_HANDLER(ViewHostMsg_GetRootWindowRect, OnMsgGetRootWindowRect) - IPC_MESSAGE_HANDLER(ViewHostMsg_SetPluginImeEnabled, - OnMsgSetPluginImeEnabled) + IPC_MESSAGE_HANDLER(ViewHostMsg_PluginFocusChanged, + OnMsgPluginFocusChanged) + IPC_MESSAGE_HANDLER(ViewHostMsg_StartPluginIme, + OnMsgStartPluginIme) IPC_MESSAGE_HANDLER(ViewHostMsg_AllocateFakePluginWindowHandle, OnAllocateFakePluginWindowHandle) IPC_MESSAGE_HANDLER(ViewHostMsg_DestroyFakePluginWindowHandle, @@ -1043,8 +1045,12 @@ void RenderWidgetHost::OnMsgGetRootWindowRect(gfx::NativeViewId window_id, } } -void RenderWidgetHost::OnMsgSetPluginImeEnabled(bool enabled, int plugin_id) { - view_->SetPluginImeEnabled(enabled, plugin_id); +void RenderWidgetHost::OnMsgPluginFocusChanged(bool focused, int plugin_id) { + view_->PluginFocusChanged(focused, plugin_id); +} + +void RenderWidgetHost::OnMsgStartPluginIme() { + view_->StartPluginIme(); } void RenderWidgetHost::OnAllocateFakePluginWindowHandle( diff --git a/chrome/browser/renderer_host/render_widget_host.h b/chrome/browser/renderer_host/render_widget_host.h index bfefefa..54fe350 100644 --- a/chrome/browser/renderer_host/render_widget_host.h +++ b/chrome/browser/renderer_host/render_widget_host.h @@ -482,7 +482,8 @@ class RenderWidgetHost : public IPC::Channel::Listener, WebKit::WebScreenInfo* results); void OnMsgGetWindowRect(gfx::NativeViewId window_id, gfx::Rect* results); void OnMsgGetRootWindowRect(gfx::NativeViewId window_id, gfx::Rect* results); - void OnMsgSetPluginImeEnabled(bool enabled, int plugin_id); + void OnMsgPluginFocusChanged(bool focused, int plugin_id); + void OnMsgStartPluginIme(); void OnAllocateFakePluginWindowHandle(bool opaque, bool root, gfx::PluginWindowHandle* id); diff --git a/chrome/browser/renderer_host/render_widget_host_view.h b/chrome/browser/renderer_host/render_widget_host_view.h index c085aab..8da1419 100644 --- a/chrome/browser/renderer_host/render_widget_host_view.h +++ b/chrome/browser/renderer_host/render_widget_host_view.h @@ -208,8 +208,11 @@ class RenderWidgetHostView { // Informs the view that its containing window's frame changed. virtual void WindowFrameChanged() = 0; - // Start or stop plugin IME for the given plugin. - virtual void SetPluginImeEnabled(bool enabled, int plugin_id) = 0; + // Informs the view that a plugin gained or lost focus. + virtual void PluginFocusChanged(bool focused, int plugin_id) = 0; + + // Start plugin IME. + virtual void StartPluginIme() = 0; // Does any event handling necessary for plugin IME; should be called after // the plugin has already had a chance to process the event. If plugin IME is diff --git a/chrome/browser/renderer_host/render_widget_host_view_mac.h b/chrome/browser/renderer_host/render_widget_host_view_mac.h index 0ddfbba..7b18f5c 100644 --- a/chrome/browser/renderer_host/render_widget_host_view_mac.h +++ b/chrome/browser/renderer_host/render_widget_host_view_mac.h @@ -120,8 +120,11 @@ class RWHVMEditCommandHelper; // etc. EditCommands editCommands_; - // The plugin for which IME is currently enabled (-1 if not enabled). - int pluginImeIdentifier_; + // The plugin that currently has focus (-1 if no plugin has focus). + int focusedPluginIdentifier_; + + // Whether or not plugin IME is currently enabled active. + BOOL pluginImeActive_; } @property(assign, nonatomic) NSRect caretRect; @@ -141,8 +144,10 @@ class RWHVMEditCommandHelper; - (void)cancelComposition; // Confirm ongoing composition. - (void)confirmComposition; -// Enables or disables plugin IME for the given plugin. -- (void)setPluginImeEnabled:(BOOL)enabled forPlugin:(int)pluginId; +// Enables or disables plugin IME. +- (void)setPluginImeActive:(BOOL)active; +// Updates the current plugin focus state. +- (void)pluginFocusChanged:(BOOL)focused forPlugin:(int)pluginId; // Evaluates the event in the context of plugin IME, if plugin IME is enabled. // Returns YES if the event was handled. - (BOOL)postProcessEventForPluginIme:(NSEvent*)event; @@ -219,7 +224,8 @@ class RenderWidgetHostViewMac : public RenderWidgetHostView { virtual void OnAccessibilityNotifications( const std::vector<ViewHostMsg_AccessibilityNotification_Params>& params); - virtual void SetPluginImeEnabled(bool enabled, int plugin_id); + virtual void PluginFocusChanged(bool focused, int plugin_id); + virtual void StartPluginIme(); virtual bool PostProcessEventForPluginIme( const NativeWebKeyboardEvent& event); @@ -269,8 +275,8 @@ class RenderWidgetHostViewMac : public RenderWidgetHostView { void SetTextInputActive(bool active); - // Sends confirmed plugin IME text back to the renderer. - void PluginImeCompositionConfirmed(const string16& text, int plugin_id); + // Sends completed plugin IME notification and text back to the renderer. + void PluginImeCompositionCompleted(const string16& text, int plugin_id); const std::string& selected_text() const { return selected_text_; } diff --git a/chrome/browser/renderer_host/render_widget_host_view_mac.mm b/chrome/browser/renderer_host/render_widget_host_view_mac.mm index f93e8b9..f8322ab 100644 --- a/chrome/browser/renderer_host/render_widget_host_view_mac.mm +++ b/chrome/browser/renderer_host/render_widget_host_view_mac.mm @@ -63,6 +63,7 @@ static inline int ToWebKitModifiers(NSUInteger flags) { - (id)initWithRenderWidgetHostViewMac:(RenderWidgetHostViewMac*)r; - (void)keyEvent:(NSEvent *)theEvent wasKeyEquivalent:(BOOL)equiv; - (void)cancelChildPopups; +- (void)checkForPluginImeCancellation; @end // This API was published since 10.6. Provide the declaration so it can be @@ -91,8 +92,8 @@ WebKit::WebColor WebColorFromNSColor(NSColor *color) { std::max(0, std::min(static_cast<int>(lroundf(255.0f * b)), 255)); } -// Extract underline information from an attributed string. -// Mostly copied from third_party/WebKit/Source/WebKit/mac/WebView/WebHTMLView.mm +// Extract underline information from an attributed string. Mostly copied from +// third_party/WebKit/Source/WebKit/mac/WebView/WebHTMLView.mm void ExtractUnderlines( NSAttributedString* string, std::vector<WebKit::WebCompositionUnderline>* underlines) { @@ -881,8 +882,12 @@ void RenderWidgetHostViewMac::KillSelf() { } } -void RenderWidgetHostViewMac::SetPluginImeEnabled(bool enabled, int plugin_id) { - [cocoa_view_ setPluginImeEnabled:(enabled ? YES : NO) forPlugin:plugin_id]; +void RenderWidgetHostViewMac::PluginFocusChanged(bool focused, int plugin_id) { + [cocoa_view_ pluginFocusChanged:(focused ? YES : NO) forPlugin:plugin_id]; +} + +void RenderWidgetHostViewMac::StartPluginIme() { + [cocoa_view_ setPluginImeActive:YES]; } bool RenderWidgetHostViewMac::PostProcessEventForPluginIme( @@ -898,10 +903,10 @@ bool RenderWidgetHostViewMac::PostProcessEventForPluginIme( return false; } -void RenderWidgetHostViewMac::PluginImeCompositionConfirmed( +void RenderWidgetHostViewMac::PluginImeCompositionCompleted( const string16& text, int plugin_id) { if (render_widget_host_) { - render_widget_host_->Send(new ViewMsg_PluginImeCompositionConfirmed( + render_widget_host_->Send(new ViewMsg_PluginImeCompositionCompleted( render_widget_host_->routing_id(), text, plugin_id)); } } @@ -1258,6 +1263,8 @@ void RenderWidgetHostViewMac::SetActive(bool active) { render_widget_host_->SetActive(active); if (HasFocus()) SetTextInputActive(active); + if (!active) + [cocoa_view_ setPluginImeActive:NO]; } void RenderWidgetHostViewMac::SetWindowVisibility(bool visible) { @@ -1331,7 +1338,7 @@ void RenderWidgetHostViewMac::SetTextInputActive(bool active) { canBeKeyView_ = YES; takesFocusOnlyOnMouseDown_ = NO; closeOnDeactivate_ = NO; - pluginImeIdentifier_ = -1; + focusedPluginIdentifier_ = -1; } return self; } @@ -1487,11 +1494,17 @@ void RenderWidgetHostViewMac::SetTextInputActive(bool active) { hasEditCommands_ = NO; editCommands_.clear(); + // Before doing anything with a key down, check to see if plugin IME has been + // cancelled, since the plugin host needs to be informed of that before + // receiving the keydown. + if ([theEvent type] == NSKeyDown) + [self checkForPluginImeCancellation]; + // Sends key down events to input method first, then we can decide what should // be done according to input method's feedback. // If a plugin is active, bypass this step since events are forwarded directly // to the plugin IME. - if (pluginImeIdentifier_ == -1) + if (focusedPluginIdentifier_ == -1) [self interpretKeyEvents:[NSArray arrayWithObject:theEvent]]; handlingKeyDown_ = NO; @@ -2399,7 +2412,7 @@ extern NSString *NSTextInputReplacementRangeAttributeName; // nil when the caret is in non-editable content or password box to avoid // making input methods do their work. - (NSTextInputContext *)inputContext { - if (pluginImeIdentifier_ != -1) + if (focusedPluginIdentifier_ != -1) return [[ComplexTextInputPanel sharedComplexTextInputPanel] inputContext]; switch(renderWidgetHostView_->text_input_type_) { @@ -2632,33 +2645,30 @@ extern NSString *NSTextInputReplacementRangeAttributeName; [self cancelComposition]; } -- (void)setPluginImeEnabled:(BOOL)enabled forPlugin:(int)pluginId { - if ((enabled && pluginId == pluginImeIdentifier_) || - (!enabled && pluginId != pluginImeIdentifier_)) +- (void)setPluginImeActive:(BOOL)active { + if (active == pluginImeActive_) return; - // If IME was already active then either it is being cancelled, or the plugin - // changed; either way the current input needs to be cleared. - if (pluginImeIdentifier_ != -1) - [[ComplexTextInputPanel sharedComplexTextInputPanel] cancelInput]; + pluginImeActive_ = active; + if (!active) { + [[ComplexTextInputPanel sharedComplexTextInputPanel] cancelComposition]; + renderWidgetHostView_->PluginImeCompositionCompleted( + string16(), focusedPluginIdentifier_); + } +} + +- (void)pluginFocusChanged:(BOOL)focused forPlugin:(int)pluginId { + if (focused) + focusedPluginIdentifier_ = pluginId; + else if (focusedPluginIdentifier_ == pluginId) + focusedPluginIdentifier_ = -1; - pluginImeIdentifier_ = enabled ? pluginId : -1; + // Whenever plugin focus changes, plugin IME resets. + [self setPluginImeActive:NO]; } - (BOOL)postProcessEventForPluginIme:(NSEvent*)event { - if (pluginImeIdentifier_ == -1) - return false; - - // ComplexTextInputPanel only works on 10.6+. - static BOOL sImeSupported = NO; - static BOOL sHaveCheckedSupport = NO; - if (!sHaveCheckedSupport) { - int32 major, minor, bugfix; - base::SysInfo::OperatingSystemVersionNumbers(&major, &minor, &bugfix); - sImeSupported = major > 10 || (major == 10 && minor > 5); - sHaveCheckedSupport = YES; - } - if (!sImeSupported) + if (!pluginImeActive_) return false; ComplexTextInputPanel* inputPanel = @@ -2667,12 +2677,22 @@ extern NSString *NSTextInputReplacementRangeAttributeName; BOOL handled = [inputPanel interpretKeyEvent:event string:&composited_string]; if (composited_string) { - renderWidgetHostView_->PluginImeCompositionConfirmed( - base::SysNSStringToUTF16(composited_string), pluginImeIdentifier_); + renderWidgetHostView_->PluginImeCompositionCompleted( + base::SysNSStringToUTF16(composited_string), focusedPluginIdentifier_); + pluginImeActive_ = NO; } return handled; } +- (void)checkForPluginImeCancellation { + if (pluginImeActive_ && + ![[ComplexTextInputPanel sharedComplexTextInputPanel] inComposition]) { + renderWidgetHostView_->PluginImeCompositionCompleted( + string16(), focusedPluginIdentifier_); + pluginImeActive_ = NO; + } +} + - (ViewID)viewID { return VIEW_ID_TAB_CONTAINER_FOCUS_VIEW; } diff --git a/chrome/browser/renderer_host/test/test_render_view_host.cc b/chrome/browser/renderer_host/test/test_render_view_host.cc index 1c2e4b4..4141706 100644 --- a/chrome/browser/renderer_host/test/test_render_view_host.cc +++ b/chrome/browser/renderer_host/test/test_render_view_host.cc @@ -143,8 +143,11 @@ void TestRenderWidgetHostView::SetActive(bool active) { // <viettrungluu@gmail.com>: Do I need to do anything here? } -void TestRenderWidgetHostView::SetPluginImeEnabled(bool enabled, - int plugin_id) { +void TestRenderWidgetHostView::PluginFocusChanged(bool focused, + int plugin_id) { +} + +void TestRenderWidgetHostView::StartPluginIme() { } bool TestRenderWidgetHostView::PostProcessEventForPluginIme( diff --git a/chrome/browser/renderer_host/test/test_render_view_host.h b/chrome/browser/renderer_host/test/test_render_view_host.h index 70f2d11..9ae4d45 100644 --- a/chrome/browser/renderer_host/test/test_render_view_host.h +++ b/chrome/browser/renderer_host/test/test_render_view_host.h @@ -103,7 +103,8 @@ class TestRenderWidgetHostView : public RenderWidgetHostView { virtual void SetActive(bool active); virtual void SetWindowVisibility(bool visible) {} virtual void WindowFrameChanged() {} - virtual void SetPluginImeEnabled(bool enabled, int plugin_id); + virtual void PluginFocusChanged(bool focused, int plugin_id); + virtual void StartPluginIme(); virtual bool PostProcessEventForPluginIme( const NativeWebKeyboardEvent& event); virtual gfx::PluginWindowHandle AllocateFakePluginWindowHandle( diff --git a/chrome/common/plugin_messages_internal.h b/chrome/common/plugin_messages_internal.h index 31eca91..e87ee0b 100644 --- a/chrome/common/plugin_messages_internal.h +++ b/chrome/common/plugin_messages_internal.h @@ -234,7 +234,7 @@ IPC_MESSAGE_ROUTED2(PluginMsg_WindowFrameChanged, gfx::Rect /* window_frame */, gfx::Rect /* view_frame */) -IPC_MESSAGE_ROUTED1(PluginMsg_ImeCompositionConfirmed, +IPC_MESSAGE_ROUTED1(PluginMsg_ImeCompositionCompleted, string16 /* text */) #endif @@ -403,8 +403,10 @@ IPC_MESSAGE_CONTROL0(PluginHostMsg_PluginShuttingDown) IPC_MESSAGE_ROUTED1(PluginHostMsg_UpdateGeometry_ACK, int /* ack_key */) -IPC_MESSAGE_ROUTED1(PluginHostMsg_SetImeEnabled, - bool /* enabled */) +IPC_MESSAGE_ROUTED1(PluginHostMsg_FocusChanged, + bool /* focused */) + +IPC_MESSAGE_ROUTED0(PluginHostMsg_StartIme) // This message, used in Mac OS X 10.5 and earlier, is sent from the plug-in // process to the renderer process to indicate that the plug-in allocated a diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h index 867523a..e3f8af1 100644 --- a/chrome/common/render_messages_internal.h +++ b/chrome/common/render_messages_internal.h @@ -890,8 +890,8 @@ IPC_MESSAGE_ROUTED2(ViewMsg_WindowFrameChanged, gfx::Rect /* window frame */, gfx::Rect /* content view frame */) -// Tell the renderer that text has been retured from plugin IME. -IPC_MESSAGE_ROUTED2(ViewMsg_PluginImeCompositionConfirmed, +// Tell the renderer that plugin IME has completed. +IPC_MESSAGE_ROUTED2(ViewMsg_PluginImeCompositionCompleted, string16 /* text */, int /* plugin_id */) #endif @@ -2145,11 +2145,14 @@ IPC_SYNC_MESSAGE_CONTROL2_1(ViewHostMsg_AllocTransportDIB, IPC_MESSAGE_CONTROL1(ViewHostMsg_FreeTransportDIB, TransportDIB::Id /* DIB id */) -// Instructs the browser to start or stop plugin IME. -IPC_MESSAGE_ROUTED2(ViewHostMsg_SetPluginImeEnabled, - bool, /* enabled */ +// Informs the browser that a plugin has gained or lost focus. +IPC_MESSAGE_ROUTED2(ViewHostMsg_PluginFocusChanged, + bool, /* focused */ int /* plugin_id */) +// Instructs the browser to start plugin IME. +IPC_MESSAGE_ROUTED0(ViewHostMsg_StartPluginIme) + //--------------------------------------------------------------------------- // Messages related to accelerated plugins diff --git a/chrome/plugin/webplugin_delegate_stub.cc b/chrome/plugin/webplugin_delegate_stub.cc index 7e8808c..6b0f39a 100644 --- a/chrome/plugin/webplugin_delegate_stub.cc +++ b/chrome/plugin/webplugin_delegate_stub.cc @@ -125,8 +125,8 @@ bool WebPluginDelegateStub::OnMessageReceived(const IPC::Message& msg) { IPC_MESSAGE_HANDLER(PluginMsg_ContainerHidden, OnContainerHidden) IPC_MESSAGE_HANDLER(PluginMsg_ContainerShown, OnContainerShown) IPC_MESSAGE_HANDLER(PluginMsg_WindowFrameChanged, OnWindowFrameChanged) - IPC_MESSAGE_HANDLER(PluginMsg_ImeCompositionConfirmed, - OnImeCompositionConfirmed) + IPC_MESSAGE_HANDLER(PluginMsg_ImeCompositionCompleted, + OnImeCompositionCompleted) #endif IPC_MESSAGE_HANDLER(PluginMsg_DidReceiveManualResponse, OnDidReceiveManualResponse) @@ -378,9 +378,9 @@ void WebPluginDelegateStub::OnWindowFrameChanged(const gfx::Rect& window_frame, delegate_->WindowFrameChanged(window_frame, view_frame); } -void WebPluginDelegateStub::OnImeCompositionConfirmed(const string16& text) { +void WebPluginDelegateStub::OnImeCompositionCompleted(const string16& text) { if (delegate_) - delegate_->ImeCompositionConfirmed(text); + delegate_->ImeCompositionCompleted(text); } #endif // OS_MACOSX diff --git a/chrome/plugin/webplugin_delegate_stub.h b/chrome/plugin/webplugin_delegate_stub.h index 0a95587..ce99e77 100644 --- a/chrome/plugin/webplugin_delegate_stub.h +++ b/chrome/plugin/webplugin_delegate_stub.h @@ -89,7 +89,7 @@ class WebPluginDelegateStub : public IPC::Channel::Listener, bool has_focus); void OnWindowFrameChanged(const gfx::Rect& window_frame, const gfx::Rect& view_frame); - void OnImeCompositionConfirmed(const string16& text); + void OnImeCompositionCompleted(const string16& text); #endif void OnDidReceiveManualResponse( diff --git a/chrome/plugin/webplugin_proxy.cc b/chrome/plugin/webplugin_proxy.cc index 6448239..de15ce7 100644 --- a/chrome/plugin/webplugin_proxy.cc +++ b/chrome/plugin/webplugin_proxy.cc @@ -653,8 +653,13 @@ void WebPluginProxy::SetDeferResourceLoading(unsigned long resource_id, } #if defined(OS_MACOSX) -void WebPluginProxy::SetImeEnabled(bool enabled) { - IPC::Message* msg = new PluginHostMsg_SetImeEnabled(route_id_, enabled); +void WebPluginProxy::FocusChanged(bool focused) { + IPC::Message* msg = new PluginHostMsg_FocusChanged(route_id_, focused); + Send(msg); +} + +void WebPluginProxy::StartIme() { + IPC::Message* msg = new PluginHostMsg_StartIme(route_id_); // This message can be sent during event-handling, and needs to be delivered // within that context. msg->set_unblock(true); diff --git a/chrome/plugin/webplugin_proxy.h b/chrome/plugin/webplugin_proxy.h index c5a0a1d..acc89ab 100644 --- a/chrome/plugin/webplugin_proxy.h +++ b/chrome/plugin/webplugin_proxy.h @@ -147,7 +147,9 @@ class WebPluginProxy : public webkit::npapi::WebPlugin { gfx::NativeViewId containing_window() { return containing_window_; } #if defined(OS_MACOSX) - virtual void SetImeEnabled(bool enabled); + virtual void FocusChanged(bool focused); + + virtual void StartIme(); virtual void BindFakePluginWindowHandle(bool opaque); diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc index a81aae0..d2f9250 100644 --- a/chrome/renderer/render_view.cc +++ b/chrome/renderer/render_view.cc @@ -1070,8 +1070,8 @@ bool RenderView::OnMessageReceived(const IPC::Message& message) { #if defined(OS_MACOSX) IPC_MESSAGE_HANDLER(ViewMsg_SetWindowVisibility, OnSetWindowVisibility) IPC_MESSAGE_HANDLER(ViewMsg_WindowFrameChanged, OnWindowFrameChanged) - IPC_MESSAGE_HANDLER(ViewMsg_PluginImeCompositionConfirmed, - OnPluginImeCompositionConfirmed) + IPC_MESSAGE_HANDLER(ViewMsg_PluginImeCompositionCompleted, + OnPluginImeCompositionCompleted) #endif IPC_MESSAGE_HANDLER(ViewMsg_SetEditCommandsForNextKeyEvent, OnSetEditCommandsForNextKeyEvent) @@ -5236,14 +5236,14 @@ void RenderView::OnWindowFrameChanged(const gfx::Rect& window_frame, } } -void RenderView::OnPluginImeCompositionConfirmed(const string16& text, +void RenderView::OnPluginImeCompositionCompleted(const string16& text, int plugin_id) { - // WebPluginDelegateProxy is responsible for figuring out if this text + // WebPluginDelegateProxy is responsible for figuring out if this event // applies to it or not, so inform all the delegates. std::set<WebPluginDelegateProxy*>::iterator plugin_it; for (plugin_it = plugin_delegates_.begin(); plugin_it != plugin_delegates_.end(); ++plugin_it) { - (*plugin_it)->ImeCompositionConfirmed(text, plugin_id); + (*plugin_it)->ImeCompositionCompleted(text, plugin_id); } } #endif // OS_MACOSX @@ -5502,9 +5502,14 @@ void RenderView::EnsureDocumentTag() { } #if defined(OS_MACOSX) -void RenderView::SetPluginImeEnabled(bool enabled, int plugin_id) { - IPC::Message* msg = new ViewHostMsg_SetPluginImeEnabled(routing_id(), - enabled, plugin_id); +void RenderView::PluginFocusChanged(bool focused, int plugin_id) { + IPC::Message* msg = new ViewHostMsg_PluginFocusChanged(routing_id(), + focused, plugin_id); + Send(msg); +} + +void RenderView::StartPluginIme() { + IPC::Message* msg = new ViewHostMsg_StartPluginIme(routing_id()); // This message can be sent during event-handling, and needs to be delivered // within that context. msg->set_unblock(true); diff --git a/chrome/renderer/render_view.h b/chrome/renderer/render_view.h index fa357c4..92a3577 100644 --- a/chrome/renderer/render_view.h +++ b/chrome/renderer/render_view.h @@ -352,8 +352,11 @@ class RenderView : public RenderWidget, uint32 GetCPBrowsingContext(); #if defined(OS_MACOSX) - // Enables/disabled plugin IME for the given plugin. - void SetPluginImeEnabled(bool enabled, int plugin_id); + // Informs the render view that the given plugin has gained or lost focus. + void PluginFocusChanged(bool focused, int plugin_id); + + // Starts plugin IME. + void StartPluginIme(); // Helper routines for accelerated plugin support. Used by the // WebPluginDelegateProxy, which has a pointer to the RenderView. @@ -898,7 +901,7 @@ class RenderView : public RenderWidget, void OnNotifyRendererViewType(ViewType::Type view_type); void OnPaste(); #if defined(OS_MACOSX) - void OnPluginImeCompositionConfirmed(const string16& text, int plugin_id); + void OnPluginImeCompositionCompleted(const string16& text, int plugin_id); #endif void OnPrintingDone(int document_cookie, bool success); void OnPrintPages(); diff --git a/chrome/renderer/webplugin_delegate_proxy.cc b/chrome/renderer/webplugin_delegate_proxy.cc index dcfe8c1..e5c50ec 100644 --- a/chrome/renderer/webplugin_delegate_proxy.cc +++ b/chrome/renderer/webplugin_delegate_proxy.cc @@ -457,8 +457,10 @@ bool WebPluginDelegateProxy::OnMessageReceived(const IPC::Message& msg) { OnDeferResourceLoading) #if defined(OS_MACOSX) - IPC_MESSAGE_HANDLER(PluginHostMsg_SetImeEnabled, - OnSetImeEnabled); + IPC_MESSAGE_HANDLER(PluginHostMsg_FocusChanged, + OnFocusChanged); + IPC_MESSAGE_HANDLER(PluginHostMsg_StartIme, + OnStartIme); IPC_MESSAGE_HANDLER(PluginHostMsg_BindFakePluginWindowHandle, OnBindFakePluginWindowHandle); IPC_MESSAGE_HANDLER(PluginHostMsg_UpdateGeometry_ACK, @@ -1016,13 +1018,13 @@ void WebPluginDelegateProxy::WindowFrameChanged(gfx::Rect window_frame, msg->set_unblock(true); Send(msg); } -void WebPluginDelegateProxy::ImeCompositionConfirmed(const string16& text, +void WebPluginDelegateProxy::ImeCompositionCompleted(const string16& text, int plugin_id) { - // If the text isn't intended for this plugin, there's nothing to do. + // If the message isn't intended for this plugin, there's nothing to do. if (instance_id_ != plugin_id) return; - IPC::Message* msg = new PluginMsg_ImeCompositionConfirmed(instance_id_, + IPC::Message* msg = new PluginMsg_ImeCompositionCompleted(instance_id_, text); // Order relative to other key events is important. msg->set_unblock(true); @@ -1376,9 +1378,14 @@ WebPluginDelegateProxy::CreateSeekableResourceClient( } #if defined(OS_MACOSX) -void WebPluginDelegateProxy::OnSetImeEnabled(bool enabled) { +void WebPluginDelegateProxy::OnFocusChanged(bool focused) { if (render_view_) - render_view_->SetPluginImeEnabled(enabled, instance_id_); + render_view_->PluginFocusChanged(focused, instance_id_); +} + +void WebPluginDelegateProxy::OnStartIme() { + if (render_view_) + render_view_->StartPluginIme(); } void WebPluginDelegateProxy::OnBindFakePluginWindowHandle(bool opaque) { diff --git a/chrome/renderer/webplugin_delegate_proxy.h b/chrome/renderer/webplugin_delegate_proxy.h index 49bcc70..0d6eda0 100644 --- a/chrome/renderer/webplugin_delegate_proxy.h +++ b/chrome/renderer/webplugin_delegate_proxy.h @@ -90,8 +90,9 @@ class WebPluginDelegateProxy virtual void SetContainerVisibility(bool is_visible); // Informs the plugin that its enclosing window's frame has changed. virtual void WindowFrameChanged(gfx::Rect window_frame, gfx::Rect view_frame); - // Informs the plugin that text is avaiable from plugin IME. - virtual void ImeCompositionConfirmed(const string16& text, int plugin_id); + // Informs the plugin that plugin IME has completed. + // If |text| is empty, composition was cancelled. + virtual void ImeCompositionCompleted(const string16& text, int plugin_id); #endif // IPC::Channel::Listener implementation: @@ -164,7 +165,8 @@ class WebPluginDelegateProxy void OnDeferResourceLoading(unsigned long resource_id, bool defer); #if defined(OS_MACOSX) - void OnSetImeEnabled(bool enabled); + void OnFocusChanged(bool focused); + void OnStartIme(); void OnBindFakePluginWindowHandle(bool opaque); void OnUpdateGeometry_ACK(int ack_key); void OnAcceleratedSurfaceSetIOSurface(gfx::PluginWindowHandle window, diff --git a/third_party/mozilla/ComplexTextInputPanel.h b/third_party/mozilla/ComplexTextInputPanel.h index 598a2b8..be1d92a 100644 --- a/third_party/mozilla/ComplexTextInputPanel.h +++ b/third_party/mozilla/ComplexTextInputPanel.h @@ -42,7 +42,8 @@ - (NSTextInputContext*)inputContext; - (BOOL)interpretKeyEvent:(NSEvent*)event string:(NSString**)string; -- (void)cancelInput; +- (void)cancelComposition; +- (BOOL)inComposition; @end diff --git a/third_party/mozilla/ComplexTextInputPanel.mm b/third_party/mozilla/ComplexTextInputPanel.mm index 638ed9d..0eb49e2 100644 --- a/third_party/mozilla/ComplexTextInputPanel.mm +++ b/third_party/mozilla/ComplexTextInputPanel.mm @@ -98,8 +98,7 @@ static NSString* const NSTextInputContextKeyboardSelectionDidChangeNotification - (void)keyboardInputSourceChanged:(NSNotification *)notification { - [mInputTextView setString:@""]; - [self orderOut:nil]; + [self cancelComposition]; } - (BOOL)interpretKeyEvent:(NSEvent*)event string:(NSString**)string @@ -129,15 +128,20 @@ static NSString* const NSTextInputContextKeyboardSelectionDidChangeNotification return hadMarkedText; } -- (void)cancelInput +- (NSTextInputContext*)inputContext +{ + return [mInputTextView inputContext]; +} + +- (void)cancelComposition { - [self orderOut:nil]; [mInputTextView setString:@""]; + [self orderOut:nil]; } -- (NSTextInputContext*)inputContext +- (BOOL)inComposition { - return [mInputTextView inputContext]; + return [mInputTextView hasMarkedText]; } @end diff --git a/third_party/mozilla/README.chromium b/third_party/mozilla/README.chromium index 8c66389..4a732d2 100644 --- a/third_party/mozilla/README.chromium +++ b/third_party/mozilla/README.chromium @@ -28,6 +28,5 @@ Although it comes from Mozilla (http://mxr.mozilla.org), it uses the original WebKit license. Local modifitations: -- Added a cancelInput method. - Add #ifdef'd definifitions of a few symbols to support 10.5 SDK. diff --git a/webkit/plugins/npapi/plugin_host.cc b/webkit/plugins/npapi/plugin_host.cc index 53841c3..9aed03b 100644 --- a/webkit/plugins/npapi/plugin_host.cc +++ b/webkit/plugins/npapi/plugin_host.cc @@ -840,6 +840,16 @@ NPError NPN_GetValue(NPP id, NPNVariable variable, void* value) { rv = NPERR_NO_ERROR; break; } + case NPNVsupportsUpdatedCocoaTextInputBool: { + // We support the clarifications to the Cocoa IME event spec, but since + // IME currently only works on 10.6, only answer true there. + NPBool* supports_update = reinterpret_cast<NPBool*>(value); + int32 major, minor, bugfix; + base::SysInfo::OperatingSystemVersionNumbers(&major, &minor, &bugfix); + *supports_update = major > 10 || (major == 10 && minor > 5); + rv = NPERR_NO_ERROR; + break; + } #endif // OS_MACOSX case NPNVPepperExtensions: // Available for any plugin that attempts to get it. diff --git a/webkit/plugins/npapi/webplugin.h b/webkit/plugins/npapi/webplugin.h index c596949..afd2865 100644 --- a/webkit/plugins/npapi/webplugin.h +++ b/webkit/plugins/npapi/webplugin.h @@ -151,8 +151,11 @@ class WebPlugin { bool defer) = 0; #if defined(OS_MACOSX) - // Enables/disables plugin IME. - virtual void SetImeEnabled(bool enabled) {}; + // Called to inform the WebPlugin that the plugin has gained or lost focus. + virtual void FocusChanged(bool focused) {}; + + // Starts plugin IME. + virtual void StartIme() {}; // Synthesize a fake window handle for the plug-in to identify the instance // to the browser, allowing mapping to a surface for hardware accelleration diff --git a/webkit/plugins/npapi/webplugin_delegate_impl.h b/webkit/plugins/npapi/webplugin_delegate_impl.h index 9f64f3a..edb319e 100644 --- a/webkit/plugins/npapi/webplugin_delegate_impl.h +++ b/webkit/plugins/npapi/webplugin_delegate_impl.h @@ -162,8 +162,9 @@ class WebPluginDelegateImpl : public WebPluginDelegate { // Frames are in screen coordinates. void WindowFrameChanged(const gfx::Rect& window_frame, const gfx::Rect& view_frame); - // Informs the plugin that IME composition has been confirmed. - void ImeCompositionConfirmed(const string16& text); + // Informs the plugin that IME composition has completed. + // If |text| is empty, IME was cancelled. + void ImeCompositionCompleted(const string16& text); // Informs the delegate that the plugin set a Carbon ThemeCursor. void SetThemeCursor(ThemeCursor cursor); // Informs the delegate that the plugin set a Carbon Cursor. @@ -391,8 +392,8 @@ class WebPluginDelegateImpl : public WebPluginDelegate { // Updates anything that depends on plugin visibility. void PluginVisibilityChanged(); - // Enables/disables IME. - void SetImeEnabled(bool enabled); + // Starts an IME session. + void StartIme(); // Informs the browser about the updated accelerated drawing surface. void UpdateAcceleratedSurface(); @@ -400,6 +401,9 @@ class WebPluginDelegateImpl : public WebPluginDelegate { // Uses a CARenderer to draw the plug-in's layer in our OpenGL surface. void DrawLayerInSurface(); + // Returns true if plugin IME is supported. + bool IsImeSupported(); + #ifndef NP_NO_CARBON // Moves our dummy window to match the current screen location of the plugin. void UpdateDummyWindowBounds(const gfx::Point& plugin_origin); @@ -446,6 +450,7 @@ class WebPluginDelegateImpl : public WebPluginDelegate { gfx::Rect cached_clip_rect_; bool ime_enabled_; + int keyup_ignore_count_; scoped_ptr<ExternalDragTracker> external_drag_tracker_; #endif // OS_MACOSX diff --git a/webkit/plugins/npapi/webplugin_delegate_impl_mac.mm b/webkit/plugins/npapi/webplugin_delegate_impl_mac.mm index 6d71a35..e43453d 100644 --- a/webkit/plugins/npapi/webplugin_delegate_impl_mac.mm +++ b/webkit/plugins/npapi/webplugin_delegate_impl_mac.mm @@ -17,6 +17,7 @@ #include "base/scoped_ptr.h" #include "base/string_util.h" #include "base/utf_string_conversions.h" +#include "base/sys_info.h" #include "base/sys_string_conversions.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.h" #include "webkit/glue/webkit_glue.h" @@ -266,6 +267,7 @@ WebPluginDelegateImpl::WebPluginDelegateImpl( container_is_visible_(false), have_called_set_window_(false), ime_enabled_(false), + keyup_ignore_count_(0), external_drag_tracker_(new ExternalDragTracker()), handle_event_depth_(0), first_set_window_call_(true), @@ -505,6 +507,21 @@ bool WebPluginDelegateImpl::PlatformHandleInputEvent( current_windowless_cursor_.GetCursorInfo(cursor_info); } + // Per the Cocoa Plugin IME spec, plugins shoudn't receive keydown or keyup + // events while composition is in progress. Treat them as handled, however, + // since IME is consuming them on behalf of the plugin. + if ((event.type == WebInputEvent::KeyDown && ime_enabled_) || + (event.type == WebInputEvent::KeyUp && keyup_ignore_count_)) { + // Composition ends on a keydown, so ime_enabled_ will be false at keyup; + // because the keydown wasn't sent to the plugin, the keyup shouldn't be + // either (per the spec). + if (event.type == WebInputEvent::KeyDown) + ++keyup_ignore_count_; + else + --keyup_ignore_count_; + return true; + } + #ifndef NP_NO_CARBON if (instance()->event_model() == NPEventModelCarbon) { #ifndef NP_NO_QUICKDRAW @@ -585,9 +602,11 @@ bool WebPluginDelegateImpl::PlatformHandleInputEvent( int16_t handle_response = instance()->NPP_HandleEvent(plugin_event); bool handled = handle_response != kNPEventNotHandled; - if (handled && event.type == WebInputEvent::KeyDown) { - // Update IME state as requested by the plugin. - SetImeEnabled(handle_response == kNPEventStartIME); + // Start IME if requested by the plugin. + if (handled && handle_response == kNPEventStartIME && + event.type == WebInputEvent::KeyDown) { + StartIme(); + ++keyup_ignore_count_; } // Plugins don't give accurate information about whether or not they handled @@ -793,9 +812,6 @@ void WebPluginDelegateImpl::SetWindowHasFocus(bool has_focus) { return; containing_window_has_focus_ = has_focus; - if (!has_focus) - SetImeEnabled(false); - #ifndef NP_NO_QUICKDRAW // Make sure controls repaint with the correct look. if (quirks_ & PLUGIN_QUIRK_ALLOW_FASTER_QUICKDRAW_PATH) @@ -832,8 +848,7 @@ bool WebPluginDelegateImpl::PlatformSetPluginHasFocus(bool focused) { if (!have_called_set_window_) return false; - if (!focused) - SetImeEnabled(false); + plugin_->FocusChanged(focused); ScopedActiveDelegate active_delegate(this); @@ -899,18 +914,24 @@ void WebPluginDelegateImpl::WindowFrameChanged(const gfx::Rect& window_frame, SetContentAreaOrigin(gfx::Point(view_frame.x(), view_frame.y())); } -void WebPluginDelegateImpl::ImeCompositionConfirmed(const string16& text) { +void WebPluginDelegateImpl::ImeCompositionCompleted(const string16& text) { if (instance()->event_model() != NPEventModelCocoa) { - DLOG(ERROR) << "IME text receieved in Carbon event model"; + DLOG(ERROR) << "IME notification receieved in Carbon event model"; return; } - NPCocoaEvent text_event; - memset(&text_event, 0, sizeof(NPCocoaEvent)); - text_event.type = NPCocoaEventTextInput; - text_event.data.text.text = - reinterpret_cast<NPNSString*>(base::SysUTF16ToNSString(text)); - instance()->NPP_HandleEvent(&text_event); + ime_enabled_ = false; + + // If |text| is empty this was just called to tell us composition was + // cancelled externally (e.g., the user pressed esc). + if (!text.empty()) { + NPCocoaEvent text_event; + memset(&text_event, 0, sizeof(NPCocoaEvent)); + text_event.type = NPCocoaEventTextInput; + text_event.data.text.text = + reinterpret_cast<NPNSString*>(base::SysUTF16ToNSString(text)); + instance()->NPP_HandleEvent(&text_event); + } } void WebPluginDelegateImpl::SetThemeCursor(ThemeCursor cursor) { @@ -971,13 +992,28 @@ void WebPluginDelegateImpl::PluginVisibilityChanged() { } } -void WebPluginDelegateImpl::SetImeEnabled(bool enabled) { - if (instance()->event_model() != NPEventModelCocoa) +void WebPluginDelegateImpl::StartIme() { + if (instance()->event_model() != NPEventModelCocoa || + !IsImeSupported()) { return; - if (enabled == ime_enabled_) + } + if (ime_enabled_) return; - ime_enabled_ = enabled; - plugin_->SetImeEnabled(enabled); + ime_enabled_ = true; + plugin_->StartIme(); +} + +bool WebPluginDelegateImpl::IsImeSupported() { + // Currently the plugin IME implementation only works on 10.6. + static BOOL sImeSupported = NO; + static BOOL sHaveCheckedSupport = NO; + if (!sHaveCheckedSupport) { + int32 major, minor, bugfix; + base::SysInfo::OperatingSystemVersionNumbers(&major, &minor, &bugfix); + sImeSupported = major > 10 || (major == 10 && minor > 5); + sHaveCheckedSupport = YES; + } + return sImeSupported; } #pragma mark - |