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