aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--generic/Color.c814
1 files changed, 603 insertions, 211 deletions
diff --git a/generic/Color.c b/generic/Color.c
index c83631d..ed2d17f 100644
--- a/generic/Color.c
+++ b/generic/Color.c
@@ -43,6 +43,7 @@
#include "Image.h"
#include "Color.h"
#include "Geo.h"
+#include "Transfo.h"
/*
@@ -91,7 +92,8 @@ ColorInit()
/*
*----------------------------------------------------------------------
*
- * ZnGetGradientColor --
+ * ZnGetGradientColor
+ * ZnInterpGradientColor --
*
*----------------------------------------------------------------------
*/
@@ -100,28 +102,28 @@ ZnGetGradientColor(ZnGradient *grad,
ZnReal position,
unsigned short *alpha)
{
- int index, min, max;
- XColor *shade=NULL;
+ int index, min, max;
+ XColor *shade=NULL;
- if ((grad->num_colors == 1) || (position <= 0.0)) {
+ if ((grad->num_actual_colors == 1) || (position <= 0.0)) {
if (alpha) {
- *alpha = grad->colors[0].alpha;
+ *alpha = grad->actual_colors[0].alpha;
}
- return grad->colors[0].rgb;
+ return grad->actual_colors[0].rgb;
}
if (position >= 100.0) {
if (alpha) {
- *alpha = grad->colors[grad->num_colors-1].alpha;
+ *alpha = grad->actual_colors[grad->num_actual_colors-1].alpha;
}
- shade = grad->colors[grad->num_colors-1].rgb;
+ shade = grad->actual_colors[grad->num_actual_colors-1].rgb;
}
else {
min = 0;
- max = grad->num_colors-1;
+ max = grad->num_actual_colors-1;
index = (max + min) / 2;
while (max - min != 1) {
/*printf("color index %d, min: %d, max: %d\n", index, min, max);*/
- if (grad->colors[index].position < position) {
+ if (grad->actual_colors[index].position < position) {
min = index;
}
else {
@@ -129,15 +131,76 @@ ZnGetGradientColor(ZnGradient *grad,
}
index = (max + min) / 2;
}
- shade = grad->colors[index].rgb;
+ shade = grad->actual_colors[index].rgb;
if (alpha) {
- *alpha = grad->colors[index].alpha;
+ *alpha = grad->actual_colors[index].alpha;
}
}
return shade;
}
+void
+ZnInterpGradientColor(ZnGradient *grad,
+ ZnReal position,
+ XColor *color,
+ unsigned short *alpha)
+{
+ int index, min, max;
+ ZnGradientColor *gc1, *gc2;
+ ZnReal rel_pos;
+
+ if ((grad->num_actual_colors == 1) || (position <= 0.0)) {
+ *alpha = grad->actual_colors[0].alpha;
+ *color = *grad->actual_colors[0].rgb;
+ }
+ else if (position >= 100.0) {
+ *alpha = grad->actual_colors[grad->num_actual_colors-1].alpha;
+ *color = *grad->actual_colors[grad->num_actual_colors-1].rgb;
+ }
+ else {
+ min = 0;
+ max = grad->num_actual_colors-1;
+ index = (max + min) / 2;
+ while (max - min != 1) {
+ /*printf("color index %d, min: %d, max: %d\n", index, min, max);*/
+ if (grad->actual_colors[index].position < position) {
+ min = index;
+ }
+ else {
+ max = index;
+ }
+ index = (max + min) / 2;
+ }
+ gc1 = &grad->actual_colors[index];
+ gc2 = &grad->actual_colors[index+1];
+ rel_pos = (position - gc1->position) * 100.0 / (gc2->position - gc1->position);
+
+ if (rel_pos > gc1->control) {
+ rel_pos = (rel_pos - gc1->control) * 100.0 / (100.0 - gc1->control);
+ color->red = gc1->mid_rgb->red +
+ (gc2->rgb->red - gc1->mid_rgb->red) * rel_pos / 100.0;
+ color->green = gc1->mid_rgb->green +
+ (gc2->rgb->green - gc1->mid_rgb->green) * rel_pos / 100.0;
+ color->blue = gc1->mid_rgb->blue +
+ (gc2->rgb->blue - gc1->mid_rgb->blue) * rel_pos / 100.0;
+ *alpha = gc1->mid_alpha +
+ (gc2->alpha - gc1->mid_alpha) * rel_pos / 100.0;
+ }
+ else {
+ rel_pos = rel_pos * 100.0 / gc1->control;
+ color->red = gc1->rgb->red +
+ (gc1->mid_rgb->red - gc1->rgb->red) * rel_pos / 100.0;
+ color->green = gc1->rgb->green +
+ (gc1->mid_rgb->green - gc1->rgb->green) * rel_pos / 100.0;
+ color->blue = gc1->rgb->blue +
+ (gc1->mid_rgb->blue - gc1->rgb->blue) * rel_pos / 100.0;
+ *alpha = gc1->alpha +
+ (gc1->mid_alpha - gc1->alpha) * rel_pos / 100.0;
+ }
+ }
+}
+
/*
*--------------------------------------------------------------
@@ -152,7 +215,7 @@ ZnGetGradientColor(ZnGradient *grad,
ZnBool
ZnGradientFlat(ZnGradient *grad)
{
- return (grad->num_colors == 1);
+ return (grad->num_actual_colors == 1);
}
@@ -305,12 +368,6 @@ ZnNameGradient(Tcl_Interp *interp,
ZnGradient *grad;
XColor color;
- grad = ZnGetGradient(interp, tkwin, grad_descr);
- if (!grad) {
- Tcl_AppendResult(interp, "gradient specification \"", grad_descr,
- "\", is invalid", NULL);
- return False;
- }
/*
* First try to find if the name interfere with a color name,
* this must be avoided. Gradients may be described by a single
@@ -322,8 +379,15 @@ ZnNameGradient(Tcl_Interp *interp,
"\", is a color name", NULL);
return False;
}
+ grad = ZnGetGradient(interp, tkwin, grad_descr);
+ if (!grad) {
+ Tcl_AppendResult(interp, "gradient specification \"", grad_descr,
+ "\", is invalid", NULL);
+ return False;
+ }
hash = Tcl_CreateHashEntry(&gradient_table, Tk_GetUid(name), &new);
if (!new) {
+ ZnFreeGradient(grad);
Tcl_AppendResult(interp, "gradient name \"", name,
"\", is already in use", NULL);
return False;
@@ -360,6 +424,290 @@ ZnDeleteGradientName(char *name)
}
}
+static void
+InterpolateGradientColor(Tk_Window tkwin,
+ ZnGradientColor *gc1, /* First color */
+ ZnGradientColor *gc2, /* Next color */
+ ZnGradientColor *gc_interp,/* New interpolated color */
+ ZnGradientColor *gc_adjust,/* Adjusted first color.
+ * Needed if interested in
+ * the range color1 interp
+ * color. */
+ int interp_pos,
+ int min_pos,
+ int span)
+{
+ int pos1, pos2, interp_rel_pos, tmp;
+ XColor rgb;
+
+ pos1 = (gc1->position-min_pos)/span;
+ pos2 = (gc2->position-min_pos)/span;
+ interp_rel_pos = (interp_pos-pos1)*100/(pos2-pos1);
+ if (interp_rel_pos < gc1->control) {
+ tmp = interp_rel_pos*gc1->control;
+ rgb.red = gc1->rgb->red + (gc1->mid_rgb->red - gc1->rgb->red)*tmp/10000;
+ rgb.green = gc1->rgb->green + (gc1->mid_rgb->green - gc1->rgb->green)*tmp/10000;
+ rgb.blue = gc1->rgb->blue + (gc1->mid_rgb->blue - gc1->rgb->blue)*tmp/10000;
+ }
+ else if (interp_rel_pos > gc1->control) {
+ tmp = (interp_rel_pos-gc1->control)*gc1->control;
+ rgb.red = gc1->rgb->red + (gc1->mid_rgb->red - gc1->rgb->red)*tmp/10000;
+ rgb.green = gc1->rgb->green + (gc1->mid_rgb->green - gc1->rgb->green)*tmp/10000;
+ rgb.blue = gc1->rgb->blue + (gc1->mid_rgb->blue - gc1->rgb->blue)*tmp/10000;
+ }
+ else {
+ rgb = *gc1->mid_rgb;
+ gc_interp->alpha = gc1->mid_alpha;
+ }
+ rgb.red = gc1->rgb->red+(gc2->rgb->red-gc1->rgb->red)*interp_rel_pos/100;
+ rgb.green = gc1->rgb->green+(gc2->rgb->green-gc1->rgb->green)*interp_rel_pos/100;
+ rgb.blue = gc1->rgb->blue+(gc2->rgb->blue-gc1->rgb->blue)*interp_rel_pos/100;
+ gc_interp->rgb = Tk_GetColorByValue(tkwin, &rgb);
+ gc_interp->alpha = gc1->alpha+(gc2->alpha-gc1->alpha)*interp_rel_pos/100;
+ if (!gc_adjust) {
+ /*
+ * Interested in the segment from the interpolated color
+ * to color 2.
+ */
+ gc_interp->position = 0;
+ if (interp_rel_pos < gc1->control) {
+ gc_interp->control = gc1->control-interp_rel_pos;
+ gc_interp->mid_rgb = Tk_GetColorByValue(tkwin, gc1->mid_rgb);
+ gc_interp->mid_alpha = gc1->mid_alpha;
+ }
+ else {
+ rgb.red = gc_interp->rgb->red+(gc2->rgb->red-gc_interp->rgb->red)/2;
+ rgb.green = gc_interp->rgb->green+(gc2->rgb->green-gc_interp->rgb->green)/2;
+ rgb.blue = gc_interp->rgb->blue+(gc2->rgb->blue-gc_interp->rgb->blue)/2;
+ gc_interp->mid_rgb = Tk_GetColorByValue(tkwin, &rgb);
+ gc_interp->mid_alpha = gc_interp->mid_alpha +
+ (gc2->mid_alpha - gc_interp->mid_alpha)/2;
+ gc_interp->control = 50;
+ }
+ }
+ else {
+ /*
+ * Interested in the segment form color 1 (color adjusted) to
+ * interpolated color.
+ */
+ gc_interp->position = 100;
+ gc_interp->mid_rgb = NULL;
+ if (interp_rel_pos > gc1->control) {
+ gc_adjust->control = gc1->control+interp_rel_pos;
+ }
+ else {
+ rgb.red = gc1->rgb->red+(gc_interp->rgb->red-gc1->rgb->red)/2;
+ rgb.green = gc1->rgb->green+(gc_interp->rgb->green-gc1->rgb->green)/2;
+ rgb.blue = gc1->rgb->blue+(gc_interp->rgb->blue-gc1->rgb->blue)/2;
+ Tk_FreeColor(gc_adjust->mid_rgb);
+ gc_adjust->mid_rgb = Tk_GetColorByValue(tkwin, &rgb);
+ gc_adjust->mid_alpha = gc1->mid_alpha +
+ (gc_interp->mid_alpha - gc1->mid_alpha)/2;
+ gc_adjust->control = 50;
+ }
+ }
+}
+
+
+static void
+ReduceGradient(Tk_Window tkwin,
+ ZnGradient *grad)
+{
+ ZnReal dx, dy, len, angle;
+ ZnTransfo t;
+ ZnPoint pbbox[4], pgrad[4];
+ ZnReal maxx, minx, span, start_in_new, end_in_new;
+ int minx100, maxx100, span100;
+ int i, j, first_color, last_color;
+ ZnBool interpolate_first, interpolate_last;
+
+ dx = grad->e.x - grad->p.x;
+ dy = grad->e.y - grad->p.y;
+ len = sqrt(dx*dx+dy*dy);
+ angle = acos(dx/len);
+ if (dy < 0) {
+ angle = 2*M_PI - angle;
+ }
+ grad->angle = (int) -ZnRadDeg(angle);
+
+ if (grad->type == ZN_CONICAL_GRADIENT) {
+ unchanged:
+ grad->actual_colors = grad->colors_in;
+ grad->num_actual_colors = grad->num_colors_in;
+ return;
+ }
+
+ ZnTransfoSetIdentity(&t);
+ ZnTranslate(&t, -grad->p.x, -grad->p.y);
+ ZnRotateRad(&t, -angle);
+ ZnScale(&t, 1/len, 1/len);
+ pbbox[0].x = -50;
+ pbbox[0].y = 50;
+ pbbox[1].x = 50;
+ pbbox[1].y = 50;
+ pbbox[2].x = 50;
+ pbbox[2].y = -50;
+ pbbox[3].x = -50;
+ pbbox[3].y = -50;
+ ZnTransformPoints(&t, pbbox, pgrad, 4);
+ maxx = minx = pgrad[0].x;
+ for (i = 1; i < 4; i++) {
+ if (pgrad[i].x > maxx) {
+ maxx = pgrad[i].x;
+ }
+ if (pgrad[i].x < minx) {
+ minx = pgrad[i].x;
+ }
+ }
+
+ span = maxx-minx;
+ if (grad->type == ZN_RADIAL_GRADIENT) {
+ start_in_new = 0;
+ end_in_new = 100/span;
+ }
+ else {
+ start_in_new = -minx*100/span;
+ end_in_new = (1-minx)*100/span;
+ }
+
+ /*printf("minx: %g, maxx: %g, start%%: %g, end%%: %g\n",
+ minx, maxx, start_in_new, end_in_new);*/
+
+ /*
+ * Gradient is unchanged
+ */
+ if ((ABS(start_in_new) < PRECISION_LIMIT) &&
+ (ABS(end_in_new-100.0) < PRECISION_LIMIT)) {
+ goto unchanged;
+ }
+ if ((start_in_new > 100.0) || (end_in_new < 0.0)) {
+ grad->num_actual_colors = 1;
+ grad->actual_colors = ZnMalloc(sizeof(ZnGradientColor));
+ if (end_in_new < 0.0) {
+ grad->actual_colors[0].alpha = grad->colors_in[0].alpha;
+ grad->actual_colors[0].rgb = Tk_GetColorByValue(tkwin,
+ grad->colors_in[0].rgb);
+ }
+ else {
+ grad->actual_colors[0].alpha = grad->colors_in[grad->num_colors_in].alpha;
+ grad->actual_colors[0].rgb = Tk_GetColorByValue(tkwin,
+ grad->colors_in[grad->num_colors_in].rgb);
+ }
+ }
+
+ grad->num_actual_colors = grad->num_colors_in;
+ interpolate_first = False;
+ minx100 = (int) (minx*100);
+ maxx100 = (int) (maxx*100);
+ span100 = (int) (span*100);
+ if (start_in_new < 0.0) {
+ /* Find the closest color inside the active area */
+ first_color = 1;
+ while ((first_color < (int) grad->num_colors_in) &&
+ (grad->colors_in[first_color].position < minx100)) {
+ first_color++;
+ grad->num_actual_colors--;
+ }
+ if (grad->colors_in[first_color].position == minx100) {
+ grad->num_actual_colors--;
+ }
+ else {
+ interpolate_first = True;
+ /*printf("interpolate first color\n");*/
+ }
+ }
+ else {
+ first_color = 0;
+ if (grad->type != ZN_RADIAL_GRADIENT) {
+ grad->num_actual_colors++;
+ }
+ }
+ interpolate_last = False;
+ if (end_in_new > 100.0) {
+ /* Find the closest color inside the active area */
+ last_color = grad->num_colors_in-2;
+ while ((last_color >= 0) &&
+ (grad->colors_in[last_color].position > maxx100)) {
+ last_color--;
+ grad->num_actual_colors--;
+ }
+ if (grad->colors_in[last_color].position == maxx100) {
+ grad->num_actual_colors--;
+ }
+ else {
+ interpolate_last = True;
+ /*printf("interpolate last color\n");*/
+ }
+ }
+ else {
+ last_color = grad->num_colors_in-1;
+ grad->num_actual_colors++;
+ }
+
+ grad->actual_colors = ZnMalloc(grad->num_actual_colors*sizeof(ZnGradientColor));
+ j = 0;
+ if (interpolate_first) {
+ InterpolateGradientColor(tkwin,
+ &grad->colors_in[first_color-1],
+ &grad->colors_in[first_color],
+ &grad->actual_colors[j],
+ NULL,
+ minx100, minx100, span100);
+ j++;
+ }
+ else if ((first_color == 0) && (grad->type != ZN_RADIAL_GRADIENT)) {
+ grad->actual_colors[j] = grad->colors_in[0];
+ grad->actual_colors[j].rgb =
+ Tk_GetColorByValue(tkwin, grad->colors_in[0].rgb);
+ if (grad->colors_in[0].mid_rgb) {
+ grad->actual_colors[j].mid_rgb =
+ Tk_GetColorByValue(tkwin, grad->colors_in[0].mid_rgb);
+ }
+ grad->actual_colors[0].position = 0;
+ grad->actual_colors[0].control = 50;
+ j++;
+ /*printf("adding a color at start\n");*/
+ }
+
+ /*printf("first color: %d, last color: %d, num colors: %d\n",
+ first_color, last_color, grad->num_actual_colors);*/
+ for (i = first_color; i <= last_color; i++, j++) {
+ grad->actual_colors[j] = grad->colors_in[i];
+ grad->actual_colors[j].rgb =
+ Tk_GetColorByValue(tkwin, grad->colors_in[i].rgb);
+ if (grad->colors_in[i].mid_rgb) {
+ grad->actual_colors[j].mid_rgb =
+ Tk_GetColorByValue(tkwin, grad->colors_in[i].mid_rgb);
+ }
+ grad->actual_colors[j].position =
+ (grad->colors_in[i].position-minx100)*100/span100;
+ /*printf("i: %d, j: %d, minx: %d, span: %d, position av: %d position ap: %d\n",
+ i, j, minx100, span100, grad->colors_in[i].position, grad->actual_colors[j].position);*/
+ }
+
+ if (interpolate_last) {
+ InterpolateGradientColor(tkwin,
+ &grad->colors_in[last_color],
+ &grad->colors_in[last_color+1],
+ &grad->actual_colors[j],
+ &grad->actual_colors[j-1],
+ maxx100, minx100, span100);
+ }
+ else if (last_color == ((int) grad->num_colors_in)-1) {
+ i = grad->num_colors_in-1;
+ grad->actual_colors[j] = grad->colors_in[i];
+ grad->actual_colors[j].rgb =
+ Tk_GetColorByValue(tkwin, grad->colors_in[i].rgb);
+ if (grad->colors_in[i].mid_rgb) {
+ grad->actual_colors[j].mid_rgb =
+ Tk_GetColorByValue(tkwin, grad->colors_in[i].mid_rgb);
+ }
+ /*printf("adding a color at end\n");*/
+ }
+ grad->actual_colors[j].position = 100;
+}
+
+
/*
*--------------------------------------------------------------
*
@@ -463,15 +811,16 @@ ZnGetGradient(Tcl_Interp *interp,
Tcl_HashEntry *hash;
ZnGradient *grad;
unsigned int i, j, nspace, num_colors;
- unsigned int size, num_coords;
+ unsigned int size, num_coords=0;
char type;
char const *scan_ptr, *next_ptr, *str_ptr;
- int angle, position, control;
+ ZnReal angle, position, control;
ZnReal coords[4];
char *color_ptr, *end, segment[SEGMENT_SIZE];
ZnGradientColor *first, *last;
XColor color;
int new, red_range, green_range, blue_range;
+ ZnBool simple;
/* printf("ZnGetGradient : %s\n", desc);*/
if (!desc || !*desc) {
@@ -487,213 +836,231 @@ ZnGetGradient(Tcl_Interp *interp,
*/
desc = Tk_GetUid(desc);
+ /*printf("get gradient: %s\n", desc);*/
hash = Tcl_CreateHashEntry(&gradient_table, desc, &new);
if (!new) {
grad = (ZnGradient *) Tcl_GetHashValue(hash);
grad->ref_count++;
+ return grad;
}
- else {
- /*
- * No satisfactory gradient exists yet. Initialize a new one.
- */
- type = ZN_AXIAL_GRADIENT;
- angle = 0;
- /*
- * Skip the trailing spaces.
- */
- while (*desc == ' ') {
- desc++;
- }
- /*
- * Count the sections in the description. It should give
- * the number of colors plus may be the gradient description.
- */
- scan_ptr = desc;
- /*
- * If the first section is the gradient description, start color
- * counts up from zero.
- */
- num_colors = (*scan_ptr == '=') ? 0 : 1;
- while ((scan_ptr = strchr(scan_ptr, '|'))) {
- num_colors++;
- scan_ptr++;
- }
- if (num_colors == 0) {
- Tcl_AppendResult(interp, "gradient should have at least one color \"",
- desc, "\",", NULL);
- grad_err1:
- Tcl_DeleteHashEntry(hash);
- /*printf("ZnGetGradient error : %s\n", desc);*/
- return NULL;
- }
- /*
- * Then look at the gradient type.
- */
- scan_ptr = desc;
- /*
- * next_ptr can't be NULL in the following code,
- * we checked that at least one color was specified
- * after the gradient description.
- */
- next_ptr = strchr(scan_ptr, '|');
- if (*scan_ptr == '=') {
- scan_ptr++;
- if ((*scan_ptr == 'a') && (strncmp(scan_ptr, "axial", 5) == 0)) {
+
+ /*
+ * No satisfactory gradient exists yet. Initialize a new one.
+ */
+ type = ZN_AXIAL_GRADIENT;
+ angle = 0.0;
+ /*
+ * Skip the trailing spaces.
+ */
+ while (*desc == ' ') {
+ desc++;
+ }
+ /*
+ * Count the sections in the description. It should give
+ * the number of colors plus may be the gradient description.
+ */
+ scan_ptr = desc;
+ /*
+ * If the first section is the gradient description, start color
+ * counts up from zero.
+ */
+ num_colors = (*scan_ptr == '=') ? 0 : 1;
+ while ((scan_ptr = strchr(scan_ptr, '|'))) {
+ num_colors++;
+ scan_ptr++;
+ }
+ if (num_colors == 0) {
+ Tcl_AppendResult(interp, "gradient should have at least one color \"",
+ desc, "\",", NULL);
+ grad_err1:
+ Tcl_DeleteHashEntry(hash);
+ /*printf("ZnGetGradient error : %s\n", desc);*/
+ return NULL;
+ }
+ /*
+ * Then look at the gradient type.
+ */
+ scan_ptr = desc;
+ /*
+ * next_ptr can't be NULL in the following code,
+ * we checked that at least one color was specified
+ * after the gradient description.
+ */
+ next_ptr = strchr(scan_ptr, '|');
+ if (*scan_ptr == '=') {
+ scan_ptr++;
+ if (((*scan_ptr == 'a') && (strncmp(scan_ptr, "axial", 5) == 0)) ||
+ ((*scan_ptr == 'c') && (strncmp(scan_ptr, "conical", 7) == 0))) {
+ if (*scan_ptr == 'a') {
scan_ptr += 5;
- if (ParseRealList(scan_ptr, next_ptr, coords, 1) != 1) {
- grad_err3:
- Tcl_AppendResult(interp, "invalid gradient parameter \"",
- desc, "\",", NULL);
- goto grad_err1;
- }
- angle = (int) coords[0];
- }
- else if (((*scan_ptr == 'r') && (strncmp(scan_ptr, "radial", 6) == 0)) ||
- ((*scan_ptr == 'p') && (strncmp(scan_ptr, "path", 4) == 0))) {
- if (*scan_ptr == 'r') {
- type = ZN_RADIAL_GRADIENT;
- scan_ptr += 6;
- }
- else {
- type = ZN_PATH_GRADIENT;
- scan_ptr += 4;
- }
- num_coords = ParseRealList(scan_ptr, next_ptr, coords, 4);
- if ((num_coords != 2) && (num_coords != 4)) {
- goto grad_err3;
- }
}
else {
- Tcl_AppendResult(interp, "invalid gradient type \"",
+ scan_ptr += 7;
+ type = ZN_CONICAL_GRADIENT;
+ }
+ num_coords = ParseRealList(scan_ptr, next_ptr, coords, 4);
+ if ((num_coords != 1) && (num_coords != 4)) {
+ grad_err3:
+ Tcl_AppendResult(interp, "invalid gradient parameter \"",
desc, "\",", NULL);
goto grad_err1;
}
- scan_ptr = next_ptr + 1;
- next_ptr = strchr(scan_ptr, '|');
+ angle = (init) coords[0];
}
- /*
- * Create the gradient structure.
- */
- grad = (ZnGradient *) ZnMalloc(sizeof(ZnGradient) +
- sizeof(ZnGradientColor)*(num_colors-1));
- grad->ref_count = 1;
- grad->simple = True;
- grad->num_colors = num_colors;
- grad->type = type;
- if (type == ZN_AXIAL_GRADIENT) {
- if (num_coords == 4) {
- grad->simple = False;
- grad->g.p.x = coords[0];
- grad->g.p.y = coords[1];
- grad->e.x = coords[2];
- grad->e.y = coords[3];
+ else if (((*scan_ptr == 'r') && (strncmp(scan_ptr, "radial", 6) == 0)) ||
+ ((*scan_ptr == 'p') && (strncmp(scan_ptr, "path", 4) == 0))) {
+ if (*scan_ptr == 'r') {
+ type = ZN_RADIAL_GRADIENT;
+ scan_ptr += 6;
}
else {
- grad->g.angle = angle;
+ type = ZN_PATH_GRADIENT;
+ scan_ptr += 4;
+ }
+ num_coords = ParseRealList(scan_ptr, next_ptr, coords, 4);
+ if ((num_coords != 2) && (num_coords != 4)) {
+ goto grad_err3;
}
}
else {
- grad->g.p.x = coords[0];
- grad->g.p.y = coords[1];
- if (num_coords == 4) {
- grad->simple = False;
- grad->e.x = coords[2];
- grad->e.y = coords[3];
- }
+ Tcl_AppendResult(interp, "invalid gradient type \"",
+ desc, "\",", NULL);
+ goto grad_err1;
}
- grad->hash = hash;
- Tcl_SetHashValue(hash, grad);
-
- for (i = 0; i < num_colors; i++) {
- grad->colors[i].alpha = 100;
- /*
- * Try to parse the color name.
- */
- nspace = strspn(scan_ptr, " \t");
- scan_ptr += nspace;
- str_ptr = strpbrk(scan_ptr, " \t|");
- if (str_ptr) {
- size = str_ptr - scan_ptr;
- }
- else {
- size = strlen(scan_ptr);
- }
- if (size > (SEGMENT_SIZE-1)) {
- Tcl_AppendResult(interp, "color name too long in gradient \"",
- desc, "\",", NULL);
- grad_err2:
- for (j = 0; j < i; j++) {
- Tk_FreeColor(grad->colors[j].rgb);
- }
- ZnFree(grad);
- goto grad_err1;
+ scan_ptr = next_ptr + 1;
+ next_ptr = strchr(scan_ptr, '|');
+ }
+ /*
+ * Create the gradient structure.
+ */
+ grad = (ZnGradient *) ZnMalloc(sizeof(ZnGradient) +
+ sizeof(ZnGradientColor)*(num_colors-1));
+ grad->ref_count = 1;
+ simple = True;
+ grad->num_colors_in = num_colors;
+ grad->type = type;
+ switch (type) {
+ case ZN_AXIAL_GRADIENT:
+ case ZN_CONICAL_GRADIENT:
+ if ((num_coords == 4) &&
+ ((coords[0] != coords[2]) || (coords[1] != coords[3]))) {
+ grad->p.x = coords[0];
+ grad->p.y = coords[1];
+ simple = False;
+ grad->e.x = coords[2];
+ grad->e.y = coords[3];
+ }
+ else {
+ grad->angle = (int) angle;
+ }
+ break;
+ case ZN_RADIAL_GRADIENT:
+ grad->p.x = coords[0];
+ grad->p.y = coords[1];
+ if ((num_coords == 4) &&
+ ((coords[0] != coords[2]) || (coords[1] != coords[3]))) {
+ simple = False;
+ grad->e.x = coords[2];
+ grad->e.y = coords[3];
+ }
+ break;
+ case ZN_PATH_GRADIENT:
+ grad->p.x = coords[0];
+ grad->p.y = coords[1];
+ break;
+ }
+ grad->hash = hash;
+ Tcl_SetHashValue(hash, grad);
+
+ for (i = 0; i < num_colors; i++) {
+ grad->colors_in[i].alpha = 100;
+ /*
+ * Try to parse the color name.
+ */
+ nspace = strspn(scan_ptr, " \t");
+ scan_ptr += nspace;
+ str_ptr = strpbrk(scan_ptr, " \t|");
+ if (str_ptr) {
+ size = str_ptr - scan_ptr;
+ }
+ else {
+ size = strlen(scan_ptr);
+ }
+ if (size > (SEGMENT_SIZE-1)) {
+ Tcl_AppendResult(interp, "color name too long in gradient \"",
+ desc, "\",", NULL);
+ grad_err2:
+ for (j = 0; j < i; j++) {
+ Tk_FreeColor(grad->colors_in[j].rgb);
}
- strncpy(segment, scan_ptr, size);
- segment[size] = 0;
- scan_ptr += size;
+ ZnFree(grad);
+ goto grad_err1;
+ }
+ strncpy(segment, scan_ptr, size);
+ segment[size] = 0;
+ scan_ptr += size;
+ /*
+ * Try to parse the color position.
+ */
+ grad->colors_in[i].position = 0;
+ grad->colors_in[i].control = 50;
+ position = strtod(scan_ptr, &end);
+ if (end != scan_ptr) {
+ grad->colors_in[i].position = (int) position;
+ scan_ptr = end;
/*
- * Try to parse the color position.
+ * Try to parse the control point
*/
- grad->colors[i].position = 0;
- grad->colors[i].control = 50;
- position = strtol(scan_ptr, &end, 10);
+ control = strtod(scan_ptr, &end);
if (end != scan_ptr) {
- grad->colors[i].position = position;
+ grad->colors_in[i].control = (int) control;
scan_ptr = end;
- /*
- * Try to parse the control point
- */
- control = strtol(scan_ptr, &end, 10);
- if (end != scan_ptr) {
- grad->colors[i].control = control;
- scan_ptr = end;
- }
- }
- nspace = strspn(scan_ptr, " \t");
- if ((scan_ptr[nspace] != 0) && (scan_ptr+nspace != next_ptr)) {
- Tcl_AppendResult(interp, "incorrect color description in gradient \"",
- desc, "\",", NULL);
- goto grad_err2;
- }
-
- color_ptr = strchr(segment, ';');
- if (color_ptr) {
- *color_ptr = 0;
- }
- grad->colors[i].rgb = Tk_GetColor(interp, tkwin, Tk_GetUid(segment));
- if (grad->colors[i].rgb == NULL) {
- Tcl_AppendResult(interp, "incorrect color value in gradient \"",
- desc, "\",", NULL);
- goto grad_err2;
- }
- if (color_ptr) {
- color_ptr++;
- grad->colors[i].alpha = atoi(color_ptr);
- }
- if (i == 0) {
- grad->colors[i].position = 0;
- }
- else if (i == num_colors - 1) {
- grad->colors[i].position = 100;
- }
- if ((i > 0) &&
- ((grad->colors[i].position > 100) ||
- (grad->colors[i].position < grad->colors[i-1].position))) {
- Tcl_AppendResult(interp, "incorrect color position in gradient \"",
- desc, "\",", NULL);
- goto grad_err2;
- }
- if (grad->colors[i].control > 100) {
- grad->colors[i].control = 100;
- }
- if (grad->colors[i].alpha > 100) {
- grad->colors[i].alpha = 100;
- }
- if (next_ptr) {
- scan_ptr = next_ptr + 1;
- next_ptr = strchr(scan_ptr, '|');
}
}
+ nspace = strspn(scan_ptr, " \t");
+ if ((scan_ptr[nspace] != 0) && (scan_ptr+nspace != next_ptr)) {
+ Tcl_AppendResult(interp, "incorrect color description in gradient \"",
+ desc, "\",", NULL);
+ goto grad_err2;
+ }
+
+ color_ptr = strchr(segment, ';');
+ if (color_ptr) {
+ *color_ptr = 0;
+ }
+ grad->colors_in[i].rgb = Tk_GetColor(interp, tkwin, Tk_GetUid(segment));
+ if (grad->colors_in[i].rgb == NULL) {
+ Tcl_AppendResult(interp, "incorrect color value in gradient \"",
+ desc, "\",", NULL);
+ goto grad_err2;
+ }
+ if (color_ptr) {
+ color_ptr++;
+ grad->colors_in[i].alpha = atoi(color_ptr);
+ }
+ if (i == 0) {
+ grad->colors_in[i].position = 0;
+ }
+ else if (i == num_colors - 1) {
+ grad->colors_in[i].position = 100;
+ }
+ if ((i > 0) &&
+ ((grad->colors_in[i].position > 100) ||
+ (grad->colors_in[i].position < grad->colors_in[i-1].position))) {
+ Tcl_AppendResult(interp, "incorrect color position in gradient \"",
+ desc, "\",", NULL);
+ goto grad_err2;
+ }
+ if (grad->colors_in[i].control > 100) {
+ grad->colors_in[i].control = 100;
+ }
+ if (grad->colors_in[i].alpha > 100) {
+ grad->colors_in[i].alpha = 100;
+ }
+ if (next_ptr) {
+ scan_ptr = next_ptr + 1;
+ next_ptr = strchr(scan_ptr, '|');
+ }
}
/*
@@ -701,9 +1068,9 @@ ZnGetGradient(Tcl_Interp *interp,
* used by the gradient rendering primitives when a control
* is not at mid range. The last color has no mid_* values.
*/
- for (i = 0; i < grad->num_colors-1; i++) {
- first = &grad->colors[i];
- last = &grad->colors[i+1];
+ for (i = 0; i < grad->num_colors_in-1; i++) {
+ first = &grad->colors_in[i];
+ last = &grad->colors_in[i+1];
red_range = (int) last->rgb->red - (int) first->rgb->red;
green_range = (int) last->rgb->green - (int) first->rgb->green;
blue_range = (int) last->rgb->blue - (int) first->rgb->blue;
@@ -713,8 +1080,24 @@ ZnGetGradient(Tcl_Interp *interp,
first->mid_rgb = Tk_GetColorByValue(tkwin, &color);
first->mid_alpha = first->alpha + (last->alpha-first->alpha)/2;
}
- grad->colors[grad->num_colors-1].mid_rgb = NULL;
+ grad->colors_in[grad->num_colors_in-1].mid_rgb = NULL;
+
+ /*
+ * If the gradient is 'simple' ie. described by a single point
+ * or an angle for axial gradients, the processing is finished.
+ * If not, we have to reduce the gradient to a simple one by adding
+ * or suppressing colors and adjusting the relative position of
+ * each remaining color.
+ */
+ if (simple) {
+ grad->num_actual_colors = grad->num_colors_in;
+ grad->actual_colors = grad->colors_in;
+ }
+ else if (type != ZN_PATH_GRADIENT) {
+ ReduceGradient(tkwin, grad);
+ }
+ /*printf("num in: %d, num actual: %d\n", grad->num_colors_in,grad->num_actual_colors);*/
/* printf("ZnGetGradient end : %s\n", desc);*/
return grad;
}
@@ -770,11 +1153,20 @@ ZnFreeGradient(ZnGradient *grad)
grad->ref_count--;
if (grad->ref_count == 0) {
Tcl_DeleteHashEntry(grad->hash);
- for (i = 0; i < grad->num_colors; i++) {
- Tk_FreeColor(grad->colors[i].rgb);
- if (grad->colors[i].mid_rgb) {
- Tk_FreeColor(grad->colors[i].mid_rgb);
+ for (i = 0; i < grad->num_colors_in; i++) {
+ Tk_FreeColor(grad->colors_in[i].rgb);
+ if (grad->colors_in[i].mid_rgb) {
+ Tk_FreeColor(grad->colors_in[i].mid_rgb);
+ }
+ }
+ if (grad->actual_colors != grad->colors_in) {
+ for (i = 0; i < grad->num_actual_colors; i++) {
+ Tk_FreeColor(grad->actual_colors[i].rgb);
+ if (grad->actual_colors[i].mid_rgb) {
+ Tk_FreeColor(grad->actual_colors[i].mid_rgb);
+ }
}
+ ZnFree(grad->actual_colors);
}
ZnFree(grad);
}