1/* 2 * Copyright (C) 2008 Apple Inc. All Rights Reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25#if USE(PLUGIN_HOST_PROCESS) 26 27#import "WebHostedNetscapePluginView.h" 28 29#import "HostedNetscapePluginStream.h" 30#import "NetscapePluginInstanceProxy.h" 31#import "NetscapePluginHostManager.h" 32#import "NetscapePluginHostProxy.h" 33#import "WebTextInputWindowController.h" 34#import "WebFrameInternal.h" 35#import "WebView.h" 36#import "WebViewInternal.h" 37#import "WebUIDelegate.h" 38 39#import <CoreFoundation/CoreFoundation.h> 40#import <WebCore/Bridge.h> 41#import <WebCore/Frame.h> 42#import <WebCore/FrameLoaderTypes.h> 43#import <WebCore/HTMLPlugInElement.h> 44#import <WebCore/runtime_root.h> 45#import <WebCore/WebCoreObjCExtras.h> 46#import <runtime/InitializeThreading.h> 47#import <wtf/Assertions.h> 48 49using namespace WebCore; 50using namespace WebKit; 51 52extern "C" { 53#include "WebKitPluginClientServer.h" 54#include "WebKitPluginHost.h" 55} 56 57@implementation WebHostedNetscapePluginView 58 59+ (void)initialize 60{ 61 JSC::initializeThreading(); 62#ifndef BUILDING_ON_TIGER 63 WebCoreObjCFinalizeOnMainThread(self); 64#endif 65 WKSendUserChangeNotifications(); 66} 67 68- (id)initWithFrame:(NSRect)frame 69 pluginPackage:(WebNetscapePluginPackage *)pluginPackage 70 URL:(NSURL *)URL 71 baseURL:(NSURL *)baseURL 72 MIMEType:(NSString *)MIME 73 attributeKeys:(NSArray *)keys 74 attributeValues:(NSArray *)values 75 loadManually:(BOOL)loadManually 76 element:(PassRefPtr<WebCore::HTMLPlugInElement>)element 77{ 78 self = [super initWithFrame:frame pluginPackage:pluginPackage URL:URL baseURL:baseURL MIMEType:MIME attributeKeys:keys attributeValues:values loadManually:loadManually element:element]; 79 if (!self) 80 return nil; 81 82 return self; 83} 84 85- (void)handleMouseMoved:(NSEvent *)event 86{ 87 if (_isStarted && _proxy) 88 _proxy->mouseEvent(self, event, NPCocoaEventMouseMoved); 89} 90 91- (void)setAttributeKeys:(NSArray *)keys andValues:(NSArray *)values 92{ 93 ASSERT(!_attributeKeys); 94 ASSERT(!_attributeValues); 95 96 _attributeKeys.adoptNS([keys copy]); 97 _attributeValues.adoptNS([values copy]); 98} 99 100- (BOOL)createPlugin 101{ 102 ASSERT(!_proxy); 103 104 NSString *userAgent = [[self webView] userAgentForURL:_baseURL.get()]; 105 BOOL accleratedCompositingEnabled = false; 106#if USE(ACCELERATED_COMPOSITING) 107 accleratedCompositingEnabled = [[[self webView] preferences] acceleratedCompositingEnabled]; 108#endif 109 110 _proxy = NetscapePluginHostManager::shared().instantiatePlugin(_pluginPackage.get(), self, _MIMEType.get(), _attributeKeys.get(), _attributeValues.get(), userAgent, _sourceURL.get(), 111 _mode == NP_FULL, _isPrivateBrowsingEnabled, accleratedCompositingEnabled); 112 if (!_proxy) 113 return NO; 114 115 if (_proxy->useSoftwareRenderer()) 116 _softwareRenderer = WKSoftwareCARendererCreate(_proxy->renderContextID()); 117 else { 118 _pluginLayer = WKMakeRenderLayer(_proxy->renderContextID()); 119 120 if (accleratedCompositingEnabled) 121 [self element]->setNeedsStyleRecalc(SyntheticStyleChange); 122 else 123 self.wantsLayer = YES; 124 } 125 126 // Update the window frame. 127 _proxy->windowFrameChanged([[self window] frame]); 128 129 return YES; 130} 131 132// FIXME: This method is an ideal candidate to move up to the base class 133- (CALayer *)pluginLayer 134{ 135 return _pluginLayer.get(); 136} 137 138- (void)setLayer:(CALayer *)newLayer 139{ 140 // FIXME: This should use the same implementation as WebNetscapePluginView (and move to the base class). 141 [super setLayer:newLayer]; 142 143 if (_pluginLayer) 144 [newLayer addSublayer:_pluginLayer.get()]; 145} 146 147- (void)privateBrowsingModeDidChange 148{ 149 if (_proxy) 150 _proxy->privateBrowsingModeDidChange(_isPrivateBrowsingEnabled); 151} 152 153- (void)loadStream 154{ 155} 156 157- (void)updateAndSetWindow 158{ 159 if (!_proxy) 160 return; 161 162 // Use AppKit to convert view coordinates to NSWindow coordinates. 163 NSRect boundsInWindow = [self convertRect:[self bounds] toView:nil]; 164 NSRect visibleRectInWindow; 165 166 // Core Animation plug-ins need to be updated (with a 0,0,0,0 clipRect) when 167 // moved to a background tab. We don't do this for Core Graphics plug-ins as 168 // older versions of Flash have historical WebKit-specific code that isn't 169 // compatible with this behavior. 170 BOOL shouldClipOutPlugin = _pluginLayer && [self shouldClipOutPlugin]; 171 if (!shouldClipOutPlugin) 172 visibleRectInWindow = [self convertRect:[self visibleRect] toView:nil]; 173 else 174 visibleRectInWindow = NSZeroRect; 175 176 // Flip Y to convert NSWindow coordinates to top-left-based window coordinates. 177 float borderViewHeight = [[self currentWindow] frame].size.height; 178 boundsInWindow.origin.y = borderViewHeight - NSMaxY(boundsInWindow); 179 180 if (!shouldClipOutPlugin) 181 visibleRectInWindow.origin.y = borderViewHeight - NSMaxY(visibleRectInWindow); 182 183 BOOL sizeChanged = !NSEqualSizes(_previousSize, boundsInWindow.size); 184 _previousSize = boundsInWindow.size; 185 186 _proxy->resize(boundsInWindow, visibleRectInWindow, sizeChanged); 187} 188 189- (void)windowFocusChanged:(BOOL)hasFocus 190{ 191 if (_proxy) 192 _proxy->windowFocusChanged(hasFocus); 193} 194 195- (BOOL)shouldStop 196{ 197 if (!_proxy) 198 return YES; 199 200 return _proxy->shouldStop(); 201} 202 203- (void)destroyPlugin 204{ 205 if (_proxy) { 206 if (_softwareRenderer) { 207 WKSoftwareCARendererDestroy(_softwareRenderer); 208 _softwareRenderer = 0; 209 } 210 211 _proxy->destroy(); 212 _proxy = 0; 213 } 214 215 _pluginLayer = 0; 216} 217 218- (void)startTimers 219{ 220 if (_proxy) 221 _proxy->startTimers(_isCompletelyObscured); 222} 223 224- (void)stopTimers 225{ 226 if (_proxy) 227 _proxy->stopTimers(); 228} 229 230- (void)focusChanged 231{ 232 if (_proxy) 233 _proxy->focusChanged(_hasFocus); 234} 235 236- (void)windowFrameDidChange:(NSNotification *)notification 237{ 238 if (_proxy && [self window]) 239 _proxy->windowFrameChanged([[self window] frame]); 240} 241 242- (void)addWindowObservers 243{ 244 [super addWindowObservers]; 245 246 ASSERT([self window]); 247 248 NSWindow *window = [self window]; 249 250 NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; 251 [notificationCenter addObserver:self selector:@selector(windowFrameDidChange:) 252 name:NSWindowDidMoveNotification object:window]; 253 [notificationCenter addObserver:self selector:@selector(windowFrameDidChange:) 254 name:NSWindowDidResizeNotification object:window]; 255 256 if (_proxy) 257 _proxy->windowFrameChanged([window frame]); 258 [self updateAndSetWindow]; 259} 260 261- (void)removeWindowObservers 262{ 263 [super removeWindowObservers]; 264 265 NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; 266 [notificationCenter removeObserver:self name:NSWindowDidMoveNotification object:nil]; 267 [notificationCenter removeObserver:self name:NSWindowDidResizeNotification object:nil]; 268} 269 270- (void)mouseDown:(NSEvent *)event 271{ 272 if (_isStarted && _proxy) 273 _proxy->mouseEvent(self, event, NPCocoaEventMouseDown); 274} 275 276- (void)mouseUp:(NSEvent *)event 277{ 278 if (_isStarted && _proxy) 279 _proxy->mouseEvent(self, event, NPCocoaEventMouseUp); 280} 281 282- (void)mouseDragged:(NSEvent *)event 283{ 284 if (_isStarted && _proxy) 285 _proxy->mouseEvent(self, event, NPCocoaEventMouseDragged); 286} 287 288- (void)mouseEntered:(NSEvent *)event 289{ 290 if (_isStarted && _proxy) 291 _proxy->mouseEvent(self, event, NPCocoaEventMouseEntered); 292} 293 294- (void)mouseExited:(NSEvent *)event 295{ 296 if (_isStarted && _proxy) 297 _proxy->mouseEvent(self, event, NPCocoaEventMouseExited); 298} 299 300- (void)scrollWheel:(NSEvent *)event 301{ 302 bool processedEvent = false; 303 304 if (_isStarted && _proxy) 305 processedEvent = _proxy->wheelEvent(self, event); 306 307 if (!processedEvent) 308 [super scrollWheel:event]; 309} 310 311- (NSTextInputContext *)inputContext 312{ 313 return [[WebTextInputWindowController sharedTextInputWindowController] inputContext]; 314} 315 316- (void)keyDown:(NSEvent *)event 317{ 318 if (!_isStarted || !_proxy) 319 return; 320 321 NSString *string = nil; 322 if ([[WebTextInputWindowController sharedTextInputWindowController] interpretKeyEvent:event string:&string]) { 323 if (string) 324 _proxy->insertText(string); 325 return; 326 } 327 328 _proxy->keyEvent(self, event, NPCocoaEventKeyDown); 329} 330 331- (void)keyUp:(NSEvent *)event 332{ 333 if (_isStarted && _proxy) 334 _proxy->keyEvent(self, event, NPCocoaEventKeyUp); 335} 336 337- (void)flagsChanged:(NSEvent *)event 338{ 339 if (_isStarted && _proxy) 340 _proxy->flagsChanged(event); 341} 342 343- (void)sendModifierEventWithKeyCode:(int)keyCode character:(char)character 344{ 345 if (_isStarted && _proxy) 346 _proxy->syntheticKeyDownWithCommandModifier(keyCode, character); 347} 348 349- (void)pluginHostDied 350{ 351 _pluginHostDied = YES; 352 353 _pluginLayer = nil; 354 _proxy = 0; 355 356 // No need for us to be layer backed anymore 357 self.wantsLayer = NO; 358 359 [self invalidatePluginContentRect:[self bounds]]; 360} 361 362 363- (void)drawRect:(NSRect)rect 364{ 365 if (_proxy) { 366 if (_softwareRenderer) { 367 if ([NSGraphicsContext currentContextDrawingToScreen]) { 368 WKSoftwareCARendererRender(_softwareRenderer, (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort], NSRectToCGRect(rect)); 369 _proxy->didDraw(); 370 } else 371 _proxy->print(reinterpret_cast<CGContextRef>([[NSGraphicsContext currentContext] graphicsPort]), [self bounds].size.width, [self bounds].size.height); 372 } 373 374 return; 375 } 376 377 if (_pluginHostDied) { 378 static NSImage *nullPlugInImage; 379 if (!nullPlugInImage) { 380 NSBundle *bundle = [NSBundle bundleForClass:[WebHostedNetscapePluginView class]]; 381 nullPlugInImage = [[NSImage alloc] initWithContentsOfFile:[bundle pathForResource:@"nullplugin" ofType:@"tiff"]]; 382 [nullPlugInImage setFlipped:YES]; 383 } 384 385 if (!nullPlugInImage) 386 return; 387 388 NSSize imageSize = [nullPlugInImage size]; 389 NSSize viewSize = [self bounds].size; 390 391 NSPoint point = NSMakePoint((viewSize.width - imageSize.width) / 2.0, (viewSize.height - imageSize.height) / 2.0); 392 [nullPlugInImage drawAtPoint:point fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0]; 393 } 394} 395 396- (PassRefPtr<JSC::Bindings::Instance>)createPluginBindingsInstance:(PassRefPtr<JSC::Bindings::RootObject>)rootObject 397{ 398 if (!_proxy) 399 return 0; 400 401 return _proxy->createBindingsInstance(rootObject); 402} 403 404- (void)pluginView:(NSView *)pluginView receivedResponse:(NSURLResponse *)response 405{ 406 ASSERT(_loadManually); 407 if (!_proxy) 408 return; 409 410 ASSERT(!_proxy->manualStream()); 411 412 _proxy->setManualStream(HostedNetscapePluginStream::create(_proxy.get(), core([self webFrame])->loader())); 413 _proxy->manualStream()->startStreamWithResponse(response); 414} 415 416- (void)pluginView:(NSView *)pluginView receivedData:(NSData *)data 417{ 418 ASSERT(_loadManually); 419 if (!_proxy) 420 return; 421 422 if (HostedNetscapePluginStream* manualStream = _proxy->manualStream()) 423 manualStream->didReceiveData(0, static_cast<const char*>([data bytes]), [data length]); 424} 425 426- (void)pluginView:(NSView *)pluginView receivedError:(NSError *)error 427{ 428 ASSERT(_loadManually); 429 if (!_proxy) 430 return; 431 432 if (HostedNetscapePluginStream* manualStream = _proxy->manualStream()) 433 manualStream->didFail(0, error); 434} 435 436- (void)pluginViewFinishedLoading:(NSView *)pluginView 437{ 438 ASSERT(_loadManually); 439 if (!_proxy) 440 return; 441 442 if (HostedNetscapePluginStream* manualStream = _proxy->manualStream()) 443 manualStream->didFinishLoading(0); 444} 445 446- (void)_webPluginContainerCancelCheckIfAllowedToLoadRequest:(id)webPluginContainerCheck 447{ 448 ASSERT([webPluginContainerCheck isKindOfClass:[WebPluginContainerCheck class]]); 449 450 id contextInfo = [webPluginContainerCheck contextInfo]; 451 ASSERT([contextInfo isKindOfClass:[NSNumber class]]); 452 453 if (!_proxy) 454 return; 455 456 uint32_t checkID = [(NSNumber *)contextInfo unsignedIntValue]; 457 _proxy->cancelCheckIfAllowedToLoadURL(checkID); 458} 459 460- (void)_containerCheckResult:(PolicyAction)policy contextInfo:(id)contextInfo 461{ 462 ASSERT([contextInfo isKindOfClass:[NSNumber class]]); 463 if (!_proxy) 464 return; 465 466 uint32_t checkID = [(NSNumber *)contextInfo unsignedIntValue]; 467 _proxy->checkIfAllowedToLoadURLResult(checkID, (policy == PolicyUse)); 468} 469 470- (void)webFrame:(WebFrame *)webFrame didFinishLoadWithReason:(NPReason)reason 471{ 472 if (_isStarted && _proxy) 473 _proxy->webFrameDidFinishLoadWithReason(webFrame, reason); 474} 475 476- (void)webFrame:(WebFrame *)webFrame didFinishLoadWithError:(NSError *)error 477{ 478 NPReason reason = NPRES_DONE; 479 if (error) 480 reason = HostedNetscapePluginStream::reasonForError(error); 481 [self webFrame:webFrame didFinishLoadWithReason:reason]; 482} 483 484@end 485 486#endif 487