[NtGDI] Set Xform flags if a changed
[reactos.git] / win32ss / gdi / ntgdi / pen.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Pen functiona
5 * FILE: win32ss/gdi/ntgdi/pen.c
6 * PROGRAMER:
7 */
8
9 #include <win32k.h>
10
11 #define NDEBUG
12 #include <debug.h>
13
14 /* PRIVATE FUNCTIONS **********************************************************/
15
16 static
17 VOID
18 PEN_vInit(
19 PPEN ppen)
20 {
21 /* Start with kmode brush attribute */
22 ppen->pBrushAttr = &ppen->BrushAttr;
23 }
24
25 PBRUSH
26 NTAPI
27 PEN_AllocPenWithHandle(
28 VOID)
29 {
30 PPEN ppen;
31
32 ppen = (PBRUSH)GDIOBJ_AllocObjWithHandle(GDILoObjType_LO_PEN_TYPE, sizeof(PEN));
33 if (ppen == NULL)
34 {
35 return NULL;
36 }
37
38 PEN_vInit(ppen);
39 return ppen;
40 }
41
42 PBRUSH
43 NTAPI
44 PEN_AllocExtPenWithHandle(
45 VOID)
46 {
47 PPEN ppen;
48
49 ppen = (PBRUSH)GDIOBJ_AllocObjWithHandle(GDILoObjType_LO_EXTPEN_TYPE, sizeof(PEN));
50 if (ppen == NULL)
51 {
52 return NULL;
53 }
54
55 PEN_vInit(ppen);
56 return ppen;
57 }
58
59 PBRUSH
60 FASTCALL
61 PEN_ShareLockPen(HPEN hobj)
62 {
63 if ((GDI_HANDLE_GET_TYPE(hobj) != GDILoObjType_LO_PEN_TYPE) &&
64 (GDI_HANDLE_GET_TYPE(hobj) != GDILoObjType_LO_EXTPEN_TYPE))
65 {
66 return NULL;
67 }
68
69 return (PBRUSH)GDIOBJ_ReferenceObjectByHandle(hobj, GDIObjType_BRUSH_TYPE);
70 }
71
72 HPEN
73 APIENTRY
74 IntGdiExtCreatePen(
75 DWORD dwPenStyle,
76 DWORD dwWidth,
77 IN ULONG ulBrushStyle,
78 IN ULONG ulColor,
79 IN ULONG_PTR ulClientHatch,
80 IN ULONG_PTR ulHatch,
81 DWORD dwStyleCount,
82 PULONG pStyle,
83 IN ULONG cjDIB,
84 IN BOOL bOldStylePen,
85 IN OPTIONAL HBRUSH hbrush)
86 {
87 HPEN hPen;
88 PBRUSH pbrushPen;
89 static ULONG aulStyleAlternate[] = { 1, 1 };
90 static ULONG aulStyleDash[] = { 6, 2 };
91 static ULONG aulStyleDot[] = { 1, 1 };
92 static ULONG aulStyleDashDot[] = { 3, 2, 1, 2 };
93 static ULONG aulStyleDashDotDot[] = { 3, 1, 1, 1, 1, 1 };
94 ULONG i;
95
96 dwWidth = abs(dwWidth);
97
98 if ( (dwPenStyle & PS_STYLE_MASK) == PS_NULL)
99 {
100 return StockObjects[NULL_PEN];
101 }
102
103 if (bOldStylePen)
104 {
105 pbrushPen = PEN_AllocPenWithHandle();
106 }
107 else
108 {
109 pbrushPen = PEN_AllocExtPenWithHandle();
110 }
111
112 if (!pbrushPen)
113 {
114 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
115 DPRINT("Can't allocate pen\n");
116 return 0;
117 }
118 hPen = pbrushPen->BaseObject.hHmgr;
119
120 // If nWidth is zero, the pen is a single pixel wide, regardless of the current transformation.
121 if ((bOldStylePen) && (!dwWidth) && ((dwPenStyle & PS_STYLE_MASK) != PS_SOLID))
122 dwWidth = 1;
123
124 pbrushPen->lWidth = dwWidth;
125 FLOATOBJ_SetLong(&pbrushPen->eWidth, pbrushPen->lWidth);
126 pbrushPen->ulPenStyle = dwPenStyle;
127 pbrushPen->BrushAttr.lbColor = ulColor;
128 pbrushPen->iBrushStyle = ulBrushStyle;
129 // FIXME: Copy the bitmap first ?
130 pbrushPen->hbmClient = (HANDLE)ulClientHatch;
131 pbrushPen->dwStyleCount = 0;
132 pbrushPen->pStyle = NULL;
133 pbrushPen->ulStyleSize = 0;
134
135 pbrushPen->flAttrs = bOldStylePen ? BR_IS_OLDSTYLEPEN : BR_IS_PEN;
136
137 // If dwPenStyle is PS_COSMETIC, the width must be set to 1.
138 if ( !(bOldStylePen) && ((dwPenStyle & PS_TYPE_MASK) == PS_COSMETIC) && ( dwWidth != 1) )
139 goto ExitCleanup;
140 // If dwPenStyle is PS_COSMETIC, the brush style must be BS_SOLID.
141 if ( !(bOldStylePen) && ((dwPenStyle & PS_TYPE_MASK) == PS_COSMETIC) && (ulBrushStyle != BS_SOLID) )
142 goto ExitCleanup;
143
144 switch (dwPenStyle & PS_STYLE_MASK)
145 {
146 case PS_NULL:
147 pbrushPen->flAttrs |= BR_IS_NULL;
148 break;
149
150 case PS_SOLID:
151 pbrushPen->flAttrs |= BR_IS_SOLID;
152 break;
153
154 case PS_ALTERNATE:
155 pbrushPen->flAttrs |= BR_IS_SOLID | BR_IS_DEFAULTSTYLE;
156 pbrushPen->pStyle = aulStyleAlternate;
157 pbrushPen->dwStyleCount = _countof(aulStyleAlternate);
158 break;
159
160 case PS_DOT:
161 pbrushPen->flAttrs |= BR_IS_SOLID | BR_IS_DEFAULTSTYLE;
162 pbrushPen->pStyle = aulStyleDot;
163 pbrushPen->dwStyleCount = _countof(aulStyleDot);
164 break;
165
166 case PS_DASH:
167 pbrushPen->flAttrs |= BR_IS_SOLID | BR_IS_DEFAULTSTYLE;
168 pbrushPen->pStyle = aulStyleDash;
169 pbrushPen->dwStyleCount = _countof(aulStyleDash);
170 break;
171
172 case PS_DASHDOT:
173 pbrushPen->flAttrs |= BR_IS_SOLID | BR_IS_DEFAULTSTYLE;
174 pbrushPen->pStyle = aulStyleDashDot;
175 pbrushPen->dwStyleCount = _countof(aulStyleDashDot);
176 break;
177
178 case PS_DASHDOTDOT:
179 pbrushPen->flAttrs |= BR_IS_SOLID | BR_IS_DEFAULTSTYLE;
180 pbrushPen->pStyle = aulStyleDashDotDot;
181 pbrushPen->dwStyleCount = _countof(aulStyleDashDotDot);
182 break;
183
184 case PS_INSIDEFRAME:
185 pbrushPen->flAttrs |= (BR_IS_SOLID | BR_IS_INSIDEFRAME);
186 break;
187
188 case PS_USERSTYLE:
189 {
190 UINT i;
191 BOOL has_neg = FALSE, all_zero = TRUE;
192
193 for(i = 0; (i < dwStyleCount) && !has_neg; i++)
194 {
195 has_neg = has_neg || (((INT)(pStyle[i])) < 0);
196 all_zero = all_zero && (pStyle[i] == 0);
197 }
198
199 if(all_zero || has_neg)
200 {
201 goto ExitCleanup;
202 }
203 }
204 /* FIXME: What style here? */
205 pbrushPen->flAttrs |= BR_IS_SOLID;
206 pbrushPen->dwStyleCount = dwStyleCount;
207 pbrushPen->pStyle = pStyle;
208 break;
209
210 default:
211 DPRINT1("IntGdiExtCreatePen unknown penstyle %x\n", dwPenStyle);
212 goto ExitCleanup;
213 }
214
215 if (pbrushPen->pStyle != NULL)
216 {
217 for (i = 0; i < pbrushPen->dwStyleCount; i++)
218 {
219 pbrushPen->ulStyleSize += pbrushPen->pStyle[i];
220 }
221 }
222
223 NT_ASSERT((pbrushPen->dwStyleCount == 0) || (pbrushPen->pStyle != NULL));
224
225 PEN_UnlockPen(pbrushPen);
226 return hPen;
227
228 ExitCleanup:
229 EngSetLastError(ERROR_INVALID_PARAMETER);
230 pbrushPen->pStyle = NULL;
231 GDIOBJ_vDeleteObject(&pbrushPen->BaseObject);
232
233 return NULL;
234 }
235
236 VOID
237 FASTCALL
238 IntGdiSetSolidPenColor(HPEN hPen, COLORREF Color)
239 {
240 PBRUSH pbrPen;
241
242 pbrPen = PEN_ShareLockPen(hPen);
243 if (pbrPen)
244 {
245 if (pbrPen->flAttrs & BR_IS_SOLID)
246 {
247 pbrPen->BrushAttr.lbColor = Color & 0xFFFFFF;
248 }
249 PEN_ShareUnlockPen(pbrPen);
250 }
251 }
252
253 INT
254 APIENTRY
255 PEN_GetObject(PBRUSH pbrushPen, INT cbCount, PLOGPEN pBuffer)
256 {
257 PLOGPEN pLogPen;
258 PEXTLOGPEN pExtLogPen;
259 INT cbRetCount;
260
261 if (pbrushPen->flAttrs & BR_IS_OLDSTYLEPEN)
262 {
263 cbRetCount = sizeof(LOGPEN);
264 if (pBuffer)
265 {
266 if (cbCount < cbRetCount) return 0;
267
268 if (((pbrushPen->ulPenStyle & PS_STYLE_MASK) == PS_NULL) &&
269 (cbCount == sizeof(EXTLOGPEN)))
270 {
271 pExtLogPen = (PEXTLOGPEN)pBuffer;
272 pExtLogPen->elpPenStyle = pbrushPen->ulPenStyle;
273 pExtLogPen->elpWidth = 0;
274 pExtLogPen->elpBrushStyle = pbrushPen->iBrushStyle;
275 pExtLogPen->elpColor = pbrushPen->BrushAttr.lbColor;
276 pExtLogPen->elpHatch = 0;
277 pExtLogPen->elpNumEntries = 0;
278 cbRetCount = sizeof(EXTLOGPEN);
279 }
280 else
281 {
282 pLogPen = (PLOGPEN)pBuffer;
283 pLogPen->lopnWidth.x = pbrushPen->lWidth;
284 pLogPen->lopnWidth.y = 0;
285 pLogPen->lopnStyle = pbrushPen->ulPenStyle;
286 pLogPen->lopnColor = pbrushPen->BrushAttr.lbColor;
287 }
288 }
289 }
290 else
291 {
292 DWORD dwStyleCount = (pbrushPen->flAttrs & BR_IS_DEFAULTSTYLE) ?
293 0 : pbrushPen->dwStyleCount;
294 cbRetCount = sizeof(EXTLOGPEN) - sizeof(DWORD) + dwStyleCount * sizeof(DWORD);
295 if (pBuffer)
296 {
297 ULONG i;
298
299 if (cbCount < cbRetCount) return 0;
300 pExtLogPen = (PEXTLOGPEN)pBuffer;
301 pExtLogPen->elpPenStyle = pbrushPen->ulPenStyle;
302 pExtLogPen->elpWidth = pbrushPen->lWidth;
303 pExtLogPen->elpBrushStyle = pbrushPen->iBrushStyle;
304 pExtLogPen->elpColor = pbrushPen->BrushAttr.lbColor;
305 pExtLogPen->elpHatch = (ULONG_PTR)pbrushPen->hbmClient;
306 pExtLogPen->elpNumEntries = dwStyleCount;
307 for (i = 0; i < dwStyleCount; i++)
308 {
309 pExtLogPen->elpStyleEntry[i] = pbrushPen->pStyle[i];
310 }
311 }
312 }
313
314 return cbRetCount;
315 }
316
317
318 /* PUBLIC FUNCTIONS ***********************************************************/
319
320 HPEN
321 APIENTRY
322 NtGdiCreatePen(
323 INT PenStyle,
324 INT Width,
325 COLORREF Color,
326 IN HBRUSH hbr)
327 {
328 if ((PenStyle < PS_SOLID) ||( PenStyle > PS_INSIDEFRAME))
329 {
330 EngSetLastError(ERROR_INVALID_PARAMETER);
331 return NULL;
332 }
333
334 return IntGdiExtCreatePen(PenStyle,
335 Width,
336 BS_SOLID,
337 Color,
338 0,
339 0,
340 0,
341 NULL,
342 0,
343 TRUE,
344 hbr);
345 }
346
347 HPEN
348 APIENTRY
349 NtGdiExtCreatePen(
350 DWORD dwPenStyle,
351 DWORD ulWidth,
352 IN ULONG ulBrushStyle,
353 IN ULONG ulColor,
354 IN ULONG_PTR ulClientHatch,
355 IN ULONG_PTR ulHatch,
356 DWORD dwStyleCount,
357 PULONG pUnsafeStyle,
358 IN ULONG cjDIB,
359 IN BOOL bOldStylePen,
360 IN OPTIONAL HBRUSH hBrush)
361 {
362 NTSTATUS Status = STATUS_SUCCESS;
363 DWORD* pSafeStyle = NULL;
364 HPEN hPen;
365
366 if ((int)dwStyleCount < 0) return 0;
367 if (dwStyleCount > 16)
368 {
369 EngSetLastError(ERROR_INVALID_PARAMETER);
370 return 0;
371 }
372
373 if (((dwPenStyle & PS_TYPE_MASK) == PS_COSMETIC) &&
374 (ulBrushStyle != BS_SOLID))
375 {
376 EngSetLastError(ERROR_INVALID_PARAMETER);
377 return 0;
378 }
379
380 if (((dwPenStyle & PS_STYLE_MASK) == PS_NULL) ||
381 (ulBrushStyle == BS_NULL))
382 {
383 return StockObjects[NULL_PEN];
384 }
385
386
387 if ((ulBrushStyle == BS_PATTERN) ||
388 (ulBrushStyle == BS_DIBPATTERN) ||
389 (ulBrushStyle == BS_DIBPATTERNPT))
390 {
391 ulColor = 0;
392 }
393 else if ((ulBrushStyle != BS_SOLID) &&
394 (ulBrushStyle != BS_HATCHED))
395 {
396 EngSetLastError(ERROR_INVALID_PARAMETER);
397 return 0;
398 }
399
400 if ((dwPenStyle & PS_STYLE_MASK) != PS_USERSTYLE)
401 {
402 dwStyleCount = 0;
403 pUnsafeStyle = NULL;
404 }
405
406 if (dwStyleCount > 0)
407 {
408 if (pUnsafeStyle == NULL)
409 {
410 EngSetLastError(ERROR_INVALID_PARAMETER);
411 return 0;
412 }
413
414 pSafeStyle = ExAllocatePoolWithTag(NonPagedPool,
415 dwStyleCount * sizeof(DWORD),
416 GDITAG_PENSTYLE);
417 if (!pSafeStyle)
418 {
419 SetLastNtError(ERROR_NOT_ENOUGH_MEMORY);
420 return 0;
421 }
422 _SEH2_TRY
423 {
424 ProbeForRead(pUnsafeStyle, dwStyleCount * sizeof(DWORD), 1);
425 RtlCopyMemory(pSafeStyle,
426 pUnsafeStyle,
427 dwStyleCount * sizeof(DWORD));
428 }
429 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
430 {
431 Status = _SEH2_GetExceptionCode();
432 }
433 _SEH2_END
434 if(!NT_SUCCESS(Status))
435 {
436 SetLastNtError(Status);
437 ExFreePoolWithTag(pSafeStyle, GDITAG_PENSTYLE);
438 return 0;
439 }
440 }
441
442 if (ulBrushStyle == BS_PATTERN)
443 {
444 _SEH2_TRY
445 {
446 ProbeForRead((PVOID)ulHatch, cjDIB, 1);
447 }
448 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
449 {
450 Status = _SEH2_GetExceptionCode();
451 }
452 _SEH2_END
453 if(!NT_SUCCESS(Status))
454 {
455 SetLastNtError(Status);
456 if (pSafeStyle) ExFreePoolWithTag(pSafeStyle, GDITAG_PENSTYLE);
457 return 0;
458 }
459 }
460
461 hPen = IntGdiExtCreatePen(dwPenStyle,
462 ulWidth,
463 ulBrushStyle,
464 ulColor,
465 ulClientHatch,
466 ulHatch,
467 dwStyleCount,
468 pSafeStyle,
469 cjDIB,
470 bOldStylePen,
471 hBrush);
472
473 if (!hPen && pSafeStyle)
474 {
475 ExFreePoolWithTag(pSafeStyle, GDITAG_PENSTYLE);
476 }
477
478 return hPen;
479 }
480
481 /* EOF */