WebCore/plugins/win/PluginViewWin.cpp
changeset 0 4f2f89ce4247
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WebCore/plugins/win/PluginViewWin.cpp	Fri Sep 17 09:02:29 2010 +0300
@@ -0,0 +1,1080 @@
+/*
+ * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Collabora Ltd. All rights reserved.
+ * Copyright (C) 2008-2009 Torch Mobile, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include "config.h"
+#include "PluginView.h"
+
+#include "BitmapImage.h"
+#include "Bridge.h"
+#include "Chrome.h"
+#include "ChromeClient.h"
+#include "Document.h"
+#include "DocumentLoader.h"
+#include "Element.h"
+#include "EventNames.h"
+#include "FocusController.h"
+#include "Frame.h"
+#include "FrameLoadRequest.h"
+#include "FrameLoader.h"
+#include "FrameTree.h"
+#include "FrameView.h"
+#include "GraphicsContext.h"
+#include "HTMLNames.h"
+#include "HTMLPlugInElement.h"
+#include "HostWindow.h"
+#include "Image.h"
+#include "JSDOMBinding.h"
+#include "JSDOMWindow.h"
+#include "KeyboardEvent.h"
+#include "MIMETypeRegistry.h"
+#include "MouseEvent.h"
+#include "Page.h"
+#include "PlatformMouseEvent.h"
+#include "PluginDatabase.h"
+#include "PluginDebug.h"
+#include "PluginMainThreadScheduler.h"
+#include "PluginMessageThrottlerWin.h"
+#include "PluginPackage.h"
+#include "RenderWidget.h"
+#include "ScriptController.h"
+#include "Settings.h"
+#include "WebCoreInstanceHandle.h"
+#include "c_instance.h"
+#include "npruntime_impl.h"
+#include "runtime_root.h"
+#include <runtime/JSLock.h>
+#include <runtime/JSValue.h>
+#include <wtf/ASCIICType.h>
+
+#if !PLATFORM(WX)
+#include "BitmapInfo.h"
+#endif
+
+#if OS(WINCE)
+#undef LOG_NPERROR
+#define LOG_NPERROR(x)
+#undef LOG_PLUGIN_NET_ERROR
+#define LOG_PLUGIN_NET_ERROR()
+#endif
+
+#if PLATFORM(CAIRO)
+#include <cairo-win32.h>
+#endif
+
+#if PLATFORM(QT)
+#include "QWebPageClient.h"
+#include <QWidget>
+#endif
+
+#if PLATFORM(WX)
+#include <wx/defs.h>
+#include <wx/window.h>
+#endif
+
+static inline HWND windowHandleForPageClient(PlatformPageClient client)
+{
+#if PLATFORM(QT)
+    if (!client)
+        return 0;
+    if (QWidget* pluginParent = qobject_cast<QWidget*>(client->pluginParent()))
+        return pluginParent->winId();
+    return 0;
+#elif PLATFORM(WX)
+    if (!client)
+        return 0;
+    return (HWND)client->GetHandle();
+#else
+    return client;
+#endif
+}
+
+using JSC::ExecState;
+using JSC::JSLock;
+using JSC::JSObject;
+using JSC::UString;
+
+using std::min;
+
+using namespace WTF;
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+const LPCWSTR kWebPluginViewdowClassName = L"WebPluginView";
+const LPCWSTR kWebPluginViewProperty = L"WebPluginViewProperty";
+
+#if !OS(WINCE)
+// The code used to hook BeginPaint/EndPaint originally came from
+// <http://www.fengyuan.com/article/wmprint.html>.
+// Copyright (C) 2000 by Feng Yuan (www.fengyuan.com).
+
+static unsigned beginPaintSysCall;
+static BYTE* beginPaint;
+
+static unsigned endPaintSysCall;
+static BYTE* endPaint;
+
+typedef HDC (WINAPI *PtrBeginPaint)(HWND, PAINTSTRUCT*);
+typedef BOOL (WINAPI *PtrEndPaint)(HWND, const PAINTSTRUCT*);
+
+#if OS(WINDOWS) && CPU(X86_64) && COMPILER(MSVC)
+extern "C" HDC __stdcall _HBeginPaint(HWND hWnd, LPPAINTSTRUCT lpPaint);
+extern "C" BOOL __stdcall _HEndPaint(HWND hWnd, const PAINTSTRUCT* lpPaint);
+#endif
+
+HDC WINAPI PluginView::hookedBeginPaint(HWND hWnd, PAINTSTRUCT* lpPaint)
+{
+    PluginView* pluginView = reinterpret_cast<PluginView*>(GetProp(hWnd, kWebPluginViewProperty));
+    if (pluginView && pluginView->m_wmPrintHDC) {
+        // We're secretly handling WM_PRINTCLIENT, so set up the PAINTSTRUCT so
+        // that the plugin will paint into the HDC we provide.
+        memset(lpPaint, 0, sizeof(PAINTSTRUCT));
+        lpPaint->hdc = pluginView->m_wmPrintHDC;
+        GetClientRect(hWnd, &lpPaint->rcPaint);
+        return pluginView->m_wmPrintHDC;
+    }
+
+#if COMPILER(GCC)
+    HDC result;
+    asm ("push    %2\n"
+         "push    %3\n"
+         "call    *%4\n"
+         : "=a" (result)
+         : "a" (beginPaintSysCall), "g" (lpPaint), "g" (hWnd), "m" (beginPaint)
+         : "memory"
+        );
+    return result;
+#elif defined(_M_IX86)
+    // Call through to the original BeginPaint.
+    __asm   mov     eax, beginPaintSysCall
+    __asm   push    lpPaint
+    __asm   push    hWnd
+    __asm   call    beginPaint
+#else
+    return _HBeginPaint(hWnd, lpPaint);
+#endif
+}
+
+BOOL WINAPI PluginView::hookedEndPaint(HWND hWnd, const PAINTSTRUCT* lpPaint)
+{
+    PluginView* pluginView = reinterpret_cast<PluginView*>(GetProp(hWnd, kWebPluginViewProperty));
+    if (pluginView && pluginView->m_wmPrintHDC) {
+        // We're secretly handling WM_PRINTCLIENT, so we don't have to do any
+        // cleanup.
+        return TRUE;
+    }
+
+#if COMPILER(GCC)
+    BOOL result;
+    asm ("push   %2\n"
+         "push   %3\n"
+         "call   *%4\n"
+         : "=a" (result)
+         : "a" (endPaintSysCall), "g" (lpPaint), "g" (hWnd), "m" (endPaint)
+        );
+    return result;
+#elif defined (_M_IX86)
+    // Call through to the original EndPaint.
+    __asm   mov     eax, endPaintSysCall
+    __asm   push    lpPaint
+    __asm   push    hWnd
+    __asm   call    endPaint
+#else
+    return _HEndPaint(hWnd, lpPaint);
+#endif
+}
+
+static void hook(const char* module, const char* proc, unsigned& sysCallID, BYTE*& pProc, const void* pNewProc)
+{
+    // See <http://www.fengyuan.com/article/wmprint.html> for an explanation of
+    // how this function works.
+
+    HINSTANCE hMod = GetModuleHandleA(module);
+
+    pProc = reinterpret_cast<BYTE*>(reinterpret_cast<ptrdiff_t>(GetProcAddress(hMod, proc)));
+
+#if COMPILER(GCC) || defined(_M_IX86)
+    if (pProc[0] != 0xB8)
+        return;
+
+    // FIXME: Should we be reading the bytes one-by-one instead of doing an
+    // unaligned read?
+    sysCallID = *reinterpret_cast<unsigned*>(pProc + 1);
+
+    DWORD flOldProtect;
+    if (!VirtualProtect(pProc, 5, PAGE_EXECUTE_READWRITE, &flOldProtect))
+        return;
+
+    pProc[0] = 0xE9;
+    *reinterpret_cast<unsigned*>(pProc + 1) = reinterpret_cast<intptr_t>(pNewProc) - reinterpret_cast<intptr_t>(pProc + 5);
+
+    pProc += 5;
+#else
+    /* Disassembly of BeginPaint()
+    00000000779FC5B0 4C 8B D1         mov         r10,rcx
+    00000000779FC5B3 B8 17 10 00 00   mov         eax,1017h
+    00000000779FC5B8 0F 05            syscall
+    00000000779FC5BA C3               ret
+    00000000779FC5BB 90               nop
+    00000000779FC5BC 90               nop
+    00000000779FC5BD 90               nop
+    00000000779FC5BE 90               nop
+    00000000779FC5BF 90               nop
+    00000000779FC5C0 90               nop
+    00000000779FC5C1 90               nop
+    00000000779FC5C2 90               nop
+    00000000779FC5C3 90               nop
+    */
+    // Check for the signature as in the above disassembly
+    DWORD guard = 0xB8D18B4C;
+    if (*reinterpret_cast<DWORD*>(pProc) != guard)
+        return;
+
+    DWORD flOldProtect;
+    VirtualProtect(pProc, 12, PAGE_EXECUTE_READWRITE, & flOldProtect);
+    pProc[0] = 0x48;    // mov rax, this
+    pProc[1] = 0xb8;
+    *(__int64*)(pProc+2) = (__int64)pNewProc;
+    pProc[10] = 0xff;   // jmp rax
+    pProc[11] = 0xe0;
+#endif
+}
+
+static void setUpOffscreenPaintingHooks(HDC (WINAPI*hookedBeginPaint)(HWND, PAINTSTRUCT*), BOOL (WINAPI*hookedEndPaint)(HWND, const PAINTSTRUCT*))
+{
+    static bool haveHooked = false;
+    if (haveHooked)
+        return;
+    haveHooked = true;
+
+    // Most (all?) windowed plugins don't seem to respond to WM_PRINTCLIENT, so
+    // we hook into BeginPaint/EndPaint to allow their normal WM_PAINT handling
+    // to draw into a given HDC. Note that this hooking affects the entire
+    // process.
+    hook("user32.dll", "BeginPaint", beginPaintSysCall, beginPaint, reinterpret_cast<const void *>(reinterpret_cast<ptrdiff_t>(hookedBeginPaint)));
+    hook("user32.dll", "EndPaint", endPaintSysCall, endPaint, reinterpret_cast<const void *>(reinterpret_cast<ptrdiff_t>(hookedEndPaint)));
+
+}
+#endif
+
+static bool registerPluginView()
+{
+    static bool haveRegisteredWindowClass = false;
+    if (haveRegisteredWindowClass)
+        return true;
+
+    haveRegisteredWindowClass = true;
+
+#if PLATFORM(QT)
+    WebCore::setInstanceHandle((HINSTANCE)(qWinAppInst()));
+#endif
+
+    ASSERT(WebCore::instanceHandle());
+
+#if OS(WINCE)
+    WNDCLASS wcex = { 0 };
+#else
+    WNDCLASSEX wcex;
+    wcex.cbSize = sizeof(WNDCLASSEX);
+    wcex.hIconSm        = 0;
+#endif
+
+    wcex.style          = CS_DBLCLKS;
+#if OS(WINCE)
+    wcex.style          |= CS_PARENTDC;
+#endif
+    wcex.lpfnWndProc    = DefWindowProc;
+    wcex.cbClsExtra     = 0;
+    wcex.cbWndExtra     = 0;
+    wcex.hInstance      = WebCore::instanceHandle();
+    wcex.hIcon          = 0;
+    wcex.hCursor        = LoadCursor(0, IDC_ARROW);
+    wcex.hbrBackground  = (HBRUSH)COLOR_WINDOW;
+    wcex.lpszMenuName   = 0;
+    wcex.lpszClassName  = kWebPluginViewdowClassName;
+
+#if OS(WINCE)
+    return !!RegisterClass(&wcex);
+#else
+    return !!RegisterClassEx(&wcex);
+#endif
+}
+
+LRESULT CALLBACK PluginView::PluginViewWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+    PluginView* pluginView = reinterpret_cast<PluginView*>(GetProp(hWnd, kWebPluginViewProperty));
+
+    return pluginView->wndProc(hWnd, message, wParam, lParam);
+}
+
+static bool isWindowsMessageUserGesture(UINT message)
+{
+    switch (message) {
+        case WM_LBUTTONUP:
+        case WM_MBUTTONUP:
+        case WM_RBUTTONUP:
+        case WM_KEYUP:
+            return true;
+        default:
+            return false;
+    }
+}
+
+LRESULT
+PluginView::wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+    // <rdar://5711136> Sometimes Flash will call SetCapture before creating
+    // a full-screen window and will not release it, which causes the
+    // full-screen window to never receive mouse events. We set/release capture
+    // on mouse down/up before sending the event to the plug-in to prevent that.
+    switch (message) {
+        case WM_LBUTTONDOWN:
+        case WM_MBUTTONDOWN:
+        case WM_RBUTTONDOWN:
+            ::SetCapture(hWnd);
+            break;
+        case WM_LBUTTONUP:
+        case WM_MBUTTONUP:
+        case WM_RBUTTONUP:
+            ::ReleaseCapture();
+            break;
+    }
+
+    if (message == m_lastMessage &&
+        m_plugin->quirks().contains(PluginQuirkDontCallWndProcForSameMessageRecursively) && 
+        m_isCallingPluginWndProc)
+        return 1;
+
+    if (message == WM_USER + 1 &&
+        m_plugin->quirks().contains(PluginQuirkThrottleWMUserPlusOneMessages)) {
+        if (!m_messageThrottler)
+            m_messageThrottler.set(new PluginMessageThrottlerWin(this));
+
+        m_messageThrottler->appendMessage(hWnd, message, wParam, lParam);
+        return 0;
+    }
+
+    m_lastMessage = message;
+    m_isCallingPluginWndProc = true;
+
+    // If the plug-in doesn't explicitly support changing the pop-up state, we enable
+    // popups for all user gestures.
+    // Note that we need to pop the state in a timer, because the Flash plug-in 
+    // pops up windows in response to a posted message.
+    if (m_plugin->pluginFuncs()->version < NPVERS_HAS_POPUPS_ENABLED_STATE &&
+        isWindowsMessageUserGesture(message) && !m_popPopupsStateTimer.isActive()) {
+
+        pushPopupsEnabledState(true);
+
+        m_popPopupsStateTimer.startOneShot(0);
+    }
+
+#if !OS(WINCE)
+    if (message == WM_PRINTCLIENT) {
+        // Most (all?) windowed plugins don't respond to WM_PRINTCLIENT, so we
+        // change the message to WM_PAINT and rely on our hooked versions of
+        // BeginPaint/EndPaint to make the plugin draw into the given HDC.
+        message = WM_PAINT;
+        m_wmPrintHDC = reinterpret_cast<HDC>(wParam);
+    }
+#endif
+
+    // Call the plug-in's window proc.
+    LRESULT result = ::CallWindowProc(m_pluginWndProc, hWnd, message, wParam, lParam);
+
+    m_wmPrintHDC = 0;
+
+    m_isCallingPluginWndProc = false;
+
+    return result;
+}
+
+void PluginView::updatePluginWidget()
+{
+    if (!parent())
+        return;
+
+    ASSERT(parent()->isFrameView());
+    FrameView* frameView = static_cast<FrameView*>(parent());
+
+    IntRect oldWindowRect = m_windowRect;
+    IntRect oldClipRect = m_clipRect;
+
+#if OS(WINCE)
+    m_windowRect = frameView->contentsToWindow(frameRect());
+#else
+    m_windowRect = IntRect(frameView->contentsToWindow(frameRect().location()), frameRect().size());
+#endif
+    m_clipRect = windowClipRect();
+    m_clipRect.move(-m_windowRect.x(), -m_windowRect.y());
+
+    if (platformPluginWidget() && (!m_haveUpdatedPluginWidget || m_windowRect != oldWindowRect || m_clipRect != oldClipRect)) {
+        HRGN rgn;
+
+        setCallingPlugin(true);
+
+        // To prevent flashes while scrolling, we disable drawing during the window
+        // update process by clipping the window to the zero rect.
+
+        bool clipToZeroRect = !m_plugin->quirks().contains(PluginQuirkDontClipToZeroRectWhenScrolling);
+
+        if (clipToZeroRect) {
+            rgn = ::CreateRectRgn(0, 0, 0, 0);
+            ::SetWindowRgn(platformPluginWidget(), rgn, FALSE);
+        } else {
+            rgn = ::CreateRectRgn(m_clipRect.x(), m_clipRect.y(), m_clipRect.right(), m_clipRect.bottom());
+            ::SetWindowRgn(platformPluginWidget(), rgn, TRUE);
+        }
+
+        if (!m_haveUpdatedPluginWidget || m_windowRect != oldWindowRect)
+            ::MoveWindow(platformPluginWidget(), m_windowRect.x(), m_windowRect.y(), m_windowRect.width(), m_windowRect.height(), TRUE);
+
+        if (clipToZeroRect) {
+            rgn = ::CreateRectRgn(m_clipRect.x(), m_clipRect.y(), m_clipRect.right(), m_clipRect.bottom());
+            ::SetWindowRgn(platformPluginWidget(), rgn, TRUE);
+        }
+
+        setCallingPlugin(false);
+
+        m_haveUpdatedPluginWidget = true;
+    }
+}
+
+void PluginView::setFocus(bool focused)
+{
+    if (focused && platformPluginWidget())
+        SetFocus(platformPluginWidget());
+
+    Widget::setFocus(focused);
+}
+
+void PluginView::show()
+{
+    setSelfVisible(true);
+
+    if (isParentVisible() && platformPluginWidget())
+        ShowWindow(platformPluginWidget(), SW_SHOWNA);
+
+    Widget::show();
+}
+
+void PluginView::hide()
+{
+    setSelfVisible(false);
+
+    if (isParentVisible() && platformPluginWidget())
+        ShowWindow(platformPluginWidget(), SW_HIDE);
+
+    Widget::hide();
+}
+
+bool PluginView::dispatchNPEvent(NPEvent& npEvent)
+{
+    if (!m_plugin->pluginFuncs()->event)
+        return true;
+
+    bool shouldPop = false;
+
+    if (m_plugin->pluginFuncs()->version < NPVERS_HAS_POPUPS_ENABLED_STATE && isWindowsMessageUserGesture(npEvent.event)) {
+        pushPopupsEnabledState(true);
+        shouldPop = true;
+    }
+
+    JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
+    setCallingPlugin(true);
+    bool result = m_plugin->pluginFuncs()->event(m_instance, &npEvent);
+    setCallingPlugin(false);
+
+    if (shouldPop) 
+        popPopupsEnabledState();
+
+    return result;
+}
+
+void PluginView::paintIntoTransformedContext(HDC hdc)
+{
+    if (m_isWindowed) {
+        SendMessage(platformPluginWidget(), WM_PRINTCLIENT, reinterpret_cast<WPARAM>(hdc), PRF_CLIENT | PRF_CHILDREN | PRF_OWNED);
+        return;
+    }
+
+    m_npWindow.type = NPWindowTypeDrawable;
+    m_npWindow.window = hdc;
+
+    WINDOWPOS windowpos = { 0, 0, 0, 0, 0, 0, 0 };
+
+    IntRect r = static_cast<FrameView*>(parent())->contentsToWindow(frameRect());
+
+    windowpos.x = r.x();
+    windowpos.y = r.y();
+    windowpos.cx = r.width();
+    windowpos.cy = r.height();
+
+    NPEvent npEvent;
+    npEvent.event = WM_WINDOWPOSCHANGED;
+    npEvent.lParam = reinterpret_cast<uintptr_t>(&windowpos);
+    npEvent.wParam = 0;
+
+    dispatchNPEvent(npEvent);
+
+    setNPWindowRect(frameRect());
+
+    npEvent.event = WM_PAINT;
+    npEvent.wParam = reinterpret_cast<uintptr_t>(hdc);
+
+    // This is supposed to be a pointer to the dirty rect, but it seems that the Flash plugin
+    // ignores it so we just pass null.
+    npEvent.lParam = 0;
+
+    dispatchNPEvent(npEvent);
+}
+
+void PluginView::paintWindowedPluginIntoContext(GraphicsContext* context, const IntRect& rect)
+{
+#if !OS(WINCE)
+    ASSERT(m_isWindowed);
+    ASSERT(context->shouldIncludeChildWindows());
+
+    ASSERT(parent()->isFrameView());
+    IntPoint locationInWindow = static_cast<FrameView*>(parent())->contentsToWindow(frameRect().location());
+
+    HDC hdc = context->getWindowsContext(frameRect(), false);
+
+#if PLATFORM(CAIRO)
+    // Must flush drawings up to this point to the backing metafile, otherwise the
+    // plugin region will be overwritten with any clear regions specified in the
+    // cairo-controlled portions of the rendering.
+    PlatformGraphicsContext* ctx = context->platformContext();
+    cairo_show_page(ctx);
+#endif
+
+    XFORM originalTransform;
+    GetWorldTransform(hdc, &originalTransform);
+
+    // The plugin expects the DC to be in client coordinates, so we translate
+    // the DC to make that so.
+    AffineTransform ctm = context->getCTM();
+    ctm.translate(locationInWindow.x(), locationInWindow.y());
+    XFORM transform = static_cast<XFORM>(ctm.toTransformationMatrix());
+
+    SetWorldTransform(hdc, &transform);
+
+    paintIntoTransformedContext(hdc);
+
+    SetWorldTransform(hdc, &originalTransform);
+
+    context->releaseWindowsContext(hdc, frameRect(), false);
+#endif
+}
+
+void PluginView::paint(GraphicsContext* context, const IntRect& rect)
+{
+    if (!m_isStarted) {
+        // Draw the "missing plugin" image
+        paintMissingPluginIcon(context, rect);
+        return;
+    }
+
+    if (context->paintingDisabled())
+        return;
+
+    // Ensure that we have called SetWindow before we try to paint.
+    if (!m_haveCalledSetWindow)
+        setNPWindowRect(frameRect());
+
+    if (m_isWindowed) {
+#if !OS(WINCE)
+        if (context->shouldIncludeChildWindows())
+            paintWindowedPluginIntoContext(context, rect);
+#endif
+        return;
+    }
+
+    ASSERT(parent()->isFrameView());
+    IntRect rectInWindow = static_cast<FrameView*>(parent())->contentsToWindow(frameRect());
+    HDC hdc = context->getWindowsContext(rectInWindow, m_isTransparent);
+
+    // On Safari/Windows without transparency layers the GraphicsContext returns the HDC
+    // of the window and the plugin expects that the passed in DC has window coordinates.
+    // In the Qt port we always draw in an offscreen buffer and therefore need to preserve
+    // the translation set in getWindowsContext.
+#if !PLATFORM(QT) && !OS(WINCE)
+    if (!context->inTransparencyLayer()) {
+        XFORM transform;
+        GetWorldTransform(hdc, &transform);
+        transform.eDx = 0;
+        transform.eDy = 0;
+        SetWorldTransform(hdc, &transform);
+    }
+#endif
+
+    paintIntoTransformedContext(hdc);
+
+    context->releaseWindowsContext(hdc, frameRect(), m_isTransparent);
+}
+
+void PluginView::handleKeyboardEvent(KeyboardEvent* event)
+{
+    NPEvent npEvent;
+
+    npEvent.wParam = event->keyCode();    
+
+    if (event->type() == eventNames().keydownEvent) {
+        npEvent.event = WM_KEYDOWN;
+        npEvent.lParam = 0;
+    } else if (event->type() == eventNames().keyupEvent) {
+        npEvent.event = WM_KEYUP;
+        npEvent.lParam = 0x8000;
+    }
+
+    JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
+    if (!dispatchNPEvent(npEvent))
+        event->setDefaultHandled();
+}
+
+#if !OS(WINCE)
+extern bool ignoreNextSetCursor;
+#endif
+
+void PluginView::handleMouseEvent(MouseEvent* event)
+{
+    NPEvent npEvent;
+
+    IntPoint p = static_cast<FrameView*>(parent())->contentsToWindow(IntPoint(event->pageX(), event->pageY()));
+
+    npEvent.lParam = MAKELPARAM(p.x(), p.y());
+    npEvent.wParam = 0;
+
+    if (event->ctrlKey())
+        npEvent.wParam |= MK_CONTROL;
+    if (event->shiftKey())
+        npEvent.wParam |= MK_SHIFT;
+
+    if (event->type() == eventNames().mousemoveEvent ||
+        event->type() == eventNames().mouseoutEvent || 
+        event->type() == eventNames().mouseoverEvent) {
+        npEvent.event = WM_MOUSEMOVE;
+        if (event->buttonDown())
+            switch (event->button()) {
+                case LeftButton:
+                    npEvent.wParam |= MK_LBUTTON;
+                    break;
+                case MiddleButton:
+                    npEvent.wParam |= MK_MBUTTON;
+                    break;
+                case RightButton:
+                    npEvent.wParam |= MK_RBUTTON;
+                break;
+            }
+    }
+    else if (event->type() == eventNames().mousedownEvent) {
+        focusPluginElement();
+        switch (event->button()) {
+            case 0:
+                npEvent.event = WM_LBUTTONDOWN;
+                break;
+            case 1:
+                npEvent.event = WM_MBUTTONDOWN;
+                break;
+            case 2:
+                npEvent.event = WM_RBUTTONDOWN;
+                break;
+        }
+    } else if (event->type() == eventNames().mouseupEvent) {
+        switch (event->button()) {
+            case 0:
+                npEvent.event = WM_LBUTTONUP;
+                break;
+            case 1:
+                npEvent.event = WM_MBUTTONUP;
+                break;
+            case 2:
+                npEvent.event = WM_RBUTTONUP;
+                break;
+        }
+    } else
+        return;
+
+    JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
+    if (!dispatchNPEvent(npEvent))
+        event->setDefaultHandled();
+
+#if !PLATFORM(QT) && !PLATFORM(WX) && !OS(WINCE)
+    // Currently, Widget::setCursor is always called after this function in EventHandler.cpp
+    // and since we don't want that we set ignoreNextSetCursor to true here to prevent that.
+    ignoreNextSetCursor = true;
+    if (Page* page = m_parentFrame->page())
+        page->chrome()->client()->setLastSetCursorToCurrentCursor();    
+#endif
+}
+
+void PluginView::setParent(ScrollView* parent)
+{
+    Widget::setParent(parent);
+
+#if OS(WINCE)
+    if (parent) {
+        init();
+        if (parent->isVisible())
+            show();
+        else
+            hide();
+    }
+#else
+    if (parent)
+        init();
+    else {
+        if (!platformPluginWidget())
+            return;
+
+        // If the plug-in window or one of its children have the focus, we need to 
+        // clear it to prevent the web view window from being focused because that can
+        // trigger a layout while the plugin element is being detached.
+        HWND focusedWindow = ::GetFocus();
+        if (platformPluginWidget() == focusedWindow || ::IsChild(platformPluginWidget(), focusedWindow))
+            ::SetFocus(0);
+    }
+#endif
+}
+
+void PluginView::setParentVisible(bool visible)
+{
+    if (isParentVisible() == visible)
+        return;
+
+    Widget::setParentVisible(visible);
+
+    if (isSelfVisible() && platformPluginWidget()) {
+        if (visible)
+            ShowWindow(platformPluginWidget(), SW_SHOWNA);
+        else
+            ShowWindow(platformPluginWidget(), SW_HIDE);
+    }
+}
+
+void PluginView::setNPWindowRect(const IntRect& rect)
+{
+    if (!m_isStarted)
+        return;
+
+#if OS(WINCE)
+    IntRect r = static_cast<FrameView*>(parent())->contentsToWindow(rect);
+    m_npWindow.x = r.x();
+    m_npWindow.y = r.y();
+
+    m_npWindow.width = r.width();
+    m_npWindow.height = r.height();
+
+    m_npWindow.clipRect.right = r.width();
+    m_npWindow.clipRect.bottom = r.height();
+#else
+    IntPoint p = static_cast<FrameView*>(parent())->contentsToWindow(rect.location());
+    m_npWindow.x = p.x();
+    m_npWindow.y = p.y();
+
+    m_npWindow.width = rect.width();
+    m_npWindow.height = rect.height();
+
+    m_npWindow.clipRect.right = rect.width();
+    m_npWindow.clipRect.bottom = rect.height();
+#endif
+    m_npWindow.clipRect.left = 0;
+    m_npWindow.clipRect.top = 0;
+
+    if (m_plugin->pluginFuncs()->setwindow) {
+        JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
+        setCallingPlugin(true);
+        m_plugin->pluginFuncs()->setwindow(m_instance, &m_npWindow);
+        setCallingPlugin(false);
+
+        m_haveCalledSetWindow = true;
+
+        if (!m_isWindowed)
+            return;
+
+        ASSERT(platformPluginWidget());
+
+#if OS(WINCE)
+        if (!m_pluginWndProc) {
+            WNDPROC currentWndProc = (WNDPROC)GetWindowLong(platformPluginWidget(), GWL_WNDPROC);
+            if (currentWndProc != PluginViewWndProc)
+                m_pluginWndProc = (WNDPROC)SetWindowLong(platformPluginWidget(), GWL_WNDPROC, (LONG)PluginViewWndProc);
+        }
+#else
+        WNDPROC currentWndProc = (WNDPROC)GetWindowLongPtr(platformPluginWidget(), GWLP_WNDPROC);
+        if (currentWndProc != PluginViewWndProc)
+            m_pluginWndProc = (WNDPROC)SetWindowLongPtr(platformPluginWidget(), GWLP_WNDPROC, (LONG_PTR)PluginViewWndProc);
+#endif
+    }
+}
+
+NPError PluginView::handlePostReadFile(Vector<char>& buffer, uint32_t len, const char* buf)
+{
+    String filename(buf, len);
+
+    if (filename.startsWith("file:///"))
+        filename = filename.substring(8);
+
+    // Get file info
+    WIN32_FILE_ATTRIBUTE_DATA attrs;
+    if (GetFileAttributesExW(filename.charactersWithNullTermination(), GetFileExInfoStandard, &attrs) == 0)
+        return NPERR_FILE_NOT_FOUND;
+
+    if (attrs.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+        return NPERR_FILE_NOT_FOUND;
+
+    HANDLE fileHandle = CreateFileW(filename.charactersWithNullTermination(), FILE_READ_DATA, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
+    
+    if (fileHandle == INVALID_HANDLE_VALUE)
+        return NPERR_FILE_NOT_FOUND;
+
+    buffer.resize(attrs.nFileSizeLow);
+
+    DWORD bytesRead;
+    int retval = ReadFile(fileHandle, buffer.data(), attrs.nFileSizeLow, &bytesRead, 0);
+
+    CloseHandle(fileHandle);
+
+    if (retval == 0 || bytesRead != attrs.nFileSizeLow)
+        return NPERR_FILE_NOT_FOUND;
+
+    return NPERR_NO_ERROR;
+}
+
+bool PluginView::platformGetValueStatic(NPNVariable, void*, NPError*)
+{
+    return false;
+}
+
+bool PluginView::platformGetValue(NPNVariable variable, void* value, NPError* result)
+{
+    switch (variable) {
+        case NPNVnetscapeWindow: {
+            HWND* w = reinterpret_cast<HWND*>(value);
+            *w = windowHandleForPageClient(parent() ? parent()->hostWindow()->platformPageClient() : 0);
+            *result = NPERR_NO_ERROR;
+            return true;
+        }
+
+        case NPNVSupportsWindowless: {
+            NPBool* flag = reinterpret_cast<NPBool*>(value);
+            *flag = TRUE;
+            *result = NPERR_NO_ERROR;
+            return true;
+        }
+
+    default:
+        return false;
+    }
+}
+
+void PluginView::invalidateRect(const IntRect& rect)
+{
+    if (m_isWindowed) {
+        RECT invalidRect = { rect.x(), rect.y(), rect.right(), rect.bottom() };
+        ::InvalidateRect(platformPluginWidget(), &invalidRect, false);
+        return;
+    }
+
+    invalidateWindowlessPluginRect(rect);
+}
+
+void PluginView::invalidateRect(NPRect* rect)
+{
+    if (!rect) {
+        invalidate();
+        return;
+    }
+
+    IntRect r(rect->left, rect->top, rect->right - rect->left, rect->bottom - rect->top);
+
+    if (m_isWindowed) {
+        RECT invalidRect = { r.x(), r.y(), r.right(), r.bottom() };
+        InvalidateRect(platformPluginWidget(), &invalidRect, FALSE);
+    } else {
+        if (m_plugin->quirks().contains(PluginQuirkThrottleInvalidate)) {
+            m_invalidRects.append(r);
+            if (!m_invalidateTimer.isActive())
+                m_invalidateTimer.startOneShot(0.001);
+        } else
+            invalidateRect(r);
+    }
+}
+
+void PluginView::invalidateRegion(NPRegion region)
+{
+    if (m_isWindowed)
+        return;
+
+    RECT r;
+
+    if (GetRgnBox(region, &r) == 0) {
+        invalidate();
+        return;
+    }
+
+    IntRect rect(IntPoint(r.left, r.top), IntSize(r.right-r.left, r.bottom-r.top));
+    invalidateRect(rect);
+}
+
+void PluginView::forceRedraw()
+{
+    if (m_isWindowed)
+        ::UpdateWindow(platformPluginWidget());
+    else
+        ::UpdateWindow(windowHandleForPageClient(parent() ? parent()->hostWindow()->platformPageClient() : 0));
+}
+
+bool PluginView::platformStart()
+{
+    ASSERT(m_isStarted);
+    ASSERT(m_status == PluginStatusLoadedSuccessfully);
+
+    if (m_isWindowed) {
+        registerPluginView();
+#if !OS(WINCE)
+        setUpOffscreenPaintingHooks(hookedBeginPaint, hookedEndPaint);
+#endif
+
+        DWORD flags = WS_CHILD;
+        if (isSelfVisible())
+            flags |= WS_VISIBLE;
+
+        HWND parentWindowHandle = windowHandleForPageClient(m_parentFrame->view()->hostWindow()->platformPageClient());
+        HWND window = ::CreateWindowEx(0, kWebPluginViewdowClassName, 0, flags,
+                                       0, 0, 0, 0, parentWindowHandle, 0, WebCore::instanceHandle(), 0);
+
+#if OS(WINDOWS) && (PLATFORM(QT) || PLATFORM(WX))
+        m_window = window;
+#else
+        setPlatformWidget(window);
+#endif
+
+        // Calling SetWindowLongPtrA here makes the window proc ASCII, which is required by at least
+        // the Shockwave Director plug-in.
+#if OS(WINDOWS) && CPU(X86_64)
+        ::SetWindowLongPtrA(platformPluginWidget(), GWLP_WNDPROC, (LONG_PTR)DefWindowProcA);
+#elif OS(WINCE)
+        ::SetWindowLong(platformPluginWidget(), GWL_WNDPROC, (LONG)DefWindowProc);
+#else
+        ::SetWindowLongPtrA(platformPluginWidget(), GWL_WNDPROC, (LONG)DefWindowProcA);
+#endif
+        SetProp(platformPluginWidget(), kWebPluginViewProperty, this);
+
+        m_npWindow.type = NPWindowTypeWindow;
+        m_npWindow.window = platformPluginWidget();
+    } else {
+        m_npWindow.type = NPWindowTypeDrawable;
+        m_npWindow.window = 0;
+    }
+
+    updatePluginWidget();
+
+    if (!m_plugin->quirks().contains(PluginQuirkDeferFirstSetWindowCall))
+        setNPWindowRect(frameRect());
+
+    return true;
+}
+
+void PluginView::platformDestroy()
+{
+    if (!platformPluginWidget())
+        return;
+
+    DestroyWindow(platformPluginWidget());
+    setPlatformPluginWidget(0);
+}
+
+PassRefPtr<Image> PluginView::snapshot()
+{
+#if !PLATFORM(WX)
+    OwnPtr<HDC> hdc(CreateCompatibleDC(0));
+
+    if (!m_isWindowed) {
+        // Enable world transforms.
+        SetGraphicsMode(hdc.get(), GM_ADVANCED);
+
+        XFORM transform;
+        GetWorldTransform(hdc.get(), &transform);
+
+        // Windowless plug-ins assume that they're drawing onto the view's DC.
+        // Translate the context so that the plug-in draws at (0, 0).
+        ASSERT(parent()->isFrameView());
+        IntPoint position = static_cast<FrameView*>(parent())->contentsToWindow(frameRect()).location();
+        transform.eDx = -position.x();
+        transform.eDy = -position.y();
+        SetWorldTransform(hdc.get(), &transform);
+    }
+
+    void* bits;
+    BitmapInfo bmp = BitmapInfo::createBottomUp(frameRect().size());
+    OwnPtr<HBITMAP> hbmp(CreateDIBSection(0, &bmp, DIB_RGB_COLORS, &bits, 0, 0));
+
+    HBITMAP hbmpOld = static_cast<HBITMAP>(SelectObject(hdc.get(), hbmp.get()));
+
+    paintIntoTransformedContext(hdc.get());
+
+    SelectObject(hdc.get(), hbmpOld);
+
+    return BitmapImage::create(hbmp.get());
+#else
+    return 0;
+#endif
+}
+
+void PluginView::halt()
+{
+    ASSERT(!m_isHalted);
+    ASSERT(m_isStarted);
+
+#if !PLATFORM(QT)
+    // Show a screenshot of the plug-in.
+    toRenderWidget(m_element->renderer())->showSubstituteImage(snapshot());
+#endif
+
+    m_isHalted = true;
+    m_hasBeenHalted = true;
+
+    stop();
+    platformDestroy();
+}
+
+void PluginView::restart()
+{
+    ASSERT(!m_isStarted);
+    ASSERT(m_isHalted);
+
+    // Clear any substitute image.
+    toRenderWidget(m_element->renderer())->showSubstituteImage(0);
+
+    m_isHalted = false;
+    m_haveUpdatedPluginWidget = false;
+    start();
+}
+
+} // namespace WebCore