cocoa: improve text out drawing, implemented ref-counting for gdi objects

git-svn-id: trunk@27255 -
This commit is contained in:
dmitry 2010-09-02 22:35:04 +00:00
parent 4475bded43
commit ea83850a40
4 changed files with 150 additions and 25 deletions

View File

@ -15,7 +15,12 @@ uses
type type
{ TCocoaGDIObject } { TCocoaGDIObject }
TCocoaGDIObject = class(TObject); TCocoaGDIObject = class(TObject)
public
RefCount: Integer;
procedure AddRef;
procedure Release;
end;
TCocoaRegionType = (crt_Empty, crt_Rectangle, crt_Complex); TCocoaRegionType = (crt_Empty, crt_Rectangle, crt_Complex);
TCocoaCombine = (cc_And, cc_Xor, cc_Or, cc_Diff, cc_Copy); TCocoaCombine = (cc_And, cc_Xor, cc_Or, cc_Diff, cc_Copy);
@ -85,7 +90,7 @@ type
procedure SetText(UTF8Text: PChar; ByteSize: Integer); virtual; abstract; procedure SetText(UTF8Text: PChar; ByteSize: Integer); virtual; abstract;
function GetSize: TSize; virtual; abstract; function GetSize: TSize; virtual; abstract;
procedure Draw(cg: CGContextRef; X, Y: Integer; DX: PInteger; DXCount: Integer); virtual; abstract; procedure Draw(cg: CGContextRef; X, Y: Integer; DX: PInteger); virtual; abstract;
end; end;
TCocoaTextLayoutClass = class of TCocoaTextLayout; TCocoaTextLayoutClass = class of TCocoaTextLayout;
@ -360,7 +365,7 @@ begin
CGContextTranslateCTM(cg, 0, -ContextSize.cy); CGContextTranslateCTM(cg, 0, -ContextSize.cy);
fText.SetText(UTF8Chars, Count); fText.SetText(UTF8Chars, Count);
fText.Draw(cg, X, ContextSize.cy-Y, CharsDelta, Count); fText.Draw(cg, X, ContextSize.cy-Y, CharsDelta);
CGContextTranslateCTM(cg, 0, ContextSize.cy); CGContextTranslateCTM(cg, 0, ContextSize.cy);
CGContextScaleCTM(cg, 1, -1); CGContextScaleCTM(cg, 1, -1);
@ -536,7 +541,6 @@ end;
------------------------------------------------------------------------------} ------------------------------------------------------------------------------}
procedure TCocoaRegion.Apply(cg: CGContextRef); procedure TCocoaRegion.Apply(cg: CGContextRef);
begin begin
exit;
if not Assigned(cg) then Exit; if not Assigned(cg) then Exit;
if HIShapeIsEmpty(FShape) or (HIShapeReplacePathInCGContext(FShape, cg)<>noErr) then if HIShapeIsEmpty(FShape) or (HIShapeReplacePathInCGContext(FShape, cg)<>noErr) then
Exit; Exit;
@ -661,4 +665,17 @@ begin
inherited Create; inherited Create;
end; end;
{ TCocoaGDIObject }
procedure TCocoaGDIObject.AddRef;
begin
if RefCount>=0 then inc(RefCount);
end;
procedure TCocoaGDIObject.Release;
begin
if RefCount>0 then Dec(RefCount)
else if RefCount=0 then Free;
end;
end. end.

View File

