diff --git a/src/attribute-rel-util.cpp b/src/attribute-rel-util.cpp index 68313a492c102a4308547d5daff973f69075d271..d2f1d35beaa0c7c35f172a18341f796b006a11af 100644 --- a/src/attribute-rel-util.cpp +++ b/src/attribute-rel-util.cpp @@ -244,7 +244,7 @@ void sp_attribute_clean_style(Node* repr, SPCSSAttr *css, unsigned int flags) { // If property value is same as default and the parent value not set or property is not inherited, // mark for deletion. if ( SPAttributeRelCSS::findIfDefault( property, value ) && - ( (css_parent != nullptr && value_p == nullptr) || !SPAttributeRelCSS::findIfInherit( property ) ) ) { + ((value_p == nullptr) || !SPAttributeRelCSS::findIfInherit( property ) ) ) { if ( flags & SP_ATTRCLEAN_DEFAULT_WARN ) { g_warning( "<%s id=\"%s\">: CSS Style property: \"%s\" with default value (%s) not needed.", diff --git a/src/path/path-object-set.cpp b/src/path/path-object-set.cpp index 18b89cf23ffeae8f3d1a1b0d50a1f13cd53c9e54..36de945987a2d3e1b748584be063e1a79511759d 100644 --- a/src/path/path-object-set.cpp +++ b/src/path/path-object-set.cpp @@ -33,8 +33,12 @@ ObjectSet::strokesToPaths(bool legacy, bool skip_undo) return false; } - // Need to turn on stroke scaling to ensure stroke is scaled when transformed! Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + if (prefs->getBool("/options/pathoperationsunlink/value", true)) { + unlinkRecursive(true); + } + + // Need to turn on stroke scaling to ensure stroke is scaled when transformed! bool scale_stroke = prefs->getBool("/options/transform/stroke", true); prefs->setBool("/options/transform/stroke", true); @@ -43,9 +47,10 @@ ObjectSet::strokesToPaths(bool legacy, bool skip_undo) std::vector my_items(items().begin(), items().end()); for (auto item : my_items) { + // Do not remove the object from the selection here + // as we want to keep it selected if the whole operation fails Inkscape::XML::Node *new_node = item_to_paths(item, legacy); if (new_node) { - remove (item); // Remove from selection. SPObject* new_item = document()->getObjectByRepr(new_node); // Markers don't inherit properties from outside the diff --git a/src/path/path-outline.cpp b/src/path/path-outline.cpp index 5cfed8f0aea578e3cd825ebc5c807cca3f115fb1..74010dc83159b8f115b41ddbf6384403c503feae 100644 --- a/src/path/path-outline.cpp +++ b/src/path/path-outline.cpp @@ -340,7 +340,8 @@ Geom::PathVector* item_to_outline(SPItem const *item, bool exclude_markers) // ========================= Stroke to Path ====================== // static -void item_to_paths_add_marker( SPObject *marker_object, Geom::Affine marker_transform, +void item_to_paths_add_marker( SPItem *context, + SPObject *marker_object, Geom::Affine marker_transform, Geom::Scale stroke_scale, Inkscape::XML::Node *g_repr, Inkscape::XML::Document *xml_doc, SPDocument * doc, bool legacy) @@ -365,7 +366,7 @@ void item_to_paths_add_marker( SPObject *marker_object, Geom::Affine marker_tran SPItem *marker_item = (SPItem *) doc->getObjectByRepr(m_repr); marker_item->doWriteTransform(tr); if (!legacy) { - item_to_paths(marker_item, legacy); + item_to_paths(marker_item, legacy, context); } } } @@ -382,13 +383,22 @@ void item_to_paths_add_marker( SPObject *marker_object, Geom::Affine marker_tran * The return value is only used externally to update a selection. */ Inkscape::XML::Node* -item_to_paths(SPItem *item, bool legacy) +item_to_paths(SPItem *item, bool legacy, SPItem *context) { + char const *id = item->getRepr()->attribute("id"); + SPDocument * document = item->document; + // flatten all paths effects SPLPEItem *lpeitem = SP_LPE_ITEM(item); if (lpeitem) { lpeitem->removeAllPathEffects(true); + SPObject *elemref = document->getObjectById(id); + if (elemref && elemref != item) { + // If the LPE item is a shape, it is converted to a path + // so we need to reupdate the item + item = dynamic_cast(elemref); + } } - + // if group, recurse SPGroup *group = dynamic_cast(item); if (group) { if (legacy) { @@ -429,32 +439,52 @@ item_to_paths(SPItem *item, bool legacy) // Copying stroke style to fill will fail for properties not defined by style attribute // (i.e., properties defined in style sheet or by attributes). SPStyle *style = item->style; - - // Stroke SPCSSAttr *ncss = sp_css_attr_from_style(style, SP_STYLE_FLAG_ALWAYS); + SPCSSAttr *ncsf = sp_css_attr_from_style(style, SP_STYLE_FLAG_ALWAYS); + if (context) { + SPStyle *context_style = context->style; + SPCSSAttr *ctxt_style = sp_css_attr_from_style(context_style, SP_STYLE_FLAG_ALWAYS); + // TODO: browsers has diferent behabiours with context on markers + // we need to revisit in the future for best matching + // also dont know if opacity is or want to be included in context + gchar const *s_val = sp_repr_css_property(ctxt_style, "stroke", nullptr); + gchar const *f_val = sp_repr_css_property(ctxt_style, "fill", nullptr); + gchar const *fill_value = (style->fill.paintOrigin == SP_CSS_PAINT_ORIGIN_CONTEXT_STROKE) ? s_val : f_val; + gchar const *stroke_value = (style->stroke.paintOrigin == SP_CSS_PAINT_ORIGIN_CONTEXT_FILL) ? f_val : s_val; + sp_repr_css_set_property(ncss, "fill", fill_value); + sp_repr_css_set_property(ncsf, "fill", fill_value); + sp_repr_css_set_property(ncss, "stroke", stroke_value); + sp_repr_css_set_property(ncsf, "stroke", stroke_value); + } + // Stroke + gchar const *s_val = sp_repr_css_property(ncss, "stroke", nullptr); gchar const *s_opac = sp_repr_css_property(ncss, "stroke-opacity", nullptr); + gchar const *f_val = sp_repr_css_property(ncss, "fill", nullptr); gchar const *opacity = sp_repr_css_property(ncss, "opacity", nullptr); // Also for markers gchar const *filter = sp_repr_css_property(ncss, "filter", nullptr); // Also for markers sp_repr_css_set_property(ncss, "stroke", "none"); + sp_repr_css_set_property(ncss, "stroke-width", nullptr); + sp_repr_css_set_property(ncss, "stroke-opacity", "1.0"); sp_repr_css_set_property(ncss, "filter", nullptr); sp_repr_css_set_property(ncss, "opacity", nullptr); - sp_repr_css_set_property(ncss, "stroke-opacity", "1.0"); + sp_repr_css_unset_property(ncss, "marker-start"); + sp_repr_css_unset_property(ncss, "marker-mid"); + sp_repr_css_unset_property(ncss, "marker-end"); + + // we change the stroke to fill on ncss for create the filled stroke sp_repr_css_set_property(ncss, "fill", s_val); if ( s_opac ) { sp_repr_css_set_property(ncss, "fill-opacity", s_opac); } else { sp_repr_css_set_property(ncss, "fill-opacity", "1.0"); } - sp_repr_css_unset_property(ncss, "marker-start"); - sp_repr_css_unset_property(ncss, "marker-mid"); - sp_repr_css_unset_property(ncss, "marker-end"); - // Fill - SPCSSAttr *ncsf = sp_css_attr_from_style(style, SP_STYLE_FLAG_ALWAYS); + sp_repr_css_set_property(ncsf, "stroke", "none"); sp_repr_css_set_property(ncsf, "stroke-opacity", "1.0"); + sp_repr_css_set_property(ncss, "stroke-width", nullptr); sp_repr_css_set_property(ncsf, "filter", nullptr); sp_repr_css_set_property(ncsf, "opacity", nullptr); sp_repr_css_unset_property(ncsf, "marker-start"); @@ -484,7 +514,7 @@ item_to_paths(SPItem *item, bool legacy) // The stroke ------------------------ Inkscape::XML::Node *stroke = nullptr; - if (stroke_path.size() > 0) { + if (s_val && g_strcmp0(s_val,"none") != 0 && stroke_path.size() > 0) { stroke = xml_doc->createElement("svg:path"); sp_repr_css_change(stroke, ncss, "style"); @@ -496,7 +526,7 @@ item_to_paths(SPItem *item, bool legacy) // The fill -------------------------- Inkscape::XML::Node *fill = nullptr; - if (!legacy) { + if (f_val && g_strcmp0(f_val,"none") != 0 && !legacy) { fill = xml_doc->createElement("svg:path"); sp_repr_css_change(fill, ncsf, "style"); @@ -522,7 +552,7 @@ item_to_paths(SPItem *item, bool legacy) for (int i = 0; i < 2; i++) { // SP_MARKER_LOC and SP_MARKER_LOC_START if ( SPObject *marker_obj = shape->_marker[i] ) { Geom::Affine const m (sp_shape_marker_get_transform_at_start(fill_path.front().front())); - item_to_paths_add_marker( marker_obj, m, scale, + item_to_paths_add_marker( item, marker_obj, m, scale, markers, xml_doc, doc, legacy); } } @@ -538,7 +568,7 @@ item_to_paths(SPItem *item, bool legacy) ! ((path_it == (fill_path.end()-1)) && (path_it->size_default() == 0)) ) // if this is the last path and it is a moveto-only, there is no mid marker there { Geom::Affine const m (sp_shape_marker_get_transform_at_start(path_it->front())); - item_to_paths_add_marker( midmarker_obj, m, scale, + item_to_paths_add_marker( item, midmarker_obj, m, scale, markers, xml_doc, doc, legacy); } @@ -552,7 +582,7 @@ item_to_paths(SPItem *item, bool legacy) * there should be a midpoint marker between last segment and closing straight line segment */ Geom::Affine const m (sp_shape_marker_get_transform(*curve_it1, *curve_it2)); - item_to_paths_add_marker( midmarker_obj, m, scale, + item_to_paths_add_marker( item, midmarker_obj, m, scale, markers, xml_doc, doc, legacy); ++curve_it1; @@ -564,7 +594,7 @@ item_to_paths(SPItem *item, bool legacy) if ( path_it != (fill_path.end()-1) && !path_it->empty()) { Geom::Curve const &lastcurve = path_it->back_default(); Geom::Affine const m = sp_shape_marker_get_transform_at_end(lastcurve); - item_to_paths_add_marker( midmarker_obj, m, scale, + item_to_paths_add_marker( item, midmarker_obj, m, scale, markers, xml_doc, doc, legacy); } } @@ -583,7 +613,7 @@ item_to_paths(SPItem *item, bool legacy) Geom::Curve const &lastcurve = path_last[index]; Geom::Affine const m = sp_shape_marker_get_transform_at_end(lastcurve); - item_to_paths_add_marker( marker_obj, m, scale, + item_to_paths_add_marker( item, marker_obj, m, scale, markers, xml_doc, doc, legacy); } } @@ -707,8 +737,8 @@ item_to_paths(SPItem *item, bool legacy) parent->removeChild(g_repr); } out->setAttribute("transform", item->getRepr()->attribute("transform")); - - Inkscape::GC::release(g_repr); + out->setAttribute("id",id); + Inkscape::GC::release(out); // We're replacing item, delete it. item->deleteObject(false); diff --git a/src/path/path-outline.h b/src/path/path-outline.h index 31556f3b9348be4eb0d07a26d734604ad2514144..10df017a79dfb12a951a92697c641278e2360c19 100644 --- a/src/path/path-outline.h +++ b/src/path/path-outline.h @@ -37,7 +37,7 @@ Geom::PathVector* item_to_outline (SPItem const *item, bool exclude_markers = fa /** * Replace item by path objects (a.k.a. stroke to path). */ -Inkscape::XML::Node* item_to_paths(SPItem *item, bool legacy = false); +Inkscape::XML::Node* item_to_paths(SPItem *item, bool legacy = false, SPItem *context = nullptr); /** * Replace selected items by path objects (a.k.a. stroke to >path). diff --git a/src/verbs.cpp b/src/verbs.cpp index 910a7c5061223f4b7f445143b3b974e0cbba3a76..364ee9edc280f7cd4a995b8599560184e72bc811 100644 --- a/src/verbs.cpp +++ b/src/verbs.cpp @@ -1283,7 +1283,6 @@ void SelectionVerb::perform(SPAction *action, void *data) tools_switch(dt, TOOLS_NODES); break; case SP_VERB_SELECTION_OUTLINE: - selection->toCurves(true); selection->strokesToPaths(); break; case SP_VERB_SELECTION_OUTLINE_LEGACY: