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
29 #include "gdiplus_private.h"
30 #include "wine/debug.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(gdiplus
);
34 GpStatus WINGDIPAPI
GdipCloneCustomLineCap(GpCustomLineCap
* from
,
37 TRACE("(%p, %p)\n", from
, to
);
40 return InvalidParameter
;
42 if (from
->type
== CustomLineCapTypeDefault
)
43 *to
= heap_alloc_zero(sizeof(GpCustomLineCap
));
45 *to
= heap_alloc_zero(sizeof(GpAdjustableArrowCap
));
50 if (from
->type
== CustomLineCapTypeDefault
)
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
);
66 memcpy((*to
)->pathdata
.Points
, from
->pathdata
.Points
, from
->pathdata
.Count
68 memcpy((*to
)->pathdata
.Types
, from
->pathdata
.Types
, from
->pathdata
.Count
);
70 TRACE("<-- %p\n", *to
);
75 static GpStatus
init_custom_linecap(GpCustomLineCap
*cap
, GpPathData
*pathdata
, BOOL fill
, GpLineCap basecap
,
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
;
93 memcpy(cap
->pathdata
.Points
, pathdata
->Points
, pathdata
->Count
* sizeof(PointF
));
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
;
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
;
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
;
125 pathdata
= &strokePath
->pathdata
;
127 pathdata
= &fillPath
->pathdata
;
129 stat
= init_custom_linecap(*customCap
, pathdata
, fillPath
!= NULL
, baseCap
, baseInset
);
132 heap_free(*customCap
);
136 TRACE("<-- %p\n", *customCap
);
141 GpStatus WINGDIPAPI
GdipDeleteCustomLineCap(GpCustomLineCap
*customCap
)
143 TRACE("(%p)\n", customCap
);
146 return InvalidParameter
;
148 heap_free(customCap
->pathdata
.Points
);
149 heap_free(customCap
->pathdata
.Types
);
150 heap_free(customCap
);
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
;
168 GpStatus WINGDIPAPI
GdipGetCustomLineCapWidthScale(GpCustomLineCap
* custom
,
171 TRACE("(%p, %p)\n", custom
, widthScale
);
173 if(!custom
|| !widthScale
)
174 return InvalidParameter
;
176 *widthScale
= custom
->scale
;
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
;
195 GpStatus WINGDIPAPI
GdipSetCustomLineCapBaseCap(GpCustomLineCap
* custom
,
198 TRACE("(%p,%u)\n", custom
, basecap
);
199 if(!custom
|| basecap
> LineCapTriangle
)
200 return InvalidParameter
;
202 custom
->basecap
= basecap
;
207 GpStatus WINGDIPAPI
GdipGetCustomLineCapBaseInset(GpCustomLineCap
* custom
,
210 TRACE("(%p, %p)\n", custom
, inset
);
212 if(!custom
|| !inset
)
213 return InvalidParameter
;
215 *inset
= custom
->inset
;
220 GpStatus WINGDIPAPI
GdipSetCustomLineCapBaseInset(GpCustomLineCap
* custom
,
223 TRACE("(%p,%0.2f)\n", custom
, inset
);
226 return InvalidParameter
;
228 custom
->inset
= inset
;
233 /*FIXME: LineJoin completely ignored now */
234 GpStatus WINGDIPAPI
GdipSetCustomLineCapStrokeJoin(GpCustomLineCap
* custom
,
237 TRACE("(%p, %d)\n", custom
, join
);
240 return InvalidParameter
;
247 GpStatus WINGDIPAPI
GdipSetCustomLineCapWidthScale(GpCustomLineCap
* custom
, REAL width
)
249 TRACE("(%p,%0.2f)\n", custom
, width
);
252 return InvalidParameter
;
254 custom
->scale
= width
;
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
;
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
;
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
294 assert(cap
->cap
.pathdata
.Count
== 3 || cap
->cap
.pathdata
.Count
== 4);
296 points
= cap
->cap
.pathdata
.Points
;
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
;
305 points
[2].X
= cap
->width
/ 2.0;
306 points
[2].Y
= -cap
->height
;
308 points
[3].Y
= -cap
->height
+ cap
->middle_inset
;
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
;
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;
325 cap
->cap
.inset
= cap
->height
/ cap
->width
;
328 GpStatus WINGDIPAPI
GdipCreateAdjustableArrowCap(REAL height
, REAL width
, BOOL fill
,
329 GpAdjustableArrowCap
**cap
)
334 TRACE("(%0.2f,%0.2f,%i,%p)\n", height
, width
, fill
, cap
);
337 return InvalidParameter
;
339 *cap
= heap_alloc_zero(sizeof(**cap
));
343 /* We'll need 4 points at most. */
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);
354 (*cap
)->cap
.type
= CustomLineCapTypeAdjustableArrow
;
355 (*cap
)->height
= height
;
356 (*cap
)->width
= width
;
357 (*cap
)->middle_inset
= 0.0;
358 arrowcap_update_path(*cap
);
363 GpStatus WINGDIPAPI
GdipGetAdjustableArrowCapFillState(GpAdjustableArrowCap
* cap
, BOOL
* fill
)
365 TRACE("(%p,%p)\n", cap
, fill
);
368 return InvalidParameter
;
370 *fill
= cap
->cap
.fill
;
374 GpStatus WINGDIPAPI
GdipGetAdjustableArrowCapHeight(GpAdjustableArrowCap
* cap
, REAL
* height
)
376 TRACE("(%p,%p)\n", cap
, height
);
379 return InvalidParameter
;
381 *height
= cap
->height
;
385 GpStatus WINGDIPAPI
GdipGetAdjustableArrowCapMiddleInset(GpAdjustableArrowCap
* cap
, REAL
* middle
)
387 TRACE("(%p,%p)\n", cap
, middle
);
390 return InvalidParameter
;
392 *middle
= cap
->middle_inset
;
396 GpStatus WINGDIPAPI
GdipGetAdjustableArrowCapWidth(GpAdjustableArrowCap
* cap
, REAL
* width
)
398 TRACE("(%p,%p)\n", cap
, width
);
401 return InvalidParameter
;
407 GpStatus WINGDIPAPI
GdipSetAdjustableArrowCapFillState(GpAdjustableArrowCap
* cap
, BOOL fill
)
409 TRACE("(%p,%i)\n", cap
, fill
);
412 return InvalidParameter
;
414 cap
->cap
.fill
= fill
;
415 arrowcap_update_path(cap
);
419 GpStatus WINGDIPAPI
GdipSetAdjustableArrowCapHeight(GpAdjustableArrowCap
* cap
, REAL height
)
421 TRACE("(%p,%0.2f)\n", cap
, height
);
424 return InvalidParameter
;
426 cap
->height
= height
;
427 arrowcap_update_path(cap
);
431 GpStatus WINGDIPAPI
GdipSetAdjustableArrowCapMiddleInset(GpAdjustableArrowCap
* cap
, REAL middle
)
433 TRACE("(%p,%0.2f)\n", cap
, middle
);
436 return InvalidParameter
;
438 cap
->middle_inset
= middle
;
439 arrowcap_update_path(cap
);
443 GpStatus WINGDIPAPI
GdipSetAdjustableArrowCapWidth(GpAdjustableArrowCap
* cap
, REAL width
)
445 TRACE("(%p,%0.2f)\n", cap
, width
);
448 return InvalidParameter
;
451 arrowcap_update_path(cap
);