|
1 /* |
|
2 * Copyright (C) 2008, 2009, 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. ``AS IS'' AND ANY |
|
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
|
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
|
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR |
|
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
|
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
|
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
|
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
|
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
24 */ |
|
25 |
|
26 #if USE(PLUGIN_HOST_PROCESS) |
|
27 |
|
28 #ifndef NetscapePluginInstanceProxy_h |
|
29 #define NetscapePluginInstanceProxy_h |
|
30 |
|
31 #include <JavaScriptCore/Protect.h> |
|
32 #include <WebCore/Timer.h> |
|
33 #include <WebKit/npapi.h> |
|
34 #include <wtf/Deque.h> |
|
35 #include <wtf/HashMap.h> |
|
36 #include <wtf/PassRefPtr.h> |
|
37 #include <wtf/RefCounted.h> |
|
38 #include <wtf/RetainPtr.h> |
|
39 #include "WebKitPluginHostTypes.h" |
|
40 |
|
41 namespace WebCore { |
|
42 class String; |
|
43 } |
|
44 |
|
45 namespace JSC { |
|
46 namespace Bindings { |
|
47 class Instance; |
|
48 class RootObject; |
|
49 } |
|
50 class ArgList; |
|
51 } |
|
52 @class WebHostedNetscapePluginView; |
|
53 @class WebFrame; |
|
54 |
|
55 namespace WebKit { |
|
56 |
|
57 class HostedNetscapePluginStream; |
|
58 class NetscapePluginHostProxy; |
|
59 class PluginRequest; |
|
60 class ProxyInstance; |
|
61 |
|
62 class NetscapePluginInstanceProxy : public RefCounted<NetscapePluginInstanceProxy> { |
|
63 public: |
|
64 static PassRefPtr<NetscapePluginInstanceProxy> create(NetscapePluginHostProxy*, WebHostedNetscapePluginView *, bool fullFramePlugin); |
|
65 ~NetscapePluginInstanceProxy(); |
|
66 |
|
67 uint32_t pluginID() const |
|
68 { |
|
69 ASSERT(m_pluginID); |
|
70 |
|
71 return m_pluginID; |
|
72 } |
|
73 uint32_t renderContextID() const { ASSERT(fastMallocSize(this)); return m_renderContextID; } |
|
74 void setRenderContextID(uint32_t renderContextID) { m_renderContextID = renderContextID; } |
|
75 |
|
76 RendererType rendererType() const { return m_rendererType; } |
|
77 void setRendererType(RendererType rendererType) { m_rendererType = rendererType; } |
|
78 |
|
79 WebHostedNetscapePluginView *pluginView() const { ASSERT(fastMallocSize(this)); return m_pluginView; } |
|
80 NetscapePluginHostProxy* hostProxy() const { ASSERT(fastMallocSize(this)); return m_pluginHostProxy; } |
|
81 |
|
82 bool cancelStreamLoad(uint32_t streamID, NPReason); |
|
83 void disconnectStream(HostedNetscapePluginStream*); |
|
84 |
|
85 void setManualStream(PassRefPtr<HostedNetscapePluginStream>); |
|
86 HostedNetscapePluginStream* manualStream() const { return m_manualStream.get(); } |
|
87 |
|
88 void pluginHostDied(); |
|
89 |
|
90 void resize(NSRect size, NSRect clipRect); |
|
91 void destroy(); |
|
92 void focusChanged(bool hasFocus); |
|
93 void windowFocusChanged(bool hasFocus); |
|
94 void windowFrameChanged(NSRect frame); |
|
95 |
|
96 void mouseEvent(NSView *pluginView, NSEvent *, NPCocoaEventType); |
|
97 void keyEvent(NSView *pluginView, NSEvent *, NPCocoaEventType); |
|
98 void insertText(NSString *); |
|
99 bool wheelEvent(NSView *pluginView, NSEvent *); |
|
100 void syntheticKeyDownWithCommandModifier(int keyCode, char character); |
|
101 void flagsChanged(NSEvent *); |
|
102 void print(CGContextRef, unsigned width, unsigned height); |
|
103 void snapshot(CGContextRef, unsigned width, unsigned height); |
|
104 |
|
105 void startTimers(bool throttleTimers); |
|
106 void stopTimers(); |
|
107 |
|
108 void invalidateRect(double x, double y, double width, double height); |
|
109 |
|
110 // NPRuntime |
|
111 bool getWindowNPObject(uint32_t& objectID); |
|
112 bool getPluginElementNPObject(uint32_t& objectID); |
|
113 bool forgetBrowserObjectID(uint32_t objectID); // Will fail if the ID is being sent to plug-in right now (i.e., retain/release calls aren't balanced). |
|
114 |
|
115 bool evaluate(uint32_t objectID, const WebCore::String& script, data_t& resultData, mach_msg_type_number_t& resultLength, bool allowPopups); |
|
116 bool invoke(uint32_t objectID, const JSC::Identifier& methodName, data_t argumentsData, mach_msg_type_number_t argumentsLength, data_t& resultData, mach_msg_type_number_t& resultLength); |
|
117 bool invokeDefault(uint32_t objectID, data_t argumentsData, mach_msg_type_number_t argumentsLength, data_t& resultData, mach_msg_type_number_t& resultLength); |
|
118 bool construct(uint32_t objectID, data_t argumentsData, mach_msg_type_number_t argumentsLength, data_t& resultData, mach_msg_type_number_t& resultLength); |
|
119 bool enumerate(uint32_t objectID, data_t& resultData, mach_msg_type_number_t& resultLength); |
|
120 |
|
121 bool getProperty(uint32_t objectID, const JSC::Identifier& propertyName, data_t &resultData, mach_msg_type_number_t& resultLength); |
|
122 bool getProperty(uint32_t objectID, unsigned propertyName, data_t &resultData, mach_msg_type_number_t& resultLength); |
|
123 bool setProperty(uint32_t objectID, const JSC::Identifier& propertyName, data_t valueData, mach_msg_type_number_t valueLength); |
|
124 bool setProperty(uint32_t objectID, unsigned propertyName, data_t valueData, mach_msg_type_number_t valueLength); |
|
125 bool removeProperty(uint32_t objectID, const JSC::Identifier& propertyName); |
|
126 bool removeProperty(uint32_t objectID, unsigned propertyName); |
|
127 bool hasProperty(uint32_t objectID, const JSC::Identifier& propertyName); |
|
128 bool hasProperty(uint32_t objectID, unsigned propertyName); |
|
129 bool hasMethod(uint32_t objectID, const JSC::Identifier& methodName); |
|
130 |
|
131 void status(const char* message); |
|
132 NPError loadURL(const char* url, const char* target, const char* postData, uint32_t postDataLength, LoadURLFlags, uint32_t& requestID); |
|
133 |
|
134 bool getCookies(data_t urlData, mach_msg_type_number_t urlLength, data_t& cookiesData, mach_msg_type_number_t& cookiesLength); |
|
135 bool setCookies(data_t urlData, mach_msg_type_number_t urlLength, data_t cookiesData, mach_msg_type_number_t cookiesLength); |
|
136 |
|
137 bool getProxy(data_t urlData, mach_msg_type_number_t urlLength, data_t& proxyData, mach_msg_type_number_t& proxyLength); |
|
138 bool getAuthenticationInfo(data_t protocolData, data_t hostData, uint32_t port, data_t schemeData, data_t realmData, |
|
139 data_t& usernameData, mach_msg_type_number_t& usernameLength, data_t& passwordData, mach_msg_type_number_t& passwordLength); |
|
140 bool convertPoint(double sourceX, double sourceY, NPCoordinateSpace sourceSpace, |
|
141 double& destX, double& destY, NPCoordinateSpace destSpace); |
|
142 |
|
143 PassRefPtr<JSC::Bindings::Instance> createBindingsInstance(PassRefPtr<JSC::Bindings::RootObject>); |
|
144 RetainPtr<NSData *> marshalValues(JSC::ExecState*, const JSC::ArgList& args); |
|
145 void marshalValue(JSC::ExecState*, JSC::JSValue, data_t& resultData, mach_msg_type_number_t& resultLength); |
|
146 JSC::JSValue demarshalValue(JSC::ExecState*, const char* valueData, mach_msg_type_number_t valueLength); |
|
147 |
|
148 // No-op if the value does not contain a local object. |
|
149 void retainLocalObject(JSC::JSValue); |
|
150 void releaseLocalObject(JSC::JSValue); |
|
151 |
|
152 void addInstance(ProxyInstance*); |
|
153 void removeInstance(ProxyInstance*); |
|
154 |
|
155 void cleanup(); |
|
156 void invalidate(); |
|
157 |
|
158 void willCallPluginFunction(); |
|
159 void didCallPluginFunction(); |
|
160 bool shouldStop(); |
|
161 |
|
162 uint32_t nextRequestID(); |
|
163 |
|
164 uint32_t checkIfAllowedToLoadURL(const char* url, const char* target); |
|
165 void cancelCheckIfAllowedToLoadURL(uint32_t checkID); |
|
166 void checkIfAllowedToLoadURLResult(uint32_t checkID, bool allowed); |
|
167 |
|
168 void resolveURL(const char* url, const char* target, data_t& resolvedURLData, mach_msg_type_number_t& resolvedURLLength); |
|
169 |
|
170 void didDraw(); |
|
171 void privateBrowsingModeDidChange(bool isPrivateBrowsingEnabled); |
|
172 |
|
173 static void setGlobalException(const WebCore::String&); |
|
174 static void moveGlobalExceptionToExecState(JSC::ExecState*); |
|
175 |
|
176 // Reply structs |
|
177 struct Reply { |
|
178 enum Type { |
|
179 InstantiatePlugin, |
|
180 GetScriptableNPObject, |
|
181 BooleanAndData, |
|
182 Boolean |
|
183 }; |
|
184 |
|
185 Reply(Type type) |
|
186 : m_type(type) |
|
187 { |
|
188 } |
|
189 |
|
190 virtual ~Reply() { } |
|
191 |
|
192 Type m_type; |
|
193 }; |
|
194 |
|
195 struct InstantiatePluginReply : public Reply { |
|
196 static const int ReplyType = InstantiatePlugin; |
|
197 |
|
198 InstantiatePluginReply(kern_return_t resultCode, uint32_t renderContextID, RendererType rendererType) |
|
199 : Reply(InstantiatePlugin) |
|
200 , m_resultCode(resultCode) |
|
201 , m_renderContextID(renderContextID) |
|
202 , m_rendererType(rendererType) |
|
203 { |
|
204 } |
|
205 |
|
206 kern_return_t m_resultCode; |
|
207 uint32_t m_renderContextID; |
|
208 RendererType m_rendererType; |
|
209 }; |
|
210 |
|
211 struct GetScriptableNPObjectReply : public Reply { |
|
212 static const Reply::Type ReplyType = GetScriptableNPObject; |
|
213 |
|
214 GetScriptableNPObjectReply(uint32_t objectID) |
|
215 : Reply(ReplyType) |
|
216 , m_objectID(objectID) |
|
217 { |
|
218 } |
|
219 |
|
220 uint32_t m_objectID; |
|
221 }; |
|
222 |
|
223 struct BooleanReply : public Reply { |
|
224 static const Reply::Type ReplyType = Boolean; |
|
225 |
|
226 BooleanReply(boolean_t result) |
|
227 : Reply(ReplyType) |
|
228 , m_result(result) |
|
229 { |
|
230 } |
|
231 |
|
232 boolean_t m_result; |
|
233 }; |
|
234 |
|
235 struct BooleanAndDataReply : public Reply { |
|
236 static const Reply::Type ReplyType = BooleanAndData; |
|
237 |
|
238 BooleanAndDataReply(boolean_t returnValue, RetainPtr<CFDataRef> result) |
|
239 : Reply(ReplyType) |
|
240 , m_returnValue(returnValue) |
|
241 , m_result(result) |
|
242 { |
|
243 } |
|
244 |
|
245 boolean_t m_returnValue; |
|
246 RetainPtr<CFDataRef> m_result; |
|
247 }; |
|
248 |
|
249 void setCurrentReply(uint32_t requestID, Reply* reply) |
|
250 { |
|
251 ASSERT(!m_replies.contains(requestID)); |
|
252 m_replies.set(requestID, reply); |
|
253 } |
|
254 |
|
255 template <typename T> |
|
256 std::auto_ptr<T> waitForReply(uint32_t requestID) |
|
257 { |
|
258 RefPtr<NetscapePluginInstanceProxy> protect(this); // Plug-in host may crash while we are waiting for reply, releasing all instances to the instance proxy. |
|
259 |
|
260 willCallPluginFunction(); |
|
261 m_waitingForReply = true; |
|
262 |
|
263 Reply* reply = processRequestsAndWaitForReply(requestID); |
|
264 if (reply) |
|
265 ASSERT(reply->m_type == T::ReplyType); |
|
266 |
|
267 m_waitingForReply = false; |
|
268 |
|
269 didCallPluginFunction(); |
|
270 |
|
271 return std::auto_ptr<T>(static_cast<T*>(reply)); |
|
272 } |
|
273 |
|
274 void webFrameDidFinishLoadWithReason(WebFrame*, NPReason); |
|
275 |
|
276 private: |
|
277 NetscapePluginInstanceProxy(NetscapePluginHostProxy*, WebHostedNetscapePluginView*, bool fullFramePlugin); |
|
278 |
|
279 NPError loadRequest(NSURLRequest*, const char* cTarget, bool currentEventIsUserGesture, uint32_t& streamID); |
|
280 |
|
281 class PluginRequest; |
|
282 void performRequest(PluginRequest*); |
|
283 void evaluateJavaScript(PluginRequest*); |
|
284 |
|
285 void stopAllStreams(); |
|
286 Reply* processRequestsAndWaitForReply(uint32_t requestID); |
|
287 |
|
288 NetscapePluginHostProxy* m_pluginHostProxy; |
|
289 WebHostedNetscapePluginView *m_pluginView; |
|
290 |
|
291 void requestTimerFired(WebCore::Timer<NetscapePluginInstanceProxy>*); |
|
292 WebCore::Timer<NetscapePluginInstanceProxy> m_requestTimer; |
|
293 Deque<RefPtr<PluginRequest> > m_pluginRequests; |
|
294 |
|
295 HashMap<uint32_t, RefPtr<HostedNetscapePluginStream> > m_streams; |
|
296 |
|
297 uint32_t m_currentURLRequestID; |
|
298 |
|
299 uint32_t m_pluginID; |
|
300 uint32_t m_renderContextID; |
|
301 RendererType m_rendererType; |
|
302 |
|
303 bool m_waitingForReply; |
|
304 HashMap<uint32_t, Reply*> m_replies; |
|
305 |
|
306 // NPRuntime |
|
307 |
|
308 void addValueToArray(NSMutableArray *, JSC::ExecState* exec, JSC::JSValue value); |
|
309 |
|
310 bool demarshalValueFromArray(JSC::ExecState*, NSArray *array, NSUInteger& index, JSC::JSValue& result); |
|
311 void demarshalValues(JSC::ExecState*, data_t valuesData, mach_msg_type_number_t valuesLength, JSC::MarkedArgumentBuffer& result); |
|
312 |
|
313 class LocalObjectMap : Noncopyable { |
|
314 public: |
|
315 LocalObjectMap(); |
|
316 ~LocalObjectMap(); |
|
317 uint32_t idForObject(JSC::JSObject*); |
|
318 void retain(JSC::JSObject*); |
|
319 void release(JSC::JSObject*); |
|
320 void clear(); |
|
321 bool forget(uint32_t); |
|
322 bool contains(uint32_t) const; |
|
323 JSC::JSObject* get(uint32_t) const; |
|
324 |
|
325 private: |
|
326 HashMap<uint32_t, JSC::ProtectedPtr<JSC::JSObject> > m_idToJSObjectMap; |
|
327 // The pair consists of object ID and a reference count. One reference belongs to remote plug-in, |
|
328 // and the proxy will add transient references for arguments that are being sent out. |
|
329 HashMap<JSC::JSObject*, pair<uint32_t, uint32_t> > m_jsObjectToIDMap; |
|
330 uint32_t m_objectIDCounter; |
|
331 }; |
|
332 |
|
333 LocalObjectMap m_localObjects; |
|
334 |
|
335 typedef HashSet<ProxyInstance*> ProxyInstanceSet; |
|
336 ProxyInstanceSet m_instances; |
|
337 |
|
338 uint32_t m_urlCheckCounter; |
|
339 typedef HashMap<uint32_t, RetainPtr<id> > URLCheckMap; |
|
340 URLCheckMap m_urlChecks; |
|
341 |
|
342 unsigned m_pluginFunctionCallDepth; |
|
343 bool m_shouldStopSoon; |
|
344 uint32_t m_currentRequestID; |
|
345 |
|
346 // All NPRuntime functions will return false when destroying a plug-in. This is necessary because there may be unhandled messages waiting, |
|
347 // and spinning in processRequests() will unexpectedly execute them from inside destroy(). That's not a good time to execute arbitrary JavaScript, |
|
348 // since both loading and rendering data structures may be in inconsistent state. |
|
349 // This suppresses calls from all plug-ins, even those in different pages, since JS might affect the frame with plug-in that's being stopped. |
|
350 // |
|
351 // FIXME: Plug-ins can execute arbitrary JS from destroy() in same process case, and other browsers also support that. |
|
352 // A better fix may be to make sure that unrelated messages are postponed until after destroy() returns. |
|
353 // Another possible fix may be to send destroy message at a time when internal structures are consistent. |
|
354 // |
|
355 // FIXME: We lack similar message suppression in other cases - resize() is also triggered by layout, so executing arbitrary JS is also problematic. |
|
356 static bool m_inDestroy; |
|
357 |
|
358 bool m_pluginIsWaitingForDraw; |
|
359 |
|
360 RefPtr<HostedNetscapePluginStream> m_manualStream; |
|
361 |
|
362 typedef HashMap<WebFrame*, RefPtr<PluginRequest> > FrameLoadMap; |
|
363 FrameLoadMap m_pendingFrameLoads; |
|
364 }; |
|
365 |
|
366 } // namespace WebKit |
|
367 |
|
368 #endif // NetscapePluginInstanceProxy_h |
|
369 #endif // USE(PLUGIN_HOST_PROCESS) |