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