wineusb.sys: Move event handling to a single thread.
[wine.git] / dlls / gdiplus / customlinecap.c
blobf35fea90eba7cbb2238b63c59b0504d7581bfd65
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 /* FIXME: Sometimes when fillPath is non-null and stroke path is null, the native
109 * version of this function returns NotImplemented. I cannot figure out why. */
110 GpStatus WINGDIPAPI GdipCreateCustomLineCap(GpPath* fillPath, GpPath* strokePath,
111 GpLineCap baseCap, REAL baseInset, GpCustomLineCap **customCap)
113 GpPathData *pathdata;
114 GpStatus stat;
116 TRACE("%p %p %d %f %p\n", fillPath, strokePath, baseCap, baseInset, customCap);
118 if(!customCap || !(fillPath || strokePath))
119 return InvalidParameter;
121 *customCap = heap_alloc_zero(sizeof(GpCustomLineCap));
122 if(!*customCap) return OutOfMemory;
124 if (strokePath)
125 pathdata = &strokePath->pathdata;
126 else
127 pathdata = &fillPath->pathdata;
129 stat = init_custom_linecap(*customCap, pathdata, fillPath != NULL, baseCap, baseInset);
130 if (stat != Ok)
132 heap_free(*customCap);
133 return stat;
136 TRACE("<-- %p\n", *customCap);
138 return Ok;
141 GpStatus WINGDIPAPI GdipDeleteCustomLineCap(GpCustomLineCap *customCap)
143 TRACE("(%p)\n", customCap);
145 if(!customCap)
146 return InvalidParameter;
148 heap_free(customCap->pathdata.Points);
149 heap_free(customCap->pathdata.Types);
150 heap_free(customCap);
152 return Ok;
155 GpStatus WINGDIPAPI GdipGetCustomLineCapStrokeJoin(GpCustomLineCap* customCap,
156 GpLineJoin* lineJoin)
158 TRACE("(%p, %p)\n", customCap, lineJoin);
160 if(!customCap || !lineJoin)
161 return InvalidParameter;
163 *lineJoin = customCap->join;
165 return Ok;
168 GpStatus WINGDIPAPI GdipGetCustomLineCapWidthScale(GpCustomLineCap* custom,
169 REAL* widthScale)
171 TRACE("(%p, %p)\n", custom, widthScale);
173 if(!custom || !widthScale)
174 return InvalidParameter;
176 *widthScale = custom->scale;
178 return Ok;
181 GpStatus WINGDIPAPI GdipSetCustomLineCapStrokeCaps(GpCustomLineCap* custom,
182 GpLineCap startcap, GpLineCap endcap)
184 TRACE("(%p,%u,%u)\n", custom, startcap, endcap);
186 if(!custom || startcap > LineCapTriangle || endcap > LineCapTriangle)
187 return InvalidParameter;
189 custom->strokeStartCap = startcap;
190 custom->strokeEndCap = endcap;
192 return Ok;
195 GpStatus WINGDIPAPI GdipSetCustomLineCapBaseCap(GpCustomLineCap* custom,
196 GpLineCap basecap)
198 TRACE("(%p,%u)\n", custom, basecap);
199 if(!custom || basecap > LineCapTriangle)
200 return InvalidParameter;
202 custom->basecap = basecap;
204 return Ok;
207 GpStatus WINGDIPAPI GdipGetCustomLineCapBaseInset(GpCustomLineCap* custom,
208 REAL* inset)
210 TRACE("(%p, %p)\n", custom, inset);
212 if(!custom || !inset)
213 return InvalidParameter;
215 *inset = custom->inset;
217 return Ok;
220 GpStatus WINGDIPAPI GdipSetCustomLineCapBaseInset(GpCustomLineCap* custom,
221 REAL inset)
223 TRACE("(%p,%0.2f)\n", custom, inset);
225 if(!custom)
226 return InvalidParameter;
228 custom->inset = inset;
230 return Ok;
233 /*FIXME: LineJoin completely ignored now */
234 GpStatus WINGDIPAPI GdipSetCustomLineCapStrokeJoin(GpCustomLineCap* custom,
235 GpLineJoin join)
237 TRACE("(%p, %d)\n", custom, join);
239 if(!custom)
240 return InvalidParameter;
242 custom->join = join;
244 return Ok;
247 GpStatus WINGDIPAPI GdipSetCustomLineCapWidthScale(GpCustomLineCap* custom, REAL width)
249 TRACE("(%p,%0.2f)\n", custom, width);
251 if(!custom)
252 return InvalidParameter;
254 custom->scale = width;
256 return Ok;
259 GpStatus WINGDIPAPI GdipGetCustomLineCapBaseCap(GpCustomLineCap *customCap, GpLineCap *baseCap)
261 TRACE("(%p, %p)\n", customCap, baseCap);
263 if(!customCap || !baseCap)
264 return InvalidParameter;
266 *baseCap = customCap->basecap;
268 return Ok;
271 GpStatus WINGDIPAPI GdipGetCustomLineCapType(GpCustomLineCap *customCap, CustomLineCapType *type)
273 TRACE("(%p, %p)\n", customCap, type);
275 if(!customCap || !type)
276 return InvalidParameter;
278 *type = customCap->type;
279 return Ok;
282 static void arrowcap_update_path(GpAdjustableArrowCap *cap)
284 static const BYTE types_filled[] =
286 PathPointTypeStart, PathPointTypeLine, PathPointTypeLine, PathPointTypeLine | PathPointTypeCloseSubpath
288 static const BYTE types_unfilled[] =
290 PathPointTypeStart, PathPointTypeLine, PathPointTypeLine
292 GpPointF *points;
294 assert(cap->cap.pathdata.Count == 3 || cap->cap.pathdata.Count == 4);
296 points = cap->cap.pathdata.Points;
297 if (cap->cap.fill)
299 memcpy(cap->cap.pathdata.Types, types_filled, sizeof(types_filled));
300 cap->cap.pathdata.Count = 4;
301 points[0].X = -cap->width / 2.0;
302 points[0].Y = -cap->height;
303 points[1].X = 0.0;
304 points[1].Y = 0.0;
305 points[2].X = cap->width / 2.0;
306 points[2].Y = -cap->height;
307 points[3].X = 0.0;
308 points[3].Y = -cap->height + cap->middle_inset;
310 else
312 memcpy(cap->cap.pathdata.Types, types_unfilled, sizeof(types_unfilled));
313 cap->cap.pathdata.Count = 3;
314 points[0].X = -cap->width / 2.0;
315 points[0].Y = -cap->height;
316 points[1].X = 0.0;
317 points[1].Y = 0.0;
318 points[2].X = cap->width / 2.0;
319 points[2].Y = -cap->height;
322 if (cap->width == 0.0)
323 cap->cap.inset = 0.0;
324 else
325 cap->cap.inset = cap->height / cap->width;
328 GpStatus WINGDIPAPI GdipCreateAdjustableArrowCap(REAL height, REAL width, BOOL fill,
329 GpAdjustableArrowCap **cap)
331 GpPathData pathdata;
332 GpStatus stat;
334 TRACE("(%0.2f,%0.2f,%i,%p)\n", height, width, fill, cap);
336 if (!cap)
337 return InvalidParameter;
339 *cap = heap_alloc_zero(sizeof(**cap));
340 if (!*cap)
341 return OutOfMemory;
343 /* We'll need 4 points at most. */
344 pathdata.Count = 4;
345 pathdata.Points = NULL;
346 pathdata.Types = NULL;
347 stat = init_custom_linecap(&(*cap)->cap, &pathdata, fill, LineCapTriangle, width != 0.0 ? height / width : 0.0);
348 if (stat != Ok)
350 heap_free(*cap);
351 return stat;
354 (*cap)->cap.type = CustomLineCapTypeAdjustableArrow;
355 (*cap)->height = height;
356 (*cap)->width = width;
357 (*cap)->middle_inset = 0.0;
358 arrowcap_update_path(*cap);
360 return Ok;
363 GpStatus WINGDIPAPI GdipGetAdjustableArrowCapFillState(GpAdjustableArrowCap* cap, BOOL* fill)
365 TRACE("(%p,%p)\n", cap, fill);
367 if (!cap || !fill)
368 return InvalidParameter;
370 *fill = cap->cap.fill;
371 return Ok;
374 GpStatus WINGDIPAPI GdipGetAdjustableArrowCapHeight(GpAdjustableArrowCap* cap, REAL* height)
376 TRACE("(%p,%p)\n", cap, height);
378 if (!cap || !height)
379 return InvalidParameter;
381 *height = cap->height;
382 return Ok;
385 GpStatus WINGDIPAPI GdipGetAdjustableArrowCapMiddleInset(GpAdjustableArrowCap* cap, REAL* middle)
387 TRACE("(%p,%p)\n", cap, middle);
389 if (!cap || !middle)
390 return InvalidParameter;
392 *middle = cap->middle_inset;
393 return Ok;
396 GpStatus WINGDIPAPI GdipGetAdjustableArrowCapWidth(GpAdjustableArrowCap* cap, REAL* width)
398 TRACE("(%p,%p)\n", cap, width);
400 if (!cap || !width)
401 return InvalidParameter;
403 *width = cap->width;
404 return Ok;
407 GpStatus WINGDIPAPI GdipSetAdjustableArrowCapFillState(GpAdjustableArrowCap* cap, BOOL fill)
409 TRACE("(%p,%i)\n", cap, fill);
411 if (!cap)
412 return InvalidParameter;
414 cap->cap.fill = fill;
415 arrowcap_update_path(cap);
416 return Ok;
419 GpStatus WINGDIPAPI GdipSetAdjustableArrowCapHeight(GpAdjustableArrowCap* cap, REAL height)
421 TRACE("(%p,%0.2f)\n", cap, height);
423 if (!cap)
424 return InvalidParameter;
426 cap->height = height;
427 arrowcap_update_path(cap);
428 return Ok;
431 GpStatus WINGDIPAPI GdipSetAdjustableArrowCapMiddleInset(GpAdjustableArrowCap* cap, REAL middle)
433 TRACE("(%p,%0.2f)\n", cap, middle);
435 if (!cap)
436 return InvalidParameter;
438 cap->middle_inset = middle;
439 arrowcap_update_path(cap);
440 return Ok;
443 GpStatus WINGDIPAPI GdipSetAdjustableArrowCapWidth(GpAdjustableArrowCap* cap, REAL width)
445 TRACE("(%p,%0.2f)\n", cap, width);
447 if (!cap)
448 return InvalidParameter;
450 cap->width = width;
451 arrowcap_update_path(cap);
452 return Ok;