gdi32: Store a pointer to the path in the DC and make the path structure opaque.

oldstable
Alexandre Julliard 2011-10-27 11:52:12 +02:00
parent ddc9860a42
commit a214a3c3da
3 changed files with 121 additions and 146 deletions

View File

@ -110,6 +110,7 @@ DC *alloc_dc_ptr( WORD magic )
dc->hDevice = 0; dc->hDevice = 0;
dc->hPalette = GetStockObject( DEFAULT_PALETTE ); dc->hPalette = GetStockObject( DEFAULT_PALETTE );
dc->gdiFont = 0; dc->gdiFont = 0;
dc->path = NULL;
dc->font_code_page = CP_ACP; dc->font_code_page = CP_ACP;
dc->ROPmode = R2_COPYPEN; dc->ROPmode = R2_COPYPEN;
dc->polyFillMode = ALTERNATE; dc->polyFillMode = ALTERNATE;
@ -146,7 +147,6 @@ DC *alloc_dc_ptr( WORD magic )
dc->BoundsRect.top = 0; dc->BoundsRect.top = 0;
dc->BoundsRect.right = 0; dc->BoundsRect.right = 0;
dc->BoundsRect.bottom = 0; dc->BoundsRect.bottom = 0;
PATH_InitGdiPath(&dc->path);
if (!(dc->hSelf = alloc_gdi_handle( &dc->header, magic, &dc_funcs ))) if (!(dc->hSelf = alloc_gdi_handle( &dc->header, magic, &dc_funcs )))
{ {
@ -174,7 +174,7 @@ static void free_dc_state( DC *dc )
if (dc->hMetaRgn) DeleteObject( dc->hMetaRgn ); if (dc->hMetaRgn) DeleteObject( dc->hMetaRgn );
if (dc->hMetaClipRgn) DeleteObject( dc->hMetaClipRgn ); if (dc->hMetaClipRgn) DeleteObject( dc->hMetaClipRgn );
if (dc->hVisRgn) DeleteObject( dc->hVisRgn ); if (dc->hVisRgn) DeleteObject( dc->hVisRgn );
PATH_DestroyGdiPath( &dc->path ); if (dc->path) free_gdi_path( dc->path );
HeapFree( GetProcessHeap(), 0, dc ); HeapFree( GetProcessHeap(), 0, dc );
} }

View File

