gdiplus: Use custom cap base inset differently.
[wine] / dlls / gdiplus / brush.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 "windef.h"
20 #include "wingdi.h"
21
22 #include "objbase.h"
23
24 #include "gdiplus.h"
25 #include "gdiplus_private.h"
26 #include "wine/debug.h"
27
28 WINE_DEFAULT_DEBUG_CHANNEL(gdiplus);
29
30 GpStatus WINGDIPAPI GdipCloneBrush(GpBrush *brush, GpBrush **clone)
31 {
32     if(!brush || !clone)
33         return InvalidParameter;
34
35     switch(brush->bt){
36         case BrushTypeSolidColor:
37             *clone = GdipAlloc(sizeof(GpSolidFill));
38             if (!*clone) return OutOfMemory;
39
40             memcpy(*clone, brush, sizeof(GpSolidFill));
41
42             (*clone)->gdibrush = CreateBrushIndirect(&(*clone)->lb);
43             break;
44         case BrushTypePathGradient:{
45             GpPathGradient *src, *dest;
46             INT count;
47
48             *clone = GdipAlloc(sizeof(GpPathGradient));
49             if (!*clone) return OutOfMemory;
50
51             src = (GpPathGradient*) brush,
52             dest = (GpPathGradient*) *clone;
53             count = src->pathdata.Count;
54
55             memcpy(dest, src, sizeof(GpPathGradient));
56
57             dest->pathdata.Count = count;
58             dest->pathdata.Points = GdipAlloc(count * sizeof(PointF));
59             dest->pathdata.Types = GdipAlloc(count);
60
61             if(!dest->pathdata.Points || !dest->pathdata.Types){
62                 GdipFree(dest->pathdata.Points);
63                 GdipFree(dest->pathdata.Types);
64                 GdipFree(dest);
65                 return OutOfMemory;
66             }
67
68             memcpy(dest->pathdata.Points, src->pathdata.Points, count * sizeof(PointF));
69             memcpy(dest->pathdata.Types, src->pathdata.Types, count);
70
71             break;
72         }
73         default:
74             return NotImplemented;
75     }
76
77     return Ok;
78 }
79
80 GpStatus WINGDIPAPI GdipCreatePathGradient(GDIPCONST GpPointF* points,
81     INT count, GpWrapMode wrap, GpPathGradient **grad)
82 {
83     COLORREF col = ARGB2COLORREF(0xffffffff);
84
85     if(!points || !grad)
86         return InvalidParameter;
87
88     if(count <= 0)
89         return OutOfMemory;
90
91     *grad = GdipAlloc(sizeof(GpPathGradient));
92     if (!*grad) return OutOfMemory;
93
94     (*grad)->pathdata.Count = count;
95     (*grad)->pathdata.Points = GdipAlloc(count * sizeof(PointF));
96     (*grad)->pathdata.Types = GdipAlloc(count);
97
98     if(!(*grad)->pathdata.Points || !(*grad)->pathdata.Types){
99         GdipFree((*grad)->pathdata.Points);
100         GdipFree((*grad)->pathdata.Types);
101         GdipFree(*grad);
102         return OutOfMemory;
103     }
104
105     memcpy((*grad)->pathdata.Points, points, count * sizeof(PointF));
106     memset((*grad)->pathdata.Types, PathPointTypeLine, count);
107
108     (*grad)->brush.lb.lbStyle = BS_SOLID;
109     (*grad)->brush.lb.lbColor = col;
110     (*grad)->brush.lb.lbHatch = 0;
111
112     (*grad)->brush.gdibrush = CreateSolidBrush(col);
113     (*grad)->brush.bt = BrushTypePathGradient;
114     (*grad)->centercolor = 0xffffffff;
115     (*grad)->wrap = wrap;
116     (*grad)->gamma = FALSE;
117     (*grad)->center.X = 0.0;
118     (*grad)->center.Y = 0.0;
119     (*grad)->focus.X = 0.0;
120     (*grad)->focus.Y = 0.0;
121
122     return Ok;
123 }
124
125 /* FIXME: path gradient brushes not truly supported (drawn as solid brushes) */
126 GpStatus WINGDIPAPI GdipCreatePathGradientFromPath(GDIPCONST GpPath* path,
127     GpPathGradient **grad)
128 {
129     COLORREF col = ARGB2COLORREF(0xffffffff);
130
131     if(!path || !grad)
132         return InvalidParameter;
133
134     *grad = GdipAlloc(sizeof(GpPathGradient));
135     if (!*grad) return OutOfMemory;
136
137     (*grad)->pathdata.Count = path->pathdata.Count;
138     (*grad)->pathdata.Points = GdipAlloc(path->pathdata.Count * sizeof(PointF));
139     (*grad)->pathdata.Types = GdipAlloc(path->pathdata.Count);
140
141     if(!(*grad)->pathdata.Points || !(*grad)->pathdata.Types){
142         GdipFree((*grad)->pathdata.Points);
143         GdipFree((*grad)->pathdata.Types);
144         GdipFree(*grad);
145         return OutOfMemory;
146     }
147
148     memcpy((*grad)->pathdata.Points, path->pathdata.Points,
149            path->pathdata.Count * sizeof(PointF));
150     memcpy((*grad)->pathdata.Types, path->pathdata.Types, path->pathdata.Count);
151
152     (*grad)->brush.lb.lbStyle = BS_SOLID;
153     (*grad)->brush.lb.lbColor = col;
154     (*grad)->brush.lb.lbHatch = 0;
155
156     (*grad)->brush.gdibrush = CreateSolidBrush(col);
157     (*grad)->brush.bt = BrushTypePathGradient;
158     (*grad)->centercolor = 0xffffffff;
159     (*grad)->wrap = WrapModeClamp;
160     (*grad)->gamma = FALSE;
161     /* FIXME: this should be set to the "centroid" of the path by default */
162     (*grad)->center.X = 0.0;
163     (*grad)->center.Y = 0.0;
164     (*grad)->focus.X = 0.0;
165     (*grad)->focus.Y = 0.0;
166
167     return Ok;
168 }
169
170 GpStatus WINGDIPAPI GdipCreateSolidFill(ARGB color, GpSolidFill **sf)
171 {
172     COLORREF col = ARGB2COLORREF(color);
173
174     if(!sf)  return InvalidParameter;
175
176     *sf = GdipAlloc(sizeof(GpSolidFill));
177     if (!*sf) return OutOfMemory;
178
179     (*sf)->brush.lb.lbStyle = BS_SOLID;
180     (*sf)->brush.lb.lbColor = col;
181     (*sf)->brush.lb.lbHatch = 0;
182
183     (*sf)->brush.gdibrush = CreateSolidBrush(col);
184     (*sf)->brush.bt = BrushTypeSolidColor;
185     (*sf)->color = color;
186
187     return Ok;
188 }
189
190 GpStatus WINGDIPAPI GdipGetBrushType(GpBrush *brush, GpBrushType *type)
191 {
192     if(!brush || !type)  return InvalidParameter;
193
194     *type = brush->bt;
195
196     return Ok;
197 }
198
199 GpStatus WINGDIPAPI GdipDeleteBrush(GpBrush *brush)
200 {
201     if(!brush)  return InvalidParameter;
202
203     switch(brush->bt)
204     {
205         case BrushTypePathGradient:
206             GdipFree(((GpPathGradient*) brush)->pathdata.Points);
207             GdipFree(((GpPathGradient*) brush)->pathdata.Types);
208             break;
209         case BrushTypeSolidColor:
210         default:
211             break;
212     }
213
214     DeleteObject(brush->gdibrush);
215     GdipFree(brush);
216
217     return Ok;
218 }
219
220 GpStatus WINGDIPAPI GdipGetPathGradientCenterPoint(GpPathGradient *grad,
221     GpPointF *point)
222 {
223     if(!grad || !point)
224         return InvalidParameter;
225
226     point->X = grad->center.X;
227     point->Y = grad->center.Y;
228
229     return Ok;
230 }
231
232 GpStatus WINGDIPAPI GdipGetPathGradientFocusScales(GpPathGradient *grad,
233     REAL *x, REAL *y)
234 {
235     if(!grad || !x || !y)
236         return InvalidParameter;
237
238     *x = grad->focus.X;
239     *y = grad->focus.Y;
240
241     return Ok;
242 }
243
244 GpStatus WINGDIPAPI GdipGetPathGradientGammaCorrection(GpPathGradient *grad,
245     BOOL *gamma)
246 {
247     if(!grad || !gamma)
248         return InvalidParameter;
249
250     *gamma = grad->gamma;
251
252     return Ok;
253 }
254
255 GpStatus WINGDIPAPI GdipGetPathGradientPointCount(GpPathGradient *grad,
256     INT *count)
257 {
258     if(!grad || !count)
259         return InvalidParameter;
260
261     *count = grad->pathdata.Count;
262
263     return Ok;
264 }
265
266 GpStatus WINGDIPAPI GdipGetPathGradientSurroundColorsWithCount(GpPathGradient
267     *grad, ARGB *argb, INT *count)
268 {
269     static int calls;
270
271     if(!grad || !argb || !count || (*count < grad->pathdata.Count))
272         return InvalidParameter;
273
274     if(!(calls++))
275         FIXME("not implemented\n");
276
277     return NotImplemented;
278 }
279
280 GpStatus WINGDIPAPI GdipGetSolidFillColor(GpSolidFill *sf, ARGB *argb)
281 {
282     if(!sf || !argb)
283         return InvalidParameter;
284
285     *argb = sf->color;
286
287     return Ok;
288 }
289
290 GpStatus WINGDIPAPI GdipSetPathGradientCenterColor(GpPathGradient *grad,
291     ARGB argb)
292 {
293     if(!grad)
294         return InvalidParameter;
295
296     grad->centercolor = argb;
297     grad->brush.lb.lbColor = ARGB2COLORREF(argb);
298
299     DeleteObject(grad->brush.gdibrush);
300     grad->brush.gdibrush = CreateSolidBrush(grad->brush.lb.lbColor);
301
302     return Ok;
303 }
304
305 GpStatus WINGDIPAPI GdipSetPathGradientCenterPoint(GpPathGradient *grad,
306     GpPointF *point)
307 {
308     if(!grad || !point)
309         return InvalidParameter;
310
311     grad->center.X = point->X;
312     grad->center.Y = point->Y;
313
314     return Ok;
315 }
316
317 GpStatus WINGDIPAPI GdipSetPathGradientFocusScales(GpPathGradient *grad,
318     REAL x, REAL y)
319 {
320     if(!grad)
321         return InvalidParameter;
322
323     grad->focus.X = x;
324     grad->focus.Y = y;
325
326     return Ok;
327 }
328
329 GpStatus WINGDIPAPI GdipSetPathGradientGammaCorrection(GpPathGradient *grad,
330     BOOL gamma)
331 {
332     if(!grad)
333         return InvalidParameter;
334
335     grad->gamma = gamma;
336
337     return Ok;
338 }
339
340 GpStatus WINGDIPAPI GdipSetPathGradientSigmaBlend(GpPathGradient *grad,
341     REAL focus, REAL scale)
342 {
343     static int calls;
344
345     if(!grad || focus < 0.0 || focus > 1.0 || scale < 0.0 || scale > 1.0)
346         return InvalidParameter;
347
348     if(!(calls++))
349         FIXME("not implemented\n");
350
351     return NotImplemented;
352 }
353
354 GpStatus WINGDIPAPI GdipSetPathGradientSurroundColorsWithCount(GpPathGradient
355     *grad, ARGB *argb, INT *count)
356 {
357     static int calls;
358
359     if(!grad || !argb || !count || (*count <= 0) ||
360         (*count > grad->pathdata.Count))
361         return InvalidParameter;
362
363     if(!(calls++))
364         FIXME("not implemented\n");
365
366     return NotImplemented;
367 }
368
369 GpStatus WINGDIPAPI GdipSetPathGradientWrapMode(GpPathGradient *grad,
370     GpWrapMode wrap)
371 {
372     if(!grad)
373         return InvalidParameter;
374
375     grad->wrap = wrap;
376
377     return Ok;
378 }
379
380 GpStatus WINGDIPAPI GdipSetSolidFillColor(GpSolidFill *sf, ARGB argb)
381 {
382     if(!sf)
383         return InvalidParameter;
384
385     sf->color = argb;
386     sf->brush.lb.lbColor = ARGB2COLORREF(argb);
387
388     DeleteObject(sf->brush.gdibrush);
389     sf->brush.gdibrush = CreateSolidBrush(sf->brush.lb.lbColor);
390
391     return Ok;
392 }