Skip to content

Commit c440118

Browse files
committed
Implement CustomLineCap and the AdjustableArrow subclass.
* src/customlinecap.c: Implement CustomLineCap drawing, and path memory management. * src/adjustablearrowcap.c: Implement AdjustableArrow drawing. * src/pen.c: Implement CustomLineCap memory management, and call the draw functions. * src/graphics-cairo.c: Draw custom line caps in cairo_DrawLine(), cairo_DrawLines(), cairo_DrawLinesI() and cairo_DrawPath(). * src/customlinecap-private.h: Add the draw method to CapClass. * src/pen-private.h: Add custom start and end cap fields to GpPen.
1 parent d50e3e6 commit c440118

File tree

6 files changed

+391
-38
lines changed

6 files changed

+391
-38
lines changed

src/adjustablearrowcap.c

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,12 @@
2323
*/
2424

2525
#include "adjustablearrowcap-private.h"
26+
#include "graphics-private.h"
2627

2728
static GpStatus gdip_adjust_arrowcap_setup (GpGraphics *graphics, GpCustomLineCap *cap);
2829
static GpStatus gdip_adjust_arrowcap_clone_cap (GpCustomLineCap *cap, GpCustomLineCap **clonedCap);
2930
static GpStatus gdip_adjust_arrowcap_destroy (GpCustomLineCap *cap);
31+
static GpStatus gdip_adjust_arrowcap_draw (GpGraphics *graphics, GpPen *pen, GpCustomLineCap *Cap, float x, float y, float otherend_x, float otherend_y);
3032

3133
/*
3234
* we have a single copy of vtable for
@@ -36,14 +38,17 @@ static GpStatus gdip_adjust_arrowcap_destroy (GpCustomLineCap *cap);
3638
static CapClass vtable = { CustomLineCapTypeAdjustableArrow,
3739
gdip_adjust_arrowcap_setup,
3840
gdip_adjust_arrowcap_clone_cap,
39-
gdip_adjust_arrowcap_destroy };
41+
gdip_adjust_arrowcap_destroy,
42+
gdip_adjust_arrowcap_draw };
4043

4144
static void
4245
gdip_adjust_arrowcap_init (GpAdjustableArrowCap *arrow)
4346
{
4447
gdip_custom_linecap_init (&arrow->base, &vtable);
4548
arrow->fill_state = TRUE;
4649
arrow->middle_inset = 0.0;
50+
arrow->width = 0.0;
51+
arrow->height = 0.0;
4752
}
4853

4954
static GpAdjustableArrowCap*
@@ -96,6 +101,59 @@ gdip_adjust_arrowcap_setup (GpGraphics *graphics, GpCustomLineCap *customCap)
96101
return NotImplemented;
97102
}
98103

104+
GpStatus
105+
gdip_adjust_arrowcap_draw (GpGraphics *graphics, GpPen *pen, GpCustomLineCap *customCap, float x, float y, float otherend_x, float otherend_y)
106+
{
107+
double angle;
108+
GpAdjustableArrowCap *arrowcap;
109+
float w;
110+
float h;
111+
float penwidth;
112+
113+
if (!graphics || !customCap)
114+
return InvalidParameter;
115+
116+
penwidth = pen->width;
117+
if (penwidth < 2.0) {
118+
/* Seems to be a minimum */
119+
penwidth = 2.0;
120+
}
121+
122+
arrowcap = (GpAdjustableArrowCap *)customCap;
123+
w = arrowcap->width / 2;
124+
h = arrowcap->height;
125+
126+
/* Vertical lines need some assistance to point the arrowhead correctly */
127+
if ((x == otherend_x) &&
128+
(y < otherend_y)) {
129+
h = -h;
130+
}
131+
132+
angle = gdip_custom_linecap_angle (x, y, otherend_x, otherend_y);
133+
134+
cairo_save (graphics->ct);
135+
136+
/* FIXME: handle base_inset (including set/get!) */
137+
cairo_translate (graphics->ct, x, y);
138+
cairo_rotate (graphics->ct, angle);
139+
140+
gdip_cairo_move_to (graphics, 0, 0, TRUE, TRUE);
141+
gdip_cairo_line_to (graphics, -w * penwidth, -h * penwidth, TRUE, TRUE);
142+
gdip_cairo_line_to (graphics, w * penwidth, -h * penwidth, TRUE, TRUE);
143+
gdip_cairo_line_to (graphics, 0, 0, TRUE, TRUE);
144+
145+
if (arrowcap->fill_state) {
146+
/* FIXME: handle middle_inset */
147+
cairo_fill_preserve (graphics->ct);
148+
}
149+
150+
cairo_stroke (graphics->ct);
151+
152+
cairo_restore (graphics->ct);
153+
154+
return Ok;
155+
}
156+
99157
/* AdjustableArrowCap functions */
100158

