widget/cocoa/nsChildView.mm

changeset 0
6474c204b198
     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, &region);
   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__

mercurial