View Issue Details

IDProjectCategoryView StatusLast Update
0036430LazarusWidgetsetpublic2019-12-20 18:06
ReporterCudaText manAssigned ToJuha Manninen 
PrioritynormalSeverityminorReproducibilityalways
Status resolvedResolutionreopened 
PlatformUbuntu 19.10 x64OSOS Version
Product Version2.1 (SVN)Product Build 
Target VersionFixed in Version 
Summary0036430: gtk3: Canvas artifacts 2
Descriptionto not crowd previous issue, I post here.
compare demo in gtk2--gtk3.
artifacts:

- PolyLine/PolyBesier don't hide when i uncheck the "Pen.Style psSolid"
- PolyBesier color must be green, but it's not
- PolyBesier form is wrong
- RoundRect corners looks like having wrong radius
TagsNo tags attached.
Fixed in Revisionr62416, r62424
LazTarget-
WidgetsetGTK 3
Attached Files
  • gtk2-gtk3.png (17,969 bytes)
    gtk2-gtk3.png (17,969 bytes)
  • Canvas figures tests.zip (7,973 bytes)
  • fix1.diff (2,798 bytes)
    Index: lcl/interfaces/gtk3/gtk3objects.pas
    ===================================================================
    --- lcl/interfaces/gtk3/gtk3objects.pas	(revision 62382)
    +++ lcl/interfaces/gtk3/gtk3objects.pas	(working copy)
    @@ -1617,7 +1617,8 @@
     
     procedure TGtk3DeviceContext.drawPolyBezier(P: PPoint; NumPoints: Integer; Filled, Continuous: boolean);
     var
    -  i: Integer;
    +  MaxIndex, i: Integer;
    +  bFill, bBorder: Boolean;
     const
       PixelOffset = 0.5;
     begin
    @@ -1625,19 +1626,29 @@
       if (NumPoints < 4) then
         Exit;
     
    +  bFill := CurrentBrush.Style <> BS_NULL;
    +  bBorder := CurrentPen.Style <> psClear;
    +
    +  // we need 3 points left for continuous and 4 for not continous
    +  MaxIndex := NumPoints - 3 - Ord(not Continuous);
    +
       cairo_save(Widget);
       try
    -    ApplyPen;
    -
         i := 0;
    -    // we need 3 points left for continuous and 4 for not continous
    -    while i < NumPoints-1 - (3 + ord(not Continuous)) do
    +    while i <= MaxIndex do
         begin
    -      if (i = 0) or Not Continuous then
    +      if i = 0 then
           begin
             cairo_move_to(Widget, P[i].X+PixelOffset, P[i].Y+PixelOffset); // start point
             Inc(i);
    +      end
    +      else
    +      if not Continuous then
    +      begin
    +        cairo_line_to(Widget, P[i].X+PixelOffset, P[i].Y+PixelOffset); // start point
    +        Inc(i);
           end;
    +
           cairo_curve_to(Widget,
                          P[i].X+PixelOffset, P[i].Y+PixelOffset, // control point 1
                          P[i+1].X+PixelOffset, P[i+1].Y+PixelOffset, // control point 2
    @@ -1644,16 +1655,24 @@
                          P[i+2].X+PixelOffset, P[i+2].Y+PixelOffset); // end point and start point of next
           Inc(i, 3);
         end;
    -    cairo_stroke_preserve(Widget);
     
         if Filled then
         begin
    -      ApplyBrush;
    -      // join start and end points
           cairo_close_path(Widget);
    -      cairo_fill(Widget);
    +      if bFill then
    +      begin
    +        ApplyBrush;
    +        cairo_fill_preserve(Widget);
    +      end;
         end;
     
    +    if bBorder then
    +    begin
    +      ApplyPen;
    +      cairo_stroke(Widget);
    +    end
    +    else
    +      cairo_new_path(Widget);
       finally
         cairo_restore(Widget);
       end;
    Index: lcl/interfaces/gtk3/gtk3winapi.inc
    ===================================================================
    --- lcl/interfaces/gtk3/gtk3winapi.inc	(revision 62382)
    +++ lcl/interfaces/gtk3/gtk3winapi.inc	(working copy)
    @@ -3162,11 +3162,11 @@
       Result:= True;
     end;
     
    -function TGtk3WidgetSet.Polyline(DC: HDC; Points: PPoint; NumPts: Integer
    -  ): boolean;
    +function TGtk3WidgetSet.Polyline(DC: HDC; Points: PPoint; NumPts: Integer): boolean;
     begin
       if not IsValidDC(DC) then
         exit(False);
    +  if TGtk3DeviceContext(DC).CurrentPen.Style = psClear then Exit;
       TGtk3DeviceContext(DC).drawPolyLine(Points, NumPts);
       Result:=True;
     end;
    
    fix1.diff (2,798 bytes)
  • 518fdf7c56d8d.png (6,128 bytes)
    518fdf7c56d8d.png (6,128 bytes)
  • offs.diff (5,480 bytes)
    Index: lcl/interfaces/gtk3/gtk3objects.pas
    ===================================================================
    --- lcl/interfaces/gtk3/gtk3objects.pas	(revision 62418)
    +++ lcl/interfaces/gtk3/gtk3objects.pas	(working copy)
    @@ -296,9 +296,13 @@
     function ReplaceAmpersandsWithUnderscores(const S: string): string; inline;
     
     implementation
    +
     uses math, gtk3int, gtk3procs;
     
     const
    +  PixelOffset = 0.5; // Cairo API needs 0.5 pixel offset to not make blurry lines
    +
    +const
       Dash_Dash:        array [0..1] of double = (18, 6);             //____ ____
       Dash_Dot:         array [0..1] of double = (3, 3);              //.........
       Dash_DashDot:     array [0..3] of double = (9, 6, 3, 6);        //__ . __ .
    @@ -1329,7 +1333,7 @@
     begin
       cairo_save(Widget);
       try
    -    cairo_rectangle(Widget, x1, y1, w - 1, h - 1);
    +    cairo_rectangle(Widget, x1+PixelOffset, y1+PixelOffset, w - 1, h - 1);
     
         if AFill then
         begin
    @@ -1429,7 +1433,7 @@
       cairo_save(Widget);
       try
         cairo_get_matrix(Widget, @save_matrix);
    -    cairo_translate (Widget, x + w / 2.0, y + h / 2.0);
    +    cairo_translate (Widget, x + w / 2.0 + PixelOffset, y + h / 2.0 + PixelOffset);
         cairo_scale (Widget, w / 2.0, h / 2.0);
         cairo_new_path(Widget);
         cairo_arc
    @@ -1471,7 +1475,7 @@
       cairo_save(Widget);
       try
         with targetRect^ do
    -      cairo_rectangle(Widget, Left, Top, Right - Left, Bottom - Top);
    +      cairo_rectangle(Widget, Left+PixelOffset, Top+PixelOffset, Right - Left, Bottom - Top);
         cairo_set_source_surface(Widget, Surface, 0, 0);
         cairo_matrix_init_identity(@M);
         cairo_matrix_translate(@M, SourceRect^.Left, SourceRect^.Top);
    @@ -1488,10 +1492,10 @@
     
     procedure TGtk3DeviceContext.drawImage(targetRect: PRect; image: PGdkPixBuf;
       sourceRect: PRect; mask: PGdkPixBuf; maskRect: PRect);
    -var
    -  pm: PGdkPixbuf;
    -  AData: PByte;
    -  ASurface: Pcairo_surface_t;
    +//var
    +//  pm: PGdkPixbuf;
    +//  AData: PByte;
    +//  ASurface: Pcairo_surface_t;
     begin
       {$IFDEF VerboseGtk3DeviceContext}
       DebugLn('TGtk3DeviceContext.DrawImage ');
    @@ -1498,13 +1502,13 @@
       {$ENDIF}
       cairo_save(Widget);
       try
    -    pm := Image;
    +    // pm := Image;
         // AData := PByte(gdk_pixbuf_get_pixels(pm));
         // ASurface := cairo_image_surface_create_for_data(AData, CAIRO_FORMAT_ARGB32, gdk_pixbuf_get_width(pm), gdk_pixbuf_get_height(pm), gdk_pixbuf_get_rowstride(pm));
         // cairo_set_source_surface(Widget, ASurface, targetRect^.Left, targetRect^.Top);
         gdk_cairo_set_source_pixbuf(Widget, Image, 0, 0);
         with targetRect^ do
    -    cairo_rectangle(Widget, Left, Top, Right-Left, Bottom-Top);
    +    cairo_rectangle(Widget, Left+PixelOffset, Top+PixelOffset, Right-Left, Bottom-Top);
         cairo_paint(Widget);
       finally
         // cairo_surface_destroy(ASurface);
    @@ -1524,7 +1528,7 @@
       try
         gdk_cairo_set_source_pixbuf(Widget, Image, 0, 0);
         with targetRect^ do
    -      cairo_rectangle(Widget, Left, Top, Right - Left, Bottom - Top);
    +      cairo_rectangle(Widget, Left+PixelOffset, Top+PixelOffset, Right - Left, Bottom - Top);
     
         cairo_matrix_init_identity(@M);
         cairo_matrix_translate(@M, SourceRect^.Left, SourceRect^.Top);
    @@ -1563,8 +1567,6 @@
     end;
     
     procedure TGtk3DeviceContext.drawPolyLine(P: PPoint; NumPts: Integer);
    -const
    -  PixelOffset = 0.5;
     var
       i: Integer;
     begin
    @@ -1585,8 +1587,6 @@
       FillRule: Integer; AFill, ABorder: Boolean);
     var
       i: Integer;
    -const
    -  PixelOffset = 0.5;
     begin
       cairo_save(Widget);
       try
    @@ -1619,8 +1619,6 @@
     var
       MaxIndex, i: Integer;
       bFill, bBorder: Boolean;
    -const
    -  PixelOffset = 0.5;
     begin
       // 3 points per curve + a starting point for the first curve
       if (NumPoints < 4) then
    @@ -1711,7 +1709,7 @@
         end;
     
         applyBrush;
    -    cairo_rectangle(Widget, x, y, w - 1, h - 1);
    +    cairo_rectangle(Widget, x+PixelOffset, y+PixelOffset, w - 1, h - 1);
         cairo_fill(Widget);
     
         if ABrush <> 0 then
    @@ -1784,11 +1782,10 @@
     var
       DX: Double;
       DY: Double;
    -  Pt: TPoint;
     begin
       Result := False;
       cairo_surface_get_device_offset(cairo_get_target(Widget), @DX, @DY);
    -  cairo_translate(Widget, DX, DY);
    +  cairo_translate(Widget, DX+PixelOffset, DY+PixelOffset);
       try
         cairo_move_to(Widget, SX(X1+RX), SY(Y1));
         cairo_line_to(Widget, SX(X2-RX), SY(Y1));
    @@ -1869,8 +1866,6 @@
     end;
     
     function TGtk3DeviceContext.LineTo(X, Y: Integer): Boolean;
    -const
    -  PixelOffset = 0.5;
     var
       FX, FY: Double;
       X0, Y0: Integer;
    @@ -1909,8 +1904,6 @@
     end;
     
     function TGtk3DeviceContext.MoveTo(const X, Y: Integer; OldPoint: PPoint): Boolean;
    -const
    -  PixelOffset = 0.5;
     var
       dx: Double;
       dy: Double;
    Index: lcl/interfaces/gtk3/gtk3winapi.inc
    ===================================================================
    --- lcl/interfaces/gtk3/gtk3winapi.inc	(revision 62418)
    +++ lcl/interfaces/gtk3/gtk3winapi.inc	(working copy)
    @@ -1699,6 +1699,8 @@
     end;
     
     function TGtk3WidgetSet.FrameRect(DC: HDC; const ARect: TRect; hBr: HBRUSH): Integer;
    +const
    +  PixelOffset = 0.5;
     var
       cr: Pcairo_t;
     begin
    @@ -1709,7 +1711,7 @@
       if not IsValidDC(DC) then
         exit;
       cr := TGtk3DeviceContext(DC).Widget;
    -  cairo_rectangle(cr, ARect.Left, ARect.Top, ARect.Right-ARect.Left-1, ARect.Bottom-ARect.Top-1);
    +  cairo_rectangle(cr, ARect.Left+PixelOffset, ARect.Top+PixelOffset, ARect.Right-ARect.Left-1, ARect.Bottom-ARect.Top-1);
       if IsValidGDIObject(hBr) then
         TGtk3DeviceContext(DC).SetSourceColor(TGtk3Brush(HBR).Color);
       cairo_set_line_width(cr, 1);
    
    offs.diff (5,480 bytes)
  • fix2.diff (6,934 bytes)
    Index: lcl/interfaces/gtk3/gtk3objects.pas
    ===================================================================
    --- lcl/interfaces/gtk3/gtk3objects.pas	(revision 62418)
    +++ lcl/interfaces/gtk3/gtk3objects.pas	(working copy)
    @@ -296,9 +296,13 @@
     function ReplaceAmpersandsWithUnderscores(const S: string): string; inline;
     
     implementation
    +
     uses math, gtk3int, gtk3procs;
     
     const
    +  PixelOffset = 0.5; // Cairo API needs 0.5 pixel offset to not make blurry lines
    +
    +const
       Dash_Dash:        array [0..1] of double = (18, 6);             //____ ____
       Dash_Dot:         array [0..1] of double = (3, 3);              //.........
       Dash_DashDot:     array [0..3] of double = (9, 6, 3, 6);        //__ . __ .
    @@ -1329,7 +1333,7 @@
     begin
       cairo_save(Widget);
       try
    -    cairo_rectangle(Widget, x1, y1, w - 1, h - 1);
    +    cairo_rectangle(Widget, x1 + PixelOffset, y1 + PixelOffset, w - 1, h - 1);
     
         if AFill then
         begin
    @@ -1429,7 +1433,7 @@
       cairo_save(Widget);
       try
         cairo_get_matrix(Widget, @save_matrix);
    -    cairo_translate (Widget, x + w / 2.0, y + h / 2.0);
    +    cairo_translate (Widget, x + w / 2.0 + PixelOffset, y + h / 2.0 + PixelOffset);
         cairo_scale (Widget, w / 2.0, h / 2.0);
         cairo_new_path(Widget);
         cairo_arc
    @@ -1471,7 +1475,7 @@
       cairo_save(Widget);
       try
         with targetRect^ do
    -      cairo_rectangle(Widget, Left, Top, Right - Left, Bottom - Top);
    +      cairo_rectangle(Widget, Left + PixelOffset, Top + PixelOffset, Right - Left, Bottom - Top);
         cairo_set_source_surface(Widget, Surface, 0, 0);
         cairo_matrix_init_identity(@M);
         cairo_matrix_translate(@M, SourceRect^.Left, SourceRect^.Top);
    @@ -1488,10 +1492,10 @@
     
     procedure TGtk3DeviceContext.drawImage(targetRect: PRect; image: PGdkPixBuf;
       sourceRect: PRect; mask: PGdkPixBuf; maskRect: PRect);
    -var
    -  pm: PGdkPixbuf;
    -  AData: PByte;
    -  ASurface: Pcairo_surface_t;
    +//var
    +//  pm: PGdkPixbuf;
    +//  AData: PByte;
    +//  ASurface: Pcairo_surface_t;
     begin
       {$IFDEF VerboseGtk3DeviceContext}
       DebugLn('TGtk3DeviceContext.DrawImage ');
    @@ -1498,13 +1502,13 @@
       {$ENDIF}
       cairo_save(Widget);
       try
    -    pm := Image;
    +    // pm := Image;
         // AData := PByte(gdk_pixbuf_get_pixels(pm));
         // ASurface := cairo_image_surface_create_for_data(AData, CAIRO_FORMAT_ARGB32, gdk_pixbuf_get_width(pm), gdk_pixbuf_get_height(pm), gdk_pixbuf_get_rowstride(pm));
         // cairo_set_source_surface(Widget, ASurface, targetRect^.Left, targetRect^.Top);
         gdk_cairo_set_source_pixbuf(Widget, Image, 0, 0);
         with targetRect^ do
    -    cairo_rectangle(Widget, Left, Top, Right-Left, Bottom-Top);
    +      cairo_rectangle(Widget, Left + PixelOffset, Top + PixelOffset, Right - Left, Bottom - Top);
         cairo_paint(Widget);
       finally
         // cairo_surface_destroy(ASurface);
    @@ -1524,7 +1528,7 @@
       try
         gdk_cairo_set_source_pixbuf(Widget, Image, 0, 0);
         with targetRect^ do
    -      cairo_rectangle(Widget, Left, Top, Right - Left, Bottom - Top);
    +      cairo_rectangle(Widget, Left + PixelOffset, Top + PixelOffset, Right - Left, Bottom - Top);
     
         cairo_matrix_init_identity(@M);
         cairo_matrix_translate(@M, SourceRect^.Left, SourceRect^.Top);
    @@ -1563,8 +1567,6 @@
     end;
     
     procedure TGtk3DeviceContext.drawPolyLine(P: PPoint; NumPts: Integer);
    -const
    -  PixelOffset = 0.5;
     var
       i: Integer;
     begin
    @@ -1585,8 +1587,6 @@
       FillRule: Integer; AFill, ABorder: Boolean);
     var
       i: Integer;
    -const
    -  PixelOffset = 0.5;
     begin
       cairo_save(Widget);
       try
    @@ -1619,8 +1619,6 @@
     var
       MaxIndex, i: Integer;
       bFill, bBorder: Boolean;
    -const
    -  PixelOffset = 0.5;
     begin
       // 3 points per curve + a starting point for the first curve
       if (NumPoints < 4) then
    @@ -1691,9 +1689,6 @@
     
     procedure TGtk3DeviceContext.fillRect(x, y, w, h: Integer; ABrush: HBRUSH);
     var
    -  //devx, devy, dx, dy, dw, dh: Double;
    -  //ATarget: Pcairo_surface_t;
    -  //ANewSurface: Pcairo_surface_t;
       ATempBrush: TGtk3Brush;
     begin
       {$ifdef VerboseGtk3DeviceContext}
    @@ -1706,36 +1701,24 @@
         if ABrush <> 0 then
         begin
           ATempBrush := FCurrentBrush;
    -      fBkMode:=OPAQUE;
    +      fBkMode := OPAQUE;
           SetCurrentBrush(TGtk3Brush(ABrush));
         end;
     
         applyBrush;
    -    cairo_rectangle(Widget, x, y, w - 1, h - 1);
    -    cairo_fill(Widget);
    +    cairo_rectangle(Widget, x + PixelOffset, y + PixelOffset, w - 1, h - 1);
    +    cairo_fill_preserve(Widget);
     
    +    // must paint border, filling is not enough
    +    SetSourceColor(FCurrentBrush.Color);
    +    cairo_set_line_width(Widget, 1);
    +    cairo_stroke(Widget);
    +
         if ABrush <> 0 then
           SetCurrentBrush(ATempBrush);
       finally
         cairo_restore(Widget);
       end;
    -
    -  // ATarget := cairo_get_target(Widget);
    -  (*
    -  cairo_save(Widget);
    -  dx := x;
    -  dy := y;
    -  dw := w;
    -  dh := h;
    -  ANewSurface := cairo_surface_create_similar(ATarget, cairo_surface_get_content(ATarget), w, h);
    -  cairo_set_source_surface(Widget, ANewSurface, x , y);
    -  cairo_clip(Widget);
    -  vBrush.SetColor(clRed);
    -  cairo_rectangle(Widget, dx, dy, dw, dh);
    -  cairo_fill(Widget);
    -  cairo_surface_destroy(ANewSurface);
    -  cairo_restore(Widget);
    -  *)
     end;
     
     procedure TGtk3DeviceContext.fillRect(x, y, w, h: Integer);
    @@ -1779,15 +1762,14 @@
       end;
     end;
     
    -function TGtk3DeviceContext.RoundRect(X1, Y1, X2, Y2: Integer; RX, RY: Integer
    -  ): Boolean;
    +function TGtk3DeviceContext.RoundRect(X1, Y1, X2, Y2: Integer; RX, RY: Integer): Boolean;
     var
    -  DX: Double;
    -  DY: Double;
    -  Pt: TPoint;
    +  DX, DY: Double;
     begin
       Result := False;
       cairo_surface_get_device_offset(cairo_get_target(Widget), @DX, @DY);
    +  DX := DX+PixelOffset;
    +  DY := DY+PixelOffset;
       cairo_translate(Widget, DX, DY);
       try
         cairo_move_to(Widget, SX(X1+RX), SY(Y1));
    @@ -1869,8 +1851,6 @@
     end;
     
     function TGtk3DeviceContext.LineTo(X, Y: Integer): Boolean;
    -const
    -  PixelOffset = 0.5;
     var
       FX, FY: Double;
       X0, Y0: Integer;
    @@ -1909,8 +1889,6 @@
     end;
     
     function TGtk3DeviceContext.MoveTo(const X, Y: Integer; OldPoint: PPoint): Boolean;
    -const
    -  PixelOffset = 0.5;
     var
       dx: Double;
       dy: Double;
    Index: lcl/interfaces/gtk3/gtk3winapi.inc
    ===================================================================
    --- lcl/interfaces/gtk3/gtk3winapi.inc	(revision 62418)
    +++ lcl/interfaces/gtk3/gtk3winapi.inc	(working copy)
    @@ -1699,6 +1699,8 @@
     end;
     
     function TGtk3WidgetSet.FrameRect(DC: HDC; const ARect: TRect; hBr: HBRUSH): Integer;
    +const
    +  PixelOffset = 0.5;
     var
       cr: Pcairo_t;
     begin
    @@ -1709,7 +1711,7 @@
       if not IsValidDC(DC) then
         exit;
       cr := TGtk3DeviceContext(DC).Widget;
    -  cairo_rectangle(cr, ARect.Left, ARect.Top, ARect.Right-ARect.Left-1, ARect.Bottom-ARect.Top-1);
    +  cairo_rectangle(cr, ARect.Left+PixelOffset, ARect.Top+PixelOffset, ARect.Right-ARect.Left-1, ARect.Bottom-ARect.Top-1);
       if IsValidGDIObject(hBr) then
         TGtk3DeviceContext(DC).SetSourceColor(TGtk3Brush(HBR).Color);
       cairo_set_line_width(cr, 1);
    
    fix2.diff (6,934 bytes)

