Closed Bug 1491445 Opened 2 years ago Closed 2 years ago

Change NSView hierarchy in preparation for CoreAnimation windows with working vibrancy


(Core :: Widget: Cocoa, enhancement, P2)




Tracking Status
firefox64 --- wontfix
firefox65 --- wontfix
firefox66 --- wontfix
firefox67 --- fixed


(Reporter: mstange, Assigned: mstange)




(4 files)

At the moment, the vibrant NSVisualEffectViews are placed *on top* of our main ChildView. This works as long as we're not using CoreAnimation layers because we can just make them transparent by replacing their drawRect method with something that doesn't paint. But once our window uses CoreAnimation, their drawRect implementation is going to be ignored anyway and they'll erase our window content.

So we need to fix the z-order somehow. The vibrant views need to go on bottom, and have the main ChildView on top.
Or maybe the NSView hierarchy should stay as it is and we can just put our window's primary CALayer on top somehow.
Or maybe we should assemble our ChildView's contents using non-overlapping vibrant and non-vibrant views, with each view getting its own CALayer, but all CALayers sharing the same IOSurface.
In my patch, I fixed this by calling `setZPosition:1` on the layer.
Priority: -- → P2
Assignee: nobody → mstange
Summary: Fix vibrancy in CoreAnimation windows → Change NSView hierarchy in preparation for CoreAnimation windows with working vibrancy
Depends on: 1527412

NSView hierarchy before:

  • window contentView
    • ChildView
      • NonDraggableView 1
      • NonDraggableView 2
      • EffectViewWithoutForegroundVibrancy 1
      • EffectViewWithoutForegroundVibrancy 2

NSView hierarchy after:

  • window contentView
    • ChildView
      • ViewRegionContainerView
        • NonDraggableView 1
        • NonDraggableView 2
      • ViewRegionContainerView
        • EffectViewWithoutForegroundVibrancy 1
        • EffectViewWithoutForegroundVibrancy 2

This allows us to give those container views a new sibling view which stays
fixed in z-order with respect to the NSViews that get created by
mNonDraggableRegion and mVibrancyManager. More specifically, I'm going to add a
view for the drawing of our ChildView ("PixelHostingView") which is going to be
a direct child of the Gecko "ChildView" and a sibling of the
ViewRegionContainerViews; the PixelHostingView needs to always stay on top of
the vibrancy views.
Without the wrapper around the vibrancy views, whenever the vibrant region
changes, a vibrant view would be placed on top of the PixelHostingView and the
order would be wrong.

Otherwise, any views inside the contentView are imbued with a vibrant effect, and
even non-NSVisualEffectView NSViews subtract from the vibrant region of any actual
vibrant views they overlap. This would cause the PixelHostingView to 'erase' the
blue context menu item highlighting.

This behavior is documented on NSVisualEffectView:

It is recommended that you enable vibrancy only in the leaf views of your view
hierarchy. Subviews inherit the vibrancy of their parent. Once enabled in a
parent view, a subview cannot turn off vibrancy. As a result, enabling
vibrancy in a parent view can lead to subviews that look incorrect if they are
not designed to take advantage of the vibrancy effect.

Depends on D19598

This has two advantages:

  • The drawing will now correctly be placed "on top" of the vibrancy views.
  • We can turn this new view into a layer-hosting view. Layer-hosting views are
    supposed to be leaf NSViews; they shouldn't have any children.

Depends on D19599

This is a clearer implementation that achieves the same thing.

Moreover, disabling the clearing by overriding drawRect wouldn't work in
CoreAnimation windows because in CoreAnimation windows, the clearing happens
through a property of the NSVisualEffectView's CALayer, and not through the
view's drawRect implementation - drawRect probably isn't even called in that

Depends on D19600

Pushed by
Wrap vibrancy and nondraggable views inside container views. r=spohl
Don't return YES from allowsVibrancy for the contentView of context menu windows. r=spohl
Move any drawing from the ChildView into a new subview called PixelHostingView. r=spohl
Make the ChildView always non-opaque and let NSVisualEffectView handle clearing of vibrant areas. r=spohl
Depends on: 1528490
You need to log in before you can comment on or make changes to this bug.