Home | History | Annotate | Download | only in win
      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 "BridgeJSC.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 "LocalWindowsContext.h"
     54 #include "MIMETypeRegistry.h"
     55 #include "MouseEvent.h"
     56 #include "Page.h"
     57 #include "PlatformMouseEvent.h"
     58 #include "PluginDatabase.h"
     59 #include "PluginDebug.h"
     60 #include "PluginMainThreadScheduler.h"
     61 #include "PluginMessageThrottlerWin.h"
     62 #include "PluginPackage.h"
     63 #include "RenderWidget.h"
     64 #include "ScriptController.h"
     65 #include "Settings.h"
     66 #include "WebCoreInstanceHandle.h"
     67 #include "c_instance.h"
     68 #include "npruntime_impl.h"
     69 #include "runtime_root.h"
     70 #include <runtime/JSLock.h>
     71 #include <runtime/JSValue.h>
     72 #include <wtf/ASCIICType.h>
     73 
     74 #if !PLATFORM(WX)
     75 #include "BitmapInfo.h"
     76 #endif
     77 
     78 #if OS(WINCE)
     79 #undef LOG_NPERROR
     80 #define LOG_NPERROR(x)
     81 #undef LOG_PLUGIN_NET_ERROR
     82 #define LOG_PLUGIN_NET_ERROR()
     83 #endif
     84 
     85 #if USE(CAIRO)
     86 #include "PlatformContextCairo.h"
     87 #include <cairo-win32.h>
     88 #endif
     89 
     90 #if PLATFORM(QT)
     91 #include "QWebPageClient.h"
     92 #include <QWidget>
     93 #endif
     94 
     95 #if PLATFORM(WX)
     96 #include <wx/defs.h>
     97 #include <wx/window.h>
     98 #endif
     99 
    100 static inline HWND windowHandleForPageClient(PlatformPageClient client)
    101 {
    102 #if PLATFORM(QT)
    103     if (!client)
    104         return 0;
    105     if (QWidget* pluginParent = qobject_cast<QWidget*>(client->pluginParent()))
    106         return pluginParent->winId();
    107     return 0;
    108 #elif PLATFORM(WX)
    109     if (!client)
    110         return 0;
    111     return (HWND)client->GetHandle();
    112 #else
    113     return client;
    114 #endif
    115 }
    116 
    117 using JSC::ExecState;
    118 using JSC::JSLock;
    119 using JSC::JSObject;
    120 using JSC::UString;
    121 
    122 using std::min;
    123 
    124 using namespace WTF;
    125 
    126 namespace WebCore {
    127 
    128 using namespace HTMLNames;
    129 
    130 const LPCWSTR kWebPluginViewdowClassName = L"WebPluginView";
    131 const LPCWSTR kWebPluginViewProperty = L"WebPluginViewProperty";
    132 
    133 #if !OS(WINCE)
    134 // The code used to hook BeginPaint/EndPaint originally came from
    135 // <http://www.fengyuan.com/article/wmprint.html>.
    136 // Copyright (C) 2000 by Feng Yuan (www.fengyuan.com).
    137 
    138 static unsigned beginPaintSysCall;
    139 static BYTE* beginPaint;
    140 
    141 static unsigned endPaintSysCall;
    142 static BYTE* endPaint;
    143 
    144 typedef HDC (WINAPI *PtrBeginPaint)(HWND, PAINTSTRUCT*);
    145 typedef BOOL (WINAPI *PtrEndPaint)(HWND, const PAINTSTRUCT*);
    146 
    147 #if OS(WINDOWS) && CPU(X86_64) && COMPILER(MSVC)
    148 extern "C" HDC __stdcall _HBeginPaint(HWND hWnd, LPPAINTSTRUCT lpPaint);
    149 extern "C" BOOL __stdcall _HEndPaint(HWND hWnd, const PAINTSTRUCT* lpPaint);
    150 #endif
    151 
    152 HDC WINAPI PluginView::hookedBeginPaint(HWND hWnd, PAINTSTRUCT* lpPaint)
    153 {
    154     PluginView* pluginView = reinterpret_cast<PluginView*>(GetProp(hWnd, kWebPluginViewProperty));
    155     if (pluginView && pluginView->m_wmPrintHDC) {
    156         // We're secretly handling WM_PRINTCLIENT, so set up the PAINTSTRUCT so
    157         // that the plugin will paint into the HDC we provide.
    158         memset(lpPaint, 0, sizeof(PAINTSTRUCT));
    159         lpPaint->hdc = pluginView->m_wmPrintHDC;
    160         GetClientRect(hWnd, &lpPaint->rcPaint);
    161         return pluginView->m_wmPrintHDC;
    162     }
    163 
    164 #if COMPILER(GCC)
    165     HDC result;
    166     asm ("push    %2\n"
    167          "push    %3\n"
    168          "call    *%4\n"
    169          : "=a" (result)
    170          : "a" (beginPaintSysCall), "g" (lpPaint), "g" (hWnd), "m" (beginPaint)
    171          : "memory"
    172         );
    173     return result;
    174 #elif defined(_M_IX86)
    175     // Call through to the original BeginPaint.
    176     __asm   mov     eax, beginPaintSysCall
    177     __asm   push    lpPaint
    178     __asm   push    hWnd
    179     __asm   call    beginPaint
    180 #else
    181     return _HBeginPaint(hWnd, lpPaint);
    182 #endif
    183 }
    184 
    185 BOOL WINAPI PluginView::hookedEndPaint(HWND hWnd, const PAINTSTRUCT* lpPaint)
    186 {
    187     PluginView* pluginView = reinterpret_cast<PluginView*>(GetProp(hWnd, kWebPluginViewProperty));
    188     if (pluginView && pluginView->m_wmPrintHDC) {
    189         // We're secretly handling WM_PRINTCLIENT, so we don't have to do any
    190         // cleanup.
    191         return TRUE;
    192     }
    193 
    194 #if COMPILER(GCC)
    195     BOOL result;
    196     asm ("push   %2\n"
    197          "push   %3\n"
    198          "call   *%4\n"
    199          : "=a" (result)
    200          : "a" (endPaintSysCall), "g" (lpPaint), "g" (hWnd), "m" (endPaint)
    201         );
    202     return result;
    203 #elif defined (_M_IX86)
    204     // Call through to the original EndPaint.
    205     __asm   mov     eax, endPaintSysCall
    206     __asm   push    lpPaint
    207     __asm   push    hWnd
    208     __asm   call    endPaint
    209 #else
    210     return _HEndPaint(hWnd, lpPaint);
    211 #endif
    212 }
    213 
    214 static void hook(const char* module, const char* proc, unsigned& sysCallID, BYTE*& pProc, const void* pNewProc)
    215 {
    216     // See <http://www.fengyuan.com/article/wmprint.html> for an explanation of
    217     // how this function works.
    218 
    219     HINSTANCE hMod = GetModuleHandleA(module);
    220 
    221     pProc = reinterpret_cast<BYTE*>(reinterpret_cast<ptrdiff_t>(GetProcAddress(hMod, proc)));
    222 
    223 #if COMPILER(GCC) || defined(_M_IX86)
    224     if (pProc[0] != 0xB8)
    225         return;
    226 
    227     // FIXME: Should we be reading the bytes one-by-one instead of doing an
    228     // unaligned read?
    229     sysCallID = *reinterpret_cast<unsigned*>(pProc + 1);
    230 
    231     DWORD flOldProtect;
    232     if (!VirtualProtect(pProc, 5, PAGE_EXECUTE_READWRITE, &flOldProtect))
    233         return;
    234 
    235     pProc[0] = 0xE9;
    236     *reinterpret_cast<unsigned*>(pProc + 1) = reinterpret_cast<intptr_t>(pNewProc) - reinterpret_cast<intptr_t>(pProc + 5);
    237 
    238     pProc += 5;
    239 #else
    240     /* Disassembly of BeginPaint()
    241     00000000779FC5B0 4C 8B D1         mov         r10,rcx
    242     00000000779FC5B3 B8 17 10 00 00   mov         eax,1017h
    243     00000000779FC5B8 0F 05            syscall
    244     00000000779FC5BA C3               ret
    245     00000000779FC5BB 90               nop
    246     00000000779FC5BC 90               nop
    247     00000000779FC5BD 90               nop
    248     00000000779FC5BE 90               nop
    249     00000000779FC5BF 90               nop
    250     00000000779FC5C0 90               nop
    251     00000000779FC5C1 90               nop
    252     00000000779FC5C2 90               nop
    253     00000000779FC5C3 90               nop
    254     */
    255     // Check for the signature as in the above disassembly
    256     DWORD guard = 0xB8D18B4C;
    257     if (*reinterpret_cast<DWORD*>(pProc) != guard)
    258         return;
    259 
    260     DWORD flOldProtect;
    261     VirtualProtect(pProc, 12, PAGE_EXECUTE_READWRITE, & flOldProtect);
    262     pProc[0] = 0x48;    // mov rax, this
    263     pProc[1] = 0xb8;
    264     *(__int64*)(pProc+2) = (__int64)pNewProc;
    265     pProc[10] = 0xff;   // jmp rax
    266     pProc[11] = 0xe0;
    267 #endif
    268 }
    269 
    270 static void setUpOffscreenPaintingHooks(HDC (WINAPI*hookedBeginPaint)(HWND, PAINTSTRUCT*), BOOL (WINAPI*hookedEndPaint)(HWND, const PAINTSTRUCT*))
    271 {
    272     static bool haveHooked = false;
    273     if (haveHooked)
    274         return;
    275     haveHooked = true;
    276 
    277     // Most (all?) windowed plugins don't seem to respond to WM_PRINTCLIENT, so
    278     // we hook into BeginPaint/EndPaint to allow their normal WM_PAINT handling
    279     // to draw into a given HDC. Note that this hooking affects the entire
    280     // process.
    281     hook("user32.dll", "BeginPaint", beginPaintSysCall, beginPaint, reinterpret_cast<const void *>(reinterpret_cast<ptrdiff_t>(hookedBeginPaint)));
    282     hook("user32.dll", "EndPaint", endPaintSysCall, endPaint, reinterpret_cast<const void *>(reinterpret_cast<ptrdiff_t>(hookedEndPaint)));
    283 
    284 }
    285 #endif
    286 
    287 static bool registerPluginView()
    288 {
    289     static bool haveRegisteredWindowClass = false;
    290     if (haveRegisteredWindowClass)
    291         return true;
    292 
    293     haveRegisteredWindowClass = true;
    294 
    295 #if PLATFORM(QT)
    296     WebCore::setInstanceHandle((HINSTANCE)(qWinAppInst()));
    297 #endif
    298 
    299     ASSERT(WebCore::instanceHandle());
    300 
    301 #if OS(WINCE)
    302     WNDCLASS wcex = { 0 };
    303 #else
    304     WNDCLASSEX wcex;
    305     wcex.cbSize = sizeof(WNDCLASSEX);
    306     wcex.hIconSm        = 0;
    307 #endif
    308 
    309     wcex.style          = CS_DBLCLKS;
    310 #if OS(WINCE)
    311     wcex.style          |= CS_PARENTDC;
    312 #endif
    313     wcex.lpfnWndProc    = DefWindowProc;
    314     wcex.cbClsExtra     = 0;
    315     wcex.cbWndExtra     = 0;
    316     wcex.hInstance      = WebCore::instanceHandle();
    317     wcex.hIcon          = 0;
    318     wcex.hCursor        = LoadCursor(0, IDC_ARROW);
    319     wcex.hbrBackground  = (HBRUSH)COLOR_WINDOW;
    320     wcex.lpszMenuName   = 0;
    321     wcex.lpszClassName  = kWebPluginViewdowClassName;
    322 
    323 #if OS(WINCE)
    324     return !!RegisterClass(&wcex);
    325 #else
    326     return !!RegisterClassEx(&wcex);
    327 #endif
    328 }
    329 
    330 LRESULT CALLBACK PluginView::PluginViewWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    331 {
    332     PluginView* pluginView = reinterpret_cast<PluginView*>(GetProp(hWnd, kWebPluginViewProperty));
    333 
    334     return pluginView->wndProc(hWnd, message, wParam, lParam);
    335 }
    336 
    337 static bool isWindowsMessageUserGesture(UINT message)
    338 {
    339     switch (message) {
    340         case WM_LBUTTONUP:
    341         case WM_MBUTTONUP:
    342         case WM_RBUTTONUP:
    343         case WM_KEYUP:
    344             return true;
    345         default:
    346             return false;
    347     }
    348 }
    349 
    350 LRESULT
    351 PluginView::wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    352 {
    353     // <rdar://5711136> Sometimes Flash will call SetCapture before creating
    354     // a full-screen window and will not release it, which causes the
    355     // full-screen window to never receive mouse events. We set/release capture
    356     // on mouse down/up before sending the event to the plug-in to prevent that.
    357     switch (message) {
    358         case WM_LBUTTONDOWN:
    359         case WM_MBUTTONDOWN:
    360         case WM_RBUTTONDOWN:
    361             ::SetCapture(hWnd);
    362             break;
    363         case WM_LBUTTONUP:
    364         case WM_MBUTTONUP:
    365         case WM_RBUTTONUP:
    366             ::ReleaseCapture();
    367             break;
    368     }
    369 
    370     if (message == m_lastMessage &&
    371         m_plugin->quirks().contains(PluginQuirkDontCallWndProcForSameMessageRecursively) &&
    372         m_isCallingPluginWndProc)
    373         return 1;
    374 
    375     if (message == WM_USER + 1 &&
    376         m_plugin->quirks().contains(PluginQuirkThrottleWMUserPlusOneMessages)) {
    377         if (!m_messageThrottler)
    378             m_messageThrottler.set(new PluginMessageThrottlerWin(this));
    379 
    380         m_messageThrottler->appendMessage(hWnd, message, wParam, lParam);
    381         return 0;
    382     }
    383 
    384     m_lastMessage = message;
    385     m_isCallingPluginWndProc = true;
    386 
    387     // If the plug-in doesn't explicitly support changing the pop-up state, we enable
    388     // popups for all user gestures.
    389     // Note that we need to pop the state in a timer, because the Flash plug-in
    390     // pops up windows in response to a posted message.
    391     if (m_plugin->pluginFuncs()->version < NPVERS_HAS_POPUPS_ENABLED_STATE &&
    392         isWindowsMessageUserGesture(message) && !m_popPopupsStateTimer.isActive()) {
    393 
    394         pushPopupsEnabledState(true);
    395 
    396         m_popPopupsStateTimer.startOneShot(0);
    397     }
    398 
    399 #if !OS(WINCE)
    400     if (message == WM_PRINTCLIENT) {
    401         // Most (all?) windowed plugins don't respond to WM_PRINTCLIENT, so we
    402         // change the message to WM_PAINT and rely on our hooked versions of
    403         // BeginPaint/EndPaint to make the plugin draw into the given HDC.
    404         message = WM_PAINT;
    405         m_wmPrintHDC = reinterpret_cast<HDC>(wParam);
    406     }
    407 #endif
    408 
    409     // Call the plug-in's window proc.
    410     LRESULT result = ::CallWindowProc(m_pluginWndProc, hWnd, message, wParam, lParam);
    411 
    412     m_wmPrintHDC = 0;
    413 
    414     m_isCallingPluginWndProc = false;
    415 
    416     return result;
    417 }
    418 
    419 void PluginView::updatePluginWidget()
    420 {
    421     if (!parent())
    422         return;
    423 
    424     ASSERT(parent()->isFrameView());
    425     FrameView* frameView = static_cast<FrameView*>(parent());
    426 
    427     IntRect oldWindowRect = m_windowRect;
    428     IntRect oldClipRect = m_clipRect;
    429 
    430 #if OS(WINCE)
    431     m_windowRect = frameView->contentsToWindow(frameRect());
    432 #else
    433     m_windowRect = IntRect(frameView->contentsToWindow(frameRect().location()), frameRect().size());
    434 #endif
    435     m_clipRect = windowClipRect();
    436     m_clipRect.move(-m_windowRect.x(), -m_windowRect.y());
    437 
    438     if (platformPluginWidget() && (!m_haveUpdatedPluginWidget || m_windowRect != oldWindowRect || m_clipRect != oldClipRect)) {
    439         HRGN rgn;
    440 
    441         setCallingPlugin(true);
    442 
    443         // To prevent flashes while scrolling, we disable drawing during the window
    444         // update process by clipping the window to the zero rect.
    445 
    446         bool clipToZeroRect = !m_plugin->quirks().contains(PluginQuirkDontClipToZeroRectWhenScrolling);
    447 
    448         if (clipToZeroRect) {
    449             rgn = ::CreateRectRgn(0, 0, 0, 0);
    450             ::SetWindowRgn(platformPluginWidget(), rgn, FALSE);
    451         } else {
    452             rgn = ::CreateRectRgn(m_clipRect.x(), m_clipRect.y(), m_clipRect.maxX(), m_clipRect.maxY());
    453             ::SetWindowRgn(platformPluginWidget(), rgn, TRUE);
    454         }
    455 
    456         if (!m_haveUpdatedPluginWidget || m_windowRect != oldWindowRect)
    457             ::MoveWindow(platformPluginWidget(), m_windowRect.x(), m_windowRect.y(), m_windowRect.width(), m_windowRect.height(), TRUE);
    458 
    459         if (clipToZeroRect) {
    460             rgn = ::CreateRectRgn(m_clipRect.x(), m_clipRect.y(), m_clipRect.maxX(), m_clipRect.maxY());
    461             ::SetWindowRgn(platformPluginWidget(), rgn, TRUE);
    462         }
    463 
    464         setCallingPlugin(false);
    465 
    466         m_haveUpdatedPluginWidget = true;
    467     }
    468 }
    469 
    470 void PluginView::setFocus(bool focused)
    471 {
    472     if (focused && platformPluginWidget())
    473         SetFocus(platformPluginWidget());
    474 
    475     Widget::setFocus(focused);
    476 }
    477 
    478 void PluginView::show()
    479 {
    480     setSelfVisible(true);
    481 
    482     if (isParentVisible() && platformPluginWidget())
    483         ShowWindow(platformPluginWidget(), SW_SHOWNA);
    484 
    485     Widget::show();
    486 }
    487 
    488 void PluginView::hide()
    489 {
    490     setSelfVisible(false);
    491 
    492     if (isParentVisible() && platformPluginWidget())
    493         ShowWindow(platformPluginWidget(), SW_HIDE);
    494 
    495     Widget::hide();
    496 }
    497 
    498 bool PluginView::dispatchNPEvent(NPEvent& npEvent)
    499 {
    500     if (!m_plugin->pluginFuncs()->event)
    501         return true;
    502 
    503     bool shouldPop = false;
    504 
    505     if (m_plugin->pluginFuncs()->version < NPVERS_HAS_POPUPS_ENABLED_STATE && isWindowsMessageUserGesture(npEvent.event)) {
    506         pushPopupsEnabledState(true);
    507         shouldPop = true;
    508     }
    509 
    510     JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
    511     setCallingPlugin(true);
    512     bool result = m_plugin->pluginFuncs()->event(m_instance, &npEvent);
    513     setCallingPlugin(false);
    514 
    515     if (shouldPop)
    516         popPopupsEnabledState();
    517 
    518     return result;
    519 }
    520 
    521 void PluginView::paintIntoTransformedContext(HDC hdc)
    522 {
    523     if (m_isWindowed) {
    524 #if !OS(WINCE)
    525         SendMessage(platformPluginWidget(), WM_PRINTCLIENT, reinterpret_cast<WPARAM>(hdc), PRF_CLIENT | PRF_CHILDREN | PRF_OWNED);
    526 #endif
    527         return;
    528     }
    529 
    530     m_npWindow.type = NPWindowTypeDrawable;
    531     m_npWindow.window = hdc;
    532 
    533     WINDOWPOS windowpos = { 0, 0, 0, 0, 0, 0, 0 };
    534 
    535     IntRect r = static_cast<FrameView*>(parent())->contentsToWindow(frameRect());
    536 
    537     windowpos.x = r.x();
    538     windowpos.y = r.y();
    539     windowpos.cx = r.width();
    540     windowpos.cy = r.height();
    541 
    542     NPEvent npEvent;
    543     npEvent.event = WM_WINDOWPOSCHANGED;
    544     npEvent.lParam = reinterpret_cast<uintptr_t>(&windowpos);
    545     npEvent.wParam = 0;
    546 
    547     dispatchNPEvent(npEvent);
    548 
    549     setNPWindowRect(frameRect());
    550 
    551     npEvent.event = WM_PAINT;
    552     npEvent.wParam = reinterpret_cast<uintptr_t>(hdc);
    553 
    554     // This is supposed to be a pointer to the dirty rect, but it seems that the Flash plugin
    555     // ignores it so we just pass null.
    556     npEvent.lParam = 0;
    557 
    558     dispatchNPEvent(npEvent);
    559 }
    560 
    561 void PluginView::paintWindowedPluginIntoContext(GraphicsContext* context, const IntRect& rect)
    562 {
    563 #if !OS(WINCE)
    564     ASSERT(m_isWindowed);
    565     ASSERT(context->shouldIncludeChildWindows());
    566 
    567     ASSERT(parent()->isFrameView());
    568     IntPoint locationInWindow = static_cast<FrameView*>(parent())->contentsToWindow(frameRect().location());
    569 
    570     LocalWindowsContext windowsContext(context, frameRect(), false);
    571 
    572 #if USE(CAIRO)
    573     // Must flush drawings up to this point to the backing metafile, otherwise the
    574     // plugin region will be overwritten with any clear regions specified in the
    575     // cairo-controlled portions of the rendering.
    576     cairo_show_page(context->platformContext()->cr());
    577 #endif
    578 
    579     HDC hdc = windowsContext.hdc();
    580     XFORM originalTransform;
    581     GetWorldTransform(hdc, &originalTransform);
    582 
    583     // The plugin expects the DC to be in client coordinates, so we translate
    584     // the DC to make that so.
    585     AffineTransform ctm = context->getCTM();
    586     ctm.translate(locationInWindow.x(), locationInWindow.y());
    587     XFORM transform = static_cast<XFORM>(ctm.toTransformationMatrix());
    588 
    589     SetWorldTransform(hdc, &transform);
    590 
    591     paintIntoTransformedContext(hdc);
    592 
    593     SetWorldTransform(hdc, &originalTransform);
    594 #endif
    595 }
    596 
    597 void PluginView::paint(GraphicsContext* context, const IntRect& rect)
    598 {
    599     if (!m_isStarted) {
    600         // Draw the "missing plugin" image
    601         paintMissingPluginIcon(context, rect);
    602         return;
    603     }
    604 
    605     if (context->paintingDisabled())
    606         return;
    607 
    608     // Ensure that we have called SetWindow before we try to paint.
    609     if (!m_haveCalledSetWindow)
    610         setNPWindowRect(frameRect());
    611 
    612     if (m_isWindowed) {
    613 #if !OS(WINCE)
    614         if (context->shouldIncludeChildWindows())
    615             paintWindowedPluginIntoContext(context, rect);
    616 #endif
    617         return;
    618     }
    619 
    620     ASSERT(parent()->isFrameView());
    621     IntRect rectInWindow = static_cast<FrameView*>(parent())->contentsToWindow(frameRect());
    622     LocalWindowsContext windowsContext(context, rectInWindow, m_isTransparent);
    623 
    624     // On Safari/Windows without transparency layers the GraphicsContext returns the HDC
    625     // of the window and the plugin expects that the passed in DC has window coordinates.
    626     // In the Qt port we always draw in an offscreen buffer and therefore need to preserve
    627     // the translation set in getWindowsContext.
    628 #if !PLATFORM(QT) && !OS(WINCE)
    629     if (!context->inTransparencyLayer()) {
    630         XFORM transform;
    631         GetWorldTransform(windowsContext.hdc(), &transform);
    632         transform.eDx = 0;
    633         transform.eDy = 0;
    634         SetWorldTransform(windowsContext.hdc(), &transform);
    635     }
    636 #endif
    637 
    638     paintIntoTransformedContext(windowsContext.hdc());
    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.maxX(), rect.maxY() };
    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.maxX(), r.maxY() };
    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) && !OS(WINCE)
   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
   1081