reactos/win32ss/gdi/gdi32/misc/misc.c
James Tabor fc16259faf [GDI32] Update Wine Metafile Code
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!
2021-09-27 16:18:20 -05:00

1095 lines
33 KiB
C

/*
* ReactOS GDI lib
* Copyright (C) 2003 ReactOS Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/*
* PROJECT: ReactOS gdi32.dll
* FILE: win32ss/gdi/gdi32/misc/misc.c
* PURPOSE: Miscellaneous functions
* PROGRAMMER: Thomas Weidenmueller <w3seek@reactos.com>
* UPDATE HISTORY:
* 2004/09/04 Created
*/
#include <precomp.h>
#define NDEBUG
#include <debug.h>
PGDI_TABLE_ENTRY GdiHandleTable = NULL;
PGDI_SHARED_HANDLE_TABLE GdiSharedHandleTable = NULL;
HANDLE CurrentProcessId = NULL;
DWORD GDI_BatchLimit = 1;
extern PGDIHANDLECACHE GdiHandleCache;
/*
* @implemented
*/
BOOL
WINAPI
GdiFlush(VOID)
{
NtGdiFlush();
return TRUE;
}
/*
* @unimplemented
*/
INT
WINAPI
Escape(
_In_ HDC hdc,
_In_ INT nEscape,
_In_ INT cbInput,
_In_ LPCSTR lpvInData,
_Out_ LPVOID lpvOutData)
{
INT retValue = SP_ERROR;
ULONG ulObjType;
ulObjType = GDI_HANDLE_GET_TYPE(hdc);
if (ulObjType == GDILoObjType_LO_METADC16_TYPE)
{
return METADC_ExtEscape(hdc, nEscape, cbInput, lpvInData, 0, lpvOutData);
}
switch (nEscape)
{
case ABORTDOC:
/* Note: Windows checks if the handle has any user data for the ABORTDOC command
* ReactOS copies this behavior to be compatible with windows 2003
*/
if (GdiGetDcAttr(hdc) == NULL)
{
GdiSetLastError(ERROR_INVALID_HANDLE);
retValue = FALSE;
}
else
{
retValue = AbortDoc(hdc);
}
break;
case DRAFTMODE:
case FLUSHOUTPUT:
case SETCOLORTABLE:
/* Note 1: DRAFTMODE, FLUSHOUTPUT, SETCOLORTABLE are outdated */
/* Note 2: Windows checks if the handle has any user data for the DRAFTMODE, FLUSHOUTPUT, SETCOLORTABLE commands
* ReactOS copies this behavior to be compatible with windows 2003
*/
if (GdiGetDcAttr(hdc) == NULL)
{
GdiSetLastError(ERROR_INVALID_HANDLE);
}
retValue = FALSE;
break;
case SETABORTPROC:
/* Note: Windows checks if the handle has any user data for the SETABORTPROC command
* ReactOS copies this behavior to be compatible with windows 2003
*/
if (GdiGetDcAttr(hdc) == NULL)
{
GdiSetLastError(ERROR_INVALID_HANDLE);
retValue = FALSE;
}
retValue = SetAbortProc(hdc, (ABORTPROC)lpvInData);
break;
case GETCOLORTABLE:
retValue = GetSystemPaletteEntries(hdc, (UINT)*lpvInData, 1, (LPPALETTEENTRY)lpvOutData);
if (!retValue)
{
retValue = SP_ERROR;
}
break;
case ENDDOC:
/* Note: Windows checks if the handle has any user data for the ENDDOC command
* ReactOS copies this behavior to be compatible with windows 2003
*/
if (GdiGetDcAttr(hdc) == NULL)
{
GdiSetLastError(ERROR_INVALID_HANDLE);
retValue = FALSE;
}
retValue = EndDoc(hdc);
break;
case GETSCALINGFACTOR:
/* Note GETSCALINGFACTOR is outdated have been replace by GetDeviceCaps */
if (ulObjType == GDI_OBJECT_TYPE_DC)
{
if (lpvOutData)
{
PPOINT ptr = (PPOINT)lpvOutData;
ptr->x = 0;
ptr->y = 0;
}
}
retValue = FALSE;
break;
case GETEXTENDEDTEXTMETRICS:
retValue = GetETM(hdc, (EXTTEXTMETRIC *)lpvOutData) != 0;
break;
case STARTDOC:
{
DOCINFOA di;
/* Note: Windows checks if the handle has any user data for the STARTDOC command
* ReactOS copies this behavior to be compatible with windows 2003
*/
if (GdiGetDcAttr(hdc) == NULL)
{
GdiSetLastError(ERROR_INVALID_HANDLE);
retValue = FALSE;
}
di.cbSize = sizeof(DOCINFOA);
di.lpszOutput = 0;
di.lpszDatatype = 0;
di.fwType = 0;
di.lpszDocName = lpvInData;
/* NOTE : doc for StartDocA/W at msdn http://msdn2.microsoft.com/en-us/library/ms535793(VS.85).aspx */
retValue = StartDocA(hdc, &di);
/* Check if StartDocA failed */
if (retValue < 0)
{
{
retValue = GetLastError();
/* Translate StartDocA error code to STARTDOC error code
* see msdn http://msdn2.microsoft.com/en-us/library/ms535472.aspx
*/
switch(retValue)
{
case ERROR_NOT_ENOUGH_MEMORY:
retValue = SP_OUTOFMEMORY;
break;
case ERROR_PRINT_CANCELLED:
retValue = SP_USERABORT;
break;
case ERROR_DISK_FULL:
retValue = SP_OUTOFDISK;
break;
default:
retValue = SP_ERROR;
break;
}
}
}
}
break;
default:
UNIMPLEMENTED;
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
}
return retValue;
}
INT
WINAPI
ExtEscape(HDC hDC,
int nEscape,
int cbInput,
LPCSTR lpszInData,
int cbOutput,
LPSTR lpszOutData)
{
return NtGdiExtEscape(hDC, NULL, 0, nEscape, cbInput, (LPSTR)lpszInData, cbOutput, lpszOutData);
}
INT
WINAPI
NamedEscape(HDC hdc,
PWCHAR pDriver,
INT iEsc,
INT cjIn,
LPSTR pjIn,
INT cjOut,
LPSTR pjOut)
{
/* FIXME metadc, metadc are done most in user mode, and we do not support it
* Windows 2000/XP/Vista ignore the current hdc, that are being pass and always set hdc to NULL
* when it calls to NtGdiExtEscape from NamedEscape
*/
return NtGdiExtEscape(NULL,pDriver,wcslen(pDriver),iEsc,cjIn,pjIn,cjOut,pjOut);
}
/*
* @implemented
*/
int
WINAPI
DrawEscape(HDC hDC,
INT nEscape,
INT cbInput,
LPCSTR lpszInData)
{
if (GDI_HANDLE_GET_TYPE(hDC) == GDI_OBJECT_TYPE_DC)
return NtGdiDrawEscape(hDC, nEscape, cbInput, (LPSTR) lpszInData);
if (GDI_HANDLE_GET_TYPE(hDC) != GDI_OBJECT_TYPE_METADC)
{
PLDC pLDC = GdiGetLDC(hDC);
if ( pLDC )
{
if (pLDC->Flags & LDC_META_PRINT)
{
// if (nEscape != QUERYESCSUPPORT)
// return EMFDRV_WriteEscape(hDC, nEscape, cbInput, lpszInData, EMR_DRAWESCAPE);
return NtGdiDrawEscape(hDC, nEscape, cbInput, (LPSTR) lpszInData);
}
}
SetLastError(ERROR_INVALID_HANDLE);
}
return 0;
}
#define ALPHABLEND_NONE 0
#define ALPHABLEND_BINARY 1
#define ALPHABLEND_FULL 2
typedef struct _MARGINS {
int cxLeftWidth;
int cxRightWidth;
int cyTopHeight;
int cyBottomHeight;
} MARGINS, *PMARGINS;
enum SIZINGTYPE {
ST_TRUESIZE = 0,
ST_STRETCH = 1,
ST_TILE = 2,
};
#define TransparentBlt GdiTransparentBlt
#define AlphaBlend GdiAlphaBlend
/***********************************************************************
* UXTHEME_StretchBlt
*
* Pseudo TransparentBlt/StretchBlt
*/
static inline BOOL UXTHEME_StretchBlt(HDC hdcDst, int nXOriginDst, int nYOriginDst, int nWidthDst, int nHeightDst,
HDC hdcSrc, int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc,
INT transparent, COLORREF transcolor)
{
static const BLENDFUNCTION blendFunc =
{
AC_SRC_OVER, /* BlendOp */
0, /* BlendFlag */
255, /* SourceConstantAlpha */
AC_SRC_ALPHA /* AlphaFormat */
};
BOOL ret = TRUE;
int old_stretch_mode;
POINT old_brush_org;
old_stretch_mode = SetStretchBltMode(hdcDst, HALFTONE);
SetBrushOrgEx(hdcDst, nXOriginDst, nYOriginDst, &old_brush_org);
if (transparent == ALPHABLEND_BINARY) {
/* Ensure we don't pass any negative values to TransparentBlt */
ret = TransparentBlt(hdcDst, nXOriginDst, nYOriginDst, abs(nWidthDst), abs(nHeightDst),
hdcSrc, nXOriginSrc, nYOriginSrc, abs(nWidthSrc), abs(nHeightSrc),
transcolor);
} else if ((transparent == ALPHABLEND_NONE) ||
!AlphaBlend(hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst,
hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc,
blendFunc))
{
ret = StretchBlt(hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst,
hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc,
SRCCOPY);
}
SetBrushOrgEx(hdcDst, old_brush_org.x, old_brush_org.y, NULL);
SetStretchBltMode(hdcDst, old_stretch_mode);
return ret;
}
/***********************************************************************
* UXTHEME_Blt
*
* Simplify sending same width/height for both source and dest
*/
static inline BOOL UXTHEME_Blt(HDC hdcDest, int nXOriginDest, int nYOriginDest, int nWidthDest, int nHeightDest,
HDC hdcSrc, int nXOriginSrc, int nYOriginSrc,
INT transparent, COLORREF transcolor)
{
return UXTHEME_StretchBlt(hdcDest, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest,
hdcSrc, nXOriginSrc, nYOriginSrc, nWidthDest, nHeightDest,
transparent, transcolor);
}
/***********************************************************************
* UXTHEME_SizedBlt
*
* Stretches or tiles, depending on sizingtype.
*/
static inline BOOL UXTHEME_SizedBlt (HDC hdcDst, int nXOriginDst, int nYOriginDst,
int nWidthDst, int nHeightDst,
HDC hdcSrc, int nXOriginSrc, int nYOriginSrc,
int nWidthSrc, int nHeightSrc,
int sizingtype,
INT transparent, COLORREF transcolor)
{
if (sizingtype == ST_TILE)
{
HDC hdcTemp;
BOOL result = FALSE;
if (!nWidthSrc || !nHeightSrc) return TRUE;
/* For destination width/height less than or equal to source
width/height, do not bother with memory bitmap optimization */
if (nWidthSrc >= nWidthDst && nHeightSrc >= nHeightDst)
{
int bltWidth = min (nWidthDst, nWidthSrc);
int bltHeight = min (nHeightDst, nHeightSrc);
return UXTHEME_Blt (hdcDst, nXOriginDst, nYOriginDst, bltWidth, bltHeight,
hdcSrc, nXOriginSrc, nYOriginSrc,
transparent, transcolor);
}
/* Create a DC with a bitmap consisting of a tiling of the source
bitmap, with standard GDI functions. This is faster than an
iteration with UXTHEME_Blt(). */
hdcTemp = CreateCompatibleDC(hdcSrc);
if (hdcTemp != 0)
{
HBITMAP bitmapTemp;
HBITMAP bitmapOrig;
int nWidthTemp, nHeightTemp;
int xOfs, xRemaining;
int yOfs, yRemaining;
int growSize;
/* Calculate temp dimensions of integer multiples of source dimensions */
nWidthTemp = ((nWidthDst + nWidthSrc - 1) / nWidthSrc) * nWidthSrc;
nHeightTemp = ((nHeightDst + nHeightSrc - 1) / nHeightSrc) * nHeightSrc;
bitmapTemp = CreateCompatibleBitmap(hdcSrc, nWidthTemp, nHeightTemp);
bitmapOrig = SelectObject(hdcTemp, bitmapTemp);
/* Initial copy of bitmap */
BitBlt(hdcTemp, 0, 0, nWidthSrc, nHeightSrc, hdcSrc, nXOriginSrc, nYOriginSrc, SRCCOPY);
/* Extend bitmap in the X direction. Growth of width is exponential */
xOfs = nWidthSrc;
xRemaining = nWidthTemp - nWidthSrc;
growSize = nWidthSrc;
while (xRemaining > 0)
{
growSize = min(growSize, xRemaining);
BitBlt(hdcTemp, xOfs, 0, growSize, nHeightSrc, hdcTemp, 0, 0, SRCCOPY);
xOfs += growSize;
xRemaining -= growSize;
growSize *= 2;
}
/* Extend bitmap in the Y direction. Growth of height is exponential */
yOfs = nHeightSrc;
yRemaining = nHeightTemp - nHeightSrc;
growSize = nHeightSrc;
while (yRemaining > 0)
{
growSize = min(growSize, yRemaining);
BitBlt(hdcTemp, 0, yOfs, nWidthTemp, growSize, hdcTemp, 0, 0, SRCCOPY);
yOfs += growSize;
yRemaining -= growSize;
growSize *= 2;
}
/* Use temporary hdc for source */
result = UXTHEME_Blt (hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst,
hdcTemp, 0, 0,
transparent, transcolor);
SelectObject(hdcTemp, bitmapOrig);
DeleteObject(bitmapTemp);
}
DeleteDC(hdcTemp);
return result;
}
else
{
return UXTHEME_StretchBlt (hdcDst, nXOriginDst, nYOriginDst, nWidthDst, nHeightDst,
hdcSrc, nXOriginSrc, nYOriginSrc, nWidthSrc, nHeightSrc,
transparent, transcolor);
}
}
/***********************************************************************
* UXTHEME_DrawImageBackground
*
* Draw an imagefile background
*/
static HRESULT UXTHEME_DrawImageBackground(HDC hdc, HBITMAP bmpSrc, RECT *prcSrc, INT transparent,
COLORREF transparentcolor, BOOL borderonly, int sizingtype, MARGINS *psm, RECT *pRect)
{
HRESULT hr = S_OK;
HBITMAP bmpSrcResized = NULL;
HGDIOBJ oldSrc;
HDC hdcSrc, hdcOrigSrc = NULL;
RECT rcDst;
POINT dstSize;
POINT srcSize;
RECT rcSrc;
MARGINS sm;
rcDst = *pRect;
rcSrc = *prcSrc;
sm = *psm;
hdcSrc = CreateCompatibleDC(hdc);
if(!hdcSrc) {
hr = HRESULT_FROM_WIN32(GetLastError());
return hr;
}
oldSrc = SelectObject(hdcSrc, bmpSrc);
dstSize.x = rcDst.right-rcDst.left;
dstSize.y = rcDst.bottom-rcDst.top;
srcSize.x = rcSrc.right-rcSrc.left;
srcSize.y = rcSrc.bottom-rcSrc.top;
if(sizingtype == ST_TRUESIZE) {
if(!UXTHEME_StretchBlt(hdc, rcDst.left, rcDst.top, dstSize.x, dstSize.y,
hdcSrc, rcSrc.left, rcSrc.top, srcSize.x, srcSize.y,
transparent, transparentcolor))
hr = HRESULT_FROM_WIN32(GetLastError());
}
else {
HDC hdcDst = NULL;
POINT org;
dstSize.x = abs(dstSize.x);
dstSize.y = abs(dstSize.y);
/* Resize source image if destination smaller than margins */
#ifndef __REACTOS__
/* Revert Wine Commit 2b650fa as it breaks themed Explorer Toolbar Separators
FIXME: Revisit this when the bug is fixed. CORE-9636 and Wine Bug #38538 */
if (sm.cyTopHeight + sm.cyBottomHeight > dstSize.y || sm.cxLeftWidth + sm.cxRightWidth > dstSize.x) {
if (sm.cyTopHeight + sm.cyBottomHeight > dstSize.y) {
sm.cyTopHeight = MulDiv(sm.cyTopHeight, dstSize.y, srcSize.y);
sm.cyBottomHeight = dstSize.y - sm.cyTopHeight;
srcSize.y = dstSize.y;
}
if (sm.cxLeftWidth + sm.cxRightWidth > dstSize.x) {
sm.cxLeftWidth = MulDiv(sm.cxLeftWidth, dstSize.x, srcSize.x);
sm.cxRightWidth = dstSize.x - sm.cxLeftWidth;
srcSize.x = dstSize.x;
}
hdcOrigSrc = hdcSrc;
hdcSrc = CreateCompatibleDC(NULL);
bmpSrcResized = CreateBitmap(srcSize.x, srcSize.y, 1, 32, NULL);
SelectObject(hdcSrc, bmpSrcResized);
UXTHEME_StretchBlt(hdcSrc, 0, 0, srcSize.x, srcSize.y, hdcOrigSrc, rcSrc.left, rcSrc.top,
rcSrc.right - rcSrc.left, rcSrc.bottom - rcSrc.top, transparent, transparentcolor);
rcSrc.left = 0;
rcSrc.top = 0;
rcSrc.right = srcSize.x;
rcSrc.bottom = srcSize.y;
}
#endif /* __REACTOS__ */
hdcDst = hdc;
OffsetViewportOrgEx(hdcDst, rcDst.left, rcDst.top, &org);
/* Upper left corner */
if(!UXTHEME_Blt(hdcDst, 0, 0, sm.cxLeftWidth, sm.cyTopHeight,
hdcSrc, rcSrc.left, rcSrc.top,
transparent, transparentcolor)) {
hr = HRESULT_FROM_WIN32(GetLastError());
goto draw_error;
}
/* Upper right corner */
if(!UXTHEME_Blt (hdcDst, dstSize.x-sm.cxRightWidth, 0,
sm.cxRightWidth, sm.cyTopHeight,
hdcSrc, rcSrc.right-sm.cxRightWidth, rcSrc.top,
transparent, transparentcolor)) {
hr = HRESULT_FROM_WIN32(GetLastError());
goto draw_error;
}
/* Lower left corner */
if(!UXTHEME_Blt (hdcDst, 0, dstSize.y-sm.cyBottomHeight,
sm.cxLeftWidth, sm.cyBottomHeight,
hdcSrc, rcSrc.left, rcSrc.bottom-sm.cyBottomHeight,
transparent, transparentcolor)) {
hr = HRESULT_FROM_WIN32(GetLastError());
goto draw_error;
}
/* Lower right corner */
if(!UXTHEME_Blt (hdcDst, dstSize.x-sm.cxRightWidth, dstSize.y-sm.cyBottomHeight,
sm.cxRightWidth, sm.cyBottomHeight,
hdcSrc, rcSrc.right-sm.cxRightWidth, rcSrc.bottom-sm.cyBottomHeight,
transparent, transparentcolor)) {
hr = HRESULT_FROM_WIN32(GetLastError());
goto draw_error;
}
if ((sizingtype == ST_STRETCH) || (sizingtype == ST_TILE)) {
int destCenterWidth = dstSize.x - (sm.cxLeftWidth + sm.cxRightWidth);
int srcCenterWidth = srcSize.x - (sm.cxLeftWidth + sm.cxRightWidth);
int destCenterHeight = dstSize.y - (sm.cyTopHeight + sm.cyBottomHeight);
int srcCenterHeight = srcSize.y - (sm.cyTopHeight + sm.cyBottomHeight);
if(destCenterWidth > 0) {
/* Center top */
if(!UXTHEME_SizedBlt (hdcDst, sm.cxLeftWidth, 0,
destCenterWidth, sm.cyTopHeight,
hdcSrc, rcSrc.left+sm.cxLeftWidth, rcSrc.top,
srcCenterWidth, sm.cyTopHeight,
sizingtype, transparent, transparentcolor)) {
hr = HRESULT_FROM_WIN32(GetLastError());
goto draw_error;
}
/* Center bottom */
if(!UXTHEME_SizedBlt (hdcDst, sm.cxLeftWidth, dstSize.y-sm.cyBottomHeight,
destCenterWidth, sm.cyBottomHeight,
hdcSrc, rcSrc.left+sm.cxLeftWidth, rcSrc.bottom-sm.cyBottomHeight,
srcCenterWidth, sm.cyBottomHeight,
sizingtype, transparent, transparentcolor)) {
hr = HRESULT_FROM_WIN32(GetLastError());
goto draw_error;
}
}
if(destCenterHeight > 0) {
/* Left center */
if(!UXTHEME_SizedBlt (hdcDst, 0, sm.cyTopHeight,
sm.cxLeftWidth, destCenterHeight,
hdcSrc, rcSrc.left, rcSrc.top+sm.cyTopHeight,
sm.cxLeftWidth, srcCenterHeight,
sizingtype,
transparent, transparentcolor)) {
hr = HRESULT_FROM_WIN32(GetLastError());
goto draw_error;
}
/* Right center */
if(!UXTHEME_SizedBlt (hdcDst, dstSize.x-sm.cxRightWidth, sm.cyTopHeight,
sm.cxRightWidth, destCenterHeight,
hdcSrc, rcSrc.right-sm.cxRightWidth, rcSrc.top+sm.cyTopHeight,
sm.cxRightWidth, srcCenterHeight,
sizingtype, transparent, transparentcolor)) {
hr = HRESULT_FROM_WIN32(GetLastError());
goto draw_error;
}
}
if(destCenterHeight > 0 && destCenterWidth > 0) {
if(!borderonly) {
/* Center */
if(!UXTHEME_SizedBlt (hdcDst, sm.cxLeftWidth, sm.cyTopHeight,
destCenterWidth, destCenterHeight,
hdcSrc, rcSrc.left+sm.cxLeftWidth, rcSrc.top+sm.cyTopHeight,
srcCenterWidth, srcCenterHeight,
sizingtype, transparent, transparentcolor)) {
hr = HRESULT_FROM_WIN32(GetLastError());
goto draw_error;
}
}
}
}
draw_error:
SetViewportOrgEx (hdcDst, org.x, org.y, NULL);
}
SelectObject(hdcSrc, oldSrc);
DeleteDC(hdcSrc);
if (bmpSrcResized) DeleteObject(bmpSrcResized);
if (hdcOrigSrc) DeleteDC(hdcOrigSrc);
*pRect = rcDst;
return hr;
}
/*
* @unimplemented
*/
BOOL
WINAPI
GdiDrawStream(HDC dc, ULONG l, PGDI_DRAW_STREAM pDS)
{
if (!pDS || l != sizeof(*pDS))
{
DPRINT1("GdiDrawStream: Invalid params\n");
return 0;
}
if (pDS->signature != 0x44727753 ||
pDS->reserved != 0 ||
pDS->unknown1 != 1 ||
pDS->unknown2 != 9)
{
DPRINT1("GdiDrawStream: Got unknown pDS data\n");
return 0;
}
{
MARGINS sm = {pDS->leftSizingMargin, pDS->rightSizingMargin, pDS->topSizingMargin, pDS->bottomSizingMargin};
INT transparent = 0;
int sizingtype;
if (pDS->drawOption & DS_TRANSPARENTALPHA)
transparent = ALPHABLEND_FULL;
else if (pDS->drawOption & DS_TRANSPARENTCLR)
transparent = ALPHABLEND_BINARY;
else
transparent = ALPHABLEND_NONE;
if (pDS->drawOption & DS_TILE)
sizingtype = ST_TILE;
else if (pDS->drawOption & DS_TRUESIZE)
sizingtype = ST_TRUESIZE;
else
sizingtype = ST_STRETCH;
if (pDS->rcDest.right < pDS->rcDest.left || pDS->rcDest.bottom < pDS->rcDest.top)
return 0;
if (sm.cxLeftWidth + sm.cxRightWidth > pDS->rcDest.right - pDS->rcDest.left)
{
sm.cxLeftWidth = sm.cxRightWidth = 0;
}
if (sm.cyTopHeight + sm.cyBottomHeight > pDS->rcDest.bottom - pDS->rcDest.top)
{
sm.cyTopHeight = sm.cyBottomHeight = 0;
}
UXTHEME_DrawImageBackground(pDS->hDC,
pDS->hImage,
&pDS->rcSrc,
transparent,
pDS->crTransparent,
FALSE,
sizingtype,
&sm,
&pDS->rcDest);
}
return 0;
}
/*
* @implemented
*/
BOOL
WINAPI
GdiValidateHandle(HGDIOBJ hobj)
{
PGDI_TABLE_ENTRY Entry = GdiHandleTable + GDI_HANDLE_GET_INDEX(hobj);
if ( (Entry->Type & GDI_ENTRY_BASETYPE_MASK) != 0 &&
( (Entry->Type << GDI_ENTRY_UPPER_SHIFT) & GDI_HANDLE_TYPE_MASK ) ==
GDI_HANDLE_GET_TYPE(hobj) )
{
HANDLE pid = (HANDLE)((ULONG_PTR)Entry->ProcessId & ~0x1);
if(pid == NULL || pid == CurrentProcessId)
{
return TRUE;
}
}
return FALSE;
}
/*
* @implemented
*/
HGDIOBJ
WINAPI
GdiFixUpHandle(HGDIOBJ hGdiObj)
{
PGDI_TABLE_ENTRY Entry;
if (((ULONG_PTR)(hGdiObj)) & GDI_HANDLE_UPPER_MASK )
{
return hGdiObj;
}
/* FIXME is this right ?? */
Entry = GdiHandleTable + GDI_HANDLE_GET_INDEX(hGdiObj);
/* Rebuild handle for Object */
return (HGDIOBJ)(((ULONG_PTR)(hGdiObj)) | (Entry->Type << GDI_ENTRY_UPPER_SHIFT));
}
/*
* @implemented
*/
PVOID
WINAPI
GdiQueryTable(VOID)
{
return (PVOID)GdiHandleTable;
}
BOOL GdiGetHandleUserData(HGDIOBJ hGdiObj, DWORD ObjectType, PVOID *UserData)
{
PGDI_TABLE_ENTRY Entry = GdiHandleTable + GDI_HANDLE_GET_INDEX(hGdiObj);
/* Check if twe have the correct type */
if (GDI_HANDLE_GET_TYPE(hGdiObj) != ObjectType ||
((Entry->Type << GDI_ENTRY_UPPER_SHIFT) & GDI_HANDLE_TYPE_MASK) != ObjectType ||
(Entry->Type & GDI_ENTRY_BASETYPE_MASK) != (ObjectType & GDI_ENTRY_BASETYPE_MASK))
{
return FALSE;
}
/* Check if we are the owner */
if ((HANDLE)((ULONG_PTR)Entry->ProcessId & ~0x1) != CurrentProcessId)
{
return FALSE;
}
*UserData = Entry->UserData;
return TRUE;
}
PLDC
FASTCALL
GdiGetLDC(HDC hdc)
{
PDC_ATTR pdcattr;
/* Get the DC attribute */
pdcattr = GdiGetDcAttr(hdc);
if (pdcattr == NULL)
{
return NULL;
}
/* Return the LDC pointer */
return pdcattr->pvLDC;
}
BOOL
FASTCALL
GdiSetLDC(HDC hdc, PVOID pvLDC)
{
PDC_ATTR pdcattr;
/* Get the DC attribute */
pdcattr = GdiGetDcAttr(hdc);
if (pdcattr == NULL)
{
return FALSE;
}
/* Set the LDC pointer */
pdcattr->pvLDC = pvLDC;
return TRUE;
}
VOID GdiSAPCallback(PLDC pldc)
{
DWORD Time, NewTime = GetTickCount();
Time = NewTime - pldc->CallBackTick;
if ( Time < SAPCALLBACKDELAY) return;
pldc->CallBackTick = NewTime;
if ( !pldc->pAbortProc(pldc->hDC, 0) )
{
CancelDC(pldc->hDC);
AbortDoc(pldc->hDC);
}
}
/*
* @implemented
*/
DWORD
WINAPI
GdiSetBatchLimit(DWORD Limit)
{
DWORD OldLimit = GDI_BatchLimit;
if ( (!Limit) ||
(Limit >= GDI_BATCH_LIMIT))
{
return Limit;
}
GdiFlush();
GDI_BatchLimit = Limit;
return OldLimit;
}
/*
* @implemented
*/
DWORD
WINAPI
GdiGetBatchLimit(VOID)
{
return GDI_BatchLimit;
}
/*
* @implemented
*/
VOID
WINAPI
GdiSetLastError(DWORD dwErrCode)
{
NtCurrentTeb()->LastErrorValue = (ULONG) dwErrCode;
}
HGDIOBJ
FASTCALL
hGetPEBHandle(HANDLECACHETYPE Type, COLORREF cr)
{
int Number, Offset, MaxNum, GdiType;
HANDLE Lock;
HGDIOBJ Handle = NULL;
Lock = InterlockedCompareExchangePointer( (PVOID*)&GdiHandleCache->ulLock,
NtCurrentTeb(),
NULL );
if (Lock) return Handle;
Number = GdiHandleCache->ulNumHandles[Type];
if (Type == hctBrushHandle)
{
Offset = 0;
MaxNum = CACHE_BRUSH_ENTRIES;
GdiType = GDILoObjType_LO_BRUSH_TYPE;
}
else if (Type == hctPenHandle)
{
Offset = CACHE_BRUSH_ENTRIES;
MaxNum = CACHE_PEN_ENTRIES;
GdiType = GDILoObjType_LO_PEN_TYPE;
}
else if (Type == hctRegionHandle)
{
Offset = CACHE_BRUSH_ENTRIES+CACHE_PEN_ENTRIES;
MaxNum = CACHE_REGION_ENTRIES;
GdiType = GDILoObjType_LO_REGION_TYPE;
}
else // Font is not supported here.
{
return Handle;
}
if ( Number && Number <= MaxNum )
{
PBRUSH_ATTR pBrush_Attr;
HGDIOBJ *hPtr;
hPtr = GdiHandleCache->Handle + Offset;
Handle = hPtr[Number - 1];
if (GdiGetHandleUserData( Handle, GdiType, (PVOID) &pBrush_Attr))
{
if (pBrush_Attr->AttrFlags & ATTR_CACHED)
{
DPRINT("Get Handle! Type %d Count %lu PEB 0x%p\n", Type, GdiHandleCache->ulNumHandles[Type], NtCurrentTeb()->ProcessEnvironmentBlock);
pBrush_Attr->AttrFlags &= ~ATTR_CACHED;
hPtr[Number - 1] = NULL;
GdiHandleCache->ulNumHandles[Type]--;
if ( Type == hctBrushHandle ) // Handle only brush.
{
if ( pBrush_Attr->lbColor != cr )
{
pBrush_Attr->lbColor = cr ;
pBrush_Attr->AttrFlags |= ATTR_NEW_COLOR;
}
}
}
}
else
{
Handle = NULL;
}
}
(void)InterlockedExchangePointer((PVOID*)&GdiHandleCache->ulLock, Lock);
return Handle;
}
/*
* @unimplemented
*/
BOOL
WINAPI
bMakePathNameW(LPWSTR lpBuffer,LPCWSTR lpFileName,LPWSTR *lpFilePart,DWORD unknown)
{
UNIMPLEMENTED;
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return 0;
}
/*
* @implemented
* Synchronized with WINE dlls/gdi32/driver.c
*/
DEVMODEW *
WINAPI
GdiConvertToDevmodeW(const DEVMODEA *dmA)
{
DEVMODEW *dmW;
WORD dmW_size, dmA_size;
dmA_size = dmA->dmSize;
/* this is the minimal dmSize that XP accepts */
if (dmA_size < FIELD_OFFSET(DEVMODEA, dmFields))
return NULL;
if (dmA_size > sizeof(DEVMODEA))
dmA_size = sizeof(DEVMODEA);
dmW_size = dmA_size + CCHDEVICENAME;
if (dmA_size >= FIELD_OFFSET(DEVMODEA, dmFormName) + CCHFORMNAME)
dmW_size += CCHFORMNAME;
dmW = HeapAlloc(GetProcessHeap(), 0, dmW_size + dmA->dmDriverExtra);
if (!dmW) return NULL;
MultiByteToWideChar(CP_ACP, 0, (const char*) dmA->dmDeviceName, -1,
dmW->dmDeviceName, CCHDEVICENAME);
/* copy slightly more, to avoid long computations */
memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion, dmA_size - CCHDEVICENAME);
if (dmA_size >= FIELD_OFFSET(DEVMODEA, dmFormName) + CCHFORMNAME)
{
if (dmA->dmFields & DM_FORMNAME)
MultiByteToWideChar(CP_ACP, 0, (const char*) dmA->dmFormName, -1,
dmW->dmFormName, CCHFORMNAME);
else
dmW->dmFormName[0] = 0;
if (dmA_size > FIELD_OFFSET(DEVMODEA, dmLogPixels))
memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA_size - FIELD_OFFSET(DEVMODEA, dmLogPixels));
}
if (dmA->dmDriverExtra)
memcpy((char *)dmW + dmW_size, (const char *)dmA + dmA_size, dmA->dmDriverExtra);
dmW->dmSize = dmW_size;
return dmW;
}
/*
* @unimplemented
*/
BOOL
WINAPI
GdiRealizationInfo(HDC hdc,
PREALIZATION_INFO pri)
{
// ATM we do not support local font data and Language Pack.
return NtGdiGetRealizationInfo(hdc, pri, (HFONT) NULL);
}
/*
* @halfplemented
*/
VOID WINAPI GdiInitializeLanguagePack(DWORD InitParam)
{
/* Lpk function pointers to be passed to user32 */
#if 0
FARPROC hookfuncs[4];
#endif
#ifdef LANGPACK
if (!LoadLPK(LPK_INIT)) // no lpk found!
#endif
return;
/* Call InitializeLpkHooks with 4 procedure addresses
loaded from lpk.dll but currently only one of them is currently implemented.
Then InitializeLpkHooks (in user32) uses these to replace certain internal functions
and ORs a DWORD being used also by ClientThreadSetup and calls
NtUserOneParam with parameter 54 which is ONEPARAM_ROUTINE_REGISTERLPK
which most likely changes the value of dwLpkEntryPoints in the
PROCESSINFO struct */
#if 0
hookfuncs[0] = GetProcAddress(hLpk, "LpkPSMTextOut");
InitializeLpkHooks(hookfuncs);
#endif
gbLpk = TRUE;
}
BOOL
WINAPI
GdiAddGlsBounds(HDC hdc,LPRECT prc)
{
return NtGdiSetBoundsRect(hdc, prc, DCB_WINDOWMGR|DCB_ACCUMULATE ) ? TRUE : FALSE;
}
BOOL
WINAPI
GetBoundsRectAlt(HDC hdc,LPRECT prc,UINT flags)
{
return NtGdiGetBoundsRect(hdc, prc, flags);
}
BOOL
WINAPI
SetBoundsRectAlt(HDC hdc,LPRECT prc,UINT flags)
{
return NtGdiSetBoundsRect(hdc, prc, flags );
}
/*
* @unimplemented
*/
BOOL
WINAPI
GdiAddGlsRecord(HDC hdc,
DWORD unknown1,
LPCSTR unknown2,
LPRECT unknown3)
{
UNIMPLEMENTED;
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return 0;
}