Relationships

related to 0036374 assignedZeljan Rikalo Lazarus gtk3: Canvas artifacts, swapped R/B colors 
related to 0036444 assignedJuha Manninen Patches gtk3: LineTo must not include final x,y 

Activities

CudaText man

2019-12-12 18:54

reporter  

gtk2-gtk3.png (17,969 bytes)
gtk2-gtk3.png (17,969 bytes)
Canvas figures tests.zip (7,973 bytes)

CudaText man

2019-12-13 14:31

reporter   ~0119819

fix for PolyLine, PolyBesier: added.
I don't know what to do with RoundRect, maybe radius is OK?
picture shows that gtk3 radius is bigger than gtk2 one.

fix1.diff (2,798 bytes)
Index: lcl/interfaces/gtk3/gtk3objects.pas
===================================================================
--- lcl/interfaces/gtk3/gtk3objects.pas	(revision 62382)
+++ lcl/interfaces/gtk3/gtk3objects.pas	(working copy)
@@ -1617,7 +1617,8 @@
 
 procedure TGtk3DeviceContext.drawPolyBezier(P: PPoint; NumPoints: Integer; Filled, Continuous: boolean);
 var
-  i: Integer;
+  MaxIndex, i: Integer;
+  bFill, bBorder: Boolean;
 const
   PixelOffset = 0.5;
 begin
