| /* |
| * Copyright (C) 2008, 2009, 2010 Apple Inc. All Rights Reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY |
| * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR |
| * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
| * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #if USE(PLUGIN_HOST_PROCESS) |
| |
| #ifndef NetscapePluginInstanceProxy_h |
| #define NetscapePluginInstanceProxy_h |
| |
| #include <JavaScriptCore/JSGlobalData.h> |
| #include <JavaScriptCore/Strong.h> |
| #include <WebCore/Timer.h> |
| #include <WebKit/npapi.h> |
| #include <wtf/Deque.h> |
| #include <wtf/Forward.h> |
| #include <wtf/HashMap.h> |
| #include <wtf/PassRefPtr.h> |
| #include <wtf/RefCounted.h> |
| #include <wtf/RetainPtr.h> |
| #include "WebKitPluginHostTypes.h" |
| |
| namespace JSC { |
| namespace Bindings { |
| class Instance; |
| class RootObject; |
| } |
| class ArgList; |
| } |
| @class WebHostedNetscapePluginView; |
| @class WebFrame; |
| |
| namespace WebKit { |
| |
| class HostedNetscapePluginStream; |
| class NetscapePluginHostProxy; |
| class PluginRequest; |
| class ProxyInstance; |
| |
| class NetscapePluginInstanceProxy : public RefCounted<NetscapePluginInstanceProxy> { |
| public: |
| static PassRefPtr<NetscapePluginInstanceProxy> create(NetscapePluginHostProxy*, WebHostedNetscapePluginView *, bool fullFramePlugin); |
| ~NetscapePluginInstanceProxy(); |
| |
| uint32_t pluginID() const |
| { |
| ASSERT(m_pluginID); |
| |
| return m_pluginID; |
| } |
| uint32_t renderContextID() const { ASSERT(fastMallocSize(this)); return m_renderContextID; } |
| void setRenderContextID(uint32_t renderContextID) { m_renderContextID = renderContextID; } |
| |
| RendererType rendererType() const { return m_rendererType; } |
| void setRendererType(RendererType rendererType) { m_rendererType = rendererType; } |
| |
| WebHostedNetscapePluginView *pluginView() const { ASSERT(fastMallocSize(this)); return m_pluginView; } |
| NetscapePluginHostProxy* hostProxy() const { ASSERT(fastMallocSize(this)); return m_pluginHostProxy; } |
| |
| bool cancelStreamLoad(uint32_t streamID, NPReason); |
| void disconnectStream(HostedNetscapePluginStream*); |
| |
| void setManualStream(PassRefPtr<HostedNetscapePluginStream>); |
| HostedNetscapePluginStream* manualStream() const { return m_manualStream.get(); } |
| |
| void pluginHostDied(); |
| |
| void resize(NSRect size, NSRect clipRect); |
| void destroy(); |
| void focusChanged(bool hasFocus); |
| void windowFocusChanged(bool hasFocus); |
| void windowFrameChanged(NSRect frame); |
| |
| void mouseEvent(NSView *pluginView, NSEvent *, NPCocoaEventType); |
| void keyEvent(NSView *pluginView, NSEvent *, NPCocoaEventType); |
| void insertText(NSString *); |
| bool wheelEvent(NSView *pluginView, NSEvent *); |
| void syntheticKeyDownWithCommandModifier(int keyCode, char character); |
| void flagsChanged(NSEvent *); |
| void print(CGContextRef, unsigned width, unsigned height); |
| void snapshot(CGContextRef, unsigned width, unsigned height); |
| |
| void startTimers(bool throttleTimers); |
| void stopTimers(); |
| |
| void invalidateRect(double x, double y, double width, double height); |
| |
| // NPRuntime |
| bool getWindowNPObject(uint32_t& objectID); |
| bool getPluginElementNPObject(uint32_t& objectID); |
| 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). |
| |
| bool evaluate(uint32_t objectID, const WTF::String& script, data_t& resultData, mach_msg_type_number_t& resultLength, bool allowPopups); |
| 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); |
| bool invokeDefault(uint32_t objectID, data_t argumentsData, mach_msg_type_number_t argumentsLength, data_t& resultData, mach_msg_type_number_t& resultLength); |
| bool construct(uint32_t objectID, data_t argumentsData, mach_msg_type_number_t argumentsLength, data_t& resultData, mach_msg_type_number_t& resultLength); |
| bool enumerate(uint32_t objectID, data_t& resultData, mach_msg_type_number_t& resultLength); |
| |
| bool getProperty(uint32_t objectID, const JSC::Identifier& propertyName, data_t &resultData, mach_msg_type_number_t& resultLength); |
| bool getProperty(uint32_t objectID, unsigned propertyName, data_t &resultData, mach_msg_type_number_t& resultLength); |
| bool setProperty(uint32_t objectID, const JSC::Identifier& propertyName, data_t valueData, mach_msg_type_number_t valueLength); |
| bool setProperty(uint32_t objectID, unsigned propertyName, data_t valueData, mach_msg_type_number_t valueLength); |
| bool removeProperty(uint32_t objectID, const JSC::Identifier& propertyName); |
| bool removeProperty(uint32_t objectID, unsigned propertyName); |
| bool hasProperty(uint32_t objectID, const JSC::Identifier& propertyName); |
| bool hasProperty(uint32_t objectID, unsigned propertyName); |
| bool hasMethod(uint32_t objectID, const JSC::Identifier& methodName); |
| |
| void status(const char* message); |
| NPError loadURL(const char* url, const char* target, const char* postData, uint32_t postDataLength, LoadURLFlags, uint32_t& requestID); |
| |
| bool getCookies(data_t urlData, mach_msg_type_number_t urlLength, data_t& cookiesData, mach_msg_type_number_t& cookiesLength); |
| bool setCookies(data_t urlData, mach_msg_type_number_t urlLength, data_t cookiesData, mach_msg_type_number_t cookiesLength); |
| |
| bool getProxy(data_t urlData, mach_msg_type_number_t urlLength, data_t& proxyData, mach_msg_type_number_t& proxyLength); |
| bool getAuthenticationInfo(data_t protocolData, data_t hostData, uint32_t port, data_t schemeData, data_t realmData, |
| data_t& usernameData, mach_msg_type_number_t& usernameLength, data_t& passwordData, mach_msg_type_number_t& passwordLength); |
| bool convertPoint(double sourceX, double sourceY, NPCoordinateSpace sourceSpace, |
| double& destX, double& destY, NPCoordinateSpace destSpace); |
| |
| PassRefPtr<JSC::Bindings::Instance> createBindingsInstance(PassRefPtr<JSC::Bindings::RootObject>); |
| RetainPtr<NSData *> marshalValues(JSC::ExecState*, const JSC::ArgList& args); |
| void marshalValue(JSC::ExecState*, JSC::JSValue, data_t& resultData, mach_msg_type_number_t& resultLength); |
| JSC::JSValue demarshalValue(JSC::ExecState*, const char* valueData, mach_msg_type_number_t valueLength); |
| |
| // No-op if the value does not contain a local object. |
| void retainLocalObject(JSC::JSValue); |
| void releaseLocalObject(JSC::JSValue); |
| |
| void addInstance(ProxyInstance*); |
| void removeInstance(ProxyInstance*); |
| |
| void cleanup(); |
| void invalidate(); |
| |
| void willCallPluginFunction(); |
| void didCallPluginFunction(bool& stopped); |
| bool shouldStop(); |
| |
| uint32_t nextRequestID(); |
| |
| uint32_t checkIfAllowedToLoadURL(const char* url, const char* target); |
| void cancelCheckIfAllowedToLoadURL(uint32_t checkID); |
| void checkIfAllowedToLoadURLResult(uint32_t checkID, bool allowed); |
| |
| void resolveURL(const char* url, const char* target, data_t& resolvedURLData, mach_msg_type_number_t& resolvedURLLength); |
| |
| void didDraw(); |
| void privateBrowsingModeDidChange(bool isPrivateBrowsingEnabled); |
| |
| static void setGlobalException(const WTF::String&); |
| static void moveGlobalExceptionToExecState(JSC::ExecState*); |
| |
| // Reply structs |
| struct Reply { |
| enum Type { |
| InstantiatePlugin, |
| GetScriptableNPObject, |
| BooleanAndData, |
| Boolean |
| }; |
| |
| Reply(Type type) |
| : m_type(type) |
| { |
| } |
| |
| virtual ~Reply() { } |
| |
| Type m_type; |
| }; |
| |
| struct InstantiatePluginReply : public Reply { |
| static const int ReplyType = InstantiatePlugin; |
| |
| InstantiatePluginReply(kern_return_t resultCode, uint32_t renderContextID, RendererType rendererType) |
| : Reply(InstantiatePlugin) |
| , m_resultCode(resultCode) |
| , m_renderContextID(renderContextID) |
| , m_rendererType(rendererType) |
| { |
| } |
| |
| kern_return_t m_resultCode; |
| uint32_t m_renderContextID; |
| RendererType m_rendererType; |
| }; |
| |
| struct GetScriptableNPObjectReply : public Reply { |
| static const Reply::Type ReplyType = GetScriptableNPObject; |
| |
| GetScriptableNPObjectReply(uint32_t objectID) |
| : Reply(ReplyType) |
| , m_objectID(objectID) |
| { |
| } |
| |
| uint32_t m_objectID; |
| }; |
| |
| struct BooleanReply : public Reply { |
| static const Reply::Type ReplyType = Boolean; |
| |
| BooleanReply(boolean_t result) |
| : Reply(ReplyType) |
| , m_result(result) |
| { |
| } |
| |
| boolean_t m_result; |
| }; |
| |
| struct BooleanAndDataReply : public Reply { |
| static const Reply::Type ReplyType = BooleanAndData; |
| |
| BooleanAndDataReply(boolean_t returnValue, RetainPtr<CFDataRef> result) |
| : Reply(ReplyType) |
| , m_returnValue(returnValue) |
| , m_result(result) |
| { |
| } |
| |
| boolean_t m_returnValue; |
| RetainPtr<CFDataRef> m_result; |
| }; |
| |
| void setCurrentReply(uint32_t requestID, Reply* reply) |
| { |
| ASSERT(!m_replies.contains(requestID)); |
| m_replies.set(requestID, reply); |
| } |
| |
| template <typename T> |
| std::auto_ptr<T> waitForReply(uint32_t requestID) |
| { |
| RefPtr<NetscapePluginInstanceProxy> protect(this); // Plug-in host may crash while we are waiting for reply, releasing all instances to the instance proxy. |
| |
| willCallPluginFunction(); |
| m_waitingForReply = true; |
| |
| Reply* reply = processRequestsAndWaitForReply(requestID); |
| if (reply) |
| ASSERT(reply->m_type == T::ReplyType); |
| |
| m_waitingForReply = false; |
| |
| bool stopped = false; |
| didCallPluginFunction(stopped); |
| if (stopped) { |
| // The instance proxy may have been deleted from didCallPluginFunction(), so a null reply needs to be returned. |
| delete static_cast<T*>(reply); |
| return std::auto_ptr<T>(); |
| } |
| |
| return std::auto_ptr<T>(static_cast<T*>(reply)); |
| } |
| |
| void webFrameDidFinishLoadWithReason(WebFrame*, NPReason); |
| |
| private: |
| NetscapePluginInstanceProxy(NetscapePluginHostProxy*, WebHostedNetscapePluginView*, bool fullFramePlugin); |
| |
| NPError loadRequest(NSURLRequest*, const char* cTarget, bool currentEventIsUserGesture, uint32_t& streamID); |
| |
| class PluginRequest; |
| void performRequest(PluginRequest*); |
| void evaluateJavaScript(PluginRequest*); |
| |
| void stopAllStreams(); |
| Reply* processRequestsAndWaitForReply(uint32_t requestID); |
| |
| NetscapePluginHostProxy* m_pluginHostProxy; |
| WebHostedNetscapePluginView *m_pluginView; |
| |
| void requestTimerFired(WebCore::Timer<NetscapePluginInstanceProxy>*); |
| WebCore::Timer<NetscapePluginInstanceProxy> m_requestTimer; |
| Deque<RefPtr<PluginRequest> > m_pluginRequests; |
| |
| HashMap<uint32_t, RefPtr<HostedNetscapePluginStream> > m_streams; |
| |
| uint32_t m_currentURLRequestID; |
| |
| uint32_t m_pluginID; |
| uint32_t m_renderContextID; |
| RendererType m_rendererType; |
| |
| bool m_waitingForReply; |
| HashMap<uint32_t, Reply*> m_replies; |
| |
| // NPRuntime |
| |
| void addValueToArray(NSMutableArray *, JSC::ExecState* exec, JSC::JSValue value); |
| |
| bool demarshalValueFromArray(JSC::ExecState*, NSArray *array, NSUInteger& index, JSC::JSValue& result); |
| void demarshalValues(JSC::ExecState*, data_t valuesData, mach_msg_type_number_t valuesLength, JSC::MarkedArgumentBuffer& result); |
| |
| class LocalObjectMap { |
| WTF_MAKE_NONCOPYABLE(LocalObjectMap); |
| public: |
| LocalObjectMap(); |
| ~LocalObjectMap(); |
| uint32_t idForObject(JSC::JSGlobalData&, JSC::JSObject*); |
| void retain(JSC::JSObject*); |
| void release(JSC::JSObject*); |
| void clear(); |
| bool forget(uint32_t); |
| bool contains(uint32_t) const; |
| JSC::JSObject* get(uint32_t) const; |
| |
| private: |
| HashMap<uint32_t, JSC::Strong<JSC::JSObject> > m_idToJSObjectMap; |
| // The pair consists of object ID and a reference count. One reference belongs to remote plug-in, |
| // and the proxy will add transient references for arguments that are being sent out. |
| HashMap<JSC::JSObject*, pair<uint32_t, uint32_t> > m_jsObjectToIDMap; |
| uint32_t m_objectIDCounter; |
| }; |
| |
| LocalObjectMap m_localObjects; |
| |
| typedef HashSet<ProxyInstance*> ProxyInstanceSet; |
| ProxyInstanceSet m_instances; |
| |
| uint32_t m_urlCheckCounter; |
| typedef HashMap<uint32_t, RetainPtr<id> > URLCheckMap; |
| URLCheckMap m_urlChecks; |
| |
| unsigned m_pluginFunctionCallDepth; |
| bool m_shouldStopSoon; |
| uint32_t m_currentRequestID; |
| |
| // All NPRuntime functions will return false when destroying a plug-in. This is necessary because there may be unhandled messages waiting, |
| // and spinning in processRequests() will unexpectedly execute them from inside destroy(). That's not a good time to execute arbitrary JavaScript, |
| // since both loading and rendering data structures may be in inconsistent state. |
| // 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. |
| // |
| // FIXME: Plug-ins can execute arbitrary JS from destroy() in same process case, and other browsers also support that. |
| // A better fix may be to make sure that unrelated messages are postponed until after destroy() returns. |
| // Another possible fix may be to send destroy message at a time when internal structures are consistent. |
| // |
| // FIXME: We lack similar message suppression in other cases - resize() is also triggered by layout, so executing arbitrary JS is also problematic. |
| static bool m_inDestroy; |
| |
| bool m_pluginIsWaitingForDraw; |
| |
| RefPtr<HostedNetscapePluginStream> m_manualStream; |
| |
| typedef HashMap<WebFrame*, RefPtr<PluginRequest> > FrameLoadMap; |
| FrameLoadMap m_pendingFrameLoads; |
| }; |
| |
| } // namespace WebKit |
| |
| #endif // NetscapePluginInstanceProxy_h |
| #endif // USE(PLUGIN_HOST_PROCESS) |