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
{ TCocoaGDIObject }
TCocoaGDIObject = class(TObject);
TCocoaGDIObject = class(TObject)
public
RefCount: Integer;
procedure AddRef;
procedure Release;
end;
TCocoaRegionType = (crt_Empty, crt_Rectangle, crt_Complex);
TCocoaCombine = (cc_And, cc_Xor, cc_Or, cc_Diff, cc_Copy);
@ -85,7 +90,7 @@ type
procedure SetText(UTF8Text: PChar; ByteSize: Integer); 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;
TCocoaTextLayoutClass = class of TCocoaTextLayout;
@ -360,7 +365,7 @@ begin
CGContextTranslateCTM(cg, 0, -ContextSize.cy);
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);
CGContextScaleCTM(cg, 1, -1);
@ -536,7 +541,6 @@ end;
------------------------------------------------------------------------------}
procedure TCocoaRegion.Apply(cg: CGContextRef);
begin
exit;
if not Assigned(cg) then Exit;
if HIShapeIsEmpty(FShape) or (HIShapeReplacePathInCGContext(FShape, cg)<>noErr) then
Exit;
@ -661,4 +665,17 @@ begin
inherited Create;
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.

View File

@ -1,4 +1,5 @@
unit CocoaTextLayout;
//todo: Implement TCoreTextLayout using CoreText API for newer OSes
interface
@ -14,10 +15,12 @@ type
// legacy layout used for Mac OS X 10.4
TASTUITextLayout = class(TCocoaTextLayout)
private
fBuffer : WideString;
fUTF8 : String;
FLayout : ATSUTextLayout;
FStyle : ATSUStyle;
fBuffer : WideString;
fUTF8 : String;
FDX : PIntegerArray;
FLayout : ATSUTextLayout;
FStyle : ATSUStyle;
FTextBefore : ATSUTextMeasurement;
FTextAfter : ATSUTextMeasurement;
@ -26,18 +29,18 @@ type
FValidSize : Boolean;
procedure RecountSize;
procedure DoJustify(iLineRef: ATSULineRef; var Handled: Boolean);
public
constructor Create; override;
destructor Destroy; override;
procedure SetFont(AFont: TCocoaFont); override;
procedure SetText(UTF8Text: PChar; ByteSize: Integer); 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;
{ TCoreTextLayout }
//todo: use CoreText for newer OSes
//TCoreTextLayout = class(TCocoaTextLayout);
implementation
@ -183,13 +186,66 @@ begin
Result.cy := FixToInt(FDescent + FAscent);
end;
procedure TASTUITextLayout.Draw(cg:CGContextRef;X,Y:Integer;DX:PInteger;DXCount: Integer);
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;
DataSize : ByteCount;
PValue : ATSUAttributeValuePtr;
Size : ByteCount;
Value : ATSUAttributeValuePtr;
OverSpec : ATSULayoutOperationOverrideSpecifier;
begin
if not Assigned(cg) then Exit;
if not FValidSize then RecountSize;
@ -197,22 +253,43 @@ begin
MX:=0;
MY:=0;
Tag := kATSUCGContextTag;
DataSize := sizeOf(CGContextRef);
PValue := @cg;
ATSUSetLayoutControls(FLayout, 1, @Tag, @DataSize, @PValue);
Size := sizeOf(CGContextRef);
Value := @cg;
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,
IntToFix(X)- FTextBefore + MX, IntToFix(Y) - FAscent + MY);
end;
procedure InitTextLayout;
begin
if not Assigned(TextLayoutClass) then
if not Assigned(TextLayoutClass) then begin
TextLayoutClass:=TASTUITextLayout;
end;
end;
procedure ReleaseTextLayout;
begin
if Assigned(ATSUDirectUPP) then DisposeATSUDirectLayoutOperationOverrideUPP(ATSUDirectUPP);
end;
initialization
InitTextLayout;
finalization
ReleaseTextLayout;
end.

View File

@ -246,6 +246,15 @@ end;
{------------------------------- 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;
var
dc: TCocoaContext;
@ -285,6 +294,9 @@ begin
//TCarbonBitmapContext(ADC).Bitmap := TCarbonBitmap(GDIObj);
end;
if Result<>0 then TCocoaGDIObject(Result).Release;
if Assigned(gdi) then gdi.AddRef;
{$IFDEF VerboseWinAPI}
DebugLn('TCocoaWidgetSet.SelectObject Result: ' + DbgS(Result));
{$ENDIF}
@ -316,7 +328,27 @@ begin
{$ENDIF}
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;
var
@ -334,5 +366,4 @@ begin
Result:=ExtTextOut(DC, X, Y, 0, nil, Str, Count, nil);
end;
//##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 CreateCompatibleBitmap(DC: HDC; Width, Height: Integer): HBITMAP; 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 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 CreatePolygonRgn(Points: PPoint; NumPts: Integer; FillMode: integer): HRGN; override;
function CreateRectRgn(X1, Y1, X2, Y2: Integer): HRGN; 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 DestroyCaret(Handle : HWND): Boolean; override;
{function DestroyCaret(Handle : HWND): Boolean; override;
function DestroyIcon(Handle: HICON): Boolean; override;
function DPtoLP(DC: HDC; var Points; Count: Integer): BOOL; override;
function DrawFocusRect(DC: HDC; const Rect: TRect): boolean; override;