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 "PluginProxy.h" 28 29 #if ENABLE(PLUGIN_PROCESS) 30 31 #include "DataReference.h" 32 #include "NPRemoteObjectMap.h" 33 #include "NPRuntimeUtilities.h" 34 #include "NPVariantData.h" 35 #include "PluginController.h" 36 #include "PluginControllerProxyMessages.h" 37 #include "PluginProcessConnection.h" 38 #include "PluginProcessConnectionManager.h" 39 #include "ShareableBitmap.h" 40 #include "WebCoreArgumentCoders.h" 41 #include "WebEvent.h" 42 #include "WebProcessConnectionMessages.h" 43 #include <WebCore/GraphicsContext.h> 44 45 using namespace WebCore; 46 47 namespace WebKit { 48 49 static uint64_t generatePluginInstanceID() 50 { 51 static uint64_t uniquePluginInstanceID; 52 return ++uniquePluginInstanceID; 53 } 54 55 PassRefPtr<PluginProxy> PluginProxy::create(const String& pluginPath) 56 { 57 return adoptRef(new PluginProxy(pluginPath)); 58 } 59 60 PluginProxy::PluginProxy(const String& pluginPath) 61 : m_pluginPath(pluginPath) 62 , m_pluginInstanceID(generatePluginInstanceID()) 63 , m_pluginController(0) 64 , m_pluginBackingStoreContainsValidData(false) 65 , m_isStarted(false) 66 , m_waitingForPaintInResponseToUpdate(false) 67 , m_remoteLayerClientID(0) 68 { 69 } 70 71 PluginProxy::~PluginProxy() 72 { 73 } 74 75 void PluginProxy::pluginProcessCrashed() 76 { 77 if (m_pluginController) 78 m_pluginController->pluginProcessCrashed(); 79 } 80 81 bool PluginProxy::initialize(PluginController* pluginController, const Parameters& parameters) 82 { 83 ASSERT(!m_pluginController); 84 ASSERT(pluginController); 85 86 m_pluginController = pluginController; 87 88 ASSERT(!m_connection); 89 m_connection = PluginProcessConnectionManager::shared().getPluginProcessConnection(m_pluginPath); 90 91 if (!m_connection) 92 return false; 93 94 // Add the plug-in proxy before creating the plug-in; it needs to be in the map because CreatePlugin 95 // can call back out to the plug-in proxy. 96 m_connection->addPluginProxy(this); 97 98 // Ask the plug-in process to create a plug-in. 99 bool result = false; 100 101 uint32_t remoteLayerClientID = 0; 102 if (!m_connection->connection()->sendSync(Messages::WebProcessConnection::CreatePlugin(m_pluginInstanceID, parameters, pluginController->userAgent(), pluginController->isPrivateBrowsingEnabled(), pluginController->isAcceleratedCompositingEnabled()), Messages::WebProcessConnection::CreatePlugin::Reply(result, remoteLayerClientID), 0) || !result) { 103 m_connection->removePluginProxy(this); 104 return false; 105 } 106 107 m_remoteLayerClientID = remoteLayerClientID; 108 m_isStarted = true; 109 110 return true; 111 } 112 113 void PluginProxy::destroy() 114 { 115 ASSERT(m_isStarted); 116 117 m_connection->connection()->sendSync(Messages::WebProcessConnection::DestroyPlugin(m_pluginInstanceID), Messages::WebProcessConnection::DestroyPlugin::Reply(), 0); 118 119 m_isStarted = false; 120 m_pluginController = 0; 121 122 m_connection->removePluginProxy(this); 123 } 124 125 void PluginProxy::paint(GraphicsContext* graphicsContext, const IntRect& dirtyRect) 126 { 127 if (!needsBackingStore() || !m_backingStore) 128 return; 129 130 if (!m_pluginBackingStoreContainsValidData) { 131 m_connection->connection()->sendSync(Messages::PluginControllerProxy::PaintEntirePlugin(), Messages::PluginControllerProxy::PaintEntirePlugin::Reply(), m_pluginInstanceID); 132 133 // Blit the plug-in backing store into our own backing store. 134 OwnPtr<WebCore::GraphicsContext> graphicsContext = m_backingStore->createGraphicsContext(); 135 graphicsContext->setCompositeOperation(CompositeCopy); 136 137 m_pluginBackingStore->paint(*graphicsContext, IntPoint(), IntRect(0, 0, m_frameRect.width(), m_frameRect.height())); 138 139 m_pluginBackingStoreContainsValidData = true; 140 } 141 142 IntRect dirtyRectInPluginCoordinates = dirtyRect; 143 dirtyRectInPluginCoordinates.move(-m_frameRect.x(), -m_frameRect.y()); 144 145 m_backingStore->paint(*graphicsContext, dirtyRect.location(), dirtyRectInPluginCoordinates); 146 147 if (m_waitingForPaintInResponseToUpdate) { 148 m_waitingForPaintInResponseToUpdate = false; 149 m_connection->connection()->send(Messages::PluginControllerProxy::DidUpdate(), m_pluginInstanceID); 150 return; 151 } 152 } 153 154 PassRefPtr<ShareableBitmap> PluginProxy::snapshot() 155 { 156 ShareableBitmap::Handle snapshotStoreHandle; 157 m_connection->connection()->sendSync(Messages::PluginControllerProxy::Snapshot(), Messages::PluginControllerProxy::Snapshot::Reply(snapshotStoreHandle), m_pluginInstanceID); 158 159 RefPtr<ShareableBitmap> snapshotBuffer = ShareableBitmap::create(snapshotStoreHandle); 160 return snapshotBuffer.release(); 161 } 162 163 bool PluginProxy::isTransparent() 164 { 165 // This should never be called from the web process. 166 ASSERT_NOT_REACHED(); 167 return false; 168 } 169 170 void PluginProxy::geometryDidChange(const IntRect& frameRect, const IntRect& clipRect) 171 { 172 ASSERT(m_isStarted); 173 174 m_frameRect = frameRect; 175 176 if (!needsBackingStore()) { 177 ShareableBitmap::Handle pluginBackingStoreHandle; 178 m_connection->connection()->send(Messages::PluginControllerProxy::GeometryDidChange(frameRect, clipRect, pluginBackingStoreHandle), m_pluginInstanceID, CoreIPC::DispatchMessageEvenWhenWaitingForSyncReply); 179 return; 180 } 181 182 bool didUpdateBackingStore = false; 183 if (!m_backingStore) { 184 m_backingStore = ShareableBitmap::create(frameRect.size(), ShareableBitmap::SupportsAlpha); 185 didUpdateBackingStore = true; 186 } else if (frameRect.size() != m_backingStore->size()) { 187 // The backing store already exists, just resize it. 188 if (!m_backingStore->resize(frameRect.size())) 189 return; 190 191 didUpdateBackingStore = true; 192 } 193 194 ShareableBitmap::Handle pluginBackingStoreHandle; 195 196 if (didUpdateBackingStore) { 197 // Create a new plug-in backing store. 198 m_pluginBackingStore = ShareableBitmap::createShareable(frameRect.size(), ShareableBitmap::SupportsAlpha); 199 if (!m_pluginBackingStore) 200 return; 201 202 // Create a handle to the plug-in backing store so we can send it over. 203 if (!m_pluginBackingStore->createHandle(pluginBackingStoreHandle)) { 204 m_pluginBackingStore = nullptr; 205 return; 206 } 207 208 m_pluginBackingStoreContainsValidData = false; 209 } 210 211 m_connection->connection()->send(Messages::PluginControllerProxy::GeometryDidChange(frameRect, clipRect, pluginBackingStoreHandle), m_pluginInstanceID, CoreIPC::DispatchMessageEvenWhenWaitingForSyncReply); 212 } 213 214 void PluginProxy::frameDidFinishLoading(uint64_t requestID) 215 { 216 m_connection->connection()->send(Messages::PluginControllerProxy::FrameDidFinishLoading(requestID), m_pluginInstanceID); 217 } 218 219 void PluginProxy::frameDidFail(uint64_t requestID, bool wasCancelled) 220 { 221 m_connection->connection()->send(Messages::PluginControllerProxy::FrameDidFail(requestID, wasCancelled), m_pluginInstanceID); 222 } 223 224 void PluginProxy::didEvaluateJavaScript(uint64_t requestID, const WTF::String& requestURLString, const WTF::String& result) 225 { 226 m_connection->connection()->send(Messages::PluginControllerProxy::DidEvaluateJavaScript(requestID, requestURLString, result), m_pluginInstanceID); 227 } 228 229 void PluginProxy::streamDidReceiveResponse(uint64_t streamID, const KURL& responseURL, uint32_t streamLength, uint32_t lastModifiedTime, const WTF::String& mimeType, const WTF::String& headers) 230 { 231 m_connection->connection()->send(Messages::PluginControllerProxy::StreamDidReceiveResponse(streamID, responseURL.string(), streamLength, lastModifiedTime, mimeType, headers), m_pluginInstanceID); 232 } 233 234 void PluginProxy::streamDidReceiveData(uint64_t streamID, const char* bytes, int length) 235 { 236 m_connection->connection()->send(Messages::PluginControllerProxy::StreamDidReceiveData(streamID, CoreIPC::DataReference(reinterpret_cast<const uint8_t*>(bytes), length)), m_pluginInstanceID); 237 } 238 239 void PluginProxy::streamDidFinishLoading(uint64_t streamID) 240 { 241 m_connection->connection()->send(Messages::PluginControllerProxy::StreamDidFinishLoading(streamID), m_pluginInstanceID); 242 } 243 244 void PluginProxy::streamDidFail(uint64_t streamID, bool wasCancelled) 245 { 246 m_connection->connection()->send(Messages::PluginControllerProxy::StreamDidFail(streamID, wasCancelled), m_pluginInstanceID); 247 } 248 249 void PluginProxy::manualStreamDidReceiveResponse(const KURL& responseURL, uint32_t streamLength, uint32_t lastModifiedTime, const WTF::String& mimeType, const WTF::String& headers) 250 { 251 m_connection->connection()->send(Messages::PluginControllerProxy::ManualStreamDidReceiveResponse(responseURL.string(), streamLength, lastModifiedTime, mimeType, headers), m_pluginInstanceID); 252 } 253 254 void PluginProxy::manualStreamDidReceiveData(const char* bytes, int length) 255 { 256 m_connection->connection()->send(Messages::PluginControllerProxy::ManualStreamDidReceiveData(CoreIPC::DataReference(reinterpret_cast<const uint8_t*>(bytes), length)), m_pluginInstanceID); 257 } 258 259 void PluginProxy::manualStreamDidFinishLoading() 260 { 261 m_connection->connection()->send(Messages::PluginControllerProxy::ManualStreamDidFinishLoading(), m_pluginInstanceID); 262 } 263 264 void PluginProxy::manualStreamDidFail(bool wasCancelled) 265 { 266 m_connection->connection()->send(Messages::PluginControllerProxy::ManualStreamDidFail(wasCancelled), m_pluginInstanceID); 267 } 268 269 bool PluginProxy::handleMouseEvent(const WebMouseEvent& mouseEvent) 270 { 271 bool handled = false; 272 if (!m_connection->connection()->sendSync(Messages::PluginControllerProxy::HandleMouseEvent(mouseEvent), Messages::PluginControllerProxy::HandleMouseEvent::Reply(handled), m_pluginInstanceID)) 273 return false; 274 275 return handled; 276 } 277 278 bool PluginProxy::handleWheelEvent(const WebWheelEvent& wheelEvent) 279 { 280 bool handled = false; 281 if (!m_connection->connection()->sendSync(Messages::PluginControllerProxy::HandleWheelEvent(wheelEvent), Messages::PluginControllerProxy::HandleWheelEvent::Reply(handled), m_pluginInstanceID)) 282 return false; 283 284 return handled; 285 } 286 287 bool PluginProxy::handleMouseEnterEvent(const WebMouseEvent& mouseEnterEvent) 288 { 289 bool handled = false; 290 if (!m_connection->connection()->sendSync(Messages::PluginControllerProxy::HandleMouseEnterEvent(mouseEnterEvent), Messages::PluginControllerProxy::HandleMouseEnterEvent::Reply(handled), m_pluginInstanceID)) 291 return false; 292 293 return handled; 294 } 295 296 bool PluginProxy::handleMouseLeaveEvent(const WebMouseEvent& mouseLeaveEvent) 297 { 298 bool handled = false; 299 if (!m_connection->connection()->sendSync(Messages::PluginControllerProxy::HandleMouseLeaveEvent(mouseLeaveEvent), Messages::PluginControllerProxy::HandleMouseLeaveEvent::Reply(handled), m_pluginInstanceID)) 300 return false; 301 302 return handled; 303 } 304 305 bool PluginProxy::handleKeyboardEvent(const WebKeyboardEvent& keyboardEvent) 306 { 307 bool handled = false; 308 if (!m_connection->connection()->sendSync(Messages::PluginControllerProxy::HandleKeyboardEvent(keyboardEvent), Messages::PluginControllerProxy::HandleKeyboardEvent::Reply(handled), m_pluginInstanceID)) 309 return false; 310 311 return handled; 312 } 313 314 void PluginProxy::setFocus(bool hasFocus) 315 { 316 m_connection->connection()->send(Messages::PluginControllerProxy::SetFocus(hasFocus), m_pluginInstanceID); 317 } 318 319 NPObject* PluginProxy::pluginScriptableNPObject() 320 { 321 uint64_t pluginScriptableNPObjectID = 0; 322 323 if (!m_connection->connection()->sendSync(Messages::PluginControllerProxy::GetPluginScriptableNPObject(), Messages::PluginControllerProxy::GetPluginScriptableNPObject::Reply(pluginScriptableNPObjectID), m_pluginInstanceID)) 324 return 0; 325 326 if (!pluginScriptableNPObjectID) 327 return 0; 328 329 return m_connection->npRemoteObjectMap()->createNPObjectProxy(pluginScriptableNPObjectID, this); 330 } 331 332 #if PLATFORM(MAC) 333 void PluginProxy::windowFocusChanged(bool hasFocus) 334 { 335 m_connection->connection()->send(Messages::PluginControllerProxy::WindowFocusChanged(hasFocus), m_pluginInstanceID); 336 } 337 338 void PluginProxy::windowAndViewFramesChanged(const WebCore::IntRect& windowFrameInScreenCoordinates, const WebCore::IntRect& viewFrameInWindowCoordinates) 339 { 340 m_connection->connection()->send(Messages::PluginControllerProxy::WindowAndViewFramesChanged(windowFrameInScreenCoordinates, viewFrameInWindowCoordinates), m_pluginInstanceID); 341 } 342 343 void PluginProxy::windowVisibilityChanged(bool isVisible) 344 { 345 m_connection->connection()->send(Messages::PluginControllerProxy::WindowVisibilityChanged(isVisible), m_pluginInstanceID); 346 } 347 348 uint64_t PluginProxy::pluginComplexTextInputIdentifier() const 349 { 350 return m_pluginInstanceID; 351 } 352 353 void PluginProxy::sendComplexTextInput(const String& textInput) 354 { 355 m_connection->connection()->send(Messages::PluginControllerProxy::SendComplexTextInput(textInput), m_pluginInstanceID); 356 } 357 358 #endif 359 360 void PluginProxy::privateBrowsingStateChanged(bool isPrivateBrowsingEnabled) 361 { 362 m_connection->connection()->send(Messages::PluginControllerProxy::PrivateBrowsingStateChanged(isPrivateBrowsingEnabled), m_pluginInstanceID); 363 } 364 365 PluginController* PluginProxy::controller() 366 { 367 return m_pluginController; 368 } 369 370 void PluginProxy::loadURL(uint64_t requestID, const String& method, const String& urlString, const String& target, const HTTPHeaderMap& headerFields, const Vector<uint8_t>& httpBody, bool allowPopups) 371 { 372 m_pluginController->loadURL(requestID, method, urlString, target, headerFields, httpBody, allowPopups); 373 } 374 375 void PluginProxy::proxiesForURL(const String& urlString, String& proxyString) 376 { 377 proxyString = m_pluginController->proxiesForURL(urlString); 378 } 379 380 void PluginProxy::cookiesForURL(const String& urlString, String& cookieString) 381 { 382 cookieString = m_pluginController->cookiesForURL(urlString); 383 } 384 385 void PluginProxy::setCookiesForURL(const String& urlString, const String& cookieString) 386 { 387 m_pluginController->setCookiesForURL(urlString, cookieString); 388 } 389 390 void PluginProxy::getWindowScriptNPObject(uint64_t& windowScriptNPObjectID) 391 { 392 NPObject* windowScriptNPObject = m_pluginController->windowScriptNPObject(); 393 if (!windowScriptNPObject) { 394 windowScriptNPObjectID = 0; 395 return; 396 } 397 398 windowScriptNPObjectID = m_connection->npRemoteObjectMap()->registerNPObject(windowScriptNPObject, this); 399 releaseNPObject(windowScriptNPObject); 400 } 401 402 void PluginProxy::getPluginElementNPObject(uint64_t& pluginElementNPObjectID) 403 { 404 NPObject* pluginElementNPObject = m_pluginController->pluginElementNPObject(); 405 if (!pluginElementNPObject) { 406 pluginElementNPObjectID = 0; 407 return; 408 } 409 410 pluginElementNPObjectID = m_connection->npRemoteObjectMap()->registerNPObject(pluginElementNPObject, this); 411 releaseNPObject(pluginElementNPObject); 412 } 413 414 void PluginProxy::evaluate(const NPVariantData& npObjectAsVariantData, const String& scriptString, bool allowPopups, bool& returnValue, NPVariantData& resultData) 415 { 416 PluginController::PluginDestructionProtector protector(m_pluginController); 417 418 NPVariant npObjectAsVariant = m_connection->npRemoteObjectMap()->npVariantDataToNPVariant(npObjectAsVariantData, this); 419 if (!NPVARIANT_IS_OBJECT(npObjectAsVariant) || !(NPVARIANT_TO_OBJECT(npObjectAsVariant))) { 420 returnValue = false; 421 return; 422 } 423 424 NPVariant result; 425 returnValue = m_pluginController->evaluate(NPVARIANT_TO_OBJECT(npObjectAsVariant), scriptString, &result, allowPopups); 426 if (!returnValue) 427 return; 428 429 // Convert the NPVariant to an NPVariantData. 430 resultData = m_connection->npRemoteObjectMap()->npVariantToNPVariantData(result, this); 431 432 // And release the result. 433 releaseNPVariantValue(&result); 434 435 releaseNPVariantValue(&npObjectAsVariant); 436 } 437 438 void PluginProxy::cancelStreamLoad(uint64_t streamID) 439 { 440 m_pluginController->cancelStreamLoad(streamID); 441 } 442 443 void PluginProxy::cancelManualStreamLoad() 444 { 445 m_pluginController->cancelManualStreamLoad(); 446 } 447 448 void PluginProxy::setStatusbarText(const String& statusbarText) 449 { 450 m_pluginController->setStatusbarText(statusbarText); 451 } 452 453 #if PLATFORM(MAC) 454 void PluginProxy::setComplexTextInputEnabled(bool complexTextInputEnabled) 455 { 456 m_pluginController->setComplexTextInputEnabled(complexTextInputEnabled); 457 } 458 #endif 459 460 void PluginProxy::update(const IntRect& paintedRect) 461 { 462 if (paintedRect == m_frameRect) 463 m_pluginBackingStoreContainsValidData = true; 464 465 IntRect paintedRectPluginCoordinates = paintedRect; 466 paintedRectPluginCoordinates.move(-m_frameRect.x(), -m_frameRect.y()); 467 468 if (m_backingStore) { 469 // Blit the plug-in backing store into our own backing store. 470 OwnPtr<GraphicsContext> graphicsContext = m_backingStore->createGraphicsContext(); 471 graphicsContext->setCompositeOperation(CompositeCopy); 472 m_pluginBackingStore->paint(*graphicsContext, paintedRectPluginCoordinates.location(), 473 paintedRectPluginCoordinates); 474 } 475 476 // Ask the controller to invalidate the rect for us. 477 m_waitingForPaintInResponseToUpdate = true; 478 m_pluginController->invalidate(paintedRectPluginCoordinates); 479 } 480 481 } // namespace WebKit 482 483 #endif // ENABLE(PLUGIN_PROCESS) 484