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