]> granicus.if.org Git - graphviz/commitdiff
Extend linear gradient fill to support two-tone fills.
authorEmden R. Gansner <erg@research.att.com>
Fri, 28 Jun 2013 21:31:22 +0000 (17:31 -0400)
committerEmden R. Gansner <erg@research.att.com>
Fri, 28 Jun 2013 21:31:22 +0000 (17:31 -0400)
lib/common/emit.c
lib/common/htmltable.c
lib/common/shapes.c
lib/common/utils.c
lib/common/utils.h
lib/gvc/gvcjob.h
lib/gvc/gvcproc.h
lib/gvc/gvrender.c
plugin/core/gvrender_core_svg.c
plugin/pango/gvrender_pango.c

index ca92d0b403d1534a1b0620f4545ff27ad1ce0346..7fad8de25589f61da1215b6ce086c5c090cd3add 100644 (file)
@@ -340,6 +340,7 @@ static char **checkClusterStyle(graph_t* sg, int *flagp)
 typedef struct {
     char* color;   /* segment color */
     float t;       /* segment size >= 0 */
+    boolean hasFraction;  /* true if color explicitly specifies its fraction */
 } colorseg_t;
 /* Sum of segment sizes should add to 1 */
 typedef struct {
@@ -433,7 +434,8 @@ parseSegs (char* clrs, int nseg, colorsegs_t** psegs)
                v = left;
            }
            left -= v;
