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