1 /* 2 * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. 3 * Copyright (C) 2008 Collabora Ltd. All rights reserved. 4 * Copyright (C) 2008-2009 Torch Mobile, Inc. All rights reserved. 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 30 #include "PluginView.h" 31 32 #include "BitmapImage.h" 33 #if !PLATFORM(WX) 34 #include "BitmapInfo.h" 35 #endif 36 #include "Bridge.h" 37 #include "Document.h" 38 #include "DocumentLoader.h" 39 #include "Element.h" 40 #include "EventNames.h" 41 #include "FrameLoader.h" 42 #include "FrameLoadRequest.h" 43 #include "FrameTree.h" 44 #include "Frame.h" 45 #include "FrameView.h" 46 #include "GraphicsContext.h" 47 #include "HostWindow.h" 48 #include "Image.h" 49 #include "HTMLNames.h" 50 #include "HTMLPlugInElement.h" 51 #include "JSDOMWindow.h" 52 #include "KeyboardEvent.h" 53 #include "MIMETypeRegistry.h" 54 #include "MouseEvent.h" 55 #include "Page.h" 56 #include "FocusController.h" 57 #include "PlatformMouseEvent.h" 58 #include "PluginMessageThrottlerWin.h" 59 #include "PluginPackage.h" 60 #include "PluginMainThreadScheduler.h" 61 #include "RenderWidget.h" 62 #include "JSDOMBinding.h" 63 #include "ScriptController.h" 64 #include "PluginDatabase.h" 65 #include "PluginDebug.h" 66 #include "PluginPackage.h" 67 #include "Settings.h" 68 #include "c_instance.h" 69 #include "npruntime_impl.h" 70 #include "runtime_root.h" 71 #include <runtime/JSLock.h> 72 #include <runtime/JSValue.h> 73 #include <wtf/ASCIICType.h> 74 75 #if OS(WINCE) 76 #undef LOG_NPERROR 77 #define LOG_NPERROR(x) 78 #undef LOG_PLUGIN_NET_ERROR 79 #define LOG_PLUGIN_NET_ERROR() 80 #endif 81 82 #if PLATFORM(CAIRO) 83 #include <cairo-win32.h> 84 #endif 85 86 #if PLATFORM(QT) 87 #include "QWebPageClient.h" 88 #include <QWidget> 89 #endif 90 91 #if PLATFORM(WX) 92 #include <wx/defs.h> 93 #include <wx/window.h> 94 #endif 95 96 static inline HWND windowHandleForPageClient(PlatformPageClient client) 97 { 98 #if PLATFORM(QT) 99 if (!client) 100 return 0; 101 if (QWidget* pluginParent = qobject_cast<QWidget*>(client->pluginParent())) 102 return pluginParent->winId(); 103 return 0; 104 #elif PLATFORM(WX) 105 if (!client) 106 return 0; 107 return (HWND)client->GetHandle(); 108 #else 109 return client; 110 #endif 111 } 112 113 using JSC::ExecState; 114 using JSC::JSLock; 115 using JSC::JSObject; 116 using JSC::UString; 117 118 using std::min; 119 120 using namespace WTF; 121 122 namespace WebCore { 123 124 using namespace HTMLNames; 125 126 const LPCWSTR kWebPluginViewdowClassName = L"WebPluginView"; 127 const LPCWSTR kWebPluginViewProperty = L"WebPluginViewProperty"; 128 129 #if !OS(WINCE) 130 // The code used to hook BeginPaint/EndPaint originally came from 131 // <http://www.fengyuan.com/article/wmprint.html>. 132 // Copyright (C) 2000 by Feng Yuan (www.fengyuan.com). 133 134 static unsigned beginPaintSysCall; 135 static BYTE* beginPaint; 136 137 static unsigned endPaintSysCall; 138 static BYTE* endPaint; 139 140 typedef HDC (WINAPI *PtrBeginPaint)(HWND, PAINTSTRUCT*); 141 typedef BOOL (WINAPI *PtrEndPaint)(HWND, const PAINTSTRUCT*); 142 143 #if OS(WINDOWS) && PLATFORM(X86_64) && COMPILER(MSVC) 144 extern "C" HDC __stdcall _HBeginPaint(HWND hWnd, LPPAINTSTRUCT lpPaint); 145 extern "C" BOOL __stdcall _HEndPaint(HWND hWnd, const PAINTSTRUCT* lpPaint); 146 #endif 147 148 HDC WINAPI PluginView::hookedBeginPaint(HWND hWnd, PAINTSTRUCT* lpPaint) 149 { 150 PluginView* pluginView = reinterpret_cast<PluginView*>(GetProp(hWnd, kWebPluginViewProperty)); 151 if (pluginView && pluginView->m_wmPrintHDC) { 152 // We're secretly handling WM_PRINTCLIENT, so set up the PAINTSTRUCT so 153 // that the plugin will paint into the HDC we provide. 154 memset(lpPaint, 0, sizeof(PAINTSTRUCT)); 155 lpPaint->hdc = pluginView->m_wmPrintHDC; 156 GetClientRect(hWnd, &lpPaint->rcPaint); 157 return pluginView->m_wmPrintHDC; 158 } 159 160 #if COMPILER(GCC) 161 HDC result; 162 asm ("push %2\n" 163 "push %3\n" 164 "call *%4\n" 165 : "=a" (result) 166 : "a" (beginPaintSysCall), "g" (lpPaint), "g" (hWnd), "m" (beginPaint) 167 : "memory" 168 ); 169 return result; 170 #elif defined(_M_IX86) 171 // Call through to the original BeginPaint. 172 __asm mov eax, beginPaintSysCall 173 __asm push lpPaint 174 __asm push hWnd 175 __asm call beginPaint 176 #else 177 return _HBeginPaint(hWnd, lpPaint); 178 #endif 179 } 180 181 BOOL WINAPI PluginView::hookedEndPaint(HWND hWnd, const PAINTSTRUCT* lpPaint) 182 { 183 PluginView* pluginView = reinterpret_cast<PluginView*>(GetProp(hWnd, kWebPluginViewProperty)); 184 if (pluginView && pluginView->m_wmPrintHDC) { 185 // We're secretly handling WM_PRINTCLIENT, so we don't have to do any 186 // cleanup. 187 return TRUE; 188 } 189 190 #if COMPILER(GCC) 191 BOOL result; 192 asm ("push %2\n" 193 "push %3\n" 194 "call *%4\n" 195 : "=a" (result) 196 : "a" (endPaintSysCall), "g" (lpPaint), "g" (hWnd), "m" (endPaint) 197 ); 198 return result; 199 #elif defined (_M_IX86) 200 // Call through to the original EndPaint. 201 __asm mov eax, endPaintSysCall 202 __asm push lpPaint 203 __asm push hWnd 204 __asm call endPaint 205 #else 206 return _HEndPaint(hWnd, lpPaint); 207 #endif 208 } 209 210 static void hook(const char* module, const char* proc, unsigned& sysCallID, BYTE*& pProc, const void* pNewProc) 211 { 212 // See <http://www.fengyuan.com/article/wmprint.html> for an explanation of 213 // how this function works. 214 215 HINSTANCE hMod = GetModuleHandleA(module); 216 217 pProc = reinterpret_cast<BYTE*>(reinterpret_cast<ptrdiff_t>(GetProcAddress(hMod, proc))); 218 219 #if COMPILER(GCC) || defined(_M_IX86) 220 if (pProc[0] != 0xB8) 221 return; 222 223 // FIXME: Should we be reading the bytes one-by-one instead of doing an 224 // unaligned read? 225 sysCallID = *reinterpret_cast<unsigned*>(pProc + 1); 226 227 DWORD flOldProtect; 228 if (!VirtualProtect(pProc, 5, PAGE_EXECUTE_READWRITE, &flOldProtect)) 229 return; 230 231 pProc[0] = 0xE9; 232 *reinterpret_cast<unsigned*>(pProc + 1) = reinterpret_cast<intptr_t>(pNewProc) - reinterpret_cast<intptr_t>(pProc + 5); 233 234 pProc += 5; 235 #else 236 /* Disassembly of BeginPaint() 237 00000000779FC5B0 4C 8B D1 mov r10,rcx 238 00000000779FC5B3 B8 17 10 00 00 mov eax,1017h 239 00000000779FC5B8 0F 05 syscall 240 00000000779FC5BA C3 ret 241 00000000779FC5BB 90 nop 242 00000000779FC5BC 90 nop 243 00000000779FC5BD 90 nop 244 00000000779FC5BE 90 nop 245 00000000779FC5BF 90 nop 246 00000000779FC5C0 90 nop 247 00000000779FC5C1 90 nop 248 00000000779FC5C2 90 nop 249 00000000779FC5C3 90 nop 250 */ 251 // Check for the signature as in the above disassembly 252 DWORD guard = 0xB8D18B4C; 253 if (*reinterpret_cast<DWORD*>(pProc) != guard) 254 return; 255 256 DWORD flOldProtect; 257 VirtualProtect(pProc, 12, PAGE_EXECUTE_READWRITE, & flOldProtect); 258 pProc[0] = 0x48; // mov rax, this 259 pProc[1] = 0xb8; 260 *(__int64*)(pProc+2) = (__int64)pNewProc; 261 pProc[10] = 0xff; // jmp rax 262 pProc[11] = 0xe0; 263 #endif 264 } 265 266 static void setUpOffscreenPaintingHooks(HDC (WINAPI*hookedBeginPaint)(HWND, PAINTSTRUCT*), BOOL (WINAPI*hookedEndPaint)(HWND, const PAINTSTRUCT*)) 267 { 268 static bool haveHooked = false; 269 if (haveHooked) 270 return; 271 haveHooked = true; 272 273 // Most (all?) windowed plugins don't seem to respond to WM_PRINTCLIENT, so 274 // we hook into BeginPaint/EndPaint to allow their normal WM_PAINT handling 275 // to draw into a given HDC. Note that this hooking affects the entire 276 // process. 277 hook("user32.dll", "BeginPaint", beginPaintSysCall, beginPaint, reinterpret_cast<const void *>(reinterpret_cast<ptrdiff_t>(hookedBeginPaint))); 278 hook("user32.dll", "EndPaint", endPaintSysCall, endPaint, reinterpret_cast<const void *>(reinterpret_cast<ptrdiff_t>(hookedEndPaint))); 279 280 } 281 #endif 282 283 static bool registerPluginView() 284 { 285 static bool haveRegisteredWindowClass = false; 286 if (haveRegisteredWindowClass) 287 return true; 288 289 haveRegisteredWindowClass = true; 290 291 #if PLATFORM(QT) 292 Page::setInstanceHandle((HINSTANCE)(qWinAppInst())); 293 #endif 294 295 ASSERT(Page::instanceHandle()); 296 297 #if OS(WINCE) 298 WNDCLASS wcex = { 0 }; 299 #else 300 WNDCLASSEX wcex; 301 wcex.cbSize = sizeof(WNDCLASSEX); 302 wcex.hIconSm = 0; 303 #endif 304 305 wcex.style = CS_DBLCLKS; 306 #if OS(WINCE) 307 wcex.style |= CS_PARENTDC; 308 #endif 309 wcex.lpfnWndProc = DefWindowProc; 310 wcex.cbClsExtra = 0; 311 wcex.cbWndExtra = 0; 312 wcex.hInstance = Page::instanceHandle(); 313 wcex.hIcon = 0; 314 wcex.hCursor = LoadCursor(0, IDC_ARROW); 315 wcex.hbrBackground = (HBRUSH)COLOR_WINDOW; 316 wcex.lpszMenuName = 0; 317 wcex.lpszClassName = kWebPluginViewdowClassName; 318 319 #if OS(WINCE) 320 return !!RegisterClass(&wcex); 321 #else 322 return !!RegisterClassEx(&wcex); 323 #endif 324 } 325 326 LRESULT CALLBACK PluginView::PluginViewWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 327 { 328 PluginView* pluginView = reinterpret_cast<PluginView*>(GetProp(hWnd, kWebPluginViewProperty)); 329 330 return pluginView->wndProc(hWnd, message, wParam, lParam); 331 } 332 333 static bool isWindowsMessageUserGesture(UINT message) 334 { 335 switch (message) { 336 case WM_LBUTTONUP: 337 case WM_MBUTTONUP: 338 case WM_RBUTTONUP: 339 case WM_KEYUP: 340 return true; 341 default: 342 return false; 343 } 344 } 345 346 LRESULT 347 PluginView::wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 348 { 349 // <rdar://5711136> Sometimes Flash will call SetCapture before creating 350 // a full-screen window and will not release it, which causes the 351 // full-screen window to never receive mouse events. We set/release capture 352 // on mouse down/up before sending the event to the plug-in to prevent that. 353 switch (message) { 354 case WM_LBUTTONDOWN: 355 case WM_MBUTTONDOWN: 356 case WM_RBUTTONDOWN: 357 ::SetCapture(hWnd); 358 break; 359 case WM_LBUTTONUP: 360 case WM_MBUTTONUP: 361 case WM_RBUTTONUP: 362 ::ReleaseCapture(); 363 break; 364 } 365 366 if (message == m_lastMessage && 367 m_plugin->quirks().contains(PluginQuirkDontCallWndProcForSameMessageRecursively) && 368 m_isCallingPluginWndProc) 369 return 1; 370 371 if (message == WM_USER + 1 && 372 m_plugin->quirks().contains(PluginQuirkThrottleWMUserPlusOneMessages)) { 373 if (!m_messageThrottler) 374 m_messageThrottler.set(new PluginMessageThrottlerWin(this)); 375 376 m_messageThrottler->appendMessage(hWnd, message, wParam, lParam); 377 return 0; 378 } 379 380 m_lastMessage = message; 381 m_isCallingPluginWndProc = true; 382 383 // If the plug-in doesn't explicitly support changing the pop-up state, we enable 384 // popups for all user gestures. 385 // Note that we need to pop the state in a timer, because the Flash plug-in 386 // pops up windows in response to a posted message. 387 if (m_plugin->pluginFuncs()->version < NPVERS_HAS_POPUPS_ENABLED_STATE && 388 isWindowsMessageUserGesture(message) && !m_popPopupsStateTimer.isActive()) { 389 390 pushPopupsEnabledState(true); 391 392 m_popPopupsStateTimer.startOneShot(0); 393 } 394 395 #if !OS(WINCE) 396 if (message == WM_PRINTCLIENT) { 397 // Most (all?) windowed plugins don't respond to WM_PRINTCLIENT, so we 398 // change the message to WM_PAINT and rely on our hooked versions of 399 // BeginPaint/EndPaint to make the plugin draw into the given HDC. 400 message = WM_PAINT; 401 m_wmPrintHDC = reinterpret_cast<HDC>(wParam); 402 } 403 #endif 404 405 // Call the plug-in's window proc. 406 LRESULT result = ::CallWindowProc(m_pluginWndProc, hWnd, message, wParam, lParam); 407 408 m_wmPrintHDC = 0; 409 410 m_isCallingPluginWndProc = false; 411 412 return result; 413 } 414 415 void PluginView::updatePluginWidget() 416 { 417 if (!parent()) 418 return; 419 420 ASSERT(parent()->isFrameView()); 421 FrameView* frameView = static_cast<FrameView*>(parent()); 422 423 IntRect oldWindowRect = m_windowRect; 424 IntRect oldClipRect = m_clipRect; 425 426 #if OS(WINCE) 427 m_windowRect = frameView->contentsToWindow(frameRect()); 428 #else 429 m_windowRect = IntRect(frameView->contentsToWindow(frameRect().location()), frameRect().size()); 430 #endif 431 m_clipRect = windowClipRect(); 432 m_clipRect.move(-m_windowRect.x(), -m_windowRect.y()); 433 434 if (platformPluginWidget() && (!m_haveUpdatedPluginWidget || m_windowRect != oldWindowRect || m_clipRect != oldClipRect)) { 435 HRGN rgn; 436 437 setCallingPlugin(true); 438 439 // To prevent flashes while scrolling, we disable drawing during the window 440 // update process by clipping the window to the zero rect. 441 442 bool clipToZeroRect = !m_plugin->quirks().contains(PluginQuirkDontClipToZeroRectWhenScrolling); 443 444 if (clipToZeroRect) { 445 rgn = ::CreateRectRgn(0, 0, 0, 0); 446 ::SetWindowRgn(platformPluginWidget(), rgn, FALSE); 447 } else { 448 rgn = ::CreateRectRgn(m_clipRect.x(), m_clipRect.y(), m_clipRect.right(), m_clipRect.bottom()); 449 ::SetWindowRgn(platformPluginWidget(), rgn, TRUE); 450 } 451 452 if (!m_haveUpdatedPluginWidget || m_windowRect != oldWindowRect) 453 ::MoveWindow(platformPluginWidget(), m_windowRect.x(), m_windowRect.y(), m_windowRect.width(), m_windowRect.height(), TRUE); 454 455 if (clipToZeroRect) { 456 rgn = ::CreateRectRgn(m_clipRect.x(), m_clipRect.y(), m_clipRect.right(), m_clipRect.bottom()); 457 ::SetWindowRgn(platformPluginWidget(), rgn, TRUE); 458 } 459 460 setCallingPlugin(false); 461 462 m_haveUpdatedPluginWidget = true; 463 } 464 } 465 466 void PluginView::setFocus() 467 { 468 if (platformPluginWidget()) 469 SetFocus(platformPluginWidget()); 470 471 Widget::setFocus(); 472 } 473 474 void PluginView::show() 475 { 476 setSelfVisible(true); 477 478 if (isParentVisible() && platformPluginWidget()) 479 ShowWindow(platformPluginWidget(), SW_SHOWNA); 480 481 Widget::show(); 482 } 483 484 void PluginView::hide() 485 { 486 setSelfVisible(false); 487 488 if (isParentVisible() && platformPluginWidget()) 489 ShowWindow(platformPluginWidget(), SW_HIDE); 490 491 Widget::hide(); 492 } 493 494 bool PluginView::dispatchNPEvent(NPEvent& npEvent) 495 { 496 if (!m_plugin->pluginFuncs()->event) 497 return true; 498 499 bool shouldPop = false; 500 501 if (m_plugin->pluginFuncs()->version < NPVERS_HAS_POPUPS_ENABLED_STATE && isWindowsMessageUserGesture(npEvent.event)) { 502 pushPopupsEnabledState(true); 503 shouldPop = true; 504 } 505 506 JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly); 507 setCallingPlugin(true); 508 bool result = m_plugin->pluginFuncs()->event(m_instance, &npEvent); 509 setCallingPlugin(false); 510 511 if (shouldPop) 512 popPopupsEnabledState(); 513 514 return result; 515 } 516 517 void PluginView::paintIntoTransformedContext(HDC hdc) 518 { 519 if (m_isWindowed) { 520 SendMessage(platformPluginWidget(), WM_PRINTCLIENT, reinterpret_cast<WPARAM>(hdc), PRF_CLIENT | PRF_CHILDREN | PRF_OWNED); 521 return; 522 } 523 524 m_npWindow.type = NPWindowTypeDrawable; 525 m_npWindow.window = hdc; 526 527 WINDOWPOS windowpos = { 0 }; 528 529 #if OS(WINCE) 530 IntRect r = static_cast<FrameView*>(parent())->contentsToWindow(frameRect()); 531 532 windowpos.x = r.x(); 533 windowpos.y = r.y(); 534 windowpos.cx = r.width(); 535 windowpos.cy = r.height(); 536 #else 537 IntPoint p = static_cast<FrameView*>(parent())->contentsToWindow(frameRect().location()); 538 539 windowpos.x = p.x(); 540 windowpos.y = p.y(); 541 windowpos.cx = frameRect().width(); 542 windowpos.cy = frameRect().height(); 543 #endif 544 545 NPEvent npEvent; 546 npEvent.event = WM_WINDOWPOSCHANGED; 547 npEvent.lParam = reinterpret_cast<uint32>(&windowpos); 548 npEvent.wParam = 0; 549 550 dispatchNPEvent(npEvent); 551 552 setNPWindowRect(frameRect()); 553 554 npEvent.event = WM_PAINT; 555 npEvent.wParam = reinterpret_cast<uint32>(hdc); 556 557 // This is supposed to be a pointer to the dirty rect, but it seems that the Flash plugin 558 // ignores it so we just pass null. 559 npEvent.lParam = 0; 560 561 dispatchNPEvent(npEvent); 562 } 563 564 void PluginView::paintWindowedPluginIntoContext(GraphicsContext* context, const IntRect& rect) 565 { 566 #if !OS(WINCE) 567 ASSERT(m_isWindowed); 568 ASSERT(context->shouldIncludeChildWindows()); 569 570 ASSERT(parent()->isFrameView()); 571 IntPoint locationInWindow = static_cast<FrameView*>(parent())->contentsToWindow(frameRect().location()); 572 573 HDC hdc = context->getWindowsContext(frameRect(), false); 574 575 #if PLATFORM(CAIRO) 576 // Must flush drawings up to this point to the backing metafile, otherwise the 577 // plugin region will be overwritten with any clear regions specified in the 578 // cairo-controlled portions of the rendering. 579 PlatformGraphicsContext* ctx = context->platformContext(); 580 cairo_show_page(ctx); 581 #endif 582 583 XFORM originalTransform; 584 GetWorldTransform(hdc, &originalTransform); 585 586 // The plugin expects the DC to be in client coordinates, so we translate 587 // the DC to make that so. 588 AffineTransform ctm = context->getCTM(); 589 ctm.translate(locationInWindow.x(), locationInWindow.y()); 590 XFORM transform = static_cast<XFORM>(ctm.toTransformationMatrix()); 591 592 SetWorldTransform(hdc, &transform); 593 594 paintIntoTransformedContext(hdc); 595 596 SetWorldTransform(hdc, &originalTransform); 597 598 context->releaseWindowsContext(hdc, frameRect(), false); 599 #endif 600 } 601 602 void PluginView::paint(GraphicsContext* context, const IntRect& rect) 603 { 604 if (!m_isStarted) { 605 // Draw the "missing plugin" image 606 paintMissingPluginIcon(context, rect); 607 return; 608 } 609 610 if (context->paintingDisabled()) 611 return; 612 613 if (m_isWindowed) { 614 #if !OS(WINCE) 615 if (context->shouldIncludeChildWindows()) 616 paintWindowedPluginIntoContext(context, rect); 617 #endif 618 return; 619 } 620 621 ASSERT(parent()->isFrameView()); 622 IntRect rectInWindow = static_cast<FrameView*>(parent())->contentsToWindow(frameRect()); 623 HDC hdc = context->getWindowsContext(rectInWindow, m_isTransparent); 624 625 // On Safari/Windows without transparency layers the GraphicsContext returns the HDC 626 // of the window and the plugin expects that the passed in DC has window coordinates. 627 // In the Qt port we always draw in an offscreen buffer and therefore need to preserve 628 // the translation set in getWindowsContext. 629 #if !PLATFORM(QT) && !OS(WINCE) 630 if (!context->inTransparencyLayer()) { 631 XFORM transform; 632 GetWorldTransform(hdc, &transform); 633 transform.eDx = 0; 634 transform.eDy = 0; 635 SetWorldTransform(hdc, &transform); 636 } 637 #endif 638 639 paintIntoTransformedContext(hdc); 640 641 context->releaseWindowsContext(hdc, frameRect(), m_isTransparent); 642 } 643 644 void PluginView::handleKeyboardEvent(KeyboardEvent* event) 645 { 646 NPEvent npEvent; 647 648 npEvent.wParam = event->keyCode(); 649 650 if (event->type() == eventNames().keydownEvent) { 651 npEvent.event = WM_KEYDOWN; 652 npEvent.lParam = 0; 653 } else if (event->type() == eventNames().keyupEvent) { 654 npEvent.event = WM_KEYUP; 655 npEvent.lParam = 0x8000; 656 } 657 658 JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly); 659 if (!dispatchNPEvent(npEvent)) 660 event->setDefaultHandled(); 661 } 662 663 #if !OS(WINCE) 664 extern HCURSOR lastSetCursor; 665 extern bool ignoreNextSetCursor; 666 #endif 667 668 void PluginView::handleMouseEvent(MouseEvent* event) 669 { 670 NPEvent npEvent; 671 672 IntPoint p = static_cast<FrameView*>(parent())->contentsToWindow(IntPoint(event->pageX(), event->pageY())); 673 674 npEvent.lParam = MAKELPARAM(p.x(), p.y()); 675 npEvent.wParam = 0; 676 677 if (event->ctrlKey()) 678 npEvent.wParam |= MK_CONTROL; 679 if (event->shiftKey()) 680 npEvent.wParam |= MK_SHIFT; 681 682 if (event->type() == eventNames().mousemoveEvent || 683 event->type() == eventNames().mouseoutEvent || 684 event->type() == eventNames().mouseoverEvent) { 685 npEvent.event = WM_MOUSEMOVE; 686 if (event->buttonDown()) 687 switch (event->button()) { 688 case LeftButton: 689 npEvent.wParam |= MK_LBUTTON; 690 break; 691 case MiddleButton: 692 npEvent.wParam |= MK_MBUTTON; 693 break; 694 case RightButton: 695 npEvent.wParam |= MK_RBUTTON; 696 break; 697 } 698 } 699 else if (event->type() == eventNames().mousedownEvent) { 700 focusPluginElement(); 701 switch (event->button()) { 702 case 0: 703 npEvent.event = WM_LBUTTONDOWN; 704 break; 705 case 1: 706 npEvent.event = WM_MBUTTONDOWN; 707 break; 708 case 2: 709 npEvent.event = WM_RBUTTONDOWN; 710 break; 711 } 712 } else if (event->type() == eventNames().mouseupEvent) { 713 switch (event->button()) { 714 case 0: 715 npEvent.event = WM_LBUTTONUP; 716 break; 717 case 1: 718 npEvent.event = WM_MBUTTONUP; 719 break; 720 case 2: 721 npEvent.event = WM_RBUTTONUP; 722 break; 723 } 724 } else 725 return; 726 727 JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly); 728 if (!dispatchNPEvent(npEvent)) 729 event->setDefaultHandled(); 730 731 #if !PLATFORM(QT) && !PLATFORM(WX) && !OS(WINCE) 732 // Currently, Widget::setCursor is always called after this function in EventHandler.cpp 733 // and since we don't want that we set ignoreNextSetCursor to true here to prevent that. 734 ignoreNextSetCursor = true; 735 lastSetCursor = ::GetCursor(); 736 #endif 737 } 738 739 void PluginView::setParent(ScrollView* parent) 740 { 741 Widget::setParent(parent); 742 743 #if OS(WINCE) 744 if (parent) { 745 init(); 746 if (parent->isVisible()) 747 show(); 748 else 749 hide(); 750 } 751 #else 752 if (parent) 753 init(); 754 else { 755 if (!platformPluginWidget()) 756 return; 757 758 // If the plug-in window or one of its children have the focus, we need to 759 // clear it to prevent the web view window from being focused because that can 760 // trigger a layout while the plugin element is being detached. 761 HWND focusedWindow = ::GetFocus(); 762 if (platformPluginWidget() == focusedWindow || ::IsChild(platformPluginWidget(), focusedWindow)) 763 ::SetFocus(0); 764 } 765 #endif 766 } 767 768 void PluginView::setParentVisible(bool visible) 769 { 770 if (isParentVisible() == visible) 771 return; 772 773 Widget::setParentVisible(visible); 774 775 if (isSelfVisible() && platformPluginWidget()) { 776 if (visible) 777 ShowWindow(platformPluginWidget(), SW_SHOWNA); 778 else 779 ShowWindow(platformPluginWidget(), SW_HIDE); 780 } 781 } 782 783 void PluginView::setNPWindowRect(const IntRect& rect) 784 { 785 if (!m_isStarted) 786 return; 787 788 #if OS(WINCE) 789 IntRect r = static_cast<FrameView*>(parent())->contentsToWindow(rect); 790 m_npWindow.x = r.x(); 791 m_npWindow.y = r.y(); 792 793 m_npWindow.width = r.width(); 794 m_npWindow.height = r.height(); 795 796 m_npWindow.clipRect.right = r.width(); 797 m_npWindow.clipRect.bottom = r.height(); 798 #else 799 IntPoint p = static_cast<FrameView*>(parent())->contentsToWindow(rect.location()); 800 m_npWindow.x = p.x(); 801 m_npWindow.y = p.y(); 802 803 m_npWindow.width = rect.width(); 804 m_npWindow.height = rect.height(); 805 806 m_npWindow.clipRect.right = rect.width(); 807 m_npWindow.clipRect.bottom = rect.height(); 808 #endif 809 m_npWindow.clipRect.left = 0; 810 m_npWindow.clipRect.top = 0; 811 812 if (m_plugin->pluginFuncs()->setwindow) { 813 JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly); 814 setCallingPlugin(true); 815 m_plugin->pluginFuncs()->setwindow(m_instance, &m_npWindow); 816 setCallingPlugin(false); 817 818 if (!m_isWindowed) 819 return; 820 821 ASSERT(platformPluginWidget()); 822 823 #if OS(WINCE) 824 if (!m_pluginWndProc) { 825 WNDPROC currentWndProc = (WNDPROC)GetWindowLong(platformPluginWidget(), GWL_WNDPROC); 826 if (currentWndProc != PluginViewWndProc) 827 m_pluginWndProc = (WNDPROC)SetWindowLong(platformPluginWidget(), GWL_WNDPROC, (LONG)PluginViewWndProc); 828 } 829 #else 830 WNDPROC currentWndProc = (WNDPROC)GetWindowLongPtr(platformPluginWidget(), GWLP_WNDPROC); 831 if (currentWndProc != PluginViewWndProc) 832 m_pluginWndProc = (WNDPROC)SetWindowLongPtr(platformPluginWidget(), GWLP_WNDPROC, (LONG)PluginViewWndProc); 833 #endif 834 } 835 } 836 837 NPError PluginView::handlePostReadFile(Vector<char>& buffer, uint32 len, const char* buf) 838 { 839 String filename(buf, len); 840 841 if (filename.startsWith("file:///")) 842 filename = filename.substring(8); 843 844 // Get file info 845 WIN32_FILE_ATTRIBUTE_DATA attrs; 846 if (GetFileAttributesExW(filename.charactersWithNullTermination(), GetFileExInfoStandard, &attrs) == 0) 847 return NPERR_FILE_NOT_FOUND; 848 849 if (attrs.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 850 return NPERR_FILE_NOT_FOUND; 851 852 HANDLE fileHandle = CreateFileW(filename.charactersWithNullTermination(), FILE_READ_DATA, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); 853 854 if (fileHandle == INVALID_HANDLE_VALUE) 855 return NPERR_FILE_NOT_FOUND; 856 857 buffer.resize(attrs.nFileSizeLow); 858 859 DWORD bytesRead; 860 int retval = ReadFile(fileHandle, buffer.data(), attrs.nFileSizeLow, &bytesRead, 0); 861 862 CloseHandle(fileHandle); 863 864 if (retval == 0 || bytesRead != attrs.nFileSizeLow) 865 return NPERR_FILE_NOT_FOUND; 866 867 return NPERR_NO_ERROR; 868 } 869 870 NPError PluginView::getValueStatic(NPNVariable variable, void* value) 871 { 872 LOG(Plugins, "PluginView::getValueStatic(%s)", prettyNameForNPNVariable(variable).data()); 873 874 return NPERR_GENERIC_ERROR; 875 } 876 877 NPError PluginView::getValue(NPNVariable variable, void* value) 878 { 879 LOG(Plugins, "PluginView::getValue(%s)", prettyNameForNPNVariable(variable).data()); 880 881 switch (variable) { 882 #if ENABLE(NETSCAPE_PLUGIN_API) 883 case NPNVWindowNPObject: { 884 if (m_isJavaScriptPaused) 885 return NPERR_GENERIC_ERROR; 886 887 NPObject* windowScriptObject = m_parentFrame->script()->windowScriptNPObject(); 888 889 // Return value is expected to be retained, as described here: <http://www.mozilla.org/projects/plugin/npruntime.html> 890 if (windowScriptObject) 891 _NPN_RetainObject(windowScriptObject); 892 893 void** v = (void**)value; 894 *v = windowScriptObject; 895 896 return NPERR_NO_ERROR; 897 } 898 899 case NPNVPluginElementNPObject: { 900 if (m_isJavaScriptPaused) 901 return NPERR_GENERIC_ERROR; 902 903 NPObject* pluginScriptObject = 0; 904 905 if (m_element->hasTagName(appletTag) || m_element->hasTagName(embedTag) || m_element->hasTagName(objectTag)) 906 pluginScriptObject = static_cast<HTMLPlugInElement*>(m_element)->getNPObject(); 907 908 // Return value is expected to be retained, as described here: <http://www.mozilla.org/projects/plugin/npruntime.html> 909 if (pluginScriptObject) 910 _NPN_RetainObject(pluginScriptObject); 911 912 void** v = (void**)value; 913 *v = pluginScriptObject; 914 915 return NPERR_NO_ERROR; 916 } 917 #endif 918 919 case NPNVnetscapeWindow: { 920 HWND* w = reinterpret_cast<HWND*>(value); 921 922 *w = windowHandleForPageClient(parent() ? parent()->hostWindow()->platformPageClient() : 0); 923 924 return NPERR_NO_ERROR; 925 } 926 927 case NPNVSupportsWindowless: { 928 NPBool *result = reinterpret_cast<NPBool*>(value); 929 930 *result = TRUE; 931 932 return NPERR_NO_ERROR; 933 } 934 935 default: 936 return NPERR_GENERIC_ERROR; 937 } 938 } 939 940 void PluginView::invalidateRect(const IntRect& rect) 941 { 942 if (m_isWindowed) { 943 RECT invalidRect = { rect.x(), rect.y(), rect.right(), rect.bottom() }; 944 ::InvalidateRect(platformPluginWidget(), &invalidRect, false); 945 return; 946 } 947 948 invalidateWindowlessPluginRect(rect); 949 } 950 951 void PluginView::invalidateRect(NPRect* rect) 952 { 953 if (!rect) { 954 invalidate(); 955 return; 956 } 957 958 IntRect r(rect->left, rect->top, rect->right - rect->left, rect->bottom - rect->top); 959 960 if (m_isWindowed) { 961 RECT invalidRect = { r.x(), r.y(), r.right(), r.bottom() }; 962 InvalidateRect(platformPluginWidget(), &invalidRect, FALSE); 963 } else { 964 if (m_plugin->quirks().contains(PluginQuirkThrottleInvalidate)) { 965 m_invalidRects.append(r); 966 if (!m_invalidateTimer.isActive()) 967 m_invalidateTimer.startOneShot(0.001); 968 } else 969 invalidateRect(r); 970 } 971 } 972 973 void PluginView::invalidateRegion(NPRegion region) 974 { 975 if (m_isWindowed) 976 return; 977 978 RECT r; 979 980 if (GetRgnBox(region, &r) == 0) { 981 invalidate(); 982 return; 983 } 984 985 IntRect rect(IntPoint(r.left, r.top), IntSize(r.right-r.left, r.bottom-r.top)); 986 invalidateRect(rect); 987 } 988 989 void PluginView::forceRedraw() 990 { 991 if (m_isWindowed) 992 ::UpdateWindow(platformPluginWidget()); 993 else 994 ::UpdateWindow(windowHandleForPageClient(parent() ? parent()->hostWindow()->platformPageClient() : 0)); 995 } 996 997 bool PluginView::platformStart() 998 { 999 ASSERT(m_isStarted); 1000 ASSERT(m_status == PluginStatusLoadedSuccessfully); 1001 1002 if (m_isWindowed) { 1003 registerPluginView(); 1004 #if !OS(WINCE) 1005 setUpOffscreenPaintingHooks(hookedBeginPaint, hookedEndPaint); 1006 #endif 1007 1008 DWORD flags = WS_CHILD; 1009 if (isSelfVisible()) 1010 flags |= WS_VISIBLE; 1011 1012 HWND parentWindowHandle = windowHandleForPageClient(m_parentFrame->view()->hostWindow()->platformPageClient()); 1013 HWND window = ::CreateWindowEx(0, kWebPluginViewdowClassName, 0, flags, 1014 0, 0, 0, 0, parentWindowHandle, 0, Page::instanceHandle(), 0); 1015 1016 #if OS(WINDOWS) && (PLATFORM(QT) || PLATFORM(WX)) 1017 m_window = window; 1018 #else 1019 setPlatformWidget(window); 1020 #endif 1021 1022 // Calling SetWindowLongPtrA here makes the window proc ASCII, which is required by at least 1023 // the Shockwave Director plug-in. 1024 #if OS(WINDOWS) && PLATFORM(X86_64) && COMPILER(MSVC) 1025 ::SetWindowLongPtrA(platformPluginWidget(), GWLP_WNDPROC, (LONG_PTR)DefWindowProcA); 1026 #elif OS(WINCE) 1027 ::SetWindowLong(platformPluginWidget(), GWL_WNDPROC, (LONG)DefWindowProc); 1028 #else 1029 ::SetWindowLongPtrA(platformPluginWidget(), GWL_WNDPROC, (LONG)DefWindowProcA); 1030 #endif 1031 SetProp(platformPluginWidget(), kWebPluginViewProperty, this); 1032 1033 m_npWindow.type = NPWindowTypeWindow; 1034 m_npWindow.window = platformPluginWidget(); 1035 } else { 1036 m_npWindow.type = NPWindowTypeDrawable; 1037 m_npWindow.window = 0; 1038 } 1039 1040 updatePluginWidget(); 1041 1042 if (!m_plugin->quirks().contains(PluginQuirkDeferFirstSetWindowCall)) 1043 setNPWindowRect(frameRect()); 1044 1045 return true; 1046 } 1047 1048 void PluginView::platformDestroy() 1049 { 1050 if (!platformPluginWidget()) 1051 return; 1052 1053 DestroyWindow(platformPluginWidget()); 1054 setPlatformPluginWidget(0); 1055 } 1056 1057 PassRefPtr<Image> PluginView::snapshot() 1058 { 1059 #if !PLATFORM(WX) 1060 OwnPtr<HDC> hdc(CreateCompatibleDC(0)); 1061 1062 if (!m_isWindowed) { 1063 // Enable world transforms. 1064 SetGraphicsMode(hdc.get(), GM_ADVANCED); 1065 1066 XFORM transform; 1067 GetWorldTransform(hdc.get(), &transform); 1068 1069 // Windowless plug-ins assume that they're drawing onto the view's DC. 1070 // Translate the context so that the plug-in draws at (0, 0). 1071 ASSERT(parent()->isFrameView()); 1072 IntPoint position = static_cast<FrameView*>(parent())->contentsToWindow(frameRect()).location(); 1073 transform.eDx = -position.x(); 1074 transform.eDy = -position.y(); 1075 SetWorldTransform(hdc.get(), &transform); 1076 } 1077 1078 void* bits; 1079 BitmapInfo bmp = BitmapInfo::createBottomUp(frameRect().size()); 1080 OwnPtr<HBITMAP> hbmp(CreateDIBSection(0, &bmp, DIB_RGB_COLORS, &bits, 0, 0)); 1081 1082 HBITMAP hbmpOld = static_cast<HBITMAP>(SelectObject(hdc.get(), hbmp.get())); 1083 1084 paintIntoTransformedContext(hdc.get()); 1085 1086 SelectObject(hdc.get(), hbmpOld); 1087 1088 return BitmapImage::create(hbmp.get()); 1089 #else 1090 return 0; 1091 #endif 1092 } 1093 1094 void PluginView::halt() 1095 { 1096 ASSERT(!m_isHalted); 1097 ASSERT(m_isStarted); 1098 1099 #if !PLATFORM(QT) 1100 // Show a screenshot of the plug-in. 1101 toRenderWidget(m_element->renderer())->showSubstituteImage(snapshot()); 1102 #endif 1103 1104 m_isHalted = true; 1105 m_hasBeenHalted = true; 1106 1107 stop(); 1108 platformDestroy(); 1109 } 1110 1111 void PluginView::restart() 1112 { 1113 ASSERT(!m_isStarted); 1114 ASSERT(m_isHalted); 1115 1116 // Clear any substitute image. 1117 toRenderWidget(m_element->renderer())->showSubstituteImage(0); 1118 1119 m_isHalted = false; 1120 m_haveUpdatedPluginWidget = false; 1121 start(); 1122 } 1123 1124 } // namespace WebCore 1125