summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorstuartmorgan@chromium.org <stuartmorgan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-04-16 15:02:37 +0000
committerstuartmorgan@chromium.org <stuartmorgan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-04-16 15:02:37 +0000
commit7ba3818362289db0081fb869caf53084fca52eaa (patch)
tree1c3e32713cc537b798d3108810df7f4d5efab9ec
parent23ce3973a2bead57dde8c741d1c2e90e15d1cf43 (diff)
downloadchromium_src-7ba3818362289db0081fb869caf53084fca52eaa.zip
chromium_src-7ba3818362289db0081fb869caf53084fca52eaa.tar.gz
chromium_src-7ba3818362289db0081fb869caf53084fca52eaa.tar.bz2
Reorganize the Mac plugin host code
Reorders the Mac WebPluginDelegateImpl code for better findability. The only changes that aren't just moving existing code unchanged are: - The external drag tracking has been consolidated into a helper class. - The Windows-specific comment in Print has been replaced with a NOTIMPLEMENTED(). BUG=none TEST=none; no behavioral change Review URL: http://codereview.chromium.org/1633014 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@44773 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--webkit/glue/plugins/webplugin_delegate_impl.h40
-rw-r--r--webkit/glue/plugins/webplugin_delegate_impl_mac.mm668
2 files changed, 372 insertions, 336 deletions
diff --git a/webkit/glue/plugins/webplugin_delegate_impl.h b/webkit/glue/plugins/webplugin_delegate_impl.h
index 7b5f970..f57755e 100644
--- a/webkit/glue/plugins/webplugin_delegate_impl.h
+++ b/webkit/glue/plugins/webplugin_delegate_impl.h
@@ -39,10 +39,10 @@ class WebMouseEvent;
}
#if defined(OS_MACOSX)
+class ExternalDragTracker;
#ifndef NP_NO_QUICKDRAW
class QuickDrawDrawingManager;
#endif
-class CoreAnimationRedrawTimerSource;
#ifdef __OBJC__
@class CALayer;
@class CARenderer;
@@ -314,21 +314,6 @@ class WebPluginDelegateImpl : public webkit_glue::WebPluginDelegate {
gfx::PluginWindowHandle parent_;
NPWindow window_;
-#if defined(OS_MACOSX)
- CGContextRef buffer_context_; // Weak ref.
-#ifndef NP_NO_CARBON
- NP_CGContext np_cg_context_;
-#endif
-#ifndef NP_NO_QUICKDRAW
- scoped_ptr<QuickDrawDrawingManager> qd_manager_;
- NP_Port qd_port_;
- base::TimeTicks fast_path_enable_tick_;
-#endif
- CALayer* layer_; // Used for CA drawing mode. Weak, retained by plug-in.
- AcceleratedSurface* surface_;
- CARenderer* renderer_; // Renders layer_ to surface_.
- scoped_ptr<base::RepeatingTimer<WebPluginDelegateImpl> > redraw_timer_;
-#endif
gfx::Rect window_rect_;
gfx::Rect clip_rect_;
int quirks_;
@@ -413,16 +398,28 @@ class WebPluginDelegateImpl : public webkit_glue::WebPluginDelegate {
void UpdateIdleEventRate();
#endif // !NP_NO_CARBON
+ CGContextRef buffer_context_; // Weak ref.
+
+#ifndef NP_NO_CARBON
+ NP_CGContext np_cg_context_;
+#endif
+#ifndef NP_NO_QUICKDRAW
+ NP_Port qd_port_;
+ scoped_ptr<QuickDrawDrawingManager> qd_manager_;
+ base::TimeTicks fast_path_enable_tick_;
+#endif
+
+ CALayer* layer_; // Used for CA drawing mode. Weak, retained by plug-in.
+ AcceleratedSurface* surface_;
+ CARenderer* renderer_; // Renders layer_ to surface_.
+ scoped_ptr<base::RepeatingTimer<WebPluginDelegateImpl> > redraw_timer_;
+
// The upper-left corner of the web content area in screen coordinates,
// relative to an upper-left (0,0).
gfx::Point content_area_origin_;
// True if the plugin thinks it has keyboard focus
bool have_focus_;
- // If non-zero, we are in the middle of a drag that started outside the
- // plugin, and this corresponds to the WebInputEvent modifier flags for any
- // buttons that were down when the mouse entered and are still down now.
- int external_drag_buttons_;
// A function to call when we want to accept keyboard focus
void (*focus_notifier_)(WebPluginDelegateImpl* notifier);
@@ -430,7 +427,10 @@ class WebPluginDelegateImpl : public webkit_glue::WebPluginDelegate {
bool initial_window_focus_;
bool container_is_visible_;
bool have_called_set_window_;
+
gfx::Rect cached_clip_rect_;
+
+ scoped_ptr<ExternalDragTracker> external_drag_tracker_;
#endif // OS_MACOSX
// Called by the message filter hook when the plugin enters a modal loop.
diff --git a/webkit/glue/plugins/webplugin_delegate_impl_mac.mm b/webkit/glue/plugins/webplugin_delegate_impl_mac.mm
index 9227242..09ee22b 100644
--- a/webkit/glue/plugins/webplugin_delegate_impl_mac.mm
+++ b/webkit/glue/plugins/webplugin_delegate_impl_mac.mm
@@ -166,7 +166,87 @@ class CarbonIdleEventSource {
} // namespace
+// Helper to build and maintain a model of a drag entering the plugin but not
+// starting there. See explanation in PlatformHandleInputEvent.
+class ExternalDragTracker {
+ public:
+ ExternalDragTracker() : pressed_buttons_(0) {}
+
+ // Returns true if an external drag is in progress.
+ bool IsDragInProgress() { return pressed_buttons_ != 0; };
+
+ // Returns true if the given event appears to be related to an external drag.
+ bool EventIsRelatedToDrag(const WebInputEvent& event);
+
+ // Updates the tracking of whether an external drag is in progress--and if
+ // so what buttons it involves--based on the given event.
+ void UpdateDragStateFromEvent(const WebInputEvent& event);
+
+ private:
+ // Returns the mask for just the button state in a WebInputEvent's modifiers.
+ static int WebEventButtonModifierMask();
+
+ // The WebInputEvent modifier flags for any buttons that were down when an
+ // external drag entered the plugin, and which and are still down now.
+ int pressed_buttons_;
+
+ DISALLOW_COPY_AND_ASSIGN(ExternalDragTracker);
+};
+
+void ExternalDragTracker::UpdateDragStateFromEvent(const WebInputEvent& event) {
+ switch (event.type) {
+ case WebInputEvent::MouseEnter:
+ pressed_buttons_ = event.modifiers & WebEventButtonModifierMask();
+ break;
+ case WebInputEvent::MouseUp: {
+ const WebMouseEvent* mouse_event =
+ static_cast<const WebMouseEvent*>(&event);
+ if (mouse_event->button == WebMouseEvent::ButtonLeft)
+ pressed_buttons_ &= ~WebInputEvent::LeftButtonDown;
+ if (mouse_event->button == WebMouseEvent::ButtonMiddle)
+ pressed_buttons_ &= ~WebInputEvent::MiddleButtonDown;
+ if (mouse_event->button == WebMouseEvent::ButtonRight)
+ pressed_buttons_ &= ~WebInputEvent::RightButtonDown;
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+bool ExternalDragTracker::EventIsRelatedToDrag(const WebInputEvent& event) {
+ const WebMouseEvent* mouse_event = static_cast<const WebMouseEvent*>(&event);
+ switch (event.type) {
+ case WebInputEvent::MouseUp:
+ // We only care about release of buttons that were part of the drag.
+ return ((mouse_event->button == WebMouseEvent::ButtonLeft &&
+ (pressed_buttons_ & WebInputEvent::LeftButtonDown)) ||
+ (mouse_event->button == WebMouseEvent::ButtonMiddle &&
+ (pressed_buttons_ & WebInputEvent::MiddleButtonDown)) ||
+ (mouse_event->button == WebMouseEvent::ButtonRight &&
+ (pressed_buttons_ & WebInputEvent::RightButtonDown)));
+ case WebInputEvent::MouseEnter:
+ return (event.modifiers & WebEventButtonModifierMask()) != 0;
+ case WebInputEvent::MouseLeave:
+ case WebInputEvent::MouseMove: {
+ int event_buttons = (event.modifiers & WebEventButtonModifierMask());
+ return (pressed_buttons_ &&
+ pressed_buttons_ == event_buttons);
+ }
+ default:
+ return false;
+ }
+ return false;
+}
+
+int ExternalDragTracker::WebEventButtonModifierMask() {
+ return WebInputEvent::LeftButtonDown |
+ WebInputEvent::RightButtonDown |
+ WebInputEvent::MiddleButtonDown;
+}
+
#pragma mark -
+#pragma mark Core WebPluginDelegate implementation
WebPluginDelegateImpl::WebPluginDelegateImpl(
gfx::PluginWindowHandle containing_view,
@@ -177,18 +257,18 @@ WebPluginDelegateImpl::WebPluginDelegateImpl(
plugin_(NULL),
instance_(instance),
parent_(containing_view),
+ quirks_(0),
buffer_context_(NULL),
layer_(nil),
surface_(NULL),
renderer_(nil),
- quirks_(0),
have_focus_(false),
- external_drag_buttons_(0),
focus_notifier_(NULL),
containing_window_has_focus_(false),
initial_window_focus_(false),
container_is_visible_(false),
have_called_set_window_(false),
+ external_drag_tracker_(new ExternalDragTracker()),
handle_event_depth_(0) {
memset(&window_, 0, sizeof(window_));
#ifndef NP_NO_CARBON
@@ -395,36 +475,183 @@ void WebPluginDelegateImpl::Paint(CGContextRef context, const gfx::Rect& rect) {
}
void WebPluginDelegateImpl::Print(CGContextRef context) {
- // Disabling the call to NPP_Print as it causes a crash in
- // flash in some cases. In any case this does not work as expected
- // as the EMF meta file dc passed in needs to be created with the
- // the plugin window dc as its sibling dc and the window rect
- // in .01 mm units.
-}
-
-void WebPluginDelegateImpl::InstallMissingPlugin() {
NOTIMPLEMENTED();
}
-bool WebPluginDelegateImpl::WindowedCreatePlugin() {
- NOTREACHED();
- return false;
+void WebPluginDelegateImpl::SetFocus() {
+ if (focus_notifier_)
+ focus_notifier_(this);
+ else
+ FocusChanged(true);
}
-void WebPluginDelegateImpl::WindowedDestroyWindow() {
- NOTREACHED();
-}
+bool WebPluginDelegateImpl::PlatformHandleInputEvent(
+ const WebInputEvent& event, WebCursorInfo* cursor_info) {
+ DCHECK(cursor_info != NULL);
-bool WebPluginDelegateImpl::WindowedReposition(const gfx::Rect& window_rect,
- const gfx::Rect& clip_rect) {
- NOTREACHED();
- return false;
+ // If we get an event before we've set up the plugin, bail.
+ if (!have_called_set_window_)
+ return false;
+#ifndef NP_NO_CARBON
+ if (instance()->event_model() == NPEventModelCarbon &&
+ !np_cg_context_.context) {
+ return false;
+ }
+#endif
+
+ if (WebInputEvent::isMouseEventType(event.type) ||
+ event.type == WebInputEvent::MouseWheel) {
+ // Ideally we would compute the content origin from the web event using the
+ // code below as a safety net for missed content area location changes.
+ // Because of <http://crbug.com/9996>, however, only globalX/Y are right if
+ // the page has been zoomed, so for now the coordinates we get aren't
+ // trustworthy enough to use for corrections.
+#if PLUGIN_SCALING_FIXED
+ // Check our plugin location before we send the event to the plugin, just
+ // in case we somehow missed a plugin frame change.
+ const WebMouseEvent* mouse_event =
+ static_cast<const WebMouseEvent*>(&event);
+ gfx::Point content_origin(
+ mouse_event->globalX - mouse_event->x - window_rect_.x(),
+ mouse_event->globalY - mouse_event->y - window_rect_.y());
+ if (content_origin.x() != content_area_origin_.x() ||
+ content_origin.y() != content_area_origin_.y()) {
+ DLOG(WARNING) << "Stale plugin content area location: "
+ << content_area_origin_ << " instead of "
+ << content_origin;
+ SetContentAreaOrigin(content_origin);
+ }
+#endif
+
+ current_windowless_cursor_.GetCursorInfo(cursor_info);
+ }
+
+#ifndef NP_NO_CARBON
+ if (instance()->event_model() == NPEventModelCarbon) {
+#ifndef NP_NO_QUICKDRAW
+ if (instance()->drawing_model() == NPDrawingModelQuickDraw) {
+ if (quirks_ & PLUGIN_QUIRK_ALLOW_FASTER_QUICKDRAW_PATH) {
+ // Mouse event handling doesn't work correctly in the fast path mode,
+ // so any time we get a mouse event turn the fast path off, but set a
+ // time to switch it on again (we don't rely just on MouseLeave because
+ // we don't want poor performance in the case of clicking the play
+ // button and then leaving the mouse there).
+ // This isn't perfect (specifically, click-and-hold doesn't seem to work
+ // if the fast path is on), but the slight regression is worthwhile
+ // for the improved framerates.
+ if (WebInputEvent::isMouseEventType(event.type)) {
+ if (event.type == WebInputEvent::MouseLeave) {
+ SetQuickDrawFastPathEnabled(true);
+ } else {
+ SetQuickDrawFastPathEnabled(false);
+ }
+ // Make sure the plugin wasn't destroyed during the switch.
+ if (!instance())
+ return false;
+ }
+ }
+
+ qd_manager_->MakePortCurrent();
+ }
+#endif
+
+ if (event.type == WebInputEvent::MouseMove) {
+ return true; // The recurring FireIdleEvent will send null events.
+ }
+ }
+#endif
+
+ // if we do not currently have focus and this is a mouseDown, trigger a
+ // notification that we are taking the keyboard focus. We can't just key
+ // off of incoming calls to SetFocus, since WebKit may already think we
+ // have it if we were the most recently focused element on our parent tab.
+ if (event.type == WebInputEvent::MouseDown && !have_focus_) {
+ SetFocus();
+ // Make sure that the plugin is still there after handling the focus event.
+ if (!instance())
+ return false;
+ }
+
+ ScopedActiveDelegate active_delegate(this);
+
+ // Create the plugin event structure.
+ NPEventModel event_model = instance()->event_model();
+ scoped_ptr<PluginWebEventConverter> event_converter(
+ PluginWebEventConverterFactory::CreateConverterForModel(event_model));
+ if (!(event_converter.get() && event_converter->InitWithEvent(event))) {
+ // Silently consume any keyboard event types that we don't handle, so that
+ // they don't fall through to the page.
+ if (WebInputEvent::isKeyboardEventType(event.type))
+ return true;
+ return false;
+ }
+ void* plugin_event = event_converter->plugin_event();
+
+ if (instance()->event_model() == NPEventModelCocoa) {
+ // We recieve events related to drags starting outside the plugin, but the
+ // NPAPI Cocoa event model spec says plugins shouldn't receive them, so
+ // filter them out.
+ // If we add a page capture mode at the WebKit layer (like the plugin
+ // capture mode that handles drags starting inside) this can be removed.
+ bool drag_related = external_drag_tracker_->EventIsRelatedToDrag(event);
+ external_drag_tracker_->UpdateDragStateFromEvent(event);
+ if (drag_related) {
+ if (event.type == WebInputEvent::MouseUp &&
+ !external_drag_tracker_->IsDragInProgress()) {
+ // When an external drag ends, we need to synthesize a MouseEntered.
+ NPCocoaEvent enter_event = *(static_cast<NPCocoaEvent*>(plugin_event));
+ enter_event.type = NPCocoaEventMouseEntered;
+ NPAPI::ScopedCurrentPluginEvent event_scope(instance(), &enter_event);
+ instance()->NPP_HandleEvent(&enter_event);
+ }
+ return false;
+ }
+ }
+
+#ifndef PLUGIN_SCALING_FIXED
+ // Because of <http://crbug.com/9996>, the non-global coordinates we get for
+ // zoomed pages are wrong. As a temporary hack around that bug, override the
+ // coordinates we are given with ones computed based on our knowledge of where
+ // the plugin is on screen. We only need to do this for Cocoa, since Carbon
+ // only uses the global coordinates.
+ if (instance()->event_model() == NPEventModelCocoa &&
+ (WebInputEvent::isMouseEventType(event.type) ||
+ event.type == WebInputEvent::MouseWheel)) {
+ const WebMouseEvent* mouse_event =
+ static_cast<const WebMouseEvent*>(&event);
+ NPCocoaEvent* cocoa_event = static_cast<NPCocoaEvent*>(plugin_event);
+ cocoa_event->data.mouse.pluginX =
+ mouse_event->globalX - content_area_origin_.x() - window_rect_.x();
+ cocoa_event->data.mouse.pluginY =
+ mouse_event->globalY - content_area_origin_.y() - window_rect_.y();
+ }
+#endif
+
+ // Send the plugin the event.
+ scoped_ptr<NPAPI::ScopedCurrentPluginEvent> event_scope(NULL);
+ if (instance()->event_model() == NPEventModelCocoa) {
+ event_scope.reset(new NPAPI::ScopedCurrentPluginEvent(
+ instance(), static_cast<NPCocoaEvent*>(plugin_event)));
+ }
+ bool handled = instance()->NPP_HandleEvent(plugin_event) != 0;
+
+ if (WebInputEvent::isMouseEventType(event.type)) {
+ // Plugins are not good about giving accurate information about whether or
+ // not they handled events, and other browsers on the Mac generally ignore
+ // the return value. We may need to expand this to other input types, but
+ // we'll need to be careful about things like Command-keys.
+ handled = true;
+ }
+
+ return handled;
}
-void WebPluginDelegateImpl::WindowedSetWindow() {
- NOTREACHED();
+void WebPluginDelegateImpl::InstallMissingPlugin() {
+ NOTIMPLEMENTED();
}
+#pragma mark -
+
void WebPluginDelegateImpl::WindowlessUpdateGeometry(
const gfx::Rect& window_rect,
const gfx::Rect& clip_rect) {
@@ -458,21 +685,6 @@ void WebPluginDelegateImpl::WindowlessUpdateGeometry(
WindowlessSetWindow();
}
-void WebPluginDelegateImpl::DrawLayerInSurface() {
- surface_->MakeCurrent();
-
- surface_->Clear(window_rect_);
-
- [renderer_ beginFrameAtTime:CACurrentMediaTime() timeStamp:NULL];
- CGRect layerRect = [layer_ bounds];
- [renderer_ addUpdateRect:layerRect];
- [renderer_ render];
- [renderer_ endFrame];
-
- surface_->SwapBuffers();
- plugin_->AcceleratedFrameBuffersDidSwap(windowed_handle());
-}
-
void WebPluginDelegateImpl::WindowlessPaint(gfx::NativeDrawingContext context,
const gfx::Rect& damage_rect) {
// If we get a paint event before we are completely set up (e.g., a nested
@@ -564,6 +776,30 @@ void WebPluginDelegateImpl::WindowlessSetWindow() {
DCHECK(err == NPERR_NO_ERROR);
}
+#pragma mark -
+
+bool WebPluginDelegateImpl::WindowedCreatePlugin() {
+ NOTREACHED();
+ return false;
+}
+
+void WebPluginDelegateImpl::WindowedDestroyWindow() {
+ NOTREACHED();
+}
+
+bool WebPluginDelegateImpl::WindowedReposition(const gfx::Rect& window_rect,
+ const gfx::Rect& clip_rect) {
+ NOTREACHED();
+ return false;
+}
+
+void WebPluginDelegateImpl::WindowedSetWindow() {
+ NOTREACHED();
+}
+
+#pragma mark -
+#pragma mark Mac Extensions
+
WebPluginDelegateImpl* WebPluginDelegateImpl::GetActiveDelegate() {
return g_active_delegate;
}
@@ -607,13 +843,6 @@ void WebPluginDelegateImpl::FocusChanged(bool has_focus) {
}
}
-void WebPluginDelegateImpl::SetFocus() {
- if (focus_notifier_)
- focus_notifier_(this);
- else
- FocusChanged(true);
-}
-
void WebPluginDelegateImpl::SetWindowHasFocus(bool has_focus) {
// If we get a window focus event before calling SetWindow, just remember the
// states (WindowlessSetWindow will then send it on the first call).
@@ -696,28 +925,6 @@ void WebPluginDelegateImpl::SetContainerVisibility(bool is_visible) {
instance()->webplugin()->InvalidateRect(gfx::Rect());
}
-// Update the size of the IOSurface to match the current size of the plug-in,
-// then tell the browser host view so it can adjust its bookkeeping and CALayer
-// appropriately.
-void WebPluginDelegateImpl::UpdateAcceleratedSurface() {
- // Will only have a window handle when using the CoreAnimation drawing model.
- if (!windowed_handle() ||
- instance()->drawing_model() != NPDrawingModelCoreAnimation)
- return;
-
- [layer_ setFrame:CGRectMake(0, 0,
- window_rect_.width(), window_rect_.height())];
- [renderer_ setBounds:[layer_ bounds]];
-
- uint64 io_surface_id = surface_->SetSurfaceSize(window_rect_.size());
- if (io_surface_id) {
- plugin_->SetAcceleratedSurface(windowed_handle(),
- window_rect_.width(),
- window_rect_.height(),
- io_surface_id);
- }
-}
-
void WebPluginDelegateImpl::WindowFrameChanged(gfx::Rect window_frame,
gfx::Rect view_frame) {
instance()->set_window_frame(window_frame);
@@ -736,6 +943,9 @@ void WebPluginDelegateImpl::SetNSCursor(NSCursor* cursor) {
current_windowless_cursor_.InitFromNSCursor(cursor);
}
+#pragma mark -
+#pragma mark Internal Tracking
+
void WebPluginDelegateImpl::SetPluginRect(const gfx::Rect& rect) {
bool plugin_size_changed = rect.width() != window_rect_.width() ||
rect.height() != window_rect_.height();
@@ -779,6 +989,49 @@ void WebPluginDelegateImpl::PluginVisibilityChanged() {
}
}
+#pragma mark -
+#pragma mark Core Animation Support
+
+void WebPluginDelegateImpl::DrawLayerInSurface() {
+ surface_->MakeCurrent();
+
+ surface_->Clear(window_rect_);
+
+ [renderer_ beginFrameAtTime:CACurrentMediaTime() timeStamp:NULL];
+ CGRect layerRect = [layer_ bounds];
+ [renderer_ addUpdateRect:layerRect];
+ [renderer_ render];
+ [renderer_ endFrame];
+
+ surface_->SwapBuffers();
+ plugin_->AcceleratedFrameBuffersDidSwap(windowed_handle());
+}
+
+// Update the size of the IOSurface to match the current size of the plug-in,
+// then tell the browser host view so it can adjust its bookkeeping and CALayer
+// appropriately.
+void WebPluginDelegateImpl::UpdateAcceleratedSurface() {
+ // Will only have a window handle when using the CoreAnimation drawing model.
+ if (!windowed_handle() ||
+ instance()->drawing_model() != NPDrawingModelCoreAnimation)
+ return;
+
+ [layer_ setFrame:CGRectMake(0, 0,
+ window_rect_.width(), window_rect_.height())];
+ [renderer_ setBounds:[layer_ bounds]];
+
+ uint64 io_surface_id = surface_->SetSurfaceSize(window_rect_.size());
+ if (io_surface_id) {
+ plugin_->SetAcceleratedSurface(windowed_handle(),
+ window_rect_.width(),
+ window_rect_.height(),
+ io_surface_id);
+ }
+}
+
+#pragma mark -
+#pragma mark Carbon Event support
+
#ifndef NP_NO_CARBON
void WebPluginDelegateImpl::UpdateDummyWindowBounds(
const gfx::Point& plugin_origin) {
@@ -805,260 +1058,12 @@ void WebPluginDelegateImpl::UpdateDummyWindowBounds(
SetWindowBounds(window, kWindowContentRgn, &new_bounds);
}
-#ifndef NP_NO_QUICKDRAW
-void WebPluginDelegateImpl::SetQuickDrawFastPathEnabled(bool enabled) {
- if (!enabled) {
- // Wait a couple of seconds, then turn the fast path back on. If we're
- // turning it off for event handling, that ensures that the common case of
- // move-mouse-then-click works (as well as making it likely that a second
- // click attempt will work if the first one fails). If we're turning it
- // off to force a new baseline image, this leaves plenty of time for the
- // plugin to draw.
- fast_path_enable_tick_ = base::TimeTicks::Now() +
- base::TimeDelta::FromSeconds(2);
- }
-
- if (enabled == qd_manager_->IsFastPathEnabled())
- return;
- if (enabled && clip_rect_.IsEmpty()) {
- // Don't switch to the fast path while the plugin is completely clipped;
- // we can only switch when the window has an up-to-date image for us to
- // scrape. We'll automatically switch after we become visible again.
- return;
- }
-
- qd_manager_->SetFastPathEnabled(enabled);
- qd_port_.port = qd_manager_->port();
- WindowlessSetWindow();
- // Send a paint event so that the new buffer gets updated immediately.
- WindowlessPaint(buffer_context_, clip_rect_);
-}
-#endif // !NP_NO_QUICKDRAW
-
void WebPluginDelegateImpl::UpdateIdleEventRate() {
bool plugin_visible = container_is_visible_ && !clip_rect_.IsEmpty();
CarbonIdleEventSource::SharedInstance()->RegisterDelegate(this,
plugin_visible);
}
-#endif // !NP_NO_CARBON
-
-// Returns the mask for just the button state in a WebInputEvent's modifiers.
-static int WebEventButtonModifierMask() {
- return WebInputEvent::LeftButtonDown |
- WebInputEvent::RightButtonDown |
- WebInputEvent::MiddleButtonDown;
-}
-
-// Returns a new drag button state from applying |event| to the previous state.
-static int UpdatedDragStateFromEvent(int drag_buttons,
- const WebInputEvent& event) {
- switch (event.type) {
- case WebInputEvent::MouseEnter:
- return event.modifiers & WebEventButtonModifierMask();
- case WebInputEvent::MouseUp: {
- const WebMouseEvent* mouse_event =
- static_cast<const WebMouseEvent*>(&event);
- int new_buttons = drag_buttons;
- if (mouse_event->button == WebMouseEvent::ButtonLeft)
- new_buttons &= ~WebInputEvent::LeftButtonDown;
- if (mouse_event->button == WebMouseEvent::ButtonMiddle)
- new_buttons &= ~WebInputEvent::MiddleButtonDown;
- if (mouse_event->button == WebMouseEvent::ButtonRight)
- new_buttons &= ~WebInputEvent::RightButtonDown;
- return new_buttons;
- }
- default:
- return drag_buttons;
- }
-}
-
-// Returns true if this is an event that looks like part of a drag with the
-// given button state.
-static bool EventIsRelatedToDrag(const WebInputEvent& event, int drag_buttons) {
- const WebMouseEvent* mouse_event = static_cast<const WebMouseEvent*>(&event);
- switch (event.type) {
- case WebInputEvent::MouseUp:
- // We only care about release of buttons that were part of the drag.
- return ((mouse_event->button == WebMouseEvent::ButtonLeft &&
- (drag_buttons & WebInputEvent::LeftButtonDown)) ||
- (mouse_event->button == WebMouseEvent::ButtonMiddle &&
- (drag_buttons & WebInputEvent::MiddleButtonDown)) ||
- (mouse_event->button == WebMouseEvent::ButtonRight &&
- (drag_buttons & WebInputEvent::RightButtonDown)));
- case WebInputEvent::MouseEnter:
- return (event.modifiers & WebEventButtonModifierMask()) != 0;
- case WebInputEvent::MouseLeave:
- case WebInputEvent::MouseMove:
- return (drag_buttons &&
- drag_buttons == (event.modifiers & WebEventButtonModifierMask()));
- default:
- return false;
- }
- return false;
-}
-
-bool WebPluginDelegateImpl::PlatformHandleInputEvent(
- const WebInputEvent& event, WebCursorInfo* cursor_info) {
- DCHECK(cursor_info != NULL);
-
- // If we get an event before we've set up the plugin, bail.
- if (!have_called_set_window_)
- return false;
-#ifndef NP_NO_CARBON
- if (instance()->event_model() == NPEventModelCarbon &&
- !np_cg_context_.context) {
- return false;
- }
-#endif
-
- if (WebInputEvent::isMouseEventType(event.type) ||
- event.type == WebInputEvent::MouseWheel) {
- // Ideally we would compute the content origin from the web event using the
- // code below as a safety net for missed content area location changes.
- // Because of <http://crbug.com/9996>, however, only globalX/Y are right if
- // the page has been zoomed, so for now the coordinates we get aren't
- // trustworthy enough to use for corrections.
-#if PLUGIN_SCALING_FIXED
- // Check our plugin location before we send the event to the plugin, just
- // in case we somehow missed a plugin frame change.
- const WebMouseEvent* mouse_event =
- static_cast<const WebMouseEvent*>(&event);
- gfx::Point content_origin(
- mouse_event->globalX - mouse_event->x - window_rect_.x(),
- mouse_event->globalY - mouse_event->y - window_rect_.y());
- if (content_origin.x() != content_area_origin_.x() ||
- content_origin.y() != content_area_origin_.y()) {
- DLOG(WARNING) << "Stale plugin content area location: "
- << content_area_origin_ << " instead of "
- << content_origin;
- SetContentAreaOrigin(content_origin);
- }
-#endif
-
- current_windowless_cursor_.GetCursorInfo(cursor_info);
- }
-
-#ifndef NP_NO_CARBON
- if (instance()->event_model() == NPEventModelCarbon) {
-#ifndef NP_NO_QUICKDRAW
- if (instance()->drawing_model() == NPDrawingModelQuickDraw) {
- if (quirks_ & PLUGIN_QUIRK_ALLOW_FASTER_QUICKDRAW_PATH) {
- // Mouse event handling doesn't work correctly in the fast path mode,
- // so any time we get a mouse event turn the fast path off, but set a
- // time to switch it on again (we don't rely just on MouseLeave because
- // we don't want poor performance in the case of clicking the play
- // button and then leaving the mouse there).
- // This isn't perfect (specifically, click-and-hold doesn't seem to work
- // if the fast path is on), but the slight regression is worthwhile
- // for the improved framerates.
- if (WebInputEvent::isMouseEventType(event.type)) {
- if (event.type == WebInputEvent::MouseLeave) {
- SetQuickDrawFastPathEnabled(true);
- } else {
- SetQuickDrawFastPathEnabled(false);
- }
- // Make sure the plugin wasn't destroyed during the switch.
- if (!instance())
- return false;
- }
- }
-
- qd_manager_->MakePortCurrent();
- }
-#endif
-
- if (event.type == WebInputEvent::MouseMove) {
- return true; // The recurring FireIdleEvent will send null events.
- }
- }
-#endif
-
- // if we do not currently have focus and this is a mouseDown, trigger a
- // notification that we are taking the keyboard focus. We can't just key
- // off of incoming calls to SetFocus, since WebKit may already think we
- // have it if we were the most recently focused element on our parent tab.
- if (event.type == WebInputEvent::MouseDown && !have_focus_) {
- SetFocus();
- // Make sure that the plugin is still there after handling the focus event.
- if (!instance())
- return false;
- }
-
- ScopedActiveDelegate active_delegate(this);
-
- // Create the plugin event structure.
- NPEventModel event_model = instance()->event_model();
- scoped_ptr<PluginWebEventConverter> event_converter(
- PluginWebEventConverterFactory::CreateConverterForModel(event_model));
- if (!(event_converter.get() && event_converter->InitWithEvent(event))) {
- // Silently consume any keyboard event types that we don't handle, so that
- // they don't fall through to the page.
- if (WebInputEvent::isKeyboardEventType(event.type))
- return true;
- return false;
- }
- void* plugin_event = event_converter->plugin_event();
-
- if (instance()->event_model() == NPEventModelCocoa) {
- // We recieve events related to drags starting outside the plugin, but the
- // NPAPI Cocoa event model spec says plugins shouldn't receive them, so
- // filter them out.
- // If we add a page capture mode at the WebKit layer (like the plugin
- // capture mode that handles drags starting inside) this can be removed.
- bool drag_related = EventIsRelatedToDrag(event, external_drag_buttons_);
- external_drag_buttons_ = UpdatedDragStateFromEvent(external_drag_buttons_,
- event);
- if (drag_related) {
- if (event.type == WebInputEvent::MouseUp && !external_drag_buttons_) {
- // When an external drag ends, we need to synthesize a MouseEntered.
- NPCocoaEvent enter_event = *(static_cast<NPCocoaEvent*>(plugin_event));
- enter_event.type = NPCocoaEventMouseEntered;
- NPAPI::ScopedCurrentPluginEvent event_scope(instance(), &enter_event);
- instance()->NPP_HandleEvent(&enter_event);
- }
- return false;
- }
- }
-
-#ifndef PLUGIN_SCALING_FIXED
- // Because of <http://crbug.com/9996>, the non-global coordinates we get for
- // zoomed pages are wrong. As a temporary hack around that bug, override the
- // coordinates we are given with ones computed based on our knowledge of where
- // the plugin is on screen. We only need to do this for Cocoa, since Carbon
- // only uses the global coordinates.
- if (instance()->event_model() == NPEventModelCocoa &&
- (WebInputEvent::isMouseEventType(event.type) ||
- event.type == WebInputEvent::MouseWheel)) {
- const WebMouseEvent* mouse_event =
- static_cast<const WebMouseEvent*>(&event);
- NPCocoaEvent* cocoa_event = static_cast<NPCocoaEvent*>(plugin_event);
- cocoa_event->data.mouse.pluginX =
- mouse_event->globalX - content_area_origin_.x() - window_rect_.x();
- cocoa_event->data.mouse.pluginY =
- mouse_event->globalY - content_area_origin_.y() - window_rect_.y();
- }
-#endif
-
- // Send the plugin the event.
- scoped_ptr<NPAPI::ScopedCurrentPluginEvent> event_scope(NULL);
- if (instance()->event_model() == NPEventModelCocoa) {
- event_scope.reset(new NPAPI::ScopedCurrentPluginEvent(
- instance(), static_cast<NPCocoaEvent*>(plugin_event)));
- }
- bool handled = instance()->NPP_HandleEvent(plugin_event) != 0;
-
- if (WebInputEvent::isMouseEventType(event.type)) {
- // Plugins are not good about giving accurate information about whether or
- // not they handled events, and other browsers on the Mac generally ignore
- // the return value. We may need to expand this to other input types, but
- // we'll need to be careful about things like Command-keys.
- handled = true;
- }
-
- return handled;
-}
-#ifndef NP_NO_CARBON
void WebPluginDelegateImpl::FireIdleEvent() {
// Avoid a race condition between IO and UI threads during plugin shutdown
if (!instance())
@@ -1099,10 +1104,41 @@ void WebPluginDelegateImpl::FireIdleEvent() {
#ifndef NP_NO_QUICKDRAW
// Quickdraw-based plugins can draw at any time, so tell the renderer to
// repaint.
- // TODO: only do this if the contents of the offscreen window/buffer have
- // changed, so as not to spam the renderer with an unchanging image.
if (instance() && instance()->drawing_model() == NPDrawingModelQuickDraw)
instance()->webplugin()->Invalidate();
#endif
}
#endif // !NP_NO_CARBON
+
+#pragma mark -
+#pragma mark QuickDraw Support
+
+#ifndef NP_NO_QUICKDRAW
+void WebPluginDelegateImpl::SetQuickDrawFastPathEnabled(bool enabled) {
+ if (!enabled) {
+ // Wait a couple of seconds, then turn the fast path back on. If we're
+ // turning it off for event handling, that ensures that the common case of
+ // move-mouse-then-click works (as well as making it likely that a second
+ // click attempt will work if the first one fails). If we're turning it
+ // off to force a new baseline image, this leaves plenty of time for the
+ // plugin to draw.
+ fast_path_enable_tick_ = base::TimeTicks::Now() +
+ base::TimeDelta::FromSeconds(2);
+ }
+
+ if (enabled == qd_manager_->IsFastPathEnabled())
+ return;
+ if (enabled && clip_rect_.IsEmpty()) {
+ // Don't switch to the fast path while the plugin is completely clipped;
+ // we can only switch when the window has an up-to-date image for us to
+ // scrape. We'll automatically switch after we become visible again.
+ return;
+ }
+
+ qd_manager_->SetFastPathEnabled(enabled);
+ qd_port_.port = qd_manager_->port();
+ WindowlessSetWindow();
+ // Send a paint event so that the new buffer gets updated immediately.
+ WindowlessPaint(buffer_context_, clip_rect_);
+}
+#endif // !NP_NO_QUICKDRAW