PluginViewGtk.cpp revision 643ca7872b450ea4efacab6188849e5aac2ba161
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 "Page.h" 45#include "PlatformMouseEvent.h" 46#include "PluginDebug.h" 47#include "PluginMainThreadScheduler.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 defined(XP_UNIX) 63#include "gtk2xtbin.h" 64#include <gdk/gdkx.h> 65#elif defined(GDK_WINDOWING_WIN32) 66#include "PluginMessageThrottlerWin.h" 67#include <gdk/gdkwin32.h> 68#endif 69 70using JSC::ExecState; 71using JSC::Interpreter; 72using JSC::JSLock; 73using JSC::JSObject; 74using JSC::UString; 75 76using std::min; 77 78using namespace WTF; 79 80namespace WebCore { 81 82using namespace HTMLNames; 83 84bool PluginView::dispatchNPEvent(NPEvent& event) 85{ 86 // sanity check 87 if (!m_plugin->pluginFuncs()->event) 88 return false; 89 90 PluginView::setCurrentPluginView(this); 91 JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly); 92 setCallingPlugin(true); 93 94 bool accepted = m_plugin->pluginFuncs()->event(m_instance, &event); 95 96 setCallingPlugin(false); 97 PluginView::setCurrentPluginView(0); 98 return accepted; 99} 100 101void PluginView::updatePluginWidget() 102{ 103 if (!parent() || !m_isWindowed) 104 return; 105 106 ASSERT(parent()->isFrameView()); 107 FrameView* frameView = static_cast<FrameView*>(parent()); 108 109 IntRect oldWindowRect = m_windowRect; 110 IntRect oldClipRect = m_clipRect; 111 112 m_windowRect = IntRect(frameView->contentsToWindow(frameRect().location()), frameRect().size()); 113 m_clipRect = windowClipRect(); 114 m_clipRect.move(-m_windowRect.x(), -m_windowRect.y()); 115 116 if (platformPluginWidget() && (m_windowRect != oldWindowRect || m_clipRect != oldClipRect)) 117 setNPWindowIfNeeded(); 118} 119 120void PluginView::setFocus() 121{ 122 if (platformPluginWidget()) 123 gtk_widget_grab_focus(platformPluginWidget()); 124 125 Widget::setFocus(); 126} 127 128void PluginView::show() 129{ 130 setSelfVisible(true); 131 132 if (isParentVisible() && platformPluginWidget()) 133 gtk_widget_show(platformPluginWidget()); 134 135 Widget::show(); 136} 137 138void PluginView::hide() 139{ 140 setSelfVisible(false); 141 142 if (isParentVisible() && platformPluginWidget()) 143 gtk_widget_hide(platformPluginWidget()); 144 145 Widget::hide(); 146} 147 148void PluginView::paint(GraphicsContext* context, const IntRect& rect) 149{ 150 if (!m_isStarted) { 151 paintMissingPluginIcon(context, rect); 152 return; 153 } 154 155 if (context->paintingDisabled()) 156 return; 157 158 setNPWindowIfNeeded(); 159 160 if (m_isWindowed) 161 return; 162 163 NPEvent npEvent; 164 /* Need to synthesize Xevents here */ 165 166 m_npWindow.type = NPWindowTypeDrawable; 167 168 ASSERT(parent()->isFrameView()); 169 170 if (!dispatchNPEvent(npEvent)) 171 LOG(Events, "PluginView::paint(): Paint event not accepted"); 172} 173 174void PluginView::handleKeyboardEvent(KeyboardEvent* event) 175{ 176 NPEvent npEvent; 177 178 /* FIXME: Synthesize an XEvent to pass through */ 179 180 JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly); 181 if (!dispatchNPEvent(npEvent)) 182 event->setDefaultHandled(); 183} 184 185void PluginView::handleMouseEvent(MouseEvent* event) 186{ 187 NPEvent npEvent; 188 189 if (!m_isWindowed) 190 return; 191 192 /* FIXME: Synthesize an XEvent to pass through */ 193 IntPoint p = static_cast<FrameView*>(parent())->contentsToWindow(IntPoint(event->pageX(), event->pageY())); 194 195 JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly); 196 if (!dispatchNPEvent(npEvent)) 197 event->setDefaultHandled(); 198} 199 200void PluginView::setParent(ScrollView* parent) 201{ 202 Widget::setParent(parent); 203 204 if (parent) 205 init(); 206} 207 208void PluginView::setNPWindowRect(const IntRect&) 209{ 210 setNPWindowIfNeeded(); 211} 212 213void PluginView::setNPWindowIfNeeded() 214{ 215 if (!m_isStarted || !parent() || !m_plugin->pluginFuncs()->setwindow) 216 return; 217 218 m_npWindow.x = m_windowRect.x(); 219 m_npWindow.y = m_windowRect.y(); 220 m_npWindow.width = m_windowRect.width(); 221 m_npWindow.height = m_windowRect.height(); 222 223 m_npWindow.clipRect.left = m_clipRect.x(); 224 m_npWindow.clipRect.top = m_clipRect.y(); 225 m_npWindow.clipRect.right = m_clipRect.width(); 226 m_npWindow.clipRect.bottom = m_clipRect.height(); 227 228 GtkAllocation allocation = { m_windowRect.x(), m_windowRect.y(), m_windowRect.width(), m_windowRect.height() }; 229 gtk_widget_size_allocate(platformPluginWidget(), &allocation); 230#if defined(XP_UNIX) 231 if (!m_needsXEmbed) { 232 gtk_xtbin_set_position(GTK_XTBIN(platformPluginWidget()), m_windowRect.x(), m_windowRect.y()); 233 gtk_xtbin_resize(platformPluginWidget(), m_windowRect.width(), m_windowRect.height()); 234 } 235#endif 236 237 PluginView::setCurrentPluginView(this); 238 JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly); 239 setCallingPlugin(true); 240 m_plugin->pluginFuncs()->setwindow(m_instance, &m_npWindow); 241 setCallingPlugin(false); 242 PluginView::setCurrentPluginView(0); 243} 244 245void PluginView::setParentVisible(bool visible) 246{ 247 if (isParentVisible() == visible) 248 return; 249 250 Widget::setParentVisible(visible); 251 252 if (isSelfVisible() && platformPluginWidget()) { 253 if (visible) 254 gtk_widget_show(platformPluginWidget()); 255 else 256 gtk_widget_hide(platformPluginWidget()); 257 } 258} 259 260NPError PluginView::handlePostReadFile(Vector<char>& buffer, uint32 len, const char* buf) 261{ 262 String filename(buf, len); 263 264 if (filename.startsWith("file:///")) 265 filename = filename.substring(8); 266 267 // Get file info 268 if (!g_file_test ((filename.utf8()).data(), (GFileTest)(G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR))) 269 return NPERR_FILE_NOT_FOUND; 270 271 //FIXME - read the file data into buffer 272 FILE* fileHandle = fopen((filename.utf8()).data(), "r"); 273 274 if (fileHandle == 0) 275 return NPERR_FILE_NOT_FOUND; 276 277 //buffer.resize(); 278 279 int bytesRead = fread(buffer.data(), 1, 0, fileHandle); 280 281 fclose(fileHandle); 282 283 if (bytesRead <= 0) 284 return NPERR_FILE_NOT_FOUND; 285 286 return NPERR_NO_ERROR; 287} 288 289NPError PluginView::getValueStatic(NPNVariable variable, void* value) 290{ 291 LOG(Plugins, "PluginView::getValueStatic(%s)", prettyNameForNPNVariable(variable).data()); 292 293 switch (variable) { 294 case NPNVToolkit: 295#if defined(XP_UNIX) 296 *static_cast<uint32*>(value) = 2; 297#else 298 *static_cast<uint32*>(value) = 0; 299#endif 300 return NPERR_NO_ERROR; 301 302 case NPNVSupportsXEmbedBool: 303#if defined(XP_UNIX) 304 *static_cast<NPBool*>(value) = true; 305#else 306 *static_cast<NPBool*>(value) = false; 307#endif 308 return NPERR_NO_ERROR; 309 310 case NPNVjavascriptEnabledBool: 311 *static_cast<NPBool*>(value) = true; 312 return NPERR_NO_ERROR; 313 314 default: 315 return NPERR_GENERIC_ERROR; 316 } 317} 318 319NPError PluginView::getValue(NPNVariable variable, void* value) 320{ 321 LOG(Plugins, "PluginView::getValue(%s)", prettyNameForNPNVariable(variable).data()); 322 323 switch (variable) { 324 case NPNVxDisplay: 325#if defined(XP_UNIX) 326 if (m_needsXEmbed) 327 *(void **)value = (void *)GDK_DISPLAY(); 328 else 329 *(void **)value = (void *)GTK_XTBIN(platformPluginWidget())->xtclient.xtdisplay; 330 return NPERR_NO_ERROR; 331#else 332 return NPERR_GENERIC_ERROR; 333#endif 334 335#if defined(XP_UNIX) 336 case NPNVxtAppContext: 337 if (!m_needsXEmbed) { 338 *(void **)value = XtDisplayToApplicationContext (GTK_XTBIN(platformPluginWidget())->xtclient.xtdisplay); 339 340 return NPERR_NO_ERROR; 341 } else 342 return NPERR_GENERIC_ERROR; 343#endif 344 345#if ENABLE(NETSCAPE_PLUGIN_API) 346 case NPNVWindowNPObject: { 347 if (m_isJavaScriptPaused) 348 return NPERR_GENERIC_ERROR; 349 350 NPObject* windowScriptObject = m_parentFrame->script()->windowScriptNPObject(); 351 352 // Return value is expected to be retained, as described here: <http://www.mozilla.org/projects/plugin/npruntime.html> 353 if (windowScriptObject) 354 _NPN_RetainObject(windowScriptObject); 355 356 void** v = (void**)value; 357 *v = windowScriptObject; 358 359 return NPERR_NO_ERROR; 360 } 361 362 case NPNVPluginElementNPObject: { 363 if (m_isJavaScriptPaused) 364 return NPERR_GENERIC_ERROR; 365 366 NPObject* pluginScriptObject = 0; 367 368 if (m_element->hasTagName(appletTag) || m_element->hasTagName(embedTag) || m_element->hasTagName(objectTag)) 369 pluginScriptObject = static_cast<HTMLPlugInElement*>(m_element)->getNPObject(); 370 371 // Return value is expected to be retained, as described here: <http://www.mozilla.org/projects/plugin/npruntime.html> 372 if (pluginScriptObject) 373 _NPN_RetainObject(pluginScriptObject); 374 375 void** v = (void**)value; 376 *v = pluginScriptObject; 377 378 return NPERR_NO_ERROR; 379 } 380#endif 381 382 case NPNVnetscapeWindow: { 383#if defined(XP_UNIX) 384 void* w = reinterpret_cast<void*>(value); 385 *((XID *)w) = GDK_WINDOW_XWINDOW(m_parentFrame->view()->hostWindow()->platformPageClient()->window); 386#endif 387#ifdef GDK_WINDOWING_WIN32 388 HGDIOBJ* w = reinterpret_cast<HGDIOBJ*>(value); 389 *w = GDK_WINDOW_HWND(m_parentFrame->view()->hostWindow()->platformPageClient()->window); 390#endif 391 return NPERR_NO_ERROR; 392 } 393 394 default: 395 return getValueStatic(variable, value); 396 } 397} 398 399void PluginView::invalidateRect(const IntRect& rect) 400{ 401 if (m_isWindowed) { 402 gtk_widget_queue_draw_area(GTK_WIDGET(platformPluginWidget()), rect.x(), rect.y(), rect.width(), rect.height()); 403 return; 404 } 405 406 invalidateWindowlessPluginRect(rect); 407} 408 409void PluginView::invalidateRect(NPRect* rect) 410{ 411 if (!rect) { 412 invalidate(); 413 return; 414 } 415 416 IntRect r(rect->left, rect->top, rect->right - rect->left, rect->bottom - rect->top); 417 invalidateRect(r); 418} 419 420void PluginView::invalidateRegion(NPRegion) 421{ 422 // TODO: optimize 423 invalidate(); 424} 425 426void PluginView::forceRedraw() 427{ 428 if (m_isWindowed) 429 gtk_widget_queue_draw(platformPluginWidget()); 430 else 431 gtk_widget_queue_draw(m_parentFrame->view()->hostWindow()->platformPageClient()); 432} 433 434static gboolean 435plug_removed_cb(GtkSocket *socket, gpointer) 436{ 437 return TRUE; 438} 439 440bool PluginView::platformStart() 441{ 442 ASSERT(m_isStarted); 443 ASSERT(m_status == PluginStatusLoadedSuccessfully); 444 445 if (m_plugin->pluginFuncs()->getvalue) { 446 PluginView::setCurrentPluginView(this); 447 JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly); 448 setCallingPlugin(true); 449 m_plugin->pluginFuncs()->getvalue(m_instance, NPPVpluginNeedsXEmbed, &m_needsXEmbed); 450 setCallingPlugin(false); 451 PluginView::setCurrentPluginView(0); 452 } 453 454#if defined(XP_UNIX) 455 if (m_needsXEmbed) { 456 setPlatformWidget(gtk_socket_new()); 457 gtk_container_add(GTK_CONTAINER(m_parentFrame->view()->hostWindow()->platformPageClient()), platformPluginWidget()); 458 g_signal_connect(platformPluginWidget(), "plug_removed", G_CALLBACK(plug_removed_cb), NULL); 459 } else if (m_isWindowed) 460 setPlatformWidget(gtk_xtbin_new(m_parentFrame->view()->hostWindow()->platformPageClient()->window, 0)); 461#else 462 setPlatformWidget(gtk_socket_new()); 463 gtk_container_add(GTK_CONTAINER(m_parentFrame->view()->hostWindow()->platformPageClient()), platformPluginWidget()); 464#endif 465 show(); 466 467 if (m_isWindowed) { 468 m_npWindow.type = NPWindowTypeWindow; 469#if defined(XP_UNIX) 470 NPSetWindowCallbackStruct *ws = new NPSetWindowCallbackStruct(); 471 472 ws->type = 0; 473 474 if (m_needsXEmbed) { 475 gtk_widget_realize(platformPluginWidget()); 476 m_npWindow.window = (void*)gtk_socket_get_id(GTK_SOCKET(platformPluginWidget())); 477 ws->display = GDK_WINDOW_XDISPLAY(platformPluginWidget()->window); 478 ws->visual = GDK_VISUAL_XVISUAL(gdk_drawable_get_visual(GDK_DRAWABLE(platformPluginWidget()->window))); 479 ws->depth = gdk_drawable_get_visual(GDK_DRAWABLE(platformPluginWidget()->window))->depth; 480 ws->colormap = GDK_COLORMAP_XCOLORMAP(gdk_drawable_get_colormap(GDK_DRAWABLE(platformPluginWidget()->window))); 481 } else { 482 m_npWindow.window = (void*)GTK_XTBIN(platformPluginWidget())->xtwindow; 483 ws->display = GTK_XTBIN(platformPluginWidget())->xtdisplay; 484 ws->visual = GTK_XTBIN(platformPluginWidget())->xtclient.xtvisual; 485 ws->depth = GTK_XTBIN(platformPluginWidget())->xtclient.xtdepth; 486 ws->colormap = GTK_XTBIN(platformPluginWidget())->xtclient.xtcolormap; 487 } 488 XFlush (ws->display); 489 490 m_npWindow.ws_info = ws; 491#elif defined(GDK_WINDOWING_WIN32) 492 m_npWindow.window = (void*)GDK_WINDOW_HWND(platformPluginWidget()->window); 493#endif 494 } else { 495 m_npWindow.type = NPWindowTypeDrawable; 496 m_npWindow.window = 0; 497 } 498 499 // TODO remove in favor of null events, like mac port? 500 if (!(m_plugin->quirks().contains(PluginQuirkDeferFirstSetWindowCall))) 501 updatePluginWidget(); // was: setNPWindowIfNeeded(), but this doesn't produce 0x0 rects at first go 502 503 return true; 504} 505 506void PluginView::platformDestroy() 507{ 508} 509 510void PluginView::halt() 511{ 512} 513 514void PluginView::restart() 515{ 516} 517 518} // namespace WebCore 519 520