summaryrefslogtreecommitdiffstats
path: root/WebKit/mac/Plugins
diff options
context:
space:
mode:
Diffstat (limited to 'WebKit/mac/Plugins')
-rw-r--r--WebKit/mac/Plugins/WebBaseNetscapePluginStream.h133
-rw-r--r--WebKit/mac/Plugins/WebBaseNetscapePluginStream.mm619
-rw-r--r--WebKit/mac/Plugins/WebBaseNetscapePluginView.h225
-rw-r--r--WebKit/mac/Plugins/WebBaseNetscapePluginView.mm2948
-rw-r--r--WebKit/mac/Plugins/WebBasePluginPackage.h107
-rw-r--r--WebKit/mac/Plugins/WebBasePluginPackage.m523
-rw-r--r--WebKit/mac/Plugins/WebJavaPlugIn.h85
-rw-r--r--WebKit/mac/Plugins/WebKitPluginContainerView.h43
-rw-r--r--WebKit/mac/Plugins/WebKitPluginContainerView.mm74
-rw-r--r--WebKit/mac/Plugins/WebNetscapeDeprecatedFunctions.c50
-rw-r--r--WebKit/mac/Plugins/WebNetscapeDeprecatedFunctions.h35
-rw-r--r--WebKit/mac/Plugins/WebNetscapePluginEventHandler.h82
-rw-r--r--WebKit/mac/Plugins/WebNetscapePluginEventHandler.mm50
-rw-r--r--WebKit/mac/Plugins/WebNetscapePluginEventHandlerCarbon.h81
-rw-r--r--WebKit/mac/Plugins/WebNetscapePluginEventHandlerCarbon.mm411
-rw-r--r--WebKit/mac/Plugins/WebNetscapePluginEventHandlerCocoa.h65
-rw-r--r--WebKit/mac/Plugins/WebNetscapePluginEventHandlerCocoa.mm205
-rw-r--r--WebKit/mac/Plugins/WebNetscapePluginPackage.h105
-rw-r--r--WebKit/mac/Plugins/WebNetscapePluginPackage.m798
-rw-r--r--WebKit/mac/Plugins/WebNullPluginView.h41
-rw-r--r--WebKit/mac/Plugins/WebNullPluginView.mm97
-rw-r--r--WebKit/mac/Plugins/WebPlugInStreamLoaderDelegate.h48
-rw-r--r--WebKit/mac/Plugins/WebPlugin.h132
-rw-r--r--WebKit/mac/Plugins/WebPluginContainer.h72
-rw-r--r--WebKit/mac/Plugins/WebPluginContainerCheck.h55
-rw-r--r--WebKit/mac/Plugins/WebPluginContainerCheck.mm180
-rw-r--r--WebKit/mac/Plugins/WebPluginContainerPrivate.h37
-rw-r--r--WebKit/mac/Plugins/WebPluginController.h65
-rw-r--r--WebKit/mac/Plugins/WebPluginController.mm433
-rw-r--r--WebKit/mac/Plugins/WebPluginDatabase.h71
-rw-r--r--WebKit/mac/Plugins/WebPluginDatabase.mm456
-rw-r--r--WebKit/mac/Plugins/WebPluginPackage.h39
-rw-r--r--WebKit/mac/Plugins/WebPluginPackage.m116
-rw-r--r--WebKit/mac/Plugins/WebPluginPrivate.h31
-rw-r--r--WebKit/mac/Plugins/WebPluginViewFactory.h86
-rw-r--r--WebKit/mac/Plugins/WebPluginViewFactoryPrivate.h39
-rw-r--r--WebKit/mac/Plugins/WebPluginsPrivate.h33
-rw-r--r--WebKit/mac/Plugins/WebPluginsPrivate.m31
-rw-r--r--WebKit/mac/Plugins/npapi.mm209
-rw-r--r--WebKit/mac/Plugins/nptextinput.h108
40 files changed, 9018 insertions, 0 deletions
diff --git a/WebKit/mac/Plugins/WebBaseNetscapePluginStream.h b/WebKit/mac/Plugins/WebBaseNetscapePluginStream.h
new file mode 100644
index 0000000..c2e8a21
--- /dev/null
+++ b/WebKit/mac/Plugins/WebBaseNetscapePluginStream.h
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2005 Apple Computer, 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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 ENABLE(NETSCAPE_PLUGIN_API)
+#import <Foundation/Foundation.h>
+
+#import <WebCore/Timer.h>
+#import <WebCore/NetscapePlugInStreamLoader.h>
+#import <WebKit/npfunctions.h>
+#import <WebKit/WebPlugInStreamLoaderDelegate.h>
+#import <wtf/PassRefPtr.h>
+#import <wtf/RefCounted.h>
+#import <wtf/RefPtr.h>
+#import <wtf/RetainPtr.h>
+
+#import "WebBaseNetscapePluginView.h"
+
+namespace WebCore {
+ class FrameLoader;
+ class NetscapePlugInStreamLoader;
+}
+
+@class WebBaseNetscapePluginView;
+@class NSURLResponse;
+
+class WebNetscapePluginStream : public RefCounted<WebNetscapePluginStream>
+ , private WebCore::NetscapePlugInStreamLoaderClient
+{
+public:
+ static PassRefPtr<WebNetscapePluginStream> create(NSURLRequest *request, NPP plugin, bool sendNotification, void* notifyData)
+ {
+ return adoptRef(new WebNetscapePluginStream(request, plugin, sendNotification, notifyData));
+ }
+ static PassRefPtr<WebNetscapePluginStream> create(WebCore::FrameLoader* frameLoader)
+ {
+ return adoptRef(new WebNetscapePluginStream(frameLoader));
+ }
+ virtual ~WebNetscapePluginStream();
+
+ NPP plugin() const { return m_plugin; }
+ void setPlugin(NPP);
+
+ static NPP ownerForStream(NPStream *);
+
+ static NPReason reasonForError(NSError *);
+ NSError *errorForReason(NPReason) const;
+
+ void cancelLoadAndDestroyStreamWithError(NSError *);
+
+ void setRequestURL(NSURL *requestURL) { m_requestURL = requestURL; }
+
+ void start();
+ void stop();
+
+ void startStreamWithResponse(NSURLResponse *response);
+
+ void didReceiveData(WebCore::NetscapePlugInStreamLoader*, const char* bytes, int length);
+ void destroyStreamWithError(NSError *);
+ void didFinishLoading(WebCore::NetscapePlugInStreamLoader*);
+
+private:
+ void destroyStream();
+ void cancelLoadWithError(NSError *);
+ void destroyStreamWithReason(NPReason);
+ void deliverDataToFile(NSData *data);
+ void deliverData();
+
+ void startStream(NSURL *, long long expectedContentLength, NSDate *lastModifiedDate, NSString *mimeType, NSData *headers);
+
+ NSError *pluginCancelledConnectionError() const;
+
+ // NetscapePlugInStreamLoaderClient methods.
+ void didReceiveResponse(WebCore::NetscapePlugInStreamLoader*, const WebCore::ResourceResponse&);
+ void didFail(WebCore::NetscapePlugInStreamLoader*, const WebCore::ResourceError&);
+ bool wantsAllStreams() const;
+
+ RetainPtr<NSMutableData> m_deliveryData;
+ RetainPtr<NSURL> m_requestURL;
+ RetainPtr<NSURL> m_responseURL;
+ RetainPtr<NSString> m_mimeType;
+
+ NPP m_plugin;
+ uint16 m_transferMode;
+ int32 m_offset;
+ NPStream m_stream;
+ RetainPtr<NSString> m_path;
+ int m_fileDescriptor;
+ BOOL m_sendNotification;
+ void *m_notifyData;
+ char *m_headers;
+ RetainPtr<WebBaseNetscapePluginView> m_pluginView;
+ NPReason m_reason;
+ bool m_isTerminated;
+ bool m_newStreamSuccessful;
+
+ WebCore::FrameLoader* m_frameLoader;
+ RefPtr<WebCore::NetscapePlugInStreamLoader> m_loader;
+ RetainPtr<NSMutableURLRequest> m_request;
+ NPPluginFuncs *m_pluginFuncs;
+
+ void deliverDataTimerFired(WebCore::Timer<WebNetscapePluginStream>* timer);
+ WebCore::Timer<WebNetscapePluginStream> m_deliverDataTimer;
+
+ WebNetscapePluginStream(WebCore::FrameLoader*);
+ WebNetscapePluginStream(NSURLRequest *, NPP, bool sendNotification, void* notifyData);
+};
+
+#endif
diff --git a/WebKit/mac/Plugins/WebBaseNetscapePluginStream.mm b/WebKit/mac/Plugins/WebBaseNetscapePluginStream.mm
new file mode 100644
index 0000000..246a3ca
--- /dev/null
+++ b/WebKit/mac/Plugins/WebBaseNetscapePluginStream.mm
@@ -0,0 +1,619 @@
+/*
+ * Copyright (C) 2005, 2006, 2007 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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 ENABLE(NETSCAPE_PLUGIN_API)
+#import "WebBaseNetscapePluginStream.h"
+
+#import "WebBaseNetscapePluginView.h"
+#import "WebFrameInternal.h"
+#import "WebKitErrorsPrivate.h"
+#import "WebKitLogging.h"
+#import "WebNSObjectExtras.h"
+#import "WebNSURLExtras.h"
+#import "WebNSURLRequestExtras.h"
+#import "WebNetscapePluginPackage.h"
+#import <Foundation/NSURLResponse.h>
+#import <runtime/JSLock.h>
+#import <WebCore/DocumentLoader.h>
+#import <WebCore/Frame.h>
+#import <WebCore/FrameLoader.h>
+#import <WebCore/WebCoreObjCExtras.h>
+#import <WebKitSystemInterface.h>
+#import <wtf/HashMap.h>
+
+using namespace WebCore;
+
+#define WEB_REASON_NONE -1
+
+static NSString *CarbonPathFromPOSIXPath(NSString *posixPath);
+
+typedef HashMap<NPStream*, NPP> StreamMap;
+static StreamMap& streams()
+{
+ static StreamMap staticStreams;
+ return staticStreams;
+}
+
+NPP WebNetscapePluginStream::ownerForStream(NPStream *stream)
+{
+ return streams().get(stream);
+}
+
+NPReason WebNetscapePluginStream::reasonForError(NSError *error)
+{
+ if (!error)
+ return NPRES_DONE;
+
+ if ([[error domain] isEqualToString:NSURLErrorDomain] && [error code] == NSURLErrorCancelled)
+ return NPRES_USER_BREAK;
+
+ return NPRES_NETWORK_ERR;
+}
+
+NSError *WebNetscapePluginStream::pluginCancelledConnectionError() const
+{
+ return [[[NSError alloc] _initWithPluginErrorCode:WebKitErrorPlugInCancelledConnection
+ contentURL:m_responseURL ? m_responseURL.get() : m_requestURL.get()
+ pluginPageURL:nil
+ pluginName:[[m_pluginView.get() pluginPackage] name]
+ MIMEType:m_mimeType.get()] autorelease];
+}
+
+NSError *WebNetscapePluginStream::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();
+}
+
+WebNetscapePluginStream::WebNetscapePluginStream(FrameLoader* frameLoader)
+ : m_plugin(0)
+ , m_transferMode(0)
+ , m_offset(0)
+ , m_fileDescriptor(-1)
+ , m_sendNotification(false)
+ , m_notifyData(0)
+ , m_headers(0)
+ , m_reason(NPRES_BASE)
+ , m_isTerminated(false)
+ , m_newStreamSuccessful(false)
+ , m_frameLoader(frameLoader)
+ , m_pluginFuncs(0)
+ , m_deliverDataTimer(this, &WebNetscapePluginStream::deliverDataTimerFired)
+{
+ memset(&m_stream, 0, sizeof(NPStream));
+}
+
+WebNetscapePluginStream::WebNetscapePluginStream(NSURLRequest *request, NPP plugin, bool sendNotification, void* notifyData)
+ : m_requestURL([request URL])
+ , m_plugin(0)
+ , m_transferMode(0)
+ , m_offset(0)
+ , m_fileDescriptor(-1)
+ , m_sendNotification(sendNotification)
+ , m_notifyData(notifyData)
+ , m_headers(0)
+ , m_reason(NPRES_BASE)
+ , m_isTerminated(false)
+ , m_newStreamSuccessful(false)
+ , m_frameLoader(0)
+ , m_request(AdoptNS, [request mutableCopy])
+ , m_pluginFuncs(0)
+ , m_deliverDataTimer(this, &WebNetscapePluginStream::deliverDataTimerFired)
+{
+ memset(&m_stream, 0, sizeof(NPStream));
+
+ WebBaseNetscapePluginView *view = (WebBaseNetscapePluginView *)plugin->ndata;
+
+ // This check has already been done by the plug-in view.
+ ASSERT(FrameLoader::canLoad([request URL], String(), core([view webFrame])->document()));
+
+ ASSERT([request URL]);
+ ASSERT(plugin);
+
+ setPlugin(plugin);
+
+ streams().add(&m_stream, plugin);
+
+ if (core([view webFrame])->loader()->shouldHideReferrer([request URL], core([view webFrame])->loader()->outgoingReferrer()))
+ [m_request.get() _web_setHTTPReferrer:nil];
+
+ m_loader = NetscapePlugInStreamLoader::create(core([view webFrame]), this);
+ m_loader->setShouldBufferData(false);
+}
+
+WebNetscapePluginStream::~WebNetscapePluginStream()
+{
+ ASSERT(!m_plugin);
+ ASSERT(m_isTerminated);
+ ASSERT(!m_stream.ndata);
+
+ // The stream file should have been deleted, and the path freed, in -_destroyStream
+ ASSERT(!m_path);
+ ASSERT(m_fileDescriptor == -1);
+
+ free((void *)m_stream.url);
+ free(m_headers);
+
+ streams().remove(&m_stream);
+}
+
+void WebNetscapePluginStream::setPlugin(NPP plugin)
+{
+ if (plugin) {
+ m_plugin = plugin;
+ m_pluginView = static_cast<WebBaseNetscapePluginView *>(m_plugin->ndata);
+
+ WebNetscapePluginPackage *pluginPackage = [m_pluginView.get() pluginPackage];
+
+ m_pluginFuncs = [pluginPackage pluginFuncs];
+ } else {
+ WebBaseNetscapePluginView *view = m_pluginView.get();
+ m_plugin = 0;
+ m_pluginFuncs = 0;
+
+ [view disconnectStream:this];
+ m_pluginView = 0;
+ }
+}
+
+void WebNetscapePluginStream::startStream(NSURL *url, long long expectedContentLength, NSDate *lastModifiedDate, NSString *mimeType, NSData *headers)
+{
+ ASSERT(!m_isTerminated);
+
+ m_responseURL = url;
+ m_mimeType = mimeType;
+
+ free((void *)m_stream.url);
+ m_stream.url = strdup([m_responseURL.get() _web_URLCString]);
+
+ m_stream.ndata = this;
+ m_stream.end = expectedContentLength > 0 ? (uint32)expectedContentLength : 0;
+ m_stream.lastmodified = (uint32)[lastModifiedDate timeIntervalSince1970];
+ m_stream.notifyData = m_notifyData;
+
+ if (headers) {
+ unsigned len = [headers length];
+ m_headers = (char*) malloc(len + 1);
+ [headers getBytes:m_headers];
+ m_headers[len] = 0;
+ m_stream.headers = m_headers;
+ }
+
+ m_transferMode = NP_NORMAL;
+ m_offset = 0;
+ m_reason = WEB_REASON_NONE;
+ // FIXME: If WebNetscapePluginStream called our initializer we wouldn't have to do this here.
+ m_fileDescriptor = -1;
+
+ // FIXME: Need a way to check if stream is seekable
+
+ [m_pluginView.get() willCallPlugInFunction];
+ NPError npErr = m_pluginFuncs->newstream(m_plugin, (char *)[m_mimeType.get() UTF8String], &m_stream, NO, &m_transferMode);
+ [m_pluginView.get() didCallPlugInFunction];
+ LOG(Plugins, "NPP_NewStream URL=%@ MIME=%@ error=%d", m_responseURL.get(), m_mimeType.get(), npErr);
+
+ if (npErr != NPERR_NO_ERROR) {
+ LOG_ERROR("NPP_NewStream failed with error: %d responseURL: %@", npErr, m_responseURL.get());
+ // Calling cancelLoadWithError: cancels the load, but doesn't call NPP_DestroyStream.
+ cancelLoadWithError(pluginCancelledConnectionError());
+ return;
+ }
+
+ m_newStreamSuccessful = true;
+
+ switch (m_transferMode) {
+ case NP_NORMAL:
+ LOG(Plugins, "Stream type: NP_NORMAL");
+ break;
+ case NP_ASFILEONLY:
+ LOG(Plugins, "Stream type: NP_ASFILEONLY");
+ break;
+ case NP_ASFILE:
+ LOG(Plugins, "Stream type: NP_ASFILE");
+ break;
+ case NP_SEEK:
+ LOG_ERROR("Stream type: NP_SEEK not yet supported");
+ cancelLoadAndDestroyStreamWithError(pluginCancelledConnectionError());
+ break;
+ default:
+ LOG_ERROR("unknown stream type");
+ }
+}
+
+void WebNetscapePluginStream::start()
+{
+ ASSERT(m_request);
+ ASSERT(!m_frameLoader);
+
+ m_loader->documentLoader()->addPlugInStreamLoader(m_loader.get());
+ m_loader->load(m_request.get());
+}
+
+void WebNetscapePluginStream::stop()
+{
+ ASSERT(!m_frameLoader);
+
+ if (!m_loader->isDone())
+ cancelLoadAndDestroyStreamWithError(m_loader->cancelledError());
+}
+
+void WebNetscapePluginStream::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;
+
+ // startStreamResponseURL:... will null-terminate.
+ }
+
+ startStream([r URL], expectedContentLength, WKGetNSURLResponseLastModifiedDate(r), [r MIMEType], theHeaders);
+}
+
+void WebNetscapePluginStream::startStreamWithResponse(NSURLResponse *response)
+{
+ didReceiveResponse(0, response);
+}
+
+bool WebNetscapePluginStream::wantsAllStreams() const
+{
+ if (!m_pluginFuncs->getvalue)
+ return false;
+
+ void *value = 0;
+ NPError error;
+ [m_pluginView.get() willCallPlugInFunction];
+ {
+ JSC::JSLock::DropAllLocks dropAllLocks(false);
+ error = m_pluginFuncs->getvalue(m_plugin, NPPVpluginWantsAllNetworkStreams, &value);
+ }
+ [m_pluginView.get() didCallPlugInFunction];
+ if (error != NPERR_NO_ERROR)
+ return false;
+
+ return value;
+}
+
+void WebNetscapePluginStream::destroyStream()
+{
+ if (m_isTerminated)
+ return;
+
+ RefPtr<WebNetscapePluginStream> protect(this);
+
+ ASSERT(m_reason != WEB_REASON_NONE);
+ ASSERT([m_deliveryData.get() length] == 0);
+
+ m_deliverDataTimer.stop();
+
+ if (m_stream.ndata) {
+ if (m_reason == NPRES_DONE && (m_transferMode == NP_ASFILE || m_transferMode == NP_ASFILEONLY)) {
+ ASSERT(m_fileDescriptor == -1);
+ ASSERT(m_path);
+ NSString *carbonPath = CarbonPathFromPOSIXPath(m_path.get());
+ ASSERT(carbonPath != NULL);
+ [m_pluginView.get() willCallPlugInFunction];
+ m_pluginFuncs->asfile(m_plugin, &m_stream, [carbonPath fileSystemRepresentation]);
+ [m_pluginView.get() didCallPlugInFunction];
+ LOG(Plugins, "NPP_StreamAsFile responseURL=%@ path=%s", m_responseURL.get(), carbonPath);
+ }
+
+ if (m_path) {
+ // Delete the file after calling NPP_StreamAsFile(), instead of in -dealloc/-finalize. It should be OK
+ // to delete the file here -- NPP_StreamAsFile() is always called immediately before NPP_DestroyStream()
+ // (the stream destruction function), so there can be no expectation that a plugin will read the stream
+ // file asynchronously after NPP_StreamAsFile() is called.
+ unlink([m_path.get() fileSystemRepresentation]);
+ m_path = 0;
+
+ if (m_isTerminated)
+ return;
+ }
+
+ if (m_fileDescriptor != -1) {
+ // The file may still be open if we are destroying the stream before it completed loading.
+ close(m_fileDescriptor);
+ m_fileDescriptor = -1;
+ }
+
+ if (m_newStreamSuccessful) {
+ [m_pluginView.get() willCallPlugInFunction];
+#if !LOG_DISABLED
+ NPError npErr =
+#endif
+ m_pluginFuncs->destroystream(m_plugin, &m_stream, m_reason);
+ [m_pluginView.get() didCallPlugInFunction];
+ LOG(Plugins, "NPP_DestroyStream responseURL=%@ error=%d", m_responseURL.get(), npErr);
+ }
+
+ free(m_headers);
+ m_headers = NULL;
+ m_stream.headers = NULL;
+
+ m_stream.ndata = 0;
+
+ if (m_isTerminated)
+ return;
+ }
+
+ if (m_sendNotification) {
+ // NPP_URLNotify expects the request URL, not the response URL.
+ [m_pluginView.get() willCallPlugInFunction];
+ m_pluginFuncs->urlnotify(m_plugin, [m_requestURL.get() _web_URLCString], m_reason, m_notifyData);
+ [m_pluginView.get() didCallPlugInFunction];
+ LOG(Plugins, "NPP_URLNotify requestURL=%@ reason=%d", m_requestURL.get(), m_reason);
+ }
+
+ m_isTerminated = true;
+
+ setPlugin(0);
+}
+
+void WebNetscapePluginStream::destroyStreamWithReason(NPReason reason)
+{
+ m_reason = reason;
+ if (m_reason != NPRES_DONE) {
+ // Stop any pending data from being streamed.
+ [m_deliveryData.get() setLength:0];
+ } else if ([m_deliveryData.get() length] > 0) {
+ // There is more data to be streamed, don't destroy the stream now.
+ return;
+ }
+ destroyStream();
+ ASSERT(!m_stream.ndata);
+}
+
+void WebNetscapePluginStream::cancelLoadWithError(NSError *error)
+{
+ if (m_frameLoader) {
+ ASSERT(!m_loader);
+
+ DocumentLoader* documentLoader = m_frameLoader->activeDocumentLoader();
+ ASSERT(documentLoader);
+
+ if (documentLoader->isLoadingMainResource())
+ documentLoader->cancelMainResourceLoad(error);
+ return;
+ }
+
+ if (!m_loader->isDone())
+ m_loader->cancel(error);
+}
+
+void WebNetscapePluginStream::destroyStreamWithError(NSError *error)
+{
+ destroyStreamWithReason(reasonForError(error));
+}
+
+void WebNetscapePluginStream::didFail(WebCore::NetscapePlugInStreamLoader*, const WebCore::ResourceError& error)
+{
+ destroyStreamWithError(error);
+}
+
+void WebNetscapePluginStream::cancelLoadAndDestroyStreamWithError(NSError *error)
+{
+ RefPtr<WebNetscapePluginStream> protect(this);
+ cancelLoadWithError(error);
+ destroyStreamWithError(error);
+ setPlugin(0);
+}
+
+void WebNetscapePluginStream::deliverData()
+{
+ if (!m_stream.ndata || [m_deliveryData.get() length] == 0)
+ return;
+
+ RefPtr<WebNetscapePluginStream> protect(this);
+
+ int32 totalBytes = [m_deliveryData.get() length];
+ int32 totalBytesDelivered = 0;
+
+ while (totalBytesDelivered < totalBytes) {
+ [m_pluginView.get() willCallPlugInFunction];
+ int32 deliveryBytes = m_pluginFuncs->writeready(m_plugin, &m_stream);
+ [m_pluginView.get() didCallPlugInFunction];
+ LOG(Plugins, "NPP_WriteReady responseURL=%@ bytes=%d", m_responseURL.get(), deliveryBytes);
+
+ if (m_isTerminated)
+ return;
+
+ if (deliveryBytes <= 0) {
+ // Plug-in can't receive anymore data right now. Send it later.
+ if (!m_deliverDataTimer.isActive())
+ m_deliverDataTimer.startOneShot(0);
+ break;
+ } else {
+ deliveryBytes = MIN(deliveryBytes, totalBytes - totalBytesDelivered);
+ NSData *subdata = [m_deliveryData.get() subdataWithRange:NSMakeRange(totalBytesDelivered, deliveryBytes)];
+ [m_pluginView.get() willCallPlugInFunction];
+ deliveryBytes = m_pluginFuncs->write(m_plugin, &m_stream, m_offset, [subdata length], (void *)[subdata bytes]);
+ [m_pluginView.get() didCallPlugInFunction];
+ if (deliveryBytes < 0) {
+ // Netscape documentation says that a negative result from NPP_Write means cancel the load.
+ cancelLoadAndDestroyStreamWithError(pluginCancelledConnectionError());
+ return;
+ }
+ deliveryBytes = MIN((unsigned)deliveryBytes, [subdata length]);
+ m_offset += deliveryBytes;
+ totalBytesDelivered += deliveryBytes;
+ LOG(Plugins, "NPP_Write responseURL=%@ bytes=%d total-delivered=%d/%d", m_responseURL.get(), deliveryBytes, m_offset, m_stream.end);
+ }
+ }
+
+ if (totalBytesDelivered > 0) {
+ if (totalBytesDelivered < totalBytes) {
+ NSMutableData *newDeliveryData = [[NSMutableData alloc] initWithCapacity:totalBytes - totalBytesDelivered];
+ [newDeliveryData appendBytes:(char *)[m_deliveryData.get() bytes] + totalBytesDelivered length:totalBytes - totalBytesDelivered];
+ [m_deliveryData.get() release];
+ m_deliveryData = newDeliveryData;
+ [newDeliveryData release];
+ } else {
+ [m_deliveryData.get() setLength:0];
+ if (m_reason != WEB_REASON_NONE)
+ destroyStream();
+ }
+ }
+}
+
+void WebNetscapePluginStream::deliverDataTimerFired(WebCore::Timer<WebNetscapePluginStream>* timer)
+{
+ deliverData();
+}
+
+void WebNetscapePluginStream::deliverDataToFile(NSData *data)
+{
+ if (m_fileDescriptor == -1 && !m_path) {
+ NSString *temporaryFileMask = [NSTemporaryDirectory() stringByAppendingPathComponent:@"WebKitPlugInStreamXXXXXX"];
+ char *temporaryFileName = strdup([temporaryFileMask fileSystemRepresentation]);
+ m_fileDescriptor = mkstemp(temporaryFileName);
+ if (m_fileDescriptor == -1) {
+ LOG_ERROR("Can't create a temporary file.");
+ // This is not a network error, but the only error codes are "network error" and "user break".
+ destroyStreamWithReason(NPRES_NETWORK_ERR);
+ free(temporaryFileName);
+ return;
+ }
+
+ m_path.adoptNS([[NSString stringWithUTF8String:temporaryFileName] retain]);
+ free(temporaryFileName);
+ }
+
+ int dataLength = [data length];
+ if (!dataLength)
+ return;
+
+ int byteCount = write(m_fileDescriptor, [data bytes], dataLength);
+ if (byteCount != dataLength) {
+ // This happens only rarely, when we are out of disk space or have a disk I/O error.
+ LOG_ERROR("error writing to temporary file, errno %d", errno);
+ close(m_fileDescriptor);
+ m_fileDescriptor = -1;
+
+ // This is not a network error, but the only error codes are "network error" and "user break".
+ destroyStreamWithReason(NPRES_NETWORK_ERR);
+ m_path = 0;
+ }
+}
+
+void WebNetscapePluginStream::didFinishLoading(NetscapePlugInStreamLoader*)
+{
+ if (!m_stream.ndata)
+ return;
+
+ if (m_transferMode == NP_ASFILE || m_transferMode == NP_ASFILEONLY) {
+ // Fake the delivery of an empty data to ensure that the file has been created
+ deliverDataToFile([NSData data]);
+ if (m_fileDescriptor != -1)
+ close(m_fileDescriptor);
+ m_fileDescriptor = -1;
+ }
+
+ destroyStreamWithReason(NPRES_DONE);
+}
+
+void WebNetscapePluginStream::didReceiveData(NetscapePlugInStreamLoader*, const char* bytes, int length)
+{
+ NSData *data = [[NSData alloc] initWithBytesNoCopy:(void*)bytes length:length freeWhenDone:NO];
+
+ ASSERT([data length] > 0);
+
+ if (m_transferMode != NP_ASFILEONLY) {
+ if (!m_deliveryData)
+ m_deliveryData.adoptNS([[NSMutableData alloc] initWithCapacity:[data length]]);
+ [m_deliveryData.get() appendData:data];
+ deliverData();
+ }
+ if (m_transferMode == NP_ASFILE || m_transferMode == NP_ASFILEONLY)
+ deliverDataToFile(data);
+
+ [data release];
+}
+
+static NSString *CarbonPathFromPOSIXPath(NSString *posixPath)
+{
+ // Doesn't add a trailing colon for directories; this is a problem for paths to a volume,
+ // so this function would need to be revised if we ever wanted to call it with that.
+
+ CFURLRef url = (CFURLRef)[NSURL fileURLWithPath:posixPath];
+ if (!url)
+ return nil;
+
+ return WebCFAutorelease(CFURLCopyFileSystemPath(url, kCFURLHFSPathStyle));
+}
+
+#endif
diff --git a/WebKit/mac/Plugins/WebBaseNetscapePluginView.h b/WebKit/mac/Plugins/WebBaseNetscapePluginView.h
new file mode 100644
index 0000000..909196b
--- /dev/null
+++ b/WebKit/mac/Plugins/WebBaseNetscapePluginView.h
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2005, 2007 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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 ENABLE(NETSCAPE_PLUGIN_API)
+#import <Cocoa/Cocoa.h>
+
+#import <WebKit/npfunctions.h>
+#import <WebKit/npapi.h>
+#import <WebKit/WebBasePluginPackage.h>
+#import <wtf/HashMap.h>
+#import <wtf/HashSet.h>
+
+@class DOMElement;
+@class WebDataSource;
+@class WebFrame;
+@class WebNetscapePluginPackage;
+@class WebView;
+
+class PluginTimer;
+class WebNetscapePluginStream;
+class WebNetscapePluginEventHandler;
+
+typedef union PluginPort {
+#ifndef NP_NO_QUICKDRAW
+ NP_Port qdPort;
+#endif
+ NP_CGContext cgPort;
+} PluginPort;
+
+typedef struct _NPPluginTextInputFuncs NPPluginTextInputFuncs;
+
+// Because the Adobe 7.x Acrobat plug-in has a hard coded check for a view named
+// "WebNetscapePluginDocumentView", this class must retain the old name in order
+// for the plug-in to function correctly. (rdar://problem/4699455)
+#define WebBaseNetscapePluginView WebNetscapePluginDocumentView
+
+@interface WebBaseNetscapePluginView : NSView <WebPluginManualLoader, NSTextInput>
+{
+ WebNetscapePluginPackage *pluginPackage;
+
+ NSURL *sourceURL;
+ WebFrame *_webFrame;
+
+ BOOL _loadManually;
+ RefPtr<WebNetscapePluginStream> _manualStream;
+#ifndef BUILDING_ON_TIGER
+ CALayer *_layer;
+#endif
+ unsigned _dataLengthReceived;
+ NSError *_error;
+
+ int mode;
+
+ unsigned argsCount;
+ char **cAttributes;
+ char **cValues;
+
+ NPP plugin;
+ NPWindow window;
+ NPWindow lastSetWindow;
+ PluginPort nPort;
+ PluginPort lastSetPort;
+ NPDrawingModel drawingModel;
+ NPEventModel eventModel;
+
+
+#ifndef NP_NO_QUICKDRAW
+ // This is only valid when drawingModel is NPDrawingModelQuickDraw
+ GWorldPtr offscreenGWorld;
+#endif
+
+ WebNetscapePluginEventHandler *eventHandler;
+
+ BOOL isStarted;
+ BOOL inSetWindow;
+ BOOL hasFocus;
+ BOOL isTransparent;
+ BOOL isCompletelyObscured;
+ BOOL shouldStopSoon;
+
+ BOOL shouldFireTimers;
+ uint32 currentTimerID;
+ HashMap<uint32, PluginTimer*>* timers;
+
+ unsigned pluginFunctionCallDepth;
+
+ DOMElement *element;
+
+ int32 specifiedHeight;
+ int32 specifiedWidth;
+
+ NSString *MIMEType;
+ NSURL *baseURL;
+ NSTrackingRectTag trackingTag;
+
+ HashSet<RefPtr<WebNetscapePluginStream> > streams;
+ NSMutableDictionary *pendingFrameLoads;
+
+ NPPluginTextInputFuncs *textInputFuncs;
+
+ NPP_NewProcPtr NPP_New;
+ NPP_DestroyProcPtr NPP_Destroy;
+ NPP_SetWindowProcPtr NPP_SetWindow;
+ NPP_NewStreamProcPtr NPP_NewStream;
+ NPP_DestroyStreamProcPtr NPP_DestroyStream;
+ NPP_StreamAsFileProcPtr NPP_StreamAsFile;
+ NPP_WriteReadyProcPtr NPP_WriteReady;
+ NPP_WriteProcPtr NPP_Write;
+ NPP_PrintProcPtr NPP_Print;
+ NPP_HandleEventProcPtr NPP_HandleEvent;
+ NPP_URLNotifyProcPtr NPP_URLNotify;
+ NPP_GetValueProcPtr NPP_GetValue;
+ NPP_SetValueProcPtr NPP_SetValue;
+}
+
++ (WebBaseNetscapePluginView *)currentPluginView;
+
+
+- (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
+ DOMElement:(DOMElement *)anElement;
+
+
+- (BOOL)start;
+- (BOOL)isStarted;
+- (void)stop;
+- (void)stopTimers;
+- (void)restartTimers;
+
+- (WebFrame *)webFrame;
+- (WebDataSource *)dataSource;
+- (WebView *)webView;
+- (NSWindow *)currentWindow;
+
+- (NPP)plugin;
+
+- (WebNetscapePluginPackage *)pluginPackage;
+- (void)setPluginPackage:(WebNetscapePluginPackage *)thePluginPackage;
+- (void)setMIMEType:(NSString *)theMIMEType;
+- (void)setBaseURL:(NSURL *)theBaseURL;
+- (void)setAttributeKeys:(NSArray *)keys andValues:(NSArray *)values;
+- (void)setMode:(int)theMode;
+- (void)viewWillMoveToHostWindow:(NSWindow *)hostWindow;
+- (void)viewDidMoveToHostWindow;
+- (void)disconnectStream:(WebNetscapePluginStream*)stream;
+
+// Returns the NPObject that represents the plugin interface.
+// The return value is expected to be retained.
+- (NPObject *)createPluginScriptableObject;
+
+// -willCallPlugInFunction must be called before calling any of the NPP_* functions for this view's plugin.
+// This is necessary to ensure that plug-ins are not destroyed while WebKit calls into them. Some plug-ins (Flash
+// at least) are written with the assumption that nothing they do in their plug-in functions can cause NPP_Destroy()
+// to be called. Unfortunately, this is not true, especially if the plug-in uses NPN_Invoke() to execute a
+// document.write(), which clears the document and destroys the plug-in.
+// See <rdar://problem/4480737>.
+- (void)willCallPlugInFunction;
+
+// -didCallPlugInFunction should be called after returning from a plug-in function. It should be called exactly
+// once for every call to -willCallPlugInFunction.
+// See <rdar://problem/4480737>.
+- (void)didCallPlugInFunction;
+
+- (void)handleMouseMoved:(NSEvent *)event;
+
+@end
+
+@interface WebBaseNetscapePluginView (WebInternal)
+- (BOOL)sendEvent:(void*)event isDrawRect:(BOOL)eventIsDrawRect;
+- (NPEventModel)eventModel;
+
+- (NPError)loadRequest:(NSURLRequest *)request inTarget:(NSString *)target withNotifyData:(void *)notifyData sendNotification:(BOOL)sendNotification;
+- (NPError)getURLNotify:(const char *)URL target:(const char *)target notifyData:(void *)notifyData;
+- (NPError)getURL:(const char *)URL target:(const char *)target;
+- (NPError)postURLNotify:(const char *)URL target:(const char *)target len:(UInt32)len buf:(const char *)buf file:(NPBool)file notifyData:(void *)notifyData;
+- (NPError)postURL:(const char *)URL target:(const char *)target len:(UInt32)len buf:(const char *)buf file:(NPBool)file;
+- (NPError)newStream:(NPMIMEType)type target:(const char *)target stream:(NPStream**)stream;
+- (NPError)write:(NPStream*)stream len:(SInt32)len buffer:(void *)buffer;
+- (NPError)destroyStream:(NPStream*)stream reason:(NPReason)reason;
+- (void)status:(const char *)message;
+- (const char *)userAgent;
+- (void)invalidateRect:(NPRect *)invalidRect;
+- (void)invalidateRegion:(NPRegion)invalidateRegion;
+- (void)forceRedraw;
+- (NPError)getVariable:(NPNVariable)variable value:(void *)value;
+- (NPError)setVariable:(NPPVariable)variable value:(void *)value;
+- (uint32)scheduleTimerWithInterval:(uint32)interval repeat:(NPBool)repeat timerFunc:(void (*)(NPP npp, uint32 timerID))timerFunc;
+- (void)unscheduleTimer:(uint32)timerID;
+- (NPError)popUpContextMenu:(NPMenu *)menu;
+
+@end
+
+#endif
+
diff --git a/WebKit/mac/Plugins/WebBaseNetscapePluginView.mm b/WebKit/mac/Plugins/WebBaseNetscapePluginView.mm
new file mode 100644
index 0000000..2097673
--- /dev/null
+++ b/WebKit/mac/Plugins/WebBaseNetscapePluginView.mm
@@ -0,0 +1,2948 @@
+/*
+ * Copyright (C) 2005, 2006, 2007 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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 ENABLE(NETSCAPE_PLUGIN_API)
+
+#import "WebBaseNetscapePluginView.h"
+
+#import "WebDataSourceInternal.h"
+#import "WebDefaultUIDelegate.h"
+#import "WebFrameInternal.h"
+#import "WebFrameView.h"
+#import "WebGraphicsExtras.h"
+#import "WebKitLogging.h"
+#import "WebKitNSStringExtras.h"
+#import "WebKitSystemInterface.h"
+#import "WebNSDataExtras.h"
+#import "WebNSDictionaryExtras.h"
+#import "WebNSObjectExtras.h"
+#import "WebNSURLExtras.h"
+#import "WebNSURLRequestExtras.h"
+#import "WebNSViewExtras.h"
+#import "WebNetscapePluginPackage.h"
+#import "WebBaseNetscapePluginStream.h"
+#import "WebNetscapePluginEventHandler.h"
+#import "WebNullPluginView.h"
+#import "WebPreferences.h"
+#import "WebViewInternal.h"
+#import "WebUIDelegatePrivate.h"
+#import <Carbon/Carbon.h>
+#import <runtime/JSLock.h>
+#import <WebCore/npruntime_impl.h>
+#import <WebCore/Document.h>
+#import <WebCore/DocumentLoader.h>
+#import <WebCore/Element.h>
+#import <WebCore/Frame.h>
+#import <WebCore/FrameLoader.h>
+#import <WebCore/FrameTree.h>
+#import <WebCore/Page.h>
+#import <WebCore/PluginMainThreadScheduler.h>
+#import <WebCore/ScriptController.h>
+#import <WebCore/SoftLinking.h>
+#import <WebCore/WebCoreObjCExtras.h>
+#import <WebKit/nptextinput.h>
+#import <WebKit/DOMPrivate.h>
+#import <WebKit/WebUIDelegate.h>
+#import <wtf/Assertions.h>
+#import <objc/objc-runtime.h>
+
+using namespace WebCore;
+
+#define LoginWindowDidSwitchFromUserNotification @"WebLoginWindowDidSwitchFromUserNotification"
+#define LoginWindowDidSwitchToUserNotification @"WebLoginWindowDidSwitchToUserNotification"
+
+static inline bool isDrawingModelQuickDraw(NPDrawingModel drawingModel)
+{
+#ifndef NP_NO_QUICKDRAW
+ return drawingModel == NPDrawingModelQuickDraw;
+#else
+ return false;
+#endif
+};
+
+@interface WebBaseNetscapePluginView (Internal)
+- (void)_viewHasMoved;
+- (NPError)_createPlugin;
+- (void)_destroyPlugin;
+- (NSBitmapImageRep *)_printedPluginBitmap;
+- (void)_redeliverStream;
+@end
+
+static WebBaseNetscapePluginView *currentPluginView = nil;
+
+typedef struct OpaquePortState* PortState;
+
+static const double ThrottledTimerInterval = 0.25;
+
+class PluginTimer : public TimerBase {
+public:
+ typedef void (*TimerFunc)(NPP npp, uint32 timerID);
+
+ PluginTimer(NPP npp, uint32 timerID, uint32 interval, NPBool repeat, TimerFunc timerFunc)
+ : m_npp(npp)
+ , m_timerID(timerID)
+ , m_interval(interval)
+ , m_repeat(repeat)
+ , m_timerFunc(timerFunc)
+ {
+ }
+
+ void start(bool throttle)
+ {
+ ASSERT(!isActive());
+
+ double timeInterval = throttle ? ThrottledTimerInterval : m_interval / 1000.0;
+ if (m_repeat)
+ startRepeating(timeInterval);
+ else
+ startOneShot(timeInterval);
+ }
+
+private:
+ virtual void fired()
+ {
+ m_timerFunc(m_npp, m_timerID);
+ if (!m_repeat)
+ delete this;
+ }
+
+ NPP m_npp;
+ uint32 m_timerID;
+ uint32 m_interval;
+ NPBool m_repeat;
+ TimerFunc m_timerFunc;
+};
+
+#ifndef NP_NO_QUICKDRAW
+
+// QuickDraw is not available in 64-bit
+
+typedef struct {
+ GrafPtr oldPort;
+ GDHandle oldDevice;
+ Point oldOrigin;
+ RgnHandle oldClipRegion;
+ RgnHandle oldVisibleRegion;
+ RgnHandle clipRegion;
+ BOOL forUpdate;
+} PortState_QD;
+
+#endif /* NP_NO_QUICKDRAW */
+
+typedef struct {
+ CGContextRef context;
+} PortState_CG;
+
+@class NSTextInputContext;
+@interface NSResponder (AppKitDetails)
+- (NSTextInputContext *)inputContext;
+@end
+
+@interface WebPluginRequest : NSObject
+{
+ NSURLRequest *_request;
+ NSString *_frameName;
+ void *_notifyData;
+ BOOL _didStartFromUserGesture;
+ BOOL _sendNotification;
+}
+
+- (id)initWithRequest:(NSURLRequest *)request frameName:(NSString *)frameName notifyData:(void *)notifyData sendNotification:(BOOL)sendNotification didStartFromUserGesture:(BOOL)currentEventIsUserGesture;
+
+- (NSURLRequest *)request;
+- (NSString *)frameName;
+- (void *)notifyData;
+- (BOOL)isCurrentEventUserGesture;
+- (BOOL)sendNotification;
+
+@end
+
+@interface NSData (WebPluginDataExtras)
+- (BOOL)_web_startsWithBlankLine;
+- (NSInteger)_web_locationAfterFirstBlankLine;
+@end
+
+@interface WebBaseNetscapePluginView (ForwardDeclarations)
+- (void)setWindowIfNecessary;
+- (NPError)loadRequest:(NSMutableURLRequest *)request inTarget:(const char *)cTarget withNotifyData:(void *)notifyData sendNotification:(BOOL)sendNotification;
+@end
+
+@implementation WebBaseNetscapePluginView
+
++ (void)initialize
+{
+#ifndef BUILDING_ON_TIGER
+ WebCoreObjCFinalizeOnMainThread(self);
+#endif
+ WKSendUserChangeNotifications();
+}
+
+#pragma mark EVENTS
+
+- (BOOL)superviewsHaveSuperviews
+{
+ NSView *contentView = [[self window] contentView];
+ NSView *view;
+ for (view = self; view != nil; view = [view superview]) {
+ if (view == contentView) {
+ return YES;
+ }
+ }
+ return NO;
+}
+
+
+// The WindowRef created by -[NSWindow windowRef] has a QuickDraw GrafPort that covers
+// the entire window frame (or structure region to use the Carbon term) rather then just the window content.
+// We can remove this when <rdar://problem/4201099> is fixed.
+- (void)fixWindowPort
+{
+#ifndef NP_NO_QUICKDRAW
+ ASSERT(isDrawingModelQuickDraw(drawingModel));
+
+ NSWindow *currentWindow = [self currentWindow];
+ if ([currentWindow isKindOfClass:objc_getClass("NSCarbonWindow")])
+ return;
+
+ float windowHeight = [currentWindow frame].size.height;
+ NSView *contentView = [currentWindow contentView];
+ NSRect contentRect = [contentView convertRect:[contentView frame] toView:nil]; // convert to window-relative coordinates
+
+ CGrafPtr oldPort;
+ GetPort(&oldPort);
+ SetPort(GetWindowPort((WindowRef)[currentWindow windowRef]));
+
+ MovePortTo(static_cast<short>(contentRect.origin.x), /* Flip Y */ static_cast<short>(windowHeight - NSMaxY(contentRect)));
+ PortSize(static_cast<short>(contentRect.size.width), static_cast<short>(contentRect.size.height));
+
+ SetPort(oldPort);
+#endif
+}
+
+#ifndef NP_NO_QUICKDRAW
+static UInt32 getQDPixelFormatForBitmapContext(CGContextRef context)
+{
+ UInt32 byteOrder = CGBitmapContextGetBitmapInfo(context) & kCGBitmapByteOrderMask;
+ if (byteOrder == kCGBitmapByteOrderDefault)
+ switch (CGBitmapContextGetBitsPerPixel(context)) {
+ case 16:
+ byteOrder = kCGBitmapByteOrder16Host;
+ break;
+ case 32:
+ byteOrder = kCGBitmapByteOrder32Host;
+ break;
+ }
+ switch (byteOrder) {
+ case kCGBitmapByteOrder16Little:
+ return k16LE555PixelFormat;
+ case kCGBitmapByteOrder32Little:
+ return k32BGRAPixelFormat;
+ case kCGBitmapByteOrder16Big:
+ return k16BE555PixelFormat;
+ case kCGBitmapByteOrder32Big:
+ return k32ARGBPixelFormat;
+ }
+ ASSERT_NOT_REACHED();
+ return 0;
+}
+
+static inline void getNPRect(const CGRect& cgr, NPRect& npr)
+{
+ npr.top = static_cast<uint16>(cgr.origin.y);
+ npr.left = static_cast<uint16>(cgr.origin.x);
+ npr.bottom = static_cast<uint16>(CGRectGetMaxY(cgr));
+ npr.right = static_cast<uint16>(CGRectGetMaxX(cgr));
+}
+
+#endif
+
+static inline void getNPRect(const NSRect& nr, NPRect& npr)
+{
+ npr.top = static_cast<uint16>(nr.origin.y);
+ npr.left = static_cast<uint16>(nr.origin.x);
+ npr.bottom = static_cast<uint16>(NSMaxY(nr));
+ npr.right = static_cast<uint16>(NSMaxX(nr));
+}
+
+- (NSRect)visibleRect
+{
+ // WebCore may impose an additional clip (via CSS overflow or clip properties). Fetch
+ // that clip now.
+ return NSIntersectionRect([self convertRect:[element _windowClipRect] fromView:nil], [super visibleRect]);
+}
+
+- (PortState)saveAndSetNewPortStateForUpdate:(BOOL)forUpdate
+{
+ ASSERT(drawingModel != NPDrawingModelCoreAnimation);
+ ASSERT([self currentWindow] != nil);
+
+ // If drawing with QuickDraw, fix the window port so that it has the same bounds as the NSWindow's
+ // content view. This makes it easier to convert between AppKit view and QuickDraw port coordinates.
+ if (isDrawingModelQuickDraw(drawingModel))
+ [self fixWindowPort];
+
+ // Use AppKit to convert view coordinates to NSWindow coordinates.
+ NSRect boundsInWindow = [self convertRect:[self bounds] toView:nil];
+ NSRect visibleRectInWindow = [self convertRect:[self visibleRect] toView:nil];
+
+ // 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);
+ visibleRectInWindow.origin.y = borderViewHeight - NSMaxY(visibleRectInWindow);
+
+#ifndef NP_NO_QUICKDRAW
+ WindowRef windowRef = (WindowRef)[[self currentWindow] windowRef];
+ ASSERT(windowRef);
+
+ // Look at the Carbon port to convert top-left-based window coordinates into top-left-based content coordinates.
+ if (isDrawingModelQuickDraw(drawingModel)) {
+ ::Rect portBounds;
+ CGrafPtr port = GetWindowPort(windowRef);
+ GetPortBounds(port, &portBounds);
+
+ PixMap *pix = *GetPortPixMap(port);
+ boundsInWindow.origin.x += pix->bounds.left - portBounds.left;
+ boundsInWindow.origin.y += pix->bounds.top - portBounds.top;
+ visibleRectInWindow.origin.x += pix->bounds.left - portBounds.left;
+ visibleRectInWindow.origin.y += pix->bounds.top - portBounds.top;
+ }
+#endif
+
+ window.x = (int32)boundsInWindow.origin.x;
+ window.y = (int32)boundsInWindow.origin.y;
+ window.width = static_cast<uint32>(NSWidth(boundsInWindow));
+ window.height = static_cast<uint32>(NSHeight(boundsInWindow));
+
+ // "Clip-out" the plug-in when:
+ // 1) it's not really in a window or off-screen or has no height or width.
+ // 2) window.x is a "big negative number" which is how WebCore expresses off-screen widgets.
+ // 3) the window is miniaturized or the app is hidden
+ // 4) we're inside of viewWillMoveToWindow: with a nil window. In this case, superviews may already have nil
+ // superviews and nil windows and results from convertRect:toView: are incorrect.
+ NSWindow *realWindow = [self window];
+ if (window.width <= 0 || window.height <= 0 || window.x < -100000
+ || realWindow == nil || [realWindow isMiniaturized]
+ || [NSApp isHidden]
+ || ![self superviewsHaveSuperviews]
+ || [self isHiddenOrHasHiddenAncestor]) {
+
+ // The following code tries to give plug-ins the same size they will eventually have.
+ // The specifiedWidth and specifiedHeight variables are used to predict the size that
+ // WebCore will eventually resize us to.
+
+ // The QuickTime plug-in has problems if you give it a width or height of 0.
+ // Since other plug-ins also might have the same sort of trouble, we make sure
+ // to always give plug-ins a size other than 0,0.
+
+ if (window.width <= 0)
+ window.width = specifiedWidth > 0 ? specifiedWidth : 100;
+ if (window.height <= 0)
+ window.height = specifiedHeight > 0 ? specifiedHeight : 100;
+
+ window.clipRect.bottom = window.clipRect.top;
+ window.clipRect.left = window.clipRect.right;
+ } else {
+ getNPRect(visibleRectInWindow, window.clipRect);
+ }
+
+ // Save the port state, set up the port for entry into the plugin
+ PortState portState;
+ switch (drawingModel) {
+#ifndef NP_NO_QUICKDRAW
+ case NPDrawingModelQuickDraw: {
+ // Set up NS_Port.
+ ::Rect portBounds;
+ CGrafPtr port = GetWindowPort(windowRef);
+ GetPortBounds(port, &portBounds);
+ nPort.qdPort.port = port;
+ nPort.qdPort.portx = (int32)-boundsInWindow.origin.x;
+ nPort.qdPort.porty = (int32)-boundsInWindow.origin.y;
+ window.window = &nPort;
+
+ PortState_QD *qdPortState = (PortState_QD*)malloc(sizeof(PortState_QD));
+ portState = (PortState)qdPortState;
+
+ GetGWorld(&qdPortState->oldPort, &qdPortState->oldDevice);
+
+ qdPortState->oldOrigin.h = portBounds.left;
+ qdPortState->oldOrigin.v = portBounds.top;
+
+ qdPortState->oldClipRegion = NewRgn();
+ GetPortClipRegion(port, qdPortState->oldClipRegion);
+
+ qdPortState->oldVisibleRegion = NewRgn();
+ GetPortVisibleRegion(port, qdPortState->oldVisibleRegion);
+
+ RgnHandle clipRegion = NewRgn();
+ qdPortState->clipRegion = clipRegion;
+
+ CGContextRef currentContext = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
+ if (currentContext && WKCGContextIsBitmapContext(currentContext)) {
+ // We use WKCGContextIsBitmapContext here, because if we just called CGBitmapContextGetData
+ // on any context, we'd log to the console every time. But even if WKCGContextIsBitmapContext
+ // returns true, it still might not be a context we need to create a GWorld for; for example
+ // transparency layers will return true, but return 0 for CGBitmapContextGetData.
+ void* offscreenData = CGBitmapContextGetData(currentContext);
+ if (offscreenData) {
+ // If the current context is an offscreen bitmap, then create a GWorld for it.
+ ::Rect offscreenBounds;
+ offscreenBounds.top = 0;
+ offscreenBounds.left = 0;
+ offscreenBounds.right = CGBitmapContextGetWidth(currentContext);
+ offscreenBounds.bottom = CGBitmapContextGetHeight(currentContext);
+ GWorldPtr newOffscreenGWorld;
+ QDErr err = NewGWorldFromPtr(&newOffscreenGWorld,
+ getQDPixelFormatForBitmapContext(currentContext), &offscreenBounds, 0, 0, 0,
+ static_cast<char*>(offscreenData), CGBitmapContextGetBytesPerRow(currentContext));
+ ASSERT(newOffscreenGWorld && !err);
+ if (!err) {
+ if (offscreenGWorld)
+ DisposeGWorld(offscreenGWorld);
+ offscreenGWorld = newOffscreenGWorld;
+
+ SetGWorld(offscreenGWorld, NULL);
+
+ port = offscreenGWorld;
+
+ nPort.qdPort.port = port;
+ boundsInWindow = [self bounds];
+
+ // Generate a QD origin based on the current affine transform for currentContext.
+ CGAffineTransform offscreenMatrix = CGContextGetCTM(currentContext);
+ CGPoint origin = {0,0};
+ CGPoint axisFlip = {1,1};
+ origin = CGPointApplyAffineTransform(origin, offscreenMatrix);
+ axisFlip = CGPointApplyAffineTransform(axisFlip, offscreenMatrix);
+
+ // Quartz bitmaps have origins at the bottom left, but the axes may be inverted, so handle that.
+ origin.x = offscreenBounds.left - origin.x * (axisFlip.x - origin.x);
+ origin.y = offscreenBounds.bottom + origin.y * (axisFlip.y - origin.y);
+
+ nPort.qdPort.portx = static_cast<int32>(-boundsInWindow.origin.x + origin.x);
+ nPort.qdPort.porty = static_cast<int32>(-boundsInWindow.origin.y - origin.y);
+ window.x = 0;
+ window.y = 0;
+ window.window = &nPort;
+
+ // Use the clip bounds from the context instead of the bounds we created
+ // from the window above.
+ getNPRect(CGRectOffset(CGContextGetClipBoundingBox(currentContext), -origin.x, origin.y), window.clipRect);
+ }
+ }
+ }
+
+ MacSetRectRgn(clipRegion,
+ window.clipRect.left + nPort.qdPort.portx, window.clipRect.top + nPort.qdPort.porty,
+ window.clipRect.right + nPort.qdPort.portx, window.clipRect.bottom + nPort.qdPort.porty);
+
+ // Clip to the dirty region if drawing to a window. When drawing to another bitmap context, do not clip.
+ if ([NSGraphicsContext currentContext] == [[self currentWindow] graphicsContext]) {
+ // Clip to dirty region so plug-in does not draw over already-drawn regions of the window that are
+ // not going to be redrawn this update. This forces plug-ins to play nice with z-index ordering.
+ if (forUpdate) {
+ RgnHandle viewClipRegion = NewRgn();
+
+ // Get list of dirty rects from the opaque ancestor -- WebKit does some tricks with invalidation and
+ // display to enable z-ordering for NSViews; a side-effect of this is that only the WebHTMLView
+ // knows about the true set of dirty rects.
+ NSView *opaqueAncestor = [self opaqueAncestor];
+ const NSRect *dirtyRects;
+ NSInteger dirtyRectCount, dirtyRectIndex;
+ [opaqueAncestor getRectsBeingDrawn:&dirtyRects count:&dirtyRectCount];
+
+ for (dirtyRectIndex = 0; dirtyRectIndex < dirtyRectCount; dirtyRectIndex++) {
+ NSRect dirtyRect = [self convertRect:dirtyRects[dirtyRectIndex] fromView:opaqueAncestor];
+ if (!NSEqualSizes(dirtyRect.size, NSZeroSize)) {
+ // Create a region for this dirty rect
+ RgnHandle dirtyRectRegion = NewRgn();
+ SetRectRgn(dirtyRectRegion, static_cast<short>(NSMinX(dirtyRect)), static_cast<short>(NSMinY(dirtyRect)), static_cast<short>(NSMaxX(dirtyRect)), static_cast<short>(NSMaxY(dirtyRect)));
+
+ // Union this dirty rect with the rest of the dirty rects
+ UnionRgn(viewClipRegion, dirtyRectRegion, viewClipRegion);
+ DisposeRgn(dirtyRectRegion);
+ }
+ }
+
+ // Intersect the dirty region with the clip region, so that we only draw over dirty parts
+ SectRgn(clipRegion, viewClipRegion, clipRegion);
+ DisposeRgn(viewClipRegion);
+ }
+ }
+
+ // Switch to the port and set it up.
+ SetPort(port);
+ PenNormal();
+ ForeColor(blackColor);
+ BackColor(whiteColor);
+ SetOrigin(nPort.qdPort.portx, nPort.qdPort.porty);
+ SetPortClipRegion(nPort.qdPort.port, clipRegion);
+
+ if (forUpdate) {
+ // AppKit may have tried to help us by doing a BeginUpdate.
+ // But the invalid region at that level didn't include AppKit's notion of what was not valid.
+ // We reset the port's visible region to counteract what BeginUpdate did.
+ SetPortVisibleRegion(nPort.qdPort.port, clipRegion);
+ InvalWindowRgn(windowRef, clipRegion);
+ }
+
+ qdPortState->forUpdate = forUpdate;
+ break;
+ }
+#endif /* NP_NO_QUICKDRAW */
+
+ case NPDrawingModelCoreGraphics: {
+ ASSERT([NSView focusView] == self);
+
+ CGContextRef context = static_cast<CGContextRef>([[NSGraphicsContext currentContext] graphicsPort]);
+
+ PortState_CG *cgPortState = (PortState_CG *)malloc(sizeof(PortState_CG));
+ portState = (PortState)cgPortState;
+ cgPortState->context = context;
+
+ // Update the plugin's window/context
+#ifdef NP_NO_CARBON
+ nPort.cgPort.window = (NPNSWindow *)[self currentWindow];
+#else
+ nPort.cgPort.window = eventHandler->platformWindow([self currentWindow]);
+#endif /* NP_NO_CARBON */
+ nPort.cgPort.context = context;
+ window.window = &nPort.cgPort;
+
+ // Save current graphics context's state; will be restored by -restorePortState:
+ CGContextSaveGState(context);
+
+ // Clip to the dirty region if drawing to a window. When drawing to another bitmap context, do not clip.
+ if ([NSGraphicsContext currentContext] == [[self currentWindow] graphicsContext]) {
+ // Get list of dirty rects from the opaque ancestor -- WebKit does some tricks with invalidation and
+ // display to enable z-ordering for NSViews; a side-effect of this is that only the WebHTMLView
+ // knows about the true set of dirty rects.
+ NSView *opaqueAncestor = [self opaqueAncestor];
+ const NSRect *dirtyRects;
+ NSInteger count;
+ [opaqueAncestor getRectsBeingDrawn:&dirtyRects count:&count];
+ Vector<CGRect, 16> convertedDirtyRects;
+ convertedDirtyRects.resize(count);
+ for (int i = 0; i < count; ++i)
+ reinterpret_cast<NSRect&>(convertedDirtyRects[i]) = [self convertRect:dirtyRects[i] fromView:opaqueAncestor];
+ CGContextClipToRects(context, convertedDirtyRects.data(), count);
+ }
+
+ break;
+ }
+
+ default:
+ ASSERT_NOT_REACHED();
+ portState = NULL;
+ break;
+ }
+
+ return portState;
+}
+
+- (PortState)saveAndSetNewPortState
+{
+ return [self saveAndSetNewPortStateForUpdate:NO];
+}
+
+- (void)restorePortState:(PortState)portState
+{
+ if (drawingModel == NPDrawingModelCoreAnimation)
+ return;
+
+ ASSERT([self currentWindow]);
+ ASSERT(portState);
+
+ switch (drawingModel) {
+#ifndef NP_NO_QUICKDRAW
+ case NPDrawingModelQuickDraw: {
+ PortState_QD *qdPortState = (PortState_QD *)portState;
+ WindowRef windowRef = (WindowRef)[[self currentWindow] windowRef];
+ CGrafPtr port = GetWindowPort(windowRef);
+
+ SetPort(port);
+
+ if (qdPortState->forUpdate)
+ ValidWindowRgn(windowRef, qdPortState->clipRegion);
+
+ SetOrigin(qdPortState->oldOrigin.h, qdPortState->oldOrigin.v);
+
+ SetPortClipRegion(port, qdPortState->oldClipRegion);
+ if (qdPortState->forUpdate)
+ SetPortVisibleRegion(port, qdPortState->oldVisibleRegion);
+
+ DisposeRgn(qdPortState->oldClipRegion);
+ DisposeRgn(qdPortState->oldVisibleRegion);
+ DisposeRgn(qdPortState->clipRegion);
+
+ SetGWorld(qdPortState->oldPort, qdPortState->oldDevice);
+ break;
+ }
+#endif /* NP_NO_QUICKDRAW */
+
+ case NPDrawingModelCoreGraphics:
+ ASSERT([NSView focusView] == self);
+ ASSERT(((PortState_CG *)portState)->context == nPort.cgPort.context);
+ CGContextRestoreGState(nPort.cgPort.context);
+ break;
+
+ default:
+ ASSERT_NOT_REACHED();
+ break;
+ }
+}
+
+- (BOOL)sendEvent:(void*)event isDrawRect:(BOOL)eventIsDrawRect
+{
+ if (![self window])
+ return NO;
+ ASSERT(event);
+
+ if (!isStarted)
+ return NO;
+
+ ASSERT(NPP_HandleEvent);
+
+ // Make sure we don't call NPP_HandleEvent while we're inside NPP_SetWindow.
+ // We probably don't want more general reentrancy protection; we are really
+ // protecting only against this one case, which actually comes up when
+ // you first install the SVG viewer plug-in.
+ if (inSetWindow)
+ return NO;
+
+ Frame* frame = core([self webFrame]);
+ if (!frame)
+ return NO;
+ Page* page = frame->page();
+ if (!page)
+ return NO;
+
+ bool wasDeferring = page->defersLoading();
+ if (!wasDeferring)
+ page->setDefersLoading(true);
+
+ // Can only send drawRect (updateEvt) to CoreGraphics plugins when actually drawing
+ ASSERT((drawingModel != NPDrawingModelCoreGraphics) || !eventIsDrawRect || [NSView focusView] == self);
+
+ PortState portState = NULL;
+
+ if (isDrawingModelQuickDraw(drawingModel) || (drawingModel != NPDrawingModelCoreAnimation && eventIsDrawRect)) {
+ // In CoreGraphics mode, the port state only needs to be saved/set when redrawing the plug-in view.
+ // The plug-in is not allowed to draw at any other time.
+ portState = [self saveAndSetNewPortStateForUpdate:eventIsDrawRect];
+ // We may have changed the window, so inform the plug-in.
+ [self setWindowIfNecessary];
+ }
+
+#if !defined(NDEBUG) && !defined(NP_NO_QUICKDRAW)
+ // Draw green to help debug.
+ // If we see any green we know something's wrong.
+ // Note that PaintRect() only works for QuickDraw plugins; otherwise the current QD port is undefined.
+ if (isDrawingModelQuickDraw(drawingModel) && !isTransparent && eventIsDrawRect) {
+ ForeColor(greenColor);
+ const ::Rect bigRect = { -10000, -10000, 10000, 10000 };
+ PaintRect(&bigRect);
+ ForeColor(blackColor);
+ }
+#endif
+
+ // Temporarily retain self in case the plug-in view is released while sending an event.
+ [[self retain] autorelease];
+
+ BOOL acceptedEvent;
+ [self willCallPlugInFunction];
+ {
+ JSC::JSLock::DropAllLocks dropAllLocks(false);
+ acceptedEvent = NPP_HandleEvent(plugin, event);
+ }
+ [self didCallPlugInFunction];
+
+ if (portState) {
+ if ([self currentWindow])
+ [self restorePortState:portState];
+ free(portState);
+ }
+
+ if (!wasDeferring)
+ page->setDefersLoading(false);
+
+ return acceptedEvent;
+}
+
+- (void)sendActivateEvent:(BOOL)activate
+{
+ if (!isStarted)
+ return;
+
+ eventHandler->windowFocusChanged(activate);
+}
+
+- (void)sendDrawRectEvent:(NSRect)rect
+{
+ ASSERT(eventHandler);
+
+ eventHandler->drawRect(rect);
+}
+
+- (void)stopTimers
+{
+ if (eventHandler)
+ eventHandler->stopTimers();
+
+ shouldFireTimers = NO;
+
+ if (!timers)
+ return;
+
+ HashMap<uint32, PluginTimer*>::const_iterator end = timers->end();
+ for (HashMap<uint32, PluginTimer*>::const_iterator it = timers->begin(); it != end; ++it) {
+ PluginTimer* timer = it->second;
+ timer->stop();
+ }
+}
+
+- (void)restartTimers
+{
+ ASSERT([self window]);
+
+ if (shouldFireTimers)
+ [self stopTimers];
+
+ if (!isStarted || [[self window] isMiniaturized])
+ return;
+
+ shouldFireTimers = YES;
+
+ // If the plugin is completely obscured (scrolled out of view, for example), then we will
+ // send null events at a reduced rate.
+ eventHandler->startTimers(isCompletelyObscured);
+
+ if (!timers)
+ return;
+
+ HashMap<uint32, PluginTimer*>::const_iterator end = timers->end();
+ for (HashMap<uint32, PluginTimer*>::const_iterator it = timers->begin(); it != end; ++it) {
+ PluginTimer* timer = it->second;
+ ASSERT(!timer->isActive());
+ timer->start(isCompletelyObscured);
+ }
+}
+
+- (BOOL)acceptsFirstResponder
+{
+ return YES;
+}
+
+- (void)setHasFocus:(BOOL)flag
+{
+ if (!isStarted)
+ return;
+
+ if (hasFocus == flag)
+ return;
+
+ hasFocus = flag;
+
+ // We need to null check the event handler here because
+ // the plug-in view can resign focus after it's been stopped
+ // and the event handler has been deleted.
+ if (eventHandler)
+ eventHandler->focusChanged(hasFocus);
+}
+
+- (BOOL)becomeFirstResponder
+{
+ [self setHasFocus:YES];
+ return YES;
+}
+
+- (BOOL)resignFirstResponder
+{
+ [self setHasFocus:NO];
+ return YES;
+}
+
+// AppKit doesn't call mouseDown or mouseUp on right-click. Simulate control-click
+// mouseDown and mouseUp so plug-ins get the right-click event as they do in Carbon (3125743).
+- (void)rightMouseDown:(NSEvent *)theEvent
+{
+ [self mouseDown:theEvent];
+}
+
+- (void)rightMouseUp:(NSEvent *)theEvent
+{
+ [self mouseUp:theEvent];
+}
+
+- (void)mouseDown:(NSEvent *)theEvent
+{
+ if (!isStarted)
+ return;
+
+ eventHandler->mouseDown(theEvent);
+}
+
+- (void)mouseUp:(NSEvent *)theEvent
+{
+ if (!isStarted)
+ return;
+
+ eventHandler->mouseUp(theEvent);
+}
+
+- (void)mouseEntered:(NSEvent *)theEvent
+{
+ if (!isStarted)
+ return;
+
+ eventHandler->mouseEntered(theEvent);
+}
+
+- (void)mouseExited:(NSEvent *)theEvent
+{
+ if (!isStarted)
+ return;
+
+ eventHandler->mouseExited(theEvent);
+
+ // 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.
+ [[NSCursor arrowCursor] set];
+}
+
+// We can't name this method mouseMoved because we don't want to override
+// the NSView mouseMoved implementation.
+- (void)handleMouseMoved:(NSEvent *)theEvent
+{
+ if (!isStarted)
+ return;
+
+ eventHandler->mouseMoved(theEvent);
+}
+
+- (void)mouseDragged:(NSEvent *)theEvent
+{
+ if (!isStarted)
+ return;
+
+ eventHandler->mouseDragged(theEvent);
+}
+
+- (void)scrollWheel:(NSEvent *)theEvent
+{
+ if (!isStarted) {
+ [super scrollWheel:theEvent];
+ return;
+ }
+
+ if (!eventHandler->scrollWheel(theEvent))
+ [super scrollWheel:theEvent];
+}
+
+- (void)keyUp:(NSEvent *)theEvent
+{
+ if (!isStarted)
+ return;
+
+ eventHandler->keyUp(theEvent);
+}
+
+- (void)keyDown:(NSEvent *)theEvent
+{
+ if (!isStarted)
+ return;
+
+ eventHandler->keyDown(theEvent);
+}
+
+- (void)flagsChanged:(NSEvent *)theEvent
+{
+ if (!isStarted)
+ return;
+
+ eventHandler->flagsChanged(theEvent);
+}
+
+- (void)cut:(id)sender
+{
+ if (!isStarted)
+ return;
+
+ eventHandler->keyDown([NSApp currentEvent]);
+}
+
+- (void)copy:(id)sender
+{
+ if (!isStarted)
+ return;
+
+ eventHandler->keyDown([NSApp currentEvent]);
+}
+
+- (void)paste:(id)sender
+{
+ if (!isStarted)
+ return;
+
+ eventHandler->keyDown([NSApp currentEvent]);
+}
+
+- (void)selectAll:(id)sender
+{
+ if (!isStarted)
+ return;
+
+ eventHandler->keyDown([NSApp currentEvent]);
+}
+
+#pragma mark WEB_NETSCAPE_PLUGIN
+
+- (BOOL)isNewWindowEqualToOldWindow
+{
+ ASSERT(drawingModel != NPDrawingModelCoreAnimation);
+
+ if (window.x != lastSetWindow.x)
+ return NO;
+ if (window.y != lastSetWindow.y)
+ return NO;
+ if (window.width != lastSetWindow.width)
+ return NO;
+ if (window.height != lastSetWindow.height)
+ return NO;
+ if (window.clipRect.top != lastSetWindow.clipRect.top)
+ return NO;
+ if (window.clipRect.left != lastSetWindow.clipRect.left)
+ return NO;
+ if (window.clipRect.bottom != lastSetWindow.clipRect.bottom)
+ return NO;
+ if (window.clipRect.right != lastSetWindow.clipRect.right)
+ return NO;
+ if (window.type != lastSetWindow.type)
+ return NO;
+
+ switch (drawingModel) {
+#ifndef NP_NO_QUICKDRAW
+ case NPDrawingModelQuickDraw:
+ if (nPort.qdPort.portx != lastSetPort.qdPort.portx)
+ return NO;
+ if (nPort.qdPort.porty != lastSetPort.qdPort.porty)
+ return NO;
+ if (nPort.qdPort.port != lastSetPort.qdPort.port)
+ return NO;
+ break;
+#endif /* NP_NO_QUICKDRAW */
+
+ case NPDrawingModelCoreGraphics:
+ if (nPort.cgPort.window != lastSetPort.cgPort.window)
+ return NO;
+ if (nPort.cgPort.context != lastSetPort.cgPort.context)
+ return NO;
+ break;
+
+ default:
+ ASSERT_NOT_REACHED();
+ break;
+ }
+
+ return YES;
+}
+
+- (void)updateAndSetWindow
+{
+ ASSERT(drawingModel != NPDrawingModelCoreAnimation);
+
+ // A plug-in can only update if it's (1) already been started (2) isn't stopped
+ // and (3) is able to draw on-screen. To meet condition (3) the plug-in must not
+ // be hidden and be attached to a window. QuickDraw plug-ins are an important
+ // excpetion to rule (3) because they manually must be told when to stop writing
+ // bits to the window backing store, thus to do so requires a new call to
+ // NPP_SetWindow() with an empty NPWindow struct.
+ if (!isStarted)
+ return;
+#ifdef NP_NO_QUICKDRAW
+ if (![self canDraw])
+ return;
+#else
+ if (drawingModel != NPDrawingModelQuickDraw && ![self canDraw])
+ return;
+#endif // NP_NO_QUICKDRAW
+
+ BOOL didLockFocus = [NSView focusView] != self && [self lockFocusIfCanDraw];
+
+ if (drawingModel == NPDrawingModelCoreGraphics || isDrawingModelQuickDraw(drawingModel)) {
+ [self setWindowIfNecessary];
+ if (didLockFocus)
+ [self unlockFocus];
+
+ return;
+ }
+
+ PortState portState = [self saveAndSetNewPortState];
+ if (portState) {
+ [self setWindowIfNecessary];
+ [self restorePortState:portState];
+ free(portState);
+ }
+ if (didLockFocus)
+ [self unlockFocus];
+}
+
+- (void)setWindowIfNecessary
+{
+ ASSERT(drawingModel != NPDrawingModelCoreAnimation);
+
+ if (!isStarted) {
+ return;
+ }
+
+ if (![self isNewWindowEqualToOldWindow]) {
+ // Make sure we don't call NPP_HandleEvent while we're inside NPP_SetWindow.
+ // We probably don't want more general reentrancy protection; we are really
+ // protecting only against this one case, which actually comes up when
+ // you first install the SVG viewer plug-in.
+ NPError npErr;
+ ASSERT(!inSetWindow);
+
+ inSetWindow = YES;
+
+ // A CoreGraphics plugin's window may only be set while the plugin is being updated
+ ASSERT((drawingModel != NPDrawingModelCoreGraphics) || [NSView focusView] == self);
+
+ [self willCallPlugInFunction];
+ {
+ JSC::JSLock::DropAllLocks dropAllLocks(false);
+ npErr = NPP_SetWindow(plugin, &window);
+ }
+ [self didCallPlugInFunction];
+ inSetWindow = NO;
+
+#ifndef NDEBUG
+ switch (drawingModel) {
+#ifndef NP_NO_QUICKDRAW
+ case NPDrawingModelQuickDraw:
+ LOG(Plugins, "NPP_SetWindow (QuickDraw): %d, port=0x%08x, window.x:%d window.y:%d window.width:%d window.height:%d",
+ npErr, (int)nPort.qdPort.port, (int)window.x, (int)window.y, (int)window.width, (int)window.height);
+ break;
+#endif /* NP_NO_QUICKDRAW */
+
+ case NPDrawingModelCoreGraphics:
+ LOG(Plugins, "NPP_SetWindow (CoreGraphics): %d, window=%p, context=%p, window.x:%d window.y:%d window.width:%d window.height:%d",
+ npErr, nPort.cgPort.window, nPort.cgPort.context, (int)window.x, (int)window.y, (int)window.width, (int)window.height);
+ break;
+
+ default:
+ ASSERT_NOT_REACHED();
+ break;
+ }
+#endif /* !defined(NDEBUG) */
+
+ lastSetWindow = window;
+ lastSetPort = nPort;
+ }
+}
+
+- (void)removeTrackingRect
+{
+ if (trackingTag) {
+ [self removeTrackingRect:trackingTag];
+ trackingTag = 0;
+
+ // Do the following after setting trackingTag to 0 so we don't re-enter.
+
+ // Balance the retain in resetTrackingRect. Use autorelease in case we hold
+ // the last reference to the window during tear-down, to avoid crashing AppKit.
+ [[self window] autorelease];
+ }
+}
+
+- (void)resetTrackingRect
+{
+ [self removeTrackingRect];
+ if (isStarted) {
+ // Retain the window so that removeTrackingRect can work after the window is closed.
+ [[self window] retain];
+ trackingTag = [self addTrackingRect:[self bounds] owner:self userData:nil assumeInside:NO];
+ }
+}
+
++ (void)setCurrentPluginView:(WebBaseNetscapePluginView *)view
+{
+ currentPluginView = view;
+}
+
++ (WebBaseNetscapePluginView *)currentPluginView
+{
+ return currentPluginView;
+}
+
+- (BOOL)canStart
+{
+ return YES;
+}
+
+- (void)didStart
+{
+ if (_loadManually) {
+ [self _redeliverStream];
+ return;
+ }
+
+ // If the OBJECT/EMBED tag has no SRC, the URL is passed to us as "".
+ // Check for this and don't start a load in this case.
+ if (sourceURL != nil && ![sourceURL _web_isEmpty]) {
+ NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:sourceURL];
+ [request _web_setHTTPReferrer:core([self webFrame])->loader()->outgoingReferrer()];
+ [self loadRequest:request inTarget:nil withNotifyData:nil sendNotification:NO];
+ }
+}
+
+- (void)addWindowObservers
+{
+ ASSERT([self window]);
+
+ NSWindow *theWindow = [self window];
+
+ NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
+ [notificationCenter addObserver:self selector:@selector(windowWillClose:)
+ name:NSWindowWillCloseNotification object:theWindow];
+ [notificationCenter addObserver:self selector:@selector(windowBecameKey:)
+ name:NSWindowDidBecomeKeyNotification object:theWindow];
+ [notificationCenter addObserver:self selector:@selector(windowResignedKey:)
+ name:NSWindowDidResignKeyNotification object:theWindow];
+ [notificationCenter addObserver:self selector:@selector(windowDidMiniaturize:)
+ name:NSWindowDidMiniaturizeNotification object:theWindow];
+ [notificationCenter addObserver:self selector:@selector(windowDidDeminiaturize:)
+ name:NSWindowDidDeminiaturizeNotification object:theWindow];
+
+ [notificationCenter addObserver:self selector:@selector(loginWindowDidSwitchFromUser:)
+ name:LoginWindowDidSwitchFromUserNotification object:nil];
+ [notificationCenter addObserver:self selector:@selector(loginWindowDidSwitchToUser:)
+ name:LoginWindowDidSwitchToUserNotification object:nil];
+}
+
+- (void)removeWindowObservers
+{
+ NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
+ [notificationCenter removeObserver:self name:NSWindowWillCloseNotification object:nil];
+ [notificationCenter removeObserver:self name:NSWindowDidBecomeKeyNotification object:nil];
+ [notificationCenter removeObserver:self name:NSWindowDidResignKeyNotification object:nil];
+ [notificationCenter removeObserver:self name:NSWindowDidMiniaturizeNotification object:nil];
+ [notificationCenter removeObserver:self name:NSWindowDidDeminiaturizeNotification object:nil];
+ [notificationCenter removeObserver:self name:LoginWindowDidSwitchFromUserNotification object:nil];
+ [notificationCenter removeObserver:self name:LoginWindowDidSwitchToUserNotification object:nil];
+}
+
+- (BOOL)start
+{
+ ASSERT([self currentWindow]);
+
+ if (isStarted)
+ return YES;
+
+ if (![self canStart])
+ return NO;
+
+ ASSERT([self webView]);
+
+ if (![[[self webView] preferences] arePlugInsEnabled])
+ return NO;
+
+ // Open the plug-in package so it remains loaded while our plugin uses it
+ [pluginPackage open];
+
+ // Initialize drawingModel to an invalid value so that we can detect when the plugin does not specify a drawingModel
+ drawingModel = (NPDrawingModel)-1;
+
+ // Initialize eventModel to an invalid value so that we can detect when the plugin does not specify an event model.
+ eventModel = (NPEventModel)-1;
+
+ // Plug-ins are "windowed" by default. On MacOS, windowed plug-ins share the same window and graphics port as the main
+ // browser window. Windowless plug-ins are rendered off-screen, then copied into the main browser window.
+ window.type = NPWindowTypeWindow;
+
+ NPError npErr = [self _createPlugin];
+ if (npErr != NPERR_NO_ERROR) {
+ LOG_ERROR("NPP_New failed with error: %d", npErr);
+ [self _destroyPlugin];
+ [pluginPackage close];
+ return NO;
+ }
+
+ if (drawingModel == (NPDrawingModel)-1) {
+#ifndef NP_NO_QUICKDRAW
+ // Default to QuickDraw if the plugin did not specify a drawing model.
+ drawingModel = NPDrawingModelQuickDraw;
+#else
+ // QuickDraw is not available, so we can't default to it. Instead, default to CoreGraphics.
+ drawingModel = NPDrawingModelCoreGraphics;
+#endif
+ }
+
+ if (eventModel == (NPEventModel)-1) {
+ // If the plug-in did not specify a drawing model we default to Carbon when it is available.
+#ifndef NP_NO_CARBON
+ eventModel = NPEventModelCarbon;
+#else
+ eventModel = NPEventModelCocoa;
+#endif // NP_NO_CARBON
+ }
+
+#ifndef NP_NO_CARBON
+ if (eventModel == NPEventModelCocoa && isDrawingModelQuickDraw(drawingModel)) {
+ LOG(Plugins, "Plugin can't use use Cocoa event model with QuickDraw drawing model: %@", pluginPackage);
+ [self _destroyPlugin];
+ [pluginPackage close];
+
+ return NO;
+ }
+#endif // NP_NO_CARBON
+
+#ifndef BUILDING_ON_TIGER
+ if (drawingModel == NPDrawingModelCoreAnimation) {
+ void *value = 0;
+ if (NPP_GetValue(plugin, NPPVpluginCoreAnimationLayer, &value) == NPERR_NO_ERROR && value) {
+ _layer = (CALayer *)value;
+ [self setWantsLayer:YES];
+ [self setLayer:_layer];
+ LOG(Plugins, "%@ is using Core Animation drawing model with layer %@", pluginPackage, _layer);
+ }
+
+ ASSERT(_layer);
+ }
+#endif
+
+ // Create the event handler
+ eventHandler = WebNetscapePluginEventHandler::create(self);
+
+ // Get the text input vtable
+ if (eventModel == NPEventModelCocoa) {
+ [self willCallPlugInFunction];
+ {
+ JSC::JSLock::DropAllLocks dropAllLocks(false);
+ NPPluginTextInputFuncs *value;
+ if (NPP_GetValue(plugin, NPPVpluginTextInputFuncs, &value) == NPERR_NO_ERROR && value)
+ textInputFuncs = value;
+ }
+ [self didCallPlugInFunction];
+ }
+
+ isStarted = YES;
+ [[self webView] addPluginInstanceView:self];
+
+ if (drawingModel == NPDrawingModelCoreGraphics || isDrawingModelQuickDraw(drawingModel))
+ [self updateAndSetWindow];
+
+ if ([self window]) {
+ [self addWindowObservers];
+ if ([[self window] isKeyWindow]) {
+ [self sendActivateEvent:YES];
+ }
+ [self restartTimers];
+ }
+
+ [self resetTrackingRect];
+
+ [self didStart];
+
+ return YES;
+}
+
+- (void)stop
+{
+ // If we're already calling a plug-in function, do not call NPP_Destroy(). The plug-in function we are calling
+ // may assume that its instance->pdata, or other memory freed by NPP_Destroy(), is valid and unchanged until said
+ // plugin-function returns.
+ // See <rdar://problem/4480737>.
+ if (pluginFunctionCallDepth > 0) {
+ shouldStopSoon = YES;
+ return;
+ }
+
+ [self removeTrackingRect];
+
+ if (!isStarted)
+ return;
+
+ isStarted = NO;
+
+ [[self webView] removePluginInstanceView:self];
+
+ // To stop active streams it's necessary to invoke stop() on a copy
+ // of streams. This is because calling WebNetscapePluginStream::stop() also has the side effect
+ // of removing a stream from this hash set.
+ Vector<RefPtr<WebNetscapePluginStream> > streamsCopy;
+ copyToVector(streams, streamsCopy);
+ for (size_t i = 0; i < streamsCopy.size(); i++)
+ streamsCopy[i]->stop();
+
+
+ // Stop the timers
+ [self stopTimers];
+
+ // Stop notifications and callbacks.
+ [self removeWindowObservers];
+ [[pendingFrameLoads allKeys] makeObjectsPerformSelector:@selector(_setInternalLoadDelegate:) withObject:nil];
+ [NSObject cancelPreviousPerformRequestsWithTarget:self];
+
+ // Setting the window type to 0 ensures that NPP_SetWindow will be called if the plug-in is restarted.
+ lastSetWindow.type = (NPWindowType)0;
+
+ [self _destroyPlugin];
+ [pluginPackage close];
+
+ delete eventHandler;
+ eventHandler = 0;
+
+ textInputFuncs = 0;
+}
+
+- (BOOL)isStarted
+{
+ return isStarted;
+}
+
+- (NPEventModel)eventModel
+{
+ return eventModel;
+}
+
+- (WebDataSource *)dataSource
+{
+ WebFrame *webFrame = kit(core(element)->document()->frame());
+ return [webFrame _dataSource];
+}
+
+- (WebFrame *)webFrame
+{
+ return [[self dataSource] webFrame];
+}
+
+- (WebView *)webView
+{
+ return [[self webFrame] webView];
+}
+
+- (NSWindow *)currentWindow
+{
+ return [self window] ? [self window] : [[self webView] hostWindow];
+}
+
+- (NPP)plugin
+{
+ return plugin;
+}
+
+- (WebNetscapePluginPackage *)pluginPackage
+{
+ return pluginPackage;
+}
+
+- (void)setPluginPackage:(WebNetscapePluginPackage *)thePluginPackage;
+{
+ [thePluginPackage retain];
+ [pluginPackage release];
+ pluginPackage = thePluginPackage;
+
+ NPP_New = [pluginPackage NPP_New];
+ NPP_Destroy = [pluginPackage NPP_Destroy];
+ NPP_SetWindow = [pluginPackage NPP_SetWindow];
+ NPP_NewStream = [pluginPackage NPP_NewStream];
+ NPP_WriteReady = [pluginPackage NPP_WriteReady];
+ NPP_Write = [pluginPackage NPP_Write];
+ NPP_StreamAsFile = [pluginPackage NPP_StreamAsFile];
+ NPP_DestroyStream = [pluginPackage NPP_DestroyStream];
+ NPP_HandleEvent = [pluginPackage NPP_HandleEvent];
+ NPP_URLNotify = [pluginPackage NPP_URLNotify];
+ NPP_GetValue = [pluginPackage NPP_GetValue];
+ NPP_SetValue = [pluginPackage NPP_SetValue];
+ NPP_Print = [pluginPackage NPP_Print];
+}
+
+- (void)setMIMEType:(NSString *)theMIMEType
+{
+ NSString *type = [theMIMEType copy];
+ [MIMEType release];
+ MIMEType = type;
+}
+
+- (void)setBaseURL:(NSURL *)theBaseURL
+{
+ [theBaseURL retain];
+ [baseURL release];
+ baseURL = theBaseURL;
+}
+
+- (void)setAttributeKeys:(NSArray *)keys andValues:(NSArray *)values;
+{
+ ASSERT([keys count] == [values count]);
+
+ // Convert the attributes to 2 C string arrays.
+ // These arrays are passed to NPP_New, but the strings need to be
+ // modifiable and live the entire life of the plugin.
+
+ // The Java plug-in requires the first argument to be the base URL
+ if ([MIMEType isEqualToString:@"application/x-java-applet"]) {
+ cAttributes = (char **)malloc(([keys count] + 1) * sizeof(char *));
+ cValues = (char **)malloc(([values count] + 1) * sizeof(char *));
+ cAttributes[0] = strdup("DOCBASE");
+ cValues[0] = strdup([baseURL _web_URLCString]);
+ argsCount++;
+ } else {
+ cAttributes = (char **)malloc([keys count] * sizeof(char *));
+ cValues = (char **)malloc([values count] * sizeof(char *));
+ }
+
+ BOOL isWMP = [[[pluginPackage bundle] bundleIdentifier] isEqualToString:@"com.microsoft.WMP.defaultplugin"];
+
+ unsigned i;
+ unsigned count = [keys count];
+ for (i = 0; i < count; i++) {
+ NSString *key = [keys objectAtIndex:i];
+ NSString *value = [values objectAtIndex:i];
+ if ([key _webkit_isCaseInsensitiveEqualToString:@"height"]) {
+ specifiedHeight = [value intValue];
+ } else if ([key _webkit_isCaseInsensitiveEqualToString:@"width"]) {
+ specifiedWidth = [value intValue];
+ }
+ // Avoid Window Media Player crash when these attributes are present.
+ if (isWMP && ([key _webkit_isCaseInsensitiveEqualToString:@"SAMIStyle"] || [key _webkit_isCaseInsensitiveEqualToString:@"SAMILang"])) {
+ continue;
+ }
+ cAttributes[argsCount] = strdup([key UTF8String]);
+ cValues[argsCount] = strdup([value UTF8String]);
+ LOG(Plugins, "%@ = %@", key, value);
+ argsCount++;
+ }
+}
+
+- (void)setMode:(int)theMode
+{
+ mode = theMode;
+}
+
+#pragma mark NSVIEW
+
+- (id)initWithFrame:(NSRect)frame
+ pluginPackage:(WebNetscapePluginPackage *)thePluginPackage
+ URL:(NSURL *)theURL
+ baseURL:(NSURL *)theBaseURL
+ MIMEType:(NSString *)MIME
+ attributeKeys:(NSArray *)keys
+ attributeValues:(NSArray *)values
+ loadManually:(BOOL)loadManually
+ DOMElement:(DOMElement *)anElement
+{
+ [super initWithFrame:frame];
+
+ pendingFrameLoads = [[NSMutableDictionary alloc] init];
+
+ // load the plug-in if it is not already loaded
+ if (![thePluginPackage load]) {
+ [self release];
+ return nil;
+ }
+ [self setPluginPackage:thePluginPackage];
+
+ element = [anElement retain];
+ sourceURL = [theURL retain];
+
+ [self setMIMEType:MIME];
+ [self setBaseURL:theBaseURL];
+ [self setAttributeKeys:keys andValues:values];
+ if (loadManually)
+ [self setMode:NP_FULL];
+ else
+ [self setMode:NP_EMBED];
+
+ _loadManually = loadManually;
+ return self;
+}
+
+- (id)initWithFrame:(NSRect)frame
+{
+ ASSERT_NOT_REACHED();
+ return nil;
+}
+
+- (void)fini
+{
+#ifndef NP_NO_QUICKDRAW
+ if (offscreenGWorld)
+ DisposeGWorld(offscreenGWorld);
+#endif
+
+ unsigned i;
+ for (i = 0; i < argsCount; i++) {
+ free(cAttributes[i]);
+ free(cValues[i]);
+ }
+ free(cAttributes);
+ free(cValues);
+
+ ASSERT(!eventHandler);
+
+ if (timers) {
+ deleteAllValues(*timers);
+ delete timers;
+ }
+}
+
+- (void)disconnectStream:(WebNetscapePluginStream*)stream
+{
+ streams.remove(stream);
+}
+
+- (void)dealloc
+{
+ ASSERT(!isStarted);
+
+ [sourceURL release];
+ [_error release];
+
+ [pluginPackage release];
+ [MIMEType release];
+ [baseURL release];
+ [pendingFrameLoads release];
+ [element release];
+
+ ASSERT(!plugin);
+
+ [self fini];
+
+ [super dealloc];
+}
+
+- (void)finalize
+{
+ ASSERT_MAIN_THREAD();
+ ASSERT(!isStarted);
+
+ [self fini];
+
+ [super finalize];
+}
+
+- (void)drawRect:(NSRect)rect
+{
+ if (drawingModel == NPDrawingModelCoreAnimation)
+ return;
+
+ if (!isStarted)
+ return;
+
+ if ([NSGraphicsContext currentContextDrawingToScreen])
+ [self sendDrawRectEvent:rect];
+ else {
+ NSBitmapImageRep *printedPluginBitmap = [self _printedPluginBitmap];
+ if (printedPluginBitmap) {
+ // Flip the bitmap before drawing because the QuickDraw port is flipped relative
+ // to this view.
+ CGContextRef cgContext = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
+ CGContextSaveGState(cgContext);
+ NSRect bounds = [self bounds];
+ CGContextTranslateCTM(cgContext, 0.0f, NSHeight(bounds));
+ CGContextScaleCTM(cgContext, 1.0f, -1.0f);
+ [printedPluginBitmap drawInRect:bounds];
+ CGContextRestoreGState(cgContext);
+ }
+ }
+}
+
+- (BOOL)isFlipped
+{
+ return YES;
+}
+
+- (void)renewGState
+{
+ [super renewGState];
+
+ // -renewGState is called whenever the view's geometry changes. It's a little hacky to override this method, but
+ // much safer than walking up the view hierarchy and observing frame/bounds changed notifications, since you don't
+ // have to track subsequent changes to the view hierarchy and add/remove notification observers.
+ // NSOpenGLView uses the exact same technique to reshape its OpenGL surface.
+ [self _viewHasMoved];
+}
+
+-(void)tellQuickTimeToChill
+{
+#ifndef NP_NO_QUICKDRAW
+ ASSERT(isDrawingModelQuickDraw(drawingModel));
+
+ // Make a call to the secret QuickDraw API that makes QuickTime calm down.
+ WindowRef windowRef = (WindowRef)[[self window] windowRef];
+ if (!windowRef) {
+ return;
+ }
+ CGrafPtr port = GetWindowPort(windowRef);
+ ::Rect bounds;
+ GetPortBounds(port, &bounds);
+ WKCallDrawingNotification(port, &bounds);
+#endif /* NP_NO_QUICKDRAW */
+}
+
+- (void)viewWillMoveToWindow:(NSWindow *)newWindow
+{
+ if (isDrawingModelQuickDraw(drawingModel))
+ [self tellQuickTimeToChill];
+
+ // We must remove the tracking rect before we move to the new window.
+ // Once we move to the new window, it will be too late.
+ [self removeTrackingRect];
+ [self removeWindowObservers];
+
+ // Workaround for: <rdar://problem/3822871> resignFirstResponder is not sent to first responder view when it is removed from the window
+ [self setHasFocus:NO];
+
+ if (!newWindow) {
+ if ([[self webView] hostWindow]) {
+ // View will be moved out of the actual window but it still has a host window.
+ [self stopTimers];
+ } else {
+ // View will have no associated windows.
+ [self stop];
+
+ // Stop observing WebPreferencesChangedNotification -- we only need to observe this when installed in the view hierarchy.
+ // When not in the view hierarchy, -viewWillMoveToWindow: and -viewDidMoveToWindow will start/stop the plugin as needed.
+ [[NSNotificationCenter defaultCenter] removeObserver:self name:WebPreferencesChangedNotification object:nil];
+ }
+ }
+}
+
+- (void)viewWillMoveToSuperview:(NSView *)newSuperview
+{
+ if (!newSuperview) {
+ // Stop the plug-in when it is removed from its superview. It is not sufficient to do this in -viewWillMoveToWindow:nil, because
+ // the WebView might still has a hostWindow at that point, which prevents the plug-in from being destroyed.
+ // There is no need to start the plug-in when moving into a superview. -viewDidMoveToWindow takes care of that.
+ [self stop];
+
+ // Stop observing WebPreferencesChangedNotification -- we only need to observe this when installed in the view hierarchy.
+ // When not in the view hierarchy, -viewWillMoveToWindow: and -viewDidMoveToWindow will start/stop the plugin as needed.
+ [[NSNotificationCenter defaultCenter] removeObserver:self name:WebPreferencesChangedNotification object:nil];
+ }
+}
+
+- (void)viewDidMoveToWindow
+{
+ [self resetTrackingRect];
+
+ if ([self window]) {
+ // While in the view hierarchy, observe WebPreferencesChangedNotification so that we can start/stop depending
+ // on whether plugins are enabled.
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(preferencesHaveChanged:)
+ name:WebPreferencesChangedNotification
+ object:nil];
+
+ // View moved to an actual window. Start it if not already started.
+ [self start];
+ [self restartTimers];
+ [self addWindowObservers];
+ } else if ([[self webView] hostWindow]) {
+ // View moved out of an actual window, but still has a host window.
+ // Call setWindow to explicitly "clip out" the plug-in from sight.
+ // FIXME: It would be nice to do this where we call stopNullEvents in viewWillMoveToWindow.
+ [self updateAndSetWindow];
+ }
+}
+
+- (void)viewWillMoveToHostWindow:(NSWindow *)hostWindow
+{
+ if (!hostWindow && ![self window]) {
+ // View will have no associated windows.
+ [self stop];
+
+ // Remove WebPreferencesChangedNotification observer -- we will observe once again when we move back into the window
+ [[NSNotificationCenter defaultCenter] removeObserver:self name:WebPreferencesChangedNotification object:nil];
+ }
+}
+
+- (void)viewDidMoveToHostWindow
+{
+ if ([[self webView] hostWindow]) {
+ // View now has an associated window. Start it if not already started.
+ [self start];
+ }
+}
+
+#pragma mark NOTIFICATIONS
+
+- (void)windowWillClose:(NSNotification *)notification
+{
+ [self stop];
+}
+
+- (void)windowBecameKey:(NSNotification *)notification
+{
+ [self sendActivateEvent:YES];
+ [self setNeedsDisplay:YES];
+ [self restartTimers];
+#ifndef NP_NO_CARBON
+ SetUserFocusWindow((WindowRef)[[self window] windowRef]);
+#endif // NP_NO_CARBON
+}
+
+- (void)windowResignedKey:(NSNotification *)notification
+{
+ [self sendActivateEvent:NO];
+ [self setNeedsDisplay:YES];
+ [self restartTimers];
+}
+
+- (void)windowDidMiniaturize:(NSNotification *)notification
+{
+ [self stopTimers];
+}
+
+- (void)windowDidDeminiaturize:(NSNotification *)notification
+{
+ [self stopTimers];
+}
+
+- (void)loginWindowDidSwitchFromUser:(NSNotification *)notification
+{
+ [self stopTimers];
+}
+
+-(void)loginWindowDidSwitchToUser:(NSNotification *)notification
+{
+ [self restartTimers];
+}
+
+- (void)preferencesHaveChanged:(NSNotification *)notification
+{
+ WebPreferences *preferences = [[self webView] preferences];
+ BOOL arePlugInsEnabled = [preferences arePlugInsEnabled];
+
+ if ([notification object] == preferences && isStarted != arePlugInsEnabled) {
+ if (arePlugInsEnabled) {
+ if ([self currentWindow]) {
+ [self start];
+ }
+ } else {
+ [self stop];
+ [self setNeedsDisplay:YES];
+ }
+ }
+}
+
+- (NPObject *)createPluginScriptableObject
+{
+ if (!NPP_GetValue || ![self isStarted])
+ return NULL;
+
+ NPObject *value = NULL;
+ NPError error;
+ [self willCallPlugInFunction];
+ {
+ JSC::JSLock::DropAllLocks dropAllLocks(false);
+ error = NPP_GetValue(plugin, NPPVpluginScriptableNPObject, &value);
+ }
+ [self didCallPlugInFunction];
+ if (error != NPERR_NO_ERROR)
+ return NULL;
+
+ return value;
+}
+
+- (void)willCallPlugInFunction
+{
+ ASSERT(plugin);
+
+ // Could try to prevent infinite recursion here, but it's probably not worth the effort.
+ pluginFunctionCallDepth++;
+}
+
+- (void)didCallPlugInFunction
+{
+ ASSERT(pluginFunctionCallDepth > 0);
+ 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 (pluginFunctionCallDepth == 0 && shouldStopSoon) {
+ shouldStopSoon = NO;
+ [self stop];
+ }
+}
+
+-(void)pluginView:(NSView *)pluginView receivedResponse:(NSURLResponse *)response
+{
+ ASSERT(_loadManually);
+ ASSERT(!_manualStream);
+
+ _manualStream = WebNetscapePluginStream::create(core([self webFrame])->loader());
+}
+
+- (void)pluginView:(NSView *)pluginView receivedData:(NSData *)data
+{
+ ASSERT(_loadManually);
+ ASSERT(_manualStream);
+
+ _dataLengthReceived += [data length];
+
+ if (![self isStarted])
+ return;
+
+ if (!_manualStream->plugin()) {
+
+ _manualStream->setRequestURL([[[self dataSource] request] URL]);
+ _manualStream->setPlugin([self plugin]);
+ ASSERT(_manualStream->plugin());
+
+ _manualStream->startStreamWithResponse([[self dataSource] response]);
+ }
+
+ if (_manualStream->plugin())
+ _manualStream->didReceiveData(0, static_cast<const char *>([data bytes]), [data length]);
+}
+
+- (void)pluginView:(NSView *)pluginView receivedError:(NSError *)error
+{
+ ASSERT(_loadManually);
+
+ [error retain];
+ [_error release];
+ _error = error;
+
+ if (![self isStarted]) {
+ return;
+ }
+
+ _manualStream->destroyStreamWithError(error);
+}
+
+- (void)pluginViewFinishedLoading:(NSView *)pluginView
+{
+ ASSERT(_loadManually);
+ ASSERT(_manualStream);
+
+ if ([self isStarted])
+ _manualStream->didFinishLoading(0);
+}
+
+#pragma mark NSTextInput implementation
+
+- (NSTextInputContext *)inputContext
+{
+#ifndef NP_NO_CARBON
+ if (![self isStarted] || eventModel == NPEventModelCarbon)
+ return nil;
+#endif
+
+ return [super inputContext];
+}
+
+- (BOOL)hasMarkedText
+{
+ ASSERT(eventModel == NPEventModelCocoa);
+ ASSERT([self isStarted]);
+
+ if (textInputFuncs && textInputFuncs->hasMarkedText)
+ return textInputFuncs->hasMarkedText(plugin);
+
+ return NO;
+}
+
+- (void)insertText:(id)aString
+{
+ ASSERT(eventModel == NPEventModelCocoa);
+ ASSERT([self isStarted]);
+
+ if (textInputFuncs && textInputFuncs->insertText)
+ textInputFuncs->insertText(plugin, aString);
+}
+
+- (NSRange)markedRange
+{
+ ASSERT(eventModel == NPEventModelCocoa);
+ ASSERT([self isStarted]);
+
+ if (textInputFuncs && textInputFuncs->markedRange)
+ return textInputFuncs->markedRange(plugin);
+
+ return NSMakeRange(NSNotFound, 0);
+}
+
+- (NSRange)selectedRange
+{
+ ASSERT(eventModel == NPEventModelCocoa);
+ ASSERT([self isStarted]);
+
+ if (textInputFuncs && textInputFuncs->selectedRange)
+ return textInputFuncs->selectedRange(plugin);
+
+ return NSMakeRange(NSNotFound, 0);
+}
+
+- (void)setMarkedText:(id)aString selectedRange:(NSRange)selRange
+{
+ ASSERT(eventModel == NPEventModelCocoa);
+ ASSERT([self isStarted]);
+
+ if (textInputFuncs && textInputFuncs->setMarkedText)
+ textInputFuncs->setMarkedText(plugin, aString, selRange);
+}
+
+- (void)unmarkText
+{
+ ASSERT(eventModel == NPEventModelCocoa);
+ ASSERT([self isStarted]);
+
+ if (textInputFuncs && textInputFuncs->unmarkText)
+ textInputFuncs->unmarkText(plugin);
+}
+
+- (NSArray *)validAttributesForMarkedText
+{
+ ASSERT(eventModel == NPEventModelCocoa);
+ ASSERT([self isStarted]);
+
+ if (textInputFuncs && textInputFuncs->validAttributesForMarkedText)
+ return textInputFuncs->validAttributesForMarkedText(plugin);
+
+ return [NSArray array];
+}
+
+- (NSAttributedString *)attributedSubstringFromRange:(NSRange)theRange
+{
+ ASSERT(eventModel == NPEventModelCocoa);
+ ASSERT([self isStarted]);
+
+ if (textInputFuncs && textInputFuncs->attributedSubstringFromRange)
+ return textInputFuncs->attributedSubstringFromRange(plugin, theRange);
+
+ return nil;
+}
+
+- (NSUInteger)characterIndexForPoint:(NSPoint)thePoint
+{
+ ASSERT(eventModel == NPEventModelCocoa);
+ ASSERT([self isStarted]);
+
+ if (textInputFuncs && textInputFuncs->characterIndexForPoint) {
+ // Convert the point to window coordinates
+ NSPoint point = [[self window] convertScreenToBase:thePoint];
+
+ // And view coordinates
+ point = [self convertPoint:point fromView:nil];
+
+ return textInputFuncs->characterIndexForPoint(plugin, point);
+ }
+
+ return NSNotFound;
+}
+
+- (void)doCommandBySelector:(SEL)aSelector
+{
+ ASSERT(eventModel == NPEventModelCocoa);
+ ASSERT([self isStarted]);
+
+ if (textInputFuncs && textInputFuncs->doCommandBySelector)
+ textInputFuncs->doCommandBySelector(plugin, aSelector);
+}
+
+- (NSRect)firstRectForCharacterRange:(NSRange)theRange
+{
+ ASSERT(eventModel == NPEventModelCocoa);
+ ASSERT([self isStarted]);
+
+ if (textInputFuncs && textInputFuncs->firstRectForCharacterRange) {
+ NSRect rect = textInputFuncs->firstRectForCharacterRange(plugin, theRange);
+
+ // Convert the rect to window coordinates
+ rect = [self convertRect:rect toView:nil];
+
+ // Convert the rect location to screen coordinates
+ rect.origin = [[self window] convertBaseToScreen:rect.origin];
+
+ return rect;
+ }
+
+ return NSZeroRect;
+}
+
+// test for 10.4 because of <rdar://problem/4243463>
+#ifdef BUILDING_ON_TIGER
+- (long)conversationIdentifier
+{
+ return (long)self;
+}
+#else
+- (NSInteger)conversationIdentifier
+{
+ return (NSInteger)self;
+}
+#endif
+
+@end
+
+@implementation WebBaseNetscapePluginView (WebNPPCallbacks)
+
+- (NSMutableURLRequest *)requestWithURLCString:(const char *)URLCString
+{
+ if (!URLCString)
+ return nil;
+
+ CFStringRef string = CFStringCreateWithCString(kCFAllocatorDefault, URLCString, kCFStringEncodingISOLatin1);
+ ASSERT(string); // All strings should be representable in ISO Latin 1
+
+ NSString *URLString = [(NSString *)string _web_stringByStrippingReturnCharacters];
+ NSURL *URL = [NSURL _web_URLWithDataAsString:URLString relativeToURL:baseURL];
+ CFRelease(string);
+ if (!URL)
+ return nil;
+
+ NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
+ Frame* frame = core([self webFrame]);
+ if (!frame)
+ return nil;
+ [request _web_setHTTPReferrer:frame->loader()->outgoingReferrer()];
+ return request;
+}
+
+- (void)evaluateJavaScriptPluginRequest:(WebPluginRequest *)JSPluginRequest
+{
+ // FIXME: Is this isStarted check needed here? evaluateJavaScriptPluginRequest should not be called
+ // if we are stopped since this method is called after a delay and we call
+ // cancelPreviousPerformRequestsWithTarget inside of stop.
+ if (!isStarted) {
+ return;
+ }
+
+ NSURL *URL = [[JSPluginRequest request] URL];
+ NSString *JSString = [URL _webkit_scriptIfJavaScriptURL];
+ ASSERT(JSString);
+
+ NSString *result = [[self webFrame] _stringByEvaluatingJavaScriptFromString:JSString forceUserGesture:[JSPluginRequest isCurrentEventUserGesture]];
+
+ // Don't continue if stringByEvaluatingJavaScriptFromString caused the plug-in to stop.
+ if (!isStarted) {
+ return;
+ }
+
+ if ([JSPluginRequest frameName] != nil) {
+ // FIXME: If the result is a string, we probably want to put that string into the frame.
+ if ([JSPluginRequest sendNotification]) {
+ [self willCallPlugInFunction];
+ {
+ JSC::JSLock::DropAllLocks dropAllLocks(false);
+ NPP_URLNotify(plugin, [URL _web_URLCString], NPRES_DONE, [JSPluginRequest notifyData]);
+ }
+ [self didCallPlugInFunction];
+ }
+ } else 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<WebNetscapePluginStream> stream = WebNetscapePluginStream::create([NSURLRequest requestWithURL:URL], plugin, [JSPluginRequest sendNotification], [JSPluginRequest notifyData]);
+
+ 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)webFrame:(WebFrame *)webFrame didFinishLoadWithReason:(NPReason)reason
+{
+ ASSERT(isStarted);
+
+ WebPluginRequest *pluginRequest = [pendingFrameLoads objectForKey:webFrame];
+ ASSERT(pluginRequest != nil);
+ ASSERT([pluginRequest sendNotification]);
+
+ [self willCallPlugInFunction];
+ {
+ JSC::JSLock::DropAllLocks dropAllLocks(false);
+ NPP_URLNotify(plugin, [[[pluginRequest request] URL] _web_URLCString], reason, [pluginRequest notifyData]);
+ }
+ [self didCallPlugInFunction];
+
+ [pendingFrameLoads removeObjectForKey:webFrame];
+ [webFrame _setInternalLoadDelegate:nil];
+}
+
+- (void)webFrame:(WebFrame *)webFrame didFinishLoadWithError:(NSError *)error
+{
+ NPReason reason = NPRES_DONE;
+ if (error != nil)
+ reason = WebNetscapePluginStream::reasonForError(error);
+ [self webFrame:webFrame didFinishLoadWithReason:reason];
+}
+
+- (void)loadPluginRequest:(WebPluginRequest *)pluginRequest
+{
+ 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([self webFrame])->loader()->findFrameForNavigation(frameName));
+ if (frame == nil) {
+ WebView *currentWebView = [self webView];
+ NSDictionary *features = [[NSDictionary alloc] init];
+ WebView *newWebView = [[currentWebView _UIDelegateForwarder] webView:currentWebView
+ createWebViewWithRequest:nil
+ windowFeatures:features];
+ [features release];
+
+ if (!newWebView) {
+ if ([pluginRequest sendNotification]) {
+ [self willCallPlugInFunction];
+ {
+ JSC::JSLock::DropAllLocks dropAllLocks(false);
+ NPP_URLNotify(plugin, [[[pluginRequest request] URL] _web_URLCString], NPERR_GENERIC_ERROR, [pluginRequest notifyData]);
+ }
+ [self didCallPlugInFunction];
+ }
+ return;
+ }
+
+ frame = [newWebView mainFrame];
+ core(frame)->tree()->setName(frameName);
+ [[newWebView _UIDelegateForwarder] webViewShow:newWebView];
+ }
+ }
+
+ if (JSString) {
+ ASSERT(frame == nil || [self webFrame] == frame);
+ [self evaluateJavaScriptPluginRequest:pluginRequest];
+ } else {
+ [frame loadRequest:request];
+ if ([pluginRequest sendNotification]) {
+ // 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.
+ WebBaseNetscapePluginView *view = [frame _internalLoadDelegate];
+ if (view != nil) {
+ ASSERT([view isKindOfClass:[WebBaseNetscapePluginView class]]);
+ [view webFrame:frame didFinishLoadWithReason:NPRES_USER_BREAK];
+ }
+ [pendingFrameLoads _webkit_setObject:pluginRequest forUncopiedKey:frame];
+ [frame _setInternalLoadDelegate:self];
+ }
+ }
+}
+
+- (NPError)loadRequest:(NSMutableURLRequest *)request inTarget:(const char *)cTarget withNotifyData:(void *)notifyData sendNotification:(BOOL)sendNotification
+{
+ 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.
+ if ([[self dataSource] _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 = [self 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 ([[self dataSource] _documentLoader] != core([self webFrame])->loader()->activeDocumentLoader() &&
+ (!cTarget || [frame findFrameNamed:target] != frame)) {
+ return NPERR_GENERIC_ERROR;
+ }
+
+ NSString *JSString = [URL _webkit_scriptIfJavaScriptURL];
+ if (JSString != nil) {
+ if (![[[self webView] preferences] isJavaScriptEnabled]) {
+ // Return NPERR_GENERIC_ERROR if JS is disabled. This is what Mozilla does.
+ return NPERR_GENERIC_ERROR;
+ } else if (cTarget == NULL && mode == NP_FULL) {
+ // Don't allow a JavaScript request from a standalone plug-in that is self-targetted
+ // because this can cause the user to be redirected to a blank page (3424039).
+ return NPERR_INVALID_PARAM;
+ }
+ } else {
+ if (!FrameLoader::canLoad(URL, String(), core([self webFrame])->document()))
+ return NPERR_GENERIC_ERROR;
+ }
+
+ 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;
+ }
+
+ bool currentEventIsUserGesture = false;
+ if (eventHandler)
+ currentEventIsUserGesture = eventHandler->currentEventIsUserGesture();
+
+ WebPluginRequest *pluginRequest = [[WebPluginRequest alloc] initWithRequest:request
+ frameName:target
+ notifyData:notifyData
+ sendNotification:sendNotification
+ didStartFromUserGesture:currentEventIsUserGesture];
+ [self performSelector:@selector(loadPluginRequest:) withObject:pluginRequest afterDelay:0];
+ [pluginRequest release];
+ } else {
+ RefPtr<WebNetscapePluginStream> stream = WebNetscapePluginStream::create(request, plugin, sendNotification, notifyData);
+
+ streams.add(stream.get());
+ stream->start();
+ }
+
+ return NPERR_NO_ERROR;
+}
+
+-(NPError)getURLNotify:(const char *)URLCString target:(const char *)cTarget notifyData:(void *)notifyData
+{
+ LOG(Plugins, "NPN_GetURLNotify: %s target: %s", URLCString, cTarget);
+
+ NSMutableURLRequest *request = [self requestWithURLCString:URLCString];
+ return [self loadRequest:request inTarget:cTarget withNotifyData:notifyData sendNotification:YES];
+}
+
+-(NPError)getURL:(const char *)URLCString target:(const char *)cTarget
+{
+ LOG(Plugins, "NPN_GetURL: %s target: %s", URLCString, cTarget);
+
+ NSMutableURLRequest *request = [self requestWithURLCString:URLCString];
+ return [self loadRequest:request inTarget:cTarget withNotifyData:NULL sendNotification:NO];
+}
+
+- (NPError)_postURL:(const char *)URLCString
+ target:(const char *)target
+ len:(UInt32)len
+ buf:(const char *)buf
+ file:(NPBool)file
+ notifyData:(void *)notifyData
+ sendNotification:(BOOL)sendNotification
+ allowHeaders:(BOOL)allowHeaders
+{
+ if (!URLCString || !len || !buf) {
+ return NPERR_INVALID_PARAM;
+ }
+
+ NSData *postData = nil;
+
+ if (file) {
+ // If we're posting a file, buf is either a file URL or a path to the file.
+ NSString *bufString = (NSString *)CFStringCreateWithCString(kCFAllocatorDefault, buf, kCFStringEncodingWindowsLatin1);
+ if (!bufString) {
+ return NPERR_INVALID_PARAM;
+ }
+ NSURL *fileURL = [NSURL _web_URLWithDataAsString:bufString];
+ NSString *path;
+ if ([fileURL isFileURL]) {
+ path = [fileURL path];
+ } else {
+ path = bufString;
+ }
+ postData = [NSData dataWithContentsOfFile:[path _webkit_fixedCarbonPOSIXPath]];
+ CFRelease(bufString);
+ if (!postData) {
+ return NPERR_FILE_NOT_FOUND;
+ }
+ } else {
+ postData = [NSData dataWithBytes:buf length:len];
+ }
+
+ if ([postData length] == 0) {
+ return NPERR_INVALID_PARAM;
+ }
+
+ NSMutableURLRequest *request = [self requestWithURLCString:URLCString];
+ [request setHTTPMethod:@"POST"];
+
+ if (allowHeaders) {
+ if ([postData _web_startsWithBlankLine]) {
+ postData = [postData subdataWithRange:NSMakeRange(1, [postData length] - 1)];
+ } else {
+ NSInteger location = [postData _web_locationAfterFirstBlankLine];
+ if (location != NSNotFound) {
+ // If the blank line is somewhere in the middle of postData, everything before is the header.
+ NSData *headerData = [postData subdataWithRange:NSMakeRange(0, location)];
+ NSMutableDictionary *header = [headerData _webkit_parseRFC822HeaderFields];
+ unsigned dataLength = [postData length] - location;
+
+ // Sometimes plugins like to set Content-Length themselves when they post,
+ // but WebFoundation 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 != nil)
+ dataLength = MIN((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.
+ postData = [postData subdataWithRange:NSMakeRange(location, dataLength)];
+
+ }
+ }
+ if ([postData length] == 0) {
+ return NPERR_INVALID_PARAM;
+ }
+ }
+
+ // Plug-ins expect to receive uncached data when doing a POST (3347134).
+ [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
+ [request setHTTPBody:postData];
+
+ return [self loadRequest:request inTarget:target withNotifyData:notifyData sendNotification:sendNotification];
+}
+
+- (NPError)postURLNotify:(const char *)URLCString
+ target:(const char *)target
+ len:(UInt32)len
+ buf:(const char *)buf
+ file:(NPBool)file
+ notifyData:(void *)notifyData
+{
+ LOG(Plugins, "NPN_PostURLNotify: %s", URLCString);
+ return [self _postURL:URLCString target:target len:len buf:buf file:file notifyData:notifyData sendNotification:YES allowHeaders:YES];
+}
+
+-(NPError)postURL:(const char *)URLCString
+ target:(const char *)target
+ len:(UInt32)len
+ buf:(const char *)buf
+ file:(NPBool)file
+{
+ LOG(Plugins, "NPN_PostURL: %s", URLCString);
+ // As documented, only allow headers to be specified via NPP_PostURL when using a file.
+ return [self _postURL:URLCString target:target len:len buf:buf file:file notifyData:NULL sendNotification:NO allowHeaders:file];
+}
+
+-(NPError)newStream:(NPMIMEType)type target:(const char *)target stream:(NPStream**)stream
+{
+ LOG(Plugins, "NPN_NewStream");
+ return NPERR_GENERIC_ERROR;
+}
+
+-(NPError)write:(NPStream*)stream len:(SInt32)len buffer:(void *)buffer
+{
+ LOG(Plugins, "NPN_Write");
+ return NPERR_GENERIC_ERROR;
+}
+
+-(NPError)destroyStream:(NPStream*)stream reason:(NPReason)reason
+{
+ LOG(Plugins, "NPN_DestroyStream");
+ // This function does a sanity check to ensure that the NPStream provided actually
+ // belongs to the plug-in that provided it, which fixes a crash in the DivX
+ // plug-in: <rdar://problem/5093862> | http://bugs.webkit.org/show_bug.cgi?id=13203
+ if (!stream || WebNetscapePluginStream::ownerForStream(stream) != plugin) {
+ LOG(Plugins, "Invalid NPStream passed to NPN_DestroyStream: %p", stream);
+ return NPERR_INVALID_INSTANCE_ERROR;
+ }
+
+ WebNetscapePluginStream* browserStream = static_cast<WebNetscapePluginStream*>(stream->ndata);
+ browserStream->cancelLoadAndDestroyStreamWithError(browserStream->errorForReason(reason));
+
+ return NPERR_NO_ERROR;
+}
+
+- (const char *)userAgent
+{
+ return [[[self webView] userAgentForURL:baseURL] UTF8String];
+}
+
+-(void)status:(const char *)message
+{
+ if (!message) {
+ LOG_ERROR("NPN_Status passed a NULL status message");
+ return;
+ }
+
+ CFStringRef status = CFStringCreateWithCString(NULL, message, kCFStringEncodingUTF8);
+ if (!status) {
+ LOG_ERROR("NPN_Status: the message was not valid UTF-8");
+ return;
+ }
+
+ LOG(Plugins, "NPN_Status: %@", status);
+ WebView *wv = [self webView];
+ [[wv _UIDelegateForwarder] webView:wv setStatusText:(NSString *)status];
+ CFRelease(status);
+}
+
+-(void)invalidateRect:(NPRect *)invalidRect
+{
+ LOG(Plugins, "NPN_InvalidateRect");
+ [self setNeedsDisplayInRect:NSMakeRect(invalidRect->left, invalidRect->top,
+ (float)invalidRect->right - invalidRect->left, (float)invalidRect->bottom - invalidRect->top)];
+}
+
+-(BOOL)isOpaque
+{
+ return YES;
+}
+
+- (void)invalidateRegion:(NPRegion)invalidRegion
+{
+ LOG(Plugins, "NPN_InvalidateRegion");
+ NSRect invalidRect = NSZeroRect;
+ switch (drawingModel) {
+#ifndef NP_NO_QUICKDRAW
+ case NPDrawingModelQuickDraw:
+ {
+ ::Rect qdRect;
+ GetRegionBounds((NPQDRegion)invalidRegion, &qdRect);
+ invalidRect = NSMakeRect(qdRect.left, qdRect.top, qdRect.right - qdRect.left, qdRect.bottom - qdRect.top);
+ }
+ break;
+#endif /* NP_NO_QUICKDRAW */
+
+ case NPDrawingModelCoreGraphics:
+ {
+ CGRect cgRect = CGPathGetBoundingBox((NPCGRegion)invalidRegion);
+ invalidRect = *(NSRect*)&cgRect;
+ break;
+ }
+ default:
+ ASSERT_NOT_REACHED();
+ break;
+ }
+
+ [self setNeedsDisplayInRect:invalidRect];
+}
+
+-(void)forceRedraw
+{
+ LOG(Plugins, "forceRedraw");
+ [self setNeedsDisplay:YES];
+ [[self window] displayIfNeeded];
+}
+
+static NPBrowserTextInputFuncs *browserTextInputFuncs()
+{
+ static NPBrowserTextInputFuncs inputFuncs = {
+ 0,
+ sizeof(NPBrowserTextInputFuncs),
+ NPN_MarkedTextAbandoned,
+ NPN_MarkedTextSelectionChanged
+ };
+
+ return &inputFuncs;
+}
+
+- (NPError)getVariable:(NPNVariable)variable value:(void *)value
+{
+ switch (variable) {
+ case NPNVWindowNPObject:
+ {
+ Frame* frame = core([self webFrame]);
+ NPObject* windowScriptObject = frame ? frame->script()->windowScriptNPObject() : 0;
+
+ // Return value is expected to be retained, as described here: <http://www.mozilla.org/projects/plugins/npruntime.html#browseraccess>
+ if (windowScriptObject)
+ _NPN_RetainObject(windowScriptObject);
+
+ void **v = (void **)value;
+ *v = windowScriptObject;
+
+ return NPERR_NO_ERROR;
+ }
+
+ case NPNVPluginElementNPObject:
+ {
+ if (!element)
+ return NPERR_GENERIC_ERROR;
+
+ NPObject *plugInScriptObject = (NPObject *)[element _NPObject];
+
+ // Return value is expected to be retained, as described here: <http://www.mozilla.org/projects/plugins/npruntime.html#browseraccess>
+ if (plugInScriptObject)
+ _NPN_RetainObject(plugInScriptObject);
+
+ void **v = (void **)value;
+ *v = plugInScriptObject;
+
+ return NPERR_NO_ERROR;
+ }
+
+ case NPNVpluginDrawingModel:
+ {
+ *(NPDrawingModel *)value = drawingModel;
+ return NPERR_NO_ERROR;
+ }
+
+#ifndef NP_NO_QUICKDRAW
+ case NPNVsupportsQuickDrawBool:
+ {
+ *(NPBool *)value = TRUE;
+ return NPERR_NO_ERROR;
+ }
+#endif /* NP_NO_QUICKDRAW */
+
+ case NPNVsupportsCoreGraphicsBool:
+ {
+ *(NPBool *)value = TRUE;
+ return NPERR_NO_ERROR;
+ }
+
+ case NPNVsupportsOpenGLBool:
+ {
+ *(NPBool *)value = FALSE;
+ return NPERR_NO_ERROR;
+ }
+
+ case NPNVsupportsCoreAnimationBool:
+ {
+#ifdef BUILDING_ON_TIGER
+ *(NPBool *)value = FALSE;
+#else
+ *(NPBool *)value = TRUE;
+#endif
+ return NPERR_NO_ERROR;
+ }
+
+#ifndef NP_NO_CARBON
+ case NPNVsupportsCarbonBool:
+ {
+ *(NPBool *)value = TRUE;
+ return NPERR_NO_ERROR;
+ }
+#endif /* NP_NO_CARBON */
+
+ case NPNVsupportsCocoaBool:
+ {
+ *(NPBool *)value = TRUE;
+ return NPERR_NO_ERROR;
+ }
+
+ case NPNVbrowserTextInputFuncs:
+ {
+ if (eventModel == NPEventModelCocoa) {
+ *(NPBrowserTextInputFuncs **)value = browserTextInputFuncs();
+ return NPERR_NO_ERROR;
+ }
+ }
+ default:
+ break;
+ }
+
+ return NPERR_GENERIC_ERROR;
+}
+
+- (NPError)setVariable:(NPPVariable)variable value:(void *)value
+{
+ switch (variable) {
+ case NPPVpluginWindowBool:
+ {
+ NPWindowType newWindowType = (value ? NPWindowTypeWindow : NPWindowTypeDrawable);
+
+ // Redisplay if window type is changing (some drawing models can only have their windows set while updating).
+ if (newWindowType != window.type)
+ [self setNeedsDisplay:YES];
+
+ window.type = newWindowType;
+ }
+
+ case NPPVpluginTransparentBool:
+ {
+ BOOL newTransparent = (value != 0);
+
+ // Redisplay if transparency is changing
+ if (isTransparent != newTransparent)
+ [self setNeedsDisplay:YES];
+
+ isTransparent = newTransparent;
+
+ return NPERR_NO_ERROR;
+ }
+
+ case NPPVpluginDrawingModel:
+ {
+ // Can only set drawing model inside NPP_New()
+ if (self != [[self class] currentPluginView])
+ return NPERR_GENERIC_ERROR;
+
+ // Check for valid, supported drawing model
+ NPDrawingModel newDrawingModel = (NPDrawingModel)(uintptr_t)value;
+ switch (newDrawingModel) {
+ // Supported drawing models:
+#ifndef NP_NO_QUICKDRAW
+ case NPDrawingModelQuickDraw:
+#endif
+ case NPDrawingModelCoreGraphics:
+ drawingModel = newDrawingModel;
+ return NPERR_NO_ERROR;
+
+ case NPDrawingModelCoreAnimation:
+ drawingModel = newDrawingModel;
+ return NPERR_NO_ERROR;
+
+
+ // Unsupported (or unknown) drawing models:
+ default:
+ LOG(Plugins, "Plugin %@ uses unsupported drawing model: %d", pluginPackage, drawingModel);
+ return NPERR_GENERIC_ERROR;
+ }
+ }
+
+ case NPPVpluginEventModel:
+ {
+ // Can only set event model inside NPP_New()
+ if (self != [[self class] currentPluginView])
+ return NPERR_GENERIC_ERROR;
+
+ // Check for valid, supported event model
+ NPEventModel newEventModel = (NPEventModel)(uintptr_t)value;
+ switch (newEventModel) {
+ // Supported event models:
+#ifndef NP_NO_CARBON
+ case NPEventModelCarbon:
+#endif
+ case NPEventModelCocoa:
+ eventModel = newEventModel;
+ return NPERR_NO_ERROR;
+
+ // Unsupported (or unknown) event models:
+ default:
+ LOG(Plugins, "Plugin %@ uses unsupported event model: %d", pluginPackage, eventModel);
+ return NPERR_GENERIC_ERROR;
+ }
+ }
+
+ default:
+ return NPERR_GENERIC_ERROR;
+ }
+}
+
+- (uint32)scheduleTimerWithInterval:(uint32)interval repeat:(NPBool)repeat timerFunc:(void (*)(NPP npp, uint32 timerID))timerFunc
+{
+ if (!timerFunc)
+ return 0;
+
+ if (!timers)
+ timers = new HashMap<uint32, PluginTimer*>;
+
+ uint32 timerID = ++currentTimerID;
+
+ PluginTimer* timer = new PluginTimer(plugin, timerID, interval, repeat, timerFunc);
+ timers->set(timerID, timer);
+
+ if (shouldFireTimers)
+ timer->start(isCompletelyObscured);
+
+ return 0;
+}
+
+- (void)unscheduleTimer:(uint32)timerID
+{
+ if (!timers)
+ return;
+
+ if (PluginTimer* timer = timers->take(timerID))
+ delete timer;
+}
+
+- (NPError)popUpContextMenu:(NPMenu *)menu
+{
+ NSEvent *currentEvent = [NSApp currentEvent];
+
+ // NPN_PopUpContextMenu must be called from within the plug-in's NPP_HandleEvent.
+ if (!currentEvent)
+ return NPERR_GENERIC_ERROR;
+
+ [NSMenu popUpContextMenu:(NSMenu *)menu withEvent:currentEvent forView:self];
+ return NPERR_NO_ERROR;
+}
+
+@end
+
+@implementation WebPluginRequest
+
+- (id)initWithRequest:(NSURLRequest *)request frameName:(NSString *)frameName notifyData:(void *)notifyData sendNotification:(BOOL)sendNotification didStartFromUserGesture:(BOOL)currentEventIsUserGesture
+{
+ [super init];
+ _didStartFromUserGesture = currentEventIsUserGesture;
+ _request = [request retain];
+ _frameName = [frameName retain];
+ _notifyData = notifyData;
+ _sendNotification = sendNotification;
+ return self;
+}
+
+- (void)dealloc
+{
+ [_request release];
+ [_frameName release];
+ [super dealloc];
+}
+
+- (NSURLRequest *)request
+{
+ return _request;
+}
+
+- (NSString *)frameName
+{
+ return _frameName;
+}
+
+- (BOOL)isCurrentEventUserGesture
+{
+ return _didStartFromUserGesture;
+}
+
+- (BOOL)sendNotification
+{
+ return _sendNotification;
+}
+
+- (void *)notifyData
+{
+ return _notifyData;
+}
+
+@end
+
+@implementation WebBaseNetscapePluginView (Internal)
+
+- (NPError)_createPlugin
+{
+ plugin = (NPP)calloc(1, sizeof(NPP_t));
+ plugin->ndata = self;
+
+ ASSERT(NPP_New);
+
+ // NPN_New(), which creates the plug-in instance, should never be called while calling a plug-in function for that instance.
+ ASSERT(pluginFunctionCallDepth == 0);
+
+ Frame* frame = core([self webFrame]);
+ if (!frame)
+ return NPERR_GENERIC_ERROR;
+ Page* page = frame->page();
+ if (!page)
+ return NPERR_GENERIC_ERROR;
+
+ bool wasDeferring = page->defersLoading();
+ if (!wasDeferring)
+ page->setDefersLoading(true);
+
+ PluginMainThreadScheduler::scheduler().registerPlugin(plugin);
+
+ [[self class] setCurrentPluginView:self];
+ NPError npErr = NPP_New((char *)[MIMEType cString], plugin, mode, argsCount, cAttributes, cValues, NULL);
+ [[self class] setCurrentPluginView:nil];
+
+ if (!wasDeferring)
+ page->setDefersLoading(false);
+
+ LOG(Plugins, "NPP_New: %d", npErr);
+ return npErr;
+}
+
+- (void)_destroyPlugin
+{
+ PluginMainThreadScheduler::scheduler().unregisterPlugin(plugin);
+
+ NPError npErr;
+ npErr = NPP_Destroy(plugin, NULL);
+ LOG(Plugins, "NPP_Destroy: %d", npErr);
+
+ if (Frame* frame = core([self webFrame]))
+ frame->script()->cleanupScriptObjectsForPlugin(self);
+
+ free(plugin);
+ plugin = NULL;
+}
+
+- (void)_viewHasMoved
+{
+ // All of the work this method does may safely be skipped if the view is not in a window. When the view
+ // is moved back into a window, everything should be set up correctly.
+ if (![self window])
+ return;
+
+ if (isDrawingModelQuickDraw(drawingModel))
+ [self tellQuickTimeToChill];
+
+ if (drawingModel == NPDrawingModelCoreGraphics || isDrawingModelQuickDraw(drawingModel))
+ [self updateAndSetWindow];
+
+ [self resetTrackingRect];
+
+ // Check to see if the plugin view is completely obscured (scrolled out of view, for example).
+ // For performance reasons, we send null events at a lower rate to plugins which are obscured.
+ BOOL oldIsObscured = isCompletelyObscured;
+ isCompletelyObscured = NSIsEmptyRect([self visibleRect]);
+ if (isCompletelyObscured != oldIsObscured)
+ [self restartTimers];
+}
+
+- (NSBitmapImageRep *)_printedPluginBitmap
+{
+#ifdef NP_NO_QUICKDRAW
+ return nil;
+#else
+ // Cannot print plugins that do not implement NPP_Print
+ if (!NPP_Print)
+ return nil;
+
+ // This NSBitmapImageRep will share its bitmap buffer with a GWorld that the plugin will draw into.
+ // The bitmap is created in 32-bits-per-pixel ARGB format, which is the default GWorld pixel format.
+ NSBitmapImageRep *bitmap = [[[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
+ pixelsWide:window.width
+ pixelsHigh:window.height
+ bitsPerSample:8
+ samplesPerPixel:4
+ hasAlpha:YES
+ isPlanar:NO
+ colorSpaceName:NSDeviceRGBColorSpace
+ bitmapFormat:NSAlphaFirstBitmapFormat
+ bytesPerRow:0
+ bitsPerPixel:0] autorelease];
+ ASSERT(bitmap);
+
+ // Create a GWorld with the same underlying buffer into which the plugin can draw
+ ::Rect printGWorldBounds;
+ SetRect(&printGWorldBounds, 0, 0, window.width, window.height);
+ GWorldPtr printGWorld;
+ if (NewGWorldFromPtr(&printGWorld,
+ k32ARGBPixelFormat,
+ &printGWorldBounds,
+ NULL,
+ NULL,
+ 0,
+ (Ptr)[bitmap bitmapData],
+ [bitmap bytesPerRow]) != noErr) {
+ LOG_ERROR("Could not create GWorld for printing");
+ return nil;
+ }
+
+ /// Create NPWindow for the GWorld
+ NPWindow printNPWindow;
+ printNPWindow.window = &printGWorld; // Normally this is an NP_Port, but when printing it is the actual CGrafPtr
+ printNPWindow.x = 0;
+ printNPWindow.y = 0;
+ printNPWindow.width = window.width;
+ printNPWindow.height = window.height;
+ printNPWindow.clipRect.top = 0;
+ printNPWindow.clipRect.left = 0;
+ printNPWindow.clipRect.right = window.width;
+ printNPWindow.clipRect.bottom = window.height;
+ printNPWindow.type = NPWindowTypeDrawable; // Offscreen graphics port as opposed to a proper window
+
+ // Create embed-mode NPPrint
+ NPPrint npPrint;
+ npPrint.mode = NP_EMBED;
+ npPrint.print.embedPrint.window = printNPWindow;
+ npPrint.print.embedPrint.platformPrint = printGWorld;
+
+ // Tell the plugin to print into the GWorld
+ [self willCallPlugInFunction];
+ {
+ JSC::JSLock::DropAllLocks dropAllLocks(false);
+ NPP_Print(plugin, &npPrint);
+ }
+ [self didCallPlugInFunction];
+
+ // Don't need the GWorld anymore
+ DisposeGWorld(printGWorld);
+
+ return bitmap;
+#endif
+}
+
+- (void)_redeliverStream
+{
+ if ([self dataSource] && [self isStarted]) {
+ // Deliver what has not been passed to the plug-in up to this point.
+ if (_dataLengthReceived > 0) {
+ NSData *data = [[[self dataSource] data] subdataWithRange:NSMakeRange(0, _dataLengthReceived)];
+ _dataLengthReceived = 0;
+ [self pluginView:self receivedData:data];
+ if (![[self dataSource] isLoading]) {
+ if (_error)
+ [self pluginView:self receivedError:_error];
+ else
+ [self pluginViewFinishedLoading:self];
+ }
+ }
+ }
+}
+
+@end
+
+@implementation NSData (PluginExtras)
+
+- (BOOL)_web_startsWithBlankLine
+{
+ return [self length] > 0 && ((const char *)[self bytes])[0] == '\n';
+}
+
+
+- (NSInteger)_web_locationAfterFirstBlankLine
+{
+ const char *bytes = (const char *)[self bytes];
+ unsigned length = [self length];
+
+ unsigned i;
+ for (i = 0; i < length - 4; i++) {
+
+ // Support for Acrobat. It sends "\n\n".
+ if (bytes[i] == '\n' && bytes[i+1] == '\n') {
+ return i+2;
+ }
+
+ // Returns the position after 2 CRLF's or 1 CRLF if it is the first line.
+ if (bytes[i] == '\r' && bytes[i+1] == '\n') {
+ i += 2;
+ if (i == 2) {
+ return i;
+ } else if (bytes[i] == '\n') {
+ // Support for Director. It sends "\r\n\n" (3880387).
+ return i+1;
+ } else if (bytes[i] == '\r' && bytes[i+1] == '\n') {
+ // Support for Flash. It sends "\r\n\r\n" (3758113).
+ return i+2;
+ }
+ }
+ }
+ return NSNotFound;
+}
+
+@end
+#endif
diff --git a/WebKit/mac/Plugins/WebBasePluginPackage.h b/WebKit/mac/Plugins/WebBasePluginPackage.h
new file mode 100644
index 0000000..1082551
--- /dev/null
+++ b/WebKit/mac/Plugins/WebBasePluginPackage.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2005 Apple Computer, 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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.
+ */
+
+#import <WebCore/WebCoreViewFactory.h>
+
+#if ENABLE(NETSCAPE_PLUGIN_API)
+#import <WebKit/npfunctions.h>
+#else
+typedef void (*BP_CreatePluginMIMETypesPreferencesFuncPtr)(void);
+#endif
+
+@class WebPluginDatabase;
+
+@protocol WebPluginManualLoader
+- (void)pluginView:(NSView *)pluginView receivedResponse:(NSURLResponse *)response;
+- (void)pluginView:(NSView *)pluginView receivedData:(NSData *)data;
+- (void)pluginView:(NSView *)pluginView receivedError:(NSError *)error;
+- (void)pluginViewFinishedLoading:(NSView *)pluginView;
+@end
+
+#define WebPluginExtensionsKey @"WebPluginExtensions"
+#define WebPluginDescriptionKey @"WebPluginDescription"
+#define WebPluginLocalizationNameKey @"WebPluginLocalizationName"
+#define WebPluginMIMETypesFilenameKey @"WebPluginMIMETypesFilename"
+#define WebPluginMIMETypesKey @"WebPluginMIMETypes"
+#define WebPluginNameKey @"WebPluginName"
+#define WebPluginTypeDescriptionKey @"WebPluginTypeDescription"
+#define WebPluginTypeEnabledKey @"WebPluginTypeEnabled"
+
+@interface WebBasePluginPackage : NSObject <WebCorePluginInfo>
+{
+ NSMutableSet *pluginDatabases;
+
+ NSString *name;
+ NSString *path;
+ NSString *pluginDescription;
+
+ NSBundle *bundle;
+ CFBundleRef cfBundle;
+
+ NSDictionary *MIMEToDescription;
+ NSDictionary *MIMEToExtensions;
+ NSMutableDictionary *extensionToMIME;
+
+ BP_CreatePluginMIMETypesPreferencesFuncPtr BP_CreatePluginMIMETypesPreferences;
+}
+
++ (WebBasePluginPackage *)pluginWithPath:(NSString *)pluginPath;
+- (id)initWithPath:(NSString *)pluginPath;
+
+- (BOOL)getPluginInfoFromPLists;
+
+- (BOOL)load;
+- (void)unload;
+
+- (NSString *)name;
+- (NSString *)path;
+- (NSString *)filename;
+- (NSString *)pluginDescription;
+- (NSBundle *)bundle;
+
+- (NSEnumerator *)extensionEnumerator;
+- (NSEnumerator *)MIMETypeEnumerator;
+- (NSString *)descriptionForMIMEType:(NSString *)MIMEType;
+- (NSString *)MIMETypeForExtension:(NSString *)extension;
+- (NSArray *)extensionsForMIMEType:(NSString *)MIMEType;
+
+- (void)setName:(NSString *)theName;
+- (void)setPath:(NSString *)thePath;
+- (void)setPluginDescription:(NSString *)description;
+- (void)setMIMEToDescriptionDictionary:(NSDictionary *)MIMEToDescriptionDictionary;
+- (void)setMIMEToExtensionsDictionary:(NSDictionary *)MIMEToExtensionsDictionary;
+
+- (BOOL)isQuickTimePlugIn;
+- (BOOL)isJavaPlugIn;
+
+- (BOOL)isNativeLibraryData:(NSData *)data;
+- (UInt32)versionNumber;
+- (void)wasAddedToPluginDatabase:(WebPluginDatabase *)database;
+- (void)wasRemovedFromPluginDatabase:(WebPluginDatabase *)database;
+
+@end
diff --git a/WebKit/mac/Plugins/WebBasePluginPackage.m b/WebKit/mac/Plugins/WebBasePluginPackage.m
new file mode 100644
index 0000000..03d438b
--- /dev/null
+++ b/WebKit/mac/Plugins/WebBasePluginPackage.m
@@ -0,0 +1,523 @@
+/*
+ * Copyright (C) 2005 Apple Computer, 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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.
+ */
+
+#import <WebKit/WebBasePluginPackage.h>
+
+#import <WebKit/WebKitNSStringExtras.h>
+#import <WebKit/WebNetscapePluginPackage.h>
+#import <WebKit/WebNSObjectExtras.h>
+#import <WebKit/WebPluginPackage.h>
+#import <WebCore/WebCoreObjCExtras.h>
+#import <wtf/Assertions.h>
+#import <wtf/Vector.h>
+
+#import <WebKitSystemInterface.h>
+
+#import "WebKitLogging.h"
+#import "WebTypesInternal.h"
+
+#import <mach-o/arch.h>
+#import <mach-o/fat.h>
+#import <mach-o/loader.h>
+
+
+#define JavaCocoaPluginIdentifier @"com.apple.JavaPluginCocoa"
+#define JavaCarbonPluginIdentifier @"com.apple.JavaAppletPlugin"
+#define JavaCFMPluginFilename @"Java Applet Plugin Enabler"
+
+#define QuickTimeCarbonPluginIdentifier @"com.apple.QuickTime Plugin.plugin"
+#define QuickTimeCocoaPluginIdentifier @"com.apple.quicktime.webplugin"
+
+@interface NSArray (WebPluginExtensions)
+- (NSArray *)_web_lowercaseStrings;
+@end;
+
+@implementation WebBasePluginPackage
+
+#ifndef BUILDING_ON_TIGER
++ (void)initialize
+{
+ WebCoreObjCFinalizeOnMainThread(self);
+}
+#endif
+
++ (WebBasePluginPackage *)pluginWithPath:(NSString *)pluginPath
+{
+
+ WebBasePluginPackage *pluginPackage = [[WebPluginPackage alloc] initWithPath:pluginPath];
+
+ if (!pluginPackage) {
+#if ENABLE(NETSCAPE_PLUGIN_API)
+ pluginPackage = [[WebNetscapePluginPackage alloc] initWithPath:pluginPath];
+#else
+ return nil;
+#endif
+ }
+
+ return [pluginPackage autorelease];
+}
+
++ (NSString *)preferredLocalizationName
+{
+ return WebCFAutorelease(WKCopyCFLocalizationPreferredName(NULL));
+}
+
+- (NSString *)pathByResolvingSymlinksAndAliasesInPath:(NSString *)thePath
+{
+ NSString *newPath = [thePath stringByResolvingSymlinksInPath];
+
+ FSRef fref;
+ OSStatus err;
+
+ err = FSPathMakeRef((const UInt8 *)[thePath fileSystemRepresentation], &fref, NULL);
+ if (err != noErr)
+ return newPath;
+
+ Boolean targetIsFolder;
+ Boolean wasAliased;
+ err = FSResolveAliasFileWithMountFlags(&fref, TRUE, &targetIsFolder, &wasAliased, kResolveAliasFileNoUI);
+ if (err != noErr)
+ return newPath;
+
+ if (wasAliased) {
+ CFURLRef URL = CFURLCreateFromFSRef(kCFAllocatorDefault, &fref);
+ newPath = [(NSURL *)URL path];
+ CFRelease(URL);
+ }
+
+ return newPath;
+}
+
+- (id)initWithPath:(NSString *)pluginPath
+{
+ if (!(self = [super init]))
+ return nil;
+
+ path = [[self pathByResolvingSymlinksAndAliasesInPath:pluginPath] retain];
+ bundle = [[NSBundle alloc] initWithPath:path];
+#ifndef __ppc__
+ // 32-bit PowerPC is the only platform where non-bundled CFM plugins are supported
+ if (!bundle) {
+ [self release];
+ return nil;
+ }
+#endif
+ cfBundle = CFBundleCreate(NULL, (CFURLRef)[NSURL fileURLWithPath:path]);
+ extensionToMIME = [[NSMutableDictionary alloc] init];
+
+ return self;
+}
+
+- (BOOL)getPluginInfoFromBundleAndMIMEDictionary:(NSDictionary *)MIMETypes
+{
+ if (!bundle)
+ return NO;
+
+ if (!MIMETypes) {
+ MIMETypes = [bundle objectForInfoDictionaryKey:WebPluginMIMETypesKey];
+ if (!MIMETypes)
+ return NO;
+ }
+
+ NSMutableDictionary *MIMEToExtensionsDictionary = [NSMutableDictionary dictionary];
+ NSMutableDictionary *MIMEToDescriptionDictionary = [NSMutableDictionary dictionary];
+ NSEnumerator *keyEnumerator = [MIMETypes keyEnumerator];
+ NSDictionary *MIMEDictionary;
+ NSString *MIME, *description;
+ NSArray *extensions;
+
+ while ((MIME = [keyEnumerator nextObject]) != nil) {
+ MIMEDictionary = [MIMETypes objectForKey:MIME];
+
+ // FIXME: Consider storing disabled MIME types.
+ NSNumber *isEnabled = [MIMEDictionary objectForKey:WebPluginTypeEnabledKey];
+ if (isEnabled && [isEnabled boolValue] == NO)
+ continue;
+
+ extensions = [[MIMEDictionary objectForKey:WebPluginExtensionsKey] _web_lowercaseStrings];
+ if ([extensions count] == 0)
+ extensions = [NSArray arrayWithObject:@""];
+
+ MIME = [MIME lowercaseString];
+
+ [MIMEToExtensionsDictionary setObject:extensions forKey:MIME];
+
+ description = [MIMEDictionary objectForKey:WebPluginTypeDescriptionKey];
+ if (!description)
+ description = @"";
+
+ [MIMEToDescriptionDictionary setObject:description forKey:MIME];
+ }
+
+ [self setMIMEToExtensionsDictionary:MIMEToExtensionsDictionary];
+ [self setMIMEToDescriptionDictionary:MIMEToDescriptionDictionary];
+
+ NSString *filename = [self filename];
+
+ NSString *theName = [bundle objectForInfoDictionaryKey:WebPluginNameKey];
+ if (!theName)
+ theName = filename;
+ [self setName:theName];
+
+ description = [bundle objectForInfoDictionaryKey:WebPluginDescriptionKey];
+ if (!description)
+ description = filename;
+ [self setPluginDescription:description];
+
+ return YES;
+}
+
+- (void)unload
+{
+}
+
+- (NSDictionary *)pListForPath:(NSString *)pListPath createFile:(BOOL)createFile
+{
+ if (createFile && [self load] && BP_CreatePluginMIMETypesPreferences) {
+ BP_CreatePluginMIMETypesPreferences();
+ [self unload];
+ }
+
+ NSDictionary *pList = nil;
+ NSData *data = [NSData dataWithContentsOfFile:pListPath];
+ if (data) {
+ pList = [NSPropertyListSerialization propertyListFromData:data
+ mutabilityOption:NSPropertyListImmutable
+ format:nil
+ errorDescription:nil];
+ }
+
+ return pList;
+}
+
+- (BOOL)getPluginInfoFromPLists
+{
+ if (!bundle)
+ return NO;
+
+ NSDictionary *MIMETypes = nil;
+ NSString *pListFilename = [bundle objectForInfoDictionaryKey:WebPluginMIMETypesFilenameKey];
+
+ // Check if the MIME types are claimed in a plist in the user's preferences directory.
+ if (pListFilename) {
+ NSString *pListPath = [NSString stringWithFormat:@"%@/Library/Preferences/%@", NSHomeDirectory(), pListFilename];
+ NSDictionary *pList = [self pListForPath:pListPath createFile:NO];
+ if (pList) {
+ // If the plist isn't localized, have the plug-in recreate it in the preferred language.
+ NSString *localizationName = [pList objectForKey:WebPluginLocalizationNameKey];
+ if (![localizationName isEqualToString:[[self class] preferredLocalizationName]])
+ pList = [self pListForPath:pListPath createFile:YES];
+ MIMETypes = [pList objectForKey:WebPluginMIMETypesKey];
+ } else
+ // Plist doesn't exist, ask the plug-in to create it.
+ MIMETypes = [[self pListForPath:pListPath createFile:YES] objectForKey:WebPluginMIMETypesKey];
+ }
+
+ // Pass the MIME dictionary to the superclass to parse it.
+ return [self getPluginInfoFromBundleAndMIMEDictionary:MIMETypes];
+}
+
+- (BOOL)load
+{
+ if (bundle && !BP_CreatePluginMIMETypesPreferences)
+ BP_CreatePluginMIMETypesPreferences = (BP_CreatePluginMIMETypesPreferencesFuncPtr)CFBundleGetFunctionPointerForName(cfBundle, CFSTR("BP_CreatePluginMIMETypesPreferences"));
+
+ return YES;
+}
+
+- (void)dealloc
+{
+ ASSERT(!pluginDatabases || [pluginDatabases count] == 0);
+ [pluginDatabases release];
+
+ [name release];
+ [path release];
+ [pluginDescription release];
+
+ [MIMEToDescription release];
+ [MIMEToExtensions release];
+ [extensionToMIME release];
+
+ [bundle release];
+ if (cfBundle)
+ CFRelease(cfBundle);
+
+ [super dealloc];
+}
+
+- (void)finalize
+{
+ ASSERT_MAIN_THREAD();
+ ASSERT(!pluginDatabases || [pluginDatabases count] == 0);
+ [pluginDatabases release];
+
+ if (cfBundle)
+ CFRelease(cfBundle);
+
+ [super finalize];
+}
+
+- (NSString *)name
+{
+ return name;
+}
+
+- (NSString *)path
+{
+ return path;
+}
+
+- (NSString *)filename
+{
+ return [path lastPathComponent];
+}
+
+- (NSString *)pluginDescription
+{
+ return pluginDescription;
+}
+
+- (NSEnumerator *)extensionEnumerator
+{
+ return [extensionToMIME keyEnumerator];
+}
+
+- (NSEnumerator *)MIMETypeEnumerator
+{
+ return [MIMEToExtensions keyEnumerator];
+}
+
+- (NSString *)descriptionForMIMEType:(NSString *)MIMEType
+{
+ return [MIMEToDescription objectForKey:MIMEType];
+}
+
+- (NSString *)MIMETypeForExtension:(NSString *)extension
+{
+ return [extensionToMIME objectForKey:extension];
+}
+
+- (NSArray *)extensionsForMIMEType:(NSString *)MIMEType
+{
+ return [MIMEToExtensions objectForKey:MIMEType];
+}
+
+- (NSBundle *)bundle
+{
+ return bundle;
+}
+
+- (void)setName:(NSString *)theName
+{
+ [name release];
+ name = [theName retain];
+}
+
+- (void)setPath:(NSString *)thePath
+{
+ [path release];
+ path = [thePath retain];
+}
+
+- (void)setPluginDescription:(NSString *)description
+{
+ [pluginDescription release];
+ pluginDescription = [description retain];
+}
+
+- (void)setMIMEToDescriptionDictionary:(NSDictionary *)MIMEToDescriptionDictionary
+{
+ [MIMEToDescription release];
+ MIMEToDescription = [MIMEToDescriptionDictionary retain];
+}
+
+- (void)setMIMEToExtensionsDictionary:(NSDictionary *)MIMEToExtensionsDictionary
+{
+ [MIMEToExtensions release];
+ MIMEToExtensions = [MIMEToExtensionsDictionary retain];
+
+ // Reverse the mapping
+ [extensionToMIME removeAllObjects];
+
+ NSEnumerator *MIMEEnumerator = [MIMEToExtensions keyEnumerator], *extensionEnumerator;
+ NSString *MIME, *extension;
+ NSArray *extensions;
+
+ while ((MIME = [MIMEEnumerator nextObject]) != nil) {
+ extensions = [MIMEToExtensions objectForKey:MIME];
+ extensionEnumerator = [extensions objectEnumerator];
+
+ while ((extension = [extensionEnumerator nextObject]) != nil) {
+ if (![extension isEqualToString:@""])
+ [extensionToMIME setObject:MIME forKey:extension];
+ }
+ }
+}
+
+- (NSString *)description
+{
+ return [NSString stringWithFormat:@"name: %@\npath: %@\nmimeTypes:\n%@\npluginDescription:%@",
+ name, path, [MIMEToExtensions description], [MIMEToDescription description], pluginDescription];
+}
+
+- (BOOL)isQuickTimePlugIn
+{
+ NSString *bundleIdentifier = [[self bundle] bundleIdentifier];
+ return [bundleIdentifier _webkit_isCaseInsensitiveEqualToString:QuickTimeCarbonPluginIdentifier] ||
+ [bundleIdentifier _webkit_isCaseInsensitiveEqualToString:QuickTimeCocoaPluginIdentifier];
+}
+
+- (BOOL)isJavaPlugIn
+{
+ NSString *bundleIdentifier = [[self bundle] bundleIdentifier];
+ return [bundleIdentifier _webkit_isCaseInsensitiveEqualToString:JavaCocoaPluginIdentifier] ||
+ [bundleIdentifier _webkit_isCaseInsensitiveEqualToString:JavaCarbonPluginIdentifier] ||
+ [[path lastPathComponent] _webkit_isCaseInsensitiveEqualToString:JavaCFMPluginFilename];
+}
+
+static inline void swapIntsInHeader(uint8_t* bytes, unsigned length)
+{
+ for (unsigned i = 0; i < length; i += 4)
+ *(uint32_t*)(bytes + i) = OSSwapInt32(*(uint32_t *)(bytes + i));
+}
+
+- (BOOL)isNativeLibraryData:(NSData *)data
+{
+ Vector<uint8_t, 512> bytes([data length]);
+ memcpy(bytes.data(), [data bytes], bytes.size());
+
+ unsigned numArchs = 0;
+ struct fat_arch singleArch = { 0, 0, 0, 0, 0 };
+ struct fat_arch* archs = 0;
+
+ if (bytes.size() >= sizeof(struct mach_header_64)) {
+ uint32_t magic = *reinterpret_cast<uint32_t*>(bytes.data());
+
+ if (magic == MH_MAGIC || magic == MH_CIGAM) {
+ // We have a 32-bit thin binary
+ struct mach_header* header = (struct mach_header*)bytes.data();
+
+ // Check if we need to swap the bytes
+ if (magic == MH_CIGAM)
+ swapIntsInHeader(bytes.data(), bytes.size());
+
+ singleArch.cputype = header->cputype;
+ singleArch.cpusubtype = header->cpusubtype;
+
+ archs = &singleArch;
+ numArchs = 1;
+ } else if (magic == MH_MAGIC_64 || magic == MH_CIGAM_64) {
+ // We have a 64-bit thin binary
+ struct mach_header_64* header = (struct mach_header_64*)bytes.data();
+
+ // Check if we need to swap the bytes
+ if (magic == MH_CIGAM_64)
+ swapIntsInHeader(bytes.data(), bytes.size());
+
+ singleArch.cputype = header->cputype;
+ singleArch.cpusubtype = header->cpusubtype;
+
+ archs = &singleArch;
+ numArchs = 1;
+ } else if (magic == FAT_MAGIC || magic == FAT_CIGAM) {
+ // We have a fat (universal) binary
+
+ // Check if we need to swap the bytes
+ if (magic == FAT_CIGAM)
+ swapIntsInHeader(bytes.data(), bytes.size());
+
+ archs = (struct fat_arch*)(bytes.data() + sizeof(struct fat_header));
+ numArchs = ((struct fat_header *)bytes.data())->nfat_arch;
+
+ unsigned maxArchs = (bytes.size() - sizeof(struct fat_header)) / sizeof(struct fat_arch);
+ if (numArchs > maxArchs)
+ numArchs = maxArchs;
+ }
+ }
+
+ if (!archs || !numArchs)
+ return NO;
+
+ const NXArchInfo* localArch = NXGetLocalArchInfo();
+ if (!localArch)
+ return NO;
+
+ cpu_type_t cputype = localArch->cputype;
+ cpu_subtype_t cpusubtype = localArch->cpusubtype;
+
+#ifdef __x86_64__
+ // NXGetLocalArchInfo returns CPU_TYPE_X86 even when running in 64-bit.
+ // See <rdar://problem/4996965> for more information.
+ cputype = CPU_TYPE_X86_64;
+#endif
+
+ return NXFindBestFatArch(cputype, cpusubtype, archs, numArchs) != 0;
+}
+
+- (UInt32)versionNumber
+{
+ // CFBundleGetVersionNumber doesn't work with all possible versioning schemes, but we think for now it's good enough for us.
+ return CFBundleGetVersionNumber(cfBundle);
+}
+
+- (void)wasAddedToPluginDatabase:(WebPluginDatabase *)database
+{
+ if (!pluginDatabases)
+ pluginDatabases = [[NSMutableSet alloc] init];
+
+ ASSERT(![pluginDatabases containsObject:database]);
+ [pluginDatabases addObject:database];
+}
+
+- (void)wasRemovedFromPluginDatabase:(WebPluginDatabase *)database
+{
+ ASSERT(pluginDatabases);
+ ASSERT([pluginDatabases containsObject:database]);
+
+ [pluginDatabases removeObject:database];
+}
+
+@end
+
+@implementation NSArray (WebPluginExtensions)
+
+- (NSArray *)_web_lowercaseStrings
+{
+ NSMutableArray *lowercaseStrings = [NSMutableArray arrayWithCapacity:[self count]];
+ NSEnumerator *strings = [self objectEnumerator];
+ NSString *string;
+
+ while ((string = [strings nextObject]) != nil) {
+ if ([string isKindOfClass:[NSString class]])
+ [lowercaseStrings addObject:[string lowercaseString]];
+ }
+
+ return lowercaseStrings;
+}
+
+@end
diff --git a/WebKit/mac/Plugins/WebJavaPlugIn.h b/WebKit/mac/Plugins/WebJavaPlugIn.h
new file mode 100644
index 0000000..5a1be6d
--- /dev/null
+++ b/WebKit/mac/Plugins/WebJavaPlugIn.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2004 Apple Computer, 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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.
+ */
+
+#import <JavaVM/jni.h>
+
+/*!
+ The Java plug-in adds the following additional methods to facilitate JNI
+ access to Java VM via the plug-in.
+*/
+
+typedef enum {
+ WebJNIReturnTypeInvalid = 0,
+ WebJNIReturnTypeVoid,
+ WebJNIReturnTypeObject,
+ WebJNIReturnTypeBoolean,
+ WebJNIReturnTypeByte,
+ WebJNIReturnTypeChar,
+ WebJNIReturnTypeShort,
+ WebJNIReturnTypeInt,
+ WebJNIReturnTypeLong,
+ WebJNIReturnTypeFloat,
+ WebJNIReturnTypeDouble
+} WebJNIReturnType;
+
+@interface NSObject (WebJavaPlugIn)
+
+/*!
+ @method webPlugInGetApplet
+ @discusssion This returns the jobject representing the java applet to the
+ WebPlugInContainer. It should always be called from the AppKit Main Thread.
+ This method is only implemented by the Java plug-in.
+*/
+- (jobject)webPlugInGetApplet;
+
+/*!
+ @method webPlugInCallJava:isStatic:returnType:method:arguments:callingURL:exceptionDescription:
+ @param object The Java instance that will receive the method call.
+ @param isStatic A flag that indicated whether the method is a class method.
+ @param returnType The return type of the Java method.
+ @param method The ID of the Java method to call.
+ @param args The arguments to use with the method invocation.
+ @param callingURL The URL of the page that contains the JavaScript that is calling Java.
+ @param exceptionDescription Pass in nil or the address of pointer to a string object. If any exception
+ is thrown by Java the return value will be a description of the exception, otherwise nil.
+ @discussion Calls to Java from native code should not make direct
+ use of JNI. Instead they should use this method to dispatch calls to the
+ Java VM. This is required to guarantee that the correct thread will receive
+ the call. webPlugInCallJava:isStatic:returnType:method:arguments:callingURL:exceptionDescription: must
+ always be called from the AppKit main thread. This method is only implemented by the Java plug-in.
+ @result The result of the method invocation.
+*/
+- (jvalue)webPlugInCallJava:(jobject)object
+ isStatic:(BOOL)isStatic
+ returnType:(WebJNIReturnType)returnType
+ method:(jmethodID)method
+ arguments:(jvalue*)args
+ callingURL:(NSURL *)url
+ exceptionDescription:(NSString **)exceptionString;
+
+@end
diff --git a/WebKit/mac/Plugins/WebKitPluginContainerView.h b/WebKit/mac/Plugins/WebKitPluginContainerView.h
new file mode 100644
index 0000000..a67c105
--- /dev/null
+++ b/WebKit/mac/Plugins/WebKitPluginContainerView.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2007 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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.
+ */
+
+#import <Cocoa/Cocoa.h>
+
+@class DOMElement;
+
+@interface WebKitPluginContainerView : NSView
+{
+ DOMElement *_element;
+}
+
+- (id)initWithFrame:(NSRect)r
+ DOMElement:(DOMElement *)anElement;
+
+- (id)objectForWebScript;
+
+@end
diff --git a/WebKit/mac/Plugins/WebKitPluginContainerView.mm b/WebKit/mac/Plugins/WebKitPluginContainerView.mm
new file mode 100644
index 0000000..fb61644
--- /dev/null
+++ b/WebKit/mac/Plugins/WebKitPluginContainerView.mm
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2007 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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.
+ */
+
+#import "WebKitPluginContainerView.h"
+#import <WebKit/DOMPrivate.h>
+
+@implementation WebKitPluginContainerView
+
+- (id)initWithFrame:(NSRect)frame
+ DOMElement:(DOMElement *)anElement
+{
+ [super initWithFrame:frame];
+
+ _element = [anElement retain];
+
+ return self;
+}
+
+- (void)dealloc
+{
+ [_element release];
+
+ [super dealloc];
+}
+
+- (NSRect)visibleRect
+{
+ if (![self window])
+ return [super visibleRect];
+
+ // WebCore may impose an additional clip (via CSS overflow or clip properties). Fetch
+ // that clip now.
+ return NSIntersectionRect([self convertRect:[_element _windowClipRect] fromView:nil], [super visibleRect]);
+}
+
+- (BOOL)respondsToSelector:(SEL)selector
+{
+ if (selector == @selector(objectForWebScript))
+ return [[[self subviews] objectAtIndex: 0] respondsToSelector:selector];
+ return [super respondsToSelector:selector];
+}
+
+- (id)objectForWebScript
+{
+ return [[[self subviews] objectAtIndex: 0] objectForWebScript];
+}
+
+@end
+
diff --git a/WebKit/mac/Plugins/WebNetscapeDeprecatedFunctions.c b/WebKit/mac/Plugins/WebNetscapeDeprecatedFunctions.c
new file mode 100644
index 0000000..797e824
--- /dev/null
+++ b/WebKit/mac/Plugins/WebNetscapeDeprecatedFunctions.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2006, 2007 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 "WebNetscapeDeprecatedFunctions.h"
+
+#if ENABLE(NETSCAPE_PLUGIN_API) && !defined(__LP64__)
+
+OSErr WebGetDiskFragment(const FSSpec *fileSpec, UInt32 offset, UInt32 length, ConstStr63Param fragName, CFragLoadOptions options, CFragConnectionID *connID, Ptr *mainAddr, Str255 errMessage)
+{
+ return GetDiskFragment(fileSpec, offset, length, fragName, options, connID, mainAddr, errMessage);
+}
+
+OSErr WebCloseConnection(CFragConnectionID *connID)
+{
+ return CloseConnection(connID);
+}
+
+SInt16 WebLMGetCurApRefNum(void)
+{
+ return LMGetCurApRefNum();
+}
+
+extern void WebLMSetCurApRefNum(SInt16 value)
+{
+ LMSetCurApRefNum(value);
+}
+
+#endif /* ENABLE(NETSCAPE_PLUGIN_API) && !defined(__LP64__) */
diff --git a/WebKit/mac/Plugins/WebNetscapeDeprecatedFunctions.h b/WebKit/mac/Plugins/WebNetscapeDeprecatedFunctions.h
new file mode 100644
index 0000000..93c3194
--- /dev/null
+++ b/WebKit/mac/Plugins/WebNetscapeDeprecatedFunctions.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2006, 2007 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 ENABLE(NETSCAPE_PLUGIN_API) && !defined(__LP64__)
+
+#import <CoreServices/CoreServices.h>
+
+extern OSErr WebGetDiskFragment(const FSSpec *fileSpec, UInt32 offset, UInt32 length, ConstStr63Param fragName, CFragLoadOptions options, CFragConnectionID *connID, Ptr *mainAddr, Str255 errMessage);
+extern OSErr WebCloseConnection(CFragConnectionID *connID);
+extern SInt16 WebLMGetCurApRefNum(void);
+extern void WebLMSetCurApRefNum(SInt16 value);
+
+#endif /* ENABLE(NETSCAPE_PLUGIN_API) && !defined(__LP64__) */
diff --git a/WebKit/mac/Plugins/WebNetscapePluginEventHandler.h b/WebKit/mac/Plugins/WebNetscapePluginEventHandler.h
new file mode 100644
index 0000000..54402bb
--- /dev/null
+++ b/WebKit/mac/Plugins/WebNetscapePluginEventHandler.h
@@ -0,0 +1,82 @@
+/*
+ * 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 WebNetscapePluginEventHandler_h
+#define WebNetscapePluginEventHandler_h
+
+#import "WebBaseNetscapePluginView.h"
+
+#if ENABLE(NETSCAPE_PLUGIN_API)
+
+@class NSEvent;
+@class WebBaseNetscapePluginView;
+
+struct CGRect;
+
+class WebNetscapePluginEventHandler {
+public:
+ static WebNetscapePluginEventHandler* create(WebBaseNetscapePluginView*);
+ virtual ~WebNetscapePluginEventHandler() { }
+
+ virtual void drawRect(const NSRect&) = 0;
+
+ virtual void mouseDown(NSEvent*) = 0;
+ virtual void mouseDragged(NSEvent*) = 0;
+ virtual void mouseEntered(NSEvent*) = 0;
+ virtual void mouseExited(NSEvent*) = 0;
+ virtual void mouseMoved(NSEvent*) = 0;
+ virtual void mouseUp(NSEvent*) = 0;
+ virtual bool scrollWheel(NSEvent*) = 0;
+
+ virtual void keyDown(NSEvent*) = 0;
+ virtual void keyUp(NSEvent*) = 0;
+ virtual void flagsChanged(NSEvent*) = 0;
+
+ virtual void focusChanged(bool hasFocus) = 0;
+ virtual void windowFocusChanged(bool hasFocus) = 0;
+
+ virtual void startTimers(bool throttleTimers) { }
+ virtual void stopTimers() { }
+
+ // Returns the platform specific window used in NPP_SetWindow
+ virtual void* platformWindow(NSWindow*) = 0;
+
+ bool currentEventIsUserGesture() const { return m_currentEventIsUserGesture; }
+protected:
+ WebNetscapePluginEventHandler(WebBaseNetscapePluginView* pluginView)
+ : m_pluginView(pluginView)
+ , m_currentEventIsUserGesture(false)
+ {
+ }
+
+ WebBaseNetscapePluginView* m_pluginView;
+ bool m_currentEventIsUserGesture;
+};
+
+#endif // ENABLE(NETSCAPE_PLUGIN_API)
+
+#endif // WebNetscapePluginEventHandler_h
+
+
diff --git a/WebKit/mac/Plugins/WebNetscapePluginEventHandler.mm b/WebKit/mac/Plugins/WebNetscapePluginEventHandler.mm
new file mode 100644
index 0000000..e8e6d8a
--- /dev/null
+++ b/WebKit/mac/Plugins/WebNetscapePluginEventHandler.mm
@@ -0,0 +1,50 @@
+/*
+ * 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 ENABLE(NETSCAPE_PLUGIN_API)
+
+#import "WebNetscapePluginEventHandler.h"
+
+#import <wtf/Assertions.h>
+#import "WebBaseNetscapePluginView.h"
+#import "WebNetscapePluginEventHandlerCarbon.h"
+#import "WebNetscapePluginEventHandlerCocoa.h"
+
+WebNetscapePluginEventHandler* WebNetscapePluginEventHandler::create(WebBaseNetscapePluginView* pluginView)
+{
+ switch ([pluginView eventModel]) {
+#ifndef NP_NO_CARBON
+ case NPEventModelCarbon:
+ return new WebNetscapePluginEventHandlerCarbon(pluginView);
+#endif // NP_NO_CARBON
+ case NPEventModelCocoa:
+ return new WebNetscapePluginEventHandlerCocoa(pluginView);
+ default:
+ ASSERT_NOT_REACHED();
+ return 0;
+ }
+}
+
+#endif // ENABLE(NETSCAPE_PLUGIN_API)
diff --git a/WebKit/mac/Plugins/WebNetscapePluginEventHandlerCarbon.h b/WebKit/mac/Plugins/WebNetscapePluginEventHandlerCarbon.h
new file mode 100644
index 0000000..cf26276
--- /dev/null
+++ b/WebKit/mac/Plugins/WebNetscapePluginEventHandlerCarbon.h
@@ -0,0 +1,81 @@
+/*
+ * 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 ENABLE(NETSCAPE_PLUGIN_API) && !defined(__LP64__)
+
+#ifndef WebNetscapePluginEventHandlerCarbon_h
+#define WebNetscapePluginEventHandlerCarbon_h
+
+#include "WebNetscapePluginEventHandler.h"
+
+#import <Carbon/Carbon.h>
+#import <wtf/RetainPtr.h>
+
+class WebNetscapePluginEventHandlerCarbon : public WebNetscapePluginEventHandler {
+public:
+ WebNetscapePluginEventHandlerCarbon(WebBaseNetscapePluginView*);
+
+ virtual void drawRect(const NSRect&);
+
+ virtual void mouseDown(NSEvent*);
+ virtual void mouseDragged(NSEvent*);
+ virtual void mouseEntered(NSEvent*);
+ virtual void mouseExited(NSEvent*);
+ virtual void mouseMoved(NSEvent*);
+ virtual void mouseUp(NSEvent*);
+ virtual bool scrollWheel(NSEvent*);
+
+ virtual void keyDown(NSEvent*);
+ virtual void keyUp(NSEvent*);
+ virtual void flagsChanged(NSEvent*);
+
+ virtual void windowFocusChanged(bool hasFocus);
+ virtual void focusChanged(bool hasFocus);
+
+ virtual void startTimers(bool throttleTimers);
+ virtual void stopTimers();
+
+ virtual void* platformWindow(NSWindow*);
+
+private:
+ void sendNullEvent();
+
+ void installKeyEventHandler();
+ void removeKeyEventHandler();
+
+ static OSStatus TSMEventHandler(EventHandlerCallRef, EventRef, void *eventHandler);
+ static void nullEventTimerFired(CFRunLoopTimerRef, void *context);
+
+ bool sendEvent(EventRecord*);
+
+ EventHandlerRef m_keyEventHandler;
+ bool m_suspendKeyUpEvents;
+ RetainPtr<CFRunLoopTimerRef> m_nullEventTimer;
+};
+
+#endif // WebNetscapePluginEventHandlerCarbon_h
+
+#endif // ENABLE(NETSCAPE_PLUGIN_API) && !defined(__LP64__)
+
diff --git a/WebKit/mac/Plugins/WebNetscapePluginEventHandlerCarbon.mm b/WebKit/mac/Plugins/WebNetscapePluginEventHandlerCarbon.mm
new file mode 100644
index 0000000..bfdd91c
--- /dev/null
+++ b/WebKit/mac/Plugins/WebNetscapePluginEventHandlerCarbon.mm
@@ -0,0 +1,411 @@
+/*
+ * 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 ENABLE(NETSCAPE_PLUGIN_API) && !defined(__LP64__)
+
+#import "WebNetscapePluginEventHandlerCarbon.h"
+
+#import "WebBaseNetscapePluginView.h"
+#import "WebKitLogging.h"
+#import "WebKitSystemInterface.h"
+
+// Send null events 50 times a second when active, so plug-ins like Flash get high frame rates.
+#define NullEventIntervalActive 0.02
+#define NullEventIntervalNotActive 0.25
+
+WebNetscapePluginEventHandlerCarbon::WebNetscapePluginEventHandlerCarbon(WebBaseNetscapePluginView* pluginView)
+ : WebNetscapePluginEventHandler(pluginView)
+ , m_keyEventHandler(0)
+ , m_suspendKeyUpEvents(false)
+{
+}
+
+static void getCarbonEvent(EventRecord* carbonEvent)
+{
+ carbonEvent->what = nullEvent;
+ carbonEvent->message = 0;
+ carbonEvent->when = TickCount();
+
+ GetGlobalMouse(&carbonEvent->where);
+ carbonEvent->where.h = static_cast<short>(carbonEvent->where.h * HIGetScaleFactor());
+ carbonEvent->where.v = static_cast<short>(carbonEvent->where.v * HIGetScaleFactor());
+ carbonEvent->modifiers = GetCurrentKeyModifiers();
+ if (!Button())
+ carbonEvent->modifiers |= btnState;
+}
+
+static EventModifiers modifiersForEvent(NSEvent *event)
+{
+ EventModifiers modifiers;
+ unsigned int modifierFlags = [event modifierFlags];
+ NSEventType eventType = [event type];
+
+ modifiers = 0;
+
+ if (eventType != NSLeftMouseDown && eventType != NSRightMouseDown)
+ modifiers |= btnState;
+
+ if (modifierFlags & NSCommandKeyMask)
+ modifiers |= cmdKey;
+
+ if (modifierFlags & NSShiftKeyMask)
+ modifiers |= shiftKey;
+
+ if (modifierFlags & NSAlphaShiftKeyMask)
+ modifiers |= alphaLock;
+
+ if (modifierFlags & NSAlternateKeyMask)
+ modifiers |= optionKey;
+
+ if (modifierFlags & NSControlKeyMask || eventType == NSRightMouseDown)
+ modifiers |= controlKey;
+
+ return modifiers;
+}
+
+static void getCarbonEvent(EventRecord *carbonEvent, NSEvent *cocoaEvent)
+{
+ if (WKConvertNSEventToCarbonEvent(carbonEvent, cocoaEvent)) {
+ carbonEvent->where.h = static_cast<short>(carbonEvent->where.h * HIGetScaleFactor());
+ carbonEvent->where.v = static_cast<short>(carbonEvent->where.v * HIGetScaleFactor());
+ return;
+ }
+
+ NSPoint where = [[cocoaEvent window] convertBaseToScreen:[cocoaEvent locationInWindow]];
+
+ carbonEvent->what = nullEvent;
+ carbonEvent->message = 0;
+ carbonEvent->when = (UInt32)([cocoaEvent timestamp] * 60); // seconds to ticks
+ carbonEvent->where.h = (short)where.x;
+ carbonEvent->where.v = (short)(NSMaxY([[[NSScreen screens] objectAtIndex:0] frame]) - where.y);
+ carbonEvent->modifiers = modifiersForEvent(cocoaEvent);
+}
+
+void WebNetscapePluginEventHandlerCarbon::sendNullEvent()
+{
+ EventRecord event;
+
+ getCarbonEvent(&event);
+
+ // Plug-in should not react to cursor position when not active or when a menu is down.
+ MenuTrackingData trackingData;
+ OSStatus error = GetMenuTrackingData(NULL, &trackingData);
+
+ // Plug-in should not react to cursor position when the actual window is not key.
+ if (![[m_pluginView window] isKeyWindow] || (error == noErr && trackingData.menu)) {
+ // FIXME: Does passing a v and h of -1 really prevent it from reacting to the cursor position?
+ event.where.v = -1;
+ event.where.h = -1;
+ }
+
+ sendEvent(&event);
+}
+
+void WebNetscapePluginEventHandlerCarbon::drawRect(const NSRect&)
+{
+ EventRecord event;
+
+ getCarbonEvent(&event);
+ event.what = updateEvt;
+ WindowRef windowRef = (WindowRef)[[m_pluginView window] windowRef];
+ event.message = (unsigned long)windowRef;
+
+ BOOL acceptedEvent;
+ acceptedEvent = sendEvent(&event);
+
+ LOG(PluginEvents, "NPP_HandleEvent(updateEvt): %d", acceptedEvent);
+}
+
+void WebNetscapePluginEventHandlerCarbon::mouseDown(NSEvent* theEvent)
+{
+ EventRecord event;
+
+ getCarbonEvent(&event, theEvent);
+ event.what = ::mouseDown;
+
+ BOOL acceptedEvent;
+ acceptedEvent = sendEvent(&event);
+
+ LOG(PluginEvents, "NPP_HandleEvent(mouseDown): %d pt.v=%d, pt.h=%d", acceptedEvent, event.where.v, event.where.h);
+}
+
+void WebNetscapePluginEventHandlerCarbon::mouseUp(NSEvent* theEvent)
+{
+ EventRecord event;
+
+ getCarbonEvent(&event, theEvent);
+ event.what = ::mouseUp;
+
+ BOOL acceptedEvent;
+ acceptedEvent = sendEvent(&event);
+
+ LOG(PluginEvents, "NPP_HandleEvent(mouseUp): %d pt.v=%d, pt.h=%d", acceptedEvent, event.where.v, event.where.h);
+}
+
+bool WebNetscapePluginEventHandlerCarbon::scrollWheel(NSEvent* theEvent)
+{
+ return false;
+}
+
+void WebNetscapePluginEventHandlerCarbon::mouseEntered(NSEvent* theEvent)
+{
+ EventRecord event;
+
+ getCarbonEvent(&event, theEvent);
+ event.what = adjustCursorEvent;
+
+ BOOL acceptedEvent;
+ acceptedEvent = sendEvent(&event);
+
+ LOG(PluginEvents, "NPP_HandleEvent(mouseEntered): %d", acceptedEvent);
+}
+
+void WebNetscapePluginEventHandlerCarbon::mouseExited(NSEvent* theEvent)
+{
+ EventRecord event;
+
+ getCarbonEvent(&event, theEvent);
+ event.what = adjustCursorEvent;
+
+ BOOL acceptedEvent;
+ acceptedEvent = sendEvent(&event);
+
+ LOG(PluginEvents, "NPP_HandleEvent(mouseExited): %d", acceptedEvent);
+}
+
+void WebNetscapePluginEventHandlerCarbon::mouseDragged(NSEvent*)
+{
+}
+
+void WebNetscapePluginEventHandlerCarbon::mouseMoved(NSEvent*)
+{
+}
+
+void WebNetscapePluginEventHandlerCarbon::keyDown(NSEvent *theEvent)
+{
+ m_suspendKeyUpEvents = true;
+ WKSendKeyEventToTSM(theEvent);
+}
+
+static UInt32 keyMessageForEvent(NSEvent *event)
+{
+ NSData *data = [[event characters] dataUsingEncoding:CFStringConvertEncodingToNSStringEncoding(CFStringGetSystemEncoding())];
+ if (!data)
+ return 0;
+
+ UInt8 characterCode;
+ [data getBytes:&characterCode length:1];
+ UInt16 keyCode = [event keyCode];
+ return keyCode << 8 | characterCode;
+}
+
+void WebNetscapePluginEventHandlerCarbon::keyUp(NSEvent* theEvent)
+{
+ WKSendKeyEventToTSM(theEvent);
+
+ // TSM won't send keyUp events so we have to send them ourselves.
+ // Only send keyUp events after we receive the TSM callback because this is what plug-in expect from OS 9.
+ if (!m_suspendKeyUpEvents) {
+ EventRecord event;
+
+ getCarbonEvent(&event, theEvent);
+ event.what = ::keyUp;
+
+ if (event.message == 0)
+ event.message = keyMessageForEvent(theEvent);
+
+ sendEvent(&event);
+ }
+}
+
+void WebNetscapePluginEventHandlerCarbon::flagsChanged(NSEvent*)
+{
+}
+
+void WebNetscapePluginEventHandlerCarbon::focusChanged(bool hasFocus)
+{
+ EventRecord event;
+
+ getCarbonEvent(&event);
+ bool acceptedEvent;
+ if (hasFocus) {
+ event.what = getFocusEvent;
+ acceptedEvent = sendEvent(&event);
+ LOG(PluginEvents, "NPP_HandleEvent(getFocusEvent): %d", acceptedEvent);
+ installKeyEventHandler();
+ } else {
+ event.what = loseFocusEvent;
+ acceptedEvent = sendEvent(&event);
+ LOG(PluginEvents, "NPP_HandleEvent(loseFocusEvent): %d", acceptedEvent);
+ removeKeyEventHandler();
+ }
+}
+
+void WebNetscapePluginEventHandlerCarbon::windowFocusChanged(bool hasFocus)
+{
+ EventRecord event;
+
+ getCarbonEvent(&event);
+ event.what = activateEvt;
+ WindowRef windowRef = (WindowRef)[[m_pluginView window] windowRef];
+ event.message = (unsigned long)windowRef;
+ if (hasFocus)
+ event.modifiers |= activeFlag;
+
+ BOOL acceptedEvent;
+ acceptedEvent = sendEvent(&event);
+
+ LOG(PluginEvents, "NPP_HandleEvent(activateEvent): %d isActive: %d", acceptedEvent, hasFocus);
+}
+
+OSStatus WebNetscapePluginEventHandlerCarbon::TSMEventHandler(EventHandlerCallRef inHandlerRef, EventRef inEvent, void *eventHandler)
+{
+ EventRef rawKeyEventRef;
+ OSStatus status = GetEventParameter(inEvent, kEventParamTextInputSendKeyboardEvent, typeEventRef, NULL, sizeof(EventRef), NULL, &rawKeyEventRef);
+ if (status != noErr) {
+ LOG_ERROR("GetEventParameter failed with error: %d", status);
+ return noErr;
+ }
+
+ // Two-pass read to allocate/extract Mac charCodes
+ ByteCount numBytes;
+ status = GetEventParameter(rawKeyEventRef, kEventParamKeyMacCharCodes, typeChar, NULL, 0, &numBytes, NULL);
+ if (status != noErr) {
+ LOG_ERROR("GetEventParameter failed with error: %d", status);
+ return noErr;
+ }
+ char *buffer = (char *)malloc(numBytes);
+ status = GetEventParameter(rawKeyEventRef, kEventParamKeyMacCharCodes, typeChar, NULL, numBytes, NULL, buffer);
+ if (status != noErr) {
+ LOG_ERROR("GetEventParameter failed with error: %d", status);
+ free(buffer);
+ return noErr;
+ }
+
+ EventRef cloneEvent = CopyEvent(rawKeyEventRef);
+ unsigned i;
+ for (i = 0; i < numBytes; i++) {
+ status = SetEventParameter(cloneEvent, kEventParamKeyMacCharCodes, typeChar, 1 /* one char code */, &buffer[i]);
+ if (status != noErr) {
+ LOG_ERROR("SetEventParameter failed with error: %d", status);
+ free(buffer);
+ return noErr;
+ }
+
+ EventRecord eventRec;
+ if (ConvertEventRefToEventRecord(cloneEvent, &eventRec)) {
+ BOOL acceptedEvent;
+ acceptedEvent = static_cast<WebNetscapePluginEventHandlerCarbon*>(eventHandler)->sendEvent(&eventRec);
+
+ LOG(PluginEvents, "NPP_HandleEvent(keyDown): %d charCode:%c keyCode:%lu",
+ acceptedEvent, (char) (eventRec.message & charCodeMask), (eventRec.message & keyCodeMask));
+
+ // We originally thought that if the plug-in didn't accept this event,
+ // we should pass it along so that keyboard scrolling, for example, will work.
+ // In practice, this is not a good idea, because plug-ins tend to eat the event but return false.
+ // MacIE handles each key event twice because of this, but we will emulate the other browsers instead.
+ }
+ }
+ ReleaseEvent(cloneEvent);
+
+ free(buffer);
+
+ return noErr;
+}
+
+void WebNetscapePluginEventHandlerCarbon::installKeyEventHandler()
+{
+ static const EventTypeSpec sTSMEvents[] =
+ {
+ { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent }
+ };
+
+ if (!m_keyEventHandler) {
+ InstallEventHandler(GetWindowEventTarget((WindowRef)[[m_pluginView window] windowRef]),
+ NewEventHandlerUPP(TSMEventHandler),
+ GetEventTypeCount(sTSMEvents),
+ sTSMEvents,
+ this,
+ &m_keyEventHandler);
+ }
+}
+
+void WebNetscapePluginEventHandlerCarbon::removeKeyEventHandler()
+{
+ if (m_keyEventHandler) {
+ RemoveEventHandler(m_keyEventHandler);
+ m_keyEventHandler = 0;
+ }
+}
+
+void WebNetscapePluginEventHandlerCarbon::nullEventTimerFired(CFRunLoopTimerRef timerRef, void *context)
+{
+ static_cast<WebNetscapePluginEventHandlerCarbon*>(context)->sendNullEvent();
+}
+
+void WebNetscapePluginEventHandlerCarbon::startTimers(bool throttleTimers)
+{
+ ASSERT(!m_nullEventTimer);
+
+ CFTimeInterval interval = !throttleTimers ? NullEventIntervalActive : NullEventIntervalNotActive;
+
+ CFRunLoopTimerContext context = { 0, this, NULL, NULL, NULL };
+ m_nullEventTimer.adoptCF(CFRunLoopTimerCreate(0, CFAbsoluteTimeGetCurrent() + interval, interval,
+ 0, 0, nullEventTimerFired, &context));
+ CFRunLoopAddTimer(CFRunLoopGetCurrent(), m_nullEventTimer.get(), kCFRunLoopDefaultMode);
+}
+
+void WebNetscapePluginEventHandlerCarbon::stopTimers()
+{
+ if (!m_nullEventTimer)
+ return;
+
+ CFRunLoopTimerInvalidate(m_nullEventTimer.get());
+ m_nullEventTimer = 0;
+}
+
+void* WebNetscapePluginEventHandlerCarbon::platformWindow(NSWindow* window)
+{
+ return [window windowRef];
+}
+
+bool WebNetscapePluginEventHandlerCarbon::sendEvent(EventRecord* event)
+{
+ // If at any point the user clicks or presses a key from within a plugin, set the
+ // currentEventIsUserGesture flag to true. This is important to differentiate legitimate
+ // window.open() calls; we still want to allow those. See rdar://problem/4010765
+ if (event->what == ::mouseDown || event->what == ::keyDown || event->what == ::mouseUp || event->what == ::autoKey)
+ m_currentEventIsUserGesture = true;
+
+ m_suspendKeyUpEvents = false;
+
+ bool result = [m_pluginView sendEvent:event isDrawRect:event->what == updateEvt];
+
+ m_currentEventIsUserGesture = false;
+
+ return result;
+}
+
+#endif // ENABLE(NETSCAPE_PLUGIN_API) && !defined(__LP64__)
diff --git a/WebKit/mac/Plugins/WebNetscapePluginEventHandlerCocoa.h b/WebKit/mac/Plugins/WebNetscapePluginEventHandlerCocoa.h
new file mode 100644
index 0000000..e22ff3d
--- /dev/null
+++ b/WebKit/mac/Plugins/WebNetscapePluginEventHandlerCocoa.h
@@ -0,0 +1,65 @@
+/*
+ * 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 ENABLE(NETSCAPE_PLUGIN_API)
+
+#ifndef WebNetscapePluginEventHandlerCocoa_h
+#define WebNetscapePluginEventHandlerCocoa_h
+
+#include <WebKit/npapi.h>
+#include "WebNetscapePluginEventHandler.h"
+
+class WebNetscapePluginEventHandlerCocoa : public WebNetscapePluginEventHandler {
+public:
+ WebNetscapePluginEventHandlerCocoa(WebBaseNetscapePluginView*);
+
+ virtual void drawRect(const NSRect&);
+
+ virtual void mouseDown(NSEvent*);
+ virtual void mouseDragged(NSEvent*);
+ virtual void mouseEntered(NSEvent*);
+ virtual void mouseExited(NSEvent*);
+ virtual void mouseMoved(NSEvent*);
+ virtual void mouseUp(NSEvent*);
+ virtual bool scrollWheel(NSEvent*);
+
+ virtual void keyDown(NSEvent*);
+ virtual void keyUp(NSEvent*);
+ virtual void flagsChanged(NSEvent*);
+
+ virtual void windowFocusChanged(bool hasFocus);
+ virtual void focusChanged(bool hasFocus);
+
+ virtual void* platformWindow(NSWindow*);
+private:
+ bool sendMouseEvent(NSEvent*, NPCocoaEventType);
+ bool sendKeyEvent(NSEvent*, NPCocoaEventType);
+ bool sendEvent(NPCocoaEvent*);
+};
+
+#endif //WebNetscapePluginEventHandlerCocoa_h
+
+#endif // ENABLE(NETSCAPE_PLUGIN_API)
+
diff --git a/WebKit/mac/Plugins/WebNetscapePluginEventHandlerCocoa.mm b/WebKit/mac/Plugins/WebNetscapePluginEventHandlerCocoa.mm
new file mode 100644
index 0000000..fb13a12
--- /dev/null
+++ b/WebKit/mac/Plugins/WebNetscapePluginEventHandlerCocoa.mm
@@ -0,0 +1,205 @@
+/*
+ * 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 ENABLE(NETSCAPE_PLUGIN_API)
+
+#import "WebNetscapePluginEventHandlerCocoa.h"
+
+#import "WebBaseNetscapePluginView.h"
+
+WebNetscapePluginEventHandlerCocoa::WebNetscapePluginEventHandlerCocoa(WebBaseNetscapePluginView* pluginView)
+ : WebNetscapePluginEventHandler(pluginView)
+{
+}
+
+static inline void initializeEvent(NPCocoaEvent* event, NPCocoaEventType type)
+{
+ event->type = type;
+ event->version = 0;
+}
+
+void WebNetscapePluginEventHandlerCocoa::drawRect(const NSRect& rect)
+{
+ NPCocoaEvent event;
+
+ initializeEvent(&event, NPCocoaEventDrawRect);
+ event.data.draw.x = rect.origin.x;
+ event.data.draw.y = rect.origin.y;
+ event.data.draw.width = rect.size.width;
+ event.data.draw.height = rect.size.height;
+
+ sendEvent(&event);
+}
+
+void WebNetscapePluginEventHandlerCocoa::mouseDown(NSEvent *event)
+{
+ sendMouseEvent(event, NPCocoaEventMouseDown);
+}
+
+void WebNetscapePluginEventHandlerCocoa::mouseDragged(NSEvent *event)
+{
+ sendMouseEvent(event, NPCocoaEventMouseDragged);
+}
+
+void WebNetscapePluginEventHandlerCocoa::mouseEntered(NSEvent *event)
+{
+ sendMouseEvent(event, NPCocoaEventMouseEntered);
+}
+
+void WebNetscapePluginEventHandlerCocoa::mouseExited(NSEvent *event)
+{
+ sendMouseEvent(event, NPCocoaEventMouseExited);
+}
+
+void WebNetscapePluginEventHandlerCocoa::mouseMoved(NSEvent *event)
+{
+ sendMouseEvent(event, NPCocoaEventMouseMoved);
+}
+
+void WebNetscapePluginEventHandlerCocoa::mouseUp(NSEvent *event)
+{
+ sendMouseEvent(event, NPCocoaEventMouseUp);
+}
+
+bool WebNetscapePluginEventHandlerCocoa::scrollWheel(NSEvent* event)
+{
+ return sendMouseEvent(event, NPCocoaEventScrollWheel);
+}
+
+bool WebNetscapePluginEventHandlerCocoa::sendMouseEvent(NSEvent *nsEvent, NPCocoaEventType type)
+{
+ NPCocoaEvent event;
+
+ NSPoint point = [m_pluginView convertPoint:[nsEvent locationInWindow] fromView:nil];
+
+ int clickCount;
+ if (type == NPCocoaEventMouseEntered || type == NPCocoaEventMouseExited || type == NPCocoaEventScrollWheel)
+ clickCount = 0;
+ else
+ clickCount = [nsEvent clickCount];
+
+ initializeEvent(&event, type);
+ event.data.mouse.modifierFlags = [nsEvent modifierFlags];
+ event.data.mouse.buttonNumber = [nsEvent buttonNumber];
+ event.data.mouse.clickCount = clickCount;
+ event.data.mouse.pluginX = point.x;
+ event.data.mouse.pluginY = point.y;
+ event.data.mouse.deltaX = [nsEvent deltaX];
+ event.data.mouse.deltaY = [nsEvent deltaY];
+ event.data.mouse.deltaZ = [nsEvent deltaZ];
+
+ return sendEvent(&event);
+}
+
+void WebNetscapePluginEventHandlerCocoa::keyDown(NSEvent *event)
+{
+ bool retval = sendKeyEvent(event, NPCocoaEventKeyDown);
+
+ // If the plug-in did not handle the event, pass it on to the Input Manager.
+ if (!retval)
+ [m_pluginView interpretKeyEvents:[NSArray arrayWithObject:event]];
+}
+
+void WebNetscapePluginEventHandlerCocoa::keyUp(NSEvent *event)
+{
+ sendKeyEvent(event, NPCocoaEventKeyUp);
+}
+
+void WebNetscapePluginEventHandlerCocoa::flagsChanged(NSEvent *nsEvent)
+{
+ NPCocoaEvent event;
+
+ initializeEvent(&event, NPCocoaEventFlagsChanged);
+ event.data.key.modifierFlags = [nsEvent modifierFlags];
+ event.data.key.keyCode = [nsEvent keyCode];
+ event.data.key.isARepeat = false;
+ event.data.key.characters = 0;
+ event.data.key.charactersIgnoringModifiers = 0;
+
+ sendEvent(&event);
+}
+
+bool WebNetscapePluginEventHandlerCocoa::sendKeyEvent(NSEvent* nsEvent, NPCocoaEventType type)
+{
+ NPCocoaEvent event;
+
+ initializeEvent(&event, type);
+ event.data.key.modifierFlags = [nsEvent modifierFlags];
+ event.data.key.keyCode = [nsEvent keyCode];
+ event.data.key.isARepeat = [nsEvent isARepeat];
+ event.data.key.characters = (NPNSString *)[nsEvent characters];
+ event.data.key.charactersIgnoringModifiers = (NPNSString *)[nsEvent charactersIgnoringModifiers];
+
+ return sendEvent(&event);
+}
+
+void WebNetscapePluginEventHandlerCocoa::windowFocusChanged(bool hasFocus)
+{
+ NPCocoaEvent event;
+
+ initializeEvent(&event, NPCocoaEventWindowFocusChanged);
+ event.data.focus.hasFocus = hasFocus;
+
+ sendEvent(&event);
+}
+
+void WebNetscapePluginEventHandlerCocoa::focusChanged(bool hasFocus)
+{
+ NPCocoaEvent event;
+
+ initializeEvent(&event, NPCocoaEventFocusChanged);
+ event.data.focus.hasFocus = hasFocus;
+
+ sendEvent(&event);
+}
+
+void* WebNetscapePluginEventHandlerCocoa::platformWindow(NSWindow* window)
+{
+ return window;
+}
+
+bool WebNetscapePluginEventHandlerCocoa::sendEvent(NPCocoaEvent* event)
+{
+ switch (event->type) {
+ case NPCocoaEventMouseDown:
+ case NPCocoaEventMouseUp:
+ case NPCocoaEventMouseDragged:
+ case NPCocoaEventKeyDown:
+ case NPCocoaEventKeyUp:
+ case NPCocoaEventFlagsChanged:
+ case NPCocoaEventScrollWheel:
+ m_currentEventIsUserGesture = true;
+ break;
+ default:
+ m_currentEventIsUserGesture = false;
+ }
+
+ bool result = [m_pluginView sendEvent:event isDrawRect:event->type == NPCocoaEventDrawRect];
+
+ m_currentEventIsUserGesture = false;
+ return result;
+}
+
+#endif // ENABLE(NETSCAPE_PLUGIN_API)
diff --git a/WebKit/mac/Plugins/WebNetscapePluginPackage.h b/WebKit/mac/Plugins/WebNetscapePluginPackage.h
new file mode 100644
index 0000000..6ccbfdb
--- /dev/null
+++ b/WebKit/mac/Plugins/WebNetscapePluginPackage.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2005, 2006, 2007 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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 ENABLE(NETSCAPE_PLUGIN_API)
+#import "WebBasePluginPackage.h"
+
+#ifdef BUILDING_ON_TIGER
+typedef short ResFileRefNum;
+#endif
+
+#if defined(__ppc__) && !defined(__LP64__)
+#define SUPPORT_CFM
+#endif
+
+typedef enum {
+ WebCFMExecutableType,
+ WebMachOExecutableType
+} WebExecutableType;
+
+@interface WebNetscapePluginPackage : WebBasePluginPackage
+{
+ NPPluginFuncs pluginFuncs;
+ NPNetscapeFuncs browserFuncs;
+
+ uint16 pluginSize;
+ uint16 pluginVersion;
+
+ ResFileRefNum resourceRef;
+
+ NPP_NewProcPtr NPP_New;
+ NPP_DestroyProcPtr NPP_Destroy;
+ NPP_SetWindowProcPtr NPP_SetWindow;
+ NPP_NewStreamProcPtr NPP_NewStream;
+ NPP_DestroyStreamProcPtr NPP_DestroyStream;
+ NPP_StreamAsFileProcPtr NPP_StreamAsFile;
+ NPP_WriteReadyProcPtr NPP_WriteReady;
+ NPP_WriteProcPtr NPP_Write;
+ NPP_PrintProcPtr NPP_Print;
+ NPP_HandleEventProcPtr NPP_HandleEvent;
+ NPP_URLNotifyProcPtr NPP_URLNotify;
+ NPP_GetValueProcPtr NPP_GetValue;
+ NPP_SetValueProcPtr NPP_SetValue;
+ NPP_ShutdownProcPtr NPP_Shutdown;
+ NPP_GetJavaClassProcPtr NPP_GetJavaClass;
+
+ BOOL isLoaded;
+ BOOL needsUnload;
+ unsigned int instanceCount;
+
+#ifdef SUPPORT_CFM
+ BOOL isBundle;
+ BOOL isCFM;
+ CFragConnectionID connID;
+#endif
+}
+
+// Netscape plug-in packages must be explicitly opened and closed by each plug-in instance.
+// This is to protect Netscape plug-ins from being unloaded while they are in use.
+- (void)open;
+- (void)close;
+
+- (WebExecutableType)executableType;
+
+- (NPP_NewProcPtr)NPP_New;
+- (NPP_DestroyProcPtr)NPP_Destroy;
+- (NPP_SetWindowProcPtr)NPP_SetWindow;
+- (NPP_NewStreamProcPtr)NPP_NewStream;
+- (NPP_WriteReadyProcPtr)NPP_WriteReady;
+- (NPP_WriteProcPtr)NPP_Write;
+- (NPP_StreamAsFileProcPtr)NPP_StreamAsFile;
+- (NPP_DestroyStreamProcPtr)NPP_DestroyStream;
+- (NPP_HandleEventProcPtr)NPP_HandleEvent;
+- (NPP_URLNotifyProcPtr)NPP_URLNotify;
+- (NPP_GetValueProcPtr)NPP_GetValue;
+- (NPP_SetValueProcPtr)NPP_SetValue;
+- (NPP_PrintProcPtr)NPP_Print;
+- (NPPluginFuncs *)pluginFuncs;
+
+@end
+#endif
diff --git a/WebKit/mac/Plugins/WebNetscapePluginPackage.m b/WebKit/mac/Plugins/WebNetscapePluginPackage.m
new file mode 100644
index 0000000..0767c1d
--- /dev/null
+++ b/WebKit/mac/Plugins/WebNetscapePluginPackage.m
@@ -0,0 +1,798 @@
+/*
+ * Copyright (C) 2005, 2006, 2007 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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 ENABLE(NETSCAPE_PLUGIN_API)
+#import "WebNetscapePluginPackage.h"
+
+#import "WebKitLogging.h"
+#import "WebKitNSStringExtras.h"
+#import "WebNSObjectExtras.h"
+#import "WebNetscapeDeprecatedFunctions.h"
+#import <WebCore/npruntime_impl.h>
+
+#ifdef SUPPORT_CFM
+typedef void (* FunctionPointer)(void);
+typedef void (* TransitionVector)(void);
+static FunctionPointer functionPointerForTVector(TransitionVector);
+static TransitionVector tVectorForFunctionPointer(FunctionPointer);
+#endif
+
+#define PluginNameOrDescriptionStringNumber 126
+#define MIMEDescriptionStringNumber 127
+#define MIMEListStringStringNumber 128
+
+#define RealPlayerAppIndentifier @"com.RealNetworks.RealOne Player"
+#define RealPlayerPluginFilename @"RealPlayer Plugin"
+
+@interface WebNetscapePluginPackage (Internal)
+- (void)_unloadWithShutdown:(BOOL)shutdown;
+@end
+
+@implementation WebNetscapePluginPackage
+
+#ifndef __LP64__
++ (void)initialize
+{
+ // The Shockwave plugin requires a valid file in CurApRefNum.
+ // But it doesn't seem to matter what file it is.
+ // If we're called inside a Cocoa application which won't have a
+ // CurApRefNum, we set it to point to the system resource file.
+
+ // Call CurResFile before testing the result of WebLMGetCurApRefNum.
+ // If we are called before the bundle resource map has been opened
+ // for a Carbon application (or a Cocoa app with Resource Manager
+ // resources) we *do not* want to set CurApRefNum to point at the
+ // system resource file. CurResFile triggers Resource Manager lazy
+ // initialization, and will open the bundle resource map as necessary.
+
+ CurResFile();
+
+ if (WebLMGetCurApRefNum() == -1) {
+ // To get the refNum for the system resource file, we have to do
+ // UseResFile(kSystemResFile) and then look at CurResFile().
+ short savedCurResFile = CurResFile();
+ UseResFile(kSystemResFile);
+ WebLMSetCurApRefNum(CurResFile());
+ UseResFile(savedCurResFile);
+ }
+}
+#endif
+
+- (ResFileRefNum)openResourceFile
+{
+#ifdef SUPPORT_CFM
+ if (!isBundle) {
+ FSRef fref;
+ OSErr err = FSPathMakeRef((const UInt8 *)[path fileSystemRepresentation], &fref, NULL);
+ if (err != noErr)
+ return -1;
+
+ return FSOpenResFile(&fref, fsRdPerm);
+ }
+#endif
+
+ return CFBundleOpenBundleResourceMap(cfBundle);
+}
+
+- (void)closeResourceFile:(ResFileRefNum)resRef
+{
+#ifdef SUPPORT_CFM
+ if (!isBundle) {
+ CloseResFile(resRef);
+ return;
+ }
+#endif
+
+ CFBundleCloseBundleResourceMap(cfBundle, resRef);
+}
+
+- (NSString *)stringForStringListID:(SInt16)stringListID andIndex:(SInt16)index
+{
+ // Get resource, and dereference the handle.
+ Handle stringHandle = Get1Resource('STR#', stringListID);
+ if (stringHandle == NULL) {
+ return nil;
+ }
+ unsigned char *p = (unsigned char *)*stringHandle;
+ if (!p)
+ return nil;
+
+ // Check the index against the length of the string list, then skip the length.
+ if (index < 1 || index > *(SInt16 *)p)
+ return nil;
+ p += sizeof(SInt16);
+
+ // Skip any strings that come before the one we are looking for.
+ while (--index)
+ p += 1 + *p;
+
+ // Convert the one we found into an NSString.
+ return [[[NSString alloc] initWithBytes:(p + 1) length:*p encoding:[NSString _web_encodingForResource:stringHandle]] autorelease];
+}
+
+- (BOOL)getPluginInfoFromResources
+{
+ SInt16 resRef = [self openResourceFile];
+ if (resRef == -1)
+ return NO;
+
+ UseResFile(resRef);
+ if (ResError() != noErr)
+ return NO;
+
+ NSString *MIME, *extensionsList, *description;
+ NSArray *extensions;
+ unsigned i;
+
+ NSMutableDictionary *MIMEToExtensionsDictionary = [NSMutableDictionary dictionary];
+ NSMutableDictionary *MIMEToDescriptionDictionary = [NSMutableDictionary dictionary];
+
+ for (i=1; 1; i+=2) {
+ MIME = [[self stringForStringListID:MIMEListStringStringNumber
+ andIndex:i] lowercaseString];
+ if (!MIME)
+ break;
+
+ extensionsList = [[self stringForStringListID:MIMEListStringStringNumber andIndex:i+1] lowercaseString];
+ if (extensionsList) {
+ extensions = [extensionsList componentsSeparatedByString:@","];
+ [MIMEToExtensionsDictionary setObject:extensions forKey:MIME];
+ } else
+ // DRM and WMP claim MIMEs without extensions. Use a @"" extension in this case.
+ [MIMEToExtensionsDictionary setObject:[NSArray arrayWithObject:@""] forKey:MIME];
+
+ description = [self stringForStringListID:MIMEDescriptionStringNumber
+ andIndex:[MIMEToExtensionsDictionary count]];
+ if (description)
+ [MIMEToDescriptionDictionary setObject:description forKey:MIME];
+ else
+ [MIMEToDescriptionDictionary setObject:@"" forKey:MIME];
+ }
+
+ [self setMIMEToDescriptionDictionary:MIMEToDescriptionDictionary];
+ [self setMIMEToExtensionsDictionary:MIMEToExtensionsDictionary];
+
+ NSString *filename = [self filename];
+
+ description = [self stringForStringListID:PluginNameOrDescriptionStringNumber andIndex:1];
+ if (!description)
+ description = filename;
+ [self setPluginDescription:description];
+
+
+ NSString *theName = [self stringForStringListID:PluginNameOrDescriptionStringNumber andIndex:2];
+ if (!theName)
+ theName = filename;
+ [self setName:theName];
+
+ [self closeResourceFile:resRef];
+
+ return YES;
+}
+
+- (BOOL)_initWithPath:(NSString *)pluginPath
+{
+ resourceRef = -1;
+
+ OSType type = 0;
+
+ if (bundle) {
+ // Bundle
+ CFBundleGetPackageInfo(cfBundle, &type, NULL);
+#ifdef SUPPORT_CFM
+ isBundle = YES;
+#endif
+ } else {
+#ifdef SUPPORT_CFM
+ // Single-file plug-in with resource fork
+ type = [[[NSFileManager defaultManager] fileAttributesAtPath:path traverseLink:YES] fileHFSTypeCode];
+ isBundle = NO;
+ isCFM = YES;
+#else
+ return NO;
+#endif
+ }
+
+ if (type != FOUR_CHAR_CODE('BRPL'))
+ return NO;
+
+ // Check if the executable is Mach-O or CFM.
+ if (bundle) {
+ NSFileHandle *executableFile = [NSFileHandle fileHandleForReadingAtPath:[bundle executablePath]];
+ NSData *data = [executableFile readDataOfLength:512];
+ [executableFile closeFile];
+ // Check the length of the data before calling memcmp. We think this fixes 3782543.
+ if (data == nil || [data length] < 8)
+ return NO;
+ BOOL hasCFMHeader = memcmp([data bytes], "Joy!peff", 8) == 0;
+#ifdef SUPPORT_CFM
+ isCFM = hasCFMHeader;
+#else
+ if (hasCFMHeader)
+ return NO;
+#endif
+
+ if (![self isNativeLibraryData:data])
+ return NO;
+ }
+
+ if (![self getPluginInfoFromPLists] && ![self getPluginInfoFromResources])
+ return NO;
+
+ return YES;
+}
+
+- (id)initWithPath:(NSString *)pluginPath
+{
+ if (!(self = [super initWithPath:pluginPath]))
+ return nil;
+
+ // Initializing a plugin package can cause it to be loaded. If there was an error initializing the plugin package,
+ // ensure that it is unloaded before deallocating it (WebBasePluginPackage requires & asserts this).
+ if (![self _initWithPath:pluginPath]) {
+ [self _unloadWithShutdown:YES];
+ [self release];
+ return nil;
+ }
+
+ return self;
+}
+
+- (WebExecutableType)executableType
+{
+#ifdef SUPPORT_CFM
+ if (isCFM)
+ return WebCFMExecutableType;
+#endif
+ return WebMachOExecutableType;
+}
+
+- (void)launchRealPlayer
+{
+ CFURLRef appURL = NULL;
+ OSStatus error = LSFindApplicationForInfo(kLSUnknownCreator, (CFStringRef)RealPlayerAppIndentifier, NULL, NULL, &appURL);
+ if (!error) {
+ LSLaunchURLSpec URLSpec;
+ bzero(&URLSpec, sizeof(URLSpec));
+ URLSpec.launchFlags = kLSLaunchDefaults | kLSLaunchDontSwitch;
+ URLSpec.appURL = appURL;
+ LSOpenFromURLSpec(&URLSpec, NULL);
+ CFRelease(appURL);
+ }
+}
+
+- (void)_applyDjVuWorkaround
+{
+ if (!cfBundle)
+ return;
+
+ if ([(NSString *)CFBundleGetIdentifier(cfBundle) isEqualToString:@"com.lizardtech.NPDjVu"]) {
+ // The DjVu plug-in will crash copying the vtable if it's too big so we cap it to
+ // what the plug-in expects here.
+ // size + version + 40 function pointers.
+ browserFuncs.size = 2 + 2 + sizeof(void *) * 40;
+ }
+
+}
+
+- (void)unload
+{
+ [self _unloadWithShutdown:YES];
+}
+
+- (BOOL)load
+{
+ NP_GetEntryPointsFuncPtr NP_GetEntryPoints = NULL;
+ NP_InitializeFuncPtr NP_Initialize = NULL;
+ NPError npErr;
+
+#ifdef SUPPORT_CFM
+ MainFuncPtr pluginMainFunc = NULL;
+#endif
+
+#if !LOG_DISABLED
+ CFAbsoluteTime start = CFAbsoluteTimeGetCurrent();
+ CFAbsoluteTime currentTime;
+ CFAbsoluteTime duration;
+#endif
+ LOG(Plugins, "%f Load timing started for: %@", start, [self name]);
+
+ if (isLoaded)
+ return YES;
+
+#ifdef SUPPORT_CFM
+ if (isBundle) {
+#endif
+ if (!CFBundleLoadExecutable(cfBundle))
+ goto abort;
+#if !LOG_DISABLED
+ currentTime = CFAbsoluteTimeGetCurrent();
+ duration = currentTime - start;
+#endif
+ LOG(Plugins, "%f CFBundleLoadExecutable took %f seconds", currentTime, duration);
+ isLoaded = YES;
+
+#ifdef SUPPORT_CFM
+ if (isCFM) {
+ pluginMainFunc = (MainFuncPtr)CFBundleGetFunctionPointerForName(cfBundle, CFSTR("main") );
+ if (!pluginMainFunc)
+ goto abort;
+ } else {
+#endif
+ NP_Initialize = (NP_InitializeFuncPtr)CFBundleGetFunctionPointerForName(cfBundle, CFSTR("NP_Initialize"));
+ NP_GetEntryPoints = (NP_GetEntryPointsFuncPtr)CFBundleGetFunctionPointerForName(cfBundle, CFSTR("NP_GetEntryPoints"));
+ NPP_Shutdown = (NPP_ShutdownProcPtr)CFBundleGetFunctionPointerForName(cfBundle, CFSTR("NP_Shutdown"));
+ if (!NP_Initialize || !NP_GetEntryPoints || !NPP_Shutdown)
+ goto abort;
+#ifdef SUPPORT_CFM
+ }
+ } else {
+ // single CFM file
+ FSSpec spec;
+ FSRef fref;
+ OSErr err;
+
+ err = FSPathMakeRef((UInt8 *)[path fileSystemRepresentation], &fref, NULL);
+ if (err != noErr) {
+ LOG_ERROR("FSPathMakeRef failed. Error=%d", err);
+ goto abort;
+ }
+ err = FSGetCatalogInfo(&fref, kFSCatInfoNone, NULL, NULL, &spec, NULL);
+ if (err != noErr) {
+ LOG_ERROR("FSGetCatalogInfo failed. Error=%d", err);
+ goto abort;
+ }
+ err = WebGetDiskFragment(&spec, 0, kCFragGoesToEOF, nil, kPrivateCFragCopy, &connID, (Ptr *)&pluginMainFunc, nil);
+ if (err != noErr) {
+ LOG_ERROR("WebGetDiskFragment failed. Error=%d", err);
+ goto abort;
+ }
+#if !LOG_DISABLED
+ currentTime = CFAbsoluteTimeGetCurrent();
+ duration = currentTime - start;
+#endif
+ LOG(Plugins, "%f WebGetDiskFragment took %f seconds", currentTime, duration);
+ isLoaded = YES;
+
+ pluginMainFunc = (MainFuncPtr)functionPointerForTVector((TransitionVector)pluginMainFunc);
+ if (!pluginMainFunc) {
+ goto abort;
+ }
+
+ // NOTE: pluginMainFunc is freed after it is called. Be sure not to return before that.
+
+ isCFM = YES;
+ }
+#endif /* SUPPORT_CFM */
+
+ // Plugins (at least QT) require that you call UseResFile on the resource file before loading it.
+ resourceRef = [self openResourceFile];
+ if (resourceRef != -1) {
+ UseResFile(resourceRef);
+ }
+
+ // swap function tables
+#ifdef SUPPORT_CFM
+ if (isCFM) {
+ browserFuncs.version = NP_VERSION_MINOR;
+ browserFuncs.size = sizeof(NPNetscapeFuncs);
+ browserFuncs.geturl = (NPN_GetURLProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_GetURL);
+ browserFuncs.posturl = (NPN_PostURLProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_PostURL);
+ browserFuncs.requestread = (NPN_RequestReadProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_RequestRead);
+ browserFuncs.newstream = (NPN_NewStreamProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_NewStream);
+ browserFuncs.write = (NPN_WriteProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_Write);
+ browserFuncs.destroystream = (NPN_DestroyStreamProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_DestroyStream);
+ browserFuncs.status = (NPN_StatusProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_Status);
+ browserFuncs.uagent = (NPN_UserAgentProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_UserAgent);
+ browserFuncs.memalloc = (NPN_MemAllocProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_MemAlloc);
+ browserFuncs.memfree = (NPN_MemFreeProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_MemFree);
+ browserFuncs.memflush = (NPN_MemFlushProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_MemFlush);
+ browserFuncs.reloadplugins = (NPN_ReloadPluginsProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_ReloadPlugins);
+ browserFuncs.geturlnotify = (NPN_GetURLNotifyProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_GetURLNotify);
+ browserFuncs.posturlnotify = (NPN_PostURLNotifyProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_PostURLNotify);
+ browserFuncs.getvalue = (NPN_GetValueProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_GetValue);
+ browserFuncs.setvalue = (NPN_SetValueProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_SetValue);
+ browserFuncs.invalidaterect = (NPN_InvalidateRectProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_InvalidateRect);
+ browserFuncs.invalidateregion = (NPN_InvalidateRegionProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_InvalidateRegion);
+ browserFuncs.forceredraw = (NPN_ForceRedrawProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_ForceRedraw);
+ browserFuncs.getJavaEnv = (NPN_GetJavaEnvProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_GetJavaEnv);
+ browserFuncs.getJavaPeer = (NPN_GetJavaPeerProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_GetJavaPeer);
+ browserFuncs.pushpopupsenabledstate = (NPN_PushPopupsEnabledStateProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_PushPopupsEnabledState);
+ browserFuncs.poppopupsenabledstate = (NPN_PopPopupsEnabledStateProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_PopPopupsEnabledState);
+ browserFuncs.pluginthreadasynccall = (NPN_PluginThreadAsyncCallProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_PluginThreadAsyncCall);
+ browserFuncs.scheduletimer = (NPN_ScheduleTimerProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_ScheduleTimer);
+ browserFuncs.unscheduletimer = (NPN_UnscheduleTimerProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_UnscheduleTimer);
+ browserFuncs.popupcontextmenu = (NPN_PopUpContextMenuProcPtr)tVectorForFunctionPointer((FunctionPointer)NPN_PopUpContextMenu);
+
+ browserFuncs.releasevariantvalue = (NPN_ReleaseVariantValueProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_ReleaseVariantValue);
+ browserFuncs.getstringidentifier = (NPN_GetStringIdentifierProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_GetStringIdentifier);
+ browserFuncs.getstringidentifiers = (NPN_GetStringIdentifiersProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_GetStringIdentifiers);
+ browserFuncs.getintidentifier = (NPN_GetIntIdentifierProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_GetIntIdentifier);
+ browserFuncs.identifierisstring = (NPN_IdentifierIsStringProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_IdentifierIsString);
+ browserFuncs.utf8fromidentifier = (NPN_UTF8FromIdentifierProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_UTF8FromIdentifier);
+ browserFuncs.intfromidentifier = (NPN_IntFromIdentifierProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_IntFromIdentifier);
+ browserFuncs.createobject = (NPN_CreateObjectProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_CreateObject);
+ browserFuncs.retainobject = (NPN_RetainObjectProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_RetainObject);
+ browserFuncs.releaseobject = (NPN_ReleaseObjectProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_ReleaseObject);
+ browserFuncs.invoke = (NPN_InvokeProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_Invoke);
+ browserFuncs.invokeDefault = (NPN_InvokeDefaultProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_InvokeDefault);
+ browserFuncs.evaluate = (NPN_EvaluateProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_Evaluate);
+ browserFuncs.getproperty = (NPN_GetPropertyProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_GetProperty);
+ browserFuncs.setproperty = (NPN_SetPropertyProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_SetProperty);
+ browserFuncs.removeproperty = (NPN_RemovePropertyProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_RemoveProperty);
+ browserFuncs.setexception = (NPN_SetExceptionProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_SetException);
+ browserFuncs.enumerate = (NPN_EnumerateProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_Enumerate);
+ browserFuncs.construct = (NPN_ConstructProcPtr)tVectorForFunctionPointer((FunctionPointer)_NPN_Construct);
+
+ [self _applyDjVuWorkaround];
+
+#if !LOG_DISABLED
+ CFAbsoluteTime mainStart = CFAbsoluteTimeGetCurrent();
+#endif
+ LOG(Plugins, "%f main timing started", mainStart);
+ NPP_ShutdownProcPtr shutdownFunction;
+ npErr = pluginMainFunc(&browserFuncs, &pluginFuncs, &shutdownFunction);
+ NPP_Shutdown = (NPP_ShutdownProcPtr)functionPointerForTVector((TransitionVector)shutdownFunction);
+ if (!isBundle)
+ // Don't free pluginMainFunc if we got it from a bundle because it is owned by CFBundle in that case.
+ free(pluginMainFunc);
+
+ // Workaround for 3270576. The RealPlayer plug-in fails to load if its preference file is out of date.
+ // Launch the RealPlayer application to refresh the file.
+ if (npErr != NPERR_NO_ERROR) {
+ if (npErr == NPERR_MODULE_LOAD_FAILED_ERROR && [[self filename] isEqualToString:RealPlayerPluginFilename])
+ [self launchRealPlayer];
+ goto abort;
+ }
+#if !LOG_DISABLED
+ currentTime = CFAbsoluteTimeGetCurrent();
+ duration = currentTime - mainStart;
+#endif
+ LOG(Plugins, "%f main took %f seconds", currentTime, duration);
+
+ pluginSize = pluginFuncs.size;
+ pluginVersion = pluginFuncs.version;
+ LOG(Plugins, "pluginMainFunc: %d, size=%d, version=%d", npErr, pluginSize, pluginVersion);
+
+ NPP_New = (NPP_NewProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.newp);
+ NPP_Destroy = (NPP_DestroyProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.destroy);
+ NPP_SetWindow = (NPP_SetWindowProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.setwindow);
+ NPP_NewStream = (NPP_NewStreamProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.newstream);
+ NPP_DestroyStream = (NPP_DestroyStreamProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.destroystream);
+ NPP_StreamAsFile = (NPP_StreamAsFileProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.asfile);
+ NPP_WriteReady = (NPP_WriteReadyProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.writeready);
+ NPP_Write = (NPP_WriteProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.write);
+ NPP_Print = (NPP_PrintProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.print);
+ NPP_HandleEvent = (NPP_HandleEventProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.event);
+ NPP_URLNotify = (NPP_URLNotifyProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.urlnotify);
+ NPP_GetValue = (NPP_GetValueProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.getvalue);
+ NPP_SetValue = (NPP_SetValueProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.setvalue);
+
+ // LiveConnect support
+ NPP_GetJavaClass = (NPP_GetJavaClassProcPtr)functionPointerForTVector((TransitionVector)pluginFuncs.javaClass);
+ if (NPP_GetJavaClass) {
+ LOG(LiveConnect, "%@: CFM entry point for NPP_GetJavaClass = %p", [self name], NPP_GetJavaClass);
+ } else {
+ LOG(LiveConnect, "%@: no entry point for NPP_GetJavaClass", [self name]);
+ }
+
+ } else {
+
+#endif
+
+ // no function pointer conversion necessary for Mach-O
+ browserFuncs.version = NP_VERSION_MINOR;
+ browserFuncs.size = sizeof(NPNetscapeFuncs);
+ browserFuncs.geturl = NPN_GetURL;
+ browserFuncs.posturl = NPN_PostURL;
+ browserFuncs.requestread = NPN_RequestRead;
+ browserFuncs.newstream = NPN_NewStream;
+ browserFuncs.write = NPN_Write;
+ browserFuncs.destroystream = NPN_DestroyStream;
+ browserFuncs.status = NPN_Status;
+ browserFuncs.uagent = NPN_UserAgent;
+ browserFuncs.memalloc = NPN_MemAlloc;
+ browserFuncs.memfree = NPN_MemFree;
+ browserFuncs.memflush = NPN_MemFlush;
+ browserFuncs.reloadplugins = NPN_ReloadPlugins;
+ browserFuncs.geturlnotify = NPN_GetURLNotify;
+ browserFuncs.posturlnotify = NPN_PostURLNotify;
+ browserFuncs.getvalue = NPN_GetValue;
+ browserFuncs.setvalue = NPN_SetValue;
+ browserFuncs.invalidaterect = NPN_InvalidateRect;
+ browserFuncs.invalidateregion = NPN_InvalidateRegion;
+ browserFuncs.forceredraw = NPN_ForceRedraw;
+ browserFuncs.getJavaEnv = NPN_GetJavaEnv;
+ browserFuncs.getJavaPeer = NPN_GetJavaPeer;
+ browserFuncs.pushpopupsenabledstate = NPN_PushPopupsEnabledState;
+ browserFuncs.poppopupsenabledstate = NPN_PopPopupsEnabledState;
+ browserFuncs.pluginthreadasynccall = NPN_PluginThreadAsyncCall;
+ browserFuncs.scheduletimer = NPN_ScheduleTimer;
+ browserFuncs.unscheduletimer = NPN_UnscheduleTimer;
+ browserFuncs.popupcontextmenu = NPN_PopUpContextMenu;
+
+ browserFuncs.releasevariantvalue = _NPN_ReleaseVariantValue;
+ browserFuncs.getstringidentifier = _NPN_GetStringIdentifier;
+ browserFuncs.getstringidentifiers = _NPN_GetStringIdentifiers;
+ browserFuncs.getintidentifier = _NPN_GetIntIdentifier;
+ browserFuncs.identifierisstring = _NPN_IdentifierIsString;
+ browserFuncs.utf8fromidentifier = _NPN_UTF8FromIdentifier;
+ browserFuncs.intfromidentifier = _NPN_IntFromIdentifier;
+ browserFuncs.createobject = _NPN_CreateObject;
+ browserFuncs.retainobject = _NPN_RetainObject;
+ browserFuncs.releaseobject = _NPN_ReleaseObject;
+ browserFuncs.invoke = _NPN_Invoke;
+ browserFuncs.invokeDefault = _NPN_InvokeDefault;
+ browserFuncs.evaluate = _NPN_Evaluate;
+ browserFuncs.getproperty = _NPN_GetProperty;
+ browserFuncs.setproperty = _NPN_SetProperty;
+ browserFuncs.removeproperty = _NPN_RemoveProperty;
+ browserFuncs.setexception = _NPN_SetException;
+ browserFuncs.enumerate = _NPN_Enumerate;
+ browserFuncs.construct = _NPN_Construct;
+
+ [self _applyDjVuWorkaround];
+
+#if !LOG_DISABLED
+ CFAbsoluteTime initializeStart = CFAbsoluteTimeGetCurrent();
+#endif
+ LOG(Plugins, "%f NP_Initialize timing started", initializeStart);
+ npErr = NP_Initialize(&browserFuncs);
+ if (npErr != NPERR_NO_ERROR)
+ goto abort;
+#if !LOG_DISABLED
+ currentTime = CFAbsoluteTimeGetCurrent();
+ duration = currentTime - initializeStart;
+#endif
+ LOG(Plugins, "%f NP_Initialize took %f seconds", currentTime, duration);
+
+ pluginFuncs.size = sizeof(NPPluginFuncs);
+
+ npErr = NP_GetEntryPoints(&pluginFuncs);
+ if (npErr != NPERR_NO_ERROR)
+ goto abort;
+
+ pluginSize = pluginFuncs.size;
+ pluginVersion = pluginFuncs.version;
+
+ NPP_New = pluginFuncs.newp;
+ NPP_Destroy = pluginFuncs.destroy;
+ NPP_SetWindow = pluginFuncs.setwindow;
+ NPP_NewStream = pluginFuncs.newstream;
+ NPP_DestroyStream = pluginFuncs.destroystream;
+ NPP_StreamAsFile = pluginFuncs.asfile;
+ NPP_WriteReady = pluginFuncs.writeready;
+ NPP_Write = pluginFuncs.write;
+ NPP_Print = pluginFuncs.print;
+ NPP_HandleEvent = pluginFuncs.event;
+ NPP_URLNotify = pluginFuncs.urlnotify;
+ NPP_GetValue = pluginFuncs.getvalue;
+ NPP_SetValue = pluginFuncs.setvalue;
+
+ // LiveConnect support
+ NPP_GetJavaClass = pluginFuncs.javaClass;
+ if (NPP_GetJavaClass){
+ LOG(LiveConnect, "%@: mach-o entry point for NPP_GetJavaClass = %p", [self name], NPP_GetJavaClass);
+ } else {
+ LOG(LiveConnect, "%@: no entry point for NPP_GetJavaClass", [self name]);
+ }
+
+#ifdef SUPPORT_CFM
+ }
+#endif
+
+#if !LOG_DISABLED
+ currentTime = CFAbsoluteTimeGetCurrent();
+ duration = currentTime - start;
+#endif
+ LOG(Plugins, "%f Total load time: %f seconds", currentTime, duration);
+
+ return [super load];
+
+abort:
+ [self _unloadWithShutdown:NO];
+ return NO;
+}
+
+- (NPP_SetWindowProcPtr)NPP_SetWindow
+{
+ return NPP_SetWindow;
+}
+
+- (NPP_NewProcPtr)NPP_New
+{
+ return NPP_New;
+}
+
+- (NPP_DestroyProcPtr)NPP_Destroy
+{
+ return NPP_Destroy;
+}
+
+- (NPP_NewStreamProcPtr)NPP_NewStream
+{
+ return NPP_NewStream;
+}
+
+- (NPP_StreamAsFileProcPtr)NPP_StreamAsFile
+{
+ return NPP_StreamAsFile;
+}
+- (NPP_DestroyStreamProcPtr)NPP_DestroyStream
+{
+ return NPP_DestroyStream;
+}
+
+- (NPP_WriteReadyProcPtr)NPP_WriteReady
+{
+ return NPP_WriteReady;
+}
+- (NPP_WriteProcPtr)NPP_Write
+{
+ return NPP_Write;
+}
+
+- (NPP_HandleEventProcPtr)NPP_HandleEvent
+{
+ return NPP_HandleEvent;
+}
+
+-(NPP_URLNotifyProcPtr)NPP_URLNotify
+{
+ return NPP_URLNotify;
+}
+
+-(NPP_GetValueProcPtr)NPP_GetValue
+{
+ return NPP_GetValue;
+}
+
+-(NPP_SetValueProcPtr)NPP_SetValue
+{
+ return NPP_SetValue;
+}
+
+-(NPP_PrintProcPtr)NPP_Print
+{
+ return NPP_Print;
+}
+
+- (NPPluginFuncs *)pluginFuncs
+{
+ return &pluginFuncs;
+}
+
+- (void)wasRemovedFromPluginDatabase:(WebPluginDatabase *)database
+{
+ [super wasRemovedFromPluginDatabase:database];
+
+ // Unload when removed from final plug-in database
+ if ([pluginDatabases count] == 0)
+ [self _unloadWithShutdown:YES];
+}
+
+- (void)open
+{
+ instanceCount++;
+
+ // Handle the case where all instances close a plug-in package, but another
+ // instance opens the package before it is unloaded (which only happens when
+ // the plug-in database is refreshed)
+ needsUnload = NO;
+
+ if (!isLoaded) {
+ // Should load when the first instance opens the plug-in package
+ ASSERT(instanceCount == 1);
+ [self load];
+ }
+}
+
+- (void)close
+{
+ ASSERT(instanceCount > 0);
+ instanceCount--;
+ if (instanceCount == 0 && needsUnload)
+ [self _unloadWithShutdown:YES];
+}
+
+@end
+
+#ifdef SUPPORT_CFM
+
+// function pointer converters
+
+FunctionPointer functionPointerForTVector(TransitionVector tvp)
+{
+ const uint32 temp[6] = {0x3D800000, 0x618C0000, 0x800C0000, 0x804C0004, 0x7C0903A6, 0x4E800420};
+ uint32 *newGlue = NULL;
+
+ if (tvp != NULL) {
+ newGlue = (uint32 *)malloc(sizeof(temp));
+ if (newGlue != NULL) {
+ unsigned i;
+ for (i = 0; i < 6; i++) newGlue[i] = temp[i];
+ newGlue[0] |= ((uintptr_t)tvp >> 16);
+ newGlue[1] |= ((uintptr_t)tvp & 0xFFFF);
+ MakeDataExecutable(newGlue, sizeof(temp));
+ }
+ }
+
+ return (FunctionPointer)newGlue;
+}
+
+TransitionVector tVectorForFunctionPointer(FunctionPointer fp)
+{
+ FunctionPointer *newGlue = NULL;
+ if (fp != NULL) {
+ newGlue = (FunctionPointer *)malloc(2 * sizeof(FunctionPointer));
+ if (newGlue != NULL) {
+ newGlue[0] = fp;
+ newGlue[1] = NULL;
+ }
+ }
+ return (TransitionVector)newGlue;
+}
+
+#endif
+
+@implementation WebNetscapePluginPackage (Internal)
+
+- (void)_unloadWithShutdown:(BOOL)shutdown
+{
+ if (!isLoaded)
+ return;
+
+ LOG(Plugins, "Unloading %@...", name);
+
+ // Cannot unload a plug-in package while an instance is still using it
+ if (instanceCount > 0) {
+ needsUnload = YES;
+ return;
+ }
+
+ if (shutdown && NPP_Shutdown)
+ NPP_Shutdown();
+
+ if (resourceRef != -1)
+ [self closeResourceFile:resourceRef];
+
+#ifdef SUPPORT_CFM
+ if (isBundle)
+#endif
+ CFBundleUnloadExecutable(cfBundle);
+#ifdef SUPPORT_CFM
+ else
+ WebCloseConnection(&connID);
+#endif
+
+ LOG(Plugins, "Plugin Unloaded");
+ isLoaded = NO;
+}
+
+@end
+#endif
diff --git a/WebKit/mac/Plugins/WebNullPluginView.h b/WebKit/mac/Plugins/WebNullPluginView.h
new file mode 100644
index 0000000..3ca1532
--- /dev/null
+++ b/WebKit/mac/Plugins/WebNullPluginView.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2005, 2007 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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.
+ */
+
+#import <AppKit/AppKit.h>
+
+@class DOMElement;
+
+@interface WebNullPluginView : NSImageView
+{
+ NSError *error;
+ DOMElement *element;
+}
+
+- (id)initWithFrame:(NSRect)frame error:(NSError *)error DOMElement:(DOMElement *)element;
+
+@end
diff --git a/WebKit/mac/Plugins/WebNullPluginView.mm b/WebKit/mac/Plugins/WebNullPluginView.mm
new file mode 100644
index 0000000..48e0e9d
--- /dev/null
+++ b/WebKit/mac/Plugins/WebNullPluginView.mm
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2005, 2007 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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.
+ */
+
+#import "WebNullPluginView.h"
+
+#import "WebFrameInternal.h"
+#import "WebViewInternal.h"
+#import <WebCore/Document.h>
+
+@implementation WebNullPluginView
+
+- initWithFrame:(NSRect)frame error:(NSError *)err DOMElement:(DOMElement *)elem
+{
+ static NSImage *nullPlugInImage;
+ if (!nullPlugInImage) {
+ NSBundle *bundle = [NSBundle bundleForClass:[WebNullPluginView class]];
+ NSString *imagePath = [bundle pathForResource:@"nullplugin" ofType:@"tiff"];
+ nullPlugInImage = [[NSImage alloc] initWithContentsOfFile:imagePath];
+ }
+
+ self = [super initWithFrame:frame];
+ if (!self)
+ return nil;
+
+ error = [err retain];
+ if (err)
+ element = [elem retain];
+
+ [self setImage:nullPlugInImage];
+
+ return self;
+}
+
+- (void)dealloc
+
+{
+ [error release];
+ [element release];
+ [super dealloc];
+}
+
+- (void)reportFailure
+{
+ NSError *localError = error;
+ DOMElement *localElement = element;
+
+ error = nil;
+ element = nil;
+
+ WebFrame *webFrame = kit(core(localElement)->document()->frame());
+ if (webFrame) {
+ WebView *webView = [webFrame webView];
+ WebResourceDelegateImplementationCache* implementations = WebViewGetResourceLoadDelegateImplementations(webView);
+ if (implementations->plugInFailedWithErrorFunc)
+ CallResourceLoadDelegate(implementations->plugInFailedWithErrorFunc, webView,
+ @selector(webView:plugInFailedWithError:dataSource:), localError, [webFrame _dataSource]);
+ }
+
+ [localError release];
+ [localElement release];
+}
+
+- (void)viewDidMoveToWindow
+{
+ if (!error)
+ return;
+
+ if ([self window])
+ [self reportFailure];
+}
+
+@end
diff --git a/WebKit/mac/Plugins/WebPlugInStreamLoaderDelegate.h b/WebKit/mac/Plugins/WebPlugInStreamLoaderDelegate.h
new file mode 100644
index 0000000..c21fe4c
--- /dev/null
+++ b/WebKit/mac/Plugins/WebPlugInStreamLoaderDelegate.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2006 Apple Computer, 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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.
+ */
+
+@class NSURLResponse;
+@class NSError;
+@class NSData;
+
+@protocol WebPlugInStreamLoaderDelegate
+
+- (void)startStreamWithResponse:(NSURLResponse *)r;
+
+// destroyStreamWithError tells the plug-in that the load is completed (error == nil) or ended in error.
+- (void)destroyStreamWithError:(NSError *)error;
+
+// cancelLoadAndDestoryStreamWithError calls cancelLoadWithError: then destroyStreamWithError:.
+- (void)cancelLoadAndDestroyStreamWithError:(NSError *)error;
+
+- (void)receivedData:(NSData *)data;
+- (void)finishedLoading;
+
+- (BOOL)wantsAllStreams;
+
+@end
diff --git a/WebKit/mac/Plugins/WebPlugin.h b/WebKit/mac/Plugins/WebPlugin.h
new file mode 100644
index 0000000..bd0600e
--- /dev/null
+++ b/WebKit/mac/Plugins/WebPlugin.h
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2004 Apple Computer, 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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.
+ */
+
+#import <Cocoa/Cocoa.h>
+#import <JavaScriptCore/WebKitAvailability.h>
+
+/*!
+ WebPlugIn is an informal protocol that enables interaction between an application
+ and web related plug-ins it may contain.
+*/
+
+@interface NSObject (WebPlugIn)
+
+/*!
+ @method webPlugInInitialize
+ @abstract Tell the plug-in to perform one-time initialization.
+ @discussion This method must be only called once per instance of the plug-in
+ object and must be called before any other methods in this protocol.
+*/
+- (void)webPlugInInitialize;
+
+/*!
+ @method webPlugInStart
+ @abstract Tell the plug-in to start normal operation.
+ @discussion The plug-in usually begins drawing, playing sounds and/or
+ animation in this method. This method must be called before calling webPlugInStop.
+ This method may called more than once, provided that the application has
+ already called webPlugInInitialize and that each call to webPlugInStart is followed
+ by a call to webPlugInStop.
+*/
+- (void)webPlugInStart;
+
+/*!
+ @method webPlugInStop
+ @abstract Tell the plug-in to stop normal operation.
+ @discussion webPlugInStop must be called before this method. This method may be
+ called more than once, provided that the application has already called
+ webPlugInInitialize and that each call to webPlugInStop is preceded by a call to
+ webPlugInStart.
+*/
+- (void)webPlugInStop;
+
+/*!
+ @method webPlugInDestroy
+ @abstract Tell the plug-in perform cleanup and prepare to be deallocated.
+ @discussion The plug-in typically releases memory and other resources in this
+ method. If the plug-in has retained the WebPlugInContainer, it must release
+ it in this mehthod. This method must be only called once per instance of the
+ plug-in object. No other methods in this interface may be called after the
+ application has called webPlugInDestroy.
+*/
+- (void)webPlugInDestroy;
+
+/*!
+ @method webPlugInSetIsSelected:
+ @discusssion Informs the plug-in whether or not it is selected. This is typically
+ used to allow the plug-in to alter it's appearance when selected.
+*/
+- (void)webPlugInSetIsSelected:(BOOL)isSelected;
+
+/*!
+ @method objectForWebScript
+ @discussion objectForWebScript is used to expose a plug-in's scripting interface. The
+ methods of the object are exposed to the script environment. See the WebScripting
+ informal protocol for more details.
+ @result Returns the object that exposes the plug-in's interface. The class of this
+ object can implement methods from the WebScripting informal protocol.
+*/
+- (id)objectForWebScript;
+
+/*!
+ @method webPlugInMainResourceDidReceiveResponse:
+ @abstract Called on the plug-in when WebKit receives -connection:didReceiveResponse:
+ for the plug-in's main resource.
+ @discussion This method is only sent to the plug-in if the
+ WebPlugInShouldLoadMainResourceKey argument passed to the plug-in was NO.
+*/
+- (void)webPlugInMainResourceDidReceiveResponse:(NSURLResponse *)response WEBKIT_OBJC_METHOD_ANNOTATION(AVAILABLE_AFTER_WEBKIT_VERSION_3_1);
+
+/*!
+ @method webPlugInMainResourceDidReceiveData:
+ @abstract Called on the plug-in when WebKit recieves -connection:didReceiveData:
+ for the plug-in's main resource.
+ @discussion This method is only sent to the plug-in if the
+ WebPlugInShouldLoadMainResourceKey argument passed to the plug-in was NO.
+*/
+- (void)webPlugInMainResourceDidReceiveData:(NSData *)data WEBKIT_OBJC_METHOD_ANNOTATION(AVAILABLE_AFTER_WEBKIT_VERSION_3_1);
+
+/*!
+ @method webPlugInMainResourceDidFailWithError:
+ @abstract Called on the plug-in when WebKit receives -connection:didFailWithError:
+ for the plug-in's main resource.
+ @discussion This method is only sent to the plug-in if the
+ WebPlugInShouldLoadMainResourceKey argument passed to the plug-in was NO.
+*/
+- (void)webPlugInMainResourceDidFailWithError:(NSError *)error WEBKIT_OBJC_METHOD_ANNOTATION(AVAILABLE_AFTER_WEBKIT_VERSION_3_1);
+
+/*!
+ @method webPlugInMainResourceDidFinishLoading
+ @abstract Called on the plug-in when WebKit receives -connectionDidFinishLoading:
+ for the plug-in's main resource.
+ @discussion This method is only sent to the plug-in if the
+ WebPlugInShouldLoadMainResourceKey argument passed to the plug-in was NO.
+*/
+- (void)webPlugInMainResourceDidFinishLoading WEBKIT_OBJC_METHOD_ANNOTATION(AVAILABLE_AFTER_WEBKIT_VERSION_3_1);
+
+@end
diff --git a/WebKit/mac/Plugins/WebPluginContainer.h b/WebKit/mac/Plugins/WebPluginContainer.h
new file mode 100644
index 0000000..112b677
--- /dev/null
+++ b/WebKit/mac/Plugins/WebPluginContainer.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2004 Apple Computer, 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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.
+ */
+
+#import <Cocoa/Cocoa.h>
+
+/*!
+ This informal protocol enables a plug-in to request that its containing application
+ perform certain operations.
+*/
+
+@interface NSObject (WebPlugInContainer)
+
+/*!
+ @method webPlugInContainerLoadRequest:inFrame:
+ @abstract Tell the application to show a URL in a target frame
+ @param request The request to be loaded.
+ @param target The target frame. If the frame with the specified target is not
+ found, a new window is opened and the main frame of the new window is named
+ with the specified target. If nil is specified, the frame that contains
+ the applet is targeted.
+*/
+- (void)webPlugInContainerLoadRequest:(NSURLRequest *)request inFrame:(NSString *)target;
+
+/*!
+ @method webPlugInContainerShowStatus:
+ @abstract Tell the application to show the specified status message.
+ @param message The string to be shown.
+*/
+- (void)webPlugInContainerShowStatus:(NSString *)message;
+
+/*!
+ @method webPlugInContainerSelectionColor
+ @result Returns the color that should be used for any special drawing when
+ plug-in is selected.
+*/
+- (NSColor *)webPlugInContainerSelectionColor;
+
+/*!
+ @method webFrame
+ @discussion The webFrame method allows the plug-in to access the WebFrame that
+ contains the plug-in. This method will not be implemented by containers that
+ are not WebKit based.
+ @result Return the WebFrame that contains the plug-in.
+*/
+- (WebFrame *)webFrame;
+
+@end
diff --git a/WebKit/mac/Plugins/WebPluginContainerCheck.h b/WebKit/mac/Plugins/WebPluginContainerCheck.h
new file mode 100644
index 0000000..1b7bbda
--- /dev/null
+++ b/WebKit/mac/Plugins/WebPluginContainerCheck.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2005 Apple Computer, 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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.
+ */
+
+#import <Foundation/Foundation.h>
+
+@class NSURLRequest;
+@class NSString;
+@class WebPluginController;
+@class WebPolicyDecisionListener;
+
+@interface WebPluginContainerCheck : NSObject
+{
+ NSURLRequest *_request;
+ NSString *_target;
+ WebPluginController *_controller;
+ id _resultObject;
+ SEL _resultSelector;
+ BOOL _done;
+ WebPolicyDecisionListener *_listener;
+}
+
++ (id)checkWithRequest:(NSURLRequest *)request target:(NSString *)target resultObject:(id)obj selector:(SEL)selector controller:(WebPluginController *)controller;
+
+- (id)initWithRequest:(NSURLRequest *)request target:(NSString *)target resultObject:(id)obj selector:(SEL)selector controller:(WebPluginController *)controller;
+
+- (void)start;
+
+- (void)cancel;
+
+@end
diff --git a/WebKit/mac/Plugins/WebPluginContainerCheck.mm b/WebKit/mac/Plugins/WebPluginContainerCheck.mm
new file mode 100644
index 0000000..5c9ecd7
--- /dev/null
+++ b/WebKit/mac/Plugins/WebPluginContainerCheck.mm
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2005, 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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.
+ */
+
+#import "WebPluginContainerCheck.h"
+
+#import "WebFrameInternal.h"
+#import "WebPluginContainerPrivate.h"
+#import "WebPluginController.h"
+#import "WebPolicyDelegatePrivate.h"
+#import "WebView.h"
+#import "WebViewInternal.h"
+#import <Foundation/NSDictionary.h>
+#import <Foundation/NSURL.h>
+#import <Foundation/NSURLRequest.h>
+#import <WebCore/Frame.h>
+#import <WebCore/FrameLoader.h>
+#import <WebCore/FrameLoaderTypes.h>
+#import <wtf/Assertions.h>
+#import <objc/objc-runtime.h>
+
+using namespace WebCore;
+
+@implementation WebPluginContainerCheck
+
++ (id)checkWithRequest:(NSURLRequest *)request target:(NSString *)target resultObject:(id)obj selector:(SEL)selector controller:(WebPluginController *)controller
+{
+ return [[[self alloc] initWithRequest:request target:target resultObject:obj selector:selector controller:controller] autorelease];
+}
+
+- (id)initWithRequest:(NSURLRequest *)request target:(NSString *)target resultObject:(id)obj selector:(SEL)selector controller:(WebPluginController *)controller
+{
+ if (!(self = [super init]))
+ return nil;
+
+ _request = [request copy];
+ _target = [target copy];
+ _resultObject = [obj retain];
+ _resultSelector = selector;
+
+ // controller owns us so don't retain, to avoid cycle
+ _controller = controller;
+
+ return self;
+}
+
+- (void)finalize
+{
+ // mandatory to complete or cancel before releasing this object
+ ASSERT(_done);
+ [super finalize];
+}
+
+- (void)dealloc
+{
+ // mandatory to complete or cancel before releasing this object
+ ASSERT(_done);
+ [super dealloc];
+}
+
+- (void)_continueWithPolicy:(PolicyAction)policy
+{
+ ((void (*)(id, SEL, BOOL))objc_msgSend)(_resultObject, _resultSelector, (policy == PolicyUse));
+
+ // this will call indirectly call cancel
+ [_controller _webPluginContainerCancelCheckIfAllowedToLoadRequest:self];
+}
+
+- (BOOL)_isForbiddenFileLoad
+{
+ Frame* coreFrame = core([_controller webFrame]);
+ ASSERT(coreFrame);
+ if (!coreFrame->loader()->canLoad([_request URL], String(), coreFrame->document())) {
+ [self _continueWithPolicy:PolicyIgnore];
+ return YES;
+ }
+
+ return NO;
+}
+
+- (NSDictionary *)_actionInformationWithURL:(NSURL *)URL
+{
+ return [NSDictionary dictionaryWithObjectsAndKeys:
+ [NSNumber numberWithInt:WebNavigationTypePlugInRequest], WebActionNavigationTypeKey,
+ [NSNumber numberWithInt:0], WebActionModifierFlagsKey,
+ URL, WebActionOriginalURLKey,
+ nil];
+}
+
+- (void)_askPolicyDelegate
+{
+ WebView *webView = [_controller webView];
+
+ WebFrame *targetFrame;
+ if ([_target length] > 0) {
+ targetFrame = [[_controller webFrame] findFrameNamed:_target];
+ } else {
+ targetFrame = [_controller webFrame];
+ }
+
+ NSDictionary *action = [self _actionInformationWithURL:[_request URL]];
+
+ _listener = [[WebPolicyDecisionListener alloc] _initWithTarget:self action:@selector(_continueWithPolicy:)];
+
+ if (targetFrame == nil) {
+ // would open new window
+ [[webView _policyDelegateForwarder] webView:webView
+ decidePolicyForNewWindowAction:action
+ request:_request
+ newFrameName:_target
+ decisionListener:_listener];
+ } else {
+ // would target existing frame
+ [[webView _policyDelegateForwarder] webView:webView
+ decidePolicyForNavigationAction:action
+ request:_request
+ frame:targetFrame
+ decisionListener:_listener];
+ }
+}
+
+- (void)start
+{
+ ASSERT(!_listener);
+ ASSERT(!_done);
+
+ if ([self _isForbiddenFileLoad])
+ return;
+
+ [self _askPolicyDelegate];
+}
+
+- (void)cancel
+{
+ if (_done)
+ return;
+
+ [_request release];
+ _request = nil;
+
+ [_target release];
+ _target = nil;
+
+ [_listener _invalidate];
+ [_listener release];
+ _listener = nil;
+
+ [_resultObject autorelease];
+ _resultObject = nil;
+
+ _controller = nil;
+
+ _done = YES;
+}
+
+@end
diff --git a/WebKit/mac/Plugins/WebPluginContainerPrivate.h b/WebKit/mac/Plugins/WebPluginContainerPrivate.h
new file mode 100644
index 0000000..c9d64d5
--- /dev/null
+++ b/WebKit/mac/Plugins/WebPluginContainerPrivate.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2005 Apple Computer, 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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.
+ */
+
+#import <Cocoa/Cocoa.h>
+
+@interface NSObject (WebPlugInContainerPrivate)
+
+- (id)_webPluginContainerCheckIfAllowedToLoadRequest:(NSURLRequest *)Request inFrame:(NSString *)target resultObject:(id)obj selector:(SEL)selector;
+
+- (void)_webPluginContainerCancelCheckIfAllowedToLoadRequest:(id)checkIdentifier;
+
+@end
diff --git a/WebKit/mac/Plugins/WebPluginController.h b/WebKit/mac/Plugins/WebPluginController.h
new file mode 100644
index 0000000..58217c3
--- /dev/null
+++ b/WebKit/mac/Plugins/WebPluginController.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2005, 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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.
+ */
+
+#import <WebKit/WebBasePluginPackage.h>
+
+@class WebFrame;
+@class WebHTMLView;
+@class WebPluginPackage;
+@class WebView;
+@class WebDataSource;
+
+@interface WebPluginController : NSObject <WebPluginManualLoader>
+{
+ NSView *_documentView;
+ WebDataSource *_dataSource;
+ NSMutableArray *_views;
+ BOOL _started;
+ NSMutableSet *_checksInProgress;
+}
+
++ (NSView *)plugInViewWithArguments:(NSDictionary *)arguments fromPluginPackage:(WebPluginPackage *)plugin;
++ (BOOL)isPlugInView:(NSView *)view;
+
+- (id)initWithDocumentView:(NSView *)view;
+
+- (void)setDataSource:(WebDataSource *)dataSource;
+
+- (void)addPlugin:(NSView *)view;
+- (void)destroyPlugin:(NSView *)view;
+
+- (void)startAllPlugins;
+- (void)stopAllPlugins;
+- (void)destroyAllPlugins;
+
+- (WebFrame *)webFrame;
+- (WebView *)webView;
+
+- (NSString *)URLPolicyCheckReferrer;
+
+@end
diff --git a/WebKit/mac/Plugins/WebPluginController.mm b/WebKit/mac/Plugins/WebPluginController.mm
new file mode 100644
index 0000000..d892d4a
--- /dev/null
+++ b/WebKit/mac/Plugins/WebPluginController.mm
@@ -0,0 +1,433 @@
+/*
+ * Copyright (C) 2005, 2006 Apple Computer, 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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.
+ */
+
+
+#import <WebKit/WebPluginController.h>
+
+#import <Foundation/NSURLRequest.h>
+#import <runtime/JSLock.h>
+#import <WebCore/Frame.h>
+#import <WebCore/FrameLoader.h>
+#import <WebCore/ResourceRequest.h>
+#import <WebCore/PlatformString.h>
+#import <WebCore/DocumentLoader.h>
+#import <WebCore/ScriptController.h>
+#import <WebKit/WebDataSourceInternal.h>
+#import <WebKit/WebFrameInternal.h>
+#import <WebKit/WebFrameView.h>
+#import <WebKit/WebHTMLViewPrivate.h>
+#import <WebKit/WebKitErrorsPrivate.h>
+#import <WebKit/WebKitLogging.h>
+#import <WebKit/WebNSURLExtras.h>
+#import <WebKit/WebNSViewExtras.h>
+#import <WebKit/WebPlugin.h>
+#import <WebKit/WebPluginContainer.h>
+#import <WebKit/WebPluginContainerCheck.h>
+#import <WebKit/WebPluginPackage.h>
+#import <WebKit/WebPluginPrivate.h>
+#import <WebKit/WebPluginViewFactory.h>
+#import <WebKit/WebUIDelegate.h>
+#import <WebKit/WebViewInternal.h>
+
+using namespace WebCore;
+
+@interface NSView (PluginSecrets)
+- (void)setContainingWindow:(NSWindow *)w;
+@end
+
+// For compatibility only.
+@interface NSObject (OldPluginAPI)
++ (NSView *)pluginViewWithArguments:(NSDictionary *)arguments;
+@end
+
+@interface NSView (OldPluginAPI)
+- (void)pluginInitialize;
+- (void)pluginStart;
+- (void)pluginStop;
+- (void)pluginDestroy;
+@end
+
+static NSMutableSet *pluginViews = nil;
+
+@implementation WebPluginController
+
++ (NSView *)plugInViewWithArguments:(NSDictionary *)arguments fromPluginPackage:(WebPluginPackage *)pluginPackage
+{
+ [pluginPackage load];
+ Class viewFactory = [pluginPackage viewFactory];
+
+ NSView *view = nil;
+
+ if ([viewFactory respondsToSelector:@selector(plugInViewWithArguments:)]) {
+ JSC::JSLock::DropAllLocks dropAllLocks(false);
+ view = [viewFactory plugInViewWithArguments:arguments];
+ } else if ([viewFactory respondsToSelector:@selector(pluginViewWithArguments:)]) {
+ JSC::JSLock::DropAllLocks dropAllLocks(false);
+ view = [viewFactory pluginViewWithArguments:arguments];
+ }
+
+ if (view == nil) {
+ return nil;
+ }
+
+ if (pluginViews == nil) {
+ pluginViews = [[NSMutableSet alloc] init];
+ }
+ [pluginViews addObject:view];
+
+ return view;
+}
+
++ (BOOL)isPlugInView:(NSView *)view
+{
+ return [pluginViews containsObject:view];
+}
+
+- (id)initWithDocumentView:(NSView *)view
+{
+ [super init];
+ _documentView = view;
+ _views = [[NSMutableArray alloc] init];
+ _checksInProgress = (NSMutableSet *)CFMakeCollectable(CFSetCreateMutable(NULL, 0, NULL));
+ return self;
+}
+
+- (void)setDataSource:(WebDataSource *)dataSource
+{
+ _dataSource = dataSource;
+}
+
+- (void)dealloc
+{
+ [_views release];
+ [_checksInProgress release];
+ [super dealloc];
+}
+
+- (void)startAllPlugins
+{
+ if (_started)
+ return;
+
+ if ([_views count] > 0)
+ LOG(Plugins, "starting WebKit plugins : %@", [_views description]);
+
+ int i, count = [_views count];
+ for (i = 0; i < count; i++) {
+ id aView = [_views objectAtIndex:i];
+ if ([aView respondsToSelector:@selector(webPlugInStart)]) {
+ JSC::JSLock::DropAllLocks dropAllLocks(false);
+ [aView webPlugInStart];
+ } else if ([aView respondsToSelector:@selector(pluginStart)]) {
+ JSC::JSLock::DropAllLocks dropAllLocks(false);
+ [aView pluginStart];
+ }
+ }
+ _started = YES;
+}
+
+- (void)stopAllPlugins
+{
+ if (!_started)
+ return;
+
+ if ([_views count] > 0) {
+ LOG(Plugins, "stopping WebKit plugins: %@", [_views description]);
+ }
+
+ int i, count = [_views count];
+ for (i = 0; i < count; i++) {
+ id aView = [_views objectAtIndex:i];
+ if ([aView respondsToSelector:@selector(webPlugInStop)]) {
+ JSC::JSLock::DropAllLocks dropAllLocks(false);
+ [aView webPlugInStop];
+ } else if ([aView respondsToSelector:@selector(pluginStop)]) {
+ JSC::JSLock::DropAllLocks dropAllLocks(false);
+ [aView pluginStop];
+ }
+ }
+ _started = NO;
+}
+
+- (void)addPlugin:(NSView *)view
+{
+ if (!_documentView) {
+ LOG_ERROR("can't add a plug-in to a defunct WebPluginController");
+ return;
+ }
+
+ if (![_views containsObject:view]) {
+ [_views addObject:view];
+ [[_documentView _webView] addPluginInstanceView:view];
+
+ LOG(Plugins, "initializing plug-in %@", view);
+ if ([view respondsToSelector:@selector(webPlugInInitialize)]) {
+ JSC::JSLock::DropAllLocks dropAllLocks(false);
+ [view webPlugInInitialize];
+ } else if ([view respondsToSelector:@selector(pluginInitialize)]) {
+ JSC::JSLock::DropAllLocks dropAllLocks(false);
+ [view pluginInitialize];
+ }
+
+ if (_started) {
+ LOG(Plugins, "starting plug-in %@", view);
+ if ([view respondsToSelector:@selector(webPlugInStart)]) {
+ JSC::JSLock::DropAllLocks dropAllLocks(false);
+ [view webPlugInStart];
+ } else if ([view respondsToSelector:@selector(pluginStart)]) {
+ JSC::JSLock::DropAllLocks dropAllLocks(false);
+ [view pluginStart];
+ }
+
+ if ([view respondsToSelector:@selector(setContainingWindow:)]) {
+ JSC::JSLock::DropAllLocks dropAllLocks(false);
+ [view setContainingWindow:[_documentView window]];
+ }
+ }
+ }
+}
+
+- (void)destroyPlugin:(NSView *)view
+{
+ if ([_views containsObject:view]) {
+ if (_started) {
+ if ([view respondsToSelector:@selector(webPlugInStop)]) {
+ JSC::JSLock::DropAllLocks dropAllLocks(false);
+ [view webPlugInStop];
+ } else if ([view respondsToSelector:@selector(pluginStop)]) {
+ JSC::JSLock::DropAllLocks dropAllLocks(false);
+ [view pluginStop];
+ }
+ }
+
+ if ([view respondsToSelector:@selector(webPlugInDestroy)]) {
+ JSC::JSLock::DropAllLocks dropAllLocks(false);
+ [view webPlugInDestroy];
+ } else if ([view respondsToSelector:@selector(pluginDestroy)]) {
+ JSC::JSLock::DropAllLocks dropAllLocks(false);
+ [view pluginDestroy];
+ }
+
+ if (Frame* frame = core([self webFrame]))
+ frame->script()->cleanupScriptObjectsForPlugin(self);
+
+ [pluginViews removeObject:view];
+ [[_documentView _webView] removePluginInstanceView:view];
+ [_views removeObject:view];
+ }
+}
+
+- (void)_webPluginContainerCancelCheckIfAllowedToLoadRequest:(id)checkIdentifier
+{
+ [checkIdentifier cancel];
+ [_checksInProgress removeObject:checkIdentifier];
+}
+
+static void cancelOutstandingCheck(const void *item, void *context)
+{
+ [(id)item cancel];
+}
+
+- (void)_cancelOutstandingChecks
+{
+ if (_checksInProgress) {
+ CFSetApplyFunction((CFSetRef)_checksInProgress, cancelOutstandingCheck, NULL);
+ [_checksInProgress release];
+ _checksInProgress = nil;
+ }
+}
+
+- (void)destroyAllPlugins
+{
+ [self stopAllPlugins];
+
+ if ([_views count] > 0) {
+ LOG(Plugins, "destroying WebKit plugins: %@", [_views description]);
+ }
+
+ [self _cancelOutstandingChecks];
+
+ int i, count = [_views count];
+ for (i = 0; i < count; i++) {
+ id aView = [_views objectAtIndex:i];
+ if ([aView respondsToSelector:@selector(webPlugInDestroy)]) {
+ JSC::JSLock::DropAllLocks dropAllLocks(false);
+ [aView webPlugInDestroy];
+ } else if ([aView respondsToSelector:@selector(pluginDestroy)]) {
+ JSC::JSLock::DropAllLocks dropAllLocks(false);
+ [aView pluginDestroy];
+ }
+
+ if (Frame* frame = core([self webFrame]))
+ frame->script()->cleanupScriptObjectsForPlugin(self);
+
+ [pluginViews removeObject:aView];
+ [[_documentView _webView] removePluginInstanceView:aView];
+ }
+ [_views makeObjectsPerformSelector:@selector(removeFromSuperviewWithoutNeedingDisplay)];
+ [_views release];
+ _views = nil;
+
+ _documentView = nil;
+}
+
+- (id)_webPluginContainerCheckIfAllowedToLoadRequest:(NSURLRequest *)request inFrame:(NSString *)target resultObject:(id)obj selector:(SEL)selector
+{
+ WebPluginContainerCheck *check = [WebPluginContainerCheck checkWithRequest:request target:target resultObject:obj selector:selector controller:self];
+ [_checksInProgress addObject:check];
+ [check start];
+
+ return check;
+}
+
+- (void)webPlugInContainerLoadRequest:(NSURLRequest *)request inFrame:(NSString *)target
+{
+ if (!request) {
+ LOG_ERROR("nil URL passed");
+ return;
+ }
+ if (!_documentView) {
+ LOG_ERROR("could not load URL %@ because plug-in has already been destroyed", request);
+ return;
+ }
+ WebFrame *frame = [_dataSource webFrame];
+ if (!frame) {
+ LOG_ERROR("could not load URL %@ because plug-in has already been stopped", request);
+ return;
+ }
+ if (!target) {
+ target = @"_top";
+ }
+ NSString *JSString = [[request URL] _webkit_scriptIfJavaScriptURL];
+ if (JSString) {
+ if ([frame findFrameNamed:target] != frame) {
+ LOG_ERROR("JavaScript requests can only be made on the frame that contains the plug-in");
+ return;
+ }
+ [frame _stringByEvaluatingJavaScriptFromString:JSString];
+ } else {
+ if (!request) {
+ LOG_ERROR("could not load URL %@", [request URL]);
+ return;
+ }
+ core(frame)->loader()->load(request, target);
+ }
+}
+
+// For compatibility only.
+- (void)showURL:(NSURL *)URL inFrame:(NSString *)target
+{
+ [self webPlugInContainerLoadRequest:[NSURLRequest requestWithURL:URL] inFrame:target];
+}
+
+- (void)webPlugInContainerShowStatus:(NSString *)message
+{
+ if (!message) {
+ message = @"";
+ }
+ if (!_documentView) {
+ LOG_ERROR("could not show status message (%@) because plug-in has already been destroyed", message);
+ return;
+ }
+ WebView *v = [_dataSource _webView];
+ [[v _UIDelegateForwarder] webView:v setStatusText:message];
+}
+
+// For compatibility only.
+- (void)showStatus:(NSString *)message
+{
+ [self webPlugInContainerShowStatus:message];
+}
+
+- (NSColor *)webPlugInContainerSelectionColor
+{
+ bool primary = true;
+ if (Frame* frame = core([self webFrame]))
+ primary = frame->selection()->isFocusedAndActive();
+ return primary ? [NSColor selectedTextBackgroundColor] : [NSColor secondarySelectedControlColor];
+}
+
+// For compatibility only.
+- (NSColor *)selectionColor
+{
+ return [self webPlugInContainerSelectionColor];
+}
+
+- (WebFrame *)webFrame
+{
+ return [_dataSource webFrame];
+}
+
+- (WebView *)webView
+{
+ return [[self webFrame] webView];
+}
+
+- (NSString *)URLPolicyCheckReferrer
+{
+ NSURL *responseURL = [[[[self webFrame] _dataSource] response] URL];
+ ASSERT(responseURL);
+ return [responseURL _web_originalDataAsString];
+}
+
+- (void)pluginView:(NSView *)pluginView receivedResponse:(NSURLResponse *)response
+{
+ if ([pluginView respondsToSelector:@selector(webPlugInMainResourceDidReceiveResponse:)])
+ [pluginView webPlugInMainResourceDidReceiveResponse:response];
+ else {
+ // Cancel the load since this plug-in does its own loading.
+ // FIXME: See <rdar://problem/4258008> for a problem with this.
+ NSError *error = [[NSError alloc] _initWithPluginErrorCode:WebKitErrorPlugInWillHandleLoad
+ contentURL:[response URL]
+ pluginPageURL:nil
+ pluginName:nil // FIXME: Get this from somewhere
+ MIMEType:[response MIMEType]];
+ [_dataSource _documentLoader]->cancelMainResourceLoad(error);
+ [error release];
+ }
+}
+
+- (void)pluginView:(NSView *)pluginView receivedData:(NSData *)data
+{
+ if ([pluginView respondsToSelector:@selector(webPlugInMainResourceDidReceiveData:)])
+ [pluginView webPlugInMainResourceDidReceiveData:data];
+}
+
+- (void)pluginView:(NSView *)pluginView receivedError:(NSError *)error
+{
+ if ([pluginView respondsToSelector:@selector(webPlugInMainResourceDidFailWithError:)])
+ [pluginView webPlugInMainResourceDidFailWithError:error];
+}
+
+- (void)pluginViewFinishedLoading:(NSView *)pluginView
+{
+ if ([pluginView respondsToSelector:@selector(webPlugInMainResourceDidFinishLoading)])
+ [pluginView webPlugInMainResourceDidFinishLoading];
+}
+
+@end
diff --git a/WebKit/mac/Plugins/WebPluginDatabase.h b/WebKit/mac/Plugins/WebPluginDatabase.h
new file mode 100644
index 0000000..350f0a7
--- /dev/null
+++ b/WebKit/mac/Plugins/WebPluginDatabase.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2005 Apple Computer, 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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.
+ */
+
+#import <Foundation/Foundation.h>
+
+@class WebBasePluginPackage;
+@class WebFrame;
+
+@interface WebPluginDatabase : NSObject
+{
+ NSMutableDictionary *plugins;
+ NSMutableSet *registeredMIMETypes;
+ NSArray *plugInPaths;
+
+ // Set of views with plugins attached
+ NSMutableSet *pluginInstanceViews;
+}
+
++ (WebPluginDatabase *)sharedDatabase;
++ (void)closeSharedDatabase; // avoids creating the database just to close it
+
+// Plug-ins are returned in this order: New plug-in (WBPL), Mach-O Netscape, CFM Netscape
+- (WebBasePluginPackage *)pluginForMIMEType:(NSString *)mimeType;
+- (WebBasePluginPackage *)pluginForExtension:(NSString *)extension;
+
+- (BOOL)isMIMETypeRegistered:(NSString *)MIMEType;
+
+- (NSArray *)plugins;
+
+- (void)refresh;
+
+- (void)setPlugInPaths:(NSArray *)newPaths;
+
+- (void)close;
+
+- (void)addPluginInstanceView:(NSView *)view;
+- (void)removePluginInstanceView:(NSView *)view;
+- (void)removePluginInstanceViewsFor:(WebFrame *)webFrame;
+- (void)destroyAllPluginInstanceViews;
+@end
+
+@interface NSObject (WebPlugInDatabase)
+
++ (void)setAdditionalWebPlugInPaths:(NSArray *)path;
+
+@end
diff --git a/WebKit/mac/Plugins/WebPluginDatabase.mm b/WebKit/mac/Plugins/WebPluginDatabase.mm
new file mode 100644
index 0000000..531214e
--- /dev/null
+++ b/WebKit/mac/Plugins/WebPluginDatabase.mm
@@ -0,0 +1,456 @@
+/*
+ * Copyright (C) 2005 Apple Computer, 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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.
+ */
+
+#import "WebPluginDatabase.h"
+
+#import "WebBasePluginPackage.h"
+#import "WebDataSourcePrivate.h"
+#import "WebFrame.h"
+#import "WebFrameViewInternal.h"
+#import "WebHTMLRepresentation.h"
+#import "WebHTMLView.h"
+#import "WebKitLogging.h"
+#import "WebNetscapePluginPackage.h"
+#import "WebNSFileManagerExtras.h"
+#import "WebPluginController.h"
+#import "WebBaseNetscapePluginView.h"
+#import "WebPluginPackage.h"
+#import "WebViewPrivate.h"
+#import "WebHTMLView.h"
+#import <WebKitSystemInterface.h>
+#import <wtf/Assertions.h>
+
+static void checkCandidate(WebBasePluginPackage **currentPlugin, WebBasePluginPackage **candidatePlugin);
+
+@interface WebPluginDatabase (Internal)
++ (NSArray *)_defaultPlugInPaths;
+- (NSArray *)_plugInPaths;
+- (void)_addPlugin:(WebBasePluginPackage *)plugin;
+- (void)_removePlugin:(WebBasePluginPackage *)plugin;
+- (NSMutableSet *)_scanForNewPlugins;
+@end
+
+@implementation WebPluginDatabase
+
+static WebPluginDatabase *sharedDatabase = nil;
+
++ (WebPluginDatabase *)sharedDatabase
+{
+ if (!sharedDatabase) {
+ sharedDatabase = [[WebPluginDatabase alloc] init];
+ [sharedDatabase setPlugInPaths:[self _defaultPlugInPaths]];
+ [sharedDatabase refresh];
+ }
+
+ return sharedDatabase;
+}
+
++ (void)closeSharedDatabase
+{
+ [sharedDatabase close];
+}
+
+static void checkCandidate(WebBasePluginPackage **currentPlugin, WebBasePluginPackage **candidatePlugin)
+{
+ if (!*currentPlugin) {
+ *currentPlugin = *candidatePlugin;
+ return;
+ }
+
+ if ([[[*currentPlugin bundle] bundleIdentifier] isEqualToString:[[*candidatePlugin bundle] bundleIdentifier]] && [*candidatePlugin versionNumber] > [*currentPlugin versionNumber])
+ *currentPlugin = *candidatePlugin;
+}
+
+- (WebBasePluginPackage *)pluginForKey:(NSString *)key withEnumeratorSelector:(SEL)enumeratorSelector
+{
+ WebBasePluginPackage *plugin = nil;
+ WebBasePluginPackage *webPlugin = nil;
+#ifdef SUPPORT_CFM
+ WebBasePluginPackage *CFMPlugin = nil;
+#endif
+ WebBasePluginPackage *machoPlugin = nil;
+
+ NSEnumerator *pluginEnumerator = [plugins objectEnumerator];
+ key = [key lowercaseString];
+
+ while ((plugin = [pluginEnumerator nextObject]) != nil) {
+ if ([[[plugin performSelector:enumeratorSelector] allObjects] containsObject:key]) {
+ if ([plugin isKindOfClass:[WebPluginPackage class]])
+ checkCandidate(&webPlugin, &plugin);
+#if ENABLE(NETSCAPE_PLUGIN_API)
+ else if([plugin isKindOfClass:[WebNetscapePluginPackage class]]) {
+ WebExecutableType executableType = [(WebNetscapePluginPackage *)plugin executableType];
+#ifdef SUPPORT_CFM
+ if (executableType == WebCFMExecutableType) {
+ checkCandidate(&CFMPlugin, &plugin);
+ } else
+#endif // SUPPORT_CFM
+ if (executableType == WebMachOExecutableType) {
+ checkCandidate(&machoPlugin, &plugin);
+ } else {
+ ASSERT_NOT_REACHED();
+ }
+ } else {
+ ASSERT_NOT_REACHED();
+ }
+#endif
+ }
+ }
+
+ // Allow other plug-ins to win over QT because if the user has installed a plug-in that can handle a type
+ // that the QT plug-in can handle, they probably intended to override QT.
+ if (webPlugin && ![webPlugin isQuickTimePlugIn])
+ return webPlugin;
+
+ else if (machoPlugin && ![machoPlugin isQuickTimePlugIn])
+ return machoPlugin;
+#ifdef SUPPORT_CFM
+ else if (CFMPlugin && ![CFMPlugin isQuickTimePlugIn])
+ return CFMPlugin;
+#endif // SUPPORT_CFM
+ else if (webPlugin)
+ return webPlugin;
+ else if (machoPlugin)
+ return machoPlugin;
+#ifdef SUPPORT_CFM
+ else if (CFMPlugin)
+ return CFMPlugin;
+#endif
+ return nil;
+}
+
+- (WebBasePluginPackage *)pluginForMIMEType:(NSString *)MIMEType
+{
+ return [self pluginForKey:[MIMEType lowercaseString]
+ withEnumeratorSelector:@selector(MIMETypeEnumerator)];
+}
+
+- (WebBasePluginPackage *)pluginForExtension:(NSString *)extension
+{
+ WebBasePluginPackage *plugin = [self pluginForKey:[extension lowercaseString]
+ withEnumeratorSelector:@selector(extensionEnumerator)];
+ if (!plugin) {
+ // If no plug-in was found from the extension, attempt to map from the extension to a MIME type
+ // and find the a plug-in from the MIME type. This is done in case the plug-in has not fully specified
+ // an extension <-> MIME type mapping.
+ NSString *MIMEType = WKGetMIMETypeForExtension(extension);
+ if ([MIMEType length] > 0)
+ plugin = [self pluginForMIMEType:MIMEType];
+ }
+ return plugin;
+}
+
+- (NSArray *)plugins
+{
+ return [plugins allValues];
+}
+
+static NSArray *additionalWebPlugInPaths;
+
++ (void)setAdditionalWebPlugInPaths:(NSArray *)additionalPaths
+{
+ if (additionalPaths == additionalWebPlugInPaths)
+ return;
+
+ [additionalWebPlugInPaths release];
+ additionalWebPlugInPaths = [additionalPaths copy];
+
+ // One might be tempted to add additionalWebPlugInPaths to the global WebPluginDatabase here.
+ // For backward compatibility with earlier versions of the +setAdditionalWebPlugInPaths: SPI,
+ // we need to save a copy of the additional paths and not cause a refresh of the plugin DB
+ // at this time.
+ // See Radars 4608487 and 4609047.
+}
+
+- (void)setPlugInPaths:(NSArray *)newPaths
+{
+ if (plugInPaths == newPaths)
+ return;
+
+ [plugInPaths release];
+ plugInPaths = [newPaths copy];
+}
+
+- (void)close
+{
+ NSEnumerator *pluginEnumerator = [[self plugins] objectEnumerator];
+ WebBasePluginPackage *plugin;
+ while ((plugin = [pluginEnumerator nextObject]) != nil)
+ [self _removePlugin:plugin];
+ [plugins release];
+ plugins = nil;
+}
+
+- (id)init
+{
+ if (!(self = [super init]))
+ return nil;
+
+ registeredMIMETypes = [[NSMutableSet alloc] init];
+ pluginInstanceViews = [[NSMutableSet alloc] init];
+
+ return self;
+}
+
+- (void)dealloc
+{
+ [plugInPaths release];
+ [plugins release];
+ [registeredMIMETypes release];
+ [pluginInstanceViews release];
+
+ [super dealloc];
+}
+
+- (void)refresh
+{
+ // This method does a bit of autoreleasing, so create an autorelease pool to ensure that calling
+ // -refresh multiple times does not bloat the default pool.
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ // Create map from plug-in path to WebBasePluginPackage
+ if (!plugins)
+ plugins = [[NSMutableDictionary alloc] initWithCapacity:12];
+
+ // Find all plug-ins on disk
+ NSMutableSet *newPlugins = [self _scanForNewPlugins];
+
+ // Find plug-ins to remove from database (i.e., plug-ins that no longer exist on disk)
+ NSMutableSet *pluginsToRemove = [NSMutableSet set];
+ NSEnumerator *pluginEnumerator = [plugins objectEnumerator];
+ WebBasePluginPackage *plugin;
+ while ((plugin = [pluginEnumerator nextObject]) != nil) {
+ // Any plug-ins that were removed from disk since the last refresh should be removed from
+ // the database.
+ if (![newPlugins containsObject:plugin])
+ [pluginsToRemove addObject:plugin];
+
+ // Remove every member of 'plugins' from 'newPlugins'. After this loop exits, 'newPlugins'
+ // will be the set of new plug-ins that should be added to the database.
+ [newPlugins removeObject:plugin];
+ }
+
+#if !LOG_DISABLED
+ if ([newPlugins count] > 0)
+ LOG(Plugins, "New plugins:\n%@", newPlugins);
+ if ([pluginsToRemove count] > 0)
+ LOG(Plugins, "Removed plugins:\n%@", pluginsToRemove);
+#endif
+
+ // Remove plugins from database
+ pluginEnumerator = [pluginsToRemove objectEnumerator];
+ while ((plugin = [pluginEnumerator nextObject]) != nil)
+ [self _removePlugin:plugin];
+
+ // Add new plugins to database
+ pluginEnumerator = [newPlugins objectEnumerator];
+ while ((plugin = [pluginEnumerator nextObject]) != nil)
+ [self _addPlugin:plugin];
+
+ // Build a list of MIME types.
+ NSMutableSet *MIMETypes = [[NSMutableSet alloc] init];
+ pluginEnumerator = [plugins objectEnumerator];
+ while ((plugin = [pluginEnumerator nextObject]) != nil)
+ [MIMETypes addObjectsFromArray:[[plugin MIMETypeEnumerator] allObjects]];
+
+ // Register plug-in views and representations.
+ NSEnumerator *MIMEEnumerator = [MIMETypes objectEnumerator];
+ NSString *MIMEType;
+ while ((MIMEType = [MIMEEnumerator nextObject]) != nil) {
+ [registeredMIMETypes addObject:MIMEType];
+
+ if ([WebView canShowMIMETypeAsHTML:MIMEType])
+ // Don't allow plug-ins to override our core HTML types.
+ continue;
+ plugin = [self pluginForMIMEType:MIMEType];
+ if ([plugin isJavaPlugIn])
+ // Don't register the Java plug-in for a document view since Java files should be downloaded when not embedded.
+ continue;
+ if ([plugin isQuickTimePlugIn] && [[WebFrameView _viewTypesAllowImageTypeOmission:NO] objectForKey:MIMEType])
+ // Don't allow the QT plug-in to override any types because it claims many that we can handle ourselves.
+ continue;
+
+ if (self == sharedDatabase)
+ [WebView registerViewClass:[WebHTMLView class] representationClass:[WebHTMLRepresentation class] forMIMEType:MIMEType];
+ }
+ [MIMETypes release];
+
+ [pool drain];
+}
+
+- (BOOL)isMIMETypeRegistered:(NSString *)MIMEType
+{
+ return [registeredMIMETypes containsObject:MIMEType];
+}
+
+- (void)addPluginInstanceView:(NSView *)view
+{
+ [pluginInstanceViews addObject:view];
+}
+
+- (void)removePluginInstanceView:(NSView *)view
+{
+ [pluginInstanceViews removeObject:view];
+}
+
+- (void)removePluginInstanceViewsFor:(WebFrame*)webFrame
+{
+ // This handles handles the case where a frame or view is being destroyed and the plugin needs to be removed from the list first
+
+ if( [pluginInstanceViews count] == 0 )
+ return;
+
+ NSView <WebDocumentView> *documentView = [[webFrame frameView] documentView];
+ if ([documentView isKindOfClass:[WebHTMLView class]]) {
+ NSArray *subviews = [documentView subviews];
+ unsigned int subviewCount = [subviews count];
+ unsigned int subviewIndex;
+
+ for (subviewIndex = 0; subviewIndex < subviewCount; subviewIndex++) {
+ NSView *subview = [subviews objectAtIndex:subviewIndex];
+ if ([subview isKindOfClass:[WebBaseNetscapePluginView class]] || [WebPluginController isPlugInView:subview])
+ [pluginInstanceViews removeObject:subview];
+ }
+ }
+}
+
+- (void)destroyAllPluginInstanceViews
+{
+ NSView *view;
+ NSArray *pli = [pluginInstanceViews allObjects];
+ NSEnumerator *enumerator = [pli objectEnumerator];
+ while ((view = [enumerator nextObject]) != nil) {
+ if ([view isKindOfClass:[WebBaseNetscapePluginView class]]) {
+ ASSERT([view respondsToSelector:@selector(stop)]);
+ [view performSelector:@selector(stop)];
+ } else if ([WebPluginController isPlugInView:view]) {
+ ASSERT([[view superview] isKindOfClass:[WebHTMLView class]]);
+ ASSERT([[view superview] respondsToSelector:@selector(_destroyAllWebPlugins)]);
+ // this will actually destroy all plugin instances for a webHTMLView and remove them from this list
+ [[view superview] performSelector:@selector(_destroyAllWebPlugins)];
+ }
+ }
+}
+
+@end
+
+@implementation WebPluginDatabase (Internal)
+
++ (NSArray *)_defaultPlugInPaths
+{
+ // Plug-ins are found in order of precedence.
+ // If there are duplicates, the first found plug-in is used.
+ // For example, if there is a QuickTime.plugin in the users's home directory
+ // that is used instead of the /Library/Internet Plug-ins version.
+ // The purpose is to allow non-admin users to update their plug-ins.
+ return [NSArray arrayWithObjects:
+ [NSHomeDirectory() stringByAppendingPathComponent:@"Library/Internet Plug-Ins"],
+ @"/Library/Internet Plug-Ins",
+ [[NSBundle mainBundle] builtInPlugInsPath],
+ nil];
+}
+
+- (NSArray *)_plugInPaths
+{
+ if (self == sharedDatabase && additionalWebPlugInPaths) {
+ // Add additionalWebPlugInPaths to the global WebPluginDatabase. We do this here for
+ // backward compatibility with earlier versions of the +setAdditionalWebPlugInPaths: SPI,
+ // which simply saved a copy of the additional paths and did not cause the plugin DB to
+ // refresh. See Radars 4608487 and 4609047.
+ NSMutableArray *modifiedPlugInPaths = [[plugInPaths mutableCopy] autorelease];
+ [modifiedPlugInPaths addObjectsFromArray:additionalWebPlugInPaths];
+ return modifiedPlugInPaths;
+ } else
+ return plugInPaths;
+}
+
+- (void)_addPlugin:(WebBasePluginPackage *)plugin
+{
+ ASSERT(plugin);
+ NSString *pluginPath = [plugin path];
+ ASSERT(pluginPath);
+ [plugins setObject:plugin forKey:pluginPath];
+ [plugin wasAddedToPluginDatabase:self];
+}
+
+- (void)_removePlugin:(WebBasePluginPackage *)plugin
+{
+ ASSERT(plugin);
+
+ // Unregister plug-in's MIME type registrations
+ NSEnumerator *MIMETypeEnumerator = [plugin MIMETypeEnumerator];
+ NSString *MIMEType;
+ while ((MIMEType = [MIMETypeEnumerator nextObject])) {
+ if ([registeredMIMETypes containsObject:MIMEType]) {
+ if (self == sharedDatabase)
+ [WebView _unregisterViewClassAndRepresentationClassForMIMEType:MIMEType];
+ [registeredMIMETypes removeObject:MIMEType];
+ }
+ }
+
+ // Remove plug-in from database
+ NSString *pluginPath = [plugin path];
+ ASSERT(pluginPath);
+ [plugin retain];
+ [plugins removeObjectForKey:pluginPath];
+ [plugin wasRemovedFromPluginDatabase:self];
+ [plugin release];
+}
+
+- (NSMutableSet *)_scanForNewPlugins
+{
+ NSMutableSet *newPlugins = [NSMutableSet set];
+ NSEnumerator *directoryEnumerator = [[self _plugInPaths] objectEnumerator];
+ NSMutableSet *uniqueFilenames = [[NSMutableSet alloc] init];
+ NSFileManager *fileManager = [NSFileManager defaultManager];
+ NSString *pluginDirectory;
+ while ((pluginDirectory = [directoryEnumerator nextObject]) != nil) {
+ // Get contents of each plug-in directory
+ NSEnumerator *filenameEnumerator = [[fileManager contentsOfDirectoryAtPath:pluginDirectory error:NULL] objectEnumerator];
+ NSString *filename;
+ while ((filename = [filenameEnumerator nextObject]) != nil) {
+ // Unique plug-ins by filename
+ if ([uniqueFilenames containsObject:filename])
+ continue;
+ [uniqueFilenames addObject:filename];
+
+ // Create a plug-in package for this path
+ NSString *pluginPath = [pluginDirectory stringByAppendingPathComponent:filename];
+ WebBasePluginPackage *pluginPackage = [plugins objectForKey:pluginPath];
+ if (!pluginPackage)
+ pluginPackage = [WebBasePluginPackage pluginWithPath:pluginPath];
+ if (pluginPackage)
+ [newPlugins addObject:pluginPackage];
+ }
+ }
+ [uniqueFilenames release];
+
+ return newPlugins;
+}
+
+@end
diff --git a/WebKit/mac/Plugins/WebPluginPackage.h b/WebKit/mac/Plugins/WebPluginPackage.h
new file mode 100644
index 0000000..290bb1b
--- /dev/null
+++ b/WebKit/mac/Plugins/WebPluginPackage.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2005 Apple Computer, 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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.
+ */
+
+#import <Foundation/Foundation.h>
+
+#import <WebKit/WebBasePluginPackage.h>
+
+@protocol WebPluginViewFactory;
+
+@interface WebPluginPackage : WebBasePluginPackage
+
+- (Class)viewFactory;
+
+@end
diff --git a/WebKit/mac/Plugins/WebPluginPackage.m b/WebKit/mac/Plugins/WebPluginPackage.m
new file mode 100644
index 0000000..d7f144e
--- /dev/null
+++ b/WebKit/mac/Plugins/WebPluginPackage.m
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2005 Apple Computer, 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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.
+ */
+
+#import <WebKit/WebPluginPackage.h>
+
+#import <WebKit/WebKitLogging.h>
+#import <WebKit/WebKitNSStringExtras.h>
+
+NSString *WebPlugInBaseURLKey = @"WebPlugInBaseURLKey";
+NSString *WebPlugInAttributesKey = @"WebPlugInAttributesKey";
+NSString *WebPlugInContainerKey = @"WebPlugInContainerKey";
+NSString *WebPlugInModeKey = @"WebPlugInModeKey";
+NSString *WebPlugInShouldLoadMainResourceKey = @"WebPlugInShouldLoadMainResourceKey";
+NSString *WebPlugInContainingElementKey = @"WebPlugInContainingElementKey";
+
+@implementation WebPluginPackage
+
+- initWithPath:(NSString *)pluginPath
+{
+ if (!(self = [super initWithPath:pluginPath]))
+ return nil;
+
+ if (bundle == nil) {
+ [self release];
+ return nil;
+ }
+
+ if (![[pluginPath pathExtension] _webkit_isCaseInsensitiveEqualToString:@"webplugin"]) {
+ UInt32 type = 0;
+ CFBundleGetPackageInfo(cfBundle, &type, NULL);
+ if (type != FOUR_CHAR_CODE('WBPL')) {
+ [self release];
+ return nil;
+ }
+ }
+
+ NSFileHandle *executableFile = [NSFileHandle fileHandleForReadingAtPath:[bundle executablePath]];
+ NSData *data = [executableFile readDataOfLength:512];
+ [executableFile closeFile];
+ if (![self isNativeLibraryData:data]) {
+ [self release];
+ return nil;
+ }
+
+ if (![self getPluginInfoFromPLists]) {
+ [self release];
+ return nil;
+ }
+
+ return self;
+}
+
+- (Class)viewFactory
+{
+ return [bundle principalClass];
+}
+
+- (BOOL)load
+{
+#if !LOG_DISABLED
+ CFAbsoluteTime start = CFAbsoluteTimeGetCurrent();
+#endif
+
+ // Load the bundle
+ if (![bundle isLoaded]) {
+ if (![bundle load])
+ return NO;
+ }
+
+#if !LOG_DISABLED
+ CFAbsoluteTime duration = CFAbsoluteTimeGetCurrent() - start;
+ LOG(Plugins, "principalClass took %f seconds for: %@", duration, [self name]);
+#endif
+ return [super load];
+}
+
+@end
+
+@implementation NSObject (WebScripting)
+
++ (BOOL)isSelectorExcludedFromWebScript:(SEL)aSelector
+{
+ return YES;
+}
+
++ (BOOL)isKeyExcludedFromWebScript:(const char *)name
+{
+ return YES;
+}
+
+@end
diff --git a/WebKit/mac/Plugins/WebPluginPrivate.h b/WebKit/mac/Plugins/WebPluginPrivate.h
new file mode 100644
index 0000000..56e4a3a
--- /dev/null
+++ b/WebKit/mac/Plugins/WebPluginPrivate.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2004 Apple Computer, 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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.
+ */
+
+@interface NSObject (WebPlugInPrivate)
+
+@end
diff --git a/WebKit/mac/Plugins/WebPluginViewFactory.h b/WebKit/mac/Plugins/WebPluginViewFactory.h
new file mode 100644
index 0000000..583a73d
--- /dev/null
+++ b/WebKit/mac/Plugins/WebPluginViewFactory.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2004 Apple Computer, 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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.
+ */
+
+#import <Cocoa/Cocoa.h>
+#import <JavaScriptCore/WebKitAvailability.h>
+
+/*!
+ @constant WebPlugInBaseURLKey REQUIRED. The base URL of the document containing
+ the plug-in's view.
+*/
+extern NSString *WebPlugInBaseURLKey;
+
+/*!
+ @constant WebPlugInAttributesKey REQUIRED. The dictionary containing the names
+ and values of all attributes of the HTML element associated with the plug-in AND
+ the names and values of all parameters to be passed to the plug-in (e.g. PARAM
+ elements within an APPLET element). In the case of a conflict between names,
+ the attributes of an element take precedence over any PARAMs. All of the keys
+ and values in this NSDictionary must be NSStrings.
+*/
+extern NSString *WebPlugInAttributesKey;
+
+/*!
+ @constant WebPlugInContainer OPTIONAL. An object that conforms to the
+ WebPlugInContainer informal protocol. This object is used for
+ callbacks from the plug-in to the app. if this argument is nil, no callbacks will
+ occur.
+*/
+extern NSString *WebPlugInContainerKey;
+
+/*!
+ @constant WebPlugInContainingElementKey The DOMElement that was used to specify
+ the plug-in. May be nil.
+*/
+extern NSString *WebPlugInContainingElementKey;
+
+/*!
+ @constant WebPlugInShouldLoadMainResourceKey REQUIRED. NSNumber (BOOL) indicating whether the plug-in should load its
+ own main resource (the "src" URL, in most cases). If YES, the plug-in should load its own main resource. If NO, the
+ plug-in should use the data provided by WebKit. See -webPlugInMainResourceReceivedData: in WebPluginPrivate.h.
+ For compatibility with older versions of WebKit, the plug-in should assume that the value for
+ WebPlugInShouldLoadMainResourceKey is NO if it is absent from the arguments dictionary.
+ */
+extern NSString *WebPlugInShouldLoadMainResourceKey AVAILABLE_AFTER_WEBKIT_VERSION_3_1;
+
+/*!
+ @protocol WebPlugInViewFactory
+ @discussion WebPlugInViewFactory are used to create the NSView for a plug-in.
+ The principal class of the plug-in bundle must implement this protocol.
+*/
+
+@protocol WebPlugInViewFactory <NSObject>
+
+/*!
+ @method plugInViewWithArguments:
+ @param arguments The arguments dictionary with the mentioned keys and objects. This method is required to implement.
+ @result Returns an NSView object that conforms to the WebPlugIn informal protocol.
+*/
++ (NSView *)plugInViewWithArguments:(NSDictionary *)arguments;
+
+@end
diff --git a/WebKit/mac/Plugins/WebPluginViewFactoryPrivate.h b/WebKit/mac/Plugins/WebPluginViewFactoryPrivate.h
new file mode 100644
index 0000000..51d4283
--- /dev/null
+++ b/WebKit/mac/Plugins/WebPluginViewFactoryPrivate.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2005 Apple Computer, 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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.
+ */
+
+#import <WebKit/WebPluginViewFactory.h>
+
+typedef enum {
+ WebPlugInModeEmbed = 0,
+ WebPlugInModeFull = 1
+} WebPlugInMode;
+
+/*!
+ @constant WebPlugInModeKey REQUIRED. Number with one of the values from the WebPlugInMode enum.
+*/
+extern NSString *WebPlugInModeKey;
diff --git a/WebKit/mac/Plugins/WebPluginsPrivate.h b/WebKit/mac/Plugins/WebPluginsPrivate.h
new file mode 100644
index 0000000..fc0067d
--- /dev/null
+++ b/WebKit/mac/Plugins/WebPluginsPrivate.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2005 Apple Computer, 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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.
+ */
+
+// WebPluginWillPresentNativeUserInterfaceNotification is sent by plugins to notify the WebKit client
+// application that the plugin will present a dialog or some other "native" user interface to the user.
+// This is currently only needed by Dashboard, which must hide itself when a plugin presents a dialog
+// box (4318632).
+extern NSString *WebPluginWillPresentNativeUserInterfaceNotification;
diff --git a/WebKit/mac/Plugins/WebPluginsPrivate.m b/WebKit/mac/Plugins/WebPluginsPrivate.m
new file mode 100644
index 0000000..79896b6
--- /dev/null
+++ b/WebKit/mac/Plugins/WebPluginsPrivate.m
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2005 Apple Computer, 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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 "WebPluginsPrivate.h"
+
+NSString *WebPluginWillPresentNativeUserInterfaceNotification = @"WebPluginWillPresentNativeUserInterface";
diff --git a/WebKit/mac/Plugins/npapi.mm b/WebKit/mac/Plugins/npapi.mm
new file mode 100644
index 0000000..f85ec9f
--- /dev/null
+++ b/WebKit/mac/Plugins/npapi.mm
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2005 Apple Computer, 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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 ENABLE(NETSCAPE_PLUGIN_API)
+#import <WebKit/npapi.h>
+#import <WebKit/nptextinput.h>
+
+#import "WebBaseNetscapePluginView.h"
+#import "WebKitLogging.h"
+#import <WebCore/PluginMainThreadScheduler.h>
+
+using namespace WebCore;
+
+WebBaseNetscapePluginView *pluginViewForInstance(NPP instance);
+
+// general plug-in to browser functions
+
+void* NPN_MemAlloc(uint32 size)
+{
+ return malloc(size);
+}
+
+void NPN_MemFree(void* ptr)
+{
+ free(ptr);
+}
+
+uint32 NPN_MemFlush(uint32 size)
+{
+ LOG(Plugins, "NPN_MemFlush");
+ return size;
+}
+
+void NPN_ReloadPlugins(NPBool reloadPages)
+{
+ LOG(Plugins, "NPN_ReloadPlugins");
+}
+
+NPError NPN_RequestRead(NPStream* stream, NPByteRange* rangeList)
+{
+ LOG(Plugins, "NPN_RequestRead");
+ return NPERR_GENERIC_ERROR;
+}
+
+// instance-specific functions
+// The plugin view is always the ndata of the instance. Sometimes, plug-ins will call an instance-specific function
+// with a NULL instance. To workaround this, call the last plug-in view that made a call to a plug-in.
+// Currently, the current plug-in view is only set before NPP_New in [WebBaseNetscapePluginView start].
+// This specifically works around Flash and Shockwave. When we call NPP_New, they call NPN_UserAgent with a NULL instance.
+WebBaseNetscapePluginView *pluginViewForInstance(NPP instance)
+{
+ if (instance && instance->ndata)
+ return (WebBaseNetscapePluginView *)instance->ndata;
+ else
+ return [WebBaseNetscapePluginView currentPluginView];
+}
+
+NPError NPN_GetURLNotify(NPP instance, const char* URL, const char* target, void* notifyData)
+{
+ return [pluginViewForInstance(instance) getURLNotify:URL target:target notifyData:notifyData];
+}
+
+NPError NPN_GetURL(NPP instance, const char* URL, const char* target)
+{
+ return [pluginViewForInstance(instance) getURL:URL target:target];
+}
+
+NPError NPN_PostURLNotify(NPP instance, const char* URL, const char* target, uint32 len, const char* buf, NPBool file, void* notifyData)
+{
+ return [pluginViewForInstance(instance) postURLNotify:URL target:target len:len buf:buf file:file notifyData:notifyData];
+}
+
+NPError NPN_PostURL(NPP instance, const char* URL, const char* target, uint32 len, const char* buf, NPBool file)
+{
+ return [pluginViewForInstance(instance) postURL:URL target:target len:len buf:buf file:file];
+}
+
+NPError NPN_NewStream(NPP instance, NPMIMEType type, const char* target, NPStream** stream)
+{
+ return [pluginViewForInstance(instance) newStream:type target:target stream:stream];
+}
+
+int32 NPN_Write(NPP instance, NPStream* stream, int32 len, void* buffer)
+{
+ return [pluginViewForInstance(instance) write:stream len:len buffer:buffer];
+}
+
+NPError NPN_DestroyStream(NPP instance, NPStream* stream, NPReason reason)
+{
+ return [pluginViewForInstance(instance) destroyStream:stream reason:reason];
+}
+
+const char* NPN_UserAgent(NPP instance)
+{
+ return [pluginViewForInstance(instance) userAgent];
+}
+
+void NPN_Status(NPP instance, const char* message)
+{
+ [pluginViewForInstance(instance) status:message];
+}
+
+void NPN_InvalidateRect(NPP instance, NPRect *invalidRect)
+{
+ [pluginViewForInstance(instance) invalidateRect:invalidRect];
+}
+
+void NPN_InvalidateRegion(NPP instance, NPRegion invalidRegion)
+{
+ [pluginViewForInstance(instance) invalidateRegion:invalidRegion];
+}
+
+void NPN_ForceRedraw(NPP instance)
+{
+ [pluginViewForInstance(instance) forceRedraw];
+}
+
+NPError NPN_GetValue(NPP instance, NPNVariable variable, void *value)
+{
+ return [pluginViewForInstance(instance) getVariable:variable value:value];
+}
+
+NPError NPN_SetValue(NPP instance, NPPVariable variable, void *value)
+{
+ return [pluginViewForInstance(instance) setVariable:variable value:value];
+}
+
+// Unsupported functions
+
+void* NPN_GetJavaEnv(void)
+{
+ LOG(Plugins, "NPN_GetJavaEnv");
+ return NULL;
+}
+
+void* NPN_GetJavaPeer(NPP instance)
+{
+ LOG(Plugins, "NPN_GetJavaPeer");
+ return NULL;
+}
+
+void NPN_PushPopupsEnabledState(NPP instance, NPBool enabled)
+{
+}
+
+void NPN_PopPopupsEnabledState(NPP instance)
+{
+}
+
+void NPN_PluginThreadAsyncCall(NPP instance, void (*func) (void *), void *userData)
+{
+ PluginMainThreadScheduler::scheduler().scheduleCall(instance, func, userData);
+}
+
+uint32 NPN_ScheduleTimer(NPP instance, uint32 interval, NPBool repeat, void (*timerFunc)(NPP npp, uint32 timerID))
+{
+ return [pluginViewForInstance(instance) scheduleTimerWithInterval:interval repeat:repeat timerFunc:timerFunc];
+}
+
+void NPN_UnscheduleTimer(NPP instance, uint32 timerID)
+{
+ [pluginViewForInstance(instance) unscheduleTimer:timerID];
+}
+
+NPError NPN_PopUpContextMenu(NPP instance, NPMenu *menu)
+{
+ return [pluginViewForInstance(instance) popUpContextMenu:menu];
+}
+
+void NPN_MarkedTextAbandoned(NPP instance)
+{
+ WebBaseNetscapePluginView *pluginView = pluginViewForInstance(instance);
+
+ [[NSInputManager currentInputManager] markedTextAbandoned:pluginView];
+}
+
+void NPN_MarkedTextSelectionChanged(NPP instance, NSRange newSel)
+{
+ WebBaseNetscapePluginView *pluginView = pluginViewForInstance(instance);
+
+ [[NSInputManager currentInputManager] markedTextSelectionChanged:newSel client:pluginView];
+}
+
+#endif
diff --git a/WebKit/mac/Plugins/nptextinput.h b/WebKit/mac/Plugins/nptextinput.h
new file mode 100644
index 0000000..2ed3146
--- /dev/null
+++ b/WebKit/mac/Plugins/nptextinput.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2008, Apple Inc. and The Mozilla Foundation.
+ * 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.
+ * 3. Neither the names of Apple Inc. ("Apple") or The Mozilla
+ * Foundation ("Mozilla") nor the names of their contributors may be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE, MOZILLA AND THEIR CONTRIBUTORS "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, MOZILLA OR
+ * THEIR 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 __OBJC__
+#error "npinput.h can only be included from Objective-C code."
+#endif
+
+#ifndef _NP_TEXTINPUT_H_
+#define _NP_TEXTINPUT_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <WebKit/npapi.h>
+
+#import <Cocoa/Cocoa.h>
+
+typedef void (*NPP_InsertTextFunc)(NPP npp, id aString);
+typedef void (*NPP_DoCommandBySelectorFunc)(NPP npp, SEL aSelector);
+typedef void (*NPP_SetMarkedTextFunc)(NPP npp, id aString, NSRange selRange);
+typedef void (*NPP_UnmarkTextFunc)(NPP npp);
+typedef BOOL (*NPP_HasMarkedTextFunc)(NPP npp);
+typedef NSAttributedString * (*NPP_AttributedSubstringFromRangeFunc)(NPP npp, NSRange theRange);
+typedef NSRange (*NPP_MarkedRangeFunc)(NPP npp);
+typedef NSRange (*NPP_SelectedRangeFunc)(NPP npp);
+typedef NSRect (*NPP_FirstRectForCharacterRangeFunc)(NPP npp, NSRange theRange);
+typedef unsigned long long (*NPP_CharacterIndexForPointFunc)(NPP npp, NSPoint thePoint);
+typedef NSArray *(*NPP_ValidAttributesForMarkedTextFunc)(NPP npp);
+
+typedef struct _NPPluginTextInputFuncs {
+ uint16 size;
+ uint16 version;
+
+ NPP_InsertTextFunc insertText;
+ NPP_DoCommandBySelectorFunc doCommandBySelector;
+ NPP_SetMarkedTextFunc setMarkedText;
+ NPP_UnmarkTextFunc unmarkText;
+ NPP_HasMarkedTextFunc hasMarkedText;
+ NPP_AttributedSubstringFromRangeFunc attributedSubstringFromRange;
+ NPP_MarkedRangeFunc markedRange;
+ NPP_SelectedRangeFunc selectedRange;
+ NPP_FirstRectForCharacterRangeFunc firstRectForCharacterRange;
+ NPP_CharacterIndexForPointFunc characterIndexForPoint;
+ NPP_ValidAttributesForMarkedTextFunc validAttributesForMarkedText;
+} NPPluginTextInputFuncs;
+
+void NPP_InsertText(NPP npp, id aString);
+void NPP_DoCommandBySelector(NPP npp, SEL aSelector);
+void NPP_SetMarkedText(NPP npp, id aString, NSRange selRange);
+void NPP_UnmarkText(NPP npp);
+BOOL NPP_HasMarkedText(NPP npp);
+NSAttributedString *NPP_AttributedSubstringFromRange(NPP npp, NSRange theRange);
+NSRange NPP_MarkedRange(NPP npp);
+NSRange NPP_SelectedRange(NPP npp);
+NSRect NPP_FirstRectForCharacterRange(NPP npp, NSRange theRange);
+unsigned long long NPP_CharacterIndexForPoint(NPP npp, NSPoint thePoint);
+NSArray *NPP_ValidAttributesForMarkedText(NPP npp);
+
+typedef void (*NPN_MarkedTextAbandonedFunc)(NPP npp);
+typedef void (*NPN_MarkedTextSelectionChangedFunc)(NPP npp, NSRange newSel);
+
+typedef struct _NPBrowserTextInputFuncs {
+ uint16 size;
+ uint16 version;
+
+ NPN_MarkedTextAbandonedFunc markedTextAbandoned;
+ NPN_MarkedTextSelectionChangedFunc markedTextSelectionChanged;
+} NPBrowserTextInputFuncs;
+
+void NPN_MarkedTextAbandoned(NPP npp);
+void NPN_MarkedTextSelectionChanged(NPP npp, NSRange newSel);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif