branch update for HEAD-2003050101
[reactos.git] / subsys / win32k / objects / color.c
1 // FIXME: Use PXLATEOBJ logicalToSystem instead of int *mapping
2
3 #undef WIN32_LEAN_AND_MEAN
4 #include <windows.h>
5 #include <ddk/ntddk.h>
6 #include <ddk/winddi.h>
7 #include <win32k/brush.h>
8 #include <win32k/dc.h>
9 #include <win32k/color.h>
10 #include <win32k/pen.h>
11 #include "../eng/handle.h"
12 #include <include/inteng.h>
13
14 #define NDEBUG
15 #include <win32k/debug1.h>
16
17 int COLOR_gapStart = 256;
18 int COLOR_gapEnd = -1;
19 int COLOR_gapFilled = 0;
20 int COLOR_max = 256;
21
22 static HPALETTE hPrimaryPalette = 0; // used for WM_PALETTECHANGED
23 static HPALETTE hLastRealizedPalette = 0; // UnrealizeObject() needs it
24
25 const PALETTEENTRY COLOR_sysPalTemplate[NB_RESERVED_COLORS] =
26 {
27   // first 10 entries in the system palette
28   // red  green blue  flags
29   { 0x00, 0x00, 0x00, PC_SYS_USED },
30   { 0x80, 0x00, 0x00, PC_SYS_USED },
31   { 0x00, 0x80, 0x00, PC_SYS_USED },
32   { 0x80, 0x80, 0x00, PC_SYS_USED },
33   { 0x00, 0x00, 0x80, PC_SYS_USED },
34   { 0x80, 0x00, 0x80, PC_SYS_USED },
35   { 0x00, 0x80, 0x80, PC_SYS_USED },
36   { 0xc0, 0xc0, 0xc0, PC_SYS_USED },
37   { 0xc0, 0xdc, 0xc0, PC_SYS_USED },
38   { 0xa6, 0xca, 0xf0, PC_SYS_USED },
39
40   // ... c_min/2 dynamic colorcells
41   // ... gap (for sparse palettes)
42   // ... c_min/2 dynamic colorcells
43
44   { 0xff, 0xfb, 0xf0, PC_SYS_USED },
45   { 0xa0, 0xa0, 0xa4, PC_SYS_USED },
46   { 0x80, 0x80, 0x80, PC_SYS_USED },
47   { 0xff, 0x00, 0x00, PC_SYS_USED },
48   { 0x00, 0xff, 0x00, PC_SYS_USED },
49   { 0xff, 0xff, 0x00, PC_SYS_USED },
50   { 0x00, 0x00, 0xff, PC_SYS_USED },
51   { 0xff, 0x00, 0xff, PC_SYS_USED },
52   { 0x00, 0xff, 0xff, PC_SYS_USED },
53   { 0xff, 0xff, 0xff, PC_SYS_USED }     // last 10
54 };
55
56 ULONG W32kGetSysColor(int nIndex)
57 {
58    PALETTEENTRY *p = COLOR_sysPalTemplate + (nIndex * sizeof(PALETTEENTRY));
59    return RGB(p->peRed, p->peGreen, p->peBlue);
60 }
61
62 HPEN STDCALL W32kGetSysColorPen(int nIndex)
63 {
64   COLORREF Col;
65   memcpy(&Col, COLOR_sysPalTemplate + nIndex, sizeof(COLORREF));
66   return(W32kCreatePen(PS_SOLID, 1, Col));
67 }
68
69 HBRUSH STDCALL W32kGetSysColorBrush(int nIndex)
70 {
71   COLORREF Col;
72   memcpy(&Col, COLOR_sysPalTemplate + nIndex, sizeof(COLORREF));
73   return(W32kCreateSolidBrush(Col));
74 }
75
76 //forward declarations
77 COLORREF COLOR_LookupNearestColor( PALETTEENTRY* palPalEntry, int size, COLORREF color );
78
79
80 const PALETTEENTRY* COLOR_GetSystemPaletteTemplate(void)
81 {
82   return (const PALETTEENTRY*)&COLOR_sysPalTemplate;
83 }
84
85 BOOL STDCALL W32kAnimatePalette(HPALETTE  hpal,
86                          UINT  StartIndex,
87                          UINT  Entries,
88                          CONST PPALETTEENTRY  ppe)
89 {
90 /*
91   if( hPal != W32kGetStockObject(DEFAULT_PALETTE) )
92   {
93     PALETTEOBJ* palPtr = (PALETTEOBJ *)GDI_GetObjPtr(hPal, PALETTE_MAGIC);
94     if (!palPtr) return FALSE;
95
96     if( (StartIndex + NumEntries) <= palPtr->logpalette.palNumEntries )
97     {
98       UINT u;
99       for( u = 0; u < NumEntries; u++ )
100         palPtr->logpalette.palPalEntry[u + StartIndex] = PaletteColors[u];
101       PALETTE_Driver->pSetMapping(palPtr, StartIndex, NumEntries, hPal != hPrimaryPalette );
102       GDI_ReleaseObj(hPal);
103       return TRUE;
104     }
105     GDI_ReleaseObj(hPal);
106   }
107   return FALSE;
108 */
109   UNIMPLEMENTED;
110 }
111
112 HPALETTE STDCALL W32kCreateHalftonePalette(HDC  hDC)
113 {
114   int i, r, g, b;
115   struct {
116     WORD Version;
117     WORD NumberOfEntries;
118     PALETTEENTRY aEntries[256];
119   } Palette;
120
121   Palette.Version = 0x300;
122   Palette.NumberOfEntries = 256;
123   W32kGetSystemPaletteEntries(hDC, 0, 256, Palette.aEntries);
124
125   for (r = 0; r < 6; r++) {
126     for (g = 0; g < 6; g++) {
127       for (b = 0; b < 6; b++) {
128         i = r + g*6 + b*36 + 10;
129         Palette.aEntries[i].peRed = r * 51;
130         Palette.aEntries[i].peGreen = g * 51;
131         Palette.aEntries[i].peBlue = b * 51;
132       }
133      }
134    }
135
136   for (i = 216; i < 246; i++) {
137     int v = (i - 216) * 8;
138     Palette.aEntries[i].peRed = v;
139     Palette.aEntries[i].peGreen = v;
140     Palette.aEntries[i].peBlue = v;
141   }
142
143   return W32kCreatePalette((LOGPALETTE *)&Palette);
144 }
145
146 HPALETTE STDCALL W32kCreatePalette(CONST PLOGPALETTE palette)
147 {
148   PPALOBJ  PalObj;
149
150   HPALETTE NewPalette = (HPALETTE)EngCreatePalette(PAL_INDEXED, palette->palNumEntries, (PULONG*) palette->palPalEntry, 0, 0, 0);
151   ULONG size;
152
153   PalObj = (PPALOBJ)AccessUserObject(NewPalette);
154
155   size = sizeof(LOGPALETTE) + (palette->palNumEntries * sizeof(PALETTEENTRY));
156   PalObj->logpalette = ExAllocatePool(NonPagedPool, size);
157   memcpy(PalObj->logpalette, palette, size);
158   PALETTE_ValidateFlags(PalObj->logpalette->palPalEntry, PalObj->logpalette->palNumEntries);
159   PalObj->logicalToSystem = NULL;
160
161   return NewPalette;
162 }
163
164 BOOL STDCALL W32kGetColorAdjustment(HDC  hDC,
165                              LPCOLORADJUSTMENT  ca)
166 {
167   UNIMPLEMENTED;
168 }
169
170 COLORREF STDCALL W32kGetNearestColor(HDC  hDC,
171                               COLORREF  Color)
172 {
173   COLORREF nearest = CLR_INVALID;
174   PDC dc;
175   PPALOBJ palObj;
176
177   if( (dc = DC_HandleToPtr(hDC) ) )
178   {
179     HPALETTE hpal = (dc->w.hPalette)? dc->w.hPalette : W32kGetStockObject(DEFAULT_PALETTE);
180     palObj = (PPALOBJ)AccessUserObject(hpal);
181     if (!palObj) {
182 //      GDI_ReleaseObj(hdc);
183       return nearest;
184     }
185
186     nearest = COLOR_LookupNearestColor(palObj->logpalette->palPalEntry,
187                                        palObj->logpalette->palNumEntries, Color);
188         // FIXME: release hpal!!
189 //    GDI_ReleaseObj( hpal );
190     DC_ReleasePtr( hDC );
191   }
192
193   return nearest;
194 }
195
196 UINT STDCALL W32kGetNearestPaletteIndex(HPALETTE  hpal,
197                                  COLORREF  Color)
198 {
199   PPALOBJ     palObj = (PPALOBJ)AccessUserObject(hpal);
200   UINT index  = 0;
201
202   if( palObj )
203   {
204     // Return closest match for the given RGB color
205     index = COLOR_PaletteLookupPixel(palObj->logpalette->palPalEntry, palObj->logpalette->palNumEntries, NULL, Color, FALSE);
206 //    GDI_ReleaseObj( hpalette );
207   }
208
209   return index;
210 }
211
212 UINT STDCALL W32kGetPaletteEntries(HPALETTE  hpal,
213                             UINT  StartIndex,
214                             UINT  Entries,
215                             LPPALETTEENTRY  pe)
216 {
217   PPALOBJ palPtr;
218   UINT numEntries;
219
220   palPtr = (PPALOBJ)AccessUserObject(hpal);
221   if (!palPtr) return 0;
222
223   numEntries = palPtr->logpalette->palNumEntries;
224   if (StartIndex + Entries > numEntries) Entries = numEntries - StartIndex;
225   if (pe)
226   {
227     if (StartIndex >= numEntries)
228     {
229 //      GDI_ReleaseObj( hpalette );
230       return 0;
231     }
232     memcpy(pe, &palPtr->logpalette->palPalEntry[StartIndex], Entries * sizeof(PALETTEENTRY));
233     for(numEntries = 0; numEntries < Entries ; numEntries++)
234       if (pe[numEntries].peFlags & 0xF0)
235         pe[numEntries].peFlags = 0;
236   }
237
238 //  GDI_ReleaseObj( hpalette );
239   return Entries;
240 }
241
242 UINT STDCALL W32kGetSystemPaletteEntries(HDC  hDC,
243                                   UINT  StartIndex,
244                                   UINT  Entries,
245                                   LPPALETTEENTRY  pe)
246 {
247   UINT i;
248   PDC dc;
249 /*
250   if (!(dc = AccessUserObject(hdc))) return 0;
251
252   if (!pe)
253   {
254     Entries = dc->devCaps->sizePalette;
255     goto done;
256   }
257
258   if (StartIndex >= dc->devCaps->sizePalette)
259   {
260     Entries = 0;
261     goto done;
262   }
263
264   if (StartIndex + Entries >= dc->devCaps->sizePalette) Entries = dc->devCaps->sizePalette - StartIndex;
265
266   for (i = 0; i < Entries; i++)
267   {
268     *(COLORREF*)(entries + i) = COLOR_GetSystemPaletteEntry(StartIndex + i);
269   }
270
271   done:
272 //    GDI_ReleaseObj(hdc);
273   return count; */
274 }
275
276 UINT STDCALL W32kGetSystemPaletteUse(HDC  hDC)
277 {
278   UNIMPLEMENTED;
279 }
280
281 /*!
282 The RealizePalette function modifies the palette for the device associated with the specified device context. If the device context is a memory DC, the color table for the bitmap selected into the DC is modified. If the device context is a display DC, the physical palette for that device is modified.
283
284 A logical palette is a buffer between color-intensive applications and the system, allowing these applications to use as many colors as needed without interfering with colors displayed by other windows.
285
286 1= IF DRAWING TO A DEVICE
287 -- If it is a paletted bitmap, and is not an identity palette, then an XLATEOBJ is created between the logical palette and
288    the system palette.
289 -- If it is an RGB palette, then an XLATEOBJ is created between the RGB values and the system palette.
290
291 2= IF DRAWING TO A MEMORY DC\BITMAP
292 -- If it is a paletted bitmap, and is not an identity palette, then an XLATEOBJ is created between the logical palette and
293    the dc palette.
294 -- If it is an RGB palette, then an XLATEOBJ is created between the RGB values and the dc palette.
295 */
296 UINT STDCALL W32kRealizePalette(HDC  hDC)
297 {
298   PPALOBJ palPtr, sysPtr;
299   PPALGDI palGDI, sysGDI;
300   int realized = 0;
301   PDC dc;
302   HPALETTE systemPalette;
303   PSURFGDI SurfGDI;
304   BOOLEAN success;
305
306   dc = DC_HandleToPtr(hDC);
307   if (!dc)
308         return 0;
309
310   palPtr = (PPALOBJ)AccessUserObject(dc->w.hPalette);
311   SurfGDI = (PSURFGDI)AccessInternalObjectFromUserObject(dc->Surface);
312   systemPalette = W32kGetStockObject(STOCK_DEFAULT_PALETTE);
313   sysPtr = (PPALOBJ)AccessInternalObject(systemPalette);
314   palGDI = (PPALGDI)AccessInternalObject(dc->w.hPalette);
315   sysGDI = (PPALGDI)AccessInternalObject(systemPalette);
316
317   // Step 1: Create mapping of system palette\DC palette
318   realized = PALETTE_SetMapping(palPtr, 0, palPtr->logpalette->palNumEntries,
319                (dc->w.hPalette != hPrimaryPalette) ||
320                (dc->w.hPalette == W32kGetStockObject(DEFAULT_PALETTE)));
321
322   // Step 2:
323   // The RealizePalette function modifies the palette for the device associated with the specified device context. If the
324   // device context is a memory DC, the color table for the bitmap selected into the DC is modified. If the device
325   // context is a display DC, the physical palette for that device is modified.
326   if(dc->w.flags == DC_MEMORY)
327   {
328     // Memory managed DC
329     DbgPrint("win32k: realizepalette unimplemented step 2 for DC_MEMORY");
330   } else {
331     if(SurfGDI->SetPalette)
332     {
333       success = SurfGDI->SetPalette(dc->PDev, sysPtr, 0, 0, sysPtr->logpalette->palNumEntries);
334     }
335   }
336
337   // Step 3: Create the XLATEOBJ for device managed DCs
338   if(dc->w.flags != DC_MEMORY)
339   {
340     // Device managed DC
341     palPtr->logicalToSystem = IntEngCreateXlate(sysGDI->Mode, palGDI->Mode, systemPalette, dc->w.hPalette);
342   }
343
344 //  GDI_ReleaseObj(dc->w.hPalette);
345 //  GDI_ReleaseObj(hdc);
346
347   return realized;
348 }
349
350 BOOL STDCALL W32kResizePalette(HPALETTE  hpal,
351                         UINT  Entries)
352 {
353 /*  PPALOBJ palPtr = (PPALOBJ)AccessUserObject(hPal);
354   UINT cPrevEnt, prevVer;
355   INT prevsize, size = sizeof(LOGPALETTE) + (cEntries - 1) * sizeof(PALETTEENTRY);
356   PXLATEOBJ XlateObj = NULL;
357
358   if(!palPtr) return FALSE;
359   cPrevEnt = palPtr->logpalette->palNumEntries;
360   prevVer = palPtr->logpalette->palVersion;
361   prevsize = sizeof(LOGPALETTE) + (cPrevEnt - 1) * sizeof(PALETTEENTRY) + sizeof(int*) + sizeof(GDIOBJHDR);
362   size += sizeof(int*) + sizeof(GDIOBJHDR);
363   XlateObj = palPtr->logicalToSystem;
364
365   if (!(palPtr = GDI_ReallocObject(size, hPal, palPtr))) return FALSE;
366
367   if(XlateObj)
368   {
369     PXLATEOBJ NewXlateObj = (int*) HeapReAlloc(GetProcessHeap(), 0, XlateObj, cEntries * sizeof(int));
370     if(NewXlateObj == NULL)
371     {
372       ERR("Can not resize logicalToSystem -- out of memory!");
373       GDI_ReleaseObj( hPal );
374       return FALSE;
375     }
376     palPtr->logicalToSystem = NewXlateObj;
377   }
378
379   if(cEntries > cPrevEnt)
380   {
381     if(XlateObj) memset(palPtr->logicalToSystem + cPrevEnt, 0, (cEntries - cPrevEnt)*sizeof(int));
382     memset( (BYTE*)palPtr + prevsize, 0, size - prevsize );
383     PALETTE_ValidateFlags((PALETTEENTRY*)((BYTE*)palPtr + prevsize), cEntries - cPrevEnt );
384   }
385   palPtr->logpalette->palNumEntries = cEntries;
386   palPtr->logpalette->palVersion = prevVer;
387 //    GDI_ReleaseObj( hPal );
388   return TRUE; */
389
390   UNIMPLEMENTED;
391 }
392
393 /*!
394  * Select logical palette into device context.
395  * \param       hDC                             handle to the device context
396  * \param       hpal                            handle to the palette
397  * \param       ForceBackground         If this value is FALSE the logical palette will be copied to the device palette only when the applicatioon
398  *                                                              is in the foreground. If this value is TRUE then map the colors in the logical palette to the device
399  *                                                              palette colors in the best way.
400  * \return      old palette
401  *
402  * \todo        implement ForceBackground == TRUE
403 */
404 HPALETTE STDCALL W32kSelectPalette(HDC  hDC,
405                             HPALETTE  hpal,
406                             BOOL  ForceBackground)
407 {
408   PDC dc;
409   HPALETTE oldPal;
410
411   // FIXME: mark the palette as a [fore\back]ground pal
412   dc = DC_HandleToPtr(hDC);
413   if( dc ){
414         oldPal = dc->w.hPalette;
415         dc->w.hPalette = hpal;
416         DC_ReleasePtr( hDC );
417   }
418
419   return oldPal;
420 }
421
422 BOOL STDCALL W32kSetColorAdjustment(HDC  hDC,
423                              CONST LPCOLORADJUSTMENT  ca)
424 {
425   UNIMPLEMENTED;
426 }
427
428 UINT STDCALL W32kSetPaletteEntries(HPALETTE  hpal,
429                             UINT  Start,
430                             UINT  Entries,
431                             CONST LPPALETTEENTRY  pe)
432 {
433   PPALOBJ palPtr;
434   INT numEntries;
435
436   palPtr = (PPALOBJ)AccessUserObject(hpal);
437   if (!palPtr) return 0;
438
439   numEntries = palPtr->logpalette->palNumEntries;
440   if (Start >= numEntries)
441   {
442 //    GDI_ReleaseObj( hpalette );
443     return 0;
444   }
445   if (Start + Entries > numEntries) Entries = numEntries - Start;
446   memcpy(&palPtr->logpalette->palPalEntry[Start], pe, Entries * sizeof(PALETTEENTRY));
447   PALETTE_ValidateFlags(palPtr->logpalette->palPalEntry, palPtr->logpalette->palNumEntries);
448   ExFreePool(palPtr->logicalToSystem);
449   palPtr->logicalToSystem = NULL;
450 //  GDI_ReleaseObj( hpalette );
451   return Entries;
452 }
453
454 UINT STDCALL W32kSetSystemPaletteUse(HDC  hDC,
455                               UINT  Usage)
456 {
457   UNIMPLEMENTED;
458 }
459
460 BOOL STDCALL W32kUnrealizeObject(HGDIOBJ  hgdiobj)
461 {
462   UNIMPLEMENTED;
463 }
464
465 BOOL STDCALL W32kUpdateColors(HDC  hDC)
466 {
467   PDC dc;
468   HWND hWnd;
469   int size;
470 /*
471   if (!(dc = AccessUserObject(hDC))) return 0;
472   size = dc->devCaps->sizePalette;
473 //  GDI_ReleaseObj( hDC );
474
475   if (Callout.WindowFromDC)
476   {
477     hWnd = Callout.WindowFromDC( hDC );
478
479     // Docs say that we have to remap current drawable pixel by pixel
480     // but it would take forever given the speed of XGet/PutPixel.
481     if (hWnd && size) Callout.RedrawWindow( hWnd, NULL, 0, RDW_INVALIDATE );
482   } */
483   return 0x666;
484 }
485
486 int COLOR_PaletteLookupPixel(PALETTEENTRY *palPalEntry, int size,
487                              PXLATEOBJ XlateObj, COLORREF col, BOOL skipReserved)
488 {
489   int i, best = 0, diff = 0x7fffffff;
490   int r, g, b;
491
492   for( i = 0; i < size && diff ; i++ )
493   {
494     if(!(palPalEntry[i].peFlags & PC_SYS_USED) || (skipReserved && palPalEntry[i].peFlags  & PC_SYS_RESERVED))
495       continue;
496
497     r = palPalEntry[i].peRed - GetRValue(col);
498     g = palPalEntry[i].peGreen - GetGValue(col);
499     b = palPalEntry[i].peBlue - GetBValue(col);
500
501     r = r*r + g*g + b*b;
502
503     if( r < diff ) { best = i; diff = r; }
504   }
505   return (XlateObj->pulXlate) ? XlateObj->pulXlate[best] : best;
506 }
507
508 COLORREF COLOR_LookupNearestColor( PALETTEENTRY* palPalEntry, int size, COLORREF color )
509 {
510   unsigned char spec_type = color >> 24;
511   int i;
512   PALETTEENTRY *COLOR_sysPal = (PALETTEENTRY*)ReturnSystemPalette();
513
514   // we need logical palette for PALETTERGB and PALETTEINDEX colorrefs
515
516   if( spec_type == 2 ) /* PALETTERGB */
517     color = *(COLORREF*)(palPalEntry + COLOR_PaletteLookupPixel(palPalEntry,size,NULL,color,FALSE));
518
519   else if( spec_type == 1 ) /* PALETTEINDEX */
520   {
521     if( (i = color & 0x0000ffff) >= size )
522     {
523       DbgPrint("RGB(%lx) : idx %d is out of bounds, assuming NULL\n", color, i);
524       color = *(COLORREF*)palPalEntry;
525     }
526     else color = *(COLORREF*)(palPalEntry + i);
527   }
528
529   color &= 0x00ffffff;
530   return (0x00ffffff & *(COLORREF*)(COLOR_sysPal + COLOR_PaletteLookupPixel(COLOR_sysPal, 256, NULL, color, FALSE)));
531 }
532
533 int COLOR_PaletteLookupExactIndex( PALETTEENTRY* palPalEntry, int size,
534                                    COLORREF col )
535 {
536   int i;
537   BYTE r = GetRValue(col), g = GetGValue(col), b = GetBValue(col);
538   for( i = 0; i < size; i++ )
539   {
540     if( palPalEntry[i].peFlags & PC_SYS_USED )  /* skips gap */
541       if(palPalEntry[i].peRed == r && palPalEntry[i].peGreen == g && palPalEntry[i].peBlue == b) return i;
542   }
543   return -1;
544 }