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
= malloc(sizeof(GpCustomLineCap
));
45 *to
= malloc(sizeof(GpAdjustableArrowCap
));
50 if (from
->type
== CustomLineCapTypeDefault
)
53 *(GpAdjustableArrowCap
*)*to
= *(GpAdjustableArrowCap
*)from
;
55 /* Duplicate path data */
56 (*to
)->pathdata
.Points
= malloc(from
->pathdata
.Count
* sizeof(PointF
));
57 (*to
)->pathdata
.Types
= malloc(from
->pathdata
.Count
);
59 if((!(*to
)->pathdata
.Types
|| !(*to
)->pathdata
.Points
) && (*to
)->pathdata
.Count
){
60 free((*to
)->pathdata
.Points
);
61 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
= malloc(pathdata
->Count
* sizeof(PointF
));
81 cap
->pathdata
.Types
= malloc(pathdata
->Count
);
83 if ((!cap
->pathdata
.Types
|| !cap
->pathdata
.Points
) && pathdata
->Count
)
85 free(cap
->pathdata
.Points
);
86 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 /* 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
;
117 TRACE("%p %p %d %f %p\n", fillPath
, strokePath
, baseCap
, baseInset
, customCap
);
119 if(!customCap
|| !(fillPath
|| strokePath
))
120 return InvalidParameter
;
122 *customCap
= calloc(1, sizeof(GpCustomLineCap
));
123 if(!*customCap
) return OutOfMemory
;
126 pathdata
= &strokePath
->pathdata
;
128 pathdata
= &fillPath
->pathdata
;
130 stat
= init_custom_linecap(*customCap
, pathdata
, fillPath
!= NULL
, baseCap
, baseInset
);
137 TRACE("<-- %p\n", *customCap
);
142 GpStatus WINGDIPAPI
GdipDeleteCustomLineCap(GpCustomLineCap
*customCap
)
144 TRACE("(%p)\n", customCap
);
147 return InvalidParameter
;
149 free(customCap
->pathdata
.Points
);
150 free(customCap
->pathdata
.Types
);
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
;
169 GpStatus WINGDIPAPI
GdipGetCustomLineCapWidthScale(GpCustomLineCap
* custom
,
172 TRACE("(%p, %p)\n", custom
, widthScale
);
174 if(!custom
|| !widthScale
)
175 return InvalidParameter
;
177 *widthScale
= custom
->scale
;
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
;
196 GpStatus WINGDIPAPI
GdipSetCustomLineCapBaseCap(GpCustomLineCap
* custom
,
199 TRACE("(%p,%u)\n", custom
, basecap
);
200 if(!custom
|| basecap
> LineCapTriangle
)
201 return InvalidParameter
;
203 custom
->basecap
= basecap
;
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
,
224 TRACE("(%p,%0.2f)\n", custom
, inset
);
227 return InvalidParameter
;
229 custom
->inset
= inset
;
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
->basecap
;
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
/ 2.0;
316 points
[0].Y
= -cap
->height
;
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;
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
= calloc(1, 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
);