View Issue Details

IDProjectCategoryView StatusLast Update
0038741LazarusWidgetsetpublic2021-04-23 18:59
ReporterCudaText man Assigned ToJuha Manninen  
PrioritynormalSeverityminorReproducibilityalways
Status closedResolutionfixed 
OSUbuntu 20.4 
Product Version2.1 (SVN) 
Summary0038741: gtk3: Canvas.Line and Canvas.Rectangle artifacts
Descriptiondemo added.
run in gtk2/qt5 modes: red+black squares look ok.
run in gtk3 mode: you see not complete edges of squares.
TagsNo tags attached.
Fixed in Revisionr65057
LazTarget-
WidgetsetGTK 3
Attached Files

Relationships

related to 0036444 resolvedJuha Manninen Patches gtk3: LineTo must not include final x,y 

Activities

CudaText man

2021-04-11 23:05

reporter  

tst-line-artifact.zip (4,043 bytes)

CudaText man

2021-04-11 23:05

reporter   ~0130295

Anton Kavalenka

2021-04-12 07:20

reporter   ~0130298

Maybe +-0.5 px offsets have to be added. Cairo paints in float.

Anton Kavalenka

2021-04-12 19:49

reporter   ~0130321

r62418
LCL-GTK3: Do not include final X,Y in LineTo. Issue 0036444, patch from CudaText man.

CudaText man

2021-04-12 20:51

reporter   ~0130322

can we fix both that old 0036444 and this one? I am lame here.

Anton Kavalenka

2021-04-13 07:26

reporter   ~0130336

Not sure, if if fixes all the variants, but cairo docs says - integral pixel numbers are for pixels between.
If desired paint in starting and ending point, the +/-0.5 offset should be used
gtk3lineto.diff (587 bytes)   
Index: lcl/interfaces/gtk3/gtk3objects.pas
===================================================================
--- lcl/interfaces/gtk3/gtk3objects.pas	(revision 64964)
+++ lcl/interfaces/gtk3/gtk3objects.pas	(working copy)
@@ -2294,19 +2294,19 @@
   begin
     if Y = Y0 then
       exit
-    else
+   { else
     if Y > Y0 then
       Dec(Y)
     else
-      Inc(Y);
+      Inc(Y);}
   end
   else
   if Y0 = Y then
   begin
-    if X > X0 then
+   { if X > X0 then
       Dec(X)
     else
-      Inc(X);
+      Inc(X);  }
   end;
 
   cairo_line_to(pcr, X+PixelOffset, Y+PixelOffset);
gtk3lineto.diff (587 bytes)   

CudaText man

2021-04-13 13:12

reporter   ~0130343

Last edited: 2021-04-13 13:14

View 3 revisions

Anton, let's not break the related issue, which paints 'cross mark' -I add the demo from the related issue. picture shows that it regressed a little, gtk2-vs-gtk3.
gtk2-gtk3.png (16,726 bytes)   
gtk2-gtk3.png (16,726 bytes)   

Anton Kavalenka

2021-04-13 16:53

reporter   ~0130347

gtk3lineto-2.diff (1,805 bytes)   
Index: lcl/interfaces/gtk3/gtk3objects.pas
===================================================================
--- lcl/interfaces/gtk3/gtk3objects.pas	(revision 64982)
+++ lcl/interfaces/gtk3/gtk3objects.pas	(working copy)
@@ -2279,37 +2279,38 @@
 function TGtk3DeviceContext.LineTo(X, Y: Integer): Boolean;
 var
   FX, FY: Double;
-  X0, Y0: Integer;
+  X0, Y0,dx,dy:integer;
 begin
   if not Assigned(pcr) then
     exit(False);
   ApplyPen;
 
-  // we must paint line until, but NOT including, (X,Y)
-  // let's offset X, Y by 1 px, but only for horizontal and vertical lines (yet?)
   cairo_get_current_point(pcr, @FX, @FY);
-  X0 := Round(FX-PixelOffset);
-  Y0 := Round(FY-PixelOffset);
-  if X0 = X then
+  X0:=round(FX);
+  Y0:=round(FY);
+  dx:=X-X0;
+  dy:=Y-Y0;
+
+  if (dx=0) and (dy=0) then exit;
+
+  if (dx=0) then
   begin
