|
|
/******************************Module*Header*******************************\
* Module Name: pathgdi.cxx * * Contains the path APIs. * * Created: 12-Sep-1991 * Author: J. Andrew Goossen [andrewgo] * * Copyright (c) 1991-1999 Microsoft Corporation \**************************************************************************/
#include "precomp.hxx"
#include "pathwide.hxx"
// Default line attributes used for WidenPath:
static LINEATTRS glaNominalGeometric = { LA_GEOMETRIC, // fl
JOIN_ROUND, // iJoin
ENDCAP_ROUND, // iEndCap
{IEEE_0_0F}, // elWidth
IEEE_0_0F, // eMiterLimit
0, // cstyle
(FLOAT_LONG*) NULL, // pstyle
{IEEE_0_0F} // elStyleState
};
/******************************Public*Routine******************************\
* BOOL NtGdiCloseFigure(hdc) * * Closes the figure in an active path. * * History: * 12-Sep-1991 -by- J. Andrew Goossen [andrewgo] * Wrote it. \**************************************************************************/
BOOL APIENTRY NtGdiCloseFigure(HDC hdc) { BOOL bRet = FALSE; DCOBJ dco(hdc);
if (!dco.bValid()) { SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER); return(bRet); }
if (!dco.pdc->bActive()) { SAVE_ERROR_CODE(ERROR_CAN_NOT_COMPLETE); return(bRet); }
XEPATHOBJ epath(dco); if (!epath.bValid() || !epath.bCloseFigure()) { SAVE_ERROR_CODE(ERROR_NOT_ENOUGH_MEMORY); return(bRet); }
bRet = TRUE; return(bRet); }
/******************************Public*Routine******************************\
* BOOL NtGdiAbortPath(hdc) * * Aborts a path bracket, or discards the path from a closed path bracket. * * History: * 19-Mar-1992 -by- J. Andrew Goossen [andrewgo] * Wrote it. \**************************************************************************/
BOOL APIENTRY NtGdiAbortPath(HDC hdc) { BOOL bRet = FALSE;
// Lock the DC.
DCOBJ dco(hdc);
if (!dco.bValid()) { SAVE_ERROR_CODE(ERROR_INVALID_HANDLE); return(bRet); }
// Delete the previous path if there was one:
if (dco.hpath() != HPATH_INVALID) { // If we did a SaveDC, we don't actually have to delete the entire path:
if (dco.pdc->bLazySave()) dco.pdc->vClearLazySave(); else { XEPATHOBJ epath(dco); ASSERTGDI(epath.bValid(), "Invalid DC path");
epath.vDelete(); }
dco.pdc->vDestroy(); }
bRet = TRUE; return(bRet); }
/******************************Public*Routine******************************\
* BOOL NtGdiBeginPath(hdc) * * Starts a path bracket; subsequent drawing calls are added to the path * until GreEndPath is called. Destroys the old one if there was one. * * History: * 12-Sep-1991 -by- J. Andrew Goossen [andrewgo] * Wrote it. \**************************************************************************/
BOOL APIENTRY NtGdiBeginPath(HDC hdc) { BOOL bRet = FALSE;
// Lock the DC.
DCOBJ dco(hdc);
if (!dco.bValid()) { SAVE_ERROR_CODE(ERROR_INVALID_HANDLE); return(bRet); }
// Delete the previous path if there was one:
if (dco.hpath() != HPATH_INVALID) { // If we did a SaveDC, we don't actually have to delete the entire path:
if (dco.pdc->bLazySave()) dco.pdc->vClearLazySave(); else { XEPATHOBJ epath(dco); ASSERTGDI(epath.bValid(), "Invalid DC path");
epath.vDelete(); }
dco.pdc->vDestroy(); }
// Create a new path:
PATHMEMOBJ pmo; if (!pmo.bValid()) { SAVE_ERROR_CODE(ERROR_NOT_ENOUGH_MEMORY); return(bRet); }
// Tell the path we're keeping it, store the handle in the DC, and
// set the flag that we're now accumulating a path:
pmo.vKeepIt(); dco.pdc->hpath(pmo.hpath()); dco.pdc->vSetActive();
bRet = TRUE; return(bRet); }
/******************************Public*Routine******************************\
* BOOL NtGdiEndPath(hdc) * * Ends an active path bracket. * * History: * 12-Sep-1991 -by- J. Andrew Goossen [andrewgo] * Wrote it. \**************************************************************************/
BOOL APIENTRY NtGdiEndPath(HDC hdc) { BOOL bRet = FALSE;
// Lock the DC.
DCOBJ dco(hdc);
if (!dco.bValid()) { SAVE_ERROR_CODE(ERROR_INVALID_HANDLE); return(bRet); }
if (!dco.pdc->bActive()) { SAVE_ERROR_CODE(ERROR_CAN_NOT_COMPLETE); return(bRet); }
// Mark the path handle as no longer active:
dco.pdc->vClearActive();
bRet = TRUE; return(bRet); }
/******************************Public*Routine******************************\
* BOOL NtGdiFlattenPath(hdc) * * Flattens an inactive path. Path must be inactive, by calling GreEndPath. * * History: * 12-Sep-1991 -by- J. Andrew Goossen [andrewgo] * Wrote it. \**************************************************************************/
BOOL APIENTRY NtGdiFlattenPath(HDC hdc) { BOOL bRet = FALSE;
// Lock the DC.
DCOBJ dco(hdc);
if (!dco.bValid()) { SAVE_ERROR_CODE(ERROR_INVALID_HANDLE); return(bRet); }
if (!dco.pdc->bInactive()) { SAVE_ERROR_CODE(ERROR_CAN_NOT_COMPLETE); return(bRet); }
XEPATHOBJ epath(dco); if (!epath.bValid() || !epath.bFlatten()) { SAVE_ERROR_CODE(ERROR_NOT_ENOUGH_MEMORY); return(bRet); }
bRet = TRUE; return(bRet); }
/******************************Public*Routine******************************\
* HRGN NtGdiWidenPath(hdc, pac) * * Widens the inactive path. * * History: * 12-Sep-1991 -by- J. Andrew Goossen [andrewgo] * Wrote it. \**************************************************************************/
BOOL APIENTRY NtGdiWidenPath(HDC hdc) { BOOL bRet = FALSE; DCOBJ dco(hdc);
if (!dco.bValid()) { SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER); return(bRet); }
if (!dco.pdc->bInactive()) { SAVE_ERROR_CODE(ERROR_CAN_NOT_COMPLETE); return(bRet); }
XEPATHOBJ epath(dco); if (!epath.bValid()) { SAVE_ERROR_CODE(ERROR_NOT_ENOUGH_MEMORY); return(bRet); }
EXFORMOBJ xfo(dco, WORLD_TO_DEVICE); ASSERTGDI(xfo.bValid(), "Invalid DC xform");
LINEATTRS *pla = dco.plaRealize(xfo);
if (!(pla->fl & LA_GEOMETRIC)) { // If the pen is an extended pen, it has to be geometric to be used
// for widening. If we have an old style pen and the transform says
// we would normally draw it using a cosmetic pen, substitute a stock
// solid geometric pen for it instead. Thus if pens created via
// CreatePen are used for the widening, we won't suddenly fail the
// call when the transform gets small enough.
if (!((PPEN)dco.pdc->pbrushLine())->bIsOldStylePen()) { SAVE_ERROR_CODE(ERROR_CAN_NOT_COMPLETE); return(bRet); }
pla = &glaNominalGeometric; }
if (!epath.bComputeWidenedBounds((XFORMOBJ *) &xfo, pla)) { SAVE_ERROR_CODE(ERROR_ARITHMETIC_OVERFLOW); return(bRet); }
if (!epath.bWiden((XFORMOBJ *) &xfo, pla)) { SAVE_ERROR_CODE(ERROR_NOT_ENOUGH_MEMORY); return(bRet); }
// The computed widened bounds were only a guess, so recompute based
// on the widened result:
epath.vReComputeBounds();
bRet = TRUE; return(bRet); }
/******************************Public*Routine******************************\
* BOOL NtGdiSelectClipPath(hdc, iMode) * * Selects a path as the DC clip region. Destroys the path. * * History: * 12-Sep-1991 -by- J. Andrew Goossen [andrewgo] * Wrote it. \**************************************************************************/
BOOL APIENTRY NtGdiSelectClipPath(HDC hdc, int iMode) { GDITraceMultiBegin("NtGdiSelectClipPath(%X, %d)\n", (va_list)&hdc); GDITraceMultiHandle(hdc); GDITraceMulti(NtGdiSelectClipPath); GDITraceMulti(PATH); GDITraceMultiEnd();
BOOL bRet = FALSE; DCOBJ dco(hdc);
if (!dco.bValid() || ((iMode < RGN_MIN) || (iMode > RGN_MAX))) { SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER); return(bRet); }
if (!dco.pdc->bInactive()) { SAVE_ERROR_CODE(ERROR_CAN_NOT_COMPLETE); return(bRet); }
// After this point, the path will be deleted no matter what:
XEPATHOBJ epath(dco); if (!epath.bValid()) { SAVE_ERROR_CODE(ERROR_NOT_ENOUGH_MEMORY);
// The path has been deleted, so delete its handle from the DC too:
dco.pdc->vDestroy(); return(bRet); }
RGNMEMOBJTMP rmo(epath, dco.pdc->jFillMode());
bRet = (rmo.bValid() && dco.pdc->iSelect(rmo.prgnGet(), iMode));
// Destroy the path (the region will be destroyed automatically):
epath.vDelete(); dco.pdc->vDestroy();
return(bRet); }
/******************************Public*Routine******************************\
* BOOL NtGdiFillPath(hdc, pac) * * Fills an inactive path. Destroys the path. * * History: * 12-Sep-1991 -by- J. Andrew Goossen [andrewgo] * Wrote it. \**************************************************************************/
BOOL APIENTRY NtGdiFillPath(HDC hdc) { BOOL bRet = FALSE; DCOBJ dco(hdc);
if (!dco.bValid()) { SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER); return(bRet); }
if (!dco.pdc->bInactive()) { SAVE_ERROR_CODE(ERROR_CAN_NOT_COMPLETE); return(bRet); }
// sync the client side cached brush
if (dco.pdc->ulDirty() & DC_BRUSH_DIRTY) { GreDCSelectBrush(dco.pdc, dco.pdc->hbrush()); }
// After this point, the path will be deleted no matter what:
XEPATHOBJ epath(dco); if (!epath.bValid()) { SAVE_ERROR_CODE(ERROR_NOT_ENOUGH_MEMORY);
// The path has been deleted, so delete its handle from the DC too:
dco.pdc->vDestroy(); return(bRet); }
epath.vCloseAllFigures();
bRet = epath.bFill(dco);
// Destroy the path:
epath.vDelete(); dco.pdc->vDestroy();
return(bRet); }
/******************************Public*Routine******************************\
* HRGN NtGdiPathToRegion(hdc) * * Creates a region from the inactive path. Destroys the path. * * History: * 12-Sep-1991 -by- J. Andrew Goossen [andrewgo] * Wrote it. \**************************************************************************/
HRGN APIENTRY NtGdiPathToRegion(HDC hdc) { DCOBJ dco(hdc); HRGN hrgnRet = (HRGN) 0;
if (!dco.bValid()) { SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER); return(hrgnRet); }
if (!dco.pdc->bInactive()) { SAVE_ERROR_CODE(ERROR_CAN_NOT_COMPLETE); return(hrgnRet); }
// After this point, the path will be deleted no matter what:
XEPATHOBJ epath(dco); if (!epath.bValid()) { SAVE_ERROR_CODE(ERROR_NOT_ENOUGH_MEMORY);
// The path has been deleted, so delete its handle from the DC too:
dco.pdc->vDestroy(); return(hrgnRet); }
RGNMEMOBJ rmo(epath, dco.pdc->jFillMode());
if (rmo.bValid()) { hrgnRet = rmo.hrgnAssociate();
if (hrgnRet == NULL) { rmo.bDeleteRGNOBJ(); } } else { hrgnRet = NULL; }
// Destroy the path:
epath.vDelete(); dco.pdc->vDestroy();
return(hrgnRet); }
/******************************Public*Routine******************************\
* HRGN NtGdiStrokeAndFillPath(hdc, pac) * * StrokeAndFill's the inactive path. Destroys it. * * History: * 12-Sep-1991 -by- J. Andrew Goossen [andrewgo] * Wrote it. \**************************************************************************/
BOOL APIENTRY NtGdiStrokeAndFillPath(HDC hdc) { BOOL bRet = FALSE; DCOBJ dco(hdc);
if (!dco.bValid()) { SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER); return(bRet); }
if (!dco.pdc->bInactive()) { SAVE_ERROR_CODE(ERROR_CAN_NOT_COMPLETE); return(bRet); }
// sync the client side cached brush and pen
SYNC_DRAWING_ATTRS(dco.pdc);
// After this point, the path will be deleted no matter what:
XEPATHOBJ epath(dco); if (!epath.bValid()) { SAVE_ERROR_CODE(ERROR_NOT_ENOUGH_MEMORY);
// The path has been deleted, so delete its handle from the DC too:
dco.pdc->vDestroy(); return(bRet); }
EXFORMOBJ xfo(dco, WORLD_TO_DEVICE); ASSERTGDI(xfo.bValid(), "Invalid DC xform");
epath.vCloseAllFigures();
bRet = epath.bStrokeAndFill(dco, dco.plaRealize(xfo), &xfo);
// Destroy the path:
epath.vDelete(); dco.pdc->vDestroy();
return(bRet); }
/******************************Public*Routine******************************\
* HRGN NtGdiStrokePath(hdc) * * Stroke's the inactive path. Destroys it. * * History: * 12-Sep-1991 -by- J. Andrew Goossen [andrewgo] * Wrote it. \**************************************************************************/
BOOL APIENTRY NtGdiStrokePath(HDC hdc) { BOOL bRet = FALSE; DCOBJ dco(hdc);
if (!dco.bValid()) { SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER); return(bRet); }
if (!dco.pdc->bInactive()) { SAVE_ERROR_CODE(ERROR_CAN_NOT_COMPLETE); return(bRet); }
// sync the client side cached pen
if (dco.pdc->ulDirty() & DC_PEN_DIRTY) { GreDCSelectPen(dco.pdc, dco.pdc->hpen()); }
// After this point, the path will be deleted no matter what:
XEPATHOBJ epath(dco); if (!epath.bValid()) { SAVE_ERROR_CODE(ERROR_NOT_ENOUGH_MEMORY);
// The path has been deleted, so delete its handle from the DC too:
dco.pdc->vDestroy(); return(bRet); }
EXFORMOBJ xfo(dco, WORLD_TO_DEVICE); ASSERTGDI(xfo.bValid(), "Invalid DC xform");
bRet = epath.bStroke(dco, dco.plaRealize(xfo), &xfo);
// Destroy the path:
epath.vDelete(); dco.pdc->vDestroy();
return(bRet); }
/******************************Public*Routine******************************\
* BOOL GreSetMiterLimit(hdc, eNewLimit, peOldLimit) * * Sets the DC's miter limit for wide lines. Optionally returns the old one. * * History: * 12-Sep-1991 -by- J. Andrew Goossen [andrewgo] * Wrote it. \**************************************************************************/
BOOL APIENTRY GreSetMiterLimit ( HDC hdc, FLOATL l_eNewLimit, FLOATL *pl_eOldLimit ) { BOOL bRet = FALSE; DCOBJ dco(hdc);
if (!dco.bValid() || l_eNewLimit < IEEE_1_0F) { SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER); return(bRet); }
if (pl_eOldLimit != (FLOATL *) NULL) { *pl_eOldLimit = dco.pdc->l_eMiterLimit(); }
dco.pdc->l_eMiterLimit(l_eNewLimit);
bRet = TRUE; return(bRet); }
/******************************Public*Routine******************************\
* BOOL GreGetMiterLimit(hdc, peMiterLimit) * * Returns the DC's miter limit for wide lines. * * History: * 7-Apr-1992 -by- J. Andrew Goossen [andrewgo] * Wrote it. \**************************************************************************/
BOOL APIENTRY GreGetMiterLimit( HDC hdc, FLOATL *pl_eMiterLimit) { BOOL bRet = FALSE; DCOBJ dco(hdc);
if (!dco.bValid()) { SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER); return(bRet); }
*pl_eMiterLimit = dco.pdc->l_eMiterLimit();
bRet = TRUE; return(bRet); }
/******************************Public*Routine******************************\
* NtGdiGetPath() * * Gets the path data. pcptPath will contain the number of points in the * path, even if the supplied buffer is too small. * * History: * 12-Sep-1991 -by- J. Andrew Goossen [andrewgo] * Wrote it. \**************************************************************************/
int APIENTRY NtGdiGetPath( HDC hdc, LPPOINT pptlBuf, LPBYTE pjTypes, int cptBuf ) { int cptPath = -1;
DCOBJ dco(hdc);
if (dco.bValid() && cptBuf >= 0) { if (dco.pdc->bInactive()) { EXFORMOBJ exfoDtoW(dco, DEVICE_TO_WORLD);
if (exfoDtoW.bValid()) { //
// We're not going to modify the path, so we don't have to worry
// about copying it if a SaveDC is pending:
//
XEPATHOBJ epath(dco.hpath()); ASSERTGDI(epath.bValid(), "Invalid DC path");
cptPath = (int) epath.cTotalPts();
//
// if cptBuf == 0, this is not an error. This is a request
// for the size of the path.
//
if (cptBuf != 0) { //
// Return an error if the buffer is too small:
//
// Note: sizeof(BYTE) < sizeof(POINT), so the single test
// suffices to check for overflow in both write
// probes; also, using MAXULONG instead of
// MAXIMUM_POOL_ALLOC because checking for overflow,
// not allocating memory
//
ASSERTGDI(sizeof(BYTE) <= sizeof(POINT), "NtGdiGetPath: bad overflow check\n");
if ((cptBuf >= cptPath) && (cptBuf <= (MAXULONG/sizeof(POINT)))) { PATHDATA pd; PBYTE pjEnd; BYTE jType; BOOL bMore;
epath.vEnumStart();
__try {
ProbeForWrite(pptlBuf, cptBuf * sizeof(POINT), sizeof(DWORD));
ProbeForWrite(pjTypes, cptBuf * sizeof(BYTE), sizeof(DWORD));
do {
bMore = epath.bEnum(&pd);
// We can get a zero point record if it's an empty path:
if (pd.count > 0) { // Copy points:
if (!exfoDtoW.bXform(pd.pptfx, (PPOINTL) pptlBuf, (SIZE_T) pd.count)) { SAVE_ERROR_CODE(ERROR_ARITHMETIC_OVERFLOW); cptPath = -1; break; }
pptlBuf += pd.count;
// Determine types:
pjEnd = pjTypes + pd.count;
// First point in a subpath is always a MoveTo:
if (pd.flags & PD_BEGINSUBPATH) { *pjTypes++ = PT_MOVETO; }
// Other points are LineTo's or BezierTo's:
jType = (pd.flags & PD_BEZIERS) ? (BYTE) PT_BEZIERTO : (BYTE) PT_LINETO;
while (pjTypes < pjEnd) { *pjTypes++ = jType; }
// Set CloseFigure bit for last point in a subpath:
if (pd.flags & PD_CLOSEFIGURE) { ASSERTGDI(pd.flags & PD_ENDSUBPATH, "Expected on last pd"); *(pjTypes - 1) |= PT_CLOSEFIGURE; } }
} while (bMore); } __except(EXCEPTION_EXECUTE_HANDLER) { // SetLastError(GetExceptionCode());
cptPath = -1; } } else { SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER); cptPath = -1; } } } else { SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER); } } else { SAVE_ERROR_CODE(ERROR_CAN_NOT_COMPLETE); } } else { SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER); }
return(cptPath); }
|