42
42
#include <FL/fl_draw.H>
45
// fl_line_width_ must contain the absolute value of the current
46
// line width to be used for X11 clipping (see below).
47
// This is defined in src/fl_line_style.cxx
48
extern int fl_line_width_;
45
50
#ifdef __APPLE_QUARTZ__
46
51
extern float fl_quartz_line_width_;
47
#define USINGQUARTZPRINTER (Fl_Surface_Device::surface()->type() == Fl_Printer::device_type)
52
#define USINGQUARTZPRINTER (Fl_Surface_Device::surface()->class_name() == Fl_Printer::class_id)
58
#define SHRT_MAX (32767)
62
We need to check some coordinates for areas for clipping before we
63
use X functions, because X can't handle coordinates outside the 16-bit
64
range. Since all windows use relative coordinates > 0, we do also
65
check for negative values. X11 only, see also STR #2304.
67
Note that this is only necessary for large objects, where only a
68
part of the object is visible. The draw() functions (e.g. box
69
drawing) must be clipped correctly. This is usually only a matter
70
for large container widgets. The individual child widgets will be
73
We define the usable X coordinate space as [ -LW : SHRT_MAX - LW ]
74
where LW = current line width for drawing. This is done so that
75
horizontal and vertical line drawing works correctly, even in real
76
border cases, e.g. drawing a rectangle slightly outside the top left
77
window corner, but with a line width so that a part of the line should
78
be visible (in this case 2 of 5 pixels):
80
fl_line_style (FL_SOLID,5); // line width = 5
81
fl_rect (-1,-1,100,100); // top/left: 2 pixels visible
83
In this example case, no clipping would be done, because X can
84
handle it and clip unneeded pixels.
86
Note that we must also take care of the case where fl_line_width_
87
is zero (maybe unitialized). If this is the case, we assume a line
90
Todo: Arbitrary line drawings (e.g. polygons) and clip regions
95
We could use max. screen coordinates instead of SHRT_MAX, but that
96
would need more work and would probably be slower. We assume that
97
all window coordinates are >= 0 and that no window extends up to
98
32767 - LW (where LW = current line width). Thus it is safe to clip
99
all coordinates to this range before calling X functions. If this
100
is not true, then clip_to_short() and clip_x() must be redefined.
102
It would be somewhat easier if we had fl_clip_w and fl_clip_h, as
103
defined in FLTK 2.0 (for the upper clipping bounds)...
107
clip_to_short() returns 1, if the area is invisible (clipped),
110
(a) w or h are <= 0 i.e. nothing is visible
111
(b) x+w or y+h are < kmin i.e. left of or above visible area
112
(c) x or y are > kmax i.e. right of or below visible area
114
kmin and kmax are the minimal and maximal X coordinate values,
115
as defined above. In this case x, y, w, and h are not changed.
117
It returns 0, if the area is potentially visible and X can handle
118
clipping. x, y, w, and h may have been adjusted to fit into the
121
Use this for clipping rectangles, as used in fl_rect() and
125
static int clip_to_short(int &x, int &y, int &w, int &h) {
127
int lw = (fl_line_width_ > 0) ? fl_line_width_ : 1;
129
int kmax = SHRT_MAX - lw;
131
if (w <= 0 || h <= 0) return 1; // (a)
132
if (x+w < kmin || y+h < kmin) return 1; // (b)
133
if (x > kmax || y > kmax) return 1; // (c)
135
if (x < kmin) { w -= (kmin-x); x = kmin; }
136
if (y < kmin) { h -= (kmin-y); y = kmin; }
137
if (x+w > kmax) w = kmax - x;
138
if (y+h > kmax) h = kmax - y;
144
clip_x() returns a coordinate value clipped to the 16-bit coordinate
145
space (see above). This can be used to draw horizontal and vertical
146
lines that can be handled by X11. Each single coordinate value can
147
be clipped individually, and the result can be used directly, e.g.
148
in fl_xyline() and fl_yxline(). Note that this can't be used for
149
arbitrary lines (not horizontal or vertical).
151
static int clip_x (int x) {
153
int lw = (fl_line_width_ > 0) ? fl_line_width_ : 1;
155
int kmax = SHRT_MAX - lw;
50
167
void Fl_Graphics_Driver::rect(int x, int y, int w, int h) {
52
169
if (w<=0 || h<=0) return;
53
170
#if defined(USE_X11)
54
XDrawRectangle(fl_display, fl_window, fl_gc, x, y, w-1, h-1);
171
if (!clip_to_short(x, y, w, h))
172
XDrawRectangle(fl_display, fl_window, fl_gc, x, y, w-1, h-1);
55
173
#elif defined(WIN32)
56
174
MoveToEx(fl_gc, x, y, 0L);
57
175
LineTo(fl_gc, x+w-1, y);
71
189
void Fl_Graphics_Driver::rectf(int x, int y, int w, int h) {
72
190
if (w<=0 || h<=0) return;
73
191
#if defined(USE_X11)
74
if (w && h) XFillRectangle(fl_display, fl_window, fl_gc, x, y, w, h);
192
if (!clip_to_short(x, y, w, h))
193
XFillRectangle(fl_display, fl_window, fl_gc, x, y, w, h);
75
194
#elif defined(WIN32)
77
196
rect.left = x; rect.top = y;
78
197
rect.right = x + w; rect.bottom = y + h;
79
198
FillRect(fl_gc, &rect, fl_brush());
80
199
#elif defined(__APPLE_QUARTZ__)
81
if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true);
82
CGRect rect = CGRectMake(x, y, w-1, h-1);
200
CGFloat delta_size = 0.9;
201
CGFloat delta_ori = 0;
202
if (USINGQUARTZPRINTER) {
206
CGRect rect = CGRectMake(x - delta_ori, y - delta_ori, w - delta_size , h - delta_size);
83
207
CGContextFillRect(fl_gc, rect);
84
if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false);
86
209
# error unsupported platform
379
502
void Fl_Graphics_Driver::point(int x, int y) {
380
503
#if defined(USE_X11)
381
XDrawPoint(fl_display, fl_window, fl_gc, x, y);
504
XDrawPoint(fl_display, fl_window, fl_gc, clip_x(x), clip_x(y));
382
505
#elif defined(WIN32)
383
506
SetPixel(fl_gc, x, y, fl_RGB());
384
507
#elif defined(__APPLE_QUARTZ__)
385
if (fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true);
386
CGContextMoveToPoint(fl_gc, x-.5, y); // Quartz needs a line that is one pixel long, or it will not draw anything
387
CGContextAddLineToPoint(fl_gc, x+.5, y);
388
CGContextStrokePath(fl_gc);
389
if (fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false);
508
CGContextFillRect(fl_gc, CGRectMake(x - 0.5, y - 0.5, 1, 1) );
391
510
# error unsupported platform
395
514
////////////////////////////////////////////////////////////////
397
#define STACK_SIZE 10
398
#define STACK_MAX (STACK_SIZE - 1)
399
static Fl_Region rstack[STACK_SIZE];
400
static int rstackptr=0;
401
int fl_clip_state_number=0; // used by gl_begin.cxx to update GL clip
403
516
#if !defined(WIN32) && !defined(__APPLE__)
404
517
// Missing X call: (is this the fastest way to init a 1-rectangle region?)
405
518
// MSWindows equivalent exists, implemented inline in win32.H
406
519
Fl_Region XRectangleRegion(int x, int y, int w, int h) {
521
clip_to_short(x, y, w, h);
408
522
R.x = x; R.y = y; R.width = w; R.height = h;
409
523
Fl_Region r = XCreateRegion();
410
524
XUnionRectWithRegion(&R, r, r);
506
620
int Fl_Graphics_Driver::not_clipped(int x, int y, int w, int h) {
507
621
if (x+w <= 0 || y+h <= 0) return 0;
508
622
Fl_Region r = rstack[rstackptr];
509
624
#if defined (USE_X11)
510
return r ? XRectInRegion(r, x, y, w, h) : 1;
625
// get rid of coordinates outside the 16-bit range the X calls take.
626
if (clip_to_short(x,y,w,h)) return 0; // clipped
627
return XRectInRegion(r, x, y, w, h);
511
628
#elif defined(WIN32)
514
if (Fl_Surface_Device::surface()->type() == Fl_Printer::device_type) { // in case of print context, convert coords from logical to device
630
if (Fl_Surface_Device::surface()->class_name() == Fl_Printer::class_id) { // in case of print context, convert coords from logical to device
515
631
POINT pt[2] = { {x, y}, {x + w, y + h} };
516
632
LPtoDP(fl_gc, pt, 2);
517
633
rect.left = pt[0].x; rect.top = pt[0].y; rect.right = pt[1].x; rect.bottom = pt[1].y;
520
635
rect.left = x; rect.top = y; rect.right = x+w; rect.bottom = y+h;
522
637
return RectInRegion(r,&rect);
523
638
#elif defined(__APPLE_QUARTZ__)
525
639
CGRect arg = fl_cgrectmake_cocoa(x, y, w, h);
526
for(int i = 0; i < r->count; i++) {
640
for (int i = 0; i < r->count; i++) {
527
641
CGRect test = CGRectIntersection(r->rects[i], arg);
528
if( ! CGRectIsEmpty(test)) return 1;
642
if (!CGRectIsEmpty(test)) return 1;