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