Update the address of the Free Software Foundation.
[wine] / dlls / gdi / pen.c
1 /*
2  * GDI pen objects
3  *
4  * Copyright 1993 Alexandre Julliard
5  *
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.
10  *
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.
15  *
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
19  */
20
21 #include "config.h"
22
23 #include <stdarg.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <assert.h>
27
28 #include "windef.h"
29 #include "winbase.h"
30 #include "wingdi.h"
31 #include "wine/wingdi16.h"
32 #include "gdi.h"
33 #include "gdi_private.h"
34 #include "wine/debug.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(gdi);
37
38   /* GDI logical pen object */
39 typedef struct
40 {
41     GDIOBJHDR header;
42     EXTLOGPEN logpen;
43 } PENOBJ;
44
45
46 static HGDIOBJ PEN_SelectObject( HGDIOBJ handle, void *obj, HDC hdc );
47 static INT PEN_GetObject16( HGDIOBJ handle, void *obj, INT count, LPVOID buffer );
48 static INT PEN_GetObject( HGDIOBJ handle, void *obj, INT count, LPVOID buffer );
49
50 static const struct gdi_obj_funcs pen_funcs =
51 {
52     PEN_SelectObject,  /* pSelectObject */
53     PEN_GetObject16,   /* pGetObject16 */
54     PEN_GetObject,     /* pGetObjectA */
55     PEN_GetObject,     /* pGetObjectW */
56     NULL,              /* pUnrealizeObject */
57     GDI_FreeObject     /* pDeleteObject */
58 };
59
60
61 /***********************************************************************
62  *           CreatePen    (GDI32.@)
63  */
64 HPEN WINAPI CreatePen( INT style, INT width, COLORREF color )
65 {
66     LOGPEN logpen;
67
68     TRACE("%d %d %06lx\n", style, width, color );
69
70     logpen.lopnStyle = style;
71     logpen.lopnWidth.x = width;
72     logpen.lopnWidth.y = 0;
73     logpen.lopnColor = color;
74
75     return CreatePenIndirect( &logpen );
76 }
77
78
79 /***********************************************************************
80  *           CreatePenIndirect    (GDI32.@)
81  */
82 HPEN WINAPI CreatePenIndirect( const LOGPEN * pen )
83 {
84     PENOBJ * penPtr;
85     HPEN hpen;
86
87     if (!(penPtr = GDI_AllocObject( sizeof(PENOBJ), PEN_MAGIC, (HGDIOBJ *)&hpen,
88                                     &pen_funcs ))) return 0;
89     if (pen->lopnStyle == PS_USERSTYLE || pen->lopnStyle == PS_ALTERNATE)
90         penPtr->logpen.elpPenStyle = PS_SOLID;
91     else
92         penPtr->logpen.elpPenStyle = pen->lopnStyle;
93     if (pen->lopnStyle == PS_NULL)
94     {
95         penPtr->logpen.elpWidth = 1;
96         penPtr->logpen.elpColor = RGB(0, 0, 0);
97     }
98     else
99     {
100         penPtr->logpen.elpWidth = abs(pen->lopnWidth.x);
101         penPtr->logpen.elpColor = pen->lopnColor;
102     }
103     penPtr->logpen.elpBrushStyle = BS_SOLID;
104     penPtr->logpen.elpHatch = 0;
105     penPtr->logpen.elpNumEntries = 0;
106     penPtr->logpen.elpStyleEntry[0] = 0;
107
108     GDI_ReleaseObj( hpen );
109     return hpen;
110 }
111
112 /***********************************************************************
113  *           ExtCreatePen    (GDI32.@)
114  *
115  * FIXME: PS_USERSTYLE not handled
116  */
117
118 HPEN WINAPI ExtCreatePen( DWORD style, DWORD width,
119                               const LOGBRUSH * brush, DWORD style_count,
120                               const DWORD *style_bits )
121 {
122     PENOBJ * penPtr;
123     HPEN hpen;
124
125     if ((style & PS_STYLE_MASK) == PS_USERSTYLE)
126     {
127         if (!style_count || !style_bits)
128         {
129             SetLastError(ERROR_INVALID_PARAMETER);
130             return 0;
131         }
132         /* FIXME: PS_USERSTYLE workaround */
133         FIXME("PS_USERSTYLE not handled\n");
134         style = (style & ~PS_STYLE_MASK) | PS_SOLID;
135     }
136     else
137     {
138         if (style_count || style_bits)
139         {
140             SetLastError(ERROR_INVALID_PARAMETER);
141             return 0;
142         }
143     }
144
145     if ((style & PS_STYLE_MASK) == PS_NULL)
146         return CreatePen( PS_NULL, 0, brush->lbColor );
147
148     if ((style & PS_TYPE_MASK) == PS_GEOMETRIC)
149     {
150         /* PS_ALTERNATE is applicable only for cosmetic pens */
151         if ((style & PS_STYLE_MASK) == PS_ALTERNATE)
152         {
153             SetLastError(ERROR_INVALID_PARAMETER);
154             return 0;
155         }
156
157         if (brush->lbHatch && ((brush->lbStyle == BS_SOLID) || (brush->lbStyle == BS_HOLLOW)))
158         {
159             static int fixme_hatches_shown;
160             if (!fixme_hatches_shown++) FIXME("Hatches not implemented\n");
161         }
162     }
163     else
164     {
165         /* PS_INSIDEFRAME is applicable only for gemetric pens */
166         if ((style & PS_STYLE_MASK) == PS_INSIDEFRAME || width != 1)
167         {
168             SetLastError(ERROR_INVALID_PARAMETER);
169             return 0;
170         }
171     }
172
173     if (!(penPtr = GDI_AllocObject( sizeof(PENOBJ) +
174                                     style_count * sizeof(DWORD) - sizeof(penPtr->logpen.elpStyleEntry),
175                                     EXT_PEN_MAGIC, (HGDIOBJ *)&hpen,
176                                     &pen_funcs ))) return 0;
177
178     penPtr->logpen.elpPenStyle = style;
179     penPtr->logpen.elpWidth = abs(width);
180     penPtr->logpen.elpBrushStyle = brush->lbStyle;
181     penPtr->logpen.elpColor = brush->lbColor;
182     penPtr->logpen.elpHatch = brush->lbHatch;
183     penPtr->logpen.elpNumEntries = style_count;
184     memcpy(penPtr->logpen.elpStyleEntry, style_bits, style_count * sizeof(DWORD));
185     
186     GDI_ReleaseObj( hpen );
187
188     return hpen;
189 }
190
191
192 /***********************************************************************
193  *           PEN_SelectObject
194  */
195 static HGDIOBJ PEN_SelectObject( HGDIOBJ handle, void *obj, HDC hdc )
196 {
197     HGDIOBJ ret;
198     DC *dc = DC_GetDCPtr( hdc );
199
200     if (!dc) return 0;
201     ret = dc->hPen;
202     if (dc->funcs->pSelectPen) handle = dc->funcs->pSelectPen( dc->physDev, handle );
203     if (handle) dc->hPen = handle;
204     else ret = 0;
205     GDI_ReleaseObj( hdc );
206     return ret;
207 }
208
209
210 /***********************************************************************
211  *           PEN_GetObject16
212  */
213 static INT PEN_GetObject16( HGDIOBJ handle, void *obj, INT count, LPVOID buffer )
214 {
215     PENOBJ *pen = obj;
216     LOGPEN16 *logpen;
217
218     if (!buffer) return sizeof(LOGPEN16);
219
220     if (count < sizeof(LOGPEN16)) return 0;
221
222     logpen = buffer;
223     logpen->lopnStyle = pen->logpen.elpPenStyle;
224     logpen->lopnColor = pen->logpen.elpColor;
225     logpen->lopnWidth.x = pen->logpen.elpWidth;
226     logpen->lopnWidth.y = 0;
227
228     return sizeof(LOGPEN16);
229 }
230
231
232 /***********************************************************************
233  *           PEN_GetObject
234  */
235 static INT PEN_GetObject( HGDIOBJ handle, void *obj, INT count, LPVOID buffer )
236 {
237     PENOBJ *pen = obj;
238
239     switch (GDIMAGIC(pen->header.wMagic))
240     {
241     case PEN_MAGIC:
242     {
243         LOGPEN *lp;
244
245         if (!buffer) return sizeof(LOGPEN);
246
247         if (count < sizeof(LOGPEN)) return 0;
248
249         if ((pen->logpen.elpPenStyle & PS_STYLE_MASK) == PS_NULL &&
250             count == sizeof(EXTLOGPEN))
251         {
252             EXTLOGPEN *elp = buffer;
253             memcpy(elp, &pen->logpen, sizeof(EXTLOGPEN));
254             elp->elpWidth = 0;
255             return sizeof(EXTLOGPEN);
256         }
257
258         lp = buffer;
259         lp->lopnStyle = pen->logpen.elpPenStyle;
260         lp->lopnColor = pen->logpen.elpColor;
261         lp->lopnWidth.x = pen->logpen.elpWidth;
262         lp->lopnWidth.y = 0;
263         return sizeof(LOGPEN);
264     }
265
266     case EXT_PEN_MAGIC:
267     {
268         INT size = sizeof(EXTLOGPEN) + pen->logpen.elpNumEntries * sizeof(DWORD) - sizeof(pen->logpen.elpStyleEntry);
269
270         if (!buffer) return size;
271
272         if (count < size) return 0;
273         memcpy(buffer, &pen->logpen, size);
274         return size;
275     }
276
277     default:
278         break;
279     }
280     assert(0);
281     return 0;
282 }