gdiplus: Stub GdipNewPrivateFontCollection.
[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
25 #include "objbase.h"
26
27 #include "gdiplus.h"
28 #include "gdiplus_private.h"
29 #include "wine/debug.h"
30
31 WINE_DEFAULT_DEBUG_CHANNEL(gdiplus);
32
33 static DWORD gdip_to_gdi_dash(GpDashStyle dash)
34 {
35     switch(dash){
36         case DashStyleSolid:
37             return PS_SOLID;
38         case DashStyleDash:
39             return PS_DASH;
40         case DashStyleDot:
41             return PS_DOT;
42         case DashStyleDashDot:
43             return PS_DASHDOT;
44         case DashStyleDashDotDot:
45             return PS_DASHDOTDOT;
46         case DashStyleCustom:
47             return PS_USERSTYLE;
48         default:
49             ERR("Not a member of GpDashStyle enumeration\n");
50             return 0;
51     }
52 }
53
54 static DWORD gdip_to_gdi_join(GpLineJoin join)
55 {
56     switch(join){
57         case LineJoinRound:
58             return PS_JOIN_ROUND;
59         case LineJoinBevel:
60             return PS_JOIN_BEVEL;
61         case LineJoinMiter:
62         case LineJoinMiterClipped:
63             return PS_JOIN_MITER;
64         default:
65             ERR("Not a member of GpLineJoin enumeration\n");
66             return 0;
67     }
68 }
69
70 GpStatus WINGDIPAPI GdipClonePen(GpPen *pen, GpPen **clonepen)
71 {
72     if(!pen || !clonepen)
73         return InvalidParameter;
74
75     *clonepen = GdipAlloc(sizeof(GpPen));
76     if(!*clonepen)  return OutOfMemory;
77
78     **clonepen = *pen;
79
80     GdipCloneCustomLineCap(pen->customstart, &(*clonepen)->customstart);
81     GdipCloneCustomLineCap(pen->customend, &(*clonepen)->customend);
82     GdipCloneBrush(pen->brush, &(*clonepen)->brush);
83
84     return Ok;
85 }
86
87 GpStatus WINGDIPAPI GdipCreatePen1(ARGB color, REAL width, GpUnit unit,
88     GpPen **pen)
89 {
90     GpBrush *brush;
91     GpStatus status;
92
93     GdipCreateSolidFill(color, (GpSolidFill **)(&brush));
94     status = GdipCreatePen2(brush, width, unit, pen);
95     GdipDeleteBrush(brush);
96     return status;
97 }
98
99 GpStatus WINGDIPAPI GdipCreatePen2(GpBrush *brush, REAL width, GpUnit unit,
100     GpPen **pen)
101 {
102     GpPen *gp_pen;
103     GpBrush *clone_brush;
104
105     if(!pen || !brush)
106         return InvalidParameter;
107
108     gp_pen = GdipAlloc(sizeof(GpPen));
109     if(!gp_pen)    return OutOfMemory;
110
111     gp_pen->style = GP_DEFAULT_PENSTYLE;
112     gp_pen->width = width;
113     gp_pen->unit = unit;
114     gp_pen->endcap = LineCapFlat;
115     gp_pen->join = LineJoinMiter;
116     gp_pen->miterlimit = 10.0;
117     gp_pen->dash = DashStyleSolid;
118     gp_pen->offset = 0.0;
119
120     if(!((gp_pen->unit == UnitWorld) || (gp_pen->unit == UnitPixel))) {
121         FIXME("UnitWorld, UnitPixel only supported units\n");
122         GdipFree(gp_pen);
123         return NotImplemented;
124     }
125
126     GdipCloneBrush(brush, &clone_brush);
127     gp_pen->brush = clone_brush;
128
129     *pen = gp_pen;
130
131     return Ok;
132 }
133
134 GpStatus WINGDIPAPI GdipDeletePen(GpPen *pen)
135 {
136     if(!pen)    return InvalidParameter;
137
138     GdipDeleteBrush(pen->brush);
139     GdipDeleteCustomLineCap(pen->customstart);
140     GdipDeleteCustomLineCap(pen->customend);
141     GdipFree(pen->dashes);
142     GdipFree(pen);
143
144     return Ok;
145 }
146
147 GpStatus WINGDIPAPI GdipGetPenBrushFill(GpPen *pen, GpBrush **brush)
148 {
149     if(!pen || !brush)
150         return InvalidParameter;
151
152     return GdipCloneBrush(pen->brush, brush);
153 }
154
155 GpStatus WINGDIPAPI GdipGetPenColor(GpPen *pen, ARGB *argb)
156 {
157     if(!pen || !argb)
158         return InvalidParameter;
159
160     if(pen->brush->bt != BrushTypeSolidColor)
161         return NotImplemented;
162
163     return GdipGetSolidFillColor(((GpSolidFill*)pen->brush), argb);
164 }
165
166 GpStatus WINGDIPAPI GdipGetPenDashArray(GpPen *pen, REAL *dash, INT count)
167 {
168     if(!pen || !dash || count > pen->numdashes)
169         return InvalidParameter;
170
171     /* note: if you pass a negative value for count, it crashes native gdiplus. */
172     if(count < 0)
173         return GenericError;
174
175     memcpy(dash, pen->dashes, count * sizeof(REAL));
176
177     return Ok;
178 }
179
180 GpStatus WINGDIPAPI GdipGetPenDashCap197819(GpPen *pen, GpDashCap *dashCap)
181 {
182     if(!pen || !dashCap)
183         return InvalidParameter;
184
185     *dashCap = pen->dashcap;
186
187     return Ok;
188 }
189
190 GpStatus WINGDIPAPI GdipGetPenDashCount(GpPen *pen, INT *count)
191 {
192     if(!pen || !count)
193         return InvalidParameter;
194
195     *count = pen->numdashes;
196
197     return Ok;
198 }
199
200 GpStatus WINGDIPAPI GdipGetPenDashOffset(GpPen *pen, REAL *offset)
201 {
202     if(!pen || !offset)
203         return InvalidParameter;
204
205     *offset = pen->offset;
206
207     return Ok;
208 }
209
210 GpStatus WINGDIPAPI GdipGetPenDashStyle(GpPen *pen, GpDashStyle *dash)
211 {
212     if(!pen || !dash)
213         return InvalidParameter;
214
215     *dash = pen->dash;
216
217     return Ok;
218 }
219
220 GpStatus WINGDIPAPI GdipGetPenEndCap(GpPen *pen, GpLineCap *endCap)
221 {
222     if(!pen || !endCap)
223         return InvalidParameter;
224
225     *endCap = pen->endcap;
226
227     return Ok;
228 }
229
230 GpStatus WINGDIPAPI GdipGetPenLineJoin(GpPen *pen, GpLineJoin *lineJoin)
231 {
232     if(!pen || !lineJoin)
233         return InvalidParameter;
234
235     *lineJoin = pen->join;
236
237     return Ok;
238 }
239
240 GpStatus WINGDIPAPI GdipGetPenMiterLimit(GpPen *pen, REAL *miterLimit)
241 {
242     if(!pen || !miterLimit)
243         return InvalidParameter;
244
245     *miterLimit = pen->miterlimit;
246
247     return Ok;
248 }
249
250 GpStatus WINGDIPAPI GdipGetPenStartCap(GpPen *pen, GpLineCap *startCap)
251 {
252     if(!pen || !startCap)
253         return InvalidParameter;
254
255     *startCap = pen->startcap;
256
257     return Ok;
258 }
259
260 GpStatus WINGDIPAPI GdipGetPenUnit(GpPen *pen, GpUnit *unit)
261 {
262     if(!pen || !unit)
263         return InvalidParameter;
264
265     *unit = pen->unit;
266
267     return Ok;
268 }
269
270 GpStatus WINGDIPAPI GdipGetPenWidth(GpPen *pen, REAL *width)
271 {
272     if(!pen || !width)
273         return InvalidParameter;
274
275     *width = pen->width;
276
277     return Ok;
278 }
279
280 GpStatus WINGDIPAPI GdipSetPenBrushFill(GpPen *pen, GpBrush *brush)
281 {
282     if(!pen || !brush)
283         return InvalidParameter;
284
285     GdipDeleteBrush(pen->brush);
286     return GdipCloneBrush(brush, &pen->brush);
287 }
288
289 GpStatus WINGDIPAPI GdipSetPenColor(GpPen *pen, ARGB argb)
290 {
291     if(!pen)
292         return InvalidParameter;
293
294     if(pen->brush->bt != BrushTypeSolidColor)
295         return NotImplemented;
296
297     return GdipSetSolidFillColor(((GpSolidFill*)pen->brush), argb);
298 }
299
300 GpStatus WINGDIPAPI GdipSetPenCustomEndCap(GpPen *pen, GpCustomLineCap* customCap)
301 {
302     GpCustomLineCap * cap;
303     GpStatus ret;
304
305     if(!pen || !customCap) return InvalidParameter;
306
307     if((ret = GdipCloneCustomLineCap(customCap, &cap)) == Ok){
308         GdipDeleteCustomLineCap(pen->customend);
309         pen->endcap = LineCapCustom;
310         pen->customend = cap;
311     }
312
313     return ret;
314 }
315
316 GpStatus WINGDIPAPI GdipSetPenCustomStartCap(GpPen *pen, GpCustomLineCap* customCap)
317 {
318     GpCustomLineCap * cap;
319     GpStatus ret;
320
321     if(!pen || !customCap) return InvalidParameter;
322
323     if((ret = GdipCloneCustomLineCap(customCap, &cap)) == Ok){
324         GdipDeleteCustomLineCap(pen->customstart);
325         pen->startcap = LineCapCustom;
326         pen->customstart = cap;
327     }
328
329     return ret;
330 }
331
332 GpStatus WINGDIPAPI GdipSetPenDashArray(GpPen *pen, GDIPCONST REAL *dash,
333     INT count)
334 {
335     INT i;
336     REAL sum = 0;
337
338     if(!pen || !dash)
339         return InvalidParameter;
340
341     if(count <= 0)
342         return OutOfMemory;
343
344     for(i = 0; i < count; i++){
345         sum += dash[i];
346         if(dash[i] < 0.0)
347             return InvalidParameter;
348     }
349
350     if(sum == 0.0 && count)
351         return InvalidParameter;
352
353     GdipFree(pen->dashes);
354     pen->dashes = NULL;
355
356     if(count > 0)
357         pen->dashes = GdipAlloc(count * sizeof(REAL));
358     if(!pen->dashes){
359         pen->numdashes = 0;
360         return OutOfMemory;
361     }
362
363     GdipSetPenDashStyle(pen, DashStyleCustom);
364     memcpy(pen->dashes, dash, count * sizeof(REAL));
365     pen->numdashes = count;
366
367     return Ok;
368 }
369
370 GpStatus WINGDIPAPI GdipSetPenDashCap197819(GpPen *pen, GpDashCap dashCap)
371 {
372     if(!pen)
373         return InvalidParameter;
374
375     pen->dashcap = dashCap;
376
377     return Ok;
378 }
379
380 /* FIXME: dash offset not used */
381 GpStatus WINGDIPAPI GdipSetPenDashOffset(GpPen *pen, REAL offset)
382 {
383     if(!pen)
384         return InvalidParameter;
385
386     pen->offset = offset;
387
388     return Ok;
389 }
390
391 GpStatus WINGDIPAPI GdipSetPenDashStyle(GpPen *pen, GpDashStyle dash)
392 {
393     if(!pen)
394         return InvalidParameter;
395
396     if(dash != DashStyleCustom){
397         GdipFree(pen->dashes);
398         pen->dashes = NULL;
399         pen->numdashes = 0;
400     }
401
402     pen->dash = dash;
403     pen->style &= ~(PS_ALTERNATE | PS_SOLID | PS_DASH | PS_DOT | PS_DASHDOT |
404                     PS_DASHDOTDOT | PS_NULL | PS_USERSTYLE | PS_INSIDEFRAME);
405     pen->style |= gdip_to_gdi_dash(dash);
406
407     return Ok;
408 }
409
410 GpStatus WINGDIPAPI GdipSetPenEndCap(GpPen *pen, GpLineCap cap)
411 {
412     if(!pen)    return InvalidParameter;
413
414     /* The old custom cap gets deleted even if the new style is LineCapCustom. */
415     GdipDeleteCustomLineCap(pen->customend);
416     pen->customend = NULL;
417     pen->endcap = cap;
418
419     return Ok;
420 }
421
422 /* FIXME: startcap, dashcap not used. */
423 GpStatus WINGDIPAPI GdipSetPenLineCap197819(GpPen *pen, GpLineCap start,
424     GpLineCap end, GpDashCap dash)
425 {
426     if(!pen)
427         return InvalidParameter;
428
429     GdipDeleteCustomLineCap(pen->customend);
430     GdipDeleteCustomLineCap(pen->customstart);
431     pen->customend = NULL;
432     pen->customstart = NULL;
433
434     pen->startcap = start;
435     pen->endcap = end;
436     pen->dashcap = dash;
437
438     return Ok;
439 }
440
441 /* FIXME: Miter line joins behave a bit differently than they do in windows.
442  * Both kinds of miter joins clip if the angle is less than 11 degrees. */
443 GpStatus WINGDIPAPI GdipSetPenLineJoin(GpPen *pen, GpLineJoin join)
444 {
445     if(!pen)    return InvalidParameter;
446
447     pen->join = join;
448     pen->style &= ~(PS_JOIN_ROUND | PS_JOIN_BEVEL | PS_JOIN_MITER);
449     pen->style |= gdip_to_gdi_join(join);
450
451     return Ok;
452 }
453
454 GpStatus WINGDIPAPI GdipSetPenMiterLimit(GpPen *pen, REAL limit)
455 {
456     if(!pen)
457         return InvalidParameter;
458
459     pen->miterlimit = limit;
460
461     return Ok;
462 }
463
464 GpStatus WINGDIPAPI GdipSetPenStartCap(GpPen *pen, GpLineCap cap)
465 {
466     if(!pen)    return InvalidParameter;
467
468     GdipDeleteCustomLineCap(pen->customstart);
469     pen->customstart = NULL;
470     pen->startcap = cap;
471
472     return Ok;
473 }
474
475 GpStatus WINGDIPAPI GdipSetPenWidth(GpPen *pen, REAL width)
476 {
477     if(!pen)    return InvalidParameter;
478
479     pen->width = width;
480
481     return Ok;
482 }
483
484
485 GpStatus WINGDIPAPI GdipSetPenMode(GpPen *pen, GpPenAlignment penAlignment)
486 {
487     if(!pen)    return InvalidParameter;
488
489     FIXME("stub (%d)\n", penAlignment);
490
491     return Ok;
492 }