branch update for HEAD-2003021201
[reactos.git] / subsys / win32k / eng / xlate.c
1 /*
2  * COPYRIGHT:        See COPYING in the top level directory
3  * PROJECT:          ReactOS kernel
4  * PURPOSE:          GDI Color Translation Functions
5  * FILE:             subsys/win32k/eng/xlate.c
6  * PROGRAMER:        Jason Filby
7  * REVISION HISTORY:
8  *        8/20/1999: Created
9  */
10
11 // TODO: Cache XLATEOBJs that are created by EngCreateXlate by checking if the given palettes match a cached list
12
13 #include <ddk/ntddk.h>
14 #include <ddk/winddi.h>
15 #include <ddk/ntddvid.h>
16
17 #include <include/object.h>
18 #include "handle.h"
19
20 //#define NDEBUG
21 #include <win32k/debug1.h>
22
23 ULONG CCMLastSourceColor = 0, CCMLastColorMatch = 0;
24
25 ULONG RGBtoULONG(BYTE Red, BYTE Green, BYTE Blue)
26 {
27   return ((Red & 0xff) << 16) | ((Green & 0xff) << 8) | (Blue & 0xff);
28 }
29
30 ULONG BGRtoULONG(BYTE Blue, BYTE Green, BYTE Red)
31 {
32   return ((Blue & 0xff) << 16) | ((Green & 0xff) << 8) | (Red & 0xff);
33 }
34
35
36 // FIXME: If the caller knows that the destinations are indexed and not RGB
37 // then we should cache more than one value. Same with the source.
38
39 // Takes indexed palette and a
40 ULONG ClosestColorMatch(ULONG SourceColor, ULONG *DestColors,
41                         ULONG NumColors)
42 {
43   PVIDEO_CLUTDATA cSourceColor;
44   PVIDEO_CLUTDATA cDestColors;
45   LONG idx = 0, i, rt;
46   ULONG cxRed, cxGreen, cxBlue, BestMatch = 16777215;
47
48   // Simple cache -- only one value because we don't want to waste time
49   // if the colors aren't very sequential
50
51   if(SourceColor == CCMLastSourceColor)
52   {
53     return CCMLastColorMatch;
54   }
55
56   cSourceColor = (PVIDEO_CLUTDATA)&SourceColor;
57   for (i=0; i<NumColors; i++)
58   {
59     cDestColors = (PVIDEO_CLUTDATA)&DestColors[i];
60
61     cxRed = (cSourceColor->Red - cDestColors->Red);
62         cxRed *= cxRed;  //compute cxRed squared
63     cxGreen = (cSourceColor->Green - cDestColors->Green);
64         cxGreen *= cxGreen;
65     cxBlue = (cSourceColor->Blue - cDestColors->Blue);
66         cxBlue *= cxBlue;
67
68     rt = /* sqrt */ (cxRed + cxGreen + cxBlue);
69
70     if(rt<=BestMatch)
71     {
72       idx = i;
73       BestMatch = rt;
74     }
75   }
76
77   CCMLastSourceColor = SourceColor;
78   CCMLastColorMatch  = idx;
79
80   return idx;
81 }
82
83 VOID IndexedToIndexedTranslationTable(ULONG *TranslationTable,
84                                       PALGDI *PalDest, PALGDI *PalSource)
85 {
86   ULONG i;
87
88   for(i=0; i<PalSource->NumColors; i++)
89   {
90     TranslationTable[i] = ClosestColorMatch(PalSource->IndexedColors[i], PalDest->IndexedColors, PalDest->NumColors);
91   }
92 }
93
94 XLATEOBJ *EngCreateXlate(USHORT DestPalType, USHORT SourcePalType,
95                          HPALETTE PaletteDest, HPALETTE PaletteSource)
96 {
97   // FIXME: Add support for BGR conversions
98
99   HPALETTE NewXlate;
100   XLATEOBJ *XlateObj;
101   XLATEGDI *XlateGDI;
102   PALGDI   *SourcePalGDI, *DestPalGDI;
103   ULONG    IndexedColors;
104
105   NewXlate = (HPALETTE)CreateGDIHandle(sizeof( XLATEGDI ), sizeof( XLATEOBJ ));
106   if( !ValidEngHandle( NewXlate ) )
107         return NULL;
108
109   XlateObj = (XLATEOBJ*) AccessUserObject( NewXlate );
110   XlateGDI = (XLATEGDI*) AccessInternalObject( NewXlate );
111   ASSERT( XlateObj );
112   ASSERT( XlateGDI );
113
114   if(SourcePalType == PAL_INDEXED)
115     SourcePalGDI = (PALGDI*)AccessInternalObject((ULONG)PaletteSource);
116   if(DestPalType == PAL_INDEXED)
117     DestPalGDI = (PALGDI*)AccessInternalObject((ULONG)PaletteDest);
118
119   XlateObj->iSrcType = SourcePalType;
120   XlateObj->iDstType = DestPalType;
121
122   // Store handles of palettes in internal Xlate GDI object (or NULLs)
123   XlateGDI->DestPal   = PaletteDest;
124   XlateGDI->SourcePal = PaletteSource;
125
126   XlateObj->flXlate = 0;
127
128   // If source and destination palettes are the same or if they're RGB/BGR
129   if( (PaletteDest == PaletteSource) ||
130       ((DestPalType == PAL_RGB) && (SourcePalType == PAL_RGB)) ||
131       ((DestPalType == PAL_BGR) && (SourcePalType == PAL_BGR)) )
132   {
133     XlateObj->flXlate |= XO_TRIVIAL;
134     return XlateObj;
135   }
136
137   // Prepare the translation table
138   if( (SourcePalType == PAL_INDEXED) || (SourcePalType == PAL_RGB) )
139   {
140     XlateObj->flXlate |= XO_TABLE;
141     if ((SourcePalType == PAL_INDEXED) && (DestPalType == PAL_INDEXED))
142     {
143       if(SourcePalGDI->NumColors > DestPalGDI->NumColors)
144       {
145         IndexedColors = SourcePalGDI->NumColors;
146       } else
147         IndexedColors = DestPalGDI->NumColors;
148     }
149     else if (SourcePalType == PAL_INDEXED) { IndexedColors = SourcePalGDI->NumColors; }
150     else if (DestPalType   == PAL_INDEXED) { IndexedColors = DestPalGDI->NumColors; }
151
152     XlateGDI->translationTable = EngAllocMem(FL_ZERO_MEMORY, sizeof(ULONG)*IndexedColors, 0);
153   }
154
155   // Source palette is indexed
156   if(XlateObj->iSrcType == PAL_INDEXED)
157   {
158     if(XlateObj->iDstType == PAL_INDEXED)
159     {
160       // Converting from indexed to indexed
161       IndexedToIndexedTranslationTable(XlateGDI->translationTable, DestPalGDI, SourcePalGDI);
162     } else
163       if(XlateObj->iDstType == PAL_RGB)
164       {
165         // FIXME: Is this necessary? I think the driver has to call this
166         // function anyways if pulXlate is NULL and Source is PAL_INDEXED
167
168         // Converting from indexed to RGB
169
170         XLATEOBJ_cGetPalette(XlateObj, XO_SRCPALETTE,
171                              SourcePalGDI->NumColors,
172                              XlateGDI->translationTable);
173       }
174
175     XlateObj->pulXlate = XlateGDI->translationTable;
176   }
177
178   // Source palette is RGB
179   if(XlateObj->iSrcType == PAL_RGB)
180   {
181     if(XlateObj->iDstType == PAL_INDEXED)
182     {
183       // FIXME: Is this necessary? I think the driver has to call this
184       // function anyways if pulXlate is NULL and Dest is PAL_INDEXED
185
186       // Converting from RGB to indexed
187       XLATEOBJ_cGetPalette(XlateObj, XO_DESTPALETTE, DestPalGDI->NumColors, XlateGDI->translationTable);
188     }
189   }
190
191   // FIXME: Add support for XO_TO_MONO
192   return XlateObj;
193 }
194
195 VOID EngDeleteXlate(XLATEOBJ *XlateObj)
196 {
197   HPALETTE HXlate    = (HPALETTE)AccessHandleFromUserObject(XlateObj);
198   XLATEGDI *XlateGDI = (XLATEGDI*)AccessInternalObject((ULONG)HXlate);
199
200   if(XlateGDI->translationTable!=NULL)
201   {
202     EngFreeMem(XlateGDI->translationTable);
203   }
204
205   FreeGDIHandle((ULONG)HXlate);
206 }
207
208 ULONG * STDCALL
209 XLATEOBJ_piVector(XLATEOBJ *XlateObj)
210 {
211   XLATEGDI *XlateGDI = (XLATEGDI*)AccessInternalObjectFromUserObject(XlateObj);
212
213   if(XlateObj->iSrcType == PAL_INDEXED)
214   {
215     return XlateGDI->translationTable;
216   }
217
218   return NULL;
219 }
220
221 ULONG STDCALL
222 XLATEOBJ_iXlate(XLATEOBJ *XlateObj,
223                 ULONG Color)
224 {
225   PALGDI   *PalGDI;
226   XLATEGDI *XlateGDI = (XLATEGDI*)AccessInternalObjectFromUserObject(XlateObj);
227
228   // Return the original color if there's no color translation object
229   if(!XlateObj) return Color;
230
231   if(XlateObj->flXlate & XO_TRIVIAL)
232   {
233     return Color;
234   } else
235   if(XlateObj->iSrcType == PAL_RGB)
236   {
237     // FIXME: should we cache colors used often?
238     // FIXME: won't work if destination isn't indexed
239
240     // Extract the destination palette
241     PalGDI = (PALGDI*)AccessInternalObject((ULONG)XlateGDI->DestPal);
242
243     // Return closest match for the given RGB color
244     return ClosestColorMatch(Color, PalGDI->IndexedColors, PalGDI->NumColors);
245   } else
246   if(XlateObj->iSrcType == PAL_INDEXED)
247   {
248     return XlateGDI->translationTable[Color];
249   }
250
251   return 0;
252 }
253
254 ULONG STDCALL
255 XLATEOBJ_cGetPalette(XLATEOBJ *XlateObj,
256                      ULONG PalOutType,
257                      ULONG cPal,
258                      ULONG *OutPal)
259 {
260   ULONG i;
261   HPALETTE HPal;
262   XLATEGDI *XlateGDI;
263   PALGDI *PalGDI;
264
265   XlateGDI = (XLATEGDI*)AccessInternalObjectFromUserObject(XlateObj);
266
267   if(PalOutType == XO_SRCPALETTE)
268   {
269     HPal = XlateGDI->SourcePal;
270   } else
271   if(PalOutType == XO_DESTPALETTE)
272   {
273     HPal = XlateGDI->DestPal;
274   }
275
276   PalGDI = (PALGDI*)AccessInternalObject((ULONG)HPal);
277   RtlCopyMemory(OutPal, PalGDI->IndexedColors, sizeof(ULONG)*cPal);
278
279   return i;
280 }