Release 8.16.
[wine.git] / dlls / gdiplus / customlinecap.c
blobe767f20e4b3231de57a271aacc6e09615554ac25
1 /*
2 * Copyright (C) 2007 Google (Evan Stade)
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.
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.
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
19 #include <stdarg.h>
20 #include <assert.h>
22 #include "windef.h"
23 #include "winbase.h"
24 #include "wingdi.h"
26 #include "objbase.h"
28 #include "gdiplus.h"
29 #include "gdiplus_private.h"
30 #include "wine/debug.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(gdiplus);
34 GpStatus WINGDIPAPI GdipCloneCustomLineCap(GpCustomLineCap* from,
35 GpCustomLineCap** to)
37 TRACE("(%p, %p)\n", from, to);
39 if(!from || !to)
40 return InvalidParameter;
42 if (from->type == CustomLineCapTypeDefault)
43 *to = heap_alloc_zero(sizeof(GpCustomLineCap));
44 else
45 *to = heap_alloc_zero(sizeof(GpAdjustableArrowCap));
47 if (!*to)
48 return OutOfMemory;
50 if (from->type == CustomLineCapTypeDefault)
51 **to = *from;
52 else
53 *(GpAdjustableArrowCap *)*to = *(GpAdjustableArrowCap *)from;
55 /* Duplicate path data */
56 (*to)->pathdata.Points = heap_alloc_zero(from->pathdata.Count * sizeof(PointF));
57 (*to)->pathdata.Types = heap_alloc_zero(from->pathdata.Count);
59 if((!(*to)->pathdata.Types || !(*to)->pathdata.Points) && (*to)->pathdata.Count){
60 heap_free((*to)->pathdata.Points);
61 heap_free((*to)->pathdata.Types);
62 heap_free(*to);
63 return OutOfMemory;
66 memcpy((*to)->pathdata.Points, from->pathdata.Points, from->pathdata.Count
67 * sizeof(PointF));
68 memcpy((*to)->pathdata.Types, from->pathdata.Types, from->pathdata.Count);
70 TRACE("<-- %p\n", *to);
72 return Ok;
75 static GpStatus init_custom_linecap(GpCustomLineCap *cap, GpPathData *pathdata, BOOL fill, GpLineCap basecap,
76 REAL base_inset)
78 cap->fill = fill;
80 cap->pathdata.Points = heap_alloc_zero(pathdata->Count * sizeof(PointF));
81 cap->pathdata.Types = heap_alloc_zero(pathdata->Count);
83 if ((!cap->pathdata.Types || !cap->pathdata.Points) && pathdata->Count)
85 heap_free(cap->pathdata.Points);
86 heap_free(cap->pathdata.Types);
87 cap->pathdata.Points = NULL;
88 cap->pathdata.Types = NULL;
89 return OutOfMemory;
92 if (pathdata->Points)
93 memcpy(cap->pathdata.Points, pathdata->Points, pathdata->Count * sizeof(PointF));
94 if (pathdata->Types)
95 memcpy(cap->pathdata.Types, pathdata->Types, pathdata->Count);
96 cap->pathdata.Count = pathdata->Count;
98 cap->inset = base_inset;
99 cap->basecap = basecap;
100 cap->strokeStartCap = LineCapFlat;
101 cap->strokeEndCap = LineCapFlat;
102 cap->join = LineJoinMiter;
103 cap->scale = 1.0;
105 return Ok;
108 /* Custom line cap position (0, 0) is a place corresponding to the end of line.
109 * If Custom Line Cap is too big and too far from position (0, 0),
110 * then NotImplemented will be returned, due to floating point precision limitation. */
111 GpStatus WINGDIPAPI GdipCreateCustomLineCap(GpPath* fillPath, GpPath* strokePath,
112 GpLineCap baseCap, REAL baseInset, GpCustomLineCap **customCap)
114 GpPathData *pathdata;
115 GpStatus stat;
117 TRACE("%p %p %d %f %p\n", fillPath, strokePath, baseCap, baseInset, customCap);
119 if(!customCap || !(fillPath || strokePath))
120 return InvalidParameter;
122 *customCap = heap_alloc_zero(sizeof(GpCustomLineCap));
123 if(!*customCap) return OutOfMemory;
125 if (strokePath)
126 pathdata = &strokePath->pathdata;
127 else
128 pathdata = &fillPath->pathdata;
130 stat = init_custom_linecap(*customCap, pathdata, fillPath != NULL, baseCap, baseInset);
131 if (stat != Ok)
133 heap_free(*customCap);
134 return stat;
137 TRACE("<-- %p\n", *customCap);
139 return Ok;
142 GpStatus WINGDIPAPI GdipDeleteCustomLineCap(GpCustomLineCap *customCap)
144 TRACE("(%p)\n", customCap);
146 if(!customCap)
147 return InvalidParameter;
149 heap_free(customCap->pathdata.Points);
150 heap_free(customCap->pathdata.Types);
151 heap_free(customCap);
153 return Ok;
156 GpStatus WINGDIPAPI GdipGetCustomLineCapStrokeJoin(GpCustomLineCap* customCap,
157 GpLineJoin* lineJoin)
159 TRACE("(%p, %p)\n", customCap, lineJoin);
161 if(!customCap || !lineJoin)
162 return InvalidParameter;
164 *lineJoin = customCap->join;
166 return Ok;
169 GpStatus WINGDIPAPI GdipGetCustomLineCapWidthScale(GpCustomLineCap* custom,
170 REAL* widthScale)
172 TRACE("(%p, %p)\n", custom, widthScale);
174 if(!custom || !widthScale)
175 return InvalidParameter;
177 *widthScale = custom->scale;
179 return Ok;
182 GpStatus WINGDIPAPI GdipSetCustomLineCapStrokeCaps(GpCustomLineCap* custom,
183 GpLineCap startcap, GpLineCap endcap)
185 TRACE("(%p,%u,%u)\n", custom, startcap, endcap);
187 if(!custom || startcap > LineCapTriangle || endcap > LineCapTriangle)
188 return InvalidParameter;
190 custom->strokeStartCap = startcap;
191 custom->strokeEndCap = endcap;
193 return Ok;
196 GpStatus WINGDIPAPI GdipSetCustomLineCapBaseCap(GpCustomLineCap* custom,
197 GpLineCap basecap)
199 TRACE("(%p,%u)\n", custom, basecap);
200 if(!custom || basecap > LineCapTriangle)
201 return InvalidParameter;
203 custom->basecap = basecap;
205 return Ok;
208 GpStatus WINGDIPAPI GdipGetCustomLineCapBaseInset(GpCustomLineCap* custom,
209 REAL* inset)
211 TRACE("(%p, %p)\n", custom, inset);
213 if(!custom || !inset)
214 return InvalidParameter;
216 *inset = custom->inset;
218 return Ok;
221 GpStatus WINGDIPAPI GdipSetCustomLineCapBaseInset(GpCustomLineCap* custom,
222 REAL inset)
224 TRACE("(%p,%0.2f)\n", custom, inset);
226 if(!custom)
227 return InvalidParameter;
229 custom->inset = inset;
231 return Ok;
234 /*FIXME: LineJoin completely ignored now */
235 GpStatus WINGDIPAPI GdipSetCustomLineCapStrokeJoin(GpCustomLineCap* custom,
236 GpLineJoin join)
238 TRACE("(%p, %d)\n", custom, join);
240 if(!custom)
241 return InvalidParameter;
243 custom->join = join;
245 return Ok;
248 GpStatus WINGDIPAPI GdipSetCustomLineCapWidthScale(GpCustomLineCap* custom, REAL width)
250 TRACE("(%p,%0.2f)\n", custom, width);
252 if(!custom)
253 return InvalidParameter;
255 custom->scale = width;
257 return Ok;
260 GpStatus WINGDIPAPI GdipGetCustomLineCapBaseCap(GpCustomLineCap *customCap, GpLineCap *baseCap)
262 TRACE("(%p, %p)\n", customCap, baseCap);
264 if(!customCap || !baseCap)
265 return InvalidParameter;
267 *baseCap = customCap->basecap;
269 return Ok;
272 GpStatus WINGDIPAPI GdipGetCustomLineCapType(GpCustomLineCap *customCap, CustomLineCapType *type)
274 TRACE("(%p, %p)\n", customCap, type);
276 if(!customCap || !type)
277 return InvalidParameter;
279 *type = customCap->type;
280 return Ok;
283 static void arrowcap_update_path(GpAdjustableArrowCap *cap)
285 static const BYTE types_filled[] =
287 PathPointTypeStart, PathPointTypeLine, PathPointTypeLine, PathPointTypeLine | PathPointTypeCloseSubpath
289 static const BYTE types_unfilled[] =
291 PathPointTypeStart, PathPointTypeLine, PathPointTypeLine
293 GpPointF *points;
295 assert(cap->cap.pathdata.Count == 3 || cap->cap.pathdata.Count == 4);
297 points = cap->cap.pathdata.Points;
298 if (cap->cap.fill)
300 memcpy(cap->cap.pathdata.Types, types_filled, sizeof(types_filled));
301 cap->cap.pathdata.Count = 4;
302 points[0].X = -cap->width / 2.0;
303 points[0].Y = -cap->height;
304 points[1].X = 0.0;
305 points[1].Y = 0.0;
306 points[2].X = cap->width / 2.0;
307 points[2].Y = -cap->height;
308 points[3].X = 0.0;
309 points[3].Y = -cap->height + cap->middle_inset;
311 else
313 memcpy(cap->cap.pathdata.Types, types_unfilled, sizeof(types_unfilled));
314 cap->cap.pathdata.Count = 3;
315 points[0].X = -cap->width / 2.0;
316 points[0].Y = -cap->height;
317 points[1].X = 0.0;
318 points[1].Y = 0.0;
319 points[2].X = cap->width / 2.0;
320 points[2].Y = -cap->height;
323 if (cap->width == 0.0)
324 cap->cap.inset = 0.0;
325 else
326 cap->cap.inset = cap->height / cap->width;
329 GpStatus WINGDIPAPI GdipCreateAdjustableArrowCap(REAL height, REAL width, BOOL fill,
330 GpAdjustableArrowCap **cap)
332 GpPathData pathdata;
333 GpStatus stat;
335 TRACE("(%0.2f,%0.2f,%i,%p)\n", height, width, fill, cap);
337 if (!cap)
338 return InvalidParameter;
340 *cap = heap_alloc_zero(sizeof(**cap));
341 if (!*cap)
342 return OutOfMemory;
344 /* We'll need 4 points at most. */
345 pathdata.Count = 4;
346 pathdata.Points = NULL;
347 pathdata.Types = NULL;
348 stat = init_custom_linecap(&(*cap)->cap, &pathdata, fill, LineCapTriangle, width != 0.0 ? height / width : 0.0);
349 if (stat != Ok)
351 heap_free(*cap);
352 return stat;
355 (*cap)->cap.type = CustomLineCapTypeAdjustableArrow;
356 (*cap)->height = height;
357 (*cap)->width = width;
358 (*cap)->middle_inset = 0.0;
359 arrowcap_update_path(*cap);
361 return Ok;
364 GpStatus WINGDIPAPI GdipGetAdjustableArrowCapFillState(GpAdjustableArrowCap* cap, BOOL* fill)
366 TRACE("(%p,%p)\n", cap, fill);
368 if (!cap || !fill)
369 return InvalidParameter;
371 *fill = cap->cap.fill;
372 return Ok;
375 GpStatus WINGDIPAPI GdipGetAdjustableArrowCapHeight(GpAdjustableArrowCap* cap, REAL* height)
377 TRACE("(%p,%p)\n", cap, height);
379 if (!cap || !height)
380 return InvalidParameter;
382 *height = cap->height;
383 return Ok;
386 GpStatus WINGDIPAPI GdipGetAdjustableArrowCapMiddleInset(GpAdjustableArrowCap* cap, REAL* middle)
388 TRACE("(%p,%p)\n", cap, middle);
390 if (!cap || !middle)
391 return InvalidParameter;
393 *middle = cap->middle_inset;
394 return Ok;
397 GpStatus WINGDIPAPI GdipGetAdjustableArrowCapWidth(GpAdjustableArrowCap* cap, REAL* width)
399 TRACE("(%p,%p)\n", cap, width);
401 if (!cap || !width)
402 return InvalidParameter;
404 *width = cap->width;
405 return Ok;
408 GpStatus WINGDIPAPI GdipSetAdjustableArrowCapFillState(GpAdjustableArrowCap* cap, BOOL fill)
410 TRACE("(%p,%i)\n", cap, fill);
412 if (!cap)
413 return InvalidParameter;
415 cap->cap.fill = fill;
416 arrowcap_update_path(cap);
417 return Ok;
420 GpStatus WINGDIPAPI GdipSetAdjustableArrowCapHeight(GpAdjustableArrowCap* cap, REAL height)
422 TRACE("(%p,%0.2f)\n", cap, height);
424 if (!cap)
425 return InvalidParameter;
427 cap->height = height;
428 arrowcap_update_path(cap);
429 return Ok;
432 GpStatus WINGDIPAPI GdipSetAdjustableArrowCapMiddleInset(GpAdjustableArrowCap* cap, REAL middle)
434 TRACE("(%p,%0.2f)\n", cap, middle);
436 if (!cap)
437 return InvalidParameter;
439 cap->middle_inset = middle;
440 arrowcap_update_path(cap);
441 return Ok;
444 GpStatus WINGDIPAPI GdipSetAdjustableArrowCapWidth(GpAdjustableArrowCap* cap, REAL width)
446 TRACE("(%p,%0.2f)\n", cap, width);
448 if (!cap)
449 return InvalidParameter;
451 cap->width = width;
452 arrowcap_update_path(cap);
453 return Ok;