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