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