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