-           s[cnum].color = color;
+           if (v > 0) s[cnum].hasFraction = TRUE;
+           if (*color) s[cnum].color = color;
            s[cnum++].t = v;
        }
        else {
@@ -1521,16 +1523,17 @@ static void emit_background(GVJ_t * job, graph_t *g)
     if (!(   ((job->flags & GVDEVICE_DOES_TRUECOLOR) && streq(str, "transparent"))
           || ((job->flags & GVRENDER_NO_WHITE_BG) && dfltColor))) {
        char* clrs[2];
+       float frac;
 
-       if ((findStopColor (str, clrs))) {
+       if ((findStopColor (str, clrs, &frac))) {
            int filled, istyle = 0;
             gvrender_set_fillcolor(job, clrs[0]);
             gvrender_set_pencolor(job, "transparent");
            checkClusterStyle(g, &istyle);
            if (clrs[1]) 
-               gvrender_set_gradient_vals(job,clrs[1],late_int(g,G_gradientangle,0,0));
+               gvrender_set_gradient_vals(job,clrs[1],late_int(g,G_gradientangle,0,0), frac);
            else 
-               gvrender_set_gradient_vals(job,DEFAULT_COLOR,late_int(g,G_gradientangle,0,0));
+               gvrender_set_gradient_vals(job,DEFAULT_COLOR,late_int(g,G_gradientangle,0,0), frac);
            if (istyle & RADIAL)
                filled = RGRADIENT;
            else
@@ -3634,12 +3637,13 @@ void emit_clusters(GVJ_t * job, Agraph_t * g, int flags)
        if (!fillcolor) fillcolor = DEFAULT_FILL;
        clrs[0] = NULL;
        if (filled) {
-           if (findStopColor (fillcolor, clrs)) {
+           float frac;
+           if (findStopColor (fillcolor, clrs, &frac)) {
                gvrender_set_fillcolor(job, clrs[0]);
                if (clrs[1]) 
-                   gvrender_set_gradient_vals(job,clrs[1],late_int(sg,G_gradientangle,0,0));
+                   gvrender_set_gradient_vals(job,clrs[1],late_int(sg,G_gradientangle,0,0), frac);
                else 
-                   gvrender_set_gradient_vals(job,DEFAULT_COLOR,late_int(sg,G_gradientangle,0,0));
+                   gvrender_set_gradient_vals(job,DEFAULT_COLOR,late_int(sg,G_gradientangle,0,0), frac);
                if (istyle & RADIAL)
                    filled = RGRADIENT;
                else
@@ -4103,3 +4107,50 @@ int gvRenderJobs (GVC_t * gvc, graph_t * g)
     FINISH();
     return 0;
 }
+
+/* findStopColor:
+ * Check for colon in colorlist. If one exists, and not the first
+ * character, store the characters before the colon in clrs[0] and
+ * the characters after the colon (and before the next or end-of-string)
+ * in clrs[1]. If there are no characters after the first colon, clrs[1]
+ * is NULL. Return TRUE.
+ * If there is no non-trivial string before a first colon, set clrs[0] to
+ * NULL and return FALSE.
+ *
+ * Note that memory is allocated as a single block stored in clrs[0] and
+ * must be freed by calling function.
+ */
+boolean findStopColor (char* colorlist, char* clrs[2], float* frac)
+{
+    colorsegs_t* segs;
+    int rv;
+
+    rv = parseSegs (colorlist, 0, &segs);
+    if (rv || (segs->numc < 2) || (segs->segs[0].color == NULL)) {
+       clrs[0] = NULL;
+       return FALSE;
+    }
+
+    if (segs->numc > 2)
+       agerr (AGWARN, "More than 2 colors specified for a gradient - ignoring remaining\n");
+
+    clrs[0] = N_GNEW (strlen(colorlist)+1,char); 
+    strcpy (clrs[0], segs->segs[0].color);
+    if (segs->segs[1].color) {
+       clrs[1] = clrs[0] + (strlen(clrs[0])+1);
+       strcpy (clrs[1], segs->segs[1].color);
+    }
+    else
+       clrs[1] = NULL;
+
+    if (segs->segs[0].hasFraction)
+       *frac = segs->segs[0].t;
+    else if (segs->segs[1].hasFraction)
+       *frac = 1 - segs->segs[1].t;
+    else 
+       *frac = 0;
+
+    freeSegs (segs);
+    return TRUE;
+}
+
index 49dc2cac37b7799f4afd6258d71f13ed9f97b6bb..54eedc7c42ee87d0d048adb8d604164b3cfef604 100644 (file)
@@ -286,12 +286,13 @@ static int
 setFill(GVJ_t * job, char *color, int angle, int style, char *clrs[2])
 {
     int filled;
-    if (findStopColor(color, clrs)) {
+    float frac;
+    if (findStopColor(color, clrs, &frac)) {
        gvrender_set_fillcolor(job, clrs[0]);
        if (clrs[1])
-           gvrender_set_gradient_vals(job, clrs[1], angle);
+           gvrender_set_gradient_vals(job, clrs[1], angle, frac);
        else
-           gvrender_set_gradient_vals(job, DEFAULT_COLOR, angle);
+           gvrender_set_gradient_vals(job, DEFAULT_COLOR, angle, frac);
        if (style & RADIAL)
            filled = RGRADIENT;
        else
index 7f27b25347c5987a3fd5c83c90de254e74296d30..c910ac145be19656ba3a8d2dcc4559481471954f 100644 (file)
@@ -2738,13 +2738,14 @@ static void poly_gencode(GVJ_t * job, node_t * n)
        filled = FILL;
     } else {
        if (style & FILLED) {
+           float frac;
            fillcolor = findFill (n);
-           if (findStopColor (fillcolor, clrs)) {
+           if (findStopColor (fillcolor, clrs, &frac)) {
                gvrender_set_fillcolor(job, clrs[0]);
                if (clrs[1]) 
-                   gvrender_set_gradient_vals(job,clrs[1],late_int(n,N_gradientangle,0,0));
+                   gvrender_set_gradient_vals(job,clrs[1],late_int(n,N_gradientangle,0,0), frac);
                else 
-                   gvrender_set_gradient_vals(job,DEFAULT_COLOR,late_int(n,N_gradientangle,0,0));
+                   gvrender_set_gradient_vals(job,DEFAULT_COLOR,late_int(n,N_gradientangle,0,0), frac);
                if (style & RADIAL)
                    filled = RGRADIENT;
                else
@@ -3616,16 +3617,19 @@ static void record_gencode(GVJ_t * job, node_t * n)
     pencolor(job, n);
     if (style & FILLED) {
        char* fillcolor = findFill (n);
-       if (findStopColor (fillcolor, clrs)) {
+       float frac;
+       
+       if (findStopColor (fillcolor, clrs, &frac)) {
             gvrender_set_fillcolor(job, clrs[0]);
            if (clrs[1]) 
-               gvrender_set_gradient_vals(job,clrs[1],late_int(n,N_gradientangle,0,0));
+               gvrender_set_gradient_vals(job,clrs[1],late_int(n,N_gradientangle,0,0), frac);
            else 
-               gvrender_set_gradient_vals(job,DEFAULT_COLOR,late_int(n,N_gradientangle,0,0));
+               gvrender_set_gradient_vals(job,DEFAULT_COLOR,late_int(n,N_gradientangle,0,0), frac);
            if (style & RADIAL)
                filled = RGRADIENT;
-            else
+           else
                filled = GRADIENT;
+           free (clrs[0]);
        }
        else {
            filled = FILL;
index 66a46adb421f462665044e36402288fcb184c674..126cd4ca9313886da19fec1a3d790ba639f068b3 100644 (file)
@@ -205,50 +205,6 @@ pointf coord(node_t * n)
     return r;
 }
 
-/* findStopColor:
- * Check for colon in colorlist. If one exists, and not the first
- * character, store the characters before the colon in clrs[0] and
- * the characters after the colon (and before the next or end-of-string)
- * in clrs[1]. If there are no characters after the first colon, clrs[1]
- * is NULL. Return TRUE.
- * If there is no non-trivial string before a first colon, set clrs[0] to
- * NULL and return FALSE.
- *
- * Note that memory is allocated as a single block stored in clrs[0] and
- * must be freed by calling function.
- */
-boolean findStopColor (char* colorlist, char* clrs[2])
-{
-    char* p;
-    char* s;
-    int len;
-
-    if ((*colorlist == ':') || !(p = strchr(colorlist,':'))) {
-       clrs[0] = NULL;
-       return FALSE;
-    }
-
-    clrs[0] = N_GNEW (strlen(colorlist)+1,char); 
-    len = p-colorlist;
-    memcpy (clrs[0],colorlist,len);
-    clrs[0][len]= '\0';
-
-    p++;
-    if ((*p == '\0') || (*p == ':'))
-       clrs[1] = NULL;
-    else {
-       clrs[1] = clrs[0] + (len+1);
-       if ((s = strchr(p,':'))) {
-           *s = '\0';
-           strcpy (clrs[1],p); 
-           *s = ':';
-       }
-       else
-           strcpy (clrs[1], p);
-    }
-    return TRUE;
-}
-
 /* from Glassner's Graphics Gems */
 #define W_DEGREE 5
 
index 5440125076ae18fd5494bb1979afe10628ddbf8a..609787e47dac9b539f4b19d7226b35dddedbaaa6 100644 (file)
@@ -84,7 +84,7 @@ extern "C" {
     extern boolean mapbool(char *);
     extern int maptoken(char *, char **, int *);
 
-    extern boolean findStopColor (char* colorlist, char* clrs[2]);
+    extern boolean findStopColor (char* colorlist, char* clrs[2], float* frac);
     extern int test_toggle(void);
 
     extern void common_init_node(node_t * n);
index 954a514221df758823002dd67232af8b6fadaa28..cc317c9553ad574d3cefbcc044ed17c7522bbc79 100644 (file)
@@ -202,6 +202,7 @@ extern "C" {
 
        gvcolor_t pencolor, fillcolor, stopcolor;
        int gradient_angle;
+       float gradient_frac;
        pen_type pen;
        fill_type fill;
        double penwidth;
index bbf661bc86edb9c7e6f4c46b5be5f52fb4f522ea..5718e5c4bd69f3f7f16899b2109e3f4208406ad6 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_gradient_vals (GVJ_t * job, char *stopcolor, int angle);
+    extern void gvrender_set_gradient_vals (GVJ_t * job, char *stopcolor, int angle, float frac);
 
     extern void gvrender_set_style(GVJ_t * job, char **s);
     extern void gvrender_ellipse(GVJ_t * job, pointf * AF, int n, int filled);
index 079eeb052efc820b25289c8ce405909e21bfe95b..1424a82fc32be9a802ffb81425b3c88712013256 100644 (file)
@@ -494,7 +494,7 @@ void gvrender_set_fillcolor(GVJ_t * job, char *name)
        *cp = ':';
 }
 
-void gvrender_set_gradient_vals (GVJ_t * job, char *stopcolor, int angle)
+void gvrender_set_gradient_vals (GVJ_t * job, char *stopcolor, int angle, float frac)
 {
     gvrender_engine_t *gvre = job->render.engine;
     gvcolor_t *color = &(job->obj->stopcolor);
@@ -505,6 +505,7 @@ void gvrender_set_gradient_vals (GVJ_t * job, char *stopcolor, int angle)
            gvre->resolve_color(job, color);
     }
     job->obj->gradient_angle = angle;
+    job->obj->gradient_frac = frac;
 }
 
 void gvrender_set_style(GVJ_t * job, char **s)
index 89dc89dfc9f2b130f4db83c0f64929b410d99707..69791ceaf1af4b8d6ca9c5d748bcf304b8e60d1a 100644 (file)
@@ -448,7 +448,10 @@ static int svg_gradstyle(GVJ_t * job, pointf * A, int n)
             "<defs>\n<linearGradient id=\"l_%d\" gradientUnits=\"userSpaceOnUse\" ", id);
     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:");
+    if (obj->gradient_frac > 0)
+       gvprintf(job, "<stop offset=\"%.03f\" style=\"stop-color:", obj->gradient_frac - 0.001);
+    else
+       gvputs(job, "<stop offset=\"0\" style=\"stop-color:");
     svg_print_color(job, obj->fillcolor);
     gvputs(job, ";stop-opacity:");
     if (obj->fillcolor.type == RGBA_BYTE && obj->fillcolor.u.rgba[3] > 0
@@ -457,7 +460,10 @@ static int svg_gradstyle(GVJ_t * job, pointf * A, int n)
     else
        gvputs(job, "1.");
     gvputs(job, ";\"/>\n");
-    gvputs(job, "<stop offset=\"1\" style=\"stop-color:");
+    if (obj->gradient_frac > 0)
+       gvprintf(job, "<stop offset=\"%.03f\" style=\"stop-color:", obj->gradient_frac);
+    else
+       gvputs(job, "<stop offset=\"1\" style=\"stop-color:");
     svg_print_color(job, obj->stopcolor);
     gvputs(job, ";stop-opacity:");
     if (obj->stopcolor.type == RGBA_BYTE && obj->stopcolor.u.rgba[3] > 0
index 39c6aeda64b66a52335a6b159f06839c7a843519..e40c364f67803a7f8ec41af09fc13eecb58fe579 100644 (file)
@@ -68,7 +68,7 @@ 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) 
+static void cairogen_add_color_stop_rgba(cairo_pattern_t *pat, double 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]);
@@ -293,8 +293,14 @@ static void cairo_gradient_fill (cairo_t* cr, obj_state_t* obj, int filled, poin
        //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->fillcolor));
-    cairogen_add_color_stop_rgba(pat,1,&(obj->stopcolor));
+    if (obj->gradient_frac > 0) {
+       cairogen_add_color_stop_rgba(pat,obj->gradient_frac - 0.001,&(obj->fillcolor));
+       cairogen_add_color_stop_rgba(pat,obj->gradient_frac,&(obj->stopcolor));
+    }
+    else {
+       cairogen_add_color_stop_rgba(pat,0,&(obj->fillcolor));
+       cairogen_add_color_stop_rgba(pat,1,&(obj->stopcolor));
+    }
     cairo_set_source (cr, pat);
     cairo_fill_preserve (cr);
     cairo_pattern_destroy (pat);