Support "use" element
diff --git a/MagickCore/draw.c b/MagickCore/draw.c
index 13ae550..5d6a522 100644
--- a/MagickCore/draw.c
+++ b/MagickCore/draw.c
@@ -1691,7 +1691,7 @@
return((size_t) floor((angle.y-angle.x)/step+0.5)+3);
}
-static char *GetGroupByID(const char *primitive,const char *id)
+static char *GetNodeByID(const char *primitive,const char *id)
{
char
*token;
@@ -1719,8 +1719,9 @@
n=0;
start=(const char *) NULL;
p=(const char *) NULL;
- for (q=primitive; *q != '\0'; )
+ for (q=primitive; (*q != '\0') && (length == 0); )
{
+ p=q;
GetNextToken(q,&q,extent,token);
if (*token == '\0')
break;
@@ -1742,12 +1743,12 @@
/*
End of group by ID.
*/
- length=(size_t) (q-start);
+ if (start != (const char *) NULL)
+ length=(size_t) (p-start);
break;
}
n--;
}
- p=q;
if (LocaleCompare("push",token) == 0)
{
GetNextToken(q,&q,extent,token);
@@ -1763,13 +1764,13 @@
Start of group by ID.
*/
n=0;
- start=p;
+ start=q;
}
}
}
}
}
- if (length == 0)
+ if (start == (const char *) NULL)
return((char *) NULL);
(void) CopyMagickString(token,start,length);
return(token);
@@ -2993,6 +2994,34 @@
status=MagickFalse;
break;
}
+ case 'u':
+ case 'U':
+ {
+ if (LocaleCompare("use",keyword) == 0)
+ {
+ char
+ *node;
+
+ /*
+ Take a node from within the MVG document, and duplicate it here.
+ */
+ GetNextToken(q,&q,extent,token);
+ node=GetNodeByID(primitive,token);
+ if (node != (char *) NULL)
+ {
+ DrawInfo
+ *clone_info;
+
+ clone_info=CloneDrawInfo((ImageInfo *) NULL,graphic_context[n]);
+ (void) CloneString(&clone_info->primitive,node);
+ node=DestroyString(node);
+ status=DrawImage(image,clone_info,exception);
+ clone_info=DestroyDrawInfo(clone_info);
+ }
+ break;
+ }
+ break;
+ }
case 'v':
case 'V':
{
diff --git a/coders/svg.c b/coders/svg.c
index 2546e47..8c2e750 100644
--- a/coders/svg.c
+++ b/coders/svg.c
@@ -786,6 +786,15 @@
static void SVGStartElement(void *context,const xmlChar *name,
const xmlChar **attributes)
{
+#define PushGraphicContext(id) \
+{ \
+ if (*id == '\0') \
+ (void) FormatLocaleFile(svg_info->file,"push graphic-context\n"); \
+ else \
+ (void) FormatLocaleFile(svg_info->file,"push graphic-context \"%s\"\n", \
+ id); \
+}
+
char
*color,
background[MagickPathExtent],
@@ -992,7 +1001,7 @@
{
if (LocaleCompare((const char *) name,"circle") == 0)
{
- (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
+ PushGraphicContext(id);
break;
}
if (LocaleCompare((const char *) name,"clipPath") == 0)
@@ -1017,7 +1026,7 @@
{
if (LocaleCompare((const char *) name,"ellipse") == 0)
{
- (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
+ PushGraphicContext(id);
break;
}
break;
@@ -1027,7 +1036,7 @@
{
if (LocaleCompare((const char *) name,"foreignObject") == 0)
{
- (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
+ PushGraphicContext(id);
break;
}
break;
@@ -1037,7 +1046,7 @@
{
if (LocaleCompare((const char *) name,"g") == 0)
{
- (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
+ PushGraphicContext(id);
break;
}
break;
@@ -1047,7 +1056,7 @@
{
if (LocaleCompare((const char *) name,"image") == 0)
{
- (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
+ PushGraphicContext(id);
break;
}
break;
@@ -1057,7 +1066,7 @@
{
if (LocaleCompare((const char *) name,"line") == 0)
{
- (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
+ PushGraphicContext(id);
break;
}
if (LocaleCompare((const char *) name,"linearGradient") == 0)
@@ -1075,7 +1084,7 @@
{
if (LocaleCompare((const char *) name,"path") == 0)
{
- (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
+ PushGraphicContext(id);
break;
}
if (LocaleCompare((const char *) name,"pattern") == 0)
@@ -1088,12 +1097,12 @@
}
if (LocaleCompare((const char *) name,"polygon") == 0)
{
- (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
+ PushGraphicContext(id);
break;
}
if (LocaleCompare((const char *) name,"polyline") == 0)
{
- (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
+ PushGraphicContext(id);
break;
}
break;
@@ -1112,7 +1121,7 @@
}
if (LocaleCompare((const char *) name,"rect") == 0)
{
- (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
+ PushGraphicContext(id);
break;
}
break;
@@ -1122,7 +1131,7 @@
{
if (LocaleCompare((const char *) name,"svg") == 0)
{
- (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
+ PushGraphicContext(id);
(void) FormatLocaleFile(svg_info->file,"fill \"black\"\n");
(void) FormatLocaleFile(svg_info->file,"fill-opacity 1\n");
(void) FormatLocaleFile(svg_info->file,"stroke \"none\"\n");
@@ -1137,7 +1146,7 @@
{
if (LocaleCompare((const char *) name,"text") == 0)
{
- (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
+ PushGraphicContext(id);
svg_info->bounds.x=0.0;
svg_info->bounds.y=0.0;
svg_info->bounds.width=0.0;
@@ -1172,7 +1181,17 @@
draw_info=DestroyDrawInfo(draw_info);
*svg_info->text='\0';
}
- (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
+ PushGraphicContext(id);
+ break;
+ }
+ break;
+ }
+ case 'U':
+ case 'u':
+ {
+ if (LocaleCompare((char *) name,"use") == 0)
+ {
+ PushGraphicContext(id);
break;
}
break;
@@ -1513,7 +1532,10 @@
}
if (LocaleCompare(keyword,"href") == 0)
{
- (void) CloneString(&svg_info->url,value);
+ if (*value != '#')
+ (void) CloneString(&svg_info->url,value);
+ else
+ (void) CloneString(&svg_info->url,value+1);
break;
}
break;
@@ -2196,7 +2218,10 @@
}
if (LocaleCompare(keyword,"xlink:href") == 0)
{
- (void) CloneString(&svg_info->url,value);
+ if (*value != '#')
+ (void) CloneString(&svg_info->url,value);
+ else
+ (void) CloneString(&svg_info->url,value+1);
break;
}
if (LocaleCompare(keyword,"x1") == 0)
@@ -2273,7 +2298,7 @@
sx,sy,tx,ty);
if (*background != '\0')
{
- (void) FormatLocaleFile(svg_info->file,"push graphic-context\n");
+ PushGraphicContext(id);
(void) FormatLocaleFile(svg_info->file,"fill %s\n",background);
(void) FormatLocaleFile(svg_info->file,
"rectangle 0,0 %g,%g\n",svg_info->view_box.width,
@@ -2566,6 +2591,20 @@
}
break;
}
+ case 'U':
+ case 'u':
+ {
+ if (LocaleCompare((char *) name,"use") == 0)
+ {
+ if ((svg_info->bounds.x != 0.0) || (svg_info->bounds.y != 0.0))
+ (void) FormatLocaleFile(svg_info->file,"translate %g,%g\n",
+ svg_info->bounds.x,svg_info->bounds.y);
+ (void) FormatLocaleFile(svg_info->file,"use \"%s\"\n",svg_info->url);
+ (void) FormatLocaleFile(svg_info->file,"pop graphic-context\n");
+ break;
+ }
+ break;
+ }
default:
break;
}
@@ -3708,7 +3747,7 @@
blob=(unsigned char *) RelinquishMagickMemory(blob);
(void) FormatLocaleString(message,MagickPathExtent,
" <image id=\"image%.20g\" width=\"%.20g\" height=\"%.20g\" "
- "x=\"%.20g\" y=\"%.20g\"\n xlink:href=\"data:image/png;base64,",
+ "x=\"%.20g\" y=\"%.20g\"\n href=\"data:image/png;base64,",
(double) image->scene,(double) image->columns,(double) image->rows,
(double) image->page.x,(double) image->page.y);
(void) WriteBlobString(image,message);
@@ -4817,7 +4856,7 @@
GetNextToken(q,&q,extent,token);
(void) FormatLocaleString(message,MagickPathExtent,
" <image x=\"%g\" y=\"%g\" width=\"%g\" height=\"%g\" "
- "xlink:href=\"%s\"/>\n",primitive_info[j].point.x,
+ "href=\"%s\"/>\n",primitive_info[j].point.x,
primitive_info[j].point.y,primitive_info[j+1].point.x,
primitive_info[j+1].point.y,token);
(void) WriteBlobString(image,message);