Home | History | Annotate | Download | only in PluginProcess
      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 "PluginControllerProxy.h"
     28 
     29 #if ENABLE(PLUGIN_PROCESS)
     30 
     31 #include "DataReference.h"
     32 #include "NPObjectProxy.h"
     33 #include "NPRemoteObjectMap.h"
     34 #include "NPRuntimeUtilities.h"
     35 #include "NPVariantData.h"
     36 #include "NetscapePlugin.h"
     37 #include "PluginProcess.h"
     38 #include "PluginProxyMessages.h"
     39 #include "ShareableBitmap.h"
     40 #include "WebCoreArgumentCoders.h"
     41 #include "WebProcessConnection.h"
     42 #include <WebCore/GraphicsContext.h>
     43 #include <wtf/text/WTFString.h>
     44 
     45 using namespace WebCore;
     46 
     47 namespace WebKit {
     48 
     49 PassOwnPtr<PluginControllerProxy> PluginControllerProxy::create(WebProcessConnection* connection, uint64_t pluginInstanceID, const String& userAgent, bool isPrivateBrowsingEnabled, bool isAcceleratedCompositingEnabled)
     50 {
     51     return adoptPtr(new PluginControllerProxy(connection, pluginInstanceID, userAgent, isPrivateBrowsingEnabled, isAcceleratedCompositingEnabled));
     52 }
     53 
     54 PluginControllerProxy::PluginControllerProxy(WebProcessConnection* connection, uint64_t pluginInstanceID, const String& userAgent, bool isPrivateBrowsingEnabled, bool isAcceleratedCompositingEnabled)
     55     : m_connection(connection)
     56     , m_pluginInstanceID(pluginInstanceID)
     57     , m_userAgent(userAgent)
     58     , m_isPrivateBrowsingEnabled(isPrivateBrowsingEnabled)
     59     , m_isAcceleratedCompositingEnabled(isAcceleratedCompositingEnabled)
     60     , m_paintTimer(RunLoop::main(), this, &PluginControllerProxy::paint)
     61     , m_pluginDestructionProtectCount(0)
     62     , m_pluginDestroyTimer(RunLoop::main(), this, &PluginControllerProxy::destroy)
     63     , m_waitingForDidUpdate(false)
     64     , m_pluginCanceledManualStreamLoad(false)
     65 #if PLATFORM(MAC)
     66     , m_isComplexTextInputEnabled(false)
     67 #endif
     68     , m_windowNPObject(0)
     69     , m_pluginElementNPObject(0)
     70 {
     71 }
     72 
     73 PluginControllerProxy::~PluginControllerProxy()
     74 {
     75     ASSERT(!m_plugin);
     76 
     77     if (m_windowNPObject)
     78         releaseNPObject(m_windowNPObject);
     79 
     80     if (m_pluginElementNPObject)
     81         releaseNPObject(m_pluginElementNPObject);
     82 }
     83 
     84 bool PluginControllerProxy::initialize(const Plugin::Parameters& parameters)
     85 {
     86     ASSERT(!m_plugin);
     87 
     88     m_plugin = NetscapePlugin::create(PluginProcess::shared().netscapePluginModule());
     89     if (!m_plugin) {
     90         // This will delete the plug-in controller proxy object.
     91         m_connection->removePluginControllerProxy(this, 0);
     92         return false;
     93     }
     94 
     95     if (!m_plugin->initialize(this, parameters)) {
     96         // Get the plug-in so we can pass it to removePluginControllerProxy. The pointer is only
     97         // used as an identifier so it's OK to just get a weak reference.
     98         Plugin* plugin = m_plugin.get();
     99 
    100         m_plugin = 0;
    101 
    102         // This will delete the plug-in controller proxy object.
    103         m_connection->removePluginControllerProxy(this, plugin);
    104         return false;
    105     }
    106 
    107     platformInitialize();
    108 
    109     return true;
    110 }
    111 
    112 void PluginControllerProxy::destroy()
    113 {
    114     ASSERT(m_plugin);
    115 
    116     if (m_pluginDestructionProtectCount) {
    117         // We have plug-in code on the stack so we can't destroy it right now.
    118         // Destroy it later.
    119         m_pluginDestroyTimer.startOneShot(0);
    120         return;
    121     }
    122 
    123     // Get the plug-in so we can pass it to removePluginControllerProxy. The pointer is only
    124     // used as an identifier so it's OK to just get a weak reference.
    125     Plugin* plugin = m_plugin.get();
    126 
    127     m_plugin->destroy();
    128     m_plugin = 0;
    129 
    130     platformDestroy();
    131 
    132     // This will delete the plug-in controller proxy object.
    133     m_connection->removePluginControllerProxy(this, plugin);
    134 }
    135 
    136 void PluginControllerProxy::paint()
    137 {
    138     ASSERT(!m_dirtyRect.isEmpty());
    139     m_paintTimer.stop();
    140 
    141     if (!m_backingStore)
    142         return;
    143 
    144     IntRect dirtyRect = m_dirtyRect;
    145     m_dirtyRect = IntRect();
    146 
    147     ASSERT(m_plugin);
    148 
    149     // Create a graphics context.
    150     OwnPtr<GraphicsContext> graphicsContext = m_backingStore->createGraphicsContext();
    151 
    152     graphicsContext->translate(-m_frameRect.x(), -m_frameRect.y());
    153 
    154     if (m_plugin->isTransparent())
    155         graphicsContext->clearRect(dirtyRect);
    156 
    157     m_plugin->paint(graphicsContext.get(), dirtyRect);
    158 
    159     m_connection->connection()->send(Messages::PluginProxy::Update(dirtyRect), m_pluginInstanceID);
    160 }
    161 
    162 void PluginControllerProxy::startPaintTimer()
    163 {
    164     // Check if we should start the timer.
    165 
    166     if (m_dirtyRect.isEmpty())
    167         return;
    168 
    169     // FIXME: Check clip rect.
    170 
    171     if (m_paintTimer.isActive())
    172         return;
    173 
    174     if (m_waitingForDidUpdate)
    175         return;
    176 
    177     // Start the timer.
    178     m_paintTimer.startOneShot(0);
    179 
    180     m_waitingForDidUpdate = true;
    181 }
    182 
    183 void PluginControllerProxy::invalidate(const IntRect& rect)
    184 {
    185     // Convert the dirty rect to window coordinates.
    186     IntRect dirtyRect = rect;
    187     dirtyRect.move(m_frameRect.x(), m_frameRect.y());
    188 
    189     // Make sure that the dirty rect is not greater than the plug-in itself.
    190     dirtyRect.intersect(m_frameRect);
    191 
    192     m_dirtyRect.unite(dirtyRect);
    193 
    194     startPaintTimer();
    195 }
    196 
    197 String PluginControllerProxy::userAgent()
    198 {
    199     return m_userAgent;
    200 }
    201 
    202 void PluginControllerProxy::loadURL(uint64_t requestID, const String& method, const String& urlString, const String& target, const HTTPHeaderMap& headerFields, const Vector<uint8_t>& httpBody, bool allowPopups)
    203 {
    204     m_connection->connection()->send(Messages::PluginProxy::LoadURL(requestID, method, urlString, target, headerFields, httpBody, allowPopups), m_pluginInstanceID);
    205 }
    206 
    207 void PluginControllerProxy::cancelStreamLoad(uint64_t streamID)
    208 {
    209     m_connection->connection()->send(Messages::PluginProxy::CancelStreamLoad(streamID), m_pluginInstanceID);
    210 }
    211 
    212 void PluginControllerProxy::cancelManualStreamLoad()
    213 {
    214     m_pluginCanceledManualStreamLoad = true;
    215 
    216     m_connection->connection()->send(Messages::PluginProxy::CancelManualStreamLoad(), m_pluginInstanceID);
    217 }
    218 
    219 NPObject* PluginControllerProxy::windowScriptNPObject()
    220 {
    221     if (!m_windowNPObject) {
    222         uint64_t windowScriptNPObjectID = 0;
    223 
    224         if (!m_connection->connection()->sendSync(Messages::PluginProxy::GetWindowScriptNPObject(), Messages::PluginProxy::GetWindowScriptNPObject::Reply(windowScriptNPObjectID), m_pluginInstanceID))
    225             return 0;
    226 
    227         if (!windowScriptNPObjectID)
    228             return 0;
    229 
    230         m_windowNPObject = m_connection->npRemoteObjectMap()->createNPObjectProxy(windowScriptNPObjectID, m_plugin.get());
    231         ASSERT(m_windowNPObject);
    232     }
    233 
    234     retainNPObject(m_windowNPObject);
    235     return m_windowNPObject;
    236 }
    237 
    238 NPObject* PluginControllerProxy::pluginElementNPObject()
    239 {
    240     if (!m_pluginElementNPObject) {
    241         uint64_t pluginElementNPObjectID = 0;
    242 
    243         if (!m_connection->connection()->sendSync(Messages::PluginProxy::GetPluginElementNPObject(), Messages::PluginProxy::GetPluginElementNPObject::Reply(pluginElementNPObjectID), m_pluginInstanceID))
    244             return 0;
    245 
    246         if (!pluginElementNPObjectID)
    247             return 0;
    248 
    249         m_pluginElementNPObject = m_connection->npRemoteObjectMap()->createNPObjectProxy(pluginElementNPObjectID, m_plugin.get());
    250         ASSERT(m_pluginElementNPObject);
    251     }
    252 
    253     retainNPObject(m_pluginElementNPObject);
    254     return m_pluginElementNPObject;
    255 }
    256 
    257 bool PluginControllerProxy::evaluate(NPObject* npObject, const String& scriptString, NPVariant* result, bool allowPopups)
    258 {
    259     PluginDestructionProtector protector(this);
    260 
    261     NPVariant npObjectAsNPVariant;
    262     OBJECT_TO_NPVARIANT(npObject, npObjectAsNPVariant);
    263 
    264     // Send the NPObject over as an NPVariantData.
    265     NPVariantData npObjectAsNPVariantData = m_connection->npRemoteObjectMap()->npVariantToNPVariantData(npObjectAsNPVariant, m_plugin.get());
    266 
    267     bool returnValue = false;
    268     NPVariantData resultData;
    269 
    270     if (!m_connection->connection()->sendSync(Messages::PluginProxy::Evaluate(npObjectAsNPVariantData, scriptString, allowPopups), Messages::PluginProxy::Evaluate::Reply(returnValue, resultData), m_pluginInstanceID))
    271         return false;
    272 
    273     if (!returnValue)
    274         return false;
    275 
    276     *result = m_connection->npRemoteObjectMap()->npVariantDataToNPVariant(resultData, m_plugin.get());
    277     return true;
    278 }
    279 
    280 void PluginControllerProxy::setStatusbarText(const String& statusbarText)
    281 {
    282     m_connection->connection()->send(Messages::PluginProxy::SetStatusbarText(statusbarText), m_pluginInstanceID);
    283 }
    284 
    285 bool PluginControllerProxy::isAcceleratedCompositingEnabled()
    286 {
    287     return m_isAcceleratedCompositingEnabled;
    288 }
    289 
    290 void PluginControllerProxy::pluginProcessCrashed()
    291 {
    292     // This should never be called from here.
    293     ASSERT_NOT_REACHED();
    294 }
    295 
    296 #if PLATFORM(MAC)
    297 void PluginControllerProxy::setComplexTextInputEnabled(bool complexTextInputEnabled)
    298 {
    299     if (m_isComplexTextInputEnabled == complexTextInputEnabled)
    300         return;
    301 
    302     m_isComplexTextInputEnabled = complexTextInputEnabled;
    303 
    304     m_connection->connection()->send(Messages::PluginProxy::SetComplexTextInputEnabled(complexTextInputEnabled), m_pluginInstanceID);
    305 }
    306 
    307 mach_port_t PluginControllerProxy::compositingRenderServerPort()
    308 {
    309     return PluginProcess::shared().compositingRenderServerPort();
    310 }
    311 #endif
    312 
    313 String PluginControllerProxy::proxiesForURL(const String& urlString)
    314 {
    315     String proxyString;
    316 
    317     if (!m_connection->connection()->sendSync(Messages::PluginProxy::CookiesForURL(urlString), Messages::PluginProxy::CookiesForURL::Reply(proxyString), m_pluginInstanceID))
    318         return String();
    319 
    320     return proxyString;
    321 }
    322 
    323 String PluginControllerProxy::cookiesForURL(const String& urlString)
    324 {
    325     String cookieString;
    326 
    327     if (!m_connection->connection()->sendSync(Messages::PluginProxy::CookiesForURL(urlString), Messages::PluginProxy::CookiesForURL::Reply(cookieString), m_pluginInstanceID))
    328         return String();
    329 
    330     return cookieString;
    331 }
    332 
    333 void PluginControllerProxy::setCookiesForURL(const String& urlString, const String& cookieString)
    334 {
    335     m_connection->connection()->send(Messages::PluginProxy::SetCookiesForURL(urlString, cookieString), m_pluginInstanceID);
    336 }
    337 
    338 bool PluginControllerProxy::isPrivateBrowsingEnabled()
    339 {
    340     return m_isPrivateBrowsingEnabled;
    341 }
    342 
    343 void PluginControllerProxy::protectPluginFromDestruction()
    344 {
    345     m_pluginDestructionProtectCount++;
    346 }
    347 
    348 void PluginControllerProxy::unprotectPluginFromDestruction()
    349 {
    350     ASSERT(m_pluginDestructionProtectCount);
    351 
    352     m_pluginDestructionProtectCount--;
    353 }
    354 
    355 void PluginControllerProxy::frameDidFinishLoading(uint64_t requestID)
    356 {
    357     m_plugin->frameDidFinishLoading(requestID);
    358 }
    359 
    360 void PluginControllerProxy::frameDidFail(uint64_t requestID, bool wasCancelled)
    361 {
    362     m_plugin->frameDidFail(requestID, wasCancelled);
    363 }
    364 
    365 void PluginControllerProxy::geometryDidChange(const IntRect& frameRect, const IntRect& clipRect, const ShareableBitmap::Handle& backingStoreHandle)
    366 {
    367     m_frameRect = frameRect;
    368     m_clipRect = clipRect;
    369 
    370     ASSERT(m_plugin);
    371 
    372     platformGeometryDidChange();
    373 
    374     if (!backingStoreHandle.isNull()) {
    375         // Create a new backing store.
    376         m_backingStore = ShareableBitmap::create(backingStoreHandle);
    377     }
    378 
    379     m_plugin->geometryDidChange(frameRect, clipRect);
    380 }
    381 
    382 void PluginControllerProxy::didEvaluateJavaScript(uint64_t requestID, const String& requestURLString, const String& result)
    383 {
    384     m_plugin->didEvaluateJavaScript(requestID, requestURLString, result);
    385 }
    386 
    387 void PluginControllerProxy::streamDidReceiveResponse(uint64_t streamID, const String& responseURLString, uint32_t streamLength, uint32_t lastModifiedTime, const String& mimeType, const String& headers)
    388 {
    389     m_plugin->streamDidReceiveResponse(streamID, KURL(ParsedURLString, responseURLString), streamLength, lastModifiedTime, mimeType, headers);
    390 }
    391 
    392 void PluginControllerProxy::streamDidReceiveData(uint64_t streamID, const CoreIPC::DataReference& data)
    393 {
    394     m_plugin->streamDidReceiveData(streamID, reinterpret_cast<const char*>(data.data()), data.size());
    395 }
    396 
    397 void PluginControllerProxy::streamDidFinishLoading(uint64_t streamID)
    398 {
    399     m_plugin->streamDidFinishLoading(streamID);
    400 }
    401 
    402 void PluginControllerProxy::streamDidFail(uint64_t streamID, bool wasCancelled)
    403 {
    404     m_plugin->streamDidFail(streamID, wasCancelled);
    405 }
    406 
    407 void PluginControllerProxy::manualStreamDidReceiveResponse(const String& responseURLString, uint32_t streamLength, uint32_t lastModifiedTime, const String& mimeType, const String& headers)
    408 {
    409     if (m_pluginCanceledManualStreamLoad)
    410         return;
    411 
    412     m_plugin->manualStreamDidReceiveResponse(KURL(ParsedURLString, responseURLString), streamLength, lastModifiedTime, mimeType, headers);
    413 }
    414 
    415 void PluginControllerProxy::manualStreamDidReceiveData(const CoreIPC::DataReference& data)
    416 {
    417     if (m_pluginCanceledManualStreamLoad)
    418         return;
    419 
    420     m_plugin->manualStreamDidReceiveData(reinterpret_cast<const char*>(data.data()), data.size());
    421 }
    422 
    423 void PluginControllerProxy::manualStreamDidFinishLoading()
    424 {
    425     if (m_pluginCanceledManualStreamLoad)
    426         return;
    427 
    428     m_plugin->manualStreamDidFinishLoading();
    429 }
    430 
    431 void PluginControllerProxy::manualStreamDidFail(bool wasCancelled)
    432 {
    433     if (m_pluginCanceledManualStreamLoad)
    434         return;
    435 
    436     m_plugin->manualStreamDidFail(wasCancelled);
    437 }
    438 
    439 void PluginControllerProxy::handleMouseEvent(const WebMouseEvent& mouseEvent, PassRefPtr<Messages::PluginControllerProxy::HandleMouseEvent::DelayedReply> reply)
    440 {
    441     // Always let the web process think that we've handled this mouse event, even before passing it along to the plug-in.
    442     // This is a workaround for
    443     // <rdar://problem/9299901> UI process thinks the page is unresponsive when a plug-in is showing a context menu.
    444     // The web process sends a synchronous HandleMouseEvent message and the plug-in process spawns a nested
    445     // run loop when showing the context menu, so eventually the unresponsiveness timer kicks in in the UI process.
    446     // FIXME: We should come up with a better way to do this.
    447     reply->send(true);
    448 
    449     m_plugin->handleMouseEvent(mouseEvent);
    450 }
    451 
    452 void PluginControllerProxy::handleWheelEvent(const WebWheelEvent& wheelEvent, bool& handled)
    453 {
    454     handled = m_plugin->handleWheelEvent(wheelEvent);
    455 }
    456 
    457 void PluginControllerProxy::handleMouseEnterEvent(const WebMouseEvent& mouseEnterEvent, bool& handled)
    458 {
    459     handled = m_plugin->handleMouseEnterEvent(mouseEnterEvent);
    460 }
    461 
    462 void PluginControllerProxy::handleMouseLeaveEvent(const WebMouseEvent& mouseLeaveEvent, bool& handled)
    463 {
    464     handled = m_plugin->handleMouseLeaveEvent(mouseLeaveEvent);
    465 }
    466 
    467 void PluginControllerProxy::handleKeyboardEvent(const WebKeyboardEvent& keyboardEvent, bool& handled)
    468 {
    469     handled = m_plugin->handleKeyboardEvent(keyboardEvent);
    470 }
    471 
    472 void PluginControllerProxy::paintEntirePlugin()
    473 {
    474     if (m_frameRect.isEmpty())
    475         return;
    476 
    477     m_dirtyRect = m_frameRect;
    478     paint();
    479 }
    480 
    481 void PluginControllerProxy::snapshot(ShareableBitmap::Handle& backingStoreHandle)
    482 {
    483     ASSERT(m_plugin);
    484     RefPtr<ShareableBitmap> bitmap = m_plugin->snapshot();
    485     if (!bitmap)
    486         return;
    487 
    488     bitmap->createHandle(backingStoreHandle);
    489 }
    490 
    491 void PluginControllerProxy::setFocus(bool hasFocus)
    492 {
    493     m_plugin->setFocus(hasFocus);
    494 }
    495 
    496 void PluginControllerProxy::didUpdate()
    497 {
    498     m_waitingForDidUpdate = false;
    499     startPaintTimer();
    500 }
    501 
    502 void PluginControllerProxy::getPluginScriptableNPObject(uint64_t& pluginScriptableNPObjectID)
    503 {
    504     NPObject* pluginScriptableNPObject = m_plugin->pluginScriptableNPObject();
    505     if (!pluginScriptableNPObject) {
    506         pluginScriptableNPObjectID = 0;
    507         return;
    508     }
    509 
    510     pluginScriptableNPObjectID = m_connection->npRemoteObjectMap()->registerNPObject(pluginScriptableNPObject, m_plugin.get());
    511     releaseNPObject(pluginScriptableNPObject);
    512 }
    513 
    514 void PluginControllerProxy::privateBrowsingStateChanged(bool isPrivateBrowsingEnabled)
    515 {
    516     m_plugin->privateBrowsingStateChanged(isPrivateBrowsingEnabled);
    517 }
    518 
    519 } // namespace WebKit
    520 
    521 #endif // ENABLE(PLUGIN_PROCESS)
    522