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