681 lines
20 KiB
C++
681 lines
20 KiB
C++
/**************************************************************************\
|
|
*
|
|
* Copyright (c) 1998 Microsoft Corporation
|
|
*
|
|
* Module Name:
|
|
*
|
|
* DpRegion.hpp
|
|
*
|
|
* Abstract:
|
|
*
|
|
* DpRegion class operates on scan-converted Y spans of rects
|
|
*
|
|
* Created:
|
|
*
|
|
* 12/16/1998 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
|
|
#ifndef _DPREGION_HPP
|
|
#define _DPREGION_HPP
|
|
|
|
// Each Y span consists of 4 values
|
|
#define YSPAN_SIZE 4
|
|
|
|
#define YSPAN_YMIN 0 // minimum Y value (inclusive)
|
|
#define YSPAN_YMAX 1 // maximum Y value (exclusive)
|
|
#define YSPAN_XOFFSET 2 // offset into XCoords for this span
|
|
#define YSPAN_XCOUNT 3 // num XCoords for this span (multiple of 2)
|
|
|
|
#if 0
|
|
// The infinite max and min values are set up to be the greatest
|
|
// values that will interop with GDI HRGNs on WinNT successfully (divided by 2).
|
|
// We divide those values by 2 so that there is a little room to offset
|
|
// the GDI region and still have it work correctly.
|
|
// Of course, this won't work on Win9x -- we have to handle Win9x as
|
|
// a special case in the GetHRGN code.
|
|
|
|
#define INFINITE_MAX 0x03FFFFC7 // (0x07ffff8f / 2)
|
|
#define INFINITE_MIN 0xFC000038 // (0xF8000070 / 2)
|
|
#define INFINITE_SIZE (INFINITE_MAX - INFINITE_MIN)
|
|
|
|
#else
|
|
|
|
// Instead of the above, let's use the largest possible integer value
|
|
// that is guaranteed to round trip correctly between float and int,
|
|
// but as above, let's leave a little head room so we can offset the region.
|
|
|
|
#include "float.h"
|
|
|
|
#define INFINITE_MAX (1 << (FLT_MANT_DIG - 2))
|
|
#define INFINITE_MIN (-INFINITE_MAX)
|
|
#define INFINITE_SIZE (INFINITE_MAX - INFINITE_MIN)
|
|
|
|
#endif
|
|
|
|
|
|
class DpComplexRegion
|
|
{
|
|
public:
|
|
INT XCoordsCapacity; // num XCoords (INTs) allocated
|
|
INT XCoordsCount; // num XCoords (INTs) used
|
|
|
|
INT YSpansCapacity; // num YSpans allocated
|
|
INT NumYSpans; // NumYSpans used
|
|
|
|
INT YSearchIndex; // search start index in YSpans
|
|
|
|
INT * XCoords; // pointer to XCoords
|
|
INT * YSpans; // pointer to YSpans
|
|
// (XCoords + XCoordsCapacity)
|
|
public:
|
|
INT * GetYSpan (INT spanIndex)
|
|
{
|
|
return YSpans + (spanIndex * YSPAN_SIZE);
|
|
}
|
|
|
|
VOID ResetSearchIndex()
|
|
{
|
|
YSearchIndex = NumYSpans >> 1;
|
|
}
|
|
|
|
BOOL YSpanSearch(INT y, INT ** ySpan, INT * spanIndex);
|
|
};
|
|
|
|
class DpRegionBuilder : public GpOutputYSpan
|
|
{
|
|
private:
|
|
// We now use an ObjectTag to determine if the object is valid
|
|
// instead of using a BOOL. This is much more robust and helps
|
|
// with debugging. It also enables us to version our objects
|
|
// more easily with a version number in the ObjectTag.
|
|
ObjectTag Tag; // Keep this as the 1st value in the object!
|
|
|
|
protected:
|
|
VOID SetValid(BOOL valid)
|
|
{
|
|
Tag = valid ? ObjectTagDpRegionBuilder : ObjectTagInvalid;
|
|
}
|
|
|
|
public:
|
|
INT XMin;
|
|
INT YMin;
|
|
INT XMax;
|
|
INT YMax;
|
|
DpComplexRegion * ComplexData;
|
|
|
|
public:
|
|
DpRegionBuilder(INT ySpans)
|
|
{
|
|
SetValid(InitComplexData(ySpans) == Ok);
|
|
}
|
|
|
|
~DpRegionBuilder()
|
|
{
|
|
GpFree(ComplexData);
|
|
|
|
SetValid(FALSE); // so we don't use a deleted object
|
|
}
|
|
|
|
BOOL IsValid() const
|
|
{
|
|
ASSERT((Tag == ObjectTagDpRegionBuilder) || (Tag == ObjectTagInvalid));
|
|
#if DBG
|
|
if (Tag == ObjectTagInvalid)
|
|
{
|
|
WARNING1("Invalid DpRegionBuilder");
|
|
}
|
|
#endif
|
|
|
|
return (Tag == ObjectTagDpRegionBuilder);
|
|
}
|
|
|
|
virtual GpStatus OutputYSpan(
|
|
INT yMin,
|
|
INT yMax,
|
|
INT * xCoords, // even number of X coordinates
|
|
INT numXCoords // must be a multiple of 2
|
|
);
|
|
|
|
GpStatus InitComplexData(INT ySpans);
|
|
};
|
|
|
|
// Forward Declaration for friendliness
|
|
class DpClipRegion;
|
|
|
|
// This class was constructed to optimize for space and speed for the common
|
|
// case of the region consisting of a single rectangle. For that case of a
|
|
// simple region, we want the region to be as small and as fast as possible so
|
|
// that it is not expensive to have a region associated with every window.
|
|
class DpRegion
|
|
{
|
|
private:
|
|
friend DpClipRegion;
|
|
// We now use an ObjectTag to determine if the object is valid
|
|
// instead of using a BOOL. This is much more robust and helps
|
|
// with debugging. It also enables us to version our objects
|
|
// more easily with a version number in the ObjectTag.
|
|
ObjectTag Tag; // Keep this as the 1st value in the object!
|
|
|
|
protected:
|
|
VOID SetValid(BOOL valid)
|
|
{
|
|
Tag = valid ? ObjectTagDpRegion : ObjectTagInvalid;
|
|
}
|
|
|
|
protected:
|
|
UINT32 Infinite : 1;
|
|
UINT32 Empty : 1;
|
|
UINT32 Lazy : 1;
|
|
UINT32 Pad : 29;
|
|
|
|
INT XMin;
|
|
INT YMin;
|
|
INT XMax; // exclusive
|
|
INT YMax; // exclusive
|
|
|
|
DpComplexRegion * ComplexData;
|
|
mutable INT Uniqueness;
|
|
|
|
public:
|
|
enum Visibility
|
|
{
|
|
Invisible = 0,
|
|
PartiallyVisible = 1,
|
|
ClippedVisible = 2,
|
|
TotallyVisible = 3,
|
|
};
|
|
|
|
public:
|
|
DpRegion(BOOL empty = FALSE); // default is infinite region
|
|
DpRegion(const GpRect * rect);
|
|
DpRegion(INT x, INT y, INT width, INT height);
|
|
DpRegion(const DpPath * path, const GpMatrix * matrix);
|
|
DpRegion(const DpRegion * region, BOOL lazy = FALSE);
|
|
DpRegion(DpRegion & region); // copy constructor
|
|
DpRegion(const RECT * rects, INT count);
|
|
~DpRegion()
|
|
{
|
|
FreeData();
|
|
|
|
SetValid(FALSE); // so we don't use a deleted object
|
|
}
|
|
|
|
DpRegion &operator=( DpRegion & region );
|
|
|
|
BOOL IsValid() const
|
|
{
|
|
ASSERT((Tag == ObjectTagDpRegion) || (Tag == ObjectTagInvalid));
|
|
#if DBG
|
|
if (Tag == ObjectTagInvalid)
|
|
{
|
|
WARNING1("Invalid DpRegion");
|
|
}
|
|
#endif
|
|
|
|
return (Tag == ObjectTagDpRegion);
|
|
}
|
|
|
|
VOID Set(INT x, INT y, INT width, INT height);
|
|
VOID Set(GpRect * rect)
|
|
{
|
|
ASSERT (rect != NULL);
|
|
Set(rect->X, rect->Y, rect->Width, rect->Height);
|
|
}
|
|
GpStatus Set(const DpPath * path, const GpMatrix * matrix); // path is in world units
|
|
GpStatus Set(const DpRegion * region, BOOL lazy = FALSE);
|
|
GpStatus Set(const RECT * rects, INT count);
|
|
VOID SetInfinite();
|
|
VOID SetEmpty();
|
|
|
|
GpStatus Offset(INT xOffset, INT yOffset);
|
|
|
|
GpStatus And (const DpRegion * region);
|
|
GpStatus Or (const DpRegion * region);
|
|
GpStatus Xor (const DpRegion * region);
|
|
GpStatus Exclude (const DpRegion * region);
|
|
GpStatus Complement(const DpRegion * region);
|
|
|
|
INT GetXMin() const { ASSERT(IsValid()); return XMin; }
|
|
INT GetYMin() const { ASSERT(IsValid()); return YMin; }
|
|
INT GetXMax() const { ASSERT(IsValid()); return XMax; }
|
|
INT GetYMax() const { ASSERT(IsValid()); return YMax; }
|
|
|
|
INT GetUniqueness() const
|
|
{ ASSERT(IsValid());
|
|
if (Uniqueness == 0)
|
|
{
|
|
Uniqueness = GenerateUniqueness();
|
|
}
|
|
return Uniqueness;
|
|
}
|
|
|
|
VOID UpdateUID() { ASSERT(IsValid()); Uniqueness = 0; }
|
|
|
|
VOID GetBounds(GpRect * bounds) const
|
|
{
|
|
ASSERT(IsValid());
|
|
ASSERT(bounds != NULL);
|
|
|
|
bounds->X = XMin;
|
|
bounds->Y = YMin;
|
|
bounds->Width = XMax - XMin;
|
|
bounds->Height = YMax - YMin;
|
|
}
|
|
|
|
VOID GetBounds(GpPointF * topLeft, GpPointF * bottomRight) const
|
|
{
|
|
ASSERT(IsValid());
|
|
ASSERT((topLeft != NULL) && (bottomRight != NULL));
|
|
|
|
topLeft->X = (REAL)XMin;
|
|
topLeft->Y = (REAL)YMin;
|
|
bottomRight->X = (REAL)XMax;
|
|
bottomRight->Y = (REAL)YMax;
|
|
}
|
|
|
|
BOOL IsEqual(DpRegion * region);
|
|
|
|
BOOL IsEmpty() const
|
|
{
|
|
ASSERT(IsValid());
|
|
return Empty;
|
|
}
|
|
|
|
BOOL IsInfinite() const
|
|
{
|
|
ASSERT(IsValid());
|
|
return Infinite;
|
|
}
|
|
|
|
// Empty and Infinite regions are always simple as well.
|
|
BOOL IsSimple() const
|
|
{
|
|
ASSERT(IsValid());
|
|
return (ComplexData == NULL);
|
|
}
|
|
|
|
BOOL IsComplex() const
|
|
{
|
|
return !IsSimple();
|
|
}
|
|
|
|
Visibility GetRectVisibility(
|
|
INT xMin,
|
|
INT yMin,
|
|
INT xMax,
|
|
INT yMax,
|
|
GpRect * rectClipped = NULL
|
|
);
|
|
|
|
BOOL RegionVisible (DpRegion * region);
|
|
BOOL RectVisible(INT xMin, INT yMin, INT xMax, INT yMax);
|
|
BOOL RectVisible(GpRect * rect)
|
|
{
|
|
return RectVisible(rect->X, rect->Y,
|
|
rect->X + rect->Width, rect->Y + rect->Height);
|
|
}
|
|
BOOL RectInside (INT xMin, INT yMin, INT xMax, INT yMax);
|
|
BOOL PointInside(INT x, INT y);
|
|
|
|
GpStatus Fill(DpOutputSpan * output, GpRect * clipBounds) const;
|
|
|
|
HRGN GetHRgn() const;
|
|
|
|
BOOL GetOutlinePoints(DynPointArray& points,
|
|
DynByteArray& types) const;
|
|
|
|
// If rects is NULL, return the number of rects in the region.
|
|
// Otherwise, assume rects is big enough to hold all the region rects
|
|
// and fill them in and return the number of rects filled in.
|
|
INT GetRects(GpRect * rects) const;
|
|
INT GetRects(GpRectF * rects) const;
|
|
|
|
protected:
|
|
VOID FreeData()
|
|
{
|
|
if (!Lazy)
|
|
{
|
|
GpFree(ComplexData);
|
|
}
|
|
ComplexData = NULL;
|
|
Lazy = FALSE;
|
|
}
|
|
|
|
GpStatus Set(DpRegionBuilder & regionBuilder);
|
|
|
|
// If rects is NULL, return the number of rects in the region.
|
|
// Otherwise, assume rects is big enough to hold all the region rects
|
|
// and fill them in and return the number of rects filled in.
|
|
INT GetRects(RECT * rects, BOOL clampToWin9xSize = FALSE) const;
|
|
|
|
GpStatus CompactAndOutput(
|
|
INT yMin,
|
|
INT yMax,
|
|
INT * xCoords,
|
|
INT numXCoords,
|
|
DpRegionBuilder * regionBuilder,
|
|
DynIntArray * combineCoords
|
|
);
|
|
|
|
GpStatus Diff(
|
|
DpRegion * region1,
|
|
DpRegion * region2,
|
|
BOOL set1
|
|
);
|
|
|
|
GpStatus XSpansAND (
|
|
DynIntArray * combineCoords,
|
|
INT * xSpan1,
|
|
INT numXCoords1,
|
|
INT * xSpan2,
|
|
INT numXCoords2
|
|
);
|
|
|
|
GpStatus XSpansOR (
|
|
DynIntArray * combineCoords,
|
|
INT * xSpan1,
|
|
INT numXCoords1,
|
|
INT * xSpan2,
|
|
INT numXCoords2
|
|
);
|
|
|
|
GpStatus XSpansXOR (
|
|
DynIntArray * combineCoords,
|
|
INT * xSpan1,
|
|
INT numXCoords1,
|
|
INT * xSpan2,
|
|
INT numXCoords2
|
|
);
|
|
|
|
GpStatus XSpansDIFF(
|
|
DynIntArray * combineCoords,
|
|
INT * xSpan1,
|
|
INT numXCoords1,
|
|
INT * xSpan2,
|
|
INT numXCoords2
|
|
);
|
|
|
|
private:
|
|
static INT
|
|
GenerateUniqueness(
|
|
)
|
|
{
|
|
LONG_PTR Uid;
|
|
static LONG_PTR gUniqueness = 0 ;
|
|
|
|
// Use InterlockedCompareExchangeFunction instead of
|
|
// InterlockedIncrement, because InterlockedIncrement doesn't work
|
|
// the way we need it to on Win9x.
|
|
|
|
do
|
|
{
|
|
Uid = gUniqueness;
|
|
} while (CompareExchangeLong_Ptr(&gUniqueness, (Uid + 1), Uid) != Uid);
|
|
|
|
return (INT) (Uid + 1);
|
|
}
|
|
|
|
};
|
|
|
|
class DpClipRegion : public DpRegion,
|
|
public DpOutputSpan
|
|
{
|
|
public:
|
|
enum Direction
|
|
{
|
|
NotEnumerating,
|
|
TopLeftToBottomRight,
|
|
TopRightToBottomLeft,
|
|
BottomLeftToTopRight,
|
|
BottomRightToTopLeft
|
|
};
|
|
|
|
protected:
|
|
DpOutputSpan * OutputClippedSpan;
|
|
DpRegion OriginalRegion; // The old Region
|
|
BOOL ComplexClipDisabled; // Did we disable the complexClip
|
|
|
|
// enumeration stuff
|
|
Direction EnumDirection;
|
|
INT EnumSpan;
|
|
|
|
private:
|
|
friend class DriverPrint;
|
|
|
|
// This is a special method intended for use only by DriverPrint.
|
|
VOID StartBanding()
|
|
{
|
|
ASSERT(IsValid());
|
|
ASSERT(!Empty); // if clipping is empty, we shouldn't be banding
|
|
|
|
ASSERT(ComplexClipDisabled == FALSE); // Unless we are banding we can't
|
|
// have ComplexClip disabled
|
|
ASSERT(OriginalRegion.IsEmpty());
|
|
|
|
// Save the current information of the ClipRegion into OriginalRegion
|
|
// this is done by setting the complexData to our current complexData
|
|
ASSERT(OriginalRegion.ComplexData == NULL);
|
|
OriginalRegion.ComplexData = ComplexData;
|
|
OriginalRegion.Lazy = Lazy;
|
|
OriginalRegion.Uniqueness = Uniqueness;
|
|
OriginalRegion.Infinite = Infinite;
|
|
OriginalRegion.Empty = Empty;
|
|
OriginalRegion.XMin = XMin;
|
|
OriginalRegion.YMin = YMin;
|
|
OriginalRegion.XMax = XMax;
|
|
OriginalRegion.YMax = YMax;
|
|
|
|
|
|
// We don't want to both regions to point to the same data
|
|
ComplexData = NULL;
|
|
Lazy = FALSE;
|
|
|
|
// Create a lazy region so that we don't copy unless needed
|
|
Set(&OriginalRegion, TRUE);
|
|
}
|
|
|
|
// This is a special method intended for use only by DriverPrint.
|
|
VOID EndBanding()
|
|
{
|
|
ASSERT(IsValid());
|
|
ASSERT(!OriginalRegion.IsEmpty());
|
|
ASSERT(!ComplexClipDisabled); // Make sure that we don't leave an opened
|
|
// DisableComplexClip call
|
|
|
|
// Free our Data, we can't be Lazy
|
|
FreeData();
|
|
ASSERT(ComplexData == NULL);
|
|
ComplexData = OriginalRegion.ComplexData;
|
|
Lazy = OriginalRegion.Lazy;
|
|
Uniqueness = OriginalRegion.Uniqueness;
|
|
Infinite = OriginalRegion.Infinite;
|
|
Empty = OriginalRegion.Empty;
|
|
XMin = OriginalRegion.XMin;
|
|
YMin = OriginalRegion.YMin;
|
|
XMax = OriginalRegion.XMax;
|
|
YMax = OriginalRegion.YMax;
|
|
|
|
// We don't want to both regions to point to the same data
|
|
OriginalRegion.ComplexData = NULL;
|
|
OriginalRegion.Lazy = FALSE;
|
|
OriginalRegion.SetEmpty();
|
|
}
|
|
|
|
// This is a special method intended for use only by DriverPrint.
|
|
// We're relying on DriverPrint to restore the bounds back correctly
|
|
// after it's done with banding (by bracketing the banding with
|
|
// StartBanding and EndBanding calls).
|
|
|
|
// This works, even when there is complex clipping, because OutputSpan
|
|
// clips against the bounds before clipping against the complex region.
|
|
VOID SetBandBounds(GpRect & bandBounds, BOOL doIntersect = TRUE)
|
|
{
|
|
ASSERT(IsValid());
|
|
ASSERT(!OriginalRegion.IsEmpty());
|
|
ASSERT((bandBounds.Width > 0) && (bandBounds.Height > 0));
|
|
|
|
GpRect intersectedBounds;
|
|
|
|
if (!doIntersect)
|
|
{
|
|
// We are coming from DisableComplexClipping. We should not have
|
|
// any ComplexData.
|
|
ASSERT(!Lazy);
|
|
ASSERT(ComplexData == NULL);
|
|
|
|
// The reason for not doing the intersection is that sometimes
|
|
// printing using a capped DPI which means that the bandBounds is
|
|
// using a different coordinate system than the original region.
|
|
intersectedBounds = bandBounds;
|
|
}
|
|
else
|
|
{
|
|
GpRect boundsOriginal(OriginalRegion.XMin, OriginalRegion.YMin,
|
|
OriginalRegion.XMax - OriginalRegion.XMin,
|
|
OriginalRegion.YMax - OriginalRegion.YMin);
|
|
if (!GpRect::IntersectRect(intersectedBounds, bandBounds, boundsOriginal))
|
|
{
|
|
// intersection is empty
|
|
SetEmpty();
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Create a region for our band
|
|
DpRegion newRegion(&intersectedBounds);
|
|
|
|
// If we haven't disabled the complex clipping, then restore the original
|
|
// complexRegion and intersect with our current region
|
|
if (!ComplexClipDisabled)
|
|
{
|
|
// Get the original Clipping Region
|
|
Set(&OriginalRegion, TRUE);
|
|
|
|
// Intersect with our current band
|
|
And(&newRegion);
|
|
}
|
|
else
|
|
{
|
|
// We've disabled the complexClipping, Set the clipping to our band
|
|
Set(&newRegion);
|
|
ASSERT(ComplexData == NULL);
|
|
}
|
|
}
|
|
|
|
// This is a special method intended for use only by DriverPrint.
|
|
// We're relying on DriverPrint to re-enable the complex clipping
|
|
// and to restore the bounds back correctly after it's done with banding
|
|
// (by bracketing the banding with StartBanding and EndBanding calls).
|
|
// Typically, when we disable complex clipping, it's because we are
|
|
// using a capped DPI, which means that the bandBounds is in a different
|
|
// resolution than the original clipping region.
|
|
VOID DisableComplexClipping(GpRect & bandBounds, BOOL doIntersect = FALSE)
|
|
{
|
|
ASSERT(IsValid());
|
|
ASSERT(!OriginalRegion.IsEmpty());
|
|
|
|
// Make sure that we call ourselves twice in a row
|
|
ASSERT(ComplexClipDisabled == FALSE);
|
|
|
|
ComplexClipDisabled = TRUE;
|
|
|
|
Set(&bandBounds);
|
|
ASSERT(ComplexData == NULL);
|
|
SetBandBounds(bandBounds, doIntersect);
|
|
}
|
|
|
|
// This is a special method intended for use only by DriverPrint.
|
|
VOID ReEnableComplexClipping()
|
|
{
|
|
ASSERT(IsValid());
|
|
ASSERT(!OriginalRegion.IsEmpty());
|
|
ASSERT(ComplexClipDisabled);
|
|
|
|
ComplexClipDisabled = FALSE;
|
|
|
|
// Set the clipping back to the original state, make in Lazy
|
|
Set(&OriginalRegion, TRUE);
|
|
}
|
|
|
|
public:
|
|
DpClipRegion(BOOL empty = FALSE) : DpRegion(empty)
|
|
{
|
|
OutputClippedSpan = NULL;
|
|
ComplexClipDisabled = FALSE;
|
|
#if DBG
|
|
OriginalRegion.SetEmpty();
|
|
#endif
|
|
}
|
|
DpClipRegion(const GpRect * rect) : DpRegion(rect)
|
|
{
|
|
OutputClippedSpan = NULL;
|
|
ComplexClipDisabled = FALSE;
|
|
#if DBG
|
|
OriginalRegion.SetEmpty();
|
|
#endif
|
|
}
|
|
DpClipRegion(INT x, INT y, INT width, INT height) :
|
|
DpRegion(x, y, width, height)
|
|
{
|
|
OutputClippedSpan = NULL;
|
|
ComplexClipDisabled = FALSE;
|
|
#if DBG
|
|
OriginalRegion.SetEmpty();
|
|
#endif
|
|
}
|
|
DpClipRegion(const DpPath * path, const GpMatrix * matrix) : DpRegion (path, matrix)
|
|
{
|
|
OutputClippedSpan = NULL;
|
|
ComplexClipDisabled = FALSE;
|
|
#if DBG
|
|
OriginalRegion.SetEmpty();
|
|
#endif
|
|
}
|
|
DpClipRegion(const DpRegion * region) : DpRegion(region)
|
|
{
|
|
OutputClippedSpan = NULL;
|
|
ComplexClipDisabled = FALSE;
|
|
#if DBG
|
|
OriginalRegion.SetEmpty();
|
|
#endif
|
|
}
|
|
DpClipRegion(DpClipRegion & region) : DpRegion(region)
|
|
{
|
|
OutputClippedSpan = NULL;
|
|
ComplexClipDisabled = FALSE;
|
|
#if DBG
|
|
OriginalRegion.SetEmpty();
|
|
#endif
|
|
}
|
|
|
|
VOID StartEnumeration (
|
|
INT yMin,
|
|
Direction direction = TopLeftToBottomRight
|
|
);
|
|
|
|
// returns FALSE when done enumerating
|
|
// numRects going in is the number of rects in the buffer and going out
|
|
// is the number of rects that we filled.
|
|
BOOL Enumerate (
|
|
GpRect * rects,
|
|
INT & numRects
|
|
);
|
|
|
|
virtual GpStatus OutputSpan(
|
|
INT y,
|
|
INT xMin,
|
|
INT xMax
|
|
);
|
|
|
|
VOID InitClipping(DpOutputSpan * outputClippedSpan, INT yMin);
|
|
|
|
// EndClipping is here only for debugging (and the Rasterizer doesn't
|
|
// call it):
|
|
VOID EndClipping() {}
|
|
|
|
virtual BOOL IsValid() const { return TRUE; }
|
|
};
|
|
|
|
#endif // _DPREGION_HPP
|