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