diff options
author | Ben Murdoch <benm@google.com> | 2011-05-13 16:23:25 +0100 |
---|---|---|
committer | Ben Murdoch <benm@google.com> | 2011-05-16 11:35:02 +0100 |
commit | 65f03d4f644ce73618e5f4f50dd694b26f55ae12 (patch) | |
tree | f478babb801e720de7bfaee23443ffe029f58731 /Source/WebKit/mac/Plugins/Hosted | |
parent | 47de4a2fb7262c7ebdb9cd133ad2c54c187454d0 (diff) | |
download | external_webkit-65f03d4f644ce73618e5f4f50dd694b26f55ae12.zip external_webkit-65f03d4f644ce73618e5f4f50dd694b26f55ae12.tar.gz external_webkit-65f03d4f644ce73618e5f4f50dd694b26f55ae12.tar.bz2 |
Merge WebKit at r75993: Initial merge by git.
Change-Id: I602bbdc3974787a3b0450456a30a7868286921c3
Diffstat (limited to 'Source/WebKit/mac/Plugins/Hosted')
22 files changed, 6223 insertions, 0 deletions
diff --git a/Source/WebKit/mac/Plugins/Hosted/HostedNetscapePluginStream.h b/Source/WebKit/mac/Plugins/Hosted/HostedNetscapePluginStream.h new file mode 100644 index 0000000..34cea32 --- /dev/null +++ b/Source/WebKit/mac/Plugins/Hosted/HostedNetscapePluginStream.h @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2008 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 HostedNetscapePluginStream_h +#define HostedNetscapePluginStream_h + +#include <WebCore/NetscapePlugInStreamLoader.h> +#include <WebKit/npapi.h> +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> +#include <wtf/RefPtr.h> +#include <wtf/RetainPtr.h> + +namespace WebCore { + class FrameLoader; + class NetscapePlugInStreamLoader; +} + +namespace WebKit { + +class NetscapePluginInstanceProxy; + +class HostedNetscapePluginStream : public RefCounted<HostedNetscapePluginStream> + , private WebCore::NetscapePlugInStreamLoaderClient { +public: + static PassRefPtr<HostedNetscapePluginStream> create(NetscapePluginInstanceProxy* instance, uint32_t streamID, NSURLRequest *request) + { + return adoptRef(new HostedNetscapePluginStream(instance, streamID, request)); + } + static PassRefPtr<HostedNetscapePluginStream> create(NetscapePluginInstanceProxy* instance, WebCore::FrameLoader* frameLoader) + { + return adoptRef(new HostedNetscapePluginStream(instance, frameLoader)); + } + + ~HostedNetscapePluginStream(); + + uint32_t streamID() const { return m_streamID; } + + void startStreamWithResponse(NSURLResponse *response); + void didReceiveData(WebCore::NetscapePlugInStreamLoader*, const char* bytes, int length); + void didFinishLoading(WebCore::NetscapePlugInStreamLoader*); + void didFail(WebCore::NetscapePlugInStreamLoader*, const WebCore::ResourceError&); + + void start(); + void stop(); + + void cancelLoad(NPReason reason); + + static NPReason reasonForError(NSError* error); + +private: + NSError *errorForReason(NPReason) const; + void cancelLoad(NSError *); + + HostedNetscapePluginStream(NetscapePluginInstanceProxy*, uint32_t streamID, NSURLRequest *); + HostedNetscapePluginStream(NetscapePluginInstanceProxy*, WebCore::FrameLoader*); + + void startStream(NSURL *, long long expectedContentLength, NSDate *lastModifiedDate, NSString *mimeType, NSData *headers); + + NSError *pluginCancelledConnectionError() const; + + // NetscapePlugInStreamLoaderClient methods. + void didReceiveResponse(WebCore::NetscapePlugInStreamLoader*, const WebCore::ResourceResponse&); + bool wantsAllStreams() const; + + RefPtr<NetscapePluginInstanceProxy> m_instance; + uint32_t m_streamID; + bool m_isTerminated; + RetainPtr<NSMutableURLRequest> m_request; + + RetainPtr<NSURL> m_requestURL; + RetainPtr<NSURL> m_responseURL; + RetainPtr<NSString> m_mimeType; + + WebCore::FrameLoader* m_frameLoader; + RefPtr<WebCore::NetscapePlugInStreamLoader> m_loader; +}; + +} + +#endif // HostedNetscapePluginStream_h +#endif // USE(PLUGIN_HOST_PROCESS) diff --git a/Source/WebKit/mac/Plugins/Hosted/HostedNetscapePluginStream.mm b/Source/WebKit/mac/Plugins/Hosted/HostedNetscapePluginStream.mm new file mode 100644 index 0000000..8ac1389 --- /dev/null +++ b/Source/WebKit/mac/Plugins/Hosted/HostedNetscapePluginStream.mm @@ -0,0 +1,276 @@ +/* + * Copyright (C) 2008 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) && ENABLE(NETSCAPE_PLUGIN_API) + +#import "HostedNetscapePluginStream.h" + +#import "NetscapePluginHostProxy.h" +#import "NetscapePluginInstanceProxy.h" +#import "WebFrameInternal.h" +#import "WebHostedNetscapePluginView.h" +#import "WebKitErrorsPrivate.h" +#import "WebKitPluginHost.h" +#import "WebKitSystemInterface.h" +#import "WebNSURLExtras.h" +#import "WebNSURLRequestExtras.h" +#import <WebCore/DocumentLoader.h> +#import <WebCore/Frame.h> +#import <WebCore/FrameLoader.h> +#import <WebCore/ResourceLoadScheduler.h> +#import <WebCore/SecurityOrigin.h> +#import <WebCore/WebCoreURLResponse.h> +#import <wtf/RefCountedLeakCounter.h> + +using namespace WebCore; + +namespace WebKit { + +#ifndef NDEBUG +static WTF::RefCountedLeakCounter hostedNetscapePluginStreamCounter("HostedNetscapePluginStream"); +#endif + +HostedNetscapePluginStream::HostedNetscapePluginStream(NetscapePluginInstanceProxy* instance, uint32_t streamID, NSURLRequest *request) + : m_instance(instance) + , m_streamID(streamID) + , m_isTerminated(false) + , m_request(AdoptNS, [request mutableCopy]) + , m_requestURL([request URL]) + , m_frameLoader(0) +{ + if (SecurityOrigin::shouldHideReferrer([request URL], core([instance->pluginView() webFrame])->loader()->outgoingReferrer())) + [m_request.get() _web_setHTTPReferrer:nil]; + +#ifndef NDEBUG + hostedNetscapePluginStreamCounter.increment(); +#endif +} + +HostedNetscapePluginStream::HostedNetscapePluginStream(NetscapePluginInstanceProxy* instance, WebCore::FrameLoader* frameLoader) + : m_instance(instance) + , m_streamID(1) + , m_isTerminated(false) + , m_frameLoader(frameLoader) +{ +#ifndef NDEBUG + hostedNetscapePluginStreamCounter.increment(); +#endif +} + +HostedNetscapePluginStream::~HostedNetscapePluginStream() +{ +#ifndef NDEBUG + hostedNetscapePluginStreamCounter.decrement(); +#endif +} + +void HostedNetscapePluginStream::startStreamWithResponse(NSURLResponse *response) +{ + didReceiveResponse(0, response); +} + +void HostedNetscapePluginStream::startStream(NSURL *responseURL, long long expectedContentLength, NSDate *lastModifiedDate, NSString *mimeType, NSData *headers) +{ + m_responseURL = responseURL; + m_mimeType = mimeType; + + char* mimeTypeUTF8 = const_cast<char*>([mimeType UTF8String]); + int mimeTypeUTF8Length = mimeTypeUTF8 ? strlen (mimeTypeUTF8) + 1 : 0; + + const char *url = [responseURL _web_URLCString]; + int urlLength = url ? strlen(url) + 1 : 0; + + _WKPHStartStream(m_instance->hostProxy()->port(), + m_instance->pluginID(), + m_streamID, + const_cast<char*>(url), urlLength, + expectedContentLength, + [lastModifiedDate timeIntervalSince1970], + mimeTypeUTF8, mimeTypeUTF8Length, + const_cast<char*>(reinterpret_cast<const char*>([headers bytes])), [headers length]); +} + +void HostedNetscapePluginStream::didReceiveData(WebCore::NetscapePlugInStreamLoader*, const char* bytes, int length) +{ + _WKPHStreamDidReceiveData(m_instance->hostProxy()->port(), + m_instance->pluginID(), + m_streamID, + const_cast<char*>(bytes), length); +} + +void HostedNetscapePluginStream::didFinishLoading(WebCore::NetscapePlugInStreamLoader*) +{ + _WKPHStreamDidFinishLoading(m_instance->hostProxy()->port(), + m_instance->pluginID(), + m_streamID); + m_instance->disconnectStream(this); +} + +void HostedNetscapePluginStream::didReceiveResponse(NetscapePlugInStreamLoader*, const ResourceResponse& response) +{ + NSURLResponse *r = response.nsURLResponse(); + + NSMutableData *theHeaders = nil; + long long expectedContentLength = [r expectedContentLength]; + + if ([r isKindOfClass:[NSHTTPURLResponse class]]) { + NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)r; + theHeaders = [NSMutableData dataWithCapacity:1024]; + + // FIXME: it would be nice to be able to get the raw HTTP header block. + // This includes the HTTP version, the real status text, + // all headers in their original order and including duplicates, + // and all original bytes verbatim, rather than sent through Unicode translation. + // Unfortunately NSHTTPURLResponse doesn't provide access at that low a level. + + [theHeaders appendBytes:"HTTP " length:5]; + char statusStr[10]; + long statusCode = [httpResponse statusCode]; + snprintf(statusStr, sizeof(statusStr), "%ld", statusCode); + [theHeaders appendBytes:statusStr length:strlen(statusStr)]; + [theHeaders appendBytes:" OK\n" length:4]; + + // HACK: pass the headers through as UTF-8. + // This is not the intended behavior; we're supposed to pass original bytes verbatim. + // But we don't have the original bytes, we have NSStrings built by the URL loading system. + // It hopefully shouldn't matter, since RFC2616/RFC822 require ASCII-only headers, + // but surely someone out there is using non-ASCII characters, and hopefully UTF-8 is adequate here. + // It seems better than NSASCIIStringEncoding, which will lose information if non-ASCII is used. + + NSDictionary *headerDict = [httpResponse allHeaderFields]; + NSArray *keys = [[headerDict allKeys] sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)]; + NSEnumerator *i = [keys objectEnumerator]; + NSString *k; + while ((k = [i nextObject]) != nil) { + NSString *v = [headerDict objectForKey:k]; + [theHeaders appendData:[k dataUsingEncoding:NSUTF8StringEncoding]]; + [theHeaders appendBytes:": " length:2]; + [theHeaders appendData:[v dataUsingEncoding:NSUTF8StringEncoding]]; + [theHeaders appendBytes:"\n" length:1]; + } + + // If the content is encoded (most likely compressed), then don't send its length to the plugin, + // which is only interested in the decoded length, not yet known at the moment. + // <rdar://problem/4470599> tracks a request for -[NSURLResponse expectedContentLength] to incorporate this logic. + NSString *contentEncoding = (NSString *)[[(NSHTTPURLResponse *)r allHeaderFields] objectForKey:@"Content-Encoding"]; + if (contentEncoding && ![contentEncoding isEqualToString:@"identity"]) + expectedContentLength = -1; + + [theHeaders appendBytes:"\0" length:1]; + } + + startStream([r URL], expectedContentLength, WKGetNSURLResponseLastModifiedDate(r), [r MIMEType], theHeaders); +} + +NPReason HostedNetscapePluginStream::reasonForError(NSError *error) +{ + if (!error) + return NPRES_DONE; + + if ([[error domain] isEqualToString:NSURLErrorDomain] && [error code] == NSURLErrorCancelled) + return NPRES_USER_BREAK; + + return NPRES_NETWORK_ERR; +} + +void HostedNetscapePluginStream::didFail(WebCore::NetscapePlugInStreamLoader*, const WebCore::ResourceError& error) +{ + if (NetscapePluginHostProxy* hostProxy = m_instance->hostProxy()) + _WKPHStreamDidFail(hostProxy->port(), m_instance->pluginID(), m_streamID, reasonForError(error)); + m_instance->disconnectStream(this); +} + +bool HostedNetscapePluginStream::wantsAllStreams() const +{ + // FIXME: Implement. + return false; +} + +void HostedNetscapePluginStream::start() +{ + ASSERT(m_request); + ASSERT(!m_frameLoader); + ASSERT(!m_loader); + + m_loader = resourceLoadScheduler()->schedulePluginStreamLoad(core([m_instance->pluginView() webFrame]), this, m_request.get()); +} + +void HostedNetscapePluginStream::stop() +{ + ASSERT(!m_frameLoader); + + if (!m_loader->isDone()) + m_loader->cancel(m_loader->cancelledError()); +} + +void HostedNetscapePluginStream::cancelLoad(NPReason reason) +{ + cancelLoad(errorForReason(reason)); +} + +void HostedNetscapePluginStream::cancelLoad(NSError *error) +{ + if (m_frameLoader) { + ASSERT(!m_loader); + + DocumentLoader* documentLoader = m_frameLoader->activeDocumentLoader(); + if (documentLoader && documentLoader->isLoadingMainResource()) + documentLoader->cancelMainResourceLoad(error); + return; + } + + if (!m_loader->isDone()) { + // Cancelling the load will disconnect the stream so there's no need to do it explicitly. + m_loader->cancel(error); + } else + m_instance->disconnectStream(this); +} + +NSError *HostedNetscapePluginStream::pluginCancelledConnectionError() const +{ + return [[[NSError alloc] _initWithPluginErrorCode:WebKitErrorPlugInCancelledConnection + contentURL:m_responseURL ? m_responseURL.get() : m_requestURL.get() + pluginPageURL:nil + pluginName:[[m_instance->pluginView() pluginPackage] pluginInfo].name + MIMEType:m_mimeType.get()] autorelease]; +} + +NSError *HostedNetscapePluginStream::errorForReason(NPReason reason) const +{ + if (reason == NPRES_DONE) + return nil; + + if (reason == NPRES_USER_BREAK) + return [NSError _webKitErrorWithDomain:NSURLErrorDomain + code:NSURLErrorCancelled + URL:m_responseURL ? m_responseURL.get() : m_requestURL.get()]; + + return pluginCancelledConnectionError(); +} + +} // namespace WebKit + +#endif // USE(PLUGIN_HOST_PROCESS) && ENABLE(NETSCAPE_PLUGIN_API) + diff --git a/Source/WebKit/mac/Plugins/Hosted/NetscapePluginHostManager.h b/Source/WebKit/mac/Plugins/Hosted/NetscapePluginHostManager.h new file mode 100644 index 0000000..4e59456 --- /dev/null +++ b/Source/WebKit/mac/Plugins/Hosted/NetscapePluginHostManager.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2008 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 NetscapePluginHostManager_h +#define NetscapePluginHostManager_h + +#import <WebCore/PlatformString.h> +#import <wtf/HashMap.h> +#import <wtf/PassRefPtr.h> +#import <wtf/text/StringHash.h> + +@class WebHostedNetscapePluginView; + +namespace WebKit { + +class NetscapePluginInstanceProxy; +class NetscapePluginHostProxy; + +class NetscapePluginHostManager { +public: + static NetscapePluginHostManager& shared(); + + PassRefPtr<NetscapePluginInstanceProxy> instantiatePlugin(const WTF::String& pluginPath, cpu_type_t pluginArchitecture, const WTF::String& bundleIdentifier, WebHostedNetscapePluginView *, NSString *mimeType, NSArray *attributeKeys, NSArray *attributeValues, NSString *userAgent, NSURL *sourceURL, bool fullFrame, bool isPrivateBrowsingEnabled, bool isAcceleratedCompositingEnabled); + + void pluginHostDied(NetscapePluginHostProxy*); + + static void createPropertyListFile(const WTF::String& pluginPath, cpu_type_t pluginArchitecture); + + void didCreateWindow(); + +private: + NetscapePluginHostProxy* hostForPlugin(const WTF::String& pluginPath, cpu_type_t pluginArchitecture, const WTF::String& bundleIdentifier); + + NetscapePluginHostManager(); + ~NetscapePluginHostManager(); + + bool spawnPluginHost(const WTF::String& pluginPath, cpu_type_t pluginArchitecture, mach_port_t clientPort, mach_port_t& pluginHostPort, ProcessSerialNumber& pluginHostPSN); + + bool initializeVendorPort(); + + mach_port_t m_pluginVendorPort; + + // FIXME: This should really be a HashMap of RetainPtrs, but that doesn't work right now. + typedef HashMap<WTF::String, NetscapePluginHostProxy*> PluginHostMap; + PluginHostMap m_pluginHosts; +}; + +} // namespace WebKit + +#endif // NetscapePluginHostManager_h +#endif // USE(PLUGIN_HOST_PROCESS) diff --git a/Source/WebKit/mac/Plugins/Hosted/NetscapePluginHostManager.mm b/Source/WebKit/mac/Plugins/Hosted/NetscapePluginHostManager.mm new file mode 100644 index 0000000..d8cd081 --- /dev/null +++ b/Source/WebKit/mac/Plugins/Hosted/NetscapePluginHostManager.mm @@ -0,0 +1,321 @@ +/* + * Copyright (C) 2008 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) && ENABLE(NETSCAPE_PLUGIN_API) + +#import "NetscapePluginHostManager.h" + +#import "NetscapePluginHostProxy.h" +#import "NetscapePluginInstanceProxy.h" +#import "WebLocalizableStrings.h" +#import "WebKitSystemInterface.h" +#import "WebNetscapePluginPackage.h" +#import <mach/mach_port.h> +#import <servers/bootstrap.h> +#import <spawn.h> +#import <wtf/Assertions.h> +#import <wtf/RetainPtr.h> +#import <wtf/StdLibExtras.h> + +extern "C" { +#import "WebKitPluginAgent.h" +#import "WebKitPluginHost.h" +} + +using namespace std; +using namespace WebCore; + +namespace WebKit { + +NetscapePluginHostManager& NetscapePluginHostManager::shared() +{ + DEFINE_STATIC_LOCAL(NetscapePluginHostManager, pluginHostManager, ()); + + return pluginHostManager; +} + +static NSString * const pluginHostAppName = @"WebKitPluginHost.app"; + +NetscapePluginHostManager::NetscapePluginHostManager() + : m_pluginVendorPort(MACH_PORT_NULL) +{ +} + +NetscapePluginHostManager::~NetscapePluginHostManager() +{ +} + +NetscapePluginHostProxy* NetscapePluginHostManager::hostForPlugin(const WTF::String& pluginPath, cpu_type_t pluginArchitecture, const String& bundleIdentifier) +{ + pair<PluginHostMap::iterator, bool> result = m_pluginHosts.add(pluginPath, 0); + + // The package was already in the map, just return it. + if (!result.second) + return result.first->second; + + mach_port_t clientPort; + if (mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &clientPort) != KERN_SUCCESS) { + m_pluginHosts.remove(result.first); + return 0; + } + + mach_port_t pluginHostPort; + ProcessSerialNumber pluginHostPSN; + if (!spawnPluginHost(pluginPath, pluginArchitecture, clientPort, pluginHostPort, pluginHostPSN)) { + mach_port_destroy(mach_task_self(), clientPort); + m_pluginHosts.remove(result.first); + return 0; + } + + // Since Flash NPObjects add methods dynamically, we don't want to cache when a property/method doesn't exist + // on an object because it could be added later. + bool shouldCacheMissingPropertiesAndMethods = bundleIdentifier != "com.macromedia.Flash Player.plugin"; + + NetscapePluginHostProxy* hostProxy = new NetscapePluginHostProxy(clientPort, pluginHostPort, pluginHostPSN, shouldCacheMissingPropertiesAndMethods); + + result.first->second = hostProxy; + + return hostProxy; +} + +bool NetscapePluginHostManager::spawnPluginHost(const String& pluginPath, cpu_type_t pluginArchitecture, mach_port_t clientPort, mach_port_t& pluginHostPort, ProcessSerialNumber& pluginHostPSN) +{ + if (m_pluginVendorPort == MACH_PORT_NULL) { + if (!initializeVendorPort()) + return false; + } + + mach_port_t renderServerPort = WKInitializeRenderServer(); + if (renderServerPort == MACH_PORT_NULL) + return false; + + NSString *pluginHostAppPath = [[NSBundle bundleWithIdentifier:@"com.apple.WebKit"] pathForAuxiliaryExecutable:pluginHostAppName]; + NSString *pluginHostAppExecutablePath = [[NSBundle bundleWithPath:pluginHostAppPath] executablePath]; + + RetainPtr<CFStringRef> localization(AdoptCF, WKCopyCFLocalizationPreferredName(NULL)); + + NSDictionary *launchProperties = [[NSDictionary alloc] initWithObjectsAndKeys: + pluginHostAppExecutablePath, @"pluginHostPath", + [NSNumber numberWithInt:pluginArchitecture], @"cpuType", + localization.get(), @"localization", + nil]; + + NSData *data = [NSPropertyListSerialization dataFromPropertyList:launchProperties format:NSPropertyListBinaryFormat_v1_0 errorDescription:0]; + ASSERT(data); + + [launchProperties release]; + + kern_return_t kr = _WKPASpawnPluginHost(m_pluginVendorPort, reinterpret_cast<uint8_t*>(const_cast<void*>([data bytes])), [data length], &pluginHostPort); + + if (kr == MACH_SEND_INVALID_DEST) { + // The plug-in vendor port has gone away for some reason. Try to reinitialize it. + m_pluginVendorPort = MACH_PORT_NULL; + if (!initializeVendorPort()) + return false; + + // And spawn the plug-in host again. + kr = _WKPASpawnPluginHost(m_pluginVendorPort, reinterpret_cast<uint8_t*>(const_cast<void*>([data bytes])), [data length], &pluginHostPort); + } + + if (kr != KERN_SUCCESS) { + // FIXME: Check for invalid dest and try to re-spawn the plug-in agent. + LOG_ERROR("Failed to spawn plug-in host, error %x", kr); + return false; + } + + NSString *visibleName = [NSString stringWithFormat:UI_STRING("%@ (%@ Internet plug-in)", + "visible name of the plug-in host process. The first argument is the plug-in name " + "and the second argument is the application name."), + [[(NSString*)pluginPath lastPathComponent] stringByDeletingPathExtension], [[NSProcessInfo processInfo] processName]]; + + NSDictionary *hostProperties = [[NSDictionary alloc] initWithObjectsAndKeys: + visibleName, @"visibleName", + (NSString *)pluginPath, @"bundlePath", + nil]; + + data = [NSPropertyListSerialization dataFromPropertyList:hostProperties format:NSPropertyListBinaryFormat_v1_0 errorDescription:nil]; + ASSERT(data); + + [hostProperties release]; + + ProcessSerialNumber psn; + GetCurrentProcess(&psn); + + kr = _WKPHCheckInWithPluginHost(pluginHostPort, (uint8_t*)[data bytes], [data length], clientPort, psn.highLongOfPSN, psn.lowLongOfPSN, renderServerPort, + &pluginHostPSN.highLongOfPSN, &pluginHostPSN.lowLongOfPSN); + + if (kr != KERN_SUCCESS) { + mach_port_deallocate(mach_task_self(), pluginHostPort); + LOG_ERROR("Failed to check in with plug-in host, error %x", kr); + + return false; + } + + return true; +} + +bool NetscapePluginHostManager::initializeVendorPort() +{ + ASSERT(m_pluginVendorPort == MACH_PORT_NULL); + + // Get the plug-in agent port. + mach_port_t pluginAgentPort; + if (bootstrap_look_up(bootstrap_port, "com.apple.WebKit.PluginAgent", &pluginAgentPort) != KERN_SUCCESS) { + LOG_ERROR("Failed to look up the plug-in agent port"); + return false; + } + + NSData *appNameData = [[[NSProcessInfo processInfo] processName] dataUsingEncoding:NSUTF8StringEncoding]; + + // Tell the plug-in agent that we exist. + if (_WKPACheckInApplication(pluginAgentPort, (uint8_t*)[appNameData bytes], [appNameData length], &m_pluginVendorPort) != KERN_SUCCESS) + return false; + + // FIXME: Should we add a notification for when the vendor port dies? + + return true; +} + +void NetscapePluginHostManager::pluginHostDied(NetscapePluginHostProxy* pluginHost) +{ + PluginHostMap::iterator end = m_pluginHosts.end(); + + // This has O(n) complexity but the number of active plug-in hosts is very small so it shouldn't matter. + for (PluginHostMap::iterator it = m_pluginHosts.begin(); it != end; ++it) { + if (it->second == pluginHost) { + m_pluginHosts.remove(it); + return; + } + } +} + +PassRefPtr<NetscapePluginInstanceProxy> NetscapePluginHostManager::instantiatePlugin(const String& pluginPath, cpu_type_t pluginArchitecture, const String& bundleIdentifier, WebHostedNetscapePluginView *pluginView, NSString *mimeType, NSArray *attributeKeys, NSArray *attributeValues, NSString *userAgent, NSURL *sourceURL, bool fullFrame, bool isPrivateBrowsingEnabled, bool isAcceleratedCompositingEnabled) +{ + NetscapePluginHostProxy* hostProxy = hostForPlugin(pluginPath, pluginArchitecture, bundleIdentifier); + if (!hostProxy) + return 0; + + RetainPtr<NSMutableDictionary> properties(AdoptNS, [[NSMutableDictionary alloc] init]); + + if (mimeType) + [properties.get() setObject:mimeType forKey:@"mimeType"]; + + ASSERT_ARG(userAgent, userAgent); + [properties.get() setObject:userAgent forKey:@"userAgent"]; + + ASSERT_ARG(attributeKeys, attributeKeys); + [properties.get() setObject:attributeKeys forKey:@"attributeKeys"]; + + ASSERT_ARG(attributeValues, attributeValues); + [properties.get() setObject:attributeValues forKey:@"attributeValues"]; + + if (sourceURL) + [properties.get() setObject:[sourceURL absoluteString] forKey:@"sourceURL"]; + + [properties.get() setObject:[NSNumber numberWithBool:fullFrame] forKey:@"fullFrame"]; + [properties.get() setObject:[NSNumber numberWithBool:isPrivateBrowsingEnabled] forKey:@"privateBrowsingEnabled"]; + [properties.get() setObject:[NSNumber numberWithBool:isAcceleratedCompositingEnabled] forKey:@"acceleratedCompositingEnabled"]; + + NSData *data = [NSPropertyListSerialization dataFromPropertyList:properties.get() format:NSPropertyListBinaryFormat_v1_0 errorDescription:nil]; + ASSERT(data); + + RefPtr<NetscapePluginInstanceProxy> instance = NetscapePluginInstanceProxy::create(hostProxy, pluginView, fullFrame); + uint32_t requestID = instance->nextRequestID(); + kern_return_t kr = _WKPHInstantiatePlugin(hostProxy->port(), requestID, (uint8_t*)[data bytes], [data length], instance->pluginID()); + if (kr == MACH_SEND_INVALID_DEST) { + // Invalidate the instance. + instance->invalidate(); + + // The plug-in host must have died, but we haven't received the death notification yet. + pluginHostDied(hostProxy); + + // Try to spawn it again. + hostProxy = hostForPlugin(pluginPath, pluginArchitecture, bundleIdentifier); + + // Create a new instance. + instance = NetscapePluginInstanceProxy::create(hostProxy, pluginView, fullFrame); + requestID = instance->nextRequestID(); + kr = _WKPHInstantiatePlugin(hostProxy->port(), requestID, (uint8_t*)[data bytes], [data length], instance->pluginID()); + } + + auto_ptr<NetscapePluginInstanceProxy::InstantiatePluginReply> reply = instance->waitForReply<NetscapePluginInstanceProxy::InstantiatePluginReply>(requestID); + if (!reply.get() || reply->m_resultCode != KERN_SUCCESS) { + instance->cleanup(); + return 0; + } + + instance->setRenderContextID(reply->m_renderContextID); + instance->setRendererType(reply->m_rendererType); + + return instance.release(); +} + +void NetscapePluginHostManager::createPropertyListFile(const String& pluginPath, cpu_type_t pluginArchitecture) +{ + NSString *pluginHostAppPath = [[NSBundle bundleWithIdentifier:@"com.apple.WebKit"] pathForAuxiliaryExecutable:pluginHostAppName]; + NSString *pluginHostAppExecutablePath = [[NSBundle bundleWithPath:pluginHostAppPath] executablePath]; + NSString *bundlePath = pluginPath; + + pid_t pid; + posix_spawnattr_t attr; + posix_spawnattr_init(&attr); + + // Set the architecture. + size_t ocount = 0; + int cpuTypes[] = { pluginArchitecture }; + posix_spawnattr_setbinpref_np(&attr, 1, cpuTypes, &ocount); + + // Spawn the plug-in host and tell it to call the registration function. + const char* args[] = { [pluginHostAppExecutablePath fileSystemRepresentation], "-createPluginMIMETypesPreferences", [bundlePath fileSystemRepresentation], 0 }; + + int result = posix_spawn(&pid, args[0], 0, &attr, const_cast<char* const*>(args), 0); + posix_spawnattr_destroy(&attr); + + if (!result && pid > 0) { + // Wait for the process to finish. + while (waitpid(pid, 0, 0) == -1) { } + } +} + +void NetscapePluginHostManager::didCreateWindow() +{ + // See if any of our hosts are in full-screen mode. + PluginHostMap::iterator end = m_pluginHosts.end(); + for (PluginHostMap::iterator it = m_pluginHosts.begin(); it != end; ++it) { + NetscapePluginHostProxy* hostProxy = it->second; + + if (!hostProxy->isMenuBarVisible()) { + // Make ourselves the front process. + ProcessSerialNumber psn; + GetCurrentProcess(&psn); + SetFrontProcess(&psn); + return; + } + } +} + +} // namespace WebKit + +#endif // USE(PLUGIN_HOST_PROCESS) && ENABLE(NETSCAPE_PLUGIN_API) diff --git a/Source/WebKit/mac/Plugins/Hosted/NetscapePluginHostProxy.h b/Source/WebKit/mac/Plugins/Hosted/NetscapePluginHostProxy.h new file mode 100644 index 0000000..20db5d2 --- /dev/null +++ b/Source/WebKit/mac/Plugins/Hosted/NetscapePluginHostProxy.h @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2008 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 NetscapePluginHostProxy_h +#define NetscapePluginHostProxy_h + +#include <dispatch/dispatch.h> +#include <wtf/HashMap.h> +#include <wtf/RetainPtr.h> +#include <wtf/PassRefPtr.h> + +@class WebPlaceholderModalWindow; + +namespace WebKit { + +class NetscapePluginInstanceProxy; + +class NetscapePluginHostProxy { +public: + NetscapePluginHostProxy(mach_port_t clientPort, mach_port_t pluginHostPort, const ProcessSerialNumber& pluginHostPSN, bool shouldCacheMissingPropertiesAndMethods); + + mach_port_t port() const { ASSERT(fastMallocSize(this)); return m_pluginHostPort; } + mach_port_t clientPort() const { ASSERT(fastMallocSize(this)); return m_clientPort; } + + void addPluginInstance(NetscapePluginInstanceProxy*); + void removePluginInstance(NetscapePluginInstanceProxy*); + + NetscapePluginInstanceProxy* pluginInstance(uint32_t pluginID); + + bool isMenuBarVisible() const { return m_menuBarIsVisible; } + void setMenuBarVisible(bool); + + bool isFullscreenWindowShowing() const { return m_fullscreenWindowIsShowing; } + void setFullscreenWindowIsShowing(bool); + + void setModal(bool); + + void applicationDidBecomeActive(); + + bool processRequests(); + static bool isProcessingRequests() { return s_processingRequests; } + + bool shouldCacheMissingPropertiesAndMethods() const { return m_shouldCacheMissingPropertiesAndMethods; } + +private: + ~NetscapePluginHostProxy(); + void pluginHostDied(); + + void beginModal(); + void endModal(); + + void didEnterFullscreen() const; + void didExitFullscreen() const; + + static void deadNameNotificationCallback(CFMachPortRef, void *msg, CFIndex size, void *info); + + typedef HashMap<uint32_t, RefPtr<NetscapePluginInstanceProxy> > PluginInstanceMap; + PluginInstanceMap m_instances; + + mach_port_t m_clientPort; + mach_port_t m_portSet; + + RetainPtr<CFRunLoopSourceRef> m_clientPortSource; + mach_port_t m_pluginHostPort; + RetainPtr<CFMachPortRef> m_deadNameNotificationPort; + + RetainPtr<id> m_activationObserver; + RetainPtr<WebPlaceholderModalWindow *> m_placeholderWindow; + unsigned m_isModal; + bool m_menuBarIsVisible; + bool m_fullscreenWindowIsShowing; + const ProcessSerialNumber m_pluginHostPSN; + + static unsigned s_processingRequests; + + bool m_shouldCacheMissingPropertiesAndMethods; +}; + +} // namespace WebKit + +#endif // NetscapePluginHostProxy_h +#endif // USE(PLUGIN_HOST_PROCESS) diff --git a/Source/WebKit/mac/Plugins/Hosted/NetscapePluginHostProxy.mm b/Source/WebKit/mac/Plugins/Hosted/NetscapePluginHostProxy.mm new file mode 100644 index 0000000..4506f03 --- /dev/null +++ b/Source/WebKit/mac/Plugins/Hosted/NetscapePluginHostProxy.mm @@ -0,0 +1,1134 @@ +/* + * Copyright (C) 2008 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) && ENABLE(NETSCAPE_PLUGIN_API) + +#import "NetscapePluginHostProxy.h" + +#import <mach/mach.h> +#import <wtf/StdLibExtras.h> + +#import "HostedNetscapePluginStream.h" +#import "NetscapePluginHostManager.h" +#import "NetscapePluginInstanceProxy.h" +#import "WebFrameInternal.h" +#import "WebHostedNetscapePluginView.h" +#import "WebKitSystemInterface.h" +#import <WebCore/Frame.h> +#import <WebCore/IdentifierRep.h> +#import <WebCore/ScriptController.h> +#import <string> + +extern "C" { +#import "WebKitPluginHost.h" +#import "WebKitPluginClientServer.h" +} + +using namespace std; +using namespace JSC; +using namespace WebCore; + +@interface WebPlaceholderModalWindow : NSWindow +@end + +@implementation WebPlaceholderModalWindow +// Prevent NSApp from calling requestUserAttention: when the window is shown +// modally, even if the app is inactive. See 6823049. +- (BOOL)_wantsUserAttention +{ + return NO; +} +@end + +namespace WebKit { + +class PluginDestroyDeferrer { +public: + PluginDestroyDeferrer(NetscapePluginInstanceProxy* proxy) + : m_proxy(proxy) + { + m_proxy->willCallPluginFunction(); + } + + ~PluginDestroyDeferrer() + { + bool stopped; + m_proxy->didCallPluginFunction(stopped); + } + +private: + RefPtr<NetscapePluginInstanceProxy> m_proxy; +}; + +typedef HashMap<mach_port_t, NetscapePluginHostProxy*> PluginProxyMap; +static PluginProxyMap& pluginProxyMap() +{ + DEFINE_STATIC_LOCAL(PluginProxyMap, pluginProxyMap, ()); + + return pluginProxyMap; +} + +unsigned NetscapePluginHostProxy::s_processingRequests; + +NetscapePluginHostProxy::NetscapePluginHostProxy(mach_port_t clientPort, mach_port_t pluginHostPort, const ProcessSerialNumber& pluginHostPSN, bool shouldCacheMissingPropertiesAndMethods) + : m_clientPort(clientPort) + , m_portSet(MACH_PORT_NULL) + , m_pluginHostPort(pluginHostPort) + , m_isModal(false) + , m_menuBarIsVisible(true) + , m_fullscreenWindowIsShowing(false) + , m_pluginHostPSN(pluginHostPSN) + , m_shouldCacheMissingPropertiesAndMethods(shouldCacheMissingPropertiesAndMethods) +{ + pluginProxyMap().add(m_clientPort, this); + + // FIXME: We should use libdispatch for this. + CFMachPortContext context = { 0, this, 0, 0, 0 }; + m_deadNameNotificationPort.adoptCF(CFMachPortCreate(0, deadNameNotificationCallback, &context, 0)); + + mach_port_t previous; + mach_port_request_notification(mach_task_self(), pluginHostPort, MACH_NOTIFY_DEAD_NAME, 0, + CFMachPortGetPort(m_deadNameNotificationPort.get()), MACH_MSG_TYPE_MAKE_SEND_ONCE, &previous); + ASSERT(previous == MACH_PORT_NULL); + + RetainPtr<CFRunLoopSourceRef> deathPortSource(AdoptCF, CFMachPortCreateRunLoopSource(0, m_deadNameNotificationPort.get(), 0)); + + CFRunLoopAddSource(CFRunLoopGetCurrent(), deathPortSource.get(), kCFRunLoopDefaultMode); + + m_clientPortSource.adoptCF(WKCreateMIGServerSource((mig_subsystem_t)&WKWebKitPluginClient_subsystem, m_clientPort)); + CFRunLoopAddSource(CFRunLoopGetCurrent(), m_clientPortSource.get(), kCFRunLoopDefaultMode); + CFRunLoopAddSource(CFRunLoopGetCurrent(), m_clientPortSource.get(), (CFStringRef)NSEventTrackingRunLoopMode); +} + +NetscapePluginHostProxy::~NetscapePluginHostProxy() +{ + pluginProxyMap().remove(m_clientPort); + + // Free the port set + if (m_portSet) { + mach_port_extract_member(mach_task_self(), m_clientPort, m_portSet); + mach_port_extract_member(mach_task_self(), CFMachPortGetPort(m_deadNameNotificationPort.get()), m_portSet); + mach_port_destroy(mach_task_self(), m_portSet); + } + + ASSERT(m_clientPortSource); + CFRunLoopSourceInvalidate(m_clientPortSource.get()); + m_clientPortSource = 0; +} + +void NetscapePluginHostProxy::pluginHostDied() +{ + PluginInstanceMap instances; + m_instances.swap(instances); + + PluginInstanceMap::const_iterator end = instances.end(); + for (PluginInstanceMap::const_iterator it = instances.begin(); it != end; ++it) + it->second->pluginHostDied(); + + NetscapePluginHostManager::shared().pluginHostDied(this); + + // The plug-in crashed while its menu bar was hidden. Make sure to show it. + if (!m_menuBarIsVisible) + setMenuBarVisible(true); + + // The plug-in crashed while it had a modal dialog up. + if (m_isModal) + endModal(); + + delete this; +} + +void NetscapePluginHostProxy::addPluginInstance(NetscapePluginInstanceProxy* instance) +{ + ASSERT(!m_instances.contains(instance->pluginID())); + + m_instances.set(instance->pluginID(), instance); +} + +void NetscapePluginHostProxy::removePluginInstance(NetscapePluginInstanceProxy* instance) +{ + ASSERT(m_instances.get(instance->pluginID()) == instance); + + m_instances.remove(instance->pluginID()); +} + +NetscapePluginInstanceProxy* NetscapePluginHostProxy::pluginInstance(uint32_t pluginID) +{ + NetscapePluginInstanceProxy* result = m_instances.get(pluginID).get(); + ASSERT(!result || result->hostProxy() == this); + return result; +} + +void NetscapePluginHostProxy::deadNameNotificationCallback(CFMachPortRef port, void *msg, CFIndex size, void *info) +{ + ASSERT(msg); + ASSERT(static_cast<mach_msg_header_t*>(msg)->msgh_id == MACH_NOTIFY_DEAD_NAME); + + static_cast<NetscapePluginHostProxy*>(info)->pluginHostDied(); +} + +void NetscapePluginHostProxy::setMenuBarVisible(bool visible) +{ + m_menuBarIsVisible = visible; + + [NSMenu setMenuBarVisible:visible]; +} + +void NetscapePluginHostProxy::didEnterFullscreen() const +{ + SetFrontProcess(&m_pluginHostPSN); +} + +void NetscapePluginHostProxy::didExitFullscreen() const +{ + // If the plug-in host is the current application then we should bring ourselves to the front when it exits full-screen mode. + + ProcessSerialNumber frontProcess; + GetFrontProcess(&frontProcess); + Boolean isSameProcess = 0; + SameProcess(&frontProcess, &m_pluginHostPSN, &isSameProcess); + if (!isSameProcess) + return; + + ProcessSerialNumber currentProcess; + GetCurrentProcess(¤tProcess); + SetFrontProcess(¤tProcess); +} + +void NetscapePluginHostProxy::setFullscreenWindowIsShowing(bool isShowing) +{ + if (m_fullscreenWindowIsShowing == isShowing) + return; + + m_fullscreenWindowIsShowing = isShowing; + if (m_fullscreenWindowIsShowing) + didEnterFullscreen(); + else + didExitFullscreen(); + +} + +void NetscapePluginHostProxy::applicationDidBecomeActive() +{ + SetFrontProcess(&m_pluginHostPSN); +} + +void NetscapePluginHostProxy::beginModal() +{ + ASSERT(!m_placeholderWindow); + ASSERT(!m_activationObserver); + + m_placeholderWindow.adoptNS([[WebPlaceholderModalWindow alloc] initWithContentRect:NSMakeRect(0, 0, 1, 1) styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:YES]); + + m_activationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:NSApplicationWillBecomeActiveNotification object:NSApp queue:nil + usingBlock:^(NSNotification *){ applicationDidBecomeActive(); }]; + + // We need to be able to get the setModal(false) call from the plug-in host. + CFRunLoopAddSource(CFRunLoopGetCurrent(), m_clientPortSource.get(), (CFStringRef)NSModalPanelRunLoopMode); + + [NSApp runModalForWindow:m_placeholderWindow.get()]; + + [m_placeholderWindow.get() orderOut:nil]; + m_placeholderWindow = 0; +} + +void NetscapePluginHostProxy::endModal() +{ + ASSERT(m_placeholderWindow); + ASSERT(m_activationObserver); + + [[NSNotificationCenter defaultCenter] removeObserver:m_activationObserver.get()]; + m_activationObserver = nil; + + CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m_clientPortSource.get(), (CFStringRef)NSModalPanelRunLoopMode); + + [NSApp stopModal]; + + // Make ourselves the front process. + ProcessSerialNumber psn; + GetCurrentProcess(&psn); + SetFrontProcess(&psn); +} + + +void NetscapePluginHostProxy::setModal(bool modal) +{ + if (modal == m_isModal) + return; + + m_isModal = modal; + + if (m_isModal) + beginModal(); + else + endModal(); +} + +bool NetscapePluginHostProxy::processRequests() +{ + s_processingRequests++; + + if (!m_portSet) { + mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_PORT_SET, &m_portSet); + mach_port_insert_member(mach_task_self(), m_clientPort, m_portSet); + mach_port_insert_member(mach_task_self(), CFMachPortGetPort(m_deadNameNotificationPort.get()), m_portSet); + } + + char buffer[4096]; + + mach_msg_header_t* msg = reinterpret_cast<mach_msg_header_t*>(buffer); + + kern_return_t kr = mach_msg(msg, MACH_RCV_MSG, 0, sizeof(buffer), m_portSet, 0, MACH_PORT_NULL); + + if (kr != KERN_SUCCESS) { + LOG_ERROR("Could not receive mach message, error %x", kr); + s_processingRequests--; + return false; + } + + if (msg->msgh_local_port == m_clientPort) { + __ReplyUnion__WKWebKitPluginClient_subsystem reply; + mach_msg_header_t* replyHeader = reinterpret_cast<mach_msg_header_t*>(&reply); + + if (WebKitPluginClient_server(msg, replyHeader) && replyHeader->msgh_remote_port != MACH_PORT_NULL) { + kr = mach_msg(replyHeader, MACH_SEND_MSG, replyHeader->msgh_size, 0, MACH_PORT_NULL, 0, MACH_PORT_NULL); + + if (kr != KERN_SUCCESS) { + LOG_ERROR("Could not send mach message, error %x", kr); + s_processingRequests--; + return false; + } + } + + s_processingRequests--; + return true; + } + + if (msg->msgh_local_port == CFMachPortGetPort(m_deadNameNotificationPort.get())) { + ASSERT(msg->msgh_id == MACH_NOTIFY_DEAD_NAME); + pluginHostDied(); + s_processingRequests--; + return false; + } + + ASSERT_NOT_REACHED(); + s_processingRequests--; + return false; +} + +} // namespace WebKit + +using namespace WebKit; + +// Helper class for deallocating data +class DataDeallocator { +public: + DataDeallocator(data_t data, mach_msg_type_number_t dataLength) + : m_data(reinterpret_cast<vm_address_t>(data)) + , m_dataLength(dataLength) + { + } + + ~DataDeallocator() + { + if (!m_data) + return; + + vm_deallocate(mach_task_self(), m_data, m_dataLength); + } + +private: + vm_address_t m_data; + vm_size_t m_dataLength; +}; + +// MiG callbacks +kern_return_t WKPCStatusText(mach_port_t clientPort, uint32_t pluginID, data_t text, mach_msg_type_number_t textCnt) +{ + DataDeallocator deallocator(text, textCnt); + + NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort); + if (!hostProxy) + return KERN_FAILURE; + + NetscapePluginInstanceProxy* instanceProxy = hostProxy->pluginInstance(pluginID); + if (!instanceProxy) + return KERN_FAILURE; + + instanceProxy->status(text); + return KERN_SUCCESS; +} + +kern_return_t WKPCLoadURL(mach_port_t clientPort, uint32_t pluginID, data_t url, mach_msg_type_number_t urlLength, data_t target, mach_msg_type_number_t targetLength, + data_t postData, mach_msg_type_number_t postDataLength, uint32_t flags, + uint16_t* outResult, uint32_t* outStreamID) +{ + DataDeallocator urlDeallocator(url, urlLength); + DataDeallocator targetDeallocator(target, targetLength); + DataDeallocator postDataDeallocator(postData, postDataLength); + + NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort); + if (!hostProxy) + return KERN_FAILURE; + + NetscapePluginInstanceProxy* instanceProxy = hostProxy->pluginInstance(pluginID); + if (!instanceProxy) + return KERN_FAILURE; + + uint32_t streamID = 0; + NPError result = instanceProxy->loadURL(url, target, postData, postDataLength, static_cast<LoadURLFlags>(flags), streamID); + + *outResult = result; + *outStreamID = streamID; + return KERN_SUCCESS; +} + +kern_return_t WKPCCancelLoadURL(mach_port_t clientPort, uint32_t pluginID, uint32_t streamID, int16_t reason) +{ + NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort); + if (!hostProxy) + return KERN_FAILURE; + + NetscapePluginInstanceProxy* instanceProxy = hostProxy->pluginInstance(pluginID); + if (!instanceProxy) + return KERN_FAILURE; + + if (!instanceProxy->cancelStreamLoad(streamID, reason)) + return KERN_FAILURE; + + return KERN_SUCCESS; +} + +kern_return_t WKPCInvalidateRect(mach_port_t clientPort, uint32_t pluginID, double x, double y, double width, double height) +{ + NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort); + if (!hostProxy) + return KERN_SUCCESS; + + if (!hostProxy->isProcessingRequests()) { + if (NetscapePluginInstanceProxy* instanceProxy = hostProxy->pluginInstance(pluginID)) + instanceProxy->invalidateRect(x, y, width, height); + return KERN_SUCCESS; + } + + // Defer the work + CFRunLoopPerformBlock(CFRunLoopGetMain(), kCFRunLoopDefaultMode, ^{ + if (NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort)) { + if (NetscapePluginInstanceProxy* instanceProxy = hostProxy->pluginInstance(pluginID)) + instanceProxy->invalidateRect(x, y, width, height); + } + }); + + return KERN_SUCCESS; +} + +kern_return_t WKPCGetScriptableNPObjectReply(mach_port_t clientPort, uint32_t pluginID, uint32_t requestID, uint32_t objectID) +{ + NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort); + if (!hostProxy) + return KERN_FAILURE; + + NetscapePluginInstanceProxy* instanceProxy = hostProxy->pluginInstance(pluginID); + if (!instanceProxy) + return KERN_FAILURE; + + instanceProxy->setCurrentReply(requestID, new NetscapePluginInstanceProxy::GetScriptableNPObjectReply(objectID)); + return KERN_SUCCESS; +} + +kern_return_t WKPCBooleanReply(mach_port_t clientPort, uint32_t pluginID, uint32_t requestID, boolean_t result) +{ + NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort); + if (!hostProxy) + return KERN_FAILURE; + + NetscapePluginInstanceProxy* instanceProxy = hostProxy->pluginInstance(pluginID); + if (!instanceProxy) + return KERN_FAILURE; + + instanceProxy->setCurrentReply(requestID, new NetscapePluginInstanceProxy::BooleanReply(result)); + return KERN_SUCCESS; +} + +kern_return_t WKPCBooleanAndDataReply(mach_port_t clientPort, uint32_t pluginID, uint32_t requestID, boolean_t returnValue, data_t resultData, mach_msg_type_number_t resultLength) +{ + DataDeallocator deallocator(resultData, resultLength); + + NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort); + if (!hostProxy) + return KERN_FAILURE; + + NetscapePluginInstanceProxy* instanceProxy = hostProxy->pluginInstance(pluginID); + if (!instanceProxy) + return KERN_FAILURE; + + RetainPtr<CFDataRef> result(AdoptCF, CFDataCreate(0, reinterpret_cast<UInt8*>(resultData), resultLength)); + instanceProxy->setCurrentReply(requestID, new NetscapePluginInstanceProxy::BooleanAndDataReply(returnValue, result)); + + return KERN_SUCCESS; +} + +kern_return_t WKPCInstantiatePluginReply(mach_port_t clientPort, uint32_t pluginID, uint32_t requestID, kern_return_t result, uint32_t renderContextID, uint32_t rendererType) +{ + NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort); + if (!hostProxy) + return KERN_FAILURE; + + NetscapePluginInstanceProxy* instanceProxy = hostProxy->pluginInstance(pluginID); + if (!instanceProxy) + return KERN_FAILURE; + + instanceProxy->setCurrentReply(requestID, new NetscapePluginInstanceProxy::InstantiatePluginReply(result, renderContextID, static_cast<RendererType>(rendererType))); + return KERN_SUCCESS; +} + +kern_return_t WKPCGetWindowNPObject(mach_port_t clientPort, uint32_t pluginID, uint32_t* outObjectID) +{ + NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort); + if (!hostProxy) + return KERN_FAILURE; + + NetscapePluginInstanceProxy* instanceProxy = hostProxy->pluginInstance(pluginID); + if (!instanceProxy) + return KERN_FAILURE; + + uint32_t objectID; + if (!instanceProxy->getWindowNPObject(objectID)) + return KERN_FAILURE; + + *outObjectID = objectID; + return KERN_SUCCESS; +} + +kern_return_t WKPCGetPluginElementNPObject(mach_port_t clientPort, uint32_t pluginID, uint32_t* outObjectID) +{ + NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort); + if (!hostProxy) + return KERN_FAILURE; + + NetscapePluginInstanceProxy* instanceProxy = hostProxy->pluginInstance(pluginID); + if (!instanceProxy) + return KERN_FAILURE; + + uint32_t objectID; + if (!instanceProxy->getPluginElementNPObject(objectID)) + return KERN_FAILURE; + + *outObjectID = objectID; + return KERN_SUCCESS; +} + +kern_return_t WKPCForgetBrowserObject(mach_port_t clientPort, uint32_t pluginID, uint32_t objectID) +{ + NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort); + if (!hostProxy) + return KERN_FAILURE; + + NetscapePluginInstanceProxy* instanceProxy = hostProxy->pluginInstance(pluginID); + if (!instanceProxy) + return KERN_FAILURE; + + return instanceProxy->forgetBrowserObjectID(objectID) ? KERN_SUCCESS : KERN_FAILURE; +} + +kern_return_t WKPCEvaluate(mach_port_t clientPort, uint32_t pluginID, uint32_t requestID, uint32_t objectID, data_t scriptData, mach_msg_type_number_t scriptLength, boolean_t allowPopups) +{ + DataDeallocator deallocator(scriptData, scriptLength); + + NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort); + if (!hostProxy) + return KERN_FAILURE; + + NetscapePluginInstanceProxy* instanceProxy = hostProxy->pluginInstance(pluginID); + if (!instanceProxy) + return KERN_FAILURE; + + PluginDestroyDeferrer deferrer(instanceProxy); + + String script = String::fromUTF8WithLatin1Fallback(scriptData, scriptLength); + + data_t resultData = 0; + mach_msg_type_number_t resultLength = 0; + boolean_t returnValue = instanceProxy->evaluate(objectID, script, resultData, resultLength, allowPopups); + + hostProxy = instanceProxy->hostProxy(); + if (!hostProxy) + return KERN_FAILURE; + + _WKPHBooleanAndDataReply(hostProxy->port(), instanceProxy->pluginID(), requestID, returnValue, resultData, resultLength); + if (resultData) + mig_deallocate(reinterpret_cast<vm_address_t>(resultData), resultLength); + + return KERN_SUCCESS; +} + +kern_return_t WKPCGetStringIdentifier(mach_port_t clientPort, data_t name, mach_msg_type_number_t nameCnt, uint64_t* identifier) +{ + DataDeallocator deallocator(name, nameCnt); + + COMPILE_ASSERT(sizeof(*identifier) == sizeof(IdentifierRep*), identifier_sizes); + + *identifier = reinterpret_cast<uint64_t>(IdentifierRep::get(name)); + return KERN_SUCCESS; +} + +kern_return_t WKPCGetIntIdentifier(mach_port_t clientPort, int32_t value, uint64_t* identifier) +{ + COMPILE_ASSERT(sizeof(*identifier) == sizeof(NPIdentifier), identifier_sizes); + + *identifier = reinterpret_cast<uint64_t>(IdentifierRep::get(value)); + return KERN_SUCCESS; +} + +static Identifier identifierFromIdentifierRep(IdentifierRep* identifier) +{ + ASSERT(IdentifierRep::isValid(identifier)); + ASSERT(identifier->isString()); + + const char* str = identifier->string(); + return Identifier(JSDOMWindow::commonJSGlobalData(), stringToUString(String::fromUTF8WithLatin1Fallback(str, strlen(str)))); +} + +kern_return_t WKPCInvoke(mach_port_t clientPort, uint32_t pluginID, uint32_t requestID, uint32_t objectID, uint64_t serverIdentifier, + data_t argumentsData, mach_msg_type_number_t argumentsLength) +{ + DataDeallocator deallocator(argumentsData, argumentsLength); + + NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort); + if (!hostProxy) + return KERN_FAILURE; + + NetscapePluginInstanceProxy* instanceProxy = hostProxy->pluginInstance(pluginID); + if (!instanceProxy) + return KERN_FAILURE; + + PluginDestroyDeferrer deferrer(instanceProxy); + + IdentifierRep* identifier = reinterpret_cast<IdentifierRep*>(serverIdentifier); + if (!IdentifierRep::isValid(identifier)) + return KERN_FAILURE; + + Identifier methodNameIdentifier = identifierFromIdentifierRep(identifier); + + data_t resultData = 0; + mach_msg_type_number_t resultLength = 0; + boolean_t returnValue = instanceProxy->invoke(objectID, methodNameIdentifier, argumentsData, argumentsLength, resultData, resultLength); + + hostProxy = instanceProxy->hostProxy(); + if (!hostProxy) + return KERN_FAILURE; + + _WKPHBooleanAndDataReply(hostProxy->port(), instanceProxy->pluginID(), requestID, returnValue, resultData, resultLength); + if (resultData) + mig_deallocate(reinterpret_cast<vm_address_t>(resultData), resultLength); + + return KERN_SUCCESS; +} + +kern_return_t WKPCInvokeDefault(mach_port_t clientPort, uint32_t pluginID, uint32_t requestID, uint32_t objectID, + data_t argumentsData, mach_msg_type_number_t argumentsLength) +{ + DataDeallocator deallocator(argumentsData, argumentsLength); + + NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort); + if (!hostProxy) + return KERN_FAILURE; + + NetscapePluginInstanceProxy* instanceProxy = hostProxy->pluginInstance(pluginID); + if (!instanceProxy) + return KERN_FAILURE; + + PluginDestroyDeferrer deferrer(instanceProxy); + + data_t resultData = 0; + mach_msg_type_number_t resultLength = 0; + boolean_t returnValue = instanceProxy->invokeDefault(objectID, argumentsData, argumentsLength, resultData, resultLength); + + hostProxy = instanceProxy->hostProxy(); + if (!hostProxy) + return KERN_FAILURE; + + _WKPHBooleanAndDataReply(hostProxy->port(), instanceProxy->pluginID(), requestID, returnValue, resultData, resultLength); + if (resultData) + mig_deallocate(reinterpret_cast<vm_address_t>(resultData), resultLength); + + return KERN_SUCCESS; +} + +kern_return_t WKPCConstruct(mach_port_t clientPort, uint32_t pluginID, uint32_t objectID, + data_t argumentsData, mach_msg_type_number_t argumentsLength, + boolean_t* returnValue, data_t* resultData, mach_msg_type_number_t* resultLength) +{ + DataDeallocator deallocator(argumentsData, argumentsLength); + + NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort); + if (!hostProxy) + return KERN_FAILURE; + + NetscapePluginInstanceProxy* instanceProxy = hostProxy->pluginInstance(pluginID); + if (!instanceProxy) + return KERN_FAILURE; + + PluginDestroyDeferrer deferrer(instanceProxy); + + *returnValue = instanceProxy->construct(objectID, argumentsData, argumentsLength, *resultData, *resultLength); + + return KERN_SUCCESS; +} + +kern_return_t WKPCGetProperty(mach_port_t clientPort, uint32_t pluginID, uint32_t requestID, uint32_t objectID, uint64_t serverIdentifier) +{ + NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort); + if (!hostProxy) + return KERN_FAILURE; + + NetscapePluginInstanceProxy* instanceProxy = hostProxy->pluginInstance(pluginID); + if (!instanceProxy) + return KERN_FAILURE; + + IdentifierRep* identifier = reinterpret_cast<IdentifierRep*>(serverIdentifier); + if (!IdentifierRep::isValid(identifier)) + return KERN_FAILURE; + + PluginDestroyDeferrer deferrer(instanceProxy); + + data_t resultData = 0; + mach_msg_type_number_t resultLength = 0; + boolean_t returnValue; + + if (identifier->isString()) { + Identifier propertyNameIdentifier = identifierFromIdentifierRep(identifier); + returnValue = instanceProxy->getProperty(objectID, propertyNameIdentifier, resultData, resultLength); + } else + returnValue = instanceProxy->setProperty(objectID, identifier->number(), resultData, resultLength); + + hostProxy = instanceProxy->hostProxy(); + if (!hostProxy) + return KERN_FAILURE; + + _WKPHBooleanAndDataReply(hostProxy->port(), instanceProxy->pluginID(), requestID, returnValue, resultData, resultLength); + if (resultData) + mig_deallocate(reinterpret_cast<vm_address_t>(resultData), resultLength); + + return KERN_SUCCESS; +} + +kern_return_t WKPCSetProperty(mach_port_t clientPort, uint32_t pluginID, uint32_t requestID, uint32_t objectID, uint64_t serverIdentifier, data_t valueData, mach_msg_type_number_t valueLength) +{ + DataDeallocator deallocator(valueData, valueLength); + + NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort); + if (!hostProxy) + return KERN_FAILURE; + + NetscapePluginInstanceProxy* instanceProxy = hostProxy->pluginInstance(pluginID); + if (!instanceProxy) + return KERN_FAILURE; + + PluginDestroyDeferrer deferrer(instanceProxy); + + IdentifierRep* identifier = reinterpret_cast<IdentifierRep*>(serverIdentifier); + if (!IdentifierRep::isValid(identifier)) + return KERN_FAILURE; + + bool result; + if (identifier->isString()) { + Identifier propertyNameIdentifier = identifierFromIdentifierRep(identifier); + result = instanceProxy->setProperty(objectID, propertyNameIdentifier, valueData, valueLength); + } else + result = instanceProxy->setProperty(objectID, identifier->number(), valueData, valueLength); + + hostProxy = instanceProxy->hostProxy(); + if (!hostProxy) + return KERN_FAILURE; + + _WKPHBooleanReply(hostProxy->port(), instanceProxy->pluginID(), requestID, result); + + return KERN_SUCCESS; +} + +kern_return_t WKPCRemoveProperty(mach_port_t clientPort, uint32_t pluginID, uint32_t requestID, uint32_t objectID, uint64_t serverIdentifier) +{ + NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort); + if (!hostProxy) + return KERN_FAILURE; + + NetscapePluginInstanceProxy* instanceProxy = hostProxy->pluginInstance(pluginID); + if (!instanceProxy) + return KERN_FAILURE; + + PluginDestroyDeferrer deferrer(instanceProxy); + + IdentifierRep* identifier = reinterpret_cast<IdentifierRep*>(serverIdentifier); + if (!IdentifierRep::isValid(identifier)) + return KERN_FAILURE; + + bool result; + if (identifier->isString()) { + Identifier propertyNameIdentifier = identifierFromIdentifierRep(identifier); + result = instanceProxy->removeProperty(objectID, propertyNameIdentifier); + } else + result = instanceProxy->removeProperty(objectID, identifier->number()); + + hostProxy = instanceProxy->hostProxy(); + if (!hostProxy) + return KERN_FAILURE; + + _WKPHBooleanReply(hostProxy->port(), instanceProxy->pluginID(), requestID, result); + + return KERN_SUCCESS; +} + +kern_return_t WKPCHasProperty(mach_port_t clientPort, uint32_t pluginID, uint32_t requestID, uint32_t objectID, uint64_t serverIdentifier) +{ + NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort); + if (!hostProxy) + return KERN_FAILURE; + + NetscapePluginInstanceProxy* instanceProxy = hostProxy->pluginInstance(pluginID); + if (!instanceProxy) + return KERN_FAILURE; + + PluginDestroyDeferrer deferrer(instanceProxy); + + IdentifierRep* identifier = reinterpret_cast<IdentifierRep*>(serverIdentifier); + if (!IdentifierRep::isValid(identifier)) + return KERN_FAILURE; + + boolean_t returnValue; + if (identifier->isString()) { + Identifier propertyNameIdentifier = identifierFromIdentifierRep(identifier); + returnValue = instanceProxy->hasProperty(objectID, propertyNameIdentifier); + } else + returnValue = instanceProxy->hasProperty(objectID, identifier->number()); + + hostProxy = instanceProxy->hostProxy(); + if (!hostProxy) + return KERN_FAILURE; + + _WKPHBooleanReply(hostProxy->port(), instanceProxy->pluginID(), requestID, returnValue); + + return KERN_SUCCESS; +} + +kern_return_t WKPCHasMethod(mach_port_t clientPort, uint32_t pluginID, uint32_t requestID, uint32_t objectID, uint64_t serverIdentifier) +{ + NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort); + if (!hostProxy) + return KERN_FAILURE; + + NetscapePluginInstanceProxy* instanceProxy = hostProxy->pluginInstance(pluginID); + if (!instanceProxy) + return KERN_FAILURE; + + PluginDestroyDeferrer deferrer(instanceProxy); + + IdentifierRep* identifier = reinterpret_cast<IdentifierRep*>(serverIdentifier); + if (!IdentifierRep::isValid(identifier)) + return KERN_FAILURE; + + Identifier methodNameIdentifier = identifierFromIdentifierRep(identifier); + boolean_t returnValue = instanceProxy->hasMethod(objectID, methodNameIdentifier); + + hostProxy = instanceProxy->hostProxy(); + if (!hostProxy) + return KERN_FAILURE; + + _WKPHBooleanReply(hostProxy->port(), instanceProxy->pluginID(), requestID, returnValue); + + return KERN_SUCCESS; +} + +kern_return_t WKPCIdentifierInfo(mach_port_t clientPort, uint64_t serverIdentifier, data_t* infoData, mach_msg_type_number_t* infoLength) +{ + IdentifierRep* identifier = reinterpret_cast<IdentifierRep*>(serverIdentifier); + if (!IdentifierRep::isValid(identifier)) + return KERN_FAILURE; + + id info; + if (identifier->isString()) { + const char* str = identifier->string(); + info = [NSData dataWithBytesNoCopy:(void*)str length:strlen(str) freeWhenDone:NO]; + } else + info = [NSNumber numberWithInt:identifier->number()]; + + RetainPtr<NSData*> data = [NSPropertyListSerialization dataFromPropertyList:info format:NSPropertyListBinaryFormat_v1_0 errorDescription:0]; + ASSERT(data); + + *infoLength = [data.get() length]; + mig_allocate(reinterpret_cast<vm_address_t*>(infoData), *infoLength); + + memcpy(*infoData, [data.get() bytes], *infoLength); + + return KERN_SUCCESS; +} + +kern_return_t WKPCEnumerate(mach_port_t clientPort, uint32_t pluginID, uint32_t requestID, uint32_t objectID) +{ + NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort); + if (!hostProxy) + return KERN_FAILURE; + + NetscapePluginInstanceProxy* instanceProxy = hostProxy->pluginInstance(pluginID); + if (!instanceProxy) + return KERN_FAILURE; + + data_t resultData = 0; + mach_msg_type_number_t resultLength = 0; + boolean_t returnValue = instanceProxy->enumerate(objectID, resultData, resultLength); + + hostProxy = instanceProxy->hostProxy(); + if (!hostProxy) + return KERN_FAILURE; + + _WKPHBooleanAndDataReply(hostProxy->port(), instanceProxy->pluginID(), requestID, returnValue, resultData, resultLength); + + if (resultData) + mig_deallocate(reinterpret_cast<vm_address_t>(resultData), resultLength); + + return KERN_SUCCESS; +} + +kern_return_t WKPCSetMenuBarVisible(mach_port_t clientPort, boolean_t menuBarVisible) +{ + NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort); + if (!hostProxy) + return KERN_FAILURE; + + hostProxy->setMenuBarVisible(menuBarVisible); + + return KERN_SUCCESS; +} + +kern_return_t WKPCSetFullscreenWindowIsShowing(mach_port_t clientPort, boolean_t fullscreenWindowIsShowing) +{ + NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort); + if (!hostProxy) + return KERN_FAILURE; + + hostProxy->setFullscreenWindowIsShowing(fullscreenWindowIsShowing); + + return KERN_SUCCESS; +} + +kern_return_t WKPCSetModal(mach_port_t clientPort, boolean_t modal) +{ + NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort); + if (!hostProxy) + return KERN_FAILURE; + + if (!hostProxy->isProcessingRequests()) { + hostProxy->setModal(modal); + return KERN_SUCCESS; + } + + // Defer the work + CFRunLoopPerformBlock(CFRunLoopGetMain(), kCFRunLoopDefaultMode, ^{ + if (NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort)) + hostProxy->setModal(modal); + }); + + return KERN_SUCCESS; +} + +kern_return_t WKPCGetCookies(mach_port_t clientPort, uint32_t pluginID, + data_t urlData, mach_msg_type_number_t urlLength, + boolean_t* returnValue, data_t* cookiesData, mach_msg_type_number_t* cookiesLength) +{ + *cookiesData = 0; + *cookiesLength = 0; + + DataDeallocator deallocator(urlData, urlLength); + + NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort); + if (!hostProxy) + return KERN_FAILURE; + + NetscapePluginInstanceProxy* instanceProxy = hostProxy->pluginInstance(pluginID); + if (!instanceProxy) + return KERN_FAILURE; + + *returnValue = instanceProxy->getCookies(urlData, urlLength, *cookiesData, *cookiesLength); + + return KERN_SUCCESS; +} + +kern_return_t WKPCGetProxy(mach_port_t clientPort, uint32_t pluginID, + data_t urlData, mach_msg_type_number_t urlLength, + boolean_t* returnValue, data_t* proxyData, mach_msg_type_number_t* proxyLength) +{ + *proxyData = 0; + *proxyLength = 0; + + DataDeallocator deallocator(urlData, urlLength); + + NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort); + if (!hostProxy) + return KERN_FAILURE; + + NetscapePluginInstanceProxy* instanceProxy = hostProxy->pluginInstance(pluginID); + if (!instanceProxy) + return KERN_FAILURE; + + *returnValue = instanceProxy->getProxy(urlData, urlLength, *proxyData, *proxyLength); + + return KERN_SUCCESS; +} + +kern_return_t WKPCSetCookies(mach_port_t clientPort, uint32_t pluginID, + data_t urlData, mach_msg_type_number_t urlLength, + data_t cookiesData, mach_msg_type_number_t cookiesLength, + boolean_t* returnValue) +{ + DataDeallocator urlDeallocator(urlData, urlLength); + DataDeallocator cookiesDeallocator(cookiesData, cookiesLength); + + NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort); + if (!hostProxy) + return KERN_FAILURE; + + NetscapePluginInstanceProxy* instanceProxy = hostProxy->pluginInstance(pluginID); + if (!instanceProxy) + return KERN_FAILURE; + + *returnValue = instanceProxy->setCookies(urlData, urlLength, cookiesData, cookiesLength); + return KERN_SUCCESS; +} + +kern_return_t WKPCGetAuthenticationInfo(mach_port_t clientPort, uint32_t pluginID, + data_t protocolData, mach_msg_type_number_t protocolLength, + data_t hostData, mach_msg_type_number_t hostLength, + uint32_t port, + data_t schemeData, mach_msg_type_number_t schemeLength, + data_t realmData, mach_msg_type_number_t realmLength, + boolean_t* returnValue, + data_t* usernameData, mach_msg_type_number_t *usernameLength, + data_t* passwordData, mach_msg_type_number_t *passwordLength) +{ + DataDeallocator protocolDeallocator(protocolData, protocolLength); + DataDeallocator hostDeallocator(hostData, hostLength); + DataDeallocator schemeDeallocator(schemeData, schemeLength); + DataDeallocator realmDeallocator(realmData, realmLength); + + *usernameData = 0; + *usernameLength = 0; + *passwordData = 0; + *passwordLength = 0; + + NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort); + if (!hostProxy) + return KERN_FAILURE; + + NetscapePluginInstanceProxy* instanceProxy = hostProxy->pluginInstance(pluginID); + if (!instanceProxy) + return KERN_FAILURE; + + *returnValue = instanceProxy->getAuthenticationInfo(protocolData, hostData, port, schemeData, realmData, *usernameData, *usernameLength, *passwordData, *passwordLength); + + return KERN_SUCCESS; +} + +kern_return_t WKPCConvertPoint(mach_port_t clientPort, uint32_t pluginID, + double sourceX, double sourceY, uint32_t sourceSpace, + uint32_t destSpace, boolean_t *returnValue, double *destX, double *destY) +{ + NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort); + if (!hostProxy) + return KERN_FAILURE; + + NetscapePluginInstanceProxy* instanceProxy = hostProxy->pluginInstance(pluginID); + if (!instanceProxy) + return KERN_FAILURE; + + *returnValue = instanceProxy->convertPoint(sourceX, sourceY, static_cast<NPCoordinateSpace>(sourceSpace), + *destX, *destY, static_cast<NPCoordinateSpace>(destSpace)); + return KERN_SUCCESS; +} + +kern_return_t WKPCCheckIfAllowedToLoadURL(mach_port_t clientPort, uint32_t pluginID, data_t urlData, mach_msg_type_number_t urlLength, + data_t targetData, mach_msg_type_number_t targetLength, uint32_t *checkID) +{ + DataDeallocator urlDeallocator(urlData, urlLength); + DataDeallocator targetDeallocator(targetData, targetLength); + + NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort); + if (!hostProxy) + return KERN_FAILURE; + + NetscapePluginInstanceProxy* instanceProxy = hostProxy->pluginInstance(pluginID); + if (!instanceProxy) + return KERN_FAILURE; + + *checkID = instanceProxy->checkIfAllowedToLoadURL(urlData, targetData); + return KERN_SUCCESS; +} + +kern_return_t WKPCCancelCheckIfAllowedToLoadURL(mach_port_t clientPort, uint32_t pluginID, uint32_t checkID) +{ + NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort); + if (!hostProxy) + return KERN_FAILURE; + + NetscapePluginInstanceProxy* instanceProxy = hostProxy->pluginInstance(pluginID); + if (!instanceProxy) + return KERN_FAILURE; + + instanceProxy->cancelCheckIfAllowedToLoadURL(checkID); + return KERN_SUCCESS; +} + +kern_return_t WKPCResolveURL(mach_port_t clientPort, uint32_t pluginID, data_t urlData, mach_msg_type_number_t urlLength, + data_t targetData, mach_msg_type_number_t targetLength, + data_t *resolvedURLData, mach_msg_type_number_t *resolvedURLLength) +{ + DataDeallocator urlDeallocator(urlData, urlLength); + DataDeallocator targetDeallocator(targetData, targetLength); + + *resolvedURLData = 0; + *resolvedURLLength = 0; + + NetscapePluginHostProxy* hostProxy = pluginProxyMap().get(clientPort); + if (!hostProxy) + return KERN_FAILURE; + + NetscapePluginInstanceProxy* instanceProxy = hostProxy->pluginInstance(pluginID); + if (!instanceProxy) + return KERN_FAILURE; + + instanceProxy->resolveURL(urlData, targetData, *resolvedURLData, *resolvedURLLength); + return KERN_SUCCESS; +} + +kern_return_t WKPCSetException(mach_port_t clientPort, data_t message, mach_msg_type_number_t messageCnt) +{ + DataDeallocator deallocator(message, messageCnt); + + string str(message, messageCnt); + NetscapePluginInstanceProxy::setGlobalException(str.c_str()); + + return KERN_SUCCESS; +} + +#endif // USE(PLUGIN_HOST_PROCESS) && ENABLE(NETSCAPE_PLUGIN_API) diff --git a/Source/WebKit/mac/Plugins/Hosted/NetscapePluginInstanceProxy.h b/Source/WebKit/mac/Plugins/Hosted/NetscapePluginInstanceProxy.h new file mode 100644 index 0000000..f784ade --- /dev/null +++ b/Source/WebKit/mac/Plugins/Hosted/NetscapePluginInstanceProxy.h @@ -0,0 +1,372 @@ +/* + * 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/Protect.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 : Noncopyable { + public: + LocalObjectMap(); + ~LocalObjectMap(); + uint32_t idForObject(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::ProtectedPtr<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) diff --git a/Source/WebKit/mac/Plugins/Hosted/NetscapePluginInstanceProxy.mm b/Source/WebKit/mac/Plugins/Hosted/NetscapePluginInstanceProxy.mm new file mode 100644 index 0000000..ecaa0d6 --- /dev/null +++ b/Source/WebKit/mac/Plugins/Hosted/NetscapePluginInstanceProxy.mm @@ -0,0 +1,1684 @@ +/* + * 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) && ENABLE(NETSCAPE_PLUGIN_API) + +#import "NetscapePluginInstanceProxy.h" + +#import "HostedNetscapePluginStream.h" +#import "NetscapePluginHostProxy.h" +#import "ProxyInstance.h" +#import "ProxyRuntimeObject.h" +#import "WebDataSourceInternal.h" +#import "WebFrameInternal.h" +#import "WebHostedNetscapePluginView.h" +#import "WebKitNSStringExtras.h" +#import "WebNSDataExtras.h" +#import "WebNSURLExtras.h" +#import "WebPluginRequest.h" +#import "WebUIDelegate.h" +#import "WebUIDelegatePrivate.h" +#import "WebViewInternal.h" +#import <JavaScriptCore/Error.h> +#import <JavaScriptCore/JSLock.h> +#import <JavaScriptCore/PropertyNameArray.h> +#import <WebCore/CookieJar.h> +#import <WebCore/DocumentLoader.h> +#import <WebCore/Frame.h> +#import <WebCore/FrameLoader.h> +#import <WebCore/FrameTree.h> +#import <WebCore/KURL.h> +#import <WebCore/ProxyServer.h> +#import <WebCore/SecurityOrigin.h> +#import <WebCore/ScriptController.h> +#import <WebCore/ScriptValue.h> +#import <WebCore/StringSourceProvider.h> +#import <WebCore/npruntime_impl.h> +#import <WebCore/runtime_object.h> +#import <WebKitSystemInterface.h> +#import <mach/mach.h> +#import <utility> +#import <wtf/RefCountedLeakCounter.h> +#import <wtf/text/CString.h> + +extern "C" { +#import "WebKitPluginClientServer.h" +#import "WebKitPluginHost.h" +} + +using namespace JSC; +using namespace JSC::Bindings; +using namespace std; +using namespace WebCore; + +namespace WebKit { + +class NetscapePluginInstanceProxy::PluginRequest : public RefCounted<NetscapePluginInstanceProxy::PluginRequest> { +public: + static PassRefPtr<PluginRequest> create(uint32_t requestID, NSURLRequest* request, NSString* frameName, bool allowPopups) + { + return adoptRef(new PluginRequest(requestID, request, frameName, allowPopups)); + } + + uint32_t requestID() const { return m_requestID; } + NSURLRequest* request() const { return m_request.get(); } + NSString* frameName() const { return m_frameName.get(); } + bool allowPopups() const { return m_allowPopups; } + +private: + PluginRequest(uint32_t requestID, NSURLRequest* request, NSString* frameName, bool allowPopups) + : m_requestID(requestID) + , m_request(request) + , m_frameName(frameName) + , m_allowPopups(allowPopups) + { + } + + uint32_t m_requestID; + RetainPtr<NSURLRequest*> m_request; + RetainPtr<NSString*> m_frameName; + bool m_allowPopups; +}; + +NetscapePluginInstanceProxy::LocalObjectMap::LocalObjectMap() + : m_objectIDCounter(0) +{ +} + +NetscapePluginInstanceProxy::LocalObjectMap::~LocalObjectMap() +{ +} + +inline bool NetscapePluginInstanceProxy::LocalObjectMap::contains(uint32_t objectID) const +{ + return m_idToJSObjectMap.contains(objectID); +} + +inline JSC::JSObject* NetscapePluginInstanceProxy::LocalObjectMap::get(uint32_t objectID) const +{ + if (objectID == HashTraits<uint32_t>::emptyValue() || HashTraits<uint32_t>::isDeletedValue(objectID)) + return 0; + + return m_idToJSObjectMap.get(objectID); +} + +uint32_t NetscapePluginInstanceProxy::LocalObjectMap::idForObject(JSObject* object) +{ + // This method creates objects with refcount of 1, but doesn't increase refcount when returning + // found objects. This extra count accounts for the main "reference" kept by plugin process. + + // To avoid excessive IPC, plugin process doesn't send each NPObject release/retain call to + // Safari. It only sends one when the last reference is removed, and it can destroy the proxy + // NPObject. + + // However, the browser may be sending the same object out to plug-in as a function call + // argument at the same time - neither side can know what the other one is doing. So, + // is to make PCForgetBrowserObject call return a boolean result, making it possible for + // the browser to make plugin host keep the proxy with zero refcount for a little longer. + + uint32_t objectID = 0; + + HashMap<JSC::JSObject*, pair<uint32_t, uint32_t> >::iterator iter = m_jsObjectToIDMap.find(object); + if (iter != m_jsObjectToIDMap.end()) + return iter->second.first; + + do { + objectID = ++m_objectIDCounter; + } while (!m_objectIDCounter || m_objectIDCounter == static_cast<uint32_t>(-1) || m_idToJSObjectMap.contains(objectID)); + + m_idToJSObjectMap.set(objectID, object); + m_jsObjectToIDMap.set(object, make_pair<uint32_t, uint32_t>(objectID, 1)); + + return objectID; +} + +void NetscapePluginInstanceProxy::LocalObjectMap::retain(JSC::JSObject* object) +{ + HashMap<JSC::JSObject*, pair<uint32_t, uint32_t> >::iterator iter = m_jsObjectToIDMap.find(object); + ASSERT(iter != m_jsObjectToIDMap.end()); + + iter->second.second = iter->second.second + 1; +} + +void NetscapePluginInstanceProxy::LocalObjectMap::release(JSC::JSObject* object) +{ + HashMap<JSC::JSObject*, pair<uint32_t, uint32_t> >::iterator iter = m_jsObjectToIDMap.find(object); + ASSERT(iter != m_jsObjectToIDMap.end()); + + ASSERT(iter->second.second > 0); + iter->second.second = iter->second.second - 1; + if (!iter->second.second) { + m_idToJSObjectMap.remove(iter->second.first); + m_jsObjectToIDMap.remove(iter); + } +} + +void NetscapePluginInstanceProxy::LocalObjectMap::clear() +{ + m_idToJSObjectMap.clear(); + m_jsObjectToIDMap.clear(); +} + +bool NetscapePluginInstanceProxy::LocalObjectMap::forget(uint32_t objectID) +{ + if (objectID == HashTraits<uint32_t>::emptyValue() || HashTraits<uint32_t>::isDeletedValue(objectID)) { + LOG_ERROR("NetscapePluginInstanceProxy::LocalObjectMap::forget: local object id %u is not valid.", objectID); + return true; + } + + HashMap<uint32_t, JSC::ProtectedPtr<JSC::JSObject> >::iterator iter = m_idToJSObjectMap.find(objectID); + if (iter == m_idToJSObjectMap.end()) { + LOG_ERROR("NetscapePluginInstanceProxy::LocalObjectMap::forget: local object %u doesn't exist.", objectID); + return true; + } + + HashMap<JSC::JSObject*, pair<uint32_t, uint32_t> >::iterator rIter = m_jsObjectToIDMap.find(iter->second.get()); + + // If the object is being sent to plug-in right now, then it's not the time to forget. + if (rIter->second.second != 1) + return false; + + m_jsObjectToIDMap.remove(rIter); + m_idToJSObjectMap.remove(iter); + return true; +} + +static uint32_t pluginIDCounter; + +bool NetscapePluginInstanceProxy::m_inDestroy; + +#ifndef NDEBUG +static WTF::RefCountedLeakCounter netscapePluginInstanceProxyCounter("NetscapePluginInstanceProxy"); +#endif + +NetscapePluginInstanceProxy::NetscapePluginInstanceProxy(NetscapePluginHostProxy* pluginHostProxy, WebHostedNetscapePluginView *pluginView, bool fullFramePlugin) + : m_pluginHostProxy(pluginHostProxy) + , m_pluginView(pluginView) + , m_requestTimer(this, &NetscapePluginInstanceProxy::requestTimerFired) + , m_currentURLRequestID(0) + , m_renderContextID(0) + , m_rendererType(UseSoftwareRenderer) + , m_waitingForReply(false) + , m_urlCheckCounter(0) + , m_pluginFunctionCallDepth(0) + , m_shouldStopSoon(false) + , m_currentRequestID(0) + , m_pluginIsWaitingForDraw(false) +{ + ASSERT(m_pluginView); + + if (fullFramePlugin) { + // For full frame plug-ins, the first requestID will always be the one for the already + // open stream. + ++m_currentURLRequestID; + } + + // Assign a plug-in ID. + do { + m_pluginID = ++pluginIDCounter; + } while (pluginHostProxy->pluginInstance(m_pluginID) || !m_pluginID); + +#ifndef NDEBUG + netscapePluginInstanceProxyCounter.increment(); +#endif +} + +PassRefPtr<NetscapePluginInstanceProxy> NetscapePluginInstanceProxy::create(NetscapePluginHostProxy* pluginHostProxy, WebHostedNetscapePluginView *pluginView, bool fullFramePlugin) +{ + RefPtr<NetscapePluginInstanceProxy> proxy = adoptRef(new NetscapePluginInstanceProxy(pluginHostProxy, pluginView, fullFramePlugin)); + pluginHostProxy->addPluginInstance(proxy.get()); + return proxy.release(); +} + +NetscapePluginInstanceProxy::~NetscapePluginInstanceProxy() +{ + ASSERT(!m_pluginHostProxy); + + m_pluginID = 0; + deleteAllValues(m_replies); + +#ifndef NDEBUG + netscapePluginInstanceProxyCounter.decrement(); +#endif +} + +void NetscapePluginInstanceProxy::resize(NSRect size, NSRect clipRect) +{ + uint32_t requestID = 0; + + requestID = nextRequestID(); + + _WKPHResizePluginInstance(m_pluginHostProxy->port(), m_pluginID, requestID, + size.origin.x, size.origin.y, size.size.width, size.size.height, + clipRect.origin.x, clipRect.origin.y, clipRect.size.width, clipRect.size.height); + + waitForReply<NetscapePluginInstanceProxy::BooleanReply>(requestID); +} + +void NetscapePluginInstanceProxy::stopAllStreams() +{ + Vector<RefPtr<HostedNetscapePluginStream> > streamsCopy; + copyValuesToVector(m_streams, streamsCopy); + for (size_t i = 0; i < streamsCopy.size(); i++) + streamsCopy[i]->stop(); +} + +void NetscapePluginInstanceProxy::cleanup() +{ + stopAllStreams(); + + m_requestTimer.stop(); + + // Clear the object map, this will cause any outstanding JS objects that the plug-in had a reference to + // to go away when the next garbage collection takes place. + m_localObjects.clear(); + + if (Frame* frame = core([m_pluginView webFrame])) + frame->script()->cleanupScriptObjectsForPlugin(m_pluginView); + + ProxyInstanceSet instances; + instances.swap(m_instances); + + // Invalidate all proxy instances. + ProxyInstanceSet::const_iterator end = instances.end(); + for (ProxyInstanceSet::const_iterator it = instances.begin(); it != end; ++it) + (*it)->invalidate(); + + m_pluginView = nil; + m_manualStream = 0; +} + +void NetscapePluginInstanceProxy::invalidate() +{ + // If the plug-in host has died, the proxy will be null. + if (!m_pluginHostProxy) + return; + + m_pluginHostProxy->removePluginInstance(this); + m_pluginHostProxy = 0; +} + +void NetscapePluginInstanceProxy::destroy() +{ + uint32_t requestID = nextRequestID(); + + ASSERT(!m_inDestroy); + m_inDestroy = true; + + FrameLoadMap::iterator end = m_pendingFrameLoads.end(); + for (FrameLoadMap::iterator it = m_pendingFrameLoads.begin(); it != end; ++it) + [(it->first) _setInternalLoadDelegate:nil]; + + _WKPHDestroyPluginInstance(m_pluginHostProxy->port(), m_pluginID, requestID); + + // If the plug-in host crashes while we're waiting for a reply, the last reference to the instance proxy + // will go away. Prevent this by protecting it here. + RefPtr<NetscapePluginInstanceProxy> protect(this); + + // We don't care about the reply here - we just want to block until the plug-in instance has been torn down. + waitForReply<NetscapePluginInstanceProxy::BooleanReply>(requestID); + + m_inDestroy = false; + + cleanup(); + invalidate(); +} + +void NetscapePluginInstanceProxy::setManualStream(PassRefPtr<HostedNetscapePluginStream> manualStream) +{ + ASSERT(!m_manualStream); + + m_manualStream = manualStream; +} + +bool NetscapePluginInstanceProxy::cancelStreamLoad(uint32_t streamID, NPReason reason) +{ + HostedNetscapePluginStream* stream = 0; + + if (m_manualStream && streamID == 1) + stream = m_manualStream.get(); + else + stream = m_streams.get(streamID).get(); + + if (!stream) + return false; + + stream->cancelLoad(reason); + return true; +} + +void NetscapePluginInstanceProxy::disconnectStream(HostedNetscapePluginStream* stream) +{ + if (stream == m_manualStream) { + m_manualStream = 0; + return; + } + + ASSERT(m_streams.get(stream->streamID()) == stream); + m_streams.remove(stream->streamID()); +} + +void NetscapePluginInstanceProxy::pluginHostDied() +{ + m_pluginHostProxy = 0; + + [m_pluginView pluginHostDied]; + + cleanup(); +} + +void NetscapePluginInstanceProxy::focusChanged(bool hasFocus) +{ + _WKPHPluginInstanceFocusChanged(m_pluginHostProxy->port(), m_pluginID, hasFocus); +} + +void NetscapePluginInstanceProxy::windowFocusChanged(bool hasFocus) +{ + _WKPHPluginInstanceWindowFocusChanged(m_pluginHostProxy->port(), m_pluginID, hasFocus); +} + +void NetscapePluginInstanceProxy::windowFrameChanged(NSRect frame) +{ + _WKPHPluginInstanceWindowFrameChanged(m_pluginHostProxy->port(), m_pluginID, frame.origin.x, frame.origin.y, frame.size.width, frame.size.height, + NSMaxY([[[NSScreen screens] objectAtIndex:0] frame])); +} + +void NetscapePluginInstanceProxy::startTimers(bool throttleTimers) +{ + _WKPHPluginInstanceStartTimers(m_pluginHostProxy->port(), m_pluginID, throttleTimers); +} + +void NetscapePluginInstanceProxy::mouseEvent(NSView *pluginView, NSEvent *event, NPCocoaEventType type) +{ + NSPoint screenPoint = [[event window] convertBaseToScreen:[event locationInWindow]]; + NSPoint pluginPoint = [pluginView convertPoint:[event locationInWindow] fromView:nil]; + + int clickCount; + if (type == NPCocoaEventMouseEntered || type == NPCocoaEventMouseExited) + clickCount = 0; + else + clickCount = [event clickCount]; + + + _WKPHPluginInstanceMouseEvent(m_pluginHostProxy->port(), m_pluginID, + [event timestamp], + type, [event modifierFlags], + pluginPoint.x, pluginPoint.y, + screenPoint.x, screenPoint.y, + NSMaxY([[[NSScreen screens] objectAtIndex:0] frame]), + [event buttonNumber], clickCount, + [event deltaX], [event deltaY], [event deltaZ]); +} + +void NetscapePluginInstanceProxy::keyEvent(NSView *pluginView, NSEvent *event, NPCocoaEventType type) +{ + NSData *charactersData = [[event characters] dataUsingEncoding:NSUTF8StringEncoding]; + NSData *charactersIgnoringModifiersData = [[event charactersIgnoringModifiers] dataUsingEncoding:NSUTF8StringEncoding]; + + _WKPHPluginInstanceKeyboardEvent(m_pluginHostProxy->port(), m_pluginID, + [event timestamp], + type, [event modifierFlags], + const_cast<char*>(reinterpret_cast<const char*>([charactersData bytes])), [charactersData length], + const_cast<char*>(reinterpret_cast<const char*>([charactersIgnoringModifiersData bytes])), [charactersIgnoringModifiersData length], + [event isARepeat], [event keyCode], WKGetNSEventKeyChar(event)); +} + +void NetscapePluginInstanceProxy::syntheticKeyDownWithCommandModifier(int keyCode, char character) +{ + NSData *charactersData = [NSData dataWithBytes:&character length:1]; + + _WKPHPluginInstanceKeyboardEvent(m_pluginHostProxy->port(), m_pluginID, + [NSDate timeIntervalSinceReferenceDate], + NPCocoaEventKeyDown, NSCommandKeyMask, + const_cast<char*>(reinterpret_cast<const char*>([charactersData bytes])), [charactersData length], + const_cast<char*>(reinterpret_cast<const char*>([charactersData bytes])), [charactersData length], + false, keyCode, character); +} + +void NetscapePluginInstanceProxy::flagsChanged(NSEvent *event) +{ + _WKPHPluginInstanceKeyboardEvent(m_pluginHostProxy->port(), m_pluginID, + [event timestamp], NPCocoaEventFlagsChanged, + [event modifierFlags], 0, 0, 0, 0, false, [event keyCode], 0); +} + +void NetscapePluginInstanceProxy::insertText(NSString *text) +{ + NSData *textData = [text dataUsingEncoding:NSUTF8StringEncoding]; + + _WKPHPluginInstanceInsertText(m_pluginHostProxy->port(), m_pluginID, + const_cast<char*>(reinterpret_cast<const char*>([textData bytes])), [textData length]); +} + +bool NetscapePluginInstanceProxy::wheelEvent(NSView *pluginView, NSEvent *event) +{ + NSPoint pluginPoint = [pluginView convertPoint:[event locationInWindow] fromView:nil]; + + uint32_t requestID = nextRequestID(); + _WKPHPluginInstanceWheelEvent(m_pluginHostProxy->port(), m_pluginID, requestID, + [event timestamp], [event modifierFlags], + pluginPoint.x, pluginPoint.y, [event buttonNumber], + [event deltaX], [event deltaY], [event deltaZ]); + + auto_ptr<NetscapePluginInstanceProxy::BooleanReply> reply = waitForReply<NetscapePluginInstanceProxy::BooleanReply>(requestID); + if (!reply.get() || !reply->m_result) + return false; + + return true; +} + +void NetscapePluginInstanceProxy::print(CGContextRef context, unsigned width, unsigned height) +{ + uint32_t requestID = nextRequestID(); + _WKPHPluginInstancePrint(m_pluginHostProxy->port(), m_pluginID, requestID, width, height); + + auto_ptr<NetscapePluginInstanceProxy::BooleanAndDataReply> reply = waitForReply<NetscapePluginInstanceProxy::BooleanAndDataReply>(requestID); + if (!reply.get() || !reply->m_returnValue) + return; + + RetainPtr<CGDataProvider> dataProvider(AdoptCF, CGDataProviderCreateWithCFData(reply->m_result.get())); + RetainPtr<CGColorSpaceRef> colorSpace(AdoptCF, CGColorSpaceCreateDeviceRGB()); + RetainPtr<CGImageRef> image(AdoptCF, CGImageCreate(width, height, 8, 32, width * 4, colorSpace.get(), kCGImageAlphaFirst, dataProvider.get(), 0, false, kCGRenderingIntentDefault)); + + // Flip the context and draw the image. + CGContextSaveGState(context); + CGContextTranslateCTM(context, 0.0, height); + CGContextScaleCTM(context, 1.0, -1.0); + + CGContextDrawImage(context, CGRectMake(0, 0, width, height), image.get()); + + CGContextRestoreGState(context); +} + +void NetscapePluginInstanceProxy::snapshot(CGContextRef context, unsigned width, unsigned height) +{ + uint32_t requestID = nextRequestID(); + _WKPHPluginInstanceSnapshot(m_pluginHostProxy->port(), m_pluginID, requestID, width, height); + + auto_ptr<NetscapePluginInstanceProxy::BooleanAndDataReply> reply = waitForReply<NetscapePluginInstanceProxy::BooleanAndDataReply>(requestID); + if (!reply.get() || !reply->m_returnValue) + return; + + RetainPtr<CGDataProvider> dataProvider(AdoptCF, CGDataProviderCreateWithCFData(reply->m_result.get())); + RetainPtr<CGColorSpaceRef> colorSpace(AdoptCF, CGColorSpaceCreateDeviceRGB()); + RetainPtr<CGImageRef> image(AdoptCF, CGImageCreate(width, height, 8, 32, width * 4, colorSpace.get(), kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host, dataProvider.get(), 0, false, kCGRenderingIntentDefault)); + + CGContextDrawImage(context, CGRectMake(0, 0, width, height), image.get()); +} + +void NetscapePluginInstanceProxy::stopTimers() +{ + _WKPHPluginInstanceStopTimers(m_pluginHostProxy->port(), m_pluginID); +} + +void NetscapePluginInstanceProxy::status(const char* message) +{ + RetainPtr<CFStringRef> status(AdoptCF, CFStringCreateWithCString(0, message ? message : "", kCFStringEncodingUTF8)); + if (!status) + return; + + WebView *wv = [m_pluginView webView]; + [[wv _UIDelegateForwarder] webView:wv setStatusText:(NSString *)status.get()]; +} + +NPError NetscapePluginInstanceProxy::loadURL(const char* url, const char* target, const char* postData, uint32_t postLen, LoadURLFlags flags, uint32_t& streamID) +{ + if (!url) + return NPERR_INVALID_PARAM; + + NSMutableURLRequest *request = [m_pluginView requestWithURLCString:url]; + + if (flags & IsPost) { + NSData *httpBody = nil; + + if (flags & PostDataIsFile) { + // If we're posting a file, buf is either a file URL or a path to the file. + if (!postData) + return NPERR_INVALID_PARAM; + RetainPtr<CFStringRef> bufString(AdoptCF, CFStringCreateWithCString(kCFAllocatorDefault, postData, kCFStringEncodingWindowsLatin1)); + if (!bufString) + return NPERR_INVALID_PARAM; + + NSURL *fileURL = [NSURL _web_URLWithDataAsString:(NSString *)bufString.get()]; + NSString *path; + if ([fileURL isFileURL]) + path = [fileURL path]; + else + path = (NSString *)bufString.get(); + httpBody = [NSData dataWithContentsOfFile:[path _webkit_fixedCarbonPOSIXPath]]; + if (!httpBody) + return NPERR_FILE_NOT_FOUND; + } else + httpBody = [NSData dataWithBytes:postData length:postLen]; + + if (![httpBody length]) + return NPERR_INVALID_PARAM; + + [request setHTTPMethod:@"POST"]; + + if (flags & AllowHeadersInPostData) { + if ([httpBody _web_startsWithBlankLine]) + httpBody = [httpBody subdataWithRange:NSMakeRange(1, [httpBody length] - 1)]; + else { + NSInteger location = [httpBody _web_locationAfterFirstBlankLine]; + if (location != NSNotFound) { + // If the blank line is somewhere in the middle of postData, everything before is the header. + NSData *headerData = [httpBody subdataWithRange:NSMakeRange(0, location)]; + NSMutableDictionary *header = [headerData _webkit_parseRFC822HeaderFields]; + unsigned dataLength = [httpBody length] - location; + + // Sometimes plugins like to set Content-Length themselves when they post, + // but CFNetwork does not like that. So we will remove the header + // and instead truncate the data to the requested length. + NSString *contentLength = [header objectForKey:@"Content-Length"]; + + if (contentLength) + dataLength = min(static_cast<unsigned>([contentLength intValue]), dataLength); + [header removeObjectForKey:@"Content-Length"]; + + if ([header count] > 0) + [request setAllHTTPHeaderFields:header]; + + // Everything after the blank line is the actual content of the POST. + httpBody = [httpBody subdataWithRange:NSMakeRange(location, dataLength)]; + } + } + } + + if (![httpBody length]) + return NPERR_INVALID_PARAM; + + // Plug-ins expect to receive uncached data when doing a POST (3347134). + [request setCachePolicy:NSURLRequestReloadIgnoringCacheData]; + [request setHTTPBody:httpBody]; + } + + return loadRequest(request, target, flags & AllowPopups, streamID); +} + +void NetscapePluginInstanceProxy::performRequest(PluginRequest* pluginRequest) +{ + ASSERT(m_pluginView); + + NSURLRequest *request = pluginRequest->request(); + NSString *frameName = pluginRequest->frameName(); + WebFrame *frame = nil; + + NSURL *URL = [request URL]; + NSString *JSString = [URL _webkit_scriptIfJavaScriptURL]; + + ASSERT(frameName || JSString); + if (frameName) { + // FIXME - need to get rid of this window creation which + // bypasses normal targeted link handling + frame = kit(core([m_pluginView webFrame])->loader()->findFrameForNavigation(frameName)); + if (!frame) { + WebView *currentWebView = [m_pluginView webView]; + NSDictionary *features = [[NSDictionary alloc] init]; + WebView *newWebView = [[currentWebView _UIDelegateForwarder] webView:currentWebView + createWebViewWithRequest:nil + windowFeatures:features]; + [features release]; + + if (!newWebView) { + _WKPHLoadURLNotify(m_pluginHostProxy->port(), m_pluginID, pluginRequest->requestID(), NPERR_GENERIC_ERROR); + return; + } + + frame = [newWebView mainFrame]; + core(frame)->tree()->setName(frameName); + [[newWebView _UIDelegateForwarder] webViewShow:newWebView]; + } + } + + if (JSString) { + ASSERT(!frame || [m_pluginView webFrame] == frame); + evaluateJavaScript(pluginRequest); + } else { + [frame loadRequest:request]; + + // Check if another plug-in view or even this view is waiting for the frame to load. + // If it is, tell it that the load was cancelled because it will be anyway. + WebHostedNetscapePluginView *view = [frame _internalLoadDelegate]; + if (view != nil) { + ASSERT([view isKindOfClass:[WebHostedNetscapePluginView class]]); + [view webFrame:frame didFinishLoadWithReason:NPRES_USER_BREAK]; + } + m_pendingFrameLoads.set(frame, pluginRequest); + [frame _setInternalLoadDelegate:m_pluginView]; + } + +} + +void NetscapePluginInstanceProxy::webFrameDidFinishLoadWithReason(WebFrame* webFrame, NPReason reason) +{ + FrameLoadMap::iterator it = m_pendingFrameLoads.find(webFrame); + ASSERT(it != m_pendingFrameLoads.end()); + + PluginRequest* pluginRequest = it->second.get(); + _WKPHLoadURLNotify(m_pluginHostProxy->port(), m_pluginID, pluginRequest->requestID(), reason); + + m_pendingFrameLoads.remove(it); + + [webFrame _setInternalLoadDelegate:nil]; +} + +void NetscapePluginInstanceProxy::evaluateJavaScript(PluginRequest* pluginRequest) +{ + NSURL *URL = [pluginRequest->request() URL]; + NSString *JSString = [URL _webkit_scriptIfJavaScriptURL]; + ASSERT(JSString); + + NSString *result = [[m_pluginView webFrame] _stringByEvaluatingJavaScriptFromString:JSString forceUserGesture:pluginRequest->allowPopups()]; + + // Don't continue if stringByEvaluatingJavaScriptFromString caused the plug-in to stop. + if (!m_pluginHostProxy) + return; + + if (pluginRequest->frameName() != nil) + return; + + if ([result length] > 0) { + // Don't call NPP_NewStream and other stream methods if there is no JS result to deliver. This is what Mozilla does. + NSData *JSData = [result dataUsingEncoding:NSUTF8StringEncoding]; + + RefPtr<HostedNetscapePluginStream> stream = HostedNetscapePluginStream::create(this, pluginRequest->requestID(), pluginRequest->request()); + m_streams.add(stream->streamID(), stream); + + RetainPtr<NSURLResponse> response(AdoptNS, [[NSURLResponse alloc] initWithURL:URL + MIMEType:@"text/plain" + expectedContentLength:[JSData length] + textEncodingName:nil]); + stream->startStreamWithResponse(response.get()); + stream->didReceiveData(0, static_cast<const char*>([JSData bytes]), [JSData length]); + stream->didFinishLoading(0); + } +} + +void NetscapePluginInstanceProxy::requestTimerFired(Timer<NetscapePluginInstanceProxy>*) +{ + ASSERT(!m_pluginRequests.isEmpty()); + ASSERT(m_pluginView); + + RefPtr<PluginRequest> request = m_pluginRequests.first(); + m_pluginRequests.removeFirst(); + + if (!m_pluginRequests.isEmpty()) + m_requestTimer.startOneShot(0); + + performRequest(request.get()); +} + +NPError NetscapePluginInstanceProxy::loadRequest(NSURLRequest *request, const char* cTarget, bool allowPopups, uint32_t& requestID) +{ + NSURL *URL = [request URL]; + + if (!URL) + return NPERR_INVALID_URL; + + // Don't allow requests to be loaded when the document loader is stopping all loaders. + DocumentLoader* documentLoader = [[m_pluginView dataSource] _documentLoader]; + if (!documentLoader || documentLoader->isStopping()) + return NPERR_GENERIC_ERROR; + + NSString *target = nil; + if (cTarget) { + // Find the frame given the target string. + target = [NSString stringWithCString:cTarget encoding:NSISOLatin1StringEncoding]; + } + WebFrame *frame = [m_pluginView webFrame]; + + // don't let a plugin start any loads if it is no longer part of a document that is being + // displayed unless the loads are in the same frame as the plugin. + if (documentLoader != core([m_pluginView webFrame])->loader()->activeDocumentLoader() && + (!cTarget || [frame findFrameNamed:target] != frame)) { + return NPERR_GENERIC_ERROR; + } + + NSString *JSString = [URL _webkit_scriptIfJavaScriptURL]; + if (JSString != nil) { + if (![[[m_pluginView webView] preferences] isJavaScriptEnabled]) { + // Return NPERR_GENERIC_ERROR if JS is disabled. This is what Mozilla does. + return NPERR_GENERIC_ERROR; + } + } else { + if (!core([m_pluginView webFrame])->document()->securityOrigin()->canDisplay(URL)) + return NPERR_GENERIC_ERROR; + } + + // FIXME: Handle wraparound + requestID = ++m_currentURLRequestID; + + if (cTarget || JSString) { + // Make when targetting a frame or evaluating a JS string, perform the request after a delay because we don't + // want to potentially kill the plug-in inside of its URL request. + + if (JSString && target && [frame findFrameNamed:target] != frame) { + // For security reasons, only allow JS requests to be made on the frame that contains the plug-in. + return NPERR_INVALID_PARAM; + } + + RefPtr<PluginRequest> pluginRequest = PluginRequest::create(requestID, request, target, allowPopups); + m_pluginRequests.append(pluginRequest.release()); + m_requestTimer.startOneShot(0); + } else { + RefPtr<HostedNetscapePluginStream> stream = HostedNetscapePluginStream::create(this, requestID, request); + + ASSERT(!m_streams.contains(requestID)); + m_streams.add(requestID, stream); + stream->start(); + } + + return NPERR_NO_ERROR; +} + +NetscapePluginInstanceProxy::Reply* NetscapePluginInstanceProxy::processRequestsAndWaitForReply(uint32_t requestID) +{ + Reply* reply = 0; + + ASSERT(m_pluginHostProxy); + while (!(reply = m_replies.take(requestID))) { + if (!m_pluginHostProxy->processRequests()) + return 0; + + // The host proxy can be destroyed while executing a nested processRequests() call, in which case it's normal + // to get a success result, but be unable to keep looping. + if (!m_pluginHostProxy) + return 0; + } + + ASSERT(reply); + return reply; +} + +// NPRuntime support +bool NetscapePluginInstanceProxy::getWindowNPObject(uint32_t& objectID) +{ + Frame* frame = core([m_pluginView webFrame]); + if (!frame) + return false; + + if (!frame->script()->canExecuteScripts(NotAboutToExecuteScript)) + objectID = 0; + else + objectID = m_localObjects.idForObject(frame->script()->windowShell(pluginWorld())->window()); + + return true; +} + +bool NetscapePluginInstanceProxy::getPluginElementNPObject(uint32_t& objectID) +{ + Frame* frame = core([m_pluginView webFrame]); + if (!frame) + return false; + + if (JSObject* object = frame->script()->jsObjectForPluginElement([m_pluginView element])) + objectID = m_localObjects.idForObject(object); + else + objectID = 0; + + return true; +} + +bool NetscapePluginInstanceProxy::forgetBrowserObjectID(uint32_t objectID) +{ + return m_localObjects.forget(objectID); +} + +bool NetscapePluginInstanceProxy::evaluate(uint32_t objectID, const String& script, data_t& resultData, mach_msg_type_number_t& resultLength, bool allowPopups) +{ + resultData = 0; + resultLength = 0; + + if (m_inDestroy) + return false; + + if (!m_localObjects.contains(objectID)) { + LOG_ERROR("NetscapePluginInstanceProxy::evaluate: local object %u doesn't exist.", objectID); + return false; + } + + Frame* frame = core([m_pluginView webFrame]); + if (!frame) + return false; + + JSLock lock(SilenceAssertionsOnly); + + ProtectedPtr<JSGlobalObject> globalObject = frame->script()->globalObject(pluginWorld()); + ExecState* exec = globalObject->globalExec(); + + bool oldAllowPopups = frame->script()->allowPopupsFromPlugin(); + frame->script()->setAllowPopupsFromPlugin(allowPopups); + + globalObject->globalData().timeoutChecker.start(); + Completion completion = JSC::evaluate(exec, globalObject->globalScopeChain(), makeSource(script)); + globalObject->globalData().timeoutChecker.stop(); + ComplType type = completion.complType(); + + frame->script()->setAllowPopupsFromPlugin(oldAllowPopups); + + JSValue result; + if (type == Normal) + result = completion.value(); + + if (!result) + result = jsUndefined(); + + marshalValue(exec, result, resultData, resultLength); + exec->clearException(); + return true; +} + +bool NetscapePluginInstanceProxy::invoke(uint32_t objectID, const Identifier& methodName, data_t argumentsData, mach_msg_type_number_t argumentsLength, data_t& resultData, mach_msg_type_number_t& resultLength) +{ + resultData = 0; + resultLength = 0; + + if (m_inDestroy) + return false; + + JSObject* object = m_localObjects.get(objectID); + if (!object) { + LOG_ERROR("NetscapePluginInstanceProxy::invoke: local object %u doesn't exist.", objectID); + return false; + } + + Frame* frame = core([m_pluginView webFrame]); + if (!frame) + return false; + + ExecState* exec = frame->script()->globalObject(pluginWorld())->globalExec(); + JSLock lock(SilenceAssertionsOnly); + JSValue function = object->get(exec, methodName); + CallData callData; + CallType callType = getCallData(function, callData); + if (callType == CallTypeNone) + return false; + + MarkedArgumentBuffer argList; + demarshalValues(exec, argumentsData, argumentsLength, argList); + + ProtectedPtr<JSGlobalObject> globalObject = frame->script()->globalObject(pluginWorld()); + globalObject->globalData().timeoutChecker.start(); + JSValue value = call(exec, function, callType, callData, object, argList); + globalObject->globalData().timeoutChecker.stop(); + + marshalValue(exec, value, resultData, resultLength); + exec->clearException(); + return true; +} + +bool NetscapePluginInstanceProxy::invokeDefault(uint32_t objectID, data_t argumentsData, mach_msg_type_number_t argumentsLength, data_t& resultData, mach_msg_type_number_t& resultLength) +{ + if (m_inDestroy) + return false; + + JSObject* object = m_localObjects.get(objectID); + if (!object) { + LOG_ERROR("NetscapePluginInstanceProxy::invokeDefault: local object %u doesn't exist.", objectID); + return false; + } + + Frame* frame = core([m_pluginView webFrame]); + if (!frame) + return false; + + ExecState* exec = frame->script()->globalObject(pluginWorld())->globalExec(); + JSLock lock(SilenceAssertionsOnly); + CallData callData; + CallType callType = object->getCallData(callData); + if (callType == CallTypeNone) + return false; + + MarkedArgumentBuffer argList; + demarshalValues(exec, argumentsData, argumentsLength, argList); + + ProtectedPtr<JSGlobalObject> globalObject = frame->script()->globalObject(pluginWorld()); + globalObject->globalData().timeoutChecker.start(); + JSValue value = call(exec, object, callType, callData, object, argList); + globalObject->globalData().timeoutChecker.stop(); + + marshalValue(exec, value, resultData, resultLength); + exec->clearException(); + return true; +} + +bool NetscapePluginInstanceProxy::construct(uint32_t objectID, data_t argumentsData, mach_msg_type_number_t argumentsLength, data_t& resultData, mach_msg_type_number_t& resultLength) +{ + if (m_inDestroy) + return false; + + JSObject* object = m_localObjects.get(objectID); + if (!object) { + LOG_ERROR("NetscapePluginInstanceProxy::construct: local object %u doesn't exist.", objectID); + return false; + } + + Frame* frame = core([m_pluginView webFrame]); + if (!frame) + return false; + + ExecState* exec = frame->script()->globalObject(pluginWorld())->globalExec(); + JSLock lock(SilenceAssertionsOnly); + + ConstructData constructData; + ConstructType constructType = object->getConstructData(constructData); + if (constructType == ConstructTypeNone) + return false; + + MarkedArgumentBuffer argList; + demarshalValues(exec, argumentsData, argumentsLength, argList); + + ProtectedPtr<JSGlobalObject> globalObject = frame->script()->globalObject(pluginWorld()); + globalObject->globalData().timeoutChecker.start(); + JSValue value = JSC::construct(exec, object, constructType, constructData, argList); + globalObject->globalData().timeoutChecker.stop(); + + marshalValue(exec, value, resultData, resultLength); + exec->clearException(); + return true; +} + +bool NetscapePluginInstanceProxy::getProperty(uint32_t objectID, const Identifier& propertyName, data_t& resultData, mach_msg_type_number_t& resultLength) +{ + if (m_inDestroy) + return false; + + JSObject* object = m_localObjects.get(objectID); + if (!object) { + LOG_ERROR("NetscapePluginInstanceProxy::getProperty: local object %u doesn't exist.", objectID); + return false; + } + + Frame* frame = core([m_pluginView webFrame]); + if (!frame) + return false; + + ExecState* exec = frame->script()->globalObject(pluginWorld())->globalExec(); + JSLock lock(SilenceAssertionsOnly); + JSValue value = object->get(exec, propertyName); + + marshalValue(exec, value, resultData, resultLength); + exec->clearException(); + return true; +} + +bool NetscapePluginInstanceProxy::getProperty(uint32_t objectID, unsigned propertyName, data_t& resultData, mach_msg_type_number_t& resultLength) +{ + JSObject* object = m_localObjects.get(objectID); + if (!object) { + LOG_ERROR("NetscapePluginInstanceProxy::getProperty: local object %u doesn't exist.", objectID); + return false; + } + + Frame* frame = core([m_pluginView webFrame]); + if (!frame) + return false; + + ExecState* exec = frame->script()->globalObject(pluginWorld())->globalExec(); + JSLock lock(SilenceAssertionsOnly); + JSValue value = object->get(exec, propertyName); + + marshalValue(exec, value, resultData, resultLength); + exec->clearException(); + return true; +} + +bool NetscapePluginInstanceProxy::setProperty(uint32_t objectID, const Identifier& propertyName, data_t valueData, mach_msg_type_number_t valueLength) +{ + if (m_inDestroy) + return false; + + JSObject* object = m_localObjects.get(objectID); + if (!object) { + LOG_ERROR("NetscapePluginInstanceProxy::setProperty: local object %u doesn't exist.", objectID); + return false; + } + + Frame* frame = core([m_pluginView webFrame]); + if (!frame) + return false; + + ExecState* exec = frame->script()->globalObject(pluginWorld())->globalExec(); + JSLock lock(SilenceAssertionsOnly); + + JSValue value = demarshalValue(exec, valueData, valueLength); + PutPropertySlot slot; + object->put(exec, propertyName, value, slot); + + exec->clearException(); + return true; +} + +bool NetscapePluginInstanceProxy::setProperty(uint32_t objectID, unsigned propertyName, data_t valueData, mach_msg_type_number_t valueLength) +{ + if (m_inDestroy) + return false; + + JSObject* object = m_localObjects.get(objectID); + if (!object) { + LOG_ERROR("NetscapePluginInstanceProxy::setProperty: local object %u doesn't exist.", objectID); + return false; + } + + Frame* frame = core([m_pluginView webFrame]); + if (!frame) + return false; + + ExecState* exec = frame->script()->globalObject(pluginWorld())->globalExec(); + JSLock lock(SilenceAssertionsOnly); + + JSValue value = demarshalValue(exec, valueData, valueLength); + object->put(exec, propertyName, value); + + exec->clearException(); + return true; +} + +bool NetscapePluginInstanceProxy::removeProperty(uint32_t objectID, const Identifier& propertyName) +{ + if (m_inDestroy) + return false; + + JSObject* object = m_localObjects.get(objectID); + if (!object) { + LOG_ERROR("NetscapePluginInstanceProxy::removeProperty: local object %u doesn't exist.", objectID); + return false; + } + + Frame* frame = core([m_pluginView webFrame]); + if (!frame) + return false; + + ExecState* exec = frame->script()->globalObject(pluginWorld())->globalExec(); + if (!object->hasProperty(exec, propertyName)) { + exec->clearException(); + return false; + } + + JSLock lock(SilenceAssertionsOnly); + object->deleteProperty(exec, propertyName); + exec->clearException(); + return true; +} + +bool NetscapePluginInstanceProxy::removeProperty(uint32_t objectID, unsigned propertyName) +{ + if (m_inDestroy) + return false; + + JSObject* object = m_localObjects.get(objectID); + if (!object) { + LOG_ERROR("NetscapePluginInstanceProxy::removeProperty: local object %u doesn't exist.", objectID); + return false; + } + + Frame* frame = core([m_pluginView webFrame]); + if (!frame) + return false; + + ExecState* exec = frame->script()->globalObject(pluginWorld())->globalExec(); + if (!object->hasProperty(exec, propertyName)) { + exec->clearException(); + return false; + } + + JSLock lock(SilenceAssertionsOnly); + object->deleteProperty(exec, propertyName); + exec->clearException(); + return true; +} + +bool NetscapePluginInstanceProxy::hasProperty(uint32_t objectID, const Identifier& propertyName) +{ + if (m_inDestroy) + return false; + + JSObject* object = m_localObjects.get(objectID); + if (!object) { + LOG_ERROR("NetscapePluginInstanceProxy::hasProperty: local object %u doesn't exist.", objectID); + return false; + } + + Frame* frame = core([m_pluginView webFrame]); + if (!frame) + return false; + + ExecState* exec = frame->script()->globalObject(pluginWorld())->globalExec(); + bool result = object->hasProperty(exec, propertyName); + exec->clearException(); + + return result; +} + +bool NetscapePluginInstanceProxy::hasProperty(uint32_t objectID, unsigned propertyName) +{ + if (m_inDestroy) + return false; + + JSObject* object = m_localObjects.get(objectID); + if (!object) { + LOG_ERROR("NetscapePluginInstanceProxy::hasProperty: local object %u doesn't exist.", objectID); + return false; + } + + Frame* frame = core([m_pluginView webFrame]); + if (!frame) + return false; + + ExecState* exec = frame->script()->globalObject(pluginWorld())->globalExec(); + bool result = object->hasProperty(exec, propertyName); + exec->clearException(); + + return result; +} + +bool NetscapePluginInstanceProxy::hasMethod(uint32_t objectID, const Identifier& methodName) +{ + if (m_inDestroy) + return false; + + JSObject* object = m_localObjects.get(objectID); + if (!object) { + LOG_ERROR("NetscapePluginInstanceProxy::hasMethod: local object %u doesn't exist.", objectID); + return false; + } + + Frame* frame = core([m_pluginView webFrame]); + if (!frame) + return false; + + ExecState* exec = frame->script()->globalObject(pluginWorld())->globalExec(); + JSLock lock(SilenceAssertionsOnly); + JSValue func = object->get(exec, methodName); + exec->clearException(); + return !func.isUndefined(); +} + +bool NetscapePluginInstanceProxy::enumerate(uint32_t objectID, data_t& resultData, mach_msg_type_number_t& resultLength) +{ + if (m_inDestroy) + return false; + + JSObject* object = m_localObjects.get(objectID); + if (!object) { + LOG_ERROR("NetscapePluginInstanceProxy::enumerate: local object %u doesn't exist.", objectID); + return false; + } + + Frame* frame = core([m_pluginView webFrame]); + if (!frame) + return false; + + ExecState* exec = frame->script()->globalObject(pluginWorld())->globalExec(); + JSLock lock(SilenceAssertionsOnly); + + PropertyNameArray propertyNames(exec); + object->getPropertyNames(exec, propertyNames); + + RetainPtr<NSMutableArray*> array(AdoptNS, [[NSMutableArray alloc] init]); + for (unsigned i = 0; i < propertyNames.size(); i++) { + uint64_t methodName = reinterpret_cast<uint64_t>(_NPN_GetStringIdentifier(propertyNames[i].ustring().utf8().data())); + + [array.get() addObject:[NSNumber numberWithLongLong:methodName]]; + } + + NSData *data = [NSPropertyListSerialization dataFromPropertyList:array.get() format:NSPropertyListBinaryFormat_v1_0 errorDescription:0]; + ASSERT(data); + + resultLength = [data length]; + mig_allocate(reinterpret_cast<vm_address_t*>(&resultData), resultLength); + + memcpy(resultData, [data bytes], resultLength); + + exec->clearException(); + + return true; +} + +void NetscapePluginInstanceProxy::addValueToArray(NSMutableArray *array, ExecState* exec, JSValue value) +{ + JSLock lock(SilenceAssertionsOnly); + + if (value.isString()) { + [array addObject:[NSNumber numberWithInt:StringValueType]]; + [array addObject:ustringToString(value.toString(exec))]; + } else if (value.isNumber()) { + [array addObject:[NSNumber numberWithInt:DoubleValueType]]; + [array addObject:[NSNumber numberWithDouble:value.toNumber(exec)]]; + } else if (value.isBoolean()) { + [array addObject:[NSNumber numberWithInt:BoolValueType]]; + [array addObject:[NSNumber numberWithBool:value.toBoolean(exec)]]; + } else if (value.isNull()) + [array addObject:[NSNumber numberWithInt:NullValueType]]; + else if (value.isObject()) { + JSObject* object = asObject(value); + if (object->classInfo() == &ProxyRuntimeObject::s_info) { + ProxyRuntimeObject* runtimeObject = static_cast<ProxyRuntimeObject*>(object); + if (ProxyInstance* instance = runtimeObject->getInternalProxyInstance()) { + [array addObject:[NSNumber numberWithInt:NPObjectValueType]]; + [array addObject:[NSNumber numberWithInt:instance->objectID()]]; + } + } else { + [array addObject:[NSNumber numberWithInt:JSObjectValueType]]; + [array addObject:[NSNumber numberWithInt:m_localObjects.idForObject(object)]]; + } + } else + [array addObject:[NSNumber numberWithInt:VoidValueType]]; +} + +void NetscapePluginInstanceProxy::marshalValue(ExecState* exec, JSValue value, data_t& resultData, mach_msg_type_number_t& resultLength) +{ + RetainPtr<NSMutableArray*> array(AdoptNS, [[NSMutableArray alloc] init]); + + addValueToArray(array.get(), exec, value); + + RetainPtr<NSData *> data = [NSPropertyListSerialization dataFromPropertyList:array.get() format:NSPropertyListBinaryFormat_v1_0 errorDescription:0]; + ASSERT(data); + + resultLength = [data.get() length]; + mig_allocate(reinterpret_cast<vm_address_t*>(&resultData), resultLength); + + memcpy(resultData, [data.get() bytes], resultLength); +} + +RetainPtr<NSData *> NetscapePluginInstanceProxy::marshalValues(ExecState* exec, const ArgList& args) +{ + RetainPtr<NSMutableArray*> array(AdoptNS, [[NSMutableArray alloc] init]); + + for (unsigned i = 0; i < args.size(); i++) + addValueToArray(array.get(), exec, args.at(i)); + + RetainPtr<NSData *> data = [NSPropertyListSerialization dataFromPropertyList:array.get() format:NSPropertyListBinaryFormat_v1_0 errorDescription:0]; + ASSERT(data); + + return data; +} + +bool NetscapePluginInstanceProxy::demarshalValueFromArray(ExecState* exec, NSArray *array, NSUInteger& index, JSValue& result) +{ + if (index == [array count]) + return false; + + int type = [[array objectAtIndex:index++] intValue]; + switch (type) { + case VoidValueType: + result = jsUndefined(); + return true; + case NullValueType: + result = jsNull(); + return true; + case BoolValueType: + result = jsBoolean([[array objectAtIndex:index++] boolValue]); + return true; + case DoubleValueType: + result = jsNumber([[array objectAtIndex:index++] doubleValue]); + return true; + case StringValueType: { + NSString *string = [array objectAtIndex:index++]; + + result = jsString(exec, String(string)); + return true; + } + case JSObjectValueType: { + uint32_t objectID = [[array objectAtIndex:index++] intValue]; + + result = m_localObjects.get(objectID); + ASSERT(result); + return true; + } + case NPObjectValueType: { + uint32_t objectID = [[array objectAtIndex:index++] intValue]; + + Frame* frame = core([m_pluginView webFrame]); + if (!frame) + return false; + + if (!frame->script()->canExecuteScripts(NotAboutToExecuteScript)) + return false; + + RefPtr<RootObject> rootObject = frame->script()->createRootObject(m_pluginView); + if (!rootObject) + return false; + + result = ProxyInstance::create(rootObject.release(), this, objectID)->createRuntimeObject(exec); + return true; + } + default: + ASSERT_NOT_REACHED(); + return false; + } +} + +JSValue NetscapePluginInstanceProxy::demarshalValue(ExecState* exec, const char* valueData, mach_msg_type_number_t valueLength) +{ + RetainPtr<NSData*> data(AdoptNS, [[NSData alloc] initWithBytesNoCopy:(void*)valueData length:valueLength freeWhenDone:NO]); + + RetainPtr<NSArray*> array = [NSPropertyListSerialization propertyListFromData:data.get() + mutabilityOption:NSPropertyListImmutable + format:0 + errorDescription:0]; + NSUInteger position = 0; + JSValue value; + bool result = demarshalValueFromArray(exec, array.get(), position, value); + ASSERT_UNUSED(result, result); + + return value; +} + +void NetscapePluginInstanceProxy::demarshalValues(ExecState* exec, data_t valuesData, mach_msg_type_number_t valuesLength, MarkedArgumentBuffer& result) +{ + RetainPtr<NSData*> data(AdoptNS, [[NSData alloc] initWithBytesNoCopy:valuesData length:valuesLength freeWhenDone:NO]); + + RetainPtr<NSArray*> array = [NSPropertyListSerialization propertyListFromData:data.get() + mutabilityOption:NSPropertyListImmutable + format:0 + errorDescription:0]; + NSUInteger position = 0; + JSValue value; + while (demarshalValueFromArray(exec, array.get(), position, value)) + result.append(value); +} + +void NetscapePluginInstanceProxy::retainLocalObject(JSC::JSValue value) +{ + if (!value.isObject() || value.inherits(&ProxyRuntimeObject::s_info)) + return; + + m_localObjects.retain(asObject(value)); +} + +void NetscapePluginInstanceProxy::releaseLocalObject(JSC::JSValue value) +{ + if (!value.isObject() || value.inherits(&ProxyRuntimeObject::s_info)) + return; + + m_localObjects.release(asObject(value)); +} + +PassRefPtr<Instance> NetscapePluginInstanceProxy::createBindingsInstance(PassRefPtr<RootObject> rootObject) +{ + uint32_t requestID = nextRequestID(); + + if (_WKPHGetScriptableNPObject(m_pluginHostProxy->port(), m_pluginID, requestID) != KERN_SUCCESS) + return 0; + + auto_ptr<GetScriptableNPObjectReply> reply = waitForReply<GetScriptableNPObjectReply>(requestID); + if (!reply.get()) + return 0; + + if (!reply->m_objectID) + return 0; + + // Since the reply was non-null, "this" is still a valid pointer. + return ProxyInstance::create(rootObject, this, reply->m_objectID); +} + +void NetscapePluginInstanceProxy::addInstance(ProxyInstance* instance) +{ + ASSERT(!m_instances.contains(instance)); + + m_instances.add(instance); +} + +void NetscapePluginInstanceProxy::removeInstance(ProxyInstance* instance) +{ + ASSERT(m_instances.contains(instance)); + + m_instances.remove(instance); +} + +void NetscapePluginInstanceProxy::willCallPluginFunction() +{ + m_pluginFunctionCallDepth++; +} + +void NetscapePluginInstanceProxy::didCallPluginFunction(bool& stopped) +{ + ASSERT(m_pluginFunctionCallDepth > 0); + m_pluginFunctionCallDepth--; + + // If -stop was called while we were calling into a plug-in function, and we're no longer + // inside a plug-in function, stop now. + if (!m_pluginFunctionCallDepth && m_shouldStopSoon) { + m_shouldStopSoon = false; + [m_pluginView stop]; + stopped = true; + } +} + +bool NetscapePluginInstanceProxy::shouldStop() +{ + if (m_pluginFunctionCallDepth) { + m_shouldStopSoon = true; + return false; + } + + return true; +} + +uint32_t NetscapePluginInstanceProxy::nextRequestID() +{ + uint32_t requestID = ++m_currentRequestID; + + // We don't want to return the HashMap empty/deleted "special keys" + if (requestID == 0 || requestID == static_cast<uint32_t>(-1)) + return nextRequestID(); + + return requestID; +} + +void NetscapePluginInstanceProxy::invalidateRect(double x, double y, double width, double height) +{ + ASSERT(m_pluginView); + + m_pluginIsWaitingForDraw = true; + [m_pluginView invalidatePluginContentRect:NSMakeRect(x, y, width, height)]; +} + +void NetscapePluginInstanceProxy::didDraw() +{ + if (!m_pluginIsWaitingForDraw) + return; + + m_pluginIsWaitingForDraw = false; + _WKPHPluginInstanceDidDraw(m_pluginHostProxy->port(), m_pluginID); +} + +bool NetscapePluginInstanceProxy::getCookies(data_t urlData, mach_msg_type_number_t urlLength, data_t& cookiesData, mach_msg_type_number_t& cookiesLength) +{ + ASSERT(m_pluginView); + + NSURL *url = [m_pluginView URLWithCString:urlData]; + if (!url) + return false; + + if (Frame* frame = core([m_pluginView webFrame])) { + String cookieString = cookies(frame->document(), url); + WTF::CString cookieStringUTF8 = cookieString.utf8(); + if (cookieStringUTF8.isNull()) + return false; + + cookiesLength = cookieStringUTF8.length(); + mig_allocate(reinterpret_cast<vm_address_t*>(&cookiesData), cookiesLength); + memcpy(cookiesData, cookieStringUTF8.data(), cookiesLength); + + return true; + } + + return false; +} + +bool NetscapePluginInstanceProxy::setCookies(data_t urlData, mach_msg_type_number_t urlLength, data_t cookiesData, mach_msg_type_number_t cookiesLength) +{ + ASSERT(m_pluginView); + + NSURL *url = [m_pluginView URLWithCString:urlData]; + if (!url) + return false; + + if (Frame* frame = core([m_pluginView webFrame])) { + String cookieString = String::fromUTF8(cookiesData, cookiesLength); + if (!cookieString) + return false; + + WebCore::setCookies(frame->document(), url, cookieString); + return true; + } + + return false; +} + +bool NetscapePluginInstanceProxy::getProxy(data_t urlData, mach_msg_type_number_t urlLength, data_t& proxyData, mach_msg_type_number_t& proxyLength) +{ + ASSERT(m_pluginView); + + NSURL *url = [m_pluginView URLWithCString:urlData]; + if (!url) + return false; + + Vector<ProxyServer> proxyServers = proxyServersForURL(url, 0); + WTF::CString proxyStringUTF8 = toString(proxyServers).utf8(); + + proxyLength = proxyStringUTF8.length(); + mig_allocate(reinterpret_cast<vm_address_t*>(&proxyData), proxyLength); + memcpy(proxyData, proxyStringUTF8.data(), proxyLength); + + return true; +} + +bool NetscapePluginInstanceProxy::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) +{ + WTF::CString username; + WTF::CString password; + + if (!WebKit::getAuthenticationInfo(protocolData, hostData, port, schemeData, realmData, username, password)) + return false; + + usernameLength = username.length(); + mig_allocate(reinterpret_cast<vm_address_t*>(&usernameData), usernameLength); + memcpy(usernameData, username.data(), usernameLength); + + passwordLength = password.length(); + mig_allocate(reinterpret_cast<vm_address_t*>(&passwordData), passwordLength); + memcpy(passwordData, password.data(), passwordLength); + + return true; +} + +bool NetscapePluginInstanceProxy::convertPoint(double sourceX, double sourceY, NPCoordinateSpace sourceSpace, + double& destX, double& destY, NPCoordinateSpace destSpace) +{ + ASSERT(m_pluginView); + + return [m_pluginView convertFromX:sourceX andY:sourceY space:sourceSpace toX:&destX andY:&destY space:destSpace]; +} + +uint32_t NetscapePluginInstanceProxy::checkIfAllowedToLoadURL(const char* url, const char* target) +{ + uint32_t checkID; + + // Assign a check ID + do { + checkID = ++m_urlCheckCounter; + } while (m_urlChecks.contains(checkID) || !m_urlCheckCounter); + + NSString *frameName = target ? [NSString stringWithCString:target encoding:NSISOLatin1StringEncoding] : nil; + + NSNumber *contextInfo = [[NSNumber alloc] initWithUnsignedInt:checkID]; + WebPluginContainerCheck *check = [WebPluginContainerCheck checkWithRequest:[m_pluginView requestWithURLCString:url] + target:frameName + resultObject:m_pluginView + selector:@selector(_containerCheckResult:contextInfo:) + controller:m_pluginView + contextInfo:contextInfo]; + + [contextInfo release]; + m_urlChecks.set(checkID, check); + [check start]; + + return checkID; +} + +void NetscapePluginInstanceProxy::cancelCheckIfAllowedToLoadURL(uint32_t checkID) +{ + URLCheckMap::iterator it = m_urlChecks.find(checkID); + if (it == m_urlChecks.end()) + return; + + WebPluginContainerCheck *check = it->second.get(); + [check cancel]; + m_urlChecks.remove(it); +} + +void NetscapePluginInstanceProxy::checkIfAllowedToLoadURLResult(uint32_t checkID, bool allowed) +{ + _WKPHCheckIfAllowedToLoadURLResult(m_pluginHostProxy->port(), m_pluginID, checkID, allowed); +} + +void NetscapePluginInstanceProxy::resolveURL(const char* url, const char* target, data_t& resolvedURLData, mach_msg_type_number_t& resolvedURLLength) +{ + ASSERT(m_pluginView); + + WTF::CString resolvedURL = [m_pluginView resolvedURLStringForURL:url target:target]; + + resolvedURLLength = resolvedURL.length(); + mig_allocate(reinterpret_cast<vm_address_t*>(&resolvedURLData), resolvedURLLength); + memcpy(resolvedURLData, resolvedURL.data(), resolvedURLLength); +} + +void NetscapePluginInstanceProxy::privateBrowsingModeDidChange(bool isPrivateBrowsingEnabled) +{ + _WKPHPluginInstancePrivateBrowsingModeDidChange(m_pluginHostProxy->port(), m_pluginID, isPrivateBrowsingEnabled); +} + +static String& globalExceptionString() +{ + DEFINE_STATIC_LOCAL(String, exceptionString, ()); + return exceptionString; +} + +void NetscapePluginInstanceProxy::setGlobalException(const String& exception) +{ + globalExceptionString() = exception; +} + +void NetscapePluginInstanceProxy::moveGlobalExceptionToExecState(ExecState* exec) +{ + if (globalExceptionString().isNull()) + return; + + { + JSLock lock(SilenceAssertionsOnly); + throwError(exec, createError(exec, stringToUString(globalExceptionString()))); + } + + globalExceptionString() = String(); +} + +} // namespace WebKit + +#endif // USE(PLUGIN_HOST_PROCESS) && ENABLE(NETSCAPE_PLUGIN_API) diff --git a/Source/WebKit/mac/Plugins/Hosted/ProxyInstance.h b/Source/WebKit/mac/Plugins/Hosted/ProxyInstance.h new file mode 100644 index 0000000..b72e49a --- /dev/null +++ b/Source/WebKit/mac/Plugins/Hosted/ProxyInstance.h @@ -0,0 +1,106 @@ +/* + * Copyright (C) 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 ProxyInstance_h +#define ProxyInstance_h + +#import "NetscapePluginInstanceProxy.h" +#import "WebKitPluginHostTypes.h" +#import <WebCore/Bridge.h> +#import <WebCore/runtime_root.h> +#import <wtf/OwnPtr.h> + +namespace WebKit { + +class ProxyClass; + +class ProxyInstance : public JSC::Bindings::Instance { +public: + static PassRefPtr<ProxyInstance> create(PassRefPtr<JSC::Bindings::RootObject> rootObject, NetscapePluginInstanceProxy* instanceProxy, uint32_t objectID) + { + return adoptRef(new ProxyInstance(rootObject, instanceProxy, objectID)); + } + ~ProxyInstance(); + + JSC::Bindings::MethodList methodsNamed(const JSC::Identifier&); + JSC::Bindings::Field* fieldNamed(const JSC::Identifier&); + + JSC::JSValue fieldValue(JSC::ExecState*, const JSC::Bindings::Field*) const; + void setFieldValue(JSC::ExecState*, const JSC::Bindings::Field*, JSC::JSValue) const; + + void invalidate(); + + uint32_t objectID() const { return m_objectID; } + +private: + ProxyInstance(PassRefPtr<JSC::Bindings::RootObject>, NetscapePluginInstanceProxy*, uint32_t objectID); + + virtual JSC::Bindings::RuntimeObject* newRuntimeObject(JSC::ExecState*); + + virtual JSC::Bindings::Class* getClass() const; + + virtual JSC::JSValue getMethod(JSC::ExecState* exec, const JSC::Identifier& propertyName); + virtual JSC::JSValue invokeMethod(JSC::ExecState*, JSC::RuntimeMethod*); + + virtual bool supportsInvokeDefaultMethod() const; + virtual JSC::JSValue invokeDefaultMethod(JSC::ExecState*); + + virtual bool supportsConstruct() const; + virtual JSC::JSValue invokeConstruct(JSC::ExecState*, const JSC::ArgList&); + + virtual JSC::JSValue defaultValue(JSC::ExecState*, JSC::PreferredPrimitiveType) const; + virtual JSC::JSValue valueOf(JSC::ExecState*) const; + + virtual void getPropertyNames(JSC::ExecState*, JSC::PropertyNameArray&); + + JSC::JSValue stringValue(JSC::ExecState*) const; + JSC::JSValue numberValue(JSC::ExecState*) const; + JSC::JSValue booleanValue() const; + + JSC::JSValue invoke(JSC::ExecState*, InvokeType, uint64_t identifier, const JSC::ArgList&); + + template <typename T> + std::auto_ptr<T> waitForReply(uint32_t requestID) const { + std::auto_ptr<T> reply = m_instanceProxy->waitForReply<T>(requestID); + + // If the instance proxy was invalidated, just return a null reply. + if (!m_instanceProxy) + return std::auto_ptr<T>(); + + return reply; + } + + NetscapePluginInstanceProxy* m_instanceProxy; + uint32_t m_objectID; + JSC::Bindings::FieldMap m_fields; + JSC::Bindings::MethodMap m_methods; +}; + +} + +#endif // ProxyInstance_h +#endif // USE(PLUGIN_HOST_PROCESS) diff --git a/Source/WebKit/mac/Plugins/Hosted/ProxyInstance.mm b/Source/WebKit/mac/Plugins/Hosted/ProxyInstance.mm new file mode 100644 index 0000000..927a008 --- /dev/null +++ b/Source/WebKit/mac/Plugins/Hosted/ProxyInstance.mm @@ -0,0 +1,458 @@ +/* + * 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) && ENABLE(NETSCAPE_PLUGIN_API) + +#import "ProxyInstance.h" + +#import "NetscapePluginHostProxy.h" +#import "ProxyRuntimeObject.h" +#import <WebCore/IdentifierRep.h> +#import <WebCore/JSDOMWindow.h> +#import <WebCore/npruntime_impl.h> +#import <WebCore/runtime_method.h> +#import <runtime/Error.h> +#import <runtime/PropertyNameArray.h> + +extern "C" { +#import "WebKitPluginHost.h" +} + +using namespace JSC; +using namespace JSC::Bindings; +using namespace std; +using namespace WebCore; + +namespace WebKit { + +class ProxyClass : public JSC::Bindings::Class { +private: + virtual MethodList methodsNamed(const Identifier&, Instance*) const; + virtual Field* fieldNamed(const Identifier&, Instance*) const; +}; + +MethodList ProxyClass::methodsNamed(const Identifier& identifier, Instance* instance) const +{ + return static_cast<ProxyInstance*>(instance)->methodsNamed(identifier); +} + +Field* ProxyClass::fieldNamed(const Identifier& identifier, Instance* instance) const +{ + return static_cast<ProxyInstance*>(instance)->fieldNamed(identifier); +} + +static ProxyClass* proxyClass() +{ + DEFINE_STATIC_LOCAL(ProxyClass, proxyClass, ()); + return &proxyClass; +} + +class ProxyField : public JSC::Bindings::Field { +public: + ProxyField(uint64_t serverIdentifier) + : m_serverIdentifier(serverIdentifier) + { + } + + uint64_t serverIdentifier() const { return m_serverIdentifier; } + +private: + virtual JSValue valueFromInstance(ExecState*, const Instance*) const; + virtual void setValueToInstance(ExecState*, const Instance*, JSValue) const; + + uint64_t m_serverIdentifier; +}; + +JSValue ProxyField::valueFromInstance(ExecState* exec, const Instance* instance) const +{ + return static_cast<const ProxyInstance*>(instance)->fieldValue(exec, this); +} + +void ProxyField::setValueToInstance(ExecState* exec, const Instance* instance, JSValue value) const +{ + static_cast<const ProxyInstance*>(instance)->setFieldValue(exec, this, value); +} + +class ProxyMethod : public JSC::Bindings::Method { +public: + ProxyMethod(uint64_t serverIdentifier) + : m_serverIdentifier(serverIdentifier) + { + } + + uint64_t serverIdentifier() const { return m_serverIdentifier; } + +private: + virtual int numParameters() const { return 0; } + + uint64_t m_serverIdentifier; +}; + +ProxyInstance::ProxyInstance(PassRefPtr<RootObject> rootObject, NetscapePluginInstanceProxy* instanceProxy, uint32_t objectID) + : Instance(rootObject) + , m_instanceProxy(instanceProxy) + , m_objectID(objectID) +{ + m_instanceProxy->addInstance(this); +} + +ProxyInstance::~ProxyInstance() +{ + deleteAllValues(m_fields); + deleteAllValues(m_methods); + + if (!m_instanceProxy) + return; + + m_instanceProxy->removeInstance(this); + + invalidate(); +} + +RuntimeObject* ProxyInstance::newRuntimeObject(ExecState* exec) +{ + return new (exec) ProxyRuntimeObject(exec, exec->lexicalGlobalObject(), this); +} + +JSC::Bindings::Class* ProxyInstance::getClass() const +{ + return proxyClass(); +} + +JSValue ProxyInstance::invoke(JSC::ExecState* exec, InvokeType type, uint64_t identifier, const ArgList& args) +{ + if (!m_instanceProxy) + return jsUndefined(); + + RetainPtr<NSData*> arguments(m_instanceProxy->marshalValues(exec, args)); + + uint32_t requestID = m_instanceProxy->nextRequestID(); + + for (unsigned i = 0; i < args.size(); i++) + m_instanceProxy->retainLocalObject(args.at(i)); + + if (_WKPHNPObjectInvoke(m_instanceProxy->hostProxy()->port(), m_instanceProxy->pluginID(), requestID, m_objectID, + type, identifier, (char*)[arguments.get() bytes], [arguments.get() length]) != KERN_SUCCESS) { + if (m_instanceProxy) { + for (unsigned i = 0; i < args.size(); i++) + m_instanceProxy->releaseLocalObject(args.at(i)); + } + return jsUndefined(); + } + + auto_ptr<NetscapePluginInstanceProxy::BooleanAndDataReply> reply = waitForReply<NetscapePluginInstanceProxy::BooleanAndDataReply>(requestID); + NetscapePluginInstanceProxy::moveGlobalExceptionToExecState(exec); + + if (m_instanceProxy) { + for (unsigned i = 0; i < args.size(); i++) + m_instanceProxy->releaseLocalObject(args.at(i)); + } + + if (!reply.get() || !reply->m_returnValue) + return jsUndefined(); + + return m_instanceProxy->demarshalValue(exec, (char*)CFDataGetBytePtr(reply->m_result.get()), CFDataGetLength(reply->m_result.get())); +} + +class ProxyRuntimeMethod : public RuntimeMethod { +public: + ProxyRuntimeMethod(ExecState* exec, JSGlobalObject* globalObject, const Identifier& name, Bindings::MethodList& list) + : RuntimeMethod(exec, globalObject, name, list) + { + } + + virtual const ClassInfo* classInfo() const { return &s_info; } + + static const ClassInfo s_info; +}; + +const ClassInfo ProxyRuntimeMethod::s_info = { "ProxyRuntimeMethod", &RuntimeMethod::s_info, 0, 0 }; + +JSValue ProxyInstance::getMethod(JSC::ExecState* exec, const JSC::Identifier& propertyName) +{ + MethodList methodList = getClass()->methodsNamed(propertyName, this); + return new (exec) ProxyRuntimeMethod(exec, exec->lexicalGlobalObject(), propertyName, methodList); +} + +JSValue ProxyInstance::invokeMethod(ExecState* exec, JSC::RuntimeMethod* runtimeMethod) +{ + if (!asObject(runtimeMethod)->inherits(&ProxyRuntimeMethod::s_info)) + return throwError(exec, createTypeError(exec, "Attempt to invoke non-plug-in method on plug-in object.")); + + const MethodList& methodList = *runtimeMethod->methods(); + + ASSERT(methodList.size() == 1); + + ProxyMethod* method = static_cast<ProxyMethod*>(methodList[0]); + + return invoke(exec, Invoke, method->serverIdentifier(), ArgList(exec)); +} + +bool ProxyInstance::supportsInvokeDefaultMethod() const +{ + if (!m_instanceProxy) + return false; + + uint32_t requestID = m_instanceProxy->nextRequestID(); + + if (_WKPHNPObjectHasInvokeDefaultMethod(m_instanceProxy->hostProxy()->port(), + m_instanceProxy->pluginID(), requestID, + m_objectID) != KERN_SUCCESS) + return false; + + auto_ptr<NetscapePluginInstanceProxy::BooleanReply> reply = waitForReply<NetscapePluginInstanceProxy::BooleanReply>(requestID); + if (reply.get() && reply->m_result) + return true; + + return false; +} + +JSValue ProxyInstance::invokeDefaultMethod(ExecState* exec) +{ + return invoke(exec, InvokeDefault, 0, ArgList(exec)); +} + +bool ProxyInstance::supportsConstruct() const +{ + if (!m_instanceProxy) + return false; + + uint32_t requestID = m_instanceProxy->nextRequestID(); + + if (_WKPHNPObjectHasConstructMethod(m_instanceProxy->hostProxy()->port(), + m_instanceProxy->pluginID(), requestID, + m_objectID) != KERN_SUCCESS) + return false; + + auto_ptr<NetscapePluginInstanceProxy::BooleanReply> reply = waitForReply<NetscapePluginInstanceProxy::BooleanReply>(requestID); + if (reply.get() && reply->m_result) + return true; + + return false; +} + +JSValue ProxyInstance::invokeConstruct(ExecState* exec, const ArgList& args) +{ + return invoke(exec, Construct, 0, args); +} + +JSValue ProxyInstance::defaultValue(ExecState* exec, PreferredPrimitiveType hint) const +{ + if (hint == PreferString) + return stringValue(exec); + if (hint == PreferNumber) + return numberValue(exec); + return valueOf(exec); +} + +JSValue ProxyInstance::stringValue(ExecState* exec) const +{ + // FIXME: Implement something sensible. + return jsEmptyString(exec); +} + +JSValue ProxyInstance::numberValue(ExecState*) const +{ + // FIXME: Implement something sensible. + return jsNumber(0); +} + +JSValue ProxyInstance::booleanValue() const +{ + // FIXME: Implement something sensible. + return jsBoolean(false); +} + +JSValue ProxyInstance::valueOf(ExecState* exec) const +{ + return stringValue(exec); +} + +void ProxyInstance::getPropertyNames(ExecState* exec, PropertyNameArray& nameArray) +{ + if (!m_instanceProxy) + return; + + uint32_t requestID = m_instanceProxy->nextRequestID(); + + if (_WKPHNPObjectEnumerate(m_instanceProxy->hostProxy()->port(), m_instanceProxy->pluginID(), requestID, m_objectID) != KERN_SUCCESS) + return; + + auto_ptr<NetscapePluginInstanceProxy::BooleanAndDataReply> reply = waitForReply<NetscapePluginInstanceProxy::BooleanAndDataReply>(requestID); + NetscapePluginInstanceProxy::moveGlobalExceptionToExecState(exec); + if (!reply.get() || !reply->m_returnValue) + return; + + RetainPtr<NSArray*> array = [NSPropertyListSerialization propertyListFromData:(NSData *)reply->m_result.get() + mutabilityOption:NSPropertyListImmutable + format:0 + errorDescription:0]; + + for (NSNumber *number in array.get()) { + IdentifierRep* identifier = reinterpret_cast<IdentifierRep*>([number longLongValue]); + if (!IdentifierRep::isValid(identifier)) + continue; + + if (identifier->isString()) { + const char* str = identifier->string(); + nameArray.add(Identifier(JSDOMWindow::commonJSGlobalData(), stringToUString(String::fromUTF8WithLatin1Fallback(str, strlen(str))))); + } else + nameArray.add(Identifier::from(exec, identifier->number())); + } +} + +MethodList ProxyInstance::methodsNamed(const Identifier& identifier) +{ + if (!m_instanceProxy) + return MethodList(); + + // If we already have an entry in the map, use it. + MethodMap::iterator existingMapEntry = m_methods.find(identifier.impl()); + if (existingMapEntry != m_methods.end()) { + MethodList methodList; + if (existingMapEntry->second) + methodList.append(existingMapEntry->second); + return methodList; + } + + uint64_t methodName = reinterpret_cast<uint64_t>(_NPN_GetStringIdentifier(identifier.ascii().data())); + uint32_t requestID = m_instanceProxy->nextRequestID(); + + if (_WKPHNPObjectHasMethod(m_instanceProxy->hostProxy()->port(), + m_instanceProxy->pluginID(), requestID, + m_objectID, methodName) != KERN_SUCCESS) + return MethodList(); + + auto_ptr<NetscapePluginInstanceProxy::BooleanReply> reply = waitForReply<NetscapePluginInstanceProxy::BooleanReply>(requestID); + if (!reply.get()) + return MethodList(); + + if (!reply->m_result && !m_instanceProxy->hostProxy()->shouldCacheMissingPropertiesAndMethods()) + return MethodList(); + + // Add a new entry to the map unless an entry was added while we were in waitForReply. + pair<MethodMap::iterator, bool> mapAddResult = m_methods.add(identifier.impl(), 0); + if (mapAddResult.second && reply->m_result) + mapAddResult.first->second = new ProxyMethod(methodName); + + MethodList methodList; + if (mapAddResult.first->second) + methodList.append(mapAddResult.first->second); + return methodList; +} + +Field* ProxyInstance::fieldNamed(const Identifier& identifier) +{ + if (!m_instanceProxy) + return 0; + + // If we already have an entry in the map, use it. + FieldMap::iterator existingMapEntry = m_fields.find(identifier.impl()); + if (existingMapEntry != m_fields.end()) + return existingMapEntry->second; + + uint64_t propertyName = reinterpret_cast<uint64_t>(_NPN_GetStringIdentifier(identifier.ascii().data())); + uint32_t requestID = m_instanceProxy->nextRequestID(); + + if (_WKPHNPObjectHasProperty(m_instanceProxy->hostProxy()->port(), + m_instanceProxy->pluginID(), requestID, + m_objectID, propertyName) != KERN_SUCCESS) + return 0; + + auto_ptr<NetscapePluginInstanceProxy::BooleanReply> reply = waitForReply<NetscapePluginInstanceProxy::BooleanReply>(requestID); + if (!reply.get()) + return 0; + + if (!reply->m_result && !m_instanceProxy->hostProxy()->shouldCacheMissingPropertiesAndMethods()) + return 0; + + // Add a new entry to the map unless an entry was added while we were in waitForReply. + pair<FieldMap::iterator, bool> mapAddResult = m_fields.add(identifier.impl(), 0); + if (mapAddResult.second && reply->m_result) + mapAddResult.first->second = new ProxyField(propertyName); + return mapAddResult.first->second; +} + +JSC::JSValue ProxyInstance::fieldValue(ExecState* exec, const Field* field) const +{ + if (!m_instanceProxy) + return jsUndefined(); + + uint64_t serverIdentifier = static_cast<const ProxyField*>(field)->serverIdentifier(); + uint32_t requestID = m_instanceProxy->nextRequestID(); + + if (_WKPHNPObjectGetProperty(m_instanceProxy->hostProxy()->port(), + m_instanceProxy->pluginID(), requestID, + m_objectID, serverIdentifier) != KERN_SUCCESS) + return jsUndefined(); + + auto_ptr<NetscapePluginInstanceProxy::BooleanAndDataReply> reply = waitForReply<NetscapePluginInstanceProxy::BooleanAndDataReply>(requestID); + NetscapePluginInstanceProxy::moveGlobalExceptionToExecState(exec); + if (!reply.get() || !reply->m_returnValue) + return jsUndefined(); + + return m_instanceProxy->demarshalValue(exec, (char*)CFDataGetBytePtr(reply->m_result.get()), CFDataGetLength(reply->m_result.get())); +} + +void ProxyInstance::setFieldValue(ExecState* exec, const Field* field, JSValue value) const +{ + if (!m_instanceProxy) + return; + + uint64_t serverIdentifier = static_cast<const ProxyField*>(field)->serverIdentifier(); + uint32_t requestID = m_instanceProxy->nextRequestID(); + + data_t valueData; + mach_msg_type_number_t valueLength; + + m_instanceProxy->marshalValue(exec, value, valueData, valueLength); + m_instanceProxy->retainLocalObject(value); + kern_return_t kr = _WKPHNPObjectSetProperty(m_instanceProxy->hostProxy()->port(), + m_instanceProxy->pluginID(), requestID, + m_objectID, serverIdentifier, valueData, valueLength); + mig_deallocate(reinterpret_cast<vm_address_t>(valueData), valueLength); + if (m_instanceProxy) + m_instanceProxy->releaseLocalObject(value); + if (kr != KERN_SUCCESS) + return; + + auto_ptr<NetscapePluginInstanceProxy::BooleanReply> reply = waitForReply<NetscapePluginInstanceProxy::BooleanReply>(requestID); + NetscapePluginInstanceProxy::moveGlobalExceptionToExecState(exec); +} + +void ProxyInstance::invalidate() +{ + ASSERT(m_instanceProxy); + + if (NetscapePluginHostProxy* hostProxy = m_instanceProxy->hostProxy()) + _WKPHNPObjectRelease(hostProxy->port(), + m_instanceProxy->pluginID(), m_objectID); + m_instanceProxy = 0; +} + +} // namespace WebKit + +#endif // USE(PLUGIN_HOST_PROCESS) && ENABLE(NETSCAPE_PLUGIN_API) + diff --git a/Source/WebKit/mac/Plugins/Hosted/ProxyRuntimeObject.h b/Source/WebKit/mac/Plugins/Hosted/ProxyRuntimeObject.h new file mode 100644 index 0000000..81d9b42 --- /dev/null +++ b/Source/WebKit/mac/Plugins/Hosted/ProxyRuntimeObject.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 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 COMPUTER, 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 ProxyRuntimeObject_h +#define ProxyRuntimeObject_h + +#include <WebCore/runtime_object.h> + +namespace WebKit { + +class ProxyInstance; + +class ProxyRuntimeObject : public JSC::Bindings::RuntimeObject { +public: + ProxyRuntimeObject(JSC::ExecState*, JSC::JSGlobalObject*, PassRefPtr<ProxyInstance>); + virtual ~ProxyRuntimeObject(); + + ProxyInstance* getInternalProxyInstance() const; + + static const JSC::ClassInfo s_info; + +private: + virtual const JSC::ClassInfo* classInfo() const { return &s_info; } +}; + +} + +#endif +#endif diff --git a/Source/WebKit/mac/Plugins/Hosted/ProxyRuntimeObject.mm b/Source/WebKit/mac/Plugins/Hosted/ProxyRuntimeObject.mm new file mode 100644 index 0000000..96855b3 --- /dev/null +++ b/Source/WebKit/mac/Plugins/Hosted/ProxyRuntimeObject.mm @@ -0,0 +1,55 @@ +/* + * Copyright (C) 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 COMPUTER, 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) + +#include "ProxyInstance.h" +#include "ProxyRuntimeObject.h" + +using namespace JSC; + +namespace WebKit { + + +const ClassInfo ProxyRuntimeObject::s_info = { "ProxyRuntimeObject", &RuntimeObject::s_info, 0, 0 }; + +ProxyRuntimeObject::ProxyRuntimeObject(ExecState* exec, JSGlobalObject* globalObject, PassRefPtr<ProxyInstance> instance) + : RuntimeObject(exec, globalObject, instance) +{ +} + +ProxyRuntimeObject::~ProxyRuntimeObject() +{ +} + +ProxyInstance* ProxyRuntimeObject::getInternalProxyInstance() const +{ + return static_cast<ProxyInstance*>(getInternalInstance()); +} + + +} + +#endif diff --git a/Source/WebKit/mac/Plugins/Hosted/WebHostedNetscapePluginView.h b/Source/WebKit/mac/Plugins/Hosted/WebHostedNetscapePluginView.h new file mode 100644 index 0000000..1eb164d --- /dev/null +++ b/Source/WebKit/mac/Plugins/Hosted/WebHostedNetscapePluginView.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2008 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) + +#import "WebBaseNetscapePluginView.h" +#import "WebKitSystemInterface.h" + +#import <wtf/RefPtr.h> + +namespace WebKit { + class HostedNetscapePluginStream; + class NetscapePluginInstanceProxy; +} + +@interface WebHostedNetscapePluginView : WebBaseNetscapePluginView<WebPluginManualLoader, WebPluginContainerCheckController> +{ + RetainPtr<NSArray> _attributeKeys; + RetainPtr<NSArray> _attributeValues; + + RetainPtr<CALayer> _pluginLayer; + WKSoftwareCARendererRef _softwareRenderer; + + NSSize _previousSize; + RefPtr<WebKit::NetscapePluginInstanceProxy> _proxy; +} + +- (id)initWithFrame:(NSRect)r + pluginPackage:(WebNetscapePluginPackage *)thePluginPackage + URL:(NSURL *)URL + baseURL:(NSURL *)baseURL + MIMEType:(NSString *)MIME + attributeKeys:(NSArray *)keys + attributeValues:(NSArray *)values + loadManually:(BOOL)loadManually + element:(PassRefPtr<WebCore::HTMLPlugInElement>)element; + +- (void)pluginHostDied; +- (CALayer *)pluginLayer; +- (void)webFrame:(WebFrame *)webFrame didFinishLoadWithReason:(NPReason)reason; + +@end + +#endif // USE(PLUGIN_HOST_PROCESS) + diff --git a/Source/WebKit/mac/Plugins/Hosted/WebHostedNetscapePluginView.mm b/Source/WebKit/mac/Plugins/Hosted/WebHostedNetscapePluginView.mm new file mode 100644 index 0000000..5593050 --- /dev/null +++ b/Source/WebKit/mac/Plugins/Hosted/WebHostedNetscapePluginView.mm @@ -0,0 +1,535 @@ +/* + * Copyright (C) 2008 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) && ENABLE(NETSCAPE_PLUGIN_API) + +#import "WebHostedNetscapePluginView.h" + +#import "HostedNetscapePluginStream.h" +#import "NetscapePluginInstanceProxy.h" +#import "NetscapePluginHostManager.h" +#import "NetscapePluginHostProxy.h" +#import "WebTextInputWindowController.h" +#import "WebFrameInternal.h" +#import "WebView.h" +#import "WebViewInternal.h" +#import "WebUIDelegate.h" + +#import <CoreFoundation/CoreFoundation.h> +#import <WebCore/Bridge.h> +#import <WebCore/Frame.h> +#import <WebCore/FrameLoaderTypes.h> +#import <WebCore/FrameView.h> +#import <WebCore/HTMLPlugInElement.h> +#import <WebCore/RenderEmbeddedObject.h> +#import <WebCore/WebCoreObjCExtras.h> +#import <WebCore/runtime_root.h> +#import <runtime/InitializeThreading.h> +#import <wtf/Assertions.h> +#import <wtf/Threading.h> + +using namespace WebCore; +using namespace WebKit; + +extern "C" { +#include "WebKitPluginClientServer.h" +#include "WebKitPluginHost.h" +} + +@implementation WebHostedNetscapePluginView + ++ (void)initialize +{ + JSC::initializeThreading(); + WTF::initializeMainThreadToProcessMainThread(); +#ifndef BUILDING_ON_TIGER + WebCoreObjCFinalizeOnMainThread(self); +#endif + WKSendUserChangeNotifications(); +} + +- (id)initWithFrame:(NSRect)frame + pluginPackage:(WebNetscapePluginPackage *)pluginPackage + URL:(NSURL *)URL + baseURL:(NSURL *)baseURL + MIMEType:(NSString *)MIME + attributeKeys:(NSArray *)keys + attributeValues:(NSArray *)values + loadManually:(BOOL)loadManually + element:(PassRefPtr<WebCore::HTMLPlugInElement>)element +{ + self = [super initWithFrame:frame pluginPackage:pluginPackage URL:URL baseURL:baseURL MIMEType:MIME attributeKeys:keys attributeValues:values loadManually:loadManually element:element]; + if (!self) + return nil; + + return self; +} + +- (void)handleMouseMoved:(NSEvent *)event +{ + if (_isStarted && _proxy) + _proxy->mouseEvent(self, event, NPCocoaEventMouseMoved); +} + +- (void)setAttributeKeys:(NSArray *)keys andValues:(NSArray *)values +{ + ASSERT(!_attributeKeys); + ASSERT(!_attributeValues); + + _attributeKeys.adoptNS([keys copy]); + _attributeValues.adoptNS([values copy]); +} + +- (BOOL)createPlugin +{ + ASSERT(!_proxy); + + NSString *userAgent = [[self webView] userAgentForURL:_baseURL.get()]; + BOOL accleratedCompositingEnabled = false; +#if USE(ACCELERATED_COMPOSITING) + accleratedCompositingEnabled = [[[self webView] preferences] acceleratedCompositingEnabled]; +#endif + + _proxy = NetscapePluginHostManager::shared().instantiatePlugin([_pluginPackage.get() path], [_pluginPackage.get() pluginHostArchitecture], [_pluginPackage.get() bundleIdentifier], self, _MIMEType.get(), _attributeKeys.get(), _attributeValues.get(), userAgent, _sourceURL.get(), + _mode == NP_FULL, _isPrivateBrowsingEnabled, accleratedCompositingEnabled); + if (!_proxy) + return NO; + + if (_proxy->rendererType() == UseSoftwareRenderer) + _softwareRenderer = WKSoftwareCARendererCreate(_proxy->renderContextID()); + else { + _pluginLayer = WKMakeRenderLayer(_proxy->renderContextID()); + + if (accleratedCompositingEnabled && _proxy->rendererType() == UseAcceleratedCompositing) { + // FIXME: This code can be shared between WebHostedNetscapePluginView and WebNetscapePluginView. +#ifndef BUILDING_ON_LEOPARD + // Since this layer isn't going to be inserted into a view, we need to create another layer and flip its geometry + // in order to get the coordinate system right. + RetainPtr<CALayer> realPluginLayer(AdoptNS, _pluginLayer.releaseRef()); + + _pluginLayer.adoptNS([[CALayer alloc] init]); + _pluginLayer.get().bounds = realPluginLayer.get().bounds; + _pluginLayer.get().geometryFlipped = YES; + + realPluginLayer.get().autoresizingMask = kCALayerWidthSizable | kCALayerHeightSizable; + [_pluginLayer.get() addSublayer:realPluginLayer.get()]; +#endif + + // Eagerly enter compositing mode, since we know we'll need it. This avoids firing setNeedsStyleRecalc() + // for iframes that contain composited plugins at bad times. https://bugs.webkit.org/show_bug.cgi?id=39033 + core([self webFrame])->view()->enterCompositingMode(); + [self element]->setNeedsStyleRecalc(SyntheticStyleChange); + } else + self.wantsLayer = YES; + } + + // Update the window frame. + _proxy->windowFrameChanged([[self window] frame]); + + return YES; +} + +// FIXME: This method is an ideal candidate to move up to the base class +- (CALayer *)pluginLayer +{ + return _pluginLayer.get(); +} + +- (void)setLayer:(CALayer *)newLayer +{ + // FIXME: This should use the same implementation as WebNetscapePluginView (and move to the base class). + [super setLayer:newLayer]; + + if (_pluginLayer) + [newLayer addSublayer:_pluginLayer.get()]; +} + +- (void)privateBrowsingModeDidChange +{ + if (_proxy) + _proxy->privateBrowsingModeDidChange(_isPrivateBrowsingEnabled); +} + +- (void)loadStream +{ +} + +- (void)updateAndSetWindow +{ + if (!_proxy) + return; + + // The base coordinates of a window and it's contentView happen to be the equal at a userSpaceScaleFactor + // of 1. For non-1.0 scale factors this assumption is false. + NSView *windowContentView = [[self window] contentView]; + NSRect boundsInWindow = [self convertRect:[self bounds] toView:windowContentView]; + + NSRect visibleRectInWindow; + + // Core Animation plug-ins need to be updated (with a 0,0,0,0 clipRect) when + // moved to a background tab. We don't do this for Core Graphics plug-ins as + // older versions of Flash have historical WebKit-specific code that isn't + // compatible with this behavior. + BOOL shouldClipOutPlugin = _pluginLayer && [self shouldClipOutPlugin]; + if (!shouldClipOutPlugin) + visibleRectInWindow = [self actualVisibleRectInWindow]; + else + visibleRectInWindow = NSZeroRect; + + // Flip Y to convert NSWindow coordinates to top-left-based window coordinates. + float borderViewHeight = [[self currentWindow] frame].size.height; + boundsInWindow.origin.y = borderViewHeight - NSMaxY(boundsInWindow); + + if (!shouldClipOutPlugin) + visibleRectInWindow.origin.y = borderViewHeight - NSMaxY(visibleRectInWindow); + + _previousSize = boundsInWindow.size; + + _proxy->resize(boundsInWindow, visibleRectInWindow); + + CGRect layerBounds = NSRectToCGRect(boundsInWindow); + CGRect bounds = NSRectToCGRect([self bounds]); + CGRect frame = NSRectToCGRect([self frame]); + + // We're not scaled, or in a subframe + CATransform3D scaleTransform = CATransform3DIdentity; + if (CGSizeEqualToSize(bounds.size, frame.size)) { + // We're in a subframe. Backing store is boundsInWindow.size. + if (boundsInWindow.size.width && boundsInWindow.size.height) + scaleTransform = CATransform3DMakeScale(frame.size.width / boundsInWindow.size.width, frame.size.height / boundsInWindow.size.height, 1); + } else { + // We're in the main frame with scaling. Need to mimic the frame/bounds scaling on Widgets. + if (frame.size.width && frame.size.height) + scaleTransform = CATransform3DMakeScale(bounds.size.width / frame.size.width, bounds.size.height / frame.size.height, 1); + } + + _pluginLayer.get().sublayerTransform = scaleTransform; +} + +- (void)windowFocusChanged:(BOOL)hasFocus +{ + if (_proxy) + _proxy->windowFocusChanged(hasFocus); +} + +- (BOOL)shouldStop +{ + if (!_proxy) + return YES; + + return _proxy->shouldStop(); +} + +- (void)destroyPlugin +{ + if (_proxy) { + if (_softwareRenderer) { + WKSoftwareCARendererDestroy(_softwareRenderer); + _softwareRenderer = 0; + } + + _proxy->destroy(); + _proxy = 0; + } + + _pluginLayer = 0; +} + +- (void)startTimers +{ + if (_proxy) + _proxy->startTimers(_isCompletelyObscured); +} + +- (void)stopTimers +{ + if (_proxy) + _proxy->stopTimers(); +} + +- (void)focusChanged +{ + if (_proxy) + _proxy->focusChanged(_hasFocus); +} + +- (void)windowFrameDidChange:(NSNotification *)notification +{ + if (_proxy && [self window]) + _proxy->windowFrameChanged([[self window] frame]); +} + +- (void)addWindowObservers +{ + [super addWindowObservers]; + + ASSERT([self window]); + + NSWindow *window = [self window]; + + NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; + [notificationCenter addObserver:self selector:@selector(windowFrameDidChange:) + name:NSWindowDidMoveNotification object:window]; + [notificationCenter addObserver:self selector:@selector(windowFrameDidChange:) + name:NSWindowDidResizeNotification object:window]; + + if (_proxy) + _proxy->windowFrameChanged([window frame]); + [self updateAndSetWindow]; +} + +- (void)removeWindowObservers +{ + [super removeWindowObservers]; + + NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; + [notificationCenter removeObserver:self name:NSWindowDidMoveNotification object:nil]; + [notificationCenter removeObserver:self name:NSWindowDidResizeNotification object:nil]; +} + +- (void)mouseDown:(NSEvent *)event +{ + if (_isStarted && _proxy) + _proxy->mouseEvent(self, event, NPCocoaEventMouseDown); +} + +- (void)mouseUp:(NSEvent *)event +{ + if (_isStarted && _proxy) + _proxy->mouseEvent(self, event, NPCocoaEventMouseUp); +} + +- (void)mouseDragged:(NSEvent *)event +{ + if (_isStarted && _proxy) + _proxy->mouseEvent(self, event, NPCocoaEventMouseDragged); +} + +- (void)handleMouseEntered:(NSEvent *)event +{ + // Set cursor to arrow. Plugins often handle cursor internally, but those that don't will just get this default one. + [[NSCursor arrowCursor] set]; + + if (_isStarted && _proxy) + _proxy->mouseEvent(self, event, NPCocoaEventMouseEntered); +} + +- (void)handleMouseExited:(NSEvent *)event +{ + if (_isStarted && _proxy) + _proxy->mouseEvent(self, event, NPCocoaEventMouseExited); + + // Set cursor back to arrow cursor. Because NSCursor doesn't know about changes that the plugin made, we could get confused about what we think the + // current cursor is otherwise. Therefore we have no choice but to unconditionally reset the cursor when the mouse exits the plugin. + // FIXME: This should be job of plugin host, see <rdar://problem/7654434>. + [[NSCursor arrowCursor] set]; +} + +- (void)scrollWheel:(NSEvent *)event +{ + bool processedEvent = false; + + if (_isStarted && _proxy) + processedEvent = _proxy->wheelEvent(self, event); + + if (!processedEvent) + [super scrollWheel:event]; +} + +- (NSTextInputContext *)inputContext +{ + return [[WebTextInputWindowController sharedTextInputWindowController] inputContext]; +} + +- (void)keyDown:(NSEvent *)event +{ + if (!_isStarted || !_proxy) + return; + + NSString *string = nil; + if ([[WebTextInputWindowController sharedTextInputWindowController] interpretKeyEvent:event string:&string]) { + if (string) + _proxy->insertText(string); + return; + } + + _proxy->keyEvent(self, event, NPCocoaEventKeyDown); +} + +- (void)keyUp:(NSEvent *)event +{ + if (_isStarted && _proxy) + _proxy->keyEvent(self, event, NPCocoaEventKeyUp); +} + +- (void)flagsChanged:(NSEvent *)event +{ + if (_isStarted && _proxy) + _proxy->flagsChanged(event); +} + +- (void)sendModifierEventWithKeyCode:(int)keyCode character:(char)character +{ + if (_isStarted && _proxy) + _proxy->syntheticKeyDownWithCommandModifier(keyCode, character); +} + +- (void)pluginHostDied +{ + if (_element->renderer() && _element->renderer()->isEmbeddedObject()) { + // FIXME: The renderer could also be a RenderApplet, we should handle that. + RenderEmbeddedObject* renderer = toRenderEmbeddedObject(_element->renderer()); + renderer->setShowsCrashedPluginIndicator(); + } + + _pluginLayer = nil; + _proxy = 0; + + // No need for us to be layer backed anymore + self.wantsLayer = NO; + + [self invalidatePluginContentRect:[self bounds]]; +} + +- (void)visibleRectDidChange +{ + [super visibleRectDidChange]; + WKSyncSurfaceToView(self); +} + +- (void)drawRect:(NSRect)rect +{ + if (_cachedSnapshot) { + NSRect sourceRect = { NSZeroPoint, [_cachedSnapshot.get() size] }; + [_cachedSnapshot.get() drawInRect:[self bounds] fromRect:sourceRect operation:NSCompositeSourceOver fraction:1]; + return; + } + + if (_proxy) { + if (_softwareRenderer) { + if ([NSGraphicsContext currentContextDrawingToScreen]) { + WKSoftwareCARendererRender(_softwareRenderer, (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort], NSRectToCGRect(rect)); + _proxy->didDraw(); + } else + _proxy->print(reinterpret_cast<CGContextRef>([[NSGraphicsContext currentContext] graphicsPort]), [self bounds].size.width, [self bounds].size.height); + } else if (_snapshotting && [self supportsSnapshotting]) { + _proxy->snapshot(reinterpret_cast<CGContextRef>([[NSGraphicsContext currentContext] graphicsPort]), [self bounds].size.width, [self bounds].size.height); + } + + return; + } +} + +- (PassRefPtr<JSC::Bindings::Instance>)createPluginBindingsInstance:(PassRefPtr<JSC::Bindings::RootObject>)rootObject +{ + if (!_proxy) + return 0; + + return _proxy->createBindingsInstance(rootObject); +} + +- (void)pluginView:(NSView *)pluginView receivedResponse:(NSURLResponse *)response +{ + ASSERT(_loadManually); + if (!_proxy) + return; + + ASSERT(!_proxy->manualStream()); + + _proxy->setManualStream(HostedNetscapePluginStream::create(_proxy.get(), core([self webFrame])->loader())); + _proxy->manualStream()->startStreamWithResponse(response); +} + +- (void)pluginView:(NSView *)pluginView receivedData:(NSData *)data +{ + ASSERT(_loadManually); + if (!_proxy) + return; + + if (HostedNetscapePluginStream* manualStream = _proxy->manualStream()) + manualStream->didReceiveData(0, static_cast<const char*>([data bytes]), [data length]); +} + +- (void)pluginView:(NSView *)pluginView receivedError:(NSError *)error +{ + ASSERT(_loadManually); + if (!_proxy) + return; + + if (HostedNetscapePluginStream* manualStream = _proxy->manualStream()) + manualStream->didFail(0, error); +} + +- (void)pluginViewFinishedLoading:(NSView *)pluginView +{ + ASSERT(_loadManually); + if (!_proxy) + return; + + if (HostedNetscapePluginStream* manualStream = _proxy->manualStream()) + manualStream->didFinishLoading(0); +} + +- (void)_webPluginContainerCancelCheckIfAllowedToLoadRequest:(id)webPluginContainerCheck +{ + ASSERT([webPluginContainerCheck isKindOfClass:[WebPluginContainerCheck class]]); + + id contextInfo = [webPluginContainerCheck contextInfo]; + ASSERT([contextInfo isKindOfClass:[NSNumber class]]); + + if (!_proxy) + return; + + uint32_t checkID = [(NSNumber *)contextInfo unsignedIntValue]; + _proxy->cancelCheckIfAllowedToLoadURL(checkID); +} + +- (void)_containerCheckResult:(PolicyAction)policy contextInfo:(id)contextInfo +{ + ASSERT([contextInfo isKindOfClass:[NSNumber class]]); + if (!_proxy) + return; + + uint32_t checkID = [(NSNumber *)contextInfo unsignedIntValue]; + _proxy->checkIfAllowedToLoadURLResult(checkID, (policy == PolicyUse)); +} + +- (void)webFrame:(WebFrame *)webFrame didFinishLoadWithReason:(NPReason)reason +{ + if (_isStarted && _proxy) + _proxy->webFrameDidFinishLoadWithReason(webFrame, reason); +} + +- (void)webFrame:(WebFrame *)webFrame didFinishLoadWithError:(NSError *)error +{ + NPReason reason = NPRES_DONE; + if (error) + reason = HostedNetscapePluginStream::reasonForError(error); + [self webFrame:webFrame didFinishLoadWithReason:reason]; +} + +@end + +#endif // USE(PLUGIN_HOST_PROCESS) && ENABLE(NETSCAPE_PLUGIN_API) diff --git a/Source/WebKit/mac/Plugins/Hosted/WebKitPluginAgent.defs b/Source/WebKit/mac/Plugins/Hosted/WebKitPluginAgent.defs new file mode 100644 index 0000000..0f332b6 --- /dev/null +++ b/Source/WebKit/mac/Plugins/Hosted/WebKitPluginAgent.defs @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2008 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. + */ + +#include <WebKit/WebKitPluginHostTypes.defs> + +subsystem WebKitPluginAgent 100; + +serverprefix WKPA; +userprefix _WKPA; + +routine CheckInApplication(serverPort :mach_port_t; + ServerAuditToken token :audit_token_t; + applicationName :application_name_t; + out pluginVendorPort :mach_port_make_send_t); + +routine SpawnPluginHost(pluginVendorPort :mach_port_t; + sreplyport _replyPort :mach_port_make_send_once_t; + options :plist_bytes_t; + out pluginHostPort: mach_port_move_send_t); + +routine CheckInPluginHost(serverPort :mach_port_t; + pluginHostPort :mach_port_move_send_t; + ServerAuditToken token :audit_token_t); diff --git a/Source/WebKit/mac/Plugins/Hosted/WebKitPluginAgentReply.defs b/Source/WebKit/mac/Plugins/Hosted/WebKitPluginAgentReply.defs new file mode 100644 index 0000000..c802b3d --- /dev/null +++ b/Source/WebKit/mac/Plugins/Hosted/WebKitPluginAgentReply.defs @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2008 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. + */ + +#include <WebKit/WebKitPluginHostTypes.defs> + +subsystem WebKitPluginAgentReply 200; + +serverprefix WKPA; +userprefix _WKPA; + +skip; // CheckInApplication + +simpleroutine SpawnPluginHostReply(_replyPort :mach_port_move_send_once_t; + in pluginHostPort: mach_port_move_send_t); + +skip; // CheckInPluginHost diff --git a/Source/WebKit/mac/Plugins/Hosted/WebKitPluginClient.defs b/Source/WebKit/mac/Plugins/Hosted/WebKitPluginClient.defs new file mode 100644 index 0000000..15fc5fa --- /dev/null +++ b/Source/WebKit/mac/Plugins/Hosted/WebKitPluginClient.defs @@ -0,0 +1,238 @@ +/* + * Copyright (C) 2008 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. + */ + +#include <WebKit/WebKitPluginHostTypes.defs> + +// FIXME: Come up with a better name. +subsystem WebKitPluginClient 300; + +serverprefix WK; +userprefix _WK; + +simpleroutine PCStatusText(clientPort :mach_port_t; + pluginID :uint32_t; + text :data_t); + +routine PCLoadURL(clientPort :mach_port_t; + pluginID :uint32_t; + url :data_t; + target :data_t; + postData :data_t; + flags: uint32_t; + out resultCode :uint16_t; + out requestID :uint32_t); + +simpleroutine PCCancelLoadURL(clientPort :mach_port_t; + pluginID :uint32_t; + streamID :uint32_t; + reason :int16_t); + +simpleroutine PCInvalidateRect(clientPort :mach_port_t; + pluginID :uint32_t; + x :double; + y :double; + width :double; + height :double); + +routine PCGetCookies(clientPort :mach_port_t; + pluginID :uint32_t; + url :data_t; + out returnValue :boolean_t; + out cookies :data_t, dealloc); + +routine PCSetCookies(clientPort :mach_port_t; + pluginID :uint32_t; + url :data_t; + cookies :data_t; + out returnValue :boolean_t); + +routine PCGetProxy(clientPort :mach_port_t; + pluginID :uint32_t; + url :data_t; + out returnValue :boolean_t; + out proxy :data_t, dealloc); + +routine PCGetAuthenticationInfo(clientPort :mach_port_t; + pluginID :uint32_t; + protocol :data_t; + host :data_t; + port :uint32_t; + scheme :data_t; + realm :data_t; + out returnValue :boolean_t; + out username :data_t, dealloc; + out password :data_t, dealloc); + +routine PCConvertPoint(clientPort :mach_port_t; + pluginID :uint32_t; + sourceX :double; + sourceY :double; + sourceSpace :uint32_t; + destSpace :uint32_t; + out returnValue :boolean_t; + out destX :double; + out destY :double); + +// NPRuntime + +routine PCGetStringIdentifier(clientPort :mach_port_t; + name :data_t; + out identifier :uint64_t); + +routine PCGetIntIdentifier(clientPort :mach_port_t; + value :int32_t; + out identifier: uint64_t); + +routine PCGetWindowNPObject(clientPort :mach_port_t; + pluginID :uint32_t; + out objectID :uint32_t); +routine PCGetPluginElementNPObject(clientPort :mach_port_t; + pluginID :uint32_t; + out objectID :uint32_t); + +routine PCForgetBrowserObject(clientPort :mach_port_t; + pluginID :uint32_t; + objectID :uint32_t); + +simpleroutine PCEvaluate(clientPort :mach_port_t; + pluginID :uint32_t; + requestID :uint32_t; + objectID :uint32_t; + script :data_t; + allowPopups :boolean_t); + +simpleroutine PCInvoke(clientPort :mach_port_t; + pluginID :uint32_t; + requestID :uint32_t; + objectID :uint32_t; + methodNameIdentifier :uint64_t; + arguments :data_t); + +simpleroutine PCInvokeDefault(clientPort :mach_port_t; + pluginID :uint32_t; + requestID :uint32_t; + objectID :uint32_t; + arguments :data_t); + +routine PCConstruct(clientPort :mach_port_t; + pluginID :uint32_t; + objectID :uint32_t; + arguments :data_t; + out returnValue :boolean_t; + out result :data_t, dealloc); + +simpleroutine PCGetProperty(clientPort :mach_port_t; + pluginID :uint32_t; + requestID :uint32_t; + objectID :uint32_t; + propertyNameIdentifier :uint64_t); + +simpleroutine PCSetProperty(clientPort :mach_port_t; + pluginID :uint32_t; + requestID :uint32_t; + objectID :uint32_t; + propertyNameIdentifier :uint64_t; + value :data_t); + +simpleroutine PCRemoveProperty(clientPort :mach_port_t; + pluginID :uint32_t; + requestID :uint32_t; + objectID :uint32_t; + propertyNameIdentifier :uint64_t); + +simpleroutine PCHasProperty(clientPort :mach_port_t; + pluginID :uint32_t; + requestID :uint32_t; + objectID :uint32_t; + propertyNameIdentifier :uint64_t); + +simpleroutine PCHasMethod(clientPort :mach_port_t; + pluginID :uint32_t; + requestID :uint32_t; + objectID :uint32_t; + methodNameIdentifier :uint64_t); + +routine PCIdentifierInfo(clientPort :mach_port_t; + identifier :uint64_t; + out info :data_t, dealloc); + +simpleroutine PCEnumerate(clientPort :mach_port_t; + pluginID :uint32_t; + requestID :uint32_t; + objectID :uint32_t); + +// Misc + +simpleroutine PCSetMenuBarVisible(clientPort :mach_port_t; + visible :boolean_t); + +simpleroutine PCSetModal(clientPort :mach_port_t; + modal :boolean_t); + +routine PCCheckIfAllowedToLoadURL(clientPort :mach_port_t; + pluginID :uint32_t; + url :data_t; + target :data_t; + out checkID :uint32_t); + +simpleroutine PCCancelCheckIfAllowedToLoadURL(clientPort :mach_port_t; + pluginID :uint32_t; + checkID :uint32_t); + +routine PCResolveURL(clientPort :mach_port_t; + pluginID :uint32_t; + url :data_t; + target :data_t; + out resolvedURL :data_t, dealloc); + +// Replies +simpleroutine PCInstantiatePluginReply(clientPort :mach_port_t; + pluginID :uint32_t; + requestID :uint32_t; + result :kern_return_t; + renderContextID :uint32_t; + rendererType :uint32_t); + +simpleroutine PCGetScriptableNPObjectReply(clientPort :mach_port_t; + pluginID :uint32_t; + requestID :uint32_t; + objectID :uint32_t); + +simpleroutine PCBooleanReply(clientPort :mach_port_t; + pluginID :uint32_t; + requestID :uint32_t; + result :boolean_t); + +simpleroutine PCBooleanAndDataReply(clientPort :mach_port_t; + pluginID :uint32_t; + requestID :uint32_t; + returnValue :boolean_t; + result :data_t); + +simpleroutine PCSetFullscreenWindowIsShowing(clientPort :mach_port_t; + isShowing :boolean_t); + +simpleroutine PCSetException(clientPort :mach_port_t; + message :data_t); diff --git a/Source/WebKit/mac/Plugins/Hosted/WebKitPluginHost.defs b/Source/WebKit/mac/Plugins/Hosted/WebKitPluginHost.defs new file mode 100644 index 0000000..fa808ac --- /dev/null +++ b/Source/WebKit/mac/Plugins/Hosted/WebKitPluginHost.defs @@ -0,0 +1,247 @@ +/* + * Copyright (C) 2008 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. + */ + +#include <WebKit/WebKitPluginHostTypes.defs> + +subsystem WebKitPluginHost 300; + +serverprefix WK; +userprefix _WK; + +routine PHCheckInWithPluginHost(pluginHostPort :mach_port_t; + options :plist_bytes_t; + clientPort :mach_port_make_send_t; + clientPSNHigh :uint32_t; + clientPSNLow :uint32_t; + renderPort :mach_port_copy_send_t; + out pluginHostPSNHigh :uint32_t; + out pluginHostPSNLow :uint32_t); + +simpleroutine PHInstantiatePlugin(pluginHostPort :mach_port_t; + requestID :uint32_t; + options :plist_bytes_t; + pluginID :uint32_t); + +simpleroutine PHResizePluginInstance(pluginHostPort :mach_port_t; + pluginID :uint32_t; + requestID :uint32_t; + pluginX :double; + pluginY :double; + pluginWidth :double; + pluginHeight :double; + clipX :double; + clipY :double; + clipWidth :double; + clipHeight :double); + +simpleroutine PHPluginInstanceFocusChanged(pluginHostPort :mach_port_t; + pluginID :uint32_t; + hasFocus :boolean_t); +simpleroutine PHPluginInstanceWindowFocusChanged(pluginHostPort :mach_port_t; + pluginID :uint32_t; + hasFocus :boolean_t); +simpleroutine PHPluginInstanceWindowFrameChanged(pluginHostPort :mach_port_t; + pluginID :uint32_t; + x :double; + y :double; + width :double; + height :double; + maxScreenY :double); + +simpleroutine PHPluginInstanceMouseEvent(pluginHostPort :mach_port_t; + pluginID :uint32_t; + timestamp :double; + eventType :uint32_t; + modifierFlags :uint32_t; + pluginX :double; + pluginY :double; + screenX :double; + screenY :double; + maxScreenY :double; + buttonNumber :int32_t; + clickCount :int32_t; + deltaX :double; + deltaY :double; + deltaZ: double); + +simpleroutine PHPluginInstanceKeyboardEvent(pluginHostPort :mach_port_t; + pluginID :uint32_t; + timestamp :double; + eventType :uint32_t; + modifierFlags :uint32_t; + characters :data_t; + charactersIgnoringModifiers :data_t; + isARepeat :boolean_t; + keyCode :uint16_t; + keyChar :uint8_t); + +simpleroutine PHPluginInstanceWheelEvent(pluginHostPort :mach_port_t; + pluginID :uint32_t; + requestID :uint32_t; + timestamp :double; + modifierFlags :uint32_t; + pluginX :double; + pluginY :double; + buttonNumber :int32_t; + deltaX :double; + deltaY :double; + deltaZ: double); + +simpleroutine PHPluginInstanceInsertText(pluginHostPort :mach_port_t; + pluginID :uint32_t; + text :data_t); + +simpleroutine PHPluginInstanceStartTimers(pluginHostPort :mach_port_t; + pluginID :uint32_t; + throttleTimers :boolean_t); +simpleroutine PHPluginInstanceStopTimers(pluginHostPort :mach_port_t; + pluginID :uint32_t); + +simpleroutine PHPluginInstancePrint(pluginHostPort :mach_port_t; + pluginID :uint32_t; + requestID :uint32_t; + width :uint32_t; + height :uint32_t); + +simpleroutine PHDestroyPluginInstance(pluginHostPort :mach_port_t; + pluginID :uint32_t; + requestID :uint32_t); + +simpleroutine PHCheckIfAllowedToLoadURLResult(clientPort :mach_port_t; + pluginID :uint32_t; + checkID :uint32_t; + result :boolean_t); + +// Streams +simpleroutine PHStartStream(pluginHostPort :mach_port_t; + pluginID :uint32_t; + streamID :uint32_t; + responseURL :data_t; + expectedContentLength :int64_t; + lastModifiedTimeInterval :double; + mimeType :data_t; + headers :data_t); + +simpleroutine PHStreamDidReceiveData(pluginHostPort :mach_port_t; + pluginID :uint32_t; + streamID :uint32_t; + data :data_t); + +simpleroutine PHStreamDidFinishLoading(pluginHostPort :mach_port_t; + pluginID :uint32_t; + streamID :uint32_t); + +simpleroutine PHStreamDidFail(pluginHostPort :mach_port_t; + pluginID :uint32_t; + streamID :uint32_t; + reason :int16_t); + +simpleroutine PHLoadURLNotify(pluginHostPort :mach_port_t; + pluginID :uint32_t; + requestID :uint32_t; + reason :int16_t); + +// NPRuntime + +simpleroutine PHGetScriptableNPObject(pluginHostPort :mach_port_t; + pluginID :uint32_t; + requestID :uint32_t); + +simpleroutine PHNPObjectHasProperty(pluginHostPort :mach_port_t; + pluginID :uint32_t; + requestID :uint32_t; + objectID :uint32_t; + propertyName :uint64_t); + +simpleroutine PHNPObjectHasMethod(pluginHostPort :mach_port_t; + pluginID :uint32_t; + requestID :uint32_t; + objectID :uint32_t; + methodName :uint64_t); + +simpleroutine PHNPObjectInvoke(pluginHostPort :mach_port_t; + pluginID :uint32_t; + requestID :uint32_t; + objectID :uint32_t; + invokeType :uint32_t; + methodName :uint64_t; + arguments :data_t); + +simpleroutine PHNPObjectHasInvokeDefaultMethod(pluginHostPort :mach_port_t; + pluginID :uint32_t; + requestID :uint32_t; + objectID :uint32_t); + +simpleroutine PHNPObjectHasConstructMethod(pluginHostPort :mach_port_t; + pluginID :uint32_t; + requestID :uint32_t; + objectID :uint32_t); + +simpleroutine PHNPObjectGetProperty(pluginHostPort :mach_port_t; + pluginID :uint32_t; + requestID :uint32_t; + objectID :uint32_t; + propertyName :uint64_t); + +simpleroutine PHNPObjectSetProperty(pluginHostPort :mach_port_t; + pluginID :uint32_t; + requestID :uint32_t; + objectID :uint32_t; + propertyName :uint64_t; + value :data_t); + +simpleroutine PHNPObjectRelease(pluginHostPort :mach_port_t; + pluginID :uint32_t; + objectID :uint32_t); + +simpleroutine PHNPObjectEnumerate(pluginHostPort :mach_port_t; + pluginID :uint32_t; + requestID :uint32_t; + objectID :uint32_t); + +// Replies + +simpleroutine PHBooleanReply(clientPort :mach_port_t; + pluginID :uint32_t; + requestID :uint32_t; + result :boolean_t); + +simpleroutine PHBooleanAndDataReply(pluginHostPort :mach_port_t; + pluginID :uint32_t; + requestID :uint32_t; + returnValue :boolean_t; + result :data_t); + +simpleroutine PHPluginInstanceDidDraw(pluginHostPort :mach_port_t; + pluginID :uint32_t); +simpleroutine PHPluginInstancePrivateBrowsingModeDidChange(pluginHostPort :mach_port_t; + pluginID :uint32_t; + privateBrowsingEnabled :boolean_t); + +simpleroutine PHPluginInstanceSnapshot(pluginHostPort :mach_port_t; + pluginID :uint32_t; + requestID :uint32_t; + width :uint32_t; + height :uint32_t); diff --git a/Source/WebKit/mac/Plugins/Hosted/WebKitPluginHostTypes.defs b/Source/WebKit/mac/Plugins/Hosted/WebKitPluginHostTypes.defs new file mode 100644 index 0000000..ee53520 --- /dev/null +++ b/Source/WebKit/mac/Plugins/Hosted/WebKitPluginHostTypes.defs @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2008 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. + */ + +#include <mach/std_types.defs> +#include <mach/mach_types.defs> + +import <WebKit/WebKitPluginHostTypes.h>; + +type plist_bytes_t = ^array [] of uint8_t; +type application_name_t = ^array [] of uint8_t; +type data_t = ^array [] of char; diff --git a/Source/WebKit/mac/Plugins/Hosted/WebKitPluginHostTypes.h b/Source/WebKit/mac/Plugins/Hosted/WebKitPluginHostTypes.h new file mode 100644 index 0000000..0bac2bc --- /dev/null +++ b/Source/WebKit/mac/Plugins/Hosted/WebKitPluginHostTypes.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2008 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. + */ + +#ifndef WebKitPluginHostTypes_h +#define WebKitPluginHostTypes_h + +typedef uint8_t* plist_bytes_t; +typedef uint8_t* application_name_t; + +typedef char* data_t; + +#ifndef __MigTypeCheck +#define __MigTypeCheck 1 +#endif + +enum LoadURLFlags { + IsPost = 1 << 0, + PostDataIsFile = 1 << 1, + AllowHeadersInPostData = 1 << 2, + AllowPopups = 1 << 3, +}; + +enum InvokeType { + Invoke, + InvokeDefault, + Construct +}; + +enum ValueType { + VoidValueType, + NullValueType, + BoolValueType, + DoubleValueType, + StringValueType, + JSObjectValueType, + NPObjectValueType +}; + +enum RendererType { + UseAcceleratedCompositing, + UseSoftwareRenderer, + UseLayerBackedView +}; + +#endif // WebKitPluginHostTypes_h diff --git a/Source/WebKit/mac/Plugins/Hosted/WebTextInputWindowController.h b/Source/WebKit/mac/Plugins/Hosted/WebTextInputWindowController.h new file mode 100644 index 0000000..9f036ee --- /dev/null +++ b/Source/WebKit/mac/Plugins/Hosted/WebTextInputWindowController.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2009 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 WebTextInputWindowController_h +#define WebTextInputWindowController_h + +@class WebTextInputPanel; + +@interface WebTextInputWindowController : NSObject { + WebTextInputPanel *_panel; +} + ++ (WebTextInputWindowController *)sharedTextInputWindowController; + +- (NSTextInputContext *)inputContext; +- (BOOL)interpretKeyEvent:(NSEvent *)event string:(NSString **)string; + +@end + +#endif // WebTextInputWindowController_h + +#endif // USE(PLUGIN_HOST_PROCESS) diff --git a/Source/WebKit/mac/Plugins/Hosted/WebTextInputWindowController.m b/Source/WebKit/mac/Plugins/Hosted/WebTextInputWindowController.m new file mode 100644 index 0000000..c168e6e --- /dev/null +++ b/Source/WebKit/mac/Plugins/Hosted/WebTextInputWindowController.m @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2009 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) + +#import "WebTextInputWindowController.h" + +#import <WebKitSystemInterface.h> + +@interface WebTextInputPanel : NSPanel { + NSTextView *_inputTextView; +} + +- (NSTextInputContext *)_inputContext; +- (BOOL)_interpretKeyEvent:(NSEvent *)event string:(NSString **)string; + +@end + +#define inputWindowHeight 20 + +@implementation WebTextInputPanel + +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; + + [_inputTextView release]; + + [super dealloc]; +} + +- (id)init +{ + self = [super initWithContentRect:NSZeroRect styleMask:WKGetInputPanelWindowStyle() backing:NSBackingStoreBuffered defer:YES]; + if (!self) + return nil; + + // Set the frame size. + NSRect visibleFrame = [[NSScreen mainScreen] visibleFrame]; + NSRect frame = NSMakeRect(visibleFrame.origin.x, visibleFrame.origin.y, visibleFrame.size.width, inputWindowHeight); + + [self setFrame:frame display:NO]; + + _inputTextView = [[NSTextView alloc] initWithFrame:[self.contentView frame]]; + _inputTextView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable | NSViewMaxXMargin | NSViewMinXMargin | NSViewMaxYMargin | NSViewMinYMargin; + + NSScrollView* scrollView = [[NSScrollView alloc] initWithFrame:[self.contentView frame]]; + scrollView.documentView = _inputTextView; + self.contentView = scrollView; + [scrollView release]; + + [self setFloatingPanel:YES]; + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(_keyboardInputSourceChanged:) + name:NSTextInputContextKeyboardSelectionDidChangeNotification + object:nil]; + + return self; +} + +- (void)_keyboardInputSourceChanged:(NSNotification *)notification +{ + [_inputTextView setString:@""]; + [self orderOut:nil]; +} + +- (BOOL)_interpretKeyEvent:(NSEvent *)event string:(NSString **)string +{ + BOOL hadMarkedText = [_inputTextView hasMarkedText]; + + *string = nil; + + if (![[_inputTextView inputContext] handleEvent:event]) + return NO; + + if ([_inputTextView hasMarkedText]) { + // Don't show the input method window for dead keys + if ([[event characters] length] > 0) + [self orderFront:nil]; + + return YES; + } + + if (hadMarkedText) { + [self orderOut:nil]; + + NSString *text = [[_inputTextView textStorage] string]; + if ([text length] > 0) + *string = [[text copy] autorelease]; + } + + [_inputTextView setString:@""]; + return hadMarkedText; +} + +- (NSTextInputContext *)_inputContext +{ + return [_inputTextView inputContext]; +} + +@end + +@implementation WebTextInputWindowController + ++ (WebTextInputWindowController *)sharedTextInputWindowController +{ + static WebTextInputWindowController *textInputWindowController; + if (!textInputWindowController) + textInputWindowController = [[WebTextInputWindowController alloc] init]; + + return textInputWindowController; +} + +- (id)init +{ + self = [super init]; + if (!self) + return nil; + + _panel = [[WebTextInputPanel alloc] init]; + + return self; +} + +- (NSTextInputContext *)inputContext +{ + return [_panel _inputContext]; +} + +- (BOOL)interpretKeyEvent:(NSEvent *)event string:(NSString **)string +{ + return [_panel _interpretKeyEvent:event string:string]; +} + +@end + +#endif // USE(PLUGIN_HOST_PROCESS) + |