1/* 2 * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. 3 * Copyright (C) 2008 Collabora Ltd. All rights reserved. 4 * Copyright (C) 2009 Girish Ramakrishnan <girish@forwardbias.in> 5 * Copyright (C) 2011 Research In Motion Limited. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 20 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 23 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 24 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29#include "config.h" 30#include "PluginView.h" 31 32#include "DocumentLoader.h" 33#include "Event.h" 34#include "EventNames.h" 35#include "Frame.h" 36#include "FrameView.h" 37#include "HTMLNames.h" 38#include "HTMLPlugInElement.h" 39#include "HostWindow.h" 40#include "JSDOMBinding.h" 41#include "KeyboardEvent.h" 42#include "MouseEvent.h" 43#include "NPCallbacksBlackBerry.h" 44#include "NotImplemented.h" 45#include "Page.h" 46#include "PlatformKeyboardEvent.h" 47#include "PluginDebug.h" 48#include "PluginMainThreadScheduler.h" 49#include "PluginPackage.h" 50#include "PluginViewPrivateBlackBerry.h" 51#include "RenderLayer.h" 52#include "Settings.h" 53#include "TouchEvent.h" 54#include "TouchList.h" 55#include "WheelEvent.h" 56#include "npruntime_impl.h" 57#include "runtime_root.h" 58 59#if USE(ACCELERATED_COMPOSITING) 60#include "Chrome.h" 61#include "ChromeClient.h" 62#include "PluginLayerWebKitThread.h" 63#endif 64 65#include <BlackBerryPlatformGraphics.h> 66#include <BlackBerryPlatformIntRectRegion.h> 67#include <BlackBerryPlatformWindow.h> 68 69#include <runtime/JSCJSValue.h> 70#include <runtime/JSLock.h> 71#include <sys/keycodes.h> 72#include <vector> 73 74const unsigned UninitializedCoordinate = 0xffffffff; 75 76namespace WebCore { 77 78template<class T> static NPRect toNPRect(const T& rect) 79{ 80 NPRect npRect; 81 npRect.top = rect.y(); 82 npRect.left = rect.x(); 83 npRect.bottom = rect.y() + rect.height(); 84 npRect.right = rect.x() + rect.width(); 85 return npRect; 86} 87 88using JSC::ExecState; 89using JSC::Interpreter; 90using JSC::JSLock; 91using JSC::JSObject; 92 93using namespace std; 94using namespace WTF; 95using namespace HTMLNames; 96 97void PluginView::updatePluginWidget() 98{ 99 if (!parent() || !m_private) 100 return; 101 102 ASSERT(parent()->isFrameView()); 103 FrameView* frameView = toFrameView(parent()); 104 105 IntRect oldWindowRect = m_windowRect; 106 IntRect oldClipRect = m_clipRect; 107 108 m_windowRect = IntRect(frameView->contentsToWindow(frameRect().location()), frameRect().size()); 109 110 ScrollView* theRoot = root(); 111 if (!theRoot) 112 return; // ASSERT(parent()->isFrameView()) should prevent this but check just in case 113 // Map rect to content coordinate space of main frame. 114 m_windowRect.move(theRoot->scrollOffset()); 115 116 m_clipRect = calculateClipRect(); 117 118 // Notify the plugin if it may or may not be on/offscreen. 119 handleScrollEvent(); 120 121 bool zoomFactorChanged = ((NPSetWindowCallbackStruct*)m_npWindow.ws_info)->zoomFactor 122 != frameView->hostWindow()->platformPageClient()->currentZoomFactor(); 123 124 if (!zoomFactorChanged && m_windowRect == oldWindowRect && m_clipRect == oldClipRect) 125 return; 126 127 // Do not call setNPWindowIfNeeded immediately, will be called on paint(). 128 m_private->m_hasPendingGeometryChange = true; 129 130 // (i) In order to move/resize the plugin window at the same time as the 131 // rest of frame during e.g. scrolling, we set the window geometry 132 // in the paint() function, but as paint() isn't called when the 133 // plugin window is outside the frame which can be caused by a 134 // scroll, we need to move/resize immediately. 135 // (ii) If we are running layout tests from DRT, paint() won't ever get called 136 // so we need to call setNPWindowIfNeeded() if window geometry has changed. 137 if (m_clipRect.isEmpty() || (platformPluginWidget() && (m_windowRect != oldWindowRect || m_clipRect != oldClipRect || zoomFactorChanged))) 138 setNPWindowIfNeeded(); 139 140 // Make sure we get repainted afterwards. This is necessary for downward 141 // scrolling to move the plugin widget properly. 142 invalidate(); 143} 144 145void PluginView::setFocus(bool focused) 146{ 147 if (!m_private || m_private->m_isFocused == focused) 148 return; 149 150 ASSERT(platformPluginWidget() == platformWidget()); 151 Widget::setFocus(focused); 152 153 if (focused) 154 handleFocusInEvent(); 155 else 156 handleFocusOutEvent(); 157} 158 159void PluginView::show() 160{ 161 setSelfVisible(true); 162 Widget::show(); 163 updatePluginWidget(); 164} 165 166void PluginView::hide() 167{ 168 setSelfVisible(false); 169 Widget::hide(); 170 updatePluginWidget(); 171} 172 173void PluginView::updateBuffer(const IntRect& bufferRect) 174{ 175 if (!m_private) 176 return; 177 178 // Update the zoom factor here, it happens right before setNPWindowIfNeeded 179 // ensuring that the plugin has every opportunity to get the zoom factor before 180 // it paints anything. 181 if (FrameView* frameView = toFrameView(parent())) 182 m_private->setZoomFactor(frameView->hostWindow()->platformPageClient()->currentZoomFactor()); 183 184 setNPWindowIfNeeded(); 185 186 // Build and dispatch an event to the plugin to notify it we are about to draw whatever 187 // is in the front buffer. This is it's opportunity to do a swap. 188 IntRect exposedRect(bufferRect); 189 exposedRect.intersect(IntRect(IntPoint(0, 0), frameRect().size())); 190 191 // Only ask the plugin to draw if the exposed rect was explicitly invalidated 192 // by the plugin. 193 BlackBerry::Platform::IntRectRegion exposedRegion = BlackBerry::Platform::IntRectRegion::intersectRegions(m_private->m_invalidateRegion, BlackBerry::Platform::IntRect(exposedRect)); 194 if (!exposedRegion.isEmpty()) { 195 m_private->m_invalidateRegion = BlackBerry::Platform::IntRectRegion::subtractRegions(m_private->m_invalidateRegion, exposedRegion); 196 std::vector<BlackBerry::Platform::IntRect> exposedRects = exposedRegion.rects(); 197 for (unsigned i = 0; i < exposedRects.size(); ++i) { 198 NPDrawEvent draw; 199 NPRect tempRect = toNPRect(exposedRects.at(i)); 200 draw.pluginRect = toNPRect(m_windowRect); 201 draw.clipRect = toNPRect(m_clipRect); 202 draw.drawRect = &tempRect; 203 draw.drawRectCount = 1; 204 draw.zoomFactor = ((NPSetWindowCallbackStruct*)m_npWindow.ws_info)->zoomFactor; 205 206 NPEvent npEvent; 207 npEvent.type = NP_DrawEvent; 208 npEvent.data = &draw; 209 210 // FIXME: Return early if this fails? Or just repaint? 211 dispatchNPEvent(npEvent); 212 } 213 } 214} 215 216void PluginView::paint(GraphicsContext* context, const IntRect& rect) 217{ 218 if (!m_private || !m_isStarted) { 219 paintMissingPluginIcon(context, rect); 220 return; 221 } 222 223 // Update the zoom factor here, it happens right before setNPWindowIfNeeded 224 // ensuring that the plugin has every opportunity to get the zoom factor before 225 // it paints anything. 226 if (FrameView* frameView = toFrameView(parent())) 227 m_private->setZoomFactor(frameView->hostWindow()->platformPageClient()->currentZoomFactor()); 228 229 if (context->paintingDisabled()) 230 return; 231 232 setNPWindowIfNeeded(); 233 234#if USE(ACCELERATED_COMPOSITING) 235 if (m_private->m_platformLayer) 236 return; 237#endif 238 239 // Build and dispatch an event to the plugin to notify it we are about to draw whatever 240 // is in the front buffer. This is it's opportunity to do a swap. 241 IntRect rectClip(rect); 242 rectClip.intersect(frameRect()); 243 244 IntRect exposedRect(rectClip); 245 exposedRect.move(-frameRect().x(), -frameRect().y()); 246 247 updateBuffer(exposedRect); 248} 249 250 251bool PluginView::dispatchFullScreenNPEvent(NPEvent& event) 252{ 253 if (!m_private) 254 return false; 255 256 ASSERT(m_private->m_isFullScreen); 257 return dispatchNPEvent(event); 258} 259 260// FIXME: Unify across ports. 261bool PluginView::dispatchNPEvent(NPEvent& event) 262{ 263 if (!m_plugin || !m_plugin->pluginFuncs()->event) 264 return false; 265 266 PluginView::setCurrentPluginView(this); 267 JSC::JSLock::DropAllLocks dropAllLocks(JSDOMWindowBase::commonVM()); 268 setCallingPlugin(true); 269 270 bool accepted = m_plugin->pluginFuncs()->event(m_instance, &event); 271 272 setCallingPlugin(false); 273 PluginView::setCurrentPluginView(0); 274 275 return accepted; 276} 277 278void PluginView::handleKeyboardEvent(KeyboardEvent* event) 279{ 280 NPEvent npEvent; 281 NPKeyboardEvent keyEvent; 282 const PlatformKeyboardEvent *platformKeyEvent = event->keyEvent(); 283 284 keyEvent.modifiers = 0; 285 286 if (platformKeyEvent->shiftKey()) 287 keyEvent.modifiers |= KEYMOD_SHIFT; 288 289 if (platformKeyEvent->ctrlKey()) 290 keyEvent.modifiers |= KEYMOD_CTRL; 291 292 if (platformKeyEvent->altKey()) 293 keyEvent.modifiers |= KEYMOD_ALT; 294 295 if (platformKeyEvent->metaKey()) 296 keyEvent.modifiers |= KEYMOD_ALTGR; 297 298 keyEvent.cap = platformKeyEvent->unmodifiedCharacter(); 299 keyEvent.sym = keyEvent.cap; 300 keyEvent.scan = 0; 301 keyEvent.flags = 0; 302 303 if (platformKeyEvent->type() == PlatformKeyboardEvent::RawKeyDown 304 || platformKeyEvent->type() == PlatformKeyboardEvent::KeyDown) { 305 keyEvent.flags = KEY_DOWN | KEY_SYM_VALID | KEY_CAP_VALID; 306 } else if (platformKeyEvent->type() == PlatformKeyboardEvent::KeyUp) 307 keyEvent.flags = KEY_SYM_VALID | KEY_CAP_VALID; 308 309 npEvent.type = NP_KeyEvent; 310 npEvent.data = &keyEvent; 311 if (dispatchNPEvent(npEvent)) 312 event->setDefaultHandled(); 313} 314 315void PluginView::handleWheelEvent(WheelEvent* event) 316{ 317 if (!m_private) 318 return; 319 320 if (!m_private->m_isFocused) 321 focusPluginElement(); 322 323 NPEvent npEvent; 324 NPWheelEvent wheelEvent; 325 326 wheelEvent.x = event->offsetX(); 327 wheelEvent.y = event->offsetY(); 328 329 wheelEvent.flags = 0; 330 331 wheelEvent.xDelta = event->rawDeltaX(); 332 wheelEvent.yDelta = event->rawDeltaY(); 333 334 npEvent.type = NP_WheelEvent; 335 npEvent.data = &wheelEvent; 336 337 if (dispatchNPEvent(npEvent)) 338 event->setDefaultHandled(); 339} 340 341void PluginView::handleTouchEvent(TouchEvent* event) 342{ 343 if (!m_private) 344 return; 345 346 if (!m_private->m_isFocused) 347 focusPluginElement(); 348 349 NPTouchEvent npTouchEvent; 350 351 if (event->isDoubleTap()) 352 npTouchEvent.type = TOUCH_EVENT_DOUBLETAP; 353 else if (event->isTouchHold()) 354 npTouchEvent.type = TOUCH_EVENT_TOUCHHOLD; 355 else if (event->type() == eventNames().touchcancelEvent) 356 npTouchEvent.type = TOUCH_EVENT_CANCEL; 357 else 358 return; 359 360 TouchList* touchList; 361 // The touches list is empty if in a touch end event. 362 // Since DoubleTap is ususally a TouchEnd Use changedTouches instead. 363 if (npTouchEvent.type == TOUCH_EVENT_DOUBLETAP) 364 touchList = event->changedTouches(); 365 else 366 touchList = event->touches(); 367 368 npTouchEvent.points = 0; 369 npTouchEvent.size = touchList->length(); 370 371 OwnArrayPtr<NPTouchPoint> touchPoints; 372 if (touchList->length()) { 373 touchPoints = adoptArrayPtr(new NPTouchPoint[touchList->length()]); 374 npTouchEvent.points = touchPoints.get(); 375 for (unsigned i = 0; i < touchList->length(); i++) { 376 Touch* touchItem = touchList->item(i); 377 touchPoints[i].touchId = touchItem->identifier(); 378 touchPoints[i].clientX = touchItem->pageX() - frameRect().x(); 379 touchPoints[i].clientY = touchItem->pageY() - frameRect().y(); 380 touchPoints[i].screenX = touchItem->screenX(); 381 touchPoints[i].screenY = touchItem->screenY(); 382 touchPoints[i].pageX = touchItem->pageX(); 383 touchPoints[i].pageY = touchItem->pageY(); 384 385 } 386 } 387 388 NPEvent npEvent; 389 npEvent.type = NP_TouchEvent; 390 npEvent.data = &npTouchEvent; 391 392 if (dispatchNPEvent(npEvent)) 393 event->setDefaultHandled(); 394} 395 396void PluginView::handleMouseEvent(MouseEvent* event) 397{ 398 if (!m_private) 399 return; 400 401 if (!m_private->m_isFocused) 402 focusPluginElement(); 403 404 NPEvent npEvent; 405 NPMouseEvent mouseEvent; 406 407 mouseEvent.x = event->offsetX(); 408 mouseEvent.y = event->offsetY(); 409 410 if (event->type() == eventNames().mousedownEvent) 411 mouseEvent.type = MOUSE_BUTTON_DOWN; 412 else if (event->type() == eventNames().mousemoveEvent) 413 mouseEvent.type = MOUSE_MOTION; 414 else if (event->type() == eventNames().mouseoutEvent) 415 mouseEvent.type = MOUSE_OUTBOUND; 416 else if (event->type() == eventNames().mouseoverEvent) 417 mouseEvent.type = MOUSE_OVER; 418 else if (event->type() == eventNames().mouseupEvent) 419 mouseEvent.type = MOUSE_BUTTON_UP; 420 else 421 return; 422 423 mouseEvent.button = event->button(); 424 mouseEvent.flags = 0; 425 426 npEvent.type = NP_MouseEvent; 427 npEvent.data = &mouseEvent; 428 429 if (dispatchNPEvent(npEvent)) 430 event->setDefaultHandled(); 431} 432 433void PluginView::handleFocusInEvent() 434{ 435 if (!m_private) 436 return; 437 438 if (m_private->m_isFocused) 439 return; 440 441 m_private->m_isFocused = true; 442 443 NPEvent npEvent; 444 npEvent.type = NP_FocusGainedEvent; 445 npEvent.data = 0; 446 dispatchNPEvent(npEvent); 447} 448 449void PluginView::handleFocusOutEvent() 450{ 451 if (!m_private) 452 return; 453 454 if (!m_private->m_isFocused) 455 return; 456 457 m_private->m_isFocused = false; 458 459 NPEvent npEvent; 460 npEvent.type = NP_FocusLostEvent; 461 npEvent.data = 0; 462 dispatchNPEvent(npEvent); 463} 464 465void PluginView::handlePauseEvent() 466{ 467 NPEvent npEvent; 468 npEvent.type = NP_PauseEvent; 469 npEvent.data = 0; 470 dispatchNPEvent(npEvent); 471} 472 473void PluginView::handleResumeEvent() 474{ 475 NPEvent npEvent; 476 npEvent.type = NP_ResumeEvent; 477 npEvent.data = 0; 478 dispatchNPEvent(npEvent); 479} 480 481void PluginView::handleScrollEvent() 482{ 483 FrameView* frameView = toFrameView(parent()); 484 485 // As a special case, if the frameView extent in either dimension is 486 // empty, then send an on screen event. This is important for sites like 487 // picnik.com which use a hidden iframe (read: width = 0 and height = 0) 488 // with an embedded swf to execute some javascript. Unless we send an 489 // on screen event the swf will not execute the javascript and the real 490 // site will never load. 491 bool onScreenEvent = frameView && (!frameView->width() || !frameView->height()); 492 493 NPEvent npEvent; 494 npEvent.type = m_clipRect.isEmpty() && !onScreenEvent ? NP_OffScreenEvent : NP_OnScreenEvent; 495 npEvent.data = 0; 496 dispatchNPEvent(npEvent); 497} 498 499IntRect PluginView::calculateClipRect() const 500{ 501 FrameView* frameView = toFrameView(parent()); 502 bool visible = frameView && isVisible(); 503 504 if (visible && frameView->width() && frameView->height()) { 505 IntSize windowSize = frameView->hostWindow()->platformPageClient()->viewportSize(); 506 507 // Get the clipped rectangle for this player within the current frame. 508 IntRect visibleContentRect; 509 IntRect contentRect = m_element->renderer()->absoluteClippedOverflowRect(); 510 FloatPoint contentLocal = m_element->renderer()->absoluteToLocal(FloatPoint(contentRect.location())); 511 512 contentRect.setLocation(roundedIntPoint(contentLocal)); 513 contentRect.move(frameRect().x(), frameRect().y()); 514 515 // Clip against any frames that the widget is inside. Note that if the frames are also clipped 516 // by a div, that will not be included in this calculation. That is an improvement that still 517 // needs to be made. 518 const Widget* current = this; 519 while (current->parent() && visible) { 520 // Determine if it is visible in this scrollview. 521 visibleContentRect = current->parent()->visibleContentRect(); 522 523 // Special case for the root ScrollView. Its size does not match the actual window size. 524 if (current->parent() == root()) 525 visibleContentRect.setSize(windowSize); 526 527 contentRect.intersect(visibleContentRect); 528 visible = !contentRect.isEmpty(); 529 530 // Offset to visible coordinates in scrollview widget's coordinate system (except in the case of 531 // the top scroll view). 532 if (current->parent()->parent()) 533 contentRect.move(-visibleContentRect.x(), -visibleContentRect.y()); 534 535 current = current->parent(); 536 537 // Don't include the offset for the root window or we get the wrong coordinates. 538 if (current->parent()) { 539 // Move content rect into the parent scrollview's coordinates. 540 IntRect curFrameRect = current->frameRect(); 541 contentRect.move(curFrameRect.x(), curFrameRect.y()); 542 } 543 } 544 545 return contentRect; 546 } 547 548 return IntRect(); 549} 550 551void PluginView::handleOnLoadEvent() 552{ 553 if (!m_private) 554 return; 555 556 if (m_private->m_sentOnLoad) 557 return; 558 559 m_private->m_sentOnLoad = true; 560 561 NPEvent npEvent; 562 npEvent.type = NP_OnLoadEvent; 563 npEvent.data = 0; 564 565 dispatchNPEvent(npEvent); 566 567 // Send an initial OnScreen/OffScreen event. It must always come after onLoad is sent. 568 handleScrollEvent(); 569} 570 571void PluginView::handleFreeMemoryEvent() 572{ 573 NPEvent npEvent; 574 npEvent.type = NP_FreeMemoryEvent; 575 npEvent.data = 0; 576 577 dispatchNPEvent(npEvent); 578} 579 580void PluginView::handleBackgroundEvent() 581{ 582 NPEvent npEvent; 583 npEvent.type = NP_BackgroundEvent; 584 npEvent.data = 0; 585 586 dispatchNPEvent(npEvent); 587} 588 589void PluginView::handleForegroundEvent() 590{ 591 setNPWindowIfNeeded(); 592 593 NPEvent npEvent; 594 npEvent.type = NP_ForegroundEvent; 595 npEvent.data = 0; 596 597 dispatchNPEvent(npEvent); 598} 599 600void PluginView::handleFullScreenAllowedEvent() 601{ 602 if (!m_private) 603 return; 604 605 NPEvent npEvent; 606 npEvent.type = NP_FullScreenReadyEvent; 607 npEvent.data = 0; 608 609 if (FrameView* frameView = toFrameView(parent())) { 610 frameView->hostWindow()->platformPageClient()->didPluginEnterFullScreen(this, m_private->m_pluginUniquePrefix.c_str()); 611 612 if (!dispatchNPEvent(npEvent)) 613 frameView->hostWindow()->platformPageClient()->didPluginExitFullScreen(this, m_private->m_pluginUniquePrefix.c_str()); 614 else 615 m_private->m_isFullScreen = true; 616 } 617} 618 619void PluginView::handleFullScreenExitEvent() 620{ 621 if (!m_private) 622 return; 623 624 NPEvent npEvent; 625 npEvent.type = NP_FullScreenExitEvent; 626 npEvent.data = 0; 627 628 dispatchNPEvent(npEvent); 629 630 if (FrameView* frameView = toFrameView(parent())) 631 frameView->hostWindow()->platformPageClient()->didPluginExitFullScreen(this, m_private->m_pluginUniquePrefix.c_str()); 632 633 m_private->m_isFullScreen = false; 634 invalidate(); 635} 636 637void PluginView::handleIdleEvent(bool enterIdle) 638{ 639 NPEvent npEvent; 640 npEvent.data = 0; 641 642 if (enterIdle) 643 npEvent.type = NP_EnterIdleEvent; 644 else 645 npEvent.type = NP_ExitIdleEvent; 646 647 dispatchNPEvent(npEvent); 648} 649 650 651void PluginView::handleAppActivatedEvent() 652{ 653 NPEvent npEvent; 654 npEvent.data = 0; 655 npEvent.type = NP_AppActivatedEvent; 656 657 dispatchNPEvent(npEvent); 658} 659 660void PluginView::handleAppDeactivatedEvent() 661{ 662 if (!m_private) 663 return; 664 665 // Plugin wants to know that it has to exit fullscreen on deactivation. 666 if (m_private->m_isFullScreen) 667 handleFullScreenExitEvent(); 668 669 NPEvent npEvent; 670 npEvent.data = 0; 671 npEvent.type = NP_AppDeactivatedEvent; 672 673 dispatchNPEvent(npEvent); 674} 675 676void PluginView::handleAppStandbyEvent() 677{ 678 // FIXME: This should send an QNP_AppStandbyEvent 679 NPEvent npEvent; 680 npEvent.data = 0; 681 npEvent.type = NP_AppStandByEvent; 682 683 dispatchNPEvent(npEvent); 684} 685 686void PluginView::handleOrientationEvent(int angle) 687{ 688 NPEvent npEvent; 689 npEvent.type = NP_OrientationEvent; 690 npEvent.data = (void*)angle; 691 692 dispatchNPEvent(npEvent); 693} 694 695void PluginView::handleSwipeEvent() 696{ 697 if (!m_private) 698 return; 699 700 // Plugin only wants to know that it has to exit fullscreen. 701 if (m_private->m_isFullScreen) 702 handleFullScreenExitEvent(); 703} 704 705void PluginView::handleScreenPowerEvent(bool powered) 706{ 707 NPEvent npEvent; 708 npEvent.data = 0; 709 710 if (powered) 711 npEvent.type = NP_ScreenPowerUpEvent; 712 else 713 npEvent.type = NP_ScreenPowerDownEvent; 714 715 dispatchNPEvent(npEvent); 716} 717 718void PluginView::setParent(ScrollView* parentWidget) 719{ 720 // If parentWidget is 0, lets unregister the plugin with the current parent. 721 if (m_private && (!parentWidget || parentWidget != parent())) { 722 if (FrameView* frameView = toFrameView(parent())) { 723 if (m_private->m_isBackgroundPlaying) 724 frameView->hostWindow()->platformPageClient()->onPluginStopBackgroundPlay(this, m_private->m_pluginUniquePrefix.c_str()); 725 726 if (m_private->m_isFullScreen) 727 handleFullScreenExitEvent(); 728 729 // This will unlock the idle (if we have locked it). 730 m_private->preventIdle(false); 731 732 // This will release any keepVisibleRects if they were set. 733 m_private->clearVisibleRects(); 734 735#if USE(ACCELERATED_COMPOSITING) 736 // If we had a hole punch rect set, clear it. 737 if (m_private->m_platformLayer && !m_private->m_holePunchRect.isEmpty()) 738 m_private->m_platformLayer->setHolePunchRect(IntRect()); 739#endif 740 frameView->hostWindow()->platformPageClient()->registerPlugin(this, false /*shouldRegister*/); 741 } 742 } 743 744 Widget::setParent(parentWidget); 745 746 if (parentWidget) { 747 init(); 748 749 FrameView* frameView = toFrameView(parentWidget); 750 751 if (frameView && m_private) { 752 frameView->hostWindow()->platformPageClient()->registerPlugin(this, true /*shouldRegister*/); 753 if (frameView->frame() 754 && frameView->frame()->loader() 755 && frameView->frame()->loader()->frameHasLoaded()) 756 handleOnLoadEvent(); 757 758 if (m_private->m_isBackgroundPlaying) 759 frameView->hostWindow()->platformPageClient()->onPluginStartBackgroundPlay(this, m_private->m_pluginUniquePrefix.c_str()); 760 } 761 } 762} 763 764void PluginView::setNPWindowRect(const IntRect&) 765{ 766 setNPWindowIfNeeded(); 767} 768 769void PluginView::setNPWindowIfNeeded() 770{ 771 if (!m_private || !m_isStarted || !parent() || !m_plugin->pluginFuncs()->setwindow) 772 return; 773 774 FrameView* frameView = toFrameView(parent()); 775 if (!frameView->hostWindow()->platformPageClient()->isActive()) 776 return; 777 778 // If the plugin didn't load sucessfully, no point in calling setwindow 779 if (m_status != PluginStatusLoadedSuccessfully) 780 return; 781 782 if (m_private->m_isFullScreen) 783 return; 784 785 if (!m_private->m_hasPendingGeometryChange) 786 return; 787 788 m_private->m_hasPendingGeometryChange = false; 789 790 m_npWindow.x = m_windowRect.x(); 791 m_npWindow.y = m_windowRect.y(); 792 793 m_npWindow.clipRect.left = max(0, m_clipRect.x()); 794 m_npWindow.clipRect.top = max(0, m_clipRect.y()); 795 m_npWindow.clipRect.right = max(0, m_clipRect.maxX()); 796 m_npWindow.clipRect.bottom = max(0, m_clipRect.maxY()); 797 798 if (m_plugin->quirks().contains(PluginQuirkDontCallSetWindowMoreThanOnce)) { 799 // Only set the width and height of the plugin content the first time setNPWindow() is called 800 // so as to workaround an issue in Flash where multiple calls to setNPWindow() cause the plugin 801 // to crash in windowed mode. 802 if (!m_isWindowed || m_npWindow.width == UninitializedCoordinate || m_npWindow.height == UninitializedCoordinate) { 803 m_npWindow.width = m_windowRect.width(); 804 m_npWindow.height = m_windowRect.height(); 805 } 806 } else { 807 m_npWindow.width = m_windowRect.width(); 808 m_npWindow.height = m_windowRect.height(); 809 } 810 811 m_npWindow.type = NPWindowTypeDrawable; 812 813 BlackBerry::Platform::Graphics::Window* window = frameView->hostWindow()->platformPageClient()->platformWindow(); 814 if (window) 815 ((NPSetWindowCallbackStruct*)m_npWindow.ws_info)->windowGroup = window->windowGroup(); 816 817 PluginView::setCurrentPluginView(this); 818 JSC::JSLock::DropAllLocks dropAllLocks(JSDOMWindowBase::commonVM()); 819 setCallingPlugin(true); 820 821 // FIXME: Passing zoomFactor to setwindow make windowed plugin scale incorrectly. 822 // Handling the zoom factor properly in the plugin side may be a better solution. 823 double oldZoomFactor = ((NPSetWindowCallbackStruct*)m_npWindow.ws_info)->zoomFactor; 824 ((NPSetWindowCallbackStruct*)m_npWindow.ws_info)->zoomFactor = 1.; 825 m_plugin->pluginFuncs()->setwindow(m_instance, &m_npWindow); 826 ((NPSetWindowCallbackStruct*)m_npWindow.ws_info)->zoomFactor = oldZoomFactor; 827 828 setCallingPlugin(false); 829 PluginView::setCurrentPluginView(0); 830} 831 832void PluginView::setParentVisible(bool visible) 833{ 834 if (isParentVisible() == visible) 835 return; 836 837 Widget::setParentVisible(visible); 838 839 // FIXME: We might want to tell the plugin to hide it's window here, but it doesn't matter 840 // since the window manager should take care of that for us. 841} 842 843NPError PluginView::handlePostReadFile(Vector<char>& buffer, uint32_t len, const char* buf) 844{ 845 String filename(buf, len); 846 847 if (filename.startsWith("file:///")) 848 filename = filename.substring(8); 849 850 long long size; 851 if (!getFileSize(filename, size)) 852 return NPERR_FILE_NOT_FOUND; 853 854 FILE* fileHandle = fopen(filename.utf8().data(), "r"); 855 if (!fileHandle) 856 return NPERR_FILE_NOT_FOUND; 857 858 buffer.resize(size); 859 int bytesRead = fread(buffer.data(), 1, size, fileHandle); 860 861 fclose(fileHandle); 862 863 if (bytesRead <= 0) 864 return NPERR_FILE_NOT_FOUND; 865 866 return NPERR_NO_ERROR; 867} 868 869bool PluginView::platformGetValueStatic(NPNVariable variable, void* value, NPError* result) 870{ 871 switch (variable) { 872 case NPNVToolkit: 873 *static_cast<uint32_t*>(value) = 0; 874 *result = NPERR_NO_ERROR; 875 return true; 876 877 case NPNVSupportsXEmbedBool: 878 *static_cast<NPBool*>(value) = true; 879 *result = NPERR_NO_ERROR; 880 return true; 881 882 case NPNVjavascriptEnabledBool: 883 *static_cast<NPBool*>(value) = true; 884 *result = NPERR_NO_ERROR; 885 return true; 886 887 case NPNVSupportsWindowless: 888 *static_cast<NPBool*>(value) = true; 889 *result = NPERR_NO_ERROR; 890 return true; 891 892 case NPNVNPCallbacksPtr: 893 *((void **) value) = (void*)&s_NpCallbacks; 894 *result = NPERR_NO_ERROR; 895 return true; 896 897 case NPNVxDisplay: 898 case NPNVxtAppContext: 899 case NPNVnetscapeWindow: 900 case NPNVasdEnabledBool: 901 case NPNVisOfflineBool: 902 case NPNVserviceManager: 903 case NPNVDOMElement: 904 case NPNVDOMWindow: 905 case NPNVWindowNPObject: 906 case NPNVPluginElementNPObject: 907 case NPNVprivateModeBool: 908 case NPNVZoomFactor: 909 case NPNVRootWindowGroup: 910 case NPNVBrowserWindowGroup: 911 case NPNVBrowserDisplayContext: 912 case NPNVPluginWindowPrefix: 913 return false; 914 915 default: 916 ASSERT_NOT_REACHED(); 917 return false; 918 } 919} 920 921bool PluginView::platformGetValue(NPNVariable variable, void* value, NPError* result) 922{ 923 switch (variable) { 924 case NPNVZoomFactor: 925 *(static_cast<void**>(value)) = static_cast<void*>(&((static_cast<NPSetWindowCallbackStruct*>(m_npWindow.ws_info)))->zoomFactor); 926 *result = NPERR_NO_ERROR; 927 return true; 928 929 case NPNVRootWindowGroup: { 930 FrameView* frameView = toFrameView(parent()); 931 if (frameView) { 932 BlackBerry::Platform::Graphics::Window *window = frameView->hostWindow()->platformPageClient()->platformWindow(); 933 if (window) { 934 void** tempValue = static_cast<void**>(value); 935 *tempValue = (void*)window->rootGroup(); 936 937 if (*tempValue) { 938 *result = NPERR_NO_ERROR; 939 return true; 940 } 941 } 942 } 943 *result = NPERR_GENERIC_ERROR; 944 return false; 945 } 946 947 case NPNVBrowserWindowGroup: { 948 FrameView* frameView = toFrameView(parent()); 949 if (frameView) { 950 BlackBerry::Platform::Graphics::Window* window = frameView->hostWindow()->platformPageClient()->platformWindow(); 951 if (window) { 952 void** tempValue = static_cast<void**>(value); 953 *tempValue = reinterpret_cast<void*>(const_cast<char*>(window->windowGroup())); 954 955 if (*tempValue) { 956 *result = NPERR_NO_ERROR; 957 return true; 958 } 959 } 960 } 961 *result = NPERR_GENERIC_ERROR; 962 return false; 963 } 964 965 case NPNVBrowserDisplayContext: { 966 FrameView* frameView = toFrameView(parent()); 967 if (frameView) { 968 BlackBerry::Platform::Graphics::PlatformDisplayContextHandle context = BlackBerry::Platform::Graphics::platformDisplayContext(); 969 if (context) { 970 void** tempValue = static_cast<void**>(value); 971 *tempValue = static_cast<void*>(context); 972 973 if (*tempValue) { 974 *result = NPERR_NO_ERROR; 975 return true; 976 } 977 } 978 } 979 *result = NPERR_GENERIC_ERROR; 980 return false; 981 } 982 983 case NPNVPluginWindowPrefix: { 984 void** tempValue = static_cast<void**>(value); 985 *tempValue = static_cast<void*>(const_cast<char*>(m_private->m_pluginUniquePrefix.c_str())); 986 987 if (*tempValue) { 988 *result = NPERR_NO_ERROR; 989 return true; 990 } 991 *result = NPERR_GENERIC_ERROR; 992 return false; 993 } 994 995 case NPNVxDisplay: 996 case NPNVxtAppContext: 997 case NPNVnetscapeWindow: 998 case NPNVjavascriptEnabledBool: 999 case NPNVasdEnabledBool: 1000 case NPNVisOfflineBool: 1001 case NPNVserviceManager: 1002 case NPNVDOMElement: 1003 case NPNVDOMWindow: 1004 case NPNVToolkit: 1005 case NPNVSupportsXEmbedBool: 1006 case NPNVWindowNPObject: 1007 case NPNVPluginElementNPObject: 1008 case NPNVSupportsWindowless: 1009 case NPNVprivateModeBool: 1010 case NPNVNPCallbacksPtr: 1011 return platformGetValueStatic(variable, value, result); 1012 1013 default: 1014 ASSERT_NOT_REACHED(); 1015 return false; 1016 } 1017} 1018 1019// This is a pure virtual inherited from Widget class and all invalidates 1020// are funneled through this method. We forward them on to either the 1021// compositing layer or the PluginView::invalidateWindowlessPluginRect method. 1022void PluginView::invalidateRect(const IntRect& rect) 1023{ 1024 if (!m_private) 1025 return; 1026 1027 // Record the region that we've been asked to invalidate 1028 m_private->m_invalidateRegion = BlackBerry::Platform::IntRectRegion::unionRegions(BlackBerry::Platform::IntRect(rect), m_private->m_invalidateRegion); 1029 1030#if USE(ACCELERATED_COMPOSITING) 1031 if (m_private->m_platformLayer) { 1032 m_private->m_platformLayer->setNeedsDisplay(); 1033 return; 1034 } 1035#endif 1036 1037 invalidateWindowlessPluginRect(rect); 1038} 1039 1040void PluginView::invalidateRect(NPRect* rect) 1041{ 1042 if (!rect) { 1043 invalidate(); 1044 return; 1045 } 1046 invalidateRect(IntRect(rect->left, rect->top, rect->right - rect->left, rect->bottom - rect->top)); 1047} 1048 1049void PluginView::invalidateRegion(NPRegion) 1050{ 1051 invalidate(); 1052} 1053 1054void PluginView::forceRedraw() 1055{ 1056 invalidate(); 1057} 1058 1059bool PluginView::platformStart() 1060{ 1061 ASSERT(m_isStarted); 1062 ASSERT(m_status == PluginStatusLoadedSuccessfully); 1063 1064 m_private = new PluginViewPrivate(this); 1065 1066 if (m_plugin->pluginFuncs()->getvalue) { 1067 PluginView::setCurrentPluginView(this); 1068 JSC::JSLock::DropAllLocks dropAllLocks(JSDOMWindowBase::commonVM()); 1069 setCallingPlugin(true); 1070 m_plugin->pluginFuncs()->getvalue(m_instance, NPPVpluginNeedsXEmbed, &m_needsXEmbed); 1071 setCallingPlugin(false); 1072 PluginView::setCurrentPluginView(0); 1073 } 1074 1075#if USE(ACCELERATED_COMPOSITING) 1076 if (m_parentFrame->page()->chrome().client()->allowsAcceleratedCompositing() 1077 && m_parentFrame->page()->settings() 1078 && m_parentFrame->page()->settings()->acceleratedCompositingEnabled()) { 1079 m_private->m_platformLayer = PluginLayerWebKitThread::create(this); 1080 // Trigger layer computation in RenderLayerCompositor 1081 m_element->setNeedsStyleRecalc(SyntheticStyleChange); 1082 } 1083#endif 1084 1085 m_npWindow.type = NPWindowTypeDrawable; 1086 m_npWindow.window = 0; // Not used? 1087 m_npWindow.x = 0; 1088 m_npWindow.y = 0; 1089 m_npWindow.width = UninitializedCoordinate; 1090 m_npWindow.height = UninitializedCoordinate; 1091 m_npWindow.ws_info = new NPSetWindowCallbackStruct; 1092 ((NPSetWindowCallbackStruct*)m_npWindow.ws_info)->zoomFactor = 1.; 1093 ((NPSetWindowCallbackStruct*)m_npWindow.ws_info)->windowGroup = 0; 1094 1095 show(); 1096 1097 if (FrameView* frameView = toFrameView(parent())) 1098 handleOrientationEvent(frameView->hostWindow()->platformPageClient()->orientation()); 1099 1100 if (!(m_plugin->quirks().contains(PluginQuirkDeferFirstSetWindowCall))) { 1101 updatePluginWidget(); 1102 setNPWindowIfNeeded(); 1103 } 1104 1105 return true; 1106} 1107 1108void PluginView::platformDestroy() 1109{ 1110 if (!m_private) 1111 return; 1112 1113 // This will unlock the idle (if we have locked it). 1114 m_private->preventIdle(false); 1115 1116 // This will release any keepVisibleRects if they were set. 1117 m_private->clearVisibleRects(); 1118 1119 // This will ensure that we unregistered the plugin. 1120 if (FrameView* frameView = toFrameView(parent())) { 1121 if (m_private->m_isBackgroundPlaying) 1122 frameView->hostWindow()->platformPageClient()->onPluginStopBackgroundPlay(this, m_private->m_pluginUniquePrefix.c_str()); 1123 1124 // If we were still fullscreen, ensure we notify everyone we're not. 1125 if (m_private->m_isFullScreen) 1126 frameView->hostWindow()->platformPageClient()->didPluginExitFullScreen(this, m_private->m_pluginUniquePrefix.c_str()); 1127 1128 if (m_private->m_orientationLocked) 1129 frameView->hostWindow()->platformPageClient()->unlockOrientation(); 1130 1131 frameView->hostWindow()->platformPageClient()->registerPlugin(this, false /*shouldRegister*/); 1132 } 1133 1134 m_private->m_isBackgroundPlaying = false; 1135 m_private->m_isFullScreen = false; 1136 1137 delete m_private; 1138 m_private = 0; 1139} 1140 1141void PluginView::getWindowInfo(Vector<PluginWindowInfo>& windowList) 1142{ 1143 if (!m_plugin->pluginFuncs()->getvalue) 1144 return; 1145 1146 void* valPtr = 0; 1147 1148 PluginView::setCurrentPluginView(this); 1149 JSC::JSLock::DropAllLocks dropAllLocks(JSDOMWindowBase::commonVM()); 1150 setCallingPlugin(true); 1151 m_plugin->pluginFuncs()->getvalue(m_instance, NPPVpluginScreenWindow, &valPtr); 1152 setCallingPlugin(false); 1153 PluginView::setCurrentPluginView(0); 1154 1155 if (!valPtr) 1156 return; 1157 1158 NPScreenWindowHandles* screenWinHandles = static_cast<NPScreenWindowHandles*>(valPtr); 1159 1160 for (int i = 0; i < screenWinHandles->numOfWindows; i++) { 1161 PluginWindowInfo info; 1162 info.windowPtr = screenWinHandles->windowHandles[i]; 1163 1164 NPRect* rc = screenWinHandles->windowRects[i]; 1165 info.windowRect = IntRect(rc->left, rc->top, rc->right - rc->left, rc->bottom - rc->top); 1166 1167 windowList.append(info); 1168 } 1169} 1170 1171BlackBerry::Platform::Graphics::Buffer* PluginView::lockFrontBufferForRead() const 1172{ 1173 if (!m_private) 1174 return 0; 1175 1176 BlackBerry::Platform::Graphics::Buffer* buffer = m_private->lockReadFrontBufferInternal(); 1177 1178 if (!buffer) 1179 m_private->unlockReadFrontBuffer(); 1180 1181 return buffer; 1182} 1183 1184void PluginView::unlockFrontBuffer() const 1185{ 1186 if (!m_private) 1187 return; 1188 m_private->unlockReadFrontBuffer(); 1189} 1190 1191#if USE(ACCELERATED_COMPOSITING) 1192PlatformLayer* PluginView::platformLayer() const 1193{ 1194 if (!m_private) 1195 return 0; 1196 return m_private->m_platformLayer.get(); 1197} 1198#endif 1199 1200IntRect PluginView::ensureVisibleRect() 1201{ 1202 if (!m_private) 1203 return IntRect(); 1204 return m_private->m_keepVisibleRect; 1205} 1206 1207void PluginView::setBackgroundPlay(bool value) 1208{ 1209 if (!m_private || m_private->m_isBackgroundPlaying == value) 1210 return; 1211 1212 FrameView* frameView = toFrameView(m_private->m_view->parent()); 1213 m_private->m_isBackgroundPlaying = value; 1214 if (m_private->m_isBackgroundPlaying) 1215 frameView->hostWindow()->platformPageClient()->onPluginStartBackgroundPlay(this, m_private->m_pluginUniquePrefix.c_str()); 1216 else 1217 frameView->hostWindow()->platformPageClient()->onPluginStopBackgroundPlay(this, m_private->m_pluginUniquePrefix.c_str()); 1218} 1219 1220} // namespace WebCore 1221 1222 1223