PluginViewGtk.cpp revision 1cbdecfa9fc428ac2d8aca0fa91c9580b3d57353
1/* 2 * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. 3 * Copyright (C) 2008 Collabora Ltd. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include "config.h" 28#include "PluginView.h" 29 30#include "Document.h" 31#include "DocumentLoader.h" 32#include "Element.h" 33#include "FrameLoader.h" 34#include "FrameLoadRequest.h" 35#include "FrameTree.h" 36#include "Frame.h" 37#include "FrameView.h" 38#include "GraphicsContext.h" 39#include "Image.h" 40#include "HTMLNames.h" 41#include "HTMLPlugInElement.h" 42#include "KeyboardEvent.h" 43#include "MouseEvent.h" 44#include "NotImplemented.h" 45#include "Page.h" 46#include "PlatformMouseEvent.h" 47#include "PluginDebug.h" 48#include "PluginPackage.h" 49#include "RenderLayer.h" 50#include "Settings.h" 51#include "JSDOMBinding.h" 52#include "ScriptController.h" 53#include "npruntime_impl.h" 54#include "runtime.h" 55#include "runtime_root.h" 56#include <runtime/JSLock.h> 57#include <runtime/JSValue.h> 58 59#include <gdkconfig.h> 60#include <gtk/gtk.h> 61 62#if PLATFORM(X11) 63#include "gtk2xtbin.h" 64#include <gdk/gdkx.h> 65#endif 66#ifdef GDK_WINDOWING_WIN32 67#include "PluginMessageThrottlerWin.h" 68#include <gdk/gdkwin32.h> 69#endif 70 71using JSC::ExecState; 72using JSC::Interpreter; 73using JSC::JSLock; 74using JSC::JSObject; 75using JSC::UString; 76 77using std::min; 78 79using namespace WTF; 80 81namespace WebCore { 82 83using namespace HTMLNames; 84 85void PluginView::updatePluginWidget() const 86{ 87 if (!parent() || !m_isWindowed) 88 return; 89 90 ASSERT(parent()->isFrameView()); 91 FrameView* frameView = static_cast<FrameView*>(parent()); 92 93 IntRect oldWindowRect = m_windowRect; 94 IntRect oldClipRect = m_clipRect; 95 96 m_windowRect = IntRect(frameView->contentsToWindow(frameRect().location()), frameRect().size()); 97 m_clipRect = windowClipRect(); 98 m_clipRect.move(-m_windowRect.x(), -m_windowRect.y()); 99 100 GtkAllocation allocation = { m_windowRect.x(), m_windowRect.y(), m_windowRect.width(), m_windowRect.height() }; 101 if (platformPluginWidget()) { 102 gtk_widget_size_allocate(platformPluginWidget(), &allocation); 103#if PLATFORM(X11) 104 if (!m_needsXEmbed) { 105 gtk_xtbin_set_position(GTK_XTBIN(platformPluginWidget()), m_windowRect.x(), m_windowRect.y()); 106 gtk_xtbin_resize(platformPluginWidget(), m_windowRect.width(), m_windowRect.height()); 107 } 108#endif 109 } 110} 111 112void PluginView::setFocus() 113{ 114 if (platformPluginWidget()) 115 gtk_widget_grab_focus(platformPluginWidget()); 116 117 Widget::setFocus(); 118} 119 120void PluginView::show() 121{ 122 setSelfVisible(true); 123 124 if (isParentVisible() && platformPluginWidget()) 125 gtk_widget_show(platformPluginWidget()); 126 127 Widget::show(); 128} 129 130void PluginView::hide() 131{ 132 setSelfVisible(false); 133 134 if (isParentVisible() && platformPluginWidget()) 135 gtk_widget_hide(platformPluginWidget()); 136 137 Widget::hide(); 138} 139 140void PluginView::paint(GraphicsContext* context, const IntRect& rect) 141{ 142 if (!m_isStarted) { 143 // Draw the "missing plugin" image 144 //paintMissingPluginIcon(context, rect); 145 return; 146 } 147 148 if (m_isWindowed || context->paintingDisabled()) 149 return; 150 151 NPEvent npEvent; 152 /* Need to synthesize Xevents here */ 153 154 m_npWindow.type = NPWindowTypeDrawable; 155 156 ASSERT(parent()->isFrameView()); 157 158 if (m_plugin->pluginFuncs()->event) { 159 JSC::JSLock::DropAllLocks dropAllLocks(false); 160 m_plugin->pluginFuncs()->event(m_instance, &npEvent); 161 } 162 163 setNPWindowRect(frameRect()); 164} 165 166void PluginView::handleKeyboardEvent(KeyboardEvent* event) 167{ 168 NPEvent npEvent; 169 170 /* FIXME: Synthesize an XEvent to pass through */ 171 172 JSC::JSLock::DropAllLocks dropAllLocks(false); 173 if (!m_plugin->pluginFuncs()->event(m_instance, &npEvent)) 174 event->setDefaultHandled(); 175} 176 177void PluginView::handleMouseEvent(MouseEvent* event) 178{ 179 NPEvent npEvent; 180 181 if (!m_isWindowed) 182 return; 183 184 /* FIXME: Synthesize an XEvent to pass through */ 185 IntPoint p = static_cast<FrameView*>(parent())->contentsToWindow(IntPoint(event->pageX(), event->pageY())); 186 187 JSC::JSLock::DropAllLocks dropAllLocks(false); 188 if (!m_plugin->pluginFuncs()->event(m_instance, &npEvent)) 189 event->setDefaultHandled(); 190} 191 192void PluginView::setParent(ScrollView* parent) 193{ 194 Widget::setParent(parent); 195 196 if (parent) 197 init(); 198 else { 199 if (!platformPluginWidget()) 200 return; 201 } 202} 203 204void PluginView::setNPWindowRect(const IntRect& rect) 205{ 206 if (!m_isStarted || !parent()) 207 return; 208 209 IntPoint p = static_cast<FrameView*>(parent())->contentsToWindow(rect.location()); 210 m_npWindow.x = p.x(); 211 m_npWindow.y = p.y(); 212 213 m_npWindow.width = rect.width(); 214 m_npWindow.height = rect.height(); 215 216 m_npWindow.clipRect.left = 0; 217 m_npWindow.clipRect.top = 0; 218 m_npWindow.clipRect.right = rect.width(); 219 m_npWindow.clipRect.bottom = rect.height(); 220 221 if (m_npWindow.x < 0 || m_npWindow.y < 0 || 222 m_npWindow.width <= 0 || m_npWindow.height <= 0) 223 return; 224 225 if (m_plugin->pluginFuncs()->setwindow) { 226 PluginView::setCurrentPluginView(this); 227 JSC::JSLock::DropAllLocks dropAllLocks(false); 228 setCallingPlugin(true); 229 m_plugin->pluginFuncs()->setwindow(m_instance, &m_npWindow); 230 setCallingPlugin(false); 231 PluginView::setCurrentPluginView(0); 232 233 if (!m_isWindowed) 234 return; 235 236 ASSERT(platformPluginWidget()); 237 } 238} 239 240void PluginView::setParentVisible(bool visible) 241{ 242 if (isParentVisible() == visible) 243 return; 244 245 Widget::setParentVisible(visible); 246 247 if (isSelfVisible() && platformPluginWidget()) { 248 if (visible) 249 gtk_widget_show(platformPluginWidget()); 250 else 251 gtk_widget_hide(platformPluginWidget()); 252 } 253} 254 255void PluginView::stop() 256{ 257 if (!m_isStarted) 258 return; 259 260 HashSet<RefPtr<PluginStream> > streams = m_streams; 261 HashSet<RefPtr<PluginStream> >::iterator end = streams.end(); 262 for (HashSet<RefPtr<PluginStream> >::iterator it = streams.begin(); it != end; ++it) { 263 (*it)->stop(); 264 disconnectStream((*it).get()); 265 } 266 267 ASSERT(m_streams.isEmpty()); 268 269 m_isStarted = false; 270 JSC::JSLock::DropAllLocks dropAllLocks(false); 271 272 // Clear the window 273 m_npWindow.window = 0; 274 if (m_plugin->pluginFuncs()->setwindow && !m_plugin->quirks().contains(PluginQuirkDontSetNullWindowHandleOnDestroy)) { 275 PluginView::setCurrentPluginView(this); 276 setCallingPlugin(true); 277 m_plugin->pluginFuncs()->setwindow(m_instance, &m_npWindow); 278 setCallingPlugin(false); 279 PluginView::setCurrentPluginView(0); 280 } 281 282#ifdef XP_UNIX 283 if (m_isWindowed && m_npWindow.ws_info) 284 delete (NPSetWindowCallbackStruct *)m_npWindow.ws_info; 285 m_npWindow.ws_info = 0; 286#endif 287 288 // Destroy the plugin 289 { 290 PluginView::setCurrentPluginView(this); 291 setCallingPlugin(true); 292 m_plugin->pluginFuncs()->destroy(m_instance, 0); 293 setCallingPlugin(false); 294 PluginView::setCurrentPluginView(0); 295 } 296 297 m_instance->pdata = 0; 298} 299 300static const char* MozillaUserAgent = "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1) Gecko/20061010 Firefox/2.0"; 301 302const char* PluginView::userAgent() 303{ 304 if (m_plugin->quirks().contains(PluginQuirkWantsMozillaUserAgent)) 305 return MozillaUserAgent; 306 307 if (m_userAgent.isNull()) 308 m_userAgent = m_parentFrame->loader()->userAgent(m_url).utf8(); 309 310 return m_userAgent.data(); 311} 312 313const char* PluginView::userAgentStatic() 314{ 315 //FIXME - Lie and say we are Mozilla 316 return MozillaUserAgent; 317} 318 319NPError PluginView::handlePostReadFile(Vector<char>& buffer, uint32 len, const char* buf) 320{ 321 String filename(buf, len); 322 323 if (filename.startsWith("file:///")) 324 filename = filename.substring(8); 325 326 // Get file info 327 if (!g_file_test ((filename.utf8()).data(), (GFileTest)(G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR))) 328 return NPERR_FILE_NOT_FOUND; 329 330 //FIXME - read the file data into buffer 331 FILE* fileHandle = fopen((filename.utf8()).data(), "r"); 332 333 if (fileHandle == 0) 334 return NPERR_FILE_NOT_FOUND; 335 336 //buffer.resize(); 337 338 int bytesRead = fread(buffer.data(), 1, 0, fileHandle); 339 340 fclose(fileHandle); 341 342 if (bytesRead <= 0) 343 return NPERR_FILE_NOT_FOUND; 344 345 return NPERR_NO_ERROR; 346} 347 348NPError PluginView::getValueStatic(NPNVariable variable, void* value) 349{ 350 switch (variable) { 351 case NPNVToolkit: 352#if PLATFORM(GTK) 353 *((uint32 *)value) = 2; 354#else 355 *((uint32 *)value) = 0; 356#endif 357 return NPERR_NO_ERROR; 358 359 case NPNVSupportsXEmbedBool: 360#if PLATFORM(X11) 361 *((uint32 *)value) = true; 362#else 363 *((uint32 *)value) = false; 364#endif 365 return NPERR_NO_ERROR; 366 367 case NPNVjavascriptEnabledBool: 368 *((uint32 *)value) = true; 369 return NPERR_NO_ERROR; 370 371 default: 372 return NPERR_GENERIC_ERROR; 373 } 374} 375 376NPError PluginView::getValue(NPNVariable variable, void* value) 377{ 378 switch (variable) { 379 case NPNVxDisplay: 380#if PLATFORM(X11) 381 if (m_needsXEmbed) 382 *(void **)value = (void *)GDK_DISPLAY(); 383 else 384 *(void **)value = (void *)GTK_XTBIN(platformPluginWidget())->xtclient.xtdisplay; 385 return NPERR_NO_ERROR; 386#else 387 return NPERR_GENERIC_ERROR; 388#endif 389 390#if PLATFORM(X11) 391 case NPNVxtAppContext: 392 if (!m_needsXEmbed) { 393 *(void **)value = XtDisplayToApplicationContext (GTK_XTBIN(platformPluginWidget())->xtclient.xtdisplay); 394 395 return NPERR_NO_ERROR; 396 } else 397 return NPERR_GENERIC_ERROR; 398#endif 399 400#if ENABLE(NETSCAPE_PLUGIN_API) 401 case NPNVWindowNPObject: { 402 if (m_isJavaScriptPaused) 403 return NPERR_GENERIC_ERROR; 404 405 NPObject* windowScriptObject = m_parentFrame->script()->windowScriptNPObject(); 406 407 // Return value is expected to be retained, as described here: <http://www.mozilla.org/projects/plugin/npruntime.html> 408 if (windowScriptObject) 409 _NPN_RetainObject(windowScriptObject); 410 411 void** v = (void**)value; 412 *v = windowScriptObject; 413 414 return NPERR_NO_ERROR; 415 } 416 417 case NPNVPluginElementNPObject: { 418 if (m_isJavaScriptPaused) 419 return NPERR_GENERIC_ERROR; 420 421 NPObject* pluginScriptObject = 0; 422 423 if (m_element->hasTagName(appletTag) || m_element->hasTagName(embedTag) || m_element->hasTagName(objectTag)) 424 pluginScriptObject = static_cast<HTMLPlugInElement*>(m_element)->getNPObject(); 425 426 // Return value is expected to be retained, as described here: <http://www.mozilla.org/projects/plugin/npruntime.html> 427 if (pluginScriptObject) 428 _NPN_RetainObject(pluginScriptObject); 429 430 void** v = (void**)value; 431 *v = pluginScriptObject; 432 433 return NPERR_NO_ERROR; 434 } 435#endif 436 437 case NPNVnetscapeWindow: { 438#if PLATFORM(X11) 439 void* w = reinterpret_cast<void*>(value); 440 *((XID *)w) = GDK_WINDOW_XWINDOW(m_parentFrame->view()->hostWindow()->platformWindow()->window); 441#endif 442#ifdef GDK_WINDOWING_WIN32 443 HGDIOBJ* w = reinterpret_cast<HGDIOBJ*>(value); 444 *w = GDK_WINDOW_HWND(m_parentFrame->view()->hostWindow()->platformWindow()->window); 445#endif 446 return NPERR_NO_ERROR; 447 } 448 449 default: 450 return getValueStatic(variable, value); 451 } 452} 453 454void PluginView::invalidateRect(const IntRect& rect) 455{ 456 if (m_isWindowed) { 457 gtk_widget_queue_draw_area(GTK_WIDGET(platformPluginWidget()), rect.x(), rect.y(), rect.width(), rect.height()); 458 return; 459 } 460 461 invalidateWindowlessPluginRect(rect); 462} 463 464void PluginView::invalidateRect(NPRect* rect) 465{ 466 if (!rect) { 467 invalidate(); 468 return; 469 } 470 471 IntRect r(rect->left, rect->top, rect->right - rect->left, rect->bottom - rect->top); 472 invalidateRect(r); 473} 474 475void PluginView::forceRedraw() 476{ 477 if (m_isWindowed) 478 gtk_widget_queue_draw(platformPluginWidget()); 479 else 480 gtk_widget_queue_draw(m_parentFrame->view()->hostWindow()->platformWindow()); 481} 482 483PluginView::~PluginView() 484{ 485 stop(); 486 487 deleteAllValues(m_requests); 488 489 freeStringArray(m_paramNames, m_paramCount); 490 freeStringArray(m_paramValues, m_paramCount); 491 492 m_parentFrame->script()->cleanupScriptObjectsForPlugin(this); 493 494 if (m_plugin && !(m_plugin->quirks().contains(PluginQuirkDontUnloadPlugin))) 495 m_plugin->unload(); 496} 497 498static gboolean 499plug_removed_cb(GtkSocket *socket, gpointer) 500{ 501 return TRUE; 502} 503 504void PluginView::init() 505{ 506 if (m_haveInitialized) 507 return; 508 m_haveInitialized = true; 509 510 if (!m_plugin) { 511 ASSERT(m_status == PluginStatusCanNotFindPlugin); 512 return; 513 } 514 515 if (!m_plugin->load()) { 516 m_plugin = 0; 517 m_status = PluginStatusCanNotLoadPlugin; 518 return; 519 } 520 521 if (!start()) { 522 m_status = PluginStatusCanNotLoadPlugin; 523 return; 524 } 525 526 if (m_plugin->pluginFuncs()->getvalue) { 527 PluginView::setCurrentPluginView(this); 528 JSC::JSLock::DropAllLocks dropAllLocks(false); 529 setCallingPlugin(true); 530 m_plugin->pluginFuncs()->getvalue(m_instance, NPPVpluginNeedsXEmbed, &m_needsXEmbed); 531 setCallingPlugin(false); 532 PluginView::setCurrentPluginView(0); 533 } 534 535#if PLATFORM(X11) 536 if (m_needsXEmbed) { 537 setPlatformWidget(gtk_socket_new()); 538 gtk_container_add(GTK_CONTAINER(m_parentFrame->view()->hostWindow()->platformWindow()), platformPluginWidget()); 539 g_signal_connect(platformPluginWidget(), "plug_removed", G_CALLBACK(plug_removed_cb), NULL); 540 } else if (m_isWindowed) 541 setPlatformWidget(gtk_xtbin_new(m_parentFrame->view()->hostWindow()->platformWindow()->window, 0)); 542#else 543 setPlatformWidget(gtk_socket_new()); 544 gtk_container_add(GTK_CONTAINER(m_parentFrame->view()->hostWindow()->platformWindow()), platformPluginWidget()); 545#endif 546 show(); 547 548 if (m_isWindowed) { 549 m_npWindow.type = NPWindowTypeWindow; 550#if PLATFORM(X11) 551 NPSetWindowCallbackStruct *ws = new NPSetWindowCallbackStruct(); 552 553 ws->type = 0; 554 555 if (m_needsXEmbed) { 556 gtk_widget_realize(platformPluginWidget()); 557 m_npWindow.window = (void*)gtk_socket_get_id(GTK_SOCKET(platformPluginWidget())); 558 ws->display = GDK_WINDOW_XDISPLAY(platformPluginWidget()->window); 559 ws->visual = GDK_VISUAL_XVISUAL(gdk_drawable_get_visual(GDK_DRAWABLE(platformPluginWidget()->window))); 560 ws->depth = gdk_drawable_get_visual(GDK_DRAWABLE(platformPluginWidget()->window))->depth; 561 ws->colormap = GDK_COLORMAP_XCOLORMAP(gdk_drawable_get_colormap(GDK_DRAWABLE(platformPluginWidget()->window))); 562 } else { 563 m_npWindow.window = (void*)GTK_XTBIN(platformPluginWidget())->xtwindow; 564 ws->display = GTK_XTBIN(platformPluginWidget())->xtdisplay; 565 ws->visual = GTK_XTBIN(platformPluginWidget())->xtclient.xtvisual; 566 ws->depth = GTK_XTBIN(platformPluginWidget())->xtclient.xtdepth; 567 ws->colormap = GTK_XTBIN(platformPluginWidget())->xtclient.xtcolormap; 568 } 569 XFlush (ws->display); 570 571 m_npWindow.ws_info = ws; 572#elif defined(GDK_WINDOWING_WIN32) 573 m_npWindow.window = (void*)GDK_WINDOW_HWND(platformPluginWidget()->window); 574#endif 575 } else { 576 m_npWindow.type = NPWindowTypeDrawable; 577 m_npWindow.window = 0; 578 } 579 580 if (!(m_plugin->quirks().contains(PluginQuirkDeferFirstSetWindowCall))) 581 setNPWindowRect(frameRect()); 582 583 m_status = PluginStatusLoadedSuccessfully; 584} 585 586} // namespace WebCore 587