@ -1,4 +1,5 @@
unit CocoaTextLayout; unit CocoaTextLayout;
//todo: Implement TCoreTextLayout using CoreText API for newer OSes
interface interface
@ -14,10 +15,12 @@ type
// legacy layout used for Mac OS X 10.4 // legacy layout used for Mac OS X 10.4
TASTUITextLayout = class(TCocoaTextLayout) TASTUITextLayout = class(TCocoaTextLayout)
private private
fBuffer : WideString; fBuffer : WideString;
fUTF8 : String; fUTF8 : String;
FLayout : ATSUTextLayout; FDX : PIntegerArray;
FStyle : ATSUStyle;
FLayout : ATSUTextLayout;
FStyle : ATSUStyle;
FTextBefore : ATSUTextMeasurement; FTextBefore : ATSUTextMeasurement;
FTextAfter : ATSUTextMeasurement; FTextAfter : ATSUTextMeasurement;
@ -26,18 +29,18 @@ type
FValidSize : Boolean; FValidSize : Boolean;
procedure RecountSize; procedure RecountSize;
procedure DoJustify(iLineRef: ATSULineRef; var Handled: Boolean);
public public
constructor Create; override; constructor Create; override;
destructor Destroy; override; destructor Destroy; override;
procedure SetFont(AFont: TCocoaFont); override; procedure SetFont(AFont: TCocoaFont); override;
procedure SetText(UTF8Text: PChar; ByteSize: Integer); override; procedure SetText(UTF8Text: PChar; ByteSize: Integer); override;
function GetSize: TSize; override; function GetSize: TSize; override;
procedure Draw(cg: CGContextRef; X, Y: Integer; DX: PInteger; DXCount: Integer); override; procedure Draw(cg: CGContextRef; X, Y: Integer; DX: PInteger); override;
end; end;
{ TCoreTextLayout } { TCoreTextLayout }
//todo: use CoreText for newer OSes
//TCoreTextLayout = class(TCocoaTextLayout); //TCoreTextLayout = class(TCocoaTextLayout);
implementation implementation
@ -183,13 +186,66 @@ begin
Result.cy := FixToInt(FDescent + FAscent); Result.cy := FixToInt(FDescent + FAscent);
end; end;
procedure TASTUITextLayout.Draw(cg:CGContextRef;X,Y:Integer;DX:PInteger;DXCount: Integer);
var var
MX, MY : Integer; ATSUDirectUPP : ATSUDirectLayoutOperationOverrideUPP = nil; //NewATSUDirectLayoutOperationOverrideUPP(@ATSUCallback)
function ATSUCallback(iCurrentOperation: ATSULayoutOperationSelector; iLineRef: ATSULineRef; iRefCon: UInt32; iOperationCallbackParameterPtr: UnivPtr;
var oCallbackStatus: ATSULayoutOperationCallbackStatus ): OSStatus; {$ifdef DARWIN}mwpascal;{$endif}
var
Buffer : TASTUITextLayout;
Handled : Boolean;
begin
Result := noErr;
Buffer := TASTUITextLayout(iRefCon);
oCallbackStatus:=kATSULayoutOperationCallbackStatusHandled;
if Assigned(Buffer) then
Buffer.DoJustify(iLineRef, Handled);
end;
procedure TASTUITextLayout.DoJustify(iLineRef: ATSULineRef; var Handled: Boolean);
type
ATSLayoutRecord1 = packed record
glyphID: ATSGlyphRef;
flags: ATSGlyphInfoFlags;
originalOffset: ByteCount;
realPos: Fixed;
end;
type
TATSLayoutRecordArray = array [Word] of ATSLayoutRecord1;
PATSLayoutRecordArray = ^TATSLayoutRecordArray;
var
i, ofs : Integer;
Layouts : PATSLayoutRecordArray;
LayCount : ItemCount;
begin
if not Assigned(FDX) then Exit;
Laycount:=0;
ATSUDirectGetLayoutDataArrayPtrFromLineRef( iLineRef,
kATSUDirectDataLayoutRecordATSLayoutRecordVersion1, true, @Layouts, Laycount);
if Assigned(Layouts) and (Laycount>0) then
begin
ofs:=0;
for i:=0 to LayCount-1 do
begin
Layouts^[i].realPos:=Long2Fix(ofs);
inc(ofs, FDX^[i]);
end;
end;
ATSUDirectReleaseLayoutDataArrayPtr(iLineRef, kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, @Layouts );
Handled:=True;
end;
procedure TASTUITextLayout.Draw(cg:CGContextRef;X,Y:Integer;DX:PInteger);
var
MX, MY : Integer;
Tag : ATSUAttributeTag; Tag : ATSUAttributeTag;
DataSize : ByteCount; Size : ByteCount;
PValue : ATSUAttributeValuePtr; Value : ATSUAttributeValuePtr;
OverSpec : ATSULayoutOperationOverrideSpecifier;
begin begin
if not Assigned(cg) then Exit; if not Assigned(cg) then Exit;
if not FValidSize then RecountSize; if not FValidSize then RecountSize;
@ -197,22 +253,43 @@ begin
MX:=0; MX:=0;
MY:=0; MY:=0;
Tag := kATSUCGContextTag; Tag := kATSUCGContextTag;
DataSize := sizeOf(CGContextRef); Size := sizeOf(CGContextRef);
PValue := @cg; Value := @cg;
ATSUSetLayoutControls(FLayout, 1, @Tag, @DataSize, @PValue); ATSUSetLayoutControls(FLayout, 1, @Tag, @Size, @Value);
Tag := kATSULayoutOperationOverrideTag;
Size := sizeof (ATSULayoutOperationOverrideSpecifier);
Value := @OverSpec;
FillChar(OverSpec, sizeof(OverSpec), 0);
if Assigned(Dx) then begin
FDX := PIntegerArray(Dx);
OverSpec.operationSelector := kATSULayoutOperationPostLayoutAdjustment;
if not Assigned(ATSUDirectUPP) then ATSUDirectUPP:=NewATSUDirectLayoutOperationOverrideUPP(@ATSUCallback);
OverSpec.overrideUPP := ATSUDirectUPP;
end else
FDX:=nil;
ATSUSetLayoutControls (FLayout, 1, @Tag, @Size, @Value);
ATSUDrawText(FLayout, kATSUFromTextBeginning, kATSUToTextEnd, ATSUDrawText(FLayout, kATSUFromTextBeginning, kATSUToTextEnd,
IntToFix(X)- FTextBefore + MX, IntToFix(Y) - FAscent + MY); IntToFix(X)- FTextBefore + MX, IntToFix(Y) - FAscent + MY);
end; end;
procedure InitTextLayout; procedure InitTextLayout;
begin begin
if not Assigned(TextLayoutClass) then if not Assigned(TextLayoutClass) then begin
TextLayoutClass:=TASTUITextLayout; TextLayoutClass:=TASTUITextLayout;
end;
end;
procedure ReleaseTextLayout;
begin
if Assigned(ATSUDirectUPP) then DisposeATSUDirectLayoutOperationOverrideUPP(ATSUDirectUPP);
end; end;
initialization initialization
InitTextLayout; InitTextLayout;
finalization
ReleaseTextLayout;
end. end.

