Пример #1
0
LineInfo* line_info_load_and_apply_from_xmlfile(const gchar *filename, LineInfo* info)
{
  xmlDocPtr doc = xmlDoParseFile(filename);
  xmlNodePtr node, root;
  xmlChar *tmp;
  int i;

  if (!doc) {
    g_warning("parse error for %s", filename);
    return NULL;
  }
  /* skip (emacs) comments */
  root = doc->xmlRootNode;
  while (root && (root->type != XML_ELEMENT_NODE)) root = root->next;
  if (!root) return NULL;
  if (xmlIsBlankNode(root)) return NULL;

  i = 0;
  for (node = root->xmlChildrenNode; node != NULL; node = node->next) {
    if (xmlIsBlankNode(node))
      continue;
    else if (node->type != XML_ELEMENT_NODE)
      continue;
    else if (!strcmp((char*)node->name, "name")) {
      tmp = xmlNodeGetContent(node);
/*      g_free(info->name);*/
      info->name = g_strdup((char*)tmp);
/*	  fprintf( stderr, "New shape of type: `%s'\n", info->name ); */
      xmlFree(tmp);
    } else if ( !strcmp((char*)node->name, "icon")) {
      tmp = xmlNodeGetContent(node);
      g_free(info->icon_filename);
      info->icon_filename = custom_get_relative_filename(filename, (char*)tmp);
      xmlFree(tmp);
    } else if ( !strcmp((char*)node->name, "type")) {
      info->type = line_info_get_line_type(filename, node);
    } else if ( !strcmp((char*)node->name, "line-style")) {
      info->line_style = line_info_get_line_style(filename, node);
    } else if ( !strcmp((char*)node->name, "dash-length")) {
      info->dashlength = line_info_get_as_float(filename, node);
    } else if ( !strcmp((char*)node->name, "line-width")) {
      info->line_width = line_info_get_as_float(filename, node);
    } else if ( !strcmp((char*)node->name, "corner-radius")) {
      info->corner_radius = line_info_get_as_float(filename, node);
    } else if ( !strcmp((char*)node->name, "arrows")) {
      line_info_get_arrows(filename, node, info);
    } else if ( !strcmp((char*)node->name, "line-color")) {
      line_info_get_line_color(filename, node, info);
    }
  }

  return( info );
}
Пример #2
0
/*!
 * \brief Contructor for ShapeInfo from file
 * 
 * Load the full shape info from file potentially reusing the preloaded
 * ShapeInfo loaded by shape_typeinfo_load()
 *
 * \extends _ShapeInfo
 */
