Synchronize with trunk's revision r57629.
[reactos.git] / win32ss / gdi / ntgdi / pen.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Pen functiona
5 * FILE: subsys/win32k/objects/pen.c
6 * PROGRAMER:
7 */
8
9 #include <win32k.h>
10
11 #define NDEBUG
12 #include <debug.h>
13
14 /* PRIVATE FUNCTIONS **********************************************************/
15
16 PBRUSH
17 FASTCALL
18 PEN_ShareLockPen(HGDIOBJ hobj)
19 {
20 if (GDI_HANDLE_GET_TYPE(hobj) != GDILoObjType_LO_PEN_TYPE &&
21 GDI_HANDLE_GET_TYPE(hobj) != GDILoObjType_LO_EXTPEN_TYPE)
22 {
23 return NULL;
24 }
25
26 return (PBRUSH)GDIOBJ_ReferenceObjectByHandle(hobj, GDIObjType_BRUSH_TYPE);
27 }
28
29 HPEN APIENTRY
30 IntGdiExtCreatePen(
31 DWORD dwPenStyle,
32 DWORD dwWidth,
33 IN ULONG ulBrushStyle,
34 IN ULONG ulColor,
35 IN ULONG_PTR ulClientHatch,
36 IN ULONG_PTR ulHatch,
37 DWORD dwStyleCount,
38 PULONG pStyle,
39 IN ULONG cjDIB,
40 IN BOOL bOldStylePen,
41 IN OPTIONAL HBRUSH hbrush)
42 {
43 HPEN hPen;
44 PBRUSH pbrushPen;
45 static const BYTE PatternAlternate[] = {0x55, 0x55, 0x55, 0};
46 static const BYTE PatternDash[] = {0xFF, 0xFF, 0xC0, 0};
47 static const BYTE PatternDot[] = {0xE3, 0x8E, 0x38, 0};
48 static const BYTE PatternDashDot[] = {0xFF, 0x81, 0xC0, 0};
49 static const BYTE PatternDashDotDot[] = {0xFF, 0x8E, 0x38, 0};
50
51 dwWidth = abs(dwWidth);
52
53 if ( (dwPenStyle & PS_STYLE_MASK) == PS_NULL)
54 {
55 return StockObjects[NULL_PEN];
56 }
57
58 if (bOldStylePen)
59 {
60 pbrushPen = PEN_AllocPenWithHandle();
61 }
62 else
63 {
64 pbrushPen = PEN_AllocExtPenWithHandle();
65 }
66
67 if (!pbrushPen)
68 {
69 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
70 DPRINT("Can't allocate pen\n");
71 return 0;
72 }
73 hPen = pbrushPen->BaseObject.hHmgr;
74
75 // If nWidth is zero, the pen is a single pixel wide, regardless of the current transformation.
76 if ((bOldStylePen) && (!dwWidth) && (dwPenStyle & PS_STYLE_MASK) != PS_SOLID)
77 dwWidth = 1;
78
79 pbrushPen->ptPenWidth.x = dwWidth;
80 pbrushPen->ptPenWidth.y = 0;
81 pbrushPen->ulPenStyle = dwPenStyle;
82 pbrushPen->BrushAttr.lbColor = ulColor;
83 pbrushPen->ulStyle = ulBrushStyle;
84 // FIXME: Copy the bitmap first ?
85 pbrushPen->hbmClient = (HANDLE)ulClientHatch;
86 pbrushPen->dwStyleCount = dwStyleCount;
87 pbrushPen->pStyle = pStyle;
88
89 pbrushPen->flAttrs = bOldStylePen? BR_IS_OLDSTYLEPEN : BR_IS_PEN;
90
91 // If dwPenStyle is PS_COSMETIC, the width must be set to 1.
92 if ( !(bOldStylePen) && ((dwPenStyle & PS_TYPE_MASK) == PS_COSMETIC) && ( dwWidth != 1) )
93 goto ExitCleanup;
94
95 switch (dwPenStyle & PS_STYLE_MASK)
96 {
97 case PS_NULL:
98 pbrushPen->flAttrs |= BR_IS_NULL;
99 break;
100
101 case PS_SOLID:
102 pbrushPen->flAttrs |= BR_IS_SOLID;
103 break;
104
105 case PS_ALTERNATE:
106 pbrushPen->flAttrs |= BR_IS_BITMAP;
107 pbrushPen->hbmPattern = GreCreateBitmap(24, 1, 1, 1, (LPBYTE)PatternAlternate);
108 break;
109
110 case PS_DOT:
111 pbrushPen->flAttrs |= BR_IS_BITMAP;
112 pbrushPen->hbmPattern = GreCreateBitmap(24, 1, 1, 1, (LPBYTE)PatternDot);
113 break;
114
115 case PS_DASH:
116 pbrushPen->flAttrs |= BR_IS_BITMAP;
117 pbrushPen->hbmPattern = GreCreateBitmap(24, 1, 1, 1, (LPBYTE)PatternDash);
118 break;
119
120 case PS_DASHDOT:
121 pbrushPen->flAttrs |= BR_IS_BITMAP;
122 pbrushPen->hbmPattern = GreCreateBitmap(24, 1, 1, 1, (LPBYTE)PatternDashDot);
123 break;
124
125 case PS_DASHDOTDOT:
126 pbrushPen->flAttrs |= BR_IS_BITMAP;
127 pbrushPen->hbmPattern = GreCreateBitmap(24, 1, 1, 1, (LPBYTE)PatternDashDotDot);
128 break;
129
130 case PS_INSIDEFRAME:
131 pbrushPen->flAttrs |= (BR_IS_SOLID|BR_IS_INSIDEFRAME);
132 break;
133
134 case PS_USERSTYLE:
135 if ((dwPenStyle & PS_TYPE_MASK) == PS_COSMETIC)
136 {
137 /* FIXME: PS_USERSTYLE workaround */
138 DPRINT1("PS_COSMETIC | PS_USERSTYLE not handled\n");
139 pbrushPen->flAttrs |= BR_IS_SOLID;
140 break;
141 }
142 else
143 {
144 UINT i;
145 BOOL has_neg = FALSE, all_zero = TRUE;
146
147 for(i = 0; (i < dwStyleCount) && !has_neg; i++)
148 {
149 has_neg = has_neg || (((INT)(pStyle[i])) < 0);
150 all_zero = all_zero && (pStyle[i] == 0);
151 }
152
153 if(all_zero || has_neg)
154 {
155 goto ExitCleanup;
156 }
157 }
158 /* FIXME: What style here? */
159 pbrushPen->flAttrs |= 0;
160 break;
161
162 default:
163 DPRINT1("IntGdiExtCreatePen unknown penstyle %x\n", dwPenStyle);
164 }
165 PEN_UnlockPen(pbrushPen);
166 return hPen;
167
168 ExitCleanup:
169 EngSetLastError(ERROR_INVALID_PARAMETER);
170 pbrushPen->pStyle = NULL;
171 GDIOBJ_vDeleteObject(&pbrushPen->BaseObject);
172 return NULL;
173 }
174
175 VOID FASTCALL
176 IntGdiSetSolidPenColor(HPEN hPen, COLORREF Color)
177 {
178 PBRUSH pbrPen;
179
180 pbrPen = PEN_ShareLockPen(hPen);
181 if (pbrPen)
182 {
183 if (pbrPen->flAttrs & BR_IS_SOLID)
184 {
185 pbrPen->BrushAttr.lbColor = Color & 0xFFFFFF;
186 }
187 PEN_ShareUnlockPen(pbrPen);
188 }
189 }
190
191 INT APIENTRY
192 PEN_GetObject(PBRUSH pbrushPen, INT cbCount, PLOGPEN pBuffer)
193 {
194 PLOGPEN pLogPen;
195 PEXTLOGPEN pExtLogPen;
196 INT cbRetCount;
197
198 if (pbrushPen->flAttrs & BR_IS_OLDSTYLEPEN)
199 {
200 cbRetCount = sizeof(LOGPEN);
201 if (pBuffer)
202 {
203
204 if (cbCount < cbRetCount) return 0;
205
206 if ( (pbrushPen->ulPenStyle & PS_STYLE_MASK) == PS_NULL &&
207 cbCount == sizeof(EXTLOGPEN))
208 {
209 pExtLogPen = (PEXTLOGPEN)pBuffer;
210 pExtLogPen->elpPenStyle = pbrushPen->ulPenStyle;
211 pExtLogPen->elpWidth = 0;
212 pExtLogPen->elpBrushStyle = pbrushPen->ulStyle;
213 pExtLogPen->elpColor = pbrushPen->BrushAttr.lbColor;
214 pExtLogPen->elpHatch = 0;
215 pExtLogPen->elpNumEntries = 0;
216 cbRetCount = sizeof(EXTLOGPEN);
217 }
218 else
219 {
220 pLogPen = (PLOGPEN)pBuffer;
221 pLogPen->lopnWidth = pbrushPen->ptPenWidth;
222 pLogPen->lopnStyle = pbrushPen->ulPenStyle;
223 pLogPen->lopnColor = pbrushPen->BrushAttr.lbColor;
224 }
225 }
226 }
227 else
228 {
229 // FIXME: Can we trust in dwStyleCount being <= 16?
230 cbRetCount = sizeof(EXTLOGPEN) - sizeof(DWORD) + pbrushPen->dwStyleCount * sizeof(DWORD);
231 if (pBuffer)
232 {
233 ULONG i;
234
235 if (cbCount < cbRetCount) return 0;
236 pExtLogPen = (PEXTLOGPEN)pBuffer;
237 pExtLogPen->elpPenStyle = pbrushPen->ulPenStyle;
238 pExtLogPen->elpWidth = pbrushPen->ptPenWidth.x;
239 pExtLogPen->elpBrushStyle = pbrushPen->ulStyle;
240 pExtLogPen->elpColor = pbrushPen->BrushAttr.lbColor;
241 pExtLogPen->elpHatch = (ULONG_PTR)pbrushPen->hbmClient;
242 pExtLogPen->elpNumEntries = pbrushPen->dwStyleCount;
243 for (i = 0; i < pExtLogPen->elpNumEntries; i++)
244 {
245 pExtLogPen->elpStyleEntry[i] = pbrushPen->pStyle[i];
246 }
247 }
248 }
249
250 return cbRetCount;
251 }
252
253
254 /* PUBLIC FUNCTIONS ***********************************************************/
255
256 HPEN APIENTRY
257 NtGdiCreatePen(
258 INT PenStyle,
259 INT Width,
260 COLORREF Color,
261 IN HBRUSH hbr)
262 {
263 if ( PenStyle < PS_SOLID || PenStyle > PS_INSIDEFRAME )
264 {
265 EngSetLastError(ERROR_INVALID_PARAMETER);
266 return NULL;
267 }
268
269 return IntGdiExtCreatePen(PenStyle,
270 Width,
271 BS_SOLID,
272 Color,
273 0,
274 0,
275 0,
276 NULL,
277 0,
278 TRUE,
279 hbr);
280 }
281
282 HPEN APIENTRY
283 NtGdiExtCreatePen(
284 DWORD dwPenStyle,
285 DWORD ulWidth,
286 IN ULONG ulBrushStyle,
287 IN ULONG ulColor,
288 IN ULONG_PTR ulClientHatch,
289 IN ULONG_PTR ulHatch,
290 DWORD dwStyleCount,
291 PULONG pUnsafeStyle,
292 IN ULONG cjDIB,
293 IN BOOL bOldStylePen,
294 IN OPTIONAL HBRUSH hBrush)
295 {
296 NTSTATUS Status = STATUS_SUCCESS;
297 DWORD* pSafeStyle = NULL;
298 HPEN hPen;
299
300 if ((int)dwStyleCount < 0) return 0;
301 if (dwStyleCount > 16)
302 {
303 EngSetLastError(ERROR_INVALID_PARAMETER);
304 return 0;
305 }
306
307 if (dwStyleCount > 0)
308 {
309 pSafeStyle = ExAllocatePoolWithTag(NonPagedPool, dwStyleCount * sizeof(DWORD), GDITAG_PENSTYLE);
310 if (!pSafeStyle)
311 {
312 SetLastNtError(ERROR_NOT_ENOUGH_MEMORY);
313 return 0;
314 }
315 _SEH2_TRY
316 {
317 ProbeForRead(pUnsafeStyle, dwStyleCount * sizeof(DWORD), 1);
318 RtlCopyMemory(pSafeStyle,
319 pUnsafeStyle,
320 dwStyleCount * sizeof(DWORD));
321 }
322 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
323 {
324 Status = _SEH2_GetExceptionCode();
325 }
326 _SEH2_END
327 if(!NT_SUCCESS(Status))
328 {
329 SetLastNtError(Status);
330 ExFreePoolWithTag(pSafeStyle, GDITAG_PENSTYLE);
331 return 0;
332 }
333 }
334
335 if (ulBrushStyle == BS_PATTERN)
336 {
337 _SEH2_TRY
338 {
339 ProbeForRead((PVOID)ulHatch, cjDIB, 1);
340 }
341 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
342 {
343 Status = _SEH2_GetExceptionCode();
344 }
345 _SEH2_END
346 if(!NT_SUCCESS(Status))
347 {
348 SetLastNtError(Status);
349 if (pSafeStyle) ExFreePoolWithTag(pSafeStyle, GDITAG_PENSTYLE);
350 return 0;
351 }
352 }
353
354 hPen = IntGdiExtCreatePen(dwPenStyle,
355 ulWidth,
356 ulBrushStyle,
357 ulColor,
358 ulClientHatch,
359 ulHatch,
360 dwStyleCount,
361 pSafeStyle,
362 cjDIB,
363 bOldStylePen,
364 hBrush);
365
366 if (!hPen && pSafeStyle)
367 {
368 ExFreePoolWithTag(pSafeStyle, GDITAG_PENSTYLE);
369 }
370 return hPen;
371 }
372
373 /* EOF */