Bug 1491442 - Make nsChildView create a NativeLayerRootCA and fill it with content when painting using BasicLayers (which used to go through drawRect). r=mattwoodrow
authorMarkus Stange <mstange@themasta.com>
Fri, 16 Aug 2019 01:13:35 +0000
changeset 488410 7711755e979e4ef6a37d0fec4bf3de41e8e4d148
parent 488409 cf2547ffbfd4d065c691e00255ce8fdda5396cb3
child 488411 5aa5080461f8910b5b3e131f7164d236536aaf79
push id113908
push userccoroiu@mozilla.com
push dateFri, 16 Aug 2019 09:57:53 +0000
treeherdermozilla-inbound@83fad6abe38a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmattwoodrow
bugs1491442
milestone70.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1491442 - Make nsChildView create a NativeLayerRootCA and fill it with content when painting using BasicLayers (which used to go through drawRect). r=mattwoodrow This makes context menus work. Regular windows are still blank at this point. This introduces a visual regression on 10.9: context menus and panels now no longer have a shadow. Only 10.10 and above support shadows on transparent windows that use CoreAnimation; 10.9 is not able to obtain the shadow shape on those types of windows. I think this is an acceptable regression to take. We want to use CoreAnimation for all window types because it simplifies the code (no need to handle two paths) and because it avoids expensive mode switches if we realize too late that a window we just opened is supposed to use CoreAnimation. Differential Revision: https://phabricator.services.mozilla.com/D40516
widget/cocoa/moz.build
widget/cocoa/nsChildView.h
widget/cocoa/nsChildView.mm
--- a/widget/cocoa/moz.build
+++ b/widget/cocoa/moz.build
@@ -163,8 +163,12 @@ RESOURCE_FILES.touchbar += [
 # an attribute with the correct name.
 RESOURCE_FILES.__setattr__('MainMenu.nib', [
     'resources/MainMenu.nib/classes.nib',
     'resources/MainMenu.nib/info.nib',
     'resources/MainMenu.nib/keyedobjects.nib',
 ])
 
 CXXFLAGS += CONFIG['TK_CFLAGS']
+
+OS_LIBS += [
+    '-framework IOSurface',
+]
--- a/widget/cocoa/nsChildView.h
+++ b/widget/cocoa/nsChildView.h
@@ -24,16 +24,17 @@
 #include "nsRegion.h"
 #include "mozilla/MouseEvents.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/webrender/WebRenderTypes.h"
 
 #include "nsString.h"
 #include "nsIDragService.h"
 #include "ViewRegion.h"
+#include "CFTypeRefPtr.h"
 
 #import <Carbon/Carbon.h>
 #import <Cocoa/Cocoa.h>
 #import <AppKit/NSOpenGL.h>
 
 class nsChildView;
 class nsCocoaWindow;
 
@@ -45,16 +46,18 @@ namespace mozilla {
 class InputData;
 class PanGestureInput;
 class SwipeTracker;
 struct SwipeEventQueue;
 class VibrancyManager;
 namespace layers {
 class GLManager;
 class IAPZCTreeManager;
+class NativeLayerRootCA;
+class NativeLayerCA;
 }  // namespace layers
 namespace widget {
 class RectTextureImage;
 class WidgetRenderingContext;
 }  // namespace widget
 }  // namespace mozilla
 
 @class PixelHostingView;
@@ -455,16 +458,20 @@ class nsChildView final : public nsBaseW
   virtual bool DispatchWindowEvent(mozilla::WidgetGUIEvent& event);
 
   void WillPaintWindow();
   bool PaintWindow(LayoutDeviceIntRegion aRegion);
   bool PaintWindowInDrawTarget(mozilla::gfx::DrawTarget* aDT, const LayoutDeviceIntRegion& aRegion,
                                const mozilla::gfx::IntSize& aSurfaceSize);
   bool PaintWindowInContext(CGContextRef aContext, const LayoutDeviceIntRegion& aRegion,
                             mozilla::gfx::IntSize aSurfaceSize);
+  bool PaintWindowInIOSurface(CFTypeRefPtr<IOSurfaceRef> aSurface,
+                              const LayoutDeviceIntRegion& aInvalidRegion);
+
+  void PaintWindowInContentLayer();
   void HandleMainThreadCATransaction();
 
 #ifdef ACCESSIBILITY
   already_AddRefed<mozilla::a11y::Accessible> GetDocumentAccessible();
 #endif
 
   virtual void CreateCompositor() override;
   virtual void PrepareWindowEffects() override;
@@ -657,16 +664,23 @@ class nsChildView final : public nsBaseW
 
   bool mPluginFocused;
 
   // Used in BasicCompositor OMTC mode. Presents the BasicCompositor result
   // surface to the screen using an OpenGL context.
   // Always null if StaticPrefs::gfx_core_animation_enabled_AtStartup() is true.
   mozilla::UniquePtr<GLPresenter> mGLPresenter;
 
+  RefPtr<mozilla::layers::NativeLayerRootCA> mNativeLayerRoot;
+
+  // The CoreAnimation layer that contains the rendering from Gecko. This is a
+  // sublayer of mNativeLayerRoot's underlying wrapper layer.
+  // Always null if StaticPrefs::gfx_core_animation_enabled_AtStartup() is false.
+  RefPtr<mozilla::layers::NativeLayerCA> mContentLayer;
+
   mozilla::UniquePtr<mozilla::VibrancyManager> mVibrancyManager;
   RefPtr<mozilla::SwipeTracker> mSwipeTracker;
   mozilla::UniquePtr<mozilla::SwipeEventQueue> mSwipeEventQueue;
 
   // Only used for drawRect-based painting in popups.
   // Always null if StaticPrefs::gfx_core_animation_enabled_AtStartup() is true.
   RefPtr<mozilla::gfx::DrawTarget> mBackingSurface;
 
--- a/widget/cocoa/nsChildView.mm
+++ b/widget/cocoa/nsChildView.mm
@@ -6,16 +6,18 @@
 #include "mozilla/ArrayUtils.h"
 
 #include "mozilla/Logging.h"
 #include "mozilla/Unused.h"
 
 #include <unistd.h>
 #include <math.h>
 
+#include <IOSurface/IOSurface.h>
+
 #include "nsChildView.h"
 #include "nsCocoaWindow.h"
 
 #include "mozilla/MiscEvents.h"
 #include "mozilla/MouseEvents.h"
 #include "mozilla/PresShell.h"
 #include "mozilla/TextEvents.h"
 #include "mozilla/TouchEvents.h"
@@ -73,16 +75,17 @@
 #include "mozilla/layers/APZInputBridge.h"
 #include "mozilla/layers/APZThreadUtils.h"
 #include "mozilla/layers/GLManager.h"
 #include "mozilla/layers/CompositorOGL.h"
 #include "mozilla/layers/CompositorBridgeParent.h"
 #include "mozilla/layers/BasicCompositor.h"
 #include "mozilla/layers/InputAPZContext.h"
 #include "mozilla/layers/IpcResourceUpdateQueue.h"
+#include "mozilla/layers/NativeLayerCA.h"
 #include "mozilla/layers/WebRenderBridgeChild.h"
 #include "mozilla/layers/WebRenderLayerManager.h"
 #include "mozilla/webrender/WebRenderAPI.h"
 #include "mozilla/widget/CompositorWidget.h"
 #include "gfxUtils.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/gfx/BorrowedContext.h"
 #include "mozilla/gfx/MacIOSurface.h"
@@ -350,16 +353,20 @@ nsChildView::~nsChildView() {
   for (nsIWidget* kid = mLastChild; kid;) {
     nsChildView* childView = static_cast<nsChildView*>(kid);
     kid = kid->GetPrevSibling();
     childView->ResetParent();
   }
 
   NS_WARNING_ASSERTION(mOnDestroyCalled, "nsChildView object destroyed without calling Destroy()");
 
+  if (StaticPrefs::gfx_core_animation_enabled_AtStartup()) {
+    mNativeLayerRoot->RemoveLayer(mContentLayer);  // safe if already removed
+  }
+
   DestroyCompositor();
 
   // An nsChildView object that was in use can be destroyed without Destroy()
   // ever being called on it.  So we also need to do a quick, safe cleanup
   // here (it's too late to just call Destroy(), which can cause crashes).
   // It's particularly important to make sure widgetDestroyed is called on our
   // mView -- this method NULLs mView's mGeckoChild, and NULL checks on
   // mGeckoChild are used throughout the ChildView class to tell if it's safe
@@ -408,16 +415,24 @@ nsresult nsChildView::Create(nsIWidget* 
   }
 
   // create our parallel NSView and hook it up to our parent. Recall
   // that NS_NATIVE_WIDGET is the NSView.
   CGFloat scaleFactor = nsCocoaUtils::GetBackingScaleFactor(mParentView);
   NSRect r = nsCocoaUtils::DevPixelsToCocoaPoints(mBounds, scaleFactor);
   mView = [[ChildView alloc] initWithFrame:r geckoChild:this];
 
+  if (StaticPrefs::gfx_core_animation_enabled_AtStartup()) {
+    mNativeLayerRoot = NativeLayerRootCA::CreateForCALayer([mView rootCALayer]);
+    mNativeLayerRoot->SetBackingScale(scaleFactor);
+    RefPtr<NativeLayer> contentLayer = mNativeLayerRoot->CreateLayer();
+    mNativeLayerRoot->AppendLayer(contentLayer);
+    mContentLayer = contentLayer->AsNativeLayerCA();
+  }
+
   // If this view was created in a Gecko view hierarchy, the initial state
   // is hidden.  If the view is attached only to a native NSView but has
   // no Gecko parent (as in embedding), the initial state is visible.
   if (mParentWidget)
     [mView setHidden:YES];
   else
     mVisible = true;
 
@@ -804,16 +819,20 @@ void nsChildView::BackingScaleFactorChan
   if (mBackingScaleFactor == newScale) {
     return;
   }
 
   mBackingScaleFactor = newScale;
   NSRect frame = [mView frame];
   mBounds = nsCocoaUtils::CocoaRectToGeckoRectDevPix(frame, newScale);
 
+  if (StaticPrefs::gfx_core_animation_enabled_AtStartup()) {
+    mNativeLayerRoot->SetBackingScale(mBackingScaleFactor);
+  }
+
   if (mWidgetListener && !mWidgetListener->GetXULWindow()) {
     if (PresShell* presShell = mWidgetListener->GetPresShell()) {
       presShell->BackingScaleFactorChanged();
     }
   }
 }
 
 int32_t nsChildView::RoundsWidgetCoordinatesTo() {
@@ -1204,17 +1223,22 @@ static void blinkRgn(RgnHandle rgn) {
 void nsChildView::Invalidate(const LayoutDeviceIntRect& aRect) {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
 
   if (!mView || !mVisible) return;
 
   NS_ASSERTION(GetLayerManager()->GetBackendType() != LayersBackend::LAYERS_CLIENT,
                "Shouldn't need to invalidate with accelerated OMTC layers!");
 
-  [[mView pixelHostingView] setNeedsDisplayInRect:DevPixelsToCocoaPoints(aRect)];
+  if (StaticPrefs::gfx_core_animation_enabled_AtStartup()) {
+    mContentLayer->InvalidateRegionThroughoutSwapchain(aRect.ToUnknownRect());
+    [mView markLayerForDisplay];
+  } else {
+    [[mView pixelHostingView] setNeedsDisplayInRect:DevPixelsToCocoaPoints(aRect)];
+  }
 
   NS_OBJC_END_TRY_ABORT_BLOCK;
 }
 
 bool nsChildView::WidgetTypeSupportsAcceleration() {
   // We need to enable acceleration in popups which contain remote layer
   // trees, since the remote content won't be rendered at all otherwise. This
   // causes issues with transparency and drop shadows, so it should not be
@@ -1393,17 +1417,53 @@ bool nsChildView::PaintWindowInContext(C
   CGDataProviderRelease(provider);
   CGContextRestoreGState(aContext);
 
   mBackingSurface->ReleaseBits(data);
 
   return painted;
 }
 
-void nsChildView::HandleMainThreadCATransaction() {}
+bool nsChildView::PaintWindowInIOSurface(CFTypeRefPtr<IOSurfaceRef> aSurface,
+                                         const LayoutDeviceIntRegion& aInvalidRegion) {
+  RefPtr<MacIOSurface> surf = new MacIOSurface(std::move(aSurface));
+  surf->Lock(false);
+  RefPtr<gfx::DrawTarget> dt = surf->GetAsDrawTargetLocked(gfx::BackendType::SKIA);
+  bool result = PaintWindowInDrawTarget(dt, aInvalidRegion, dt->GetSize());
+  surf->Unlock(false);
+  return result;
+}
+
+void nsChildView::PaintWindowInContentLayer() {
+  mContentLayer->SetRect(GetBounds().ToUnknownRect());
+  mContentLayer->SetSurfaceIsFlipped(false);
+  CFTypeRefPtr<IOSurfaceRef> surf = mContentLayer->NextSurface();
+  if (!surf) {
+    return;
+  }
+
+  PaintWindowInIOSurface(
+      surf, LayoutDeviceIntRegion::FromUnknownRegion(mContentLayer->CurrentSurfaceInvalidRegion()));
+  mContentLayer->NotifySurfaceReady();
+}
+
+void nsChildView::HandleMainThreadCATransaction() {
+  WillPaintWindow();
+
+  if (GetLayerManager()->GetBackendType() == LayersBackend::LAYERS_BASIC) {
+    // We're in BasicLayers mode, i.e. main thread software compositing.
+    // Composite the window into our layer's surface.
+    PaintWindowInContentLayer();
+  }
+
+  // Apply the changes from mContentLayer to its underlying CALayer. Now is a
+  // good time to call this because we know we're currently inside a main thread
+  // CATransaction.
+  mNativeLayerRoot->ApplyChanges();
+}
 
 #pragma mark -
 
 void nsChildView::ReportMoveEvent() { NotifyWindowMoved(mBounds.x, mBounds.y); }
 
 void nsChildView::ReportSizeEvent() {
   if (mWidgetListener) mWidgetListener->WindowResized(this, mBounds.width, mBounds.height);
 }