6c74f4633fbb5b37aa165f889978d22e158f65c7
[WebKit-https.git] / Source / WebKit2 / WebProcess / Plugins / PluginView.cpp
1 /*
2  * Copyright (C) 2010, 2012 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "PluginView.h"
28
29 #include "NPRuntimeUtilities.h"
30 #include "Plugin.h"
31 #include "ShareableBitmap.h"
32 #include "WebCoreArgumentCoders.h"
33 #include "WebEvent.h"
34 #include "WebPage.h"
35 #include "WebPageProxyMessages.h"
36 #include "WebProcess.h"
37 #include <WebCore/Chrome.h>
38 #include <WebCore/CookieJar.h>
39 #include <WebCore/Credential.h>
40 #include <WebCore/CredentialStorage.h>
41 #include <WebCore/DocumentLoader.h>
42 #include <WebCore/MouseEvent.h>
43 #include <WebCore/FocusController.h>
44 #include <WebCore/Frame.h>
45 #include <WebCore/FrameLoadRequest.h>
46 #include <WebCore/FrameLoaderClient.h>
47 #include <WebCore/FrameView.h>
48 #include <WebCore/GraphicsContext.h>
49 #include <WebCore/HTMLPlugInElement.h>
50 #include <WebCore/HostWindow.h>
51 #include <WebCore/NetscapePlugInStreamLoader.h>
52 #include <WebCore/NetworkingContext.h>
53 #include <WebCore/Page.h>
54 #include <WebCore/ProtectionSpace.h>
55 #include <WebCore/ProxyServer.h>
56 #include <WebCore/RenderEmbeddedObject.h>
57 #include <WebCore/ResourceLoadScheduler.h>
58 #include <WebCore/ScriptValue.h>
59 #include <WebCore/ScrollView.h>
60 #include <WebCore/SecurityOrigin.h>
61 #include <WebCore/SecurityPolicy.h>
62 #include <WebCore/Settings.h>
63 #include <WebCore/UserGestureIndicator.h>
64 #include <wtf/text/StringBuilder.h>
65
66 using namespace JSC;
67 using namespace WebCore;
68
69 namespace WebKit {
70
71 // This simulated mouse click delay in HTMLPlugInImageElement.cpp should generally be the same or shorter than this delay.
72 static const double pluginSnapshotTimerDelay = 1.1;
73
74 class PluginView::URLRequest : public RefCounted<URLRequest> {
75 public:
76     static PassRefPtr<PluginView::URLRequest> create(uint64_t requestID, const FrameLoadRequest& request, bool allowPopups)
77     {
78         return adoptRef(new URLRequest(requestID, request, allowPopups));
79     }
80
81     uint64_t requestID() const { return m_requestID; }
82     const String& target() const { return m_request.frameName(); }
83     const ResourceRequest & request() const { return m_request.resourceRequest(); }
84     bool allowPopups() const { return m_allowPopups; }
85
86 private:
87     URLRequest(uint64_t requestID, const FrameLoadRequest& request, bool allowPopups)
88         : m_requestID(requestID)
89         , m_request(request)
90         , m_allowPopups(allowPopups)
91     {
92     }
93
94     uint64_t m_requestID;
95     FrameLoadRequest m_request;
96     bool m_allowPopups;
97 };
98
99 class PluginView::Stream : public RefCounted<PluginView::Stream>, NetscapePlugInStreamLoaderClient {
100 public:
101     static PassRefPtr<Stream> create(PluginView* pluginView, uint64_t streamID, const ResourceRequest& request)
102     {
103         return adoptRef(new Stream(pluginView, streamID, request));
104     }
105     ~Stream();
106
107     void start();
108     void cancel();
109
110     uint64_t streamID() const { return m_streamID; }
111
112 private:
113     Stream(PluginView* pluginView, uint64_t streamID, const ResourceRequest& request)
114         : m_pluginView(pluginView)
115         , m_streamID(streamID)
116         , m_request(request)
117         , m_streamWasCancelled(false)
118     {
119     }
120
121     // NetscapePluginStreamLoaderClient
122     virtual void didReceiveResponse(NetscapePlugInStreamLoader*, const ResourceResponse&);
123     virtual void didReceiveData(NetscapePlugInStreamLoader*, const char*, int);
124     virtual void didFail(NetscapePlugInStreamLoader*, const ResourceError&);
125     virtual void didFinishLoading(NetscapePlugInStreamLoader*);
126
127     PluginView* m_pluginView;
128     uint64_t m_streamID;
129     const ResourceRequest m_request;
130     
131     // True if the stream was explicitly cancelled by calling cancel().
132     // (As opposed to being cancelled by the user hitting the stop button for example.
133     bool m_streamWasCancelled;
134     
135     RefPtr<NetscapePlugInStreamLoader> m_loader;
136 };
137
138 PluginView::Stream::~Stream()
139 {
140     ASSERT(!m_pluginView);
141 }
142     
143 void PluginView::Stream::start()
144 {
145     ASSERT(!m_loader);
146
147     Frame* frame = m_pluginView->m_pluginElement->document()->frame();
148     ASSERT(frame);
149
150     m_loader = resourceLoadScheduler()->schedulePluginStreamLoad(frame, this, m_request);
151 }
152
153 void PluginView::Stream::cancel()
154 {
155     ASSERT(m_loader);
156
157     m_streamWasCancelled = true;
158     m_loader->cancel(m_loader->cancelledError());
159     m_loader = 0;
160 }
161
162 static String buildHTTPHeaders(const ResourceResponse& response, long long& expectedContentLength)
163 {
164     if (!response.isHTTP())
165         return String();
166
167     StringBuilder stringBuilder;
168     
169     String statusLine = String::format("HTTP %d ", response.httpStatusCode());
170     stringBuilder.append(statusLine);
171     stringBuilder.append(response.httpStatusText());
172     stringBuilder.append('\n');
173     
174     HTTPHeaderMap::const_iterator end = response.httpHeaderFields().end();
175     for (HTTPHeaderMap::const_iterator it = response.httpHeaderFields().begin(); it != end; ++it) {
176         stringBuilder.append(it->key);
177         stringBuilder.appendLiteral(": ");
178         stringBuilder.append(it->value);
179         stringBuilder.append('\n');
180     }
181     
182     String headers = stringBuilder.toString();
183     
184     // If the content is encoded (most likely compressed), then don't send its length to the plugin,
185     // which is only interested in the decoded length, not yet known at the moment.
186     // <rdar://problem/4470599> tracks a request for -[NSURLResponse expectedContentLength] to incorporate this logic.
187     String contentEncoding = response.httpHeaderField("Content-Encoding");
188     if (!contentEncoding.isNull() && contentEncoding != "identity")
189         expectedContentLength = -1;
190
191     return headers;
192 }
193
194 void PluginView::Stream::didReceiveResponse(NetscapePlugInStreamLoader*, const ResourceResponse& response)
195 {
196     // Compute the stream related data from the resource response.
197     const KURL& responseURL = response.url();
198     const String& mimeType = response.mimeType();
199     long long expectedContentLength = response.expectedContentLength();
200     
201     String headers = buildHTTPHeaders(response, expectedContentLength);
202
203     uint32_t streamLength = 0;
204     if (expectedContentLength > 0)
205         streamLength = expectedContentLength;
206
207     m_pluginView->m_plugin->streamDidReceiveResponse(m_streamID, responseURL, streamLength, response.lastModifiedDate(), mimeType, headers, response.suggestedFilename());
208 }
209
210 void PluginView::Stream::didReceiveData(NetscapePlugInStreamLoader*, const char* bytes, int length)
211 {
212     m_pluginView->m_plugin->streamDidReceiveData(m_streamID, bytes, length);
213 }
214
215 void PluginView::Stream::didFail(NetscapePlugInStreamLoader*, const ResourceError& error) 
216 {
217     // Calling streamDidFail could cause us to be deleted, so we hold on to a reference here.
218     RefPtr<Stream> protect(this);
219
220     // We only want to call streamDidFail if the stream was not explicitly cancelled by the plug-in.
221     if (!m_streamWasCancelled)
222         m_pluginView->m_plugin->streamDidFail(m_streamID, error.isCancellation());
223
224     m_pluginView->removeStream(this);
225     m_pluginView = 0;
226 }
227
228 void PluginView::Stream::didFinishLoading(NetscapePlugInStreamLoader*)
229 {
230     // Calling streamDidFinishLoading could cause us to be deleted, so we hold on to a reference here.
231     RefPtr<Stream> protectStream(this);
232
233 #if ENABLE(NETSCAPE_PLUGIN_API)
234     // Protect the plug-in while we're calling into it.
235     NPRuntimeObjectMap::PluginProtector pluginProtector(&m_pluginView->m_npRuntimeObjectMap);
236 #endif
237     m_pluginView->m_plugin->streamDidFinishLoading(m_streamID);
238
239     m_pluginView->removeStream(this);
240     m_pluginView = 0;
241 }
242
243 static inline WebPage* webPage(HTMLPlugInElement* pluginElement)
244 {
245     Frame* frame = pluginElement->document()->frame();
246     ASSERT(frame);
247
248     WebPage* webPage = static_cast<WebFrameLoaderClient*>(frame->loader()->client())->webFrame()->page();
249     ASSERT(webPage);
250
251     return webPage;
252 }
253
254 PassRefPtr<PluginView> PluginView::create(PassRefPtr<HTMLPlugInElement> pluginElement, PassRefPtr<Plugin> plugin, const Plugin::Parameters& parameters)
255 {
256     return adoptRef(new PluginView(pluginElement, plugin, parameters));
257 }
258
259 PluginView::PluginView(PassRefPtr<HTMLPlugInElement> pluginElement, PassRefPtr<Plugin> plugin, const Plugin::Parameters& parameters)
260     : PluginViewBase(0)
261     , m_pluginElement(pluginElement)
262     , m_plugin(plugin)
263     , m_webPage(webPage(m_pluginElement.get()))
264     , m_parameters(parameters)
265     , m_isInitialized(false)
266     , m_isWaitingForSynchronousInitialization(false)
267     , m_isWaitingUntilMediaCanStart(false)
268     , m_isBeingDestroyed(false)
269     , m_pendingURLRequestsTimer(RunLoop::main(), this, &PluginView::pendingURLRequestsTimerFired)
270 #if ENABLE(NETSCAPE_PLUGIN_API)
271     , m_npRuntimeObjectMap(this)
272 #endif
273     , m_manualStreamState(StreamStateInitial)
274     , m_pluginSnapshotTimer(this, &PluginView::pluginSnapshotTimerFired, pluginSnapshotTimerDelay)
275     , m_pageScaleFactor(1)
276 {
277     m_webPage->addPluginView(this);
278 }
279
280 PluginView::~PluginView()
281 {
282     if (m_webPage)
283         m_webPage->removePluginView(this);
284
285     ASSERT(!m_isBeingDestroyed);
286
287     if (m_isWaitingUntilMediaCanStart)
288         m_pluginElement->document()->removeMediaCanStartListener(this);
289
290     destroyPluginAndReset();
291
292     // Null out the plug-in element explicitly so we'll crash earlier if we try to use
293     // the plug-in view after it's been destroyed.
294     m_pluginElement = nullptr;
295 }
296
297 void PluginView::destroyPluginAndReset()
298 {
299     // Cancel all pending frame loads.
300     for (FrameLoadMap::iterator it = m_pendingFrameLoads.begin(), end = m_pendingFrameLoads.end(); it != end; ++it)
301         it->key->setLoadListener(0);
302
303     if (m_plugin) {
304         m_isBeingDestroyed = true;
305         m_plugin->destroyPlugin();
306         m_isBeingDestroyed = false;
307 #if PLATFORM(MAC)
308         if (m_webPage)
309             pluginFocusOrWindowFocusChanged(false);
310 #endif
311     }
312
313 #if ENABLE(NETSCAPE_PLUGIN_API)
314     // Invalidate the object map.
315     m_npRuntimeObjectMap.invalidate();
316 #endif
317
318     cancelAllStreams();
319 }
320
321 void PluginView::recreateAndInitialize(PassRefPtr<Plugin> plugin)
322 {
323     if (m_plugin) {
324         if (m_pluginSnapshotTimer.isActive())
325             m_pluginSnapshotTimer.stop();
326         destroyPluginAndReset();
327     }
328
329     // Reset member variables to initial values.
330     m_plugin = plugin;
331     m_isInitialized = false;
332     m_isWaitingForSynchronousInitialization = false;
333     m_isWaitingUntilMediaCanStart = false;
334     m_isBeingDestroyed = false;
335     m_manualStreamState = StreamStateInitial;
336     m_transientPaintingSnapshot = nullptr;
337
338     initializePlugin();
339 }
340
341 Frame* PluginView::frame() const
342 {
343     return m_pluginElement->document()->frame();
344 }
345
346 void PluginView::manualLoadDidReceiveResponse(const ResourceResponse& response)
347 {
348     // The plug-in can be null here if it failed to initialize.
349     if (!m_plugin)
350         return;
351
352     if (!m_isInitialized) {
353         ASSERT(m_manualStreamState == StreamStateInitial);
354         m_manualStreamState = StreamStateHasReceivedResponse;
355         m_manualStreamResponse = response;
356         return;
357     }
358
359     // Compute the stream related data from the resource response.
360     const KURL& responseURL = response.url();
361     const String& mimeType = response.mimeType();
362     long long expectedContentLength = response.expectedContentLength();
363     
364     String headers = buildHTTPHeaders(response, expectedContentLength);
365     
366     uint32_t streamLength = 0;
367     if (expectedContentLength > 0)
368         streamLength = expectedContentLength;
369
370     m_plugin->manualStreamDidReceiveResponse(responseURL, streamLength, response.lastModifiedDate(), mimeType, headers, response.suggestedFilename());
371 }
372
373 void PluginView::manualLoadDidReceiveData(const char* bytes, int length)
374 {
375     // The plug-in can be null here if it failed to initialize.
376     if (!m_plugin)
377         return;
378
379     if (!m_isInitialized) {
380         ASSERT(m_manualStreamState == StreamStateHasReceivedResponse);
381         if (!m_manualStreamData)
382             m_manualStreamData = SharedBuffer::create();
383
384         m_manualStreamData->append(bytes, length);
385         return;
386     }
387
388     m_plugin->manualStreamDidReceiveData(bytes, length);
389 }
390
391 void PluginView::manualLoadDidFinishLoading()
392 {
393     // The plug-in can be null here if it failed to initialize.
394     if (!m_plugin)
395         return;
396
397     if (!m_isInitialized) {
398         ASSERT(m_manualStreamState == StreamStateHasReceivedResponse);
399         m_manualStreamState = StreamStateFinished;
400         return;
401     }
402
403     m_plugin->manualStreamDidFinishLoading();
404 }
405
406 void PluginView::manualLoadDidFail(const ResourceError& error)
407 {
408     // The plug-in can be null here if it failed to initialize.
409     if (!m_plugin)
410         return;
411
412     if (!m_isInitialized) {
413         m_manualStreamState = StreamStateFinished;
414         m_manualStreamError = error;
415         m_manualStreamData = nullptr;
416         return;
417     }
418
419     m_plugin->manualStreamDidFail(error.isCancellation());
420 }
421
422 RenderBoxModelObject* PluginView::renderer() const
423 {
424     return toRenderBoxModelObject(m_pluginElement->renderer());
425 }
426
427 void PluginView::pageScaleFactorDidChange()
428 {
429     viewGeometryDidChange();
430 }
431
432 void PluginView::setPageScaleFactor(double scaleFactor, IntPoint)
433 {
434     m_pageScaleFactor = scaleFactor;
435     m_webPage->send(Messages::WebPageProxy::PageScaleFactorDidChange(scaleFactor));
436     pageScaleFactorDidChange();
437 }
438
439 double PluginView::pageScaleFactor()
440 {
441     return m_pageScaleFactor;
442 }
443
444 void PluginView::webPageDestroyed()
445 {
446     m_webPage = 0;
447 }
448
449 #if PLATFORM(MAC)    
450 void PluginView::setWindowIsVisible(bool windowIsVisible)
451 {
452     if (!m_isInitialized || !m_plugin)
453         return;
454
455     m_plugin->windowVisibilityChanged(windowIsVisible);
456 }
457
458 void PluginView::setWindowIsFocused(bool windowIsFocused)
459 {
460     if (!m_isInitialized || !m_plugin)
461         return;
462
463     m_plugin->windowFocusChanged(windowIsFocused);    
464 }
465
466 void PluginView::setDeviceScaleFactor(float scaleFactor)
467 {
468     if (!m_isInitialized || !m_plugin)
469         return;
470
471     m_plugin->contentsScaleFactorChanged(scaleFactor);
472 }
473
474 void PluginView::windowAndViewFramesChanged(const IntRect& windowFrameInScreenCoordinates, const IntRect& viewFrameInWindowCoordinates)
475 {
476     if (!m_isInitialized || !m_plugin)
477         return;
478
479     m_plugin->windowAndViewFramesChanged(windowFrameInScreenCoordinates, viewFrameInWindowCoordinates);
480 }
481
482 bool PluginView::sendComplexTextInput(uint64_t pluginComplexTextInputIdentifier, const String& textInput)
483 {
484     if (!m_plugin)
485         return false;
486
487     if (m_plugin->pluginComplexTextInputIdentifier() != pluginComplexTextInputIdentifier)
488         return false;
489
490     m_plugin->sendComplexTextInput(textInput);
491     return true;
492 }
493
494 void PluginView::setLayerHostingMode(LayerHostingMode layerHostingMode)
495 {
496     if (!m_plugin)
497         return;
498
499     if (!m_isInitialized) {
500         m_parameters.layerHostingMode = layerHostingMode;
501         return;
502     }
503
504     m_plugin->setLayerHostingMode(layerHostingMode);
505 }
506
507 #endif
508
509 void PluginView::initializePlugin()
510 {
511     if (m_isInitialized)
512         return;
513
514     if (!m_plugin) {
515         // We've already tried and failed to initialize the plug-in.
516         return;
517     }
518
519     if (Frame* frame = m_pluginElement->document()->frame()) {
520         if (Page* page = frame->page()) {
521             
522             // We shouldn't initialize the plug-in right now, add a listener.
523             if (!page->canStartMedia()) {
524                 if (m_isWaitingUntilMediaCanStart)
525                     return;
526                 
527                 m_isWaitingUntilMediaCanStart = true;
528                 m_pluginElement->document()->addMediaCanStartListener(this);
529                 return;
530             }
531         }
532     }
533
534     m_plugin->initialize(this, m_parameters);
535     
536     // Plug-in initialization continued in didFailToInitializePlugin() or didInitializePlugin().
537 }
538
539 void PluginView::didFailToInitializePlugin()
540 {
541     m_plugin = 0;
542     m_webPage->send(Messages::WebPageProxy::DidFailToInitializePlugin(m_parameters.mimeType));
543 }
544
545 void PluginView::didInitializePlugin()
546 {
547     m_isInitialized = true;
548
549 #if PLATFORM(MAC)
550     windowAndViewFramesChanged(m_webPage->windowFrameInScreenCoordinates(), m_webPage->viewFrameInWindowCoordinates());
551 #endif
552
553     viewGeometryDidChange();
554
555     redeliverManualStream();
556
557 #if PLATFORM(MAC)
558     if (m_pluginElement->displayState() < HTMLPlugInElement::PlayingWithPendingMouseClick)
559         m_pluginSnapshotTimer.restart();
560     else {
561         if (m_plugin->pluginLayer()) {
562             if (frame()) {
563                 frame()->view()->enterCompositingMode();
564                 m_pluginElement->setNeedsStyleRecalc(SyntheticStyleChange);
565             }
566         }
567         if (m_pluginElement->displayState() < HTMLPlugInElement::Playing)
568             m_pluginElement->dispatchPendingMouseClick();
569     }
570
571     setWindowIsVisible(m_webPage->windowIsVisible());
572     setWindowIsFocused(m_webPage->windowIsFocused());
573 #endif
574
575     if (wantsWheelEvents()) {
576         if (Frame* frame = m_pluginElement->document()->frame()) {
577             if (FrameView* frameView = frame->view())
578                 frameView->setNeedsLayout();
579         }
580     }
581 }
582
583 #if PLATFORM(MAC)
584 PlatformLayer* PluginView::platformLayer() const
585 {
586     // The plug-in can be null here if it failed to initialize.
587     if (!m_isInitialized || !m_plugin)
588         return 0;
589         
590     return m_plugin->pluginLayer();
591 }
592 #endif
593
594 JSObject* PluginView::scriptObject(JSGlobalObject* globalObject)
595 {
596     // If we're already waiting for synchronous initialization of the plugin,
597     // calls to scriptObject() are from the plug-in itself and need to return 0;
598     if (m_isWaitingForSynchronousInitialization)
599         return 0;
600
601     // We might not have started initialization of the plug-in yet, the plug-in might be in the middle
602     // of being initializing asynchronously, or initialization might have previously failed.
603     if (!m_isInitialized || !m_plugin)
604         return 0;
605
606 #if ENABLE(NETSCAPE_PLUGIN_API)
607     NPObject* scriptableNPObject = m_plugin->pluginScriptableNPObject();
608     if (!scriptableNPObject)
609         return 0;
610
611     JSObject* jsObject = m_npRuntimeObjectMap.getOrCreateJSObject(globalObject, scriptableNPObject);
612     releaseNPObject(scriptableNPObject);
613
614     return jsObject;
615 #else
616     UNUSED_PARAM(globalObject);
617     return 0;
618 #endif
619 }
620
621 void PluginView::storageBlockingStateChanged()
622 {
623     // The plug-in can be null here if it failed to initialize.
624     if (!m_isInitialized || !m_plugin)
625         return;
626
627     bool storageBlockingPolicy = !frame()->document()->securityOrigin()->canAccessPluginStorage(frame()->tree()->top()->document()->securityOrigin());
628
629     m_plugin->storageBlockingStateChanged(storageBlockingPolicy);
630 }
631
632 void PluginView::privateBrowsingStateChanged(bool privateBrowsingEnabled)
633 {
634     // The plug-in can be null here if it failed to initialize.
635     if (!m_isInitialized || !m_plugin)
636         return;
637
638     m_plugin->privateBrowsingStateChanged(privateBrowsingEnabled);
639 }
640
641 bool PluginView::getFormValue(String& formValue)
642 {
643     // The plug-in can be null here if it failed to initialize.
644     if (!m_isInitialized || !m_plugin)
645         return false;
646
647     return m_plugin->getFormValue(formValue);
648 }
649
650 bool PluginView::scroll(ScrollDirection direction, ScrollGranularity granularity)
651 {
652     // The plug-in can be null here if it failed to initialize.
653     if (!m_isInitialized || !m_plugin)
654         return false;
655
656     return m_plugin->handleScroll(direction, granularity);
657 }
658
659 Scrollbar* PluginView::horizontalScrollbar()
660 {
661     // The plug-in can be null here if it failed to initialize.
662     if (!m_isInitialized || !m_plugin)
663         return 0;
664
665     return m_plugin->horizontalScrollbar();
666 }
667
668 Scrollbar* PluginView::verticalScrollbar()
669 {
670     // The plug-in can be null here if it failed to initialize.
671     if (!m_isInitialized || !m_plugin)
672         return 0;
673
674     return m_plugin->verticalScrollbar();
675 }
676
677 bool PluginView::wantsWheelEvents()
678 {
679     // The plug-in can be null here if it failed to initialize.
680     if (!m_isInitialized || !m_plugin)
681         return 0;
682     
683     return m_plugin->wantsWheelEvents();
684 }
685
686 void PluginView::setFrameRect(const WebCore::IntRect& rect)
687 {
688     Widget::setFrameRect(rect);
689     viewGeometryDidChange();
690 }
691
692 void PluginView::paint(GraphicsContext* context, const IntRect& /*dirtyRect*/)
693 {
694     if (!m_plugin || !m_isInitialized || m_pluginElement->displayState() < HTMLPlugInElement::PlayingWithPendingMouseClick)
695         return;
696
697     if (context->paintingDisabled()) {
698         if (context->updatingControlTints())
699             m_plugin->updateControlTints(context);
700         return;
701     }
702
703     // FIXME: We should try to intersect the dirty rect with the plug-in's clip rect here.
704     IntRect paintRect = IntRect(IntPoint(), frameRect().size());
705
706     if (paintRect.isEmpty())
707         return;
708
709     if (m_transientPaintingSnapshot) {
710         m_transientPaintingSnapshot->paint(*context, contentsScaleFactor(), frameRect().location(), m_transientPaintingSnapshot->bounds());
711         return;
712     }
713     
714     GraphicsContextStateSaver stateSaver(*context);
715
716     // Translate the coordinate system so that the origin is in the top-left corner of the plug-in.
717     context->translate(frameRect().location().x(), frameRect().location().y());
718
719     m_plugin->paint(context, paintRect);
720 }
721
722 void PluginView::frameRectsChanged()
723 {
724     Widget::frameRectsChanged();
725     viewGeometryDidChange();
726 }
727
728 void PluginView::setParent(ScrollView* scrollView)
729 {
730     Widget::setParent(scrollView);
731     
732     if (scrollView)
733         initializePlugin();
734 }
735
736 PassOwnPtr<WebEvent> PluginView::createWebEvent(MouseEvent* event) const
737 {
738     WebEvent::Type type = WebEvent::NoType;
739     unsigned clickCount = 1;
740     if (event->type() == eventNames().mousedownEvent)
741         type = WebEvent::MouseDown;
742     else if (event->type() == eventNames().mouseupEvent)
743         type = WebEvent::MouseUp;
744     else if (event->type() == eventNames().mouseoverEvent) {
745         type = WebEvent::MouseMove;
746         clickCount = 0;
747     } else if (event->type() == eventNames().clickEvent)
748         return nullptr;
749     else
750         ASSERT_NOT_REACHED();
751
752     WebMouseEvent::Button button = WebMouseEvent::NoButton;
753     switch (event->button()) {
754     case WebCore::LeftButton:
755         button = WebMouseEvent::LeftButton;
756         break;
757     case WebCore::MiddleButton:
758         button = WebMouseEvent::MiddleButton;
759         break;
760     case WebCore::RightButton:
761         button = WebMouseEvent::RightButton;
762         break;
763     default:
764         ASSERT_NOT_REACHED();
765         break;
766     }
767
768     unsigned modifiers = 0;
769     if (event->shiftKey())
770         modifiers |= WebEvent::ShiftKey;
771     if (event->ctrlKey())
772         modifiers |= WebEvent::ControlKey;
773     if (event->altKey())
774         modifiers |= WebEvent::AltKey;
775     if (event->metaKey())
776         modifiers |= WebEvent::MetaKey;
777
778     return adoptPtr(new WebMouseEvent(type, button, m_plugin->convertToRootView(IntPoint(event->offsetX(), event->offsetY())), event->screenLocation(), 0, 0, 0, clickCount, static_cast<WebEvent::Modifiers>(modifiers), 0));
779 }
780
781 void PluginView::handleEvent(Event* event)
782 {
783     if (!m_isInitialized || !m_plugin)
784         return;
785
786     const WebEvent* currentEvent = WebPage::currentEvent();
787     OwnPtr<WebEvent> simulatedWebEvent;
788     if (event->isMouseEvent() && toMouseEvent(event)->isSimulated()) {
789         simulatedWebEvent = createWebEvent(toMouseEvent(event));
790         currentEvent = simulatedWebEvent.get();
791     }
792     if (!currentEvent)
793         return;
794
795     bool didHandleEvent = false;
796
797     if ((event->type() == eventNames().mousemoveEvent && currentEvent->type() == WebEvent::MouseMove)
798         || (event->type() == eventNames().mousedownEvent && currentEvent->type() == WebEvent::MouseDown)
799         || (event->type() == eventNames().mouseupEvent && currentEvent->type() == WebEvent::MouseUp)) {
800         // We have a mouse event.
801
802         // FIXME: Clicking in a scroll bar should not change focus.
803         if (currentEvent->type() == WebEvent::MouseDown) {
804             focusPluginElement();
805             frame()->eventHandler()->setCapturingMouseEventsNode(m_pluginElement.get());
806         } else if (currentEvent->type() == WebEvent::MouseUp)
807             frame()->eventHandler()->setCapturingMouseEventsNode(0);
808
809         didHandleEvent = m_plugin->handleMouseEvent(static_cast<const WebMouseEvent&>(*currentEvent));
810     } else if (event->type() == eventNames().mousewheelEvent && currentEvent->type() == WebEvent::Wheel && m_plugin->wantsWheelEvents()) {
811         // We have a wheel event.
812         didHandleEvent = m_plugin->handleWheelEvent(static_cast<const WebWheelEvent&>(*currentEvent));
813     } else if (event->type() == eventNames().mouseoverEvent && currentEvent->type() == WebEvent::MouseMove) {
814         // We have a mouse enter event.
815         didHandleEvent = m_plugin->handleMouseEnterEvent(static_cast<const WebMouseEvent&>(*currentEvent));
816     } else if (event->type() == eventNames().mouseoutEvent && currentEvent->type() == WebEvent::MouseMove) {
817         // We have a mouse leave event.
818         didHandleEvent = m_plugin->handleMouseLeaveEvent(static_cast<const WebMouseEvent&>(*currentEvent));
819     } else if (event->type() == eventNames().contextmenuEvent && currentEvent->type() == WebEvent::MouseDown) {
820         // We have a context menu event.
821         didHandleEvent = m_plugin->handleContextMenuEvent(static_cast<const WebMouseEvent&>(*currentEvent));
822     } else if ((event->type() == eventNames().keydownEvent && currentEvent->type() == WebEvent::KeyDown)
823                || (event->type() == eventNames().keyupEvent && currentEvent->type() == WebEvent::KeyUp)) {
824         // We have a keyboard event.
825         didHandleEvent = m_plugin->handleKeyboardEvent(static_cast<const WebKeyboardEvent&>(*currentEvent));
826     }
827
828     if (didHandleEvent)
829         event->setDefaultHandled();
830 }
831     
832 bool PluginView::handleEditingCommand(const String& commandName, const String& argument)
833 {
834     if (!m_isInitialized || !m_plugin)
835         return false;
836
837     return m_plugin->handleEditingCommand(commandName, argument);
838 }
839     
840 bool PluginView::isEditingCommandEnabled(const String& commandName)
841 {
842     if (!m_isInitialized || !m_plugin)
843         return false;
844
845     return m_plugin->isEditingCommandEnabled(commandName);
846 }
847
848 bool PluginView::shouldAllowScripting()
849 {
850     if (!m_isInitialized || !m_plugin)
851         return false;
852
853     return m_plugin->shouldAllowScripting();
854 }
855
856 void PluginView::notifyWidget(WidgetNotification notification)
857 {
858     switch (notification) {
859     case WillPaintFlattened:
860         if (m_plugin && m_isInitialized)
861             m_transientPaintingSnapshot = m_plugin->snapshot();
862         break;
863     case DidPaintFlattened:
864         m_transientPaintingSnapshot = nullptr;
865         break;
866     }
867 }
868
869 void PluginView::show()
870 {
871     bool wasVisible = isVisible();
872
873     setSelfVisible(true);
874
875     if (!wasVisible)
876         viewVisibilityDidChange();
877
878     Widget::show();
879 }
880
881 void PluginView::hide()
882 {
883     bool wasVisible = isVisible();
884
885     setSelfVisible(false);
886
887     if (wasVisible)
888         viewVisibilityDidChange();
889
890     Widget::hide();
891 }
892
893 bool PluginView::transformsAffectFrameRect()
894 {
895     return false;
896 }
897
898 void PluginView::viewGeometryDidChange()
899 {
900     if (!m_isInitialized || !m_plugin || !parent())
901         return;
902
903     ASSERT(frame());
904     float pageScaleFactor = frame()->page() ? frame()->page()->pageScaleFactor() : 1;
905
906     IntPoint scaledFrameRectLocation(frameRect().location().x() * pageScaleFactor, frameRect().location().y() * pageScaleFactor);
907     IntPoint scaledLocationInRootViewCoordinates(parent()->contentsToRootView(scaledFrameRectLocation));
908
909     // FIXME: We still don't get the right coordinates for transformed plugins.
910     AffineTransform transform;
911     transform.translate(scaledLocationInRootViewCoordinates.x(), scaledLocationInRootViewCoordinates.y());
912     transform.scale(pageScaleFactor);
913
914     // FIXME: The way we calculate this clip rect isn't correct.
915     // But it is still important to distinguish between empty and non-empty rects so we can notify the plug-in when it becomes invisible.
916     // Making the rect actually correct is covered by https://bugs.webkit.org/show_bug.cgi?id=95362
917     IntRect clipRect = boundsRect();
918     
919     // FIXME: We can only get a semi-reliable answer from clipRectInWindowCoordinates() when the page is not scaled.
920     // Fixing that is tracked in <rdar://problem/9026611> - Make the Widget hierarchy play nicely with transforms, for zoomed plug-ins and iframes
921     if (pageScaleFactor == 1) {
922         clipRect = clipRectInWindowCoordinates();
923         if (!clipRect.isEmpty())
924             clipRect = boundsRect();
925     }
926     
927     m_plugin->geometryDidChange(size(), clipRect, transform);
928 }
929
930 void PluginView::viewVisibilityDidChange()
931 {
932     if (!m_isInitialized || !m_plugin || !parent())
933         return;
934
935     m_plugin->visibilityDidChange();
936 }
937
938 IntRect PluginView::clipRectInWindowCoordinates() const
939 {
940     // Get the frame rect in window coordinates.
941     IntRect frameRectInWindowCoordinates = parent()->contentsToWindow(frameRect());
942
943     Frame* frame = this->frame();
944
945     // Get the window clip rect for the plugin element (in window coordinates).
946     IntRect windowClipRect = frame->view()->windowClipRectForFrameOwner(m_pluginElement.get(), true);
947
948     // Intersect the two rects to get the view clip rect in window coordinates.
949     frameRectInWindowCoordinates.intersect(windowClipRect);
950
951     return frameRectInWindowCoordinates;
952 }
953
954 void PluginView::focusPluginElement()
955 {
956     ASSERT(frame());
957     
958     if (Page* page = frame()->page())
959        page->focusController()->setFocusedNode(m_pluginElement.get(), frame());
960     else
961        frame()->document()->setFocusedNode(m_pluginElement);
962 }
963
964 void PluginView::pendingURLRequestsTimerFired()
965 {
966     ASSERT(!m_pendingURLRequests.isEmpty());
967     
968     RefPtr<URLRequest> urlRequest = m_pendingURLRequests.takeFirst();
969
970     // If there are more requests to perform, reschedule the timer.
971     if (!m_pendingURLRequests.isEmpty())
972         m_pendingURLRequestsTimer.startOneShot(0);
973     
974     performURLRequest(urlRequest.get());
975 }
976     
977 void PluginView::performURLRequest(URLRequest* request)
978 {
979     // This protector is needed to make sure the PluginView is not destroyed while it is still needed.
980     RefPtr<PluginView> protect(this);
981
982     // First, check if this is a javascript: url.
983     if (protocolIsJavaScript(request->request().url())) {
984         performJavaScriptURLRequest(request);
985         return;
986     }
987
988     if (!request->target().isNull()) {
989         performFrameLoadURLRequest(request);
990         return;
991     }
992
993     // This request is to load a URL and create a stream.
994     RefPtr<Stream> stream = PluginView::Stream::create(this, request->requestID(), request->request());
995     addStream(stream.get());
996     stream->start();
997 }
998
999 void PluginView::performFrameLoadURLRequest(URLRequest* request)
1000 {
1001     ASSERT(!request->target().isNull());
1002
1003     Frame* frame = m_pluginElement->document()->frame();
1004     if (!frame)
1005         return;
1006
1007     if (!m_pluginElement->document()->securityOrigin()->canDisplay(request->request().url())) {
1008         // We can't load the request, send back a reply to the plug-in.
1009         m_plugin->frameDidFail(request->requestID(), false);
1010         return;
1011     }
1012
1013     // First, try to find a target frame.
1014     Frame* targetFrame = frame->loader()->findFrameForNavigation(request->target());
1015     if (!targetFrame) {
1016         // We did not find a target frame. Ask our frame to load the page. This may or may not create a popup window.
1017         FrameLoadRequest frameRequest(frame, request->request());
1018         frameRequest.setFrameName(request->target());
1019         frameRequest.setShouldCheckNewWindowPolicy(true);
1020         frame->loader()->load(frameRequest);
1021
1022         // FIXME: We don't know whether the window was successfully created here so we just assume that it worked.
1023         // It's better than not telling the plug-in anything.
1024         m_plugin->frameDidFinishLoading(request->requestID());
1025         return;
1026     }
1027
1028     // Now ask the frame to load the request.
1029     targetFrame->loader()->load(FrameLoadRequest(targetFrame, request->request()));
1030
1031     WebFrame* targetWebFrame = static_cast<WebFrameLoaderClient*>(targetFrame->loader()->client())->webFrame();
1032     if (WebFrame::LoadListener* loadListener = targetWebFrame->loadListener()) {
1033         // Check if another plug-in view or even this view is waiting for the frame to load.
1034         // If it is, tell it that the load was cancelled because it will be anyway.
1035         loadListener->didFailLoad(targetWebFrame, true);
1036     }
1037     
1038     m_pendingFrameLoads.set(targetWebFrame, request);
1039     targetWebFrame->setLoadListener(this);
1040 }
1041
1042 void PluginView::performJavaScriptURLRequest(URLRequest* request)
1043 {
1044     ASSERT(protocolIsJavaScript(request->request().url()));
1045
1046     RefPtr<Frame> frame = m_pluginElement->document()->frame();
1047     if (!frame)
1048         return;
1049     
1050     String jsString = decodeURLEscapeSequences(request->request().url().string().substring(sizeof("javascript:") - 1));
1051
1052     if (!request->target().isNull()) {
1053         // For security reasons, only allow JS requests to be made on the frame that contains the plug-in.
1054         if (frame->tree()->find(request->target()) != frame) {
1055             // Let the plug-in know that its frame load failed.
1056             m_plugin->frameDidFail(request->requestID(), false);
1057             return;
1058         }
1059     }
1060
1061     // Evaluate the JavaScript code. Note that running JavaScript here could cause the plug-in to be destroyed, so we
1062     // grab references to the plug-in here.
1063     RefPtr<Plugin> plugin = m_plugin;
1064     ScriptValue result = frame->script()->executeScript(jsString, request->allowPopups());
1065
1066     // Check if evaluating the JavaScript destroyed the plug-in.
1067     if (!plugin->controller())
1068         return;
1069
1070     // Don't notify the plug-in at all about targeted javascript: requests. This matches Mozilla and WebKit1.
1071     if (!request->target().isNull())
1072         return;
1073
1074     ScriptState* scriptState = frame->script()->globalObject(pluginWorld())->globalExec();
1075     String resultString;
1076     result.getString(scriptState, resultString);
1077   
1078     // Send the result back to the plug-in.
1079     plugin->didEvaluateJavaScript(request->requestID(), resultString);
1080 }
1081
1082 void PluginView::addStream(Stream* stream)
1083 {
1084     ASSERT(!m_streams.contains(stream->streamID()));
1085     m_streams.set(stream->streamID(), stream);
1086 }
1087     
1088 void PluginView::removeStream(Stream* stream)
1089 {
1090     ASSERT(m_streams.get(stream->streamID()) == stream);
1091     
1092     m_streams.remove(stream->streamID());
1093 }
1094
1095 void PluginView::cancelAllStreams()
1096 {
1097     Vector<RefPtr<Stream> > streams;
1098     copyValuesToVector(m_streams, streams);
1099     
1100     for (size_t i = 0; i < streams.size(); ++i)
1101         streams[i]->cancel();
1102
1103     // Cancelling a stream removes it from the m_streams map, so if we cancel all streams the map should be empty.
1104     ASSERT(m_streams.isEmpty());
1105 }
1106
1107 void PluginView::redeliverManualStream()
1108 {
1109     if (m_manualStreamState == StreamStateInitial) {
1110         // Nothing to do.
1111         return;
1112     }
1113
1114     if (m_manualStreamState == StreamStateFailed) {
1115         manualLoadDidFail(m_manualStreamError);
1116         return;
1117     }
1118
1119     // Deliver the response.
1120     manualLoadDidReceiveResponse(m_manualStreamResponse);
1121
1122     // Deliver the data.
1123     if (m_manualStreamData) {
1124         const char* data;
1125         unsigned position = 0;
1126
1127         while (unsigned length = m_manualStreamData->getSomeData(data, position)) {
1128             manualLoadDidReceiveData(data, length);
1129             position += length;
1130         }
1131
1132         m_manualStreamData = nullptr;
1133     }
1134
1135     if (m_manualStreamState == StreamStateFinished)
1136         manualLoadDidFinishLoading();
1137 }
1138
1139 void PluginView::invalidateRect(const IntRect& dirtyRect)
1140 {
1141     if (!parent() || !m_plugin || !m_isInitialized)
1142         return;
1143
1144 #if PLATFORM(MAC)
1145     if (m_plugin->pluginLayer())
1146         return;
1147 #endif
1148
1149     if (m_pluginElement->displayState() < HTMLPlugInElement::PlayingWithPendingMouseClick)
1150         return;
1151
1152     RenderBoxModelObject* renderer = toRenderBoxModelObject(m_pluginElement->renderer());
1153     if (!renderer)
1154         return;
1155     
1156     IntRect contentRect(dirtyRect);
1157     contentRect.move(renderer->borderLeft() + renderer->paddingLeft(), renderer->borderTop() + renderer->paddingTop());
1158     renderer->repaintRectangle(contentRect);
1159 }
1160
1161 void PluginView::setFocus(bool hasFocus)
1162 {
1163     Widget::setFocus(hasFocus);
1164
1165     if (!m_isInitialized || !m_plugin)
1166         return;
1167
1168     m_plugin->setFocus(hasFocus);
1169 }
1170
1171 void PluginView::mediaCanStart()
1172 {
1173     ASSERT(m_isWaitingUntilMediaCanStart);
1174     m_isWaitingUntilMediaCanStart = false;
1175     
1176     initializePlugin();
1177 }
1178
1179 bool PluginView::isPluginVisible()
1180 {
1181     return isVisible();
1182 }
1183
1184 void PluginView::invalidate(const IntRect& dirtyRect)
1185 {
1186     invalidateRect(dirtyRect);
1187 }
1188
1189 String PluginView::userAgent()
1190 {
1191     Frame* frame = m_pluginElement->document()->frame();
1192     if (!frame)
1193         return String();
1194     
1195     return frame->loader()->client()->userAgent(KURL());
1196 }
1197
1198 void PluginView::loadURL(uint64_t requestID, const String& method, const String& urlString, const String& target, 
1199                          const HTTPHeaderMap& headerFields, const Vector<uint8_t>& httpBody, bool allowPopups)
1200 {
1201     FrameLoadRequest frameLoadRequest(m_pluginElement->document()->securityOrigin());
1202     frameLoadRequest.resourceRequest().setHTTPMethod(method);
1203     frameLoadRequest.resourceRequest().setURL(m_pluginElement->document()->completeURL(urlString));
1204     frameLoadRequest.resourceRequest().addHTTPHeaderFields(headerFields);
1205     frameLoadRequest.resourceRequest().setHTTPBody(FormData::create(httpBody.data(), httpBody.size()));
1206     frameLoadRequest.setFrameName(target);
1207
1208     String referrer = SecurityPolicy::generateReferrerHeader(frame()->document()->referrerPolicy(), frameLoadRequest.resourceRequest().url(), frame()->loader()->outgoingReferrer());
1209     if (!referrer.isEmpty())
1210         frameLoadRequest.resourceRequest().setHTTPReferrer(referrer);
1211
1212     m_pendingURLRequests.append(URLRequest::create(requestID, frameLoadRequest, allowPopups));
1213     m_pendingURLRequestsTimer.startOneShot(0);
1214 }
1215
1216 void PluginView::cancelStreamLoad(uint64_t streamID)
1217 {
1218     // Keep a reference to the stream. Stream::cancel might remove the stream from the map, and thus
1219     // releasing its last reference.
1220     RefPtr<Stream> stream = m_streams.get(streamID).get();
1221     if (!stream)
1222         return;
1223
1224     // Cancelling the stream here will remove it from the map.
1225     stream->cancel();
1226     ASSERT(!m_streams.contains(streamID));
1227 }
1228
1229 void PluginView::cancelManualStreamLoad()
1230 {
1231     if (!frame())
1232         return;
1233
1234     DocumentLoader* documentLoader = frame()->loader()->activeDocumentLoader();
1235     ASSERT(documentLoader);
1236     
1237     if (documentLoader->isLoadingMainResource())
1238         documentLoader->cancelMainResourceLoad(frame()->loader()->cancelledError(m_parameters.url));
1239 }
1240
1241 #if ENABLE(NETSCAPE_PLUGIN_API)
1242 NPObject* PluginView::windowScriptNPObject()
1243 {
1244     if (!frame())
1245         return 0;
1246
1247     if (!frame()->script()->canExecuteScripts(NotAboutToExecuteScript)) {
1248         // FIXME: Investigate if other browsers allow plug-ins to access JavaScript objects even if JavaScript is disabled.
1249         return 0;
1250     }
1251
1252     return m_npRuntimeObjectMap.getOrCreateNPObject(*pluginWorld()->globalData(), frame()->script()->windowShell(pluginWorld())->window());
1253 }
1254
1255 NPObject* PluginView::pluginElementNPObject()
1256 {
1257     if (!frame())
1258         return 0;
1259
1260     if (!frame()->script()->canExecuteScripts(NotAboutToExecuteScript)) {
1261         // FIXME: Investigate if other browsers allow plug-ins to access JavaScript objects even if JavaScript is disabled.
1262         return 0;
1263     }
1264
1265     JSObject* object = frame()->script()->jsObjectForPluginElement(m_pluginElement.get());
1266     ASSERT(object);
1267
1268     return m_npRuntimeObjectMap.getOrCreateNPObject(*pluginWorld()->globalData(), object);
1269 }
1270
1271 bool PluginView::evaluate(NPObject* npObject, const String& scriptString, NPVariant* result, bool allowPopups)
1272 {
1273     // FIXME: Is this check necessary?
1274     if (!m_pluginElement->document()->frame())
1275         return false;
1276
1277     // Calling evaluate will run JavaScript that can potentially remove the plug-in element, so we need to
1278     // protect the plug-in view from destruction.
1279     NPRuntimeObjectMap::PluginProtector pluginProtector(&m_npRuntimeObjectMap);
1280
1281     UserGestureIndicator gestureIndicator(allowPopups ? DefinitelyProcessingUserGesture : PossiblyProcessingUserGesture);
1282     return m_npRuntimeObjectMap.evaluate(npObject, scriptString, result);
1283 }
1284 #endif
1285
1286 void PluginView::setStatusbarText(const String& statusbarText)
1287 {
1288     if (!frame())
1289         return;
1290     
1291     Page* page = frame()->page();
1292     if (!page)
1293         return;
1294
1295     page->chrome()->setStatusbarText(frame(), statusbarText);
1296 }
1297
1298 bool PluginView::isAcceleratedCompositingEnabled()
1299 {
1300     if (!frame())
1301         return false;
1302     
1303     Settings* settings = frame()->settings();
1304     if (!settings)
1305         return false;
1306
1307     if (m_pluginElement->displayState() < HTMLPlugInElement::PlayingWithPendingMouseClick)
1308         return false;
1309     return settings->acceleratedCompositingEnabled();
1310 }
1311
1312 void PluginView::pluginProcessCrashed()
1313 {
1314     if (!m_pluginElement->renderer())
1315         return;
1316
1317     // FIXME: The renderer could also be a RenderApplet, we should handle that.
1318     if (!m_pluginElement->renderer()->isEmbeddedObject())
1319         return;
1320         
1321     RenderEmbeddedObject* renderer = toRenderEmbeddedObject(m_pluginElement->renderer());
1322     renderer->setPluginUnavailabilityReason(RenderEmbeddedObject::PluginCrashed);
1323     
1324     Widget::invalidate();
1325 }
1326
1327 void PluginView::willSendEventToPlugin()
1328 {
1329     // If we're sending an event to a plug-in, we can't control how long the plug-in
1330     // takes to process it (e.g. it may display a context menu), so we tell the UI process
1331     // to stop the responsiveness timer in this case.
1332     m_webPage->send(Messages::WebPageProxy::StopResponsivenessTimer());
1333 }
1334
1335 #if PLATFORM(WIN)
1336 HWND PluginView::nativeParentWindow()
1337 {
1338     return m_webPage->nativeWindow();
1339 }
1340
1341 void PluginView::scheduleWindowedPluginGeometryUpdate(const WindowGeometry& geometry)
1342 {
1343     m_webPage->drawingArea()->scheduleChildWindowGeometryUpdate(geometry);
1344 }
1345 #endif
1346
1347 #if PLATFORM(MAC)
1348 void PluginView::pluginFocusOrWindowFocusChanged(bool pluginHasFocusAndWindowHasFocus)
1349 {
1350     if (m_webPage)
1351         m_webPage->send(Messages::WebPageProxy::PluginFocusOrWindowFocusChanged(m_plugin->pluginComplexTextInputIdentifier(), pluginHasFocusAndWindowHasFocus));
1352 }
1353
1354 void PluginView::setComplexTextInputState(PluginComplexTextInputState pluginComplexTextInputState)
1355 {
1356     if (m_webPage)
1357         m_webPage->send(Messages::WebPageProxy::SetPluginComplexTextInputState(m_plugin->pluginComplexTextInputIdentifier(), pluginComplexTextInputState));
1358 }
1359
1360 mach_port_t PluginView::compositingRenderServerPort()
1361 {
1362     return WebProcess::shared().compositingRenderServerPort();
1363 }
1364 #endif
1365
1366 float PluginView::contentsScaleFactor()
1367 {
1368     if (Page* page = frame() ? frame()->page() : 0)
1369         return page->deviceScaleFactor();
1370         
1371     return 1;
1372 }
1373     
1374 String PluginView::proxiesForURL(const String& urlString)
1375 {
1376     const FrameLoader* frameLoader = frame() ? frame()->loader() : 0;
1377     const NetworkingContext* context = frameLoader ? frameLoader->networkingContext() : 0;
1378     Vector<ProxyServer> proxyServers = proxyServersForURL(KURL(KURL(), urlString), context);
1379     return toString(proxyServers);
1380 }
1381
1382 String PluginView::cookiesForURL(const String& urlString)
1383 {
1384     return cookies(m_pluginElement->document(), KURL(KURL(), urlString));
1385 }
1386
1387 void PluginView::setCookiesForURL(const String& urlString, const String& cookieString)
1388 {
1389     setCookies(m_pluginElement->document(), KURL(KURL(), urlString), cookieString);
1390 }
1391
1392 bool PluginView::getAuthenticationInfo(const ProtectionSpace& protectionSpace, String& username, String& password)
1393 {
1394     Credential credential = CredentialStorage::get(protectionSpace);
1395     if (credential.isEmpty())
1396         credential = CredentialStorage::getFromPersistentStorage(protectionSpace);
1397
1398     if (!credential.hasPassword())
1399         return false;
1400
1401     username = credential.user();
1402     password = credential.password();
1403
1404     return true;
1405 }
1406
1407 bool PluginView::isPrivateBrowsingEnabled()
1408 {
1409     // If we can't get the real setting, we'll assume that private browsing is enabled.
1410     if (!frame())
1411         return true;
1412
1413     if (!frame()->document()->securityOrigin()->canAccessPluginStorage(frame()->tree()->top()->document()->securityOrigin()))
1414         return true;
1415
1416     Settings* settings = frame()->settings();
1417     if (!settings)
1418         return true;
1419
1420     return settings->privateBrowsingEnabled();
1421 }
1422
1423 bool PluginView::asynchronousPluginInitializationEnabled() const
1424 {
1425     return m_webPage->asynchronousPluginInitializationEnabled();
1426 }
1427
1428 bool PluginView::asynchronousPluginInitializationEnabledForAllPlugins() const
1429 {
1430     return m_webPage->asynchronousPluginInitializationEnabledForAllPlugins();
1431 }
1432
1433 bool PluginView::artificialPluginInitializationDelayEnabled() const
1434 {
1435     return m_webPage->artificialPluginInitializationDelayEnabled();
1436 }
1437
1438 void PluginView::protectPluginFromDestruction()
1439 {
1440     if (!m_isBeingDestroyed)
1441         ref();
1442 }
1443
1444 static void derefPluginView(PluginView* pluginView)
1445 {
1446     pluginView->deref();
1447 }
1448
1449 void PluginView::unprotectPluginFromDestruction()
1450 {
1451     if (m_isBeingDestroyed)
1452         return;
1453
1454     // A plug-in may ask us to evaluate JavaScript that removes the plug-in from the
1455     // page, but expect the object to still be alive when the call completes. Flash,
1456     // for example, may crash if the plug-in is destroyed and we return to code for
1457     // the destroyed object higher on the stack. To prevent this, if the plug-in has
1458     // only one remaining reference, call deref() asynchronously.
1459     if (hasOneRef())
1460         RunLoop::main()->dispatch(bind(derefPluginView, this));
1461     else
1462         deref();
1463 }
1464
1465 void PluginView::didFinishLoad(WebFrame* webFrame)
1466 {
1467     RefPtr<URLRequest> request = m_pendingFrameLoads.take(webFrame);
1468     ASSERT(request);
1469     webFrame->setLoadListener(0);
1470
1471     m_plugin->frameDidFinishLoading(request->requestID());
1472 }
1473
1474 void PluginView::didFailLoad(WebFrame* webFrame, bool wasCancelled)
1475 {
1476     RefPtr<URLRequest> request = m_pendingFrameLoads.take(webFrame);
1477     ASSERT(request);
1478     webFrame->setLoadListener(0);
1479     
1480     m_plugin->frameDidFail(request->requestID(), wasCancelled);
1481 }
1482
1483 #if PLUGIN_ARCHITECTURE(X11)
1484 uint64_t PluginView::createPluginContainer()
1485 {
1486     uint64_t windowID = 0;
1487     m_webPage->sendSync(Messages::WebPageProxy::CreatePluginContainer(), Messages::WebPageProxy::CreatePluginContainer::Reply(windowID));
1488     return windowID;
1489 }
1490
1491 void PluginView::windowedPluginGeometryDidChange(const WebCore::IntRect& frameRect, const WebCore::IntRect& clipRect, uint64_t windowID)
1492 {
1493     m_webPage->send(Messages::WebPageProxy::WindowedPluginGeometryDidChange(frameRect, clipRect, windowID));
1494 }
1495 #endif
1496
1497 void PluginView::pluginSnapshotTimerFired(DeferrableOneShotTimer<PluginView>* timer)
1498 {
1499     ASSERT_UNUSED(timer, timer == &m_pluginSnapshotTimer);
1500     ASSERT(m_plugin);
1501
1502     // Snapshot might be 0 if plugin size is 0x0.
1503     RefPtr<ShareableBitmap> snapshot = m_plugin->snapshot();
1504     RefPtr<Image> snapshotImage;
1505     if (snapshot)
1506         snapshotImage = snapshot->createImage();
1507     m_pluginElement->updateSnapshot(snapshotImage.release());
1508     destroyPluginAndReset();
1509     m_plugin = 0;
1510 }
1511
1512 } // namespace WebKit