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