@@ -1625,19 +1626,29 @@
   if (NumPoints < 4) then
     Exit;
 
+  bFill := CurrentBrush.Style <> BS_NULL;
+  bBorder := CurrentPen.Style <> psClear;
+
+  // we need 3 points left for continuous and 4 for not continous
+  MaxIndex := NumPoints - 3 - Ord(not Continuous);
+
   cairo_save(Widget);
   try
-    ApplyPen;
-
     i := 0;
-    // we need 3 points left for continuous and 4 for not continous
-    while i < NumPoints-1 - (3 + ord(not Continuous)) do
+    while i <= MaxIndex do
     begin
-      if (i = 0) or Not Continuous then
+      if i = 0 then
       begin
         cairo_move_to(Widget, P[i].X+PixelOffset, P[i].Y+PixelOffset); // start point
         Inc(i);
+      end
+      else
+      if not Continuous then
+      begin
+        cairo_line_to(Widget, P[i].X+PixelOffset, P[i].Y+PixelOffset); // start point
+        Inc(i);
       end;
+
       cairo_curve_to(Widget,
                      P[i].X+PixelOffset, P[i].Y+PixelOffset, // control point 1
                      P[i+1].X+PixelOffset, P[i+1].Y+PixelOffset, // control point 2
@@ -1644,16 +1655,24 @@
                      P[i+2].X+PixelOffset, P[i+2].Y+PixelOffset); // end point and start point of next
       Inc(i, 3);
     end;
