:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[reactos.git] / subsys / win32k / objects / palette.c
1 #undef WIN32_LEAN_AND_MEAN
2 #include <windows.h>
3 #include <win32k/debug.h>
4 #include <win32k/bitmaps.h>
5 #include <win32k/color.h>
6 #include <debug.h>
7 #include "../include/palette.h"
8
9 static int           PALETTE_firstFree = 0; 
10 static unsigned char PALETTE_freeList[256];
11
12 int PALETTE_PaletteFlags     = 0;
13 PALETTEENTRY *COLOR_sysPal   = NULL;
14 int COLOR_gapStart;
15 int COLOR_gapEnd;
16 int COLOR_gapFilled;
17 int COLOR_max;
18
19 PALETTEENTRY *ReturnSystemPalette(void)
20 {
21   return COLOR_sysPal;
22 }
23
24 // Create the system palette
25 HPALETTE PALETTE_Init(void)
26 {
27   int i;
28   HPALETTE hpalette;
29   PLOGPALETTE palPtr;
30   PPALOBJ palObj;
31   const PALETTEENTRY* __sysPalTemplate = (const PALETTEENTRY*)COLOR_GetSystemPaletteTemplate();
32
33   // create default palette (20 system colors)
34   palPtr = ExAllocatePool(NonPagedPool, sizeof(LOGPALETTE) + (NB_RESERVED_COLORS * sizeof(PALETTEENTRY)));
35   if (!palPtr) return FALSE;
36
37   palPtr->palVersion = 0x300;
38   palPtr->palNumEntries = NB_RESERVED_COLORS;
39   for(i=0; i<NB_RESERVED_COLORS; i++)
40   {
41     palPtr->palPalEntry[i].peRed = __sysPalTemplate[i].peRed;
42     palPtr->palPalEntry[i].peGreen = __sysPalTemplate[i].peGreen;
43     palPtr->palPalEntry[i].peBlue = __sysPalTemplate[i].peBlue;
44     palPtr->palPalEntry[i].peFlags = 0;
45   }
46
47   hpalette = W32kCreatePalette(palPtr);
48   ExFreePool(palPtr);
49
50   palObj = (PPALOBJ)AccessUserObject(hpalette);
51   if (palObj)
52   {
53     if (!(palObj->mapping = ExAllocatePool(NonPagedPool, sizeof(int) * 20)))
54     {
55       DbgPrint("Win32k: Can not create palette mapping -- out of memory!");
56       return FALSE;
57     }
58 //      GDI_ReleaseObj( hpalette );
59   }
60
61 /*  palette_size = visual->map_entries; */
62
63   return hpalette;
64 }
65
66 static void PALETTE_FormatSystemPalette(void)
67 {
68   // Build free list so we'd have an easy way to find
69   // out if there are any available colorcells. 
70
71   int i, j = PALETTE_firstFree = NB_RESERVED_COLORS/2;
72
73   COLOR_sysPal[j].peFlags = 0;
74   for(i = NB_RESERVED_COLORS/2 + 1 ; i < 256 - NB_RESERVED_COLORS/2 ; i++)
75   {
76     if( i < COLOR_gapStart || i > COLOR_gapEnd )
77     {
78       COLOR_sysPal[i].peFlags = 0;  // unused tag
79       PALETTE_freeList[j] = i; // next
80       j = i;
81     }
82   }
83   PALETTE_freeList[j] = 0;
84 }
85
86 /* Ported from WINE 20020804 (graphics\x11drv\palette.c) */
87 static int SysPaletteLookupPixel( COLORREF col, BOOL skipReserved )
88 {
89   int i, best = 0, diff = 0x7fffffff;
90   int r,g,b;
91
92   for( i = 0; i < palette_size && diff ; i++ )
93   {
94     if( !(COLOR_sysPal[i].peFlags & PC_SYS_USED) || (skipReserved && COLOR_sysPal[i].peFlags  & PC_SYS_RESERVED) )
95       continue;
96
97     r = COLOR_sysPal[i].peRed - GetRValue(col);
98     g = COLOR_sysPal[i].peGreen - GetGValue(col);
99     b = COLOR_sysPal[i].peBlue - GetBValue(col);
100
101     r = r*r + g*g + b*b;
102
103     if( r < diff ) { best = i; diff = r; }
104   }
105   return best;
106 }
107
108 /* Ported from WINE 20020804 (graphics\x11drv\palette.c) */
109 /* Make sure this is required - ROS's xlate may make this redundant */
110 UINT WINAPI GetNearestPaletteIndex(
111     HPALETTE hpalette, /* [in] Handle of logical color palette */
112     COLORREF color)      /* [in] Color to be matched */
113 {
114   PPALOBJ palObj = (PPALOBJ)AccessUserObject(hpalette);
115   UINT    index  = 0;
116
117   if( palObj )
118   {
119     int i, diff = 0x7fffffff;
120     int r,g,b;
121     PALETTEENTRY* entry = palObj->logpalette->palPalEntry;
122
123     for( i = 0; i < palObj->logpalette->palNumEntries && diff ; i++, entry++)
124     {
125       if (!(entry->peFlags & PC_SYS_USED)) continue;
126
127       r = entry->peRed - GetRValue(color);
128       g = entry->peGreen - GetGValue(color);
129       b = entry->peBlue - GetBValue(color);
130
131       r = r*r + g*g + b*b;
132
133       if( r < diff ) { index = i; diff = r; }
134     }
135 //        GDI_ReleaseObj( hpalette );
136   }
137   DPRINT("(%04x,%06lx): returning %d\n", hpalette, color, index );
138   return index;
139 }
140
141 void PALETTE_ValidateFlags(PALETTEENTRY* lpPalE, int size)
142 {
143   int i = 0;
144   for( ; i<size ; i++ )
145     lpPalE[i].peFlags = PC_SYS_USED | (lpPalE[i].peFlags & 0x07);
146 }
147
148 // Set the color-mapping table for selected palette. 
149 // Return number of entries which mapping has changed.
150 int PALETTE_SetMapping(PPALOBJ palPtr, UINT uStart, UINT uNum, BOOL mapOnly)
151 {
152   char flag;
153   int  prevMapping = (palPtr->mapping) ? 1 : 0;
154   int  index, iRemapped = 0;
155   int *mapping;
156
157   // reset dynamic system palette entries
158
159   if( !mapOnly && PALETTE_firstFree != -1) PALETTE_FormatSystemPalette();
160
161   // initialize palette mapping table
162  
163   //mapping = HeapReAlloc( GetProcessHeap(), 0, palPtr->mapping,
164   //                       sizeof(int)*palPtr->logpalette->palNumEntries);
165   ExFreePool(palPtr->mapping);
166   mapping = ExAllocatePool(NonPagedPool, sizeof(int)*palPtr->logpalette->palNumEntries);
167
168   palPtr->mapping = mapping;
169
170   for(uNum += uStart; uStart < uNum; uStart++)
171   {
172     index = -1;
173     flag = PC_SYS_USED;
174
175     switch( palPtr->logpalette->palPalEntry[uStart].peFlags & 0x07 )
176     {
177       case PC_EXPLICIT:   // palette entries are indices into system palette
178                           // The PC_EXPLICIT flag is used to copy an entry from the system palette into the logical palette
179         index = *(WORD*)(palPtr->logpalette->palPalEntry + uStart);
180         if(index > 255 || (index >= COLOR_gapStart && index <= COLOR_gapEnd))
181         {
182           DbgPrint("Win32k: PC_EXPLICIT: idx %d out of system palette, assuming black.\n", index); 
183           index = 0;
184         }
185         break;
186
187       case PC_RESERVED:   // forbid future mappings to this entry
188                           // For palette animation, the entries in the logical palette need the PC_RESERVED flag
189         flag |= PC_SYS_RESERVED;
190
191       // fall through
192       default: // try to collapse identical colors
193         index = COLOR_PaletteLookupExactIndex(COLOR_sysPal, 256,  
194                                               *(COLORREF*)(palPtr->logpalette->palPalEntry + uStart));
195             // fall through
196
197       case PC_NOCOLLAPSE:
198         // If an entry in the logical palette is marked with the PC_NOCOLLAPSE flag, the palette
199         // manager allocates a free entry in the system palette if one is available and only uses the
200         // closest colour match if there are no (more) free entries in the system palette
201
202         DbgPrint("Win32k: WARNING: PC_NOCOLLAPSE is not yet working properly\n");
203
204         if( index < 0 )
205         {
206           if(PALETTE_firstFree > 0 /* && !(PALETTE_PaletteFlags & PALETTE_FIXED) FIXME */ )
207           {
208             DbgPrint("Win32k: Unimplemented Palette Operation: PC_NOCOLLAPSE [objects/palette.c]\n");
209 /*            XColor color;
210             index = PALETTE_firstFree;  // ought to be available
211             PALETTE_firstFree = PALETTE_freeList[index];
212
213             color.pixel = (PALETTE_PaletteToXPixel) ? PALETTE_PaletteToXPixel[index] : index;
214             color.red = palPtr->logpalette->palPalEntry[uStart].peRed << 8;
215             color.green = palPtr->logpalette->palPalEntry[uStart].peGreen << 8;
216             color.blue = palPtr->logpalette->palPalEntry[uStart].peBlue << 8;
217             color.flags = DoRed | DoGreen | DoBlue;
218             TSXStoreColor(display, PALETTE_PaletteXColormap, &color);
219
220             COLOR_sysPal[index] = palPtr->logpalette->palPalEntry[uStart];
221             COLOR_sysPal[index].peFlags = flag;
222             PALETTE_freeList[index] = 0;
223
224             if(PALETTE_PaletteToXPixel) index = PALETTE_PaletteToXPixel[index]; */
225             break;
226           }
227 /*          else if (PALETTE_PaletteFlags & PALETTE_VIRTUAL)
228           {
229             index = PALETTE_ToPhysical(NULL, 0x00ffffff &
230                                        *(COLORREF*)(palPtr->logpalette->palPalEntry + uStart));
231              break;     
232            } FIXME */
233
234            // we have to map to existing entry in the system palette
235
236            index = COLOR_PaletteLookupPixel(COLOR_sysPal, 256, NULL,
237                                             *(COLORREF*)(palPtr->logpalette->palPalEntry + uStart), TRUE);
238            }
239            palPtr->logpalette->palPalEntry[uStart].peFlags |= PC_SYS_USED;
240
241 /*         if(PALETTE_PaletteToXPixel) index = PALETTE_PaletteToXPixel[index]; FIXME */
242            break;
243         }
244
245         if( !prevMapping || palPtr->mapping[uStart] != index ) iRemapped++;
246         palPtr->mapping[uStart] = index;
247
248   }
249   return iRemapped;
250 }
251
252 /* Return the physical color closest to 'color'. */
253 /* Ported from WINE 20020804 (graphics\x11drv\palette.c) */
254 int PALETTE_ToPhysical( PDC dc, COLORREF color )
255 {
256     WORD            index = 0;
257     HPALETTE        hPal = (dc)? dc->w.hPalette: W32kGetStockObject(DEFAULT_PALETTE);
258     unsigned char   spec_type = color >> 24;
259     PPALOBJ         palPtr = (PPALOBJ)AccessUserObject(hPal);
260
261     /* palPtr can be NULL when DC is being destroyed */
262     if( !palPtr ) return 0;
263
264     if ( PALETTE_PaletteFlags & PALETTE_FIXED )
265     {
266         /* there is no colormap limitation; we are going to have to compute
267          * the pixel value from the visual information stored earlier
268          */
269
270         unsigned        long red, green, blue;
271         unsigned        idx = 0;
272
273         switch(spec_type)
274         {
275           case 1: /* PALETTEINDEX */
276
277             if( (idx = color & 0xffff) >= palPtr->logpalette->palNumEntries)
278             {
279                 DPRINT("RGB(%lx) : idx %d is out of bounds, assuming black\n", color, idx);
280 //              GDI_ReleaseObj( hPal );
281                 return 0;
282             }
283
284             if( palPtr->mapping )
285             {
286                 int ret = palPtr->mapping[idx];
287 //              GDI_ReleaseObj( hPal );
288                 return ret;
289             }
290             color = *(COLORREF*)(palPtr->logpalette->palPalEntry + idx);
291             break;
292
293           default:
294             color &= 0xffffff;
295             /* fall through to RGB */
296
297           case 0: /* RGB */
298             if( dc && (dc->w.bitsPerPixel == 1) )
299             {
300 //              GDI_ReleaseObj( hPal );
301                 return (((color >> 16) & 0xff) +
302                         ((color >> 8) & 0xff) + (color & 0xff) > 255*3/2) ? 1 : 0;
303             }
304
305         }
306
307         red = GetRValue(color); green = GetGValue(color); blue = GetBValue(color);
308
309         if (PALETTE_Graymax)
310         {
311             /* grayscale only; return scaled value */
312 //          GDI_ReleaseObj( hPal );
313             return ( (red * 30 + green * 59 + blue * 11) * PALETTE_Graymax) / 25500;
314         }
315         else
316         {
317             /* scale each individually and construct the TrueColor pixel value */
318             if (PALETTE_PRed.scale < 8)
319                 red = red >> (8-PALETTE_PRed.scale);
320             else if (PALETTE_PRed.scale > 8)
321                 red =   red   << (PALETTE_PRed.scale-8) |
322                         red   >> (16-PALETTE_PRed.scale);
323             if (PALETTE_PGreen.scale < 8)
324                 green = green >> (8-PALETTE_PGreen.scale);
325             else if (PALETTE_PGreen.scale > 8)
326                 green = green << (PALETTE_PGreen.scale-8) |
327                         green >> (16-PALETTE_PGreen.scale);
328             if (PALETTE_PBlue.scale < 8)
329                 blue =  blue  >> (8-PALETTE_PBlue.scale);
330             else if (PALETTE_PBlue.scale > 8)
331                 blue =  blue  << (PALETTE_PBlue.scale-8) |
332                         blue  >> (16-PALETTE_PBlue.scale);
333
334 //          GDI_ReleaseObj( hPal );
335             return (red << PALETTE_PRed.shift) | (green << PALETTE_PGreen.shift) | (blue << PALETTE_PBlue.shift);
336         }
337     }
338     else
339     {
340
341         if( !palPtr->mapping )
342             DPRINT("Palette %04x is not realized\n", dc->w.hPalette);
343
344         switch(spec_type)       /* we have to peruse DC and system palette */
345         {
346             default:
347                 color &= 0xffffff;
348                 /* fall through to RGB */
349
350             case 0:  /* RGB */
351                 if( dc && (dc->w.bitsPerPixel == 1) )
352                 {
353 //                  GDI_ReleaseObj( hPal );
354                     return (((color >> 16) & 0xff) +
355                             ((color >> 8) & 0xff) + (color & 0xff) > 255*3/2) ? 1 : 0;
356                 }
357
358                 index = SysPaletteLookupPixel( color, FALSE);
359
360 /*                if (PALETTE_PaletteToXPixel) index = PALETTE_PaletteToXPixel[index]; */
361
362                 /* DPRINT(palette,"RGB(%lx) -> pixel %i\n", color, index);
363                  */
364                 break;
365             case 1:  /* PALETTEINDEX */
366                 index = color & 0xffff;
367
368                 if( index >= palPtr->logpalette->palNumEntries )
369                     DbgPrint("RGB(%lx) : index %i is out of bounds\n", color, index);
370                 else if( palPtr->mapping ) index = palPtr->mapping[index];
371
372                 /*  DPRINT(palette,"PALETTEINDEX(%04x) -> pixel %i\n", (WORD)color, index);
373                  */
374                 break;
375             case 2:  /* PALETTERGB */
376                 index = GetNearestPaletteIndex( hPal, color );
377                 if (palPtr->mapping) index = palPtr->mapping[index];
378                 /* DPRINT(palette,"PALETTERGB(%lx) -> pixel %i\n", color, index);
379                  */
380                 break;
381         }
382     }
383
384 //    GDI_ReleaseObj( hPal );
385     return index;
386 }