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