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.
873 lines
22 KiB
873 lines
22 KiB
/******************************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);
|
|
}
|