static ShapeInfo *
load_shape_info(const gchar *filename, ShapeInfo *preload)
{
  xmlErrorPtr error_xml = NULL;
  xmlDocPtr doc = xmlDoParseFile(filename, &error_xml);
  xmlNsPtr shape_ns, svg_ns;
  xmlNodePtr node, root, ext_node = NULL;
  ShapeInfo *info;
  gchar *tmp;
  int i;
  
  if (!doc) {
    g_warning("Custom shape parser error for %s\n%s", filename,
	      error_xml ? error_xml->message : "");
    return NULL;
  }
  /* skip (emacs) comments */
  root = doc->xmlRootNode;
  while (root && (root->type != XML_ELEMENT_NODE)) root = root->next;
  if (!root) return NULL;
  if (xmlIsBlankNode(root)) return NULL;

  if (!(shape_ns = xmlSearchNsByHref(doc, root,
		(const xmlChar *)"http://www.daa.com.au/~james/dia-shape-ns"))) {
    xmlFreeDoc(doc);
    g_warning("could not find shape namespace");
    return NULL;
  }
  if (!(svg_ns = xmlSearchNsByHref(doc, root, (const xmlChar *)"http://www.w3.org/2000/svg"))) {
    xmlFreeDoc(doc);
    g_warning("could not find svg namespace");
    return NULL;
  }
  if (root->ns != shape_ns || xmlStrcmp(root->name, (const xmlChar *)"shape")) {
    g_warning("root element was %s -- expecting shape", root->name);
    xmlFreeDoc(doc);
    return NULL;
  }

  if (preload)
    info = preload;
  else 
    info = g_new0(ShapeInfo, 1);
  info->loaded = TRUE;
  info->shape_bounds.top = DBL_MAX;
  info->shape_bounds.left = DBL_MAX;
  info->shape_bounds.bottom = -DBL_MAX;
  info->shape_bounds.right = -DBL_MAX;
  info->aspect_type = SHAPE_ASPECT_FREE; 
  info->default_width = 0.0;
  info->default_height = 0.0;
  info->main_cp = -1;
  info->object_flags = 0;

  i = 0;
  for (node = root->xmlChildrenNode; node != NULL; node = node->next) {
    if (xmlIsBlankNode(node)) continue;
    if (node->type != XML_ELEMENT_NODE) continue;
    if (node->ns == shape_ns && !xmlStrcmp(node->name, (const xmlChar *)"name")) {
      tmp = (gchar *) xmlNodeGetContent(node);
      if (preload) { 
        if (strcmp (tmp, info->name) != 0)
          g_warning ("Shape(preload) '%s' can't change name '%s'", info->name, tmp);
        /* the key name is already used as key in name_to_info */
      } else {
        g_free(info->name);
        info->name = g_strdup(tmp);
      }
      xmlFree(tmp);
    } else if (node->ns == shape_ns && !xmlStrcmp(node->name, (const xmlChar *)"icon")) {
      tmp = (gchar *) xmlNodeGetContent(node);
      if (preload) { 
        if (strstr (info->icon, tmp) == NULL) /* the left including the absolute path */
          g_warning ("Shape(preload) '%s' can't change icon '%s'", info->icon, tmp);
        /* the key name is already used as key in name_to_info */
      } else {
        g_free(info->icon);
        info->icon = custom_get_relative_filename(filename, tmp);
      }
      xmlFree(tmp);
    } else if (node->ns == shape_ns && !xmlStrcmp(node->name, (const xmlChar *)"connections")) {
      GArray *arr = g_array_new(FALSE, FALSE, sizeof(Point));
      xmlNodePtr pt_node;

      for (pt_node = node->xmlChildrenNode; 
           pt_node != NULL; 
           pt_node = pt_node->next) {
        if (xmlIsBlankNode(pt_node)) continue;

	if (pt_node->ns == shape_ns && !xmlStrcmp(pt_node->name, (const xmlChar *)"point")) {
	  Point pt = { 0.0, 0.0 };
	  xmlChar *str;

	  str = xmlGetProp(pt_node, (const xmlChar *)"x");
	  if (str) {
	    pt.x = g_ascii_strtod((gchar *) str, NULL);
	    xmlFree(str);
	  }
	  str = xmlGetProp(pt_node, (const xmlChar *)"y");
	  if (str) {
	    pt.y = g_ascii_strtod((gchar *) str, NULL);
	    xmlFree(str);
	  }
	  g_array_append_val(arr, pt);
	  str = xmlGetProp(pt_node, (const xmlChar *)"main");
	  if (str && str[0] != '\0') {
	    if (info->main_cp != -1) {
	      message_warning("More than one main connection point in %s.  Only the first one will be used.\n",
			      info->name);
	    } else {
	      info->main_cp = i;
	    }
	    xmlFree(str);
	  }
	}
	i++;
      }
      info->nconnections = arr->len;
      info->connections = (Point *)arr->data;
      g_array_free(arr, FALSE);
    } else if (node->ns == shape_ns && !xmlStrcmp(node->name, (const xmlChar *)"can-parent")) {
      info->object_flags |= DIA_OBJECT_CAN_PARENT;
    } else if (node->ns == shape_ns && !xmlStrcmp(node->name, (const xmlChar *)"textbox")) {
      xmlChar *str;
      
      str = xmlGetProp(node, (const xmlChar *)"x1");
      if (str) {
	info->text_bounds.left = g_ascii_strtod((gchar *) str, NULL);
	xmlFree(str);
      }
      str = xmlGetProp(node, (const xmlChar *)"y1");
      if (str) {
	info->text_bounds.top = g_ascii_strtod((gchar *) str, NULL);
	xmlFree(str);
      }
      str = xmlGetProp(node, (const xmlChar *)"x2");
      if (str) {
	info->text_bounds.right = g_ascii_strtod((gchar *) str, NULL);
	xmlFree(str);
      }
      str = xmlGetProp(node, (const xmlChar *)"y2");
      if (str) {
	info->text_bounds.bottom = g_ascii_strtod((gchar *) str, NULL);
	xmlFree(str);
      }
      info->resize_with_text = TRUE;
      str = xmlGetProp(node, (const xmlChar *)"resize");
      if (str) {
        info->resize_with_text = TRUE;
        if (!xmlStrcmp(str,(const xmlChar *)"no"))
          info->resize_with_text = FALSE;
	xmlFree(str);
      }
      info->text_align = ALIGN_CENTER;
      str = xmlGetProp(node, (const xmlChar *)"align");
      if (str) {
	if (!xmlStrcmp(str, (const xmlChar *)"left")) 
	  info->text_align = ALIGN_LEFT;
	else if (!xmlStrcmp(str, (const xmlChar *)"right"))
	  info->text_align = ALIGN_RIGHT;
	xmlFree(str);
      }
      info->has_text = TRUE;
    } else if (node->ns == shape_ns && !xmlStrcmp(node->name, (const xmlChar *)"aspectratio")) {
      tmp = (gchar *) xmlGetProp(node, (const xmlChar *)"type");
      if (tmp) {
	if (!strcmp(tmp, "free"))
	  info->aspect_type = SHAPE_ASPECT_FREE;
	else if (!strcmp(tmp, "fixed"))
	  info->aspect_type = SHAPE_ASPECT_FIXED;
	else if (!strcmp(tmp, "range")) {
	  xmlChar *str;

	  info->aspect_type = SHAPE_ASPECT_RANGE;
	  info->aspect_min = 0.0;
	  info->aspect_max = G_MAXFLOAT;
	  str = xmlGetProp(node, (const xmlChar *)"min");
	  if (str) {
	    info->aspect_min = g_ascii_strtod((gchar *) str, NULL);
	    xmlFree(str);
	  }
	  str = xmlGetProp(node, (const xmlChar *)"max");
	  if (str) {
	    info->aspect_max = g_ascii_strtod((gchar *) str, NULL);
	    xmlFree(str);
	  }
	  if (info->aspect_max < info->aspect_min) {
	    real asp = info->aspect_max;
	    info->aspect_max = info->aspect_min;
	    info->aspect_min = asp;
	  }
	}
	xmlFree(tmp);
      }
    } else if (node->ns == shape_ns && (!xmlStrcmp(node->name, (const xmlChar *)"default-width") || !xmlStrcmp(node->name, (const xmlChar *)"default-height"))) {
      
      int j = 0;
      DiaUnitDef ud;
      
      gdouble val = 0.0;
      
      int unit_ssize = 0;
      int ssize = 0;
      tmp = (gchar *) xmlNodeGetContent(node);
      ssize = strlen(tmp);

      val = g_ascii_strtod(tmp, NULL);

      for (ud = units[j]; ud.name; ud = units[++j]) {
        unit_ssize = strlen(ud.unit);
        if (ssize > unit_ssize && !strcmp(tmp+(ssize-unit_ssize), ud.unit)) {
          val *= (ud.factor / 28.346457);
          break;
        }
      }

      if (!xmlStrcmp(node->name, (const xmlChar *)"default-width")) {
        info->default_width = val;
      } else {
        info->default_height = val;
      }
      
      xmlFree(tmp);
    } else if (node->ns == svg_ns && !xmlStrcmp(node->name, (const xmlChar *)"svg")) {
      DiaSvgStyle s = {
	1.0, DIA_SVG_COLOUR_FOREGROUND, 1.0, DIA_SVG_COLOUR_NONE, 1.0,
	DIA_SVG_LINECAPS_DEFAULT, DIA_SVG_LINEJOIN_DEFAULT, DIA_SVG_LINESTYLE_DEFAULT, 1.0
      };

      dia_svg_parse_style(node, &s, -1);
      parse_svg_node(info, node, svg_ns, &s, filename);
      update_bounds(info);
    } else if (!xmlStrcmp(node->name, (const xmlChar *)"ext_attributes")) {
      ext_node = node;
    }
  }
  /*MC 11/03 parse ext attributes if any & prepare prop tables */
  custom_setup_properties (info, ext_node);
  xmlFreeDoc(doc);
  return info;
}
Пример #3
0
/*!
 * \brief Parse the SVG node from a shape file
 * 
 * Fill the ShapeInfo display list with GraphicElement each got from
 * a single node within the shape's SVG part.
 *
 * \extends _ShapeInfo
 */
