📄 pluginviewwin.cpp
字号:
/* * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. * Copyright (C) 2008 Collabora Ltd. 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 "Document.h"#include "DocumentLoader.h"#include "Element.h"#include "EventNames.h"#include "FrameLoader.h"#include "FrameLoadRequest.h"#include "FrameTree.h"#include "Frame.h"#include "FrameView.h"#include "GraphicsContext.h"#include "Image.h"#include "HTMLNames.h"#include "HTMLPlugInElement.h"#include "JSDOMWindow.h"#include "KeyboardEvent.h"#include "MIMETypeRegistry.h"#include "MouseEvent.h"#include "NotImplemented.h"#include "Page.h"#include "FocusController.h"#include "PlatformMouseEvent.h"#include "PluginMessageThrottlerWin.h"#include "PluginPackage.h"#include "PluginMainThreadScheduler.h"#include "JSDOMBinding.h"#include "ScriptController.h"#include "PluginDatabase.h"#include "PluginDebug.h"#include "PluginPackage.h"#include "c_instance.h"#include "npruntime_impl.h"#include "runtime_root.h"#include "Settings.h"#include "runtime.h"#include <runtime/JSLock.h>#include <runtime/JSValue.h>#include <wtf/ASCIICType.h>#if PLATFORM(QT)#include <QWidget.h>#endifstatic inline HWND windowHandleForPlatformWidget(PlatformWidget widget){#if PLATFORM(QT) if (!widget) return 0; return widget->winId();#else return widget;#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";static const char* MozillaUserAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1) Gecko/20061010 Firefox/2.0";// 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;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; } // Call through to the original BeginPaint. __asm mov eax, beginPaintSysCall __asm push lpPaint __asm push hWnd __asm call beginPaint}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; } // Call through to the original EndPaint. __asm mov eax, endPaintSysCall __asm push lpPaint __asm push hWnd __asm call endPaint}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*>(GetProcAddress(hMod, proc)); 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;}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, hookedBeginPaint); hook("user32.dll", "EndPaint", endPaintSysCall, endPaint, hookedEndPaint);}static bool registerPluginView(){ static bool haveRegisteredWindowClass = false; if (haveRegisteredWindowClass) return true; haveRegisteredWindowClass = true;#if PLATFORM(QT) Page::setInstanceHandle((HINSTANCE)(qWinAppInst()));#endif ASSERT(Page::instanceHandle()); WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_DBLCLKS; wcex.lpfnWndProc = DefWindowProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = Page::instanceHandle(); wcex.hIcon = 0; wcex.hCursor = LoadCursor(0, IDC_ARROW); wcex.hbrBackground = (HBRUSH)COLOR_WINDOW; wcex.lpszMenuName = 0; wcex.lpszClassName = kWebPluginViewdowClassName; wcex.hIconSm = 0; return !!RegisterClassEx(&wcex);}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; }}LRESULTPluginView::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 (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); } // 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; m_windowRect = IntRect(frameView->contentsToWindow(frameRect().location()), frameRect().size()); m_clipRect = windowClipRect(); m_clipRect.move(-m_windowRect.x(), -m_windowRect.y()); if (platformPluginWidget() && (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_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); }}void PluginView::setFocus(){ if (platformPluginWidget()) SetFocus(platformPluginWidget()); Widget::setFocus();}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(false); setCallingPlugin(true); bool result = m_plugin->pluginFuncs()->event(m_instance, &npEvent); setCallingPlugin(false); if (shouldPop) popPopupsEnabledState(); return result;}void PluginView::paintWindowedPluginIntoContext(GraphicsContext* context, const IntRect& rect) const{ ASSERT(m_isWindowed); ASSERT(context->shouldIncludeChildWindows()); ASSERT(parent()->isFrameView()); IntPoint locationInWindow = static_cast<FrameView*>(parent())->contentsToWindow(frameRect().location()); HDC hdc = context->getWindowsContext(frameRect(), false); XFORM originalTransform; GetWorldTransform(hdc, &originalTransform); // The plugin expects the DC to be in client coordinates, so we translate // the DC to make that so. XFORM transform = originalTransform; transform.eDx = locationInWindow.x(); transform.eDy = locationInWindow.y(); SetWorldTransform(hdc, &transform); SendMessage(platformPluginWidget(), WM_PRINTCLIENT, reinterpret_cast<WPARAM>(hdc), PRF_CLIENT | PRF_CHILDREN | PRF_OWNED); SetWorldTransform(hdc, &originalTransform); context->releaseWindowsContext(hdc, frameRect(), false);}void PluginView::paint(GraphicsContext* context, const IntRect& rect){ if (!m_isStarted) { // Draw the "missing plugin" image paintMissingPluginIcon(context, rect); return; } if (context->paintingDisabled()) return; if (m_isWindowed) { if (context->shouldIncludeChildWindows()) paintWindowedPluginIntoContext(context, rect); return; } ASSERT(parent()->isFrameView()); IntRect rectInWindow = static_cast<FrameView*>(parent())->contentsToWindow(frameRect()); HDC hdc = context->getWindowsContext(rectInWindow, m_isTransparent); NPEvent npEvent; // 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) if (!context->inTransparencyLayer()) { XFORM transform; GetWorldTransform(hdc, &transform); transform.eDx = 0; transform.eDy = 0; SetWorldTransform(hdc, &transform); }#endif m_npWindow.type = NPWindowTypeDrawable; m_npWindow.window = hdc; IntPoint p = static_cast<FrameView*>(parent())->contentsToWindow(frameRect().location()); WINDOWPOS windowpos; memset(&windowpos, 0, sizeof(windowpos)); windowpos.x = p.x(); windowpos.y = p.y(); windowpos.cx = frameRect().width(); windowpos.cy = frameRect().height(); npEvent.event = WM_WINDOWPOSCHANGED; npEvent.lParam = reinterpret_cast<uint32>(&windowpos); npEvent.wParam = 0; dispatchNPEvent(npEvent);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -