Describe the bug
In FLTK 1.4 + X11 only, rects and lines drawn by fl_draw.H are clipped incorrectly when dealing with positions/sizes greater than 16-bit.
For example, a rect will be clipped incorrectly if its width is greater than 32,767 and its x position is negative.
And a vertical yx line will have its x position clipped incorrectly if its x position is greater than 65,535.
There may be more scenarios, but these are the two that come up in my experience.
To Reproduce
Here is a heavily modified version of test/scroll.cxx to demonstrate the issue:
Summary of the program:
The window contains an Fl_Scroll with a single Drawing widget inside it.
The Drawing widget uses fl_rectf() to draw horizontal stripes of alternating color that span the width of the widget, and uses fl_yxline() to draw uniformly spaced black vertical lines along the width of the widget.
There is an Fl_Slider below the Fl_Scroll which controls the width of the Drawing widget. The current width of the Drawing widget is also displayed in the window's title bar for convenience.
Steps to reproduce the behavior:
Replace test/scroll.cxx with the above code
Compile test/scroll.cxx like normal
Run test/scroll
Use the slider to increase the width of the drawing area higher and higher
See that the yx lines start drawing at unexpected positions after exceeding 65,535, and continues to get worse as it gets even wider
Scroll the Fl_Scroll to the right to any non-zero position (to set the x position of the Drawing widget to a negative value)
See that the rects clip incorrectly after exceeding a width of 32,767
Expected behavior
Even with a width greater than 32,767 or 65,535 and with a negative x position, rects and lines should be clipped sensibly and be drawn as normal (drawn the same as with a width less than 32,767 or with a non-negative x position).
Additional context
This bug is not present in FLTK 1.3 on X11, and the bug is also not present in FLTK 1.4 on Windows or Mac. (I have not tested Wayland.)
The bug appears to be new to FLTK 1.4 and only occurs on X11.
Here is the same program from above working correctly on X11 using FLTK 1.3:
And here is a very crude patch for Fl_Xlib_Graphics_Driver_rect.cxx which restores part of the implementation from FLTK 1.3 simply to demonstrate that this code is the source of the incorrect clipping:
diff --git a/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_rect.cxx b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_rect.cxx
index ea24eba34..cae364ee5 100644
--- a/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_rect.cxx+++ b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_rect.cxx@@ -60,7 +60,7 @@
int Fl_Xlib_Graphics_Driver::clip_line(int &x1, int &y1, int &x2, int &y2) {
// define variables
- float p1 = float(-(x2 - x1));+ /* float p1 = float(-(x2 - x1));
float p2 = float(-p1);
float p3 = float(-(y2 - y1));
float p4 = float(-p3);
@@ -108,7 +108,31 @@ int Fl_Xlib_Graphics_Driver::clip_line(int &x1, int &y1, int &x2, int &y2) {
y2 = int(y1 + p4 * posmin);
x1 = int(x1 + p2 * negmax);
- y1 = int(y1 + p4 * negmax);+ y1 = int(y1 + p4 * negmax); */++ int lw = 1;+ int kmin = -lw;+ int kmax = 32767 - lw;++ if (x1 < kmin)+ x1 = kmin;+ else if (x1 > kmax)+ x1 = kmax;++ if (y1 < kmin)+ y1 = kmin;+ else if (y1 > kmax)+ y1 = kmax;++ if (x2 < kmin)+ x2 = kmin;+ else if (x2 > kmax)+ x2 = kmax;++ if (y2 < kmin)+ y2 = kmin;+ else if (y2 > kmax)+ y2 = kmax;
return 0; // not clipped
@@ -173,14 +197,27 @@ int Fl_Xlib_Graphics_Driver::clip_line(int &x1, int &y1, int &x2, int &y2) {
int Fl_Xlib_Graphics_Driver::clip_rect(int &x, int &y, int &w, int &h) {
- if (w <= 0 || h <= 0) return 1; // (a)+ /* if (w <= 0 || h <= 0) return 1; // (a)
if (x+w < clip_min() || y+h < clip_min()) return 1; // (b)
if (x > clip_max() || y > clip_max()) return 1; // (c)
if (x < clip_min()) { w -= (clip_min()-x); x = clip_min(); }
if (y < clip_min()) { h -= (clip_min()-y); y = clip_min(); }
if (x+w > clip_max()) w = clip_max() - x;
- if (y+h > clip_max()) h = clip_max() - y;+ if (y+h > clip_max()) h = clip_max() - y; */++ int lw = 1;+ int kmin = -lw;+ int kmax = 32767 - lw;++ if (w <= 0 || h <= 0) return 1; // (a)+ if (x+w < kmin || y+h < kmin) return 1; // (b)+ if (x > kmax || y > kmax) return 1; // (c)++ if (x < kmin) { w -= (kmin-x); x = kmin; }+ if (y < kmin) { h -= (kmin-y); y = kmin; }+ if (x+w > kmax) w = kmax - x;+ if (y+h > kmax) h = kmax - y;
return 0;
}
With this patch, the above demo program functions exactly as expected (again, only for demonstration purposes).
— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you are subscribed to this thread.Message ID: <fltk/fltk/issues/963@github.com>
Comments are owned by the poster. All other content is copyright 1998-2025 by Bill Spitzak and others. This project is hosted by The FLTK Team. Please report site problems to 'erco@seriss.com'.