-    cairo_stroke_preserve(Widget);
 
     if Filled then
     begin
-      ApplyBrush;
-      // join start and end points
       cairo_close_path(Widget);
-      cairo_fill(Widget);
+      if bFill then
+      begin
+        ApplyBrush;
+        cairo_fill_preserve(Widget);
+      end;
     end;
 
+    if bBorder then
+    begin
+      ApplyPen;
+      cairo_stroke(Widget);
+    end
+    else
+      cairo_new_path(Widget);
   finally
     cairo_restore(Widget);
   end;
Index: lcl/interfaces/gtk3/gtk3winapi.inc
===================================================================
--- lcl/interfaces/gtk3/gtk3winapi.inc	(revision 62382)
+++ lcl/interfaces/gtk3/gtk3winapi.inc	(working copy)
@@ -3162,11 +3162,11 @@
   Result:= True;
 end;
 
-function TGtk3WidgetSet.Polyline(DC: HDC; Points: PPoint; NumPts: Integer
-  ): boolean;
+function TGtk3WidgetSet.Polyline(DC: HDC; Points: PPoint; NumPts: Integer): boolean;
 begin
   if not IsValidDC(DC) then
     exit(False);
+  if TGtk3DeviceContext(DC).CurrentPen.Style = psClear then Exit;
   TGtk3DeviceContext(DC).drawPolyLine(Points, NumPts);
   Result:=True;
 end;
