mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-28 22:20:25 +02:00
Cocoa: CocoaGDIObjects TCocoaContext.TextOut text drawing optimization, patch by David Jenkins (try 2), issue #39641
This commit is contained in:
parent
a297b6b623
commit
ffd4757217
@ -343,45 +343,6 @@ type
|
|||||||
destructor Destroy; override;
|
destructor Destroy; override;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
TGlyphArray = array of NSGlyph;
|
|
||||||
|
|
||||||
{ TCocoaTextLayout }
|
|
||||||
|
|
||||||
TCocoaTextLayout = class
|
|
||||||
strict private
|
|
||||||
FBackgroundColor: TColor;
|
|
||||||
FForegroundColor: TColor;
|
|
||||||
FLayout: NSLayoutManager;
|
|
||||||
FTextStorage: NSTextStorage;
|
|
||||||
FTextContainer: NSTextContainer;
|
|
||||||
FText: String;
|
|
||||||
FFont: TCocoaFont;
|
|
||||||
// surrogate pairs (for UTF16)
|
|
||||||
FSurr: array of NSRange;
|
|
||||||
FSurrCount: Integer;
|
|
||||||
procedure SetBackgoundColor(AValue: TColor);
|
|
||||||
procedure SetForegoundColor(AValue: TColor);
|
|
||||||
procedure SetFont(AFont: TCocoaFont);
|
|
||||||
procedure UpdateFont;
|
|
||||||
procedure UpdateColor;
|
|
||||||
function GetTextRange: NSRange;
|
|
||||||
|
|
||||||
procedure EvalSurrogate(s: NSString);
|
|
||||||
public
|
|
||||||
constructor Create;
|
|
||||||
destructor Destroy; override;
|
|
||||||
procedure SetFontToStr(dst: NSMutableAttributedString);
|
|
||||||
procedure SetText(UTF8Text: PChar; ByteSize: Integer);
|
|
||||||
function GetSize: TSize;
|
|
||||||
function GetGlyphs: TGlyphArray;
|
|
||||||
procedure Draw(ctx: NSGraphicsContext; X, Y: Integer; FillBackground: Boolean; DX: PInteger);
|
|
||||||
|
|
||||||
property Font: TCocoaFont read FFont write SetFont;
|
|
||||||
property BackgroundColor: TColor read FBackgroundColor write SetBackgoundColor;
|
|
||||||
property ForegroundColor: TColor read FForegroundColor write SetForegoundColor;
|
|
||||||
property Layout: NSLayoutManager read FLayout;
|
|
||||||
end;
|
|
||||||
|
|
||||||
{ TCocoaContext }
|
{ TCocoaContext }
|
||||||
|
|
||||||
TCocoaBitmapContext = class;
|
TCocoaBitmapContext = class;
|
||||||
@ -391,8 +352,10 @@ type
|
|||||||
FBkColor: TColor;
|
FBkColor: TColor;
|
||||||
FBkMode: Integer;
|
FBkMode: Integer;
|
||||||
FROP2: Integer;
|
FROP2: Integer;
|
||||||
FText : TCocoaTextLayout;
|
|
||||||
FBrush : TCocoaBrush;
|
FBrush : TCocoaBrush;
|
||||||
|
FBackgroundColor: TColor;
|
||||||
|
FForegroundColor: TColor;
|
||||||
|
FFont: TCocoaFont;
|
||||||
FPen : TCocoaPen;
|
FPen : TCocoaPen;
|
||||||
FRegion : TCocoaRegion;
|
FRegion : TCocoaRegion;
|
||||||
// In Cocoa there is no way to enlarge a clip region :(
|
// In Cocoa there is no way to enlarge a clip region :(
|
||||||
@ -1280,297 +1243,6 @@ begin
|
|||||||
NSCursor.arrowCursor.set_;
|
NSCursor.arrowCursor.set_;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ TCocoaTextLayout }
|
|
||||||
|
|
||||||
procedure TCocoaTextLayout.UpdateFont;
|
|
||||||
begin
|
|
||||||
SetFontToStr(FTextStorage);
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure TCocoaTextLayout.SetFontToStr(dst: NSMutableAttributedString);
|
|
||||||
const
|
|
||||||
UnderlineStyle = NSUnderlineStyleSingle or NSUnderlinePatternSolid;
|
|
||||||
var
|
|
||||||
Range: NSRange;
|
|
||||||
begin
|
|
||||||
if Assigned(FFont) then
|
|
||||||
begin
|
|
||||||
Range.location := 0;
|
|
||||||
Range.length := dst.string_.length;
|
|
||||||
if (Range.length <= 0) or (FFont.Font = nil) then Exit;
|
|
||||||
// apply font itself
|
|
||||||
dst.addAttribute_value_range(NSFontAttributeName, FFont.Font, Range);
|
|
||||||
// aply font attributes which are not in NSFont
|
|
||||||
if cfs_Underline in FFont.Style then
|
|
||||||
dst.addAttribute_value_range(NSUnderlineStyleAttributeName, NSNumber.numberWithInteger(UnderlineStyle), Range)
|
|
||||||
else
|
|
||||||
dst.removeAttribute_range(NSUnderlineStyleAttributeName, Range);
|
|
||||||
|
|
||||||
if cfs_Strikeout in FFont.Style then
|
|
||||||
dst.addAttribute_value_range(NSStrikethroughStyleAttributeName, NSNumber.numberWithInteger(UnderlineStyle), Range)
|
|
||||||
else
|
|
||||||
dst.removeAttribute_range(NSStrikethroughStyleAttributeName, Range);
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure TCocoaTextLayout.UpdateColor;
|
|
||||||
var
|
|
||||||
lForegroundColor: NSColor;
|
|
||||||
begin
|
|
||||||
lForegroundColor := SysColorToNSColor(SysColorToSysColorIndex(ForegroundColor));
|
|
||||||
if lForegroundColor = nil then
|
|
||||||
lForegroundColor := ColorToNSColor(ColorToRGB(ForegroundColor));
|
|
||||||
FTextStorage.addAttribute_value_range(NSForegroundColorAttributeName, lForegroundColor, GetTextRange);
|
|
||||||
FTextStorage.addAttribute_value_range(NSBackgroundColorAttributeName, ColorToNSColor(BackgroundColor), GetTextRange);
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TCocoaTextLayout.GetTextRange: NSRange;
|
|
||||||
begin
|
|
||||||
Result.location := 0;
|
|
||||||
Result.length := FTextStorage.length;
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure TCocoaTextLayout.EvalSurrogate(s: NSString);
|
|
||||||
var
|
|
||||||
res : NSRange;
|
|
||||||
i : integer;
|
|
||||||
ln : integer;
|
|
||||||
scnt : integer;
|
|
||||||
ch : integer;
|
|
||||||
begin
|
|
||||||
FSurrCount := 0;
|
|
||||||
i := 0;
|
|
||||||
ln := s.length;
|
|
||||||
// must analyze the string to presence of surrogate pairs.
|
|
||||||
// this is required for the use
|
|
||||||
ch := 0;
|
|
||||||
while i < ln do
|
|
||||||
begin
|
|
||||||
res := s.rangeOfComposedCharacterSequenceAtIndex(i); //s.rangeOfComposedCharacterSequencesForRange(src);
|
|
||||||
inc(i, res.length);
|
|
||||||
if res.length>1 then
|
|
||||||
begin
|
|
||||||
if length(FSurr) = FSurrCount then
|
|
||||||
begin
|
|
||||||
if FSurrCount = 0 then SetLength(FSurr, 4)
|
|
||||||
else SetLength(FSurr, FSurrCount * 2)
|
|
||||||
end;
|
|
||||||
FSurr[FSurrCount] := res;
|
|
||||||
inc(fSurrCount);
|
|
||||||
end;
|
|
||||||
inc(ch);
|
|
||||||
end;
|
|
||||||
if ((FSurrCount = 0) and (length(FSurr)<>0)) or (length(FSurr) div 2>FSurrCount) then
|
|
||||||
SetLength(FSurr, FSurrCount);
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure TCocoaTextLayout.SetForegoundColor(AValue: TColor);
|
|
||||||
begin
|
|
||||||
if FForegroundColor <> AValue then
|
|
||||||
begin
|
|
||||||
FForegroundColor := AValue;
|
|
||||||
FTextStorage.beginEditing;
|
|
||||||
UpdateColor;
|
|
||||||
FTextStorage.endEditing;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure TCocoaTextLayout.SetBackgoundColor(AValue: TColor);
|
|
||||||
begin
|
|
||||||
if FBackgroundColor <> AValue then
|
|
||||||
begin
|
|
||||||
FBackgroundColor := AValue;
|
|
||||||
FTextStorage.beginEditing;
|
|
||||||
UpdateColor;
|
|
||||||
FTextStorage.endEditing;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
constructor TCocoaTextLayout.Create;
|
|
||||||
var
|
|
||||||
LocalPool: NSAutoReleasePool;
|
|
||||||
begin
|
|
||||||
inherited Create;
|
|
||||||
LocalPool := NSAutoReleasePool.alloc.init;
|
|
||||||
FTextStorage := NSTextStorage.alloc.initWithString(NSSTR(''));
|
|
||||||
FLayout := NSLayoutManager.alloc.init;
|
|
||||||
FTextStorage.addLayoutManager(FLayout);
|
|
||||||
FTextContainer := NSTextContainer.alloc.init;
|
|
||||||
FTextContainer.setLineFragmentPadding(0);
|
|
||||||
FLayout.addTextContainer(FTextContainer);
|
|
||||||
|
|
||||||
LocalPool.release;
|
|
||||||
|
|
||||||
FFont := DefaultFont;
|
|
||||||
FFont.AddRef;
|
|
||||||
FText := '';
|
|
||||||
FBackgroundColor := clWhite;
|
|
||||||
FForegroundColor := clBlack;
|
|
||||||
end;
|
|
||||||
|
|
||||||
destructor TCocoaTextLayout.Destroy;
|
|
||||||
begin
|
|
||||||
FLayout.release;
|
|
||||||
FTextContainer.release;
|
|
||||||
FTextStorage.release;
|
|
||||||
if Assigned(FFont) then
|
|
||||||
FFont.Release;
|
|
||||||
inherited Destroy;
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure TCocoaTextLayout.SetFont(AFont: TCocoaFont);
|
|
||||||
begin
|
|
||||||
if TCocoaGDIObject.UpdateRefs(FFont, AFont) then
|
|
||||||
begin
|
|
||||||
FFont := AFont as TCocoaFont;
|
|
||||||
FTextStorage.beginEditing;
|
|
||||||
updateFont;
|
|
||||||
FTextStorage.endEditing;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure TCocoaTextLayout.SetText(UTF8Text: PChar; ByteSize: Integer);
|
|
||||||
var
|
|
||||||
NewText: String;
|
|
||||||
S: NSString;
|
|
||||||
begin
|
|
||||||
if ByteSize >= 0 then
|
|
||||||
System.SetString(NewText, UTF8Text, ByteSize)
|
|
||||||
else
|
|
||||||
NewText := StrPas(UTF8Text);
|
|
||||||
if FText <> NewText then
|
|
||||||
begin
|
|
||||||
FText := NewText;
|
|
||||||
S := NSStringUTF8(NewText);
|
|
||||||
try
|
|
||||||
FSurrCount:=-1; // invalidating surragete pair search
|
|
||||||
FTextStorage.beginEditing;
|
|
||||||
if S <> nil then
|
|
||||||
FTextStorage.replaceCharactersInRange_withString(GetTextRange, S);
|
|
||||||
updateFont;
|
|
||||||
updateColor;
|
|
||||||
FTextStorage.endEditing;
|
|
||||||
except
|
|
||||||
end;
|
|
||||||
S.release;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TCocoaTextLayout.GetSize: TSize;
|
|
||||||
var
|
|
||||||
Range: NSRange;
|
|
||||||
bnds: NSRect;
|
|
||||||
begin
|
|
||||||
Range := FLayout.glyphRangeForTextContainer(FTextContainer);
|
|
||||||
//for text with soft-breaks (#13) the vertical bounds is too high!
|
|
||||||
//(feels like it tryes to span it from top to bottom)
|
|
||||||
//bnds := FLayout.boundingRectForGlyphRange_inTextContainer(Range, FTextContainer);
|
|
||||||
bnds := FLayout.usedRectForTextContainer(FTextContainer);
|
|
||||||
Result.cx := Round(bnds.size.width);
|
|
||||||
Result.cy := Round(bnds.size.height);
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TCocoaTextLayout.GetGlyphs: TGlyphArray;
|
|
||||||
var
|
|
||||||
Range: NSRange;
|
|
||||||
begin
|
|
||||||
Range := FLayout.glyphRangeForTextContainer(FTextContainer);
|
|
||||||
// required length + 1 space
|
|
||||||
SetLength(Result, Range.length + 1);
|
|
||||||
FLayout.getGlyphs_range(@Result[0], Range);
|
|
||||||
SetLength(Result, Range.length);
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure TCocoaTextLayout.Draw(ctx: NSGraphicsContext; X, Y: Integer; FillBackground: Boolean; DX: PInteger);
|
|
||||||
var
|
|
||||||
Range: NSRange;
|
|
||||||
Pt: NSPoint;
|
|
||||||
Context: NSGraphicsContext;
|
|
||||||
Locations: array of NSPoint;
|
|
||||||
Indexes: array of NSUInteger;
|
|
||||||
I,j, Count, ii: NSUInteger;
|
|
||||||
si: Integer;
|
|
||||||
transform : NSAffineTransform;
|
|
||||||
begin
|
|
||||||
Range := FLayout.glyphRangeForTextContainer(FTextContainer);
|
|
||||||
if Range.length = 0 then
|
|
||||||
Exit; // cannot render anything. string is empty or invalid characters
|
|
||||||
|
|
||||||
if not ctx.isFlipped then
|
|
||||||
Context := NSGraphicsContext.graphicsContextWithGraphicsPort_flipped(ctx.graphicsPort, True)
|
|
||||||
else
|
|
||||||
Context := ctx;
|
|
||||||
|
|
||||||
NSGraphicsContext.classSaveGraphicsState;
|
|
||||||
NSGraphicsContext.setCurrentContext(Context);
|
|
||||||
ctx.setShouldAntialias(FFont.Antialiased);
|
|
||||||
if FFont.RotationDeg<>0 then
|
|
||||||
begin
|
|
||||||
transform := NSAffineTransform.transform;
|
|
||||||
transform.translateXBy_yBy(X, Y);
|
|
||||||
if ctx.isFlipped then
|
|
||||||
transform.rotateByDegrees( FFont.RotationDeg )
|
|
||||||
else
|
|
||||||
transform.rotateByDegrees( -FFont.RotationDeg );
|
|
||||||
transform.translateXBy_yBy(-X, -Y);
|
|
||||||
transform.concat;
|
|
||||||
end;
|
|
||||||
|
|
||||||
Pt.x := X;
|
|
||||||
Pt.y := Y;
|
|
||||||
if Assigned(DX) then
|
|
||||||
begin
|
|
||||||
// DX - is provided for UTF8 characters. UTF8 doesn't have surrogate pairs
|
|
||||||
// UTF16 does. UTF16 is the base for NSTextLayout and NSString.
|
|
||||||
// Thus for any character in DX, there might be mulitple "characeters"
|
|
||||||
// in NSTextLayout. See #35675.
|
|
||||||
if FSurrCount<0 then EvalSurrogate(FTextStorage.string_);
|
|
||||||
|
|
||||||
Count := Range.length;
|
|
||||||
SetLength(Locations, Count);
|
|
||||||
SetLength(Indexes, Count);
|
|
||||||
Locations[0] := FLayout.locationForGlyphAtIndex(0);
|
|
||||||
Indexes[0] := 0;
|
|
||||||
for I := 1 to Count - 1 do Indexes[I] := I;
|
|
||||||
|
|
||||||
// no surrogate pairs
|
|
||||||
I := 1;
|
|
||||||
j := 0;
|
|
||||||
if FSurrCount > 0 then
|
|
||||||
begin
|
|
||||||
si := 0;
|
|
||||||
for si:=0 to FSurrCount - 1 do
|
|
||||||
begin
|
|
||||||
for ii := i to FSurr[si].location do
|
|
||||||
begin
|
|
||||||
Locations[I] := Locations[I - 1];
|
|
||||||
Locations[I].x := Locations[I].x + DX[J];
|
|
||||||
inc(i);
|
|
||||||
inc(j);
|
|
||||||
end;
|
|
||||||
for ii := 2 to FSurr[si].length do
|
|
||||||
begin
|
|
||||||
Locations[I] := Locations[I - 1];
|
|
||||||
inc(I);
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
// remaining DX offsets
|
|
||||||
for I := I to Count - 1 do
|
|
||||||
begin
|
|
||||||
Locations[I] := Locations[I - 1];
|
|
||||||
Locations[I].x := Locations[I].x + DX[J];
|
|
||||||
inc(j);
|
|
||||||
end;
|
|
||||||
FLayout.setLocations_startingGlyphIndexes_count_forGlyphRange(@Locations[0], @Indexes[0], Count, Range);
|
|
||||||
end;
|
|
||||||
|
|
||||||
if FillBackground then
|
|
||||||
FLayout.drawBackgroundForGlyphRange_atPoint(Range, Pt);
|
|
||||||
FLayout.drawGlyphsForGlyphRange_atPoint(Range, Pt);
|
|
||||||
NSGraphicsContext.classRestoreGraphicsState;
|
|
||||||
end;
|
|
||||||
|
|
||||||
{ TCocoaContext }
|
{ TCocoaContext }
|
||||||
|
|
||||||
@ -1625,12 +1297,12 @@ end;
|
|||||||
|
|
||||||
function TCocoaContext.GetTextColor: TColor;
|
function TCocoaContext.GetTextColor: TColor;
|
||||||
begin
|
begin
|
||||||
Result := FText.ForegroundColor;
|
Result := FForegroundColor;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TCocoaContext.GetFont: TCocoaFont;
|
function TCocoaContext.GetFont: TCocoaFont;
|
||||||
begin
|
begin
|
||||||
Result := FText.Font;
|
Result := FFont;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TCocoaContext.SetBkColor(AValue: TColor);
|
procedure TCocoaContext.SetBkColor(AValue: TColor);
|
||||||
@ -1660,7 +1332,7 @@ end;
|
|||||||
|
|
||||||
procedure TCocoaContext.SetFont(const AValue: TCocoaFont);
|
procedure TCocoaContext.SetFont(const AValue: TCocoaFont);
|
||||||
begin
|
begin
|
||||||
FText.Font := AValue; // UpdateRefs done within property setter
|
FFont := AValue; // UpdateRefs done within property setter
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TCocoaContext.SetPen(const AValue: TCocoaPen);
|
procedure TCocoaContext.SetPen(const AValue: TCocoaPen);
|
||||||
@ -1693,7 +1365,7 @@ end;
|
|||||||
|
|
||||||
procedure TCocoaContext.SetTextColor(AValue: TColor);
|
procedure TCocoaContext.SetTextColor(AValue: TColor);
|
||||||
begin
|
begin
|
||||||
FText.ForegroundColor := AValue;
|
FForegroundColor := AValue;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TCocoaContext.UpdateContextOfs(const AWindowOfs, AViewOfs: TPoint);
|
procedure TCocoaContext.UpdateContextOfs(const AWindowOfs, AViewOfs: TPoint);
|
||||||
@ -1802,7 +1474,6 @@ begin
|
|||||||
FClipRegion.AddRef;
|
FClipRegion.AddRef;
|
||||||
|
|
||||||
FSavedDCList := nil;
|
FSavedDCList := nil;
|
||||||
FText := TCocoaTextLayout.Create;
|
|
||||||
FClipped := False;
|
FClipped := False;
|
||||||
FFlipped := False;
|
FFlipped := False;
|
||||||
end;
|
end;
|
||||||
@ -1819,7 +1490,6 @@ begin
|
|||||||
FClipRegion.Release;
|
FClipRegion.Release;
|
||||||
|
|
||||||
FSavedDCList.Free;
|
FSavedDCList.Free;
|
||||||
FText.Free;
|
|
||||||
|
|
||||||
FBkBrush.Free;
|
FBkBrush.Free;
|
||||||
|
|
||||||
@ -2172,10 +1842,32 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TCocoaContext.TextOut(X, Y: Integer; Options: Longint; Rect: PRect; UTF8Chars: PChar; Count: Integer; CharsDelta: PInteger);
|
procedure TCocoaContext.TextOut(X, Y: Integer; Options: Longint; Rect: PRect; UTF8Chars: PChar; Count: Integer; CharsDelta: PInteger);
|
||||||
|
const
|
||||||
|
UnderlineStyle = NSUnderlineStyleSingle or NSUnderlinePatternSolid;
|
||||||
var
|
var
|
||||||
|
cg: CGContextRef;
|
||||||
BrushSolid, FillBg: Boolean;
|
BrushSolid, FillBg: Boolean;
|
||||||
|
AttribStr: CFAttributedStringRef;
|
||||||
|
Str: NSString;
|
||||||
|
CoreLine: CTLineRef;
|
||||||
|
Glyphcount, k, i, CurGlyphCount: integer;
|
||||||
|
Locations: array of NSPoint;
|
||||||
|
Runs: CFArrayRef;
|
||||||
|
CurRun: CTRunRef;
|
||||||
|
RunCount: Integer;
|
||||||
|
Glyphs: array of CGGlyph;
|
||||||
|
RunFont: CTFontRef;
|
||||||
|
transform: NSAffineTransform;
|
||||||
|
Dict: NSMutableDictionary;
|
||||||
|
YPrime, StrikeH, StrikeW: CGFloat;
|
||||||
|
lForegroundColor: NSColor;
|
||||||
begin
|
begin
|
||||||
CGContextSaveGState(CGContext());
|
cg := CGContext();
|
||||||
|
if not Assigned(cg) then
|
||||||
|
Exit;
|
||||||
|
|
||||||
|
CGContextSaveGState(cg);
|
||||||
|
CGContextSetTextMatrix(cg, CGAffineTransformIdentity);
|
||||||
|
|
||||||
if Assigned(Rect) then
|
if Assigned(Rect) then
|
||||||
begin
|
begin
|
||||||
@ -2192,9 +1884,9 @@ begin
|
|||||||
|
|
||||||
if ((Options and ETO_CLIPPED) <> 0) and (Count > 0) then
|
if ((Options and ETO_CLIPPED) <> 0) and (Count > 0) then
|
||||||
begin
|
begin
|
||||||
CGContextBeginPath(CGContext);
|
CGContextBeginPath(cg);
|
||||||
CGContextAddRect(CGContext, RectToCGrect(Rect^));
|
CGContextAddRect(cg, RectToCGrect(Rect^));
|
||||||
CGContextClip(CGContext);
|
CGContextClip(cg);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -2202,12 +1894,105 @@ begin
|
|||||||
begin
|
begin
|
||||||
FillBg := BkMode = OPAQUE;
|
FillBg := BkMode = OPAQUE;
|
||||||
if FillBg then
|
if FillBg then
|
||||||
FText.BackgroundColor := BkBrush.ColorRef;
|
FBackgroundColor := BkBrush.ColorRef;
|
||||||
FText.SetText(UTF8Chars, Count);
|
|
||||||
FText.Draw(ctx, X, Y, FillBg, CharsDelta);
|
Str := NSStringUTF8(UTF8Chars, Count);
|
||||||
|
try
|
||||||
|
|
||||||
|
lForegroundColor := SysColorToNSColor(SysColorToSysColorIndex(FForegroundColor));
|
||||||
|
if lForegroundColor = nil then
|
||||||
|
lForegroundColor := ColorToNSColor(ColorToRGB(FForegroundColor));
|
||||||
|
|
||||||
|
Dict := NSMutableDictionary.dictionaryWithObjectsAndKeys(
|
||||||
|
Font.Font, kCTFontAttributeName,
|
||||||
|
lForegroundColor, NSForegroundColorAttributeName,
|
||||||
|
nil);
|
||||||
|
|
||||||
|
if FillBg then
|
||||||
|
Dict.setObject_forKey(ColorToNSColor(FBackgroundColor), NSBackgroundColorAttributeName);
|
||||||
|
|
||||||
|
if cfs_Underline in Font.Style then
|
||||||
|
Dict.setObject_forKey(NSNumber.numberWithInteger(UnderlineStyle), NSUnderlineStyleAttributeName);
|
||||||
|
|
||||||
|
AttribStr := CFAttributedStringCreate(kCFAllocatorDefault, CFStringRef(Str), CFDictionaryRef(Dict));
|
||||||
|
try
|
||||||
|
CoreLine := CTLineCreateWithAttributedString(CFAttributedStringRef(AttribStr));
|
||||||
|
try
|
||||||
|
|
||||||
|
ctx.setShouldAntialias(Font.Antialiased);
|
||||||
|
if FFont.RotationDeg <> 0 then
|
||||||
|
begin
|
||||||
|
transform := NSAffineTransform.transform;
|
||||||
|
transform.translateXBy_yBy(X, Y);
|
||||||
|
if ctx.isFlipped then
|
||||||
|
transform.rotateByDegrees( FFont.RotationDeg )
|
||||||
|
else
|
||||||
|
transform.rotateByDegrees( -FFont.RotationDeg );
|
||||||
|
transform.translateXBy_yBy(-X, -Y);
|
||||||
|
transform.concat;
|
||||||
|
end;
|
||||||
|
|
||||||
|
CGContextTranslateCTM(cg, 0, FSize.Height);
|
||||||
|
CGContextScaleCTM(cg, 1, -1);
|
||||||
|
YPrime := FSize.Height - y - Font.Font.ascender;
|
||||||
|
CGContextSetTextPosition(cg, x, YPrime);
|
||||||
|
|
||||||
|
if CharsDelta = nil then
|
||||||
|
begin
|
||||||
|
CTLineDraw(CoreLine, cg);
|
||||||
|
end
|
||||||
|
else // CharsDelta <> nil;
|
||||||
|
begin
|
||||||
|
CGContextSetFillColorWithColor(cg, lForegroundColor.CGColor);
|
||||||
|
GlyphCount := CTLineGetGlyphCount(CoreLine);
|
||||||
|
|
||||||
|
SetLength(Locations, GlyphCount);
|
||||||
|
Locations[0].x := 0;
|
||||||
|
Locations[0].y := 0;
|
||||||
|
for k := 1 to GlyphCount - 1 do
|
||||||
|
begin
|
||||||
|
Locations[k] := Locations[k - 1];
|
||||||
|
Locations[k].x := Locations[k].x + CharsDelta[k - 1]
|
||||||
|
end;
|
||||||
|
|
||||||
|
Runs := CTLineGetGlyphRuns(CoreLine);
|
||||||
|
if Runs <> nil then
|
||||||
|
begin
|
||||||
|
GlyphCount := 0;
|
||||||
|
RunCount := CFArrayGetCount(Runs);
|
||||||
|
for i := 0 to RunCount - 1 do
|
||||||
|
begin
|
||||||
|
CurRun := CTRunRef(CFArrayGetValueAtIndex(Runs, i));
|
||||||
|
CurGlyphCount := CTRunGetGlyphCount(CurRun);
|
||||||
|
SetLength(Glyphs, CurGlyphCount);
|
||||||
|
CTRunGetGlyphs(CurRun, CFRangeMake(0,0), @Glyphs[0]);
|
||||||
|
RunFont := CFDictionaryGetValue(CTRunGetAttributes(CurRun), kCTFontAttributeName);
|
||||||
|
CTFontDrawGlyphs(runFont, @Glyphs[0], @Locations[GlyphCount], CurGlyphCount, cg);
|
||||||
|
GlyphCount := GlyphCount + CurGlyphCount;
|
||||||
|
end;
|
||||||
|
end
|
||||||
|
end;
|
||||||
|
|
||||||
|
if cfs_Strikeout in FFont.Style then begin
|
||||||
|
CGContextSetStrokeColorWithColor(cg, lForegroundColor.CGColor);
|
||||||
|
StrikeH := Font.Font.xHeight / 2;
|
||||||
|
StrikeW := CTLineGetTypographicBounds(CoreLine, nil, nil, nil);
|
||||||
|
CGContextMoveToPoint(cg, X, YPrime + StrikeH);
|
||||||
|
CGContextAddLineToPoint(cg, X + StrikeW, YPrime + StrikeH);
|
||||||
|
CGContextStrokePath(cg);
|
||||||
|
end;
|
||||||
|
finally
|
||||||
|
CFRelease(CoreLine);
|
||||||
|
end;
|
||||||
|
finally
|
||||||
|
CFRelease(AttribStr);
|
||||||
|
end;
|
||||||
|
finally
|
||||||
|
Str.release;
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
CGContextRestoreGState(CGContext());
|
CGContextRestoreGState(cg);
|
||||||
|
|
||||||
AttachedBitmap_SetModified();
|
AttachedBitmap_SetModified();
|
||||||
end;
|
end;
|
||||||
@ -2411,30 +2196,32 @@ end;
|
|||||||
function TCocoaContext.GetTextExtentPoint(AStr: PChar; ACount: Integer; var Size: TSize): Boolean;
|
function TCocoaContext.GetTextExtentPoint(AStr: PChar; ACount: Integer; var Size: TSize): Boolean;
|
||||||
var
|
var
|
||||||
s : NSString;
|
s : NSString;
|
||||||
M : NSMutableAttributedString;
|
AttribStr : CFAttributedStringRef;
|
||||||
|
CoreLine : CTLineRef;
|
||||||
r : NSRect;
|
r : NSRect;
|
||||||
begin
|
begin
|
||||||
{FText.SetText(AStr, ACount);
|
S := NSStringUtf8(AStr, ACount);
|
||||||
Size := FText.GetSize;
|
|
||||||
Result := True;}
|
|
||||||
S := NSString( CFStringCreateWithBytesNoCopy(nil, AStr, ACount, kCFStringEncodingUTF8,
|
|
||||||
false,
|
|
||||||
kCFAllocatorNull));
|
|
||||||
Result := Assigned(S);
|
Result := Assigned(S);
|
||||||
if not Result then Exit;
|
if not Result then Exit;
|
||||||
|
|
||||||
M := NSMutableAttributedString.alloc.initWithString(S);
|
AttribStr := CFAttributedStringCreate(kCFAllocatorDefault, CFStringRef(S),
|
||||||
Result := Assigned(M);
|
CFDictionaryRef(NSDictionary.dictionaryWithObject_forKey(
|
||||||
|
Font.Font, id(kCTFontAttributeName))));
|
||||||
|
|
||||||
|
Result := Assigned(AttribStr);
|
||||||
if Result then
|
if Result then
|
||||||
begin
|
begin
|
||||||
FText.SetFontToStr(M);
|
CoreLine := CTLineCreateWithAttributedString(CFAttributedStringRef(AttribStr));
|
||||||
r := M.boundingRectWithSize_options(NSMakeSize(MaxInt, MaxInt), 0);
|
try
|
||||||
|
r := CTLineGetBoundsWithOptions(CoreLine, 0);
|
||||||
Size.cx := Round(r.size.width);
|
Size.cx := Round(r.size.width);
|
||||||
Size.cy := Round(r.Size.height);
|
Size.cy := Round(r.Size.height);
|
||||||
M.release;
|
finally
|
||||||
|
CFRelease(CoreLine);
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
CFRelease(S);
|
S.release;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{------------------------------------------------------------------------------
|
{------------------------------------------------------------------------------
|
||||||
@ -2446,11 +2233,9 @@ end;
|
|||||||
------------------------------------------------------------------------------}
|
------------------------------------------------------------------------------}
|
||||||
function TCocoaContext.GetTextMetrics(var TM: TTextMetric): Boolean;
|
function TCocoaContext.GetTextMetrics(var TM: TTextMetric): Boolean;
|
||||||
var
|
var
|
||||||
Glyphs: TGlyphArray;
|
|
||||||
Adjustments: array of NSSize;
|
|
||||||
I: Integer;
|
|
||||||
A: Single;
|
|
||||||
lNSFont: NSFont;
|
lNSFont: NSFont;
|
||||||
|
AttrStr: CFAttributedStringRef;
|
||||||
|
CoreLine: CTLineRef;
|
||||||
begin
|
begin
|
||||||
result := False;
|
result := False;
|
||||||
if not Assigned(Font) then
|
if not Assigned(Font) then
|
||||||
@ -2467,21 +2252,22 @@ begin
|
|||||||
TM.tmExternalLeading := 0;
|
TM.tmExternalLeading := 0;
|
||||||
|
|
||||||
TM.tmMaxCharWidth := Round(lNSFont.maximumAdvancement.width);
|
TM.tmMaxCharWidth := Round(lNSFont.maximumAdvancement.width);
|
||||||
FText.SetText('WMTigq[_|^', 10);
|
|
||||||
Glyphs := FText.GetGlyphs;
|
AttrStr := CFAttributedStringCreate(kCFAllocatorDefault,
|
||||||
if Length(Glyphs) > 0 then
|
CFSTR('WMTigq[_|^'),
|
||||||
begin
|
CFDictionaryRef(NSDictionary.dictionaryWithObject_forKey(
|
||||||
SetLength(Adjustments, Length(Glyphs));
|
Font.Font, id(kCTFontAttributeName))));
|
||||||
lNSFont.getAdvancements_forGlyphs_count(@Adjustments[0], @Glyphs[0], Length(Glyphs));
|
try
|
||||||
A := 0;
|
CoreLine := CTLineCreateWithAttributedString(CFAttributedStringRef(AttrStr));
|
||||||
for I := 0 to High(Adjustments) do
|
try
|
||||||
A := A + Adjustments[I].width;
|
TM.tmAveCharWidth := Round(CTLineGetTypographicBounds(CoreLine, nil, nil, nil) /
|
||||||
TM.tmAveCharWidth := Round(A / Length(Adjustments));
|
CTLineGetGlyphCount(CoreLine));
|
||||||
SetLength(Adjustments, 0);
|
finally
|
||||||
SetLength(Glyphs, 0);
|
CFRelease(CoreLine);
|
||||||
end
|
end;
|
||||||
else
|
finally
|
||||||
TM.tmAveCharWidth := TM.tmMaxCharWidth;
|
CFRelease(AttrStr);
|
||||||
|
end;
|
||||||
|
|
||||||
TM.tmOverhang := 0;
|
TM.tmOverhang := 0;
|
||||||
TM.tmDigitizedAspectX := 0;
|
TM.tmDigitizedAspectX := 0;
|
||||||
|
@ -46,7 +46,7 @@ function NSScreenZeroHeight: CGFloat;
|
|||||||
|
|
||||||
function CreateParamsToNSRect(const params: TCreateParams): NSRect;
|
function CreateParamsToNSRect(const params: TCreateParams): NSRect;
|
||||||
|
|
||||||
function NSStringUtf8(s: PChar): NSString;
|
function NSStringUtf8(s: PChar; len: Integer = -1): NSString;
|
||||||
function NSStringUtf8(const s: String): NSString;
|
function NSStringUtf8(const s: String): NSString;
|
||||||
function NSStringToString(ns: NSString): String;
|
function NSStringToString(ns: NSString): String;
|
||||||
|
|
||||||
@ -773,14 +773,24 @@ begin
|
|||||||
with params do Result:=GetNSRect(X,Y,Width,Height);
|
with params do Result:=GetNSRect(X,Y,Width,Height);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function NSStringUtf8(s: PChar): NSString;
|
function NSStringUtf8(s: PChar; len: Integer = -1): NSString;
|
||||||
var
|
var
|
||||||
cf: CFStringRef;
|
W: WideString;
|
||||||
r: Integer;
|
WLen: Integer;
|
||||||
begin
|
begin
|
||||||
{NSString and CFStringRef are interchangable}
|
// Avoid CFString/NSString UTF8 functions (see other overload)
|
||||||
cf := CFStringCreateWithCString(nil, S, kCFStringEncodingUTF8);
|
Result := nil;
|
||||||
Result := NSString(cf);
|
if len = -1 then
|
||||||
|
len := StrLen(s);
|
||||||
|
if len > 0 then
|
||||||
|
begin
|
||||||
|
SetLength(W, len);
|
||||||
|
WLen := Utf8ToUnicode(PWideChar(W), Length(W) + 1, s, len) - 1;
|
||||||
|
if WLen > 0 then
|
||||||
|
Result := NSString.alloc.initWithCharacters_length(unicharPtr(W), WLen);
|
||||||
|
end;
|
||||||
|
if Result = nil then
|
||||||
|
Result := NSString.alloc.init;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function NSStringUtf8(const s: String): NSString;
|
function NSStringUtf8(const s: String): NSString;
|
||||||
|
Loading…
Reference in New Issue
Block a user