rename DCs pDc_Attr to pdcattr, like in gdikdx.
[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 APIENTRY
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,
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 ( (dwPenStyle & PS_STYLE_MASK) == PS_NULL)
65 {
66 return StockObjects[NULL_PEN];
67 }
68
69 if (bOldStylePen)
70 {
71 PenObject = PENOBJ_AllocPenWithHandle();
72 }
73 else
74 {
75 PenObject = PENOBJ_AllocExtPenWithHandle();
76 }
77
78 if (!PenObject)
79 {
80 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
81 DPRINT("Can't allocate pen\n");
82 return 0;
83 }
84 hPen = PenObject->BaseObject.hHmgr;
85
86 // If nWidth is zero, the pen is a single pixel wide, regardless of the current transformation.
87 if ((bOldStylePen) && (!dwWidth) && (dwPenStyle & PS_STYLE_MASK) != PS_SOLID)
88 dwWidth = 1;
89
90 PenObject->ptPenWidth.x = dwWidth;
91 PenObject->ptPenWidth.y = 0;
92 PenObject->ulPenStyle = dwPenStyle;
93 PenObject->BrushAttr.lbColor = ulColor;
94 PenObject->ulStyle = ulBrushStyle;
95 // FIXME: copy the bitmap first ?
96 PenObject->hbmClient = (HANDLE)ulClientHatch;
97 PenObject->dwStyleCount = dwStyleCount;
98 PenObject->pStyle = pStyle;
99
100 PenObject->flAttrs = bOldStylePen? GDIBRUSH_IS_OLDSTYLEPEN : GDIBRUSH_IS_PEN;
101
102 // If dwPenStyle is PS_COSMETIC, the width must be set to 1.
103 if ( !(bOldStylePen) && ((dwPenStyle & PS_TYPE_MASK) == PS_COSMETIC) && ( dwWidth != 1) )
104 goto ExitCleanup;
105
106 switch (dwPenStyle & PS_STYLE_MASK)
107 {
108 case PS_NULL:
109 PenObject->flAttrs |= GDIBRUSH_IS_NULL;
110 break;
111
112 case PS_SOLID:
113 PenObject->flAttrs |= GDIBRUSH_IS_SOLID;
114 break;
115
116 case PS_ALTERNATE:
117 PenObject->flAttrs |= GDIBRUSH_IS_BITMAP;
118 PenObject->hbmPattern = IntGdiCreateBitmap(24, 1, 1, 1, (LPBYTE)PatternAlternate);
119 break;
120
121 case PS_DOT:
122 PenObject->flAttrs |= GDIBRUSH_IS_BITMAP;
123 PenObject->hbmPattern = IntGdiCreateBitmap(24, 1, 1, 1, (LPBYTE)PatternDot);
124 break;
125
126 case PS_DASH:
127 PenObject->flAttrs |= GDIBRUSH_IS_BITMAP;
128 PenObject->hbmPattern = IntGdiCreateBitmap(24, 1, 1, 1, (LPBYTE)PatternDash);
129 break;
130
131 case PS_DASHDOT:
132 PenObject->flAttrs |= GDIBRUSH_IS_BITMAP;
133 PenObject->hbmPattern = IntGdiCreateBitmap(24, 1, 1, 1, (LPBYTE)PatternDashDot);
134 break;
135
136 case PS_DASHDOTDOT:
137 PenObject->flAttrs |= GDIBRUSH_IS_BITMAP;
138 PenObject->hbmPattern = IntGdiCreateBitmap(24, 1, 1, 1, (LPBYTE)PatternDashDotDot);
139 break;
140
141 case PS_INSIDEFRAME:
142 PenObject->flAttrs |= (GDIBRUSH_IS_SOLID|GDIBRUSH_IS_INSIDEFRAME);
143 break;
144
145 case PS_USERSTYLE:
146 if ((dwPenStyle & PS_TYPE_MASK) == PS_COSMETIC)
147 {
148 /* FIXME: PS_USERSTYLE workaround */
149 DPRINT1("PS_COSMETIC | PS_USERSTYLE not handled\n");
150 PenObject->flAttrs |= GDIBRUSH_IS_SOLID;
151 break;
152 }
153 else
154 {
155 UINT i;
156 BOOL has_neg = FALSE, all_zero = TRUE;
157
158 for(i = 0; (i < dwStyleCount) && !has_neg; i++)
159 {
160 has_neg = has_neg || (((INT)(pStyle[i])) < 0);
161 all_zero = all_zero && (pStyle[i] == 0);
162 }
163
164 if(all_zero || has_neg)
165 {
166 goto ExitCleanup;
167 }
168 }
169 /* FIXME: what style here? */
170 PenObject->flAttrs |= 0;
171 break;
172
173 default:
174 DPRINT1("IntGdiExtCreatePen unknown penstyle %x\n", dwPenStyle);
175 }
176 PENOBJ_UnlockPen(PenObject);
177 return hPen;
178
179 ExitCleanup:
180 SetLastWin32Error(ERROR_INVALID_PARAMETER);
181 PenObject->pStyle = NULL;
182 PENOBJ_UnlockPen(PenObject);
183 if (bOldStylePen)
184 PENOBJ_FreePenByHandle(hPen);
185 else
186 PENOBJ_FreeExtPenByHandle(hPen);
187 return NULL;
188 }
189
190 VOID FASTCALL
191 IntGdiSetSolidPenColor(HPEN hPen, COLORREF Color)
192 {
193 PGDIBRUSHOBJ PenObject;
194
195 PenObject = PENOBJ_LockPen(hPen);
196 if (PenObject)
197 {
198 if (PenObject->flAttrs & GDIBRUSH_IS_SOLID)
199 {
200 PenObject->BrushAttr.lbColor = Color & 0xFFFFFF;
201 }
202 PENOBJ_UnlockPen(PenObject);
203 }
204 }
205
206 INT APIENTRY
207 PEN_GetObject(PGDIBRUSHOBJ pPenObject, INT cbCount, PLOGPEN pBuffer)
208 {
209 PLOGPEN pLogPen;
210 PEXTLOGPEN pExtLogPen;
211 INT cbRetCount;
212
213 if (pPenObject->flAttrs & GDIBRUSH_IS_OLDSTYLEPEN)
214 {
215 cbRetCount = sizeof(LOGPEN);
216 if (pBuffer)
217 {
218
219 if (cbCount < cbRetCount) return 0;
220
221 if ( (pPenObject->ulPenStyle & PS_STYLE_MASK) == PS_NULL &&
222 cbCount == sizeof(EXTLOGPEN))
223 {
224 pExtLogPen = (PEXTLOGPEN)pBuffer;
225 pExtLogPen->elpPenStyle = pPenObject->ulPenStyle;
226 pExtLogPen->elpWidth = 0;
227 pExtLogPen->elpBrushStyle = pPenObject->ulStyle;
228 pExtLogPen->elpColor = pPenObject->BrushAttr.lbColor;
229 pExtLogPen->elpHatch = 0;
230 pExtLogPen->elpNumEntries = 0;
231 cbRetCount = sizeof(EXTLOGPEN);
232 }
233 else
234 {
235 pLogPen = (PLOGPEN)pBuffer;
236 pLogPen->lopnWidth = pPenObject->ptPenWidth;
237 pLogPen->lopnStyle = pPenObject->ulPenStyle;
238 pLogPen->lopnColor = pPenObject->BrushAttr.lbColor;
239 }
240 }
241 }
242 else
243 {
244 // FIXME: Can we trust in dwStyleCount being <= 16?
245 cbRetCount = sizeof(EXTLOGPEN) - sizeof(DWORD) + pPenObject->dwStyleCount * sizeof(DWORD);
246 if (pBuffer)
247 {
248 INT i;
249
250 if (cbCount < cbRetCount) return 0;
251 pExtLogPen = (PEXTLOGPEN)pBuffer;
252 pExtLogPen->elpPenStyle = pPenObject->ulPenStyle;
253 pExtLogPen->elpWidth = pPenObject->ptPenWidth.x;
254 pExtLogPen->elpBrushStyle = pPenObject->ulStyle;
255 pExtLogPen->elpColor = pPenObject->BrushAttr.lbColor;
256 pExtLogPen->elpHatch = (ULONG_PTR)pPenObject->hbmClient;
257 pExtLogPen->elpNumEntries = pPenObject->dwStyleCount;
258 for (i = 0; i < pExtLogPen->elpNumEntries; i++)
259 {
260 pExtLogPen->elpStyleEntry[i] = pPenObject->pStyle[i];
261 }
262 }
263 }
264
265 return cbRetCount;
266 }
267
268
269 HPEN
270 FASTCALL
271 IntGdiSelectPen(
272 PDC pDC,
273 HPEN hPen)
274 {
275 PDC_ATTR pdcattr;
276 HPEN hOrgPen = NULL;
277 PGDIBRUSHOBJ pPen;
278 XLATEOBJ *XlateObj;
279 BOOLEAN bFailed;
280
281 if (pDC == NULL || hPen == NULL) return NULL;
282
283 pdcattr = pDC->pdcattr;
284
285 pPen = PENOBJ_LockPen(hPen);
286 if (pPen == NULL)
287 {
288 return NULL;
289 }
290
291 XlateObj = IntGdiCreateBrushXlate(pDC, pPen, &bFailed);
292 PENOBJ_UnlockPen(pPen);
293 if (bFailed)
294 {
295 SetLastWin32Error(ERROR_NO_SYSTEM_RESOURCES);
296 return NULL;
297 }
298
299 hOrgPen = pdcattr->hpen;
300 pdcattr->hpen = hPen;
301
302 if (pDC->rosdc.XlatePen != NULL)
303 {
304 EngDeleteXlate(pDC->rosdc.XlatePen);
305 }
306 pdcattr->ulDirty_ &= ~DC_PEN_DIRTY;
307
308 pDC->rosdc.XlatePen = XlateObj;
309
310 return hOrgPen;
311 }
312
313 /* PUBLIC FUNCTIONS ***********************************************************/
314
315 HPEN APIENTRY
316 NtGdiCreatePen(
317 INT PenStyle,
318 INT Width,
319 COLORREF Color,
320 IN HBRUSH hbr)
321 {
322 if ( PenStyle < PS_SOLID || PenStyle > PS_INSIDEFRAME )
323 {
324 SetLastWin32Error(ERROR_INVALID_PARAMETER);
325 return NULL;
326 }
327
328 return IntGdiExtCreatePen(PenStyle,
329 Width,
330 BS_SOLID,
331 Color,
332 0,
333 0,
334 0,
335 NULL,
336 0,
337 TRUE,
338 hbr);
339 }
340
341 HPEN APIENTRY
342 NtGdiExtCreatePen(
343 DWORD dwPenStyle,
344 DWORD ulWidth,
345 IN ULONG ulBrushStyle,
346 IN ULONG ulColor,
347 IN ULONG_PTR ulClientHatch,
348 IN ULONG_PTR ulHatch,
349 DWORD dwStyleCount,
350 PULONG pUnsafeStyle,
351 IN ULONG cjDIB,
352 IN BOOL bOldStylePen,
353 IN OPTIONAL HBRUSH hBrush)
354 {
355 NTSTATUS Status = STATUS_SUCCESS;
356 DWORD* pSafeStyle = NULL;
357 HPEN hPen;
358
359 if ((int)dwStyleCount < 0) return 0;
360 if (dwStyleCount > 16)
361 {
362 SetLastWin32Error(ERROR_INVALID_PARAMETER);
363 return 0;
364 }
365
366 if (dwStyleCount > 0)
367 {
368 pSafeStyle = ExAllocatePoolWithTag(NonPagedPool, dwStyleCount * sizeof(DWORD), TAG_PENSTYLES);
369 if (!pSafeStyle)
370 {
371 SetLastNtError(ERROR_NOT_ENOUGH_MEMORY);
372 return 0;
373 }
374 _SEH2_TRY
375 {
376 ProbeForRead(pUnsafeStyle, dwStyleCount * sizeof(DWORD), 1);
377 RtlCopyMemory(pSafeStyle,
378 pUnsafeStyle,
379 dwStyleCount * sizeof(DWORD));
380 }
381 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
382 {
383 Status = _SEH2_GetExceptionCode();
384 }
385 _SEH2_END
386 if(!NT_SUCCESS(Status))
387 {
388 SetLastNtError(Status);
389 ExFreePoolWithTag(pSafeStyle, TAG_PENSTYLES);
390 return 0;
391 }
392 }
393
394 if (ulBrushStyle == BS_PATTERN)
395 {
396 _SEH2_TRY
397 {
398 ProbeForRead((PVOID)ulHatch, cjDIB, 1);
399 }
400 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
401 {
402 Status = _SEH2_GetExceptionCode();
403 }
404 _SEH2_END
405 if(!NT_SUCCESS(Status))
406 {
407 SetLastNtError(Status);
408 if (pSafeStyle) ExFreePoolWithTag(pSafeStyle, TAG_PENSTYLES);
409 return 0;
410 }
411 }
412
413 hPen = IntGdiExtCreatePen(dwPenStyle,
414 ulWidth,
415 ulBrushStyle,
416 ulColor,
417 ulClientHatch,
418 ulHatch,
419 dwStyleCount,
420 pSafeStyle,
421 cjDIB,
422 bOldStylePen,
423 hBrush);
424
425 if (!hPen && pSafeStyle)
426 {
427 ExFreePoolWithTag(pSafeStyle, TAG_PENSTYLES);
428 }
429 return hPen;
430 }
431
432 /*
433 * @implemented
434 */
435 HPEN
436 APIENTRY
437 NtGdiSelectPen(
438 IN HDC hDC,
439 IN HPEN hPen)
440 {
441 PDC pDC;
442 HPEN hOrgPen;
443
444 if (hDC == NULL || hPen == NULL) return NULL;
445
446 pDC = DC_LockDc(hDC);
447 if (!pDC)
448 {
449 return NULL;
450 }
451
452 hOrgPen = IntGdiSelectPen(pDC,hPen);
453
454 DC_UnlockDc(pDC);
455
456 return hOrgPen;
457 }
458
459 /* EOF */