1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Pen functiona
5 * FILE: win32ss/gdi/ntgdi/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
PEN_vInit(PPEN ppen)18 PEN_vInit(
19 PPEN ppen)
20 {
21 /* Start with kmode brush attribute */
22 ppen->pBrushAttr = &ppen->BrushAttr;
23 }
24
25 PBRUSH
26 NTAPI
PEN_AllocPenWithHandle(VOID)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
PEN_AllocExtPenWithHandle(VOID)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
PEN_ShareLockPen(HPEN hobj)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
IntGdiExtCreatePen(DWORD dwPenStyle,DWORD dwWidth,IN ULONG ulBrushStyle,IN ULONG ulColor,IN ULONG_PTR ulClientHatch,IN ULONG_PTR ulHatch,DWORD dwStyleCount,PULONG pStyle,IN ULONG cjDIB,IN BOOL bOldStylePen,IN OPTIONAL HBRUSH hbrush)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 ULONG aulStyleAlternate[] = { 1, 1 };
90 static ULONG aulStyleDash[] = { 6, 2 };
91 static ULONG aulStyleDot[] = { 1, 1 };
92 static ULONG aulStyleDashDot[] = { 3, 2, 1, 2 };
93 static ULONG aulStyleDashDotDot[] = { 3, 1, 1, 1, 1, 1 };
94 ULONG i;
95
96 dwWidth = abs(dwWidth);
97
98 if ( (dwPenStyle & PS_STYLE_MASK) == PS_NULL)
99 {
100 return StockObjects[NULL_PEN];
101 }
102
103 if (bOldStylePen)
104 {
105 pbrushPen = PEN_AllocPenWithHandle();
106 }
107 else
108 {
109 pbrushPen = PEN_AllocExtPenWithHandle();
110 }
111
112 if (!pbrushPen)
113 {
114 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
115 DPRINT("Can't allocate pen\n");
116 return 0;
117 }
118
119 hPen = pbrushPen->BaseObject.hHmgr;
120
121 if (bOldStylePen)
122 {
123 // If nWidth is zero, the pen is a single pixel wide, regardless of the current transformation.
124 if (!dwWidth && (dwPenStyle & PS_STYLE_MASK) != PS_SOLID)
125 dwWidth = 1;
126 }
127 else
128 {
129 switch (dwPenStyle & PS_ENDCAP_MASK)
130 {
131 case PS_ENDCAP_ROUND:
132 case PS_ENDCAP_SQUARE:
133 case PS_ENDCAP_FLAT:
134 break;
135
136 default:
137 goto ExitCleanup;
138 }
139
140 switch (dwPenStyle & PS_JOIN_MASK)
141 {
142 case PS_JOIN_ROUND:
143 case PS_JOIN_BEVEL:
144 case PS_JOIN_MITER:
145 break;
146
147 default:
148 goto ExitCleanup;
149 }
150
151 switch (dwPenStyle & PS_TYPE_MASK)
152 {
153 case PS_COSMETIC:
154 if (dwWidth != 1 || ulBrushStyle != BS_SOLID)
155 goto ExitCleanup;
156
157 break;
158
159 case PS_GEOMETRIC:
160 break;
161
162 default:
163 goto ExitCleanup;
164 }
165 }
166
167 pbrushPen->lWidth = dwWidth;
168 FLOATOBJ_SetLong(&pbrushPen->eWidth, pbrushPen->lWidth);
169 pbrushPen->ulPenStyle = dwPenStyle;
170 pbrushPen->BrushAttr.lbColor = ulColor;
171 pbrushPen->iBrushStyle = ulBrushStyle;
172 // FIXME: Copy the bitmap first ?
173 pbrushPen->hbmClient = (HANDLE)ulClientHatch;
174 pbrushPen->dwStyleCount = 0;
175 pbrushPen->pStyle = NULL;
176 pbrushPen->ulStyleSize = 0;
177 pbrushPen->flAttrs = bOldStylePen ? BR_IS_OLDSTYLEPEN : BR_IS_PEN;
178
179 switch (dwPenStyle & PS_STYLE_MASK)
180 {
181 case PS_NULL:
182 pbrushPen->flAttrs |= BR_IS_NULL;
183 break;
184
185 case PS_SOLID:
186 pbrushPen->flAttrs |= BR_IS_SOLID;
187 break;
188
189 case PS_ALTERNATE:
190 pbrushPen->flAttrs |= BR_IS_SOLID | BR_IS_DEFAULTSTYLE;
191 pbrushPen->pStyle = aulStyleAlternate;
192 pbrushPen->dwStyleCount = _countof(aulStyleAlternate);
193 break;
194
195 case PS_DOT:
196 pbrushPen->flAttrs |= BR_IS_SOLID | BR_IS_DEFAULTSTYLE;
197 pbrushPen->pStyle = aulStyleDot;
198 pbrushPen->dwStyleCount = _countof(aulStyleDot);
199 break;
200
201 case PS_DASH:
202 pbrushPen->flAttrs |= BR_IS_SOLID | BR_IS_DEFAULTSTYLE;
203 pbrushPen->pStyle = aulStyleDash;
204 pbrushPen->dwStyleCount = _countof(aulStyleDash);
205 break;
206
207 case PS_DASHDOT:
208 pbrushPen->flAttrs |= BR_IS_SOLID | BR_IS_DEFAULTSTYLE;
209 pbrushPen->pStyle = aulStyleDashDot;
210 pbrushPen->dwStyleCount = _countof(aulStyleDashDot);
211 break;
212
213 case PS_DASHDOTDOT:
214 pbrushPen->flAttrs |= BR_IS_SOLID | BR_IS_DEFAULTSTYLE;
215 pbrushPen->pStyle = aulStyleDashDotDot;
216 pbrushPen->dwStyleCount = _countof(aulStyleDashDotDot);
217 break;
218
219 case PS_INSIDEFRAME:
220 pbrushPen->flAttrs |= (BR_IS_SOLID | BR_IS_INSIDEFRAME);
221 break;
222
223 case PS_USERSTYLE:
224 {
225 UINT i;
226 BOOL has_neg = FALSE, all_zero = TRUE;
227
228 for(i = 0; (i < dwStyleCount) && !has_neg; i++)
229 {
230 has_neg = has_neg || (((INT)(pStyle[i])) < 0);
231 all_zero = all_zero && (pStyle[i] == 0);
232 }
233
234 if(all_zero || has_neg)
235 {
236 goto ExitCleanup;
237 }
238 }
239 /* FIXME: What style here? */
240 pbrushPen->flAttrs |= BR_IS_SOLID;
241 pbrushPen->dwStyleCount = dwStyleCount;
242 pbrushPen->pStyle = pStyle;
243 break;
244
245 default:
246 DPRINT1("IntGdiExtCreatePen unknown penstyle %x\n", dwPenStyle);
247 goto ExitCleanup;
248 }
249
250 if (pbrushPen->pStyle != NULL)
251 {
252 for (i = 0; i < pbrushPen->dwStyleCount; i++)
253 {
254 pbrushPen->ulStyleSize += pbrushPen->pStyle[i];
255 }
256 }
257
258 NT_ASSERT((pbrushPen->dwStyleCount == 0) || (pbrushPen->pStyle != NULL));
259
260 PEN_UnlockPen(pbrushPen);
261 return hPen;
262
263 ExitCleanup:
264 EngSetLastError(ERROR_INVALID_PARAMETER);
265 pbrushPen->pStyle = NULL;
266 GDIOBJ_vDeleteObject(&pbrushPen->BaseObject);
267
268 return NULL;
269 }
270
271 VOID
272 FASTCALL
IntGdiSetSolidPenColor(HPEN hPen,COLORREF Color)273 IntGdiSetSolidPenColor(HPEN hPen, COLORREF Color)
274 {
275 PBRUSH pbrPen;
276
277 pbrPen = PEN_ShareLockPen(hPen);
278 if (pbrPen)
279 {
280 if (pbrPen->flAttrs & BR_IS_SOLID)
281 {
282 pbrPen->BrushAttr.lbColor = Color & 0xFFFFFF;
283 }
284 PEN_ShareUnlockPen(pbrPen);
285 }
286 }
287
288 INT
289 APIENTRY
PEN_GetObject(PBRUSH pbrushPen,INT cbCount,PLOGPEN pBuffer)290 PEN_GetObject(PBRUSH pbrushPen, INT cbCount, PLOGPEN pBuffer)
291 {
292 PLOGPEN pLogPen;
293 PEXTLOGPEN pExtLogPen;
294 INT cbRetCount;
295
296 if (pbrushPen->flAttrs & BR_IS_OLDSTYLEPEN)
297 {
298 cbRetCount = sizeof(LOGPEN);
299 if (pBuffer)
300 {
301 if (cbCount < cbRetCount) return 0;
302
303 if (((pbrushPen->ulPenStyle & PS_STYLE_MASK) == PS_NULL) &&
304 (cbCount == sizeof(EXTLOGPEN)))
305 {
306 pExtLogPen = (PEXTLOGPEN)pBuffer;
307 pExtLogPen->elpPenStyle = pbrushPen->ulPenStyle;
308 pExtLogPen->elpWidth = 0;
309 pExtLogPen->elpBrushStyle = pbrushPen->iBrushStyle;
310 pExtLogPen->elpColor = pbrushPen->BrushAttr.lbColor;
311 pExtLogPen->elpHatch = 0;
312 pExtLogPen->elpNumEntries = 0;
313 cbRetCount = sizeof(EXTLOGPEN);
314 }
315 else
316 {
317 pLogPen = (PLOGPEN)pBuffer;
318 pLogPen->lopnWidth.x = pbrushPen->lWidth;
319 pLogPen->lopnWidth.y = 0;
320 pLogPen->lopnStyle = pbrushPen->ulPenStyle;
321 pLogPen->lopnColor = pbrushPen->BrushAttr.lbColor;
322 }
323 }
324 }
325 else
326 {
327 DWORD dwStyleCount = (pbrushPen->flAttrs & BR_IS_DEFAULTSTYLE) ?
328 0 : pbrushPen->dwStyleCount;
329 cbRetCount = sizeof(EXTLOGPEN) - sizeof(DWORD) + dwStyleCount * sizeof(DWORD);
330 if (pBuffer)
331 {
332 ULONG i;
333
334 if (cbCount < cbRetCount) return 0;
335 pExtLogPen = (PEXTLOGPEN)pBuffer;
336 pExtLogPen->elpPenStyle = pbrushPen->ulPenStyle;
337 pExtLogPen->elpWidth = pbrushPen->lWidth;
338 pExtLogPen->elpBrushStyle = pbrushPen->iBrushStyle;
339 pExtLogPen->elpColor = pbrushPen->BrushAttr.lbColor;
340 pExtLogPen->elpHatch = (ULONG_PTR)pbrushPen->hbmClient;
341 pExtLogPen->elpNumEntries = dwStyleCount;
342 for (i = 0; i < dwStyleCount; i++)
343 {
344 pExtLogPen->elpStyleEntry[i] = pbrushPen->pStyle[i];
345 }
346 }
347 }
348
349 return cbRetCount;
350 }
351
352
353 /* PUBLIC FUNCTIONS ***********************************************************/
354
355 HPEN
356 APIENTRY
NtGdiCreatePen(INT PenStyle,INT Width,COLORREF Color,IN HBRUSH hbr)357 NtGdiCreatePen(
358 INT PenStyle,
359 INT Width,
360 COLORREF Color,
361 IN HBRUSH hbr)
362 {
363 if ((PenStyle < PS_SOLID) ||( PenStyle > PS_INSIDEFRAME))
364 {
365 EngSetLastError(ERROR_INVALID_PARAMETER);
366 return NULL;
367 }
368
369 return IntGdiExtCreatePen(PenStyle,
370 Width,
371 BS_SOLID,
372 Color,
373 0,
374 0,
375 0,
376 NULL,
377 0,
378 TRUE,
379 hbr);
380 }
381
382 HPEN
383 APIENTRY
NtGdiExtCreatePen(DWORD dwPenStyle,DWORD ulWidth,IN ULONG ulBrushStyle,IN ULONG ulColor,IN ULONG_PTR ulClientHatch,IN ULONG_PTR ulHatch,DWORD dwStyleCount,PULONG pUnsafeStyle,IN ULONG cjDIB,IN BOOL bOldStylePen,IN OPTIONAL HBRUSH hBrush)384 NtGdiExtCreatePen(
385 DWORD dwPenStyle,
386 DWORD ulWidth,
387 IN ULONG ulBrushStyle,
388 IN ULONG ulColor,
389 IN ULONG_PTR ulClientHatch,
390 IN ULONG_PTR ulHatch,
391 DWORD dwStyleCount,
392 PULONG pUnsafeStyle,
393 IN ULONG cjDIB,
394 IN BOOL bOldStylePen,
395 IN OPTIONAL HBRUSH hBrush)
396 {
397 NTSTATUS Status = STATUS_SUCCESS;
398 DWORD* pSafeStyle = NULL;
399 HPEN hPen;
400
401 if ((int)dwStyleCount < 0) return 0;
402 if (dwStyleCount > 16)
403 {
404 EngSetLastError(ERROR_INVALID_PARAMETER);
405 return 0;
406 }
407
408 if (((dwPenStyle & PS_TYPE_MASK) == PS_COSMETIC) &&
409 (ulBrushStyle != BS_SOLID))
410 {
411 EngSetLastError(ERROR_INVALID_PARAMETER);
412 return 0;
413 }
414
415 if (((dwPenStyle & PS_STYLE_MASK) == PS_NULL) ||
416 (ulBrushStyle == BS_NULL))
417 {
418 return StockObjects[NULL_PEN];
419 }
420
421
422 if ((ulBrushStyle == BS_PATTERN) ||
423 (ulBrushStyle == BS_DIBPATTERN) ||
424 (ulBrushStyle == BS_DIBPATTERNPT))
425 {
426 ulColor = 0;
427 }
428 else if ((ulBrushStyle != BS_SOLID) &&
429 (ulBrushStyle != BS_HATCHED))
430 {
431 EngSetLastError(ERROR_INVALID_PARAMETER);
432 return 0;
433 }
434
435 if ((dwPenStyle & PS_STYLE_MASK) != PS_USERSTYLE)
436 {
437 dwStyleCount = 0;
438 pUnsafeStyle = NULL;
439 }
440
441 if (dwStyleCount > 0)
442 {
443 if (pUnsafeStyle == NULL)
444 {
445 EngSetLastError(ERROR_INVALID_PARAMETER);
446 return 0;
447 }
448
449 pSafeStyle = ExAllocatePoolWithTag(NonPagedPool,
450 dwStyleCount * sizeof(DWORD),
451 GDITAG_PENSTYLE);
452 if (!pSafeStyle)
453 {
454 SetLastNtError(ERROR_NOT_ENOUGH_MEMORY);
455 return 0;
456 }
457 _SEH2_TRY
458 {
459 ProbeForRead(pUnsafeStyle, dwStyleCount * sizeof(DWORD), 1);
460 RtlCopyMemory(pSafeStyle,
461 pUnsafeStyle,
462 dwStyleCount * sizeof(DWORD));
463 }
464 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
465 {
466 Status = _SEH2_GetExceptionCode();
467 }
468 _SEH2_END
469 if(!NT_SUCCESS(Status))
470 {
471 SetLastNtError(Status);
472 ExFreePoolWithTag(pSafeStyle, GDITAG_PENSTYLE);
473 return 0;
474 }
475 }
476
477 if (ulBrushStyle == BS_PATTERN)
478 {
479 _SEH2_TRY
480 {
481 ProbeForRead((PVOID)ulHatch, cjDIB, 1);
482 }
483 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
484 {
485 Status = _SEH2_GetExceptionCode();
486 }
487 _SEH2_END
488 if(!NT_SUCCESS(Status))
489 {
490 SetLastNtError(Status);
491 if (pSafeStyle) ExFreePoolWithTag(pSafeStyle, GDITAG_PENSTYLE);
492 return 0;
493 }
494 }
495
496 hPen = IntGdiExtCreatePen(dwPenStyle,
497 ulWidth,
498 ulBrushStyle,
499 ulColor,
500 ulClientHatch,
501 ulHatch,
502 dwStyleCount,
503 pSafeStyle,
504 cjDIB,
505 bOldStylePen,
506 hBrush);
507
508 if (!hPen && pSafeStyle)
509 {
510 ExFreePoolWithTag(pSafeStyle, GDITAG_PENSTYLE);
511 }
512
513 return hPen;
514 }
515
516 /* EOF */
517