FLTK logo

[fltk/fltk] FLTK 1.4: X11 Clipping bugs (Issue #963)

FLTK matrix user chat room
(using Element browser app)   FLTK gitter user chat room   GitHub FLTK Project   FLTK News RSS Feed  
  FLTK Apps      FLTK Library      Forums      Links     Login 
 All Forums  |  Back to fltk.issues  ]
 
Previous Message ]New Message | Reply ]Next Message ]

[fltk/fltk] FLTK 1.4: X11 Clipping bugs (Issue #963) dannye 11:24 Apr 28  
 

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:

#include <FL/Fl.H>
#include <FL/Fl_Double_Window.H>
#include <FL/Fl_Scroll.H>
#include <FL/Fl_Slider.H>
#include <FL/fl_draw.H>

class Drawing : public Fl_Widget {
  void draw() override;
public:
  Drawing(int X,int Y,int W,int H,const char* L) : Fl_Widget(X,Y,W,H,L) {}
};

void Drawing::draw() {
  for (int i = 0; i < h() / 20; i++) {
    fl_rectf(x(), y() + i * 20, w(), 20, i % 2 ? FL_LIGHT1 : FL_DARK2);
  }
  fl_color(FL_BLACK);
  for (int i = 0; i < w() / 50; i++) {
    fl_yxline(x() + i * 50, y(), y()+h());
  }
}

void set_window_label(Fl_Window *w, int v) {
  char buffer[64] = {};
  sprintf(buffer, "Scroll Width: %d", v);
  w->copy_label(buffer);
}

void slider_cb(Fl_Slider *w) {
  Drawing *drawing = (Drawing *)w->user_data();
  drawing->size(w->value(), drawing->h());
  drawing->redraw();
  set_window_label(drawing->window(), (int)w->value());
}

int main(int argc, char** argv) {
  Fl_Double_Window window(5*75,320);
  window.resizable(nullptr);
  set_window_label(&window, 50*75);

  Fl_Scroll scroll(0,0,5*75,300);
  Drawing drawing(0,0,50*75,300,0);
  scroll.type(Fl_Scroll::HORIZONTAL);
  scroll.end();

  Fl_Slider slider(0, 300, 5*75, 20);
  slider.type(FL_HORIZONTAL);
  slider.value(50*75);
  slider.bounds(50*75, 5000*75);
  slider.user_data(&drawing);
  slider.callback((Fl_Callback *)slider_cb);

  window.end();
  window.show(argc,argv);
  return Fl::run();
}

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:

  1. Replace test/scroll.cxx with the above code
  2. Compile test/scroll.cxx like normal
  3. Run test/scroll
  4. Use the slider to increase the width of the drawing area higher and higher
  5. See that the yx lines start drawing at unexpected positions after exceeding 65,535, and continues to get worse as it gets even wider
  6. 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)
  7. 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).

Video

https://github.com/fltk/fltk/assets/5231310/c3d5db3e-937d-4dd4-954d-3fb83524ea3f

FLTK Version

  • Version: 1.4.0
  • Downloaded and self-built from: Git
  • If from Git, branch: master
  • If from Git, commit: 8664fde

FLTK Configure / Build Options

  • ./configure

Operating System / Platform:

  • OS: Linux
  • OS Version: Peppermint OS 10
  • Processor if relevant: Intel

Linux/Unix Runtime, if applicable:

  • X11

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:

https://github.com/fltk/fltk/assets/5231310/4e6d3894-f6b2-475b-827a-4a1f9faba230

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>

Direct Link to Message ]
 
     
Previous Message ]New Message | Reply ]Next Message ]
 
 

Comments are owned by the poster. All other content is copyright 1998-2024 by Bill Spitzak and others. This project is hosted by The FLTK Team. Please report site problems to 'erco@seriss.com'.