diff options
author | amanda@chromium.org <amanda@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-11-06 17:08:36 +0000 |
---|---|---|
committer | amanda@chromium.org <amanda@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-11-06 17:08:36 +0000 |
commit | 7b032aa6098222270f9f78ede822e1256e672a08 (patch) | |
tree | 5779eb59f8d492cd3943bcefde6ebafa6778f6b7 /webkit/glue | |
parent | 6b6db57f06b8610f211d7fd8e5122447adf1fa71 (diff) | |
download | chromium_src-7b032aa6098222270f9f78ede822e1256e672a08.zip chromium_src-7b032aa6098222270f9f78ede822e1256e672a08.tar.gz chromium_src-7b032aa6098222270f9f78ede822e1256e672a08.tar.bz2 |
Implement the Cocoa event model for Mac NPAPI. This is a first cut for the
Google Earth plugin engineers to experiment with, though it's not specific to
that plugin. Note that the Google Earth plugin still doesn't draw correctly
with this patch--we need some help from the Earth team for that, but at least
it will negotiate the event model). Other plugins that use the Cocoa event
model may work as a result, but I haven't found any in the wild so far that
don't also depend on the CoreAnimation drawing model (which is not yet
implemented).
BUG=16443
TEST=The latest Google Earth plugin should load if you add #geplugin_browserok to the URL.
Review URL: http://codereview.chromium.org/355044
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@31240 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/glue')
-rw-r--r-- | webkit/glue/plugins/plugin_host.cc | 5 | ||||
-rw-r--r-- | webkit/glue/plugins/webplugin_delegate_impl_mac.mm | 269 |
2 files changed, 214 insertions, 60 deletions
diff --git a/webkit/glue/plugins/plugin_host.cc b/webkit/glue/plugins/plugin_host.cc index efd84af..e9f8f3d 100644 --- a/webkit/glue/plugins/plugin_host.cc +++ b/webkit/glue/plugins/plugin_host.cc @@ -846,6 +846,7 @@ NPError NPN_GetValue(NPP id, NPNVariable variable, void *value) { } case NPNVsupportsCoreGraphicsBool: case NPNVsupportsCarbonBool: + case NPNVsupportsCocoaBool: { // we do support these drawing and event models. NPBool* supports_model = reinterpret_cast<NPBool*>(value); @@ -855,7 +856,6 @@ NPError NPN_GetValue(NPP id, NPNVariable variable, void *value) { } case NPNVsupportsOpenGLBool: case NPNVsupportsCoreAnimationBool: - case NPNVsupportsCocoaBool: { // we do not support these drawing and event models. NPBool* supports_model = reinterpret_cast<NPBool*>(value); @@ -947,10 +947,11 @@ NPError NPN_SetValue(NPP id, NPPVariable variable, void *value) { } case NPPVpluginEventModel: { - // we only support the Carbon event model + // we support Carbon and Cocoa event models int model = reinterpret_cast<int>(value); switch (model) { case NPNVsupportsCarbonBool: + case NPNVsupportsCocoaBool: plugin->set_event_model(model); return NPERR_NO_ERROR; break; diff --git a/webkit/glue/plugins/webplugin_delegate_impl_mac.mm b/webkit/glue/plugins/webplugin_delegate_impl_mac.mm index d51e4fc..a2f7459 100644 --- a/webkit/glue/plugins/webplugin_delegate_impl_mac.mm +++ b/webkit/glue/plugins/webplugin_delegate_impl_mac.mm @@ -42,6 +42,7 @@ using WebKit::WebCursorInfo; using WebKit::WebKeyboardEvent; using WebKit::WebInputEvent; using WebKit::WebMouseEvent; +using WebKit::WebMouseWheelEvent; // Important implementation notes: The Mac definition of NPAPI, particularly // the distinction between windowed and windowless modes, differs from the @@ -184,10 +185,12 @@ bool WebPluginDelegateImpl::Initialize(const GURL& url, plugin->SetWindow(NULL); plugin_url_ = url.spec(); - MessageLoop::current()->PostDelayedTask(FROM_HERE, - null_event_factory_.NewRunnableMethod( - &WebPluginDelegateImpl::OnNullEvent), - kPluginIdleThrottleDelayMs); + // If the plugin wants Carbon events, fire up a source of idle events. + if (instance_->event_model() == NPEventModelCarbon) { + MessageLoop::current()->PostDelayedTask(FROM_HERE, + null_event_factory_.NewRunnableMethod( + &WebPluginDelegateImpl::OnNullEvent), kPluginIdleThrottleDelayMs); + } return true; } @@ -314,8 +317,7 @@ void WebPluginDelegateImpl::DidManualLoadFail() { } void WebPluginDelegateImpl::InstallMissingPlugin() { - NPEvent evt; - instance()->NPP_HandleEvent(&evt); + NOTIMPLEMENTED(); } void WebPluginDelegateImpl::WindowlessUpdateGeometry( @@ -347,8 +349,7 @@ void WebPluginDelegateImpl::WindowlessPaint(gfx::NativeDrawingContext context, switch (instance()->drawing_model()) { #ifndef NP_NO_QUICKDRAW - case NPDrawingModelQuickDraw: - { + case NPDrawingModelQuickDraw: { // Plugins using the QuickDraw drawing model do not restrict their // drawing to update events the way that CoreGraphics-based plugins // do. When we are asked to paint, we therefore just copy from the @@ -376,29 +377,31 @@ void WebPluginDelegateImpl::WindowlessPaint(gfx::NativeDrawingContext context, break; } #endif - case NPDrawingModelCoreGraphics: - { - NPEvent paint_event; - - // Save and restore the NSGraphicsContext state in case the plugin uses - // Cocoa drawing. - [NSGraphicsContext saveGraphicsState]; - [NSGraphicsContext setCurrentContext: - [NSGraphicsContext graphicsContextWithGraphicsPort:context - flipped:YES]]; + case NPDrawingModelCoreGraphics: { CGContextSaveGState(context); - - paint_event.what = updateEvt; - paint_event.message = reinterpret_cast<uint32>(cg_context_.window); - paint_event.when = TickCount(); - paint_event.where.h = 0; - paint_event.where.v = 0; - paint_event.modifiers = 0; - instance()->NPP_HandleEvent(&paint_event); - + switch (instance()->event_model()) { + case NPEventModelCarbon: { + NPEvent paint_event = { 0 }; + paint_event.what = updateEvt; + paint_event.message = reinterpret_cast<uint32>(cg_context_.window); + paint_event.when = TickCount(); + instance()->NPP_HandleEvent(&paint_event); + break; + } + case NPEventModelCocoa: { + NPCocoaEvent paint_event; + memset(&paint_event, 0, sizeof(NPCocoaEvent)); + paint_event.type = NPCocoaEventDrawRect; + paint_event.data.draw.context = context; + paint_event.data.draw.x = damage_rect.x(); + paint_event.data.draw.y = damage_rect.y(); + paint_event.data.draw.width = damage_rect.width(); + paint_event.data.draw.height = damage_rect.height(); + instance()->NPP_HandleEvent(reinterpret_cast<NPEvent*>(&paint_event)); + break; + } + } CGContextRestoreGState(context); - [NSGraphicsContext restoreGraphicsState]; - break; } } } @@ -455,10 +458,23 @@ void WebPluginDelegateImpl::WindowlessSetWindow(bool force_set_window) { } void WebPluginDelegateImpl::SetFocus() { - NPEvent focus_event = { 0 }; - focus_event.what = NPEventType_GetFocusEvent; - focus_event.when = TickCount(); - instance()->NPP_HandleEvent(&focus_event); + switch (instance()->event_model()) { + case NPEventModelCarbon: { + NPEvent focus_event = { 0 }; + focus_event.what = NPEventType_GetFocusEvent; + focus_event.when = TickCount(); + instance()->NPP_HandleEvent(&focus_event); + break; + } + case NPEventModelCocoa: { + NPCocoaEvent focus_event; + memset(&focus_event, 0, sizeof(focus_event)); + focus_event.type = NPCocoaEventFocusChanged; + focus_event.data.focus.hasFocus = true; + instance()->NPP_HandleEvent(reinterpret_cast<NPEvent*>(&focus_event)); + break; + } + } } static bool WebInputEventIsWebMouseEvent(const WebInputEvent& event) { @@ -583,6 +599,114 @@ static bool NPEventFromWebInputEvent(const WebInputEvent& event, return false; } + +static bool NPCocoaEventFromWebMouseEvent(const WebMouseEvent& event, + NPCocoaEvent *np_cocoa_event) { + np_cocoa_event->data.mouse.pluginX = event.x; + np_cocoa_event->data.mouse.pluginY = event.y; + + if (event.modifiers & WebInputEvent::ControlKey) + np_cocoa_event->data.mouse.modifierFlags |= controlKey; + if (event.modifiers & WebInputEvent::ShiftKey) + np_cocoa_event->data.mouse.modifierFlags |= shiftKey; + + np_cocoa_event->data.mouse.clickCount = event.clickCount; + switch (event.button) { + case WebMouseEvent::ButtonLeft: + np_cocoa_event->data.mouse.buttonNumber = 0; + break; + case WebMouseEvent::ButtonMiddle: + np_cocoa_event->data.mouse.buttonNumber = 2; + break; + case WebMouseEvent::ButtonRight: + np_cocoa_event->data.mouse.buttonNumber = 1; + break; + default: + np_cocoa_event->data.mouse.buttonNumber = event.button; + break; + } + switch (event.type) { + case WebInputEvent::MouseDown: + np_cocoa_event->type = NPCocoaEventMouseDown; + return true; + case WebInputEvent::MouseUp: + np_cocoa_event->type = NPCocoaEventMouseUp; + return true; + case WebInputEvent::MouseMove: + np_cocoa_event->type = NPCocoaEventMouseMoved; + return true; + case WebInputEvent::MouseEnter: + np_cocoa_event->type = NPCocoaEventMouseEntered; + return true; + case WebInputEvent::MouseLeave: + np_cocoa_event->type = NPCocoaEventMouseExited; + return true; + default: + NOTREACHED(); + return false; + } +} + +static bool NPCocoaEventFromWebMouseWheelEvent(const WebMouseWheelEvent& event, + NPCocoaEvent *np_cocoa_event) { + np_cocoa_event->type = NPCocoaEventScrollWheel; + np_cocoa_event->data.mouse.pluginX = event.x; + np_cocoa_event->data.mouse.pluginY = event.y; + if (event.modifiers & WebInputEvent::ControlKey) + np_cocoa_event->data.mouse.modifierFlags |= controlKey; + if (event.modifiers & WebInputEvent::ShiftKey) + np_cocoa_event->data.mouse.modifierFlags |= shiftKey; + np_cocoa_event->data.mouse.deltaX = event.deltaX; + np_cocoa_event->data.mouse.deltaY = event.deltaY; + return true; +} + +static bool NPCocoaEventFromWebKeyboardEvent(const WebKeyboardEvent& event, + NPCocoaEvent *np_cocoa_event) { + np_cocoa_event->data.key.keyCode = event.nativeKeyCode; + + if (event.modifiers & WebInputEvent::ControlKey) + np_cocoa_event->data.key.modifierFlags |= controlKey; + if (event.modifiers & WebInputEvent::ShiftKey) + np_cocoa_event->data.key.modifierFlags |= shiftKey; + if (event.modifiers & WebInputEvent::AltKey) + np_cocoa_event->data.key.modifierFlags |= cmdKey; + if (event.modifiers & WebInputEvent::MetaKey) + np_cocoa_event->data.key.modifierFlags |= optionKey; + + if (event.modifiers & WebInputEvent::IsAutoRepeat) + np_cocoa_event->data.key.isARepeat = true; + + switch (event.type) { + case WebInputEvent::KeyDown: + np_cocoa_event->type = NPCocoaEventKeyDown; + return true; + case WebInputEvent::KeyUp: + np_cocoa_event->type = NPCocoaEventKeyUp; + return true; + default: + NOTREACHED(); + return false; + } +} + +static bool NPCocoaEventFromWebInputEvent(const WebInputEvent& event, + NPCocoaEvent *np_cocoa_event) { + memset(np_cocoa_event, 0, sizeof(NPCocoaEvent)); + if (event.type == WebInputEvent::MouseWheel) { + return NPCocoaEventFromWebMouseWheelEvent( + *static_cast<const WebMouseWheelEvent*>(&event), np_cocoa_event); + } else if (WebInputEventIsWebMouseEvent(event)) { + return NPCocoaEventFromWebMouseEvent( + *static_cast<const WebMouseEvent*>(&event), np_cocoa_event); + } else if (WebInputEventIsWebKeyboardEvent(event)) { + return NPCocoaEventFromWebKeyboardEvent( + *static_cast<const WebKeyboardEvent*>(&event), np_cocoa_event); + } + DLOG(WARNING) << "unknown event type " << event.type; + return false; +} + static void UpdateWindowLocation(WindowRef window, const WebMouseEvent& event) { // TODO: figure out where the vertical offset of 22 comes from (and if 22 is // exactly right) and replace with an appropriate calculation. It feels like @@ -602,6 +726,7 @@ bool WebPluginDelegateImpl::HandleInputEvent(const WebInputEvent& event, DCHECK(windowless_) << "events should only be received in windowless mode"; DCHECK(cursor != NULL); +#ifndef NP_NO_CARBON NPEvent np_event = {0}; if (!NPEventFromWebInputEvent(event, &np_event)) { LOG(WARNING) << "NPEventFromWebInputEvent failed"; @@ -611,18 +736,21 @@ bool WebPluginDelegateImpl::HandleInputEvent(const WebInputEvent& event, if (np_event.what == nullEvent) { last_mouse_x_ = np_event.where.h; last_mouse_y_ = np_event.where.v; - return true; // Let the recurring task actually send the event. + if (instance()->event_model() == NPEventModelCarbon) + return true; // Let the recurring task actually send the event. + } else { + // If this is a mouse event, we need to make sure our dummy window + // has the correct location before we send the event to the plugin, + // so that any coordinate conversion the plugin does will work out. + if (WebInputEventIsWebMouseEvent(event)) { + const WebMouseEvent* mouse_event = + static_cast<const WebMouseEvent*>(&event); + UpdateWindowLocation(reinterpret_cast<WindowRef>(cg_context_.window), + *mouse_event); + } } +#endif - // If this is a mouse event, we need to make sure our dummy window has the - // correct location before we send the event to the plugin, so that any - // coordinate conversion the plugin does will work out. - if (WebInputEventIsWebMouseEvent(event)) { - const WebMouseEvent* mouse_event = - static_cast<const WebMouseEvent*>(&event); - UpdateWindowLocation(reinterpret_cast<WindowRef>(cg_context_.window), - *mouse_event); - } bool ret = false; switch (instance()->drawing_model()) { #ifndef NP_NO_QUICKDRAW @@ -633,7 +761,24 @@ bool WebPluginDelegateImpl::HandleInputEvent(const WebInputEvent& event, #endif case NPDrawingModelCoreGraphics: CGContextSaveGState(cg_context_.context); - ret = instance()->NPP_HandleEvent(&np_event) != 0; + switch (instance()->event_model()) { +#ifndef NP_NO_CARBON + case NPEventModelCarbon: + // Send the event to the plugin. + ret = instance()->NPP_HandleEvent(&np_event) != 0; + break; +#endif + case NPEventModelCocoa: { + NPCocoaEvent np_cocoa_event; + if (!NPCocoaEventFromWebInputEvent(event, &np_cocoa_event)) { + LOG(WARNING) << "NPCocoaEventFromWebInputEvent failed"; + return false; + } + ret = instance()->NPP_HandleEvent( + reinterpret_cast<NPEvent*>(&np_cocoa_event)) != 0; + break; + } + } CGContextRestoreGState(cg_context_.context); break; } @@ -662,6 +807,7 @@ WebPluginResourceClient* WebPluginDelegateImpl::CreateResourceClient( } void WebPluginDelegateImpl::OnNullEvent() { +#ifndef NP_NO_CARBON if (!webkit_glue::IsPluginRunningInRendererProcess()) { switch (instance_->event_model()) { case NPEventModelCarbon: @@ -680,16 +826,19 @@ void WebPluginDelegateImpl::OnNullEvent() { } } - // Send an idle event so that the plugin can do background work - NPEvent np_event = {0}; - np_event.what = nullEvent; - np_event.when = TickCount(); - np_event.modifiers = GetCurrentKeyModifiers(); - if (!Button()) - np_event.modifiers |= btnState; - np_event.where.h = last_mouse_x_; - np_event.where.v = last_mouse_y_; - instance()->NPP_HandleEvent(&np_event); + if (instance_->event_model() == NPEventModelCarbon) { + // Send an idle event so that the plugin can do background work + NPEvent np_event = {0}; + np_event.what = nullEvent; + np_event.when = TickCount(); + np_event.modifiers = GetCurrentKeyModifiers(); + if (!Button()) + np_event.modifiers |= btnState; + np_event.where.h = last_mouse_x_; + np_event.where.v = last_mouse_y_; + instance()->NPP_HandleEvent(&np_event); + } +#endif #ifndef NP_NO_QUICKDRAW // Quickdraw-based plugins can draw at any time, so tell the renderer to @@ -700,8 +849,12 @@ void WebPluginDelegateImpl::OnNullEvent() { instance()->webplugin()->Invalidate(); #endif - MessageLoop::current()->PostDelayedTask(FROM_HERE, - null_event_factory_.NewRunnableMethod( - &WebPluginDelegateImpl::OnNullEvent), - kPluginIdleThrottleDelayMs); +#ifndef NP_NO_CARBON + if (instance_->event_model() == NPEventModelCarbon) { + MessageLoop::current()->PostDelayedTask(FROM_HERE, + null_event_factory_.NewRunnableMethod( + &WebPluginDelegateImpl::OnNullEvent), + kPluginIdleThrottleDelayMs); + } +#endif } |