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