• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 
26 #include "config.h"
27 #include "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