1/* 2 * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. 3 * Copyright (C) 2008 Collabora Ltd. All rights reserved. 4 * Copyright (C) 2009, 2010 Kakai, Inc. <brian@kakai.com> 5 * Copyright (C) 2010 Igalia S.L. 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 "BridgeJSC.h" 33#include "Document.h" 34#include "DocumentLoader.h" 35#include "Element.h" 36#include "FocusController.h" 37#include "FrameLoader.h" 38#include "FrameLoadRequest.h" 39#include "FrameTree.h" 40#include "Frame.h" 41#include "FrameView.h" 42#include "GraphicsContext.h" 43#include "GtkVersioning.h" 44#include "HTMLNames.h" 45#include "HTMLPlugInElement.h" 46#include "HostWindow.h" 47#include "Image.h" 48#include "KeyboardEvent.h" 49#include "MouseEvent.h" 50#include "NotImplemented.h" 51#include "Page.h" 52#include "PlatformContextCairo.h" 53#include "PlatformKeyboardEvent.h" 54#include "PlatformMouseEvent.h" 55#include "PluginDebug.h" 56#include "PluginMainThreadScheduler.h" 57#include "PluginPackage.h" 58#include "RenderLayer.h" 59#include "Settings.h" 60#include "JSDOMBinding.h" 61#include "ScriptController.h" 62#include "npruntime_impl.h" 63#include "runtime_root.h" 64#include <runtime/JSLock.h> 65#include <runtime/JSValue.h> 66 67#ifdef GTK_API_VERSION_2 68#include <gdkconfig.h> 69#endif 70#include <gtk/gtk.h> 71 72#if defined(XP_UNIX) 73#include "RefPtrCairo.h" 74#include "gtk2xtbin.h" 75#define Bool int // this got undefined somewhere 76#define Status int // ditto 77#include <X11/extensions/Xrender.h> 78#include <cairo/cairo-xlib.h> 79#include <gdk/gdkx.h> 80#elif defined(GDK_WINDOWING_WIN32) 81#include "PluginMessageThrottlerWin.h" 82#include <gdk/gdkwin32.h> 83#endif 84 85using JSC::ExecState; 86using JSC::Interpreter; 87using JSC::JSLock; 88using JSC::JSObject; 89using JSC::UString; 90 91using std::min; 92 93using namespace WTF; 94 95namespace WebCore { 96 97using namespace HTMLNames; 98 99bool PluginView::dispatchNPEvent(NPEvent& event) 100{ 101 // sanity check 102 if (!m_plugin->pluginFuncs()->event) 103 return false; 104 105 PluginView::setCurrentPluginView(this); 106 JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly); 107 setCallingPlugin(true); 108 109 bool accepted = m_plugin->pluginFuncs()->event(m_instance, &event); 110 111 setCallingPlugin(false); 112 PluginView::setCurrentPluginView(0); 113 return accepted; 114} 115 116#if defined(XP_UNIX) 117static Window getRootWindow(Frame* parentFrame) 118{ 119 GtkWidget* parentWidget = parentFrame->view()->hostWindow()->platformPageClient(); 120 GdkScreen* gscreen = gtk_widget_get_screen(parentWidget); 121 return GDK_WINDOW_XWINDOW(gdk_screen_get_root_window(gscreen)); 122} 123#endif 124 125void PluginView::updatePluginWidget() 126{ 127 if (!parent()) 128 return; 129 130 ASSERT(parent()->isFrameView()); 131 FrameView* frameView = static_cast<FrameView*>(parent()); 132 133 IntRect oldWindowRect = m_windowRect; 134 IntRect oldClipRect = m_clipRect; 135 136 m_windowRect = IntRect(frameView->contentsToWindow(frameRect().location()), frameRect().size()); 137 m_clipRect = windowClipRect(); 138 m_clipRect.move(-m_windowRect.x(), -m_windowRect.y()); 139 140 if (m_windowRect == oldWindowRect && m_clipRect == oldClipRect) 141 return; 142 143#if defined(XP_UNIX) 144 if (!m_isWindowed) { 145 Display* display = GDK_DISPLAY_XDISPLAY(gdk_display_get_default()); 146 if (m_drawable) 147 XFreePixmap(display, m_drawable); 148 149 m_drawable = XCreatePixmap(display, getRootWindow(m_parentFrame.get()), 150 m_windowRect.width(), m_windowRect.height(), 151 ((NPSetWindowCallbackStruct*)m_npWindow.ws_info)->depth); 152 XSync(display, false); // make sure that the server knows about the Drawable 153 } 154#endif 155 156 setNPWindowIfNeeded(); 157} 158 159void PluginView::setFocus(bool focused) 160{ 161 ASSERT(platformPluginWidget() == platformWidget()); 162 Widget::setFocus(focused); 163} 164 165void PluginView::show() 166{ 167 ASSERT(platformPluginWidget() == platformWidget()); 168 Widget::show(); 169} 170 171void PluginView::hide() 172{ 173 ASSERT(platformPluginWidget() == platformWidget()); 174 Widget::hide(); 175} 176 177void PluginView::paint(GraphicsContext* context, const IntRect& rect) 178{ 179 if (!m_isStarted) { 180 paintMissingPluginIcon(context, rect); 181 return; 182 } 183 184 if (context->paintingDisabled()) 185 return; 186 187 setNPWindowIfNeeded(); 188 189 if (m_isWindowed) 190 return; 191 192#if defined(XP_UNIX) 193 if (!m_drawable) 194 return; 195 196 Display* display = GDK_DISPLAY_XDISPLAY(gdk_display_get_default()); 197 const bool syncX = m_pluginDisplay && m_pluginDisplay != display; 198 199 IntRect exposedRect(rect); 200 exposedRect.intersect(frameRect()); 201 exposedRect.move(-frameRect().x(), -frameRect().y()); 202 203 RefPtr<cairo_surface_t> drawableSurface = adoptRef(cairo_xlib_surface_create(display, 204 m_drawable, 205 m_visual, 206 m_windowRect.width(), 207 m_windowRect.height())); 208 209 if (m_isTransparent) { 210 // If we have a 32 bit drawable and the plugin wants transparency, 211 // we'll clear the exposed area to transparent first. Otherwise, 212 // we'd end up with junk in there from the last paint, or, worse, 213 // uninitialized data. 214 RefPtr<cairo_t> cr = adoptRef(cairo_create(drawableSurface.get())); 215 216 if (!(cairo_surface_get_content(drawableSurface.get()) & CAIRO_CONTENT_ALPHA)) { 217 // Attempt to fake it when we don't have an alpha channel on our 218 // pixmap. If that's not possible, at least clear the window to 219 // avoid drawing artifacts. 220 221 // This Would not work without double buffering, but we always use it. 222 cairo_set_source_surface(cr.get(), cairo_get_group_target(context->platformContext()->cr()), 223 -m_windowRect.x(), -m_windowRect.y()); 224 cairo_set_operator(cr.get(), CAIRO_OPERATOR_SOURCE); 225 } else 226 cairo_set_operator(cr.get(), CAIRO_OPERATOR_CLEAR); 227 228 cairo_rectangle(cr.get(), exposedRect.x(), exposedRect.y(), 229 exposedRect.width(), exposedRect.height()); 230 cairo_fill(cr.get()); 231 } 232 233 XEvent xevent; 234 memset(&xevent, 0, sizeof(XEvent)); 235 XGraphicsExposeEvent& exposeEvent = xevent.xgraphicsexpose; 236 exposeEvent.type = GraphicsExpose; 237 exposeEvent.display = display; 238 exposeEvent.drawable = m_drawable; 239 exposeEvent.x = exposedRect.x(); 240 exposeEvent.y = exposedRect.y(); 241 exposeEvent.width = exposedRect.x() + exposedRect.width(); // flash bug? it thinks width is the right in transparent mode 242 exposeEvent.height = exposedRect.y() + exposedRect.height(); // flash bug? it thinks height is the bottom in transparent mode 243 244 dispatchNPEvent(xevent); 245 246 if (syncX) 247 XSync(m_pluginDisplay, false); // sync changes by plugin 248 249 cairo_t* cr = context->platformContext()->cr(); 250 cairo_save(cr); 251 252 cairo_set_source_surface(cr, drawableSurface.get(), frameRect().x(), frameRect().y()); 253 254 cairo_rectangle(cr, 255 frameRect().x() + exposedRect.x(), frameRect().y() + exposedRect.y(), 256 exposedRect.width(), exposedRect.height()); 257 cairo_clip(cr); 258 259 if (m_isTransparent) 260 cairo_set_operator(cr, CAIRO_OPERATOR_OVER); 261 else 262 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); 263 cairo_paint(cr); 264 265 cairo_restore(cr); 266#endif // defined(XP_UNIX) 267} 268 269void PluginView::handleKeyboardEvent(KeyboardEvent* event) 270{ 271 JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly); 272 273 if (m_isWindowed) 274 return; 275 276 if (event->type() != eventNames().keydownEvent && event->type() != eventNames().keyupEvent) 277 return; 278 279 NPEvent xEvent; 280#if defined(XP_UNIX) 281 initXEvent(&xEvent); 282 GdkEventKey* gdkEvent = event->keyEvent()->gdkEventKey(); 283 284 xEvent.type = (event->type() == eventNames().keydownEvent) ? 2 : 3; // KeyPress/Release get unset somewhere 285 xEvent.xkey.root = getRootWindow(m_parentFrame.get()); 286 xEvent.xkey.subwindow = 0; // we have no child window 287 xEvent.xkey.time = event->timeStamp(); 288 xEvent.xkey.state = gdkEvent->state; // GdkModifierType mirrors xlib state masks 289 xEvent.xkey.keycode = gdkEvent->hardware_keycode; 290 xEvent.xkey.same_screen = true; 291 292 // NOTE: As the XEvents sent to the plug-in are synthesized and there is not a native window 293 // corresponding to the plug-in rectangle, some of the members of the XEvent structures are not 294 // set to their normal Xserver values. e.g. Key events don't have a position. 295 // source: https://developer.mozilla.org/en/NPEvent 296 xEvent.xkey.x = 0; 297 xEvent.xkey.y = 0; 298 xEvent.xkey.x_root = 0; 299 xEvent.xkey.y_root = 0; 300#endif 301 302 if (!dispatchNPEvent(xEvent)) 303 event->setDefaultHandled(); 304} 305 306#if defined(XP_UNIX) 307static unsigned int inputEventState(MouseEvent* event) 308{ 309 unsigned int state = 0; 310 if (event->ctrlKey()) 311 state |= ControlMask; 312 if (event->shiftKey()) 313 state |= ShiftMask; 314 if (event->altKey()) 315 state |= Mod1Mask; 316 if (event->metaKey()) 317 state |= Mod4Mask; 318 return state; 319} 320 321void PluginView::initXEvent(XEvent* xEvent) 322{ 323 memset(xEvent, 0, sizeof(XEvent)); 324 325 xEvent->xany.serial = 0; // we are unaware of the last request processed by X Server 326 xEvent->xany.send_event = false; 327 GtkWidget* widget = m_parentFrame->view()->hostWindow()->platformPageClient(); 328 xEvent->xany.display = GDK_DISPLAY_XDISPLAY(gtk_widget_get_display(widget)); 329 330 // Mozilla also sends None here for windowless plugins. See nsObjectFrame.cpp in the Mozilla sources. 331 // This method also sets up FocusIn and FocusOut events for windows plugins, but Mozilla doesn't 332 // even send these types of events to windowed plugins. In the future, it may be good to only 333 // send them to windowless plugins. 334 xEvent->xany.window = None; 335} 336 337static void setXButtonEventSpecificFields(XEvent* xEvent, MouseEvent* event, const IntPoint& postZoomPos, Frame* parentFrame) 338{ 339 XButtonEvent& xbutton = xEvent->xbutton; 340 xbutton.type = event->type() == eventNames().mousedownEvent ? ButtonPress : ButtonRelease; 341 xbutton.root = getRootWindow(parentFrame); 342 xbutton.subwindow = 0; 343 xbutton.time = event->timeStamp(); 344 xbutton.x = postZoomPos.x(); 345 xbutton.y = postZoomPos.y(); 346 xbutton.x_root = event->screenX(); 347 xbutton.y_root = event->screenY(); 348 xbutton.state = inputEventState(event); 349 switch (event->button()) { 350 case MiddleButton: 351 xbutton.button = Button2; 352 break; 353 case RightButton: 354 xbutton.button = Button3; 355 break; 356 case LeftButton: 357 default: 358 xbutton.button = Button1; 359 break; 360 } 361 xbutton.same_screen = true; 362} 363 364static void setXMotionEventSpecificFields(XEvent* xEvent, MouseEvent* event, const IntPoint& postZoomPos, Frame* parentFrame) 365{ 366 XMotionEvent& xmotion = xEvent->xmotion; 367 xmotion.type = MotionNotify; 368 xmotion.root = getRootWindow(parentFrame); 369 xmotion.subwindow = 0; 370 xmotion.time = event->timeStamp(); 371 xmotion.x = postZoomPos.x(); 372 xmotion.y = postZoomPos.y(); 373 xmotion.x_root = event->screenX(); 374 xmotion.y_root = event->screenY(); 375 xmotion.state = inputEventState(event); 376 xmotion.is_hint = NotifyNormal; 377 xmotion.same_screen = true; 378} 379 380static void setXCrossingEventSpecificFields(XEvent* xEvent, MouseEvent* event, const IntPoint& postZoomPos, Frame* parentFrame) 381{ 382 XCrossingEvent& xcrossing = xEvent->xcrossing; 383 xcrossing.type = event->type() == eventNames().mouseoverEvent ? EnterNotify : LeaveNotify; 384 xcrossing.root = getRootWindow(parentFrame); 385 xcrossing.subwindow = 0; 386 xcrossing.time = event->timeStamp(); 387 xcrossing.x = postZoomPos.y(); 388 xcrossing.y = postZoomPos.x(); 389 xcrossing.x_root = event->screenX(); 390 xcrossing.y_root = event->screenY(); 391 xcrossing.state = inputEventState(event); 392 xcrossing.mode = NotifyNormal; 393 xcrossing.detail = NotifyDetailNone; 394 xcrossing.same_screen = true; 395 xcrossing.focus = false; 396} 397#endif 398 399void PluginView::handleMouseEvent(MouseEvent* event) 400{ 401 JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly); 402 403 if (m_isWindowed) 404 return; 405 406 if (event->type() == eventNames().mousedownEvent) { 407 if (Page* page = m_parentFrame->page()) 408 page->focusController()->setActive(true); 409 focusPluginElement(); 410 } 411 412 NPEvent xEvent; 413#if defined(XP_UNIX) 414 initXEvent(&xEvent); 415 416 IntPoint postZoomPos = roundedIntPoint(m_element->renderer()->absoluteToLocal(event->absoluteLocation())); 417 418 if (event->type() == eventNames().mousedownEvent || event->type() == eventNames().mouseupEvent) 419 setXButtonEventSpecificFields(&xEvent, event, postZoomPos, m_parentFrame.get()); 420 else if (event->type() == eventNames().mousemoveEvent) 421 setXMotionEventSpecificFields(&xEvent, event, postZoomPos, m_parentFrame.get()); 422 else if (event->type() == eventNames().mouseoutEvent || event->type() == eventNames().mouseoverEvent) { 423 setXCrossingEventSpecificFields(&xEvent, event, postZoomPos, m_parentFrame.get()); 424 425 // This is a work-around for plugins which change the cursor. When that happens we 426 // get out of sync with GDK somehow. Resetting the cursor here seems to fix the issue. 427 if (event->type() == eventNames().mouseoutEvent) 428 gdk_window_set_cursor(gtk_widget_get_window(m_parentFrame->view()->hostWindow()->platformPageClient()), 0); 429 } 430 else 431 return; 432#endif 433 434 if (!dispatchNPEvent(xEvent)) 435 event->setDefaultHandled(); 436} 437 438#if defined(XP_UNIX) 439void PluginView::handleFocusInEvent() 440{ 441 XEvent npEvent; 442 initXEvent(&npEvent); 443 444 XFocusChangeEvent& event = npEvent.xfocus; 445 event.type = 9; // FocusIn gets unset somewhere 446 event.mode = NotifyNormal; 447 event.detail = NotifyDetailNone; 448 449 dispatchNPEvent(npEvent); 450} 451 452void PluginView::handleFocusOutEvent() 453{ 454 XEvent npEvent; 455 initXEvent(&npEvent); 456 457 XFocusChangeEvent& event = npEvent.xfocus; 458 event.type = 10; // FocusOut gets unset somewhere 459 event.mode = NotifyNormal; 460 event.detail = NotifyDetailNone; 461 462 dispatchNPEvent(npEvent); 463} 464#endif 465 466void PluginView::setParent(ScrollView* parent) 467{ 468 Widget::setParent(parent); 469 470 if (parent) 471 init(); 472} 473 474void PluginView::setNPWindowRect(const IntRect&) 475{ 476 if (!m_isWindowed) 477 setNPWindowIfNeeded(); 478} 479 480void PluginView::setNPWindowIfNeeded() 481{ 482 if (!m_isStarted || !parent() || !m_plugin->pluginFuncs()->setwindow) 483 return; 484 485 // If the plugin didn't load sucessfully, no point in calling setwindow 486 if (m_status != PluginStatusLoadedSuccessfully) 487 return; 488 489 // On Unix, only call plugin's setwindow if it's full-page or windowed 490 if (m_mode != NP_FULL && m_mode != NP_EMBED) 491 return; 492 493 // Check if the platformPluginWidget still exists 494 if (m_isWindowed && !platformPluginWidget()) 495 return; 496 497 if (m_isWindowed) { 498 m_npWindow.x = m_windowRect.x(); 499 m_npWindow.y = m_windowRect.y(); 500 m_npWindow.width = m_windowRect.width(); 501 m_npWindow.height = m_windowRect.height(); 502 503 m_npWindow.clipRect.left = max(0, m_clipRect.x()); 504 m_npWindow.clipRect.top = max(0, m_clipRect.y()); 505 m_npWindow.clipRect.right = m_clipRect.x() + m_clipRect.width(); 506 m_npWindow.clipRect.bottom = m_clipRect.y() + m_clipRect.height(); 507 } else { 508 m_npWindow.x = 0; 509 m_npWindow.y = 0; 510 m_npWindow.width = m_windowRect.width(); 511 m_npWindow.height = m_windowRect.height(); 512 513 m_npWindow.clipRect.left = 0; 514 m_npWindow.clipRect.top = 0; 515 m_npWindow.clipRect.right = 0; 516 m_npWindow.clipRect.bottom = 0; 517 } 518 519 PluginView::setCurrentPluginView(this); 520 JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly); 521 setCallingPlugin(true); 522 m_plugin->pluginFuncs()->setwindow(m_instance, &m_npWindow); 523 setCallingPlugin(false); 524 PluginView::setCurrentPluginView(0); 525 526 if (!m_isWindowed) 527 return; 528 529#if defined(XP_UNIX) 530 // GtkXtBin will call gtk_widget_size_allocate, so we don't need to do it here. 531 if (!m_needsXEmbed) { 532 gtk_xtbin_set_position(GTK_XTBIN(platformPluginWidget()), m_windowRect.x(), m_windowRect.y()); 533 gtk_xtbin_resize(platformPluginWidget(), m_windowRect.width(), m_windowRect.height()); 534 return; 535 } 536#endif 537 538 GtkAllocation allocation = { m_windowRect.x(), m_windowRect.y(), m_windowRect.width(), m_windowRect.height() }; 539 540 // If the window has not been embedded yet (the plug added), we delay setting its allocation until 541 // that point. This fixes issues with some Java plugin instances not rendering immediately. 542 if (!m_plugAdded) { 543 m_delayedAllocation = allocation; 544 return; 545 } 546 gtk_widget_size_allocate(platformPluginWidget(), &allocation); 547} 548 549void PluginView::setParentVisible(bool visible) 550{ 551 if (isParentVisible() == visible) 552 return; 553 554 Widget::setParentVisible(visible); 555 556 if (isSelfVisible() && platformPluginWidget()) { 557 if (visible) 558 gtk_widget_show(platformPluginWidget()); 559 else 560 gtk_widget_hide(platformPluginWidget()); 561 } 562} 563 564NPError PluginView::handlePostReadFile(Vector<char>& outputBuffer, uint32_t filenameLength, const char* filenameBuffer) 565{ 566 // There doesn't seem to be any documentation about what encoding the filename 567 // is in, but most ports seem to assume UTF-8 here and the test plugin is definitely 568 // sending the path in UTF-8 encoding. 569 CString filename(filenameBuffer, filenameLength); 570 571 GRefPtr<GFile> file = adoptGRef(g_file_new_for_commandline_arg(filename.data())); 572 if (g_file_query_file_type(file.get(), G_FILE_QUERY_INFO_NONE, 0) != G_FILE_TYPE_REGULAR) 573 return NPERR_FILE_NOT_FOUND; 574 575 GRefPtr<GFileInfo> fileInfo = adoptGRef(g_file_query_info(file.get(), 576 G_FILE_ATTRIBUTE_STANDARD_SIZE, 577 G_FILE_QUERY_INFO_NONE, 578 0, 0)); 579 if (!fileInfo) 580 return NPERR_FILE_NOT_FOUND; 581 582 GRefPtr<GFileInputStream> inputStream = adoptGRef(g_file_read(file.get(), 0, 0)); 583 if (!inputStream) 584 return NPERR_FILE_NOT_FOUND; 585 586 outputBuffer.resize(g_file_info_get_size(fileInfo.get())); 587 gsize bytesRead = 0; 588 if (!g_input_stream_read_all(G_INPUT_STREAM(inputStream.get()), 589 outputBuffer.data(), outputBuffer.size(), &bytesRead, 0, 0)) 590 return NPERR_FILE_NOT_FOUND; 591 592 return NPERR_NO_ERROR; 593} 594 595bool PluginView::platformGetValueStatic(NPNVariable variable, void* value, NPError* result) 596{ 597 switch (variable) { 598 case NPNVToolkit: 599#if defined(XP_UNIX) 600 *static_cast<uint32_t*>(value) = 2; 601#else 602 *static_cast<uint32_t*>(value) = 0; 603#endif 604 *result = NPERR_NO_ERROR; 605 return true; 606 607 case NPNVSupportsXEmbedBool: 608#if defined(XP_UNIX) 609 *static_cast<NPBool*>(value) = true; 610#else 611 *static_cast<NPBool*>(value) = false; 612#endif 613 *result = NPERR_NO_ERROR; 614 return true; 615 616 case NPNVjavascriptEnabledBool: 617 *static_cast<NPBool*>(value) = true; 618 *result = NPERR_NO_ERROR; 619 return true; 620 621 case NPNVSupportsWindowless: 622#if defined(XP_UNIX) 623 *static_cast<NPBool*>(value) = true; 624#else 625 *static_cast<NPBool*>(value) = false; 626#endif 627 *result = NPERR_NO_ERROR; 628 return true; 629 630 default: 631 return false; 632 } 633} 634 635bool PluginView::platformGetValue(NPNVariable variable, void* value, NPError* result) 636{ 637 switch (variable) { 638 case NPNVxDisplay: 639#if defined(XP_UNIX) 640 if (m_needsXEmbed) 641 *(void **)value = (void *)GDK_DISPLAY_XDISPLAY(gdk_display_get_default()); 642 else 643 *(void **)value = (void *)GTK_XTBIN(platformPluginWidget())->xtclient.xtdisplay; 644 *result = NPERR_NO_ERROR; 645#else 646 *result = NPERR_GENERIC_ERROR; 647#endif 648 return true; 649 650#if defined(XP_UNIX) 651 case NPNVxtAppContext: 652 if (!m_needsXEmbed) { 653 *(void **)value = XtDisplayToApplicationContext (GTK_XTBIN(platformPluginWidget())->xtclient.xtdisplay); 654 655 *result = NPERR_NO_ERROR; 656 } else 657 *result = NPERR_GENERIC_ERROR; 658 return true; 659#endif 660 661 case NPNVnetscapeWindow: { 662 GdkWindow* gdkWindow = gtk_widget_get_window(m_parentFrame->view()->hostWindow()->platformPageClient()); 663#if defined(XP_UNIX) 664 *static_cast<Window*>(value) = GDK_WINDOW_XWINDOW(gdk_window_get_toplevel(gdkWindow)); 665#elif defined(GDK_WINDOWING_WIN32) 666 *static_cast<HGDIOBJ*>(value) = GDK_WINDOW_HWND(gdkWindow); 667#endif 668 *result = NPERR_NO_ERROR; 669 return true; 670 } 671 672 default: 673 return false; 674 } 675} 676 677void PluginView::invalidateRect(const IntRect& rect) 678{ 679 if (m_isWindowed) { 680 gtk_widget_queue_draw_area(GTK_WIDGET(platformPluginWidget()), rect.x(), rect.y(), rect.width(), rect.height()); 681 return; 682 } 683 684 invalidateWindowlessPluginRect(rect); 685} 686 687void PluginView::invalidateRect(NPRect* rect) 688{ 689 if (!rect) { 690 invalidate(); 691 return; 692 } 693 694 IntRect r(rect->left, rect->top, rect->right - rect->left, rect->bottom - rect->top); 695 invalidateWindowlessPluginRect(r); 696} 697 698void PluginView::invalidateRegion(NPRegion) 699{ 700 // TODO: optimize 701 invalidate(); 702} 703 704void PluginView::forceRedraw() 705{ 706 if (m_isWindowed) 707 gtk_widget_queue_draw(platformPluginWidget()); 708 else 709 gtk_widget_queue_draw(m_parentFrame->view()->hostWindow()->platformPageClient()); 710} 711 712#ifndef GDK_WINDOWING_WIN32 713static Display* getPluginDisplay() 714{ 715 // The plugin toolkit might have a different X connection open. Since we're 716 // a gdk/gtk app, we'll (probably?) have the same X connection as any gdk-based 717 // plugins, so we can return that. We might want to add other implementations here 718 // later. 719 720#if defined(XP_UNIX) 721 return GDK_DISPLAY_XDISPLAY(gdk_display_get_default()); 722#else 723 return 0; 724#endif 725} 726#endif 727 728#if defined(XP_UNIX) 729static void getVisualAndColormap(int depth, Visual** visual, Colormap* colormap) 730{ 731 *visual = 0; 732 *colormap = 0; 733 734 Display* display = GDK_DISPLAY_XDISPLAY(gdk_display_get_default()); 735 int rmaj, rmin; 736 if (depth == 32 && (!XRenderQueryVersion(display, &rmaj, &rmin) || (rmaj == 0 && rmin < 5))) 737 return; 738 739 XVisualInfo templ; 740 templ.screen = gdk_screen_get_number(gdk_screen_get_default()); 741 templ.depth = depth; 742 templ.c_class = TrueColor; 743 int nVisuals; 744 XVisualInfo* visualInfo = XGetVisualInfo(display, VisualScreenMask | VisualDepthMask | VisualClassMask, &templ, &nVisuals); 745 746 if (!nVisuals) 747 return; 748 749 if (depth == 32) { 750 for (int idx = 0; idx < nVisuals; ++idx) { 751 XRenderPictFormat* format = XRenderFindVisualFormat(display, visualInfo[idx].visual); 752 if (format->type == PictTypeDirect && format->direct.alphaMask) { 753 *visual = visualInfo[idx].visual; 754 break; 755 } 756 } 757 } else 758 *visual = visualInfo[0].visual; 759 760 XFree(visualInfo); 761 762 if (*visual) 763 *colormap = XCreateColormap(display, GDK_ROOT_WINDOW(), *visual, AllocNone); 764} 765#endif 766 767gboolean PluginView::plugRemovedCallback(GtkSocket* socket, PluginView* view) 768{ 769 view->m_plugAdded = false; 770 return TRUE; 771} 772 773void PluginView::plugAddedCallback(GtkSocket* socket, PluginView* view) 774{ 775 ASSERT(socket); 776 ASSERT(view); 777 778 view->m_plugAdded = true; 779 if (!view->m_delayedAllocation.isEmpty()) { 780 GtkAllocation allocation(view->m_delayedAllocation); 781 gtk_widget_size_allocate(GTK_WIDGET(socket), &allocation); 782 view->m_delayedAllocation.setSize(IntSize()); 783 } 784} 785 786bool PluginView::platformStart() 787{ 788 ASSERT(m_isStarted); 789 ASSERT(m_status == PluginStatusLoadedSuccessfully); 790 791#if defined(XP_UNIX) 792 if (m_plugin->pluginFuncs()->getvalue) { 793 PluginView::setCurrentPluginView(this); 794 JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly); 795 setCallingPlugin(true); 796 m_plugin->pluginFuncs()->getvalue(m_instance, NPPVpluginNeedsXEmbed, &m_needsXEmbed); 797 setCallingPlugin(false); 798 PluginView::setCurrentPluginView(0); 799 } 800#endif 801 802 if (m_isWindowed) { 803 GtkWidget* pageClient = m_parentFrame->view()->hostWindow()->platformPageClient(); 804#if defined(XP_UNIX) 805 if (m_needsXEmbed) { 806 // If our parent is not anchored the startup process will 807 // fail miserably for XEmbed plugins a bit later on when 808 // we try to get the ID of our window (since realize will 809 // fail), so let's just abort here. 810 if (!gtk_widget_get_parent(pageClient)) 811 return false; 812 813 m_plugAdded = false; 814 setPlatformWidget(gtk_socket_new()); 815 gtk_container_add(GTK_CONTAINER(pageClient), platformPluginWidget()); 816 g_signal_connect(platformPluginWidget(), "plug-added", G_CALLBACK(PluginView::plugAddedCallback), this); 817 g_signal_connect(platformPluginWidget(), "plug-removed", G_CALLBACK(PluginView::plugRemovedCallback), this); 818 } else 819 setPlatformWidget(gtk_xtbin_new(pageClient, 0)); 820#else 821 setPlatformWidget(gtk_socket_new()); 822 gtk_container_add(GTK_CONTAINER(pageClient), platformPluginWidget()); 823#endif 824 } else { 825 setPlatformWidget(0); 826#if defined(XP_UNIX) 827 m_pluginDisplay = getPluginDisplay(); 828#endif 829 } 830 831 show(); 832 833#if defined(XP_UNIX) 834 NPSetWindowCallbackStruct* ws = new NPSetWindowCallbackStruct(); 835 ws->type = 0; 836#endif 837 838 if (m_isWindowed) { 839 m_npWindow.type = NPWindowTypeWindow; 840#if defined(XP_UNIX) 841 if (m_needsXEmbed) { 842 GtkWidget* widget = platformPluginWidget(); 843 gtk_widget_realize(widget); 844 m_npWindow.window = (void*)gtk_socket_get_id(GTK_SOCKET(platformPluginWidget())); 845 GdkWindow* window = gtk_widget_get_window(widget); 846 ws->display = GDK_WINDOW_XDISPLAY(window); 847 ws->visual = GDK_VISUAL_XVISUAL(gdk_window_get_visual(window)); 848 ws->depth = gdk_visual_get_depth(gdk_window_get_visual(window)); 849 ws->colormap = XCreateColormap(ws->display, GDK_ROOT_WINDOW(), ws->visual, AllocNone); 850 } else { 851 m_npWindow.window = (void*)GTK_XTBIN(platformPluginWidget())->xtwindow; 852 ws->display = GTK_XTBIN(platformPluginWidget())->xtdisplay; 853 ws->visual = GTK_XTBIN(platformPluginWidget())->xtclient.xtvisual; 854 ws->depth = GTK_XTBIN(platformPluginWidget())->xtclient.xtdepth; 855 ws->colormap = GTK_XTBIN(platformPluginWidget())->xtclient.xtcolormap; 856 } 857 XFlush (ws->display); 858#elif defined(GDK_WINDOWING_WIN32) 859 m_npWindow.window = (void*)GDK_WINDOW_HWND(gtk_widget_get_window(platformPluginWidget())); 860#endif 861 } else { 862 m_npWindow.type = NPWindowTypeDrawable; 863 m_npWindow.window = 0; // Not used? 864 865#if defined(XP_UNIX) 866 GdkScreen* gscreen = gdk_screen_get_default(); 867 GdkVisual* gvisual = gdk_screen_get_system_visual(gscreen); 868 869 if (gdk_visual_get_depth(gvisual) == 32 || !m_plugin->quirks().contains(PluginQuirkRequiresDefaultScreenDepth)) { 870 getVisualAndColormap(32, &m_visual, &m_colormap); 871 ws->depth = 32; 872 } 873 874 if (!m_visual) { 875 getVisualAndColormap(gdk_visual_get_depth(gvisual), &m_visual, &m_colormap); 876 ws->depth = gdk_visual_get_depth(gvisual); 877 } 878 879 ws->display = GDK_DISPLAY_XDISPLAY(gdk_display_get_default()); 880 ws->visual = m_visual; 881 ws->colormap = m_colormap; 882 883 m_npWindow.x = 0; 884 m_npWindow.y = 0; 885 m_npWindow.width = -1; 886 m_npWindow.height = -1; 887#else 888 notImplemented(); 889 m_status = PluginStatusCanNotLoadPlugin; 890 return false; 891#endif 892 } 893 894#if defined(XP_UNIX) 895 m_npWindow.ws_info = ws; 896#endif 897 898 // TODO remove in favor of null events, like mac port? 899 if (!(m_plugin->quirks().contains(PluginQuirkDeferFirstSetWindowCall))) 900 updatePluginWidget(); // was: setNPWindowIfNeeded(), but this doesn't produce 0x0 rects at first go 901 902 return true; 903} 904 905void PluginView::platformDestroy() 906{ 907#if defined(XP_UNIX) 908 if (m_drawable) { 909 XFreePixmap(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), m_drawable); 910 m_drawable = 0; 911 } 912#endif 913} 914 915void PluginView::halt() 916{ 917} 918 919void PluginView::restart() 920{ 921} 922 923} // namespace WebCore 924