Now checks that the GCP_REORDER flag is set before trying to access
[wine] / objects / palette.c
1 /*
2  * GDI palette objects
3  *
4  * Copyright 1993,1994 Alexandre Julliard
5  * Copyright 1996 Alex Korobka
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  *
21  * NOTES:
22  * PALETTEOBJ is documented in the Dr. Dobbs Journal May 1993.
23  * Information in the "Undocumented Windows" is incorrect.
24  */
25
26 #include <stdlib.h>
27 #include <string.h>
28
29 #include "winbase.h"
30 #include "windef.h"
31 #include "wingdi.h"
32 #include "wine/winuser16.h"
33 #include "gdi.h"
34 #include "palette.h"
35 #include "wine/debug.h"
36 #include "winerror.h"
37
38 WINE_DEFAULT_DEBUG_CHANNEL(palette);
39
40 static INT PALETTE_GetObject( HGDIOBJ handle, void *obj, INT count, LPVOID buffer );
41 static BOOL PALETTE_UnrealizeObject( HGDIOBJ handle, void *obj );
42 static BOOL PALETTE_DeleteObject( HGDIOBJ handle, void *obj );
43
44 static const struct gdi_obj_funcs palette_funcs =
45 {
46     NULL,                     /* pSelectObject */
47     PALETTE_GetObject,        /* pGetObject16 */
48     PALETTE_GetObject,        /* pGetObjectA */
49     PALETTE_GetObject,        /* pGetObjectW */
50     PALETTE_UnrealizeObject,  /* pUnrealizeObject */
51     PALETTE_DeleteObject      /* pDeleteObject */
52 };
53
54 /* Pointers to USER implementation of SelectPalette/RealizePalette */
55 /* they will be patched by USER on startup */
56 FARPROC pfnSelectPalette = NULL;
57 FARPROC pfnRealizePalette = NULL;
58
59 static UINT SystemPaletteUse = SYSPAL_STATIC;  /* currently not considered */
60
61 static HPALETTE hPrimaryPalette = 0; /* used for WM_PALETTECHANGED */
62 static HPALETTE hLastRealizedPalette = 0; /* UnrealizeObject() needs it */
63 static const DC_FUNCTIONS *pLastRealizedDC;
64
65 static const PALETTEENTRY sys_pal_template[NB_RESERVED_COLORS] =
66 {
67     /* first 10 entries in the system palette */
68     /* red  green blue  flags */
69     { 0x00, 0x00, 0x00, 0 },
70     { 0x80, 0x00, 0x00, 0 },
71     { 0x00, 0x80, 0x00, 0 },
72     { 0x80, 0x80, 0x00, 0 },
73     { 0x00, 0x00, 0x80, 0 },
74     { 0x80, 0x00, 0x80, 0 },
75     { 0x00, 0x80, 0x80, 0 },
76     { 0xc0, 0xc0, 0xc0, 0 },
77     { 0xc0, 0xdc, 0xc0, 0 },
78     { 0xa6, 0xca, 0xf0, 0 },
79
80     /* ... c_min/2 dynamic colorcells */
81
82     /* ... gap (for sparse palettes) */
83
84     /* ... c_min/2 dynamic colorcells */
85
86     { 0xff, 0xfb, 0xf0, 0 },
87     { 0xa0, 0xa0, 0xa4, 0 },
88     { 0x80, 0x80, 0x80, 0 },
89     { 0xff, 0x00, 0x00, 0 },
90     { 0x00, 0xff, 0x00, 0 },
91     { 0xff, 0xff, 0x00, 0 },
92     { 0x00, 0x00, 0xff, 0 },
93     { 0xff, 0x00, 0xff, 0 },
94     { 0x00, 0xff, 0xff, 0 },
95     { 0xff, 0xff, 0xff, 0 }     /* last 10 */
96 };
97
98 /***********************************************************************
99  *           PALETTE_Init
100  *
101  * Create the system palette.
102  */
103 HPALETTE16 PALETTE_Init(void)
104 {
105     HPALETTE16          hpalette;
106     LOGPALETTE *        palPtr;
107     PALETTEOBJ*         palObj;
108
109     /* create default palette (20 system colors) */
110
111     palPtr = HeapAlloc( GetProcessHeap(), 0,
112              sizeof(LOGPALETTE) + (NB_RESERVED_COLORS-1)*sizeof(PALETTEENTRY));
113     if (!palPtr) return FALSE;
114
115     palPtr->palVersion = 0x300;
116     palPtr->palNumEntries = NB_RESERVED_COLORS;
117     memcpy( palPtr->palPalEntry, sys_pal_template, sizeof(sys_pal_template) );
118     hpalette = CreatePalette16( palPtr );
119     HeapFree( GetProcessHeap(), 0, palPtr );
120
121     palObj = (PALETTEOBJ*) GDI_GetObjPtr( hpalette, PALETTE_MAGIC );
122     if (palObj)
123     {
124         if (!(palObj->mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(int) * NB_RESERVED_COLORS )))
125             ERR("Can not create palette mapping -- out of memory!\n");
126         GDI_ReleaseObj( hpalette );
127     }
128     return hpalette;
129 }
130
131 /***********************************************************************
132  *           PALETTE_ValidateFlags
133  */
134 static void PALETTE_ValidateFlags(PALETTEENTRY* lpPalE, int size)
135 {
136     int i = 0;
137     for( ; i<size ; i++ )
138         lpPalE[i].peFlags = PC_SYS_USED | (lpPalE[i].peFlags & 0x07);
139 }
140
141
142 /***********************************************************************
143  *           CreatePalette    (GDI.360)
144  */
145 HPALETTE16 WINAPI CreatePalette16( const LOGPALETTE* palette )
146 {
147     return CreatePalette( palette );
148 }
149
150
151 /***********************************************************************
152  * CreatePalette [GDI32.@]  Creates a logical color palette
153  *
154  * RETURNS
155  *    Success: Handle to logical palette
156  *    Failure: NULL
157  */
158 HPALETTE WINAPI CreatePalette(
159     const LOGPALETTE* palette) /* [in] Pointer to logical color palette */
160 {
161     PALETTEOBJ * palettePtr;
162     HPALETTE hpalette;
163     int size;
164
165     if (!palette) return 0;
166     TRACE("entries=%i\n", palette->palNumEntries);
167
168     size = sizeof(LOGPALETTE) + (palette->palNumEntries - 1) * sizeof(PALETTEENTRY);
169
170     if (!(palettePtr = GDI_AllocObject( size + sizeof(int*) +sizeof(GDIOBJHDR),
171                                         PALETTE_MAGIC, &hpalette, &palette_funcs ))) return 0;
172     memcpy( &palettePtr->logpalette, palette, size );
173     PALETTE_ValidateFlags(palettePtr->logpalette.palPalEntry,
174                           palettePtr->logpalette.palNumEntries);
175     palettePtr->mapping = NULL;
176     GDI_ReleaseObj( hpalette );
177
178     TRACE("   returning %04x\n", hpalette);
179     return hpalette;
180 }
181
182
183 /***********************************************************************
184  * CreateHalftonePalette [GDI.529]  Creates a halftone palette
185  *
186  * RETURNS
187  *    Success: Handle to logical halftone palette
188  *    Failure: 0
189  */
190 HPALETTE16 WINAPI CreateHalftonePalette16(
191     HDC16 hdc) /* [in] Handle to device context */
192 {
193     return CreateHalftonePalette(hdc);
194 }
195
196
197 /***********************************************************************
198  * CreateHalftonePalette [GDI32.@]  Creates a halftone palette
199  *
200  * RETURNS
201  *    Success: Handle to logical halftone palette
202  *    Failure: 0
203  *
204  * FIXME: This simply creates the halftone palette dirived from runing
205  *        tests on an windows NT machine. this is assuming a color depth
206  *        of greater that 256 color. On a 256 color device the halftone
207  *        palette will be differnt and this funtion will be incorrect
208  */
209 HPALETTE WINAPI CreateHalftonePalette(
210     HDC hdc) /* [in] Handle to device context */
211 {
212     int i;
213     struct {
214         WORD Version;
215         WORD NumberOfEntries;
216         PALETTEENTRY aEntries[256];
217     } Palette;
218
219     Palette.Version = 0x300;
220     Palette.NumberOfEntries = 256;
221     GetSystemPaletteEntries(hdc, 0, 256, Palette.aEntries);
222
223     Palette.NumberOfEntries = 20;
224
225     for (i = 0; i < Palette.NumberOfEntries; i++)
226     {
227         Palette.aEntries[i].peRed=0xff;
228         Palette.aEntries[i].peGreen=0xff;
229         Palette.aEntries[i].peBlue=0xff;
230         Palette.aEntries[i].peFlags=0x00;
231     }
232
233     Palette.aEntries[0].peRed=0x00;
234     Palette.aEntries[0].peBlue=0x00;
235     Palette.aEntries[0].peGreen=0x00;
236
237     /* the first 6 */
238     for (i=1; i <= 6; i++)
239     {
240         Palette.aEntries[i].peRed=(i%2)?0x80:0;
241         Palette.aEntries[i].peGreen=(i==2)?0x80:(i==3)?0x80:(i==6)?0x80:0;
242         Palette.aEntries[i].peBlue=(i>3)?0x80:0;
243     }
244
245     for (i=7;  i <= 12; i++)
246     {
247         switch(i)
248         {
249             case 7:
250                 Palette.aEntries[i].peRed=0xc0;
251                 Palette.aEntries[i].peBlue=0xc0;
252                 Palette.aEntries[i].peGreen=0xc0;
253                 break;
254             case 8:
255                 Palette.aEntries[i].peRed=0xc0;
256                 Palette.aEntries[i].peGreen=0xdc;
257                 Palette.aEntries[i].peBlue=0xc0;
258                 break;
259             case 9:
260                 Palette.aEntries[i].peRed=0xa6;
261                 Palette.aEntries[i].peGreen=0xca;
262                 Palette.aEntries[i].peBlue=0xf0;
263                 break;
264             case 10:
265                 Palette.aEntries[i].peRed=0xff;
266                 Palette.aEntries[i].peGreen=0xfb;
267                 Palette.aEntries[i].peBlue=0xf0;
268                 break;
269             case 11:
270                 Palette.aEntries[i].peRed=0xa0;
271                 Palette.aEntries[i].peGreen=0xa0;
272                 Palette.aEntries[i].peBlue=0xa4;
273                 break;
274             case 12:
275                 Palette.aEntries[i].peRed=0x80;
276                 Palette.aEntries[i].peGreen=0x80;
277                 Palette.aEntries[i].peBlue=0x80;
278         }
279     }
280
281    for (i=13; i <= 18; i++)
282     {
283         Palette.aEntries[i].peRed=(i%2)?0xff:0;
284         Palette.aEntries[i].peGreen=(i==14)?0xff:(i==15)?0xff:(i==18)?0xff:0;
285         Palette.aEntries[i].peBlue=(i>15)?0xff:0x00;
286     }
287
288     return CreatePalette((LOGPALETTE *)&Palette);
289 }
290
291
292 /***********************************************************************
293  *           GetPaletteEntries    (GDI.363)
294  */
295 UINT16 WINAPI GetPaletteEntries16( HPALETTE16 hpalette, UINT16 start,
296                                    UINT16 count, LPPALETTEENTRY entries )
297 {
298     return GetPaletteEntries( hpalette, start, count, entries );
299 }
300
301
302 /***********************************************************************
303  * GetPaletteEntries [GDI32.@]  Retrieves palette entries
304  *
305  * RETURNS
306  *    Success: Number of entries from logical palette
307  *    Failure: 0
308  */
309 UINT WINAPI GetPaletteEntries(
310     HPALETTE hpalette,    /* [in]  Handle of logical palette */
311     UINT start,           /* [in]  First entry to receive */
312     UINT count,           /* [in]  Number of entries to receive */
313     LPPALETTEENTRY entries) /* [out] Address of array receiving entries */
314 {
315     PALETTEOBJ * palPtr;
316     UINT numEntries;
317
318     TRACE("hpal = %04x, count=%i\n", hpalette, count );
319
320     palPtr = (PALETTEOBJ *) GDI_GetObjPtr( hpalette, PALETTE_MAGIC );
321     if (!palPtr) return 0;
322
323     /* NOTE: not documented but test show this to be the case */
324     if (count == 0)
325     {
326         int rc = palPtr->logpalette.palNumEntries;
327             GDI_ReleaseObj( hpalette );
328         return rc;
329     }
330
331     numEntries = palPtr->logpalette.palNumEntries;
332     if (start+count > numEntries) count = numEntries - start;
333     if (entries)
334     {
335       if (start >= numEntries)
336       {
337         GDI_ReleaseObj( hpalette );
338         return 0;
339       }
340       memcpy( entries, &palPtr->logpalette.palPalEntry[start],
341               count * sizeof(PALETTEENTRY) );
342       for( numEntries = 0; numEntries < count ; numEntries++ )
343            if (entries[numEntries].peFlags & 0xF0)
344                entries[numEntries].peFlags = 0;
345     }
346
347     GDI_ReleaseObj( hpalette );
348     return count;
349 }
350
351
352 /***********************************************************************
353  *           SetPaletteEntries    (GDI.364)
354  */
355 UINT16 WINAPI SetPaletteEntries16( HPALETTE16 hpalette, UINT16 start,
356                                    UINT16 count, const PALETTEENTRY *entries )
357 {
358     return SetPaletteEntries( hpalette, start, count, entries );
359 }
360
361
362 /***********************************************************************
363  * SetPaletteEntries [GDI32.@]  Sets color values for range in palette
364  *
365  * RETURNS
366  *    Success: Number of entries that were set
367  *    Failure: 0
368  */
369 UINT WINAPI SetPaletteEntries(
370     HPALETTE hpalette,    /* [in] Handle of logical palette */
371     UINT start,           /* [in] Index of first entry to set */
372     UINT count,           /* [in] Number of entries to set */
373     const PALETTEENTRY *entries) /* [in] Address of array of structures */
374 {
375     PALETTEOBJ * palPtr;
376     UINT numEntries;
377
378     TRACE("hpal=%04x,start=%i,count=%i\n",hpalette,start,count );
379
380     if (hpalette == GetStockObject(DEFAULT_PALETTE)) return 0;
381     palPtr = (PALETTEOBJ *) GDI_GetObjPtr( hpalette, PALETTE_MAGIC );
382     if (!palPtr) return 0;
383
384     numEntries = palPtr->logpalette.palNumEntries;
385     if (start >= numEntries)
386     {
387       GDI_ReleaseObj( hpalette );
388       return 0;
389     }
390     if (start+count > numEntries) count = numEntries - start;
391     memcpy( &palPtr->logpalette.palPalEntry[start], entries,
392             count * sizeof(PALETTEENTRY) );
393     PALETTE_ValidateFlags(palPtr->logpalette.palPalEntry,
394                           palPtr->logpalette.palNumEntries);
395     UnrealizeObject( hpalette );
396     GDI_ReleaseObj( hpalette );
397     return count;
398 }
399
400
401 /***********************************************************************
402  *           ResizePalette   (GDI.368)
403  */
404 BOOL16 WINAPI ResizePalette16( HPALETTE16 hPal, UINT16 cEntries )
405 {
406     return ResizePalette( hPal, cEntries );
407 }
408
409
410 /***********************************************************************
411  * ResizePalette [GDI32.@]  Resizes logical palette
412  *
413  * RETURNS
414  *    Success: TRUE
415  *    Failure: FALSE
416  */
417 BOOL WINAPI ResizePalette(
418     HPALETTE hPal, /* [in] Handle of logical palette */
419     UINT cEntries) /* [in] Number of entries in logical palette */
420 {
421     PALETTEOBJ * palPtr = (PALETTEOBJ *) GDI_GetObjPtr( hPal, PALETTE_MAGIC );
422     UINT         cPrevEnt, prevVer;
423     int          prevsize, size = sizeof(LOGPALETTE) + (cEntries - 1) * sizeof(PALETTEENTRY);
424     int*         mapping = NULL;
425
426     TRACE("hpal = %04x, prev = %i, new = %i\n",
427                     hPal, palPtr ? palPtr->logpalette.palNumEntries : -1,
428                     cEntries );
429     if( !palPtr ) return FALSE;
430     cPrevEnt = palPtr->logpalette.palNumEntries;
431     prevVer = palPtr->logpalette.palVersion;
432     prevsize = sizeof(LOGPALETTE) + (cPrevEnt - 1) * sizeof(PALETTEENTRY) +
433                                         sizeof(int*) + sizeof(GDIOBJHDR);
434     size += sizeof(int*) + sizeof(GDIOBJHDR);
435     mapping = palPtr->mapping;
436
437     if (!(palPtr = GDI_ReallocObject( size, hPal, palPtr ))) return FALSE;
438
439     if( mapping )
440     {
441         int *newMap = (int*) HeapReAlloc(GetProcessHeap(), 0,
442                                     mapping, cEntries * sizeof(int) );
443         if(newMap == NULL)
444         {
445             ERR("Can not resize mapping -- out of memory!\n");
446             GDI_ReleaseObj( hPal );
447             return FALSE;
448         }
449         palPtr->mapping = newMap;
450     }
451
452     if( cEntries > cPrevEnt )
453     {
454         if( mapping )
455             memset(palPtr->mapping + cPrevEnt, 0, (cEntries - cPrevEnt)*sizeof(int));
456         memset( (BYTE*)palPtr + prevsize, 0, size - prevsize );
457         PALETTE_ValidateFlags((PALETTEENTRY*)((BYTE*)palPtr + prevsize),
458                                                      cEntries - cPrevEnt );
459     }
460     palPtr->logpalette.palNumEntries = cEntries;
461     palPtr->logpalette.palVersion = prevVer;
462     GDI_ReleaseObj( hPal );
463     return TRUE;
464 }
465
466
467 /***********************************************************************
468  *           AnimatePalette   (GDI.367)
469  */
470 void WINAPI AnimatePalette16( HPALETTE16 hPal, UINT16 StartIndex,
471                               UINT16 NumEntries, const PALETTEENTRY* PaletteColors)
472 {
473     AnimatePalette( hPal, StartIndex, NumEntries, PaletteColors );
474 }
475
476
477 /***********************************************************************
478  * AnimatePalette [GDI32.@]  Replaces entries in logical palette
479  *
480  * RETURNS
481  *    Success: TRUE
482  *    Failure: FALSE
483  *
484  * FIXME
485  *    Should use existing mapping when animating a primary palette
486  */
487 BOOL WINAPI AnimatePalette(
488     HPALETTE hPal,              /* [in] Handle to logical palette */
489     UINT StartIndex,            /* [in] First entry in palette */
490     UINT NumEntries,            /* [in] Count of entries in palette */
491     const PALETTEENTRY* PaletteColors) /* [in] Pointer to first replacement */
492 {
493     TRACE("%04x (%i - %i)\n", hPal, StartIndex,StartIndex+NumEntries);
494
495     if( hPal != GetStockObject(DEFAULT_PALETTE) )
496     {
497         if (!SetPaletteEntries( hPal, StartIndex, NumEntries, PaletteColors )) return FALSE;
498
499         if (pLastRealizedDC && pLastRealizedDC->pRealizePalette)
500             pLastRealizedDC->pRealizePalette( NULL, hPal, hPal == hPrimaryPalette );
501     }
502     return TRUE;
503 }
504
505
506 /***********************************************************************
507  *           SetSystemPaletteUse   (GDI.373)
508  */
509 UINT16 WINAPI SetSystemPaletteUse16( HDC16 hdc, UINT16 use )
510 {
511     return SetSystemPaletteUse( hdc, use );
512 }
513
514
515 /***********************************************************************
516  * SetSystemPaletteUse [GDI32.@]
517  *
518  * RETURNS
519  *    Success: Previous system palette
520  *    Failure: SYSPAL_ERROR
521  */
522 UINT WINAPI SetSystemPaletteUse(
523     HDC hdc,  /* [in] Handle of device context */
524     UINT use) /* [in] Palette-usage flag */
525 {
526     UINT old = SystemPaletteUse;
527     FIXME("(%04x,%04x): stub\n", hdc, use );
528     SystemPaletteUse = use;
529     return old;
530 }
531
532
533 /***********************************************************************
534  *           GetSystemPaletteUse   (GDI.374)
535  */
536 UINT16 WINAPI GetSystemPaletteUse16( HDC16 hdc )
537 {
538     return SystemPaletteUse;
539 }
540
541
542 /***********************************************************************
543  * GetSystemPaletteUse [GDI32.@]  Gets state of system palette
544  *
545  * RETURNS
546  *    Current state of system palette
547  */
548 UINT WINAPI GetSystemPaletteUse(
549     HDC hdc) /* [in] Handle of device context */
550 {
551     return SystemPaletteUse;
552 }
553
554
555 /***********************************************************************
556  *           GetSystemPaletteEntries   (GDI.375)
557  */
558 UINT16 WINAPI GetSystemPaletteEntries16( HDC16 hdc, UINT16 start, UINT16 count,
559                                          LPPALETTEENTRY entries )
560 {
561     return GetSystemPaletteEntries( hdc, start, count, entries );
562 }
563
564
565 /***********************************************************************
566  * GetSystemPaletteEntries [GDI32.@]  Gets range of palette entries
567  *
568  * RETURNS
569  *    Success: Number of entries retrieved from palette
570  *    Failure: 0
571  */
572 UINT WINAPI GetSystemPaletteEntries(
573     HDC hdc,              /* [in]  Handle of device context */
574     UINT start,           /* [in]  Index of first entry to be retrieved */
575     UINT count,           /* [in]  Number of entries to be retrieved */
576     LPPALETTEENTRY entries) /* [out] Array receiving system-palette entries */
577 {
578     UINT ret = 0;
579     DC *dc;
580
581     TRACE("hdc=%04x,start=%i,count=%i\n", hdc,start,count);
582
583     if ((dc = DC_GetDCPtr( hdc )))
584     {
585         if (dc->funcs->pGetSystemPaletteEntries)
586             ret = dc->funcs->pGetSystemPaletteEntries( dc->physDev, start, count, entries );
587         GDI_ReleaseObj( hdc );
588     }
589     return ret;
590 }
591
592
593 /***********************************************************************
594  *           GetNearestPaletteIndex   (GDI.370)
595  */
596 UINT16 WINAPI GetNearestPaletteIndex16( HPALETTE16 hpalette, COLORREF color )
597 {
598     return GetNearestPaletteIndex( hpalette, color );
599 }
600
601
602 /***********************************************************************
603  * GetNearestPaletteIndex [GDI32.@]  Gets palette index for color
604  *
605  * NOTES
606  *    Should index be initialized to CLR_INVALID instead of 0?
607  *
608  * RETURNS
609  *    Success: Index of entry in logical palette
610  *    Failure: CLR_INVALID
611  */
612 UINT WINAPI GetNearestPaletteIndex(
613     HPALETTE hpalette, /* [in] Handle of logical color palette */
614     COLORREF color)      /* [in] Color to be matched */
615 {
616     PALETTEOBJ* palObj = (PALETTEOBJ*)GDI_GetObjPtr( hpalette, PALETTE_MAGIC );
617     UINT index  = 0;
618
619     if( palObj )
620     {
621         int i, diff = 0x7fffffff;
622         int r,g,b;
623         PALETTEENTRY* entry = palObj->logpalette.palPalEntry;
624
625         for( i = 0; i < palObj->logpalette.palNumEntries && diff ; i++, entry++)
626         {
627             if (!(entry->peFlags & PC_SYS_USED)) continue;
628
629             r = entry->peRed - GetRValue(color);
630             g = entry->peGreen - GetGValue(color);
631             b = entry->peBlue - GetBValue(color);
632
633             r = r*r + g*g + b*b;
634
635             if( r < diff ) { index = i; diff = r; }
636         }
637         GDI_ReleaseObj( hpalette );
638     }
639     TRACE("(%04x,%06lx): returning %d\n", hpalette, color, index );
640     return index;
641 }
642
643
644 /***********************************************************************
645  *           GetNearestColor   (GDI.154)
646  */
647 COLORREF WINAPI GetNearestColor16( HDC16 hdc, COLORREF color )
648 {
649     return GetNearestColor( hdc, color );
650 }
651
652
653 /***********************************************************************
654  * GetNearestColor [GDI32.@]  Gets a system color to match
655  *
656  * RETURNS
657  *    Success: Color from system palette that corresponds to given color
658  *    Failure: CLR_INVALID
659  */
660 COLORREF WINAPI GetNearestColor(
661     HDC hdc,      /* [in] Handle of device context */
662     COLORREF color) /* [in] Color to be matched */
663 {
664     unsigned char spec_type;
665     COLORREF nearest;
666     DC          *dc;
667
668     if (!(dc = DC_GetDCPtr( hdc ))) return CLR_INVALID;
669
670     if (dc->funcs->pGetNearestColor)
671     {
672         nearest = dc->funcs->pGetNearestColor( dc->physDev, color );
673         GDI_ReleaseObj( hdc );
674         return nearest;
675     }
676
677     if (!(GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE))
678     {
679         GDI_ReleaseObj( hdc );
680         return color;
681     }
682
683     spec_type = color >> 24;
684     if (spec_type == 1 || spec_type == 2)
685     {
686         /* we need logical palette for PALETTERGB and PALETTEINDEX colorrefs */
687
688         UINT index;
689         PALETTEENTRY entry;
690         HPALETTE hpal = dc->hPalette ? dc->hPalette : GetStockObject( DEFAULT_PALETTE );
691
692         if (spec_type == 2) /* PALETTERGB */
693             index = GetNearestPaletteIndex( hpal, color );
694         else  /* PALETTEINDEX */
695             index = LOWORD(color);
696
697         if (!GetPaletteEntries( hpal, index, 1, &entry ))
698         {
699             WARN("RGB(%lx) : idx %d is out of bounds, assuming NULL\n", color, index );
700             if (!GetPaletteEntries( hpal, 0, 1, &entry ))
701             {
702                 GDI_ReleaseObj( hdc );
703                 return CLR_INVALID;
704             }
705         }
706         color = RGB( entry.peRed, entry.peGreen, entry.peBlue );
707     }
708     nearest = color & 0x00ffffff;
709     GDI_ReleaseObj( hdc );
710
711     TRACE("(%06lx): returning %06lx\n", color, nearest );
712     return nearest;
713 }
714
715
716 /***********************************************************************
717  *           PALETTE_GetObject
718  */
719 static INT PALETTE_GetObject( HGDIOBJ handle, void *obj, INT count, LPVOID buffer )
720 {
721     PALETTEOBJ *palette = obj;
722
723     if (count > sizeof(WORD)) count = sizeof(WORD);
724     memcpy( buffer, &palette->logpalette.palNumEntries, count );
725     return count;
726 }
727
728
729 /***********************************************************************
730  *           PALETTE_UnrealizeObject
731  */
732 static BOOL PALETTE_UnrealizeObject( HGDIOBJ handle, void *obj )
733 {
734     PALETTEOBJ *palette = obj;
735
736     if (palette->mapping)
737     {
738         HeapFree( GetProcessHeap(), 0, palette->mapping );
739         palette->mapping = NULL;
740     }
741     if (hLastRealizedPalette == handle)
742     {
743         hLastRealizedPalette = 0;
744         pLastRealizedDC = NULL;
745     }
746     return TRUE;
747 }
748
749
750 /***********************************************************************
751  *           PALETTE_DeleteObject
752  */
753 static BOOL PALETTE_DeleteObject( HGDIOBJ handle, void *obj )
754 {
755     PALETTEOBJ *palette = obj;
756
757     HeapFree( GetProcessHeap(), 0, palette->mapping );
758     if (hLastRealizedPalette == handle)
759     {
760         hLastRealizedPalette = 0;
761         pLastRealizedDC = NULL;
762     }
763     return GDI_FreeObject( handle, obj );
764 }
765
766
767 /***********************************************************************
768  *           GDISelectPalette    (GDI.361)
769  */
770 HPALETTE16 WINAPI GDISelectPalette16( HDC16 hdc, HPALETTE16 hpal, WORD wBkg)
771 {
772     HPALETTE16 prev;
773     DC *dc;
774
775     TRACE("%04x %04x\n", hdc, hpal );
776
777     if (GetObjectType(hpal) != OBJ_PAL)
778     {
779       WARN("invalid selected palette %04x\n",hpal);
780       return 0;
781     }
782     if (!(dc = DC_GetDCPtr( hdc ))) return 0;
783     prev = dc->hPalette;
784     dc->hPalette = hpal;
785     GDI_ReleaseObj( hdc );
786     if (!wBkg) hPrimaryPalette = hpal;
787     return prev;
788 }
789
790
791 /***********************************************************************
792  *           GDIRealizePalette    (GDI.362)
793  */
794 UINT16 WINAPI GDIRealizePalette16( HDC16 hdc )
795 {
796     UINT realized = 0;
797     DC* dc = DC_GetDCPtr( hdc );
798
799     if (!dc) return 0;
800
801     TRACE("%04x...\n", hdc );
802
803     if( dc->hPalette == GetStockObject( DEFAULT_PALETTE ))
804     {
805         GDI_ReleaseObj( hdc );
806         return RealizeDefaultPalette16( hdc );
807     }
808
809     if(dc->hPalette != hLastRealizedPalette )
810     {
811         if (dc->funcs->pRealizePalette)
812             realized = dc->funcs->pRealizePalette( dc->physDev, dc->hPalette,
813                                                    (dc->hPalette == hPrimaryPalette) );
814         hLastRealizedPalette = dc->hPalette;
815         pLastRealizedDC = dc->funcs;
816     }
817     else TRACE("  skipping (hLastRealizedPalette = %04x)\n", hLastRealizedPalette);
818     GDI_ReleaseObj( hdc );
819
820     TRACE("   realized %i colors.\n", realized );
821     return (UINT16)realized;
822 }
823
824
825 /***********************************************************************
826  *           RealizeDefaultPalette    (GDI.365)
827  */
828 UINT16 WINAPI RealizeDefaultPalette16( HDC16 hdc )
829 {
830     UINT16 ret = 0;
831     DC          *dc;
832
833     TRACE("%04x\n", hdc );
834
835     if (!(dc = DC_GetDCPtr( hdc ))) return 0;
836
837     if (dc->funcs->pRealizeDefaultPalette) ret = dc->funcs->pRealizeDefaultPalette( dc->physDev );
838     GDI_ReleaseObj( hdc );
839     return ret;
840 }
841
842 /***********************************************************************
843  *           IsDCCurrentPalette   (GDI.412)
844  */
845 BOOL16 WINAPI IsDCCurrentPalette16(HDC16 hDC)
846 {
847     DC *dc = DC_GetDCPtr( hDC );
848     if (dc)
849     {
850       BOOL bRet = dc->hPalette == hPrimaryPalette;
851       GDI_ReleaseObj( hDC );
852       return bRet;
853     }
854     return FALSE;
855 }
856
857
858 /***********************************************************************
859  * SelectPalette [GDI32.@]  Selects logical palette into DC
860  *
861  * RETURNS
862  *    Success: Previous logical palette
863  *    Failure: NULL
864  */
865 HPALETTE WINAPI SelectPalette(
866     HDC hDC,               /* [in] Handle of device context */
867     HPALETTE hPal,         /* [in] Handle of logical color palette */
868     BOOL bForceBackground) /* [in] Foreground/background mode */
869 {
870     return pfnSelectPalette( hDC, hPal, bForceBackground );
871 }
872
873
874 /***********************************************************************
875  * RealizePalette [GDI32.@]  Maps palette entries to system palette
876  *
877  * RETURNS
878  *    Success: Number of entries in logical palette
879  *    Failure: GDI_ERROR
880  */
881 UINT WINAPI RealizePalette(
882     HDC hDC) /* [in] Handle of device context */
883 {
884     return pfnRealizePalette( hDC );
885 }
886
887
888 typedef HWND (WINAPI *WindowFromDC_funcptr)( HDC );
889 typedef BOOL (WINAPI *RedrawWindow_funcptr)( HWND, const RECT *, HRGN, UINT );
890
891 /**********************************************************************
892  * UpdateColors [GDI32.@]  Remaps current colors to logical palette
893  *
894  * RETURNS
895  *    Success: TRUE
896  *    Failure: FALSE
897  */
898 BOOL WINAPI UpdateColors(
899     HDC hDC) /* [in] Handle of device context */
900 {
901     HMODULE mod;
902     int size = GetDeviceCaps( hDC, SIZEPALETTE );
903
904     if (!size) return 0;
905
906     mod = GetModuleHandleA("user32.dll");
907     if (mod)
908     {
909         WindowFromDC_funcptr pWindowFromDC = (WindowFromDC_funcptr)GetProcAddress(mod,"WindowFromDC");
910         if (pWindowFromDC)
911         {
912             HWND hWnd = pWindowFromDC( hDC );
913
914             /* Docs say that we have to remap current drawable pixel by pixel
915              * but it would take forever given the speed of XGet/PutPixel.
916              */
917             if (hWnd && size)
918             {
919                 RedrawWindow_funcptr pRedrawWindow = GetProcAddress( mod, "RedrawWindow" );
920                 if (pRedrawWindow) pRedrawWindow( hWnd, NULL, 0, RDW_INVALIDATE );
921             }
922         }
923     }
924     return 0x666;
925 }
926
927
928 /**********************************************************************
929  *            UpdateColors   (GDI.366)
930  */
931 INT16 WINAPI UpdateColors16( HDC16 hDC )
932 {
933     UpdateColors( hDC );
934     return TRUE;
935 }
936
937
938 /*********************************************************************
939  *           SetMagicColors   (GDI.606)
940  */
941 VOID WINAPI SetMagicColors16(HDC16 hDC, COLORREF color, UINT16 index)
942 {
943     FIXME("(hDC %04x, color %04x, index %04x): stub\n", hDC, (int)color, index);
944
945 }
946
947 /**********************************************************************
948  * GetICMProfileA [GDI32.@]
949  *
950  * Returns the filename of the specified device context's color
951  * management profile, even if color management is not enabled
952  * for that DC.
953  *
954  * RETURNS
955  *    TRUE if name copied succesfully OR lpszFilename is NULL
956  *    FALSE if the buffer length pointed to by lpcbName is too small
957  *
958  * NOTE
959  *    The buffer length pointed to by lpcbName is ALWAYS updated to
960  *    the length required regardless of other actions this function
961  *    may take.
962  *
963  * FIXME
964  *    How does Windows assign these?  Some registry key?
965  */
966
967 #define WINEICM "winefake.icm"  /* easy-to-identify fake filename */
968
969 /*********************************************************************/
970
971 BOOL WINAPI GetICMProfileA(HDC hDC, LPDWORD lpcbName, LPSTR lpszFilename)
972 {
973     DWORD callerLen;
974
975     FIXME("(%04x, %p, %p): partial stub\n", hDC, lpcbName, lpszFilename);
976
977     callerLen = *lpcbName;
978
979     /* all 3 behaviors require the required buffer size to be set */
980     *lpcbName = strlen(WINEICM);
981
982     /* behavior 1: if lpszFilename is NULL, return size of string and no error */
983     if ((DWORD)lpszFilename == (DWORD)0x00000000)
984         return TRUE;
985
986     /* behavior 2: if buffer size too small, return size of string and error */
987     if (callerLen < strlen(WINEICM))
988     {
989         SetLastError(ERROR_INSUFFICIENT_BUFFER);
990         return FALSE;
991     }
992
993     /* behavior 3: if buffer size OK and pointer not NULL, copy and return size */
994     strcpy(lpszFilename, WINEICM);
995     return TRUE;
996 }