Lines with thickness > 1 appear to be drawn differently on Windows and Android. I'm using Delphi 11.0. Create a blank multi-platform application and add the following in the FormPaint event.
procedure TMainForm.FormPaint(Sender: TObject; Canvas: TCanvas;
const ARect: TRectF);
begin
Canvas.Stroke.Thickness := 20;
Canvas.Stroke.Cap := TStrokeCap.Round;
Canvas.Stroke.Color := TAlphaColorRec.Red;
Canvas.Stroke.Kind := TBrushKind.Solid;
Canvas.DrawLine(PointF(20,20), PointF(70,70), 1);
Canvas.DrawLine(PointF(70,70), PointF(130,70), 1);
end;
This results in the following. The same happens when drawing on a TImage.
It seems that in Windows the endpoints of the line are at the center of the line caps, whereas on Android they're at the extremes of the line caps. I'm testing on a Huawei P10 running Android 8.0.0. I'm not currently able to test on a more recent Android version. A Google search doesn't seem to give any results on this issue. I'd appreciate if anyone has any info on this issue and what could be done about it? If someone could test this on a more recent Android version, that would also be appreciated. I could of course add special code for Android to extend the line endpoints by half the line thickness, but I'd like to avoid that if possible.
The Android documentation seem to imply that it shouldn't behave like this. https://developer.android.com/reference/android/graphics/Paint.Cap
The main difference between Windows and Android is that they use different implementations of TCanvas. Windows uses TCanvasD2D, whereas Android is using TCanvasGpu. Looking into the Delphi code. I wonder if the following code in FMX.StrokeBuilder.pas is causing the issue. This code gets runs from FMX.Canvas.GPU.pas, even with TStrokeDash.Solid. I can't work out why it would offset the ends like that.
procedure TStrokeBuilder.InsertDash(SrcPos, DestPos: TPointF; const DashDirVec, ThickPerp: TPointF);
var
InitIndex, DivIndex, Divisions: Integer;
SinValue, CosValue: Single;
RoundShift: TPointF;
begin
if FBrush.Cap = TStrokeCap.Round then
begin
RoundShift := DashDirVec * FHalfThickness;
SrcPos := SrcPos + RoundShift;
DestPos := DestPos - RoundShift;
end;
I can confirm that TCanvasGpu is the issue by setting FMX.Types.GlobalUseGPUCanvas to True before Application.Initialize. Then TCanvasGpu is used even on Windows instead of TCanvasD2D and I get the same issue that I see on Android.