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