Copy riched20
[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$ */
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 { 0xd4, 0xd0, 0xc7, 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 { 0x3a, 0x6e, 0xa5, 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 /* FIXME - Handle PalGDI == NULL!!!! */
127
128 PALETTE_ValidateFlags(PalGDI->IndexedColors, PalGDI->NumColors);
129 PalGDI->logicalToSystem = NULL;
130
131 PALETTE_UnlockPalette(NewPalette);
132
133 return NewPalette;
134 }
135
136 BOOL STDCALL NtGdiGetColorAdjustment(HDC hDC,
137 LPCOLORADJUSTMENT ca)
138 {
139 UNIMPLEMENTED;
140 return FALSE;
141 }
142
143 unsigned short GetNumberOfBits(unsigned int dwMask)
144 {
145 unsigned short wBits;
146 for (wBits = 0; dwMask; dwMask = dwMask & (dwMask - 1))
147 wBits++;
148 return wBits;
149 }
150
151 COLORREF STDCALL NtGdiGetNearestColor(HDC hDC, COLORREF Color)
152 {
153 COLORREF nearest = CLR_INVALID;
154 PDC dc;
155 PPALGDI palGDI;
156 LONG RBits, GBits, BBits;
157
158 dc = DC_LockDc(hDC);
159 if (NULL != dc)
160 {
161 HPALETTE hpal = dc->w.hPalette;
162 palGDI = (PPALGDI) PALETTE_LockPalette(hpal);
163 if (!palGDI)
164 {
165 DC_UnlockDc(hDC);
166 return nearest;
167 }
168
169 switch (palGDI->Mode)
170 {
171 case PAL_INDEXED:
172 nearest = COLOR_LookupNearestColor(palGDI->IndexedColors,
173 palGDI->NumColors, Color);
174 break;
175 case PAL_BGR:
176 case PAL_RGB:
177 nearest = Color;
178 break;
179 case PAL_BITFIELDS:
180 RBits = 8 - GetNumberOfBits(palGDI->RedMask);
181 GBits = 8 - GetNumberOfBits(palGDI->GreenMask);
182 BBits = 8 - GetNumberOfBits(palGDI->BlueMask);
183 nearest = RGB(
184 (GetRValue(Color) >> RBits) << RBits,
185 (GetGValue(Color) >> GBits) << GBits,
186 (GetBValue(Color) >> BBits) << BBits);
187 break;
188 }
189 PALETTE_UnlockPalette(hpal);
190 DC_UnlockDc(hDC);
191 }
192
193 return nearest;
194 }
195
196 UINT STDCALL NtGdiGetNearestPaletteIndex(HPALETTE hpal,
197 COLORREF Color)
198 {
199 PPALGDI palGDI = (PPALGDI) PALETTE_LockPalette(hpal);
200 UINT index = 0;
201
202 if (NULL != palGDI)
203 {
204 /* Return closest match for the given RGB color */
205 index = COLOR_PaletteLookupPixel(palGDI->IndexedColors, palGDI->NumColors, NULL, Color, FALSE);
206 PALETTE_UnlockPalette(hpal);
207 }
208
209 return index;
210 }
211
212 UINT STDCALL NtGdiGetPaletteEntries(HPALETTE hpal,
213 UINT StartIndex,
214 UINT Entries,
215 LPPALETTEENTRY pe)
216 {
217 PPALGDI palGDI;
218 UINT numEntries;
219
220 palGDI = (PPALGDI) PALETTE_LockPalette(hpal);
221 if (NULL == palGDI)
222 {
223 return 0;
224 }
225
226 numEntries = palGDI->NumColors;
227 if (numEntries < StartIndex + Entries)
228 {
229 Entries = numEntries - StartIndex;
230 }
231 if (NULL != pe)
232 {
233 if (numEntries <= StartIndex)
234 {
235 PALETTE_UnlockPalette(hpal);
236 return 0;
237 }
238 memcpy(pe, palGDI->IndexedColors + StartIndex, Entries * sizeof(PALETTEENTRY));
239 for (numEntries = 0; numEntries < Entries; numEntries++)
240 {
241 if (pe[numEntries].peFlags & 0xF0)
242 {
243 pe[numEntries].peFlags = 0;
244 }
245 }
246 }
247
248 PALETTE_UnlockPalette(hpal);
249 return Entries;
250 }
251
252 UINT STDCALL NtGdiGetSystemPaletteEntries(HDC hDC,
253 UINT StartIndex,
254 UINT Entries,
255 LPPALETTEENTRY pe)
256 {
257 //UINT i;
258 //PDC dc;
259 /*
260 if (!(dc = AccessUserObject(hdc))) return 0;
261
262 if (!pe)
263 {
264 Entries = dc->GDIInfo->ulNumPalReg;
265 goto done;
266 }
267
268 if (StartIndex >= dc->GDIInfo->ulNumPalReg)
269 {
270 Entries = 0;
271 goto done;
272 }
273
274 if (StartIndex + Entries >= dc->GDIInfo->ulNumPalReg) Entries = dc->GDIInfo->ulNumPalReg - StartIndex;
275
276 for (i = 0; i < Entries; i++)
277 {
278 *(COLORREF*)(entries + i) = COLOR_GetSystemPaletteEntry(StartIndex + i);
279 }
280
281 done:
282 // GDI_ReleaseObj(hdc);
283 return count; */
284 // FIXME UNIMPLEMENTED;
285 return 0;
286 }
287
288 UINT STDCALL NtGdiGetSystemPaletteUse(HDC hDC)
289 {
290 UNIMPLEMENTED;
291 return 0;
292 }
293
294 /*!
295 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.
296
297 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.
298
299 1= IF DRAWING TO A DEVICE
300 -- If it is a paletted bitmap, and is not an identity palette, then an XLATEOBJ is created between the logical palette and
301 the system palette.
302 -- If it is an RGB palette, then an XLATEOBJ is created between the RGB values and the system palette.
303
304 2= IF DRAWING TO A MEMORY DC\BITMAP
305 -- If it is a paletted bitmap, and is not an identity palette, then an XLATEOBJ is created between the logical palette and
306 the dc palette.
307 -- If it is an RGB palette, then an XLATEOBJ is created between the RGB values and the dc palette.
308 */
309 UINT STDCALL NtGdiRealizePalette(HDC hDC)
310 {
311 /*
312 * This function doesn't do any real work now and there's plenty
313 * of bugd in it (calling SetPalette for high/true-color modes,
314 * using DEFAULT_PALETTE instead of the device palette, ...).
315 */
316 #if 1
317 DPRINT1("NtGdiRealizePalette is unimplemented\n");
318 return 0;
319 #else
320 PALOBJ *palPtr, *sysPtr;
321 PPALGDI palGDI, sysGDI;
322 int realized = 0;
323 PDC dc;
324 HPALETTE systemPalette;
325 SURFOBJ *SurfObj;
326 BOOLEAN success;
327 USHORT sysMode, palMode;
328
329 dc = DC_LockDc(hDC);
330 if (!dc)
331 return 0;
332
333 SurfObj = (SURFOBJ*)AccessUserObject((ULONG)dc->Surface);
334 systemPalette = NtGdiGetStockObject((INT)DEFAULT_PALETTE);
335 palGDI = PALETTE_LockPalette(dc->w.hPalette);
336 palPtr = (PALOBJ*) palGDI;
337 /* FIXME - Handle palGDI == NULL!!!! */
338
339 // Step 1: Create mapping of system palette\DC palette
340 #ifndef NO_MAPPING
341 realized = PALETTE_SetMapping(palPtr, 0, palGDI->NumColors,
342 (dc->w.hPalette != hPrimaryPalette) ||
343 (dc->w.hPalette == NtGdiGetStockObject(DEFAULT_PALETTE)));
344 #else
345 realized = 0;
346 #endif
347
348 sysGDI = PALETTE_LockPalette(systemPalette);
349 sysPtr = (PALOBJ*) sysGDI;
350 /* FIXME - Handle sysGDI == NULL!!!!! */
351
352 // Step 2:
353 // The RealizePalette function modifies the palette for the device associated with the specified device context. If the
354 // device context is a memory DC, the color table for the bitmap selected into the DC is modified. If the device
355 // context is a display DC, the physical palette for that device is modified.
356 if(dc->w.flags == DC_MEMORY)
357 {
358 // Memory managed DC
359 DbgPrint("win32k: realizepalette unimplemented step 2 for DC_MEMORY");
360 } else {
361 if(GDIDEVFUNCS(SurfObj).SetPalette)
362 {
363 ASSERT(sysGDI->NumColors <= 256);
364 success = GDIDEVFUNCS(SurfObj).SetPalette(
365 dc->PDev, sysPtr, 0, 0, sysGDI->NumColors);
366 }
367 }
368
369 // need to pass this to IntEngCreateXlate with palettes unlocked
370 sysMode = sysGDI->Mode;
371 palMode = palGDI->Mode;
372 PALETTE_UnlockPalette(systemPalette);
373 PALETTE_UnlockPalette(dc->w.hPalette);
374
375 // Step 3: Create the XLATEOBJ for device managed DCs
376 if(dc->w.flags != DC_MEMORY)
377 {
378 // Device managed DC
379 palGDI->logicalToSystem = IntEngCreateXlate(sysMode, palMode, systemPalette, dc->w.hPalette);
380 }
381
382 DC_UnlockDc(hDC);
383
384 return realized;
385 #endif
386 }
387
388 BOOL STDCALL NtGdiResizePalette(HPALETTE hpal,
389 UINT Entries)
390 {
391 /* PALOBJ *palPtr = (PALOBJ*)AccessUserObject(hPal);
392 UINT cPrevEnt, prevVer;
393 INT prevsize, size = sizeof(LOGPALETTE) + (cEntries - 1) * sizeof(PALETTEENTRY);
394 XLATEOBJ *XlateObj = NULL;
395
396 if(!palPtr) return FALSE;
397 cPrevEnt = palPtr->logpalette->palNumEntries;
398 prevVer = palPtr->logpalette->palVersion;
399 prevsize = sizeof(LOGPALETTE) + (cPrevEnt - 1) * sizeof(PALETTEENTRY) + sizeof(int*) + sizeof(GDIOBJHDR);
400 size += sizeof(int*) + sizeof(GDIOBJHDR);
401 XlateObj = palPtr->logicalToSystem;
402
403 if (!(palPtr = GDI_ReallocObject(size, hPal, palPtr))) return FALSE;
404
405 if(XlateObj)
406 {
407 XLATEOBJ *NewXlateObj = (int*) HeapReAlloc(GetProcessHeap(), 0, XlateObj, cEntries * sizeof(int));
408 if(NewXlateObj == NULL)
409 {
410 ERR("Can not resize logicalToSystem -- out of memory!");
411 GDI_ReleaseObj( hPal );
412 return FALSE;
413 }
414 palPtr->logicalToSystem = NewXlateObj;
415 }
416
417 if(cEntries > cPrevEnt)
418 {
419 if(XlateObj) memset(palPtr->logicalToSystem + cPrevEnt, 0, (cEntries - cPrevEnt)*sizeof(int));
420 memset( (BYTE*)palPtr + prevsize, 0, size - prevsize );
421 PALETTE_ValidateFlags((PALETTEENTRY*)((BYTE*)palPtr + prevsize), cEntries - cPrevEnt );
422 }
423 palPtr->logpalette->palNumEntries = cEntries;
424 palPtr->logpalette->palVersion = prevVer;
425 // GDI_ReleaseObj( hPal );
426 return TRUE; */
427
428 UNIMPLEMENTED;
429 return FALSE;
430 }
431
432 /*!
433 * Select logical palette into device context.
434 * \param hDC handle to the device context
435 * \param hpal handle to the palette
436 * \param ForceBackground If this value is FALSE the logical palette will be copied to the device palette only when the applicatioon
437 * is in the foreground. If this value is TRUE then map the colors in the logical palette to the device
438 * palette colors in the best way.
439 * \return old palette
440 *
441 * \todo implement ForceBackground == TRUE
442 */
443 HPALETTE STDCALL NtGdiSelectPalette(HDC hDC,
444 HPALETTE hpal,
445 BOOL ForceBackground)
446 {
447 PDC dc;
448 HPALETTE oldPal = NULL;
449 PPALGDI PalGDI;
450
451 // FIXME: mark the palette as a [fore\back]ground pal
452 dc = DC_LockDc(hDC);
453 if (NULL != dc)
454 {
455 /* Check if this is a valid palette handle */
456 PalGDI = PALETTE_LockPalette(hpal);
457 if (NULL != PalGDI)
458 {
459 /* Is this a valid palette for this depth? */
460 if ((dc->w.bitsPerPixel <= 8 && PAL_INDEXED == PalGDI->Mode)
461 || (8 < dc->w.bitsPerPixel && PAL_INDEXED != PalGDI->Mode))
462 {
463 PALETTE_UnlockPalette(hpal);
464 oldPal = dc->w.hPalette;
465 dc->w.hPalette = hpal;
466 }
467 else
468 {
469 PALETTE_UnlockPalette(hpal);
470 oldPal = NULL;
471 }
472 }
473 else
474 {
475 oldPal = NULL;
476 }
477 DC_UnlockDc(hDC);
478 }
479
480 return oldPal;
481 }
482
483 BOOL STDCALL NtGdiSetColorAdjustment(HDC hDC,
484 CONST LPCOLORADJUSTMENT ca)
485 {
486 UNIMPLEMENTED;
487 return FALSE;
488 }
489
490 UINT STDCALL NtGdiSetPaletteEntries(HPALETTE hpal,
491 UINT Start,
492 UINT Entries,
493 CONST LPPALETTEENTRY pe)
494 {
495 PPALGDI palGDI;
496 WORD numEntries;
497
498 palGDI = PALETTE_LockPalette(hpal);
499 if (!palGDI) return 0;
500
501 numEntries = palGDI->NumColors;
502 if (Start >= numEntries)
503 {
504 PALETTE_UnlockPalette(hpal);
505 return 0;
506 }
507 if (numEntries < Start + Entries)
508 {
509 Entries = numEntries - Start;
510 }
511 memcpy(palGDI->IndexedColors + Start, pe, Entries * sizeof(PALETTEENTRY));
512 PALETTE_ValidateFlags(palGDI->IndexedColors, palGDI->NumColors);
513 ExFreePool(palGDI->logicalToSystem);
514 palGDI->logicalToSystem = NULL;
515 PALETTE_UnlockPalette(hpal);
516
517 return Entries;
518 }
519
520 UINT STDCALL
521 NtGdiSetSystemPaletteUse(HDC hDC, UINT Usage)
522 {
523 UNIMPLEMENTED;
524 return 0;
525 }
526
527 BOOL STDCALL
528 NtGdiUnrealizeObject(HGDIOBJ hgdiobj)
529 {
530 UNIMPLEMENTED;
531 return FALSE;
532 }
533
534 BOOL STDCALL
535 NtGdiUpdateColors(HDC hDC)
536 {
537 HWND hWnd;
538
539 hWnd = (HWND)NtUserCallOneParam((DWORD)hDC, ONEPARAM_ROUTINE_WINDOWFROMDC);
540 if (hWnd == NULL)
541 {
542 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
543 return FALSE;
544 }
545 return NtUserRedrawWindow(hWnd, NULL, 0, RDW_INVALIDATE);
546 }
547
548 INT STDCALL COLOR_PaletteLookupPixel(PALETTEENTRY *palPalEntry, INT size,
549 XLATEOBJ *XlateObj, COLORREF col, BOOL skipReserved)
550 {
551 int i, best = 0, diff = 0x7fffffff;
552 int r, g, b;
553
554 for( i = 0; i < size && diff ; i++ )
555 {
556 #if 0
557 if(!(palPalEntry[i].peFlags & PC_SYS_USED) || (skipReserved && palPalEntry[i].peFlags & PC_SYS_RESERVED))
558 continue;
559 #endif
560
561 r = abs((SHORT)palPalEntry[i].peRed - GetRValue(col));
562 g = abs((SHORT)palPalEntry[i].peGreen - GetGValue(col));
563 b = abs((SHORT)palPalEntry[i].peBlue - GetBValue(col));
564
565 r = r*r + g*g + b*b;
566
567 if( r < diff ) { best = i; diff = r; }
568 }
569
570 if (XlateObj == NULL)
571 return best;
572 else
573 return (XlateObj->pulXlate) ? (INT)XlateObj->pulXlate[best] : best;
574 }
575
576 COLORREF STDCALL COLOR_LookupNearestColor( PALETTEENTRY* palPalEntry, int size, COLORREF color )
577 {
578 INT index;
579
580 index = COLOR_PaletteLookupPixel(palPalEntry, size, NULL, color, FALSE);
581 return RGB(
582 palPalEntry[index].peRed,
583 palPalEntry[index].peGreen,
584 palPalEntry[index].peBlue);
585 }
586
587 int STDCALL COLOR_PaletteLookupExactIndex( PALETTEENTRY* palPalEntry, int size,
588 COLORREF col )
589 {
590 int i;
591 BYTE r = GetRValue(col), g = GetGValue(col), b = GetBValue(col);
592 for( i = 0; i < size; i++ )
593 {
594 if( palPalEntry[i].peFlags & PC_SYS_USED ) /* skips gap */
595 if(palPalEntry[i].peRed == r && palPalEntry[i].peGreen == g && palPalEntry[i].peBlue == b) return i;
596 }
597 return -1;
598 }
599 /* EOF */