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