diff options
24 files changed, 465 insertions, 14 deletions
diff --git a/chrome/browser/renderer_host/render_widget_host.cc b/chrome/browser/renderer_host/render_widget_host.cc index 7d4aa79f..a6efd58 100644 --- a/chrome/browser/renderer_host/render_widget_host.cc +++ b/chrome/browser/renderer_host/render_widget_host.cc @@ -168,6 +168,8 @@ void 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_AllocateFakePluginWindowHandle, OnAllocateFakePluginWindowHandle) IPC_MESSAGE_HANDLER(ViewHostMsg_DestroyFakePluginWindowHandle, @@ -1006,6 +1008,10 @@ void RenderWidgetHost::OnMsgGetRootWindowRect(gfx::NativeViewId window_id, } } +void RenderWidgetHost::OnMsgSetPluginImeEnabled(bool enabled, int plugin_id) { + view_->SetPluginImeEnabled(enabled, plugin_id); +} + void RenderWidgetHost::OnAllocateFakePluginWindowHandle( bool opaque, bool root, @@ -1209,6 +1215,11 @@ void RenderWidgetHost::ProcessKeyboardEventAck(int type, bool processed) { NativeWebKeyboardEvent front_item = key_queue_.front(); key_queue_.pop_front(); +#if defined(OS_MACOSX) + if (!is_hidden_ && view_->PostProcessEventForPluginIme(front_item)) + return; +#endif + // We only send unprocessed key event upwards if we are not hidden, // because the user has moved away from us and no longer expect any effect // of this key event. diff --git a/chrome/browser/renderer_host/render_widget_host.h b/chrome/browser/renderer_host/render_widget_host.h index f4e0b96..6c3fed7 100644 --- a/chrome/browser/renderer_host/render_widget_host.h +++ b/chrome/browser/renderer_host/render_widget_host.h @@ -499,6 +499,7 @@ 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 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 86c2abc..46d6bda 100644 --- a/chrome/browser/renderer_host/render_widget_host_view.h +++ b/chrome/browser/renderer_host/render_widget_host_view.h @@ -32,6 +32,7 @@ class RenderProcessHost; class RenderWidgetHost; class VideoLayer; class WebCursor; +struct NativeWebKeyboardEvent; struct ViewHostMsg_AccessibilityNotification_Params; struct WebMenuItem; @@ -211,6 +212,16 @@ 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; + + // 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 + // not enabled, this is a no-op, so it is always safe to call. + // Returns true if the event was handled by IME. + virtual bool PostProcessEventForPluginIme( + const NativeWebKeyboardEvent& event) = 0; + // Methods associated with GPU-accelerated plug-in instances. virtual gfx::PluginWindowHandle AllocateFakePluginWindowHandle( bool opaque, bool root) = 0; 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 f41ae8d..b9e41f9 100644 --- a/chrome/browser/renderer_host/render_widget_host_view_mac.h +++ b/chrome/browser/renderer_host/render_widget_host_view_mac.h @@ -124,6 +124,9 @@ class RWHVMEditCommandHelper; // handling a key down event, not including inserting commands, eg. insertTab, // etc. EditCommands editCommands_; + + // The plugin for which IME is currently enabled (-1 if not enabled). + int pluginImeIdentifier_; } @property(assign, nonatomic) NSRect caretRect; @@ -145,6 +148,11 @@ class RWHVMEditCommandHelper; - (void)setAccessibilityTreeRoot:(BrowserAccessibility*) treeRoot; // Confirm ongoing composition. - (void)confirmComposition; +// Enables or disables plugin IME for the given plugin. +- (void)setPluginImeEnabled:(BOOL)enabled 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; @end @@ -224,6 +232,10 @@ class RenderWidgetHostViewMac : public RenderWidgetHostView { virtual void OnAccessibilityNotifications( const std::vector<ViewHostMsg_AccessibilityNotification_Params>& params); + virtual void SetPluginImeEnabled(bool enabled, int plugin_id); + virtual bool PostProcessEventForPluginIme( + const NativeWebKeyboardEvent& event); + // Methods associated with GPU-accelerated plug-in instances and the // accelerated compositor. virtual gfx::PluginWindowHandle AllocateFakePluginWindowHandle(bool opaque, @@ -263,6 +275,9 @@ 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); + const std::string& selected_text() const { return selected_text_; } // These member variables should be private, but the associated ObjC class 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 ce0f8c0..a27fbcd 100644 --- a/chrome/browser/renderer_host/render_widget_host_view_mac.mm +++ b/chrome/browser/renderer_host/render_widget_host_view_mac.mm @@ -15,6 +15,7 @@ #import "base/scoped_nsautorelease_pool.h" #import "base/scoped_nsobject.h" #include "base/string_util.h" +#include "base/sys_info.h" #include "base/sys_string_conversions.h" #include "chrome/browser/browser_thread.h" #include "chrome/browser/browser_trial.h" @@ -38,6 +39,7 @@ #include "webkit/glue/plugins/webplugin.h" #include "webkit/glue/webaccessibility.h" #include "webkit/glue/webmenurunner_mac.h" +#import "third_party/mozilla/ComplexTextInputPanel.h" using WebKit::WebInputEvent; using WebKit::WebInputEventFactory; @@ -58,7 +60,6 @@ static inline int ToWebKitModifiers(NSUInteger flags) { - (id)initWithRenderWidgetHostViewMac:(RenderWidgetHostViewMac*)r; - (void)keyEvent:(NSEvent *)theEvent wasKeyEquivalent:(BOOL)equiv; - (void)cancelChildPopups; -- (void)attachPluginLayer; @end // This API was published since 10.6. Provide the declaration so it can be @@ -890,6 +891,31 @@ void RenderWidgetHostViewMac::KillSelf() { } } +void RenderWidgetHostViewMac::SetPluginImeEnabled(bool enabled, int plugin_id) { + [cocoa_view_ setPluginImeEnabled:(enabled ? YES : NO) forPlugin:plugin_id]; +} + +bool RenderWidgetHostViewMac::PostProcessEventForPluginIme( + const NativeWebKeyboardEvent& event) { + // Check WebInputEvent type since multiple types of events can be sent into + // WebKit for the same OS event (e.g., RawKeyDown and Char), so filtering is + // necessary to avoid double processing. + // Also check the native type, since NSFlagsChanged is considered a key event + // for WebKit purposes, but isn't considered a key event by the OS. + if (event.type == WebInputEvent::RawKeyDown && + [event.os_event type] == NSKeyDown) + return [cocoa_view_ postProcessEventForPluginIme:event.os_event]; + return false; +} + +void RenderWidgetHostViewMac::PluginImeCompositionConfirmed( + const string16& text, int plugin_id) { + if (render_widget_host_) { + render_widget_host_->Send(new ViewMsg_PluginImeCompositionConfirmed( + render_widget_host_->routing_id(), text, plugin_id)); + } +} + gfx::PluginWindowHandle RenderWidgetHostViewMac::AllocateFakePluginWindowHandle(bool opaque, bool root) { @@ -1194,6 +1220,7 @@ void RenderWidgetHostViewMac::SetTextInputActive(bool active) { canBeKeyView_ = YES; takesFocusOnlyOnMouseDown_ = NO; closeOnDeactivate_ = NO; + pluginImeIdentifier_ = -1; } return self; } @@ -1351,7 +1378,10 @@ void RenderWidgetHostViewMac::SetTextInputActive(bool active) { // Sends key down events to input method first, then we can decide what should // be done according to input method's feedback. - [self interpretKeyEvents:[NSArray arrayWithObject:theEvent]]; + // If a plugin is active, bypass this step since events are forwarded directly + // to the plugin IME. + if (pluginImeIdentifier_ == -1) + [self interpretKeyEvents:[NSArray arrayWithObject:theEvent]]; handlingKeyDown_ = NO; @@ -2239,6 +2269,9 @@ 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) + return [[ComplexTextInputPanel sharedComplexTextInputPanel] inputContext]; + switch(renderWidgetHostView_->text_input_type_) { case WebKit::WebTextInputTypeNone: case WebKit::WebTextInputTypePassword: @@ -2469,6 +2502,46 @@ extern NSString *NSTextInputReplacementRangeAttributeName; [self cancelComposition]; } +- (void)setPluginImeEnabled:(BOOL)enabled forPlugin:(int)pluginId { + if ((enabled && pluginId == pluginImeIdentifier_) || + (!enabled && pluginId != pluginImeIdentifier_)) + 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]; + + pluginImeIdentifier_ = enabled ? pluginId : -1; +} + +- (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); + } + if (!sImeSupported) + return false; + + ComplexTextInputPanel* inputPanel = + [ComplexTextInputPanel sharedComplexTextInputPanel]; + NSString* composited_string = nil; + BOOL handled = [inputPanel interpretKeyEvent:event + string:&composited_string]; + if (composited_string) { + renderWidgetHostView_->PluginImeCompositionConfirmed( + base::SysNSStringToUTF16(composited_string), pluginImeIdentifier_); + } + return handled; +} + - (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 70d6a9c..ecc2426 100644 --- a/chrome/browser/renderer_host/test/test_render_view_host.cc +++ b/chrome/browser/renderer_host/test/test_render_view_host.cc @@ -143,6 +143,15 @@ void TestRenderWidgetHostView::SetActive(bool active) { // <viettrungluu@gmail.com>: Do I need to do anything here? } +void TestRenderWidgetHostView::SetPluginImeEnabled(bool enabled, + int plugin_id) { +} + +bool TestRenderWidgetHostView::PostProcessEventForPluginIme( + const NativeWebKeyboardEvent& event) { + return false; +} + gfx::PluginWindowHandle TestRenderWidgetHostView::AllocateFakePluginWindowHandle( bool opaque, 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 2312ba3..e3c9f39 100644 --- a/chrome/browser/renderer_host/test/test_render_view_host.h +++ b/chrome/browser/renderer_host/test/test_render_view_host.h @@ -101,6 +101,9 @@ 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 bool PostProcessEventForPluginIme( + const NativeWebKeyboardEvent& event); virtual gfx::PluginWindowHandle AllocateFakePluginWindowHandle( bool opaque, bool root); diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index bcfca8ce..7d77275 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -3496,6 +3496,8 @@ '../third_party/mozilla/NSURL+Utils.m', '../third_party/mozilla/NSWorkspace+Utils.h', '../third_party/mozilla/NSWorkspace+Utils.m', + '../third_party/mozilla/ComplexTextInputPanel.h', + '../third_party/mozilla/ComplexTextInputPanel.mm', # Headers so that IB can find classes it needs to resolve classes # in XIB files. '../base/chrome_application_mac.h', diff --git a/chrome/common/plugin_messages_internal.h b/chrome/common/plugin_messages_internal.h index 99e265a..a83b41a 100644 --- a/chrome/common/plugin_messages_internal.h +++ b/chrome/common/plugin_messages_internal.h @@ -238,6 +238,9 @@ IPC_BEGIN_MESSAGES(Plugin) IPC_MESSAGE_ROUTED2(PluginMsg_WindowFrameChanged, gfx::Rect /* window_frame */, gfx::Rect /* view_frame */) + + IPC_MESSAGE_ROUTED1(PluginMsg_ImeCompositionConfirmed, + string16 /* text */) #endif IPC_SYNC_MESSAGE_ROUTED2_0(PluginMsg_WillSendRequest, @@ -402,6 +405,9 @@ IPC_BEGIN_MESSAGES(PluginHost) IPC_MESSAGE_ROUTED1(PluginHostMsg_UpdateGeometry_ACK, int /* ack_key */) + IPC_MESSAGE_ROUTED1(PluginHostMsg_SetImeEnabled, + bool /* enabled */) + // 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 // new TransportDIB that holds the GPU's rendered image. This information is diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h index 1307799..1cfa70b3 100644 --- a/chrome/common/render_messages_internal.h +++ b/chrome/common/render_messages_internal.h @@ -851,6 +851,11 @@ IPC_BEGIN_MESSAGES(View) 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, + string16 /* text */, + int /* plugin_id */) #endif // Response message to ViewHostMsg_CreateShared/DedicatedWorker. @@ -2148,8 +2153,13 @@ IPC_BEGIN_MESSAGES(ViewHost) 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 */ + int /* plugin_id */) + //--------------------------------------------------------------------------- - // Messages related to the GPU plugin on Mac OS X 10.6 and later + // Messages related to accelerated plugins // This is sent from the renderer to the browser to allocate a fake // PluginWindowHandle on the browser side which is used to identify diff --git a/chrome/plugin/webplugin_delegate_stub.cc b/chrome/plugin/webplugin_delegate_stub.cc index 39282a1..cb6af0d 100644 --- a/chrome/plugin/webplugin_delegate_stub.cc +++ b/chrome/plugin/webplugin_delegate_stub.cc @@ -122,6 +122,8 @@ void 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) #endif IPC_MESSAGE_HANDLER(PluginMsg_DidReceiveManualResponse, OnDidReceiveManualResponse) @@ -367,6 +369,11 @@ void WebPluginDelegateStub::OnWindowFrameChanged(const gfx::Rect& window_frame, if (delegate_) delegate_->WindowFrameChanged(window_frame, view_frame); } + +void WebPluginDelegateStub::OnImeCompositionConfirmed(const string16& text) { + if (delegate_) + delegate_->ImeCompositionConfirmed(text); +} #endif // OS_MACOSX void WebPluginDelegateStub::OnDidReceiveManualResponse( diff --git a/chrome/plugin/webplugin_delegate_stub.h b/chrome/plugin/webplugin_delegate_stub.h index 0c1101e..5bc2887 100644 --- a/chrome/plugin/webplugin_delegate_stub.h +++ b/chrome/plugin/webplugin_delegate_stub.h @@ -85,6 +85,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); #endif void OnDidReceiveManualResponse( diff --git a/chrome/plugin/webplugin_proxy.cc b/chrome/plugin/webplugin_proxy.cc index 5ec1b43..9741393 100644 --- a/chrome/plugin/webplugin_proxy.cc +++ b/chrome/plugin/webplugin_proxy.cc @@ -648,6 +648,14 @@ 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); + // This message can be sent during event-handling, and needs to be delivered + // within that context. + msg->set_unblock(true); + Send(msg); +} + void WebPluginProxy::BindFakePluginWindowHandle(bool opaque) { Send(new PluginHostMsg_BindFakePluginWindowHandle(route_id_, opaque)); } diff --git a/chrome/plugin/webplugin_proxy.h b/chrome/plugin/webplugin_proxy.h index 2134bf3..bf0b705 100644 --- a/chrome/plugin/webplugin_proxy.h +++ b/chrome/plugin/webplugin_proxy.h @@ -141,6 +141,8 @@ class WebPluginProxy : public webkit_glue::WebPlugin { gfx::NativeViewId containing_window() { return containing_window_; } #if defined(OS_MACOSX) + virtual void SetImeEnabled(bool enabled); + virtual void BindFakePluginWindowHandle(bool opaque); virtual webkit_glue::WebPluginAcceleratedSurface* GetAcceleratedSurface(); diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc index 0ca3650..125e4d5 100644 --- a/chrome/renderer/render_view.cc +++ b/chrome/renderer/render_view.cc @@ -789,6 +789,8 @@ void 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) #endif IPC_MESSAGE_HANDLER(ViewMsg_SetEditCommandsForNextKeyEvent, OnSetEditCommandsForNextKeyEvent) @@ -4872,6 +4874,17 @@ void RenderView::OnWindowFrameChanged(const gfx::Rect& window_frame, (*plugin_it)->WindowFrameChanged(window_frame, view_frame); } } + +void RenderView::OnPluginImeCompositionConfirmed(const string16& text, + int plugin_id) { + // WebPluginDelegateProxy is responsible for figuring out if this text + // 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); + } +} #endif // OS_MACOSX void RenderView::SendExtensionRequest( @@ -5794,6 +5807,15 @@ 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); + // This message can be sent during event-handling, and needs to be delivered + // within that context. + msg->set_unblock(true); + Send(msg); +} + gfx::PluginWindowHandle RenderView::AllocateFakePluginWindowHandle( bool opaque, bool root) { gfx::PluginWindowHandle window = NULL; diff --git a/chrome/renderer/render_view.h b/chrome/renderer/render_view.h index 95766c1..360b24d 100644 --- a/chrome/renderer/render_view.h +++ b/chrome/renderer/render_view.h @@ -304,7 +304,10 @@ class RenderView : public RenderWidget, uint32 GetCPBrowsingContext(); #if defined(OS_MACOSX) - // Helper routines for GPU plugin support. Used by the + // Enables/disabled plugin IME for the given plugin. + void SetPluginImeEnabled(bool enabled, int plugin_id); + + // Helper routines for accelerated plugin support. Used by the // WebPluginDelegateProxy, which has a pointer to the RenderView. gfx::PluginWindowHandle AllocateFakePluginWindowHandle(bool opaque, bool root); @@ -824,6 +827,9 @@ class RenderView : public RenderWidget, void OnFillPasswordForm( const webkit_glue::PasswordFormFillData& form_data); void OnPaste(); +#if defined(OS_MACOSX) + void OnPluginImeCompositionConfirmed(const string16& text, int plugin_id); +#endif void OnPrintingDone(int document_cookie, bool success); void OnPrintPages(); void OnRedo(); diff --git a/chrome/renderer/webplugin_delegate_proxy.cc b/chrome/renderer/webplugin_delegate_proxy.cc index 708bbc9..f4229ff 100644 --- a/chrome/renderer/webplugin_delegate_proxy.cc +++ b/chrome/renderer/webplugin_delegate_proxy.cc @@ -462,6 +462,8 @@ void WebPluginDelegateProxy::OnMessageReceived(const IPC::Message& msg) { OnDeferResourceLoading) #if defined(OS_MACOSX) + IPC_MESSAGE_HANDLER(PluginHostMsg_SetImeEnabled, + OnSetImeEnabled); IPC_MESSAGE_HANDLER(PluginHostMsg_BindFakePluginWindowHandle, OnBindFakePluginWindowHandle); IPC_MESSAGE_HANDLER(PluginHostMsg_UpdateGeometry_ACK, @@ -1015,6 +1017,18 @@ void WebPluginDelegateProxy::WindowFrameChanged(gfx::Rect window_frame, msg->set_unblock(true); Send(msg); } +void WebPluginDelegateProxy::ImeCompositionConfirmed(const string16& text, + int plugin_id) { + // If the text 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_, + text); + // Order relative to other key events is important. + msg->set_unblock(true); + Send(msg); +} #endif // OS_MACOSX void WebPluginDelegateProxy::OnSetWindow(gfx::PluginWindowHandle window) { @@ -1363,6 +1377,11 @@ WebPluginDelegateProxy::CreateSeekableResourceClient( } #if defined(OS_MACOSX) +void WebPluginDelegateProxy::OnSetImeEnabled(bool enabled) { + if (render_view_) + render_view_->SetPluginImeEnabled(enabled, instance_id_); +} + void WebPluginDelegateProxy::OnBindFakePluginWindowHandle(bool opaque) { BindFakePluginWindowHandle(opaque); } diff --git a/chrome/renderer/webplugin_delegate_proxy.h b/chrome/renderer/webplugin_delegate_proxy.h index 0cabc1b..204cf4d 100644 --- a/chrome/renderer/webplugin_delegate_proxy.h +++ b/chrome/renderer/webplugin_delegate_proxy.h @@ -88,6 +88,8 @@ 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); #endif // IPC::Channel::Listener implementation: @@ -160,6 +162,7 @@ class WebPluginDelegateProxy void OnDeferResourceLoading(unsigned long resource_id, bool defer); #if defined(OS_MACOSX) + void OnSetImeEnabled(bool enabled); 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 new file mode 100644 index 0000000..598a2b8 --- /dev/null +++ b/third_party/mozilla/ComplexTextInputPanel.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2009 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Modified by Josh Aas of Mozilla Corporation. + */ + +#ifndef ComplexTextInputPanel_h_ +#define ComplexTextInputPanel_h_ + +#import <Cocoa/Cocoa.h> + +#if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5 +@class NSTextInputContext; +#endif + +@interface ComplexTextInputPanel : NSPanel { + NSTextView *mInputTextView; +} + ++ (ComplexTextInputPanel*)sharedComplexTextInputPanel; + +- (NSTextInputContext*)inputContext; +- (BOOL)interpretKeyEvent:(NSEvent*)event string:(NSString**)string; +- (void)cancelInput; + +@end + +#endif // ComplexTextInputPanel_h_ diff --git a/third_party/mozilla/ComplexTextInputPanel.mm b/third_party/mozilla/ComplexTextInputPanel.mm new file mode 100644 index 0000000..638ed9d --- /dev/null +++ b/third_party/mozilla/ComplexTextInputPanel.mm @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2009 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Modified by Josh Aas of Mozilla Corporation. + */ + +#import "ComplexTextInputPanel.h" + +#if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5 +@interface NSView (SnowLeopardMethods) +- (NSTextInputContext *)inputContext; +@end + +// This is actually an NSTextInputContext method, but we can't declare +// that since the whole class is 10.6+. +@interface NSObject (SnowLeopardMethods) +- (BOOL)handleEvent:(NSEvent *)theEvent; +@end + +static NSString* const NSTextInputContextKeyboardSelectionDidChangeNotification = + @"NSTextInputContextKeyboardSelectionDidChangeNotification"; +#endif + +#define kInputWindowHeight 20 + +@implementation ComplexTextInputPanel + ++ (ComplexTextInputPanel*)sharedComplexTextInputPanel +{ + static ComplexTextInputPanel *sComplexTextInputPanel; + if (!sComplexTextInputPanel) + sComplexTextInputPanel = [[ComplexTextInputPanel alloc] init]; + return sComplexTextInputPanel; +} + +- (id)init +{ + // In the original Apple code the style mask is given by a function which is not open source. + // What could possibly be worth hiding in that function, I do not know. + // Courtesy of gdb: stylemask: 011000011111, 0x61f + self = [super initWithContentRect:NSZeroRect styleMask:0x61f backing:NSBackingStoreBuffered defer:YES]; + if (!self) + return nil; + + // Set the frame size. + NSRect visibleFrame = [[NSScreen mainScreen] visibleFrame]; + NSRect frame = NSMakeRect(visibleFrame.origin.x, visibleFrame.origin.y, visibleFrame.size.width, kInputWindowHeight); + + [self setFrame:frame display:NO]; + + mInputTextView = [[NSTextView alloc] initWithFrame:[self.contentView frame]]; + mInputTextView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable | NSViewMaxXMargin | NSViewMinXMargin | NSViewMaxYMargin | NSViewMinYMargin; + + NSScrollView* scrollView = [[NSScrollView alloc] initWithFrame:[self.contentView frame]]; + scrollView.documentView = mInputTextView; + self.contentView = scrollView; + [scrollView release]; + + [self setFloatingPanel:YES]; + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(keyboardInputSourceChanged:) + name:NSTextInputContextKeyboardSelectionDidChangeNotification + object:nil]; + + return self; +} + +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; + + [mInputTextView release]; + + [super dealloc]; +} + +- (void)keyboardInputSourceChanged:(NSNotification *)notification +{ + [mInputTextView setString:@""]; + [self orderOut:nil]; +} + +- (BOOL)interpretKeyEvent:(NSEvent*)event string:(NSString**)string +{ + BOOL hadMarkedText = [mInputTextView hasMarkedText]; + + *string = nil; + + if (![[mInputTextView inputContext] handleEvent:event]) + return NO; + + if ([mInputTextView hasMarkedText]) { + // Don't show the input method window for dead keys + if ([[event characters] length] > 0) + [self orderFront:nil]; + + return YES; + } else { + [self orderOut:nil]; + + NSString *text = [[mInputTextView textStorage] string]; + if ([text length] > 0) + *string = [[text copy] autorelease]; + } + + [mInputTextView setString:@""]; + return hadMarkedText; +} + +- (void)cancelInput +{ + [self orderOut:nil]; + [mInputTextView setString:@""]; +} + +- (NSTextInputContext*)inputContext +{ + return [mInputTextView inputContext]; +} + +@end diff --git a/third_party/mozilla/README.chromium b/third_party/mozilla/README.chromium index fe93bb8..8c66389 100644 --- a/third_party/mozilla/README.chromium +++ b/third_party/mozilla/README.chromium @@ -20,3 +20,14 @@ Local modifications: -[NSPasteboard getURLs:andTitles:] to determine whether or not filenames in the drag should be converted to file URLs. -[NSPasteboard htmlFromRtf] added to do rtf->html conversion. + +----------------------------------------------------------------- + +Also includes IME panel from Gecko, which is based on WebKit's implementation. +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/glue/plugins/webplugin.h b/webkit/glue/plugins/webplugin.h index 1a14d545..36426fa 100644 --- a/webkit/glue/plugins/webplugin.h +++ b/webkit/glue/plugins/webplugin.h @@ -149,6 +149,9 @@ class WebPlugin { bool defer) = 0; #if defined(OS_MACOSX) + // Enables/disables plugin IME. + virtual void SetImeEnabled(bool enabled) {}; + // Synthesize a fake window handle for the plug-in to identify the instance // to the browser, allowing mapping to a surface for hardware accelleration // of plug-in content. The browser generates the handle which is then set on diff --git a/webkit/glue/plugins/webplugin_delegate_impl.h b/webkit/glue/plugins/webplugin_delegate_impl.h index 55381f9..30a4a58 100644 --- a/webkit/glue/plugins/webplugin_delegate_impl.h +++ b/webkit/glue/plugins/webplugin_delegate_impl.h @@ -161,6 +161,8 @@ class WebPluginDelegateImpl : public webkit_glue::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 delegate that the plugin set a Carbon ThemeCursor. void SetThemeCursor(ThemeCursor cursor); // Informs the delegate that the plugin set a Carbon Cursor. @@ -385,20 +387,15 @@ class WebPluginDelegateImpl : public webkit_glue::WebPluginDelegate { void SetContentAreaOrigin(const gfx::Point& origin); // Updates everything that depends on the plugin's absolute screen location. void PluginScreenLocationChanged(); + // Updates anything that depends on plugin visibility. + void PluginVisibilityChanged(); - // Returns the apparent zoom ratio for the given event, as inferred from our - // current knowledge about about where on screen the plugin is. - // This is a temporary workaround for <http://crbug.com/9996>; once that is - // fixed we should have correct event coordinates (or an explicit - // notification of zoom level). - float ApparentEventZoomLevel(const WebKit::WebMouseEvent& event); + // Enables/disables IME. + void SetImeEnabled(bool enabled); // Informs the browser about the updated accelerated drawing surface. void UpdateAcceleratedSurface(); - // Updates anything that depends on plugin visibility. - void PluginVisibilityChanged(); - // Uses a CARenderer to draw the plug-in's layer in our OpenGL surface. void DrawLayerInSurface(); @@ -447,6 +444,8 @@ class WebPluginDelegateImpl : public webkit_glue::WebPluginDelegate { gfx::Rect cached_clip_rect_; + bool ime_enabled_; + scoped_ptr<ExternalDragTracker> external_drag_tracker_; #endif // OS_MACOSX diff --git a/webkit/glue/plugins/webplugin_delegate_impl_mac.mm b/webkit/glue/plugins/webplugin_delegate_impl_mac.mm index b7e7702..cca8695 100644 --- a/webkit/glue/plugins/webplugin_delegate_impl_mac.mm +++ b/webkit/glue/plugins/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_string_conversions.h" #include "third_party/WebKit/WebKit/chromium/public/WebInputEvent.h" #include "webkit/glue/plugins/plugin_instance.h" #include "webkit/glue/plugins/plugin_lib.h" @@ -263,6 +264,7 @@ WebPluginDelegateImpl::WebPluginDelegateImpl( initial_window_focus_(false), container_is_visible_(false), have_called_set_window_(false), + ime_enabled_(false), external_drag_tracker_(new ExternalDragTracker()), handle_event_depth_(0), first_set_window_call_(true), @@ -573,7 +575,13 @@ bool WebPluginDelegateImpl::PlatformHandleInputEvent( event_scope.reset(new NPAPI::ScopedCurrentPluginEvent( instance(), static_cast<NPCocoaEvent*>(plugin_event))); } - bool handled = instance()->NPP_HandleEvent(plugin_event) != 0; + 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); + } // Plugins don't give accurate information about whether or not they handled // events, so browsers on the Mac ignore the return value. @@ -778,6 +786,9 @@ 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) @@ -814,6 +825,9 @@ bool WebPluginDelegateImpl::PlatformSetPluginHasFocus(bool focused) { if (!have_called_set_window_) return false; + if (!focused) + SetImeEnabled(false); + ScopedActiveDelegate active_delegate(this); switch (instance()->event_model()) { @@ -878,6 +892,20 @@ void WebPluginDelegateImpl::WindowFrameChanged(const gfx::Rect& window_frame, SetContentAreaOrigin(gfx::Point(view_frame.x(), view_frame.y())); } +void WebPluginDelegateImpl::ImeCompositionConfirmed(const string16& text) { + if (instance()->event_model() != NPEventModelCocoa) { + DLOG(ERROR) << "IME text 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); +} + void WebPluginDelegateImpl::SetThemeCursor(ThemeCursor cursor) { current_windowless_cursor_.InitFromThemeCursor(cursor); } @@ -936,6 +964,15 @@ void WebPluginDelegateImpl::PluginVisibilityChanged() { } } +void WebPluginDelegateImpl::SetImeEnabled(bool enabled) { + if (instance()->event_model() != NPEventModelCocoa) + return; + if (enabled == ime_enabled_) + return; + ime_enabled_ = enabled; + plugin_->SetImeEnabled(enabled); +} + #pragma mark - #pragma mark Core Animation Support |