fix1.diff (2,798 bytes)

CudaText man

2019-12-16 21:47

reporter   ~0119890

gtk3objects.pas

procedure TGtk3DeviceContext.drawPolyBezier(P: PPoint; NumPoints: Integer; Filled, Continuous: boolean);
var
  MaxIndex, i: Integer;
  bFill, bBorder: Boolean;
const
  PixelOffset = 0.5;
begin
  // 3 points per curve + a starting point for the first curve
  if (NumPoints < 4) then
    Exit;

  bFill := CurrentBrush.Style <> BS_NULL;
  bBorder := CurrentPen.Style <> psClear;

  // we need 3 points left for continuous and 4 for not continous
  MaxIndex := NumPoints - 3 - Ord(not Continuous);

  cairo_save(Widget);
  try
    i := 0;
    while i <= MaxIndex do
    begin
      if i = 0 then
      begin
        cairo_move_to(Widget, P[i].X+PixelOffset, P[i].Y+PixelOffset); // start point
        Inc(i);
      end
      else
      if not Continuous then
      begin
        cairo_line_to(Widget, P[i].X+PixelOffset, P[i].Y+PixelOffset); // start point
        Inc(i);
      end;

      cairo_curve_to(Widget,
                     P[i].X+PixelOffset, P[i].Y+PixelOffset, // control point 1
                     P[i+1].X+PixelOffset, P[i+1].Y+PixelOffset, // control point 2
                     P[i+2].X+PixelOffset, P[i+2].Y+PixelOffset); // end point and start point of next
      Inc(i, 3);
    end;

    if Filled then
    begin
      cairo_close_path(Widget);
      if bFill then
      begin
        ApplyBrush;
        cairo_fill_preserve(Widget);
      end;
    end;

    if bBorder then
    begin
      ApplyPen;
      cairo_stroke(Widget);
    end
    else
      cairo_new_path(Widget);
  finally
    cairo_restore(Widget);
  end;
end;


gtk3winapi

function TGtk3WidgetSet.Polyline(DC: HDC; Points: PPoint; NumPts: Integer): boolean;
begin
  if not IsValidDC(DC) then
    exit(False);
  if TGtk3DeviceContext(DC).CurrentPen.Style = psClear then Exit;
  TGtk3DeviceContext(DC).drawPolyLine(Points, NumPts);
  Result:=True;
end;

hamidhb

2019-12-18 07:03

reporter   ~0119905

Dear developer
__________________________________________
cairo_get_matrix(Widget, @save_matrix);
cairo_translate (Widget, 0,5, 0,5);
.
.// your cairo calls here //
.
.
cairo_set_matrix(Widget, @save_matrix);
___________________________________________
We do not need PixelOffset++

518fdf7c56d8d.png (6,128 bytes)
518fdf7c56d8d.png (6,128 bytes)

CudaText man

2019-12-18 12:13

reporter   ~0119907

Last edited: 2019-12-18 12:14

View 2 revisions

I will address this pixel offset in next patch.

Juha Manninen

2019-12-18 22:06

developer   ~0119930

I applied the patch although I don't see much difference in the graphs.
Thanks.

CudaText man

2019-12-19 12:12

reporter   ~0119943

Last edited: 2019-12-19 12:12

View 2 revisions

Here is fix for 0.5 px offset, which is required by Cairo API, it fixes Rect, FillRect, FrameRect, Ellipse.



offs.diff (5,480 bytes)
Index: lcl/interfaces/gtk3/gtk3objects.pas
===================================================================
--- lcl/interfaces/gtk3/gtk3objects.pas	(revision 62418)
+++ lcl/interfaces/gtk3/gtk3objects.pas	(working copy)
@@ -296,9 +296,13 @@
 function ReplaceAmpersandsWithUnderscores(const S: string): string; inline;
 
 implementation
+
 uses math, gtk3int, gtk3procs;
 
 const
+  PixelOffset = 0.5; // Cairo API needs 0.5 pixel offset to not make blurry lines
+
+const
   Dash_Dash:        array [0..1] of double = (18, 6);             //____ ____
   Dash_Dot:         array [0..1] of double = (3, 3);              //.........
   Dash_DashDot:     array [0..3] of double = (9, 6, 3, 6);        //__ . __ .
@@ -1329,7 +1333,7 @@
 begin
   cairo_save(Widget);
   try
-    cairo_rectangle(Widget, x1, y1, w - 1, h - 1);
+    cairo_rectangle(Widget, x1+PixelOffset, y1+PixelOffset, w - 1, h - 1);
 
     if AFill then
     begin
@@ -1429,7 +1433,7 @@
   cairo_save(Widget);
   try
     cairo_get_matrix(Widget, @save_matrix);
