Re-apply change 353dcfd307853da289fdd245410e2e07358624a0 by Friedemann Kleint
[qt-netbsd.git] / src / 3rdparty / webkit / WebCore / plugins / win / PluginViewWin.cpp
blobe47796584b5d2f9c97c8c7650a66fb0e3a56a541
1 /*
2 * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Collabora Ltd. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #include "config.h"
29 #include "PluginView.h"
31 #include "Document.h"
32 #include "DocumentLoader.h"
33 #include "Element.h"
34 #include "EventNames.h"
35 #include "FrameLoader.h"
36 #include "FrameLoadRequest.h"
37 #include "FrameTree.h"
38 #include "Frame.h"
39 #include "FrameView.h"
40 #include "GraphicsContext.h"
41 #include "Image.h"
42 #include "HTMLNames.h"
43 #include "HTMLPlugInElement.h"
44 #include "JSDOMWindow.h"
45 #include "KeyboardEvent.h"
46 #include "MIMETypeRegistry.h"
47 #include "MouseEvent.h"
48 #include "Page.h"
49 #include "FocusController.h"
50 #include "PlatformMouseEvent.h"
51 #include "PluginMessageThrottlerWin.h"
52 #include "PluginPackage.h"
53 #include "PluginMainThreadScheduler.h"
54 #include "JSDOMBinding.h"
55 #include "ScriptController.h"
56 #include "PluginDatabase.h"
57 #include "PluginDebug.h"
58 #include "PluginPackage.h"
59 #include "c_instance.h"
60 #include "npruntime_impl.h"
61 #include "runtime_root.h"
62 #include "Settings.h"
63 #include "runtime.h"
64 #include <runtime/JSLock.h>
65 #include <runtime/JSValue.h>
66 #include <wtf/ASCIICType.h>
68 #if PLATFORM(QT)
69 #include <QWidget.h>
70 #endif
72 static inline HWND windowHandleForPlatformWidget(PlatformWidget widget)
74 #if PLATFORM(QT)
75 if (!widget)
76 return 0;
77 return widget->winId();
78 #else
79 return widget;
80 #endif
83 using JSC::ExecState;
84 using JSC::JSLock;
85 using JSC::JSObject;
86 using JSC::UString;
88 using std::min;
90 using namespace WTF;
92 namespace WebCore {
94 using namespace HTMLNames;
96 const LPCWSTR kWebPluginViewdowClassName = L"WebPluginView";
97 const LPCWSTR kWebPluginViewProperty = L"WebPluginViewProperty";
99 static const char* MozillaUserAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1) Gecko/20061010 Firefox/2.0";
101 // The code used to hook BeginPaint/EndPaint originally came from
102 // <http://www.fengyuan.com/article/wmprint.html>.
103 // Copyright (C) 2000 by Feng Yuan (www.fengyuan.com).
105 static unsigned beginPaintSysCall;
106 static BYTE* beginPaint;
108 static unsigned endPaintSysCall;
109 static BYTE* endPaint;
111 HDC WINAPI PluginView::hookedBeginPaint(HWND hWnd, PAINTSTRUCT* lpPaint)
113 #if (COMPILER(MINGW))
114 Q_UNUSED(hWnd)
115 Q_UNUSED(lpPaint)
116 return 0;
117 #else
118 PluginView* pluginView = reinterpret_cast<PluginView*>(GetProp(hWnd, kWebPluginViewProperty));
119 if (pluginView && pluginView->m_wmPrintHDC) {
120 // We're secretly handling WM_PRINTCLIENT, so set up the PAINTSTRUCT so
121 // that the plugin will paint into the HDC we provide.
122 memset(lpPaint, 0, sizeof(PAINTSTRUCT));
123 lpPaint->hdc = pluginView->m_wmPrintHDC;
124 GetClientRect(hWnd, &lpPaint->rcPaint);
125 return pluginView->m_wmPrintHDC;
128 // Call through to the original BeginPaint.
129 __asm mov eax, beginPaintSysCall
130 __asm push lpPaint
131 __asm push hWnd
132 __asm call beginPaint
133 #endif
136 BOOL WINAPI PluginView::hookedEndPaint(HWND hWnd, const PAINTSTRUCT* lpPaint)
138 #if (COMPILER(MINGW))
139 Q_UNUSED(hWnd)
140 Q_UNUSED(lpPaint)
141 return FALSE;
142 #else
143 PluginView* pluginView = reinterpret_cast<PluginView*>(GetProp(hWnd, kWebPluginViewProperty));
144 if (pluginView && pluginView->m_wmPrintHDC) {
145 // We're secretly handling WM_PRINTCLIENT, so we don't have to do any
146 // cleanup.
147 return TRUE;
150 // Call through to the original EndPaint.
151 __asm mov eax, endPaintSysCall
152 __asm push lpPaint
153 __asm push hWnd
154 __asm call endPaint
155 #endif
158 #if (!COMPILER(MINGW))
159 static void hook(const char* module, const char* proc, unsigned& sysCallID, BYTE*& pProc, const void* pNewProc)
161 // See <http://www.fengyuan.com/article/wmprint.html> for an explanation of
162 // how this function works.
164 HINSTANCE hMod = GetModuleHandleA(module);
166 pProc = reinterpret_cast<BYTE*>(GetProcAddress(hMod, proc));
168 if (pProc[0] != 0xB8)
169 return;
171 // FIXME: Should we be reading the bytes one-by-one instead of doing an
172 // unaligned read?
173 sysCallID = *reinterpret_cast<unsigned*>(pProc + 1);
175 DWORD flOldProtect;
176 if (!VirtualProtect(pProc, 5, PAGE_EXECUTE_READWRITE, &flOldProtect))
177 return;
179 pProc[0] = 0xE9;
180 *reinterpret_cast<unsigned*>(pProc + 1) = reinterpret_cast<intptr_t>(pNewProc) - reinterpret_cast<intptr_t>(pProc + 5);
182 pProc += 5;
185 static void setUpOffscreenPaintingHooks(HDC (WINAPI*hookedBeginPaint)(HWND, PAINTSTRUCT*), BOOL (WINAPI*hookedEndPaint)(HWND, const PAINTSTRUCT*))
187 static bool haveHooked = false;
188 if (haveHooked)
189 return;
190 haveHooked = true;
192 // Most (all?) windowed plugins don't seem to respond to WM_PRINTCLIENT, so
193 // we hook into BeginPaint/EndPaint to allow their normal WM_PAINT handling
194 // to draw into a given HDC. Note that this hooking affects the entire
195 // process.
196 hook("user32.dll", "BeginPaint", beginPaintSysCall, beginPaint, hookedBeginPaint);
197 hook("user32.dll", "EndPaint", endPaintSysCall, endPaint, hookedEndPaint);
199 #endif
201 static bool registerPluginView()
203 static bool haveRegisteredWindowClass = false;
204 if (haveRegisteredWindowClass)
205 return true;
207 haveRegisteredWindowClass = true;
209 #if PLATFORM(QT)
210 Page::setInstanceHandle((HINSTANCE)(qWinAppInst()));
211 #endif
213 ASSERT(Page::instanceHandle());
215 WNDCLASSEX wcex;
217 wcex.cbSize = sizeof(WNDCLASSEX);
219 wcex.style = CS_DBLCLKS;
220 wcex.lpfnWndProc = DefWindowProc;
221 wcex.cbClsExtra = 0;
222 wcex.cbWndExtra = 0;
223 wcex.hInstance = Page::instanceHandle();
224 wcex.hIcon = 0;
225 wcex.hCursor = LoadCursor(0, IDC_ARROW);
226 wcex.hbrBackground = (HBRUSH)COLOR_WINDOW;
227 wcex.lpszMenuName = 0;
228 wcex.lpszClassName = kWebPluginViewdowClassName;
229 wcex.hIconSm = 0;
231 return !!RegisterClassEx(&wcex);
234 LRESULT CALLBACK PluginView::PluginViewWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
236 PluginView* pluginView = reinterpret_cast<PluginView*>(GetProp(hWnd, kWebPluginViewProperty));
238 return pluginView->wndProc(hWnd, message, wParam, lParam);
241 static bool isWindowsMessageUserGesture(UINT message)
243 switch (message) {
244 case WM_LBUTTONUP:
245 case WM_MBUTTONUP:
246 case WM_RBUTTONUP:
247 case WM_KEYUP:
248 return true;
249 default:
250 return false;
254 LRESULT
255 PluginView::wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
257 // <rdar://5711136> Sometimes Flash will call SetCapture before creating
258 // a full-screen window and will not release it, which causes the
259 // full-screen window to never receive mouse events. We set/release capture
260 // on mouse down/up before sending the event to the plug-in to prevent that.
261 switch (message) {
262 case WM_LBUTTONDOWN:
263 case WM_MBUTTONDOWN:
264 case WM_RBUTTONDOWN:
265 ::SetCapture(hWnd);
266 break;
267 case WM_LBUTTONUP:
268 case WM_MBUTTONUP:
269 case WM_RBUTTONUP:
270 ::ReleaseCapture();
271 break;
274 if (message == m_lastMessage &&
275 m_plugin->quirks().contains(PluginQuirkDontCallWndProcForSameMessageRecursively) &&
276 m_isCallingPluginWndProc)
277 return 1;
279 if (message == WM_USER + 1 &&
280 m_plugin->quirks().contains(PluginQuirkThrottleWMUserPlusOneMessages)) {
281 if (!m_messageThrottler)
282 m_messageThrottler.set(new PluginMessageThrottlerWin(this));
284 m_messageThrottler->appendMessage(hWnd, message, wParam, lParam);
285 return 0;
288 m_lastMessage = message;
289 m_isCallingPluginWndProc = true;
291 // If the plug-in doesn't explicitly support changing the pop-up state, we enable
292 // popups for all user gestures.
293 // Note that we need to pop the state in a timer, because the Flash plug-in
294 // pops up windows in response to a posted message.
295 if (m_plugin->pluginFuncs()->version < NPVERS_HAS_POPUPS_ENABLED_STATE &&
296 isWindowsMessageUserGesture(message) && !m_popPopupsStateTimer.isActive()) {
298 pushPopupsEnabledState(true);
300 m_popPopupsStateTimer.startOneShot(0);
303 if (message == WM_PRINTCLIENT) {
304 // Most (all?) windowed plugins don't respond to WM_PRINTCLIENT, so we
305 // change the message to WM_PAINT and rely on our hooked versions of
306 // BeginPaint/EndPaint to make the plugin draw into the given HDC.
307 message = WM_PAINT;
308 m_wmPrintHDC = reinterpret_cast<HDC>(wParam);
311 // Call the plug-in's window proc.
312 LRESULT result = ::CallWindowProc(m_pluginWndProc, hWnd, message, wParam, lParam);
314 m_wmPrintHDC = 0;
316 m_isCallingPluginWndProc = false;
318 return result;
321 void PluginView::updatePluginWidget()
323 if (!parent())
324 return;
326 ASSERT(parent()->isFrameView());
327 FrameView* frameView = static_cast<FrameView*>(parent());
329 IntRect oldWindowRect = m_windowRect;
330 IntRect oldClipRect = m_clipRect;
332 m_windowRect = IntRect(frameView->contentsToWindow(frameRect().location()), frameRect().size());
333 m_clipRect = windowClipRect();
334 m_clipRect.move(-m_windowRect.x(), -m_windowRect.y());
336 if (platformPluginWidget() && (m_windowRect != oldWindowRect || m_clipRect != oldClipRect)) {
337 HRGN rgn;
339 setCallingPlugin(true);
341 // To prevent flashes while scrolling, we disable drawing during the window
342 // update process by clipping the window to the zero rect.
344 bool clipToZeroRect = !m_plugin->quirks().contains(PluginQuirkDontClipToZeroRectWhenScrolling);
346 if (clipToZeroRect) {
347 rgn = ::CreateRectRgn(0, 0, 0, 0);
348 ::SetWindowRgn(platformPluginWidget(), rgn, FALSE);
349 } else {
350 rgn = ::CreateRectRgn(m_clipRect.x(), m_clipRect.y(), m_clipRect.right(), m_clipRect.bottom());
351 ::SetWindowRgn(platformPluginWidget(), rgn, TRUE);
354 if (m_windowRect != oldWindowRect)
355 ::MoveWindow(platformPluginWidget(), m_windowRect.x(), m_windowRect.y(), m_windowRect.width(), m_windowRect.height(), TRUE);
357 if (clipToZeroRect) {
358 rgn = ::CreateRectRgn(m_clipRect.x(), m_clipRect.y(), m_clipRect.right(), m_clipRect.bottom());
359 ::SetWindowRgn(platformPluginWidget(), rgn, TRUE);
362 setCallingPlugin(false);
366 void PluginView::setFocus()
368 if (platformPluginWidget())
369 SetFocus(platformPluginWidget());
371 Widget::setFocus();
374 void PluginView::show()
376 setSelfVisible(true);
378 if (isParentVisible() && platformPluginWidget())
379 ShowWindow(platformPluginWidget(), SW_SHOWNA);
381 Widget::show();
384 void PluginView::hide()
386 setSelfVisible(false);
388 if (isParentVisible() && platformPluginWidget())
389 ShowWindow(platformPluginWidget(), SW_HIDE);
391 Widget::hide();
394 bool PluginView::dispatchNPEvent(NPEvent& npEvent)
396 if (!m_plugin->pluginFuncs()->event)
397 return true;
399 bool shouldPop = false;
401 if (m_plugin->pluginFuncs()->version < NPVERS_HAS_POPUPS_ENABLED_STATE && isWindowsMessageUserGesture(npEvent.event)) {
402 pushPopupsEnabledState(true);
403 shouldPop = true;
406 JSC::JSLock::DropAllLocks dropAllLocks(false);
407 setCallingPlugin(true);
408 bool result = m_plugin->pluginFuncs()->event(m_instance, &npEvent);
409 setCallingPlugin(false);
411 if (shouldPop)
412 popPopupsEnabledState();
414 return result;
417 void PluginView::paintWindowedPluginIntoContext(GraphicsContext* context, const IntRect& rect) const
419 ASSERT(m_isWindowed);
420 ASSERT(context->shouldIncludeChildWindows());
422 ASSERT(parent()->isFrameView());
423 IntPoint locationInWindow = static_cast<FrameView*>(parent())->contentsToWindow(frameRect().location());
425 HDC hdc = context->getWindowsContext(frameRect(), false);
427 XFORM originalTransform;
428 GetWorldTransform(hdc, &originalTransform);
430 // The plugin expects the DC to be in client coordinates, so we translate
431 // the DC to make that so.
432 XFORM transform = originalTransform;
433 transform.eDx = locationInWindow.x();
434 transform.eDy = locationInWindow.y();
436 SetWorldTransform(hdc, &transform);
438 SendMessage(platformPluginWidget(), WM_PRINTCLIENT, reinterpret_cast<WPARAM>(hdc), PRF_CLIENT | PRF_CHILDREN | PRF_OWNED);
440 SetWorldTransform(hdc, &originalTransform);
442 context->releaseWindowsContext(hdc, frameRect(), false);
445 void PluginView::paint(GraphicsContext* context, const IntRect& rect)
447 if (!m_isStarted) {
448 // Draw the "missing plugin" image
449 paintMissingPluginIcon(context, rect);
450 return;
453 if (context->paintingDisabled())
454 return;
456 if (m_isWindowed) {
457 if (context->shouldIncludeChildWindows())
458 paintWindowedPluginIntoContext(context, rect);
459 return;
462 ASSERT(parent()->isFrameView());
463 IntRect rectInWindow = static_cast<FrameView*>(parent())->contentsToWindow(frameRect());
464 HDC hdc = context->getWindowsContext(rectInWindow, m_isTransparent);
465 NPEvent npEvent;
467 // On Safari/Windows without transparency layers the GraphicsContext returns the HDC
468 // of the window and the plugin expects that the passed in DC has window coordinates.
469 // In the Qt port we always draw in an offscreen buffer and therefore need to preserve
470 // the translation set in getWindowsContext.
471 #if !PLATFORM(QT)
472 if (!context->inTransparencyLayer()) {
473 XFORM transform;
474 GetWorldTransform(hdc, &transform);
475 transform.eDx = 0;
476 transform.eDy = 0;
477 SetWorldTransform(hdc, &transform);
479 #endif
481 m_npWindow.type = NPWindowTypeDrawable;
482 m_npWindow.window = hdc;
484 IntPoint p = static_cast<FrameView*>(parent())->contentsToWindow(frameRect().location());
486 WINDOWPOS windowpos;
487 memset(&windowpos, 0, sizeof(windowpos));
489 windowpos.x = p.x();
490 windowpos.y = p.y();
491 windowpos.cx = frameRect().width();
492 windowpos.cy = frameRect().height();
494 npEvent.event = WM_WINDOWPOSCHANGED;
495 npEvent.lParam = reinterpret_cast<uint32>(&windowpos);
496 npEvent.wParam = 0;
498 dispatchNPEvent(npEvent);
500 setNPWindowRect(frameRect());
502 npEvent.event = WM_PAINT;
503 npEvent.wParam = reinterpret_cast<uint32>(hdc);
505 // This is supposed to be a pointer to the dirty rect, but it seems that the Flash plugin
506 // ignores it so we just pass null.
507 npEvent.lParam = 0;
509 dispatchNPEvent(npEvent);
511 context->releaseWindowsContext(hdc, frameRect(), m_isTransparent);
514 void PluginView::handleKeyboardEvent(KeyboardEvent* event)
516 NPEvent npEvent;
518 npEvent.wParam = event->keyCode();
520 if (event->type() == eventNames().keydownEvent) {
521 npEvent.event = WM_KEYDOWN;
522 npEvent.lParam = 0;
523 } else if (event->type() == eventNames().keyupEvent) {
524 npEvent.event = WM_KEYUP;
525 npEvent.lParam = 0x8000;
528 JSC::JSLock::DropAllLocks dropAllLocks(false);
529 if (!dispatchNPEvent(npEvent))
530 event->setDefaultHandled();
533 extern HCURSOR lastSetCursor;
534 extern bool ignoreNextSetCursor;
536 void PluginView::handleMouseEvent(MouseEvent* event)
538 NPEvent npEvent;
540 IntPoint p = static_cast<FrameView*>(parent())->contentsToWindow(IntPoint(event->pageX(), event->pageY()));
542 npEvent.lParam = MAKELPARAM(p.x(), p.y());
543 npEvent.wParam = 0;
545 if (event->ctrlKey())
546 npEvent.wParam |= MK_CONTROL;
547 if (event->shiftKey())
548 npEvent.wParam |= MK_SHIFT;
550 if (event->type() == eventNames().mousemoveEvent ||
551 event->type() == eventNames().mouseoutEvent ||
552 event->type() == eventNames().mouseoverEvent) {
553 npEvent.event = WM_MOUSEMOVE;
554 if (event->buttonDown())
555 switch (event->button()) {
556 case LeftButton:
557 npEvent.wParam |= MK_LBUTTON;
558 break;
559 case MiddleButton:
560 npEvent.wParam |= MK_MBUTTON;
561 break;
562 case RightButton:
563 npEvent.wParam |= MK_RBUTTON;
564 break;
567 else if (event->type() == eventNames().mousedownEvent) {
568 focusPluginElement();
569 switch (event->button()) {
570 case 0:
571 npEvent.event = WM_LBUTTONDOWN;
572 break;
573 case 1:
574 npEvent.event = WM_MBUTTONDOWN;
575 break;
576 case 2:
577 npEvent.event = WM_RBUTTONDOWN;
578 break;
580 } else if (event->type() == eventNames().mouseupEvent) {
581 switch (event->button()) {
582 case 0:
583 npEvent.event = WM_LBUTTONUP;
584 break;
585 case 1:
586 npEvent.event = WM_MBUTTONUP;
587 break;
588 case 2:
589 npEvent.event = WM_RBUTTONUP;
590 break;
592 } else
593 return;
595 JSC::JSLock::DropAllLocks dropAllLocks(false);
596 if (!dispatchNPEvent(npEvent))
597 event->setDefaultHandled();
599 #if !PLATFORM(QT)
600 // Currently, Widget::setCursor is always called after this function in EventHandler.cpp
601 // and since we don't want that we set ignoreNextSetCursor to true here to prevent that.
602 ignoreNextSetCursor = true;
603 lastSetCursor = ::GetCursor();
604 #endif
607 void PluginView::setParent(ScrollView* parent)
609 Widget::setParent(parent);
611 if (parent)
612 init();
613 else {
614 if (!platformPluginWidget())
615 return;
617 // If the plug-in window or one of its children have the focus, we need to
618 // clear it to prevent the web view window from being focused because that can
619 // trigger a layout while the plugin element is being detached.
620 HWND focusedWindow = ::GetFocus();
621 if (platformPluginWidget() == focusedWindow || ::IsChild(platformPluginWidget(), focusedWindow))
622 ::SetFocus(0);
627 void PluginView::setParentVisible(bool visible)
629 if (isParentVisible() == visible)
630 return;
632 Widget::setParentVisible(visible);
634 if (isSelfVisible() && platformPluginWidget()) {
635 if (visible)
636 ShowWindow(platformPluginWidget(), SW_SHOWNA);
637 else
638 ShowWindow(platformPluginWidget(), SW_HIDE);
642 void PluginView::setNPWindowRect(const IntRect& rect)
644 if (!m_isStarted)
645 return;
647 IntPoint p = static_cast<FrameView*>(parent())->contentsToWindow(rect.location());
648 m_npWindow.x = p.x();
649 m_npWindow.y = p.y();
651 m_npWindow.width = rect.width();
652 m_npWindow.height = rect.height();
654 m_npWindow.clipRect.left = 0;
655 m_npWindow.clipRect.top = 0;
656 m_npWindow.clipRect.right = rect.width();
657 m_npWindow.clipRect.bottom = rect.height();
659 if (m_plugin->pluginFuncs()->setwindow) {
660 JSC::JSLock::DropAllLocks dropAllLocks(false);
661 setCallingPlugin(true);
662 m_plugin->pluginFuncs()->setwindow(m_instance, &m_npWindow);
663 setCallingPlugin(false);
665 if (!m_isWindowed)
666 return;
668 ASSERT(platformPluginWidget());
670 WNDPROC currentWndProc = (WNDPROC)GetWindowLongPtr(platformPluginWidget(), GWLP_WNDPROC);
671 if (currentWndProc != PluginViewWndProc)
672 m_pluginWndProc = (WNDPROC)SetWindowLongPtr(platformPluginWidget(), GWLP_WNDPROC, (LONG)PluginViewWndProc);
676 void PluginView::stop()
678 if (!m_isStarted)
679 return;
681 HashSet<RefPtr<PluginStream> > streams = m_streams;
682 HashSet<RefPtr<PluginStream> >::iterator end = streams.end();
683 for (HashSet<RefPtr<PluginStream> >::iterator it = streams.begin(); it != end; ++it) {
684 (*it)->stop();
685 disconnectStream((*it).get());
688 ASSERT(m_streams.isEmpty());
690 m_isStarted = false;
692 // Unsubclass the window
693 if (m_isWindowed) {
694 WNDPROC currentWndProc = (WNDPROC)GetWindowLongPtr(platformPluginWidget(), GWLP_WNDPROC);
696 if (currentWndProc == PluginViewWndProc)
697 SetWindowLongPtr(platformPluginWidget(), GWLP_WNDPROC, (LONG)m_pluginWndProc);
700 JSC::JSLock::DropAllLocks dropAllLocks(false);
702 // Clear the window
703 m_npWindow.window = 0;
704 if (m_plugin->pluginFuncs()->setwindow && !m_plugin->quirks().contains(PluginQuirkDontSetNullWindowHandleOnDestroy)) {
705 setCallingPlugin(true);
706 m_plugin->pluginFuncs()->setwindow(m_instance, &m_npWindow);
707 setCallingPlugin(false);
710 PluginMainThreadScheduler::scheduler().unregisterPlugin(m_instance);
712 // Destroy the plugin
713 NPSavedData* savedData = 0;
714 setCallingPlugin(true);
715 NPError npErr = m_plugin->pluginFuncs()->destroy(m_instance, &savedData);
716 setCallingPlugin(false);
717 LOG_NPERROR(npErr);
719 if (savedData) {
720 if (savedData->buf)
721 NPN_MemFree(savedData->buf);
722 NPN_MemFree(savedData);
725 m_instance->pdata = 0;
728 const char* PluginView::userAgentStatic()
730 return 0;
733 const char* PluginView::userAgent()
735 if (m_plugin->quirks().contains(PluginQuirkWantsMozillaUserAgent))
736 return MozillaUserAgent;
738 if (m_userAgent.isNull())
739 m_userAgent = m_parentFrame->loader()->userAgent(m_url).utf8();
740 return m_userAgent.data();
743 NPError PluginView::handlePostReadFile(Vector<char>& buffer, uint32 len, const char* buf)
745 String filename(buf, len);
747 if (filename.startsWith("file:///"))
748 filename = filename.substring(8);
750 // Get file info
751 WIN32_FILE_ATTRIBUTE_DATA attrs;
752 if (GetFileAttributesExW(filename.charactersWithNullTermination(), GetFileExInfoStandard, &attrs) == 0)
753 return NPERR_FILE_NOT_FOUND;
755 if (attrs.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
756 return NPERR_FILE_NOT_FOUND;
758 HANDLE fileHandle = CreateFileW(filename.charactersWithNullTermination(), FILE_READ_DATA, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
760 if (fileHandle == INVALID_HANDLE_VALUE)
761 return NPERR_FILE_NOT_FOUND;
763 buffer.resize(attrs.nFileSizeLow);
765 DWORD bytesRead;
766 int retval = ReadFile(fileHandle, buffer.data(), attrs.nFileSizeLow, &bytesRead, 0);
768 CloseHandle(fileHandle);
770 if (retval == 0 || bytesRead != attrs.nFileSizeLow)
771 return NPERR_FILE_NOT_FOUND;
773 return NPERR_NO_ERROR;
776 NPError PluginView::getValueStatic(NPNVariable variable, void* value)
778 return NPERR_GENERIC_ERROR;
781 NPError PluginView::getValue(NPNVariable variable, void* value)
783 switch (variable) {
784 #if ENABLE(NETSCAPE_PLUGIN_API)
785 case NPNVWindowNPObject: {
786 if (m_isJavaScriptPaused)
787 return NPERR_GENERIC_ERROR;
789 NPObject* windowScriptObject = m_parentFrame->script()->windowScriptNPObject();
791 // Return value is expected to be retained, as described here: <http://www.mozilla.org/projects/plugin/npruntime.html>
792 if (windowScriptObject)
793 _NPN_RetainObject(windowScriptObject);
795 void** v = (void**)value;
796 *v = windowScriptObject;
798 return NPERR_NO_ERROR;
801 case NPNVPluginElementNPObject: {
802 if (m_isJavaScriptPaused)
803 return NPERR_GENERIC_ERROR;
805 NPObject* pluginScriptObject = 0;
807 if (m_element->hasTagName(appletTag) || m_element->hasTagName(embedTag) || m_element->hasTagName(objectTag))
808 pluginScriptObject = static_cast<HTMLPlugInElement*>(m_element)->getNPObject();
810 // Return value is expected to be retained, as described here: <http://www.mozilla.org/projects/plugin/npruntime.html>
811 if (pluginScriptObject)
812 _NPN_RetainObject(pluginScriptObject);
814 void** v = (void**)value;
815 *v = pluginScriptObject;
817 return NPERR_NO_ERROR;
819 #endif
821 case NPNVnetscapeWindow: {
822 HWND* w = reinterpret_cast<HWND*>(value);
824 *w = windowHandleForPlatformWidget(parent() ? parent()->hostWindow()->platformWindow() : 0);
826 return NPERR_NO_ERROR;
829 case NPNVSupportsWindowless: {
830 NPBool *result = reinterpret_cast<NPBool*>(value);
832 *result = TRUE;
834 return NPERR_NO_ERROR;
837 default:
838 return NPERR_GENERIC_ERROR;
842 void PluginView::invalidateRect(const IntRect& rect)
844 if (m_isWindowed) {
845 RECT invalidRect = { rect.x(), rect.y(), rect.right(), rect.bottom() };
846 ::InvalidateRect(platformPluginWidget(), &invalidRect, false);
847 return;
850 invalidateWindowlessPluginRect(rect);
853 void PluginView::invalidateRect(NPRect* rect)
855 if (!rect) {
856 invalidate();
857 return;
860 IntRect r(rect->left, rect->top, rect->right - rect->left, rect->bottom - rect->top);
862 if (m_isWindowed) {
863 RECT invalidRect = { r.x(), r.y(), r.right(), r.bottom() };
864 InvalidateRect(platformPluginWidget(), &invalidRect, FALSE);
865 } else {
866 if (m_plugin->quirks().contains(PluginQuirkThrottleInvalidate)) {
867 m_invalidRects.append(r);
868 if (!m_invalidateTimer.isActive())
869 m_invalidateTimer.startOneShot(0.001);
870 } else
871 invalidateRect(r);
875 void PluginView::invalidateRegion(NPRegion region)
877 if (m_isWindowed)
878 return;
880 RECT r;
882 if (GetRgnBox(region, &r) == 0) {
883 invalidate();
884 return;
887 IntRect rect(IntPoint(r.left, r.top), IntSize(r.right-r.left, r.bottom-r.top));
888 invalidateRect(rect);
891 void PluginView::forceRedraw()
893 if (m_isWindowed)
894 ::UpdateWindow(platformPluginWidget());
895 else
896 ::UpdateWindow(windowHandleForPlatformWidget(parent() ? parent()->hostWindow()->platformWindow() : 0));
899 PluginView::~PluginView()
901 if (m_instance)
902 m_instance->ndata = 0;
903 stop();
905 deleteAllValues(m_requests);
907 freeStringArray(m_paramNames, m_paramCount);
908 freeStringArray(m_paramValues, m_paramCount);
910 if (platformPluginWidget())
911 DestroyWindow(platformPluginWidget());
913 m_parentFrame->script()->cleanupScriptObjectsForPlugin(this);
915 if (m_plugin && !m_plugin->quirks().contains(PluginQuirkDontUnloadPlugin))
916 m_plugin->unload();
919 void PluginView::init()
921 if (m_haveInitialized)
922 return;
923 m_haveInitialized = true;
925 if (!m_plugin) {
926 ASSERT(m_status == PluginStatusCanNotFindPlugin);
927 return;
930 if (!m_plugin->load()) {
931 m_plugin = 0;
932 m_status = PluginStatusCanNotLoadPlugin;
933 return;
936 if (!start()) {
937 m_status = PluginStatusCanNotLoadPlugin;
938 return;
941 if (m_isWindowed) {
942 registerPluginView();
943 #if (!COMPILER(MINGW))
944 setUpOffscreenPaintingHooks(hookedBeginPaint, hookedEndPaint);
945 #endif
946 DWORD flags = WS_CHILD;
947 if (isSelfVisible())
948 flags |= WS_VISIBLE;
950 HWND parentWindowHandle = windowHandleForPlatformWidget(m_parentFrame->view()->hostWindow()->platformWindow());
951 HWND window = ::CreateWindowEx(0, kWebPluginViewdowClassName, 0, flags,
952 0, 0, 0, 0, parentWindowHandle, 0, Page::instanceHandle(), 0);
953 #if PLATFORM(WIN_OS) && PLATFORM(QT)
954 m_window = window;
955 #else
956 setPlatformWidget(window);
957 #endif
959 // Calling SetWindowLongPtrA here makes the window proc ASCII, which is required by at least
960 // the Shockwave Director plug-in.
961 #if PLATFORM(WIN_OS) && PLATFORM(X86_64) && COMPILER(MSVC)
962 ::SetWindowLongPtrA(platformPluginWidget(), GWLP_WNDPROC, (LONG_PTR)DefWindowProcA);
963 #else
964 ::SetWindowLongPtrA(platformPluginWidget(), GWL_WNDPROC, (LONG)DefWindowProcA);
965 #endif
966 SetProp(platformPluginWidget(), kWebPluginViewProperty, this);
968 m_npWindow.type = NPWindowTypeWindow;
969 m_npWindow.window = platformPluginWidget();
970 } else {
971 m_npWindow.type = NPWindowTypeDrawable;
972 m_npWindow.window = 0;
975 if (!m_plugin->quirks().contains(PluginQuirkDeferFirstSetWindowCall))
976 setNPWindowRect(frameRect());
978 m_status = PluginStatusLoadedSuccessfully;
981 } // namespace WebCore