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