summaryrefslogtreecommitdiffstats
path: root/Source/WebKit/mac/Plugins/Hosted/WebHostedNetscapePluginView.mm
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebKit/mac/Plugins/Hosted/WebHostedNetscapePluginView.mm')
-rw-r--r--Source/WebKit/mac/Plugins/Hosted/WebHostedNetscapePluginView.mm534
1 files changed, 534 insertions, 0 deletions
diff --git a/Source/WebKit/mac/Plugins/Hosted/WebHostedNetscapePluginView.mm b/Source/WebKit/mac/Plugins/Hosted/WebHostedNetscapePluginView.mm
new file mode 100644
index 0000000..d3cce46
--- /dev/null
+++ b/Source/WebKit/mac/Plugins/Hosted/WebHostedNetscapePluginView.mm
@@ -0,0 +1,534 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if USE(PLUGIN_HOST_PROCESS) && ENABLE(NETSCAPE_PLUGIN_API)
+
+#import "WebHostedNetscapePluginView.h"
+
+#import "HostedNetscapePluginStream.h"
+#import "NetscapePluginInstanceProxy.h"
+#import "NetscapePluginHostManager.h"
+#import "NetscapePluginHostProxy.h"
+#import "WebTextInputWindowController.h"
+#import "WebFrameInternal.h"
+#import "WebView.h"
+#import "WebViewInternal.h"
+#import "WebUIDelegate.h"
+
+#import <CoreFoundation/CoreFoundation.h>
+#import <WebCore/BridgeJSC.h>
+#import <WebCore/Frame.h>
+#import <WebCore/FrameLoaderTypes.h>
+#import <WebCore/FrameView.h>
+#import <WebCore/HTMLPlugInElement.h>
+#import <WebCore/RenderEmbeddedObject.h>
+#import <WebCore/WebCoreObjCExtras.h>
+#import <WebCore/runtime_root.h>
+#import <runtime/InitializeThreading.h>
+#import <wtf/Assertions.h>
+#import <wtf/Threading.h>
+
+using namespace WebCore;
+using namespace WebKit;
+
+extern "C" {
+#include "WebKitPluginClientServer.h"
+#include "WebKitPluginHost.h"
+}
+
+@implementation WebHostedNetscapePluginView
+
++ (void)initialize
+{
+ JSC::initializeThreading();
+ WTF::initializeMainThreadToProcessMainThread();
+#ifndef BUILDING_ON_TIGER
+ WebCoreObjCFinalizeOnMainThread(self);
+#endif
+ WKSendUserChangeNotifications();
+}
+
+- (id)initWithFrame:(NSRect)frame
+ pluginPackage:(WebNetscapePluginPackage *)pluginPackage
+ URL:(NSURL *)URL
+ baseURL:(NSURL *)baseURL
+ MIMEType:(NSString *)MIME
+ attributeKeys:(NSArray *)keys
+ attributeValues:(NSArray *)values
+ loadManually:(BOOL)loadManually
+ element:(PassRefPtr<WebCore::HTMLPlugInElement>)element
+{
+ self = [super initWithFrame:frame pluginPackage:pluginPackage URL:URL baseURL:baseURL MIMEType:MIME attributeKeys:keys attributeValues:values loadManually:loadManually element:element];
+ if (!self)
+ return nil;
+
+ return self;
+}
+
+- (void)handleMouseMoved:(NSEvent *)event
+{
+ if (_isStarted && _proxy)
+ _proxy->mouseEvent(self, event, NPCocoaEventMouseMoved);
+}
+
+- (void)setAttributeKeys:(NSArray *)keys andValues:(NSArray *)values
+{
+ ASSERT(!_attributeKeys);
+ ASSERT(!_attributeValues);
+
+ _attributeKeys.adoptNS([keys copy]);
+ _attributeValues.adoptNS([values copy]);
+}
+
+- (BOOL)createPlugin
+{
+ ASSERT(!_proxy);
+
+ NSString *userAgent = [[self webView] userAgentForURL:_baseURL.get()];
+ BOOL accleratedCompositingEnabled = false;
+#if USE(ACCELERATED_COMPOSITING)
+ accleratedCompositingEnabled = [[[self webView] preferences] acceleratedCompositingEnabled];
+#endif
+
+ _proxy = NetscapePluginHostManager::shared().instantiatePlugin([_pluginPackage.get() path], [_pluginPackage.get() pluginHostArchitecture], [_pluginPackage.get() bundleIdentifier], self, _MIMEType.get(), _attributeKeys.get(), _attributeValues.get(), userAgent, _sourceURL.get(),
+ _mode == NP_FULL, _isPrivateBrowsingEnabled, accleratedCompositingEnabled);
+ if (!_proxy)
+ return NO;
+
+ if (_proxy->rendererType() == UseSoftwareRenderer)
+ _softwareRenderer = WKSoftwareCARendererCreate(_proxy->renderContextID());
+ else {
+ _pluginLayer = WKMakeRenderLayer(_proxy->renderContextID());
+
+ if (accleratedCompositingEnabled && _proxy->rendererType() == UseAcceleratedCompositing) {
+ // FIXME: This code can be shared between WebHostedNetscapePluginView and WebNetscapePluginView.
+#ifndef BUILDING_ON_LEOPARD
+ // Since this layer isn't going to be inserted into a view, we need to create another layer and flip its geometry
+ // in order to get the coordinate system right.
+ RetainPtr<CALayer> realPluginLayer(AdoptNS, _pluginLayer.releaseRef());
+
+ _pluginLayer.adoptNS([[CALayer alloc] init]);
+ _pluginLayer.get().bounds = realPluginLayer.get().bounds;
+ _pluginLayer.get().geometryFlipped = YES;
+
+ realPluginLayer.get().autoresizingMask = kCALayerWidthSizable | kCALayerHeightSizable;
+ [_pluginLayer.get() addSublayer:realPluginLayer.get()];
+#endif
+
+ // Eagerly enter compositing mode, since we know we'll need it. This avoids firing setNeedsStyleRecalc()
+ // for iframes that contain composited plugins at bad times. https://bugs.webkit.org/show_bug.cgi?id=39033
+ core([self webFrame])->view()->enterCompositingMode();
+ [self element]->setNeedsStyleRecalc(SyntheticStyleChange);
+ } else
+ self.wantsLayer = YES;
+ }
+
+ // Update the window frame.
+ _proxy->windowFrameChanged([[self window] frame]);
+
+ return YES;
+}
+
+// FIXME: This method is an ideal candidate to move up to the base class
+- (CALayer *)pluginLayer
+{
+ return _pluginLayer.get();
+}
+
+- (void)setLayer:(CALayer *)newLayer
+{
+ // FIXME: This should use the same implementation as WebNetscapePluginView (and move to the base class).
+ [super setLayer:newLayer];
+
+ if (_pluginLayer)
+ [newLayer addSublayer:_pluginLayer.get()];
+}
+
+- (void)privateBrowsingModeDidChange
+{
+ if (_proxy)
+ _proxy->privateBrowsingModeDidChange(_isPrivateBrowsingEnabled);
+}
+
+- (void)loadStream
+{
+}
+
+- (void)updateAndSetWindow
+{
+ if (!_proxy)
+ return;
+
+ // The base coordinates of a window and it's contentView happen to be the equal at a userSpaceScaleFactor
+ // of 1. For non-1.0 scale factors this assumption is false.
+ NSView *windowContentView = [[self window] contentView];
+ NSRect boundsInWindow = [self convertRect:[self bounds] toView:windowContentView];
+
+ NSRect visibleRectInWindow;
+
+ // Core Animation plug-ins need to be updated (with a 0,0,0,0 clipRect) when
+ // moved to a background tab. We don't do this for Core Graphics plug-ins as
+ // older versions of Flash have historical WebKit-specific code that isn't
+ // compatible with this behavior.
+ BOOL shouldClipOutPlugin = _pluginLayer && [self shouldClipOutPlugin];
+ if (!shouldClipOutPlugin)
+ visibleRectInWindow = [self actualVisibleRectInWindow];
+ else
+ visibleRectInWindow = NSZeroRect;
+
+ // Flip Y to convert NSWindow coordinates to top-left-based window coordinates.
+ float borderViewHeight = [[self currentWindow] frame].size.height;
+ boundsInWindow.origin.y = borderViewHeight - NSMaxY(boundsInWindow);
+
+ if (!shouldClipOutPlugin)
+ visibleRectInWindow.origin.y = borderViewHeight - NSMaxY(visibleRectInWindow);
+
+ _previousSize = boundsInWindow.size;
+
+ _proxy->resize(boundsInWindow, visibleRectInWindow);
+
+ CGRect bounds = NSRectToCGRect([self bounds]);
+ CGRect frame = NSRectToCGRect([self frame]);
+
+ // We're not scaled, or in a subframe
+ CATransform3D scaleTransform = CATransform3DIdentity;
+ if (CGSizeEqualToSize(bounds.size, frame.size)) {
+ // We're in a subframe. Backing store is boundsInWindow.size.
+ if (boundsInWindow.size.width && boundsInWindow.size.height)
+ scaleTransform = CATransform3DMakeScale(frame.size.width / boundsInWindow.size.width, frame.size.height / boundsInWindow.size.height, 1);
+ } else {
+ // We're in the main frame with scaling. Need to mimic the frame/bounds scaling on Widgets.
+ if (frame.size.width && frame.size.height)
+ scaleTransform = CATransform3DMakeScale(bounds.size.width / frame.size.width, bounds.size.height / frame.size.height, 1);
+ }
+
+ _pluginLayer.get().sublayerTransform = scaleTransform;
+}
+
+- (void)windowFocusChanged:(BOOL)hasFocus
+{
+ if (_proxy)
+ _proxy->windowFocusChanged(hasFocus);
+}
+
+- (BOOL)shouldStop
+{
+ if (!_proxy)
+ return YES;
+
+ return _proxy->shouldStop();
+}
+
+- (void)destroyPlugin
+{
+ if (_proxy) {
+ if (_softwareRenderer) {
+ WKSoftwareCARendererDestroy(_softwareRenderer);
+ _softwareRenderer = 0;
+ }
+
+ _proxy->destroy();
+ _proxy = 0;
+ }
+
+ _pluginLayer = 0;
+}
+
+- (void)startTimers
+{
+ if (_proxy)
+ _proxy->startTimers(_isCompletelyObscured);
+}
+
+- (void)stopTimers
+{
+ if (_proxy)
+ _proxy->stopTimers();
+}
+
+- (void)focusChanged
+{
+ if (_proxy)
+ _proxy->focusChanged(_hasFocus);
+}
+
+- (void)windowFrameDidChange:(NSNotification *)notification
+{
+ if (_proxy && [self window])
+ _proxy->windowFrameChanged([[self window] frame]);
+}
+
+- (void)addWindowObservers
+{
+ [super addWindowObservers];
+
+ ASSERT([self window]);
+
+ NSWindow *window = [self window];
+
+ NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
+ [notificationCenter addObserver:self selector:@selector(windowFrameDidChange:)
+ name:NSWindowDidMoveNotification object:window];
+ [notificationCenter addObserver:self selector:@selector(windowFrameDidChange:)
+ name:NSWindowDidResizeNotification object:window];
+
+ if (_proxy)
+ _proxy->windowFrameChanged([window frame]);
+ [self updateAndSetWindow];
+}
+
+- (void)removeWindowObservers
+{
+ [super removeWindowObservers];
+
+ NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
+ [notificationCenter removeObserver:self name:NSWindowDidMoveNotification object:nil];
+ [notificationCenter removeObserver:self name:NSWindowDidResizeNotification object:nil];
+}
+
+- (void)mouseDown:(NSEvent *)event
+{
+ if (_isStarted && _proxy)
+ _proxy->mouseEvent(self, event, NPCocoaEventMouseDown);
+}
+
+- (void)mouseUp:(NSEvent *)event
+{
+ if (_isStarted && _proxy)
+ _proxy->mouseEvent(self, event, NPCocoaEventMouseUp);
+}
+
+- (void)mouseDragged:(NSEvent *)event
+{
+ if (_isStarted && _proxy)
+ _proxy->mouseEvent(self, event, NPCocoaEventMouseDragged);
+}
+
+- (void)handleMouseEntered:(NSEvent *)event
+{
+ // Set cursor to arrow. Plugins often handle cursor internally, but those that don't will just get this default one.
+ [[NSCursor arrowCursor] set];
+
+ if (_isStarted && _proxy)
+ _proxy->mouseEvent(self, event, NPCocoaEventMouseEntered);
+}
+
+- (void)handleMouseExited:(NSEvent *)event
+{
+ if (_isStarted && _proxy)
+ _proxy->mouseEvent(self, event, NPCocoaEventMouseExited);
+
+ // Set cursor back to arrow cursor. Because NSCursor doesn't know about changes that the plugin made, we could get confused about what we think the
+ // current cursor is otherwise. Therefore we have no choice but to unconditionally reset the cursor when the mouse exits the plugin.
+ // FIXME: This should be job of plugin host, see <rdar://problem/7654434>.
+ [[NSCursor arrowCursor] set];
+}
+
+- (void)scrollWheel:(NSEvent *)event
+{
+ bool processedEvent = false;
+
+ if (_isStarted && _proxy)
+ processedEvent = _proxy->wheelEvent(self, event);
+
+ if (!processedEvent)
+ [super scrollWheel:event];
+}
+
+- (NSTextInputContext *)inputContext
+{
+ return [[WebTextInputWindowController sharedTextInputWindowController] inputContext];
+}
+
+- (void)keyDown:(NSEvent *)event
+{
+ if (!_isStarted || !_proxy)
+ return;
+
+ NSString *string = nil;
+ if ([[WebTextInputWindowController sharedTextInputWindowController] interpretKeyEvent:event string:&string]) {
+ if (string)
+ _proxy->insertText(string);
+ return;
+ }
+
+ _proxy->keyEvent(self, event, NPCocoaEventKeyDown);
+}
+
+- (void)keyUp:(NSEvent *)event
+{
+ if (_isStarted && _proxy)
+ _proxy->keyEvent(self, event, NPCocoaEventKeyUp);
+}
+
+- (void)flagsChanged:(NSEvent *)event
+{
+ if (_isStarted && _proxy)
+ _proxy->flagsChanged(event);
+}
+
+- (void)sendModifierEventWithKeyCode:(int)keyCode character:(char)character
+{
+ if (_isStarted && _proxy)
+ _proxy->syntheticKeyDownWithCommandModifier(keyCode, character);
+}
+
+- (void)pluginHostDied
+{
+ if (_element->renderer() && _element->renderer()->isEmbeddedObject()) {
+ // FIXME: The renderer could also be a RenderApplet, we should handle that.
+ RenderEmbeddedObject* renderer = toRenderEmbeddedObject(_element->renderer());
+ renderer->setShowsCrashedPluginIndicator();
+ }
+
+ _pluginLayer = nil;
+ _proxy = 0;
+
+ // No need for us to be layer backed anymore
+ self.wantsLayer = NO;
+
+ [self invalidatePluginContentRect:[self bounds]];
+}
+
+- (void)visibleRectDidChange
+{
+ [super visibleRectDidChange];
+ WKSyncSurfaceToView(self);
+}
+
+- (void)drawRect:(NSRect)rect
+{
+ if (_cachedSnapshot) {
+ NSRect sourceRect = { NSZeroPoint, [_cachedSnapshot.get() size] };
+ [_cachedSnapshot.get() drawInRect:[self bounds] fromRect:sourceRect operation:NSCompositeSourceOver fraction:1];
+ return;
+ }
+
+ if (_proxy) {
+ if (_softwareRenderer) {
+ if ([NSGraphicsContext currentContextDrawingToScreen]) {
+ WKSoftwareCARendererRender(_softwareRenderer, (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort], NSRectToCGRect(rect));
+ _proxy->didDraw();
+ } else
+ _proxy->print(reinterpret_cast<CGContextRef>([[NSGraphicsContext currentContext] graphicsPort]), [self bounds].size.width, [self bounds].size.height);
+ } else if (_snapshotting && [self supportsSnapshotting]) {
+ _proxy->snapshot(reinterpret_cast<CGContextRef>([[NSGraphicsContext currentContext] graphicsPort]), [self bounds].size.width, [self bounds].size.height);
+ }
+
+ return;
+ }
+}
+
+- (PassRefPtr<JSC::Bindings::Instance>)createPluginBindingsInstance:(PassRefPtr<JSC::Bindings::RootObject>)rootObject
+{
+ if (!_proxy)
+ return 0;
+
+ return _proxy->createBindingsInstance(rootObject);
+}
+
+- (void)pluginView:(NSView *)pluginView receivedResponse:(NSURLResponse *)response
+{
+ ASSERT(_loadManually);
+ if (!_proxy)
+ return;
+
+ ASSERT(!_proxy->manualStream());
+
+ _proxy->setManualStream(HostedNetscapePluginStream::create(_proxy.get(), core([self webFrame])->loader()));
+ _proxy->manualStream()->startStreamWithResponse(response);
+}
+
+- (void)pluginView:(NSView *)pluginView receivedData:(NSData *)data
+{
+ ASSERT(_loadManually);
+ if (!_proxy)
+ return;
+
+ if (HostedNetscapePluginStream* manualStream = _proxy->manualStream())
+ manualStream->didReceiveData(0, static_cast<const char*>([data bytes]), [data length]);
+}
+
+- (void)pluginView:(NSView *)pluginView receivedError:(NSError *)error
+{
+ ASSERT(_loadManually);
+ if (!_proxy)
+ return;
+
+ if (HostedNetscapePluginStream* manualStream = _proxy->manualStream())
+ manualStream->didFail(0, error);
+}
+
+- (void)pluginViewFinishedLoading:(NSView *)pluginView
+{
+ ASSERT(_loadManually);
+ if (!_proxy)
+ return;
+
+ if (HostedNetscapePluginStream* manualStream = _proxy->manualStream())
+ manualStream->didFinishLoading(0);
+}
+
+- (void)_webPluginContainerCancelCheckIfAllowedToLoadRequest:(id)webPluginContainerCheck
+{
+ ASSERT([webPluginContainerCheck isKindOfClass:[WebPluginContainerCheck class]]);
+
+ id contextInfo = [webPluginContainerCheck contextInfo];
+ ASSERT([contextInfo isKindOfClass:[NSNumber class]]);
+
+ if (!_proxy)
+ return;
+
+ uint32_t checkID = [(NSNumber *)contextInfo unsignedIntValue];
+ _proxy->cancelCheckIfAllowedToLoadURL(checkID);
+}
+
+- (void)_containerCheckResult:(PolicyAction)policy contextInfo:(id)contextInfo
+{
+ ASSERT([contextInfo isKindOfClass:[NSNumber class]]);
+ if (!_proxy)
+ return;
+
+ uint32_t checkID = [(NSNumber *)contextInfo unsignedIntValue];
+ _proxy->checkIfAllowedToLoadURLResult(checkID, (policy == PolicyUse));
+}
+
+- (void)webFrame:(WebFrame *)webFrame didFinishLoadWithReason:(NPReason)reason
+{
+ if (_isStarted && _proxy)
+ _proxy->webFrameDidFinishLoadWithReason(webFrame, reason);
+}
+
+- (void)webFrame:(WebFrame *)webFrame didFinishLoadWithError:(NSError *)error
+{
+ NPReason reason = NPRES_DONE;
+ if (error)
+ reason = HostedNetscapePluginStream::reasonForError(error);
+ [self webFrame:webFrame didFinishLoadWithReason:reason];
+}
+
+@end
+
+#endif // USE(PLUGIN_HOST_PROCESS) && ENABLE(NETSCAPE_PLUGIN_API)