From e5159ea7a2dd2f16eb4782170f43cfb0dd5ae133 Mon Sep 17 00:00:00 2001 From: rich2014 Date: Tue, 17 Sep 2024 21:02:26 +0800 Subject: [PATCH] cocoa: fix some legacy transparent icon format issues #41131 there are two transparent formats: 1. the one with alpha channel like modern graphic formats (supported previously) 2. the other historical legacy with extra 1bit/pixel MaskBitmap (fixed this time), scaled mask supported also. --- lcl/interfaces/cocoa/cocoagdiobjects.pas | 56 +++++++++++++++++------- 1 file changed, 40 insertions(+), 16 deletions(-) diff --git a/lcl/interfaces/cocoa/cocoagdiobjects.pas b/lcl/interfaces/cocoa/cocoagdiobjects.pas index a36c7a52fa..d9b13a62b3 100644 --- a/lcl/interfaces/cocoa/cocoagdiobjects.pas +++ b/lcl/interfaces/cocoa/cocoagdiobjects.pas @@ -281,6 +281,7 @@ type procedure ReCreateHandle_IfModified(); procedure SetModified(); function CreateSubImage(const ARect: TRect): CGImageRef; + function CreateMaskImage(const ARect: TRect): CGImageRef; procedure PreMultiplyAlpha(); function GetNonPreMultipliedData(): PByte; public @@ -1080,6 +1081,22 @@ begin end; +function TCocoaBitmap.CreateMaskImage(const ARect: TRect): CGImageRef; +var + CGDataProvider: CGDataProviderRef; + Mask: CGImageRef; +begin + CGDataProvider := CGDataProviderCreateWithData(nil, FData, FDataSize, nil); + try + Mask := CGImageMaskCreate(FWidth, FHeight, FBitsPerPixel, + FBitsPerPixel, FBytesPerRow, CGDataProvider, nil, 0); + Result := CGImageCreateWithImageInRect(Mask, RectToCGRect(ARect)); + finally + CGDataProviderRelease(CGDataProvider); + CGImageRelease(Mask); + end; +end; + function TCocoaBitmap.GetColorSpace: NSString; begin if FType in [cbtMono, cbtGray] then @@ -2148,36 +2165,43 @@ function TCocoaContext.StretchDraw(X, Y, Width, Height: Integer; SrcDC: TCocoaBitmapContext; XSrc, YSrc, SrcWidth, SrcHeight: Integer; Msk: TCocoaBitmap; XMsk, YMsk: Integer; Rop: DWORD): Boolean; var - Bmp: TCocoaBitmap; - ImgRect: CGRect; - - dcWidth: Integer; - dcHeight: Integer; + dcBitmap: TCocoaBitmap; + maskImage: CGImageRef = nil; + cgImage: CGImageRef; + imageRep: NSBitmapImageRep; begin - Bmp := SrcDC.Bitmap; - if not Assigned(Bmp) then + dcBitmap := SrcDC.Bitmap; + if not Assigned(dcBitmap) then Exit(False); - dcWidth:= Max(Width,FSize.Width); - dcHeight:= Max(Height,FSize.Height); - // Make sure that bitmap is the most up-to-date - Bmp.ReCreateHandle_IfModified(); // Fix for bug 28102 + dcBitmap.ReCreateHandle_IfModified(); // Fix for bug 28102 // see https://bugs.freepascal.org/view.php?id=34197 // Bitmap context windowsofs should be used when rendering a bitmap inc(XSrc, -SrcDC.WindowOfs.X); inc(YSrc, -SrcDC.WindowOfs.Y); - CGContextSaveGState(CGContext); - if NOT SrcDC.ctx.isFlipped then begin - YSrc := Bmp.Height - (SrcHeight + YSrc); + YSrc := dcBitmap.Height - (SrcHeight + YSrc); end; - Result := DrawImageRep(GetNSRect(X, Y, Width, Height),GetNSRect(XSrc, YSrc, SrcWidth, SrcHeight), bmp.ImageRep); + imageRep:= dcBitmap.ImageRep; + if (Msk <> nil) and (Msk.Image <> nil) then begin + maskImage := Msk.CreateMaskImage(Bounds(XMsk, YMsk, SrcWidth, SrcHeight)); + cgImage:= CGImageCreateWithMask(imageRep.CGImage, maskImage); + imageRep:= NSBitmapImageRep.alloc.initWithCGImage(cgImage); + end; - CGContextRestoreGState(CGContext); + Result := DrawImageRep( GetNSRect(X, Y, Width, Height), + GetNSRect(XSrc, YSrc, SrcWidth, SrcHeight), + imageRep ); + + if Assigned(maskImage) then begin + imageRep.release; + CGImageRelease(cgImage); + CGImageRelease(maskImage); + end; AttachedBitmap_SetModified(); end;