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 (at) forwardbias.in> 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 16 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 19 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 22 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 23 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include "config.h" 29 #include "PluginView.h" 30 31 #if USE(JSC) 32 #include "BridgeJSC.h" 33 #endif 34 #include "Chrome.h" 35 #include "ChromeClient.h" 36 #include "Document.h" 37 #include "DocumentLoader.h" 38 #include "Element.h" 39 #include "FloatPoint.h" 40 #include "FocusController.h" 41 #include "Frame.h" 42 #include "FrameLoadRequest.h" 43 #include "FrameLoader.h" 44 #include "FrameTree.h" 45 #include "FrameView.h" 46 #include "GraphicsContext.h" 47 #include "HTMLNames.h" 48 #include "HTMLPlugInElement.h" 49 #include "HostWindow.h" 50 #include "IFrameShimSupport.h" 51 #include "Image.h" 52 #if USE(JSC) 53 #include "JSDOMBinding.h" 54 #endif 55 #include "KeyboardEvent.h" 56 #include "MouseEvent.h" 57 #include "NotImplemented.h" 58 #include "Page.h" 59 #include "PlatformMouseEvent.h" 60 #include "PlatformKeyboardEvent.h" 61 #include "PluginContainerQt.h" 62 #include "PluginDebug.h" 63 #include "PluginPackage.h" 64 #include "PluginMainThreadScheduler.h" 65 #include "QWebPageClient.h" 66 #include "RenderLayer.h" 67 #include "ScriptController.h" 68 #include "Settings.h" 69 #include "npruntime_impl.h" 70 #include "qwebpage_p.h" 71 #if USE(JSC) 72 #include "runtime_root.h" 73 #endif 74 75 #include <QApplication> 76 #include <QDesktopWidget> 77 #include <QGraphicsWidget> 78 #include <QKeyEvent> 79 #include <QPainter> 80 #include <QStyleOptionGraphicsItem> 81 #include <QWidget> 82 #include <QX11Info> 83 #include <X11/X.h> 84 #ifndef QT_NO_XRENDER 85 #define Bool int 86 #define Status int 87 #include <X11/extensions/Xrender.h> 88 #endif 89 #include <runtime/JSLock.h> 90 #include <runtime/JSValue.h> 91 92 using JSC::ExecState; 93 #if USE(JSC) 94 using JSC::Interpreter; 95 #endif 96 using JSC::JSLock; 97 using JSC::JSObject; 98 using JSC::UString; 99 100 using std::min; 101 102 using namespace WTF; 103 104 namespace WebCore { 105 106 using namespace HTMLNames; 107 108 #if USE(ACCELERATED_COMPOSITING) 109 // Qt's GraphicsLayer (GraphicsLayerQt) requires layers to be QGraphicsWidgets 110 class PluginGraphicsLayerQt : public QGraphicsWidget { 111 public: 112 PluginGraphicsLayerQt(PluginView* view) : m_view(view) { } 113 ~PluginGraphicsLayerQt() { } 114 115 void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget = 0) 116 { 117 Q_UNUSED(widget); 118 m_view->paintUsingXPixmap(painter, option->exposedRect.toRect()); 119 } 120 121 private: 122 PluginView* m_view; 123 }; 124 #endif 125 126 void PluginView::updatePluginWidget() 127 { 128 if (!parent()) 129 return; 130 131 ASSERT(parent()->isFrameView()); 132 FrameView* frameView = static_cast<FrameView*>(parent()); 133 134 IntRect oldWindowRect = m_windowRect; 135 IntRect oldClipRect = m_clipRect; 136 137 m_windowRect = IntRect(frameView->contentsToWindow(frameRect().location()), frameRect().size()); 138 m_clipRect = windowClipRect(); 139 m_clipRect.move(-m_windowRect.x(), -m_windowRect.y()); 140 141 if (m_windowRect == oldWindowRect && m_clipRect == oldClipRect) 142 return; 143 144 // The plugin had a zero width or height before but was resized, we need to show it again. 145 if (oldWindowRect.isEmpty()) 146 show(); 147 148 if (!m_isWindowed && m_windowRect.size() != oldWindowRect.size()) { 149 #if defined(MOZ_PLATFORM_MAEMO) && (MOZ_PLATFORM_MAEMO >= 5) 150 // On Maemo5, Flash always renders to 16-bit buffer 151 if (m_renderToImage) 152 m_image = QImage(m_windowRect.width(), m_windowRect.height(), QImage::Format_RGB16); 153 else 154 #endif 155 { 156 if (m_drawable) 157 XFreePixmap(QX11Info::display(), m_drawable); 158 159 m_drawable = XCreatePixmap(QX11Info::display(), QX11Info::appRootWindow(), m_windowRect.width(), m_windowRect.height(), 160 ((NPSetWindowCallbackStruct*)m_npWindow.ws_info)->depth); 161 QApplication::syncX(); // make sure that the server knows about the Drawable 162 } 163 } 164 165 // do not call setNPWindowIfNeeded immediately, will be called on paint() 166 m_hasPendingGeometryChange = true; 167 168 // (i) in order to move/resize the plugin window at the same time as the 169 // rest of frame during e.g. scrolling, we set the window geometry 170 // in the paint() function, but as paint() isn't called when the 171 // plugin window is outside the frame which can be caused by a 172 // scroll, we need to move/resize immediately. 173 // (ii) if we are running layout tests from DRT, paint() won't ever get called 174 // so we need to call setNPWindowIfNeeded() if window geometry has changed 175 if (!m_windowRect.intersects(frameView->frameRect()) 176 || (QWebPagePrivate::drtRun && platformPluginWidget() && (m_windowRect != oldWindowRect || m_clipRect != oldClipRect))) 177 setNPWindowIfNeeded(); 178 179 if (!m_platformLayer) { 180 // Make sure we get repainted afterwards. This is necessary for downward 181 // scrolling to move the plugin widget properly. 182 // Note that we don't invalidate the frameRect() here. This is because QWebFrame::renderRelativeCoords() 183 // imitates ScrollView and adds the scroll offset back on to the rect we damage here (making the co-ordinates absolute 184 // to the frame again) before passing it to FrameView. 185 invalidate(); 186 } 187 } 188 189 void PluginView::setFocus(bool focused) 190 { 191 if (platformPluginWidget()) { 192 if (focused) 193 platformPluginWidget()->setFocus(Qt::OtherFocusReason); 194 } else { 195 Widget::setFocus(focused); 196 } 197 } 198 199 void PluginView::show() 200 { 201 Q_ASSERT(platformPluginWidget() == platformWidget()); 202 Widget::show(); 203 } 204 205 void PluginView::hide() 206 { 207 Q_ASSERT(platformPluginWidget() == platformWidget()); 208 Widget::hide(); 209 } 210 211 #if defined(MOZ_PLATFORM_MAEMO) && (MOZ_PLATFORM_MAEMO >= 5) 212 void PluginView::paintUsingImageSurfaceExtension(QPainter* painter, const IntRect& exposedRect) 213 { 214 NPImageExpose imageExpose; 215 QPoint offset; 216 QWebPageClient* client = m_parentFrame->view()->hostWindow()->platformPageClient(); 217 const bool surfaceHasUntransformedContents = client && qobject_cast<QWidget*>(client->pluginParent()); 218 219 QPaintDevice* surface = QPainter::redirected(painter->device(), &offset); 220 221 // If the surface is a QImage, we can render directly into it 222 if (surfaceHasUntransformedContents && surface && surface->devType() == QInternal::Image) { 223 QImage* image = static_cast<QImage*>(surface); 224 offset = -offset; // negating the offset gives us the offset of the view within the surface 225 imageExpose.data = reinterpret_cast<char*>(image->bits()); 226 imageExpose.dataSize.width = image->width(); 227 imageExpose.dataSize.height = image->height(); 228 imageExpose.stride = image->bytesPerLine(); 229 imageExpose.depth = image->depth(); // this is guaranteed to be 16 on Maemo5 230 imageExpose.translateX = offset.x() + m_windowRect.x(); 231 imageExpose.translateY = offset.y() + m_windowRect.y(); 232 imageExpose.scaleX = 1; 233 imageExpose.scaleY = 1; 234 } else { 235 if (m_isTransparent) { 236 // On Maemo5, Flash expects the buffer to contain the contents that are below it. 237 // We don't support transparency for non-raster graphicssystem, so clean the image 238 // before giving to Flash. 239 QPainter imagePainter(&m_image); 240 imagePainter.fillRect(exposedRect, Qt::white); 241 } 242 243 imageExpose.data = reinterpret_cast<char*>(m_image.bits()); 244 imageExpose.dataSize.width = m_image.width(); 245 imageExpose.dataSize.height = m_image.height(); 246 imageExpose.stride = m_image.bytesPerLine(); 247 imageExpose.depth = m_image.depth(); 248 imageExpose.translateX = 0; 249 imageExpose.translateY = 0; 250 imageExpose.scaleX = 1; 251 imageExpose.scaleY = 1; 252 } 253 imageExpose.x = exposedRect.x(); 254 imageExpose.y = exposedRect.y(); 255 imageExpose.width = exposedRect.width(); 256 imageExpose.height = exposedRect.height(); 257 258 XEvent xevent; 259 memset(&xevent, 0, sizeof(XEvent)); 260 XGraphicsExposeEvent& exposeEvent = xevent.xgraphicsexpose; 261 exposeEvent.type = GraphicsExpose; 262 exposeEvent.display = 0; 263 exposeEvent.drawable = reinterpret_cast<XID>(&imageExpose); 264 exposeEvent.x = exposedRect.x(); 265 exposeEvent.y = exposedRect.y(); 266 exposeEvent.width = exposedRect.width(); 267 exposeEvent.height = exposedRect.height(); 268 269 dispatchNPEvent(xevent); 270 271 if (!surfaceHasUntransformedContents || !surface || surface->devType() != QInternal::Image) 272 painter->drawImage(QPoint(frameRect().x() + exposedRect.x(), frameRect().y() + exposedRect.y()), m_image, exposedRect); 273 } 274 #endif 275 276 void PluginView::paintUsingXPixmap(QPainter* painter, const QRect &exposedRect) 277 { 278 QPixmap qtDrawable = QPixmap::fromX11Pixmap(m_drawable, QPixmap::ExplicitlyShared); 279 const int drawableDepth = ((NPSetWindowCallbackStruct*)m_npWindow.ws_info)->depth; 280 ASSERT(drawableDepth == qtDrawable.depth()); 281 const bool syncX = m_pluginDisplay && m_pluginDisplay != QX11Info::display(); 282 283 // When printing, Qt uses a QPicture to capture the output in preview mode. The 284 // QPicture holds a reference to the X Pixmap. As a result, the print preview would 285 // update itself when the X Pixmap changes. To prevent this, we create a copy. 286 if (m_element->document()->printing()) 287 qtDrawable = qtDrawable.copy(); 288 289 if (m_isTransparent && drawableDepth != 32) { 290 // Attempt content propagation for drawable with no alpha by copying over from the backing store 291 QPoint offset; 292 QPaintDevice* backingStoreDevice = QPainter::redirected(painter->device(), &offset); 293 offset = -offset; // negating the offset gives us the offset of the view within the backing store pixmap 294 295 const bool hasValidBackingStore = backingStoreDevice && backingStoreDevice->devType() == QInternal::Pixmap; 296 QPixmap* backingStorePixmap = static_cast<QPixmap*>(backingStoreDevice); 297 298 // We cannot grab contents from the backing store when painting on QGraphicsView items 299 // (because backing store contents are already transformed). What we really mean to do 300 // here is to check if we are painting on QWebView, but let's be a little permissive :) 301 QWebPageClient* client = m_parentFrame->view()->hostWindow()->platformPageClient(); 302 const bool backingStoreHasUntransformedContents = client && qobject_cast<QWidget*>(client->pluginParent()); 303 304 if (hasValidBackingStore && backingStorePixmap->depth() == drawableDepth 305 && backingStoreHasUntransformedContents) { 306 GC gc = XDefaultGC(QX11Info::display(), QX11Info::appScreen()); 307 XCopyArea(QX11Info::display(), backingStorePixmap->handle(), m_drawable, gc, 308 offset.x() + m_windowRect.x() + exposedRect.x(), offset.y() + m_windowRect.y() + exposedRect.y(), 309 exposedRect.width(), exposedRect.height(), exposedRect.x(), exposedRect.y()); 310 } else { // no backing store, clean the pixmap because the plugin thinks its transparent 311 QPainter painter(&qtDrawable); 312 painter.fillRect(exposedRect, Qt::white); 313 } 314 315 if (syncX) 316 QApplication::syncX(); 317 } 318 319 XEvent xevent; 320 memset(&xevent, 0, sizeof(XEvent)); 321 XGraphicsExposeEvent& exposeEvent = xevent.xgraphicsexpose; 322 exposeEvent.type = GraphicsExpose; 323 exposeEvent.display = QX11Info::display(); 324 exposeEvent.drawable = qtDrawable.handle(); 325 exposeEvent.x = exposedRect.x(); 326 exposeEvent.y = exposedRect.y(); 327 exposeEvent.width = exposedRect.x() + exposedRect.width(); // flash bug? it thinks width is the right in transparent mode 328 exposeEvent.height = exposedRect.y() + exposedRect.height(); // flash bug? it thinks height is the bottom in transparent mode 329 330 dispatchNPEvent(xevent); 331 332 if (syncX) 333 XSync(m_pluginDisplay, false); // sync changes by plugin 334 335 painter->drawPixmap(QPoint(exposedRect.x(), exposedRect.y()), qtDrawable, exposedRect); 336 } 337 338 void PluginView::paint(GraphicsContext* context, const IntRect& rect) 339 { 340 if (!m_isStarted) { 341 paintMissingPluginIcon(context, rect); 342 return; 343 } 344 345 if (context->paintingDisabled()) 346 return; 347 348 setNPWindowIfNeeded(); 349 350 if (m_isWindowed) 351 return; 352 353 #if USE(ACCELERATED_COMPOSITING) 354 if (m_platformLayer) 355 return; 356 #endif 357 358 if (!m_drawable 359 #if defined(MOZ_PLATFORM_MAEMO) && (MOZ_PLATFORM_MAEMO >= 5) 360 && m_image.isNull() 361 #endif 362 ) 363 return; 364 365 QPainter* painter = context->platformContext(); 366 IntRect exposedRect(rect); 367 exposedRect.intersect(frameRect()); 368 exposedRect.move(-frameRect().x(), -frameRect().y()); 369 370 #if defined(MOZ_PLATFORM_MAEMO) && (MOZ_PLATFORM_MAEMO >= 5) 371 if (!m_image.isNull()) { 372 paintUsingImageSurfaceExtension(painter, exposedRect); 373 return; 374 } 375 #endif 376 377 painter->translate(frameRect().x(), frameRect().y()); 378 paintUsingXPixmap(painter, exposedRect); 379 painter->translate(-frameRect().x(), -frameRect().y()); 380 } 381 382 // TODO: Unify across ports. 383 bool PluginView::dispatchNPEvent(NPEvent& event) 384 { 385 if (!m_plugin->pluginFuncs()->event) 386 return false; 387 388 PluginView::setCurrentPluginView(this); 389 #if USE(JSC) 390 JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly); 391 #endif 392 setCallingPlugin(true); 393 bool accepted = m_plugin->pluginFuncs()->event(m_instance, &event); 394 setCallingPlugin(false); 395 PluginView::setCurrentPluginView(0); 396 397 return accepted; 398 } 399 400 void setSharedXEventFields(XEvent* xEvent, QWidget* ownerWidget) 401 { 402 xEvent->xany.serial = 0; // we are unaware of the last request processed by X Server 403 xEvent->xany.send_event = false; 404 xEvent->xany.display = QX11Info::display(); 405 // NOTE: event->xany.window doesn't always respond to the .window property of other XEvent's 406 // but does in the case of KeyPress, KeyRelease, ButtonPress, ButtonRelease, and MotionNotify 407 // events; thus, this is right: 408 xEvent->xany.window = ownerWidget ? ownerWidget->window()->handle() : 0; 409 } 410 411 void PluginView::initXEvent(XEvent* xEvent) 412 { 413 memset(xEvent, 0, sizeof(XEvent)); 414 415 QWebPageClient* client = m_parentFrame->view()->hostWindow()->platformPageClient(); 416 QWidget* ownerWidget = client ? client->ownerWidget() : 0; 417 setSharedXEventFields(xEvent, ownerWidget); 418 } 419 420 void setXKeyEventSpecificFields(XEvent* xEvent, KeyboardEvent* event) 421 { 422 const PlatformKeyboardEvent* keyEvent = event->keyEvent(); 423 424 xEvent->type = (event->type() == eventNames().keydownEvent) ? 2 : 3; // ints as Qt unsets KeyPress and KeyRelease 425 xEvent->xkey.root = QX11Info::appRootWindow(); 426 xEvent->xkey.subwindow = 0; // we have no child window 427 xEvent->xkey.time = event->timeStamp(); 428 xEvent->xkey.state = keyEvent->nativeModifiers(); 429 xEvent->xkey.keycode = keyEvent->nativeScanCode(); 430 431 // We may not have a nativeScanCode() if the key event is from DRT's eventsender. In that 432 // case fetch the XEvent's keycode from the event's text. The only 433 // place this keycode will be used is in webkit_test_plugin_handle_event(). 434 // FIXME: Create Qt API so that we can set the appropriate keycode in DRT EventSender instead. 435 if (QWebPagePrivate::drtRun && !xEvent->xkey.keycode) { 436 QKeyEvent* qKeyEvent = keyEvent->qtEvent(); 437 ASSERT(qKeyEvent); 438 QString keyText = qKeyEvent->text().left(1); 439 xEvent->xkey.keycode = XKeysymToKeycode(QX11Info::display(), XStringToKeysym(keyText.toUtf8().constData())); 440 } 441 442 xEvent->xkey.same_screen = true; 443 444 // NOTE: As the XEvents sent to the plug-in are synthesized and there is not a native window 445 // corresponding to the plug-in rectangle, some of the members of the XEvent structures are not 446 // set to their normal Xserver values. e.g. Key events don't have a position. 447 // source: https://developer.mozilla.org/en/NPEvent 448 xEvent->xkey.x = 0; 449 xEvent->xkey.y = 0; 450 xEvent->xkey.x_root = 0; 451 xEvent->xkey.y_root = 0; 452 } 453 454 void PluginView::handleKeyboardEvent(KeyboardEvent* event) 455 { 456 if (m_isWindowed) 457 return; 458 459 if (event->type() != eventNames().keydownEvent && event->type() != eventNames().keyupEvent) 460 return; 461 462 XEvent npEvent; 463 initXEvent(&npEvent); 464 setXKeyEventSpecificFields(&npEvent, event); 465 466 if (!dispatchNPEvent(npEvent)) 467 event->setDefaultHandled(); 468 } 469 470 static unsigned int inputEventState(MouseEvent* event) 471 { 472 unsigned int state = 0; 473 if (event->ctrlKey()) 474 state |= ControlMask; 475 if (event->shiftKey()) 476 state |= ShiftMask; 477 if (event->altKey()) 478 state |= Mod1Mask; 479 if (event->metaKey()) 480 state |= Mod4Mask; 481 return state; 482 } 483 484 static void setXButtonEventSpecificFields(XEvent* xEvent, MouseEvent* event, const IntPoint& postZoomPos) 485 { 486 XButtonEvent& xbutton = xEvent->xbutton; 487 xbutton.type = event->type() == eventNames().mousedownEvent ? ButtonPress : ButtonRelease; 488 xbutton.root = QX11Info::appRootWindow(); 489 xbutton.subwindow = 0; 490 xbutton.time = event->timeStamp(); 491 xbutton.x = postZoomPos.x(); 492 xbutton.y = postZoomPos.y(); 493 xbutton.x_root = event->screenX(); 494 xbutton.y_root = event->screenY(); 495 xbutton.state = inputEventState(event); 496 switch (event->button()) { 497 case MiddleButton: 498 xbutton.button = Button2; 499 break; 500 case RightButton: 501 xbutton.button = Button3; 502 break; 503 case LeftButton: 504 default: 505 xbutton.button = Button1; 506 break; 507 } 508 xbutton.same_screen = true; 509 } 510 511 static void setXMotionEventSpecificFields(XEvent* xEvent, MouseEvent* event, const IntPoint& postZoomPos) 512 { 513 XMotionEvent& xmotion = xEvent->xmotion; 514 xmotion.type = MotionNotify; 515 xmotion.root = QX11Info::appRootWindow(); 516 xmotion.subwindow = 0; 517 xmotion.time = event->timeStamp(); 518 xmotion.x = postZoomPos.x(); 519 xmotion.y = postZoomPos.y(); 520 xmotion.x_root = event->screenX(); 521 xmotion.y_root = event->screenY(); 522 xmotion.state = inputEventState(event); 523 xmotion.is_hint = NotifyNormal; 524 xmotion.same_screen = true; 525 } 526 527 static void setXCrossingEventSpecificFields(XEvent* xEvent, MouseEvent* event, const IntPoint& postZoomPos) 528 { 529 XCrossingEvent& xcrossing = xEvent->xcrossing; 530 xcrossing.type = event->type() == eventNames().mouseoverEvent ? EnterNotify : LeaveNotify; 531 xcrossing.root = QX11Info::appRootWindow(); 532 xcrossing.subwindow = 0; 533 xcrossing.time = event->timeStamp(); 534 xcrossing.x = postZoomPos.y(); 535 xcrossing.y = postZoomPos.x(); 536 xcrossing.x_root = event->screenX(); 537 xcrossing.y_root = event->screenY(); 538 xcrossing.state = inputEventState(event); 539 xcrossing.mode = NotifyNormal; 540 xcrossing.detail = NotifyDetailNone; 541 xcrossing.same_screen = true; 542 xcrossing.focus = false; 543 } 544 545 void PluginView::handleMouseEvent(MouseEvent* event) 546 { 547 if (m_isWindowed) 548 return; 549 550 if (event->button() == RightButton && m_plugin->quirks().contains(PluginQuirkIgnoreRightClickInWindowlessMode)) 551 return; 552 553 if (event->type() == eventNames().mousedownEvent) { 554 // Give focus to the plugin on click 555 if (Page* page = m_parentFrame->page()) 556 page->focusController()->setActive(true); 557 558 focusPluginElement(); 559 } 560 561 XEvent npEvent; 562 initXEvent(&npEvent); 563 564 IntPoint postZoomPos = roundedIntPoint(m_element->renderer()->absoluteToLocal(event->absoluteLocation())); 565 566 if (event->type() == eventNames().mousedownEvent || event->type() == eventNames().mouseupEvent) 567 setXButtonEventSpecificFields(&npEvent, event, postZoomPos); 568 else if (event->type() == eventNames().mousemoveEvent) 569 setXMotionEventSpecificFields(&npEvent, event, postZoomPos); 570 else if (event->type() == eventNames().mouseoutEvent || event->type() == eventNames().mouseoverEvent) 571 setXCrossingEventSpecificFields(&npEvent, event, postZoomPos); 572 else 573 return; 574 575 if (!dispatchNPEvent(npEvent)) 576 event->setDefaultHandled(); 577 } 578 579 void PluginView::handleFocusInEvent() 580 { 581 XEvent npEvent; 582 initXEvent(&npEvent); 583 584 XFocusChangeEvent& event = npEvent.xfocus; 585 event.type = 9; /* int as Qt unsets FocusIn */ 586 event.mode = NotifyNormal; 587 event.detail = NotifyDetailNone; 588 589 dispatchNPEvent(npEvent); 590 } 591 592 void PluginView::handleFocusOutEvent() 593 { 594 XEvent npEvent; 595 initXEvent(&npEvent); 596 597 XFocusChangeEvent& event = npEvent.xfocus; 598 event.type = 10; /* int as Qt unsets FocusOut */ 599 event.mode = NotifyNormal; 600 event.detail = NotifyDetailNone; 601 602 dispatchNPEvent(npEvent); 603 } 604 605 void PluginView::setParent(ScrollView* parent) 606 { 607 Widget::setParent(parent); 608 609 if (parent) 610 init(); 611 } 612 613 void PluginView::setNPWindowRect(const IntRect&) 614 { 615 if (!m_isWindowed) 616 setNPWindowIfNeeded(); 617 } 618 619 void PluginView::setNPWindowIfNeeded() 620 { 621 if (!m_isStarted || !parent() || !m_plugin->pluginFuncs()->setwindow) 622 return; 623 624 // If the plugin didn't load sucessfully, no point in calling setwindow 625 if (m_status != PluginStatusLoadedSuccessfully) 626 return; 627 628 // On Unix, only call plugin if it's full-page or windowed 629 if (m_mode != NP_FULL && m_mode != NP_EMBED) 630 return; 631 632 // Check if the platformPluginWidget still exists 633 if (m_isWindowed && !platformPluginWidget()) 634 return; 635 636 if (!m_hasPendingGeometryChange) 637 return; 638 m_hasPendingGeometryChange = false; 639 640 if (m_isWindowed) { 641 platformPluginWidget()->setGeometry(m_windowRect); 642 643 // Cut out areas of the plugin occluded by iframe shims 644 Vector<IntRect> cutOutRects; 645 QRegion clipRegion = QRegion(m_clipRect); 646 getPluginOcclusions(m_element, this->parent(), frameRect(), cutOutRects); 647 for (size_t i = 0; i < cutOutRects.size(); i++) { 648 cutOutRects[i].move(-frameRect().x(), -frameRect().y()); 649 clipRegion = clipRegion.subtracted(QRegion(cutOutRects[i])); 650 } 651 // if setMask is set with an empty QRegion, no clipping will 652 // be performed, so in that case we hide the plugin view 653 platformPluginWidget()->setVisible(!clipRegion.isEmpty()); 654 platformPluginWidget()->setMask(clipRegion); 655 656 m_npWindow.x = m_windowRect.x(); 657 m_npWindow.y = m_windowRect.y(); 658 } else { 659 m_npWindow.x = 0; 660 m_npWindow.y = 0; 661 } 662 663 // If the width or height are null, set the clipRect to null, indicating that 664 // the plugin is not visible/scrolled out. 665 if (!m_clipRect.width() || !m_clipRect.height()) { 666 m_npWindow.clipRect.left = 0; 667 m_npWindow.clipRect.right = 0; 668 m_npWindow.clipRect.top = 0; 669 m_npWindow.clipRect.bottom = 0; 670 } else { 671 // Clipping rectangle of the plug-in; the origin is the top left corner of the drawable or window. 672 m_npWindow.clipRect.left = m_npWindow.x + m_clipRect.x(); 673 m_npWindow.clipRect.top = m_npWindow.y + m_clipRect.y(); 674 m_npWindow.clipRect.right = m_npWindow.x + m_clipRect.x() + m_clipRect.width(); 675 m_npWindow.clipRect.bottom = m_npWindow.y + m_clipRect.y() + m_clipRect.height(); 676 } 677 678 if (m_plugin->quirks().contains(PluginQuirkDontCallSetWindowMoreThanOnce)) { 679 // FLASH WORKAROUND: Only set initially. Multiple calls to 680 // setNPWindow() cause the plugin to crash in windowed mode. 681 if (!m_isWindowed || m_npWindow.width == -1 || m_npWindow.height == -1) { 682 m_npWindow.width = m_windowRect.width(); 683 m_npWindow.height = m_windowRect.height(); 684 } 685 } else { 686 m_npWindow.width = m_windowRect.width(); 687 m_npWindow.height = m_windowRect.height(); 688 } 689 690 PluginView::setCurrentPluginView(this); 691 #if USE(JSC) 692 JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly); 693 #endif 694 setCallingPlugin(true); 695 m_plugin->pluginFuncs()->setwindow(m_instance, &m_npWindow); 696 setCallingPlugin(false); 697 PluginView::setCurrentPluginView(0); 698 } 699 700 void PluginView::setParentVisible(bool visible) 701 { 702 if (isParentVisible() == visible) 703 return; 704 705 Widget::setParentVisible(visible); 706 707 if (isSelfVisible() && platformPluginWidget()) 708 platformPluginWidget()->setVisible(visible); 709 } 710 711 NPError PluginView::handlePostReadFile(Vector<char>& buffer, uint32_t len, const char* buf) 712 { 713 String filename(buf, len); 714 715 if (filename.startsWith("file:///")) 716 filename = filename.substring(8); 717 718 long long size; 719 if (!getFileSize(filename, size)) 720 return NPERR_FILE_NOT_FOUND; 721 722 FILE* fileHandle = fopen((filename.utf8()).data(), "r"); 723 if (!fileHandle) 724 return NPERR_FILE_NOT_FOUND; 725 726 buffer.resize(size); 727 int bytesRead = fread(buffer.data(), 1, size, fileHandle); 728 729 fclose(fileHandle); 730 731 if (bytesRead <= 0) 732 return NPERR_FILE_NOT_FOUND; 733 734 return NPERR_NO_ERROR; 735 } 736 737 bool PluginView::platformGetValueStatic(NPNVariable variable, void* value, NPError* result) 738 { 739 switch (variable) { 740 case NPNVToolkit: 741 *static_cast<uint32_t*>(value) = 0; 742 *result = NPERR_NO_ERROR; 743 return true; 744 745 case NPNVSupportsXEmbedBool: 746 *static_cast<NPBool*>(value) = true; 747 *result = NPERR_NO_ERROR; 748 return true; 749 750 case NPNVjavascriptEnabledBool: 751 *static_cast<NPBool*>(value) = true; 752 *result = NPERR_NO_ERROR; 753 return true; 754 755 case NPNVSupportsWindowless: 756 *static_cast<NPBool*>(value) = true; 757 *result = NPERR_NO_ERROR; 758 return true; 759 760 #if defined(MOZ_PLATFORM_MAEMO) && (MOZ_PLATFORM_MAEMO >= 5) 761 case NPNVSupportsWindowlessLocal: 762 *static_cast<NPBool*>(value) = true; 763 *result = NPERR_NO_ERROR; 764 return true; 765 #endif 766 767 default: 768 return false; 769 } 770 } 771 772 bool PluginView::platformGetValue(NPNVariable variable, void* value, NPError* result) 773 { 774 switch (variable) { 775 case NPNVxDisplay: 776 *(void **)value = QX11Info::display(); 777 *result = NPERR_NO_ERROR; 778 return true; 779 780 case NPNVxtAppContext: 781 *result = NPERR_GENERIC_ERROR; 782 return true; 783 784 case NPNVnetscapeWindow: { 785 void* w = reinterpret_cast<void*>(value); 786 QWebPageClient* client = m_parentFrame->view()->hostWindow()->platformPageClient(); 787 *((XID *)w) = client ? client->ownerWidget()->window()->winId() : 0; 788 *result = NPERR_NO_ERROR; 789 return true; 790 } 791 792 case NPNVToolkit: 793 if (m_plugin->quirks().contains(PluginQuirkRequiresGtkToolKit)) { 794 *((uint32_t *)value) = 2; 795 *result = NPERR_NO_ERROR; 796 return true; 797 } 798 return false; 799 800 default: 801 return false; 802 } 803 } 804 805 void PluginView::invalidateRect(const IntRect& rect) 806 { 807 #if USE(ACCELERATED_COMPOSITING) && !USE(TEXTURE_MAPPER) 808 if (m_platformLayer) { 809 m_platformLayer->update(QRectF(rect)); 810 return; 811 } 812 #endif 813 814 if (m_isWindowed) { 815 if (platformWidget()) { 816 // update() will schedule a repaint of the widget so ensure 817 // its knowledge of its position on the page is up to date. 818 platformWidget()->setGeometry(m_windowRect); 819 platformWidget()->update(rect); 820 } 821 return; 822 } 823 824 invalidateWindowlessPluginRect(rect); 825 } 826 827 void PluginView::invalidateRect(NPRect* rect) 828 { 829 if (!rect) { 830 invalidate(); 831 return; 832 } 833 IntRect r(rect->left, rect->top, rect->right - rect->left, rect->bottom - rect->top); 834 invalidateRect(r); 835 } 836 837 void PluginView::invalidateRegion(NPRegion region) 838 { 839 Q_UNUSED(region); 840 invalidate(); 841 } 842 843 void PluginView::forceRedraw() 844 { 845 invalidate(); 846 } 847 848 static Display *getPluginDisplay() 849 { 850 // The plugin toolkit might run using a different X connection. At the moment, we only 851 // support gdk based plugins (like flash) that use a different X connection. 852 // The code below has the same effect as this one: 853 // Display *gdkDisplay = gdk_x11_display_get_xdisplay(gdk_display_get_default()); 854 QLibrary library(QLatin1String("libgdk-x11-2.0"), 0); 855 if (!library.load()) 856 return 0; 857 858 typedef void *(*gdk_display_get_default_ptr)(); 859 gdk_display_get_default_ptr gdk_display_get_default = (gdk_display_get_default_ptr)library.resolve("gdk_display_get_default"); 860 if (!gdk_display_get_default) 861 return 0; 862 863 typedef void *(*gdk_x11_display_get_xdisplay_ptr)(void *); 864 gdk_x11_display_get_xdisplay_ptr gdk_x11_display_get_xdisplay = (gdk_x11_display_get_xdisplay_ptr)library.resolve("gdk_x11_display_get_xdisplay"); 865 if (!gdk_x11_display_get_xdisplay) 866 return 0; 867 868 return (Display*)gdk_x11_display_get_xdisplay(gdk_display_get_default()); 869 } 870 871 static void getVisualAndColormap(int depth, Visual **visual, Colormap *colormap) 872 { 873 *visual = 0; 874 *colormap = 0; 875 876 #ifndef QT_NO_XRENDER 877 static const bool useXRender = qgetenv("QT_X11_NO_XRENDER").isNull(); // Should also check for XRender >= 0.5 878 #else 879 static const bool useXRender = false; 880 #endif 881 882 if (!useXRender && depth == 32) 883 return; 884 885 int nvi; 886 XVisualInfo templ; 887 templ.screen = QX11Info::appScreen(); 888 templ.depth = depth; 889 templ.c_class = TrueColor; 890 XVisualInfo* xvi = XGetVisualInfo(QX11Info::display(), VisualScreenMask | VisualDepthMask | VisualClassMask, &templ, &nvi); 891 892 if (!xvi) 893 return; 894 895 #ifndef QT_NO_XRENDER 896 if (depth == 32) { 897 for (int idx = 0; idx < nvi; ++idx) { 898 XRenderPictFormat* format = XRenderFindVisualFormat(QX11Info::display(), xvi[idx].visual); 899 if (format->type == PictTypeDirect && format->direct.alphaMask) { 900 *visual = xvi[idx].visual; 901 break; 902 } 903 } 904 } else 905 #endif // QT_NO_XRENDER 906 *visual = xvi[0].visual; 907 908 XFree(xvi); 909 910 if (*visual) 911 *colormap = XCreateColormap(QX11Info::display(), QX11Info::appRootWindow(), *visual, AllocNone); 912 } 913 914 bool PluginView::platformStart() 915 { 916 ASSERT(m_isStarted); 917 ASSERT(m_status == PluginStatusLoadedSuccessfully); 918 919 if (m_plugin->pluginFuncs()->getvalue) { 920 PluginView::setCurrentPluginView(this); 921 #if USE(JSC) 922 JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly); 923 #endif 924 setCallingPlugin(true); 925 m_plugin->pluginFuncs()->getvalue(m_instance, NPPVpluginNeedsXEmbed, &m_needsXEmbed); 926 setCallingPlugin(false); 927 PluginView::setCurrentPluginView(0); 928 } 929 930 if (m_isWindowed) { 931 QWebPageClient* client = m_parentFrame->view()->hostWindow()->platformPageClient(); 932 if (m_needsXEmbed && client) { 933 setPlatformWidget(new PluginContainerQt(this, client->ownerWidget())); 934 // sync our XEmbed container window creation before sending the xid to plugins. 935 QApplication::syncX(); 936 } else { 937 notImplemented(); 938 m_status = PluginStatusCanNotLoadPlugin; 939 return false; 940 } 941 } else { 942 setPlatformWidget(0); 943 m_pluginDisplay = getPluginDisplay(); 944 945 #if USE(ACCELERATED_COMPOSITING) && !USE(TEXTURE_MAPPER) 946 if (m_parentFrame->page()->chrome()->client()->allowsAcceleratedCompositing() 947 && m_parentFrame->page()->settings() 948 && m_parentFrame->page()->settings()->acceleratedCompositingEnabled()) { 949 m_platformLayer = new PluginGraphicsLayerQt(this); 950 // Trigger layer computation in RenderLayerCompositor 951 m_element->setNeedsStyleRecalc(SyntheticStyleChange); 952 } 953 #endif 954 } 955 956 // If the width and the height are not zero we show the PluginView. 957 if (!frameRect().isEmpty()) 958 show(); 959 960 NPSetWindowCallbackStruct* wsi = new NPSetWindowCallbackStruct(); 961 wsi->type = 0; 962 963 if (m_isWindowed) { 964 const QX11Info* x11Info = &platformPluginWidget()->x11Info(); 965 966 wsi->display = x11Info->display(); 967 wsi->visual = (Visual*)x11Info->visual(); 968 wsi->depth = x11Info->depth(); 969 wsi->colormap = x11Info->colormap(); 970 971 m_npWindow.type = NPWindowTypeWindow; 972 m_npWindow.window = (void*)platformPluginWidget()->winId(); 973 m_npWindow.width = -1; 974 m_npWindow.height = -1; 975 } else { 976 const QX11Info* x11Info = &QApplication::desktop()->x11Info(); 977 978 if (x11Info->depth() == 32 || !m_plugin->quirks().contains(PluginQuirkRequiresDefaultScreenDepth)) { 979 getVisualAndColormap(32, &m_visual, &m_colormap); 980 wsi->depth = 32; 981 } 982 983 if (!m_visual) { 984 getVisualAndColormap(x11Info->depth(), &m_visual, &m_colormap); 985 wsi->depth = x11Info->depth(); 986 } 987 988 wsi->display = x11Info->display(); 989 wsi->visual = m_visual; 990 wsi->colormap = m_colormap; 991 992 m_npWindow.type = NPWindowTypeDrawable; 993 m_npWindow.window = 0; // Not used? 994 m_npWindow.x = 0; 995 m_npWindow.y = 0; 996 m_npWindow.width = -1; 997 m_npWindow.height = -1; 998 } 999 1000 m_npWindow.ws_info = wsi; 1001 1002 if (!(m_plugin->quirks().contains(PluginQuirkDeferFirstSetWindowCall))) { 1003 updatePluginWidget(); 1004 setNPWindowIfNeeded(); 1005 } 1006 1007 return true; 1008 } 1009 1010 void PluginView::platformDestroy() 1011 { 1012 if (platformPluginWidget()) 1013 delete platformPluginWidget(); 1014 1015 if (m_drawable) 1016 XFreePixmap(QX11Info::display(), m_drawable); 1017 1018 if (m_colormap) 1019 XFreeColormap(QX11Info::display(), m_colormap); 1020 } 1021 1022 void PluginView::halt() 1023 { 1024 } 1025 1026 void PluginView::restart() 1027 { 1028 } 1029 1030 #if USE(ACCELERATED_COMPOSITING) 1031 PlatformLayer* PluginView::platformLayer() const 1032 { 1033 return m_platformLayer.get(); 1034 } 1035 #endif 1036 1037 } // namespace WebCore 1038