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