d2d1: Implement ID2D1DeviceContext::CreateImageBrush().
[wine.git] / dlls / gdiplus / customlinecap.c
blobc74928eeda6c2a44e3e29938e3d7af790334e6d9
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->cap = basecap;
100 cap->join = LineJoinMiter;
101 cap->scale = 1.0;
103 return Ok;
106 /* FIXME: Sometimes when fillPath is non-null and stroke path is null, the native
107 * version of this function returns NotImplemented. I cannot figure out why. */
108 GpStatus WINGDIPAPI GdipCreateCustomLineCap(GpPath* fillPath, GpPath* strokePath,
109 GpLineCap baseCap, REAL baseInset, GpCustomLineCap **customCap)
111 GpPathData *pathdata;
112 GpStatus stat;
114 TRACE("%p %p %d %f %p\n", fillPath, strokePath, baseCap, baseInset, customCap);
116 if(!customCap || !(fillPath || strokePath))
117 return InvalidParameter;
119 *customCap = heap_alloc_zero(sizeof(GpCustomLineCap));
120 if(!*customCap) return OutOfMemory;
122 if (strokePath)
123 pathdata = &strokePath->pathdata;
124 else
125 pathdata = &fillPath->pathdata;
127 stat = init_custom_linecap(*customCap, pathdata, fillPath != NULL, baseCap, baseInset);
128 if (stat != Ok)
130 heap_free(*customCap);
131 return stat;
134 TRACE("<-- %p\n", *customCap);
136 return Ok;
139 GpStatus WINGDIPAPI GdipDeleteCustomLineCap(GpCustomLineCap *customCap)
141 TRACE("(%p)\n", customCap);
143 if(!customCap)
144 return InvalidParameter;
146 heap_free(customCap->pathdata.Points);
147 heap_free(customCap->pathdata.Types);
148 heap_free(customCap);
150 return Ok;
153 GpStatus WINGDIPAPI GdipGetCustomLineCapStrokeJoin(GpCustomLineCap* customCap,
154 GpLineJoin* lineJoin)
156 TRACE("(%p, %p)\n", customCap, lineJoin);
158 if(!customCap || !lineJoin)
159 return InvalidParameter;
161 *lineJoin = customCap->join;
163 return Ok;
166 GpStatus WINGDIPAPI GdipGetCustomLineCapWidthScale(GpCustomLineCap* custom,
167 REAL* widthScale)
169 TRACE("(%p, %p)\n", custom, widthScale);
171 if(!custom || !widthScale)
172 return InvalidParameter;
174 *widthScale = custom->scale;
176 return Ok;
179 GpStatus WINGDIPAPI GdipSetCustomLineCapStrokeCaps(GpCustomLineCap* custom,
180 GpLineCap start, GpLineCap end)
182 static int calls;
184 TRACE("(%p,%u,%u)\n", custom, start, end);
186 if(!custom)
187 return InvalidParameter;
189 if(!(calls++))
190 FIXME("not implemented\n");
192 return NotImplemented;
195 GpStatus WINGDIPAPI GdipSetCustomLineCapBaseCap(GpCustomLineCap* custom,
196 GpLineCap base)
198 static int calls;
200 TRACE("(%p,%u)\n", custom, base);
202 if(!(calls++))
203 FIXME("not implemented\n");
205 return NotImplemented;
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 static int calls;
226 TRACE("(%p,%0.2f)\n", custom, inset);
228 if(!(calls++))
229 FIXME("not implemented\n");
231 return NotImplemented;
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->cap;
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 / 4.0;
316 points[0].Y = -cap->height / 2.0;
317 points[1].X = 0.0;
318 points[1].Y = 0.0;
319 points[2].X = cap->width / 4.0;
320 points[2].Y = -cap->height / 2.0;
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;