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.
1189 lines
29 KiB
1189 lines
29 KiB
/**************************************************************************\
|
|
*
|
|
* Copyright (c) 1999 Microsoft Corporation
|
|
*
|
|
* Module Name:
|
|
*
|
|
* GraphicsClip.cpp
|
|
*
|
|
* Abstract:
|
|
*
|
|
* Clipping methods of Graphics class
|
|
*
|
|
* Created:
|
|
*
|
|
* 02/05/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
|
|
#include "precomp.hpp"
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* Get a copy of the current clipping region. Transform it through the
|
|
* inverse of the current world-to-device matrix, so that if this region
|
|
* was immediately set as the clipping, then the clipping wouldn't change.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* NONE
|
|
*
|
|
* Return Value:
|
|
*
|
|
* GpRegion * region - a copy of the current clipping region; must be
|
|
* deleted by the application.
|
|
*
|
|
* Created:
|
|
*
|
|
* 02/09/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
GpRegion*
|
|
GpGraphics::GetClip() const
|
|
{
|
|
ASSERT(this->IsValid());
|
|
|
|
GpRegion * region = new GpRegion(&(Context->AppClip));
|
|
|
|
if (region != NULL)
|
|
{
|
|
if (region->IsValid())
|
|
{
|
|
GpMatrix deviceToWorld;
|
|
|
|
if ((GetDeviceToWorldTransform(&deviceToWorld) == Ok) &&
|
|
(region->Transform(&deviceToWorld) == Ok))
|
|
{
|
|
return region;
|
|
}
|
|
}
|
|
delete region;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* Get a copy of the current clipping region. Transform it through the
|
|
* inverse of the current world-to-device matrix, so that if this region
|
|
* was immediately set as the clipping, then the clipping wouldn't change.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* NONE
|
|
*
|
|
* Return Value:
|
|
*
|
|
* GpRegion * region - an already created region, we set the contents of it.
|
|
*
|
|
* Created:
|
|
*
|
|
* 02/09/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
GpStatus
|
|
GpGraphics::GetClip(GpRegion* region) const
|
|
{
|
|
ASSERT(this->IsValid());
|
|
|
|
region->Set(&(Context->AppClip));
|
|
|
|
if (region->IsValid())
|
|
{
|
|
GpMatrix deviceToWorld;
|
|
|
|
if ((GetDeviceToWorldTransform(&deviceToWorld) == Ok) &&
|
|
(region->Transform(&deviceToWorld) == Ok))
|
|
{
|
|
return Ok;
|
|
}
|
|
}
|
|
|
|
return GenericError;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* Reset the clipping back to its default state.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* NONE
|
|
*
|
|
* Return Value:
|
|
*
|
|
* GpStatus - Ok or failure status
|
|
*
|
|
* Created:
|
|
*
|
|
* 02/09/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
GpStatus
|
|
GpGraphics::ResetClip()
|
|
{
|
|
ASSERT(this->IsValid());
|
|
|
|
GpStatus status = Ok;
|
|
|
|
if (IsRecording())
|
|
{
|
|
status = Metafile->RecordResetClip();
|
|
if (status != Ok)
|
|
{
|
|
SetValid(FALSE); // Prevent any more recording
|
|
return status;
|
|
}
|
|
}
|
|
|
|
DoResetClip();
|
|
return status;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* Set the clipping in the graphics context to be the specified rect.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] rect - the rectangle, in world units
|
|
* [IN] combineMode - the combine operator (and, or, xor, exclude, complement)
|
|
*
|
|
* Return Value:
|
|
*
|
|
* GpStatus - Ok or failure status
|
|
*
|
|
* Created:
|
|
*
|
|
* 02/05/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
GpStatus
|
|
GpGraphics::SetClip(
|
|
const GpRectF& rect,
|
|
CombineMode combineMode
|
|
)
|
|
{
|
|
ASSERT(this->IsValid());
|
|
|
|
GpStatus status = Ok;
|
|
|
|
GpRectF tmpRect = rect;
|
|
|
|
// handle flipped rects
|
|
if (tmpRect.Width < 0)
|
|
{
|
|
tmpRect.X += tmpRect.Width;
|
|
tmpRect.Width = -tmpRect.Width;
|
|
}
|
|
|
|
if (tmpRect.Height < 0)
|
|
{
|
|
tmpRect.Y += tmpRect.Height;
|
|
tmpRect.Height = -tmpRect.Height;
|
|
}
|
|
|
|
// crop to infinity
|
|
if (tmpRect.X < INFINITE_MIN)
|
|
{
|
|
if (tmpRect.Width < INFINITE_SIZE)
|
|
{
|
|
tmpRect.Width -= (INFINITE_MIN - tmpRect.X);
|
|
}
|
|
tmpRect.X = INFINITE_MIN;
|
|
}
|
|
if (tmpRect.Y < INFINITE_MIN)
|
|
{
|
|
if (tmpRect.Height < INFINITE_SIZE)
|
|
{
|
|
tmpRect.Height -= (INFINITE_MIN - tmpRect.Y);
|
|
}
|
|
tmpRect.Y = INFINITE_MIN;
|
|
}
|
|
|
|
if ((tmpRect.Width <= REAL_EPSILON) || (tmpRect.Height <= REAL_EPSILON))
|
|
{
|
|
GpRegion emptyRegion;
|
|
|
|
emptyRegion.SetEmpty();
|
|
return this->SetClip(&emptyRegion, combineMode);
|
|
}
|
|
|
|
if (tmpRect.Width >= INFINITE_SIZE)
|
|
{
|
|
if (tmpRect.Height >= INFINITE_SIZE)
|
|
{
|
|
GpRegion infiniteRegion;
|
|
return this->SetClip(&infiniteRegion, combineMode);
|
|
}
|
|
tmpRect.Width = INFINITE_SIZE; // crop to infinite
|
|
}
|
|
else if (tmpRect.Height > INFINITE_SIZE)
|
|
{
|
|
tmpRect.Height = INFINITE_SIZE; // crop to infinite
|
|
}
|
|
|
|
if (IsRecording())
|
|
{
|
|
status = Metafile->RecordSetClip(rect, combineMode);
|
|
if (status != Ok)
|
|
{
|
|
SetValid(FALSE); // Prevent any more recording
|
|
return status;
|
|
}
|
|
}
|
|
|
|
if (combineMode != CombineModeReplace)
|
|
{
|
|
return this->CombineClip(rect, combineMode);
|
|
}
|
|
|
|
if (Context->WorldToDevice.IsTranslateScale())
|
|
{
|
|
GpRectF transformedRect = rect;
|
|
|
|
Context->WorldToDevice.TransformRect(transformedRect);
|
|
Context->AppClip.Set(transformedRect.X,
|
|
transformedRect.Y,
|
|
transformedRect.Width,
|
|
transformedRect.Height);
|
|
|
|
// Try to match the GDI+ rasterizer
|
|
// In theory, this could cause a floating point exception, but
|
|
// the transform would have to be a very big scaling transform to do it.
|
|
INT left = RasterizerCeiling(transformedRect.X);
|
|
INT top = RasterizerCeiling(transformedRect.Y);
|
|
INT right = RasterizerCeiling(transformedRect.GetRight());
|
|
INT bottom = RasterizerCeiling(transformedRect.GetBottom());
|
|
|
|
Context->VisibleClip.Set(left, top, right - left, bottom - top);
|
|
goto AndClip;
|
|
}
|
|
else
|
|
{
|
|
GpPointF points[4];
|
|
REAL left = rect.X;
|
|
REAL top = rect.Y;
|
|
REAL right = rect.X + rect.Width;
|
|
REAL bottom = rect.Y + rect.Height;
|
|
|
|
points[0].X = left;
|
|
points[0].Y = top;
|
|
points[1].X = right;
|
|
points[1].Y = top;
|
|
points[2].X = right;
|
|
points[2].Y = bottom;
|
|
points[3].X = left;
|
|
points[3].Y = bottom;
|
|
|
|
// Transform the points now so we only have to do it once
|
|
Context->WorldToDevice.Transform(points, 4);
|
|
|
|
GpPath path;
|
|
|
|
path.AddLines(points, 4);
|
|
|
|
if (path.IsValid())
|
|
{
|
|
GpMatrix identityMatrix;
|
|
|
|
if ((Context->AppClip.Set(&path) == Ok) &&
|
|
(Context->VisibleClip.Set(&path, &identityMatrix) == Ok))
|
|
{
|
|
goto AndClip;
|
|
}
|
|
}
|
|
}
|
|
|
|
ErrorExit:
|
|
DoResetClip();
|
|
return GenericError;
|
|
|
|
AndClip:
|
|
if (AndVisibleClip() == Ok)
|
|
{
|
|
return status;
|
|
}
|
|
goto ErrorExit;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* Set the clipping in the graphics context to be the specified region.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] region - the region to clip to
|
|
* [IN] combineMode - the combine operator (and, or, xor, exclude, complement)
|
|
*
|
|
* Return Value:
|
|
*
|
|
* GpStatus - Ok or failure status
|
|
*
|
|
* Created:
|
|
*
|
|
* 02/05/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
GpStatus
|
|
GpGraphics::SetClip(
|
|
GpRegion * region,
|
|
CombineMode combineMode
|
|
)
|
|
{
|
|
ASSERT(this->IsValid());
|
|
ASSERT((region != NULL) && (region->IsValid()));
|
|
|
|
GpStatus status = Ok;
|
|
|
|
if (IsRecording())
|
|
{
|
|
status = Metafile->RecordSetClip(region, combineMode);
|
|
if (status != Ok)
|
|
{
|
|
SetValid(FALSE); // Prevent any more recording
|
|
return status;
|
|
}
|
|
}
|
|
|
|
if (combineMode != CombineModeReplace)
|
|
{
|
|
return this->CombineClip(region, combineMode);
|
|
}
|
|
|
|
if ((Context->AppClip.Set(region) == Ok) &&
|
|
(Context->AppClip.Transform(&(Context->WorldToDevice)) == Ok))
|
|
{
|
|
GpMatrix identityMatrix;
|
|
|
|
if ((Context->AppClip.UpdateDeviceRegion(&identityMatrix) == Ok) &&
|
|
(Context->VisibleClip.Set(&(Context->AppClip.DeviceRegion)) == Ok)&&
|
|
(AndVisibleClip() == Ok))
|
|
{
|
|
return status;
|
|
}
|
|
}
|
|
|
|
DoResetClip();
|
|
return GenericError;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* Set the clipping in the graphics context to be the specified region.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] hRgn - the region to clip to (already in device units)
|
|
* [IN] combineMode - the combine operator (and, or, xor, exclude, complement)
|
|
*
|
|
* Return Value:
|
|
*
|
|
* GpStatus - Ok or failure status
|
|
*
|
|
* Created:
|
|
*
|
|
* 02/05/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
GpStatus
|
|
GpGraphics::SetClip(
|
|
HRGN hRgn,
|
|
CombineMode combineMode
|
|
)
|
|
{
|
|
ASSERT(this->IsValid());
|
|
|
|
GpPath path(hRgn);
|
|
|
|
if (path.IsValid())
|
|
{
|
|
return this->SetClip(&path, combineMode, TRUE/*isDevicePath*/);
|
|
}
|
|
return OutOfMemory;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* Set the clipping in the graphics context to be the same as what
|
|
* the specified graphics has.
|
|
*
|
|
* Currently, this only works if the other graphics has the same
|
|
* resolution as this one does.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] g - the graphics to copy the clipping from
|
|
* [IN] combineMode - the combine operator (and, or, xor, exclude, complement)
|
|
*
|
|
* Return Value:
|
|
*
|
|
* GpStatus - Ok or failure status
|
|
*
|
|
* Created:
|
|
*
|
|
* 02/09/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
GpStatus
|
|
GpGraphics::SetClip(
|
|
GpGraphics* g,
|
|
CombineMode combineMode
|
|
)
|
|
{
|
|
ASSERT(this->IsValid() && (g != NULL) && g->IsValid());
|
|
|
|
GpStatus status = GenericError;
|
|
GpRegion * region = new GpRegion(&(g->Context->AppClip));
|
|
|
|
if (region != NULL)
|
|
{
|
|
if (region->IsValid())
|
|
{
|
|
|
|
GpMatrix deviceToWorld;
|
|
|
|
if ((GetDeviceToWorldTransform(&deviceToWorld) == Ok) &&
|
|
(region->Transform(&deviceToWorld) == Ok))
|
|
{
|
|
status = this->SetClip(region, combineMode);
|
|
}
|
|
}
|
|
delete region;
|
|
}
|
|
return status;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* Set the clipping in the graphics context to be the specified path.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] path - the path to clip to
|
|
* [IN] combineMode - the combine operator (and, or, xor, exclude, complement)
|
|
* [IN] isDevicePath- if path is already in device units
|
|
*
|
|
* Return Value:
|
|
*
|
|
* GpStatus - Ok or failure status
|
|
*
|
|
* Created:
|
|
*
|
|
* 02/09/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
GpStatus
|
|
GpGraphics::SetClip(
|
|
GpPath* path,
|
|
CombineMode combineMode,
|
|
BOOL isDevicePath // if path is already in device units
|
|
)
|
|
{
|
|
ASSERT(this->IsValid() && (path != NULL) && path->IsValid());
|
|
|
|
GpStatus status = Ok;
|
|
|
|
if (IsRecording())
|
|
{
|
|
status = Metafile->RecordSetClip(path, combineMode, isDevicePath);
|
|
if (status != Ok)
|
|
{
|
|
SetValid(FALSE); // Prevent any more recording
|
|
return status;
|
|
}
|
|
}
|
|
|
|
if (combineMode != CombineModeReplace)
|
|
{
|
|
return this->CombineClip(path, combineMode, isDevicePath);
|
|
}
|
|
|
|
if ((Context->AppClip.Set(path) == Ok) &&
|
|
(isDevicePath ||
|
|
(Context->AppClip.Transform(&(Context->WorldToDevice)) == Ok)))
|
|
{
|
|
GpMatrix identityMatrix;
|
|
|
|
if ((Context->AppClip.UpdateDeviceRegion(&identityMatrix) == Ok) &&
|
|
(Context->VisibleClip.Set(&(Context->AppClip.DeviceRegion)) == Ok)&&
|
|
(AndVisibleClip() == Ok))
|
|
{
|
|
return status;
|
|
}
|
|
}
|
|
|
|
DoResetClip();
|
|
return GenericError;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* Combine the region with the current clipping using the specified
|
|
* combine type.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] region - the region to combine the clipping with.
|
|
* [IN] combineMode - the combine operator (and, or, xor, exclude, complement)
|
|
*
|
|
* Return Value:
|
|
*
|
|
* GpStatus - Ok or failure status
|
|
*
|
|
* Created:
|
|
*
|
|
* 02/09/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
GpStatus
|
|
GpGraphics::CombineClip(
|
|
GpRegion * region,
|
|
CombineMode combineMode
|
|
)
|
|
{
|
|
ASSERT(this->IsValid());
|
|
ASSERT((region != NULL) && (region->IsValid()));
|
|
ASSERT(CombineModeIsValid(combineMode));
|
|
|
|
GpRegion regionCopy;
|
|
|
|
if (!Context->WorldToDevice.IsIdentity())
|
|
{
|
|
regionCopy.Set(region);
|
|
|
|
if ((!regionCopy.IsValid()) ||
|
|
(regionCopy.Transform(&(Context->WorldToDevice)) != Ok))
|
|
{
|
|
return GenericError;
|
|
}
|
|
region = ®ionCopy;
|
|
}
|
|
|
|
if (Context->AppClip.Combine(region, combineMode) == Ok)
|
|
{
|
|
GpMatrix identityMatrix;
|
|
|
|
if ((Context->AppClip.UpdateDeviceRegion(&identityMatrix) == Ok) &&
|
|
(Context->VisibleClip.Set(&(Context->AppClip.DeviceRegion)) == Ok)&&
|
|
(AndVisibleClip() == Ok))
|
|
{
|
|
return Ok;
|
|
}
|
|
}
|
|
|
|
DoResetClip();
|
|
return GenericError;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* Combine the rect with the current clipping using the specified
|
|
* combine type.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] path - the path to combine the clipping with.
|
|
* [IN] combineMode - the combine operator (and, or, xor, exclude, complement)
|
|
*
|
|
* Return Value:
|
|
*
|
|
* GpStatus - Ok or failure status
|
|
*
|
|
* Created:
|
|
*
|
|
* 02/09/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
GpStatus
|
|
GpGraphics::CombineClip(
|
|
const GpPath * path,
|
|
CombineMode combineMode,
|
|
BOOL isDevicePath // if path is already in device units
|
|
)
|
|
{
|
|
ASSERT(this->IsValid());
|
|
ASSERT((path != NULL) && (path->IsValid()));
|
|
ASSERT(CombineModeIsValid(combineMode));
|
|
|
|
GpPath * pathCopy = NULL;
|
|
|
|
if (!isDevicePath && (!Context->WorldToDevice.IsIdentity()))
|
|
{
|
|
pathCopy = path->Clone();
|
|
|
|
if (!CheckValid(pathCopy))
|
|
{
|
|
return OutOfMemory;
|
|
}
|
|
pathCopy->Transform(&(Context->WorldToDevice));
|
|
path = pathCopy;
|
|
}
|
|
|
|
GpStatus status = Context->AppClip.Combine(path, combineMode);
|
|
|
|
delete pathCopy;
|
|
|
|
if (status == Ok)
|
|
{
|
|
GpMatrix identityMatrix;
|
|
|
|
if ((Context->AppClip.UpdateDeviceRegion(&identityMatrix) == Ok) &&
|
|
(Context->VisibleClip.Set(&(Context->AppClip.DeviceRegion)) == Ok)&&
|
|
(AndVisibleClip() == Ok))
|
|
{
|
|
return Ok;
|
|
}
|
|
}
|
|
|
|
DoResetClip();
|
|
return GenericError;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* Combine the rect with the current clipping using the specified
|
|
* combine type.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] rect - the rect to combine the clipping with.
|
|
* [IN] combineMode - the combine operator (and, or, xor, exclude, complement)
|
|
*
|
|
* Return Value:
|
|
*
|
|
* GpStatus - Ok or failure status
|
|
*
|
|
* Created:
|
|
*
|
|
* 02/09/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
GpStatus
|
|
GpGraphics::CombineClip(
|
|
const GpRectF& rect,
|
|
CombineMode combineMode
|
|
)
|
|
{
|
|
ASSERT(this->IsValid());
|
|
ASSERT(CombineModeIsValid(combineMode));
|
|
|
|
if (Context->WorldToDevice.IsTranslateScale())
|
|
{
|
|
GpRectF transformedRect = rect;
|
|
|
|
Context->WorldToDevice.TransformRect(transformedRect);
|
|
|
|
if (Context->AppClip.Combine(&transformedRect, combineMode) == Ok)
|
|
{
|
|
goto SetVisibleClip;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
GpPointF points[4];
|
|
REAL left = rect.X;
|
|
REAL top = rect.Y;
|
|
REAL right = rect.X + rect.Width;
|
|
REAL bottom = rect.Y + rect.Height;
|
|
|
|
points[0].X = left;
|
|
points[0].Y = top;
|
|
points[1].X = right;
|
|
points[1].Y = top;
|
|
points[2].X = right;
|
|
points[2].Y = bottom;
|
|
points[3].X = left;
|
|
points[3].Y = bottom;
|
|
|
|
Context->WorldToDevice.Transform(points, 4);
|
|
|
|
GpPath path;
|
|
|
|
path.AddLines(points, 4);
|
|
|
|
if (path.IsValid())
|
|
{
|
|
if ( Context->AppClip.Combine(&path, combineMode) == Ok)
|
|
{
|
|
goto SetVisibleClip;
|
|
}
|
|
}
|
|
}
|
|
|
|
ErrorExit:
|
|
DoResetClip();
|
|
return GenericError;
|
|
|
|
SetVisibleClip:
|
|
{
|
|
GpMatrix identityMatrix;
|
|
|
|
if ((Context->AppClip.UpdateDeviceRegion(&identityMatrix) == Ok) &&
|
|
(Context->VisibleClip.Set(&(Context->AppClip.DeviceRegion)) == Ok)&&
|
|
(AndVisibleClip() == Ok))
|
|
{
|
|
return Ok;
|
|
}
|
|
goto ErrorExit;
|
|
}
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* Offset (translate) the current clipping region by the specified
|
|
* world unit amounts.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] dx - the amount of X to offset the region by, in world units
|
|
* [IN] dy - the amount of Y to offset the region by, in world units
|
|
*
|
|
* Return Value:
|
|
*
|
|
* GpStatus - Ok or failure status
|
|
*
|
|
* Created:
|
|
*
|
|
* 02/09/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
GpStatus
|
|
GpGraphics::OffsetClip(
|
|
REAL dx,
|
|
REAL dy
|
|
)
|
|
{
|
|
ASSERT(this->IsValid());
|
|
|
|
GpStatus status = Ok;
|
|
|
|
if (IsRecording())
|
|
{
|
|
status = Metafile->RecordOffsetClip(dx, dy);
|
|
if (status != Ok)
|
|
{
|
|
SetValid(FALSE); // Prevent any more recording
|
|
return status;
|
|
}
|
|
}
|
|
|
|
GpPointF offset(dx, dy);
|
|
|
|
Context->WorldToDevice.VectorTransform(&offset);
|
|
|
|
if (Context->AppClip.Offset(offset.X, offset.Y) == Ok)
|
|
{
|
|
GpMatrix identityMatrix;
|
|
|
|
if ((Context->AppClip.UpdateDeviceRegion(&identityMatrix) == Ok) &&
|
|
(Context->VisibleClip.Set(&(Context->AppClip.DeviceRegion)) == Ok)&&
|
|
(AndVisibleClip() == Ok))
|
|
{
|
|
return status;
|
|
}
|
|
}
|
|
|
|
DoResetClip();
|
|
return GenericError;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* Determine if the specified rect is completely outside the current
|
|
* clipping region.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] rect - the rect to check, in device units
|
|
*
|
|
* Return Value:
|
|
*
|
|
* TRUE - the rect is completely outside the current clipping region
|
|
* FALSE - the rect is at least partially visible
|
|
*
|
|
* Created:
|
|
*
|
|
* 02/05/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
BOOL
|
|
GpGraphics::IsTotallyClipped(
|
|
GpRect * rect // rect in device units
|
|
) const
|
|
{
|
|
ASSERT(rect != NULL);
|
|
|
|
return !(Context->VisibleClip.RectVisible(rect));
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* Determine if the current clipping is empty or not
|
|
*
|
|
* Arguments:
|
|
*
|
|
* NONE
|
|
*
|
|
* Return Value:
|
|
*
|
|
* BOOL - whether or not the current clipping area is empty.
|
|
*
|
|
* Created:
|
|
*
|
|
* 02/09/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
BOOL
|
|
GpGraphics::IsClipEmpty() const
|
|
{
|
|
ASSERT(this->IsValid());
|
|
|
|
GpMatrix identityMatrix;
|
|
BOOL isEmpty = FALSE;
|
|
|
|
Context->AppClip.IsEmpty(&identityMatrix, &isEmpty);
|
|
|
|
return isEmpty;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* Return a rect with the bounds (in world units) of the current clip region.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [OUT] rect - the bounds of the current clip region, in world units
|
|
*
|
|
* Return Value:
|
|
*
|
|
* NONE
|
|
*
|
|
* Created:
|
|
*
|
|
* 02/09/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
VOID
|
|
GpGraphics::GetClipBounds(
|
|
GpRectF& rect
|
|
) const
|
|
{
|
|
ASSERT(this->IsValid());
|
|
|
|
GpRect deviceRect;
|
|
GpMatrix identityMatrix;
|
|
|
|
// We keep AppClip in device units
|
|
Context->AppClip.GetBounds(&identityMatrix, &deviceRect);
|
|
|
|
DeviceToWorldTransformRect(deviceRect, rect);
|
|
}
|
|
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* Transform a device units rect to a world units rect.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] deviceRect - the bounds in device units
|
|
* [OUT] rect - the bounds, in world units
|
|
*
|
|
* Return Value:
|
|
*
|
|
* NONE
|
|
*
|
|
* Created:
|
|
*
|
|
* 04/07/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
VOID
|
|
GpGraphics::DeviceToWorldTransformRect(
|
|
const GpRect & deviceRect,
|
|
GpRectF & rect
|
|
) const
|
|
{
|
|
if (Context->WorldToDevice.IsIdentity())
|
|
{
|
|
rect.X = LTOF(deviceRect.X);
|
|
rect.Y = LTOF(deviceRect.Y);
|
|
rect.Width = LTOF(deviceRect.Width);
|
|
rect.Height = LTOF(deviceRect.Height);
|
|
}
|
|
else
|
|
{
|
|
GpMatrix deviceToWorld;
|
|
|
|
if (GetDeviceToWorldTransform(&deviceToWorld) != Ok)
|
|
{
|
|
rect.X = rect.Y = rect.Width = rect.Height = 0;
|
|
return;
|
|
}
|
|
|
|
if (deviceToWorld.IsTranslateScale())
|
|
{
|
|
rect.X = LTOF(deviceRect.X);
|
|
rect.Y = LTOF(deviceRect.Y);
|
|
rect.Width = LTOF(deviceRect.Width);
|
|
rect.Height = LTOF(deviceRect.Height);
|
|
|
|
deviceToWorld.TransformRect(rect);
|
|
}
|
|
else
|
|
{
|
|
GpPointF points[4];
|
|
REAL left = LTOF(deviceRect.X);
|
|
REAL top = LTOF(deviceRect.Y);
|
|
REAL right = LTOF(deviceRect.X + deviceRect.Width);
|
|
REAL bottom = LTOF(deviceRect.Y + deviceRect.Height);
|
|
|
|
points[0].X = left;
|
|
points[0].Y = top;
|
|
points[1].X = right;
|
|
points[1].Y = top;
|
|
points[2].X = right;
|
|
points[2].Y = bottom;
|
|
points[3].X = left;
|
|
points[3].Y = bottom;
|
|
|
|
deviceToWorld.Transform(points, 4);
|
|
|
|
REAL value;
|
|
|
|
left = points[0].X;
|
|
right = left;
|
|
top = points[0].Y;
|
|
bottom = top;
|
|
|
|
INT count = 3;
|
|
|
|
do
|
|
{
|
|
value = points[count].X;
|
|
|
|
if (value < left)
|
|
{
|
|
left = value;
|
|
}
|
|
else if (value > right)
|
|
{
|
|
right = value;
|
|
}
|
|
|
|
value = points[count].Y;
|
|
|
|
if (value < top)
|
|
{
|
|
top = value;
|
|
}
|
|
else if (value > bottom)
|
|
{
|
|
bottom = value;
|
|
}
|
|
} while (--count > 0);
|
|
|
|
rect.X = left;
|
|
rect.Y = top;
|
|
rect.Width = right - left;
|
|
rect.Height = bottom - top;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* Return a rect with the bounds (in world units) of the current
|
|
* visible clip region.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [OUT] rect - the bounds of the current clip region, in world units
|
|
*
|
|
* Return Value:
|
|
*
|
|
* NONE
|
|
*
|
|
* Created:
|
|
*
|
|
* 02/09/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
VOID
|
|
GpGraphics::GetVisibleClipBounds(
|
|
GpRectF& rect
|
|
) const
|
|
{
|
|
ASSERT(this->IsValid());
|
|
|
|
GpRect deviceRect;
|
|
Context->VisibleClip.GetBounds(&deviceRect);
|
|
|
|
DeviceToWorldTransformRect(deviceRect, rect);
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* Determine if the current visible clipping is empty or not
|
|
*
|
|
* Arguments:
|
|
*
|
|
* NONE
|
|
*
|
|
* Return Value:
|
|
*
|
|
* BOOL - whether or not the current clipping area is empty.
|
|
*
|
|
* Created:
|
|
*
|
|
* 02/09/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
BOOL
|
|
GpGraphics::IsVisibleClipEmpty() const
|
|
{
|
|
ASSERT(this->IsValid());
|
|
|
|
return Context->VisibleClip.IsEmpty();
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* Determine if the specified point is visible within the current clip region.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* point - the point to test, in world units.
|
|
*
|
|
* Return Value:
|
|
*
|
|
* BOOL - whether or not the point is inside the current clipping.
|
|
*
|
|
* Created:
|
|
*
|
|
* 02/09/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
BOOL
|
|
GpGraphics::IsVisible(
|
|
const GpPointF& point
|
|
) const
|
|
{
|
|
ASSERT(this->IsValid());
|
|
|
|
GpPointF pointCopy = point;
|
|
|
|
Context->WorldToDevice.Transform(&pointCopy);
|
|
|
|
|
|
return Context->VisibleClip.PointInside(GpRound(pointCopy.X),
|
|
GpRound(pointCopy.Y));
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* Determine if the specified rect is visible within the current clip region.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* rect - the rect to test, in world units.
|
|
*
|
|
* Return Value:
|
|
*
|
|
* BOOL - whether or not the rect is inside/overlaps the current clipping.
|
|
*
|
|
* Created:
|
|
*
|
|
* 02/09/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
BOOL
|
|
GpGraphics::IsVisible(
|
|
const GpRectF& rect
|
|
) const
|
|
{
|
|
ASSERT(this->IsValid());
|
|
|
|
if (Context->WorldToDevice.IsTranslateScale())
|
|
{
|
|
GpRectF transformedRect = rect;
|
|
|
|
Context->WorldToDevice.TransformRect(transformedRect);
|
|
|
|
// use ceiling to match rasterizer
|
|
return Context->VisibleClip.RectVisible(
|
|
GpCeiling(transformedRect.X),
|
|
GpCeiling(transformedRect.Y),
|
|
GpCeiling(transformedRect.GetRight()),
|
|
GpCeiling(transformedRect.GetBottom()));
|
|
}
|
|
else
|
|
{
|
|
GpRectF bounds;
|
|
GpRect deviceBounds;
|
|
GpRect clipBounds;
|
|
|
|
TransformBounds(&(Context->WorldToDevice),
|
|
rect.X, rect.Y,
|
|
rect.GetRight(), rect.GetBottom(),
|
|
&bounds);
|
|
|
|
GpStatus status = BoundsFToRect(&bounds, &deviceBounds);
|
|
Context->VisibleClip.GetBounds(&clipBounds);
|
|
|
|
// try trivial reject
|
|
if (status == Ok && clipBounds.IntersectsWith(deviceBounds))
|
|
{
|
|
// couldn't reject, so do full test
|
|
GpRegion region(&rect);
|
|
|
|
if (region.IsValid() &&
|
|
(region.UpdateDeviceRegion(&(Context->WorldToDevice)) == Ok))
|
|
{
|
|
return Context->VisibleClip.RegionVisible(®ion.DeviceRegion);
|
|
}
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|