diff options
author | amanda@chromium.org <amanda@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-07-11 01:57:28 +0000 |
---|---|---|
committer | amanda@chromium.org <amanda@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-07-11 01:57:28 +0000 |
commit | 6bf1a81cdfcc48f20cf53c2601f4456f2d9d30ef (patch) | |
tree | 7bedf19228a20b83189ab96e617e72210991c7c4 /webkit/glue | |
parent | 7e05f6c4baad4f81e06835b83febe2784568ebe1 (diff) | |
download | chromium_src-6bf1a81cdfcc48f20cf53c2601f4456f2d9d30ef.zip chromium_src-6bf1a81cdfcc48f20cf53c2601f4456f2d9d30ef.tar.gz chromium_src-6bf1a81cdfcc48f20cf53c2601f4456f2d9d30ef.tar.bz2 |
Wire up windowless plugins. Mostly Mac related, some cross
platform aspects.
BUG=10809
TEST=none
Review URL: http://codereview.chromium.org/113637
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@20453 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/glue')
-rw-r--r-- | webkit/glue/plugins/plugin_host.cc | 24 | ||||
-rw-r--r-- | webkit/glue/plugins/webplugin_delegate_impl.h | 4 | ||||
-rw-r--r-- | webkit/glue/plugins/webplugin_delegate_impl_mac.mm | 375 |
3 files changed, 236 insertions, 167 deletions
diff --git a/webkit/glue/plugins/plugin_host.cc b/webkit/glue/plugins/plugin_host.cc index 2e1c233..40b2e1e 100644 --- a/webkit/glue/plugins/plugin_host.cc +++ b/webkit/glue/plugins/plugin_host.cc @@ -600,22 +600,19 @@ void NPN_InvalidateRect(NPP id, NPRect *invalidRect) { DCHECK(plugin.get() != NULL); if (plugin.get() && plugin->webplugin()) { if (invalidRect) { - if (!plugin->windowless()) { #if defined(OS_WIN) + if (!plugin->windowless()) { RECT rect = {0}; rect.left = invalidRect->left; rect.right = invalidRect->right; rect.top = invalidRect->top; rect.bottom = invalidRect->bottom; ::InvalidateRect(plugin->window_handle(), &rect, FALSE); -#elif defined(OS_MACOSX) - NOTIMPLEMENTED(); -#else - NOTIMPLEMENTED(); -#endif return; } - +#elif defined(OS_LINUX) + NOTIMPLEMENTED(); +#endif gfx::Rect rect(invalidRect->left, invalidRect->top, invalidRect->right - invalidRect->left, @@ -633,8 +630,13 @@ void NPN_InvalidateRegion(NPP id, NPRegion invalidRegion) { // // Similar to NPN_InvalidateRect. - // TODO: implement me - DLOG(INFO) << "NPN_InvalidateRegion is not implemented yet."; + // TODO: this is overkill--add platform-specific region handling (at the + // very least, fetch the region's bounding box and pass it to InvalidateRect). + scoped_refptr<NPAPI::PluginInstance> plugin = FindInstance(id); + DCHECK(plugin.get() != NULL); + if (plugin.get() && plugin->webplugin()) { + plugin->webplugin()->Invalidate(); + } } void NPN_ForceRedraw(NPP id) { @@ -652,10 +654,8 @@ void NPN_ForceRedraw(NPP id) { // settings. The HDC settings must be restored whenever control returns // back to the browser, either before returning from NPP_HandleEvent or // before calling a drawing-related netscape method. - // - // TODO: implement me - DLOG(INFO) << "NPN_ForceRedraw is not implemented yet."; + NOTIMPLEMENTED(); } NPError NPN_GetValue(NPP id, NPNVariable variable, void *value) { diff --git a/webkit/glue/plugins/webplugin_delegate_impl.h b/webkit/glue/plugins/webplugin_delegate_impl.h index a6f0715..35302dc7 100644 --- a/webkit/glue/plugins/webplugin_delegate_impl.h +++ b/webkit/glue/plugins/webplugin_delegate_impl.h @@ -95,6 +95,7 @@ class WebPluginDelegateImpl : public WebPluginDelegate { NPAPI::PluginInstance *instance); ~WebPluginDelegateImpl(); +#if !defined(OS_MACOSX) //-------------------------- // used for windowed plugins void WindowedUpdateGeometry(const gfx::Rect& window_rect, @@ -115,6 +116,7 @@ class WebPluginDelegateImpl : public WebPluginDelegate { // Tells the plugin about the current state of the window. // See NPAPI NPP_SetWindow for more information. void WindowedSetWindow(); +#endif #if defined(OS_WIN) // Registers the window class for our window @@ -153,10 +155,10 @@ class WebPluginDelegateImpl : public WebPluginDelegate { // Closes down and destroys our plugin instance. void DestroyInstance(); +#if !defined(OS_MACOSX) // used for windowed plugins gfx::PluginWindowHandle windowed_handle_; bool windowed_did_set_window_; -#if defined(OS_WIN) gfx::Rect windowed_last_pos_; #endif diff --git a/webkit/glue/plugins/webplugin_delegate_impl_mac.mm b/webkit/glue/plugins/webplugin_delegate_impl_mac.mm index 414d635..9232fca 100644 --- a/webkit/glue/plugins/webplugin_delegate_impl_mac.mm +++ b/webkit/glue/plugins/webplugin_delegate_impl_mac.mm @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#import <Cocoa/Cocoa.h> + #include "config.h" #include "webkit/glue/plugins/webplugin_delegate_impl.h" @@ -29,31 +31,27 @@ using WebKit::WebKeyboardEvent; using WebKit::WebInputEvent; using WebKit::WebMouseEvent; -namespace { +// Important implementation notes: The Mac definition of NPAPI, particularly +// the distinction between windowed and windowless modes, differs from the +// Windows and Linux definitions. Most of those differences are +// accomodated by the WebPluginDelegate class. -const wchar_t kWebPluginDelegateProperty[] = L"WebPluginDelegateProperty"; -const wchar_t kPluginNameAtomProperty[] = L"PluginNameAtom"; -const wchar_t kDummyActivationWindowName[] = L"DummyWindowForActivation"; -const wchar_t kPluginOrigProc[] = L"OriginalPtr"; -const wchar_t kPluginFlashThrottle[] = L"FlashThrottle"; +namespace { -// The fastest we are willing to process WM_USER+1 events for Flash. +// The fastest we are willing to process idle events for Flash. // Flash can easily exceed the limits of our CPU if we don't throttle it. // The throttle has been chosen by testing various delays and compromising // on acceptable Flash performance and reasonable CPU consumption. // -// I'd like to make the throttle delay variable, based on the amount of +// We'd like to make the throttle delay variable, based on the amount of // time currently required to paint Flash plugins. There isn't a good // way to count the time spent in aggregate plugin painting, however, so // this seems to work well enough. -const int kFlashWMUSERMessageThrottleDelayMs = 5; +const int kFlashIdleThrottleDelayMs = 20; // 20ms (50Hz) // The current instance of the plugin which entered the modal loop. WebPluginDelegateImpl* g_current_plugin_instance = NULL; -// base::LazyInstance<std::list<MSG> > g_throttle_queue(base::LINKER_INITIALIZED); - - } // namespace WebPluginDelegate* WebPluginDelegate::Create( @@ -81,27 +79,20 @@ WebPluginDelegateImpl::WebPluginDelegateImpl( instance_(instance), quirks_(0), plugin_(NULL), - windowless_(false), - windowed_handle_(NULL), - windowed_did_set_window_(false), + // all Mac plugins are "windowless" in the Windows/X11 sense + windowless_(true), windowless_needs_set_window_(true), handle_event_depth_(0), user_gesture_message_posted_(this), user_gesture_msg_factory_(this) { memset(&window_, 0, sizeof(window_)); - - const WebPluginInfo& plugin_info = instance_->plugin_lib()->plugin_info(); - std::string filename = - StringToLowerASCII(plugin_info.path.BaseName().value()); - - // plugin_module_handle_ = ::GetModuleHandle(plugin_info.path.value().c_str()); } WebPluginDelegateImpl::~WebPluginDelegateImpl() { DestroyInstance(); - if (!windowless_) - WindowedDestroyWindow(); + if (cg_context_.window) + DisposeWindow(cg_context_.window); } void WebPluginDelegateImpl::PluginDestroyed() { @@ -128,20 +119,11 @@ bool WebPluginDelegateImpl::Initialize(const GURL& url, if (!start_result) return false; - windowless_ = instance_->windowless(); - if (windowless_) { - // For windowless plugins we should set the containing window handle - // as the instance window handle. This is what Safari does. Not having - // a valid window handle causes subtle bugs with plugins which retreive - // the window handle and validate the same. The window handle can be - // retreived via NPN_GetValue of NPNVnetscapeWindow. - // instance_->set_window_handle(parent_); - } else { - if (!WindowedCreatePlugin()) - return false; - } + cg_context_.window = NULL; + window_.window = &cg_context_; + window_.type = NPWindowTypeDrawable; - // plugin->SetWindow(windowed_handle_); + plugin->SetWindow(NULL); plugin_url_ = url.spec(); return true; @@ -154,18 +136,8 @@ void WebPluginDelegateImpl::DestroyInstance() { // this before calling set_web_plugin(NULL) because the // instance uses the helper to do the download. instance_->CloseStreams(); - - window_.window = NULL; - instance_->NPP_SetWindow(&window_); - instance_->NPP_Destroy(); - instance_->set_web_plugin(NULL); - - if (instance_->plugin_lib()) { - // Unpatch if this is the last plugin instance. - } - instance_ = 0; } } @@ -173,11 +145,36 @@ void WebPluginDelegateImpl::DestroyInstance() { void WebPluginDelegateImpl::UpdateGeometry( const gfx::Rect& window_rect, const gfx::Rect& clip_rect) { - if (windowless_) { - WindowlessUpdateGeometry(window_rect, clip_rect); - } else { - WindowedUpdateGeometry(window_rect, clip_rect); + + if (!window_rect.IsEmpty()) { + NSPoint windowOffset = {0.0, 0.0}; + Rect window_bounds; + window_bounds.top = window_rect.y() + windowOffset.y; + window_bounds.left = window_rect.x() + windowOffset.x; + window_bounds.bottom = window_rect.y() + window_rect.height(); + window_bounds.right = window_rect.x() + window_rect.width(); + + if (!cg_context_.window) { + // For all plugins we create a placeholder offscreen window for the use + // of NPWindow. NPAPI on the Mac requires a Carbon WindowRef for the + // "browser window", even if we're not using the Quickdraw drawing model. + // Not having a valid window reference causes subtle bugs with plugins + // which retreive the NPWindow and validate the same. The NPWindow + // can be retreived via NPN_GetValue of NPNVnetscapeWindow. + + WindowRef window_ref; + if (CreateNewWindow(kDocumentWindowClass, + kWindowStandardDocumentAttributes, + &window_bounds, + &window_ref) == noErr) { + cg_context_.window = window_ref; + } + } else { + SetWindowBounds(cg_context_.window, kWindowContentRgn, &window_bounds); + } } + + WindowlessUpdateGeometry(window_rect, clip_rect); } void WebPluginDelegateImpl::Paint(CGContextRef context, const gfx::Rect& rect) { @@ -218,12 +215,6 @@ void WebPluginDelegateImpl::SendJavaScriptStream(const std::string& url, void WebPluginDelegateImpl::DidReceiveManualResponse( const std::string& url, const std::string& mime_type, const std::string& headers, uint32 expected_length, uint32 last_modified) { - if (!windowless_) { - // Calling NPP_WriteReady before NPP_SetWindow causes movies to not load in - // Flash. See http://b/issue?id=892174. - DCHECK(windowed_did_set_window_); - } - instance()->DidReceiveManualResponse(url, mime_type, headers, expected_length, last_modified); } @@ -250,91 +241,6 @@ void WebPluginDelegateImpl::InstallMissingPlugin() { instance()->NPP_HandleEvent(&evt); } -void WebPluginDelegateImpl::WindowedUpdateGeometry( - const gfx::Rect& window_rect, - const gfx::Rect& clip_rect) { - if (WindowedReposition(window_rect, clip_rect) || - !windowed_did_set_window_) { - // Let the plugin know that it has been moved - WindowedSetWindow(); - } -} - -bool WebPluginDelegateImpl::WindowedCreatePlugin() { - DCHECK(!windowed_handle_); - - // create window - if (windowed_handle_ == 0) - return false; - - return true; -} - -void WebPluginDelegateImpl::WindowedDestroyWindow() { - if (windowed_handle_ != NULL) { - // destroy the window - windowed_handle_ = 0; - } -} - -bool WebPluginDelegateImpl::WindowedReposition( - const gfx::Rect& window_rect, - const gfx::Rect& clip_rect) { - if (!windowed_handle_) { - NOTREACHED(); - return false; - } - - if (window_rect_ == window_rect && clip_rect_ == clip_rect) - return false; - - // Clipping is handled by WebPlugin. - if (window_rect.size() != window_rect_.size()) { - // resize window - } - - window_rect_ = window_rect; - clip_rect_ = clip_rect; - - // Ensure that the entire window gets repainted. - // invalidate entire window - - return true; -} - -void WebPluginDelegateImpl::WindowedSetWindow() { - if (!instance_) - return; - - if (!windowed_handle_) { - NOTREACHED(); - return; - } - - // instance()->set_window_handle(windowed_handle_); - - DCHECK(!instance()->windowless()); - - window_.clipRect.top = clip_rect_.y(); - window_.clipRect.left = clip_rect_.x(); - window_.clipRect.bottom = clip_rect_.y() + clip_rect_.height(); - window_.clipRect.right = clip_rect_.x() + clip_rect_.width(); - window_.height = window_rect_.height(); - window_.width = window_rect_.width(); - window_.x = window_rect_.x(); - window_.y = window_rect_.y(); - - cg_context_.context = NULL; - cg_context_.window = NULL; - window_.window = &cg_context_; - window_.type = NPWindowTypeDrawable; // NPWindowTypeWindow; - - // Reset this flag before entering the instance in case of side-effects. - windowed_did_set_window_ = true; - - NPError err = instance()->NPP_SetWindow(&window_); -} - void WebPluginDelegateImpl::WindowlessUpdateGeometry( const gfx::Rect& window_rect, const gfx::Rect& clip_rect) { @@ -349,20 +255,72 @@ void WebPluginDelegateImpl::WindowlessUpdateGeometry( if (window_rect_ != window_rect) { window_rect_ = window_rect; - WindowlessSetWindow(true); - - NPEvent pos_changed_event; - - instance()->NPP_HandleEvent(&pos_changed_event); + window_.clipRect.top = clip_rect_.y(); + window_.clipRect.left = clip_rect_.x(); + window_.clipRect.bottom = clip_rect_.y() + clip_rect_.height(); + window_.clipRect.right = clip_rect_.x() + clip_rect_.width(); + window_.height = window_rect_.height(); + window_.width = window_rect_.width(); + window_.x = window_rect_.x(); + window_.y = window_rect_.y(); + window_.type = NPWindowTypeDrawable; + windowless_needs_set_window_ = true; } } -void WebPluginDelegateImpl::WindowlessPaint(gfx::NativeDrawingContext hdc, +void WebPluginDelegateImpl::WindowlessPaint(gfx::NativeDrawingContext context, const gfx::Rect& damage_rect) { static StatsRate plugin_paint("Plugin.Paint"); StatsScope<StatsRate> scope(plugin_paint); + + // We save and restore the NSGraphicsContext state in case the plugin uses + // Cocoa drawing. + [NSGraphicsContext saveGraphicsState]; + [NSGraphicsContext setCurrentContext:[NSGraphicsContext + graphicsContextWithGraphicsPort:context + flipped:NO]]; + + CGContextSaveGState(context); + cg_context_.context = context; + window_.window = &cg_context_; + window_.type = NPWindowTypeDrawable; + if (windowless_needs_set_window_) { + Rect window_bounds; + window_bounds.top = window_rect_.y(); + window_bounds.left = window_rect_.x(); + window_bounds.bottom = window_rect_.y() + window_rect_.height(); + window_bounds.right = window_rect_.x() + window_rect_.width(); + if (!cg_context_.window) { + // For all plugins we create a placeholder offscreen window for the use + // of NPWindow. NPAPI on the Mac requires a Carbon WindowRef for the + // "browser window", even if we're not using the Quickdraw drawing model. + // Not having a valid window reference causes subtle bugs with plugins + // which retreive the NPWindow and validate the same. The NPWindow + // can be retreived via NPN_GetValue of NPNVnetscapeWindow. + + WindowRef window_ref; + if (CreateNewWindow(kDocumentWindowClass, + kWindowStandardDocumentAttributes, + &window_bounds, + &window_ref) == noErr) { + cg_context_.window = window_ref; + } + } else { + SetWindowBounds(cg_context_.window, kWindowContentRgn, &window_bounds); + } + instance()->NPP_SetWindow(&window_); + windowless_needs_set_window_ = false; + } NPEvent paint_event; + 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); + CGContextRestoreGState(context); + [NSGraphicsContext restoreGraphicsState]; } void WebPluginDelegateImpl::WindowlessSetWindow(bool force_set_window) { @@ -372,8 +330,6 @@ void WebPluginDelegateImpl::WindowlessSetWindow(bool force_set_window) { if (window_rect_.IsEmpty()) // wait for geometry to be set. return; - DCHECK(instance()->windowless()); - window_.clipRect.top = clip_rect_.y(); window_.clipRect.left = clip_rect_.x(); window_.clipRect.bottom = clip_rect_.y() + clip_rect_.height(); @@ -388,25 +344,136 @@ void WebPluginDelegateImpl::WindowlessSetWindow(bool force_set_window) { // Reset this flag before entering the instance in case of side-effects. windowless_needs_set_window_ = false; + Rect window_bounds; + window_bounds.top = window_rect_.y(); + window_bounds.left = window_rect_.x(); + window_bounds.bottom = window_rect_.y() + window_rect_.height(); + window_bounds.right = window_rect_.x() + window_rect_.width(); + if (!cg_context_.window) { + // For all plugins we create a placeholder offscreen window for the use + // of NPWindow. NPAPI on the Mac requires a Carbon WindowRef for the + // "browser window", even if we're not using the Quickdraw drawing model. + // Not having a valid window reference causes subtle bugs with plugins + // which retreive the NPWindow and validate the same. The NPWindow + // can be retreived via NPN_GetValue of NPNVnetscapeWindow. + + WindowRef window_ref; + if (CreateNewWindow(kDocumentWindowClass, + kWindowStandardDocumentAttributes, + &window_bounds, + &window_ref) == noErr) { + cg_context_.window = window_ref; + } + } else { + SetWindowBounds(cg_context_.window, kWindowContentRgn, &window_bounds); + } + NPError err = instance()->NPP_SetWindow(&window_); DCHECK(err == NPERR_NO_ERROR); } void WebPluginDelegateImpl::SetFocus() { - DCHECK(instance()->windowless()); + NPEvent focus_event = { 0 }; + focus_event.what = NPEventType_GetFocusEvent; + focus_event.when = TickCount(); + instance()->NPP_HandleEvent(&focus_event); +} - NPEvent focus_event; +static bool NPEventFromWebMouseEvent(const WebMouseEvent& event, + NPEvent *np_event) { + np_event->where.h = event.windowX; + np_event->where.v = event.windowY; + + if (event.modifiers & WebInputEvent::ControlKey) + np_event->modifiers |= controlKey; + if (event.modifiers & WebInputEvent::ShiftKey) + np_event->modifiers |= shiftKey; + + switch (event.type) { + case WebInputEvent::MouseMove: + case WebInputEvent::MouseLeave: + case WebInputEvent::MouseEnter: + np_event->what = NPEventType_AdjustCursorEvent; + return true; + case WebInputEvent::MouseDown: + switch (event.button) { + case WebMouseEvent::ButtonLeft: + case WebMouseEvent::ButtonMiddle: + case WebMouseEvent::ButtonRight: + np_event->what = mouseDown; + break; + } + return true; + case WebInputEvent::MouseUp: + switch (event.button) { + case WebMouseEvent::ButtonLeft: + case WebMouseEvent::ButtonMiddle: + case WebMouseEvent::ButtonRight: + np_event->what = mouseUp; + break; + } + return true; + default: + NOTREACHED(); + return false; + } +} - instance()->NPP_HandleEvent(&focus_event); +static bool NPEventFromWebKeyboardEvent(const WebKeyboardEvent& event, + NPEvent *np_event) { + np_event->message = event.nativeKeyCode; + + switch (event.type) { + case WebInputEvent::KeyDown: + np_event->what = keyDown; + return true; + case WebInputEvent::KeyUp: + np_event->what = keyUp; + return true; + default: + NOTREACHED(); + return false; + } +} + +static bool NPEventFromWebInputEvent(const WebInputEvent& event, + NPEvent* np_event) { + switch (event.type) { + case WebInputEvent::MouseMove: + case WebInputEvent::MouseLeave: + case WebInputEvent::MouseEnter: + case WebInputEvent::MouseDown: + case WebInputEvent::MouseUp: + if (event.size < sizeof(WebMouseEvent)) { + NOTREACHED(); + return false; + } + return NPEventFromWebMouseEvent(*static_cast<const WebMouseEvent*>(&event), np_event); + case WebInputEvent::KeyDown: + case WebInputEvent::KeyUp: + if (event.size < sizeof(WebKeyboardEvent)) { + NOTREACHED(); + return false; + } + return NPEventFromWebKeyboardEvent(*static_cast<const WebKeyboardEvent*>(&event), np_event); + default: + DLOG(WARNING) << "unknown event type" << event.type; + return false; + } } bool WebPluginDelegateImpl::HandleInputEvent(const WebInputEvent& event, WebCursorInfo* cursor) { DCHECK(windowless_) << "events should only be received in windowless mode"; DCHECK(cursor != NULL); - // TODO: convert event into a NPEvent, and call NPP_HandleEvent(np_event). - return true; + NPEvent np_event = {0}; + if (!NPEventFromWebInputEvent(event, &np_event)) { + return false; + } + np_event.when = TickCount(); + bool ret = instance()->NPP_HandleEvent(&np_event) != 0; + return ret; } WebPluginResourceClient* WebPluginDelegateImpl::CreateResourceClient( |