101159
// coverity[+alloc : arg-*3]

src/customlinecap-private.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ typedef struct _CapClass {
4242
GpStatus (*setup) (GpGraphics *graphics, GpCustomLineCap *cap);
4343
GpStatus (*clone_cap) (GpCustomLineCap *cap, GpCustomLineCap **clonedCap);
4444
GpStatus (*destroy) (GpCustomLineCap *cap);
45+
GpStatus (*draw) (GpGraphics *graphics, GpPen *pen, GpCustomLineCap *cap, float x, float y, float otherend_x, float otherend_y);
4546
} CapClass;
4647

4748
typedef struct _CustomLineCap {
@@ -58,6 +59,8 @@ typedef struct _CustomLineCap {
5859

5960
void gdip_custom_linecap_init (GpCustomLineCap *cap, CapClass *vt) GDIP_INTERNAL;
6061
GpStatus gdip_linecap_setup (GpGraphics *graphics, GpCustomLineCap *customCap) GDIP_INTERNAL;
62+
GpStatus gdip_linecap_draw (GpGraphics *graphics, GpPen *pen, GpCustomLineCap *customCap, float x, float y, float otherend_x, float otherend_y) GDIP_INTERNAL;
63+
double gdip_custom_linecap_angle (float x, float y, float otherend_x, float otherend_y);
6164

6265
#include "customlinecap.h"
6366

src/customlinecap.c

Lines changed: 170 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,14 @@
2525
*/
2626

2727
#include "customlinecap-private.h"
28+
#include "graphics-path-private.h"
29+
#include "graphics-private.h"
30+
#include "graphics-cairo-private.h"
2831

2932
static GpStatus gdip_custom_linecap_setup (GpGraphics *graphics, GpCustomLineCap *cap);
3033
static GpStatus gdip_custom_linecap_clone_cap (GpCustomLineCap *cap, GpCustomLineCap **clonedCap);
3134
static GpStatus gdip_custom_linecap_destroy (GpCustomLineCap *cap);
35+
static GpStatus gdip_custom_linecap_draw (GpGraphics *graphics, GpPen *pen, GpCustomLineCap *cap, float x, float y, float otherend_x, float otherend_y);
3236

3337
/*
3438
* we have a single copy of vtable for
@@ -38,7 +42,8 @@ static GpStatus gdip_custom_linecap_destroy (GpCustomLineCap *cap);
3842
static CapClass vtable = { CustomLineCapTypeDefault,
3943
gdip_custom_linecap_setup,
4044
gdip_custom_linecap_clone_cap,
41-
gdip_custom_linecap_destroy };
45+
gdip_custom_linecap_destroy,
46+
gdip_custom_linecap_draw };
4247

4348
void
4449
gdip_custom_linecap_init (GpCustomLineCap *cap, CapClass *vt)
@@ -51,6 +56,8 @@ gdip_custom_linecap_init (GpCustomLineCap *cap, CapClass *vt)
5156
cap->base_inset = 0.0;
5257
/* LAMESPEC: Default value is documented as 1.0, but actually it is 0.0 */
5358
cap->width_scale = 0.0;
59+
cap->fill_path = NULL;
60+
cap->stroke_path = NULL;
5461
}
5562

5663
static GpCustomLineCap*
@@ -68,6 +75,7 @@ GpStatus
6875
gdip_custom_linecap_clone_cap (GpCustomLineCap *cap, GpCustomLineCap **clonedCap)
6976
{
7077
GpCustomLineCap *newcap;
78+
GpPath *fillpath = NULL, *strokepath = NULL;
7179

7280
if (!cap || !clonedCap)
7381
return InvalidParameter;
@@ -84,6 +92,27 @@ gdip_custom_linecap_clone_cap (GpCustomLineCap *cap, GpCustomLineCap **clonedCap
8492
newcap->base_inset = cap->base_inset;
8593
newcap->width_scale = cap->width_scale;
8694

95+
if (cap->fill_path) {
96+
if (GdipClonePath (cap->fill_path, &fillpath) != Ok) {
97+
if (fillpath != NULL)
98+
GdipFree (fillpath);
99+
GdipFree (newcap);
100+
return OutOfMemory;
101+
}
102+
}
103+
newcap->fill_path = fillpath;
104+
105+
if (cap->stroke_path) {
106+
if (GdipClonePath (cap->stroke_path, &strokepath) != Ok) {
107+
if (strokepath != NULL)
108+
GdipFree (strokepath);
109+
GdipFree (fillpath);
110+
GdipFree (newcap);
111+
return OutOfMemory;
112+
}
113+
}
114+
newcap->stroke_path = strokepath;
115+
87116
*clonedCap = newcap;
88117

89118
return Ok;
@@ -95,6 +124,14 @@ gdip_custom_linecap_destroy (GpCustomLineCap *cap)
95124
if (!cap)
96125
return InvalidParameter;
97126

127+
if (cap->fill_path) {
128+
GdipDeletePath (cap->fill_path);
129+
cap->fill_path = NULL;
130+
}
131+
if (cap->stroke_path) {
132+
GdipDeletePath (cap->stroke_path);
133+
cap->stroke_path = NULL;
134+
}
98135
GdipFree (cap);
99136

100137
return Ok;
@@ -110,6 +147,105 @@ gdip_custom_linecap_setup (GpGraphics *graphics, GpCustomLineCap *customCap)
110147
return NotImplemented;
111148
}
112149

150+
double
151+
gdip_custom_linecap_angle (float x, float y, float otherend_x, float otherend_y)
152+
{
153+
float slope;
154+
double angle;
155+
156+
if (y < otherend_y) {
157+
slope = (otherend_y - y) / (otherend_x - x);
158+
if (x < otherend_x) {
159+
angle = PI/2;
160+
} else {
161+
angle = PI/-2;
162+
}
163+
} else {
164+
slope = (otherend_x - x) / (y - otherend_y);
165+
angle = 0;
166+
}
167+
angle += atan (slope);
168+
169+
return angle;
170+
}
171+
172+
GpStatus
173+
gdip_custom_linecap_draw (GpGraphics *graphics, GpPen *pen, GpCustomLineCap *customCap, float x, float y, float otherend_x, float otherend_y)
174+
{
175+
double angle;
176+
int points;
177+
int i, idx = 0;
178+
float penwidth;
179+
180+
if (!graphics || !pen || !customCap)
181+
return InvalidParameter;
182+
183+
penwidth = pen->width;
184+
angle = gdip_custom_linecap_angle (x, y, otherend_x, otherend_y);
185+
186+
cairo_save (graphics->ct);
187+
188+
/* FIXME: handle base_inset (including set/get!) */
189+
cairo_translate (graphics->ct, x, y);
190+
cairo_rotate (graphics->ct, angle);
191+
192+
if (customCap->stroke_path) {
193+
GpPath *path = customCap->stroke_path;
194+
points = path->count;
195+
196+
for (i = 0; i < points; i++) {
197+
/* Adapted from gdip_plot_path() */
198+
GpPointF point = g_array_index (path->points, GpPointF, i);
199+
BYTE type = g_array_index (path->types, BYTE, i);
200+
GpPointF pts [3];
201+
202+
/* mask the bits so that we get only the type value not the other flags */
203+
switch (type & PathPointTypePathTypeMask) {
204+
case PathPointTypeStart:
205+
gdip_cairo_move_to (graphics, point.X * penwidth, point.Y * penwidth, TRUE, TRUE);
206+
break;
207+
208+
case PathPointTypeLine:
209+
gdip_cairo_line_to (graphics, point.X * penwidth, point.Y * penwidth, TRUE, TRUE);
210+
break;
211+
212+
case PathPointTypeBezier:
213+
/* make sure we only add at most 3 points to pts */
214+
if (idx < 3) {
215+
pts [idx] = point;
216+
idx ++;
217+
}
218+
219+
/* once we've added 3 pts, we can draw the curve */
220+
if (idx == 3) {
221+
gdip_cairo_curve_to (graphics, pts[0].X * penwidth, pts[0].Y * penwidth, pts[1].X * penwidth, pts[1].Y * penwidth, pts[2].X * penwidth, pts[2].Y * penwidth, TRUE, TRUE);
222+
idx = 0;
223+
}
224+
break;
225+
226+
default:
227+
g_warning ("Unknown PathPointType %d", type);
228+
return NotImplemented;
229+
}
230+
231+
/* close the subpath */
232+
if (type & PathPointTypeCloseSubpath) {
233+
cairo_close_path (graphics->ct);
234+
}
235+
}
236+
237+
gdip_pen_setup (graphics, pen);
238+
cairo_stroke (graphics->ct);
239+
cairo_set_matrix (graphics->ct, graphics->copy_of_ctm);
240+
}
241+
242+
/* FIXME: handle fill_path */
243+
244+
cairo_restore (graphics->ct);
245+
246+
return gdip_get_status (cairo_status (graphics->ct));
247+
}
248+
113249
/* this setup function gets called from pen */
114250

115251
GpStatus
@@ -121,13 +257,25 @@ gdip_linecap_setup (GpGraphics *graphics, GpCustomLineCap *customCap)
121257
return customCap->vtable->setup (graphics, customCap);
122258
}
123259

260+
/* this draw function gets called from pen */
261+
262+
GpStatus
263+
gdip_linecap_draw (GpGraphics *graphics, GpPen *pen, GpCustomLineCap *customCap, float x, float y, float otherend_x, float otherend_y)
264+
{
265+
if (!graphics || !pen || !customCap)
266+
return InvalidParameter;
267+
268+
return customCap->vtable->draw (graphics, pen, customCap, x, y, otherend_x, otherend_y);
269+
}
270+
124271
/* CustomLineCap functions */
125272

126273
// coverity[+alloc : arg-*4]
127274
GpStatus
128275
GdipCreateCustomLineCap (GpPath *fillPath, GpPath *strokePath, GpLineCap baseCap, float baseInset, GpCustomLineCap **customCap)
129276
{
130277
GpCustomLineCap *cap;
278+
GpPath *fillpath_clone = NULL, *strokepath_clone = NULL;
131279

132280
if ((!fillPath && !strokePath) || !customCap)
133281
return InvalidParameter;
@@ -136,8 +284,27 @@ GdipCreateCustomLineCap (GpPath *fillPath, GpPath *strokePath, GpLineCap baseCap
136284
if (!cap)
137285
return OutOfMemory;
138286

139-
cap->fill_path = fillPath;
140-
cap->stroke_path = strokePath;
287+
if (fillPath) {
288+
if (GdipClonePath (fillPath, &fillpath_clone) != Ok) {
289+
if (fillpath_clone != NULL)
290+
GdipFree (fillpath_clone);
291+
GdipFree (cap);
292+
return OutOfMemory;
293+
}
294+
}
295+
cap->fill_path = fillpath_clone;
296+
297+
if (strokePath) {
298+
if (GdipClonePath (strokePath, &strokepath_clone) != Ok) {
299+
if (strokepath_clone != NULL)
300+
GdipFree (strokepath_clone);
301+
GdipFree (fillpath_clone);
302+
GdipFree (cap);
303+
return OutOfMemory;
304+
}
305+
}
306+
cap->stroke_path = strokepath_clone;
307+
141308
cap->base_cap = baseCap;
142309
cap->base_inset = baseInset;
143310

0 commit comments

Comments
 (0)