winemac.drv: Use a mask layer to support window regions.

Signed-off-by: Chip Davis <cdavis@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Chip Davis 2021-09-01 09:28:21 -05:00 committed by Alexandre Julliard
parent a5cf847aa4
commit 01f027b2db
2 changed files with 45 additions and 47 deletions

View File

@ -51,8 +51,6 @@ @interface WineWindow : NSPanel <NSWindowDelegate>
NSRect wineFrame;
NSRect roundedWineFrame;
NSBezierPath* shape;
NSData* shapeData;
BOOL shapeChangedSinceLastDraw;
BOOL colorKeyed;

View File

@ -321,6 +321,22 @@ - (BOOL) layer:(CALayer*)layer shouldInheritContentsScale:(CGFloat)newScale from
#endif
@interface CAShapeLayer (WineShapeMaskExtensions)
@property(readonly, nonatomic, getter=isEmptyShaped) BOOL emptyShaped;
@end
@implementation CAShapeLayer (WineShapeMaskExtensions)
- (BOOL) isEmptyShaped
{
return CGRectEqualToRect(CGPathGetBoundingBox(self.path), CGRectZero);
}
@end
@interface WineBaseView : NSView
@end
@ -388,8 +404,6 @@ @interface WineWindow ()
@property (nonatomic) void* surface;
@property (nonatomic) pthread_mutex_t* surface_mutex;
@property (copy, nonatomic) NSBezierPath* shape;
@property (copy, nonatomic) NSData* shapeData;
@property (nonatomic) BOOL shapeChangedSinceLastDraw;
@property (readonly, nonatomic) BOOL needsTransparency;
@ -402,6 +416,8 @@ @interface WineWindow ()
@property (readonly, copy, nonatomic) NSArray* childWineWindows;
- (void) setShape:(CGPathRef)newShape;
- (void) updateForGLSubviews;
- (BOOL) becameEligibleParentOrChild;
@ -494,17 +510,6 @@ - (void) drawRect:(NSRect)rect
if ([window contentView] != self)
return;
if (window.drawnSinceShown && window.shapeChangedSinceLastDraw && window.shape && !window.colorKeyed && !window.usePerPixelAlpha)
{
[[NSColor clearColor] setFill];
NSRectFill(rect);
[window.shape addClip];
[[NSColor windowBackgroundColor] setFill];
NSRectFill(rect);
}
if (window.surface && window.surface_mutex &&
!pthread_mutex_lock(window.surface_mutex))
{
@ -517,8 +522,6 @@ - (void) drawRect:(NSRect)rect
CGContextRef context;
int i;
[window.shape addClip];
context = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
CGContextSetBlendMode(context, kCGBlendModeCopy);
CGContextSetInterpolationQuality(context, retina_on ? kCGInterpolationHigh : kCGInterpolationNone);
@ -968,7 +971,7 @@ @implementation WineWindow
@synthesize disabled, noActivate, floating, fullscreen, fakingClose, latentParentWindow, hwnd, queue;
@synthesize drawnSinceShown;
@synthesize surface, surface_mutex;
@synthesize shape, shapeData, shapeChangedSinceLastDraw;
@synthesize shapeChangedSinceLastDraw;
@synthesize colorKeyed, colorKeyRed, colorKeyGreen, colorKeyBlue;
@synthesize usePerPixelAlpha;
@synthesize imeData, commandDone;
@ -1069,8 +1072,6 @@ - (void) dealloc
[queue release];
[latentChildWindows release];
[latentParentWindow release];
[shape release];
[shapeData release];
[super dealloc];
}
@ -2011,7 +2012,7 @@ - (void) setDisabled:(BOOL)newValue
- (BOOL) needsTransparency
{
return self.shape || self.colorKeyed || self.usePerPixelAlpha ||
return self.contentView.layer.mask || self.colorKeyed || self.usePerPixelAlpha ||
(gl_surface_mode == GL_SURFACE_BEHIND && [(WineContentView*)self.contentView hasGLDescendant]);
}
@ -2033,22 +2034,27 @@ - (void) checkTransparency
}
}
- (void) setShape:(NSBezierPath*)newShape
- (void) setShape:(CGPathRef)newShape
{
if (shape == newShape) return;
CALayer* layer = [[self contentView] layer];
CAShapeLayer* mask = (CAShapeLayer*)layer.mask;
if (CGPathEqualToPath(newShape, mask.path)) return;
if (shape)
{
[[self contentView] setNeedsDisplayInRect:[shape bounds]];
[shape release];
}
if (newShape && !layer.mask)
layer.mask = mask = [CAShapeLayer layer];
else if (!newShape)
layer.mask = mask = nil;
if (mask.path)
[[self contentView] setNeedsDisplayInRect:NSRectFromCGRect(CGPathGetBoundingBox(mask.path))];
if (newShape)
[[self contentView] setNeedsDisplayInRect:[newShape bounds]];
[[self contentView] setNeedsDisplayInRect:NSRectFromCGRect(CGPathGetBoundingBox(newShape))];
shape = [newShape copy];
mask.path = newShape;
self.shapeChangedSinceLastDraw = TRUE;
[self checkTransparency];
[self checkEmptyShaped];
}
- (void) makeFocused:(BOOL)activate
@ -2245,7 +2251,8 @@ - (void) checkWineDisplayLink
- (BOOL) isEmptyShaped
{
return (self.shapeData.length == sizeof(CGRectZero) && !memcmp(self.shapeData.bytes, &CGRectZero, sizeof(CGRectZero)));
CAShapeLayer* mask = (CAShapeLayer*)[[self contentView] layer].mask;
return ([mask isEmptyShaped]);
}
- (BOOL) canProvideSnapshot
@ -2648,8 +2655,7 @@ - (void) setRetinaMode:(int)mode
[transform scaleBy:scale];
if (shape)
[shape transformUsingAffineTransform:transform];
[[self contentView] layer].mask.contentsScale = mode ? 2.0 : 1.0;
for (WineBaseView* subview in [self.contentView subviews])
{
@ -3453,25 +3459,19 @@ void macdrv_set_window_shape(macdrv_window w, const CGRect *rects, int count)
OnMainThread(^{
if (!rects || !count)
{
window.shape = nil;
window.shapeData = nil;
[window setShape:NULL];
[window checkEmptyShaped];
}
else
{
size_t length = sizeof(*rects) * count;
if (window.shapeData.length != length || memcmp(window.shapeData.bytes, rects, length))
{
NSBezierPath* path;
unsigned int i;
CGMutablePathRef path;
unsigned int i;
path = [NSBezierPath bezierPath];
for (i = 0; i < count; i++)
[path appendBezierPathWithRect:NSRectFromCGRect(cgrect_mac_from_win(rects[i]))];
window.shape = path;
window.shapeData = [NSData dataWithBytes:rects length:length];
[window checkEmptyShaped];
}
path = CGPathCreateMutable();
for (i = 0; i < count; i++)
CGPathAddRect(path, NULL, cgrect_mac_from_win(rects[i]));
[window setShape:path];
CGPathRelease(path);
}
});