More clipping fixes for X11 with coordinates > 32767 (STR #2304).

The following functions are fixed now:
  fl_rect(x,y,w,h),
  fl_rectf(x,y,w,h),
  fl_not_clipped(x,y,w,h),
  fl_xyline(x, y, x1), and
  fl_yxline(x, y, y1).
 
These functions are sufficient for basic box and frame drawing functions,
but maybe there are other functions left.

Note that fl_xyline() and fl_yxline() are fixed only for one line segment.
Those with more line segments need still to be fixed.


git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3@7884 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
This commit is contained in:
Albrecht Schlosser 2010-11-22 18:17:51 +00:00
parent cdad633e87
commit 3a807e55bc

View File

@ -47,11 +47,62 @@ extern float fl_quartz_line_width_;
#define USINGQUARTZPRINTER (Fl_Surface_Device::surface()->type() == Fl_Printer::device_type)
#endif
#ifdef USE_X11
#ifndef SHRT_MAX
#define SHRT_MAX (32767)
#endif
/*
We need to check some coordinates for areas for clipping before we
use X calls, because X can't handle coordinates outside the 16-bit
range. Since windows use relative coordinates > 0, we do also check
for negative values. X11 only, see also STR #2304.
Note:
We could use max. screen coordinates instead of SHRT_MAX, but that
would need more work and would probably be slower.
returns 1, if the area is invisible (clipped), because ...
(a) w or h are <= 0 i.e. nothing is visible
(b) x+w or y+h are < 0 i.e. left of or above visible area
(c) x or y are > SHRT_MAX i.e. right of or below visible area
returns 0, if the area is potentially visible and X can handle the
clipping. x, y, w, and h may have been adjusted to fit into the
X coordinate space.
*/
static int clip_to_short(int &x, int &y, int &w, int &h) {
if (w <= 0 || h <= 0) return 1; // (a)
if (x+w < 0 || y+h < 0) return 1; // (b)
if (x > SHRT_MAX || y > SHRT_MAX) return 1; // (c)
if (x < 0) { w += x; x = 0; }
if (y < 0) { h += y; y = 0; }
if (x+w > SHRT_MAX) w = SHRT_MAX - x;
if (y+h > SHRT_MAX) h = SHRT_MAX - y;
return 0;
}
#endif // USE_X11
void Fl_Graphics_Driver::rect(int x, int y, int w, int h) {
if (w<=0 || h<=0) return;
#if defined(USE_X11)
XDrawRectangle(fl_display, fl_window, fl_gc, x, y, w-1, h-1);
if (x+w < 0 || y+h < 0 || x > SHRT_MAX || y > SHRT_MAX ) return;
if (x+w > SHRT_MAX || y+h > SHRT_MAX ||
w > SHRT_MAX || h > SHRT_MAX) { // X can't handle clipping
xyline(x, y, x+w-1);
yxline(x+w-1, y, y+h-1);
xyline(x+w-1, y+h-1, x);
yxline(x, y+h-1, y);
} else
XDrawRectangle(fl_display, fl_window, fl_gc, x, y, w-1, h-1);
#elif defined(WIN32)
MoveToEx(fl_gc, x, y, 0L);
LineTo(fl_gc, x+w-1, y);
@ -71,7 +122,10 @@ void Fl_Graphics_Driver::rect(int x, int y, int w, int h) {
void Fl_Graphics_Driver::rectf(int x, int y, int w, int h) {
if (w<=0 || h<=0) return;
#if defined(USE_X11)
if (w && h) XFillRectangle(fl_display, fl_window, fl_gc, x, y, w, h);
if (w && h) {
if (!clip_to_short(x,y,w,h))
XFillRectangle(fl_display, fl_window, fl_gc, x, y, w, h);
}
#elif defined(WIN32)
RECT rect;
rect.left = x; rect.top = y;
@ -89,6 +143,17 @@ void Fl_Graphics_Driver::rectf(int x, int y, int w, int h) {
void Fl_Graphics_Driver::xyline(int x, int y, int x1) {
#if defined(USE_X11)
// get rid of coordinates outside the 16-bit range
if (y < 0 || y > SHRT_MAX) return;
if (x <= x1) {
if (x1 < 0 || x > SHRT_MAX) return;
if (x < 0) x = 0;
if (x1 > SHRT_MAX) x1 = SHRT_MAX;
} else { // x1 < x
if (x < 0 || x1 > SHRT_MAX) return;
if (x1 < 0) x1 = 0;
if (x > SHRT_MAX) x = SHRT_MAX;
}
XDrawLine(fl_display, fl_window, fl_gc, x, y, x1, y);
#elif defined(WIN32)
MoveToEx(fl_gc, x, y, 0L); LineTo(fl_gc, x1+1, y);
@ -156,6 +221,17 @@ void Fl_Graphics_Driver::xyline(int x, int y, int x1, int y2, int x3) {
void Fl_Graphics_Driver::yxline(int x, int y, int y1) {
#if defined(USE_X11)
// get rid of coordinates outside the 16-bit range
if (x < 0 || x > SHRT_MAX) return;
if (y <= y1) {
if (y1 < 0 || y > SHRT_MAX) return;
if (y < 0) y = 0;
if (y1 > SHRT_MAX) y1 = SHRT_MAX;
} else { // y1 < y
if (y < 0 || y1 > SHRT_MAX) return;
if (y1 < 0) y1 = 0;
if (y > SHRT_MAX) y = SHRT_MAX;
}
XDrawLine(fl_display, fl_window, fl_gc, x, y, x, y1);
#elif defined(WIN32)
if (y1 < y) y1--;
@ -508,24 +584,9 @@ int Fl_Graphics_Driver::not_clipped(int x, int y, int w, int h) {
Fl_Region r = rstack[rstackptr];
#if defined (USE_X11)
if (!r) return 1;
// First get rid of coordinates outside the 16-bit range the X calls take.
// We could probably also use max. screen coordinates instead of SHRT_MAX
#ifndef SHRT_MAX
#define SHRT_MAX (32767)
#endif
if (x>SHRT_MAX || y > SHRT_MAX) return 0;
int tx = x, ty = y, tw = w, th = h;
if (x < 0) { tx = 0; tw += x; }
if (y < 0) { ty = 0; th += y; }
if (tx+tw > SHRT_MAX) tw = SHRT_MAX - tx;
if (ty+th > SHRT_MAX) th = SHRT_MAX - ty;
// now all coordinates to test are in the range [0,32767]
return XRectInRegion(r, tx, ty, tw, th);
// get rid of coordinates outside the 16-bit range the X calls take.
if (clip_to_short(x,y,w,h)) return 0; // clipped
return XRectInRegion(r, x, y, w, h);
#elif defined(WIN32)
if (!r) return 1;
RECT rect;
@ -533,17 +594,16 @@ int Fl_Graphics_Driver::not_clipped(int x, int y, int w, int h) {
POINT pt[2] = { {x, y}, {x + w, y + h} };
LPtoDP(fl_gc, pt, 2);
rect.left = pt[0].x; rect.top = pt[0].y; rect.right = pt[1].x; rect.bottom = pt[1].y;
}
else {
} else {
rect.left = x; rect.top = y; rect.right = x+w; rect.bottom = y+h;
}
}
return RectInRegion(r,&rect);
#elif defined(__APPLE_QUARTZ__)
if (!r) return 1;
CGRect arg = fl_cgrectmake_cocoa(x, y, w, h);
for(int i = 0; i < r->count; i++) {
for (int i = 0; i < r->count; i++) {
CGRect test = CGRectIntersection(r->rects[i], arg);
if( ! CGRectIsEmpty(test)) return 1;
if (!CGRectIsEmpty(test)) return 1;
}
return 0;
#else