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