mirror of
https://github.com/reactos/reactos.git
synced 2024-11-01 04:11:30 +00:00
fc16259faf
Sync/Port: Metafile code from wine. Patches by Jacek Caban, Daniel Lehman, Zhiyi Zhang. Gabriel Ivancescu, Michael Stefaniuc, Francois Gouget, Nikolay Sivov Dmitry Timoshkov, Andrew EiKum, Piotr Caban and Alexandre Julliard. This commit is dedicated to George Bisoc!
428 lines
10 KiB
C
428 lines
10 KiB
C
|
|
#include <precomp.h>
|
|
#include "gdi_private.h"
|
|
#undef SetWorldTransform
|
|
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
static
|
|
GDILOOBJTYPE
|
|
ConvertObjectType(
|
|
WORD wType)
|
|
{
|
|
/* Get the GDI object type */
|
|
switch (wType)
|
|
{
|
|
case OBJ_PEN: return GDILoObjType_LO_PEN_TYPE;
|
|
case OBJ_BRUSH: return GDILoObjType_LO_BRUSH_TYPE;
|
|
case OBJ_DC: return GDILoObjType_LO_DC_TYPE;
|
|
case OBJ_METADC: return GDILoObjType_LO_METADC16_TYPE;
|
|
case OBJ_PAL: return GDILoObjType_LO_PALETTE_TYPE;
|
|
case OBJ_FONT: return GDILoObjType_LO_FONT_TYPE;
|
|
case OBJ_BITMAP: return GDILoObjType_LO_BITMAP_TYPE;
|
|
case OBJ_REGION: return GDILoObjType_LO_REGION_TYPE;
|
|
case OBJ_METAFILE: return GDILoObjType_LO_METAFILE16_TYPE;
|
|
case OBJ_MEMDC: return GDILoObjType_LO_DC_TYPE;
|
|
case OBJ_EXTPEN: return GDILoObjType_LO_EXTPEN_TYPE;
|
|
case OBJ_ENHMETADC: return GDILoObjType_LO_ALTDC_TYPE;
|
|
case OBJ_ENHMETAFILE: return GDILoObjType_LO_METAFILE_TYPE;
|
|
case OBJ_COLORSPACE: return GDILoObjType_LO_ICMLCS_TYPE;
|
|
default: return 0;
|
|
}
|
|
}
|
|
|
|
HGDIOBJ
|
|
alloc_gdi_handle(
|
|
PVOID pvObject,
|
|
WORD wType,
|
|
const struct gdi_obj_funcs *funcs)
|
|
{
|
|
GDILOOBJTYPE eObjType;
|
|
|
|
/* Get the GDI object type */
|
|
eObjType = ConvertObjectType(wType);
|
|
if ((eObjType != GDILoObjType_LO_METAFILE_TYPE) &&
|
|
(eObjType != GDILoObjType_LO_METAFILE16_TYPE) &&
|
|
(eObjType != GDILoObjType_LO_METADC16_TYPE))
|
|
{
|
|
/* This is not supported! */
|
|
ASSERT(FALSE);
|
|
return NULL;
|
|
}
|
|
|
|
/* Insert the client object */
|
|
return GdiCreateClientObj(pvObject, eObjType);
|
|
}
|
|
|
|
PVOID
|
|
free_gdi_handle(HGDIOBJ hobj)
|
|
{
|
|
/* Should be a client object */
|
|
return GdiDeleteClientObj(hobj);
|
|
}
|
|
|
|
PVOID
|
|
GDI_GetObjPtr(
|
|
HGDIOBJ hobj,
|
|
WORD wType)
|
|
{
|
|
GDILOOBJTYPE eObjType;
|
|
|
|
/* Check if the object type matches */
|
|
eObjType = ConvertObjectType(wType);
|
|
if ((eObjType == 0) || (GDI_HANDLE_GET_TYPE(hobj) != eObjType))
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
/* Check if we have an ALTDC */
|
|
if (eObjType == GDILoObjType_LO_ALTDC_TYPE)
|
|
{
|
|
/* Object is stored as LDC */
|
|
return GdiGetLDC(hobj);
|
|
}
|
|
|
|
/* Check for client objects */
|
|
if ((eObjType == GDILoObjType_LO_METAFILE_TYPE) ||
|
|
(eObjType == GDILoObjType_LO_METAFILE16_TYPE) ||
|
|
(eObjType == GDILoObjType_LO_METADC16_TYPE))
|
|
{
|
|
return GdiGetClientObjLink(hobj);
|
|
}
|
|
|
|
/* This should never happen! */
|
|
ASSERT(FALSE);
|
|
return NULL;
|
|
}
|
|
|
|
VOID
|
|
GDI_ReleaseObj(HGDIOBJ hobj)
|
|
{
|
|
/* We don't do any reference-counting */
|
|
}
|
|
|
|
WINEDC*
|
|
alloc_dc_ptr(WORD magic)
|
|
{
|
|
WINEDC* pWineDc;
|
|
|
|
/* Allocate the Wine DC */
|
|
pWineDc = HeapAlloc(GetProcessHeap(), 0, sizeof(*pWineDc));
|
|
if (pWineDc == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
ZeroMemory(pWineDc, sizeof(*pWineDc));
|
|
pWineDc->hBrush = GetStockObject(WHITE_BRUSH);
|
|
pWineDc->hPen = GetStockObject(BLACK_PEN);
|
|
|
|
if (magic == OBJ_ENHMETADC)
|
|
{
|
|
/* We create a metafile DC, but we ignore the reference DC, this is
|
|
handled by the wine code */
|
|
pWineDc->hdc = NtGdiCreateMetafileDC(NULL);
|
|
if (pWineDc->hdc == NULL)
|
|
{
|
|
HeapFree(GetProcessHeap(), 0, pWineDc);
|
|
return NULL;
|
|
}
|
|
|
|
pWineDc->iType = LDC_EMFLDC;
|
|
|
|
/* Set the Wine DC as LDC */
|
|
GdiSetLDC(pWineDc->hdc, pWineDc);
|
|
}
|
|
else
|
|
{
|
|
// nothing else supported!
|
|
ASSERT(FALSE);
|
|
}
|
|
|
|
return pWineDc;
|
|
}
|
|
|
|
WINEDC*
|
|
get_dc_ptr(HDC hdc)
|
|
{
|
|
/* Check for EMF DC */
|
|
if (GDI_HANDLE_GET_TYPE(hdc) == GDILoObjType_LO_ALTDC_TYPE)
|
|
{
|
|
/* The Wine DC is stored as the LDC */
|
|
return (WINEDC*)GdiGetLDC(hdc);
|
|
}
|
|
|
|
/* Check for METADC16 */
|
|
if (GDI_HANDLE_GET_TYPE(hdc) == GDILoObjType_LO_METADC16_TYPE)
|
|
{
|
|
return GdiGetClientObjLink(hdc);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
VOID
|
|
GDI_hdc_using_object(
|
|
HGDIOBJ hobj,
|
|
HDC hdc)
|
|
{
|
|
/* Record that we have an object in use by a METADC. We simply link the
|
|
object to the HDC that we use. Wine API does not give us a way to
|
|
respond to failure, so we silently ignore it */
|
|
if (!GdiCreateClientObjLink(hobj, hdc))
|
|
{
|
|
/* Ignore failure, and return */
|
|
DPRINT1("Failed to create link for selected METADC object.\n");
|
|
return;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
GDI_hdc_not_using_object(
|
|
HGDIOBJ hobj,
|
|
HDC hdc)
|
|
{
|
|
HDC hdcLink;
|
|
|
|
/* Remove the HDC link for the object */
|
|
hdcLink = GdiRemoveClientObjLink(hobj);
|
|
ASSERT(hdcLink == hdc);
|
|
}
|
|
|
|
/***********************************************************************
|
|
* bitmap_info_size
|
|
*
|
|
* Return the size of the bitmap info structure including color table.
|
|
*/
|
|
int
|
|
bitmap_info_size(
|
|
const BITMAPINFO * info,
|
|
WORD coloruse)
|
|
{
|
|
unsigned int colors, size, masks = 0;
|
|
|
|
if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
|
|
{
|
|
const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)info;
|
|
colors = (core->bcBitCount <= 8) ? 1 << core->bcBitCount : 0;
|
|
return sizeof(BITMAPCOREHEADER) + colors *
|
|
((coloruse == DIB_RGB_COLORS) ? sizeof(RGBTRIPLE) : sizeof(WORD));
|
|
}
|
|
else /* assume BITMAPINFOHEADER */
|
|
{
|
|
if (info->bmiHeader.biClrUsed) colors = min( info->bmiHeader.biClrUsed, 256 );
|
|
else colors = info->bmiHeader.biBitCount > 8 ? 0 : 1 << info->bmiHeader.biBitCount;
|
|
if (info->bmiHeader.biCompression == BI_BITFIELDS) masks = 3;
|
|
size = max( info->bmiHeader.biSize, sizeof(BITMAPINFOHEADER) + masks * sizeof(DWORD) );
|
|
return size + colors * ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBQUAD) : sizeof(WORD));
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
get_brush_bitmap_info(
|
|
HBRUSH hbr,
|
|
PBITMAPINFO pbmi,
|
|
PVOID pvBits,
|
|
PUINT puUsage)
|
|
{
|
|
HBITMAP hbmp;
|
|
HDC hdc;
|
|
PVOID Bits;
|
|
|
|
/* Call win32k to get the bitmap handle and color usage */
|
|
hbmp = NtGdiGetObjectBitmapHandle(hbr, puUsage);
|
|
if (hbmp == NULL)
|
|
return FALSE;
|
|
|
|
hdc = GetDC(NULL);
|
|
if (hdc == NULL)
|
|
return FALSE;
|
|
|
|
/* Initialize the BITMAPINFO */
|
|
ZeroMemory(pbmi, sizeof(*pbmi));
|
|
pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
|
|
|
/* Retrieve information about the bitmap */
|
|
if (!GetDIBits(hdc, hbmp, 0, 0, NULL, pbmi, *puUsage))
|
|
return FALSE;
|
|
|
|
if (pvBits)
|
|
{
|
|
/* Now allocate a buffer for the bits */
|
|
Bits = HeapAlloc(GetProcessHeap(), 0, pbmi->bmiHeader.biSizeImage);
|
|
if (Bits == NULL)
|
|
return FALSE;
|
|
|
|
/* Retrieve the bitmap bits */
|
|
if (!GetDIBits(hdc, hbmp, 0, pbmi->bmiHeader.biHeight, Bits, pbmi, *puUsage))
|
|
{
|
|
HeapFree(GetProcessHeap(), 0, Bits);
|
|
return FALSE;
|
|
}
|
|
|
|
CopyMemory( pvBits, Bits, pbmi->bmiHeader.biSizeImage );
|
|
|
|
}
|
|
|
|
/* GetDIBits doesn't set biClrUsed, but wine code needs it, so we set it */
|
|
if (pbmi->bmiHeader.biBitCount <= 8)
|
|
{
|
|
pbmi->bmiHeader.biClrUsed = 1 << pbmi->bmiHeader.biBitCount;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
WINAPI
|
|
SetVirtualResolution(
|
|
HDC hdc,
|
|
DWORD cxVirtualDevicePixel,
|
|
DWORD cyVirtualDevicePixel,
|
|
DWORD cxVirtualDeviceMm,
|
|
DWORD cyVirtualDeviceMm)
|
|
{
|
|
return NtGdiSetVirtualResolution(hdc,
|
|
cxVirtualDevicePixel,
|
|
cyVirtualDevicePixel,
|
|
cxVirtualDeviceMm,
|
|
cyVirtualDeviceMm);
|
|
}
|
|
|
|
BOOL
|
|
WINAPI
|
|
DeleteColorSpace(
|
|
HCOLORSPACE hcs)
|
|
{
|
|
return NtGdiDeleteColorSpace(hcs);
|
|
}
|
|
void
|
|
__cdecl
|
|
_assert (
|
|
const char *exp,
|
|
const char *file,
|
|
unsigned line)
|
|
{
|
|
DbgRaiseAssertionFailure();
|
|
}
|
|
|
|
/******************************************************************************/
|
|
BOOL
|
|
WINAPI
|
|
METADC_SetD(
|
|
_In_ HDC hdc,
|
|
_In_ DWORD dwIn,
|
|
_In_ USHORT usMF16Id
|
|
)
|
|
{
|
|
switch(usMF16Id)
|
|
{
|
|
case META_SETMAPMODE:
|
|
return METADC_SetMapMode(hdc, dwIn);
|
|
case META_SETRELABS:
|
|
return METADC_SetRelAbs(hdc, dwIn);
|
|
default:
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
WINAPI
|
|
EMFDC_SetD(
|
|
_In_ PLDC pldc,
|
|
_In_ DWORD dwIn,
|
|
_In_ ULONG ulMFId)
|
|
{
|
|
switch(ulMFId)
|
|
{
|
|
case EMR_SETMAPMODE:
|
|
return EMFDC_SetMapMode( pldc, dwIn);
|
|
case EMR_SETARCDIRECTION:
|
|
return EMFDC_SetArcDirection( pldc, dwIn);
|
|
default:
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
extern void METADC_DeleteObject( HDC hdc, HGDIOBJ obj );
|
|
extern void emfdc_delete_object( HDC hdc, HGDIOBJ obj );
|
|
|
|
VOID
|
|
WINAPI
|
|
METADC_RosGlueDeleteObject(HGDIOBJ hobj)
|
|
{
|
|
GDILOOBJTYPE eObjectType;
|
|
HDC hdc;
|
|
|
|
/* Check for one of the types we actually handle here */
|
|
eObjectType = GDI_HANDLE_GET_TYPE(hobj);
|
|
if ((eObjectType != GDILoObjType_LO_BRUSH_TYPE) &&
|
|
(eObjectType != GDILoObjType_LO_PEN_TYPE) &&
|
|
(eObjectType != GDILoObjType_LO_EXTPEN_TYPE) &&
|
|
(eObjectType != GDILoObjType_LO_PALETTE_TYPE) &&
|
|
(eObjectType != GDILoObjType_LO_FONT_TYPE))
|
|
{
|
|
return;
|
|
}
|
|
|
|
/* Check if we have a client object link and remove it if it was found.
|
|
The link is the HDC that the object was selected into. */
|
|
hdc = GdiRemoveClientObjLink(hobj);
|
|
if (hdc == NULL)
|
|
{
|
|
DPRINT1("the link was not found\n");
|
|
/* The link was not found, so we are not handling this object here */
|
|
return;
|
|
}
|
|
|
|
if ( GDI_HANDLE_GET_TYPE(hdc) == GDILoObjType_LO_METADC16_TYPE ) METADC_DeleteObject( hdc, hobj );
|
|
|
|
if ( GDI_HANDLE_GET_TYPE(hdc) == GDILoObjType_LO_ALTDC_TYPE )
|
|
{
|
|
LDC* pWineDc = GdiGetLDC(hdc);
|
|
if ( pWineDc )
|
|
{
|
|
emfdc_delete_object( hdc, hobj );
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
WINAPI
|
|
METADC_RosGlueDeleteDC(
|
|
_In_ HDC hdc)
|
|
{
|
|
LDC* pWineDc = NULL;
|
|
|
|
if ( GDI_HANDLE_GET_TYPE(hdc) == GDILoObjType_LO_METADC16_TYPE )
|
|
{
|
|
return METADC_DeleteDC(hdc);
|
|
}
|
|
|
|
if ( GDI_HANDLE_GET_TYPE(hdc) == GDILoObjType_LO_ALTDC_TYPE )
|
|
{
|
|
pWineDc = GdiGetLDC(hdc);
|
|
|
|
if ( pWineDc )
|
|
{
|
|
// Handle Printer LDC
|
|
if (pWineDc->iType != LDC_EMFLDC)
|
|
{
|
|
//return IntDeleteDC(hdc);
|
|
}
|
|
|
|
EMFDC_DeleteDC( pWineDc );
|
|
|
|
/* Get rid of the LDC */
|
|
ASSERT(GdiGetLDC(pWineDc->hDC) == pWineDc);
|
|
GdiSetLDC(pWineDc->hDC, NULL);
|
|
|
|
/* Free the Wine DC */
|
|
HeapFree(GetProcessHeap(), 0, pWineDc);
|
|
}
|
|
}
|
|
|
|
return NtGdiDeleteObjectApp(hdc);
|
|
}
|
|
|