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