1 //
2 // "$Id: fl_rect.cxx 8630 2011-05-01 12:45:29Z AlbrechtS $"
3 //
4 // Rectangle drawing routines for the Fast Light Tool Kit (FLTK).
5 //
6 // Copyright 1998-2010 by Bill Spitzak and others.
7 //
8 // This library is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU Library General Public
10 // License as published by the Free Software Foundation; either
11 // version 2 of the License, or (at your option) any later version.
12 //
13 // This library is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 // Library General Public License for more details.
17 //
18 // You should have received a copy of the GNU Library General Public
19 // License along with this library; if not, write to the Free Software
20 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21 // USA.
22 //
23 // Please report all bugs and problems on the following page:
24 //
25 //     http://www.fltk.org/str.php
26 //
27 
28 /**
29   \file fl_rect.cxx
30   \brief Drawing and clipping routines for rectangles.
31 */
32 
33 // These routines from fl_draw.H are used by the standard boxtypes
34 // and thus are always linked into an fltk program.
35 // Also all fl_clip routines, since they are always linked in so
36 // that minimal update works.
37 
38 #include <config.h>
39 #include <FL/Fl.H>
40 #include <FL/Fl_Widget.H>
41 #include <FL/Fl_Printer.H>
42 #include <FL/fl_draw.H>
43 #include <FL/x.H>
44 
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_;
49 
50 #ifdef __APPLE_QUARTZ__
51 extern float fl_quartz_line_width_;
52 #define USINGQUARTZPRINTER  (Fl_Surface_Device::surface()->class_name() == Fl_Printer::class_id)
53 #endif
54 
55 #ifdef USE_X11
56 
57 #ifndef SHRT_MAX
58 #define SHRT_MAX (32767)
59 #endif
60 
61 /*
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.
66 
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
71   clipped completely.
72 
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):
79 
80     fl_line_style (FL_SOLID,5);	// line width = 5
81     fl_rect (-1,-1,100,100);	// top/left: 2 pixels visible
82 
83   In this example case, no clipping would be done, because X can
84   handle it and clip unneeded pixels.
85 
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
88   width of 1.
89 
90   Todo: Arbitrary line drawings (e.g. polygons) and clip regions
91   are not yet done.
92 
93   Note:
94 
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.
101 
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)...
104 */
105 
106 /*
107   clip_to_short() returns 1, if the area is invisible (clipped),
108   because ...
109 
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
113 
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.
116 
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
119   X coordinate space.
120 
121   Use this for clipping rectangles, as used in fl_rect() and
122   fl_rectf().
123 */
124 
clip_to_short(int & x,int & y,int & w,int & h)125 static int clip_to_short(int &x, int &y, int &w, int &h) {
126 
127   int lw = (fl_line_width_ > 0) ? fl_line_width_ : 1;
128   int kmin = -lw;
129   int kmax = SHRT_MAX - lw;
130 
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)
134 
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;
139 
140   return 0;
141 }
142 
143 /*
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).
150 */
clip_x(int x)151 static int clip_x (int x) {
152 
153   int lw = (fl_line_width_ > 0) ? fl_line_width_ : 1;
154   int kmin = -lw;
155   int kmax = SHRT_MAX - lw;
156 
157   if (x < kmin)
158     x = kmin;
159   else if (x > kmax)
160     x = kmax;
161   return x;
162 }
163 
164 #endif	// USE_X11
165 
166 
rect(int x,int y,int w,int h)167 void Fl_Graphics_Driver::rect(int x, int y, int w, int h) {
168 
169   if (w<=0 || h<=0) return;
170 #if defined(USE_X11)
171   if (!clip_to_short(x, y, w, h))
172     XDrawRectangle(fl_display, fl_window, fl_gc, x, y, w-1, h-1);
173 #elif defined(WIN32)
174   MoveToEx(fl_gc, x, y, 0L);
175   LineTo(fl_gc, x+w-1, y);
176   LineTo(fl_gc, x+w-1, y+h-1);
177   LineTo(fl_gc, x, y+h-1);
178   LineTo(fl_gc, x, y);
179 #elif defined(__APPLE_QUARTZ__)
180   if ( (!USINGQUARTZPRINTER) && fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true);
181   CGRect rect = CGRectMake(x, y, w-1, h-1);
182   CGContextStrokeRect(fl_gc, rect);
183   if ( (!USINGQUARTZPRINTER) && fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false);
184 #else
185 # error unsupported platform
186 #endif
187 }
188 
rectf(int x,int y,int w,int h)189 void Fl_Graphics_Driver::rectf(int x, int y, int w, int h) {
190   if (w<=0 || h<=0) return;
191 #if defined(USE_X11)
192   if (!clip_to_short(x, y, w, h))
193     XFillRectangle(fl_display, fl_window, fl_gc, x, y, w, h);
194 #elif defined(WIN32)
195   RECT rect;
196   rect.left = x; rect.top = y;
197   rect.right = x + w; rect.bottom = y + h;
198   FillRect(fl_gc, &rect, fl_brush());
199 #elif defined(__APPLE_QUARTZ__)
200   CGFloat delta_size =  0.9;
201   CGFloat delta_ori = 0;
202   if (USINGQUARTZPRINTER) {
203     delta_size = 0;
204     delta_ori = 0.5;
205     }
206   CGRect  rect = CGRectMake(x - delta_ori, y - delta_ori, w - delta_size , h - delta_size);
207   CGContextFillRect(fl_gc, rect);
208 #else
209 # error unsupported platform
210 #endif
211 }
212 
xyline(int x,int y,int x1)213 void Fl_Graphics_Driver::xyline(int x, int y, int x1) {
214 #if defined(USE_X11)
215   XDrawLine(fl_display, fl_window, fl_gc, clip_x(x), clip_x(y), clip_x(x1), clip_x(y));
216 #elif defined(WIN32)
217   MoveToEx(fl_gc, x, y, 0L); LineTo(fl_gc, x1+1, y);
218 #elif defined(__APPLE_QUARTZ__)
219   if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true);
220   CGContextMoveToPoint(fl_gc, x, y);
221   CGContextAddLineToPoint(fl_gc, x1, y);
222   CGContextStrokePath(fl_gc);
223   if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false);
224 #else
225 # error unsupported platform
226 #endif
227 }
228 
xyline(int x,int y,int x1,int y2)229 void Fl_Graphics_Driver::xyline(int x, int y, int x1, int y2) {
230 #if defined (USE_X11)
231   XPoint p[3];
232   p[0].x = clip_x(x);  p[0].y = p[1].y = clip_x(y);
233   p[1].x = p[2].x = clip_x(x1); p[2].y = clip_x(y2);
234   XDrawLines(fl_display, fl_window, fl_gc, p, 3, 0);
235 #elif defined(WIN32)
236   if (y2 < y) y2--;
237   else y2++;
238   MoveToEx(fl_gc, x, y, 0L);
239   LineTo(fl_gc, x1, y);
240   LineTo(fl_gc, x1, y2);
241 #elif defined(__APPLE_QUARTZ__)
242   if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true);
243   CGContextMoveToPoint(fl_gc, x, y);
244   CGContextAddLineToPoint(fl_gc, x1, y);
245   CGContextAddLineToPoint(fl_gc, x1, y2);
246   CGContextStrokePath(fl_gc);
247   if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false);
248 #else
249 #error unsupported platform
250 #endif
251 }
252 
xyline(int x,int y,int x1,int y2,int x3)253 void Fl_Graphics_Driver::xyline(int x, int y, int x1, int y2, int x3) {
254 #if defined(USE_X11)
255   XPoint p[4];
256   p[0].x = clip_x(x);  p[0].y = p[1].y = clip_x(y);
257   p[1].x = p[2].x = clip_x(x1); p[2].y = p[3].y = clip_x(y2);
258   p[3].x = clip_x(x3);
259   XDrawLines(fl_display, fl_window, fl_gc, p, 4, 0);
260 #elif defined(WIN32)
261   if(x3 < x1) x3--;
262   else x3++;
263   MoveToEx(fl_gc, x, y, 0L);
264   LineTo(fl_gc, x1, y);
265   LineTo(fl_gc, x1, y2);
266   LineTo(fl_gc, x3, y2);
267 #elif defined(__APPLE_QUARTZ__)
268   if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true);
269   CGContextMoveToPoint(fl_gc, x, y);
270   CGContextAddLineToPoint(fl_gc, x1, y);
271   CGContextAddLineToPoint(fl_gc, x1, y2);
272   CGContextAddLineToPoint(fl_gc, x3, y2);
273   CGContextStrokePath(fl_gc);
274   if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false);
275 #else
276 # error unsupported platform
277 #endif
278 }
279 
yxline(int x,int y,int y1)280 void Fl_Graphics_Driver::yxline(int x, int y, int y1) {
281 #if defined(USE_X11)
282   XDrawLine(fl_display, fl_window, fl_gc, clip_x(x), clip_x(y), clip_x(x), clip_x(y1));
283 #elif defined(WIN32)
284   if (y1 < y) y1--;
285   else y1++;
286   MoveToEx(fl_gc, x, y, 0L); LineTo(fl_gc, x, y1);
287 #elif defined(__APPLE_QUARTZ__)
288   if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true);
289   CGContextMoveToPoint(fl_gc, x, y);
290   CGContextAddLineToPoint(fl_gc, x, y1);
291   CGContextStrokePath(fl_gc);
292   if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false);
293 #else
294 # error unsupported platform
295 #endif
296 }
297 
yxline(int x,int y,int y1,int x2)298 void Fl_Graphics_Driver::yxline(int x, int y, int y1, int x2) {
299 #if defined(USE_X11)
300   XPoint p[3];
301   p[0].x = p[1].x = clip_x(x);  p[0].y = clip_x(y);
302   p[1].y = p[2].y = clip_x(y1); p[2].x = clip_x(x2);
303   XDrawLines(fl_display, fl_window, fl_gc, p, 3, 0);
304 #elif defined(WIN32)
305   if (x2 > x) x2++;
306   else x2--;
307   MoveToEx(fl_gc, x, y, 0L);
308   LineTo(fl_gc, x, y1);
309   LineTo(fl_gc, x2, y1);
310 #elif defined(__APPLE_QUARTZ__)
311   if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true);
312   CGContextMoveToPoint(fl_gc, x, y);
313   CGContextAddLineToPoint(fl_gc, x, y1);
314   CGContextAddLineToPoint(fl_gc, x2, y1);
315   CGContextStrokePath(fl_gc);
316   if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false);
317 #else
318 # error unsupported platform
319 #endif
320 }
321 
yxline(int x,int y,int y1,int x2,int y3)322 void Fl_Graphics_Driver::yxline(int x, int y, int y1, int x2, int y3) {
323 #if defined(USE_X11)
324   XPoint p[4];
325   p[0].x = p[1].x = clip_x(x);  p[0].y = clip_x(y);
326   p[1].y = p[2].y = clip_x(y1); p[2].x = p[3].x = clip_x(x2);
327   p[3].y = clip_x(y3);
328   XDrawLines(fl_display, fl_window, fl_gc, p, 4, 0);
329 #elif defined(WIN32)
330   if(y3<y1) y3--;
331   else y3++;
332   MoveToEx(fl_gc, x, y, 0L);
333   LineTo(fl_gc, x, y1);
334   LineTo(fl_gc, x2, y1);
335   LineTo(fl_gc, x2, y3);
336 #elif defined(__APPLE_QUARTZ__)
337   if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true);
338   CGContextMoveToPoint(fl_gc, x, y);
339   CGContextAddLineToPoint(fl_gc, x, y1);
340   CGContextAddLineToPoint(fl_gc, x2, y1);
341   CGContextAddLineToPoint(fl_gc, x2, y3);
342   CGContextStrokePath(fl_gc);
343   if (USINGQUARTZPRINTER || fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false);
344 #else
345 # error unsupported platform
346 #endif
347 }
348 
line(int x,int y,int x1,int y1)349 void Fl_Graphics_Driver::line(int x, int y, int x1, int y1) {
350 #if defined(USE_X11)
351   XDrawLine(fl_display, fl_window, fl_gc, x, y, x1, y1);
352 #elif defined(WIN32)
353   MoveToEx(fl_gc, x, y, 0L);
354   LineTo(fl_gc, x1, y1);
355   // Draw the last point *again* because the GDI line drawing
356   // functions will not draw the last point ("it's a feature!"...)
357   SetPixel(fl_gc, x1, y1, fl_RGB());
358 #elif defined(__APPLE_QUARTZ__)
359   if (fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true);
360   CGContextMoveToPoint(fl_gc, x, y);
361   CGContextAddLineToPoint(fl_gc, x1, y1);
362   CGContextStrokePath(fl_gc);
363   if (fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false);
364 #else
365 # error unsupported platform
366 #endif
367 }
368 
line(int x,int y,int x1,int y1,int x2,int y2)369 void Fl_Graphics_Driver::line(int x, int y, int x1, int y1, int x2, int y2) {
370 #if defined(USE_X11)
371   XPoint p[3];
372   p[0].x = x;  p[0].y = y;
373   p[1].x = x1; p[1].y = y1;
374   p[2].x = x2; p[2].y = y2;
375   XDrawLines(fl_display, fl_window, fl_gc, p, 3, 0);
376 #elif defined(WIN32)
377   MoveToEx(fl_gc, x, y, 0L);
378   LineTo(fl_gc, x1, y1);
379   LineTo(fl_gc, x2, y2);
380   // Draw the last point *again* because the GDI line drawing
381   // functions will not draw the last point ("it's a feature!"...)
382   SetPixel(fl_gc, x2, y2, fl_RGB());
383 #elif defined(__APPLE_QUARTZ__)
384   if (fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, true);
385   CGContextMoveToPoint(fl_gc, x, y);
386   CGContextAddLineToPoint(fl_gc, x1, y1);
387   CGContextAddLineToPoint(fl_gc, x2, y2);
388   CGContextStrokePath(fl_gc);
389   if (fl_quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(fl_gc, false);
390 #else
391 # error unsupported platform
392 #endif
393 }
394 
loop(int x,int y,int x1,int y1,int x2,int y2)395 void Fl_Graphics_Driver::loop(int x, int y, int x1, int y1, int x2, int y2) {
396 #if defined(USE_X11)
397   XPoint p[4];
398   p[0].x = x;  p[0].y = y;
399   p[1].x = x1; p[1].y = y1;
400   p[2].x = x2; p[2].y = y2;
401   p[3].x = x;  p[3].y = y;
402   XDrawLines(fl_display, fl_window, fl_gc, p, 4, 0);
403 #elif defined(WIN32)
404   MoveToEx(fl_gc, x, y, 0L);
405   LineTo(fl_gc, x1, y1);
406   LineTo(fl_gc, x2, y2);
407   LineTo(fl_gc, x, y);
408 #elif defined(__APPLE_QUARTZ__)
409   CGContextSetShouldAntialias(fl_gc, true);
410   CGContextMoveToPoint(fl_gc, x, y);
411   CGContextAddLineToPoint(fl_gc, x1, y1);
412   CGContextAddLineToPoint(fl_gc, x2, y2);
413   CGContextClosePath(fl_gc);
414   CGContextStrokePath(fl_gc);
415   CGContextSetShouldAntialias(fl_gc, false);
416 #else
417 # error unsupported platform
418 #endif
419 }
420 
loop(int x,int y,int x1,int y1,int x2,int y2,int x3,int y3)421 void Fl_Graphics_Driver::loop(int x, int y, int x1, int y1, int x2, int y2, int x3, int y3) {
422 #if defined(USE_X11)
423   XPoint p[5];
424   p[0].x = x;  p[0].y = y;
425   p[1].x = x1; p[1].y = y1;
426   p[2].x = x2; p[2].y = y2;
427   p[3].x = x3; p[3].y = y3;
428   p[4].x = x;  p[4].y = y;
429   XDrawLines(fl_display, fl_window, fl_gc, p, 5, 0);
430 #elif defined(WIN32)
431   MoveToEx(fl_gc, x, y, 0L);
432   LineTo(fl_gc, x1, y1);
433   LineTo(fl_gc, x2, y2);
434   LineTo(fl_gc, x3, y3);
435   LineTo(fl_gc, x, y);
436 #elif defined(__APPLE_QUARTZ__)
437   CGContextSetShouldAntialias(fl_gc, true);
438   CGContextMoveToPoint(fl_gc, x, y);
439   CGContextAddLineToPoint(fl_gc, x1, y1);
440   CGContextAddLineToPoint(fl_gc, x2, y2);
441   CGContextAddLineToPoint(fl_gc, x3, y3);
442   CGContextClosePath(fl_gc);
443   CGContextStrokePath(fl_gc);
444   CGContextSetShouldAntialias(fl_gc, false);
445 #else
446 # error unsupported platform
447 #endif
448 }
449 
polygon(int x,int y,int x1,int y1,int x2,int y2)450 void Fl_Graphics_Driver::polygon(int x, int y, int x1, int y1, int x2, int y2) {
451   XPoint p[4];
452   p[0].x = x;  p[0].y = y;
453   p[1].x = x1; p[1].y = y1;
454   p[2].x = x2; p[2].y = y2;
455 #if defined (USE_X11)
456   p[3].x = x;  p[3].y = y;
457   XFillPolygon(fl_display, fl_window, fl_gc, p, 3, Convex, 0);
458   XDrawLines(fl_display, fl_window, fl_gc, p, 4, 0);
459 #elif defined(WIN32)
460   SelectObject(fl_gc, fl_brush());
461   Polygon(fl_gc, p, 3);
462 #elif defined(__APPLE_QUARTZ__)
463   CGContextSetShouldAntialias(fl_gc, true);
464   CGContextMoveToPoint(fl_gc, x, y);
465   CGContextAddLineToPoint(fl_gc, x1, y1);
466   CGContextAddLineToPoint(fl_gc, x2, y2);
467   CGContextClosePath(fl_gc);
468   CGContextFillPath(fl_gc);
469   CGContextSetShouldAntialias(fl_gc, false);
470 #else
471 # error unsupported platform
472 #endif
473 }
474 
polygon(int x,int y,int x1,int y1,int x2,int y2,int x3,int y3)475 void Fl_Graphics_Driver::polygon(int x, int y, int x1, int y1, int x2, int y2, int x3, int y3) {
476   XPoint p[5];
477   p[0].x = x;  p[0].y = y;
478   p[1].x = x1; p[1].y = y1;
479   p[2].x = x2; p[2].y = y2;
480   p[3].x = x3; p[3].y = y3;
481 #if defined(USE_X11)
482   p[4].x = x;  p[4].y = y;
483   XFillPolygon(fl_display, fl_window, fl_gc, p, 4, Convex, 0);
484   XDrawLines(fl_display, fl_window, fl_gc, p, 5, 0);
485 #elif defined(WIN32)
486   SelectObject(fl_gc, fl_brush());
487   Polygon(fl_gc, p, 4);
488 #elif defined(__APPLE_QUARTZ__)
489   CGContextSetShouldAntialias(fl_gc, true);
490   CGContextMoveToPoint(fl_gc, x, y);
491   CGContextAddLineToPoint(fl_gc, x1, y1);
492   CGContextAddLineToPoint(fl_gc, x2, y2);
493   CGContextAddLineToPoint(fl_gc, x3, y3);
494   CGContextClosePath(fl_gc);
495   CGContextFillPath(fl_gc);
496   CGContextSetShouldAntialias(fl_gc, false);
497 #else
498 # error unsupported platform
499 #endif
500 }
501 
point(int x,int y)502 void Fl_Graphics_Driver::point(int x, int y) {
503 #if defined(USE_X11)
504   XDrawPoint(fl_display, fl_window, fl_gc, clip_x(x), clip_x(y));
505 #elif defined(WIN32)
506   SetPixel(fl_gc, x, y, fl_RGB());
507 #elif defined(__APPLE_QUARTZ__)
508   CGContextFillRect(fl_gc, CGRectMake(x - 0.5, y - 0.5, 1, 1) );
509 #else
510 # error unsupported platform
511 #endif
512 }
513 
XRegionFromRectangle(Fl_Region rg)514 Region XRegionFromRectangle ( Fl_Region rg )
515 {
516   if ( rg )
517   {
518  Region region = XCreateRegion();
519 
520       XRectangle rr;
521 
522       cairo_rectangle_int_t rect;
523 
524       cairo_region_get_extents( rg, &rect );
525 
526       rr.x = rect.x;
527       rr.y = rect.y;
528       rr.width = rect.width;
529       rr.height = rect.height;
530 
531       XUnionRectWithRegion( &rr, region, region );
532 
533       return region;
534   }
535 
536   return 0;
537 }
538 
539 ////////////////////////////////////////////////////////////////
540 
541 #if !defined(WIN32) && !defined(__APPLE__)
542 // Missing X call: (is this the fastest way to init a 1-rectangle region?)
543 // MSWindows equivalent exists, implemented inline in win32.H
XRectangleRegion(int x,int y,int w,int h)544 Fl_Region XRectangleRegion(int x, int y, int w, int h) {
545 
546 
547     cairo_rectangle_int_t rect;
548 
549     rect.x = x;
550     rect.y = y;
551     rect.width = w;
552     rect.height = h;
553 
554     return cairo_region_create_rectangle( &rect );
555 
556 }
557 #endif
558 
restore_clip()559 void Fl_Graphics_Driver::restore_clip() {
560   fl_clip_state_number++;
561   Fl_Region r = rstack[rstackptr];
562 #if defined(USE_X11)
563 #elif defined(WIN32)
564   SelectClipRgn(fl_gc, r); //if r is NULL, clip is automatically cleared
565 #elif defined(__APPLE_QUARTZ__)
566   if ( fl_window ) { // clipping for a true window
567     Fl_X::q_clear_clipping();
568     Fl_X::q_fill_context();//flip coords if bitmap context
569     //apply program clip
570     if (r) {
571       CGContextClipToRects(fl_gc, r->rects, r->count);
572     }
573   } else if (fl_gc) { // clipping for an offscreen drawing world (CGBitmap)
574     Fl_X::q_clear_clipping();
575     Fl_X::q_fill_context();
576     if (r) {
577       CGContextClipToRects(fl_gc, r->rects, r->count);
578     }
579   }
580 #else
581 # error unsupported platform
582 #endif
583 
584   cairo_t *cr = fl_cairo_context;
585 
586   if ( cr )
587   {
588     cairo_reset_clip( cr );
589 
590     if ( r )
591     {
592         cairo_rectangle_int_t rect;
593 
594         for ( int i = cairo_region_num_rectangles( r ); --i >= 0; )
595         {
596             cairo_region_get_rectangle( r, i, &rect );
597 
598             cairo_rectangle( cr, rect.x, rect.y, rect.width, rect.height );
599         }
600 //        cairo_set_source_rgb( cr, 0, 1, 0 );
601 //        cairo_rectangle( cr, r->x(), r->y(), r->w(), r->h() );
602 //        cairo_stroke_preserve( cr );
603 
604         cairo_clip( cr );
605     }
606   }
607 
608 }
609 
clip_region(Fl_Region r)610 void Fl_Graphics_Driver::clip_region(Fl_Region r) {
611   Fl_Region oldr = rstack[rstackptr];
612 
613   if ( r != oldr )
614   {
615       if ( oldr )
616           cairo_region_destroy( oldr );
617 
618       rstack[rstackptr] = r ? cairo_region_reference( r ) : 0;
619   }
620 
621   fl_restore_clip();
622 }
623 
clip_region()624 Fl_Region Fl_Graphics_Driver::clip_region() {
625   return rstack[rstackptr];
626 }
627 
push_clip(int x,int y,int w,int h)628 void Fl_Graphics_Driver::push_clip(int x, int y, int w, int h) {
629   Fl_Region r;
630   if (w > 0 && h > 0) {
631     r = XRectangleRegion(x,y,w,h);
632     Fl_Region current = rstack[rstackptr];
633     if (current) {
634 #if defined(USE_X11)
635         cairo_region_intersect( r, current );
636 #elif defined(WIN32)
637       CombineRgn(r,r,current,RGN_AND);
638 #elif defined(__APPLE_QUARTZ__)
639       XDestroyRegion(r);
640       r = Fl_X::intersect_region_and_rect(current, x,y,w,h);
641 #else
642 # error unsupported platform
643 #endif
644     }
645   } else { // make empty clip region:
646 #if defined(USE_X11)
647       r = XRectangleRegion( 0, 0, 0, 0 );
648 #elif defined(WIN32)
649     r = CreateRectRgn(0,0,0,0);
650 #elif defined(__APPLE_QUARTZ__)
651     r = XRectangleRegion(0,0,0,0);
652 #else
653 # error unsupported platform
654 #endif
655   }
656   if (rstackptr < region_stack_max) rstack[++rstackptr] = r;
657   else Fl::warning("fl_push_clip: clip stack overflow!\n");
658   fl_restore_clip();
659 }
660 
661 // make there be no clip (used by fl_begin_offscreen() only!)
push_no_clip()662 void Fl_Graphics_Driver::push_no_clip() {
663   if (rstackptr < region_stack_max) rstack[++rstackptr] = 0;
664   else Fl::warning("fl_push_no_clip: clip stack overflow!\n");
665   fl_restore_clip();
666 }
667 
668 // pop back to previous clip:
pop_clip()669 void Fl_Graphics_Driver::pop_clip() {
670   if (rstackptr > 0) {
671     Fl_Region oldr = rstack[rstackptr--];
672   if (oldr)
673     {
674         cairo_region_destroy( oldr );
675     }
676   } else Fl::warning("fl_pop_clip: clip stack underflow!\n");
677   fl_restore_clip();
678 }
679 
not_clipped(int x,int y,int w,int h)680 int Fl_Graphics_Driver::not_clipped(int x, int y, int w, int h) {
681   if (x+w <= 0 || y+h <= 0) return 0;
682   Fl_Region r = rstack[rstackptr];
683   if (!r) return 1;
684 #if defined (USE_X11)
685   // get rid of coordinates outside the 16-bit range the X calls take.
686   if (clip_to_short(x,y,w,h)) return 0;	// clipped
687 
688 cairo_rectangle_int_t rect;
689   rect.x = x; rect.y = y; rect.width = w; rect.height = h;
690 
691   cairo_region_overlap_t o = cairo_region_contains_rectangle( r, &rect );
692 
693   return o != CAIRO_REGION_OVERLAP_OUT;
694 #elif defined(WIN32)
695   RECT rect;
696   if (Fl_Surface_Device::surface()->class_name() == Fl_Printer::class_id) { // in case of print context, convert coords from logical to device
697     POINT pt[2] = { {x, y}, {x + w, y + h} };
698     LPtoDP(fl_gc, pt, 2);
699     rect.left = pt[0].x; rect.top = pt[0].y; rect.right = pt[1].x; rect.bottom = pt[1].y;
700   } else {
701     rect.left = x; rect.top = y; rect.right = x+w; rect.bottom = y+h;
702   }
703   return RectInRegion(r,&rect);
704 #elif defined(__APPLE_QUARTZ__)
705   CGRect arg = fl_cgrectmake_cocoa(x, y, w, h);
706   for (int i = 0; i < r->count; i++) {
707     CGRect test = CGRectIntersection(r->rects[i], arg);
708     if (!CGRectIsEmpty(test)) return 1;
709   }
710   return 0;
711 #else
712 # error unsupported platform
713 #endif
714 }
715 
716 // return rectangle surrounding intersection of this rectangle and clip:
clip_box(int x,int y,int w,int h,int & X,int & Y,int & W,int & H)717 int Fl_Graphics_Driver::clip_box(int x, int y, int w, int h, int& X, int& Y, int& W, int& H){
718   X = x; Y = y; W = w; H = h;
719   Fl_Region r = rstack[rstackptr];
720   if (!r) return 0;
721 #if defined(USE_X11)
722  cairo_rectangle_int_t rect;
723   rect.x = x; rect.y = y; rect.width = w; rect.height = h;
724 
725   cairo_region_t *t = cairo_region_copy( r );
726 
727   cairo_region_intersect_rectangle( t, &rect );
728 
729   cairo_region_get_extents( t, &rect );
730 
731   X = rect.x; Y = rect.y; W = rect.width; H = rect.height;
732 
733   cairo_region_overlap_t o = cairo_region_contains_rectangle( r, &rect );
734 
735   cairo_region_destroy(t);
736 
737   switch ( o )
738   {
739       case CAIRO_REGION_OVERLAP_IN:
740           return 0;
741       case CAIRO_REGION_OVERLAP_OUT:
742           return 2;
743       case CAIRO_REGION_OVERLAP_PART:
744           return 1;
745       default:
746           return 2;
747   }
748 
749 #elif defined(WIN32)
750 // The win32 API makes no distinction between partial and complete
751 // intersection, so we have to check for partial intersection ourselves.
752 // However, given that the regions may be composite, we have to do
753 // some voodoo stuff...
754   Fl_Region rr = XRectangleRegion(x,y,w,h);
755   Fl_Region temp = CreateRectRgn(0,0,0,0);
756   int ret;
757   if (CombineRgn(temp, rr, r, RGN_AND) == NULLREGION) { // disjoint
758     W = H = 0;
759     ret = 2;
760   } else if (EqualRgn(temp, rr)) { // complete
761     ret = 0;
762   } else {	// partial intersection
763     RECT rect;
764     GetRgnBox(temp, &rect);
765     if(Fl_Surface_Device::surface()->class_name() == Fl_Printer::class_id) { // if print context, convert coords from device to logical
766       POINT pt[2] = { {rect.left, rect.top}, {rect.right, rect.bottom} };
767       DPtoLP(fl_gc, pt, 2);
768       X = pt[0].x; Y = pt[0].y; W = pt[1].x - X; H = pt[1].y - Y;
769     }
770     else {
771       X = rect.left; Y = rect.top; W = rect.right - X; H = rect.bottom - Y;
772       }
773     ret = 1;
774   }
775   DeleteObject(temp);
776   DeleteObject(rr);
777   return ret;
778 #elif defined(__APPLE_QUARTZ__)
779   CGRect arg = fl_cgrectmake_cocoa(x, y, w, h);
780   CGRect u = CGRectMake(0,0,0,0);
781   CGRect test;
782   for(int i = 0; i < r->count; i++) {
783     test = CGRectIntersection(r->rects[i], arg);
784     if( ! CGRectIsEmpty(test) ) {
785       if(CGRectIsEmpty(u)) u = test;
786       else u = CGRectUnion(u, test);
787     }
788   }
789   X = int(u.origin.x);
790   Y = int(u.origin.y);
791   W = int(u.size.width + 1);
792   H = int(u.size.height + 1);
793   if(CGRectIsEmpty(u)) W = H = 0;
794   return ! CGRectEqualToRect(arg, u);
795 #else
796 # error unsupported platform
797 #endif
798 }
799 
800 //
801 // End of "$Id: fl_rect.cxx 8630 2011-05-01 12:45:29Z AlbrechtS $".
802 //
803