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