Home | History | Annotate | Line # | Download | only in dist
      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
    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 *
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
   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
   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 *
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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 *
   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