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