-    if Y = Y0 then
-      exit
-    else
-    if Y > Y0 then
-      Dec(Y)
-    else
-      Inc(Y);
-  end
-  else
-  if Y0 = Y then
+    cairo_move_to(pcr,X+PixelOffset,Y0);
+    cairo_line_to(pcr,X+PixelOffset,Y);
+  end else
+  if (dy=0) then
   begin
-    if X > X0 then
-      Dec(X)
-    else
-      Inc(X);
-  end;
+    cairo_move_to(pcr,X0,Y+PixelOffset);
+    cairo_line_to(pcr,X,Y+PixelOffset);
+  end else
+  if abs(dx)=abs(dy) then
+  begin
+    cairo_move_to(pcr,FX{-PixelOffset},FY{+PixelOffset});
+    cairo_line_to(pcr,X+PixelOffset, Y+PixelOffset);
+  end else
+    cairo_line_to(pcr,X+PixelOffset, Y+PixelOffset);
 
-  cairo_line_to(pcr, X+PixelOffset, Y+PixelOffset);
+
   cairo_stroke(pcr);
   Result := True;
 end;
@@ -2327,7 +2328,7 @@
     OldPoint^.X := Round(dx);
     OldPoint^.Y := Round(dy);
   end;
-  cairo_move_to(pcr, X+PixelOffset, Y+PixelOffset);
+  cairo_move_to(pcr, X{-PixelOffset}, Y{-PixelOffset});
   Result := True;
 end;
 
gtk3lineto-2.diff (1,805 bytes)   

CudaText man

2021-04-13 18:31

reporter   ~0130356

with the new patch, X mark is still distorted, in the 'Canvas figures tests.zip'.
also that demo hangs on exiting, but it's another thing.

CudaText man

2021-04-20 11:18

reporter   ~0130474

Anton, do you see that the 'x' mark (from red and blue lines, small one) is distorted in demo?

Anton Kavalenka

2021-04-20 14:15

reporter   ~0130481

Thank you for caring, my sight is OK.
In attachment the next approach still unfinished.

Try to add your original approach in the branch where dx=dy - strictly diagonal lines.
gtk3objects.diff (2,248 bytes)   
Index: lcl/interfaces/gtk3/gtk3objects.pas
===================================================================
--- lcl/interfaces/gtk3/gtk3objects.pas	(revision 65026)
+++ lcl/interfaces/gtk3/gtk3objects.pas	(working copy)
@@ -1414,7 +1414,7 @@
   else
   begin
     w := FCurrentPen.Width;
-    if w = 0 then
+    if w <= 1 then
       w := 0.5;
     cairo_set_line_width(pcr, w {* ScaleX}); //line_width is diameter of the pen circle
   end;
@@ -2279,37 +2279,43 @@
 function TGtk3DeviceContext.LineTo(X, Y: Integer): Boolean;
 var
   FX, FY: Double;
-  X0, Y0: Integer;
+  X0, Y0,dx,dy:integer;
 begin
   if not Assigned(pcr) then
     exit(False);
   ApplyPen;
 
-  // we must paint line until, but NOT including, (X,Y)
-  // let's offset X, Y by 1 px, but only for horizontal and vertical lines (yet?)
-  cairo_get_current_point(pcr, @FX, @FY);
-  X0 := Round(FX-PixelOffset);
-  Y0 := Round(FY-PixelOffset);
-  if X0 = X then
+
+  if fCurrentPen.Width<=1 then // optimizations
   begin
-    if Y = Y0 then
-      exit
-    else
-    if Y > Y0 then
-      Dec(Y)
-    else
-      Inc(Y);
-  end
-  else
-  if Y0 = Y then
-  begin
-    if X > X0 then
-      Dec(X)
-    else
-      Inc(X);
-  end;
+    cairo_get_current_point(pcr, @FX, @FY);
+    X0:=round(FX);
+    Y0:=round(FY);
+    dx:=X-X0;
+    dy:=Y-Y0;
 
