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
create(WebProcessConnection * connection,uint64_t pluginInstanceID,const String & userAgent,bool isPrivateBrowsingEnabled,bool isAcceleratedCompositingEnabled)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
PluginControllerProxy(WebProcessConnection * connection,uint64_t pluginInstanceID,const String & userAgent,bool isPrivateBrowsingEnabled,bool isAcceleratedCompositingEnabled)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
~PluginControllerProxy()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
initialize(const Plugin::Parameters & parameters)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
destroy()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
paint()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
startPaintTimer()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
invalidate(const IntRect & rect)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
userAgent()197 String PluginControllerProxy::userAgent()
198 {
199 return m_userAgent;
200 }
201
loadURL(uint64_t requestID,const String & method,const String & urlString,const String & target,const HTTPHeaderMap & headerFields,const Vector<uint8_t> & httpBody,bool allowPopups)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
cancelStreamLoad(uint64_t streamID)207 void PluginControllerProxy::cancelStreamLoad(uint64_t streamID)
208 {
209 m_connection->connection()->send(Messages::PluginProxy::CancelStreamLoad(streamID), m_pluginInstanceID);
210 }
211
cancelManualStreamLoad()212 void PluginControllerProxy::cancelManualStreamLoad()
213 {
214 m_pluginCanceledManualStreamLoad = true;
215
216 m_connection->connection()->send(Messages::PluginProxy::CancelManualStreamLoad(), m_pluginInstanceID);
217 }
218
windowScriptNPObject()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
pluginElementNPObject()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
evaluate(NPObject * npObject,const String & scriptString,NPVariant * result,bool allowPopups)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
setStatusbarText(const String & statusbarText)280 void PluginControllerProxy::setStatusbarText(const String& statusbarText)
281 {
282 m_connection->connection()->send(Messages::PluginProxy::SetStatusbarText(statusbarText), m_pluginInstanceID);
283 }
284
isAcceleratedCompositingEnabled()285 bool PluginControllerProxy::isAcceleratedCompositingEnabled()
286 {
287 return m_isAcceleratedCompositingEnabled;
288 }
289
pluginProcessCrashed()290 void PluginControllerProxy::pluginProcessCrashed()
291 {
292 // This should never be called from here.
293 ASSERT_NOT_REACHED();
294 }
295
296 #if PLATFORM(MAC)
setComplexTextInputEnabled(bool complexTextInputEnabled)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
compositingRenderServerPort()307 mach_port_t PluginControllerProxy::compositingRenderServerPort()
308 {
309 return PluginProcess::shared().compositingRenderServerPort();
310 }
311 #endif
312
proxiesForURL(const String & urlString)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
cookiesForURL(const String & urlString)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
setCookiesForURL(const String & urlString,const String & cookieString)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
isPrivateBrowsingEnabled()338 bool PluginControllerProxy::isPrivateBrowsingEnabled()
339 {
340 return m_isPrivateBrowsingEnabled;
341 }
342
protectPluginFromDestruction()343 void PluginControllerProxy::protectPluginFromDestruction()
344 {
345 m_pluginDestructionProtectCount++;
346 }
347
unprotectPluginFromDestruction()348 void PluginControllerProxy::unprotectPluginFromDestruction()
349 {
350 ASSERT(m_pluginDestructionProtectCount);
351
352 m_pluginDestructionProtectCount--;
353 }
354
frameDidFinishLoading(uint64_t requestID)355 void PluginControllerProxy::frameDidFinishLoading(uint64_t requestID)
356 {
357 m_plugin->frameDidFinishLoading(requestID);
358 }
359
frameDidFail(uint64_t requestID,bool wasCancelled)360 void PluginControllerProxy::frameDidFail(uint64_t requestID, bool wasCancelled)
361 {
362 m_plugin->frameDidFail(requestID, wasCancelled);
363 }
364
geometryDidChange(const IntRect & frameRect,const IntRect & clipRect,const ShareableBitmap::Handle & backingStoreHandle)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
didEvaluateJavaScript(uint64_t requestID,const String & requestURLString,const String & result)382 void PluginControllerProxy::didEvaluateJavaScript(uint64_t requestID, const String& requestURLString, const String& result)
383 {
384 m_plugin->didEvaluateJavaScript(requestID, requestURLString, result);
385 }
386
streamDidReceiveResponse(uint64_t streamID,const String & responseURLString,uint32_t streamLength,uint32_t lastModifiedTime,const String & mimeType,const String & headers)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
streamDidReceiveData(uint64_t streamID,const CoreIPC::DataReference & data)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
streamDidFinishLoading(uint64_t streamID)397 void PluginControllerProxy::streamDidFinishLoading(uint64_t streamID)
398 {
399 m_plugin->streamDidFinishLoading(streamID);
400 }
401
streamDidFail(uint64_t streamID,bool wasCancelled)402 void PluginControllerProxy::streamDidFail(uint64_t streamID, bool wasCancelled)
403 {
404 m_plugin->streamDidFail(streamID, wasCancelled);
405 }
406
manualStreamDidReceiveResponse(const String & responseURLString,uint32_t streamLength,uint32_t lastModifiedTime,const String & mimeType,const String & headers)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
manualStreamDidReceiveData(const CoreIPC::DataReference & data)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
manualStreamDidFinishLoading()423 void PluginControllerProxy::manualStreamDidFinishLoading()
424 {
425 if (m_pluginCanceledManualStreamLoad)
426 return;
427
428 m_plugin->manualStreamDidFinishLoading();
429 }
430
manualStreamDidFail(bool wasCancelled)431 void PluginControllerProxy::manualStreamDidFail(bool wasCancelled)
432 {
433 if (m_pluginCanceledManualStreamLoad)
434 return;
435
436 m_plugin->manualStreamDidFail(wasCancelled);
437 }
438
handleMouseEvent(const WebMouseEvent & mouseEvent,PassRefPtr<Messages::PluginControllerProxy::HandleMouseEvent::DelayedReply> reply)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
handleWheelEvent(const WebWheelEvent & wheelEvent,bool & handled)452 void PluginControllerProxy::handleWheelEvent(const WebWheelEvent& wheelEvent, bool& handled)
453 {
454 handled = m_plugin->handleWheelEvent(wheelEvent);
455 }
456
handleMouseEnterEvent(const WebMouseEvent & mouseEnterEvent,bool & handled)457 void PluginControllerProxy::handleMouseEnterEvent(const WebMouseEvent& mouseEnterEvent, bool& handled)
458 {
459 handled = m_plugin->handleMouseEnterEvent(mouseEnterEvent);
460 }
461
handleMouseLeaveEvent(const WebMouseEvent & mouseLeaveEvent,bool & handled)462 void PluginControllerProxy::handleMouseLeaveEvent(const WebMouseEvent& mouseLeaveEvent, bool& handled)
463 {
464 handled = m_plugin->handleMouseLeaveEvent(mouseLeaveEvent);
465 }
466
handleKeyboardEvent(const WebKeyboardEvent & keyboardEvent,bool & handled)467 void PluginControllerProxy::handleKeyboardEvent(const WebKeyboardEvent& keyboardEvent, bool& handled)
468 {
469 handled = m_plugin->handleKeyboardEvent(keyboardEvent);
470 }
471
paintEntirePlugin()472 void PluginControllerProxy::paintEntirePlugin()
473 {
474 if (m_frameRect.isEmpty())
475 return;
476
477 m_dirtyRect = m_frameRect;
478 paint();
479 }
480
snapshot(ShareableBitmap::Handle & backingStoreHandle)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
setFocus(bool hasFocus)491 void PluginControllerProxy::setFocus(bool hasFocus)
492 {
493 m_plugin->setFocus(hasFocus);
494 }
495
didUpdate()496 void PluginControllerProxy::didUpdate()
497 {
498 m_waitingForDidUpdate = false;
499 startPaintTimer();
500 }
501
getPluginScriptableNPObject(uint64_t & pluginScriptableNPObjectID)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
privateBrowsingStateChanged(bool isPrivateBrowsingEnabled)514 void PluginControllerProxy::privateBrowsingStateChanged(bool isPrivateBrowsingEnabled)
515 {
516 m_plugin->privateBrowsingStateChanged(isPrivateBrowsingEnabled);
517 }
518
519 } // namespace WebKit
520
521 #endif // ENABLE(PLUGIN_PROCESS)
522