2 * ReactOS Win32 Subsystem
4 * Copyright (C) 1998 - 2004 ReactOS Team
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
28 /* PRIVATE FUNCTIONS **********************************************************/
32 PEN_LockPen(HGDIOBJ hBMObj
)
34 if (GDI_HANDLE_GET_TYPE(hBMObj
) == GDI_OBJECT_TYPE_EXTPEN
)
35 return GDIOBJ_LockObj( hBMObj
, GDI_OBJECT_TYPE_EXTPEN
);
37 return GDIOBJ_LockObj( hBMObj
, GDI_OBJECT_TYPE_PEN
);
42 PEN_ShareLockPen(HGDIOBJ hBMObj
)
44 if (GDI_HANDLE_GET_TYPE(hBMObj
) == GDI_OBJECT_TYPE_EXTPEN
)
45 return GDIOBJ_ShareLockObj( hBMObj
, GDI_OBJECT_TYPE_EXTPEN
);
47 return GDIOBJ_ShareLockObj( hBMObj
, GDI_OBJECT_TYPE_PEN
);
54 IN ULONG ulBrushStyle
,
56 IN ULONG_PTR ulClientHatch
,
62 IN OPTIONAL HBRUSH hbrush
)
66 static const BYTE PatternAlternate
[] = {0x55, 0x55, 0x55};
67 static const BYTE PatternDash
[] = {0xFF, 0xFF, 0xC0};
68 static const BYTE PatternDot
[] = {0xE3, 0x8E, 0x38};
69 static const BYTE PatternDashDot
[] = {0xFF, 0x81, 0xC0};
70 static const BYTE PatternDashDotDot
[] = {0xFF, 0x8E, 0x38};
72 dwWidth
= abs(dwWidth
);
74 if ( (dwPenStyle
& PS_STYLE_MASK
) == PS_NULL
)
76 return StockObjects
[NULL_PEN
];
81 pbrushPen
= PEN_AllocPenWithHandle();
85 pbrushPen
= PEN_AllocExtPenWithHandle();
90 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
91 DPRINT("Can't allocate pen\n");
94 hPen
= pbrushPen
->BaseObject
.hHmgr
;
96 // If nWidth is zero, the pen is a single pixel wide, regardless of the current transformation.
97 if ((bOldStylePen
) && (!dwWidth
) && (dwPenStyle
& PS_STYLE_MASK
) != PS_SOLID
)
100 pbrushPen
->ptPenWidth
.x
= dwWidth
;
101 pbrushPen
->ptPenWidth
.y
= 0;
102 pbrushPen
->ulPenStyle
= dwPenStyle
;
103 pbrushPen
->BrushAttr
.lbColor
= ulColor
;
104 pbrushPen
->ulStyle
= ulBrushStyle
;
105 // FIXME: copy the bitmap first ?
106 pbrushPen
->hbmClient
= (HANDLE
)ulClientHatch
;
107 pbrushPen
->dwStyleCount
= dwStyleCount
;
108 pbrushPen
->pStyle
= pStyle
;
110 pbrushPen
->flAttrs
= bOldStylePen
? GDIBRUSH_IS_OLDSTYLEPEN
: GDIBRUSH_IS_PEN
;
112 // If dwPenStyle is PS_COSMETIC, the width must be set to 1.
113 if ( !(bOldStylePen
) && ((dwPenStyle
& PS_TYPE_MASK
) == PS_COSMETIC
) && ( dwWidth
!= 1) )
116 switch (dwPenStyle
& PS_STYLE_MASK
)
119 pbrushPen
->flAttrs
|= GDIBRUSH_IS_NULL
;
123 pbrushPen
->flAttrs
|= GDIBRUSH_IS_SOLID
;
127 pbrushPen
->flAttrs
|= GDIBRUSH_IS_BITMAP
;
128 pbrushPen
->hbmPattern
= IntGdiCreateBitmap(24, 1, 1, 1, (LPBYTE
)PatternAlternate
);
132 pbrushPen
->flAttrs
|= GDIBRUSH_IS_BITMAP
;
133 pbrushPen
->hbmPattern
= IntGdiCreateBitmap(24, 1, 1, 1, (LPBYTE
)PatternDot
);
137 pbrushPen
->flAttrs
|= GDIBRUSH_IS_BITMAP
;
138 pbrushPen
->hbmPattern
= IntGdiCreateBitmap(24, 1, 1, 1, (LPBYTE
)PatternDash
);
142 pbrushPen
->flAttrs
|= GDIBRUSH_IS_BITMAP
;
143 pbrushPen
->hbmPattern
= IntGdiCreateBitmap(24, 1, 1, 1, (LPBYTE
)PatternDashDot
);
147 pbrushPen
->flAttrs
|= GDIBRUSH_IS_BITMAP
;
148 pbrushPen
->hbmPattern
= IntGdiCreateBitmap(24, 1, 1, 1, (LPBYTE
)PatternDashDotDot
);
152 pbrushPen
->flAttrs
|= (GDIBRUSH_IS_SOLID
|GDIBRUSH_IS_INSIDEFRAME
);
156 if ((dwPenStyle
& PS_TYPE_MASK
) == PS_COSMETIC
)
158 /* FIXME: PS_USERSTYLE workaround */
159 DPRINT1("PS_COSMETIC | PS_USERSTYLE not handled\n");
160 pbrushPen
->flAttrs
|= GDIBRUSH_IS_SOLID
;
166 BOOL has_neg
= FALSE
, all_zero
= TRUE
;
168 for(i
= 0; (i
< dwStyleCount
) && !has_neg
; i
++)
170 has_neg
= has_neg
|| (((INT
)(pStyle
[i
])) < 0);
171 all_zero
= all_zero
&& (pStyle
[i
] == 0);
174 if(all_zero
|| has_neg
)
179 /* FIXME: what style here? */
180 pbrushPen
->flAttrs
|= 0;
184 DPRINT1("IntGdiExtCreatePen unknown penstyle %x\n", dwPenStyle
);
186 PEN_UnlockPen(pbrushPen
);
190 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
191 pbrushPen
->pStyle
= NULL
;
192 PEN_UnlockPen(pbrushPen
);
194 PEN_FreePenByHandle(hPen
);
196 PEN_FreeExtPenByHandle(hPen
);
201 IntGdiSetSolidPenColor(HPEN hPen
, COLORREF Color
)
205 pbrushPen
= PEN_LockPen(hPen
);
208 if (pbrushPen
->flAttrs
& GDIBRUSH_IS_SOLID
)
210 pbrushPen
->BrushAttr
.lbColor
= Color
& 0xFFFFFF;
212 PEN_UnlockPen(pbrushPen
);
217 PEN_GetObject(PBRUSH pbrushPen
, INT cbCount
, PLOGPEN pBuffer
)
220 PEXTLOGPEN pExtLogPen
;
223 if (pbrushPen
->flAttrs
& GDIBRUSH_IS_OLDSTYLEPEN
)
225 cbRetCount
= sizeof(LOGPEN
);
229 if (cbCount
< cbRetCount
) return 0;
231 if ( (pbrushPen
->ulPenStyle
& PS_STYLE_MASK
) == PS_NULL
&&
232 cbCount
== sizeof(EXTLOGPEN
))
234 pExtLogPen
= (PEXTLOGPEN
)pBuffer
;
235 pExtLogPen
->elpPenStyle
= pbrushPen
->ulPenStyle
;
236 pExtLogPen
->elpWidth
= 0;
237 pExtLogPen
->elpBrushStyle
= pbrushPen
->ulStyle
;
238 pExtLogPen
->elpColor
= pbrushPen
->BrushAttr
.lbColor
;
239 pExtLogPen
->elpHatch
= 0;
240 pExtLogPen
->elpNumEntries
= 0;
241 cbRetCount
= sizeof(EXTLOGPEN
);
245 pLogPen
= (PLOGPEN
)pBuffer
;
246 pLogPen
->lopnWidth
= pbrushPen
->ptPenWidth
;
247 pLogPen
->lopnStyle
= pbrushPen
->ulPenStyle
;
248 pLogPen
->lopnColor
= pbrushPen
->BrushAttr
.lbColor
;
254 // FIXME: Can we trust in dwStyleCount being <= 16?
255 cbRetCount
= sizeof(EXTLOGPEN
) - sizeof(DWORD
) + pbrushPen
->dwStyleCount
* sizeof(DWORD
);
260 if (cbCount
< cbRetCount
) return 0;
261 pExtLogPen
= (PEXTLOGPEN
)pBuffer
;
262 pExtLogPen
->elpPenStyle
= pbrushPen
->ulPenStyle
;
263 pExtLogPen
->elpWidth
= pbrushPen
->ptPenWidth
.x
;
264 pExtLogPen
->elpBrushStyle
= pbrushPen
->ulStyle
;
265 pExtLogPen
->elpColor
= pbrushPen
->BrushAttr
.lbColor
;
266 pExtLogPen
->elpHatch
= (ULONG_PTR
)pbrushPen
->hbmClient
;
267 pExtLogPen
->elpNumEntries
= pbrushPen
->dwStyleCount
;
268 for (i
= 0; i
< pExtLogPen
->elpNumEntries
; i
++)
270 pExtLogPen
->elpStyleEntry
[i
] = pbrushPen
->pStyle
[i
];
279 /* PUBLIC FUNCTIONS ***********************************************************/
288 if ( PenStyle
< PS_SOLID
|| PenStyle
> PS_INSIDEFRAME
)
290 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
294 return IntGdiExtCreatePen(PenStyle
,
311 IN ULONG ulBrushStyle
,
313 IN ULONG_PTR ulClientHatch
,
314 IN ULONG_PTR ulHatch
,
318 IN BOOL bOldStylePen
,
319 IN OPTIONAL HBRUSH hBrush
)
321 NTSTATUS Status
= STATUS_SUCCESS
;
322 DWORD
* pSafeStyle
= NULL
;
325 if ((int)dwStyleCount
< 0) return 0;
326 if (dwStyleCount
> 16)
328 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
332 if (dwStyleCount
> 0)
334 pSafeStyle
= ExAllocatePoolWithTag(NonPagedPool
, dwStyleCount
* sizeof(DWORD
), TAG_PENSTYLES
);
337 SetLastNtError(ERROR_NOT_ENOUGH_MEMORY
);
342 ProbeForRead(pUnsafeStyle
, dwStyleCount
* sizeof(DWORD
), 1);
343 RtlCopyMemory(pSafeStyle
,
345 dwStyleCount
* sizeof(DWORD
));
347 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
349 Status
= _SEH2_GetExceptionCode();
352 if(!NT_SUCCESS(Status
))
354 SetLastNtError(Status
);
355 ExFreePoolWithTag(pSafeStyle
, TAG_PENSTYLES
);
360 if (ulBrushStyle
== BS_PATTERN
)
364 ProbeForRead((PVOID
)ulHatch
, cjDIB
, 1);
366 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
368 Status
= _SEH2_GetExceptionCode();
371 if(!NT_SUCCESS(Status
))
373 SetLastNtError(Status
);
374 if (pSafeStyle
) ExFreePoolWithTag(pSafeStyle
, TAG_PENSTYLES
);
379 hPen
= IntGdiExtCreatePen(dwPenStyle
,
391 if (!hPen
&& pSafeStyle
)
393 ExFreePoolWithTag(pSafeStyle
, TAG_PENSTYLES
);