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