From 2b4e6c9e057eaa7268b8ba76e76ff3e38c2ed28e Mon Sep 17 00:00:00 2001 From: Josh Andler Date: Tue, 2 Sep 2014 16:51:04 -0700 Subject: Remove more whiteboard related leftovers. (bzr r13543) --- src/document.cpp | 1 - src/ui/CMakeLists.txt | 4 ---- 2 files changed, 5 deletions(-) (limited to 'src') diff --git a/src/document.cpp b/src/document.cpp index f79a00178..f94a9f04f 100644 --- a/src/document.cpp +++ b/src/document.cpp @@ -229,7 +229,6 @@ SPDocument::~SPDocument() { // This is at the end of the destructor, because preceding code adds new orphans to the queue collectOrphans(); - //delete this->_whiteboard_session_manager; } sigc::connection SPDocument::connectDestroy(sigc::signal::slot_type slot) diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt index 7d80f1e36..2b9dd6e45 100644 --- a/src/ui/CMakeLists.txt +++ b/src/ui/CMakeLists.txt @@ -89,7 +89,6 @@ set(ui_SRC dialog/print.cpp dialog/symbols.cpp dialog/xml-tree.cpp - # dialog/session-player.cpp dialog/spellcheck.cpp dialog/svg-fonts-dialog.cpp dialog/swatches.cpp @@ -101,9 +100,6 @@ set(ui_SRC dialog/pixelartdialog.cpp dialog/transformation.cpp dialog/undo-history.cpp - # dialog/whiteboard-connect.cpp - # dialog/whiteboard-sharewithchat.cpp - # dialog/whiteboard-sharewithuser.cpp widget/anchor-selector.cpp widget/button.cpp -- cgit v1.2.3 From 018c346b862ccd7dafcbf0e35b757735446821f7 Mon Sep 17 00:00:00 2001 From: mathog <> Date: Thu, 4 Sep 2014 13:50:55 -0700 Subject: resolves bug 1348417 and implements addition features for bug 1302857 (bzr r13544) --- src/extension/internal/emf-inout.cpp | 29 ++++- src/extension/internal/emf-inout.h | 3 +- src/extension/internal/emf-print.cpp | 187 ++++++++++++++++++++++++++++---- src/extension/internal/emf-print.h | 4 + src/extension/internal/metafile-print.h | 2 + src/extension/internal/wmf-inout.cpp | 4 +- src/extension/internal/wmf-inout.h | 2 +- src/sp-item-group.cpp | 20 +++- 8 files changed, 218 insertions(+), 33 deletions(-) (limited to 'src') diff --git a/src/extension/internal/emf-inout.cpp b/src/extension/internal/emf-inout.cpp index 084fbcd58..ee5e76969 100644 --- a/src/extension/internal/emf-inout.cpp +++ b/src/extension/internal/emf-inout.cpp @@ -63,6 +63,7 @@ namespace Internal { static uint32_t ICMmode = 0; // not used yet, but code to read it from EMF implemented static uint32_t BLTmode = 0; +float faraway = 10000000; // used in "exclude" clips, hopefully well outside any real drawing! Emf::Emf (void) // The null constructor { @@ -1040,13 +1041,30 @@ Emf::pix_to_abs_size(PEMF_CALLBACK_DATA d, double px) return ppx; } -/* returns "x,y" (without the quotes) in inkscape coordinates for a pair of EMF x,y coordinates +/* snaps coordinate pairs made up of values near +/-faraway, +/-faraway to exactly faraway. + This eliminates coordinate drift on repeated clipping cycles which use exclude. + It should not affect internals of normal drawings because the value of faraway is so large. +*/ +void +Emf::snap_to_faraway_pair(double *x, double *y) +{ + if((abs(abs(*x) - faraway)/faraway <= 1e-4) && (abs(abs(*y) - faraway)/faraway <= 1e-4)){ + *x = (*x > 0 ? faraway : -faraway); + *y = (*y > 0 ? faraway : -faraway); + } +} + +/* returns "x,y" (without the quotes) in inkscape coordinates for a pair of EMF x,y coordinates. + Since exclude clip can go through here, it calls snap_to_faraway_pair for numerical stability. */ std::string Emf::pix_to_xy(PEMF_CALLBACK_DATA d, double x, double y){ std::stringstream cxform; - cxform << pix_to_x_point(d,x,y); + double tx = pix_to_x_point(d,x,y); + double ty = pix_to_y_point(d,x,y); + snap_to_faraway_pair(&tx,&ty); + cxform << tx; cxform << ","; - cxform << pix_to_y_point(d,x,y); + cxform << ty; return(cxform.str()); } @@ -2221,7 +2239,6 @@ std::cout << "BEFORE DRAW" U_RECTL rc = pEmr->rclClip; SVGOStringStream tmp_path; - float faraway = 10000000; // hopefully well outside any real drawing! //outer rect, clockwise tmp_path << "M " << faraway << "," << faraway << " "; tmp_path << "L " << faraway << "," << -faraway << " "; @@ -3466,6 +3483,8 @@ Emf::open( Inkscape::Extension::Input * /*mod*/, const gchar *uri ) return NULL; } + d.dc[0].font_name = strdup("Arial"); // Default font, set only on lowest level, it copies up from there EMF spec says device can pick whatever it wants + // set up the size default for patterns in defs. This might not be referenced if there are no patterns defined in the drawing. d.defs += "\n"; @@ -3513,7 +3532,7 @@ Emf::open( Inkscape::Extension::Input * /*mod*/, const gchar *uri ) d.dc[0].style.stroke_dasharray.values.clear(); - for(int i=0; i<=d.level;i++){ + for(int i=0; i<=EMF_MAX_DC; i++){ if(d.dc[i].font_name)free(d.dc[i].font_name); } diff --git a/src/extension/internal/emf-inout.h b/src/extension/internal/emf-inout.h index 302d5c474..c64299093 100644 --- a/src/extension/internal/emf-inout.h +++ b/src/extension/internal/emf-inout.h @@ -65,7 +65,7 @@ typedef struct emf_device_context { textAlign(0) // worldTransform, cur { - font_name = strdup("Arial"); // Default font, EMF spec says device can pick whatever it wants + font_name = NULL; sizeWnd = sizel_set( 0.0, 0.0 ); sizeView = sizel_set( 0.0, 0.0 ); winorg = point32_set( 0.0, 0.0 ); @@ -218,6 +218,7 @@ protected: static double pix_to_x_point(PEMF_CALLBACK_DATA d, double px, double py); static double pix_to_y_point(PEMF_CALLBACK_DATA d, double px, double py); static double pix_to_abs_size(PEMF_CALLBACK_DATA d, double px); + static void snap_to_faraway_pair(double *x, double *y); static std::string pix_to_xy(PEMF_CALLBACK_DATA d, double x, double y); static void select_pen(PEMF_CALLBACK_DATA d, int index); static void select_extpen(PEMF_CALLBACK_DATA d, int index); diff --git a/src/extension/internal/emf-print.cpp b/src/extension/internal/emf-print.cpp index e054829b5..0f43fbca1 100644 --- a/src/extension/internal/emf-print.cpp +++ b/src/extension/internal/emf-print.cpp @@ -55,6 +55,7 @@ #include "sp-radial-gradient.h" #include "sp-linear-gradient.h" #include "display/cairo-utils.h" +#include "sp-shape.h" #include "splivarot.h" // pieces for union on shapes #include "2geom/svg-path-parser.h" // to get from SVG text to Geom::Path @@ -143,6 +144,7 @@ unsigned int PrintEmf::begin(Inkscape::Extension::Print *mod, SPDocument *doc) // width and height in px _width = doc->getWidth().value("px"); _height = doc->getHeight().value("px"); + _doc_unit_scale = Inkscape::Util::Quantity::convert(1, (doc->getDefaultUnit()), "px"); // initialize a few global variables hbrush = hbrushOld = hpen = 0; @@ -298,6 +300,7 @@ unsigned int PrintEmf::begin(Inkscape::Extension::Print *mod, SPDocument *doc) unsigned int PrintEmf::finish(Inkscape::Extension::Print * /*mod*/) { + do_clip_if_present(NULL); // Terminate any open clip. char *rec; if (!et) { return 0; @@ -969,19 +972,145 @@ U_TRIVERTEX PrintEmf::make_trivertex(Geom::Point Pt, U_COLORREF uc){ return(tv); } +/* Examine clip. If there is a (new) one then apply it. If there is one and it is the + same as the preceding one, leave the preceding one active. If style is NULL + terminate the current clip, if any, and return. +*/ +void PrintEmf::do_clip_if_present(SPStyle const *style){ + char *rec; + static SPClipPath *scpActive = NULL; + if(!style){ + if(scpActive){ // clear the existing clip + rec = U_EMRRESTOREDC_set(-1); + if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { + g_error("Fatal programming error in PrintEmf::fill at U_EMRRESTOREDC_set"); + } + scpActive=NULL; + } + } else { + /* The current implementation converts only one level of clipping. If there were more + clips further up the stack they should be combined with the pathvector using "and". Since this + comes up rarely, and would involve a lot of searching (all the way up the stack for every + draw operation), it has not yet been implemented. + + Note, to debug this section of code use print statements on sp_svg_write_path(combined_pathvector). + */ + /* find the first clip_ref at object or up the stack. There may not be one. */ + SPClipPath *scp = NULL; + SPItem *item = SP_ITEM(style->object); + while(1) { + scp = (item->clip_ref ? item->clip_ref->getObject() : NULL); + if(scp)break; + item = SP_ITEM(item->parent); + if(!item || SP_IS_ROOT(item))break; // this will never be a clipping path + } + + if(scp != scpActive){ // change or remove the clipping + if(scpActive){ // clear the existing clip + rec = U_EMRRESTOREDC_set(-1); + if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { + g_error("Fatal programming error in PrintEmf::fill at U_EMRRESTOREDC_set"); + } + scpActive = NULL; + } + + if (scp) { // set the new clip + /* because of units and who knows what other transforms that might be applied above we + need the full transform all the way to the root. + */ + Geom::Affine tf = item->transform; + SPItem *scan_item = item; + while(1) { + scan_item = SP_ITEM(scan_item->parent); + if(!scan_item)break; + tf *= scan_item->transform; + } + tf *= Geom::Scale(_doc_unit_scale);; // Transform must be in PIXELS, no matter what the document unit is. + + /* find the clipping path */ + Geom::PathVector combined_pathvector; + Geom::Affine tfc; // clipping transform, generally not the same as item transform + for(item = SP_ITEM(scp->firstChild()); item; item=SP_ITEM(item->getNext())){ + if (SP_IS_GROUP(item)) { // not implemented + // return sp_group_render(item); + combined_pathvector = merge_PathVector_with_group(combined_pathvector, item, tfc); + } else if (SP_IS_SHAPE(item)) { + combined_pathvector = merge_PathVector_with_shape(combined_pathvector, item, tfc); + } else { // not implemented + } + } + + if (!combined_pathvector.empty()) { // if clipping path isn't empty, define EMF clipping record + scpActive = scp; // remember for next time + // the sole purpose of this SAVEDC is to let us clear the clipping region later. + rec = U_EMRSAVEDC_set(); + if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { + g_error("Fatal programming error in PrintEmf::image at U_EMRSAVEDC_set"); + } + (void) draw_pathv_to_EMF(combined_pathvector, tf); + rec = U_EMRSELECTCLIPPATH_set(U_RGN_OR); + if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { + g_error("Fatal programming error in PrintEmf::do_clip_if_present at U_EMRSELECTCLIPPATH_set"); + } + } + else { + scpActive = NULL; // no valid path available to draw, so no DC was saved, so no signal to restore + } + } // change or remove clipping + } // scp exists + } // style exists +} + +Geom::PathVector PrintEmf::merge_PathVector_with_group(Geom::PathVector const &combined_pathvector, SPItem const *item, const Geom::Affine &transform) +{ + Geom::PathVector new_combined_pathvector; + if(!SP_IS_GROUP(item))return(new_combined_pathvector); // sanity test, only a group should be passed in, return empty if something else happens + + new_combined_pathvector = combined_pathvector; + SPGroup *group = SP_GROUP(item); + Geom::Affine tfc = item->transform * transform; + for(SPItem *item = SP_ITEM(group->firstChild()); item; item=SP_ITEM(item->getNext())){ + if (SP_IS_GROUP(item)) { + new_combined_pathvector = merge_PathVector_with_group(new_combined_pathvector, item, tfc); // could be endlessly recursive on a badly formed SVG + } else if (SP_IS_SHAPE(item)) { + new_combined_pathvector = merge_PathVector_with_shape(new_combined_pathvector, item, tfc); + } else { // not implemented + } + } + return new_combined_pathvector; +} + +Geom::PathVector PrintEmf::merge_PathVector_with_shape(Geom::PathVector const &combined_pathvector, SPItem const *item, const Geom::Affine &transform) +{ + Geom::PathVector new_combined_pathvector; + if(!SP_IS_SHAPE(item))return(new_combined_pathvector); // sanity test, only a shape should be passed in, return empty if something else happens + + Geom::Affine tfc = item->transform * transform; + SPShape *shape = SP_SHAPE(item); + if (shape->_curve) { + Geom::PathVector const & new_vect = shape->_curve->get_pathvector(); + if(combined_pathvector.empty()){ + new_combined_pathvector = new_vect * tfc; + } + else { + new_combined_pathvector = sp_pathvector_boolop(new_vect * tfc, combined_pathvector, bool_op_union , (FillRule) fill_oddEven, (FillRule) fill_oddEven); + } + } + return new_combined_pathvector; +} + unsigned int PrintEmf::fill( Inkscape::Extension::Print * /*mod*/, Geom::PathVector const &pathv, Geom::Affine const & /*transform*/, SPStyle const *style, Geom::OptRect const &/*pbox*/, Geom::OptRect const &/*dbox*/, Geom::OptRect const &/*bbox*/) { + char *rec; using Geom::X; using Geom::Y; - - //SPItem *item = SP_ITEM(style->object); - //SPClipPath *scp = (item->clip_ref ? item->clip_ref->getObject() : NULL); - Geom::Affine tf = m_tr_stack.top(); + do_clip_if_present(style); // If clipping is needed set it up + use_fill = true; use_stroke = false; @@ -1095,7 +1224,6 @@ unsigned int PrintEmf::fill( } } else if (gv.mode == DRAW_LINEAR_GRADIENT) { if(is_Rect){ - char *rec; int gMode; Geom::Point ul, ur, lr; Geom::Point outUL, outLR; // UL,LR corners of a stop rectangle, in OUTPUT coordinates @@ -1284,6 +1412,7 @@ unsigned int PrintEmf::stroke( char *rec = NULL; Geom::Affine tf = m_tr_stack.top(); + do_clip_if_present(style); // If clipping is needed set it up use_stroke = true; // use_fill was set in ::fill, if it is needed @@ -1568,12 +1697,14 @@ unsigned int PrintEmf::image( unsigned int h, /** height of bitmap */ unsigned int rs, /** row stride (normally w*4) */ Geom::Affine const &tf_rect, /** affine transform only used for defining location and size of rect, for all other tranforms, use the one from m_tr_stack */ - SPStyle const * /*style*/) /** provides indirect link to image object */ + SPStyle const *style) /** provides indirect link to image object */ { double x1, y1, dw, dh; char *rec = NULL; Geom::Affine tf = m_tr_stack.top(); + do_clip_if_present(style); // If clipping is needed set it up + rec = U_EMRSETSTRETCHBLTMODE_set(U_COLORONCOLOR); if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { g_error("Fatal programming error in PrintEmf::image at EMRHEADER"); @@ -1658,28 +1789,14 @@ unsigned int PrintEmf::image( return 0; } -// may also be called with a simple_shape or an empty path, whereupon it just returns without doing anything -unsigned int PrintEmf::print_pathv(Geom::PathVector const &pathv, const Geom::Affine &transform) -{ - Geom::Affine tf = transform; - char *rec = NULL; - - simple_shape = print_simple_shape(pathv, tf); - if (simple_shape || pathv.empty()) { - if (use_fill) { - destroy_brush(); // these must be cleared even if nothing is drawn or hbrush,hpen fill up - } - if (use_stroke) { - destroy_pen(); - } - return TRUE; - } +unsigned int PrintEmf::draw_pathv_to_EMF(Geom::PathVector const &pathv, const Geom::Affine &transform) { + char *rec; /* inkscape to EMF scaling is done below, but NOT the rotation/translation transform, that is handled by the EMF MODIFYWORLDTRANSFORM record */ - - Geom::PathVector pv = pathv_to_linear_and_cubic_beziers(pathv * tf); + + Geom::PathVector pv = pathv_to_linear_and_cubic_beziers(pathv * transform); rec = U_EMRBEGINPATH_set(); if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { @@ -1781,6 +1898,27 @@ unsigned int PrintEmf::print_pathv(Geom::PathVector const &pathv, const Geom::Af if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { g_error("Fatal programming error in PrintEmf::print_pathv at U_EMRENDPATH_set"); } + return(0); +} + +// may also be called with a simple_shape or an empty path, whereupon it just returns without doing anything +unsigned int PrintEmf::print_pathv(Geom::PathVector const &pathv, const Geom::Affine &transform) +{ + Geom::Affine tf = transform; + char *rec = NULL; + + simple_shape = print_simple_shape(pathv, tf); + if (simple_shape || pathv.empty()) { + if (use_fill) { + destroy_brush(); // these must be cleared even if nothing is drawn or hbrush,hpen fill up + } + if (use_stroke) { + destroy_pen(); + } + return TRUE; + } + + (void) draw_pathv_to_EMF(pathv, tf); // explicit FILL/STROKE commands are needed for each sub section of the path if (use_fill && !use_stroke) { @@ -1819,6 +1957,7 @@ unsigned int PrintEmf::text(Inkscape::Extension::Print * /*mod*/, char const *te return 0; } + do_clip_if_present(style); // If clipping is needed set it up char *rec = NULL; int ccount, newfont; int fix90n = 0; diff --git a/src/extension/internal/emf-print.h b/src/extension/internal/emf-print.h index 9a1251b38..5bad48de5 100644 --- a/src/extension/internal/emf-print.h +++ b/src/extension/internal/emf-print.h @@ -69,6 +69,10 @@ public: protected: static void smuggle_adxkyrtl_out(const char *string, uint32_t **adx, double *ky, int *rtl, int *ndx, float scale); + void do_clip_if_present(SPStyle const *style); + Geom::PathVector merge_PathVector_with_group(Geom::PathVector const &combined_pathvector, SPItem const *item, const Geom::Affine &transform); + Geom::PathVector merge_PathVector_with_shape(Geom::PathVector const &combined_pathvector, SPItem const *item, const Geom::Affine &transform); + unsigned int draw_pathv_to_EMF(Geom::PathVector const &pathv, const Geom::Affine &transform); Geom::Path pathv_to_simple_polygon(Geom::PathVector const &pathv, int *vertices); Geom::Path pathv_to_rect(Geom::PathVector const &pathv, bool *is_rect, double *angle); Geom::Point get_pathrect_corner(Geom::Path pathRect, double angle, int corner); diff --git a/src/extension/internal/metafile-print.h b/src/extension/internal/metafile-print.h index a21f9de58..d184b72b7 100644 --- a/src/extension/internal/metafile-print.h +++ b/src/extension/internal/metafile-print.h @@ -69,6 +69,8 @@ protected: double _width; double _height; + double _doc_unit_scale; // to pixels, regardless of the document units + U_RECTL rc; uint32_t htextalignment; diff --git a/src/extension/internal/wmf-inout.cpp b/src/extension/internal/wmf-inout.cpp index 5ccad678a..44d73ee8d 100644 --- a/src/extension/internal/wmf-inout.cpp +++ b/src/extension/internal/wmf-inout.cpp @@ -3062,6 +3062,8 @@ Wmf::open( Inkscape::Extension::Input * /*mod*/, const gchar *uri ) return NULL; } + d.dc[0].font_name = strdup("Arial"); // Default font, set only on lowest level, it copies up from there WMF spec says device can pick whatever it wants + // set up the size default for patterns in defs. This might not be referenced if there are no patterns defined in the drawing. d.defs += "\n"; @@ -3104,7 +3106,7 @@ Wmf::open( Inkscape::Extension::Input * /*mod*/, const gchar *uri ) d.dc[0].style.stroke_dasharray.values.clear(); - for(int i=0; i<=d.level;i++){ + for(int i=0; i<=WMF_MAX_DC; i++){ if(d.dc[i].font_name)free(d.dc[i].font_name); } diff --git a/src/extension/internal/wmf-inout.h b/src/extension/internal/wmf-inout.h index 27ec14358..5a0a760dd 100644 --- a/src/extension/internal/wmf-inout.h +++ b/src/extension/internal/wmf-inout.h @@ -65,7 +65,7 @@ typedef struct wmf_device_context { textAlign(0) // worldTransform, cur { - font_name = strdup("Arial"); // Default font, WMF spec says device can pick whatever it wants + font_name = NULL; sizeWnd = point16_set( 0.0, 0.0 ); sizeView = point16_set( 0.0, 0.0 ); winorg = point16_set( 0.0, 0.0 ); diff --git a/src/sp-item-group.cpp b/src/sp-item-group.cpp index bb52b0c55..3d03edd85 100644 --- a/src/sp-item-group.cpp +++ b/src/sp-item-group.cpp @@ -651,7 +651,25 @@ void SPGroup::scaleChildItemsRec(Geom::Scale const &sc, Geom::Point const &p) for (SPObject *o = firstChild() ; o ; o = o->getNext() ) { if ( SP_IS_ITEM(o) ) { if (SP_IS_GROUP(o) && !SP_IS_BOX3D(o)) { - SP_GROUP(o)->scaleChildItemsRec(sc, p); + // Doing it this way breaks clipping because transforms are applied + // in coordinates for draws but nothing in defs is changed + // SP_GROUP(o)->scaleChildItemsRec(sc, p); + // instead change the transform on the entire group, and the transform + // is applied after any references to clipping paths. + SPItem *item = SP_ITEM(o); + Geom::Translate const s(p); + Geom::Affine final = s.inverse() * sc * s; + Geom::Affine tAff = item->i2dt_affine() * final; + item->set_i2d_affine(tAff); + tAff = item->transform; + // Eliminate common rounding error affecting EMF/WMF input. + // When the rounding error persists it converts the simple + // transform=scale() to transform=matrix(). + if(std::abs(tAff[4]) < 1.0e-5 && std::abs(tAff[5]) < 1.0e-5){ + tAff[4] = 0.0; + tAff[5] = 0.0; + } + item->doWriteTransform(item->getRepr(), tAff, NULL, true); } else { SPItem *item = SP_ITEM(o); Geom::OptRect bbox = item->desktopVisualBounds(); -- cgit v1.2.3 From d685d3f417cbecaf96e2acb55918283f36f21cd3 Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Fri, 5 Sep 2014 00:02:09 +0200 Subject: LPE Powerstroke: add Centripetal Catmull-Rom interpolator (bzr r13545) --- src/live_effects/lpe-powerstroke-interpolators.h | 90 +++++++++++++++++++++++- src/live_effects/lpe-powerstroke.cpp | 3 +- 2 files changed, 91 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/live_effects/lpe-powerstroke-interpolators.h b/src/live_effects/lpe-powerstroke-interpolators.h index 6f5b75af8..ee4951882 100644 --- a/src/live_effects/lpe-powerstroke-interpolators.h +++ b/src/live_effects/lpe-powerstroke-interpolators.h @@ -27,7 +27,8 @@ enum InterpolatorType { INTERP_LINEAR, INTERP_CUBICBEZIER, INTERP_CUBICBEZIER_JOHAN, - INTERP_SPIRO + INTERP_SPIRO, + INTERP_CENTRIPETAL_CATMULLROM }; class Interpolator { @@ -167,6 +168,91 @@ private: SpiroInterpolator& operator=(const SpiroInterpolator&); }; +class CentripetalCatmullRomInterpolator : public Interpolator { +// the code in this class can certainly be optimized and made more terse, feel free +public: + CentripetalCatmullRomInterpolator() {}; + virtual ~CentripetalCatmullRomInterpolator() {}; + + virtual Path interpolateToPath(std::vector const &points) const { + unsigned int n_points = points.size(); + + Geom::Path fit(points.front()); + + if (n_points < 2) return fit; + if (n_points < 3) { + // if only 2 points, return linear segment + fit.appendNew(points[1]); + return fit; + } + + // return n_points-1 cubic segments + + // duplicate first point + fit.append(calc_bezier(points[0],points[0],points[1],points[2])); + + for (std::size_t i = 0; i < n_points-2; ++i) { + Point p0 = points[i]; + Point p1 = points[i+1]; + Point p2 = points[i+2]; + Point p3 = (i < n_points-3) ? points[i+3] : points[i+2]; + + fit.append(calc_bezier(p0, p1, p2, p3)); + // this is quite wasteful: the distances between the same points are repeatedly calculated by calc_bezier + } + + return fit; + }; + +private: + CubicBezier calc_bezier(Point p0, Point p1, Point p2, Point p3) const { + // create interpolating bezier between p1 and p2 + + // Part of the code comes from StackOverflow user eriatarka84 + // http://stackoverflow.com/a/23980479/2929337 + + // calculate time coords (deltas) of points + // the factor 0.25 can be generalized for other Catmull-Rom interpolation types + // see alpha in Yuksel et al. "On the Parameterization of Catmull-Rom Curves", + // --> http://www.cemyuksel.com/research/catmullrom_param/catmullrom.pdf + double dt0 = powf(distanceSq(p0, p1), 0.25); + double dt1 = powf(distanceSq(p1, p2), 0.25); + double dt2 = powf(distanceSq(p2, p3), 0.25); + + + // safety check for repeated points + double eps = Geom::EPSILON; + if (dt1 < eps) + dt1 = 1.0; + if (dt0 < eps) + dt0 = dt1; + if (dt2 < eps) + dt2 = dt1; + + // compute tangents when parameterized in [t1,t2] + Point tan1 = (p1 - p0) / dt0 - (p2 - p0) / (dt0 + dt1) + (p2 - p1) / dt1; + Point tan2 = (p2 - p1) / dt1 - (p3 - p1) / (dt1 + dt2) + (p3 - p2) / dt2; + // rescale tangents for parametrization in [0,1] + tan1 *= dt1; + tan2 *= dt1; + + // create bezier from tangents (this is already in 2geom somewhere, or should be moved to it) + // the tangent of a bezier curve is: B'(t) = 3(1-t)^2 (b1 - b0) + 6(1-t)t(b2-b1) + 3t^2(b3-b2) + // So we have to make sure that B'(0) = tan1 and B'(1) = tan2, and we already know that b0=p1 and b3=p2 + // tan1 = B'(0) = 3 (b1 - p1) --> p1 + (tan1)/3 = b1 + // tan2 = B'(1) = 3 (p2 - b2) --> p2 - (tan2)/3 = b2 + + Point b0 = p1; + Point b1 = p1 + tan1 / 3; + Point b2 = p2 - tan2 / 3; + Point b3 = p2; + + return CubicBezier(b0, b1, b2, b3); + } + + CentripetalCatmullRomInterpolator(const CentripetalCatmullRomInterpolator&); + CentripetalCatmullRomInterpolator& operator=(const CentripetalCatmullRomInterpolator&); +}; Interpolator* Interpolator::create(InterpolatorType type) { @@ -179,6 +265,8 @@ Interpolator::create(InterpolatorType type) { return new Geom::Interpolate::CubicBezierJohan(); case INTERP_SPIRO: return new Geom::Interpolate::SpiroInterpolator(); + case INTERP_CENTRIPETAL_CATMULLROM: + return new Geom::Interpolate::CentripetalCatmullRomInterpolator(); default: return new Geom::Interpolate::Linear(); } diff --git a/src/live_effects/lpe-powerstroke.cpp b/src/live_effects/lpe-powerstroke.cpp index 90b01aaa4..eed564b20 100644 --- a/src/live_effects/lpe-powerstroke.cpp +++ b/src/live_effects/lpe-powerstroke.cpp @@ -188,7 +188,8 @@ static const Util::EnumData InterpolatorTypeData[] = { {Geom::Interpolate::INTERP_LINEAR , N_("Linear"), "Linear"}, {Geom::Interpolate::INTERP_CUBICBEZIER , N_("CubicBezierFit"), "CubicBezierFit"}, {Geom::Interpolate::INTERP_CUBICBEZIER_JOHAN , N_("CubicBezierJohan"), "CubicBezierJohan"}, - {Geom::Interpolate::INTERP_SPIRO , N_("SpiroInterpolator"), "SpiroInterpolator"} + {Geom::Interpolate::INTERP_SPIRO , N_("SpiroInterpolator"), "SpiroInterpolator"}, + {Geom::Interpolate::INTERP_CENTRIPETAL_CATMULLROM , N_("Centripetal Catmull-Rom"), "CentripetalCatmullRom"} }; static const Util::EnumDataConverter InterpolatorTypeConverter(InterpolatorTypeData, sizeof(InterpolatorTypeData)/sizeof(*InterpolatorTypeData)); -- cgit v1.2.3 From e043dcd131751f2a0d29068f178fc008dc8c73d7 Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Fri, 5 Sep 2014 20:30:18 +0200 Subject: LPE Powerstroke: enable Extrapolated arc, remove Extrapolated (mirroring) The code to deal with Extrapolated mirroring is still working (if someone has an old file with that type of extrapolation), but perhaps that should also be removed. (bzr r13546) --- src/live_effects/lpe-powerstroke.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/live_effects/lpe-powerstroke.cpp b/src/live_effects/lpe-powerstroke.cpp index eed564b20..b8657e165 100644 --- a/src/live_effects/lpe-powerstroke.cpp +++ b/src/live_effects/lpe-powerstroke.cpp @@ -220,12 +220,10 @@ enum LineJoinType { static const Util::EnumData LineJoinTypeData[] = { {LINEJOIN_BEVEL, N_("Beveled"), "bevel"}, {LINEJOIN_ROUND, N_("Rounded"), "round"}, - {LINEJOIN_EXTRP_MITER, N_("Extrapolated"), "extrapolated"}, +// {LINEJOIN_EXTRP_MITER, N_("Extrapolated"), "extrapolated"}, // disabled because doesn't work well + {LINEJOIN_EXTRP_MITER_ARC, N_("Extrapolated arc"), "extrp_arc"}, {LINEJOIN_MITER, N_("Miter"), "miter"}, {LINEJOIN_SPIRO, N_("Spiro"), "spiro"}, -#ifdef LPE_ENABLE_TEST_EFFECTS - {LINEJOIN_EXTRP_MITER_ARC, N_("Extrapolated arc"), "extrp_arc"}, -#endif }; static const Util::EnumDataConverter LineJoinTypeConverter(LineJoinTypeData, sizeof(LineJoinTypeData)/sizeof(*LineJoinTypeData)); @@ -407,8 +405,9 @@ static Geom::Path path_from_piecewise_fix_cusps( Geom::Piecewise Date: Sun, 7 Sep 2014 12:39:35 -0400 Subject: prevent multiple simultaneous updates during undo (Bug 1348382) Fixed bugs: - https://launchpad.net/bugs/1348382 (bzr r13547) --- src/widgets/node-toolbar.cpp | 2 +- src/widgets/rect-toolbar.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/widgets/node-toolbar.cpp b/src/widgets/node-toolbar.cpp index 53161857a..39e0a9be0 100644 --- a/src/widgets/node-toolbar.cpp +++ b/src/widgets/node-toolbar.cpp @@ -270,7 +270,7 @@ static void sp_node_path_value_changed(GtkAdjustment *adj, GObject *tbl, Geom::D } // quit if run by the attr_changed listener - if (g_object_get_data( tbl, "freeze" )) { + if (g_object_get_data( tbl, "freeze" ) || tracker->isUpdating()) { return; } diff --git a/src/widgets/rect-toolbar.cpp b/src/widgets/rect-toolbar.cpp index 6996786e3..908e6cc78 100644 --- a/src/widgets/rect-toolbar.cpp +++ b/src/widgets/rect-toolbar.cpp @@ -95,7 +95,7 @@ static void sp_rtb_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const * } // quit if run by the attr_changed listener - if (g_object_get_data( tbl, "freeze" )) { + if (g_object_get_data( tbl, "freeze" ) || tracker->isUpdating()) { return; } -- cgit v1.2.3 From 71c3b0398381d4bace1427bbda11f486fcbcc307 Mon Sep 17 00:00:00 2001 From: mathog <> Date: Mon, 8 Sep 2014 10:13:03 -0700 Subject: partial rollback of r13544, allow old recursive behavior for some locations, but not EMF import (bzr r13549) --- src/extension/internal/metafile-inout.cpp | 2 +- src/sp-item-group.cpp | 49 ++++++++++++++++++------------- src/sp-item-group.h | 2 +- src/ui/dialog/document-properties.cpp | 3 +- 4 files changed, 33 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/extension/internal/metafile-inout.cpp b/src/extension/internal/metafile-inout.cpp index 162ad8b7d..28e9932b3 100644 --- a/src/extension/internal/metafile-inout.cpp +++ b/src/extension/internal/metafile-inout.cpp @@ -222,7 +222,7 @@ void Metafile::setViewBoxIfMissing(SPDocument *doc) { prefs->setBool("/options/transform/pattern", true); prefs->setBool("/options/transform/gradient", true); - doc->getRoot()->scaleChildItemsRec(Geom::Scale(scale), Geom::Point(0, dh)); + doc->getRoot()->scaleChildItemsRec(Geom::Scale(scale), Geom::Point(0, dh), true); ShapeEditor::blockSetItem(false); // restore options diff --git a/src/sp-item-group.cpp b/src/sp-item-group.cpp index 3d03edd85..5936cfbe5 100644 --- a/src/sp-item-group.cpp +++ b/src/sp-item-group.cpp @@ -644,32 +644,41 @@ void SPGroup::translateChildItems(Geom::Translate const &tr) } } -// Recursively scale child items around a point -void SPGroup::scaleChildItemsRec(Geom::Scale const &sc, Geom::Point const &p) +// Recursively (or not) scale child items around a point +void SPGroup::scaleChildItemsRec(Geom::Scale const &sc, Geom::Point const &p, bool noRecurse) { if ( hasChildren() ) { for (SPObject *o = firstChild() ; o ; o = o->getNext() ) { if ( SP_IS_ITEM(o) ) { if (SP_IS_GROUP(o) && !SP_IS_BOX3D(o)) { - // Doing it this way breaks clipping because transforms are applied - // in coordinates for draws but nothing in defs is changed - // SP_GROUP(o)->scaleChildItemsRec(sc, p); - // instead change the transform on the entire group, and the transform - // is applied after any references to clipping paths. - SPItem *item = SP_ITEM(o); - Geom::Translate const s(p); - Geom::Affine final = s.inverse() * sc * s; - Geom::Affine tAff = item->i2dt_affine() * final; - item->set_i2d_affine(tAff); - tAff = item->transform; - // Eliminate common rounding error affecting EMF/WMF input. - // When the rounding error persists it converts the simple - // transform=scale() to transform=matrix(). - if(std::abs(tAff[4]) < 1.0e-5 && std::abs(tAff[5]) < 1.0e-5){ - tAff[4] = 0.0; - tAff[5] = 0.0; + /* Using recursion breaks clipping because transforms are applied + in coordinates for draws but nothing in defs is changed + instead change the transform on the entire group, and the transform + is applied after any references to clipping paths. However NOT using + recursion apparently breaks as of r13544 other parts of Inkscape + involved with showing/modifying units. So offer both for use + in different contexts. + */ + if(noRecurse) { + // used for EMF import + SPItem *item = SP_ITEM(o); + Geom::Translate const s(p); + Geom::Affine final = s.inverse() * sc * s; + Geom::Affine tAff = item->i2dt_affine() * final; + item->set_i2d_affine(tAff); + tAff = item->transform; + // Eliminate common rounding error affecting EMF/WMF input. + // When the rounding error persists it converts the simple + // transform=scale() to transform=matrix(). + if(std::abs(tAff[4]) < 1.0e-5 && std::abs(tAff[5]) < 1.0e-5){ + tAff[4] = 0.0; + tAff[5] = 0.0; + } + item->doWriteTransform(item->getRepr(), tAff, NULL, true); + } else { + // used for other import + SP_GROUP(o)->scaleChildItemsRec(sc, p, false); } - item->doWriteTransform(item->getRepr(), tAff, NULL, true); } else { SPItem *item = SP_ITEM(o); Geom::OptRect bbox = item->desktopVisualBounds(); diff --git a/src/sp-item-group.h b/src/sp-item-group.h index 2004a72b8..dd1e9317a 100644 --- a/src/sp-item-group.h +++ b/src/sp-item-group.h @@ -52,7 +52,7 @@ public: LayerMode layerDisplayMode(unsigned int display_key) const; void setLayerDisplayMode(unsigned int display_key, LayerMode mode); void translateChildItems(Geom::Translate const &tr); - void scaleChildItemsRec(Geom::Scale const &sc, Geom::Point const &p); + void scaleChildItemsRec(Geom::Scale const &sc, Geom::Point const &p, bool noRecurse); gint getItemCount() const; virtual void _showChildren (Inkscape::Drawing &drawing, Inkscape::DrawingItem *ai, unsigned int key, unsigned int flags); diff --git a/src/ui/dialog/document-properties.cpp b/src/ui/dialog/document-properties.cpp index 2757a0ec9..1f220b246 100644 --- a/src/ui/dialog/document-properties.cpp +++ b/src/ui/dialog/document-properties.cpp @@ -1747,7 +1747,8 @@ void DocumentProperties::onDocUnitChange() doc->getRoot()->scaleChildItemsRec(Geom::Scale(scale), Geom::Point(-viewscale*doc->getRoot()->viewBox.min()[Geom::X] + (doc->getWidth().value("px") - viewscale*doc->getRoot()->viewBox.width())/2, viewscale*doc->getRoot()->viewBox.min()[Geom::Y] + - (doc->getHeight().value("px") + viewscale*doc->getRoot()->viewBox.height())/2)); + (doc->getHeight().value("px") + viewscale*doc->getRoot()->viewBox.height())/2), + false); ShapeEditor::blockSetItem(false); } prefs->setBool("/options/transform/stroke", transform_stroke); -- cgit v1.2.3 From 991f33ed582722d64ae964986570cd20379a4c56 Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Tue, 9 Sep 2014 15:10:27 -0400 Subject: Fix bug #1357411 Fixed bugs: - https://launchpad.net/bugs/1357411 (bzr r13550) --- src/object-snapper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/object-snapper.cpp b/src/object-snapper.cpp index 0f7aa6368..9ff6df3bf 100644 --- a/src/object-snapper.cpp +++ b/src/object-snapper.cpp @@ -677,7 +677,7 @@ void Inkscape::ObjectSnapper::_snapPathsConstrained(IntermSnapResults &isr, (*p_inters) = dt->doc2dt(*p_inters); // Construct a snapped point Geom::Coord dist = Geom::L2(p.getPoint() - *p_inters); - SnappedPoint s = SnappedPoint(*p_inters, p.getSourceType(), p.getSourceNum(), k->target_type, dist, getSnapperTolerance(), getSnapperAlwaysSnap(), true, k->target_bbox);; + SnappedPoint s = SnappedPoint(*p_inters, p.getSourceType(), p.getSourceNum(), k->target_type, dist, getSnapperTolerance(), getSnapperAlwaysSnap(), true, false, k->target_bbox); // Store the snapped point if (dist <= tolerance) { // If the intersection is within snapping range, then we might snap to it isr.points.push_back(s); -- cgit v1.2.3 From 24166b289293a2b706a55f6605f06f436fa1d9bc Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Wed, 10 Sep 2014 15:12:07 -0400 Subject: Fix bug #1367520 (crash regression) Fixed bugs: - https://launchpad.net/bugs/1367520 (bzr r13551) --- src/live_effects/parameter/path.cpp | 2 +- src/live_effects/parameter/text.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/live_effects/parameter/path.cpp b/src/live_effects/parameter/path.cpp index 8095056b7..89947034d 100644 --- a/src/live_effects/parameter/path.cpp +++ b/src/live_effects/parameter/path.cpp @@ -143,7 +143,7 @@ gchar * PathParam::param_getSVGValue() const { if (href) { - return href; + return g_strdup(href); } else { gchar * svgd = sp_svg_write_path( _pathvector ); return svgd; diff --git a/src/live_effects/parameter/text.cpp b/src/live_effects/parameter/text.cpp index fcb2fc9fc..956a001ad 100644 --- a/src/live_effects/parameter/text.cpp +++ b/src/live_effects/parameter/text.cpp @@ -85,7 +85,7 @@ TextParam::param_readSVGValue(const gchar * strvalue) gchar * TextParam::param_getSVGValue() const { - return (gchar *) value.c_str(); + return g_strdup(value.c_str()); } Gtk::Widget * -- cgit v1.2.3 From 1e435432e61ca5794f784e3758d1034aa93cc171 Mon Sep 17 00:00:00 2001 From: Nicolas Dufour Date: Fri, 12 Sep 2014 07:59:27 +0200 Subject: i18n. Fix for Bug #1368375 (Page titles in preferences don't escape text for markup) by houz. Fixed bugs: - https://launchpad.net/bugs/1368375 (bzr r13552) --- src/ui/dialog/inkscape-preferences.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/ui/dialog/inkscape-preferences.cpp b/src/ui/dialog/inkscape-preferences.cpp index 5d065dc60..e04748759 100644 --- a/src/ui/dialog/inkscape-preferences.cpp +++ b/src/ui/dialog/inkscape-preferences.cpp @@ -2054,7 +2054,8 @@ void InkscapePreferences::on_pagelist_selection_changed() if (!_init) { prefs->setInt("/dialogs/preferences/page", row[_page_list_columns._col_id]); } - _page_title.set_markup("" + row[_page_list_columns._col_name] + ""); + Glib::ustring col_name_escaped = Glib::Markup::escape_text( row[_page_list_columns._col_name] ); + _page_title.set_markup("" + col_name_escaped + ""); _page_frame.add(*_current_page); _current_page->show(); while (Gtk::Main::events_pending()) -- cgit v1.2.3 From 3f0ff95e24a6ac528ccd4249eceb7066071bfea4 Mon Sep 17 00:00:00 2001 From: Nicolas Dufour Date: Fri, 12 Sep 2014 20:56:00 +0200 Subject: i18n. Adding context to the "Group" verb (undo history). Translations. Translation template and French translation udpate. (bzr r13554) --- src/selection-chemistry.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/selection-chemistry.cpp b/src/selection-chemistry.cpp index 01ce20509..83ae5a954 100644 --- a/src/selection-chemistry.cpp +++ b/src/selection-chemistry.cpp @@ -762,7 +762,7 @@ void sp_selection_group(Inkscape::Selection *selection, SPDesktop *desktop) sp_selection_group_impl(p, group, xml_doc, doc); DocumentUndo::done(doc, SP_VERB_SELECTION_GROUP, - _("Group")); + C_("Verb", "Group")); selection->set(group); Inkscape::GC::release(group); -- cgit v1.2.3 From e81250edbb1751c3626b01645872f74948081a19 Mon Sep 17 00:00:00 2001 From: su_v Date: Sat, 13 Sep 2014 19:48:17 +0200 Subject: Fix GTK3 build (bzr r13555) --- src/ui/dialog/inkscape-preferences.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/ui/dialog/inkscape-preferences.cpp b/src/ui/dialog/inkscape-preferences.cpp index e04748759..7d43adc0f 100644 --- a/src/ui/dialog/inkscape-preferences.cpp +++ b/src/ui/dialog/inkscape-preferences.cpp @@ -19,6 +19,7 @@ #include "inkscape-preferences.h" #include +#include #include #include #include -- cgit v1.2.3 From 70f0a1b307456191c5f2ce103d3edbf4ca23d514 Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Sun, 14 Sep 2014 16:03:29 -0700 Subject: Always check result of sp_repr_read_mem for NULL In cases where undefined or invalid XML is passed to sp_repr_read_mem(), it will indicate failure by returning NULL. All callers must check for this and handle the error condition accordingly. Fixes: lp: #1170248 Fixed bugs: - https://launchpad.net/bugs/1170248 (bzr r13556) --- src/extension/prefdialog.cpp | 4 ++++ src/extension/system.cpp | 3 ++- src/inkscape.cpp | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/extension/prefdialog.cpp b/src/extension/prefdialog.cpp index d1f83701f..3a384257c 100644 --- a/src/extension/prefdialog.cpp +++ b/src/extension/prefdialog.cpp @@ -90,6 +90,10 @@ PrefDialog::PrefDialog (Glib::ustring name, gchar const * help, Gtk::Widget * co if (_effect != NULL && !_effect->no_live_preview) { if (_param_preview == NULL) { XML::Document * doc = sp_repr_read_mem(live_param_xml, strlen(live_param_xml), NULL); + if (doc == NULL) { + std::cout << "Error encountered loading live parameter XML !!!" << std::endl; + return; + } _param_preview = Parameter::make(doc->root(), _effect); } diff --git a/src/extension/system.cpp b/src/extension/system.cpp index c244d9c16..45feb882f 100644 --- a/src/extension/system.cpp +++ b/src/extension/system.cpp @@ -556,7 +556,7 @@ build_from_file(gchar const *filename) } /** - * \return The module created + * \return The module created, or NULL if buffer is invalid * \brief This function creates a module from a buffer holding an * XML description. * \param buffer The buffer holding the XML description of the module. @@ -568,6 +568,7 @@ Extension * build_from_mem(gchar const *buffer, Implementation::Implementation *in_imp) { Inkscape::XML::Document *doc = sp_repr_read_mem(buffer, strlen(buffer), INKSCAPE_EXTENSION_URI); + g_return_val_if_fail(doc != NULL, NULL); Extension *ext = build_from_reprdoc(doc, in_imp); Inkscape::GC::release(doc); return ext; diff --git a/src/inkscape.cpp b/src/inkscape.cpp index 4b4c8c678..e312e15b9 100644 --- a/src/inkscape.cpp +++ b/src/inkscape.cpp @@ -945,7 +945,7 @@ bool inkscape_load_menus( Inkscape::Application * inkscape ) inkscape->menus = sp_repr_read_mem(menus_skeleton, MENUS_SKELETON_SIZE, NULL); } - return (inkscape->menus != 0); + return (inkscape->menus != NULL); } -- cgit v1.2.3 From dc01e8e42fff68b0fcf56e814cf837110da54d1d Mon Sep 17 00:00:00 2001 From: Bryce Harrington Date: Wed, 17 Sep 2014 21:37:41 -0700 Subject: Fix build for fink on OS X 10.9 by including unistd.h Fixes: https://bugs.launchpad.net/inkscape/+bug/1340914 Fixed bugs: - https://launchpad.net/bugs/1340914 (bzr r13560) --- src/color-profile.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/color-profile.cpp b/src/color-profile.cpp index aa0750c00..6f335b590 100644 --- a/src/color-profile.cpp +++ b/src/color-profile.cpp @@ -19,6 +19,7 @@ #include #endif // DEBUG_LCMS +#include #include #include #include -- cgit v1.2.3 From b91f59f850cf88b2c5a4579cbb4a515189f96b24 Mon Sep 17 00:00:00 2001 From: Alvin Penner Date: Fri, 19 Sep 2014 15:10:08 -0400 Subject: scale clip or mask upon unit change (Bug 1287288) Fixed bugs: - https://launchpad.net/bugs/1287288 (bzr r13561) --- src/sp-item-group.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'src') diff --git a/src/sp-item-group.cpp b/src/sp-item-group.cpp index 5936cfbe5..a24056630 100644 --- a/src/sp-item-group.cpp +++ b/src/sp-item-group.cpp @@ -677,6 +677,18 @@ void SPGroup::scaleChildItemsRec(Geom::Scale const &sc, Geom::Point const &p, bo item->doWriteTransform(item->getRepr(), tAff, NULL, true); } else { // used for other import + SPItem *item = NULL; + if (SP_ITEM(o)->clip_ref->getObject()) { + item = SP_ITEM(SP_ITEM(o)->clip_ref->getObject()->firstChild()); + } else if (SP_ITEM(o)->mask_ref->getObject()) { + item = SP_ITEM(SP_ITEM(o)->mask_ref->getObject()->firstChild()); + } + if (item != NULL) { + Geom::Affine tdoc2dt = Geom::Scale(1, -1) * Geom::Translate(p); // re-create doc2dt() + Geom::Affine ti2doc = SP_ITEM(o)->i2doc_affine(); + item->set_i2d_affine(ti2doc * sc * ti2doc.inverse() * tdoc2dt); + item->doWriteTransform(item->getRepr(), item->transform, NULL, true); + } SP_GROUP(o)->scaleChildItemsRec(sc, p, false); } } else { -- cgit v1.2.3 From 44d5ffff67f726c355a28492a427a55d6e6387fd Mon Sep 17 00:00:00 2001 From: Alvin Penner Date: Fri, 19 Sep 2014 17:47:25 -0400 Subject: improved version of rev 13561, to allow transforming both clip and mask on the same group Fixed bugs: - https://launchpad.net/bugs/1287288 (bzr r13562) --- src/sp-item-group.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/sp-item-group.cpp b/src/sp-item-group.cpp index a24056630..b65be8f22 100644 --- a/src/sp-item-group.cpp +++ b/src/sp-item-group.cpp @@ -680,7 +680,15 @@ void SPGroup::scaleChildItemsRec(Geom::Scale const &sc, Geom::Point const &p, bo SPItem *item = NULL; if (SP_ITEM(o)->clip_ref->getObject()) { item = SP_ITEM(SP_ITEM(o)->clip_ref->getObject()->firstChild()); - } else if (SP_ITEM(o)->mask_ref->getObject()) { + } + if (item != NULL) { + Geom::Affine tdoc2dt = Geom::Scale(1, -1) * Geom::Translate(p); // re-create doc2dt() + Geom::Affine ti2doc = SP_ITEM(o)->i2doc_affine(); + item->set_i2d_affine(ti2doc * sc * ti2doc.inverse() * tdoc2dt); + item->doWriteTransform(item->getRepr(), item->transform, NULL, true); + } + item = NULL; + if (SP_ITEM(o)->mask_ref->getObject()) { item = SP_ITEM(SP_ITEM(o)->mask_ref->getObject()->firstChild()); } if (item != NULL) { -- cgit v1.2.3 From 363a3075b59439f9845412e9bb678ac759794753 Mon Sep 17 00:00:00 2001 From: Nicolas Dufour Date: Tue, 23 Sep 2014 08:43:33 +0200 Subject: Extensions. Fix for Bug #1372200 (Comment within