cocoa: port StretchMaskBlt from carbon, fix context destruction, misc

git-svn-id: trunk@34341 -
This commit is contained in:
paul 2011-12-21 08:30:02 +00:00
parent 3f02801700
commit 47ac6db82c
7 changed files with 279 additions and 59 deletions

View File

@ -194,10 +194,10 @@ type
// Cocoa information
FbitsPerSample: NSInteger; // How many bits in each color component
FsamplesPerPixel: NSInteger;// How many color components
FImage: NSImage;
FImagerep: NSBitmapImageRep;
function GetColorSpace: NSString;
public
image: NSImage;
imagerep: NSBitmapImageRep;
constructor Create(ABitmap: TCocoaBitmap);
constructor Create(AWidth, AHeight, ADepth, ABitsPerPixel: Integer;
AAlignment: TCocoaBitmapAlignment; AType: TCocoaBitmapType;
@ -205,17 +205,19 @@ type
destructor Destroy; override;
procedure SetInfo(AWidth, AHeight, ADepth, ABitsPerPixel: Integer;
AAlignment: TCocoaBitmapAlignment; AType: TCocoaBitmapType);
function CreateSubImage(const ARect: TRect): CGImageRef;
public
property BitmapType: TCocoaBitmapType read FType;
property BitsPerPixel: Byte read FBitsPerPixel;
property BitsPerSample: NSInteger read FBitsPerSample;
property BytesPerRow: Integer read FBytesPerRow;
// property CGImage: CGImageRef read FCGImage write SetCGImage;
property Image: NSImage read FImage;
property ImageRep: NSBitmapImageRep read FImageRep;
property ColorSpace: NSString read GetColorSpace;
property Data: Pointer read FData;
property DataSize: Integer read FDataSize;
property Depth: Byte read FDepth;
// property Info: CGBitmapInfo read GetInfo;
property Width: Integer read FWidth;
property Height: Integer read FHeight;
end;
@ -301,6 +303,8 @@ type
protected
function SaveDCData: TCocoaDCData; virtual;
procedure RestoreDCData(const AData: TCocoaDCData); virtual;
procedure SetCGFillping(Ctx: CGContextRef; Width, Height: Integer);
procedure RestoreCGFillping(Ctx: CGContextRef; Width, Height: Integer);
public
ctx: NSGraphicsContext;
constructor Create;
@ -324,6 +328,10 @@ type
procedure Frame(const R: TRect);
procedure Frame3d(var ARect: TRect; const FrameWidth: integer; const Style: TBevelCut);
procedure FrameRect(const ARect: TRect; const Brush: TCocoaBrush);
function DrawCGImage(X, Y, Width, Height: Integer; CGImage: CGImageRef): Boolean;
function StretchDraw(X, Y, Width, Height: Integer; SrcDC: TCocoaContext;
XSrc, YSrc, SrcWidth, SrcHeight: Integer; Msk: TCocoaBitmap; XMsk,
YMsk: Integer; Rop: DWORD): Boolean;
function GetTextExtentPoint(AStr: PChar; ACount: Integer; var Size: TSize): Boolean;
function GetTextMetrics(var TM: TTextMetric): Boolean;
@ -358,7 +366,10 @@ type
end;
var
TextLayoutClass : TCocoaTextLayoutClass = nil;
TextLayoutClass: TCocoaTextLayoutClass = nil;
DefaultBrush: TCocoaBrush;
DefaultPen: TCocoaPen;
DefaultFont: TCocoaFont;
function CheckDC(dc: HDC): TCocoaContext;
function CheckDC(dc: HDC; Str: string): Boolean;
@ -374,17 +385,17 @@ uses
function CheckDC(dc: HDC): TCocoaContext;
begin
Result:=TCocoaContext(dc);
Result := TCocoaContext(dc);
end;
function CheckDC(dc: HDC; Str: string): Boolean;
begin
Result:=dc<>0;
Result := dc<>0;
end;
function CheckGDIOBJ(obj: HGDIOBJ): TCocoaGDIObject;
begin
Result:=TCocoaGDIObject(obj);
Result := TCocoaGDIObject(obj);
end;
function CheckBitmap(ABitmap: HBITMAP; AStr: string): Boolean;
@ -545,7 +556,7 @@ begin
[Integer(HasAlpha)]));
{$endif}
// Create the associated NSImageRep
imagerep := NSBitmapImageRep(NSBitmapImageRep.alloc.initWithBitmapDataPlanes_pixelsWide_pixelsHigh__colorSpaceName_bitmapFormat_bytesPerRow_bitsPerPixel(
FImagerep := NSBitmapImageRep(NSBitmapImageRep.alloc.initWithBitmapDataPlanes_pixelsWide_pixelsHigh__colorSpaceName_bitmapFormat_bytesPerRow_bitsPerPixel(
@FData, // planes, BitmapDataPlanes
FWidth, // width, pixelsWide
FHeight,// height, PixelsHigh
@ -560,8 +571,8 @@ begin
));
// Create the associated NSImage
image := NSImage.alloc.initWithSize(NSMakeSize(AWidth, AHeight));
image.addRepresentation(imagerep);
FImage := NSImage.alloc.initWithSize(NSMakeSize(AWidth, AHeight));
Image.addRepresentation(Imagerep);
end;
destructor TCocoaBitmap.Destroy;
@ -631,6 +642,14 @@ begin
end;
end;
function TCocoaBitmap.CreateSubImage(const ARect: TRect): CGImageRef;
begin
if ImageRep = nil then
Result := nil
else
Result := CGImageCreateWithImageInRect(ImageRep.CGImage, RectToCGRect(ARect));
end;
function TCocoaBitmap.GetColorSpace: NSString;
begin
if FType in [cbtMono, cbtGray] then
@ -879,11 +898,11 @@ begin
FBkBrush := TCocoaBrush.CreateDefault;
FTextBrush := TCocoaBrush.CreateDefault;
FBrush := TCocoaBrush.CreateDefault;
FBrush := DefaultBrush;
FBrush.AddRef;
FPen := TCocoaPen.CreateDefault;
FPen := DefaultPen;
FPen.AddRef;
FFont := TCocoaFont.CreateDefault;
FFont := DefaultFont;
FFont.AddRef;
FRegion := TCocoaRegion.CreateDefault;
FRegion.AddRef;
@ -898,29 +917,13 @@ begin
FTextBrush.Free;
if Assigned(FBrush) then
begin
FBrush.Release;
if FBrush.RefCount = 0 then
FBrush.Free;
end;
if Assigned(FPen) then
begin
FPen.Release;
if FPen.RefCount = 0 then
FPen.Free;
end;
if Assigned(FFont) then
begin
FFont.Release;
if FFont.RefCount = 0 then
FFont.Free;
end;
if Assigned(FRegion) then
begin
FRegion.Release;
if FRegion.RefCount = 0 then
FRegion.Free;
end;
FClipRegion.Free;
FSavedDCList.Free;
FText.Free;
@ -1220,6 +1223,162 @@ begin
end;
end;
procedure TCocoaContext.SetCGFillping(Ctx: CGContextRef; Width, Height: Integer);
begin
if Width < 0 then
begin
CGContextTranslateCTM(Ctx, -Width, 0);
CGContextScaleCTM(Ctx, -1, 1);
end;
if Height < 0 then
begin
CGContextTranslateCTM(Ctx, 0, -Height);
CGContextScaleCTM(Ctx, 1, -1);
end;
end;
procedure TCocoaContext.RestoreCGFillping(Ctx: CGContextRef; Width, Height: Integer);
begin
if Height < 0 then
begin
CGContextTranslateCTM(Ctx, 0, Height);
CGContextScaleCTM(Ctx, 1, -1);
end;
if Width < 0 then
begin
CGContextScaleCTM(Ctx, -1, 1);
CGContextTranslateCTM(Ctx, Width, 0);
end;
end;
function TCocoaContext.DrawCGImage(X, Y, Width, Height: Integer;
CGImage: CGImageRef): Boolean;
begin
Result := False;
// save dest context
ctx.saveGraphicsState;
CGContextSetBlendMode(CGContext, kCGBlendModeNormal);
try
SetCGFillping(CGContext, Width, Height);
CGContextDrawImage(CGContext, GetCGRectSorted(X, Y, X + Width, Y + Height), CGImage);
RestoreCGFillping(CGContext, Width, Height);
finally
ctx.restoreGraphicsState;
end;
Result := True;
end;
function TCocoaContext.StretchDraw(X, Y, Width, Height: Integer;
SrcDC: TCocoaContext; XSrc, YSrc, SrcWidth, SrcHeight: Integer;
Msk: TCocoaBitmap; XMsk, YMsk: Integer; Rop: DWORD): Boolean;
var
Image, MskImage: CGImageRef;
SubImage, SubMask: Boolean;
Bmp: TCocoaBitmap;
LayRect, DstRect: CGRect;
ImgRect: CGRect;
LayerContext: CGContextRef;
Layer: CGLayerRef;
UseLayer: Boolean;
begin
Result := False;
Bmp := SrcDC.Bitmap;
if Assigned(Bmp) then
Image := Bmp.ImageRep.CGImage
else
Image := nil;
if Image = nil then Exit;
DstRect := CGRectMake(X, Y, Abs(Width), Abs(Height));
SubMask := (Msk <> nil)
and (Msk.Image <> nil)
and ( (XMsk <> 0)
or (YMsk <> 0)
or (Msk.Width <> SrcWidth)
or (Msk.Height <> SrcHeight));
SubImage := ((Msk <> nil) and (Msk.Image <> nil))
or (XSrc <> 0)
or (YSrc <> 0)
or (SrcWidth <> Bmp.Width)
or (SrcHeight <> Bmp.Height);
if SubMask then
MskImage := Msk.CreateSubImage(Bounds(XMsk, YMsk, SrcWidth, SrcHeight))
else
if Assigned(Msk) then
MskImage := Msk.ImageRep.CGImage
else
MskImage := nil;
if SubImage then
Image := Bmp.CreateSubImage(Bounds(XSrc, YSrc, SrcWidth, SrcHeight));
UseLayer:=Assigned(MskImage)
or (CGImageGetWidth(Image)<>SrcWidth)
or (CGImageGetHeight(Image)<>SrcHeight);
try
if not UseLayer then
begin
// Normal drawing
Result := DrawCGImage(X, Y, Width, Height, Image);
end
else
begin
// use temp layer to mask source image
// todo find a way to mask "hard" when stretching, now some soft remains are visible
LayRect := CGRectMake(0, 0, SrcWidth, SrcHeight);
Layer := CGLayerCreateWithContext(SrcDC.CGContext, LayRect.size, nil);
// the sub-image is out of edges
if (CGImageGetWidth(Image)<>SrcWidth) or (CGImageGetHeight(Image)<>SrcHeight) then
begin
with ImgRect do
if XSrc<0 then origin.x:=SrcWidth-CGImageGetWidth(Image) else origin.x:=0;
with ImgRect do
if YSrc<0 then origin.y:=0 else origin.y:=SrcHeight-CGImageGetHeight(Image);
ImgRect.size.width:=CGImageGetWidth(Image);
ImgRect.size.height:=CGImageGetHeight(Image);
end
else
ImgRect:=LayRect;
try
LayerContext := CGLayerGetContext(Layer);
CGContextScaleCTM(LayerContext, 1, -1);
CGContextTranslateCTM(LayerContext, 0, -SrcHeight);
SetCGFillping(LayerContext, Width, Height);
if Assigned(MskImage) then
CGContextClipToMask(LayerContext, ImgRect, MskImage);
CGContextDrawImage(LayerContext, ImgRect, Image);
CGContextDrawLayerInRect(CGContext, DstRect, Layer);
Result := True;
finally
CGLayerRelease(Layer);
end;
end;
finally
if SubImage then CGImageRelease(Image);
if SubMask then CGImageRelease(MskImage);
end;
end;
{------------------------------------------------------------------------------
Method: GetTextExtentPoint
Params: Str - Text string
@ -2008,4 +2167,13 @@ begin
end;
end;
initialization
DefaultBrush := TCocoaBrush.CreateDefault;
DefaultPen := TCocoaPen.CreateDefault;
DefaultFont := TCocoaFont.CreateDefault;
finalization
DefaultBrush.Free;
DefaultPen.Free;
DefaultFont.Free;
end.

View File

@ -86,9 +86,6 @@ type
function GetAppHandle: THandle; override;
public
// post message/ send message string
NSMessageWnd, NSMessageMsg, NSMessageWParam, NSMessageLParam, NSMessageResult: NSString;
constructor Create; override;
destructor Destroy; override;

View File

@ -328,9 +328,6 @@ type
implementation
uses
CocoaInt;
{ TCocoaScrollView }
function TCocoaScrollView.lclGetCallback: ICommonCallback;
@ -598,15 +595,15 @@ begin
begin
// extract message data
Message := NSMutableDictionary(event.data1);
Handle := NSNumber(Message.objectForKey(CocoaWidgetSet.NSMessageWnd)).unsignedIntegerValue;
Msg := NSNumber(Message.objectForKey(CocoaWidgetSet.NSMessageMsg)).unsignedLongValue;
WP := NSNumber(Message.objectForKey(CocoaWidgetSet.NSMessageWParam)).integerValue;
LP := NSNumber(Message.objectForKey(CocoaWidgetSet.NSMessageLParam)).integerValue;
Handle := NSNumber(Message.objectForKey(NSMessageWnd)).unsignedIntegerValue;
Msg := NSNumber(Message.objectForKey(NSMessageMsg)).unsignedLongValue;
WP := NSNumber(Message.objectForKey(NSMessageWParam)).integerValue;
LP := NSNumber(Message.objectForKey(NSMessageLParam)).integerValue;
// deliver message and set result
Obj := NSObject(Handle);
// todo: check that Obj is still a valid NSView/NSWindow
Result := NSNumber.numberWithInteger(Obj.lclDeliverMessage(Msg, WP, LP));
Message.setObject_forKey(Result, CocoaWidgetSet.NSMessageResult);
Message.setObject_forKey(Result, NSMessageResult);
Result.release;
end;
end

View File

@ -11,6 +11,9 @@ uses
const
LCLEventSubTypeMessage = MaxShort - 1;
var
// post message/send message string. Created by TCocoaWidgetSet
NSMessageWnd, NSMessageMsg, NSMessageWParam, NSMessageLParam, NSMessageResult: NSString;
type
{ NSLCLDebugExtension }
@ -25,6 +28,7 @@ const
function GetNSPoint(x,y: single): NSPoint; inline;
function GetCGRect(x1, y1, x2, y2: Integer): CGRect; inline;
function GetCGRectSorted(X1, Y1, X2, Y2: Integer): CGRect;
function RectToCGRect(const R: TRect): CGRect;
function CGRectToRect(const c: CGRect): TRect;
@ -163,6 +167,31 @@ begin
end;
end;
function GetCGRectSorted(X1, Y1, X2, Y2: Integer): CGRect;
begin
if X1 <= X2 then
begin
Result.origin.x := X1;
Result.size.width := X2 - X1;
end
else
begin
Result.origin.x := X2;
Result.size.width := X1 - X2;
end;
if Y1 <= Y2 then
begin
Result.origin.y := Y1;
Result.size.height := Y2 - Y1;
end
else
begin
Result.origin.y := Y2;
Result.size.height := Y1 - Y2;
end;
end;
function RectToCGRect(const R: TRect): CGRect;
begin
with R do

View File

@ -574,6 +574,33 @@ begin
Result:=true;
end;
function TCocoaWidgetSet.StretchBlt(DestDC: HDC; X, Y, Width, Height: Integer;
SrcDC: HDC; XSrc, YSrc, SrcWidth, SrcHeight: Integer; ROp: Cardinal
): Boolean;
begin
Result := StretchMaskBlt(DestDC, X, Y, Width, Height, SrcDC, XSrc, YSrc,
SrcWidth, SrcHeight, 0, 0, 0, Rop);
end;
function TCocoaWidgetSet.StretchMaskBlt(DestDC: HDC; X, Y, Width,
Height: Integer; SrcDC: HDC; XSrc, YSrc, SrcWidth, SrcHeight: Integer;
Mask: HBITMAP; XMask, YMask: Integer; Rop: DWORD): Boolean;
var
SrcCtx, DestCtx: TCocoaContext;
begin
DestCtx := CheckDC(DestDC);
SrcCtx := CheckDC(SrcDC);
Result := Assigned(DestCtx) and Assigned(SrcCtx);
if not Result then
Exit;
Result := DestCtx.StretchDraw(X, Y, Width, Height,
SrcCtx, XSrc, YSrc, SrcWidth, SrcHeight,
TCocoaBitmap(Mask), XMask, YMask, Rop);
end;
{------------------------------------------------------------------------------
Method: GetWindowRect
Params: Handle - Handle of window
@ -1723,4 +1750,10 @@ begin
Result := False;
end;
function TCocoaWidgetSet.RoundRect(DC: HDC; X1, Y1, X2, Y2: Integer; RX,
RY: Integer): Boolean;
begin
Result:=inherited RoundRect(DC, X1, Y1, X2, Y2, RX, RY);
end;
//##apiwiz##eps## // Do not remove, no wizard declaration after this line

View File

@ -157,7 +157,7 @@ function RectVisible(dc : hdc; const ARect: TRect) : Boolean; override;
{function ReleaseCapture : Boolean; override;
function ReleaseDC(hWnd: HWND; DC: HDC): Integer; override;}
function RestoreDC(DC: HDC; SavedDC: Integer): Boolean; override;
{function RoundRect(DC : hDC; X1, Y1, X2, Y2: Integer; RX,RY : Integer): Boolean; override;}
function RoundRect(DC: HDC; X1, Y1, X2, Y2: Integer; RX, RY : Integer): Boolean; override;
function SaveDC(DC: HDC): Integer; override;
function ScreenToClient(Handle: HWND; var P: TPoint): Integer; override;
@ -183,12 +183,12 @@ function SetTextColor(DC: HDC; Color: TColorRef): TColorRef; override;
function ShowCaret(hWnd: HWND): Boolean; override;}
function ShowScrollBar(Handle: HWND; wBar: Integer; bShow: Boolean): Boolean; override;
function ShowWindow(hWnd: HWND; nCmdShow: Integer): Boolean; override;
{function StretchBlt(DestDC: HDC; X, Y, Width, Height: Integer;
function StretchBlt(DestDC: HDC; X, Y, Width, Height: Integer;
SrcDC: HDC; XSrc, YSrc, SrcWidth, SrcHeight: Integer; ROp: Cardinal): Boolean; override;
function StretchMaskBlt(DestDC: HDC; X, Y, Width, Height: Integer;
SrcDC: HDC; XSrc, YSrc, SrcWidth, SrcHeight: Integer; Mask: HBITMAP;
XMask, YMask: Integer; Rop: DWORD): Boolean; override;
function SystemParametersInfo(uiAction: DWord; uiParam: DWord; pvParam: Pointer; fWinIni: DWord): LongBool; override;}
{function SystemParametersInfo(uiAction: DWord; uiParam: DWord; pvParam: Pointer; fWinIni: DWord): LongBool; override;}
function TextOut(DC: HDC; X,Y : Integer; Str : Pchar; Count: Integer) : Boolean; override;
function UpdateWindow(Handle: HWND): Boolean; override;

View File

@ -83,26 +83,22 @@ implementation
function AllocCustomControl(const AWinControl: TWinControl): TCocoaCustomControl;
begin
if not Assigned(AWinControl) then begin
Result:=nil;
Exit;
end;
Result:=TCocoaCustomControl(TCocoaCustomControl.alloc).init;
Result.callback:=TLCLCommonCallback.Create(Result, AWinControl);
if not Assigned(AWinControl) then
Exit(nil);
Result := TCocoaCustomControl(TCocoaCustomControl.alloc).init;
Result.callback := TLCLCommonCallback.Create(Result, AWinControl);
end;
function EmbedInScrollView(AView:NSView):TCocoaScrollView;
var
r : TRect;
p : NSView;
r: TRect;
p: NSView;
begin
if not Assigned(AView) then begin
Result:=nil;
Exit;
end;
r:=AView.lclFrame;
p:=AView.superview;
Result:=TCocoaScrollView.alloc.initWithFrame(NSNullRect);
if not Assigned(AView) then
Exit(nil);
r := AView.lclFrame;
p := AView.superview;
Result := TCocoaScrollView.alloc.initWithFrame(NSNullRect);
if Assigned(p) then p.addSubView(Result);
Result.lclSetFrame(r);
Result.setDocumentView(AView);