Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

303 lines
9.4 KiB

/**************************************************************************\
*
* Copyright (c) 1998 Microsoft Corporation
*
* Module Name:
*
*
*
* Abstract:
*
*
*
* Notes:
*
*
*
* Created:
*
* //1999 agodfrey
*
\**************************************************************************/
#include "precomp.hpp"
DpDriver::DpDriver()
{
Internal = new DpDriverInternal;
Device = NULL;
}
DpDriver::~DpDriver()
{
delete Internal;
SetValid(FALSE); // so we don't use a deleted object
}
// If we let the clipping region height get too large, then GDI will allocate
// tons of memory when we select the clip path in.
#define GDI_MAX_REGION_HEIGHT_FOR_GDI 65536
// Returns TRUE if we succeed in setting the clipping using
// path clipping.
static BOOL
SetupPathClipping(
HDC hdc,
const DpContext * context,
BOOL doSaveDC,
const GpRect * drawBounds
)
{
// We can use the actual clip path to set up the clipping
// under the following circumstances:
// 1) the application clipping has only one path
// 2) the container clip is simple (a single rect)
// which either fully encompasses the application clipping
// or else the application clipping is also a single rect
// and the intersection of the 2 rects can be used.
// We could expand this criteria to include more cases, but for
// now, this is sufficient.
const GpRegion * appClip = &(context->AppClip);
const DpRegion * containerClip = &(context->ContainerClip);
if (appClip->IsOnePath() && containerClip->IsSimple())
{
// ContainerClip is a single rect
// It may be inifinte, but it shouldn't be empty at this point.
GpRect pathRect;
GpRect containerBounds;
GpRect appBounds;
GpMatrix identityMatrix;
containerClip->GetBounds(&containerBounds);
appClip->GetBounds(&identityMatrix, &appBounds);
if (appClip->IsRect())
{
GpRect::IntersectRect(pathRect, appBounds, containerBounds);
if (doSaveDC)
{
::SaveDC(hdc);
}
// Use IntersectClipRect (not BeginPath, Rectangle, EndPath),
// because mf3216.dll assumes that
// path clipping means do XOR, black, XOR technique, and
// we don't want that if we are playing a metafile into
// another metafile.
::IntersectClipRect(hdc,
pathRect.GetLeft(),
pathRect.GetTop(),
pathRect.GetRight(),
pathRect.GetBottom());
return TRUE;
}
else // use the AppClip as the clip path
{
ConvertPathToGdi gdiPath(appClip->GetPath(), &identityMatrix, ForFill);
if (gdiPath.IsValid())
{
if (doSaveDC)
{
::SaveDC(hdc);
}
gdiPath.AndClip(hdc);
if ((appBounds.GetLeft() < containerBounds.GetLeft()) ||
(appBounds.GetRight() > containerBounds.GetRight()) ||
(appBounds.GetTop() < containerBounds.GetTop()) ||
(appBounds.GetBottom() > containerBounds.GetBottom()))
{
::IntersectClipRect(hdc,
containerBounds.GetLeft(),
containerBounds.GetTop(),
containerBounds.GetRight(),
containerBounds.GetBottom());
}
return TRUE;
}
}
}
else
{
const DpClipRegion * clipRegion = &(context->VisibleClip);
DpClipRegion intersectClip(drawBounds);
GpRect clipBounds;
if (intersectClip.IsValid())
{
clipRegion->GetBounds(&clipBounds);
// GDI doesn't handle large clip regions very well -- it uses
// the height of the region to decide how much memory to allocate,
// so can end up allocating huge amounts of memory. An example
// of this is to take an infinite region and exclude a rect from
// it and then clip to that region. To solve this problem,
// intersect the clip region with the drawBounds (which are hopefully
// a reasonable size).
if (clipBounds.Height >= GDI_MAX_REGION_HEIGHT_FOR_GDI)
{
intersectClip.And(clipRegion);
if (intersectClip.IsValid())
{
clipRegion = &intersectClip;
}
}
GpPath path(clipRegion);
if (path.IsValid())
{
GpMatrix identityMatrix;
ConvertPathToGdi gdiPath(&path, &identityMatrix, ForFill);
if (gdiPath.IsValid())
{
if (doSaveDC)
{
::SaveDC(hdc);
}
gdiPath.AndClip(hdc);
return TRUE;
}
}
}
}
return FALSE;
}
/**************************************************************************\
*
* Function Description:
*
* Set up the clipping in the HDC for the GDI primitive
*
* Arguments:
*
* [IN] hdc - The device to set the clipping in
* [IN] clipRegion - The region to clip to
* [IN] drawBounds - The bounds of the object being drawn
* [OUT] isClip - Whether or not we are clipping the object
*
* Return Value:
*
* N/A
*
* Created:
*
* 9/15/1999 DCurtis
*
\**************************************************************************/
VOID
DpDriver::SetupClipping(
HDC hdc,
DpContext * context,
const GpRect * drawBounds,
BOOL & isClip,
BOOL & usePathClipping,
BOOL forceClipping
)
{
// VisibleClip is the combination of the AppClip and the ContainerClip.
// The ContainerClip is always intersected with the WindowClip.
DpClipRegion * clipRegion = &(context->VisibleClip);
// We set wantPathClipping to be what the user wants to do. This way
// when we return usePathClipping is true only if we did indeed setup a
// path clipping
BOOL wantPathClipping = usePathClipping;
usePathClipping = FALSE;
isClip = FALSE;
if (forceClipping ||
(clipRegion->GetRectVisibility(
drawBounds->X, drawBounds->Y,
drawBounds->GetRight(),
drawBounds->GetBottom()) != DpRegion::TotallyVisible))
{
if (clipRegion->IsSimple())
{
isClip = TRUE;
GpRect clipRect;
clipRegion->GetBounds(&clipRect);
::SaveDC(hdc);
// If we have an infinite region don't intersect
if (!clipRegion->IsInfinite())
{
::IntersectClipRect(hdc, clipRect.X, clipRect.Y,
clipRect.GetRight(), clipRect.GetBottom());
}
return;
}
// I'm assuming that by now we've already decided that the
// drawBounds is at least partially visible. Otherwise, we're
// going to a lot of trouble here for nothing.
// When writing a metafile, we always want to use path clipping
// so that the clipping scales properly when being played back.
if (wantPathClipping)
{
if (SetupPathClipping(hdc, context, TRUE, drawBounds))
{
isClip = TRUE;
usePathClipping = TRUE;
return;
}
}
// Either we're not supposed to use path clipping, or else
// path clipping failed for some reason, so use the region
// to clip.
// Since this might get saved out to a metafile, we need
// to Save the DC, and restore it once the clipping is back
// so that we don't overwrite the application's clipping
HRGN hRgn = clipRegion->GetHRgn();
if (hRgn != (HRGN)0)
{
::SaveDC(hdc);
::ExtSelectClipRgn(hdc, hRgn, RGN_AND);
::DeleteObject(hRgn);
isClip = TRUE;
}
}
}
/**************************************************************************\
*
* Function Description:
*
* Restore the clipping state in the HDC
*
* Arguments:
*
* [IN] hdc - The device to set the clipping in
* [IN] isClip - If clipping was turned on or not
*
* Return Value:
*
* N/A
*
* Created:
*
* 9/15/1999 DCurtis
*
\**************************************************************************/
VOID
DpDriver::RestoreClipping(
HDC hdc,
BOOL isClip,
BOOL usePathClipping
)
{
if (isClip)
{
// Restore the DC in both cases for PathClipping or
// for region clipping
::RestoreDC(hdc, -1);
}
}