diff options
| author | Michael Soegtrop <MSoegtrop@yahoo.de> | 2017-06-05 13:01:17 +0000 |
|---|---|---|
| committer | Michael Soegtrop <MSoegtrop@yahoo.de> | 2017-06-05 13:01:17 +0000 |
| commit | e7248b2fa042f42a5c4dd14cd86ab6a5b4524059 (patch) | |
| tree | 9097520c54e355ded9bd0b4d6618af4e8dacdd91 /src/splivarot.cpp | |
| parent | updated to latest trunk (diff) | |
| parent | [Bug #1695016] Xaml export misses some radialGradients. (diff) | |
| download | inkscape-e7248b2fa042f42a5c4dd14cd86ab6a5b4524059.tar.gz inkscape-e7248b2fa042f42a5c4dd14cd86ab6a5b4524059.zip | |
updated to latest trunk
(bzr r14876.2.4)
Diffstat (limited to 'src/splivarot.cpp')
| -rw-r--r-- | src/splivarot.cpp | 805 |
1 files changed, 481 insertions, 324 deletions
diff --git a/src/splivarot.cpp b/src/splivarot.cpp index 1bc6da3e1..c594a6426 100644 --- a/src/splivarot.cpp +++ b/src/splivarot.cpp @@ -13,7 +13,6 @@ */ #ifdef HAVE_CONFIG_H -# include <config.h> #endif #include <cstring> @@ -23,14 +22,11 @@ #include "xml/repr.h" #include "svg/svg.h" #include "sp-path.h" -#include "sp-shape.h" #include "sp-image.h" #include "sp-marker.h" -#include "enums.h" #include "sp-text.h" #include "sp-flowtext.h" #include "text-editing.h" -#include "sp-item-group.h" #include "style.h" #include "document.h" #include "document-undo.h" @@ -38,15 +34,9 @@ #include "message-stack.h" #include "selection.h" -#include "desktop.h" -#include "display/canvas-bpath.h" -#include "display/curve.h" #include <glibmm/i18n.h> -#include "preferences.h" -#include "xml/repr.h" #include "xml/repr-sorting.h" -#include <2geom/pathvector.h> #include <2geom/svg-path-writer.h> #include "helper/geom.h" @@ -56,66 +46,53 @@ #include "splivarot.h" #include "verbs.h" #include "2geom/svg-path-parser.h" // to get from SVG on boolean to Geom::Path +#include "util/units.h" // to get abbr for document units using Inkscape::DocumentUndo; bool Ancetre(Inkscape::XML::Node *a, Inkscape::XML::Node *who); -void sp_selected_path_boolop(Inkscape::Selection *selection, SPDesktop *desktop, bool_op bop, const unsigned int verb=SP_VERB_NONE, const Glib::ustring description=""); void sp_selected_path_do_offset(SPDesktop *desktop, bool expand, double prefOffset); void sp_selected_path_create_offset_object(SPDesktop *desktop, int expand, bool updating); -void -sp_selected_path_union(Inkscape::Selection *selection, SPDesktop *desktop) -{ - sp_selected_path_boolop(selection, desktop, bool_op_union, SP_VERB_SELECTION_UNION, _("Union")); -} - -void -sp_selected_path_union_skip_undo(Inkscape::Selection *selection, SPDesktop *desktop) -{ - sp_selected_path_boolop(selection, desktop, bool_op_union, SP_VERB_NONE, _("Union")); +bool Inkscape::ObjectSet::pathUnion(const bool skip_undo) { + BoolOpErrors result = pathBoolOp(bool_op_union, skip_undo, SP_VERB_SELECTION_UNION, _("Union")); + return DONE == result; } -void -sp_selected_path_intersect(Inkscape::Selection *selection, SPDesktop *desktop) -{ - sp_selected_path_boolop(selection, desktop, bool_op_inters, SP_VERB_SELECTION_INTERSECT, _("Intersection")); -} - -void -sp_selected_path_diff(Inkscape::Selection *selection, SPDesktop *desktop) +bool +Inkscape::ObjectSet::pathIntersect(const bool skip_undo) { - sp_selected_path_boolop(selection, desktop, bool_op_diff, SP_VERB_SELECTION_DIFF, _("Difference")); + BoolOpErrors result = pathBoolOp(bool_op_inters, skip_undo, SP_VERB_SELECTION_INTERSECT, _("Intersection")); + return DONE == result; } -void -sp_selected_path_diff_skip_undo(Inkscape::Selection *selection, SPDesktop *desktop) +bool +Inkscape::ObjectSet::pathDiff(const bool skip_undo) { - sp_selected_path_boolop(selection, desktop, bool_op_diff, SP_VERB_NONE, _("Difference")); + BoolOpErrors result = pathBoolOp(bool_op_diff, skip_undo, SP_VERB_SELECTION_DIFF, _("Difference")); + return DONE == result; } -void -sp_selected_path_symdiff(Inkscape::Selection *selection, SPDesktop *desktop) -{ - sp_selected_path_boolop(selection, desktop, bool_op_symdiff, SP_VERB_SELECTION_SYMDIFF, _("Exclusion")); -} -void -sp_selected_path_cut(Inkscape::Selection *selection, SPDesktop *desktop) +bool +Inkscape::ObjectSet::pathSymDiff(const bool skip_undo) { - sp_selected_path_boolop(selection, desktop, bool_op_cut, SP_VERB_SELECTION_CUT, _("Division")); + BoolOpErrors result = pathBoolOp(bool_op_symdiff, skip_undo, SP_VERB_SELECTION_SYMDIFF, _("Exclusion")); + return DONE == result; } -void -sp_selected_path_cut_skip_undo(Inkscape::Selection *selection, SPDesktop *desktop) +bool +Inkscape::ObjectSet::pathCut(const bool skip_undo) { - sp_selected_path_boolop(selection, desktop, bool_op_cut, SP_VERB_NONE, _("Division")); + BoolOpErrors result = pathBoolOp(bool_op_cut, skip_undo, SP_VERB_SELECTION_CUT, _("Division")); + return DONE == result; } -void -sp_selected_path_slice(Inkscape::Selection *selection, SPDesktop *desktop) +bool +Inkscape::ObjectSet::pathSlice(const bool skip_undo) { - sp_selected_path_boolop(selection, desktop, bool_op_slice, SP_VERB_SELECTION_SLICE, _("Cut path")); + BoolOpErrors result = pathBoolOp(bool_op_slice, skip_undo, SP_VERB_SELECTION_SLICE, _("Cut path")); + return DONE == result; } // helper for printing error messages, regardless of whether we have a GUI or not @@ -331,20 +308,43 @@ Geom::PathVector pathliv_to_pathvector(Path *pathliv){ // boolean operations on the desktop // take the source paths from the file, do the operation, delete the originals and add the results -void -sp_selected_path_boolop(Inkscape::Selection *selection, SPDesktop *desktop, bool_op bop, const unsigned int verb, const Glib::ustring description) +BoolOpErrors Inkscape::ObjectSet::pathBoolOp(bool_op bop, const bool skip_undo, const unsigned int verb, const Glib::ustring description) { - SPDocument *doc = selection->layers()->getDocument(); - std::vector<SPItem*> il= selection->itemList(); - + if (nullptr != desktop() && !skip_undo) { + SPDocument *doc = desktop()->getDocument(); + BoolOpErrors returnCode = ObjectSet::pathBoolOp(bop, true); + switch(returnCode) { + case ERR_TOO_LESS_PATHS_1: + boolop_display_error_message(desktop(), _("Select <b>at least 1 path</b> to perform a boolean union.")); + break; + case ERR_TOO_LESS_PATHS_2: + boolop_display_error_message(desktop(), _("Select <b>at least 2 paths</b> to perform a boolean operation.")); + break; + case ERR_NO_PATHS: + boolop_display_error_message(desktop(), _("One of the objects is <b>not a path</b>, cannot perform boolean operation.")); + break; + case ERR_Z_ORDER: + boolop_display_error_message(desktop(), _("Unable to determine the <b>z-order</b> of the objects selected for difference, XOR, division, or path cut.")); + break; + case DONE_NO_PATH: + DocumentUndo::done(doc, SP_VERB_NONE, description); + break; + case DONE: + DocumentUndo::done(doc, verb, description); + break; + } + return returnCode; + } + + SPDocument *doc = document(); + std::vector<SPItem*> il(items().begin(), items().end()); + // allow union on a single object for the purpose of removing self overlapse (svn log, revision 13334) - if ( (il.size() < 2) && (bop != bool_op_union)) { - boolop_display_error_message(desktop, _("Select <b>at least 2 paths</b> to perform a boolean operation.")); - return; + if (il.size() < 2 && bop != bool_op_union) { + return ERR_TOO_LESS_PATHS_2; } - else if ( il.size() < 1 ) { - boolop_display_error_message(desktop, _("Select <b>at least 1 path</b> to perform a boolean union.")); - return; + else if (il.size() < 1) { + return ERR_TOO_LESS_PATHS_1; } g_assert(!il.empty()); @@ -360,8 +360,7 @@ sp_selected_path_boolop(Inkscape::Selection *selection, SPDesktop *desktop, bool Inkscape::XML::Node *b = il.back()->getRepr(); if (a == NULL || b == NULL) { - boolop_display_error_message(desktop, _("Unable to determine the <b>z-order</b> of the objects selected for difference, XOR, division, or path cut.")); - return; + return ERR_Z_ORDER; } if (Ancetre(a, b)) { @@ -375,8 +374,7 @@ sp_selected_path_boolop(Inkscape::Selection *selection, SPDesktop *desktop, bool // find their lowest common ancestor Inkscape::XML::Node *parent = LCA(a, b); if (parent == NULL) { - boolop_display_error_message(desktop, _("Unable to determine the <b>z-order</b> of the objects selected for difference, XOR, division, or path cut.")); - return; + return ERR_Z_ORDER; } // find the children of the LCA that lead from it to the a and b @@ -405,8 +403,7 @@ sp_selected_path_boolop(Inkscape::Selection *selection, SPDesktop *desktop, bool SPItem *item = *l; if (!SP_IS_SHAPE(item) && !SP_IS_TEXT(item) && !SP_IS_FLOWTEXT(item)) { - boolop_display_error_message(desktop, _("One of the objects is <b>not a path</b>, cannot perform boolean operation.")); - return; + return ERR_NO_PATHS; } } @@ -439,7 +436,7 @@ sp_selected_path_boolop(Inkscape::Selection *selection, SPDesktop *desktop, bool if (originaux[curOrig] == NULL || originaux[curOrig]->descr_cmd.size() <= 1) { for (int i = curOrig; i >= 0; i--) delete originaux[i]; - return; + return DONE_NO_ACTION; } curOrig++; } @@ -500,18 +497,18 @@ sp_selected_path_boolop(Inkscape::Selection *selection, SPDesktop *desktop, bool bool zeroA = theShapeA->numberOfEdges() == 0; bool zeroB = theShapeB->numberOfEdges() == 0; if (zeroA || zeroB) { - // We might need to do a swap. Apply the above rules depending on operation type. - bool resultIsB = ((bop == bool_op_union || bop == bool_op_symdiff) && zeroA) - || ((bop == bool_op_inters) && zeroB) - || (bop == bool_op_diff); + // We might need to do a swap. Apply the above rules depending on operation type. + bool resultIsB = ((bop == bool_op_union || bop == bool_op_symdiff) && zeroA) + || ((bop == bool_op_inters) && zeroB) + || (bop == bool_op_diff); if (resultIsB) { - // Swap A and B to use B as the result + // Swap A and B to use B as the result Shape *swap = theShapeB; theShapeB = theShapeA; theShapeA = swap; } } else { - // Just do the Boolean operation as usual + // Just do the Boolean operation as usual // les elements arrivent en ordre inverse dans la liste theShape->Booleen(theShapeB, theShapeA, bop); Shape *swap = theShape; @@ -672,24 +669,23 @@ sp_selected_path_boolop(Inkscape::Selection *selection, SPDesktop *desktop, bool for (std::vector<SPItem*>::const_iterator l = il.begin(); l != il.end(); l++){ (*l)->deleteObject(); } - DocumentUndo::done(doc, SP_VERB_NONE, description); - selection->clear(); + clear(); delete res; - return; + return DONE_NO_PATH; } // get the source path object SPObject *source; if ( bop == bool_op_diff || bop == bool_op_cut || bop == bool_op_slice ) { if (reverseOrderForOp) { - source = il[0]; + source = il[0]; } else { - source = il.back(); + source = il.back(); } } else { // find out the bottom object - std::vector<Inkscape::XML::Node*> sorted(selection->reprList()); + std::vector<Inkscape::XML::Node*> sorted(xmlNodes().begin(), xmlNodes().end()); sort(sorted.begin(),sorted.end(),sp_repr_compare_position_bool); @@ -717,7 +713,7 @@ sp_selected_path_boolop(Inkscape::Selection *selection, SPDesktop *desktop, bool gchar *title = source->title(); gchar *desc = source->desc(); // remove source paths - selection->clear(); + clear(); for (std::vector<SPItem*>::const_iterator l = il.begin(); l != il.end(); l++){ // if this is the bottommost object, if (!strcmp(reinterpret_cast<SPObject *>(*l)->getRepr()->attribute("id"), id)) { @@ -796,7 +792,7 @@ sp_selected_path_boolop(Inkscape::Selection *selection, SPDesktop *desktop, bool // move to the saved position repr->setPosition(pos > 0 ? pos : 0); - selection->add(repr); + add(doc->getObjectByRepr(repr)); Inkscape::GC::release(repr); delete resPath[i]; @@ -824,14 +820,14 @@ sp_selected_path_boolop(Inkscape::Selection *selection, SPDesktop *desktop, bool repr->setAttribute("id", id); parent->appendChild(repr); if (title) { - doc->getObjectByRepr(repr)->setTitle(title); - } + doc->getObjectByRepr(repr)->setTitle(title); + } if (desc) { - doc->getObjectByRepr(repr)->setDesc(desc); + doc->getObjectByRepr(repr)->setDesc(desc); } - repr->setPosition(pos > 0 ? pos : 0); + repr->setPosition(pos > 0 ? pos : 0); - selection->add(repr); + add(doc->getObjectByRepr(repr)); Inkscape::GC::release(repr); } @@ -839,17 +835,16 @@ sp_selected_path_boolop(Inkscape::Selection *selection, SPDesktop *desktop, bool if (title) g_free(title); if (desc) g_free(desc); - if (verb != SP_VERB_NONE) { - DocumentUndo::done(doc, verb, description); - } - delete res; + + return DONE; } static void sp_selected_path_outline_add_marker( SPObject *marker_object, Geom::Affine marker_transform, Geom::Scale stroke_scale, Geom::Affine transform, - Inkscape::XML::Node *g_repr, Inkscape::XML::Document *xml_doc, SPDocument * doc ) + Inkscape::XML::Node *g_repr, Inkscape::XML::Document *xml_doc, SPDocument * doc, + SPDesktop *desktop , bool legacy) { SPMarker* marker = SP_MARKER (marker_object); SPItem* marker_item = sp_item_first_item_child(marker_object); @@ -869,8 +864,13 @@ void sp_selected_path_outline_add_marker( SPObject *marker_object, Geom::Affine if (marker_item->getRepr()) { Inkscape::XML::Node *m_repr = marker_item->getRepr()->duplicate(xml_doc); g_repr->appendChild(m_repr); + //There is a special group to markers whith this reverse the order in clussion + m_repr->setPosition(0); SPItem *marker_item = (SPItem *) doc->getObjectByRepr(m_repr); marker_item->doWriteTransform(m_repr, tr); + if (!legacy) { + sp_item_path_outline(marker_item, desktop, legacy); + } } } @@ -883,9 +883,9 @@ void item_outline_add_marker_child( SPItem const *item, Geom::Affine marker_tran // note: a marker child item can be an item group! if (SP_IS_GROUP(item)) { // recurse through all childs: - for (SPObject const *o = item->firstChild() ; o ; o = o->getNext() ) { - if ( SP_IS_ITEM(o) ) { - item_outline_add_marker_child(SP_ITEM(o), tr, pathv_in); + for (auto& o: item->children) { + if ( SP_IS_ITEM(&o) ) { + item_outline_add_marker_child(SP_ITEM(&o), tr, pathv_in); } } } else { @@ -1144,59 +1144,72 @@ Geom::PathVector* item_outline(SPItem const *item, bool bbox_only) return ret_pathv; } -void -sp_selected_path_outline(SPDesktop *desktop) +bool +sp_item_path_outline(SPItem *item, SPDesktop *desktop, bool legacy) { + bool did = false; Inkscape::Selection *selection = desktop->getSelection(); - - if (selection->isEmpty()) { - desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select <b>stroked path(s)</b> to convert stroke to path.")); - return; + SPDocument * doc = desktop->getDocument(); + Inkscape::XML::Document *xml_doc = doc->getReprDoc(); + SPLPEItem *lpeitem = SP_LPE_ITEM(item); + if (lpeitem) { + lpeitem->removeAllPathEffects(true); } - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - bool scale_stroke = prefs->getBool("/options/transform/stroke", true); - prefs->setBool("/options/transform/stroke", true); - bool did = false; - std::vector<SPItem*> il(selection->itemList()); - for (std::vector<SPItem*>::const_iterator l = il.begin(); l != il.end(); l++){ - SPItem *item = *l; + SPGroup *group = dynamic_cast<SPGroup *>(item); + if (group) { + if (legacy) { + return false; + } + std::vector<SPItem*> const item_list = sp_item_group_item_list(group); + for ( std::vector<SPItem*>::const_iterator iter=item_list.begin();iter!=item_list.end();++iter) { + SPItem *subitem = *iter; + sp_item_path_outline(subitem, desktop, legacy); + } + } else { if (!SP_IS_SHAPE(item) && !SP_IS_TEXT(item)) - continue; + return did; SPCurve *curve = NULL; if (SP_IS_SHAPE(item)) { curve = SP_SHAPE(item)->getCurve(); if (curve == NULL) - continue; + return did; } if (SP_IS_TEXT(item)) { curve = SP_TEXT(item)->getNormalizedBpath(); if (curve == NULL) - continue; + return did; } g_assert(curve != NULL); if (curve->get_pathvector().empty()) { - continue; + return did; } // pas de stroke pas de chocolat - if (!item->style || item->style->stroke.noneSet) { + if (!item->style) { curve->unref(); - continue; + return did; } // remember old stroke style, to be set on fill SPStyle *i_style = item->style; + //Stroke - and markers + gchar const *opacity; + gchar const *filter; + SPCSSAttr *ncss = 0; { ncss = sp_css_attr_from_style(i_style, SP_STYLE_FLAG_ALWAYS); gchar const *s_val = sp_repr_css_property(ncss, "stroke", NULL); gchar const *s_opac = sp_repr_css_property(ncss, "stroke-opacity", NULL); - + opacity = sp_repr_css_property(ncss, "opacity", NULL); + filter = sp_repr_css_property(ncss, "filter", NULL); sp_repr_css_set_property(ncss, "stroke", "none"); + sp_repr_css_set_property(ncss, "filter", NULL); + sp_repr_css_set_property(ncss, "opacity", NULL); sp_repr_css_set_property(ncss, "stroke-opacity", "1.0"); sp_repr_css_set_property(ncss, "fill", s_val); if ( s_opac ) { @@ -1208,123 +1221,133 @@ sp_selected_path_outline(SPDesktop *desktop) sp_repr_css_unset_property(ncss, "marker-mid"); sp_repr_css_unset_property(ncss, "marker-end"); } + //fill + SPCSSAttr *ncsf = 0; + { + ncsf = sp_css_attr_from_style(i_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(ncsf, "filter", NULL); + sp_repr_css_set_property(ncsf, "opacity", NULL); + sp_repr_css_unset_property(ncsf, "marker-start"); + sp_repr_css_unset_property(ncsf, "marker-mid"); + sp_repr_css_unset_property(ncsf, "marker-end"); + } Geom::Affine const transform(item->transform); float const scale = transform.descrim(); gchar const *mask = item->getRepr()->attribute("mask"); gchar const *clip_path = item->getRepr()->attribute("clip-path"); - float o_width, o_miter; - JoinType o_join; - ButtType o_butt; - - { - int jointype, captype; - - jointype = i_style->stroke_linejoin.computed; - captype = i_style->stroke_linecap.computed; - o_width = i_style->stroke_width.computed; - - switch (jointype) { - case SP_STROKE_LINEJOIN_MITER: - o_join = join_pointy; - break; - case SP_STROKE_LINEJOIN_ROUND: - o_join = join_round; - break; - default: - o_join = join_straight; - break; - } - - switch (captype) { - case SP_STROKE_LINECAP_SQUARE: - o_butt = butt_square; - break; - case SP_STROKE_LINECAP_ROUND: - o_butt = butt_round; - break; - default: - o_butt = butt_straight; - break; - } - - if (o_width < 0.032) - o_width = 0.032; - o_miter = i_style->stroke_miterlimit.value * o_width; - } - + Path *orig = new Path; + Path *res = new Path; SPCurve *curvetemp = curve_for_item(item); if (curvetemp == NULL) { curve->unref(); - continue; + return did; } // Livarot's outline of arcs is broken. So convert the path to linear and cubics only, for which the outline is created correctly. Geom::PathVector pathv = pathv_to_linear_and_cubic_beziers( curvetemp->get_pathvector() ); curvetemp->unref(); + if ( !item->style->stroke.noneSet ) { + float o_width, o_miter; + JoinType o_join; + ButtType o_butt; - Path *orig = new Path; - orig->LoadPathVector(pathv); + { + int jointype, captype; + + jointype = i_style->stroke_linejoin.computed; + captype = i_style->stroke_linecap.computed; + o_width = i_style->stroke_width.computed; + + switch (jointype) { + case SP_STROKE_LINEJOIN_MITER: + o_join = join_pointy; + break; + case SP_STROKE_LINEJOIN_ROUND: + o_join = join_round; + break; + default: + o_join = join_straight; + break; + } - Path *res = new Path; - res->SetBackData(false); + switch (captype) { + case SP_STROKE_LINECAP_SQUARE: + o_butt = butt_square; + break; + case SP_STROKE_LINECAP_ROUND: + o_butt = butt_round; + break; + default: + o_butt = butt_straight; + break; + } - if (!i_style->stroke_dasharray.values.empty()) { - // For dashed strokes, use Stroke method, because Outline can't do dashes - // However Stroke adds lots of extra nodes _or_ makes the path crooked, so consider this a temporary workaround + if (o_width < 0.032) + o_width = 0.032; + o_miter = i_style->stroke_miterlimit.value * o_width; + } - orig->ConvertWithBackData(0.1); - orig->DashPolylineFromStyle(i_style, scale, 0); + orig->LoadPathVector(pathv); + res->SetBackData(false); - Shape* theShape = new Shape; - orig->Stroke(theShape, false, 0.5*o_width, o_join, o_butt, - 0.5 * o_miter); - orig->Outline(res, 0.5 * o_width, o_join, o_butt, 0.5 * o_miter); + if (!i_style->stroke_dasharray.values.empty()) { + // For dashed strokes, use Stroke method, because Outline can't do dashes + // However Stroke adds lots of extra nodes _or_ makes the path crooked, so consider this a temporary workaround - Shape *theRes = new Shape; + orig->ConvertWithBackData(0.1); - theRes->ConvertToShape(theShape, fill_positive); + orig->DashPolylineFromStyle(i_style, scale, 0); - Path *originaux[1]; - originaux[0] = res; - theRes->ConvertToForme(orig, 1, originaux); + Shape* theShape = new Shape; + orig->Stroke(theShape, false, 0.5*o_width, o_join, o_butt, + 0.5 * o_miter); + orig->Outline(res, 0.5 * o_width, o_join, o_butt, 0.5 * o_miter); - res->Coalesce(5.0); + Shape *theRes = new Shape; - delete theShape; - delete theRes; + theRes->ConvertToShape(theShape, fill_positive); - } else { + Path *originaux[1]; + originaux[0] = res; + theRes->ConvertToForme(orig, 1, originaux); - orig->Outline(res, 0.5 * o_width, o_join, o_butt, 0.5 * o_miter); + res->Coalesce(5.0); - orig->Coalesce(0.5 * o_width); + delete theShape; + delete theRes; - Shape *theShape = new Shape; - Shape *theRes = new Shape; + } else { - res->ConvertWithBackData(1.0); - res->Fill(theShape, 0); - theRes->ConvertToShape(theShape, fill_positive); + orig->Outline(res, 0.5 * o_width, o_join, o_butt, 0.5 * o_miter); - Path *originaux[1]; - originaux[0] = res; - theRes->ConvertToForme(orig, 1, originaux); + orig->Coalesce(0.5 * o_width); - delete theShape; - delete theRes; - } + Shape *theShape = new Shape; + Shape *theRes = new Shape; - if (orig->descr_cmd.size() <= 1) { - // ca a merd, ou bien le resultat est vide - delete res; - delete orig; - continue; - } + res->ConvertWithBackData(1.0); + res->Fill(theShape, 0); + theRes->ConvertToShape(theShape, fill_positive); - did = true; + Path *originaux[1]; + originaux[0] = res; + theRes->ConvertToForme(orig, 1, originaux); + delete theShape; + delete theRes; + } + + if (orig->descr_cmd.size() <= 1) { + // ca a merd, ou bien le resultat est vide + delete res; + delete orig; + return did; + } + } // remember the position of the item gint pos = item->getRepr()->position(); // remember parent @@ -1338,27 +1361,29 @@ sp_selected_path_outline(SPDesktop *desktop) if (res->descr_cmd.size() > 1) { // if there's 0 or 1 node left, drop this path altogether - SPDocument * doc = desktop->getDocument(); - Inkscape::XML::Document *xml_doc = doc->getReprDoc(); - Inkscape::XML::Node *repr = xml_doc->createElement("svg:path"); - - // restore old style, but set old stroke style on fill - sp_repr_css_change(repr, ncss, "style"); + //The stroke + Inkscape::XML::Node *stroke = NULL; + if( !item->style->stroke.noneSet ){ + SPDocument * doc = desktop->getDocument(); + Inkscape::XML::Document *xml_doc = doc->getReprDoc(); + stroke = xml_doc->createElement("svg:path"); - sp_repr_css_attr_unref(ncss); + // restore old style, but set old stroke style on fill + sp_repr_css_change(stroke, ncss, "style"); - gchar *str = orig->svg_dump_path(); - repr->setAttribute("d", str); - g_free(str); + sp_repr_css_attr_unref(ncss); - if (mask) - repr->setAttribute("mask", mask); - if (clip_path) - repr->setAttribute("clip-path", clip_path); + gchar *str = orig->svg_dump_path(); + stroke->setAttribute("d", str); + g_free(str); - if (SP_IS_SHAPE(item) && SP_SHAPE(item)->hasMarkers ()) { + if (mask) + stroke->setAttribute("mask", mask); + if (clip_path) + stroke->setAttribute("clip-path", clip_path); + } - Inkscape::XML::Document *xml_doc = doc->getReprDoc(); + if (SP_IS_SHAPE(item)) { Inkscape::XML::Node *g_repr = xml_doc->createElement("svg:g"); // add the group to the parent @@ -1366,133 +1391,254 @@ sp_selected_path_outline(SPDesktop *desktop) // move to the saved position g_repr->setPosition(pos > 0 ? pos : 0); - g_repr->appendChild(repr); + //The fill + Inkscape::XML::Node *fill = NULL; + if (!legacy) { + gchar const *f_val = sp_repr_css_property(ncsf, "fill", NULL); + if( !item->style->fill.noneSet ){ + fill = xml_doc->createElement("svg:path"); + sp_repr_css_change(fill, ncsf, "style"); + + sp_repr_css_attr_unref(ncsf); + + gchar *str = sp_svg_write_path( pathv ); + fill->setAttribute("d", str); + g_free(str); + + if (mask) + fill->setAttribute("mask", mask); + if (clip_path) + fill->setAttribute("clip-path", clip_path); + } + } // restore title, description, id, transform - repr->setAttribute("id", id); - SPItem *newitem = (SPItem *) doc->getObjectByRepr(repr); - newitem->doWriteTransform(repr, transform); + g_repr->setAttribute("id", id); + SPItem *newitem = (SPItem *) doc->getObjectByRepr(g_repr); + newitem->doWriteTransform(g_repr, transform); if (title) { newitem->setTitle(title); } if (desc) { newitem->setDesc(desc); } - SPShape *shape = SP_SHAPE(item); Geom::PathVector const & pathv = curve->get_pathvector(); - - // START marker - 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(pathv.front().front())); - sp_selected_path_outline_add_marker( marker_obj, m, - Geom::Scale(i_style->stroke_width.computed), transform, - g_repr, xml_doc, doc ); + Inkscape::XML::Node *markers = NULL; + if(SP_SHAPE(item)->hasMarkers ()) { + if (!legacy) { + markers = xml_doc->createElement("svg:g"); + g_repr->appendChild(markers); + markers->setPosition(pos > 0 ? pos : 0); + } else { + markers = g_repr; } - } - // MID marker - for (int i = 0; i < 3; i += 2) { // SP_MARKER_LOC and SP_MARKER_LOC_MID - SPObject *midmarker_obj = shape->_marker[i]; - if (!midmarker_obj) continue; - for(Geom::PathVector::const_iterator path_it = pathv.begin(); path_it != pathv.end(); ++path_it) { - // START position - if ( path_it != pathv.begin() - && ! ((path_it == (pathv.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())); - sp_selected_path_outline_add_marker( midmarker_obj, m, + // START marker + 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(pathv.front().front())); + sp_selected_path_outline_add_marker( marker_obj, m, Geom::Scale(i_style->stroke_width.computed), transform, - g_repr, xml_doc, doc ); + markers, xml_doc, doc, desktop, legacy); } - // MID position - if (path_it->size_default() > 1) { - Geom::Path::const_iterator curve_it1 = path_it->begin(); // incoming curve - Geom::Path::const_iterator curve_it2 = ++(path_it->begin()); // outgoing curve - while (curve_it2 != path_it->end_default()) + } + // MID marker + for (int i = 0; i < 3; i += 2) { // SP_MARKER_LOC and SP_MARKER_LOC_MID + SPObject *midmarker_obj = shape->_marker[i]; + if (!midmarker_obj) continue; + for(Geom::PathVector::const_iterator path_it = pathv.begin(); path_it != pathv.end(); ++path_it) { + // START position + if ( path_it != pathv.begin() + && ! ((path_it == (pathv.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 { - /* Put marker between curve_it1 and curve_it2. - * Loop to end_default (so including closing segment), because when a path is closed, - * 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)); - sp_selected_path_outline_add_marker(midmarker_obj, m, - Geom::Scale(i_style->stroke_width.computed), transform, - g_repr, xml_doc, doc); - - ++curve_it1; - ++curve_it2; + Geom::Affine const m (sp_shape_marker_get_transform_at_start(path_it->front())); + sp_selected_path_outline_add_marker( midmarker_obj, m, + Geom::Scale(i_style->stroke_width.computed), transform, + markers, xml_doc, doc, desktop, legacy); + } + // MID position + if (path_it->size_default() > 1) { + Geom::Path::const_iterator curve_it1 = path_it->begin(); // incoming curve + Geom::Path::const_iterator curve_it2 = ++(path_it->begin()); // outgoing curve + while (curve_it2 != path_it->end_default()) + { + /* Put marker between curve_it1 and curve_it2. + * Loop to end_default (so including closing segment), because when a path is closed, + * 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)); + sp_selected_path_outline_add_marker( midmarker_obj, m, + Geom::Scale(i_style->stroke_width.computed), transform, + markers, xml_doc, doc, desktop, legacy); + + ++curve_it1; + ++curve_it2; + } + } + // END position + if ( path_it != (pathv.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); + sp_selected_path_outline_add_marker( midmarker_obj, m, + Geom::Scale(i_style->stroke_width.computed), transform, + markers, xml_doc, doc, desktop, legacy); } } - // END position - if ( path_it != (pathv.end()-1) && !path_it->empty()) { - Geom::Curve const &lastcurve = path_it->back_default(); + } + // END marker + for (int i = 0; i < 4; i += 3) { // SP_MARKER_LOC and SP_MARKER_LOC_END + if ( SPObject *marker_obj = shape->_marker[i] ) { + /* Get reference to last curve in the path. + * For moveto-only path, this returns the "closing line segment". */ + Geom::Path const &path_last = pathv.back(); + unsigned int index = path_last.size_default(); + if (index > 0) { + index--; + } + Geom::Curve const &lastcurve = path_last[index]; + Geom::Affine const m = sp_shape_marker_get_transform_at_end(lastcurve); - sp_selected_path_outline_add_marker( midmarker_obj, m, + sp_selected_path_outline_add_marker( marker_obj, m, Geom::Scale(i_style->stroke_width.computed), transform, - g_repr, xml_doc, doc ); + markers, xml_doc, doc, desktop, legacy); } } + if (!legacy) { + if (mask) + markers->setAttribute("mask", mask); + if (clip_path) + markers->setAttribute("clip-path", clip_path); + } } - // END marker - for (int i = 0; i < 4; i += 3) { // SP_MARKER_LOC and SP_MARKER_LOC_END - if ( SPObject *marker_obj = shape->_marker[i] ) { - /* Get reference to last curve in the path. - * For moveto-only path, this returns the "closing line segment". */ - Geom::Path const &path_last = pathv.back(); - unsigned int index = path_last.size_default(); - if (index > 0) { - index--; + gchar const *paint_order = sp_repr_css_property(ncss, "paint-order", NULL); + SPIPaintOrder temp; + temp.read( paint_order ); + bool unique = false; + if ((!fill && !markers) || (!fill && !stroke) || (!markers && !stroke)) { + unique = true; + } + if (temp.layer[0] != SP_CSS_PAINT_ORDER_NORMAL && !legacy && !unique) { + + if (temp.layer[0] == SP_CSS_PAINT_ORDER_FILL) { + if (temp.layer[1] == SP_CSS_PAINT_ORDER_STROKE) { + if ( fill ) { + g_repr->appendChild(fill); + } + if ( stroke ) { + g_repr->appendChild(stroke); + } + if ( markers ) { + markers->setPosition(2); + } + } else { + if ( fill ) { + g_repr->appendChild(fill); + } + if ( markers ) { + markers->setPosition(1); + } + if ( stroke ) { + g_repr->appendChild(stroke); + } + } + } else if (temp.layer[0] == SP_CSS_PAINT_ORDER_STROKE) { + if (temp.layer[1] == SP_CSS_PAINT_ORDER_FILL) { + if ( stroke ) { + g_repr->appendChild(stroke); + } + if ( fill ) { + g_repr->appendChild(fill); + } + if ( markers ) { + markers->setPosition(2); + } + } else { + if ( stroke ) { + g_repr->appendChild(stroke); + } + if ( markers ) { + markers->setPosition(1); + } + if ( fill ) { + g_repr->appendChild(fill); + } } - Geom::Curve const &lastcurve = path_last[index]; + } else { + if (temp.layer[1] == SP_CSS_PAINT_ORDER_STROKE) { + if ( markers ) { + markers->setPosition(0); + } + if ( stroke ) { + g_repr->appendChild(stroke); + } + if ( fill ) { + g_repr->appendChild(fill); + } + } else { + if ( markers ) { + markers->setPosition(0); + } + if ( fill ) { + g_repr->appendChild(fill); + } + if ( stroke ) { + g_repr->appendChild(stroke); + } + } + } - Geom::Affine const m = sp_shape_marker_get_transform_at_end(lastcurve); - sp_selected_path_outline_add_marker( marker_obj, m, - Geom::Scale(i_style->stroke_width.computed), transform, - g_repr, xml_doc, doc ); + } else if (!unique) { + if ( fill ) { + g_repr->appendChild(fill); + } + if ( stroke ) { + g_repr->appendChild(stroke); } + if ( markers ) { + markers->setPosition(2); + } + } + if( fill || stroke || markers ) { + did = true; } + + Inkscape::XML::Node *out = NULL; + if (!fill && !markers && did) { + out = stroke; + } else if (!fill && !stroke && did) { + out = markers; + } else if (!markers && !stroke && did) { + out = fill; + } else if(did) { + out = g_repr; + } + SPCSSAttr *r_style = sp_repr_css_attr_new(); + sp_repr_css_set_property(r_style, "opacity", opacity); + sp_repr_css_set_property(r_style, "filter", filter); + sp_repr_css_change(out, r_style, "style"); + sp_repr_css_attr_unref(r_style); + if (unique) { + parent->appendChild(out); + parent->removeChild(g_repr); + out->setPosition(pos > 0 ? pos : 0); + } + out->setAttribute("transform", item->getRepr()->attribute("transform")); //bug lp:1290573 : completely destroy the old object first curve->unref(); - selection->remove(item); - item->deleteObject(false); - - selection->add(g_repr); - - Inkscape::GC::release(g_repr); - - } else - { - //lp:1290573 - curve->unref(); - selection->remove(item); - item->deleteObject(false); - - // add the new repr to the parent - parent->appendChild(repr); - - // move to the saved position - repr->setPosition(pos > 0 ? pos : 0); - - // restore title, description, id, transform - repr->setAttribute("id", id); - - SPItem *newitem = (SPItem *) desktop->getDocument()->getObjectByRepr(repr); - newitem->doWriteTransform(repr, transform); - if (title) { - newitem->setTitle(title); - } - if (desc) { - newitem->setDesc(desc); + //Check for recursive markers to path + if (did) { + if( selection->includes(item) ){ + selection->remove(item); + item->deleteObject(false); + selection->add(out); + } else { + item->deleteObject(false); + } + Inkscape::GC::release(g_repr); } - - selection->add(repr); - } - - Inkscape::GC::release(repr); - } + if (title) { g_free(title); title = 0; @@ -1505,6 +1651,28 @@ sp_selected_path_outline(SPDesktop *desktop) delete res; delete orig; } + return did; +} + +void +sp_selected_path_outline(SPDesktop *desktop, bool legacy) +{ + Inkscape::Selection *selection = desktop->getSelection(); + + if (selection->isEmpty()) { + desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select <b>stroked path(s)</b> to convert stroke to path.")); + return; + } + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + bool scale_stroke = prefs->getBool("/options/transform/stroke", true); + prefs->setBool("/options/transform/stroke", true); + bool did = false; + std::vector<SPItem*> il(selection->items().begin(), selection->items().end()); + for (std::vector<SPItem*>::const_iterator l = il.begin(); l != il.end(); l++){ + SPItem *item = *l; + did = sp_item_path_outline(item, desktop, legacy); + } + prefs->setBool("/options/transform/stroke", scale_stroke); if (did) { DocumentUndo::done(desktop->getDocument(), SP_VERB_SELECTION_OUTLINE, @@ -1521,7 +1689,7 @@ void sp_selected_path_offset(SPDesktop *desktop) { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - double prefOffset = prefs->getDouble("/options/defaultoffsetwidth/value", 1.0, "px"); + double prefOffset = prefs->getDouble("/options/defaultoffsetwidth/value", 1.0, desktop->getDocument()->getDisplayUnit()->abbr); sp_selected_path_do_offset(desktop, true, prefOffset); } @@ -1529,7 +1697,7 @@ void sp_selected_path_inset(SPDesktop *desktop) { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - double prefOffset = prefs->getDouble("/options/defaultoffsetwidth/value", 1.0, "px"); + double prefOffset = prefs->getDouble("/options/defaultoffsetwidth/value", 1.0, desktop->getDocument()->getDisplayUnit()->abbr); sp_selected_path_do_offset(desktop, false, prefOffset); } @@ -1615,7 +1783,7 @@ void sp_selected_path_create_offset_object(SPDesktop *desktop, int expand, bool { { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - o_width = prefs->getDouble("/options/defaultoffsetwidth/value", 1.0, "px"); + o_width = prefs->getDouble("/options/defaultoffsetwidth/value", 1.0, desktop->getDocument()->getDisplayUnit()->abbr); } if (o_width < 0.01){ @@ -1771,7 +1939,7 @@ sp_selected_path_do_offset(SPDesktop *desktop, bool expand, double prefOffset) } bool did = false; - std::vector<SPItem*> il(selection->itemList()); + std::vector<SPItem*> il(selection->items().begin(), selection->items().end()); for (std::vector<SPItem*>::const_iterator l = il.begin(); l != il.end(); l++){ SPItem *item = *l; SPCurve *curve = NULL; @@ -1899,17 +2067,6 @@ sp_selected_path_do_offset(SPDesktop *desktop, bool expand, double prefOffset) res->Reset(); theRes->ConvertToForme(res); - if (o_width >= 1.0) - { - res->ConvertEvenLines(1.0); - res->Simplify(1.0); - } - else - { - res->ConvertEvenLines(1.0*o_width); - res->Simplify(1.0 * o_width); - } - delete theShape; delete theRes; } @@ -2196,7 +2353,7 @@ sp_selected_path_simplify_selection(SPDesktop *desktop, float threshold, bool ju return; } - std::vector<SPItem*> items(selection->itemList()); + std::vector<SPItem*> items(selection->items().begin(), selection->items().end()); bool didSomething = sp_selected_path_simplify_items(desktop, selection, items, threshold, |