static void
parse_svg_node(ShapeInfo *info, xmlNodePtr node, xmlNsPtr svg_ns,
               DiaSvgStyle *style, const gchar *filename)
{
  xmlChar *str;

      /* walk SVG node ... */
  for (node = node->xmlChildrenNode; node != NULL; node = node->next) {
    GraphicElement *el = NULL;
    DiaSvgStyle s;

    if (xmlIsBlankNode(node)) continue;
    if (node->type != XML_ELEMENT_NODE || node->ns != svg_ns)
      continue;
    dia_svg_style_init (&s, style);
    dia_svg_parse_style(node, &s, -1);
    if (!xmlStrcmp(node->name, (const xmlChar *)"line")) {
      GraphicElementLine *line = g_new0(GraphicElementLine, 1);

      el = (GraphicElement *)line;
      line->type = GE_LINE;
      str = xmlGetProp(node, (const xmlChar *)"x1");
      if (str) {
        line->p1.x = g_ascii_strtod((gchar *) str, NULL);
        xmlFree(str);
      }
      str = xmlGetProp(node, (const xmlChar *)"y1");
      if (str) {
        line->p1.y = g_ascii_strtod((gchar *) str, NULL);
        xmlFree(str);
      }
      str = xmlGetProp(node, (const xmlChar *)"x2");
      if (str) {
        line->p2.x = g_ascii_strtod((gchar *) str, NULL);
        xmlFree(str);
      }
      str = xmlGetProp(node, (const xmlChar *)"y2");
      if (str) {
        line->p2.y = g_ascii_strtod((gchar *) str, NULL);
        xmlFree(str);
      }
    } else if (!xmlStrcmp(node->name, (const xmlChar *)"polyline")) {
      GraphicElementPoly *poly;
      GArray *arr = g_array_new(FALSE, FALSE, sizeof(real));
      real val, *rarr;
      gchar *tmp;
      int i;

      str = xmlGetProp(node, (const xmlChar *)"points");
      tmp = (gchar *) str;
      while (tmp[0] != '\0') {
            /* skip junk */
        while (tmp[0] != '\0' && !g_ascii_isdigit(tmp[0]) && tmp[0]!='.'&&tmp[0]!='-')
          tmp++;
        if (tmp[0] == '\0') break;
        val = g_ascii_strtod(tmp, &tmp);
        g_array_append_val(arr, val);
      }
      xmlFree(str);
      val = 0;
      if (arr->len % 2 == 1) 
        g_array_append_val(arr, val);
      poly = g_malloc0(sizeof(GraphicElementPoly) + arr->len/2*sizeof(Point));
      el = (GraphicElement *)poly;
      poly->type = GE_POLYLINE;
      poly->npoints = arr->len / 2;
      rarr = (real *)arr->data;
      for (i = 0; i < poly->npoints; i++) {
        poly->points[i].x = rarr[2*i];
        poly->points[i].y = rarr[2*i+1];
      }
      g_array_free(arr, TRUE);
    } else if (!xmlStrcmp(node->name, (const xmlChar *)"polygon")) {
      GraphicElementPoly *poly;
      GArray *arr = g_array_new(FALSE, FALSE, sizeof(real));
      real val, *rarr;
      char *tmp;
      int i;

      str = xmlGetProp(node, (const xmlChar *)"points");
      tmp = (char *) str;
      while (tmp[0] != '\0') {
            /* skip junk */
        while (tmp[0] != '\0' && !g_ascii_isdigit(tmp[0]) && tmp[0]!='.'&&tmp[0]!='-')
          tmp++;
        if (tmp[0] == '\0') break;
        val = g_ascii_strtod(tmp, &tmp);
        g_array_append_val(arr, val);
      }
      xmlFree(str);
      val = 0;
      if (arr->len % 2 == 1) 
        g_array_append_val(arr, val);
      poly = g_malloc0(sizeof(GraphicElementPoly) + arr->len/2*sizeof(Point));
      el = (GraphicElement *)poly;
      poly->type = GE_POLYGON;
      poly->npoints = arr->len / 2;
      rarr = (real *)arr->data;
      for (i = 0; i < poly->npoints; i++) {
        poly->points[i].x = rarr[2*i];
        poly->points[i].y = rarr[2*i+1];
      }
      g_array_free(arr, TRUE);
    } else if (!xmlStrcmp(node->name, (const xmlChar *)"rect")) {
      GraphicElementRect *rect = g_new0(GraphicElementRect, 1);
      real corner_radius = 0.0;

      el = (GraphicElement *)rect;
      rect->type = GE_RECT;
      str = xmlGetProp(node, (const xmlChar *)"x");
      if (str) {
        rect->corner1.x = g_ascii_strtod((gchar *) str, NULL);
        xmlFree(str);
      } else rect->corner1.x = 0;
      str = xmlGetProp(node, (const xmlChar *)"y");
      if (str) {
        rect->corner1.y = g_ascii_strtod((gchar *) str, NULL);
        xmlFree(str);
      } else rect->corner1.y = 0;
      str = xmlGetProp(node, (const xmlChar *)"width");
      if (str) {
        rect->corner2.x = rect->corner1.x + g_ascii_strtod((gchar *) str, NULL);
        xmlFree(str);
      }
      str = xmlGetProp(node, (const xmlChar *)"height");
      if (str) {
        rect->corner2.y = rect->corner1.y + g_ascii_strtod((gchar *) str, NULL);
        xmlFree(str);
      }
      str = xmlGetProp(node, (const xmlChar *)"rx");
      if (str) {
        corner_radius = g_ascii_strtod((gchar *) str, NULL);
        xmlFree(str);
      }
      str = xmlGetProp(node, (const xmlChar *)"ry");
      if (str) {
        if(corner_radius != 0.0) {
          /* calculate the mean value of rx and ry */
          corner_radius = (corner_radius+g_ascii_strtod((gchar *) str, NULL))/2;
        } else {
          corner_radius = g_ascii_strtod((gchar *) str, NULL);
        }
        xmlFree(str);
      }
      rect->corner_radius = corner_radius;
    } else if (!xmlStrcmp(node->name, (const xmlChar *)"text")) {

      GraphicElementText *text = g_new(GraphicElementText, 1);
      el = (GraphicElement *)text;
      text->type = GE_TEXT;
      text->object = NULL;
      str = xmlGetProp(node, (const xmlChar *)"x");
      if (str) {
        text->anchor.x = g_ascii_strtod((gchar *) str, NULL);
        xmlFree(str);
      } else text->anchor.x = 0;
      str = xmlGetProp(node, (const xmlChar *)"y");
      if (str) {
        text->anchor.y = g_ascii_strtod((gchar *) str, NULL);
        xmlFree(str);
      } else text->anchor.y = 0;

      str = xmlGetProp(node, (const xmlChar *)"font-size");
      if (str) {
        text->s.font_height = g_ascii_strtod((gchar *) str, NULL);
        xmlFree(str);
      } else text->s.font_height = 0.8;

      str = xmlNodeGetContent(node);
      if (str) {
        text->string = g_strdup((gchar *) str);
        xmlFree(str);
      } else text->string = g_strdup("");
    } else if (!xmlStrcmp(node->name, (const xmlChar *)"circle")) {
      GraphicElementEllipse *ellipse = g_new0(GraphicElementEllipse, 1);

      el = (GraphicElement *)ellipse;
      ellipse->type = GE_ELLIPSE;
      str = xmlGetProp(node, (const xmlChar *)"cx");
      if (str) {
        ellipse->center.x = g_ascii_strtod((gchar *) str, NULL);
        xmlFree(str);
      }
      str = xmlGetProp(node, (const xmlChar *)"cy");
      if (str) {
        ellipse->center.y = g_ascii_strtod((gchar *) str, NULL);
        xmlFree(str);
      }
      str = xmlGetProp(node, (const xmlChar *)"r");
      if (str) {
        ellipse->width = ellipse->height = 2 * g_ascii_strtod((gchar *) str, NULL);
        xmlFree(str);
      }
    } else if (!xmlStrcmp(node->name, (const xmlChar *)"ellipse")) {
      GraphicElementEllipse *ellipse = g_new0(GraphicElementEllipse, 1);

      el = (GraphicElement *)ellipse;
      ellipse->type = GE_ELLIPSE;
      str = xmlGetProp(node, (const xmlChar *)"cx");
      if (str) {
        ellipse->center.x = g_ascii_strtod((gchar *) str, NULL);
        xmlFree(str);
      }
      str = xmlGetProp(node, (const xmlChar *)"cy");
      if (str) {
        ellipse->center.y = g_ascii_strtod((gchar *) str, NULL);
        xmlFree(str);
      }
      str = xmlGetProp(node, (const xmlChar *)"rx");
      if (str) {
        ellipse->width = 2 * g_ascii_strtod((gchar *) str, NULL);
        xmlFree(str);
      }
      str = xmlGetProp(node, (const xmlChar *)"ry");
      if (str) {
        ellipse->height = 2 * g_ascii_strtod((gchar *) str, NULL);
        xmlFree(str);
      }
    } else if (!xmlStrcmp(node->name, (const xmlChar *)"path")) {
      str = xmlGetProp(node, (const xmlChar *)"d");
      if (str) {
        parse_path(info, (char *) str, &s, filename);
        xmlFree(str);
      }
    } else if (!xmlStrcmp(node->name, (const xmlChar *)"image")) {
      GraphicElementImage *image = g_new0(GraphicElementImage, 1);

      el = (GraphicElement *)image;
      image->type = GE_IMAGE;
      str = xmlGetProp(node, (const xmlChar *)"x");
      if (str) {
        image->topleft.x = g_ascii_strtod((gchar *) str, NULL);
        xmlFree(str);
      }
      str = xmlGetProp(node, (const xmlChar *)"y");
      if (str) {
        image->topleft.y = g_ascii_strtod((gchar *) str, NULL);
        xmlFree(str);
      }
      str = xmlGetProp(node, (const xmlChar *)"width");
      if (str) {
        image->width = g_ascii_strtod((gchar *) str, NULL);
        xmlFree(str);
      }
      str = xmlGetProp(node, (const xmlChar *)"height");
      if (str) {
        image->height = g_ascii_strtod((gchar *) str, NULL);
        xmlFree(str);
      }
      str = xmlGetProp(node, (const xmlChar *)"xlink:href");
      if (!str) /* this doesn't look right but it appears to work w/o namespace --hb */
        str = xmlGetProp(node, (const xmlChar *)"href");
      if (str) {
        gchar *imgfn = NULL;
        const char* data = strchr((char *)str, ',');

	/* first check for inlined data */
	if (data) {
	  GdkPixbuf *pixbuf = pixbuf_decode_base64 (data+1);

	  if (pixbuf) {
	    image->image = dia_image_new_from_pixbuf (pixbuf);
	    g_object_unref (pixbuf);
	  }
	} else {
	  imgfn = g_filename_from_uri((gchar *) str, NULL, NULL);
          if (!imgfn)
	    /* despite it's name it ensures an absolute filename */
            imgfn = custom_get_relative_filename(filename, (gchar *) str);

          image->image = dia_image_load(imgfn);
	}
        if (!image->image)
          g_debug("failed to load image file %s", imgfn ? imgfn : "(data:)");
        g_free(imgfn);
        xmlFree(str);
      }
      /* w/o the image we would crash later */
      if (!image->image)
        image->image = dia_image_get_broken();
    } else if (!xmlStrcmp(node->name, (const xmlChar *)"g")) {
      if (!is_subshape(node)) {
          /* add elements from the group element */
        parse_svg_node(info, node, svg_ns, &s, filename);
      } else {
          /* add elements from the group element, but make it a subshape */
        GraphicElementSubShape *subshape = g_new0(GraphicElementSubShape, 1);
        ShapeInfo* tmpinfo = g_new0(ShapeInfo, 1);
        xmlChar *v_anchor_attr = xmlGetProp(node, (const xmlChar*)"v_anchor");
        xmlChar *h_anchor_attr = xmlGetProp(node, (const xmlChar*)"h_anchor");
      
        parse_svg_node(tmpinfo, node, svg_ns, &s, filename);
        
        tmpinfo->shape_bounds.top = DBL_MAX;
        tmpinfo->shape_bounds.left = DBL_MAX;
        tmpinfo->shape_bounds.bottom = -DBL_MAX;
        tmpinfo->shape_bounds.right = -DBL_MAX;

        update_bounds( tmpinfo );
        update_bounds( info );
        
        subshape->half_width = (tmpinfo->shape_bounds.right-tmpinfo->shape_bounds.left) / 2.0;
        subshape->half_height = (tmpinfo->shape_bounds.bottom-tmpinfo->shape_bounds.top) / 2.0;
        subshape->center.x = tmpinfo->shape_bounds.left + subshape->half_width;
        subshape->center.y = tmpinfo->shape_bounds.top + subshape->half_height;
            
        subshape->type = GE_SUBSHAPE;
        subshape->display_list = tmpinfo->display_list;
        subshape->v_anchor_method = OFFSET_METHOD_FIXED;
        subshape->h_anchor_method = OFFSET_METHOD_FIXED;
        subshape->default_scale = 0.0;
                
        if (!v_anchor_attr || !strcmp((const char*)v_anchor_attr,"fixed.top"))
          subshape->v_anchor_method = OFFSET_METHOD_FIXED;
        else if (v_anchor_attr && !strcmp((const char*)v_anchor_attr,"fixed.bottom"))
          subshape->v_anchor_method = -OFFSET_METHOD_FIXED;
        else if (v_anchor_attr && !strcmp((const char*)v_anchor_attr,"proportional"))
          subshape->v_anchor_method = OFFSET_METHOD_PROPORTIONAL;
        else
          fprintf( stderr, "illegal v_anchor `%s', defaulting to fixed.top\n",
                   v_anchor_attr );
          
        if (!h_anchor_attr || !strcmp((const char*)h_anchor_attr,"fixed.left"))
          subshape->h_anchor_method = OFFSET_METHOD_FIXED;
        else if (h_anchor_attr && !strcmp((const char*)h_anchor_attr,"fixed.right"))
          subshape->h_anchor_method = -OFFSET_METHOD_FIXED;
        else if (h_anchor_attr && !strcmp((const char*)h_anchor_attr,"proportional"))
          subshape->h_anchor_method = OFFSET_METHOD_PROPORTIONAL;
        else
          fprintf( stderr, "illegal h_anchor `%s', defaulting to fixed.left\n",
                   h_anchor_attr );
        
        info->subshapes = g_list_append(info->subshapes, subshape);
        
        /* gfree( tmpinfo );*/
        xmlFree(v_anchor_attr);
        xmlFree(h_anchor_attr);
        
        el = (GraphicElement *)subshape;
      }    
    }
    if (el) {
      el->any.s = s;
      if (el->any.s.font)
        el->any.s.font = g_object_ref(s.font);
      info->display_list = g_list_append(info->display_list, el);
    }
    if (s.font)
      dia_font_unref (s.font);
  }
}