Bug 1370034 - Add nsIWidget::SetWindowTransform and implement it on Mac. r?spohl draft
authorMarkus Stange <mstange@themasta.com>
Wed, 14 Jun 2017 19:15:10 -0400
changeset 596346 db46a233c5d9f40f957daed476795ed76aaa300f
parent 596345 a8b292491888ede3a5d75a5f19aa775b5697e8ca
child 596347 09e3d93c1bcb133e6d0157a856751c331451500f
push id64588
push userbmo:mstange@themasta.com
push dateMon, 19 Jun 2017 05:46:08 +0000
reviewersspohl
bugs1370034
milestone56.0a1
Bug 1370034 - Add nsIWidget::SetWindowTransform and implement it on Mac. r?spohl MozReview-Commit-ID: 6tghHjKe6pb
widget/cocoa/nsCocoaWindow.h
widget/cocoa/nsCocoaWindow.mm
widget/nsIWidget.h
--- a/widget/cocoa/nsCocoaWindow.h
+++ b/widget/cocoa/nsCocoaWindow.h
@@ -311,16 +311,17 @@ public:
     virtual void CaptureRollupEvents(nsIRollupListener * aListener,
                                      bool aDoCapture) override;
     virtual MOZ_MUST_USE nsresult GetAttention(int32_t aCycleCount) override;
     virtual bool HasPendingInputEvent() override;
     virtual nsTransparencyMode GetTransparencyMode() override;
     virtual void SetTransparencyMode(nsTransparencyMode aMode) override;
     virtual void SetWindowShadowStyle(int32_t aStyle) override;
     virtual void SetWindowOpacity(float aOpacity) override;
+    virtual void SetWindowTransform(const mozilla::gfx::Matrix& aTransform) override;
     virtual void SetShowsToolbarButton(bool aShow) override;
     virtual void SetShowsFullScreenButton(bool aShow) override;
     virtual void SetWindowAnimationType(WindowAnimationType aType) override;
     virtual void SetDrawsTitle(bool aDrawTitle) override;
     virtual void SetUseBrightTitlebarForeground(bool aBrightForeground) override;
     virtual nsresult SetNonClientMargins(LayoutDeviceIntMargin& aMargins) override;
     virtual void SetWindowTitlebarColor(nscolor aColor, bool aActive) override;
     virtual void SetDrawsInTitlebar(bool aState) override;
@@ -414,14 +415,15 @@ protected:
   // Whether we are currently using native fullscreen. It could be false because
   // we are in the DOM fullscreen where we do not use the native fullscreen.
   bool                 mInNativeFullScreenMode;
 
   bool                 mIsAnimationSuppressed;
 
   bool                 mInReportMoveEvent; // true if in a call to ReportMoveEvent().
   bool                 mInResize; // true if in a call to DoResize().
+  bool                 mWindowTransformIsIdentity;
 
   int32_t              mNumModalDescendents;
   InputContext         mInputContext;
 };
 
 #endif // nsCocoaWindow_h_
--- a/widget/cocoa/nsCocoaWindow.mm
+++ b/widget/cocoa/nsCocoaWindow.mm
@@ -79,16 +79,17 @@ extern BOOL                gSomeMenuBarP
 extern "C" {
   // CGSPrivate.h
   typedef NSInteger CGSConnection;
   typedef NSInteger CGSWindow;
   typedef NSUInteger CGSWindowFilterRef;
   extern CGSConnection _CGSDefaultConnection(void);
   extern CGError CGSSetWindowShadowAndRimParameters(const CGSConnection cid, CGSWindow wid, float standardDeviation, float density, int offsetX, int offsetY, unsigned int flags);
   extern CGError CGSSetWindowBackgroundBlurRadius(CGSConnection cid, CGSWindow wid, NSUInteger blur);
+  extern CGError CGSSetWindowTransform(CGSConnection cid, CGSWindow wid, CGAffineTransform transform);
 }
 
 #define NS_APPSHELLSERVICE_CONTRACTID "@mozilla.org/appshell/appShellService;1"
 
 NS_IMPL_ISUPPORTS_INHERITED(nsCocoaWindow, Inherited, nsPIWidgetCocoa)
 
 // A note on testing to see if your object is a sheet...
 // |mWindowType == eWindowType_sheet| is true if your gecko nsIWidget is a sheet