View File

@ -246,6 +246,15 @@ end;
{------------------------------- DEVICE CONTEXT -------------------------------} {------------------------------- DEVICE CONTEXT -------------------------------}
function TCocoaWidgetSet.DeleteObject(GDIObject: HGDIOBJ): Boolean;
var
gdi: TCocoaGDIObject;
begin
Result:=True;
gdi:=CheckGDIOBJ(GdiObject);
if Assigned(gdi) then gdi.Release;
end;
function TCocoaWidgetSet.SelectObject(ADC: HDC; GDIObj: HGDIOBJ): HGDIOBJ; function TCocoaWidgetSet.SelectObject(ADC: HDC; GDIObj: HGDIOBJ): HGDIOBJ;
var var
dc: TCocoaContext; dc: TCocoaContext;
@ -285,6 +294,9 @@ begin
//TCarbonBitmapContext(ADC).Bitmap := TCarbonBitmap(GDIObj); //TCarbonBitmapContext(ADC).Bitmap := TCarbonBitmap(GDIObj);
end; end;
if Result<>0 then TCocoaGDIObject(Result).Release;
if Assigned(gdi) then gdi.AddRef;
{$IFDEF VerboseWinAPI} {$IFDEF VerboseWinAPI}
DebugLn('TCocoaWidgetSet.SelectObject Result: ' + DbgS(Result)); DebugLn('TCocoaWidgetSet.SelectObject Result: ' + DbgS(Result));
{$ENDIF} {$ENDIF}
@ -316,7 +328,27 @@ begin
{$ENDIF} {$ENDIF}
end; end;
{------------------------------------ TEXT ------------------------------------} {------------------------------- FONT AND TEXT --------------------------------}
function TCocoaWidgetSet.CreateFontIndirect(const LogFont: TLogFont): HFONT;
begin
Result:=CreateFontIndirectEx(LogFont, LogFont.lfFaceName);
end;
function TCocoaWidgetSet.CreateFontIndirectEx(const LogFont: TLogFont; const LongFontName: string): HFONT;
var
cf : TCocoaFont;
begin
cf:=TCocoaFont.Create;
cf.Size:=LogFont.lfHeight;
cf.Name:=LongFontName;
if LogFont.lfWeight>FW_NORMAL then Include(cf.Style, cfs_Bold);
if LogFont.lfItalic>0 then Include(cf.Style, cfs_Italic);
if LogFont.lfUnderline>0 then Include(cf.Style, cfs_Underline);
if LogFont.lfStrikeOut>0 then Include(cf.Style, cfs_Strikeout);
cf.Antialiased:=logFont.lfQuality>=ANTIALIASED_QUALITY;
Result:=HFONT(cf);
end;
function TCocoaWidgetSet.ExtTextOut(DC: HDC; X, Y: Integer; Options: Longint; Rect: PRect; Str: PChar; Count: Longint; Dx: PInteger): Boolean; function TCocoaWidgetSet.ExtTextOut(DC: HDC; X, Y: Integer; Options: Longint; Rect: PRect; Str: PChar; Count: Longint; Dx: PInteger): Boolean;
var var
@ -334,5 +366,4 @@ begin
Result:=ExtTextOut(DC, X, Y, 0, nil, Str, Count, nil); Result:=ExtTextOut(DC, X, Y, 0, nil, Str, Count, nil);
end; end;
//##apiwiz##eps## // Do not remove, no wizard declaration after this line //##apiwiz##eps## // Do not remove, no wizard declaration after this line

