Release 941227
[wine] / objects / color.c
1 /*
2  * Color functions
3  *
4  * Copyright 1993 Alexandre Julliard
5  *
6 static char Copyright[] = "Copyright  Alexandre Julliard, 1993";
7 */
8 #include <stdlib.h>
9 #include <X11/Xlib.h>
10 #include <stdio.h>
11 #include "windows.h"
12 #include "options.h"
13 #include "gdi.h"
14 #include "color.h"
15
16
17 Colormap COLOR_WinColormap = 0;
18
19   /* System palette static colors */
20
21 #define NB_RESERVED_COLORS  20
22
23   /* The first and last eight colors are EGA colors */
24 static PALETTEENTRY COLOR_sysPaletteEntries[NB_RESERVED_COLORS] =
25 {
26     /* red  green blue  flags */
27     { 0x00, 0x00, 0x00, 0 },
28     { 0x80, 0x00, 0x00, 0 },
29     { 0x00, 0x80, 0x00, 0 },
30     { 0x80, 0x80, 0x00, 0 },
31     { 0x00, 0x00, 0x80, 0 },
32     { 0x80, 0x00, 0x80, 0 },
33     { 0x00, 0x80, 0x80, 0 },
34     { 0xc0, 0xc0, 0xc0, 0 },
35     { 0xc0, 0xdc, 0xc0, 0 },
36     { 0xa6, 0xca, 0xf0, 0 },
37
38     { 0xff, 0xfb, 0xf0, 0 },
39     { 0xa0, 0xa0, 0xa4, 0 },
40     { 0x80, 0x80, 0x80, 0 },
41     { 0xff, 0x00, 0x00, 0 },
42     { 0x00, 0xff, 0x00, 0 },
43     { 0xff, 0xff, 0x00, 0 },
44     { 0x00, 0x00, 0xff, 0 },
45     { 0xff, 0x00, 0xff, 0 },
46     { 0x00, 0xff, 0xff, 0 },
47     { 0xff, 0xff, 0xff, 0 }
48 };
49
50 static HANDLE hSysColorTranslation = 0;
51 static HANDLE hRevSysColorTranslation = 0;
52
53    /* Map an EGA index (0..15) to a pixel value. Used for dithering. */
54 int COLOR_mapEGAPixel[16];
55
56 int* COLOR_PaletteToPixel = NULL;
57 int* COLOR_PixelToPalette = NULL;
58 int COLOR_ColormapSize = 0;
59
60 /***********************************************************************
61  *           COLOR_BuildMap
62  *
63  * Fill the private colormap.
64  */
65 static BOOL COLOR_BuildMap( Colormap map, int depth, int size )
66 {
67     XColor color;
68     int r, g, b, red_incr, green_incr, blue_incr;
69     int index = 0;
70
71       /* Fill the whole map with a range of colors */
72
73     blue_incr  = 0x10000 >> (depth / 3);
74     red_incr   = 0x10000 >> ((depth + 1) / 3);
75     green_incr = 0x10000 >> ((depth + 2) / 3);
76
77     for (r = red_incr - 1; r < 0x10000; r += red_incr)
78         for (g = green_incr - 1; g < 0x10000; g += green_incr)
79             for (b = blue_incr - 1; b < 0x10000; b += blue_incr)
80             {
81                 if (index >= size) break;
82                 color.pixel = index++;
83                 color.red   = r;
84                 color.green = g;
85                 color.blue  = b;
86                 XStoreColor( display, map, &color );
87             }
88
89     return TRUE;
90 }
91
92
93 /***********************************************************************
94  *           COLOR_InitPalette
95  *
96  * Create the system palette.
97  */
98 static HPALETTE COLOR_InitPalette(void)
99 {
100     int i, size, pixel;
101     XColor color;
102     HPALETTE hpalette;
103     LOGPALETTE * palPtr;
104     WORD *colorTranslation, *revTranslation;
105
106     size = DefaultVisual( display, DefaultScreen(display) )->map_entries;
107     COLOR_ColormapSize = size;
108     if (!(hSysColorTranslation = GDI_HEAP_ALLOC( GMEM_MOVEABLE,
109                                             sizeof(WORD)*NB_RESERVED_COLORS )))
110         return FALSE;
111     if (!(hRevSysColorTranslation = GDI_HEAP_ALLOC( GMEM_MOVEABLE,
112                                                     sizeof(WORD)*size )))
113         return FALSE;
114     colorTranslation = (WORD *) GDI_HEAP_ADDR( hSysColorTranslation );
115     revTranslation   = (WORD *) GDI_HEAP_ADDR( hRevSysColorTranslation );
116
117     if (COLOR_WinColormap == DefaultColormapOfScreen(screen))
118     {
119         COLOR_PaletteToPixel = (int *)malloc( sizeof(int) * size );
120         COLOR_PixelToPalette = (int *)malloc( sizeof(int) * size );
121     }
122
123     for (i = 0; i < NB_RESERVED_COLORS; i++)
124     {
125         color.red   = COLOR_sysPaletteEntries[i].peRed * 65535 / 255;
126         color.green = COLOR_sysPaletteEntries[i].peGreen * 65535 / 255;
127         color.blue  = COLOR_sysPaletteEntries[i].peBlue * 65535 / 255;
128         color.flags = DoRed | DoGreen | DoBlue;
129
130         if (i < NB_RESERVED_COLORS/2)
131         {
132             /* Bottom half of the colormap */
133             pixel = i;
134             if (pixel >= size/2) continue;
135         }
136         else
137         {
138             /* Top half of the colormap */
139             pixel = size - NB_RESERVED_COLORS + i;
140             if (pixel < size/2) continue;
141         }
142         if (COLOR_WinColormap != DefaultColormapOfScreen(screen))
143         {
144             color.pixel = pixel;
145             XStoreColor( display, COLOR_WinColormap, &color );
146         }
147         else
148         {
149             if (!XAllocColor( display, COLOR_WinColormap, &color ))
150             {
151                 fprintf(stderr, "Warning: Not enough free colors. Try using the -privatemap option.\n" );
152                 color.pixel = color.red = color.green = color.blue = 0;
153             }
154             else
155             {
156                 COLOR_PaletteToPixel[pixel] = color.pixel;
157                 COLOR_PixelToPalette[color.pixel] = pixel;
158             }
159         }
160         colorTranslation[i] = color.pixel;
161         revTranslation[color.pixel] = i;
162           /* Set EGA mapping if color in the first or last eight */
163         if (i < 8)
164             COLOR_mapEGAPixel[i] = color.pixel;
165         else if (i >= NB_RESERVED_COLORS-8)
166             COLOR_mapEGAPixel[i - (NB_RESERVED_COLORS-16)] = color.pixel;
167     }
168
169     palPtr = malloc( sizeof(LOGPALETTE) + (NB_RESERVED_COLORS-1)*sizeof(PALETTEENTRY) );
170     if (!palPtr) return FALSE;
171     palPtr->palVersion = 0x300;
172     palPtr->palNumEntries = NB_RESERVED_COLORS;
173     memcpy( palPtr->palPalEntry, COLOR_sysPaletteEntries,
174             sizeof(COLOR_sysPaletteEntries) );
175     hpalette = CreatePalette( palPtr );
176     free( palPtr );
177     return hpalette;
178 }
179
180
181 /***********************************************************************
182  *           COLOR_Init
183  *
184  * Initialize color map and system palette.
185  */
186 HPALETTE COLOR_Init(void)
187 {
188     Visual * visual = DefaultVisual( display, DefaultScreen(display) );
189     
190     switch(visual->class)
191     {
192     case GrayScale:
193     case PseudoColor:
194     case DirectColor:
195         if (Options.usePrivateMap)
196         {
197             COLOR_WinColormap = XCreateColormap( display, rootWindow,
198                                                  visual, AllocAll );
199             if (COLOR_WinColormap)
200             {
201                 COLOR_BuildMap( COLOR_WinColormap, screenDepth,
202                                 visual->map_entries );
203                 if (rootWindow != DefaultRootWindow(display))
204                 {
205                     XSetWindowAttributes win_attr;
206                     win_attr.colormap = COLOR_WinColormap;
207                     XChangeWindowAttributes( display, rootWindow,
208                                              CWColormap, &win_attr );
209                 }
210                 break;
211             }
212         }
213         /* Fall through */
214     case StaticGray:
215     case StaticColor:
216     case TrueColor:
217         COLOR_WinColormap = DefaultColormapOfScreen( screen );
218         break;  
219     }
220     return COLOR_InitPalette();
221 }
222
223
224 /***********************************************************************
225  *           COLOR_IsSolid
226  *
227  * Check whether 'color' can be represented with a solid color.
228  */
229 BOOL COLOR_IsSolid( COLORREF color )
230 {
231     int i;
232     PALETTEENTRY *pEntry = COLOR_sysPaletteEntries;
233
234     if (color & 0xff000000) return TRUE;
235     if (!color || (color == 0xffffff)) return TRUE;
236     for (i = NB_RESERVED_COLORS; i > 0; i--, pEntry++)
237     {
238         if ((GetRValue(color) == pEntry->peRed) &&
239             (GetGValue(color) == pEntry->peGreen) &&
240             (GetBValue(color) == pEntry->peBlue)) return TRUE;
241     }
242     return FALSE;
243 }
244
245
246 /***********************************************************************
247  *           COLOR_ToPhysical
248  *
249  * Return the physical color closest to 'color'.
250  */
251 int COLOR_ToPhysical( DC *dc, COLORREF color )
252 {
253     WORD index = 0;
254     WORD *mapping;
255
256     if (screenDepth > 8) return color;
257     switch(color >> 24)
258     {
259     case 0:  /* RGB */
260         index = GetNearestPaletteIndex( STOCK_DEFAULT_PALETTE, color );
261         break;
262     case 1:  /* PALETTEINDEX */
263         index = color & 0xffff;
264         break;
265     case 2:  /* PALETTERGB */
266         if (dc) index = GetNearestPaletteIndex( dc->w.hPalette, color );
267         else index = 0;
268         break;
269     }
270     if (dc)
271     {
272         if (index >= dc->u.x.pal.mappingSize) return 0;
273         mapping = (WORD *) GDI_HEAP_ADDR( dc->u.x.pal.hMapping );
274     }
275     else
276     {
277         if (index >= NB_RESERVED_COLORS) return 0;
278         mapping = (WORD *) GDI_HEAP_ADDR( hSysColorTranslation );
279     }
280     if (mapping) return mapping[index];
281     else return index;  /* Identity mapping */
282 }
283
284
285 /***********************************************************************
286  *           COLOR_SetMapping
287  *
288  * Set the color-mapping table in a DC.
289  */
290 void COLOR_SetMapping( DC *dc, HANDLE map, HANDLE revMap, WORD size )
291 {
292     WORD *pmap, *pnewmap;
293     WORD i;
294
295     if (dc->u.x.pal.hMapping && (dc->u.x.pal.hMapping != hSysColorTranslation))
296         GDI_HEAP_FREE( dc->u.x.pal.hMapping );
297     if (dc->u.x.pal.hRevMapping &&
298         (dc->u.x.pal.hRevMapping != hRevSysColorTranslation))
299         GDI_HEAP_FREE( dc->u.x.pal.hRevMapping );
300     if (map && (map != hSysColorTranslation))
301     {
302           /* Copy mapping table */
303         dc->u.x.pal.hMapping = GDI_HEAP_ALLOC(GMEM_MOVEABLE,sizeof(WORD)*size);
304         pmap = (WORD *) GDI_HEAP_ADDR( map );
305         pnewmap = (WORD *) GDI_HEAP_ADDR( dc->u.x.pal.hMapping );
306         memcpy( pnewmap, pmap, sizeof(WORD)*size );
307           /* Build reverse table */
308         dc->u.x.pal.hRevMapping = GDI_HEAP_ALLOC( GMEM_MOVEABLE,
309                                              sizeof(WORD)*COLOR_ColormapSize );
310         pmap = (WORD *) GDI_HEAP_ADDR( dc->u.x.pal.hRevMapping );
311         for (i = 0; i < size; i++) pmap[pnewmap[i]] = i;
312     }
313     else
314     {
315         dc->u.x.pal.hMapping = map;
316         dc->u.x.pal.hRevMapping = map ? hRevSysColorTranslation : 0;
317     }
318     dc->u.x.pal.mappingSize = size;
319 }
320
321
322 /***********************************************************************
323  *           GetNearestColor    (GDI.154)
324  */
325 COLORREF GetNearestColor( HDC hdc, COLORREF color )
326 {
327     WORD index;
328     DC *dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC );
329     if (!dc) return 0;
330     if (screenDepth > 8) return color;
331     index = (WORD)(COLOR_ToPhysical( dc, color & 0xffffff ) & 0xffff);
332     return PALETTEINDEX( index );
333 }
334
335
336 /***********************************************************************
337  *           RealizeDefaultPalette    (GDI.365)
338  */
339 WORD RealizeDefaultPalette( HDC hdc )
340 {
341     DC *dc;
342     if (!(dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC ))) return 0;
343     dc->w.hPalette = STOCK_DEFAULT_PALETTE;
344     COLOR_SetMapping( dc, hSysColorTranslation,
345                       hRevSysColorTranslation, NB_RESERVED_COLORS );
346     return NB_RESERVED_COLORS;
347 }