2131 lines
63 KiB
C
2131 lines
63 KiB
C
/*************************************************************************\
|
|
* Module Name: Lines.c
|
|
*
|
|
* Contains most of the required GDI line support. Supports drawing
|
|
* lines in short 'strips' when clipping is complex or coordinates
|
|
* are too large to be drawn by the line hardware.
|
|
*
|
|
* Copyright (c) 1990-1995 Microsoft Corporation
|
|
\**************************************************************************/
|
|
|
|
#include "precomp.h"
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
// We have to be careful of arithmetic overflow in a number of places.
|
|
// Fortunately, the compiler is guaranteed to natively support 64-bit
|
|
// signed LONGLONGs and 64-bit unsigned DWORDLONGs.
|
|
//
|
|
// UUInt32x32To64(a, b) is a macro defined in 'winnt.h' that multiplies
|
|
// two 32-bit ULONGs to produce a 64-bit DWORDLONG result.
|
|
//
|
|
// UInt64By32To32 is our own macro to divide a 64-bit DWORDLONG by
|
|
// a 32-bit ULONG to produce a 32-bit ULONG result.
|
|
//
|
|
// UInt64Mod32To32 is our own macro to modulus a 64-bit DWORDLONG by
|
|
// a 32-bit ULONG to produce a 32-bit ULONG result.
|
|
//
|
|
// 64 bit divides are usually very expensive. Since it's very rare
|
|
// that we'll get lines where the upper 32 bits of the 64 bit result
|
|
// are used, we can almost always use 32-bit ULONG divides. We still
|
|
// must correctly handle the larger cases:
|
|
|
|
#define UInt64Div32To32(a, b) \
|
|
((((DWORDLONG)(a)) > ULONG_MAX) ? \
|
|
(ULONG)((DWORDLONG)(a) / (ULONG)(b)) : \
|
|
(ULONG)((ULONG)(a) / (ULONG)(b)))
|
|
|
|
#define UInt64Mod32To32(a, b) \
|
|
((((DWORDLONG)(a)) > ULONG_MAX) ? \
|
|
(ULONG)((DWORDLONG)(a) % (ULONG)(b)) : \
|
|
(ULONG)((ULONG)(a) % (ULONG)(b)))
|
|
|
|
#define SWAPL(x,y,t) {t = x; x = y; y = t;}
|
|
|
|
FLONG gaflRound[] = {
|
|
FL_H_ROUND_DOWN | FL_V_ROUND_DOWN, // no flips
|
|
FL_H_ROUND_DOWN | FL_V_ROUND_DOWN, // FL_FLIP_D
|
|
FL_H_ROUND_DOWN, // FL_FLIP_V
|
|
FL_V_ROUND_DOWN, // FL_FLIP_V | FL_FLIP_D
|
|
FL_V_ROUND_DOWN, // FL_FLIP_SLOPE_ONE
|
|
0xbaadf00d, // FL_FLIP_SLOPE_ONE | FL_FLIP_D
|
|
FL_H_ROUND_DOWN, // FL_FLIP_SLOPE_ONE | FL_FLIP_V
|
|
0xbaadf00d // FL_FLIP_SLOPE_ONE | FL_FLIP_V | FL_FLIP_D
|
|
};
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL bLines(ppdev, pptfxFirst, pptfxBuf, cptfx, pls,
|
|
* prclClip, apfn[], flStart)
|
|
*
|
|
* Computes the DDA for the line and gets ready to draw it. Puts the
|
|
* pixel data into an array of strips, and calls a strip routine to
|
|
* do the actual drawing.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL bLines(
|
|
PDEV* ppdev,
|
|
POINTFIX* pptfxFirst, // Start of first line
|
|
POINTFIX* pptfxBuf, // Pointer to buffer of all remaining lines
|
|
RUN* prun, // Pointer to runs if doing complex clipping
|
|
ULONG cptfx, // Number of points in pptfxBuf or number of runs
|
|
// in prun
|
|
LINESTATE* pls, // Colour and style info
|
|
RECTL* prclClip, // Pointer to clip rectangle if doing simple clipping
|
|
PFNSTRIP* apfn, // Array of strip functions
|
|
FLONG flStart, // Flags for each line, which is a combination of:
|
|
// FL_SIMPLE_CLIP
|
|
// FL_COMPLEX_CLIP
|
|
// FL_STYLED
|
|
// FL_LAST_PEL_INCLUSIVE
|
|
// - Should be set only for all integer lines,
|
|
// and can't be used with FL_COMPLEX_CLIP
|
|
ULONG ulHwMix)
|
|
{
|
|
ULONG M0;
|
|
ULONG dM;
|
|
ULONG N0;
|
|
ULONG dN;
|
|
ULONG dN_Original;
|
|
FLONG fl;
|
|
LONG x;
|
|
LONG y;
|
|
|
|
LONGLONG llBeta;
|
|
LONGLONG llGamma;
|
|
LONGLONG dl;
|
|
LONGLONG ll;
|
|
|
|
ULONG ulDelta;
|
|
|
|
ULONG x0;
|
|
ULONG y0;
|
|
ULONG x1;
|
|
ULONG cStylePels; // Major length of line in pixels for styling
|
|
ULONG xStart;
|
|
POINTL ptlStart;
|
|
STRIP strip;
|
|
PFNSTRIP pfn;
|
|
LONG cPels;
|
|
LONG* plStrip;
|
|
LONG* plStripEnd;
|
|
LONG cStripsInNextRun;
|
|
|
|
POINTFIX* pptfxBufEnd = pptfxBuf + cptfx; // Last point in path record
|
|
STYLEPOS spThis; // Style pos for this line
|
|
BYTE* pjBase;
|
|
|
|
pjBase = ppdev->pjBase;
|
|
|
|
do {
|
|
|
|
/***********************************************************************\
|
|
* Start the DDA calculations. *
|
|
\***********************************************************************/
|
|
|
|
M0 = (LONG) pptfxFirst->x;
|
|
dM = (LONG) pptfxBuf->x;
|
|
|
|
N0 = (LONG) pptfxFirst->y;
|
|
dN = (LONG) pptfxBuf->y;
|
|
|
|
fl = flStart;
|
|
|
|
// Check for non-clipped, non-styled integer endpoint lines
|
|
|
|
if ((fl & (FL_CLIP | FL_STYLED)) == 0)
|
|
{
|
|
// Special-case integer end-point lines:
|
|
|
|
if (((M0 | dM | N0 | dN) & (F - 1)) == 0)
|
|
{
|
|
LONG x0;
|
|
LONG y0;
|
|
LONG x1;
|
|
LONG y1;
|
|
|
|
x0 = M0 >> FLOG2;
|
|
x1 = dM >> FLOG2;
|
|
y0 = N0 >> FLOG2;
|
|
y1 = dN >> FLOG2;
|
|
|
|
// Unfortunately, we can only use the Weitek's point-
|
|
// to-point capability for perfectly horizontal and
|
|
// vertical lines, because for other lines the tie-
|
|
// breaker rule comes into play, and the Weitek has
|
|
// exactly the wrong tie-breaker convention.
|
|
|
|
if (y0 == y1)
|
|
{
|
|
// Horizontal integer line. Do last-pel exclusion:
|
|
|
|
if (x0 < x1)
|
|
x1--;
|
|
else if (x0 > x1)
|
|
x1++;
|
|
else
|
|
goto Next_Line; // Zero-pel line
|
|
|
|
CP_METALINE(ppdev, pjBase, x0, y0);
|
|
CP_METALINE(ppdev, pjBase, x1, y1);
|
|
CP_START_QUAD_WAIT(ppdev, pjBase);
|
|
goto Next_Line;
|
|
}
|
|
else if (x0 == x1)
|
|
{
|
|
// Vertical integer line. Do last-pel exclusion:
|
|
|
|
if (y0 < y1)
|
|
y1--;
|
|
else
|
|
y1++;
|
|
|
|
CP_METALINE(ppdev, pjBase, x0, y0);
|
|
CP_METALINE(ppdev, pjBase, x1, y1);
|
|
CP_START_QUAD_WAIT(ppdev, pjBase);
|
|
goto Next_Line;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((LONG) M0 > (LONG) dM)
|
|
{
|
|
// Ensure that we run left-to-right:
|
|
|
|
register ULONG ulTmp;
|
|
SWAPL(M0, dM, ulTmp);
|
|
SWAPL(N0, dN, ulTmp);
|
|
fl |= FL_FLIP_H;
|
|
}
|
|
|
|
// Compute the delta dx. The DDI says we can never have a valid delta
|
|
// with a magnitued more than 2^31 - 1, but GDI never actually checks
|
|
// its transforms. So we have to check for this case to avoid overflow:
|
|
|
|
dM -= M0;
|
|
if ((LONG) dM < 0)
|
|
{
|
|
goto Next_Line;
|
|
}
|
|
|
|
if ((LONG) dN < (LONG) N0)
|
|
{
|
|
// Line runs from bottom to top, so flip across y = 0:
|
|
|
|
N0 = -(LONG) N0;
|
|
dN = -(LONG) dN;
|
|
fl |= FL_FLIP_V;
|
|
}
|
|
|
|
dN -= N0;
|
|
|
|
if ((LONG) dN < 0)
|
|
{
|
|
goto Next_Line;
|
|
}
|
|
|
|
// We now have a line running left-to-right, top-to-bottom from (M0, N0)
|
|
// to (M0 + dM, N0 + dN):
|
|
|
|
if (dN >= dM)
|
|
{
|
|
if (dN == dM)
|
|
{
|
|
// Have to special case slopes of one:
|
|
|
|
fl |= FL_FLIP_SLOPE_ONE;
|
|
}
|
|
else
|
|
{
|
|
// Since line has slope greater than 1, flip across x = y:
|
|
|
|
register ULONG ulTmp;
|
|
SWAPL(dM, dN, ulTmp);
|
|
SWAPL(M0, N0, ulTmp);
|
|
fl |= FL_FLIP_D;
|
|
}
|
|
}
|
|
|
|
fl |= gaflRound[(fl & FL_ROUND_MASK) >> FL_ROUND_SHIFT];
|
|
|
|
x = LFLOOR((LONG) M0);
|
|
y = LFLOOR((LONG) N0);
|
|
|
|
M0 = FXFRAC(M0);
|
|
N0 = FXFRAC(N0);
|
|
|
|
// Calculate the remainder term [ dM * (N0 + F/2) - M0 * dN ]:
|
|
|
|
llGamma = UInt32x32To64(dM, N0 + F/2) - UInt32x32To64(M0, dN);
|
|
if (fl & FL_V_ROUND_DOWN) // Adjust so y = 1/2 rounds down
|
|
{
|
|
llGamma--;
|
|
}
|
|
|
|
llGamma >>= FLOG2;
|
|
llBeta = ~llGamma;
|
|
|
|
/***********************************************************************\
|
|
* Figure out which pixels are at the ends of the line. *
|
|
\***********************************************************************/
|
|
|
|
// The toughest part of GIQ is determining the start and end pels.
|
|
//
|
|
// Our approach here is to calculate x0 and x1 (the inclusive start
|
|
// and end columns of the line respectively, relative to our normalized
|
|
// origin). Then x1 - x0 + 1 is the number of pels in the line. The
|
|
// start point is easily calculated by plugging x0 into our line equation
|
|
// (which takes care of whether y = 1/2 rounds up or down in value)
|
|
// getting y0, and then undoing the normalizing flips to get back
|
|
// into device space.
|
|
//
|
|
// We look at the fractional parts of the coordinates of the start and
|
|
// end points, and call them (M0, N0) and (M1, N1) respectively, where
|
|
// 0 <= M0, N0, M1, N1 < 16. We plot (M0, N0) on the following grid
|
|
// to determine x0:
|
|
//
|
|
// +-----------------------> +x
|
|
// |
|
|
// | 0 1
|
|
// | 0123456789abcdef
|
|
// |
|
|
// | 0 ........?xxxxxxx
|
|
// | 1 ..........xxxxxx
|
|
// | 2 ...........xxxxx
|
|
// | 3 ............xxxx
|
|
// | 4 .............xxx
|
|
// | 5 ..............xx
|
|
// | 6 ...............x
|
|
// | 7 ................
|
|
// | 8 ................
|
|
// | 9 ......**........
|
|
// | a ........****...x
|
|
// | b ............****
|
|
// | c .............xxx****
|
|
// | d ............xxxx ****
|
|
// | e ...........xxxxx ****
|
|
// | f ..........xxxxxx
|
|
// |
|
|
// | 2 3
|
|
// v
|
|
//
|
|
// +y
|
|
//
|
|
// This grid accounts for the appropriate rounding of GIQ and last-pel
|
|
// exclusion. If (M0, N0) lands on an 'x', x0 = 2. If (M0, N0) lands
|
|
// on a '.', x0 = 1. If (M0, N0) lands on a '?', x0 rounds up or down,
|
|
// depending on what flips have been done to normalize the line.
|
|
//
|
|
// For the end point, if (M1, N1) lands on an 'x', x1 =
|
|
// floor((M0 + dM) / 16) + 1. If (M1, N1) lands on a '.', x1 =
|
|
// floor((M0 + dM)). If (M1, N1) lands on a '?', x1 rounds up or down,
|
|
// depending on what flips have been done to normalize the line.
|
|
//
|
|
// Lines of exactly slope one require a special case for both the start
|
|
// and end. For example, if the line ends such that (M1, N1) is (9, 1),
|
|
// the line has gone exactly through (8, 0) -- which may be considered
|
|
// to be part of 'x' because of rounding! So slopes of exactly slope
|
|
// one going through (8, 0) must also be considered as belonging in 'x'.
|
|
//
|
|
// For lines that go left-to-right, we have the following grid:
|
|
//
|
|
// +-----------------------> +x
|
|
// |
|
|
// | 0 1
|
|
// | 0123456789abcdef
|
|
// |
|
|
// | 0 xxxxxxxx?.......
|
|
// | 1 xxxxxxx.........
|
|
// | 2 xxxxxx..........
|
|
// | 3 xxxxx...........
|
|
// | 4 xxxx............
|
|
// | 5 xxx.............
|
|
// | 6 xx..............
|
|
// | 7 x...............
|
|
// | 8 x...............
|
|
// | 9 x.....**........
|
|
// | a xx......****....
|
|
// | b xxx.........****
|
|
// | c xxxx............****
|
|
// | d xxxxx........... ****
|
|
// | e xxxxxx.......... ****
|
|
// | f xxxxxxx.........
|
|
// |
|
|
// | 2 3
|
|
// v
|
|
//
|
|
// +y
|
|
//
|
|
// This grid accounts for the appropriate rounding of GIQ and last-pel
|
|
// exclusion. If (M0, N0) lands on an 'x', x0 = 0. If (M0, N0) lands
|
|
// on a '.', x0 = 1. If (M0, N0) lands on a '?', x0 rounds up or down,
|
|
// depending on what flips have been done to normalize the line.
|
|
//
|
|
// For the end point, if (M1, N1) lands on an 'x', x1 =
|
|
// floor((M0 + dM) / 16) - 1. If (M1, N1) lands on a '.', x1 =
|
|
// floor((M0 + dM)). If (M1, N1) lands on a '?', x1 rounds up or down,
|
|
// depending on what flips have been done to normalize the line.
|
|
//
|
|
// Lines of exactly slope one must be handled similarly to the right-to-
|
|
// left case.
|
|
|
|
{
|
|
|
|
// Calculate x0, x1
|
|
|
|
ULONG N1 = FXFRAC(N0 + dN);
|
|
ULONG M1 = FXFRAC(M0 + dM);
|
|
|
|
x1 = LFLOOR(M0 + dM);
|
|
|
|
if (fl & FL_LAST_PEL_INCLUSIVE)
|
|
{
|
|
// It sure is easy to compute the first pel when lines have only
|
|
// integer coordinates and are last-pel inclusive:
|
|
|
|
x0 = 0;
|
|
y0 = 0;
|
|
|
|
// Last-pel inclusive lines that are exactly one pixel long
|
|
// have a 'delta-x' and 'delta-y' equal to zero. The problem is
|
|
// that our clip code assumes that 'delta-x' is always non-zero
|
|
// (since it never happens with last-pel exclusive lines). As
|
|
// an inelegant solution, we simply modify 'delta-x' in this
|
|
// case -- because the line is exactly one pixel long, changing
|
|
// the slope will obviously have no effect on rasterization.
|
|
|
|
if (x1 == 0)
|
|
{
|
|
dM = 1;
|
|
llGamma = 0;
|
|
llBeta = ~llGamma;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (fl & FL_FLIP_H)
|
|
{
|
|
// ---------------------------------------------------------------
|
|
// Line runs right-to-left: <----
|
|
|
|
// Compute x1:
|
|
|
|
if (N1 == 0)
|
|
{
|
|
if (LROUND(M1, fl & FL_H_ROUND_DOWN))
|
|
{
|
|
x1++;
|
|
}
|
|
}
|
|
else if (abs((LONG) (N1 - F/2)) + M1 > F)
|
|
{
|
|
x1++;
|
|
}
|
|
|
|
if ((fl & (FL_FLIP_SLOPE_ONE | FL_H_ROUND_DOWN))
|
|
== (FL_FLIP_SLOPE_ONE))
|
|
{
|
|
// Have to special-case diagonal lines going through our
|
|
// the point exactly equidistant between two horizontal
|
|
// pixels, if we're supposed to round x=1/2 down:
|
|
|
|
if ((N1 > 0) && (M1 == N1 + 8))
|
|
x1++;
|
|
|
|
// Don't you love special cases? Is this a rhetorical question?
|
|
|
|
if ((N0 > 0) && (M0 == N0 + 8))
|
|
{
|
|
x0 = 2;
|
|
ulDelta = dN;
|
|
goto right_to_left_compute_y0;
|
|
}
|
|
}
|
|
|
|
// Compute x0:
|
|
|
|
x0 = 1;
|
|
ulDelta = 0;
|
|
if (N0 == 0)
|
|
{
|
|
if (LROUND(M0, fl & FL_H_ROUND_DOWN))
|
|
{
|
|
x0 = 2;
|
|
ulDelta = dN;
|
|
}
|
|
}
|
|
else if (abs((LONG) (N0 - F/2)) + M0 > F)
|
|
{
|
|
x0 = 2;
|
|
ulDelta = dN;
|
|
}
|
|
|
|
|
|
// Compute y0:
|
|
|
|
right_to_left_compute_y0:
|
|
|
|
y0 = 0;
|
|
ll = llGamma + (LONGLONG) ulDelta;
|
|
|
|
if (ll >= (LONGLONG) (2 * dM - dN))
|
|
y0 = 2;
|
|
else if (ll >= (LONGLONG) (dM - dN))
|
|
y0 = 1;
|
|
}
|
|
else
|
|
{
|
|
// ---------------------------------------------------------------
|
|
// Line runs left-to-right: ---->
|
|
|
|
// Compute x1:
|
|
|
|
if (!(fl & FL_LAST_PEL_INCLUSIVE))
|
|
x1--;
|
|
|
|
if (M1 > 0)
|
|
{
|
|
if (N1 == 0)
|
|
{
|
|
if (LROUND(M1, fl & FL_H_ROUND_DOWN))
|
|
x1++;
|
|
}
|
|
else if (abs((LONG) (N1 - F/2)) <= (LONG) M1)
|
|
{
|
|
x1++;
|
|
}
|
|
}
|
|
|
|
if ((fl & (FL_FLIP_SLOPE_ONE | FL_H_ROUND_DOWN))
|
|
== (FL_FLIP_SLOPE_ONE | FL_H_ROUND_DOWN))
|
|
{
|
|
// Have to special-case diagonal lines going through our
|
|
// the point exactly equidistant between two horizontal
|
|
// pixels, if we're supposed to round x=1/2 down:
|
|
|
|
if ((M1 > 0) && (N1 == M1 + 8))
|
|
x1--;
|
|
|
|
if ((M0 > 0) && (N0 == M0 + 8))
|
|
{
|
|
x0 = 0;
|
|
goto left_to_right_compute_y0;
|
|
}
|
|
}
|
|
|
|
// Compute x0:
|
|
|
|
x0 = 0;
|
|
if (M0 > 0)
|
|
{
|
|
if (N0 == 0)
|
|
{
|
|
if (LROUND(M0, fl & FL_H_ROUND_DOWN))
|
|
x0 = 1;
|
|
}
|
|
else if (abs((LONG) (N0 - F/2)) <= (LONG) M0)
|
|
{
|
|
x0 = 1;
|
|
}
|
|
}
|
|
|
|
// Compute y0:
|
|
|
|
left_to_right_compute_y0:
|
|
|
|
y0 = 0;
|
|
if (llGamma >= (LONGLONG) (dM - (dN & (-(LONG) x0))))
|
|
{
|
|
y0 = 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
cStylePels = x1 - x0 + 1;
|
|
if ((LONG) cStylePels <= 0)
|
|
goto Next_Line;
|
|
|
|
xStart = x0;
|
|
|
|
/***********************************************************************\
|
|
* Complex clipping. *
|
|
\***********************************************************************/
|
|
|
|
if (fl & FL_COMPLEX_CLIP)
|
|
{
|
|
dN_Original = dN;
|
|
|
|
Continue_Complex_Clipping:
|
|
|
|
if (fl & FL_FLIP_H)
|
|
{
|
|
// Line runs right-to-left <-----
|
|
|
|
x0 = xStart + cStylePels - prun->iStop - 1;
|
|
x1 = xStart + cStylePels - prun->iStart - 1;
|
|
}
|
|
else
|
|
{
|
|
// Line runs left-to-right ----->
|
|
|
|
x0 = xStart + prun->iStart;
|
|
x1 = xStart + prun->iStop;
|
|
}
|
|
|
|
prun++;
|
|
|
|
// Reset some variables we'll nuke a little later:
|
|
|
|
dN = dN_Original;
|
|
pls->spNext = pls->spComplex;
|
|
|
|
// No overflow since large integer math is used. Both values
|
|
// will be positive:
|
|
|
|
dl = UInt32x32To64(x0, dN) + llGamma;
|
|
|
|
// y0 = dl / dM:
|
|
|
|
y0 = UInt64Div32To32(dl, dM);
|
|
|
|
ASSERTDD((LONG) y0 >= 0, "y0 weird: Goofed up end pel calc?");
|
|
}
|
|
|
|
/***********************************************************************\
|
|
* Simple rectangular clipping. *
|
|
\***********************************************************************/
|
|
|
|
if (fl & FL_SIMPLE_CLIP)
|
|
{
|
|
ULONG y1;
|
|
LONG xRight;
|
|
LONG xLeft;
|
|
LONG yBottom;
|
|
LONG yTop;
|
|
|
|
// Note that y0 and y1 are actually the lower and upper bounds,
|
|
// respectively, of the y coordinates of the line (the line may
|
|
// have actually shrunk due to first/last pel clipping).
|
|
//
|
|
// Also note that x0, y0 are not necessarily zero.
|
|
|
|
RECTL* prcl = &prclClip[(fl & FL_RECTLCLIP_MASK) >>
|
|
FL_RECTLCLIP_SHIFT];
|
|
|
|
// Normalize to the same point we've normalized for the DDA
|
|
// calculations:
|
|
|
|
xRight = prcl->right - x;
|
|
xLeft = prcl->left - x;
|
|
yBottom = prcl->bottom - y;
|
|
yTop = prcl->top - y;
|
|
|
|
if (yBottom <= (LONG) y0 ||
|
|
xRight <= (LONG) x0 ||
|
|
xLeft > (LONG) x1)
|
|
{
|
|
Totally_Clipped:
|
|
|
|
if (fl & FL_STYLED)
|
|
{
|
|
pls->spNext += cStylePels;
|
|
if (pls->spNext >= pls->spTotal2)
|
|
pls->spNext %= pls->spTotal2;
|
|
}
|
|
|
|
goto Next_Line;
|
|
}
|
|
|
|
if ((LONG) x1 >= xRight)
|
|
x1 = xRight - 1;
|
|
|
|
// We have to know the correct y1, which we haven't bothered to
|
|
// calculate up until now. This multiply and divide is quite
|
|
// expensive; we could replace it with code similar to that which
|
|
// we used for computing y0.
|
|
//
|
|
// The reason why we need the actual value, and not an upper
|
|
// bounds guess like y1 = LFLOOR(dM) + 2 is that we have to be
|
|
// careful when calculating x(y) that y0 <= y <= y1, otherwise
|
|
// we can overflow on the divide (which, needless to say, is very
|
|
// bad).
|
|
|
|
dl = UInt32x32To64(x1, dN) + llGamma;
|
|
|
|
// y1 = dl / dM:
|
|
|
|
y1 = UInt64Div32To32(dl, dM);
|
|
|
|
if (yTop > (LONG) y1)
|
|
goto Totally_Clipped;
|
|
|
|
if (yBottom <= (LONG) y1)
|
|
{
|
|
y1 = yBottom;
|
|
dl = UInt32x32To64(y1, dM) + llBeta;
|
|
|
|
// x1 = dl / dN:
|
|
|
|
x1 = UInt64Div32To32(dl, dN);
|
|
}
|
|
|
|
// At this point, we've taken care of calculating the intercepts
|
|
// with the right and bottom edges. Now we work on the left and
|
|
// top edges:
|
|
|
|
if (xLeft > (LONG) x0)
|
|
{
|
|
x0 = xLeft;
|
|
dl = UInt32x32To64(x0, dN) + llGamma;
|
|
|
|
// y0 = dl / dM;
|
|
|
|
y0 = UInt64Div32To32(dl, dM);
|
|
|
|
if (yBottom <= (LONG) y0)
|
|
goto Totally_Clipped;
|
|
}
|
|
|
|
if (yTop > (LONG) y0)
|
|
{
|
|
y0 = yTop;
|
|
dl = UInt32x32To64(y0, dM) + llBeta;
|
|
|
|
// x0 = dl / dN + 1;
|
|
|
|
x0 = UInt64Div32To32(dl, dN) + 1;
|
|
|
|
if (xRight <= (LONG) x0)
|
|
goto Totally_Clipped;
|
|
}
|
|
|
|
ASSERTDD(x0 <= x1, "Improper rectangle clip");
|
|
}
|
|
|
|
/***********************************************************************\
|
|
* Done clipping. Unflip if necessary. *
|
|
\***********************************************************************/
|
|
|
|
ptlStart.x = x + x0;
|
|
ptlStart.y = y + y0;
|
|
|
|
if (fl & FL_FLIP_D)
|
|
{
|
|
register LONG lTmp;
|
|
SWAPL(ptlStart.x, ptlStart.y, lTmp);
|
|
}
|
|
|
|
|
|
if (fl & FL_FLIP_V)
|
|
{
|
|
ptlStart.y = -ptlStart.y;
|
|
}
|
|
|
|
cPels = x1 - x0 + 1;
|
|
|
|
/***********************************************************************\
|
|
* Style calculations. *
|
|
\***********************************************************************/
|
|
|
|
if (fl & FL_STYLED)
|
|
{
|
|
STYLEPOS sp;
|
|
|
|
spThis = pls->spNext;
|
|
pls->spNext += cStylePels;
|
|
|
|
{
|
|
if (pls->spNext >= pls->spTotal2)
|
|
pls->spNext %= pls->spTotal2;
|
|
|
|
if (fl & FL_FLIP_H)
|
|
sp = pls->spNext - x0 + xStart;
|
|
else
|
|
sp = spThis + x0 - xStart;
|
|
|
|
ASSERTDD(fl & FL_STYLED, "Oops");
|
|
|
|
// Normalize our target style position:
|
|
|
|
if ((sp < 0) || (sp >= pls->spTotal2))
|
|
{
|
|
sp %= pls->spTotal2;
|
|
|
|
// The modulus of a negative number is not well-defined
|
|
// in C -- if it's negative we'll adjust it so that it's
|
|
// back in the range [0, spTotal2):
|
|
|
|
if (sp < 0)
|
|
sp += pls->spTotal2;
|
|
}
|
|
|
|
// Since we always draw the line left-to-right, but styling is
|
|
// always done in the direction of the original line, we have
|
|
// to figure out where we are in the style array for the left
|
|
// edge of this line.
|
|
|
|
if (fl & FL_FLIP_H)
|
|
{
|
|
// Line originally ran right-to-left:
|
|
|
|
sp = -sp;
|
|
if (sp < 0)
|
|
sp += pls->spTotal2;
|
|
|
|
pls->ulStyleMask = ~pls->ulStartMask;
|
|
pls->pspStart = &pls->aspRtoL[0];
|
|
pls->pspEnd = &pls->aspRtoL[pls->cStyle - 1];
|
|
}
|
|
else
|
|
{
|
|
// Line originally ran left-to-right:
|
|
|
|
pls->ulStyleMask = pls->ulStartMask;
|
|
pls->pspStart = &pls->aspLtoR[0];
|
|
pls->pspEnd = &pls->aspLtoR[pls->cStyle - 1];
|
|
}
|
|
|
|
if (sp >= pls->spTotal)
|
|
{
|
|
sp -= pls->spTotal;
|
|
if (pls->cStyle & 1)
|
|
pls->ulStyleMask = ~pls->ulStyleMask;
|
|
}
|
|
|
|
pls->psp = pls->pspStart;
|
|
while (sp >= *pls->psp)
|
|
sp -= *pls->psp++;
|
|
|
|
ASSERTDD(pls->psp <= pls->pspEnd,
|
|
"Flew off into NeverNeverLand");
|
|
|
|
pls->spRemaining = *pls->psp - sp;
|
|
if ((pls->psp - pls->pspStart) & 1)
|
|
pls->ulStyleMask = ~pls->ulStyleMask;
|
|
}
|
|
}
|
|
|
|
plStrip = &strip.alStrips[0];
|
|
plStripEnd = &strip.alStrips[STRIP_MAX]; // Is exclusive
|
|
cStripsInNextRun = 0x7fffffff;
|
|
|
|
strip.ptlStart = ptlStart;
|
|
|
|
if (2 * dN > dM &&
|
|
!(fl & FL_STYLED))
|
|
{
|
|
// Do a half flip! Remember that we may doing this on the
|
|
// same line multiple times for complex clipping (meaning the
|
|
// affected variables should be reset for every clip run):
|
|
|
|
fl |= FL_FLIP_HALF;
|
|
|
|
llBeta = llGamma - (LONGLONG) ((LONG) dM);
|
|
dN = dM - dN;
|
|
y0 = x0 - y0; // Note this may overflow, but that's okay
|
|
}
|
|
|
|
// Now, run the DDA starting at (ptlStart.x, ptlStart.y)!
|
|
|
|
strip.flFlips = fl;
|
|
pfn = apfn[(fl & FL_STRIP_MASK) >> FL_STRIP_SHIFT];
|
|
|
|
// Now calculate the DDA variables needed to figure out how many pixels
|
|
// go in the very first strip:
|
|
|
|
{
|
|
register LONG i;
|
|
register ULONG dI;
|
|
register ULONG dR;
|
|
ULONG r;
|
|
|
|
if (dN == 0)
|
|
i = 0x7fffffff;
|
|
else
|
|
{
|
|
dl = UInt32x32To64(y0 + 1, dM) + llBeta;
|
|
|
|
ASSERTDD(dl >= 0, "Oops!");
|
|
|
|
// i = (dl / dN) - x0 + 1;
|
|
// r = (dl % dN);
|
|
|
|
i = UInt64Div32To32(dl, dN);
|
|
r = UInt64Mod32To32(dl, dN);
|
|
i = i - x0 + 1;
|
|
|
|
dI = dM / dN;
|
|
dR = dM % dN; // 0 <= dR < dN
|
|
|
|
ASSERTDD(dI > 0, "Weird dI");
|
|
}
|
|
|
|
ASSERTDD(i > 0 && i <= 0x7fffffff, "Weird initial strip length");
|
|
ASSERTDD(cPels > 0, "Zero pel line");
|
|
|
|
/***********************************************************************\
|
|
* Run the DDA! *
|
|
\***********************************************************************/
|
|
|
|
while(TRUE)
|
|
{
|
|
cPels -= i;
|
|
if (cPels <= 0)
|
|
break;
|
|
|
|
*plStrip++ = i;
|
|
|
|
if (plStrip == plStripEnd)
|
|
{
|
|
strip.cStrips = (LONG)(plStrip - &strip.alStrips[0]);
|
|
(*pfn)(ppdev, &strip, pls);
|
|
plStrip = &strip.alStrips[0];
|
|
}
|
|
|
|
i = dI;
|
|
r += dR;
|
|
|
|
if (r >= dN)
|
|
{
|
|
r -= dN;
|
|
i++;
|
|
}
|
|
}
|
|
|
|
*plStrip++ = cPels + i;
|
|
|
|
strip.cStrips = (ULONG)(plStrip - &strip.alStrips[0]);
|
|
(*pfn)(ppdev, &strip, pls);
|
|
|
|
|
|
}
|
|
|
|
Next_Line:
|
|
|
|
if (fl & FL_COMPLEX_CLIP)
|
|
{
|
|
cptfx--;
|
|
if (cptfx != 0)
|
|
goto Continue_Complex_Clipping;
|
|
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
pptfxFirst = pptfxBuf;
|
|
pptfxBuf++;
|
|
}
|
|
|
|
} while (pptfxBuf < pptfxBufEnd);
|
|
|
|
return(TRUE);
|
|
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL bIntegerUnclippedLines
|
|
*
|
|
* Draws lines using the Weitek's point-to-point capabilities.
|
|
* Unfortunately, the Weitek has exactly the wrong rounding convention
|
|
* for tie-breakers, and GDI is very picky about this.
|
|
*
|
|
* Consequently, we can only use the line hardware when we know there
|
|
* will be no tie-breakers. Fortunately, this is pretty easy to detect,
|
|
* and the odds are that 3 out of 4 lines will not have tie breakers. For
|
|
* those cases where there are tie-breakers, we can still usually draw the
|
|
* lines using the hardware, this time by doing a one-wide trapezoid.
|
|
* Unfortunately, this works for only 6 of the 8 octants, so for the final
|
|
* case we punt to our strips routine.
|
|
*
|
|
* Additional complications include the fact that lines have to be last-pel
|
|
* exclusive, and that we try to optimize horizontal and vertical lines.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL bIntegerUnclippedLines(
|
|
PDEV* ppdev,
|
|
POINTFIX* pptfxFirst,
|
|
POINTFIX* pptfxBuf,
|
|
RUN* prun,
|
|
ULONG cptfx,
|
|
LINESTATE* pls,
|
|
RECTL* prclClip,
|
|
PFNSTRIP* apfn,
|
|
FLONG flStart,
|
|
ULONG ulHwMix)
|
|
{
|
|
BYTE* pjBase;
|
|
BOOL bClippingSet;
|
|
ULONG ulLineMix;
|
|
ULONG ulTrapezoidMix;
|
|
LONG x0;
|
|
LONG y0;
|
|
LONG x1;
|
|
LONG y1;
|
|
LONG xLeft;
|
|
LONG xRight;
|
|
LONG yTop;
|
|
LONG yBottom;
|
|
LONG dx;
|
|
LONG dy;
|
|
LONG lOr;
|
|
LONG lBit;
|
|
LONG iShift;
|
|
LONG xDir;
|
|
LONG yDir;
|
|
|
|
pjBase = ppdev->pjBase;
|
|
bClippingSet = FALSE;
|
|
|
|
if (P9000(ppdev))
|
|
{
|
|
ulTrapezoidMix = ulHwMix;
|
|
ulLineMix = ulTrapezoidMix | P9000_OVERSIZED;
|
|
}
|
|
else
|
|
{
|
|
ulTrapezoidMix = ulHwMix & 0xff;
|
|
ulLineMix = ulTrapezoidMix | P9100_OVERSIZED;
|
|
}
|
|
|
|
while (TRUE)
|
|
{
|
|
x0 = pptfxFirst->x;
|
|
y0 = pptfxFirst->y;
|
|
x1 = pptfxBuf->x;
|
|
y1 = pptfxBuf->y;
|
|
|
|
// First, check to see if the line is has all-integer coordinates:
|
|
|
|
if (((x0 | y0 | x1 | y1) & 0xf) != 0)
|
|
{
|
|
// Ack, this line has non-integer coordinates. The rest of the
|
|
// lines in this batch likely have non-integer coordinates
|
|
// as well, so punt the entire batch to our strips routine:
|
|
|
|
if (bClippingSet)
|
|
{
|
|
CP_WAIT(ppdev, pjBase);
|
|
CP_RASTER(ppdev, pjBase, ulLineMix);
|
|
CP_ABS_WMIN(ppdev, pjBase, 0, 0);
|
|
CP_ABS_WMAX(ppdev, pjBase, MAX_COORD, MAX_COORD);
|
|
}
|
|
|
|
return(bLines(ppdev, pptfxFirst, pptfxBuf, prun, cptfx, pls,
|
|
prclClip, apfn, flStart, ulHwMix));
|
|
}
|
|
else
|
|
{
|
|
x0 >>= 4;
|
|
x1 >>= 4;
|
|
y0 >>= 4;
|
|
y1 >>= 4;
|
|
|
|
if ((y0 == y1) && (!bClippingSet))
|
|
{
|
|
// We special case horizontal lines:
|
|
|
|
if (x0 < x1)
|
|
x1--;
|
|
else if (x0 > x1)
|
|
x1++;
|
|
else
|
|
goto Next_Line; // Zero-length line
|
|
|
|
CP_METALINE(ppdev, pjBase, x0, y0);
|
|
CP_METALINE(ppdev, pjBase, x1, y0);
|
|
CP_START_QUAD_WAIT(ppdev, pjBase);
|
|
goto Next_Line;
|
|
}
|
|
else if (y0 < y1)
|
|
{
|
|
yTop = y0;
|
|
yBottom = y1;
|
|
}
|
|
else
|
|
{
|
|
yBottom = y0;
|
|
yTop = y1;
|
|
}
|
|
|
|
if ((x0 == x1) && (!bClippingSet))
|
|
{
|
|
// We special case vertical lines:
|
|
|
|
if (y0 < y1)
|
|
y1--;
|
|
else
|
|
y1++;
|
|
|
|
CP_METALINE(ppdev, pjBase, x0, y0);
|
|
CP_METALINE(ppdev, pjBase, x0, y1);
|
|
CP_START_QUAD_WAIT(ppdev, pjBase);
|
|
goto Next_Line;
|
|
}
|
|
else if (x0 < x1)
|
|
{
|
|
xLeft = x0;
|
|
xRight = x1;
|
|
}
|
|
else
|
|
{
|
|
xRight = x0;
|
|
xLeft = x1;
|
|
}
|
|
|
|
dx = xRight - xLeft;
|
|
dy = yBottom - yTop;
|
|
|
|
if (dx >= dy)
|
|
{
|
|
if (dx == 0)
|
|
goto Next_Line; // Get rid of zero-length line case
|
|
|
|
// We have an x-major line. Adjust the clip box to
|
|
// account for last-pel exclusion:
|
|
|
|
if (x0 < x1)
|
|
xRight--;
|
|
else
|
|
xLeft++;
|
|
|
|
lOr = (dx | dy);
|
|
lBit = 1;
|
|
iShift = 1;
|
|
while (!(lOr & lBit))
|
|
{
|
|
lBit <<= 1;
|
|
iShift++;
|
|
}
|
|
|
|
if (dx & lBit)
|
|
{
|
|
|
|
Output_Simple_Line:
|
|
|
|
CP_METALINE(ppdev, pjBase, x0, y0);
|
|
CP_METALINE(ppdev, pjBase, x1, y1);
|
|
|
|
CP_WAIT(ppdev, pjBase);
|
|
CP_RASTER(ppdev, pjBase, ulLineMix);
|
|
CP_WMIN(ppdev, pjBase, xLeft, yTop);
|
|
CP_WMAX(ppdev, pjBase, xRight, yBottom);
|
|
CP_START_QUAD_WAIT(ppdev, pjBase);
|
|
bClippingSet = TRUE;
|
|
goto Next_Line;
|
|
}
|
|
else
|
|
{
|
|
if ((dx ^ dy) > 0)
|
|
goto Punt_Line;
|
|
|
|
// Ick, this x-major line has tie-breaker cases.
|
|
|
|
xDir = 0;
|
|
yDir = 1;
|
|
dy >>= iShift;
|
|
if (y0 > y1)
|
|
{
|
|
dy = -dy;
|
|
yDir = -1;
|
|
}
|
|
|
|
y0 -= dy;
|
|
y1 += dy;
|
|
|
|
dx >>= iShift;
|
|
if (x0 > x1)
|
|
dx = -dx;
|
|
|
|
x0 -= dx;
|
|
x1 += dx;
|
|
|
|
Output_Trapezoid_Line:
|
|
|
|
CP_METAQUAD(ppdev, pjBase, x0, y0);
|
|
CP_METAQUAD(ppdev, pjBase, x1 + xDir, y1 - yDir);
|
|
CP_METAQUAD(ppdev, pjBase, x1, y1);
|
|
CP_METAQUAD(ppdev, pjBase, x0 - xDir, y0 + yDir);
|
|
|
|
CP_WAIT(ppdev, pjBase);
|
|
CP_RASTER(ppdev, pjBase, ulTrapezoidMix);
|
|
CP_WMIN(ppdev, pjBase, xLeft, yTop);
|
|
CP_WMAX(ppdev, pjBase, xRight, yBottom);
|
|
CP_START_QUAD_WAIT(ppdev, pjBase);
|
|
bClippingSet = TRUE;
|
|
goto Next_Line;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// We have a y-major line. Adjust the clip box to
|
|
// account for last-pel exclusion:
|
|
|
|
if (y0 < y1)
|
|
yBottom--;
|
|
else
|
|
yTop++;
|
|
|
|
lOr = (dx | dy);
|
|
lBit = 1;
|
|
iShift = 1;
|
|
while (!(lOr & lBit))
|
|
{
|
|
lBit <<= 1;
|
|
iShift++;
|
|
}
|
|
|
|
if (dy & lBit)
|
|
{
|
|
goto Output_Simple_Line;
|
|
}
|
|
else
|
|
{
|
|
// Ick, this y-major line has tie-breaker cases.
|
|
|
|
yDir = 0;
|
|
xDir = 1;
|
|
dx >>= iShift;
|
|
if (x0 > x1)
|
|
{
|
|
dx = -dx;
|
|
xDir = -1;
|
|
}
|
|
|
|
x0 -= dx;
|
|
x1 += dx;
|
|
|
|
dy >>= iShift;
|
|
if (y0 > y1)
|
|
dy = -dy;
|
|
|
|
y0 -= dy;
|
|
y1 += dy;
|
|
|
|
goto Output_Trapezoid_Line;
|
|
}
|
|
}
|
|
}
|
|
|
|
Punt_Line:
|
|
|
|
if (bClippingSet)
|
|
{
|
|
CP_WAIT(ppdev, pjBase);
|
|
CP_RASTER(ppdev, pjBase, ulLineMix);
|
|
CP_ABS_WMIN(ppdev, pjBase, 0, 0);
|
|
CP_ABS_WMAX(ppdev, pjBase, MAX_COORD, MAX_COORD);
|
|
bClippingSet = FALSE;
|
|
}
|
|
|
|
bLines(ppdev, pptfxFirst, pptfxBuf, NULL, 1, pls,
|
|
prclClip, apfn, flStart, ulHwMix);
|
|
|
|
Next_Line:
|
|
|
|
--cptfx;
|
|
if (cptfx == 0)
|
|
break;
|
|
|
|
pptfxFirst = pptfxBuf;
|
|
pptfxBuf++;
|
|
}
|
|
|
|
if (bClippingSet)
|
|
{
|
|
CP_WAIT(ppdev, pjBase);
|
|
CP_RASTER(ppdev, pjBase, ulLineMix); // Might need for next batch
|
|
CP_ABS_WMIN(ppdev, pjBase, 0, 0);
|
|
CP_ABS_WMAX(ppdev, pjBase, MAX_COORD, MAX_COORD);
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL bIntegerClippedLines
|
|
*
|
|
* Draws lines using the hardware when there is a single clipping rectangle.
|
|
* See 'bIntegerUnclippedLines' above for more details.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL bIntegerClippedLines(
|
|
PDEV* ppdev,
|
|
POINTFIX* pptfxFirst,
|
|
POINTFIX* pptfxBuf,
|
|
RUN* prun,
|
|
ULONG cptfx,
|
|
LINESTATE* pls,
|
|
RECTL* prclClip,
|
|
PFNSTRIP* apfn,
|
|
FLONG flStart,
|
|
ULONG ulHwMix)
|
|
{
|
|
BYTE* pjBase;
|
|
BOOL bClippingSet;
|
|
ULONG ulLineMix;
|
|
ULONG ulTrapezoidMix;
|
|
LONG x0;
|
|
LONG y0;
|
|
LONG x1;
|
|
LONG y1;
|
|
LONG xLeft;
|
|
LONG xRight;
|
|
LONG yTop;
|
|
LONG yBottom;
|
|
LONG dx;
|
|
LONG dy;
|
|
LONG lOr;
|
|
LONG lBit;
|
|
LONG iShift;
|
|
LONG xDir;
|
|
LONG yDir;
|
|
|
|
ASSERTDD(flStart & FL_SIMPLE_CLIP, "Expected only simple clipping");
|
|
|
|
pjBase = ppdev->pjBase;
|
|
bClippingSet = FALSE;
|
|
|
|
if (P9000(ppdev))
|
|
{
|
|
ulTrapezoidMix = ulHwMix;
|
|
ulLineMix = ulTrapezoidMix | P9000_OVERSIZED;
|
|
}
|
|
else
|
|
{
|
|
ulTrapezoidMix = ulHwMix & 0xff;
|
|
ulLineMix = ulTrapezoidMix | P9100_OVERSIZED;
|
|
}
|
|
|
|
while (TRUE)
|
|
{
|
|
x0 = pptfxFirst->x;
|
|
y0 = pptfxFirst->y;
|
|
x1 = pptfxBuf->x;
|
|
y1 = pptfxBuf->y;
|
|
|
|
// First, check to see if the line is has all-integer coordinates:
|
|
|
|
if (((x0 | y0 | x1 | y1) & 0xf) != 0)
|
|
{
|
|
// Ack, this line has non-integer coordinates. The rest of the
|
|
// lines in this batch likely have non-integer coordinates
|
|
// as well, so punt the entire batch to our strips routine:
|
|
|
|
if (bClippingSet)
|
|
{
|
|
CP_WAIT(ppdev, pjBase);
|
|
CP_RASTER(ppdev, pjBase, ulLineMix);
|
|
CP_ABS_WMIN(ppdev, pjBase, 0, 0);
|
|
CP_ABS_WMAX(ppdev, pjBase, MAX_COORD, MAX_COORD);
|
|
}
|
|
|
|
return(bLines(ppdev, pptfxFirst, pptfxBuf, prun, cptfx, pls,
|
|
prclClip, apfn, flStart, ulHwMix));
|
|
}
|
|
else
|
|
{
|
|
x0 >>= 4;
|
|
x1 >>= 4;
|
|
y0 >>= 4;
|
|
y1 >>= 4;
|
|
|
|
if (y0 < y1)
|
|
{
|
|
yTop = y0;
|
|
yBottom = y1;
|
|
}
|
|
else
|
|
{
|
|
yBottom = y0;
|
|
yTop = y1;
|
|
}
|
|
|
|
if (x0 < x1)
|
|
{
|
|
xLeft = x0;
|
|
xRight = x1;
|
|
}
|
|
else
|
|
{
|
|
xRight = x0;
|
|
xLeft = x1;
|
|
}
|
|
|
|
// Do a trivial rejection test, remembering that the bound box
|
|
// we just computed is lower-right inclusive:
|
|
|
|
if ((xLeft >= prclClip->right) ||
|
|
(yTop >= prclClip->bottom) ||
|
|
(xRight < prclClip->left) ||
|
|
(yBottom < prclClip->top))
|
|
{
|
|
goto Next_Line;
|
|
}
|
|
else
|
|
{
|
|
dx = xRight - xLeft;
|
|
dy = yBottom - yTop;
|
|
|
|
if (dx >= dy)
|
|
{
|
|
if (dx == 0)
|
|
goto Next_Line; // Get rid of zero-length line case
|
|
|
|
// We have an x-major line. Adjust the clip box to
|
|
// account for last-pel exclusion:
|
|
|
|
if (x0 < x1)
|
|
xRight--;
|
|
else
|
|
xLeft++;
|
|
|
|
lOr = (dx | dy);
|
|
lBit = 1;
|
|
iShift = 1;
|
|
while (!(lOr & lBit))
|
|
{
|
|
lBit <<= 1;
|
|
iShift++;
|
|
}
|
|
|
|
// The Weitek's clip registers are inclusive, and
|
|
// are expected to be well-ordered:
|
|
|
|
xLeft = max(xLeft, prclClip->left);
|
|
yTop = max(yTop, prclClip->top);
|
|
xRight = min(xRight, prclClip->right - 1);
|
|
yBottom = min(yBottom, prclClip->bottom - 1);
|
|
|
|
if ((xLeft <= xRight) && (yTop <= yBottom))
|
|
{
|
|
if (dx & lBit)
|
|
{
|
|
|
|
Output_Simple_Line:
|
|
|
|
CP_METALINE(ppdev, pjBase, x0, y0);
|
|
CP_METALINE(ppdev, pjBase, x1, y1);
|
|
|
|
CP_WAIT(ppdev, pjBase);
|
|
CP_RASTER(ppdev, pjBase, ulLineMix);
|
|
CP_WMIN(ppdev, pjBase, xLeft, yTop);
|
|
CP_WMAX(ppdev, pjBase, xRight, yBottom);
|
|
CP_START_QUAD_WAIT(ppdev, pjBase);
|
|
bClippingSet = TRUE;
|
|
goto Next_Line;
|
|
}
|
|
else
|
|
{
|
|
if ((dx ^ dy) > 0)
|
|
goto Punt_Line;
|
|
|
|
// Ick, this x-major line has tie-breaker cases.
|
|
|
|
xDir = 0;
|
|
yDir = 1;
|
|
dy >>= iShift;
|
|
if (y0 > y1)
|
|
{
|
|
dy = -dy;
|
|
yDir = -1;
|
|
}
|
|
|
|
y0 -= dy;
|
|
y1 += dy;
|
|
|
|
dx >>= iShift;
|
|
if (x0 > x1)
|
|
dx = -dx;
|
|
|
|
x0 -= dx;
|
|
x1 += dx;
|
|
|
|
Output_Trapezoid_Line:
|
|
|
|
CP_METAQUAD(ppdev, pjBase, x0, y0);
|
|
CP_METAQUAD(ppdev, pjBase, x1 + xDir, y1 - yDir);
|
|
CP_METAQUAD(ppdev, pjBase, x1, y1);
|
|
CP_METAQUAD(ppdev, pjBase, x0 - xDir, y0 + yDir);
|
|
|
|
CP_WAIT(ppdev, pjBase);
|
|
CP_RASTER(ppdev, pjBase, ulTrapezoidMix);
|
|
CP_WMIN(ppdev, pjBase, xLeft, yTop);
|
|
CP_WMAX(ppdev, pjBase, xRight, yBottom);
|
|
CP_START_QUAD_WAIT(ppdev, pjBase);
|
|
bClippingSet = TRUE;
|
|
goto Next_Line;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// We have a y-major line. Adjust the clip box to
|
|
// account for last-pel exclusion:
|
|
|
|
if (y0 < y1)
|
|
yBottom--;
|
|
else
|
|
yTop++;
|
|
|
|
lOr = (dx | dy);
|
|
lBit = 1;
|
|
iShift = 1;
|
|
while (!(lOr & lBit))
|
|
{
|
|
lBit <<= 1;
|
|
iShift++;
|
|
}
|
|
|
|
// The Weitek's clip registers are inclusive, and
|
|
// are expected to be well-ordered:
|
|
|
|
xLeft = max(xLeft, prclClip->left);
|
|
yTop = max(yTop, prclClip->top);
|
|
xRight = min(xRight, prclClip->right - 1);
|
|
yBottom = min(yBottom, prclClip->bottom - 1);
|
|
|
|
if ((xLeft <= xRight) && (yTop <= yBottom))
|
|
{
|
|
if (dy & lBit)
|
|
{
|
|
goto Output_Simple_Line;
|
|
}
|
|
else
|
|
{
|
|
// Ick, this y-major line has tie-breaker cases.
|
|
|
|
yDir = 0;
|
|
xDir = 1;
|
|
dx >>= iShift;
|
|
if (x0 > x1)
|
|
{
|
|
dx = -dx;
|
|
xDir = -1;
|
|
}
|
|
|
|
x0 -= dx;
|
|
x1 += dx;
|
|
|
|
dy >>= iShift;
|
|
if (y0 > y1)
|
|
dy = -dy;
|
|
|
|
y0 -= dy;
|
|
y1 += dy;
|
|
|
|
goto Output_Trapezoid_Line;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Punt_Line:
|
|
|
|
if (bClippingSet)
|
|
{
|
|
CP_WAIT(ppdev, pjBase);
|
|
CP_RASTER(ppdev, pjBase, ulLineMix);
|
|
CP_ABS_WMIN(ppdev, pjBase, 0, 0);
|
|
CP_ABS_WMAX(ppdev, pjBase, MAX_COORD, MAX_COORD);
|
|
bClippingSet = FALSE;
|
|
}
|
|
|
|
bLines(ppdev, pptfxFirst, pptfxBuf, NULL, 1, pls,
|
|
prclClip, apfn, flStart, ulHwMix);
|
|
|
|
Next_Line:
|
|
|
|
--cptfx;
|
|
if (cptfx == 0)
|
|
break;
|
|
|
|
pptfxFirst = pptfxBuf;
|
|
pptfxBuf++;
|
|
}
|
|
|
|
if (bClippingSet)
|
|
{
|
|
CP_WAIT(ppdev, pjBase);
|
|
CP_RASTER(ppdev, pjBase, ulLineMix); // Might need for next batch
|
|
CP_ABS_WMIN(ppdev, pjBase, 0, 0);
|
|
CP_ABS_WMAX(ppdev, pjBase, MAX_COORD, MAX_COORD);
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL bCacheCircle(ppdev, ppo, pco, pbo, bStroke, pla)
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL bCacheCircle(
|
|
PDEV* ppdev,
|
|
PATHOBJ* ppo,
|
|
CLIPOBJ* pco,
|
|
BRUSHOBJ* pbo,
|
|
BOOL bStroke, // TRUE if stroke, FALSE if fill
|
|
LINEATTRS* pla) // Used for strokes only
|
|
{
|
|
RECTFX rcfx;
|
|
LONG xCircle;
|
|
LONG yCircle;
|
|
LONG xCached;
|
|
LONG yCached;
|
|
LONG cx;
|
|
LONG cy;
|
|
CIRCLEENTRY* pce;
|
|
LONG i;
|
|
BYTE* pjBase;
|
|
RECTL rclDst;
|
|
POINTL ptlSrc;
|
|
ULONG ulHwMix;
|
|
RECTL rclTmp;
|
|
CLIPENUM ce;
|
|
LONG c;
|
|
LONG bMore;
|
|
LONG iCircleCache;
|
|
SURFOBJ* pso;
|
|
CLIPOBJ co;
|
|
BRUSHOBJ bo;
|
|
|
|
if (!(ppdev->flStat & STAT_CIRCLE_CACHE))
|
|
return(FALSE);
|
|
|
|
PATHOBJ_vGetBounds(ppo, &rcfx);
|
|
|
|
// Normalize bounds to upper-left corner:
|
|
|
|
xCircle = rcfx.xLeft & ~0xfL;
|
|
yCircle = rcfx.yTop & ~0xfL;
|
|
|
|
rcfx.xLeft -= xCircle;
|
|
rcfx.xRight -= xCircle;
|
|
rcfx.yTop -= yCircle;
|
|
rcfx.yBottom -= yCircle;
|
|
|
|
// Convert to pixel units:
|
|
|
|
xCircle >>= 4;
|
|
yCircle >>= 4;
|
|
|
|
cx = (rcfx.xRight >> 4) + 2;
|
|
cy = (rcfx.yBottom >> 4) + 2;
|
|
|
|
if ((cx > CIRCLE_DIMENSION) || (cy > CIRCLE_DIMENSION))
|
|
{
|
|
// This circle is too big to cache, so decline it:
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
pjBase = ppdev->pjBase;
|
|
|
|
pce = &ppdev->ace[0];
|
|
for (i = TOTAL_CIRCLE_COUNT; i != 0; i--)
|
|
{
|
|
if ((pce->bStroke == bStroke) &&
|
|
(pce->rcfxCircle.xLeft == rcfx.xLeft) &&
|
|
(pce->rcfxCircle.yTop == rcfx.yTop) &&
|
|
(pce->rcfxCircle.xRight == rcfx.xRight) &&
|
|
(pce->rcfxCircle.yBottom == rcfx.yBottom))
|
|
{
|
|
Draw_It:
|
|
// We got a hit! Colour-expand from our off-screen
|
|
// cache to the screen:
|
|
|
|
rclDst.left = xCircle;
|
|
rclDst.right = xCircle + cx;
|
|
rclDst.top = yCircle;
|
|
rclDst.bottom = yCircle + cy;
|
|
|
|
// 'ptlSrc' has to be in relative coordinates:
|
|
|
|
ptlSrc.x = pce->xCached - ppdev->xOffset;
|
|
ptlSrc.y = pce->yCached - ppdev->yOffset;
|
|
|
|
CP_WAIT(ppdev, pjBase);
|
|
if (P9000(ppdev))
|
|
{
|
|
CP_FOREGROUND(ppdev, pjBase, pbo->iSolidColor);
|
|
ulHwMix = 0xee22;
|
|
}
|
|
else
|
|
{
|
|
CP_COLOR0(ppdev, pjBase, pbo->iSolidColor);
|
|
ulHwMix = 0xe2e2;
|
|
}
|
|
|
|
if ((pco == NULL) || (pco->iDComplexity == DC_TRIVIAL))
|
|
{
|
|
ppdev->pfnCopyBlt(ppdev, 1, &rclDst, ulHwMix, &ptlSrc, &rclDst);
|
|
}
|
|
else if (pco->iDComplexity == DC_RECT)
|
|
{
|
|
if (bIntersect(&rclDst, &pco->rclBounds, &rclTmp))
|
|
ppdev->pfnCopyBlt(ppdev, 1, &rclTmp, ulHwMix, &ptlSrc, &rclDst);
|
|
}
|
|
else
|
|
{
|
|
CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_ANY, 0);
|
|
|
|
do {
|
|
bMore = CLIPOBJ_bEnum(pco, sizeof(ce), (ULONG*) &ce);
|
|
|
|
c = cIntersect(&rclDst, ce.arcl, ce.c);
|
|
|
|
if (c != 0)
|
|
ppdev->pfnCopyBlt(ppdev, c, ce.arcl, ulHwMix, &ptlSrc, &rclDst);
|
|
|
|
} while (bMore);
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
}
|
|
|
|
// Make an entry in our cache:
|
|
|
|
iCircleCache = ppdev->iCircleCache;
|
|
if (++iCircleCache >= TOTAL_CIRCLE_COUNT)
|
|
iCircleCache = 0;
|
|
ppdev->iCircleCache = iCircleCache;
|
|
|
|
pce = &ppdev->ace[iCircleCache];
|
|
|
|
// We must place the circle in off-screen memory with the same dword
|
|
// alignment as the one we've been asked to draw, because we're
|
|
// going to have GDI draw there instead:
|
|
|
|
xCached = pce->x + (xCircle & 3);
|
|
yCached = pce->y;
|
|
|
|
// Store all the relevant information about the circle:
|
|
|
|
pce->xCached = xCached;
|
|
pce->yCached = yCached;
|
|
pce->bStroke = bStroke;
|
|
|
|
pce->rcfxCircle.xLeft = rcfx.xLeft;
|
|
pce->rcfxCircle.yTop = rcfx.yTop;
|
|
pce->rcfxCircle.xRight = rcfx.xRight;
|
|
pce->rcfxCircle.yBottom = rcfx.yBottom;
|
|
|
|
// Fudge up some parameters for the GDI call:
|
|
|
|
pso = ppdev->psoPunt;
|
|
pso->pvScan0 = ppdev->pjScreen
|
|
+ ((yCached - yCircle) * ppdev->lDelta)
|
|
+ ((xCached - xCircle) * ppdev->cjPel);
|
|
|
|
ASSERTDD((((ULONG_PTR) pso->pvScan0) & 0x3) == 0,
|
|
"Surface must have dword alignment");
|
|
|
|
co.iDComplexity = DC_TRIVIAL;
|
|
bo.iSolidColor = ppdev->ulWhite;
|
|
|
|
// Erase old thing:
|
|
|
|
CP_ABS_METARECT(ppdev, pjBase, xCached, yCached);
|
|
CP_ABS_METARECT(ppdev, pjBase, xCached + CIRCLE_DIMENSION,
|
|
yCached + CIRCLE_DIMENSION);
|
|
|
|
CP_WAIT(ppdev, pjBase);
|
|
CP_RASTER(ppdev, pjBase, 0); // Same on both P9000 and P9100
|
|
CP_START_QUAD(ppdev, pjBase);
|
|
|
|
// Get GDI to draw the circle in our off-screen cache:
|
|
|
|
if (bStroke)
|
|
{
|
|
EngStrokePath(pso, ppo, &co, NULL, &bo, NULL, pla, 0x0d0d);
|
|
}
|
|
else
|
|
{
|
|
EngFillPath(pso, ppo, &co, &bo, NULL, 0x0d0d, FP_ALTERNATEMODE);
|
|
}
|
|
|
|
goto Draw_It;
|
|
}
|
|
|
|
VOID (*gapfnStrip[])(PDEV*, STRIP*, LINESTATE*) = {
|
|
vStripSolidHorizontal,
|
|
vStripSolidVertical,
|
|
vStripSolidDiagonalHorizontal,
|
|
vStripSolidDiagonalVertical,
|
|
|
|
vStripStyledHorizontal,
|
|
vStripStyledVertical,
|
|
vStripStyledVertical, // Diagonal goes here
|
|
vStripStyledVertical, // Diagonal goes here
|
|
};
|
|
|
|
// Style array for alternate style (alternates one pixel on, one pixel off):
|
|
|
|
STYLEPOS gaspAlternateStyle[] = { 1 };
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL DrvStrokePath(pso, ppo, pco, pxo, pbo, pptlBrush, pla, mix)
|
|
*
|
|
* Strokes the path.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL DrvStrokePath(
|
|
SURFOBJ* pso,
|
|
PATHOBJ* ppo,
|
|
CLIPOBJ* pco,
|
|
XFORMOBJ* pxo,
|
|
BRUSHOBJ* pbo,
|
|
POINTL* pptlBrush,
|
|
LINEATTRS* pla,
|
|
MIX mix)
|
|
{
|
|
STYLEPOS aspLtoR[STYLE_MAX_COUNT];
|
|
STYLEPOS aspRtoL[STYLE_MAX_COUNT];
|
|
LINESTATE ls;
|
|
PFNSTRIP* apfn;
|
|
PFNLINES pfnLines;
|
|
FLONG fl;
|
|
PDEV* ppdev;
|
|
DSURF* pdsurf;
|
|
OH* poh;
|
|
RECTL arclClip[4]; // For rectangular clipping
|
|
BYTE* pjBase;
|
|
RECTL* prclClip;
|
|
ULONG ulHwMix;
|
|
|
|
ASSERTDD(((mix >> 8) & 0xff) == (mix & 0xff),
|
|
"GDI gave us an improper mix");
|
|
|
|
// Pass the surface off to GDI if it's a device bitmap that we've
|
|
// converted to a DIB:
|
|
|
|
pdsurf = (DSURF*) pso->dhsurf;
|
|
if (pdsurf->dt == DT_DIB)
|
|
{
|
|
return(EngStrokePath(pdsurf->pso, ppo, pco, pxo, pbo, pptlBrush,
|
|
pla, mix));
|
|
}
|
|
|
|
// We'll be drawing to the screen or an off-screen DFB; copy the surface's
|
|
// offset now so that we won't need to refer to the DSURF again:
|
|
|
|
poh = pdsurf->poh;
|
|
ppdev = (PDEV*) pso->dhpdev;
|
|
ppdev->xOffset = poh->x;
|
|
ppdev->yOffset = poh->y;
|
|
|
|
// Because we set GCAPS_BEZIERS, we have to watch out for Beziers:
|
|
|
|
if (ppo->fl & PO_BEZIERS)
|
|
{
|
|
// We only try to cache solid-styled COPYPEN ellipses:
|
|
|
|
if ((ppo->fl & PO_ELLIPSE) &&
|
|
(mix == 0x0d0d) &&
|
|
!(pla->fl & LA_ALTERNATE) &&
|
|
(pla->pstyle == NULL))
|
|
{
|
|
if (bCacheCircle(ppdev, ppo, pco, pbo, TRUE, pla))
|
|
return(TRUE);
|
|
}
|
|
|
|
// Get GDI to break the Beziers into lines before calling us
|
|
// again:
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
pfnLines = bLines;
|
|
if ((pla->pstyle == NULL) && !(pla->fl & LA_ALTERNATE))
|
|
{
|
|
// We can accelerate solid lines:
|
|
|
|
if (pco->iDComplexity == DC_TRIVIAL)
|
|
{
|
|
pfnLines = bIntegerUnclippedLines;
|
|
}
|
|
else if (pco->iDComplexity == DC_RECT)
|
|
{
|
|
RECTFX rcfxBounds;
|
|
|
|
// We have to be sure that we don't overflow the hardware registers
|
|
// for current position, line length, or DDA terms. We check
|
|
// here to make sure that the current position and line length
|
|
// values won't overflow:
|
|
|
|
PATHOBJ_vGetBounds(ppo, &rcfxBounds);
|
|
|
|
if (rcfxBounds.xLeft + (ppdev->xOffset * F)
|
|
>= (MIN_INTEGER_BOUND * F) &&
|
|
rcfxBounds.xRight + (ppdev->xOffset * F)
|
|
<= (MAX_INTEGER_BOUND * F) &&
|
|
rcfxBounds.yTop + (ppdev->yOffset * F)
|
|
>= (MIN_INTEGER_BOUND * F) &&
|
|
rcfxBounds.yBottom + (ppdev->yOffset * F)
|
|
<= (MAX_INTEGER_BOUND * F))
|
|
{
|
|
pfnLines = bIntegerClippedLines;
|
|
}
|
|
}
|
|
}
|
|
|
|
pjBase = ppdev->pjBase;
|
|
prclClip = NULL;
|
|
fl = 0;
|
|
|
|
// Look after styling initialization:
|
|
|
|
if (pla->fl & LA_ALTERNATE)
|
|
{
|
|
ls.cStyle = 1;
|
|
ls.spTotal = 1;
|
|
ls.spTotal2 = 2;
|
|
ls.spRemaining = 1;
|
|
ls.aspRtoL = &gaspAlternateStyle[0];
|
|
ls.aspLtoR = &gaspAlternateStyle[0];
|
|
ls.spNext = HIWORD(pla->elStyleState.l);
|
|
ls.xyDensity = 1;
|
|
fl |= FL_STYLED;
|
|
ls.ulStartMask = 0L;
|
|
}
|
|
else if (pla->pstyle != (FLOAT_LONG*) NULL)
|
|
{
|
|
PFLOAT_LONG pstyle;
|
|
STYLEPOS* pspDown;
|
|
STYLEPOS* pspUp;
|
|
|
|
pstyle = &pla->pstyle[pla->cstyle];
|
|
|
|
ls.xyDensity = STYLE_DENSITY;
|
|
ls.spTotal = 0;
|
|
while (pstyle-- > pla->pstyle)
|
|
{
|
|
ls.spTotal += pstyle->l;
|
|
}
|
|
ls.spTotal *= STYLE_DENSITY;
|
|
ls.spTotal2 = 2 * ls.spTotal;
|
|
|
|
// Compute starting style position (this is guaranteed not to overflow):
|
|
|
|
ls.spNext = HIWORD(pla->elStyleState.l) * STYLE_DENSITY +
|
|
LOWORD(pla->elStyleState.l);
|
|
|
|
fl |= FL_STYLED;
|
|
ls.cStyle = pla->cstyle;
|
|
ls.aspRtoL = aspRtoL;
|
|
ls.aspLtoR = aspLtoR;
|
|
|
|
if (pla->fl & LA_STARTGAP)
|
|
ls.ulStartMask = 0xffffffffL;
|
|
else
|
|
ls.ulStartMask = 0L;
|
|
|
|
pstyle = pla->pstyle;
|
|
pspDown = &ls.aspRtoL[ls.cStyle - 1];
|
|
pspUp = &ls.aspLtoR[0];
|
|
|
|
while (pspDown >= &ls.aspRtoL[0])
|
|
{
|
|
*pspDown = pstyle->l * STYLE_DENSITY;
|
|
*pspUp = *pspDown;
|
|
|
|
pspUp++;
|
|
pspDown--;
|
|
pstyle++;
|
|
}
|
|
}
|
|
|
|
if (pco->iDComplexity == DC_RECT)
|
|
{
|
|
fl |= FL_SIMPLE_CLIP;
|
|
|
|
arclClip[0] = pco->rclBounds;
|
|
|
|
// FL_FLIP_D:
|
|
|
|
arclClip[1].top = pco->rclBounds.left;
|
|
arclClip[1].left = pco->rclBounds.top;
|
|
arclClip[1].bottom = pco->rclBounds.right;
|
|
arclClip[1].right = pco->rclBounds.bottom;
|
|
|
|
// FL_FLIP_V:
|
|
|
|
arclClip[2].top = -pco->rclBounds.bottom + 1;
|
|
arclClip[2].left = pco->rclBounds.left;
|
|
arclClip[2].bottom = -pco->rclBounds.top + 1;
|
|
arclClip[2].right = pco->rclBounds.right;
|
|
|
|
// FL_FLIP_V | FL_FLIP_D:
|
|
|
|
arclClip[3].top = pco->rclBounds.left;
|
|
arclClip[3].left = -pco->rclBounds.bottom + 1;
|
|
arclClip[3].bottom = pco->rclBounds.right;
|
|
arclClip[3].right = -pco->rclBounds.top + 1;
|
|
|
|
prclClip = arclClip;
|
|
}
|
|
|
|
apfn = &gapfnStrip[4 * ((fl & FL_STYLE_MASK) >> FL_STYLE_SHIFT)];
|
|
|
|
// Get the device ready:
|
|
|
|
ulHwMix = gaRop3FromMix[mix & 0xF];
|
|
ulHwMix = (ulHwMix << 8) | (ulHwMix);
|
|
|
|
CP_WAIT(ppdev, pjBase);
|
|
if (P9000(ppdev))
|
|
{
|
|
CP_RASTER(ppdev, pjBase, P9000_OVERSIZED | ulHwMix);
|
|
CP_BACKGROUND(ppdev, pjBase, pbo->iSolidColor);
|
|
}
|
|
else
|
|
{
|
|
CP_RASTER(ppdev, pjBase, P9100_OVERSIZED | (ulHwMix & 0xff));
|
|
CP_COLOR0(ppdev, pjBase, pbo->iSolidColor);
|
|
}
|
|
|
|
// Set up to enumerate the path:
|
|
|
|
if (pco->iDComplexity != DC_COMPLEX)
|
|
{
|
|
PATHDATA pd;
|
|
BOOL bMore;
|
|
ULONG cptfx;
|
|
POINTFIX ptfxStartFigure;
|
|
POINTFIX ptfxLast;
|
|
POINTFIX* pptfxFirst;
|
|
POINTFIX* pptfxBuf;
|
|
|
|
pd.flags = 0;
|
|
|
|
do {
|
|
bMore = PATHOBJ_bEnum(ppo, &pd);
|
|
|
|
cptfx = pd.count;
|
|
if (cptfx == 0)
|
|
break;
|
|
|
|
if (pd.flags & PD_BEGINSUBPATH)
|
|
{
|
|
ptfxStartFigure = *pd.pptfx;
|
|
pptfxFirst = pd.pptfx;
|
|
pptfxBuf = pd.pptfx + 1;
|
|
cptfx--;
|
|
}
|
|
else
|
|
{
|
|
pptfxFirst = &ptfxLast;
|
|
pptfxBuf = pd.pptfx;
|
|
}
|
|
|
|
if (pd.flags & PD_RESETSTYLE)
|
|
ls.spNext = 0;
|
|
|
|
if (cptfx > 0)
|
|
{
|
|
if (!pfnLines(ppdev,
|
|
pptfxFirst,
|
|
pptfxBuf,
|
|
(RUN*) NULL,
|
|
cptfx,
|
|
&ls,
|
|
prclClip,
|
|
apfn,
|
|
fl,
|
|
ulHwMix))
|
|
{
|
|
return(FALSE);
|
|
}
|
|
}
|
|
|
|
ptfxLast = pd.pptfx[pd.count - 1];
|
|
|
|
if (pd.flags & PD_CLOSEFIGURE)
|
|
{
|
|
if (!pfnLines(ppdev,
|
|
&ptfxLast,
|
|
&ptfxStartFigure,
|
|
(RUN*) NULL,
|
|
1,
|
|
&ls,
|
|
prclClip,
|
|
apfn,
|
|
fl,
|
|
ulHwMix))
|
|
{
|
|
return(FALSE);
|
|
}
|
|
}
|
|
} while (bMore);
|
|
|
|
if (fl & FL_STYLED)
|
|
{
|
|
// Save the style state:
|
|
|
|
ULONG ulHigh;
|
|
ULONG ulLow;
|
|
|
|
// Masked styles don't normalize the style state. It's a good
|
|
// thing to do, so let's do it now:
|
|
|
|
if ((ULONG) ls.spNext >= (ULONG) ls.spTotal2)
|
|
ls.spNext = (ULONG) ls.spNext % (ULONG) ls.spTotal2;
|
|
|
|
ulHigh = ls.spNext / ls.xyDensity;
|
|
ulLow = ls.spNext % ls.xyDensity;
|
|
|
|
pla->elStyleState.l = MAKELONG(ulLow, ulHigh);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Local state for path enumeration:
|
|
|
|
BOOL bMore;
|
|
union {
|
|
BYTE aj[offsetof(CLIPLINE, arun) + RUN_MAX * sizeof(RUN)];
|
|
CLIPLINE cl;
|
|
} cl;
|
|
|
|
fl |= FL_COMPLEX_CLIP;
|
|
|
|
// We use the clip object when non-simple clipping is involved:
|
|
|
|
PATHOBJ_vEnumStartClipLines(ppo, pco, pso, pla);
|
|
|
|
do {
|
|
bMore = PATHOBJ_bEnumClipLines(ppo, sizeof(cl), &cl.cl);
|
|
if (cl.cl.c != 0)
|
|
{
|
|
if (fl & FL_STYLED)
|
|
{
|
|
ls.spComplex = HIWORD(cl.cl.lStyleState) * ls.xyDensity
|
|
+ LOWORD(cl.cl.lStyleState);
|
|
}
|
|
if (!pfnLines(ppdev,
|
|
&cl.cl.ptfxA,
|
|
&cl.cl.ptfxB,
|
|
&cl.cl.arun[0],
|
|
cl.cl.c,
|
|
&ls,
|
|
(RECTL*) NULL,
|
|
apfn,
|
|
fl,
|
|
ulHwMix))
|
|
{
|
|
return(FALSE);
|
|
}
|
|
}
|
|
} while (bMore);
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|