cocoa: port carbon clipping code, port carbon SaveDC, RestoreDC

git-svn-id: trunk@34148 -
This commit is contained in:
paul 2011-12-13 07:51:39 +00:00
parent be198d094a
commit f2b683630b
5 changed files with 314 additions and 70 deletions

View File

@ -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);

View File

@ -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)

View File

@ -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

View File

@ -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;

View File

@ -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