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