-  cairo_line_to(pcr, X+PixelOffset, Y+PixelOffset);
+    if (dx=0) and (dy=0) then exit;
+
+    if (dx=0) then
+    begin
+      cairo_move_to(pcr,X+PixelOffset,Y0);
+      cairo_line_to(pcr,X+PixelOffset,Y);
+    end else
+    if (dy=0) then
+    begin
+      cairo_move_to(pcr,X0,Y+PixelOffset);
+      cairo_line_to(pcr,X,Y+PixelOffset);
+    end else
+    if abs(dx)=abs(dy) then
+    begin
+      cairo_move_to(pcr,FX-PixelOffset,FY-PixelOffset);
+      cairo_line_to(pcr,X+2*PixelOffset, Y+2*PixelOffset);
+    end else
+      cairo_line_to(pcr,X+PixelOffset, Y+PixelOffset);
+
+  end else
+    cairo_line_to(pcr,X+PixelOffset, Y+PixelOffset);
+
   cairo_stroke(pcr);
   Result := True;
 end;
@@ -2327,7 +2333,7 @@
     OldPoint^.X := Round(dx);
     OldPoint^.Y := Round(dy);
   end;
-  cairo_move_to(pcr, X+PixelOffset, Y+PixelOffset);
+  cairo_move_to(pcr, X{-PixelOffset}, Y{-PixelOffset});
   Result := True;
 end;
 
gtk3objects.diff (2,248 bytes)   

CudaText man

2021-04-21 11:50

reporter   ~0130493

I still see that X mark is not ok, picture--
bad-demo-x.png (642 bytes)   
bad-demo-x.png (642 bytes)   

Anton Kavalenka

2021-04-21 15:19

reporter   ~0130499

>Try to add your original approach in the branch where dx=dy - strictly diagonal lines.

CudaText man

2021-04-21 15:28

reporter   ~0130500

I am busy with another work, so cannot do it now (to recall what I did before)

Anton Kavalenka

2021-04-22 14:12

reporter   ~0130513

Last edited: 2021-04-22 14:14

View 2 revisions

Here is another approach. Cannot catch corner pixels.

Just for information: I'm busy at 3 different works.
gtk3objects-2.diff (2,479 bytes)   
Index: lcl/interfaces/gtk3/gtk3objects.pas
===================================================================
--- lcl/interfaces/gtk3/gtk3objects.pas	(revision 65026)
+++ lcl/interfaces/gtk3/gtk3objects.pas	(working copy)
@@ -1414,7 +1414,7 @@
   else
   begin
     w := FCurrentPen.Width;
-    if w = 0 then
+    if w <= 1 then
       w := 0.5;
     cairo_set_line_width(pcr, w {* ScaleX}); //line_width is diameter of the pen circle
   end;
@@ -2279,37 +2279,51 @@
 function TGtk3DeviceContext.LineTo(X, Y: Integer): Boolean;
 var
   FX, FY: Double;
-  X0, Y0: Integer;
+  X0, Y0,dx,dy:integer;
 begin
   if not Assigned(pcr) then
     exit(False);
   ApplyPen;
 
-  // we must paint line until, but NOT including, (X,Y)
-  // let's offset X, Y by 1 px, but only for horizontal and vertical lines (yet?)
-  cairo_get_current_point(pcr, @FX, @FY);
-  X0 := Round(FX-PixelOffset);
-  Y0 := Round(FY-PixelOffset);
-  if X0 = X then
+
+  if fCurrentPen.Width<=1 then // optimizations
   begin
-    if Y = Y0 then
-      exit
-    else
-    if Y > Y0 then
-      Dec(Y)
-    else
-      Inc(Y);
-  end
-  else
-  if Y0 = Y then
-  begin
-    if X > X0 then
-      Dec(X)
-    else
-      Inc(X);
-  end;
+    cairo_get_current_point(pcr, @FX, @FY);
+    X0:=round(FX);
+    Y0:=round(FY);
+    dx:=X-X0;
+    dy:=Y-Y0;
 
