crypt32: Introduce function to encode an array of items as a set.
[wine] / dlls / gdiplus / pen.c
1 /*
2  * Copyright (C) 2007 Google (Evan Stade)
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #include <stdarg.h>
20
21 #include "windef.h"
22 #include "winbase.h"
23 #include "wingdi.h"
24 #include "gdiplus.h"
25 #include "gdiplus_private.h"
26 #include "wine/debug.h"
27
28 WINE_DEFAULT_DEBUG_CHANNEL(gdiplus);
29
30 static DWORD gdip_to_gdi_dash(GpDashStyle dash)
31 {
32     switch(dash){
33         case DashStyleSolid:
34             return PS_SOLID;
35         case DashStyleDash:
36             return PS_DASH;
37         case DashStyleDot:
38             return PS_DOT;
39         case DashStyleDashDot:
40             return PS_DASHDOT;
41         case DashStyleDashDotDot:
42             return PS_DASHDOTDOT;
43         case DashStyleCustom:
44             FIXME("DashStyleCustom not implemented\n");
45             return PS_SOLID;
46         default:
47             ERR("Not a member of GpDashStyle enumeration\n");
48             return 0;
49     }
50 }
51
52 static DWORD gdip_to_gdi_join(GpLineJoin join)
53 {
54     switch(join){
55         case LineJoinRound:
56             return PS_JOIN_ROUND;
57         case LineJoinBevel:
58             return PS_JOIN_BEVEL;
59         case LineJoinMiter:
60         case LineJoinMiterClipped:
61             return PS_JOIN_MITER;
62         default:
63             ERR("Not a member of GpLineJoin enumeration\n");
64             return 0;
65     }
66 }
67
68 GpStatus WINGDIPAPI GdipClonePen(GpPen *pen, GpPen **clonepen)
69 {
70     if(!pen || !clonepen)
71         return InvalidParameter;
72
73     *clonepen = GdipAlloc(sizeof(GpPen));
74     if(!*clonepen)  return OutOfMemory;
75
76     memcpy(*clonepen, pen, sizeof(GpPen));
77
78     GdipCloneCustomLineCap(pen->customstart, &(*clonepen)->customstart);
79     GdipCloneCustomLineCap(pen->customend, &(*clonepen)->customend);
80     GdipCloneBrush(pen->brush, &(*clonepen)->brush);
81
82     (*clonepen)->gdipen = ExtCreatePen((*clonepen)->style,
83                                        roundr((*clonepen)->width),
84                                        &(*clonepen)->brush->lb, 0, NULL);
85
86     return Ok;
87 }
88
89 GpStatus WINGDIPAPI GdipCreatePen1(ARGB color, FLOAT width, GpUnit unit,
90     GpPen **pen)
91 {
92     GpPen *gp_pen;
93
94     if(!pen)
95         return InvalidParameter;
96
97     gp_pen = GdipAlloc(sizeof(GpPen));
98     if(!gp_pen)    return OutOfMemory;
99
100     gp_pen->style = GP_DEFAULT_PENSTYLE;
101     gp_pen->color = ARGB2COLORREF(color);
102     gp_pen->width = width;
103     gp_pen->unit = unit;
104     gp_pen->endcap = LineCapFlat;
105     gp_pen->join = LineJoinMiter;
106     gp_pen->miterlimit = 10.0;
107     gp_pen->dash = DashStyleSolid;
108     GdipCreateSolidFill(color, (GpSolidFill **)(&gp_pen->brush));
109
110     if((gp_pen->unit == UnitWorld) || (gp_pen->unit == UnitPixel)) {
111         gp_pen->gdipen = ExtCreatePen(gp_pen->style, (INT) gp_pen->width,
112                                       &gp_pen->brush->lb, 0, NULL);
113     } else {
114         FIXME("UnitWorld, UnitPixel only supported units\n");
115         GdipFree(gp_pen);
116         return NotImplemented;
117     }
118
119     *pen = gp_pen;
120
121     return Ok;
122 }
123
124 GpStatus WINGDIPAPI GdipDeletePen(GpPen *pen)
125 {
126     if(!pen)    return InvalidParameter;
127     DeleteObject(pen->gdipen);
128
129     GdipDeleteBrush(pen->brush);
130     GdipDeleteCustomLineCap(pen->customstart);
131     GdipDeleteCustomLineCap(pen->customend);
132     GdipFree(pen);
133
134     return Ok;
135 }
136
137 GpStatus WINGDIPAPI GdipGetPenDashStyle(GpPen *pen, GpDashStyle *dash)
138 {
139     if(!pen || !dash)
140         return InvalidParameter;
141
142     *dash = pen->dash;
143
144     return Ok;
145 }
146
147 GpStatus WINGDIPAPI GdipSetPenCustomEndCap(GpPen *pen, GpCustomLineCap* customCap)
148 {
149     GpCustomLineCap * cap;
150     GpStatus ret;
151
152     if(!pen || !customCap) return InvalidParameter;
153
154     if((ret = GdipCloneCustomLineCap(customCap, &cap)) == Ok){
155         GdipDeleteCustomLineCap(pen->customend);
156         pen->endcap = LineCapCustom;
157         pen->customend = cap;
158     }
159
160     return ret;
161 }
162
163 GpStatus WINGDIPAPI GdipSetPenCustomStartCap(GpPen *pen, GpCustomLineCap* customCap)
164 {
165     GpCustomLineCap * cap;
166     GpStatus ret;
167
168     if(!pen || !customCap) return InvalidParameter;
169
170     if((ret = GdipCloneCustomLineCap(customCap, &cap)) == Ok){
171         GdipDeleteCustomLineCap(pen->customstart);
172         pen->startcap = LineCapCustom;
173         pen->customstart = cap;
174     }
175
176     return ret;
177 }
178
179 GpStatus WINGDIPAPI GdipSetPenDashStyle(GpPen *pen, GpDashStyle dash)
180 {
181     if(!pen)
182         return InvalidParameter;
183
184     DeleteObject(pen->gdipen);
185     pen->dash = dash;
186     pen->style &= ~(PS_ALTERNATE | PS_SOLID | PS_DASH | PS_DOT | PS_DASHDOT |
187                     PS_DASHDOTDOT | PS_NULL | PS_USERSTYLE | PS_INSIDEFRAME);
188     pen->style |= gdip_to_gdi_dash(dash);
189
190     pen->gdipen = ExtCreatePen(pen->style, (INT) pen->width, &pen->brush->lb, 0, NULL);
191
192     return Ok;
193 }
194
195 GpStatus WINGDIPAPI GdipSetPenEndCap(GpPen *pen, GpLineCap cap)
196 {
197     if(!pen)    return InvalidParameter;
198
199     /* The old custom cap gets deleted even if the new style is LineCapCustom. */
200     GdipDeleteCustomLineCap(pen->customend);
201     pen->customend = NULL;
202     pen->endcap = cap;
203
204     return Ok;
205 }
206
207 /* FIXME: startcap, dashcap not used. */
208 GpStatus WINGDIPAPI GdipSetPenLineCap197819(GpPen *pen, GpLineCap start,
209     GpLineCap end, GpDashCap dash)
210 {
211     if(!pen)
212         return InvalidParameter;
213
214     GdipDeleteCustomLineCap(pen->customend);
215     GdipDeleteCustomLineCap(pen->customstart);
216     pen->customend = NULL;
217     pen->customstart = NULL;
218
219     pen->startcap = start;
220     pen->endcap = end;
221     pen->dashcap = dash;
222
223     return Ok;
224 }
225
226 /* FIXME: Miter line joins behave a bit differently than they do in windows.
227  * Both kinds of miter joins clip if the angle is less than 11 degrees. */
228 GpStatus WINGDIPAPI GdipSetPenLineJoin(GpPen *pen, GpLineJoin join)
229 {
230     if(!pen)    return InvalidParameter;
231
232     DeleteObject(pen->gdipen);
233     pen->join = join;
234     pen->style &= ~(PS_JOIN_ROUND | PS_JOIN_BEVEL | PS_JOIN_MITER);
235     pen->style |= gdip_to_gdi_join(join);
236
237     pen->gdipen = ExtCreatePen(pen->style, (INT) pen->width, &pen->brush->lb, 0, NULL);
238
239     return Ok;
240 }
241
242 GpStatus WINGDIPAPI GdipSetPenMiterLimit(GpPen *pen, REAL limit)
243 {
244     if(!pen)
245         return InvalidParameter;
246
247     pen->miterlimit = limit;
248
249     return Ok;
250 }
251
252 GpStatus WINGDIPAPI GdipSetPenStartCap(GpPen *pen, GpLineCap cap)
253 {
254     if(!pen)    return InvalidParameter;
255
256     GdipDeleteCustomLineCap(pen->customstart);
257     pen->customstart = NULL;
258     pen->startcap = cap;
259
260     return Ok;
261 }