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