a "osx" gradient, it is like horizontal but mirrors in the center
[dana/openbox.git] / render / gradient.c
1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
2
3    gradient.c for the Openbox window manager
4    Copyright (c) 2003        Ben Jansens
5    Copyright (c) 2003        Derek Foreman
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    See the COPYING file for a copy of the GNU General Public License.
18 */
19
20 #include "render.h"
21 #include "gradient.h"
22 #include "color.h"
23 #include <glib.h>
24
25 static void highlight(RrPixel32 *x, RrPixel32 *y, gboolean raised);
26 static void gradient_solid(RrAppearance *l, gint w, gint h);
27 static void gradient_split(RrAppearance *a, gint w, gint h);
28 static void gradient_vertical(RrSurface *sf, gint w, gint h);
29 static void gradient_horizontal(RrSurface *sf, gint w, gint h);
30 static void gradient_osx(RrSurface *sf, gint w, gint h);
31 static void gradient_diagonal(RrSurface *sf, gint w, gint h);
32 static void gradient_crossdiagonal(RrSurface *sf, gint w, gint h);
33 static void gradient_pyramid(RrSurface *sf, gint inw, gint inh);
34
35 void RrRender(RrAppearance *a, gint w, gint h)
36 {
37     RrPixel32 *data = a->surface.pixel_data;
38     RrPixel32 current;
39     guint r,g,b;
40     gint off, x;
41
42     switch (a->surface.grad) {
43     case RR_SURFACE_SOLID:
44         gradient_solid(a, w, h);
45         break;
46     case RR_SURFACE_SPLIT:
47         gradient_split(a, w, h);
48         break;
49     case RR_SURFACE_VERTICAL:
50         gradient_vertical(&a->surface, w, h);
51         break;
52     case RR_SURFACE_HORIZONTAL:
53         gradient_horizontal(&a->surface, w, h);
54         break;
55     case RR_SURFACE_OSX:
56         gradient_osx(&a->surface, w, h);
57         break;
58     case RR_SURFACE_DIAGONAL:
59         gradient_diagonal(&a->surface, w, h);
60         break;
61     case RR_SURFACE_CROSS_DIAGONAL:
62         gradient_crossdiagonal(&a->surface, w, h);
63         break;
64     case RR_SURFACE_PYRAMID:
65         gradient_pyramid(&a->surface, w, h);
66         break;
67     default:
68         g_assert_not_reached(); /* unhandled gradient */
69         return;
70     }
71   
72     if (a->surface.interlaced) {
73         gint i;
74         RrPixel32 *p;
75
76         r = a->surface.interlace_color->r;
77         g = a->surface.interlace_color->g;
78         b = a->surface.interlace_color->b;
79         current = (r << RrDefaultRedOffset)
80             + (g << RrDefaultGreenOffset)
81             + (b << RrDefaultBlueOffset);
82         p = data;
83         for (i = 0; i < h; i += 2, p += w)
84             for (x = 0; x < w; ++x, ++p)
85                 *p = current;
86     }
87
88     if (a->surface.relief == RR_RELIEF_FLAT && a->surface.border) {
89         r = a->surface.border_color->r;
90         g = a->surface.border_color->g;
91         b = a->surface.border_color->b;
92         current = (r << RrDefaultRedOffset)
93             + (g << RrDefaultGreenOffset)
94             + (b << RrDefaultBlueOffset);
95         for (off = 0, x = 0; x < w; ++x, off++) {
96             *(data + off) = current;
97             *(data + off + ((h-1) * w)) = current;
98         }
99         for (off = 0, x = 0; x < h; ++x, off++) {
100             *(data + (off * w)) = current;
101             *(data + (off * w) + w - 1) = current;
102         }
103     }
104
105     if (a->surface.relief != RR_RELIEF_FLAT) {
106         if (a->surface.bevel == RR_BEVEL_1) {
107             for (off = 1, x = 1; x < w - 1; ++x, off++)
108                 highlight(data + off,
109                           data + off + (h-1) * w,
110                           a->surface.relief==RR_RELIEF_RAISED);
111             for (off = 0, x = 0; x < h; ++x, off++)
112                 highlight(data + off * w,
113                           data + off * w + w - 1,
114                           a->surface.relief==RR_RELIEF_RAISED);
115         }
116
117         if (a->surface.bevel == RR_BEVEL_2) {
118             for (off = 2, x = 2; x < w - 2; ++x, off++)
119                 highlight(data + off + w,
120                           data + off + (h-2) * w,
121                           a->surface.relief==RR_RELIEF_RAISED);
122             for (off = 1, x = 1; x < h-1; ++x, off++)
123                 highlight(data + off * w + 1,
124                           data + off * w + w - 2,
125                           a->surface.relief==RR_RELIEF_RAISED);
126         }
127     }
128 }
129
130 static void highlight(RrPixel32 *x, RrPixel32 *y, gboolean raised)
131 {
132     gint r, g, b;
133
134     RrPixel32 *up, *down;
135     if (raised) {
136         up = x;
137         down = y;
138     } else {
139         up = y;
140         down = x;
141     }
142     r = (*up >> RrDefaultRedOffset) & 0xFF;
143     r += r >> 1;
144     g = (*up >> RrDefaultGreenOffset) & 0xFF;
145     g += g >> 1;
146     b = (*up >> RrDefaultBlueOffset) & 0xFF;
147     b += b >> 1;
148     if (r > 0xFF) r = 0xFF;
149     if (g > 0xFF) g = 0xFF;
150     if (b > 0xFF) b = 0xFF;
151     *up = (r << RrDefaultRedOffset) + (g << RrDefaultGreenOffset)
152         + (b << RrDefaultBlueOffset);
153   
154     r = (*down >> RrDefaultRedOffset) & 0xFF;
155     r = (r >> 1) + (r >> 2);
156     g = (*down >> RrDefaultGreenOffset) & 0xFF;
157     g = (g >> 1) + (g >> 2);
158     b = (*down >> RrDefaultBlueOffset) & 0xFF;
159     b = (b >> 1) + (b >> 2);
160     *down = (r << RrDefaultRedOffset) + (g << RrDefaultGreenOffset)
161         + (b << RrDefaultBlueOffset);
162 }
163
164 static void create_bevel_colors(RrAppearance *l)
165 {
166     gint r, g, b;
167
168     /* light color */
169     r = l->surface.primary->r;
170     r += r >> 1;
171     g = l->surface.primary->g;
172     g += g >> 1;
173     b = l->surface.primary->b;
174     b += b >> 1;
175     if (r > 0xFF) r = 0xFF;
176     if (g > 0xFF) g = 0xFF;
177     if (b > 0xFF) b = 0xFF;
178     g_assert(!l->surface.bevel_light);
179     l->surface.bevel_light = RrColorNew(l->inst, r, g, b);
180
181     /* dark color */
182     r = l->surface.primary->r;
183     r = (r >> 1) + (r >> 2);
184     g = l->surface.primary->g;
185     g = (g >> 1) + (g >> 2);
186     b = l->surface.primary->b;
187     b = (b >> 1) + (b >> 2);
188     g_assert(!l->surface.bevel_dark);
189     l->surface.bevel_dark = RrColorNew(l->inst, r, g, b);
190 }
191
192 static void gradient_solid(RrAppearance *l, gint w, gint h) 
193 {
194     RrPixel32 pix;
195     gint i, a, b;
196     RrSurface *sp = &l->surface;
197     gint left = 0, top = 0, right = w - 1, bottom = h - 1;
198
199     pix = (sp->primary->r << RrDefaultRedOffset)
200         + (sp->primary->g << RrDefaultGreenOffset)
201         + (sp->primary->b << RrDefaultBlueOffset);
202
203     for (a = 0; a < w; a++)
204         for (b = 0; b < h; b++)
205             sp->pixel_data[a + b * w] = pix;
206
207     XFillRectangle(RrDisplay(l->inst), l->pixmap, RrColorGC(sp->primary),
208                    0, 0, w, h);
209
210     if (sp->interlaced) {
211         for (i = 0; i < h; i += 2)
212             XDrawLine(RrDisplay(l->inst), l->pixmap,
213                       RrColorGC(sp->interlace_color),
214                       0, i, w, i);
215     }
216
217     switch (sp->relief) {
218     case RR_RELIEF_RAISED:
219         if (!sp->bevel_dark)
220             create_bevel_colors(l);
221
222         switch (sp->bevel) {
223         case RR_BEVEL_1:
224             XDrawLine(RrDisplay(l->inst), l->pixmap, RrColorGC(sp->bevel_dark),
225                       left, bottom, right, bottom);
226             XDrawLine(RrDisplay(l->inst), l->pixmap, RrColorGC(sp->bevel_dark),
227                       right, bottom, right, top);
228                 
229             XDrawLine(RrDisplay(l->inst), l->pixmap,RrColorGC(sp->bevel_light),
230                       left, top, right, top);
231             XDrawLine(RrDisplay(l->inst), l->pixmap,RrColorGC(sp->bevel_light),
232                       left, bottom, left, top);
233             break;
234         case RR_BEVEL_2:
235             XDrawLine(RrDisplay(l->inst), l->pixmap, RrColorGC(sp->bevel_dark),
236                       left + 1, bottom - 2, right - 2, bottom - 2);
237             XDrawLine(RrDisplay(l->inst), l->pixmap, RrColorGC(sp->bevel_dark),
238                       right - 2, bottom - 2, right - 2, top + 1);
239
240             XDrawLine(RrDisplay(l->inst), l->pixmap,RrColorGC(sp->bevel_light),
241                       left + 1, top + 1, right - 2, top + 1);
242             XDrawLine(RrDisplay(l->inst), l->pixmap,RrColorGC(sp->bevel_light),
243                       left + 1, bottom - 2, left + 1, top + 1);
244             break;
245         default:
246             g_assert_not_reached(); /* unhandled BevelType */
247         }
248         break;
249     case RR_RELIEF_SUNKEN:
250         if (!sp->bevel_dark)
251             create_bevel_colors(l);
252
253         switch (sp->bevel) {
254         case RR_BEVEL_1:
255             XDrawLine(RrDisplay(l->inst), l->pixmap,RrColorGC(sp->bevel_light),
256                       left, bottom, right, bottom);
257             XDrawLine(RrDisplay(l->inst), l->pixmap,RrColorGC(sp->bevel_light),
258                       right, bottom, right, top);
259       
260             XDrawLine(RrDisplay(l->inst), l->pixmap, RrColorGC(sp->bevel_dark),
261                       left, top, right, top);
262             XDrawLine(RrDisplay(l->inst), l->pixmap, RrColorGC(sp->bevel_dark),
263                       left, bottom, left, top);
264             break;
265         case RR_BEVEL_2:
266             XDrawLine(RrDisplay(l->inst), l->pixmap,RrColorGC(sp->bevel_light),
267                       left + 1, bottom - 2, right - 2, bottom - 2);
268             XDrawLine(RrDisplay(l->inst), l->pixmap,RrColorGC(sp->bevel_light),
269                       right - 2, bottom - 2, right - 2, top + 1);
270       
271             XDrawLine(RrDisplay(l->inst), l->pixmap, RrColorGC(sp->bevel_dark),
272                       left + 1, top + 1, right - 2, top + 1);
273             XDrawLine(RrDisplay(l->inst), l->pixmap, RrColorGC(sp->bevel_dark),
274                       left + 1, bottom - 2, left + 1, top + 1);
275
276             break;
277         default:
278             g_assert_not_reached(); /* unhandled BevelType */
279         }
280         break;
281     case RR_RELIEF_FLAT:
282         if (sp->border) {
283             XDrawRectangle(RrDisplay(l->inst), l->pixmap,
284                            RrColorGC(sp->border_color),
285                            left, top, right, bottom);
286         }
287         break;
288     default:  
289         g_assert_not_reached(); /* unhandled ReliefType */
290     }
291 }
292
293 /* * * * * * * * * * * * * * GRADIENT MAGIC WOOT * * * * * * * * * * * * * * */
294
295 #define VARS(x)                                                     \
296     guint color##x[3];                                       \
297     gint len##x, cdelta##x[3], error##x[3] = { 0, 0, 0 }, inc##x[3]; \
298     gboolean bigslope##x[3] /* color slope > 1 */
299
300 #define SETUP(x, from, to, w)         \
301     len##x = w;                       \
302                                       \
303     color##x[0] = from->r;            \
304     color##x[1] = from->g;            \
305     color##x[2] = from->b;            \
306                                       \
307     cdelta##x[0] = to->r - from->r;   \
308     cdelta##x[1] = to->g - from->g;   \
309     cdelta##x[2] = to->b - from->b;   \
310                                       \
311     if (cdelta##x[0] < 0) {           \
312         cdelta##x[0] = -cdelta##x[0]; \
313         inc##x[0] = -1;               \
314     } else                            \
315         inc##x[0] = 1;                \
316     if (cdelta##x[1] < 0) {           \
317         cdelta##x[1] = -cdelta##x[1]; \
318         inc##x[1] = -1;               \
319     } else                            \
320         inc##x[1] = 1;                \
321     if (cdelta##x[2] < 0) {           \
322         cdelta##x[2] = -cdelta##x[2]; \
323         inc##x[2] = -1;               \
324     } else                            \
325         inc##x[2] = 1;                \
326     bigslope##x[0] = cdelta##x[0] > w;\
327     bigslope##x[1] = cdelta##x[1] > w;\
328     bigslope##x[2] = cdelta##x[2] > w
329
330 #define COLOR_RR(x, c)                       \
331     c->r = color##x[0];                      \
332     c->g = color##x[1];                      \
333     c->b = color##x[2]
334
335 #define COLOR(x)                             \
336     ((color##x[0] << RrDefaultRedOffset) +   \
337      (color##x[1] << RrDefaultGreenOffset) + \
338      (color##x[2] << RrDefaultBlueOffset))
339
340 #define INCREMENT(x, i) \
341     (inc##x[i])
342
343 #define NEXT(x)                                           \
344 {                                                         \
345     gint i;                                                \
346     for (i = 2; i >= 0; --i) {                            \
347         if (!cdelta##x[i]) continue;                      \
348                                                           \
349         if (!bigslope##x[i]) {                            \
350             /* Y (color) is dependant on X */             \
351             error##x[i] += cdelta##x[i];                  \
352             if ((error##x[i] << 1) >= len##x) {           \
353                 color##x[i] += INCREMENT(x, i);           \
354                 error##x[i] -= len##x;                    \
355             }                                             \
356         } else {                                          \
357             /* X is dependant on Y (color) */             \
358             while (1) {                                   \
359                 color##x[i] += INCREMENT(x, i);           \
360                 error##x[i] += len##x;                    \
361                 if ((error##x[i] << 1) >= cdelta##x[i]) { \
362                     error##x[i] -= cdelta##x[i];          \
363                     break;                                \
364                 }                                         \
365             }                                             \
366         }                                                 \
367     }                                                     \
368 }
369
370 static void gradient_split(RrAppearance *a, gint w, gint h)
371 {
372     gint x, y1, y3, r, g, b;
373     RrSurface *sf = &a->surface;
374     RrPixel32 *data = sf->pixel_data;
375     RrPixel32 current;
376     RrColor *primary_light, *secondary_light;
377
378     r = sf->primary->r;
379     r += r >> 2;
380     g = sf->primary->g;
381     g += g >> 2;
382     b = sf->primary->b;
383     b += b >> 2;
384     if (r > 0xFF) r = 0xFF;
385     if (g > 0xFF) g = 0xFF;
386     if (b > 0xFF) b = 0xFF;
387       primary_light = RrColorNew(a->inst, r, g, b);
388
389     r = sf->secondary->r;
390     r += r >> 4;
391     g = sf->secondary->g;
392     g += g >> 4;
393     b = sf->secondary->b;
394     b += b >> 4;
395     if (r > 0xFF) r = 0xFF;
396     if (g > 0xFF) g = 0xFF;
397     if (b > 0xFF) b = 0xFF;
398     secondary_light = RrColorNew(a->inst, r, g, b);
399
400     VARS(y1);
401     SETUP(y1, primary_light, sf->primary, (h / 2) -1);
402   
403     VARS(y3);
404     SETUP(y3, sf->secondary, secondary_light,  (h / 2) -1);
405
406     for (y1 = h - 1; y1 > (h / 2) -1; --y1) {  /* 0 -> h-1 */
407         current = COLOR(y1);
408         for (x = w - 1; x >= 0; --x)  /* 0 -> w */
409             *(data++) = current;
410
411         NEXT(y1);
412     }
413
414     
415     for (y3 = (h / 2) - 1; y3 > 0; --y3) {
416         current = COLOR(y3);
417         for (x = w - 1; x >= 0; --x)
418             *(data++) = current;
419
420         NEXT(y3);
421     }
422
423     current = COLOR(y3);
424     for (x = w - 1; x >= 0; --x)  /* 0 -> w */
425         *(data++) = current;
426
427     RrColorFree(primary_light);
428     RrColorFree(secondary_light);
429 }
430
431 static void gradient_horizontal(RrSurface *sf, gint w, gint h)
432 {
433     gint x, y;
434     RrPixel32 *data = sf->pixel_data, *datav;
435     RrPixel32 current;
436
437     VARS(x);
438     SETUP(x, sf->primary, sf->secondary, w);
439
440     for (x = w - 1; x > 0; --x) {  /* 0 -> w-1 */
441         current = COLOR(x);
442         datav = data;
443         for (y = h - 1; y >= 0; --y) {  /* 0 -> h */
444             *datav = current;
445             datav += w;
446         }
447         ++data;
448
449         NEXT(x);
450     }
451     current = COLOR(x);
452     for (y = h - 1; y >= 0; --y)  /* 0 -> h */
453         *(data + y * w) = current;
454 }
455
456 static void gradient_osx(RrSurface *sf, gint w, gint h)
457 {
458     gint x, y;
459     RrPixel32 *data = sf->pixel_data, *datav;
460     RrPixel32 current;
461
462     VARS(x);
463     SETUP(x, sf->primary, sf->secondary, w/2);
464
465     for (x = w - 1; x > w/2-1; --x) {  /* 0 -> w-1 */
466         current = COLOR(x);
467         datav = data;
468         for (y = h - 1; y >= 0; --y) {  /* 0 -> h */
469             *datav = current;
470             datav += w;
471         }
472         ++data;
473
474         NEXT(x);
475     }
476     SETUP(x, sf->secondary, sf->primary, w/2);
477     for (x = w/2 - 1; x > 0; --x) {  /* 0 -> w-1 */
478         current = COLOR(x);
479         datav = data;
480         for (y = h - 1; y >= 0; --y) {  /* 0 -> h */
481             *datav = current;
482             datav += w;
483         }
484         ++data;
485
486         NEXT(x);
487     }
488     current = COLOR(x);
489     for (y = h - 1; y >= 0; --y)  /* 0 -> h */
490         *(data + y * w) = current;
491 }
492
493 static void gradient_vertical(RrSurface *sf, gint w, gint h)
494 {
495     gint x, y;
496     RrPixel32 *data = sf->pixel_data;
497     RrPixel32 current;
498
499     VARS(y);
500     SETUP(y, sf->primary, sf->secondary, h);
501
502     for (y = h - 1; y > 0; --y) {  /* 0 -> h-1 */
503         current = COLOR(y);
504         for (x = w - 1; x >= 0; --x)  /* 0 -> w */
505             *(data++) = current;
506
507         NEXT(y);
508     }
509     current = COLOR(y);
510     for (x = w - 1; x >= 0; --x)  /* 0 -> w */
511         *(data++) = current;
512 }
513
514
515 static void gradient_diagonal(RrSurface *sf, gint w, gint h)
516 {
517     gint x, y;
518     RrPixel32 *data = sf->pixel_data;
519     RrColor left, right;
520     RrColor extracorner;
521
522     VARS(lefty);
523     VARS(righty);
524     VARS(x);
525
526     extracorner.r = (sf->primary->r + sf->secondary->r) / 2;
527     extracorner.g = (sf->primary->g + sf->secondary->g) / 2;
528     extracorner.b = (sf->primary->b + sf->secondary->b) / 2;
529
530     SETUP(lefty, sf->primary, (&extracorner), h);
531     SETUP(righty, (&extracorner), sf->secondary, h);
532
533     for (y = h - 1; y > 0; --y) {  /* 0 -> h-1 */
534         COLOR_RR(lefty, (&left));
535         COLOR_RR(righty, (&right));
536
537         SETUP(x, (&left), (&right), w);
538
539         for (x = w - 1; x > 0; --x) {  /* 0 -> w-1 */
540             *(data++) = COLOR(x);
541
542             NEXT(x);
543         }
544         *(data++) = COLOR(x);
545
546         NEXT(lefty);
547         NEXT(righty);
548     }
549     COLOR_RR(lefty, (&left));
550     COLOR_RR(righty, (&right));
551
552     SETUP(x, (&left), (&right), w);
553
554     for (x = w - 1; x > 0; --x) {  /* 0 -> w-1 */
555         *(data++) = COLOR(x);
556         
557         NEXT(x);
558     }
559     *data = COLOR(x);
560 }
561
562 static void gradient_crossdiagonal(RrSurface *sf, gint w, gint h)
563 {
564     gint x, y;
565     RrPixel32 *data = sf->pixel_data;
566     RrColor left, right;
567     RrColor extracorner;
568
569     VARS(lefty);
570     VARS(righty);
571     VARS(x);
572
573     extracorner.r = (sf->primary->r + sf->secondary->r) / 2;
574     extracorner.g = (sf->primary->g + sf->secondary->g) / 2;
575     extracorner.b = (sf->primary->b + sf->secondary->b) / 2;
576
577     SETUP(lefty, (&extracorner), sf->secondary, h);
578     SETUP(righty, sf->primary, (&extracorner), h);
579
580     for (y = h - 1; y > 0; --y) {  /* 0 -> h-1 */
581         COLOR_RR(lefty, (&left));
582         COLOR_RR(righty, (&right));
583
584         SETUP(x, (&left), (&right), w);
585
586         for (x = w - 1; x > 0; --x) {  /* 0 -> w-1 */
587             *(data++) = COLOR(x);
588
589             NEXT(x);
590         }
591         *(data++) = COLOR(x);
592
593         NEXT(lefty);
594         NEXT(righty);
595     }
596     COLOR_RR(lefty, (&left));
597     COLOR_RR(righty, (&right));
598
599     SETUP(x, (&left), (&right), w);
600
601     for (x = w - 1; x > 0; --x) {  /* 0 -> w-1 */
602         *(data++) = COLOR(x);
603         
604         NEXT(x);
605     }
606     *data = COLOR(x);
607 }
608
609 static void gradient_pyramid(RrSurface *sf, gint inw, gint inh)
610 {
611     gint x, y, w = (inw >> 1) + 1, h = (inh >> 1) + 1;
612     RrPixel32 *data = sf->pixel_data;
613     RrPixel32 *end = data + inw*inh - 1;
614     RrPixel32 current;
615     RrColor left, right;
616     RrColor extracorner;
617
618     VARS(lefty);
619     VARS(righty);
620     VARS(x);
621
622     extracorner.r = (sf->primary->r + sf->secondary->r) / 2;
623     extracorner.g = (sf->primary->g + sf->secondary->g) / 2;
624     extracorner.b = (sf->primary->b + sf->secondary->b) / 2;
625
626     SETUP(lefty, (&extracorner), sf->secondary, h);
627     SETUP(righty, sf->primary, (&extracorner), h);
628
629     for (y = h - 1; y > 0; --y) {  /* 0 -> h-1 */
630         COLOR_RR(lefty, (&left));
631         COLOR_RR(righty, (&right));
632
633         SETUP(x, (&left), (&right), w);
634
635         for (x = w - 1; x > 0; --x) {  /* 0 -> w-1 */
636             current = COLOR(x);
637             *(data+x) = current;
638             *(data+inw-x) = current;
639             *(end-x) = current;
640             *(end-(inw-x)) = current;
641
642             NEXT(x);
643         }
644         current = COLOR(x);
645         *(data+x) = current;
646         *(data+inw-x) = current;
647         *(end-x) = current;
648         *(end-(inw-x)) = current;
649
650         data+=inw;
651         end-=inw;
652
653         NEXT(lefty);
654         NEXT(righty);
655     }
656     COLOR_RR(lefty, (&left));
657     COLOR_RR(righty, (&right));
658
659     SETUP(x, (&left), (&right), w);
660
661     for (x = w - 1; x > 0; --x) {  /* 0 -> w-1 */
662         current = COLOR(x);
663         *(data+x) = current;
664         *(data+inw-x) = current;
665         *(end-x) = current;
666         *(end-(inw-x)) = current;
667         
668         NEXT(x);
669     }
670     current = COLOR(x);
671     *(data+x) = current;
672     *(data+inw-x) = current;
673     *(end-x) = current;
674     *(end-(inw-x)) = current;
675 }
676