-    cairo_translate (Widget, x + w / 2.0, y + h / 2.0);
+    cairo_translate (Widget, x + w / 2.0 + PixelOffset, y + h / 2.0 + PixelOffset);
     cairo_scale (Widget, w / 2.0, h / 2.0);
     cairo_new_path(Widget);
     cairo_arc
@@ -1471,7 +1475,7 @@
   cairo_save(Widget);
   try
     with targetRect^ do
-      cairo_rectangle(Widget, Left, Top, Right - Left, Bottom - Top);
+      cairo_rectangle(Widget, Left+PixelOffset, Top+PixelOffset, Right - Left, Bottom - Top);
     cairo_set_source_surface(Widget, Surface, 0, 0);
     cairo_matrix_init_identity(@M);
     cairo_matrix_translate(@M, SourceRect^.Left, SourceRect^.Top);
@@ -1488,10 +1492,10 @@
 
 procedure TGtk3DeviceContext.drawImage(targetRect: PRect; image: PGdkPixBuf;
   sourceRect: PRect; mask: PGdkPixBuf; maskRect: PRect);
-var
-  pm: PGdkPixbuf;
-  AData: PByte;
-  ASurface: Pcairo_surface_t;
+//var
+//  pm: PGdkPixbuf;
+//  AData: PByte;
+//  ASurface: Pcairo_surface_t;
 begin
   {$IFDEF VerboseGtk3DeviceContext}
   DebugLn('TGtk3DeviceContext.DrawImage ');
@@ -1498,13 +1502,13 @@
   {$ENDIF}
   cairo_save(Widget);
   try
-    pm := Image;
+    // pm := Image;
     // AData := PByte(gdk_pixbuf_get_pixels(pm));
     // ASurface := cairo_image_surface_create_for_data(AData, CAIRO_FORMAT_ARGB32, gdk_pixbuf_get_width(pm), gdk_pixbuf_get_height(pm), gdk_pixbuf_get_rowstride(pm));
     // cairo_set_source_surface(Widget, ASurface, targetRect^.Left, targetRect^.Top);
     gdk_cairo_set_source_pixbuf(Widget, Image, 0, 0);
     with targetRect^ do
-    cairo_rectangle(Widget, Left, Top, Right-Left, Bottom-Top);
+    cairo_rectangle(Widget, Left+PixelOffset, Top+PixelOffset, Right-Left, Bottom-Top);
     cairo_paint(Widget);
   finally
     // cairo_surface_destroy(ASurface);
@@ -1524,7 +1528,7 @@
   try
     gdk_cairo_set_source_pixbuf(Widget, Image, 0, 0);
     with targetRect^ do
-      cairo_rectangle(Widget, Left, Top, Right - Left, Bottom - Top);
+      cairo_rectangle(Widget, Left+PixelOffset, Top+PixelOffset, Right - Left, Bottom - Top);
 
     cairo_matrix_init_identity(@M);
     cairo_matrix_translate(@M, SourceRect^.Left, SourceRect^.Top);
@@ -1563,8 +1567,6 @@
 end;
 
 procedure TGtk3DeviceContext.drawPolyLine(P: PPoint; NumPts: Integer);
-const
-  PixelOffset = 0.5;
 var
   i: Integer;
 begin
@@ -1585,8 +1587,6 @@
   FillRule: Integer; AFill, ABorder: Boolean);
 var
   i: Integer;
-const
-  PixelOffset = 0.5;
 begin
   cairo_save(Widget);
   try
@@ -1619,8 +1619,6 @@
 var
   MaxIndex, i: Integer;
   bFill, bBorder: Boolean;
-const
-  PixelOffset = 0.5;
 begin
   // 3 points per curve + a starting point for the first curve
   if (NumPoints < 4) then
@@ -1711,7 +1709,7 @@
     end;
 
     applyBrush;
-    cairo_rectangle(Widget, x, y, w - 1, h - 1);
+    cairo_rectangle(Widget, x+PixelOffset, y+PixelOffset, w - 1, h - 1);
     cairo_fill(Widget);
 
     if ABrush <> 0 then
@@ -1784,11 +1782,10 @@
 var
   DX: Double;
   DY: Double;
-  Pt: TPoint;
 begin
   Result := False;
   cairo_surface_get_device_offset(cairo_get_target(Widget), @DX, @DY);
-  cairo_translate(Widget, DX, DY);
+  cairo_translate(Widget, DX+PixelOffset, DY+PixelOffset);
   try
     cairo_move_to(Widget, SX(X1+RX), SY(Y1));
     cairo_line_to(Widget, SX(X2-RX), SY(Y1));
@@ -1869,8 +1866,6 @@
 end;
 
 function TGtk3DeviceContext.LineTo(X, Y: Integer): Boolean;
-const
-  PixelOffset = 0.5;
 var
   FX, FY: Double;
   X0, Y0: Integer;
@@ -1909,8 +1904,6 @@
 end;
 
 function TGtk3DeviceContext.MoveTo(const X, Y: Integer; OldPoint: PPoint): Boolean;
-const
-  PixelOffset = 0.5;
 var
   dx: Double;
   dy: Double;
Index: lcl/interfaces/gtk3/gtk3winapi.inc
===================================================================
--- lcl/interfaces/gtk3/gtk3winapi.inc	(revision 62418)
+++ lcl/interfaces/gtk3/gtk3winapi.inc	(working copy)
@@ -1699,6 +1699,8 @@
 end;
 
 function TGtk3WidgetSet.FrameRect(DC: HDC; const ARect: TRect; hBr: HBRUSH): Integer;
+const
+  PixelOffset = 0.5;
 var
   cr: Pcairo_t;
 begin
@@ -1709,7 +1711,7 @@
   if not IsValidDC(DC) then
     exit;
   cr := TGtk3DeviceContext(DC).Widget;
-  cairo_rectangle(cr, ARect.Left, ARect.Top, ARect.Right-ARect.Left-1, ARect.Bottom-ARect.Top-1);
+  cairo_rectangle(cr, ARect.Left+PixelOffset, ARect.Top+PixelOffset, ARect.Right-ARect.Left-1, ARect.Bottom-ARect.Top-1);
   if IsValidGDIObject(hBr) then
     TGtk3DeviceContext(DC).SetSourceColor(TGtk3Brush(HBR).Color);
   cairo_set_line_width(cr, 1);
offs.diff (5,480 bytes)

Juha Manninen

2019-12-20 12:36

developer   ~0119971

