46089c3e1f697bd9c8e5f02b6dcce7804db9aecd
[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/BitmapImage.h>
38 #include <WebCore/Chrome.h>
39 #include <WebCore/CookieJar.h>
40 #include <WebCore/Credential.h>
41 #include <WebCore/CredentialStorage.h>
42 #include <WebCore/DocumentLoader.h>
43 #include <WebCore/EventHandler.h>
44 #include <WebCore/FocusController.h>
45 #include <WebCore/FrameLoadRequest.h>
46 #include <WebCore/FrameLoader.h>
47 #include <WebCore/FrameLoaderClient.h>
48 #include <WebCore/FrameView.h>
49 #include <WebCore/GraphicsContext.h>
50 #include <WebCore/HTMLPlugInElement.h>
51 #include <WebCore/HTMLPlugInImageElement.h>
52 #include <WebCore/HTTPHeaderNames.h>
53 #include <WebCore/HostWindow.h>
54 #include <WebCore/MIMETypeRegistry.h>
55 #include <WebCore/MainFrame.h>
56 #include <WebCore/MouseEvent.h>
57 #include <WebCore/NetscapePlugInStreamLoader.h>
58 #include <WebCore/NetworkingContext.h>
59 #include <WebCore/Page.h>
60 #include <WebCore/PageThrottler.h>
61 #include <WebCore/PlatformMouseEvent.h>
62 #include <WebCore/ProtectionSpace.h>
63 #include <WebCore/ProxyServer.h>
64 #include <WebCore/RenderEmbeddedObject.h>
65 #include <WebCore/ResourceLoadScheduler.h>
66 #include <WebCore/ScriptController.h>
67 #include <WebCore/ScrollView.h>
68 #include <WebCore/SecurityOrigin.h>
69 #include <WebCore/SecurityPolicy.h>
70 #include <WebCore/Settings.h>
71 #include <WebCore/UserGestureIndicator.h>
72 #include <bindings/ScriptValue.h>
73 #include <wtf/text/StringBuilder.h>
74
75 using namespace JSC;
76 using namespace WebCore;
77
78 namespace WebKit {
79
80 // This simulated mouse click delay in HTMLPlugInImageElement.cpp should generally be the same or shorter than this delay.
81 static const auto pluginSnapshotTimerDelay = std::chrono::milliseconds { 1100 };
82
83 class PluginView::URLRequest : public RefCounted<URLRequest> {
84 public:
85     static PassRefPtr<PluginView::URLRequest> create(uint64_t requestID, const FrameLoadRequest& request, bool allowPopups)
86     {
87         return adoptRef(new URLRequest(requestID, request, allowPopups));
88     }
89
90     uint64_t requestID() const { return m_requestID; }
91     const String& target() const { return m_request.frameName(); }
92     const ResourceRequest & request() const { return m_request.resourceRequest(); }
93     bool allowPopups() const { return m_allowPopups; }
94
95 private:
96     URLRequest(uint64_t requestID, const FrameLoadRequest& request, bool allowPopups)
97         : m_requestID(requestID)
98         , m_request(request)
99         , m_allowPopups(allowPopups)
100     {
101     }
102
103     uint64_t m_requestID;
104     FrameLoadRequest m_request;
105     bool m_allowPopups;
106 };
107
108 class PluginView::Stream : public RefCounted<PluginView::Stream>, NetscapePlugInStreamLoaderClient {
109 public:
110     static PassRefPtr<Stream> create(PluginView* pluginView, uint64_t streamID, const ResourceRequest& request)
111     {
112         return adoptRef(new Stream(pluginView, streamID, request));
113     }
114     ~Stream();
115
116     void start();
117     void cancel();
118
119     uint64_t streamID() const { return m_streamID; }
120
121 private:
122     Stream(PluginView* pluginView, uint64_t streamID, const ResourceRequest& request)
123         : m_pluginView(pluginView)
124         , m_streamID(streamID)
125         , m_request(request)
126         , m_streamWasCancelled(false)
127     {
128     }
129
130     // NetscapePluginStreamLoaderClient
131     virtual void didReceiveResponse(NetscapePlugInStreamLoader*, const ResourceResponse&);
132     virtual void didReceiveData(NetscapePlugInStreamLoader*, const char*, int);
133     virtual void didFail(NetscapePlugInStreamLoader*, const ResourceError&);
134     virtual void didFinishLoading(NetscapePlugInStreamLoader*);
135
136     PluginView* m_pluginView;
137     uint64_t m_streamID;
138     const ResourceRequest m_request;
139     
140     // True if the stream was explicitly cancelled by calling cancel().
141     // (As opposed to being cancelled by the user hitting the stop button for example.
142     bool m_streamWasCancelled;
143     
144     RefPtr<NetscapePlugInStreamLoader> m_loader;
145 };
146
147 PluginView::Stream::~Stream()
148 {
149     ASSERT(!m_pluginView);
150 }
151     
152 void PluginView::Stream::start()
153 {
154     ASSERT(m_pluginView->m_plugin);
155     ASSERT(!m_loader);
156
157     Frame* frame = m_pluginView->m_pluginElement->document().frame();
158     ASSERT(frame);
159
160     m_loader = resourceLoadScheduler()->schedulePluginStreamLoad(frame, this, m_request);
161 }
162
163 void PluginView::Stream::cancel()
164 {
165     ASSERT(m_loader);
166
167     m_streamWasCancelled = true;
168     m_loader->cancel(m_loader->cancelledError());
169     m_loader = 0;
170 }
171
172 static String buildHTTPHeaders(const ResourceResponse& response, long long& expectedContentLength)
173 {
174     if (!response.isHTTP())
175         return String();
176
177     StringBuilder stringBuilder;
178     
179     String statusLine = String::format("HTTP %d ", response.httpStatusCode());
180     stringBuilder.append(statusLine);
181     stringBuilder.append(response.httpStatusText());
182     stringBuilder.append('\n');
183     
184     HTTPHeaderMap::const_iterator end = response.httpHeaderFields().end();
185     for (HTTPHeaderMap::const_iterator it = response.httpHeaderFields().begin(); it != end; ++it) {
186         stringBuilder.append(it->key);
187         stringBuilder.appendLiteral(": ");
188         stringBuilder.append(it->value);
189         stringBuilder.append('\n');
190     }
191     
192     String headers = stringBuilder.toString();
193     
194     // If the content is encoded (most likely compressed), then don't send its length to the plugin,
195     // which is only interested in the decoded length, not yet known at the moment.
196     // <rdar://problem/4470599> tracks a request for -[NSURLResponse expectedContentLength] to incorporate this logic.
197     String contentEncoding = response.httpHeaderField(HTTPHeaderName::ContentEncoding);
198     if (!contentEncoding.isNull() && contentEncoding != "identity")
199         expectedContentLength = -1;
200
201     return headers;
202 }
203
204 static uint32_t lastModifiedDate(const ResourceResponse& response)
205 {
206     double lastModified = response.lastModified();
207     if (!std::isfinite(lastModified))
208         return 0;
209
210     return lastModified * 1000;
211 }
212
213 void PluginView::Stream::didReceiveResponse(NetscapePlugInStreamLoader*, const ResourceResponse& response)
214 {
215     // Compute the stream related data from the resource response.
216     const URL& responseURL = response.url();
217     const String& mimeType = response.mimeType();
218     long long expectedContentLength = response.expectedContentLength();
219     
220     String headers = buildHTTPHeaders(response, expectedContentLength);
221
222     uint32_t streamLength = 0;
223     if (expectedContentLength > 0)
224         streamLength = expectedContentLength;
225
226     m_pluginView->m_plugin->streamDidReceiveResponse(m_streamID, responseURL, streamLength, lastModifiedDate(response), mimeType, headers, response.suggestedFilename());
227 }
228
229 void PluginView::Stream::didReceiveData(NetscapePlugInStreamLoader*, const char* bytes, int length)
230 {
231     m_pluginView->m_plugin->streamDidReceiveData(m_streamID, bytes, length);
232 }
233
234 void PluginView::Stream::didFail(NetscapePlugInStreamLoader*, const ResourceError& error) 
235 {
236     // Calling streamDidFail could cause us to be deleted, so we hold on to a reference here.
237     Ref<Stream> protect(*this);
238
239     // We only want to call streamDidFail if the stream was not explicitly cancelled by the plug-in.
240     if (!m_streamWasCancelled)
241         m_pluginView->m_plugin->streamDidFail(m_streamID, error.isCancellation());
242
243     m_pluginView->removeStream(this);
244     m_pluginView = 0;
245 }
246
247 void PluginView::Stream::didFinishLoading(NetscapePlugInStreamLoader*)
248 {
249     // Calling streamDidFinishLoading could cause us to be deleted, so we hold on to a reference here.
250     Ref<Stream> protect(*this);
251
252 #if ENABLE(NETSCAPE_PLUGIN_API)
253     // Protect the plug-in while we're calling into it.
254     NPRuntimeObjectMap::PluginProtector pluginProtector(&m_pluginView->m_npRuntimeObjectMap);
255 #endif
256     m_pluginView->m_plugin->streamDidFinishLoading(m_streamID);
257
258     m_pluginView->removeStream(this);
259     m_pluginView = 0;
260 }
261
262 static inline WebPage* webPage(HTMLPlugInElement* pluginElement)
263 {
264     Frame* frame = pluginElement->document().frame();
265     ASSERT(frame);
266
267     WebFrame* webFrame = WebFrame::fromCoreFrame(*frame);
268     if (!webFrame)
269         return nullptr;
270
271     return webFrame->page();
272 }
273
274 PassRefPtr<PluginView> PluginView::create(PassRefPtr<HTMLPlugInElement> pluginElement, PassRefPtr<Plugin> plugin, const Plugin::Parameters& parameters)
275 {
276     return adoptRef(new PluginView(pluginElement, plugin, parameters));
277 }
278
279 PluginView::PluginView(PassRefPtr<HTMLPlugInElement> pluginElement, PassRefPtr<Plugin> plugin, const Plugin::Parameters& parameters)
280     : PluginViewBase(0)
281     , m_pluginElement(pluginElement)
282     , m_plugin(plugin)
283     , m_webPage(webPage(m_pluginElement.get()))
284     , m_parameters(parameters)
285     , m_isInitialized(false)
286     , m_isWaitingForSynchronousInitialization(false)
287     , m_isWaitingUntilMediaCanStart(false)
288     , m_isBeingDestroyed(false)
289     , m_pluginProcessHasCrashed(false)
290     , m_didPlugInStartOffScreen(false)
291     , m_pendingURLRequestsTimer(RunLoop::main(), this, &PluginView::pendingURLRequestsTimerFired)
292 #if ENABLE(NETSCAPE_PLUGIN_API)
293     , m_npRuntimeObjectMap(this)
294 #endif
295     , m_manualStreamState(StreamStateInitial)
296     , m_pluginSnapshotTimer(this, &PluginView::pluginSnapshotTimerFired, pluginSnapshotTimerDelay)
297     , m_countSnapshotRetries(0)
298     , m_didReceiveUserInteraction(false)
299     , m_pageScaleFactor(1)
300 {
301     m_webPage->addPluginView(this);
302 }
303
304 PluginView::~PluginView()
305 {
306     if (m_webPage)
307         m_webPage->removePluginView(this);
308
309     ASSERT(!m_isBeingDestroyed);
310
311     if (m_isWaitingUntilMediaCanStart)
312         m_pluginElement->document().removeMediaCanStartListener(this);
313
314     destroyPluginAndReset();
315
316     // Null out the plug-in element explicitly so we'll crash earlier if we try to use
317     // the plug-in view after it's been destroyed.
318     m_pluginElement = nullptr;
319 }
320
321 void PluginView::destroyPluginAndReset()
322 {
323     // Cancel all pending frame loads.
324     for (FrameLoadMap::iterator it = m_pendingFrameLoads.begin(), end = m_pendingFrameLoads.end(); it != end; ++it)
325         it->key->setLoadListener(0);
326
327     if (m_plugin) {
328         m_isBeingDestroyed = true;
329         m_plugin->destroyPlugin();
330         m_isBeingDestroyed = false;
331
332         m_pendingURLRequests.clear();
333         m_pendingURLRequestsTimer.stop();
334
335 #if PLATFORM(COCOA)
336         if (m_webPage)
337             pluginFocusOrWindowFocusChanged(false);
338 #endif
339     }
340
341 #if ENABLE(NETSCAPE_PLUGIN_API)
342     // Invalidate the object map.
343     m_npRuntimeObjectMap.invalidate();
344 #endif
345
346     cancelAllStreams();
347 }
348
349 void PluginView::recreateAndInitialize(PassRefPtr<Plugin> plugin)
350 {
351     if (m_plugin) {
352         if (m_pluginSnapshotTimer.isActive())
353             m_pluginSnapshotTimer.stop();
354         destroyPluginAndReset();
355     }
356
357     // Reset member variables to initial values.
358     m_plugin = plugin;
359     m_isInitialized = false;
360     m_isWaitingForSynchronousInitialization = false;
361     m_isWaitingUntilMediaCanStart = false;
362     m_isBeingDestroyed = false;
363     m_manualStreamState = StreamStateInitial;
364     m_transientPaintingSnapshot = nullptr;
365
366     initializePlugin();
367 }
368
369 void PluginView::setLayerHostingMode(LayerHostingMode layerHostingMode)
370 {
371 #if HAVE(OUT_OF_PROCESS_LAYER_HOSTING)
372     if (!m_plugin)
373         return;
374
375     if (m_isInitialized)
376         m_plugin->setLayerHostingMode(layerHostingMode);
377     else
378         m_parameters.layerHostingMode = layerHostingMode;
379 #else
380     UNUSED_PARAM(layerHostingMode);
381 #endif
382 }
383
384 Frame* PluginView::frame() const
385 {
386     return m_pluginElement->document().frame();
387 }
388
389 void PluginView::manualLoadDidReceiveResponse(const ResourceResponse& response)
390 {
391     // The plug-in can be null here if it failed to initialize.
392     if (!m_plugin)
393         return;
394
395     if (!m_isInitialized) {
396         ASSERT(m_manualStreamState == StreamStateInitial);
397         m_manualStreamState = StreamStateHasReceivedResponse;
398         m_manualStreamResponse = response;
399         return;
400     }
401
402     // Compute the stream related data from the resource response.
403     const URL& responseURL = response.url();
404     const String& mimeType = response.mimeType();
405     long long expectedContentLength = response.expectedContentLength();
406     
407     String headers = buildHTTPHeaders(response, expectedContentLength);
408     
409     uint32_t streamLength = 0;
410     if (expectedContentLength > 0)
411         streamLength = expectedContentLength;
412
413     m_plugin->manualStreamDidReceiveResponse(responseURL, streamLength, lastModifiedDate(response), mimeType, headers, response.suggestedFilename());
414 }
415
416 void PluginView::manualLoadDidReceiveData(const char* bytes, int length)
417 {
418     // The plug-in can be null here if it failed to initialize.
419     if (!m_plugin)
420         return;
421
422     if (!m_isInitialized) {
423         ASSERT(m_manualStreamState == StreamStateHasReceivedResponse);
424         if (!m_manualStreamData)
425             m_manualStreamData = SharedBuffer::create();
426
427         m_manualStreamData->append(bytes, length);
428         return;
429     }
430
431     m_plugin->manualStreamDidReceiveData(bytes, length);
432 }
433
434 void PluginView::manualLoadDidFinishLoading()
435 {
436     // The plug-in can be null here if it failed to initialize.
437     if (!m_plugin)
438         return;
439
440     if (!m_isInitialized) {
441         ASSERT(m_manualStreamState == StreamStateHasReceivedResponse);
442         m_manualStreamState = StreamStateFinished;
443         return;
444     }
445
446     m_plugin->manualStreamDidFinishLoading();
447 }
448
449 void PluginView::manualLoadDidFail(const ResourceError& error)
450 {
451     // The plug-in can be null here if it failed to initialize.
452     if (!m_plugin)
453         return;
454
455     if (!m_isInitialized) {
456         m_manualStreamState = StreamStateFinished;
457         m_manualStreamError = error;
458         m_manualStreamData = nullptr;
459         return;
460     }
461
462     m_plugin->manualStreamDidFail(error.isCancellation());
463 }
464
465 RenderBoxModelObject* PluginView::renderer() const
466 {
467     return toRenderBoxModelObject(m_pluginElement->renderer());
468 }
469
470 void PluginView::pageScaleFactorDidChange()
471 {
472     viewGeometryDidChange();
473 }
474
475 void PluginView::topContentInsetDidChange()
476 {
477     viewGeometryDidChange();
478 }
479
480 void PluginView::setPageScaleFactor(double scaleFactor, IntPoint)
481 {
482     m_pageScaleFactor = scaleFactor;
483     m_webPage->send(Messages::WebPageProxy::PageScaleFactorDidChange(scaleFactor));
484     m_webPage->send(Messages::WebPageProxy::PageZoomFactorDidChange(scaleFactor));
485     pageScaleFactorDidChange();
486 }
487
488 double PluginView::pageScaleFactor() const
489 {
490     return m_pageScaleFactor;
491 }
492
493 bool PluginView::handlesPageScaleFactor() const
494 {
495     if (!m_plugin || !m_isInitialized)
496         return false;
497
498     return m_plugin->handlesPageScaleFactor();
499 }
500
501 void PluginView::webPageDestroyed()
502 {
503     m_webPage = 0;
504 }
505
506 void PluginView::viewStateDidChange(ViewState::Flags changed)
507 {
508     if (!m_plugin || !m_isInitialized)
509         return;
510
511     if (changed & ViewState::IsVisibleOrOccluded)
512         m_plugin->windowVisibilityChanged(m_webPage->isVisibleOrOccluded());
513     if (changed & ViewState::WindowIsActive)
514         m_plugin->windowFocusChanged(m_webPage->windowIsFocused());
515 }
516
517 #if PLATFORM(COCOA)
518 void PluginView::setDeviceScaleFactor(float scaleFactor)
519 {
520     if (!m_isInitialized || !m_plugin)
521         return;
522
523     m_plugin->contentsScaleFactorChanged(scaleFactor);
524 }
525
526 void PluginView::windowAndViewFramesChanged(const FloatRect& windowFrameInScreenCoordinates, const FloatRect& viewFrameInWindowCoordinates)
527 {
528     if (!m_isInitialized || !m_plugin)
529         return;
530
531     m_plugin->windowAndViewFramesChanged(enclosingIntRect(windowFrameInScreenCoordinates), enclosingIntRect(viewFrameInWindowCoordinates));
532 }
533
534 bool PluginView::sendComplexTextInput(uint64_t pluginComplexTextInputIdentifier, const String& textInput)
535 {
536     if (!m_plugin)
537         return false;
538
539     if (m_plugin->pluginComplexTextInputIdentifier() != pluginComplexTextInputIdentifier)
540         return false;
541
542     m_plugin->sendComplexTextInput(textInput);
543     return true;
544 }
545     
546 WebCore::AudioHardwareActivityType PluginView::audioHardwareActivity() const
547 {
548     return m_plugin->audioHardwareActivity();
549 }
550     
551 NSObject *PluginView::accessibilityObject() const
552 {
553     if (!m_isInitialized || !m_plugin)
554         return 0;
555     
556     return m_plugin->accessibilityObject();
557 }
558 #endif
559
560 void PluginView::initializePlugin()
561 {
562     if (m_isInitialized)
563         return;
564
565     if (!m_plugin) {
566         // We've already tried and failed to initialize the plug-in.
567         return;
568     }
569
570     if (Frame* frame = m_pluginElement->document().frame()) {
571         if (Page* page = frame->page()) {
572             
573             // We shouldn't initialize the plug-in right now, add a listener.
574             if (!page->canStartMedia()) {
575                 if (m_isWaitingUntilMediaCanStart)
576                     return;
577                 
578                 m_isWaitingUntilMediaCanStart = true;
579                 m_pluginElement->document().addMediaCanStartListener(this);
580                 return;
581             }
582         }
583     }
584
585 #if ENABLE(PRIMARY_SNAPSHOTTED_PLUGIN_HEURISTIC)
586     HTMLPlugInImageElement* plugInImageElement = toHTMLPlugInImageElement(m_pluginElement.get());
587     m_didPlugInStartOffScreen = !m_webPage->plugInIntersectsSearchRect(*plugInImageElement);
588 #endif
589     m_plugin->initialize(this, m_parameters);
590     
591     // Plug-in initialization continued in didFailToInitializePlugin() or didInitializePlugin().
592 }
593
594 void PluginView::didFailToInitializePlugin()
595 {
596     m_plugin = 0;
597
598 #if ENABLE(NETSCAPE_PLUGIN_API)
599     String frameURLString = frame()->loader().documentLoader()->responseURL().string();
600     String pageURLString = m_webPage->corePage()->mainFrame().loader().documentLoader()->responseURL().string();
601     m_webPage->send(Messages::WebPageProxy::DidFailToInitializePlugin(m_parameters.mimeType, frameURLString, pageURLString));
602 #endif // ENABLE(NETSCAPE_PLUGIN_API)
603 }
604
605 void PluginView::didInitializePlugin()
606 {
607     m_isInitialized = true;
608
609 #if PLATFORM(COCOA)
610     windowAndViewFramesChanged(m_webPage->windowFrameInScreenCoordinates(), m_webPage->viewFrameInWindowCoordinates());
611 #endif
612
613     viewVisibilityDidChange();
614     viewGeometryDidChange();
615
616     if (m_pluginElement->document().focusedElement() == m_pluginElement)
617         m_plugin->setFocus(true);
618
619     redeliverManualStream();
620
621 #if PLATFORM(COCOA)
622     if (m_pluginElement->displayState() < HTMLPlugInElement::Restarting) {
623         if (m_plugin->pluginLayer() && frame()) {
624             frame()->view()->enterCompositingMode();
625             m_pluginElement->setNeedsStyleRecalc(SyntheticStyleChange);
626         }
627         if (frame() && !frame()->settings().maximumPlugInSnapshotAttempts()) {
628             beginSnapshottingRunningPlugin();
629             return;
630         }
631         m_pluginSnapshotTimer.restart();
632     } else {
633         if (m_plugin->pluginLayer() && frame()) {
634             frame()->view()->enterCompositingMode();
635             m_pluginElement->setNeedsStyleRecalc(SyntheticStyleChange);
636         }
637         if (m_pluginElement->displayState() == HTMLPlugInElement::RestartingWithPendingMouseClick)
638             m_pluginElement->dispatchPendingMouseClick();
639     }
640
641     m_plugin->visibilityDidChange(isVisible());
642     m_plugin->windowVisibilityChanged(m_webPage->isVisibleOrOccluded());
643     m_plugin->windowFocusChanged(m_webPage->windowIsFocused());
644 #endif
645
646     if (wantsWheelEvents()) {
647         if (Frame* frame = m_pluginElement->document().frame()) {
648             if (FrameView* frameView = frame->view())
649                 frameView->setNeedsLayout();
650         }
651     }
652 }
653
654 #if PLATFORM(COCOA)
655 PlatformLayer* PluginView::platformLayer() const
656 {
657     // The plug-in can be null here if it failed to initialize.
658     if (!m_isInitialized || !m_plugin || m_pluginProcessHasCrashed)
659         return 0;
660         
661     return m_plugin->pluginLayer();
662 }
663 #endif
664
665 JSObject* PluginView::scriptObject(JSGlobalObject* globalObject)
666 {
667     // If we're already waiting for synchronous initialization of the plugin,
668     // calls to scriptObject() are from the plug-in itself and need to return 0;
669     if (m_isWaitingForSynchronousInitialization)
670         return 0;
671
672     // We might not have started initialization of the plug-in yet, the plug-in might be in the middle
673     // of being initializing asynchronously, or initialization might have previously failed.
674     if (!m_isInitialized || !m_plugin)
675         return 0;
676
677 #if ENABLE(NETSCAPE_PLUGIN_API)
678     NPObject* scriptableNPObject = m_plugin->pluginScriptableNPObject();
679     if (!scriptableNPObject)
680         return 0;
681
682     JSObject* jsObject = m_npRuntimeObjectMap.getOrCreateJSObject(globalObject, scriptableNPObject);
683     releaseNPObject(scriptableNPObject);
684
685     return jsObject;
686 #else
687     UNUSED_PARAM(globalObject);
688     return 0;
689 #endif
690 }
691
692 void PluginView::storageBlockingStateChanged()
693 {
694     // The plug-in can be null here if it failed to initialize.
695     if (!m_isInitialized || !m_plugin)
696         return;
697
698     bool storageBlockingPolicy = !frame()->document()->securityOrigin()->canAccessPluginStorage(frame()->document()->topOrigin());
699
700     m_plugin->storageBlockingStateChanged(storageBlockingPolicy);
701 }
702
703 void PluginView::privateBrowsingStateChanged(bool privateBrowsingEnabled)
704 {
705     // The plug-in can be null here if it failed to initialize.
706     if (!m_isInitialized || !m_plugin)
707         return;
708
709     m_plugin->privateBrowsingStateChanged(privateBrowsingEnabled);
710 }
711
712 bool PluginView::getFormValue(String& formValue)
713 {
714     // The plug-in can be null here if it failed to initialize.
715     if (!m_isInitialized || !m_plugin)
716         return false;
717
718     return m_plugin->getFormValue(formValue);
719 }
720
721 bool PluginView::scroll(ScrollDirection direction, ScrollGranularity granularity)
722 {
723     // The plug-in can be null here if it failed to initialize.
724     if (!m_isInitialized || !m_plugin)
725         return false;
726
727     return m_plugin->handleScroll(direction, granularity);
728 }
729
730 Scrollbar* PluginView::horizontalScrollbar()
731 {
732     // The plug-in can be null here if it failed to initialize.
733     if (!m_isInitialized || !m_plugin)
734         return 0;
735
736     return m_plugin->horizontalScrollbar();
737 }
738
739 Scrollbar* PluginView::verticalScrollbar()
740 {
741     // The plug-in can be null here if it failed to initialize.
742     if (!m_isInitialized || !m_plugin)
743         return 0;
744
745     return m_plugin->verticalScrollbar();
746 }
747
748 bool PluginView::wantsWheelEvents()
749 {
750     // The plug-in can be null here if it failed to initialize.
751     if (!m_isInitialized || !m_plugin)
752         return 0;
753     
754     return m_plugin->wantsWheelEvents();
755 }
756
757 void PluginView::setFrameRect(const WebCore::IntRect& rect)
758 {
759     Widget::setFrameRect(rect);
760     viewGeometryDidChange();
761 }
762
763 void PluginView::paint(GraphicsContext* context, const IntRect& /*dirtyRect*/)
764 {
765     if (!m_plugin || !m_isInitialized || m_pluginElement->displayState() < HTMLPlugInElement::Restarting)
766         return;
767
768     if (context->paintingDisabled()) {
769         if (context->updatingControlTints())
770             m_plugin->updateControlTints(context);
771         return;
772     }
773
774     // FIXME: We should try to intersect the dirty rect with the plug-in's clip rect here.
775     IntRect paintRect = IntRect(IntPoint(), frameRect().size());
776
777     if (paintRect.isEmpty())
778         return;
779
780     if (m_transientPaintingSnapshot) {
781         m_transientPaintingSnapshot->paint(*context, contentsScaleFactor(), frameRect().location(), m_transientPaintingSnapshot->bounds());
782         return;
783     }
784     
785     GraphicsContextStateSaver stateSaver(*context);
786
787     // Translate the coordinate system so that the origin is in the top-left corner of the plug-in.
788     context->translate(frameRect().location().x(), frameRect().location().y());
789
790     m_plugin->paint(context, paintRect);
791 }
792
793 void PluginView::frameRectsChanged()
794 {
795     Widget::frameRectsChanged();
796     viewGeometryDidChange();
797 }
798
799 void PluginView::clipRectChanged()
800 {
801     viewGeometryDidChange();
802 }
803
804 void PluginView::setParent(ScrollView* scrollView)
805 {
806     Widget::setParent(scrollView);
807     
808     if (scrollView)
809         initializePlugin();
810 }
811
812 unsigned PluginView::countFindMatches(const String& target, WebCore::FindOptions options, unsigned maxMatchCount)
813 {
814     if (!m_isInitialized || !m_plugin)
815         return 0;
816
817     return m_plugin->countFindMatches(target, options, maxMatchCount);
818 }
819
820 bool PluginView::findString(const String& target, WebCore::FindOptions options, unsigned maxMatchCount)
821 {
822     if (!m_isInitialized || !m_plugin)
823         return false;
824
825     return m_plugin->findString(target, options, maxMatchCount);
826 }
827
828 String PluginView::getSelectionString() const
829 {
830     if (!m_isInitialized || !m_plugin)
831         return String();
832
833     return m_plugin->getSelectionString();
834 }
835
836 std::unique_ptr<WebEvent> PluginView::createWebEvent(MouseEvent* event) const
837 {
838     WebEvent::Type type = WebEvent::NoType;
839     unsigned clickCount = 1;
840     if (event->type() == eventNames().mousedownEvent)
841         type = WebEvent::MouseDown;
842     else if (event->type() == eventNames().mouseupEvent)
843         type = WebEvent::MouseUp;
844     else if (event->type() == eventNames().mouseoverEvent) {
845         type = WebEvent::MouseMove;
846         clickCount = 0;
847     } else if (event->type() == eventNames().clickEvent)
848         return nullptr;
849     else
850         ASSERT_NOT_REACHED();
851
852     WebMouseEvent::Button button = WebMouseEvent::NoButton;
853     switch (event->button()) {
854     case WebCore::LeftButton:
855         button = WebMouseEvent::LeftButton;
856         break;
857     case WebCore::MiddleButton:
858         button = WebMouseEvent::MiddleButton;
859         break;
860     case WebCore::RightButton:
861         button = WebMouseEvent::RightButton;
862         break;
863     default:
864         ASSERT_NOT_REACHED();
865         break;
866     }
867
868     unsigned modifiers = 0;
869     if (event->shiftKey())
870         modifiers |= WebEvent::ShiftKey;
871     if (event->ctrlKey())
872         modifiers |= WebEvent::ControlKey;
873     if (event->altKey())
874         modifiers |= WebEvent::AltKey;
875     if (event->metaKey())
876         modifiers |= WebEvent::MetaKey;
877
878     return std::make_unique<WebMouseEvent>(type, button, m_plugin->convertToRootView(IntPoint(event->offsetX(), event->offsetY())), event->screenLocation(), 0, 0, 0, clickCount, static_cast<WebEvent::Modifiers>(modifiers), 0);
879 }
880
881 void PluginView::handleEvent(Event* event)
882 {
883     if (!m_isInitialized || !m_plugin)
884         return;
885
886     const WebEvent* currentEvent = WebPage::currentEvent();
887     std::unique_ptr<WebEvent> simulatedWebEvent;
888     if (event->isMouseEvent() && toMouseEvent(event)->isSimulated()) {
889         simulatedWebEvent = createWebEvent(toMouseEvent(event));
890         currentEvent = simulatedWebEvent.get();
891     }
892     if (!currentEvent)
893         return;
894
895     bool didHandleEvent = false;
896
897     if ((event->type() == eventNames().mousemoveEvent && currentEvent->type() == WebEvent::MouseMove)
898         || (event->type() == eventNames().mousedownEvent && currentEvent->type() == WebEvent::MouseDown)
899         || (event->type() == eventNames().mouseupEvent && currentEvent->type() == WebEvent::MouseUp)) {
900         // FIXME: Clicking in a scroll bar should not change focus.
901         if (currentEvent->type() == WebEvent::MouseDown) {
902             focusPluginElement();
903             frame()->eventHandler().setCapturingMouseEventsElement(m_pluginElement.get());
904         } else if (currentEvent->type() == WebEvent::MouseUp)
905             frame()->eventHandler().setCapturingMouseEventsElement(nullptr);
906
907         didHandleEvent = m_plugin->handleMouseEvent(static_cast<const WebMouseEvent&>(*currentEvent));
908         if (event->type() != eventNames().mousemoveEvent)
909             pluginDidReceiveUserInteraction();
910     } else if ((event->type() == eventNames().wheelEvent || event->type() == eventNames().mousewheelEvent)
911         && currentEvent->type() == WebEvent::Wheel && m_plugin->wantsWheelEvents()) {
912         didHandleEvent = m_plugin->handleWheelEvent(static_cast<const WebWheelEvent&>(*currentEvent));
913         pluginDidReceiveUserInteraction();
914     } else if (event->type() == eventNames().mouseoverEvent && currentEvent->type() == WebEvent::MouseMove)
915         didHandleEvent = m_plugin->handleMouseEnterEvent(static_cast<const WebMouseEvent&>(*currentEvent));
916     else if (event->type() == eventNames().mouseoutEvent && currentEvent->type() == WebEvent::MouseMove)
917         didHandleEvent = m_plugin->handleMouseLeaveEvent(static_cast<const WebMouseEvent&>(*currentEvent));
918     else if (event->type() == eventNames().contextmenuEvent && currentEvent->type() == WebEvent::MouseDown) {
919         didHandleEvent = m_plugin->handleContextMenuEvent(static_cast<const WebMouseEvent&>(*currentEvent));
920         pluginDidReceiveUserInteraction();
921     } else if ((event->type() == eventNames().keydownEvent && currentEvent->type() == WebEvent::KeyDown)
922                || (event->type() == eventNames().keyupEvent && currentEvent->type() == WebEvent::KeyUp)) {
923         didHandleEvent = m_plugin->handleKeyboardEvent(static_cast<const WebKeyboardEvent&>(*currentEvent));
924         pluginDidReceiveUserInteraction();
925     }
926
927     if (didHandleEvent)
928         event->setDefaultHandled();
929 }
930     
931 bool PluginView::handleEditingCommand(const String& commandName, const String& argument)
932 {
933     if (!m_isInitialized || !m_plugin)
934         return false;
935
936     return m_plugin->handleEditingCommand(commandName, argument);
937 }
938     
939 bool PluginView::isEditingCommandEnabled(const String& commandName)
940 {
941     if (!m_isInitialized || !m_plugin)
942         return false;
943
944     return m_plugin->isEditingCommandEnabled(commandName);
945 }
946
947 bool PluginView::shouldAllowScripting()
948 {
949     if (!m_isInitialized || !m_plugin)
950         return false;
951
952     return m_plugin->shouldAllowScripting();
953 }
954
955 bool PluginView::shouldAllowNavigationFromDrags() const
956 {
957     if (!m_isInitialized || !m_plugin)
958         return false;
959
960     return m_plugin->shouldAllowNavigationFromDrags();
961 }
962
963 bool PluginView::shouldNotAddLayer() const
964 {
965     return m_pluginElement->displayState() < HTMLPlugInElement::Restarting && !m_plugin->supportsSnapshotting();
966 }
967
968 PassRefPtr<SharedBuffer> PluginView::liveResourceData() const
969 {
970     if (!m_isInitialized || !m_plugin)
971         return 0;
972
973     return m_plugin->liveResourceData();
974 }
975
976 bool PluginView::performDictionaryLookupAtLocation(const WebCore::FloatPoint& point)
977 {
978     if (!m_isInitialized || !m_plugin)
979         return false;
980
981     return m_plugin->performDictionaryLookupAtLocation(point);
982 }
983
984 void PluginView::notifyWidget(WidgetNotification notification)
985 {
986     switch (notification) {
987     case WillPaintFlattened:
988         if (shouldCreateTransientPaintingSnapshot())
989             m_transientPaintingSnapshot = m_plugin->snapshot();
990         break;
991     case DidPaintFlattened:
992         m_transientPaintingSnapshot = nullptr;
993         break;
994     }
995 }
996
997 void PluginView::show()
998 {
999     bool wasVisible = isVisible();
1000
1001     setSelfVisible(true);
1002
1003     if (!wasVisible)
1004         viewVisibilityDidChange();
1005
1006     Widget::show();
1007 }
1008
1009 void PluginView::hide()
1010 {
1011     bool wasVisible = isVisible();
1012
1013     setSelfVisible(false);
1014
1015     if (wasVisible)
1016         viewVisibilityDidChange();
1017
1018     Widget::hide();
1019 }
1020
1021 void PluginView::setParentVisible(bool isVisible)
1022 {
1023     if (isParentVisible() == isVisible)
1024         return;
1025
1026     Widget::setParentVisible(isVisible);
1027     viewVisibilityDidChange();
1028 }
1029
1030 bool PluginView::transformsAffectFrameRect()
1031 {
1032     return false;
1033 }
1034
1035 void PluginView::viewGeometryDidChange()
1036 {
1037     if (!m_isInitialized || !m_plugin || !parent())
1038         return;
1039
1040     ASSERT(frame());
1041     float pageScaleFactor = frame()->page() ? frame()->page()->pageScaleFactor() : 1;
1042
1043     IntPoint scaledFrameRectLocation(frameRect().location().x() * pageScaleFactor, frameRect().location().y() * pageScaleFactor);
1044     IntPoint scaledLocationInRootViewCoordinates(parent()->contentsToRootView(scaledFrameRectLocation));
1045
1046     // FIXME: We still don't get the right coordinates for transformed plugins.
1047     AffineTransform transform;
1048     transform.translate(scaledLocationInRootViewCoordinates.x(), scaledLocationInRootViewCoordinates.y());
1049     transform.scale(pageScaleFactor);
1050
1051     // FIXME: The way we calculate this clip rect isn't correct.
1052     // But it is still important to distinguish between empty and non-empty rects so we can notify the plug-in when it becomes invisible.
1053     // Making the rect actually correct is covered by https://bugs.webkit.org/show_bug.cgi?id=95362
1054     IntRect clipRect = boundsRect();
1055     
1056     // FIXME: We can only get a semi-reliable answer from clipRectInWindowCoordinates() when the page is not scaled.
1057     // Fixing that is tracked in <rdar://problem/9026611> - Make the Widget hierarchy play nicely with transforms, for zoomed plug-ins and iframes
1058     if (pageScaleFactor == 1) {
1059         clipRect = clipRectInWindowCoordinates();
1060         if (!clipRect.isEmpty())
1061             clipRect = boundsRect();
1062     }
1063     
1064     m_plugin->geometryDidChange(size(), clipRect, transform);
1065 }
1066
1067 void PluginView::viewVisibilityDidChange()
1068 {
1069     if (!m_isInitialized || !m_plugin || !parent())
1070         return;
1071
1072     m_plugin->visibilityDidChange(isVisible());
1073 }
1074
1075 IntRect PluginView::clipRectInWindowCoordinates() const
1076 {
1077     // Get the frame rect in window coordinates.
1078     IntRect frameRectInWindowCoordinates = parent()->contentsToWindow(frameRect());
1079
1080     Frame* frame = this->frame();
1081
1082     // Get the window clip rect for the plugin element (in window coordinates).
1083     IntRect windowClipRect = frame->view()->windowClipRectForFrameOwner(m_pluginElement.get(), true);
1084
1085     // Intersect the two rects to get the view clip rect in window coordinates.
1086     frameRectInWindowCoordinates.intersect(windowClipRect);
1087
1088     return frameRectInWindowCoordinates;
1089 }
1090
1091 void PluginView::focusPluginElement()
1092 {
1093     ASSERT(frame());
1094     
1095     if (Page* page = frame()->page())
1096         page->focusController().setFocusedElement(m_pluginElement.get(), frame());
1097     else
1098         frame()->document()->setFocusedElement(m_pluginElement);
1099 }
1100
1101 void PluginView::pendingURLRequestsTimerFired()
1102 {
1103     ASSERT(!m_pendingURLRequests.isEmpty());
1104     
1105     RefPtr<URLRequest> urlRequest = m_pendingURLRequests.takeFirst();
1106
1107     // If there are more requests to perform, reschedule the timer.
1108     if (!m_pendingURLRequests.isEmpty())
1109         m_pendingURLRequestsTimer.startOneShot(0);
1110     
1111     performURLRequest(urlRequest.get());
1112 }
1113     
1114 void PluginView::performURLRequest(URLRequest* request)
1115 {
1116     // This protector is needed to make sure the PluginView is not destroyed while it is still needed.
1117     Ref<PluginView> protect(*this);
1118
1119     // First, check if this is a javascript: url.
1120     if (protocolIsJavaScript(request->request().url())) {
1121         performJavaScriptURLRequest(request);
1122         return;
1123     }
1124
1125     if (!request->target().isNull()) {
1126         performFrameLoadURLRequest(request);
1127         return;
1128     }
1129
1130     // This request is to load a URL and create a stream.
1131     RefPtr<Stream> stream = PluginView::Stream::create(this, request->requestID(), request->request());
1132     addStream(stream.get());
1133     stream->start();
1134 }
1135
1136 void PluginView::performFrameLoadURLRequest(URLRequest* request)
1137 {
1138     ASSERT(!request->target().isNull());
1139
1140     Frame* frame = m_pluginElement->document().frame();
1141     if (!frame)
1142         return;
1143
1144     if (!m_pluginElement->document().securityOrigin()->canDisplay(request->request().url())) {
1145         // We can't load the request, send back a reply to the plug-in.
1146         m_plugin->frameDidFail(request->requestID(), false);
1147         return;
1148     }
1149
1150     UserGestureIndicator gestureIndicator(request->allowPopups() ? DefinitelyProcessingUserGesture : PossiblyProcessingUserGesture);
1151
1152     // First, try to find a target frame.
1153     Frame* targetFrame = frame->loader().findFrameForNavigation(request->target());
1154     if (!targetFrame) {
1155         // We did not find a target frame. Ask our frame to load the page. This may or may not create a popup window.
1156         FrameLoadRequest frameRequest(frame, request->request());
1157         frameRequest.setFrameName(request->target());
1158         frameRequest.setShouldCheckNewWindowPolicy(true);
1159         frame->loader().load(frameRequest);
1160
1161         // FIXME: We don't know whether the window was successfully created here so we just assume that it worked.
1162         // It's better than not telling the plug-in anything.
1163         m_plugin->frameDidFinishLoading(request->requestID());
1164         return;
1165     }
1166
1167     // Now ask the frame to load the request.
1168     targetFrame->loader().load(FrameLoadRequest(targetFrame, request->request()));
1169
1170     auto* targetWebFrame = WebFrame::fromCoreFrame(*targetFrame);
1171     ASSERT(targetWebFrame);
1172
1173     if (WebFrame::LoadListener* loadListener = targetWebFrame->loadListener()) {
1174         // Check if another plug-in view or even this view is waiting for the frame to load.
1175         // If it is, tell it that the load was cancelled because it will be anyway.
1176         loadListener->didFailLoad(targetWebFrame, true);
1177     }
1178     
1179     m_pendingFrameLoads.set(targetWebFrame, request);
1180     targetWebFrame->setLoadListener(this);
1181 }
1182
1183 void PluginView::performJavaScriptURLRequest(URLRequest* request)
1184 {
1185     ASSERT(protocolIsJavaScript(request->request().url()));
1186
1187     RefPtr<Frame> frame = m_pluginElement->document().frame();
1188     if (!frame)
1189         return;
1190     
1191     String jsString = decodeURLEscapeSequences(request->request().url().string().substring(sizeof("javascript:") - 1));
1192
1193     if (!request->target().isNull()) {
1194         // For security reasons, only allow JS requests to be made on the frame that contains the plug-in.
1195         if (frame->tree().find(request->target()) != frame) {
1196             // Let the plug-in know that its frame load failed.
1197             m_plugin->frameDidFail(request->requestID(), false);
1198             return;
1199         }
1200     }
1201
1202     // Evaluate the JavaScript code. Note that running JavaScript here could cause the plug-in to be destroyed, so we
1203     // grab references to the plug-in here.
1204     RefPtr<Plugin> plugin = m_plugin;
1205     Deprecated::ScriptValue result = frame->script().executeScript(jsString, request->allowPopups());
1206
1207     // Check if evaluating the JavaScript destroyed the plug-in.
1208     if (!plugin->controller())
1209         return;
1210
1211     // Don't notify the plug-in at all about targeted javascript: requests. This matches Mozilla and WebKit1.
1212     if (!request->target().isNull())
1213         return;
1214
1215     ExecState* scriptState = frame->script().globalObject(pluginWorld())->globalExec();
1216     String resultString;
1217     result.getString(scriptState, resultString);
1218   
1219     // Send the result back to the plug-in.
1220     plugin->didEvaluateJavaScript(request->requestID(), resultString);
1221 }
1222
1223 void PluginView::addStream(Stream* stream)
1224 {
1225     ASSERT(!m_streams.contains(stream->streamID()));
1226     m_streams.set(stream->streamID(), stream);
1227 }
1228     
1229 void PluginView::removeStream(Stream* stream)
1230 {
1231     ASSERT(m_streams.get(stream->streamID()) == stream);
1232     
1233     m_streams.remove(stream->streamID());
1234 }
1235
1236 void PluginView::cancelAllStreams()
1237 {
1238     Vector<RefPtr<Stream>> streams;
1239     copyValuesToVector(m_streams, streams);
1240     
1241     for (size_t i = 0; i < streams.size(); ++i)
1242         streams[i]->cancel();
1243
1244     // Cancelling a stream removes it from the m_streams map, so if we cancel all streams the map should be empty.
1245     ASSERT(m_streams.isEmpty());
1246 }
1247
1248 void PluginView::redeliverManualStream()
1249 {
1250     if (m_manualStreamState == StreamStateInitial) {
1251         // Nothing to do.
1252         return;
1253     }
1254
1255     if (m_manualStreamState == StreamStateFailed) {
1256         manualLoadDidFail(m_manualStreamError);
1257         return;
1258     }
1259
1260     // Deliver the response.
1261     manualLoadDidReceiveResponse(m_manualStreamResponse);
1262
1263     // Deliver the data.
1264     if (m_manualStreamData) {
1265         const char* data;
1266         unsigned position = 0;
1267
1268         while (unsigned length = m_manualStreamData->getSomeData(data, position)) {
1269             manualLoadDidReceiveData(data, length);
1270             position += length;
1271         }
1272
1273         m_manualStreamData = nullptr;
1274     }
1275
1276     if (m_manualStreamState == StreamStateFinished)
1277         manualLoadDidFinishLoading();
1278 }
1279
1280 void PluginView::invalidateRect(const IntRect& dirtyRect)
1281 {
1282     if (!parent() || !m_plugin || !m_isInitialized)
1283         return;
1284
1285 #if PLATFORM(COCOA)
1286     if (m_plugin->pluginLayer())
1287         return;
1288 #endif
1289
1290     if (m_pluginElement->displayState() < HTMLPlugInElement::Restarting)
1291         return;
1292
1293     RenderBoxModelObject* renderer = toRenderBoxModelObject(m_pluginElement->renderer());
1294     if (!renderer)
1295         return;
1296
1297     IntRect contentRect(dirtyRect);
1298     contentRect.move(renderer->borderLeft() + renderer->paddingLeft(), renderer->borderTop() + renderer->paddingTop());
1299     renderer->repaintRectangle(contentRect);
1300 }
1301
1302 void PluginView::setFocus(bool hasFocus)
1303 {
1304     Widget::setFocus(hasFocus);
1305
1306     if (!m_isInitialized || !m_plugin)
1307         return;
1308
1309     m_plugin->setFocus(hasFocus);
1310 }
1311
1312 void PluginView::mediaCanStart()
1313 {
1314     ASSERT(m_isWaitingUntilMediaCanStart);
1315     m_isWaitingUntilMediaCanStart = false;
1316     
1317     initializePlugin();
1318 }
1319
1320 bool PluginView::isPluginVisible()
1321 {
1322     return isVisible();
1323 }
1324
1325 void PluginView::invalidate(const IntRect& dirtyRect)
1326 {
1327     invalidateRect(dirtyRect);
1328 }
1329
1330 String PluginView::userAgent()
1331 {
1332     Frame* frame = m_pluginElement->document().frame();
1333     if (!frame)
1334         return String();
1335     
1336     return frame->loader().client().userAgent(URL());
1337 }
1338
1339 void PluginView::loadURL(uint64_t requestID, const String& method, const String& urlString, const String& target, const HTTPHeaderMap& headerFields, const Vector<uint8_t>& httpBody, bool allowPopups)
1340 {
1341     FrameLoadRequest frameLoadRequest(m_pluginElement->document().securityOrigin());
1342     frameLoadRequest.resourceRequest().setHTTPMethod(method);
1343     frameLoadRequest.resourceRequest().setURL(m_pluginElement->document().completeURL(urlString));
1344     frameLoadRequest.resourceRequest().setHTTPHeaderFields(headerFields);
1345     if (!httpBody.isEmpty()) {
1346         frameLoadRequest.resourceRequest().setHTTPBody(FormData::create(httpBody.data(), httpBody.size()));
1347         if (frameLoadRequest.resourceRequest().httpContentType().isEmpty())
1348             frameLoadRequest.resourceRequest().setHTTPContentType("application/x-www-form-urlencoded");
1349     }
1350
1351     frameLoadRequest.setFrameName(target);
1352
1353     String referrer = SecurityPolicy::generateReferrerHeader(frame()->document()->referrerPolicy(), frameLoadRequest.resourceRequest().url(), frame()->loader().outgoingReferrer());
1354     if (!referrer.isEmpty())
1355         frameLoadRequest.resourceRequest().setHTTPReferrer(referrer);
1356
1357     m_pendingURLRequests.append(URLRequest::create(requestID, frameLoadRequest, allowPopups));
1358     m_pendingURLRequestsTimer.startOneShot(0);
1359 }
1360
1361 void PluginView::cancelStreamLoad(uint64_t streamID)
1362 {
1363     // Keep a reference to the stream. Stream::cancel might remove the stream from the map, and thus
1364     // releasing its last reference.
1365     RefPtr<Stream> stream = m_streams.get(streamID);
1366     if (!stream)
1367         return;
1368
1369     // Cancelling the stream here will remove it from the map.
1370     stream->cancel();
1371     ASSERT(!m_streams.contains(streamID));
1372 }
1373
1374 void PluginView::cancelManualStreamLoad()
1375 {
1376     if (!frame())
1377         return;
1378
1379     DocumentLoader* documentLoader = frame()->loader().activeDocumentLoader();
1380     ASSERT(documentLoader);
1381     
1382     if (documentLoader->isLoadingMainResource())
1383         documentLoader->cancelMainResourceLoad(frame()->loader().cancelledError(m_parameters.url));
1384 }
1385
1386 #if ENABLE(NETSCAPE_PLUGIN_API)
1387 NPObject* PluginView::windowScriptNPObject()
1388 {
1389     if (!frame())
1390         return 0;
1391
1392     if (!frame()->script().canExecuteScripts(NotAboutToExecuteScript)) {
1393         // FIXME: Investigate if other browsers allow plug-ins to access JavaScript objects even if JavaScript is disabled.
1394         return 0;
1395     }
1396
1397     return m_npRuntimeObjectMap.getOrCreateNPObject(pluginWorld().vm(), frame()->script().windowShell(pluginWorld())->window());
1398 }
1399
1400 NPObject* PluginView::pluginElementNPObject()
1401 {
1402     if (!frame())
1403         return 0;
1404
1405     if (!frame()->script().canExecuteScripts(NotAboutToExecuteScript)) {
1406         // FIXME: Investigate if other browsers allow plug-ins to access JavaScript objects even if JavaScript is disabled.
1407         return 0;
1408     }
1409
1410     JSObject* object = frame()->script().jsObjectForPluginElement(m_pluginElement.get());
1411     ASSERT(object);
1412
1413     return m_npRuntimeObjectMap.getOrCreateNPObject(pluginWorld().vm(), object);
1414 }
1415
1416 bool PluginView::evaluate(NPObject* npObject, const String& scriptString, NPVariant* result, bool allowPopups)
1417 {
1418     // FIXME: Is this check necessary?
1419     if (!m_pluginElement->document().frame())
1420         return false;
1421
1422     // Calling evaluate will run JavaScript that can potentially remove the plug-in element, so we need to
1423     // protect the plug-in view from destruction.
1424     NPRuntimeObjectMap::PluginProtector pluginProtector(&m_npRuntimeObjectMap);
1425
1426     UserGestureIndicator gestureIndicator(allowPopups ? DefinitelyProcessingUserGesture : PossiblyProcessingUserGesture);
1427     return m_npRuntimeObjectMap.evaluate(npObject, scriptString, result);
1428 }
1429 #endif
1430
1431 void PluginView::setStatusbarText(const String& statusbarText)
1432 {
1433     if (!frame())
1434         return;
1435     
1436     Page* page = frame()->page();
1437     if (!page)
1438         return;
1439
1440     page->chrome().setStatusbarText(frame(), statusbarText);
1441 }
1442
1443 bool PluginView::isAcceleratedCompositingEnabled()
1444 {
1445     if (!frame())
1446         return false;
1447     
1448     // We know that some plug-ins can support snapshotting without needing
1449     // accelerated compositing. Since we're trying to snapshot them anyway,
1450     // put them into normal compositing mode. A side benefit is that this might
1451     // allow the entire page to stay in that mode.
1452     if (m_pluginElement->displayState() < HTMLPlugInElement::Restarting && m_parameters.mimeType == "application/x-shockwave-flash")
1453         return false;
1454
1455     return frame()->settings().acceleratedCompositingEnabled();
1456 }
1457
1458 void PluginView::pluginProcessCrashed()
1459 {
1460     m_pluginProcessHasCrashed = true;
1461
1462     if (!m_pluginElement->renderer())
1463         return;
1464
1465     if (!m_pluginElement->renderer()->isEmbeddedObject())
1466         return;
1467
1468     m_pluginElement->setNeedsStyleRecalc(SyntheticStyleChange);
1469
1470     RenderEmbeddedObject* renderer = toRenderEmbeddedObject(m_pluginElement->renderer());
1471     renderer->setPluginUnavailabilityReason(RenderEmbeddedObject::PluginCrashed);
1472     
1473     Widget::invalidate();
1474 }
1475
1476 void PluginView::willSendEventToPlugin()
1477 {
1478     // If we're sending an event to a plug-in, we can't control how long the plug-in
1479     // takes to process it (e.g. it may display a context menu), so we tell the UI process
1480     // to stop the responsiveness timer in this case.
1481     m_webPage->send(Messages::WebPageProxy::StopResponsivenessTimer());
1482 }
1483
1484 #if PLATFORM(COCOA)
1485 void PluginView::pluginFocusOrWindowFocusChanged(bool pluginHasFocusAndWindowHasFocus)
1486 {
1487     if (m_webPage)
1488         m_webPage->send(Messages::WebPageProxy::PluginFocusOrWindowFocusChanged(m_plugin->pluginComplexTextInputIdentifier(), pluginHasFocusAndWindowHasFocus));
1489 }
1490
1491 void PluginView::setComplexTextInputState(PluginComplexTextInputState pluginComplexTextInputState)
1492 {
1493     if (m_webPage)
1494         m_webPage->send(Messages::WebPageProxy::SetPluginComplexTextInputState(m_plugin->pluginComplexTextInputIdentifier(), pluginComplexTextInputState));
1495 }
1496
1497 mach_port_t PluginView::compositingRenderServerPort()
1498 {
1499     return WebProcess::shared().compositingRenderServerPort();
1500 }
1501
1502 void PluginView::openPluginPreferencePane()
1503 {
1504     ASSERT_NOT_REACHED();
1505 }
1506
1507 #endif
1508
1509 float PluginView::contentsScaleFactor()
1510 {
1511     if (Page* page = frame() ? frame()->page() : 0)
1512         return page->deviceScaleFactor();
1513         
1514     return 1;
1515 }
1516     
1517 String PluginView::proxiesForURL(const String& urlString)
1518 {
1519     const FrameLoader* frameLoader = frame() ? &frame()->loader() : 0;
1520     const NetworkingContext* context = frameLoader ? frameLoader->networkingContext() : 0;
1521     Vector<ProxyServer> proxyServers = proxyServersForURL(URL(URL(), urlString), context);
1522     return toString(proxyServers);
1523 }
1524
1525 String PluginView::cookiesForURL(const String& urlString)
1526 {
1527     return cookies(&m_pluginElement->document(), URL(URL(), urlString));
1528 }
1529
1530 void PluginView::setCookiesForURL(const String& urlString, const String& cookieString)
1531 {
1532     setCookies(&m_pluginElement->document(), URL(URL(), urlString), cookieString);
1533 }
1534
1535 bool PluginView::getAuthenticationInfo(const ProtectionSpace& protectionSpace, String& username, String& password)
1536 {
1537     Credential credential = CredentialStorage::get(protectionSpace);
1538     if (credential.isEmpty())
1539         credential = CredentialStorage::getFromPersistentStorage(protectionSpace);
1540
1541     if (!credential.hasPassword())
1542         return false;
1543
1544     username = credential.user();
1545     password = credential.password();
1546
1547     return true;
1548 }
1549
1550 bool PluginView::isPrivateBrowsingEnabled()
1551 {
1552     // If we can't get the real setting, we'll assume that private browsing is enabled.
1553     if (!frame())
1554         return true;
1555
1556     if (!frame()->document()->securityOrigin()->canAccessPluginStorage(frame()->document()->topOrigin()))
1557         return true;
1558
1559     return frame()->page()->usesEphemeralSession();
1560 }
1561
1562 bool PluginView::asynchronousPluginInitializationEnabled() const
1563 {
1564     return m_webPage->asynchronousPluginInitializationEnabled();
1565 }
1566
1567 bool PluginView::asynchronousPluginInitializationEnabledForAllPlugins() const
1568 {
1569     return m_webPage->asynchronousPluginInitializationEnabledForAllPlugins();
1570 }
1571
1572 bool PluginView::artificialPluginInitializationDelayEnabled() const
1573 {
1574     return m_webPage->artificialPluginInitializationDelayEnabled();
1575 }
1576
1577 void PluginView::protectPluginFromDestruction()
1578 {
1579     if (!m_isBeingDestroyed)
1580         ref();
1581 }
1582
1583 static void derefPluginView(PluginView* pluginView)
1584 {
1585     pluginView->deref();
1586 }
1587
1588 void PluginView::unprotectPluginFromDestruction()
1589 {
1590     if (m_isBeingDestroyed)
1591         return;
1592
1593     // A plug-in may ask us to evaluate JavaScript that removes the plug-in from the
1594     // page, but expect the object to still be alive when the call completes. Flash,
1595     // for example, may crash if the plug-in is destroyed and we return to code for
1596     // the destroyed object higher on the stack. To prevent this, if the plug-in has
1597     // only one remaining reference, call deref() asynchronously.
1598     if (hasOneRef())
1599         RunLoop::main().dispatch(bind(derefPluginView, this));
1600     else
1601         deref();
1602 }
1603
1604 void PluginView::didFinishLoad(WebFrame* webFrame)
1605 {
1606     RefPtr<URLRequest> request = m_pendingFrameLoads.take(webFrame);
1607     ASSERT(request);
1608     webFrame->setLoadListener(0);
1609
1610     m_plugin->frameDidFinishLoading(request->requestID());
1611 }
1612
1613 void PluginView::didFailLoad(WebFrame* webFrame, bool wasCancelled)
1614 {
1615     RefPtr<URLRequest> request = m_pendingFrameLoads.take(webFrame);
1616     ASSERT(request);
1617     webFrame->setLoadListener(0);
1618     
1619     m_plugin->frameDidFail(request->requestID(), wasCancelled);
1620 }
1621
1622 #if PLUGIN_ARCHITECTURE(X11)
1623 uint64_t PluginView::createPluginContainer()
1624 {
1625     uint64_t windowID = 0;
1626     m_webPage->sendSync(Messages::WebPageProxy::CreatePluginContainer(), Messages::WebPageProxy::CreatePluginContainer::Reply(windowID));
1627     return windowID;
1628 }
1629
1630 void PluginView::windowedPluginGeometryDidChange(const WebCore::IntRect& frameRect, const WebCore::IntRect& clipRect, uint64_t windowID)
1631 {
1632     m_webPage->send(Messages::WebPageProxy::WindowedPluginGeometryDidChange(frameRect, clipRect, windowID));
1633 }
1634
1635 void PluginView::windowedPluginVisibilityDidChange(bool isVisible, uint64_t windowID)
1636 {
1637     m_webPage->send(Messages::WebPageProxy::WindowedPluginVisibilityDidChange(isVisible, windowID));
1638 }
1639 #endif
1640
1641 #if PLATFORM(COCOA)
1642 static bool isAlmostSolidColor(BitmapImage* bitmap)
1643 {
1644     CGImageRef image = bitmap->getCGImageRef();
1645     ASSERT(CGImageGetBitsPerComponent(image) == 8);
1646
1647     CGBitmapInfo imageInfo = CGImageGetBitmapInfo(image);
1648     if (!(imageInfo & kCGBitmapByteOrder32Little) || (imageInfo & kCGBitmapAlphaInfoMask) != kCGImageAlphaPremultipliedFirst) {
1649         // FIXME: Consider being able to handle other pixel formats.
1650         ASSERT_NOT_REACHED();
1651         return false;
1652     }
1653
1654     size_t width = CGImageGetWidth(image);
1655     size_t height = CGImageGetHeight(image);
1656     size_t bytesPerRow = CGImageGetBytesPerRow(image);
1657
1658     RetainPtr<CFDataRef> provider = adoptCF(CGDataProviderCopyData(CGImageGetDataProvider(image)));
1659     const UInt8* data = CFDataGetBytePtr(provider.get());
1660
1661     // Overlay a grid of sampling dots on top of a grayscale version of the image.
1662     // For the interior points, calculate the difference in luminance among the sample point
1663     // and its surrounds points, scaled by transparency.
1664     const unsigned sampleRows = 7;
1665     const unsigned sampleCols = 7;
1666     // FIXME: Refine the proper number of samples, and accommodate different aspect ratios.
1667     if (width < sampleCols || height < sampleRows)
1668         return false;
1669
1670     // Ensure that the last row/column land on the image perimeter.
1671     const float strideWidth = static_cast<float>(width - 1) / (sampleCols - 1);
1672     const float strideHeight = static_cast<float>(height - 1) / (sampleRows - 1);
1673     float samples[sampleRows][sampleCols];
1674
1675     // Find the luminance of the sample points.
1676     float y = 0;
1677     const UInt8* row = data;
1678     for (unsigned i = 0; i < sampleRows; ++i) {
1679         float x = 0;
1680         for (unsigned j = 0; j < sampleCols; ++j) {
1681             const UInt8* p0 = row + (static_cast<int>(x + .5)) * 4;
1682             // R G B A
1683             samples[i][j] = (0.2125 * *p0 + 0.7154 * *(p0+1) + 0.0721 * *(p0+2)) * *(p0+3) / 255;
1684             x += strideWidth;
1685         }
1686         y += strideHeight;
1687         row = data + (static_cast<int>(y + .5)) * bytesPerRow;
1688     }
1689
1690     // Determine the image score.
1691     float accumScore = 0;
1692     for (unsigned i = 1; i < sampleRows - 1; ++i) {
1693         for (unsigned j = 1; j < sampleCols - 1; ++j) {
1694             float diff = samples[i - 1][j] + samples[i + 1][j] + samples[i][j - 1] + samples[i][j + 1] - 4 * samples[i][j];
1695             accumScore += diff * diff;
1696         }
1697     }
1698
1699     // The score for a given sample can be within the range of 0 and 255^2.
1700     return accumScore < 2500 * (sampleRows - 2) * (sampleCols - 2);
1701 }
1702 #endif
1703
1704 void PluginView::pluginSnapshotTimerFired()
1705 {
1706     ASSERT(m_plugin);
1707
1708 #if ENABLE(PRIMARY_SNAPSHOTTED_PLUGIN_HEURISTIC)
1709     HTMLPlugInImageElement* plugInImageElement = toHTMLPlugInImageElement(m_pluginElement.get());
1710     bool isPlugInOnScreen = m_webPage->plugInIntersectsSearchRect(*plugInImageElement);
1711     bool plugInCameOnScreen = isPlugInOnScreen && m_didPlugInStartOffScreen;
1712     bool snapshotFound = false;
1713 #endif
1714
1715     if (m_plugin->supportsSnapshotting()) {
1716         // Snapshot might be 0 if plugin size is 0x0.
1717         RefPtr<ShareableBitmap> snapshot = m_plugin->snapshot();
1718         RefPtr<Image> snapshotImage;
1719         if (snapshot)
1720             snapshotImage = snapshot->createImage();
1721         m_pluginElement->updateSnapshot(snapshotImage.get());
1722
1723         if (snapshotImage) {
1724 #if ENABLE(PRIMARY_SNAPSHOTTED_PLUGIN_HEURISTIC)
1725             bool snapshotIsAlmostSolidColor = isAlmostSolidColor(toBitmapImage(snapshotImage.get()));
1726             snapshotFound = !snapshotIsAlmostSolidColor;
1727 #endif
1728
1729 #if PLATFORM(COCOA)
1730             unsigned maximumSnapshotRetries = frame() ? frame()->settings().maximumPlugInSnapshotAttempts() : 0;
1731             if (snapshotIsAlmostSolidColor && m_countSnapshotRetries < maximumSnapshotRetries && !plugInCameOnScreen) {
1732                 ++m_countSnapshotRetries;
1733                 m_pluginSnapshotTimer.restart();
1734                 return;
1735             }
1736 #endif
1737         }
1738     }
1739
1740 #if ENABLE(PRIMARY_SNAPSHOTTED_PLUGIN_HEURISTIC)
1741     unsigned candidateArea = 0;
1742     bool noSnapshotFoundAfterMaxRetries = m_countSnapshotRetries == frame()->settings().maximumPlugInSnapshotAttempts() && !isPlugInOnScreen && !snapshotFound;
1743     if (m_webPage->plugInIsPrimarySize(*plugInImageElement, candidateArea)
1744         && (noSnapshotFoundAfterMaxRetries || plugInCameOnScreen))
1745         m_pluginElement->setDisplayState(HTMLPlugInElement::Playing);
1746     else
1747 #endif
1748         m_pluginElement->setDisplayState(HTMLPlugInElement::DisplayingSnapshot);
1749 }
1750
1751 void PluginView::beginSnapshottingRunningPlugin()
1752 {
1753     m_pluginSnapshotTimer.restart();
1754 }
1755
1756 bool PluginView::shouldAlwaysAutoStart() const
1757 {
1758     if (!m_plugin)
1759         return PluginViewBase::shouldAlwaysAutoStart();
1760
1761     if (MIMETypeRegistry::isJavaAppletMIMEType(m_parameters.mimeType))
1762         return true;
1763
1764     return m_plugin->shouldAlwaysAutoStart();
1765 }
1766
1767 void PluginView::pluginDidReceiveUserInteraction()
1768 {
1769     if (frame() && !frame()->settings().plugInSnapshottingEnabled())
1770         return;
1771
1772     if (m_didReceiveUserInteraction)
1773         return;
1774
1775     m_didReceiveUserInteraction = true;
1776
1777     WebCore::HTMLPlugInImageElement* plugInImageElement = toHTMLPlugInImageElement(m_pluginElement.get());
1778     String pageOrigin = plugInImageElement->document().page()->mainFrame().document()->baseURL().host();
1779     String pluginOrigin = plugInImageElement->loadedUrl().host();
1780     String mimeType = plugInImageElement->loadedMimeType();
1781
1782     WebProcess::shared().plugInDidReceiveUserInteraction(pageOrigin, pluginOrigin, mimeType, plugInImageElement->document().page()->sessionID());
1783 }
1784
1785 bool PluginView::shouldCreateTransientPaintingSnapshot() const
1786 {
1787     if (!m_plugin)
1788         return false;
1789
1790     if (!m_isInitialized)
1791         return false;
1792
1793     if (FrameView* frameView = frame()->view()) {
1794         if (frameView->paintBehavior() & (PaintBehaviorSelectionOnly | PaintBehaviorForceBlackText)) {
1795             // This paint behavior is used when drawing the find indicator and there's no need to
1796             // snapshot plug-ins, because they can never be painted as part of the find indicator.
1797             return false;
1798         }
1799     }
1800
1801     return true;
1802 }
1803
1804 } // namespace WebKit