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 49 using namespace WebCore; 50 using namespace WebKit; 51 52 extern "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