]> granicus.if.org Git - graphviz/commitdiff
Added gradient fill feature
authorDwight Perry <dperry@research.att.com>
Tue, 10 Jan 2012 15:38:11 +0000 (10:38 -0500)
committerDwight Perry <dperry@research.att.com>
Tue, 10 Jan 2012 15:38:11 +0000 (10:38 -0500)
15 files changed:
lib/common/const.h
lib/common/emit.c
lib/common/globals.h
lib/common/htmllex.c
lib/common/htmltable.c
lib/common/htmltable.h
lib/common/input.c
lib/common/render.h
lib/common/shapes.c
lib/common/utils.c
lib/gvc/gvcjob.h
lib/gvc/gvcproc.h
lib/gvc/gvrender.c
plugin/core/gvrender_core_svg.c
plugin/pango/gvrender_pango.c

index befff90e93abb286f3ec730046793ace5cc61764..cdf45fba46249371929e568753040c393855362c 100644 (file)
@@ -83,6 +83,7 @@
 #define                DEFAULT_RANKSEP 0.5
 #define                MIN_RANKSEP             0.02
 
+
 /* default margin for paged formats such as PostScript - in points  = 0.5in */
 #define                DEFAULT_PRINT_MARGIN 36
 /* default margin for embedded formats such as PNG - in points */
 #define FOLDER (1 << 7)
 #define BOX3D (1 << 8)
 #define COMPONENT (1 << 9)
+#define GRADIENT (1 << 10)
+#define RGRADIENT GRADIENT + 1 /*radial gradient */
 
 /* label types */
 #define LT_NONE        (0 << 1)
index 1eed99757aefa68efdf7746c9524456de07473c1..a77ac0eabc13d766d92fc7c46bba25a26475da7e 100644 (file)
@@ -31,6 +31,7 @@
 #define P2RECT(p, pr, sx, sy) (pr[0].x = p.x - sx, pr[0].y = p.y - sy, pr[1].x = p.x + sx, pr[1].y = p.y + sy)
 #define FUZZ 3
 #define EPSILON .0001
+#define GR_SZ 50
 
 typedef struct {
     xdot_op op;
@@ -90,6 +91,9 @@ obj_state_t* push_obj_state(GVJ_t *job)
         obj->pen = parent->pen;
         obj->fill = parent->fill;
         obj->penwidth = parent->penwidth;
+       obj->gradient.angle = parent->gradient.angle;
+       obj->gradient.startcolor = parent->gradient.startcolor;
+       obj->gradient.stopcolor = parent->gradient.stopcolor;
     }
     else {
        /* obj->pencolor = NULL */
@@ -1013,8 +1017,8 @@ static void emit_xdot (GVJ_t * job, xdot* xd)
 static void emit_background(GVJ_t * job, graph_t *g)
 {
     xdot* xd;
-    char *str;
-    int dfltColor;
+    char *str,*gcolor,*style;
+    int dfltColor,filltype;
     
     /* if no bgcolor specified - first assume default of "white" */
     if (! ((str = agget(g, "bgcolor")) && str[0])) {
@@ -1023,6 +1027,19 @@ static void emit_background(GVJ_t * job, graph_t *g)
     }
     else
        dfltColor = 0;
+    
+    if (((style = agget(g, "style")) && str[0])) {
+       if(strcmp(style,"linear") == 0)
+         filltype = GRADIENT;
+       else if(strcmp(style,"radial") == 0)
+         filltype = RGRADIENT;
+       else
+         filltype = 0;
+    }
+
+   if ( filltype > 0 && ((gcolor = agget(g, "gradientcolor")) && str[0])) {
+      gvrender_set_gradient(job,g,G_gradientcolor,G_gradientangle);
+   }
 
     /* if device has no truecolor support, change "transparent" to "white" */
     if (! (job->flags & GVDEVICE_DOES_TRUECOLOR) && (streq(str, "transparent")))
@@ -1033,7 +1050,10 @@ static void emit_background(GVJ_t * job, graph_t *g)
           || ((job->flags & GVRENDER_NO_WHITE_BG) && dfltColor))) {
         gvrender_set_fillcolor(job, str);
         gvrender_set_pencolor(job, str);
-        gvrender_box(job, job->clip, TRUE);    /* filled */
+       if(filltype > 0)
+         gvrender_box(job, job->clip,filltype); /* linear or radial gradient */
+       else
+         gvrender_box(job, job->clip, TRUE);   /* filled */
     }
 
     if ((xd = (xdot*)GD_drawing(g)->xdots))
@@ -2813,6 +2833,7 @@ static void emit_colors(GVJ_t * job, graph_t * g)
        gvrender_set_fillcolor(job, str);
     if (((str = agget(g, "fontcolor")) != 0) && str[0])
        gvrender_set_pencolor(job, str);
+  
     emit_cluster_colors(job, g);
     for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
        if (((str = agget(n, "color")) != 0) && str[0])
@@ -3098,7 +3119,15 @@ static char **checkClusterStyle(graph_t* sg, int *flagp)
            if (strcmp(p, "filled") == 0) {
                istyle |= FILLED;
                pp++;
-           } else if (strcmp(p, "rounded") == 0) {
+           }
+           else if (strcmp(p, "linear") == 0) {
+               istyle |= GRADIENT;
+               pp++;
+           }
+                   if (strcmp(p, "radial") == 0) {
+               istyle |= (RGRADIENT);
+               pp++;
+           }else if (strcmp(p, "rounded") == 0) {
                istyle |= ROUNDED;
                qp = pp; /* remove rounded from list passed to renderer */
                do {
@@ -3204,6 +3233,11 @@ void emit_clusters(GVJ_t * job, Agraph_t * g, int flags)
                fillcolor = color;
                filled = TRUE;
             }
+           if (istyle & GRADIENT) {  //handles both linear and radial gradients
+             gvrender_set_gradient(job,sg,G_gradientcolor,G_gradientangle);
+             filled = FALSE;
+           } 
+
        }
        if (!pencolor) pencolor = DEFAULT_COLOR;
        if (!fillcolor) fillcolor = DEFAULT_FILL;
