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