Home | History | Annotate | Download | only in Plugins
      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:
     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 
     68     uint64_t requestID() const { return m_requestID; }
     69     const String& target() const { return m_request.frameName(); }
     70     const ResourceRequest & request() const { return m_request.resourceRequest(); }
     71     bool allowPopups() const { return m_allowPopups; }
     72 
     73 private:
     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:
     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 
     97     uint64_t streamID() const { return m_streamID; }
     98 
     99 private:
    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 
    125 PluginView::Stream::~Stream()
    126 {
    127     ASSERT(!m_pluginView);
    128 }
    129 
    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 
    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 
    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 
    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 
    198 void PluginView::Stream::didReceiveData(NetscapePlugInStreamLoader*, const char* bytes, int length)
    199 {
    200     m_pluginView->m_plugin->streamDidReceiveData(m_streamID, bytes, length);
    201 }
    202 
    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 
    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 
    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 
    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 
    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 
    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 
    295 Frame* PluginView::frame()
    296 {
    297     return m_pluginElement->document()->frame();
    298 }
    299 
    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 
    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 
    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 
    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)
    377 void PluginView::setWindowIsVisible(bool windowIsVisible)
    378 {
    379     if (!m_plugin)
    380         return;
    381 
    382     // FIXME: Implement.
    383 }
    384 
    385 void PluginView::setWindowIsFocused(bool windowIsFocused)
    386 {
    387     if (!m_isInitialized || !m_plugin)
    388         return;
    389 
    390     m_plugin->windowFocusChanged(windowIsFocused);
    391 }
    392 
    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 
    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 
    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)
    468 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 
    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 
    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 
    503 void PluginView::setFrameRect(const WebCore::IntRect& rect)
    504 {
    505     Widget::setFrameRect(rect);
    506     viewGeometryDidChange();
    507 }
    508 
    509 void PluginView::setBoundsSize(const WebCore::IntSize& size)
    510 {
    511     Widget::setBoundsSize(size);
    512     m_boundsSize = size;
    513     viewGeometryDidChange();
    514 }
    515 
    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 
    541 void PluginView::frameRectsChanged()
    542 {
    543     Widget::frameRectsChanged();
    544     viewGeometryDidChange();
    545 }
    546 
    547 void PluginView::setParent(ScrollView* scrollView)
    548 {
    549     Widget::setParent(scrollView);
    550 
    551     if (scrollView)
    552         initializePlugin();
    553 }
    554 
    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 
    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 
    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 
    617 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 
    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 
    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 
    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 
    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 
    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 
    766 void PluginView::addStream(Stream* stream)
    767 {
    768     ASSERT(!m_streams.contains(stream->streamID()));
    769     m_streams.set(stream->streamID(), stream);
    770 }
    771 
    772 void PluginView::removeStream(Stream* stream)
    773 {
    774     ASSERT(m_streams.get(stream->streamID()) == stream);
    775 
    776     m_streams.remove(stream->streamID());
    777 }
    778 
    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 
    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 
    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 
    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 
    848 void PluginView::mediaCanStart()
    849 {
    850     ASSERT(m_isWaitingUntilMediaCanStart);
    851     m_isWaitingUntilMediaCanStart = false;
    852 
    853     initializePlugin();
    854 }
    855 
    856 void PluginView::invalidate(const IntRect& dirtyRect)
    857 {
    858     invalidateRect(dirtyRect);
    859 }
    860 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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)
    992 HWND PluginView::nativeParentWindow()
    993 {
    994     return m_webPage->nativeWindow();
    995 }
    996 #endif
    997 
    998 #if PLATFORM(MAC)
    999 void PluginView::setComplexTextInputEnabled(bool complexTextInputEnabled)
   1000 {
   1001     m_webPage->send(Messages::WebPageProxy::SetComplexTextInputEnabled(m_plugin->pluginComplexTextInputIdentifier(), complexTextInputEnabled));
   1002 }
   1003 
   1004 mach_port_t PluginView::compositingRenderServerPort()
   1005 {
   1006     return WebProcess::shared().compositingRenderServerPort();
   1007 }
   1008 
   1009 #endif
   1010 
   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 
   1019 String PluginView::cookiesForURL(const String& urlString)
   1020 {
   1021     return cookies(m_pluginElement->document(), KURL(KURL(), urlString));
   1022 }
   1023 
   1024 void PluginView::setCookiesForURL(const String& urlString, const String& cookieString)
   1025 {
   1026     setCookies(m_pluginElement->document(), KURL(KURL(), urlString), cookieString);
   1027 }
   1028 
   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 
   1042 void PluginView::protectPluginFromDestruction()
   1043 {
   1044     if (!m_isBeingDestroyed)
   1045         ref();
   1046 }
   1047 
   1048 void PluginView::unprotectPluginFromDestruction()
   1049 {
   1050     if (!m_isBeingDestroyed)
   1051         deref();
   1052 }
   1053 
   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 
   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