- Finnish up gdi wine pen cross test fixes.
[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,
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 STDCALL
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 pDc_Attr;
276 HPEN hOrgPen = NULL;
277 PGDIBRUSHOBJ pPen;
278 XLATEOBJ *XlateObj;
279 BOOLEAN bFailed;
280
281 if (pDC == NULL || hPen == NULL) return NULL;
282
283 pDc_Attr = pDC->pDc_Attr;
284 if(!pDc_Attr) pDc_Attr = &pDC->Dc_Attr;
285
286 pPen = PENOBJ_LockPen(hPen);
287 if (pPen == NULL)
288 {
289 return NULL;
290 }
291
292 XlateObj = IntGdiCreateBrushXlate(pDC, pPen, &bFailed);
293 PENOBJ_UnlockPen(pPen);
294 if (bFailed)
295 {
296 SetLastWin32Error(ERROR_NO_SYSTEM_RESOURCES);
297 return NULL;
298 }
299
300 hOrgPen = pDc_Attr->hpen;
301 pDc_Attr->hpen = hPen;
302
303 if (pDC->XlatePen != NULL)
304 {
305 EngDeleteXlate(pDC->XlatePen);
306 }
307 pDc_Attr->ulDirty_ &= ~DC_PEN_DIRTY;
308
309 pDC->XlatePen = XlateObj;
310
311 return hOrgPen;
312 }
313
314 /* PUBLIC FUNCTIONS ***********************************************************/
315
316 HPEN STDCALL
317 NtGdiCreatePen(
318 INT PenStyle,
319 INT Width,
320 COLORREF Color,
321 IN HBRUSH hbr)
322 {
323 if ( PenStyle < PS_SOLID || PenStyle > PS_INSIDEFRAME )
324 {
325 SetLastWin32Error(ERROR_INVALID_PARAMETER);
326 return NULL;
327 }
328
329 return IntGdiExtCreatePen(PenStyle,
330 Width,
331 BS_SOLID,
332 Color,
333 0,
334 0,
335 0,
336 NULL,
337 0,
338 TRUE,
339 hbr);
340 }
341
342 HPEN STDCALL
343 NtGdiExtCreatePen(
344 DWORD dwPenStyle,
345 DWORD ulWidth,
346 IN ULONG ulBrushStyle,
347 IN ULONG ulColor,
348 IN ULONG_PTR ulClientHatch,
349 IN ULONG_PTR ulHatch,
350 DWORD dwStyleCount,
351 PULONG pUnsafeStyle,
352 IN ULONG cjDIB,
353 IN BOOL bOldStylePen,
354 IN OPTIONAL HBRUSH hBrush)
355 {
356 NTSTATUS Status = STATUS_SUCCESS;
357 DWORD* pSafeStyle = NULL;
358 HPEN hPen;
359
360 if ((int)dwStyleCount < 0) return 0;
361 if (dwStyleCount > 16)
362 {
363 SetLastWin32Error(ERROR_INVALID_PARAMETER);
364 return 0;
365 }
366
367 if (dwStyleCount > 0)
368 {
369 pSafeStyle = ExAllocatePoolWithTag(NonPagedPool, dwStyleCount * sizeof(DWORD), TAG_PENSTYLES);
370 if (!pSafeStyle)
371 {
372 SetLastNtError(ERROR_NOT_ENOUGH_MEMORY);
373 return 0;
374 }
375 _SEH_TRY
376 {
377 ProbeForRead(pUnsafeStyle, dwStyleCount * sizeof(DWORD), 1);
378 RtlCopyMemory(pSafeStyle,
379 pUnsafeStyle,
380 dwStyleCount * sizeof(DWORD));
381 }
382 _SEH_HANDLE
383 {
384 Status = _SEH_GetExceptionCode();
385 }
386 _SEH_END
387 if(!NT_SUCCESS(Status))
388 {
389 SetLastNtError(Status);
390 ExFreePoolWithTag(pSafeStyle, TAG_PENSTYLES);
391 return 0;
392 }
393 }
394
395 if (ulBrushStyle == BS_PATTERN)
396 {
397 _SEH_TRY
398 {
399 ProbeForRead((PVOID)ulHatch, cjDIB, 1);
400 }
401 _SEH_HANDLE
402 {
403 Status = _SEH_GetExceptionCode();
404 }
405 _SEH_END
406 if(!NT_SUCCESS(Status))
407 {
408 SetLastNtError(Status);
409 if (pSafeStyle) ExFreePoolWithTag(pSafeStyle, TAG_PENSTYLES);
410 return 0;
411 }
412 }
413
414 hPen = IntGdiExtCreatePen(dwPenStyle,
415 ulWidth,
416 ulBrushStyle,
417 ulColor,
418 ulClientHatch,
419 ulHatch,
420 dwStyleCount,
421 pSafeStyle,
422 cjDIB,
423 bOldStylePen,
424 hBrush);
425
426 if (!hPen && pSafeStyle)
427 {
428 ExFreePoolWithTag(pSafeStyle, TAG_PENSTYLES);
429 }
430 return hPen;
431 }
432
433 /*
434 * @implemented
435 */
436 HPEN
437 APIENTRY
438 NtGdiSelectPen(
439 IN HDC hDC,
440 IN HPEN hPen)
441 {
442 PDC pDC;
443 HPEN hOrgPen;
444
445 if (hDC == NULL || hPen == NULL) return NULL;
446
447 pDC = DC_LockDc(hDC);
448 if (!pDC)
449 {
450 return NULL;
451 }
452
453 hOrgPen = IntGdiSelectPen(pDC,hPen);
454
455 DC_UnlockDc(pDC);
456
457 return hOrgPen;
458 }
459
460 /* EOF */