1 // Image.cc from Blackbox - an X11 Window manager
2 // Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net)
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a
5 // copy of this software and associated documentation files (the "Software"),
6 // to deal in the Software without restriction, including without limitation
7 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 // and/or sell copies of the Software, and to permit persons to whom the
9 // Software is furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 // DEALINGS IN THE SOFTWARE.
21 
22 // stupid macros needed to access some functions in version 2 of the GNU C
23 // library
24 
25 #ifndef   _GNU_SOURCE
26 #define   _GNU_SOURCE
27 #endif // _GNU_SOURCE
28 
29 #ifdef    HAVE_CONFIG_H
30 #  include "../config.h"
31 #endif // HAVE_CONFIG_H
32 
33 #include "BaseDisplay.hh"
34 #include "Image.hh"
35 
36 #ifdef    HAVE_SYS_TYPES_H
37 #  include <sys/types.h>
38 #endif // HAVE_SYS_TYPES_H
39 
40 #ifndef u_int32_t
41 #  ifdef uint_32_t
42 typedef uint32_t u_int32_t;
43 #  else
44 #    ifdef __uint32_t
45 typedef __uint32_t u_int32_t;
46 #    else
47 typedef unsigned int u_int32_t;
48 #    endif
49 #  endif
50 #endif
51 
52 #ifdef    STDC_HEADERS
53 #  include <stdlib.h>
54 #  include <string.h>
55 #endif // STDC_HEADERS
56 
57 #ifdef    HAVE_STDIO_H
58 #  include <stdio.h>
59 #endif // HAVE_STDIO_H
60 
61 #ifdef    HAVE_CTYPE_H
62 #  include <ctype.h>
63 #endif // HAVE_CTYPE_H
64 
bsqrt(unsigned long x)65 static unsigned long bsqrt(unsigned long x) {
66   if (x <= 0) return 0;
67   if (x == 1) return 1;
68 
69   unsigned long r = x >> 1;
70   unsigned long q;
71 
72   while (1) {
73     q = x / r;
74     if (q >= r) return r;
75     r = (r + q) >> 1;
76   }
77 }
78 
79 
BImage(BImageControl * c,unsigned int w,unsigned int h)80 BImage::BImage(BImageControl *c, unsigned int w, unsigned int h) {
81   control = c;
82 
83   width = ((signed) w > 0) ? w : 1;
84   height = ((signed) h > 0) ? h : 1;
85 
86   red = new unsigned char[width * height];
87   green = new unsigned char[width * height];
88   blue = new unsigned char[width * height];
89 
90   xtable = ytable = (unsigned int *) 0;
91 
92   cpc = control->getColorsPerChannel();
93   cpccpc = cpc * cpc;
94 
95   control->getColorTables(&red_table, &green_table, &blue_table,
96                           &red_offset, &green_offset, &blue_offset,
97                           &red_bits, &green_bits, &blue_bits);
98 
99   if (control->getVisual()->c_class != TrueColor)
100     control->getXColorTable(&colors, &ncolors);
101 }
102 
103 
~BImage(void)104 BImage::~BImage(void) {
105   if (red) delete [] red;
106   if (green) delete [] green;
107   if (blue) delete [] blue;
108 }
109 
110 
render(BTexture * texture)111 Pixmap BImage::render(BTexture *texture) {
112   if (texture->getTexture() & BImage_ParentRelative)
113     return ParentRelative;
114   else if (texture->getTexture() & BImage_Solid)
115     return render_solid(texture);
116   else if (texture->getTexture() & BImage_Gradient)
117     return render_gradient(texture);
118 
119   return None;
120 }
121 
122 
render_solid(BTexture * texture)123 Pixmap BImage::render_solid(BTexture *texture) {
124   Pixmap pixmap = XCreatePixmap(control->getBaseDisplay()->getXDisplay(),
125 				control->getDrawable(), width,
126 				height, control->getDepth());
127   if (pixmap == None) {
128     fprintf(stderr,
129 		       "BImage::render_solid: error creating pixmap\n");
130     return None;
131   }
132 
133   XGCValues gcv;
134   GC gc, hgc, lgc;
135 
136   gcv.foreground = texture->getColor()->getPixel();
137   gcv.fill_style = FillSolid;
138   gc = XCreateGC(control->getBaseDisplay()->getXDisplay(), pixmap,
139 		 GCForeground | GCFillStyle, &gcv);
140 
141   gcv.foreground = texture->getHiColor()->getPixel();
142   hgc = XCreateGC(control->getBaseDisplay()->getXDisplay(), pixmap,
143 		  GCForeground, &gcv);
144 
145   gcv.foreground = texture->getLoColor()->getPixel();
146   lgc = XCreateGC(control->getBaseDisplay()->getXDisplay(), pixmap,
147 		  GCForeground, &gcv);
148 
149   XFillRectangle(control->getBaseDisplay()->getXDisplay(), pixmap, gc, 0, 0,
150 		 width, height);
151 
152 #ifdef    INTERLACE
153   if (texture->getTexture() & BImage_Interlaced) {
154     gcv.foreground = texture->getColorTo()->getPixel();
155     GC igc = XCreateGC(control->getBaseDisplay()->getXDisplay(), pixmap,
156 		       GCForeground, &gcv);
157 
158     register unsigned int i = 0;
159     for (; i < height; i += 2)
160       XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, igc,
161 		0, i, width, i);
162 
163     XFreeGC(control->getBaseDisplay()->getXDisplay(), igc);
164   }
165 #endif // INTERLACE
166 
167 
168   if (texture->getTexture() & BImage_Bevel1) {
169     if (texture->getTexture() & BImage_Raised) {
170       XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, lgc,
171                 0, height - 1, width - 1, height - 1);
172       XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, lgc,
173                 width - 1, height - 1, width - 1, 0);
174 
175       XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, hgc,
176                 0, 0, width - 1, 0);
177       XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, hgc,
178                 0, height - 1, 0, 0);
179     } else if (texture->getTexture() & BImage_Sunken) {
180       XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, hgc,
181                 0, height - 1, width - 1, height - 1);
182       XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, hgc,
183                 width - 1, height - 1, width - 1, 0);
184 
185       XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, lgc,
186                 0, 0, width - 1, 0);
187       XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, lgc,
188                 0, height - 1, 0, 0);
189     }
190   } else if (texture->getTexture() & BImage_Bevel2) {
191     if (texture->getTexture() & BImage_Raised) {
192       XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, lgc,
193                 1, height - 3, width - 3, height - 3);
194       XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, lgc,
195                 width - 3, height - 3, width - 3, 1);
196 
197       XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, hgc,
198                 1, 1, width - 3, 1);
199       XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, hgc,
200                 1, height - 3, 1, 1);
201     } else if (texture->getTexture() & BImage_Sunken) {
202       XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, hgc,
203                 1, height - 3, width - 3, height - 3);
204       XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, hgc,
205                 width - 3, height - 3, width - 3, 1);
206 
207       XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, lgc,
208                 1, 1, width - 3, 1);
209       XDrawLine(control->getBaseDisplay()->getXDisplay(), pixmap, lgc,
210                 1, height - 3, 1, 1);
211     }
212   }
213 
214   XFreeGC(control->getBaseDisplay()->getXDisplay(), gc);
215   XFreeGC(control->getBaseDisplay()->getXDisplay(), hgc);
216   XFreeGC(control->getBaseDisplay()->getXDisplay(), lgc);
217 
218   return pixmap;
219 }
220 
221 
render_gradient(BTexture * texture)222 Pixmap BImage::render_gradient(BTexture *texture) {
223  int inverted = 0;
224 
225 #ifdef    INTERLACE
226   interlaced = texture->getTexture() & BImage_Interlaced;
227 #endif // INTERLACE
228 
229   if (texture->getTexture() & BImage_Sunken) {
230     from = texture->getColorTo();
231     to = texture->getColor();
232 
233     if (! (texture->getTexture() & BImage_Invert)) inverted = 1;
234   } else {
235     from = texture->getColor();
236     to = texture->getColorTo();
237 
238     if (texture->getTexture() & BImage_Invert) inverted = 1;
239   }
240 
241   control->getGradientBuffers(width, height, &xtable, &ytable);
242 
243   if (texture->getTexture() & BImage_Diagonal) dgradient();
244   else if (texture->getTexture() & BImage_Elliptic) egradient();
245   else if (texture->getTexture() & BImage_Horizontal) hgradient();
246   else if (texture->getTexture() & BImage_Pyramid) pgradient();
247   else if (texture->getTexture() & BImage_Rectangle) rgradient();
248   else if (texture->getTexture() & BImage_Vertical) vgradient();
249   else if (texture->getTexture() & BImage_CrossDiagonal) cdgradient();
250   else if (texture->getTexture() & BImage_PipeCross) pcgradient();
251 
252   if (texture->getTexture() & BImage_Bevel1) bevel1();
253   else if (texture->getTexture() & BImage_Bevel2) bevel2();
254 
255   if (inverted) invert();
256 
257   Pixmap pixmap = renderPixmap();
258 
259   return pixmap;
260 
261 }
262 
263 
renderXImage(void)264 XImage *BImage::renderXImage(void) {
265   XImage *image =
266     XCreateImage(control->getBaseDisplay()->getXDisplay(),
267                  control->getVisual(), /*24*/control->getDepth(), ZPixmap, 0, 0,
268                  width, height, 32, 0);
269 
270   if (! image) {
271     fprintf(stderr,
272 		       "BImage::renderXImage: error creating XImage\n");
273     return (XImage *) 0;
274   }
275 
276   // insurance policy
277   image->data = (char *) 0;
278 
279   unsigned char *d = new unsigned char[image->bytes_per_line * (height + 1)];
280   register unsigned int x, y, dithx, dithy, r, g, b, o, er, eg, eb, offset;
281 
282   unsigned char *pixel_data = d, *ppixel_data = d;
283   unsigned long pixel;
284 
285   o = image->bits_per_pixel + ((image->byte_order == MSBFirst) ? 1 : 0);
286 
287   if (control->doDither() && width > 1 && height > 1) {
288     unsigned char dither4[4][4] = { {0, 4, 1, 5},
289                                     {6, 2, 7, 3},
290                                     {1, 5, 0, 4},
291                                     {7, 3, 6, 2} };
292 
293 #ifdef    ORDEREDPSEUDO
294     unsigned char dither8[8][8] = { { 0,  32, 8,  40, 2,  34, 10, 42 },
295                                     { 48, 16, 56, 24, 50, 18, 58, 26 },
296                                     { 12, 44, 4,  36, 14, 46, 6,  38 },
297                                     { 60, 28, 52, 20, 62, 30, 54, 22 },
298                                     { 3,  35, 11, 43, 1,  33, 9,  41 },
299                                     { 51, 19, 59, 27, 49, 17, 57, 25 },
300                                     { 15, 47, 7,  39, 13, 45, 5,  37 },
301                                     { 63, 31, 55, 23, 61, 29, 53, 21 } };
302 #endif // ORDEREDPSEUDO
303 
304     switch (control->getVisual()->c_class) {
305     case TrueColor:
306       // algorithm: ordered dithering... many many thanks to rasterman
307       // (raster@rasterman.com) for telling me about this... portions of this
308       // code is based off of his code in Imlib
309       for (y = 0, offset = 0; y < height; y++) {
310 	dithy = y & 0x3;
311 
312 	for (x = 0; x < width; x++, offset++) {
313           dithx = x & 0x3;
314           r = red[offset];
315           g = green[offset];
316           b = blue[offset];
317 
318           er = r & (red_bits - 1);
319           eg = g & (green_bits - 1);
320           eb = b & (blue_bits - 1);
321 
322           r = red_table[r];
323           g = green_table[g];
324           b = blue_table[b];
325 
326           if ((dither4[dithy][dithx] < er) && (r < red_table[255])) r++;
327           if ((dither4[dithy][dithx] < eg) && (g < green_table[255])) g++;
328           if ((dither4[dithy][dithx] < eb) && (b < blue_table[255])) b++;
329 
330 	  pixel = (r << red_offset) | (g << green_offset) | (b << blue_offset);
331 
332           switch (o) {
333           case 16: // 16bpp LSB
334             *pixel_data++ = pixel;
335 	    *pixel_data++ = pixel >> 8;
336             break;
337 
338           case 17: // 16bpp MSB
339 	    *pixel_data++ = pixel >> 8;
340 	    *pixel_data++ = pixel;
341             break;
342 
343 	  case 24: // 24bpp LSB
344 	    *pixel_data++ = pixel;
345 	    *pixel_data++ = pixel >> 8;
346 	    *pixel_data++ = pixel >> 16;
347 	    break;
348 
349           case 25: // 24bpp MSB
350             *pixel_data++ = pixel >> 16;
351             *pixel_data++ = pixel >> 8;
352             *pixel_data++ = pixel;
353             break;
354 
355           case 32: // 32bpp LSB
356             *pixel_data++ = pixel;
357             *pixel_data++ = pixel >> 8;
358             *pixel_data++ = pixel >> 16;
359             *pixel_data++ = pixel >> 24;
360             break;
361 
362           case 33: // 32bpp MSB
363             *pixel_data++ = pixel >> 24;
364             *pixel_data++ = pixel >> 16;
365             *pixel_data++ = pixel >> 8;
366             *pixel_data++ = pixel;
367             break;
368           }
369 	}
370 
371 	pixel_data = (ppixel_data += image->bytes_per_line);
372       }
373 
374       break;
375 
376     case StaticColor:
377     case PseudoColor: {
378 #ifndef   ORDEREDPSEUDO
379       short *terr,
380 	*rerr = new short[width + 2],
381 	*gerr = new short[width + 2],
382 	*berr = new short[width + 2],
383 	*nrerr = new short[width + 2],
384 	*ngerr = new short[width + 2],
385 	*nberr = new short[width + 2];
386       int rr, gg, bb, rer, ger, ber;
387       int dd = 255 / control->getColorsPerChannel();
388 
389       for (x = 0; x < width; x++) {
390 	*(rerr + x) = *(red + x);
391 	*(gerr + x) = *(green + x);
392 	*(berr + x) = *(blue + x);
393       }
394 
395       *(rerr + x) = *(gerr + x) = *(berr + x) = 0;
396 #endif // ORDEREDPSEUDO
397 
398       for (y = 0, offset = 0; y < height; y++) {
399 #ifdef    ORDEREDPSEUDO
400         dithy = y & 7;
401 
402         for (x = 0; x < width; x++, offset++) {
403           dithx = x & 7;
404 
405           r = red[offset];
406           g = green[offset];
407           b = blue[offset];
408 
409           er = r & (red_bits - 1);
410           eg = g & (green_bits - 1);
411           eb = b & (blue_bits - 1);
412 
413           r = red_table[r];
414           g = green_table[g];
415           b = blue_table[b];
416 
417           if ((dither8[dithy][dithx] < er) && (r < red_table[255])) r++;
418           if ((dither8[dithy][dithx] < eg) && (g < green_table[255])) g++;
419           if ((dither8[dithy][dithx] < eb) && (b < blue_table[255])) b++;
420 
421           pixel = (r * cpccpc) + (g * cpc) + b;
422           *(pixel_data++) = colors[pixel].pixel;
423         }
424 
425         pixel_data = (ppixel_data += image->bytes_per_line);
426       }
427 #else // !ORDEREDPSEUDO
428       if (y < (height - 1)) {
429 	int i = offset + width;
430 	for (x = 0; x < width; x++, i++) {
431 	  *(nrerr + x) = *(red + i);
432 	  *(ngerr + x) = *(green + i);
433 	  *(nberr + x) = *(blue + i);
434 	}
435 
436 	*(nrerr + x) = *(red + (--i));
437 	*(ngerr + x) = *(green + i);
438 	*(nberr + x) = *(blue + i);
439       }
440 
441       for (x = 0; x < width; x++) {
442 	rr = rerr[x];
443 	gg = gerr[x];
444 	bb = berr[x];
445 
446 	if (rr > 255) rr = 255; else if (rr < 0) rr = 0;
447 	if (gg > 255) gg = 255; else if (gg < 0) gg = 0;
448 	if (bb > 255) bb = 255; else if (bb < 0) bb = 0;
449 
450 	r = red_table[rr];
451 	g = green_table[gg];
452 	b = blue_table[bb];
453 
454 	rer = rerr[x] - r*dd;
455 	ger = gerr[x] - g*dd;
456 	ber = berr[x] - b*dd;
457 
458 	pixel = (r * cpccpc) + (g * cpc) + b;
459 	*pixel_data++ = colors[pixel].pixel;
460 
461 	r = rer >> 1;
462 	g = ger >> 1;
463 	b = ber >> 1;
464 	rerr[x+1] += r;
465 	gerr[x+1] += g;
466 	berr[x+1] += b;
467 	nrerr[x] += r;
468 	ngerr[x] += g;
469 	nberr[x] += b;
470       }
471 
472       offset += width;
473 
474       pixel_data = (ppixel_data += image->bytes_per_line);
475 
476       terr = rerr;
477       rerr = nrerr;
478       nrerr = terr;
479 
480       terr = gerr;
481       gerr = ngerr;
482       ngerr = terr;
483 
484       terr = berr;
485       berr = nberr;
486       nberr = terr;
487     }
488 
489     delete [] rerr;
490     delete [] gerr;
491     delete [] berr;
492     delete [] nrerr;
493     delete [] ngerr;
494     delete [] nberr;
495 #endif // ORDEREDPSUEDO
496 
497     break; }
498 
499     /*
500        case StaticGray:
501        case GrayScale:
502        for (y = 0, offset = 0; y < height; y++) {
503        dithy = y & 0x3;
504 
505        for (x = 0; x < width; x++, offset++) {
506        dithx = x & 0x3;
507 
508        r = *(red + offset);
509        g = *(green + offset);
510        b = *(blue + offset);
511 
512        er = r & 0x7;
513        eg = g & 0x7;
514        eb = b & 0x7;
515 
516        if ((dither[dithy][dithx] < er) && (r < (256 - 8)))
517        r += 8;
518        if ((dither[dithy][dithx] < (eg << 1)) && (g < (256 - 4)))
519        g += 4;
520        if ((dither[dithy][dithx] < eb) && (b < (256 - 8)))
521        b += 8;
522 
523        r = *(red_table + r);
524        g = *(green_table + g);
525        b = *(blue_table + b);
526 
527        g = ((r * 30) + (g * 59) + (b * 11)) / 100;
528        *pixel_data++ = colors[g].pixel;
529        }
530 
531        pixel_data = (ppixel_data += image->bytes_per_line);
532        }
533 
534        break;
535     */
536 
537     default:
538       fprintf(stderr,
539 			 "BImage::renderXImage: unsupported visual\n");
540       delete [] d;
541       XDestroyImage(image);
542       return (XImage *) 0;
543     }
544   } else {
545     switch (control->getVisual()->c_class) {
546     case StaticColor:
547     case PseudoColor:
548       for (y = 0, offset = 0; y < height; y++) {
549         for (x = 0; x < width; x++, offset++) {
550   	  r = red_table[red[offset]];
551           g = green_table[green[offset]];
552 	  b = blue_table[blue[offset]];
553 
554 	  pixel = (r * cpccpc) + (g * cpc) + b;
555 	  *pixel_data++ = colors[pixel].pixel;
556         }
557 
558         pixel_data = (ppixel_data += image->bytes_per_line);
559       }
560 
561       break;
562 
563   case TrueColor:
564     for (y = 0, offset = 0; y < height; y++) {
565       for (x = 0; x < width; x++, offset++) {
566 	r = red_table[red[offset]];
567 	g = green_table[green[offset]];
568 	b = blue_table[blue[offset]];
569 
570 	pixel = (r << red_offset) | (g << green_offset) | (b << blue_offset);
571 
572         switch (o) {
573         case 16: // 16bpp LSB
574           *pixel_data++ = pixel;
575           *pixel_data++ = pixel >> 8;
576           break;
577 
578         case 17: // 16bpp MSB
579           *pixel_data++ = pixel >> 8;
580           *pixel_data++ = pixel;
581           break;
582 
583         case 24: // 24bpp LSB
584           *pixel_data++ = pixel;
585           *pixel_data++ = pixel >> 8;
586           *pixel_data++ = pixel >> 16;
587           break;
588 
589         case 25: // 24bpp MSB
590           *pixel_data++ = pixel >> 16;
591           *pixel_data++ = pixel >> 8;
592           *pixel_data++ = pixel;
593           break;
594 
595         case 32: // 32bpp LSB
596           *pixel_data++ = pixel;
597           *pixel_data++ = pixel >> 8;
598           *pixel_data++ = pixel >> 16;
599           *pixel_data++ = pixel >> 24;
600           break;
601 
602         case 33: // 32bpp MSB
603           *pixel_data++ = pixel >> 24;
604           *pixel_data++ = pixel >> 16;
605           *pixel_data++ = pixel >> 8;
606           *pixel_data++ = pixel;
607           break;
608         }
609       }
610 
611       pixel_data = (ppixel_data += image->bytes_per_line);
612     }
613 
614     break;
615 
616   case StaticGray:
617   case GrayScale:
618     for (y = 0, offset = 0; y < height; y++) {
619       for (x = 0; x < width; x++, offset++) {
620 	r = *(red_table + *(red + offset));
621 	g = *(green_table + *(green + offset));
622 	b = *(blue_table + *(blue + offset));
623 
624 	g = ((r * 30) + (g * 59) + (b * 11)) / 100;
625 	*pixel_data++ = colors[g].pixel;
626       }
627 
628       pixel_data = (ppixel_data += image->bytes_per_line);
629     }
630 
631     break;
632 
633   default:
634     fprintf(stderr,
635 		       "BImage::renderXImage: unsupported visual\n");
636     delete [] d;
637     XDestroyImage(image);
638     return (XImage *) 0;
639   }
640 }
641 
642   image->data = (char *) d;
643   return image;
644 }
645 
646 
renderPixmap(void)647 Pixmap BImage::renderPixmap(void) {
648     Pixmap pixmap =
649     XCreatePixmap(control->getBaseDisplay()->getXDisplay(),
650                   control->getDrawable(), width, height,
651                   /*24*/control->getDepth());
652 
653 
654     if (pixmap == None) {
655         fprintf(stderr,
656 	              "BImage::renderPixmap: error creating pixmap\n");
657         return None;
658     }
659 #ifdef DEBUG
660     fprintf(stderr,"Pixmap drawable: %X\n",control->getDrawable());
661     fprintf(stderr,"width: %d, height: %d\n",width,height);
662     fprintf(stderr,"depth: %d\n",control->getDepth());
663 #endif
664   XImage *image = renderXImage();
665 
666   if (! image) {
667     XFreePixmap(control->getBaseDisplay()->getXDisplay(), pixmap);
668     return None;
669   } else if (! image->data) {
670     XDestroyImage(image);
671     XFreePixmap(control->getBaseDisplay()->getXDisplay(), pixmap);
672     return None;
673   }
674 #if DEBUG>=2
675   fprintf(stderr,"Attempting XPutImage...\n");
676   fprintf(stderr,"Display: %X\n",control->getBaseDisplay()->getXDisplay());
677   fprintf(stderr,"pixmap: %X\n",pixmap);
678   fprintf(stderr,"GC: %X\n",DefaultGC(control->getBaseDisplay()->getXDisplay(),                             control->getScreenInfo()->getScreenNumber()));
679   fprintf(stderr,"image: %X\n",image);
680   fprintf(stderr,"width: %d\n",width);
681   fprintf(stderr,"height: %d\n",height);
682 //  return pixmap;
683 #endif
684   XPutImage(control->getBaseDisplay()->getXDisplay(), pixmap,
685 	    DefaultGC(control->getBaseDisplay()->getXDisplay(),
686 		      control->getScreenInfo()->getScreenNumber()),
687             image, 0, 0, 0, 0, width, height);
688 
689   if (image->data) {
690     delete [] image->data;
691     image->data = NULL;
692   }
693 
694   XDestroyImage(image);
695 
696   return pixmap;
697 }
698 
699 
bevel1(void)700 void BImage::bevel1(void) {
701   if (width > 2 && height > 2) {
702     unsigned char *pr = red, *pg = green, *pb = blue;
703 
704     register unsigned char r, g, b, rr ,gg ,bb;
705     register unsigned int w = width, h = height - 1, wh = w * h;
706 
707     while (--w) {
708       r = *pr;
709       rr = r + (r >> 1);
710       if (rr < r) rr = ~0;
711       g = *pg;
712       gg = g + (g >> 1);
713       if (gg < g) gg = ~0;
714       b = *pb;
715       bb = b + (b >> 1);
716       if (bb < b) bb = ~0;
717 
718       *pr = rr;
719       *pg = gg;
720       *pb = bb;
721 
722       r = *(pr + wh);
723       rr = (r >> 2) + (r >> 1);
724       if (rr > r) rr = 0;
725       g = *(pg + wh);
726       gg = (g >> 2) + (g >> 1);
727       if (gg > g) gg = 0;
728       b = *(pb + wh);
729       bb = (b >> 2) + (b >> 1);
730       if (bb > b) bb = 0;
731 
732       *((pr++) + wh) = rr;
733       *((pg++) + wh) = gg;
734       *((pb++) + wh) = bb;
735     }
736 
737     r = *pr;
738     rr = r + (r >> 1);
739     if (rr < r) rr = ~0;
740     g = *pg;
741     gg = g + (g >> 1);
742     if (gg < g) gg = ~0;
743     b = *pb;
744     bb = b + (b >> 1);
745     if (bb < b) bb = ~0;
746 
747     *pr = rr;
748     *pg = gg;
749     *pb = bb;
750 
751     r = *(pr + wh);
752     rr = (r >> 2) + (r >> 1);
753     if (rr > r) rr = 0;
754     g = *(pg + wh);
755     gg = (g >> 2) + (g >> 1);
756     if (gg > g) gg = 0;
757     b = *(pb + wh);
758     bb = (b >> 2) + (b >> 1);
759     if (bb > b) bb = 0;
760 
761     *(pr + wh) = rr;
762     *(pg + wh) = gg;
763     *(pb + wh) = bb;
764 
765     pr = red + width;
766     pg = green + width;
767     pb = blue + width;
768 
769     while (--h) {
770       r = *pr;
771       rr = r + (r >> 1);
772       if (rr < r) rr = ~0;
773       g = *pg;
774       gg = g + (g >> 1);
775       if (gg < g) gg = ~0;
776       b = *pb;
777       bb = b + (b >> 1);
778       if (bb < b) bb = ~0;
779 
780       *pr = rr;
781       *pg = gg;
782       *pb = bb;
783 
784       pr += width - 1;
785       pg += width - 1;
786       pb += width - 1;
787 
788       r = *pr;
789       rr = (r >> 2) + (r >> 1);
790       if (rr > r) rr = 0;
791       g = *pg;
792       gg = (g >> 2) + (g >> 1);
793       if (gg > g) gg = 0;
794       b = *pb;
795       bb = (b >> 2) + (b >> 1);
796       if (bb > b) bb = 0;
797 
798       *(pr++) = rr;
799       *(pg++) = gg;
800       *(pb++) = bb;
801     }
802 
803     r = *pr;
804     rr = r + (r >> 1);
805     if (rr < r) rr = ~0;
806     g = *pg;
807     gg = g + (g >> 1);
808     if (gg < g) gg = ~0;
809     b = *pb;
810     bb = b + (b >> 1);
811     if (bb < b) bb = ~0;
812 
813     *pr = rr;
814     *pg = gg;
815     *pb = bb;
816 
817     pr += width - 1;
818     pg += width - 1;
819     pb += width - 1;
820 
821     r = *pr;
822     rr = (r >> 2) + (r >> 1);
823     if (rr > r) rr = 0;
824     g = *pg;
825     gg = (g >> 2) + (g >> 1);
826     if (gg > g) gg = 0;
827     b = *pb;
828     bb = (b >> 2) + (b >> 1);
829     if (bb > b) bb = 0;
830 
831     *pr = rr;
832     *pg = gg;
833     *pb = bb;
834   }
835 }
836 
837 
bevel2(void)838 void BImage::bevel2(void) {
839   if (width > 4 && height > 4) {
840     unsigned char r, g, b, rr ,gg ,bb, *pr = red + width + 1,
841       *pg = green + width + 1, *pb = blue + width + 1;
842     unsigned int w = width - 2, h = height - 1, wh = width * (height - 3);
843 
844     while (--w) {
845       r = *pr;
846       rr = r + (r >> 1);
847       if (rr < r) rr = ~0;
848       g = *pg;
849       gg = g + (g >> 1);
850       if (gg < g) gg = ~0;
851       b = *pb;
852       bb = b + (b >> 1);
853       if (bb < b) bb = ~0;
854 
855       *pr = rr;
856       *pg = gg;
857       *pb = bb;
858 
859       r = *(pr + wh);
860       rr = (r >> 2) + (r >> 1);
861       if (rr > r) rr = 0;
862       g = *(pg + wh);
863       gg = (g >> 2) + (g >> 1);
864       if (gg > g) gg = 0;
865       b = *(pb + wh);
866       bb = (b >> 2) + (b >> 1);
867       if (bb > b) bb = 0;
868 
869       *((pr++) + wh) = rr;
870       *((pg++) + wh) = gg;
871       *((pb++) + wh) = bb;
872     }
873 
874     pr = red + width;
875     pg = green + width;
876     pb = blue + width;
877 
878     while (--h) {
879       r = *pr;
880       rr = r + (r >> 1);
881       if (rr < r) rr = ~0;
882       g = *pg;
883       gg = g + (g >> 1);
884       if (gg < g) gg = ~0;
885       b = *pb;
886       bb = b + (b >> 1);
887       if (bb < b) bb = ~0;
888 
889       *(++pr) = rr;
890       *(++pg) = gg;
891       *(++pb) = bb;
892 
893       pr += width - 3;
894       pg += width - 3;
895       pb += width - 3;
896 
897       r = *pr;
898       rr = (r >> 2) + (r >> 1);
899       if (rr > r) rr = 0;
900       g = *pg;
901       gg = (g >> 2) + (g >> 1);
902       if (gg > g) gg = 0;
903       b = *pb;
904       bb = (b >> 2) + (b >> 1);
905       if (bb > b) bb = 0;
906 
907       *(pr++) = rr;
908       *(pg++) = gg;
909       *(pb++) = bb;
910 
911       pr++; pg++; pb++;
912     }
913   }
914 }
915 
916 
invert(void)917 void BImage::invert(void) {
918   register unsigned int i, j, wh = (width * height) - 1;
919   unsigned char tmp;
920 
921   for (i = 0, j = wh; j > i; j--, i++) {
922     tmp = *(red + j);
923     *(red + j) = *(red + i);
924     *(red + i) = tmp;
925 
926     tmp = *(green + j);
927     *(green + j) = *(green + i);
928     *(green + i) = tmp;
929 
930     tmp = *(blue + j);
931     *(blue + j) = *(blue + i);
932     *(blue + i) = tmp;
933   }
934 }
935 
936 
dgradient(void)937 void BImage::dgradient(void) {
938   // diagonal gradient code was written by Mike Cole <mike@mydot.com>
939   // modified for interlacing by Brad Hughes
940 
941   float drx, dgx, dbx, dry, dgy, dby, yr = 0.0, yg = 0.0, yb = 0.0,
942     xr = (float) from->getRed(),
943     xg = (float) from->getGreen(),
944     xb = (float) from->getBlue();
945   unsigned char *pr = red, *pg = green, *pb = blue;
946   unsigned int w = width * 2, h = height * 2, *xt = xtable, *yt = ytable;
947 
948   register unsigned int x, y;
949 
950   dry = drx = (float) (to->getRed() - from->getRed());
951   dgy = dgx = (float) (to->getGreen() - from->getGreen());
952   dby = dbx = (float) (to->getBlue() - from->getBlue());
953 
954   // Create X table
955   drx /= w;
956   dgx /= w;
957   dbx /= w;
958 
959   for (x = 0; x < width; x++) {
960     *(xt++) = (unsigned char) (xr);
961     *(xt++) = (unsigned char) (xg);
962     *(xt++) = (unsigned char) (xb);
963 
964     xr += drx;
965     xg += dgx;
966     xb += dbx;
967   }
968 
969   // Create Y table
970   dry /= h;
971   dgy /= h;
972   dby /= h;
973 
974   for (y = 0; y < height; y++) {
975     *(yt++) = ((unsigned char) yr);
976     *(yt++) = ((unsigned char) yg);
977     *(yt++) = ((unsigned char) yb);
978 
979     yr += dry;
980     yg += dgy;
981     yb += dby;
982   }
983 
984   // Combine tables to create gradient
985 
986 #ifdef    INTERLACE
987   if (! interlaced) {
988 #endif // INTERLACE
989 
990     // normal dgradient
991     for (yt = ytable, y = 0; y < height; y++, yt += 3) {
992       for (xt = xtable, x = 0; x < width; x++) {
993         *(pr++) = *(xt++) + *(yt);
994         *(pg++) = *(xt++) + *(yt + 1);
995         *(pb++) = *(xt++) + *(yt + 2);
996       }
997     }
998 
999 #ifdef    INTERLACE
1000   } else {
1001     // faked interlacing effect
1002     unsigned char channel, channel2;
1003 
1004     for (yt = ytable, y = 0; y < height; y++, yt += 3) {
1005       for (xt = xtable, x = 0; x < width; x++) {
1006         if (y & 1) {
1007           channel = *(xt++) + *(yt);
1008           channel2 = (channel >> 1) + (channel >> 2);
1009           if (channel2 > channel) channel2 = 0;
1010           *(pr++) = channel2;
1011 
1012           channel = *(xt++) + *(yt + 1);
1013           channel2 = (channel >> 1) + (channel >> 2);
1014           if (channel2 > channel) channel2 = 0;
1015           *(pg++) = channel2;
1016 
1017           channel = *(xt++) + *(yt + 2);
1018           channel2 = (channel >> 1) + (channel >> 2);
1019           if (channel2 > channel) channel2 = 0;
1020           *(pb++) = channel2;
1021         } else {
1022           channel = *(xt++) + *(yt);
1023           channel2 = channel + (channel >> 3);
1024           if (channel2 < channel) channel2 = ~0;
1025           *(pr++) = channel2;
1026 
1027           channel = *(xt++) + *(yt + 1);
1028           channel2 = channel + (channel >> 3);
1029           if (channel2 < channel) channel2 = ~0;
1030           *(pg++) = channel2;
1031 
1032           channel = *(xt++) + *(yt + 2);
1033           channel2 = channel + (channel >> 3);
1034           if (channel2 < channel) channel2 = ~0;
1035           *(pb++) = channel2;
1036         }
1037       }
1038     }
1039   }
1040 #endif // INTERLACE
1041 
1042 }
1043 
1044 
hgradient(void)1045 void BImage::hgradient(void) {
1046   float drx, dgx, dbx,
1047     xr = (float) from->getRed(),
1048     xg = (float) from->getGreen(),
1049     xb = (float) from->getBlue();
1050   unsigned char *pr = red, *pg = green, *pb = blue;
1051 
1052   register unsigned int x, y;
1053 
1054   drx = (float) (to->getRed() - from->getRed());
1055   dgx = (float) (to->getGreen() - from->getGreen());
1056   dbx = (float) (to->getBlue() - from->getBlue());
1057 
1058   drx /= width;
1059   dgx /= width;
1060   dbx /= width;
1061 
1062 #ifdef    INTERLACE
1063   if (interlaced && height > 2) {
1064     // faked interlacing effect
1065     unsigned char channel, channel2;
1066 
1067     for (x = 0; x < width; x++, pr++, pg++, pb++) {
1068       channel = (unsigned char) xr;
1069       channel2 = (channel >> 1) + (channel >> 2);
1070       if (channel2 > channel) channel2 = 0;
1071       *pr = channel2;
1072 
1073       channel = (unsigned char) xg;
1074       channel2 = (channel >> 1) + (channel >> 2);
1075       if (channel2 > channel) channel2 = 0;
1076       *pg = channel2;
1077 
1078       channel = (unsigned char) xb;
1079       channel2 = (channel >> 1) + (channel >> 2);
1080       if (channel2 > channel) channel2 = 0;
1081       *pb = channel2;
1082 
1083 
1084       channel = (unsigned char) xr;
1085       channel2 = channel + (channel >> 3);
1086       if (channel2 < channel) channel2 = ~0;
1087       *(pr + width) = channel2;
1088 
1089       channel = (unsigned char) xg;
1090       channel2 = channel + (channel >> 3);
1091       if (channel2 < channel) channel2 = ~0;
1092       *(pg + width) = channel2;
1093 
1094       channel = (unsigned char) xb;
1095       channel2 = channel + (channel >> 3);
1096       if (channel2 < channel) channel2 = ~0;
1097       *(pb + width) = channel2;
1098 
1099       xr += drx;
1100       xg += dgx;
1101       xb += dbx;
1102     }
1103 
1104     pr += width;
1105     pg += width;
1106     pb += width;
1107 
1108     int offset;
1109 
1110     for (y = 2; y < height; y++, pr += width, pg += width, pb += width) {
1111       if (y & 1) offset = width; else offset = 0;
1112 
1113       memcpy(pr, (red + offset), width);
1114       memcpy(pg, (green + offset), width);
1115       memcpy(pb, (blue + offset), width);
1116     }
1117   } else {
1118 #endif // INTERLACE
1119 
1120     // normal hgradient
1121     for (x = 0; x < width; x++) {
1122       *(pr++) = (unsigned char) (xr);
1123       *(pg++) = (unsigned char) (xg);
1124       *(pb++) = (unsigned char) (xb);
1125 
1126       xr += drx;
1127       xg += dgx;
1128       xb += dbx;
1129     }
1130 
1131     for (y = 1; y < height; y++, pr += width, pg += width, pb += width) {
1132       memcpy(pr, red, width);
1133       memcpy(pg, green, width);
1134       memcpy(pb, blue, width);
1135     }
1136 
1137 #ifdef    INTERLACE
1138   }
1139 #endif // INTERLACE
1140 
1141 }
1142 
1143 
vgradient(void)1144 void BImage::vgradient(void) {
1145   float dry, dgy, dby,
1146     yr = (float) from->getRed(),
1147     yg = (float) from->getGreen(),
1148     yb = (float) from->getBlue();
1149   unsigned char *pr = red, *pg = green, *pb = blue;
1150 
1151   register unsigned int y;
1152 
1153   dry = (float) (to->getRed() - from->getRed());
1154   dgy = (float) (to->getGreen() - from->getGreen());
1155   dby = (float) (to->getBlue() - from->getBlue());
1156 
1157   dry /= height;
1158   dgy /= height;
1159   dby /= height;
1160 
1161 #ifdef    INTERLACE
1162   if (interlaced) {
1163     // faked interlacing effect
1164     unsigned char channel, channel2;
1165 
1166     for (y = 0; y < height; y++, pr += width, pg += width, pb += width) {
1167       if (y & 1) {
1168         channel = (unsigned char) yr;
1169         channel2 = (channel >> 1) + (channel >> 2);
1170         if (channel2 > channel) channel2 = 0;
1171         memset(pr, channel2, width);
1172 
1173         channel = (unsigned char) yg;
1174         channel2 = (channel >> 1) + (channel >> 2);
1175         if (channel2 > channel) channel2 = 0;
1176         memset(pg, channel2, width);
1177 
1178         channel = (unsigned char) yb;
1179         channel2 = (channel >> 1) + (channel >> 2);
1180         if (channel2 > channel) channel2 = 0;
1181         memset(pb, channel2, width);
1182       } else {
1183         channel = (unsigned char) yr;
1184         channel2 = channel + (channel >> 3);
1185         if (channel2 < channel) channel2 = ~0;
1186         memset(pr, channel2, width);
1187 
1188         channel = (unsigned char) yg;
1189         channel2 = channel + (channel >> 3);
1190         if (channel2 < channel) channel2 = ~0;
1191         memset(pg, channel2, width);
1192 
1193         channel = (unsigned char) yb;
1194         channel2 = channel + (channel >> 3);
1195         if (channel2 < channel) channel2 = ~0;
1196         memset(pb, channel2, width);
1197       }
1198 
1199       yr += dry;
1200       yg += dgy;
1201       yb += dby;
1202     }
1203   } else {
1204 #endif // INTERLACE
1205 
1206     // normal vgradient
1207     for (y = 0; y < height; y++, pr += width, pg += width, pb += width) {
1208       memset(pr, (unsigned char) yr, width);
1209       memset(pg, (unsigned char) yg, width);
1210       memset(pb, (unsigned char) yb, width);
1211 
1212       yr += dry;
1213       yg += dgy;
1214       yb += dby;
1215     }
1216 
1217 #ifdef    INTERLACE
1218   }
1219 #endif // INTERLACE
1220 
1221 }
1222 
1223 
pgradient(void)1224 void BImage::pgradient(void) {
1225   // pyramid gradient -  based on original dgradient, written by
1226   // Mosfet (mosfet@kde.org)
1227   // adapted from kde sources for Blackbox by Brad Hughes
1228 
1229   float yr, yg, yb, drx, dgx, dbx, dry, dgy, dby,
1230     xr, xg, xb;
1231   int rsign, gsign, bsign;
1232   unsigned char *pr = red, *pg = green, *pb = blue;
1233   unsigned int tr = to->getRed(), tg = to->getGreen(), tb = to->getBlue(),
1234     *xt = xtable, *yt = ytable;
1235 
1236   register unsigned int x, y;
1237 
1238   dry = drx = (float) (to->getRed() - from->getRed());
1239   dgy = dgx = (float) (to->getGreen() - from->getGreen());
1240   dby = dbx = (float) (to->getBlue() - from->getBlue());
1241 
1242   rsign = (drx < 0) ? -1 : 1;
1243   gsign = (dgx < 0) ? -1 : 1;
1244   bsign = (dbx < 0) ? -1 : 1;
1245 
1246   xr = yr = (drx / 2);
1247   xg = yg = (dgx / 2);
1248   xb = yb = (dbx / 2);
1249 
1250   // Create X table
1251   drx /= width;
1252   dgx /= width;
1253   dbx /= width;
1254 
1255   for (x = 0; x < width; x++) {
1256     *(xt++) = (unsigned char) ((xr < 0) ? -xr : xr);
1257     *(xt++) = (unsigned char) ((xg < 0) ? -xg : xg);
1258     *(xt++) = (unsigned char) ((xb < 0) ? -xb : xb);
1259 
1260     xr -= drx;
1261     xg -= dgx;
1262     xb -= dbx;
1263   }
1264 
1265   // Create Y table
1266   dry /= height;
1267   dgy /= height;
1268   dby /= height;
1269 
1270   for (y = 0; y < height; y++) {
1271     *(yt++) = ((unsigned char) ((yr < 0) ? -yr : yr));
1272     *(yt++) = ((unsigned char) ((yg < 0) ? -yg : yg));
1273     *(yt++) = ((unsigned char) ((yb < 0) ? -yb : yb));
1274 
1275     yr -= dry;
1276     yg -= dgy;
1277     yb -= dby;
1278   }
1279 
1280   // Combine tables to create gradient
1281 
1282 #ifdef    INTERLACE
1283   if (! interlaced) {
1284 #endif // INTERLACE
1285 
1286     // normal pgradient
1287     for (yt = ytable, y = 0; y < height; y++, yt += 3) {
1288       for (xt = xtable, x = 0; x < width; x++) {
1289         *(pr++) = (unsigned char) (tr - (rsign * (*(xt++) + *(yt))));
1290         *(pg++) = (unsigned char) (tg - (gsign * (*(xt++) + *(yt + 1))));
1291         *(pb++) = (unsigned char) (tb - (bsign * (*(xt++) + *(yt + 2))));
1292       }
1293     }
1294 
1295 #ifdef    INTERLACE
1296   } else {
1297     // faked interlacing effect
1298     unsigned char channel, channel2;
1299 
1300     for (yt = ytable, y = 0; y < height; y++, yt += 3) {
1301       for (xt = xtable, x = 0; x < width; x++) {
1302         if (y & 1) {
1303           channel = (unsigned char) (tr - (rsign * (*(xt++) + *(yt))));
1304           channel2 = (channel >> 1) + (channel >> 2);
1305           if (channel2 > channel) channel2 = 0;
1306           *(pr++) = channel2;
1307 
1308           channel = (unsigned char) (tg - (gsign * (*(xt++) + *(yt + 1))));
1309           channel2 = (channel >> 1) + (channel >> 2);
1310           if (channel2 > channel) channel2 = 0;
1311           *(pg++) = channel2;
1312 
1313           channel = (unsigned char) (tb - (bsign * (*(xt++) + *(yt + 2))));
1314           channel2 = (channel >> 1) + (channel >> 2);
1315           if (channel2 > channel) channel2 = 0;
1316           *(pb++) = channel2;
1317         } else {
1318           channel = (unsigned char) (tr - (rsign * (*(xt++) + *(yt))));
1319           channel2 = channel + (channel >> 3);
1320           if (channel2 < channel) channel2 = ~0;
1321           *(pr++) = channel2;
1322 
1323           channel = (unsigned char) (tg - (gsign * (*(xt++) + *(yt + 1))));
1324           channel2 = channel + (channel >> 3);
1325           if (channel2 < channel) channel2 = ~0;
1326           *(pg++) = channel2;
1327 
1328           channel = (unsigned char) (tb - (bsign * (*(xt++) + *(yt + 2))));
1329           channel2 = channel + (channel >> 3);
1330           if (channel2 < channel) channel2 = ~0;
1331           *(pb++) = channel2;
1332         }
1333       }
1334     }
1335   }
1336 #endif // INTERLACE
1337 
1338 }
1339 
1340 
rgradient(void)1341 void BImage::rgradient(void) {
1342   // rectangle gradient -  based on original dgradient, written by
1343   // Mosfet (mosfet@kde.org)
1344   // adapted from kde sources for Blackbox by Brad Hughes
1345 
1346   float drx, dgx, dbx, dry, dgy, dby, xr, xg, xb, yr, yg, yb;
1347   int rsign, gsign, bsign;
1348   unsigned char *pr = red, *pg = green, *pb = blue;
1349   unsigned int tr = to->getRed(), tg = to->getGreen(), tb = to->getBlue(),
1350     *xt = xtable, *yt = ytable;
1351 
1352   register unsigned int x, y;
1353 
1354   dry = drx = (float) (to->getRed() - from->getRed());
1355   dgy = dgx = (float) (to->getGreen() - from->getGreen());
1356   dby = dbx = (float) (to->getBlue() - from->getBlue());
1357 
1358   rsign = (drx < 0) ? -2 : 2;
1359   gsign = (dgx < 0) ? -2 : 2;
1360   bsign = (dbx < 0) ? -2 : 2;
1361 
1362   xr = yr = (drx / 2);
1363   xg = yg = (dgx / 2);
1364   xb = yb = (dbx / 2);
1365 
1366   // Create X table
1367   drx /= width;
1368   dgx /= width;
1369   dbx /= width;
1370 
1371   for (x = 0; x < width; x++) {
1372     *(xt++) = (unsigned char) ((xr < 0) ? -xr : xr);
1373     *(xt++) = (unsigned char) ((xg < 0) ? -xg : xg);
1374     *(xt++) = (unsigned char) ((xb < 0) ? -xb : xb);
1375 
1376     xr -= drx;
1377     xg -= dgx;
1378     xb -= dbx;
1379   }
1380 
1381   // Create Y table
1382   dry /= height;
1383   dgy /= height;
1384   dby /= height;
1385 
1386   for (y = 0; y < height; y++) {
1387     *(yt++) = ((unsigned char) ((yr < 0) ? -yr : yr));
1388     *(yt++) = ((unsigned char) ((yg < 0) ? -yg : yg));
1389     *(yt++) = ((unsigned char) ((yb < 0) ? -yb : yb));
1390 
1391     yr -= dry;
1392     yg -= dgy;
1393     yb -= dby;
1394   }
1395 
1396   // Combine tables to create gradient
1397 
1398 #ifdef    INTERLACE
1399   if (! interlaced) {
1400 #endif // INTERLACE
1401 
1402     // normal rgradient
1403     for (yt = ytable, y = 0; y < height; y++, yt += 3) {
1404       for (xt = xtable, x = 0; x < width; x++) {
1405         *(pr++) = (unsigned char) (tr - (rsign * max(*(xt++), *(yt))));
1406         *(pg++) = (unsigned char) (tg - (gsign * max(*(xt++), *(yt + 1))));
1407         *(pb++) = (unsigned char) (tb - (bsign * max(*(xt++), *(yt + 2))));
1408       }
1409     }
1410 
1411 #ifdef    INTERLACE
1412   } else {
1413     // faked interlacing effect
1414     unsigned char channel, channel2;
1415 
1416     for (yt = ytable, y = 0; y < height; y++, yt += 3) {
1417       for (xt = xtable, x = 0; x < width; x++) {
1418         if (y & 1) {
1419           channel = (unsigned char) (tr - (rsign * max(*(xt++), *(yt))));
1420           channel2 = (channel >> 1) + (channel >> 2);
1421           if (channel2 > channel) channel2 = 0;
1422           *(pr++) = channel2;
1423 
1424           channel = (unsigned char) (tg - (gsign * max(*(xt++), *(yt + 1))));
1425           channel2 = (channel >> 1) + (channel >> 2);
1426           if (channel2 > channel) channel2 = 0;
1427           *(pg++) = channel2;
1428 
1429           channel = (unsigned char) (tb - (bsign * max(*(xt++), *(yt + 2))));
1430           channel2 = (channel >> 1) + (channel >> 2);
1431           if (channel2 > channel) channel2 = 0;
1432           *(pb++) = channel2;
1433         } else {
1434           channel = (unsigned char) (tr - (rsign * max(*(xt++), *(yt))));
1435           channel2 = channel + (channel >> 3);
1436           if (channel2 < channel) channel2 = ~0;
1437           *(pr++) = channel2;
1438 
1439           channel = (unsigned char) (tg - (gsign * max(*(xt++), *(yt + 1))));
1440           channel2 = channel + (channel >> 3);
1441           if (channel2 < channel) channel2 = ~0;
1442           *(pg++) = channel2;
1443 
1444           channel = (unsigned char) (tb - (bsign * max(*(xt++), *(yt + 2))));
1445           channel2 = channel + (channel >> 3);
1446           if (channel2 < channel) channel2 = ~0;
1447           *(pb++) = channel2;
1448         }
1449       }
1450     }
1451   }
1452 #endif // INTERLACE
1453 
1454 }
1455 
1456 
egradient(void)1457 void BImage::egradient(void) {
1458   // elliptic gradient -  based on original dgradient, written by
1459   // Mosfet (mosfet@kde.org)
1460   // adapted from kde sources for Blackbox by Brad Hughes
1461 
1462   float drx, dgx, dbx, dry, dgy, dby, yr, yg, yb, xr, xg, xb;
1463   int rsign, gsign, bsign;
1464   unsigned char *pr = red, *pg = green, *pb = blue;
1465   unsigned int *xt = xtable, *yt = ytable,
1466     tr = (unsigned long) to->getRed(),
1467     tg = (unsigned long) to->getGreen(),
1468     tb = (unsigned long) to->getBlue();
1469 
1470   register unsigned int x, y;
1471 
1472   dry = drx = (float) (to->getRed() - from->getRed());
1473   dgy = dgx = (float) (to->getGreen() - from->getGreen());
1474   dby = dbx = (float) (to->getBlue() - from->getBlue());
1475 
1476   rsign = (drx < 0) ? -1 : 1;
1477   gsign = (dgx < 0) ? -1 : 1;
1478   bsign = (dbx < 0) ? -1 : 1;
1479 
1480   xr = yr = (drx / 2);
1481   xg = yg = (dgx / 2);
1482   xb = yb = (dbx / 2);
1483 
1484   // Create X table
1485   drx /= width;
1486   dgx /= width;
1487   dbx /= width;
1488 
1489   for (x = 0; x < width; x++) {
1490     *(xt++) = (unsigned long) (xr * xr);
1491     *(xt++) = (unsigned long) (xg * xg);
1492     *(xt++) = (unsigned long) (xb * xb);
1493 
1494     xr -= drx;
1495     xg -= dgx;
1496     xb -= dbx;
1497   }
1498 
1499   // Create Y table
1500   dry /= height;
1501   dgy /= height;
1502   dby /= height;
1503 
1504   for (y = 0; y < height; y++) {
1505     *(yt++) = (unsigned long) (yr * yr);
1506     *(yt++) = (unsigned long) (yg * yg);
1507     *(yt++) = (unsigned long) (yb * yb);
1508 
1509     yr -= dry;
1510     yg -= dgy;
1511     yb -= dby;
1512   }
1513 
1514   // Combine tables to create gradient
1515 
1516 #ifdef    INTERLACE
1517   if (! interlaced) {
1518 #endif // INTERLACE
1519 
1520     // normal egradient
1521     for (yt = ytable, y = 0; y < height; y++, yt += 3) {
1522       for (xt = xtable, x = 0; x < width; x++) {
1523         *(pr++) = (unsigned char)
1524           (tr - (rsign * control->getSqrt(*(xt++) + *(yt))));
1525         *(pg++) = (unsigned char)
1526           (tg - (gsign * control->getSqrt(*(xt++) + *(yt + 1))));
1527         *(pb++) = (unsigned char)
1528           (tb - (bsign * control->getSqrt(*(xt++) + *(yt + 2))));
1529       }
1530     }
1531 
1532 #ifdef    INTERLACE
1533   } else {
1534     // faked interlacing effect
1535     unsigned char channel, channel2;
1536 
1537     for (yt = ytable, y = 0; y < height; y++, yt += 3) {
1538       for (xt = xtable, x = 0; x < width; x++) {
1539         if (y & 1) {
1540           channel = (unsigned char)
1541             (tr - (rsign * control->getSqrt(*(xt++) + *(yt))));
1542           channel2 = (channel >> 1) + (channel >> 2);
1543           if (channel2 > channel) channel2 = 0;
1544           *(pr++) = channel2;
1545 
1546           channel = (unsigned char)
1547             (tg - (gsign * control->getSqrt(*(xt++) + *(yt + 1))));
1548           channel2 = (channel >> 1) + (channel >> 2);
1549           if (channel2 > channel) channel2 = 0;
1550           *(pg++) = channel2;
1551 
1552           channel = (unsigned char)
1553             (tb - (bsign * control->getSqrt(*(xt++) + *(yt + 2))));
1554           channel2 = (channel >> 1) + (channel >> 2);
1555           if (channel2 > channel) channel2 = 0;
1556           *(pb++) = channel2;
1557         } else {
1558           channel = (unsigned char)
1559             (tr - (rsign * control->getSqrt(*(xt++) + *(yt))));
1560           channel2 = channel + (channel >> 3);
1561           if (channel2 < channel) channel2 = ~0;
1562           *(pr++) = channel2;
1563 
1564           channel = (unsigned char)
1565           (tg - (gsign * control->getSqrt(*(xt++) + *(yt + 1))));
1566           channel2 = channel + (channel >> 3);
1567           if (channel2 < channel) channel2 = ~0;
1568           *(pg++) = channel2;
1569 
1570           channel = (unsigned char)
1571             (tb - (bsign * control->getSqrt(*(xt++) + *(yt + 2))));
1572           channel2 = channel + (channel >> 3);
1573           if (channel2 < channel) channel2 = ~0;
1574           *(pb++) = channel2;
1575         }
1576       }
1577     }
1578   }
1579 #endif // INTERLACE
1580 
1581 }
1582 
1583 
pcgradient(void)1584 void BImage::pcgradient(void) {
1585   // pipe cross gradient -  based on original dgradient, written by
1586   // Mosfet (mosfet@kde.org)
1587   // adapted from kde sources for Blackbox by Brad Hughes
1588 
1589   float drx, dgx, dbx, dry, dgy, dby, xr, xg, xb, yr, yg, yb;
1590   int rsign, gsign, bsign;
1591   unsigned char *pr = red, *pg = green, *pb = blue;
1592   unsigned int *xt = xtable, *yt = ytable,
1593     tr = to->getRed(),
1594     tg = to->getGreen(),
1595     tb = to->getBlue();
1596 
1597   register unsigned int x, y;
1598 
1599   dry = drx = (float) (to->getRed() - from->getRed());
1600   dgy = dgx = (float) (to->getGreen() - from->getGreen());
1601   dby = dbx = (float) (to->getBlue() - from->getBlue());
1602 
1603   rsign = (drx < 0) ? -2 : 2;
1604   gsign = (dgx < 0) ? -2 : 2;
1605   bsign = (dbx < 0) ? -2 : 2;
1606 
1607   xr = yr = (drx / 2);
1608   xg = yg = (dgx / 2);
1609   xb = yb = (dbx / 2);
1610 
1611   // Create X table
1612   drx /= width;
1613   dgx /= width;
1614   dbx /= width;
1615 
1616   for (x = 0; x < width; x++) {
1617     *(xt++) = (unsigned char) ((xr < 0) ? -xr : xr);
1618     *(xt++) = (unsigned char) ((xg < 0) ? -xg : xg);
1619     *(xt++) = (unsigned char) ((xb < 0) ? -xb : xb);
1620 
1621     xr -= drx;
1622     xg -= dgx;
1623     xb -= dbx;
1624   }
1625 
1626   // Create Y table
1627   dry /= height;
1628   dgy /= height;
1629   dby /= height;
1630 
1631   for (y = 0; y < height; y++) {
1632     *(yt++) = ((unsigned char) ((yr < 0) ? -yr : yr));
1633     *(yt++) = ((unsigned char) ((yg < 0) ? -yg : yg));
1634     *(yt++) = ((unsigned char) ((yb < 0) ? -yb : yb));
1635 
1636     yr -= dry;
1637     yg -= dgy;
1638     yb -= dby;
1639   }
1640 
1641   // Combine tables to create gradient
1642 
1643 #ifdef    INTERLACE
1644   if (! interlaced) {
1645 #endif // INTERLACE
1646 
1647     // normal pcgradient
1648     for (yt = ytable, y = 0; y < height; y++, yt += 3) {
1649       for (xt = xtable, x = 0; x < width; x++) {
1650         *(pr++) = (unsigned char) (tr - (rsign * min(*(xt++), *(yt))));
1651         *(pg++) = (unsigned char) (tg - (gsign * min(*(xt++), *(yt + 1))));
1652         *(pb++) = (unsigned char) (tb - (bsign * min(*(xt++), *(yt + 2))));
1653       }
1654     }
1655 
1656 #ifdef    INTERLACE
1657   } else {
1658     // faked interlacing effect
1659     unsigned char channel, channel2;
1660 
1661     for (yt = ytable, y = 0; y < height; y++, yt += 3) {
1662       for (xt = xtable, x = 0; x < width; x++) {
1663         if (y & 1) {
1664           channel = (unsigned char) (tr - (rsign * min(*(xt++), *(yt))));
1665           channel2 = (channel >> 1) + (channel >> 2);
1666           if (channel2 > channel) channel2 = 0;
1667           *(pr++) = channel2;
1668 
1669           channel = (unsigned char) (tg - (bsign * min(*(xt++), *(yt + 1))));
1670           channel2 = (channel >> 1) + (channel >> 2);
1671           if (channel2 > channel) channel2 = 0;
1672           *(pg++) = channel2;
1673 
1674           channel = (unsigned char) (tb - (gsign * min(*(xt++), *(yt + 2))));
1675           channel2 = (channel >> 1) + (channel >> 2);
1676           if (channel2 > channel) channel2 = 0;
1677           *(pb++) = channel2;
1678         } else {
1679           channel = (unsigned char) (tr - (rsign * min(*(xt++), *(yt))));
1680           channel2 = channel + (channel >> 3);
1681           if (channel2 < channel) channel2 = ~0;
1682           *(pr++) = channel2;
1683 
1684           channel = (unsigned char) (tg - (gsign * min(*(xt++), *(yt + 1))));
1685           channel2 = channel + (channel >> 3);
1686           if (channel2 < channel) channel2 = ~0;
1687           *(pg++) = channel2;
1688 
1689           channel = (unsigned char) (tb - (bsign * min(*(xt++), *(yt + 2))));
1690           channel2 = channel + (channel >> 3);
1691           if (channel2 < channel) channel2 = ~0;
1692           *(pb++) = channel2;
1693         }
1694       }
1695     }
1696   }
1697 #endif // INTERLACE
1698 
1699 }
1700 
1701 
cdgradient(void)1702 void BImage::cdgradient(void) {
1703   // cross diagonal gradient -  based on original dgradient, written by
1704   // Mosfet (mosfet@kde.org)
1705   // adapted from kde sources for Blackbox by Brad Hughes
1706 
1707   float drx, dgx, dbx, dry, dgy, dby, yr = 0.0, yg = 0.0, yb = 0.0,
1708     xr = (float) from->getRed(),
1709     xg = (float) from->getGreen(),
1710     xb = (float) from->getBlue();
1711   unsigned char *pr = red, *pg = green, *pb = blue;
1712   unsigned int w = width * 2, h = height * 2, *xt, *yt;
1713 
1714   register unsigned int x, y;
1715 
1716   dry = drx = (float) (to->getRed() - from->getRed());
1717   dgy = dgx = (float) (to->getGreen() - from->getGreen());
1718   dby = dbx = (float) (to->getBlue() - from->getBlue());
1719 
1720   // Create X table
1721   drx /= w;
1722   dgx /= w;
1723   dbx /= w;
1724 
1725   for (xt = (xtable + (width * 3) - 1), x = 0; x < width; x++) {
1726     *(xt--) = (unsigned char) xb;
1727     *(xt--) = (unsigned char) xg;
1728     *(xt--) = (unsigned char) xr;
1729 
1730     xr += drx;
1731     xg += dgx;
1732     xb += dbx;
1733   }
1734 
1735   // Create Y table
1736   dry /= h;
1737   dgy /= h;
1738   dby /= h;
1739 
1740   for (yt = ytable, y = 0; y < height; y++) {
1741     *(yt++) = (unsigned char) yr;
1742     *(yt++) = (unsigned char) yg;
1743     *(yt++) = (unsigned char) yb;
1744 
1745     yr += dry;
1746     yg += dgy;
1747     yb += dby;
1748   }
1749 
1750   // Combine tables to create gradient
1751 
1752 #ifdef    INTERLACE
1753   if (! interlaced) {
1754 #endif // INTERLACE
1755 
1756     // normal cdgradient
1757     for (yt = ytable, y = 0; y < height; y++, yt += 3) {
1758       for (xt = xtable, x = 0; x < width; x++) {
1759         *(pr++) = *(xt++) + *(yt);
1760         *(pg++) = *(xt++) + *(yt + 1);
1761         *(pb++) = *(xt++) + *(yt + 2);
1762       }
1763     }
1764 
1765 #ifdef    INTERLACE
1766   } else {
1767     // faked interlacing effect
1768     unsigned char channel, channel2;
1769 
1770     for (yt = ytable, y = 0; y < height; y++, yt += 3) {
1771       for (xt = xtable, x = 0; x < width; x++) {
1772         if (y & 1) {
1773           channel = *(xt++) + *(yt);
1774           channel2 = (channel >> 1) + (channel >> 2);
1775           if (channel2 > channel) channel2 = 0;
1776           *(pr++) = channel2;
1777 
1778           channel = *(xt++) + *(yt + 1);
1779           channel2 = (channel >> 1) + (channel >> 2);
1780           if (channel2 > channel) channel2 = 0;
1781           *(pg++) = channel2;
1782 
1783           channel = *(xt++) + *(yt + 2);
1784           channel2 = (channel >> 1) + (channel >> 2);
1785           if (channel2 > channel) channel2 = 0;
1786           *(pb++) = channel2;
1787         } else {
1788           channel = *(xt++) + *(yt);
1789           channel2 = channel + (channel >> 3);
1790           if (channel2 < channel) channel2 = ~0;
1791           *(pr++) = channel2;
1792 
1793           channel = *(xt++) + *(yt + 1);
1794           channel2 = channel + (channel >> 3);
1795           if (channel2 < channel) channel2 = ~0;
1796           *(pg++) = channel2;
1797 
1798           channel = *(xt++) + *(yt + 2);
1799           channel2 = channel + (channel >> 3);
1800           if (channel2 < channel) channel2 = ~0;
1801           *(pb++) = channel2;
1802         }
1803       }
1804     }
1805   }
1806 #endif // INTERLACE
1807 
1808 }
1809 
1810 
BImageControl(BaseDisplay * dpy,ScreenInfo * scrn,Bool _dither,int _cpc,unsigned long cache_timeout,unsigned long cmax)1811 BImageControl::BImageControl(BaseDisplay *dpy, ScreenInfo *scrn, Bool _dither,
1812                              int _cpc, unsigned long cache_timeout,
1813                              unsigned long cmax)
1814 {
1815   basedisplay = dpy;
1816   screeninfo = scrn;
1817   setDither(_dither);
1818   setColorsPerChannel(_cpc);
1819 
1820   cache_max = cmax;
1821 #ifdef    TIMEDCACHE
1822   if (cache_timeout) {
1823     timer = new BTimer(basedisplay, this);
1824     timer->setTimeout(cache_timeout);
1825     timer->start();
1826   } else
1827     timer = (BTimer *) 0;
1828 #endif // TIMEDCACHE
1829 
1830   colors = (XColor *) 0;
1831   ncolors = 0;
1832 
1833   grad_xbuffer = grad_ybuffer = (unsigned int *) 0;
1834   grad_buffer_width = grad_buffer_height = 0;
1835 
1836   sqrt_table = (unsigned long *) 0;
1837 
1838   screen_depth = screeninfo->getDepth();
1839   window = screeninfo->getRootWindow();
1840   screen_number = screeninfo->getScreenNumber();
1841 
1842   int count;
1843   XPixmapFormatValues *pmv = XListPixmapFormats(basedisplay->getXDisplay(),
1844                                                 &count);
1845   root_colormap = DefaultColormap(basedisplay->getXDisplay(), screen_number);
1846 
1847   if (pmv) {
1848     bits_per_pixel = 0;
1849     for (int i = 0; i < count; i++)
1850       if (pmv[i].depth == screen_depth) {
1851 	bits_per_pixel = pmv[i].bits_per_pixel;
1852 	break;
1853       }
1854 
1855     XFree(pmv);
1856   }
1857 
1858   if (bits_per_pixel == 0) bits_per_pixel = screen_depth;
1859   if (bits_per_pixel >= 24) setDither(False);
1860 
1861   red_offset = green_offset = blue_offset = 0;
1862 
1863   switch (getVisual()->c_class) {
1864   case TrueColor:
1865     {
1866       int i;
1867 
1868       // compute color tables
1869       unsigned long red_mask = getVisual()->red_mask,
1870         green_mask = getVisual()->green_mask,
1871         blue_mask = getVisual()->blue_mask;
1872 
1873       while (! (red_mask & 1)) { red_offset++; red_mask >>= 1; }
1874       while (! (green_mask & 1)) { green_offset++; green_mask >>= 1; }
1875       while (! (blue_mask & 1)) { blue_offset++; blue_mask >>= 1; }
1876 
1877       red_bits = 255 / red_mask;
1878       green_bits = 255 / green_mask;
1879       blue_bits = 255 / blue_mask;
1880 
1881       for (i = 0; i < 256; i++) {
1882 	red_color_table[i] = i / red_bits;
1883         green_color_table[i] = i / green_bits;
1884         blue_color_table[i] = i / blue_bits;
1885       }
1886     }
1887 
1888     break;
1889 
1890   case PseudoColor:
1891   case StaticColor:
1892     {
1893       ncolors = colors_per_channel * colors_per_channel * colors_per_channel;
1894 
1895       if (ncolors > (1 << screen_depth)) {
1896 	colors_per_channel = (1 << screen_depth) / 3;
1897 	ncolors = colors_per_channel * colors_per_channel * colors_per_channel;
1898       }
1899 
1900       if (colors_per_channel < 2 || ncolors > (1 << screen_depth)) {
1901 	fprintf(stderr,
1902                            "BImageControl::BImageControl: invalid colormap size %d "
1903 		           "(%d/%d/%d) - reducing",
1904                 ncolors, colors_per_channel, colors_per_channel,
1905                 colors_per_channel);
1906 
1907         colors_per_channel = (1 << screen_depth) / 3;
1908       }
1909 
1910       colors = new XColor[ncolors];
1911       if (! colors) {
1912 	fprintf(stderr,
1913 	        	   "BImageControl::BImageControl: error allocating "
1914 		           "colormap\n");
1915 	exit(1);
1916       }
1917 
1918       int i = 0, ii, p, r, g, b,
1919 
1920 #ifdef    ORDEREDPSEUDO
1921         bits = 256 / colors_per_channel;
1922 #else // !ORDEREDPSEUDO
1923         bits = 255 / (colors_per_channel - 1);
1924 #endif // ORDEREDPSEUDO
1925 
1926       red_bits = green_bits = blue_bits = bits;
1927 
1928       for (i = 0; i < 256; i++)
1929 	red_color_table[i] = green_color_table[i] = blue_color_table[i] =
1930 	  i / bits;
1931 
1932       for (r = 0, i = 0; r < colors_per_channel; r++)
1933 	for (g = 0; g < colors_per_channel; g++)
1934 	  for (b = 0; b < colors_per_channel; b++, i++) {
1935 	    colors[i].red = (r * 0xffff) / (colors_per_channel - 1);
1936 	    colors[i].green = (g * 0xffff) / (colors_per_channel - 1);
1937 	    colors[i].blue = (b * 0xffff) / (colors_per_channel - 1);;
1938 	    colors[i].flags = DoRed|DoGreen|DoBlue;
1939 	  }
1940 
1941       basedisplay->grab();
1942 
1943       for (i = 0; i < ncolors; i++)
1944 	if (! XAllocColor(basedisplay->getXDisplay(), getColormap(),
1945                           &colors[i])) {
1946 	  fprintf(stderr,
1947 		                   "couldn't alloc color %i %i %i\n",
1948 		  colors[i].red, colors[i].green, colors[i].blue);
1949 	  colors[i].flags = 0;
1950 	} else
1951 	  colors[i].flags = DoRed|DoGreen|DoBlue;
1952 
1953       basedisplay->ungrab();
1954 
1955       XColor icolors[256];
1956       int incolors = (((1 << screen_depth) > 256) ? 256 : (1 << screen_depth));
1957 
1958       for (i = 0; i < incolors; i++)
1959 	icolors[i].pixel = i;
1960 
1961       XQueryColors(basedisplay->getXDisplay(), getColormap(), icolors,
1962                    incolors);
1963       for (i = 0; i < ncolors; i++) {
1964 	if (! colors[i].flags) {
1965 	  unsigned long chk = 0xffffffff, pixel, close = 0;
1966 
1967 	  p = 2;
1968 	  while (p--) {
1969 	    for (ii = 0; ii < incolors; ii++) {
1970 	      r = (colors[i].red - icolors[i].red) >> 8;
1971 	      g = (colors[i].green - icolors[i].green) >> 8;
1972 	      b = (colors[i].blue - icolors[i].blue) >> 8;
1973 	      pixel = (r * r) + (g * g) + (b * b);
1974 
1975 	      if (pixel < chk) {
1976 		chk = pixel;
1977 		close = ii;
1978 	      }
1979 
1980 	      colors[i].red = icolors[close].red;
1981 	      colors[i].green = icolors[close].green;
1982 	      colors[i].blue = icolors[close].blue;
1983 
1984 	      if (XAllocColor(basedisplay->getXDisplay(), getColormap(),
1985                               &colors[i])) {
1986 		colors[i].flags = DoRed|DoGreen|DoBlue;
1987 		break;
1988 	      }
1989 	    }
1990 	  }
1991 	}
1992       }
1993 
1994       break;
1995     }
1996 
1997   case GrayScale:
1998   case StaticGray:
1999     {
2000 
2001       if (getVisual()->c_class == StaticGray) {
2002 	ncolors = 1 << screen_depth;
2003       } else {
2004 	ncolors = colors_per_channel * colors_per_channel * colors_per_channel;
2005 
2006 	if (ncolors > (1 << screen_depth)) {
2007 	  colors_per_channel = (1 << screen_depth) / 3;
2008 	  ncolors =
2009 	    colors_per_channel * colors_per_channel * colors_per_channel;
2010 	}
2011       }
2012 
2013       if (colors_per_channel < 2 || ncolors > (1 << screen_depth)) {
2014 	fprintf(stderr,
2015                            "BImageControl::BImageControl: invalid colormap size %d "
2016 		           "(%d/%d/%d) - reducing",
2017 		ncolors, colors_per_channel, colors_per_channel,
2018 		colors_per_channel);
2019 
2020 	colors_per_channel = (1 << screen_depth) / 3;
2021       }
2022 
2023       colors = new XColor[ncolors];
2024       if (! colors) {
2025 	fprintf(stderr,
2026 			   "BImageControl::BImageControl: error allocating "
2027        	                   "colormap\n");
2028 	exit(1);
2029       }
2030 
2031       int i = 0, ii, p, bits = 255 / (colors_per_channel - 1);
2032       red_bits = green_bits = blue_bits = bits;
2033 
2034       for (i = 0; i < 256; i++)
2035 	red_color_table[i] = green_color_table[i] = blue_color_table[i] =
2036 	  i / bits;
2037 
2038       basedisplay->grab();
2039       for (i = 0; i < ncolors; i++) {
2040 	colors[i].red = (i * 0xffff) / (colors_per_channel - 1);
2041 	colors[i].green = (i * 0xffff) / (colors_per_channel - 1);
2042 	colors[i].blue = (i * 0xffff) / (colors_per_channel - 1);;
2043 	colors[i].flags = DoRed|DoGreen|DoBlue;
2044 
2045 	if (! XAllocColor(basedisplay->getXDisplay(), getColormap(),
2046 			  &colors[i])) {
2047 	  fprintf(stderr,
2048 		             "couldn't alloc color %i %i %i\n",
2049 		  colors[i].red, colors[i].green, colors[i].blue);
2050 	  colors[i].flags = 0;
2051 	} else
2052 	  colors[i].flags = DoRed|DoGreen|DoBlue;
2053       }
2054 
2055       basedisplay->ungrab();
2056 
2057       XColor icolors[256];
2058       int incolors = (((1 << screen_depth) > 256) ? 256 :
2059 		      (1 << screen_depth));
2060 
2061       for (i = 0; i < incolors; i++)
2062 	icolors[i].pixel = i;
2063 
2064       XQueryColors(basedisplay->getXDisplay(), getColormap(), icolors,
2065 		   incolors);
2066       for (i = 0; i < ncolors; i++) {
2067 	if (! colors[i].flags) {
2068 	  unsigned long chk = 0xffffffff, pixel, close = 0;
2069 
2070 	  p = 2;
2071 	  while (p--) {
2072 	    for (ii = 0; ii < incolors; ii++) {
2073 	      int r = (colors[i].red - icolors[i].red) >> 8;
2074 	      int g = (colors[i].green - icolors[i].green) >> 8;
2075 	      int b = (colors[i].blue - icolors[i].blue) >> 8;
2076 	      pixel = (r * r) + (g * g) + (b * b);
2077 
2078 	      if (pixel < chk) {
2079 		chk = pixel;
2080 		close = ii;
2081 	      }
2082 
2083 	      colors[i].red = icolors[close].red;
2084 	      colors[i].green = icolors[close].green;
2085   	      colors[i].blue = icolors[close].blue;
2086 
2087 	      if (XAllocColor(basedisplay->getXDisplay(), getColormap(),
2088 			      &colors[i])) {
2089 		colors[i].flags = DoRed|DoGreen|DoBlue;
2090 		break;
2091 	      }
2092 	    }
2093 	  }
2094 	}
2095       }
2096 
2097       break;
2098     }
2099 
2100   default:
2101     fprintf(stderr,
2102 	               "BImageControl::BImageControl: unsupported visual %d\n",
2103 	    getVisual()->c_class);
2104     exit(1);
2105   }
2106 
2107   cache = new LinkedList<Cache>;
2108 }
2109 
2110 
~BImageControl(void)2111 BImageControl::~BImageControl(void) {
2112   if (sqrt_table) {
2113     delete [] sqrt_table;
2114   }
2115 
2116   if (grad_xbuffer) {
2117     delete [] grad_xbuffer;
2118   }
2119 
2120   if (grad_ybuffer) {
2121     delete [] grad_ybuffer;
2122   }
2123 
2124   if (colors) {
2125     unsigned long *pixels = new unsigned long [ncolors];
2126 
2127     int i;
2128     for (i = 0; i < ncolors; i++)
2129       *(pixels + i) = (*(colors + i)).pixel;
2130 
2131     XFreeColors(basedisplay->getXDisplay(), getColormap(),
2132 		pixels, ncolors, 0);
2133 
2134     delete [] colors;
2135   }
2136 
2137   if (cache->count()) {
2138     int i, n = cache->count();
2139     fprintf(stderr,
2140 		       "BImageContol::~BImageControl: pixmap cache - "
2141 	               "releasing %d pixmaps\n", n);
2142 
2143     for (i = 0; i < n; i++) {
2144       Cache *tmp = cache->first();
2145       XFreePixmap(basedisplay->getXDisplay(), tmp->pixmap);
2146       cache->remove(tmp);
2147       delete tmp;
2148     }
2149 
2150 #ifdef    TIMEDCACHE
2151     if (timer) {
2152       timer->stop();
2153       delete timer;
2154     }
2155 #endif // TIMEDCACHE
2156   }
2157 
2158   delete cache;
2159 }
2160 
2161 
searchCache(unsigned int width,unsigned int height,unsigned long texture,BColor * c1,BColor * c2)2162 Pixmap BImageControl::searchCache(unsigned int width, unsigned int height,
2163 		  unsigned long texture,
2164 		  BColor *c1, BColor *c2) {
2165   if (cache->count()) {
2166     LinkedListIterator<Cache> it(cache);
2167 
2168     for (; it.current(); it++) {
2169       if ((it.current()->width == width) &&
2170           (it.current()->height == height) &&
2171           (it.current()->texture == texture) &&
2172           (it.current()->pixel1 == c1->getPixel()))
2173           if (texture & BImage_Gradient) {
2174             if (it.current()->pixel2 == c2->getPixel()) {
2175               it.current()->count++;
2176               return it.current()->pixmap;
2177             }
2178           } else {
2179             it.current()->count++;
2180             return it.current()->pixmap;
2181           }
2182         }
2183   }
2184 
2185   return None;
2186 }
2187 
2188 
renderImage(unsigned int width,unsigned int height,BTexture * texture)2189 Pixmap BImageControl::renderImage(unsigned int width, unsigned int height,
2190       BTexture *texture) {
2191   if (texture->getTexture() & BImage_ParentRelative) return ParentRelative;
2192 
2193   Pixmap pixmap = searchCache(width, height, texture->getTexture(),
2194 			      texture->getColor(), texture->getColorTo());
2195   if (pixmap) return pixmap;
2196 
2197   BImage image(this, width, height);
2198   pixmap = image.render(texture);
2199 
2200   if (pixmap) {
2201     Cache *tmp = new Cache;
2202 
2203     tmp->pixmap = pixmap;
2204     tmp->width = width;
2205     tmp->height = height;
2206     tmp->count = 1;
2207     tmp->texture = texture->getTexture();
2208     tmp->pixel1 = texture->getColor()->getPixel();
2209 
2210     if (texture->getTexture() & BImage_Gradient)
2211       tmp->pixel2 = texture->getColorTo()->getPixel();
2212     else
2213       tmp->pixel2 = 0l;
2214 
2215     cache->insert(tmp);
2216 
2217     if ((unsigned) cache->count() > cache_max) {
2218 #ifdef    DEBUG
2219       fprintf(stderr,
2220                          "BImageControl::renderImage: cache is large, "
2221                          "forcing cleanout\n");
2222 #endif // DEBUG
2223 
2224       timeout();
2225     }
2226 
2227     return pixmap;
2228   }
2229 
2230   return None;
2231 }
2232 
2233 
removeImage(Pixmap pixmap)2234 void BImageControl::removeImage(Pixmap pixmap) {
2235   if (pixmap) {
2236     LinkedListIterator<Cache> it(cache);
2237     for (; it.current(); it++) {
2238       if (it.current()->pixmap == pixmap) {
2239 	Cache *tmp = it.current();
2240 
2241         if (tmp->count) {
2242 	  tmp->count--;
2243 
2244 #ifdef    TIMEDCACHE
2245 	   if (! timer) timeout();
2246 #else // !TIMEDCACHE
2247 	   if (! tmp->count) timeout();
2248 #endif // TIMEDCACHE
2249         }
2250 
2251 	return;
2252       }
2253     }
2254   }
2255 }
2256 
2257 
getColor(const char * colorname,unsigned char * r,unsigned char * g,unsigned char * b)2258 unsigned long BImageControl::getColor(const char *colorname,
2259 				      unsigned char *r, unsigned char *g,
2260 				      unsigned char *b)
2261 {
2262   XColor color;
2263   color.pixel = 0;
2264 
2265   if (! XParseColor(basedisplay->getXDisplay(), getColormap(),
2266 		    colorname, &color)) {
2267     fprintf(stderr, "BImageControl::getColor: color parse error: \"%s\"\n",
2268 	    colorname);
2269   } else if (! XAllocColor(basedisplay->getXDisplay(), getColormap(),
2270 			   &color)) {
2271     fprintf(stderr, "BImageControl::getColor: color alloc error: \"%s\"\n",
2272 	    colorname);
2273   }
2274 
2275   if (color.red == 65535) *r = 0xff;
2276   else *r = (unsigned char) (color.red / 0xff);
2277   if (color.green == 65535) *g = 0xff;
2278   else *g = (unsigned char) (color.green / 0xff);
2279   if (color.blue == 65535) *b = 0xff;
2280   else *b = (unsigned char) (color.blue / 0xff);
2281 
2282   return color.pixel;
2283 }
2284 
2285 
getColor(const char * colorname)2286 unsigned long BImageControl::getColor(const char *colorname) {
2287   XColor color;
2288   color.pixel = 0;
2289 
2290   if (! XParseColor(basedisplay->getXDisplay(), getColormap(),
2291 		    colorname, &color)) {
2292     fprintf(stderr, "BImageControl::getColor: color parse error: \"%s\"\n",
2293 	    colorname);
2294   } else if (! XAllocColor(basedisplay->getXDisplay(), getColormap(),
2295 			   &color)) {
2296     fprintf(stderr, "BImageControl::getColor: color alloc error: \"%s\"\n",
2297 	    colorname);
2298   }
2299 
2300   return color.pixel;
2301 }
2302 
2303 
getColorTables(unsigned char ** rmt,unsigned char ** gmt,unsigned char ** bmt,int * roff,int * goff,int * boff,int * rbit,int * gbit,int * bbit)2304 void BImageControl::getColorTables(unsigned char **rmt, unsigned char **gmt,
2305 				   unsigned char **bmt,
2306 				   int *roff, int *goff, int *boff,
2307                                    int *rbit, int *gbit, int *bbit) {
2308   if (rmt) *rmt = red_color_table;
2309   if (gmt) *gmt = green_color_table;
2310   if (bmt) *bmt = blue_color_table;
2311 
2312   if (roff) *roff = red_offset;
2313   if (goff) *goff = green_offset;
2314   if (boff) *boff = blue_offset;
2315 
2316   if (rbit) *rbit = red_bits;
2317   if (gbit) *gbit = green_bits;
2318   if (bbit) *bbit = blue_bits;
2319 }
2320 
2321 
getXColorTable(XColor ** c,int * n)2322 void BImageControl::getXColorTable(XColor **c, int *n) {
2323   if (c) *c = colors;
2324   if (n) *n = ncolors;
2325 }
2326 
2327 
getGradientBuffers(unsigned int w,unsigned int h,unsigned int ** xbuf,unsigned int ** ybuf)2328 void BImageControl::getGradientBuffers(unsigned int w,
2329 				       unsigned int h,
2330 				       unsigned int **xbuf,
2331 				       unsigned int **ybuf)
2332 {
2333   if (w > grad_buffer_width) {
2334     if (grad_xbuffer) {
2335       delete [] grad_xbuffer;
2336     }
2337 
2338     grad_buffer_width = w;
2339 
2340     grad_xbuffer = new unsigned int[grad_buffer_width * 3];
2341   }
2342 
2343   if (h > grad_buffer_height) {
2344     if (grad_ybuffer) {
2345       delete [] grad_ybuffer;
2346     }
2347 
2348     grad_buffer_height = h;
2349 
2350     grad_ybuffer = new unsigned int[grad_buffer_height * 3];
2351   }
2352 
2353   *xbuf = grad_xbuffer;
2354   *ybuf = grad_ybuffer;
2355 }
2356 
2357 
installRootColormap(void)2358 void BImageControl::installRootColormap(void) {
2359   basedisplay->grab();
2360 
2361   Bool install = True;
2362   int i = 0, ncmap = 0;
2363   Colormap *cmaps =
2364     XListInstalledColormaps(basedisplay->getXDisplay(), window, &ncmap);
2365 
2366   if (cmaps) {
2367     for (i = 0; i < ncmap; i++)
2368       if (*(cmaps + i) == getColormap())
2369 	install = False;
2370 
2371     if (install)
2372       XInstallColormap(basedisplay->getXDisplay(), getColormap());
2373 
2374     XFree(cmaps);
2375   }
2376 
2377   basedisplay->ungrab();
2378 }
2379 
2380 
setColorsPerChannel(int cpc)2381 void BImageControl::setColorsPerChannel(int cpc) {
2382   if (cpc < 2) cpc = 2;
2383   if (cpc > 6) cpc = 6;
2384 
2385   colors_per_channel = cpc;
2386 }
2387 
2388 
getSqrt(unsigned int x)2389 unsigned long BImageControl::getSqrt(unsigned int x) {
2390   if (! sqrt_table) {
2391     // build sqrt table for use with elliptic gradient
2392 
2393     sqrt_table = new unsigned long[(256 * 256 * 2) + 1];
2394     int i = 0;
2395 
2396     for (; i < (256 * 256 * 2); i++)
2397       *(sqrt_table + i) = bsqrt(i);
2398   }
2399 
2400   return (*(sqrt_table + x));
2401 }
2402 
2403 
parseTexture(BTexture * texture,const char * t)2404 void BImageControl::parseTexture(BTexture *texture, const char *t) {
2405   if ((! texture) || (! t)) return;
2406 
2407   int t_len = strlen(t) + 1, i;
2408   char *ts = new char[t_len];
2409   if (! ts) return;
2410 
2411   // convert to lower case
2412   for (i = 0; i < t_len; i++)
2413     *(ts + i) = tolower(*(t + i));
2414 
2415   if (strstr(ts, "parentrelative")) {
2416     texture->setTexture(BImage_ParentRelative);
2417   } else {
2418     texture->setTexture(0);
2419 
2420     if (strstr(ts, "solid"))
2421       texture->addTexture(BImage_Solid);
2422     else if (strstr(ts, "gradient")) {
2423       texture->addTexture(BImage_Gradient);
2424       if (strstr(ts, "crossdiagonal"))
2425 	texture->addTexture(BImage_CrossDiagonal);
2426       else if (strstr(ts, "rectangle"))
2427 	texture->addTexture(BImage_Rectangle);
2428       else if (strstr(ts, "pyramid"))
2429 	texture->addTexture(BImage_Pyramid);
2430       else if (strstr(ts, "pipecross"))
2431 	texture->addTexture(BImage_PipeCross);
2432       else if (strstr(ts, "elliptic"))
2433 	texture->addTexture(BImage_Elliptic);
2434       else if (strstr(ts, "diagonal"))
2435 	texture->addTexture(BImage_Diagonal);
2436       else if (strstr(ts, "horizontal"))
2437 	texture->addTexture(BImage_Horizontal);
2438       else if (strstr(ts, "vertical"))
2439 	texture->addTexture(BImage_Vertical);
2440       else
2441 	texture->addTexture(BImage_Diagonal);
2442     } else
2443       texture->addTexture(BImage_Solid);
2444 
2445     if (strstr(ts, "raised"))
2446       texture->addTexture(BImage_Raised);
2447     else if (strstr(ts, "sunken"))
2448       texture->addTexture(BImage_Sunken);
2449     else if (strstr(ts, "flat"))
2450       texture->addTexture(BImage_Flat);
2451     else
2452       texture->addTexture(BImage_Raised);
2453 
2454     if (! (texture->getTexture() & BImage_Flat))
2455       if (strstr(ts, "bevel2"))
2456 	texture->addTexture(BImage_Bevel2);
2457       else
2458 	texture->addTexture(BImage_Bevel1);
2459 
2460 #ifdef    INTERLACE
2461     if (strstr(ts, "interlaced"))
2462       texture->addTexture(BImage_Interlaced);
2463 #endif // INTERLACE
2464   }
2465 
2466   delete [] ts;
2467 }
2468 
2469 
parseColor(BColor * color,const char * c)2470 void BImageControl::parseColor(BColor *color, const char *c) {
2471   if (! color) return;
2472 
2473   if (color->isAllocated()) {
2474     unsigned long pixel = color->getPixel();
2475 
2476     XFreeColors(basedisplay->getXDisplay(), getColormap(), &pixel, 1, 0);
2477 
2478     color->setPixel(0l);
2479     color->setRGB(0, 0, 0);
2480     color->setAllocated(False);
2481   }
2482 
2483   if (c) {
2484     unsigned char r, g, b;
2485 
2486     color->setPixel(getColor(c, &r, &g, &b));
2487     color->setRGB(r, g, b);
2488     color->setAllocated(True);
2489   }
2490 }
2491 
2492 
timeout(void)2493 void BImageControl::timeout(void) {
2494   LinkedListIterator<Cache> it(cache);
2495   for (; it.current(); it++) {
2496     Cache *tmp = it.current();
2497 
2498     if (tmp->count <= 0) {
2499       XFreePixmap(basedisplay->getXDisplay(), tmp->pixmap);
2500       cache->remove(tmp);
2501       delete tmp;
2502     }
2503   }
2504 }
2505