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