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