| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 } |
| OLD | NEW |