reactos/win32ss/gdi/gdi32/objects/utils.c
Baruch Rutman 7143e411c4
[GDI32] Integrate LpkGetTextExtentExPoint(). (#1362)
- Assume that GetTextExtentExPointWPri() uses the same kind of
  arguments as GetTextExtentExPointW().

- Add GetTextExtentExPointWPri() declaration to undocgdi.h.
2019-03-23 23:34:09 +01:00

479 lines
14 KiB
C

#include <precomp.h>
/* LoadLPK global variables */
HINSTANCE hLpk = NULL;
LPKETO LpkExtTextOut = NULL;
LPKGCP LpkGetCharacterPlacement = NULL;
LPKGTEP LpkGetTextExtentExPoint = NULL;
/**
* @name CalculateColorTableSize
*
* Internal routine to calculate the number of color table entries.
*
* @param BitmapInfoHeader
* Input bitmap information header, can be any version of
* BITMAPINFOHEADER or BITMAPCOREHEADER.
*
* @param ColorSpec
* Pointer to variable which specifiing the color mode (DIB_RGB_COLORS
* or DIB_RGB_COLORS). On successful return this value is normalized
* according to the bitmap info.
*
* @param ColorTableSize
* On successful return this variable is filled with number of
* entries in color table for the image with specified parameters.
*
* @return
* TRUE if the input values together form a valid image, FALSE otherwise.
*/
BOOL WINAPI
CalculateColorTableSize(
CONST BITMAPINFOHEADER *BitmapInfoHeader,
UINT *ColorSpec,
UINT *ColorTableSize)
{
WORD BitCount;
DWORD ClrUsed;
DWORD Compression;
/*
* At first get some basic parameters from the passed BitmapInfoHeader
* structure. It can have one of the following formats:
* - BITMAPCOREHEADER (the oldest one with totally different layout
* from the others)
* - BITMAPINFOHEADER (the standard and most common header)
* - BITMAPV4HEADER (extension of BITMAPINFOHEADER)
* - BITMAPV5HEADER (extension of BITMAPV4HEADER)
*/
if (BitmapInfoHeader->biSize == sizeof(BITMAPCOREHEADER))
{
BitCount = ((LPBITMAPCOREHEADER)BitmapInfoHeader)->bcBitCount;
ClrUsed = 0;
Compression = BI_RGB;
}
else
{
BitCount = BitmapInfoHeader->biBitCount;
ClrUsed = BitmapInfoHeader->biClrUsed;
Compression = BitmapInfoHeader->biCompression;
}
switch (Compression)
{
case BI_BITFIELDS:
if (*ColorSpec == DIB_PAL_COLORS)
*ColorSpec = DIB_RGB_COLORS;
if (BitCount != 16 && BitCount != 32)
return FALSE;
/*
* For BITMAPV4HEADER/BITMAPV5HEADER the masks are included in
* the structure itself (bV4RedMask, bV4GreenMask, and bV4BlueMask).
* For BITMAPINFOHEADER the color masks are stored in the palette.
*/
if (BitmapInfoHeader->biSize > sizeof(BITMAPINFOHEADER))
*ColorTableSize = 0;
else
*ColorTableSize = 3;
return TRUE;
case BI_RGB:
switch (BitCount)
{
case 1:
*ColorTableSize = ClrUsed ? min(ClrUsed, 2) : 2;
return TRUE;
case 4:
*ColorTableSize = ClrUsed ? min(ClrUsed, 16) : 16;
return TRUE;
case 8:
*ColorTableSize = ClrUsed ? min(ClrUsed, 256) : 256;
return TRUE;
default:
if (*ColorSpec == DIB_PAL_COLORS)
*ColorSpec = DIB_RGB_COLORS;
if (BitCount != 16 && BitCount != 24 && BitCount != 32)
return FALSE;
*ColorTableSize = ClrUsed;
return TRUE;
}
case BI_RLE4:
if (BitCount == 4)
{
*ColorTableSize = ClrUsed ? min(ClrUsed, 16) : 16;
return TRUE;
}
return FALSE;
case BI_RLE8:
if (BitCount == 8)
{
*ColorTableSize = ClrUsed ? min(ClrUsed, 256) : 256;
return TRUE;
}
return FALSE;
case BI_JPEG:
case BI_PNG:
*ColorTableSize = ClrUsed;
return TRUE;
default:
return FALSE;
}
}
/**
* @name ConvertBitmapInfo
*
* Internal routine to convert a user-passed BITMAPINFO structure into
* unified BITMAPINFO structure.
*
* @param BitmapInfo
* Input bitmap info, can be any version of BITMAPINFO or
* BITMAPCOREINFO.
* @param ColorSpec
* Specifies whether the bmiColors member of the BITMAPINFO structure
* contains a valid color table and, if so, whether the entries in
* this color table contain explicit red, green, blue (DIB_RGB_COLORS)
* values or palette indexes (DIB_PAL_COLORS).
* @param BitmapInfoSize
* On successful return contains the size of the returned BITMAPINFO
* structure. If FollowedByData is TRUE the size includes the number
* of bytes occupied by the image data.
* @param FollowedByData
* Specifies if the BITMAPINFO header is immediately followed
* by the actual bitmap data (eg. as passed to CreateDIBPatternBrush).
*
* @return
* Either the original BitmapInfo or newly allocated structure is
* returned. For the later case the caller is responsible for freeing the
* memory using RtlFreeHeap with the current process heap.
*
* @example
* PBITMAPINFO NewBitmapInfo;
* UINT NewBitmapInfoSize;
*
* NewBitmapInfo = ConvertBitmapInfo(OldBitmapInfo, DIB_RGB_COLORS,
* &NewBitmapInfoSize, FALSE);
* if (NewBitmapInfo)
* {
* <do something with the bitmap info>
* if (NewBitmapInfo != OldBitmapInfo)
* RtlFreeHeap(RtlGetProcessHeap(), 0, NewBitmapInfo);
* }
*/
LPBITMAPINFO WINAPI
ConvertBitmapInfo(
CONST BITMAPINFO *BitmapInfo,
UINT ColorSpec,
UINT *BitmapInfoSize,
BOOL FollowedByData)
{
LPBITMAPINFO NewBitmapInfo = (LPBITMAPINFO)BitmapInfo;
LPBITMAPCOREINFO CoreBitmapInfo = (LPBITMAPCOREINFO)BitmapInfo;
DWORD Size = 0;
ULONG DataSize = 0;
UINT PaletteEntryCount = 0;
/*
* At first check if the passed BitmapInfo structure has valid size. It
* can have one of these headers: BITMAPCOREHEADER, BITMAPINFOHEADER,
* BITMAPV4HEADER or BITMAPV5HEADER (see CalculateColorTableSize for
* description).
*/
if ( !BitmapInfo ||
(BitmapInfo->bmiHeader.biSize != sizeof(BITMAPCOREHEADER) &&
(BitmapInfo->bmiHeader.biSize < sizeof(BITMAPINFOHEADER) ||
BitmapInfo->bmiHeader.biSize > sizeof(BITMAPV5HEADER))))
{
return NULL;
}
/*
* Now calculate the color table size. Also if the bitmap info contains
* invalid color information it's rejected here.
*/
if (!CalculateColorTableSize(&BitmapInfo->bmiHeader, &ColorSpec,
&PaletteEntryCount))
{
return NULL;
}
/*
* Calculate the size of image data if applicable. We must be careful
* to do proper aligning on line ends.
*/
if (FollowedByData)
{
DataSize = GdiGetBitmapBitsSize((PBITMAPINFO)BitmapInfo );
}
/*
* If BitmapInfo was originally BITMAPCOREINFO then we need to convert
* it to the standard BITMAPINFO layout.
*/
if (BitmapInfo->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
{
Size = sizeof(BITMAPINFOHEADER);
if (ColorSpec == DIB_RGB_COLORS)
Size += PaletteEntryCount * sizeof(RGBQUAD);
else
Size += PaletteEntryCount * sizeof(USHORT);
Size += DataSize;
NewBitmapInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, Size);
if (NewBitmapInfo == NULL)
{
return NULL;
}
NewBitmapInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
NewBitmapInfo->bmiHeader.biWidth = CoreBitmapInfo->bmciHeader.bcWidth;
NewBitmapInfo->bmiHeader.biHeight = CoreBitmapInfo->bmciHeader.bcHeight;
NewBitmapInfo->bmiHeader.biPlanes = CoreBitmapInfo->bmciHeader.bcPlanes;
NewBitmapInfo->bmiHeader.biBitCount = CoreBitmapInfo->bmciHeader.bcBitCount;
NewBitmapInfo->bmiHeader.biCompression = BI_RGB;
NewBitmapInfo->bmiHeader.biSizeImage = 0;
NewBitmapInfo->bmiHeader.biXPelsPerMeter = 0;
NewBitmapInfo->bmiHeader.biYPelsPerMeter = 0;
NewBitmapInfo->bmiHeader.biClrUsed = 0;
NewBitmapInfo->bmiHeader.biClrImportant = 0;
if (PaletteEntryCount != 0)
{
if (ColorSpec == DIB_RGB_COLORS)
{
ULONG Index;
for (Index = 0; Index < PaletteEntryCount; Index++)
{
NewBitmapInfo->bmiColors[Index].rgbRed =
CoreBitmapInfo->bmciColors[Index].rgbtRed;
NewBitmapInfo->bmiColors[Index].rgbGreen =
CoreBitmapInfo->bmciColors[Index].rgbtGreen;
NewBitmapInfo->bmiColors[Index].rgbBlue =
CoreBitmapInfo->bmciColors[Index].rgbtBlue;
NewBitmapInfo->bmiColors[Index].rgbReserved = 0;
}
}
else
{
RtlCopyMemory(NewBitmapInfo->bmiColors,
CoreBitmapInfo->bmciColors,
PaletteEntryCount * sizeof(USHORT));
}
}
if (FollowedByData)
{
ULONG_PTR NewDataPtr, OldDataPtr;
if (ColorSpec == DIB_RGB_COLORS)
{
NewDataPtr = (ULONG_PTR)(NewBitmapInfo->bmiColors +
PaletteEntryCount);
OldDataPtr = (ULONG_PTR)(CoreBitmapInfo->bmciColors +
PaletteEntryCount);
}
else
{
NewDataPtr = (ULONG_PTR)(NewBitmapInfo->bmiColors) +
PaletteEntryCount * sizeof(USHORT);
OldDataPtr = (ULONG_PTR)(CoreBitmapInfo->bmciColors) +
PaletteEntryCount * sizeof(USHORT);
}
RtlCopyMemory((PVOID)NewDataPtr, (PVOID)OldDataPtr, DataSize);
}
}
else
{
/* Verify some data validity */
switch (BitmapInfo->bmiHeader.biCompression)
{
case BI_RLE8:
if (BitmapInfo->bmiHeader.biBitCount != 8)
return NULL;
if (BitmapInfo->bmiHeader.biHeight < 0)
return NULL;
break;
case BI_RLE4:
if (BitmapInfo->bmiHeader.biBitCount != 4)
return NULL;
if (BitmapInfo->bmiHeader.biHeight < 0)
return NULL;
break;
default:
break;
}
/* Non "standard" formats must have a valid size set */
if ((BitmapInfo->bmiHeader.biCompression != BI_RGB) &&
(BitmapInfo->bmiHeader.biCompression != BI_BITFIELDS))
{
if (BitmapInfo->bmiHeader.biSizeImage == 0)
return NULL;
}
}
Size = NewBitmapInfo->bmiHeader.biSize;
if (ColorSpec == DIB_RGB_COLORS)
Size += PaletteEntryCount * sizeof(RGBQUAD);
else
Size += PaletteEntryCount * sizeof(USHORT);
Size += DataSize;
*BitmapInfoSize = Size;
return NewBitmapInfo;
}
VOID
WINAPI
LogFontA2W(LPLOGFONTW pW, CONST LOGFONTA *pA)
{
#define COPYS(f,len) MultiByteToWideChar ( CP_THREAD_ACP, 0, pA->f, len, pW->f, len )
#define COPYN(f) pW->f = pA->f
COPYN(lfHeight);
COPYN(lfWidth);
COPYN(lfEscapement);
COPYN(lfOrientation);
COPYN(lfWeight);
COPYN(lfItalic);
COPYN(lfUnderline);
COPYN(lfStrikeOut);
COPYN(lfCharSet);
COPYN(lfOutPrecision);
COPYN(lfClipPrecision);
COPYN(lfQuality);
COPYN(lfPitchAndFamily);
COPYS(lfFaceName,LF_FACESIZE);
pW->lfFaceName[LF_FACESIZE - 1] = '\0';
#undef COPYN
#undef COPYS
}
VOID
WINAPI
LogFontW2A(LPLOGFONTA pA, CONST LOGFONTW *pW)
{
#define COPYS(f,len) WideCharToMultiByte ( CP_THREAD_ACP, 0, pW->f, len, pA->f, len, NULL, NULL )
#define COPYN(f) pA->f = pW->f
COPYN(lfHeight);
COPYN(lfWidth);
COPYN(lfEscapement);
COPYN(lfOrientation);
COPYN(lfWeight);
COPYN(lfItalic);
COPYN(lfUnderline);
COPYN(lfStrikeOut);
COPYN(lfCharSet);
COPYN(lfOutPrecision);
COPYN(lfClipPrecision);
COPYN(lfQuality);
COPYN(lfPitchAndFamily);
COPYS(lfFaceName,LF_FACESIZE);
pA->lfFaceName[LF_FACESIZE - 1] = '\0';
#undef COPYN
#undef COPYS
}
VOID
WINAPI
EnumLogFontExW2A( LPENUMLOGFONTEXA fontA, CONST ENUMLOGFONTEXW *fontW )
{
LogFontW2A( (LPLOGFONTA)fontA, (CONST LOGFONTW *)fontW );
WideCharToMultiByte( CP_THREAD_ACP, 0, fontW->elfFullName, -1,
(LPSTR) fontA->elfFullName, LF_FULLFACESIZE, NULL, NULL );
fontA->elfFullName[LF_FULLFACESIZE-1] = '\0';
WideCharToMultiByte( CP_THREAD_ACP, 0, fontW->elfStyle, -1,
(LPSTR) fontA->elfStyle, LF_FACESIZE, NULL, NULL );
fontA->elfStyle[LF_FACESIZE-1] = '\0';
WideCharToMultiByte( CP_THREAD_ACP, 0, fontW->elfScript, -1,
(LPSTR) fontA->elfScript, LF_FACESIZE, NULL, NULL );
fontA->elfScript[LF_FACESIZE-1] = '\0';
}
/*
* LPK.DLL loader function
*
* Returns TRUE if a valid parameter was passed and loading was successful,
* returns FALSE otherwise.
*/
BOOL WINAPI LoadLPK(INT LpkFunctionID)
{
if(!hLpk) // Check if the DLL is already loaded
hLpk = LoadLibraryW(L"lpk.dll");
if (hLpk)
{
switch (LpkFunctionID)
{
case LPK_INIT:
return TRUE;
case LPK_ETO:
if (!LpkExtTextOut) // Check if the function is already loaded
LpkExtTextOut = (LPKETO) GetProcAddress(hLpk, "LpkExtTextOut");
if (!LpkExtTextOut)
{
FreeLibrary(hLpk);
return FALSE;
}
return TRUE;
case LPK_GCP:
if (!LpkGetCharacterPlacement) // Check if the function is already loaded
LpkGetCharacterPlacement = (LPKGCP) GetProcAddress(hLpk, "LpkGetCharacterPlacement");
if (!LpkGetCharacterPlacement)
{
FreeLibrary(hLpk);
return FALSE;
}
return TRUE;
case LPK_GTEP:
if (!LpkGetTextExtentExPoint) // Check if the function is already loaded
LpkGetTextExtentExPoint = (LPKGTEP) GetProcAddress(hLpk, "LpkGetTextExtentExPoint");
if (!LpkGetTextExtentExPoint)
{
FreeLibrary(hLpk);
return FALSE;
}
return TRUE;
default:
FreeLibrary(hLpk);
return FALSE;
}
}
else
return FALSE;
}