1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/widget/cocoa/nsChildView.mm Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,6555 @@ 1.4 +/* -*- Mode: objc; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "mozilla/ArrayUtils.h" 1.10 + 1.11 +#ifdef MOZ_LOGGING 1.12 +#define FORCE_PR_LOG 1.13 +#endif 1.14 +#include "prlog.h" 1.15 + 1.16 +#include <unistd.h> 1.17 +#include <math.h> 1.18 + 1.19 +#include "nsChildView.h" 1.20 +#include "nsCocoaWindow.h" 1.21 + 1.22 +#include "mozilla/MiscEvents.h" 1.23 +#include "mozilla/MouseEvents.h" 1.24 +#include "mozilla/TextEvents.h" 1.25 +#include "mozilla/TouchEvents.h" 1.26 + 1.27 +#include "nsObjCExceptions.h" 1.28 +#include "nsCOMPtr.h" 1.29 +#include "nsToolkit.h" 1.30 +#include "nsCRT.h" 1.31 + 1.32 +#include "nsFontMetrics.h" 1.33 +#include "nsIRollupListener.h" 1.34 +#include "nsViewManager.h" 1.35 +#include "nsIInterfaceRequestor.h" 1.36 +#include "nsIFile.h" 1.37 +#include "nsILocalFileMac.h" 1.38 +#include "nsGfxCIID.h" 1.39 +#include "nsIDOMSimpleGestureEvent.h" 1.40 +#include "nsNPAPIPluginInstance.h" 1.41 +#include "nsThemeConstants.h" 1.42 +#include "nsIWidgetListener.h" 1.43 +#include "nsIPresShell.h" 1.44 + 1.45 +#include "nsDragService.h" 1.46 +#include "nsClipboard.h" 1.47 +#include "nsCursorManager.h" 1.48 +#include "nsWindowMap.h" 1.49 +#include "nsCocoaFeatures.h" 1.50 +#include "nsCocoaUtils.h" 1.51 +#include "nsMenuUtilsX.h" 1.52 +#include "nsMenuBarX.h" 1.53 +#ifdef __LP64__ 1.54 +#include "ComplexTextInputPanel.h" 1.55 +#endif 1.56 +#include "NativeKeyBindings.h" 1.57 + 1.58 +#include "gfxContext.h" 1.59 +#include "gfxQuartzSurface.h" 1.60 +#include "gfxUtils.h" 1.61 +#include "nsRegion.h" 1.62 +#include "Layers.h" 1.63 +#include "ClientLayerManager.h" 1.64 +#include "mozilla/layers/LayerManagerComposite.h" 1.65 +#include "GLTextureImage.h" 1.66 +#include "GLContextProvider.h" 1.67 +#include "GLContextCGL.h" 1.68 +#include "GLUploadHelpers.h" 1.69 +#include "ScopedGLHelpers.h" 1.70 +#include "mozilla/layers/GLManager.h" 1.71 +#include "mozilla/layers/CompositorOGL.h" 1.72 +#include "mozilla/layers/BasicCompositor.h" 1.73 +#include "gfxUtils.h" 1.74 +#include "mozilla/gfx/2D.h" 1.75 +#include "mozilla/gfx/BorrowedContext.h" 1.76 +#ifdef ACCESSIBILITY 1.77 +#include "nsAccessibilityService.h" 1.78 +#include "mozilla/a11y/Platform.h" 1.79 +#endif 1.80 +#ifdef MOZ_CRASHREPORTER 1.81 +#include "nsExceptionHandler.h" 1.82 +#endif 1.83 + 1.84 +#include "mozilla/Preferences.h" 1.85 + 1.86 +#include <dlfcn.h> 1.87 + 1.88 +#include <ApplicationServices/ApplicationServices.h> 1.89 + 1.90 +#include "GeckoProfiler.h" 1.91 + 1.92 +#include "nsIDOMWheelEvent.h" 1.93 + 1.94 +using namespace mozilla; 1.95 +using namespace mozilla::layers; 1.96 +using namespace mozilla::gl; 1.97 +using namespace mozilla::widget; 1.98 + 1.99 +#undef DEBUG_UPDATE 1.100 +#undef INVALIDATE_DEBUGGING // flash areas as they are invalidated 1.101 + 1.102 +// Don't put more than this many rects in the dirty region, just fluff 1.103 +// out to the bounding-box if there are more 1.104 +#define MAX_RECTS_IN_REGION 100 1.105 + 1.106 +#ifdef PR_LOGGING 1.107 +PRLogModuleInfo* sCocoaLog = nullptr; 1.108 +#endif 1.109 + 1.110 +extern "C" { 1.111 + CG_EXTERN void CGContextResetCTM(CGContextRef); 1.112 + CG_EXTERN void CGContextSetCTM(CGContextRef, CGAffineTransform); 1.113 + CG_EXTERN void CGContextResetClip(CGContextRef); 1.114 + 1.115 + typedef CFTypeRef CGSRegionObj; 1.116 + CGError CGSNewRegionWithRect(const CGRect *rect, CGSRegionObj *outRegion); 1.117 +} 1.118 + 1.119 +// defined in nsMenuBarX.mm 1.120 +extern NSMenu* sApplicationMenu; // Application menu shared by all menubars 1.121 + 1.122 +bool gChildViewMethodsSwizzled = false; 1.123 + 1.124 +extern nsISupportsArray *gDraggedTransferables; 1.125 + 1.126 +ChildView* ChildViewMouseTracker::sLastMouseEventView = nil; 1.127 +NSEvent* ChildViewMouseTracker::sLastMouseMoveEvent = nil; 1.128 +NSWindow* ChildViewMouseTracker::sWindowUnderMouse = nil; 1.129 +NSPoint ChildViewMouseTracker::sLastScrollEventScreenLocation = NSZeroPoint; 1.130 + 1.131 +#ifdef INVALIDATE_DEBUGGING 1.132 +static void blinkRect(Rect* r); 1.133 +static void blinkRgn(RgnHandle rgn); 1.134 +#endif 1.135 + 1.136 +bool gUserCancelledDrag = false; 1.137 + 1.138 +uint32_t nsChildView::sLastInputEventCount = 0; 1.139 + 1.140 +@interface ChildView(Private) 1.141 + 1.142 +// sets up our view, attaching it to its owning gecko view 1.143 +- (id)initWithFrame:(NSRect)inFrame geckoChild:(nsChildView*)inChild; 1.144 +- (void)forceRefreshOpenGL; 1.145 + 1.146 +// set up a gecko mouse event based on a cocoa mouse event 1.147 +- (void) convertCocoaMouseWheelEvent:(NSEvent*)aMouseEvent 1.148 + toGeckoEvent:(WidgetWheelEvent*)outWheelEvent; 1.149 +- (void) convertCocoaMouseEvent:(NSEvent*)aMouseEvent 1.150 + toGeckoEvent:(WidgetInputEvent*)outGeckoEvent; 1.151 + 1.152 +- (NSMenu*)contextMenu; 1.153 + 1.154 +- (void)setIsPluginView:(BOOL)aIsPlugin; 1.155 +- (void)setPluginEventModel:(NPEventModel)eventModel; 1.156 +- (void)setPluginDrawingModel:(NPDrawingModel)drawingModel; 1.157 +- (NPDrawingModel)pluginDrawingModel; 1.158 + 1.159 +- (BOOL)isRectObscuredBySubview:(NSRect)inRect; 1.160 + 1.161 +- (void)processPendingRedraws; 1.162 + 1.163 +- (void)drawRect:(NSRect)aRect inContext:(CGContextRef)aContext; 1.164 +- (nsIntRegion)nativeDirtyRegionWithBoundingRect:(NSRect)aRect; 1.165 +- (BOOL)isUsingMainThreadOpenGL; 1.166 +- (BOOL)isUsingOpenGL; 1.167 +- (void)drawUsingOpenGL; 1.168 +- (void)drawUsingOpenGLCallback; 1.169 + 1.170 +- (BOOL)hasRoundedBottomCorners; 1.171 +- (CGFloat)cornerRadius; 1.172 +- (void)clearCorners; 1.173 + 1.174 +// Overlay drawing functions for traditional CGContext drawing 1.175 +- (void)drawTitleString; 1.176 +- (void)drawTitlebarHighlight; 1.177 +- (void)maskTopCornersInContext:(CGContextRef)aContext; 1.178 + 1.179 +// Called using performSelector:withObject:afterDelay:0 to release 1.180 +// aWidgetArray (and its contents) the next time through the run loop. 1.181 +- (void)releaseWidgets:(NSArray*)aWidgetArray; 1.182 + 1.183 +#if USE_CLICK_HOLD_CONTEXTMENU 1.184 + // called on a timer two seconds after a mouse down to see if we should display 1.185 + // a context menu (click-hold) 1.186 +- (void)clickHoldCallback:(id)inEvent; 1.187 +#endif 1.188 + 1.189 +#ifdef ACCESSIBILITY 1.190 +- (id<mozAccessible>)accessible; 1.191 +#endif 1.192 + 1.193 +- (BOOL)inactiveWindowAcceptsMouseEvent:(NSEvent*)aEvent; 1.194 + 1.195 +@end 1.196 + 1.197 +@interface NSView(NSThemeFrameCornerRadius) 1.198 +- (float)roundedCornerRadius; 1.199 +@end 1.200 + 1.201 +// Starting with 10.7 the bottom corners of all windows are rounded. 1.202 +// Unfortunately, the standard rounding that OS X applies to OpenGL views 1.203 +// does not use anti-aliasing and looks very crude. Since we want a smooth, 1.204 +// anti-aliased curve, we'll draw it ourselves. 1.205 +// Additionally, we need to turn off the OS-supplied rounding because it 1.206 +// eats into our corner's curve. We do that by overriding an NSSurface method. 1.207 +@interface NSSurface @end 1.208 + 1.209 +@implementation NSSurface(DontCutOffCorners) 1.210 +- (CGSRegionObj)_createRoundedBottomRegionForRect:(CGRect)rect 1.211 +{ 1.212 + // Create a normal rect region without rounded bottom corners. 1.213 + CGSRegionObj region; 1.214 + CGSNewRegionWithRect(&rect, ®ion); 1.215 + return region; 1.216 +} 1.217 +@end 1.218 + 1.219 +#pragma mark - 1.220 + 1.221 +/* Convenience routine to go from a Gecko rect to Cocoa NSRect. 1.222 + * 1.223 + * Gecko rects (nsRect) contain an origin (x,y) in a coordinate 1.224 + * system with (0,0) in the top-left of the screen. Cocoa rects 1.225 + * (NSRect) contain an origin (x,y) in a coordinate system with 1.226 + * (0,0) in the bottom-left of the screen. Both nsRect and NSRect 1.227 + * contain width/height info, with no difference in their use. 1.228 + * If a Cocoa rect is from a flipped view, there is no need to 1.229 + * convert coordinate systems. 1.230 + */ 1.231 +#ifndef __LP64__ 1.232 +static inline void 1.233 +ConvertGeckoRectToMacRect(const nsIntRect& aRect, Rect& outMacRect) 1.234 +{ 1.235 + outMacRect.left = aRect.x; 1.236 + outMacRect.top = aRect.y; 1.237 + outMacRect.right = aRect.x + aRect.width; 1.238 + outMacRect.bottom = aRect.y + aRect.height; 1.239 +} 1.240 +#endif 1.241 + 1.242 +// Flips a screen coordinate from a point in the cocoa coordinate system (bottom-left rect) to a point 1.243 +// that is a "flipped" cocoa coordinate system (starts in the top-left). 1.244 +static inline void 1.245 +FlipCocoaScreenCoordinate(NSPoint &inPoint) 1.246 +{ 1.247 + inPoint.y = nsCocoaUtils::FlippedScreenY(inPoint.y); 1.248 +} 1.249 + 1.250 +void EnsureLogInitialized() 1.251 +{ 1.252 +#ifdef PR_LOGGING 1.253 + if (!sCocoaLog) { 1.254 + sCocoaLog = PR_NewLogModule("nsCocoaWidgets"); 1.255 + } 1.256 +#endif // PR_LOGGING 1.257 +} 1.258 + 1.259 +namespace { 1.260 + 1.261 +// Manages a texture which can resize dynamically, binds to the 1.262 +// LOCAL_GL_TEXTURE_RECTANGLE_ARB texture target and is automatically backed 1.263 +// by a power-of-two size GL texture. The latter two features are used for 1.264 +// compatibility with older Mac hardware which we block GL layers on. 1.265 +// RectTextureImages are used both for accelerated GL layers drawing and for 1.266 +// OMTC BasicLayers drawing. 1.267 +class RectTextureImage { 1.268 +public: 1.269 + RectTextureImage(GLContext* aGLContext) 1.270 + : mGLContext(aGLContext) 1.271 + , mTexture(0) 1.272 + , mInUpdate(false) 1.273 + {} 1.274 + 1.275 + virtual ~RectTextureImage(); 1.276 + 1.277 + TemporaryRef<gfx::DrawTarget> 1.278 + BeginUpdate(const nsIntSize& aNewSize, 1.279 + const nsIntRegion& aDirtyRegion = nsIntRegion()); 1.280 + void EndUpdate(bool aKeepSurface = false); 1.281 + 1.282 + void UpdateIfNeeded(const nsIntSize& aNewSize, 1.283 + const nsIntRegion& aDirtyRegion, 1.284 + void (^aCallback)(gfx::DrawTarget*, const nsIntRegion&)) 1.285 + { 1.286 + RefPtr<gfx::DrawTarget> drawTarget = BeginUpdate(aNewSize, aDirtyRegion); 1.287 + if (drawTarget) { 1.288 + aCallback(drawTarget, GetUpdateRegion()); 1.289 + EndUpdate(); 1.290 + } 1.291 + } 1.292 + 1.293 + void UpdateFromCGContext(const nsIntSize& aNewSize, 1.294 + const nsIntRegion& aDirtyRegion, 1.295 + CGContextRef aCGContext); 1.296 + 1.297 + void UpdateFromDrawTarget(const nsIntSize& aNewSize, 1.298 + const nsIntRegion& aDirtyRegion, 1.299 + gfx::DrawTarget* aFromDrawTarget); 1.300 + 1.301 + nsIntRegion GetUpdateRegion() { 1.302 + MOZ_ASSERT(mInUpdate, "update region only valid during update"); 1.303 + return mUpdateRegion; 1.304 + } 1.305 + 1.306 + void Draw(mozilla::layers::GLManager* aManager, 1.307 + const nsIntPoint& aLocation, 1.308 + const gfx3DMatrix& aTransform = gfx3DMatrix()); 1.309 + 1.310 + static nsIntSize TextureSizeForSize(const nsIntSize& aSize); 1.311 + 1.312 +protected: 1.313 + 1.314 + RefPtr<gfx::DrawTarget> mUpdateDrawTarget; 1.315 + GLContext* mGLContext; 1.316 + nsIntRegion mUpdateRegion; 1.317 + nsIntSize mUsedSize; 1.318 + nsIntSize mBufferSize; 1.319 + nsIntSize mTextureSize; 1.320 + GLuint mTexture; 1.321 + bool mInUpdate; 1.322 +}; 1.323 + 1.324 +// Used for OpenGL drawing from the compositor thread for OMTC BasicLayers. 1.325 +// We need to use OpenGL for this because there seems to be no other robust 1.326 +// way of drawing from a secondary thread without locking, which would cause 1.327 +// deadlocks in our setup. See bug 882523. 1.328 +class GLPresenter : public GLManager 1.329 +{ 1.330 +public: 1.331 + static GLPresenter* CreateForWindow(nsIWidget* aWindow) 1.332 + { 1.333 + nsRefPtr<GLContext> context = gl::GLContextProvider::CreateForWindow(aWindow); 1.334 + return context ? new GLPresenter(context) : nullptr; 1.335 + } 1.336 + 1.337 + GLPresenter(GLContext* aContext); 1.338 + virtual ~GLPresenter(); 1.339 + 1.340 + virtual GLContext* gl() const MOZ_OVERRIDE { return mGLContext; } 1.341 + virtual ShaderProgramOGL* GetProgram(GLenum aTarget, gfx::SurfaceFormat aFormat) MOZ_OVERRIDE 1.342 + { 1.343 + MOZ_ASSERT(aTarget == LOCAL_GL_TEXTURE_RECTANGLE_ARB); 1.344 + MOZ_ASSERT(aFormat == gfx::SurfaceFormat::R8G8B8A8); 1.345 + return mRGBARectProgram; 1.346 + } 1.347 + virtual const gfx::Matrix4x4& GetProjMatrix() const MOZ_OVERRIDE 1.348 + { 1.349 + return mProjMatrix; 1.350 + } 1.351 + virtual void BindAndDrawQuad(ShaderProgramOGL *aProg) MOZ_OVERRIDE; 1.352 + 1.353 + void BeginFrame(nsIntSize aRenderSize); 1.354 + void EndFrame(); 1.355 + 1.356 + NSOpenGLContext* GetNSOpenGLContext() 1.357 + { 1.358 + return GLContextCGL::Cast(mGLContext)->GetNSOpenGLContext(); 1.359 + } 1.360 + 1.361 +protected: 1.362 + nsRefPtr<mozilla::gl::GLContext> mGLContext; 1.363 + nsAutoPtr<mozilla::layers::ShaderProgramOGL> mRGBARectProgram; 1.364 + gfx::Matrix4x4 mProjMatrix; 1.365 + GLuint mQuadVBO; 1.366 +}; 1.367 + 1.368 +} // unnamed namespace 1.369 + 1.370 +#pragma mark - 1.371 + 1.372 +nsChildView::nsChildView() : nsBaseWidget() 1.373 +, mView(nullptr) 1.374 +, mParentView(nullptr) 1.375 +, mParentWidget(nullptr) 1.376 +, mViewTearDownLock("ChildViewTearDown") 1.377 +, mEffectsLock("WidgetEffects") 1.378 +, mShowsResizeIndicator(false) 1.379 +, mHasRoundedBottomCorners(false) 1.380 +, mIsCoveringTitlebar(false) 1.381 +, mIsFullscreen(false) 1.382 +, mTitlebarCGContext(nullptr) 1.383 +, mBackingScaleFactor(0.0) 1.384 +, mVisible(false) 1.385 +, mDrawing(false) 1.386 +, mPluginDrawing(false) 1.387 +, mIsDispatchPaint(false) 1.388 +, mPluginInstanceOwner(nullptr) 1.389 +{ 1.390 + EnsureLogInitialized(); 1.391 + 1.392 + memset(&mPluginCGContext, 0, sizeof(mPluginCGContext)); 1.393 +} 1.394 + 1.395 +nsChildView::~nsChildView() 1.396 +{ 1.397 + ReleaseTitlebarCGContext(); 1.398 + 1.399 + // Notify the children that we're gone. childView->ResetParent() can change 1.400 + // our list of children while it's being iterated, so the way we iterate the 1.401 + // list must allow for this. 1.402 + for (nsIWidget* kid = mLastChild; kid;) { 1.403 + nsChildView* childView = static_cast<nsChildView*>(kid); 1.404 + kid = kid->GetPrevSibling(); 1.405 + childView->ResetParent(); 1.406 + } 1.407 + 1.408 + NS_WARN_IF_FALSE(mOnDestroyCalled, "nsChildView object destroyed without calling Destroy()"); 1.409 + 1.410 + DestroyCompositor(); 1.411 + 1.412 + // An nsChildView object that was in use can be destroyed without Destroy() 1.413 + // ever being called on it. So we also need to do a quick, safe cleanup 1.414 + // here (it's too late to just call Destroy(), which can cause crashes). 1.415 + // It's particularly important to make sure widgetDestroyed is called on our 1.416 + // mView -- this method NULLs mView's mGeckoChild, and NULL checks on 1.417 + // mGeckoChild are used throughout the ChildView class to tell if it's safe 1.418 + // to use a ChildView object. 1.419 + [mView widgetDestroyed]; // Safe if mView is nil. 1.420 + mParentWidget = nil; 1.421 + TearDownView(); // Safe if called twice. 1.422 +} 1.423 + 1.424 +void 1.425 +nsChildView::ReleaseTitlebarCGContext() 1.426 +{ 1.427 + if (mTitlebarCGContext) { 1.428 + CGContextRelease(mTitlebarCGContext); 1.429 + mTitlebarCGContext = nullptr; 1.430 + } 1.431 +} 1.432 + 1.433 +NS_IMPL_ISUPPORTS_INHERITED(nsChildView, nsBaseWidget, nsIPluginWidget) 1.434 + 1.435 +nsresult nsChildView::Create(nsIWidget *aParent, 1.436 + nsNativeWidget aNativeParent, 1.437 + const nsIntRect &aRect, 1.438 + nsDeviceContext *aContext, 1.439 + nsWidgetInitData *aInitData) 1.440 +{ 1.441 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; 1.442 + 1.443 + // Because the hidden window is created outside of an event loop, 1.444 + // we need to provide an autorelease pool to avoid leaking cocoa objects 1.445 + // (see bug 559075). 1.446 + nsAutoreleasePool localPool; 1.447 + 1.448 + // See NSView (MethodSwizzling) below. 1.449 + if (!gChildViewMethodsSwizzled) { 1.450 + nsToolkit::SwizzleMethods([NSView class], @selector(mouseDownCanMoveWindow), 1.451 + @selector(nsChildView_NSView_mouseDownCanMoveWindow)); 1.452 +#ifdef __LP64__ 1.453 + if (nsCocoaFeatures::OnLionOrLater()) { 1.454 + nsToolkit::SwizzleMethods([NSEvent class], @selector(addLocalMonitorForEventsMatchingMask:handler:), 1.455 + @selector(nsChildView_NSEvent_addLocalMonitorForEventsMatchingMask:handler:), 1.456 + true); 1.457 + nsToolkit::SwizzleMethods([NSEvent class], @selector(removeMonitor:), 1.458 + @selector(nsChildView_NSEvent_removeMonitor:), true); 1.459 + } 1.460 +#else 1.461 + TextInputHandler::SwizzleMethods(); 1.462 +#endif 1.463 + gChildViewMethodsSwizzled = true; 1.464 + } 1.465 + 1.466 + mBounds = aRect; 1.467 + 1.468 + // Ensure that the toolkit is created. 1.469 + nsToolkit::GetToolkit(); 1.470 + 1.471 + BaseCreate(aParent, aRect, aContext, aInitData); 1.472 + 1.473 + // inherit things from the parent view and create our parallel 1.474 + // NSView in the Cocoa display system 1.475 + mParentView = nil; 1.476 + if (aParent) { 1.477 + // inherit the top-level window. NS_NATIVE_WIDGET is always a NSView 1.478 + // regardless of if we're asking a window or a view (for compatibility 1.479 + // with windows). 1.480 + mParentView = (NSView<mozView>*)aParent->GetNativeData(NS_NATIVE_WIDGET); 1.481 + mParentWidget = aParent; 1.482 + } else { 1.483 + // This is the normal case. When we're the root widget of the view hiararchy, 1.484 + // aNativeParent will be the contentView of our window, since that's what 1.485 + // nsCocoaWindow returns when asked for an NS_NATIVE_VIEW. 1.486 + mParentView = reinterpret_cast<NSView<mozView>*>(aNativeParent); 1.487 + } 1.488 + 1.489 + // create our parallel NSView and hook it up to our parent. Recall 1.490 + // that NS_NATIVE_WIDGET is the NSView. 1.491 + CGFloat scaleFactor = nsCocoaUtils::GetBackingScaleFactor(mParentView); 1.492 + NSRect r = nsCocoaUtils::DevPixelsToCocoaPoints(mBounds, scaleFactor); 1.493 + mView = [(NSView<mozView>*)CreateCocoaView(r) retain]; 1.494 + if (!mView) { 1.495 + return NS_ERROR_FAILURE; 1.496 + } 1.497 + 1.498 + [(ChildView*)mView setIsPluginView:(mWindowType == eWindowType_plugin)]; 1.499 + 1.500 + // If this view was created in a Gecko view hierarchy, the initial state 1.501 + // is hidden. If the view is attached only to a native NSView but has 1.502 + // no Gecko parent (as in embedding), the initial state is visible. 1.503 + if (mParentWidget) 1.504 + [mView setHidden:YES]; 1.505 + else 1.506 + mVisible = true; 1.507 + 1.508 + // Hook it up in the NSView hierarchy. 1.509 + if (mParentView) { 1.510 + [mParentView addSubview:mView]; 1.511 + } 1.512 + 1.513 + // if this is a ChildView, make sure that our per-window data 1.514 + // is set up 1.515 + if ([mView isKindOfClass:[ChildView class]]) 1.516 + [[WindowDataMap sharedWindowDataMap] ensureDataForWindow:[mView window]]; 1.517 + 1.518 + NS_ASSERTION(!mTextInputHandler, "mTextInputHandler has already existed"); 1.519 + mTextInputHandler = new TextInputHandler(this, mView); 1.520 + 1.521 + return NS_OK; 1.522 + 1.523 + NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; 1.524 +} 1.525 + 1.526 +// Creates the appropriate child view. Override to create something other than 1.527 +// our |ChildView| object. Autoreleases, so caller must retain. 1.528 +NSView* 1.529 +nsChildView::CreateCocoaView(NSRect inFrame) 1.530 +{ 1.531 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; 1.532 + 1.533 + return [[[ChildView alloc] initWithFrame:inFrame geckoChild:this] autorelease]; 1.534 + 1.535 + NS_OBJC_END_TRY_ABORT_BLOCK_NIL; 1.536 +} 1.537 + 1.538 +void nsChildView::TearDownView() 1.539 +{ 1.540 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK; 1.541 + 1.542 + if (!mView) 1.543 + return; 1.544 + 1.545 + NSWindow* win = [mView window]; 1.546 + NSResponder* responder = [win firstResponder]; 1.547 + 1.548 + // We're being unhooked from the view hierarchy, don't leave our view 1.549 + // or a child view as the window first responder. 1.550 + if (responder && [responder isKindOfClass:[NSView class]] && 1.551 + [(NSView*)responder isDescendantOf:mView]) { 1.552 + [win makeFirstResponder:[mView superview]]; 1.553 + } 1.554 + 1.555 + // If mView is win's contentView, win (mView's NSWindow) "owns" mView -- 1.556 + // win has retained mView, and will detach it from the view hierarchy and 1.557 + // release it when necessary (when win is itself destroyed (in a call to 1.558 + // [win dealloc])). So all we need to do here is call [mView release] (to 1.559 + // match the call to [mView retain] in nsChildView::StandardCreate()). 1.560 + // Also calling [mView removeFromSuperviewWithoutNeedingDisplay] causes 1.561 + // mView to be released again and dealloced, while remaining win's 1.562 + // contentView. So if we do that here, win will (for a short while) have 1.563 + // an invalid contentView (for the consequences see bmo bugs 381087 and 1.564 + // 374260). 1.565 + if ([mView isEqual:[win contentView]]) { 1.566 + [mView release]; 1.567 + } else { 1.568 + // Stop NSView hierarchy being changed during [ChildView drawRect:] 1.569 + [mView performSelectorOnMainThread:@selector(delayedTearDown) withObject:nil waitUntilDone:false]; 1.570 + } 1.571 + mView = nil; 1.572 + 1.573 + NS_OBJC_END_TRY_ABORT_BLOCK; 1.574 +} 1.575 + 1.576 +nsCocoaWindow* 1.577 +nsChildView::GetXULWindowWidget() 1.578 +{ 1.579 + id windowDelegate = [[mView window] delegate]; 1.580 + if (windowDelegate && [windowDelegate isKindOfClass:[WindowDelegate class]]) { 1.581 + return [(WindowDelegate *)windowDelegate geckoWidget]; 1.582 + } 1.583 + return nullptr; 1.584 +} 1.585 + 1.586 +NS_IMETHODIMP nsChildView::Destroy() 1.587 +{ 1.588 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; 1.589 + 1.590 + // Make sure that no composition is in progress while disconnecting 1.591 + // ourselves from the view. 1.592 + MutexAutoLock lock(mViewTearDownLock); 1.593 + 1.594 + if (mOnDestroyCalled) 1.595 + return NS_OK; 1.596 + mOnDestroyCalled = true; 1.597 + 1.598 + [mView widgetDestroyed]; 1.599 + 1.600 + nsBaseWidget::Destroy(); 1.601 + 1.602 + NotifyWindowDestroyed(); 1.603 + mParentWidget = nil; 1.604 + 1.605 + TearDownView(); 1.606 + 1.607 + nsBaseWidget::OnDestroy(); 1.608 + 1.609 + return NS_OK; 1.610 + 1.611 + NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; 1.612 +} 1.613 + 1.614 +#pragma mark - 1.615 + 1.616 +#if 0 1.617 +static void PrintViewHierarchy(NSView *view) 1.618 +{ 1.619 + while (view) { 1.620 + NSLog(@" view is %x, frame %@", view, NSStringFromRect([view frame])); 1.621 + view = [view superview]; 1.622 + } 1.623 +} 1.624 +#endif 1.625 + 1.626 +// Return native data according to aDataType 1.627 +void* nsChildView::GetNativeData(uint32_t aDataType) 1.628 +{ 1.629 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSNULL; 1.630 + 1.631 + void* retVal = nullptr; 1.632 + 1.633 + switch (aDataType) 1.634 + { 1.635 + case NS_NATIVE_WIDGET: 1.636 + case NS_NATIVE_DISPLAY: 1.637 + retVal = (void*)mView; 1.638 + break; 1.639 + 1.640 + case NS_NATIVE_WINDOW: 1.641 + retVal = [mView window]; 1.642 + break; 1.643 + 1.644 + case NS_NATIVE_GRAPHIC: 1.645 + NS_ERROR("Requesting NS_NATIVE_GRAPHIC on a Mac OS X child view!"); 1.646 + retVal = nullptr; 1.647 + break; 1.648 + 1.649 + case NS_NATIVE_OFFSETX: 1.650 + retVal = 0; 1.651 + break; 1.652 + 1.653 + case NS_NATIVE_OFFSETY: 1.654 + retVal = 0; 1.655 + break; 1.656 + 1.657 + case NS_NATIVE_PLUGIN_PORT: 1.658 + case NS_NATIVE_PLUGIN_PORT_CG: 1.659 + { 1.660 + // The NP_CGContext pointer should always be NULL in the Cocoa event model. 1.661 + if ([(ChildView*)mView pluginEventModel] == NPEventModelCocoa) 1.662 + return nullptr; 1.663 + 1.664 + UpdatePluginPort(); 1.665 + retVal = (void*)&mPluginCGContext; 1.666 + break; 1.667 + } 1.668 + } 1.669 + 1.670 + return retVal; 1.671 + 1.672 + NS_OBJC_END_TRY_ABORT_BLOCK_NSNULL; 1.673 +} 1.674 + 1.675 +#pragma mark - 1.676 + 1.677 +nsTransparencyMode nsChildView::GetTransparencyMode() 1.678 +{ 1.679 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN; 1.680 + 1.681 + nsCocoaWindow* windowWidget = GetXULWindowWidget(); 1.682 + return windowWidget ? windowWidget->GetTransparencyMode() : eTransparencyOpaque; 1.683 + 1.684 + NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(eTransparencyOpaque); 1.685 +} 1.686 + 1.687 +// This is called by nsContainerFrame on the root widget for all window types 1.688 +// except popup windows (when nsCocoaWindow::SetTransparencyMode is used instead). 1.689 +void nsChildView::SetTransparencyMode(nsTransparencyMode aMode) 1.690 +{ 1.691 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK; 1.692 + 1.693 + nsCocoaWindow* windowWidget = GetXULWindowWidget(); 1.694 + if (windowWidget) { 1.695 + windowWidget->SetTransparencyMode(aMode); 1.696 + } 1.697 + 1.698 + NS_OBJC_END_TRY_ABORT_BLOCK; 1.699 +} 1.700 + 1.701 +bool nsChildView::IsVisible() const 1.702 +{ 1.703 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN; 1.704 + 1.705 + if (!mVisible) { 1.706 + return mVisible; 1.707 + } 1.708 + 1.709 + // mVisible does not accurately reflect the state of a hidden tabbed view 1.710 + // so verify that the view has a window as well 1.711 + // then check native widget hierarchy visibility 1.712 + return ([mView window] != nil) && !NSIsEmptyRect([mView visibleRect]); 1.713 + 1.714 + NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(false); 1.715 +} 1.716 + 1.717 +void nsChildView::HidePlugin() 1.718 +{ 1.719 + NS_ASSERTION(mWindowType == eWindowType_plugin, 1.720 + "HidePlugin called on non-plugin view"); 1.721 +} 1.722 + 1.723 +void nsChildView::UpdatePluginPort() 1.724 +{ 1.725 + NS_ASSERTION(mWindowType == eWindowType_plugin, 1.726 + "UpdatePluginPort called on non-plugin view"); 1.727 + 1.728 + // [NSGraphicsContext currentContext] is supposed to "return the 1.729 + // current graphics context of the current thread." But sometimes 1.730 + // (when called while mView isn't focused for drawing) it returns a 1.731 + // graphics context for the wrong window. [window graphicsContext] 1.732 + // (which "provides the graphics context associated with the window 1.733 + // for the current thread") seems always to return the "right" 1.734 + // graphics context. See bug 500130. 1.735 + mPluginCGContext.context = NULL; 1.736 + mPluginCGContext.window = NULL; 1.737 +} 1.738 + 1.739 +static void HideChildPluginViews(NSView* aView) 1.740 +{ 1.741 + NSArray* subviews = [aView subviews]; 1.742 + 1.743 + for (unsigned int i = 0; i < [subviews count]; ++i) { 1.744 + NSView* view = [subviews objectAtIndex: i]; 1.745 + 1.746 + if (![view isKindOfClass:[ChildView class]]) 1.747 + continue; 1.748 + 1.749 + ChildView* childview = static_cast<ChildView*>(view); 1.750 + if ([childview isPluginView]) { 1.751 + nsChildView* widget = static_cast<nsChildView*>([childview widget]); 1.752 + if (widget) { 1.753 + widget->HidePlugin(); 1.754 + } 1.755 + } else { 1.756 + HideChildPluginViews(view); 1.757 + } 1.758 + } 1.759 +} 1.760 + 1.761 +// Some NSView methods (e.g. setFrame and setHidden) invalidate the view's 1.762 +// bounds in our window. However, we don't want these invalidations because 1.763 +// they are unnecessary and because they actually slow us down since we 1.764 +// block on the compositor inside drawRect. 1.765 +// When we actually need something invalidated, there will be an explicit call 1.766 +// to Invalidate from Gecko, so turning these automatic invalidations off 1.767 +// won't hurt us in the non-OMTC case. 1.768 +// The invalidations inside these NSView methods happen via a call to the 1.769 +// private method -[NSWindow _setNeedsDisplayInRect:]. Our BaseWindow 1.770 +// implementation of that method is augmented to let us ignore those calls 1.771 +// using -[BaseWindow disable/enableSetNeedsDisplay]. 1.772 +static void 1.773 +ManipulateViewWithoutNeedingDisplay(NSView* aView, void (^aCallback)()) 1.774 +{ 1.775 + BaseWindow* win = nil; 1.776 + if ([[aView window] isKindOfClass:[BaseWindow class]]) { 1.777 + win = (BaseWindow*)[aView window]; 1.778 + } 1.779 + [win disableSetNeedsDisplay]; 1.780 + aCallback(); 1.781 + [win enableSetNeedsDisplay]; 1.782 +} 1.783 + 1.784 +// Hide or show this component 1.785 +NS_IMETHODIMP nsChildView::Show(bool aState) 1.786 +{ 1.787 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; 1.788 + 1.789 + if (aState != mVisible) { 1.790 + // Provide an autorelease pool because this gets called during startup 1.791 + // on the "hidden window", resulting in cocoa object leakage if there's 1.792 + // no pool in place. 1.793 + nsAutoreleasePool localPool; 1.794 + 1.795 + ManipulateViewWithoutNeedingDisplay(mView, ^{ 1.796 + [mView setHidden:!aState]; 1.797 + }); 1.798 + 1.799 + mVisible = aState; 1.800 + if (!mVisible && IsPluginView()) 1.801 + HidePlugin(); 1.802 + } 1.803 + return NS_OK; 1.804 + 1.805 + NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; 1.806 +} 1.807 + 1.808 +// Change the parent of this widget 1.809 +NS_IMETHODIMP 1.810 +nsChildView::SetParent(nsIWidget* aNewParent) 1.811 +{ 1.812 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; 1.813 + 1.814 + if (mOnDestroyCalled) 1.815 + return NS_OK; 1.816 + 1.817 + nsCOMPtr<nsIWidget> kungFuDeathGrip(this); 1.818 + 1.819 + if (mParentWidget) { 1.820 + mParentWidget->RemoveChild(this); 1.821 + } 1.822 + 1.823 + if (aNewParent) { 1.824 + ReparentNativeWidget(aNewParent); 1.825 + } else { 1.826 + [mView removeFromSuperview]; 1.827 + mParentView = nil; 1.828 + } 1.829 + 1.830 + mParentWidget = aNewParent; 1.831 + 1.832 + if (mParentWidget) { 1.833 + mParentWidget->AddChild(this); 1.834 + } 1.835 + 1.836 + return NS_OK; 1.837 + 1.838 + NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; 1.839 +} 1.840 + 1.841 +NS_IMETHODIMP 1.842 +nsChildView::ReparentNativeWidget(nsIWidget* aNewParent) 1.843 +{ 1.844 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; 1.845 + 1.846 + NS_PRECONDITION(aNewParent, ""); 1.847 + 1.848 + if (mOnDestroyCalled) 1.849 + return NS_OK; 1.850 + 1.851 + NSView<mozView>* newParentView = 1.852 + (NSView<mozView>*)aNewParent->GetNativeData(NS_NATIVE_WIDGET); 1.853 + NS_ENSURE_TRUE(newParentView, NS_ERROR_FAILURE); 1.854 + 1.855 + // we hold a ref to mView, so this is safe 1.856 + [mView removeFromSuperview]; 1.857 + mParentView = newParentView; 1.858 + [mParentView addSubview:mView]; 1.859 + return NS_OK; 1.860 + 1.861 + NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; 1.862 +} 1.863 + 1.864 +void nsChildView::ResetParent() 1.865 +{ 1.866 + if (!mOnDestroyCalled) { 1.867 + if (mParentWidget) 1.868 + mParentWidget->RemoveChild(this); 1.869 + if (mView) 1.870 + [mView removeFromSuperview]; 1.871 + } 1.872 + mParentWidget = nullptr; 1.873 +} 1.874 + 1.875 +nsIWidget* 1.876 +nsChildView::GetParent() 1.877 +{ 1.878 + return mParentWidget; 1.879 +} 1.880 + 1.881 +float 1.882 +nsChildView::GetDPI() 1.883 +{ 1.884 + NSWindow* window = [mView window]; 1.885 + if (window && [window isKindOfClass:[BaseWindow class]]) { 1.886 + return [(BaseWindow*)window getDPI]; 1.887 + } 1.888 + 1.889 + return 96.0; 1.890 +} 1.891 + 1.892 +NS_IMETHODIMP nsChildView::Enable(bool aState) 1.893 +{ 1.894 + return NS_OK; 1.895 +} 1.896 + 1.897 +bool nsChildView::IsEnabled() const 1.898 +{ 1.899 + return true; 1.900 +} 1.901 + 1.902 +NS_IMETHODIMP nsChildView::SetFocus(bool aRaise) 1.903 +{ 1.904 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; 1.905 + 1.906 + NSWindow* window = [mView window]; 1.907 + if (window) 1.908 + [window makeFirstResponder:mView]; 1.909 + return NS_OK; 1.910 + 1.911 + NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; 1.912 +} 1.913 + 1.914 +// Override to set the cursor on the mac 1.915 +NS_IMETHODIMP nsChildView::SetCursor(nsCursor aCursor) 1.916 +{ 1.917 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; 1.918 + 1.919 + if ([mView isDragInProgress]) 1.920 + return NS_OK; // Don't change the cursor during dragging. 1.921 + 1.922 + nsBaseWidget::SetCursor(aCursor); 1.923 + return [[nsCursorManager sharedInstance] setCursor:aCursor]; 1.924 + 1.925 + NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; 1.926 +} 1.927 + 1.928 +// implement to fix "hidden virtual function" warning 1.929 +NS_IMETHODIMP nsChildView::SetCursor(imgIContainer* aCursor, 1.930 + uint32_t aHotspotX, uint32_t aHotspotY) 1.931 +{ 1.932 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; 1.933 + 1.934 + nsBaseWidget::SetCursor(aCursor, aHotspotX, aHotspotY); 1.935 + return [[nsCursorManager sharedInstance] setCursorWithImage:aCursor hotSpotX:aHotspotX hotSpotY:aHotspotY scaleFactor:BackingScaleFactor()]; 1.936 + 1.937 + NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; 1.938 +} 1.939 + 1.940 +#pragma mark - 1.941 + 1.942 +// Get this component dimension 1.943 +NS_IMETHODIMP nsChildView::GetBounds(nsIntRect &aRect) 1.944 +{ 1.945 + if (!mView) { 1.946 + aRect = mBounds; 1.947 + } else { 1.948 + aRect = CocoaPointsToDevPixels([mView frame]); 1.949 + } 1.950 + return NS_OK; 1.951 +} 1.952 + 1.953 +NS_IMETHODIMP nsChildView::GetClientBounds(nsIntRect &aRect) 1.954 +{ 1.955 + GetBounds(aRect); 1.956 + if (!mParentWidget) { 1.957 + // For top level widgets we want the position on screen, not the position 1.958 + // of this view inside the window. 1.959 + MOZ_ASSERT(mWindowType != eWindowType_plugin, "plugin widgets should have parents"); 1.960 + aRect.MoveTo(WidgetToScreenOffset()); 1.961 + } 1.962 + return NS_OK; 1.963 +} 1.964 + 1.965 +NS_IMETHODIMP nsChildView::GetScreenBounds(nsIntRect &aRect) 1.966 +{ 1.967 + GetBounds(aRect); 1.968 + aRect.MoveTo(WidgetToScreenOffset()); 1.969 + return NS_OK; 1.970 +} 1.971 + 1.972 +double 1.973 +nsChildView::GetDefaultScaleInternal() 1.974 +{ 1.975 + return BackingScaleFactor(); 1.976 +} 1.977 + 1.978 +CGFloat 1.979 +nsChildView::BackingScaleFactor() 1.980 +{ 1.981 + if (mBackingScaleFactor > 0.0) { 1.982 + return mBackingScaleFactor; 1.983 + } 1.984 + if (!mView) { 1.985 + return 1.0; 1.986 + } 1.987 + mBackingScaleFactor = nsCocoaUtils::GetBackingScaleFactor(mView); 1.988 + return mBackingScaleFactor; 1.989 +} 1.990 + 1.991 +void 1.992 +nsChildView::BackingScaleFactorChanged() 1.993 +{ 1.994 + CGFloat newScale = nsCocoaUtils::GetBackingScaleFactor(mView); 1.995 + 1.996 + // ignore notification if it hasn't really changed (or maybe we have 1.997 + // disabled HiDPI mode via prefs) 1.998 + if (mBackingScaleFactor == newScale) { 1.999 + return; 1.1000 + } 1.1001 + 1.1002 + mBackingScaleFactor = newScale; 1.1003 + 1.1004 + if (mWidgetListener && !mWidgetListener->GetXULWindow()) { 1.1005 + nsIPresShell* presShell = mWidgetListener->GetPresShell(); 1.1006 + if (presShell) { 1.1007 + presShell->BackingScaleFactorChanged(); 1.1008 + } 1.1009 + } 1.1010 + 1.1011 + if (IsPluginView()) { 1.1012 + nsEventStatus status = nsEventStatus_eIgnore; 1.1013 + WidgetGUIEvent guiEvent(true, NS_PLUGIN_RESOLUTION_CHANGED, this); 1.1014 + guiEvent.time = PR_IntervalNow(); 1.1015 + DispatchEvent(&guiEvent, status); 1.1016 + } 1.1017 +} 1.1018 + 1.1019 +int32_t 1.1020 +nsChildView::RoundsWidgetCoordinatesTo() 1.1021 +{ 1.1022 + if (BackingScaleFactor() == 2.0) { 1.1023 + return 2; 1.1024 + } 1.1025 + return 1; 1.1026 +} 1.1027 + 1.1028 +NS_IMETHODIMP nsChildView::ConstrainPosition(bool aAllowSlop, 1.1029 + int32_t *aX, int32_t *aY) 1.1030 +{ 1.1031 + return NS_OK; 1.1032 +} 1.1033 + 1.1034 +// Move this component, aX and aY are in the parent widget coordinate system 1.1035 +NS_IMETHODIMP nsChildView::Move(double aX, double aY) 1.1036 +{ 1.1037 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; 1.1038 + 1.1039 + int32_t x = NSToIntRound(aX); 1.1040 + int32_t y = NSToIntRound(aY); 1.1041 + 1.1042 + if (!mView || (mBounds.x == x && mBounds.y == y)) 1.1043 + return NS_OK; 1.1044 + 1.1045 + mBounds.x = x; 1.1046 + mBounds.y = y; 1.1047 + 1.1048 + ManipulateViewWithoutNeedingDisplay(mView, ^{ 1.1049 + [mView setFrame:DevPixelsToCocoaPoints(mBounds)]; 1.1050 + }); 1.1051 + 1.1052 + NotifyRollupGeometryChange(); 1.1053 + ReportMoveEvent(); 1.1054 + 1.1055 + return NS_OK; 1.1056 + 1.1057 + NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; 1.1058 +} 1.1059 + 1.1060 +NS_IMETHODIMP nsChildView::Resize(double aWidth, double aHeight, bool aRepaint) 1.1061 +{ 1.1062 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; 1.1063 + 1.1064 + int32_t width = NSToIntRound(aWidth); 1.1065 + int32_t height = NSToIntRound(aHeight); 1.1066 + 1.1067 + if (!mView || (mBounds.width == width && mBounds.height == height)) 1.1068 + return NS_OK; 1.1069 + 1.1070 + mBounds.width = width; 1.1071 + mBounds.height = height; 1.1072 + 1.1073 + ManipulateViewWithoutNeedingDisplay(mView, ^{ 1.1074 + [mView setFrame:DevPixelsToCocoaPoints(mBounds)]; 1.1075 + }); 1.1076 + 1.1077 + if (mVisible && aRepaint) 1.1078 + [mView setNeedsDisplay:YES]; 1.1079 + 1.1080 + NotifyRollupGeometryChange(); 1.1081 + ReportSizeEvent(); 1.1082 + 1.1083 + return NS_OK; 1.1084 + 1.1085 + NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; 1.1086 +} 1.1087 + 1.1088 +NS_IMETHODIMP nsChildView::Resize(double aX, double aY, 1.1089 + double aWidth, double aHeight, bool aRepaint) 1.1090 +{ 1.1091 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; 1.1092 + 1.1093 + int32_t x = NSToIntRound(aX); 1.1094 + int32_t y = NSToIntRound(aY); 1.1095 + int32_t width = NSToIntRound(aWidth); 1.1096 + int32_t height = NSToIntRound(aHeight); 1.1097 + 1.1098 + BOOL isMoving = (mBounds.x != x || mBounds.y != y); 1.1099 + BOOL isResizing = (mBounds.width != width || mBounds.height != height); 1.1100 + if (!mView || (!isMoving && !isResizing)) 1.1101 + return NS_OK; 1.1102 + 1.1103 + if (isMoving) { 1.1104 + mBounds.x = x; 1.1105 + mBounds.y = y; 1.1106 + } 1.1107 + if (isResizing) { 1.1108 + mBounds.width = width; 1.1109 + mBounds.height = height; 1.1110 + } 1.1111 + 1.1112 + ManipulateViewWithoutNeedingDisplay(mView, ^{ 1.1113 + [mView setFrame:DevPixelsToCocoaPoints(mBounds)]; 1.1114 + }); 1.1115 + 1.1116 + if (mVisible && aRepaint) 1.1117 + [mView setNeedsDisplay:YES]; 1.1118 + 1.1119 + NotifyRollupGeometryChange(); 1.1120 + if (isMoving) { 1.1121 + ReportMoveEvent(); 1.1122 + if (mOnDestroyCalled) 1.1123 + return NS_OK; 1.1124 + } 1.1125 + if (isResizing) 1.1126 + ReportSizeEvent(); 1.1127 + 1.1128 + return NS_OK; 1.1129 + 1.1130 + NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; 1.1131 +} 1.1132 + 1.1133 +static const int32_t resizeIndicatorWidth = 15; 1.1134 +static const int32_t resizeIndicatorHeight = 15; 1.1135 +bool nsChildView::ShowsResizeIndicator(nsIntRect* aResizerRect) 1.1136 +{ 1.1137 + NSView *topLevelView = mView, *superView = nil; 1.1138 + while ((superView = [topLevelView superview])) 1.1139 + topLevelView = superView; 1.1140 + 1.1141 + if (![[topLevelView window] showsResizeIndicator] || 1.1142 + !([[topLevelView window] styleMask] & NSResizableWindowMask)) 1.1143 + return false; 1.1144 + 1.1145 + if (aResizerRect) { 1.1146 + NSSize bounds = [topLevelView bounds].size; 1.1147 + NSPoint corner = NSMakePoint(bounds.width, [topLevelView isFlipped] ? bounds.height : 0); 1.1148 + corner = [topLevelView convertPoint:corner toView:mView]; 1.1149 + aResizerRect->SetRect(NSToIntRound(corner.x) - resizeIndicatorWidth, 1.1150 + NSToIntRound(corner.y) - resizeIndicatorHeight, 1.1151 + resizeIndicatorWidth, resizeIndicatorHeight); 1.1152 + } 1.1153 + return true; 1.1154 +} 1.1155 + 1.1156 +// In QuickDraw mode the coordinate system used here should be that of the 1.1157 +// browser window's content region (defined as everything but the 22-pixel 1.1158 +// high titlebar). But in CoreGraphics mode the coordinate system should be 1.1159 +// that of the browser window as a whole (including its titlebar). Both 1.1160 +// coordinate systems have a top-left origin. See bmo bug 474491. 1.1161 +// 1.1162 +// There's a bug in this method's code -- it currently uses the QuickDraw 1.1163 +// coordinate system for both the QuickDraw and CoreGraphics drawing modes. 1.1164 +// This bug is fixed by the patch for bug 474491. But the Flash plugin (both 1.1165 +// version 10.0.12.36 from Adobe and version 9.0 r151 from Apple) has Mozilla- 1.1166 +// specific code to work around this bug, which breaks when we fix it (see bmo 1.1167 +// bug 477077). So we'll need to coordinate releasing a fix for this bug with 1.1168 +// Adobe and other major plugin vendors that support the CoreGraphics mode. 1.1169 +// 1.1170 +// outClipRect and outOrigin are in display pixels, not device pixels. 1.1171 +NS_IMETHODIMP nsChildView::GetPluginClipRect(nsIntRect& outClipRect, nsIntPoint& outOrigin, bool& outWidgetVisible) 1.1172 +{ 1.1173 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; 1.1174 + 1.1175 + NS_ASSERTION(mWindowType == eWindowType_plugin, 1.1176 + "GetPluginClipRect must only be called on a plugin widget"); 1.1177 + if (mWindowType != eWindowType_plugin) return NS_ERROR_FAILURE; 1.1178 + 1.1179 + NSWindow* window = [mView window]; 1.1180 + if (!window) return NS_ERROR_FAILURE; 1.1181 + 1.1182 + NSPoint viewOrigin = [mView convertPoint:NSZeroPoint toView:nil]; 1.1183 + NSRect frame = [[window contentView] frame]; 1.1184 + viewOrigin.y = frame.size.height - viewOrigin.y; 1.1185 + 1.1186 + // set up the clipping region for plugins. 1.1187 + NSRect visibleBounds = [mView visibleRect]; 1.1188 + NSPoint clipOrigin = [mView convertPoint:visibleBounds.origin toView:nil]; 1.1189 + 1.1190 + // Convert from cocoa to QuickDraw coordinates 1.1191 + clipOrigin.y = frame.size.height - clipOrigin.y; 1.1192 + 1.1193 + outClipRect.x = NSToIntRound(clipOrigin.x); 1.1194 + outClipRect.y = NSToIntRound(clipOrigin.y); 1.1195 + 1.1196 + // need to convert view's origin to window coordinates. 1.1197 + // then, encode as "SetOrigin" ready values. 1.1198 + outOrigin.x = -NSToIntRound(viewOrigin.x); 1.1199 + outOrigin.y = -NSToIntRound(viewOrigin.y); 1.1200 + 1.1201 + if (IsVisible() && [mView window] != nil) { 1.1202 + outClipRect.width = NSToIntRound(visibleBounds.origin.x + visibleBounds.size.width) - NSToIntRound(visibleBounds.origin.x); 1.1203 + outClipRect.height = NSToIntRound(visibleBounds.origin.y + visibleBounds.size.height) - NSToIntRound(visibleBounds.origin.y); 1.1204 + 1.1205 + if (mClipRects) { 1.1206 + nsIntRect clipBounds; 1.1207 + for (uint32_t i = 0; i < mClipRectCount; ++i) { 1.1208 + NSRect cocoaPoints = DevPixelsToCocoaPoints(mClipRects[i]); 1.1209 + clipBounds.UnionRect(clipBounds, nsIntRect(NSToIntRound(cocoaPoints.origin.x), 1.1210 + NSToIntRound(cocoaPoints.origin.y), 1.1211 + NSToIntRound(cocoaPoints.size.width), 1.1212 + NSToIntRound(cocoaPoints.size.height))); 1.1213 + } 1.1214 + outClipRect.IntersectRect(outClipRect, clipBounds - outOrigin); 1.1215 + } 1.1216 + 1.1217 + // XXXroc should this be !outClipRect.IsEmpty()? 1.1218 + outWidgetVisible = true; 1.1219 + } 1.1220 + else { 1.1221 + outClipRect.width = 0; 1.1222 + outClipRect.height = 0; 1.1223 + outWidgetVisible = false; 1.1224 + } 1.1225 + 1.1226 + return NS_OK; 1.1227 + 1.1228 + NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; 1.1229 +} 1.1230 + 1.1231 +NS_IMETHODIMP nsChildView::StartDrawPlugin() 1.1232 +{ 1.1233 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; 1.1234 + 1.1235 + NS_ASSERTION(mWindowType == eWindowType_plugin, 1.1236 + "StartDrawPlugin must only be called on a plugin widget"); 1.1237 + if (mWindowType != eWindowType_plugin) return NS_ERROR_FAILURE; 1.1238 + 1.1239 + // This code is necessary for CoreGraphics in 32-bit builds. 1.1240 + // See comments below about why. In 64-bit CoreGraphics mode we will not keep 1.1241 + // this region up to date, plugins should not depend on it. 1.1242 +#ifndef __LP64__ 1.1243 + NSWindow* window = [mView window]; 1.1244 + if (!window) 1.1245 + return NS_ERROR_FAILURE; 1.1246 + 1.1247 + // In QuickDraw drawing mode we used to prevent reentrant handling of any 1.1248 + // plugin event. But in CoreGraphics drawing mode only do this if the current 1.1249 + // plugin event isn't an update/paint event. This allows popupcontextmenu() 1.1250 + // to work properly from a plugin that supports the Cocoa event model, 1.1251 + // without regressing bug 409615. See bug 435041. (StartDrawPlugin() and 1.1252 + // EndDrawPlugin() wrap every call to nsIPluginInstance::HandleEvent() -- 1.1253 + // not just calls that "draw" or paint.) 1.1254 + if (mIsDispatchPaint && mPluginDrawing) { 1.1255 + return NS_ERROR_FAILURE; 1.1256 + } 1.1257 + 1.1258 + // It appears that the WindowRef from which we get the plugin port undergoes the 1.1259 + // traditional BeginUpdate/EndUpdate cycle, which, if you recall, sets the visible 1.1260 + // region to the intersection of the visible region and the update region. Since 1.1261 + // we don't know here if we're being drawn inside a BeginUpdate/EndUpdate pair 1.1262 + // (which seem to occur in [NSWindow display]), and we don't want to have the burden 1.1263 + // of correctly doing Carbon invalidates of the plugin rect, we manually set the 1.1264 + // visible region to be the entire port every time. It is necessary to set up our 1.1265 + // window's port even for CoreGraphics plugins, because they may still use Carbon 1.1266 + // internally (see bug #420527 for details). 1.1267 + // 1.1268 + // Don't use this code if any of the QuickDraw APIs it currently requires are 1.1269 + // missing (as they probably will be on OS X 10.8 and up). 1.1270 + if (::NewRgn && ::GetQDGlobalsThePort && ::GetGWorld && ::SetGWorld && 1.1271 + ::IsPortOffscreen && ::GetMainDevice && ::SetOrigin && ::RectRgn && 1.1272 + ::SetPortVisibleRegion && ::SetPortClipRegion && ::DisposeRgn) { 1.1273 + RgnHandle pluginRegion = ::NewRgn(); 1.1274 + if (pluginRegion) { 1.1275 + CGrafPtr port = ::GetWindowPort(WindowRef([window windowRef])); 1.1276 + bool portChanged = (port != CGrafPtr(::GetQDGlobalsThePort())); 1.1277 + CGrafPtr oldPort; 1.1278 + GDHandle oldDevice; 1.1279 + 1.1280 + if (portChanged) { 1.1281 + ::GetGWorld(&oldPort, &oldDevice); 1.1282 + ::SetGWorld(port, ::IsPortOffscreen(port) ? nullptr : ::GetMainDevice()); 1.1283 + } 1.1284 + 1.1285 + ::SetOrigin(0, 0); 1.1286 + 1.1287 + nsIntRect clipRect; // this is in native window coordinates 1.1288 + nsIntPoint origin; 1.1289 + bool visible; 1.1290 + GetPluginClipRect(clipRect, origin, visible); 1.1291 + 1.1292 + // XXX if we're not visible, set an empty clip region? 1.1293 + Rect pluginRect; 1.1294 + ConvertGeckoRectToMacRect(clipRect, pluginRect); 1.1295 + 1.1296 + ::RectRgn(pluginRegion, &pluginRect); 1.1297 + ::SetPortVisibleRegion(port, pluginRegion); 1.1298 + ::SetPortClipRegion(port, pluginRegion); 1.1299 + 1.1300 + // now set up the origin for the plugin 1.1301 + ::SetOrigin(origin.x, origin.y); 1.1302 + 1.1303 + ::DisposeRgn(pluginRegion); 1.1304 + 1.1305 + if (portChanged) { 1.1306 + ::SetGWorld(oldPort, oldDevice); 1.1307 + } 1.1308 + } 1.1309 + } 1.1310 +#endif 1.1311 + 1.1312 + mPluginDrawing = true; 1.1313 + return NS_OK; 1.1314 + 1.1315 + NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; 1.1316 +} 1.1317 + 1.1318 +NS_IMETHODIMP nsChildView::EndDrawPlugin() 1.1319 +{ 1.1320 + NS_ASSERTION(mWindowType == eWindowType_plugin, 1.1321 + "EndDrawPlugin must only be called on a plugin widget"); 1.1322 + if (mWindowType != eWindowType_plugin) return NS_ERROR_FAILURE; 1.1323 + 1.1324 + mPluginDrawing = false; 1.1325 + return NS_OK; 1.1326 +} 1.1327 + 1.1328 +NS_IMETHODIMP nsChildView::SetPluginInstanceOwner(nsIPluginInstanceOwner* aInstanceOwner) 1.1329 +{ 1.1330 + mPluginInstanceOwner = aInstanceOwner; 1.1331 + 1.1332 + return NS_OK; 1.1333 +} 1.1334 + 1.1335 +NS_IMETHODIMP nsChildView::SetPluginEventModel(int inEventModel) 1.1336 +{ 1.1337 + [(ChildView*)mView setPluginEventModel:(NPEventModel)inEventModel]; 1.1338 + return NS_OK; 1.1339 +} 1.1340 + 1.1341 +NS_IMETHODIMP nsChildView::GetPluginEventModel(int* outEventModel) 1.1342 +{ 1.1343 + *outEventModel = [(ChildView*)mView pluginEventModel]; 1.1344 + return NS_OK; 1.1345 +} 1.1346 + 1.1347 +NS_IMETHODIMP nsChildView::SetPluginDrawingModel(int inDrawingModel) 1.1348 +{ 1.1349 + [(ChildView*)mView setPluginDrawingModel:(NPDrawingModel)inDrawingModel]; 1.1350 + return NS_OK; 1.1351 +} 1.1352 + 1.1353 +NS_IMETHODIMP nsChildView::StartComplexTextInputForCurrentEvent() 1.1354 +{ 1.1355 + return mTextInputHandler->StartComplexTextInputForCurrentEvent(); 1.1356 +} 1.1357 + 1.1358 +nsresult nsChildView::SynthesizeNativeKeyEvent(int32_t aNativeKeyboardLayout, 1.1359 + int32_t aNativeKeyCode, 1.1360 + uint32_t aModifierFlags, 1.1361 + const nsAString& aCharacters, 1.1362 + const nsAString& aUnmodifiedCharacters) 1.1363 +{ 1.1364 + return mTextInputHandler->SynthesizeNativeKeyEvent(aNativeKeyboardLayout, 1.1365 + aNativeKeyCode, 1.1366 + aModifierFlags, 1.1367 + aCharacters, 1.1368 + aUnmodifiedCharacters); 1.1369 +} 1.1370 + 1.1371 +nsresult nsChildView::SynthesizeNativeMouseEvent(nsIntPoint aPoint, 1.1372 + uint32_t aNativeMessage, 1.1373 + uint32_t aModifierFlags) 1.1374 +{ 1.1375 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; 1.1376 + 1.1377 + NSPoint pt = 1.1378 + nsCocoaUtils::DevPixelsToCocoaPoints(aPoint, BackingScaleFactor()); 1.1379 + 1.1380 + // Move the mouse cursor to the requested position and reconnect it to the mouse. 1.1381 + CGWarpMouseCursorPosition(NSPointToCGPoint(pt)); 1.1382 + CGAssociateMouseAndMouseCursorPosition(true); 1.1383 + 1.1384 + // aPoint is given with the origin on the top left, but convertScreenToBase 1.1385 + // expects a point in a coordinate system that has its origin on the bottom left. 1.1386 + NSPoint screenPoint = NSMakePoint(pt.x, nsCocoaUtils::FlippedScreenY(pt.y)); 1.1387 + NSPoint windowPoint = [[mView window] convertScreenToBase:screenPoint]; 1.1388 + 1.1389 + NSEvent* event = [NSEvent mouseEventWithType:(NSEventType)aNativeMessage 1.1390 + location:windowPoint 1.1391 + modifierFlags:aModifierFlags 1.1392 + timestamp:[NSDate timeIntervalSinceReferenceDate] 1.1393 + windowNumber:[[mView window] windowNumber] 1.1394 + context:nil 1.1395 + eventNumber:0 1.1396 + clickCount:1 1.1397 + pressure:0.0]; 1.1398 + 1.1399 + if (!event) 1.1400 + return NS_ERROR_FAILURE; 1.1401 + 1.1402 + if ([[mView window] isKindOfClass:[BaseWindow class]]) { 1.1403 + // Tracking area events don't end up in their tracking areas when sent 1.1404 + // through [NSApp sendEvent:], so pass them directly to the right methods. 1.1405 + BaseWindow* window = (BaseWindow*)[mView window]; 1.1406 + if (aNativeMessage == NSMouseEntered) { 1.1407 + [window mouseEntered:event]; 1.1408 + return NS_OK; 1.1409 + } 1.1410 + if (aNativeMessage == NSMouseExited) { 1.1411 + [window mouseExited:event]; 1.1412 + return NS_OK; 1.1413 + } 1.1414 + if (aNativeMessage == NSMouseMoved) { 1.1415 + [window mouseMoved:event]; 1.1416 + return NS_OK; 1.1417 + } 1.1418 + } 1.1419 + 1.1420 + [NSApp sendEvent:event]; 1.1421 + return NS_OK; 1.1422 + 1.1423 + NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; 1.1424 +} 1.1425 + 1.1426 +// First argument has to be an NSMenu representing the application's top-level 1.1427 +// menu bar. The returned item is *not* retained. 1.1428 +static NSMenuItem* NativeMenuItemWithLocation(NSMenu* menubar, NSString* locationString) 1.1429 +{ 1.1430 + NSArray* indexes = [locationString componentsSeparatedByString:@"|"]; 1.1431 + unsigned int indexCount = [indexes count]; 1.1432 + if (indexCount == 0) 1.1433 + return nil; 1.1434 + 1.1435 + NSMenu* currentSubmenu = [NSApp mainMenu]; 1.1436 + for (unsigned int i = 0; i < indexCount; i++) { 1.1437 + int targetIndex; 1.1438 + // We remove the application menu from consideration for the top-level menu 1.1439 + if (i == 0) 1.1440 + targetIndex = [[indexes objectAtIndex:i] intValue] + 1; 1.1441 + else 1.1442 + targetIndex = [[indexes objectAtIndex:i] intValue]; 1.1443 + int itemCount = [currentSubmenu numberOfItems]; 1.1444 + if (targetIndex < itemCount) { 1.1445 + NSMenuItem* menuItem = [currentSubmenu itemAtIndex:targetIndex]; 1.1446 + // if this is the last index just return the menu item 1.1447 + if (i == (indexCount - 1)) 1.1448 + return menuItem; 1.1449 + // if this is not the last index find the submenu and keep going 1.1450 + if ([menuItem hasSubmenu]) 1.1451 + currentSubmenu = [menuItem submenu]; 1.1452 + else 1.1453 + return nil; 1.1454 + } 1.1455 + } 1.1456 + 1.1457 + return nil; 1.1458 +} 1.1459 + 1.1460 +// Used for testing native menu system structure and event handling. 1.1461 +NS_IMETHODIMP nsChildView::ActivateNativeMenuItemAt(const nsAString& indexString) 1.1462 +{ 1.1463 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; 1.1464 + 1.1465 + NSString* locationString = [NSString stringWithCharacters:reinterpret_cast<const unichar*>(indexString.BeginReading()) 1.1466 + length:indexString.Length()]; 1.1467 + NSMenuItem* item = NativeMenuItemWithLocation([NSApp mainMenu], locationString); 1.1468 + // We can't perform an action on an item with a submenu, that will raise 1.1469 + // an obj-c exception. 1.1470 + if (item && ![item hasSubmenu]) { 1.1471 + NSMenu* parent = [item menu]; 1.1472 + if (parent) { 1.1473 + // NSLog(@"Performing action for native menu item titled: %@\n", 1.1474 + // [[currentSubmenu itemAtIndex:targetIndex] title]); 1.1475 + [parent performActionForItemAtIndex:[parent indexOfItem:item]]; 1.1476 + return NS_OK; 1.1477 + } 1.1478 + } 1.1479 + return NS_ERROR_FAILURE; 1.1480 + 1.1481 + NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; 1.1482 +} 1.1483 + 1.1484 +// Used for testing native menu system structure and event handling. 1.1485 +NS_IMETHODIMP nsChildView::ForceUpdateNativeMenuAt(const nsAString& indexString) 1.1486 +{ 1.1487 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; 1.1488 + 1.1489 + nsCocoaWindow *widget = GetXULWindowWidget(); 1.1490 + if (widget) { 1.1491 + nsMenuBarX* mb = widget->GetMenuBar(); 1.1492 + if (mb) { 1.1493 + if (indexString.IsEmpty()) 1.1494 + mb->ForceNativeMenuReload(); 1.1495 + else 1.1496 + mb->ForceUpdateNativeMenuAt(indexString); 1.1497 + } 1.1498 + } 1.1499 + return NS_OK; 1.1500 + 1.1501 + NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; 1.1502 +} 1.1503 + 1.1504 +#pragma mark - 1.1505 + 1.1506 +#ifdef INVALIDATE_DEBUGGING 1.1507 + 1.1508 +static Boolean KeyDown(const UInt8 theKey) 1.1509 +{ 1.1510 + KeyMap map; 1.1511 + GetKeys(map); 1.1512 + return ((*((UInt8 *)map + (theKey >> 3)) >> (theKey & 7)) & 1) != 0; 1.1513 +} 1.1514 + 1.1515 +static Boolean caps_lock() 1.1516 +{ 1.1517 + return KeyDown(0x39); 1.1518 +} 1.1519 + 1.1520 +static void blinkRect(Rect* r) 1.1521 +{ 1.1522 + StRegionFromPool oldClip; 1.1523 + if (oldClip != NULL) 1.1524 + ::GetClip(oldClip); 1.1525 + 1.1526 + ::ClipRect(r); 1.1527 + ::InvertRect(r); 1.1528 + UInt32 end = ::TickCount() + 5; 1.1529 + while (::TickCount() < end) ; 1.1530 + ::InvertRect(r); 1.1531 + 1.1532 + if (oldClip != NULL) 1.1533 + ::SetClip(oldClip); 1.1534 +} 1.1535 + 1.1536 +static void blinkRgn(RgnHandle rgn) 1.1537 +{ 1.1538 + StRegionFromPool oldClip; 1.1539 + if (oldClip != NULL) 1.1540 + ::GetClip(oldClip); 1.1541 + 1.1542 + ::SetClip(rgn); 1.1543 + ::InvertRgn(rgn); 1.1544 + UInt32 end = ::TickCount() + 5; 1.1545 + while (::TickCount() < end) ; 1.1546 + ::InvertRgn(rgn); 1.1547 + 1.1548 + if (oldClip != NULL) 1.1549 + ::SetClip(oldClip); 1.1550 +} 1.1551 + 1.1552 +#endif 1.1553 + 1.1554 +// Invalidate this component's visible area 1.1555 +NS_IMETHODIMP nsChildView::Invalidate(const nsIntRect &aRect) 1.1556 +{ 1.1557 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; 1.1558 + 1.1559 + if (!mView || !mVisible) 1.1560 + return NS_OK; 1.1561 + 1.1562 + NS_ASSERTION(GetLayerManager()->GetBackendType() != LayersBackend::LAYERS_CLIENT, 1.1563 + "Shouldn't need to invalidate with accelerated OMTC layers!"); 1.1564 + 1.1565 + if ([NSView focusView]) { 1.1566 + // if a view is focussed (i.e. being drawn), then postpone the invalidate so that we 1.1567 + // don't lose it. 1.1568 + [mView setNeedsPendingDisplayInRect:DevPixelsToCocoaPoints(aRect)]; 1.1569 + } 1.1570 + else { 1.1571 + [mView setNeedsDisplayInRect:DevPixelsToCocoaPoints(aRect)]; 1.1572 + } 1.1573 + 1.1574 + return NS_OK; 1.1575 + 1.1576 + NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; 1.1577 +} 1.1578 + 1.1579 +bool 1.1580 +nsChildView::ComputeShouldAccelerate(bool aDefault) 1.1581 +{ 1.1582 + // Don't use OpenGL for transparent windows or for popup windows. 1.1583 + if (!mView || ![[mView window] isOpaque] || 1.1584 + [[mView window] isKindOfClass:[PopupWindow class]]) 1.1585 + return false; 1.1586 + 1.1587 + return nsBaseWidget::ComputeShouldAccelerate(aDefault); 1.1588 +} 1.1589 + 1.1590 +bool 1.1591 +nsChildView::ShouldUseOffMainThreadCompositing() 1.1592 +{ 1.1593 + // Don't use OMTC for transparent windows or for popup windows. 1.1594 + if (!mView || ![[mView window] isOpaque] || 1.1595 + [[mView window] isKindOfClass:[PopupWindow class]]) 1.1596 + return false; 1.1597 + 1.1598 + return nsBaseWidget::ShouldUseOffMainThreadCompositing(); 1.1599 +} 1.1600 + 1.1601 +inline uint16_t COLOR8TOCOLOR16(uint8_t color8) 1.1602 +{ 1.1603 + // return (color8 == 0xFF ? 0xFFFF : (color8 << 8)); 1.1604 + return (color8 << 8) | color8; /* (color8 * 257) == (color8 * 0x0101) */ 1.1605 +} 1.1606 + 1.1607 +#pragma mark - 1.1608 + 1.1609 +nsresult nsChildView::ConfigureChildren(const nsTArray<Configuration>& aConfigurations) 1.1610 +{ 1.1611 + for (uint32_t i = 0; i < aConfigurations.Length(); ++i) { 1.1612 + const Configuration& config = aConfigurations[i]; 1.1613 + nsChildView* child = static_cast<nsChildView*>(config.mChild); 1.1614 +#ifdef DEBUG 1.1615 + nsWindowType kidType = child->WindowType(); 1.1616 +#endif 1.1617 + NS_ASSERTION(kidType == eWindowType_plugin, 1.1618 + "Configured widget is not a plugin type"); 1.1619 + NS_ASSERTION(child->GetParent() == this, 1.1620 + "Configured widget is not a child of the right widget"); 1.1621 + 1.1622 + // nsIWidget::Show() doesn't get called on plugin widgets unless we call 1.1623 + // it from here. See bug 592563. 1.1624 + child->Show(!config.mClipRegion.IsEmpty()); 1.1625 + 1.1626 + child->Resize( 1.1627 + config.mBounds.x, config.mBounds.y, 1.1628 + config.mBounds.width, config.mBounds.height, 1.1629 + false); 1.1630 + 1.1631 + // Store the clip region here in case GetPluginClipRect needs it. 1.1632 + child->StoreWindowClipRegion(config.mClipRegion); 1.1633 + } 1.1634 + return NS_OK; 1.1635 +} 1.1636 + 1.1637 +// Invokes callback and ProcessEvent methods on Event Listener object 1.1638 +NS_IMETHODIMP nsChildView::DispatchEvent(WidgetGUIEvent* event, 1.1639 + nsEventStatus& aStatus) 1.1640 +{ 1.1641 +#ifdef DEBUG 1.1642 + debug_DumpEvent(stdout, event->widget, event, nsAutoCString("something"), 0); 1.1643 +#endif 1.1644 + 1.1645 + NS_ASSERTION(!(mTextInputHandler && mTextInputHandler->IsIMEComposing() && 1.1646 + event->HasKeyEventMessage()), 1.1647 + "Any key events should not be fired during IME composing"); 1.1648 + 1.1649 + if (event->mFlags.mIsSynthesizedForTests) { 1.1650 + WidgetKeyboardEvent* keyEvent = event->AsKeyboardEvent(); 1.1651 + if (keyEvent) { 1.1652 + nsresult rv = mTextInputHandler->AttachNativeKeyEvent(*keyEvent); 1.1653 + NS_ENSURE_SUCCESS(rv, rv); 1.1654 + } 1.1655 + } 1.1656 + 1.1657 + aStatus = nsEventStatus_eIgnore; 1.1658 + 1.1659 + nsIWidgetListener* listener = mWidgetListener; 1.1660 + 1.1661 + // If the listener is NULL, check if the parent is a popup. If it is, then 1.1662 + // this child is the popup content view attached to a popup. Get the 1.1663 + // listener from the parent popup instead. 1.1664 + nsCOMPtr<nsIWidget> kungFuDeathGrip = do_QueryInterface(mParentWidget ? mParentWidget : this); 1.1665 + if (!listener && mParentWidget) { 1.1666 + if (mParentWidget->WindowType() == eWindowType_popup) { 1.1667 + // Check just in case event->widget isn't this widget 1.1668 + if (event->widget) 1.1669 + listener = event->widget->GetWidgetListener(); 1.1670 + if (!listener) { 1.1671 + event->widget = mParentWidget; 1.1672 + listener = mParentWidget->GetWidgetListener(); 1.1673 + } 1.1674 + } 1.1675 + } 1.1676 + 1.1677 + if (listener) 1.1678 + aStatus = listener->HandleEvent(event, mUseAttachedEvents); 1.1679 + 1.1680 + return NS_OK; 1.1681 +} 1.1682 + 1.1683 +bool nsChildView::DispatchWindowEvent(WidgetGUIEvent& event) 1.1684 +{ 1.1685 + nsEventStatus status; 1.1686 + DispatchEvent(&event, status); 1.1687 + return ConvertStatus(status); 1.1688 +} 1.1689 + 1.1690 +nsIWidget* 1.1691 +nsChildView::GetWidgetForListenerEvents() 1.1692 +{ 1.1693 + // If there is no listener, use the parent popup's listener if that exists. 1.1694 + if (!mWidgetListener && mParentWidget && 1.1695 + mParentWidget->WindowType() == eWindowType_popup) { 1.1696 + return mParentWidget; 1.1697 + } 1.1698 + 1.1699 + return this; 1.1700 +} 1.1701 + 1.1702 +void nsChildView::WillPaintWindow() 1.1703 +{ 1.1704 + nsCOMPtr<nsIWidget> widget = GetWidgetForListenerEvents(); 1.1705 + 1.1706 + nsIWidgetListener* listener = widget->GetWidgetListener(); 1.1707 + if (listener) { 1.1708 + listener->WillPaintWindow(widget); 1.1709 + } 1.1710 +} 1.1711 + 1.1712 +bool nsChildView::PaintWindow(nsIntRegion aRegion) 1.1713 +{ 1.1714 + nsCOMPtr<nsIWidget> widget = GetWidgetForListenerEvents(); 1.1715 + 1.1716 + nsIWidgetListener* listener = widget->GetWidgetListener(); 1.1717 + if (!listener) 1.1718 + return false; 1.1719 + 1.1720 + bool returnValue = false; 1.1721 + bool oldDispatchPaint = mIsDispatchPaint; 1.1722 + mIsDispatchPaint = true; 1.1723 + returnValue = listener->PaintWindow(widget, aRegion); 1.1724 + 1.1725 + listener = widget->GetWidgetListener(); 1.1726 + if (listener) { 1.1727 + listener->DidPaintWindow(); 1.1728 + } 1.1729 + 1.1730 + mIsDispatchPaint = oldDispatchPaint; 1.1731 + return returnValue; 1.1732 +} 1.1733 + 1.1734 +#pragma mark - 1.1735 + 1.1736 +void nsChildView::ReportMoveEvent() 1.1737 +{ 1.1738 + NotifyWindowMoved(mBounds.x, mBounds.y); 1.1739 +} 1.1740 + 1.1741 +void nsChildView::ReportSizeEvent() 1.1742 +{ 1.1743 + if (mWidgetListener) 1.1744 + mWidgetListener->WindowResized(this, mBounds.width, mBounds.height); 1.1745 +} 1.1746 + 1.1747 +#pragma mark - 1.1748 + 1.1749 +// Return the offset between this child view and the screen. 1.1750 +// @return -- widget origin in device-pixel coords 1.1751 +nsIntPoint nsChildView::WidgetToScreenOffset() 1.1752 +{ 1.1753 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN; 1.1754 + 1.1755 + NSPoint origin = NSMakePoint(0, 0); 1.1756 + 1.1757 + // 1. First translate view origin point into window coords. 1.1758 + // The returned point is in bottom-left coordinates. 1.1759 + origin = [mView convertPoint:origin toView:nil]; 1.1760 + 1.1761 + // 2. We turn the window-coord rect's origin into screen (still bottom-left) coords. 1.1762 + origin = [[mView window] convertBaseToScreen:origin]; 1.1763 + 1.1764 + // 3. Since we're dealing in bottom-left coords, we need to make it top-left coords 1.1765 + // before we pass it back to Gecko. 1.1766 + FlipCocoaScreenCoordinate(origin); 1.1767 + 1.1768 + // convert to device pixels 1.1769 + return CocoaPointsToDevPixels(origin); 1.1770 + 1.1771 + NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(nsIntPoint(0,0)); 1.1772 +} 1.1773 + 1.1774 +NS_IMETHODIMP nsChildView::CaptureRollupEvents(nsIRollupListener * aListener, 1.1775 + bool aDoCapture) 1.1776 +{ 1.1777 + // this never gets called, only top-level windows can be rollup widgets 1.1778 + return NS_OK; 1.1779 +} 1.1780 + 1.1781 +NS_IMETHODIMP nsChildView::SetTitle(const nsAString& title) 1.1782 +{ 1.1783 + // child views don't have titles 1.1784 + return NS_OK; 1.1785 +} 1.1786 + 1.1787 +NS_IMETHODIMP nsChildView::GetAttention(int32_t aCycleCount) 1.1788 +{ 1.1789 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; 1.1790 + 1.1791 + [NSApp requestUserAttention:NSInformationalRequest]; 1.1792 + return NS_OK; 1.1793 + 1.1794 + NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; 1.1795 +} 1.1796 + 1.1797 +/* static */ 1.1798 +bool nsChildView::DoHasPendingInputEvent() 1.1799 +{ 1.1800 + return sLastInputEventCount != GetCurrentInputEventCount(); 1.1801 +} 1.1802 + 1.1803 +/* static */ 1.1804 +uint32_t nsChildView::GetCurrentInputEventCount() 1.1805 +{ 1.1806 + // Can't use kCGAnyInputEventType because that updates too rarely for us (and 1.1807 + // always in increments of 30+!) and because apparently it's sort of broken 1.1808 + // on Tiger. So just go ahead and query the counters we care about. 1.1809 + static const CGEventType eventTypes[] = { 1.1810 + kCGEventLeftMouseDown, 1.1811 + kCGEventLeftMouseUp, 1.1812 + kCGEventRightMouseDown, 1.1813 + kCGEventRightMouseUp, 1.1814 + kCGEventMouseMoved, 1.1815 + kCGEventLeftMouseDragged, 1.1816 + kCGEventRightMouseDragged, 1.1817 + kCGEventKeyDown, 1.1818 + kCGEventKeyUp, 1.1819 + kCGEventScrollWheel, 1.1820 + kCGEventTabletPointer, 1.1821 + kCGEventOtherMouseDown, 1.1822 + kCGEventOtherMouseUp, 1.1823 + kCGEventOtherMouseDragged 1.1824 + }; 1.1825 + 1.1826 + uint32_t eventCount = 0; 1.1827 + for (uint32_t i = 0; i < ArrayLength(eventTypes); ++i) { 1.1828 + eventCount += 1.1829 + CGEventSourceCounterForEventType(kCGEventSourceStateCombinedSessionState, 1.1830 + eventTypes[i]); 1.1831 + } 1.1832 + return eventCount; 1.1833 +} 1.1834 + 1.1835 +/* static */ 1.1836 +void nsChildView::UpdateCurrentInputEventCount() 1.1837 +{ 1.1838 + sLastInputEventCount = GetCurrentInputEventCount(); 1.1839 +} 1.1840 + 1.1841 +bool nsChildView::HasPendingInputEvent() 1.1842 +{ 1.1843 + return DoHasPendingInputEvent(); 1.1844 +} 1.1845 + 1.1846 +#pragma mark - 1.1847 + 1.1848 +NS_IMETHODIMP 1.1849 +nsChildView::NotifyIME(const IMENotification& aIMENotification) 1.1850 +{ 1.1851 + switch (aIMENotification.mMessage) { 1.1852 + case REQUEST_TO_COMMIT_COMPOSITION: 1.1853 + NS_ENSURE_TRUE(mTextInputHandler, NS_ERROR_NOT_AVAILABLE); 1.1854 + mTextInputHandler->CommitIMEComposition(); 1.1855 + return NS_OK; 1.1856 + case REQUEST_TO_CANCEL_COMPOSITION: 1.1857 + NS_ENSURE_TRUE(mTextInputHandler, NS_ERROR_NOT_AVAILABLE); 1.1858 + mTextInputHandler->CancelIMEComposition(); 1.1859 + return NS_OK; 1.1860 + case NOTIFY_IME_OF_FOCUS: 1.1861 + if (mInputContext.IsPasswordEditor()) { 1.1862 + TextInputHandler::EnableSecureEventInput(); 1.1863 + } 1.1864 + 1.1865 + NS_ENSURE_TRUE(mTextInputHandler, NS_ERROR_NOT_AVAILABLE); 1.1866 + mTextInputHandler->OnFocusChangeInGecko(true); 1.1867 + return NS_OK; 1.1868 + case NOTIFY_IME_OF_BLUR: 1.1869 + // When we're going to be deactive, we must disable the secure event input 1.1870 + // mode, see the Carbon Event Manager Reference. 1.1871 + TextInputHandler::EnsureSecureEventInputDisabled(); 1.1872 + 1.1873 + NS_ENSURE_TRUE(mTextInputHandler, NS_ERROR_NOT_AVAILABLE); 1.1874 + mTextInputHandler->OnFocusChangeInGecko(false); 1.1875 + return NS_OK; 1.1876 + case NOTIFY_IME_OF_SELECTION_CHANGE: 1.1877 + NS_ENSURE_TRUE(mTextInputHandler, NS_ERROR_NOT_AVAILABLE); 1.1878 + mTextInputHandler->OnSelectionChange(); 1.1879 + default: 1.1880 + return NS_ERROR_NOT_IMPLEMENTED; 1.1881 + } 1.1882 +} 1.1883 + 1.1884 +NS_IMETHODIMP_(void) 1.1885 +nsChildView::SetInputContext(const InputContext& aContext, 1.1886 + const InputContextAction& aAction) 1.1887 +{ 1.1888 + NS_ENSURE_TRUE_VOID(mTextInputHandler); 1.1889 + 1.1890 + if (mTextInputHandler->IsFocused()) { 1.1891 + if (aContext.IsPasswordEditor()) { 1.1892 + TextInputHandler::EnableSecureEventInput(); 1.1893 + } else { 1.1894 + TextInputHandler::EnsureSecureEventInputDisabled(); 1.1895 + } 1.1896 + } 1.1897 + 1.1898 + mInputContext = aContext; 1.1899 + switch (aContext.mIMEState.mEnabled) { 1.1900 + case IMEState::ENABLED: 1.1901 + case IMEState::PLUGIN: 1.1902 + mTextInputHandler->SetASCIICapableOnly(false); 1.1903 + mTextInputHandler->EnableIME(true); 1.1904 + if (mInputContext.mIMEState.mOpen != IMEState::DONT_CHANGE_OPEN_STATE) { 1.1905 + mTextInputHandler->SetIMEOpenState( 1.1906 + mInputContext.mIMEState.mOpen == IMEState::OPEN); 1.1907 + } 1.1908 + break; 1.1909 + case IMEState::DISABLED: 1.1910 + mTextInputHandler->SetASCIICapableOnly(false); 1.1911 + mTextInputHandler->EnableIME(false); 1.1912 + break; 1.1913 + case IMEState::PASSWORD: 1.1914 + mTextInputHandler->SetASCIICapableOnly(true); 1.1915 + mTextInputHandler->EnableIME(false); 1.1916 + break; 1.1917 + default: 1.1918 + NS_ERROR("not implemented!"); 1.1919 + } 1.1920 +} 1.1921 + 1.1922 +NS_IMETHODIMP_(InputContext) 1.1923 +nsChildView::GetInputContext() 1.1924 +{ 1.1925 + switch (mInputContext.mIMEState.mEnabled) { 1.1926 + case IMEState::ENABLED: 1.1927 + case IMEState::PLUGIN: 1.1928 + if (mTextInputHandler) { 1.1929 + mInputContext.mIMEState.mOpen = 1.1930 + mTextInputHandler->IsIMEOpened() ? IMEState::OPEN : IMEState::CLOSED; 1.1931 + break; 1.1932 + } 1.1933 + // If mTextInputHandler is null, set CLOSED instead... 1.1934 + default: 1.1935 + mInputContext.mIMEState.mOpen = IMEState::CLOSED; 1.1936 + break; 1.1937 + } 1.1938 + mInputContext.mNativeIMEContext = [mView inputContext]; 1.1939 + // If input context isn't available on this widget, we should set |this| 1.1940 + // instead of nullptr since nullptr means that the platform has only one 1.1941 + // context per process. 1.1942 + if (!mInputContext.mNativeIMEContext) { 1.1943 + mInputContext.mNativeIMEContext = this; 1.1944 + } 1.1945 + return mInputContext; 1.1946 +} 1.1947 + 1.1948 +NS_IMETHODIMP 1.1949 +nsChildView::AttachNativeKeyEvent(mozilla::WidgetKeyboardEvent& aEvent) 1.1950 +{ 1.1951 + NS_ENSURE_TRUE(mTextInputHandler, NS_ERROR_NOT_AVAILABLE); 1.1952 + return mTextInputHandler->AttachNativeKeyEvent(aEvent); 1.1953 +} 1.1954 + 1.1955 +NS_IMETHODIMP_(bool) 1.1956 +nsChildView::ExecuteNativeKeyBinding(NativeKeyBindingsType aType, 1.1957 + const WidgetKeyboardEvent& aEvent, 1.1958 + DoCommandCallback aCallback, 1.1959 + void* aCallbackData) 1.1960 +{ 1.1961 + NativeKeyBindings* keyBindings = NativeKeyBindings::GetInstance(aType); 1.1962 + return keyBindings->Execute(aEvent, aCallback, aCallbackData); 1.1963 +} 1.1964 + 1.1965 +nsIMEUpdatePreference 1.1966 +nsChildView::GetIMEUpdatePreference() 1.1967 +{ 1.1968 + return nsIMEUpdatePreference(nsIMEUpdatePreference::NOTIFY_SELECTION_CHANGE); 1.1969 +} 1.1970 + 1.1971 +NS_IMETHODIMP nsChildView::GetToggledKeyState(uint32_t aKeyCode, 1.1972 + bool* aLEDState) 1.1973 +{ 1.1974 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; 1.1975 + 1.1976 + NS_ENSURE_ARG_POINTER(aLEDState); 1.1977 + uint32_t key; 1.1978 + switch (aKeyCode) { 1.1979 + case NS_VK_CAPS_LOCK: 1.1980 + key = alphaLock; 1.1981 + break; 1.1982 + case NS_VK_NUM_LOCK: 1.1983 + key = kEventKeyModifierNumLockMask; 1.1984 + break; 1.1985 + // Mac doesn't support SCROLL_LOCK state. 1.1986 + default: 1.1987 + return NS_ERROR_NOT_IMPLEMENTED; 1.1988 + } 1.1989 + uint32_t modifierFlags = ::GetCurrentKeyModifiers(); 1.1990 + *aLEDState = (modifierFlags & key) != 0; 1.1991 + return NS_OK; 1.1992 + 1.1993 + NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; 1.1994 +} 1.1995 + 1.1996 +NSView<mozView>* nsChildView::GetEditorView() 1.1997 +{ 1.1998 + NSView<mozView>* editorView = mView; 1.1999 + // We need to get editor's view. E.g., when the focus is in the bookmark 1.2000 + // dialog, the view is <panel> element of the dialog. At this time, the key 1.2001 + // events are processed the parent window's view that has native focus. 1.2002 + WidgetQueryContentEvent textContent(true, NS_QUERY_TEXT_CONTENT, this); 1.2003 + textContent.InitForQueryTextContent(0, 0); 1.2004 + DispatchWindowEvent(textContent); 1.2005 + if (textContent.mSucceeded && textContent.mReply.mFocusedWidget) { 1.2006 + NSView<mozView>* view = static_cast<NSView<mozView>*>( 1.2007 + textContent.mReply.mFocusedWidget->GetNativeData(NS_NATIVE_WIDGET)); 1.2008 + if (view) 1.2009 + editorView = view; 1.2010 + } 1.2011 + return editorView; 1.2012 +} 1.2013 + 1.2014 +#pragma mark - 1.2015 + 1.2016 +void 1.2017 +nsChildView::CreateCompositor() 1.2018 +{ 1.2019 + nsBaseWidget::CreateCompositor(); 1.2020 + if (mCompositorChild) { 1.2021 + [(ChildView *)mView setUsingOMTCompositor:true]; 1.2022 + } 1.2023 +} 1.2024 + 1.2025 +gfxASurface* 1.2026 +nsChildView::GetThebesSurface() 1.2027 +{ 1.2028 + if (!mTempThebesSurface) { 1.2029 + mTempThebesSurface = new gfxQuartzSurface(gfxSize(1, 1), gfxImageFormat::ARGB32); 1.2030 + } 1.2031 + 1.2032 + return mTempThebesSurface; 1.2033 +} 1.2034 + 1.2035 +void 1.2036 +nsChildView::NotifyDirtyRegion(const nsIntRegion& aDirtyRegion) 1.2037 +{ 1.2038 + if ([(ChildView*)mView isCoveringTitlebar]) { 1.2039 + // We store the dirty region so that we know what to repaint in the titlebar. 1.2040 + mDirtyTitlebarRegion.Or(mDirtyTitlebarRegion, aDirtyRegion); 1.2041 + } 1.2042 +} 1.2043 + 1.2044 +nsIntRect 1.2045 +nsChildView::RectContainingTitlebarControls() 1.2046 +{ 1.2047 + // Start with a thin strip at the top of the window for the highlight line. 1.2048 + NSRect rect = NSMakeRect(0, 0, [mView bounds].size.width, 1.2049 + [(ChildView*)mView cornerRadius]); 1.2050 + 1.2051 + // Add the rects of the titlebar controls. 1.2052 + for (id view in [(BaseWindow*)[mView window] titlebarControls]) { 1.2053 + rect = NSUnionRect(rect, [mView convertRect:[view bounds] fromView:view]); 1.2054 + } 1.2055 + return CocoaPointsToDevPixels(rect); 1.2056 +} 1.2057 + 1.2058 +void 1.2059 +nsChildView::PrepareWindowEffects() 1.2060 +{ 1.2061 + MutexAutoLock lock(mEffectsLock); 1.2062 + mShowsResizeIndicator = ShowsResizeIndicator(&mResizeIndicatorRect); 1.2063 + mHasRoundedBottomCorners = [(ChildView*)mView hasRoundedBottomCorners]; 1.2064 + CGFloat cornerRadius = [(ChildView*)mView cornerRadius]; 1.2065 + mDevPixelCornerRadius = cornerRadius * BackingScaleFactor(); 1.2066 + mIsCoveringTitlebar = [(ChildView*)mView isCoveringTitlebar]; 1.2067 + mIsFullscreen = ([[mView window] styleMask] & NSFullScreenWindowMask) != 0; 1.2068 + if (mIsCoveringTitlebar) { 1.2069 + mTitlebarRect = RectContainingTitlebarControls(); 1.2070 + UpdateTitlebarCGContext(); 1.2071 + } 1.2072 +} 1.2073 + 1.2074 +void 1.2075 +nsChildView::CleanupWindowEffects() 1.2076 +{ 1.2077 + mResizerImage = nullptr; 1.2078 + mCornerMaskImage = nullptr; 1.2079 + mTitlebarImage = nullptr; 1.2080 +} 1.2081 + 1.2082 +bool 1.2083 +nsChildView::PreRender(LayerManagerComposite* aManager) 1.2084 +{ 1.2085 + nsAutoPtr<GLManager> manager(GLManager::CreateGLManager(aManager)); 1.2086 + if (!manager) { 1.2087 + return true; 1.2088 + } 1.2089 + 1.2090 + // The lock makes sure that we don't attempt to tear down the view while 1.2091 + // compositing. That would make us unable to call postRender on it when the 1.2092 + // composition is done, thus keeping the GL context locked forever. 1.2093 + mViewTearDownLock.Lock(); 1.2094 + 1.2095 + NSOpenGLContext *glContext = GLContextCGL::Cast(manager->gl())->GetNSOpenGLContext(); 1.2096 + 1.2097 + if (![(ChildView*)mView preRender:glContext]) { 1.2098 + mViewTearDownLock.Unlock(); 1.2099 + return false; 1.2100 + } 1.2101 + return true; 1.2102 +} 1.2103 + 1.2104 +void 1.2105 +nsChildView::PostRender(LayerManagerComposite* aManager) 1.2106 +{ 1.2107 + nsAutoPtr<GLManager> manager(GLManager::CreateGLManager(aManager)); 1.2108 + if (!manager) { 1.2109 + return; 1.2110 + } 1.2111 + NSOpenGLContext *glContext = GLContextCGL::Cast(manager->gl())->GetNSOpenGLContext(); 1.2112 + [(ChildView*)mView postRender:glContext]; 1.2113 + mViewTearDownLock.Unlock(); 1.2114 +} 1.2115 + 1.2116 +void 1.2117 +nsChildView::DrawWindowOverlay(LayerManagerComposite* aManager, nsIntRect aRect) 1.2118 +{ 1.2119 + nsAutoPtr<GLManager> manager(GLManager::CreateGLManager(aManager)); 1.2120 + if (manager) { 1.2121 + DrawWindowOverlay(manager, aRect); 1.2122 + } 1.2123 +} 1.2124 + 1.2125 +void 1.2126 +nsChildView::DrawWindowOverlay(GLManager* aManager, nsIntRect aRect) 1.2127 +{ 1.2128 + GLContext* gl = aManager->gl(); 1.2129 + ScopedGLState scopedScissorTestState(gl, LOCAL_GL_SCISSOR_TEST, false); 1.2130 + 1.2131 + MaybeDrawTitlebar(aManager, aRect); 1.2132 + MaybeDrawResizeIndicator(aManager, aRect); 1.2133 + MaybeDrawRoundedCorners(aManager, aRect); 1.2134 +} 1.2135 + 1.2136 +static void 1.2137 +ClearRegion(gfx::DrawTarget *aDT, nsIntRegion aRegion) 1.2138 +{ 1.2139 + gfxUtils::ClipToRegion(aDT, aRegion); 1.2140 + aDT->ClearRect(gfx::Rect(0, 0, aDT->GetSize().width, aDT->GetSize().height)); 1.2141 + aDT->PopClip(); 1.2142 +} 1.2143 + 1.2144 +static void 1.2145 +DrawResizer(CGContextRef aCtx) 1.2146 +{ 1.2147 + CGContextSetShouldAntialias(aCtx, false); 1.2148 + CGPoint points[6]; 1.2149 + points[0] = CGPointMake(13.0f, 4.0f); 1.2150 + points[1] = CGPointMake(3.0f, 14.0f); 1.2151 + points[2] = CGPointMake(13.0f, 8.0f); 1.2152 + points[3] = CGPointMake(7.0f, 14.0f); 1.2153 + points[4] = CGPointMake(13.0f, 12.0f); 1.2154 + points[5] = CGPointMake(11.0f, 14.0f); 1.2155 + CGContextSetRGBStrokeColor(aCtx, 0.00f, 0.00f, 0.00f, 0.15f); 1.2156 + CGContextStrokeLineSegments(aCtx, points, 6); 1.2157 + 1.2158 + points[0] = CGPointMake(13.0f, 5.0f); 1.2159 + points[1] = CGPointMake(4.0f, 14.0f); 1.2160 + points[2] = CGPointMake(13.0f, 9.0f); 1.2161 + points[3] = CGPointMake(8.0f, 14.0f); 1.2162 + points[4] = CGPointMake(13.0f, 13.0f); 1.2163 + points[5] = CGPointMake(12.0f, 14.0f); 1.2164 + CGContextSetRGBStrokeColor(aCtx, 0.13f, 0.13f, 0.13f, 0.54f); 1.2165 + CGContextStrokeLineSegments(aCtx, points, 6); 1.2166 + 1.2167 + points[0] = CGPointMake(13.0f, 6.0f); 1.2168 + points[1] = CGPointMake(5.0f, 14.0f); 1.2169 + points[2] = CGPointMake(13.0f, 10.0f); 1.2170 + points[3] = CGPointMake(9.0f, 14.0f); 1.2171 + points[5] = CGPointMake(13.0f, 13.9f); 1.2172 + points[4] = CGPointMake(13.0f, 14.0f); 1.2173 + CGContextSetRGBStrokeColor(aCtx, 0.84f, 0.84f, 0.84f, 0.55f); 1.2174 + CGContextStrokeLineSegments(aCtx, points, 6); 1.2175 +} 1.2176 + 1.2177 +void 1.2178 +nsChildView::MaybeDrawResizeIndicator(GLManager* aManager, const nsIntRect& aRect) 1.2179 +{ 1.2180 + MutexAutoLock lock(mEffectsLock); 1.2181 + if (!mShowsResizeIndicator) { 1.2182 + return; 1.2183 + } 1.2184 + 1.2185 + if (!mResizerImage) { 1.2186 + mResizerImage = new RectTextureImage(aManager->gl()); 1.2187 + } 1.2188 + 1.2189 + nsIntSize size = mResizeIndicatorRect.Size(); 1.2190 + mResizerImage->UpdateIfNeeded(size, nsIntRegion(), ^(gfx::DrawTarget* drawTarget, const nsIntRegion& updateRegion) { 1.2191 + ClearRegion(drawTarget, updateRegion); 1.2192 + gfx::BorrowedCGContext borrow(drawTarget); 1.2193 + DrawResizer(borrow.cg); 1.2194 + borrow.Finish(); 1.2195 + }); 1.2196 + 1.2197 + mResizerImage->Draw(aManager, mResizeIndicatorRect.TopLeft()); 1.2198 +} 1.2199 + 1.2200 +// Draw the highlight line at the top of the titlebar. 1.2201 +// This function draws into the current NSGraphicsContext and assumes flippedness. 1.2202 +static void 1.2203 +DrawTitlebarHighlight(NSSize aWindowSize, CGFloat aRadius, CGFloat aDevicePixelWidth) 1.2204 +{ 1.2205 + [NSGraphicsContext saveGraphicsState]; 1.2206 + 1.2207 + // Set up the clip path. We start with the outer rectangle and cut out a 1.2208 + // slightly smaller inner rectangle with rounded corners. 1.2209 + // The outer corners of the resulting path will be square, but they will be 1.2210 + // masked away in a later step. 1.2211 + NSBezierPath* path = [NSBezierPath bezierPath]; 1.2212 + [path setWindingRule:NSEvenOddWindingRule]; 1.2213 + NSRect pathRect = NSMakeRect(0, 0, aWindowSize.width, aRadius + 2); 1.2214 + [path appendBezierPathWithRect:pathRect]; 1.2215 + pathRect = NSInsetRect(pathRect, aDevicePixelWidth, aDevicePixelWidth); 1.2216 + CGFloat innerRadius = aRadius - aDevicePixelWidth; 1.2217 + [path appendBezierPathWithRoundedRect:pathRect xRadius:innerRadius yRadius:innerRadius]; 1.2218 + [path addClip]; 1.2219 + 1.2220 + // Now we fill the path with a subtle highlight gradient. 1.2221 + // We don't use NSGradient because it's 5x to 15x slower than the manual fill, 1.2222 + // as indicated by the performance test in bug 880620. 1.2223 + for (CGFloat y = 0; y < aRadius; y += aDevicePixelWidth) { 1.2224 + CGFloat t = y / aRadius; 1.2225 + [[NSColor colorWithDeviceWhite:1.0 alpha:0.4 * (1.0 - t)] set]; 1.2226 + NSRectFill(NSMakeRect(0, y, aWindowSize.width, aDevicePixelWidth)); 1.2227 + } 1.2228 + 1.2229 + [NSGraphicsContext restoreGraphicsState]; 1.2230 +} 1.2231 + 1.2232 +static CGContextRef 1.2233 +CreateCGContext(const nsIntSize& aSize) 1.2234 +{ 1.2235 + CGColorSpaceRef cs = CGColorSpaceCreateDeviceRGB(); 1.2236 + CGContextRef ctx = 1.2237 + CGBitmapContextCreate(NULL, 1.2238 + aSize.width, 1.2239 + aSize.height, 1.2240 + 8 /* bitsPerComponent */, 1.2241 + aSize.width * 4, 1.2242 + cs, 1.2243 + kCGBitmapByteOrder32Host | kCGImageAlphaPremultipliedFirst); 1.2244 + CGColorSpaceRelease(cs); 1.2245 + 1.2246 + CGContextTranslateCTM(ctx, 0, aSize.height); 1.2247 + CGContextScaleCTM(ctx, 1, -1); 1.2248 + CGContextSetInterpolationQuality(ctx, kCGInterpolationLow); 1.2249 + 1.2250 + return ctx; 1.2251 +} 1.2252 + 1.2253 +// When this method is entered, mEffectsLock is already being held. 1.2254 +void 1.2255 +nsChildView::UpdateTitlebarCGContext() 1.2256 +{ 1.2257 + nsIntRegion dirtyTitlebarRegion; 1.2258 + dirtyTitlebarRegion.And(mDirtyTitlebarRegion, mTitlebarRect); 1.2259 + mDirtyTitlebarRegion.SetEmpty(); 1.2260 + 1.2261 + nsIntSize texSize = RectTextureImage::TextureSizeForSize(mTitlebarRect.Size()); 1.2262 + if (!mTitlebarCGContext || 1.2263 + CGBitmapContextGetWidth(mTitlebarCGContext) != size_t(texSize.width) || 1.2264 + CGBitmapContextGetHeight(mTitlebarCGContext) != size_t(texSize.height)) { 1.2265 + dirtyTitlebarRegion = mTitlebarRect; 1.2266 + 1.2267 + ReleaseTitlebarCGContext(); 1.2268 + 1.2269 + mTitlebarCGContext = CreateCGContext(texSize); 1.2270 + } 1.2271 + 1.2272 + if (dirtyTitlebarRegion.IsEmpty()) 1.2273 + return; 1.2274 + 1.2275 + CGContextRef ctx = mTitlebarCGContext; 1.2276 + 1.2277 + CGContextSaveGState(ctx); 1.2278 + 1.2279 + std::vector<CGRect> rects; 1.2280 + nsIntRegionRectIterator iter(dirtyTitlebarRegion); 1.2281 + for (;;) { 1.2282 + const nsIntRect* r = iter.Next(); 1.2283 + if (!r) 1.2284 + break; 1.2285 + rects.push_back(CGRectMake(r->x, r->y, r->width, r->height)); 1.2286 + } 1.2287 + CGContextClipToRects(ctx, rects.data(), rects.size()); 1.2288 + 1.2289 + CGContextClearRect(ctx, CGRectMake(0, 0, texSize.width, texSize.height)); 1.2290 + 1.2291 + double scale = BackingScaleFactor(); 1.2292 + CGContextScaleCTM(ctx, scale, scale); 1.2293 + NSGraphicsContext* oldContext = [NSGraphicsContext currentContext]; 1.2294 + 1.2295 + CGContextSaveGState(ctx); 1.2296 + 1.2297 + BaseWindow* window = (BaseWindow*)[mView window]; 1.2298 + NSView* frameView = [[window contentView] superview]; 1.2299 + if (![frameView isFlipped]) { 1.2300 + CGContextTranslateCTM(ctx, 0, [frameView bounds].size.height); 1.2301 + CGContextScaleCTM(ctx, 1, -1); 1.2302 + } 1.2303 + NSGraphicsContext* context = [NSGraphicsContext graphicsContextWithGraphicsPort:ctx flipped:[frameView isFlipped]]; 1.2304 + [NSGraphicsContext setCurrentContext:context]; 1.2305 + 1.2306 + // Draw the title string. 1.2307 + if ([window wantsTitleDrawn] && [frameView respondsToSelector:@selector(_drawTitleBar:)]) { 1.2308 + [frameView _drawTitleBar:[frameView bounds]]; 1.2309 + } 1.2310 + 1.2311 + // Draw the titlebar controls into the titlebar image. 1.2312 + for (id view in [window titlebarControls]) { 1.2313 + NSRect viewFrame = [view frame]; 1.2314 + nsIntRect viewRect = CocoaPointsToDevPixels([mView convertRect:viewFrame fromView:frameView]); 1.2315 + if (!dirtyTitlebarRegion.Intersects(viewRect)) { 1.2316 + continue; 1.2317 + } 1.2318 + // All of the titlebar controls we're interested in are subclasses of 1.2319 + // NSButton. 1.2320 + if (![view isKindOfClass:[NSButton class]]) { 1.2321 + continue; 1.2322 + } 1.2323 + NSButton *button = (NSButton *) view; 1.2324 + id cellObject = [button cell]; 1.2325 + if (![cellObject isKindOfClass:[NSCell class]]) { 1.2326 + continue; 1.2327 + } 1.2328 + NSCell *cell = (NSCell *) cellObject; 1.2329 + 1.2330 + CGContextSaveGState(ctx); 1.2331 + CGContextTranslateCTM(ctx, viewFrame.origin.x, viewFrame.origin.y); 1.2332 + 1.2333 + if ([context isFlipped] != [view isFlipped]) { 1.2334 + CGContextTranslateCTM(ctx, 0, viewFrame.size.height); 1.2335 + CGContextScaleCTM(ctx, 1, -1); 1.2336 + } 1.2337 + 1.2338 + [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithGraphicsPort:ctx flipped:[view isFlipped]]]; 1.2339 + 1.2340 + [cell drawWithFrame:[button bounds] inView:button]; 1.2341 + 1.2342 + [NSGraphicsContext setCurrentContext:context]; 1.2343 + CGContextRestoreGState(ctx); 1.2344 + } 1.2345 + 1.2346 + CGContextRestoreGState(ctx); 1.2347 + 1.2348 + DrawTitlebarHighlight([frameView bounds].size, [(ChildView*)mView cornerRadius], 1.2349 + DevPixelsToCocoaPoints(1)); 1.2350 + 1.2351 + [NSGraphicsContext setCurrentContext:oldContext]; 1.2352 + 1.2353 + CGContextRestoreGState(ctx); 1.2354 + 1.2355 + mUpdatedTitlebarRegion.Or(mUpdatedTitlebarRegion, dirtyTitlebarRegion); 1.2356 +} 1.2357 + 1.2358 +// This method draws an overlay in the top of the window which contains the 1.2359 +// titlebar controls (e.g. close, min, zoom, fullscreen) and the titlebar 1.2360 +// highlight effect. 1.2361 +// This is necessary because the real titlebar controls are covered by our 1.2362 +// OpenGL context. Note that in terms of the NSView hierarchy, our ChildView 1.2363 +// is actually below the titlebar controls - that's why hovering and clicking 1.2364 +// them works as expected - but their visual representation is only drawn into 1.2365 +// the normal window buffer, and the window buffer surface lies below the 1.2366 +// GLContext surface. In order to make the titlebar controls visible, we have 1.2367 +// to redraw them inside the OpenGL context surface. 1.2368 +void 1.2369 +nsChildView::MaybeDrawTitlebar(GLManager* aManager, const nsIntRect& aRect) 1.2370 +{ 1.2371 + MutexAutoLock lock(mEffectsLock); 1.2372 + if (!mIsCoveringTitlebar || mIsFullscreen) { 1.2373 + return; 1.2374 + } 1.2375 + 1.2376 + nsIntRegion updatedTitlebarRegion; 1.2377 + updatedTitlebarRegion.And(mUpdatedTitlebarRegion, mTitlebarRect); 1.2378 + mUpdatedTitlebarRegion.SetEmpty(); 1.2379 + 1.2380 + if (!mTitlebarImage) { 1.2381 + mTitlebarImage = new RectTextureImage(aManager->gl()); 1.2382 + } 1.2383 + 1.2384 + mTitlebarImage->UpdateFromCGContext(mTitlebarRect.Size(), 1.2385 + updatedTitlebarRegion, 1.2386 + mTitlebarCGContext); 1.2387 + 1.2388 + mTitlebarImage->Draw(aManager, mTitlebarRect.TopLeft()); 1.2389 +} 1.2390 + 1.2391 +static void 1.2392 +DrawTopLeftCornerMask(CGContextRef aCtx, int aRadius) 1.2393 +{ 1.2394 + CGContextSetRGBFillColor(aCtx, 1.0, 1.0, 1.0, 1.0); 1.2395 + CGContextFillEllipseInRect(aCtx, CGRectMake(0, 0, aRadius * 2, aRadius * 2)); 1.2396 +} 1.2397 + 1.2398 +void 1.2399 +nsChildView::MaybeDrawRoundedCorners(GLManager* aManager, const nsIntRect& aRect) 1.2400 +{ 1.2401 + MutexAutoLock lock(mEffectsLock); 1.2402 + 1.2403 + if (!mCornerMaskImage) { 1.2404 + mCornerMaskImage = new RectTextureImage(aManager->gl()); 1.2405 + } 1.2406 + 1.2407 + nsIntSize size(mDevPixelCornerRadius, mDevPixelCornerRadius); 1.2408 + mCornerMaskImage->UpdateIfNeeded(size, nsIntRegion(), ^(gfx::DrawTarget* drawTarget, const nsIntRegion& updateRegion) { 1.2409 + ClearRegion(drawTarget, updateRegion); 1.2410 + RefPtr<gfx::PathBuilder> builder = drawTarget->CreatePathBuilder(); 1.2411 + builder->Arc(gfx::Point(mDevPixelCornerRadius, mDevPixelCornerRadius), mDevPixelCornerRadius, 0, 2.0f * M_PI); 1.2412 + RefPtr<gfx::Path> path = builder->Finish(); 1.2413 + drawTarget->Fill(path, 1.2414 + gfx::ColorPattern(gfx::Color(1.0, 1.0, 1.0, 1.0)), 1.2415 + gfx::DrawOptions(1.0f, gfx::CompositionOp::OP_SOURCE)); 1.2416 + }); 1.2417 + 1.2418 + // Use operator destination in: multiply all 4 channels with source alpha. 1.2419 + aManager->gl()->fBlendFuncSeparate(LOCAL_GL_ZERO, LOCAL_GL_SRC_ALPHA, 1.2420 + LOCAL_GL_ZERO, LOCAL_GL_SRC_ALPHA); 1.2421 + 1.2422 + gfx3DMatrix flipX = gfx3DMatrix::ScalingMatrix(-1, 1, 1); 1.2423 + gfx3DMatrix flipY = gfx3DMatrix::ScalingMatrix(1, -1, 1); 1.2424 + 1.2425 + if (mIsCoveringTitlebar && !mIsFullscreen) { 1.2426 + // Mask the top corners. 1.2427 + mCornerMaskImage->Draw(aManager, aRect.TopLeft()); 1.2428 + mCornerMaskImage->Draw(aManager, aRect.TopRight(), flipX); 1.2429 + } 1.2430 + 1.2431 + if (mHasRoundedBottomCorners && !mIsFullscreen) { 1.2432 + // Mask the bottom corners. 1.2433 + mCornerMaskImage->Draw(aManager, aRect.BottomLeft(), flipY); 1.2434 + mCornerMaskImage->Draw(aManager, aRect.BottomRight(), flipY * flipX); 1.2435 + } 1.2436 + 1.2437 + // Reset blend mode. 1.2438 + aManager->gl()->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA, 1.2439 + LOCAL_GL_ONE, LOCAL_GL_ONE); 1.2440 +} 1.2441 + 1.2442 +static int32_t 1.2443 +FindTitlebarBottom(const nsTArray<nsIWidget::ThemeGeometry>& aThemeGeometries, 1.2444 + int32_t aWindowWidth) 1.2445 +{ 1.2446 + int32_t titlebarBottom = 0; 1.2447 + for (uint32_t i = 0; i < aThemeGeometries.Length(); ++i) { 1.2448 + const nsIWidget::ThemeGeometry& g = aThemeGeometries[i]; 1.2449 + if ((g.mWidgetType == NS_THEME_WINDOW_TITLEBAR) && 1.2450 + g.mRect.X() <= 0 && 1.2451 + g.mRect.XMost() >= aWindowWidth && 1.2452 + g.mRect.Y() <= 0) { 1.2453 + titlebarBottom = std::max(titlebarBottom, g.mRect.YMost()); 1.2454 + } 1.2455 + } 1.2456 + return titlebarBottom; 1.2457 +} 1.2458 + 1.2459 +static int32_t 1.2460 +FindUnifiedToolbarBottom(const nsTArray<nsIWidget::ThemeGeometry>& aThemeGeometries, 1.2461 + int32_t aWindowWidth, int32_t aTitlebarBottom) 1.2462 +{ 1.2463 + int32_t unifiedToolbarBottom = aTitlebarBottom; 1.2464 + for (uint32_t i = 0; i < aThemeGeometries.Length(); ++i) { 1.2465 + const nsIWidget::ThemeGeometry& g = aThemeGeometries[i]; 1.2466 + if ((g.mWidgetType == NS_THEME_MOZ_MAC_UNIFIED_TOOLBAR || 1.2467 + g.mWidgetType == NS_THEME_TOOLBAR) && 1.2468 + g.mRect.X() <= 0 && 1.2469 + g.mRect.XMost() >= aWindowWidth && 1.2470 + g.mRect.Y() <= aTitlebarBottom) { 1.2471 + unifiedToolbarBottom = std::max(unifiedToolbarBottom, g.mRect.YMost()); 1.2472 + } 1.2473 + } 1.2474 + return unifiedToolbarBottom; 1.2475 +} 1.2476 + 1.2477 +static nsIntRect 1.2478 +FindFirstRectOfType(const nsTArray<nsIWidget::ThemeGeometry>& aThemeGeometries, 1.2479 + uint8_t aWidgetType) 1.2480 +{ 1.2481 + for (uint32_t i = 0; i < aThemeGeometries.Length(); ++i) { 1.2482 + const nsIWidget::ThemeGeometry& g = aThemeGeometries[i]; 1.2483 + if (g.mWidgetType == aWidgetType) { 1.2484 + return g.mRect; 1.2485 + } 1.2486 + } 1.2487 + return nsIntRect(); 1.2488 +} 1.2489 + 1.2490 +void 1.2491 +nsChildView::UpdateThemeGeometries(const nsTArray<ThemeGeometry>& aThemeGeometries) 1.2492 +{ 1.2493 + if (![mView window] || ![[mView window] isKindOfClass:[ToolbarWindow class]]) 1.2494 + return; 1.2495 + 1.2496 + // Update unified toolbar height. 1.2497 + int32_t windowWidth = mBounds.width; 1.2498 + int32_t titlebarBottom = FindTitlebarBottom(aThemeGeometries, windowWidth); 1.2499 + int32_t unifiedToolbarBottom = 1.2500 + FindUnifiedToolbarBottom(aThemeGeometries, windowWidth, titlebarBottom); 1.2501 + 1.2502 + ToolbarWindow* win = (ToolbarWindow*)[mView window]; 1.2503 + bool drawsContentsIntoWindowFrame = [win drawsContentsIntoWindowFrame]; 1.2504 + int32_t titlebarHeight = CocoaPointsToDevPixels([win titlebarHeight]); 1.2505 + int32_t contentOffset = drawsContentsIntoWindowFrame ? titlebarHeight : 0; 1.2506 + int32_t devUnifiedHeight = titlebarHeight + unifiedToolbarBottom - contentOffset; 1.2507 + [win setUnifiedToolbarHeight:DevPixelsToCocoaPoints(devUnifiedHeight)]; 1.2508 + 1.2509 + // Update titlebar control offsets. 1.2510 + nsIntRect windowButtonRect = FindFirstRectOfType(aThemeGeometries, NS_THEME_WINDOW_BUTTON_BOX); 1.2511 + [win placeWindowButtons:[mView convertRect:DevPixelsToCocoaPoints(windowButtonRect) toView:nil]]; 1.2512 + nsIntRect fullScreenButtonRect = FindFirstRectOfType(aThemeGeometries, NS_THEME_MOZ_MAC_FULLSCREEN_BUTTON); 1.2513 + [win placeFullScreenButton:[mView convertRect:DevPixelsToCocoaPoints(fullScreenButtonRect) toView:nil]]; 1.2514 +} 1.2515 + 1.2516 +TemporaryRef<gfx::DrawTarget> 1.2517 +nsChildView::StartRemoteDrawing() 1.2518 +{ 1.2519 + if (!mGLPresenter) { 1.2520 + mGLPresenter = GLPresenter::CreateForWindow(this); 1.2521 + 1.2522 + if (!mGLPresenter) { 1.2523 + return nullptr; 1.2524 + } 1.2525 + } 1.2526 + 1.2527 + nsIntRegion dirtyRegion = mBounds; 1.2528 + nsIntSize renderSize = mBounds.Size(); 1.2529 + 1.2530 + if (!mBasicCompositorImage) { 1.2531 + mBasicCompositorImage = new RectTextureImage(mGLPresenter->gl()); 1.2532 + } 1.2533 + 1.2534 + RefPtr<gfx::DrawTarget> drawTarget = 1.2535 + mBasicCompositorImage->BeginUpdate(renderSize, dirtyRegion); 1.2536 + 1.2537 + if (!drawTarget) { 1.2538 + // Composite unchanged textures. 1.2539 + DoRemoteComposition(mBounds); 1.2540 + return nullptr; 1.2541 + } 1.2542 + 1.2543 + return drawTarget; 1.2544 +} 1.2545 + 1.2546 +void 1.2547 +nsChildView::EndRemoteDrawing() 1.2548 +{ 1.2549 + mBasicCompositorImage->EndUpdate(true); 1.2550 + DoRemoteComposition(mBounds); 1.2551 +} 1.2552 + 1.2553 +void 1.2554 +nsChildView::CleanupRemoteDrawing() 1.2555 +{ 1.2556 + mBasicCompositorImage = nullptr; 1.2557 + mCornerMaskImage = nullptr; 1.2558 + mResizerImage = nullptr; 1.2559 + mTitlebarImage = nullptr; 1.2560 + mGLPresenter = nullptr; 1.2561 +} 1.2562 + 1.2563 +void 1.2564 +nsChildView::DoRemoteComposition(const nsIntRect& aRenderRect) 1.2565 +{ 1.2566 + if (![(ChildView*)mView preRender:mGLPresenter->GetNSOpenGLContext()]) { 1.2567 + return; 1.2568 + } 1.2569 + mGLPresenter->BeginFrame(aRenderRect.Size()); 1.2570 + 1.2571 + // Draw the result from the basic compositor. 1.2572 + mBasicCompositorImage->Draw(mGLPresenter, nsIntPoint(0, 0)); 1.2573 + 1.2574 + // DrawWindowOverlay doesn't do anything for non-GL, so it didn't paint 1.2575 + // anything during the basic compositor transaction. Draw the overlay now. 1.2576 + DrawWindowOverlay(mGLPresenter, aRenderRect); 1.2577 + 1.2578 + mGLPresenter->EndFrame(); 1.2579 + 1.2580 + [(ChildView*)mView postRender:mGLPresenter->GetNSOpenGLContext()]; 1.2581 +} 1.2582 + 1.2583 +#ifdef ACCESSIBILITY 1.2584 +already_AddRefed<a11y::Accessible> 1.2585 +nsChildView::GetDocumentAccessible() 1.2586 +{ 1.2587 + if (!mozilla::a11y::ShouldA11yBeEnabled()) 1.2588 + return nullptr; 1.2589 + 1.2590 + if (mAccessible) { 1.2591 + nsRefPtr<a11y::Accessible> ret; 1.2592 + CallQueryReferent(mAccessible.get(), 1.2593 + static_cast<a11y::Accessible**>(getter_AddRefs(ret))); 1.2594 + return ret.forget(); 1.2595 + } 1.2596 + 1.2597 + // need to fetch the accessible anew, because it has gone away. 1.2598 + // cache the accessible in our weak ptr 1.2599 + nsRefPtr<a11y::Accessible> acc = GetRootAccessible(); 1.2600 + mAccessible = do_GetWeakReference(static_cast<nsIAccessible *>(acc.get())); 1.2601 + 1.2602 + return acc.forget(); 1.2603 +} 1.2604 +#endif 1.2605 + 1.2606 +// RectTextureImage implementation 1.2607 + 1.2608 +RectTextureImage::~RectTextureImage() 1.2609 +{ 1.2610 + if (mTexture) { 1.2611 + mGLContext->MakeCurrent(); 1.2612 + mGLContext->fDeleteTextures(1, &mTexture); 1.2613 + mTexture = 0; 1.2614 + } 1.2615 +} 1.2616 + 1.2617 +nsIntSize 1.2618 +RectTextureImage::TextureSizeForSize(const nsIntSize& aSize) 1.2619 +{ 1.2620 + return nsIntSize(gfx::NextPowerOfTwo(aSize.width), 1.2621 + gfx::NextPowerOfTwo(aSize.height)); 1.2622 +} 1.2623 + 1.2624 +TemporaryRef<gfx::DrawTarget> 1.2625 +RectTextureImage::BeginUpdate(const nsIntSize& aNewSize, 1.2626 + const nsIntRegion& aDirtyRegion) 1.2627 +{ 1.2628 + MOZ_ASSERT(!mInUpdate, "Beginning update during update!"); 1.2629 + mUpdateRegion = aDirtyRegion; 1.2630 + if (aNewSize != mUsedSize) { 1.2631 + mUsedSize = aNewSize; 1.2632 + mUpdateRegion = nsIntRect(nsIntPoint(0, 0), aNewSize); 1.2633 + } 1.2634 + 1.2635 + if (mUpdateRegion.IsEmpty()) { 1.2636 + return nullptr; 1.2637 + } 1.2638 + 1.2639 + nsIntSize neededBufferSize = TextureSizeForSize(mUsedSize); 1.2640 + if (!mUpdateDrawTarget || mBufferSize != neededBufferSize) { 1.2641 + gfx::IntSize size(neededBufferSize.width, neededBufferSize.height); 1.2642 + mUpdateDrawTarget = 1.2643 + gfx::Factory::CreateDrawTarget(gfx::BackendType::COREGRAPHICS, size, 1.2644 + gfx::SurfaceFormat::B8G8R8A8); 1.2645 + mBufferSize = neededBufferSize; 1.2646 + } 1.2647 + 1.2648 + mInUpdate = true; 1.2649 + 1.2650 + RefPtr<gfx::DrawTarget> drawTarget = mUpdateDrawTarget; 1.2651 + return drawTarget; 1.2652 +} 1.2653 + 1.2654 +#define NSFoundationVersionWithProperStrideSupportForSubtextureUpload NSFoundationVersionNumber10_6_3 1.2655 + 1.2656 +static bool 1.2657 +CanUploadSubtextures() 1.2658 +{ 1.2659 + return NSFoundationVersionNumber >= NSFoundationVersionWithProperStrideSupportForSubtextureUpload; 1.2660 +} 1.2661 + 1.2662 +void 1.2663 +RectTextureImage::EndUpdate(bool aKeepSurface) 1.2664 +{ 1.2665 + MOZ_ASSERT(mInUpdate, "Ending update while not in update"); 1.2666 + 1.2667 + bool overwriteTexture = false; 1.2668 + nsIntRegion updateRegion = mUpdateRegion; 1.2669 + if (!mTexture || (mTextureSize != mBufferSize)) { 1.2670 + overwriteTexture = true; 1.2671 + mTextureSize = mBufferSize; 1.2672 + } 1.2673 + 1.2674 + if (overwriteTexture || !CanUploadSubtextures()) { 1.2675 + updateRegion = nsIntRect(nsIntPoint(0, 0), mTextureSize); 1.2676 + } 1.2677 + 1.2678 + RefPtr<gfx::SourceSurface> snapshot = mUpdateDrawTarget->Snapshot(); 1.2679 + RefPtr<gfx::DataSourceSurface> dataSnapshot = snapshot->GetDataSurface(); 1.2680 + 1.2681 + UploadSurfaceToTexture(mGLContext, 1.2682 + dataSnapshot, 1.2683 + updateRegion, 1.2684 + mTexture, 1.2685 + overwriteTexture, 1.2686 + updateRegion.GetBounds().TopLeft(), 1.2687 + false, 1.2688 + LOCAL_GL_TEXTURE0, 1.2689 + LOCAL_GL_TEXTURE_RECTANGLE_ARB); 1.2690 + 1.2691 + if (!aKeepSurface) { 1.2692 + mUpdateDrawTarget = nullptr; 1.2693 + } 1.2694 + 1.2695 + mInUpdate = false; 1.2696 +} 1.2697 + 1.2698 +void 1.2699 +RectTextureImage::UpdateFromCGContext(const nsIntSize& aNewSize, 1.2700 + const nsIntRegion& aDirtyRegion, 1.2701 + CGContextRef aCGContext) 1.2702 +{ 1.2703 + gfx::IntSize size = gfx::IntSize(CGBitmapContextGetWidth(aCGContext), 1.2704 + CGBitmapContextGetHeight(aCGContext)); 1.2705 + mBufferSize.SizeTo(size.width, size.height); 1.2706 + RefPtr<gfx::DrawTarget> dt = BeginUpdate(aNewSize, aDirtyRegion); 1.2707 + if (dt) { 1.2708 + gfx::Rect rect(0, 0, size.width, size.height); 1.2709 + gfxUtils::ClipToRegion(dt, GetUpdateRegion()); 1.2710 + RefPtr<gfx::SourceSurface> sourceSurface = 1.2711 + dt->CreateSourceSurfaceFromData(static_cast<uint8_t *>(CGBitmapContextGetData(aCGContext)), 1.2712 + size, 1.2713 + CGBitmapContextGetBytesPerRow(aCGContext), 1.2714 + gfx::SurfaceFormat::B8G8R8A8); 1.2715 + dt->DrawSurface(sourceSurface, rect, rect, 1.2716 + gfx::DrawSurfaceOptions(), 1.2717 + gfx::DrawOptions(1.0, gfx::CompositionOp::OP_SOURCE)); 1.2718 + dt->PopClip(); 1.2719 + EndUpdate(); 1.2720 + } 1.2721 +} 1.2722 + 1.2723 +void 1.2724 +RectTextureImage::UpdateFromDrawTarget(const nsIntSize& aNewSize, 1.2725 + const nsIntRegion& aDirtyRegion, 1.2726 + gfx::DrawTarget* aFromDrawTarget) 1.2727 +{ 1.2728 + mUpdateDrawTarget = aFromDrawTarget; 1.2729 + mBufferSize.SizeTo(aFromDrawTarget->GetSize().width, aFromDrawTarget->GetSize().height); 1.2730 + RefPtr<gfx::DrawTarget> drawTarget = BeginUpdate(aNewSize, aDirtyRegion); 1.2731 + if (drawTarget) { 1.2732 + if (drawTarget != aFromDrawTarget) { 1.2733 + RefPtr<gfx::SourceSurface> source = aFromDrawTarget->Snapshot(); 1.2734 + gfx::Rect rect(0, 0, aFromDrawTarget->GetSize().width, aFromDrawTarget->GetSize().height); 1.2735 + gfxUtils::ClipToRegion(drawTarget, GetUpdateRegion()); 1.2736 + drawTarget->DrawSurface(source, rect, rect, 1.2737 + gfx::DrawSurfaceOptions(), 1.2738 + gfx::DrawOptions(1.0, gfx::CompositionOp::OP_SOURCE)); 1.2739 + drawTarget->PopClip(); 1.2740 + } 1.2741 + EndUpdate(); 1.2742 + } 1.2743 + mUpdateDrawTarget = nullptr; 1.2744 +} 1.2745 + 1.2746 +void 1.2747 +RectTextureImage::Draw(GLManager* aManager, 1.2748 + const nsIntPoint& aLocation, 1.2749 + const gfx3DMatrix& aTransform) 1.2750 +{ 1.2751 + ShaderProgramOGL* program = aManager->GetProgram(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 1.2752 + gfx::SurfaceFormat::R8G8B8A8); 1.2753 + 1.2754 + aManager->gl()->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, mTexture); 1.2755 + 1.2756 + program->Activate(); 1.2757 + program->SetProjectionMatrix(aManager->GetProjMatrix()); 1.2758 + program->SetLayerQuadRect(nsIntRect(nsIntPoint(0, 0), mUsedSize)); 1.2759 + gfx::Matrix4x4 transform; 1.2760 + gfx::ToMatrix4x4(aTransform, transform); 1.2761 + program->SetLayerTransform(transform * gfx::Matrix4x4().Translate(aLocation.x, aLocation.y, 0)); 1.2762 + program->SetTextureTransform(gfx::Matrix4x4()); 1.2763 + program->SetRenderOffset(nsIntPoint(0, 0)); 1.2764 + program->SetTexCoordMultiplier(mUsedSize.width, mUsedSize.height); 1.2765 + program->SetTextureUnit(0); 1.2766 + 1.2767 + aManager->BindAndDrawQuad(program); 1.2768 + 1.2769 + aManager->gl()->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, 0); 1.2770 +} 1.2771 + 1.2772 +// GLPresenter implementation 1.2773 + 1.2774 +GLPresenter::GLPresenter(GLContext* aContext) 1.2775 + : mGLContext(aContext) 1.2776 +{ 1.2777 + mGLContext->MakeCurrent(); 1.2778 + ShaderConfigOGL config; 1.2779 + config.SetTextureTarget(LOCAL_GL_TEXTURE_RECTANGLE_ARB); 1.2780 + mRGBARectProgram = new ShaderProgramOGL(mGLContext, 1.2781 + ProgramProfileOGL::GetProfileFor(config)); 1.2782 + 1.2783 + // Create mQuadVBO. 1.2784 + mGLContext->fGenBuffers(1, &mQuadVBO); 1.2785 + mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mQuadVBO); 1.2786 + 1.2787 + GLfloat vertices[] = { 1.2788 + /* First quad vertices */ 1.2789 + 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.2790 + /* Then quad texcoords */ 1.2791 + 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.2792 + }; 1.2793 + mGLContext->fBufferData(LOCAL_GL_ARRAY_BUFFER, sizeof(vertices), vertices, LOCAL_GL_STATIC_DRAW); 1.2794 + mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0); 1.2795 +} 1.2796 + 1.2797 +GLPresenter::~GLPresenter() 1.2798 +{ 1.2799 + if (mQuadVBO) { 1.2800 + mGLContext->MakeCurrent(); 1.2801 + mGLContext->fDeleteBuffers(1, &mQuadVBO); 1.2802 + mQuadVBO = 0; 1.2803 + } 1.2804 +} 1.2805 + 1.2806 +void 1.2807 +GLPresenter::BindAndDrawQuad(ShaderProgramOGL *aProgram) 1.2808 +{ 1.2809 + mGLContext->MakeCurrent(); 1.2810 + 1.2811 + GLuint vertAttribIndex = aProgram->AttribLocation(ShaderProgramOGL::VertexCoordAttrib); 1.2812 + GLuint texCoordAttribIndex = aProgram->AttribLocation(ShaderProgramOGL::TexCoordAttrib); 1.2813 + 1.2814 + mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mQuadVBO); 1.2815 + mGLContext->fVertexAttribPointer(vertAttribIndex, 2, 1.2816 + LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, 1.2817 + (GLvoid*)0); 1.2818 + mGLContext->fEnableVertexAttribArray(vertAttribIndex); 1.2819 + mGLContext->fVertexAttribPointer(texCoordAttribIndex, 2, 1.2820 + LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, 1.2821 + (GLvoid*) (sizeof(float)*4*2)); 1.2822 + mGLContext->fEnableVertexAttribArray(texCoordAttribIndex); 1.2823 + mGLContext->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4); 1.2824 + mGLContext->fDisableVertexAttribArray(vertAttribIndex); 1.2825 + mGLContext->fDisableVertexAttribArray(texCoordAttribIndex); 1.2826 +} 1.2827 + 1.2828 +void 1.2829 +GLPresenter::BeginFrame(nsIntSize aRenderSize) 1.2830 +{ 1.2831 + mGLContext->MakeCurrent(); 1.2832 + 1.2833 + mGLContext->fViewport(0, 0, aRenderSize.width, aRenderSize.height); 1.2834 + 1.2835 + // Matrix to transform (0, 0, width, height) to viewport space (-1.0, 1.0, 1.2836 + // 2, 2) and flip the contents. 1.2837 + gfx::Matrix viewMatrix; 1.2838 + viewMatrix.Translate(-1.0, 1.0); 1.2839 + viewMatrix.Scale(2.0f / float(aRenderSize.width), 2.0f / float(aRenderSize.height)); 1.2840 + viewMatrix.Scale(1.0f, -1.0f); 1.2841 + 1.2842 + gfx::Matrix4x4 matrix3d = gfx::Matrix4x4::From2D(viewMatrix); 1.2843 + matrix3d._33 = 0.0f; 1.2844 + 1.2845 + // set the projection matrix for the next time the program is activated 1.2846 + mProjMatrix = matrix3d; 1.2847 + 1.2848 + // Default blend function implements "OVER" 1.2849 + mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA, 1.2850 + LOCAL_GL_ONE, LOCAL_GL_ONE); 1.2851 + mGLContext->fEnable(LOCAL_GL_BLEND); 1.2852 + 1.2853 + mGLContext->fClearColor(0.0, 0.0, 0.0, 0.0); 1.2854 + mGLContext->fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT); 1.2855 + 1.2856 + mGLContext->fEnable(LOCAL_GL_TEXTURE_RECTANGLE_ARB); 1.2857 +} 1.2858 + 1.2859 +void 1.2860 +GLPresenter::EndFrame() 1.2861 +{ 1.2862 + mGLContext->SwapBuffers(); 1.2863 + mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0); 1.2864 +} 1.2865 + 1.2866 +#pragma mark - 1.2867 + 1.2868 +@implementation ChildView 1.2869 + 1.2870 +// globalDragPboard is non-null during native drag sessions that did not originate 1.2871 +// in our native NSView (it is set in |draggingEntered:|). It is unset when the 1.2872 +// drag session ends for this view, either with the mouse exiting or when a drop 1.2873 +// occurs in this view. 1.2874 +NSPasteboard* globalDragPboard = nil; 1.2875 + 1.2876 +// gLastDragView and gLastDragMouseDownEvent are used to communicate information 1.2877 +// to the drag service during drag invocation (starting a drag in from the view). 1.2878 +// gLastDragView is only non-null while mouseDragged is on the call stack. 1.2879 +NSView* gLastDragView = nil; 1.2880 +NSEvent* gLastDragMouseDownEvent = nil; 1.2881 + 1.2882 ++ (void)initialize 1.2883 +{ 1.2884 + static BOOL initialized = NO; 1.2885 + 1.2886 + if (!initialized) { 1.2887 + // Inform the OS about the types of services (from the "Services" menu) 1.2888 + // that we can handle. 1.2889 + 1.2890 + NSArray *sendTypes = [[NSArray alloc] initWithObjects:NSStringPboardType,NSHTMLPboardType,nil]; 1.2891 + NSArray *returnTypes = [[NSArray alloc] initWithObjects:NSStringPboardType,NSHTMLPboardType,nil]; 1.2892 + 1.2893 + [NSApp registerServicesMenuSendTypes:sendTypes returnTypes:returnTypes]; 1.2894 + 1.2895 + [sendTypes release]; 1.2896 + [returnTypes release]; 1.2897 + 1.2898 + initialized = YES; 1.2899 + } 1.2900 +} 1.2901 + 1.2902 ++ (void)registerViewForDraggedTypes:(NSView*)aView 1.2903 +{ 1.2904 + [aView registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType, 1.2905 + NSStringPboardType, 1.2906 + NSHTMLPboardType, 1.2907 + NSURLPboardType, 1.2908 + NSFilesPromisePboardType, 1.2909 + kWildcardPboardType, 1.2910 + kCorePboardType_url, 1.2911 + kCorePboardType_urld, 1.2912 + kCorePboardType_urln, 1.2913 + nil]]; 1.2914 +} 1.2915 + 1.2916 +// initWithFrame:geckoChild: 1.2917 +- (id)initWithFrame:(NSRect)inFrame geckoChild:(nsChildView*)inChild 1.2918 +{ 1.2919 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; 1.2920 + 1.2921 + if ((self = [super initWithFrame:inFrame])) { 1.2922 + mGeckoChild = inChild; 1.2923 + mIsPluginView = NO; 1.2924 +#ifndef NP_NO_CARBON 1.2925 + // We don't support the Carbon event model but it's still the default 1.2926 + // model for i386 per NPAPI. 1.2927 + mPluginEventModel = NPEventModelCarbon; 1.2928 +#else 1.2929 + mPluginEventModel = NPEventModelCocoa; 1.2930 +#endif 1.2931 +#ifndef NP_NO_QUICKDRAW 1.2932 + // We don't support the Quickdraw drawing model any more but it's still 1.2933 + // the default model for i386 per NPAPI. 1.2934 + mPluginDrawingModel = NPDrawingModelQuickDraw; 1.2935 +#else 1.2936 + mPluginDrawingModel = NPDrawingModelCoreGraphics; 1.2937 +#endif 1.2938 + mPendingDisplay = NO; 1.2939 + mBlockedLastMouseDown = NO; 1.2940 + mExpectingWheelStop = NO; 1.2941 + 1.2942 + mLastMouseDownEvent = nil; 1.2943 + mClickThroughMouseDownEvent = nil; 1.2944 + mDragService = nullptr; 1.2945 + 1.2946 + mGestureState = eGestureState_None; 1.2947 + mCumulativeMagnification = 0.0; 1.2948 + mCumulativeRotation = 0.0; 1.2949 + 1.2950 + // We can't call forceRefreshOpenGL here because, in order to work around 1.2951 + // the bug, it seems we need to have a draw already happening. Therefore, 1.2952 + // we call it in drawRect:inContext:, when we know that a draw is in 1.2953 + // progress. 1.2954 + mDidForceRefreshOpenGL = NO; 1.2955 + 1.2956 + [self setFocusRingType:NSFocusRingTypeNone]; 1.2957 + 1.2958 +#ifdef __LP64__ 1.2959 + mCancelSwipeAnimation = nil; 1.2960 + mCurrentSwipeDir = 0; 1.2961 +#endif 1.2962 + 1.2963 + mTopLeftCornerMask = NULL; 1.2964 + } 1.2965 + 1.2966 + // register for things we'll take from other applications 1.2967 + [ChildView registerViewForDraggedTypes:self]; 1.2968 + 1.2969 + [[NSNotificationCenter defaultCenter] addObserver:self 1.2970 + selector:@selector(windowBecameMain:) 1.2971 + name:NSWindowDidBecomeMainNotification 1.2972 + object:nil]; 1.2973 + [[NSNotificationCenter defaultCenter] addObserver:self 1.2974 + selector:@selector(windowResignedMain:) 1.2975 + name:NSWindowDidResignMainNotification 1.2976 + object:nil]; 1.2977 + [[NSNotificationCenter defaultCenter] addObserver:self 1.2978 + selector:@selector(systemMetricsChanged) 1.2979 + name:NSControlTintDidChangeNotification 1.2980 + object:nil]; 1.2981 + [[NSNotificationCenter defaultCenter] addObserver:self 1.2982 + selector:@selector(systemMetricsChanged) 1.2983 + name:NSSystemColorsDidChangeNotification 1.2984 + object:nil]; 1.2985 + // TODO: replace the string with the constant once we build with the 10.7 SDK 1.2986 + [[NSNotificationCenter defaultCenter] addObserver:self 1.2987 + selector:@selector(scrollbarSystemMetricChanged) 1.2988 + name:@"NSPreferredScrollerStyleDidChangeNotification" 1.2989 + object:nil]; 1.2990 + [[NSDistributedNotificationCenter defaultCenter] addObserver:self 1.2991 + selector:@selector(systemMetricsChanged) 1.2992 + name:@"AppleAquaScrollBarVariantChanged" 1.2993 + object:nil 1.2994 + suspensionBehavior:NSNotificationSuspensionBehaviorDeliverImmediately]; 1.2995 + [[NSNotificationCenter defaultCenter] addObserver:self 1.2996 + selector:@selector(_surfaceNeedsUpdate:) 1.2997 + name:NSViewGlobalFrameDidChangeNotification 1.2998 + object:self]; 1.2999 + 1.3000 + return self; 1.3001 + 1.3002 + NS_OBJC_END_TRY_ABORT_BLOCK_NIL; 1.3003 +} 1.3004 + 1.3005 +- (void)installTextInputHandler:(TextInputHandler*)aHandler 1.3006 +{ 1.3007 + mTextInputHandler = aHandler; 1.3008 +} 1.3009 + 1.3010 +- (void)uninstallTextInputHandler 1.3011 +{ 1.3012 + mTextInputHandler = nullptr; 1.3013 +} 1.3014 + 1.3015 +// Work around bug 603134. 1.3016 +// OS X has a bug that causes new OpenGL windows to only paint once or twice, 1.3017 +// then stop painting altogether. By clearing the drawable from the GL context, 1.3018 +// and then resetting the view to ourselves, we convince OS X to start updating 1.3019 +// again. 1.3020 +// This can cause a flash in new windows - bug 631339 - but it's very hard to 1.3021 +// fix that while maintaining this workaround. 1.3022 +- (void)forceRefreshOpenGL 1.3023 +{ 1.3024 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK; 1.3025 + 1.3026 + [mGLContext clearDrawable]; 1.3027 + [self updateGLContext]; 1.3028 + 1.3029 + NS_OBJC_END_TRY_ABORT_BLOCK; 1.3030 +} 1.3031 + 1.3032 +- (void)setGLContext:(NSOpenGLContext *)aGLContext 1.3033 +{ 1.3034 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK; 1.3035 + 1.3036 + mGLContext = aGLContext; 1.3037 + [mGLContext retain]; 1.3038 + 1.3039 + NS_OBJC_END_TRY_ABORT_BLOCK; 1.3040 +} 1.3041 + 1.3042 +- (bool)preRender:(NSOpenGLContext *)aGLContext 1.3043 +{ 1.3044 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN; 1.3045 + 1.3046 + if (![self window] || 1.3047 + ([[self window] isKindOfClass:[BaseWindow class]] && 1.3048 + ![(BaseWindow*)[self window] isVisibleOrBeingShown])) { 1.3049 + // Before the window is shown, our GL context's front FBO is not 1.3050 + // framebuffer complete, so we refuse to render. 1.3051 + return false; 1.3052 + } 1.3053 + 1.3054 + if (!mGLContext) { 1.3055 + [self setGLContext:aGLContext]; 1.3056 + [self updateGLContext]; 1.3057 + } 1.3058 + 1.3059 + CGLLockContext((CGLContextObj)[aGLContext CGLContextObj]); 1.3060 + 1.3061 + return true; 1.3062 + 1.3063 + NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(false); 1.3064 +} 1.3065 + 1.3066 +- (void)postRender:(NSOpenGLContext *)aGLContext 1.3067 +{ 1.3068 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK; 1.3069 + 1.3070 + CGLUnlockContext((CGLContextObj)[aGLContext CGLContextObj]); 1.3071 + 1.3072 + NS_OBJC_END_TRY_ABORT_BLOCK; 1.3073 +} 1.3074 + 1.3075 +- (void)dealloc 1.3076 +{ 1.3077 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK; 1.3078 + 1.3079 + [mGLContext release]; 1.3080 + [mPendingDirtyRects release]; 1.3081 + [mLastMouseDownEvent release]; 1.3082 + [mClickThroughMouseDownEvent release]; 1.3083 + CGImageRelease(mTopLeftCornerMask); 1.3084 + ChildViewMouseTracker::OnDestroyView(self); 1.3085 + 1.3086 + [[NSNotificationCenter defaultCenter] removeObserver:self]; 1.3087 + [[NSDistributedNotificationCenter defaultCenter] removeObserver:self]; 1.3088 + 1.3089 + [super dealloc]; 1.3090 + 1.3091 + NS_OBJC_END_TRY_ABORT_BLOCK; 1.3092 +} 1.3093 + 1.3094 +- (void)updatePluginTopLevelWindowStatus:(BOOL)hasMain 1.3095 +{ 1.3096 + if (!mGeckoChild) 1.3097 + return; 1.3098 + 1.3099 + WidgetPluginEvent pluginEvent(true, NS_PLUGIN_FOCUS_EVENT, mGeckoChild); 1.3100 + NPCocoaEvent cocoaEvent; 1.3101 + nsCocoaUtils::InitNPCocoaEvent(&cocoaEvent); 1.3102 + cocoaEvent.type = NPCocoaEventWindowFocusChanged; 1.3103 + cocoaEvent.data.focus.hasFocus = hasMain; 1.3104 + nsCocoaUtils::InitPluginEvent(pluginEvent, cocoaEvent); 1.3105 + mGeckoChild->DispatchWindowEvent(pluginEvent); 1.3106 +} 1.3107 + 1.3108 +- (void)windowBecameMain:(NSNotification*)inNotification 1.3109 +{ 1.3110 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK; 1.3111 + 1.3112 + if (mIsPluginView && mPluginEventModel == NPEventModelCocoa) { 1.3113 + if ((NSWindow*)[inNotification object] == [self window]) { 1.3114 + [self updatePluginTopLevelWindowStatus:YES]; 1.3115 + } 1.3116 + } 1.3117 + 1.3118 + NS_OBJC_END_TRY_ABORT_BLOCK; 1.3119 +} 1.3120 + 1.3121 +- (void)windowResignedMain:(NSNotification*)inNotification 1.3122 +{ 1.3123 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK; 1.3124 + 1.3125 + if (mIsPluginView && mPluginEventModel == NPEventModelCocoa) { 1.3126 + if ((NSWindow*)[inNotification object] == [self window]) { 1.3127 + [self updatePluginTopLevelWindowStatus:NO]; 1.3128 + } 1.3129 + } 1.3130 + 1.3131 + NS_OBJC_END_TRY_ABORT_BLOCK; 1.3132 +} 1.3133 + 1.3134 +- (void)widgetDestroyed 1.3135 +{ 1.3136 + if (mTextInputHandler) { 1.3137 + mTextInputHandler->OnDestroyWidget(mGeckoChild); 1.3138 + mTextInputHandler = nullptr; 1.3139 + } 1.3140 + mGeckoChild = nullptr; 1.3141 + 1.3142 + // Just in case we're destroyed abruptly and missed the draggingExited 1.3143 + // or performDragOperation message. 1.3144 + NS_IF_RELEASE(mDragService); 1.3145 +} 1.3146 + 1.3147 +// mozView method, return our gecko child view widget. Note this does not AddRef. 1.3148 +- (nsIWidget*) widget 1.3149 +{ 1.3150 + return static_cast<nsIWidget*>(mGeckoChild); 1.3151 +} 1.3152 + 1.3153 +- (void)systemMetricsChanged 1.3154 +{ 1.3155 + if (mGeckoChild) 1.3156 + mGeckoChild->NotifyThemeChanged(); 1.3157 +} 1.3158 + 1.3159 +- (void)scrollbarSystemMetricChanged 1.3160 +{ 1.3161 + [self systemMetricsChanged]; 1.3162 + 1.3163 + if (mGeckoChild) { 1.3164 + nsIWidgetListener* listener = mGeckoChild->GetWidgetListener(); 1.3165 + if (listener) { 1.3166 + listener->GetPresShell()->ReconstructFrames(); 1.3167 + } 1.3168 + } 1.3169 +} 1.3170 + 1.3171 +- (void)setNeedsPendingDisplay 1.3172 +{ 1.3173 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK; 1.3174 + 1.3175 + mPendingFullDisplay = YES; 1.3176 + if (!mPendingDisplay) { 1.3177 + [self performSelector:@selector(processPendingRedraws) withObject:nil afterDelay:0]; 1.3178 + mPendingDisplay = YES; 1.3179 + } 1.3180 + 1.3181 + NS_OBJC_END_TRY_ABORT_BLOCK; 1.3182 +} 1.3183 + 1.3184 +- (void)setNeedsPendingDisplayInRect:(NSRect)invalidRect 1.3185 +{ 1.3186 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK; 1.3187 + 1.3188 + if (!mPendingDirtyRects) 1.3189 + mPendingDirtyRects = [[NSMutableArray alloc] initWithCapacity:1]; 1.3190 + [mPendingDirtyRects addObject:[NSValue valueWithRect:invalidRect]]; 1.3191 + if (!mPendingDisplay) { 1.3192 + [self performSelector:@selector(processPendingRedraws) withObject:nil afterDelay:0]; 1.3193 + mPendingDisplay = YES; 1.3194 + } 1.3195 + 1.3196 + NS_OBJC_END_TRY_ABORT_BLOCK; 1.3197 +} 1.3198 + 1.3199 +// Clears the queue of any pending invalides 1.3200 +- (void)processPendingRedraws 1.3201 +{ 1.3202 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK; 1.3203 + 1.3204 + if (mPendingFullDisplay) { 1.3205 + [self setNeedsDisplay:YES]; 1.3206 + } 1.3207 + else if (mPendingDirtyRects) { 1.3208 + unsigned int count = [mPendingDirtyRects count]; 1.3209 + for (unsigned int i = 0; i < count; ++i) { 1.3210 + [self setNeedsDisplayInRect:[[mPendingDirtyRects objectAtIndex:i] rectValue]]; 1.3211 + } 1.3212 + } 1.3213 + mPendingFullDisplay = NO; 1.3214 + mPendingDisplay = NO; 1.3215 + [mPendingDirtyRects release]; 1.3216 + mPendingDirtyRects = nil; 1.3217 + 1.3218 + NS_OBJC_END_TRY_ABORT_BLOCK; 1.3219 +} 1.3220 + 1.3221 +- (void)setNeedsDisplayInRect:(NSRect)aRect 1.3222 +{ 1.3223 + if (![self isUsingOpenGL]) { 1.3224 + [super setNeedsDisplayInRect:aRect]; 1.3225 + return; 1.3226 + } 1.3227 + 1.3228 + if ([[self window] isVisible] && [self isUsingMainThreadOpenGL]) { 1.3229 + // Draw without calling drawRect. This prevent us from 1.3230 + // needing to access the normal window buffer surface unnecessarily, so we 1.3231 + // waste less time synchronizing the two surfaces. (These synchronizations 1.3232 + // show up in a profiler as CGSDeviceLock / _CGSLockWindow / 1.3233 + // _CGSSynchronizeWindowBackingStore.) It also means that Cocoa doesn't 1.3234 + // have any potentially expensive invalid rect management for us. 1.3235 + if (!mWaitingForPaint) { 1.3236 + mWaitingForPaint = YES; 1.3237 + // Use NSRunLoopCommonModes instead of the default NSDefaultRunLoopMode 1.3238 + // so that the timer also fires while a native menu is open. 1.3239 + [self performSelector:@selector(drawUsingOpenGLCallback) 1.3240 + withObject:nil 1.3241 + afterDelay:0 1.3242 + inModes:[NSArray arrayWithObject:NSRunLoopCommonModes]]; 1.3243 + } 1.3244 + } 1.3245 +} 1.3246 + 1.3247 +- (NSString*)description 1.3248 +{ 1.3249 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; 1.3250 + 1.3251 + return [NSString stringWithFormat:@"ChildView %p, gecko child %p, frame %@", self, mGeckoChild, NSStringFromRect([self frame])]; 1.3252 + 1.3253 + NS_OBJC_END_TRY_ABORT_BLOCK_NIL; 1.3254 +} 1.3255 + 1.3256 +// Make the origin of this view the topLeft corner (gecko origin) rather 1.3257 +// than the bottomLeft corner (standard cocoa origin). 1.3258 +- (BOOL)isFlipped 1.3259 +{ 1.3260 + return YES; 1.3261 +} 1.3262 + 1.3263 +- (BOOL)isOpaque 1.3264 +{ 1.3265 + return [[self window] isOpaque] && !mIsPluginView; 1.3266 +} 1.3267 + 1.3268 +-(void)setIsPluginView:(BOOL)aIsPlugin 1.3269 +{ 1.3270 + mIsPluginView = aIsPlugin; 1.3271 +} 1.3272 + 1.3273 +-(BOOL)isPluginView 1.3274 +{ 1.3275 + return mIsPluginView; 1.3276 +} 1.3277 + 1.3278 +- (NSView *)hitTest:(NSPoint)aPoint 1.3279 +{ 1.3280 + NSView* target = [super hitTest:aPoint]; 1.3281 + if ((target == self) && [self isPluginView] && mGeckoChild) { 1.3282 + nsAutoRetainCocoaObject kungFuDeathGrip(self); 1.3283 + 1.3284 + NSPoint cocoaLoc = [[self superview] convertPoint:aPoint toView:self]; 1.3285 + LayoutDeviceIntPoint widgetLoc = LayoutDeviceIntPoint::FromUntyped( 1.3286 + mGeckoChild->CocoaPointsToDevPixels(cocoaLoc)); 1.3287 + 1.3288 + WidgetQueryContentEvent hitTest(true, NS_QUERY_DOM_WIDGET_HITTEST, 1.3289 + mGeckoChild); 1.3290 + hitTest.InitForQueryDOMWidgetHittest(widgetLoc); 1.3291 + // This might destroy our widget. 1.3292 + mGeckoChild->DispatchWindowEvent(hitTest); 1.3293 + if (!mGeckoChild) { 1.3294 + return nil; 1.3295 + } 1.3296 + if (hitTest.mSucceeded && !hitTest.mReply.mWidgetIsHit) { 1.3297 + return nil; 1.3298 + } 1.3299 + } 1.3300 + return target; 1.3301 +} 1.3302 + 1.3303 +// Are we processing an NSLeftMouseDown event that will fail to click through? 1.3304 +// If so, we shouldn't focus or unfocus a plugin. 1.3305 +- (BOOL)isInFailingLeftClickThrough 1.3306 +{ 1.3307 + if (!mGeckoChild) 1.3308 + return NO; 1.3309 + 1.3310 + if (!mClickThroughMouseDownEvent || 1.3311 + [mClickThroughMouseDownEvent type] != NSLeftMouseDown) 1.3312 + return NO; 1.3313 + 1.3314 + BOOL retval = 1.3315 + !ChildViewMouseTracker::WindowAcceptsEvent([self window], 1.3316 + mClickThroughMouseDownEvent, 1.3317 + self, true); 1.3318 + 1.3319 + // If we return YES here, this will result in us not being focused, 1.3320 + // which will stop us receiving mClickThroughMouseDownEvent in 1.3321 + // [ChildView mouseDown:]. So we need to release and null-out 1.3322 + // mClickThroughMouseDownEvent here. 1.3323 + if (retval) { 1.3324 + [mClickThroughMouseDownEvent release]; 1.3325 + mClickThroughMouseDownEvent = nil; 1.3326 + } 1.3327 + 1.3328 + return retval; 1.3329 +} 1.3330 + 1.3331 +- (void)setPluginEventModel:(NPEventModel)eventModel 1.3332 +{ 1.3333 + mPluginEventModel = eventModel; 1.3334 +} 1.3335 + 1.3336 +- (void)setPluginDrawingModel:(NPDrawingModel)drawingModel 1.3337 +{ 1.3338 + mPluginDrawingModel = drawingModel; 1.3339 +} 1.3340 + 1.3341 +- (NPEventModel)pluginEventModel 1.3342 +{ 1.3343 + return mPluginEventModel; 1.3344 +} 1.3345 + 1.3346 +- (NPDrawingModel)pluginDrawingModel 1.3347 +{ 1.3348 + return mPluginDrawingModel; 1.3349 +} 1.3350 + 1.3351 +- (void)sendFocusEvent:(uint32_t)eventType 1.3352 +{ 1.3353 + if (!mGeckoChild) 1.3354 + return; 1.3355 + 1.3356 + nsEventStatus status = nsEventStatus_eIgnore; 1.3357 + WidgetGUIEvent focusGuiEvent(true, eventType, mGeckoChild); 1.3358 + focusGuiEvent.time = PR_IntervalNow(); 1.3359 + mGeckoChild->DispatchEvent(&focusGuiEvent, status); 1.3360 +} 1.3361 + 1.3362 +// We accept key and mouse events, so don't keep passing them up the chain. Allow 1.3363 +// this to be a 'focused' widget for event dispatch. 1.3364 +- (BOOL)acceptsFirstResponder 1.3365 +{ 1.3366 + return YES; 1.3367 +} 1.3368 + 1.3369 +// Accept mouse down events on background windows 1.3370 +- (BOOL)acceptsFirstMouse:(NSEvent*)aEvent 1.3371 +{ 1.3372 + if (![[self window] isKindOfClass:[PopupWindow class]]) { 1.3373 + // We rely on this function to tell us that the mousedown was on a 1.3374 + // background window. Inside mouseDown we can't tell whether we were 1.3375 + // inactive because at that point we've already been made active. 1.3376 + // Unfortunately, acceptsFirstMouse is called for PopupWindows even when 1.3377 + // their parent window is active, so ignore this on them for now. 1.3378 + mClickThroughMouseDownEvent = [aEvent retain]; 1.3379 + } 1.3380 + return YES; 1.3381 +} 1.3382 + 1.3383 +- (void)viewWillMoveToWindow:(NSWindow *)newWindow 1.3384 +{ 1.3385 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK; 1.3386 + 1.3387 + if (!newWindow) 1.3388 + HideChildPluginViews(self); 1.3389 + 1.3390 + [super viewWillMoveToWindow:newWindow]; 1.3391 + 1.3392 + NS_OBJC_END_TRY_ABORT_BLOCK; 1.3393 +} 1.3394 + 1.3395 +- (void)viewDidMoveToWindow 1.3396 +{ 1.3397 + if (mPluginEventModel == NPEventModelCocoa && 1.3398 + [self window] && [self isPluginView] && mGeckoChild) { 1.3399 + mGeckoChild->UpdatePluginPort(); 1.3400 + } 1.3401 + 1.3402 + [super viewDidMoveToWindow]; 1.3403 +} 1.3404 + 1.3405 +- (void)scrollRect:(NSRect)aRect by:(NSSize)offset 1.3406 +{ 1.3407 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK; 1.3408 + 1.3409 + // Update any pending dirty rects to reflect the new scroll position 1.3410 + if (mPendingDirtyRects) { 1.3411 + unsigned int count = [mPendingDirtyRects count]; 1.3412 + for (unsigned int i = 0; i < count; ++i) { 1.3413 + NSRect oldRect = [[mPendingDirtyRects objectAtIndex:i] rectValue]; 1.3414 + NSRect newRect = NSOffsetRect(oldRect, offset.width, offset.height); 1.3415 + [mPendingDirtyRects replaceObjectAtIndex:i 1.3416 + withObject:[NSValue valueWithRect:newRect]]; 1.3417 + } 1.3418 + } 1.3419 + [super scrollRect:aRect by:offset]; 1.3420 + 1.3421 + NS_OBJC_END_TRY_ABORT_BLOCK; 1.3422 +} 1.3423 + 1.3424 +- (BOOL)mouseDownCanMoveWindow 1.3425 +{ 1.3426 + return [[self window] isMovableByWindowBackground]; 1.3427 +} 1.3428 + 1.3429 +-(void)updateGLContext 1.3430 +{ 1.3431 + if (mGLContext) { 1.3432 + CGLLockContext((CGLContextObj)[mGLContext CGLContextObj]); 1.3433 + [mGLContext setView:self]; 1.3434 + [mGLContext update]; 1.3435 + CGLUnlockContext((CGLContextObj)[mGLContext CGLContextObj]); 1.3436 + } 1.3437 +} 1.3438 + 1.3439 +- (void)_surfaceNeedsUpdate:(NSNotification*)notification 1.3440 +{ 1.3441 + [self updateGLContext]; 1.3442 +} 1.3443 + 1.3444 +- (BOOL)wantsBestResolutionOpenGLSurface 1.3445 +{ 1.3446 + return nsCocoaUtils::HiDPIEnabled() ? YES : NO; 1.3447 +} 1.3448 + 1.3449 +- (void)viewDidChangeBackingProperties 1.3450 +{ 1.3451 + [super viewDidChangeBackingProperties]; 1.3452 + if (mGeckoChild) { 1.3453 + // actually, it could be the color space that's changed, 1.3454 + // but we can't tell the difference here except by retrieving 1.3455 + // the backing scale factor and comparing to the old value 1.3456 + mGeckoChild->BackingScaleFactorChanged(); 1.3457 + } 1.3458 +} 1.3459 + 1.3460 +- (BOOL)isCoveringTitlebar 1.3461 +{ 1.3462 + return [[self window] isKindOfClass:[BaseWindow class]] && 1.3463 + [(BaseWindow*)[self window] mainChildView] == self && 1.3464 + [(BaseWindow*)[self window] drawsContentsIntoWindowFrame]; 1.3465 +} 1.3466 + 1.3467 +- (nsIntRegion)nativeDirtyRegionWithBoundingRect:(NSRect)aRect 1.3468 +{ 1.3469 + nsIntRect boundingRect = mGeckoChild->CocoaPointsToDevPixels(aRect); 1.3470 + const NSRect *rects; 1.3471 + NSInteger count; 1.3472 + [self getRectsBeingDrawn:&rects count:&count]; 1.3473 + 1.3474 + if (count > MAX_RECTS_IN_REGION) { 1.3475 + return boundingRect; 1.3476 + } 1.3477 + 1.3478 + nsIntRegion region; 1.3479 + for (NSInteger i = 0; i < count; ++i) { 1.3480 + region.Or(region, mGeckoChild->CocoaPointsToDevPixels(rects[i])); 1.3481 + } 1.3482 + region.And(region, boundingRect); 1.3483 + return region; 1.3484 +} 1.3485 + 1.3486 +// The display system has told us that a portion of our view is dirty. Tell 1.3487 +// gecko to paint it 1.3488 +- (void)drawRect:(NSRect)aRect 1.3489 +{ 1.3490 + CGContextRef cgContext = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort]; 1.3491 + [self drawRect:aRect inContext:cgContext]; 1.3492 + 1.3493 + // If we're a transparent window and our contents have changed, we need 1.3494 + // to make sure the shadow is updated to the new contents. 1.3495 + if ([[self window] isKindOfClass:[BaseWindow class]]) { 1.3496 + [(BaseWindow*)[self window] deferredInvalidateShadow]; 1.3497 + } 1.3498 +} 1.3499 + 1.3500 +- (void)drawRect:(NSRect)aRect inContext:(CGContextRef)aContext 1.3501 +{ 1.3502 + if (!mGeckoChild || !mGeckoChild->IsVisible()) 1.3503 + return; 1.3504 + 1.3505 + // Don't ever draw plugin views explicitly; they'll be drawn as part of their parent widget. 1.3506 + if (mIsPluginView) 1.3507 + return; 1.3508 + 1.3509 +#ifdef DEBUG_UPDATE 1.3510 + nsIntRect geckoBounds; 1.3511 + mGeckoChild->GetBounds(geckoBounds); 1.3512 + 1.3513 + fprintf (stderr, "---- Update[%p][%p] [%f %f %f %f] cgc: %p\n gecko bounds: [%d %d %d %d]\n", 1.3514 + self, mGeckoChild, 1.3515 + aRect.origin.x, aRect.origin.y, aRect.size.width, aRect.size.height, aContext, 1.3516 + geckoBounds.x, geckoBounds.y, geckoBounds.width, geckoBounds.height); 1.3517 + 1.3518 + CGAffineTransform xform = CGContextGetCTM(aContext); 1.3519 + fprintf (stderr, " xform in: [%f %f %f %f %f %f]\n", xform.a, xform.b, xform.c, xform.d, xform.tx, xform.ty); 1.3520 +#endif 1.3521 + 1.3522 + if ([self isUsingOpenGL]) { 1.3523 + // For Gecko-initiated repaints in OpenGL mode, drawUsingOpenGL is 1.3524 + // directly called from a delayed perform callback - without going through 1.3525 + // drawRect. 1.3526 + // Paints that come through here are triggered by something that Cocoa 1.3527 + // controls, for example by window resizing or window focus changes. 1.3528 + 1.3529 + // Since this view is usually declared as opaque, the window's pixel 1.3530 + // buffer may now contain garbage which we need to prevent from reaching 1.3531 + // the screen. The only place where garbage can show is in the window 1.3532 + // corners - the rest of the window is covered by opaque content in our 1.3533 + // OpenGL surface. 1.3534 + // So we need to clear the pixel buffer contents in the corners. 1.3535 + [self clearCorners]; 1.3536 + 1.3537 + // Do GL composition and return. 1.3538 + [self drawUsingOpenGL]; 1.3539 + return; 1.3540 + } 1.3541 + 1.3542 + PROFILER_LABEL("widget", "ChildView::drawRect"); 1.3543 + 1.3544 + // The CGContext that drawRect supplies us with comes with a transform that 1.3545 + // scales one user space unit to one Cocoa point, which can consist of 1.3546 + // multiple dev pixels. But Gecko expects its supplied context to be scaled 1.3547 + // to device pixels, so we need to reverse the scaling. 1.3548 + double scale = mGeckoChild->BackingScaleFactor(); 1.3549 + CGContextSaveGState(aContext); 1.3550 + CGContextScaleCTM(aContext, 1.0 / scale, 1.0 / scale); 1.3551 + 1.3552 + NSSize viewSize = [self bounds].size; 1.3553 + nsIntSize backingSize(viewSize.width * scale, viewSize.height * scale); 1.3554 + 1.3555 + CGContextSaveGState(aContext); 1.3556 + 1.3557 + nsIntRegion region = [self nativeDirtyRegionWithBoundingRect:aRect]; 1.3558 + 1.3559 + // Create Cairo objects. 1.3560 + nsRefPtr<gfxQuartzSurface> targetSurface = 1.3561 + new gfxQuartzSurface(aContext, backingSize); 1.3562 + targetSurface->SetAllowUseAsSource(false); 1.3563 + 1.3564 + nsRefPtr<gfxContext> targetContext; 1.3565 + if (gfxPlatform::GetPlatform()->SupportsAzureContentForType(gfx::BackendType::CAIRO)) { 1.3566 + RefPtr<gfx::DrawTarget> dt = 1.3567 + gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(targetSurface, 1.3568 + gfx::IntSize(backingSize.width, 1.3569 + backingSize.height)); 1.3570 + dt->AddUserData(&gfxContext::sDontUseAsSourceKey, dt, nullptr); 1.3571 + targetContext = new gfxContext(dt); 1.3572 + } else if (gfxPlatform::GetPlatform()->SupportsAzureContentForType(gfx::BackendType::COREGRAPHICS)) { 1.3573 + RefPtr<gfx::DrawTarget> dt = 1.3574 + gfx::Factory::CreateDrawTargetForCairoCGContext(aContext, 1.3575 + gfx::IntSize(backingSize.width, 1.3576 + backingSize.height)); 1.3577 + dt->AddUserData(&gfxContext::sDontUseAsSourceKey, dt, nullptr); 1.3578 + targetContext = new gfxContext(dt); 1.3579 + } else { 1.3580 + targetContext = new gfxContext(targetSurface); 1.3581 + } 1.3582 + 1.3583 + // Set up the clip region. 1.3584 + nsIntRegionRectIterator iter(region); 1.3585 + targetContext->NewPath(); 1.3586 + for (;;) { 1.3587 + const nsIntRect* r = iter.Next(); 1.3588 + if (!r) 1.3589 + break; 1.3590 + targetContext->Rectangle(gfxRect(r->x, r->y, r->width, r->height)); 1.3591 + } 1.3592 + targetContext->Clip(); 1.3593 + 1.3594 + nsAutoRetainCocoaObject kungFuDeathGrip(self); 1.3595 + bool painted = false; 1.3596 + if (mGeckoChild->GetLayerManager()->GetBackendType() == LayersBackend::LAYERS_BASIC) { 1.3597 + nsBaseWidget::AutoLayerManagerSetup 1.3598 + setupLayerManager(mGeckoChild, targetContext, BufferMode::BUFFER_NONE); 1.3599 + painted = mGeckoChild->PaintWindow(region); 1.3600 + } else if (mGeckoChild->GetLayerManager()->GetBackendType() == LayersBackend::LAYERS_CLIENT) { 1.3601 + // We only need this so that we actually get DidPaintWindow fired 1.3602 + painted = mGeckoChild->PaintWindow(region); 1.3603 + } 1.3604 + 1.3605 + targetContext = nullptr; 1.3606 + targetSurface = nullptr; 1.3607 + 1.3608 + CGContextRestoreGState(aContext); 1.3609 + 1.3610 + // Undo the scale transform so that from now on the context is in 1.3611 + // CocoaPoints again. 1.3612 + CGContextRestoreGState(aContext); 1.3613 + 1.3614 + if (!painted && [self isOpaque]) { 1.3615 + // Gecko refused to draw, but we've claimed to be opaque, so we have to 1.3616 + // draw something--fill with white. 1.3617 + CGContextSetRGBFillColor(aContext, 1, 1, 1, 1); 1.3618 + CGContextFillRect(aContext, NSRectToCGRect(aRect)); 1.3619 + } 1.3620 + 1.3621 + if ([self isCoveringTitlebar]) { 1.3622 + [self drawTitleString]; 1.3623 + [self drawTitlebarHighlight]; 1.3624 + [self maskTopCornersInContext:aContext]; 1.3625 + } 1.3626 + 1.3627 +#ifdef DEBUG_UPDATE 1.3628 + fprintf (stderr, "---- update done ----\n"); 1.3629 + 1.3630 +#if 0 1.3631 + CGContextSetRGBStrokeColor (aContext, 1.3632 + ((((unsigned long)self) & 0xff)) / 255.0, 1.3633 + ((((unsigned long)self) & 0xff00) >> 8) / 255.0, 1.3634 + ((((unsigned long)self) & 0xff0000) >> 16) / 255.0, 1.3635 + 0.5); 1.3636 +#endif 1.3637 + CGContextSetRGBStrokeColor(aContext, 1, 0, 0, 0.8); 1.3638 + CGContextSetLineWidth(aContext, 4.0); 1.3639 + CGContextStrokeRect(aContext, NSRectToCGRect(aRect)); 1.3640 +#endif 1.3641 +} 1.3642 + 1.3643 +- (BOOL)isUsingMainThreadOpenGL 1.3644 +{ 1.3645 + if (!mGeckoChild || ![self window]) 1.3646 + return NO; 1.3647 + 1.3648 + return mGeckoChild->GetLayerManager(nullptr)->GetBackendType() == mozilla::layers::LayersBackend::LAYERS_OPENGL; 1.3649 +} 1.3650 + 1.3651 +- (BOOL)isUsingOpenGL 1.3652 +{ 1.3653 + if (!mGeckoChild || ![self window]) 1.3654 + return NO; 1.3655 + 1.3656 + return mGLContext || mUsingOMTCompositor || [self isUsingMainThreadOpenGL]; 1.3657 +} 1.3658 + 1.3659 +- (void)drawUsingOpenGL 1.3660 +{ 1.3661 + PROFILER_LABEL("widget", "ChildView::drawUsingOpenGL"); 1.3662 + 1.3663 + if (![self isUsingOpenGL] || !mGeckoChild->IsVisible()) 1.3664 + return; 1.3665 + 1.3666 + mWaitingForPaint = NO; 1.3667 + 1.3668 + nsIntRect geckoBounds; 1.3669 + mGeckoChild->GetBounds(geckoBounds); 1.3670 + nsIntRegion region(geckoBounds); 1.3671 + 1.3672 + mGeckoChild->PaintWindow(region); 1.3673 + 1.3674 + // Force OpenGL to refresh the very first time we draw. This works around a 1.3675 + // Mac OS X bug that stops windows updating on OS X when we use OpenGL. 1.3676 + if (!mDidForceRefreshOpenGL) { 1.3677 + [self performSelector:@selector(forceRefreshOpenGL) withObject:nil afterDelay:0]; 1.3678 + mDidForceRefreshOpenGL = YES; 1.3679 + } 1.3680 +} 1.3681 + 1.3682 +// Called asynchronously after setNeedsDisplay in order to avoid entering the 1.3683 +// normal drawing machinery. 1.3684 +- (void)drawUsingOpenGLCallback 1.3685 +{ 1.3686 + if (mWaitingForPaint) { 1.3687 + [self drawUsingOpenGL]; 1.3688 + } 1.3689 +} 1.3690 + 1.3691 +- (BOOL)hasRoundedBottomCorners 1.3692 +{ 1.3693 + return [[self window] respondsToSelector:@selector(bottomCornerRounded)] && 1.3694 + [[self window] bottomCornerRounded]; 1.3695 +} 1.3696 + 1.3697 +- (CGFloat)cornerRadius 1.3698 +{ 1.3699 + NSView* frameView = [[[self window] contentView] superview]; 1.3700 + if (!frameView || ![frameView respondsToSelector:@selector(roundedCornerRadius)]) 1.3701 + return 4.0f; 1.3702 + return [frameView roundedCornerRadius]; 1.3703 +} 1.3704 + 1.3705 +// Accelerated windows have two NSSurfaces: 1.3706 +// (1) The window's pixel buffer in the back and 1.3707 +// (2) the OpenGL view in the front. 1.3708 +// These two surfaces are composited by the window manager. Drawing into the 1.3709 +// CGContext which is provided by drawRect ends up in (1). 1.3710 +// When our window has rounded corners, the OpenGL view has transparent pixels 1.3711 +// in the corners. In these places the contents of the window's pixel buffer 1.3712 +// can show through. So we need to make sure that the pixel buffer is 1.3713 +// transparent in the corners so that no garbage reaches the screen. 1.3714 +// The contents of the pixel buffer in the rest of the window don't matter 1.3715 +// because they're covered by opaque pixels of the OpenGL context. 1.3716 +// Making the corners transparent works even though our window is 1.3717 +// declared "opaque" (in the NSWindow's isOpaque method). 1.3718 +- (void)clearCorners 1.3719 +{ 1.3720 + CGFloat radius = [self cornerRadius]; 1.3721 + CGFloat w = [self bounds].size.width, h = [self bounds].size.height; 1.3722 + [[NSColor clearColor] set]; 1.3723 + 1.3724 + if ([self isCoveringTitlebar]) { 1.3725 + NSRectFill(NSMakeRect(0, 0, radius, radius)); 1.3726 + NSRectFill(NSMakeRect(w - radius, 0, radius, radius)); 1.3727 + } 1.3728 + 1.3729 + if ([self hasRoundedBottomCorners]) { 1.3730 + NSRectFill(NSMakeRect(0, h - radius, radius, radius)); 1.3731 + NSRectFill(NSMakeRect(w - radius, h - radius, radius, radius)); 1.3732 + } 1.3733 +} 1.3734 + 1.3735 +// This is the analog of nsChildView::MaybeDrawRoundedCorners for CGContexts. 1.3736 +// We only need to mask the top corners here because Cocoa does the masking 1.3737 +// for the window's bottom corners automatically (starting with 10.7). 1.3738 +- (void)maskTopCornersInContext:(CGContextRef)aContext 1.3739 +{ 1.3740 + CGFloat radius = [self cornerRadius]; 1.3741 + int32_t devPixelCornerRadius = mGeckoChild->CocoaPointsToDevPixels(radius); 1.3742 + 1.3743 + // First make sure that mTopLeftCornerMask is set up. 1.3744 + if (!mTopLeftCornerMask || 1.3745 + int32_t(CGImageGetWidth(mTopLeftCornerMask)) != devPixelCornerRadius) { 1.3746 + CGImageRelease(mTopLeftCornerMask); 1.3747 + CGColorSpaceRef rgb = CGColorSpaceCreateDeviceRGB(); 1.3748 + CGContextRef imgCtx = CGBitmapContextCreate(NULL, 1.3749 + devPixelCornerRadius, 1.3750 + devPixelCornerRadius, 1.3751 + 8, devPixelCornerRadius * 4, 1.3752 + rgb, kCGImageAlphaPremultipliedFirst); 1.3753 + CGColorSpaceRelease(rgb); 1.3754 + DrawTopLeftCornerMask(imgCtx, devPixelCornerRadius); 1.3755 + mTopLeftCornerMask = CGBitmapContextCreateImage(imgCtx); 1.3756 + CGContextRelease(imgCtx); 1.3757 + } 1.3758 + 1.3759 + // kCGBlendModeDestinationIn is the secret sauce which allows us to erase 1.3760 + // already painted pixels. It's defined as R = D * Sa: multiply all channels 1.3761 + // of the destination pixel with the alpha of the source pixel. In our case, 1.3762 + // the source is mTopLeftCornerMask. 1.3763 + CGContextSaveGState(aContext); 1.3764 + CGContextSetBlendMode(aContext, kCGBlendModeDestinationIn); 1.3765 + 1.3766 + CGRect destRect = CGRectMake(0, 0, radius, radius); 1.3767 + 1.3768 + // Erase the top left corner... 1.3769 + CGContextDrawImage(aContext, destRect, mTopLeftCornerMask); 1.3770 + 1.3771 + // ... and the top right corner. 1.3772 + CGContextTranslateCTM(aContext, [self bounds].size.width, 0); 1.3773 + CGContextScaleCTM(aContext, -1, 1); 1.3774 + CGContextDrawImage(aContext, destRect, mTopLeftCornerMask); 1.3775 + 1.3776 + CGContextRestoreGState(aContext); 1.3777 +} 1.3778 + 1.3779 +- (void)drawTitleString 1.3780 +{ 1.3781 + BaseWindow* window = (BaseWindow*)[self window]; 1.3782 + if (![window wantsTitleDrawn]) { 1.3783 + return; 1.3784 + } 1.3785 + 1.3786 + NSView* frameView = [[window contentView] superview]; 1.3787 + if (![frameView respondsToSelector:@selector(_drawTitleBar:)]) { 1.3788 + return; 1.3789 + } 1.3790 + 1.3791 + NSGraphicsContext* oldContext = [NSGraphicsContext currentContext]; 1.3792 + CGContextRef ctx = (CGContextRef)[oldContext graphicsPort]; 1.3793 + CGContextSaveGState(ctx); 1.3794 + if ([oldContext isFlipped] != [frameView isFlipped]) { 1.3795 + CGContextTranslateCTM(ctx, 0, [self bounds].size.height); 1.3796 + CGContextScaleCTM(ctx, 1, -1); 1.3797 + } 1.3798 + [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithGraphicsPort:ctx flipped:[frameView isFlipped]]]; 1.3799 + [frameView _drawTitleBar:[frameView bounds]]; 1.3800 + CGContextRestoreGState(ctx); 1.3801 + [NSGraphicsContext setCurrentContext:oldContext]; 1.3802 +} 1.3803 + 1.3804 +- (void)drawTitlebarHighlight 1.3805 +{ 1.3806 + DrawTitlebarHighlight([self bounds].size, [self cornerRadius], 1.3807 + mGeckoChild->DevPixelsToCocoaPoints(1)); 1.3808 +} 1.3809 + 1.3810 +- (void)releaseWidgets:(NSArray*)aWidgetArray 1.3811 +{ 1.3812 + if (!aWidgetArray) { 1.3813 + return; 1.3814 + } 1.3815 + NSInteger count = [aWidgetArray count]; 1.3816 + for (NSInteger i = 0; i < count; ++i) { 1.3817 + NSNumber* pointer = (NSNumber*) [aWidgetArray objectAtIndex:i]; 1.3818 + nsIWidget* widget = (nsIWidget*) [pointer unsignedIntegerValue]; 1.3819 + NS_RELEASE(widget); 1.3820 + } 1.3821 +} 1.3822 + 1.3823 +- (void)viewWillDraw 1.3824 +{ 1.3825 + if (mGeckoChild) { 1.3826 + // The OS normally *will* draw our NSWindow, no matter what we do here. 1.3827 + // But Gecko can delete our parent widget(s) (along with mGeckoChild) 1.3828 + // while processing a paint request, which closes our NSWindow and 1.3829 + // makes the OS throw an NSInternalInconsistencyException assertion when 1.3830 + // it tries to draw it. Sometimes the OS also aborts the browser process. 1.3831 + // So we need to retain our parent(s) here and not release it/them until 1.3832 + // the next time through the main thread's run loop. When we do this we 1.3833 + // also need to retain and release mGeckoChild, which holds a strong 1.3834 + // reference to us (otherwise we might have been deleted by the time 1.3835 + // releaseWidgets: is called on us). See bug 550392. 1.3836 + nsIWidget* parent = mGeckoChild->GetParent(); 1.3837 + if (parent) { 1.3838 + NSMutableArray* widgetArray = [NSMutableArray arrayWithCapacity:3]; 1.3839 + while (parent) { 1.3840 + NS_ADDREF(parent); 1.3841 + [widgetArray addObject:[NSNumber numberWithUnsignedInteger:(NSUInteger)parent]]; 1.3842 + parent = parent->GetParent(); 1.3843 + } 1.3844 + NS_ADDREF(mGeckoChild); 1.3845 + [widgetArray addObject:[NSNumber numberWithUnsignedInteger:(NSUInteger)mGeckoChild]]; 1.3846 + [self performSelector:@selector(releaseWidgets:) 1.3847 + withObject:widgetArray 1.3848 + afterDelay:0]; 1.3849 + } 1.3850 + 1.3851 + if ([self isUsingOpenGL]) { 1.3852 + // When our view covers the titlebar, we need to repaint the titlebar 1.3853 + // texture buffer when, for example, the window buttons are hovered. 1.3854 + // So we notify our nsChildView about any areas needing repainting. 1.3855 + mGeckoChild->NotifyDirtyRegion([self nativeDirtyRegionWithBoundingRect:[self bounds]]); 1.3856 + 1.3857 + if (mGeckoChild->GetLayerManager()->GetBackendType() == LayersBackend::LAYERS_CLIENT) { 1.3858 + ClientLayerManager *manager = static_cast<ClientLayerManager*>(mGeckoChild->GetLayerManager()); 1.3859 + manager->AsShadowForwarder()->WindowOverlayChanged(); 1.3860 + } 1.3861 + } 1.3862 + 1.3863 + mGeckoChild->WillPaintWindow(); 1.3864 + } 1.3865 + [super viewWillDraw]; 1.3866 +} 1.3867 + 1.3868 +#if USE_CLICK_HOLD_CONTEXTMENU 1.3869 +// 1.3870 +// -clickHoldCallback: 1.3871 +// 1.3872 +// called from a timer two seconds after a mouse down to see if we should display 1.3873 +// a context menu (click-hold). |anEvent| is the original mouseDown event. If we're 1.3874 +// still in that mouseDown by this time, put up the context menu, otherwise just 1.3875 +// fuhgeddaboutit. |anEvent| has been retained by the OS until after this callback 1.3876 +// fires so we're ok there. 1.3877 +// 1.3878 +// This code currently messes in a bunch of edge cases (bugs 234751, 232964, 232314) 1.3879 +// so removing it until we get it straightened out. 1.3880 +// 1.3881 +- (void)clickHoldCallback:(id)theEvent; 1.3882 +{ 1.3883 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK; 1.3884 + 1.3885 + if( theEvent == [NSApp currentEvent] ) { 1.3886 + // we're still in the middle of the same mousedown event here, activate 1.3887 + // click-hold context menu by triggering the right mouseDown action. 1.3888 + NSEvent* clickHoldEvent = [NSEvent mouseEventWithType:NSRightMouseDown 1.3889 + location:[theEvent locationInWindow] 1.3890 + modifierFlags:[theEvent modifierFlags] 1.3891 + timestamp:[theEvent timestamp] 1.3892 + windowNumber:[theEvent windowNumber] 1.3893 + context:[theEvent context] 1.3894 + eventNumber:[theEvent eventNumber] 1.3895 + clickCount:[theEvent clickCount] 1.3896 + pressure:[theEvent pressure]]; 1.3897 + [self rightMouseDown:clickHoldEvent]; 1.3898 + } 1.3899 + 1.3900 + NS_OBJC_END_TRY_ABORT_BLOCK; 1.3901 +} 1.3902 +#endif 1.3903 + 1.3904 +// If we've just created a non-native context menu, we need to mark it as 1.3905 +// such and let the OS (and other programs) know when it opens and closes 1.3906 +// (this is how the OS knows to close other programs' context menus when 1.3907 +// ours open). We send the initial notification here, but others are sent 1.3908 +// in nsCocoaWindow::Show(). 1.3909 +- (void)maybeInitContextMenuTracking 1.3910 +{ 1.3911 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK; 1.3912 + 1.3913 +#ifdef MOZ_USE_NATIVE_POPUP_WINDOWS 1.3914 + return; 1.3915 +#endif /* MOZ_USE_NATIVE_POPUP_WINDOWS */ 1.3916 + 1.3917 + nsIRollupListener* rollupListener = nsBaseWidget::GetActiveRollupListener(); 1.3918 + NS_ENSURE_TRUE_VOID(rollupListener); 1.3919 + nsCOMPtr<nsIWidget> widget = rollupListener->GetRollupWidget(); 1.3920 + NS_ENSURE_TRUE_VOID(widget); 1.3921 + 1.3922 + NSWindow *popupWindow = (NSWindow*)widget->GetNativeData(NS_NATIVE_WINDOW); 1.3923 + if (!popupWindow || ![popupWindow isKindOfClass:[PopupWindow class]]) 1.3924 + return; 1.3925 + 1.3926 + [[NSDistributedNotificationCenter defaultCenter] 1.3927 + postNotificationName:@"com.apple.HIToolbox.beginMenuTrackingNotification" 1.3928 + object:@"org.mozilla.gecko.PopupWindow"]; 1.3929 + [(PopupWindow*)popupWindow setIsContextMenu:YES]; 1.3930 + 1.3931 + NS_OBJC_END_TRY_ABORT_BLOCK; 1.3932 +} 1.3933 + 1.3934 +// Returns true if the event should no longer be processed, false otherwise. 1.3935 +// This does not return whether or not anything was rolled up. 1.3936 +- (BOOL)maybeRollup:(NSEvent*)theEvent 1.3937 +{ 1.3938 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN; 1.3939 + 1.3940 + BOOL consumeEvent = NO; 1.3941 + 1.3942 + nsIRollupListener* rollupListener = nsBaseWidget::GetActiveRollupListener(); 1.3943 + NS_ENSURE_TRUE(rollupListener, false); 1.3944 + nsCOMPtr<nsIWidget> rollupWidget = rollupListener->GetRollupWidget(); 1.3945 + if (rollupWidget) { 1.3946 + NSWindow* currentPopup = static_cast<NSWindow*>(rollupWidget->GetNativeData(NS_NATIVE_WINDOW)); 1.3947 + if (!nsCocoaUtils::IsEventOverWindow(theEvent, currentPopup)) { 1.3948 + // event is not over the rollup window, default is to roll up 1.3949 + bool shouldRollup = true; 1.3950 + 1.3951 + // check to see if scroll events should roll up the popup 1.3952 + if ([theEvent type] == NSScrollWheel) { 1.3953 + shouldRollup = rollupListener->ShouldRollupOnMouseWheelEvent(); 1.3954 + // consume scroll events that aren't over the popup 1.3955 + // unless the popup is an arrow panel 1.3956 + consumeEvent = rollupListener->ShouldConsumeOnMouseWheelEvent(); 1.3957 + } 1.3958 + 1.3959 + // if we're dealing with menus, we probably have submenus and 1.3960 + // we don't want to rollup if the click is in a parent menu of 1.3961 + // the current submenu 1.3962 + uint32_t popupsToRollup = UINT32_MAX; 1.3963 + nsAutoTArray<nsIWidget*, 5> widgetChain; 1.3964 + uint32_t sameTypeCount = rollupListener->GetSubmenuWidgetChain(&widgetChain); 1.3965 + for (uint32_t i = 0; i < widgetChain.Length(); i++) { 1.3966 + nsIWidget* widget = widgetChain[i]; 1.3967 + NSWindow* currWindow = (NSWindow*)widget->GetNativeData(NS_NATIVE_WINDOW); 1.3968 + if (nsCocoaUtils::IsEventOverWindow(theEvent, currWindow)) { 1.3969 + // don't roll up if the mouse event occurred within a menu of the 1.3970 + // same type. If the mouse event occurred in a menu higher than 1.3971 + // that, roll up, but pass the number of popups to Rollup so 1.3972 + // that only those of the same type close up. 1.3973 + if (i < sameTypeCount) { 1.3974 + shouldRollup = false; 1.3975 + } 1.3976 + else { 1.3977 + popupsToRollup = sameTypeCount; 1.3978 + } 1.3979 + break; 1.3980 + } 1.3981 + } 1.3982 + 1.3983 + if (shouldRollup) { 1.3984 + if ([theEvent type] == NSLeftMouseDown) { 1.3985 + NSPoint point = [NSEvent mouseLocation]; 1.3986 + FlipCocoaScreenCoordinate(point); 1.3987 + nsIntPoint pos(point.x, point.y); 1.3988 + consumeEvent = (BOOL)rollupListener->Rollup(popupsToRollup, &pos, nullptr); 1.3989 + } 1.3990 + else { 1.3991 + consumeEvent = (BOOL)rollupListener->Rollup(popupsToRollup, nullptr, nullptr); 1.3992 + } 1.3993 + } 1.3994 + } 1.3995 + } 1.3996 + 1.3997 + return consumeEvent; 1.3998 + 1.3999 + NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(NO); 1.4000 +} 1.4001 + 1.4002 +/* 1.4003 + * In OS X Mountain Lion and above, smart zoom gestures are implemented in 1.4004 + * smartMagnifyWithEvent. In OS X Lion, they are implemented in 1.4005 + * magnifyWithEvent. See inline comments for more info. 1.4006 + * 1.4007 + * The prototypes swipeWithEvent, beginGestureWithEvent, magnifyWithEvent, 1.4008 + * smartMagnifyWithEvent, rotateWithEvent, and endGestureWithEvent were 1.4009 + * obtained from the following links: 1.4010 + * https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ApplicationKit/Classes/NSResponder_Class/Reference/Reference.html 1.4011 + * https://developer.apple.com/library/mac/#releasenotes/Cocoa/AppKit.html 1.4012 + */ 1.4013 + 1.4014 +- (void)swipeWithEvent:(NSEvent *)anEvent 1.4015 +{ 1.4016 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK; 1.4017 + 1.4018 + if (!anEvent || !mGeckoChild) 1.4019 + return; 1.4020 + 1.4021 + nsAutoRetainCocoaObject kungFuDeathGrip(self); 1.4022 + 1.4023 + float deltaX = [anEvent deltaX]; // left=1.0, right=-1.0 1.4024 + float deltaY = [anEvent deltaY]; // up=1.0, down=-1.0 1.4025 + 1.4026 + // Setup the "swipe" event. 1.4027 + WidgetSimpleGestureEvent geckoEvent(true, NS_SIMPLE_GESTURE_SWIPE, 1.4028 + mGeckoChild); 1.4029 + [self convertCocoaMouseEvent:anEvent toGeckoEvent:&geckoEvent]; 1.4030 + 1.4031 + // Record the left/right direction. 1.4032 + if (deltaX > 0.0) 1.4033 + geckoEvent.direction |= nsIDOMSimpleGestureEvent::DIRECTION_LEFT; 1.4034 + else if (deltaX < 0.0) 1.4035 + geckoEvent.direction |= nsIDOMSimpleGestureEvent::DIRECTION_RIGHT; 1.4036 + 1.4037 + // Record the up/down direction. 1.4038 + if (deltaY > 0.0) 1.4039 + geckoEvent.direction |= nsIDOMSimpleGestureEvent::DIRECTION_UP; 1.4040 + else if (deltaY < 0.0) 1.4041 + geckoEvent.direction |= nsIDOMSimpleGestureEvent::DIRECTION_DOWN; 1.4042 + 1.4043 + // Send the event. 1.4044 + mGeckoChild->DispatchWindowEvent(geckoEvent); 1.4045 + 1.4046 + NS_OBJC_END_TRY_ABORT_BLOCK; 1.4047 +} 1.4048 + 1.4049 +- (void)beginGestureWithEvent:(NSEvent *)anEvent 1.4050 +{ 1.4051 + if (!anEvent) 1.4052 + return; 1.4053 + 1.4054 + mGestureState = eGestureState_StartGesture; 1.4055 + mCumulativeMagnification = 0; 1.4056 + mCumulativeRotation = 0.0; 1.4057 +} 1.4058 + 1.4059 +- (void)magnifyWithEvent:(NSEvent *)anEvent 1.4060 +{ 1.4061 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK; 1.4062 + 1.4063 + if (!anEvent || !mGeckoChild) 1.4064 + return; 1.4065 + 1.4066 + /* 1.4067 + * In OS X 10.7.* (Lion), smart zoom events come through magnifyWithEvent, 1.4068 + * instead of smartMagnifyWithEvent. See bug 863841. 1.4069 + */ 1.4070 + if ([ChildView isLionSmartMagnifyEvent: anEvent]) { 1.4071 + [self smartMagnifyWithEvent: anEvent]; 1.4072 + return; 1.4073 + } 1.4074 + 1.4075 + nsAutoRetainCocoaObject kungFuDeathGrip(self); 1.4076 + 1.4077 + float deltaZ = [anEvent deltaZ]; 1.4078 + 1.4079 + uint32_t msg; 1.4080 + switch (mGestureState) { 1.4081 + case eGestureState_StartGesture: 1.4082 + msg = NS_SIMPLE_GESTURE_MAGNIFY_START; 1.4083 + mGestureState = eGestureState_MagnifyGesture; 1.4084 + break; 1.4085 + 1.4086 + case eGestureState_MagnifyGesture: 1.4087 + msg = NS_SIMPLE_GESTURE_MAGNIFY_UPDATE; 1.4088 + break; 1.4089 + 1.4090 + case eGestureState_None: 1.4091 + case eGestureState_RotateGesture: 1.4092 + default: 1.4093 + return; 1.4094 + } 1.4095 + 1.4096 + // Setup the event. 1.4097 + WidgetSimpleGestureEvent geckoEvent(true, msg, mGeckoChild); 1.4098 + geckoEvent.delta = deltaZ; 1.4099 + [self convertCocoaMouseEvent:anEvent toGeckoEvent:&geckoEvent]; 1.4100 + 1.4101 + // Send the event. 1.4102 + mGeckoChild->DispatchWindowEvent(geckoEvent); 1.4103 + 1.4104 + // Keep track of the cumulative magnification for the final "magnify" event. 1.4105 + mCumulativeMagnification += deltaZ; 1.4106 + 1.4107 + NS_OBJC_END_TRY_ABORT_BLOCK; 1.4108 +} 1.4109 + 1.4110 +- (void)smartMagnifyWithEvent:(NSEvent *)anEvent 1.4111 +{ 1.4112 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK; 1.4113 + 1.4114 + if (!anEvent || !mGeckoChild) { 1.4115 + return; 1.4116 + } 1.4117 + 1.4118 + nsAutoRetainCocoaObject kungFuDeathGrip(self); 1.4119 + 1.4120 + // Setup the "double tap" event. 1.4121 + WidgetSimpleGestureEvent geckoEvent(true, NS_SIMPLE_GESTURE_TAP, 1.4122 + mGeckoChild); 1.4123 + [self convertCocoaMouseEvent:anEvent toGeckoEvent:&geckoEvent]; 1.4124 + geckoEvent.clickCount = 1; 1.4125 + 1.4126 + // Send the event. 1.4127 + mGeckoChild->DispatchWindowEvent(geckoEvent); 1.4128 + 1.4129 + // Clear the gesture state 1.4130 + mGestureState = eGestureState_None; 1.4131 + 1.4132 + NS_OBJC_END_TRY_ABORT_BLOCK; 1.4133 +} 1.4134 + 1.4135 +- (void)rotateWithEvent:(NSEvent *)anEvent 1.4136 +{ 1.4137 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK; 1.4138 + 1.4139 + if (!anEvent || !mGeckoChild) 1.4140 + return; 1.4141 + 1.4142 + nsAutoRetainCocoaObject kungFuDeathGrip(self); 1.4143 + 1.4144 + float rotation = [anEvent rotation]; 1.4145 + 1.4146 + uint32_t msg; 1.4147 + switch (mGestureState) { 1.4148 + case eGestureState_StartGesture: 1.4149 + msg = NS_SIMPLE_GESTURE_ROTATE_START; 1.4150 + mGestureState = eGestureState_RotateGesture; 1.4151 + break; 1.4152 + 1.4153 + case eGestureState_RotateGesture: 1.4154 + msg = NS_SIMPLE_GESTURE_ROTATE_UPDATE; 1.4155 + break; 1.4156 + 1.4157 + case eGestureState_None: 1.4158 + case eGestureState_MagnifyGesture: 1.4159 + default: 1.4160 + return; 1.4161 + } 1.4162 + 1.4163 + // Setup the event. 1.4164 + WidgetSimpleGestureEvent geckoEvent(true, msg, mGeckoChild); 1.4165 + [self convertCocoaMouseEvent:anEvent toGeckoEvent:&geckoEvent]; 1.4166 + geckoEvent.delta = -rotation; 1.4167 + if (rotation > 0.0) { 1.4168 + geckoEvent.direction = nsIDOMSimpleGestureEvent::ROTATION_COUNTERCLOCKWISE; 1.4169 + } else { 1.4170 + geckoEvent.direction = nsIDOMSimpleGestureEvent::ROTATION_CLOCKWISE; 1.4171 + } 1.4172 + 1.4173 + // Send the event. 1.4174 + mGeckoChild->DispatchWindowEvent(geckoEvent); 1.4175 + 1.4176 + // Keep track of the cumulative rotation for the final "rotate" event. 1.4177 + mCumulativeRotation += rotation; 1.4178 + 1.4179 + NS_OBJC_END_TRY_ABORT_BLOCK; 1.4180 +} 1.4181 + 1.4182 +- (void)endGestureWithEvent:(NSEvent *)anEvent 1.4183 +{ 1.4184 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK; 1.4185 + 1.4186 + if (!anEvent || !mGeckoChild) { 1.4187 + // Clear the gestures state if we cannot send an event. 1.4188 + mGestureState = eGestureState_None; 1.4189 + mCumulativeMagnification = 0.0; 1.4190 + mCumulativeRotation = 0.0; 1.4191 + return; 1.4192 + } 1.4193 + 1.4194 + nsAutoRetainCocoaObject kungFuDeathGrip(self); 1.4195 + 1.4196 + switch (mGestureState) { 1.4197 + case eGestureState_MagnifyGesture: 1.4198 + { 1.4199 + // Setup the "magnify" event. 1.4200 + WidgetSimpleGestureEvent geckoEvent(true, NS_SIMPLE_GESTURE_MAGNIFY, 1.4201 + mGeckoChild); 1.4202 + geckoEvent.delta = mCumulativeMagnification; 1.4203 + [self convertCocoaMouseEvent:anEvent toGeckoEvent:&geckoEvent]; 1.4204 + 1.4205 + // Send the event. 1.4206 + mGeckoChild->DispatchWindowEvent(geckoEvent); 1.4207 + } 1.4208 + break; 1.4209 + 1.4210 + case eGestureState_RotateGesture: 1.4211 + { 1.4212 + // Setup the "rotate" event. 1.4213 + WidgetSimpleGestureEvent geckoEvent(true, NS_SIMPLE_GESTURE_ROTATE, 1.4214 + mGeckoChild); 1.4215 + [self convertCocoaMouseEvent:anEvent toGeckoEvent:&geckoEvent]; 1.4216 + geckoEvent.delta = -mCumulativeRotation; 1.4217 + if (mCumulativeRotation > 0.0) { 1.4218 + geckoEvent.direction = nsIDOMSimpleGestureEvent::ROTATION_COUNTERCLOCKWISE; 1.4219 + } else { 1.4220 + geckoEvent.direction = nsIDOMSimpleGestureEvent::ROTATION_CLOCKWISE; 1.4221 + } 1.4222 + 1.4223 + // Send the event. 1.4224 + mGeckoChild->DispatchWindowEvent(geckoEvent); 1.4225 + } 1.4226 + break; 1.4227 + 1.4228 + case eGestureState_None: 1.4229 + case eGestureState_StartGesture: 1.4230 + default: 1.4231 + break; 1.4232 + } 1.4233 + 1.4234 + // Clear the gestures state. 1.4235 + mGestureState = eGestureState_None; 1.4236 + mCumulativeMagnification = 0.0; 1.4237 + mCumulativeRotation = 0.0; 1.4238 + 1.4239 + NS_OBJC_END_TRY_ABORT_BLOCK; 1.4240 +} 1.4241 + 1.4242 ++ (BOOL)isLionSmartMagnifyEvent:(NSEvent*)anEvent 1.4243 +{ 1.4244 + /* 1.4245 + * On Lion, smart zoom events have type NSEventTypeGesture, subtype 0x16, 1.4246 + * whereas pinch zoom events have type NSEventTypeMagnify. So, use that to 1.4247 + * discriminate between the two. Smart zoom gestures do not call 1.4248 + * beginGestureWithEvent or endGestureWithEvent, so mGestureState is not 1.4249 + * changed. Documentation couldn't be found for the meaning of the subtype 1.4250 + * 0x16, but it will probably never change. See bug 863841. 1.4251 + */ 1.4252 + return nsCocoaFeatures::OnLionOrLater() && 1.4253 + !nsCocoaFeatures::OnMountainLionOrLater() && 1.4254 + [anEvent type] == NSEventTypeGesture && 1.4255 + [anEvent subtype] == 0x16; 1.4256 +} 1.4257 + 1.4258 +#ifdef __LP64__ 1.4259 +- (bool)sendSwipeEvent:(NSEvent*)aEvent 1.4260 + withKind:(uint32_t)aMsg 1.4261 + allowedDirections:(uint32_t*)aAllowedDirections 1.4262 + direction:(uint32_t)aDirection 1.4263 + delta:(double)aDelta 1.4264 +{ 1.4265 + if (!mGeckoChild) 1.4266 + return false; 1.4267 + 1.4268 + WidgetSimpleGestureEvent geckoEvent(true, aMsg, mGeckoChild); 1.4269 + geckoEvent.direction = aDirection; 1.4270 + geckoEvent.delta = aDelta; 1.4271 + geckoEvent.allowedDirections = *aAllowedDirections; 1.4272 + [self convertCocoaMouseEvent:aEvent toGeckoEvent:&geckoEvent]; 1.4273 + bool eventCancelled = mGeckoChild->DispatchWindowEvent(geckoEvent); 1.4274 + *aAllowedDirections = geckoEvent.allowedDirections; 1.4275 + return eventCancelled; // event cancelled == swipe should start 1.4276 +} 1.4277 + 1.4278 +- (void)sendSwipeEndEvent:(NSEvent *)anEvent 1.4279 + allowedDirections:(uint32_t)aAllowedDirections 1.4280 +{ 1.4281 + // Tear down animation overlay by sending a swipe end event. 1.4282 + uint32_t allowedDirectionsCopy = aAllowedDirections; 1.4283 + [self sendSwipeEvent:anEvent 1.4284 + withKind:NS_SIMPLE_GESTURE_SWIPE_END 1.4285 + allowedDirections:&allowedDirectionsCopy 1.4286 + direction:0 1.4287 + delta:0.0]; 1.4288 +} 1.4289 + 1.4290 +// Support fluid swipe tracking on OS X 10.7 and higher. We must be careful 1.4291 +// to only invoke this support on a two-finger gesture that really 1.4292 +// is a swipe (and not a scroll) -- in other words, the app is responsible 1.4293 +// for deciding which is which. But once the decision is made, the OS tracks 1.4294 +// the swipe until it has finished, and decides whether or not it succeeded. 1.4295 +// A horizontal swipe has the same functionality as the Back and Forward 1.4296 +// buttons. 1.4297 +// This method is partly based on Apple sample code available at 1.4298 +// developer.apple.com/library/mac/#releasenotes/Cocoa/AppKitOlderNotes.html 1.4299 +// (under Fluid Swipe Tracking API). 1.4300 +- (void)maybeTrackScrollEventAsSwipe:(NSEvent *)anEvent 1.4301 + scrollOverflowX:(double)anOverflowX 1.4302 + scrollOverflowY:(double)anOverflowY 1.4303 + viewPortIsOverscrolled:(BOOL)aViewPortIsOverscrolled 1.4304 +{ 1.4305 + if (!nsCocoaFeatures::OnLionOrLater()) { 1.4306 + return; 1.4307 + } 1.4308 + 1.4309 + // This method checks whether the AppleEnableSwipeNavigateWithScrolls global 1.4310 + // preference is set. If it isn't, fluid swipe tracking is disabled, and a 1.4311 + // horizontal two-finger gesture is always a scroll (even in Safari). This 1.4312 + // preference can't (currently) be set from the Preferences UI -- only using 1.4313 + // 'defaults write'. 1.4314 + if (![NSEvent isSwipeTrackingFromScrollEventsEnabled]) { 1.4315 + return; 1.4316 + } 1.4317 + 1.4318 + // We should only track scroll events as swipe if the viewport is being 1.4319 + // overscrolled. 1.4320 + if (!aViewPortIsOverscrolled) { 1.4321 + return; 1.4322 + } 1.4323 + 1.4324 + // Verify that this is a scroll wheel event with proper phase to be tracked 1.4325 + // by the OS. 1.4326 + if ([anEvent type] != NSScrollWheel || [anEvent phase] == NSEventPhaseNone) { 1.4327 + return; 1.4328 + } 1.4329 + 1.4330 + // Only initiate tracking if the user has tried to scroll past the edge of 1.4331 + // the current page (as indicated by 'anOverflowX' or 'anOverflowY' being 1.4332 + // non-zero). Gecko only sets WidgetMouseScrollEvent.scrollOverflow when it's 1.4333 + // processing NS_MOUSE_PIXEL_SCROLL events (not NS_MOUSE_SCROLL events). 1.4334 + if (anOverflowX == 0.0 && anOverflowY == 0.0) { 1.4335 + return; 1.4336 + } 1.4337 + 1.4338 + CGFloat deltaX, deltaY; 1.4339 + if ([anEvent hasPreciseScrollingDeltas]) { 1.4340 + deltaX = [anEvent scrollingDeltaX]; 1.4341 + deltaY = [anEvent scrollingDeltaY]; 1.4342 + } else { 1.4343 + return; 1.4344 + } 1.4345 + 1.4346 + uint32_t vDirs = (uint32_t)nsIDOMSimpleGestureEvent::DIRECTION_DOWN | 1.4347 + (uint32_t)nsIDOMSimpleGestureEvent::DIRECTION_UP; 1.4348 + uint32_t direction = 0; 1.4349 + 1.4350 + // Only initiate horizontal tracking for events whose horizontal element is 1.4351 + // at least eight times larger than its vertical element. This minimizes 1.4352 + // performance problems with vertical scrolls (by minimizing the possibility 1.4353 + // that they'll be misinterpreted as horizontal swipes), while still 1.4354 + // tolerating a small vertical element to a true horizontal swipe. The number 1.4355 + // '8' was arrived at by trial and error. 1.4356 + if (anOverflowX != 0.0 && deltaX != 0.0 && 1.4357 + fabsf(deltaX) > fabsf(deltaY) * 8) { 1.4358 + // Only initiate horizontal tracking for gestures that have just begun -- 1.4359 + // otherwise a scroll to one side of the page can have a swipe tacked on 1.4360 + // to it. 1.4361 + if ([anEvent phase] != NSEventPhaseBegan) { 1.4362 + return; 1.4363 + } 1.4364 + 1.4365 + if (deltaX < 0.0) { 1.4366 + direction = (uint32_t)nsIDOMSimpleGestureEvent::DIRECTION_RIGHT; 1.4367 + } else { 1.4368 + direction = (uint32_t)nsIDOMSimpleGestureEvent::DIRECTION_LEFT; 1.4369 + } 1.4370 + } 1.4371 + // Only initiate vertical tracking for events whose vertical element is 1.4372 + // at least two times larger than its horizontal element. This minimizes 1.4373 + // performance problems. The number '2' was arrived at by trial and error. 1.4374 + else if (anOverflowY != 0.0 && deltaY != 0.0 && 1.4375 + fabsf(deltaY) > fabsf(deltaX) * 2) { 1.4376 + if (deltaY < 0.0) { 1.4377 + direction = (uint32_t)nsIDOMSimpleGestureEvent::DIRECTION_DOWN; 1.4378 + } else { 1.4379 + direction = (uint32_t)nsIDOMSimpleGestureEvent::DIRECTION_UP; 1.4380 + } 1.4381 + 1.4382 + if ((mCurrentSwipeDir & vDirs) && (mCurrentSwipeDir != direction)) { 1.4383 + // If a swipe is currently being tracked kill it -- it's been interrupted 1.4384 + // by another gesture event. 1.4385 + if (mCancelSwipeAnimation && *mCancelSwipeAnimation == NO) { 1.4386 + *mCancelSwipeAnimation = YES; 1.4387 + mCancelSwipeAnimation = nil; 1.4388 + [self sendSwipeEndEvent:anEvent allowedDirections:0]; 1.4389 + } 1.4390 + return; 1.4391 + } 1.4392 + } else { 1.4393 + return; 1.4394 + } 1.4395 + 1.4396 + // Track the direction we're going in. 1.4397 + mCurrentSwipeDir = direction; 1.4398 + 1.4399 + uint32_t allowedDirections = 0; 1.4400 + // We're ready to start the animation. Tell Gecko about it, and at the same 1.4401 + // time ask it if it really wants to start an animation for this event. 1.4402 + // This event also reports back the directions that we can swipe in. 1.4403 + bool shouldStartSwipe = [self sendSwipeEvent:anEvent 1.4404 + withKind:NS_SIMPLE_GESTURE_SWIPE_START 1.4405 + allowedDirections:&allowedDirections 1.4406 + direction:direction 1.4407 + delta:0.0]; 1.4408 + 1.4409 + if (!shouldStartSwipe) { 1.4410 + return; 1.4411 + } 1.4412 + 1.4413 + // If a swipe is currently being tracked kill it -- it's been interrupted 1.4414 + // by another gesture event. 1.4415 + if (mCancelSwipeAnimation && *mCancelSwipeAnimation == NO) { 1.4416 + *mCancelSwipeAnimation = YES; 1.4417 + mCancelSwipeAnimation = nil; 1.4418 + } 1.4419 + 1.4420 + CGFloat min = 0.0; 1.4421 + CGFloat max = 0.0; 1.4422 + if (!(direction & vDirs)) { 1.4423 + min = (allowedDirections & nsIDOMSimpleGestureEvent::DIRECTION_RIGHT) ? 1.4424 + -1.0 : 0.0; 1.4425 + max = (allowedDirections & nsIDOMSimpleGestureEvent::DIRECTION_LEFT) ? 1.4426 + 1.0 : 0.0; 1.4427 + } 1.4428 + 1.4429 + __block BOOL animationCanceled = NO; 1.4430 + __block BOOL geckoSwipeEventSent = NO; 1.4431 + // At this point, anEvent is the first scroll wheel event in a two-finger 1.4432 + // horizontal gesture that we've decided to treat as a swipe. When we call 1.4433 + // [NSEvent trackSwipeEventWithOptions:...], the OS interprets all 1.4434 + // subsequent scroll wheel events that are part of this gesture as a swipe, 1.4435 + // and stops sending them to us. The OS calls the trackingHandler "block" 1.4436 + // multiple times, asynchronously (sometimes after [NSEvent 1.4437 + // maybeTrackScrollEventAsSwipe:...] has returned). The OS determines when 1.4438 + // the gesture has finished, and whether or not it was "successful" -- this 1.4439 + // information is passed to trackingHandler. We must be careful to only 1.4440 + // call [NSEvent maybeTrackScrollEventAsSwipe:...] on a "real" swipe -- 1.4441 + // otherwise two-finger scrolling performance will suffer significantly. 1.4442 + // Note that we use anEvent inside the block. This extends the lifetime of 1.4443 + // the anEvent object because it's retained by the block, see bug 682445. 1.4444 + // The block will release it when the block goes away at the end of the 1.4445 + // animation, or when the animation is canceled. 1.4446 + [anEvent trackSwipeEventWithOptions:NSEventSwipeTrackingLockDirection | 1.4447 + NSEventSwipeTrackingClampGestureAmount 1.4448 + dampenAmountThresholdMin:min 1.4449 + max:max 1.4450 + usingHandler:^(CGFloat gestureAmount, 1.4451 + NSEventPhase phase, 1.4452 + BOOL isComplete, 1.4453 + BOOL *stop) { 1.4454 + uint32_t allowedDirectionsCopy = allowedDirections; 1.4455 + // Since this tracking handler can be called asynchronously, mGeckoChild 1.4456 + // might have become NULL here (our child widget might have been 1.4457 + // destroyed). 1.4458 + // Checking for gestureAmount == 0.0 also works around bug 770626, which 1.4459 + // happens when DispatchWindowEvent() triggers a modal dialog, which spins 1.4460 + // the event loop and confuses the OS. This results in several re-entrant 1.4461 + // calls to this handler. 1.4462 + if (animationCanceled || !mGeckoChild || gestureAmount == 0.0) { 1.4463 + *stop = YES; 1.4464 + animationCanceled = YES; 1.4465 + if (gestureAmount == 0.0 || 1.4466 + ((direction & vDirs) && (direction != mCurrentSwipeDir))) { 1.4467 + if (mCancelSwipeAnimation) 1.4468 + *mCancelSwipeAnimation = YES; 1.4469 + mCancelSwipeAnimation = nil; 1.4470 + [self sendSwipeEndEvent:anEvent 1.4471 + allowedDirections:allowedDirectionsCopy]; 1.4472 + } 1.4473 + mCurrentSwipeDir = 0; 1.4474 + return; 1.4475 + } 1.4476 + 1.4477 + // Update animation overlay to match gestureAmount. 1.4478 + [self sendSwipeEvent:anEvent 1.4479 + withKind:NS_SIMPLE_GESTURE_SWIPE_UPDATE 1.4480 + allowedDirections:&allowedDirectionsCopy 1.4481 + direction:0.0 1.4482 + delta:gestureAmount]; 1.4483 + 1.4484 + if (phase == NSEventPhaseEnded && !geckoSwipeEventSent) { 1.4485 + // The result of the swipe is now known, so the main event can be sent. 1.4486 + // The animation might continue even after this event was sent, so 1.4487 + // don't tear down the animation overlay yet. 1.4488 + 1.4489 + uint32_t directionCopy = direction; 1.4490 + 1.4491 + // gestureAmount is documented to be '-1', '0' or '1' when isComplete 1.4492 + // is TRUE, but the docs don't say anything about its value at other 1.4493 + // times. However, tests show that, when phase == NSEventPhaseEnded, 1.4494 + // gestureAmount is negative when it will be '-1' at isComplete, and 1.4495 + // positive when it will be '1'. And phase is never equal to 1.4496 + // NSEventPhaseEnded when gestureAmount will be '0' at isComplete. 1.4497 + geckoSwipeEventSent = YES; 1.4498 + [self sendSwipeEvent:anEvent 1.4499 + withKind:NS_SIMPLE_GESTURE_SWIPE 1.4500 + allowedDirections:&allowedDirectionsCopy 1.4501 + direction:directionCopy 1.4502 + delta:0.0]; 1.4503 + } 1.4504 + 1.4505 + if (isComplete) { 1.4506 + [self sendSwipeEndEvent:anEvent allowedDirections:allowedDirectionsCopy]; 1.4507 + mCurrentSwipeDir = 0; 1.4508 + mCancelSwipeAnimation = nil; 1.4509 + } 1.4510 + }]; 1.4511 + 1.4512 + mCancelSwipeAnimation = &animationCanceled; 1.4513 +} 1.4514 +#endif // #ifdef __LP64__ 1.4515 + 1.4516 +- (void)setUsingOMTCompositor:(BOOL)aUseOMTC 1.4517 +{ 1.4518 + mUsingOMTCompositor = aUseOMTC; 1.4519 +} 1.4520 + 1.4521 + 1.4522 +// Returning NO from this method only disallows ordering on mousedown - in order 1.4523 +// to prevent it for mouseup too, we need to call [NSApp preventWindowOrdering] 1.4524 +// when handling the mousedown event. 1.4525 +- (BOOL)shouldDelayWindowOrderingForEvent:(NSEvent*)aEvent 1.4526 +{ 1.4527 + // Always using system-provided window ordering for normal windows. 1.4528 + if (![[self window] isKindOfClass:[PopupWindow class]]) 1.4529 + return NO; 1.4530 + 1.4531 + // Don't reorder when we don't have a parent window, like when we're a 1.4532 + // context menu or a tooltip. 1.4533 + return ![[self window] parentWindow]; 1.4534 +} 1.4535 + 1.4536 +- (void)mouseDown:(NSEvent*)theEvent 1.4537 +{ 1.4538 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK; 1.4539 + 1.4540 + if ([self shouldDelayWindowOrderingForEvent:theEvent]) { 1.4541 + [NSApp preventWindowOrdering]; 1.4542 + } 1.4543 + 1.4544 + // If we've already seen this event due to direct dispatch from menuForEvent: 1.4545 + // just bail; if not, remember it. 1.4546 + if (mLastMouseDownEvent == theEvent) { 1.4547 + [mLastMouseDownEvent release]; 1.4548 + mLastMouseDownEvent = nil; 1.4549 + return; 1.4550 + } 1.4551 + else { 1.4552 + [mLastMouseDownEvent release]; 1.4553 + mLastMouseDownEvent = [theEvent retain]; 1.4554 + } 1.4555 + 1.4556 + [gLastDragMouseDownEvent release]; 1.4557 + gLastDragMouseDownEvent = [theEvent retain]; 1.4558 + 1.4559 + // We need isClickThrough because at this point the window we're in might 1.4560 + // already have become main, so the check for isMainWindow in 1.4561 + // WindowAcceptsEvent isn't enough. It also has to check isClickThrough. 1.4562 + BOOL isClickThrough = (theEvent == mClickThroughMouseDownEvent); 1.4563 + [mClickThroughMouseDownEvent release]; 1.4564 + mClickThroughMouseDownEvent = nil; 1.4565 + 1.4566 + nsAutoRetainCocoaObject kungFuDeathGrip(self); 1.4567 + 1.4568 + if ([self maybeRollup:theEvent] || 1.4569 + !ChildViewMouseTracker::WindowAcceptsEvent([self window], theEvent, self, isClickThrough)) { 1.4570 + // Remember blocking because that means we want to block mouseup as well. 1.4571 + mBlockedLastMouseDown = YES; 1.4572 + return; 1.4573 + } 1.4574 + 1.4575 +#if USE_CLICK_HOLD_CONTEXTMENU 1.4576 + // fire off timer to check for click-hold after two seconds. retains |theEvent| 1.4577 + [self performSelector:@selector(clickHoldCallback:) withObject:theEvent afterDelay:2.0]; 1.4578 +#endif 1.4579 + 1.4580 + // in order to send gecko events we'll need a gecko widget 1.4581 + if (!mGeckoChild) 1.4582 + return; 1.4583 + 1.4584 + NSUInteger modifierFlags = [theEvent modifierFlags]; 1.4585 + 1.4586 + WidgetMouseEvent geckoEvent(true, NS_MOUSE_BUTTON_DOWN, mGeckoChild, 1.4587 + WidgetMouseEvent::eReal); 1.4588 + [self convertCocoaMouseEvent:theEvent toGeckoEvent:&geckoEvent]; 1.4589 + 1.4590 + NSInteger clickCount = [theEvent clickCount]; 1.4591 + if (mBlockedLastMouseDown && clickCount > 1) { 1.4592 + // Don't send a double click if the first click of the double click was 1.4593 + // blocked. 1.4594 + clickCount--; 1.4595 + } 1.4596 + geckoEvent.clickCount = clickCount; 1.4597 + 1.4598 + if (modifierFlags & NSControlKeyMask) 1.4599 + geckoEvent.button = WidgetMouseEvent::eRightButton; 1.4600 + else 1.4601 + geckoEvent.button = WidgetMouseEvent::eLeftButton; 1.4602 + 1.4603 + // Create event for use by plugins. 1.4604 + // This is going to our child view so we don't need to look up the destination 1.4605 + // event type. 1.4606 + NPCocoaEvent cocoaEvent; 1.4607 + ChildViewMouseTracker::AttachPluginEvent(geckoEvent, self, theEvent, 1.4608 + NPCocoaEventMouseDown, 1.4609 + &cocoaEvent); 1.4610 + // Don't lose possible changes made above to clickCount 1.4611 + cocoaEvent.data.mouse.clickCount = clickCount; 1.4612 + 1.4613 + mGeckoChild->DispatchWindowEvent(geckoEvent); 1.4614 + mBlockedLastMouseDown = NO; 1.4615 + 1.4616 + // XXX maybe call markedTextSelectionChanged:client: here? 1.4617 + 1.4618 + NS_OBJC_END_TRY_ABORT_BLOCK; 1.4619 +} 1.4620 + 1.4621 +- (void)mouseUp:(NSEvent *)theEvent 1.4622 +{ 1.4623 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK; 1.4624 + 1.4625 + if (!mGeckoChild || mBlockedLastMouseDown) 1.4626 + return; 1.4627 + 1.4628 + nsAutoRetainCocoaObject kungFuDeathGrip(self); 1.4629 + 1.4630 + NPCocoaEvent cocoaEvent; 1.4631 + 1.4632 + WidgetMouseEvent geckoEvent(true, NS_MOUSE_BUTTON_UP, mGeckoChild, 1.4633 + WidgetMouseEvent::eReal); 1.4634 + [self convertCocoaMouseEvent:theEvent toGeckoEvent:&geckoEvent]; 1.4635 + if ([theEvent modifierFlags] & NSControlKeyMask) 1.4636 + geckoEvent.button = WidgetMouseEvent::eRightButton; 1.4637 + else 1.4638 + geckoEvent.button = WidgetMouseEvent::eLeftButton; 1.4639 + 1.4640 + // Create event for use by plugins. 1.4641 + // This is going to our child view so we don't need to look up the destination 1.4642 + // event type. 1.4643 + ChildViewMouseTracker::AttachPluginEvent(geckoEvent, self, theEvent, 1.4644 + NPCocoaEventMouseUp, 1.4645 + &cocoaEvent); 1.4646 + 1.4647 + // This might destroy our widget (and null out mGeckoChild). 1.4648 + bool defaultPrevented = mGeckoChild->DispatchWindowEvent(geckoEvent); 1.4649 + 1.4650 + // Check to see if we are double-clicking in the titlebar. 1.4651 + CGFloat locationInTitlebar = [[self window] frame].size.height - [theEvent locationInWindow].y; 1.4652 + if (!defaultPrevented && [theEvent clickCount] == 2 && 1.4653 + [[self window] isMovableByWindowBackground] && 1.4654 + [self shouldMinimizeOnTitlebarDoubleClick] && 1.4655 + [[self window] isKindOfClass:[ToolbarWindow class]] && 1.4656 + (locationInTitlebar < [(ToolbarWindow*)[self window] titlebarHeight] || 1.4657 + locationInTitlebar < [(ToolbarWindow*)[self window] unifiedToolbarHeight])) { 1.4658 + 1.4659 + NSButton *minimizeButton = [[self window] standardWindowButton:NSWindowMiniaturizeButton]; 1.4660 + [minimizeButton performClick:self]; 1.4661 + } 1.4662 + 1.4663 + // If our mouse-up event's location is over some other object (as might 1.4664 + // happen if it came at the end of a dragging operation), also send our 1.4665 + // Gecko frame a mouse-exit event. 1.4666 + if (mGeckoChild && mIsPluginView) { 1.4667 + ChildViewMouseTracker::ReEvaluateMouseEnterState(theEvent, self); 1.4668 + } 1.4669 + 1.4670 + NS_OBJC_END_TRY_ABORT_BLOCK; 1.4671 +} 1.4672 + 1.4673 +- (void)sendMouseEnterOrExitEvent:(NSEvent*)aEvent 1.4674 + enter:(BOOL)aEnter 1.4675 + type:(WidgetMouseEvent::exitType)aType 1.4676 +{ 1.4677 + if (!mGeckoChild) 1.4678 + return; 1.4679 + 1.4680 + NSPoint windowEventLocation = nsCocoaUtils::EventLocationForWindow(aEvent, [self window]); 1.4681 + NSPoint localEventLocation = [self convertPoint:windowEventLocation fromView:nil]; 1.4682 + 1.4683 + uint32_t msg = aEnter ? NS_MOUSE_ENTER : NS_MOUSE_EXIT; 1.4684 + WidgetMouseEvent event(true, msg, mGeckoChild, WidgetMouseEvent::eReal); 1.4685 + event.refPoint = LayoutDeviceIntPoint::FromUntyped( 1.4686 + mGeckoChild->CocoaPointsToDevPixels(localEventLocation)); 1.4687 + 1.4688 + // Create event for use by plugins. 1.4689 + // This is going to our child view so we don't need to look up the destination 1.4690 + // event type. 1.4691 + NPCocoaEvent cocoaEvent; 1.4692 + ChildViewMouseTracker::AttachPluginEvent(event, self, aEvent, 1.4693 + (msg == NS_MOUSE_ENTER) ? 1.4694 + NPCocoaEventMouseEntered : NPCocoaEventMouseExited, 1.4695 + &cocoaEvent); 1.4696 + 1.4697 + event.exit = aType; 1.4698 + 1.4699 + nsEventStatus status; // ignored 1.4700 + mGeckoChild->DispatchEvent(&event, status); 1.4701 +} 1.4702 + 1.4703 +- (void)updateWindowDraggableStateOnMouseMove:(NSEvent*)theEvent 1.4704 +{ 1.4705 + if (!theEvent || !mGeckoChild) { 1.4706 + return; 1.4707 + } 1.4708 + 1.4709 + nsCocoaWindow* windowWidget = mGeckoChild->GetXULWindowWidget(); 1.4710 + if (!windowWidget) { 1.4711 + return; 1.4712 + } 1.4713 + 1.4714 + // We assume later on that sending a hit test event won't cause widget destruction. 1.4715 + WidgetMouseEvent hitTestEvent(true, NS_MOUSE_MOZHITTEST, mGeckoChild, 1.4716 + WidgetMouseEvent::eReal); 1.4717 + [self convertCocoaMouseEvent:theEvent toGeckoEvent:&hitTestEvent]; 1.4718 + bool result = mGeckoChild->DispatchWindowEvent(hitTestEvent); 1.4719 + 1.4720 + [windowWidget->GetCocoaWindow() setMovableByWindowBackground:result]; 1.4721 +} 1.4722 + 1.4723 +- (void)handleMouseMoved:(NSEvent*)theEvent 1.4724 +{ 1.4725 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK; 1.4726 + 1.4727 + if (!mGeckoChild) 1.4728 + return; 1.4729 + 1.4730 + WidgetMouseEvent geckoEvent(true, NS_MOUSE_MOVE, mGeckoChild, 1.4731 + WidgetMouseEvent::eReal); 1.4732 + [self convertCocoaMouseEvent:theEvent toGeckoEvent:&geckoEvent]; 1.4733 + 1.4734 + // Create event for use by plugins. 1.4735 + // This is going to our child view so we don't need to look up the destination 1.4736 + // event type. 1.4737 + NPCocoaEvent cocoaEvent; 1.4738 + ChildViewMouseTracker::AttachPluginEvent(geckoEvent, self, theEvent, 1.4739 + NPCocoaEventMouseMoved, 1.4740 + &cocoaEvent); 1.4741 + mGeckoChild->DispatchWindowEvent(geckoEvent); 1.4742 + 1.4743 + NS_OBJC_END_TRY_ABORT_BLOCK; 1.4744 +} 1.4745 + 1.4746 +- (void)mouseDragged:(NSEvent*)theEvent 1.4747 +{ 1.4748 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK; 1.4749 + 1.4750 + if (!mGeckoChild) 1.4751 + return; 1.4752 + 1.4753 + gLastDragView = self; 1.4754 + 1.4755 + NPCocoaEvent cocoaEvent; 1.4756 + 1.4757 + WidgetMouseEvent geckoEvent(true, NS_MOUSE_MOVE, mGeckoChild, 1.4758 + WidgetMouseEvent::eReal); 1.4759 + [self convertCocoaMouseEvent:theEvent toGeckoEvent:&geckoEvent]; 1.4760 + 1.4761 + // create event for use by plugins 1.4762 + ChildViewMouseTracker::AttachPluginEvent(geckoEvent, self, theEvent, 1.4763 + NPCocoaEventMouseDragged, 1.4764 + &cocoaEvent); 1.4765 + 1.4766 + mGeckoChild->DispatchWindowEvent(geckoEvent); 1.4767 + 1.4768 + // Note, sending the above event might have destroyed our widget since we didn't retain. 1.4769 + // Fine so long as we don't access any local variables from here on. 1.4770 + gLastDragView = nil; 1.4771 + 1.4772 + // XXX maybe call markedTextSelectionChanged:client: here? 1.4773 + 1.4774 + NS_OBJC_END_TRY_ABORT_BLOCK; 1.4775 +} 1.4776 + 1.4777 +- (void)rightMouseDown:(NSEvent *)theEvent 1.4778 +{ 1.4779 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK; 1.4780 + 1.4781 + nsAutoRetainCocoaObject kungFuDeathGrip(self); 1.4782 + 1.4783 + [self maybeRollup:theEvent]; 1.4784 + if (!mGeckoChild) 1.4785 + return; 1.4786 + 1.4787 + // The right mouse went down, fire off a right mouse down event to gecko 1.4788 + WidgetMouseEvent geckoEvent(true, NS_MOUSE_BUTTON_DOWN, mGeckoChild, 1.4789 + WidgetMouseEvent::eReal); 1.4790 + [self convertCocoaMouseEvent:theEvent toGeckoEvent:&geckoEvent]; 1.4791 + geckoEvent.button = WidgetMouseEvent::eRightButton; 1.4792 + geckoEvent.clickCount = [theEvent clickCount]; 1.4793 + 1.4794 + // create event for use by plugins 1.4795 + NPCocoaEvent cocoaEvent; 1.4796 + ChildViewMouseTracker::AttachPluginEvent(geckoEvent, self, theEvent, 1.4797 + NPCocoaEventMouseDown, 1.4798 + &cocoaEvent); 1.4799 + 1.4800 + mGeckoChild->DispatchWindowEvent(geckoEvent); 1.4801 + if (!mGeckoChild) 1.4802 + return; 1.4803 + 1.4804 + // Let the superclass do the context menu stuff. 1.4805 + [super rightMouseDown:theEvent]; 1.4806 + 1.4807 + NS_OBJC_END_TRY_ABORT_BLOCK; 1.4808 +} 1.4809 + 1.4810 +- (void)rightMouseUp:(NSEvent *)theEvent 1.4811 +{ 1.4812 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK; 1.4813 + 1.4814 + if (!mGeckoChild) 1.4815 + return; 1.4816 + 1.4817 + NPCocoaEvent cocoaEvent; 1.4818 + 1.4819 + WidgetMouseEvent geckoEvent(true, NS_MOUSE_BUTTON_UP, mGeckoChild, 1.4820 + WidgetMouseEvent::eReal); 1.4821 + [self convertCocoaMouseEvent:theEvent toGeckoEvent:&geckoEvent]; 1.4822 + geckoEvent.button = WidgetMouseEvent::eRightButton; 1.4823 + geckoEvent.clickCount = [theEvent clickCount]; 1.4824 + 1.4825 + // create event for use by plugins 1.4826 + ChildViewMouseTracker::AttachPluginEvent(geckoEvent, self, theEvent, 1.4827 + NPCocoaEventMouseUp, 1.4828 + &cocoaEvent); 1.4829 + 1.4830 + nsAutoRetainCocoaObject kungFuDeathGrip(self); 1.4831 + mGeckoChild->DispatchWindowEvent(geckoEvent); 1.4832 + 1.4833 + // If our mouse-up event's location is over some other object (as might 1.4834 + // happen if it came at the end of a dragging operation), also send our 1.4835 + // Gecko frame a mouse-exit event. 1.4836 + if (mGeckoChild && mIsPluginView) { 1.4837 + ChildViewMouseTracker::ReEvaluateMouseEnterState(theEvent, self); 1.4838 + } 1.4839 + 1.4840 + NS_OBJC_END_TRY_ABORT_BLOCK; 1.4841 +} 1.4842 + 1.4843 +- (void)rightMouseDragged:(NSEvent*)theEvent 1.4844 +{ 1.4845 + if (!mGeckoChild) 1.4846 + return; 1.4847 + 1.4848 + WidgetMouseEvent geckoEvent(true, NS_MOUSE_MOVE, mGeckoChild, 1.4849 + WidgetMouseEvent::eReal); 1.4850 + [self convertCocoaMouseEvent:theEvent toGeckoEvent:&geckoEvent]; 1.4851 + geckoEvent.button = WidgetMouseEvent::eRightButton; 1.4852 + 1.4853 + // create event for use by plugins 1.4854 + NPCocoaEvent cocoaEvent; 1.4855 + ChildViewMouseTracker::AttachPluginEvent(geckoEvent, self, theEvent, 1.4856 + NPCocoaEventMouseDragged, 1.4857 + &cocoaEvent); 1.4858 + 1.4859 + // send event into Gecko by going directly to the 1.4860 + // the widget. 1.4861 + mGeckoChild->DispatchWindowEvent(geckoEvent); 1.4862 +} 1.4863 + 1.4864 +- (void)otherMouseDown:(NSEvent *)theEvent 1.4865 +{ 1.4866 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK; 1.4867 + 1.4868 + nsAutoRetainCocoaObject kungFuDeathGrip(self); 1.4869 + 1.4870 + if ([self maybeRollup:theEvent] || 1.4871 + !ChildViewMouseTracker::WindowAcceptsEvent([self window], theEvent, self)) 1.4872 + return; 1.4873 + 1.4874 + if (!mGeckoChild) 1.4875 + return; 1.4876 + 1.4877 + WidgetMouseEvent geckoEvent(true, NS_MOUSE_BUTTON_DOWN, mGeckoChild, 1.4878 + WidgetMouseEvent::eReal); 1.4879 + [self convertCocoaMouseEvent:theEvent toGeckoEvent:&geckoEvent]; 1.4880 + geckoEvent.button = WidgetMouseEvent::eMiddleButton; 1.4881 + geckoEvent.clickCount = [theEvent clickCount]; 1.4882 + 1.4883 + // create event for use by plugins 1.4884 + NPCocoaEvent cocoaEvent; 1.4885 + ChildViewMouseTracker::AttachPluginEvent(geckoEvent, self, theEvent, 1.4886 + NPCocoaEventMouseDown, 1.4887 + &cocoaEvent); 1.4888 + 1.4889 + mGeckoChild->DispatchWindowEvent(geckoEvent); 1.4890 + 1.4891 + NS_OBJC_END_TRY_ABORT_BLOCK; 1.4892 +} 1.4893 + 1.4894 +- (void)otherMouseUp:(NSEvent *)theEvent 1.4895 +{ 1.4896 + if (!mGeckoChild) 1.4897 + return; 1.4898 + 1.4899 + WidgetMouseEvent geckoEvent(true, NS_MOUSE_BUTTON_UP, mGeckoChild, 1.4900 + WidgetMouseEvent::eReal); 1.4901 + [self convertCocoaMouseEvent:theEvent toGeckoEvent:&geckoEvent]; 1.4902 + geckoEvent.button = WidgetMouseEvent::eMiddleButton; 1.4903 + 1.4904 + // create event for use by plugins 1.4905 + NPCocoaEvent cocoaEvent; 1.4906 + ChildViewMouseTracker::AttachPluginEvent(geckoEvent, self, theEvent, 1.4907 + NPCocoaEventMouseUp, 1.4908 + &cocoaEvent); 1.4909 + 1.4910 + nsAutoRetainCocoaObject kungFuDeathGrip(self); 1.4911 + mGeckoChild->DispatchWindowEvent(geckoEvent); 1.4912 + 1.4913 + // If our mouse-up event's location is over some other object (as might 1.4914 + // happen if it came at the end of a dragging operation), also send our 1.4915 + // Gecko frame a mouse-exit event. 1.4916 + if (mGeckoChild && mIsPluginView) { 1.4917 + ChildViewMouseTracker::ReEvaluateMouseEnterState(theEvent, self); 1.4918 + } 1.4919 +} 1.4920 + 1.4921 +- (void)otherMouseDragged:(NSEvent*)theEvent 1.4922 +{ 1.4923 + if (!mGeckoChild) 1.4924 + return; 1.4925 + 1.4926 + WidgetMouseEvent geckoEvent(true, NS_MOUSE_MOVE, mGeckoChild, 1.4927 + WidgetMouseEvent::eReal); 1.4928 + [self convertCocoaMouseEvent:theEvent toGeckoEvent:&geckoEvent]; 1.4929 + geckoEvent.button = WidgetMouseEvent::eMiddleButton; 1.4930 + 1.4931 + // create event for use by plugins 1.4932 + NPCocoaEvent cocoaEvent; 1.4933 + ChildViewMouseTracker::AttachPluginEvent(geckoEvent, self, theEvent, 1.4934 + NPCocoaEventMouseDragged, 1.4935 + &cocoaEvent); 1.4936 + 1.4937 + // send event into Gecko by going directly to the 1.4938 + // the widget. 1.4939 + mGeckoChild->DispatchWindowEvent(geckoEvent); 1.4940 +} 1.4941 + 1.4942 +static int32_t RoundUp(double aDouble) 1.4943 +{ 1.4944 + return aDouble < 0 ? static_cast<int32_t>(floor(aDouble)) : 1.4945 + static_cast<int32_t>(ceil(aDouble)); 1.4946 +} 1.4947 + 1.4948 +- (void)sendWheelStartOrStop:(uint32_t)msg forEvent:(NSEvent *)theEvent 1.4949 +{ 1.4950 + WidgetWheelEvent wheelEvent(true, msg, mGeckoChild); 1.4951 + [self convertCocoaMouseWheelEvent:theEvent toGeckoEvent:&wheelEvent]; 1.4952 + mExpectingWheelStop = (msg == NS_WHEEL_START); 1.4953 + mGeckoChild->DispatchWindowEvent(wheelEvent); 1.4954 +} 1.4955 + 1.4956 +- (void)sendWheelCondition:(BOOL)condition first:(uint32_t)first second:(uint32_t)second forEvent:(NSEvent *)theEvent 1.4957 +{ 1.4958 + if (mExpectingWheelStop == condition) { 1.4959 + [self sendWheelStartOrStop:first forEvent:theEvent]; 1.4960 + } 1.4961 + [self sendWheelStartOrStop:second forEvent:theEvent]; 1.4962 +} 1.4963 + 1.4964 +- (void)scrollWheel:(NSEvent*)theEvent 1.4965 +{ 1.4966 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK; 1.4967 + 1.4968 + nsAutoRetainCocoaObject kungFuDeathGrip(self); 1.4969 + 1.4970 + ChildViewMouseTracker::MouseScrolled(theEvent); 1.4971 + 1.4972 + if ([self maybeRollup:theEvent]) { 1.4973 + return; 1.4974 + } 1.4975 + 1.4976 + if (!mGeckoChild) { 1.4977 + return; 1.4978 + } 1.4979 + 1.4980 + if (nsCocoaFeatures::OnLionOrLater()) { 1.4981 + NSEventPhase phase = [theEvent phase]; 1.4982 + // Fire NS_WHEEL_START/STOP events when 2 fingers touch/release the touchpad. 1.4983 + if (phase & NSEventPhaseMayBegin) { 1.4984 + [self sendWheelCondition:YES first:NS_WHEEL_STOP second:NS_WHEEL_START forEvent:theEvent]; 1.4985 + return; 1.4986 + } 1.4987 + 1.4988 + if (phase & (NSEventPhaseEnded | NSEventPhaseCancelled)) { 1.4989 + [self sendWheelCondition:NO first:NS_WHEEL_START second:NS_WHEEL_STOP forEvent:theEvent]; 1.4990 + return; 1.4991 + } 1.4992 + } 1.4993 + 1.4994 + WidgetWheelEvent wheelEvent(true, NS_WHEEL_WHEEL, mGeckoChild); 1.4995 + [self convertCocoaMouseWheelEvent:theEvent toGeckoEvent:&wheelEvent]; 1.4996 + 1.4997 + wheelEvent.lineOrPageDeltaX = RoundUp(-[theEvent deltaX]); 1.4998 + wheelEvent.lineOrPageDeltaY = RoundUp(-[theEvent deltaY]); 1.4999 + 1.5000 + if (wheelEvent.deltaMode == nsIDOMWheelEvent::DOM_DELTA_PIXEL) { 1.5001 + // Some scrolling devices supports pixel scrolling, e.g. a Macbook 1.5002 + // touchpad or a Mighty Mouse. On those devices, [theEvent deviceDeltaX/Y] 1.5003 + // contains the amount of pixels to scroll. Since Lion this has changed 1.5004 + // to [theEvent scrollingDeltaX/Y]. 1.5005 + double scale = mGeckoChild->BackingScaleFactor(); 1.5006 + if ([theEvent respondsToSelector:@selector(scrollingDeltaX)]) { 1.5007 + wheelEvent.deltaX = -[theEvent scrollingDeltaX] * scale; 1.5008 + wheelEvent.deltaY = -[theEvent scrollingDeltaY] * scale; 1.5009 + } else { 1.5010 + wheelEvent.deltaX = -[theEvent deviceDeltaX] * scale; 1.5011 + wheelEvent.deltaY = -[theEvent deviceDeltaY] * scale; 1.5012 + } 1.5013 + } else { 1.5014 + wheelEvent.deltaX = -[theEvent deltaX]; 1.5015 + wheelEvent.deltaY = -[theEvent deltaY]; 1.5016 + } 1.5017 + 1.5018 + // TODO: We should not set deltaZ for now because we're not sure if we should 1.5019 + // revert the sign. 1.5020 + // wheelEvent.deltaZ = [theEvent deltaZ]; 1.5021 + 1.5022 + if (!wheelEvent.deltaX && !wheelEvent.deltaY && !wheelEvent.deltaZ) { 1.5023 + // No sense in firing off a Gecko event. 1.5024 + return; 1.5025 + } 1.5026 + 1.5027 + NPCocoaEvent cocoaEvent; 1.5028 + ChildViewMouseTracker::AttachPluginEvent(wheelEvent, self, theEvent, 1.5029 + NPCocoaEventScrollWheel, 1.5030 + &cocoaEvent); 1.5031 + 1.5032 + mGeckoChild->DispatchWindowEvent(wheelEvent); 1.5033 + if (!mGeckoChild) { 1.5034 + return; 1.5035 + } 1.5036 + 1.5037 +#ifdef __LP64__ 1.5038 + // overflowDeltaX and overflowDeltaY tell us when the user has tried to 1.5039 + // scroll past the edge of a page (in those cases it's non-zero). 1.5040 + if ((wheelEvent.deltaMode == nsIDOMWheelEvent::DOM_DELTA_PIXEL) && 1.5041 + (wheelEvent.deltaX != 0.0 || wheelEvent.deltaY != 0.0)) { 1.5042 + [self maybeTrackScrollEventAsSwipe:theEvent 1.5043 + scrollOverflowX:wheelEvent.overflowDeltaX 1.5044 + scrollOverflowY:wheelEvent.overflowDeltaY 1.5045 + viewPortIsOverscrolled:wheelEvent.mViewPortIsOverscrolled]; 1.5046 + } 1.5047 +#endif // #ifdef __LP64__ 1.5048 + 1.5049 + NS_OBJC_END_TRY_ABORT_BLOCK; 1.5050 +} 1.5051 + 1.5052 +-(NSMenu*)menuForEvent:(NSEvent*)theEvent 1.5053 +{ 1.5054 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; 1.5055 + 1.5056 + if (!mGeckoChild || [self isPluginView]) 1.5057 + return nil; 1.5058 + 1.5059 + nsAutoRetainCocoaObject kungFuDeathGrip(self); 1.5060 + 1.5061 + [self maybeRollup:theEvent]; 1.5062 + if (!mGeckoChild) 1.5063 + return nil; 1.5064 + 1.5065 + // Cocoa doesn't always dispatch a mouseDown: for a control-click event, 1.5066 + // depends on what we return from menuForEvent:. Gecko always expects one 1.5067 + // and expects the mouse down event before the context menu event, so 1.5068 + // get that event sent first if this is a left mouse click. 1.5069 + if ([theEvent type] == NSLeftMouseDown) { 1.5070 + [self mouseDown:theEvent]; 1.5071 + if (!mGeckoChild) 1.5072 + return nil; 1.5073 + } 1.5074 + 1.5075 + WidgetMouseEvent geckoEvent(true, NS_CONTEXTMENU, mGeckoChild, 1.5076 + WidgetMouseEvent::eReal); 1.5077 + [self convertCocoaMouseEvent:theEvent toGeckoEvent:&geckoEvent]; 1.5078 + geckoEvent.button = WidgetMouseEvent::eRightButton; 1.5079 + mGeckoChild->DispatchWindowEvent(geckoEvent); 1.5080 + if (!mGeckoChild) 1.5081 + return nil; 1.5082 + 1.5083 + [self maybeInitContextMenuTracking]; 1.5084 + 1.5085 + // Go up our view chain to fetch the correct menu to return. 1.5086 + return [self contextMenu]; 1.5087 + 1.5088 + NS_OBJC_END_TRY_ABORT_BLOCK_NIL; 1.5089 +} 1.5090 + 1.5091 +- (NSMenu*)contextMenu 1.5092 +{ 1.5093 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; 1.5094 + 1.5095 + NSView* superView = [self superview]; 1.5096 + if ([superView respondsToSelector:@selector(contextMenu)]) 1.5097 + return [(NSView<mozView>*)superView contextMenu]; 1.5098 + 1.5099 + return nil; 1.5100 + 1.5101 + NS_OBJC_END_TRY_ABORT_BLOCK_NIL; 1.5102 +} 1.5103 + 1.5104 +- (void) convertCocoaMouseWheelEvent:(NSEvent*)aMouseEvent 1.5105 + toGeckoEvent:(WidgetWheelEvent*)outWheelEvent 1.5106 +{ 1.5107 + [self convertCocoaMouseEvent:aMouseEvent toGeckoEvent:outWheelEvent]; 1.5108 + outWheelEvent->deltaMode = 1.5109 + Preferences::GetBool("mousewheel.enable_pixel_scrolling", true) ? 1.5110 + nsIDOMWheelEvent::DOM_DELTA_PIXEL : nsIDOMWheelEvent::DOM_DELTA_LINE; 1.5111 + 1.5112 + // Calling deviceDeltaX or deviceDeltaY on theEvent will trigger a Cocoa 1.5113 + // assertion and an Objective-C NSInternalInconsistencyException if the 1.5114 + // underlying "Carbon" event doesn't contain pixel scrolling information. 1.5115 + // For these events, carbonEventKind is kEventMouseWheelMoved instead of 1.5116 + // kEventMouseScroll. 1.5117 + if (outWheelEvent->deltaMode == nsIDOMWheelEvent::DOM_DELTA_PIXEL) { 1.5118 + EventRef theCarbonEvent = [aMouseEvent _eventRef]; 1.5119 + UInt32 carbonEventKind = theCarbonEvent ? ::GetEventKind(theCarbonEvent) : 0; 1.5120 + if (carbonEventKind != kEventMouseScroll) { 1.5121 + outWheelEvent->deltaMode = nsIDOMWheelEvent::DOM_DELTA_LINE; 1.5122 + } 1.5123 + } 1.5124 + outWheelEvent->isMomentum = nsCocoaUtils::IsMomentumScrollEvent(aMouseEvent); 1.5125 +} 1.5126 + 1.5127 +- (void) convertCocoaMouseEvent:(NSEvent*)aMouseEvent 1.5128 + toGeckoEvent:(WidgetInputEvent*)outGeckoEvent 1.5129 +{ 1.5130 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK; 1.5131 + 1.5132 + NS_ASSERTION(outGeckoEvent, "convertCocoaMouseEvent:toGeckoEvent: requires non-null aoutGeckoEvent"); 1.5133 + if (!outGeckoEvent) 1.5134 + return; 1.5135 + 1.5136 + nsCocoaUtils::InitInputEvent(*outGeckoEvent, aMouseEvent); 1.5137 + 1.5138 + // convert point to view coordinate system 1.5139 + NSPoint locationInWindow = nsCocoaUtils::EventLocationForWindow(aMouseEvent, [self window]); 1.5140 + NSPoint localPoint = [self convertPoint:locationInWindow fromView:nil]; 1.5141 + 1.5142 + outGeckoEvent->refPoint = LayoutDeviceIntPoint::FromUntyped( 1.5143 + mGeckoChild->CocoaPointsToDevPixels(localPoint)); 1.5144 + 1.5145 + WidgetMouseEventBase* mouseEvent = outGeckoEvent->AsMouseEventBase(); 1.5146 + mouseEvent->buttons = 0; 1.5147 + NSUInteger mouseButtons = [NSEvent pressedMouseButtons]; 1.5148 + 1.5149 + if (mouseButtons & 0x01) { 1.5150 + mouseEvent->buttons |= WidgetMouseEvent::eLeftButtonFlag; 1.5151 + } 1.5152 + if (mouseButtons & 0x02) { 1.5153 + mouseEvent->buttons |= WidgetMouseEvent::eRightButtonFlag; 1.5154 + } 1.5155 + if (mouseButtons & 0x04) { 1.5156 + mouseEvent->buttons |= WidgetMouseEvent::eMiddleButtonFlag; 1.5157 + } 1.5158 + if (mouseButtons & 0x08) { 1.5159 + mouseEvent->buttons |= WidgetMouseEvent::e4thButtonFlag; 1.5160 + } 1.5161 + if (mouseButtons & 0x10) { 1.5162 + mouseEvent->buttons |= WidgetMouseEvent::e5thButtonFlag; 1.5163 + } 1.5164 + 1.5165 + switch ([aMouseEvent type]) { 1.5166 + case NSLeftMouseDown: 1.5167 + case NSLeftMouseUp: 1.5168 + case NSLeftMouseDragged: 1.5169 + case NSRightMouseDown: 1.5170 + case NSRightMouseUp: 1.5171 + case NSRightMouseDragged: 1.5172 + case NSOtherMouseDown: 1.5173 + case NSOtherMouseUp: 1.5174 + case NSOtherMouseDragged: 1.5175 + if ([aMouseEvent subtype] == NSTabletPointEventSubtype) { 1.5176 + mouseEvent->pressure = [aMouseEvent pressure]; 1.5177 + } 1.5178 + break; 1.5179 + } 1.5180 + 1.5181 + NS_OBJC_END_TRY_ABORT_BLOCK; 1.5182 +} 1.5183 + 1.5184 + 1.5185 +#pragma mark - 1.5186 +// NSTextInput implementation 1.5187 + 1.5188 +- (void)insertText:(id)insertString 1.5189 +{ 1.5190 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK; 1.5191 + 1.5192 + NS_ENSURE_TRUE_VOID(mGeckoChild); 1.5193 + 1.5194 + nsAutoRetainCocoaObject kungFuDeathGrip(self); 1.5195 + 1.5196 + NSAttributedString* attrStr; 1.5197 + if ([insertString isKindOfClass:[NSAttributedString class]]) { 1.5198 + attrStr = static_cast<NSAttributedString*>(insertString); 1.5199 + } else { 1.5200 + attrStr = 1.5201 + [[[NSAttributedString alloc] initWithString:insertString] autorelease]; 1.5202 + } 1.5203 + 1.5204 + mTextInputHandler->InsertText(attrStr); 1.5205 + 1.5206 + NS_OBJC_END_TRY_ABORT_BLOCK; 1.5207 +} 1.5208 + 1.5209 +- (void)insertNewline:(id)sender 1.5210 +{ 1.5211 + [self insertText:@"\n"]; 1.5212 +} 1.5213 + 1.5214 +- (void) doCommandBySelector:(SEL)aSelector 1.5215 +{ 1.5216 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK; 1.5217 + 1.5218 + if (!mGeckoChild || !mTextInputHandler) { 1.5219 + return; 1.5220 + } 1.5221 + 1.5222 + const char* sel = reinterpret_cast<const char*>(aSelector); 1.5223 + if (!mTextInputHandler->DoCommandBySelector(sel)) { 1.5224 + [super doCommandBySelector:aSelector]; 1.5225 + } 1.5226 + 1.5227 + NS_OBJC_END_TRY_ABORT_BLOCK; 1.5228 +} 1.5229 + 1.5230 +- (void) setMarkedText:(id)aString selectedRange:(NSRange)selRange 1.5231 +{ 1.5232 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK; 1.5233 + 1.5234 + NS_ENSURE_TRUE_VOID(mTextInputHandler); 1.5235 + 1.5236 + nsAutoRetainCocoaObject kungFuDeathGrip(self); 1.5237 + 1.5238 + NSAttributedString* attrStr; 1.5239 + if ([aString isKindOfClass:[NSAttributedString class]]) { 1.5240 + attrStr = static_cast<NSAttributedString*>(aString); 1.5241 + } else { 1.5242 + attrStr = [[[NSAttributedString alloc] initWithString:aString] autorelease]; 1.5243 + } 1.5244 + 1.5245 + mTextInputHandler->SetMarkedText(attrStr, selRange); 1.5246 + 1.5247 + NS_OBJC_END_TRY_ABORT_BLOCK; 1.5248 +} 1.5249 + 1.5250 +- (void) unmarkText 1.5251 +{ 1.5252 + NS_ENSURE_TRUE(mTextInputHandler, ); 1.5253 + mTextInputHandler->CommitIMEComposition(); 1.5254 +} 1.5255 + 1.5256 +- (BOOL) hasMarkedText 1.5257 +{ 1.5258 + NS_ENSURE_TRUE(mTextInputHandler, NO); 1.5259 + return mTextInputHandler->HasMarkedText(); 1.5260 +} 1.5261 + 1.5262 +- (BOOL)shouldMinimizeOnTitlebarDoubleClick 1.5263 +{ 1.5264 + NSString *MDAppleMiniaturizeOnDoubleClickKey = 1.5265 + @"AppleMiniaturizeOnDoubleClick"; 1.5266 + NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; 1.5267 + bool shouldMinimize = [[userDefaults 1.5268 + objectForKey:MDAppleMiniaturizeOnDoubleClickKey] boolValue]; 1.5269 + 1.5270 + return shouldMinimize; 1.5271 +} 1.5272 + 1.5273 +- (NSInteger) conversationIdentifier 1.5274 +{ 1.5275 + NS_ENSURE_TRUE(mTextInputHandler, reinterpret_cast<NSInteger>(self)); 1.5276 + return mTextInputHandler->ConversationIdentifier(); 1.5277 +} 1.5278 + 1.5279 +- (NSAttributedString *) attributedSubstringFromRange:(NSRange)theRange 1.5280 +{ 1.5281 + NS_ENSURE_TRUE(mTextInputHandler, nil); 1.5282 + return mTextInputHandler->GetAttributedSubstringFromRange(theRange); 1.5283 +} 1.5284 + 1.5285 +- (NSRange) markedRange 1.5286 +{ 1.5287 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN; 1.5288 + 1.5289 + NS_ENSURE_TRUE(mTextInputHandler, NSMakeRange(NSNotFound, 0)); 1.5290 + return mTextInputHandler->MarkedRange(); 1.5291 + 1.5292 + NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(NSMakeRange(0, 0)); 1.5293 +} 1.5294 + 1.5295 +- (NSRange) selectedRange 1.5296 +{ 1.5297 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN; 1.5298 + 1.5299 + NS_ENSURE_TRUE(mTextInputHandler, NSMakeRange(NSNotFound, 0)); 1.5300 + return mTextInputHandler->SelectedRange(); 1.5301 + 1.5302 + NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(NSMakeRange(0, 0)); 1.5303 +} 1.5304 + 1.5305 +- (NSRect) firstRectForCharacterRange:(NSRange)theRange 1.5306 +{ 1.5307 + NSRect rect; 1.5308 + NS_ENSURE_TRUE(mTextInputHandler, rect); 1.5309 + return mTextInputHandler->FirstRectForCharacterRange(theRange); 1.5310 +} 1.5311 + 1.5312 +- (NSUInteger)characterIndexForPoint:(NSPoint)thePoint 1.5313 +{ 1.5314 + NS_ENSURE_TRUE(mTextInputHandler, 0); 1.5315 + return mTextInputHandler->CharacterIndexForPoint(thePoint); 1.5316 +} 1.5317 + 1.5318 +- (NSArray*) validAttributesForMarkedText 1.5319 +{ 1.5320 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; 1.5321 + 1.5322 + NS_ENSURE_TRUE(mTextInputHandler, [NSArray array]); 1.5323 + return mTextInputHandler->GetValidAttributesForMarkedText(); 1.5324 + 1.5325 + NS_OBJC_END_TRY_ABORT_BLOCK_NIL; 1.5326 +} 1.5327 + 1.5328 +#pragma mark - 1.5329 +// NSTextInputClient implementation 1.5330 + 1.5331 +- (void)insertText:(id)aString replacementRange:(NSRange)replacementRange 1.5332 +{ 1.5333 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK; 1.5334 + 1.5335 + NS_ENSURE_TRUE_VOID(mGeckoChild); 1.5336 + 1.5337 + nsAutoRetainCocoaObject kungFuDeathGrip(self); 1.5338 + 1.5339 + NSAttributedString* attrStr; 1.5340 + if ([aString isKindOfClass:[NSAttributedString class]]) { 1.5341 + attrStr = static_cast<NSAttributedString*>(aString); 1.5342 + } else { 1.5343 + attrStr = [[[NSAttributedString alloc] initWithString:aString] autorelease]; 1.5344 + } 1.5345 + 1.5346 + mTextInputHandler->InsertText(attrStr, &replacementRange); 1.5347 + 1.5348 + NS_OBJC_END_TRY_ABORT_BLOCK; 1.5349 +} 1.5350 + 1.5351 +- (void)setMarkedText:(id)aString selectedRange:(NSRange)selectedRange 1.5352 + replacementRange:(NSRange)replacementRange 1.5353 +{ 1.5354 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK; 1.5355 + 1.5356 + NS_ENSURE_TRUE_VOID(mTextInputHandler); 1.5357 + 1.5358 + nsAutoRetainCocoaObject kungFuDeathGrip(self); 1.5359 + 1.5360 + NSAttributedString* attrStr; 1.5361 + if ([aString isKindOfClass:[NSAttributedString class]]) { 1.5362 + attrStr = static_cast<NSAttributedString*>(aString); 1.5363 + } else { 1.5364 + attrStr = [[[NSAttributedString alloc] initWithString:aString] autorelease]; 1.5365 + } 1.5366 + 1.5367 + mTextInputHandler->SetMarkedText(attrStr, selectedRange, &replacementRange); 1.5368 + 1.5369 + NS_OBJC_END_TRY_ABORT_BLOCK; 1.5370 +} 1.5371 + 1.5372 +- (NSAttributedString*)attributedSubstringForProposedRange:(NSRange)aRange 1.5373 + actualRange:(NSRangePointer)actualRange 1.5374 +{ 1.5375 + NS_ENSURE_TRUE(mTextInputHandler, nil); 1.5376 + return mTextInputHandler->GetAttributedSubstringFromRange(aRange, 1.5377 + actualRange); 1.5378 +} 1.5379 + 1.5380 +- (NSRect)firstRectForCharacterRange:(NSRange)aRange 1.5381 + actualRange:(NSRangePointer)actualRange 1.5382 +{ 1.5383 + NS_ENSURE_TRUE(mTextInputHandler, NSMakeRect(0.0, 0.0, 0.0, 0.0)); 1.5384 + return mTextInputHandler->FirstRectForCharacterRange(aRange, actualRange); 1.5385 +} 1.5386 + 1.5387 +- (NSInteger)windowLevel 1.5388 +{ 1.5389 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN; 1.5390 + 1.5391 + NS_ENSURE_TRUE(mTextInputHandler, [[self window] level]); 1.5392 + return mTextInputHandler->GetWindowLevel(); 1.5393 + 1.5394 + NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(NSNormalWindowLevel); 1.5395 +} 1.5396 + 1.5397 +#pragma mark - 1.5398 + 1.5399 +#ifdef __LP64__ 1.5400 +- (NSTextInputContext *)inputContext 1.5401 +{ 1.5402 + if (mIsPluginView && mPluginEventModel == NPEventModelCocoa) 1.5403 + return [[ComplexTextInputPanel sharedComplexTextInputPanel] inputContext]; 1.5404 + else 1.5405 + return [super inputContext]; 1.5406 +} 1.5407 +#endif 1.5408 + 1.5409 +// This is a private API that Cocoa uses. 1.5410 +// Cocoa will call this after the menu system returns "NO" for "performKeyEquivalent:". 1.5411 +// We want all they key events we can get so just return YES. In particular, this fixes 1.5412 +// ctrl-tab - we don't get a "keyDown:" call for that without this. 1.5413 +- (BOOL)_wantsKeyDownForEvent:(NSEvent*)event 1.5414 +{ 1.5415 + return YES; 1.5416 +} 1.5417 + 1.5418 +- (void)keyDown:(NSEvent*)theEvent 1.5419 +{ 1.5420 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK; 1.5421 + 1.5422 +#if !defined(RELEASE_BUILD) || defined(DEBUG) 1.5423 + if (mGeckoChild && mTextInputHandler && mTextInputHandler->IsFocused()) { 1.5424 +#ifdef MOZ_CRASHREPORTER 1.5425 + NSWindow* window = [self window]; 1.5426 + NSString* info = [NSString stringWithFormat:@"\nview [%@], window [%@], key event [%@], window is key %i, is fullscreen %i, app is active %i", 1.5427 + self, window, theEvent, [window isKeyWindow], ([window styleMask] & (1 << 14)) != 0, 1.5428 + [NSApp isActive]]; 1.5429 + nsAutoCString additionalInfo([info UTF8String]); 1.5430 +#endif 1.5431 + if (mIsPluginView) { 1.5432 + if (TextInputHandler::IsSecureEventInputEnabled()) { 1.5433 + #define CRASH_MESSAGE "While a plugin has focus, we must not be in secure mode" 1.5434 +#ifdef MOZ_CRASHREPORTER 1.5435 + CrashReporter::AppendAppNotesToCrashReport(NS_LITERAL_CSTRING("\nBug 893973: ") + 1.5436 + NS_LITERAL_CSTRING(CRASH_MESSAGE)); 1.5437 + CrashReporter::AppendAppNotesToCrashReport(additionalInfo); 1.5438 +#endif 1.5439 + MOZ_CRASH(CRASH_MESSAGE); 1.5440 + #undef CRASH_MESSAGE 1.5441 + } 1.5442 + } else if (mGeckoChild->GetInputContext().IsPasswordEditor() && 1.5443 + !TextInputHandler::IsSecureEventInputEnabled()) { 1.5444 + #define CRASH_MESSAGE "A password editor has focus, but not in secure input mode" 1.5445 +#ifdef MOZ_CRASHREPORTER 1.5446 + CrashReporter::AppendAppNotesToCrashReport(NS_LITERAL_CSTRING("\nBug 893973: ") + 1.5447 + NS_LITERAL_CSTRING(CRASH_MESSAGE)); 1.5448 + CrashReporter::AppendAppNotesToCrashReport(additionalInfo); 1.5449 +#endif 1.5450 + MOZ_CRASH(CRASH_MESSAGE); 1.5451 + #undef CRASH_MESSAGE 1.5452 + } else if (!mGeckoChild->GetInputContext().IsPasswordEditor() && 1.5453 + TextInputHandler::IsSecureEventInputEnabled()) { 1.5454 + #define CRASH_MESSAGE "A non-password editor has focus, but in secure input mode" 1.5455 +#ifdef MOZ_CRASHREPORTER 1.5456 + CrashReporter::AppendAppNotesToCrashReport(NS_LITERAL_CSTRING("\nBug 893973: ") + 1.5457 + NS_LITERAL_CSTRING(CRASH_MESSAGE)); 1.5458 + CrashReporter::AppendAppNotesToCrashReport(additionalInfo); 1.5459 +#endif 1.5460 + MOZ_CRASH(CRASH_MESSAGE); 1.5461 + #undef CRASH_MESSAGE 1.5462 + } 1.5463 + } 1.5464 +#endif // #if !defined(RELEASE_BUILD) || defined(DEBUG) 1.5465 + 1.5466 + if (mGeckoChild && mTextInputHandler && mIsPluginView) { 1.5467 + mTextInputHandler->HandleKeyDownEventForPlugin(theEvent); 1.5468 + return; 1.5469 + } 1.5470 + 1.5471 + nsAutoRetainCocoaObject kungFuDeathGrip(self); 1.5472 + bool handled = false; 1.5473 + if (mGeckoChild && mTextInputHandler) { 1.5474 + handled = mTextInputHandler->HandleKeyDownEvent(theEvent); 1.5475 + } 1.5476 + 1.5477 + // We always allow keyboard events to propagate to keyDown: but if they are not 1.5478 + // handled we give special Application menu items a chance to act. 1.5479 + if (!handled && sApplicationMenu) { 1.5480 + [sApplicationMenu performKeyEquivalent:theEvent]; 1.5481 + } 1.5482 + 1.5483 + NS_OBJC_END_TRY_ABORT_BLOCK; 1.5484 +} 1.5485 + 1.5486 +- (void)keyUp:(NSEvent*)theEvent 1.5487 +{ 1.5488 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK; 1.5489 + 1.5490 + NS_ENSURE_TRUE(mGeckoChild, ); 1.5491 + 1.5492 + nsAutoRetainCocoaObject kungFuDeathGrip(self); 1.5493 + 1.5494 + if (mIsPluginView) { 1.5495 + mTextInputHandler->HandleKeyUpEventForPlugin(theEvent); 1.5496 + return; 1.5497 + } 1.5498 + 1.5499 + mTextInputHandler->HandleKeyUpEvent(theEvent); 1.5500 + 1.5501 + NS_OBJC_END_TRY_ABORT_BLOCK; 1.5502 +} 1.5503 + 1.5504 +- (void)flagsChanged:(NSEvent*)theEvent 1.5505 +{ 1.5506 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK; 1.5507 + 1.5508 + NS_ENSURE_TRUE(mGeckoChild, ); 1.5509 + 1.5510 + nsAutoRetainCocoaObject kungFuDeathGrip(self); 1.5511 + mTextInputHandler->HandleFlagsChanged(theEvent); 1.5512 + 1.5513 + NS_OBJC_END_TRY_ABORT_BLOCK; 1.5514 +} 1.5515 + 1.5516 +- (BOOL) isFirstResponder 1.5517 +{ 1.5518 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN; 1.5519 + 1.5520 + NSResponder* resp = [[self window] firstResponder]; 1.5521 + return (resp == (NSResponder*)self); 1.5522 + 1.5523 + NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(NO); 1.5524 +} 1.5525 + 1.5526 +- (BOOL)isDragInProgress 1.5527 +{ 1.5528 + if (!mDragService) 1.5529 + return NO; 1.5530 + 1.5531 + nsCOMPtr<nsIDragSession> dragSession; 1.5532 + mDragService->GetCurrentSession(getter_AddRefs(dragSession)); 1.5533 + return dragSession != nullptr; 1.5534 +} 1.5535 + 1.5536 +- (BOOL)inactiveWindowAcceptsMouseEvent:(NSEvent*)aEvent 1.5537 +{ 1.5538 + // If we're being destroyed assume the default -- return YES. 1.5539 + if (!mGeckoChild) 1.5540 + return YES; 1.5541 + 1.5542 + WidgetMouseEvent geckoEvent(true, NS_MOUSE_ACTIVATE, mGeckoChild, 1.5543 + WidgetMouseEvent::eReal); 1.5544 + [self convertCocoaMouseEvent:aEvent toGeckoEvent:&geckoEvent]; 1.5545 + return !mGeckoChild->DispatchWindowEvent(geckoEvent); 1.5546 +} 1.5547 + 1.5548 +// Returns NO if the plugin shouldn't be focused/unfocused. 1.5549 +- (BOOL)updatePluginFocusStatus:(BOOL)getFocus 1.5550 +{ 1.5551 + if (!mGeckoChild) 1.5552 + return NO; 1.5553 + 1.5554 + if (mPluginEventModel == NPEventModelCocoa) { 1.5555 + WidgetPluginEvent pluginEvent(true, NS_PLUGIN_FOCUS_EVENT, mGeckoChild); 1.5556 + NPCocoaEvent cocoaEvent; 1.5557 + nsCocoaUtils::InitNPCocoaEvent(&cocoaEvent); 1.5558 + cocoaEvent.type = NPCocoaEventFocusChanged; 1.5559 + cocoaEvent.data.focus.hasFocus = getFocus; 1.5560 + nsCocoaUtils::InitPluginEvent(pluginEvent, cocoaEvent); 1.5561 + mGeckoChild->DispatchWindowEvent(pluginEvent); 1.5562 + 1.5563 + if (getFocus) 1.5564 + [self sendFocusEvent:NS_PLUGIN_FOCUS]; 1.5565 + } 1.5566 + 1.5567 + return YES; 1.5568 +} 1.5569 + 1.5570 +// We must always call through to our superclass, even when mGeckoChild is 1.5571 +// nil -- otherwise the keyboard focus can end up in the wrong NSView. 1.5572 +- (BOOL)becomeFirstResponder 1.5573 +{ 1.5574 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN; 1.5575 + 1.5576 + if (mIsPluginView) { 1.5577 + if (![self updatePluginFocusStatus:YES]) 1.5578 + return NO; 1.5579 + } 1.5580 + 1.5581 + return [super becomeFirstResponder]; 1.5582 + 1.5583 + NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(YES); 1.5584 +} 1.5585 + 1.5586 +// We must always call through to our superclass, even when mGeckoChild is 1.5587 +// nil -- otherwise the keyboard focus can end up in the wrong NSView. 1.5588 +- (BOOL)resignFirstResponder 1.5589 +{ 1.5590 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN; 1.5591 + 1.5592 + if (mIsPluginView) { 1.5593 + if (![self updatePluginFocusStatus:NO]) 1.5594 + return NO; 1.5595 + } 1.5596 + 1.5597 + return [super resignFirstResponder]; 1.5598 + 1.5599 + NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(YES); 1.5600 +} 1.5601 + 1.5602 +- (void)viewsWindowDidBecomeKey 1.5603 +{ 1.5604 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK; 1.5605 + 1.5606 + if (!mGeckoChild) 1.5607 + return; 1.5608 + 1.5609 + nsAutoRetainCocoaObject kungFuDeathGrip(self); 1.5610 + 1.5611 + // check to see if the window implements the mozWindow protocol. This 1.5612 + // allows embedders to avoid re-entrant calls to -makeKeyAndOrderFront, 1.5613 + // which can happen because these activate calls propagate out 1.5614 + // to the embedder via nsIEmbeddingSiteWindow::SetFocus(). 1.5615 + BOOL isMozWindow = [[self window] respondsToSelector:@selector(setSuppressMakeKeyFront:)]; 1.5616 + if (isMozWindow) 1.5617 + [[self window] setSuppressMakeKeyFront:YES]; 1.5618 + 1.5619 + nsIWidgetListener* listener = mGeckoChild->GetWidgetListener(); 1.5620 + if (listener) 1.5621 + listener->WindowActivated(); 1.5622 + 1.5623 + if (isMozWindow) 1.5624 + [[self window] setSuppressMakeKeyFront:NO]; 1.5625 + 1.5626 + NS_OBJC_END_TRY_ABORT_BLOCK; 1.5627 +} 1.5628 + 1.5629 +- (void)viewsWindowDidResignKey 1.5630 +{ 1.5631 + if (!mGeckoChild) 1.5632 + return; 1.5633 + 1.5634 + nsAutoRetainCocoaObject kungFuDeathGrip(self); 1.5635 + 1.5636 + nsIWidgetListener* listener = mGeckoChild->GetWidgetListener(); 1.5637 + if (listener) 1.5638 + listener->WindowDeactivated(); 1.5639 +} 1.5640 + 1.5641 +// If the call to removeFromSuperview isn't delayed from nsChildView:: 1.5642 +// TearDownView(), the NSView hierarchy might get changed during calls to 1.5643 +// [ChildView drawRect:], which leads to "beyond bounds" exceptions in 1.5644 +// NSCFArray. For more info see bmo bug 373122. Apple's docs claim that 1.5645 +// removeFromSuperviewWithoutNeedingDisplay "can be safely invoked during 1.5646 +// display" (whatever "display" means). But it's _not_ true that it can be 1.5647 +// safely invoked during calls to [NSView drawRect:]. We use 1.5648 +// removeFromSuperview here because there's no longer any danger of being 1.5649 +// "invoked during display", and because doing do clears up bmo bug 384343. 1.5650 +- (void)delayedTearDown 1.5651 +{ 1.5652 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK; 1.5653 + 1.5654 + [self removeFromSuperview]; 1.5655 + [self release]; 1.5656 + 1.5657 + NS_OBJC_END_TRY_ABORT_BLOCK; 1.5658 +} 1.5659 + 1.5660 +#pragma mark - 1.5661 + 1.5662 +// drag'n'drop stuff 1.5663 +#define kDragServiceContractID "@mozilla.org/widget/dragservice;1" 1.5664 + 1.5665 +- (NSDragOperation)dragOperationForSession:(nsIDragSession*)aDragSession 1.5666 +{ 1.5667 + uint32_t dragAction; 1.5668 + aDragSession->GetDragAction(&dragAction); 1.5669 + if (nsIDragService::DRAGDROP_ACTION_LINK & dragAction) 1.5670 + return NSDragOperationLink; 1.5671 + if (nsIDragService::DRAGDROP_ACTION_COPY & dragAction) 1.5672 + return NSDragOperationCopy; 1.5673 + if (nsIDragService::DRAGDROP_ACTION_MOVE & dragAction) 1.5674 + return NSDragOperationGeneric; 1.5675 + return NSDragOperationNone; 1.5676 +} 1.5677 + 1.5678 +// This is a utility function used by NSView drag event methods 1.5679 +// to send events. It contains all of the logic needed for Gecko 1.5680 +// dragging to work. Returns the appropriate cocoa drag operation code. 1.5681 +- (NSDragOperation)doDragAction:(uint32_t)aMessage sender:(id)aSender 1.5682 +{ 1.5683 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN; 1.5684 + 1.5685 + if (!mGeckoChild) 1.5686 + return NSDragOperationNone; 1.5687 + 1.5688 + PR_LOG(sCocoaLog, PR_LOG_ALWAYS, ("ChildView doDragAction: entered\n")); 1.5689 + 1.5690 + if (!mDragService) { 1.5691 + CallGetService(kDragServiceContractID, &mDragService); 1.5692 + NS_ASSERTION(mDragService, "Couldn't get a drag service - big problem!"); 1.5693 + if (!mDragService) 1.5694 + return NSDragOperationNone; 1.5695 + } 1.5696 + 1.5697 + if (aMessage == NS_DRAGDROP_ENTER) 1.5698 + mDragService->StartDragSession(); 1.5699 + 1.5700 + nsCOMPtr<nsIDragSession> dragSession; 1.5701 + mDragService->GetCurrentSession(getter_AddRefs(dragSession)); 1.5702 + if (dragSession) { 1.5703 + if (aMessage == NS_DRAGDROP_OVER) { 1.5704 + // fire the drag event at the source. Just ignore whether it was 1.5705 + // cancelled or not as there isn't actually a means to stop the drag 1.5706 + mDragService->FireDragEventAtSource(NS_DRAGDROP_DRAG); 1.5707 + dragSession->SetCanDrop(false); 1.5708 + } 1.5709 + else if (aMessage == NS_DRAGDROP_DROP) { 1.5710 + // We make the assumption that the dragOver handlers have correctly set 1.5711 + // the |canDrop| property of the Drag Session. 1.5712 + bool canDrop = false; 1.5713 + if (!NS_SUCCEEDED(dragSession->GetCanDrop(&canDrop)) || !canDrop) { 1.5714 + [self doDragAction:NS_DRAGDROP_EXIT sender:aSender]; 1.5715 + 1.5716 + nsCOMPtr<nsIDOMNode> sourceNode; 1.5717 + dragSession->GetSourceNode(getter_AddRefs(sourceNode)); 1.5718 + if (!sourceNode) { 1.5719 + mDragService->EndDragSession(false); 1.5720 + } 1.5721 + return NSDragOperationNone; 1.5722 + } 1.5723 + } 1.5724 + 1.5725 + unsigned int modifierFlags = [[NSApp currentEvent] modifierFlags]; 1.5726 + uint32_t action = nsIDragService::DRAGDROP_ACTION_MOVE; 1.5727 + // force copy = option, alias = cmd-option, default is move 1.5728 + if (modifierFlags & NSAlternateKeyMask) { 1.5729 + if (modifierFlags & NSCommandKeyMask) 1.5730 + action = nsIDragService::DRAGDROP_ACTION_LINK; 1.5731 + else 1.5732 + action = nsIDragService::DRAGDROP_ACTION_COPY; 1.5733 + } 1.5734 + dragSession->SetDragAction(action); 1.5735 + } 1.5736 + 1.5737 + // set up gecko event 1.5738 + WidgetDragEvent geckoEvent(true, aMessage, mGeckoChild); 1.5739 + nsCocoaUtils::InitInputEvent(geckoEvent, [NSApp currentEvent]); 1.5740 + 1.5741 + // Use our own coordinates in the gecko event. 1.5742 + // Convert event from gecko global coords to gecko view coords. 1.5743 + NSPoint draggingLoc = [aSender draggingLocation]; 1.5744 + NSPoint localPoint = [self convertPoint:draggingLoc fromView:nil]; 1.5745 + 1.5746 + geckoEvent.refPoint = LayoutDeviceIntPoint::FromUntyped( 1.5747 + mGeckoChild->CocoaPointsToDevPixels(localPoint)); 1.5748 + 1.5749 + nsAutoRetainCocoaObject kungFuDeathGrip(self); 1.5750 + mGeckoChild->DispatchWindowEvent(geckoEvent); 1.5751 + if (!mGeckoChild) 1.5752 + return NSDragOperationNone; 1.5753 + 1.5754 + if (dragSession) { 1.5755 + switch (aMessage) { 1.5756 + case NS_DRAGDROP_ENTER: 1.5757 + case NS_DRAGDROP_OVER: 1.5758 + return [self dragOperationForSession:dragSession]; 1.5759 + case NS_DRAGDROP_EXIT: 1.5760 + case NS_DRAGDROP_DROP: { 1.5761 + nsCOMPtr<nsIDOMNode> sourceNode; 1.5762 + dragSession->GetSourceNode(getter_AddRefs(sourceNode)); 1.5763 + if (!sourceNode) { 1.5764 + // We're leaving a window while doing a drag that was 1.5765 + // initiated in a different app. End the drag session, 1.5766 + // since we're done with it for now (until the user 1.5767 + // drags back into mozilla). 1.5768 + mDragService->EndDragSession(false); 1.5769 + } 1.5770 + } 1.5771 + } 1.5772 + } 1.5773 + 1.5774 + return NSDragOperationGeneric; 1.5775 + 1.5776 + NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(NSDragOperationNone); 1.5777 +} 1.5778 + 1.5779 +- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender 1.5780 +{ 1.5781 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN; 1.5782 + 1.5783 + PR_LOG(sCocoaLog, PR_LOG_ALWAYS, ("ChildView draggingEntered: entered\n")); 1.5784 + 1.5785 + // there should never be a globalDragPboard when "draggingEntered:" is 1.5786 + // called, but just in case we'll take care of it here. 1.5787 + [globalDragPboard release]; 1.5788 + 1.5789 + // Set the global drag pasteboard that will be used for this drag session. 1.5790 + // This will be set back to nil when the drag session ends (mouse exits 1.5791 + // the view or a drop happens within the view). 1.5792 + globalDragPboard = [[sender draggingPasteboard] retain]; 1.5793 + 1.5794 + return [self doDragAction:NS_DRAGDROP_ENTER sender:sender]; 1.5795 + 1.5796 + NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(NSDragOperationNone); 1.5797 +} 1.5798 + 1.5799 +- (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender 1.5800 +{ 1.5801 + PR_LOG(sCocoaLog, PR_LOG_ALWAYS, ("ChildView draggingUpdated: entered\n")); 1.5802 + 1.5803 + return [self doDragAction:NS_DRAGDROP_OVER sender:sender]; 1.5804 +} 1.5805 + 1.5806 +- (void)draggingExited:(id <NSDraggingInfo>)sender 1.5807 +{ 1.5808 + PR_LOG(sCocoaLog, PR_LOG_ALWAYS, ("ChildView draggingExited: entered\n")); 1.5809 + 1.5810 + nsAutoRetainCocoaObject kungFuDeathGrip(self); 1.5811 + [self doDragAction:NS_DRAGDROP_EXIT sender:sender]; 1.5812 + NS_IF_RELEASE(mDragService); 1.5813 +} 1.5814 + 1.5815 +- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender 1.5816 +{ 1.5817 + nsAutoRetainCocoaObject kungFuDeathGrip(self); 1.5818 + BOOL handled = [self doDragAction:NS_DRAGDROP_DROP sender:sender] != NSDragOperationNone; 1.5819 + NS_IF_RELEASE(mDragService); 1.5820 + return handled; 1.5821 +} 1.5822 + 1.5823 +// NSDraggingSource 1.5824 +- (void)draggedImage:(NSImage *)anImage movedTo:(NSPoint)aPoint 1.5825 +{ 1.5826 + // Get the drag service if it isn't already cached. The drag service 1.5827 + // isn't cached when dragging over a different application. 1.5828 + nsCOMPtr<nsIDragService> dragService = mDragService; 1.5829 + if (!dragService) { 1.5830 + dragService = do_GetService(kDragServiceContractID); 1.5831 + } 1.5832 + 1.5833 + if (dragService) { 1.5834 + NSPoint pnt = [NSEvent mouseLocation]; 1.5835 + FlipCocoaScreenCoordinate(pnt); 1.5836 + dragService->DragMoved(NSToIntRound(pnt.x), NSToIntRound(pnt.y)); 1.5837 + } 1.5838 +} 1.5839 + 1.5840 +// NSDraggingSource 1.5841 +- (void)draggedImage:(NSImage *)anImage endedAt:(NSPoint)aPoint operation:(NSDragOperation)operation 1.5842 +{ 1.5843 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK; 1.5844 + 1.5845 + gDraggedTransferables = nullptr; 1.5846 + 1.5847 + NSEvent *currentEvent = [NSApp currentEvent]; 1.5848 + gUserCancelledDrag = ([currentEvent type] == NSKeyDown && 1.5849 + [currentEvent keyCode] == kVK_Escape); 1.5850 + 1.5851 + if (!mDragService) { 1.5852 + CallGetService(kDragServiceContractID, &mDragService); 1.5853 + NS_ASSERTION(mDragService, "Couldn't get a drag service - big problem!"); 1.5854 + } 1.5855 + 1.5856 + if (mDragService) { 1.5857 + // set the dragend point from the current mouse location 1.5858 + nsDragService* dragService = static_cast<nsDragService *>(mDragService); 1.5859 + NSPoint pnt = [NSEvent mouseLocation]; 1.5860 + FlipCocoaScreenCoordinate(pnt); 1.5861 + dragService->SetDragEndPoint(nsIntPoint(NSToIntRound(pnt.x), NSToIntRound(pnt.y))); 1.5862 + 1.5863 + // XXX: dropEffect should be updated per |operation|. 1.5864 + // As things stand though, |operation| isn't well handled within "our" 1.5865 + // events, that is, when the drop happens within the window: it is set 1.5866 + // either to NSDragOperationGeneric or to NSDragOperationNone. 1.5867 + // For that reason, it's not yet possible to override dropEffect per the 1.5868 + // given OS value, and it's also unclear what's the correct dropEffect 1.5869 + // value for NSDragOperationGeneric that is passed by other applications. 1.5870 + // All that said, NSDragOperationNone is still reliable. 1.5871 + if (operation == NSDragOperationNone) { 1.5872 + nsCOMPtr<nsIDOMDataTransfer> dataTransfer; 1.5873 + dragService->GetDataTransfer(getter_AddRefs(dataTransfer)); 1.5874 + if (dataTransfer) 1.5875 + dataTransfer->SetDropEffectInt(nsIDragService::DRAGDROP_ACTION_NONE); 1.5876 + } 1.5877 + 1.5878 + mDragService->EndDragSession(true); 1.5879 + NS_RELEASE(mDragService); 1.5880 + } 1.5881 + 1.5882 + [globalDragPboard release]; 1.5883 + globalDragPboard = nil; 1.5884 + [gLastDragMouseDownEvent release]; 1.5885 + gLastDragMouseDownEvent = nil; 1.5886 + 1.5887 + NS_OBJC_END_TRY_ABORT_BLOCK; 1.5888 +} 1.5889 + 1.5890 +// NSDraggingSource 1.5891 +// this is just implemented so we comply with the NSDraggingSource informal protocol 1.5892 +- (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal 1.5893 +{ 1.5894 + return UINT_MAX; 1.5895 +} 1.5896 + 1.5897 +// This method is a callback typically invoked in response to a drag ending on the desktop 1.5898 +// or a Findow folder window; the argument passed is a path to the drop location, to be used 1.5899 +// in constructing a complete pathname for the file(s) we want to create as a result of 1.5900 +// the drag. 1.5901 +- (NSArray *)namesOfPromisedFilesDroppedAtDestination:(NSURL*)dropDestination 1.5902 +{ 1.5903 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; 1.5904 + 1.5905 + nsresult rv; 1.5906 + 1.5907 + PR_LOG(sCocoaLog, PR_LOG_ALWAYS, ("ChildView namesOfPromisedFilesDroppedAtDestination: entering callback for promised files\n")); 1.5908 + 1.5909 + nsCOMPtr<nsIFile> targFile; 1.5910 + NS_NewLocalFile(EmptyString(), true, getter_AddRefs(targFile)); 1.5911 + nsCOMPtr<nsILocalFileMac> macLocalFile = do_QueryInterface(targFile); 1.5912 + if (!macLocalFile) { 1.5913 + NS_ERROR("No Mac local file"); 1.5914 + return nil; 1.5915 + } 1.5916 + 1.5917 + if (!NS_SUCCEEDED(macLocalFile->InitWithCFURL((CFURLRef)dropDestination))) { 1.5918 + NS_ERROR("failed InitWithCFURL"); 1.5919 + return nil; 1.5920 + } 1.5921 + 1.5922 + if (!gDraggedTransferables) 1.5923 + return nil; 1.5924 + 1.5925 + uint32_t transferableCount; 1.5926 + rv = gDraggedTransferables->Count(&transferableCount); 1.5927 + if (NS_FAILED(rv)) 1.5928 + return nil; 1.5929 + 1.5930 + for (uint32_t i = 0; i < transferableCount; i++) { 1.5931 + nsCOMPtr<nsISupports> genericItem; 1.5932 + gDraggedTransferables->GetElementAt(i, getter_AddRefs(genericItem)); 1.5933 + nsCOMPtr<nsITransferable> item(do_QueryInterface(genericItem)); 1.5934 + if (!item) { 1.5935 + NS_ERROR("no transferable"); 1.5936 + return nil; 1.5937 + } 1.5938 + 1.5939 + item->SetTransferData(kFilePromiseDirectoryMime, macLocalFile, sizeof(nsIFile*)); 1.5940 + 1.5941 + // now request the kFilePromiseMime data, which will invoke the data provider 1.5942 + // If successful, the returned data is a reference to the resulting file. 1.5943 + nsCOMPtr<nsISupports> fileDataPrimitive; 1.5944 + uint32_t dataSize = 0; 1.5945 + item->GetTransferData(kFilePromiseMime, getter_AddRefs(fileDataPrimitive), &dataSize); 1.5946 + } 1.5947 + 1.5948 + NSPasteboard* generalPboard = [NSPasteboard pasteboardWithName:NSDragPboard]; 1.5949 + NSData* data = [generalPboard dataForType:@"application/x-moz-file-promise-dest-filename"]; 1.5950 + NSString* name = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; 1.5951 + NSArray* rslt = [NSArray arrayWithObject:name]; 1.5952 + 1.5953 + [name release]; 1.5954 + 1.5955 + return rslt; 1.5956 + 1.5957 + NS_OBJC_END_TRY_ABORT_BLOCK_NIL; 1.5958 +} 1.5959 + 1.5960 +#pragma mark - 1.5961 + 1.5962 +// Support for the "Services" menu. We currently only support sending strings 1.5963 +// and HTML to system services. 1.5964 + 1.5965 +- (id)validRequestorForSendType:(NSString *)sendType 1.5966 + returnType:(NSString *)returnType 1.5967 +{ 1.5968 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; 1.5969 + 1.5970 + // sendType contains the type of data that the service would like this 1.5971 + // application to send to it. sendType is nil if the service is not 1.5972 + // requesting any data. 1.5973 + // 1.5974 + // returnType contains the type of data the the service would like to 1.5975 + // return to this application (e.g., to overwrite the selection). 1.5976 + // returnType is nil if the service will not return any data. 1.5977 + // 1.5978 + // The following condition thus triggers when the service expects a string 1.5979 + // or HTML from us or no data at all AND when the service will either not 1.5980 + // send back any data to us or will send a string or HTML back to us. 1.5981 + 1.5982 +#define IsSupportedType(typeStr) ([typeStr isEqual:NSStringPboardType] || [typeStr isEqual:NSHTMLPboardType]) 1.5983 + 1.5984 + id result = nil; 1.5985 + 1.5986 + if ((!sendType || IsSupportedType(sendType)) && 1.5987 + (!returnType || IsSupportedType(returnType))) { 1.5988 + if (mGeckoChild) { 1.5989 + // Assume that this object will be able to handle this request. 1.5990 + result = self; 1.5991 + 1.5992 + // Keep the ChildView alive during this operation. 1.5993 + nsAutoRetainCocoaObject kungFuDeathGrip(self); 1.5994 + 1.5995 + // Determine if there is a selection (if sending to the service). 1.5996 + if (sendType) { 1.5997 + WidgetQueryContentEvent event(true, NS_QUERY_CONTENT_STATE, 1.5998 + mGeckoChild); 1.5999 + // This might destroy our widget (and null out mGeckoChild). 1.6000 + mGeckoChild->DispatchWindowEvent(event); 1.6001 + if (!mGeckoChild || !event.mSucceeded || !event.mReply.mHasSelection) 1.6002 + result = nil; 1.6003 + } 1.6004 + 1.6005 + // Determine if we can paste (if receiving data from the service). 1.6006 + if (mGeckoChild && returnType) { 1.6007 + WidgetContentCommandEvent command(true, 1.6008 + NS_CONTENT_COMMAND_PASTE_TRANSFERABLE, 1.6009 + mGeckoChild, true); 1.6010 + // This might possibly destroy our widget (and null out mGeckoChild). 1.6011 + mGeckoChild->DispatchWindowEvent(command); 1.6012 + if (!mGeckoChild || !command.mSucceeded || !command.mIsEnabled) 1.6013 + result = nil; 1.6014 + } 1.6015 + } 1.6016 + } 1.6017 + 1.6018 +#undef IsSupportedType 1.6019 + 1.6020 + // Give the superclass a chance if this object will not handle this request. 1.6021 + if (!result) 1.6022 + result = [super validRequestorForSendType:sendType returnType:returnType]; 1.6023 + 1.6024 + return result; 1.6025 + 1.6026 + NS_OBJC_END_TRY_ABORT_BLOCK_NIL; 1.6027 +} 1.6028 + 1.6029 +- (BOOL)writeSelectionToPasteboard:(NSPasteboard *)pboard 1.6030 + types:(NSArray *)types 1.6031 +{ 1.6032 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN; 1.6033 + 1.6034 + nsAutoRetainCocoaObject kungFuDeathGrip(self); 1.6035 + 1.6036 + // Make sure that the service will accept strings or HTML. 1.6037 + if ([types containsObject:NSStringPboardType] == NO && 1.6038 + [types containsObject:NSHTMLPboardType] == NO) 1.6039 + return NO; 1.6040 + 1.6041 + // Bail out if there is no Gecko object. 1.6042 + if (!mGeckoChild) 1.6043 + return NO; 1.6044 + 1.6045 + // Obtain the current selection. 1.6046 + WidgetQueryContentEvent event(true, 1.6047 + NS_QUERY_SELECTION_AS_TRANSFERABLE, 1.6048 + mGeckoChild); 1.6049 + mGeckoChild->DispatchWindowEvent(event); 1.6050 + if (!event.mSucceeded || !event.mReply.mTransferable) 1.6051 + return NO; 1.6052 + 1.6053 + // Transform the transferable to an NSDictionary. 1.6054 + NSDictionary* pasteboardOutputDict = nsClipboard::PasteboardDictFromTransferable(event.mReply.mTransferable); 1.6055 + if (!pasteboardOutputDict) 1.6056 + return NO; 1.6057 + 1.6058 + // Declare the pasteboard types. 1.6059 + unsigned int typeCount = [pasteboardOutputDict count]; 1.6060 + NSMutableArray * types = [NSMutableArray arrayWithCapacity:typeCount]; 1.6061 + [types addObjectsFromArray:[pasteboardOutputDict allKeys]]; 1.6062 + [pboard declareTypes:types owner:nil]; 1.6063 + 1.6064 + // Write the data to the pasteboard. 1.6065 + for (unsigned int i = 0; i < typeCount; i++) { 1.6066 + NSString* currentKey = [types objectAtIndex:i]; 1.6067 + id currentValue = [pasteboardOutputDict valueForKey:currentKey]; 1.6068 + 1.6069 + if (currentKey == NSStringPboardType || 1.6070 + currentKey == kCorePboardType_url || 1.6071 + currentKey == kCorePboardType_urld || 1.6072 + currentKey == kCorePboardType_urln) { 1.6073 + [pboard setString:currentValue forType:currentKey]; 1.6074 + } else if (currentKey == NSHTMLPboardType) { 1.6075 + [pboard setString:(nsClipboard::WrapHtmlForSystemPasteboard(currentValue)) forType:currentKey]; 1.6076 + } else if (currentKey == NSTIFFPboardType) { 1.6077 + [pboard setData:currentValue forType:currentKey]; 1.6078 + } else if (currentKey == NSFilesPromisePboardType) { 1.6079 + [pboard setPropertyList:currentValue forType:currentKey]; 1.6080 + } 1.6081 + } 1.6082 + 1.6083 + return YES; 1.6084 + 1.6085 + NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(NO); 1.6086 +} 1.6087 + 1.6088 +// Called if the service wants us to replace the current selection. 1.6089 +- (BOOL)readSelectionFromPasteboard:(NSPasteboard *)pboard 1.6090 +{ 1.6091 + nsresult rv; 1.6092 + nsCOMPtr<nsITransferable> trans = do_CreateInstance("@mozilla.org/widget/transferable;1", &rv); 1.6093 + if (NS_FAILED(rv)) 1.6094 + return NO; 1.6095 + trans->Init(nullptr); 1.6096 + 1.6097 + trans->AddDataFlavor(kUnicodeMime); 1.6098 + trans->AddDataFlavor(kHTMLMime); 1.6099 + 1.6100 + rv = nsClipboard::TransferableFromPasteboard(trans, pboard); 1.6101 + if (NS_FAILED(rv)) 1.6102 + return NO; 1.6103 + 1.6104 + NS_ENSURE_TRUE(mGeckoChild, false); 1.6105 + 1.6106 + WidgetContentCommandEvent command(true, 1.6107 + NS_CONTENT_COMMAND_PASTE_TRANSFERABLE, 1.6108 + mGeckoChild); 1.6109 + command.mTransferable = trans; 1.6110 + mGeckoChild->DispatchWindowEvent(command); 1.6111 + 1.6112 + return command.mSucceeded && command.mIsEnabled; 1.6113 +} 1.6114 + 1.6115 +#pragma mark - 1.6116 + 1.6117 +#ifdef ACCESSIBILITY 1.6118 + 1.6119 +/* Every ChildView has a corresponding mozDocAccessible object that is doing all 1.6120 + the heavy lifting. The topmost ChildView corresponds to a mozRootAccessible 1.6121 + object. 1.6122 + 1.6123 + All ChildView needs to do is to route all accessibility calls (from the NSAccessibility APIs) 1.6124 + down to its object, pretending that they are the same. 1.6125 +*/ 1.6126 +- (id<mozAccessible>)accessible 1.6127 +{ 1.6128 + if (!mGeckoChild) 1.6129 + return nil; 1.6130 + 1.6131 + id<mozAccessible> nativeAccessible = nil; 1.6132 + 1.6133 + nsAutoRetainCocoaObject kungFuDeathGrip(self); 1.6134 + nsCOMPtr<nsIWidget> kungFuDeathGrip2(mGeckoChild); 1.6135 + nsRefPtr<a11y::Accessible> accessible = mGeckoChild->GetDocumentAccessible(); 1.6136 + if (!accessible) 1.6137 + return nil; 1.6138 + 1.6139 + accessible->GetNativeInterface((void**)&nativeAccessible); 1.6140 + 1.6141 +#ifdef DEBUG_hakan 1.6142 + NSAssert(![nativeAccessible isExpired], @"native acc is expired!!!"); 1.6143 +#endif 1.6144 + 1.6145 + return nativeAccessible; 1.6146 +} 1.6147 + 1.6148 +/* Implementation of formal mozAccessible formal protocol (enabling mozViews 1.6149 + to talk to mozAccessible objects in the accessibility module). */ 1.6150 + 1.6151 +- (BOOL)hasRepresentedView 1.6152 +{ 1.6153 + return YES; 1.6154 +} 1.6155 + 1.6156 +- (id)representedView 1.6157 +{ 1.6158 + return self; 1.6159 +} 1.6160 + 1.6161 +- (BOOL)isRoot 1.6162 +{ 1.6163 + return [[self accessible] isRoot]; 1.6164 +} 1.6165 + 1.6166 +#ifdef DEBUG 1.6167 +- (void)printHierarchy 1.6168 +{ 1.6169 + [[self accessible] printHierarchy]; 1.6170 +} 1.6171 +#endif 1.6172 + 1.6173 +#pragma mark - 1.6174 + 1.6175 +// general 1.6176 + 1.6177 +- (BOOL)accessibilityIsIgnored 1.6178 +{ 1.6179 + if (!mozilla::a11y::ShouldA11yBeEnabled()) 1.6180 + return [super accessibilityIsIgnored]; 1.6181 + 1.6182 + return [[self accessible] accessibilityIsIgnored]; 1.6183 +} 1.6184 + 1.6185 +- (id)accessibilityHitTest:(NSPoint)point 1.6186 +{ 1.6187 + if (!mozilla::a11y::ShouldA11yBeEnabled()) 1.6188 + return [super accessibilityHitTest:point]; 1.6189 + 1.6190 + return [[self accessible] accessibilityHitTest:point]; 1.6191 +} 1.6192 + 1.6193 +- (id)accessibilityFocusedUIElement 1.6194 +{ 1.6195 + if (!mozilla::a11y::ShouldA11yBeEnabled()) 1.6196 + return [super accessibilityFocusedUIElement]; 1.6197 + 1.6198 + return [[self accessible] accessibilityFocusedUIElement]; 1.6199 +} 1.6200 + 1.6201 +// actions 1.6202 + 1.6203 +- (NSArray*)accessibilityActionNames 1.6204 +{ 1.6205 + if (!mozilla::a11y::ShouldA11yBeEnabled()) 1.6206 + return [super accessibilityActionNames]; 1.6207 + 1.6208 + return [[self accessible] accessibilityActionNames]; 1.6209 +} 1.6210 + 1.6211 +- (NSString*)accessibilityActionDescription:(NSString*)action 1.6212 +{ 1.6213 + if (!mozilla::a11y::ShouldA11yBeEnabled()) 1.6214 + return [super accessibilityActionDescription:action]; 1.6215 + 1.6216 + return [[self accessible] accessibilityActionDescription:action]; 1.6217 +} 1.6218 + 1.6219 +- (void)accessibilityPerformAction:(NSString*)action 1.6220 +{ 1.6221 + if (!mozilla::a11y::ShouldA11yBeEnabled()) 1.6222 + return [super accessibilityPerformAction:action]; 1.6223 + 1.6224 + return [[self accessible] accessibilityPerformAction:action]; 1.6225 +} 1.6226 + 1.6227 +// attributes 1.6228 + 1.6229 +- (NSArray*)accessibilityAttributeNames 1.6230 +{ 1.6231 + if (!mozilla::a11y::ShouldA11yBeEnabled()) 1.6232 + return [super accessibilityAttributeNames]; 1.6233 + 1.6234 + return [[self accessible] accessibilityAttributeNames]; 1.6235 +} 1.6236 + 1.6237 +- (BOOL)accessibilityIsAttributeSettable:(NSString*)attribute 1.6238 +{ 1.6239 + if (!mozilla::a11y::ShouldA11yBeEnabled()) 1.6240 + return [super accessibilityIsAttributeSettable:attribute]; 1.6241 + 1.6242 + return [[self accessible] accessibilityIsAttributeSettable:attribute]; 1.6243 +} 1.6244 + 1.6245 +- (id)accessibilityAttributeValue:(NSString*)attribute 1.6246 +{ 1.6247 + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; 1.6248 + 1.6249 + if (!mozilla::a11y::ShouldA11yBeEnabled()) 1.6250 + return [super accessibilityAttributeValue:attribute]; 1.6251 + 1.6252 + id<mozAccessible> accessible = [self accessible]; 1.6253 + 1.6254 + // if we're the root (topmost) accessible, we need to return our native AXParent as we 1.6255 + // traverse outside to the hierarchy of whoever embeds us. thus, fall back on NSView's 1.6256 + // default implementation for this attribute. 1.6257 + if ([attribute isEqualToString:NSAccessibilityParentAttribute] && [accessible isRoot]) { 1.6258 + id parentAccessible = [super accessibilityAttributeValue:attribute]; 1.6259 + return parentAccessible; 1.6260 + } 1.6261 + 1.6262 + return [accessible accessibilityAttributeValue:attribute]; 1.6263 + 1.6264 + NS_OBJC_END_TRY_ABORT_BLOCK_NIL; 1.6265 +} 1.6266 + 1.6267 +#endif /* ACCESSIBILITY */ 1.6268 + 1.6269 +@end 1.6270 + 1.6271 +#pragma mark - 1.6272 + 1.6273 +void 1.6274 +ChildViewMouseTracker::OnDestroyView(ChildView* aView) 1.6275 +{ 1.6276 + if (sLastMouseEventView == aView) { 1.6277 + sLastMouseEventView = nil; 1.6278 + [sLastMouseMoveEvent release]; 1.6279 + sLastMouseMoveEvent = nil; 1.6280 + } 1.6281 +} 1.6282 + 1.6283 +void 1.6284 +ChildViewMouseTracker::OnDestroyWindow(NSWindow* aWindow) 1.6285 +{ 1.6286 + if (sWindowUnderMouse == aWindow) { 1.6287 + sWindowUnderMouse = nil; 1.6288 + } 1.6289 +} 1.6290 + 1.6291 +void 1.6292 +ChildViewMouseTracker::MouseEnteredWindow(NSEvent* aEvent) 1.6293 +{ 1.6294 + sWindowUnderMouse = [aEvent window]; 1.6295 + ReEvaluateMouseEnterState(aEvent); 1.6296 +} 1.6297 + 1.6298 +void 1.6299 +ChildViewMouseTracker::MouseExitedWindow(NSEvent* aEvent) 1.6300 +{ 1.6301 + if (sWindowUnderMouse == [aEvent window]) { 1.6302 + sWindowUnderMouse = nil; 1.6303 + ReEvaluateMouseEnterState(aEvent); 1.6304 + } 1.6305 +} 1.6306 + 1.6307 +void 1.6308 +ChildViewMouseTracker::ReEvaluateMouseEnterState(NSEvent* aEvent, ChildView* aOldView) 1.6309 +{ 1.6310 + ChildView* oldView = aOldView ? aOldView : sLastMouseEventView; 1.6311 + sLastMouseEventView = ViewForEvent(aEvent); 1.6312 + if (sLastMouseEventView != oldView) { 1.6313 + // Send enter and / or exit events. 1.6314 + WidgetMouseEvent::exitType type = 1.6315 + [sLastMouseEventView window] == [oldView window] ? 1.6316 + WidgetMouseEvent::eChild : WidgetMouseEvent::eTopLevel; 1.6317 + [oldView sendMouseEnterOrExitEvent:aEvent enter:NO type:type]; 1.6318 + // After the cursor exits the window set it to a visible regular arrow cursor. 1.6319 + if (type == WidgetMouseEvent::eTopLevel) { 1.6320 + [[nsCursorManager sharedInstance] setCursor:eCursor_standard]; 1.6321 + } 1.6322 + [sLastMouseEventView sendMouseEnterOrExitEvent:aEvent enter:YES type:type]; 1.6323 + } 1.6324 +} 1.6325 + 1.6326 +void 1.6327 +ChildViewMouseTracker::ResendLastMouseMoveEvent() 1.6328 +{ 1.6329 + if (sLastMouseMoveEvent) { 1.6330 + MouseMoved(sLastMouseMoveEvent); 1.6331 + } 1.6332 +} 1.6333 + 1.6334 +void 1.6335 +ChildViewMouseTracker::MouseMoved(NSEvent* aEvent) 1.6336 +{ 1.6337 + MouseEnteredWindow(aEvent); 1.6338 + [sLastMouseEventView handleMouseMoved:aEvent]; 1.6339 + if (sLastMouseMoveEvent != aEvent) { 1.6340 + [sLastMouseMoveEvent release]; 1.6341 + sLastMouseMoveEvent = [aEvent retain]; 1.6342 + } 1.6343 +} 1.6344 + 1.6345 +void 1.6346 +ChildViewMouseTracker::MouseScrolled(NSEvent* aEvent) 1.6347 +{ 1.6348 + if (!nsCocoaUtils::IsMomentumScrollEvent(aEvent)) { 1.6349 + // Store the position so we can pin future momentum scroll events. 1.6350 + sLastScrollEventScreenLocation = nsCocoaUtils::ScreenLocationForEvent(aEvent); 1.6351 + } 1.6352 +} 1.6353 + 1.6354 +ChildView* 1.6355 +ChildViewMouseTracker::ViewForEvent(NSEvent* aEvent) 1.6356 +{ 1.6357 + NSWindow* window = sWindowUnderMouse; 1.6358 + if (!window) 1.6359 + return nil; 1.6360 + 1.6361 + NSPoint windowEventLocation = nsCocoaUtils::EventLocationForWindow(aEvent, window); 1.6362 + NSView* view = [[[window contentView] superview] hitTest:windowEventLocation]; 1.6363 + 1.6364 + if (![view isKindOfClass:[ChildView class]]) 1.6365 + return nil; 1.6366 + 1.6367 + ChildView* childView = (ChildView*)view; 1.6368 + // If childView is being destroyed return nil. 1.6369 + if (![childView widget]) 1.6370 + return nil; 1.6371 + return WindowAcceptsEvent(window, aEvent, childView) ? childView : nil; 1.6372 +} 1.6373 + 1.6374 +void 1.6375 +ChildViewMouseTracker::AttachPluginEvent(WidgetMouseEventBase& aMouseEvent, 1.6376 + ChildView* aView, 1.6377 + NSEvent* aNativeMouseEvent, 1.6378 + int aPluginEventType, 1.6379 + void* aPluginEventHolder) 1.6380 +{ 1.6381 + if (![aView isPluginView] || 1.6382 + [aView pluginEventModel] != NPEventModelCocoa) { 1.6383 + return; 1.6384 + } 1.6385 + 1.6386 + NPCocoaEvent* cocoaEvent = (NPCocoaEvent*)aPluginEventHolder; 1.6387 + nsCocoaUtils::InitNPCocoaEvent(cocoaEvent); 1.6388 + NSPoint point = [aView convertPoint:[aNativeMouseEvent locationInWindow] 1.6389 + fromView:nil]; 1.6390 + NPCocoaEventType type = (NPCocoaEventType)aPluginEventType; 1.6391 + // XXX We should consider dropping this code, which causes data.mouse.pluginX 1.6392 + // and data.mouse.pluginY to be set to '5' for mouse-entered and mouse-exited 1.6393 + // events. But note that it's been in the tree since the Cocoa NPAPI event 1.6394 + // model was first implemented four years ago, without any known complaints. 1.6395 + // 1.6396 + // Similar code first appeared (without explanation) in a very early version 1.6397 + // ("fix 0.3") of the patch for bug 435041 ("Implement Cocoa NPAPI event 1.6398 + // model for Mac OS X"). But there's no trace of it in the WebKit code that 1.6399 + // was used as a model for much of that patch. 1.6400 +#if (0) 1.6401 + if (type == NPCocoaEventMouseEntered || 1.6402 + type == NPCocoaEventMouseExited) { 1.6403 + point.x = point.y = 5; 1.6404 + } 1.6405 +#endif 1.6406 + NSUInteger clickCount = 0; 1.6407 + if (type != NPCocoaEventMouseEntered && 1.6408 + type != NPCocoaEventMouseExited && 1.6409 + type != NPCocoaEventScrollWheel) { 1.6410 + clickCount = [aNativeMouseEvent clickCount]; 1.6411 + } 1.6412 + cocoaEvent->type = type; 1.6413 + cocoaEvent->data.mouse.modifierFlags = [aNativeMouseEvent modifierFlags]; 1.6414 + cocoaEvent->data.mouse.pluginX = point.x; 1.6415 + cocoaEvent->data.mouse.pluginY = point.y; 1.6416 + cocoaEvent->data.mouse.buttonNumber = [aNativeMouseEvent buttonNumber]; 1.6417 + cocoaEvent->data.mouse.clickCount = clickCount; 1.6418 + cocoaEvent->data.mouse.deltaX = [aNativeMouseEvent deltaX]; 1.6419 + cocoaEvent->data.mouse.deltaY = [aNativeMouseEvent deltaY]; 1.6420 + cocoaEvent->data.mouse.deltaZ = [aNativeMouseEvent deltaZ]; 1.6421 + aMouseEvent.pluginEvent = cocoaEvent; 1.6422 +} 1.6423 + 1.6424 +BOOL 1.6425 +ChildViewMouseTracker::WindowAcceptsEvent(NSWindow* aWindow, NSEvent* aEvent, 1.6426 + ChildView* aView, BOOL aIsClickThrough) 1.6427 +{ 1.6428 + // Right mouse down events may get through to all windows, even to a top level 1.6429 + // window with an open sheet. 1.6430 + if (!aWindow || [aEvent type] == NSRightMouseDown) 1.6431 + return YES; 1.6432 + 1.6433 + id delegate = [aWindow delegate]; 1.6434 + if (!delegate || ![delegate isKindOfClass:[WindowDelegate class]]) 1.6435 + return YES; 1.6436 + 1.6437 + nsIWidget *windowWidget = [(WindowDelegate *)delegate geckoWidget]; 1.6438 + if (!windowWidget) 1.6439 + return YES; 1.6440 + 1.6441 + NSWindow* topLevelWindow = nil; 1.6442 + 1.6443 + switch (windowWidget->WindowType()) { 1.6444 + case eWindowType_popup: 1.6445 + // If this is a context menu, it won't have a parent. So we'll always 1.6446 + // accept mouse move events on context menus even when none of our windows 1.6447 + // is active, which is the right thing to do. 1.6448 + // For panels, the parent window is the XUL window that owns the panel. 1.6449 + return WindowAcceptsEvent([aWindow parentWindow], aEvent, aView, aIsClickThrough); 1.6450 + 1.6451 + case eWindowType_toplevel: 1.6452 + case eWindowType_dialog: 1.6453 + if ([aWindow attachedSheet]) 1.6454 + return NO; 1.6455 + 1.6456 + topLevelWindow = aWindow; 1.6457 + break; 1.6458 + case eWindowType_sheet: { 1.6459 + nsIWidget* parentWidget = windowWidget->GetSheetWindowParent(); 1.6460 + if (!parentWidget) 1.6461 + return YES; 1.6462 + 1.6463 + topLevelWindow = (NSWindow*)parentWidget->GetNativeData(NS_NATIVE_WINDOW); 1.6464 + break; 1.6465 + } 1.6466 + 1.6467 + default: 1.6468 + return YES; 1.6469 + } 1.6470 + 1.6471 + if (!topLevelWindow || 1.6472 + ([topLevelWindow isMainWindow] && !aIsClickThrough) || 1.6473 + [aEvent type] == NSOtherMouseDown || 1.6474 + (([aEvent modifierFlags] & NSCommandKeyMask) != 0 && 1.6475 + [aEvent type] != NSMouseMoved)) 1.6476 + return YES; 1.6477 + 1.6478 + // If we're here then we're dealing with a left click or mouse move on an 1.6479 + // inactive window or something similar. Ask Gecko what to do. 1.6480 + return [aView inactiveWindowAcceptsMouseEvent:aEvent]; 1.6481 +} 1.6482 + 1.6483 +#pragma mark - 1.6484 + 1.6485 +@interface NSView (MethodSwizzling) 1.6486 +- (BOOL)nsChildView_NSView_mouseDownCanMoveWindow; 1.6487 +@end 1.6488 + 1.6489 +@implementation NSView (MethodSwizzling) 1.6490 + 1.6491 +// All top-level browser windows belong to the ToolbarWindow class and have 1.6492 +// NSTexturedBackgroundWindowMask turned on in their "style" (see particularly 1.6493 +// [ToolbarWindow initWithContentRect:...] in nsCocoaWindow.mm). This style 1.6494 +// normally means the window "may be moved by clicking and dragging anywhere 1.6495 +// in the window background", but we've suppressed this by giving the 1.6496 +// ChildView class a mouseDownCanMoveWindow method that always returns NO. 1.6497 +// Normally a ToolbarWindow's contentView (not a ChildView) returns YES when 1.6498 +// NSTexturedBackgroundWindowMask is turned on. But normally this makes no 1.6499 +// difference. However, under some (probably very unusual) circumstances 1.6500 +// (and only on Leopard) it *does* make a difference -- for example it 1.6501 +// triggers bmo bugs 431902 and 476393. So here we make sure that a 1.6502 +// ToolbarWindow's contentView always returns NO from the 1.6503 +// mouseDownCanMoveWindow method. 1.6504 +- (BOOL)nsChildView_NSView_mouseDownCanMoveWindow 1.6505 +{ 1.6506 + NSWindow *ourWindow = [self window]; 1.6507 + NSView *contentView = [ourWindow contentView]; 1.6508 + if ([ourWindow isKindOfClass:[ToolbarWindow class]] && (self == contentView)) 1.6509 + return [ourWindow isMovableByWindowBackground]; 1.6510 + return [self nsChildView_NSView_mouseDownCanMoveWindow]; 1.6511 +} 1.6512 + 1.6513 +@end 1.6514 + 1.6515 +#ifdef __LP64__ 1.6516 +// When using blocks, at least on OS X 10.7, the OS sometimes calls 1.6517 +// +[NSEvent removeMonitor:] more than once on a single event monitor, which 1.6518 +// causes crashes. See bug 678607. We hook these methods to work around 1.6519 +// the problem. 1.6520 +@interface NSEvent (MethodSwizzling) 1.6521 ++ (id)nsChildView_NSEvent_addLocalMonitorForEventsMatchingMask:(unsigned long long)mask handler:(id)block; 1.6522 ++ (void)nsChildView_NSEvent_removeMonitor:(id)eventMonitor; 1.6523 +@end 1.6524 + 1.6525 +// This is a local copy of the AppKit frameworks sEventObservers hashtable. 1.6526 +// It only stores "local monitors". We use it to ensure that +[NSEvent 1.6527 +// removeMonitor:] is never called more than once on the same local monitor. 1.6528 +static NSHashTable *sLocalEventObservers = nil; 1.6529 + 1.6530 +@implementation NSEvent (MethodSwizzling) 1.6531 + 1.6532 ++ (id)nsChildView_NSEvent_addLocalMonitorForEventsMatchingMask:(unsigned long long)mask handler:(id)block 1.6533 +{ 1.6534 + if (!sLocalEventObservers) { 1.6535 + sLocalEventObservers = [[NSHashTable hashTableWithOptions: 1.6536 + NSHashTableStrongMemory | NSHashTableObjectPointerPersonality] retain]; 1.6537 + } 1.6538 + id retval = 1.6539 + [self nsChildView_NSEvent_addLocalMonitorForEventsMatchingMask:mask handler:block]; 1.6540 + if (sLocalEventObservers && retval && ![sLocalEventObservers containsObject:retval]) { 1.6541 + [sLocalEventObservers addObject:retval]; 1.6542 + } 1.6543 + return retval; 1.6544 +} 1.6545 + 1.6546 ++ (void)nsChildView_NSEvent_removeMonitor:(id)eventMonitor 1.6547 +{ 1.6548 + if (sLocalEventObservers && [eventMonitor isKindOfClass: ::NSClassFromString(@"_NSLocalEventObserver")]) { 1.6549 + if (![sLocalEventObservers containsObject:eventMonitor]) { 1.6550 + return; 1.6551 + } 1.6552 + [sLocalEventObservers removeObject:eventMonitor]; 1.6553 + } 1.6554 + [self nsChildView_NSEvent_removeMonitor:eventMonitor]; 1.6555 +} 1.6556 + 1.6557 +@end 1.6558 +#endif // #ifdef __LP64__