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