@@ -3231,8 +3265,14 @@ void emit_clusters(GVJ_t * job, Agraph_t * g, int flags)
        else {
            gvrender_set_pencolor(job, pencolor);
            gvrender_set_fillcolor(job, fillcolor);
-           if (late_int(sg, G_peripheries, 1, 0))
+           if (late_int(sg, G_peripheries, 1, 0)){
+             if (istyle & GRADIENT)
+                 gvrender_box(job, GD_bb(sg), istyle);
+             else
                gvrender_box(job, GD_bb(sg), filled);
+           }
+           else if (istyle & GRADIENT)
+                 gvrender_box(job, GD_bb(sg), istyle);
            else if (filled) { 
                if (fillcolor && fillcolor != pencolor)
                    gvrender_set_pencolor(job, fillcolor);
index af4f05405324e25471eea3fd284206453b061689..121539cdb15f38beb6e5c43bfe73beba4c7f1b35 100644 (file)
@@ -98,7 +98,8 @@ extern "C" {
        *G_selectedpencolor, *G_selectedfillcolor,
        *G_visitedpencolor, *G_visitedfillcolor,
        *G_deletedpencolor, *G_deletedfillcolor,
-       *G_ordering, *G_peripheries, *G_penwidth;
+       *G_ordering, *G_peripheries, *G_penwidth,
+       *G_gradientcolor,*G_gradientangle;
     EXTERN attrsym_t
        *N_height, *N_width, *N_shape, *N_color, *N_fillcolor,
        *N_activepencolor, *N_activefillcolor,
@@ -110,7 +111,7 @@ extern "C" {
        *N_sides, *N_peripheries, *N_ordering, *N_orientation,
        *N_skew, *N_distortion, *N_fixed, *N_imagescale, *N_layer,
        *N_group, *N_comment, *N_vertices, *N_z,
-       *N_penwidth;
+       *N_penwidth,*N_gradientcolor, *N_gradientangle;
     EXTERN attrsym_t
        *E_weight, *E_minlen, *E_color,
        *E_activepencolor, *E_activefillcolor,
index c044137ee9994e6d1fbf70f8b7945728e7badaee..1d6a63f075cf1e3724456ea0b26a30417888bcb4 100644 (file)
@@ -160,6 +160,19 @@ static int idfn(htmldata_t * p, char *v)
     return 0;
 }
 
+static int gradientfn(htmldata_t * p, char *v)
+{
+    p->gradient = strdup(v);
+    return 0;
+}
+
+static int gradientcolorfn(htmldata_t * p, char *v)
+{
+    p->gradientcolor = strdup(v);
+    return 0;
+}
+
+
 /* doInt:
  * Scan v for integral value. Check that
  * the value is >= min and <= max. Return value in ul.
@@ -434,6 +447,8 @@ static attr_item tbl_items[] = {
     {"color", (attrFn) pencolorfn},
     {"columns", (attrFn) columnsfn},
     {"fixedsize", (attrFn) fixedsizefn},
+    {"gradient", (attrFn) gradientfn},
+    {"gradientcolor", (attrFn) gradientcolorfn},
     {"height", (attrFn) heightfn},
     {"href", (attrFn) hreffn},
     {"id", (attrFn) idfn},
@@ -457,6 +472,8 @@ static attr_item cell_items[] = {
     {"color", (attrFn) pencolorfn},
     {"colspan", (attrFn) colspanfn},
     {"fixedsize", (attrFn) fixedsizefn},
+    {"gradient", (attrFn) gradientfn},
+    {"gradientcolor", (attrFn) gradientcolorfn},
     {"height", (attrFn) heightfn},
     {"href", (attrFn) hreffn},
     {"id", (attrFn) idfn},
index 7f8015c6da6ef5165baee8ab4009ec1419be1a24..de878f5aa0b793dc0f3b46189d848173a927f44d 100644 (file)
@@ -259,6 +259,13 @@ static void doFill(GVJ_t * job, char *color, boxf BF)
     gvrender_box(job, BF, 1);
 }
 
+static void doGrdtFill(GVJ_t * job, char *color, boxf BF, int gradient)
+{
+    //gvrender_set_fillcolor(job, color);
+    gvrender_set_pencolor(job, color);
+    gvrender_box(job, BF, gradient);
+}
+
 /* initAnchor:
  * Save current map values
  * Initialize fields in job->obj pertaining to anchors.
@@ -432,6 +439,8 @@ emit_html_tbl(GVJ_t * job, htmltbl_t * tbl, htmlenv_t * env)
     int anchor; /* if true, we need to undo anchor settings. */
     int doAnchor = (tbl->data.href || tbl->data.target);
     pointf AF[4];
+    int gradient;
+    char *bordercolor;
 
     if (tbl->font)
        pushFontInfo(env, tbl->font, &savef);
@@ -445,7 +454,6 @@ emit_html_tbl(GVJ_t * job, htmltbl_t * tbl, htmlenv_t * env)
        anchor = initAnchor(job, env, &tbl->data, pts, &saved, 1);
     else
        anchor = 0;
-
     /* Set up rounded style */
     if (tbl->style & ROUNDED) {
        AF[0] = pts.LL;
@@ -465,11 +473,29 @@ emit_html_tbl(GVJ_t * job, htmltbl_t * tbl, htmlenv_t * env)
 
     /* Fill first */
     if (tbl->data.bgcolor) {
-       if (tbl->style & ROUNDED)
+       if (tbl->style & ROUNDED){
            round_corners (job, tbl->data.bgcolor, NULL, AF, 4, tbl->style, 1);
+       }
        else
            doFill(job, tbl->data.bgcolor, pts);
+     }
+     
+    if (tbl->data.gradient && tbl->data.gradientcolor) {
+       if (strcmp(tbl->data.gradient,"linear") == 0)
+          gradient = GRADIENT;
+       else if (strcmp(tbl->data.gradient,"radial") == 0)
+           gradient = RGRADIENT;
+       else
+           gradient = 0;
+       bordercolor = gvrender_set_gradient_values(job, tbl->data.gradientcolor, 0);        
+       
+       if (tbl->style & ROUNDED){
+           round_corners (job, bordercolor, NULL, AF, 4, tbl->style, gradient);
+       }
+       else
+           doGrdtFill(job, bordercolor, pts,gradient);
     }
+     
 
     while (*cells) {
        emit_html_cell(job, *cells, env);
@@ -547,6 +573,8 @@ emit_html_cell(GVJ_t * job, htmlcell_t * cp, htmlenv_t * env)
     boxf pts = cp->data.box;
     pointf pos = env->pos;
     int inAnchor, doAnchor = (cp->data.href || cp->data.target);
+    int gradient;
+    char *bordercolor;
 
     pts.LL.x += pos.x;
     pts.UR.x += pos.x;
@@ -558,12 +586,22 @@ emit_html_cell(GVJ_t * job, htmlcell_t * cp, htmlenv_t * env)
     else
        inAnchor = 0;
 
-    if (cp->data.bgcolor) {
+    if (cp->data.bgcolor)
        doFill(job, cp->data.bgcolor, pts);
-    }
 
     if (cp->data.border)
        doBorder(job, cp->data.pencolor, cp->data.border, pts);
+    
+    if(cp->data.gradient && cp->data.gradientcolor){
+       if(strcmp(cp->data.gradient,"linear")==0)
+         gradient = GRADIENT;
+       else if (strcmp(cp->data.gradient,"radial")==0)
+         gradient = RGRADIENT;
+       else
+         gradient = 0;
+       bordercolor = gvrender_set_gradient_values(job, cp->data.gradientcolor, 0);
+       doGrdtFill(job,bordercolor, pts, gradient);
+      }
 
     if (cp->child.kind == HTML_TBL)
        emit_html_tbl(job, cp->child.u.tbl, env);
index f0d3cc9d3184ab4ffb2be9066be323c57df6f03d..33edfa1cebd07bcf25488af55020c233c791a21f 100644 (file)
@@ -69,6 +69,8 @@ extern "C" {
        char *id;
        char *bgcolor;
        char *pencolor;
+       char *gradient;
+       char *gradientcolor;
        signed char space;
        unsigned char border;
        unsigned char pad;
index 33f30aebd8165bea7cfff12b57aa0418d2d93852..789e166da52cdbb27b2341ed21a4173ceac7cc7e 100644 (file)
@@ -794,6 +794,8 @@ void graph_init(graph_t * g, boolean use_rankdir)
     Initial_dist = MYHUGE;
 
     G_ordering = agfindgraphattr(g, "ordering");
+    G_gradientcolor = agfindgraphattr(g,"gradientcolor");
+    G_gradientangle = agfindgraphattr(g,"gradientangle");
 
     /* initialize nodes */
     N_height = agfindnodeattr(g, "height");
@@ -824,6 +826,8 @@ void graph_init(graph_t * g, boolean use_rankdir)
     N_comment = agfindnodeattr(g, "comment");
     N_vertices = agfindnodeattr(g, "vertices");
     N_z = agfindnodeattr(g, "z");
+    N_gradientcolor = agfindnodeattr(g,"gradientcolor");
+    N_gradientangle = agfindnodeattr(g,"gradientangle");
 
     /* initialize edges */
     E_weight = agfindedgeattr(g, "weight");
index f39c72ddfe711df52aa5559bbcff3937915db496..9167d98199c73226d8a8534edee4f23dd8a6c236 100644 (file)
@@ -160,6 +160,9 @@ extern "C" {
     extern void write_attributed_dot(graph_t *g, FILE *f);
     extern void write_canonical_dot(graph_t *g, FILE *f);
     extern boxf xdotBB (graph_t* g);
+    extern char *findStartColor(void * n, attrsym_t * attr, char *);
+    extern char *findStopColor(void * n, attrsym_t * attr, char *);
+    extern int findGradientAngle(void * n, attrsym_t * attr);
 
 #undef extern
 
index 77e7847e30c5ca8ea6a0797412cc9ea9c2028d3c..284a333d5f3fe9f63f1582d75d8d50dafb4a05a7 100644 (file)
@@ -17,6 +17,7 @@
 
 #define RBCONST 12
 #define RBCURVE .5
+#define GR_SZ 50
 
 static port Center = { {0, 0}, -1, 0, 0, 0, 1, 0, 0, 0 };
 
@@ -280,6 +281,50 @@ char *findFill(node_t * n)
     return (findFillDflt(n, DEFAULT_FILL));
 }
 
+char *findStartColor(void * n, attrsym_t * attr, char *dflt)
+{
+    char *color;
+
+    color = late_nnstring(n, attr, dflt);
+    if (!color[0]) {
+       color = late_nnstring(n, N_color, "");
+       if (!color[0]) {
+           color =  DEFAULT_FILL;
+       }
+    }
+    return color;
+}
+
+
+char *findStopColor(void * n, attrsym_t * attr, char *dflt)
+{
+    char *color,*str;
+
+    str = late_nnstring(n, attr, dflt);
+    color = strchr(str, ':');
+   if ((color == NULL) || !color[0]) {
+       color = str;
+       if (!color[0]) {
+           color = DEFAULT_FILL;
+       }
+    }
+    else {
+      color++;
+      if (!color[0]) {
+           color = DEFAULT_FILL;
+       }
+    }
+
+    return color;
+}
+
+int findGradientAngle(void * n,  attrsym_t * attr)
+{
+  int angle;
+      angle = late_int(n, attr, 0, 0);
+      return (angle);
+}
+
 static char **checkStyle(node_t * n, int *flagp)
 {
     char *style;
@@ -297,6 +342,12 @@ static char **checkStyle(node_t * n, int *flagp)
            if (streq(p, "filled")) {
                istyle |= FILLED;
                pp++;
+           } else if (streq(p, "linear")) {
+               istyle |= GRADIENT;
+               pp++;
+           }else if (streq(p, "radial")) {
+               istyle |= (RGRADIENT);
+               pp++;
            } else if (streq(p, "rounded")) {
                istyle |= ROUNDED;
                qp = pp;        /* remove rounded from list passed to renderer */
@@ -434,7 +485,10 @@ void round_corners(GVJ_t * job, char *fillc, char *penc, pointf * AF,
                pts[j++] = B[4 * seg + 1];
                pts[j++] = B[4 * seg + 2];
            }
-           gvrender_polygon(job, pts, 2 * sides, TRUE);
+           if (filled & GRADIENT)
+             gvrender_polygon(job, pts, 2 * sides, filled);
+           else
+             gvrender_polygon(job, pts, 2 * sides, TRUE);
            free(pts);
            for (seg = 0; seg < sides; seg++) {
                gvrender_beziercurve(job, B + 4 * seg + 2, 4, FALSE, FALSE,
@@ -1623,10 +1677,15 @@ static void poly_gencode(GVJ_t * job, node_t * n)
        gvrender_set_fillcolor(job, color);
        filled = TRUE;
     } else {
-       if (style & FILLED) {
+       if (style & GRADIENT) {
+           gvrender_set_gradient(job,n,N_gradientcolor,N_gradientangle);
+           filled = FALSE;
+       } 
+       else if (style & FILLED) {
            gvrender_set_fillcolor(job, findFill(n));   /* emit fill color */
            filled = TRUE;
-       } else {
+       } 
+       else {
            filled = FALSE;
        }
        pencolor(job, n);       /* emit pen color */
@@ -1661,14 +1720,26 @@ static void poly_gencode(GVJ_t * job, node_t * n)
        /* lay down fill first */
        if (filled && pfilled) {
            if (sides <= 2) {
-               gvrender_ellipse(job, AF, sides, filled);
+               if (style & GRADIENT)
+                 gvrender_ellipse(job, AF, sides, style);
+               else
+                 gvrender_ellipse(job, AF, sides, filled);
+                 
                if (style & DIAGONALS) {
                    Mcircle_hack(job, n);
                }
            } else if (style & (ROUNDED | DIAGONALS)) {
-               node_round_corners(job, n, AF, sides, style, filled);
+               if (style & GRADIENT) {
+                 gvrender_set_gradient(job,n,N_gradientcolor,N_gradientangle);
+                 node_round_corners(job, n, AF, sides, style, style);
+               }
+               else
+                 node_round_corners(job, n, AF, sides, style, filled);
            } else {
-               gvrender_polygon(job, AF, sides, filled);
+               if (style & GRADIENT)
+                 gvrender_polygon(job, AF, sides, style);
+               else
+                 gvrender_polygon(job, AF, sides, filled);
            }
        }
        gvrender_usershape(job, name, AF, sides, filled,
@@ -1683,14 +1754,25 @@ static void poly_gencode(GVJ_t * job, node_t * n)
            AF[i].y = P.y * ysize + ND_coord(n).y;
        }
        if (sides <= 2) {
-           gvrender_ellipse(job, AF, sides, filled);
+           if (style & GRADIENT)
+               gvrender_ellipse(job, AF, sides, style);
+           else
+               gvrender_ellipse(job, AF, sides, filled);
            if (style & DIAGONALS) {
                Mcircle_hack(job, n);
            }
        } else if (SPECIAL_CORNERS(style)) {
+         if (style & GRADIENT) {
+           gvrender_set_gradient(job,n,N_gradientcolor,N_gradientangle);
+           node_round_corners(job, n, AF, sides, style, style);
+         }
+         else
            node_round_corners(job, n, AF, sides, style, filled);
        } else {
-           gvrender_polygon(job, AF, sides, filled);
+           if (style & GRADIENT)
+             gvrender_polygon(job, AF, sides, style);
+           else
+             gvrender_polygon(job, AF, sides, filled);
        }
        /* fill innermost periphery only */
        filled = FALSE;
index 9448701f5f00e82c755823fd9e0722315786001c..701c669f0b9e1386eb0740d5ea5e9f9188eb1a95 100644 (file)
@@ -1831,6 +1831,87 @@ void setEdgeType (graph_t* g, int dflt)
     GD_flags(g) |= et;
 }
 
+
+/* cairogen_get_gradient_points
+ * Evaluates the extreme points of an ellipse or polygon
+ * Determines the point at the center of the extreme points
+ * Uses the angle parameter to identify two points on a line that defines the gradient direction
+ * 
+ */
+void cairogen_get_gradient_points(pointf * A, pointf * G, int n, float angle)
+{
+    int i;
+    double rx, ry;
+    pointf min,max,center;
+    
+    if ( n == 2) {
+      rx = A[1].x - A[0].x;
+      ry = A[1].y - A[0].y;
+      min.x = A[0].x - rx;
+      max.x = A[0].x + rx;
+      min.y = A[0].y - ry;
+      max.y = A[0].y + ry;
+    }    
+    else {
+      min.x = max.x = A[0].x;
+      min.y = max.y = A[0].y;
+      for (i = 0; i < n; i++){
+       min.x = (A[i].x < min.x ? A[i].x : min.x);
+       min.y = (A[i].y < min.y ? A[i].y : min.y);
+       max.x = (A[i].x > max.x ? A[i].x : max.x);
+       max.y = (A[i].y > max.y ? A[i].y : max.y);
+      }
+    }
+      center.x = min.x + (max.x - min.x)/2;
+      center.y = min.y + (max.y - min.y)/2;
+      G[0].x = center.x - (max.x - center.x) * cos(angle);
+      G[0].y = -center.y + (max.y - center.y) * sin(angle);
+      G[1].x = center.x + (center.x - min.x) * cos(angle);
+      G[1].y = -center.y - (center.y - min.y) * sin(angle);
+}
+
+/* cairogen_get_rgradient_points
+ * Evaluates the extreme points of an ellipse or polygon
+ * Determines the point at the center of the extreme points
+ * Sets the inner radius to half the distance to the min point
+ * 
+ */
+void cairogen_get_rgradient_points(pointf * A, pointf * G, int n)
+{
+    int i;
+    double rx, ry,inner_r,outer_r;
+    pointf min,max,center;
+    
+    if ( n == 2) {
+      rx = A[1].x - A[0].x;
+      ry = A[1].y - A[0].y;
+      min.x = A[0].x - rx;
+      max.x = A[0].x + rx;
+      min.y = A[0].y - ry;
+      max.y = A[0].y + ry;
+    }    
+    else {
+      min.x = max.x = A[0].x;
+      min.y = max.y = A[0].y;
+      for (i = 0; i < n; i++){
+       min.x = (A[i].x < min.x ? A[i].x : min.x);
+       min.y = (A[i].y < min.y ? A[i].y : min.y);
+       max.x = (A[i].x > max.x ? A[i].x : max.x);
+       max.y = (A[i].y > max.y ? A[i].y : max.y);
+      }
+    }
+      center.x = min.x + (max.x - min.x)/2;
+      center.y = min.y + (max.y - min.y)/2;
+      outer_r = sqrt((center.x - min.x)*(center.x - min.x) +
+                     (center.y - min.y)*(center.y - min.y));
+      inner_r = outer_r /4.;
+      G[0].x = center.x;
+      G[0].y = -center.y;
+      G[1].x = inner_r;
+      G[1].y = outer_r;
+      
+}
+
 #ifndef WIN32_STATIC
 #ifndef HAVE_STRCASECMP
 
index b8acce5c2dcd4a79f5aa90d359ec79a46f67d9d0..1944f8538d3d540db3a945e849e128acb576f2b1 100644 (file)
@@ -33,7 +33,7 @@ extern "C" {
     typedef struct gvloadimage_engine_s gvloadimage_engine_t;
 
     typedef enum { PEN_NONE, PEN_DASHED, PEN_DOTTED, PEN_SOLID } pen_type;
-    typedef enum { FILL_NONE, FILL_SOLID } fill_type;
+    typedef enum { FILL_NONE, FILL_SOLID, FILL_LINEAR, FILL_RADIAL } fill_type;
     typedef enum { FONT_REGULAR, FONT_BOLD, FONT_ITALIC } font_type;
     typedef enum { LABEL_PLAIN, LABEL_HTML } label_type;
 
@@ -152,7 +152,13 @@ extern "C" {
        int argc;
        int alloc;
     } gv_argvlist_t;
-
+    
+    typedef struct gv_gradient_s {
+      int angle;
+      gvcolor_t startcolor, stopcolor;
+      int id;
+    } gv_gradient_t;
+    
     typedef struct gvdevice_callbacks_s {
        void (*refresh) (GVJ_t * job);
         void (*button_press) (GVJ_t * job, int button, pointf pointer);
@@ -201,6 +207,7 @@ extern "C" {
        emit_state_t emit_state; 
 
        gvcolor_t pencolor, fillcolor;
+       gv_gradient_t gradient;
        pen_type pen;
        fill_type fill;
        double penwidth;
index 53d6c63c477b9273943f9bd1018cd883223ce0b5..f149c8eb21e006abe5033f574f830561d3c15d29 100644 (file)
     extern void gvrender_set_pencolor(GVJ_t * job, char *name);
     extern void gvrender_set_penwidth(GVJ_t * job, double penwidth);
     extern void gvrender_set_fillcolor(GVJ_t * job, char *name);
+    extern void gvrender_set_gradientcolor(GVJ_t * job, char *gr_color_ptr[2]);
+    extern void gvrender_set_gradientAngle(GVJ_t * job, int angle);
+    extern void gvrender_set_gradientId(GVJ_t * job);
+    extern void gvrender_set_gradient(GVJ_t * job, void *g_obj, attrsym_t * color_attr, attrsym_t * angle_attr);
+    extern char *gvrender_set_gradient_values(GVJ_t* job, char* gradcolor, int angle);
     extern void gvrender_set_style(GVJ_t * job, char **s);
-    extern void gvrender_ellipse(GVJ_t * job, pointf * AF, int n, boolean filled);
-    extern void gvrender_polygon(GVJ_t * job, pointf * AF, int n, boolean filled);
-    extern void gvrender_box(GVJ_t * job, boxf BF, boolean filled);
+    extern void gvrender_ellipse(GVJ_t * job, pointf * AF, int n, int filled);
+    extern void gvrender_polygon(GVJ_t* job, pointf* af, int n, int filled);
+    extern void gvrender_box(GVJ_t * job, boxf BF, int filled);
     extern void gvrender_beziercurve(GVJ_t * job, pointf * AF, int n,
                        int arrow_at_start, int arrow_at_end, boolean filled);
     extern void gvrender_polyline(GVJ_t * job, pointf * AF, int n);
index 4a085cdd6ca84a0e6a41ee51dc7b4aafdd86c5d6..4c5763fbae2d4ac2b92c7284965ebd85ffecde36 100644 (file)
 
 extern int emit_once(char *str);
 extern shape_desc *find_user_shape(char *name);
+extern char *findStopColor(void * n, attrsym_t * attr, char *dflt);
+extern char *findStartColor(void * n, attrsym_t * attr, char *dflt);
+extern int findGradientAngle(void * n,  attrsym_t * attr);
 extern boolean mapbool(char *s);
 
 #ifndef HAVE_STRCASECMP
 extern int strcasecmp(const char *s1, const char *s2);
 #endif
 
+#define GR_SZ 50
+
 /* storage for temporary hacks until client API is FP */
 static pointf *AF;
 static int sizeAF;
@@ -489,6 +494,92 @@ void gvrender_set_fillcolor(GVJ_t * job, char *name)
        *cp = ':';
 }
 
+void gvrender_set_gradientcolor(GVJ_t * job, char *gr_color_ptr[2])
+{
+    gvrender_engine_t *gvre = job->render.engine;
+    gvcolor_t *color;
+    char * start_color, * stop_color;
+    
+    start_color = gr_color_ptr[0];
+    stop_color = gr_color_ptr[1];
+    if (gvre && gr_color_ptr[0] != NULL && gr_color_ptr[1] != NULL) {
+      color = &(job->obj->gradient.startcolor);
+      gvrender_resolve_color(job->render.features, start_color, color);
+      if (gvre->resolve_color)
+       gvre->resolve_color(job, color);
+      color = &(job->obj->gradient.stopcolor);
+      gvrender_resolve_color(job->render.features, stop_color, color);
+      if (gvre->resolve_color)
+       gvre->resolve_color(job, color);
+    }
+}
+
+void gvrender_set_gradientAngle(GVJ_t * job, int angle)
+{
+  obj_state_t *obj = job->obj;
+  obj->gradient.angle = angle;
+      
+}
+static int gradientId;
+void gvrender_set_gradientId(GVJ_t * job){
+
+  obj_state_t *obj = job->obj;
+  obj->gradient.id = gradientId++;
+}
+
+void gvrender_set_gradient(GVJ_t * job, void *g_obj, attrsym_t * color_attr, attrsym_t * angle_attr){
+char *ptr, *gradcolor = NULL,*gradstartcolor;
+int angle;
+
+    
+    if(g_obj != NULL && color_attr != NULL) {
+      gradcolor = N_GNEW((2 * GR_SZ)+1,char);
+      gradstartcolor = N_GNEW(GR_SZ,char);
+      strcpy(gradcolor,findStartColor(g_obj,color_attr,DEFAULT_FILL));
+      if ((ptr = strstr(gradcolor, ":")) != NULL) /* if attribute is a color list use first one */
+       *ptr = '\0';
+      strcpy(gradstartcolor,gradcolor);
+      strcat(gradcolor,":");
+      strcat(gradcolor,findStopColor(g_obj,color_attr,gradstartcolor)); /* use start color as stop color if : missing */
+      angle = findGradientAngle(g_obj,angle_attr);
+      gvrender_set_gradient_values(job,gradcolor,angle);
+      free(gradstartcolor);
+      free(gradcolor);
+    }
+      
+}
+
+static char gradientcolor[2][GR_SZ];
+
+char *gvrender_set_gradient_values(GVJ_t* job, char* gradcolor, int angle){
+    char *gr_color_ptr[2], *ptr;
+
+    gr_color_ptr[0] = gradientcolor[0];
+    gr_color_ptr[1] = gradientcolor[1];
+    gr_color_ptr[0][GR_SZ - 1] = gr_color_ptr[0][0] = 0;
+    gr_color_ptr[1][GR_SZ - 1] = gr_color_ptr[1][0] = 0;
+    if(gradcolor != NULL && gradcolor[0]){
+      ptr= strstr(gradcolor,":");
+      if(ptr != NULL){
+       *ptr = '\0';
+       ++ptr;
+       if(ptr[0])
+         strncpy(gr_color_ptr[1],ptr,GR_SZ - 1);
+       else
+         strncpy(gr_color_ptr[1],gradcolor,GR_SZ - 1);  //use start color as stop color
+      }
+      else
+       strncpy(gr_color_ptr[1],gradcolor,GR_SZ - 1);  //use start color as stop color  
+      strncpy(gr_color_ptr[0],gradcolor,GR_SZ - 1);
+      gvrender_set_gradientcolor(job, gr_color_ptr);
+      gvrender_set_gradientAngle(job,angle);
+      gvrender_set_gradientId(job);
+    }
+    return gr_color_ptr[1];
+
+}
+
+
 void gvrender_set_style(GVJ_t * job, char **s)
 {
     gvrender_engine_t *gvre = job->render.engine;
@@ -515,6 +606,10 @@ void gvrender_set_style(GVJ_t * job, char **s)
                obj->penwidth = atof(p);
            } else if (streq(line, "filled"))
                obj->fill = FILL_SOLID;
+           else if (streq(line, "linear"))
+               obj->fill = FILL_LINEAR;
+           else if (streq(line, "radial"))
+               obj->fill = FILL_RADIAL;
            else if (streq(line, "unfilled"))
                obj->fill = FILL_NONE;
            else if (streq(line, "tapered"))
@@ -528,7 +623,7 @@ void gvrender_set_style(GVJ_t * job, char **s)
     }
 }
 
-void gvrender_ellipse(GVJ_t * job, pointf * pf, int n, boolean filled)
+void gvrender_ellipse(GVJ_t * job, pointf * pf, int n, int filled)
 {
     gvrender_engine_t *gvre = job->render.engine;
 
@@ -549,10 +644,9 @@ void gvrender_ellipse(GVJ_t * job, pointf * pf, int n, boolean filled)
     }
 }
 
-void gvrender_polygon(GVJ_t * job, pointf * af, int n, boolean filled)
+void gvrender_polygon(GVJ_t * job, pointf * af, int n, int filled)
 {
     gvrender_engine_t *gvre = job->render.engine;
-
     if (gvre) {
        if (gvre->polygon && job->obj->pen != PEN_NONE) {
            if (job->flags & GVRENDER_DOES_TRANSFORM)
@@ -569,7 +663,8 @@ void gvrender_polygon(GVJ_t * job, pointf * af, int n, boolean filled)
     }
 }
 
-void gvrender_box(GVJ_t * job, boxf B, boolean filled)
+
+void gvrender_box(GVJ_t * job, boxf B, int filled)
 {
     pointf A[4];
 
index c979543393b972d98878be08bc718a0c1de2c737..512ac04b76e841ac4c57f20a7edc58ea474f1ba9 100644 (file)
@@ -44,6 +44,8 @@ typedef enum { FORMAT_SVG, FORMAT_SVGZ, } format_type;
 
 extern char *xml_string(char *str);
 extern char *xml_url_string(char *str);
+extern void cairogen_get_gradient_points(pointf * A, pointf * G, int n, float angle);
+extern void cairogen_get_rgradient_points(pointf * A, pointf * G, int n);
 
 /* SVG dash array */
 static char *sdasharray = "5,2";
@@ -90,9 +92,18 @@ static void svg_print_color(GVJ_t * job, gvcolor_t color)
 static void svg_grstyle(GVJ_t * job, int filled)
 {
     obj_state_t *obj = job->obj;
+    char sgid[11];
 
     gvputs(job, " fill=\"");
-    if (filled) {
+    if (filled == GRADIENT){
+       sprintf(sgid,"%d",obj->gradient.id);
+       gvprintf(job,"url(#l_%s)",sgid);
+    }
+    else if (filled == RGRADIENT){
+       sprintf(sgid,"%d",obj->gradient.id);
+       gvprintf(job,"url(#r_%s)",sgid);
+    }
+    else if (filled) {
        svg_print_color(job, obj->fillcolor);
        if (obj->fillcolor.type == RGBA_BYTE && obj->fillcolor.u.rgba[3] > 0 && obj->fillcolor.u.rgba[3] < 255 )
            gvprintf(job, "\" fill-opacity=\"%f", ((float)obj->fillcolor.u.rgba[3]/255.0));
@@ -392,9 +403,93 @@ static void svg_textpara(GVJ_t * job, pointf p, textpara_t * para)
     gvputs(job, "</text>\n");
 }
 
+/* svg_gradstyle
+ * Outputs the SVG statements that define the gradient pattern
+ */
+static void svg_gradstyle(GVJ_t * job, pointf * A, int n)
+{
+      pointf G[2];
+      float angle;
+      char sgid[11];
+    
+      obj_state_t *obj = job->obj;
+      angle = obj->gradient.angle * M_PI / 180; //angle of gradient line
+      G[0].x = G[0].y = G[1].x = G[1].y = 0.;
+      cairogen_get_gradient_points(A, G, n, angle); //get points on gradient line
+      sprintf(sgid,"%d",obj->gradient.id);
+
+      gvprintf(job, "<defs>\n<linearGradient id=\"l_%s\" gradientUnits=\"userSpaceOnUse\" ",sgid);
+      gvprintf(job,"x1=\"%g\" y1=\"%g\" x2=\"%g\" y2=\"%g\" >\n", G[0].x,G[0].y,G[1].x,G[1].y);
+      gvputs(job,"<stop offset=\"0\" style=\"stop-color:");
+      svg_print_color(job, obj->gradient.startcolor);
+      gvputs(job,";stop-opacity:");
+      if (obj->gradient.startcolor.type == RGBA_BYTE && obj->gradient.startcolor.u.rgba[3] > 0 && obj->gradient.startcolor.u.rgba[3] < 255 )
+           gvprintf(job, "%f", ((float)obj->gradient.startcolor.u.rgba[3]/255.0));
+      else gvputs(job,"1.");
+      gvputs(job,";\"/>\n");
+      gvputs(job,"<stop offset=\"1\" style=\"stop-color:");
+      svg_print_color(job, obj->gradient.stopcolor);
+      gvputs(job,";stop-opacity:");
+      if (obj->gradient.stopcolor.type == RGBA_BYTE && obj->gradient.stopcolor.u.rgba[3] > 0 && obj->gradient.stopcolor.u.rgba[3] < 255 )
+           gvprintf(job, "%f", ((float)obj->gradient.stopcolor.u.rgba[3]/255.0));
+      else gvputs(job,"1.");
+      gvputs(job,";\"/>\n</linearGradient>\n</defs>\n");
+}
+
+/* svg_gradstyle
+ * Outputs the SVG statements that define the radial gradient pattern
+ */
+static void svg_rgradstyle(GVJ_t * job, pointf * A, int n)
+{
+      pointf G[2];
+      float angle;
+      char fx[5],fy[5],sgid[11];
+      int ifx,ify;
+    
+      obj_state_t *obj = job->obj;
+      angle = obj->gradient.angle * M_PI / 180; //angle of gradient line
+      G[0].x = G[0].y = G[1].x = G[1].y = G[2].x = G[2].y= 0.;
+      cairogen_get_rgradient_points(A, G, n);
+      if(angle == 0.){
+       ifx = ify = 50;
+      }
+      else {
+       ifx = 50*(1 + cos(angle));
+       ify = 50*(1 - sin(angle));
+      }
+      sprintf(sgid,"%d",obj->gradient.id);
+      sprintf(fx,"%d%%",ifx);
+      sprintf(fy,"%d%%",ify);
+      gvprintf(job, "<defs>\n<radialGradient id=\"r_%s\" cx=\"50%\" cy=\"50%\" r=\"75%\" fx=",sgid);
+      gvprintf(job,"\"%s\"",fx);
+      gvputs(job," fy=");
+      gvprintf(job,"\"%s\">\n",fy);
+      gvputs(job,"<stop offset=\"0\" style=\"stop-color:");
+      svg_print_color(job, obj->gradient.startcolor);
+      gvputs(job,";stop-opacity:");
+      if (obj->gradient.startcolor.type == RGBA_BYTE && obj->gradient.startcolor.u.rgba[3] > 0 && obj->gradient.startcolor.u.rgba[3] < 255 )
+           gvprintf(job, "%f", ((float)obj->gradient.startcolor.u.rgba[3]/255.0));
+      else gvputs(job,"1.");
+      gvputs(job,";\"/>\n");
+      gvputs(job,"<stop offset=\"1\" style=\"stop-color:");
+      svg_print_color(job, obj->gradient.stopcolor);
+      gvputs(job,";stop-opacity:");
+      if (obj->gradient.stopcolor.type == RGBA_BYTE && obj->gradient.stopcolor.u.rgba[3] > 0 && obj->gradient.stopcolor.u.rgba[3] < 255 )
+           gvprintf(job, "%f", ((float)obj->gradient.stopcolor.u.rgba[3]/255.0));
+      else gvputs(job,"1.");
+      gvputs(job,";\"/>\n</radialGradient>\n</defs>\n");
+}
+
+
 static void svg_ellipse(GVJ_t * job, pointf * A, int filled)
 {
     /* A[] contains 2 points: the center and corner. */
+    if (filled == GRADIENT) {
+      svg_gradstyle(job,A,2);
+    }
+    else if (filled == (RGRADIENT)){
+      svg_rgradstyle(job,A,2);
+    }
     gvputs(job, "<ellipse");
     svg_grstyle(job, filled);
     gvprintf(job, " cx=\"%g\" cy=\"%g\"", A[0].x, -A[0].y);
@@ -417,7 +512,12 @@ svg_bezier(GVJ_t * job, pointf * A, int n, int arrow_at_start,
 static void svg_polygon(GVJ_t * job, pointf * A, int n, int filled)
 {
     int i;
-
+    if (filled == GRADIENT) {
+      svg_gradstyle(job,A,n);
+    }
+    else if (filled == (RGRADIENT)){
+      svg_rgradstyle(job,A,n);
+    }
     gvputs(job, "<polygon");
     svg_grstyle(job, filled);
     gvputs(job, " points=\"");
index c3630d5711bd73fad19e914acafb8a8b747366bd..281b07293ae6b8e0929a79e44303c14fe9842ebb 100644 (file)
@@ -22,6 +22,7 @@
 #include <string.h>
 #endif
 
+#include "const.h"
 #include "gvplugin_render.h"
 #include "gvplugin_device.h"
 #include "gvio.h"
@@ -30,6 +31,8 @@
 
 #ifdef HAVE_PANGOCAIRO
 #include <pango/pangocairo.h>
+extern void cairogen_get_gradient_points(pointf * A, pointf * G, int n, float angle);
+extern void cairogen_get_rgradient_points(pointf * A, pointf * G, int n);
 
 typedef enum {
                FORMAT_CAIRO,
@@ -65,6 +68,13 @@ static void cairogen_set_color(cairo_t * cr, gvcolor_t * color)
                         color->u.RGBA[2], color->u.RGBA[3]);
 }
 
+static void cairogen_add_color_stop_rgba(cairo_pattern_t *pat,int stop , gvcolor_t * color) 
+{
+  cairo_pattern_add_color_stop_rgba (pat, stop,color->u.RGBA[0], color->u.RGBA[1],
+                        color->u.RGBA[2], color->u.RGBA[3]);
+}
+
+
 static cairo_status_t
 writer (void *closure, const unsigned char *data, unsigned int length)
 {
@@ -259,6 +269,9 @@ static void cairogen_ellipse(GVJ_t * job, pointf * A, int filled)
     cairo_t *cr = (cairo_t *) job->context;
     cairo_matrix_t matrix;
     double rx, ry;
+    float angle,r1,r2;
+    pointf G[2],c1,c2;
+    cairo_pattern_t *pat;
 
     cairogen_set_penstyle(job, cr);
 
@@ -278,7 +291,39 @@ if (ry < RMIN) ry = RMIN;
 
     cairo_set_matrix(cr, &matrix);
 
-    if (filled) {
+    if (filled == GRADIENT || filled == (RGRADIENT)) {
+      angle = obj->gradient.angle * M_PI / 180;
+      if(filled == GRADIENT) {
+         angle = obj->gradient.angle * M_PI / 180;
+         cairogen_get_gradient_points(A, G, 2, angle);
+         pat = cairo_pattern_create_linear (G[0].x,G[0].y,G[1].x,G[1].y);
+      }
+      else {
+         cairogen_get_rgradient_points(A, G, 2);
+         //r1 is inner radius, r2 is outter radius
+       r1 = G[1].x;
+       r2 = G[1].y;
+         if (angle == 0) {
+           c1.x = G[0].x;
+           c1.y = G[0].y;
+         }
+         else {
+           c1.x = G[0].x +  (r2/4) * cos(angle);
+           c1.y = G[0].y -  (r2/4) * sin(angle);
+         }
+       c2.x = G[0].x;
+       c2.y = G[0].y;
+       r1 = r2/4;
+       //r1 is inner radius, r2 is outter radius
+         pat = cairo_pattern_create_radial(c1.x,c1.y,r1,c2.x,c2.y,r2); 
+       }
+       cairogen_add_color_stop_rgba(pat,0,&(obj->gradient.startcolor));
+       cairogen_add_color_stop_rgba(pat,1,&(obj->gradient.stopcolor));
+       cairo_set_source (cr, pat);
+       cairo_fill_preserve (cr);
+       cairo_pattern_destroy (pat);
+    }
+    else if (filled) {
        cairogen_set_color(cr, &(obj->fillcolor));
        cairo_fill_preserve(cr);
     }
@@ -292,16 +337,49 @@ cairogen_polygon(GVJ_t * job, pointf * A, int n, int filled)
     obj_state_t *obj = job->obj;
     cairo_t *cr = (cairo_t *) job->context;
     int i;
+    float angle,r1,r2;
+    cairo_pattern_t *pat;
+    pointf G[2],c1,c2;
 
     cairogen_set_penstyle(job, cr);
 
     cairo_move_to(cr, A[0].x, -A[0].y);
     for (i = 1; i < n; i++)
-       cairo_line_to(cr, A[i].x, -A[i].y);
+    cairo_line_to(cr, A[i].x, -A[i].y);
     cairo_close_path(cr);
-    if (filled) {
-       cairogen_set_color(cr, &(obj->fillcolor));
-       cairo_fill_preserve(cr);
+    if (filled == GRADIENT || filled == (RGRADIENT)) {
+      angle = obj->gradient.angle * M_PI / 180;
+      if(filled == GRADIENT) {
+       cairogen_get_gradient_points(A, G, n, angle);
+       pat = cairo_pattern_create_linear (G[0].x,G[0].y,G[1].x,G[1].y);
+      }
+      else {
+       cairogen_get_rgradient_points(A, G, n);
+       r1 = G[1].x;
+       r2 = G[1].y;
+         if (angle == 0) {
+           c1.x = G[0].x;
+           c1.y = G[0].y;
+         }
+         else {
+           c1.x = G[0].x +  (r2/4) * cos(angle);
+           c1.y = G[0].y -  (r2/4) * sin(angle);
+         }
+       c2.x = G[0].x;
+       c2.y = G[0].y;
+       r1 = r2/4;
+       //r1 is inner radius, r2 is outter radius
+       pat = cairo_pattern_create_radial(c1.x,c1.y,r1,c2.x,c2.y,r2); 
+      }
+      cairogen_add_color_stop_rgba(pat,0,&(obj->gradient.startcolor));
+      cairogen_add_color_stop_rgba(pat,1,&(obj->gradient.stopcolor));
+      cairo_set_source (cr, pat);
+      cairo_fill_preserve (cr);
+      cairo_pattern_destroy (pat);
+    }
+    else if (filled) {
+      cairogen_set_color(cr, &(obj->fillcolor));
+      cairo_fill_preserve(cr);
     }
     cairogen_set_color(cr, &(obj->pencolor));
     cairo_stroke(cr);