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