added more test samples.

2004-07-23  Sven Neumann  <sven@gimp.org>

	* libgimpcolor/test-color-parser.c: added more test samples.

	* libgimpcolor/gimprgb-parse.c: fixed a bug that I found with the
	new tests.

	* app/core/gimpgradient-load.c: changed SVG parser to handle
	gradients that are defined more deeply in the SVG hierarchy. Added
	a simplistic CSS style parser to deal with gradient definitions
	that use CSS to define the gradient stop properties (closes bug
	#148127).
This commit is contained in:
Sven Neumann 2004-07-23 11:31:16 +00:00 committed by Sven Neumann
parent 21dd07518c
commit e965603984
4 changed files with 148 additions and 123 deletions

View File

@ -1,3 +1,16 @@
2004-07-23 Sven Neumann <sven@gimp.org>
* libgimpcolor/test-color-parser.c: added more test samples.
* libgimpcolor/gimprgb-parse.c: fixed a bug that I found with the
new tests.
* app/core/gimpgradient-load.c: changed SVG parser to handle
gradients that are defined more deeply in the SVG hierarchy. Added
a simplistic CSS style parser to deal with gradient definitions
that use CSS to define the gradient stop properties (closes bug
#148127).
2004-07-23 Sven Neumann <sven@gimp.org>
* app/core/gimpdatafactory.c: some newlines to improve error

View File

@ -186,27 +186,25 @@ gimp_gradient_load (const gchar *filename,
typedef enum
{
SVG_START,
SVG_IN_SVG,
SVG_IN_GRADIENT,
SVG_IN_GRADIENT_STOP,
SVG_IN_UNKNOWN
SVG_STATE_OUT, /* not inside an <svg /> */
SVG_STATE_IN, /* inside an <svg /> */
SVG_STATE_DONE /* finished, don't care about the rest of the file
* (this is stupid, we should continue parsing
* and return multiple gradients if there are any)
*/
} SvgParserState;
typedef struct
{
SvgParserState state;
SvgParserState last_known_state;
gint unknown_depth;
GimpGradient *gradient;
GList *stops;
SvgParserState state;
GimpGradient *gradient;
GList *stops;
} SvgParser;
typedef struct
{
gdouble offset;
GimpRGB color;
gdouble offset;
GimpRGB color;
} SvgStop;
@ -220,8 +218,7 @@ static void svg_parser_end_element (GMarkupParseContext *context,
const gchar *element_name,
gpointer user_data,
GError **error);
static void svg_parser_start_unknown (SvgParser *parser);
static void svg_parser_end_unknown (SvgParser *parser);
static SvgStop * svg_parse_gradient_stop (const gchar **names,
const gchar **values);
@ -250,10 +247,9 @@ gimp_gradient_load_svg (const gchar *filename,
g_return_val_if_fail (g_path_is_absolute (filename), NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
parser.state = SVG_START;
parser.unknown_depth = 0;
parser.gradient = NULL;
parser.stops = NULL;
parser.state = SVG_STATE_OUT;
parser.gradient = NULL;
parser.stops = NULL;
xml_parser = gimp_xml_parser_new (&markup_parser, &parser);
@ -261,39 +257,9 @@ gimp_gradient_load_svg (const gchar *filename,
gimp_xml_parser_free (xml_parser);
if (success && parser.gradient && parser.stops)
if (success && parser.state == SVG_STATE_DONE)
{
GimpGradientSegment *seg = gimp_gradient_segment_new ();
GimpGradientSegment *next = NULL;
SvgStop *stop = parser.stops->data;
GList *list;
seg->left_color = stop->color;
seg->right_color = stop->color;
/* the list of offsets is sorted from largest to smallest */
for (list = g_list_next (parser.stops); list; list = g_list_next (list))
{
seg->left = stop->offset;
seg->middle = (seg->left + seg->right) / 2.0;
next = seg;
seg = gimp_gradient_segment_new ();
seg->next = next;
next->prev = seg;
seg->right = stop->offset;
seg->right_color = stop->color;
stop = list->data;
seg->left_color = stop->color;
}
seg->middle = (seg->left + seg->right) / 2.0;
parser.gradient->segments = seg;
g_return_val_if_fail (parser.gradient != NULL, FALSE);
data = g_object_ref (parser.gradient);
@ -338,16 +304,13 @@ svg_parser_start_element (GMarkupParseContext *context,
switch (parser->state)
{
case SVG_START:
case SVG_STATE_OUT:
if (strcmp (element_name, "svg") == 0)
parser->state = SVG_IN_SVG;
else
svg_parser_start_unknown (parser);
parser->state = SVG_STATE_IN;
break;
case SVG_IN_SVG:
if (parser->gradient == NULL &&
strcmp (element_name, "linearGradient") == 0)
case SVG_STATE_IN:
if (! parser->gradient && strcmp (element_name, "linearGradient") == 0)
{
const gchar *name = NULL;
@ -363,15 +326,8 @@ svg_parser_start_element (GMarkupParseContext *context,
parser->gradient = g_object_new (GIMP_TYPE_GRADIENT,
"name", name,
NULL);
parser->state = SVG_IN_GRADIENT;
}
else
svg_parser_start_unknown (parser);
break;
case SVG_IN_GRADIENT:
if (strcmp (element_name, "stop") == 0)
else if (parser->gradient && strcmp (element_name, "stop") == 0)
{
SvgStop *stop = svg_parse_gradient_stop (attribute_names,
attribute_values);
@ -385,19 +341,10 @@ svg_parser_start_element (GMarkupParseContext *context,
((SvgStop *) parser->stops->data)->offset);
parser->stops = g_list_prepend (parser->stops, stop);
parser->state = SVG_IN_GRADIENT_STOP;
}
else
svg_parser_start_unknown (parser);
break;
case SVG_IN_GRADIENT_STOP:
svg_parser_start_unknown (parser);
break;
case SVG_IN_UNKNOWN:
svg_parser_start_unknown (parser);
case SVG_STATE_DONE:
break;
}
}
@ -410,60 +357,114 @@ svg_parser_end_element (GMarkupParseContext *context,
{
SvgParser *parser = user_data;
switch (parser->state)
if (parser->state != SVG_STATE_IN)
return;
if (strcmp (element_name, "svg") == 0)
{
case SVG_START:
g_return_if_reached ();
break;
parser->state = SVG_STATE_OUT;
}
else if (parser->gradient && strcmp (element_name, "linearGradient") == 0)
{
GimpGradientSegment *seg = gimp_gradient_segment_new ();
GimpGradientSegment *next = NULL;
SvgStop *stop = parser->stops->data;
GList *list;
case SVG_IN_SVG:
parser->state = SVG_START;
break;
seg->left_color = stop->color;
seg->right_color = stop->color;
case SVG_IN_GRADIENT:
parser->state = SVG_IN_SVG;
break;
/* the list of offsets is sorted from largest to smallest */
for (list = g_list_next (parser->stops); list; list = g_list_next (list))
{
seg->left = stop->offset;
seg->middle = (seg->left + seg->right) / 2.0;
case SVG_IN_GRADIENT_STOP:
parser->state = SVG_IN_GRADIENT;
break;
next = seg;
seg = gimp_gradient_segment_new ();
case SVG_IN_UNKNOWN:
svg_parser_end_unknown (parser);
break;
seg->next = next;
next->prev = seg;
seg->right = stop->offset;
seg->right_color = stop->color;
stop = list->data;
seg->left_color = stop->color;
}
seg->middle = (seg->left + seg->right) / 2.0;
parser->gradient->segments = seg;
parser->state = SVG_STATE_DONE;
}
}
static void
svg_parser_start_unknown (SvgParser *parser)
{
if (parser->unknown_depth == 0)
parser->last_known_state = parser->state;
parser->state = SVG_IN_UNKNOWN;
parser->unknown_depth++;
static void
svg_parse_gradient_stop_style_prop (SvgStop *stop,
const gchar *name,
const gchar *value)
{
if (strcmp (name, "stop-color") == 0)
{
gimp_rgb_parse_css (&stop->color, value, -1);
}
else if (strcmp (name, "stop-opacity") == 0)
{
gdouble opacity = g_ascii_strtod (value, NULL);
if (errno != ERANGE)
gimp_rgb_set_alpha (&stop->color, CLAMP (opacity, 0.0, 1.0));
}
}
/* very simplistic CSS style parser */
static void
svg_parser_end_unknown (SvgParser *parser)
svg_parse_gradient_stop_style (SvgStop *stop,
const gchar *style)
{
g_return_if_fail (parser->unknown_depth > 0 &&
parser->state == SVG_IN_UNKNOWN);
const gchar *end;
const gchar *sep;
parser->unknown_depth--;
while (*style)
{
while (g_ascii_isspace (*style))
style++;
if (parser->unknown_depth == 0)
parser->state = parser->last_known_state;
for (end = style; *end && *end != ';'; end++)
/* do nothing */;
for (sep = style; sep < end && *sep != ':'; sep++)
/* do nothing */;
if (end > sep && sep > style)
{
gchar *name = g_strndup (style, sep - style);
gchar *value = g_strndup (++sep, end - sep - (*end == ';' ? 1 : 0));
svg_parse_gradient_stop_style_prop (stop, name, value);
g_free (value);
g_free (name);
}
style = end;
if (*style == ';')
style++;
}
}
static SvgStop *
svg_parse_gradient_stop (const gchar **names,
const gchar **values)
{
SvgStop stop;
SvgStop *stop = g_new0 (SvgStop, 1);
stop.offset = 0.0;
gimp_rgba_set (&stop.color, 0.0, 0.0, 0.0, 1.0);
gimp_rgb_set_alpha (&stop->color, 1.0);
while (*names && *values)
{
@ -471,28 +472,25 @@ svg_parse_gradient_stop (const gchar **names,
{
gchar *end;
stop.offset = g_ascii_strtod (*values, &end);
stop->offset = g_ascii_strtod (*values, &end);
if (end && *end == '%')
stop.offset /= 100.0;
stop->offset /= 100.0;
stop.offset = CLAMP (stop.offset, 0.0, 1.0);
stop->offset = CLAMP (stop->offset, 0.0, 1.0);
}
else if (strcmp (*names, "stop-color") == 0)
else if (strcmp (*names, "style") == 0)
{
gimp_rgb_parse_css (&stop.color, *values, -1);
svg_parse_gradient_stop_style (stop, *values);
}
else if (strcmp (*names, "stop-opacity") == 0)
else
{
gdouble opacity = g_ascii_strtod (*values, NULL);
if (errno != ERANGE)
gimp_rgb_set_alpha (&stop.color, CLAMP (opacity, 0.0, 1.0));
svg_parse_gradient_stop_style_prop (stop, *names, *values);
}
names++;
values++;
}
return g_memdup (&stop, sizeof (SvgStop));
return stop;
}

View File

@ -234,7 +234,7 @@ gimp_rgb_parse_strip (const gchar *str,
len = strlen (str);
}
while (len > 0 && g_ascii_isspace (str[len]))
while (len > 0 && g_ascii_isspace (str[len - 1]))
len--;
result = g_malloc (len + 1);

View File

@ -27,6 +27,8 @@ typedef struct
static const ColorSample samples[] =
{
/* sample alpha fail red green blue alpha */
{ "#000000", FALSE, FALSE, 0.0, 0.0, 0.0, 0.0 },
{ "#FFff00", FALSE, FALSE, 1.0, 1.0, 0.0, 0.0 },
{ "#6495ed", FALSE, FALSE, DBL(100), DBL(149), DBL(237), 0.0 },
@ -35,9 +37,21 @@ static const ColorSample samples[] =
{ "rgb(0,0,0)", FALSE, FALSE, 0.0, 0.0, 0.0, 0.0 },
{ "rgb(100,149,237)", FALSE, FALSE, DBL(100), DBL(149), DBL(237), 0.0 },
{ "rgba(100%,0,100%,0.5)", TRUE, FALSE, 255.0, 0.0, 255.0, 0.5 },
{ "rgba(100%,0,100%,0.5)", FALSE, TRUE, 255.0, 0.0, 255.0, 0.5 },
{ "rgb(100%,149,20%)", FALSE, FALSE, 1.0, DBL(149), 0.2, 0.0 },
{ "red", FALSE, FALSE, 1.0, 0.0, 0.0, 0.0 },
{ "cornflowerblue", FALSE, FALSE, DBL(100), DBL(149), DBL(237), 0.0 }
{ "rgb(100%,149,20%)", TRUE, TRUE, 1.0, DBL(149), 0.2, 0.0 },
{ "rgb(foobar)", FALSE, TRUE, 0.0, 0.0, 0.0, 0.0 },
{ "rgb(100,149,237", FALSE, TRUE, 0.0, 0.0, 0.0, 0.0 },
{ "rED", FALSE, FALSE, 1.0, 0.0, 0.0, 0.0 },
{ "cornflowerblue", FALSE, FALSE, DBL(100), DBL(149), DBL(237), 0.0 },
{ " red", FALSE, FALSE, 1.0, 0.0, 0.0, 0.0 },
{ "red ", FALSE, FALSE, 1.0, 0.0, 0.0, 0.0 },
{ "red", TRUE, TRUE, 1.0, 0.0, 0.0, 0.0 },
{ "red blue", FALSE, TRUE, 0.0, 0.0, 0.0, 0.0 },
{ "transparent", FALSE, TRUE, 0.0, 0.0, 0.0, 0.0 },
{ "transparent", TRUE, FALSE, 0.0, 0.0, 0.0, 0.0 },
{ "23foobar", FALSE, TRUE, 0.0, 0.0, 0.0, 0.0 },
{ "", FALSE, TRUE, 0.0, 0.0, 0.0, 0.0 }
};
@ -71,7 +85,7 @@ main (void)
gint failures = 0;
gint i;
g_print ("Testing the GIMP color parser ...\n\n");
g_print ("\nTesting the GIMP color parser ...\n");
for (i = 0; i < G_N_ELEMENTS (samples); i++)
{