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