From b4ec5d95f7ae134d69449e1715f7f744dee31448 Mon Sep 17 00:00:00 2001 From: "avi@chromium.org" Date: Tue, 19 Jan 2010 19:24:24 +0000 Subject: (Mac) Allow the tracking of the "active" plugin delegate separate from the fake windows. BUG=http://crbug.com/20717 TEST=none; no visible change Review URL: http://codereview.chromium.org/549085 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@36533 0039d316-1c4b-4281-b951-d872f2087c98 --- chrome/app/framework.order | 16 ++++----- chrome/browser/plugin_carbon_interpose_mac.cc | 7 ++-- chrome/plugin/plugin_interpose_util_mac.h | 3 ++ chrome/plugin/plugin_interpose_util_mac.mm | 5 +++ .../glue/plugins/fake_plugin_window_tracker_mac.cc | 34 ++++++++++--------- .../glue/plugins/fake_plugin_window_tracker_mac.h | 39 +++++----------------- webkit/glue/plugins/webplugin_delegate_impl.h | 4 ++- webkit/glue/plugins/webplugin_delegate_impl_mac.mm | 37 ++++++++++++++++---- 8 files changed, 79 insertions(+), 66 deletions(-) diff --git a/chrome/app/framework.order b/chrome/app/framework.order index 167d45f..814cecc 100644 --- a/chrome/app/framework.order +++ b/chrome/app/framework.order @@ -23,20 +23,20 @@ _NP_GetValue _NP_Initialize _NP_Shutdown __ZN22mac_plugin_interposing21SwitchToPluginProcessEv -__ZN22mac_plugin_interposing31NotifyBrowserOfPluginHideWindowEj6CGRect -__ZN22mac_plugin_interposing31NotifyBrowserOfPluginShowWindowEj6CGRectb +__ZN22mac_plugin_interposing17GetActiveDelegateEv __ZN22mac_plugin_interposing33NotifyBrowserOfPluginSelectWindowEj6CGRectb +__ZN22mac_plugin_interposing31NotifyBrowserOfPluginShowWindowEj6CGRectb +__ZN22mac_plugin_interposing31NotifyBrowserOfPluginHideWindowEj6CGRect __ZN22mac_plugin_interposing28NotifyPluginOfSetThemeCursorEP21WebPluginDelegateImplm -__ZN23FakePluginWindowTracker14SharedInstanceEv -__ZN23FakePluginWindowTracker27RemoveFakeWindowForDelegateEP21WebPluginDelegateImplP15OpaqueWindowPtr -__ZN23FakePluginWindowTracker29GenerateFakeWindowForDelegateEP21WebPluginDelegateImpl -__ZN23FakePluginWindowTracker24get_active_plugin_windowEv -__ZN23FakePluginWindowTracker24set_active_plugin_windowEP15OpaqueWindowPtr __ZN23FakePluginWindowTrackerC1Ev __ZN23FakePluginWindowTrackerC2Ev +__ZN23FakePluginWindowTracker14SharedInstanceEv +__ZN23FakePluginWindowTracker29GenerateFakeWindowForDelegateEP21WebPluginDelegateImpl +__ZNK23FakePluginWindowTracker24GetDelegateForFakeWindowEP15OpaqueWindowPtr +__ZNK23FakePluginWindowTracker24GetFakeWindowForDelegateEP21WebPluginDelegateImpl +__ZN23FakePluginWindowTracker27RemoveFakeWindowForDelegateEP21WebPluginDelegateImplP15OpaqueWindowPtr __ZN7WebCore22narrowPrecisionToFloatIdEEfT_ __ZN7WebCore24narrowPrecisionToCGFloatIdEEfT_ -__ZNK23FakePluginWindowTracker24GetDelegateForFakeWindowEP15OpaqueWindowPtr __ZnwmPv _catch_exception_raise diff --git a/chrome/browser/plugin_carbon_interpose_mac.cc b/chrome/browser/plugin_carbon_interpose_mac.cc index 45f0ffe..adbba7e 100644 --- a/chrome/browser/plugin_carbon_interpose_mac.cc +++ b/chrome/browser/plugin_carbon_interpose_mac.cc @@ -126,8 +126,9 @@ static void ChromePluginDisposeDialog(DialogRef dialog) { } static WindowPartCode ChromePluginFindWindow(Point point, WindowRef* window) { + WebPluginDelegateImpl* delegate = mac_plugin_interposing::GetActiveDelegate(); FakePluginWindowTracker* tracker = FakePluginWindowTracker::SharedInstance(); - WindowRef plugin_window = tracker->get_active_plugin_window(); + WindowRef plugin_window = tracker->GetFakeWindowForDelegate(delegate); if (plugin_window) { // If plugin_window is non-NULL, then we are in the middle of routing an // event to the plugin, so we know it's destined for this window already, @@ -145,9 +146,7 @@ static WindowPartCode ChromePluginFindWindow(Point point, WindowRef* window) { } static OSStatus ChromePluginSetThemeCursor(ThemeCursor cursor) { - FakePluginWindowTracker* tracker = FakePluginWindowTracker::SharedInstance(); - WebPluginDelegateImpl* delegate = - tracker->GetDelegateForFakeWindow(tracker->get_active_plugin_window()); + WebPluginDelegateImpl* delegate = mac_plugin_interposing::GetActiveDelegate(); if (delegate) { mac_plugin_interposing::NotifyPluginOfSetThemeCursor(delegate, cursor); return noErr; diff --git a/chrome/plugin/plugin_interpose_util_mac.h b/chrome/plugin/plugin_interpose_util_mac.h index 75d1142..deabe6c 100644 --- a/chrome/plugin/plugin_interpose_util_mac.h +++ b/chrome/plugin/plugin_interpose_util_mac.h @@ -20,6 +20,9 @@ void SetUpCocoaInterposing(); // Brings the plugin process to the front so that the user can see its windows. void SwitchToPluginProcess(); +// Returns the delegate currently processing events. +WebPluginDelegateImpl* GetActiveDelegate(); + // Sends a message to the browser process to inform it that the given window // has been brought forward. void NotifyBrowserOfPluginSelectWindow(uint32 window_id, CGRect bounds, diff --git a/chrome/plugin/plugin_interpose_util_mac.mm b/chrome/plugin/plugin_interpose_util_mac.mm index 1cad1bb..7743175 100644 --- a/chrome/plugin/plugin_interpose_util_mac.mm +++ b/chrome/plugin/plugin_interpose_util_mac.mm @@ -31,6 +31,11 @@ void SwitchToPluginProcess() { } __attribute__((visibility("default"))) +WebPluginDelegateImpl* GetActiveDelegate() { + return WebPluginDelegateImpl::GetActiveDelegate(); +} + +__attribute__((visibility("default"))) void NotifyBrowserOfPluginSelectWindow(uint32 window_id, CGRect bounds, bool modal) { PluginThread* plugin_thread = PluginThread::current(); diff --git a/webkit/glue/plugins/fake_plugin_window_tracker_mac.cc b/webkit/glue/plugins/fake_plugin_window_tracker_mac.cc index 5be919e..1099a99 100644 --- a/webkit/glue/plugins/fake_plugin_window_tracker_mac.cc +++ b/webkit/glue/plugins/fake_plugin_window_tracker_mac.cc @@ -5,9 +5,7 @@ #include "base/logging.h" #include "webkit/glue/plugins/fake_plugin_window_tracker_mac.h" -FakePluginWindowTracker::FakePluginWindowTracker() - : window_to_delegate_map_(CFDictionaryCreateMutable(kCFAllocatorDefault, - 0, NULL, NULL)) { +FakePluginWindowTracker::FakePluginWindowTracker() { } FakePluginWindowTracker* FakePluginWindowTracker::SharedInstance() { @@ -29,30 +27,34 @@ WindowRef FakePluginWindowTracker::GenerateFakeWindowForDelegate( kWindowNoTitleBarAttribute, &window_bounds, &new_ref) == noErr) { - CFDictionaryAddValue(window_to_delegate_map_, new_ref, delegate); + window_to_delegate_map_[new_ref] = delegate; + delegate_to_window_map_[delegate] = new_ref; } return new_ref; } WebPluginDelegateImpl* FakePluginWindowTracker::GetDelegateForFakeWindow( WindowRef window) const { - return const_cast( - static_cast( - CFDictionaryGetValue(window_to_delegate_map_, window))); + WindowToDelegateMap::const_iterator i = window_to_delegate_map_.find(window); + if (i != window_to_delegate_map_.end()) + return i->second; + return NULL; +} + +WindowRef FakePluginWindowTracker::GetFakeWindowForDelegate( + WebPluginDelegateImpl* delegate) const { + DelegateToWindowMap::const_iterator i = + delegate_to_window_map_.find(delegate); + if (i != delegate_to_window_map_.end()) + return i->second; + return NULL; } void FakePluginWindowTracker::RemoveFakeWindowForDelegate( WebPluginDelegateImpl* delegate, WindowRef window) { DCHECK(GetDelegateForFakeWindow(window) == delegate); - CFDictionaryRemoveValue(window_to_delegate_map_, delegate); + window_to_delegate_map_.erase(window); + delegate_to_window_map_.erase(delegate); if (window) // Check just in case the initial window creation failed. DisposeWindow(window); } - -WindowRef FakePluginWindowTracker::get_active_plugin_window() { - return active_plugin_window_; -} - -void FakePluginWindowTracker::set_active_plugin_window(WindowRef window) { - active_plugin_window_ = window; -} diff --git a/webkit/glue/plugins/fake_plugin_window_tracker_mac.h b/webkit/glue/plugins/fake_plugin_window_tracker_mac.h index eeb2c81..d6576bf 100644 --- a/webkit/glue/plugins/fake_plugin_window_tracker_mac.h +++ b/webkit/glue/plugins/fake_plugin_window_tracker_mac.h @@ -6,9 +6,9 @@ #define WEBKIT_GLUE_PLUGINS_FAKE_PLUGIN_WINDOW_TRACKER_MAC_H_ #include +#include #include "base/basictypes.h" -#include "base/scoped_cftyperef.h" class ScopedActivePluginWindow; class WebPluginDelegateImpl; @@ -30,43 +30,20 @@ class __attribute__((visibility("default"))) FakePluginWindowTracker { // Returns the WebPluginDelegate associated with the given fake window ref. WebPluginDelegateImpl* GetDelegateForFakeWindow(WindowRef window) const; + // Returns the fake window ref associated with |delegate|. + WindowRef GetFakeWindowForDelegate(WebPluginDelegateImpl* delegate) const; + // Removes the fake window ref entry for |delegate|. void RemoveFakeWindowForDelegate(WebPluginDelegateImpl* delegate, WindowRef window); - // Gets the window for the plugin that is currently handling an input event. - // To set the value, use ScopedActivePluginWindow. - WindowRef get_active_plugin_window(); - private: - friend class ScopedActivePluginWindow; - // Sets the window corresponding to the plugin that is currently handling an - // input event. - void set_active_plugin_window(WindowRef window); - - scoped_cftyperef window_to_delegate_map_; - - WindowRef active_plugin_window_; // weak reference + typedef std::map WindowToDelegateMap; + typedef std::map DelegateToWindowMap; + WindowToDelegateMap window_to_delegate_map_; + DelegateToWindowMap delegate_to_window_map_; DISALLOW_COPY_AND_ASSIGN(FakePluginWindowTracker); }; -// Helper to simplify correct usage of set_active_plugin_window. -// Instantiating will set the shared plugin window tracker's active window to -// |window| for the lifetime of the object, then NULL when it goes out of scope. -class ScopedActivePluginWindow { - public: - explicit ScopedActivePluginWindow(WindowRef window) : window_(window) { - FakePluginWindowTracker::SharedInstance()->set_active_plugin_window( - window_); - } - ~ScopedActivePluginWindow() { - FakePluginWindowTracker::SharedInstance()->set_active_plugin_window( - NULL); - } -private: - WindowRef window_; // weak ref - DISALLOW_COPY_AND_ASSIGN(ScopedActivePluginWindow); -}; - #endif // WEBKIT_GLUE_PLUGINS_FAKE_PLUGIN_WINDOW_TRACKER_MAC_H_ diff --git a/webkit/glue/plugins/webplugin_delegate_impl.h b/webkit/glue/plugins/webplugin_delegate_impl.h index 3e407aa..4e66936 100644 --- a/webkit/glue/plugins/webplugin_delegate_impl.h +++ b/webkit/glue/plugins/webplugin_delegate_impl.h @@ -117,7 +117,9 @@ class WebPluginDelegateImpl : public webkit_glue::WebPluginDelegate { // Informs the delegate that the context used for painting windowless plugins // has changed. void UpdateContext(gfx::NativeDrawingContext context); - // returns a vector of currently active delegates in this process. + // Returns the delegate currently processing events. + static WebPluginDelegateImpl* GetActiveDelegate(); + // Returns a vector of currently active delegates in this process. static std::set GetActiveDelegates(); // Informs the delegate which plugin instance has just received keyboard focus // so that it can notify the plugin as appropriate. If |process_id| and diff --git a/webkit/glue/plugins/webplugin_delegate_impl_mac.mm b/webkit/glue/plugins/webplugin_delegate_impl_mac.mm index e7918a9..92edf23 100644 --- a/webkit/glue/plugins/webplugin_delegate_impl_mac.mm +++ b/webkit/glue/plugins/webplugin_delegate_impl_mac.mm @@ -65,6 +65,23 @@ const int kPluginIdleThrottleDelayMs = 20; // 20ms (50Hz) base::LazyInstance > g_active_delegates( base::LINKER_INITIALIZED); +WebPluginDelegateImpl* g_active_delegate; + +// Helper to simplify correct usage of g_active_delegate. Instantiating will +// set the active delegate to |delegate| for the lifetime of the object, then +// NULL when it goes out of scope. +class ScopedActiveDelegate { +public: + explicit ScopedActiveDelegate(WebPluginDelegateImpl* delegate) { + g_active_delegate = delegate; + } + ~ScopedActiveDelegate() { + g_active_delegate = NULL; + } +private: + DISALLOW_COPY_AND_ASSIGN(ScopedActiveDelegate); +}; + } // namespace WebPluginDelegateImpl::WebPluginDelegateImpl( @@ -278,6 +295,8 @@ void WebPluginDelegateImpl::WindowlessPaint(gfx::NativeDrawingContext context, static StatsRate plugin_paint("Plugin.Paint"); StatsScope scope(plugin_paint); + ScopedActiveDelegate active_delegate(this); + switch (instance()->drawing_model()) { #ifndef NP_NO_QUICKDRAW case NPDrawingModelQuickDraw: { @@ -371,6 +390,10 @@ void WebPluginDelegateImpl::WindowlessSetWindow(bool force_set_window) { DCHECK(err == NPERR_NO_ERROR); } +WebPluginDelegateImpl* WebPluginDelegateImpl::GetActiveDelegate() { + return g_active_delegate; +} + std::set WebPluginDelegateImpl::GetActiveDelegates() { std::set* delegates = g_active_delegates.Pointer(); return *delegates; @@ -382,6 +405,8 @@ void WebPluginDelegateImpl::FocusNotify(WebPluginDelegateImpl* delegate) { have_focus_ = (delegate == this); + ScopedActiveDelegate active_delegate(this); + switch (instance()->event_model()) { case NPEventModelCarbon: { NPEvent focus_event = { 0 }; @@ -743,6 +768,8 @@ bool WebPluginDelegateImpl::HandleInputEvent(const WebInputEvent& event, } #endif + ScopedActiveDelegate active_delegate(this); + // Create the plugin event structure, and send it to the plugin. bool ret = false; switch (instance()->event_model()) { @@ -753,9 +780,6 @@ bool WebPluginDelegateImpl::HandleInputEvent(const WebInputEvent& event, LOG(WARNING) << "NPEventFromWebInputEvent failed"; return false; } - // Set this plugin's window as the active one, for global Carbon calls. - ScopedActivePluginWindow active_window_scope( - reinterpret_cast(cg_context_.window)); ret = instance()->NPP_HandleEvent(&np_event) != 0; break; } @@ -798,9 +822,13 @@ void WebPluginDelegateImpl::OnNullEvent() { delete this; return; } + // Avoid a race condition between IO and UI threads during plugin shutdown if (!instance_) return; + + ScopedActiveDelegate active_delegate(this); + #ifndef NP_NO_CARBON if (!webkit_glue::IsPluginRunningInRendererProcess()) { switch (instance()->event_model()) { @@ -830,9 +858,6 @@ void WebPluginDelegateImpl::OnNullEvent() { np_event.modifiers |= btnState; np_event.where.h = last_mouse_x_; np_event.where.v = last_mouse_y_; - // Set this plugin's window as the active one, for global Carbon calls. - ScopedActivePluginWindow active_window_scope( - reinterpret_cast(cg_context_.window)); instance()->NPP_HandleEvent(&np_event); } #endif -- cgit v1.1