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