9c246b891e31cee97e9a2e8b114eeb8dab6441b8
[reactos.git] / subsystems / win32 / win32k / objects / pen.c
1 /*
2 * ReactOS Win32 Subsystem
3 *
4 * Copyright (C) 1998 - 2004 ReactOS Team
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 *
20 * $Id$
21 */
22
23 #include <win32k.h>
24
25 #define NDEBUG
26 #include <debug.h>
27
28 /* PRIVATE FUNCTIONS **********************************************************/
29
30 PBRUSH
31 FASTCALL
32 PEN_ShareLockPen(HGDIOBJ hobj)
33 {
34 if (GDI_HANDLE_GET_TYPE(hobj) != GDILoObjType_LO_PEN_TYPE &&
35 GDI_HANDLE_GET_TYPE(hobj) != GDILoObjType_LO_EXTPEN_TYPE)
36 {
37 return NULL;
38 }
39
40 return (PBRUSH)GDIOBJ_ReferenceObjectByHandle(hobj, GDIObjType_BRUSH_TYPE);
41 }
42
43 HPEN APIENTRY
44 IntGdiExtCreatePen(
45 DWORD dwPenStyle,
46 DWORD dwWidth,
47 IN ULONG ulBrushStyle,
48 IN ULONG ulColor,
49 IN ULONG_PTR ulClientHatch,
50 IN ULONG_PTR ulHatch,
51 DWORD dwStyleCount,
52 PULONG pStyle,
53 IN ULONG cjDIB,
54 IN BOOL bOldStylePen,
55 IN OPTIONAL HBRUSH hbrush)
56 {
57 HPEN hPen;
58 PBRUSH pbrushPen;
59 static const BYTE PatternAlternate[] = {0x55, 0x55, 0x55, 0};
60 static const BYTE PatternDash[] = {0xFF, 0xFF, 0xC0, 0};
61 static const BYTE PatternDot[] = {0xE3, 0x8E, 0x38, 0};
62 static const BYTE PatternDashDot[] = {0xFF, 0x81, 0xC0, 0};
63 static const BYTE PatternDashDotDot[] = {0xFF, 0x8E, 0x38, 0};
64
65 dwWidth = abs(dwWidth);
66
67 if ( (dwPenStyle & PS_STYLE_MASK) == PS_NULL)
68 {
69 return StockObjects[NULL_PEN];
70 }
71
72 if (bOldStylePen)
73 {
74 pbrushPen = PEN_AllocPenWithHandle();
75 }
76 else
77 {
78 pbrushPen = PEN_AllocExtPenWithHandle();
79 }
80
81 if (!pbrushPen)
82 {
83 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
84 DPRINT("Can't allocate pen\n");
85 return 0;
86 }
87 hPen = pbrushPen->BaseObject.hHmgr;
88
89 // If nWidth is zero, the pen is a single pixel wide, regardless of the current transformation.
90 if ((bOldStylePen) && (!dwWidth) && (dwPenStyle & PS_STYLE_MASK) != PS_SOLID)
91 dwWidth = 1;
92
93 pbrushPen->ptPenWidth.x = dwWidth;
94 pbrushPen->ptPenWidth.y = 0;
95 pbrushPen->ulPenStyle = dwPenStyle;
96 pbrushPen->BrushAttr.lbColor = ulColor;
97 pbrushPen->ulStyle = ulBrushStyle;
98 // FIXME: copy the bitmap first ?
99 pbrushPen->hbmClient = (HANDLE)ulClientHatch;
100 pbrushPen->dwStyleCount = dwStyleCount;
101 pbrushPen->pStyle = pStyle;
102
103 pbrushPen->flAttrs = bOldStylePen? GDIBRUSH_IS_OLDSTYLEPEN : GDIBRUSH_IS_PEN;
104
105 // If dwPenStyle is PS_COSMETIC, the width must be set to 1.
106 if ( !(bOldStylePen) && ((dwPenStyle & PS_TYPE_MASK) == PS_COSMETIC) && ( dwWidth != 1) )
107 goto ExitCleanup;
108
109 switch (dwPenStyle & PS_STYLE_MASK)
110 {
111 case PS_NULL:
112 pbrushPen->flAttrs |= GDIBRUSH_IS_NULL;
113 break;
114
115 case PS_SOLID:
116 pbrushPen->flAttrs |= GDIBRUSH_IS_SOLID;
117 break;
118
119 case PS_ALTERNATE:
120 pbrushPen->flAttrs |= GDIBRUSH_IS_BITMAP;
121 pbrushPen->hbmPattern = GreCreateBitmap(24, 1, 1, 1, (LPBYTE)PatternAlternate);
122 break;
123
124 case PS_DOT:
125 pbrushPen->flAttrs |= GDIBRUSH_IS_BITMAP;
126 pbrushPen->hbmPattern = GreCreateBitmap(24, 1, 1, 1, (LPBYTE)PatternDot);
127 break;
128
129 case PS_DASH:
130 pbrushPen->flAttrs |= GDIBRUSH_IS_BITMAP;
131 pbrushPen->hbmPattern = GreCreateBitmap(24, 1, 1, 1, (LPBYTE)PatternDash);
132 break;
133
134 case PS_DASHDOT:
135 pbrushPen->flAttrs |= GDIBRUSH_IS_BITMAP;
136 pbrushPen->hbmPattern = GreCreateBitmap(24, 1, 1, 1, (LPBYTE)PatternDashDot);
137 break;
138
139 case PS_DASHDOTDOT:
140 pbrushPen->flAttrs |= GDIBRUSH_IS_BITMAP;
141 pbrushPen->hbmPattern = GreCreateBitmap(24, 1, 1, 1, (LPBYTE)PatternDashDotDot);
142 break;
143
144 case PS_INSIDEFRAME:
145 pbrushPen->flAttrs |= (GDIBRUSH_IS_SOLID|GDIBRUSH_IS_INSIDEFRAME);
146 break;
147
148 case PS_USERSTYLE:
149 if ((dwPenStyle & PS_TYPE_MASK) == PS_COSMETIC)
150 {
151 /* FIXME: PS_USERSTYLE workaround */
152 DPRINT1("PS_COSMETIC | PS_USERSTYLE not handled\n");
153 pbrushPen->flAttrs |= GDIBRUSH_IS_SOLID;
154 break;
155 }
156 else
157 {
158 UINT i;
159 BOOL has_neg = FALSE, all_zero = TRUE;
160
161 for(i = 0; (i < dwStyleCount) && !has_neg; i++)
162 {
163 has_neg = has_neg || (((INT)(pStyle[i])) < 0);
164 all_zero = all_zero && (pStyle[i] == 0);
165 }
166
167 if(all_zero || has_neg)
168 {
169 goto ExitCleanup;
170 }
171 }
172 /* FIXME: what style here? */
173 pbrushPen->flAttrs |= 0;
174 break;
175
176 default:
177 DPRINT1("IntGdiExtCreatePen unknown penstyle %x\n", dwPenStyle);
178 }
179 PEN_UnlockPen(pbrushPen);
180 return hPen;
181
182 ExitCleanup:
183 EngSetLastError(ERROR_INVALID_PARAMETER);
184 pbrushPen->pStyle = NULL;
185 GDIOBJ_vDeleteObject(&pbrushPen->BaseObject);
186 return NULL;
187 }
188
189 VOID FASTCALL
190 IntGdiSetSolidPenColor(HPEN hPen, COLORREF Color)
191 {
192 PBRUSH pbrPen;
193
194 pbrPen = PEN_ShareLockPen(hPen);
195 if (pbrPen)
196 {
197 if (pbrPen->flAttrs & GDIBRUSH_IS_SOLID)
198 {
199 pbrPen->BrushAttr.lbColor = Color & 0xFFFFFF;
200 }
201 PEN_ShareUnlockPen(pbrPen);
202 }
203 }
204
205 INT APIENTRY
206 PEN_GetObject(PBRUSH pbrushPen, INT cbCount, PLOGPEN pBuffer)
207 {
208 PLOGPEN pLogPen;
209 PEXTLOGPEN pExtLogPen;
210 INT cbRetCount;
211
212 if (pbrushPen->flAttrs & GDIBRUSH_IS_OLDSTYLEPEN)
213 {
214 cbRetCount = sizeof(LOGPEN);
215 if (pBuffer)
216 {
217
218 if (cbCount < cbRetCount) return 0;
219
220 if ( (pbrushPen->ulPenStyle & PS_STYLE_MASK) == PS_NULL &&
221 cbCount == sizeof(EXTLOGPEN))
222 {
223 pExtLogPen = (PEXTLOGPEN)pBuffer;
224 pExtLogPen->elpPenStyle = pbrushPen->ulPenStyle;
225 pExtLogPen->elpWidth = 0;
226 pExtLogPen->elpBrushStyle = pbrushPen->ulStyle;
227 pExtLogPen->elpColor = pbrushPen->BrushAttr.lbColor;
228 pExtLogPen->elpHatch = 0;
229 pExtLogPen->elpNumEntries = 0;
230 cbRetCount = sizeof(EXTLOGPEN);
231 }
232 else
233 {
234 pLogPen = (PLOGPEN)pBuffer;
235 pLogPen->lopnWidth = pbrushPen->ptPenWidth;
236 pLogPen->lopnStyle = pbrushPen->ulPenStyle;
237 pLogPen->lopnColor = pbrushPen->BrushAttr.lbColor;
238 }
239 }
240 }
241 else
242 {
243 // FIXME: Can we trust in dwStyleCount being <= 16?
244 cbRetCount = sizeof(EXTLOGPEN) - sizeof(DWORD) + pbrushPen->dwStyleCount * sizeof(DWORD);
245 if (pBuffer)
246 {
247 INT i;
248
249 if (cbCount < cbRetCount) return 0;
250 pExtLogPen = (PEXTLOGPEN)pBuffer;
251 pExtLogPen->elpPenStyle = pbrushPen->ulPenStyle;
252 pExtLogPen->elpWidth = pbrushPen->ptPenWidth.x;
253 pExtLogPen->elpBrushStyle = pbrushPen->ulStyle;
254 pExtLogPen->elpColor = pbrushPen->BrushAttr.lbColor;
255 pExtLogPen->elpHatch = (ULONG_PTR)pbrushPen->hbmClient;
256 pExtLogPen->elpNumEntries = pbrushPen->dwStyleCount;
257 for (i = 0; i < pExtLogPen->elpNumEntries; i++)
258 {
259 pExtLogPen->elpStyleEntry[i] = pbrushPen->pStyle[i];
260 }
261 }
262 }
263
264 return cbRetCount;
265 }
266
267
268 /* PUBLIC FUNCTIONS ***********************************************************/
269
270 HPEN APIENTRY
271 NtGdiCreatePen(
272 INT PenStyle,
273 INT Width,
274 COLORREF Color,
275 IN HBRUSH hbr)
276 {
277 if ( PenStyle < PS_SOLID || PenStyle > PS_INSIDEFRAME )
278 {
279 EngSetLastError(ERROR_INVALID_PARAMETER);
280 return NULL;
281 }
282
283 return IntGdiExtCreatePen(PenStyle,
284 Width,
285 BS_SOLID,
286 Color,
287 0,
288 0,
289 0,
290 NULL,
291 0,
292 TRUE,
293 hbr);
294 }
295
296 HPEN APIENTRY
297 NtGdiExtCreatePen(
298 DWORD dwPenStyle,
299 DWORD ulWidth,
300 IN ULONG ulBrushStyle,
301 IN ULONG ulColor,
302 IN ULONG_PTR ulClientHatch,
303 IN ULONG_PTR ulHatch,
304 DWORD dwStyleCount,
305 PULONG pUnsafeStyle,
306 IN ULONG cjDIB,
307 IN BOOL bOldStylePen,
308 IN OPTIONAL HBRUSH hBrush)
309 {
310 NTSTATUS Status = STATUS_SUCCESS;
311 DWORD* pSafeStyle = NULL;
312 HPEN hPen;
313
314 if ((int)dwStyleCount < 0) return 0;
315 if (dwStyleCount > 16)
316 {
317 EngSetLastError(ERROR_INVALID_PARAMETER);
318 return 0;
319 }
320
321 if (dwStyleCount > 0)
322 {
323 pSafeStyle = ExAllocatePoolWithTag(NonPagedPool, dwStyleCount * sizeof(DWORD), 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 return hPen;
385 }
386
387
388
389 /* EOF */