void SPUsePath::refresh_source() { sourceDirty = false; delete originalPath; originalPath = NULL; // le mauvais cas: pas d'attribut d => il faut verifier que c'est une SPShape puis prendre le contour // [tr: The bad case: no d attribute. Must check that it's a SPShape and then take the outline.] SPObject *refobj = sourceObject; if ( refobj == NULL ) return; SPItem *item = SP_ITEM(refobj); SPCurve *curve = NULL; if (SP_IS_SHAPE(item)) { curve = SP_SHAPE(item)->getCurve(); } else if (SP_IS_TEXT(item)) { curve = SP_TEXT(item)->getNormalizedBpath(); } else { return; } if (curve == NULL) return; originalPath = new Path; originalPath->LoadPathVector(curve->get_pathvector(), item->transform, true); curve->unref(); }
Inkscape::XML::Node* SPUse::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) { if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) { repr = xml_doc->createElement("svg:use"); } SPItem::write(xml_doc, repr, flags); sp_repr_set_svg_double(repr, "x", this->x.computed); sp_repr_set_svg_double(repr, "y", this->y.computed); repr->setAttribute("width", sp_svg_length_write_with_units(this->width).c_str()); repr->setAttribute("height", sp_svg_length_write_with_units(this->height).c_str()); if (this->ref->getURI()) { gchar *uri_string = this->ref->getURI()->toString(); repr->setAttribute("xlink:href", uri_string); g_free(uri_string); } if (SP_IS_SHAPE(this->child)) { SP_SHAPE(this->child)->set_shape(); // evaluate SPCurve of child } else if (SP_IS_TEXT(this->child)) { SP_TEXT(this->child)->rebuildLayout(); // refresh Layout, LP Bug 1339305 } else if (SP_IS_FLOWTEXT(this->child)) { if (SP_IS_FLOWREGION(SP_FLOWTEXT(this->child)->firstChild())) SP_FLOWREGION(SP_FLOWTEXT(this->child)->firstChild())->UpdateComputed(); SP_FLOWTEXT(this->child)->rebuildLayout(); } return repr; }
SPItem * shape_in_selection(Inkscape::Selection *selection) { for (GSList *items = (GSList *) selection->itemList(); items != NULL; items = items->next) { if (SP_IS_SHAPE(items->data)) return ((SPItem *) items->data); } return NULL; }
void SPLPEItem::apply_to_clippath(SPItem *item) { SPClipPath *clipPath = item->clip_ref->getObject(); if(clipPath) { SPObject * clip_data = clipPath->firstChild(); SPCurve * clip_curve = NULL; if (SP_IS_PATH(clip_data)) { clip_curve = SP_PATH(clip_data)->get_original_curve(); } else if(SP_IS_SHAPE(clip_data)) { clip_curve = SP_SHAPE(clip_data)->getCurve(); } else if(SP_IS_GROUP(clip_data)) { apply_to_clip_or_mask_group(SP_ITEM(clip_data), item); return; } if(clip_curve) { bool success = false; if(SP_IS_GROUP(this)){ clip_curve->transform(i2anc_affine(SP_GROUP(item), SP_GROUP(this))); success = this->performPathEffect(clip_curve); clip_curve->transform(i2anc_affine(SP_GROUP(item), SP_GROUP(this)).inverse()); } else { success = this->performPathEffect(clip_curve); } Inkscape::XML::Node *reprClip = clip_data->getRepr(); if (success) { gchar *str = sp_svg_write_path(clip_curve->get_pathvector()); reprClip->setAttribute("d", str); g_free(str); } else { // LPE was unsuccesfull. Read the old 'd'-attribute. if (gchar const * value = reprClip->attribute("d")) { Geom::PathVector pv = sp_svg_read_pathv(value); SPCurve *oldcurve = new SPCurve(pv); if (oldcurve) { SP_SHAPE(clip_data)->setCurve(oldcurve, TRUE); oldcurve->unref(); } } } clip_curve->unref(); } } if(SP_IS_GROUP(item)){ GSList const *item_list = sp_item_group_item_list(SP_GROUP(item)); for ( GSList const *iter = item_list; iter; iter = iter->next ) { SPObject *subitem = static_cast<SPObject *>(iter->data); apply_to_clippath(SP_ITEM(subitem)); } } }
static bool try_get_intersect_point_with_item_recursive(Geom::PathVector& conn_pv, SPItem* item, const Geom::Affine& item_transform, double& intersect_pos) { double initial_pos = intersect_pos; // if this is a group... if (SP_IS_GROUP(item)) { SPGroup* group = SP_GROUP(item); // consider all first-order children double child_pos = 0.0; std::vector<SPItem*> g = sp_item_group_item_list(group); for (std::vector<SPItem*>::const_iterator i = g.begin();i!=g.end();i++) { SPItem* child_item = *i; try_get_intersect_point_with_item_recursive(conn_pv, child_item, item_transform * child_item->transform, child_pos); if (intersect_pos < child_pos) intersect_pos = child_pos; } return intersect_pos != initial_pos; } // if this is not a shape, nothing to be done if (!SP_IS_SHAPE(item)) return false; // make sure it has an associated curve SPCurve* item_curve = SP_SHAPE(item)->getCurve(); if (!item_curve) return false; // apply transformations (up to common ancestor) item_curve->transform(item_transform); const Geom::PathVector& curve_pv = item_curve->get_pathvector(); Geom::CrossingSet cross = crossings(conn_pv, curve_pv); // iterate over all Crossings //TODO: check correctness of the following code: inner loop uses loop variable // with a name identical to the loop variable of the outer loop. Then rename. for (Geom::CrossingSet::const_iterator i = cross.begin(); i != cross.end(); ++i) { const Geom::Crossings& cr = *i; for (Geom::Crossings::const_iterator i = cr.begin(); i != cr.end(); ++i) { const Geom::Crossing& cr_pt = *i; if ( intersect_pos < cr_pt.ta) intersect_pos = cr_pt.ta; } } item_curve->unref(); return intersect_pos != initial_pos; }
static bool try_get_intersect_point_with_item_recursive(Geom::PathVector& conn_pv, SPItem* item, const Geom::Matrix& item_transform, double& intersect_pos) { double initial_pos = intersect_pos; // if this is a group... if (SP_IS_GROUP(item)) { SPGroup* group = SP_GROUP(item); // consider all first-order children double child_pos = 0.0; for (GSList const* i = sp_item_group_item_list(group); i != NULL; i = i->next) { SPItem* child_item = SP_ITEM(i->data); try_get_intersect_point_with_item_recursive(conn_pv, child_item, item_transform * child_item->transform, child_pos); if (intersect_pos < child_pos) intersect_pos = child_pos; } return intersect_pos != initial_pos; } // if this is not a shape, nothing to be done if (!SP_IS_SHAPE(item)) return false; // make sure it has an associated curve SPCurve* item_curve = sp_shape_get_curve(SP_SHAPE(item)); if (!item_curve) return false; // apply transformations (up to common ancestor) item_curve->transform(item_transform); const Geom::PathVector& curve_pv = item_curve->get_pathvector(); Geom::CrossingSet cross = crossings(conn_pv, curve_pv); // iterate over all Crossings for (Geom::CrossingSet::const_iterator i = cross.begin(); i != cross.end(); i++) { const Geom::Crossings& cr = *i; for (Geom::Crossings::const_iterator i = cr.begin(); i != cr.end(); i++) { const Geom::Crossing& cr_pt = *i; if ( intersect_pos < cr_pt.ta) intersect_pos = cr_pt.ta; } } item_curve->unref(); return intersect_pos != initial_pos; }
static void GetDest(SPObject* child,Shape **computed) { if ( child == NULL ) return; SPCurve *curve=NULL; Geom::Matrix tr_mat; SPObject* u_child=child; if ( SP_IS_USE(u_child) ) { u_child=SP_USE(u_child)->child; tr_mat = SP_ITEM(u_child)->getRelativeTransform(SP_OBJECT_PARENT(child)); } else { tr_mat = SP_ITEM(u_child)->transform; } if ( SP_IS_SHAPE (u_child) ) { curve = sp_shape_get_curve (SP_SHAPE (u_child)); } else if ( SP_IS_TEXT (u_child) ) { curve = SP_TEXT (u_child)->getNormalizedBpath (); } if ( curve ) { Path* temp=new Path; temp->LoadPathVector(curve->get_pathvector(), tr_mat, true); Shape* n_shp=new Shape; temp->Convert(0.25); temp->Fill(n_shp,0); Shape* uncross=new Shape; SPStyle* style=SP_OBJECT_STYLE(u_child); if ( style && style->fill_rule.computed == SP_WIND_RULE_EVENODD ) { uncross->ConvertToShape(n_shp,fill_oddEven); } else { uncross->ConvertToShape(n_shp,fill_nonZero); } UnionShape(computed, uncross); delete uncross; delete n_shp; delete temp; curve->unref(); } else { // printf("no curve\n"); } }
void OriginalPathParam::linked_modified_callback(SPObject *linked_obj, guint /*flags*/) { SPCurve *curve = NULL; if (SP_IS_SHAPE(linked_obj)) { curve = SP_SHAPE(linked_obj)->getCurveBeforeLPE(); } if (SP_IS_TEXT(linked_obj)) { curve = SP_TEXT(linked_obj)->getNormalizedBpath(); } if (curve == NULL) { // curve invalid, set empty pathvector _pathvector = Geom::PathVector(); } else { _pathvector = curve->get_pathvector(); curve->unref(); } must_recalculate_pwd2 = true; emit_changed(); SP_OBJECT(param_effect->getLPEObj())->requestModified(SP_OBJECT_MODIFIED_FLAG); }
void text_flow_into_shape() { SPDesktop *desktop = SP_ACTIVE_DESKTOP; if (!desktop) return; SPDocument *doc = sp_desktop_document (desktop); Inkscape::XML::Document *xml_doc = sp_document_repr_doc(doc); Inkscape::Selection *selection = sp_desktop_selection(desktop); SPItem *text = text_or_flowtext_in_selection(selection); SPItem *shape = shape_in_selection(selection); if (!text || !shape || g_slist_length((GSList *) selection->itemList()) < 2) { sp_desktop_message_stack(desktop)->flash(Inkscape::WARNING_MESSAGE, _("Select <b>a text</b> and one or more <b>paths or shapes</b> to flow text into frame.")); return; } if (SP_IS_TEXT(text)) { // remove transform from text, but recursively scale text's fontsize by the expansion SP_TEXT(text)->_adjustFontsizeRecursive(text, NR::expansion(SP_ITEM(text)->transform)); SP_OBJECT_REPR(text)->setAttribute("transform", NULL); } Inkscape::XML::Node *root_repr = xml_doc->createElement("svg:flowRoot"); root_repr->setAttribute("xml:space", "preserve"); // we preserve spaces in the text objects we create root_repr->setAttribute("style", SP_OBJECT_REPR(text)->attribute("style")); // fixme: transfer style attrs too SP_OBJECT_REPR(SP_OBJECT_PARENT(shape))->appendChild(root_repr); SPObject *root_object = doc->getObjectByRepr(root_repr); g_return_if_fail(SP_IS_FLOWTEXT(root_object)); Inkscape::XML::Node *region_repr = xml_doc->createElement("svg:flowRegion"); root_repr->appendChild(region_repr); SPObject *object = doc->getObjectByRepr(region_repr); g_return_if_fail(SP_IS_FLOWREGION(object)); /* Add clones */ for (GSList *items = (GSList *) selection->itemList(); items != NULL; items = items->next) { SPItem *item = SP_ITEM(items->data); if (SP_IS_SHAPE(item)){ Inkscape::XML::Node *clone = xml_doc->createElement("svg:use"); clone->setAttribute("x", "0"); clone->setAttribute("y", "0"); clone->setAttribute("xlink:href", g_strdup_printf("#%s", SP_OBJECT_REPR(item)->attribute("id"))); // add the new clone to the region region_repr->appendChild(clone); } } if (SP_IS_TEXT(text)) { // flow from text, as string Inkscape::XML::Node *para_repr = xml_doc->createElement("svg:flowPara"); root_repr->appendChild(para_repr); object = doc->getObjectByRepr(para_repr); g_return_if_fail(SP_IS_FLOWPARA(object)); Inkscape::Text::Layout const *layout = te_get_layout(text); Glib::ustring text_ustring = sp_te_get_string_multiline(text, layout->begin(), layout->end()); Inkscape::XML::Node *text_repr = xml_doc->createTextNode(text_ustring.c_str()); // FIXME: transfer all formatting! and convert newlines into flowParas! para_repr->appendChild(text_repr); Inkscape::GC::release(para_repr); Inkscape::GC::release(text_repr); } else { // reflow an already flowed text, preserving paras for (SPObject *o = SP_OBJECT(text)->children; o != NULL; o = o->next) { if (SP_IS_FLOWPARA(o)) { Inkscape::XML::Node *para_repr = SP_OBJECT_REPR(o)->duplicate(xml_doc); root_repr->appendChild(para_repr); object = doc->getObjectByRepr(para_repr); g_return_if_fail(SP_IS_FLOWPARA(object)); Inkscape::GC::release(para_repr); } } } SP_OBJECT(text)->deleteObject (true); sp_document_done(doc, SP_VERB_CONTEXT_TEXT, _("Flow text into shape")); sp_desktop_selection(desktop)->set(SP_ITEM(root_object)); Inkscape::GC::release(root_repr); Inkscape::GC::release(region_repr); }
/** * Get the selected image. Also check for any SPItems over it, in * case the user wants SIOX pre-processing. */ SPImage * Tracer::getSelectedSPImage() { SPDesktop *desktop = SP_ACTIVE_DESKTOP; if (!desktop) { g_warning("Trace: No active desktop"); return NULL; } Inkscape::MessageStack *msgStack = sp_desktop_message_stack(desktop); Inkscape::Selection *sel = sp_desktop_selection(desktop); if (!sel) { char *msg = _("Select an <b>image</b> to trace"); msgStack->flash(Inkscape::ERROR_MESSAGE, msg); //g_warning(msg); return NULL; } if (sioxEnabled) { SPImage *img = NULL; GSList const *list = sel->itemList(); std::vector<SPItem *> items; sioxShapes.clear(); /* First, things are selected top-to-bottom, so we need to invert them as bottom-to-top so that we can discover the image and any SPItems above it */ for ( ; list ; list=list->next) { if (!SP_IS_ITEM(list->data)) { continue; } SPItem *item = SP_ITEM(list->data); items.insert(items.begin(), item); } std::vector<SPItem *>::iterator iter; for (iter = items.begin() ; iter!= items.end() ; iter++) { SPItem *item = *iter; if (SP_IS_IMAGE(item)) { if (img) //we want only one { char *msg = _("Select only one <b>image</b> to trace"); msgStack->flash(Inkscape::ERROR_MESSAGE, msg); return NULL; } img = SP_IMAGE(item); } else // if (img) //# items -after- the image in tree (above it in Z) { if (SP_IS_SHAPE(item)) { SPShape *shape = SP_SHAPE(item); sioxShapes.push_back(shape); } } } if (!img || sioxShapes.size() < 1) { char *msg = _("Select one image and one or more shapes above it"); msgStack->flash(Inkscape::ERROR_MESSAGE, msg); return NULL; } return img; } else //### SIOX not enabled. We want exactly one image selected { SPItem *item = sel->singleItem(); if (!item) { char *msg = _("Select an <b>image</b> to trace"); //same as above msgStack->flash(Inkscape::ERROR_MESSAGE, msg); //g_warning(msg); return NULL; } if (!SP_IS_IMAGE(item)) { char *msg = _("Select an <b>image</b> to trace"); msgStack->flash(Inkscape::ERROR_MESSAGE, msg); //g_warning(msg); return NULL; } SPImage *img = SP_IMAGE(item); return img; } }
/// @todo investigate why Geom::Point p is passed in but ignored. void Inkscape::ObjectSnapper::_collectPaths(Geom::Point /*p*/, SnapSourceType const source_type, bool const &first_point) const { // Now, let's first collect all paths to snap to. If we have a whole bunch of points to snap, // e.g. when translating an item using the selector tool, then we will only do this for the // first point and store the collection for later use. This significantly improves the performance if (first_point) { _clear_paths(); // Determine the type of bounding box we should snap to SPItem::BBoxType bbox_type = SPItem::GEOMETRIC_BBOX; bool p_is_a_node = source_type & SNAPSOURCE_NODE_CATEGORY; bool p_is_a_bbox = source_type & SNAPSOURCE_BBOX_CATEGORY; bool p_is_other = (source_type & SNAPSOURCE_OTHERS_CATEGORY) || (source_type & SNAPSOURCE_DATUMS_CATEGORY); if (_snapmanager->snapprefs.isTargetSnappable(SNAPTARGET_BBOX_EDGE)) { Preferences *prefs = Preferences::get(); int prefs_bbox = prefs->getBool("/tools/bounding_box", 0); bbox_type = !prefs_bbox ? SPItem::VISUAL_BBOX : SPItem::GEOMETRIC_BBOX; } // Consider the page border for snapping if (_snapmanager->snapprefs.isTargetSnappable(SNAPTARGET_PAGE_BORDER) && _snapmanager->snapprefs.isAnyCategorySnappable()) { Geom::PathVector *border_path = _getBorderPathv(); if (border_path != NULL) { _paths_to_snap_to->push_back(SnapCandidatePath(border_path, SNAPTARGET_PAGE_BORDER, Geom::OptRect())); } } for (std::vector<SnapCandidateItem>::const_iterator i = _candidates->begin(); i != _candidates->end(); ++i) { /* Transform the requested snap point to this item's coordinates */ Geom::Affine i2doc(Geom::identity()); SPItem *root_item = NULL; /* We might have a clone at hand, so make sure we get the root item */ if (SP_IS_USE((*i).item)) { i2doc = SP_USE((*i).item)->get_root_transform(); root_item = SP_USE((*i).item)->root(); g_return_if_fail(root_item); } else { i2doc = (*i).item->i2doc_affine(); root_item = (*i).item; } //Build a list of all paths considered for snapping to //Add the item's path to snap to if (_snapmanager->snapprefs.isTargetSnappable(SNAPTARGET_PATH, SNAPTARGET_PATH_INTERSECTION, SNAPTARGET_TEXT_BASELINE)) { if (p_is_other || p_is_a_node || (!_snapmanager->snapprefs.getStrictSnapping() && p_is_a_bbox)) { if (SP_IS_TEXT(root_item) || SP_IS_FLOWTEXT(root_item)) { if (_snapmanager->snapprefs.isTargetSnappable(SNAPTARGET_TEXT_BASELINE)) { // Snap to the text baseline Text::Layout const *layout = te_get_layout(static_cast<SPItem *>(root_item)); if (layout != NULL && layout->outputExists()) { Geom::PathVector *pv = new Geom::PathVector(); pv->push_back(layout->baseline() * root_item->i2dt_affine() * (*i).additional_affine * _snapmanager->getDesktop()->doc2dt()); _paths_to_snap_to->push_back(SnapCandidatePath(pv, SNAPTARGET_TEXT_BASELINE, Geom::OptRect())); } } } else { // Snapping for example to a traced bitmap is very stressing for // the CPU, so we'll only snap to paths having no more than 500 nodes // This also leads to a lag of approx. 500 msec (in my lousy test set-up). bool very_complex_path = false; if (SP_IS_PATH(root_item)) { very_complex_path = SP_PATH(root_item)->nodesInPath() > 500; } if (!very_complex_path && root_item && _snapmanager->snapprefs.isTargetSnappable(SNAPTARGET_PATH, SNAPTARGET_PATH_INTERSECTION)) { SPCurve *curve = NULL; if (SP_IS_SHAPE(root_item)) { curve = SP_SHAPE(root_item)->getCurve(); }/* else if (SP_IS_TEXT(root_item) || SP_IS_FLOWTEXT(root_item)) { curve = te_get_layout(root_item)->convertToCurves(); }*/ if (curve) { // We will get our own copy of the pathvector, which must be freed at some point // Geom::PathVector *pv = pathvector_for_curve(root_item, curve, true, true, Geom::identity(), (*i).additional_affine); Geom::PathVector *pv = new Geom::PathVector(curve->get_pathvector()); (*pv) *= root_item->i2dt_affine() * (*i).additional_affine * _snapmanager->getDesktop()->doc2dt(); // (_edit_transform * _i2d_transform); _paths_to_snap_to->push_back(SnapCandidatePath(pv, SNAPTARGET_PATH, Geom::OptRect())); // Perhaps for speed, get a reference to the Geom::pathvector, and store the transformation besides it. curve->unref(); } } } } } //Add the item's bounding box to snap to if (_snapmanager->snapprefs.isTargetSnappable(SNAPTARGET_BBOX_EDGE)) { if (p_is_other || p_is_a_bbox || (!_snapmanager->snapprefs.getStrictSnapping() && p_is_a_node)) { // Discard the bbox of a clipped path / mask, because we don't want to snap to both the bbox // of the item AND the bbox of the clipping path at the same time if (!(*i).clip_or_mask) { Geom::OptRect rect = root_item->bounds(bbox_type, i2doc); if (rect) { Geom::PathVector *path = _getPathvFromRect(*rect); rect = root_item->desktopBounds(bbox_type); _paths_to_snap_to->push_back(SnapCandidatePath(path, SNAPTARGET_BBOX_EDGE, rect)); } } } } } } }
Inkscape::XML::Node * sp_selected_item_to_curved_repr(SPItem *item, guint32 /*text_grouping_policy*/) { if (!item) return NULL; Inkscape::XML::Document *xml_doc = SP_OBJECT_REPR(item)->document(); if (SP_IS_TEXT(item) || SP_IS_FLOWTEXT(item)) { // Special treatment for text: convert each glyph to separate path, then group the paths Inkscape::XML::Node *g_repr = xml_doc->createElement("svg:g"); g_repr->setAttribute("transform", SP_OBJECT_REPR(item)->attribute("transform")); /* Mask */ gchar *mask_str = (gchar *) SP_OBJECT_REPR(item)->attribute("mask"); if ( mask_str ) g_repr->setAttribute("mask", mask_str); /* Clip path */ gchar *clip_path_str = (gchar *) SP_OBJECT_REPR(item)->attribute("clip-path"); if ( clip_path_str ) g_repr->setAttribute("clip-path", clip_path_str); /* Rotation center */ g_repr->setAttribute("inkscape:transform-center-x", SP_OBJECT_REPR(item)->attribute("inkscape:transform-center-x"), false); g_repr->setAttribute("inkscape:transform-center-y", SP_OBJECT_REPR(item)->attribute("inkscape:transform-center-y"), false); /* Whole text's style */ gchar *style_str = sp_style_write_difference(SP_OBJECT_STYLE(item), SP_OBJECT_STYLE(SP_OBJECT_PARENT(item))); g_repr->setAttribute("style", style_str); g_free(style_str); Inkscape::Text::Layout::iterator iter = te_get_layout(item)->begin(); do { Inkscape::Text::Layout::iterator iter_next = iter; iter_next.nextGlyph(); // iter_next is one glyph ahead from iter if (iter == iter_next) break; /* This glyph's style */ SPObject const *pos_obj = 0; void *rawptr = 0; te_get_layout(item)->getSourceOfCharacter(iter, &rawptr); if (!rawptr || !SP_IS_OBJECT(rawptr)) // no source for glyph, abort break; pos_obj = SP_OBJECT(rawptr); while (SP_IS_STRING(pos_obj) && SP_OBJECT_PARENT(pos_obj)) { pos_obj = SP_OBJECT_PARENT(pos_obj); // SPStrings don't have style } gchar *style_str = sp_style_write_difference(SP_OBJECT_STYLE(pos_obj), SP_OBJECT_STYLE(SP_OBJECT_PARENT(pos_obj))); // get path from iter to iter_next: SPCurve *curve = te_get_layout(item)->convertToCurves(iter, iter_next); iter = iter_next; // shift to next glyph if (!curve) { // error converting this glyph g_free (style_str); continue; } if (curve->is_empty()) { // whitespace glyph? curve->unref(); g_free (style_str); continue; } Inkscape::XML::Node *p_repr = xml_doc->createElement("svg:path"); gchar *def_str = sp_svg_write_path(curve->get_pathvector()); p_repr->setAttribute("d", def_str); g_free(def_str); curve->unref(); p_repr->setAttribute("style", style_str); g_free(style_str); g_repr->appendChild(p_repr); Inkscape::GC::release(p_repr); if (iter == te_get_layout(item)->end()) break; } while (true); return g_repr; } SPCurve *curve = NULL; if (SP_IS_SHAPE(item)) { curve = sp_shape_get_curve(SP_SHAPE(item)); } if (!curve) return NULL; // Prevent empty paths from being added to the document // otherwise we end up with zomby markup in the SVG file if(curve->is_empty()) { curve->unref(); return NULL; } Inkscape::XML::Node *repr = xml_doc->createElement("svg:path"); /* Transformation */ repr->setAttribute("transform", SP_OBJECT_REPR(item)->attribute("transform")); /* Style */ gchar *style_str = sp_style_write_difference(SP_OBJECT_STYLE(item), SP_OBJECT_STYLE(SP_OBJECT_PARENT(item))); repr->setAttribute("style", style_str); g_free(style_str); /* Mask */ gchar *mask_str = (gchar *) SP_OBJECT_REPR(item)->attribute("mask"); if ( mask_str ) repr->setAttribute("mask", mask_str); /* Clip path */ gchar *clip_path_str = (gchar *) SP_OBJECT_REPR(item)->attribute("clip-path"); if ( clip_path_str ) repr->setAttribute("clip-path", clip_path_str); /* Rotation center */ repr->setAttribute("inkscape:transform-center-x", SP_OBJECT_REPR(item)->attribute("inkscape:transform-center-x"), false); repr->setAttribute("inkscape:transform-center-y", SP_OBJECT_REPR(item)->attribute("inkscape:transform-center-y"), false); /* Definition */ gchar *def_str = sp_svg_write_path(curve->get_pathvector()); repr->setAttribute("d", def_str); g_free(def_str); curve->unref(); return repr; }