gdi32: Support MWT_SET in NtGdiModifyWorldTransform.
[wine.git] / dlls / gdi32 / pen.c
blob3b3ab78ecd7f18945c9371c4de6420b39e79e463
1 /*
2 * GDI pen objects
4 * Copyright 1993 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library 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 GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <assert.h>
26 #include "windef.h"
27 #include "winbase.h"
28 #include "wingdi.h"
29 #include "ntgdi_private.h"
30 #include "wine/debug.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(gdi);
34 /* GDI logical pen object */
35 typedef struct
37 struct gdi_obj_header obj;
38 struct brush_pattern pattern;
39 EXTLOGPEN logpen;
40 } PENOBJ;
43 static INT PEN_GetObject( HGDIOBJ handle, INT count, LPVOID buffer );
44 static BOOL PEN_DeleteObject( HGDIOBJ handle );
46 static const struct gdi_obj_funcs pen_funcs =
48 PEN_GetObject, /* pGetObjectW */
49 NULL, /* pUnrealizeObject */
50 PEN_DeleteObject /* pDeleteObject */
54 /***********************************************************************
55 * NtGdiCreatePen (win32u.@)
57 HPEN WINAPI NtGdiCreatePen( INT style, INT width, COLORREF color, HBRUSH brush )
59 PENOBJ *penPtr;
60 HPEN hpen;
62 TRACE( "%d %d %06x\n", style, width, color );
63 if (brush) FIXME( "brush not supported\n" );
65 switch (style)
67 case PS_SOLID:
68 case PS_DASH:
69 case PS_DOT:
70 case PS_DASHDOT:
71 case PS_DASHDOTDOT:
72 case PS_INSIDEFRAME:
73 break;
74 case PS_NULL:
75 if ((hpen = GetStockObject( NULL_PEN ))) return hpen;
76 width = 1;
77 color = 0;
78 break;
79 default:
80 return 0;
83 if (!(penPtr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*penPtr) ))) return 0;
85 penPtr->logpen.elpPenStyle = style;
86 penPtr->logpen.elpWidth = abs(width);
87 penPtr->logpen.elpColor = color;
88 penPtr->logpen.elpBrushStyle = BS_SOLID;
90 if (!(hpen = alloc_gdi_handle( &penPtr->obj, NTGDI_OBJ_PEN, &pen_funcs )))
91 HeapFree( GetProcessHeap(), 0, penPtr );
92 return hpen;
95 /***********************************************************************
96 * ExtCreatePen (GDI32.@)
99 HPEN WINAPI ExtCreatePen( DWORD style, DWORD width,
100 const LOGBRUSH * brush, DWORD style_count,
101 const DWORD *style_bits )
103 PENOBJ *penPtr = NULL;
104 HPEN hpen;
105 LOGBRUSH logbrush;
107 if ((style_count || style_bits) && (style & PS_STYLE_MASK) != PS_USERSTYLE)
108 goto invalid;
110 switch (style & PS_STYLE_MASK)
112 case PS_NULL:
113 return CreatePen( PS_NULL, 0, brush->lbColor );
115 case PS_SOLID:
116 case PS_DASH:
117 case PS_DOT:
118 case PS_DASHDOT:
119 case PS_DASHDOTDOT:
120 break;
122 case PS_USERSTYLE:
123 if (((INT)style_count) <= 0) return 0;
125 if ((style_count > 16) || !style_bits) goto invalid;
127 if ((style & PS_TYPE_MASK) == PS_GEOMETRIC)
129 UINT i;
130 BOOL has_neg = FALSE, all_zero = TRUE;
132 for(i = 0; (i < style_count) && !has_neg; i++)
134 has_neg = has_neg || (((INT)(style_bits[i])) < 0);
135 all_zero = all_zero && (style_bits[i] == 0);
138 if (all_zero || has_neg) goto invalid;
140 break;
142 case PS_INSIDEFRAME: /* applicable only for geometric pens */
143 if ((style & PS_TYPE_MASK) != PS_GEOMETRIC) goto invalid;
144 break;
146 case PS_ALTERNATE: /* applicable only for cosmetic pens */
147 if ((style & PS_TYPE_MASK) == PS_GEOMETRIC) goto invalid;
148 break;
150 default:
151 SetLastError(ERROR_INVALID_PARAMETER);
152 return 0;
155 if ((style & PS_TYPE_MASK) == PS_GEOMETRIC)
157 if (brush->lbStyle == BS_NULL) return CreatePen( PS_NULL, 0, 0 );
159 else
161 if (width != 1) goto invalid;
162 if (brush->lbStyle != BS_SOLID) goto invalid;
165 if (!(penPtr = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(PENOBJ,logpen.elpStyleEntry[style_count]))))
166 return 0;
168 logbrush = *brush;
169 if (!store_brush_pattern( &logbrush, &penPtr->pattern )) goto invalid;
170 if (logbrush.lbStyle == BS_DIBPATTERN) logbrush.lbStyle = BS_DIBPATTERNPT;
172 penPtr->logpen.elpPenStyle = style;
173 penPtr->logpen.elpWidth = abs((int)width);
174 penPtr->logpen.elpBrushStyle = logbrush.lbStyle;
175 penPtr->logpen.elpColor = logbrush.lbColor;
176 penPtr->logpen.elpHatch = brush->lbHatch;
177 penPtr->logpen.elpNumEntries = style_count;
178 memcpy(penPtr->logpen.elpStyleEntry, style_bits, style_count * sizeof(DWORD));
180 if (!(hpen = alloc_gdi_handle( &penPtr->obj, NTGDI_OBJ_EXTPEN, &pen_funcs )))
182 free_brush_pattern( &penPtr->pattern );
183 HeapFree( GetProcessHeap(), 0, penPtr );
185 return hpen;
187 invalid:
188 HeapFree( GetProcessHeap(), 0, penPtr );
189 SetLastError( ERROR_INVALID_PARAMETER );
190 return 0;
193 /***********************************************************************
194 * NtGdiSelectPen (win32u.@)
196 HGDIOBJ WINAPI NtGdiSelectPen( HDC hdc, HGDIOBJ handle )
198 PENOBJ *pen;
199 HGDIOBJ ret = 0;
200 WORD type;
201 DC *dc;
203 if (!(dc = get_dc_ptr( hdc ))) return 0;
205 if ((pen = get_any_obj_ptr( handle, &type )))
207 struct brush_pattern *pattern;
208 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSelectPen );
210 switch (type)
212 case NTGDI_OBJ_PEN:
213 pattern = NULL;
214 break;
215 case NTGDI_OBJ_EXTPEN:
216 pattern = &pen->pattern;
217 if (!pattern->info) pattern = NULL;
218 break;
219 default:
220 GDI_ReleaseObj( handle );
221 release_dc_ptr( dc );
222 return 0;
225 GDI_inc_ref_count( handle );
226 GDI_ReleaseObj( handle );
228 if (!physdev->funcs->pSelectPen( physdev, handle, pattern ))
230 GDI_dec_ref_count( handle );
232 else
234 ret = dc->hPen;
235 dc->hPen = handle;
236 GDI_dec_ref_count( ret );
239 release_dc_ptr( dc );
240 return ret;
244 /***********************************************************************
245 * PEN_DeleteObject
247 static BOOL PEN_DeleteObject( HGDIOBJ handle )
249 PENOBJ *pen = free_gdi_handle( handle );
251 if (!pen) return FALSE;
252 free_brush_pattern( &pen->pattern );
253 HeapFree( GetProcessHeap(), 0, pen );
254 return TRUE;
258 /***********************************************************************
259 * PEN_GetObject
261 static INT PEN_GetObject( HGDIOBJ handle, INT count, LPVOID buffer )
263 WORD type;
264 PENOBJ *pen = get_any_obj_ptr( handle, &type );
265 INT ret = 0;
267 if (!pen) return 0;
269 switch (type)
271 case NTGDI_OBJ_PEN:
273 LOGPEN *lp;
275 if (!buffer) ret = sizeof(LOGPEN);
276 else if (count < sizeof(LOGPEN)) ret = 0;
277 else if ((pen->logpen.elpPenStyle & PS_STYLE_MASK) == PS_NULL && count == sizeof(EXTLOGPEN))
279 EXTLOGPEN *elp = buffer;
280 *elp = pen->logpen;
281 elp->elpWidth = 0;
282 ret = sizeof(EXTLOGPEN);
284 else
286 lp = buffer;
287 lp->lopnStyle = pen->logpen.elpPenStyle;
288 lp->lopnColor = pen->logpen.elpColor;
289 lp->lopnWidth.x = pen->logpen.elpWidth;
290 lp->lopnWidth.y = 0;
291 ret = sizeof(LOGPEN);
293 break;
296 case NTGDI_OBJ_EXTPEN:
297 ret = sizeof(EXTLOGPEN) + pen->logpen.elpNumEntries * sizeof(DWORD) - sizeof(pen->logpen.elpStyleEntry);
298 if (buffer)
300 if (count < ret) ret = 0;
301 else memcpy(buffer, &pen->logpen, ret);
303 break;
305 GDI_ReleaseObj( handle );
306 return ret;