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