View File

@ -54,18 +54,18 @@ function CreateBrushIndirect(const LogBrush: TLogBrush): HBRUSH; override;
function CreateCaret(Handle : HWND; Bitmap : hBitmap; Width, Height : Integer) : Boolean; override; function CreateCaret(Handle : HWND; Bitmap : hBitmap; Width, Height : Integer) : Boolean; override;
function CreateCompatibleBitmap(DC: HDC; Width, Height: Integer): HBITMAP; override; function CreateCompatibleBitmap(DC: HDC; Width, Height: Integer): HBITMAP; override;
function CreateCompatibleDC(DC: HDC): HDC; override; function CreateCompatibleDC(DC: HDC): HDC; override;
function CreateEllipticRgn(p1, p2, p3, p4: Integer): HRGN; override; function CreateEllipticRgn(p1, p2, p3, p4: Integer): HRGN; override;}
function CreateFontIndirect(const LogFont: TLogFont): HFONT; override; function CreateFontIndirect(const LogFont: TLogFont): HFONT; override;
function CreateFontIndirectEx(const LogFont: TLogFont; const LongFontName: string): HFONT; override; function CreateFontIndirectEx(const LogFont: TLogFont; const LongFontName: string): HFONT; override;
function CreateIconIndirect(IconInfo: PIconInfo): HICON; override;} {function CreateIconIndirect(IconInfo: PIconInfo): HICON; override;}
function CreatePenIndirect(const LogPen: TLogPen): HPEN; override; function CreatePenIndirect(const LogPen: TLogPen): HPEN; override;
function CreatePolygonRgn(Points: PPoint; NumPts: Integer; FillMode: integer): HRGN; override; function CreatePolygonRgn(Points: PPoint; NumPts: Integer; FillMode: integer): HRGN; override;
function CreateRectRgn(X1, Y1, X2, Y2: Integer): HRGN; override; function CreateRectRgn(X1, Y1, X2, Y2: Integer): HRGN; override;
{ {
procedure DeleteCriticalSection(var CritSection: TCriticalSection); override; procedure DeleteCriticalSection(var CritSection: TCriticalSection); override;
function DeleteDC(hDC: HDC): Boolean; override; function DeleteDC(hDC: HDC): Boolean; override;}
function DeleteObject(GDIObject: HGDIOBJ): Boolean; override; function DeleteObject(GDIObject: HGDIOBJ): Boolean; override;
function DestroyCaret(Handle : HWND): Boolean; override; {function DestroyCaret(Handle : HWND): Boolean; override;
function DestroyIcon(Handle: HICON): Boolean; override; function DestroyIcon(Handle: HICON): Boolean; override;
function DPtoLP(DC: HDC; var Points; Count: Integer): BOOL; override; function DPtoLP(DC: HDC; var Points; Count: Integer): BOOL; override;
function DrawFocusRect(DC: HDC; const Rect: TRect): boolean; override; function DrawFocusRect(DC: HDC; const Rect: TRect): boolean; override;