[email protected] | 6ce58c8a | 2011-02-07 16:19:51 | [diff] [blame] | 1 | // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
[email protected] | 39b8c513 | 2009-02-11 07:48:22 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
[email protected] | 6bf1a81 | 2009-07-11 01:57:28 | [diff] [blame] | 5 | #import <Cocoa/Cocoa.h> |
[email protected] | 3d1e89d | 2010-03-10 20:01:35 | [diff] [blame] | 6 | #import <QuartzCore/QuartzCore.h> |
[email protected] | 6bf1a81 | 2009-07-11 01:57:28 | [diff] [blame] | 7 | |
[email protected] | 191eb3f7 | 2010-12-21 06:27:50 | [diff] [blame] | 8 | #include "webkit/plugins/npapi/webplugin_delegate_impl.h" |
[email protected] | 39b8c513 | 2009-02-11 07:48:22 | [diff] [blame] | 9 | |
| 10 | #include <string> |
[email protected] | 27f5a6c8 | 2009-11-20 18:26:16 | [diff] [blame] | 11 | #include <unistd.h> |
[email protected] | bc384e4a | 2010-01-21 17:26:28 | [diff] [blame] | 12 | #include <set> |
[email protected] | 39b8c513 | 2009-02-11 07:48:22 | [diff] [blame] | 13 | |
| 14 | #include "base/file_util.h" |
[email protected] | 3b63f8f4 | 2011-03-28 01:54:15 | [diff] [blame^] | 15 | #include "base/memory/scoped_ptr.h" |
[email protected] | 39b8c513 | 2009-02-11 07:48:22 | [diff] [blame] | 16 | #include "base/message_loop.h" |
[email protected] | 835d7c8 | 2010-10-14 04:38:38 | [diff] [blame] | 17 | #include "base/metrics/stats_counters.h" |
[email protected] | 39b8c513 | 2009-02-11 07:48:22 | [diff] [blame] | 18 | #include "base/string_util.h" |
[email protected] | 81e34d8 | 2010-08-19 18:36:25 | [diff] [blame] | 19 | #include "base/utf_string_conversions.h" |
[email protected] | b7f7586 | 2011-01-21 21:15:13 | [diff] [blame] | 20 | #include "base/sys_info.h" |
[email protected] | 935d63d | 2010-10-15 23:31:55 | [diff] [blame] | 21 | #include "base/sys_string_conversions.h" |
[email protected] | c1d9cdc | 2011-01-17 06:50:01 | [diff] [blame] | 22 | #include "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.h" |
[email protected] | 39b8c513 | 2009-02-11 07:48:22 | [diff] [blame] | 23 | #include "webkit/glue/webkit_glue.h" |
[email protected] | 191eb3f7 | 2010-12-21 06:27:50 | [diff] [blame] | 24 | #include "webkit/plugins/npapi/plugin_instance.h" |
| 25 | #include "webkit/plugins/npapi/plugin_lib.h" |
| 26 | #include "webkit/plugins/npapi/plugin_list.h" |
| 27 | #include "webkit/plugins/npapi/plugin_stream_url.h" |
| 28 | #include "webkit/plugins/npapi/plugin_web_event_converter_mac.h" |
| 29 | #include "webkit/plugins/npapi/webplugin.h" |
| 30 | #include "webkit/plugins/npapi/webplugin_accelerated_surface_mac.h" |
[email protected] | 39b8c513 | 2009-02-11 07:48:22 | [diff] [blame] | 31 | |
[email protected] | ae40ccd | 2010-03-02 23:45:21 | [diff] [blame] | 32 | #ifndef NP_NO_CARBON |
[email protected] | 191eb3f7 | 2010-12-21 06:27:50 | [diff] [blame] | 33 | #include "webkit/plugins/npapi/carbon_plugin_window_tracker_mac.h" |
[email protected] | ae40ccd | 2010-03-02 23:45:21 | [diff] [blame] | 34 | #endif |
| 35 | |
[email protected] | 760cd212 | 2009-10-13 17:53:22 | [diff] [blame] | 36 | #ifndef NP_NO_QUICKDRAW |
[email protected] | 191eb3f7 | 2010-12-21 06:27:50 | [diff] [blame] | 37 | #include "webkit/plugins/npapi/quickdraw_drawing_manager_mac.h" |
[email protected] | 760cd212 | 2009-10-13 17:53:22 | [diff] [blame] | 38 | #endif |
| 39 | |
[email protected] | 7c51b0ee | 2009-07-08 21:49:30 | [diff] [blame] | 40 | using WebKit::WebCursorInfo; |
[email protected] | 41fbf09 | 2009-05-22 01:29:05 | [diff] [blame] | 41 | using WebKit::WebKeyboardEvent; |
| 42 | using WebKit::WebInputEvent; |
| 43 | using WebKit::WebMouseEvent; |
[email protected] | 7b032aa6 | 2009-11-06 17:08:36 | [diff] [blame] | 44 | using WebKit::WebMouseWheelEvent; |
[email protected] | 41fbf09 | 2009-05-22 01:29:05 | [diff] [blame] | 45 | |
[email protected] | 6bf1a81 | 2009-07-11 01:57:28 | [diff] [blame] | 46 | // Important implementation notes: The Mac definition of NPAPI, particularly |
| 47 | // the distinction between windowed and windowless modes, differs from the |
| 48 | // Windows and Linux definitions. Most of those differences are |
| 49 | // accomodated by the WebPluginDelegate class. |
| 50 | |
[email protected] | 191eb3f7 | 2010-12-21 06:27:50 | [diff] [blame] | 51 | namespace webkit { |
| 52 | namespace npapi { |
| 53 | |
[email protected] | 39b8c513 | 2009-02-11 07:48:22 | [diff] [blame] | 54 | namespace { |
| 55 | |
[email protected] | 191eb3f7 | 2010-12-21 06:27:50 | [diff] [blame] | 56 | const int kCoreAnimationRedrawPeriodMs = 10; // 100 Hz |
| 57 | |
[email protected] | b4ec5d9 | 2010-01-19 19:24:24 | [diff] [blame] | 58 | WebPluginDelegateImpl* g_active_delegate; |
| 59 | |
| 60 | // Helper to simplify correct usage of g_active_delegate. Instantiating will |
| 61 | // set the active delegate to |delegate| for the lifetime of the object, then |
| 62 | // NULL when it goes out of scope. |
| 63 | class ScopedActiveDelegate { |
[email protected] | 191eb3f7 | 2010-12-21 06:27:50 | [diff] [blame] | 64 | public: |
[email protected] | b4ec5d9 | 2010-01-19 19:24:24 | [diff] [blame] | 65 | explicit ScopedActiveDelegate(WebPluginDelegateImpl* delegate) { |
| 66 | g_active_delegate = delegate; |
| 67 | } |
| 68 | ~ScopedActiveDelegate() { |
| 69 | g_active_delegate = NULL; |
| 70 | } |
[email protected] | 191eb3f7 | 2010-12-21 06:27:50 | [diff] [blame] | 71 | |
| 72 | private: |
[email protected] | b4ec5d9 | 2010-01-19 19:24:24 | [diff] [blame] | 73 | DISALLOW_COPY_AND_ASSIGN(ScopedActiveDelegate); |
| 74 | }; |
| 75 | |
[email protected] | bc384e4a | 2010-01-21 17:26:28 | [diff] [blame] | 76 | #ifndef NP_NO_CARBON |
[email protected] | 385579b | 2010-01-21 20:18:48 | [diff] [blame] | 77 | // Timer periods for sending idle events to Carbon plugins. The visible value |
| 78 | // (50Hz) matches both Safari and Firefox. The hidden value (8Hz) matches |
| 79 | // Firefox; according to https://bugzilla.mozilla.org/show_bug.cgi?id=525533 |
| 80 | // going lower than that causes issues. |
| 81 | const int kVisibleIdlePeriodMs = 20; // (50Hz) |
| 82 | const int kHiddenIdlePeriodMs = 125; // (8Hz) |
| 83 | |
[email protected] | bc384e4a | 2010-01-21 17:26:28 | [diff] [blame] | 84 | class CarbonIdleEventSource { |
| 85 | public: |
| 86 | // Returns the shared Carbon idle event source. |
| 87 | static CarbonIdleEventSource* SharedInstance() { |
| 88 | DCHECK(MessageLoop::current()->type() == MessageLoop::TYPE_UI); |
| 89 | static CarbonIdleEventSource* event_source = new CarbonIdleEventSource(); |
| 90 | return event_source; |
| 91 | } |
| 92 | |
[email protected] | 80635063 | 2010-02-05 17:39:36 | [diff] [blame] | 93 | // Registers the plugin delegate as interested in receiving idle events at |
| 94 | // a rate appropriate for the given visibility. A delegate can safely be |
| 95 | // re-registered any number of times, with the latest registration winning. |
| 96 | void RegisterDelegate(WebPluginDelegateImpl* delegate, bool visible) { |
| 97 | if (visible) { |
| 98 | visible_delegates_->RegisterDelegate(delegate); |
| 99 | hidden_delegates_->UnregisterDelegate(delegate); |
| 100 | } else { |
| 101 | hidden_delegates_->RegisterDelegate(delegate); |
| 102 | visible_delegates_->UnregisterDelegate(delegate); |
[email protected] | bc384e4a | 2010-01-21 17:26:28 | [diff] [blame] | 103 | } |
[email protected] | bc384e4a | 2010-01-21 17:26:28 | [diff] [blame] | 104 | } |
| 105 | |
| 106 | // Removes the plugin delegate from the list of plugins receiving idle events. |
| 107 | void UnregisterDelegate(WebPluginDelegateImpl* delegate) { |
[email protected] | 80635063 | 2010-02-05 17:39:36 | [diff] [blame] | 108 | visible_delegates_->UnregisterDelegate(delegate); |
| 109 | hidden_delegates_->UnregisterDelegate(delegate); |
[email protected] | bc384e4a | 2010-01-21 17:26:28 | [diff] [blame] | 110 | } |
| 111 | |
| 112 | private: |
[email protected] | 80635063 | 2010-02-05 17:39:36 | [diff] [blame] | 113 | class VisibilityGroup { |
| 114 | public: |
| 115 | explicit VisibilityGroup(int timer_period) |
| 116 | : timer_period_(timer_period), iterator_(delegates_.end()) {} |
[email protected] | bc384e4a | 2010-01-21 17:26:28 | [diff] [blame] | 117 | |
[email protected] | 80635063 | 2010-02-05 17:39:36 | [diff] [blame] | 118 | // Adds |delegate| to this visibility group. |
| 119 | void RegisterDelegate(WebPluginDelegateImpl* delegate) { |
| 120 | if (delegates_.empty()) { |
| 121 | timer_.Start(base::TimeDelta::FromMilliseconds(timer_period_), |
| 122 | this, &VisibilityGroup::SendIdleEvents); |
| 123 | } |
| 124 | delegates_.insert(delegate); |
[email protected] | bc384e4a | 2010-01-21 17:26:28 | [diff] [blame] | 125 | } |
[email protected] | bc384e4a | 2010-01-21 17:26:28 | [diff] [blame] | 126 | |
[email protected] | 80635063 | 2010-02-05 17:39:36 | [diff] [blame] | 127 | // Removes |delegate| from this visibility group. |
| 128 | void UnregisterDelegate(WebPluginDelegateImpl* delegate) { |
| 129 | // If a plugin changes visibility during idle event handling, it |
| 130 | // may be removed from this set while SendIdleEvents is still iterating; |
| 131 | // if that happens and it's next on the list, increment the iterator |
| 132 | // before erasing so that the iteration won't be corrupted. |
| 133 | if ((iterator_ != delegates_.end()) && (*iterator_ == delegate)) |
| 134 | ++iterator_; |
| 135 | size_t removed = delegates_.erase(delegate); |
| 136 | if (removed > 0 && delegates_.empty()) |
| 137 | timer_.Stop(); |
| 138 | } |
| 139 | |
| 140 | private: |
| 141 | // Fires off idle events for each delegate in the group. |
| 142 | void SendIdleEvents() { |
| 143 | for (iterator_ = delegates_.begin(); iterator_ != delegates_.end();) { |
| 144 | // Pre-increment so that the skip logic in UnregisterDelegates works. |
| 145 | WebPluginDelegateImpl* delegate = *(iterator_++); |
| 146 | delegate->FireIdleEvent(); |
| 147 | } |
| 148 | } |
| 149 | |
| 150 | int timer_period_; |
| 151 | base::RepeatingTimer<VisibilityGroup> timer_; |
| 152 | std::set<WebPluginDelegateImpl*> delegates_; |
| 153 | std::set<WebPluginDelegateImpl*>::iterator iterator_; |
| 154 | }; |
| 155 | |
| 156 | CarbonIdleEventSource() |
| 157 | : visible_delegates_(new VisibilityGroup(kVisibleIdlePeriodMs)), |
| 158 | hidden_delegates_(new VisibilityGroup(kHiddenIdlePeriodMs)) {} |
| 159 | |
| 160 | scoped_ptr<VisibilityGroup> visible_delegates_; |
| 161 | scoped_ptr<VisibilityGroup> hidden_delegates_; |
| 162 | |
| 163 | DISALLOW_COPY_AND_ASSIGN(CarbonIdleEventSource); |
[email protected] | bc384e4a | 2010-01-21 17:26:28 | [diff] [blame] | 164 | }; |
[email protected] | 385579b | 2010-01-21 20:18:48 | [diff] [blame] | 165 | #endif // !NP_NO_CARBON |
[email protected] | bc384e4a | 2010-01-21 17:26:28 | [diff] [blame] | 166 | |
[email protected] | 39b8c513 | 2009-02-11 07:48:22 | [diff] [blame] | 167 | } // namespace |
| 168 | |
[email protected] | 7ba38183 | 2010-04-16 15:02:37 | [diff] [blame] | 169 | // Helper to build and maintain a model of a drag entering the plugin but not |
| 170 | // starting there. See explanation in PlatformHandleInputEvent. |
| 171 | class ExternalDragTracker { |
| 172 | public: |
| 173 | ExternalDragTracker() : pressed_buttons_(0) {} |
| 174 | |
| 175 | // Returns true if an external drag is in progress. |
| 176 | bool IsDragInProgress() { return pressed_buttons_ != 0; }; |
| 177 | |
| 178 | // Returns true if the given event appears to be related to an external drag. |
| 179 | bool EventIsRelatedToDrag(const WebInputEvent& event); |
| 180 | |
| 181 | // Updates the tracking of whether an external drag is in progress--and if |
| 182 | // so what buttons it involves--based on the given event. |
| 183 | void UpdateDragStateFromEvent(const WebInputEvent& event); |
| 184 | |
| 185 | private: |
| 186 | // Returns the mask for just the button state in a WebInputEvent's modifiers. |
| 187 | static int WebEventButtonModifierMask(); |
| 188 | |
| 189 | // The WebInputEvent modifier flags for any buttons that were down when an |
| 190 | // external drag entered the plugin, and which and are still down now. |
| 191 | int pressed_buttons_; |
| 192 | |
| 193 | DISALLOW_COPY_AND_ASSIGN(ExternalDragTracker); |
| 194 | }; |
| 195 | |
| 196 | void ExternalDragTracker::UpdateDragStateFromEvent(const WebInputEvent& event) { |
| 197 | switch (event.type) { |
| 198 | case WebInputEvent::MouseEnter: |
| 199 | pressed_buttons_ = event.modifiers & WebEventButtonModifierMask(); |
| 200 | break; |
| 201 | case WebInputEvent::MouseUp: { |
| 202 | const WebMouseEvent* mouse_event = |
| 203 | static_cast<const WebMouseEvent*>(&event); |
| 204 | if (mouse_event->button == WebMouseEvent::ButtonLeft) |
| 205 | pressed_buttons_ &= ~WebInputEvent::LeftButtonDown; |
| 206 | if (mouse_event->button == WebMouseEvent::ButtonMiddle) |
| 207 | pressed_buttons_ &= ~WebInputEvent::MiddleButtonDown; |
| 208 | if (mouse_event->button == WebMouseEvent::ButtonRight) |
| 209 | pressed_buttons_ &= ~WebInputEvent::RightButtonDown; |
| 210 | break; |
| 211 | } |
| 212 | default: |
| 213 | break; |
| 214 | } |
| 215 | } |
| 216 | |
| 217 | bool ExternalDragTracker::EventIsRelatedToDrag(const WebInputEvent& event) { |
| 218 | const WebMouseEvent* mouse_event = static_cast<const WebMouseEvent*>(&event); |
| 219 | switch (event.type) { |
| 220 | case WebInputEvent::MouseUp: |
| 221 | // We only care about release of buttons that were part of the drag. |
| 222 | return ((mouse_event->button == WebMouseEvent::ButtonLeft && |
| 223 | (pressed_buttons_ & WebInputEvent::LeftButtonDown)) || |
| 224 | (mouse_event->button == WebMouseEvent::ButtonMiddle && |
| 225 | (pressed_buttons_ & WebInputEvent::MiddleButtonDown)) || |
| 226 | (mouse_event->button == WebMouseEvent::ButtonRight && |
| 227 | (pressed_buttons_ & WebInputEvent::RightButtonDown))); |
| 228 | case WebInputEvent::MouseEnter: |
| 229 | return (event.modifiers & WebEventButtonModifierMask()) != 0; |
| 230 | case WebInputEvent::MouseLeave: |
| 231 | case WebInputEvent::MouseMove: { |
| 232 | int event_buttons = (event.modifiers & WebEventButtonModifierMask()); |
| 233 | return (pressed_buttons_ && |
| 234 | pressed_buttons_ == event_buttons); |
| 235 | } |
| 236 | default: |
| 237 | return false; |
| 238 | } |
| 239 | return false; |
| 240 | } |
| 241 | |
| 242 | int ExternalDragTracker::WebEventButtonModifierMask() { |
| 243 | return WebInputEvent::LeftButtonDown | |
| 244 | WebInputEvent::RightButtonDown | |
| 245 | WebInputEvent::MiddleButtonDown; |
| 246 | } |
| 247 | |
[email protected] | 3d1e89d | 2010-03-10 20:01:35 | [diff] [blame] | 248 | #pragma mark - |
[email protected] | 7ba38183 | 2010-04-16 15:02:37 | [diff] [blame] | 249 | #pragma mark Core WebPluginDelegate implementation |
[email protected] | 3d1e89d | 2010-03-10 20:01:35 | [diff] [blame] | 250 | |
[email protected] | 39b8c513 | 2009-02-11 07:48:22 | [diff] [blame] | 251 | WebPluginDelegateImpl::WebPluginDelegateImpl( |
[email protected] | 700d3d5 | 2009-07-07 17:40:46 | [diff] [blame] | 252 | gfx::PluginWindowHandle containing_view, |
[email protected] | 191eb3f7 | 2010-12-21 06:27:50 | [diff] [blame] | 253 | PluginInstance *instance) |
[email protected] | 3d1e89d | 2010-03-10 20:01:35 | [diff] [blame] | 254 | : windowed_handle_(NULL), |
[email protected] | 6bf1a81 | 2009-07-11 01:57:28 | [diff] [blame] | 255 | // all Mac plugins are "windowless" in the Windows/X11 sense |
| 256 | windowless_(true), |
[email protected] | be21555 | 2009-09-21 20:12:56 | [diff] [blame] | 257 | plugin_(NULL), |
| 258 | instance_(instance), |
| 259 | parent_(containing_view), |
[email protected] | 7ba38183 | 2010-04-16 15:02:37 | [diff] [blame] | 260 | quirks_(0), |
[email protected] | 33f39d5 | 2010-03-05 16:09:11 | [diff] [blame] | 261 | buffer_context_(NULL), |
[email protected] | 3d1e89d | 2010-03-10 20:01:35 | [diff] [blame] | 262 | layer_(nil), |
| 263 | surface_(NULL), |
| 264 | renderer_(nil), |
[email protected] | 2f2ba98 | 2010-01-21 16:47:08 | [diff] [blame] | 265 | containing_window_has_focus_(false), |
[email protected] | 1e6e3c99 | 2010-02-08 15:52:13 | [diff] [blame] | 266 | initial_window_focus_(false), |
[email protected] | 941e455 | 2010-02-01 21:23:43 | [diff] [blame] | 267 | container_is_visible_(false), |
| 268 | have_called_set_window_(false), |
[email protected] | 935d63d | 2010-10-15 23:31:55 | [diff] [blame] | 269 | ime_enabled_(false), |
[email protected] | b7f7586 | 2011-01-21 21:15:13 | [diff] [blame] | 270 | keyup_ignore_count_(0), |
[email protected] | 7ba38183 | 2010-04-16 15:02:37 | [diff] [blame] | 271 | external_drag_tracker_(new ExternalDragTracker()), |
[email protected] | 0c860d0 | 2010-06-15 22:08:35 | [diff] [blame] | 272 | handle_event_depth_(0), |
[email protected] | 784ea1ab | 2010-09-18 00:02:34 | [diff] [blame] | 273 | first_set_window_call_(true), |
| 274 | plugin_has_focus_(false), |
| 275 | has_webkit_focus_(false), |
[email protected] | 5fd5d03 | 2010-11-30 01:01:01 | [diff] [blame] | 276 | containing_view_has_focus_(true), |
| 277 | creation_succeeded_(false) { |
[email protected] | 39b8c513 | 2009-02-11 07:48:22 | [diff] [blame] | 278 | memset(&window_, 0, sizeof(window_)); |
[email protected] | 8aff32f | 2010-01-07 17:16:27 | [diff] [blame] | 279 | #ifndef NP_NO_CARBON |
[email protected] | 33f39d5 | 2010-03-05 16:09:11 | [diff] [blame] | 280 | memset(&np_cg_context_, 0, sizeof(np_cg_context_)); |
[email protected] | 8aff32f | 2010-01-07 17:16:27 | [diff] [blame] | 281 | #endif |
[email protected] | 760cd212 | 2009-10-13 17:53:22 | [diff] [blame] | 282 | #ifndef NP_NO_QUICKDRAW |
| 283 | memset(&qd_port_, 0, sizeof(qd_port_)); |
| 284 | #endif |
[email protected] | 81895a4 | 2009-11-11 21:33:12 | [diff] [blame] | 285 | instance->set_windowless(true); |
[email protected] | 39b8c513 | 2009-02-11 07:48:22 | [diff] [blame] | 286 | } |
| 287 | |
| 288 | WebPluginDelegateImpl::~WebPluginDelegateImpl() { |
[email protected] | c1a9443 | 2010-02-11 16:17:39 | [diff] [blame] | 289 | DestroyInstance(); |
| 290 | |
[email protected] | 8aff32f | 2010-01-07 17:16:27 | [diff] [blame] | 291 | #ifndef NP_NO_CARBON |
[email protected] | 33f39d5 | 2010-03-05 16:09:11 | [diff] [blame] | 292 | if (np_cg_context_.window) { |
[email protected] | ae40ccd | 2010-03-02 23:45:21 | [diff] [blame] | 293 | CarbonPluginWindowTracker::SharedInstance()->DestroyDummyWindowForDelegate( |
[email protected] | 33f39d5 | 2010-03-05 16:09:11 | [diff] [blame] | 294 | this, reinterpret_cast<WindowRef>(np_cg_context_.window)); |
[email protected] | 8aff32f | 2010-01-07 17:16:27 | [diff] [blame] | 295 | } |
[email protected] | 8aff32f | 2010-01-07 17:16:27 | [diff] [blame] | 296 | #endif |
[email protected] | 39b8c513 | 2009-02-11 07:48:22 | [diff] [blame] | 297 | } |
| 298 | |
[email protected] | 3411060 | 2010-04-06 16:03:08 | [diff] [blame] | 299 | bool WebPluginDelegateImpl::PlatformInitialize() { |
[email protected] | 81895a4 | 2009-11-11 21:33:12 | [diff] [blame] | 300 | // Don't set a NULL window handle on destroy for Mac plugins. This matches |
| 301 | // Safari and other Mac browsers (see PluginView::stop() in PluginView.cpp, |
| 302 | // where code to do so is surrounded by an #ifdef that excludes Mac OS X, or |
| 303 | // destroyPlugin in WebNetscapePluginView.mm, for examples). |
| 304 | quirks_ |= PLUGIN_QUIRK_DONT_SET_NULL_WINDOW_HANDLE_ON_DESTROY; |
[email protected] | 4d9ef386a | 2009-11-06 20:13:11 | [diff] [blame] | 305 | |
[email protected] | 42ed07c | 2010-04-14 16:11:49 | [diff] [blame] | 306 | // Mac plugins don't expect to be unloaded, and they don't always do so |
| 307 | // cleanly, so don't unload them at shutdown. |
| 308 | instance()->plugin_lib()->PreventLibraryUnload(); |
[email protected] | c18388fb | 2010-02-11 21:10:25 | [diff] [blame] | 309 | |
[email protected] | 779b881 | 2010-03-26 18:55:09 | [diff] [blame] | 310 | #ifndef NP_NO_QUICKDRAW |
| 311 | if (instance()->drawing_model() == NPDrawingModelQuickDraw) { |
| 312 | // For some QuickDraw plugins, we can sometimes get away with giving them |
| 313 | // a port pointing to a pixel buffer instead of a our actual dummy window. |
| 314 | // This gives us much better frame rates, because the window scraping we |
| 315 | // normally use is very slow. |
| 316 | // This breaks down if the plugin does anything complicated with the port |
| 317 | // (as QuickTime seems to during event handling, and sometimes when painting |
| 318 | // its controls), so we switch on the fly as necessary. (It might be |
| 319 | // possible to interpose sufficiently that we wouldn't have to switch back |
| 320 | // and forth, but the current approach gets us most of the benefit.) |
| 321 | // We can't do this at all with plugins that bypass the port entirely and |
| 322 | // attaches their own surface to the window. |
| 323 | // TODO(stuartmorgan): Test other QuickDraw plugins that we support and |
| 324 | // see if any others can use the fast path. |
| 325 | const WebPluginInfo& plugin_info = instance_->plugin_lib()->plugin_info(); |
[email protected] | c9d81137 | 2010-06-23 21:44:57 | [diff] [blame] | 326 | if (plugin_info.name.find(ASCIIToUTF16("QuickTime")) != string16::npos) |
[email protected] | 779b881 | 2010-03-26 18:55:09 | [diff] [blame] | 327 | quirks_ |= PLUGIN_QUIRK_ALLOW_FASTER_QUICKDRAW_PATH; |
| 328 | } |
| 329 | #endif |
| 330 | |
[email protected] | 8aff32f | 2010-01-07 17:16:27 | [diff] [blame] | 331 | #ifndef NP_NO_CARBON |
| 332 | if (instance()->event_model() == NPEventModelCarbon) { |
| 333 | // Create a stand-in for the browser window so that the plugin will have |
| 334 | // a non-NULL WindowRef to which it can refer. |
[email protected] | ae40ccd | 2010-03-02 23:45:21 | [diff] [blame] | 335 | CarbonPluginWindowTracker* window_tracker = |
| 336 | CarbonPluginWindowTracker::SharedInstance(); |
[email protected] | 33f39d5 | 2010-03-05 16:09:11 | [diff] [blame] | 337 | np_cg_context_.window = window_tracker->CreateDummyWindowForDelegate(this); |
| 338 | np_cg_context_.context = NULL; |
[email protected] | f374cebc | 2010-03-03 23:46:03 | [diff] [blame] | 339 | UpdateDummyWindowBounds(gfx::Point(0, 0)); |
[email protected] | 8aff32f | 2010-01-07 17:16:27 | [diff] [blame] | 340 | } |
| 341 | #endif |
[email protected] | 760cd212 | 2009-10-13 17:53:22 | [diff] [blame] | 342 | |
[email protected] | 51a0bb5 | 2010-06-03 21:34:06 | [diff] [blame] | 343 | NPDrawingModel drawing_model = instance()->drawing_model(); |
| 344 | switch (drawing_model) { |
[email protected] | 760cd212 | 2009-10-13 17:53:22 | [diff] [blame] | 345 | #ifndef NP_NO_QUICKDRAW |
| 346 | case NPDrawingModelQuickDraw: |
[email protected] | 3411060 | 2010-04-06 16:03:08 | [diff] [blame] | 347 | if (instance()->event_model() != NPEventModelCarbon) |
| 348 | return false; |
[email protected] | 4491a78 | 2010-04-12 15:38:44 | [diff] [blame] | 349 | qd_manager_.reset(new QuickDrawDrawingManager()); |
| 350 | qd_manager_->SetPluginWindow( |
| 351 | reinterpret_cast<WindowRef>(np_cg_context_.window)); |
| 352 | qd_port_.port = qd_manager_->port(); |
[email protected] | 760cd212 | 2009-10-13 17:53:22 | [diff] [blame] | 353 | window_.window = &qd_port_; |
| 354 | window_.type = NPWindowTypeDrawable; |
| 355 | break; |
| 356 | #endif |
| 357 | case NPDrawingModelCoreGraphics: |
[email protected] | 8aff32f | 2010-01-07 17:16:27 | [diff] [blame] | 358 | #ifndef NP_NO_CARBON |
[email protected] | 227b543 | 2010-01-07 17:56:51 | [diff] [blame] | 359 | if (instance()->event_model() == NPEventModelCarbon) |
[email protected] | 33f39d5 | 2010-03-05 16:09:11 | [diff] [blame] | 360 | window_.window = &np_cg_context_; |
[email protected] | 8aff32f | 2010-01-07 17:16:27 | [diff] [blame] | 361 | #endif |
[email protected] | 760cd212 | 2009-10-13 17:53:22 | [diff] [blame] | 362 | window_.type = NPWindowTypeDrawable; |
| 363 | break; |
[email protected] | 51a0bb5 | 2010-06-03 21:34:06 | [diff] [blame] | 364 | case NPDrawingModelCoreAnimation: |
| 365 | case NPDrawingModelInvalidatingCoreAnimation: { |
[email protected] | 3411060 | 2010-04-06 16:03:08 | [diff] [blame] | 366 | if (instance()->event_model() != NPEventModelCocoa) |
| 367 | return false; |
[email protected] | 3d1e89d | 2010-03-10 20:01:35 | [diff] [blame] | 368 | window_.type = NPWindowTypeDrawable; |
[email protected] | 8b4755f | 2010-10-01 18:04:06 | [diff] [blame] | 369 | // Ask the plug-in for the CALayer it created for rendering content. |
| 370 | // Create a surface to host it, and request a "window" handle to identify |
| 371 | // the surface. |
[email protected] | 3d1e89d | 2010-03-10 20:01:35 | [diff] [blame] | 372 | CALayer* layer = nil; |
| 373 | NPError err = instance()->NPP_GetValue(NPPVpluginCoreAnimationLayer, |
| 374 | reinterpret_cast<void*>(&layer)); |
| 375 | if (!err) { |
[email protected] | 51a0bb5 | 2010-06-03 21:34:06 | [diff] [blame] | 376 | if (drawing_model == NPDrawingModelCoreAnimation) { |
| 377 | // Create the timer; it will be started when we get a window handle. |
| 378 | redraw_timer_.reset(new base::RepeatingTimer<WebPluginDelegateImpl>); |
| 379 | } |
[email protected] | 3d1e89d | 2010-03-10 20:01:35 | [diff] [blame] | 380 | layer_ = layer; |
[email protected] | 8b4755f | 2010-10-01 18:04:06 | [diff] [blame] | 381 | surface_ = plugin_->GetAcceleratedSurface(); |
| 382 | |
[email protected] | d92bec4 | 2010-11-22 22:49:34 | [diff] [blame] | 383 | // If surface initialization fails for some reason, just continue |
| 384 | // without any drawing; returning false would be a more confusing user |
| 385 | // experience (since it triggers a missing plugin placeholder). |
[email protected] | c651f6e | 2011-02-24 09:19:48 | [diff] [blame] | 386 | if (surface_ && surface_->context()) { |
[email protected] | d92bec4 | 2010-11-22 22:49:34 | [diff] [blame] | 387 | renderer_ = [[CARenderer rendererWithCGLContext:surface_->context() |
| 388 | options:NULL] retain]; |
| 389 | [renderer_ setLayer:layer_]; |
| 390 | } |
[email protected] | 4736973b | 2010-04-28 17:56:42 | [diff] [blame] | 391 | plugin_->BindFakePluginWindowHandle(false); |
[email protected] | 3d1e89d | 2010-03-10 20:01:35 | [diff] [blame] | 392 | } |
| 393 | break; |
| 394 | } |
[email protected] | 760cd212 | 2009-10-13 17:53:22 | [diff] [blame] | 395 | default: |
| 396 | NOTREACHED(); |
| 397 | break; |
| 398 | } |
[email protected] | 6ef2d78d | 2009-09-02 23:49:05 | [diff] [blame] | 399 | |
[email protected] | ee48d17 | 2010-03-18 17:30:52 | [diff] [blame] | 400 | // Let the WebPlugin know that we are windowless (unless this is a |
| 401 | // Core Animation plugin, in which case BindFakePluginWindowHandle will take |
| 402 | // care of setting up the appropriate window handle). |
[email protected] | 23607ccf | 2010-06-03 23:15:33 | [diff] [blame] | 403 | if (!layer_) |
[email protected] | ee48d17 | 2010-03-18 17:30:52 | [diff] [blame] | 404 | plugin_->SetWindow(NULL); |
| 405 | |
[email protected] | 8aff32f | 2010-01-07 17:16:27 | [diff] [blame] | 406 | #ifndef NP_NO_CARBON |
[email protected] | bc384e4a | 2010-01-21 17:26:28 | [diff] [blame] | 407 | // If the plugin wants Carbon events, hook up to the source of idle events. |
| 408 | if (instance()->event_model() == NPEventModelCarbon) |
[email protected] | 385579b | 2010-01-21 20:18:48 | [diff] [blame] | 409 | UpdateIdleEventRate(); |
[email protected] | 8aff32f | 2010-01-07 17:16:27 | [diff] [blame] | 410 | #endif |
[email protected] | 0a46d19 | 2010-02-26 00:16:21 | [diff] [blame] | 411 | |
[email protected] | cbc02a6 | 2010-03-30 15:10:18 | [diff] [blame] | 412 | // QuickTime (in QD mode only) can crash if it gets other calls (e.g., |
| 413 | // NPP_Write) before it gets a SetWindow call, so call SetWindow (with a 0x0 |
| 414 | // rect) immediately. |
| 415 | #ifndef NP_NO_QUICKDRAW |
| 416 | if (instance()->drawing_model() == NPDrawingModelQuickDraw) { |
| 417 | const WebPluginInfo& plugin_info = instance_->plugin_lib()->plugin_info(); |
[email protected] | c9d81137 | 2010-06-23 21:44:57 | [diff] [blame] | 418 | if (plugin_info.name.find(ASCIIToUTF16("QuickTime")) != string16::npos) |
[email protected] | bc5fc9f | 2010-04-15 14:47:41 | [diff] [blame] | 419 | WindowlessSetWindow(); |
[email protected] | cbc02a6 | 2010-03-30 15:10:18 | [diff] [blame] | 420 | } |
| 421 | #endif |
[email protected] | 3411060 | 2010-04-06 16:03:08 | [diff] [blame] | 422 | |
| 423 | return true; |
[email protected] | 459c700 | 2009-08-26 01:31:20 | [diff] [blame] | 424 | } |
[email protected] | f103ab7 | 2009-09-02 17:10:59 | [diff] [blame] | 425 | |
[email protected] | 459c700 | 2009-08-26 01:31:20 | [diff] [blame] | 426 | void WebPluginDelegateImpl::PlatformDestroyInstance() { |
[email protected] | 23563dc1e | 2010-02-16 16:11:00 | [diff] [blame] | 427 | #ifndef NP_NO_CARBON |
[email protected] | bc384e4a | 2010-01-21 17:26:28 | [diff] [blame] | 428 | if (instance()->event_model() == NPEventModelCarbon) |
| 429 | CarbonIdleEventSource::SharedInstance()->UnregisterDelegate(this); |
[email protected] | 23563dc1e | 2010-02-16 16:11:00 | [diff] [blame] | 430 | #endif |
[email protected] | 3d1e89d | 2010-03-10 20:01:35 | [diff] [blame] | 431 | if (redraw_timer_.get()) |
| 432 | redraw_timer_->Stop(); |
| 433 | [renderer_ release]; |
| 434 | renderer_ = nil; |
| 435 | layer_ = nil; |
[email protected] | 6ef2d78d | 2009-09-02 23:49:05 | [diff] [blame] | 436 | } |
| 437 | |
[email protected] | 2b5b8ba | 2010-03-06 15:32:44 | [diff] [blame] | 438 | void WebPluginDelegateImpl::UpdateGeometryAndContext( |
| 439 | const gfx::Rect& window_rect, const gfx::Rect& clip_rect, |
| 440 | CGContextRef context) { |
[email protected] | 33f39d5 | 2010-03-05 16:09:11 | [diff] [blame] | 441 | buffer_context_ = context; |
[email protected] | 8aff32f | 2010-01-07 17:16:27 | [diff] [blame] | 442 | #ifndef NP_NO_CARBON |
[email protected] | 2b5b8ba | 2010-03-06 15:32:44 | [diff] [blame] | 443 | if (instance()->event_model() == NPEventModelCarbon) { |
| 444 | // Update the structure that is passed to Carbon+CoreGraphics plugins in |
| 445 | // NPP_SetWindow before calling UpdateGeometry, since that will trigger an |
| 446 | // NPP_SetWindow call if the geometry changes (which is the only time the |
| 447 | // context would be different), and some plugins (e.g., Flash) have an |
| 448 | // internal cache of the context that they only update when NPP_SetWindow |
| 449 | // is called. |
[email protected] | 33f39d5 | 2010-03-05 16:09:11 | [diff] [blame] | 450 | np_cg_context_.context = context; |
[email protected] | 278429b | 2009-08-13 17:56:55 | [diff] [blame] | 451 | } |
[email protected] | 8aff32f | 2010-01-07 17:16:27 | [diff] [blame] | 452 | #endif |
[email protected] | 4491a78 | 2010-04-12 15:38:44 | [diff] [blame] | 453 | #ifndef NP_NO_QUICKDRAW |
| 454 | if (instance()->drawing_model() == NPDrawingModelQuickDraw) |
| 455 | qd_manager_->SetTargetContext(context, window_rect.size()); |
| 456 | #endif |
[email protected] | 2b5b8ba | 2010-03-06 15:32:44 | [diff] [blame] | 457 | UpdateGeometry(window_rect, clip_rect); |
[email protected] | 278429b | 2009-08-13 17:56:55 | [diff] [blame] | 458 | } |
| 459 | |
[email protected] | 39b8c513 | 2009-02-11 07:48:22 | [diff] [blame] | 460 | void WebPluginDelegateImpl::Paint(CGContextRef context, const gfx::Rect& rect) { |
[email protected] | d5a8a42 | 2009-07-29 20:27:09 | [diff] [blame] | 461 | WindowlessPaint(context, rect); |
[email protected] | 33f39d5 | 2010-03-05 16:09:11 | [diff] [blame] | 462 | |
| 463 | #ifndef NP_NO_QUICKDRAW |
[email protected] | 4491a78 | 2010-04-12 15:38:44 | [diff] [blame] | 464 | // Paint events are our cue to dump the current plugin bits into the buffer |
| 465 | // context if we are dealing with a QuickDraw plugin. |
[email protected] | 33f39d5 | 2010-03-05 16:09:11 | [diff] [blame] | 466 | if (instance()->drawing_model() == NPDrawingModelQuickDraw) { |
[email protected] | 4491a78 | 2010-04-12 15:38:44 | [diff] [blame] | 467 | qd_manager_->UpdateContext(); |
[email protected] | 33f39d5 | 2010-03-05 16:09:11 | [diff] [blame] | 468 | } |
| 469 | #endif |
[email protected] | 39b8c513 | 2009-02-11 07:48:22 | [diff] [blame] | 470 | } |
| 471 | |
| 472 | void WebPluginDelegateImpl::Print(CGContextRef context) { |
[email protected] | 7b032aa6 | 2009-11-06 17:08:36 | [diff] [blame] | 473 | NOTIMPLEMENTED(); |
[email protected] | 39b8c513 | 2009-02-11 07:48:22 | [diff] [blame] | 474 | } |
| 475 | |
[email protected] | d7e2df1 | 2010-02-11 23:25:26 | [diff] [blame] | 476 | bool WebPluginDelegateImpl::PlatformHandleInputEvent( |
| 477 | const WebInputEvent& event, WebCursorInfo* cursor_info) { |
| 478 | DCHECK(cursor_info != NULL); |
[email protected] | 39b8c513 | 2009-02-11 07:48:22 | [diff] [blame] | 479 | |
[email protected] | 32c0554d | 2010-04-05 20:57:17 | [diff] [blame] | 480 | // If we get an event before we've set up the plugin, bail. |
[email protected] | 33f39d5 | 2010-03-05 16:09:11 | [diff] [blame] | 481 | if (!have_called_set_window_) |
| 482 | return false; |
[email protected] | 673590a | 2010-01-26 01:40:02 | [diff] [blame] | 483 | #ifndef NP_NO_CARBON |
| 484 | if (instance()->event_model() == NPEventModelCarbon && |
[email protected] | 33f39d5 | 2010-03-05 16:09:11 | [diff] [blame] | 485 | !np_cg_context_.context) { |
[email protected] | 673590a | 2010-01-26 01:40:02 | [diff] [blame] | 486 | return false; |
| 487 | } |
| 488 | #endif |
[email protected] | d5a8a42 | 2009-07-29 20:27:09 | [diff] [blame] | 489 | |
[email protected] | 6c9c89b | 2010-03-30 18:02:11 | [diff] [blame] | 490 | if (WebInputEvent::isMouseEventType(event.type) || |
| 491 | event.type == WebInputEvent::MouseWheel) { |
[email protected] | 1e6e3c99 | 2010-02-08 15:52:13 | [diff] [blame] | 492 | // Check our plugin location before we send the event to the plugin, just |
| 493 | // in case we somehow missed a plugin frame change. |
[email protected] | 0aa54d6 | 2010-01-12 18:31:00 | [diff] [blame] | 494 | const WebMouseEvent* mouse_event = |
| 495 | static_cast<const WebMouseEvent*>(&event); |
[email protected] | 1e6e3c99 | 2010-02-08 15:52:13 | [diff] [blame] | 496 | gfx::Point content_origin( |
| 497 | mouse_event->globalX - mouse_event->x - window_rect_.x(), |
| 498 | mouse_event->globalY - mouse_event->y - window_rect_.y()); |
| 499 | if (content_origin.x() != content_area_origin_.x() || |
| 500 | content_origin.y() != content_area_origin_.y()) { |
[email protected] | f42e1ec3 | 2010-04-12 14:54:55 | [diff] [blame] | 501 | DLOG(WARNING) << "Stale plugin content area location: " |
| 502 | << content_area_origin_ << " instead of " |
| 503 | << content_origin; |
| 504 | SetContentAreaOrigin(content_origin); |
[email protected] | 1e6e3c99 | 2010-02-08 15:52:13 | [diff] [blame] | 505 | } |
[email protected] | 997a47a | 2010-01-15 21:51:19 | [diff] [blame] | 506 | |
[email protected] | d7e2df1 | 2010-02-11 23:25:26 | [diff] [blame] | 507 | current_windowless_cursor_.GetCursorInfo(cursor_info); |
[email protected] | 0aa54d6 | 2010-01-12 18:31:00 | [diff] [blame] | 508 | } |
| 509 | |
[email protected] | b7f7586 | 2011-01-21 21:15:13 | [diff] [blame] | 510 | // Per the Cocoa Plugin IME spec, plugins shoudn't receive keydown or keyup |
| 511 | // events while composition is in progress. Treat them as handled, however, |
| 512 | // since IME is consuming them on behalf of the plugin. |
| 513 | if ((event.type == WebInputEvent::KeyDown && ime_enabled_) || |
| 514 | (event.type == WebInputEvent::KeyUp && keyup_ignore_count_)) { |
| 515 | // Composition ends on a keydown, so ime_enabled_ will be false at keyup; |
| 516 | // because the keydown wasn't sent to the plugin, the keyup shouldn't be |
| 517 | // either (per the spec). |
| 518 | if (event.type == WebInputEvent::KeyDown) |
| 519 | ++keyup_ignore_count_; |
| 520 | else |
| 521 | --keyup_ignore_count_; |
| 522 | return true; |
| 523 | } |
| 524 | |
[email protected] | 779b881 | 2010-03-26 18:55:09 | [diff] [blame] | 525 | #ifndef NP_NO_CARBON |
| 526 | if (instance()->event_model() == NPEventModelCarbon) { |
| 527 | #ifndef NP_NO_QUICKDRAW |
| 528 | if (instance()->drawing_model() == NPDrawingModelQuickDraw) { |
| 529 | if (quirks_ & PLUGIN_QUIRK_ALLOW_FASTER_QUICKDRAW_PATH) { |
| 530 | // Mouse event handling doesn't work correctly in the fast path mode, |
| 531 | // so any time we get a mouse event turn the fast path off, but set a |
| 532 | // time to switch it on again (we don't rely just on MouseLeave because |
| 533 | // we don't want poor performance in the case of clicking the play |
| 534 | // button and then leaving the mouse there). |
| 535 | // This isn't perfect (specifically, click-and-hold doesn't seem to work |
| 536 | // if the fast path is on), but the slight regression is worthwhile |
| 537 | // for the improved framerates. |
[email protected] | 7c64a2f | 2010-03-29 20:49:41 | [diff] [blame] | 538 | if (WebInputEvent::isMouseEventType(event.type)) { |
[email protected] | 779b881 | 2010-03-26 18:55:09 | [diff] [blame] | 539 | if (event.type == WebInputEvent::MouseLeave) { |
| 540 | SetQuickDrawFastPathEnabled(true); |
| 541 | } else { |
| 542 | SetQuickDrawFastPathEnabled(false); |
| 543 | } |
| 544 | // Make sure the plugin wasn't destroyed during the switch. |
| 545 | if (!instance()) |
| 546 | return false; |
| 547 | } |
| 548 | } |
| 549 | |
[email protected] | 4491a78 | 2010-04-12 15:38:44 | [diff] [blame] | 550 | qd_manager_->MakePortCurrent(); |
[email protected] | 779b881 | 2010-03-26 18:55:09 | [diff] [blame] | 551 | } |
| 552 | #endif |
| 553 | |
| 554 | if (event.type == WebInputEvent::MouseMove) { |
| 555 | return true; // The recurring FireIdleEvent will send null events. |
| 556 | } |
| 557 | } |
| 558 | #endif |
| 559 | |
[email protected] | b4ec5d9 | 2010-01-19 19:24:24 | [diff] [blame] | 560 | ScopedActiveDelegate active_delegate(this); |
| 561 | |
[email protected] | 7c64a2f | 2010-03-29 20:49:41 | [diff] [blame] | 562 | // Create the plugin event structure. |
| 563 | NPEventModel event_model = instance()->event_model(); |
| 564 | scoped_ptr<PluginWebEventConverter> event_converter( |
| 565 | PluginWebEventConverterFactory::CreateConverterForModel(event_model)); |
[email protected] | f5b8436 | 2010-04-01 22:02:49 | [diff] [blame] | 566 | if (!(event_converter.get() && event_converter->InitWithEvent(event))) { |
| 567 | // Silently consume any keyboard event types that we don't handle, so that |
| 568 | // they don't fall through to the page. |
| 569 | if (WebInputEvent::isKeyboardEventType(event.type)) |
| 570 | return true; |
[email protected] | 7c64a2f | 2010-03-29 20:49:41 | [diff] [blame] | 571 | return false; |
[email protected] | f5b8436 | 2010-04-01 22:02:49 | [diff] [blame] | 572 | } |
[email protected] | 7c64a2f | 2010-03-29 20:49:41 | [diff] [blame] | 573 | void* plugin_event = event_converter->plugin_event(); |
[email protected] | e612d76 | 2010-03-31 04:32:30 | [diff] [blame] | 574 | |
[email protected] | 7c64a2f | 2010-03-29 20:49:41 | [diff] [blame] | 575 | if (instance()->event_model() == NPEventModelCocoa) { |
| 576 | // We recieve events related to drags starting outside the plugin, but the |
| 577 | // NPAPI Cocoa event model spec says plugins shouldn't receive them, so |
| 578 | // filter them out. |
| 579 | // If we add a page capture mode at the WebKit layer (like the plugin |
| 580 | // capture mode that handles drags starting inside) this can be removed. |
[email protected] | 7ba38183 | 2010-04-16 15:02:37 | [diff] [blame] | 581 | bool drag_related = external_drag_tracker_->EventIsRelatedToDrag(event); |
| 582 | external_drag_tracker_->UpdateDragStateFromEvent(event); |
[email protected] | 7c64a2f | 2010-03-29 20:49:41 | [diff] [blame] | 583 | if (drag_related) { |
[email protected] | 7ba38183 | 2010-04-16 15:02:37 | [diff] [blame] | 584 | if (event.type == WebInputEvent::MouseUp && |
| 585 | !external_drag_tracker_->IsDragInProgress()) { |
[email protected] | 7c64a2f | 2010-03-29 20:49:41 | [diff] [blame] | 586 | // When an external drag ends, we need to synthesize a MouseEntered. |
| 587 | NPCocoaEvent enter_event = *(static_cast<NPCocoaEvent*>(plugin_event)); |
| 588 | enter_event.type = NPCocoaEventMouseEntered; |
[email protected] | 191eb3f7 | 2010-12-21 06:27:50 | [diff] [blame] | 589 | ScopedCurrentPluginEvent event_scope(instance(), &enter_event); |
[email protected] | 7c64a2f | 2010-03-29 20:49:41 | [diff] [blame] | 590 | instance()->NPP_HandleEvent(&enter_event); |
[email protected] | 3be438a | 2010-03-15 22:18:09 | [diff] [blame] | 591 | } |
[email protected] | 7c64a2f | 2010-03-29 20:49:41 | [diff] [blame] | 592 | return false; |
[email protected] | 5c6ac767 | 2009-12-10 23:45:31 | [diff] [blame] | 593 | } |
| 594 | } |
| 595 | |
[email protected] | 7c64a2f | 2010-03-29 20:49:41 | [diff] [blame] | 596 | // Send the plugin the event. |
[email protected] | 191eb3f7 | 2010-12-21 06:27:50 | [diff] [blame] | 597 | scoped_ptr<ScopedCurrentPluginEvent> event_scope(NULL); |
[email protected] | 7c64a2f | 2010-03-29 20:49:41 | [diff] [blame] | 598 | if (instance()->event_model() == NPEventModelCocoa) { |
[email protected] | 191eb3f7 | 2010-12-21 06:27:50 | [diff] [blame] | 599 | event_scope.reset(new ScopedCurrentPluginEvent( |
[email protected] | 7c64a2f | 2010-03-29 20:49:41 | [diff] [blame] | 600 | instance(), static_cast<NPCocoaEvent*>(plugin_event))); |
| 601 | } |
[email protected] | 935d63d | 2010-10-15 23:31:55 | [diff] [blame] | 602 | int16_t handle_response = instance()->NPP_HandleEvent(plugin_event); |
| 603 | bool handled = handle_response != kNPEventNotHandled; |
| 604 | |
[email protected] | b7f7586 | 2011-01-21 21:15:13 | [diff] [blame] | 605 | // Start IME if requested by the plugin. |
| 606 | if (handled && handle_response == kNPEventStartIME && |
| 607 | event.type == WebInputEvent::KeyDown) { |
| 608 | StartIme(); |
| 609 | ++keyup_ignore_count_; |
[email protected] | 935d63d | 2010-10-15 23:31:55 | [diff] [blame] | 610 | } |
[email protected] | 7c64a2f | 2010-03-29 20:49:41 | [diff] [blame] | 611 | |
[email protected] | 0c395ac | 2010-06-15 18:17:26 | [diff] [blame] | 612 | // Plugins don't give accurate information about whether or not they handled |
| 613 | // events, so browsers on the Mac ignore the return value. |
| 614 | // Scroll events are the exception, since the Cocoa spec defines a meaning |
| 615 | // for the return value. |
[email protected] | 7c64a2f | 2010-03-29 20:49:41 | [diff] [blame] | 616 | if (WebInputEvent::isMouseEventType(event.type)) { |
[email protected] | 7c64a2f | 2010-03-29 20:49:41 | [diff] [blame] | 617 | handled = true; |
[email protected] | 0c395ac | 2010-06-15 18:17:26 | [diff] [blame] | 618 | } else if (WebInputEvent::isKeyboardEventType(event.type)) { |
| 619 | // For Command-key events, trust the return value since eating all menu |
| 620 | // shortcuts is not ideal. |
| 621 | // TODO(stuartmorgan): Implement the advanced key handling spec, and trust |
| 622 | // trust the key event return value from plugins that implement it. |
| 623 | if (!(event.modifiers & WebInputEvent::MetaKey)) |
| 624 | handled = true; |
[email protected] | 01938c9 | 2010-01-15 17:05:13 | [diff] [blame] | 625 | } |
| 626 | |
[email protected] | 7c64a2f | 2010-03-29 20:49:41 | [diff] [blame] | 627 | return handled; |
[email protected] | 39b8c513 | 2009-02-11 07:48:22 | [diff] [blame] | 628 | } |
| 629 | |
[email protected] | 7ba38183 | 2010-04-16 15:02:37 | [diff] [blame] | 630 | void WebPluginDelegateImpl::InstallMissingPlugin() { |
| 631 | NOTIMPLEMENTED(); |
| 632 | } |
| 633 | |
| 634 | #pragma mark - |
| 635 | |
| 636 | void WebPluginDelegateImpl::WindowlessUpdateGeometry( |
| 637 | const gfx::Rect& window_rect, |
| 638 | const gfx::Rect& clip_rect) { |
| 639 | gfx::Rect old_clip_rect = clip_rect_; |
| 640 | cached_clip_rect_ = clip_rect; |
| 641 | if (container_is_visible_) // Remove check when cached_clip_rect_ is removed. |
| 642 | clip_rect_ = clip_rect; |
| 643 | bool clip_rect_changed = (clip_rect_ != old_clip_rect); |
| 644 | bool window_size_changed = (window_rect.size() != window_rect_.size()); |
| 645 | |
[email protected] | 372a33a | 2010-05-04 15:48:33 | [diff] [blame] | 646 | bool force_set_window = false; |
| 647 | #ifndef NP_NO_QUICKDRAW |
| 648 | // In a QuickDraw plugin, a geometry update might have caused a port change; |
| 649 | // if so, we need to call SetWindow even if nothing else changed. |
| 650 | if (qd_manager_.get() && (qd_port_.port != qd_manager_->port())) { |
[email protected] | 372a33a | 2010-05-04 15:48:33 | [diff] [blame] | 651 | qd_port_.port = qd_manager_->port(); |
| 652 | force_set_window = true; |
| 653 | } |
| 654 | #endif |
| 655 | |
| 656 | if (window_rect == window_rect_ && !clip_rect_changed && !force_set_window) |
[email protected] | 7ba38183 | 2010-04-16 15:02:37 | [diff] [blame] | 657 | return; |
| 658 | |
| 659 | if (old_clip_rect.IsEmpty() != clip_rect_.IsEmpty()) { |
| 660 | PluginVisibilityChanged(); |
| 661 | } |
| 662 | |
| 663 | SetPluginRect(window_rect); |
| 664 | |
| 665 | #ifndef NP_NO_QUICKDRAW |
| 666 | if (window_size_changed && qd_manager_.get() && |
| 667 | qd_manager_->IsFastPathEnabled()) { |
| 668 | // If the window size has changed, we need to turn off the fast path so that |
| 669 | // the full redraw goes to the window and we get a correct baseline paint. |
| 670 | SetQuickDrawFastPathEnabled(false); |
| 671 | return; // SetQuickDrawFastPathEnabled will call SetWindow for us. |
| 672 | } |
| 673 | #endif |
| 674 | |
[email protected] | 372a33a | 2010-05-04 15:48:33 | [diff] [blame] | 675 | if (window_size_changed || clip_rect_changed || force_set_window) |
[email protected] | 7ba38183 | 2010-04-16 15:02:37 | [diff] [blame] | 676 | WindowlessSetWindow(); |
| 677 | } |
| 678 | |
| 679 | void WebPluginDelegateImpl::WindowlessPaint(gfx::NativeDrawingContext context, |
| 680 | const gfx::Rect& damage_rect) { |
| 681 | // If we get a paint event before we are completely set up (e.g., a nested |
| 682 | // call while the plugin is still in NPP_SetWindow), bail. |
[email protected] | 2fc51e5b | 2011-02-04 03:36:00 | [diff] [blame] | 683 | if (!have_called_set_window_ || !buffer_context_) |
[email protected] | 7ba38183 | 2010-04-16 15:02:37 | [diff] [blame] | 684 | return; |
[email protected] | 2fc51e5b | 2011-02-04 03:36:00 | [diff] [blame] | 685 | DCHECK(buffer_context_ == context); |
[email protected] | 7ba38183 | 2010-04-16 15:02:37 | [diff] [blame] | 686 | |
[email protected] | 835d7c8 | 2010-10-14 04:38:38 | [diff] [blame] | 687 | static base::StatsRate plugin_paint("Plugin.Paint"); |
| 688 | base::StatsScope<base::StatsRate> scope(plugin_paint); |
[email protected] | 7ba38183 | 2010-04-16 15:02:37 | [diff] [blame] | 689 | |
| 690 | // Plugin invalidates trigger asynchronous paints with the original |
| 691 | // invalidation rect; the plugin may be resized before the paint is handled, |
| 692 | // so we need to ensure that the damage rect is still sane. |
| 693 | const gfx::Rect paint_rect(damage_rect.Intersect( |
| 694 | gfx::Rect(0, 0, window_rect_.width(), window_rect_.height()))); |
| 695 | |
| 696 | ScopedActiveDelegate active_delegate(this); |
| 697 | |
| 698 | #ifndef NP_NO_QUICKDRAW |
| 699 | if (instance()->drawing_model() == NPDrawingModelQuickDraw) |
| 700 | qd_manager_->MakePortCurrent(); |
| 701 | #endif |
| 702 | |
| 703 | CGContextSaveGState(context); |
| 704 | |
| 705 | switch (instance()->event_model()) { |
[email protected] | 385579b | 2010-01-21 20:18:48 | [diff] [blame] | 706 | #ifndef NP_NO_CARBON |
[email protected] | 7ba38183 | 2010-04-16 15:02:37 | [diff] [blame] | 707 | case NPEventModelCarbon: { |
| 708 | NPEvent paint_event = { 0 }; |
| 709 | paint_event.what = updateEvt; |
| 710 | paint_event.message = reinterpret_cast<uint32>(np_cg_context_.window); |
| 711 | paint_event.when = TickCount(); |
| 712 | instance()->NPP_HandleEvent(&paint_event); |
| 713 | break; |
| 714 | } |
| 715 | #endif |
| 716 | case NPEventModelCocoa: { |
| 717 | NPCocoaEvent paint_event; |
| 718 | memset(&paint_event, 0, sizeof(NPCocoaEvent)); |
| 719 | paint_event.type = NPCocoaEventDrawRect; |
| 720 | paint_event.data.draw.context = context; |
| 721 | paint_event.data.draw.x = paint_rect.x(); |
| 722 | paint_event.data.draw.y = paint_rect.y(); |
| 723 | paint_event.data.draw.width = paint_rect.width(); |
| 724 | paint_event.data.draw.height = paint_rect.height(); |
| 725 | instance()->NPP_HandleEvent(&paint_event); |
| 726 | break; |
| 727 | } |
| 728 | } |
| 729 | |
| 730 | // The backing buffer can change during the call to NPP_HandleEvent, in which |
| 731 | // case the old context is (or is about to be) invalid. |
[email protected] | 2fc51e5b | 2011-02-04 03:36:00 | [diff] [blame] | 732 | if (context == buffer_context_) |
| 733 | CGContextRestoreGState(context); |
[email protected] | 7ba38183 | 2010-04-16 15:02:37 | [diff] [blame] | 734 | } |
| 735 | |
| 736 | void WebPluginDelegateImpl::WindowlessSetWindow() { |
| 737 | if (!instance()) |
| 738 | return; |
| 739 | |
| 740 | window_.x = 0; |
| 741 | window_.y = 0; |
| 742 | window_.height = window_rect_.height(); |
| 743 | window_.width = window_rect_.width(); |
| 744 | window_.clipRect.left = clip_rect_.x(); |
| 745 | window_.clipRect.top = clip_rect_.y(); |
| 746 | window_.clipRect.right = clip_rect_.x() + clip_rect_.width(); |
| 747 | window_.clipRect.bottom = clip_rect_.y() + clip_rect_.height(); |
| 748 | |
| 749 | NPError err = instance()->NPP_SetWindow(&window_); |
| 750 | |
| 751 | // Send an appropriate window focus event after the first SetWindow. |
| 752 | if (!have_called_set_window_) { |
| 753 | have_called_set_window_ = true; |
| 754 | SetWindowHasFocus(initial_window_focus_); |
| 755 | } |
| 756 | |
| 757 | #ifndef NP_NO_QUICKDRAW |
| 758 | if ((quirks_ & PLUGIN_QUIRK_ALLOW_FASTER_QUICKDRAW_PATH) && |
| 759 | !qd_manager_->IsFastPathEnabled() && !clip_rect_.IsEmpty()) { |
| 760 | // Give the plugin a few seconds to stabilize so we get a good initial paint |
| 761 | // to use as a baseline, then switch to the fast path. |
| 762 | fast_path_enable_tick_ = base::TimeTicks::Now() + |
| 763 | base::TimeDelta::FromSeconds(3); |
| 764 | } |
| 765 | #endif |
| 766 | |
| 767 | DCHECK(err == NPERR_NO_ERROR); |
| 768 | } |
| 769 | |
| 770 | #pragma mark - |
| 771 | |
| 772 | bool WebPluginDelegateImpl::WindowedCreatePlugin() { |
| 773 | NOTREACHED(); |
| 774 | return false; |
| 775 | } |
| 776 | |
| 777 | void WebPluginDelegateImpl::WindowedDestroyWindow() { |
| 778 | NOTREACHED(); |
| 779 | } |
| 780 | |
| 781 | bool WebPluginDelegateImpl::WindowedReposition(const gfx::Rect& window_rect, |
| 782 | const gfx::Rect& clip_rect) { |
| 783 | NOTREACHED(); |
| 784 | return false; |
| 785 | } |
| 786 | |
| 787 | void WebPluginDelegateImpl::WindowedSetWindow() { |
| 788 | NOTREACHED(); |
| 789 | } |
| 790 | |
| 791 | #pragma mark - |
| 792 | #pragma mark Mac Extensions |
| 793 | |
[email protected] | 51a0bb5 | 2010-06-03 21:34:06 | [diff] [blame] | 794 | void WebPluginDelegateImpl::PluginDidInvalidate() { |
| 795 | if (instance()->drawing_model() == NPDrawingModelInvalidatingCoreAnimation) |
| 796 | DrawLayerInSurface(); |
| 797 | } |
| 798 | |
[email protected] | 7ba38183 | 2010-04-16 15:02:37 | [diff] [blame] | 799 | WebPluginDelegateImpl* WebPluginDelegateImpl::GetActiveDelegate() { |
| 800 | return g_active_delegate; |
| 801 | } |
| 802 | |
[email protected] | 7ba38183 | 2010-04-16 15:02:37 | [diff] [blame] | 803 | void WebPluginDelegateImpl::SetWindowHasFocus(bool has_focus) { |
| 804 | // If we get a window focus event before calling SetWindow, just remember the |
| 805 | // states (WindowlessSetWindow will then send it on the first call). |
| 806 | if (!have_called_set_window_) { |
| 807 | initial_window_focus_ = has_focus; |
| 808 | return; |
| 809 | } |
| 810 | |
| 811 | if (has_focus == containing_window_has_focus_) |
| 812 | return; |
| 813 | containing_window_has_focus_ = has_focus; |
| 814 | |
| 815 | #ifndef NP_NO_QUICKDRAW |
| 816 | // Make sure controls repaint with the correct look. |
| 817 | if (quirks_ & PLUGIN_QUIRK_ALLOW_FASTER_QUICKDRAW_PATH) |
| 818 | SetQuickDrawFastPathEnabled(false); |
| 819 | #endif |
| 820 | |
| 821 | ScopedActiveDelegate active_delegate(this); |
| 822 | switch (instance()->event_model()) { |
| 823 | #ifndef NP_NO_CARBON |
| 824 | case NPEventModelCarbon: { |
| 825 | NPEvent focus_event = { 0 }; |
| 826 | focus_event.what = activateEvt; |
| 827 | if (has_focus) |
| 828 | focus_event.modifiers |= activeFlag; |
| 829 | focus_event.message = |
| 830 | reinterpret_cast<unsigned long>(np_cg_context_.window); |
| 831 | focus_event.when = TickCount(); |
| 832 | instance()->NPP_HandleEvent(&focus_event); |
| 833 | break; |
| 834 | } |
| 835 | #endif |
| 836 | case NPEventModelCocoa: { |
| 837 | NPCocoaEvent focus_event; |
| 838 | memset(&focus_event, 0, sizeof(focus_event)); |
| 839 | focus_event.type = NPCocoaEventWindowFocusChanged; |
| 840 | focus_event.data.focus.hasFocus = has_focus; |
| 841 | instance()->NPP_HandleEvent(&focus_event); |
| 842 | break; |
| 843 | } |
| 844 | } |
| 845 | } |
| 846 | |
[email protected] | 784ea1ab | 2010-09-18 00:02:34 | [diff] [blame] | 847 | bool WebPluginDelegateImpl::PlatformSetPluginHasFocus(bool focused) { |
[email protected] | 7d3c02c | 2010-05-05 23:10:31 | [diff] [blame] | 848 | if (!have_called_set_window_) |
[email protected] | 784ea1ab | 2010-09-18 00:02:34 | [diff] [blame] | 849 | return false; |
[email protected] | 7d3c02c | 2010-05-05 23:10:31 | [diff] [blame] | 850 | |
[email protected] | b7f7586 | 2011-01-21 21:15:13 | [diff] [blame] | 851 | plugin_->FocusChanged(focused); |
[email protected] | 935d63d | 2010-10-15 23:31:55 | [diff] [blame] | 852 | |
[email protected] | 7d3c02c | 2010-05-05 23:10:31 | [diff] [blame] | 853 | ScopedActiveDelegate active_delegate(this); |
| 854 | |
| 855 | switch (instance()->event_model()) { |
| 856 | #ifndef NP_NO_CARBON |
| 857 | case NPEventModelCarbon: { |
| 858 | NPEvent focus_event = { 0 }; |
[email protected] | 784ea1ab | 2010-09-18 00:02:34 | [diff] [blame] | 859 | if (focused) |
[email protected] | 7d3c02c | 2010-05-05 23:10:31 | [diff] [blame] | 860 | focus_event.what = NPEventType_GetFocusEvent; |
| 861 | else |
| 862 | focus_event.what = NPEventType_LoseFocusEvent; |
| 863 | focus_event.when = TickCount(); |
| 864 | instance()->NPP_HandleEvent(&focus_event); |
| 865 | break; |
| 866 | } |
| 867 | #endif |
| 868 | case NPEventModelCocoa: { |
| 869 | NPCocoaEvent focus_event; |
| 870 | memset(&focus_event, 0, sizeof(focus_event)); |
| 871 | focus_event.type = NPCocoaEventFocusChanged; |
[email protected] | 784ea1ab | 2010-09-18 00:02:34 | [diff] [blame] | 872 | focus_event.data.focus.hasFocus = focused; |
[email protected] | 7d3c02c | 2010-05-05 23:10:31 | [diff] [blame] | 873 | instance()->NPP_HandleEvent(&focus_event); |
| 874 | break; |
| 875 | } |
| 876 | } |
[email protected] | 784ea1ab | 2010-09-18 00:02:34 | [diff] [blame] | 877 | return true; |
[email protected] | 7d3c02c | 2010-05-05 23:10:31 | [diff] [blame] | 878 | } |
| 879 | |
[email protected] | 7ba38183 | 2010-04-16 15:02:37 | [diff] [blame] | 880 | void WebPluginDelegateImpl::SetContainerVisibility(bool is_visible) { |
| 881 | if (is_visible == container_is_visible_) |
| 882 | return; |
| 883 | container_is_visible_ = is_visible; |
| 884 | |
| 885 | // TODO(stuartmorgan): This is a temporary workarond for |
| 886 | // <http://crbug.com/34266>. When that is fixed, the cached_clip_rect_ code |
| 887 | // should all be removed. |
| 888 | if (is_visible) { |
| 889 | clip_rect_ = cached_clip_rect_; |
| 890 | } else { |
| 891 | clip_rect_.set_width(0); |
| 892 | clip_rect_.set_height(0); |
| 893 | } |
| 894 | |
[email protected] | 7ba38183 | 2010-04-16 15:02:37 | [diff] [blame] | 895 | // If the plugin is changing visibility, let the plugin know. If it's scrolled |
| 896 | // off screen (i.e., cached_clip_rect_ is empty), then container visibility |
| 897 | // doesn't change anything. |
| 898 | if (!cached_clip_rect_.IsEmpty()) { |
| 899 | PluginVisibilityChanged(); |
| 900 | WindowlessSetWindow(); |
| 901 | } |
| 902 | |
| 903 | // When the plugin become visible, send an empty invalidate. If there were any |
| 904 | // pending invalidations this will trigger a paint event for the damaged |
| 905 | // region, and if not it's a no-op. This is necessary since higher levels |
| 906 | // that would normally do this weren't responsible for the clip_rect_ change). |
| 907 | if (!clip_rect_.IsEmpty()) |
| 908 | instance()->webplugin()->InvalidateRect(gfx::Rect()); |
| 909 | } |
| 910 | |
[email protected] | 784ea1ab | 2010-09-18 00:02:34 | [diff] [blame] | 911 | void WebPluginDelegateImpl::WindowFrameChanged(const gfx::Rect& window_frame, |
| 912 | const gfx::Rect& view_frame) { |
[email protected] | 7ba38183 | 2010-04-16 15:02:37 | [diff] [blame] | 913 | instance()->set_window_frame(window_frame); |
| 914 | SetContentAreaOrigin(gfx::Point(view_frame.x(), view_frame.y())); |
| 915 | } |
| 916 | |
[email protected] | b7f7586 | 2011-01-21 21:15:13 | [diff] [blame] | 917 | void WebPluginDelegateImpl::ImeCompositionCompleted(const string16& text) { |
[email protected] | 935d63d | 2010-10-15 23:31:55 | [diff] [blame] | 918 | if (instance()->event_model() != NPEventModelCocoa) { |
[email protected] | b7f7586 | 2011-01-21 21:15:13 | [diff] [blame] | 919 | DLOG(ERROR) << "IME notification receieved in Carbon event model"; |
[email protected] | 935d63d | 2010-10-15 23:31:55 | [diff] [blame] | 920 | return; |
| 921 | } |
| 922 | |
[email protected] | b7f7586 | 2011-01-21 21:15:13 | [diff] [blame] | 923 | ime_enabled_ = false; |
| 924 | |
| 925 | // If |text| is empty this was just called to tell us composition was |
| 926 | // cancelled externally (e.g., the user pressed esc). |
| 927 | if (!text.empty()) { |
| 928 | NPCocoaEvent text_event; |
| 929 | memset(&text_event, 0, sizeof(NPCocoaEvent)); |
| 930 | text_event.type = NPCocoaEventTextInput; |
| 931 | text_event.data.text.text = |
| 932 | reinterpret_cast<NPNSString*>(base::SysUTF16ToNSString(text)); |
| 933 | instance()->NPP_HandleEvent(&text_event); |
| 934 | } |
[email protected] | 935d63d | 2010-10-15 23:31:55 | [diff] [blame] | 935 | } |
| 936 | |
[email protected] | 6ce58c8a | 2011-02-07 16:19:51 | [diff] [blame] | 937 | #ifndef NP_NO_CARBON |
[email protected] | 7ba38183 | 2010-04-16 15:02:37 | [diff] [blame] | 938 | void WebPluginDelegateImpl::SetThemeCursor(ThemeCursor cursor) { |
| 939 | current_windowless_cursor_.InitFromThemeCursor(cursor); |
| 940 | } |
| 941 | |
[email protected] | 6ce58c8a | 2011-02-07 16:19:51 | [diff] [blame] | 942 | void WebPluginDelegateImpl::SetCarbonCursor(const Cursor* cursor) { |
[email protected] | 7ba38183 | 2010-04-16 15:02:37 | [diff] [blame] | 943 | current_windowless_cursor_.InitFromCursor(cursor); |
| 944 | } |
[email protected] | 6ce58c8a | 2011-02-07 16:19:51 | [diff] [blame] | 945 | #endif |
[email protected] | 7ba38183 | 2010-04-16 15:02:37 | [diff] [blame] | 946 | |
| 947 | void WebPluginDelegateImpl::SetNSCursor(NSCursor* cursor) { |
| 948 | current_windowless_cursor_.InitFromNSCursor(cursor); |
| 949 | } |
| 950 | |
| 951 | #pragma mark - |
| 952 | #pragma mark Internal Tracking |
| 953 | |
| 954 | void WebPluginDelegateImpl::SetPluginRect(const gfx::Rect& rect) { |
| 955 | bool plugin_size_changed = rect.width() != window_rect_.width() || |
| 956 | rect.height() != window_rect_.height(); |
| 957 | window_rect_ = rect; |
| 958 | PluginScreenLocationChanged(); |
| 959 | if (plugin_size_changed) |
| 960 | UpdateAcceleratedSurface(); |
| 961 | } |
| 962 | |
| 963 | void WebPluginDelegateImpl::SetContentAreaOrigin(const gfx::Point& origin) { |
| 964 | content_area_origin_ = origin; |
| 965 | PluginScreenLocationChanged(); |
| 966 | } |
| 967 | |
| 968 | void WebPluginDelegateImpl::PluginScreenLocationChanged() { |
| 969 | gfx::Point plugin_origin(content_area_origin_.x() + window_rect_.x(), |
| 970 | content_area_origin_.y() + window_rect_.y()); |
| 971 | instance()->set_plugin_origin(plugin_origin); |
| 972 | |
| 973 | #ifndef NP_NO_CARBON |
| 974 | if (instance()->event_model() == NPEventModelCarbon) { |
| 975 | UpdateDummyWindowBounds(plugin_origin); |
| 976 | } |
| 977 | #endif |
| 978 | } |
| 979 | |
| 980 | void WebPluginDelegateImpl::PluginVisibilityChanged() { |
| 981 | #ifndef NP_NO_CARBON |
| 982 | if (instance()->event_model() == NPEventModelCarbon) |
| 983 | UpdateIdleEventRate(); |
| 984 | #endif |
| 985 | if (instance()->drawing_model() == NPDrawingModelCoreAnimation) { |
| 986 | bool plugin_visible = container_is_visible_ && !clip_rect_.IsEmpty(); |
[email protected] | 4736973b | 2010-04-28 17:56:42 | [diff] [blame] | 987 | if (plugin_visible && !redraw_timer_->IsRunning() && windowed_handle()) { |
[email protected] | 7ba38183 | 2010-04-16 15:02:37 | [diff] [blame] | 988 | redraw_timer_->Start( |
| 989 | base::TimeDelta::FromMilliseconds(kCoreAnimationRedrawPeriodMs), |
| 990 | this, &WebPluginDelegateImpl::DrawLayerInSurface); |
| 991 | } else if (!plugin_visible) { |
| 992 | redraw_timer_->Stop(); |
| 993 | } |
| 994 | } |
| 995 | } |
| 996 | |
[email protected] | b7f7586 | 2011-01-21 21:15:13 | [diff] [blame] | 997 | void WebPluginDelegateImpl::StartIme() { |
| 998 | if (instance()->event_model() != NPEventModelCocoa || |
| 999 | !IsImeSupported()) { |
[email protected] | 935d63d | 2010-10-15 23:31:55 | [diff] [blame] | 1000 | return; |
[email protected] | b7f7586 | 2011-01-21 21:15:13 | [diff] [blame] | 1001 | } |
| 1002 | if (ime_enabled_) |
[email protected] | 935d63d | 2010-10-15 23:31:55 | [diff] [blame] | 1003 | return; |
[email protected] | b7f7586 | 2011-01-21 21:15:13 | [diff] [blame] | 1004 | ime_enabled_ = true; |
| 1005 | plugin_->StartIme(); |
| 1006 | } |
| 1007 | |
| 1008 | bool WebPluginDelegateImpl::IsImeSupported() { |
| 1009 | // Currently the plugin IME implementation only works on 10.6. |
| 1010 | static BOOL sImeSupported = NO; |
| 1011 | static BOOL sHaveCheckedSupport = NO; |
| 1012 | if (!sHaveCheckedSupport) { |
| 1013 | int32 major, minor, bugfix; |
| 1014 | base::SysInfo::OperatingSystemVersionNumbers(&major, &minor, &bugfix); |
| 1015 | sImeSupported = major > 10 || (major == 10 && minor > 5); |
| 1016 | sHaveCheckedSupport = YES; |
| 1017 | } |
| 1018 | return sImeSupported; |
[email protected] | 935d63d | 2010-10-15 23:31:55 | [diff] [blame] | 1019 | } |
| 1020 | |
[email protected] | 7ba38183 | 2010-04-16 15:02:37 | [diff] [blame] | 1021 | #pragma mark - |
| 1022 | #pragma mark Core Animation Support |
| 1023 | |
| 1024 | void WebPluginDelegateImpl::DrawLayerInSurface() { |
[email protected] | 4736973b | 2010-04-28 17:56:42 | [diff] [blame] | 1025 | // If we haven't plumbed up the surface yet, don't try to draw. |
[email protected] | d92bec4 | 2010-11-22 22:49:34 | [diff] [blame] | 1026 | if (!windowed_handle() || !renderer_) |
[email protected] | 4736973b | 2010-04-28 17:56:42 | [diff] [blame] | 1027 | return; |
| 1028 | |
[email protected] | 7ba38183 | 2010-04-16 15:02:37 | [diff] [blame] | 1029 | [renderer_ beginFrameAtTime:CACurrentMediaTime() timeStamp:NULL]; |
[email protected] | daaaef4 | 2010-06-15 16:16:20 | [diff] [blame] | 1030 | if (CGRectIsEmpty([renderer_ updateBounds])) { |
| 1031 | // If nothing has changed, we are done. |
| 1032 | [renderer_ endFrame]; |
| 1033 | return; |
| 1034 | } |
[email protected] | 65d52b9 | 2010-11-18 17:44:26 | [diff] [blame] | 1035 | |
| 1036 | surface_->StartDrawing(); |
| 1037 | |
[email protected] | 7ba38183 | 2010-04-16 15:02:37 | [diff] [blame] | 1038 | CGRect layerRect = [layer_ bounds]; |
| 1039 | [renderer_ addUpdateRect:layerRect]; |
| 1040 | [renderer_ render]; |
| 1041 | [renderer_ endFrame]; |
| 1042 | |
[email protected] | 8b4755f | 2010-10-01 18:04:06 | [diff] [blame] | 1043 | surface_->EndDrawing(); |
[email protected] | 7ba38183 | 2010-04-16 15:02:37 | [diff] [blame] | 1044 | } |
| 1045 | |
[email protected] | 8b4755f | 2010-10-01 18:04:06 | [diff] [blame] | 1046 | // Update the size of the surface to match the current size of the plug-in. |
[email protected] | 7ba38183 | 2010-04-16 15:02:37 | [diff] [blame] | 1047 | void WebPluginDelegateImpl::UpdateAcceleratedSurface() { |
[email protected] | 51a0bb5 | 2010-06-03 21:34:06 | [diff] [blame] | 1048 | // Will only have a window handle when using a Core Animation drawing model. |
| 1049 | if (!windowed_handle() || !layer_) |
[email protected] | 7ba38183 | 2010-04-16 15:02:37 | [diff] [blame] | 1050 | return; |
| 1051 | |
[email protected] | 515040e | 2010-10-11 19:55:10 | [diff] [blame] | 1052 | [CATransaction begin]; |
| 1053 | [CATransaction setValue:[NSNumber numberWithInt:0] |
| 1054 | forKey:kCATransactionAnimationDuration]; |
[email protected] | 7ba38183 | 2010-04-16 15:02:37 | [diff] [blame] | 1055 | [layer_ setFrame:CGRectMake(0, 0, |
| 1056 | window_rect_.width(), window_rect_.height())]; |
[email protected] | 515040e | 2010-10-11 19:55:10 | [diff] [blame] | 1057 | [CATransaction commit]; |
| 1058 | |
[email protected] | 7ba38183 | 2010-04-16 15:02:37 | [diff] [blame] | 1059 | [renderer_ setBounds:[layer_ bounds]]; |
[email protected] | 8b4755f | 2010-10-01 18:04:06 | [diff] [blame] | 1060 | surface_->SetSize(window_rect_.size()); |
[email protected] | 7ba38183 | 2010-04-16 15:02:37 | [diff] [blame] | 1061 | } |
| 1062 | |
[email protected] | 4736973b | 2010-04-28 17:56:42 | [diff] [blame] | 1063 | void WebPluginDelegateImpl::set_windowed_handle( |
| 1064 | gfx::PluginWindowHandle handle) { |
| 1065 | windowed_handle_ = handle; |
[email protected] | 8b4755f | 2010-10-01 18:04:06 | [diff] [blame] | 1066 | surface_->SetWindowHandle(handle); |
[email protected] | 4736973b | 2010-04-28 17:56:42 | [diff] [blame] | 1067 | UpdateAcceleratedSurface(); |
| 1068 | // Kick off the drawing timer, if necessary. |
| 1069 | PluginVisibilityChanged(); |
| 1070 | } |
| 1071 | |
[email protected] | 7ba38183 | 2010-04-16 15:02:37 | [diff] [blame] | 1072 | #pragma mark - |
| 1073 | #pragma mark Carbon Event support |
| 1074 | |
| 1075 | #ifndef NP_NO_CARBON |
| 1076 | void WebPluginDelegateImpl::UpdateDummyWindowBounds( |
| 1077 | const gfx::Point& plugin_origin) { |
| 1078 | WindowRef window = reinterpret_cast<WindowRef>(np_cg_context_.window); |
| 1079 | Rect current_bounds; |
| 1080 | GetWindowBounds(window, kWindowContentRgn, ¤t_bounds); |
| 1081 | |
| 1082 | Rect new_bounds; |
| 1083 | // We never want to resize the window to 0x0, so if the plugin is 0x0 just |
| 1084 | // move the window without resizing it. |
| 1085 | if (window_rect_.width() > 0 && window_rect_.height() > 0) { |
| 1086 | SetRect(&new_bounds, 0, 0, window_rect_.width(), window_rect_.height()); |
| 1087 | OffsetRect(&new_bounds, plugin_origin.x(), plugin_origin.y()); |
| 1088 | } else { |
| 1089 | new_bounds = current_bounds; |
| 1090 | OffsetRect(&new_bounds, plugin_origin.x() - current_bounds.left, |
| 1091 | plugin_origin.y() - current_bounds.top); |
| 1092 | } |
| 1093 | |
| 1094 | if (new_bounds.left != current_bounds.left || |
| 1095 | new_bounds.top != current_bounds.top || |
| 1096 | new_bounds.right != current_bounds.right || |
| 1097 | new_bounds.bottom != current_bounds.bottom) |
| 1098 | SetWindowBounds(window, kWindowContentRgn, &new_bounds); |
| 1099 | } |
| 1100 | |
| 1101 | void WebPluginDelegateImpl::UpdateIdleEventRate() { |
| 1102 | bool plugin_visible = container_is_visible_ && !clip_rect_.IsEmpty(); |
| 1103 | CarbonIdleEventSource::SharedInstance()->RegisterDelegate(this, |
| 1104 | plugin_visible); |
| 1105 | } |
| 1106 | |
[email protected] | bc384e4a | 2010-01-21 17:26:28 | [diff] [blame] | 1107 | void WebPluginDelegateImpl::FireIdleEvent() { |
[email protected] | 28dbd6c | 2009-11-20 18:52:16 | [diff] [blame] | 1108 | // Avoid a race condition between IO and UI threads during plugin shutdown |
[email protected] | 47e9c75c | 2010-02-16 21:31:54 | [diff] [blame] | 1109 | if (!instance()) |
[email protected] | 28dbd6c | 2009-11-20 18:52:16 | [diff] [blame] | 1110 | return; |
[email protected] | 32c0554d | 2010-04-05 20:57:17 | [diff] [blame] | 1111 | // Don't send idle events until we've called SetWindow. |
| 1112 | if (!have_called_set_window_) |
| 1113 | return; |
[email protected] | b4ec5d9 | 2010-01-19 19:24:24 | [diff] [blame] | 1114 | |
[email protected] | 779b881 | 2010-03-26 18:55:09 | [diff] [blame] | 1115 | #ifndef NP_NO_QUICKDRAW |
| 1116 | // Check whether it's time to turn the QuickDraw fast path back on. |
| 1117 | if (!fast_path_enable_tick_.is_null() && |
| 1118 | (base::TimeTicks::Now() > fast_path_enable_tick_)) { |
| 1119 | SetQuickDrawFastPathEnabled(true); |
| 1120 | fast_path_enable_tick_ = base::TimeTicks(); |
| 1121 | } |
| 1122 | #endif |
| 1123 | |
[email protected] | b4ec5d9 | 2010-01-19 19:24:24 | [diff] [blame] | 1124 | ScopedActiveDelegate active_delegate(this); |
| 1125 | |
[email protected] | 779b881 | 2010-03-26 18:55:09 | [diff] [blame] | 1126 | #ifndef NP_NO_QUICKDRAW |
[email protected] | 4491a78 | 2010-04-12 15:38:44 | [diff] [blame] | 1127 | if (instance()->drawing_model() == NPDrawingModelQuickDraw) |
| 1128 | qd_manager_->MakePortCurrent(); |
[email protected] | 779b881 | 2010-03-26 18:55:09 | [diff] [blame] | 1129 | #endif |
| 1130 | |
[email protected] | 44b67155 | 2010-03-01 21:19:06 | [diff] [blame] | 1131 | // Send an idle event so that the plugin can do background work |
| 1132 | NPEvent np_event = {0}; |
| 1133 | np_event.what = nullEvent; |
| 1134 | np_event.when = TickCount(); |
| 1135 | np_event.modifiers = GetCurrentKeyModifiers(); |
| 1136 | if (!Button()) |
| 1137 | np_event.modifiers |= btnState; |
| 1138 | HIPoint mouse_location; |
| 1139 | HIGetMousePosition(kHICoordSpaceScreenPixel, NULL, &mouse_location); |
| 1140 | np_event.where.h = mouse_location.x; |
| 1141 | np_event.where.v = mouse_location.y; |
| 1142 | instance()->NPP_HandleEvent(&np_event); |
[email protected] | 9ee23c5b | 2009-07-13 21:02:00 | [diff] [blame] | 1143 | |
[email protected] | 760cd212 | 2009-10-13 17:53:22 | [diff] [blame] | 1144 | #ifndef NP_NO_QUICKDRAW |
| 1145 | // Quickdraw-based plugins can draw at any time, so tell the renderer to |
| 1146 | // repaint. |
[email protected] | 47e9c75c | 2010-02-16 21:31:54 | [diff] [blame] | 1147 | if (instance() && instance()->drawing_model() == NPDrawingModelQuickDraw) |
[email protected] | 760cd212 | 2009-10-13 17:53:22 | [diff] [blame] | 1148 | instance()->webplugin()->Invalidate(); |
| 1149 | #endif |
[email protected] | 9ee23c5b | 2009-07-13 21:02:00 | [diff] [blame] | 1150 | } |
[email protected] | 385579b | 2010-01-21 20:18:48 | [diff] [blame] | 1151 | #endif // !NP_NO_CARBON |
[email protected] | 7ba38183 | 2010-04-16 15:02:37 | [diff] [blame] | 1152 | |
| 1153 | #pragma mark - |
| 1154 | #pragma mark QuickDraw Support |
| 1155 | |
| 1156 | #ifndef NP_NO_QUICKDRAW |
| 1157 | void WebPluginDelegateImpl::SetQuickDrawFastPathEnabled(bool enabled) { |
| 1158 | if (!enabled) { |
| 1159 | // Wait a couple of seconds, then turn the fast path back on. If we're |
| 1160 | // turning it off for event handling, that ensures that the common case of |
| 1161 | // move-mouse-then-click works (as well as making it likely that a second |
| 1162 | // click attempt will work if the first one fails). If we're turning it |
| 1163 | // off to force a new baseline image, this leaves plenty of time for the |
| 1164 | // plugin to draw. |
| 1165 | fast_path_enable_tick_ = base::TimeTicks::Now() + |
| 1166 | base::TimeDelta::FromSeconds(2); |
| 1167 | } |
| 1168 | |
| 1169 | if (enabled == qd_manager_->IsFastPathEnabled()) |
| 1170 | return; |
| 1171 | if (enabled && clip_rect_.IsEmpty()) { |
| 1172 | // Don't switch to the fast path while the plugin is completely clipped; |
| 1173 | // we can only switch when the window has an up-to-date image for us to |
| 1174 | // scrape. We'll automatically switch after we become visible again. |
| 1175 | return; |
| 1176 | } |
| 1177 | |
| 1178 | qd_manager_->SetFastPathEnabled(enabled); |
| 1179 | qd_port_.port = qd_manager_->port(); |
| 1180 | WindowlessSetWindow(); |
| 1181 | // Send a paint event so that the new buffer gets updated immediately. |
| 1182 | WindowlessPaint(buffer_context_, clip_rect_); |
| 1183 | } |
| 1184 | #endif // !NP_NO_QUICKDRAW |
[email protected] | 191eb3f7 | 2010-12-21 06:27:50 | [diff] [blame] | 1185 | |
| 1186 | } // namespace npapi |
| 1187 | } // namespace webkit |