From f2b683630b6da56a0dc9f9d7eed420312b9f5a22 Mon Sep 17 00:00:00 2001 From: paul Date: Tue, 13 Dec 2011 07:51:39 +0000 Subject: [PATCH] cocoa: port carbon clipping code, port carbon SaveDC, RestoreDC git-svn-id: trunk@34148 - --- lcl/interfaces/cocoa/cocoagdiobjects.pas | 228 +++++++++++++++++++++-- lcl/interfaces/cocoa/cocoaprivate.pp | 4 + lcl/interfaces/cocoa/cocoawinapi.inc | 114 +++++++----- lcl/interfaces/cocoa/cocoawinapih.inc | 12 +- lcl/interfaces/cocoa/cocoawscommon.pas | 26 ++- 5 files changed, 314 insertions(+), 70 deletions(-) diff --git a/lcl/interfaces/cocoa/cocoagdiobjects.pas b/lcl/interfaces/cocoa/cocoagdiobjects.pas index d7d2f801fd..c838bbb67b 100644 --- a/lcl/interfaces/cocoa/cocoagdiobjects.pas +++ b/lcl/interfaces/cocoa/cocoagdiobjects.pas @@ -11,7 +11,7 @@ uses MacOSAll, // for CGContextRef LCLtype, LCLProc, Graphics, CocoaAll, CocoaUtils, - Classes, Types, Math; + SysUtils, Classes, Contnrs, Types, Math; type TCocoaBitmapAlignment = ( @@ -235,29 +235,57 @@ type end; TCocoaTextLayoutClass = class of TCocoaTextLayout; + // device context data for SaveDC/RestoreDC + TCocoaDCData = class + public + CurrentFont: TCocoaFont; + CurrentBrush: TCocoaBrush; + CurrentPen: TCocoaPen; + CurrentRegion: TCocoaRegion; + + {BkColor: TColor; + BkMode: Integer; + BkBrush: TCocoaBrush; + + TextColor: TColor; + TextBrush: TCocoaBrush; + + ROP2: Integer;} + PenPos: TPoint; + end; + { TCocoaContext } TCocoaContext = class(TObject) private - FText : TCocoaTextLayout; - FBrush : TCocoaBrush; - FPen : TCocoaPen; - FFont : TCocoaFont; - FRegion : TCocoaRegion; - FBitmap : TCocoaBitmap; + FText : TCocoaTextLayout; + FBrush : TCocoaBrush; + FPen : TCocoaPen; + FFont : TCocoaFont; + FRegion : TCocoaRegion; + FBitmap : TCocoaBitmap; + FClipped: Boolean; + FClipRegion: TCocoaRegion; + FSavedDCList: TFPObjectList; + FPenPos: TPoint; procedure SetBitmap(const AValue: TCocoaBitmap); procedure SetBrush(const AValue: TCocoaBrush); procedure SetFont(const AValue: TCocoaFont); procedure SetPen(const AValue: TCocoaPen); procedure SetRegion(const AValue: TCocoaRegion); + protected + function SaveDCData: TCocoaDCData; virtual; + procedure RestoreDCData(const AData: TCocoaDCData); virtual; public ContextSize : TSize; ctx : NSGraphicsContext; - PenPos : TPoint; - Stack : Integer; TR,TG,TB : Single; constructor Create; destructor Destroy; override; + + function SaveDC: Integer; + function RestoreDC(ASavedDC: Integer): Boolean; + function InitDraw(width, height: Integer): Boolean; procedure MoveTo(x,y: Integer); @@ -275,6 +303,11 @@ type function CGContext: CGContextRef; virtual; procedure SetAntialiasing(AValue: Boolean); + function GetClipRect: TRect; + function SetClipRegion(AClipRegion: TCocoaRegion; Mode: TCocoaCombine): Integer; + function CopyClipRegion(ADstRegion: TCocoaRegion): Integer; + + property PenPos: TPoint read FPenPos write FPenPos; property Brush: TCocoaBrush read FBrush write SetBrush; property Pen: TCocoaPen read FPen write SetPen; property Font: TCocoaFont read FFont write SetFont; @@ -603,7 +636,7 @@ end; { TCocoaContext } -function TCocoaContext.CGContext:CGContextRef; +function TCocoaContext.CGContext: CGContextRef; begin Result := CGContextRef(ctx.graphicsPort); end; @@ -617,6 +650,42 @@ begin ctx.setShouldAntialias(AValue); end; +function TCocoaContext.GetClipRect: TRect; +begin + Result := CGRectToRect(CGContextGetClipBoundingBox(CGContext)); +end; + +function TCocoaContext.SetClipRegion(AClipRegion: TCocoaRegion; Mode: TCocoaCombine): Integer; +begin + if FClipped then + begin + FClipped := False; + ctx.restoreGraphicsState; + end; + + if not Assigned(AClipRegion) then + begin + HIShapeSetEmpty(FClipRegion.Shape); + Result := LCLType.NullRegion; + end + else + begin + ctx.saveGraphicsState; + FClipRegion.CombineWith(AClipRegion, Mode); + FClipRegion.Apply(Self); + FClipped := True; + Result := LCLType.ComplexRegion; + end; +end; + +function TCocoaContext.CopyClipRegion(ADstRegion: TCocoaRegion): Integer; +begin + if Assigned(ADstRegion) and ADstRegion.CombineWith(FClipRegion, cc_Copy) then + Result := LCLType.ComplexRegion + else + Result := LCLType.Error; +end; + procedure TCocoaContext.SetBitmap(const AValue: TCocoaBitmap); begin if FBitmap <> AValue then @@ -662,6 +731,75 @@ begin end; end; +function TCocoaContext.SaveDCData: TCocoaDCData; +begin + Result := TCocoaDCData.Create; + + Result.CurrentFont := FFont; + Result.CurrentBrush := FBrush; + Result.CurrentPen := FPen; + Result.CurrentRegion := FRegion; +{ + Result.BkColor := FBkColor; + Result.BkMode := FBkMode; + Result.BkBrush := FBkBrush; + + Result.TextColor := FTextColor; + Result.TextBrush := FTextBrush; + + Result.ROP2 := FROP2;} + Result.PenPos := FPenPos; +end; + +procedure TCocoaContext.RestoreDCData(const AData: TCocoaDCData); +begin + if (FFont <> AData.CurrentFont) then + begin + if (FFont <> nil) then + FFont.Release; + if (AData.CurrentFont <> nil) then + AData.CurrentFont.AddRef; + end; + FFont := AData.CurrentFont; + + if (FBrush <> AData.CurrentBrush) then + begin + if (FBrush <> nil) then + FBrush.Release; + if (AData.CurrentBrush <> nil) then + AData.CurrentBrush.AddRef; + end; + FBrush := AData.CurrentBrush; + + if (FPen <> AData.CurrentPen) then + begin + if (FPen <> nil) then + FPen.Release; + if (AData.CurrentPen <> nil) then + AData.CurrentPen.AddRef; + end; + FPen := AData.CurrentPen; + + if (FRegion <> AData.CurrentRegion) then + begin + if (FRegion <> nil) then + FRegion.Release; + if (AData.CurrentRegion <> nil) then + AData.CurrentRegion.AddRef; + end; + FRegion := AData.CurrentRegion; + +{ FBkColor := AData.BkColor; + FBkMode := AData.BkMode; + FBkBrush := AData.BkBrush; + + FTextColor := AData.TextColor; + FTextBrush := AData.TextBrush; + + FROP2 := AData.ROP2;} + FPenPos := AData.PenPos; +end; + constructor TCocoaContext.Create; begin inherited Create; @@ -673,7 +811,9 @@ begin FFont.AddRef; FRegion := TCocoaRegion.CreateDefault; FRegion.AddRef; + FClipRegion := FRegion; FText := TextLayoutClass.Create; + FClipped := False; end; destructor TCocoaContext.Destroy; @@ -702,10 +842,62 @@ begin if FRegion.RefCount = 0 then FRegion.Free; end; + FClipRegion.Free; + FSavedDCList.Free; FText.Free; inherited Destroy; end; +function TCocoaContext.SaveDC: Integer; +begin + if FClipped then + ctx.restoreGraphicsState; + + Result := 0; + + if FSavedDCList = nil then + FSavedDCList := TFPObjectList.Create(True); + + ctx.saveGraphicsState; + Result := FSavedDCList.Add(SaveDCData) + 1; + + if FClipped then + begin + ctx.saveGraphicsState; + FClipRegion.Apply(Self); + end; +end; + +function TCocoaContext.RestoreDC(ASavedDC: Integer): Boolean; +begin + if FClipped then + ctx.restoreGraphicsState; + + Result := False; + if (FSavedDCList = nil) or (ASavedDC <= 0) or (ASavedDC > FSavedDCList.Count) then + Exit; + + while FSavedDCList.Count > ASavedDC do + begin + ctx.restoreGraphicsState; + FSavedDCList.Delete(FSavedDCList.Count - 1); + end; + + ctx.restoreGraphicsState; + RestoreDCData(TCocoaDCData(FSavedDCList[ASavedDC - 1])); + FSavedDCList.Delete(ASavedDC - 1); + Result := True; + + if FSavedDCList.Count = 0 then FreeAndNil(FSavedDCList); + + if FClipped then + begin + FClipped := False; + FClipRegion.Shape := HIShapeCreateEmpty; + end; + +end; + function TCocoaContext.InitDraw(width,height:Integer): Boolean; var cg : CGContextRef; @@ -719,17 +911,17 @@ begin CGContextTranslateCTM(cg, 0, height); CGContextScaleCTM(cg, 1, -1); - PenPos.x:=0; - PenPos.y:=0; + FPenPos.x := 0; + FPenPos.y := 0; end; -procedure TCocoaContext.MoveTo(x,y:Integer); +procedure TCocoaContext.MoveTo(x, y: Integer); begin - PenPos.x:=x; - PenPos.y:=y; + FPenPos.x := x; + FPenPos.y := y; end; -procedure TCocoaContext.LineTo(x,y:Integer); +procedure TCocoaContext.LineTo(x, y: Integer); var cg : CGContextRef; p : array [0..1] of CGPoint; @@ -778,8 +970,8 @@ begin CGContextAddLines(cg, @p, 2); CGContextStrokePath(cg); - PenPos.x := X; - PenPos.y := Y; + FPenPos.x := X; + FPenPos.y := Y; end; procedure CGContextAddLCLPoints(cg: CGContextRef; const Points: array of TPoint;NumPts:Integer); diff --git a/lcl/interfaces/cocoa/cocoaprivate.pp b/lcl/interfaces/cocoa/cocoaprivate.pp index ad886fc58a..595b479000 100644 --- a/lcl/interfaces/cocoa/cocoaprivate.pp +++ b/lcl/interfaces/cocoa/cocoaprivate.pp @@ -67,6 +67,10 @@ type function lclClientFrame: TRect; message 'lclClientFrame'; reintroduce; end; + NSViewFix = objccategory external (NSView) + function fittingSize: NSSize; message 'fittingSize'; + end; + { LCLControlExtension } LCLControlExtension = objccategory(NSControl) diff --git a/lcl/interfaces/cocoa/cocoawinapi.inc b/lcl/interfaces/cocoa/cocoawinapi.inc index 0f328a72ed..d11f004ff9 100644 --- a/lcl/interfaces/cocoa/cocoawinapi.inc +++ b/lcl/interfaces/cocoa/cocoawinapi.inc @@ -357,6 +357,17 @@ begin end; end; +function TCocoaWidgetSet.ExtSelectClipRGN(dc: hdc; rgn: hrgn; Mode: Longint): Integer; +var + ctx: TCocoaContext; +begin + ctx := CheckDC(DC); + if Assigned(ctx) then + Result := ctx.SetClipRegion(TCocoaRegion(rgn), CocoaCombineMode(Mode)) + else + Result := ERROR; +end; + function TCocoaWidgetSet.ExtCreatePen(dwPenStyle, dwWidth: DWord; const lplb: TLogBrush; dwStyleCount: DWord; lpStyle: PDWord): HPEN; begin @@ -407,6 +418,8 @@ begin NSWindow(hwnd).orderOut(nil); SW_MINIMIZE: NSWindow(hwnd).miniaturize(nil); + SW_MAXIMIZE: + NSWindow(hwnd).zoom(nil); end; Result:=true; end; @@ -424,14 +437,17 @@ function TCocoaWidgetSet.GetWindowRect(Handle: hwnd; var ARect: TRect): Integer; var dx, dy: Integer; begin - if Handle<>0 then begin - ARect:=NSObject(Handle).lclFrame; - if not NSObject(Handle).isKindOfClass_(NSWindow) then begin - dx:=0; dy:=0; + if Handle <> 0 then + begin + ARect := NSObject(Handle).lclFrame; + if not NSObject(Handle).isKindOfClass_(NSWindow) then + begin + dx := 0; + dy := 0; NSObject(Handle).lclLocalToScreen(dx, dx); MoveRect(ARect, dx, dy); end; - Result:=1; + Result := 1; end else Result:=0; end; @@ -452,25 +468,49 @@ end; function TCocoaWidgetSet.GetClientBounds(handle : HWND; var ARect : TRect) : Boolean; begin - if Handle<>0 then begin - Result:=True; - ARect:=NSObject(handle).lclClientFrame; - end else - Result:=False; + Result := Handle <> 0; + if Result then + ARect := NSObject(handle).lclClientFrame; end; function TCocoaWidgetSet.GetClientRect(handle : HWND; var ARect : TRect) : Boolean; var dx, dy: Integer; begin - if Handle<>0 then begin - Result:=True; - ARect:=NSObject(handle).lclClientFrame; - dx:=0; dy:=0; + Result := Handle <> 0; + if Result then + begin + ARect := NSObject(handle).lclClientFrame; + dx := 0; + dy := 0; NSObject(Handle).lclLocalToScreen(dx, dy); MoveRect(ARect, dx, dy); - end else - Result:=False; + end; +end; + +function TCocoaWidgetSet.GetClipBox(DC: hDC; lpRect: PRect): Longint; +var + ctx: TCocoaContext; +begin + ctx := CheckDC(DC); + if Assigned(ctx) and Assigned(lpRect) then + begin + lpRect^ := ctx.GetClipRect; + Result := COMPLEXREGION; + end + else + Result := ERROR; +end; + +function TCocoaWidgetSet.GetClipRGN(DC: hDC; RGN: hRGN): Longint; +var + ctx: TCocoaContext; +begin + ctx := CheckDC(DC); + if Assigned(ctx) and (RGN <> 0) then + Result := ctx.CopyClipRegion(TCocoaRegion(RGN)) + else + Result := ERROR; end; function TCocoaWidgetSet.GetCursorPos(var lpPoint: TPoint ): Boolean; @@ -1025,43 +1065,29 @@ end; function TCocoaWidgetSet.SaveDC(DC: HDC): Integer; var - ctx : TCocoaContext; - cg : CGContextRef; + ctx: TCocoaContext; begin ctx := CheckDC(DC); - if not Assigned(ctx) then begin - Result:=0; - Exit; - end; - cg:=ctx.CGContext; - if Assigned(cg) then begin - CGContextSaveGState(cg); - inc(ctx.Stack); - Result:=ctx.Stack; - end else + if Assigned(ctx) then + Result := ctx.SaveDC + else Result:=0; end; +function TCocoaWidgetSet.SelectClipRGN(DC: hDC; RGN: HRGN): Longint; +begin + Result := ExtSelectClipRgn(DC, RGN, RGN_COPY); +end; + function TCocoaWidgetSet.RestoreDC(DC: HDC; SavedDC: Integer): Boolean; var - ctx : TCocoaContext; - cg : CGContextRef; - cnt : Integer; - i : Integer; + ctx: TCocoaContext; begin - Result:=False; ctx := CheckDC(DC); - cg:=ctx.CGContext; - if not Assigned(ctx) or not Assigned(cg) then Exit; - - if SavedDC<0 then cnt:=1 - else cnt:=ctx.Stack-SavedDC+1; - Result:=cnt>0; - - if Result then begin - for i:=1 to cnt do CGContextRestoreGState(cg); - dec(ctx.Stack, cnt); - end; + if Assigned(ctx) then + Result := ctx.RestoreDC(SavedDC) + else + Result := False; end; //##apiwiz##eps## // Do not remove, no wizard declaration after this line diff --git a/lcl/interfaces/cocoa/cocoawinapih.inc b/lcl/interfaces/cocoa/cocoawinapih.inc index 77cb38c757..356028d019 100644 --- a/lcl/interfaces/cocoa/cocoawinapih.inc +++ b/lcl/interfaces/cocoa/cocoawinapih.inc @@ -78,8 +78,8 @@ function EnableWindow(hWnd: HWND; bEnable: Boolean): Boolean; override; procedure EnterCriticalSection(var CritSection: TCriticalSection); override; function EnumFontFamiliesEx(DC: HDC; lpLogFont: PLogFont; Callback: FontEnumExProc; Lparam: LParam; Flags: dword): longint; override; function EnumDisplayMonitors(hdc: HDC; lprcClip: PRect; lpfnEnum: MonitorEnumProc; dwData: LPARAM): LongBool; override; -{function ExcludeClipRect(dc: hdc; Left, Top, Right, Bottom : Integer) : Integer; override; -function ExtSelectClipRGN(dc: hdc; rgn : hrgn; Mode : Longint) : Integer; override;} +{function ExcludeClipRect(dc: hdc; Left, Top, Right, Bottom : Integer) : Integer; override;} +function ExtSelectClipRGN(dc: hdc; rgn : hrgn; Mode : Longint) : Integer; override; function ExtCreatePen(dwPenStyle, dwWidth: DWord; const lplb: TLogBrush; dwStyleCount: DWord; lpStyle: PDWord): HPEN; override; function ExtTextOut(DC: HDC; X, Y: Integer; Options: Longint; Rect: PRect; Str: PChar; Count: Longint; Dx: PInteger): Boolean; override; @@ -96,8 +96,8 @@ function GetCaretPos(var lpPoint: TPoint): Boolean; override; function GetCaretRespondToFocus(handle: HWND; var ShowHideOnFocus: boolean): Boolean; override;} function GetClientBounds(handle : HWND; var ARect : TRect) : Boolean; override; function GetClientRect(handle : HWND; var ARect : TRect) : Boolean; override; -{function GetClipBox(DC : hDC; lpRect : PRect) : Longint; override; -function GetClipRGN(DC: hDC; RGN: hRGN): Longint; override;} +function GetClipBox(DC : hDC; lpRect : PRect) : Longint; override; +function GetClipRGN(DC: hDC; RGN: hRGN): Longint; override; function GetCursorPos(var lpPoint: TPoint ): Boolean; override; function GetDC(hWnd: HWND): HDC; override; {function GetDCOriginRelativeToWindow(PaintDC: HDC; WindowHandle: HWND; var OriginDiff: TPoint): boolean; override; @@ -158,8 +158,8 @@ function RestoreDC(DC: HDC; SavedDC: 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; -function SelectClipRGN(DC : hDC; RGN : HRGN) : Longint; override;} +{function ScreenToClient(Handle : HWND; var P : TPoint) : Integer; override;} +function SelectClipRGN(DC : hDC; RGN : HRGN) : Longint; override; function SelectObject(ADC: HDC; GDIObj: HGDIOBJ): HGDIOBJ; override; {function SendMessage(HandleWnd: HWND; Msg: Cardinal; WParam: WParam; LParam: LParam): LResult; override; function SetActiveWindow(Handle: HWND): HWND; override; diff --git a/lcl/interfaces/cocoa/cocoawscommon.pas b/lcl/interfaces/cocoa/cocoawscommon.pas index 76df72395c..c78344ebce 100644 --- a/lcl/interfaces/cocoa/cocoawscommon.pas +++ b/lcl/interfaces/cocoa/cocoawscommon.pas @@ -44,7 +44,7 @@ type { TCocoaWSWinControl } - TCocoaWSWinControl=class(TWSWinControl) + TCocoaWSWinControl = class(TWSWinControl) published class function CreateHandle(const AWinControl: TWinControl; const AParams: TCreateParams): TLCLIntfHandle; override; @@ -54,6 +54,7 @@ type class function GetClientBounds(const AWincontrol: TWinControl; var ARect: TRect): Boolean; override; class function GetClientRect(const AWincontrol: TWinControl; var ARect: TRect): Boolean; override; + class procedure GetPreferredSize(const AWinControl: TWinControl; var PreferredWidth, PreferredHeight: integer; WithThemeSpace: Boolean); override; class procedure SetBounds(const AWinControl: TWinControl; const ALeft, ATop, AWidth, AHeight: Integer); override; class procedure SetCursor(const AWinControl: TWinControl; const ACursor: HCursor); override; end; @@ -61,7 +62,7 @@ type { TCocoaWSCustomControl } - TCocoaWSCustomControl=class(TWSCustomControl) + TCocoaWSCustomControl = class(TWSCustomControl) published class function CreateHandle(const AWinControl: TWinControl; const AParams: TCreateParams): TLCLIntfHandle; override; @@ -329,6 +330,27 @@ begin ARect:=NSObject(AWinControl.Handle).lclClientFrame; end; +class procedure TCocoaWSWinControl.GetPreferredSize( + const AWinControl: TWinControl; var PreferredWidth, PreferredHeight: integer; + WithThemeSpace: Boolean); +var + Obj: NSObject; + Size: NSSize; +begin + if (AWinControl.Handle <> 0) then + begin + Obj := NSObject(AWinControl.Handle); +{ + if Obj.isKindOfClass_(NSView) then + begin + Size := NSView(Obj).fittingSize; + PreferredWidth := Round(Size.width); + PreferredHeight := Round(Size.height); + end; +} + end; +end; + class procedure TCocoaWSWinControl.SetBounds(const AWinControl: TWinControl; const ALeft, ATop, AWidth, AHeight: Integer); begin