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