1 /* 2 * Copyright (C) 2005, 2006, 2007 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 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 14 * its contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #if ENABLE(NETSCAPE_PLUGIN_API) 30 31 #import "WebNetscapePluginView.h" 32 33 #import "WebDataSourceInternal.h" 34 #import "WebDefaultUIDelegate.h" 35 #import "WebFrameInternal.h" 36 #import "WebFrameView.h" 37 #import "WebKitErrorsPrivate.h" 38 #import "WebKitLogging.h" 39 #import "WebNetscapeContainerCheckPrivate.h" 40 #import "WebKitNSStringExtras.h" 41 #import "WebKitSystemInterface.h" 42 #import "WebNSDataExtras.h" 43 #import "WebNSDictionaryExtras.h" 44 #import "WebNSObjectExtras.h" 45 #import "WebNSURLExtras.h" 46 #import "WebNSURLRequestExtras.h" 47 #import "WebNSViewExtras.h" 48 #import "WebNetscapePluginPackage.h" 49 #import "WebBaseNetscapePluginStream.h" 50 #import "WebPluginContainerCheck.h" 51 #import "WebNetscapeContainerCheckContextInfo.h" 52 #import "WebNetscapePluginEventHandler.h" 53 #import "WebNullPluginView.h" 54 #import "WebPreferences.h" 55 #import "WebPluginRequest.h" 56 #import "WebViewInternal.h" 57 #import "WebUIDelegatePrivate.h" 58 #import <Carbon/Carbon.h> 59 #import <runtime/JSLock.h> 60 #import <WebCore/npruntime_impl.h> 61 #import <WebCore/CookieJar.h> 62 #import <WebCore/CString.h> 63 #import <WebCore/DocumentLoader.h> 64 #import <WebCore/Element.h> 65 #import <WebCore/Frame.h> 66 #import <WebCore/FrameLoader.h> 67 #import <WebCore/FrameTree.h> 68 #import <WebCore/HTMLPlugInElement.h> 69 #import <WebCore/Page.h> 70 #import <WebCore/PluginMainThreadScheduler.h> 71 #import <WebCore/ScriptController.h> 72 #import <WebCore/SecurityOrigin.h> 73 #import <WebCore/SoftLinking.h> 74 #import <WebCore/WebCoreObjCExtras.h> 75 #import <WebCore/WebCoreURLResponse.h> 76 #import <WebKit/DOMPrivate.h> 77 #import <WebKit/WebUIDelegate.h> 78 #import <runtime/InitializeThreading.h> 79 #import <wtf/Assertions.h> 80 #import <objc/objc-runtime.h> 81 82 #define LoginWindowDidSwitchFromUserNotification @"WebLoginWindowDidSwitchFromUserNotification" 83 #define LoginWindowDidSwitchToUserNotification @"WebLoginWindowDidSwitchToUserNotification" 84 #define WKNVSupportsCompositingCoreAnimationPluginsBool 74656 /* TRUE if the browser supports hardware compositing of Core Animation plug-ins */ 85 static const int WKNVSilverlightFullScreenPerformanceIssueFixed = 7288546; /* TRUE if Siverlight addressed its underlying bug in <rdar://problem/7288546> */ 86 87 using namespace WebCore; 88 using namespace WebKit; 89 using namespace std; 90 91 static inline bool isDrawingModelQuickDraw(NPDrawingModel drawingModel) 92 { 93 #ifndef NP_NO_QUICKDRAW 94 return drawingModel == NPDrawingModelQuickDraw; 95 #else 96 return false; 97 #endif 98 }; 99 100 @interface WebNetscapePluginView (Internal) 101 - (NPError)_createPlugin; 102 - (void)_destroyPlugin; 103 - (NSBitmapImageRep *)_printedPluginBitmap; 104 - (void)_redeliverStream; 105 - (BOOL)_shouldCancelSrcStream; 106 @end 107 108 static WebNetscapePluginView *currentPluginView = nil; 109 110 typedef struct OpaquePortState* PortState; 111 112 static const double ThrottledTimerInterval = 0.25; 113 114 class PluginTimer : public TimerBase { 115 public: 116 typedef void (*TimerFunc)(NPP npp, uint32 timerID); 117 118 PluginTimer(NPP npp, uint32 timerID, uint32 interval, NPBool repeat, TimerFunc timerFunc) 119 : m_npp(npp) 120 , m_timerID(timerID) 121 , m_interval(interval) 122 , m_repeat(repeat) 123 , m_timerFunc(timerFunc) 124 { 125 } 126 127 void start(bool throttle) 128 { 129 ASSERT(!isActive()); 130 131 double timeInterval = m_interval / 1000.0; 132 133 if (throttle) 134 timeInterval = max(timeInterval, ThrottledTimerInterval); 135 136 if (m_repeat) 137 startRepeating(timeInterval); 138 else 139 startOneShot(timeInterval); 140 } 141 142 private: 143 virtual void fired() 144 { 145 m_timerFunc(m_npp, m_timerID); 146 if (!m_repeat) 147 delete this; 148 } 149 150 NPP m_npp; 151 uint32 m_timerID; 152 uint32 m_interval; 153 NPBool m_repeat; 154 TimerFunc m_timerFunc; 155 }; 156 157 #ifndef NP_NO_QUICKDRAW 158 159 // QuickDraw is not available in 64-bit 160 161 typedef struct { 162 GrafPtr oldPort; 163 GDHandle oldDevice; 164 Point oldOrigin; 165 RgnHandle oldClipRegion; 166 RgnHandle oldVisibleRegion; 167 RgnHandle clipRegion; 168 BOOL forUpdate; 169 } PortState_QD; 170 171 #endif /* NP_NO_QUICKDRAW */ 172 173 typedef struct { 174 CGContextRef context; 175 } PortState_CG; 176 177 @class NSTextInputContext; 178 @interface NSResponder (AppKitDetails) 179 - (NSTextInputContext *)inputContext; 180 @end 181 182 @interface WebNetscapePluginView (ForwardDeclarations) 183 - (void)setWindowIfNecessary; 184 - (NPError)loadRequest:(NSMutableURLRequest *)request inTarget:(const char *)cTarget withNotifyData:(void *)notifyData sendNotification:(BOOL)sendNotification; 185 @end 186 187 @implementation WebNetscapePluginView 188 189 + (void)initialize 190 { 191 JSC::initializeThreading(); 192 #ifndef BUILDING_ON_TIGER 193 WebCoreObjCFinalizeOnMainThread(self); 194 #endif 195 WKSendUserChangeNotifications(); 196 } 197 198 #pragma mark EVENTS 199 200 // The WindowRef created by -[NSWindow windowRef] has a QuickDraw GrafPort that covers 201 // the entire window frame (or structure region to use the Carbon term) rather then just the window content. 202 // We can remove this when <rdar://problem/4201099> is fixed. 203 - (void)fixWindowPort 204 { 205 #ifndef NP_NO_QUICKDRAW 206 ASSERT(isDrawingModelQuickDraw(drawingModel)); 207 208 NSWindow *currentWindow = [self currentWindow]; 209 if ([currentWindow isKindOfClass:objc_getClass("NSCarbonWindow")]) 210 return; 211 212 float windowHeight = [currentWindow frame].size.height; 213 NSView *contentView = [currentWindow contentView]; 214 NSRect contentRect = [contentView convertRect:[contentView frame] toView:nil]; // convert to window-relative coordinates 215 216 CGrafPtr oldPort; 217 GetPort(&oldPort); 218 SetPort(GetWindowPort((WindowRef)[currentWindow windowRef])); 219 220 MovePortTo(static_cast<short>(contentRect.origin.x), /* Flip Y */ static_cast<short>(windowHeight - NSMaxY(contentRect))); 221 PortSize(static_cast<short>(contentRect.size.width), static_cast<short>(contentRect.size.height)); 222 223 SetPort(oldPort); 224 #endif 225 } 226 227 #ifndef NP_NO_QUICKDRAW 228 static UInt32 getQDPixelFormatForBitmapContext(CGContextRef context) 229 { 230 UInt32 byteOrder = CGBitmapContextGetBitmapInfo(context) & kCGBitmapByteOrderMask; 231 if (byteOrder == kCGBitmapByteOrderDefault) 232 switch (CGBitmapContextGetBitsPerPixel(context)) { 233 case 16: 234 byteOrder = kCGBitmapByteOrder16Host; 235 break; 236 case 32: 237 byteOrder = kCGBitmapByteOrder32Host; 238 break; 239 } 240 switch (byteOrder) { 241 case kCGBitmapByteOrder16Little: 242 return k16LE555PixelFormat; 243 case kCGBitmapByteOrder32Little: 244 return k32BGRAPixelFormat; 245 case kCGBitmapByteOrder16Big: 246 return k16BE555PixelFormat; 247 case kCGBitmapByteOrder32Big: 248 return k32ARGBPixelFormat; 249 } 250 ASSERT_NOT_REACHED(); 251 return 0; 252 } 253 254 static inline void getNPRect(const CGRect& cgr, NPRect& npr) 255 { 256 npr.top = static_cast<uint16>(cgr.origin.y); 257 npr.left = static_cast<uint16>(cgr.origin.x); 258 npr.bottom = static_cast<uint16>(CGRectGetMaxY(cgr)); 259 npr.right = static_cast<uint16>(CGRectGetMaxX(cgr)); 260 } 261 262 #endif 263 264 static inline void getNPRect(const NSRect& nr, NPRect& npr) 265 { 266 npr.top = static_cast<uint16>(nr.origin.y); 267 npr.left = static_cast<uint16>(nr.origin.x); 268 npr.bottom = static_cast<uint16>(NSMaxY(nr)); 269 npr.right = static_cast<uint16>(NSMaxX(nr)); 270 } 271 272 - (PortState)saveAndSetNewPortStateForUpdate:(BOOL)forUpdate 273 { 274 ASSERT([self currentWindow] != nil); 275 276 // Use AppKit to convert view coordinates to NSWindow coordinates. 277 NSRect boundsInWindow = [self convertRect:[self bounds] toView:nil]; 278 NSRect visibleRectInWindow = [self convertRect:[self visibleRect] toView:nil]; 279 280 // Flip Y to convert NSWindow coordinates to top-left-based window coordinates. 281 float borderViewHeight = [[self currentWindow] frame].size.height; 282 boundsInWindow.origin.y = borderViewHeight - NSMaxY(boundsInWindow); 283 visibleRectInWindow.origin.y = borderViewHeight - NSMaxY(visibleRectInWindow); 284 285 #ifndef NP_NO_QUICKDRAW 286 WindowRef windowRef = (WindowRef)[[self currentWindow] windowRef]; 287 ASSERT(windowRef); 288 289 // Look at the Carbon port to convert top-left-based window coordinates into top-left-based content coordinates. 290 if (isDrawingModelQuickDraw(drawingModel)) { 291 // If drawing with QuickDraw, fix the window port so that it has the same bounds as the NSWindow's 292 // content view. This makes it easier to convert between AppKit view and QuickDraw port coordinates. 293 [self fixWindowPort]; 294 295 ::Rect portBounds; 296 CGrafPtr port = GetWindowPort(windowRef); 297 GetPortBounds(port, &portBounds); 298 299 PixMap *pix = *GetPortPixMap(port); 300 boundsInWindow.origin.x += pix->bounds.left - portBounds.left; 301 boundsInWindow.origin.y += pix->bounds.top - portBounds.top; 302 visibleRectInWindow.origin.x += pix->bounds.left - portBounds.left; 303 visibleRectInWindow.origin.y += pix->bounds.top - portBounds.top; 304 } 305 #endif 306 307 window.type = NPWindowTypeWindow; 308 window.x = (int32)boundsInWindow.origin.x; 309 window.y = (int32)boundsInWindow.origin.y; 310 window.width = static_cast<uint32>(NSWidth(boundsInWindow)); 311 window.height = static_cast<uint32>(NSHeight(boundsInWindow)); 312 313 // "Clip-out" the plug-in when: 314 // 1) it's not really in a window or off-screen or has no height or width. 315 // 2) window.x is a "big negative number" which is how WebCore expresses off-screen widgets. 316 // 3) the window is miniaturized or the app is hidden 317 // 4) we're inside of viewWillMoveToWindow: with a nil window. In this case, superviews may already have nil 318 // superviews and nil windows and results from convertRect:toView: are incorrect. 319 if (window.width <= 0 || window.height <= 0 || window.x < -100000 || [self shouldClipOutPlugin]) { 320 321 // The following code tries to give plug-ins the same size they will eventually have. 322 // The specifiedWidth and specifiedHeight variables are used to predict the size that 323 // WebCore will eventually resize us to. 324 325 // The QuickTime plug-in has problems if you give it a width or height of 0. 326 // Since other plug-ins also might have the same sort of trouble, we make sure 327 // to always give plug-ins a size other than 0,0. 328 329 if (window.width <= 0) 330 window.width = specifiedWidth > 0 ? specifiedWidth : 100; 331 if (window.height <= 0) 332 window.height = specifiedHeight > 0 ? specifiedHeight : 100; 333 334 window.clipRect.bottom = window.clipRect.top; 335 window.clipRect.left = window.clipRect.right; 336 337 // Core Animation plug-ins need to be updated (with a 0,0,0,0 clipRect) when 338 // moved to a background tab. We don't do this for Core Graphics plug-ins as 339 // older versions of Flash have historical WebKit-specific code that isn't 340 // compatible with this behavior. 341 if (drawingModel == NPDrawingModelCoreAnimation) 342 getNPRect(NSZeroRect, window.clipRect); 343 } else { 344 getNPRect(visibleRectInWindow, window.clipRect); 345 } 346 347 // Save the port state, set up the port for entry into the plugin 348 PortState portState; 349 switch (drawingModel) { 350 #ifndef NP_NO_QUICKDRAW 351 case NPDrawingModelQuickDraw: { 352 // Set up NS_Port. 353 ::Rect portBounds; 354 CGrafPtr port = GetWindowPort(windowRef); 355 GetPortBounds(port, &portBounds); 356 nPort.qdPort.port = port; 357 nPort.qdPort.portx = (int32)-boundsInWindow.origin.x; 358 nPort.qdPort.porty = (int32)-boundsInWindow.origin.y; 359 window.window = &nPort; 360 361 PortState_QD *qdPortState = (PortState_QD*)malloc(sizeof(PortState_QD)); 362 portState = (PortState)qdPortState; 363 364 GetGWorld(&qdPortState->oldPort, &qdPortState->oldDevice); 365 366 qdPortState->oldOrigin.h = portBounds.left; 367 qdPortState->oldOrigin.v = portBounds.top; 368 369 qdPortState->oldClipRegion = NewRgn(); 370 GetPortClipRegion(port, qdPortState->oldClipRegion); 371 372 qdPortState->oldVisibleRegion = NewRgn(); 373 GetPortVisibleRegion(port, qdPortState->oldVisibleRegion); 374 375 RgnHandle clipRegion = NewRgn(); 376 qdPortState->clipRegion = clipRegion; 377 378 CGContextRef currentContext = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort]; 379 if (currentContext && WKCGContextIsBitmapContext(currentContext)) { 380 // We use WKCGContextIsBitmapContext here, because if we just called CGBitmapContextGetData 381 // on any context, we'd log to the console every time. But even if WKCGContextIsBitmapContext 382 // returns true, it still might not be a context we need to create a GWorld for; for example 383 // transparency layers will return true, but return 0 for CGBitmapContextGetData. 384 void* offscreenData = CGBitmapContextGetData(currentContext); 385 if (offscreenData) { 386 // If the current context is an offscreen bitmap, then create a GWorld for it. 387 ::Rect offscreenBounds; 388 offscreenBounds.top = 0; 389 offscreenBounds.left = 0; 390 offscreenBounds.right = CGBitmapContextGetWidth(currentContext); 391 offscreenBounds.bottom = CGBitmapContextGetHeight(currentContext); 392 GWorldPtr newOffscreenGWorld; 393 QDErr err = NewGWorldFromPtr(&newOffscreenGWorld, 394 getQDPixelFormatForBitmapContext(currentContext), &offscreenBounds, 0, 0, 0, 395 static_cast<char*>(offscreenData), CGBitmapContextGetBytesPerRow(currentContext)); 396 ASSERT(newOffscreenGWorld); 397 ASSERT(!err); 398 if (!err) { 399 if (offscreenGWorld) 400 DisposeGWorld(offscreenGWorld); 401 offscreenGWorld = newOffscreenGWorld; 402 403 SetGWorld(offscreenGWorld, NULL); 404 405 port = offscreenGWorld; 406 407 nPort.qdPort.port = port; 408 boundsInWindow = [self bounds]; 409 410 // Generate a QD origin based on the current affine transform for currentContext. 411 CGAffineTransform offscreenMatrix = CGContextGetCTM(currentContext); 412 CGPoint origin = {0,0}; 413 CGPoint axisFlip = {1,1}; 414 origin = CGPointApplyAffineTransform(origin, offscreenMatrix); 415 axisFlip = CGPointApplyAffineTransform(axisFlip, offscreenMatrix); 416 417 // Quartz bitmaps have origins at the bottom left, but the axes may be inverted, so handle that. 418 origin.x = offscreenBounds.left - origin.x * (axisFlip.x - origin.x); 419 origin.y = offscreenBounds.bottom + origin.y * (axisFlip.y - origin.y); 420 421 nPort.qdPort.portx = static_cast<int32>(-boundsInWindow.origin.x + origin.x); 422 nPort.qdPort.porty = static_cast<int32>(-boundsInWindow.origin.y - origin.y); 423 window.x = 0; 424 window.y = 0; 425 window.window = &nPort; 426 427 // Use the clip bounds from the context instead of the bounds we created 428 // from the window above. 429 getNPRect(CGRectOffset(CGContextGetClipBoundingBox(currentContext), -origin.x, origin.y), window.clipRect); 430 } 431 } 432 } 433 434 MacSetRectRgn(clipRegion, 435 window.clipRect.left + nPort.qdPort.portx, window.clipRect.top + nPort.qdPort.porty, 436 window.clipRect.right + nPort.qdPort.portx, window.clipRect.bottom + nPort.qdPort.porty); 437 438 // Clip to the dirty region if drawing to a window. When drawing to another bitmap context, do not clip. 439 if ([NSGraphicsContext currentContext] == [[self currentWindow] graphicsContext]) { 440 // Clip to dirty region so plug-in does not draw over already-drawn regions of the window that are 441 // not going to be redrawn this update. This forces plug-ins to play nice with z-index ordering. 442 if (forUpdate) { 443 RgnHandle viewClipRegion = NewRgn(); 444 445 // Get list of dirty rects from the opaque ancestor -- WebKit does some tricks with invalidation and 446 // display to enable z-ordering for NSViews; a side-effect of this is that only the WebHTMLView 447 // knows about the true set of dirty rects. 448 NSView *opaqueAncestor = [self opaqueAncestor]; 449 const NSRect *dirtyRects; 450 NSInteger dirtyRectCount, dirtyRectIndex; 451 [opaqueAncestor getRectsBeingDrawn:&dirtyRects count:&dirtyRectCount]; 452 453 for (dirtyRectIndex = 0; dirtyRectIndex < dirtyRectCount; dirtyRectIndex++) { 454 NSRect dirtyRect = [self convertRect:dirtyRects[dirtyRectIndex] fromView:opaqueAncestor]; 455 if (!NSEqualSizes(dirtyRect.size, NSZeroSize)) { 456 // Create a region for this dirty rect 457 RgnHandle dirtyRectRegion = NewRgn(); 458 SetRectRgn(dirtyRectRegion, static_cast<short>(NSMinX(dirtyRect)), static_cast<short>(NSMinY(dirtyRect)), static_cast<short>(NSMaxX(dirtyRect)), static_cast<short>(NSMaxY(dirtyRect))); 459 460 // Union this dirty rect with the rest of the dirty rects 461 UnionRgn(viewClipRegion, dirtyRectRegion, viewClipRegion); 462 DisposeRgn(dirtyRectRegion); 463 } 464 } 465 466 // Intersect the dirty region with the clip region, so that we only draw over dirty parts 467 SectRgn(clipRegion, viewClipRegion, clipRegion); 468 DisposeRgn(viewClipRegion); 469 } 470 } 471 472 // Switch to the port and set it up. 473 SetPort(port); 474 PenNormal(); 475 ForeColor(blackColor); 476 BackColor(whiteColor); 477 SetOrigin(nPort.qdPort.portx, nPort.qdPort.porty); 478 SetPortClipRegion(nPort.qdPort.port, clipRegion); 479 480 if (forUpdate) { 481 // AppKit may have tried to help us by doing a BeginUpdate. 482 // But the invalid region at that level didn't include AppKit's notion of what was not valid. 483 // We reset the port's visible region to counteract what BeginUpdate did. 484 SetPortVisibleRegion(nPort.qdPort.port, clipRegion); 485 InvalWindowRgn(windowRef, clipRegion); 486 } 487 488 qdPortState->forUpdate = forUpdate; 489 break; 490 } 491 #endif /* NP_NO_QUICKDRAW */ 492 493 case NPDrawingModelCoreGraphics: { 494 if (![self canDraw]) { 495 portState = NULL; 496 break; 497 } 498 499 ASSERT([NSView focusView] == self); 500 501 CGContextRef context = static_cast<CGContextRef>([[NSGraphicsContext currentContext] graphicsPort]); 502 503 PortState_CG *cgPortState = (PortState_CG *)malloc(sizeof(PortState_CG)); 504 portState = (PortState)cgPortState; 505 cgPortState->context = context; 506 507 #ifndef NP_NO_CARBON 508 if (eventModel != NPEventModelCocoa) { 509 // Update the plugin's window/context 510 nPort.cgPort.window = windowRef; 511 nPort.cgPort.context = context; 512 window.window = &nPort.cgPort; 513 } 514 #endif /* NP_NO_CARBON */ 515 516 // Save current graphics context's state; will be restored by -restorePortState: 517 CGContextSaveGState(context); 518 519 // Clip to the dirty region if drawing to a window. When drawing to another bitmap context, do not clip. 520 if ([NSGraphicsContext currentContext] == [[self currentWindow] graphicsContext]) { 521 // Get list of dirty rects from the opaque ancestor -- WebKit does some tricks with invalidation and 522 // display to enable z-ordering for NSViews; a side-effect of this is that only the WebHTMLView 523 // knows about the true set of dirty rects. 524 NSView *opaqueAncestor = [self opaqueAncestor]; 525 const NSRect *dirtyRects; 526 NSInteger count; 527 [opaqueAncestor getRectsBeingDrawn:&dirtyRects count:&count]; 528 Vector<CGRect, 16> convertedDirtyRects; 529 convertedDirtyRects.resize(count); 530 for (int i = 0; i < count; ++i) 531 reinterpret_cast<NSRect&>(convertedDirtyRects[i]) = [self convertRect:dirtyRects[i] fromView:opaqueAncestor]; 532 CGContextClipToRects(context, convertedDirtyRects.data(), count); 533 } 534 535 break; 536 } 537 538 case NPDrawingModelCoreAnimation: 539 // Just set the port state to a dummy value. 540 portState = (PortState)1; 541 break; 542 543 default: 544 ASSERT_NOT_REACHED(); 545 portState = NULL; 546 break; 547 } 548 549 return portState; 550 } 551 552 - (PortState)saveAndSetNewPortState 553 { 554 return [self saveAndSetNewPortStateForUpdate:NO]; 555 } 556 557 - (void)restorePortState:(PortState)portState 558 { 559 ASSERT([self currentWindow]); 560 ASSERT(portState); 561 562 switch (drawingModel) { 563 #ifndef NP_NO_QUICKDRAW 564 case NPDrawingModelQuickDraw: { 565 PortState_QD *qdPortState = (PortState_QD *)portState; 566 WindowRef windowRef = (WindowRef)[[self currentWindow] windowRef]; 567 CGrafPtr port = GetWindowPort(windowRef); 568 569 SetPort(port); 570 571 if (qdPortState->forUpdate) 572 ValidWindowRgn(windowRef, qdPortState->clipRegion); 573 574 SetOrigin(qdPortState->oldOrigin.h, qdPortState->oldOrigin.v); 575 576 SetPortClipRegion(port, qdPortState->oldClipRegion); 577 if (qdPortState->forUpdate) 578 SetPortVisibleRegion(port, qdPortState->oldVisibleRegion); 579 580 DisposeRgn(qdPortState->oldClipRegion); 581 DisposeRgn(qdPortState->oldVisibleRegion); 582 DisposeRgn(qdPortState->clipRegion); 583 584 SetGWorld(qdPortState->oldPort, qdPortState->oldDevice); 585 break; 586 } 587 #endif /* NP_NO_QUICKDRAW */ 588 589 case NPDrawingModelCoreGraphics: { 590 ASSERT([NSView focusView] == self); 591 592 CGContextRef context = ((PortState_CG *)portState)->context; 593 ASSERT(!nPort.cgPort.context || (context == nPort.cgPort.context)); 594 CGContextRestoreGState(context); 595 break; 596 } 597 598 case NPDrawingModelCoreAnimation: 599 ASSERT(portState == (PortState)1); 600 break; 601 default: 602 ASSERT_NOT_REACHED(); 603 break; 604 } 605 } 606 607 - (BOOL)sendEvent:(void*)event isDrawRect:(BOOL)eventIsDrawRect 608 { 609 if (![self window]) 610 return NO; 611 ASSERT(event); 612 613 if (!_isStarted) 614 return NO; 615 616 ASSERT([_pluginPackage.get() pluginFuncs]->event); 617 618 // Make sure we don't call NPP_HandleEvent while we're inside NPP_SetWindow. 619 // We probably don't want more general reentrancy protection; we are really 620 // protecting only against this one case, which actually comes up when 621 // you first install the SVG viewer plug-in. 622 if (inSetWindow) 623 return NO; 624 625 Frame* frame = core([self webFrame]); 626 if (!frame) 627 return NO; 628 Page* page = frame->page(); 629 if (!page) 630 return NO; 631 632 // Can only send drawRect (updateEvt) to CoreGraphics plugins when actually drawing 633 ASSERT((drawingModel != NPDrawingModelCoreGraphics) || !eventIsDrawRect || [NSView focusView] == self); 634 635 PortState portState = NULL; 636 637 if (isDrawingModelQuickDraw(drawingModel) || (drawingModel != NPDrawingModelCoreAnimation && eventIsDrawRect)) { 638 // In CoreGraphics mode, the port state only needs to be saved/set when redrawing the plug-in view. 639 // The plug-in is not allowed to draw at any other time. 640 portState = [self saveAndSetNewPortStateForUpdate:eventIsDrawRect]; 641 // We may have changed the window, so inform the plug-in. 642 [self setWindowIfNecessary]; 643 } 644 645 #if !defined(NDEBUG) && !defined(NP_NO_QUICKDRAW) 646 // Draw green to help debug. 647 // If we see any green we know something's wrong. 648 // Note that PaintRect() only works for QuickDraw plugins; otherwise the current QD port is undefined. 649 if (isDrawingModelQuickDraw(drawingModel) && eventIsDrawRect) { 650 ForeColor(greenColor); 651 const ::Rect bigRect = { -10000, -10000, 10000, 10000 }; 652 PaintRect(&bigRect); 653 ForeColor(blackColor); 654 } 655 #endif 656 657 // Temporarily retain self in case the plug-in view is released while sending an event. 658 [[self retain] autorelease]; 659 660 BOOL acceptedEvent; 661 [self willCallPlugInFunction]; 662 { 663 JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly); 664 acceptedEvent = [_pluginPackage.get() pluginFuncs]->event(plugin, event); 665 } 666 [self didCallPlugInFunction]; 667 668 if (portState) { 669 if ([self currentWindow]) 670 [self restorePortState:portState]; 671 if (portState != (PortState)1) 672 free(portState); 673 } 674 675 return acceptedEvent; 676 } 677 678 - (void)windowFocusChanged:(BOOL)hasFocus 679 { 680 _eventHandler->windowFocusChanged(hasFocus); 681 } 682 683 - (void)sendDrawRectEvent:(NSRect)rect 684 { 685 ASSERT(_eventHandler); 686 687 CGContextRef context = static_cast<CGContextRef>([[NSGraphicsContext currentContext] graphicsPort]); 688 _eventHandler->drawRect(context, rect); 689 } 690 691 - (void)stopTimers 692 { 693 [super stopTimers]; 694 695 if (_eventHandler) 696 _eventHandler->stopTimers(); 697 698 if (!timers) 699 return; 700 701 HashMap<uint32, PluginTimer*>::const_iterator end = timers->end(); 702 for (HashMap<uint32, PluginTimer*>::const_iterator it = timers->begin(); it != end; ++it) { 703 PluginTimer* timer = it->second; 704 timer->stop(); 705 } 706 } 707 708 - (void)startTimers 709 { 710 [super startTimers]; 711 712 // If the plugin is completely obscured (scrolled out of view, for example), then we will 713 // send null events at a reduced rate. 714 _eventHandler->startTimers(_isCompletelyObscured); 715 716 if (!timers) 717 return; 718 719 HashMap<uint32, PluginTimer*>::const_iterator end = timers->end(); 720 for (HashMap<uint32, PluginTimer*>::const_iterator it = timers->begin(); it != end; ++it) { 721 PluginTimer* timer = it->second; 722 ASSERT(!timer->isActive()); 723 timer->start(_isCompletelyObscured); 724 } 725 } 726 727 - (void)focusChanged 728 { 729 // We need to null check the event handler here because 730 // the plug-in view can resign focus after it's been stopped 731 // and the event handler has been deleted. 732 if (_eventHandler) 733 _eventHandler->focusChanged(_hasFocus); 734 } 735 736 - (void)mouseDown:(NSEvent *)theEvent 737 { 738 if (!_isStarted) 739 return; 740 741 _eventHandler->mouseDown(theEvent); 742 } 743 744 - (void)mouseUp:(NSEvent *)theEvent 745 { 746 if (!_isStarted) 747 return; 748 749 _eventHandler->mouseUp(theEvent); 750 } 751 752 - (void)mouseEntered:(NSEvent *)theEvent 753 { 754 if (!_isStarted) 755 return; 756 757 _eventHandler->mouseEntered(theEvent); 758 } 759 760 - (void)mouseExited:(NSEvent *)theEvent 761 { 762 if (!_isStarted) 763 return; 764 765 _eventHandler->mouseExited(theEvent); 766 767 // 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 768 // current cursor is otherwise. Therefore we have no choice but to unconditionally reset the cursor when the mouse exits the plugin. 769 [[NSCursor arrowCursor] set]; 770 } 771 772 // We can't name this method mouseMoved because we don't want to override 773 // the NSView mouseMoved implementation. 774 - (void)handleMouseMoved:(NSEvent *)theEvent 775 { 776 if (!_isStarted) 777 return; 778 779 _eventHandler->mouseMoved(theEvent); 780 } 781 782 - (void)mouseDragged:(NSEvent *)theEvent 783 { 784 if (!_isStarted) 785 return; 786 787 _eventHandler->mouseDragged(theEvent); 788 } 789 790 - (void)scrollWheel:(NSEvent *)theEvent 791 { 792 if (!_isStarted) { 793 [super scrollWheel:theEvent]; 794 return; 795 } 796 797 if (!_eventHandler->scrollWheel(theEvent)) 798 [super scrollWheel:theEvent]; 799 } 800 801 - (void)keyUp:(NSEvent *)theEvent 802 { 803 if (!_isStarted) 804 return; 805 806 _eventHandler->keyUp(theEvent); 807 } 808 809 - (void)keyDown:(NSEvent *)theEvent 810 { 811 if (!_isStarted) 812 return; 813 814 _eventHandler->keyDown(theEvent); 815 } 816 817 - (void)flagsChanged:(NSEvent *)theEvent 818 { 819 if (!_isStarted) 820 return; 821 822 _eventHandler->flagsChanged(theEvent); 823 } 824 825 - (void)sendModifierEventWithKeyCode:(int)keyCode character:(char)character 826 { 827 if (!_isStarted) 828 return; 829 830 _eventHandler->syntheticKeyDownWithCommandModifier(keyCode, character); 831 } 832 833 - (void)privateBrowsingModeDidChange 834 { 835 if (!_isStarted) 836 return; 837 838 NPBool value = _isPrivateBrowsingEnabled; 839 840 [self willCallPlugInFunction]; 841 { 842 JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly); 843 if ([_pluginPackage.get() pluginFuncs]->setvalue) 844 [_pluginPackage.get() pluginFuncs]->setvalue(plugin, NPNVprivateModeBool, &value); 845 } 846 [self didCallPlugInFunction]; 847 } 848 849 #pragma mark WEB_NETSCAPE_PLUGIN 850 851 - (BOOL)isNewWindowEqualToOldWindow 852 { 853 if (window.x != lastSetWindow.x) 854 return NO; 855 if (window.y != lastSetWindow.y) 856 return NO; 857 if (window.width != lastSetWindow.width) 858 return NO; 859 if (window.height != lastSetWindow.height) 860 return NO; 861 if (window.clipRect.top != lastSetWindow.clipRect.top) 862 return NO; 863 if (window.clipRect.left != lastSetWindow.clipRect.left) 864 return NO; 865 if (window.clipRect.bottom != lastSetWindow.clipRect.bottom) 866 return NO; 867 if (window.clipRect.right != lastSetWindow.clipRect.right) 868 return NO; 869 if (window.type != lastSetWindow.type) 870 return NO; 871 872 switch (drawingModel) { 873 #ifndef NP_NO_QUICKDRAW 874 case NPDrawingModelQuickDraw: 875 if (nPort.qdPort.portx != lastSetPort.qdPort.portx) 876 return NO; 877 if (nPort.qdPort.porty != lastSetPort.qdPort.porty) 878 return NO; 879 if (nPort.qdPort.port != lastSetPort.qdPort.port) 880 return NO; 881 break; 882 #endif /* NP_NO_QUICKDRAW */ 883 884 case NPDrawingModelCoreGraphics: 885 if (nPort.cgPort.window != lastSetPort.cgPort.window) 886 return NO; 887 if (nPort.cgPort.context != lastSetPort.cgPort.context) 888 return NO; 889 break; 890 891 case NPDrawingModelCoreAnimation: 892 if (window.window != lastSetWindow.window) 893 return NO; 894 break; 895 default: 896 ASSERT_NOT_REACHED(); 897 break; 898 } 899 900 return YES; 901 } 902 903 -(void)tellQuickTimeToChill 904 { 905 #ifndef NP_NO_QUICKDRAW 906 ASSERT(isDrawingModelQuickDraw(drawingModel)); 907 908 // Make a call to the secret QuickDraw API that makes QuickTime calm down. 909 WindowRef windowRef = (WindowRef)[[self window] windowRef]; 910 if (!windowRef) { 911 return; 912 } 913 CGrafPtr port = GetWindowPort(windowRef); 914 ::Rect bounds; 915 GetPortBounds(port, &bounds); 916 WKCallDrawingNotification(port, &bounds); 917 #endif /* NP_NO_QUICKDRAW */ 918 } 919 920 - (void)updateAndSetWindow 921 { 922 // A plug-in can only update if it's (1) already been started (2) isn't stopped 923 // and (3) is able to draw on-screen. To meet condition (3) the plug-in must not 924 // be hidden and be attached to a window. There are two exceptions to this rule: 925 // 926 // Exception 1: QuickDraw plug-ins must be manually told when to stop writing 927 // bits to the window backing store, thus to do so requires a new call to 928 // NPP_SetWindow() with an empty NPWindow struct. 929 // 930 // Exception 2: CoreGraphics plug-ins expect to have their drawable area updated 931 // when they are moved to a background tab, via a NPP_SetWindow call. This is 932 // accomplished by allowing -saveAndSetNewPortStateForUpdate to "clip-out" the window's 933 // clipRect. Flash is curently an exception to this. See 6453738. 934 // 935 936 if (!_isStarted) 937 return; 938 939 #ifdef NP_NO_QUICKDRAW 940 if (![self canDraw]) 941 return; 942 #else 943 if (drawingModel == NPDrawingModelQuickDraw) 944 [self tellQuickTimeToChill]; 945 else if (drawingModel == NPDrawingModelCoreGraphics && ![self canDraw] && _isFlash) { 946 // The Flash plug-in does not expect an NPP_SetWindow call from WebKit in this case. 947 // See Exception 2 above. 948 return; 949 } 950 #endif // NP_NO_QUICKDRAW 951 952 BOOL didLockFocus = [NSView focusView] != self && [self lockFocusIfCanDraw]; 953 954 PortState portState = [self saveAndSetNewPortState]; 955 if (portState) { 956 [self setWindowIfNecessary]; 957 [self restorePortState:portState]; 958 if (portState != (PortState)1) 959 free(portState); 960 } else if (drawingModel == NPDrawingModelCoreGraphics) 961 [self setWindowIfNecessary]; 962 963 if (didLockFocus) 964 [self unlockFocus]; 965 } 966 967 - (void)setWindowIfNecessary 968 { 969 if (!_isStarted) 970 return; 971 972 if (![self isNewWindowEqualToOldWindow]) { 973 // Make sure we don't call NPP_HandleEvent while we're inside NPP_SetWindow. 974 // We probably don't want more general reentrancy protection; we are really 975 // protecting only against this one case, which actually comes up when 976 // you first install the SVG viewer plug-in. 977 NPError npErr; 978 ASSERT(!inSetWindow); 979 980 inSetWindow = YES; 981 [self willCallPlugInFunction]; 982 { 983 JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly); 984 npErr = [_pluginPackage.get() pluginFuncs]->setwindow(plugin, &window); 985 } 986 [self didCallPlugInFunction]; 987 inSetWindow = NO; 988 989 #ifndef NDEBUG 990 switch (drawingModel) { 991 #ifndef NP_NO_QUICKDRAW 992 case NPDrawingModelQuickDraw: 993 LOG(Plugins, "NPP_SetWindow (QuickDraw): %d, port=0x%08x, window.x:%d window.y:%d window.width:%d window.height:%d", 994 npErr, (int)nPort.qdPort.port, (int)window.x, (int)window.y, (int)window.width, (int)window.height); 995 break; 996 #endif /* NP_NO_QUICKDRAW */ 997 998 case NPDrawingModelCoreGraphics: 999 LOG(Plugins, "NPP_SetWindow (CoreGraphics): %d, window=%p, context=%p, window.x:%d window.y:%d window.width:%d window.height:%d window.clipRect size:%dx%d", 1000 npErr, nPort.cgPort.window, nPort.cgPort.context, (int)window.x, (int)window.y, (int)window.width, (int)window.height, 1001 window.clipRect.right - window.clipRect.left, window.clipRect.bottom - window.clipRect.top); 1002 break; 1003 1004 case NPDrawingModelCoreAnimation: 1005 LOG(Plugins, "NPP_SetWindow (CoreAnimation): %d, window=%p window.x:%d window.y:%d window.width:%d window.height:%d", 1006 npErr, window.window, nPort.cgPort.context, (int)window.x, (int)window.y, (int)window.width, (int)window.height); 1007 break; 1008 1009 default: 1010 ASSERT_NOT_REACHED(); 1011 break; 1012 } 1013 #endif /* !defined(NDEBUG) */ 1014 1015 lastSetWindow = window; 1016 lastSetPort = nPort; 1017 } 1018 } 1019 1020 + (void)setCurrentPluginView:(WebNetscapePluginView *)view 1021 { 1022 currentPluginView = view; 1023 } 1024 1025 + (WebNetscapePluginView *)currentPluginView 1026 { 1027 return currentPluginView; 1028 } 1029 1030 - (BOOL)createPlugin 1031 { 1032 // Open the plug-in package so it remains loaded while our plugin uses it 1033 [_pluginPackage.get() open]; 1034 1035 // Initialize drawingModel to an invalid value so that we can detect when the plugin does not specify a drawingModel 1036 drawingModel = (NPDrawingModel)-1; 1037 1038 // Initialize eventModel to an invalid value so that we can detect when the plugin does not specify an event model. 1039 eventModel = (NPEventModel)-1; 1040 1041 NPError npErr = [self _createPlugin]; 1042 if (npErr != NPERR_NO_ERROR) { 1043 LOG_ERROR("NPP_New failed with error: %d", npErr); 1044 [self _destroyPlugin]; 1045 [_pluginPackage.get() close]; 1046 return NO; 1047 } 1048 1049 if (drawingModel == (NPDrawingModel)-1) { 1050 #ifndef NP_NO_QUICKDRAW 1051 // Default to QuickDraw if the plugin did not specify a drawing model. 1052 drawingModel = NPDrawingModelQuickDraw; 1053 #else 1054 // QuickDraw is not available, so we can't default to it. Instead, default to CoreGraphics. 1055 drawingModel = NPDrawingModelCoreGraphics; 1056 #endif 1057 } 1058 1059 if (eventModel == (NPEventModel)-1) { 1060 // If the plug-in did not specify a drawing model we default to Carbon when it is available. 1061 #ifndef NP_NO_CARBON 1062 eventModel = NPEventModelCarbon; 1063 #else 1064 eventModel = NPEventModelCocoa; 1065 #endif // NP_NO_CARBON 1066 } 1067 1068 #ifndef NP_NO_CARBON 1069 if (eventModel == NPEventModelCocoa && isDrawingModelQuickDraw(drawingModel)) { 1070 LOG(Plugins, "Plugin can't use use Cocoa event model with QuickDraw drawing model: %@", _pluginPackage.get()); 1071 [self _destroyPlugin]; 1072 [_pluginPackage.get() close]; 1073 1074 return NO; 1075 } 1076 #endif // NP_NO_CARBON 1077 1078 #ifndef BUILDING_ON_TIGER 1079 if (drawingModel == NPDrawingModelCoreAnimation) { 1080 void *value = 0; 1081 if ([_pluginPackage.get() pluginFuncs]->getvalue(plugin, NPPVpluginCoreAnimationLayer, &value) == NPERR_NO_ERROR && value) { 1082 1083 // The plug-in gives us a retained layer. 1084 _pluginLayer.adoptNS((CALayer *)value); 1085 1086 BOOL accleratedCompositingEnabled = false; 1087 #if USE(ACCELERATED_COMPOSITING) 1088 accleratedCompositingEnabled = [[[self webView] preferences] acceleratedCompositingEnabled]; 1089 #endif 1090 if (accleratedCompositingEnabled) 1091 [self element]->setNeedsStyleRecalc(SyntheticStyleChange); 1092 else 1093 [self setWantsLayer:YES]; 1094 LOG(Plugins, "%@ is using Core Animation drawing model with layer %@", _pluginPackage.get(), _pluginLayer.get()); 1095 } 1096 1097 ASSERT(_pluginLayer); 1098 } 1099 #endif 1100 1101 // Create the event handler 1102 _eventHandler.set(WebNetscapePluginEventHandler::create(self)); 1103 1104 return YES; 1105 } 1106 1107 #ifndef BUILDING_ON_TIGER 1108 // FIXME: This method is an ideal candidate to move up to the base class 1109 - (CALayer *)pluginLayer 1110 { 1111 return _pluginLayer.get(); 1112 } 1113 1114 - (void)setLayer:(CALayer *)newLayer 1115 { 1116 [super setLayer:newLayer]; 1117 1118 if (newLayer && _pluginLayer) { 1119 _pluginLayer.get().frame = [newLayer frame]; 1120 _pluginLayer.get().autoresizingMask = kCALayerWidthSizable | kCALayerHeightSizable; 1121 [newLayer addSublayer:_pluginLayer.get()]; 1122 } 1123 } 1124 #endif 1125 1126 - (void)loadStream 1127 { 1128 if ([self _shouldCancelSrcStream]) 1129 return; 1130 1131 if (_loadManually) { 1132 [self _redeliverStream]; 1133 return; 1134 } 1135 1136 // If the OBJECT/EMBED tag has no SRC, the URL is passed to us as "". 1137 // Check for this and don't start a load in this case. 1138 if (_sourceURL && ![_sourceURL.get() _web_isEmpty]) { 1139 NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:_sourceURL.get()]; 1140 [request _web_setHTTPReferrer:core([self webFrame])->loader()->outgoingReferrer()]; 1141 [self loadRequest:request inTarget:nil withNotifyData:nil sendNotification:NO]; 1142 } 1143 } 1144 1145 - (BOOL)shouldStop 1146 { 1147 // If we're already calling a plug-in function, do not call NPP_Destroy(). The plug-in function we are calling 1148 // may assume that its instance->pdata, or other memory freed by NPP_Destroy(), is valid and unchanged until said 1149 // plugin-function returns. 1150 // See <rdar://problem/4480737>. 1151 if (pluginFunctionCallDepth > 0) { 1152 shouldStopSoon = YES; 1153 return NO; 1154 } 1155 1156 return YES; 1157 } 1158 1159 - (void)destroyPlugin 1160 { 1161 // To stop active streams it's necessary to invoke stop() on a copy 1162 // of streams. This is because calling WebNetscapePluginStream::stop() also has the side effect 1163 // of removing a stream from this hash set. 1164 Vector<RefPtr<WebNetscapePluginStream> > streamsCopy; 1165 copyToVector(streams, streamsCopy); 1166 for (size_t i = 0; i < streamsCopy.size(); i++) 1167 streamsCopy[i]->stop(); 1168 1169 [[_pendingFrameLoads.get() allKeys] makeObjectsPerformSelector:@selector(_setInternalLoadDelegate:) withObject:nil]; 1170 [NSObject cancelPreviousPerformRequestsWithTarget:self]; 1171 1172 // Setting the window type to 0 ensures that NPP_SetWindow will be called if the plug-in is restarted. 1173 lastSetWindow.type = (NPWindowType)0; 1174 1175 #ifndef BUILDING_ON_TIGER 1176 _pluginLayer = 0; 1177 #endif 1178 1179 [self _destroyPlugin]; 1180 [_pluginPackage.get() close]; 1181 1182 _eventHandler.clear(); 1183 } 1184 1185 - (NPEventModel)eventModel 1186 { 1187 return eventModel; 1188 } 1189 1190 - (NPP)plugin 1191 { 1192 return plugin; 1193 } 1194 1195 - (void)setAttributeKeys:(NSArray *)keys andValues:(NSArray *)values 1196 { 1197 ASSERT([keys count] == [values count]); 1198 1199 // Convert the attributes to 2 C string arrays. 1200 // These arrays are passed to NPP_New, but the strings need to be 1201 // modifiable and live the entire life of the plugin. 1202 1203 // The Java plug-in requires the first argument to be the base URL 1204 if ([_MIMEType.get() isEqualToString:@"application/x-java-applet"]) { 1205 cAttributes = (char **)malloc(([keys count] + 1) * sizeof(char *)); 1206 cValues = (char **)malloc(([values count] + 1) * sizeof(char *)); 1207 cAttributes[0] = strdup("DOCBASE"); 1208 cValues[0] = strdup([_baseURL.get() _web_URLCString]); 1209 argsCount++; 1210 } else { 1211 cAttributes = (char **)malloc([keys count] * sizeof(char *)); 1212 cValues = (char **)malloc([values count] * sizeof(char *)); 1213 } 1214 1215 BOOL isWMP = [[[_pluginPackage.get() bundle] bundleIdentifier] isEqualToString:@"com.microsoft.WMP.defaultplugin"]; 1216 1217 unsigned i; 1218 unsigned count = [keys count]; 1219 for (i = 0; i < count; i++) { 1220 NSString *key = [keys objectAtIndex:i]; 1221 NSString *value = [values objectAtIndex:i]; 1222 if ([key _webkit_isCaseInsensitiveEqualToString:@"height"]) { 1223 specifiedHeight = [value intValue]; 1224 } else if ([key _webkit_isCaseInsensitiveEqualToString:@"width"]) { 1225 specifiedWidth = [value intValue]; 1226 } 1227 // Avoid Window Media Player crash when these attributes are present. 1228 if (isWMP && ([key _webkit_isCaseInsensitiveEqualToString:@"SAMIStyle"] || [key _webkit_isCaseInsensitiveEqualToString:@"SAMILang"])) { 1229 continue; 1230 } 1231 cAttributes[argsCount] = strdup([key UTF8String]); 1232 cValues[argsCount] = strdup([value UTF8String]); 1233 LOG(Plugins, "%@ = %@", key, value); 1234 argsCount++; 1235 } 1236 } 1237 1238 - (uint32)checkIfAllowedToLoadURL:(const char*)urlCString frame:(const char*)frameNameCString 1239 callbackFunc:(void (*)(NPP npp, uint32 checkID, NPBool allowed, void* context))callbackFunc 1240 context:(void*)context 1241 { 1242 if (!_containerChecksInProgress) 1243 _containerChecksInProgress = [[NSMutableDictionary alloc] init]; 1244 1245 NSString *frameName = frameNameCString ? [NSString stringWithCString:frameNameCString encoding:NSISOLatin1StringEncoding] : nil; 1246 1247 ++_currentContainerCheckRequestID; 1248 WebNetscapeContainerCheckContextInfo *contextInfo = [[WebNetscapeContainerCheckContextInfo alloc] initWithCheckRequestID:_currentContainerCheckRequestID 1249 callbackFunc:callbackFunc 1250 context:context]; 1251 1252 WebPluginContainerCheck *check = [WebPluginContainerCheck checkWithRequest:[self requestWithURLCString:urlCString] 1253 target:frameName 1254 resultObject:self 1255 selector:@selector(_containerCheckResult:contextInfo:) 1256 controller:self 1257 contextInfo:contextInfo]; 1258 1259 [contextInfo release]; 1260 [_containerChecksInProgress setObject:check forKey:[NSNumber numberWithInt:_currentContainerCheckRequestID]]; 1261 [check start]; 1262 1263 return _currentContainerCheckRequestID; 1264 } 1265 1266 - (void)_containerCheckResult:(PolicyAction)policy contextInfo:(id)contextInfo 1267 { 1268 ASSERT([contextInfo isKindOfClass:[WebNetscapeContainerCheckContextInfo class]]); 1269 void (*pluginCallback)(NPP npp, uint32, NPBool, void*) = [contextInfo callback]; 1270 1271 if (!pluginCallback) { 1272 ASSERT_NOT_REACHED(); 1273 return; 1274 } 1275 1276 pluginCallback([self plugin], [contextInfo checkRequestID], (policy == PolicyUse), [contextInfo context]); 1277 } 1278 1279 - (void)cancelCheckIfAllowedToLoadURL:(uint32)checkID 1280 { 1281 WebPluginContainerCheck *check = (WebPluginContainerCheck *)[_containerChecksInProgress objectForKey:[NSNumber numberWithInt:checkID]]; 1282 1283 if (!check) 1284 return; 1285 1286 [check cancel]; 1287 [_containerChecksInProgress removeObjectForKey:[NSNumber numberWithInt:checkID]]; 1288 } 1289 1290 // WebPluginContainerCheck automatically calls this method after invoking our _containerCheckResult: selector. 1291 // It works this way because calling -[WebPluginContainerCheck cancel] allows it to do it's teardown process. 1292 - (void)_webPluginContainerCancelCheckIfAllowedToLoadRequest:(id)webPluginContainerCheck 1293 { 1294 ASSERT([webPluginContainerCheck isKindOfClass:[WebPluginContainerCheck class]]); 1295 WebPluginContainerCheck *check = (WebPluginContainerCheck *)webPluginContainerCheck; 1296 ASSERT([[check contextInfo] isKindOfClass:[WebNetscapeContainerCheckContextInfo class]]); 1297 1298 [self cancelCheckIfAllowedToLoadURL:[[check contextInfo] checkRequestID]]; 1299 } 1300 1301 #ifdef BUILDING_ON_TIGER 1302 // The Tiger compiler requires these two methods be present. Otherwise it doesn't think WebNetscapePluginView 1303 // conforms to the WebPluginContainerCheckController protocol. 1304 - (WebView *)webView 1305 { 1306 return [super webView]; 1307 } 1308 1309 - (WebFrame *)webFrame 1310 { 1311 return [super webFrame]; 1312 } 1313 #endif 1314 1315 #pragma mark NSVIEW 1316 1317 - (id)initWithFrame:(NSRect)frame 1318 pluginPackage:(WebNetscapePluginPackage *)pluginPackage 1319 URL:(NSURL *)URL 1320 baseURL:(NSURL *)baseURL 1321 MIMEType:(NSString *)MIME 1322 attributeKeys:(NSArray *)keys 1323 attributeValues:(NSArray *)values 1324 loadManually:(BOOL)loadManually 1325 element:(PassRefPtr<WebCore::HTMLPlugInElement>)element 1326 { 1327 self = [super initWithFrame:frame pluginPackage:pluginPackage URL:URL baseURL:baseURL MIMEType:MIME attributeKeys:keys attributeValues:values loadManually:loadManually element:element]; 1328 if (!self) 1329 return nil; 1330 1331 _pendingFrameLoads.adoptNS([[NSMutableDictionary alloc] init]); 1332 1333 // load the plug-in if it is not already loaded 1334 if (![pluginPackage load]) { 1335 [self release]; 1336 return nil; 1337 } 1338 1339 return self; 1340 } 1341 1342 - (id)initWithFrame:(NSRect)frame 1343 { 1344 ASSERT_NOT_REACHED(); 1345 return nil; 1346 } 1347 1348 - (void)fini 1349 { 1350 #ifndef NP_NO_QUICKDRAW 1351 if (offscreenGWorld) 1352 DisposeGWorld(offscreenGWorld); 1353 #endif 1354 1355 for (unsigned i = 0; i < argsCount; i++) { 1356 free(cAttributes[i]); 1357 free(cValues[i]); 1358 } 1359 free(cAttributes); 1360 free(cValues); 1361 1362 ASSERT(!_eventHandler); 1363 1364 if (timers) { 1365 deleteAllValues(*timers); 1366 delete timers; 1367 } 1368 1369 [_containerChecksInProgress release]; 1370 } 1371 1372 - (void)disconnectStream:(WebNetscapePluginStream*)stream 1373 { 1374 streams.remove(stream); 1375 } 1376 1377 - (void)dealloc 1378 { 1379 ASSERT(!_isStarted); 1380 ASSERT(!plugin); 1381 1382 [self fini]; 1383 1384 [super dealloc]; 1385 } 1386 1387 - (void)finalize 1388 { 1389 ASSERT_MAIN_THREAD(); 1390 ASSERT(!_isStarted); 1391 1392 [self fini]; 1393 1394 [super finalize]; 1395 } 1396 1397 - (void)drawRect:(NSRect)rect 1398 { 1399 if (drawingModel == NPDrawingModelCoreAnimation) 1400 return; 1401 1402 if (!_isStarted) 1403 return; 1404 1405 if ([NSGraphicsContext currentContextDrawingToScreen]) 1406 [self sendDrawRectEvent:rect]; 1407 else { 1408 NSBitmapImageRep *printedPluginBitmap = [self _printedPluginBitmap]; 1409 if (printedPluginBitmap) { 1410 // Flip the bitmap before drawing because the QuickDraw port is flipped relative 1411 // to this view. 1412 CGContextRef cgContext = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort]; 1413 CGContextSaveGState(cgContext); 1414 NSRect bounds = [self bounds]; 1415 CGContextTranslateCTM(cgContext, 0.0f, NSHeight(bounds)); 1416 CGContextScaleCTM(cgContext, 1.0f, -1.0f); 1417 [printedPluginBitmap drawInRect:bounds]; 1418 CGContextRestoreGState(cgContext); 1419 } 1420 } 1421 } 1422 1423 - (NPObject *)createPluginScriptableObject 1424 { 1425 if (![_pluginPackage.get() pluginFuncs]->getvalue || !_isStarted) 1426 return NULL; 1427 1428 NPObject *value = NULL; 1429 NPError error; 1430 [self willCallPlugInFunction]; 1431 { 1432 JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly); 1433 error = [_pluginPackage.get() pluginFuncs]->getvalue(plugin, NPPVpluginScriptableNPObject, &value); 1434 } 1435 [self didCallPlugInFunction]; 1436 if (error != NPERR_NO_ERROR) 1437 return NULL; 1438 1439 return value; 1440 } 1441 1442 - (void)willCallPlugInFunction 1443 { 1444 ASSERT(plugin); 1445 1446 // Could try to prevent infinite recursion here, but it's probably not worth the effort. 1447 pluginFunctionCallDepth++; 1448 } 1449 1450 - (void)didCallPlugInFunction 1451 { 1452 ASSERT(pluginFunctionCallDepth > 0); 1453 pluginFunctionCallDepth--; 1454 1455 // If -stop was called while we were calling into a plug-in function, and we're no longer 1456 // inside a plug-in function, stop now. 1457 if (pluginFunctionCallDepth == 0 && shouldStopSoon) { 1458 shouldStopSoon = NO; 1459 [self stop]; 1460 } 1461 } 1462 1463 -(void)pluginView:(NSView *)pluginView receivedResponse:(NSURLResponse *)response 1464 { 1465 ASSERT(_loadManually); 1466 ASSERT(!_manualStream); 1467 1468 _manualStream = WebNetscapePluginStream::create(core([self webFrame])->loader()); 1469 } 1470 1471 - (void)pluginView:(NSView *)pluginView receivedData:(NSData *)data 1472 { 1473 ASSERT(_loadManually); 1474 ASSERT(_manualStream); 1475 1476 _dataLengthReceived += [data length]; 1477 1478 if (!_isStarted) 1479 return; 1480 1481 if (!_manualStream->plugin()) { 1482 // Check if the load should be cancelled 1483 if ([self _shouldCancelSrcStream]) { 1484 NSURLResponse *response = [[self dataSource] response]; 1485 1486 NSError *error = [[NSError alloc] _initWithPluginErrorCode:WebKitErrorPlugInWillHandleLoad 1487 contentURL:[response URL] 1488 pluginPageURL:nil 1489 pluginName:nil // FIXME: Get this from somewhere 1490 MIMEType:[response MIMEType]]; 1491 [[self dataSource] _documentLoader]->cancelMainResourceLoad(error); 1492 [error release]; 1493 return; 1494 } 1495 1496 _manualStream->setRequestURL([[[self dataSource] request] URL]); 1497 _manualStream->setPlugin([self plugin]); 1498 ASSERT(_manualStream->plugin()); 1499 1500 _manualStream->startStreamWithResponse([[self dataSource] response]); 1501 } 1502 1503 if (_manualStream->plugin()) 1504 _manualStream->didReceiveData(0, static_cast<const char *>([data bytes]), [data length]); 1505 } 1506 1507 - (void)pluginView:(NSView *)pluginView receivedError:(NSError *)error 1508 { 1509 ASSERT(_loadManually); 1510 1511 _error = error; 1512 1513 if (!_isStarted) { 1514 return; 1515 } 1516 1517 _manualStream->destroyStreamWithError(error); 1518 } 1519 1520 - (void)pluginViewFinishedLoading:(NSView *)pluginView 1521 { 1522 ASSERT(_loadManually); 1523 ASSERT(_manualStream); 1524 1525 if (_isStarted) 1526 _manualStream->didFinishLoading(0); 1527 } 1528 1529 - (NSTextInputContext *)inputContext 1530 { 1531 return nil; 1532 } 1533 1534 @end 1535 1536 @implementation WebNetscapePluginView (WebNPPCallbacks) 1537 1538 - (void)evaluateJavaScriptPluginRequest:(WebPluginRequest *)JSPluginRequest 1539 { 1540 // FIXME: Is this isStarted check needed here? evaluateJavaScriptPluginRequest should not be called 1541 // if we are stopped since this method is called after a delay and we call 1542 // cancelPreviousPerformRequestsWithTarget inside of stop. 1543 if (!_isStarted) { 1544 return; 1545 } 1546 1547 NSURL *URL = [[JSPluginRequest request] URL]; 1548 NSString *JSString = [URL _webkit_scriptIfJavaScriptURL]; 1549 ASSERT(JSString); 1550 1551 NSString *result = [[self webFrame] _stringByEvaluatingJavaScriptFromString:JSString forceUserGesture:[JSPluginRequest isCurrentEventUserGesture]]; 1552 1553 // Don't continue if stringByEvaluatingJavaScriptFromString caused the plug-in to stop. 1554 if (!_isStarted) { 1555 return; 1556 } 1557 1558 if ([JSPluginRequest frameName] != nil) { 1559 // FIXME: If the result is a string, we probably want to put that string into the frame. 1560 if ([JSPluginRequest sendNotification]) { 1561 [self willCallPlugInFunction]; 1562 { 1563 JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly); 1564 [_pluginPackage.get() pluginFuncs]->urlnotify(plugin, [URL _web_URLCString], NPRES_DONE, [JSPluginRequest notifyData]); 1565 } 1566 [self didCallPlugInFunction]; 1567 } 1568 } else if ([result length] > 0) { 1569 // Don't call NPP_NewStream and other stream methods if there is no JS result to deliver. This is what Mozilla does. 1570 NSData *JSData = [result dataUsingEncoding:NSUTF8StringEncoding]; 1571 1572 RefPtr<WebNetscapePluginStream> stream = WebNetscapePluginStream::create([NSURLRequest requestWithURL:URL], plugin, [JSPluginRequest sendNotification], [JSPluginRequest notifyData]); 1573 1574 RetainPtr<NSURLResponse> response(AdoptNS, [[NSURLResponse alloc] initWithURL:URL 1575 MIMEType:@"text/plain" 1576 expectedContentLength:[JSData length] 1577 textEncodingName:nil]); 1578 1579 stream->startStreamWithResponse(response.get()); 1580 stream->didReceiveData(0, static_cast<const char*>([JSData bytes]), [JSData length]); 1581 stream->didFinishLoading(0); 1582 } 1583 } 1584 1585 - (void)webFrame:(WebFrame *)webFrame didFinishLoadWithReason:(NPReason)reason 1586 { 1587 ASSERT(_isStarted); 1588 1589 WebPluginRequest *pluginRequest = [_pendingFrameLoads.get() objectForKey:webFrame]; 1590 ASSERT(pluginRequest != nil); 1591 ASSERT([pluginRequest sendNotification]); 1592 1593 [self willCallPlugInFunction]; 1594 { 1595 JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly); 1596 [_pluginPackage.get() pluginFuncs]->urlnotify(plugin, [[[pluginRequest request] URL] _web_URLCString], reason, [pluginRequest notifyData]); 1597 } 1598 [self didCallPlugInFunction]; 1599 1600 [_pendingFrameLoads.get() removeObjectForKey:webFrame]; 1601 [webFrame _setInternalLoadDelegate:nil]; 1602 } 1603 1604 - (void)webFrame:(WebFrame *)webFrame didFinishLoadWithError:(NSError *)error 1605 { 1606 NPReason reason = NPRES_DONE; 1607 if (error != nil) 1608 reason = WebNetscapePluginStream::reasonForError(error); 1609 [self webFrame:webFrame didFinishLoadWithReason:reason]; 1610 } 1611 1612 - (void)loadPluginRequest:(WebPluginRequest *)pluginRequest 1613 { 1614 NSURLRequest *request = [pluginRequest request]; 1615 NSString *frameName = [pluginRequest frameName]; 1616 WebFrame *frame = nil; 1617 1618 NSURL *URL = [request URL]; 1619 NSString *JSString = [URL _webkit_scriptIfJavaScriptURL]; 1620 1621 ASSERT(frameName || JSString); 1622 1623 if (frameName) { 1624 // FIXME - need to get rid of this window creation which 1625 // bypasses normal targeted link handling 1626 frame = kit(core([self webFrame])->loader()->findFrameForNavigation(frameName)); 1627 if (frame == nil) { 1628 WebView *currentWebView = [self webView]; 1629 NSDictionary *features = [[NSDictionary alloc] init]; 1630 WebView *newWebView = [[currentWebView _UIDelegateForwarder] webView:currentWebView 1631 createWebViewWithRequest:nil 1632 windowFeatures:features]; 1633 [features release]; 1634 1635 if (!newWebView) { 1636 if ([pluginRequest sendNotification]) { 1637 [self willCallPlugInFunction]; 1638 { 1639 JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly); 1640 [_pluginPackage.get() pluginFuncs]->urlnotify(plugin, [[[pluginRequest request] URL] _web_URLCString], NPERR_GENERIC_ERROR, [pluginRequest notifyData]); 1641 } 1642 [self didCallPlugInFunction]; 1643 } 1644 return; 1645 } 1646 1647 frame = [newWebView mainFrame]; 1648 core(frame)->tree()->setName(frameName); 1649 [[newWebView _UIDelegateForwarder] webViewShow:newWebView]; 1650 } 1651 } 1652 1653 if (JSString) { 1654 ASSERT(frame == nil || [self webFrame] == frame); 1655 [self evaluateJavaScriptPluginRequest:pluginRequest]; 1656 } else { 1657 [frame loadRequest:request]; 1658 if ([pluginRequest sendNotification]) { 1659 // Check if another plug-in view or even this view is waiting for the frame to load. 1660 // If it is, tell it that the load was cancelled because it will be anyway. 1661 WebNetscapePluginView *view = [frame _internalLoadDelegate]; 1662 if (view != nil) { 1663 ASSERT([view isKindOfClass:[WebNetscapePluginView class]]); 1664 [view webFrame:frame didFinishLoadWithReason:NPRES_USER_BREAK]; 1665 } 1666 [_pendingFrameLoads.get() _webkit_setObject:pluginRequest forUncopiedKey:frame]; 1667 [frame _setInternalLoadDelegate:self]; 1668 } 1669 } 1670 } 1671 1672 - (NPError)loadRequest:(NSMutableURLRequest *)request inTarget:(const char *)cTarget withNotifyData:(void *)notifyData sendNotification:(BOOL)sendNotification 1673 { 1674 NSURL *URL = [request URL]; 1675 1676 if (!URL) 1677 return NPERR_INVALID_URL; 1678 1679 // Don't allow requests to be loaded when the document loader is stopping all loaders. 1680 if ([[self dataSource] _documentLoader]->isStopping()) 1681 return NPERR_GENERIC_ERROR; 1682 1683 NSString *target = nil; 1684 if (cTarget) { 1685 // Find the frame given the target string. 1686 target = [NSString stringWithCString:cTarget encoding:NSISOLatin1StringEncoding]; 1687 } 1688 WebFrame *frame = [self webFrame]; 1689 1690 // don't let a plugin start any loads if it is no longer part of a document that is being 1691 // displayed unless the loads are in the same frame as the plugin. 1692 if ([[self dataSource] _documentLoader] != core([self webFrame])->loader()->activeDocumentLoader() && 1693 (!cTarget || [frame findFrameNamed:target] != frame)) { 1694 return NPERR_GENERIC_ERROR; 1695 } 1696 1697 NSString *JSString = [URL _webkit_scriptIfJavaScriptURL]; 1698 if (JSString != nil) { 1699 if (![[[self webView] preferences] isJavaScriptEnabled]) { 1700 // Return NPERR_GENERIC_ERROR if JS is disabled. This is what Mozilla does. 1701 return NPERR_GENERIC_ERROR; 1702 } else if (cTarget == NULL && _mode == NP_FULL) { 1703 // Don't allow a JavaScript request from a standalone plug-in that is self-targetted 1704 // because this can cause the user to be redirected to a blank page (3424039). 1705 return NPERR_INVALID_PARAM; 1706 } 1707 } else { 1708 if (!SecurityOrigin::canLoad(URL, String(), core([self webFrame])->document())) 1709 return NPERR_GENERIC_ERROR; 1710 } 1711 1712 if (cTarget || JSString) { 1713 // Make when targetting a frame or evaluating a JS string, perform the request after a delay because we don't 1714 // want to potentially kill the plug-in inside of its URL request. 1715 1716 if (JSString && target && [frame findFrameNamed:target] != frame) { 1717 // For security reasons, only allow JS requests to be made on the frame that contains the plug-in. 1718 return NPERR_INVALID_PARAM; 1719 } 1720 1721 bool currentEventIsUserGesture = false; 1722 if (_eventHandler) 1723 currentEventIsUserGesture = _eventHandler->currentEventIsUserGesture(); 1724 1725 WebPluginRequest *pluginRequest = [[WebPluginRequest alloc] initWithRequest:request 1726 frameName:target 1727 notifyData:notifyData 1728 sendNotification:sendNotification 1729 didStartFromUserGesture:currentEventIsUserGesture]; 1730 [self performSelector:@selector(loadPluginRequest:) withObject:pluginRequest afterDelay:0]; 1731 [pluginRequest release]; 1732 } else { 1733 RefPtr<WebNetscapePluginStream> stream = WebNetscapePluginStream::create(request, plugin, sendNotification, notifyData); 1734 1735 streams.add(stream.get()); 1736 stream->start(); 1737 } 1738 1739 return NPERR_NO_ERROR; 1740 } 1741 1742 -(NPError)getURLNotify:(const char *)URLCString target:(const char *)cTarget notifyData:(void *)notifyData 1743 { 1744 LOG(Plugins, "NPN_GetURLNotify: %s target: %s", URLCString, cTarget); 1745 1746 NSMutableURLRequest *request = [self requestWithURLCString:URLCString]; 1747 return [self loadRequest:request inTarget:cTarget withNotifyData:notifyData sendNotification:YES]; 1748 } 1749 1750 -(NPError)getURL:(const char *)URLCString target:(const char *)cTarget 1751 { 1752 LOG(Plugins, "NPN_GetURL: %s target: %s", URLCString, cTarget); 1753 1754 NSMutableURLRequest *request = [self requestWithURLCString:URLCString]; 1755 return [self loadRequest:request inTarget:cTarget withNotifyData:NULL sendNotification:NO]; 1756 } 1757 1758 - (NPError)_postURL:(const char *)URLCString 1759 target:(const char *)target 1760 len:(UInt32)len 1761 buf:(const char *)buf 1762 file:(NPBool)file 1763 notifyData:(void *)notifyData 1764 sendNotification:(BOOL)sendNotification 1765 allowHeaders:(BOOL)allowHeaders 1766 { 1767 if (!URLCString || !len || !buf) { 1768 return NPERR_INVALID_PARAM; 1769 } 1770 1771 NSData *postData = nil; 1772 1773 if (file) { 1774 // If we're posting a file, buf is either a file URL or a path to the file. 1775 NSString *bufString = (NSString *)CFStringCreateWithCString(kCFAllocatorDefault, buf, kCFStringEncodingWindowsLatin1); 1776 if (!bufString) { 1777 return NPERR_INVALID_PARAM; 1778 } 1779 NSURL *fileURL = [NSURL _web_URLWithDataAsString:bufString]; 1780 NSString *path; 1781 if ([fileURL isFileURL]) { 1782 path = [fileURL path]; 1783 } else { 1784 path = bufString; 1785 } 1786 postData = [NSData dataWithContentsOfFile:[path _webkit_fixedCarbonPOSIXPath]]; 1787 CFRelease(bufString); 1788 if (!postData) { 1789 return NPERR_FILE_NOT_FOUND; 1790 } 1791 } else { 1792 postData = [NSData dataWithBytes:buf length:len]; 1793 } 1794 1795 if ([postData length] == 0) { 1796 return NPERR_INVALID_PARAM; 1797 } 1798 1799 NSMutableURLRequest *request = [self requestWithURLCString:URLCString]; 1800 [request setHTTPMethod:@"POST"]; 1801 1802 if (allowHeaders) { 1803 if ([postData _web_startsWithBlankLine]) { 1804 postData = [postData subdataWithRange:NSMakeRange(1, [postData length] - 1)]; 1805 } else { 1806 NSInteger location = [postData _web_locationAfterFirstBlankLine]; 1807 if (location != NSNotFound) { 1808 // If the blank line is somewhere in the middle of postData, everything before is the header. 1809 NSData *headerData = [postData subdataWithRange:NSMakeRange(0, location)]; 1810 NSMutableDictionary *header = [headerData _webkit_parseRFC822HeaderFields]; 1811 unsigned dataLength = [postData length] - location; 1812 1813 // Sometimes plugins like to set Content-Length themselves when they post, 1814 // but WebFoundation does not like that. So we will remove the header 1815 // and instead truncate the data to the requested length. 1816 NSString *contentLength = [header objectForKey:@"Content-Length"]; 1817 1818 if (contentLength != nil) 1819 dataLength = min<unsigned>([contentLength intValue], dataLength); 1820 [header removeObjectForKey:@"Content-Length"]; 1821 1822 if ([header count] > 0) { 1823 [request setAllHTTPHeaderFields:header]; 1824 } 1825 // Everything after the blank line is the actual content of the POST. 1826 postData = [postData subdataWithRange:NSMakeRange(location, dataLength)]; 1827 1828 } 1829 } 1830 if ([postData length] == 0) { 1831 return NPERR_INVALID_PARAM; 1832 } 1833 } 1834 1835 // Plug-ins expect to receive uncached data when doing a POST (3347134). 1836 [request setCachePolicy:NSURLRequestReloadIgnoringCacheData]; 1837 [request setHTTPBody:postData]; 1838 1839 return [self loadRequest:request inTarget:target withNotifyData:notifyData sendNotification:sendNotification]; 1840 } 1841 1842 - (NPError)postURLNotify:(const char *)URLCString 1843 target:(const char *)target 1844 len:(UInt32)len 1845 buf:(const char *)buf 1846 file:(NPBool)file 1847 notifyData:(void *)notifyData 1848 { 1849 LOG(Plugins, "NPN_PostURLNotify: %s", URLCString); 1850 return [self _postURL:URLCString target:target len:len buf:buf file:file notifyData:notifyData sendNotification:YES allowHeaders:YES]; 1851 } 1852 1853 -(NPError)postURL:(const char *)URLCString 1854 target:(const char *)target 1855 len:(UInt32)len 1856 buf:(const char *)buf 1857 file:(NPBool)file 1858 { 1859 LOG(Plugins, "NPN_PostURL: %s", URLCString); 1860 // As documented, only allow headers to be specified via NPP_PostURL when using a file. 1861 return [self _postURL:URLCString target:target len:len buf:buf file:file notifyData:NULL sendNotification:NO allowHeaders:file]; 1862 } 1863 1864 -(NPError)newStream:(NPMIMEType)type target:(const char *)target stream:(NPStream**)stream 1865 { 1866 LOG(Plugins, "NPN_NewStream"); 1867 return NPERR_GENERIC_ERROR; 1868 } 1869 1870 -(NPError)write:(NPStream*)stream len:(SInt32)len buffer:(void *)buffer 1871 { 1872 LOG(Plugins, "NPN_Write"); 1873 return NPERR_GENERIC_ERROR; 1874 } 1875 1876 -(NPError)destroyStream:(NPStream*)stream reason:(NPReason)reason 1877 { 1878 LOG(Plugins, "NPN_DestroyStream"); 1879 // This function does a sanity check to ensure that the NPStream provided actually 1880 // belongs to the plug-in that provided it, which fixes a crash in the DivX 1881 // plug-in: <rdar://problem/5093862> | http://bugs.webkit.org/show_bug.cgi?id=13203 1882 if (!stream || WebNetscapePluginStream::ownerForStream(stream) != plugin) { 1883 LOG(Plugins, "Invalid NPStream passed to NPN_DestroyStream: %p", stream); 1884 return NPERR_INVALID_INSTANCE_ERROR; 1885 } 1886 1887 WebNetscapePluginStream* browserStream = static_cast<WebNetscapePluginStream*>(stream->ndata); 1888 browserStream->cancelLoadAndDestroyStreamWithError(browserStream->errorForReason(reason)); 1889 1890 return NPERR_NO_ERROR; 1891 } 1892 1893 - (const char *)userAgent 1894 { 1895 NSString *userAgent = [[self webView] userAgentForURL:_baseURL.get()]; 1896 1897 if (_isSilverlight) { 1898 // Silverlight has a workaround for a leak in Safari 2. This workaround is 1899 // applied when the user agent does not contain "Version/3" so we append it 1900 // at the end of the user agent. 1901 userAgent = [userAgent stringByAppendingString:@" Version/3.2.1"]; 1902 } 1903 1904 return [userAgent UTF8String]; 1905 } 1906 1907 -(void)status:(const char *)message 1908 { 1909 if (!message) { 1910 LOG_ERROR("NPN_Status passed a NULL status message"); 1911 return; 1912 } 1913 1914 CFStringRef status = CFStringCreateWithCString(NULL, message, kCFStringEncodingUTF8); 1915 if (!status) { 1916 LOG_ERROR("NPN_Status: the message was not valid UTF-8"); 1917 return; 1918 } 1919 1920 LOG(Plugins, "NPN_Status: %@", status); 1921 WebView *wv = [self webView]; 1922 [[wv _UIDelegateForwarder] webView:wv setStatusText:(NSString *)status]; 1923 CFRelease(status); 1924 } 1925 1926 -(void)invalidateRect:(NPRect *)invalidRect 1927 { 1928 LOG(Plugins, "NPN_InvalidateRect"); 1929 [self invalidatePluginContentRect:NSMakeRect(invalidRect->left, invalidRect->top, 1930 (float)invalidRect->right - invalidRect->left, (float)invalidRect->bottom - invalidRect->top)]; 1931 } 1932 1933 - (void)invalidateRegion:(NPRegion)invalidRegion 1934 { 1935 LOG(Plugins, "NPN_InvalidateRegion"); 1936 NSRect invalidRect = NSZeroRect; 1937 switch (drawingModel) { 1938 #ifndef NP_NO_QUICKDRAW 1939 case NPDrawingModelQuickDraw: 1940 { 1941 ::Rect qdRect; 1942 GetRegionBounds((NPQDRegion)invalidRegion, &qdRect); 1943 invalidRect = NSMakeRect(qdRect.left, qdRect.top, qdRect.right - qdRect.left, qdRect.bottom - qdRect.top); 1944 } 1945 break; 1946 #endif /* NP_NO_QUICKDRAW */ 1947 1948 case NPDrawingModelCoreGraphics: 1949 { 1950 CGRect cgRect = CGPathGetBoundingBox((NPCGRegion)invalidRegion); 1951 invalidRect = *(NSRect*)&cgRect; 1952 break; 1953 } 1954 default: 1955 ASSERT_NOT_REACHED(); 1956 break; 1957 } 1958 1959 [self invalidatePluginContentRect:invalidRect]; 1960 } 1961 1962 -(void)forceRedraw 1963 { 1964 LOG(Plugins, "forceRedraw"); 1965 [self invalidatePluginContentRect:[self bounds]]; 1966 [[self window] displayIfNeeded]; 1967 } 1968 1969 - (NPError)getVariable:(NPNVariable)variable value:(void *)value 1970 { 1971 switch (variable) { 1972 case NPNVWindowNPObject: 1973 { 1974 Frame* frame = core([self webFrame]); 1975 NPObject* windowScriptObject = frame ? frame->script()->windowScriptNPObject() : 0; 1976 1977 // Return value is expected to be retained, as described here: <http://www.mozilla.org/projects/plugins/npruntime.html#browseraccess> 1978 if (windowScriptObject) 1979 _NPN_RetainObject(windowScriptObject); 1980 1981 void **v = (void **)value; 1982 *v = windowScriptObject; 1983 1984 return NPERR_NO_ERROR; 1985 } 1986 1987 case NPNVPluginElementNPObject: 1988 { 1989 if (!_element) 1990 return NPERR_GENERIC_ERROR; 1991 1992 NPObject *plugInScriptObject = _element->getNPObject(); 1993 1994 // Return value is expected to be retained, as described here: <http://www.mozilla.org/projects/plugins/npruntime.html#browseraccess> 1995 if (plugInScriptObject) 1996 _NPN_RetainObject(plugInScriptObject); 1997 1998 void **v = (void **)value; 1999 *v = plugInScriptObject; 2000 2001 return NPERR_NO_ERROR; 2002 } 2003 2004 case NPNVpluginDrawingModel: 2005 { 2006 *(NPDrawingModel *)value = drawingModel; 2007 return NPERR_NO_ERROR; 2008 } 2009 2010 #ifndef NP_NO_QUICKDRAW 2011 case NPNVsupportsQuickDrawBool: 2012 { 2013 *(NPBool *)value = TRUE; 2014 return NPERR_NO_ERROR; 2015 } 2016 #endif /* NP_NO_QUICKDRAW */ 2017 2018 case NPNVsupportsCoreGraphicsBool: 2019 { 2020 *(NPBool *)value = TRUE; 2021 return NPERR_NO_ERROR; 2022 } 2023 2024 case NPNVsupportsOpenGLBool: 2025 { 2026 *(NPBool *)value = FALSE; 2027 return NPERR_NO_ERROR; 2028 } 2029 2030 case NPNVsupportsCoreAnimationBool: 2031 { 2032 #ifdef BUILDING_ON_TIGER 2033 *(NPBool *)value = FALSE; 2034 #else 2035 *(NPBool *)value = TRUE; 2036 #endif 2037 return NPERR_NO_ERROR; 2038 } 2039 2040 #ifndef NP_NO_CARBON 2041 case NPNVsupportsCarbonBool: 2042 { 2043 *(NPBool *)value = TRUE; 2044 return NPERR_NO_ERROR; 2045 } 2046 #endif /* NP_NO_CARBON */ 2047 2048 case NPNVsupportsCocoaBool: 2049 { 2050 *(NPBool *)value = TRUE; 2051 return NPERR_NO_ERROR; 2052 } 2053 2054 case NPNVprivateModeBool: 2055 { 2056 *(NPBool *)value = _isPrivateBrowsingEnabled; 2057 return NPERR_NO_ERROR; 2058 } 2059 2060 case WKNVBrowserContainerCheckFuncs: 2061 { 2062 *(WKNBrowserContainerCheckFuncs **)value = browserContainerCheckFuncs(); 2063 return NPERR_NO_ERROR; 2064 } 2065 #if USE(ACCELERATED_COMPOSITING) 2066 case WKNVSupportsCompositingCoreAnimationPluginsBool: 2067 { 2068 *(NPBool *)value = [[[self webView] preferences] acceleratedCompositingEnabled]; 2069 return NPERR_NO_ERROR; 2070 } 2071 #endif 2072 default: 2073 break; 2074 } 2075 2076 return NPERR_GENERIC_ERROR; 2077 } 2078 2079 - (NPError)setVariable:(NPPVariable)variable value:(void *)value 2080 { 2081 switch (variable) { 2082 case NPPVpluginDrawingModel: 2083 { 2084 // Can only set drawing model inside NPP_New() 2085 if (self != [[self class] currentPluginView]) 2086 return NPERR_GENERIC_ERROR; 2087 2088 // Check for valid, supported drawing model 2089 NPDrawingModel newDrawingModel = (NPDrawingModel)(uintptr_t)value; 2090 switch (newDrawingModel) { 2091 // Supported drawing models: 2092 #ifndef NP_NO_QUICKDRAW 2093 case NPDrawingModelQuickDraw: 2094 #endif 2095 case NPDrawingModelCoreGraphics: 2096 #ifndef BUILDING_ON_TIGER 2097 case NPDrawingModelCoreAnimation: 2098 #endif 2099 drawingModel = newDrawingModel; 2100 return NPERR_NO_ERROR; 2101 2102 2103 // Unsupported (or unknown) drawing models: 2104 default: 2105 LOG(Plugins, "Plugin %@ uses unsupported drawing model: %d", _eventHandler.get(), drawingModel); 2106 return NPERR_GENERIC_ERROR; 2107 } 2108 } 2109 2110 case NPPVpluginEventModel: 2111 { 2112 // Can only set event model inside NPP_New() 2113 if (self != [[self class] currentPluginView]) 2114 return NPERR_GENERIC_ERROR; 2115 2116 // Check for valid, supported event model 2117 NPEventModel newEventModel = (NPEventModel)(uintptr_t)value; 2118 switch (newEventModel) { 2119 // Supported event models: 2120 #ifndef NP_NO_CARBON 2121 case NPEventModelCarbon: 2122 #endif 2123 case NPEventModelCocoa: 2124 eventModel = newEventModel; 2125 return NPERR_NO_ERROR; 2126 2127 // Unsupported (or unknown) event models: 2128 default: 2129 LOG(Plugins, "Plugin %@ uses unsupported event model: %d", _eventHandler.get(), eventModel); 2130 return NPERR_GENERIC_ERROR; 2131 } 2132 } 2133 2134 default: 2135 return NPERR_GENERIC_ERROR; 2136 } 2137 } 2138 2139 - (uint32)scheduleTimerWithInterval:(uint32)interval repeat:(NPBool)repeat timerFunc:(void (*)(NPP npp, uint32 timerID))timerFunc 2140 { 2141 if (!timerFunc) 2142 return 0; 2143 2144 if (!timers) 2145 timers = new HashMap<uint32, PluginTimer*>; 2146 2147 uint32 timerID; 2148 2149 do { 2150 timerID = ++currentTimerID; 2151 } while (timers->contains(timerID) || timerID == 0); 2152 2153 PluginTimer* timer = new PluginTimer(plugin, timerID, interval, repeat, timerFunc); 2154 timers->set(timerID, timer); 2155 2156 if (_shouldFireTimers) 2157 timer->start(_isCompletelyObscured); 2158 2159 return timerID; 2160 } 2161 2162 - (void)unscheduleTimer:(uint32)timerID 2163 { 2164 if (!timers) 2165 return; 2166 2167 if (PluginTimer* timer = timers->take(timerID)) 2168 delete timer; 2169 } 2170 2171 - (NPError)popUpContextMenu:(NPMenu *)menu 2172 { 2173 NSEvent *currentEvent = [NSApp currentEvent]; 2174 2175 // NPN_PopUpContextMenu must be called from within the plug-in's NPP_HandleEvent. 2176 if (!currentEvent) 2177 return NPERR_GENERIC_ERROR; 2178 2179 [NSMenu popUpContextMenu:(NSMenu *)menu withEvent:currentEvent forView:self]; 2180 return NPERR_NO_ERROR; 2181 } 2182 2183 - (NPError)getVariable:(NPNURLVariable)variable forURL:(const char*)url value:(char**)value length:(uint32*)length 2184 { 2185 switch (variable) { 2186 case NPNURLVCookie: { 2187 if (!value) 2188 break; 2189 2190 NSURL *URL = [self URLWithCString:url]; 2191 if (!URL) 2192 break; 2193 2194 if (Frame* frame = core([self webFrame])) { 2195 String cookieString = cookies(frame->document(), URL); 2196 CString cookieStringUTF8 = cookieString.utf8(); 2197 if (cookieStringUTF8.isNull()) 2198 return NPERR_GENERIC_ERROR; 2199 2200 *value = static_cast<char*>(NPN_MemAlloc(cookieStringUTF8.length())); 2201 memcpy(*value, cookieStringUTF8.data(), cookieStringUTF8.length()); 2202 2203 if (length) 2204 *length = cookieStringUTF8.length(); 2205 return NPERR_NO_ERROR; 2206 } 2207 break; 2208 } 2209 case NPNURLVProxy: { 2210 #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) 2211 if (!value) 2212 break; 2213 2214 NSURL *URL = [self URLWithCString:url]; 2215 if (!URL) 2216 break; 2217 2218 CString proxiesUTF8 = proxiesForURL(URL); 2219 2220 *value = static_cast<char*>(NPN_MemAlloc(proxiesUTF8.length())); 2221 memcpy(*value, proxiesUTF8.data(), proxiesUTF8.length()); 2222 2223 if (length) 2224 *length = proxiesUTF8.length(); 2225 2226 return NPERR_NO_ERROR; 2227 #else 2228 break; 2229 #endif 2230 } 2231 } 2232 return NPERR_GENERIC_ERROR; 2233 } 2234 2235 - (NPError)setVariable:(NPNURLVariable)variable forURL:(const char*)url value:(const char*)value length:(uint32)length 2236 { 2237 switch (variable) { 2238 case NPNURLVCookie: { 2239 NSURL *URL = [self URLWithCString:url]; 2240 if (!URL) 2241 break; 2242 2243 String cookieString = String::fromUTF8(value, length); 2244 if (!cookieString) 2245 break; 2246 2247 if (Frame* frame = core([self webFrame])) { 2248 setCookies(frame->document(), URL, cookieString); 2249 return NPERR_NO_ERROR; 2250 } 2251 2252 break; 2253 } 2254 case NPNURLVProxy: 2255 // Can't set the proxy for a URL. 2256 break; 2257 } 2258 return NPERR_GENERIC_ERROR; 2259 } 2260 2261 - (NPError)getAuthenticationInfoWithProtocol:(const char*)protocolStr host:(const char*)hostStr port:(int32)port scheme:(const char*)schemeStr realm:(const char*)realmStr 2262 username:(char**)usernameStr usernameLength:(uint32*)usernameLength 2263 password:(char**)passwordStr passwordLength:(uint32*)passwordLength 2264 { 2265 if (!protocolStr || !hostStr || !schemeStr || !realmStr || !usernameStr || !usernameLength || !passwordStr || !passwordLength) 2266 return NPERR_GENERIC_ERROR; 2267 2268 CString username; 2269 CString password; 2270 if (!getAuthenticationInfo(protocolStr, hostStr, port, schemeStr, realmStr, username, password)) 2271 return NPERR_GENERIC_ERROR; 2272 2273 *usernameLength = username.length(); 2274 *usernameStr = static_cast<char*>(NPN_MemAlloc(username.length())); 2275 memcpy(*usernameStr, username.data(), username.length()); 2276 2277 *passwordLength = password.length(); 2278 *passwordStr = static_cast<char*>(NPN_MemAlloc(password.length())); 2279 memcpy(*passwordStr, password.data(), password.length()); 2280 2281 return NPERR_NO_ERROR; 2282 } 2283 2284 - (char*)resolveURL:(const char*)url forTarget:(const char*)target 2285 { 2286 WebCore::CString location = [self resolvedURLStringForURL:url target:target]; 2287 2288 if (location.isNull()) 2289 return 0; 2290 2291 // We use strdup here because the caller needs to free it with NPN_MemFree (which calls free). 2292 return strdup(location.data()); 2293 } 2294 2295 @end 2296 2297 @implementation WebNetscapePluginView (Internal) 2298 2299 - (BOOL)_shouldCancelSrcStream 2300 { 2301 ASSERT(_isStarted); 2302 2303 // Check if we should cancel the load 2304 NPBool cancelSrcStream = 0; 2305 if ([_pluginPackage.get() pluginFuncs]->getvalue && 2306 [_pluginPackage.get() pluginFuncs]->getvalue(plugin, NPPVpluginCancelSrcStream, &cancelSrcStream) == NPERR_NO_ERROR && cancelSrcStream) 2307 return YES; 2308 2309 return NO; 2310 } 2311 2312 // Work around Silverlight full screen performance issue by maintaining an accelerated GL pixel format. 2313 // We can safely remove it at some point in the future when both: 2314 // 1) Microsoft releases a genuine fix for 7288546. 2315 // 2) Enough Silverlight users update to the new Silverlight. 2316 // For now, we'll distinguish older broken versions of Silverlight by asking the plug-in if it resolved its full screen badness. 2317 - (void)_workaroundSilverlightFullScreenBug:(BOOL)initializedPlugin 2318 { 2319 #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) 2320 ASSERT(_isSilverlight); 2321 NPBool isFullScreenPerformanceIssueFixed = 0; 2322 NPPluginFuncs *pluginFuncs = [_pluginPackage.get() pluginFuncs]; 2323 if (pluginFuncs->getvalue && pluginFuncs->getvalue(plugin, static_cast<NPPVariable>(WKNVSilverlightFullScreenPerformanceIssueFixed), &isFullScreenPerformanceIssueFixed) == NPERR_NO_ERROR && isFullScreenPerformanceIssueFixed) 2324 return; 2325 2326 static CGLPixelFormatObj pixelFormatObject = 0; 2327 static unsigned refCount = 0; 2328 2329 if (initializedPlugin) { 2330 refCount++; 2331 if (refCount == 1) { 2332 const CGLPixelFormatAttribute attributes[] = { kCGLPFAAccelerated, static_cast<CGLPixelFormatAttribute>(0) }; 2333 GLint npix; 2334 CGLChoosePixelFormat(attributes, &pixelFormatObject, &npix); 2335 } 2336 } else { 2337 ASSERT(pixelFormatObject); 2338 refCount--; 2339 if (!refCount) 2340 CGLReleasePixelFormat(pixelFormatObject); 2341 } 2342 #endif 2343 } 2344 2345 - (NPError)_createPlugin 2346 { 2347 plugin = (NPP)calloc(1, sizeof(NPP_t)); 2348 plugin->ndata = self; 2349 2350 ASSERT([_pluginPackage.get() pluginFuncs]->newp); 2351 2352 // NPN_New(), which creates the plug-in instance, should never be called while calling a plug-in function for that instance. 2353 ASSERT(pluginFunctionCallDepth == 0); 2354 2355 PluginMainThreadScheduler::scheduler().registerPlugin(plugin); 2356 2357 _isFlash = [[[_pluginPackage.get() bundle] bundleIdentifier] isEqualToString:@"com.macromedia.Flash Player.plugin"]; 2358 _isSilverlight = [[[_pluginPackage.get() bundle] bundleIdentifier] isEqualToString:@"com.microsoft.SilverlightPlugin"]; 2359 2360 [[self class] setCurrentPluginView:self]; 2361 NPError npErr = [_pluginPackage.get() pluginFuncs]->newp((char *)[_MIMEType.get() cString], plugin, _mode, argsCount, cAttributes, cValues, NULL); 2362 [[self class] setCurrentPluginView:nil]; 2363 if (_isSilverlight) 2364 [self _workaroundSilverlightFullScreenBug:YES]; 2365 LOG(Plugins, "NPP_New: %d", npErr); 2366 return npErr; 2367 } 2368 2369 - (void)_destroyPlugin 2370 { 2371 PluginMainThreadScheduler::scheduler().unregisterPlugin(plugin); 2372 2373 if (_isSilverlight) 2374 [self _workaroundSilverlightFullScreenBug:NO]; 2375 2376 NPError npErr; 2377 npErr = ![_pluginPackage.get() pluginFuncs]->destroy(plugin, NULL); 2378 LOG(Plugins, "NPP_Destroy: %d", npErr); 2379 2380 if (Frame* frame = core([self webFrame])) 2381 frame->script()->cleanupScriptObjectsForPlugin(self); 2382 2383 free(plugin); 2384 plugin = NULL; 2385 } 2386 2387 - (NSBitmapImageRep *)_printedPluginBitmap 2388 { 2389 #ifdef NP_NO_QUICKDRAW 2390 return nil; 2391 #else 2392 // Cannot print plugins that do not implement NPP_Print 2393 if (![_pluginPackage.get() pluginFuncs]->print) 2394 return nil; 2395 2396 // This NSBitmapImageRep will share its bitmap buffer with a GWorld that the plugin will draw into. 2397 // The bitmap is created in 32-bits-per-pixel ARGB format, which is the default GWorld pixel format. 2398 NSBitmapImageRep *bitmap = [[[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL 2399 pixelsWide:window.width 2400 pixelsHigh:window.height 2401 bitsPerSample:8 2402 samplesPerPixel:4 2403 hasAlpha:YES 2404 isPlanar:NO 2405 colorSpaceName:NSDeviceRGBColorSpace 2406 bitmapFormat:NSAlphaFirstBitmapFormat 2407 bytesPerRow:0 2408 bitsPerPixel:0] autorelease]; 2409 ASSERT(bitmap); 2410 2411 // Create a GWorld with the same underlying buffer into which the plugin can draw 2412 ::Rect printGWorldBounds; 2413 SetRect(&printGWorldBounds, 0, 0, window.width, window.height); 2414 GWorldPtr printGWorld; 2415 if (NewGWorldFromPtr(&printGWorld, 2416 k32ARGBPixelFormat, 2417 &printGWorldBounds, 2418 NULL, 2419 NULL, 2420 0, 2421 (Ptr)[bitmap bitmapData], 2422 [bitmap bytesPerRow]) != noErr) { 2423 LOG_ERROR("Could not create GWorld for printing"); 2424 return nil; 2425 } 2426 2427 /// Create NPWindow for the GWorld 2428 NPWindow printNPWindow; 2429 printNPWindow.window = &printGWorld; // Normally this is an NP_Port, but when printing it is the actual CGrafPtr 2430 printNPWindow.x = 0; 2431 printNPWindow.y = 0; 2432 printNPWindow.width = window.width; 2433 printNPWindow.height = window.height; 2434 printNPWindow.clipRect.top = 0; 2435 printNPWindow.clipRect.left = 0; 2436 printNPWindow.clipRect.right = window.width; 2437 printNPWindow.clipRect.bottom = window.height; 2438 printNPWindow.type = NPWindowTypeDrawable; // Offscreen graphics port as opposed to a proper window 2439 2440 // Create embed-mode NPPrint 2441 NPPrint npPrint; 2442 npPrint.mode = NP_EMBED; 2443 npPrint.print.embedPrint.window = printNPWindow; 2444 npPrint.print.embedPrint.platformPrint = printGWorld; 2445 2446 // Tell the plugin to print into the GWorld 2447 [self willCallPlugInFunction]; 2448 { 2449 JSC::JSLock::DropAllLocks dropAllLocks(JSC::SilenceAssertionsOnly); 2450 [_pluginPackage.get() pluginFuncs]->print(plugin, &npPrint); 2451 } 2452 [self didCallPlugInFunction]; 2453 2454 // Don't need the GWorld anymore 2455 DisposeGWorld(printGWorld); 2456 2457 return bitmap; 2458 #endif 2459 } 2460 2461 - (void)_redeliverStream 2462 { 2463 if ([self dataSource] && _isStarted) { 2464 // Deliver what has not been passed to the plug-in up to this point. 2465 if (_dataLengthReceived > 0) { 2466 NSData *data = [[[self dataSource] data] subdataWithRange:NSMakeRange(0, _dataLengthReceived)]; 2467 _dataLengthReceived = 0; 2468 [self pluginView:self receivedData:data]; 2469 if (![[self dataSource] isLoading]) { 2470 if (_error) 2471 [self pluginView:self receivedError:_error.get()]; 2472 else 2473 [self pluginViewFinishedLoading:self]; 2474 } 2475 } 2476 } 2477 } 2478 2479 @end 2480 2481 #endif 2482