diff options
author | stuartmorgan@chromium.org <stuartmorgan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-01-21 20:18:48 +0000 |
---|---|---|
committer | stuartmorgan@chromium.org <stuartmorgan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-01-21 20:18:48 +0000 |
commit | 385579b9bec3cc54d69b7754a9d803cb45071ffb (patch) | |
tree | 5bcef12c90a47887eb503c9ac3bba8870c3f8770 /webkit/glue | |
parent | c646aed1426646854532c8d90f8c7a35667081c2 (diff) | |
download | chromium_src-385579b9bec3cc54d69b7754a9d803cb45071ffb.zip chromium_src-385579b9bec3cc54d69b7754a9d803cb45071ffb.tar.gz chromium_src-385579b9bec3cc54d69b7754a9d803cb45071ffb.tar.bz2 |
Improve handling of off-screen plugins on the Mac
This makes two notable changes:
- Plugins that are scrolled completely out of view will get an empty clip rect now.
- Carbon Plugins that are scrolled completely out of view will get idle events at a lower rate.
Also removes code to compute title bar offset, which is now cruft since the dummy window is chromeless.
BUG=30838
TEST=Plugins should continue to draw smoothly when visible, and audio should not be interrupted when they are scrolled out of view.
Review URL: http://codereview.chromium.org/543156
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@36776 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/glue')
-rw-r--r-- | webkit/glue/plugins/webplugin_delegate_impl.h | 9 | ||||
-rw-r--r-- | webkit/glue/plugins/webplugin_delegate_impl_mac.mm | 159 |
2 files changed, 101 insertions, 67 deletions
diff --git a/webkit/glue/plugins/webplugin_delegate_impl.h b/webkit/glue/plugins/webplugin_delegate_impl.h index acfa687..d4b5e56 100644 --- a/webkit/glue/plugins/webplugin_delegate_impl.h +++ b/webkit/glue/plugins/webplugin_delegate_impl.h @@ -142,9 +142,11 @@ class WebPluginDelegateImpl : public webkit_glue::WebPluginDelegate { // Informs the delegate that the plugin set a Cocoa NSCursor. void SetNSCursor(NSCursor* cursor); +#ifndef NP_NO_CARBON // Indicates that it's time to send the plugin a null event. void FireIdleEvent(); #endif +#endif // OS_MACOSX #if !defined(OS_MACOSX) gfx::PluginWindowHandle windowed_handle() const { @@ -330,6 +332,7 @@ class WebPluginDelegateImpl : public webkit_glue::WebPluginDelegate { // the screen. void UpdatePluginLocation(const WebKit::WebMouseEvent& event); +#ifndef NP_NO_CARBON // Moves our dummy window to the given offset relative to the last known // location of the real renderer window's content view. // If new_width or new_height is non-zero, the window size (content region) @@ -338,8 +341,10 @@ class WebPluginDelegateImpl : public webkit_glue::WebPluginDelegate { void UpdateDummyWindowBoundsWithOffset(int x_offset, int y_offset, int new_width, int new_height); - // Runnable Method Factory used to drip null events into the plugin. - ScopedRunnableMethodFactory<WebPluginDelegateImpl> null_event_factory_; + // Adjusts the idle event rate for a Carbon plugin based on its current + // visibility. + void UpdateIdleEventRate(); +#endif // !NP_NO_CARBON // The most recently seen offset between global and browser-window-local // coordinates. We use this to keep the placeholder Carbon WindowRef's origin diff --git a/webkit/glue/plugins/webplugin_delegate_impl_mac.mm b/webkit/glue/plugins/webplugin_delegate_impl_mac.mm index 8a531ff..78bf785 100644 --- a/webkit/glue/plugins/webplugin_delegate_impl_mac.mm +++ b/webkit/glue/plugins/webplugin_delegate_impl_mac.mm @@ -53,16 +53,6 @@ using WebKit::WebMouseWheelEvent; namespace { -// The fastest we are willing to process idle events for plugins. -// Some can easily exceed the limits of our CPU if we don't throttle them. -// The throttle has been chosen by using the same value as Apple's WebKit port. -// -// We'd like to make the throttle delay variable, based on the amount of -// time currently required to paint 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 kPluginIdleThrottleDelayMs = 20; // 20ms (50Hz) - base::LazyInstance<std::set<WebPluginDelegateImpl*> > g_active_delegates( base::LINKER_INITIALIZED); @@ -84,6 +74,13 @@ private: }; #ifndef NP_NO_CARBON +// Timer periods for sending idle events to Carbon plugins. The visible value +// (50Hz) matches both Safari and Firefox. The hidden value (8Hz) matches +// Firefox; according to https://bugzilla.mozilla.org/show_bug.cgi?id=525533 +// going lower than that causes issues. +const int kVisibleIdlePeriodMs = 20; // (50Hz) +const int kHiddenIdlePeriodMs = 125; // (8Hz) + class CarbonIdleEventSource { public: // Returns the shared Carbon idle event source. @@ -93,41 +90,69 @@ class CarbonIdleEventSource { return event_source; } - // Registers the plugin delegate as interested in receiving idle events. - void RegisterDelegate(WebPluginDelegateImpl* delegate) { - if (delegates_.empty()) { - timer_.Start( - base::TimeDelta::FromMilliseconds(kPluginIdleThrottleDelayMs), this, - &CarbonIdleEventSource::SendPluginEvents); + // Registers the plugin delegate as interested in receiving idle events + // suitable for a visible plugin. + // Registering a delegate as visible automatically unregisters it from the + // hidden event source. + void RegisterVisibleDelegate(WebPluginDelegateImpl* delegate) { + UnregisterDelegate(delegate); + if (visible_delegates_.empty()) { + visible_timer_.Start( + base::TimeDelta::FromMilliseconds(kVisibleIdlePeriodMs), this, + &CarbonIdleEventSource::SendVisiblePluginEvents); + } + visible_delegates_.insert(delegate); + } + + // Registers the plugin delegate as interested in receiving idle events + // suitable for a plugin that isn't visible. + // Registering a delegate as hidden automatically unregisters it from the + // visible event source. + void RegisterHiddenDelegate(WebPluginDelegateImpl* delegate) { + UnregisterDelegate(delegate); + if (hidden_delegates_.empty()) { + hidden_timer_.Start( + base::TimeDelta::FromMilliseconds(kHiddenIdlePeriodMs), this, + &CarbonIdleEventSource::SendHiddenPluginEvents); } - delegates_.insert(delegate); + hidden_delegates_.insert(delegate); } // Removes the plugin delegate from the list of plugins receiving idle events. void UnregisterDelegate(WebPluginDelegateImpl* delegate) { - delegates_.erase(delegate); - if (delegates_.empty()) { - timer_.Stop(); - } + size_t removed = visible_delegates_.erase(delegate); + if (removed > 0 && visible_delegates_.empty()) + visible_timer_.Stop(); + removed = hidden_delegates_.erase(delegate); + if (removed > 0 && hidden_delegates_.empty()) + hidden_timer_.Stop(); } private: CarbonIdleEventSource() {} - void SendPluginEvents() { - // TODO(stuartmorgan): Plugins that aren't visible (background tab, - // minimized window, etc.) should instead get events from a second, slower - // timer (8 times per second, rather than 50). - for (std::set<WebPluginDelegateImpl*>::iterator i = delegates_.begin(); - i != delegates_.end(); ++i) { + void SendVisiblePluginEvents() { + SendIdleEventsToDelegates(visible_delegates_); + } + + void SendHiddenPluginEvents() { + SendIdleEventsToDelegates(hidden_delegates_); + } + + void SendIdleEventsToDelegates( + const std::set<WebPluginDelegateImpl*>& delegates) const { + for (std::set<WebPluginDelegateImpl*>::iterator i = delegates.begin(); + i != delegates.end(); ++i) { (*i)->FireIdleEvent(); } } - base::RepeatingTimer<CarbonIdleEventSource> timer_; - std::set<WebPluginDelegateImpl*> delegates_; + base::RepeatingTimer<CarbonIdleEventSource> visible_timer_; + base::RepeatingTimer<CarbonIdleEventSource> hidden_timer_; + std::set<WebPluginDelegateImpl*> visible_delegates_; + std::set<WebPluginDelegateImpl*> hidden_delegates_; }; -#endif // NP_NO_CARBON +#endif // !NP_NO_CARBON } // namespace @@ -141,7 +166,6 @@ WebPluginDelegateImpl::WebPluginDelegateImpl( instance_(instance), parent_(containing_view), quirks_(0), - null_event_factory_(this), last_window_x_offset_(0), last_window_y_offset_(0), last_mouse_x_(0), @@ -242,7 +266,7 @@ void WebPluginDelegateImpl::PlatformInitialize() { #ifndef NP_NO_CARBON // If the plugin wants Carbon events, hook up to the source of idle events. if (instance()->event_model() == NPEventModelCarbon) - CarbonIdleEventSource::SharedInstance()->RegisterDelegate(this); + UpdateIdleEventRate(); #endif plugin_->SetWindow(NULL); @@ -306,18 +330,26 @@ void WebPluginDelegateImpl::WindowedSetWindow() { void WebPluginDelegateImpl::WindowlessUpdateGeometry( const gfx::Rect& window_rect, const gfx::Rect& clip_rect) { - // Only resend to the instance if the geometry has changed. - if (window_rect == window_rect_ && clip_rect == clip_rect_) - return; - - // We will inform the instance of this change when we call NPP_SetWindow. + bool old_clip_was_empty = clip_rect_.IsEmpty(); + bool new_clip_is_empty = clip_rect.IsEmpty(); clip_rect_ = clip_rect; - if (window_rect_ != window_rect) { - window_rect_ = window_rect; + // Only resend to the instance if the geometry has changed (see note in + // WindowlesSetWindow for why we only care about the clip rect switching + // empty state). + if (window_rect == window_rect_ && old_clip_was_empty == new_clip_is_empty) + return; - WindowlessSetWindow(true); +#ifndef NP_NO_CARBON + // If visibility has changed, switch our idle event rate. + if (instance()->event_model() == NPEventModelCarbon && + old_clip_was_empty != new_clip_is_empty) { + UpdateIdleEventRate(); } +#endif + + window_rect_ = window_rect; + WindowlessSetWindow(true); } void WebPluginDelegateImpl::WindowlessPaint(gfx::NativeDrawingContext context, @@ -392,33 +424,21 @@ void WebPluginDelegateImpl::WindowlessSetWindow(bool force_set_window) { if (!instance()) return; - int y_offset = 0; -#ifndef NP_NO_CARBON - if (instance()->event_model() == NPEventModelCarbon && - instance()->drawing_model() == NPDrawingModelCoreGraphics) { - // Get the dummy window structure height; we're pretenting the plugin takes - // up the whole (dummy) window, but the clip rect and x/y are relative to - // the full window region, not just the content region. - Rect titlebar_bounds; - WindowRef window = reinterpret_cast<WindowRef>(cg_context_.window); - GetWindowBounds(window, kWindowTitleBarRgn, &titlebar_bounds); - y_offset = titlebar_bounds.bottom - titlebar_bounds.top; - } -#endif - // It's not clear what we should do in the QD case; Safari always seems to use - // 0, whereas Firefox uses the offset in the window and passes -offset as - // port_y in the NP_Port structure. Since the port we are using corresponds - // directly to the context, not the window, we need to use 0 for now, but - // that may not work once we get events working. - window_.x = 0; - window_.y = y_offset; + window_.y = 0; window_.height = window_rect_.height(); window_.width = window_rect_.width(); window_.clipRect.left = window_.x; window_.clipRect.top = window_.y; - window_.clipRect.right = window_.clipRect.left + window_.width; - window_.clipRect.bottom = window_.clipRect.top + window_.height; + window_.clipRect.right = window_.clipRect.left; + window_.clipRect.bottom = window_.clipRect.top; + if (!clip_rect_.IsEmpty()) { + // We never tell plugins that they are only partially visible; because the + // drawing target doesn't change size, the positioning of what plugins drew + // would be wrong, as would any transforms they did on the context. + window_.clipRect.right += window_.width; + window_.clipRect.bottom += window_.height; + } UpdateDummyWindowBoundsWithOffset(window_rect_.x(), window_rect_.y(), window_rect_.width(), @@ -502,19 +522,20 @@ void WebPluginDelegateImpl::UpdatePluginLocation(const WebMouseEvent& event) { instance()->set_plugin_origin(gfx::Point(event.globalX - event.x, event.globalY - event.y)); -#ifndef NP_NO_CARBON if (instance()->event_model() == NPEventModelCarbon) { last_window_x_offset_ = event.globalX - event.windowX; last_window_y_offset_ = event.globalY - event.windowY; last_mouse_x_ = event.globalX; last_mouse_y_ = event.globalY; +#ifndef NP_NO_CARBON UpdateDummyWindowBoundsWithOffset(event.windowX - event.x, event.windowY - event.y, 0, 0); } #endif } +#ifndef NP_NO_CARBON void WebPluginDelegateImpl::UpdateDummyWindowBoundsWithOffset( int x_offset, int y_offset, int new_width, int new_height) { if (instance()->event_model() == NPEventModelCocoa) @@ -541,6 +562,14 @@ void WebPluginDelegateImpl::UpdateDummyWindowBoundsWithOffset( } } +void WebPluginDelegateImpl::UpdateIdleEventRate() { + if (clip_rect_.IsEmpty()) + CarbonIdleEventSource::SharedInstance()->RegisterHiddenDelegate(this); + else + CarbonIdleEventSource::SharedInstance()->RegisterVisibleDelegate(this); +} +#endif // !NP_NO_CARBON + static bool WebInputEventIsWebMouseEvent(const WebInputEvent& event) { switch (event.type) { case WebInputEvent::MouseMove: @@ -872,6 +901,7 @@ bool WebPluginDelegateImpl::HandleInputEvent(const WebInputEvent& event, return ret; } +#ifndef NP_NO_CARBON void WebPluginDelegateImpl::FireIdleEvent() { // Avoid a race condition between IO and UI threads during plugin shutdown if (!instance_) @@ -879,7 +909,6 @@ void WebPluginDelegateImpl::FireIdleEvent() { ScopedActiveDelegate active_delegate(this); -#ifndef NP_NO_CARBON if (!webkit_glue::IsPluginRunningInRendererProcess()) { switch (instance()->event_model()) { case NPEventModelCarbon: @@ -910,7 +939,6 @@ void WebPluginDelegateImpl::FireIdleEvent() { 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 @@ -921,3 +949,4 @@ void WebPluginDelegateImpl::FireIdleEvent() { instance()->webplugin()->Invalidate(); #endif } +#endif // !NP_NO_CARBON |