LCL-GTK3: Improve canvas operations. Issue #36374, patch from Alexey Tor.

git-svn-id: trunk@62380 -
This commit is contained in:
juha 2019-12-12 13:53:41 +00:00
parent 9449a23949
commit 0bd01ab2ed
3 changed files with 105 additions and 82 deletions

View File

@ -229,12 +229,12 @@ type
procedure DeleteObjects;
public
procedure drawPoint(x1: Integer; y1: Integer);
procedure drawRect(x1: Integer; y1: Integer; w: Integer; h: Integer; const AFill: Boolean);
procedure drawRect(x1, y1, w, h: Integer; const AFill, ABorder: Boolean);
procedure drawRoundRect(x, y, w, h, rx, ry: Integer);
procedure drawText(x: Integer; y: Integer; const s: String); overload;
procedure drawText(x,y,w,h,flags: Integer; const s: String); overload;
procedure drawLine(x1: Integer; y1: Integer; x2: Integer; y2: Integer);
procedure drawEllipse(x: Integer; y: Integer; w: Integer; h: Integer);
procedure drawEllipse(x, y, w, h: Integer; AFill, ABorder: Boolean);
procedure drawSurface(targetRect: PRect; Surface: Pcairo_surface_t; sourceRect: PRect;
mask: PGdkPixBuf; maskRect: PRect);
procedure drawImage(targetRect: PRect; image: PGdkPixBuf; sourceRect: PRect;
@ -243,7 +243,8 @@ type
mask: PGdkPixBuf; maskRect: PRect);
procedure drawPixmap(p: PPoint; pm: PGdkPixbuf; sr: PRect);
procedure drawPolyLine(P: PPoint; NumPts: Integer);
procedure drawPolygon(P: PPoint; NumPts: Integer; FillRule: integer);
procedure drawPolygon(P: PPoint; NumPts: Integer; FillRule: Integer; AFill,
ABorder: Boolean);
procedure drawPolyBezier(P: PPoint; NumPoints: Integer; Filled, Continuous: boolean);
procedure EllipseArcPath(CX, CY, RX, RY: Double; Angle1, Angle2: Double; Clockwise, Continuous: Boolean);
procedure eraseRect(ARect: PRect);
@ -1324,20 +1325,22 @@ begin
cairo_stroke(Widget);
end;
procedure TGtk3DeviceContext.drawRect(x1: Integer; y1: Integer; w: Integer;
h: Integer; const AFill: Boolean);
procedure TGtk3DeviceContext.drawRect(x1, y1, w, h: Integer; const AFill, ABorder: Boolean);
begin
cairo_save(Widget);
try
ApplyPen;
cairo_rectangle(Widget, x1, y1, w, h);
cairo_stroke(Widget);
if AFill then
begin
cairo_rectangle(Widget, x1, y1, w - 1, h - 1);
ApplyBrush;
cairo_fill(Widget);
end;
if ABorder then
begin
ApplyPen;
cairo_rectangle(Widget, x1, y1, w - 1, h - 1);
cairo_stroke(Widget);
end;
finally
cairo_restore(Widget);
end;
@ -1407,7 +1410,6 @@ begin
finally
cairo_restore(Widget);
end;
end;
procedure TGtk3DeviceContext.drawLine(x1: Integer; y1: Integer; x2: Integer;
@ -1418,31 +1420,41 @@ begin
cairo_line_to(Widget, x2, y2);
end;
procedure TGtk3DeviceContext.drawEllipse(x: Integer; y: Integer; w: Integer;
h: Integer);
procedure TGtk3DeviceContext.drawEllipse(x, y, w, h: Integer; AFill, ABorder: Boolean);
var
save_matrix:cairo_matrix_t;
begin
cairo_save(Widget);
cairo_get_matrix(Widget, @save_matrix);
cairo_translate (Widget, x + w / 2.0, y + h / 2.0);
cairo_scale (Widget, w / 2.0, h / 2.0);
try
cairo_get_matrix(Widget, @save_matrix);
cairo_translate (Widget, x + w / 2.0, y + h / 2.0);
cairo_scale (Widget, w / 2.0, h / 2.0);
cairo_new_path(Widget);
cairo_arc
(
(*cr =*) Widget,
(*xc =*) 0,
(*yc =*) 0,
(*radius =*) 1,
(*angle1 =*) 0,
(*angle2 =*) 2 * Pi
);
cairo_close_path(Widget);
if AFill then
begin
ApplyBrush;
cairo_fill_preserve(Widget);
end;
finally
cairo_restore(Widget);
end;
if ABorder then
begin
ApplyPen;
cairo_stroke(Widget);
end;
//if ABorder=false, need to clear current path
cairo_new_path(Widget);
cairo_arc
(
(*cr =*) Widget,
(*xc =*) 0,
(*yc =*) 0,
(*radius =*) 1,
(*angle1 =*) 0,
(*angle2 =*) 2 * Pi
);
cairo_close_path(Widget);
ApplyBrush;
cairo_fill_preserve(Widget);
cairo_restore(Widget);
ApplyPen;
cairo_stroke(Widget);
end;
procedure TGtk3DeviceContext.drawSurface(targetRect: PRect;
@ -1568,7 +1580,7 @@ begin
end;
procedure TGtk3DeviceContext.drawPolygon(P: PPoint; NumPts: Integer;
FillRule: integer);
FillRule: Integer; AFill, ABorder: Boolean);
var
i: Integer;
const
@ -1576,25 +1588,28 @@ const
begin
cairo_save(Widget);
try
// first apply the fill because the line is drawn over the filled area after
applyBrush;
cairo_set_fill_rule(Widget, cairo_fill_rule_t(FillRule));
// + Offset is so the center of the pixel is used.
cairo_move_to(Widget, P[0].X+PixelOffset, P[0].Y+PixelOffset);
for i := 1 to NumPts-1 do
cairo_line_to(Widget, P[i].X+PixelOffset, P[i].Y+PixelOffset);
if AFill then
begin
// first apply the fill because the line is drawn over the filled area after
ApplyBrush;
cairo_set_fill_rule(Widget, cairo_fill_rule_t(FillRule));
// + Offset is so the center of the pixel is used.
cairo_move_to(Widget, P[0].X+PixelOffset, P[0].Y+PixelOffset);
for i := 1 to NumPts-1 do
cairo_line_to(Widget, P[i].X+PixelOffset, P[i].Y+PixelOffset);
cairo_close_path(Widget);
cairo_fill(Widget);
end;
cairo_close_path(Widget);
cairo_fill_preserve(Widget);
// now draw the line
ApplyPen;
//cairo_set_antialias(widget, CAIRO_ANTIALIAS_SUBPIXEL);
cairo_move_to(Widget, P[0].X+PixelOffset, P[0].Y+PixelOffset);
for i := 1 to NumPts-1 do
cairo_line_to(Widget, P[i].X+PixelOffset, P[i].Y+PixelOffset);
cairo_close_path(Widget);
cairo_stroke_preserve(Widget);
if ABorder then
begin
ApplyPen;
cairo_move_to(Widget, P[0].X+PixelOffset, P[0].Y+PixelOffset);
for i := 1 to NumPts-1 do
cairo_line_to(Widget, P[i].X+PixelOffset, P[i].Y+PixelOffset);
cairo_close_path(Widget);
cairo_stroke(Widget);
end;
finally
cairo_restore(Widget);
end;
@ -1657,10 +1672,9 @@ end;
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;
ACairo: Pcairo_t;
//devx, devy, dx, dy, dw, dh: Double;
//ATarget: Pcairo_surface_t;
//ANewSurface: Pcairo_surface_t;
ATempBrush: TGtk3Brush;
begin
{$ifdef VerboseGtk3DeviceContext}
@ -1668,25 +1682,25 @@ begin
{$endif}
cairo_save(Widget);
ATempBrush := nil;
if ABrush <> 0 then
begin
ATempBrush := FCurrentBrush;
fBkMode:=OPAQUE;
SetCurrentBrush(TGtk3Brush(ABrush));
try
ATempBrush := nil;
if ABrush <> 0 then
begin
ATempBrush := FCurrentBrush;
fBkMode:=OPAQUE;
SetCurrentBrush(TGtk3Brush(ABrush));
end;
applyBrush;
cairo_rectangle(Widget, x, y, w - 1, h - 1);
cairo_fill(Widget);
if ABrush <> 0 then
SetCurrentBrush(ATempBrush);
finally
cairo_restore(Widget);
end;
applyBrush;
cairo_rectangle(Widget, x, y, w, h);
cairo_stroke_preserve(Widget);
cairo_fill(Widget);
// cairo_clip(Widget);
// cairo_fill_preserve(Widget);
if ABrush <> 0 then
SetCurrentBrush(ATempBrush);
cairo_restore(Widget);
// ATarget := cairo_get_target(Widget);
(*
cairo_save(Widget);

View File

@ -3079,7 +3079,7 @@ begin
end;
if BorderStyle <> bsNone then
DC.drawRect(0, 0, LCLObject.Width, LCLObject.Height, LCLObject.Color <> clDefault);
DC.drawRect(0, 0, LCLObject.Width, LCLObject.Height, LCLObject.Color <> clDefault, True);
end;
function TGtk3Panel.getText: String;

View File

@ -1052,9 +1052,13 @@ begin
end;
function TGtk3WidgetSet.Ellipse(DC: HDC; x1, y1, x2, y2: Integer): Boolean;
var
bFill, bBorder: Boolean;
begin
TGtk3DeviceContext(DC).drawEllipse(x1,y1,x2-x1,y2-y1);
Result:=true;
bFill := TGtk3DeviceContext(DC).CurrentBrush.Style <> BS_NULL;
bBorder := TGtk3DeviceContext(DC).CurrentPen.Style <> psClear;
TGtk3DeviceContext(DC).drawEllipse(x1, y1, x2 - x1 - 1, y2 - y1 - 1, bFill, bBorder);
Result := True;
end;
function TGtk3WidgetSet.EnableScrollBar(Wnd: HWND; wSBflags, wArrows: Cardinal
@ -1694,8 +1698,7 @@ begin
end;
function TGtk3WidgetSet.FrameRect(DC: HDC; const ARect: TRect; hBr: HBRUSH
): Integer;
function TGtk3WidgetSet.FrameRect(DC: HDC; const ARect: TRect; hBr: HBRUSH): Integer;
var
cr: Pcairo_t;
begin
@ -1706,7 +1709,7 @@ begin
if not IsValidDC(DC) then
exit;
cr := TGtk3DeviceContext(DC).Widget;
cairo_rectangle(cr, ARect.Left, ARect.Top, ARect.Right-ARect.Left, ARect.Bottom-ARect.Top);
cairo_rectangle(cr, ARect.Left, ARect.Top, 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);
@ -3143,13 +3146,19 @@ end;
function TGtk3WidgetSet.Polygon(DC: HDC; Points: PPoint; NumPts: Integer;
Winding: boolean): boolean;
var
NFillRule: integer;
bFill, bBorder: boolean;
begin
if not IsValidDC(DC) then
exit(False);
if not Winding then // faster
TGtk3DeviceContext(DC).drawPolygon(Points, NumPts, ord(CAIRO_FILL_RULE_EVEN_ODD))
if Winding then
NFillRule := Ord(CAIRO_FILL_RULE_WINDING)
else
TGtk3DeviceContext(DC).drawPolygon(Points, NumPts, Ord(CAIRO_FILL_RULE_WINDING));
NFillRule := Ord(CAIRO_FILL_RULE_EVEN_ODD);
bFill := TGtk3DeviceContext(DC).CurrentBrush.Style <> BS_NULL;
bBorder := TGtk3DeviceContext(DC).CurrentPen.Style <> psClear;
TGtk3DeviceContext(DC).drawPolygon(Points, NumPts, NFillRule, bFill, bBorder);
Result:= True;
end;
@ -3257,15 +3266,15 @@ end;
function TGtk3WidgetSet.Rectangle(DC: HDC; X1, Y1, X2, Y2: Integer): Boolean;
var
R: TRect;
bFill, bBorder: Boolean;
begin
if not IsValidDC(DC) then
exit(False);
R := NormalizeRect(Rect(X1, Y1, X2, Y2));
if IsRectEmpty(R) then Exit(True);
with R do
TGtk3DeviceContext(DC).drawRect(Left, Top, Right - Left, Bottom - Top,
TGtk3DeviceContext(DC).CurrentBrush.Style<>BS_NULL{bsClear}
);
bFill := TGtk3DeviceContext(DC).CurrentBrush.Style <> BS_NULL;
bBorder := TGtk3DeviceContext(DC).CurrentPen.Style <> psClear;
TGtk3DeviceContext(DC).drawRect(R.Left, R.Top, R.Right - R.Left, R.Bottom - R.Top, bFill, bBorder);
Result := True;
end;