Merging r37048, r37051, r37052, r37055 from the-real-msvc branch
[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
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 *
20 * $Id$
21 */
22
23 #include <w32k.h>
24
25 #define NDEBUG
26 #include <debug.h>
27
28 /* PRIVATE FUNCTIONS **********************************************************/
29
30 PGDIBRUSHOBJ
31 FASTCALL
32 PENOBJ_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 HPEN STDCALL
41 IntGdiExtCreatePen(
42 DWORD dwPenStyle,
43 DWORD dwWidth,
44 IN ULONG ulBrushStyle,
45 IN ULONG ulColor,
46 IN ULONG_PTR ulClientHatch,
47 IN ULONG_PTR ulHatch,
48 DWORD dwStyleCount,
49 PULONG pStyle,
50 IN ULONG cjDIB, // FIXME! We are shipping this too!
51 IN BOOL bOldStylePen,
52 IN OPTIONAL HBRUSH hbrush)
53 {
54 HPEN hPen;
55 PGDIBRUSHOBJ PenObject;
56 static const BYTE PatternAlternate[] = {0x55, 0x55, 0x55};
57 static const BYTE PatternDash[] = {0xFF, 0xFF, 0xC0};
58 static const BYTE PatternDot[] = {0xE3, 0x8E, 0x38};
59 static const BYTE PatternDashDot[] = {0xFF, 0x81, 0xC0};
60 static const BYTE PatternDashDotDot[] = {0xFF, 0x8E, 0x38};
61
62 dwWidth = abs(dwWidth);
63
64 if (bOldStylePen)
65 {
66 PenObject = PENOBJ_AllocPenWithHandle();
67 }
68 else
69 {
70 PenObject = PENOBJ_AllocExtPenWithHandle();
71 }
72
73 if (!PenObject)
74 {
75 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
76 DPRINT("Can't allocate pen\n");
77 return 0;
78 }
79 hPen = PenObject->BaseObject.hHmgr;
80
81 // If nWidth is zero, the pen is a single pixel wide, regardless of the current transformation.
82 if ((bOldStylePen) && (!dwWidth)) dwWidth = 1;
83
84 PenObject->ptPenWidth.x = dwWidth;
85 PenObject->ptPenWidth.y = 0;
86 PenObject->ulPenStyle = dwPenStyle;
87 PenObject->BrushAttr.lbColor = ulColor;
88 PenObject->ulStyle = ulBrushStyle;
89 // FIXME: copy the bitmap first ?
90 PenObject->hbmClient = (HANDLE)ulClientHatch;
91 PenObject->dwStyleCount = dwStyleCount;
92 PenObject->pStyle = pStyle;
93
94 PenObject->flAttrs = bOldStylePen? GDIBRUSH_IS_OLDSTYLEPEN : GDIBRUSH_IS_PEN;
95
96 // If dwPenStyle is PS_COSMETIC, the width must be set to 1.
97 if ( !(bOldStylePen) && ((dwPenStyle & PS_TYPE_MASK) == PS_COSMETIC) && ( dwWidth != 1) )
98 goto ExitCleanup;
99
100 switch (dwPenStyle & PS_STYLE_MASK)
101 {
102 case PS_NULL:
103 PenObject->flAttrs |= GDIBRUSH_IS_NULL;
104 break;
105
106 case PS_SOLID:
107 PenObject->flAttrs |= GDIBRUSH_IS_SOLID;
108 break;
109
110 case PS_ALTERNATE:
111 /* PS_ALTERNATE is applicable only for cosmetic pens */
112 if ((dwPenStyle & PS_TYPE_MASK) == PS_GEOMETRIC) goto ExitCleanup;
113 PenObject->flAttrs |= GDIBRUSH_IS_BITMAP;
114 PenObject->hbmPattern = IntGdiCreateBitmap(24, 1, 1, 1, (LPBYTE)PatternAlternate);
115 break;
116
117 case PS_DOT:
118 PenObject->flAttrs |= GDIBRUSH_IS_BITMAP;
119 PenObject->hbmPattern = IntGdiCreateBitmap(24, 1, 1, 1, (LPBYTE)PatternDot);
120 break;
121
122 case PS_DASH:
123 PenObject->flAttrs |= GDIBRUSH_IS_BITMAP;
124 PenObject->hbmPattern = IntGdiCreateBitmap(24, 1, 1, 1, (LPBYTE)PatternDash);
125 break;
126
127 case PS_DASHDOT:
128 PenObject->flAttrs |= GDIBRUSH_IS_BITMAP;
129 PenObject->hbmPattern = IntGdiCreateBitmap(24, 1, 1, 1, (LPBYTE)PatternDashDot);
130 break;
131
132 case PS_DASHDOTDOT:
133 PenObject->flAttrs |= GDIBRUSH_IS_BITMAP;
134 PenObject->hbmPattern = IntGdiCreateBitmap(24, 1, 1, 1, (LPBYTE)PatternDashDotDot);
135 break;
136
137 case PS_INSIDEFRAME:
138 /* FIXME: does it need some additional work? */
139 /* PS_INSIDEFRAME is applicable only for geometric pens */
140 if ((dwPenStyle & PS_TYPE_MASK) == PS_COSMETIC) goto ExitCleanup;
141 PenObject->flAttrs |= (GDIBRUSH_IS_SOLID|GDIBRUSH_IS_INSIDEFRAME);
142 break;
143
144 case PS_USERSTYLE:
145 if ((dwPenStyle & PS_TYPE_MASK) == PS_COSMETIC)
146 {
147 /* FIXME: PS_USERSTYLE workaround */
148 DPRINT1("PS_COSMETIC | PS_USERSTYLE not handled\n");
149 PenObject->flAttrs |= GDIBRUSH_IS_SOLID;
150 break;
151 }
152 else
153 {
154 UINT i;
155 BOOL has_neg = FALSE, all_zero = TRUE;
156
157 for(i = 0; (i < dwStyleCount) && !has_neg; i++)
158 {
159 has_neg = has_neg || (((INT)(pStyle[i])) < 0);
160 all_zero = all_zero && (pStyle[i] == 0);
161 }
162
163 if(all_zero || has_neg)
164 {
165 goto ExitCleanup;
166 }
167 }
168 /* FIXME: what style here? */
169 PenObject->flAttrs |= 0;
170 break;
171
172 default:
173 DPRINT1("IntGdiExtCreatePen unknown penstyle %x\n", dwPenStyle);
174 }
175 PENOBJ_UnlockPen(PenObject);
176 return hPen;
177
178 ExitCleanup:
179 SetLastWin32Error(ERROR_INVALID_PARAMETER);
180 PenObject->pStyle = NULL;
181 PENOBJ_UnlockPen(PenObject);
182 if (bOldStylePen)
183 PENOBJ_FreePenByHandle(hPen);
184 else
185 PENOBJ_FreeExtPenByHandle(hPen);
186 return NULL;
187 }
188
189 VOID FASTCALL
190 IntGdiSetSolidPenColor(HPEN hPen, COLORREF Color)
191 {
192 PGDIBRUSHOBJ PenObject;
193
194 PenObject = PENOBJ_LockPen(hPen);
195 if (PenObject)
196 {
197 if (PenObject->flAttrs & GDIBRUSH_IS_SOLID)
198 {
199 PenObject->BrushAttr.lbColor = Color & 0xFFFFFF;
200 }
201 PENOBJ_UnlockPen(PenObject);
202 }
203 }
204
205 INT STDCALL
206 PEN_GetObject(PGDIBRUSHOBJ pPenObject, INT cbCount, PLOGPEN pBuffer)
207 {
208 PLOGPEN pLogPen;
209 PEXTLOGPEN pExtLogPen;
210 INT cbRetCount;
211
212 if (pPenObject->flAttrs & GDIBRUSH_IS_OLDSTYLEPEN)
213 {
214 cbRetCount = sizeof(LOGPEN);
215 if (pBuffer)
216 {
217 if (cbCount < cbRetCount) return 0;
218 pLogPen = (PLOGPEN)pBuffer;
219 pLogPen->lopnWidth = pPenObject->ptPenWidth;
220 pLogPen->lopnStyle = pPenObject->ulPenStyle;
221 pLogPen->lopnColor = pPenObject->BrushAttr.lbColor;
222 }
223 }
224 else
225 {
226 // FIXME: Can we trust in dwStyleCount being <= 16?
227 cbRetCount = sizeof(EXTLOGPEN) - sizeof(DWORD) + pPenObject->dwStyleCount * sizeof(DWORD);
228 if (pBuffer)
229 {
230 INT i;
231
232 if (cbCount < cbRetCount) return 0;
233 pExtLogPen = (PEXTLOGPEN)pBuffer;
234 pExtLogPen->elpPenStyle = pPenObject->ulPenStyle;
235 pExtLogPen->elpWidth = pPenObject->ptPenWidth.x;
236 pExtLogPen->elpBrushStyle = pPenObject->ulStyle;
237 pExtLogPen->elpColor = pPenObject->BrushAttr.lbColor;
238 pExtLogPen->elpHatch = (ULONG_PTR)pPenObject->hbmClient;
239 pExtLogPen->elpNumEntries = pPenObject->dwStyleCount;
240 for (i = 0; i < pExtLogPen->elpNumEntries; i++)
241 {
242 pExtLogPen->elpStyleEntry[i] = pPenObject->pStyle[i];
243 }
244 }
245 }
246
247 return cbRetCount;
248 }
249
250 /* PUBLIC FUNCTIONS ***********************************************************/
251
252 HPEN STDCALL
253 NtGdiCreatePen(
254 INT PenStyle,
255 INT Width,
256 COLORREF Color,
257 IN HBRUSH hbr)
258 {
259 if ( PenStyle < PS_SOLID || PenStyle > PS_INSIDEFRAME )
260 {
261 SetLastWin32Error(ERROR_INVALID_PARAMETER);
262 return NULL;
263 }
264
265 return IntGdiExtCreatePen(PenStyle,
266 Width,
267 BS_SOLID,
268 Color,
269 0,
270 0,
271 0,
272 NULL,
273 0,
274 TRUE,
275 0);
276 }
277
278 HPEN STDCALL
279 NtGdiExtCreatePen(
280 DWORD dwPenStyle,
281 DWORD ulWidth,
282 IN ULONG ulBrushStyle,
283 IN ULONG ulColor,
284 IN ULONG_PTR ulClientHatch,
285 IN ULONG_PTR ulHatch,
286 DWORD dwStyleCount,
287 PULONG pUnsafeStyle,
288 IN ULONG cjDIB,
289 IN BOOL bOldStylePen,
290 IN OPTIONAL HBRUSH hBrush)
291 {
292 NTSTATUS Status = STATUS_SUCCESS;
293 DWORD* pSafeStyle = NULL;
294 HPEN hPen;
295
296 if ((int)dwStyleCount < 0) return 0;
297 if (dwStyleCount > 16)
298 {
299 SetLastWin32Error(ERROR_INVALID_PARAMETER);
300 return 0;
301 }
302
303 if (dwStyleCount > 0)
304 {
305 pSafeStyle = ExAllocatePoolWithTag(NonPagedPool, dwStyleCount * sizeof(DWORD), TAG_PENSTYLES);
306 if (!pSafeStyle)
307 {
308 SetLastNtError(ERROR_NOT_ENOUGH_MEMORY);
309 return 0;
310 }
311 _SEH_TRY
312 {
313 ProbeForRead(pUnsafeStyle, dwStyleCount * sizeof(DWORD), 1);
314 RtlCopyMemory(pSafeStyle,
315 pUnsafeStyle,
316 dwStyleCount * sizeof(DWORD));
317 }
318 _SEH_HANDLE
319 {
320 Status = _SEH_GetExceptionCode();
321 }
322 _SEH_END
323 if(!NT_SUCCESS(Status))
324 {
325 SetLastNtError(Status);
326 ExFreePool(pSafeStyle);
327 return 0;
328 }
329 }
330
331 hPen = IntGdiExtCreatePen(dwPenStyle,
332 ulWidth,
333 ulBrushStyle,
334 ulColor,
335 ulClientHatch,
336 ulHatch,
337 dwStyleCount,
338 pSafeStyle,
339 cjDIB,
340 bOldStylePen,
341 hBrush);
342 if (!hPen && pSafeStyle)
343 {
344 ExFreePool(pSafeStyle);
345 }
346 return hPen;
347 }
348
349
350 /* EOF */