Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(331)

Side by Side Diff: content/child/npapi/webplugin_delegate_impl_mac.mm

Issue 1851093005: Remove content/child/npapi (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@remove_combined_01_02
Patch Set: rebase Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "content/child/npapi/webplugin_delegate_impl.h"
6
7 #import <Cocoa/Cocoa.h>
8 #import <QuartzCore/QuartzCore.h>
9 #include <stdint.h>
10 #include <string.h>
11 #include <unistd.h>
12
13 #include <set>
14 #include <string>
15
16 #include "base/macros.h"
17 #include "base/memory/scoped_ptr.h"
18 #include "base/strings/string_util.h"
19 #include "base/strings/sys_string_conversions.h"
20 #include "base/strings/utf_string_conversions.h"
21 #include "content/child/npapi/plugin_instance.h"
22 #include "content/child/npapi/plugin_lib.h"
23 #include "content/child/npapi/plugin_web_event_converter_mac.h"
24 #include "content/child/npapi/webplugin.h"
25 #include "content/child/npapi/webplugin_accelerated_surface_mac.h"
26 #include "content/common/cursors/webcursor.h"
27 #include "skia/ext/skia_utils_mac.h"
28 #include "third_party/WebKit/public/web/WebInputEvent.h"
29 #include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h"
30
31 using blink::WebKeyboardEvent;
32 using blink::WebInputEvent;
33 using blink::WebMouseEvent;
34 using blink::WebMouseWheelEvent;
35
36 // Important implementation notes: The Mac definition of NPAPI, particularly
37 // the distinction between windowed and windowless modes, differs from the
38 // Windows and Linux definitions. Most of those differences are
39 // accomodated by the WebPluginDelegate class.
40
41 namespace content {
42
43 namespace {
44
45 const int kCoreAnimationRedrawPeriodMs = 10; // 100 Hz
46
47 WebPluginDelegateImpl* g_active_delegate;
48
49 // Helper to simplify correct usage of g_active_delegate. Instantiating will
50 // set the active delegate to |delegate| for the lifetime of the object, then
51 // NULL when it goes out of scope.
52 class ScopedActiveDelegate {
53 public:
54 explicit ScopedActiveDelegate(WebPluginDelegateImpl* delegate) {
55 g_active_delegate = delegate;
56 }
57 ~ScopedActiveDelegate() {
58 g_active_delegate = NULL;
59 }
60
61 private:
62 DISALLOW_COPY_AND_ASSIGN(ScopedActiveDelegate);
63 };
64
65 } // namespace
66
67 // Helper to build and maintain a model of a drag entering the plugin but not
68 // starting there. See explanation in PlatformHandleInputEvent.
69 class ExternalDragTracker {
70 public:
71 ExternalDragTracker() : pressed_buttons_(0) {}
72
73 // Returns true if an external drag is in progress.
74 bool IsDragInProgress() { return pressed_buttons_ != 0; };
75
76 // Returns true if the given event appears to be related to an external drag.
77 bool EventIsRelatedToDrag(const WebInputEvent& event);
78
79 // Updates the tracking of whether an external drag is in progress--and if
80 // so what buttons it involves--based on the given event.
81 void UpdateDragStateFromEvent(const WebInputEvent& event);
82
83 private:
84 // Returns the mask for just the button state in a WebInputEvent's modifiers.
85 static int WebEventButtonModifierMask();
86
87 // The WebInputEvent modifier flags for any buttons that were down when an
88 // external drag entered the plugin, and which and are still down now.
89 int pressed_buttons_;
90
91 DISALLOW_COPY_AND_ASSIGN(ExternalDragTracker);
92 };
93
94 void ExternalDragTracker::UpdateDragStateFromEvent(const WebInputEvent& event) {
95 switch (event.type) {
96 case WebInputEvent::MouseEnter:
97 pressed_buttons_ = event.modifiers & WebEventButtonModifierMask();
98 break;
99 case WebInputEvent::MouseUp: {
100 const WebMouseEvent* mouse_event =
101 static_cast<const WebMouseEvent*>(&event);
102 if (mouse_event->button == WebMouseEvent::ButtonLeft)
103 pressed_buttons_ &= ~WebInputEvent::LeftButtonDown;
104 if (mouse_event->button == WebMouseEvent::ButtonMiddle)
105 pressed_buttons_ &= ~WebInputEvent::MiddleButtonDown;
106 if (mouse_event->button == WebMouseEvent::ButtonRight)
107 pressed_buttons_ &= ~WebInputEvent::RightButtonDown;
108 break;
109 }
110 default:
111 break;
112 }
113 }
114
115 bool ExternalDragTracker::EventIsRelatedToDrag(const WebInputEvent& event) {
116 const WebMouseEvent* mouse_event = static_cast<const WebMouseEvent*>(&event);
117 switch (event.type) {
118 case WebInputEvent::MouseUp:
119 // We only care about release of buttons that were part of the drag.
120 return ((mouse_event->button == WebMouseEvent::ButtonLeft &&
121 (pressed_buttons_ & WebInputEvent::LeftButtonDown)) ||
122 (mouse_event->button == WebMouseEvent::ButtonMiddle &&
123 (pressed_buttons_ & WebInputEvent::MiddleButtonDown)) ||
124 (mouse_event->button == WebMouseEvent::ButtonRight &&
125 (pressed_buttons_ & WebInputEvent::RightButtonDown)));
126 case WebInputEvent::MouseEnter:
127 return (event.modifiers & WebEventButtonModifierMask()) != 0;
128 case WebInputEvent::MouseLeave:
129 case WebInputEvent::MouseMove: {
130 int event_buttons = (event.modifiers & WebEventButtonModifierMask());
131 return (pressed_buttons_ &&
132 pressed_buttons_ == event_buttons);
133 }
134 default:
135 return false;
136 }
137 return false;
138 }
139
140 int ExternalDragTracker::WebEventButtonModifierMask() {
141 return WebInputEvent::LeftButtonDown |
142 WebInputEvent::RightButtonDown |
143 WebInputEvent::MiddleButtonDown;
144 }
145
146 #pragma mark -
147 #pragma mark Core WebPluginDelegate implementation
148
149 WebPluginDelegateImpl::WebPluginDelegateImpl(
150 WebPlugin* plugin,
151 PluginInstance* instance)
152 : plugin_(plugin),
153 instance_(instance),
154 quirks_(0),
155 use_buffer_context_(true),
156 buffer_context_(NULL),
157 layer_(nil),
158 surface_(NULL),
159 renderer_(nil),
160 containing_window_has_focus_(false),
161 initial_window_focus_(false),
162 container_is_visible_(false),
163 have_called_set_window_(false),
164 ime_enabled_(false),
165 keyup_ignore_count_(0),
166 external_drag_tracker_(new ExternalDragTracker()),
167 handle_event_depth_(0),
168 first_set_window_call_(true),
169 plugin_has_focus_(false),
170 has_webkit_focus_(false),
171 containing_view_has_focus_(true),
172 creation_succeeded_(false) {
173 memset(&window_, 0, sizeof(window_));
174 }
175
176 WebPluginDelegateImpl::~WebPluginDelegateImpl() {
177 DestroyInstance();
178 }
179
180 bool WebPluginDelegateImpl::PlatformInitialize() {
181 // Don't set a NULL window handle on destroy for Mac plugins. This matches
182 // Safari and other Mac browsers (see PluginView::stop() in PluginView.cpp,
183 // where code to do so is surrounded by an #ifdef that excludes Mac OS X, or
184 // destroyPlugin in WebNetscapePluginView.mm, for examples).
185 quirks_ |= PLUGIN_QUIRK_DONT_SET_NULL_WINDOW_HANDLE_ON_DESTROY;
186
187 // Mac plugins don't expect to be unloaded, and they don't always do so
188 // cleanly, so don't unload them at shutdown.
189 instance()->plugin_lib()->PreventLibraryUnload();
190
191 #ifndef NP_NO_CARBON
192 if (instance()->event_model() == NPEventModelCarbon)
193 return false;
194 #endif
195
196 window_.type = NPWindowTypeDrawable;
197 NPDrawingModel drawing_model = instance()->drawing_model();
198 switch (drawing_model) {
199 #ifndef NP_NO_QUICKDRAW
200 case NPDrawingModelQuickDraw:
201 return false;
202 #endif
203 case NPDrawingModelCoreGraphics:
204 break;
205 case NPDrawingModelCoreAnimation:
206 case NPDrawingModelInvalidatingCoreAnimation: {
207 // Ask the plugin for the CALayer it created for rendering content.
208 // Create a surface to host it, and request a "window" handle to identify
209 // the surface.
210 CALayer* layer = nil;
211 NPError err = instance()->NPP_GetValue(NPPVpluginCoreAnimationLayer,
212 reinterpret_cast<void*>(&layer));
213 if (!err) {
214 if (drawing_model == NPDrawingModelCoreAnimation) {
215 // Create the timer; it will be started when we get a window handle.
216 redraw_timer_.reset(new base::RepeatingTimer);
217 }
218 layer_ = layer;
219
220 gfx::GpuPreference gpu_preference = gfx::PreferDiscreteGpu;
221 // On dual GPU systems, force the use of the discrete GPU for
222 // the CARenderer underlying our Core Animation backend for
223 // all plugins except Flash. For some reason Unity3D's output
224 // doesn't show up if the integrated GPU is used. Safari keeps
225 // even Flash 11 with Stage3D on the integrated GPU, so mirror
226 // that behavior here.
227 const WebPluginInfo& plugin_info =
228 instance_->plugin_lib()->plugin_info();
229 if (plugin_info.name.find(base::ASCIIToUTF16("Flash")) !=
230 base::string16::npos)
231 gpu_preference = gfx::PreferIntegratedGpu;
232 surface_ = plugin_->GetAcceleratedSurface(gpu_preference);
233
234 // If surface initialization fails for some reason, just continue
235 // without any drawing; returning false would be a more confusing user
236 // experience (since it triggers a missing plugin placeholder).
237 if (surface_ && surface_->context()) {
238 renderer_ = [[CARenderer rendererWithCGLContext:surface_->context()
239 options:NULL] retain];
240 [renderer_ setLayer:layer_];
241 plugin_->AcceleratedPluginEnabledRendering();
242 }
243 }
244 break;
245 }
246 default:
247 NOTREACHED();
248 break;
249 }
250
251 return true;
252 }
253
254 void WebPluginDelegateImpl::PlatformDestroyInstance() {
255 if (redraw_timer_)
256 redraw_timer_->Stop();
257 [renderer_ release];
258 renderer_ = nil;
259 layer_ = nil;
260 }
261
262 void WebPluginDelegateImpl::UpdateGeometryAndContext(
263 const gfx::Rect& window_rect, const gfx::Rect& clip_rect,
264 CGContextRef context) {
265 buffer_context_ = context;
266 UpdateGeometry(window_rect, clip_rect);
267 }
268
269 void WebPluginDelegateImpl::Paint(SkCanvas* canvas, const gfx::Rect& rect) {
270 skia::SkiaBitLocker bit_locker(canvas);
271 CGContextRef context = bit_locker.cgContext();
272 CGPaint(context, rect);
273 }
274
275 void WebPluginDelegateImpl::CGPaint(CGContextRef context,
276 const gfx::Rect& rect) {
277 WindowlessPaint(context, rect);
278 }
279
280 bool WebPluginDelegateImpl::PlatformHandleInputEvent(
281 const WebInputEvent& event, WebCursor::CursorInfo* cursor_info) {
282 DCHECK(cursor_info != NULL);
283
284 // If an event comes in before the plugin has been set up, bail.
285 if (!have_called_set_window_)
286 return false;
287
288 // WebKit sometimes sends spurious mouse move events when the window doesn't
289 // have focus; Cocoa event model plugins don't expect to receive mouse move
290 // events when they are in a background window, so drop those events.
291 if (!containing_window_has_focus_ &&
292 (event.type == WebInputEvent::MouseMove ||
293 event.type == WebInputEvent::MouseEnter ||
294 event.type == WebInputEvent::MouseLeave)) {
295 return false;
296 }
297
298 if (WebInputEvent::isMouseEventType(event.type) ||
299 event.type == WebInputEvent::MouseWheel) {
300 // Check our plugin location before we send the event to the plugin, just
301 // in case we somehow missed a plugin frame change.
302 const WebMouseEvent* mouse_event =
303 static_cast<const WebMouseEvent*>(&event);
304 gfx::Point content_origin(
305 mouse_event->globalX - mouse_event->x - window_rect_.x(),
306 mouse_event->globalY - mouse_event->y - window_rect_.y());
307 if (content_origin.x() != content_area_origin_.x() ||
308 content_origin.y() != content_area_origin_.y()) {
309 DLOG(WARNING) << "Stale plugin content area location: "
310 << content_area_origin_.ToString() << " instead of "
311 << content_origin.ToString();
312 SetContentAreaOrigin(content_origin);
313 }
314
315 current_windowless_cursor_.GetCursorInfo(cursor_info);
316 }
317
318 // Per the Cocoa Plugin IME spec, plugins shoudn't receive keydown or keyup
319 // events while composition is in progress. Treat them as handled, however,
320 // since IME is consuming them on behalf of the plugin.
321 if ((event.type == WebInputEvent::KeyDown && ime_enabled_) ||
322 (event.type == WebInputEvent::KeyUp && keyup_ignore_count_)) {
323 // Composition ends on a keydown, so ime_enabled_ will be false at keyup;
324 // because the keydown wasn't sent to the plugin, the keyup shouldn't be
325 // either (per the spec).
326 if (event.type == WebInputEvent::KeyDown)
327 ++keyup_ignore_count_;
328 else
329 --keyup_ignore_count_;
330 return true;
331 }
332
333 ScopedActiveDelegate active_delegate(this);
334
335 // Create the plugin event structure.
336 scoped_ptr<PluginWebEventConverter> event_converter(
337 new PluginWebEventConverter);
338 if (!event_converter->InitWithEvent(event)) {
339 // Silently consume any keyboard event types that aren't handled, so that
340 // they don't fall through to the page.
341 if (WebInputEvent::isKeyboardEventType(event.type))
342 return true;
343 return false;
344 }
345 NPCocoaEvent* plugin_event = event_converter->plugin_event();
346
347 // The plugin host receives events related to drags starting outside the
348 // plugin, but the NPAPI Cocoa event model spec says plugins shouldn't receive
349 // them, so filter them out.
350 // If WebKit adds a page capture mode (like the plugin capture mode that
351 // handles drags starting inside) this can be removed.
352 bool drag_related = external_drag_tracker_->EventIsRelatedToDrag(event);
353 external_drag_tracker_->UpdateDragStateFromEvent(event);
354 if (drag_related) {
355 if (event.type == WebInputEvent::MouseUp &&
356 !external_drag_tracker_->IsDragInProgress()) {
357 // When an external drag ends, we need to synthesize a MouseEntered.
358 NPCocoaEvent enter_event = *plugin_event;
359 enter_event.type = NPCocoaEventMouseEntered;
360 ScopedCurrentPluginEvent event_scope(instance(), &enter_event);
361 instance()->NPP_HandleEvent(&enter_event);
362 }
363 return false;
364 }
365
366 // Send the plugin the event.
367 scoped_ptr<ScopedCurrentPluginEvent> event_scope(
368 new ScopedCurrentPluginEvent(instance(), plugin_event));
369 int16_t handle_response = instance()->NPP_HandleEvent(plugin_event);
370 bool handled = handle_response != kNPEventNotHandled;
371
372 // Start IME if requested by the plugin.
373 if (handled && handle_response == kNPEventStartIME &&
374 event.type == WebInputEvent::KeyDown) {
375 StartIme();
376 ++keyup_ignore_count_;
377 }
378
379 // Plugins don't give accurate information about whether or not they handled
380 // events, so browsers on the Mac ignore the return value.
381 // Scroll events are the exception, since the Cocoa spec defines a meaning
382 // for the return value.
383 if (WebInputEvent::isMouseEventType(event.type)) {
384 handled = true;
385 } else if (WebInputEvent::isKeyboardEventType(event.type)) {
386 // For Command-key events, trust the return value since eating all menu
387 // shortcuts is not ideal.
388 // TODO(stuartmorgan): Implement the advanced key handling spec, and trust
389 // trust the key event return value from plugins that implement it.
390 if (!(event.modifiers & WebInputEvent::MetaKey))
391 handled = true;
392 }
393
394 return handled;
395 }
396
397 #pragma mark -
398
399 void WebPluginDelegateImpl::WindowlessUpdateGeometry(
400 const gfx::Rect& window_rect,
401 const gfx::Rect& clip_rect) {
402 gfx::Rect old_clip_rect = clip_rect_;
403 cached_clip_rect_ = clip_rect;
404 if (container_is_visible_) // Remove check when cached_clip_rect_ is removed.
405 clip_rect_ = clip_rect;
406 bool clip_rect_changed = (clip_rect_ != old_clip_rect);
407 bool window_size_changed = (window_rect.size() != window_rect_.size());
408
409 if (window_rect == window_rect_ && !clip_rect_changed)
410 return;
411
412 if (old_clip_rect.IsEmpty() != clip_rect_.IsEmpty()) {
413 PluginVisibilityChanged();
414 }
415
416 SetPluginRect(window_rect);
417
418 if (window_size_changed || clip_rect_changed)
419 WindowlessSetWindow();
420 }
421
422 void WebPluginDelegateImpl::WindowlessPaint(gfx::NativeDrawingContext context,
423 const gfx::Rect& damage_rect) {
424 // If we get a paint event before we are completely set up (e.g., a nested
425 // call while the plugin is still in NPP_SetWindow), bail.
426 if (!have_called_set_window_ || (use_buffer_context_ && !buffer_context_))
427 return;
428 DCHECK(!use_buffer_context_ || buffer_context_ == context);
429
430 gfx::Rect paint_rect = damage_rect;
431 if (use_buffer_context_) {
432 // Plugin invalidates trigger asynchronous paints with the original
433 // invalidation rect; the plugin may be resized before the paint is handled,
434 // so we need to ensure that the damage rect is still sane.
435 paint_rect.Intersect(
436 gfx::Rect(0, 0, window_rect_.width(), window_rect_.height()));
437 } else {
438 // Use the actual window region when drawing directly to the window context.
439 paint_rect.Intersect(window_rect_);
440 }
441
442 ScopedActiveDelegate active_delegate(this);
443
444 CGContextSaveGState(context);
445
446 if (!use_buffer_context_) {
447 // Reposition the context origin so that plugins will draw at the correct
448 // location in the window.
449 CGContextClipToRect(context, paint_rect.ToCGRect());
450 CGContextTranslateCTM(context, window_rect_.x(), window_rect_.y());
451 }
452
453 NPCocoaEvent paint_event;
454 memset(&paint_event, 0, sizeof(NPCocoaEvent));
455 paint_event.type = NPCocoaEventDrawRect;
456 paint_event.data.draw.context = context;
457 paint_event.data.draw.x = paint_rect.x();
458 paint_event.data.draw.y = paint_rect.y();
459 paint_event.data.draw.width = paint_rect.width();
460 paint_event.data.draw.height = paint_rect.height();
461 instance()->NPP_HandleEvent(&paint_event);
462
463 if (use_buffer_context_) {
464 // The backing buffer can change during the call to NPP_HandleEvent, in
465 // which case the old context is (or is about to be) invalid.
466 if (context == buffer_context_)
467 CGContextRestoreGState(context);
468 } else {
469 // Always restore the context to the saved state.
470 CGContextRestoreGState(context);
471 }
472 }
473
474 void WebPluginDelegateImpl::WindowlessSetWindow() {
475 if (!instance())
476 return;
477
478 window_.x = 0;
479 window_.y = 0;
480 window_.height = window_rect_.height();
481 window_.width = window_rect_.width();
482 window_.clipRect.left = clip_rect_.x();
483 window_.clipRect.top = clip_rect_.y();
484 window_.clipRect.right = clip_rect_.x() + clip_rect_.width();
485 window_.clipRect.bottom = clip_rect_.y() + clip_rect_.height();
486
487 NPError err = instance()->NPP_SetWindow(&window_);
488
489 // Send an appropriate window focus event after the first SetWindow.
490 if (!have_called_set_window_) {
491 have_called_set_window_ = true;
492 SetWindowHasFocus(initial_window_focus_);
493 }
494
495 DCHECK(err == NPERR_NO_ERROR);
496 }
497
498 #pragma mark -
499
500 #pragma mark -
501 #pragma mark Mac Extensions
502
503 void WebPluginDelegateImpl::PluginDidInvalidate() {
504 if (instance()->drawing_model() == NPDrawingModelInvalidatingCoreAnimation)
505 DrawLayerInSurface();
506 }
507
508 WebPluginDelegateImpl* WebPluginDelegateImpl::GetActiveDelegate() {
509 return g_active_delegate;
510 }
511
512 void WebPluginDelegateImpl::SetWindowHasFocus(bool has_focus) {
513 // If we get a window focus event before calling SetWindow, just remember the
514 // states (WindowlessSetWindow will then send it on the first call).
515 if (!have_called_set_window_) {
516 initial_window_focus_ = has_focus;
517 return;
518 }
519
520 if (has_focus == containing_window_has_focus_)
521 return;
522 containing_window_has_focus_ = has_focus;
523
524 ScopedActiveDelegate active_delegate(this);
525 NPCocoaEvent focus_event;
526 memset(&focus_event, 0, sizeof(focus_event));
527 focus_event.type = NPCocoaEventWindowFocusChanged;
528 focus_event.data.focus.hasFocus = has_focus;
529 instance()->NPP_HandleEvent(&focus_event);
530 }
531
532 bool WebPluginDelegateImpl::PlatformSetPluginHasFocus(bool focused) {
533 if (!have_called_set_window_)
534 return false;
535
536 plugin_->FocusChanged(focused);
537
538 ScopedActiveDelegate active_delegate(this);
539
540 NPCocoaEvent focus_event;
541 memset(&focus_event, 0, sizeof(focus_event));
542 focus_event.type = NPCocoaEventFocusChanged;
543 focus_event.data.focus.hasFocus = focused;
544 instance()->NPP_HandleEvent(&focus_event);
545
546 return true;
547 }
548
549 void WebPluginDelegateImpl::SetContainerVisibility(bool is_visible) {
550 if (is_visible == container_is_visible_)
551 return;
552 container_is_visible_ = is_visible;
553
554 // TODO(stuartmorgan): This is a temporary workarond for
555 // <http://crbug.com/34266>. When that is fixed, the cached_clip_rect_ code
556 // should all be removed.
557 if (is_visible) {
558 clip_rect_ = cached_clip_rect_;
559 } else {
560 clip_rect_.set_width(0);
561 clip_rect_.set_height(0);
562 }
563
564 // If the plugin is changing visibility, let the plugin know. If it's scrolled
565 // off screen (i.e., cached_clip_rect_ is empty), then container visibility
566 // doesn't change anything.
567 if (!cached_clip_rect_.IsEmpty()) {
568 PluginVisibilityChanged();
569 WindowlessSetWindow();
570 }
571
572 // When the plugin become visible, send an empty invalidate. If there were any
573 // pending invalidations this will trigger a paint event for the damaged
574 // region, and if not it's a no-op. This is necessary since higher levels
575 // that would normally do this weren't responsible for the clip_rect_ change).
576 if (!clip_rect_.IsEmpty())
577 instance()->webplugin()->InvalidateRect(gfx::Rect());
578 }
579
580 void WebPluginDelegateImpl::WindowFrameChanged(const gfx::Rect& window_frame,
581 const gfx::Rect& view_frame) {
582 instance()->set_window_frame(window_frame);
583 SetContentAreaOrigin(gfx::Point(view_frame.x(), view_frame.y()));
584 }
585
586 void WebPluginDelegateImpl::ImeCompositionCompleted(
587 const base::string16& text) {
588 ime_enabled_ = false;
589
590 // If |text| is empty this was just called to tell us composition was
591 // cancelled externally (e.g., the user pressed esc).
592 if (!text.empty()) {
593 NPCocoaEvent text_event;
594 memset(&text_event, 0, sizeof(NPCocoaEvent));
595 text_event.type = NPCocoaEventTextInput;
596 text_event.data.text.text =
597 reinterpret_cast<NPNSString*>(base::SysUTF16ToNSString(text));
598 instance()->NPP_HandleEvent(&text_event);
599 }
600 }
601
602 void WebPluginDelegateImpl::SetNSCursor(NSCursor* cursor) {
603 current_windowless_cursor_.InitFromNSCursor(cursor);
604 }
605
606 void WebPluginDelegateImpl::SetNoBufferContext() {
607 use_buffer_context_ = false;
608 }
609
610 #pragma mark -
611 #pragma mark Internal Tracking
612
613 void WebPluginDelegateImpl::SetPluginRect(const gfx::Rect& rect) {
614 bool plugin_size_changed = rect.width() != window_rect_.width() ||
615 rect.height() != window_rect_.height();
616 window_rect_ = rect;
617 PluginScreenLocationChanged();
618 if (plugin_size_changed)
619 UpdateAcceleratedSurface();
620 }
621
622 void WebPluginDelegateImpl::SetContentAreaOrigin(const gfx::Point& origin) {
623 content_area_origin_ = origin;
624 PluginScreenLocationChanged();
625 }
626
627 void WebPluginDelegateImpl::PluginScreenLocationChanged() {
628 gfx::Point plugin_origin(content_area_origin_.x() + window_rect_.x(),
629 content_area_origin_.y() + window_rect_.y());
630 instance()->set_plugin_origin(plugin_origin);
631 }
632
633 void WebPluginDelegateImpl::PluginVisibilityChanged() {
634 if (instance()->drawing_model() == NPDrawingModelCoreAnimation) {
635 bool plugin_visible = container_is_visible_ && !clip_rect_.IsEmpty();
636 if (plugin_visible && !redraw_timer_->IsRunning()) {
637 redraw_timer_->Start(FROM_HERE,
638 base::TimeDelta::FromMilliseconds(kCoreAnimationRedrawPeriodMs),
639 this, &WebPluginDelegateImpl::DrawLayerInSurface);
640 } else if (!plugin_visible) {
641 redraw_timer_->Stop();
642 }
643 }
644 }
645
646 void WebPluginDelegateImpl::StartIme() {
647 if (ime_enabled_)
648 return;
649 ime_enabled_ = true;
650 plugin_->StartIme();
651 }
652
653 #pragma mark -
654 #pragma mark Core Animation Support
655
656 void WebPluginDelegateImpl::DrawLayerInSurface() {
657 // If we haven't plumbed up the surface yet, don't try to draw.
658 if (!renderer_)
659 return;
660
661 [renderer_ beginFrameAtTime:CACurrentMediaTime() timeStamp:NULL];
662 if (CGRectIsEmpty([renderer_ updateBounds])) {
663 // If nothing has changed, we are done.
664 [renderer_ endFrame];
665 return;
666 }
667
668 surface_->StartDrawing();
669
670 CGRect layerRect = [layer_ bounds];
671 [renderer_ addUpdateRect:layerRect];
672 [renderer_ render];
673 [renderer_ endFrame];
674
675 surface_->EndDrawing();
676 }
677
678 // Update the size of the surface to match the current size of the plugin.
679 void WebPluginDelegateImpl::UpdateAcceleratedSurface() {
680 if (!surface_ || !layer_)
681 return;
682
683 [CATransaction begin];
684 [CATransaction setValue:[NSNumber numberWithInt:0]
685 forKey:kCATransactionAnimationDuration];
686 [layer_ setFrame:CGRectMake(0, 0,
687 window_rect_.width(), window_rect_.height())];
688 [CATransaction commit];
689
690 [renderer_ setBounds:[layer_ bounds]];
691 surface_->SetSize(window_rect_.size());
692 // Kick off the drawing timer, if necessary.
693 PluginVisibilityChanged();
694 }
695
696 } // namespace content
OLDNEW
« no previous file with comments | « content/child/npapi/webplugin_delegate_impl_aura.cc ('k') | content/child/npapi/webplugin_delegate_impl_win.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698