- Fix newest Wine bitmap gdi32 crosstest.
[reactos.git] / reactos / dll / win32 / gdi32 / objects / utils.c
1 #include "precomp.h"
2
3 /**
4 * @name CalculateColorTableSize
5 *
6 * Internal routine to calculate the number of color table entries.
7 *
8 * @param BitmapInfoHeader
9 * Input bitmap information header, can be any version of
10 * BITMAPINFOHEADER or BITMAPCOREHEADER.
11 *
12 * @param ColorSpec
13 * Pointer to variable which specifiing the color mode (DIB_RGB_COLORS
14 * or DIB_RGB_COLORS). On successful return this value is normalized
15 * according to the bitmap info.
16 *
17 * @param ColorTableSize
18 * On successful return this variable is filled with number of
19 * entries in color table for the image with specified parameters.
20 *
21 * @return
22 * TRUE if the input values together form a valid image, FALSE otherwise.
23 */
24
25 BOOL STDCALL
26 CalculateColorTableSize(
27 CONST BITMAPINFOHEADER *BitmapInfoHeader,
28 UINT *ColorSpec,
29 UINT *ColorTableSize)
30 {
31 WORD BitCount;
32 DWORD ClrUsed;
33 DWORD Compression;
34
35 /*
36 * At first get some basic parameters from the passed BitmapInfoHeader
37 * structure. It can have one of the following formats:
38 * - BITMAPCOREHEADER (the oldest one with totally different layout
39 * from the others)
40 * - BITMAPINFOHEADER (the standard and most common header)
41 * - BITMAPV4HEADER (extension of BITMAPINFOHEADER)
42 * - BITMAPV5HEADER (extension of BITMAPV4HEADER)
43 */
44
45 if (BitmapInfoHeader->biSize == sizeof(BITMAPCOREHEADER))
46 {
47 BitCount = ((LPBITMAPCOREHEADER)BitmapInfoHeader)->bcBitCount;
48 ClrUsed = 0;
49 Compression = BI_RGB;
50 }
51 else
52 {
53 BitCount = BitmapInfoHeader->biBitCount;
54 ClrUsed = BitmapInfoHeader->biClrUsed;
55 Compression = BitmapInfoHeader->biCompression;
56 }
57
58 switch (Compression)
59 {
60 case BI_BITFIELDS:
61 if (*ColorSpec == DIB_PAL_COLORS)
62 *ColorSpec = DIB_RGB_COLORS;
63
64 if (BitCount != 16 && BitCount != 32)
65 return FALSE;
66
67 /*
68 * For BITMAPV4HEADER/BITMAPV5HEADER the masks are included in
69 * the structure itself (bV4RedMask, bV4GreenMask, and bV4BlueMask).
70 * For BITMAPINFOHEADER the color masks are stored in the palette.
71 */
72
73 if (BitmapInfoHeader->biSize > sizeof(BITMAPINFOHEADER))
74 *ColorTableSize = 0;
75 else
76 *ColorTableSize = 3;
77
78 return TRUE;
79
80 case BI_RGB:
81 switch (BitCount)
82 {
83 case 1:
84 *ColorTableSize = ClrUsed ? min(ClrUsed, 2) : 2;
85 return TRUE;
86
87 case 4:
88 *ColorTableSize = ClrUsed ? min(ClrUsed, 16) : 16;
89 return TRUE;
90
91 case 8:
92 *ColorTableSize = ClrUsed ? min(ClrUsed, 256) : 256;
93 return TRUE;
94
95 default:
96 if (*ColorSpec == DIB_PAL_COLORS)
97 *ColorSpec = DIB_RGB_COLORS;
98 if (BitCount != 16 && BitCount != 24 && BitCount != 32)
99 return FALSE;
100 *ColorTableSize = ClrUsed;
101 return TRUE;
102 }
103
104 case BI_RLE4:
105 if (BitCount == 4)
106 {
107 *ColorTableSize = ClrUsed ? min(ClrUsed, 16) : 16;
108 return TRUE;
109 }
110 return FALSE;
111
112 case BI_RLE8:
113 if (BitCount == 8)
114 {
115 *ColorTableSize = ClrUsed ? min(ClrUsed, 256) : 256;
116 return TRUE;
117 }
118 return FALSE;
119
120 case BI_JPEG:
121 case BI_PNG:
122 *ColorTableSize = ClrUsed;
123 return TRUE;
124
125 default:
126 return FALSE;
127 }
128 }
129
130 /**
131 * @name ConvertBitmapInfo
132 *
133 * Internal routine to convert a user-passed BITMAPINFO structure into
134 * unified BITMAPINFO structure.
135 *
136 * @param BitmapInfo
137 * Input bitmap info, can be any version of BITMAPINFO or
138 * BITMAPCOREINFO.
139 * @param ColorSpec
140 * Specifies whether the bmiColors member of the BITMAPINFO structure
141 * contains a valid color table and, if so, whether the entries in
142 * this color table contain explicit red, green, blue (DIB_RGB_COLORS)
143 * values or palette indexes (DIB_PAL_COLORS).
144 * @param BitmapInfoSize
145 * On successful return contains the size of the returned BITMAPINFO
146 * structure. If FollowedByData is TRUE the size includes the number
147 * of bytes occupied by the image data.
148 * @param FollowedByData
149 * Specifies if the BITMAPINFO header is immediately followed
150 * by the actual bitmap data (eg. as passed to CreateDIBPatternBrush).
151 *
152 * @return
153 * Either the original BitmapInfo or newly allocated structure is
154 * returned. For the later case the caller is responsible for freeing the
155 * memory using RtlFreeHeap with the current process heap.
156 *
157 * @example
158 * PBITMAPINFO NewBitmapInfo;
159 * UINT NewBitmapInfoSize;
160 *
161 * NewBitmapInfo = ConvertBitmapInfo(OldBitmapInfo, DIB_RGB_COLORS,
162 * &NewBitmapInfoSize, FALSE);
163 * if (NewBitmapInfo)
164 * {
165 * <do something with the bitmap info>
166 * if (NewBitmapInfo != OldBitmapInfo)
167 * RtlFreeHeap(RtlGetProcessHeap(), 0, NewBitmapInfo);
168 * }
169 */
170
171 LPBITMAPINFO STDCALL
172 ConvertBitmapInfo(
173 CONST BITMAPINFO *BitmapInfo,
174 UINT ColorSpec,
175 UINT *BitmapInfoSize,
176 BOOL FollowedByData)
177 {
178 LPBITMAPINFO NewBitmapInfo = (LPBITMAPINFO)BitmapInfo;
179 LPBITMAPCOREINFO CoreBitmapInfo = (LPBITMAPCOREINFO)BitmapInfo;
180 DWORD Size = 0;
181 ULONG DataSize = 0;
182 UINT PaletteEntryCount = 0;
183
184 /*
185 * At first check if the passed BitmapInfo structure has valid size. It
186 * can have one of these headers: BITMAPCOREHEADER, BITMAPINFOHEADER,
187 * BITMAPV4HEADER or BITMAPV5HEADER (see CalculateColorTableSize for
188 * description).
189 */
190
191 if ( !BitmapInfo ||
192 (BitmapInfo->bmiHeader.biSize != sizeof(BITMAPCOREHEADER) &&
193 (BitmapInfo->bmiHeader.biSize < sizeof(BITMAPINFOHEADER) ||
194 BitmapInfo->bmiHeader.biSize > sizeof(BITMAPV5HEADER))))
195 {
196 return NULL;
197 }
198
199 /*
200 * Now calculate the color table size. Also if the bitmap info contains
201 * invalid color information it's rejected here.
202 */
203
204 if (!CalculateColorTableSize(&BitmapInfo->bmiHeader, &ColorSpec,
205 &PaletteEntryCount))
206 {
207 return NULL;
208 }
209
210 /*
211 * Calculate the size of image data if applicable. We must be careful
212 * to do proper aligning on line ends.
213 */
214
215 if (FollowedByData)
216 {
217 if (BitmapInfo->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
218 {
219 DataSize =
220 CoreBitmapInfo->bmciHeader.bcHeight *
221 CoreBitmapInfo->bmciHeader.bcWidth *
222 CoreBitmapInfo->bmciHeader.bcBitCount;
223 DataSize = ((DataSize + 31) & ~31) / 8;
224 DataSize *= CoreBitmapInfo->bmciHeader.bcPlanes;
225 }
226 else
227 {
228 if (BitmapInfo->bmiHeader.biCompression == BI_RGB ||
229 BitmapInfo->bmiHeader.biCompression == BI_BITFIELDS)
230 {
231 DataSize =
232 abs(BitmapInfo->bmiHeader.biHeight) *
233 BitmapInfo->bmiHeader.biWidth *
234 BitmapInfo->bmiHeader.biBitCount;
235 DataSize = ((DataSize + 31) & ~31) / 8;
236 DataSize *= BitmapInfo->bmiHeader.biPlanes;
237 }
238 else
239 {
240 DataSize = BitmapInfo->bmiHeader.biSizeImage;
241 }
242 }
243 }
244
245 /*
246 * If BitmapInfo was originally BITMAPCOREINFO then we need to convert
247 * it to the standard BITMAPINFO layout.
248 */
249
250 if (BitmapInfo->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
251 {
252 Size = sizeof(BITMAPINFOHEADER);
253 if (ColorSpec == DIB_RGB_COLORS)
254 Size += PaletteEntryCount * sizeof(RGBQUAD);
255 else
256 Size += PaletteEntryCount * sizeof(USHORT);
257 Size += DataSize;
258
259 NewBitmapInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, Size);
260 if (NewBitmapInfo == NULL)
261 {
262 return NULL;
263 }
264
265 NewBitmapInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
266 NewBitmapInfo->bmiHeader.biWidth = CoreBitmapInfo->bmciHeader.bcWidth;
267 NewBitmapInfo->bmiHeader.biHeight = CoreBitmapInfo->bmciHeader.bcHeight;
268 NewBitmapInfo->bmiHeader.biPlanes = CoreBitmapInfo->bmciHeader.bcPlanes;
269 NewBitmapInfo->bmiHeader.biBitCount = CoreBitmapInfo->bmciHeader.bcBitCount;
270 NewBitmapInfo->bmiHeader.biCompression = BI_RGB;
271 NewBitmapInfo->bmiHeader.biSizeImage = 0;
272 NewBitmapInfo->bmiHeader.biXPelsPerMeter = 0;
273 NewBitmapInfo->bmiHeader.biYPelsPerMeter = 0;
274 NewBitmapInfo->bmiHeader.biClrUsed = 0;
275 NewBitmapInfo->bmiHeader.biClrImportant = 0;
276
277 if (PaletteEntryCount != 0)
278 {
279 if (ColorSpec == DIB_RGB_COLORS)
280 {
281 ULONG Index;
282
283 for (Index = 0; Index < PaletteEntryCount; Index++)
284 {
285 NewBitmapInfo->bmiColors[Index].rgbRed =
286 CoreBitmapInfo->bmciColors[Index].rgbtRed;
287 NewBitmapInfo->bmiColors[Index].rgbGreen =
288 CoreBitmapInfo->bmciColors[Index].rgbtGreen;
289 NewBitmapInfo->bmiColors[Index].rgbBlue =
290 CoreBitmapInfo->bmciColors[Index].rgbtBlue;
291 NewBitmapInfo->bmiColors[Index].rgbReserved = 0;
292 }
293 }
294 else
295 {
296 RtlCopyMemory(NewBitmapInfo->bmiColors,
297 CoreBitmapInfo->bmciColors,
298 PaletteEntryCount * sizeof(USHORT));
299 }
300 }
301
302 if (FollowedByData)
303 {
304 ULONG_PTR NewDataPtr, OldDataPtr;
305
306 if (ColorSpec == DIB_RGB_COLORS)
307 {
308 NewDataPtr = (ULONG_PTR)(NewBitmapInfo->bmiColors +
309 PaletteEntryCount);
310 OldDataPtr = (ULONG_PTR)(CoreBitmapInfo->bmciColors +
311 PaletteEntryCount);
312 }
313 else
314 {
315 NewDataPtr = (ULONG_PTR)(NewBitmapInfo->bmiColors) +
316 PaletteEntryCount * sizeof(USHORT);
317 OldDataPtr = (ULONG_PTR)(CoreBitmapInfo->bmciColors) +
318 PaletteEntryCount * sizeof(USHORT);
319 }
320
321 RtlCopyMemory((PVOID)NewDataPtr, (PVOID)OldDataPtr, DataSize);
322 }
323 }
324
325 Size = NewBitmapInfo->bmiHeader.biSize;
326 if (ColorSpec == DIB_RGB_COLORS)
327 Size += PaletteEntryCount * sizeof(RGBQUAD);
328 else
329 Size += PaletteEntryCount * sizeof(USHORT);
330 Size += DataSize;
331 *BitmapInfoSize = Size;
332
333 return NewBitmapInfo;
334 }
335
336 VOID
337 STDCALL
338 LogFontA2W(LPLOGFONTW pW, CONST LOGFONTA *pA)
339 {
340 #define COPYS(f,len) MultiByteToWideChar ( CP_THREAD_ACP, 0, pA->f, len, pW->f, len )
341 #define COPYN(f) pW->f = pA->f
342
343 COPYN(lfHeight);
344 COPYN(lfWidth);
345 COPYN(lfEscapement);
346 COPYN(lfOrientation);
347 COPYN(lfWeight);
348 COPYN(lfItalic);
349 COPYN(lfUnderline);
350 COPYN(lfStrikeOut);
351 COPYN(lfCharSet);
352 COPYN(lfOutPrecision);
353 COPYN(lfClipPrecision);
354 COPYN(lfQuality);
355 COPYN(lfPitchAndFamily);
356 COPYS(lfFaceName,LF_FACESIZE);
357
358 #undef COPYN
359 #undef COPYS
360 }
361
362 VOID
363 STDCALL
364 LogFontW2A(LPLOGFONTA pA, CONST LOGFONTW *pW)
365 {
366 #define COPYS(f,len) WideCharToMultiByte ( CP_THREAD_ACP, 0, pW->f, len, pA->f, len, NULL, NULL )
367 #define COPYN(f) pA->f = pW->f
368
369 COPYN(lfHeight);
370 COPYN(lfWidth);
371 COPYN(lfEscapement);
372 COPYN(lfOrientation);
373 COPYN(lfWeight);
374 COPYN(lfItalic);
375 COPYN(lfUnderline);
376 COPYN(lfStrikeOut);
377 COPYN(lfCharSet);
378 COPYN(lfOutPrecision);
379 COPYN(lfClipPrecision);
380 COPYN(lfQuality);
381 COPYN(lfPitchAndFamily);
382 COPYS(lfFaceName,LF_FACESIZE);
383
384 #undef COPYN
385 #undef COPYS
386 }
387
388 VOID
389 STDCALL
390 EnumLogFontExW2A( LPENUMLOGFONTEXA fontA, CONST ENUMLOGFONTEXW *fontW )
391 {
392 LogFontW2A( (LPLOGFONTA)fontA, (CONST LOGFONTW *)fontW );
393
394 WideCharToMultiByte( CP_THREAD_ACP, 0, fontW->elfFullName, -1,
395 (LPSTR) fontA->elfFullName, LF_FULLFACESIZE, NULL, NULL );
396 fontA->elfFullName[LF_FULLFACESIZE-1] = '\0';
397 WideCharToMultiByte( CP_THREAD_ACP, 0, fontW->elfStyle, -1,
398 (LPSTR) fontA->elfStyle, LF_FACESIZE, NULL, NULL );
399 fontA->elfStyle[LF_FACESIZE-1] = '\0';
400 WideCharToMultiByte( CP_THREAD_ACP, 0, fontW->elfScript, -1,
401 (LPSTR) fontA->elfScript, LF_FACESIZE, NULL, NULL );
402 fontA->elfScript[LF_FACESIZE-1] = '\0';
403 }
404