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 
     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