mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-08 11:36:05 +02:00
cocoa: improve text out drawing, implemented ref-counting for gdi objects
git-svn-id: trunk@27255 -
This commit is contained in:
parent
4475bded43
commit
ea83850a40
@ -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.
|
||||||
|
@ -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.
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user