wine/objects/dc.c
Alexandre Julliard d8a9244fc4 Added function table to GDI objects for better encapsulation.
Removed some direct accesses to the bitmap structure.
Fixed handling of stock bitmap if selected in multiple DCs.
Some minor fixes to the DC function table.
2002-05-31 18:43:22 +00:00

1522 lines
43 KiB
C

/*
* GDI Device Context functions
*
* Copyright 1993 Alexandre Julliard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include <stdlib.h>
#include <string.h>
#include "gdi.h"
#include "heap.h"
#include "wine/debug.h"
#include "font.h"
#include "winerror.h"
#include "windef.h"
#include "wingdi.h"
#include "wine/winuser16.h"
WINE_DEFAULT_DEBUG_CHANNEL(dc);
/* ### start build ### */
extern WORD CALLBACK GDI_CallTo16_word_wwll(FARPROC16,WORD,WORD,LONG,LONG);
/* ### stop build ### */
static BOOL DC_DeleteObject( HGDIOBJ handle, void *obj );
static const struct gdi_obj_funcs dc_funcs =
{
NULL, /* pSelectObject */
NULL, /* pGetObject16 */
NULL, /* pGetObjectA */
NULL, /* pGetObjectW */
NULL, /* pUnrealizeObject */
DC_DeleteObject /* pDeleteObject */
};
/***********************************************************************
* DC_AllocDC
*/
DC *DC_AllocDC( const DC_FUNCTIONS *funcs )
{
HDC hdc;
DC *dc;
if (!(dc = GDI_AllocObject( sizeof(*dc), DC_MAGIC, &hdc, &dc_funcs ))) return NULL;
dc->hSelf = hdc;
dc->funcs = funcs;
dc->physDev = NULL;
dc->saveLevel = 0;
dc->dwHookData = 0;
dc->hookProc = NULL;
dc->hookThunk = NULL;
dc->wndOrgX = 0;
dc->wndOrgY = 0;
dc->wndExtX = 1;
dc->wndExtY = 1;
dc->vportOrgX = 0;
dc->vportOrgY = 0;
dc->vportExtX = 1;
dc->vportExtY = 1;
dc->flags = 0;
dc->hClipRgn = 0;
dc->hVisRgn = 0;
dc->hGCClipRgn = 0;
dc->hPen = GetStockObject( BLACK_PEN );
dc->hBrush = GetStockObject( WHITE_BRUSH );
dc->hFont = GetStockObject( SYSTEM_FONT );
dc->hBitmap = 0;
dc->hDevice = 0;
dc->hPalette = GetStockObject( DEFAULT_PALETTE );
dc->gdiFont = 0;
dc->ROPmode = R2_COPYPEN;
dc->polyFillMode = ALTERNATE;
dc->stretchBltMode = BLACKONWHITE;
dc->relAbsMode = ABSOLUTE;
dc->backgroundMode = OPAQUE;
dc->backgroundColor = RGB( 255, 255, 255 );
dc->textColor = RGB( 0, 0, 0 );
dc->brushOrgX = 0;
dc->brushOrgY = 0;
dc->textAlign = TA_LEFT | TA_TOP | TA_NOUPDATECP;
dc->charExtra = 0;
dc->breakTotalExtra = 0;
dc->breakCount = 0;
dc->breakExtra = 0;
dc->breakRem = 0;
dc->totalExtent.left = 0;
dc->totalExtent.top = 0;
dc->totalExtent.right = 0;
dc->totalExtent.bottom = 0;
dc->bitsPerPixel = 1;
dc->MapMode = MM_TEXT;
dc->GraphicsMode = GM_COMPATIBLE;
dc->DCOrgX = 0;
dc->DCOrgY = 0;
dc->pAbortProc = NULL;
dc->CursPosX = 0;
dc->CursPosY = 0;
dc->ArcDirection = AD_COUNTERCLOCKWISE;
dc->xformWorld2Wnd.eM11 = 1.0f;
dc->xformWorld2Wnd.eM12 = 0.0f;
dc->xformWorld2Wnd.eM21 = 0.0f;
dc->xformWorld2Wnd.eM22 = 1.0f;
dc->xformWorld2Wnd.eDx = 0.0f;
dc->xformWorld2Wnd.eDy = 0.0f;
dc->xformWorld2Vport = dc->xformWorld2Wnd;
dc->xformVport2World = dc->xformWorld2Wnd;
dc->vport2WorldValid = TRUE;
PATH_InitGdiPath(&dc->path);
return dc;
}
/***********************************************************************
* DC_GetDCPtr
*/
DC *DC_GetDCPtr( HDC hdc )
{
GDIOBJHDR *ptr = GDI_GetObjPtr( hdc, MAGIC_DONTCARE );
if (!ptr) return NULL;
if ((GDIMAGIC(ptr->wMagic) == DC_MAGIC) ||
(GDIMAGIC(ptr->wMagic) == METAFILE_DC_MAGIC) ||
(GDIMAGIC(ptr->wMagic) == ENHMETAFILE_DC_MAGIC))
return (DC *)ptr;
GDI_ReleaseObj( hdc );
SetLastError( ERROR_INVALID_HANDLE );
return NULL;
}
/***********************************************************************
* DC_GetDCUpdate
*
* Retrieve a DC ptr while making sure the visRgn is updated.
* This function may call up to USER so the GDI lock should _not_
* be held when calling it.
*/
DC *DC_GetDCUpdate( HDC hdc )
{
DC *dc = DC_GetDCPtr( hdc );
if (!dc) return NULL;
while (dc->flags & DC_DIRTY)
{
dc->flags &= ~DC_DIRTY;
if (!(dc->flags & (DC_SAVED | DC_MEMORY)))
{
DCHOOKPROC proc = dc->hookThunk;
if (proc)
{
DWORD data = dc->dwHookData;
GDI_ReleaseObj( hdc );
proc( hdc, DCHC_INVALIDVISRGN, data, 0 );
if (!(dc = DC_GetDCPtr( hdc ))) break;
/* otherwise restart the loop in case it became dirty again in the meantime */
}
}
}
return dc;
}
/***********************************************************************
* DC_DeleteObject
*/
static BOOL DC_DeleteObject( HGDIOBJ handle, void *obj )
{
GDI_ReleaseObj( handle );
return DeleteDC( handle );
}
/***********************************************************************
* DC_InitDC
*
* Setup device-specific DC values for a newly created DC.
*/
void DC_InitDC( DC* dc )
{
RealizeDefaultPalette16( dc->hSelf );
SetTextColor( dc->hSelf, dc->textColor );
SetBkColor( dc->hSelf, dc->backgroundColor );
SelectObject( dc->hSelf, dc->hPen );
SelectObject( dc->hSelf, dc->hBrush );
SelectObject( dc->hSelf, dc->hFont );
CLIPPING_UpdateGCRegion( dc );
}
/***********************************************************************
* DC_InvertXform
*
* Computes the inverse of the transformation xformSrc and stores it to
* xformDest. Returns TRUE if successful or FALSE if the xformSrc matrix
* is singular.
*/
static BOOL DC_InvertXform( const XFORM *xformSrc, XFORM *xformDest )
{
FLOAT determinant;
determinant = xformSrc->eM11*xformSrc->eM22 -
xformSrc->eM12*xformSrc->eM21;
if (determinant > -1e-12 && determinant < 1e-12)
return FALSE;
xformDest->eM11 = xformSrc->eM22 / determinant;
xformDest->eM12 = -xformSrc->eM12 / determinant;
xformDest->eM21 = -xformSrc->eM21 / determinant;
xformDest->eM22 = xformSrc->eM11 / determinant;
xformDest->eDx = -xformSrc->eDx * xformDest->eM11 -
xformSrc->eDy * xformDest->eM21;
xformDest->eDy = -xformSrc->eDx * xformDest->eM12 -
xformSrc->eDy * xformDest->eM22;
return TRUE;
}
/***********************************************************************
* DC_UpdateXforms
*
* Updates the xformWorld2Vport, xformVport2World and vport2WorldValid
* fields of the specified DC by creating a transformation that
* represents the current mapping mode and combining it with the DC's
* world transform. This function should be called whenever the
* parameters associated with the mapping mode (window and viewport
* extents and origins) or the world transform change.
*/
void DC_UpdateXforms( DC *dc )
{
XFORM xformWnd2Vport;
FLOAT scaleX, scaleY;
/* Construct a transformation to do the window-to-viewport conversion */
scaleX = (FLOAT)dc->vportExtX / (FLOAT)dc->wndExtX;
scaleY = (FLOAT)dc->vportExtY / (FLOAT)dc->wndExtY;
xformWnd2Vport.eM11 = scaleX;
xformWnd2Vport.eM12 = 0.0;
xformWnd2Vport.eM21 = 0.0;
xformWnd2Vport.eM22 = scaleY;
xformWnd2Vport.eDx = (FLOAT)dc->vportOrgX -
scaleX * (FLOAT)dc->wndOrgX;
xformWnd2Vport.eDy = (FLOAT)dc->vportOrgY -
scaleY * (FLOAT)dc->wndOrgY;
/* Combine with the world transformation */
CombineTransform( &dc->xformWorld2Vport, &dc->xformWorld2Wnd,
&xformWnd2Vport );
/* Create inverse of world-to-viewport transformation */
dc->vport2WorldValid = DC_InvertXform( &dc->xformWorld2Vport,
&dc->xformVport2World );
}
/***********************************************************************
* GetDCState (GDI.179)
*/
HDC16 WINAPI GetDCState16( HDC16 hdc )
{
DC * newdc, * dc;
HGDIOBJ handle;
if (!(dc = DC_GetDCPtr( hdc ))) return 0;
if (!(newdc = GDI_AllocObject( sizeof(DC), DC_MAGIC, &handle, &dc_funcs )))
{
GDI_ReleaseObj( hdc );
return 0;
}
TRACE("(%04x): returning %04x\n", hdc, handle );
newdc->flags = dc->flags | DC_SAVED;
newdc->hPen = dc->hPen;
newdc->hBrush = dc->hBrush;
newdc->hFont = dc->hFont;
newdc->hBitmap = dc->hBitmap;
newdc->hDevice = dc->hDevice;
newdc->hPalette = dc->hPalette;
newdc->totalExtent = dc->totalExtent;
newdc->bitsPerPixel = dc->bitsPerPixel;
newdc->ROPmode = dc->ROPmode;
newdc->polyFillMode = dc->polyFillMode;
newdc->stretchBltMode = dc->stretchBltMode;
newdc->relAbsMode = dc->relAbsMode;
newdc->backgroundMode = dc->backgroundMode;
newdc->backgroundColor = dc->backgroundColor;
newdc->textColor = dc->textColor;
newdc->brushOrgX = dc->brushOrgX;
newdc->brushOrgY = dc->brushOrgY;
newdc->textAlign = dc->textAlign;
newdc->charExtra = dc->charExtra;
newdc->breakTotalExtra = dc->breakTotalExtra;
newdc->breakCount = dc->breakCount;
newdc->breakExtra = dc->breakExtra;
newdc->breakRem = dc->breakRem;
newdc->MapMode = dc->MapMode;
newdc->GraphicsMode = dc->GraphicsMode;
#if 0
/* Apparently, the DC origin is not changed by [GS]etDCState */
newdc->DCOrgX = dc->DCOrgX;
newdc->DCOrgY = dc->DCOrgY;
#endif
newdc->CursPosX = dc->CursPosX;
newdc->CursPosY = dc->CursPosY;
newdc->ArcDirection = dc->ArcDirection;
newdc->xformWorld2Wnd = dc->xformWorld2Wnd;
newdc->xformWorld2Vport = dc->xformWorld2Vport;
newdc->xformVport2World = dc->xformVport2World;
newdc->vport2WorldValid = dc->vport2WorldValid;
newdc->wndOrgX = dc->wndOrgX;
newdc->wndOrgY = dc->wndOrgY;
newdc->wndExtX = dc->wndExtX;
newdc->wndExtY = dc->wndExtY;
newdc->vportOrgX = dc->vportOrgX;
newdc->vportOrgY = dc->vportOrgY;
newdc->vportExtX = dc->vportExtX;
newdc->vportExtY = dc->vportExtY;
newdc->hSelf = (HDC)handle;
newdc->saveLevel = 0;
PATH_InitGdiPath( &newdc->path );
newdc->pAbortProc = NULL;
newdc->hookThunk = NULL;
newdc->hookProc = 0;
/* Get/SetDCState() don't change hVisRgn field ("Undoc. Windows" p.559). */
newdc->hGCClipRgn = newdc->hVisRgn = 0;
if (dc->hClipRgn)
{
newdc->hClipRgn = CreateRectRgn( 0, 0, 0, 0 );
CombineRgn( newdc->hClipRgn, dc->hClipRgn, 0, RGN_COPY );
}
else
newdc->hClipRgn = 0;
if(dc->gdiFont) {
newdc->gdiFont = dc->gdiFont;
} else
newdc->gdiFont = 0;
GDI_ReleaseObj( handle );
GDI_ReleaseObj( hdc );
return handle;
}
/***********************************************************************
* SetDCState (GDI.180)
*/
void WINAPI SetDCState16( HDC16 hdc, HDC16 hdcs )
{
DC *dc, *dcs;
if (!(dc = DC_GetDCUpdate( hdc ))) return;
if (!(dcs = DC_GetDCPtr( hdcs )))
{
GDI_ReleaseObj( hdc );
return;
}
if (!dcs->flags & DC_SAVED)
{
GDI_ReleaseObj( hdc );
GDI_ReleaseObj( hdcs );
return;
}
TRACE("%04x %04x\n", hdc, hdcs );
dc->flags = dcs->flags & ~DC_SAVED;
dc->hDevice = dcs->hDevice;
dc->totalExtent = dcs->totalExtent;
dc->ROPmode = dcs->ROPmode;
dc->polyFillMode = dcs->polyFillMode;
dc->stretchBltMode = dcs->stretchBltMode;
dc->relAbsMode = dcs->relAbsMode;
dc->backgroundMode = dcs->backgroundMode;
dc->backgroundColor = dcs->backgroundColor;
dc->textColor = dcs->textColor;
dc->brushOrgX = dcs->brushOrgX;
dc->brushOrgY = dcs->brushOrgY;
dc->textAlign = dcs->textAlign;
dc->charExtra = dcs->charExtra;
dc->breakTotalExtra = dcs->breakTotalExtra;
dc->breakCount = dcs->breakCount;
dc->breakExtra = dcs->breakExtra;
dc->breakRem = dcs->breakRem;
dc->MapMode = dcs->MapMode;
dc->GraphicsMode = dcs->GraphicsMode;
#if 0
/* Apparently, the DC origin is not changed by [GS]etDCState */
dc->DCOrgX = dcs->DCOrgX;
dc->DCOrgY = dcs->DCOrgY;
#endif
dc->CursPosX = dcs->CursPosX;
dc->CursPosY = dcs->CursPosY;
dc->ArcDirection = dcs->ArcDirection;
dc->xformWorld2Wnd = dcs->xformWorld2Wnd;
dc->xformWorld2Vport = dcs->xformWorld2Vport;
dc->xformVport2World = dcs->xformVport2World;
dc->vport2WorldValid = dcs->vport2WorldValid;
dc->wndOrgX = dcs->wndOrgX;
dc->wndOrgY = dcs->wndOrgY;
dc->wndExtX = dcs->wndExtX;
dc->wndExtY = dcs->wndExtY;
dc->vportOrgX = dcs->vportOrgX;
dc->vportOrgY = dcs->vportOrgY;
dc->vportExtX = dcs->vportExtX;
dc->vportExtY = dcs->vportExtY;
if (!(dc->flags & DC_MEMORY)) dc->bitsPerPixel = dcs->bitsPerPixel;
if (dcs->hClipRgn)
{
if (!dc->hClipRgn) dc->hClipRgn = CreateRectRgn( 0, 0, 0, 0 );
CombineRgn( dc->hClipRgn, dcs->hClipRgn, 0, RGN_COPY );
}
else
{
if (dc->hClipRgn) DeleteObject( dc->hClipRgn );
dc->hClipRgn = 0;
}
CLIPPING_UpdateGCRegion( dc );
SelectObject( hdc, dcs->hBitmap );
SelectObject( hdc, dcs->hBrush );
SelectObject( hdc, dcs->hFont );
SelectObject( hdc, dcs->hPen );
SetBkColor( hdc, dcs->backgroundColor);
SetTextColor( hdc, dcs->textColor);
GDISelectPalette16( hdc, dcs->hPalette, FALSE );
GDI_ReleaseObj( hdcs );
GDI_ReleaseObj( hdc );
}
/***********************************************************************
* SaveDC (GDI.30)
*/
INT16 WINAPI SaveDC16( HDC16 hdc )
{
return (INT16)SaveDC( hdc );
}
/***********************************************************************
* SaveDC (GDI32.@)
*/
INT WINAPI SaveDC( HDC hdc )
{
HDC hdcs;
DC * dc, * dcs;
INT ret;
dc = DC_GetDCPtr( hdc );
if (!dc) return 0;
if(dc->funcs->pSaveDC)
{
ret = dc->funcs->pSaveDC( dc->physDev );
GDI_ReleaseObj( hdc );
return ret;
}
if (!(hdcs = GetDCState16( hdc )))
{
GDI_ReleaseObj( hdc );
return 0;
}
dcs = DC_GetDCPtr( hdcs );
/* Copy path. The reason why path saving / restoring is in SaveDC/
* RestoreDC and not in GetDCState/SetDCState is that the ...DCState
* functions are only in Win16 (which doesn't have paths) and that
* SetDCState doesn't allow us to signal an error (which can happen
* when copying paths).
*/
if (!PATH_AssignGdiPath( &dcs->path, &dc->path ))
{
GDI_ReleaseObj( hdc );
GDI_ReleaseObj( hdcs );
DeleteDC( hdcs );
return 0;
}
dcs->header.hNext = dc->header.hNext;
dc->header.hNext = hdcs;
TRACE("(%04x): returning %d\n", hdc, dc->saveLevel+1 );
ret = ++dc->saveLevel;
GDI_ReleaseObj( hdcs );
GDI_ReleaseObj( hdc );
return ret;
}
/***********************************************************************
* RestoreDC (GDI.39)
*/
BOOL16 WINAPI RestoreDC16( HDC16 hdc, INT16 level )
{
return RestoreDC( hdc, level );
}
/***********************************************************************
* RestoreDC (GDI32.@)
*/
BOOL WINAPI RestoreDC( HDC hdc, INT level )
{
DC * dc, * dcs;
BOOL success;
TRACE("%04x %d\n", hdc, level );
dc = DC_GetDCUpdate( hdc );
if(!dc) return FALSE;
if(dc->funcs->pRestoreDC)
{
success = dc->funcs->pRestoreDC( dc->physDev, level );
GDI_ReleaseObj( hdc );
return success;
}
if (level == -1) level = dc->saveLevel;
if ((level < 1)
/* This pair of checks disagrees with MSDN "Platform SDK:
Windows GDI" July 2000 which says all negative values
for level will be interpreted as an instance relative
to the current state. Restricting it to just -1 does
not satisfy this */
|| (level > dc->saveLevel))
{
GDI_ReleaseObj( hdc );
return FALSE;
}
success=TRUE;
while (dc->saveLevel >= level)
{
HDC16 hdcs = dc->header.hNext;
if (!(dcs = DC_GetDCPtr( hdcs )))
{
GDI_ReleaseObj( hdc );
return FALSE;
}
dc->header.hNext = dcs->header.hNext;
if (--dc->saveLevel < level)
{
SetDCState16( hdc, hdcs );
if (!PATH_AssignGdiPath( &dc->path, &dcs->path ))
/* FIXME: This might not be quite right, since we're
* returning FALSE but still destroying the saved DC state */
success=FALSE;
}
GDI_ReleaseObj( hdcs );
GDI_ReleaseObj( hdc );
DeleteDC( hdcs );
if (!(dc = DC_GetDCPtr( hdc ))) return FALSE;
}
GDI_ReleaseObj( hdc );
return success;
}
/***********************************************************************
* CreateDC (GDI.53)
*/
HDC16 WINAPI CreateDC16( LPCSTR driver, LPCSTR device, LPCSTR output,
const DEVMODEA *initData )
{
return CreateDCA( driver, device, output, initData );
}
/***********************************************************************
* CreateDCA (GDI32.@)
*/
HDC WINAPI CreateDCA( LPCSTR driver, LPCSTR device, LPCSTR output,
const DEVMODEA *initData )
{
HDC hdc;
DC * dc;
const DC_FUNCTIONS *funcs;
char buf[300];
GDI_CheckNotLock();
if (!device || !DRIVER_GetDriverName( device, buf, sizeof(buf) ))
strcpy(buf, driver);
if (!(funcs = DRIVER_load_driver( buf )))
{
ERR( "no driver found for %s\n", buf );
return 0;
}
if (!(dc = DC_AllocDC( funcs )))
{
DRIVER_release_driver( funcs );
return 0;
}
dc->flags = 0;
TRACE("(driver=%s, device=%s, output=%s): returning %04x\n",
debugstr_a(driver), debugstr_a(device), debugstr_a(output), dc->hSelf );
if (dc->funcs->pCreateDC &&
!dc->funcs->pCreateDC( dc, buf, device, output, initData ))
{
WARN("creation aborted by device\n" );
GDI_FreeObject( dc->hSelf, dc );
DRIVER_release_driver( funcs );
return 0;
}
dc->totalExtent.left = 0;
dc->totalExtent.top = 0;
dc->totalExtent.right = GetDeviceCaps( dc->hSelf, HORZRES );
dc->totalExtent.bottom = GetDeviceCaps( dc->hSelf, VERTRES );
dc->hVisRgn = CreateRectRgnIndirect( &dc->totalExtent );
DC_InitDC( dc );
hdc = dc->hSelf;
GDI_ReleaseObj( hdc );
return hdc;
}
/***********************************************************************
* CreateDCW (GDI32.@)
*/
HDC WINAPI CreateDCW( LPCWSTR driver, LPCWSTR device, LPCWSTR output,
const DEVMODEW *initData )
{
LPSTR driverA = HEAP_strdupWtoA( GetProcessHeap(), 0, driver );
LPSTR deviceA = HEAP_strdupWtoA( GetProcessHeap(), 0, device );
LPSTR outputA = HEAP_strdupWtoA( GetProcessHeap(), 0, output );
HDC res = CreateDCA( driverA, deviceA, outputA,
(const DEVMODEA *)initData /*FIXME*/ );
HeapFree( GetProcessHeap(), 0, driverA );
HeapFree( GetProcessHeap(), 0, deviceA );
HeapFree( GetProcessHeap(), 0, outputA );
return res;
}
/***********************************************************************
* CreateIC (GDI.153)
*/
HDC16 WINAPI CreateIC16( LPCSTR driver, LPCSTR device, LPCSTR output,
const DEVMODEA* initData )
{
/* Nothing special yet for ICs */
return CreateDC16( driver, device, output, initData );
}
/***********************************************************************
* CreateICA (GDI32.@)
*/
HDC WINAPI CreateICA( LPCSTR driver, LPCSTR device, LPCSTR output,
const DEVMODEA* initData )
{
/* Nothing special yet for ICs */
return CreateDCA( driver, device, output, initData );
}
/***********************************************************************
* CreateICW (GDI32.@)
*/
HDC WINAPI CreateICW( LPCWSTR driver, LPCWSTR device, LPCWSTR output,
const DEVMODEW* initData )
{
/* Nothing special yet for ICs */
return CreateDCW( driver, device, output, initData );
}
/***********************************************************************
* CreateCompatibleDC (GDI.52)
*/
HDC16 WINAPI CreateCompatibleDC16( HDC16 hdc )
{
return (HDC16)CreateCompatibleDC( hdc );
}
/***********************************************************************
* CreateCompatibleDC (GDI32.@)
*/
HDC WINAPI CreateCompatibleDC( HDC hdc )
{
DC *dc, *origDC;
const DC_FUNCTIONS *funcs;
GDI_CheckNotLock();
if ((origDC = GDI_GetObjPtr( hdc, DC_MAGIC )))
{
funcs = origDC->funcs;
GDI_ReleaseObj( hdc ); /* can't hold the lock while loading the driver */
funcs = DRIVER_get_driver( funcs );
}
else funcs = DRIVER_load_driver( "DISPLAY" );
if (!funcs) return 0;
if (!(dc = DC_AllocDC( funcs )))
{
DRIVER_release_driver( funcs );
return 0;
}
TRACE("(%04x): returning %04x\n",
hdc, dc->hSelf );
dc->flags = DC_MEMORY;
dc->bitsPerPixel = 1;
dc->hBitmap = GetStockObject( DEFAULT_BITMAP );
/* Copy the driver-specific physical device info into
* the new DC. The driver may use this read-only info
* while creating the compatible DC below. */
if ((origDC = GDI_GetObjPtr( hdc, DC_MAGIC ))) dc->physDev = origDC->physDev;
if (dc->funcs->pCreateDC &&
!dc->funcs->pCreateDC( dc, NULL, NULL, NULL, NULL ))
{
WARN("creation aborted by device\n");
GDI_FreeObject( dc->hSelf, dc );
if (origDC) GDI_ReleaseObj( hdc );
DRIVER_release_driver( funcs );
return 0;
}
dc->totalExtent.left = 0;
dc->totalExtent.top = 0;
dc->totalExtent.right = 1; /* default bitmap is 1x1 */
dc->totalExtent.bottom = 1;
dc->hVisRgn = CreateRectRgnIndirect( &dc->totalExtent );
DC_InitDC( dc );
GDI_ReleaseObj( dc->hSelf );
if (origDC) GDI_ReleaseObj( hdc );
return dc->hSelf;
}
/***********************************************************************
* DeleteDC (GDI.68)
*/
BOOL16 WINAPI DeleteDC16( HDC16 hdc )
{
return DeleteDC( hdc );
}
/***********************************************************************
* DeleteDC (GDI32.@)
*/
BOOL WINAPI DeleteDC( HDC hdc )
{
const DC_FUNCTIONS *funcs = NULL;
DC * dc;
TRACE("%04x\n", hdc );
GDI_CheckNotLock();
if (!(dc = GDI_GetObjPtr( hdc, DC_MAGIC ))) return FALSE;
/* Call hook procedure to check whether is it OK to delete this DC */
if (dc->hookThunk && !(dc->flags & (DC_SAVED | DC_MEMORY)))
{
DCHOOKPROC proc = dc->hookThunk;
if (proc)
{
DWORD data = dc->dwHookData;
GDI_ReleaseObj( hdc );
if (!proc( hdc, DCHC_DELETEDC, data, 0 )) return FALSE;
if (!(dc = DC_GetDCPtr( hdc ))) return TRUE; /* deleted by the hook */
}
}
while (dc->saveLevel)
{
DC * dcs;
HDC16 hdcs = dc->header.hNext;
if (!(dcs = DC_GetDCPtr( hdcs ))) break;
dc->header.hNext = dcs->header.hNext;
dc->saveLevel--;
if (dcs->hClipRgn) DeleteObject( dcs->hClipRgn );
if (dcs->hVisRgn) DeleteObject( dcs->hVisRgn );
if (dcs->hGCClipRgn) DeleteObject( dcs->hGCClipRgn );
PATH_DestroyGdiPath(&dcs->path);
GDI_FreeObject( hdcs, dcs );
}
if (!(dc->flags & DC_SAVED))
{
SelectObject( hdc, GetStockObject(BLACK_PEN) );
SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
SelectObject( hdc, GetStockObject(SYSTEM_FONT) );
SelectObject( hdc, GetStockObject(DEFAULT_BITMAP) );
funcs = dc->funcs;
if (dc->funcs->pDeleteDC) dc->funcs->pDeleteDC(dc->physDev);
}
if (dc->hClipRgn) DeleteObject( dc->hClipRgn );
if (dc->hVisRgn) DeleteObject( dc->hVisRgn );
if (dc->hGCClipRgn) DeleteObject( dc->hGCClipRgn );
PATH_DestroyGdiPath(&dc->path);
GDI_FreeObject( hdc, dc );
if (funcs) DRIVER_release_driver( funcs ); /* do that after releasing the GDI lock */
return TRUE;
}
/***********************************************************************
* ResetDC (GDI.376)
*/
HDC16 WINAPI ResetDC16( HDC16 hdc, const DEVMODEA *devmode )
{
return ResetDCA(hdc, devmode);
}
/***********************************************************************
* ResetDCA (GDI32.@)
*/
HDC WINAPI ResetDCA( HDC hdc, const DEVMODEA *devmode )
{
DC *dc;
HDC ret = hdc;
if ((dc = DC_GetDCPtr( hdc )))
{
if (dc->funcs->pResetDC) ret = dc->funcs->pResetDC( dc->physDev, devmode );
GDI_ReleaseObj( hdc );
}
return ret;
}
/***********************************************************************
* ResetDCW (GDI32.@)
*/
HDC WINAPI ResetDCW( HDC hdc, const DEVMODEW *devmode )
{
return ResetDCA(hdc, (const DEVMODEA*)devmode); /* FIXME */
}
/***********************************************************************
* GetDeviceCaps (GDI.80)
*/
INT16 WINAPI GetDeviceCaps16( HDC16 hdc, INT16 cap )
{
INT16 ret = GetDeviceCaps( hdc, cap );
/* some apps don't expect -1 and think it's a B&W screen */
if ((cap == NUMCOLORS) && (ret == -1)) ret = 2048;
return ret;
}
/***********************************************************************
* GetDeviceCaps (GDI32.@)
*/
INT WINAPI GetDeviceCaps( HDC hdc, INT cap )
{
DC *dc;
INT ret = 0;
if ((dc = DC_GetDCPtr( hdc )))
{
if (dc->funcs->pGetDeviceCaps) ret = dc->funcs->pGetDeviceCaps( dc->physDev, cap );
GDI_ReleaseObj( hdc );
}
return ret;
}
/***********************************************************************
* SetBkColor (GDI.1)
*/
COLORREF WINAPI SetBkColor16( HDC16 hdc, COLORREF color )
{
return SetBkColor( hdc, color );
}
/***********************************************************************
* SetBkColor (GDI32.@)
*/
COLORREF WINAPI SetBkColor( HDC hdc, COLORREF color )
{
COLORREF oldColor;
DC * dc = DC_GetDCPtr( hdc );
if (!dc) return CLR_INVALID;
oldColor = dc->backgroundColor;
if (dc->funcs->pSetBkColor)
{
color = dc->funcs->pSetBkColor(dc->physDev, color);
if (color == CLR_INVALID) /* don't change it */
{
color = oldColor;
oldColor = CLR_INVALID;
}
}
dc->backgroundColor = color;
GDI_ReleaseObj( hdc );
return oldColor;
}
/***********************************************************************
* SetTextColor (GDI.9)
*/
COLORREF WINAPI SetTextColor16( HDC16 hdc, COLORREF color )
{
return SetTextColor( hdc, color );
}
/***********************************************************************
* SetTextColor (GDI32.@)
*/
COLORREF WINAPI SetTextColor( HDC hdc, COLORREF color )
{
COLORREF oldColor;
DC * dc = DC_GetDCPtr( hdc );
if (!dc) return CLR_INVALID;
oldColor = dc->textColor;
if (dc->funcs->pSetTextColor)
{
color = dc->funcs->pSetTextColor(dc->physDev, color);
if (color == CLR_INVALID) /* don't change it */
{
color = oldColor;
oldColor = CLR_INVALID;
}
}
dc->textColor = color;
GDI_ReleaseObj( hdc );
return oldColor;
}
/***********************************************************************
* SetTextAlign (GDI.346)
*/
UINT16 WINAPI SetTextAlign16( HDC16 hdc, UINT16 align )
{
return SetTextAlign( hdc, align );
}
/***********************************************************************
* SetTextAlign (GDI32.@)
*/
UINT WINAPI SetTextAlign( HDC hdc, UINT align )
{
UINT prevAlign;
DC *dc = DC_GetDCPtr( hdc );
if (!dc) return 0x0;
if (dc->funcs->pSetTextAlign)
prevAlign = dc->funcs->pSetTextAlign(dc->physDev, align);
else {
prevAlign = dc->textAlign;
dc->textAlign = align;
}
GDI_ReleaseObj( hdc );
return prevAlign;
}
/***********************************************************************
* GetDCOrgEx (GDI32.@)
*/
BOOL WINAPI GetDCOrgEx( HDC hDC, LPPOINT lpp )
{
DC * dc;
if (!lpp) return FALSE;
if (!(dc = DC_GetDCPtr( hDC ))) return FALSE;
lpp->x = lpp->y = 0;
if (dc->funcs->pGetDCOrgEx) dc->funcs->pGetDCOrgEx( dc->physDev, lpp );
lpp->x += dc->DCOrgX;
lpp->y += dc->DCOrgY;
GDI_ReleaseObj( hDC );
return TRUE;
}
/***********************************************************************
* GetDCOrg (GDI.79)
*/
DWORD WINAPI GetDCOrg16( HDC16 hdc )
{
POINT pt;
if( GetDCOrgEx( hdc, &pt) )
return MAKELONG( (WORD)pt.x, (WORD)pt.y );
return 0;
}
/***********************************************************************
* SetDCOrg (GDI.117)
*/
DWORD WINAPI SetDCOrg16( HDC16 hdc, INT16 x, INT16 y )
{
DWORD prevOrg;
DC *dc = DC_GetDCPtr( hdc );
if (!dc) return 0;
prevOrg = dc->DCOrgX | (dc->DCOrgY << 16);
dc->DCOrgX = x;
dc->DCOrgY = y;
GDI_ReleaseObj( hdc );
return prevOrg;
}
/***********************************************************************
* SetGraphicsMode (GDI32.@)
*/
INT WINAPI SetGraphicsMode( HDC hdc, INT mode )
{
INT ret = 0;
DC *dc = DC_GetDCPtr( hdc );
/* One would think that setting the graphics mode to GM_COMPATIBLE
* would also reset the world transformation matrix to the unity
* matrix. However, in Windows, this is not the case. This doesn't
* make a lot of sense to me, but that's the way it is.
*/
if (!dc) return 0;
if ((mode > 0) || (mode <= GM_LAST))
{
ret = dc->GraphicsMode;
dc->GraphicsMode = mode;
}
GDI_ReleaseObj( hdc );
return ret;
}
/***********************************************************************
* SetArcDirection (GDI.525)
*/
INT16 WINAPI SetArcDirection16( HDC16 hdc, INT16 nDirection )
{
return SetArcDirection( (HDC)hdc, (INT)nDirection );
}
/***********************************************************************
* SetArcDirection (GDI32.@)
*/
INT WINAPI SetArcDirection( HDC hdc, INT nDirection )
{
DC * dc;
INT nOldDirection = 0;
if (nDirection!=AD_COUNTERCLOCKWISE && nDirection!=AD_CLOCKWISE)
{
SetLastError(ERROR_INVALID_PARAMETER);
return 0;
}
if ((dc = DC_GetDCPtr( hdc )))
{
nOldDirection = dc->ArcDirection;
dc->ArcDirection = nDirection;
GDI_ReleaseObj( hdc );
}
return nOldDirection;
}
/***********************************************************************
* GetWorldTransform (GDI32.@)
*/
BOOL WINAPI GetWorldTransform( HDC hdc, LPXFORM xform )
{
DC * dc;
if (!xform) return FALSE;
if (!(dc = DC_GetDCPtr( hdc ))) return FALSE;
*xform = dc->xformWorld2Wnd;
GDI_ReleaseObj( hdc );
return TRUE;
}
/***********************************************************************
* SetWorldTransform (GDI32.@)
*/
BOOL WINAPI SetWorldTransform( HDC hdc, const XFORM *xform )
{
BOOL ret = FALSE;
DC *dc = DC_GetDCPtr( hdc );
if (!dc) return FALSE;
if (!xform) goto done;
/* Check that graphics mode is GM_ADVANCED */
if (dc->GraphicsMode!=GM_ADVANCED) goto done;
dc->xformWorld2Wnd = *xform;
DC_UpdateXforms( dc );
ret = TRUE;
done:
GDI_ReleaseObj( hdc );
return ret;
}
/****************************************************************************
* ModifyWorldTransform [GDI32.@]
* Modifies the world transformation for a device context.
*
* PARAMS
* hdc [I] Handle to device context
* xform [I] XFORM structure that will be used to modify the world
* transformation
* iMode [I] Specifies in what way to modify the world transformation
* Possible values:
* MWT_IDENTITY
* Resets the world transformation to the identity matrix.
* The parameter xform is ignored.
* MWT_LEFTMULTIPLY
* Multiplies xform into the world transformation matrix from
* the left.
* MWT_RIGHTMULTIPLY
* Multiplies xform into the world transformation matrix from
* the right.
*
* RETURNS STD
*/
BOOL WINAPI ModifyWorldTransform( HDC hdc, const XFORM *xform,
DWORD iMode )
{
BOOL ret = FALSE;
DC *dc = DC_GetDCPtr( hdc );
/* Check for illegal parameters */
if (!dc) return FALSE;
if (!xform) goto done;
/* Check that graphics mode is GM_ADVANCED */
if (dc->GraphicsMode!=GM_ADVANCED) goto done;
switch (iMode)
{
case MWT_IDENTITY:
dc->xformWorld2Wnd.eM11 = 1.0f;
dc->xformWorld2Wnd.eM12 = 0.0f;
dc->xformWorld2Wnd.eM21 = 0.0f;
dc->xformWorld2Wnd.eM22 = 1.0f;
dc->xformWorld2Wnd.eDx = 0.0f;
dc->xformWorld2Wnd.eDy = 0.0f;
break;
case MWT_LEFTMULTIPLY:
CombineTransform( &dc->xformWorld2Wnd, xform,
&dc->xformWorld2Wnd );
break;
case MWT_RIGHTMULTIPLY:
CombineTransform( &dc->xformWorld2Wnd, &dc->xformWorld2Wnd,
xform );
break;
default:
goto done;
}
DC_UpdateXforms( dc );
ret = TRUE;
done:
GDI_ReleaseObj( hdc );
return ret;
}
/****************************************************************************
* CombineTransform [GDI32.@]
* Combines two transformation matrices.
*
* PARAMS
* xformResult [O] Stores the result of combining the two matrices
* xform1 [I] Specifies the first matrix to apply
* xform2 [I] Specifies the second matrix to apply
*
* REMARKS
* The same matrix can be passed in for more than one of the parameters.
*
* RETURNS STD
*/
BOOL WINAPI CombineTransform( LPXFORM xformResult, const XFORM *xform1,
const XFORM *xform2 )
{
XFORM xformTemp;
/* Check for illegal parameters */
if (!xformResult || !xform1 || !xform2)
return FALSE;
/* Create the result in a temporary XFORM, since xformResult may be
* equal to xform1 or xform2 */
xformTemp.eM11 = xform1->eM11 * xform2->eM11 +
xform1->eM12 * xform2->eM21;
xformTemp.eM12 = xform1->eM11 * xform2->eM12 +
xform1->eM12 * xform2->eM22;
xformTemp.eM21 = xform1->eM21 * xform2->eM11 +
xform1->eM22 * xform2->eM21;
xformTemp.eM22 = xform1->eM21 * xform2->eM12 +
xform1->eM22 * xform2->eM22;
xformTemp.eDx = xform1->eDx * xform2->eM11 +
xform1->eDy * xform2->eM21 +
xform2->eDx;
xformTemp.eDy = xform1->eDx * xform2->eM12 +
xform1->eDy * xform2->eM22 +
xform2->eDy;
/* Copy the result to xformResult */
*xformResult = xformTemp;
return TRUE;
}
/***********************************************************************
* SetDCHook (GDI32.@)
*
* Note: this doesn't exist in Win32, we add it here because user32 needs it.
*/
BOOL WINAPI SetDCHook( HDC hdc, DCHOOKPROC hookProc, DWORD dwHookData )
{
DC *dc = DC_GetDCPtr( hdc );
if (!dc) return FALSE;
dc->dwHookData = dwHookData;
dc->hookThunk = hookProc;
GDI_ReleaseObj( hdc );
return TRUE;
}
/* relay function to call the 16-bit DC hook proc */
static BOOL16 WINAPI call_dc_hook16( HDC16 hdc, WORD code, DWORD data, LPARAM lParam )
{
FARPROC16 proc = NULL;
DC *dc = DC_GetDCPtr( hdc );
if (!dc) return FALSE;
proc = dc->hookProc;
GDI_ReleaseObj( hdc );
if (!proc) return FALSE;
return GDI_CallTo16_word_wwll( proc, hdc, code, data, lParam );
}
/***********************************************************************
* SetDCHook (GDI.190)
*/
BOOL16 WINAPI SetDCHook16( HDC16 hdc, FARPROC16 hookProc, DWORD dwHookData )
{
DC *dc = DC_GetDCPtr( hdc );
if (!dc) return FALSE;
dc->hookProc = hookProc;
GDI_ReleaseObj( hdc );
return SetDCHook( hdc, call_dc_hook16, dwHookData );
}
/***********************************************************************
* GetDCHook (GDI.191)
*/
DWORD WINAPI GetDCHook( HDC16 hdc, FARPROC16 *phookProc )
{
DC *dc = DC_GetDCPtr( hdc );
if (!dc) return 0;
*phookProc = dc->hookProc;
GDI_ReleaseObj( hdc );
return dc->dwHookData;
}
/***********************************************************************
* SetHookFlags (GDI.192)
*/
WORD WINAPI SetHookFlags16(HDC16 hDC, WORD flags)
{
DC *dc = DC_GetDCPtr( hDC );
if( dc )
{
WORD wRet = dc->flags & DC_DIRTY;
/* "Undocumented Windows" info is slightly confusing.
*/
TRACE("hDC %04x, flags %04x\n",hDC,flags);
if( flags & DCHF_INVALIDATEVISRGN )
dc->flags |= DC_DIRTY;
else if( flags & DCHF_VALIDATEVISRGN || !flags )
dc->flags &= ~DC_DIRTY;
GDI_ReleaseObj( hDC );
return wRet;
}
return 0;
}
/***********************************************************************
* SetICMMode (GDI32.@)
*/
INT WINAPI SetICMMode(HDC hdc, INT iEnableICM)
{
/*FIXME Asuming that ICM is always off, and cannot be turned on */
if (iEnableICM == ICM_OFF) return ICM_OFF;
if (iEnableICM == ICM_ON) return 0;
if (iEnableICM == ICM_QUERY) return ICM_OFF;
return 0;
}
/***********************************************************************
* GetDeviceGammaRamp (GDI32.@)
*/
BOOL WINAPI GetDeviceGammaRamp(HDC hDC, LPVOID ptr)
{
BOOL ret = FALSE;
DC *dc = DC_GetDCPtr( hDC );
if( dc )
{
if (dc->funcs->pGetDeviceGammaRamp)
ret = dc->funcs->pGetDeviceGammaRamp(dc->physDev, ptr);
GDI_ReleaseObj( hDC );
}
return ret;
}
/***********************************************************************
* SetDeviceGammaRamp (GDI32.@)
*/
BOOL WINAPI SetDeviceGammaRamp(HDC hDC, LPVOID ptr)
{
BOOL ret = FALSE;
DC *dc = DC_GetDCPtr( hDC );
if( dc )
{
if (dc->funcs->pSetDeviceGammaRamp)
ret = dc->funcs->pSetDeviceGammaRamp(dc->physDev, ptr);
GDI_ReleaseObj( hDC );
}
return ret;
}
/***********************************************************************
* GetColorSpace (GDI32.@)
*/
HCOLORSPACE WINAPI GetColorSpace(HDC hdc)
{
/*FIXME Need to to whatever GetColorSpace actually does */
return 0;
}
/***********************************************************************
* CreateColorSpaceA (GDI32.@)
*/
HCOLORSPACE WINAPI CreateColorSpaceA( LPLOGCOLORSPACEA lpLogColorSpace )
{
FIXME( "stub\n" );
return 0;
}
/***********************************************************************
* CreateColorSpaceW (GDI32.@)
*/
HCOLORSPACE WINAPI CreateColorSpaceW( LPLOGCOLORSPACEW lpLogColorSpace )
{
FIXME( "stub\n" );
return 0;
}
/***********************************************************************
* DeleteColorSpace (GDI32.@)
*/
BOOL WINAPI DeleteColorSpace( HCOLORSPACE hColorSpace )
{
FIXME( "stub\n" );
return TRUE;
}
/***********************************************************************
* SetColorSpace (GDI32.@)
*/
HCOLORSPACE WINAPI SetColorSpace( HDC hDC, HCOLORSPACE hColorSpace )
{
FIXME( "stub\n" );
return hColorSpace;
}
/***********************************************************************
* GetBoundsRect (GDI.194)
*/
UINT16 WINAPI GetBoundsRect16(HDC16 hdc, LPRECT16 rect, UINT16 flags)
{
return DCB_RESET | DCB_DISABLE; /* bounding rectangle always empty and disabled*/
}
/***********************************************************************
* GetBoundsRect (GDI32.@)
*/
UINT WINAPI GetBoundsRect(HDC hdc, LPRECT rect, UINT flags)
{
FIXME("(): stub\n");
return DCB_RESET; /* bounding rectangle always empty */
}
/***********************************************************************
* SetBoundsRect (GDI.193)
*/
UINT16 WINAPI SetBoundsRect16(HDC16 hdc, const RECT16* rect, UINT16 flags)
{
if ( (flags & DCB_ACCUMULATE) || (flags & DCB_ENABLE) )
FIXME("(%04x, %p, %04x): stub\n", hdc, rect, flags );
return DCB_RESET | DCB_DISABLE; /* bounding rectangle always empty and disabled*/
}
/***********************************************************************
* SetBoundsRect (GDI32.@)
*/
UINT WINAPI SetBoundsRect(HDC hdc, const RECT* rect, UINT flags)
{
FIXME("(): stub\n");
return DCB_DISABLE; /* bounding rectangle always empty */
}
/***********************************************************************
* GetRelAbs (GDI32.@)
*/
INT WINAPI GetRelAbs( HDC hdc, DWORD dwIgnore )
{
INT ret = 0;
DC *dc = DC_GetDCPtr( hdc );
if (dc) ret = dc->relAbsMode;
GDI_ReleaseObj( hdc );
return ret;
}
/***********************************************************************
* Death (GDI.121)
*
* Disables GDI, switches back to text mode.
* We don't have to do anything here,
* just let console support handle everything
*/
void WINAPI Death16(HDC16 hDC)
{
MESSAGE("Death(%04x) called. Application enters text mode...\n", hDC);
}
/***********************************************************************
* Resurrection (GDI.122)
*
* Restores GDI functionality
*/
void WINAPI Resurrection16(HDC16 hDC,
WORD w1, WORD w2, WORD w3, WORD w4, WORD w5, WORD w6)
{
MESSAGE("Resurrection(%04x, %04x, %04x, %04x, %04x, %04x, %04x) called. Application left text mode.\n", hDC, w1, w2, w3, w4, w5, w6);
}
/***********************************************************************
* GetLayout (GDI32.@)
*
* Gets left->right or right->left text layout flags of a dc.
* win98 just returns 0 and sets ERROR_CALL_NOT_IMPLEMENTED so we do the same
*
*/
DWORD WINAPI GetLayout(HDC hdc)
{
FIXME("(%08x): stub\n", hdc);
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return 0;
}
/***********************************************************************
* SetLayout (GDI32.@)
*
* Sets left->right or right->left text layout flags of a dc.
* win98 just returns 0 and sets ERROR_CALL_NOT_IMPLEMENTED so we do the same
*
*/
DWORD WINAPI SetLayout(HDC hdc, DWORD layout)
{
FIXME("(%08x,%08lx): stub\n", hdc, layout);
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return 0;
}