WebCore:
[WebKit-https.git] / WebCore / plugins / PluginView.cpp
1 /*
2  * Copyright (C) 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
3  * Copyright (C) 2008 Collabora Ltd. All rights reserved.
4  * Copyright (C) 2010 Girish Ramakrishnan <girish@forwardbias.in>
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
16  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
19  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
26  */
27
28 #include "config.h"
29 #include "PluginView.h"
30
31 #include "Bridge.h"
32 #include "Chrome.h"
33 #include "Document.h"
34 #include "DocumentLoader.h"
35 #include "Element.h"
36 #include "FocusController.h"
37 #include "Frame.h"
38 #include "FrameLoader.h"
39 #include "FrameLoaderClient.h"
40 #include "FrameTree.h"
41 #include "FrameView.h"
42 #include "GraphicsContext.h"
43 #include "HTMLNames.h"
44 #include "HTMLPlugInElement.h"
45 #include "Image.h"
46 #include "KeyboardEvent.h"
47 #include "MIMETypeRegistry.h"
48 #include "MouseEvent.h"
49 #include "NotImplemented.h"
50 #include "Page.h"
51 #include "PlatformMouseEvent.h"
52 #include "PluginDatabase.h"
53 #include "PluginDebug.h"
54 #include "PluginMainThreadScheduler.h"
55 #include "PluginPackage.h"
56 #include "RenderBox.h"
57 #include "RenderObject.h"
58 #include "ScriptController.h"
59 #include "ScriptValue.h"
60 #include "SecurityOrigin.h"
61 #include "Settings.h"
62 #include "npruntime_impl.h"
63 #include <wtf/ASCIICType.h>
64
65 #if OS(WINDOWS) && ENABLE(NETSCAPE_PLUGIN_API)
66 #include "PluginMessageThrottlerWin.h"
67 #endif
68
69 #if USE(JSC)
70 #include "JSDOMBinding.h"
71 #include "JSDOMWindow.h"
72 #include "c_instance.h"
73 #include "runtime_root.h"
74 #include <runtime/JSLock.h>
75 #include <runtime/JSValue.h>
76
77 using JSC::ExecState;
78 using JSC::JSLock;
79 using JSC::JSObject;
80 using JSC::JSValue;
81 using JSC::UString;
82 #endif
83
84 #if ENABLE(NETSCAPE_PLUGIN_API)
85
86 using std::min;
87
88 using namespace WTF;
89
90 namespace WebCore {
91
92 using namespace HTMLNames;
93
94 static int s_callingPlugin;
95
96 typedef HashMap<NPP, PluginView*> InstanceMap;
97
98 static InstanceMap& instanceMap()
99 {
100     static InstanceMap& map = *new InstanceMap;
101     return map;
102 }
103
104 static String scriptStringIfJavaScriptURL(const KURL& url)
105 {
106     if (!protocolIsJavaScript(url))
107         return String();
108
109     // This returns an unescaped string
110     return decodeURLEscapeSequences(url.string().substring(11));
111 }
112
113 PluginView* PluginView::s_currentPluginView = 0;
114
115 void PluginView::popPopupsStateTimerFired(Timer<PluginView>*)
116 {
117     popPopupsEnabledState();
118 }
119
120 IntRect PluginView::windowClipRect() const
121 {
122     // Start by clipping to our bounds.
123     IntRect clipRect(m_windowRect);
124     
125     // Take our element and get the clip rect from the enclosing layer and frame view.
126     RenderLayer* layer = m_element->renderer()->enclosingLayer();
127     FrameView* parentView = m_element->document()->view();
128     clipRect.intersect(parentView->windowClipRectForLayer(layer, true));
129
130     return clipRect;
131 }
132
133 void PluginView::setFrameRect(const IntRect& rect)
134 {
135     if (m_element->document()->printing())
136         return;
137
138     if (rect != frameRect())
139         Widget::setFrameRect(rect);
140
141     updatePluginWidget();
142
143 #if OS(WINDOWS) || OS(SYMBIAN)
144     // On Windows and Symbian, always call plugin to change geometry.
145     setNPWindowRect(rect);
146 #elif defined(XP_UNIX)
147     // On Unix, multiple calls to setNPWindow() in windowed mode causes Flash to crash
148     if (m_mode == NP_FULL || !m_isWindowed)
149         setNPWindowRect(rect);
150 #endif
151 }
152
153 void PluginView::frameRectsChanged()
154 {
155     updatePluginWidget();
156 }
157
158 void PluginView::handleEvent(Event* event)
159 {
160     if (!m_plugin || m_isWindowed)
161         return;
162
163     // Protect the plug-in from deletion while dispatching the event.
164     RefPtr<PluginView> protect(this);
165
166     if (event->isMouseEvent())
167         handleMouseEvent(static_cast<MouseEvent*>(event));
168     else if (event->isKeyboardEvent())
169         handleKeyboardEvent(static_cast<KeyboardEvent*>(event));
170 #if defined(XP_UNIX) && ENABLE(NETSCAPE_PLUGIN_API)
171     else if (event->type() == eventNames().DOMFocusOutEvent || event->type() == eventNames().focusoutEvent)
172         handleFocusOutEvent();
173     else if (event->type() == eventNames().DOMFocusInEvent || event->type() == eventNames().focusinEvent)
174         handleFocusInEvent();
175 #endif
176 }
177
178 void PluginView::init()
179 {
180     if (m_haveInitialized)
181         return;
182
183     m_haveInitialized = true;
184
185     if (!m_plugin) {
186         ASSERT(m_status == PluginStatusCanNotFindPlugin);
187         return;
188     }
189
190     LOG(Plugins, "PluginView::init(): Initializing plug-in '%s'", m_plugin->name().utf8().data());
191
192     if (!m_plugin->load()) {
193         m_plugin = 0;
194         m_status = PluginStatusCanNotLoadPlugin;
195         return;
196     }
197
198     if (!startOrAddToUnstartedList()) {
199         m_status = PluginStatusCanNotLoadPlugin;
200         return;
201     }
202
203     m_status = PluginStatusLoadedSuccessfully;
204 }
205
206 bool PluginView::startOrAddToUnstartedList()
207 {
208     if (!m_parentFrame->page())
209         return false;
210
211     // We only delay starting the plug-in if we're going to kick off the load
212     // ourselves. Otherwise, the loader will try to deliver data before we've
213     // started the plug-in.
214     if (!m_loadManually && !m_parentFrame->page()->canStartMedia()) {
215         m_parentFrame->document()->addMediaCanStartListener(this);
216         m_isWaitingToStart = true;
217         return true;
218     }
219
220     return start();
221 }
222
223 bool PluginView::start()
224 {
225     if (m_isStarted)
226         return false;
227
228     m_isWaitingToStart = false;
229
230     PluginMainThreadScheduler::scheduler().registerPlugin(m_instance);
231
232     ASSERT(m_plugin);
233     ASSERT(m_plugin->pluginFuncs()->newp);
234
235     NPError npErr;
236     {
237         PluginView::setCurrentPluginView(this);
238 #if USE(JSC)
239         JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
240 #endif
241         setCallingPlugin(true);
242         npErr = m_plugin->pluginFuncs()->newp((NPMIMEType)m_mimeType.utf8().data(), m_instance, m_mode, m_paramCount, m_paramNames, m_paramValues, NULL);
243         setCallingPlugin(false);
244         LOG_NPERROR(npErr);
245         PluginView::setCurrentPluginView(0);
246     }
247
248     if (npErr != NPERR_NO_ERROR) {
249         m_status = PluginStatusCanNotLoadPlugin;
250         PluginMainThreadScheduler::scheduler().unregisterPlugin(m_instance);
251         return false;
252     }
253
254     m_isStarted = true;
255
256     if (!m_url.isEmpty() && !m_loadManually) {
257         FrameLoadRequest frameLoadRequest;
258         frameLoadRequest.resourceRequest().setHTTPMethod("GET");
259         frameLoadRequest.resourceRequest().setURL(m_url);
260         load(frameLoadRequest, false, 0);
261     }
262
263     m_status = PluginStatusLoadedSuccessfully;
264
265     if (!platformStart())
266         m_status = PluginStatusCanNotLoadPlugin;
267
268     if (m_status != PluginStatusLoadedSuccessfully)
269         return false;
270
271     if (parentFrame()->page())
272         parentFrame()->page()->didStartPlugin(this);
273
274     return true;
275 }
276
277 void PluginView::mediaCanStart()
278 {
279     ASSERT(!m_isStarted);
280     if (!start())
281         parentFrame()->loader()->client()->dispatchDidFailToStartPlugin(this);
282 }
283
284 PluginView::~PluginView()
285 {
286     LOG(Plugins, "PluginView::~PluginView()");
287
288     ASSERT(!m_lifeSupportTimer.isActive());
289
290     // If we failed to find the plug-in, we'll return early in our constructor, and
291     // m_instance will be 0.
292     if (m_instance)
293         instanceMap().remove(m_instance);
294
295     if (m_isWaitingToStart)
296         m_parentFrame->document()->removeMediaCanStartListener(this);
297
298     stop();
299
300     deleteAllValues(m_requests);
301
302     freeStringArray(m_paramNames, m_paramCount);
303     freeStringArray(m_paramValues, m_paramCount);
304
305     platformDestroy();
306
307     m_parentFrame->script()->cleanupScriptObjectsForPlugin(this);
308
309     if (m_plugin && !(m_plugin->quirks().contains(PluginQuirkDontUnloadPlugin)))
310         m_plugin->unload();
311 }
312
313 void PluginView::stop()
314 {
315     if (!m_isStarted)
316         return;
317
318     if (parentFrame()->page())
319         parentFrame()->page()->didStopPlugin(this);
320
321     LOG(Plugins, "PluginView::stop(): Stopping plug-in '%s'", m_plugin->name().utf8().data());
322
323     HashSet<RefPtr<PluginStream> > streams = m_streams;
324     HashSet<RefPtr<PluginStream> >::iterator end = streams.end();
325     for (HashSet<RefPtr<PluginStream> >::iterator it = streams.begin(); it != end; ++it) {
326         (*it)->stop();
327         disconnectStream((*it).get());
328     }
329
330     ASSERT(m_streams.isEmpty());
331
332     m_isStarted = false;
333
334 #if USE(JSC)
335     JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
336 #endif
337
338 #if ENABLE(NETSCAPE_PLUGIN_API)
339 #ifdef XP_WIN
340     // Unsubclass the window
341     if (m_isWindowed) {
342 #if OS(WINCE)
343         WNDPROC currentWndProc = (WNDPROC)GetWindowLong(platformPluginWidget(), GWL_WNDPROC);
344
345         if (currentWndProc == PluginViewWndProc)
346             SetWindowLong(platformPluginWidget(), GWL_WNDPROC, (LONG)m_pluginWndProc);
347 #else
348         WNDPROC currentWndProc = (WNDPROC)GetWindowLongPtr(platformPluginWidget(), GWLP_WNDPROC);
349
350         if (currentWndProc == PluginViewWndProc)
351             SetWindowLongPtr(platformPluginWidget(), GWLP_WNDPROC, (LONG_PTR)m_pluginWndProc);
352 #endif
353     }
354 #endif // XP_WIN
355 #endif // ENABLE(NETSCAPE_PLUGIN_API)
356
357 #if !defined(XP_MACOSX)
358     // Clear the window
359     m_npWindow.window = 0;
360
361     if (m_plugin->pluginFuncs()->setwindow && !m_plugin->quirks().contains(PluginQuirkDontSetNullWindowHandleOnDestroy)) {
362         PluginView::setCurrentPluginView(this);
363         setCallingPlugin(true);
364         m_plugin->pluginFuncs()->setwindow(m_instance, &m_npWindow);
365         setCallingPlugin(false);
366         PluginView::setCurrentPluginView(0);
367     }
368
369 #ifdef XP_UNIX
370     if (m_isWindowed && m_npWindow.ws_info)
371            delete (NPSetWindowCallbackStruct *)m_npWindow.ws_info;
372     m_npWindow.ws_info = 0;
373 #endif
374
375 #endif // !defined(XP_MACOSX)
376
377     PluginMainThreadScheduler::scheduler().unregisterPlugin(m_instance);
378
379     NPSavedData* savedData = 0;
380     PluginView::setCurrentPluginView(this);
381     setCallingPlugin(true);
382     NPError npErr = m_plugin->pluginFuncs()->destroy(m_instance, &savedData);
383     setCallingPlugin(false);
384     LOG_NPERROR(npErr);
385     PluginView::setCurrentPluginView(0);
386
387 #if ENABLE(NETSCAPE_PLUGIN_API)
388     if (savedData) {
389         // TODO: Actually save this data instead of just discarding it
390         if (savedData->buf)
391             NPN_MemFree(savedData->buf);
392         NPN_MemFree(savedData);
393     }
394 #endif
395
396     m_instance->pdata = 0;
397 }
398
399 void PluginView::setCurrentPluginView(PluginView* pluginView)
400 {
401     s_currentPluginView = pluginView;
402 }
403
404 PluginView* PluginView::currentPluginView()
405 {
406     return s_currentPluginView;
407 }
408
409 static char* createUTF8String(const String& str)
410 {
411     CString cstr = str.utf8();
412     char* result = reinterpret_cast<char*>(fastMalloc(cstr.length() + 1));
413
414     strncpy(result, cstr.data(), cstr.length() + 1);
415
416     return result;
417 }
418
419 void PluginView::performRequest(PluginRequest* request)
420 {
421     if (!m_isStarted)
422         return;
423
424     // don't let a plugin start any loads if it is no longer part of a document that is being 
425     // displayed unless the loads are in the same frame as the plugin.
426     const String& targetFrameName = request->frameLoadRequest().frameName();
427     if (m_parentFrame->loader()->documentLoader() != m_parentFrame->loader()->activeDocumentLoader() &&
428         (targetFrameName.isNull() || m_parentFrame->tree()->find(targetFrameName) != m_parentFrame))
429         return;
430
431     KURL requestURL = request->frameLoadRequest().resourceRequest().url();
432     String jsString = scriptStringIfJavaScriptURL(requestURL);
433
434     if (jsString.isNull()) {
435         // if this is not a targeted request, create a stream for it. otherwise,
436         // just pass it off to the loader
437         if (targetFrameName.isEmpty()) {
438             RefPtr<PluginStream> stream = PluginStream::create(this, m_parentFrame.get(), request->frameLoadRequest().resourceRequest(), request->sendNotification(), request->notifyData(), plugin()->pluginFuncs(), instance(), m_plugin->quirks());
439             m_streams.add(stream);
440             stream->start();
441         } else {
442             // If the target frame is our frame, we could destroy the
443             // PluginView, so we protect it. <rdar://problem/6991251>
444             RefPtr<PluginView> protect(this);
445
446             m_parentFrame->loader()->load(request->frameLoadRequest().resourceRequest(), targetFrameName, false);
447
448             // FIXME: <rdar://problem/4807469> This should be sent when the document has finished loading
449             if (request->sendNotification()) {
450                 PluginView::setCurrentPluginView(this);
451 #if USE(JSC)
452                 JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
453 #endif
454                 setCallingPlugin(true);
455                 m_plugin->pluginFuncs()->urlnotify(m_instance, requestURL.string().utf8().data(), NPRES_DONE, request->notifyData());
456                 setCallingPlugin(false);
457                 PluginView::setCurrentPluginView(0);
458             }
459         }
460         return;
461     }
462
463     // Targeted JavaScript requests are only allowed on the frame that contains the JavaScript plugin
464     // and this has been made sure in ::load.
465     ASSERT(targetFrameName.isEmpty() || m_parentFrame->tree()->find(targetFrameName) == m_parentFrame);
466     
467     // Executing a script can cause the plugin view to be destroyed, so we keep a reference to the parent frame.
468     RefPtr<Frame> parentFrame = m_parentFrame;
469     ScriptValue result = m_parentFrame->script()->executeScript(jsString, request->shouldAllowPopups());
470
471     if (targetFrameName.isNull()) {
472         String resultString;
473
474 #if USE(JSC)
475         ScriptState* scriptState = parentFrame->script()->globalObject(pluginWorld())->globalExec();
476 #elif USE(V8)
477         ScriptState* scriptState = 0; // Not used with V8
478 #endif
479         CString cstr;
480         if (result.getString(scriptState, resultString))
481             cstr = resultString.utf8();
482
483         RefPtr<PluginStream> stream = PluginStream::create(this, m_parentFrame.get(), request->frameLoadRequest().resourceRequest(), request->sendNotification(), request->notifyData(), plugin()->pluginFuncs(), instance(), m_plugin->quirks());
484         m_streams.add(stream);
485         stream->sendJavaScriptStream(requestURL, cstr);
486     }
487 }
488
489 void PluginView::requestTimerFired(Timer<PluginView>* timer)
490 {
491     ASSERT(timer == &m_requestTimer);
492     ASSERT(m_requests.size() > 0);
493     ASSERT(!m_isJavaScriptPaused);
494
495     PluginRequest* request = m_requests[0];
496     m_requests.remove(0);
497     
498     // Schedule a new request before calling performRequest since the call to
499     // performRequest can cause the plugin view to be deleted.
500     if (m_requests.size() > 0)
501         m_requestTimer.startOneShot(0);
502
503     performRequest(request);
504     delete request;
505 }
506
507 void PluginView::scheduleRequest(PluginRequest* request)
508 {
509     m_requests.append(request);
510
511     if (!m_isJavaScriptPaused)
512         m_requestTimer.startOneShot(0);
513 }
514
515 NPError PluginView::load(const FrameLoadRequest& frameLoadRequest, bool sendNotification, void* notifyData)
516 {
517     ASSERT(frameLoadRequest.resourceRequest().httpMethod() == "GET" || frameLoadRequest.resourceRequest().httpMethod() == "POST");
518
519     KURL url = frameLoadRequest.resourceRequest().url();
520     
521     if (url.isEmpty())
522         return NPERR_INVALID_URL;
523
524     // Don't allow requests to be made when the document loader is stopping all loaders.
525     DocumentLoader* loader = m_parentFrame->loader()->documentLoader();
526     if (!loader || loader->isStopping())
527         return NPERR_GENERIC_ERROR;
528
529     const String& targetFrameName = frameLoadRequest.frameName();
530     String jsString = scriptStringIfJavaScriptURL(url);
531
532     if (!jsString.isNull()) {
533         // Return NPERR_GENERIC_ERROR if JS is disabled. This is what Mozilla does.
534         if (!m_parentFrame->script()->canExecuteScripts(NotAboutToExecuteScript))
535             return NPERR_GENERIC_ERROR;
536
537         // For security reasons, only allow JS requests to be made on the frame that contains the plug-in.
538         if (!targetFrameName.isNull() && m_parentFrame->tree()->find(targetFrameName) != m_parentFrame)
539             return NPERR_INVALID_PARAM;
540     } else if (!SecurityOrigin::canDisplay(url, String(), m_parentFrame->document()))
541             return NPERR_GENERIC_ERROR;
542
543     PluginRequest* request = new PluginRequest(frameLoadRequest, sendNotification, notifyData, arePopupsAllowed());
544     scheduleRequest(request);
545
546     return NPERR_NO_ERROR;
547 }
548
549 static KURL makeURL(const KURL& baseURL, const char* relativeURLString)
550 {
551     String urlString = relativeURLString;
552
553     // Strip return characters.
554     urlString.replace('\n', "");
555     urlString.replace('\r', "");
556
557     return KURL(baseURL, urlString);
558 }
559
560 NPError PluginView::getURLNotify(const char* url, const char* target, void* notifyData)
561 {
562     FrameLoadRequest frameLoadRequest;
563
564     frameLoadRequest.setFrameName(target);
565     frameLoadRequest.resourceRequest().setHTTPMethod("GET");
566     frameLoadRequest.resourceRequest().setURL(makeURL(m_baseURL, url));
567
568     return load(frameLoadRequest, true, notifyData);
569 }
570
571 NPError PluginView::getURL(const char* url, const char* target)
572 {
573     FrameLoadRequest frameLoadRequest;
574
575     frameLoadRequest.setFrameName(target);
576     frameLoadRequest.resourceRequest().setHTTPMethod("GET");
577     frameLoadRequest.resourceRequest().setURL(makeURL(m_baseURL, url));
578
579     return load(frameLoadRequest, false, 0);
580 }
581
582 NPError PluginView::postURLNotify(const char* url, const char* target, uint32_t len, const char* buf, NPBool file, void* notifyData)
583 {
584     return handlePost(url, target, len, buf, file, notifyData, true, true);
585 }
586
587 NPError PluginView::postURL(const char* url, const char* target, uint32_t len, const char* buf, NPBool file)
588 {
589     // As documented, only allow headers to be specified via NPP_PostURL when using a file.
590     return handlePost(url, target, len, buf, file, 0, false, file);
591 }
592
593 NPError PluginView::newStream(NPMIMEType type, const char* target, NPStream** stream)
594 {
595     notImplemented();
596     // Unsupported
597     return NPERR_GENERIC_ERROR;
598 }
599
600 int32_t PluginView::write(NPStream* stream, int32_t len, void* buffer)
601 {
602     notImplemented();
603     // Unsupported
604     return -1;
605 }
606
607 NPError PluginView::destroyStream(NPStream* stream, NPReason reason)
608 {
609     if (!stream || PluginStream::ownerForStream(stream) != m_instance)
610         return NPERR_INVALID_INSTANCE_ERROR;
611
612     PluginStream* browserStream = static_cast<PluginStream*>(stream->ndata);
613     browserStream->cancelAndDestroyStream(reason);
614
615     return NPERR_NO_ERROR;
616 }
617
618 void PluginView::status(const char* message)
619 {
620     if (Page* page = m_parentFrame->page())
621         page->chrome()->setStatusbarText(m_parentFrame.get(), String::fromUTF8(message));
622 }
623
624 NPError PluginView::setValue(NPPVariable variable, void* value)
625 {
626     LOG(Plugins, "PluginView::setValue(%s): ", prettyNameForNPPVariable(variable, value).data());
627
628     switch (variable) {
629     case NPPVpluginWindowBool:
630         m_isWindowed = value;
631         return NPERR_NO_ERROR;
632     case NPPVpluginTransparentBool:
633         m_isTransparent = value;
634         return NPERR_NO_ERROR;
635 #if defined(XP_MACOSX)
636     case NPPVpluginDrawingModel: {
637         // Can only set drawing model inside NPP_New()
638         if (this != currentPluginView())
639            return NPERR_GENERIC_ERROR;
640
641         NPDrawingModel newDrawingModel = NPDrawingModel(uintptr_t(value));
642         switch (newDrawingModel) {
643         case NPDrawingModelCoreGraphics:
644             m_drawingModel = newDrawingModel;
645             return NPERR_NO_ERROR;
646 #ifndef NP_NO_QUICKDRAW
647         case NPDrawingModelQuickDraw:
648 #endif
649         case NPDrawingModelCoreAnimation:
650         default:
651             LOG(Plugins, "Plugin asked for unsupported drawing model: %s",
652                     prettyNameForDrawingModel(newDrawingModel));
653             return NPERR_GENERIC_ERROR;
654         }
655     }
656
657     case NPPVpluginEventModel: {
658         // Can only set event model inside NPP_New()
659         if (this != currentPluginView())
660            return NPERR_GENERIC_ERROR;
661
662         NPEventModel newEventModel = NPEventModel(uintptr_t(value));
663         switch (newEventModel) {
664 #ifndef NP_NO_CARBON
665         case NPEventModelCarbon:
666 #endif
667         case NPEventModelCocoa:
668             m_eventModel = newEventModel;
669             return NPERR_NO_ERROR;
670
671         default:
672             LOG(Plugins, "Plugin asked for unsupported event model: %s",
673                     prettyNameForEventModel(newEventModel));
674             return NPERR_GENERIC_ERROR;
675         }
676     }
677 #endif // defined(XP_MACOSX)
678
679 #if PLATFORM(QT) && defined(MOZ_PLATFORM_MAEMO) && (MOZ_PLATFORM_MAEMO == 5)
680     case NPPVpluginWindowlessLocalBool:
681         m_renderToImage = true;
682         return NPERR_NO_ERROR;
683 #endif
684
685     default:
686         notImplemented();
687         return NPERR_GENERIC_ERROR;
688     }
689 }
690
691 void PluginView::invalidateTimerFired(Timer<PluginView>* timer)
692 {
693     ASSERT(timer == &m_invalidateTimer);
694
695     for (unsigned i = 0; i < m_invalidRects.size(); i++)
696         invalidateRect(m_invalidRects[i]);
697     m_invalidRects.clear();
698 }
699
700
701 void PluginView::pushPopupsEnabledState(bool state)
702 {
703     m_popupStateStack.append(state);
704 }
705  
706 void PluginView::popPopupsEnabledState()
707 {
708     m_popupStateStack.removeLast();
709 }
710
711 bool PluginView::arePopupsAllowed() const
712 {
713     if (!m_popupStateStack.isEmpty())
714         return m_popupStateStack.last();
715
716     return false;
717 }
718
719 void PluginView::setJavaScriptPaused(bool paused)
720 {
721     if (m_isJavaScriptPaused == paused)
722         return;
723     m_isJavaScriptPaused = paused;
724
725     if (m_isJavaScriptPaused)
726         m_requestTimer.stop();
727     else if (!m_requests.isEmpty())
728         m_requestTimer.startOneShot(0);
729 }
730
731 #if USE(JSC)
732 PassRefPtr<JSC::Bindings::Instance> PluginView::bindingInstance()
733 {
734 #if ENABLE(NETSCAPE_PLUGIN_API)
735     NPObject* object = 0;
736
737     if (!m_isStarted || !m_plugin || !m_plugin->pluginFuncs()->getvalue)
738         return 0;
739
740     // On Windows, calling Java's NPN_GetValue can allow the message loop to
741     // run, allowing loading to take place or JavaScript to run. Protect the
742     // PluginView from destruction. <rdar://problem/6978804>
743     RefPtr<PluginView> protect(this);
744
745     NPError npErr;
746     {
747         PluginView::setCurrentPluginView(this);
748         JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
749         setCallingPlugin(true);
750         npErr = m_plugin->pluginFuncs()->getvalue(m_instance, NPPVpluginScriptableNPObject, &object);
751         setCallingPlugin(false);
752         PluginView::setCurrentPluginView(0);
753     }
754
755     if (hasOneRef()) {
756         // The renderer for the PluginView was destroyed during the above call, and
757         // the PluginView will be destroyed when this function returns, so we
758         // return null.
759         return 0;
760     }
761
762     if (npErr != NPERR_NO_ERROR || !object)
763         return 0;
764
765     RefPtr<JSC::Bindings::RootObject> root = m_parentFrame->script()->createRootObject(this);
766     RefPtr<JSC::Bindings::Instance> instance = JSC::Bindings::CInstance::create(object, root.release());
767
768     _NPN_ReleaseObject(object);
769
770     return instance.release();
771 #else
772     return 0;
773 #endif
774 }
775 #endif
776
777 void PluginView::disconnectStream(PluginStream* stream)
778 {
779     ASSERT(m_streams.contains(stream));
780
781     m_streams.remove(stream);
782 }
783
784 void PluginView::setParameters(const Vector<String>& paramNames, const Vector<String>& paramValues)
785 {
786     ASSERT(paramNames.size() == paramValues.size());
787
788     unsigned size = paramNames.size();
789     unsigned paramCount = 0;
790
791     m_paramNames = reinterpret_cast<char**>(fastMalloc(sizeof(char*) * size));
792     m_paramValues = reinterpret_cast<char**>(fastMalloc(sizeof(char*) * size));
793
794     for (unsigned i = 0; i < size; i++) {
795         if (m_plugin->quirks().contains(PluginQuirkRemoveWindowlessVideoParam) && equalIgnoringCase(paramNames[i], "windowlessvideo"))
796             continue;
797
798         if (paramNames[i] == "pluginspage")
799             m_pluginsPage = paramValues[i];
800
801         m_paramNames[paramCount] = createUTF8String(paramNames[i]);
802         m_paramValues[paramCount] = createUTF8String(paramValues[i]);
803
804         paramCount++;
805     }
806
807     m_paramCount = paramCount;
808 }
809
810 PluginView::PluginView(Frame* parentFrame, const IntSize& size, PluginPackage* plugin, Element* element, const KURL& url, const Vector<String>& paramNames, const Vector<String>& paramValues, const String& mimeType, bool loadManually)
811     : m_parentFrame(parentFrame)
812     , m_plugin(plugin)
813     , m_element(element)
814     , m_isStarted(false)
815     , m_url(url)
816     , m_baseURL(m_parentFrame->loader()->completeURL(m_parentFrame->document()->baseURL().string()))
817     , m_status(PluginStatusLoadedSuccessfully)
818     , m_requestTimer(this, &PluginView::requestTimerFired)
819     , m_invalidateTimer(this, &PluginView::invalidateTimerFired)
820     , m_popPopupsStateTimer(this, &PluginView::popPopupsStateTimerFired)
821     , m_lifeSupportTimer(this, &PluginView::lifeSupportTimerFired)
822     , m_mode(loadManually ? NP_FULL : NP_EMBED)
823     , m_paramNames(0)
824     , m_paramValues(0)
825     , m_mimeType(mimeType)
826     , m_instance(0)
827 #if defined(XP_MACOSX)
828     , m_isWindowed(false)
829 #else
830     , m_isWindowed(true)
831 #endif
832     , m_isTransparent(false)
833     , m_haveInitialized(false)
834     , m_isWaitingToStart(false)
835 #if defined(XP_UNIX)
836     , m_needsXEmbed(false)
837 #endif
838 #if OS(WINDOWS) && ENABLE(NETSCAPE_PLUGIN_API)
839     , m_pluginWndProc(0)
840     , m_lastMessage(0)
841     , m_isCallingPluginWndProc(false)
842     , m_wmPrintHDC(0)
843     , m_haveUpdatedPluginWidget(false)
844 #endif
845 #if (PLATFORM(QT) && OS(WINDOWS)) || defined(XP_MACOSX)
846     , m_window(0)
847 #endif
848 #if defined(XP_MACOSX)
849     , m_drawingModel(NPDrawingModel(-1))
850     , m_eventModel(NPEventModel(-1))
851     , m_contextRef(0)
852     , m_fakeWindow(0)
853 #endif
854 #if defined(XP_UNIX) && ENABLE(NETSCAPE_PLUGIN_API)
855     , m_hasPendingGeometryChange(true)
856     , m_drawable(0)
857     , m_visual(0)
858     , m_colormap(0)
859     , m_pluginDisplay(0)
860 #endif
861 #if PLATFORM(QT) && defined(MOZ_PLATFORM_MAEMO) && (MOZ_PLATFORM_MAEMO == 5)
862     , m_renderToImage(false)
863 #endif
864     , m_loadManually(loadManually)
865     , m_manualStream(0)
866     , m_isJavaScriptPaused(false)
867     , m_isHalted(false)
868     , m_hasBeenHalted(false)
869     , m_haveCalledSetWindow(false)
870 {
871     if (!m_plugin) {
872         m_status = PluginStatusCanNotFindPlugin;
873         return;
874     }
875
876     m_instance = &m_instanceStruct;
877     m_instance->ndata = this;
878     m_instance->pdata = 0;
879
880     instanceMap().add(m_instance, this);
881
882     setParameters(paramNames, paramValues);
883
884     memset(&m_npWindow, 0, sizeof(m_npWindow));
885 #if defined(XP_MACOSX)
886     memset(&m_npCgContext, 0, sizeof(m_npCgContext));
887 #endif
888
889     resize(size);
890 }
891
892 void PluginView::focusPluginElement()
893 {
894     // Focus the plugin
895     if (Page* page = m_parentFrame->page())
896         page->focusController()->setFocusedFrame(m_parentFrame);
897     m_parentFrame->document()->setFocusedNode(m_element);
898 }
899
900 void PluginView::didReceiveResponse(const ResourceResponse& response)
901 {
902     if (m_status != PluginStatusLoadedSuccessfully)
903         return;
904
905     ASSERT(m_loadManually);
906     ASSERT(!m_manualStream);
907
908     m_manualStream = PluginStream::create(this, m_parentFrame.get(), m_parentFrame->loader()->activeDocumentLoader()->request(), false, 0, plugin()->pluginFuncs(), instance(), m_plugin->quirks());
909     m_manualStream->setLoadManually(true);
910
911     m_manualStream->didReceiveResponse(0, response);
912 }
913
914 void PluginView::didReceiveData(const char* data, int length)
915 {
916     if (m_status != PluginStatusLoadedSuccessfully)
917         return;
918
919     ASSERT(m_loadManually);
920     ASSERT(m_manualStream);
921     
922     m_manualStream->didReceiveData(0, data, length);
923 }
924
925 void PluginView::didFinishLoading()
926 {
927     if (m_status != PluginStatusLoadedSuccessfully)
928         return;
929
930     ASSERT(m_loadManually);
931     ASSERT(m_manualStream);
932
933     m_manualStream->didFinishLoading(0);
934 }
935
936 void PluginView::didFail(const ResourceError& error)
937 {
938     if (m_status != PluginStatusLoadedSuccessfully)
939         return;
940
941     ASSERT(m_loadManually);
942     ASSERT(m_manualStream);
943
944     m_manualStream->didFail(0, error);
945 }
946
947 void PluginView::setCallingPlugin(bool b) const
948 {
949     if (!m_plugin->quirks().contains(PluginQuirkHasModalMessageLoop))
950         return;
951
952     if (b)
953         ++s_callingPlugin;
954     else
955         --s_callingPlugin;
956
957     ASSERT(s_callingPlugin >= 0);
958 }
959
960 bool PluginView::isCallingPlugin()
961 {
962     return s_callingPlugin > 0;
963 }
964
965 PassRefPtr<PluginView> PluginView::create(Frame* parentFrame, const IntSize& size, Element* element, const KURL& url, const Vector<String>& paramNames, const Vector<String>& paramValues, const String& mimeType, bool loadManually)
966 {
967     // if we fail to find a plugin for this MIME type, findPlugin will search for
968     // a plugin by the file extension and update the MIME type, so pass a mutable String
969     String mimeTypeCopy = mimeType;
970     PluginPackage* plugin = PluginDatabase::installedPlugins()->findPlugin(url, mimeTypeCopy);
971
972     // No plugin was found, try refreshing the database and searching again
973     if (!plugin && PluginDatabase::installedPlugins()->refresh()) {
974         mimeTypeCopy = mimeType;
975         plugin = PluginDatabase::installedPlugins()->findPlugin(url, mimeTypeCopy);
976     }
977
978     return adoptRef(new PluginView(parentFrame, size, plugin, element, url, paramNames, paramValues, mimeTypeCopy, loadManually));
979 }
980
981 void PluginView::freeStringArray(char** stringArray, int length)
982 {
983     if (!stringArray)
984         return;
985
986     for (int i = 0; i < length; i++)
987         fastFree(stringArray[i]);
988
989     fastFree(stringArray);
990 }
991
992 static inline bool startsWithBlankLine(const Vector<char>& buffer)
993 {
994     return buffer.size() > 0 && buffer[0] == '\n';
995 }
996
997 static inline int locationAfterFirstBlankLine(const Vector<char>& buffer)
998 {
999     const char* bytes = buffer.data();
1000     unsigned length = buffer.size();
1001
1002     for (unsigned i = 0; i < length - 4; i++) {
1003         // Support for Acrobat. It sends "\n\n".
1004         if (bytes[i] == '\n' && bytes[i + 1] == '\n')
1005             return i + 2;
1006         
1007         // Returns the position after 2 CRLF's or 1 CRLF if it is the first line.
1008         if (bytes[i] == '\r' && bytes[i + 1] == '\n') {
1009             i += 2;
1010             if (i == 2)
1011                 return i;
1012             else if (bytes[i] == '\n')
1013                 // Support for Director. It sends "\r\n\n" (3880387).
1014                 return i + 1;
1015             else if (bytes[i] == '\r' && bytes[i + 1] == '\n')
1016                 // Support for Flash. It sends "\r\n\r\n" (3758113).
1017                 return i + 2;
1018         }
1019     }
1020
1021     return -1;
1022 }
1023
1024 static inline const char* findEOL(const char* bytes, unsigned length)
1025 {
1026     // According to the HTTP specification EOL is defined as
1027     // a CRLF pair. Unfortunately, some servers will use LF
1028     // instead. Worse yet, some servers will use a combination
1029     // of both (e.g. <header>CRLFLF<body>), so findEOL needs
1030     // to be more forgiving. It will now accept CRLF, LF or
1031     // CR.
1032     //
1033     // It returns NULL if EOLF is not found or it will return
1034     // a pointer to the first terminating character.
1035     for (unsigned i = 0; i < length; i++) {
1036         if (bytes[i] == '\n')
1037             return bytes + i;
1038         if (bytes[i] == '\r') {
1039             // Check to see if spanning buffer bounds
1040             // (CRLF is across reads). If so, wait for
1041             // next read.
1042             if (i + 1 == length)
1043                 break;
1044
1045             return bytes + i;
1046         }
1047     }
1048
1049     return 0;
1050 }
1051
1052 static inline String capitalizeRFC822HeaderFieldName(const String& name)
1053 {
1054     bool capitalizeCharacter = true;
1055     String result;
1056
1057     for (unsigned i = 0; i < name.length(); i++) {
1058         UChar c;
1059
1060         if (capitalizeCharacter && name[i] >= 'a' && name[i] <= 'z')
1061             c = toASCIIUpper(name[i]);
1062         else if (!capitalizeCharacter && name[i] >= 'A' && name[i] <= 'Z')
1063             c = toASCIILower(name[i]);
1064         else
1065             c = name[i];
1066
1067         if (name[i] == '-')
1068             capitalizeCharacter = true;
1069         else
1070             capitalizeCharacter = false;
1071
1072         result.append(c);
1073     }
1074
1075     return result;
1076 }
1077
1078 static inline HTTPHeaderMap parseRFC822HeaderFields(const Vector<char>& buffer, unsigned length)
1079 {
1080     const char* bytes = buffer.data();
1081     const char* eol;
1082     String lastKey;
1083     HTTPHeaderMap headerFields;
1084
1085     // Loop ove rlines until we're past the header, or we can't find any more end-of-lines
1086     while ((eol = findEOL(bytes, length))) {
1087         const char* line = bytes;
1088         int lineLength = eol - bytes;
1089         
1090         // Move bytes to the character after the terminator as returned by findEOL.
1091         bytes = eol + 1;
1092         if ((*eol == '\r') && (*bytes == '\n'))
1093             bytes++; // Safe since findEOL won't return a spanning CRLF.
1094
1095         length -= (bytes - line);
1096         if (lineLength == 0)
1097             // Blank line; we're at the end of the header
1098             break;
1099         else if (*line == ' ' || *line == '\t') {
1100             // Continuation of the previous header
1101             if (lastKey.isNull()) {
1102                 // malformed header; ignore it and continue
1103                 continue;
1104             } else {
1105                 // Merge the continuation of the previous header
1106                 String currentValue = headerFields.get(lastKey);
1107                 String newValue(line, lineLength);
1108
1109                 headerFields.set(lastKey, currentValue + newValue);
1110             }
1111         } else {
1112             // Brand new header
1113             const char* colon;
1114             for (colon = line; *colon != ':' && colon != eol; colon++) {
1115                 // empty loop
1116             }
1117             if (colon == eol) 
1118                 // malformed header; ignore it and continue
1119                 continue;
1120             else {
1121                 lastKey = capitalizeRFC822HeaderFieldName(String(line, colon - line));
1122                 String value;
1123
1124                 for (colon++; colon != eol; colon++) {
1125                     if (*colon != ' ' && *colon != '\t')
1126                         break;
1127                 }
1128                 if (colon == eol)
1129                     value = "";
1130                 else
1131                     value = String(colon, eol - colon);
1132
1133                 String oldValue = headerFields.get(lastKey);
1134                 if (!oldValue.isNull()) {
1135                     String tmp = oldValue;
1136                     tmp += ", ";
1137                     tmp += value;
1138                     value = tmp;
1139                 }
1140
1141                 headerFields.set(lastKey, value);
1142             }
1143         }
1144     }
1145
1146     return headerFields;
1147 }
1148
1149 NPError PluginView::handlePost(const char* url, const char* target, uint32_t len, const char* buf, bool file, void* notifyData, bool sendNotification, bool allowHeaders)
1150 {
1151     if (!url || !len || !buf)
1152         return NPERR_INVALID_PARAM;
1153
1154     FrameLoadRequest frameLoadRequest;
1155
1156     HTTPHeaderMap headerFields;
1157     Vector<char> buffer;
1158     
1159     if (file) {
1160         NPError readResult = handlePostReadFile(buffer, len, buf);
1161         if(readResult != NPERR_NO_ERROR)
1162             return readResult;
1163     } else {
1164         buffer.resize(len);
1165         memcpy(buffer.data(), buf, len);
1166     }
1167
1168     const char* postData = buffer.data();
1169     int postDataLength = buffer.size();
1170
1171     if (allowHeaders) {
1172         if (startsWithBlankLine(buffer)) {
1173             postData++;
1174             postDataLength--;
1175         } else {
1176             int location = locationAfterFirstBlankLine(buffer);
1177             if (location != -1) {
1178                 // If the blank line is somewhere in the middle of the buffer, everything before is the header
1179                 headerFields = parseRFC822HeaderFields(buffer, location);
1180                 unsigned dataLength = buffer.size() - location;
1181
1182                 // Sometimes plugins like to set Content-Length themselves when they post,
1183                 // but WebFoundation does not like that. So we will remove the header
1184                 // and instead truncate the data to the requested length.
1185                 String contentLength = headerFields.get("Content-Length");
1186
1187                 if (!contentLength.isNull())
1188                     dataLength = min(contentLength.toInt(), (int)dataLength);
1189                 headerFields.remove("Content-Length");
1190
1191                 postData += location;
1192                 postDataLength = dataLength;
1193             }
1194         }
1195     }
1196
1197     frameLoadRequest.resourceRequest().setHTTPMethod("POST");
1198     frameLoadRequest.resourceRequest().setURL(makeURL(m_baseURL, url));
1199     frameLoadRequest.resourceRequest().addHTTPHeaderFields(headerFields);
1200     frameLoadRequest.resourceRequest().setHTTPBody(FormData::create(postData, postDataLength));
1201     frameLoadRequest.setFrameName(target);
1202
1203     return load(frameLoadRequest, sendNotification, notifyData);
1204 }
1205
1206 void PluginView::invalidateWindowlessPluginRect(const IntRect& rect)
1207 {
1208     if (!isVisible())
1209         return;
1210     
1211     if (!m_element->renderer())
1212         return;
1213     RenderBox* renderer = toRenderBox(m_element->renderer());
1214     
1215     IntRect dirtyRect = rect;
1216     dirtyRect.move(renderer->borderLeft() + renderer->paddingLeft(), renderer->borderTop() + renderer->paddingTop());
1217     renderer->repaintRectangle(dirtyRect);
1218 }
1219
1220 void PluginView::paintMissingPluginIcon(GraphicsContext* context, const IntRect& rect)
1221 {
1222     static RefPtr<Image> nullPluginImage;
1223     if (!nullPluginImage)
1224         nullPluginImage = Image::loadPlatformResource("nullPlugin");
1225
1226     IntRect imageRect(frameRect().x(), frameRect().y(), nullPluginImage->width(), nullPluginImage->height());
1227
1228     int xOffset = (frameRect().width() - imageRect.width()) / 2;
1229     int yOffset = (frameRect().height() - imageRect.height()) / 2;
1230
1231     imageRect.move(xOffset, yOffset);
1232
1233     if (!rect.intersects(imageRect))
1234         return;
1235
1236     context->save();
1237     context->clip(windowClipRect());
1238     context->drawImage(nullPluginImage.get(), DeviceColorSpace, imageRect.location());
1239     context->restore();
1240 }
1241
1242 static const char* MozillaUserAgent = "Mozilla/5.0 ("
1243 #if defined(XP_MACOSX)
1244         "Macintosh; U; Intel Mac OS X;"
1245 #elif defined(XP_WIN)
1246         "Windows; U; Windows NT 5.1;"
1247 #elif defined(XP_UNIX)
1248 // The Gtk port uses X11 plugins in Mac.
1249 #if OS(DARWIN) && PLATFORM(GTK)
1250     "X11; U; Intel Mac OS X;"
1251 #else
1252     "X11; U; Linux i686;"
1253 #endif
1254 #endif
1255         " en-US; rv:1.8.1) Gecko/20061010 Firefox/2.0";
1256
1257 const char* PluginView::userAgent()
1258 {
1259     if (m_plugin->quirks().contains(PluginQuirkWantsMozillaUserAgent))
1260         return MozillaUserAgent;
1261
1262     if (m_userAgent.isNull())
1263         m_userAgent = m_parentFrame->loader()->userAgent(m_url).utf8();
1264
1265     return m_userAgent.data();
1266 }
1267
1268 #if ENABLE(NETSCAPE_PLUGIN_API)
1269 const char* PluginView::userAgentStatic()
1270 {
1271     return MozillaUserAgent;
1272 }
1273 #endif
1274
1275
1276 Node* PluginView::node() const
1277 {
1278     return m_element;
1279 }
1280
1281 String PluginView::pluginName() const
1282 {
1283     return m_plugin->name();
1284 }
1285
1286 void PluginView::lifeSupportTimerFired(Timer<PluginView>*)
1287 {
1288     deref();
1289 }
1290
1291 void PluginView::keepAlive()
1292 {
1293     if (m_lifeSupportTimer.isActive())
1294         return;
1295
1296     ref();
1297     m_lifeSupportTimer.startOneShot(0);
1298 }
1299
1300 #if ENABLE(NETSCAPE_PLUGIN_API)
1301 void PluginView::keepAlive(NPP instance)
1302 {
1303     PluginView* view = instanceMap().get(instance);
1304     if (!view)
1305         return;
1306
1307     view->keepAlive();
1308 }
1309
1310 NPError PluginView::getValueStatic(NPNVariable variable, void* value)
1311 {
1312     LOG(Plugins, "PluginView::getValueStatic(%s)", prettyNameForNPNVariable(variable).data());
1313
1314     NPError result;
1315     if (platformGetValueStatic(variable, value, &result))
1316         return result;
1317
1318     return NPERR_GENERIC_ERROR;
1319 }
1320
1321 NPError PluginView::getValue(NPNVariable variable, void* value)
1322 {
1323     LOG(Plugins, "PluginView::getValue(%s)", prettyNameForNPNVariable(variable).data());
1324
1325     NPError result;
1326     if (platformGetValue(variable, value, &result))
1327         return result;
1328
1329     if (platformGetValueStatic(variable, value, &result))
1330         return result;
1331
1332     switch (variable) {
1333     case NPNVWindowNPObject: {
1334         if (m_isJavaScriptPaused)
1335             return NPERR_GENERIC_ERROR;
1336
1337         NPObject* windowScriptObject = m_parentFrame->script()->windowScriptNPObject();
1338
1339         // Return value is expected to be retained, as described here: <http://www.mozilla.org/projects/plugin/npruntime.html>
1340         if (windowScriptObject)
1341             _NPN_RetainObject(windowScriptObject);
1342
1343         void** v = (void**)value;
1344         *v = windowScriptObject;
1345
1346         return NPERR_NO_ERROR;
1347     }
1348
1349     case NPNVPluginElementNPObject: {
1350         if (m_isJavaScriptPaused)
1351             return NPERR_GENERIC_ERROR;
1352
1353         NPObject* pluginScriptObject = 0;
1354
1355         if (m_element->hasTagName(appletTag) || m_element->hasTagName(embedTag) || m_element->hasTagName(objectTag))
1356             pluginScriptObject = static_cast<HTMLPlugInElement*>(m_element)->getNPObject();
1357
1358         // Return value is expected to be retained, as described here: <http://www.mozilla.org/projects/plugin/npruntime.html>
1359         if (pluginScriptObject)
1360             _NPN_RetainObject(pluginScriptObject);
1361
1362         void** v = (void**)value;
1363         *v = pluginScriptObject;
1364
1365         return NPERR_NO_ERROR;
1366     }
1367
1368     case NPNVprivateModeBool: {
1369         Page* page = m_parentFrame->page();
1370         if (!page)
1371             return NPERR_GENERIC_ERROR;
1372         *((NPBool*)value) = !page->settings() || page->settings()->privateBrowsingEnabled();
1373         return NPERR_NO_ERROR;
1374     }
1375
1376     default:
1377         return NPERR_GENERIC_ERROR;
1378     }
1379 }
1380 #endif
1381
1382 void PluginView::privateBrowsingStateChanged(bool privateBrowsingEnabled)
1383 {
1384     NPP_SetValueProcPtr setValue = m_plugin->pluginFuncs()->setvalue;
1385     if (!setValue)
1386         return;
1387
1388     PluginView::setCurrentPluginView(this);
1389     JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly);
1390     setCallingPlugin(true);
1391     NPBool value = privateBrowsingEnabled;
1392     setValue(m_instance, NPNVprivateModeBool, &value);
1393     setCallingPlugin(false);
1394     PluginView::setCurrentPluginView(0);
1395 }
1396
1397 } // namespace WebCore
1398
1399 #endif // ENABLE(NETSCAPE_PLUGIN_API)