Permalink
Browse files

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.
  • Loading branch information...
1 parent 69db5de commit afb6c6271f3010f1fe78528e371e50bc66224ece @dickp dickp committed Sep 16, 2010
Showing with 391 additions and 38 deletions.
  1. +59 −1 src/adjustablearrowcap.c
  2. +3 −0 src/customlinecap-private.h
  3. +170 −3 src/customlinecap.c
  4. +66 −4 src/graphics-cairo.c
  5. +4 −0 src/pen-private.h
  6. +89 −30 src/pen.c
View
@@ -23,10 +23,12 @@
*/
#include "adjustablearrowcap-private.h"
+#include "graphics-private.h"
static GpStatus gdip_adjust_arrowcap_setup (GpGraphics *graphics, GpCustomLineCap *cap);
static GpStatus gdip_adjust_arrowcap_clone_cap (GpCustomLineCap *cap, GpCustomLineCap **clonedCap);
static GpStatus gdip_adjust_arrowcap_destroy (GpCustomLineCap *cap);
+static GpStatus gdip_adjust_arrowcap_draw (GpGraphics *graphics, GpPen *pen, GpCustomLineCap *Cap, float x, float y, float otherend_x, float otherend_y);
/*
* we have a single copy of vtable for
@@ -36,14 +38,17 @@ static GpStatus gdip_adjust_arrowcap_destroy (GpCustomLineCap *cap);
static CapClass vtable = { CustomLineCapTypeAdjustableArrow,
gdip_adjust_arrowcap_setup,
gdip_adjust_arrowcap_clone_cap,
- gdip_adjust_arrowcap_destroy };
+ gdip_adjust_arrowcap_destroy,
+ gdip_adjust_arrowcap_draw };
static void
gdip_adjust_arrowcap_init (GpAdjustableArrowCap *arrow)
{
gdip_custom_linecap_init (&arrow->base, &vtable);
arrow->fill_state = TRUE;
arrow->middle_inset = 0.0;
+ arrow->width = 0.0;
+ arrow->height = 0.0;
}
static GpAdjustableArrowCap*
@@ -96,6 +101,59 @@ gdip_adjust_arrowcap_setup (GpGraphics *graphics, GpCustomLineCap *customCap)
return NotImplemented;
}
+GpStatus
+gdip_adjust_arrowcap_draw (GpGraphics *graphics, GpPen *pen, GpCustomLineCap *customCap, float x, float y, float otherend_x, float otherend_y)
+{
+ double angle;
+ GpAdjustableArrowCap *arrowcap;
+ float w;
+ float h;
+ float penwidth;
+
+ if (!graphics || !customCap)
+ return InvalidParameter;
+
+ penwidth = pen->width;
+ if (penwidth < 2.0) {
+ /* Seems to be a minimum */
+ penwidth = 2.0;
+ }
+
+ arrowcap = (GpAdjustableArrowCap *)customCap;
+ w = arrowcap->width / 2;
+ h = arrowcap->height;
+
+ /* Vertical lines need some assistance to point the arrowhead correctly */
+ if ((x == otherend_x) &&
+ (y < otherend_y)) {
+ h = -h;
+ }
+
+ angle = gdip_custom_linecap_angle (x, y, otherend_x, otherend_y);
+
+ cairo_save (graphics->ct);
+
+ /* FIXME: handle base_inset (including set/get!) */
+ cairo_translate (graphics->ct, x, y);
+ cairo_rotate (graphics->ct, angle);
+
+ gdip_cairo_move_to (graphics, 0, 0, TRUE, TRUE);
+ gdip_cairo_line_to (graphics, -w * penwidth, -h * penwidth, TRUE, TRUE);
+ gdip_cairo_line_to (graphics, w * penwidth, -h * penwidth, TRUE, TRUE);
+ gdip_cairo_line_to (graphics, 0, 0, TRUE, TRUE);
+
+ if (arrowcap->fill_state) {
+ /* FIXME: handle middle_inset */
+ cairo_fill_preserve (graphics->ct);
+ }
+
+ cairo_stroke (graphics->ct);
+
+ cairo_restore (graphics->ct);
+
+ return Ok;
+}
+
/* AdjustableArrowCap functions */
// coverity[+alloc : arg-*3]
@@ -42,6 +42,7 @@ typedef struct _CapClass {
GpStatus (*setup) (GpGraphics *graphics, GpCustomLineCap *cap);
GpStatus (*clone_cap) (GpCustomLineCap *cap, GpCustomLineCap **clonedCap);
GpStatus (*destroy) (GpCustomLineCap *cap);
+ GpStatus (*draw) (GpGraphics *graphics, GpPen *pen, GpCustomLineCap *cap, float x, float y, float otherend_x, float otherend_y);
} CapClass;
typedef struct _CustomLineCap {
@@ -58,6 +59,8 @@ typedef struct _CustomLineCap {
void gdip_custom_linecap_init (GpCustomLineCap *cap, CapClass *vt) GDIP_INTERNAL;
GpStatus gdip_linecap_setup (GpGraphics *graphics, GpCustomLineCap *customCap) GDIP_INTERNAL;
+GpStatus gdip_linecap_draw (GpGraphics *graphics, GpPen *pen, GpCustomLineCap *customCap, float x, float y, float otherend_x, float otherend_y) GDIP_INTERNAL;
+double gdip_custom_linecap_angle (float x, float y, float otherend_x, float otherend_y);
#include "customlinecap.h"
View
@@ -25,10 +25,14 @@
*/
#include "customlinecap-private.h"
+#include "graphics-path-private.h"
+#include "graphics-private.h"
+#include "graphics-cairo-private.h"
static GpStatus gdip_custom_linecap_setup (GpGraphics *graphics, GpCustomLineCap *cap);
static GpStatus gdip_custom_linecap_clone_cap (GpCustomLineCap *cap, GpCustomLineCap **clonedCap);
static GpStatus gdip_custom_linecap_destroy (GpCustomLineCap *cap);
+static GpStatus gdip_custom_linecap_draw (GpGraphics *graphics, GpPen *pen, GpCustomLineCap *cap, float x, float y, float otherend_x, float otherend_y);
/*
* we have a single copy of vtable for
@@ -38,7 +42,8 @@ static GpStatus gdip_custom_linecap_destroy (GpCustomLineCap *cap);
static CapClass vtable = { CustomLineCapTypeDefault,
gdip_custom_linecap_setup,
gdip_custom_linecap_clone_cap,
- gdip_custom_linecap_destroy };
+ gdip_custom_linecap_destroy,
+ gdip_custom_linecap_draw };
void
gdip_custom_linecap_init (GpCustomLineCap *cap, CapClass *vt)
@@ -51,6 +56,8 @@ gdip_custom_linecap_init (GpCustomLineCap *cap, CapClass *vt)
cap->base_inset = 0.0;
/* LAMESPEC: Default value is documented as 1.0, but actually it is 0.0 */
cap->width_scale = 0.0;
+ cap->fill_path = NULL;
+ cap->stroke_path = NULL;
}
static GpCustomLineCap*
@@ -68,6 +75,7 @@ GpStatus
gdip_custom_linecap_clone_cap (GpCustomLineCap *cap, GpCustomLineCap **clonedCap)
{
GpCustomLineCap *newcap;
+ GpPath *fillpath = NULL, *strokepath = NULL;
if (!cap || !clonedCap)
return InvalidParameter;
@@ -84,6 +92,27 @@ gdip_custom_linecap_clone_cap (GpCustomLineCap *cap, GpCustomLineCap **clonedCap
newcap->base_inset = cap->base_inset;
newcap->width_scale = cap->width_scale;
+ if (cap->fill_path) {
+ if (GdipClonePath (cap->fill_path, &fillpath) != Ok) {
+ if (fillpath != NULL)
+ GdipFree (fillpath);
+ GdipFree (newcap);
+ return OutOfMemory;
+ }
+ }
+ newcap->fill_path = fillpath;
+
+ if (cap->stroke_path) {
+ if (GdipClonePath (cap->stroke_path, &strokepath) != Ok) {
+ if (strokepath != NULL)
+ GdipFree (strokepath);
+ GdipFree (fillpath);
+ GdipFree (newcap);
+ return OutOfMemory;
+ }
+ }
+ newcap->stroke_path = strokepath;
+
*clonedCap = newcap;
return Ok;
@@ -95,6 +124,14 @@ gdip_custom_linecap_destroy (GpCustomLineCap *cap)
if (!cap)
return InvalidParameter;
+ if (cap->fill_path) {
+ GdipDeletePath (cap->fill_path);
+ cap->fill_path = NULL;
+ }
+ if (cap->stroke_path) {
+ GdipDeletePath (cap->stroke_path);
+ cap->stroke_path = NULL;
+ }
GdipFree (cap);
return Ok;
@@ -110,6 +147,105 @@ gdip_custom_linecap_setup (GpGraphics *graphics, GpCustomLineCap *customCap)
return NotImplemented;
}
+double
+gdip_custom_linecap_angle (float x, float y, float otherend_x, float otherend_y)
+{
+ float slope;
+ double angle;
+
+ if (y < otherend_y) {
+ slope = (otherend_y - y) / (otherend_x - x);
+ if (x < otherend_x) {
+ angle = PI/2;
+ } else {
+ angle = PI/-2;
+ }
+ } else {
+ slope = (otherend_x - x) / (y - otherend_y);
+ angle = 0;
+ }
+ angle += atan (slope);
+
+ return angle;
+}
+
+GpStatus
+gdip_custom_linecap_draw (GpGraphics *graphics, GpPen *pen, GpCustomLineCap *customCap, float x, float y, float otherend_x, float otherend_y)
+{
+ double angle;
+ int points;
+ int i, idx = 0;
+ float penwidth;
+
+ if (!graphics || !pen || !customCap)
+ return InvalidParameter;
+
+ penwidth = pen->width;
+ angle = gdip_custom_linecap_angle (x, y, otherend_x, otherend_y);
+
+ cairo_save (graphics->ct);
+
+ /* FIXME: handle base_inset (including set/get!) */
+ cairo_translate (graphics->ct, x, y);
+ cairo_rotate (graphics->ct, angle);
+
+ if (customCap->stroke_path) {
+ GpPath *path = customCap->stroke_path;
+ points = path->count;
+
+ for (i = 0; i < points; i++) {
+ /* Adapted from gdip_plot_path() */
+ GpPointF point = g_array_index (path->points, GpPointF, i);
+ BYTE type = g_array_index (path->types, BYTE, i);
+ GpPointF pts [3];
+
+ /* mask the bits so that we get only the type value not the other flags */
+ switch (type & PathPointTypePathTypeMask) {
+ case PathPointTypeStart:
+ gdip_cairo_move_to (graphics, point.X * penwidth, point.Y * penwidth, TRUE, TRUE);
+ break;
+
+ case PathPointTypeLine:
+ gdip_cairo_line_to (graphics, point.X * penwidth, point.Y * penwidth, TRUE, TRUE);
+ break;
+
+ case PathPointTypeBezier:
+ /* make sure we only add at most 3 points to pts */
+ if (idx < 3) {
+ pts [idx] = point;
+ idx ++;
+ }
+
+ /* once we've added 3 pts, we can draw the curve */
+ if (idx == 3) {
+ 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);
+ idx = 0;
+ }
+ break;
+
+ default:
+ g_warning ("Unknown PathPointType %d", type);
+ return NotImplemented;
+ }
+
+ /* close the subpath */
+ if (type & PathPointTypeCloseSubpath) {
+ cairo_close_path (graphics->ct);
+ }
+ }
+
+ gdip_pen_setup (graphics, pen);
+ cairo_stroke (graphics->ct);
+ cairo_set_matrix (graphics->ct, graphics->copy_of_ctm);
+ }
+
+ /* FIXME: handle fill_path */
+
+ cairo_restore (graphics->ct);
+
+ return gdip_get_status (cairo_status (graphics->ct));
+}
+
/* this setup function gets called from pen */
GpStatus
@@ -121,13 +257,25 @@ gdip_linecap_setup (GpGraphics *graphics, GpCustomLineCap *customCap)
return customCap->vtable->setup (graphics, customCap);
}
+/* this draw function gets called from pen */
+
+GpStatus
+gdip_linecap_draw (GpGraphics *graphics, GpPen *pen, GpCustomLineCap *customCap, float x, float y, float otherend_x, float otherend_y)
+{
+ if (!graphics || !pen || !customCap)
+ return InvalidParameter;
+
+ return customCap->vtable->draw (graphics, pen, customCap, x, y, otherend_x, otherend_y);
+}
+
/* CustomLineCap functions */
// coverity[+alloc : arg-*4]
GpStatus
GdipCreateCustomLineCap (GpPath *fillPath, GpPath *strokePath, GpLineCap baseCap, float baseInset, GpCustomLineCap **customCap)
{
GpCustomLineCap *cap;
+ GpPath *fillpath_clone = NULL, *strokepath_clone = NULL;
if ((!fillPath && !strokePath) || !customCap)
return InvalidParameter;
@@ -136,8 +284,27 @@ GdipCreateCustomLineCap (GpPath *fillPath, GpPath *strokePath, GpLineCap baseCap
if (!cap)
return OutOfMemory;
- cap->fill_path = fillPath;
- cap->stroke_path = strokePath;
+ if (fillPath) {
+ if (GdipClonePath (fillPath, &fillpath_clone) != Ok) {
+ if (fillpath_clone != NULL)
+ GdipFree (fillpath_clone);
+ GdipFree (cap);
+ return OutOfMemory;
+ }
+ }
+ cap->fill_path = fillpath_clone;
+
+ if (strokePath) {
+ if (GdipClonePath (strokePath, &strokepath_clone) != Ok) {
+ if (strokepath_clone != NULL)
+ GdipFree (strokepath_clone);
+ GdipFree (fillpath_clone);
+ GdipFree (cap);
+ return OutOfMemory;
+ }
+ }
+ cap->stroke_path = strokepath_clone;
+
cap->base_cap = baseCap;
cap->base_inset = baseInset;
Oops, something went wrong.

0 comments on commit afb6c62

Please sign in to comment.