• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
3  * Copyright (C) 2008 Collabora Ltd. All rights reserved.
4  *
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