Alexey, you last offs.diff is bad. It causes all graphic objects to move slowly to South-East when the window is resized. You can make the window either bigger or smaller, they always move to South-East.
Clearly the 0.5 offset somehow accumulates although I don't know how.

CudaText man

2019-12-20 13:23

reporter   ~0119973

Thanks for note!
fixed! and fixed FillRect blurry border as well.
fix2.diff

fix2.diff (6,934 bytes)
Index: lcl/interfaces/gtk3/gtk3objects.pas
===================================================================
--- lcl/interfaces/gtk3/gtk3objects.pas	(revision 62418)
+++ lcl/interfaces/gtk3/gtk3objects.pas	(working copy)
@@ -296,9 +296,13 @@
 function ReplaceAmpersandsWithUnderscores(const S: string): string; inline;
 
 implementation
+
 uses math, gtk3int, gtk3procs;
 
 const
+  PixelOffset = 0.5; // Cairo API needs 0.5 pixel offset to not make blurry lines
+
+const
   Dash_Dash:        array [0..1] of double = (18, 6);             //____ ____
   Dash_Dot:         array [0..1] of double = (3, 3);              //.........
   Dash_DashDot:     array [0..3] of double = (9, 6, 3, 6);        //__ . __ .
@@ -1329,7 +1333,7 @@
 begin
   cairo_save(Widget);
   try
-    cairo_rectangle(Widget, x1, y1, w - 1, h - 1);
+    cairo_rectangle(Widget, x1 + PixelOffset, y1 + PixelOffset, w - 1, h - 1);
 
     if AFill then
     begin
@@ -1429,7 +1433,7 @@
   cairo_save(Widget);
   try
     cairo_get_matrix(Widget, @save_matrix);
-    cairo_translate (Widget, x + w / 2.0, y + h / 2.0);
+    cairo_translate (Widget, x + w / 2.0 + PixelOffset, y + h / 2.0 + PixelOffset);
     cairo_scale (Widget, w / 2.0, h / 2.0);
     cairo_new_path(Widget);
     cairo_arc
@@ -1471,7 +1475,7 @@
   cairo_save(Widget);
   try
     with targetRect^ do
-      cairo_rectangle(Widget, Left, Top, Right - Left, Bottom - Top);
+      cairo_rectangle(Widget, Left + PixelOffset, Top + PixelOffset, Right - Left, Bottom - Top);
     cairo_set_source_surface(Widget, Surface, 0, 0);
     cairo_matrix_init_identity(@M);
     cairo_matrix_translate(@M, SourceRect^.Left, SourceRect^.Top);
@@ -1488,10 +1492,10 @@
 
 procedure TGtk3DeviceContext.drawImage(targetRect: PRect; image: PGdkPixBuf;
   sourceRect: PRect; mask: PGdkPixBuf; maskRect: PRect);
-var
-  pm: PGdkPixbuf;
-  AData: PByte;
-  ASurface: Pcairo_surface_t;
+//var
+//  pm: PGdkPixbuf;
+//  AData: PByte;
+//  ASurface: Pcairo_surface_t;
 begin
   {$IFDEF VerboseGtk3DeviceContext}
   DebugLn('TGtk3DeviceContext.DrawImage ');
@@ -1498,13 +1502,13 @@
   {$ENDIF}
   cairo_save(Widget);
   try
-    pm := Image;
+    // pm := Image;
     // AData := PByte(gdk_pixbuf_get_pixels(pm));
     // ASurface := cairo_image_surface_create_for_data(AData, CAIRO_FORMAT_ARGB32, gdk_pixbuf_get_width(pm), gdk_pixbuf_get_height(pm), gdk_pixbuf_get_rowstride(pm));
     // cairo_set_source_surface(Widget, ASurface, targetRect^.Left, targetRect^.Top);
     gdk_cairo_set_source_pixbuf(Widget, Image, 0, 0);
     with targetRect^ do
-    cairo_rectangle(Widget, Left, Top, Right-Left, Bottom-Top);
+      cairo_rectangle(Widget, Left + PixelOffset, Top + PixelOffset, Right - Left, Bottom - Top);
     cairo_paint(Widget);
   finally
     // cairo_surface_destroy(ASurface);
@@ -1524,7 +1528,7 @@
   try
     gdk_cairo_set_source_pixbuf(Widget, Image, 0, 0);
     with targetRect^ do
-      cairo_rectangle(Widget, Left, Top, Right - Left, Bottom - Top);
+      cairo_rectangle(Widget, Left + PixelOffset, Top + PixelOffset, Right - Left, Bottom - Top);
 
     cairo_matrix_init_identity(@M);
     cairo_matrix_translate(@M, SourceRect^.Left, SourceRect^.Top);
@@ -1563,8 +1567,6 @@
 end;
 
 procedure TGtk3DeviceContext.drawPolyLine(P: PPoint; NumPts: Integer);
-const
-  PixelOffset = 0.5;
 var
   i: Integer;
 begin
@@ -1585,8 +1587,6 @@
   FillRule: Integer; AFill, ABorder: Boolean);
 var
   i: Integer;
-const
-  PixelOffset = 0.5;
 begin
   cairo_save(Widget);
   try
@@ -1619,8 +1619,6 @@
 var
   MaxIndex, i: Integer;
   bFill, bBorder: Boolean;
-const
-  PixelOffset = 0.5;
 begin
   // 3 points per curve + a starting point for the first curve
   if (NumPoints < 4) then
@@ -1691,9 +1689,6 @@
 
 procedure TGtk3DeviceContext.fillRect(x, y, w, h: Integer; ABrush: HBRUSH);
 var
-  //devx, devy, dx, dy, dw, dh: Double;
-  //ATarget: Pcairo_surface_t;
-  //ANewSurface: Pcairo_surface_t;
   ATempBrush: TGtk3Brush;
 begin
   {$ifdef VerboseGtk3DeviceContext}
@@ -1706,36 +1701,24 @@
     if ABrush <> 0 then
     begin
       ATempBrush := FCurrentBrush;
-      fBkMode:=OPAQUE;
+      fBkMode := OPAQUE;
       SetCurrentBrush(TGtk3Brush(ABrush));
     end;
 
     applyBrush;
-    cairo_rectangle(Widget, x, y, w - 1, h - 1);
-    cairo_fill(Widget);
+    cairo_rectangle(Widget, x + PixelOffset, y + PixelOffset, w - 1, h - 1);
+    cairo_fill_preserve(Widget);
 
