bb68f0c36afa03a32b86cd6a085374a55c93698a
[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 "WebEvent.h"
33 #include "WebPage.h"
34 #include "WebPageProxyMessages.h"
35 #include "WebProcess.h"
36 #include <WebCore/Chrome.h>
37 #include <WebCore/CookieJar.h>
38 #include <WebCore/Credential.h>
39 #include <WebCore/CredentialStorage.h>
40 #include <WebCore/DocumentLoader.h>
41 #include <WebCore/MouseEvent.h>
42 #include <WebCore/FocusController.h>
43 #include <WebCore/Frame.h>
44 #include <WebCore/FrameLoadRequest.h>
45 #include <WebCore/FrameLoaderClient.h>
46 #include <WebCore/FrameView.h>
47 #include <WebCore/GraphicsContext.h>
48 #include <WebCore/HTMLPlugInElement.h>
49 #include <WebCore/HostWindow.h>
50 #include <WebCore/NetscapePlugInStreamLoader.h>
51 #include <WebCore/NetworkingContext.h>
52 #include <WebCore/Page.h>
53 #include <WebCore/ProtectionSpace.h>
54 #include <WebCore/ProxyServer.h>
55 #include <WebCore/RenderEmbeddedObject.h>
56 #include <WebCore/RenderLayer.h>
57 #include <WebCore/ResourceLoadScheduler.h>
58 #include <WebCore/ScriptValue.h>
59 #include <WebCore/ScrollView.h>
60 #include <WebCore/Settings.h>
61
62 using namespace JSC;
63 using namespace WebCore;
64
65 namespace WebKit {
66
67 class PluginView::URLRequest : public RefCounted<URLRequest> {
68 public:
69     static PassRefPtr<PluginView::URLRequest> create(uint64_t requestID, const FrameLoadRequest& request, bool allowPopups)
70     {
71         return adoptRef(new URLRequest(requestID, request, allowPopups));
72     }
73
74     uint64_t requestID() const { return m_requestID; }
75     const String& target() const { return m_request.frameName(); }
76     const ResourceRequest & request() const { return m_request.resourceRequest(); }
77     bool allowPopups() const { return m_allowPopups; }
78
79 private:
80     URLRequest(uint64_t requestID, const FrameLoadRequest& request, bool allowPopups)
81         : m_requestID(requestID)
82         , m_request(request)
83         , m_allowPopups(allowPopups)
84     {
85     }
86
87     uint64_t m_requestID;
88     FrameLoadRequest m_request;
89     bool m_allowPopups;
90 };
91
92 class PluginView::Stream : public RefCounted<PluginView::Stream>, NetscapePlugInStreamLoaderClient {
93 public:
94     static PassRefPtr<Stream> create(PluginView* pluginView, uint64_t streamID, const ResourceRequest& request)
95     {
96         return adoptRef(new Stream(pluginView, streamID, request));
97     }
98     ~Stream();
99
100     void start();
101     void cancel();
102
103     uint64_t streamID() const { return m_streamID; }
104
105 private:
106     Stream(PluginView* pluginView, uint64_t streamID, const ResourceRequest& request)
107         : m_pluginView(pluginView)
108         , m_streamID(streamID)
109         , m_request(request)
110         , m_streamWasCancelled(false)
111     {
112     }
113
114     // NetscapePluginStreamLoaderClient
115     virtual void didReceiveResponse(NetscapePlugInStreamLoader*, const ResourceResponse&);
116     virtual void didReceiveData(NetscapePlugInStreamLoader*, const char*, int);
117     virtual void didFail(NetscapePlugInStreamLoader*, const ResourceError&);
118     virtual void didFinishLoading(NetscapePlugInStreamLoader*);
119
120     PluginView* m_pluginView;
121     uint64_t m_streamID;
122     const ResourceRequest m_request;
123     
124     // True if the stream was explicitly cancelled by calling cancel().
125     // (As opposed to being cancelled by the user hitting the stop button for example.
126     bool m_streamWasCancelled;
127     
128     RefPtr<NetscapePlugInStreamLoader> m_loader;
129 };
130
131 PluginView::Stream::~Stream()
132 {
133     ASSERT(!m_pluginView);
134 }
135     
136 void PluginView::Stream::start()
137 {
138     ASSERT(!m_loader);
139
140     Frame* frame = m_pluginView->m_pluginElement->document()->frame();
141     ASSERT(frame);
142
143     m_loader = resourceLoadScheduler()->schedulePluginStreamLoad(frame, this, m_request);
144 }
145
146 void PluginView::Stream::cancel()
147 {
148     ASSERT(m_loader);
149
150     m_streamWasCancelled = true;
151     m_loader->cancel(m_loader->cancelledError());
152     m_loader = 0;
153 }
154
155 static String buildHTTPHeaders(const ResourceResponse& response, long long& expectedContentLength)
156 {
157     if (!response.isHTTP())
158         return String();
159
160     Vector<UChar> stringBuilder;
161     String separator(": ");
162     
163     String statusLine = String::format("HTTP %d ", response.httpStatusCode());
164     stringBuilder.append(statusLine.characters(), statusLine.length());
165     stringBuilder.append(response.httpStatusText().characters(), response.httpStatusText().length());
166     stringBuilder.append('\n');
167     
168     HTTPHeaderMap::const_iterator end = response.httpHeaderFields().end();
169     for (HTTPHeaderMap::const_iterator it = response.httpHeaderFields().begin(); it != end; ++it) {
170         stringBuilder.append(it->first.characters(), it->first.length());
171         stringBuilder.append(separator.characters(), separator.length());
172         stringBuilder.append(it->second.characters(), it->second.length());
173         stringBuilder.append('\n');
174     }
175     
176     String headers = String::adopt(stringBuilder);
177     
178     // If the content is encoded (most likely compressed), then don't send its length to the plugin,
179     // which is only interested in the decoded length, not yet known at the moment.
180     // <rdar://problem/4470599> tracks a request for -[NSURLResponse expectedContentLength] to incorporate this logic.
181     String contentEncoding = response.httpHeaderField("Content-Encoding");
182     if (!contentEncoding.isNull() && contentEncoding != "identity")
183         expectedContentLength = -1;
184
185     return headers;
186 }
187
188 void PluginView::Stream::didReceiveResponse(NetscapePlugInStreamLoader*, const ResourceResponse& response)
189 {
190     // Compute the stream related data from the resource response.
191     const KURL& responseURL = response.url();
192     const String& mimeType = response.mimeType();
193     long long expectedContentLength = response.expectedContentLength();
194     
195     String headers = buildHTTPHeaders(response, expectedContentLength);
196
197     uint32_t streamLength = 0;
198     if (expectedContentLength > 0)
199         streamLength = expectedContentLength;
200
201     m_pluginView->m_plugin->streamDidReceiveResponse(m_streamID, responseURL, streamLength, response.lastModifiedDate(), mimeType, headers);
202 }
203
204 void PluginView::Stream::didReceiveData(NetscapePlugInStreamLoader*, const char* bytes, int length)
205 {
206     m_pluginView->m_plugin->streamDidReceiveData(m_streamID, bytes, length);
207 }
208
209 void PluginView::Stream::didFail(NetscapePlugInStreamLoader*, const ResourceError& error) 
210 {
211     // Calling streamDidFail could cause us to be deleted, so we hold on to a reference here.
212     RefPtr<Stream> protect(this);
213
214     // We only want to call streamDidFail if the stream was not explicitly cancelled by the plug-in.
215     if (!m_streamWasCancelled)
216         m_pluginView->m_plugin->streamDidFail(m_streamID, error.isCancellation());
217
218     m_pluginView->removeStream(this);
219     m_pluginView = 0;
220 }
221
222 void PluginView::Stream::didFinishLoading(NetscapePlugInStreamLoader*)
223 {
224     // Calling streamDidFinishLoading could cause us to be deleted, so we hold on to a reference here.
225     RefPtr<Stream> protectStream(this);
226
227     // Protect the plug-in while we're calling into it.
228     NPRuntimeObjectMap::PluginProtector pluginProtector(&m_pluginView->m_npRuntimeObjectMap);
229     m_pluginView->m_plugin->streamDidFinishLoading(m_streamID);
230
231     m_pluginView->removeStream(this);
232     m_pluginView = 0;
233 }
234
235 static inline WebPage* webPage(HTMLPlugInElement* pluginElement)
236 {
237     Frame* frame = pluginElement->document()->frame();
238     ASSERT(frame);
239
240     WebPage* webPage = static_cast<WebFrameLoaderClient*>(frame->loader()->client())->webFrame()->page();
241     ASSERT(webPage);
242
243     return webPage;
244 }
245
246 PassRefPtr<PluginView> PluginView::create(PassRefPtr<HTMLPlugInElement> pluginElement, PassRefPtr<Plugin> plugin, const Plugin::Parameters& parameters)
247 {
248     return adoptRef(new PluginView(pluginElement, plugin, parameters));
249 }
250
251 PluginView::PluginView(PassRefPtr<HTMLPlugInElement> pluginElement, PassRefPtr<Plugin> plugin, const Plugin::Parameters& parameters)
252     : PluginViewBase(0)
253     , m_pluginElement(pluginElement)
254     , m_plugin(plugin)
255     , m_webPage(webPage(m_pluginElement.get()))
256     , m_parameters(parameters)
257     , m_isInitialized(false)
258     , m_isWaitingUntilMediaCanStart(false)
259     , m_isBeingDestroyed(false)
260     , m_pendingURLRequestsTimer(RunLoop::main(), this, &PluginView::pendingURLRequestsTimerFired)
261     , m_npRuntimeObjectMap(this)
262     , m_manualStreamState(StreamStateInitial)
263 {
264 #if PLATFORM(MAC)
265     m_webPage->addPluginView(this);
266 #endif
267 }
268
269 PluginView::~PluginView()
270 {
271 #if PLATFORM(MAC)
272     m_webPage->removePluginView(this);
273 #endif
274
275     ASSERT(!m_isBeingDestroyed);
276
277     if (m_isWaitingUntilMediaCanStart)
278         m_pluginElement->document()->removeMediaCanStartListener(this);
279
280     // Cancel all pending frame loads.
281     for (FrameLoadMap::iterator it = m_pendingFrameLoads.begin(), end = m_pendingFrameLoads.end(); it != end; ++it)
282         it->first->setLoadListener(0);
283
284     if (m_plugin && m_isInitialized) {
285         m_isBeingDestroyed = true;
286         m_plugin->destroy();
287         m_isBeingDestroyed = false;
288     }
289
290     // Invalidate the object map.
291     m_npRuntimeObjectMap.invalidate();
292
293     cancelAllStreams();
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 Frame* PluginView::frame() const
301 {
302     return m_pluginElement->document()->frame();
303 }
304
305 void PluginView::manualLoadDidReceiveResponse(const ResourceResponse& response)
306 {
307     // The plug-in can be null here if it failed to initialize.
308     if (!m_plugin)
309         return;
310
311     if (!m_isInitialized) {
312         ASSERT(m_manualStreamState == StreamStateInitial);
313         m_manualStreamState = StreamStateHasReceivedResponse;
314         m_manualStreamResponse = response;
315         return;
316     }
317
318     // Compute the stream related data from the resource response.
319     const KURL& responseURL = response.url();
320     const String& mimeType = response.mimeType();
321     long long expectedContentLength = response.expectedContentLength();
322     
323     String headers = buildHTTPHeaders(response, expectedContentLength);
324     
325     uint32_t streamLength = 0;
326     if (expectedContentLength > 0)
327         streamLength = expectedContentLength;
328
329     m_plugin->manualStreamDidReceiveResponse(responseURL, streamLength, response.lastModifiedDate(), mimeType, headers);
330 }
331
332 void PluginView::manualLoadDidReceiveData(const char* bytes, int length)
333 {
334     // The plug-in can be null here if it failed to initialize.
335     if (!m_plugin)
336         return;
337
338     if (!m_isInitialized) {
339         ASSERT(m_manualStreamState == StreamStateHasReceivedResponse);
340         if (!m_manualStreamData)
341             m_manualStreamData = SharedBuffer::create();
342
343         m_manualStreamData->append(bytes, length);
344         return;
345     }
346
347     m_plugin->manualStreamDidReceiveData(bytes, length);
348 }
349
350 void PluginView::manualLoadDidFinishLoading()
351 {
352     // The plug-in can be null here if it failed to initialize.
353     if (!m_plugin)
354         return;
355
356     if (!m_isInitialized) {
357         ASSERT(m_manualStreamState == StreamStateHasReceivedResponse);
358         m_manualStreamState = StreamStateFinished;
359         return;
360     }
361
362     m_plugin->manualStreamDidFinishLoading();
363 }
364
365 void PluginView::manualLoadDidFail(const ResourceError& error)
366 {
367     // The plug-in can be null here if it failed to initialize.
368     if (!m_plugin)
369         return;
370
371     if (!m_isInitialized) {
372         m_manualStreamState = StreamStateFinished;
373         m_manualStreamError = error;
374         m_manualStreamData = nullptr;
375         return;
376     }
377
378     m_plugin->manualStreamDidFail(error.isCancellation());
379 }
380
381 #if PLATFORM(MAC)    
382 void PluginView::setWindowIsVisible(bool windowIsVisible)
383 {
384     if (!m_plugin)
385         return;
386
387     // FIXME: Implement.
388 }
389
390 void PluginView::setWindowIsFocused(bool windowIsFocused)
391 {
392     if (!m_isInitialized || !m_plugin)
393         return;
394
395     m_plugin->windowFocusChanged(windowIsFocused);    
396 }
397
398 void PluginView::windowAndViewFramesChanged(const IntRect& windowFrameInScreenCoordinates, const IntRect& viewFrameInWindowCoordinates)
399 {
400     if (!m_isInitialized || !m_plugin)
401         return;
402
403     m_plugin->windowAndViewFramesChanged(windowFrameInScreenCoordinates, viewFrameInWindowCoordinates);
404 }
405
406 bool PluginView::sendComplexTextInput(uint64_t pluginComplexTextInputIdentifier, const String& textInput)
407 {
408     if (!m_plugin)
409         return false;
410
411     if (m_plugin->pluginComplexTextInputIdentifier() != pluginComplexTextInputIdentifier)
412         return false;
413
414     m_plugin->sendComplexTextInput(textInput);
415     return true;
416 }
417
418 #endif
419
420 void PluginView::initializePlugin()
421 {
422     if (m_isInitialized)
423         return;
424
425     if (!m_plugin) {
426         // We've already tried and failed to initialize the plug-in.
427         return;
428     }
429
430     if (Frame* frame = m_pluginElement->document()->frame()) {
431         if (Page* page = frame->page()) {
432             
433             // We shouldn't initialize the plug-in right now, add a listener.
434             if (!page->canStartMedia()) {
435                 if (m_isWaitingUntilMediaCanStart)
436                     return;
437                 
438                 m_isWaitingUntilMediaCanStart = true;
439                 m_pluginElement->document()->addMediaCanStartListener(this);
440                 return;
441             }
442         }
443     }
444     
445     if (!m_plugin->initialize(this, m_parameters)) {
446         // We failed to initialize the plug-in.
447         m_plugin = 0;
448
449         m_webPage->send(Messages::WebPageProxy::DidFailToInitializePlugin(m_parameters.mimeType));
450         return;
451     }
452     
453     m_isInitialized = true;
454
455     viewGeometryDidChange();
456
457     redeliverManualStream();
458
459 #if PLATFORM(MAC)
460     if (m_plugin->pluginLayer()) {
461         if (frame()) {
462             frame()->view()->enterCompositingMode();
463             m_pluginElement->setNeedsStyleRecalc(SyntheticStyleChange);
464         }
465     }
466
467     windowAndViewFramesChanged(m_webPage->windowFrameInScreenCoordinates(), m_webPage->viewFrameInWindowCoordinates());
468     setWindowIsVisible(m_webPage->windowIsVisible());
469     setWindowIsFocused(m_webPage->windowIsFocused());
470 #endif
471 }
472
473 #if PLATFORM(MAC)
474 PlatformLayer* PluginView::platformLayer() const
475 {
476     // The plug-in can be null here if it failed to initialize.
477     if (!m_isInitialized || !m_plugin)
478         return 0;
479         
480     return m_plugin->pluginLayer();
481 }
482 #endif
483
484 JSObject* PluginView::scriptObject(JSGlobalObject* globalObject)
485 {
486     // The plug-in can be null here if it failed to initialize.
487     if (!m_isInitialized || !m_plugin)
488         return 0;
489
490     NPObject* scriptableNPObject = m_plugin->pluginScriptableNPObject();
491     if (!scriptableNPObject)
492         return 0;
493
494     JSObject* jsObject = m_npRuntimeObjectMap.getOrCreateJSObject(globalObject, scriptableNPObject);
495     releaseNPObject(scriptableNPObject);
496
497     return jsObject;
498 }
499
500 void PluginView::privateBrowsingStateChanged(bool privateBrowsingEnabled)
501 {
502     // The plug-in can be null here if it failed to initialize.
503     if (!m_isInitialized || !m_plugin)
504         return;
505
506     m_plugin->privateBrowsingStateChanged(privateBrowsingEnabled);
507 }
508
509 void PluginView::setFrameRect(const WebCore::IntRect& rect)
510 {
511     Widget::setFrameRect(rect);
512     viewGeometryDidChange();
513 }
514
515 void PluginView::setBoundsSize(const WebCore::IntSize& size)
516 {
517     Widget::setBoundsSize(size);
518     m_boundsSize = size;
519     viewGeometryDidChange();
520 }
521
522 void PluginView::paint(GraphicsContext* context, const IntRect& dirtyRect)
523 {
524     if (context->paintingDisabled() || !m_plugin || !m_isInitialized)
525         return;
526
527     IntRect dirtyRectInWindowCoordinates = parent()->contentsToWindow(dirtyRect);
528     IntRect paintRectInWindowCoordinates = intersection(dirtyRectInWindowCoordinates, clipRectInWindowCoordinates());
529     if (paintRectInWindowCoordinates.isEmpty())
530         return;
531
532     if (m_snapshot)
533         m_snapshot->paint(*context, frameRect().location(), m_snapshot->bounds());
534     else {
535         // The plugin is given a frame rect which is parent()->contentsToWindow(frameRect()),
536         // and un-translates by the its origin when painting. The current CTM reflects
537         // this widget's frame is its parent (the document), so we have to offset the CTM by
538         // the document's window coordinates.
539         IntPoint documentOriginInWindowCoordinates = parent()->contentsToWindow(IntPoint());
540         
541         GraphicsContextStateSaver stateSaver(*context);
542         context->translate(-documentOriginInWindowCoordinates.x(), -documentOriginInWindowCoordinates.y());
543         m_plugin->paint(context, paintRectInWindowCoordinates);
544     }
545 }
546
547 void PluginView::frameRectsChanged()
548 {
549     Widget::frameRectsChanged();
550     viewGeometryDidChange();
551 }
552
553 void PluginView::setParent(ScrollView* scrollView)
554 {
555     Widget::setParent(scrollView);
556     
557     if (scrollView)
558         initializePlugin();
559 }
560
561 void PluginView::handleEvent(Event* event)
562 {
563     if (!m_isInitialized || !m_plugin)
564         return;
565
566     const WebEvent* currentEvent = WebPage::currentEvent();
567     if (!currentEvent)
568         return;
569
570     bool didHandleEvent = false;
571
572     if ((event->type() == eventNames().mousemoveEvent && currentEvent->type() == WebEvent::MouseMove)
573         || (event->type() == eventNames().mousedownEvent && currentEvent->type() == WebEvent::MouseDown)
574         || (event->type() == eventNames().mouseupEvent && currentEvent->type() == WebEvent::MouseUp)) {
575         // We have a mouse event.
576         if (currentEvent->type() == WebEvent::MouseDown)
577             focusPluginElement();
578         
579         // Adjust mouse coordinates to account for pageScaleFactor
580         float scaleFactor = frame()->pageScaleFactor();
581         WebMouseEvent eventWithScaledCoordinates(*(static_cast<const WebMouseEvent*>(currentEvent)), scaleFactor);
582         didHandleEvent = m_plugin->handleMouseEvent(eventWithScaledCoordinates);
583     } else if (event->type() == eventNames().mousewheelEvent && currentEvent->type() == WebEvent::Wheel) {
584         // We have a wheel event.
585         didHandleEvent = m_plugin->handleWheelEvent(static_cast<const WebWheelEvent&>(*currentEvent));
586     } else if (event->type() == eventNames().mouseoverEvent && currentEvent->type() == WebEvent::MouseMove) {
587         // We have a mouse enter event.
588         didHandleEvent = m_plugin->handleMouseEnterEvent(static_cast<const WebMouseEvent&>(*currentEvent));
589     } else if (event->type() == eventNames().mouseoutEvent && currentEvent->type() == WebEvent::MouseMove) {
590         // We have a mouse leave event.
591         didHandleEvent = m_plugin->handleMouseLeaveEvent(static_cast<const WebMouseEvent&>(*currentEvent));
592     } else if ((event->type() == eventNames().keydownEvent && currentEvent->type() == WebEvent::KeyDown)
593                || (event->type() == eventNames().keyupEvent && currentEvent->type() == WebEvent::KeyUp)) {
594         // We have a keyboard event.
595         didHandleEvent = m_plugin->handleKeyboardEvent(static_cast<const WebKeyboardEvent&>(*currentEvent));
596     }
597
598     if (didHandleEvent)
599         event->setDefaultHandled();
600 }
601
602 void PluginView::notifyWidget(WidgetNotification notification)
603 {
604     switch (notification) {
605     case WillPaintFlattened:
606         if (m_plugin && m_isInitialized)
607             m_snapshot = m_plugin->snapshot();
608         break;
609     case DidPaintFlattened:
610         m_snapshot = nullptr;
611         break;
612     }
613 }
614
615 void PluginView::show()
616 {
617     bool wasVisible = isVisible();
618
619     setSelfVisible(true);
620
621     if (!wasVisible)
622         viewVisibilityDidChange();
623
624     Widget::show();
625 }
626
627 void PluginView::hide()
628 {
629     bool wasVisible = isVisible();
630
631     setSelfVisible(false);
632
633     if (wasVisible)
634         viewVisibilityDidChange();
635
636     Widget::hide();
637 }
638
639 void PluginView::viewGeometryDidChange()
640 {
641     if (!m_isInitialized || !m_plugin || !parent())
642         return;
643
644     // Get the frame rect in window coordinates.
645     IntRect frameRectInWindowCoordinates = parent()->contentsToWindow(frameRect());
646     
647     // Adjust bounds to account for pageScaleFactor
648     frameRectInWindowCoordinates.scale(1 / frame()->pageScaleFactor());
649     m_plugin->geometryDidChange(frameRectInWindowCoordinates, clipRectInWindowCoordinates());
650 }
651
652 void PluginView::viewVisibilityDidChange()
653 {
654     if (!m_isInitialized || !m_plugin || !parent())
655         return;
656
657     m_plugin->visibilityDidChange();
658 }
659
660 IntRect PluginView::clipRectInWindowCoordinates() const
661 {
662     // Get the frame rect in window coordinates.
663     IntRect frameRectInWindowCoordinates = parent()->contentsToWindow(frameRect());
664
665     Frame* frame = this->frame();
666
667     // Get the window clip rect for the enclosing layer (in window coordinates).
668     RenderLayer* layer = m_pluginElement->renderer()->enclosingLayer();
669     IntRect windowClipRect = frame->view()->windowClipRectForLayer(layer, true);
670
671     // Intersect the two rects to get the view clip rect in window coordinates.
672     frameRectInWindowCoordinates.intersect(windowClipRect);
673
674     frameRectInWindowCoordinates.scale(1 / frame->pageScaleFactor());
675     return frameRectInWindowCoordinates;
676 }
677
678 void PluginView::focusPluginElement()
679 {
680     ASSERT(frame());
681     
682     if (Page* page = frame()->page())
683         page->focusController()->setFocusedFrame(frame());
684     frame()->document()->setFocusedNode(m_pluginElement);
685 }
686
687 void PluginView::pendingURLRequestsTimerFired()
688 {
689     ASSERT(!m_pendingURLRequests.isEmpty());
690     
691     RefPtr<URLRequest> urlRequest = m_pendingURLRequests.takeFirst();
692
693     // If there are more requests to perform, reschedule the timer.
694     if (!m_pendingURLRequests.isEmpty())
695         m_pendingURLRequestsTimer.startOneShot(0);
696     
697     performURLRequest(urlRequest.get());
698 }
699     
700 void PluginView::performURLRequest(URLRequest* request)
701 {
702     // First, check if this is a javascript: url.
703     if (protocolIsJavaScript(request->request().url())) {
704         performJavaScriptURLRequest(request);
705         return;
706     }
707
708     if (!request->target().isNull()) {
709         performFrameLoadURLRequest(request);
710         return;
711     }
712
713     // This request is to load a URL and create a stream.
714     RefPtr<Stream> stream = PluginView::Stream::create(this, request->requestID(), request->request());
715     addStream(stream.get());
716     stream->start();
717 }
718
719 void PluginView::performFrameLoadURLRequest(URLRequest* request)
720 {
721     ASSERT(!request->target().isNull());
722
723     Frame* frame = m_pluginElement->document()->frame();
724     if (!frame)
725         return;
726
727     if (!m_pluginElement->document()->securityOrigin()->canDisplay(request->request().url())) {
728         // We can't load the request, send back a reply to the plug-in.
729         m_plugin->frameDidFail(request->requestID(), false);
730         return;
731     }
732
733     // First, try to find a target frame.
734     Frame* targetFrame = frame->loader()->findFrameForNavigation(request->target());
735     if (!targetFrame) {
736         // We did not find a target frame. Ask our frame to load the page. This may or may not create a popup window.
737         frame->loader()->load(request->request(), request->target(), false);
738
739         // FIXME: We don't know whether the window was successfully created here so we just assume that it worked.
740         // It's better than not telling the plug-in anything.
741         m_plugin->frameDidFinishLoading(request->requestID());
742         return;
743     }
744
745     // Now ask the frame to load the request.
746     targetFrame->loader()->load(request->request(), false);
747
748     WebFrame* targetWebFrame = static_cast<WebFrameLoaderClient*>(targetFrame->loader()->client())->webFrame();
749     if (WebFrame::LoadListener* loadListener = targetWebFrame->loadListener()) {
750         // Check if another plug-in view or even this view is waiting for the frame to load.
751         // If it is, tell it that the load was cancelled because it will be anyway.
752         loadListener->didFailLoad(targetWebFrame, true);
753     }
754     
755     m_pendingFrameLoads.set(targetWebFrame, request);
756     targetWebFrame->setLoadListener(this);
757 }
758
759 void PluginView::performJavaScriptURLRequest(URLRequest* request)
760 {
761     ASSERT(protocolIsJavaScript(request->request().url()));
762
763     RefPtr<Frame> frame = m_pluginElement->document()->frame();
764     if (!frame)
765         return;
766     
767     String jsString = decodeURLEscapeSequences(request->request().url().string().substring(sizeof("javascript:") - 1));
768
769     if (!request->target().isNull()) {
770         // For security reasons, only allow JS requests to be made on the frame that contains the plug-in.
771         if (frame->tree()->find(request->target()) != frame) {
772             // Let the plug-in know that its frame load failed.
773             m_plugin->frameDidFail(request->requestID(), false);
774             return;
775         }
776     }
777
778     // Evaluate the JavaScript code. Note that running JavaScript here could cause the plug-in to be destroyed, so we
779     // grab references to the plug-in here.
780     RefPtr<Plugin> plugin = m_plugin;
781
782     bool oldAllowPopups = frame->script()->allowPopupsFromPlugin();
783     frame->script()->setAllowPopupsFromPlugin(request->allowPopups());
784     
785     ScriptValue result = frame->script()->executeScript(jsString);
786
787     frame->script()->setAllowPopupsFromPlugin(oldAllowPopups);
788
789     // Check if evaluating the JavaScript destroyed the plug-in.
790     if (!plugin->controller())
791         return;
792
793     // Don't notify the plug-in at all about targeted javascript: requests. This matches Mozilla and WebKit1.
794     if (!request->target().isNull())
795         return;
796
797     ScriptState* scriptState = frame->script()->globalObject(pluginWorld())->globalExec();
798     String resultString;
799     result.getString(scriptState, resultString);
800   
801     // Send the result back to the plug-in.
802     plugin->didEvaluateJavaScript(request->requestID(), resultString);
803 }
804
805 void PluginView::addStream(Stream* stream)
806 {
807     ASSERT(!m_streams.contains(stream->streamID()));
808     m_streams.set(stream->streamID(), stream);
809 }
810     
811 void PluginView::removeStream(Stream* stream)
812 {
813     ASSERT(m_streams.get(stream->streamID()) == stream);
814     
815     m_streams.remove(stream->streamID());
816 }
817
818 void PluginView::cancelAllStreams()
819 {
820     Vector<RefPtr<Stream> > streams;
821     copyValuesToVector(m_streams, streams);
822     
823     for (size_t i = 0; i < streams.size(); ++i)
824         streams[i]->cancel();
825
826     // Cancelling a stream removes it from the m_streams map, so if we cancel all streams the map should be empty.
827     ASSERT(m_streams.isEmpty());
828 }
829
830 void PluginView::redeliverManualStream()
831 {
832     if (m_manualStreamState == StreamStateInitial) {
833         // Nothing to do.
834         return;
835     }
836
837     if (m_manualStreamState == StreamStateFailed) {
838         manualLoadDidFail(m_manualStreamError);
839         return;
840     }
841
842     // Deliver the response.
843     manualLoadDidReceiveResponse(m_manualStreamResponse);
844
845     // Deliver the data.
846     if (m_manualStreamData) {
847         const char* data;
848         unsigned position = 0;
849
850         while (unsigned length = m_manualStreamData->getSomeData(data, position)) {
851             manualLoadDidReceiveData(data, length);
852             position += length;
853         }
854
855         m_manualStreamData = nullptr;
856     }
857
858     if (m_manualStreamState == StreamStateFinished)
859         manualLoadDidFinishLoading();
860 }
861
862 void PluginView::invalidateRect(const IntRect& dirtyRect)
863 {
864     if (!parent() || !m_plugin || !m_isInitialized)
865         return;
866
867 #if PLATFORM(MAC)
868     if (m_plugin->pluginLayer())
869         return;
870 #endif
871
872     RenderBoxModelObject* renderer = toRenderBoxModelObject(m_pluginElement->renderer());
873     if (!renderer)
874         return;
875     
876     IntRect contentRect(dirtyRect);
877     contentRect.move(renderer->borderLeft() + renderer->paddingLeft(), renderer->borderTop() + renderer->paddingTop());
878     renderer->repaintRectangle(contentRect);
879 }
880
881 void PluginView::setFocus(bool hasFocus)
882 {
883     Widget::setFocus(hasFocus);
884
885     if (!m_isInitialized || !m_plugin)
886         return;
887
888     m_plugin->setFocus(hasFocus);
889 }
890
891 void PluginView::mediaCanStart()
892 {
893     ASSERT(m_isWaitingUntilMediaCanStart);
894     m_isWaitingUntilMediaCanStart = false;
895     
896     initializePlugin();
897 }
898
899 bool PluginView::isPluginVisible()
900 {
901     return isVisible();
902 }
903
904 void PluginView::invalidate(const IntRect& dirtyRect)
905 {
906     invalidateRect(dirtyRect);
907 }
908
909 String PluginView::userAgent()
910 {
911     Frame* frame = m_pluginElement->document()->frame();
912     if (!frame)
913         return String();
914     
915     return frame->loader()->client()->userAgent(KURL());
916 }
917
918 void PluginView::loadURL(uint64_t requestID, const String& method, const String& urlString, const String& target, 
919                          const HTTPHeaderMap& headerFields, const Vector<uint8_t>& httpBody, bool allowPopups)
920 {
921     FrameLoadRequest frameLoadRequest(m_pluginElement->document()->securityOrigin());
922     frameLoadRequest.resourceRequest().setHTTPMethod(method);
923     frameLoadRequest.resourceRequest().setURL(m_pluginElement->document()->completeURL(urlString));
924     frameLoadRequest.resourceRequest().addHTTPHeaderFields(headerFields);
925     frameLoadRequest.resourceRequest().setHTTPBody(FormData::create(httpBody.data(), httpBody.size()));
926     frameLoadRequest.setFrameName(target);
927
928     m_pendingURLRequests.append(URLRequest::create(requestID, frameLoadRequest, allowPopups));
929     m_pendingURLRequestsTimer.startOneShot(0);
930 }
931
932 void PluginView::cancelStreamLoad(uint64_t streamID)
933 {
934     // Keep a reference to the stream. Stream::cancel might remove the stream from the map, and thus
935     // releasing its last reference.
936     RefPtr<Stream> stream = m_streams.get(streamID).get();
937     if (!stream)
938         return;
939
940     // Cancelling the stream here will remove it from the map.
941     stream->cancel();
942     ASSERT(!m_streams.contains(streamID));
943 }
944
945 void PluginView::cancelManualStreamLoad()
946 {
947     if (!frame())
948         return;
949
950     DocumentLoader* documentLoader = frame()->loader()->activeDocumentLoader();
951     ASSERT(documentLoader);
952     
953     if (documentLoader->isLoadingMainResource())
954         documentLoader->cancelMainResourceLoad(frame()->loader()->cancelledError(m_parameters.url));
955 }
956
957 NPObject* PluginView::windowScriptNPObject()
958 {
959     if (!frame())
960         return 0;
961
962     // FIXME: Handle JavaScript being disabled.
963     ASSERT(frame()->script()->canExecuteScripts(NotAboutToExecuteScript));
964
965     return m_npRuntimeObjectMap.getOrCreateNPObject(*pluginWorld()->globalData(), frame()->script()->windowShell(pluginWorld())->window());
966 }
967
968 NPObject* PluginView::pluginElementNPObject()
969 {
970     if (!frame())
971         return 0;
972
973     // FIXME: Handle JavaScript being disabled.
974     JSObject* object = frame()->script()->jsObjectForPluginElement(m_pluginElement.get());
975     ASSERT(object);
976
977     return m_npRuntimeObjectMap.getOrCreateNPObject(*pluginWorld()->globalData(), object);
978 }
979
980 bool PluginView::evaluate(NPObject* npObject, const String& scriptString, NPVariant* result, bool allowPopups)
981 {
982     RefPtr<Frame> frame = m_pluginElement->document()->frame();
983     if (!frame)
984         return false;
985
986     bool oldAllowPopups = frame->script()->allowPopupsFromPlugin();
987     frame->script()->setAllowPopupsFromPlugin(allowPopups);
988
989     // Calling evaluate will run JavaScript that can potentially remove the plug-in element, so we need to
990     // protect the plug-in view from destruction.
991     NPRuntimeObjectMap::PluginProtector pluginProtector(&m_npRuntimeObjectMap);
992
993     bool returnValue = m_npRuntimeObjectMap.evaluate(npObject, scriptString, result);
994
995     frame->script()->setAllowPopupsFromPlugin(oldAllowPopups);
996
997     return returnValue;
998 }
999
1000 bool PluginView::tryToShortCircuitInvoke(NPObject*, NPIdentifier methodName, const NPVariant* arguments, uint32_t argumentCount, bool& returnValue, NPVariant& result)
1001 {
1002     // Never try to short-circuit invoke in the web process.
1003     return false;
1004 }
1005
1006 void PluginView::setStatusbarText(const String& statusbarText)
1007 {
1008     if (!frame())
1009         return;
1010     
1011     Page* page = frame()->page();
1012     if (!page)
1013         return;
1014
1015     page->chrome()->setStatusbarText(frame(), statusbarText);
1016 }
1017
1018 bool PluginView::isAcceleratedCompositingEnabled()
1019 {
1020     if (!frame())
1021         return false;
1022     
1023     Settings* settings = frame()->settings();
1024     if (!settings)
1025         return false;
1026
1027     return settings->acceleratedCompositingEnabled();
1028 }
1029
1030 void PluginView::pluginProcessCrashed()
1031 {
1032     if (!m_pluginElement->renderer())
1033         return;
1034
1035     // FIXME: The renderer could also be a RenderApplet, we should handle that.
1036     if (!m_pluginElement->renderer()->isEmbeddedObject())
1037         return;
1038         
1039     RenderEmbeddedObject* renderer = toRenderEmbeddedObject(m_pluginElement->renderer());
1040     renderer->setShowsCrashedPluginIndicator();
1041     
1042     Widget::invalidate();
1043 }
1044
1045 void PluginView::willSendEventToPlugin()
1046 {
1047     // If we're sending an event to a plug-in, we can't control how long the plug-in
1048     // takes to process it (e.g. it may display a context menu), so we tell the UI process
1049     // to stop the responsiveness timer in this case.
1050     m_webPage->send(Messages::WebPageProxy::StopResponsivenessTimer());
1051 }
1052
1053 #if PLATFORM(WIN)
1054 HWND PluginView::nativeParentWindow()
1055 {
1056     return m_webPage->nativeWindow();
1057 }
1058
1059 void PluginView::scheduleWindowedPluginGeometryUpdate(const WindowGeometry& geometry)
1060 {
1061     m_webPage->scheduleChildWindowGeometryUpdate(geometry);
1062 }
1063 #endif
1064
1065 #if PLATFORM(MAC)
1066 void PluginView::setComplexTextInputEnabled(bool complexTextInputEnabled)
1067 {
1068     m_webPage->send(Messages::WebPageProxy::SetComplexTextInputEnabled(m_plugin->pluginComplexTextInputIdentifier(), complexTextInputEnabled));
1069 }
1070
1071 mach_port_t PluginView::compositingRenderServerPort()
1072 {
1073     return WebProcess::shared().compositingRenderServerPort();
1074 }
1075
1076 #endif
1077     
1078 String PluginView::proxiesForURL(const String& urlString)
1079 {
1080     const FrameLoader* frameLoader = frame() ? frame()->loader() : 0;
1081     const NetworkingContext* context = frameLoader ? frameLoader->networkingContext() : 0;
1082     Vector<ProxyServer> proxyServers = proxyServersForURL(KURL(KURL(), urlString), context);
1083     return toString(proxyServers);
1084 }
1085
1086 String PluginView::cookiesForURL(const String& urlString)
1087 {
1088     return cookies(m_pluginElement->document(), KURL(KURL(), urlString));
1089 }
1090
1091 void PluginView::setCookiesForURL(const String& urlString, const String& cookieString)
1092 {
1093     setCookies(m_pluginElement->document(), KURL(KURL(), urlString), cookieString);
1094 }
1095
1096 bool PluginView::getAuthenticationInfo(const ProtectionSpace& protectionSpace, String& username, String& password)
1097 {
1098     Credential credential = CredentialStorage::get(protectionSpace);
1099     if (credential.isEmpty())
1100         credential = CredentialStorage::getFromPersistentStorage(protectionSpace);
1101
1102     if (!credential.hasPassword())
1103         return false;
1104
1105     username = credential.user();
1106     password = credential.password();
1107
1108     return true;
1109 }
1110
1111 bool PluginView::isPrivateBrowsingEnabled()
1112 {
1113     // If we can't get the real setting, we'll assume that private browsing is enabled.
1114     if (!frame())
1115         return true;
1116
1117     Settings* settings = frame()->settings();
1118     if (!settings)
1119         return true;
1120
1121     return settings->privateBrowsingEnabled();
1122 }
1123
1124 void PluginView::protectPluginFromDestruction()
1125 {
1126     if (!m_isBeingDestroyed)
1127         ref();
1128 }
1129
1130 void PluginView::unprotectPluginFromDestruction()
1131 {
1132     if (!m_isBeingDestroyed)
1133         deref();
1134 }
1135
1136 void PluginView::didFinishLoad(WebFrame* webFrame)
1137 {
1138     RefPtr<URLRequest> request = m_pendingFrameLoads.take(webFrame);
1139     ASSERT(request);
1140     webFrame->setLoadListener(0);
1141
1142     m_plugin->frameDidFinishLoading(request->requestID());
1143 }
1144
1145 void PluginView::didFailLoad(WebFrame* webFrame, bool wasCancelled)
1146 {
1147     RefPtr<URLRequest> request = m_pendingFrameLoads.take(webFrame);
1148     ASSERT(request);
1149     webFrame->setLoadListener(0);
1150     
1151     m_plugin->frameDidFail(request->requestID(), wasCancelled);
1152 }
1153
1154 } // namespace WebKit