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.
1130 lines
29 KiB
1130 lines
29 KiB
/******************************Module*Header*******************************\
|
|
* Module Name: brushapi.cxx *
|
|
* *
|
|
* Contains all the various GDI versions of Brush creation. *
|
|
* *
|
|
* Created: 06-Nov-1990 14:46:03 *
|
|
* Author: Walt Moore [waltm] *
|
|
* *
|
|
* Copyright (c) 1990-1999 Microsoft Corporation *
|
|
\**************************************************************************/
|
|
|
|
#include "precomp.hxx"
|
|
#include "engline.hxx"
|
|
|
|
// Default wide-line style arrays:
|
|
|
|
ULONG gaulGeometricDot[] = { 1, 1 };
|
|
ULONG gaulGeometricDash[] = { 3, 1 };
|
|
ULONG gaulGeometricDashDot[] = { 3, 1, 1, 1 };
|
|
ULONG gaulGeometricDashDotDot[] = { 3, 1, 1, 1, 1, 1 };
|
|
|
|
// Default cosmetic style arrays (must all sum to 8):
|
|
|
|
LONG_FLOAT galeCosmeticDot[] = { {1}, {1}, {1}, {1},
|
|
{1}, {1}, {1}, {1} };
|
|
LONG_FLOAT galeCosmeticDash[] = { {6}, {2} };
|
|
LONG_FLOAT galeCosmeticDashDot[] = { {3}, {2}, {1}, {2} };
|
|
LONG_FLOAT galeCosmeticDashDotDot[] = { {3}, {1}, {1}, {1}, {1}, {1} };
|
|
|
|
|
|
/**************************************************************************\
|
|
* hCreateSolidBrushInternal(clrr, bPen)
|
|
*
|
|
* Creates a solid brush. Whether or not the brush is solid or dithered
|
|
* will depend on what mode the DC is in at realization time.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
HBRUSH
|
|
hCreateSolidBrushInternal(
|
|
COLORREF clrr,
|
|
BOOL bPen,
|
|
HBRUSH hbr,
|
|
BOOL bSharedMem)
|
|
{
|
|
HBRUSH hbrReturn = NULL;
|
|
|
|
if (hbr)
|
|
{
|
|
//
|
|
// If an already created brush is passed, just try to set it.
|
|
//
|
|
|
|
if (GreSetSolidBrushInternal(hbr,clrr,bPen,FALSE))
|
|
{
|
|
hbrReturn = hbr;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
BRUSHMEMOBJ brmo(clrr, HS_DITHEREDCLR, bPen, bSharedMem);
|
|
|
|
if (brmo.bValid())
|
|
{
|
|
brmo.vKeepIt();
|
|
brmo.vEnableDither();
|
|
|
|
hbrReturn = brmo.hbrush();
|
|
}
|
|
}
|
|
|
|
return hbrReturn;
|
|
}
|
|
|
|
|
|
/**************************************************************************\
|
|
* GreCreateSolidBrush()
|
|
*
|
|
\**************************************************************************/
|
|
|
|
HBRUSH
|
|
GreCreateSolidBrush(
|
|
COLORREF clrr)
|
|
{
|
|
return(hCreateSolidBrushInternal(clrr,FALSE,NULL,FALSE));
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* NtGdiCreateSolidBrush()
|
|
*
|
|
\**************************************************************************/
|
|
|
|
HBRUSH
|
|
APIENTRY
|
|
NtGdiCreateSolidBrush(
|
|
COLORREF cr,
|
|
HBRUSH hbr
|
|
)
|
|
{
|
|
HBRUSH hbrush;
|
|
|
|
hbrush = hCreateSolidBrushInternal(cr, FALSE, hbr, TRUE);
|
|
|
|
return (hbrush);
|
|
}
|
|
|
|
|
|
|
|
|
|
/**************************************************************************\
|
|
* hCreateHatchBrushInternal(ulStyle, clrr, bPen)
|
|
*
|
|
* Creates a hatch brush.
|
|
*
|
|
* History:
|
|
* 07-Jun-1995 -by- Andre Vachon [andreva]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
HBRUSH
|
|
hCreateHatchBrushInternal(
|
|
ULONG ulStyle,
|
|
COLORREF clrr,
|
|
BOOL bPen)
|
|
{
|
|
HBRUSH hbr = NULL;
|
|
|
|
if (ulStyle <= HS_API_MAX-1)
|
|
{
|
|
BRUSHMEMOBJ brmo(clrr, ulStyle, bPen, FALSE);
|
|
|
|
if (brmo.bValid())
|
|
{
|
|
brmo.vKeepIt();
|
|
hbr = brmo.hbrush();
|
|
}
|
|
}
|
|
|
|
|
|
return hbr;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* NtGdiCreateHatchBrushInternal(ulStyle, clrr, bPen)
|
|
*
|
|
\**************************************************************************/
|
|
|
|
|
|
HBRUSH
|
|
APIENTRY
|
|
NtGdiCreateHatchBrushInternal(
|
|
ULONG ulStyle,
|
|
COLORREF cr,
|
|
BOOL bPen
|
|
)
|
|
{
|
|
HBRUSH hbrush;
|
|
|
|
hbrush = hCreateHatchBrushInternal (ulStyle, cr, bPen);
|
|
|
|
return (hbrush);
|
|
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* NtGdiCreatePatternBrushInternal()
|
|
*
|
|
* History:
|
|
* 01-Nov-1994 -by- Eric Kutter [erick]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
HBRUSH
|
|
APIENTRY
|
|
NtGdiCreatePatternBrushInternal(
|
|
HBITMAP hbm,
|
|
BOOL bPen,
|
|
BOOL b8X8
|
|
)
|
|
{
|
|
HBRUSH hbrush;
|
|
|
|
hbrush = GreCreatePatternBrushInternal(hbm,bPen,b8X8);
|
|
|
|
return (hbrush);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* NtGdiCreateDIBBrush()
|
|
*
|
|
* History:
|
|
* 01-Nov-1994 -by- Eric Kutter [erick]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
HBRUSH
|
|
APIENTRY
|
|
NtGdiCreateDIBBrush(
|
|
PVOID pv,
|
|
FLONG fl,
|
|
UINT cj,
|
|
BOOL b8X8,
|
|
BOOL bPen,
|
|
PVOID pClient
|
|
)
|
|
{
|
|
HBRUSH hbrRet;
|
|
PVOID pvTmp;
|
|
|
|
pvTmp = AllocFreeTmpBuffer(cj);
|
|
|
|
if (pvTmp)
|
|
{
|
|
hbrRet = (HBRUSH)1;
|
|
|
|
__try
|
|
{
|
|
ProbeForRead(pv,cj, sizeof(BYTE));
|
|
RtlCopyMemory(pvTmp,pv,cj);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
// SetLastError(GetExceptionCode());
|
|
|
|
hbrRet = (HBRUSH)0;
|
|
}
|
|
|
|
if (hbrRet)
|
|
{
|
|
hbrRet = GreCreateDIBBrush(pvTmp,fl,cj,b8X8,bPen,pClient);
|
|
}
|
|
FreeTmpBuffer(pvTmp);
|
|
}
|
|
else
|
|
{
|
|
// SetLastError();
|
|
hbrRet = (HBRUSH)0;
|
|
}
|
|
|
|
return(hbrRet);
|
|
}
|
|
|
|
|
|
|
|
/**************************************************************************\
|
|
* GreCreatePatternBrushInternal(hbm, bPen)
|
|
*
|
|
* Creates a pattern brush from the bitmap passed in.
|
|
*
|
|
* History:
|
|
* Mon 24-Jun-1991 -by- Patrick Haluptzok [patrickh]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
HBRUSH GreCreatePatternBrushInternal(
|
|
HBITMAP hbm,
|
|
BOOL bPen,
|
|
BOOL b8X8)
|
|
{
|
|
HBRUSH hbrReturn = (HBRUSH) 0;
|
|
SURFREF SurfBmo((HSURF)hbm);
|
|
|
|
if (SurfBmo.bValid())
|
|
{
|
|
if (SurfBmo.ps->bApiBitmap())
|
|
{
|
|
HBITMAP hbmClone;
|
|
|
|
if (b8X8)
|
|
hbmClone = hbmCreateClone(SurfBmo.ps,8,8);
|
|
else
|
|
hbmClone = hbmCreateClone(SurfBmo.ps,0,0);
|
|
|
|
if (hbmClone != (HBITMAP) 0)
|
|
{
|
|
XEPALOBJ pal(SurfBmo.ps->ppal());
|
|
|
|
BRUSHMEMOBJ brmo(hbmClone, hbm, pal.bIsMonochrome(), DIB_RGB_COLORS,
|
|
BR_IS_BITMAP, bPen);
|
|
|
|
if (brmo.bValid())
|
|
{
|
|
hbrReturn = brmo.hbrush();
|
|
brmo.vKeepIt();
|
|
} // hmgr logs error code
|
|
} // hmgr logs error code
|
|
}
|
|
else
|
|
{
|
|
WARNING("GreCreatePatternBrushInternal: Invalid surface");
|
|
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
|
|
}
|
|
|
|
return(hbrReturn);
|
|
}
|
|
|
|
HBRUSH GreCreatePatternBrush(HBITMAP hbm)
|
|
{
|
|
return(GreCreatePatternBrushInternal(hbm,FALSE,FALSE));
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* GreCreateDIBBrush
|
|
*
|
|
* Creates a DIB pattern brush.
|
|
*
|
|
* History:
|
|
* 02-Jun-1991 -by- Patrick Haluptzok patrickh
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
HBRUSH
|
|
GreCreateDIBBrush(PVOID pv, FLONG fl, UINT cjMax, BOOL b8X8, BOOL bPen, PVOID pClient)
|
|
{
|
|
// Validate your parameters.
|
|
|
|
if ((pv == (PVOID) 0) ||
|
|
(cjMax < sizeof(BITMAPINFOHEADER)) ||
|
|
(((BITMAPINFOHEADER *) pv)->biSize > cjMax) ||
|
|
((fl != DIB_PAL_INDICES) &&
|
|
(fl != DIB_PAL_COLORS) &&
|
|
(fl != DIB_RGB_COLORS)))
|
|
{
|
|
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
|
return((HBRUSH) 0);
|
|
}
|
|
|
|
// Compute offset to the bits
|
|
|
|
UINT cjHeader = ((BITMAPINFOHEADER *) pv)->biSize;
|
|
PBYTE pjBits = ((PBYTE) pv) + cjHeader;
|
|
PUSHORT pusIndices;
|
|
UINT uiBits,cSize,uiCompression;
|
|
UINT cPalEntriesTotal;
|
|
LPBITMAPINFO pbmiTmp = NULL;
|
|
|
|
UINT cPalEntryMax;
|
|
|
|
uiBits = ((BITMAPINFOHEADER *) pv)->biBitCount;
|
|
|
|
pusIndices = (PUSHORT) pjBits;
|
|
|
|
cSize = sizeof(RGBQUAD);
|
|
|
|
cPalEntriesTotal = (UINT) ((BITMAPINFOHEADER *) pv)->biClrUsed;
|
|
|
|
uiCompression = ((BITMAPINFOHEADER *) pv)->biCompression;
|
|
|
|
// Check proper settings for compression.
|
|
if (uiCompression == BI_BITFIELDS)
|
|
{
|
|
cPalEntriesTotal = 3;
|
|
|
|
if (fl == DIB_PAL_COLORS)
|
|
fl = DIB_RGB_COLORS;
|
|
|
|
if ((uiBits != 16) && (uiBits != 32))
|
|
{
|
|
WARNING("CreateDIBPatternBrush given invalid data for BI_BITFIELDS\n");
|
|
return((HBRUSH) 0);
|
|
}
|
|
}
|
|
else if (uiCompression == BI_RGB)
|
|
{
|
|
switch(uiBits)
|
|
{
|
|
case 1:
|
|
cPalEntryMax = 2;
|
|
break;
|
|
case 4:
|
|
cPalEntryMax = 16;
|
|
break;
|
|
case 8:
|
|
cPalEntryMax = 256;
|
|
break;
|
|
case 16:
|
|
case 24:
|
|
case 32:
|
|
cPalEntryMax =
|
|
cPalEntriesTotal = 0;
|
|
|
|
// Win3.1 ignores the DIB_PAL_COLORS flag when non-indexed passed in.
|
|
|
|
if (fl == DIB_PAL_COLORS)
|
|
fl = DIB_RGB_COLORS;
|
|
|
|
break;
|
|
default:
|
|
WARNING("GreCreateDIBPatternBrushPt failed because of invalid bit count BI_RGB");
|
|
return((HBRUSH) 0);
|
|
}
|
|
|
|
if (cPalEntriesTotal == 0)
|
|
{
|
|
cPalEntriesTotal = cPalEntryMax;
|
|
}
|
|
else
|
|
cPalEntriesTotal = MIN(cPalEntryMax, cPalEntriesTotal);
|
|
}
|
|
else if (uiCompression == BI_RLE4)
|
|
{
|
|
if (uiBits != 4)
|
|
{
|
|
WARNING("CreateDIBrush RLE4 invalid bpp\n");
|
|
return((HBRUSH) 0);
|
|
}
|
|
|
|
if (cPalEntriesTotal == 0)
|
|
{
|
|
cPalEntriesTotal = 16;
|
|
}
|
|
}
|
|
else if (uiCompression == BI_RLE8)
|
|
{
|
|
if (uiBits != 8)
|
|
{
|
|
WARNING("CreateDIBrush RLE8 invalid bpp\n");
|
|
return((HBRUSH) 0);
|
|
}
|
|
|
|
if (cPalEntriesTotal == 0)
|
|
{
|
|
cPalEntriesTotal = 256;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// We don't support any other compressions for creating a brush on NT.
|
|
|
|
WARNING("Unknown Compression passed in - failed CreateDIBPatternBrush\n");
|
|
return((HBRUSH) 0);
|
|
}
|
|
|
|
// Check for the DIB_PAL_COLORS case.
|
|
|
|
if (fl == DIB_PAL_COLORS)
|
|
cSize = sizeof(USHORT);
|
|
else if (fl == DIB_PAL_INDICES)
|
|
cSize = 0;
|
|
|
|
// Validate that buffer is large enough to include color table. Guarantees
|
|
// that pjBits is within the bounds of the pv buffer passed in.
|
|
|
|
UINT cjColorTable = (((cSize * cPalEntriesTotal) + 3) & ~3);
|
|
|
|
if (cjColorTable > (cjMax - cjHeader))
|
|
{
|
|
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
|
return(0);
|
|
}
|
|
|
|
pjBits += cjColorTable; // now, pjBits = pv + cjHeader + cjColorTable
|
|
|
|
//
|
|
// Sundown: safe to truncate to INT since pjBits - pv will not exceed 4GB
|
|
// (validation above ensures that difference is <= cjMax)
|
|
//
|
|
|
|
INT cjBits = cjMax - (INT)(pjBits - (PBYTE)pv);
|
|
|
|
// Store the handle to bitmap just like a pattern brush, only mark
|
|
// it as a DIB.
|
|
|
|
HBITMAP hbmDIB;
|
|
|
|
FLONG flCreate = DIB_RGB_COLORS;
|
|
|
|
if (fl != DIB_RGB_COLORS)
|
|
{
|
|
flCreate = DIB_PAL_NONE;
|
|
}
|
|
|
|
|
|
hbmDIB = GreCreateDIBitmapReal(
|
|
(HDC) 0,
|
|
CBM_INIT | CBM_CREATEDIB,
|
|
pjBits,
|
|
(BITMAPINFO *)pv,
|
|
flCreate,
|
|
cjMax,
|
|
cjBits,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
CDBI_INTERNAL,
|
|
0,
|
|
NULL);
|
|
|
|
if (hbmDIB == (HBITMAP) 0)
|
|
{
|
|
WARNING("GreCreateDIBPatternBrush failed because GreCreateDIBitmap failed");
|
|
return((HBRUSH) 0);
|
|
}
|
|
|
|
if (b8X8)
|
|
{
|
|
SURFREF so((HSURF)hbmDIB);
|
|
ASSERTGDI(so.bValid(), "ERROR just created and already dead");
|
|
|
|
SIZEL sizlNew = so.ps->sizl();
|
|
|
|
if (so.ps->sizl().cx > 8)
|
|
{
|
|
sizlNew.cx = 8;
|
|
}
|
|
|
|
if (so.ps->sizl().cy > 8)
|
|
{
|
|
sizlNew.cy = 8;
|
|
}
|
|
|
|
so.ps->sizl(sizlNew);
|
|
}
|
|
|
|
// Now if we are creating a DIB_PAL_COLORS DIB brush we need to save the
|
|
// indices in the palette, so at runtime we can do the right thing.
|
|
|
|
if (fl == DIB_PAL_COLORS)
|
|
{
|
|
SURFREF so((HSURF)hbmDIB);
|
|
ASSERTGDI(so.bValid(), "ERROR GreCreateDIBBrush surface\n");
|
|
|
|
XEPALOBJ pal(so.ps->ppal());
|
|
|
|
pal.flPal(PAL_BRUSHHACK);
|
|
|
|
ASSERTGDI(pal.bValid(), "ERROR GreCreateDIBBrush pal.bValid\n");
|
|
ASSERTGDI(!pal.bIsPalDefault(), "ERROR GreCreateDIBBrush pal.bIsPal\n");
|
|
|
|
RtlCopyMemory((PUSHORT) pal.apalColorGet(), pusIndices,
|
|
cPalEntriesTotal << 1);
|
|
|
|
// Remember how big the color table is
|
|
|
|
pal.cColorTableLength(cPalEntriesTotal);
|
|
}
|
|
|
|
BRUSHMEMOBJ brmo(hbmDIB, (HBITMAP)pClient, FALSE, fl, BR_IS_DIB, bPen);
|
|
|
|
HBRUSH hbrRet;
|
|
|
|
if (brmo.bValid())
|
|
{
|
|
brmo.vKeepIt();
|
|
brmo.iUsage(fl);
|
|
hbrRet = brmo.hbrush();
|
|
}
|
|
else
|
|
{
|
|
bDeleteSurface((HSURF)hbmDIB);
|
|
hbrRet = (HBRUSH) 0;
|
|
}
|
|
|
|
return(hbrRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* GreMarkUndeletableBrush
|
|
*
|
|
* Private API for USER.
|
|
*
|
|
* Mark a Brush as undeletable. This must be called before the Brush is ever
|
|
* passed out to an application.
|
|
*
|
|
* History:
|
|
* 13-Sep-1991 -by- Patrick Haluptzok patrickh
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID GreMarkUndeletableBrush(HBRUSH hbr)
|
|
{
|
|
if(hbr == NULL)
|
|
{
|
|
WARNING("GreMarkUndeletableBrush called with NULL handle");
|
|
}
|
|
else if(!HmgMarkUndeletable((HOBJ)hbr, BRUSH_TYPE))
|
|
{
|
|
RIP("GreMarkUndeletableBrush failed to mark handle undeletable");
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* GreMarkDeletableBrush
|
|
*
|
|
* Private API for USER.
|
|
*
|
|
* This can be called anytime by USER to make the Brush deletable. We need
|
|
* to check they don't do this on our global objects.
|
|
*
|
|
* History:
|
|
* 13-Sep-1991 -by- Patrick Haluptzok patrickh
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID GreMarkDeletableBrush(HBRUSH hbr)
|
|
{
|
|
BRUSHSELOBJ bro(hbr);
|
|
|
|
if (bro.bValid())
|
|
{
|
|
if(!bro.bIsGlobal())
|
|
{
|
|
if (hbr == NULL)
|
|
{
|
|
WARNING("GreMarkDeletableBrush called with NULL handle");
|
|
}
|
|
else if (!HmgMarkDeletable((HOBJ)hbr,BRUSH_TYPE))
|
|
{
|
|
RIP("GreMarkDeletableBrush failed to mark handle deletable");
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("ERROR User gives Gdi invalid Brush");
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* GreCreatePen
|
|
*
|
|
* API creates a logical pen.
|
|
*
|
|
* History:
|
|
* 08-May-1991 -by- Patrick Haluptzok patrickh
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
HPEN GreCreatePen(int iPenStyle, int ulWidth, COLORREF clrr, HBRUSH hbr)
|
|
{
|
|
HPEN hRet = 0;
|
|
|
|
PW32THREAD pthread = W32GetCurrentThread();
|
|
|
|
ASSERTGDI(!hbr,"GreCreatePen - hbr\n");
|
|
|
|
switch(iPenStyle)
|
|
{
|
|
case PS_NULL:
|
|
case PS_SOLID:
|
|
case PS_DASH:
|
|
case PS_DOT:
|
|
case PS_DASHDOT:
|
|
case PS_DASHDOTDOT:
|
|
case PS_INSIDEFRAME:
|
|
break;
|
|
|
|
default:
|
|
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
|
return((HPEN) 0);
|
|
}
|
|
|
|
hRet = GreExtCreatePen(iPenStyle,
|
|
ulWidth,
|
|
BS_SOLID,
|
|
clrr,
|
|
0,
|
|
0,
|
|
0,
|
|
(PULONG) NULL,
|
|
0,
|
|
TRUE,
|
|
hbr);
|
|
|
|
return (hRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* GreExtCreatePen
|
|
*
|
|
* API creates an old-style or extended logical pen.
|
|
*
|
|
* History:
|
|
* 23-Jan-1992 -by- J. Andrew Goossen [andrewgo]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
HPEN GreExtCreatePen(
|
|
ULONG flPenStyle,
|
|
ULONG ulWidth,
|
|
ULONG iBrushStyle,
|
|
ULONG ulColor,
|
|
ULONG_PTR lClientHatch,
|
|
ULONG_PTR lHatch,
|
|
ULONG cstyle,
|
|
PULONG pulStyle,
|
|
ULONG cjDIB,
|
|
BOOL bOldStylePen,
|
|
HBRUSH hbrush)
|
|
{
|
|
BOOL bInvalidParm = FALSE;
|
|
BOOL bDefaultStyle = FALSE;
|
|
PFLOAT_LONG pstyle = (PFLOAT_LONG) NULL;
|
|
|
|
ULONG iType = flPenStyle & PS_TYPE_MASK;
|
|
ULONG ulStyle = flPenStyle & PS_STYLE_MASK;
|
|
ULONG iJoin;
|
|
ULONG iEndCap;
|
|
|
|
// We take the absoluate value of the integer width, like Win3 does:
|
|
|
|
LONG lWidthPen = ABS((LONG) ulWidth);
|
|
|
|
// Make sure no weird bits are set where none of our fields are:
|
|
|
|
if ((flPenStyle &
|
|
~(PS_TYPE_MASK | PS_STYLE_MASK | PS_ENDCAP_MASK | PS_JOIN_MASK)) != 0)
|
|
{
|
|
bInvalidParm = TRUE;
|
|
}
|
|
|
|
// Don't do any more parameter checking for NULL pens:
|
|
|
|
if (ulStyle == PS_NULL)
|
|
return(STOCKOBJ_NULLPEN);
|
|
|
|
// Do some more parameter checking.
|
|
|
|
switch(iType)
|
|
{
|
|
case PS_GEOMETRIC:
|
|
break;
|
|
case PS_COSMETIC:
|
|
if ((iBrushStyle == BS_SOLID) ||
|
|
((iBrushStyle == BS_HATCHED) &&
|
|
((lHatch == HS_SOLIDTEXTCLR) || (lHatch == HS_SOLIDBKCLR))))
|
|
{
|
|
break;
|
|
}
|
|
default:
|
|
bInvalidParm = TRUE;
|
|
}
|
|
|
|
if (lWidthPen != 1 && iType == PS_COSMETIC && !bOldStylePen)
|
|
{
|
|
bInvalidParm = TRUE;
|
|
}
|
|
|
|
switch(flPenStyle & PS_JOIN_MASK)
|
|
{
|
|
case PS_JOIN_ROUND: iJoin = JOIN_ROUND; break;
|
|
case PS_JOIN_BEVEL: iJoin = JOIN_BEVEL; break;
|
|
case PS_JOIN_MITER: iJoin = JOIN_MITER; break;
|
|
default:
|
|
bInvalidParm = TRUE;
|
|
}
|
|
|
|
switch(flPenStyle & PS_ENDCAP_MASK)
|
|
{
|
|
case PS_ENDCAP_ROUND: iEndCap = ENDCAP_ROUND; break;
|
|
case PS_ENDCAP_FLAT: iEndCap = ENDCAP_BUTT; break;
|
|
case PS_ENDCAP_SQUARE: iEndCap = ENDCAP_SQUARE; break;
|
|
default:
|
|
bInvalidParm = TRUE;
|
|
}
|
|
|
|
// Zero length array allowed iff not doing a user-supplied style,
|
|
// and aribtrarily limit the style array size:
|
|
|
|
if ((ulStyle == PS_USERSTYLE && cstyle == 0) ||
|
|
(ulStyle != PS_USERSTYLE && cstyle != 0) ||
|
|
cstyle > STYLE_MAX_COUNT)
|
|
{
|
|
bInvalidParm = TRUE;
|
|
}
|
|
|
|
if (iType == PS_GEOMETRIC)
|
|
{
|
|
switch(ulStyle)
|
|
{
|
|
case PS_DOT:
|
|
cstyle = sizeof(gaulGeometricDot) / sizeof(ULONG);
|
|
pulStyle = gaulGeometricDot;
|
|
break;
|
|
case PS_DASH:
|
|
cstyle = sizeof(gaulGeometricDash) / sizeof(ULONG);
|
|
pulStyle = gaulGeometricDash;
|
|
break;
|
|
case PS_DASHDOT:
|
|
cstyle = sizeof(gaulGeometricDashDot) / sizeof(ULONG);
|
|
pulStyle = gaulGeometricDashDot;
|
|
break;
|
|
case PS_DASHDOTDOT:
|
|
cstyle = sizeof(gaulGeometricDashDotDot) / sizeof(ULONG);
|
|
pulStyle = gaulGeometricDashDotDot;
|
|
break;
|
|
case PS_USERSTYLE:
|
|
case PS_SOLID:
|
|
break;
|
|
case PS_INSIDEFRAME:
|
|
break;
|
|
case PS_ALTERNATE:
|
|
default:
|
|
bInvalidParm = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch(ulStyle)
|
|
{
|
|
case PS_DOT:
|
|
cstyle = sizeof(galeCosmeticDot) / sizeof(LONG_FLOAT);
|
|
pstyle = &galeCosmeticDot[0].el;
|
|
bDefaultStyle = TRUE;
|
|
break;
|
|
case PS_DASH:
|
|
cstyle = sizeof(galeCosmeticDash) / sizeof(LONG_FLOAT);
|
|
pstyle = &galeCosmeticDash[0].el;
|
|
bDefaultStyle = TRUE;
|
|
break;
|
|
case PS_DASHDOT:
|
|
cstyle = sizeof(galeCosmeticDashDot) / sizeof(LONG_FLOAT);
|
|
pstyle = &galeCosmeticDashDot[0].el;
|
|
bDefaultStyle = TRUE;
|
|
break;
|
|
case PS_DASHDOTDOT:
|
|
cstyle = sizeof(galeCosmeticDashDotDot) / sizeof(LONG_FLOAT);
|
|
pstyle = &galeCosmeticDashDotDot[0].el;
|
|
bDefaultStyle = TRUE;
|
|
break;
|
|
case PS_USERSTYLE:
|
|
case PS_SOLID:
|
|
break;
|
|
case PS_ALTERNATE:
|
|
break;
|
|
case PS_INSIDEFRAME:
|
|
|
|
// Don't allow PS_INSIDEFRAME with new style cosmetic pens:
|
|
|
|
if (!bOldStylePen)
|
|
bInvalidParm = TRUE;
|
|
break;
|
|
default:
|
|
bInvalidParm = TRUE;
|
|
}
|
|
}
|
|
|
|
if (bInvalidParm)
|
|
{
|
|
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
|
return((HPEN) 0);
|
|
}
|
|
|
|
if (cstyle > 0 && pstyle == (PFLOAT_LONG) NULL)
|
|
{
|
|
pstyle = (PFLOAT_LONG) PALLOCNOZ(cstyle * sizeof(FLOAT_LONG),'ytsG');
|
|
if (pstyle == (PFLOAT_LONG) NULL)
|
|
{
|
|
SAVE_ERROR_CODE(ERROR_NOT_ENOUGH_MEMORY);
|
|
return((HPEN) 0);
|
|
}
|
|
|
|
PFLOAT_LONG ple = pstyle;
|
|
PFLOAT_LONG pleEnd = ple + cstyle;
|
|
|
|
if (iType == PS_COSMETIC || bOldStylePen)
|
|
{
|
|
// Handle cosmetic styles:
|
|
|
|
LONG lMin = 1;
|
|
LONG lMax = 1;
|
|
LONG lSum = 0;
|
|
|
|
while (ple < pleEnd)
|
|
{
|
|
ple->l = (LONG) *pulStyle;
|
|
lMin = MIN(lMin, ple->l);
|
|
lMax = MAX(lMax, ple->l);
|
|
lSum += ple->l;
|
|
|
|
pulStyle++;
|
|
ple++;
|
|
}
|
|
|
|
if (lMin <= 0 || lMax > STYLE_MAX_VALUE || lSum > STYLE_MAX_VALUE)
|
|
bInvalidParm = TRUE;
|
|
}
|
|
else
|
|
{
|
|
// Handle geometric styles:
|
|
|
|
LONG lSum = 0;
|
|
LONG lMin = 0;
|
|
while (ple < pleEnd)
|
|
{
|
|
LONG lLength = (LONG) *pulStyle;
|
|
|
|
// Default styles are based on multiples of the pen width:
|
|
|
|
if (ulStyle != PS_USERSTYLE)
|
|
{
|
|
// For round and square caps, shorten dashes and lengthen
|
|
// the gaps:
|
|
|
|
if (iEndCap != ENDCAP_BUTT)
|
|
lLength += ((ple - pstyle) & 1) ? 1 : -1;
|
|
|
|
// Don't really care about overflow on this multiplication:
|
|
|
|
lLength *= lWidthPen;
|
|
}
|
|
|
|
lMin = MIN(lMin, lLength);
|
|
lSum += lLength;
|
|
|
|
EFLOATEXT efLength(lLength);
|
|
efLength.vEfToF(ple->e);
|
|
|
|
pulStyle++;
|
|
ple++;
|
|
}
|
|
|
|
if (lMin < 0 || lSum <= 0)
|
|
bInvalidParm = TRUE;
|
|
}
|
|
|
|
if (bInvalidParm)
|
|
{
|
|
// At least one entry in the style array has to be non-zero:
|
|
|
|
VFREEMEM(pstyle);
|
|
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
|
return((HPEN) 0);
|
|
}
|
|
}
|
|
|
|
HBRUSH hbr = 0;
|
|
|
|
switch(iBrushStyle)
|
|
{
|
|
case BS_HOLLOW:
|
|
if (pstyle != (PFLOAT_LONG) NULL && !bDefaultStyle)
|
|
VFREEMEM(pstyle);
|
|
|
|
return(STOCKOBJ_NULLPEN);
|
|
|
|
case BS_SOLID:
|
|
hbr = hCreateSolidBrushInternal(ulColor,
|
|
TRUE,
|
|
hbrush,
|
|
(lWidthPen == 0) && (ulStyle == PS_SOLID));
|
|
break;
|
|
|
|
case BS_HATCHED:
|
|
hbr = hCreateHatchBrushInternal((ULONG) lHatch, ulColor, TRUE);
|
|
break;
|
|
|
|
case BS_PATTERN:
|
|
hbr = GreCreatePatternBrushInternal((HBITMAP) lHatch, TRUE,FALSE);
|
|
break;
|
|
|
|
case BS_DIBPATTERNPT:
|
|
hbr = GreCreateDIBBrush((PVOID) lHatch, ulColor,
|
|
(UINT) cjDIB, FALSE, TRUE, (PVOID)lClientHatch);
|
|
break;
|
|
|
|
case BS_DIBPATTERN:
|
|
RIP("BS_DIBPATTERN not supported in server");
|
|
|
|
default:
|
|
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
if (hbr == (HBRUSH) 0)
|
|
{
|
|
if (pstyle != (PFLOAT_LONG) NULL && !bDefaultStyle)
|
|
VFREEMEM(pstyle);
|
|
|
|
return((HPEN) 0);
|
|
}
|
|
|
|
BRUSHSELOBJ bso(hbr);
|
|
|
|
// we had better validate this since it is just a handle, it could already
|
|
// have been deleted.
|
|
|
|
if (!bso.bValid())
|
|
{
|
|
WARNING("Created invalid pen\n");
|
|
|
|
if (pstyle != (PFLOAT_LONG) NULL && !bDefaultStyle)
|
|
VFREEMEM(pstyle);
|
|
|
|
return((HPEN)0);
|
|
}
|
|
|
|
bso.vSetPen();
|
|
bso.flStylePen(flPenStyle);
|
|
bso.iEndCap(iEndCap);
|
|
bso.iJoin(iJoin);
|
|
bso.pstyle(pstyle);
|
|
bso.cstyle(cstyle);
|
|
bso.lWidthPen(lWidthPen);
|
|
if (bDefaultStyle)
|
|
bso.vSetDefaultStyle();
|
|
bso.lBrushStyle (iBrushStyle);
|
|
bso.lHatch (lClientHatch);
|
|
|
|
if (iType == PS_GEOMETRIC || bOldStylePen)
|
|
{
|
|
// Geometric line widths are FLOATs in the LINEATTRS structure, so
|
|
// we have to keep a FLOAT version of its width around too:
|
|
|
|
EFLOATEXT efWidth(lWidthPen);
|
|
FLOATL l_eWidth;
|
|
|
|
efWidth.vEfToF(l_eWidth);
|
|
bso.l_eWidthPen(l_eWidth);
|
|
}
|
|
|
|
// we need to add the pen/extpen bits to handle type for the client
|
|
|
|
HBRUSH hbrPen = (HBRUSH) MODIFY_HMGR_TYPE(hbr,LO_EXTPEN_TYPE);
|
|
|
|
if (bOldStylePen)
|
|
{
|
|
bso.vSetOldStylePen();
|
|
bso.vDisableDither();
|
|
if (ulStyle == PS_INSIDEFRAME)
|
|
{
|
|
bso.vEnableDither();
|
|
bso.vSetInsideFrame();
|
|
}
|
|
hbrPen = (HBRUSH) MODIFY_HMGR_TYPE(hbr,LO_PEN_TYPE);
|
|
}
|
|
else if (iType == PS_COSMETIC)
|
|
{
|
|
// For now, cosmetic lines must also be solid colored:
|
|
|
|
bso.vDisableDither();
|
|
}
|
|
else
|
|
{
|
|
// We also support inside frame for geometric ExtCreatePen pens:
|
|
|
|
if (ulStyle == PS_INSIDEFRAME)
|
|
{
|
|
bso.vSetInsideFrame();
|
|
}
|
|
}
|
|
|
|
// we now set the new pen handle type. This must be done while the pen is locked
|
|
|
|
HmgModifyHandleType((HOBJ)hbrPen);
|
|
|
|
ASSERTGDI(!bInvalidParm, "Invalid parm?");
|
|
return((HPEN) hbrPen);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* GreCreatePenIndirect
|
|
*
|
|
* API creates a logical pen.
|
|
*
|
|
* History:
|
|
* 08-May-1991 -by- Patrick Haluptzok patrickh
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
HPEN GreCreatePenIndirect(LPLOGPEN lpLogPen)
|
|
{
|
|
return(GreCreatePen((int)lpLogPen->lopnStyle,
|
|
(int)lpLogPen->lopnWidth.x,
|
|
lpLogPen->lopnColor,0));
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* GreMonoBitmap
|
|
*
|
|
* Is the specified bitmap monochromatic?
|
|
*
|
|
* History:
|
|
* 18-Mar-1992 -by- Donald Sidoroff [donalds]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL NtGdiMonoBitmap(HBITMAP hbm)
|
|
{
|
|
SURFREF SurfBmo((HSURF)hbm);
|
|
|
|
if (!SurfBmo.bValid())
|
|
return(FALSE);
|
|
|
|
XEPALOBJ pal(SurfBmo.ps->ppal());
|
|
return(pal.bIsMonochrome());
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* GreGetObjectBitmapHandle
|
|
*
|
|
* Gets the handle of the bitmap associated with this brush
|
|
*
|
|
* History:
|
|
* 09-Mar-1992 -by- Donald Sidoroff [donalds]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
HBITMAP GreGetObjectBitmapHandle(
|
|
HBRUSH hbr,
|
|
UINT *piUsage)
|
|
{
|
|
BRUSHSELOBJ ebo(hbr);
|
|
|
|
if (!ebo.bValid())
|
|
{
|
|
return((HBITMAP) 0);
|
|
}
|
|
|
|
HBITMAP hbm = ebo.hbmPattern();
|
|
|
|
if (ebo.bPalColors())
|
|
{
|
|
*piUsage = DIB_PAL_COLORS;
|
|
}
|
|
else if (ebo.bPalIndices())
|
|
{
|
|
*piUsage = DIB_PAL_INDICES;
|
|
}
|
|
else
|
|
{
|
|
*piUsage = DIB_RGB_COLORS;
|
|
}
|
|
|
|
return(hbm);
|
|
}
|