mirror of https://github.com/GNOME/gimp.git
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:
parent
21dd07518c
commit
e965603984
13
ChangeLog
13
ChangeLog
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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++)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue