OSDN Git Service

Merge remote-tracking branch 'remotes/origin/feature/Refactor-Unnecessary-Files-Remov...
[hengband/hengband.git] / src / maid-x11.c
1 /* File: maid-x11.c */
2
3 /*
4  * Copyright (c) 1997 Ben Harrison, and others
5  *
6  * This software may be copied and distributed for educational, research,
7  * and not for profit purposes provided that this copyright and statement
8  * are included in all such copies.
9  */
10
11 #ifdef USE_X11
12
13 #include <math.h>
14 #include "main/x11-gamma-builder.h"
15
16 /*
17  * This file defines some "XImage" manipulation functions for X11.
18  *
19  * Original code by Desvignes Sebastien (desvigne@solar12.eerie.fr).
20  *
21  * BMP format support by Denis Eropkin (denis@dream.homepage.ru).
22  *
23  * Major fixes and cleanup by Ben Harrison (benh@phial.com).
24  *
25  * This file is designed to be "included" by "main-x11.c" or "main-xaw.c",
26  * which will have already "included" several relevant header files.
27  */
28
29
30
31 #ifndef IsModifierKey
32
33 /*
34  * Keysym macros, used on Keysyms to test for classes of symbols
35  * These were stolen from one of the X11 header files
36  *
37  * Also appears in "main-x11.c".
38  */
39
40 #define IsKeypadKey(keysym) \
41   (((unsigned)(keysym) >= XK_KP_Space) && ((unsigned)(keysym) <= XK_KP_Equal))
42
43 #define IsCursorKey(keysym) \
44   (((unsigned)(keysym) >= XK_Home)     && ((unsigned)(keysym) <  XK_Select))
45
46 #define IsPFKey(keysym) \
47   (((unsigned)(keysym) >= XK_KP_F1)     && ((unsigned)(keysym) <= XK_KP_F4))
48
49 #define IsFunctionKey(keysym) \
50   (((unsigned)(keysym) >= XK_F1)       && ((unsigned)(keysym) <= XK_F35))
51
52 #define IsMiscFunctionKey(keysym) \
53   (((unsigned)(keysym) >= XK_Select)   && ((unsigned)(keysym) <  XK_KP_Space))
54
55 #define IsModifierKey(keysym) \
56   (((unsigned)(keysym) >= XK_Shift_L)  && ((unsigned)(keysym) <= XK_Hyper_R))
57
58 #endif /* IsModifierKey */
59
60
61 /*
62  * Checks if the keysym is a special key or a normal key
63  * Assume that XK_MISCELLANY keysyms are special
64  *
65  * Also appears in "main-x11.c".
66  */
67 #define IsSpecialKey(keysym) \
68   ((unsigned)(keysym) >= 0xFF00)
69
70
71 static bool gamma_table_ready = FALSE;
72 static int gamma_val = 0;
73
74
75 /*
76  * Hack -- Convert an RGB value to an X11 Pixel, or die.
77  */
78 #ifdef USE_XFT
79 static XftColor create_pixel(Display *dpy, byte red, byte green, byte blue)
80 #else
81 static unsigned long create_pixel(Display *dpy, byte red, byte green, byte blue)
82 #endif
83 {
84         Colormap cmap = DefaultColormapOfScreen(DefaultScreenOfDisplay(dpy));
85         XColor xcolour;
86         if (!gamma_table_ready)
87         {
88                 concptr str = getenv("ANGBAND_X11_GAMMA");
89                 if (str != NULL) gamma_val = atoi(str);
90                 
91                 gamma_table_ready = TRUE;
92                 
93                 /* Only need to build the table if gamma exists */
94                 if (gamma_val) build_gamma_table(gamma_val);
95         }
96
97         /* Hack -- Gamma Correction */
98         if (gamma_val > 0)
99         {
100                 red = gamma_table[red];
101                 green = gamma_table[green];
102                 blue = gamma_table[blue];
103         }
104
105         /* Build the color */
106         
107         xcolour.red = red * 255;
108         xcolour.green = green * 255;
109         xcolour.blue = blue * 255;
110         xcolour.flags = DoRed | DoGreen | DoBlue;
111
112 #ifdef USE_XFT
113         XftColor color;
114         XRenderColor xcol;
115         xcol.red = xcolour.red;
116         xcol.green = xcolour.green;
117         xcol.blue = xcolour.blue;
118         if (!XftColorAllocValue(dpy, DefaultVisual(dpy, 0), cmap, &xcol, &color))
119         {
120                 quit_fmt("Couldn't allocate bitmap color '#%02x%02x%02x'\n",
121                          red, green, blue);
122         }
123
124         return color;
125 #else
126         /* Attempt to Allocate the Parsed color */
127         if (!(XAllocColor(dpy, cmap, &xcolour)))
128         {
129                 quit_fmt("Couldn't allocate bitmap color '#%02x%02x%02x'\n",
130                          red, green, blue);
131         }
132
133         return (xcolour.pixel);
134 #endif
135 }
136
137
138 #ifndef USE_XFT
139
140 /*
141  * The Win32 "BITMAPFILEHEADER" type.
142  */
143 typedef struct BITMAPFILEHEADER
144 {
145         u16b bfType;
146         u32b bfSize;
147         u16b bfReserved1;
148         u16b bfReserved2;
149         u32b bfOffBits;
150 } BITMAPFILEHEADER;
151
152 /*
153  * The Win32 "BITMAPINFOHEADER" type.
154  */
155 typedef struct BITMAPINFOHEADER
156 {
157         u32b biSize;
158         u32b biWidth;
159         u32b biHeight;
160         u16b biPlanes;
161         u16b biBitCount;
162         u32b biCompresion;
163         u32b biSizeImage;
164         u32b biXPelsPerMeter;
165         u32b biYPelsPerMeter;
166         u32b biClrUsed;
167         u32b biClrImportand;
168 } BITMAPINFOHEADER;
169
170 /*
171  * The Win32 "RGBQUAD" type.
172  */
173 typedef struct RGBQUAD
174 {
175         unsigned char b, g, r;
176         unsigned char filler;
177 } RGBQUAD;
178
179
180 /*** Helper functions for system independent file loading. ***/
181
182 static byte get_byte(FILE *fff)
183 {
184         /* Get a character, and return it */
185         return (getc(fff) & 0xFF);
186 }
187
188 static void rd_byte(FILE *fff, byte *ip)
189 {
190         *ip = get_byte(fff);
191 }
192
193 static void rd_u16b(FILE *fff, u16b *ip)
194 {
195         (*ip) = get_byte(fff);
196         (*ip) |= ((u16b)(get_byte(fff)) << 8);
197 }
198
199 static void rd_u32b(FILE *fff, u32b *ip)
200 {
201         (*ip) = get_byte(fff);
202         (*ip) |= ((u32b)(get_byte(fff)) << 8);
203         (*ip) |= ((u32b)(get_byte(fff)) << 16);
204         (*ip) |= ((u32b)(get_byte(fff)) << 24);
205 }
206
207
208 /*
209  * Read a Win32 BMP file.
210  *
211  * This function replaces the old ReadRaw and RemapColors functions.
212  *
213  * Assumes that the bitmap has a size such that no padding is needed in
214  * various places.  Currently only handles bitmaps with 3 to 256 colors.
215  */
216 static XImage *ReadBMP(Display *dpy, char *Name)
217 {
218         Visual *visual = DefaultVisual(dpy, DefaultScreen(dpy));
219
220         int depth = DefaultDepth(dpy, DefaultScreen(dpy));
221
222         FILE *f;
223
224         BITMAPFILEHEADER fileheader;
225         BITMAPINFOHEADER infoheader;
226
227         XImage *Res = NULL;
228
229         char *Data;
230
231         int ncol;
232
233         int total;
234
235         int i, j;
236
237         int x, y;
238
239         unsigned long clr_pixels[256];
240
241
242         /* Open the BMP file */
243         f = fopen(Name, "r");
244
245         /* No such file */
246         if (f == NULL)
247         {
248                 return (NULL);
249         }
250
251         /* Read the "BITMAPFILEHEADER" */
252         rd_u16b(f, &(fileheader.bfType));
253         rd_u32b(f, &(fileheader.bfSize));
254         rd_u16b(f, &(fileheader.bfReserved1));
255         rd_u16b(f, &(fileheader.bfReserved2));
256         rd_u32b(f, &(fileheader.bfOffBits));
257
258         /* Read the "BITMAPINFOHEADER" */
259         rd_u32b(f, &(infoheader.biSize));
260         rd_u32b(f, &(infoheader.biWidth));
261         rd_u32b(f, &(infoheader.biHeight));
262         rd_u16b(f, &(infoheader.biPlanes));
263         rd_u16b(f, &(infoheader.biBitCount));
264         rd_u32b(f, &(infoheader.biCompresion));
265         rd_u32b(f, &(infoheader.biSizeImage));
266         rd_u32b(f, &(infoheader.biXPelsPerMeter));
267         rd_u32b(f, &(infoheader.biYPelsPerMeter));
268         rd_u32b(f, &(infoheader.biClrUsed));
269         rd_u32b(f, &(infoheader.biClrImportand));
270
271         /* Verify the header */
272         if (feof(f) ||
273             (fileheader.bfType != 19778) ||
274             (infoheader.biSize != 40))
275         {
276                 quit_fmt("Incorrect BMP file format %s", Name);
277         }
278
279         /* The two headers above occupy 54 bytes total */
280         /* The "bfOffBits" field says where the data starts */
281         /* The "biClrUsed" field does not seem to be reliable */
282         /* Compute number of colors recorded */
283         ncol = (fileheader.bfOffBits - 54) / 4;
284
285         for (i = 0; i < ncol; i++)
286         {
287                 RGBQUAD clrg;
288
289                 /* Read an "RGBQUAD" */
290                 rd_byte(f, &(clrg.b));
291                 rd_byte(f, &(clrg.g));
292                 rd_byte(f, &(clrg.r));
293                 rd_byte(f, &(clrg.filler));
294                 
295                 /* Analyze the color */
296                 clr_pixels[i] = create_pixel(dpy, clrg.r, clrg.g, clrg.b);
297         }
298
299         /* Determine total bytes needed for image */
300         i = 1;
301         j = (depth - 1) >> 2;
302         while (j >>= 1) i <<= 1;
303         total = infoheader.biWidth * infoheader.biHeight * i;
304
305         /* Allocate image memory */
306         C_MAKE(Data, total, char);
307
308         Res = XCreateImage(dpy, visual, depth, ZPixmap, 0 /*offset*/,
309                            Data, infoheader.biWidth, infoheader.biHeight,
310                            8 /*bitmap_pad*/, 0 /*bytes_per_line*/);
311
312         /* Failure */
313         if (Res == NULL)
314         {
315                 C_KILL(Data, total, char);
316                 fclose(f);
317                 return (NULL);
318         }
319
320         for (y = 0; y < infoheader.biHeight; y++)
321         {
322                 int y2 = infoheader.biHeight - y - 1;
323
324                 for (x = 0; x < infoheader.biWidth; x++)
325                 {
326                         int ch = getc(f);
327
328                         /* Verify not at end of file XXX XXX */
329                         if (feof(f)) quit_fmt("Unexpected end of file in %s", Name);
330
331                         if (infoheader.biBitCount == 24)
332                         {
333                                 int c2 = getc(f);
334                                 int c3 = getc(f);
335
336                                 /* Verify not at end of file XXX XXX */
337                                 if (feof(f)) quit_fmt("Unexpected end of file in %s", Name);
338
339                                 XPutPixel(Res, x, y2, create_pixel(dpy, ch, c2, c3));
340                         }
341                         else if (infoheader.biBitCount == 8)
342                         {
343                                 XPutPixel(Res, x, y2, clr_pixels[ch]);
344                         }
345                         else if (infoheader.biBitCount == 4)
346                         {
347                                 XPutPixel(Res, x, y2, clr_pixels[ch / 16]);
348                                 x++;
349                                 XPutPixel(Res, x, y2, clr_pixels[ch % 16]);
350                         }
351                         else
352                         {
353                                 /* Technically 1 bit is legal too */
354                                 quit_fmt("Illegal biBitCount %d in %s",
355                                          infoheader.biBitCount, Name);
356                         }
357                 }
358         }
359
360         fclose(f);
361
362         return Res;
363 }
364
365
366 /* ========================================================*/
367 /* Code for smooth icon rescaling from Uwe Siems, Jan 2000 */
368 /* ========================================================*/
369
370 /*
371  * to save ourselves some labour, define a maximum expected icon width here:
372  */
373 #define MAX_ICON_WIDTH 32
374
375
376 /* some static variables for composing and decomposing pixel values into
377  * red, green and blue values
378  */
379 static unsigned long redMask, greenMask, blueMask;
380 static int redShift, greenShift, blueShift;
381
382
383 /*
384  * Use smooth rescaling?
385  */
386 static bool smoothRescaling = TRUE;
387
388
389 /*
390  * GetScaledRow reads a scan from the given XImage, scales it smoothly
391  * and returns the red, green and blue values in arrays.
392  * The values in this arrays must be divided by a certain value that is
393  * calculated in ScaleIcon.
394  * x, y is the position, iw is the input width and ow the output width
395  * redScan, greenScan and blueScan must be sufficiently sized
396  */
397 static void GetScaledRow(XImage *Im, int x, int y, int iw, int ow,
398                          unsigned long *redScan, unsigned long *greenScan,
399                          unsigned long *blueScan)
400 {
401         int xi, si, sifrac, ci, cifrac, addWhole, addFrac;
402         unsigned long pix;
403         int prevRed, prevGreen, prevBlue, nextRed, nextGreen, nextBlue;
404         bool getNextPix;
405
406         if (iw == ow)
407         {
408                 /* unscaled */
409                 for (xi = 0; xi < ow; xi++)
410                 {
411                         pix = XGetPixel(Im, x + xi, y);
412                         redScan   [xi] = (pix >> redShift) & redMask;
413                         greenScan [xi] = (pix >> greenShift) & greenMask;
414                         blueScan  [xi] = (pix >> blueShift) & blueMask;
415                 }
416         }
417         else if (iw < ow)
418         {
419                 /* scaling by subsampling (grow) */
420                 iw--;
421                 ow--;
422                 /* read first pixel: */
423                 pix = XGetPixel(Im, x, y);
424                 nextRed   = (pix >> redShift) & redMask;
425                 nextGreen = (pix >> greenShift) & greenMask;
426                 nextBlue  = (pix >> blueShift) & blueMask;
427                 prevRed   = nextRed;
428                 prevGreen = nextGreen;
429                 prevBlue  = nextBlue;
430                 /* si and sifrac give the subsampling position: */
431                 si = x;
432                 sifrac = 0;
433                 /* getNextPix tells us, that we need the next pixel */
434                 getNextPix = TRUE;
435
436                 for (xi = 0; xi <= ow; xi++)
437                 {
438                         if (getNextPix)
439                         {
440                                 prevRed   = nextRed;
441                                 prevGreen = nextGreen;
442                                 prevBlue  = nextBlue;
443                                 if (xi < ow)
444                                 {
445                                         /* only get next pixel if in same icon */
446                                         pix = XGetPixel(Im, si + 1, y);
447                                         nextRed   = (pix >> redShift) & redMask;
448                                         nextGreen = (pix >> greenShift) & greenMask;
449                                         nextBlue  = (pix >> blueShift) & blueMask;
450                                 }
451                         }
452
453                         /* calculate subsampled color values: */
454                         /* division by ow occurs in ScaleIcon */
455                         redScan   [xi] = prevRed   * (ow - sifrac) + nextRed   * sifrac;
456                         greenScan [xi] = prevGreen * (ow - sifrac) + nextGreen * sifrac;
457                         blueScan  [xi] = prevBlue  * (ow - sifrac) + nextBlue  * sifrac;
458
459                         /* advance sampling position: */
460                         sifrac += iw;
461                         if (sifrac >= ow)
462                         {
463                                 si++;
464                                 sifrac -= ow;
465                                 getNextPix = TRUE;
466                         }
467                         else
468                         {
469                                 getNextPix = FALSE;
470                         }
471
472                 }
473         }
474         else
475         {
476                 /* scaling by averaging (shrink) */
477                 /* width of an output pixel in input pixels: */
478                 addWhole = iw / ow;
479                 addFrac = iw % ow;
480                 /* start position of the first output pixel: */
481                 si = x;
482                 sifrac = 0;
483                 /* get first input pixel: */
484                 pix = XGetPixel(Im, x, y);
485                 nextRed   = (pix >> redShift) & redMask;
486                 nextGreen = (pix >> greenShift) & greenMask;
487                 nextBlue  = (pix >> blueShift) & blueMask;
488                 for (xi = 0; xi < ow; xi++)
489                 {
490                         /* find endpoint of the current output pixel: */
491                         ci = si + addWhole;
492                         cifrac = sifrac + addFrac;
493                         if (cifrac >= ow)
494                         {
495                                 ci++;
496                                 cifrac -= ow;
497                         }
498                         /* take fraction of current input pixel (starting segment): */
499                         redScan[xi]   = nextRed   * (ow - sifrac);
500                         greenScan[xi] = nextGreen * (ow - sifrac);
501                         blueScan[xi]  = nextBlue  * (ow - sifrac);
502                         si++;
503                         /* add values for whole pixels: */
504                         while (si < ci)
505                         {
506                                 pix = XGetPixel(Im, si, y);
507                                 redScan[xi]   += ((pix >> redShift) & redMask)   *ow;
508                                 greenScan[xi] += ((pix >> greenShift) & greenMask) *ow;
509                                 blueScan[xi]  += ((pix >> blueShift) & blueMask)   *ow;
510                                 si++;
511                         }
512                         /* add fraction of current input pixel (ending segment): */
513                         if (xi < ow - 1)
514                         {
515                                 /* only get next pixel if still in icon: */
516                                 pix = XGetPixel(Im, si, y);
517                                 nextRed   = (pix >> redShift) & redMask;
518                                 nextGreen = (pix >> greenShift) & greenMask;
519                                 nextBlue  = (pix >> blueShift) & blueMask;
520                         }
521                         sifrac = cifrac;
522                         if (sifrac > 0)
523                         {
524                                 redScan[xi]   += nextRed   * sifrac;
525                                 greenScan[xi] += nextGreen * sifrac;
526                                 blueScan[xi]  += nextBlue  * sifrac;
527                         }
528                 }
529         }
530 }
531
532
533 /*
534  * PutRGBScan takes arrays for red, green and blue and writes pixel values
535  * according to this values in the XImage-structure. w is the number of
536  * pixels to write and div is the value by which all red/green/blue values
537  * are divided first.
538  */
539 static void PutRGBScan(XImage *Im, int x, int y, int w, int div,
540                        unsigned long *redScan, unsigned long *greenScan,
541                        unsigned long *blueScan)
542 {
543         int xi;
544         unsigned long pix;
545         unsigned long adj = div / 2;
546         for (xi = 0; xi < w; xi++)
547         {
548                 pix = (((((redScan[xi] + adj) / div) & redMask) << redShift) +
549                        ((((greenScan[xi] + adj) / div) & greenMask) << greenShift) +
550                        ((((blueScan[xi] + adj) / div) & blueMask) << blueShift));
551                 XPutPixel(Im, x + xi, y, pix);
552         }
553 }
554
555
556 /*
557  * ScaleIcon transfers an area from XImage ImIn, locate (x1,y1) to ImOut,
558  * locate (x2, y2).
559  * Source size is (ix, iy) and destination size is (ox, oy).
560  * It does this by getting icon scan line from GetScaledScan and handling
561  * them the same way as pixels are handled in GetScaledScan.
562  * This even allows icons to be scaled differently in horizontal and
563  * vertical directions (eg. shrink horizontal, grow vertical).
564  */
565 static void ScaleIcon(XImage *ImIn, XImage *ImOut,
566                       int x1, int y1, int x2, int y2,
567                       int ix, int iy, int ox, int oy)
568 {
569         int div;
570         int xi, yi, si, sifrac, ci, cifrac, addWhole, addFrac;
571
572         /* buffers for pixel rows: */
573         unsigned long prevRed   [MAX_ICON_WIDTH];
574         unsigned long prevGreen [MAX_ICON_WIDTH];
575         unsigned long prevBlue  [MAX_ICON_WIDTH];
576         unsigned long nextRed   [MAX_ICON_WIDTH];
577         unsigned long nextGreen [MAX_ICON_WIDTH];
578         unsigned long nextBlue  [MAX_ICON_WIDTH];
579         unsigned long tempRed   [MAX_ICON_WIDTH];
580         unsigned long tempGreen [MAX_ICON_WIDTH];
581         unsigned long tempBlue  [MAX_ICON_WIDTH];
582
583         bool getNextRow;
584
585         /* get divider value for the horizontal scaling: */
586         if (ix == ox)
587                 div = 1;
588         else if (ix < ox)
589                 div = ox - 1;
590         else
591                 div = ix;
592
593         if (iy == oy)
594         {
595                 /* no scaling needed vertically: */
596                 for (yi = 0; yi < oy; yi++)
597                 {
598                         GetScaledRow(ImIn, x1, y1 + yi, ix, ox,
599                                      tempRed, tempGreen, tempBlue);
600                         PutRGBScan(ImOut, x2, y2 + yi, ox, div,
601                                    tempRed, tempGreen, tempBlue);
602                 }
603         }
604         else if (iy < oy)
605         {
606                 /* scaling by subsampling (grow): */
607                 iy--;
608                 oy--;
609                 div *= oy;
610                 /* get first row: */
611                 GetScaledRow(ImIn, x1, y1, ix, ox, nextRed, nextGreen, nextBlue);
612                 /* si and sifrac give the subsampling position: */
613                 si = y1;
614                 sifrac = 0;
615                 /* getNextRow tells us, that we need the next row */
616                 getNextRow = TRUE;
617                 for (yi = 0; yi <= oy; yi++)
618                 {
619                         if (getNextRow)
620                         {
621                                 for (xi = 0; xi < ox; xi++)
622                                 {
623                                         prevRed[xi]   = nextRed[xi];
624                                         prevGreen[xi] = nextGreen[xi];
625                                         prevBlue[xi]  = nextBlue[xi];
626                                 }
627                                 if (yi < oy)
628                                 {
629                                         /* only get next row if in same icon */
630                                         GetScaledRow(ImIn, x1, si + 1, ix, ox,
631                                                      nextRed, nextGreen, nextBlue);
632                                 }
633                         }
634
635                         /* calculate subsampled color values: */
636                         /* division by oy occurs in PutRGBScan */
637                         for (xi = 0; xi < ox; xi++)
638                         {
639                                 tempRed[xi] = (prevRed[xi] * (oy - sifrac) +
640                                                nextRed[xi] * sifrac);
641                                 tempGreen[xi] = (prevGreen[xi] * (oy - sifrac) +
642                                                  nextGreen[xi] * sifrac);
643                                 tempBlue[xi] = (prevBlue[xi] * (oy - sifrac) +
644                                                 nextBlue[xi] * sifrac);
645                         }
646
647                         /* write row to output image: */
648                         PutRGBScan(ImOut, x2, y2 + yi, ox, div,
649                                    tempRed, tempGreen, tempBlue);
650
651                         /* advance sampling position: */
652                         sifrac += iy;
653                         if (sifrac >= oy)
654                         {
655                                 si++;
656                                 sifrac -= oy;
657                                 getNextRow = TRUE;
658                         }
659                         else
660                         {
661                                 getNextRow = FALSE;
662                         }
663
664                 }
665         }
666         else
667         {
668                 /* scaling by averaging (shrink) */
669                 div *= iy;
670                 /* height of a output row in input rows: */
671                 addWhole = iy / oy;
672                 addFrac = iy % oy;
673                 /* start position of the first output row: */
674                 si = y1;
675                 sifrac = 0;
676                 /* get first input row: */
677                 GetScaledRow(ImIn, x1, y1, ix, ox, nextRed, nextGreen, nextBlue);
678                 for (yi = 0; yi < oy; yi++)
679                 {
680                         /* find endpoint of the current output row: */
681                         ci = si + addWhole;
682                         cifrac = sifrac + addFrac;
683                         if (cifrac >= oy)
684                         {
685                                 ci++;
686                                 cifrac -= oy;
687                         }
688                         /* take fraction of current input row (starting segment): */
689                         for (xi = 0; xi < ox; xi++)
690                         {
691                                 tempRed[xi]   = nextRed[xi]   * (oy - sifrac);
692                                 tempGreen[xi] = nextGreen[xi] * (oy - sifrac);
693                                 tempBlue[xi]  = nextBlue[xi]  * (oy - sifrac);
694                         }
695                         si++;
696                         /* add values for whole pixels: */
697                         while (si < ci)
698                         {
699                                 GetScaledRow(ImIn, x1, si, ix, ox,
700                                              nextRed, nextGreen, nextBlue);
701                                 for (xi = 0; xi < ox; xi++)
702                                 {
703                                         tempRed[xi]   += nextRed[xi]   * oy;
704                                         tempGreen[xi] += nextGreen[xi] * oy;
705                                         tempBlue[xi]  += nextBlue[xi]  * oy;
706                                 }
707                                 si++;
708                         }
709                         /* add fraction of current input row (ending segment): */
710                         if (yi < oy - 1)
711                         {
712                                 /* only get next row if still in icon: */
713                                 GetScaledRow(ImIn, x1, si, ix, ox,
714                                              nextRed, nextGreen, nextBlue);
715                         }
716                         sifrac = cifrac;
717                         for (xi = 0; xi < ox; xi++)
718                         {
719                                 tempRed[xi]   += nextRed[xi]   * sifrac;
720                                 tempGreen[xi] += nextGreen[xi] * sifrac;
721                                 tempBlue[xi]  += nextBlue[xi]  * sifrac;
722                         }
723                         /* write row to output image: */
724                         PutRGBScan(ImOut, x2, y2 + yi, ox, div,
725                                    tempRed, tempGreen, tempBlue);
726                 }
727         }
728 }
729
730
731
732 static XImage *ResizeImageSmooth(Display *dpy, XImage *Im,
733                                  int ix, int iy, int ox, int oy)
734 {
735         Visual *visual = DefaultVisual(dpy, DefaultScreen(dpy));
736
737         int width1, height1, width2, height2;
738         int x1, x2, y1, y2;
739
740         XImage *Tmp;
741
742         char *Data;
743
744         width1 = Im->width;
745         height1 = Im->height;
746
747         width2 = ox * width1 / ix;
748         height2 = oy * height1 / iy;
749
750         Data = (char *)malloc(width2 * height2 * Im->bits_per_pixel / 8);
751
752         Tmp = XCreateImage(dpy, visual,
753                            Im->depth, ZPixmap, 0, Data, width2, height2,
754                            32, 0);
755
756         /* compute values for decomposing pixel into color values: */
757         redMask = Im->red_mask;
758         redShift = 0;
759         while ((redMask & 1) == 0)
760         {
761             redShift++;
762             redMask >>= 1;
763         }
764         greenMask = Im->green_mask;
765         greenShift = 0;
766         while ((greenMask & 1) == 0)
767         {
768             greenShift++;
769             greenMask >>= 1;
770         }
771         blueMask = Im->blue_mask;
772         blueShift = 0;
773         while ((blueMask & 1) == 0)
774         {
775             blueShift++;
776             blueMask >>= 1;
777         }
778
779         /* scale each icon: */
780         for (y1 = 0, y2 = 0; (y1 < height1) && (y2 < height2); y1 += iy, y2 += oy)
781         {
782                 for (x1 = 0, x2 = 0; (x1 < width1) && (x2 < width2); x1 += ix, x2 += ox)
783                 {
784                         ScaleIcon(Im, Tmp, x1, y1, x2, y2,
785                                   ix, iy, ox, oy);
786                 }
787         }
788
789         return Tmp;
790 }
791
792
793 /*
794  * Resize an image. XXX XXX XXX
795  *
796  * Also appears in "main-xaw.c".
797  */
798 static XImage *ResizeImage(Display *dpy, XImage *Im,
799                            int ix, int iy, int ox, int oy)
800 {
801         Visual *visual = DefaultVisual(dpy, DefaultScreen(dpy));
802
803         int width1, height1, width2, height2;
804         int x1, x2, y1, y2, Tx, Ty;
805         int *px1, *px2, *dx1, *dx2;
806         int *py1, *py2, *dy1, *dy2;
807
808         XImage *Tmp;
809
810         char *Data;
811
812         if (smoothRescaling && (ix != ox || iy != oy) &&
813             visual->class == TrueColor)
814         {
815             return ResizeImageSmooth(dpy, Im, ix, iy, ox, oy);
816         }
817
818         width1 = Im->width;
819         height1 = Im->height;
820
821         width2 = ox * width1 / ix;
822         height2 = oy * height1 / iy;
823
824         Data = (char *)malloc(width2 * height2 * Im->bits_per_pixel / 8);
825
826         Tmp = XCreateImage(dpy, visual,
827                            Im->depth, ZPixmap, 0, Data, width2, height2,
828                            32, 0);
829
830         if (ix > ox)
831         {
832                 px1 = &x1;
833                 px2 = &x2;
834                 dx1 = &ix;
835                 dx2 = &ox;
836         }
837         else
838         {
839                 px1 = &x2;
840                 px2 = &x1;
841                 dx1 = &ox;
842                 dx2 = &ix;
843         }
844
845         if (iy > oy)
846         {
847                 py1 = &y1;
848                 py2 = &y2;
849                 dy1 = &iy;
850                 dy2 = &oy;
851         }
852         else
853         {
854                 py1 = &y2;
855                 py2 = &y1;
856                 dy1 = &oy;
857                 dy2 = &iy;
858         }
859
860         Ty = *dy1/2;
861
862         for (y1 = 0, y2 = 0; (y1 < height1) && (y2 < height2); )
863         {
864                 Tx = *dx1/2;
865
866                 for (x1 = 0, x2 = 0; (x1 < width1) && (x2 < width2); )
867                 {
868                         XPutPixel(Tmp, x2, y2, XGetPixel(Im, x1, y1));
869
870                         (*px1)++;
871
872                         Tx -= *dx2;
873                         if (Tx < 0)
874                         {
875                                 Tx += *dx1;
876                                 (*px2)++;
877                         }
878                 }
879
880                 (*py1)++;
881
882                 Ty -= *dy2;
883                 if (Ty < 0)
884                 {
885                         Ty += *dy1;
886                         (*py2)++;
887                 }
888         }
889
890         return Tmp;
891 }
892
893 #endif /* !USE_XFT */
894
895 #endif /* USE_X11 */