gdiplus: Added GdipSetLineWrapMode.
[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 GdipCreateLineBrush(GDIPCONST GpPointF* startpoint,
81     GDIPCONST GpPointF* endpoint, ARGB startcolor, ARGB endcolor,
82     GpWrapMode wrap, GpLineGradient **line)
83 {
84     COLORREF col = ARGB2COLORREF(startcolor);
85
86     if(!line || !startpoint || !endpoint || wrap == WrapModeClamp)
87         return InvalidParameter;
88
89     *line = GdipAlloc(sizeof(GpLineGradient));
90     if(!*line)  return OutOfMemory;
91
92     (*line)->brush.lb.lbStyle = BS_SOLID;
93     (*line)->brush.lb.lbColor = col;
94     (*line)->brush.lb.lbHatch = 0;
95     (*line)->brush.gdibrush = CreateSolidBrush(col);
96     (*line)->brush.bt = BrushTypeLinearGradient;
97
98     (*line)->startpoint.X = startpoint->X;
99     (*line)->startpoint.Y = startpoint->Y;
100     (*line)->endpoint.X = endpoint->X;
101     (*line)->endpoint.Y = endpoint->Y;
102     (*line)->startcolor = startcolor;
103     (*line)->endcolor = endcolor;
104     (*line)->wrap = wrap;
105
106     return Ok;
107 }
108
109 GpStatus WINGDIPAPI GdipCreatePathGradient(GDIPCONST GpPointF* points,
110     INT count, GpWrapMode wrap, GpPathGradient **grad)
111 {
112     COLORREF col = ARGB2COLORREF(0xffffffff);
113
114     if(!points || !grad)
115         return InvalidParameter;
116
117     if(count <= 0)
118         return OutOfMemory;
119
120     *grad = GdipAlloc(sizeof(GpPathGradient));
121     if (!*grad) return OutOfMemory;
122
123     (*grad)->pathdata.Count = count;
124     (*grad)->pathdata.Points = GdipAlloc(count * sizeof(PointF));
125     (*grad)->pathdata.Types = GdipAlloc(count);
126
127     if(!(*grad)->pathdata.Points || !(*grad)->pathdata.Types){
128         GdipFree((*grad)->pathdata.Points);
129         GdipFree((*grad)->pathdata.Types);
130         GdipFree(*grad);
131         return OutOfMemory;
132     }
133
134     memcpy((*grad)->pathdata.Points, points, count * sizeof(PointF));
135     memset((*grad)->pathdata.Types, PathPointTypeLine, count);
136
137     (*grad)->brush.lb.lbStyle = BS_SOLID;
138     (*grad)->brush.lb.lbColor = col;
139     (*grad)->brush.lb.lbHatch = 0;
140
141     (*grad)->brush.gdibrush = CreateSolidBrush(col);
142     (*grad)->brush.bt = BrushTypePathGradient;
143     (*grad)->centercolor = 0xffffffff;
144     (*grad)->wrap = wrap;
145     (*grad)->gamma = FALSE;
146     (*grad)->center.X = 0.0;
147     (*grad)->center.Y = 0.0;
148     (*grad)->focus.X = 0.0;
149     (*grad)->focus.Y = 0.0;
150
151     return Ok;
152 }
153
154 /* FIXME: path gradient brushes not truly supported (drawn as solid brushes) */
155 GpStatus WINGDIPAPI GdipCreatePathGradientFromPath(GDIPCONST GpPath* path,
156     GpPathGradient **grad)
157 {
158     COLORREF col = ARGB2COLORREF(0xffffffff);
159
160     if(!path || !grad)
161         return InvalidParameter;
162
163     *grad = GdipAlloc(sizeof(GpPathGradient));
164     if (!*grad) return OutOfMemory;
165
166     (*grad)->pathdata.Count = path->pathdata.Count;
167     (*grad)->pathdata.Points = GdipAlloc(path->pathdata.Count * sizeof(PointF));
168     (*grad)->pathdata.Types = GdipAlloc(path->pathdata.Count);
169
170     if(!(*grad)->pathdata.Points || !(*grad)->pathdata.Types){
171         GdipFree((*grad)->pathdata.Points);
172         GdipFree((*grad)->pathdata.Types);
173         GdipFree(*grad);
174         return OutOfMemory;
175     }
176
177     memcpy((*grad)->pathdata.Points, path->pathdata.Points,
178            path->pathdata.Count * sizeof(PointF));
179     memcpy((*grad)->pathdata.Types, path->pathdata.Types, path->pathdata.Count);
180
181     (*grad)->brush.lb.lbStyle = BS_SOLID;
182     (*grad)->brush.lb.lbColor = col;
183     (*grad)->brush.lb.lbHatch = 0;
184
185     (*grad)->brush.gdibrush = CreateSolidBrush(col);
186     (*grad)->brush.bt = BrushTypePathGradient;
187     (*grad)->centercolor = 0xffffffff;
188     (*grad)->wrap = WrapModeClamp;
189     (*grad)->gamma = FALSE;
190     /* FIXME: this should be set to the "centroid" of the path by default */
191     (*grad)->center.X = 0.0;
192     (*grad)->center.Y = 0.0;
193     (*grad)->focus.X = 0.0;
194     (*grad)->focus.Y = 0.0;
195
196     return Ok;
197 }
198
199 GpStatus WINGDIPAPI GdipCreateSolidFill(ARGB color, GpSolidFill **sf)
200 {
201     COLORREF col = ARGB2COLORREF(color);
202
203     if(!sf)  return InvalidParameter;
204
205     *sf = GdipAlloc(sizeof(GpSolidFill));
206     if (!*sf) return OutOfMemory;
207
208     (*sf)->brush.lb.lbStyle = BS_SOLID;
209     (*sf)->brush.lb.lbColor = col;
210     (*sf)->brush.lb.lbHatch = 0;
211
212     (*sf)->brush.gdibrush = CreateSolidBrush(col);
213     (*sf)->brush.bt = BrushTypeSolidColor;
214     (*sf)->color = color;
215
216     return Ok;
217 }
218
219 GpStatus WINGDIPAPI GdipGetBrushType(GpBrush *brush, GpBrushType *type)
220 {
221     if(!brush || !type)  return InvalidParameter;
222
223     *type = brush->bt;
224
225     return Ok;
226 }
227
228 GpStatus WINGDIPAPI GdipDeleteBrush(GpBrush *brush)
229 {
230     if(!brush)  return InvalidParameter;
231
232     switch(brush->bt)
233     {
234         case BrushTypePathGradient:
235             GdipFree(((GpPathGradient*) brush)->pathdata.Points);
236             GdipFree(((GpPathGradient*) brush)->pathdata.Types);
237             break;
238         case BrushTypeSolidColor:
239         default:
240             break;
241     }
242
243     DeleteObject(brush->gdibrush);
244     GdipFree(brush);
245
246     return Ok;
247 }
248
249 GpStatus WINGDIPAPI GdipGetPathGradientCenterPoint(GpPathGradient *grad,
250     GpPointF *point)
251 {
252     if(!grad || !point)
253         return InvalidParameter;
254
255     point->X = grad->center.X;
256     point->Y = grad->center.Y;
257
258     return Ok;
259 }
260
261 GpStatus WINGDIPAPI GdipGetPathGradientFocusScales(GpPathGradient *grad,
262     REAL *x, REAL *y)
263 {
264     if(!grad || !x || !y)
265         return InvalidParameter;
266
267     *x = grad->focus.X;
268     *y = grad->focus.Y;
269
270     return Ok;
271 }
272
273 GpStatus WINGDIPAPI GdipGetPathGradientGammaCorrection(GpPathGradient *grad,
274     BOOL *gamma)
275 {
276     if(!grad || !gamma)
277         return InvalidParameter;
278
279     *gamma = grad->gamma;
280
281     return Ok;
282 }
283
284 GpStatus WINGDIPAPI GdipGetPathGradientPointCount(GpPathGradient *grad,
285     INT *count)
286 {
287     if(!grad || !count)
288         return InvalidParameter;
289
290     *count = grad->pathdata.Count;
291
292     return Ok;
293 }
294
295 GpStatus WINGDIPAPI GdipGetPathGradientSurroundColorsWithCount(GpPathGradient
296     *grad, ARGB *argb, INT *count)
297 {
298     static int calls;
299
300     if(!grad || !argb || !count || (*count < grad->pathdata.Count))
301         return InvalidParameter;
302
303     if(!(calls++))
304         FIXME("not implemented\n");
305
306     return NotImplemented;
307 }
308
309 GpStatus WINGDIPAPI GdipGetSolidFillColor(GpSolidFill *sf, ARGB *argb)
310 {
311     if(!sf || !argb)
312         return InvalidParameter;
313
314     *argb = sf->color;
315
316     return Ok;
317 }
318
319 GpStatus WINGDIPAPI GdipSetLineWrapMode(GpLineGradient *line,
320     GpWrapMode wrap)
321 {
322     if(!line || wrap == WrapModeClamp)
323         return InvalidParameter;
324
325     line->wrap = wrap;
326
327     return Ok;
328 }
329
330 GpStatus WINGDIPAPI GdipSetPathGradientCenterColor(GpPathGradient *grad,
331     ARGB argb)
332 {
333     if(!grad)
334         return InvalidParameter;
335
336     grad->centercolor = argb;
337     grad->brush.lb.lbColor = ARGB2COLORREF(argb);
338
339     DeleteObject(grad->brush.gdibrush);
340     grad->brush.gdibrush = CreateSolidBrush(grad->brush.lb.lbColor);
341
342     return Ok;
343 }
344
345 GpStatus WINGDIPAPI GdipSetPathGradientCenterPoint(GpPathGradient *grad,
346     GpPointF *point)
347 {
348     if(!grad || !point)
349         return InvalidParameter;
350
351     grad->center.X = point->X;
352     grad->center.Y = point->Y;
353
354     return Ok;
355 }
356
357 GpStatus WINGDIPAPI GdipSetPathGradientFocusScales(GpPathGradient *grad,
358     REAL x, REAL y)
359 {
360     if(!grad)
361         return InvalidParameter;
362
363     grad->focus.X = x;
364     grad->focus.Y = y;
365
366     return Ok;
367 }
368
369 GpStatus WINGDIPAPI GdipSetPathGradientGammaCorrection(GpPathGradient *grad,
370     BOOL gamma)
371 {
372     if(!grad)
373         return InvalidParameter;
374
375     grad->gamma = gamma;
376
377     return Ok;
378 }
379
380 GpStatus WINGDIPAPI GdipSetPathGradientSigmaBlend(GpPathGradient *grad,
381     REAL focus, REAL scale)
382 {
383     static int calls;
384
385     if(!grad || focus < 0.0 || focus > 1.0 || scale < 0.0 || scale > 1.0)
386         return InvalidParameter;
387
388     if(!(calls++))
389         FIXME("not implemented\n");
390
391     return NotImplemented;
392 }
393
394 GpStatus WINGDIPAPI GdipSetPathGradientSurroundColorsWithCount(GpPathGradient
395     *grad, ARGB *argb, INT *count)
396 {
397     static int calls;
398
399     if(!grad || !argb || !count || (*count <= 0) ||
400         (*count > grad->pathdata.Count))
401         return InvalidParameter;
402
403     if(!(calls++))
404         FIXME("not implemented\n");
405
406     return NotImplemented;
407 }
408
409 GpStatus WINGDIPAPI GdipSetPathGradientWrapMode(GpPathGradient *grad,
410     GpWrapMode wrap)
411 {
412     if(!grad)
413         return InvalidParameter;
414
415     grad->wrap = wrap;
416
417     return Ok;
418 }
419
420 GpStatus WINGDIPAPI GdipSetSolidFillColor(GpSolidFill *sf, ARGB argb)
421 {
422     if(!sf)
423         return InvalidParameter;
424
425     sf->color = argb;
426     sf->brush.lb.lbColor = ARGB2COLORREF(argb);
427
428     DeleteObject(sf->brush.gdibrush);
429     sf->brush.gdibrush = CreateSolidBrush(sf->brush.lb.lbColor);
430
431     return Ok;
432 }