• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "Document.h"
33 #include "DocumentLoader.h"
34 #include "Element.h"
35 #include "EventNames.h"
36 #include "FrameLoader.h"
37 #include "FrameLoadRequest.h"
38 #include "FrameTree.h"
39 #include "Frame.h"
40 #include "FrameView.h"
41 #include "GraphicsContext.h"
42 #include "Image.h"
43 #include "HTMLNames.h"
44 #include "HTMLPlugInElement.h"
45 #include "JSDOMWindow.h"
46 #include "KeyboardEvent.h"
47 #include "MIMETypeRegistry.h"
48 #include "MouseEvent.h"
49 #include "Page.h"
50 #include "FocusController.h"
51 #include "PlatformMouseEvent.h"
52 #include "PluginMessageThrottlerWin.h"
53 #include "PluginPackage.h"
54 #include "PluginMainThreadScheduler.h"
55 #include "JSDOMBinding.h"
56 #include "ScriptController.h"
57 #include "PluginDatabase.h"
58 #include "PluginDebug.h"
59 #include "PluginPackage.h"
60 #include "c_instance.h"
61 #include "npruntime_impl.h"
62 #include "runtime_root.h"
63 #include "Settings.h"
64 #include "runtime.h"
65 #include <runtime/JSLock.h>
66 #include <runtime/JSValue.h>
67 #include <wtf/ASCIICType.h>
68 
69 #if PLATFORM(WINCE)
70 #undef LOG_NPERROR
71 #define LOG_NPERROR(x)
72 #undef LOG_PLUGIN_NET_ERROR
73 #define LOG_PLUGIN_NET_ERROR()
74 #endif
75 
76 #if PLATFORM(QT)
77 #include <QWidget.h>
78 #endif
79 
windowHandleForPlatformWidget(PlatformWidget widget)80 static inline HWND windowHandleForPlatformWidget(PlatformWidget widget)
81 {
82 #if PLATFORM(QT)
83     if (!widget)
84         return 0;
85     return widget->winId();
86 #else
87     return widget;
88 #endif
89 }
90 
91 using JSC::ExecState;
92 using JSC::JSLock;
93 using JSC::JSObject;
94 using JSC::UString;
95 
96 using std::min;
97 
98 using namespace WTF;
99 
100 namespace WebCore {
101 
102 using namespace HTMLNames;
103 
104 const LPCWSTR kWebPluginViewdowClassName = L"WebPluginView";
105 const LPCWSTR kWebPluginViewProperty = L"WebPluginViewProperty";
106 
107 #if !PLATFORM(WINCE)
108 // The code used to hook BeginPaint/EndPaint originally came from
109 // <http://www.fengyuan.com/article/wmprint.html>.
110 // Copyright (C) 2000 by Feng Yuan (www.fengyuan.com).
111 
112 static unsigned beginPaintSysCall;
113 static BYTE* beginPaint;
114 
115 static unsigned endPaintSysCall;
116 static BYTE* endPaint;
117 
hookedBeginPaint(HWND hWnd,PAINTSTRUCT * lpPaint)118 HDC WINAPI PluginView::hookedBeginPaint(HWND hWnd, PAINTSTRUCT* lpPaint)
119 {
120     PluginView* pluginView = reinterpret_cast<PluginView*>(GetProp(hWnd, kWebPluginViewProperty));
121     if (pluginView && pluginView->m_wmPrintHDC) {
122         // We're secretly handling WM_PRINTCLIENT, so set up the PAINTSTRUCT so
123         // that the plugin will paint into the HDC we provide.
124         memset(lpPaint, 0, sizeof(PAINTSTRUCT));
125         lpPaint->hdc = pluginView->m_wmPrintHDC;
126         GetClientRect(hWnd, &lpPaint->rcPaint);
127         return pluginView->m_wmPrintHDC;
128     }
129 
130 #if COMPILER(GCC)
131     HDC result;
132     asm ("push    %2\n"
133          "push    %3\n"
134          "call    *%4\n"
135          : "=a" (result)
136          : "a" (beginPaintSysCall), "g" (lpPaint), "g" (hWnd), "m" (*beginPaint)
137          : "memory"
138         );
139     return result;
140 #else
141     // Call through to the original BeginPaint.
142     __asm   mov     eax, beginPaintSysCall
143     __asm   push    lpPaint
144     __asm   push    hWnd
145     __asm   call    beginPaint
146 #endif
147 }
148 
hookedEndPaint(HWND hWnd,const PAINTSTRUCT * lpPaint)149 BOOL WINAPI PluginView::hookedEndPaint(HWND hWnd, const PAINTSTRUCT* lpPaint)
150 {
151     PluginView* pluginView = reinterpret_cast<PluginView*>(GetProp(hWnd, kWebPluginViewProperty));
152     if (pluginView && pluginView->m_wmPrintHDC) {
153         // We're secretly handling WM_PRINTCLIENT, so we don't have to do any
154         // cleanup.
155         return TRUE;
156     }
157 
158 #if COMPILER(GCC)
159     BOOL result;
160     asm ("push   %2\n"
161          "push   %3\n"
162          "call   *%4\n"
163          : "=a" (result)
164          : "a" (endPaintSysCall), "g" (lpPaint), "g" (hWnd), "m" (*endPaint)
165         );
166     return result;
167 #else
168     // Call through to the original EndPaint.
169     __asm   mov     eax, endPaintSysCall
170     __asm   push    lpPaint
171     __asm   push    hWnd
172     __asm   call    endPaint
173 #endif
174 }
175 
hook(const char * module,const char * proc,unsigned & sysCallID,BYTE * & pProc,const void * pNewProc)176 static void hook(const char* module, const char* proc, unsigned& sysCallID, BYTE*& pProc, const void* pNewProc)
177 {
178     // See <http://www.fengyuan.com/article/wmprint.html> for an explanation of
179     // how this function works.
180 
181     HINSTANCE hMod = GetModuleHandleA(module);
182 
183     pProc = reinterpret_cast<BYTE*>(reinterpret_cast<ptrdiff_t>(GetProcAddress(hMod, proc)));
184 
185     if (pProc[0] != 0xB8)
186         return;
187 
188     // FIXME: Should we be reading the bytes one-by-one instead of doing an
189     // unaligned read?
190     sysCallID = *reinterpret_cast<unsigned*>(pProc + 1);
191 
192     DWORD flOldProtect;
193     if (!VirtualProtect(pProc, 5, PAGE_EXECUTE_READWRITE, &flOldProtect))
194         return;
195 
196     pProc[0] = 0xE9;
197     *reinterpret_cast<unsigned*>(pProc + 1) = reinterpret_cast<intptr_t>(pNewProc) - reinterpret_cast<intptr_t>(pProc + 5);
198 
199     pProc += 5;
200 }
201 
setUpOffscreenPaintingHooks(HDC (WINAPI * hookedBeginPaint)(HWND,PAINTSTRUCT *),BOOL (WINAPI * hookedEndPaint)(HWND,const PAINTSTRUCT *))202 static void setUpOffscreenPaintingHooks(HDC (WINAPI*hookedBeginPaint)(HWND, PAINTSTRUCT*), BOOL (WINAPI*hookedEndPaint)(HWND, const PAINTSTRUCT*))
203 {
204     static bool haveHooked = false;
205     if (haveHooked)
206         return;
207     haveHooked = true;
208 
209     // Most (all?) windowed plugins don't seem to respond to WM_PRINTCLIENT, so
210     // we hook into BeginPaint/EndPaint to allow their normal WM_PAINT handling
211     // to draw into a given HDC. Note that this hooking affects the entire
212     // process.
213     hook("user32.dll", "BeginPaint", beginPaintSysCall, beginPaint, reinterpret_cast<const void *>(reinterpret_cast<ptrdiff_t>(hookedBeginPaint)));
214     hook("user32.dll", "EndPaint", endPaintSysCall, endPaint, reinterpret_cast<const void *>(reinterpret_cast<ptrdiff_t>(hookedEndPaint)));
215 
216 }
217 #endif
218 
registerPluginView()219 static bool registerPluginView()
220 {
221     static bool haveRegisteredWindowClass = false;
222     if (haveRegisteredWindowClass)
223         return true;
224 
225     haveRegisteredWindowClass = true;
226 
227 #if PLATFORM(QT)
228     Page::setInstanceHandle((HINSTANCE)(qWinAppInst()));
229 #endif
230 
231     ASSERT(Page::instanceHandle());
232 
233 #if PLATFORM(WINCE)
234     WNDCLASS wcex = { 0 };
235 #else
236     WNDCLASSEX wcex;
237     wcex.cbSize = sizeof(WNDCLASSEX);
238     wcex.hIconSm        = 0;
239 #endif
240 
241     wcex.style          = CS_DBLCLKS;
242 #if PLATFORM(WINCE)
243     wcex.style          |= CS_PARENTDC;
244 #endif
245     wcex.lpfnWndProc    = DefWindowProc;
246     wcex.cbClsExtra     = 0;
247     wcex.cbWndExtra     = 0;
248     wcex.hInstance      = Page::instanceHandle();
249     wcex.hIcon          = 0;
250     wcex.hCursor        = LoadCursor(0, IDC_ARROW);
251     wcex.hbrBackground  = (HBRUSH)COLOR_WINDOW;
252     wcex.lpszMenuName   = 0;
253     wcex.lpszClassName  = kWebPluginViewdowClassName;
254 
255 #if PLATFORM(WINCE)
256     return !!RegisterClass(&wcex);
257 #else
258     return !!RegisterClassEx(&wcex);
259 #endif
260 }
261 
PluginViewWndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)262 LRESULT CALLBACK PluginView::PluginViewWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
263 {
264     PluginView* pluginView = reinterpret_cast<PluginView*>(GetProp(hWnd, kWebPluginViewProperty));
265 
266     return pluginView->wndProc(hWnd, message, wParam, lParam);
267 }
268 
isWindowsMessageUserGesture(UINT message)269 static bool isWindowsMessageUserGesture(UINT message)
270 {
271     switch (message) {
272         case WM_LBUTTONUP:
273         case WM_MBUTTONUP:
274         case WM_RBUTTONUP:
275         case WM_KEYUP:
276             return true;
277         default:
278             return false;
279     }
280 }
281 
282 LRESULT
wndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)283 PluginView::wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
284 {
285     // <rdar://5711136> Sometimes Flash will call SetCapture before creating
286     // a full-screen window and will not release it, which causes the
287     // full-screen window to never receive mouse events. We set/release capture
288     // on mouse down/up before sending the event to the plug-in to prevent that.
289     switch (message) {
290         case WM_LBUTTONDOWN:
291         case WM_MBUTTONDOWN:
292         case WM_RBUTTONDOWN:
293             ::SetCapture(hWnd);
294             break;
295         case WM_LBUTTONUP:
296         case WM_MBUTTONUP:
297         case WM_RBUTTONUP:
298             ::ReleaseCapture();
299             break;
300     }
301 
302     if (message == m_lastMessage &&
303         m_plugin->quirks().contains(PluginQuirkDontCallWndProcForSameMessageRecursively) &&
304         m_isCallingPluginWndProc)
305         return 1;
306 
307     if (message == WM_USER + 1 &&
308         m_plugin->quirks().contains(PluginQuirkThrottleWMUserPlusOneMessages)) {
309         if (!m_messageThrottler)
310             m_messageThrottler.set(new PluginMessageThrottlerWin(this));
311 
312         m_messageThrottler->appendMessage(hWnd, message, wParam, lParam);
313         return 0;
314     }
315 
316     m_lastMessage = message;
317     m_isCallingPluginWndProc = true;
318 
319     // If the plug-in doesn't explicitly support changing the pop-up state, we enable
320     // popups for all user gestures.
321     // Note that we need to pop the state in a timer, because the Flash plug-in
322     // pops up windows in response to a posted message.
323     if (m_plugin->pluginFuncs()->version < NPVERS_HAS_POPUPS_ENABLED_STATE &&
324         isWindowsMessageUserGesture(message) && !m_popPopupsStateTimer.isActive()) {
325 
326         pushPopupsEnabledState(true);
327 
328         m_popPopupsStateTimer.startOneShot(0);
329     }
330 
331 #if !PLATFORM(WINCE)
332     if (message == WM_PRINTCLIENT) {
333         // Most (all?) windowed plugins don't respond to WM_PRINTCLIENT, so we
334         // change the message to WM_PAINT and rely on our hooked versions of
335         // BeginPaint/EndPaint to make the plugin draw into the given HDC.
336         message = WM_PAINT;
337         m_wmPrintHDC = reinterpret_cast<HDC>(wParam);
338     }
339 #endif
340 
341     // Call the plug-in's window proc.
342     LRESULT result = ::CallWindowProc(m_pluginWndProc, hWnd, message, wParam, lParam);
343 
344     m_wmPrintHDC = 0;
345 
346     m_isCallingPluginWndProc = false;
347 
348     return result;
349 }
350 
updatePluginWidget()351 void PluginView::updatePluginWidget()
352 {
353     if (!parent())
354         return;
355 
356     ASSERT(parent()->isFrameView());
357     FrameView* frameView = static_cast<FrameView*>(parent());
358 
359     IntRect oldWindowRect = m_windowRect;
360     IntRect oldClipRect = m_clipRect;
361 
362 #if PLATFORM(WINCE)
363     m_windowRect = frameView->contentsToWindow(frameRect());
364 #else
365     m_windowRect = IntRect(frameView->contentsToWindow(frameRect().location()), frameRect().size());
366 #endif
367     m_clipRect = windowClipRect();
368     m_clipRect.move(-m_windowRect.x(), -m_windowRect.y());
369 
370     if (platformPluginWidget() && (!m_haveUpdatedPluginWidget || m_windowRect != oldWindowRect || m_clipRect != oldClipRect)) {
371         HRGN rgn;
372 
373         setCallingPlugin(true);
374 
375         // To prevent flashes while scrolling, we disable drawing during the window
376         // update process by clipping the window to the zero rect.
377 
378         bool clipToZeroRect = !m_plugin->quirks().contains(PluginQuirkDontClipToZeroRectWhenScrolling);
379 
380         if (clipToZeroRect) {
381             rgn = ::CreateRectRgn(0, 0, 0, 0);
382             ::SetWindowRgn(platformPluginWidget(), rgn, FALSE);
383         } else {
384             rgn = ::CreateRectRgn(m_clipRect.x(), m_clipRect.y(), m_clipRect.right(), m_clipRect.bottom());
385             ::SetWindowRgn(platformPluginWidget(), rgn, TRUE);
386         }
387 
388         if (!m_haveUpdatedPluginWidget || m_windowRect != oldWindowRect)
389             ::MoveWindow(platformPluginWidget(), m_windowRect.x(), m_windowRect.y(), m_windowRect.width(), m_windowRect.height(), TRUE);
390 
391         if (clipToZeroRect) {
392             rgn = ::CreateRectRgn(m_clipRect.x(), m_clipRect.y(), m_clipRect.right(), m_clipRect.bottom());
393             ::SetWindowRgn(platformPluginWidget(), rgn, TRUE);
394         }
395 
396         setCallingPlugin(false);
397 
398         m_haveUpdatedPluginWidget = true;
399     }
400 }
401 
setFocus()402 void PluginView::setFocus()
403 {
404     if (platformPluginWidget())
405         SetFocus(platformPluginWidget());
406 
407     Widget::setFocus();
408 }
409 
show()410 void PluginView::show()
411 {
412     setSelfVisible(true);
413 
414     if (isParentVisible() && platformPluginWidget())
415         ShowWindow(platformPluginWidget(), SW_SHOWNA);
416 
417     Widget::show();
418 }
419 
hide()420 void PluginView::hide()
421 {
422     setSelfVisible(false);
423 
424     if (isParentVisible() && platformPluginWidget())
425         ShowWindow(platformPluginWidget(), SW_HIDE);
426 
427     Widget::hide();
428 }
429 
dispatchNPEvent(NPEvent & npEvent)430 bool PluginView::dispatchNPEvent(NPEvent& npEvent)
431 {
432     if (!m_plugin->pluginFuncs()->event)
433         return true;
434 
435     bool shouldPop = false;
436 
437     if (m_plugin->pluginFuncs()->version < NPVERS_HAS_POPUPS_ENABLED_STATE && isWindowsMessageUserGesture(npEvent.event)) {
438         pushPopupsEnabledState(true);
439         shouldPop = true;
440     }
441 
442     JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
443     setCallingPlugin(true);
444     bool result = m_plugin->pluginFuncs()->event(m_instance, &npEvent);
445     setCallingPlugin(false);
446 
447     if (shouldPop)
448         popPopupsEnabledState();
449 
450     return result;
451 }
452 
paintWindowedPluginIntoContext(GraphicsContext * context,const IntRect & rect) const453 void PluginView::paintWindowedPluginIntoContext(GraphicsContext* context, const IntRect& rect) const
454 {
455 #if !PLATFORM(WINCE)
456     ASSERT(m_isWindowed);
457     ASSERT(context->shouldIncludeChildWindows());
458 
459     ASSERT(parent()->isFrameView());
460     IntPoint locationInWindow = static_cast<FrameView*>(parent())->contentsToWindow(frameRect().location());
461 
462     HDC hdc = context->getWindowsContext(frameRect(), false);
463 
464     XFORM originalTransform;
465     GetWorldTransform(hdc, &originalTransform);
466 
467     // The plugin expects the DC to be in client coordinates, so we translate
468     // the DC to make that so.
469     XFORM transform = originalTransform;
470     transform.eDx = locationInWindow.x();
471     transform.eDy = locationInWindow.y();
472 
473     SetWorldTransform(hdc, &transform);
474 
475     SendMessage(platformPluginWidget(), WM_PRINTCLIENT, reinterpret_cast<WPARAM>(hdc), PRF_CLIENT | PRF_CHILDREN | PRF_OWNED);
476 
477     SetWorldTransform(hdc, &originalTransform);
478 
479     context->releaseWindowsContext(hdc, frameRect(), false);
480 #endif
481 }
482 
paint(GraphicsContext * context,const IntRect & rect)483 void PluginView::paint(GraphicsContext* context, const IntRect& rect)
484 {
485     if (!m_isStarted) {
486         // Draw the "missing plugin" image
487         paintMissingPluginIcon(context, rect);
488         return;
489     }
490 
491     if (context->paintingDisabled())
492         return;
493 
494     if (m_isWindowed) {
495 #if !PLATFORM(WINCE)
496         if (context->shouldIncludeChildWindows())
497             paintWindowedPluginIntoContext(context, rect);
498 #endif
499         return;
500     }
501 
502     ASSERT(parent()->isFrameView());
503     IntRect rectInWindow = static_cast<FrameView*>(parent())->contentsToWindow(frameRect());
504     HDC hdc = context->getWindowsContext(rectInWindow, m_isTransparent);
505     NPEvent npEvent;
506 
507     // On Safari/Windows without transparency layers the GraphicsContext returns the HDC
508     // of the window and the plugin expects that the passed in DC has window coordinates.
509     // In the Qt port we always draw in an offscreen buffer and therefore need to preserve
510     // the translation set in getWindowsContext.
511 #if !PLATFORM(QT) && !PLATFORM(WINCE)
512     if (!context->inTransparencyLayer()) {
513         XFORM transform;
514         GetWorldTransform(hdc, &transform);
515         transform.eDx = 0;
516         transform.eDy = 0;
517         SetWorldTransform(hdc, &transform);
518     }
519 #endif
520 
521     m_npWindow.type = NPWindowTypeDrawable;
522     m_npWindow.window = hdc;
523 
524     WINDOWPOS windowpos;
525     memset(&windowpos, 0, sizeof(windowpos));
526 
527 #if PLATFORM(WINCE)
528     IntRect r = static_cast<FrameView*>(parent())->contentsToWindow(frameRect());
529 
530     windowpos.x = r.x();
531     windowpos.y = r.y();
532     windowpos.cx = r.width();
533     windowpos.cy = r.height();
534 #else
535     IntPoint p = static_cast<FrameView*>(parent())->contentsToWindow(frameRect().location());
536 
537     windowpos.x = p.x();
538     windowpos.y = p.y();
539     windowpos.cx = frameRect().width();
540     windowpos.cy = frameRect().height();
541 #endif
542 
543     npEvent.event = WM_WINDOWPOSCHANGED;
544     npEvent.lParam = reinterpret_cast<uint32>(&windowpos);
545     npEvent.wParam = 0;
546 
547     dispatchNPEvent(npEvent);
548 
549     setNPWindowRect(frameRect());
550 
551     npEvent.event = WM_PAINT;
552     npEvent.wParam = reinterpret_cast<uint32>(hdc);
553 
554     // This is supposed to be a pointer to the dirty rect, but it seems that the Flash plugin
555     // ignores it so we just pass null.
556     npEvent.lParam = 0;
557 
558     dispatchNPEvent(npEvent);
559 
560     context->releaseWindowsContext(hdc, frameRect(), m_isTransparent);
561 }
562 
handleKeyboardEvent(KeyboardEvent * event)563 void PluginView::handleKeyboardEvent(KeyboardEvent* event)
564 {
565     NPEvent npEvent;
566 
567     npEvent.wParam = event->keyCode();
568 
569     if (event->type() == eventNames().keydownEvent) {
570         npEvent.event = WM_KEYDOWN;
571         npEvent.lParam = 0;
572     } else if (event->type() == eventNames().keyupEvent) {
573         npEvent.event = WM_KEYUP;
574         npEvent.lParam = 0x8000;
575     }
576 
577     JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
578     if (!dispatchNPEvent(npEvent))
579         event->setDefaultHandled();
580 }
581 
582 #if !PLATFORM(WINCE)
583 extern HCURSOR lastSetCursor;
584 extern bool ignoreNextSetCursor;
585 #endif
586 
handleMouseEvent(MouseEvent * event)587 void PluginView::handleMouseEvent(MouseEvent* event)
588 {
589     NPEvent npEvent;
590 
591     IntPoint p = static_cast<FrameView*>(parent())->contentsToWindow(IntPoint(event->pageX(), event->pageY()));
592 
593     npEvent.lParam = MAKELPARAM(p.x(), p.y());
594     npEvent.wParam = 0;
595 
596     if (event->ctrlKey())
597         npEvent.wParam |= MK_CONTROL;
598     if (event->shiftKey())
599         npEvent.wParam |= MK_SHIFT;
600 
601     if (event->type() == eventNames().mousemoveEvent ||
602         event->type() == eventNames().mouseoutEvent ||
603         event->type() == eventNames().mouseoverEvent) {
604         npEvent.event = WM_MOUSEMOVE;
605         if (event->buttonDown())
606             switch (event->button()) {
607                 case LeftButton:
608                     npEvent.wParam |= MK_LBUTTON;
609                     break;
610                 case MiddleButton:
611                     npEvent.wParam |= MK_MBUTTON;
612                     break;
613                 case RightButton:
614                     npEvent.wParam |= MK_RBUTTON;
615                 break;
616             }
617     }
618     else if (event->type() == eventNames().mousedownEvent) {
619         focusPluginElement();
620         switch (event->button()) {
621             case 0:
622                 npEvent.event = WM_LBUTTONDOWN;
623                 break;
624             case 1:
625                 npEvent.event = WM_MBUTTONDOWN;
626                 break;
627             case 2:
628                 npEvent.event = WM_RBUTTONDOWN;
629                 break;
630         }
631     } else if (event->type() == eventNames().mouseupEvent) {
632         switch (event->button()) {
633             case 0:
634                 npEvent.event = WM_LBUTTONUP;
635                 break;
636             case 1:
637                 npEvent.event = WM_MBUTTONUP;
638                 break;
639             case 2:
640                 npEvent.event = WM_RBUTTONUP;
641                 break;
642         }
643     } else
644         return;
645 
646     JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
647     if (!dispatchNPEvent(npEvent))
648         event->setDefaultHandled();
649 
650 #if !PLATFORM(QT) && !PLATFORM(WINCE)
651     // Currently, Widget::setCursor is always called after this function in EventHandler.cpp
652     // and since we don't want that we set ignoreNextSetCursor to true here to prevent that.
653     ignoreNextSetCursor = true;
654     lastSetCursor = ::GetCursor();
655 #endif
656 }
657 
setParent(ScrollView * parent)658 void PluginView::setParent(ScrollView* parent)
659 {
660     Widget::setParent(parent);
661 
662 #if PLATFORM(WINCE)
663     if (parent) {
664         init();
665         if (parent->isVisible())
666             show();
667         else
668             hide();
669     }
670 #else
671     if (parent)
672         init();
673     else {
674         if (!platformPluginWidget())
675             return;
676 
677         // If the plug-in window or one of its children have the focus, we need to
678         // clear it to prevent the web view window from being focused because that can
679         // trigger a layout while the plugin element is being detached.
680         HWND focusedWindow = ::GetFocus();
681         if (platformPluginWidget() == focusedWindow || ::IsChild(platformPluginWidget(), focusedWindow))
682             ::SetFocus(0);
683     }
684 #endif
685 }
686 
setParentVisible(bool visible)687 void PluginView::setParentVisible(bool visible)
688 {
689     if (isParentVisible() == visible)
690         return;
691 
692     Widget::setParentVisible(visible);
693 
694     if (isSelfVisible() && platformPluginWidget()) {
695         if (visible)
696             ShowWindow(platformPluginWidget(), SW_SHOWNA);
697         else
698             ShowWindow(platformPluginWidget(), SW_HIDE);
699     }
700 }
701 
setNPWindowRect(const IntRect & rect)702 void PluginView::setNPWindowRect(const IntRect& rect)
703 {
704     if (!m_isStarted)
705         return;
706 
707 #if PLATFORM(WINCE)
708     IntRect r = static_cast<FrameView*>(parent())->contentsToWindow(rect);
709     m_npWindow.x = r.x();
710     m_npWindow.y = r.y();
711 
712     m_npWindow.width = r.width();
713     m_npWindow.height = r.height();
714 
715     m_npWindow.clipRect.right = r.width();
716     m_npWindow.clipRect.bottom = r.height();
717 #else
718     IntPoint p = static_cast<FrameView*>(parent())->contentsToWindow(rect.location());
719     m_npWindow.x = p.x();
720     m_npWindow.y = p.y();
721 
722     m_npWindow.width = rect.width();
723     m_npWindow.height = rect.height();
724 
725     m_npWindow.clipRect.right = rect.width();
726     m_npWindow.clipRect.bottom = rect.height();
727 #endif
728     m_npWindow.clipRect.left = 0;
729     m_npWindow.clipRect.top = 0;
730 
731     if (m_plugin->pluginFuncs()->setwindow) {
732         JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
733         setCallingPlugin(true);
734         m_plugin->pluginFuncs()->setwindow(m_instance, &m_npWindow);
735         setCallingPlugin(false);
736 
737         if (!m_isWindowed)
738             return;
739 
740         ASSERT(platformPluginWidget());
741 
742 #if PLATFORM(WINCE)
743         if (!m_pluginWndProc) {
744             WNDPROC currentWndProc = (WNDPROC)GetWindowLong(platformPluginWidget(), GWL_WNDPROC);
745             if (currentWndProc != PluginViewWndProc)
746                 m_pluginWndProc = (WNDPROC)SetWindowLong(platformPluginWidget(), GWL_WNDPROC, (LONG)PluginViewWndProc);
747         }
748 #else
749         WNDPROC currentWndProc = (WNDPROC)GetWindowLongPtr(platformPluginWidget(), GWLP_WNDPROC);
750         if (currentWndProc != PluginViewWndProc)
751             m_pluginWndProc = (WNDPROC)SetWindowLongPtr(platformPluginWidget(), GWLP_WNDPROC, (LONG)PluginViewWndProc);
752 #endif
753     }
754 }
755 
handlePostReadFile(Vector<char> & buffer,uint32 len,const char * buf)756 NPError PluginView::handlePostReadFile(Vector<char>& buffer, uint32 len, const char* buf)
757 {
758     String filename(buf, len);
759 
760     if (filename.startsWith("file:///"))
761         filename = filename.substring(8);
762 
763     // Get file info
764     WIN32_FILE_ATTRIBUTE_DATA attrs;
765     if (GetFileAttributesExW(filename.charactersWithNullTermination(), GetFileExInfoStandard, &attrs) == 0)
766         return NPERR_FILE_NOT_FOUND;
767 
768     if (attrs.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
769         return NPERR_FILE_NOT_FOUND;
770 
771     HANDLE fileHandle = CreateFileW(filename.charactersWithNullTermination(), FILE_READ_DATA, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
772 
773     if (fileHandle == INVALID_HANDLE_VALUE)
774         return NPERR_FILE_NOT_FOUND;
775 
776     buffer.resize(attrs.nFileSizeLow);
777 
778     DWORD bytesRead;
779     int retval = ReadFile(fileHandle, buffer.data(), attrs.nFileSizeLow, &bytesRead, 0);
780 
781     CloseHandle(fileHandle);
782 
783     if (retval == 0 || bytesRead != attrs.nFileSizeLow)
784         return NPERR_FILE_NOT_FOUND;
785 
786     return NPERR_NO_ERROR;
787 }
788 
getValueStatic(NPNVariable variable,void * value)789 NPError PluginView::getValueStatic(NPNVariable variable, void* value)
790 {
791     LOG(Plugins, "PluginView::getValueStatic(%s)", prettyNameForNPNVariable(variable).data());
792 
793     return NPERR_GENERIC_ERROR;
794 }
795 
getValue(NPNVariable variable,void * value)796 NPError PluginView::getValue(NPNVariable variable, void* value)
797 {
798     LOG(Plugins, "PluginView::getValue(%s)", prettyNameForNPNVariable(variable).data());
799 
800     switch (variable) {
801 #if ENABLE(NETSCAPE_PLUGIN_API)
802         case NPNVWindowNPObject: {
803             if (m_isJavaScriptPaused)
804                 return NPERR_GENERIC_ERROR;
805 
806             NPObject* windowScriptObject = m_parentFrame->script()->windowScriptNPObject();
807 
808             // Return value is expected to be retained, as described here: <http://www.mozilla.org/projects/plugin/npruntime.html>
809             if (windowScriptObject)
810                 _NPN_RetainObject(windowScriptObject);
811 
812             void** v = (void**)value;
813             *v = windowScriptObject;
814 
815             return NPERR_NO_ERROR;
816         }
817 
818         case NPNVPluginElementNPObject: {
819             if (m_isJavaScriptPaused)
820                 return NPERR_GENERIC_ERROR;
821 
822             NPObject* pluginScriptObject = 0;
823 
824             if (m_element->hasTagName(appletTag) || m_element->hasTagName(embedTag) || m_element->hasTagName(objectTag))
825                 pluginScriptObject = static_cast<HTMLPlugInElement*>(m_element)->getNPObject();
826 
827             // Return value is expected to be retained, as described here: <http://www.mozilla.org/projects/plugin/npruntime.html>
828             if (pluginScriptObject)
829                 _NPN_RetainObject(pluginScriptObject);
830 
831             void** v = (void**)value;
832             *v = pluginScriptObject;
833 
834             return NPERR_NO_ERROR;
835         }
836 #endif
837 
838         case NPNVnetscapeWindow: {
839             HWND* w = reinterpret_cast<HWND*>(value);
840 
841             *w = windowHandleForPlatformWidget(parent() ? parent()->hostWindow()->platformWindow() : 0);
842 
843             return NPERR_NO_ERROR;
844         }
845 
846         case NPNVSupportsWindowless: {
847             NPBool *result = reinterpret_cast<NPBool*>(value);
848 
849             *result = TRUE;
850 
851             return NPERR_NO_ERROR;
852         }
853 
854         default:
855             return NPERR_GENERIC_ERROR;
856     }
857 }
858 
invalidateRect(const IntRect & rect)859 void PluginView::invalidateRect(const IntRect& rect)
860 {
861     if (m_isWindowed) {
862         RECT invalidRect = { rect.x(), rect.y(), rect.right(), rect.bottom() };
863         ::InvalidateRect(platformPluginWidget(), &invalidRect, false);
864         return;
865     }
866 
867     invalidateWindowlessPluginRect(rect);
868 }
869 
invalidateRect(NPRect * rect)870 void PluginView::invalidateRect(NPRect* rect)
871 {
872     if (!rect) {
873         invalidate();
874         return;
875     }
876 
877     IntRect r(rect->left, rect->top, rect->right - rect->left, rect->bottom - rect->top);
878 
879     if (m_isWindowed) {
880         RECT invalidRect = { r.x(), r.y(), r.right(), r.bottom() };
881         InvalidateRect(platformPluginWidget(), &invalidRect, FALSE);
882     } else {
883         if (m_plugin->quirks().contains(PluginQuirkThrottleInvalidate)) {
884             m_invalidRects.append(r);
885             if (!m_invalidateTimer.isActive())
886                 m_invalidateTimer.startOneShot(0.001);
887         } else
888             invalidateRect(r);
889     }
890 }
891 
invalidateRegion(NPRegion region)892 void PluginView::invalidateRegion(NPRegion region)
893 {
894     if (m_isWindowed)
895         return;
896 
897     RECT r;
898 
899     if (GetRgnBox(region, &r) == 0) {
900         invalidate();
901         return;
902     }
903 
904     IntRect rect(IntPoint(r.left, r.top), IntSize(r.right-r.left, r.bottom-r.top));
905     invalidateRect(rect);
906 }
907 
forceRedraw()908 void PluginView::forceRedraw()
909 {
910     if (m_isWindowed)
911         ::UpdateWindow(platformPluginWidget());
912     else
913         ::UpdateWindow(windowHandleForPlatformWidget(parent() ? parent()->hostWindow()->platformWindow() : 0));
914 }
915 
~PluginView()916 PluginView::~PluginView()
917 {
918     removeFromUnstartedListIfNecessary();
919 
920     stop();
921 
922     deleteAllValues(m_requests);
923 
924     freeStringArray(m_paramNames, m_paramCount);
925     freeStringArray(m_paramValues, m_paramCount);
926 
927     if (platformPluginWidget())
928         DestroyWindow(platformPluginWidget());
929 
930     m_parentFrame->script()->cleanupScriptObjectsForPlugin(this);
931 
932     if (m_plugin && !m_plugin->quirks().contains(PluginQuirkDontUnloadPlugin))
933         m_plugin->unload();
934 }
935 
init()936 void PluginView::init()
937 {
938     if (m_haveInitialized)
939         return;
940     m_haveInitialized = true;
941 
942     if (!m_plugin) {
943         ASSERT(m_status == PluginStatusCanNotFindPlugin);
944         return;
945     }
946 
947     if (!m_plugin->load()) {
948         m_plugin = 0;
949         m_status = PluginStatusCanNotLoadPlugin;
950         return;
951     }
952 
953     if (!startOrAddToUnstartedList()) {
954         m_status = PluginStatusCanNotLoadPlugin;
955         return;
956     }
957 
958     m_status = PluginStatusLoadedSuccessfully;
959 }
960 
platformStart()961 void PluginView::platformStart()
962 {
963     ASSERT(m_isStarted);
964     ASSERT(m_status == PluginStatusLoadedSuccessfully);
965 
966     if (m_isWindowed) {
967         registerPluginView();
968 #if !PLATFORM(WINCE)
969         setUpOffscreenPaintingHooks(hookedBeginPaint, hookedEndPaint);
970 #endif
971 
972         DWORD flags = WS_CHILD;
973         if (isSelfVisible())
974             flags |= WS_VISIBLE;
975 
976         HWND parentWindowHandle = windowHandleForPlatformWidget(m_parentFrame->view()->hostWindow()->platformWindow());
977         HWND window = ::CreateWindowEx(0, kWebPluginViewdowClassName, 0, flags,
978                                        0, 0, 0, 0, parentWindowHandle, 0, Page::instanceHandle(), 0);
979 
980 #if PLATFORM(WIN_OS) && PLATFORM(QT)
981         m_window = window;
982 #else
983         setPlatformWidget(window);
984 #endif
985 
986         // Calling SetWindowLongPtrA here makes the window proc ASCII, which is required by at least
987         // the Shockwave Director plug-in.
988 #if PLATFORM(WIN_OS) && PLATFORM(X86_64) && COMPILER(MSVC)
989         ::SetWindowLongPtrA(platformPluginWidget(), GWLP_WNDPROC, (LONG_PTR)DefWindowProcA);
990 #elif PLATFORM(WINCE)
991         ::SetWindowLong(platformPluginWidget(), GWL_WNDPROC, (LONG)DefWindowProc);
992 #else
993         ::SetWindowLongPtrA(platformPluginWidget(), GWL_WNDPROC, (LONG)DefWindowProcA);
994 #endif
995         SetProp(platformPluginWidget(), kWebPluginViewProperty, this);
996 
997         m_npWindow.type = NPWindowTypeWindow;
998         m_npWindow.window = platformPluginWidget();
999     } else {
1000         m_npWindow.type = NPWindowTypeDrawable;
1001         m_npWindow.window = 0;
1002     }
1003 
1004     updatePluginWidget();
1005 
1006     if (!m_plugin->quirks().contains(PluginQuirkDeferFirstSetWindowCall))
1007         setNPWindowRect(frameRect());
1008 }
1009 
1010 } // namespace WebCore
1011