@@ -122,16 +123,17 @@ nsCocoaWindow::nsCocoaWindow()
 , mInFullScreenTransition(false)
 , mModal(false)
 , mFakeModal(false)
 , mSupportsNativeFullScreen(false)
 , mInNativeFullScreenMode(false)
 , mIsAnimationSuppressed(false)
 , mInReportMoveEvent(false)
 , mInResize(false)
+, mWindowTransformIsIdentity(true)
 , mNumModalDescendents(0)
 {
   if ([NSWindow respondsToSelector:@selector(setAllowsAutomaticWindowTabbing:)]) {
     // Disable automatic tabbing on 10.12. We need to do this before we
     // orderFront any of our windows.
     [NSWindow setAllowsAutomaticWindowTabbing:NO];
   }
 }
@@ -2173,16 +2175,78 @@ nsCocoaWindow::SetWindowOpacity(float aO
     return;
   }
 
   [mWindow setAlphaValue:(CGFloat)aOpacity];
 
   NS_OBJC_END_TRY_ABORT_BLOCK;
 }
 
+static inline CGAffineTransform
+GfxMatrixToCGAffineTransform(const gfx::Matrix& m)
+{
+  CGAffineTransform t;
+  t.a = m._11;
+  t.b = m._12;
+  t.c = m._21;
+  t.d = m._22;
+  t.tx = m._31;
+  t.ty = m._32;
+  return t;
+}
+
+void
+nsCocoaWindow::SetWindowTransform(const gfx::Matrix& aTransform)
+{
+  NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
+
+  if (!mWindow) {
+    return;
+  }
+
+  gfx::Matrix transform = aTransform;
+
+  // aTransform is a transform that should be applied to the window relative
+  // to its regular position: If aTransform._31 is 100, then we want the
+  // window to be displayed 100 pixels to the right of its regular position.
+  // The transform that CGSSetWindowTransform accepts has a different meaning:
+  // It's used to answer the question "For the screen pixel at x,y (with the
+  // origin at the top left), what pixel in the window's buffer (again with
+  // origin top left) should be displayed at that position?"
+  // In the example above, this means that we need to call
+  // CGSSetWindowTransform with a horizontal translation of -windowPos.x - 100.
+  // So we need to invert the transform and adjust it by the window's position.
+  if (!transform.Invert()) {
+    // Treat non-invertible transforms as the identity transform.
+    transform = gfx::Matrix();
+  }
+
+  bool isIdentity = transform.IsIdentity();
+  if (isIdentity && mWindowTransformIsIdentity) {
+    return;
+  }
+
+  transform.PreTranslate(-mBounds.x, -mBounds.y);
+
+  // We also need to account for the backing scale factor: aTransform is given
+  // in device pixels, but CGSSetWindowTransform works with logical display
+  // pixels.
+  CGFloat backingScale = BackingScaleFactor();
+  transform.PreScale(backingScale, backingScale);
+  transform.PostScale(1 / backingScale, 1 / backingScale);
+
+  CGSConnection cid = _CGSDefaultConnection();
+  CGSSetWindowTransform(cid, [mWindow windowNumber],
+                        GfxMatrixToCGAffineTransform(transform));
+
+  mWindowTransformIsIdentity = isIdentity;
+
+  NS_OBJC_END_TRY_ABORT_BLOCK;
+}
+
 void nsCocoaWindow::SetShowsToolbarButton(bool aShow)
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
 
   if (mWindow)
     [mWindow setShowsToolbarButton:aShow];
 
   NS_OBJC_END_TRY_ABORT_BLOCK;
--- a/widget/nsIWidget.h
+++ b/widget/nsIWidget.h
@@ -1108,16 +1108,24 @@ class nsIWidget : public nsISupports
     /**
      * Set the opacity of the window.
      * Values need to be between 0.0f (invisible) and 1.0f (fully opaque).
      *
      * Ignored on child widgets and on non-Mac platforms.
      */
     virtual void SetWindowOpacity(float aOpacity) {}
 
+    /**
+     * Set the transform of the window. Values are in device pixels,
+     * the origin is the top left corner of the window.
+     *
+     * Ignored on child widgets and on non-Mac platforms.
+     */
+    virtual void SetWindowTransform(const mozilla::gfx::Matrix& aTransform) {}
+
     /*
      * On Mac OS X, this method shows or hides the pill button in the titlebar
      * that's used to collapse the toolbar.
      *
      * Ignored on child widgets and on non-Mac platforms.
      */
     virtual void SetShowsToolbarButton(bool aShow) = 0;