@ -72,27 +72,6 @@ typedef struct tagGDIOBJHDR
struct hdc_list *hdcs; struct hdc_list *hdcs;
} GDIOBJHDR; } GDIOBJHDR;
/* It should not be necessary to access the contents of the GdiPath
* structure directly; if you find that the exported functions don't
* allow you to do what you want, then please place a new exported
* function that does this job in path.c.
*/
typedef enum tagGdiPathState
{
PATH_Null,
PATH_Open,
PATH_Closed
} GdiPathState;
typedef struct gdi_path
{
GdiPathState state;
POINT *pPoints;
BYTE *pFlags;
int numEntriesUsed, numEntriesAllocated;
BOOL newStroke;
} GdiPath;
typedef struct tagGdiFont GdiFont; typedef struct tagGdiFont GdiFont;
typedef struct tagDC typedef struct tagDC
@ -137,7 +116,7 @@ typedef struct tagDC
HPALETTE hPalette; HPALETTE hPalette;
GdiFont *gdiFont; GdiFont *gdiFont;
GdiPath path; struct gdi_path *path;
UINT font_code_page; UINT font_code_page;
WORD ROPmode; WORD ROPmode;
@ -320,8 +299,7 @@ extern METAHEADER *MF_CreateMetaHeaderDisk(METAHEADER *mr, LPCVOID filename, BOO
/* path.c */ /* path.c */
extern void PATH_InitGdiPath(GdiPath *pPath) DECLSPEC_HIDDEN; extern void free_gdi_path( struct gdi_path *path ) DECLSPEC_HIDDEN;
extern void PATH_DestroyGdiPath(GdiPath *pPath) DECLSPEC_HIDDEN;
extern BOOL PATH_SavePath( DC *dst, DC *src ) DECLSPEC_HIDDEN; extern BOOL PATH_SavePath( DC *dst, DC *src ) DECLSPEC_HIDDEN;
extern BOOL PATH_RestorePath( DC *dst, DC *src ) DECLSPEC_HIDDEN; extern BOOL PATH_RestorePath( DC *dst, DC *src ) DECLSPEC_HIDDEN;

View File

@ -81,11 +81,26 @@ typedef struct tagFLOAT_POINT
double x, y; double x, y;
} FLOAT_POINT; } FLOAT_POINT;
typedef enum
{
PATH_Null,
PATH_Open,
PATH_Closed
} GdiPathState;
typedef struct gdi_path
{
GdiPathState state;
POINT *pPoints;
BYTE *pFlags;
int numEntriesUsed, numEntriesAllocated;
BOOL newStroke;
} GdiPath;
struct path_physdev struct path_physdev
{ {
struct gdi_physdev dev; struct gdi_physdev dev;
GdiPath *path; struct gdi_path *path;
}; };
static inline struct path_physdev *get_path_physdev( PHYSDEV dev ) static inline struct path_physdev *get_path_physdev( PHYSDEV dev )
@ -100,7 +115,7 @@ static inline void pop_path_driver( DC *dc )
HeapFree( GetProcessHeap(), 0, dev ); HeapFree( GetProcessHeap(), 0, dev );
} }
static void free_gdi_path( struct gdi_path *path ) void free_gdi_path( struct gdi_path *path )
{ {
HeapFree( GetProcessHeap(), 0, path->pPoints ); HeapFree( GetProcessHeap(), 0, path->pPoints );
HeapFree( GetProcessHeap(), 0, path->pFlags ); HeapFree( GetProcessHeap(), 0, path->pFlags );
@ -131,6 +146,31 @@ static struct gdi_path *alloc_gdi_path(void)
return path; return path;
} }
static struct gdi_path *copy_gdi_path( const struct gdi_path *src_path )
{
struct gdi_path *path = HeapAlloc( GetProcessHeap(), 0, sizeof(*path) );
if (!path)
{
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
return NULL;
}
path->state = src_path->state;
path->numEntriesUsed = path->numEntriesAllocated = src_path->numEntriesUsed;
path->newStroke = src_path->newStroke;
path->pPoints = HeapAlloc( GetProcessHeap(), 0, path->numEntriesUsed * sizeof(*path->pPoints) );
path->pFlags = HeapAlloc( GetProcessHeap(), 0, path->numEntriesUsed * sizeof(*path->pFlags) );
if (!path->pPoints || !path->pFlags)
{
free_gdi_path( path );
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
return NULL;
}
memcpy( path->pPoints, src_path->pPoints, path->numEntriesUsed * sizeof(*path->pPoints) );
memcpy( path->pFlags, src_path->pFlags, path->numEntriesUsed * sizeof(*path->pFlags) );
return path;
}
/* Performs a world-to-viewport transformation on the specified point (which /* Performs a world-to-viewport transformation on the specified point (which
* is in floating point format). * is in floating point format).
*/ */
@ -156,16 +196,6 @@ static inline INT int_from_fixed(FIXED f)
} }
/* PATH_EmptyPath
*
* Removes all entries from the path and sets the path state to PATH_Null.
*/
static void PATH_EmptyPath(GdiPath *pPath)
{
pPath->state=PATH_Null;
pPath->numEntriesUsed=0;
}
/* PATH_ReserveEntries /* PATH_ReserveEntries
* *
* Ensures that at least "numEntries" entries (for points and flags) have * Ensures that at least "numEntries" entries (for points and flags) have
@ -262,35 +292,6 @@ static BOOL start_new_stroke( struct path_physdev *physdev )
return add_log_points( physdev, &pos, 1, PT_MOVETO ) != NULL; return add_log_points( physdev, &pos, 1, PT_MOVETO ) != NULL;
} }
/* PATH_AssignGdiPath
*
* Copies the GdiPath structure "pPathSrc" to "pPathDest". A deep copy is
* performed, i.e. the contents of the pPoints and pFlags arrays are copied,
* not just the pointers. Since this means that the arrays in pPathDest may
* need to be resized, pPathDest should have been initialized using
* PATH_InitGdiPath (in C++, this function would be an assignment operator,
* not a copy constructor).
* Returns TRUE if successful, else FALSE.
*/
static BOOL PATH_AssignGdiPath(GdiPath *pPathDest, const GdiPath *pPathSrc)
{
/* Make sure destination arrays are big enough */
if(!PATH_ReserveEntries(pPathDest, pPathSrc->numEntriesUsed))
return FALSE;
/* Perform the copy operation */
memcpy(pPathDest->pPoints, pPathSrc->pPoints,
sizeof(POINT)*pPathSrc->numEntriesUsed);
memcpy(pPathDest->pFlags, pPathSrc->pFlags,
sizeof(BYTE)*pPathSrc->numEntriesUsed);
pPathDest->state=pPathSrc->state;
pPathDest->numEntriesUsed=pPathSrc->numEntriesUsed;
pPathDest->newStroke=pPathSrc->newStroke;
return TRUE;
}
/* PATH_CheckCorners /* PATH_CheckCorners
* *
* Helper function for RoundRect() and Rectangle() * Helper function for RoundRect() and Rectangle()
@ -622,10 +623,10 @@ INT WINAPI GetPath(HDC hdc, LPPOINT pPoints, LPBYTE pTypes,
if(!dc) return -1; if(!dc) return -1;
pPath = &dc->path; pPath = dc->path;
/* Check that path is closed */ /* Check that path is closed */
if(pPath->state!=PATH_Closed) if(!pPath || pPath->state != PATH_Closed)
{ {
SetLastError(ERROR_CAN_NOT_COMPLETE); SetLastError(ERROR_CAN_NOT_COMPLETE);
goto done; goto done;
@ -669,22 +670,22 @@ INT WINAPI GetPath(HDC hdc, LPPOINT pPoints, LPBYTE pTypes,
*/ */
HRGN WINAPI PathToRegion(HDC hdc) HRGN WINAPI PathToRegion(HDC hdc)
{ {
GdiPath *pPath;
HRGN hrgnRval = 0; HRGN hrgnRval = 0;
DC *dc = get_dc_ptr( hdc ); DC *dc = get_dc_ptr( hdc );
/* Get pointer to path */ /* Get pointer to path */
if(!dc) return 0; if(!dc) return 0;
pPath = &dc->path;
/* Check that path is closed */ /* Check that path is closed */
if(pPath->state!=PATH_Closed) SetLastError(ERROR_CAN_NOT_COMPLETE); if (!dc->path || dc->path->state != PATH_Closed) SetLastError(ERROR_CAN_NOT_COMPLETE);
else else
{ {
/* FIXME: Should we empty the path even if conversion failed? */ if ((hrgnRval = PATH_PathToRegion(dc->path, GetPolyFillMode(hdc))))
hrgnRval = PATH_PathToRegion(pPath, GetPolyFillMode(hdc)); {
if (hrgnRval) PATH_EmptyPath(pPath); /* FIXME: Should we empty the path even if conversion failed? */
free_gdi_path( dc->path );
dc->path = NULL;
}
} }
release_dc_ptr( dc ); release_dc_ptr( dc );
return hrgnRval; return hrgnRval;
@ -813,7 +814,8 @@ static BOOL pathdrv_AbortPath( PHYSDEV dev )
DC *dc = get_dc_ptr( dev->hdc ); DC *dc = get_dc_ptr( dev->hdc );
if (!dc) return FALSE; if (!dc) return FALSE;
PATH_EmptyPath( &dc->path ); free_gdi_path( dc->path );
dc->path = NULL;
pop_path_driver( dc ); pop_path_driver( dc );
release_dc_ptr( dc ); release_dc_ptr( dc );
return TRUE; return TRUE;
@ -828,7 +830,7 @@ static BOOL pathdrv_EndPath( PHYSDEV dev )
DC *dc = get_dc_ptr( dev->hdc ); DC *dc = get_dc_ptr( dev->hdc );
if (!dc) return FALSE; if (!dc) return FALSE;
dc->path.state = PATH_Closed; dc->path->state = PATH_Closed;
pop_path_driver( dc ); pop_path_driver( dc );
release_dc_ptr( dc ); release_dc_ptr( dc );
return TRUE; return TRUE;
@ -846,7 +848,6 @@ static BOOL pathdrv_CreateDC( PHYSDEV *dev, LPCWSTR driver, LPCWSTR device,
if (!physdev) return FALSE; if (!physdev) return FALSE;
dc = get_dc_ptr( (*dev)->hdc ); dc = get_dc_ptr( (*dev)->hdc );
physdev->path = &dc->path;
push_dc_driver( dev, &physdev->dev, &path_driver ); push_dc_driver( dev, &physdev->dev, &path_driver );
release_dc_ptr( dc ); release_dc_ptr( dc );
return TRUE; return TRUE;
@ -863,56 +864,36 @@ static BOOL pathdrv_DeleteDC( PHYSDEV dev )
} }
/* PATH_InitGdiPath
*
* Initializes the GdiPath structure.
*/
void PATH_InitGdiPath(GdiPath *pPath)
{
assert(pPath!=NULL);
pPath->state=PATH_Null;
pPath->pPoints=NULL;
pPath->pFlags=NULL;
pPath->numEntriesUsed=0;
pPath->numEntriesAllocated=0;
}
/* PATH_DestroyGdiPath
*
* Destroys a GdiPath structure (frees the memory in the arrays).
*/
void PATH_DestroyGdiPath(GdiPath *pPath)
{
assert(pPath!=NULL);
HeapFree( GetProcessHeap(), 0, pPath->pPoints );
HeapFree( GetProcessHeap(), 0, pPath->pFlags );
}
BOOL PATH_SavePath( DC *dst, DC *src ) BOOL PATH_SavePath( DC *dst, DC *src )
{ {
PATH_InitGdiPath( &dst->path ); if (src->path)
return PATH_AssignGdiPath( &dst->path, &src->path ); {
if (!(dst->path = copy_gdi_path( src->path ))) return FALSE;
}
else dst->path = NULL;
return TRUE;
} }
BOOL PATH_RestorePath( DC *dst, DC *src ) BOOL PATH_RestorePath( DC *dst, DC *src )
{ {
BOOL ret; struct path_physdev *physdev;
if (src->path.state == PATH_Open && dst->path.state != PATH_Open) if (src->path && src->path->state == PATH_Open)
{ {
if (!path_driver.pCreateDC( &dst->physDev, NULL, NULL, NULL, NULL )) return FALSE; if (!dst->path || dst->path->state != PATH_Open)
ret = PATH_AssignGdiPath( &dst->path, &src->path ); {
if (!ret) pop_path_driver( dst ); if (!path_driver.pCreateDC( &dst->physDev, NULL, NULL, NULL, NULL )) return FALSE;
}
physdev = get_path_physdev( dst->physDev );
assert( physdev->dev.funcs == &path_driver );
physdev->path = src->path;
} }
else if (src->path.state != PATH_Open && dst->path.state == PATH_Open) else if (dst->path && dst->path->state == PATH_Open) pop_path_driver( dst );
{
ret = PATH_AssignGdiPath( &dst->path, &src->path ); if (dst->path) free_gdi_path( dst->path );
if (ret) pop_path_driver( dst ); dst->path = src->path;
} src->path = NULL;
else ret = PATH_AssignGdiPath( &dst->path, &src->path ); return TRUE;
return ret;
} }
@ -1797,7 +1778,7 @@ static struct gdi_path *PATH_WidenPath(DC *dc)
return NULL; return NULL;
} }
if (!(flat_path = PATH_FlattenPath( &dc->path ))) return NULL; if (!(flat_path = PATH_FlattenPath( dc->path ))) return NULL;
penWidthIn = penWidth / 2; penWidthIn = penWidth / 2;
penWidthOut = penWidth / 2; penWidthOut = penWidth / 2;
@ -2113,11 +2094,19 @@ BOOL WINAPI WidenPath(HDC hdc)
BOOL nulldrv_BeginPath( PHYSDEV dev ) BOOL nulldrv_BeginPath( PHYSDEV dev )
{ {
DC *dc = get_nulldrv_dc( dev ); DC *dc = get_nulldrv_dc( dev );
struct path_physdev *physdev;
struct gdi_path *path = alloc_gdi_path();
if (!path_driver.pCreateDC( &dc->physDev, NULL, NULL, NULL, NULL )) return FALSE; if (!path) return FALSE;
PATH_EmptyPath(&dc->path); if (!path_driver.pCreateDC( &dc->physDev, NULL, NULL, NULL, NULL ))
dc->path.newStroke = TRUE; {
dc->path.state = PATH_Open; free_gdi_path( path );
return FALSE;
}
physdev = get_path_physdev( dc->physDev );
physdev->path = path;
if (dc->path) free_gdi_path( dc->path );
dc->path = path;
return TRUE; return TRUE;
} }
@ -2131,7 +2120,8 @@ BOOL nulldrv_AbortPath( PHYSDEV dev )
{ {
DC *dc = get_nulldrv_dc( dev ); DC *dc = get_nulldrv_dc( dev );
PATH_EmptyPath( &dc->path ); if (dc->path) free_gdi_path( dc->path );
dc->path = NULL;
return TRUE; return TRUE;
} }
@ -2147,14 +2137,18 @@ BOOL nulldrv_SelectClipPath( PHYSDEV dev, INT mode )
HRGN hrgn; HRGN hrgn;
DC *dc = get_nulldrv_dc( dev ); DC *dc = get_nulldrv_dc( dev );
if (dc->path.state != PATH_Closed) if (!dc->path || dc->path->state != PATH_Closed)
{ {
SetLastError( ERROR_CAN_NOT_COMPLETE ); SetLastError( ERROR_CAN_NOT_COMPLETE );
return FALSE; return FALSE;
} }
if (!(hrgn = PATH_PathToRegion( &dc->path, GetPolyFillMode(dev->hdc)))) return FALSE; if (!(hrgn = PATH_PathToRegion( dc->path, GetPolyFillMode(dev->hdc)))) return FALSE;
ret = ExtSelectClipRgn( dev->hdc, hrgn, mode ) != ERROR; ret = ExtSelectClipRgn( dev->hdc, hrgn, mode ) != ERROR;
if (ret) PATH_EmptyPath( &dc->path ); if (ret)
{
free_gdi_path( dc->path );
dc->path = NULL;
}
/* FIXME: Should this function delete the path even if it failed? */ /* FIXME: Should this function delete the path even if it failed? */
DeleteObject( hrgn ); DeleteObject( hrgn );
return ret; return ret;
@ -2164,14 +2158,15 @@ BOOL nulldrv_FillPath( PHYSDEV dev )
{ {
DC *dc = get_nulldrv_dc( dev ); DC *dc = get_nulldrv_dc( dev );
if (dc->path.state != PATH_Closed) if (!dc->path || dc->path->state != PATH_Closed)
{ {
SetLastError( ERROR_CAN_NOT_COMPLETE ); SetLastError( ERROR_CAN_NOT_COMPLETE );
return FALSE; return FALSE;
} }
if (!PATH_FillPath( dev->hdc, &dc->path )) return FALSE; if (!PATH_FillPath( dev->hdc, dc->path )) return FALSE;
/* FIXME: Should the path be emptied even if conversion failed? */ /* FIXME: Should the path be emptied even if conversion failed? */
PATH_EmptyPath( &dc->path ); free_gdi_path( dc->path );
dc->path = NULL;
return TRUE; return TRUE;
} }
@ -2179,14 +2174,15 @@ BOOL nulldrv_StrokeAndFillPath( PHYSDEV dev )
{ {
DC *dc = get_nulldrv_dc( dev ); DC *dc = get_nulldrv_dc( dev );
if (dc->path.state != PATH_Closed) if (!dc->path || dc->path->state != PATH_Closed)
{ {
SetLastError( ERROR_CAN_NOT_COMPLETE ); SetLastError( ERROR_CAN_NOT_COMPLETE );
return FALSE; return FALSE;
} }
if (!PATH_FillPath( dev->hdc, &dc->path )) return FALSE; if (!PATH_FillPath( dev->hdc, dc->path )) return FALSE;
if (!PATH_StrokePath( dev->hdc, &dc->path )) return FALSE; if (!PATH_StrokePath( dev->hdc, dc->path )) return FALSE;
PATH_EmptyPath( &dc->path ); free_gdi_path( dc->path );
dc->path = NULL;
return TRUE; return TRUE;
} }
@ -2194,13 +2190,14 @@ BOOL nulldrv_StrokePath( PHYSDEV dev )
{ {
DC *dc = get_nulldrv_dc( dev ); DC *dc = get_nulldrv_dc( dev );
if (dc->path.state != PATH_Closed) if (!dc->path || dc->path->state != PATH_Closed)
{ {
SetLastError( ERROR_CAN_NOT_COMPLETE ); SetLastError( ERROR_CAN_NOT_COMPLETE );
return FALSE; return FALSE;
} }
if (!PATH_StrokePath( dev->hdc, &dc->path )) return FALSE; if (!PATH_StrokePath( dev->hdc, dc->path )) return FALSE;
PATH_EmptyPath( &dc->path ); free_gdi_path( dc->path );
dc->path = NULL;
return TRUE; return TRUE;
} }
@ -2209,14 +2206,14 @@ BOOL nulldrv_FlattenPath( PHYSDEV dev )
DC *dc = get_nulldrv_dc( dev ); DC *dc = get_nulldrv_dc( dev );
struct gdi_path *path; struct gdi_path *path;
if (dc->path.state != PATH_Closed) if (!dc->path || dc->path->state != PATH_Closed)
{ {
SetLastError( ERROR_CAN_NOT_COMPLETE ); SetLastError( ERROR_CAN_NOT_COMPLETE );
return FALSE; return FALSE;
} }
if (!(path = PATH_FlattenPath( &dc->path ))) return FALSE; if (!(path = PATH_FlattenPath( dc->path ))) return FALSE;
PATH_AssignGdiPath( &dc->path, path ); free_gdi_path( dc->path );
free_gdi_path( path ); dc->path = path;
return TRUE; return TRUE;
} }
@ -2225,14 +2222,14 @@ BOOL nulldrv_WidenPath( PHYSDEV dev )
DC *dc = get_nulldrv_dc( dev ); DC *dc = get_nulldrv_dc( dev );
struct gdi_path *path; struct gdi_path *path;
if (dc->path.state != PATH_Closed) if (!dc->path || dc->path->state != PATH_Closed)
{ {
SetLastError( ERROR_CAN_NOT_COMPLETE ); SetLastError( ERROR_CAN_NOT_COMPLETE );
return FALSE; return FALSE;
} }
if (!(path = PATH_WidenPath( dc ))) return FALSE; if (!(path = PATH_WidenPath( dc ))) return FALSE;
PATH_AssignGdiPath( &dc->path, path ); free_gdi_path( dc->path );
free_gdi_path( path ); dc->path = path;
return TRUE; return TRUE;
} }