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

Side by Side Diff: webkit/glue/plugins/webplugin_delegate_impl_gtk.cc

Issue 56160: Linux: more windowless plugin work. (Closed)
Patch Set: typo Created 11 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
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 // HACK: we need this #define in place before npapi.h is included for 5 // HACK: we need this #define in place before npapi.h is included for
6 // plugins to work. However, all sorts of headers include npapi.h, so 6 // plugins to work. However, all sorts of headers include npapi.h, so
7 // the only way to be certain the define is in place is to put it 7 // the only way to be certain the define is in place is to put it
8 // here. You might ask, "Why not set it in npapi.h directly, or in 8 // here. You might ask, "Why not set it in npapi.h directly, or in
9 // this directory's SConscript, then?" but it turns out this define 9 // this directory's SConscript, then?" but it turns out this define
10 // makes npapi.h include Xlib.h, which in turn defines a ton of symbols 10 // makes npapi.h include Xlib.h, which in turn defines a ton of symbols
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after
164 const gfx::Rect& clip_rect) { 164 const gfx::Rect& clip_rect) {
165 if (windowless_) { 165 if (windowless_) {
166 WindowlessUpdateGeometry(window_rect, clip_rect); 166 WindowlessUpdateGeometry(window_rect, clip_rect);
167 } else { 167 } else {
168 WindowedUpdateGeometry(window_rect, clip_rect); 168 WindowedUpdateGeometry(window_rect, clip_rect);
169 } 169 }
170 } 170 }
171 171
172 void WebPluginDelegateImpl::Paint(cairo_surface_t* context, 172 void WebPluginDelegateImpl::Paint(cairo_surface_t* context,
173 const gfx::Rect& rect) { 173 const gfx::Rect& rect) {
174 if (windowless_) { 174 if (windowless_)
175 WindowlessPaint(context, rect); 175 WindowlessPaint(context, rect);
176 }
177 } 176 }
178 177
179 void WebPluginDelegateImpl::Print(cairo_surface_t* context) { 178 void WebPluginDelegateImpl::Print(cairo_surface_t* context) {
180 NOTIMPLEMENTED(); 179 NOTIMPLEMENTED();
181 } 180 }
182 181
183 NPObject* WebPluginDelegateImpl::GetPluginScriptableObject() { 182 NPObject* WebPluginDelegateImpl::GetPluginScriptableObject() {
184 return instance_->GetPluginScriptableObject(); 183 return instance_->GetPluginScriptableObject();
185 } 184 }
186 185
(...skipping 266 matching lines...) Expand 10 before | Expand all | Expand 10 after
453 452
454 // |sys_visual| is owned by gdk; we shouldn't free it. 453 // |sys_visual| is owned by gdk; we shouldn't free it.
455 GdkVisual* sys_visual = gdk_visual_get_system(); 454 GdkVisual* sys_visual = gdk_visual_get_system();
456 pixmap_ = gdk_pixmap_new(NULL, // use width/height/depth params 455 pixmap_ = gdk_pixmap_new(NULL, // use width/height/depth params
457 width, height, sys_visual->depth); 456 width, height, sys_visual->depth);
458 GdkColormap* colormap = gdk_colormap_new(gdk_visual_get_system(), 457 GdkColormap* colormap = gdk_colormap_new(gdk_visual_get_system(),
459 FALSE); 458 FALSE);
460 gdk_drawable_set_colormap(GDK_DRAWABLE(pixmap_), colormap); 459 gdk_drawable_set_colormap(GDK_DRAWABLE(pixmap_), colormap);
461 } 460 }
462 461
462 #ifdef DEBUG_RECTANGLES
463 namespace {
464
465 // Draw a rectangle on a Cairo surface.
466 // Useful for debugging various rectangles involved in drawing plugins.
467 void DrawDebugRectangle(cairo_surface_t* surface,
468 const gfx::Rect& rect,
469 float r, float g, float b) {
470 cairo_t* cairo = cairo_create(surface);
471 cairo_set_source_rgba(cairo, r, g, b, 0.5);
472 cairo_rectangle(cairo, rect.x(), rect.y(),
473 rect.width(), rect.height());
474 cairo_stroke(cairo);
475 cairo_destroy(cairo);
476 }
477
478 } // namespace
479 #endif
480
463 void WebPluginDelegateImpl::WindowlessPaint(cairo_surface_t* context, 481 void WebPluginDelegateImpl::WindowlessPaint(cairo_surface_t* context,
464 const gfx::Rect& damage_rect) { 482 const gfx::Rect& damage_rect) {
465 // Compare to: 483 // Compare to:
466 // http://mxr.mozilla.org/firefox/source/layout/generic/nsObjectFrame.cpp: 484 // http://mxr.mozilla.org/firefox/source/layout/generic/nsObjectFrame.cpp:
467 // nsPluginInstanceOwner::Renderer::NativeDraw(). 485 // nsPluginInstanceOwner::Renderer::NativeDraw().
468 486
469 DCHECK(context); 487 DCHECK(context);
470 488
471 // We need to pass the DC to the plugin via NPP_SetWindow in the 489 // We need to pass the DC to the plugin via NPP_SetWindow in the
472 // first paint to ensure that it initiates rect invalidations. 490 // first paint to ensure that it initiates rect invalidations.
473 // TODO(evanm): for now, it appears we always need to do this. 491 // TODO(evanm): for now, it appears we always need to do this.
474 if (true) 492 if (true)
475 windowless_needs_set_window_ = true; 493 windowless_needs_set_window_ = true;
476 494
477 // TODO(darin): we should avoid calling NPP_SetWindow here since it may 495 // TODO(darin): we should avoid calling NPP_SetWindow here since it may
478 // cause page layout to be invalidated. 496 // cause page layout to be invalidated.
479 497
480 // We really don't need to continually call SetWindow. 498 // We really don't need to continually call SetWindow.
481 // m_needsSetWindow flags when the geometry has changed. 499 // m_needsSetWindow flags when the geometry has changed.
482 if (windowless_needs_set_window_) 500 if (windowless_needs_set_window_)
483 WindowlessSetWindow(false); 501 WindowlessSetWindow(false);
484 502
485 EnsurePixmapAtLeastSize(damage_rect.width(), damage_rect.height()); 503 // The actual dirty region is just the intersection of the plugin
504 // window with the damage region. However, the plugin wants to draw
505 // relative to the containing window's origin, so our pixmap must be
506 // from the window's origin down to the bottom-right edge of the
507 // dirty region.
508 //
509 // +-----------------------------+-----------------------------+
510 // | | |
511 // | pixmap +-------------+ |
512 // | | damage | window |
513 // | | | |
514 // | +-------+-------------+----------+ |
515 // | | | draw | | |
516 // +-------+-------+-------------+ | |
517 // | | | |
518 // | | plugin | |
519 // | +--------------------------------+ |
520 // | |
521 // | |
522 // +-----------------------------------------------------------+
523 //
524 // TOOD(evanm): on Windows, we instead just translate the origin of
525 // the DC that we hand to the plugin. Does such a thing exist on X?
526 // TODO(evanm): make use of the clip rect as well.
527
528 gfx::Rect plugin_rect(window_.x, window_.y, window_.width, window_.height);
529 gfx::Rect draw_rect = plugin_rect.Intersect(damage_rect);
530
531 gfx::Rect pixmap_rect(0, 0,
532 draw_rect.x() + draw_rect.width(),
533 draw_rect.y() + draw_rect.height());
534
535 EnsurePixmapAtLeastSize(pixmap_rect.width(), pixmap_rect.height());
486 536
487 // Copy the current image into the pixmap, so the plugin can draw over 537 // Copy the current image into the pixmap, so the plugin can draw over
488 // this background. 538 // this background.
489 cairo_t* cairo = gdk_cairo_create(pixmap_); 539 cairo_t* cairo = gdk_cairo_create(pixmap_);
490 cairo_set_source_surface(cairo, context, 0, 0); 540 cairo_set_source_surface(cairo, context, 0, 0);
541 cairo_rectangle(cairo, draw_rect.x(), draw_rect.y(),
542 draw_rect.width(), draw_rect.height());
543 cairo_clip(cairo);
491 cairo_paint(cairo); 544 cairo_paint(cairo);
492 cairo_destroy(cairo); 545 cairo_destroy(cairo);
493 546
494 // Construct the paint message, targeting the pixmap. 547 // Construct the paint message, targeting the pixmap.
495 XGraphicsExposeEvent event = {0}; 548 XGraphicsExposeEvent event = {0};
496 event.type = GraphicsExpose; 549 event.type = GraphicsExpose;
497 event.display = GDK_DISPLAY(); 550 event.display = GDK_DISPLAY();
498 event.drawable = GDK_PIXMAP_XID(pixmap_); 551 event.drawable = GDK_PIXMAP_XID(pixmap_);
499 event.x = damage_rect.x(); 552 event.x = draw_rect.x();
500 event.y = damage_rect.y(); 553 event.y = draw_rect.y();
501 event.width = damage_rect.width(); 554 event.width = draw_rect.width();
502 event.height = damage_rect.height(); 555 event.height = draw_rect.height();
503 556
504 // Tell the plugin to paint into the pixmap. 557 // Tell the plugin to paint into the pixmap.
505 static StatsRate plugin_paint("Plugin.Paint"); 558 static StatsRate plugin_paint("Plugin.Paint");
506 StatsScope<StatsRate> scope(plugin_paint); 559 StatsScope<StatsRate> scope(plugin_paint);
507 NPError err = instance()->NPP_HandleEvent(reinterpret_cast<XEvent*>(&event)); 560 NPError err = instance()->NPP_HandleEvent(reinterpret_cast<XEvent*>(&event));
508 DCHECK_EQ(err, NPERR_NO_ERROR); 561 DCHECK_EQ(err, NPERR_NO_ERROR);
509 562
510 // Now copy the rendered image pixmap back into the drawing buffer. 563 // Now copy the rendered image pixmap back into the drawing buffer.
511 cairo = cairo_create(context); 564 cairo = cairo_create(context);
512 gdk_cairo_set_source_pixmap(cairo, pixmap_, 0, 0); 565 gdk_cairo_set_source_pixmap(cairo, pixmap_, 0, 0);
566 cairo_rectangle(cairo, draw_rect.x(), draw_rect.y(),
567 draw_rect.width(), draw_rect.height());
568 cairo_clip(cairo);
513 cairo_paint(cairo); 569 cairo_paint(cairo);
514 cairo_destroy(cairo); 570 cairo_destroy(cairo);
571
572 #ifdef DEBUG_RECTANGLES
573 // Draw some debugging rectangles.
574 // Pixmap rect = blue.
575 DrawDebugRectangle(context, pixmap_rect, 0, 0, 1);
576 // Drawing rect = red.
577 DrawDebugRectangle(context, draw_rect, 1, 0, 0);
578 #endif
515 } 579 }
516 580
517 void WebPluginDelegateImpl::WindowlessSetWindow(bool force_set_window) { 581 void WebPluginDelegateImpl::WindowlessSetWindow(bool force_set_window) {
518 if (!instance()) 582 if (!instance())
519 return; 583 return;
520 584
521 if (window_rect_.IsEmpty()) // wait for geometry to be set. 585 if (window_rect_.IsEmpty()) // wait for geometry to be set.
522 return; 586 return;
523 587
524 DCHECK(instance()->windowless()); 588 DCHECK(instance()->windowless());
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
561 /* NPEvent focus_event; 625 /* NPEvent focus_event;
562 focus_event.event = WM_SETFOCUS; 626 focus_event.event = WM_SETFOCUS;
563 focus_event.wParam = 0; 627 focus_event.wParam = 0;
564 focus_event.lParam = 0; 628 focus_event.lParam = 0;
565 629
566 instance()->NPP_HandleEvent(&focus_event);*/ 630 instance()->NPP_HandleEvent(&focus_event);*/
567 } 631 }
568 632
569 bool WebPluginDelegateImpl::HandleEvent(NPEvent* event, 633 bool WebPluginDelegateImpl::HandleEvent(NPEvent* event,
570 WebCursor* cursor) { 634 WebCursor* cursor) {
571 NOTIMPLEMENTED();
572 #if 0
573 DCHECK(windowless_) << "events should only be received in windowless mode";
574 DCHECK(cursor != NULL);
575
576 // To ensure that the plugin receives keyboard events we set focus to the
577 // dummy window.
578 // TODO(iyengar) We need a framework in the renderer to identify which
579 // windowless plugin is under the mouse and to handle this. This would
580 // also require some changes in RenderWidgetHost to detect this in the
581 // WM_MOUSEACTIVATE handler and inform the renderer accordingly.
582 HWND prev_focus_window = NULL;
583 if (event->event == WM_RBUTTONDOWN) {
584 prev_focus_window = ::SetFocus(dummy_window_for_activation_);
585 }
586
587 if (ShouldTrackEventForModalLoops(event)) {
588 // A windowless plugin can enter a modal loop in a NPP_HandleEvent call.
589 // For e.g. Flash puts up a context menu when we right click on the
590 // windowless plugin area. We detect this by setting up a message filter
591 // hook pror to calling NPP_HandleEvent on the plugin and unhook on
592 // return from NPP_HandleEvent. If the plugin does enter a modal loop
593 // in that context we unhook on receiving the first notification in
594 // the message filter hook.
595 handle_event_message_filter_hook_ =
596 SetWindowsHookEx(WH_MSGFILTER, HandleEventMessageFilterHook, NULL,
597 GetCurrentThreadId());
598 }
599
600 bool old_task_reentrancy_state =
601 MessageLoop::current()->NestableTasksAllowed();
602
603 current_plugin_instance_ = this;
604
605 handle_event_depth_++;
606
607 bool pop_user_gesture = false;
608
609 if (IsUserGestureMessage(event->event)) {
610 pop_user_gesture = true;
611 instance()->PushPopupsEnabledState(true);
612 }
613
614 bool ret = instance()->NPP_HandleEvent(event) != 0; 635 bool ret = instance()->NPP_HandleEvent(event) != 0;
615 636
637 #if 0
616 if (event->event == WM_MOUSEMOVE) { 638 if (event->event == WM_MOUSEMOVE) {
617 // Snag a reference to the current cursor ASAP in case the plugin modified 639 // Snag a reference to the current cursor ASAP in case the plugin modified
618 // it. There is a nasty race condition here with the multiprocess browser 640 // it. There is a nasty race condition here with the multiprocess browser
619 // as someone might be setting the cursor in the main process as well. 641 // as someone might be setting the cursor in the main process as well.
620 *cursor = current_windowless_cursor_; 642 *cursor = current_windowless_cursor_;
621 } 643 }
622 644 #endif
623 if (pop_user_gesture) {
624 instance()->PopPopupsEnabledState();
625 }
626
627 handle_event_depth_--;
628
629 current_plugin_instance_ = NULL;
630
631 MessageLoop::current()->SetNestableTasksAllowed(old_task_reentrancy_state);
632
633 if (handle_event_message_filter_hook_) {
634 UnhookWindowsHookEx(handle_event_message_filter_hook_);
635 handle_event_message_filter_hook_ = NULL;
636 }
637
638 // We could have multiple NPP_HandleEvent calls nested together in case
639 // the plugin enters a modal loop. Reset the pump messages event when
640 // the outermost NPP_HandleEvent call unwinds.
641 if (handle_event_depth_ == 0) {
642 ResetEvent(handle_event_pump_messages_event_);
643 }
644
645 if (event->event == WM_RBUTTONUP && ::IsWindow(prev_focus_window)) {
646 ::SetFocus(prev_focus_window);
647 }
648 645
649 return ret; 646 return ret;
650 #endif
651 return 0;
652 } 647 }
653 648
654 WebPluginResourceClient* WebPluginDelegateImpl::CreateResourceClient( 649 WebPluginResourceClient* WebPluginDelegateImpl::CreateResourceClient(
655 int resource_id, const std::string &url, bool notify_needed, 650 int resource_id, const std::string &url, bool notify_needed,
656 intptr_t notify_data, intptr_t existing_stream) { 651 intptr_t notify_data, intptr_t existing_stream) {
657 // Stream already exists. This typically happens for range requests 652 // Stream already exists. This typically happens for range requests
658 // initiated via NPN_RequestRead. 653 // initiated via NPN_RequestRead.
659 if (existing_stream) { 654 if (existing_stream) {
660 NPAPI::PluginStream* plugin_stream = 655 NPAPI::PluginStream* plugin_stream =
661 reinterpret_cast<NPAPI::PluginStream*>(existing_stream); 656 reinterpret_cast<NPAPI::PluginStream*>(existing_stream);
(...skipping 13 matching lines...) Expand all
675 return stream; 670 return stream;
676 } 671 }
677 672
678 void WebPluginDelegateImpl::URLRequestRouted(const std::string&url, 673 void WebPluginDelegateImpl::URLRequestRouted(const std::string&url,
679 bool notify_needed, 674 bool notify_needed,
680 intptr_t notify_data) { 675 intptr_t notify_data) {
681 if (notify_needed) { 676 if (notify_needed) {
682 instance()->SetURLLoadData(GURL(url.c_str()), notify_data); 677 instance()->SetURLLoadData(GURL(url.c_str()), notify_data);
683 } 678 }
684 } 679 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698