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
;
100 cap
->join
= LineJoinMiter
;
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
;
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
;
123 pathdata
= &strokePath
->pathdata
;
125 pathdata
= &fillPath
->pathdata
;
127 stat
= init_custom_linecap(*customCap
, pathdata
, fillPath
!= NULL
, baseCap
, baseInset
);
130 heap_free(*customCap
);
134 TRACE("<-- %p\n", *customCap
);
139 GpStatus WINGDIPAPI
GdipDeleteCustomLineCap(GpCustomLineCap
*customCap
)
141 TRACE("(%p)\n", customCap
);
144 return InvalidParameter
;
146 heap_free(customCap
->pathdata
.Points
);
147 heap_free(customCap
->pathdata
.Types
);
148 heap_free(customCap
);
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
;
166 GpStatus WINGDIPAPI
GdipGetCustomLineCapWidthScale(GpCustomLineCap
* custom
,
169 TRACE("(%p, %p)\n", custom
, widthScale
);
171 if(!custom
|| !widthScale
)
172 return InvalidParameter
;
174 *widthScale
= custom
->scale
;
179 GpStatus WINGDIPAPI
GdipSetCustomLineCapStrokeCaps(GpCustomLineCap
* custom
,
180 GpLineCap start
, GpLineCap end
)
184 TRACE("(%p,%u,%u)\n", custom
, start
, end
);
187 return InvalidParameter
;
190 FIXME("not implemented\n");
192 return NotImplemented
;
195 GpStatus WINGDIPAPI
GdipSetCustomLineCapBaseCap(GpCustomLineCap
* custom
,
200 TRACE("(%p,%u)\n", custom
, base
);
203 FIXME("not implemented\n");
205 return NotImplemented
;
208 GpStatus WINGDIPAPI
GdipGetCustomLineCapBaseInset(GpCustomLineCap
* custom
,
211 TRACE("(%p, %p)\n", custom
, inset
);
213 if(!custom
|| !inset
)
214 return InvalidParameter
;
216 *inset
= custom
->inset
;
221 GpStatus WINGDIPAPI
GdipSetCustomLineCapBaseInset(GpCustomLineCap
* custom
,
226 TRACE("(%p,%0.2f)\n", custom
, inset
);
229 FIXME("not implemented\n");
231 return NotImplemented
;
234 /*FIXME: LineJoin completely ignored now */
235 GpStatus WINGDIPAPI
GdipSetCustomLineCapStrokeJoin(GpCustomLineCap
* custom
,
238 TRACE("(%p, %d)\n", custom
, join
);
241 return InvalidParameter
;
248 GpStatus WINGDIPAPI
GdipSetCustomLineCapWidthScale(GpCustomLineCap
* custom
, REAL width
)
250 TRACE("(%p,%0.2f)\n", custom
, width
);
253 return InvalidParameter
;
255 custom
->scale
= width
;
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
;
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
;
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
295 assert(cap
->cap
.pathdata
.Count
== 3 || cap
->cap
.pathdata
.Count
== 4);
297 points
= cap
->cap
.pathdata
.Points
;
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
;
306 points
[2].X
= cap
->width
/ 2.0;
307 points
[2].Y
= -cap
->height
;
309 points
[3].Y
= -cap
->height
- cap
->middle_inset
;
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;
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;
326 cap
->cap
.inset
= cap
->height
/ cap
->width
;
329 GpStatus WINGDIPAPI
GdipCreateAdjustableArrowCap(REAL height
, REAL width
, BOOL fill
,
330 GpAdjustableArrowCap
**cap
)
335 TRACE("(%0.2f,%0.2f,%i,%p)\n", height
, width
, fill
, cap
);
338 return InvalidParameter
;
340 *cap
= heap_alloc_zero(sizeof(**cap
));
344 /* We'll need 4 points at most. */
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);
355 (*cap
)->cap
.type
= CustomLineCapTypeAdjustableArrow
;
356 (*cap
)->height
= height
;
357 (*cap
)->width
= width
;
358 (*cap
)->middle_inset
= 0.0;
359 arrowcap_update_path(*cap
);
364 GpStatus WINGDIPAPI
GdipGetAdjustableArrowCapFillState(GpAdjustableArrowCap
* cap
, BOOL
* fill
)
366 TRACE("(%p,%p)\n", cap
, fill
);
369 return InvalidParameter
;
371 *fill
= cap
->cap
.fill
;
375 GpStatus WINGDIPAPI
GdipGetAdjustableArrowCapHeight(GpAdjustableArrowCap
* cap
, REAL
* height
)
377 TRACE("(%p,%p)\n", cap
, height
);
380 return InvalidParameter
;
382 *height
= cap
->height
;
386 GpStatus WINGDIPAPI
GdipGetAdjustableArrowCapMiddleInset(GpAdjustableArrowCap
* cap
, REAL
* middle
)
388 TRACE("(%p,%p)\n", cap
, middle
);
391 return InvalidParameter
;
393 *middle
= cap
->middle_inset
;
397 GpStatus WINGDIPAPI
GdipGetAdjustableArrowCapWidth(GpAdjustableArrowCap
* cap
, REAL
* width
)
399 TRACE("(%p,%p)\n", cap
, width
);
402 return InvalidParameter
;
408 GpStatus WINGDIPAPI
GdipSetAdjustableArrowCapFillState(GpAdjustableArrowCap
* cap
, BOOL fill
)
410 TRACE("(%p,%i)\n", cap
, fill
);
413 return InvalidParameter
;
415 cap
->cap
.fill
= fill
;
416 arrowcap_update_path(cap
);
420 GpStatus WINGDIPAPI
GdipSetAdjustableArrowCapHeight(GpAdjustableArrowCap
* cap
, REAL height
)
422 TRACE("(%p,%0.2f)\n", cap
, height
);
425 return InvalidParameter
;
427 cap
->height
= height
;
428 arrowcap_update_path(cap
);
432 GpStatus WINGDIPAPI
GdipSetAdjustableArrowCapMiddleInset(GpAdjustableArrowCap
* cap
, REAL middle
)
434 TRACE("(%p,%0.2f)\n", cap
, middle
);
437 return InvalidParameter
;
439 cap
->middle_inset
= middle
;
440 arrowcap_update_path(cap
);
444 GpStatus WINGDIPAPI
GdipSetAdjustableArrowCapWidth(GpAdjustableArrowCap
* cap
, REAL width
)
446 TRACE("(%p,%0.2f)\n", cap
, width
);
449 return InvalidParameter
;
452 arrowcap_update_path(cap
);