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