set svn:eol-style to native
[reactos.git] / reactos / lib / 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->bmiHeader.biSize != sizeof(BITMAPCOREHEADER) &&
192 (BitmapInfo->bmiHeader.biSize < sizeof(BITMAPINFOHEADER) ||
193 BitmapInfo->bmiHeader.biSize > sizeof(BITMAPV5HEADER)))
194 {
195 return NULL;
196 }
197
198 /*
199 * Now calculate the color table size. Also if the bitmap info contains
200 * invalid color information it's rejected here.
201 */
202
203 if (!CalculateColorTableSize(&BitmapInfo->bmiHeader, &ColorSpec,
204 &PaletteEntryCount))
205 {
206 return NULL;
207 }
208
209 /*
210 * Calculate the size of image data if applicable. We must be careful
211 * to do proper aligning on line ends.
212 */
213
214 if (FollowedByData)
215 {
216 if (BitmapInfo->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
217 {
218 DataSize =
219 CoreBitmapInfo->bmciHeader.bcHeight *
220 CoreBitmapInfo->bmciHeader.bcWidth *
221 CoreBitmapInfo->bmciHeader.bcBitCount;
222 DataSize = ((DataSize + 31) & ~31) / 8;
223 DataSize *= CoreBitmapInfo->bmciHeader.bcPlanes;
224 }
225 else
226 {
227 if (BitmapInfo->bmiHeader.biCompression == BI_RGB ||
228 BitmapInfo->bmiHeader.biCompression == BI_BITFIELDS)
229 {
230 DataSize =
231 abs(BitmapInfo->bmiHeader.biHeight) *
232 BitmapInfo->bmiHeader.biWidth *
233 BitmapInfo->bmiHeader.biBitCount;
234 DataSize = ((DataSize + 31) & ~31) / 8;
235 DataSize *= BitmapInfo->bmiHeader.biPlanes;
236 }
237 else
238 {
239 DataSize = BitmapInfo->bmiHeader.biSizeImage;
240 }
241 }
242 }
243
244 /*
245 * If BitmapInfo was originally BITMAPCOREINFO then we need to convert
246 * it to the standard BITMAPINFO layout.
247 */
248
249 if (BitmapInfo->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
250 {
251 Size = sizeof(BITMAPINFOHEADER);
252 if (ColorSpec == DIB_RGB_COLORS)
253 Size += PaletteEntryCount * sizeof(RGBQUAD);
254 else
255 Size += PaletteEntryCount * sizeof(USHORT);
256 Size += DataSize;
257
258 NewBitmapInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, Size);
259 if (NewBitmapInfo == NULL)
260 {
261 return NULL;
262 }
263
264 NewBitmapInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
265 NewBitmapInfo->bmiHeader.biWidth = CoreBitmapInfo->bmciHeader.bcWidth;
266 NewBitmapInfo->bmiHeader.biHeight = CoreBitmapInfo->bmciHeader.bcHeight;
267 NewBitmapInfo->bmiHeader.biPlanes = CoreBitmapInfo->bmciHeader.bcPlanes;
268 NewBitmapInfo->bmiHeader.biBitCount = CoreBitmapInfo->bmciHeader.bcBitCount;
269 NewBitmapInfo->bmiHeader.biCompression = BI_RGB;
270 NewBitmapInfo->bmiHeader.biSizeImage = 0;
271 NewBitmapInfo->bmiHeader.biXPelsPerMeter = 0;
272 NewBitmapInfo->bmiHeader.biYPelsPerMeter = 0;
273 NewBitmapInfo->bmiHeader.biClrUsed = 0;
274 NewBitmapInfo->bmiHeader.biClrImportant = 0;
275
276 if (PaletteEntryCount != 0)
277 {
278 if (ColorSpec == DIB_RGB_COLORS)
279 {
280 ULONG Index;
281
282 for (Index = 0; Index < PaletteEntryCount; Index++)
283 {
284 NewBitmapInfo->bmiColors[Index].rgbRed =
285 CoreBitmapInfo->bmciColors[Index].rgbtRed;
286 NewBitmapInfo->bmiColors[Index].rgbGreen =
287 CoreBitmapInfo->bmciColors[Index].rgbtGreen;
288 NewBitmapInfo->bmiColors[Index].rgbBlue =
289 CoreBitmapInfo->bmciColors[Index].rgbtBlue;
290 NewBitmapInfo->bmiColors[Index].rgbReserved = 0;
291 }
292 }
293 else
294 {
295 RtlCopyMemory(NewBitmapInfo->bmiColors,
296 CoreBitmapInfo->bmciColors,
297 PaletteEntryCount * sizeof(USHORT));
298 }
299 }
300
301 if (FollowedByData)
302 {
303 ULONG_PTR NewDataPtr, OldDataPtr;
304
305 if (ColorSpec == DIB_RGB_COLORS)
306 {
307 NewDataPtr = (ULONG_PTR)(NewBitmapInfo->bmiColors +
308 PaletteEntryCount);
309 OldDataPtr = (ULONG_PTR)(CoreBitmapInfo->bmciColors +
310 PaletteEntryCount);
311 }
312 else
313 {
314 NewDataPtr = (ULONG_PTR)(NewBitmapInfo->bmiColors) +
315 PaletteEntryCount * sizeof(USHORT);
316 OldDataPtr = (ULONG_PTR)(CoreBitmapInfo->bmciColors) +
317 PaletteEntryCount * sizeof(USHORT);
318 }
319
320 RtlCopyMemory((PVOID)NewDataPtr, (PVOID)OldDataPtr, DataSize);
321 }
322 }
323
324 Size = NewBitmapInfo->bmiHeader.biSize;
325 if (ColorSpec == DIB_RGB_COLORS)
326 Size += PaletteEntryCount * sizeof(RGBQUAD);
327 else
328 Size += PaletteEntryCount * sizeof(USHORT);
329 Size += DataSize;
330 *BitmapInfoSize = Size;
331
332 return NewBitmapInfo;
333 }
334
335 VOID
336 STDCALL
337 LogFontA2W(LPLOGFONTW pW, CONST LOGFONTA *pA)
338 {
339 #define COPYS(f,len) MultiByteToWideChar ( CP_THREAD_ACP, 0, pA->f, len, pW->f, len )
340 #define COPYN(f) pW->f = pA->f
341
342 COPYN(lfHeight);
343 COPYN(lfWidth);
344 COPYN(lfEscapement);
345 COPYN(lfOrientation);
346 COPYN(lfWeight);
347 COPYN(lfItalic);
348 COPYN(lfUnderline);
349 COPYN(lfStrikeOut);
350 COPYN(lfCharSet);
351 COPYN(lfOutPrecision);
352 COPYN(lfClipPrecision);
353 COPYN(lfQuality);
354 COPYN(lfPitchAndFamily);
355 COPYS(lfFaceName,LF_FACESIZE);
356
357 #undef COPYN
358 #undef COPYS
359 }
360
361 VOID
362 STDCALL
363 LogFontW2A(LPLOGFONTA pA, CONST LOGFONTW *pW)
364 {
365 #define COPYS(f,len) WideCharToMultiByte ( CP_THREAD_ACP, 0, pW->f, len, pA->f, len, NULL, NULL )
366 #define COPYN(f) pA->f = pW->f
367
368 COPYN(lfHeight);
369 COPYN(lfWidth);
370 COPYN(lfEscapement);
371 COPYN(lfOrientation);
372 COPYN(lfWeight);
373 COPYN(lfItalic);
374 COPYN(lfUnderline);
375 COPYN(lfStrikeOut);
376 COPYN(lfCharSet);
377 COPYN(lfOutPrecision);
378 COPYN(lfClipPrecision);
379 COPYN(lfQuality);
380 COPYN(lfPitchAndFamily);
381 COPYS(lfFaceName,LF_FACESIZE);
382
383 #undef COPYN
384 #undef COPYS
385 }