+    // must paint border, filling is not enough
+    SetSourceColor(FCurrentBrush.Color);
+    cairo_set_line_width(Widget, 1);
+    cairo_stroke(Widget);
+
     if ABrush <> 0 then
       SetCurrentBrush(ATempBrush);
   finally
     cairo_restore(Widget);
   end;
-
-  // ATarget := cairo_get_target(Widget);
-  (*
-  cairo_save(Widget);
-  dx := x;
-  dy := y;
-  dw := w;
-  dh := h;
-  ANewSurface := cairo_surface_create_similar(ATarget, cairo_surface_get_content(ATarget), w, h);
-  cairo_set_source_surface(Widget, ANewSurface, x , y);
-  cairo_clip(Widget);
-  vBrush.SetColor(clRed);
-  cairo_rectangle(Widget, dx, dy, dw, dh);
-  cairo_fill(Widget);
-  cairo_surface_destroy(ANewSurface);
-  cairo_restore(Widget);
-  *)
 end;
 
 procedure TGtk3DeviceContext.fillRect(x, y, w, h: Integer);
@@ -1779,15 +1762,14 @@
   end;
 end;
 
-function TGtk3DeviceContext.RoundRect(X1, Y1, X2, Y2: Integer; RX, RY: Integer
-  ): Boolean;
+function TGtk3DeviceContext.RoundRect(X1, Y1, X2, Y2: Integer; RX, RY: Integer): Boolean;
 var
-  DX: Double;
-  DY: Double;
-  Pt: TPoint;
+  DX, DY: Double;
 begin
   Result := False;
   cairo_surface_get_device_offset(cairo_get_target(Widget), @DX, @DY);
+  DX := DX+PixelOffset;
+  DY := DY+PixelOffset;
   cairo_translate(Widget, DX, DY);
   try
     cairo_move_to(Widget, SX(X1+RX), SY(Y1));
@@ -1869,8 +1851,6 @@
 end;
 
 function TGtk3DeviceContext.LineTo(X, Y: Integer): Boolean;
-const
-  PixelOffset = 0.5;
 var
   FX, FY: Double;
   X0, Y0: Integer;
@@ -1909,8 +1889,6 @@
 end;
 
 function TGtk3DeviceContext.MoveTo(const X, Y: Integer; OldPoint: PPoint): Boolean;
-const
-  PixelOffset = 0.5;
 var
   dx: Double;
   dy: Double;
Index: lcl/interfaces/gtk3/gtk3winapi.inc
===================================================================
--- lcl/interfaces/gtk3/gtk3winapi.inc	(revision 62418)
+++ lcl/interfaces/gtk3/gtk3winapi.inc	(working copy)
@@ -1699,6 +1699,8 @@
 end;
 
 function TGtk3WidgetSet.FrameRect(DC: HDC; const ARect: TRect; hBr: HBRUSH): Integer;
+const
+  PixelOffset = 0.5;
 var
   cr: Pcairo_t;
 begin
@@ -1709,7 +1711,7 @@
   if not IsValidDC(DC) then
     exit;
   cr := TGtk3DeviceContext(DC).Widget;
-  cairo_rectangle(cr, ARect.Left, ARect.Top, ARect.Right-ARect.Left-1, ARect.Bottom-ARect.Top-1);
+  cairo_rectangle(cr, ARect.Left+PixelOffset, ARect.Top+PixelOffset, ARect.Right-ARect.Left-1, ARect.Bottom-ARect.Top-1);
   if IsValidGDIObject(hBr) then
     TGtk3DeviceContext(DC).SetSourceColor(TGtk3Brush(HBR).Color);
   cairo_set_line_width(cr, 1);
fix2.diff (6,934 bytes)

Juha Manninen

2019-12-20 18:06

developer   ~0119976

Ok, looks good. I applied fix2.diff.

Issue History

Date Modified Username Field Change
2019-12-12 18:54 CudaText man New Issue
2019-12-12 18:54 CudaText man File Added: gtk2-gtk3.png
2019-12-12 18:54 CudaText man File Added: Canvas figures tests.zip
2019-12-12 22:54 Juha Manninen Relationship added related to 0036374
2019-12-13 14:31 CudaText man File Added: fix1.diff
2019-12-13 14:31 CudaText man Note Added: 0119819
2019-12-16 21:47 CudaText man Note Added: 0119890
2019-12-18 07:03 hamidhb File Added: 518fdf7c56d8d.png
2019-12-18 07:03 hamidhb Note Added: 0119905
2019-12-18 12:13 CudaText man Note Added: 0119907
2019-12-18 12:14 CudaText man Note Edited: 0119907 View Revisions
2019-12-18 12:35 Juha Manninen Relationship added related to 0036444
2019-12-18 21:57 Juha Manninen Assigned To => Juha Manninen
2019-12-18 21:57 Juha Manninen Status new => assigned
2019-12-18 22:06 Juha Manninen Status assigned => resolved
2019-12-18 22:06 Juha Manninen Resolution open => fixed
2019-12-18 22:06 Juha Manninen Fixed in Revision => r62416
2019-12-18 22:06 Juha Manninen LazTarget => -
2019-12-18 22:06 Juha Manninen Widgetset GTK 3 => GTK 3
2019-12-18 22:06 Juha Manninen Note Added: 0119930
2019-12-19 12:12 CudaText man File Added: offs.diff
2019-12-19 12:12 CudaText man Note Added: 0119943
2019-12-19 12:12 CudaText man Status resolved => assigned
2019-12-19 12:12 CudaText man Resolution fixed => reopened
2019-12-19 12:12 CudaText man Note Edited: 0119943 View Revisions
2019-12-20 12:36 Juha Manninen Status assigned => feedback
2019-12-20 12:36 Juha Manninen Note Added: 0119971
2019-12-20 13:23 CudaText man File Added: fix2.diff
2019-12-20 13:23 CudaText man Note Added: 0119973
2019-12-20 13:23 CudaText man Status feedback => assigned
2019-12-20 18:06 Juha Manninen Status assigned => resolved
2019-12-20 18:06 Juha Manninen Fixed in Revision r62416 => r62416, r62424
2019-12-20 18:06 Juha Manninen Widgetset GTK 3 => GTK 3
2019-12-20 18:06 Juha Manninen Note Added: 0119976