/* * DC clipping 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 #include "windef.h" #include "wingdi.h" #include "wine/winuser16.h" #include "gdi.h" #include "region.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(clipping); /*********************************************************************** * CLIPPING_UpdateGCRegion * * Update the GC clip region when the ClipRgn or VisRgn have changed. */ void CLIPPING_UpdateGCRegion( DC * dc ) { if (!dc->hGCClipRgn) dc->hGCClipRgn = CreateRectRgn( 0, 0, 0, 0 ); if (!dc->hVisRgn) { ERR("hVisRgn is zero. Please report this.\n" ); exit(1); } if (dc->flags & DC_DIRTY) ERR( "DC is dirty. Please report this.\n" ); if (!dc->hClipRgn) CombineRgn( dc->hGCClipRgn, dc->hVisRgn, 0, RGN_COPY ); else CombineRgn(dc->hGCClipRgn, dc->hClipRgn, dc->hVisRgn, RGN_AND); if (dc->funcs->pSetDeviceClipping) dc->funcs->pSetDeviceClipping( dc ); } /*********************************************************************** * SelectClipRgn (GDI.44) */ INT16 WINAPI SelectClipRgn16( HDC16 hdc, HRGN16 hrgn ) { return (INT16)SelectClipRgn( hdc, hrgn ); } /*********************************************************************** * SelectClipRgn (GDI32.@) */ INT WINAPI SelectClipRgn( HDC hdc, HRGN hrgn ) { return ExtSelectClipRgn( hdc, hrgn, RGN_COPY ); } /****************************************************************************** * ExtSelectClipRgn [GDI.508] */ INT16 WINAPI ExtSelectClipRgn16( HDC16 hdc, HRGN16 hrgn, INT16 fnMode ) { return (INT16) ExtSelectClipRgn((HDC) hdc, (HRGN) hrgn, fnMode); } /****************************************************************************** * ExtSelectClipRgn [GDI32.@] */ INT WINAPI ExtSelectClipRgn( HDC hdc, HRGN hrgn, INT fnMode ) { INT retval; DC * dc = DC_GetDCUpdate( hdc ); if (!dc) return ERROR; TRACE("%04x %04x %d\n", hdc, hrgn, fnMode ); if (!hrgn) { if (fnMode == RGN_COPY) { if (dc->hClipRgn) DeleteObject( dc->hClipRgn ); dc->hClipRgn = 0; retval = SIMPLEREGION; /* Clip region == whole DC */ } else { FIXME("Unimplemented: hrgn NULL in mode: %d\n", fnMode); GDI_ReleaseObj( hdc ); return ERROR; } } else { if (!dc->hClipRgn) { RECT rect; GetRgnBox( dc->hVisRgn, &rect ); dc->hClipRgn = CreateRectRgnIndirect( &rect ); } OffsetRgn( dc->hClipRgn, -dc->DCOrgX, -dc->DCOrgY ); if(fnMode == RGN_COPY) retval = CombineRgn( dc->hClipRgn, hrgn, 0, fnMode ); else retval = CombineRgn( dc->hClipRgn, dc->hClipRgn, hrgn, fnMode); OffsetRgn( dc->hClipRgn, dc->DCOrgX, dc->DCOrgY ); } CLIPPING_UpdateGCRegion( dc ); GDI_ReleaseObj( hdc ); return retval; } /*********************************************************************** * SelectVisRgn (GDI.105) */ INT16 WINAPI SelectVisRgn16( HDC16 hdc, HRGN16 hrgn ) { int retval; DC * dc; if (!hrgn) return ERROR; if (!(dc = DC_GetDCPtr( hdc ))) return ERROR; TRACE("%04x %04x\n", hdc, hrgn ); dc->flags &= ~DC_DIRTY; retval = CombineRgn16( dc->hVisRgn, hrgn, 0, RGN_COPY ); CLIPPING_UpdateGCRegion( dc ); GDI_ReleaseObj( hdc ); return retval; } /*********************************************************************** * OffsetClipRgn (GDI.32) */ INT16 WINAPI OffsetClipRgn16( HDC16 hdc, INT16 x, INT16 y ) { return (INT16)OffsetClipRgn( hdc, x, y ); } /*********************************************************************** * OffsetClipRgn (GDI32.@) */ INT WINAPI OffsetClipRgn( HDC hdc, INT x, INT y ) { INT ret = SIMPLEREGION; DC *dc = DC_GetDCUpdate( hdc ); if (!dc) return ERROR; TRACE("%04x %d,%d\n", hdc, x, y ); if(dc->funcs->pOffsetClipRgn) ret = dc->funcs->pOffsetClipRgn( dc, x, y ); else if (dc->hClipRgn) { ret = OffsetRgn( dc->hClipRgn, XLSTODS(dc,x), YLSTODS(dc,y)); CLIPPING_UpdateGCRegion( dc ); } GDI_ReleaseObj( hdc ); return ret; } /*********************************************************************** * OffsetVisRgn (GDI.102) */ INT16 WINAPI OffsetVisRgn16( HDC16 hdc, INT16 x, INT16 y ) { INT16 retval; DC * dc = DC_GetDCUpdate( hdc ); if (!dc) return ERROR; TRACE("%04x %d,%d\n", hdc, x, y ); retval = OffsetRgn( dc->hVisRgn, x, y ); CLIPPING_UpdateGCRegion( dc ); GDI_ReleaseObj( hdc ); return retval; } /*********************************************************************** * CLIPPING_IntersectClipRect * * Helper function for {Intersect,Exclude}ClipRect, can be called from * elsewhere (like ExtTextOut()) to skip redundant metafile update and * coordinate conversion. */ INT CLIPPING_IntersectClipRect( DC * dc, INT left, INT top, INT right, INT bottom, UINT flags ) { HRGN newRgn; INT ret; left += dc->DCOrgX; right += dc->DCOrgX; top += dc->DCOrgY; bottom += dc->DCOrgY; if (!(newRgn = CreateRectRgn( left, top, right, bottom ))) return ERROR; if (!dc->hClipRgn) { if( flags & CLIP_INTERSECT ) { dc->hClipRgn = newRgn; CLIPPING_UpdateGCRegion( dc ); return SIMPLEREGION; } else if( flags & CLIP_EXCLUDE ) { dc->hClipRgn = CreateRectRgn( 0, 0, 0, 0 ); CombineRgn( dc->hClipRgn, dc->hVisRgn, 0, RGN_COPY ); } else WARN("No hClipRgn and flags are %x\n",flags); } ret = CombineRgn( newRgn, dc->hClipRgn, newRgn, (flags & CLIP_EXCLUDE) ? RGN_DIFF : RGN_AND ); if (ret != ERROR) { if (!(flags & CLIP_KEEPRGN)) DeleteObject( dc->hClipRgn ); dc->hClipRgn = newRgn; CLIPPING_UpdateGCRegion( dc ); } else DeleteObject( newRgn ); return ret; } /*********************************************************************** * ExcludeClipRect (GDI.21) */ INT16 WINAPI ExcludeClipRect16( HDC16 hdc, INT16 left, INT16 top, INT16 right, INT16 bottom ) { return (INT16)ExcludeClipRect( hdc, left, top, right, bottom ); } /*********************************************************************** * ExcludeClipRect (GDI32.@) */ INT WINAPI ExcludeClipRect( HDC hdc, INT left, INT top, INT right, INT bottom ) { INT ret; DC *dc = DC_GetDCUpdate( hdc ); if (!dc) return ERROR; TRACE("%04x %dx%d,%dx%d\n", hdc, left, top, right, bottom ); if(dc->funcs->pExcludeClipRect) ret = dc->funcs->pExcludeClipRect( dc, left, top, right, bottom ); else { left = XLPTODP( dc, left ); right = XLPTODP( dc, right ); top = YLPTODP( dc, top ); bottom = YLPTODP( dc, bottom ); ret = CLIPPING_IntersectClipRect( dc, left, top, right, bottom, CLIP_EXCLUDE ); } GDI_ReleaseObj( hdc ); return ret; } /*********************************************************************** * IntersectClipRect (GDI.22) */ INT16 WINAPI IntersectClipRect16( HDC16 hdc, INT16 left, INT16 top, INT16 right, INT16 bottom ) { return (INT16)IntersectClipRect( hdc, left, top, right, bottom ); } /*********************************************************************** * IntersectClipRect (GDI32.@) */ INT WINAPI IntersectClipRect( HDC hdc, INT left, INT top, INT right, INT bottom ) { INT ret; DC *dc = DC_GetDCUpdate( hdc ); if (!dc) return ERROR; TRACE("%04x %dx%d,%dx%d\n", hdc, left, top, right, bottom ); if(dc->funcs->pIntersectClipRect) ret = dc->funcs->pIntersectClipRect( dc, left, top, right, bottom ); else { left = XLPTODP( dc, left ); right = XLPTODP( dc, right ); top = YLPTODP( dc, top ); bottom = YLPTODP( dc, bottom ); ret = CLIPPING_IntersectClipRect( dc, left, top, right, bottom, CLIP_INTERSECT ); } GDI_ReleaseObj( hdc ); return ret; } /*********************************************************************** * CLIPPING_IntersectVisRect * * Helper function for {Intersect,Exclude}VisRect, can be called from * elsewhere (like ExtTextOut()) to skip redundant metafile update and * coordinate conversion. */ INT CLIPPING_IntersectVisRect( DC * dc, INT left, INT top, INT right, INT bottom, BOOL exclude ) { HRGN tempRgn, newRgn; INT ret; left += dc->DCOrgX; right += dc->DCOrgX; top += dc->DCOrgY; bottom += dc->DCOrgY; if (!(newRgn = CreateRectRgn( 0, 0, 0, 0 ))) return ERROR; if (!(tempRgn = CreateRectRgn( left, top, right, bottom ))) { DeleteObject( newRgn ); return ERROR; } ret = CombineRgn( newRgn, dc->hVisRgn, tempRgn, exclude ? RGN_DIFF : RGN_AND ); DeleteObject( tempRgn ); if (ret != ERROR) { RGNOBJ *newObj = (RGNOBJ*)GDI_GetObjPtr( newRgn, REGION_MAGIC); if (newObj) { RGNOBJ *prevObj = (RGNOBJ*)GDI_GetObjPtr( dc->hVisRgn, REGION_MAGIC); if (prevObj) { newObj->header.hNext = prevObj->header.hNext; GDI_ReleaseObj( dc->hVisRgn ); } GDI_ReleaseObj( newRgn ); } DeleteObject( dc->hVisRgn ); dc->hVisRgn = newRgn; CLIPPING_UpdateGCRegion( dc ); } else DeleteObject( newRgn ); return ret; } /*********************************************************************** * ExcludeVisRect (GDI.73) */ INT16 WINAPI ExcludeVisRect16( HDC16 hdc, INT16 left, INT16 top, INT16 right, INT16 bottom ) { INT16 ret; DC * dc = DC_GetDCUpdate( hdc ); if (!dc) return ERROR; left = XLPTODP( dc, left ); right = XLPTODP( dc, right ); top = YLPTODP( dc, top ); bottom = YLPTODP( dc, bottom ); TRACE("%04x %dx%d,%dx%d\n", hdc, left, top, right, bottom ); ret = CLIPPING_IntersectVisRect( dc, left, top, right, bottom, TRUE ); GDI_ReleaseObj( hdc ); return ret; } /*********************************************************************** * IntersectVisRect (GDI.98) */ INT16 WINAPI IntersectVisRect16( HDC16 hdc, INT16 left, INT16 top, INT16 right, INT16 bottom ) { INT16 ret; DC * dc = DC_GetDCUpdate( hdc ); if (!dc) return ERROR; left = XLPTODP( dc, left ); right = XLPTODP( dc, right ); top = YLPTODP( dc, top ); bottom = YLPTODP( dc, bottom ); TRACE("%04x %dx%d,%dx%d\n", hdc, left, top, right, bottom ); ret = CLIPPING_IntersectVisRect( dc, left, top, right, bottom, FALSE ); GDI_ReleaseObj( hdc ); return ret; } /*********************************************************************** * PtVisible (GDI.103) */ BOOL16 WINAPI PtVisible16( HDC16 hdc, INT16 x, INT16 y ) { return PtVisible( hdc, x, y ); } /*********************************************************************** * PtVisible (GDI32.@) */ BOOL WINAPI PtVisible( HDC hdc, INT x, INT y ) { BOOL ret = FALSE; DC *dc = DC_GetDCUpdate( hdc ); TRACE("%04x %d,%d\n", hdc, x, y ); if (!dc) return FALSE; if (dc->hGCClipRgn) { ret = PtInRegion( dc->hGCClipRgn, XLPTODP(dc,x) + dc->DCOrgX, YLPTODP(dc,y) + dc->DCOrgY ); } GDI_ReleaseObj( hdc ); return ret; } /*********************************************************************** * RectVisible (GDI.465) * RectVisibleOld (GDI.104) */ BOOL16 WINAPI RectVisible16( HDC16 hdc, const RECT16* rect16 ) { RECT rect; CONV_RECT16TO32( rect16, &rect ); return RectVisible( hdc, &rect ); } /*********************************************************************** * RectVisible (GDI32.@) */ BOOL WINAPI RectVisible( HDC hdc, const RECT* rect ) { BOOL ret = FALSE; RECT tmpRect; DC *dc = DC_GetDCUpdate( hdc ); if (!dc) return FALSE; TRACE("%04x %d,%dx%d,%d\n", hdc, rect->left, rect->top, rect->right, rect->bottom ); if (dc->hGCClipRgn) { /* copy rectangle to avoid overwriting by LPtoDP */ tmpRect = *rect; LPtoDP( hdc, (LPPOINT)&tmpRect, 2 ); tmpRect.left += dc->DCOrgX; tmpRect.right += dc->DCOrgX; tmpRect.top += dc->DCOrgY; tmpRect.bottom += dc->DCOrgY; ret = RectInRegion( dc->hGCClipRgn, &tmpRect ); } GDI_ReleaseObj( hdc ); return ret; } /*********************************************************************** * GetClipBox (GDI.77) */ INT16 WINAPI GetClipBox16( HDC16 hdc, LPRECT16 rect ) { int ret; DC *dc = DC_GetDCUpdate( hdc ); if (!dc) return ERROR; ret = GetRgnBox16( dc->hGCClipRgn, rect ); rect->left -= dc->DCOrgX; rect->right -= dc->DCOrgX; rect->top -= dc->DCOrgY; rect->bottom -= dc->DCOrgY; DPtoLP16( hdc, (LPPOINT16)rect, 2 ); TRACE("%d,%d-%d,%d\n", rect->left,rect->top,rect->right,rect->bottom ); GDI_ReleaseObj( hdc ); return ret; } /*********************************************************************** * GetClipBox (GDI32.@) */ INT WINAPI GetClipBox( HDC hdc, LPRECT rect ) { INT ret; DC *dc = DC_GetDCUpdate( hdc ); if (!dc) return ERROR; ret = GetRgnBox( dc->hGCClipRgn, rect ); rect->left -= dc->DCOrgX; rect->right -= dc->DCOrgX; rect->top -= dc->DCOrgY; rect->bottom -= dc->DCOrgY; DPtoLP( hdc, (LPPOINT)rect, 2 ); GDI_ReleaseObj( hdc ); return ret; } /*********************************************************************** * GetClipRgn (GDI32.@) */ INT WINAPI GetClipRgn( HDC hdc, HRGN hRgn ) { INT ret = -1; DC * dc; if (hRgn && (dc = DC_GetDCPtr( hdc ))) { if( dc->hClipRgn ) { /* this assumes that dc->hClipRgn is in coordinates relative to the device (not DC origin) */ if( CombineRgn(hRgn, dc->hClipRgn, 0, RGN_COPY) != ERROR ) { OffsetRgn( hRgn, -dc->DCOrgX, -dc->DCOrgY ); ret = 1; } } else ret = 0; GDI_ReleaseObj( hdc ); } return ret; } /*********************************************************************** * SaveVisRgn (GDI.129) */ HRGN16 WINAPI SaveVisRgn16( HDC16 hdc ) { HRGN copy; RGNOBJ *obj, *copyObj; DC *dc = DC_GetDCUpdate( hdc ); if (!dc) return 0; TRACE("%04x\n", hdc ); if (!(obj = (RGNOBJ *) GDI_GetObjPtr( dc->hVisRgn, REGION_MAGIC ))) { GDI_ReleaseObj( hdc ); return 0; } if (!(copy = CreateRectRgn( 0, 0, 0, 0 ))) { GDI_ReleaseObj( dc->hVisRgn ); GDI_ReleaseObj( hdc ); return 0; } CombineRgn( copy, dc->hVisRgn, 0, RGN_COPY ); if (!(copyObj = (RGNOBJ *) GDI_GetObjPtr( copy, REGION_MAGIC ))) { DeleteObject( copy ); GDI_ReleaseObj( dc->hVisRgn ); GDI_ReleaseObj( hdc ); return 0; } copyObj->header.hNext = obj->header.hNext; obj->header.hNext = copy; GDI_ReleaseObj( copy ); GDI_ReleaseObj( dc->hVisRgn ); GDI_ReleaseObj( hdc ); return copy; } /*********************************************************************** * RestoreVisRgn (GDI.130) */ INT16 WINAPI RestoreVisRgn16( HDC16 hdc ) { HRGN saved; RGNOBJ *obj, *savedObj; DC *dc = DC_GetDCPtr( hdc ); INT16 ret = ERROR; if (!dc) return ERROR; if (!dc->hVisRgn) goto done; TRACE("%04x\n", hdc ); if (!(obj = (RGNOBJ *) GDI_GetObjPtr( dc->hVisRgn, REGION_MAGIC ))) goto done; saved = obj->header.hNext; GDI_ReleaseObj( dc->hVisRgn ); if (!saved || !(savedObj = (RGNOBJ *) GDI_GetObjPtr( saved, REGION_MAGIC ))) goto done; DeleteObject( dc->hVisRgn ); dc->hVisRgn = saved; dc->flags &= ~DC_DIRTY; CLIPPING_UpdateGCRegion( dc ); ret = savedObj->rgn->type; /* FIXME */ GDI_ReleaseObj( saved ); done: GDI_ReleaseObj( hdc ); return ret; }