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 * 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#include "Bridge.h" 32#include "Document.h" 33#include "DocumentLoader.h" 34#include "Element.h" 35#include "FloatPoint.h" 36#include "FocusController.h" 37#include "Frame.h" 38#include "FrameLoadRequest.h" 39#include "FrameLoader.h" 40#include "FrameTree.h" 41#include "FrameView.h" 42#include "GraphicsContext.h" 43#include "HTMLNames.h" 44#include "HTMLPlugInElement.h" 45#include "HostWindow.h" 46#include "Image.h" 47#include "JSDOMBinding.h" 48#include "KeyboardEvent.h" 49#include "MouseEvent.h" 50#include "NotImplemented.h" 51#include "Page.h" 52#include "PlatformMouseEvent.h" 53#include "PlatformKeyboardEvent.h" 54#include "PluginContainerQt.h" 55#include "PluginDebug.h" 56#include "PluginPackage.h" 57#include "PluginMainThreadScheduler.h" 58#include "QWebPageClient.h" 59#include "RenderLayer.h" 60#include "ScriptController.h" 61#include "Settings.h" 62#include "npruntime_impl.h" 63#include "runtime_root.h" 64 65#include <QApplication> 66#include <QDesktopWidget> 67#include <QKeyEvent> 68#include <QPainter> 69#include <QWidget> 70#include <QX11Info> 71#include <X11/X.h> 72#ifndef QT_NO_XRENDER 73#define Bool int 74#define Status int 75#include <X11/extensions/Xrender.h> 76#endif 77#include <runtime/JSLock.h> 78#include <runtime/JSValue.h> 79 80using JSC::ExecState; 81using JSC::Interpreter; 82using JSC::JSLock; 83using JSC::JSObject; 84using JSC::UString; 85 86using std::min; 87 88using namespace WTF; 89 90namespace WebCore { 91 92using namespace HTMLNames; 93 94void PluginView::updatePluginWidget() 95{ 96 if (!parent()) 97 return; 98 99 ASSERT(parent()->isFrameView()); 100 FrameView* frameView = static_cast<FrameView*>(parent()); 101 102 IntRect oldWindowRect = m_windowRect; 103 IntRect oldClipRect = m_clipRect; 104 105 m_windowRect = IntRect(frameView->contentsToWindow(frameRect().location()), frameRect().size()); 106 m_clipRect = windowClipRect(); 107 m_clipRect.move(-m_windowRect.x(), -m_windowRect.y()); 108 109 if (m_windowRect == oldWindowRect && m_clipRect == oldClipRect) 110 return; 111 112 if (!m_isWindowed && m_windowRect.size() != oldWindowRect.size()) { 113 if (m_drawable) 114 XFreePixmap(QX11Info::display(), m_drawable); 115 116 m_drawable = XCreatePixmap(QX11Info::display(), QX11Info::appRootWindow(), m_windowRect.width(), m_windowRect.height(), 117 ((NPSetWindowCallbackStruct*)m_npWindow.ws_info)->depth); 118 QApplication::syncX(); // make sure that the server knows about the Drawable 119 } 120 121 // do not call setNPWindowIfNeeded immediately, will be called on paint() 122 m_hasPendingGeometryChange = true; 123 124 // in order to move/resize the plugin window at the same time as the 125 // rest of frame during e.g. scrolling, we set the window geometry 126 // in the paint() function, but as paint() isn't called when the 127 // plugin window is outside the frame which can be caused by a 128 // scroll, we need to move/resize immediately. 129 if (!m_windowRect.intersects(frameView->frameRect())) 130 setNPWindowIfNeeded(); 131 132 // Make sure we get repainted afterwards. This is necessary for downward 133 // scrolling to move the plugin widget properly. 134 invalidate(); 135} 136 137void PluginView::setFocus() 138{ 139 if (platformPluginWidget()) 140 platformPluginWidget()->setFocus(Qt::OtherFocusReason); 141 else 142 Widget::setFocus(); 143} 144 145void PluginView::show() 146{ 147 Q_ASSERT(platformPluginWidget() == platformWidget()); 148 Widget::show(); 149} 150 151void PluginView::hide() 152{ 153 Q_ASSERT(platformPluginWidget() == platformWidget()); 154 Widget::hide(); 155} 156 157void PluginView::paint(GraphicsContext* context, const IntRect& rect) 158{ 159 if (!m_isStarted) { 160 paintMissingPluginIcon(context, rect); 161 return; 162 } 163 164 if (context->paintingDisabled()) 165 return; 166 167 setNPWindowIfNeeded(); 168 169 if (m_isWindowed || !m_drawable) 170 return; 171 172 const bool syncX = m_pluginDisplay && m_pluginDisplay != QX11Info::display(); 173 174 QPainter* painter = context->platformContext(); 175 IntRect exposedRect(rect); 176 exposedRect.intersect(frameRect()); 177 exposedRect.move(-frameRect().x(), -frameRect().y()); 178 179 QPixmap qtDrawable = QPixmap::fromX11Pixmap(m_drawable, QPixmap::ExplicitlyShared); 180 const int drawableDepth = ((NPSetWindowCallbackStruct*)m_npWindow.ws_info)->depth; 181 ASSERT(drawableDepth == qtDrawable.depth()); 182 183 // When printing, Qt uses a QPicture to capture the output in preview mode. The 184 // QPicture holds a reference to the X Pixmap. As a result, the print preview would 185 // update itself when the X Pixmap changes. To prevent this, we create a copy. 186 if (m_element->document()->printing()) 187 qtDrawable = qtDrawable.copy(); 188 189 if (m_isTransparent && drawableDepth != 32) { 190 // Attempt content propagation for drawable with no alpha by copying over from the backing store 191 QPoint offset; 192 QPaintDevice* backingStoreDevice = QPainter::redirected(painter->device(), &offset); 193 offset = -offset; // negating the offset gives us the offset of the view within the backing store pixmap 194 195 const bool hasValidBackingStore = backingStoreDevice && backingStoreDevice->devType() == QInternal::Pixmap; 196 QPixmap* backingStorePixmap = static_cast<QPixmap*>(backingStoreDevice); 197 198 // We cannot grab contents from the backing store when painting on QGraphicsView items 199 // (because backing store contents are already transformed). What we really mean to do 200 // here is to check if we are painting on QWebView, but let's be a little permissive :) 201 QWebPageClient* client = m_parentFrame->view()->hostWindow()->platformPageClient(); 202 const bool backingStoreHasUntransformedContents = client && qobject_cast<QWidget*>(client->pluginParent()); 203 204 if (hasValidBackingStore && backingStorePixmap->depth() == drawableDepth 205 && backingStoreHasUntransformedContents) { 206 GC gc = XDefaultGC(QX11Info::display(), QX11Info::appScreen()); 207 XCopyArea(QX11Info::display(), backingStorePixmap->handle(), m_drawable, gc, 208 offset.x() + m_windowRect.x() + exposedRect.x(), offset.y() + m_windowRect.y() + exposedRect.y(), 209 exposedRect.width(), exposedRect.height(), exposedRect.x(), exposedRect.y()); 210 } else { // no backing store, clean the pixmap because the plugin thinks its transparent 211 QPainter painter(&qtDrawable); 212 painter.fillRect(exposedRect, Qt::white); 213 } 214 215 if (syncX) 216 QApplication::syncX(); 217 } 218 219 XEvent xevent; 220 memset(&xevent, 0, sizeof(XEvent)); 221 XGraphicsExposeEvent& exposeEvent = xevent.xgraphicsexpose; 222 exposeEvent.type = GraphicsExpose; 223 exposeEvent.display = QX11Info::display(); 224 exposeEvent.drawable = qtDrawable.handle(); 225 exposeEvent.x = exposedRect.x(); 226 exposeEvent.y = exposedRect.y(); 227 exposeEvent.width = exposedRect.x() + exposedRect.width(); // flash bug? it thinks width is the right in transparent mode 228 exposeEvent.height = exposedRect.y() + exposedRect.height(); // flash bug? it thinks height is the bottom in transparent mode 229 230 dispatchNPEvent(xevent); 231 232 if (syncX) 233 XSync(m_pluginDisplay, False); // sync changes by plugin 234 235 painter->drawPixmap(QPoint(frameRect().x() + exposedRect.x(), frameRect().y() + exposedRect.y()), qtDrawable, 236 exposedRect); 237} 238 239// TODO: Unify across ports. 240bool PluginView::dispatchNPEvent(NPEvent& event) 241{ 242 if (!m_plugin->pluginFuncs()->event) 243 return false; 244 245 PluginView::setCurrentPluginView(this); 246 JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly); 247 setCallingPlugin(true); 248 bool accepted = m_plugin->pluginFuncs()->event(m_instance, &event); 249 setCallingPlugin(false); 250 PluginView::setCurrentPluginView(0); 251 252 return accepted; 253} 254 255void setSharedXEventFields(XEvent* xEvent, QWidget* ownerWidget) 256{ 257 xEvent->xany.serial = 0; // we are unaware of the last request processed by X Server 258 xEvent->xany.send_event = false; 259 xEvent->xany.display = QX11Info::display(); 260 // NOTE: event->xany.window doesn't always respond to the .window property of other XEvent's 261 // but does in the case of KeyPress, KeyRelease, ButtonPress, ButtonRelease, and MotionNotify 262 // events; thus, this is right: 263 xEvent->xany.window = ownerWidget ? ownerWidget->window()->handle() : 0; 264} 265 266void PluginView::initXEvent(XEvent* xEvent) 267{ 268 memset(xEvent, 0, sizeof(XEvent)); 269 270 QWebPageClient* client = m_parentFrame->view()->hostWindow()->platformPageClient(); 271 QWidget* ownerWidget = client ? client->ownerWidget() : 0; 272 setSharedXEventFields(xEvent, ownerWidget); 273} 274 275void setXKeyEventSpecificFields(XEvent* xEvent, KeyboardEvent* event) 276{ 277 QKeyEvent* qKeyEvent = event->keyEvent()->qtEvent(); 278 279 xEvent->type = (event->type() == eventNames().keydownEvent) ? 2 : 3; // ints as Qt unsets KeyPress and KeyRelease 280 xEvent->xkey.root = QX11Info::appRootWindow(); 281 xEvent->xkey.subwindow = 0; // we have no child window 282 xEvent->xkey.time = event->timeStamp(); 283 xEvent->xkey.state = qKeyEvent->nativeModifiers(); 284 xEvent->xkey.keycode = qKeyEvent->nativeScanCode(); 285 xEvent->xkey.same_screen = true; 286 287 // NOTE: As the XEvents sent to the plug-in are synthesized and there is not a native window 288 // corresponding to the plug-in rectangle, some of the members of the XEvent structures are not 289 // set to their normal Xserver values. e.g. Key events don't have a position. 290 // source: https://developer.mozilla.org/en/NPEvent 291 xEvent->xkey.x = 0; 292 xEvent->xkey.y = 0; 293 xEvent->xkey.x_root = 0; 294 xEvent->xkey.y_root = 0; 295} 296 297void PluginView::handleKeyboardEvent(KeyboardEvent* event) 298{ 299 if (m_isWindowed) 300 return; 301 302 if (event->type() != eventNames().keydownEvent && event->type() != eventNames().keyupEvent) 303 return; 304 305 XEvent npEvent; 306 initXEvent(&npEvent); 307 setXKeyEventSpecificFields(&npEvent, event); 308 309 if (!dispatchNPEvent(npEvent)) 310 event->setDefaultHandled(); 311} 312 313static unsigned int inputEventState(MouseEvent* event) 314{ 315 unsigned int state = 0; 316 if (event->ctrlKey()) 317 state |= ControlMask; 318 if (event->shiftKey()) 319 state |= ShiftMask; 320 if (event->altKey()) 321 state |= Mod1Mask; 322 if (event->metaKey()) 323 state |= Mod4Mask; 324 return state; 325} 326 327static void setXButtonEventSpecificFields(XEvent* xEvent, MouseEvent* event, const IntPoint& postZoomPos) 328{ 329 XButtonEvent& xbutton = xEvent->xbutton; 330 xbutton.type = event->type() == eventNames().mousedownEvent ? ButtonPress : ButtonRelease; 331 xbutton.root = QX11Info::appRootWindow(); 332 xbutton.subwindow = 0; 333 xbutton.time = event->timeStamp(); 334 xbutton.x = postZoomPos.x(); 335 xbutton.y = postZoomPos.y(); 336 xbutton.x_root = event->screenX(); 337 xbutton.y_root = event->screenY(); 338 xbutton.state = inputEventState(event); 339 switch (event->button()) { 340 case MiddleButton: 341 xbutton.button = Button2; 342 break; 343 case RightButton: 344 xbutton.button = Button3; 345 break; 346 case LeftButton: 347 default: 348 xbutton.button = Button1; 349 break; 350 } 351 xbutton.same_screen = true; 352} 353 354static void setXMotionEventSpecificFields(XEvent* xEvent, MouseEvent* event, const IntPoint& postZoomPos) 355{ 356 XMotionEvent& xmotion = xEvent->xmotion; 357 xmotion.type = MotionNotify; 358 xmotion.root = QX11Info::appRootWindow(); 359 xmotion.subwindow = 0; 360 xmotion.time = event->timeStamp(); 361 xmotion.x = postZoomPos.x(); 362 xmotion.y = postZoomPos.y(); 363 xmotion.x_root = event->screenX(); 364 xmotion.y_root = event->screenY(); 365 xmotion.state = inputEventState(event); 366 xmotion.is_hint = NotifyNormal; 367 xmotion.same_screen = true; 368} 369 370static void setXCrossingEventSpecificFields(XEvent* xEvent, MouseEvent* event, const IntPoint& postZoomPos) 371{ 372 XCrossingEvent& xcrossing = xEvent->xcrossing; 373 xcrossing.type = event->type() == eventNames().mouseoverEvent ? EnterNotify : LeaveNotify; 374 xcrossing.root = QX11Info::appRootWindow(); 375 xcrossing.subwindow = 0; 376 xcrossing.time = event->timeStamp(); 377 xcrossing.x = postZoomPos.y(); 378 xcrossing.y = postZoomPos.x(); 379 xcrossing.x_root = event->screenX(); 380 xcrossing.y_root = event->screenY(); 381 xcrossing.state = inputEventState(event); 382 xcrossing.mode = NotifyNormal; 383 xcrossing.detail = NotifyDetailNone; 384 xcrossing.same_screen = true; 385 xcrossing.focus = false; 386} 387 388void PluginView::handleMouseEvent(MouseEvent* event) 389{ 390 if (m_isWindowed) 391 return; 392 393 if (event->type() == eventNames().mousedownEvent) { 394 // Give focus to the plugin on click 395 if (Page* page = m_parentFrame->page()) 396 page->focusController()->setActive(true); 397 398 focusPluginElement(); 399 } 400 401 XEvent npEvent; 402 initXEvent(&npEvent); 403 404 IntPoint postZoomPos = roundedIntPoint(m_element->renderer()->absoluteToLocal(event->absoluteLocation())); 405 406 if (event->type() == eventNames().mousedownEvent || event->type() == eventNames().mouseupEvent) 407 setXButtonEventSpecificFields(&npEvent, event, postZoomPos); 408 else if (event->type() == eventNames().mousemoveEvent) 409 setXMotionEventSpecificFields(&npEvent, event, postZoomPos); 410 else if (event->type() == eventNames().mouseoutEvent || event->type() == eventNames().mouseoverEvent) 411 setXCrossingEventSpecificFields(&npEvent, event, postZoomPos); 412 else 413 return; 414 415 if (!dispatchNPEvent(npEvent)) 416 event->setDefaultHandled(); 417} 418 419void PluginView::handleFocusInEvent() 420{ 421 XEvent npEvent; 422 initXEvent(&npEvent); 423 424 XFocusChangeEvent& event = npEvent.xfocus; 425 event.type = 9; /* int as Qt unsets FocusIn */ 426 event.mode = NotifyNormal; 427 event.detail = NotifyDetailNone; 428 429 dispatchNPEvent(npEvent); 430} 431 432void PluginView::handleFocusOutEvent() 433{ 434 XEvent npEvent; 435 initXEvent(&npEvent); 436 437 XFocusChangeEvent& event = npEvent.xfocus; 438 event.type = 10; /* int as Qt unsets FocusOut */ 439 event.mode = NotifyNormal; 440 event.detail = NotifyDetailNone; 441 442 dispatchNPEvent(npEvent); 443} 444 445void PluginView::setParent(ScrollView* parent) 446{ 447 Widget::setParent(parent); 448 449 if (parent) 450 init(); 451} 452 453void PluginView::setNPWindowRect(const IntRect&) 454{ 455 if (!m_isWindowed) 456 setNPWindowIfNeeded(); 457} 458 459void PluginView::setNPWindowIfNeeded() 460{ 461 if (!m_isStarted || !parent() || !m_plugin->pluginFuncs()->setwindow) 462 return; 463 464 // If the plugin didn't load sucessfully, no point in calling setwindow 465 if (m_status != PluginStatusLoadedSuccessfully) 466 return; 467 468 // On Unix, only call plugin if it's full-page or windowed 469 if (m_mode != NP_FULL && m_mode != NP_EMBED) 470 return; 471 472 // Check if the platformPluginWidget still exists 473 if (m_isWindowed && !platformPluginWidget()) 474 return; 475 476 if (!m_hasPendingGeometryChange) 477 return; 478 m_hasPendingGeometryChange = false; 479 480 if (m_isWindowed) { 481 platformPluginWidget()->setGeometry(m_windowRect); 482 // if setMask is set with an empty QRegion, no clipping will 483 // be performed, so in that case we hide the plugin view 484 platformPluginWidget()->setVisible(!m_clipRect.isEmpty()); 485 platformPluginWidget()->setMask(QRegion(m_clipRect)); 486 487 m_npWindow.x = m_windowRect.x(); 488 m_npWindow.y = m_windowRect.y(); 489 490 m_npWindow.clipRect.left = m_clipRect.x(); 491 m_npWindow.clipRect.top = m_clipRect.y(); 492 m_npWindow.clipRect.right = m_clipRect.width(); 493 m_npWindow.clipRect.bottom = m_clipRect.height(); 494 } else { 495 m_npWindow.x = 0; 496 m_npWindow.y = 0; 497 498 m_npWindow.clipRect.left = 0; 499 m_npWindow.clipRect.top = 0; 500 m_npWindow.clipRect.right = 0; 501 m_npWindow.clipRect.bottom = 0; 502 } 503 504 // FLASH WORKAROUND: Only set initially. Multiple calls to 505 // setNPWindow() cause the plugin to crash in windowed mode. 506 if (!m_isWindowed || m_npWindow.width == -1 || m_npWindow.height == -1) { 507 m_npWindow.width = m_windowRect.width(); 508 m_npWindow.height = m_windowRect.height(); 509 } 510 511 PluginView::setCurrentPluginView(this); 512 JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly); 513 setCallingPlugin(true); 514 m_plugin->pluginFuncs()->setwindow(m_instance, &m_npWindow); 515 setCallingPlugin(false); 516 PluginView::setCurrentPluginView(0); 517} 518 519void PluginView::setParentVisible(bool visible) 520{ 521 if (isParentVisible() == visible) 522 return; 523 524 Widget::setParentVisible(visible); 525 526 if (isSelfVisible() && platformPluginWidget()) 527 platformPluginWidget()->setVisible(visible); 528} 529 530NPError PluginView::handlePostReadFile(Vector<char>& buffer, uint32 len, const char* buf) 531{ 532 String filename(buf, len); 533 534 if (filename.startsWith("file:///")) 535 filename = filename.substring(8); 536 537 long long size; 538 if (!getFileSize(filename, size)) 539 return NPERR_FILE_NOT_FOUND; 540 541 FILE* fileHandle = fopen((filename.utf8()).data(), "r"); 542 if (!fileHandle) 543 return NPERR_FILE_NOT_FOUND; 544 545 buffer.resize(size); 546 int bytesRead = fread(buffer.data(), 1, size, fileHandle); 547 548 fclose(fileHandle); 549 550 if (bytesRead <= 0) 551 return NPERR_FILE_NOT_FOUND; 552 553 return NPERR_NO_ERROR; 554} 555 556NPError PluginView::getValueStatic(NPNVariable variable, void* value) 557{ 558 LOG(Plugins, "PluginView::getValueStatic(%s)", prettyNameForNPNVariable(variable).data()); 559 560 switch (variable) { 561 case NPNVToolkit: 562 *static_cast<uint32*>(value) = 0; 563 return NPERR_NO_ERROR; 564 565 case NPNVSupportsXEmbedBool: 566 *static_cast<NPBool*>(value) = true; 567 return NPERR_NO_ERROR; 568 569 case NPNVjavascriptEnabledBool: 570 *static_cast<NPBool*>(value) = true; 571 return NPERR_NO_ERROR; 572 573 case NPNVSupportsWindowless: 574 *static_cast<NPBool*>(value) = true; 575 return NPERR_NO_ERROR; 576 577 default: 578 return NPERR_GENERIC_ERROR; 579 } 580} 581 582NPError PluginView::getValue(NPNVariable variable, void* value) 583{ 584 LOG(Plugins, "PluginView::getValue(%s)", prettyNameForNPNVariable(variable).data()); 585 586 switch (variable) { 587 case NPNVxDisplay: 588 *(void **)value = QX11Info::display(); 589 return NPERR_NO_ERROR; 590 591 case NPNVxtAppContext: 592 return NPERR_GENERIC_ERROR; 593 594#if ENABLE(NETSCAPE_PLUGIN_API) 595 case NPNVWindowNPObject: { 596 if (m_isJavaScriptPaused) 597 return NPERR_GENERIC_ERROR; 598 599 NPObject* windowScriptObject = m_parentFrame->script()->windowScriptNPObject(); 600 601 // Return value is expected to be retained, as described here: <http://www.mozilla.org/projects/plugin/npruntime.html> 602 if (windowScriptObject) 603 _NPN_RetainObject(windowScriptObject); 604 605 void** v = (void**)value; 606 *v = windowScriptObject; 607 608 return NPERR_NO_ERROR; 609 } 610 611 case NPNVPluginElementNPObject: { 612 if (m_isJavaScriptPaused) 613 return NPERR_GENERIC_ERROR; 614 615 NPObject* pluginScriptObject = 0; 616 617 if (m_element->hasTagName(appletTag) || m_element->hasTagName(embedTag) || m_element->hasTagName(objectTag)) 618 pluginScriptObject = static_cast<HTMLPlugInElement*>(m_element)->getNPObject(); 619 620 // Return value is expected to be retained, as described here: <http://www.mozilla.org/projects/plugin/npruntime.html> 621 if (pluginScriptObject) 622 _NPN_RetainObject(pluginScriptObject); 623 624 void** v = (void**)value; 625 *v = pluginScriptObject; 626 627 return NPERR_NO_ERROR; 628 } 629#endif 630 631 case NPNVnetscapeWindow: { 632 void* w = reinterpret_cast<void*>(value); 633 QWebPageClient* client = m_parentFrame->view()->hostWindow()->platformPageClient(); 634 *((XID *)w) = client ? client->ownerWidget()->window()->winId() : 0; 635 return NPERR_NO_ERROR; 636 } 637 638 case NPNVToolkit: 639 if (m_plugin->quirks().contains(PluginQuirkRequiresGtkToolKit)) { 640 *((uint32 *)value) = 2; 641 return NPERR_NO_ERROR; 642 } 643 // fall through 644 default: 645 return getValueStatic(variable, value); 646 } 647} 648 649void PluginView::invalidateRect(const IntRect& rect) 650{ 651 if (m_isWindowed) { 652 if (platformWidget()) 653 platformWidget()->update(rect); 654 return; 655 } 656 657 invalidateWindowlessPluginRect(rect); 658} 659 660void PluginView::invalidateRect(NPRect* rect) 661{ 662 if (!rect) { 663 invalidate(); 664 return; 665 } 666 IntRect r(rect->left, rect->top, rect->right - rect->left, rect->bottom - rect->top); 667 invalidateWindowlessPluginRect(r); 668} 669 670void PluginView::invalidateRegion(NPRegion region) 671{ 672 invalidate(); 673} 674 675void PluginView::forceRedraw() 676{ 677 invalidate(); 678} 679 680static Display *getPluginDisplay() 681{ 682 // The plugin toolkit might run using a different X connection. At the moment, we only 683 // support gdk based plugins (like flash) that use a different X connection. 684 // The code below has the same effect as this one: 685 // Display *gdkDisplay = gdk_x11_display_get_xdisplay(gdk_display_get_default()); 686 QLibrary library("libgdk-x11-2.0"); 687 if (!library.load()) 688 return 0; 689 690 typedef void *(*gdk_display_get_default_ptr)(); 691 gdk_display_get_default_ptr gdk_display_get_default = (gdk_display_get_default_ptr)library.resolve("gdk_display_get_default"); 692 if (!gdk_display_get_default) 693 return 0; 694 695 typedef void *(*gdk_x11_display_get_xdisplay_ptr)(void *); 696 gdk_x11_display_get_xdisplay_ptr gdk_x11_display_get_xdisplay = (gdk_x11_display_get_xdisplay_ptr)library.resolve("gdk_x11_display_get_xdisplay"); 697 if (!gdk_x11_display_get_xdisplay) 698 return 0; 699 700 return (Display*)gdk_x11_display_get_xdisplay(gdk_display_get_default()); 701} 702 703static void getVisualAndColormap(int depth, Visual **visual, Colormap *colormap) 704{ 705 *visual = 0; 706 *colormap = 0; 707 708#ifndef QT_NO_XRENDER 709 static const bool useXRender = qgetenv("QT_X11_NO_XRENDER").isNull(); // Should also check for XRender >= 0.5 710#else 711 static const bool useXRender = false; 712#endif 713 714 if (!useXRender && depth == 32) 715 return; 716 717 int nvi; 718 XVisualInfo templ; 719 templ.screen = QX11Info::appScreen(); 720 templ.depth = depth; 721 templ.c_class = TrueColor; 722 XVisualInfo* xvi = XGetVisualInfo(QX11Info::display(), VisualScreenMask | VisualDepthMask | VisualClassMask, &templ, &nvi); 723 724 if (!xvi) 725 return; 726 727#ifndef QT_NO_XRENDER 728 if (depth == 32) { 729 for (int idx = 0; idx < nvi; ++idx) { 730 XRenderPictFormat* format = XRenderFindVisualFormat(QX11Info::display(), xvi[idx].visual); 731 if (format->type == PictTypeDirect && format->direct.alphaMask) { 732 *visual = xvi[idx].visual; 733 break; 734 } 735 } 736 } else 737#endif // QT_NO_XRENDER 738 *visual = xvi[0].visual; 739 740 XFree(xvi); 741 742 if (*visual) 743 *colormap = XCreateColormap(QX11Info::display(), QX11Info::appRootWindow(), *visual, AllocNone); 744} 745 746bool PluginView::platformStart() 747{ 748 ASSERT(m_isStarted); 749 ASSERT(m_status == PluginStatusLoadedSuccessfully); 750 751 if (m_plugin->pluginFuncs()->getvalue) { 752 PluginView::setCurrentPluginView(this); 753 JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly); 754 setCallingPlugin(true); 755 m_plugin->pluginFuncs()->getvalue(m_instance, NPPVpluginNeedsXEmbed, &m_needsXEmbed); 756 setCallingPlugin(false); 757 PluginView::setCurrentPluginView(0); 758 } 759 760 if (m_isWindowed) { 761 QWebPageClient* client = m_parentFrame->view()->hostWindow()->platformPageClient(); 762 if (m_needsXEmbed && client) { 763 setPlatformWidget(new PluginContainerQt(this, client->ownerWidget())); 764 // sync our XEmbed container window creation before sending the xid to plugins. 765 QApplication::syncX(); 766 } else { 767 notImplemented(); 768 m_status = PluginStatusCanNotLoadPlugin; 769 return false; 770 } 771 } else { 772 setPlatformWidget(0); 773 m_pluginDisplay = getPluginDisplay(); 774 } 775 776 show(); 777 778 NPSetWindowCallbackStruct* wsi = new NPSetWindowCallbackStruct(); 779 wsi->type = 0; 780 781 if (m_isWindowed) { 782 const QX11Info* x11Info = &platformPluginWidget()->x11Info(); 783 784 wsi->display = x11Info->display(); 785 wsi->visual = (Visual*)x11Info->visual(); 786 wsi->depth = x11Info->depth(); 787 wsi->colormap = x11Info->colormap(); 788 789 m_npWindow.type = NPWindowTypeWindow; 790 m_npWindow.window = (void*)platformPluginWidget()->winId(); 791 m_npWindow.width = -1; 792 m_npWindow.height = -1; 793 } else { 794 const QX11Info* x11Info = &QApplication::desktop()->x11Info(); 795 796 if (x11Info->depth() == 32 || !m_plugin->quirks().contains(PluginQuirkRequiresDefaultScreenDepth)) { 797 getVisualAndColormap(32, &m_visual, &m_colormap); 798 wsi->depth = 32; 799 } 800 801 if (!m_visual) { 802 getVisualAndColormap(x11Info->depth(), &m_visual, &m_colormap); 803 wsi->depth = x11Info->depth(); 804 } 805 806 wsi->display = x11Info->display(); 807 wsi->visual = m_visual; 808 wsi->colormap = m_colormap; 809 810 m_npWindow.type = NPWindowTypeDrawable; 811 m_npWindow.window = 0; // Not used? 812 m_npWindow.x = 0; 813 m_npWindow.y = 0; 814 m_npWindow.width = -1; 815 m_npWindow.height = -1; 816 } 817 818 m_npWindow.ws_info = wsi; 819 820 if (!(m_plugin->quirks().contains(PluginQuirkDeferFirstSetWindowCall))) { 821 updatePluginWidget(); 822 setNPWindowIfNeeded(); 823 } 824 825 return true; 826} 827 828void PluginView::platformDestroy() 829{ 830 if (platformPluginWidget()) 831 delete platformPluginWidget(); 832 833 if (m_drawable) 834 XFreePixmap(QX11Info::display(), m_drawable); 835 836 if (m_colormap) 837 XFreeColormap(QX11Info::display(), m_colormap); 838} 839 840void PluginView::halt() 841{ 842} 843 844void PluginView::restart() 845{ 846} 847 848} // namespace WebCore 849