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);