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 {
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 {
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
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
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;
+}
+
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
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
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;
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
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);
gvcolor_t pencolor, fillcolor, stopcolor;
int gradient_angle;
+ float gradient_frac;
pen_type pen;
fill_type fill;
double penwidth;
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);
*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);
gvre->resolve_color(job, color);
}
job->obj->gradient_angle = angle;
+ job->obj->gradient_frac = frac;
}
void gvrender_set_style(GVJ_t * job, char **s)
"<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
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
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]);
//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);