mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-08 07:21:34 +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;
|
||||
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 }
|
||||
|
||||
TCocoaBitmapContext = class;
|
||||
@ -391,8 +352,10 @@ type
|
||||
FBkColor: TColor;
|
||||
FBkMode: Integer;
|
||||
FROP2: Integer;
|
||||
FText : TCocoaTextLayout;
|
||||
FBrush : TCocoaBrush;
|
||||
FBackgroundColor: TColor;
|
||||
FForegroundColor: TColor;
|
||||
FFont: TCocoaFont;
|
||||
FPen : TCocoaPen;
|
||||
FRegion : TCocoaRegion;
|
||||
// In Cocoa there is no way to enlarge a clip region :(
|
||||
@ -1280,297 +1243,6 @@ begin
|
||||
NSCursor.arrowCursor.set_;
|
||||
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 }
|
||||
|
||||
@ -1625,12 +1297,12 @@ end;
|
||||
|
||||
function TCocoaContext.GetTextColor: TColor;
|
||||
begin
|
||||
Result := FText.ForegroundColor;
|
||||
Result := FForegroundColor;
|
||||
end;
|
||||
|
||||
function TCocoaContext.GetFont: TCocoaFont;
|
||||
begin
|
||||
Result := FText.Font;
|
||||
Result := FFont;
|
||||
end;
|
||||
|
||||
procedure TCocoaContext.SetBkColor(AValue: TColor);
|
||||
@ -1660,7 +1332,7 @@ end;
|
||||
|
||||
procedure TCocoaContext.SetFont(const AValue: TCocoaFont);
|
||||
begin
|
||||
FText.Font := AValue; // UpdateRefs done within property setter
|
||||
FFont := AValue; // UpdateRefs done within property setter
|
||||
end;
|
||||
|
||||
procedure TCocoaContext.SetPen(const AValue: TCocoaPen);
|
||||
@ -1693,7 +1365,7 @@ end;
|
||||
|
||||
procedure TCocoaContext.SetTextColor(AValue: TColor);
|
||||
begin
|
||||
FText.ForegroundColor := AValue;
|
||||
FForegroundColor := AValue;
|
||||
end;
|
||||
|
||||
procedure TCocoaContext.UpdateContextOfs(const AWindowOfs, AViewOfs: TPoint);
|
||||
@ -1802,7 +1474,6 @@ begin
|
||||
FClipRegion.AddRef;
|
||||
|
||||
FSavedDCList := nil;
|
||||
FText := TCocoaTextLayout.Create;
|
||||
FClipped := False;
|
||||
FFlipped := False;
|
||||
end;
|
||||
@ -1819,7 +1490,6 @@ begin
|
||||
FClipRegion.Release;
|
||||
|
||||
FSavedDCList.Free;
|
||||
FText.Free;
|
||||
|
||||
FBkBrush.Free;
|
||||
|
||||
@ -2172,10 +1842,32 @@ begin
|
||||
end;
|
||||
|
||||
procedure TCocoaContext.TextOut(X, Y: Integer; Options: Longint; Rect: PRect; UTF8Chars: PChar; Count: Integer; CharsDelta: PInteger);
|
||||
const
|
||||
UnderlineStyle = NSUnderlineStyleSingle or NSUnderlinePatternSolid;
|
||||
var
|
||||
cg: CGContextRef;
|
||||
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
|
||||
CGContextSaveGState(CGContext());
|
||||
cg := CGContext();
|
||||
if not Assigned(cg) then
|
||||
Exit;
|
||||
|
||||
CGContextSaveGState(cg);
|
||||
CGContextSetTextMatrix(cg, CGAffineTransformIdentity);
|
||||
|
||||
if Assigned(Rect) then
|
||||
begin
|
||||
@ -2192,9 +1884,9 @@ begin
|
||||
|
||||
if ((Options and ETO_CLIPPED) <> 0) and (Count > 0) then
|
||||
begin
|
||||
CGContextBeginPath(CGContext);
|
||||
CGContextAddRect(CGContext, RectToCGrect(Rect^));
|
||||
CGContextClip(CGContext);
|
||||
CGContextBeginPath(cg);
|
||||
CGContextAddRect(cg, RectToCGrect(Rect^));
|
||||
CGContextClip(cg);
|
||||
end;
|
||||
end;
|
||||
|
||||
@ -2202,12 +1894,105 @@ begin
|
||||
begin
|
||||
FillBg := BkMode = OPAQUE;
|
||||
if FillBg then
|
||||
FText.BackgroundColor := BkBrush.ColorRef;
|
||||
FText.SetText(UTF8Chars, Count);
|
||||
FText.Draw(ctx, X, Y, FillBg, CharsDelta);
|
||||
FBackgroundColor := BkBrush.ColorRef;
|
||||
|
||||
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;
|
||||
|
||||
CGContextRestoreGState(CGContext());
|
||||
CGContextRestoreGState(cg);
|
||||
|
||||
AttachedBitmap_SetModified();
|
||||
end;
|
||||
@ -2411,30 +2196,32 @@ end;
|
||||
function TCocoaContext.GetTextExtentPoint(AStr: PChar; ACount: Integer; var Size: TSize): Boolean;
|
||||
var
|
||||
s : NSString;
|
||||
M : NSMutableAttributedString;
|
||||
AttribStr : CFAttributedStringRef;
|
||||
CoreLine : CTLineRef;
|
||||
r : NSRect;
|
||||
begin
|
||||
{FText.SetText(AStr, ACount);
|
||||
Size := FText.GetSize;
|
||||
Result := True;}
|
||||
S := NSString( CFStringCreateWithBytesNoCopy(nil, AStr, ACount, kCFStringEncodingUTF8,
|
||||
false,
|
||||
kCFAllocatorNull));
|
||||
S := NSStringUtf8(AStr, ACount);
|
||||
|
||||
Result := Assigned(S);
|
||||
if not Result then Exit;
|
||||
|
||||
M := NSMutableAttributedString.alloc.initWithString(S);
|
||||
Result := Assigned(M);
|
||||
AttribStr := CFAttributedStringCreate(kCFAllocatorDefault, CFStringRef(S),
|
||||
CFDictionaryRef(NSDictionary.dictionaryWithObject_forKey(
|
||||
Font.Font, id(kCTFontAttributeName))));
|
||||
|
||||
Result := Assigned(AttribStr);
|
||||
if Result then
|
||||
begin
|
||||
FText.SetFontToStr(M);
|
||||
r := M.boundingRectWithSize_options(NSMakeSize(MaxInt, MaxInt), 0);
|
||||
|
||||
Size.cx := Round(r.size.width);
|
||||
Size.cy := Round(r.Size.height);
|
||||
M.release;
|
||||
CoreLine := CTLineCreateWithAttributedString(CFAttributedStringRef(AttribStr));
|
||||
try
|
||||
r := CTLineGetBoundsWithOptions(CoreLine, 0);
|
||||
Size.cx := Round(r.size.width);
|
||||
Size.cy := Round(r.Size.height);
|
||||
finally
|
||||
CFRelease(CoreLine);
|
||||
end;
|
||||
end;
|
||||
CFRelease(S);
|
||||
S.release;
|
||||
end;
|
||||
|
||||
{------------------------------------------------------------------------------
|
||||
@ -2446,11 +2233,9 @@ end;
|
||||
------------------------------------------------------------------------------}
|
||||
function TCocoaContext.GetTextMetrics(var TM: TTextMetric): Boolean;
|
||||
var
|
||||
Glyphs: TGlyphArray;
|
||||
Adjustments: array of NSSize;
|
||||
I: Integer;
|
||||
A: Single;
|
||||
lNSFont: NSFont;
|
||||
AttrStr: CFAttributedStringRef;
|
||||
CoreLine: CTLineRef;
|
||||
begin
|
||||
result := False;
|
||||
if not Assigned(Font) then
|
||||
@ -2467,21 +2252,22 @@ begin
|
||||
TM.tmExternalLeading := 0;
|
||||
|
||||
TM.tmMaxCharWidth := Round(lNSFont.maximumAdvancement.width);
|
||||
FText.SetText('WMTigq[_|^', 10);
|
||||
Glyphs := FText.GetGlyphs;
|
||||
if Length(Glyphs) > 0 then
|
||||
begin
|
||||
SetLength(Adjustments, Length(Glyphs));
|
||||
lNSFont.getAdvancements_forGlyphs_count(@Adjustments[0], @Glyphs[0], Length(Glyphs));
|
||||
A := 0;
|
||||
for I := 0 to High(Adjustments) do
|
||||
A := A + Adjustments[I].width;
|
||||
TM.tmAveCharWidth := Round(A / Length(Adjustments));
|
||||
SetLength(Adjustments, 0);
|
||||
SetLength(Glyphs, 0);
|
||||
end
|
||||
else
|
||||
TM.tmAveCharWidth := TM.tmMaxCharWidth;
|
||||
|
||||
AttrStr := CFAttributedStringCreate(kCFAllocatorDefault,
|
||||
CFSTR('WMTigq[_|^'),
|
||||
CFDictionaryRef(NSDictionary.dictionaryWithObject_forKey(
|
||||
Font.Font, id(kCTFontAttributeName))));
|
||||
try
|
||||
CoreLine := CTLineCreateWithAttributedString(CFAttributedStringRef(AttrStr));
|
||||
try
|
||||
TM.tmAveCharWidth := Round(CTLineGetTypographicBounds(CoreLine, nil, nil, nil) /
|
||||
CTLineGetGlyphCount(CoreLine));
|
||||
finally
|
||||
CFRelease(CoreLine);
|
||||
end;
|
||||
finally
|
||||
CFRelease(AttrStr);
|
||||
end;
|
||||
|
||||
TM.tmOverhang := 0;
|
||||
TM.tmDigitizedAspectX := 0;
|
||||
|
@ -46,7 +46,7 @@ function NSScreenZeroHeight: CGFloat;
|
||||
|
||||
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 NSStringToString(ns: NSString): String;
|
||||
|
||||
@ -773,14 +773,24 @@ begin
|
||||
with params do Result:=GetNSRect(X,Y,Width,Height);
|
||||
end;
|
||||
|
||||
function NSStringUtf8(s: PChar): NSString;
|
||||
function NSStringUtf8(s: PChar; len: Integer = -1): NSString;
|
||||
var
|
||||
cf: CFStringRef;
|
||||
r: Integer;
|
||||
W: WideString;
|
||||
WLen: Integer;
|
||||
begin
|
||||
{NSString and CFStringRef are interchangable}
|
||||
cf := CFStringCreateWithCString(nil, S, kCFStringEncodingUTF8);
|
||||
Result := NSString(cf);
|
||||
// Avoid CFString/NSString UTF8 functions (see other overload)
|
||||
Result := nil;
|
||||
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;
|
||||
|
||||
function NSStringUtf8(const s: String): NSString;
|
||||
|
Loading…
Reference in New Issue
Block a user