xref: /reactos/win32ss/gdi/gdi32/objects/utils.c (revision cc439606)
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 }
467