1 /*
2 
3 Copyright 1989, 1998  The Open Group
4 
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
9 documentation.
10 
11 The above copyright notice and this permission notice shall be included
12 in all copies or substantial portions of the Software.
13 
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 OTHER DEALINGS IN THE SOFTWARE.
21 
22 Except as contained in this notice, the name of The Open Group shall
23 not be used in advertising or otherwise to promote the sale, use or
24 other dealings in this Software without prior written authorization
25 from The Open Group.
26 
27 */
28 
29 /*
30  * Author:  Davor Matic, MIT X Consortium
31  */
32 
33 #ifdef HAVE_CONFIG_H
34 # include "config.h"
35 #endif
36 
37 #include <X11/IntrinsicP.h>
38 #include <X11/StringDefs.h>
39 #include <X11/Xfuncs.h>
40 #include "BitmapP.h"
41 #include "Bitmap.h"
42 #include "Requests.h"
43 
44 #include <stdio.h>
45 #include <math.h>
46 
47 #ifndef abs
48 #define abs(x)                        (((x) > 0) ? (x) : -(x))
49 #endif
50 #define min(x, y)                     (((int)(x) < (int)(y)) ? (x) : (y))
51 #define max(x, y)                     (((int)(x) > (int)(y)) ? (x) : (y))
52 #ifndef rint
53 # if HAVE_LRINT
54 #  define rint(x)                     lrint(x)
55 # else
56 #  define rint(x)                     floor(x + 0.5)
57 # endif
58 #endif
59 
60 #ifdef __clang__
61 /* clang doesn't like (int)floor(d) */
62 #pragma clang diagnostic push
63 #pragma clang diagnostic ignored "-Wbad-function-cast"
64 #endif
65 
66 /*****************************************************************************\
67  *                                   Graphics                                *
68 \*****************************************************************************/
69 
70 #define GetBit(image, x, y)\
71     ((bit)((*(image->data + (x) / 8 + (y) * image->bytes_per_line) &\
72 	    (1 << ((x) & 7))) ? 1 : 0))
73 
74 #if 0
75 bit
76 BWGetBit(Widget w, Position x, Position y)
77 {
78     BitmapWidget BW = (BitmapWidget) w;
79 
80     if (QueryInBitmap(BW, x, y))
81 	return GetBit(BW->bitmap.image, x, y);
82     else
83 	return NotSet;
84 }
85 #endif
86 
87 #define InvertBit(image, x, y)\
88     (*(image->data + (x) / 8 + (y) * image->bytes_per_line) ^=\
89      (bit) (1 << ((x) % 8)))
90 
91 
92 #define SetBit(image, x, y)\
93     (*(image->data + (x) / 8 + (y) * image->bytes_per_line) |=\
94      (bit) (1 << ((x) % 8)))
95 
96 #define ClearBit(image, x, y)\
97     (*(image->data + (x) / 8 + (y) * image->bytes_per_line) &=\
98      (bit)~(1 << ((x) % 8)))
99 
100 
101 #define HighlightSquare(BW, x, y)\
102     XFillRectangle(XtDisplay(BW), XtWindow(BW),\
103                    BW->bitmap.highlighting_gc,\
104 		   InWindowX(BW, x), InWindowY(BW, y),\
105                    BW->bitmap.squareW, BW->bitmap.squareH)
106 /*
107 void
108 HighlightSquare(BitmapWidget BW, Position x, Position y)
109 {
110     XFillRectangle(XtDisplay(BW), XtWindow(BW),
111                    BW->bitmap.highlighting_gc,
112 		   InWindowX(BW, x), InWindowY(BW, y),
113                    BW->bitmap.squareW, BW->bitmap.squareH);
114 }
115 */
116 
117 #define DrawSquare(BW, x, y)\
118     XFillRectangle(XtDisplay(BW), XtWindow(BW),\
119                    BW->bitmap.drawing_gc,\
120 		   InWindowX(BW, x), InWindowY(BW, y),\
121                    BW->bitmap.squareW, BW->bitmap.squareH)
122 
123 /*
124 void
125 DrawSquare(BitmapWidget BW, Position x, Position y)
126 {
127     XFillRectangle(XtDisplay(BW), XtWindow(BW),
128                    BW->bitmap.drawing_gc,
129 		   InWindowX(BW, x), InWindowY(BW, y),
130                    BW->bitmap.squareW, BW->bitmap.squareH);
131 }
132 */
133 
134 #define InvertPoint(BW, x, y)\
135     {InvertBit(BW->bitmap.image, x, y); DrawSquare(BW, x, y);}
136 
137 #define DrawPoint(BW, x, y, value)\
138     if (GetBit(BW->bitmap.image, x, y) != value)\
139        InvertPoint(BW, x, y)
140 
141 void
BWDrawPoint(Widget w,Position x,Position y,bit value)142 BWDrawPoint(Widget w, Position x, Position y, bit value)
143 {
144     BitmapWidget BW = (BitmapWidget) w;
145 
146     if (QueryInBitmap(BW, x, y)) {
147 	if (value == Highlight)
148 	    HighlightSquare(BW, x, y);
149 	else
150 	    DrawPoint(BW, x, y, value);
151     }
152 }
153 
154 static XPoint *
HotSpotShape(BitmapWidget BW,Position x,Position y)155 HotSpotShape(BitmapWidget BW, Position x, Position y)
156 {
157     static XPoint points[5];
158 
159     points[0].x = InWindowX(BW, x);
160     points[0].y = InWindowY(BW, y + 1.0/2);
161     points[1].x = InWindowX(BW, x + 1.0/2);
162     points[1].y = InWindowY(BW, y + 1);
163     points[2].x = InWindowX(BW, x + 1);
164     points[2].y = InWindowY(BW, y + 1.0/2);
165     points[3].x = InWindowX(BW, x + 1.0/2);
166     points[3].y = InWindowY(BW, y);
167     points[4].x = InWindowX(BW, x);
168     points[4].y = InWindowY(BW, y + 1.0/2);
169 
170     return points;
171 }
172 
173 #define DrawHotSpot(BW, x, y)\
174   XFillPolygon(XtDisplay(BW), XtWindow(BW), BW->bitmap.drawing_gc,\
175 	       HotSpotShape(BW, x, y), 5, Convex, CoordModeOrigin)
176 
177 #define HighlightHotSpot(BW, x, y)\
178   XFillPolygon(XtDisplay(BW), XtWindow(BW), BW->bitmap.highlighting_gc,\
179 	       HotSpotShape(BW, x, y), 5, Convex, CoordModeOrigin)
180 
181 /*
182 XImage *CreateBitmapImage();
183 void DestroyBitmapImage();
184 */
185 
186 void
BWRedrawHotSpot(Widget w)187 BWRedrawHotSpot(Widget w)
188 {
189     BitmapWidget BW = (BitmapWidget) w;
190 
191     if (QuerySet(BW->bitmap.hot.x, BW->bitmap.hot.y))
192 	DrawHotSpot(BW, BW->bitmap.hot.x, BW->bitmap.hot.y);
193 }
194 
195 void
BWClearHotSpot(Widget w)196 BWClearHotSpot(Widget w)
197 {
198     BitmapWidget BW = (BitmapWidget) w;
199 
200     if (QuerySet(BW->bitmap.hot.x, BW->bitmap.hot.y)) {
201       DrawHotSpot(BW, BW->bitmap.hot.x, BW->bitmap.hot.y);
202       BW->bitmap.hot.x = BW->bitmap.hot.y = NotSet;
203     }
204 }
205 
206 void
BWDrawHotSpot(Widget w,Position x,Position y,int value)207 BWDrawHotSpot(Widget w, Position x, Position y, int value)
208 {
209     BitmapWidget BW = (BitmapWidget) w;
210 
211     if (QueryInBitmap(BW, x, y)) {
212 	if (QuerySet(BW->bitmap.hot.x, BW->bitmap.hot.y) &&
213 	    ((BW->bitmap.hot.x == x) && (BW->bitmap.hot.y == y))) {
214 	    if ((value == Clear) || (value == Invert)) {
215 		BWClearHotSpot(w);
216 	    }
217 	}
218 	else
219 	    if ((value == Set) || (value == Invert)) {
220 		BWClearHotSpot(w);
221 		DrawHotSpot(BW, x, y);
222 		BW->bitmap.hot.x = x;
223 		BW->bitmap.hot.y = y;
224 	    }
225 
226 	if (value == Highlight)
227 	    HighlightHotSpot(BW, x, y);
228     }
229 }
230 
231 void
BWSetHotSpot(Widget w,Position x,Position y)232 BWSetHotSpot(Widget w, Position x, Position y)
233 {
234     if (QuerySet(x, y))
235 	BWDrawHotSpot(w, x, y, Set);
236     else
237 	BWClearHotSpot(w);
238 }
239 
240 /* high level procedures */
241 
242 void
BWRedrawSquares(Widget w,Position x,Position y,Dimension width,Dimension height)243 BWRedrawSquares(Widget w,
244 		Position x, Position y,
245 		Dimension width, Dimension height)
246 {
247     BitmapWidget BW = (BitmapWidget) w;
248     Position from_x = InBitmapX(BW, x);
249     Position from_y = InBitmapY(BW, y);
250     Position to_x = InBitmapX(BW, x + width);
251     Position to_y = InBitmapY(BW, y + height);
252 
253     QuerySwap(from_x, to_x);
254     QuerySwap(from_y, to_y);
255     from_x = max(0, from_x);
256     from_y = max(0, from_y);
257     to_x = min(BW->bitmap.image->width - 1, to_x);
258     to_y = min(BW->bitmap.image->height - 1, to_y);
259 
260     for (x = from_x; x <= to_x; x++)
261 	for (y = from_y; y <= to_y; y++)
262 	    if (GetBit(BW->bitmap.image, x, y)) DrawSquare(BW, x, y);
263 }
264 
265 void
BWDrawGrid(Widget w,Position from_x,Position from_y,Position to_x,Position to_y)266 BWDrawGrid(Widget w,
267 	   Position from_x, Position from_y,
268 	   Position to_x, Position to_y)
269 {
270     BitmapWidget BW = (BitmapWidget) w;
271     int i;
272 
273     QuerySwap(from_x, to_x);
274     QuerySwap(from_y, to_y);
275     from_x = max(0, from_x);
276     from_y = max(0, from_y);
277     to_x = min(BW->bitmap.image->width - 1, to_x);
278     to_y = min(BW->bitmap.image->height - 1, to_y);
279 
280     for(i = from_x + (from_x == 0); i <= to_x; i++)
281 	XDrawLine(XtDisplay(BW), XtWindow(BW),
282 		  BW->bitmap.frame_gc,
283 		  InWindowX(BW, i), InWindowY(BW, from_y),
284 		  InWindowX(BW, i), InWindowY(BW, to_y + 1));
285 
286     for(i = from_y + (from_y == 0); i <= to_y; i++)
287 	XDrawLine(XtDisplay(BW), XtWindow(BW),
288 		  BW->bitmap.frame_gc,
289 		  InWindowX(BW, from_x), InWindowY(BW, i),
290 		  InWindowX(BW, to_x + 1), InWindowY(BW, i));
291 }
292 
293 
294 void
BWRedrawGrid(Widget w,Position x,Position y,Dimension width,Dimension height)295 BWRedrawGrid(Widget w,
296 	     Position x, Position y,
297 	     Dimension width, Dimension height)
298 {
299     BitmapWidget BW = (BitmapWidget) w;
300     Position from_x = InBitmapX(BW, x);
301     Position from_y = InBitmapY(BW, y);
302     Position to_x = InBitmapX(BW, x + width);
303     Position to_y = InBitmapY(BW, y + height);
304 
305     if (BW->bitmap.grid)
306 	BWDrawGrid(w, from_x, from_y, to_x, to_y);
307 }
308 
309 void
BWDrawLine(Widget w,Position from_x,Position from_y,Position to_x,Position to_y,int value)310 BWDrawLine(Widget w,
311 	   Position from_x, Position from_y,
312 	   Position to_x, Position to_y, int value)
313 {
314     Position i;
315     register double x, y;
316     double dx, dy, delta;
317 
318     dx = to_x - from_x;
319     dy = to_y - from_y;
320     x = from_x + 0.5;
321     y = from_y + 0.5;
322     delta = max(abs(dx), abs(dy));
323     if (delta > 0) {
324 	dx /= delta;
325 	dy /= delta;
326 	for(i = 0; i <= delta; i++) {
327 	    BWDrawPoint(w, (Position) x, (Position) y, value);
328 	    x += dx;
329 	    y += dy;
330 	}
331     }
332     else
333 	BWDrawPoint(w, from_x, from_y, value);
334 }
335 
336 void
BWBlindLine(Widget w,Position from_x,Position from_y,Position to_x,Position to_y,int value)337 BWBlindLine(Widget w,
338 	    Position from_x, Position from_y,
339 	    Position to_x, Position to_y, int value)
340 {
341     Position i;
342     register double x, y;
343     double dx, dy, delta;
344 
345     dx = to_x - from_x;
346     dy = to_y - from_y;
347     x = from_x + 0.5;
348     y = from_y + 0.5;
349     delta = max(abs(dx), abs(dy));
350     if (delta > 0) {
351 	dx /= delta;
352 	dy /= delta;
353 	x += dx;
354 	y += dy;
355 	for(i = 1; i <= delta; i++) {
356 	    BWDrawPoint(w, (Position) x, (Position) y, value);
357 	    x += dx;
358 	    y += dy;
359 	}
360     }
361     else
362 	BWDrawPoint(w, from_x, from_y, value);
363 }
364 
365 void
BWDrawRectangle(Widget w,Position from_x,Position from_y,Position to_x,Position to_y,int value)366 BWDrawRectangle(Widget w,
367 		Position from_x, Position from_y,
368 		Position to_x, Position to_y, int value)
369 {
370     register Position i;
371     Dimension delta, width, height;
372 
373     QuerySwap(from_x, to_x);
374     QuerySwap(from_y, to_y);
375 
376     width = to_x - from_x;
377     height = to_y - from_y;
378 
379     delta = max(width, height);
380 
381     if (!QueryZero(width, height)) {
382 	for (i = 0; (int)i < (int)delta; i++) {
383 	    if ((int)i < (int)width) {
384 		BWDrawPoint(w, from_x + i, from_y, value);
385 		BWDrawPoint(w, to_x - i, to_y, value);
386 	    }
387 	    if ((int)i < (int)height) {
388 		BWDrawPoint(w, from_x, to_y - i, value);
389 		BWDrawPoint(w, to_x, from_y + i, value);
390 	    }
391 	}
392     }
393     else
394 	BWDrawLine(w,
395 		   from_x, from_y,
396 		   to_x, to_y, value);
397 }
398 
399 void
BWDrawFilledRectangle(Widget w,Position from_x,Position from_y,Position to_x,Position to_y,int value)400 BWDrawFilledRectangle(Widget w,
401 		      Position from_x, Position from_y,
402 		      Position to_x, Position to_y, int value)
403 {
404     register Position x, y;
405 
406     QuerySwap(from_x, to_x);
407     QuerySwap(from_y, to_y);
408 
409     for (x = from_x; x <= to_x; x++)
410 	for (y = from_y; y <= to_y; y++)
411 	    BWDrawPoint(w, x, y, value);
412 }
413 
414 void
BWDrawCircle(Widget w,Position origin_x,Position origin_y,Position point_x,Position point_y,int value)415 BWDrawCircle(Widget w,
416 	     Position origin_x, Position origin_y,
417 	     Position point_x, Position point_y, int value)
418 {
419     register Position i, delta;
420     Dimension dx, dy, half;
421     double radius;
422 
423     dx = abs(point_x - origin_x);
424     dy = abs(point_y - origin_y);
425     radius = sqrt((double) ((int)dx * (int)dx + (int)dy * (int)dy));
426     if (radius < 1.0) {
427 	BWDrawPoint(w, origin_x, origin_y, value);
428     }
429     else {
430 	BWDrawPoint(w, origin_x - (Position) floor(radius), origin_y, value);
431 	BWDrawPoint(w, origin_x + (Position) floor(radius), origin_y, value);
432 	BWDrawPoint(w, origin_x, origin_y - (Position) floor(radius), value);
433 	BWDrawPoint(w, origin_x, origin_y + (Position) floor(radius), value);
434     }
435     half = radius / sqrt(2.0);
436     for(i = 1; (int)i <= (int)half; i++) {
437 	delta = sqrt(radius * radius - i * i);
438 	BWDrawPoint(w, origin_x - delta, origin_y - i, value);
439 	BWDrawPoint(w, origin_x - delta, origin_y + i, value);
440 	BWDrawPoint(w, origin_x + delta, origin_y - i, value);
441 	BWDrawPoint(w, origin_x + delta, origin_y + i, value);
442 	if (i != delta) {
443 	    BWDrawPoint(w, origin_x - i, origin_y - delta, value);
444 	    BWDrawPoint(w, origin_x - i, origin_y + delta, value);
445 	    BWDrawPoint(w, origin_x + i, origin_y - delta, value);
446 	    BWDrawPoint(w, origin_x + i, origin_y + delta, value);
447 	}
448     }
449 }
450 
451 void
BWDrawFilledCircle(Widget w,Position origin_x,Position origin_y,Position point_x,Position point_y,int value)452 BWDrawFilledCircle(Widget w,
453 		   Position origin_x, Position origin_y,
454 		   Position point_x, Position point_y, int value)
455 {
456     register Position i, j, delta;
457     Dimension dx, dy;
458     double radius;
459 
460     dx = abs(point_x - origin_x);
461     dy = abs(point_y - origin_y);
462     radius = sqrt((double) ((int)dx * (int)dx + (int)dy * (int)dy));
463     for(j = origin_x - (Position) floor(radius);
464 	j <= origin_x + (Position) floor(radius); j++)
465 	BWDrawPoint(w, j, origin_y, value);
466     for(i = 1; i <= (Position) floor(radius); i++) {
467 	delta = sqrt(radius * radius - i * i);
468 	for(j = origin_x - delta; j <= origin_x + delta; j++) {
469 	    BWDrawPoint(w, j, origin_y - i, value);
470 	    BWDrawPoint(w, j, origin_y + i, value);
471 	}
472     }
473 }
474 
475 #define QueryFlood(BW, x, y, value)\
476     ((GetBit(BW->bitmap.image, x, y) !=\
477       (value & 1)) && QueryInBitmap(BW, x, y))
478 
479 #define Flood(BW, x, y, value)\
480     {if (value == Highlight) HighlightSquare(BW, x, y);\
481      else InvertPoint(BW, x, y);}
482 
483 /*
484 static void
485 FloodLoop(BitmapWidget BW, Position x, Position y, int value)
486 {
487     if (QueryFlood(BW, x, y, value)) {
488 	Flood(BW, x, y, value);
489 	FloodLoop(BW, x, y - 1, value);
490 	FloodLoop(BW, x - 1, y, value);
491 	FloodLoop(BW, x, y + 1, value);
492 	FloodLoop(BW, x + 1, y, value);
493     }
494 }
495 */
496 
497 static void
FloodLoop(BitmapWidget BW,Position x,Position y,int value)498 FloodLoop(BitmapWidget BW, Position x, Position y, int value)
499 {
500     Position save_x, save_y, x_left, x_right;
501 
502     if (QueryFlood(BW, x, y, value))
503 	Flood(BW, x, y, value)
504 
505 
506     save_x = x;
507     save_y = y;
508 
509     x++;
510     while (QueryFlood(BW, x, y, value)) {
511 	Flood(BW, x, y, value);
512 	x++;
513     }
514     x_right = --x;
515 
516     x = save_x;
517     x--;
518     while (QueryFlood(BW, x, y, value)) {
519 	Flood(BW, x, y, value);
520 	x--;
521     }
522     x_left = ++x;
523 
524 
525     x = x_left;
526     y = save_y;
527     y++;
528 
529     while (x <= x_right) {
530 	Boolean flag = False;
531 	Position x_enter;
532 
533 	while (QueryFlood(BW, x, y, value) && (x <= x_right)) {
534 	    flag = True;
535 	    x++;
536 	}
537 
538 	if (flag) {
539 	    if ((x == x_right) && QueryFlood(BW, x, y, value))
540 		FloodLoop(BW, x, y, value);
541 	    else
542 		FloodLoop(BW, x - 1, y, value);
543 	}
544 
545 	x_enter = x;
546 
547 	while (!QueryFlood(BW, x, y, value) && (x < x_right))
548 	    x++;
549 
550 	if (x == x_enter) x++;
551     }
552 
553     x = x_left;
554     y = save_y;
555     y--;
556 
557     while (x <= x_right) {
558 	Boolean flag = False;
559 	Position x_enter;
560 
561 	while (QueryFlood(BW, x, y, value) && (x <= x_right)) {
562 	    flag = True;
563 	    x++;
564 	}
565 
566 	if (flag) {
567 	    if ((x == x_right) && QueryFlood(BW, x, y, value))
568 		FloodLoop(BW, x, y, value);
569 	    else
570 		FloodLoop(BW, x - 1, y, value);
571 	}
572 
573 	x_enter = x;
574 
575 	while (!QueryFlood(BW, x, y, value) && (x < x_right))
576 	    x++;
577 
578 	if (x == x_enter) x++;
579     }
580 }
581 
582 void
BWFloodFill(Widget w,Position x,Position y,int value)583 BWFloodFill(Widget w, Position x, Position y, int value)
584 {
585     BitmapWidget BW = (BitmapWidget) w;
586     int pixel;
587 
588     pixel = GetBit(BW->bitmap.image, x, y);
589 
590     if (value == Invert)
591 	FloodLoop(BW, x, y, (pixel ? Clear : Set));
592     else if (value != pixel)
593 	FloodLoop(BW, x, y, value);
594 }
595 
596 #define QueryHotInMark(BW)\
597     ((BW->bitmap.hot.x == max(BW->bitmap.mark.from_x,\
598 			      min(BW->bitmap.hot.x, BW->bitmap.mark.to_x)))\
599      &&\
600      (BW->bitmap.hot.y == max(BW->bitmap.mark.from_y,\
601 			      min(BW->bitmap.hot.y, BW->bitmap.mark.to_y))))
602 
603 void
BWUp(Widget w)604 BWUp(Widget w)
605 {
606     BitmapWidget BW = (BitmapWidget) w;
607     register Position x, y;
608     bit first, up, down=0;
609     Position from_x, from_y, to_x, to_y;
610 
611     if (BWQueryMarked(w)) {
612 	from_x = BW->bitmap.mark.from_x;
613 	from_y = BW->bitmap.mark.from_y;
614 	to_x = BW->bitmap.mark.to_x;
615 	to_y = BW->bitmap.mark.to_y;
616     }
617     else {
618 	from_x = 0;
619 	from_y = 0;
620 	to_x = BW->bitmap.width - 1;
621 	to_y = BW->bitmap.height - 1;
622     }
623 
624     if ((to_y - from_y) == 0)
625 	return;
626 
627     for(x = from_x; x <= to_x; x++) {
628 	first = up = GetBit(BW->bitmap.image, x, to_y);
629 	for(y = to_y - 1; y >= from_y; y--) {
630 	    down = GetBit(BW->bitmap.image, x, y);
631 	    if (up != down)
632 		InvertPoint(BW, x, y);
633 	    up =down;
634 	}
635 	if(first != down)
636 	    InvertPoint(BW, x, to_y);
637     }
638 
639     if (QuerySet(BW->bitmap.hot.x, BW->bitmap.hot.y)
640 	&&
641 	!BWQueryMarked(w))
642 	BWSetHotSpot(w,
643 		     BW->bitmap.hot.x,
644 		     (BW->bitmap.hot.y - 1 + BW->bitmap.image->height) %
645 		     BW->bitmap.image->height);
646 
647 }
648 
649 void
BWDown(Widget w)650 BWDown(Widget w)
651 {
652     BitmapWidget BW = (BitmapWidget) w;
653     register Position x, y;
654     bit first, down, up=0;
655     Position from_x, from_y, to_x, to_y;
656 
657     if (BWQueryMarked(w)) {
658 	from_x = BW->bitmap.mark.from_x;
659 	from_y = BW->bitmap.mark.from_y;
660 	to_x = BW->bitmap.mark.to_x;
661 	to_y = BW->bitmap.mark.to_y;
662     }
663     else {
664 	from_x = 0;
665 	from_y = 0;
666 	to_x = BW->bitmap.width - 1;
667 	to_y = BW->bitmap.height - 1;
668     }
669 
670     if ((to_y - from_y) == 0)
671 	return;
672 
673     for(x = from_x; x <= to_x; x++) {
674 	first = down = GetBit(BW->bitmap.image, x, from_y);
675 	for(y = from_y + 1; y <= to_y; y++) {
676 	    up = GetBit(BW->bitmap.image, x, y);
677 	    if (down != up)
678 		InvertPoint(BW, x, y);
679 	    down = up;
680 	}
681 	if(first != up)
682 	    InvertPoint(BW, x, from_y);
683     }
684 
685     if (QuerySet(BW->bitmap.hot.x, BW->bitmap.hot.y)
686 	&&
687 	!BWQueryMarked(w))
688 	BWSetHotSpot(w,
689 		     BW->bitmap.hot.x,
690 		     (BW->bitmap.hot.y + 1) % BW->bitmap.image->height);
691 }
692 
693 void
BWLeft(Widget w)694 BWLeft(Widget w)
695 {
696     BitmapWidget BW = (BitmapWidget) w;
697     register Position x, y;
698     bit first, left, right=0;
699     Position from_x, from_y, to_x, to_y;
700 
701     if (BWQueryMarked(w)) {
702 	from_x = BW->bitmap.mark.from_x;
703 	from_y = BW->bitmap.mark.from_y;
704 	to_x = BW->bitmap.mark.to_x;
705 	to_y = BW->bitmap.mark.to_y;
706     }
707     else {
708 	from_x = 0;
709 	from_y = 0;
710 	to_x = BW->bitmap.width - 1;
711 	to_y = BW->bitmap.height - 1;
712     }
713 
714     if ((to_x - from_x) == 0)
715 	return;
716 
717     for(y = from_y; y <= to_y; y++) {
718 	first = left = GetBit(BW->bitmap.image, to_x, y);
719 	for(x = to_x - 1; x >= from_x; x--) {
720 	    right = GetBit(BW->bitmap.image, x, y);
721 	    if (left != right)
722 		InvertPoint(BW, x, y);
723 	    left = right;
724 	}
725 	if(first != right)
726 	    InvertPoint(BW, to_x, y);
727     }
728 
729     if (QuerySet(BW->bitmap.hot.x, BW->bitmap.hot.y)
730 	&&
731 	!BWQueryMarked(w))
732 	BWSetHotSpot(w,
733 		     (BW->bitmap.hot.x - 1 + BW->bitmap.image->width) %
734 		     BW->bitmap.image->width,
735 		     BW->bitmap.hot.y);
736 }
737 
738 void
BWRight(Widget w)739 BWRight(Widget w)
740 {
741     BitmapWidget BW = (BitmapWidget) w;
742     register Position x, y;
743     bit first, right, left=0;
744     Position from_x, from_y, to_x, to_y;
745 
746     if (BWQueryMarked(w)) {
747 	from_x = BW->bitmap.mark.from_x;
748 	from_y = BW->bitmap.mark.from_y;
749 	to_x = BW->bitmap.mark.to_x;
750 	to_y = BW->bitmap.mark.to_y;
751     }
752     else {
753 	from_x = 0;
754 	from_y = 0;
755 	to_x = BW->bitmap.width - 1;
756 	to_y = BW->bitmap.height - 1;
757     }
758 
759     if ((to_x - from_x) == 0)
760 	return;
761 
762     for(y = from_y; y <= to_y; y++) {
763 	first = right = GetBit(BW->bitmap.image, from_x, y);
764 	for(x = from_x + 1; x <= to_x; x++) {
765 	    left = GetBit(BW->bitmap.image, x, y);
766 	    if (right != left)
767 		InvertPoint(BW, x, y);
768 	    right = left;
769 	}
770 	if(first != left)
771 	    InvertPoint(BW, from_x, y);
772     }
773 
774     if (QuerySet(BW->bitmap.hot.x, BW->bitmap.hot.y)
775 	&&
776 	!BWQueryMarked(w))
777 	BWSetHotSpot(w,
778 		     (BW->bitmap.hot.x + 1) % BW->bitmap.image->width,
779 		     BW->bitmap.hot.y);
780 }
781 
782 /* void TransferImageData(); */
783 
784 void
BWFold(Widget w)785 BWFold(Widget w)
786 {
787     BitmapWidget BW = (BitmapWidget) w;
788     Position x, y, new_x, new_y;
789     Dimension horiz, vert;
790     char *storage_data;
791     XImage *storage;
792 
793     storage_data = CreateCleanData(Length(BW->bitmap.image->width,
794 					  BW->bitmap.image->height));
795 
796     storage = CreateBitmapImage(BW, storage_data,
797 				(Dimension) BW->bitmap.image->width,
798 				(Dimension) BW->bitmap.image->height);
799 
800     TransferImageData(BW->bitmap.image, storage);
801 
802     BW->bitmap.fold ^= True;
803     horiz = (BW->bitmap.image->width + BW->bitmap.fold) / 2;
804     vert = (BW->bitmap.image->height + BW->bitmap.fold) / 2;
805 
806     for (x = 0; x < BW->bitmap.image->width; x++)
807 	for (y = 0; y < BW->bitmap.image->height; y++) {
808 	    new_x = (int)(x + horiz) % (int)BW->bitmap.image->width;
809 	    new_y = (int)(y + vert) % (int)BW->bitmap.image->height;
810 	    if(GetBit(BW->bitmap.image, new_x, new_y) !=
811 	       GetBit(storage, x, y))
812 		InvertPoint(BW, new_x, new_y);
813 	}
814 
815     DestroyBitmapImage(&storage);
816 
817     if (QuerySet(BW->bitmap.hot.x, BW->bitmap.hot.y))
818       BWSetHotSpot(w,
819 		   (Position)
820 		   ((int)(BW->bitmap.hot.x+horiz)
821 		    %(int)BW->bitmap.image->width),
822 		   (Position)
823 		   ((int)(BW->bitmap.hot.y+vert)
824 		    %(int)BW->bitmap.image->height)
825 		   );
826 }
827 
828 
829 void
BWClear(Widget w)830 BWClear(Widget w)
831 {
832     BitmapWidget BW = (BitmapWidget) w;
833     register Position x, y;
834     int i, length;
835 
836     length = Length(BW->bitmap.image->width, BW->bitmap.image->height);
837 
838     for (x = 0; x < BW->bitmap.image->width; x++)
839 	for (y = 0; y < BW->bitmap.image->height; y++)
840 	    if (GetBit(BW->bitmap.image, x, y))
841 		DrawSquare(BW, x, y);
842 
843     for (i = 0; i < length; i++)
844 	BW->bitmap.image->data[i] = 0;
845 
846 }
847 
848 void
BWSet(Widget w)849 BWSet(Widget w)
850 {
851     BitmapWidget BW = (BitmapWidget) w;
852     register Position x, y;
853     int i, length;
854 
855     length = Length(BW->bitmap.image->width, BW->bitmap.image->height);
856 
857     for (x = 0; x < BW->bitmap.image->width; x++)
858 	for (y = 0; y < BW->bitmap.image->height; y++)
859 	    if (!GetBit(BW->bitmap.image, x, y))
860 		DrawSquare(BW, x, y);
861 
862     for (i = 0; i < length; i++)
863 	BW->bitmap.image->data[i] = (char)255;
864 
865 }
866 
867 void
BWRedraw(Widget w)868 BWRedraw(Widget w)
869 {
870     BitmapWidget BW = (BitmapWidget) w;
871 
872     XClearArea(XtDisplay(BW), XtWindow(BW),
873 	       0, 0, BW->core.width, BW->core.height,
874 	       True);
875 }
876 
877 void
BWInvert(Widget w)878 BWInvert(Widget w)
879 {
880     BitmapWidget BW = (BitmapWidget) w;
881     int i, length;
882 
883     length = Length(BW->bitmap.image->width, BW->bitmap.image->height);
884 
885     XFillRectangle(XtDisplay(BW), XtWindow(BW),
886 		   BW->bitmap.drawing_gc,
887 		   InWindowX(BW, 0), InWindowY(BW, 0),
888 		   InWindowX(BW, BW->bitmap.image->width) - InWindowX(BW, 0),
889 		   InWindowY(BW, BW->bitmap.image->height) - InWindowY(BW, 0));
890 
891     for (i = 0; i < length; i++)
892 	BW->bitmap.image->data[i] ^= 255;
893 }
894 
895 void
BWFlipHoriz(Widget w)896 BWFlipHoriz(Widget w)
897 {
898     BitmapWidget BW = (BitmapWidget) w;
899     register Position x, y;
900     Position from_x, from_y, to_x, to_y;
901     float half;
902 
903     if (BWQueryMarked(w)) {
904 	from_x = BW->bitmap.mark.from_x;
905 	from_y = BW->bitmap.mark.from_y;
906 	to_x = BW->bitmap.mark.to_x;
907 	to_y = BW->bitmap.mark.to_y;
908     }
909     else {
910 	from_x = 0;
911 	from_y = 0;
912 	to_x = BW->bitmap.width - 1;
913 	to_y = BW->bitmap.height - 1;
914     }
915     half = (float) (to_y - from_y) / 2.0 + 0.5;
916 
917     if (half == 0.0)
918 	return;
919 
920     for (x = from_x; x <= to_x; x++)
921 	for (y = 0; y <  half; y++)
922 	    if (GetBit(BW->bitmap.image, x, from_y + y) !=
923 		GetBit(BW->bitmap.image, x, to_y - y)) {
924 		InvertPoint(BW, x, from_y + y);
925 		InvertPoint(BW, x, to_y - y);
926 	    }
927 
928     if (QuerySet(BW->bitmap.hot.x, BW->bitmap.hot.y)
929 	&&
930 	!BWQueryMarked(w))
931 	BWSetHotSpot(w,
932 		     BW->bitmap.hot.x,
933 		     BW->bitmap.image->height - 1 - BW->bitmap.hot.y);
934 }
935 
936 void
BWFlipVert(Widget w)937 BWFlipVert(Widget w)
938 {
939     BitmapWidget BW = (BitmapWidget) w;
940     register Position x, y;
941     Position from_x, from_y, to_x, to_y;
942     float half;
943 
944     if (BWQueryMarked(w)) {
945 	from_x = BW->bitmap.mark.from_x;
946 	from_y = BW->bitmap.mark.from_y;
947 	to_x = BW->bitmap.mark.to_x;
948 	to_y = BW->bitmap.mark.to_y;
949     }
950     else {
951 	from_x = 0;
952 	from_y = 0;
953 	to_x = BW->bitmap.width - 1;
954 	to_y = BW->bitmap.height - 1;
955     }
956     half = (float) (to_x - from_x) / 2.0 + 0.5;
957 
958     if (half == 0)
959 	return;
960 
961     for (y = from_y; y <= to_y; y++)
962 	for (x = 0; x < half; x++)
963 	    if (GetBit(BW->bitmap.image, from_x + x, y) !=
964 		GetBit(BW->bitmap.image, to_x - x, y)) {
965 		InvertPoint(BW, from_x + x, y);
966 		InvertPoint(BW, to_x - x, y);
967 	    }
968 
969     if (QuerySet(BW->bitmap.hot.x, BW->bitmap.hot.y)
970 	&&
971 	!BWQueryMarked(w))
972 	BWSetHotSpot(w,
973 		     BW->bitmap.image->width - 1 - BW->bitmap.hot.x,
974 		     BW->bitmap.hot.y);
975 }
976 
977 
978 void
BWRotateRight(Widget w)979 BWRotateRight(Widget w)
980 {
981     BitmapWidget BW = (BitmapWidget) w;
982     Position x, y, delta, shift, tmp;
983     Position half_width, half_height;
984     XPoint hot;
985     bit quad1, quad2, quad3, quad4;
986     Position from_x, from_y, to_x, to_y;
987 
988     if (BWQueryMarked(w)) {
989 	from_x = BW->bitmap.mark.from_x;
990 	from_y = BW->bitmap.mark.from_y;
991 	to_x = BW->bitmap.mark.to_x;
992 	to_y = BW->bitmap.mark.to_y;
993     }
994     else {
995 	from_x = 0;
996 	from_y = 0;
997 	to_x = BW->bitmap.width - 1;
998 	to_y = BW->bitmap.height - 1;
999     }
1000 
1001     half_width = floor((to_x - from_x) / 2.0 + 0.5);
1002     half_height = floor((to_y - from_y ) / 2.0 + 0.5);
1003     shift = min((Position)(to_x - from_x), (Position)(to_y - from_y )) % 2;
1004     delta = min((Position) half_width, (Position) half_height) - shift;
1005 
1006     for (x = 0; x <= delta; x++) {
1007 	for (y = 1 - shift; y <= delta; y++) {
1008 	    quad1 = GetBit(BW->bitmap.image,
1009 			   from_x + (Position)half_width + x,
1010 			   from_y + (Position)half_height + y);
1011 	    quad2 = GetBit(BW->bitmap.image,
1012 			   from_x + (Position)half_width + y,
1013 			   from_y + (Position)half_height - shift - x);
1014 	    quad3 = GetBit(BW->bitmap.image,
1015 			   from_x + (Position)half_width - shift - x,
1016 			   from_y + (Position)half_height - shift - y);
1017 	    quad4 = GetBit(BW->bitmap.image,
1018 			   from_x + (Position)half_width - shift - y,
1019 			   from_y + (Position)half_height + x);
1020 
1021 	    if (quad1 != quad2)
1022 		InvertPoint(BW,
1023 			    from_x + (Position)half_width + x,
1024 			    from_y + (Position)half_height + y);
1025 	    if (quad2 != quad3)
1026 		InvertPoint(BW,
1027 			    from_x + (Position)half_width + y,
1028 			    from_y + (Position)half_height - shift - x);
1029 	    if (quad3 != quad4)
1030 		InvertPoint(BW,
1031 			    from_x + (Position)half_width - shift - x,
1032 			    from_y + (Position)half_height - shift - y);
1033 	    if (quad4 != quad1)
1034 		InvertPoint(BW,
1035 			    from_x + (Position)half_width - shift - y,
1036 			    from_y + (Position)half_height + x);
1037 	}
1038     }
1039 
1040     if (QuerySet(BW->bitmap.hot.x, BW->bitmap.hot.y)
1041 	&&
1042 	!BWQueryMarked(w)) {
1043 	hot.x = BW->bitmap.hot.x - half_width;
1044 	hot.y = BW->bitmap.hot.y - half_height;
1045 	if (hot.x >= 0) hot.x += shift;
1046 	if (hot.y >= 0) hot.y += shift;
1047 	tmp = hot.x;
1048 	hot.x = - hot.y;
1049 	hot.y = tmp;
1050 	if (hot.x > 0) hot.x -= shift;
1051 	if (hot.y > 0) hot.y -= shift;
1052 	hot.x += half_width;
1053 	hot.y += half_height;
1054 	if (QueryInBitmap(BW, hot.x, hot.y))
1055 	    BWSetHotSpot(w, hot.x, hot.y);
1056     }
1057 
1058 }
1059 
1060 void
BWRotateLeft(Widget w)1061 BWRotateLeft(Widget w)
1062 {
1063     BitmapWidget BW = (BitmapWidget) w;
1064     Position x, y,delta, shift, tmp;
1065     Position half_width, half_height;
1066     XPoint hot;
1067     bit quad1, quad2, quad3, quad4;
1068     Position from_x, from_y, to_x, to_y;
1069 
1070     if (BWQueryMarked(w)) {
1071 	from_x = BW->bitmap.mark.from_x;
1072 	from_y = BW->bitmap.mark.from_y;
1073 	to_x = BW->bitmap.mark.to_x;
1074 	to_y = BW->bitmap.mark.to_y;
1075     }
1076     else {
1077 	from_x = 0;
1078 	from_y = 0;
1079 	to_x = BW->bitmap.width - 1;
1080 	to_y = BW->bitmap.height - 1;
1081     }
1082 
1083     half_width = floor((to_x - from_x) / 2.0 + 0.5);
1084     half_height = floor((to_y - from_y ) / 2.0 + 0.5);
1085     shift = min((Position)(to_x - from_x), (Position)(to_y - from_y )) % 2;
1086     delta = min((Position) half_width, (Position) half_height) - shift;
1087 
1088     for (x = 0; x <= delta; x++) {
1089 	for (y = 1 - shift; y <= delta; y++) {
1090 	    quad1 = GetBit(BW->bitmap.image,
1091 			   from_x + (Position)half_width + x,
1092 			   from_y + (Position)half_height + y);
1093 	    quad2 = GetBit(BW->bitmap.image,
1094 			   from_x + (Position)half_width + y,
1095 			   from_y + (Position)half_height - shift - x);
1096 	    quad3 = GetBit(BW->bitmap.image,
1097 			   from_x + (Position)half_width - shift - x,
1098 			   from_y + (Position)half_height - shift - y);
1099 	    quad4 = GetBit(BW->bitmap.image,
1100 			   from_x + (Position)half_width - shift - y,
1101 			   from_y + (Position)half_height + x);
1102 
1103 	    if (quad1 != quad4)
1104 		InvertPoint(BW,
1105 			    from_x + (Position)half_width + x,
1106 			    from_y + (Position)half_height + y);
1107 	    if (quad2 != quad1)
1108 		InvertPoint(BW,
1109 			    from_x + (Position)half_width + y,
1110 			    from_y + (Position)half_height - shift - x);
1111 	    if (quad3 != quad2)
1112 		InvertPoint(BW,
1113 			    from_x + (Position)half_width - shift - x,
1114 			    from_y + (Position)half_height - shift - y);
1115 	    if (quad4 != quad3)
1116 		InvertPoint(BW,
1117 			    from_x + (Position)half_width - shift - y,
1118 			    from_y + (Position)half_height + x);
1119 	}
1120     }
1121 
1122     if (QuerySet(BW->bitmap.hot.x, BW->bitmap.hot.y)
1123 	&&
1124 	!BWQueryMarked(w)) {
1125 	hot.x = BW->bitmap.hot.x - half_width;
1126 	hot.y = BW->bitmap.hot.y - half_height;
1127 	if (hot.x >= 0) hot.x += shift;
1128 	if (hot.y >= 0) hot.y += shift;
1129 	tmp = hot.x;
1130 	hot.x = hot.y;
1131 	hot.y = - tmp;
1132 	if (hot.x > 0) hot.x -= shift;
1133 	if (hot.y > 0) hot.y -= shift;
1134 	hot.x += half_width;
1135 	hot.y += half_height;
1136 	if (QueryInBitmap(BW, hot.x, hot.y))
1137 	    BWSetHotSpot(w, hot.x, hot.y);
1138     }
1139 }
1140 
1141 
1142 void
CopyImageData(XImage * source,XImage * destination,Position from_x,Position from_y,Position to_x,Position to_y,Position at_x,Position at_y)1143 CopyImageData(XImage *source, XImage *destination,
1144 	      Position from_x, Position from_y,
1145 	      Position to_x, Position to_y,
1146 	      Position at_x, Position at_y)
1147 {
1148     Position x, y, delta_x, delta_y;
1149 
1150     delta_x = to_x - from_x + 1;
1151     delta_y = to_y - from_y + 1;
1152 
1153     for (x = 0; x < delta_x; x++)
1154 	for (y = 0; y < delta_y; y++)
1155 	    if (GetBit(source, from_x + x, from_y + y))
1156 		SetBit(destination, at_x + x, at_y + y);
1157 	    else
1158 		ClearBit(destination, at_x + x, at_y + y);
1159 }
1160 
1161 XImage *
ConvertToBitmapImage(BitmapWidget BW,XImage * image)1162 ConvertToBitmapImage(BitmapWidget BW, XImage *image)
1163 {
1164     XImage *bitmap_image;
1165     char   *data;
1166     Position x, y;
1167 
1168     data = CreateCleanData(Length(image->width, image->height));
1169     bitmap_image = CreateBitmapImage(BW, data,
1170 				     (Dimension) image->width,
1171 				     (Dimension) image->height);
1172 
1173     for (x = 0; x < min(image->width, bitmap_image->width); x++)
1174 	for (y = 0; y < min(image->height, bitmap_image->height); y++)
1175 	    if ((XGetPixel(image, x, y) != 0) != GetBit(bitmap_image, x, y))
1176 		InvertBit(bitmap_image, x, y);
1177 
1178     return bitmap_image;
1179 }
1180 
1181 void
TransferImageData(XImage * source,XImage * destination)1182 TransferImageData(XImage *source, XImage *destination)
1183 {
1184     Position x, y;
1185 
1186     for (x = 0; x < min(source->width, destination->width); x++)
1187 	for (y = 0; y < min(source->height, destination->height); y++)
1188 	    if (GetBit(source, x, y) != GetBit(destination, x, y))
1189 		InvertBit(destination, x, y);
1190 }
1191 
1192 void
BWStore(Widget w)1193 BWStore(Widget w)
1194 {
1195     BitmapWidget BW = (BitmapWidget) w;
1196     Dimension width, height;
1197     char *storage_data;
1198 
1199     if (QuerySet(BW->bitmap.mark.from_x, BW->bitmap.mark.from_y)) {
1200 
1201 	DestroyBitmapImage(&BW->bitmap.storage);
1202 
1203 	width = BW->bitmap.mark.to_x - BW->bitmap.mark.from_x + 1;
1204 	height = BW->bitmap.mark.to_y - BW->bitmap.mark.from_y + 1;
1205 
1206 	storage_data = CreateCleanData(Length(width, height));
1207 
1208 	BW->bitmap.storage = CreateBitmapImage(BW,
1209 					       storage_data,
1210 					       width, height);
1211 
1212 	CopyImageData(BW->bitmap.image, BW->bitmap.storage,
1213 		      BW->bitmap.mark.from_x,  BW->bitmap.mark.from_y,
1214 		      BW->bitmap.mark.to_x,  BW->bitmap.mark.to_y,
1215 		      0, 0);
1216     }
1217 }
1218 
1219 void
BWClearMarked(Widget w)1220 BWClearMarked(Widget w)
1221 {
1222     BitmapWidget BW = (BitmapWidget) w;
1223 
1224     if (QuerySet(BW->bitmap.mark.from_x, BW->bitmap.mark.from_y))
1225 	BWDrawFilledRectangle(w,
1226 			      BW->bitmap.mark.from_x,
1227 			      BW->bitmap.mark.from_y,
1228 			      BW->bitmap.mark.to_x,
1229 			      BW->bitmap.mark.to_y,
1230 			      Clear);
1231 }
1232 
1233 
1234 void
BWDragMarked(Widget w,Position at_x,Position at_y)1235 BWDragMarked(Widget w, Position at_x, Position at_y)
1236 {
1237     BitmapWidget BW = (BitmapWidget) w;
1238 
1239     if (QuerySet(BW->bitmap.mark.from_x, BW->bitmap.mark.from_y))
1240 	BWDrawRectangle(w,
1241 			at_x, at_y,
1242 			at_x + BW->bitmap.mark.to_x - BW->bitmap.mark.from_x,
1243 			at_y + BW->bitmap.mark.to_y - BW->bitmap.mark.from_y,
1244 			Highlight);
1245 }
1246 
1247 void
BWDragStored(Widget w,Position at_x,Position at_y)1248 BWDragStored(Widget w, Position at_x, Position at_y)
1249 {
1250     BitmapWidget BW = (BitmapWidget) w;
1251 
1252     if (BW->bitmap.storage)
1253 	BWDrawRectangle(w,
1254 			at_x, at_y,
1255 			at_x + BW->bitmap.storage->width - 1,
1256 			at_y + BW->bitmap.storage->height - 1,
1257 			Highlight);
1258 }
1259 
1260 static void
DrawImageData(BitmapWidget BW,XImage * image,Position at_x,Position at_y,int value)1261 DrawImageData(BitmapWidget BW, XImage *image,
1262 	      Position at_x, Position at_y, int value)
1263 {
1264     Position x, y;
1265     Boolean  C, S, I, H;
1266     bit      A, B;
1267 
1268     C = value == Clear;
1269     S = value == Set;
1270     I = value == Invert;
1271     H = value == Highlight;
1272 
1273     for (x = 0; x < image->width; x++)
1274 	for (y = 0; y < image->height; y++) {
1275 	    A = GetBit(image, x, y);
1276 	    B = GetBit(BW->bitmap.image, at_x + x, at_y + y);
1277 	    if ((A & C) | ((A | B) & S) | ((A ^ B) & I) | ((A | B) & H))
1278 		value = (A & H) ? Highlight : Set;
1279 	    else
1280 		value = Clear;
1281 	    BWDrawPoint((Widget) BW,
1282 			 at_x + x, at_y + y,
1283 			 value);
1284 	}
1285 }
1286 
1287 void
BWRestore(Widget w,Position at_x,Position at_y,int value)1288 BWRestore(Widget w, Position at_x, Position at_y, int value)
1289 {
1290     BitmapWidget BW = (BitmapWidget) w;
1291 
1292     if (BW->bitmap.storage) {
1293       DrawImageData(BW, BW->bitmap.storage, at_x, at_y, value);
1294       /*DestroyBitmapImage(&BW->bitmap.storage);*/
1295     }
1296 }
1297 
1298 void
BWCopy(Widget w,Position at_x,Position at_y,int value)1299 BWCopy(Widget w, Position at_x, Position at_y, int value)
1300 {
1301     BitmapWidget BW = (BitmapWidget) w;
1302     XImage *storage;
1303     char *storage_data;
1304     Dimension width, height;
1305 
1306     if (QuerySet(BW->bitmap.mark.from_x, BW->bitmap.mark.from_y)) {
1307 
1308 	width = BW->bitmap.mark.to_x - BW->bitmap.mark.from_x + 1;
1309 	height = BW->bitmap.mark.to_y - BW->bitmap.mark.from_y + 1;
1310 
1311 	storage_data = CreateCleanData(Length(width, height));
1312 
1313 	storage = CreateBitmapImage(BW, storage_data, width, height);
1314 
1315 	CopyImageData(BW->bitmap.image, storage,
1316 		      BW->bitmap.mark.from_x,  BW->bitmap.mark.from_y,
1317 		      BW->bitmap.mark.to_x,  BW->bitmap.mark.to_y,
1318 		      0, 0);
1319 
1320 	DrawImageData(BW, storage, at_x, at_y, value);
1321 
1322 	DestroyBitmapImage(&storage);
1323     }
1324 }
1325 
1326 /* void BWMark(); */
1327 
1328 void
BWMove(Widget w,Position at_x,Position at_y,int value)1329 BWMove(Widget w, Position at_x, Position at_y, int value)
1330 {
1331     BitmapWidget BW = (BitmapWidget) w;
1332     XImage *storage;
1333     char *storage_data;
1334     Dimension width, height;
1335 
1336     if (QuerySet(BW->bitmap.mark.from_x, BW->bitmap.mark.from_y)) {
1337 
1338 	width = BW->bitmap.mark.to_x - BW->bitmap.mark.from_x + 1;
1339 	height = BW->bitmap.mark.to_y - BW->bitmap.mark.from_y + 1;
1340 
1341 	storage_data = CreateCleanData(Length(width, height));
1342 
1343 	storage = CreateBitmapImage(BW, storage_data, width, height);
1344 
1345 	CopyImageData(BW->bitmap.image, storage,
1346 		      BW->bitmap.mark.from_x,  BW->bitmap.mark.from_y,
1347 		      BW->bitmap.mark.to_x,  BW->bitmap.mark.to_y,
1348 		      0, 0);
1349 
1350 	BWDrawFilledRectangle(w,
1351 			      BW->bitmap.mark.from_x, BW->bitmap.mark.from_y,
1352 			      BW->bitmap.mark.to_x, BW->bitmap.mark.to_y,
1353 			      Clear);
1354 
1355 	DrawImageData(BW, storage, at_x, at_y, value);
1356 
1357 	BWMark(w, at_x, at_y,
1358 	     at_x + BW->bitmap.mark.to_x - BW->bitmap.mark.from_x,
1359 	     at_y + BW->bitmap.mark.to_y - BW->bitmap.mark.from_y);
1360 
1361 	DestroyBitmapImage(&storage);
1362     }
1363 }
1364 
1365 void
BWRedrawMark(Widget w)1366 BWRedrawMark(Widget w)
1367 {
1368     BitmapWidget BW = (BitmapWidget) w;
1369 
1370     if (QuerySet(BW->bitmap.mark.from_x, BW->bitmap.mark.from_y))
1371 	XFillRectangle(XtDisplay(BW), XtWindow(BW), BW->bitmap.highlighting_gc,
1372 		       InWindowX(BW, BW->bitmap.mark.from_x),
1373 		       InWindowY(BW, BW->bitmap.mark.from_y),
1374 		       InWindowX(BW, BW->bitmap.mark.to_x + 1) -
1375 		       InWindowX(BW, BW->bitmap.mark.from_x),
1376 		       InWindowY(BW, BW->bitmap.mark.to_y + 1) -
1377 		       InWindowY(BW, BW->bitmap.mark.from_y));
1378 }
1379 
1380 void
BWStoreToBuffer(Widget w)1381 BWStoreToBuffer(Widget w)
1382 {
1383     BitmapWidget BW = (BitmapWidget) w;
1384 
1385     memmove( BW->bitmap.buffer->data, BW->bitmap.image->data,
1386 	  Length(BW->bitmap.image->width, BW->bitmap.image->height));
1387 
1388     BW->bitmap.buffer_hot = BW->bitmap.hot;
1389     BW->bitmap.buffer_mark = BW->bitmap.mark;
1390 }
1391 
1392 void
BWUnmark(Widget w)1393 BWUnmark(Widget w)
1394 {
1395     BitmapWidget BW = (BitmapWidget) w;
1396 
1397     BW->bitmap.buffer_mark = BW->bitmap.mark;
1398 
1399     if (QuerySet(BW->bitmap.mark.from_x, BW->bitmap.mark.from_y)) {
1400 	XFillRectangle(XtDisplay(BW), XtWindow(BW), BW->bitmap.highlighting_gc,
1401 		       InWindowX(BW, BW->bitmap.mark.from_x),
1402 		       InWindowY(BW, BW->bitmap.mark.from_y),
1403 		       InWindowX(BW, BW->bitmap.mark.to_x + 1) -
1404 		       InWindowX(BW, BW->bitmap.mark.from_x),
1405 		       InWindowY(BW, BW->bitmap.mark.to_y + 1) -
1406 		       InWindowY(BW, BW->bitmap.mark.from_y));
1407 
1408 	BW->bitmap.mark.from_x = BW->bitmap.mark.from_y = NotSet;
1409 	BW->bitmap.mark.to_x = BW->bitmap.mark.to_y = NotSet;
1410     }
1411 }
1412 
1413 void
BWMark(Widget w,Position from_x,Position from_y,Position to_x,Position to_y)1414 BWMark(Widget w, Position from_x, Position from_y,
1415        Position to_x, Position to_y)
1416 {
1417     BitmapWidget BW = (BitmapWidget) w;
1418 
1419     BWUnmark(w);
1420 
1421     if (QuerySet(from_x, from_y)) {
1422 	if ((from_x == to_x) && (from_y == to_y)) {
1423 	    /*
1424 	      BW->bitmap.mark.from_x = 0;
1425 	      BW->bitmap.mark.from_y = 0;
1426 	      BW->bitmap.mark.to_x = BW->bitmap.image->width - 1;
1427 	      BW->bitmap.mark.to_y = BW->bitmap.image->height - 1;
1428 	      */
1429 	    return;
1430 	}
1431 	else {
1432 	    QuerySwap(from_x, to_x);
1433 	    QuerySwap(from_y, to_y);
1434 	    from_x = max(0, from_x);
1435 	    from_y = max(0, from_y);
1436 	    to_x = min(BW->bitmap.image->width - 1, to_x);
1437 	    to_y = min(BW->bitmap.image->height - 1, to_y);
1438 
1439 	    BW->bitmap.mark.from_x = from_x;
1440 	    BW->bitmap.mark.from_y = from_y;
1441 	    BW->bitmap.mark.to_x = to_x;
1442 	    BW->bitmap.mark.to_y = to_y;
1443 	}
1444 
1445 	XFillRectangle(XtDisplay(BW), XtWindow(BW), BW->bitmap.highlighting_gc,
1446 		       InWindowX(BW, BW->bitmap.mark.from_x),
1447 		       InWindowY(BW, BW->bitmap.mark.from_y),
1448 		       InWindowX(BW, BW->bitmap.mark.to_x + 1) -
1449 		       InWindowX(BW, BW->bitmap.mark.from_x),
1450 		       InWindowY(BW, BW->bitmap.mark.to_y +1) -
1451 		       InWindowY(BW, BW->bitmap.mark.from_y));
1452     }
1453 }
1454 
1455 void
BWMarkAll(Widget w)1456 BWMarkAll(Widget w)
1457 {
1458   BitmapWidget BW = (BitmapWidget) w;
1459 
1460   BWMark(w, 0, 0, BW->bitmap.image->width - 1, BW->bitmap.image->height - 1);
1461 }
1462 
1463 void
BWUndo(Widget w)1464 BWUndo(Widget w)
1465 {
1466     BitmapWidget BW = (BitmapWidget) w;
1467     Position x, y;
1468     char *tmp_data;
1469     XPoint tmp_hot;
1470     BWArea tmp_mark;
1471 
1472     tmp_data = BW->bitmap.image->data;
1473     BW->bitmap.image->data = BW->bitmap.buffer->data;
1474     BW->bitmap.buffer->data = tmp_data;
1475 
1476     tmp_hot = BW->bitmap.hot;
1477     tmp_mark = BW->bitmap.mark;
1478 
1479     for (x = 0; x < BW->bitmap.image->width; x++)
1480 	for (y = 0; y < BW->bitmap.image->height; y++)
1481 	 if (GetBit(BW->bitmap.image, x, y) != GetBit(BW->bitmap.buffer, x, y))
1482 	     DrawSquare(BW, x, y);
1483 
1484     BWSetHotSpot(w, BW->bitmap.buffer_hot.x, BW->bitmap.buffer_hot.y);
1485 /*
1486     BWMark(w, BW->bitmap.buffer_mark.from_x, BW->bitmap.buffer_mark.from_y,
1487 	   BW->bitmap.buffer_mark.to_x, BW->bitmap.buffer_mark.to_y);
1488 */
1489     BW->bitmap.buffer_hot = tmp_hot;
1490     BW->bitmap.buffer_mark= tmp_mark;
1491 
1492 }
1493 
1494 void
BWHighlightAxes(Widget w)1495 BWHighlightAxes(Widget w)
1496 {
1497     BitmapWidget BW = (BitmapWidget) w;
1498 
1499     XDrawLine(XtDisplay(BW), XtWindow(BW),
1500 	      BW->bitmap.axes_gc,
1501 	      InWindowX(BW, 0),
1502 	      InWindowY(BW, 0),
1503 	      InWindowX(BW, BW->bitmap.width),
1504 	      InWindowY(BW, BW->bitmap.height));
1505     XDrawLine(XtDisplay(BW), XtWindow(BW),
1506 	      BW->bitmap.axes_gc,
1507 	      InWindowX(BW, BW->bitmap.width),
1508 	      InWindowY(BW, 0),
1509 	      InWindowX(BW, 0),
1510 	      InWindowY(BW, BW->bitmap.height));
1511     XDrawLine(XtDisplay(BW), XtWindow(BW),
1512 	      BW->bitmap.axes_gc,
1513 	      InWindowX(BW, 0),
1514 	      InWindowY(BW, (float)BW->bitmap.height / 2.0),
1515 	      InWindowX(BW, BW->bitmap.width),
1516 	      InWindowY(BW, (float)BW->bitmap.height / 2.0));
1517     XDrawLine(XtDisplay(BW), XtWindow(BW),
1518 	      BW->bitmap.axes_gc,
1519 	      InWindowX(BW, (float)BW->bitmap.width / 2.0),
1520 	      InWindowY(BW, 0),
1521 	      InWindowX(BW, (float)BW->bitmap.width / 2.0),
1522 	      InWindowY(BW, BW->bitmap.height));
1523 }
1524 
1525 typedef struct {
1526     Position *x, *y;
1527     Dimension *width, *height;
1528 } Table;
1529 
1530 XImage *
ScaleBitmapImage(BitmapWidget BW,XImage * src,double scale_x,double scale_y)1531 ScaleBitmapImage(BitmapWidget BW, XImage *src,
1532 		 double scale_x, double scale_y)
1533 {
1534     char *data;
1535     XImage *dst;
1536     Table table;
1537     Position x, y, w, h;
1538     Dimension width, height;
1539     bit pixel;
1540 
1541     width = max(rint(scale_x * src->width), 1);
1542     height = max(rint(scale_y * src->height), 1);
1543 
1544     data = CreateCleanData(Length(width, height));
1545     dst = CreateBitmapImage(BW, data, width, height);
1546 
1547     /*
1548      * It would be nice to check if width or height < 1.0 and
1549      * average the skipped pixels. But, it is slow as it is now.
1550      */
1551     if (scale_x == 1.0 && scale_y == 1.0)
1552 	memmove( dst->data, src->data, Length(width, height));
1553     else {
1554 	table.x = (Position *) XtMalloc(sizeof(Position) * src->width);
1555 	table.y = (Position *) XtMalloc(sizeof(Position) * src->height);
1556 	table.width = (Dimension *) XtMalloc(sizeof(Dimension) * src->width);
1557 	table.height = (Dimension *) XtMalloc(sizeof(Dimension) * src->height);
1558 
1559 	for (x = 0; x < src->width; x++) {
1560 	    table.x[x] = rint(scale_x * x);
1561 	    table.width[x] = rint(scale_x * (x + 1)) - rint(scale_x * x);
1562 	}
1563 	for (y = 0; y < src->height; y++) {
1564 	    table.y[y] = rint(scale_y * y);
1565 	    table.height[y] = rint(scale_y * (y + 1)) - rint(scale_y * y);
1566 	}
1567 
1568 	for (x = 0; x < src->width; x++)
1569 	    for (y = 0; y < src->height; y++) {
1570 	        pixel = GetBit(src, x, y);
1571 		for (w = 0; (int)w < (int)table.width[x]; w++)
1572 		    for (h = 0; (int)h < (int)table.height[y]; h++)
1573 			if (pixel) SetBit(dst,
1574 					table.x[x] + w,
1575 					table.y[y] + h);
1576 	    }
1577 
1578 	XtFree((char *)table.x);
1579 	XtFree((char *)table.y);
1580 	XtFree((char *)table.width);
1581 	XtFree((char *)table.height);
1582     }
1583 
1584     return (dst);
1585 }
1586 
1587 /*****************************************************************************/
1588