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