-  cairo_line_to(pcr, X+PixelOffset, Y+PixelOffset);
+    if (dx=0) and (dy=0) then exit;
+
+    if (dx=0) then
+    begin
+      cairo_move_to(pcr,X+PixelOffset,Y0);
+      cairo_line_to(pcr,X+PixelOffset,Y);
+    end else
+    if (dy=0) then
+    begin
+      cairo_move_to(pcr,X0,Y+PixelOffset);
+      cairo_line_to(pcr,X,Y+PixelOffset);
+    end else
+    if abs(dx)=abs(dy) then
+    begin
+      // here is required more Cairo magic
+      if (dx>0) then
+      begin
+        cairo_move_to(pcr,FX-PixelOffset,FY-PixelOffset);
+        cairo_line_to(pcr,X+2*PixelOffset, Y+2*PixelOffset);
+      end else
+      begin
+        cairo_move_to(pcr,FX+2*PixelOffset,FY);
+        cairo_line_to(pcr,X+PixelOffset, Y+PixelOffset);
+      end;
+    end else
+      cairo_line_to(pcr,X+PixelOffset, Y+PixelOffset);
+
+  end else
+    cairo_line_to(pcr,X+PixelOffset, Y+PixelOffset);
+
   cairo_stroke(pcr);
   Result := True;
 end;
@@ -2327,7 +2341,7 @@
     OldPoint^.X := Round(dx);
     OldPoint^.Y := Round(dy);
   end;
-  cairo_move_to(pcr, X+PixelOffset, Y+PixelOffset);
+  cairo_move_to(pcr, X{-PixelOffset}, Y{-PixelOffset});
   Result := True;
 end;
 
gtk3objects-2.diff (2,479 bytes)   

CudaText man

2021-04-22 18:29

reporter   ~0130524

Anton,
good now- both demos show almost OK lines. (canvas-figures demo 'x mark' is still not perfect but it's acceptable now, we can talk about it later).

Juha Manninen

2021-04-23 17:38

developer   ~0130544

Applied, thanks.

Issue History

Date Modified Username Field Change
2021-04-11 23:05 CudaText man New Issue
2021-04-11 23:05 CudaText man File Added: tst-line-artifact.zip
2021-04-11 23:05 CudaText man Note Added: 0130295
2021-04-11 23:05 CudaText man File Added: Screenshot from 2021-04-12 00-02-20.png
2021-04-12 07:20 Anton Kavalenka Note Added: 0130298
2021-04-12 19:49 Anton Kavalenka Note Added: 0130321
2021-04-12 20:51 CudaText man Note Added: 0130322
2021-04-12 20:53 Juha Manninen Relationship added related to 0036444
2021-04-13 07:26 Anton Kavalenka Note Added: 0130336
2021-04-13 07:26 Anton Kavalenka File Added: gtk3lineto.diff
2021-04-13 13:12 CudaText man Note Added: 0130343
2021-04-13 13:12 CudaText man File Added: gtk2-gtk3.png
2021-04-13 13:12 CudaText man File Added: Canvas figures tests.zip
2021-04-13 13:13 CudaText man Note Edited: 0130343 View Revisions
2021-04-13 13:14 CudaText man Note Edited: 0130343 View Revisions
2021-04-13 16:53 Anton Kavalenka Note Added: 0130347
2021-04-13 16:53 Anton Kavalenka File Added: gtk3lineto-2.diff
2021-04-13 18:31 CudaText man Note Added: 0130356
2021-04-20 11:18 CudaText man Note Added: 0130474
2021-04-20 14:15 Anton Kavalenka Note Added: 0130481
2021-04-20 14:15 Anton Kavalenka File Added: gtk3objects.diff
2021-04-21 11:50 CudaText man Note Added: 0130493
2021-04-21 11:50 CudaText man File Added: bad-demo-x.png
2021-04-21 15:19 Anton Kavalenka Note Added: 0130499
2021-04-21 15:28 CudaText man Note Added: 0130500
2021-04-22 14:12 Anton Kavalenka Note Added: 0130513
2021-04-22 14:12 Anton Kavalenka File Added: gtk3objects-2.diff
2021-04-22 14:14 Anton Kavalenka Note Edited: 0130513 View Revisions
2021-04-22 18:29 CudaText man Note Added: 0130524
2021-04-23 17:10 Juha Manninen Assigned To => Juha Manninen
2021-04-23 17:10 Juha Manninen Status new => assigned
2021-04-23 17:38 Juha Manninen Status assigned => resolved
2021-04-23 17:38 Juha Manninen Resolution open => fixed
2021-04-23 17:38 Juha Manninen Fixed in Revision => r65057
2021-04-23 17:38 Juha Manninen LazTarget => -
2021-04-23 17:38 Juha Manninen Widgetset GTK 3 => GTK 3
2021-04-23 17:38 Juha Manninen Note Added: 0130544
2021-04-23 18:59 CudaText man Status resolved => closed