xref: /reactos/win32ss/gdi/ntgdi/pen.c (revision 84344399)
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
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 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
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
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
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
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