diff options
| author | Jabier Arraiza Cenoz <jabier.arraiza@marker.es> | 2015-12-08 11:05:08 +0000 |
|---|---|---|
| committer | jabiertxof <jabier.arraiza@marker.es> | 2015-12-08 11:05:08 +0000 |
| commit | d79bd642b3214f1c44d7c1268e8adcb7bd55fffc (patch) | |
| tree | 74a8529da5f23996ba4b358c045a7588f8c27f24 /src | |
| parent | minor changes (diff) | |
| parent | merge lp:~inkscape.dev/inkscape/lock_guides (diff) | |
| download | inkscape-d79bd642b3214f1c44d7c1268e8adcb7bd55fffc.tar.gz inkscape-d79bd642b3214f1c44d7c1268e8adcb7bd55fffc.zip | |
update to trunk
(bzr r14272.1.11)
Diffstat (limited to 'src')
299 files changed, 7788 insertions, 7395 deletions
diff --git a/src/2geom/curve.cpp b/src/2geom/curve.cpp index b45228514..24c8be9f8 100644 --- a/src/2geom/curve.cpp +++ b/src/2geom/curve.cpp @@ -108,7 +108,11 @@ std::vector<CurveIntersection> Curve::intersectSelf(Coord eps) const // Monotonic segments cannot have self-intersections. // Thus, we can split the curve at roots and intersect the portions. std::vector<Coord> splits; +#if __cplusplus <= 199711L std::auto_ptr<Curve> deriv(derivative()); +#else + std::unique_ptr<Curve> deriv(derivative()); +#endif splits = deriv->roots(0, X); if (splits.empty()) { return result; diff --git a/src/2geom/d2-sbasis.cpp b/src/2geom/d2-sbasis.cpp index ebec16fdd..4f00ff6a5 100644 --- a/src/2geom/d2-sbasis.cpp +++ b/src/2geom/d2-sbasis.cpp @@ -147,12 +147,12 @@ Piecewise<D2<SBasis> > force_continuity(Piecewise<D2<SBasis> > const &f, double SBasis &prev_sb=result.segs[prev][dim]; SBasis &cur_sb =result.segs[cur][dim]; Coord const c=pt0[dim]; - if (prev_sb.empty()) { + if (prev_sb.isZero(0)) { prev_sb = SBasis(Linear(0.0, c)); } else { prev_sb[0][1] = c; } - if (cur_sb.empty()) { + if (cur_sb.isZero(0)) { cur_sb = SBasis(Linear(c, 0.0)); } else { cur_sb[0][0] = c; @@ -198,30 +198,22 @@ Point unitTangentAt(D2<SBasis> const & a, Coord t, unsigned n) return Point (0,0); } -static void set_first_point(Piecewise<D2<SBasis> > &f, Point a){ +static void set_first_point(Piecewise<D2<SBasis> > &f, Point const &a){ if ( f.empty() ){ f.concat(Piecewise<D2<SBasis> >(D2<SBasis>(SBasis(Linear(a[X])), SBasis(Linear(a[Y]))))); return; } for (unsigned dim=0; dim<2; dim++){ - if (f.segs.front()[dim].size() == 0){ - f.segs.front()[dim] = SBasis(Linear(a[dim],0)); - }else{ - f.segs.front()[dim][0][0] = a[dim]; - } + f.segs.front()[dim][0][0] = a[dim]; } } -static void set_last_point(Piecewise<D2<SBasis> > &f, Point a){ +static void set_last_point(Piecewise<D2<SBasis> > &f, Point const &a){ if ( f.empty() ){ f.concat(Piecewise<D2<SBasis> >(D2<SBasis>(SBasis(Linear(a[X])), SBasis(Linear(a[Y]))))); return; } for (unsigned dim=0; dim<2; dim++){ - if (f.segs.back()[dim].size() == 0){ - f.segs.back()[dim] = SBasis(Linear(0,a[dim])); - }else{ - f.segs.back()[dim][0][1] = a[dim]; - } + f.segs.back()[dim][0][1] = a[dim]; } } diff --git a/src/2geom/elliptical-arc.cpp b/src/2geom/elliptical-arc.cpp index 25a78b4ad..77d3d788d 100644 --- a/src/2geom/elliptical-arc.cpp +++ b/src/2geom/elliptical-arc.cpp @@ -354,7 +354,11 @@ EllipticalArc::pointAndDerivatives(Coord t, unsigned int n) const std::vector<Point> result; result.reserve(nn); double angle = angleAt(t); +#if __cplusplus <= 199711L std::auto_ptr<EllipticalArc> ea( static_cast<EllipticalArc*>(duplicate()) ); +#else + std::unique_ptr<EllipticalArc> ea( static_cast<EllipticalArc*>(duplicate()) ); +#endif ea->_ellipse.setCenter(0, 0); unsigned int m = std::min(nn, 4u); for ( unsigned int i = 0; i < m; ++i ) diff --git a/src/2geom/numeric/fitting-model.h b/src/2geom/numeric/fitting-model.h index fb96d1d2a..b2ca92ad8 100644 --- a/src/2geom/numeric/fitting-model.h +++ b/src/2geom/numeric/fitting-model.h @@ -372,7 +372,6 @@ class LFMSBasis void instance(SBasis & sb, ConstVectorView const& raw_data) const { - sb.clear(); sb.resize(m_order+1); for (unsigned int i = 0, k = 0; i < raw_data.size(); i+=2, ++k) { diff --git a/src/2geom/path-sink.cpp b/src/2geom/path-sink.cpp index 3b8d407f8..77301b716 100644 --- a/src/2geom/path-sink.cpp +++ b/src/2geom/path-sink.cpp @@ -73,8 +73,8 @@ void PathSink::feed(Rect const &r) { void PathSink::feed(Circle const &e) { Coord r = e.radius(); Point c = e.center(); - Point a = c + Point(0, c[Y] + r); - Point b = c + Point(0, c[Y] - r); + Point a = c + Point(0, +r); + Point b = c + Point(0, -r); moveTo(a); arcTo(r, r, 0, false, false, b); diff --git a/src/2geom/sbasis-geometric.cpp b/src/2geom/sbasis-geometric.cpp index 4c474f7f0..8aaa15144 100644 --- a/src/2geom/sbasis-geometric.cpp +++ b/src/2geom/sbasis-geometric.cpp @@ -228,7 +228,7 @@ Geom::unitVector(D2<SBasis> const &V_in, double tol, unsigned order){ // -This done, unitVector will have jumps at zeros: fill the gaps with arcs of circles. D2<SBasis> V = RescaleForNonVanishingEnds(V_in); - if (V[0].empty() && V[1].empty()) + if (V[0].isZero(0) && V[1].isZero(0)) return Piecewise<D2<SBasis> >(D2<SBasis>(Linear(1),SBasis())); SBasis x = V[0], y = V[1]; SBasis r_eqn1, r_eqn2; diff --git a/src/2geom/sbasis-roots.cpp b/src/2geom/sbasis-roots.cpp index 57bef4c0f..e3e5e4441 100644 --- a/src/2geom/sbasis-roots.cpp +++ b/src/2geom/sbasis-roots.cpp @@ -222,7 +222,7 @@ static void multi_roots_internal(SBasis const &f, double b, double fb){ - if (f.size()==0){ + if (f.isZero(0)){ int idx; idx=upper_level(levels,0,vtol); if (idx<(int)levels.size()&&fabs(levels.at(idx))<=vtol){ @@ -414,7 +414,7 @@ static void level_sets_internal(SBasis const &f, double fb, double tol=1e-5){ - if (f.size()==0){ + if (f.isZero(0)){ unsigned idx; idx=upper_level( levels, 0. ); if (idx<levels.size() && levels[idx].contains(0.)){ @@ -614,6 +614,7 @@ std::vector<double> roots1(SBasis const & s, Interval const ivl) { std::vector<double> roots(SBasis const & s) { switch(s.size()) { case 0: + assert(false); return std::vector<double>(); case 1: return roots1(s); @@ -628,6 +629,7 @@ std::vector<double> roots(SBasis const & s) { std::vector<double> roots(SBasis const & s, Interval const ivl) { switch(s.size()) { case 0: + assert(false); return std::vector<double>(); case 1: return roots1(s, ivl); diff --git a/src/2geom/sbasis-to-bezier.cpp b/src/2geom/sbasis-to-bezier.cpp index 09fbb03ef..d9a90aace 100644 --- a/src/2geom/sbasis-to-bezier.cpp +++ b/src/2geom/sbasis-to-bezier.cpp @@ -100,9 +100,7 @@ int sgn(unsigned int j, unsigned int k) */ void sbasis_to_bezier (Bezier & bz, SBasis const& sb, size_t sz) { - if (sb.size() == 0) { - THROW_RANGEERROR("size of sb is too small"); - } + assert(sb.size() > 0); size_t q, n; bool even; diff --git a/src/2geom/sbasis.cpp b/src/2geom/sbasis.cpp index 42d92d7b8..0f4159e94 100644 --- a/src/2geom/sbasis.cpp +++ b/src/2geom/sbasis.cpp @@ -279,9 +279,11 @@ SBasis multiply_add(SBasis const &a, SBasis const &b, SBasis c) { */ SBasis multiply(SBasis const &a, SBasis const &b) { - SBasis c(a.size() + b.size(), Linear(0,0)); - if(a.isZero() || b.isZero()) + if(a.isZero() || b.isZero()) { + SBasis c(1, Linear(0,0)); return c; + } + SBasis c(a.size() + b.size(), Linear(0,0)); return multiply_add(a, b, c); } #endif diff --git a/src/2geom/sbasis.h b/src/2geom/sbasis.h index 787e8b722..6923017be 100644 --- a/src/2geom/sbasis.h +++ b/src/2geom/sbasis.h @@ -83,49 +83,52 @@ public: const_iterator end() const { return d.end();} iterator begin() { return d.begin();} iterator end() { return d.end();} - bool empty() const {return d.empty();} + bool empty() const { return d.size() == 1 && d[0][0] == 0 && d[0][1] == 0; } Linear &back() {return d.back();} Linear const &back() const {return d.back();} - void pop_back() { d.pop_back();} - void resize(unsigned n) { d.resize(n);} - void resize(unsigned n, Linear const& l) { d.resize(n, l);} + void pop_back() { + if (d.size() > 1) { + d.pop_back(); + } else { + d[0][0] = 0; + d[0][1] = 0; + } + } + void resize(unsigned n) { d.resize(std::max<unsigned>(n, 1));} + void resize(unsigned n, Linear const& l) { d.resize(std::max<unsigned>(n, 1), l);} void reserve(unsigned n) { d.reserve(n);} - void clear() {d.clear();} + void clear() { + d.resize(1); + d[0][0] = 0; + d[0][1] = 0; + } void insert(iterator before, const_iterator src_begin, const_iterator src_end) { d.insert(before, src_begin, src_end);} Linear& at(unsigned i) { return d.at(i);} //void insert(Linear* before, int& n, Linear const &l) { d.insert(std::vector<Linear>::iterator(before), n, l);} bool operator==(SBasis const&B) const { return d == B.d;} bool operator!=(SBasis const&B) const { return d != B.d;} - operator std::vector<Linear>() { return d;} - - SBasis() {} + SBasis() + : d(1, Linear(0, 0)) + {} explicit SBasis(double a) - : d(1) - { - d[0][0] = a; - d[0][1] = a; - } + : d(1, Linear(a, a)) + {} explicit SBasis(double a, double b) - : d(1) - { - d[0][0] = a; - d[0][1] = b; - } - SBasis(SBasis const & a) : - d(a.d) + : d(1, Linear(a, b)) {} - SBasis(std::vector<Linear> const & ls) : - d(ls) + SBasis(SBasis const &a) + : d(a.d) + {} + SBasis(std::vector<Linear> const &ls) + : d(ls) + {} + SBasis(Linear const &bo) + : d(1, bo) + {} + SBasis(Linear* bo) + : d(1, bo ? *bo : Linear(0, 0)) {} - SBasis(Linear const & bo) { - push_back(bo); - } - SBasis(Linear* bo) { - if (bo) { - push_back(*bo); - } - } explicit SBasis(size_t n, Linear const&l) : d(n, l) {} SBasis(Coord c0, Coord c1, Coord c2, Coord c3) @@ -179,6 +182,7 @@ public: template <typename Iter> SBasis(Iter first, Iter last) { assert(std::distance(first, last) % 2 == 0); + assert(std::distance(first, last) >= 2); for (; first != last; ++first) { --last; push_back(Linear(*first, *last)); @@ -188,14 +192,14 @@ public: //IMPL: FragmentConcept typedef double output_type; inline bool isZero(double eps=EPSILON) const { - if(empty()) return true; + assert(size() > 0); for(unsigned i = 0; i < size(); i++) { if(!(*this)[i].isZero(eps)) return false; } return true; } inline bool isConstant(double eps=EPSILON) const { - if (empty()) return true; + assert(size() > 0); if(!(*this)[0].isConstant(eps)) return false; for (unsigned i = 1; i < size(); i++) { if(!(*this)[i].isZero(eps)) return false; @@ -212,6 +216,7 @@ public: int degreesOfFreedom() const { return size()*2;} double valueAt(double t) const { + assert(size() > 0); double s = t*(1-t); double p0 = 0, p1 = 0; for(unsigned k = size(); k > 0; k--) { @@ -239,11 +244,11 @@ public: //MUTATOR PRISON //remove extra zeros void normalize() { - while(!empty() && 0 == back()[0] && 0 == back()[1]) + while(size() > 1 && back().isZero(0)) pop_back(); } - void truncate(unsigned k) { if(k < size()) resize(k); } + void truncate(unsigned k) { if(k < size()) resize(std::max<size_t>(k, 1)); } private: void derive(); // in place version }; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c416b0dea..30af55925 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -240,6 +240,7 @@ set(inkscape_SRC print.cpp profile-manager.cpp proj_pt.cpp + pure-transform.cpp rdf.cpp removeoverlap.cpp resource-manager.cpp @@ -367,6 +368,7 @@ set(inkscape_SRC print.h profile-manager.h proj_pt.h + pure-transform.h rdf.h remove-last.h removeoverlap.h @@ -509,8 +511,14 @@ set(inkscape_SRC #add_inkscape_lib(sp_LIB "${sp_SRC}") #add_inkscape_lib(inkscape_LIB "${inkscape_SRC}") -# make executable for INKSCAPE -add_executable(inkscape ${main_SRC} ${inkscape_SRC} ${sp_SRC}) +# Build everything except main and inkview.c in a CMake "object" library. +# An object library is just a bunch of .o files. Linking them with main.c or inkview.c +# we get the inkscape and inkview executables respectively. +add_library(inkscape_base OBJECT ${inkscape_SRC} ${sp_SRC}) + +# make executables for inkscape and inkview +add_executable(inkscape ${main_SRC} $<TARGET_OBJECTS:inkscape_base>) +add_executable(inkview inkview.cpp $<TARGET_OBJECTS:inkscape_base>) if(UNIX) # message after building. @@ -523,31 +531,31 @@ endif() add_dependencies(inkscape inkscape_version) -target_link_libraries(inkscape - # order from automake - #sp_LIB - #nrtype_LIB +if (NOT "${WITH_EXT_GDL}") + list (APPEND INKSCAPE_LIBS "gdl_LIB") +endif() - #inkscape_LIB - #sp_LIB # annoying, we need both! - nrtype_LIB # annoying, we need both! +set(INKSCAPE_TARGET_LIBS + # order from automake + #sp_LIB + #nrtype_LIB - croco_LIB - avoid_LIB - gdl_LIB - cola_LIB - vpsc_LIB - livarot_LIB - uemf_LIB - 2geom_LIB - depixelize_LIB - util_LIB - gc_LIB + #inkscape_LIB + #sp_LIB # annoying, we need both! + nrtype_LIB # annoying, we need both! - ${INKSCAPE_LIBS} + croco_LIB + avoid_LIB + cola_LIB + vpsc_LIB + livarot_LIB + uemf_LIB + 2geom_LIB + depixelize_LIB + util_LIB + gc_LIB + ${INKSCAPE_LIBS} ) -# TODO -# make executable for INKVIEW -#add_executable(inkview inkview.cpp) -# ... +target_link_libraries(inkscape ${INKSCAPE_TARGET_LIBS}) +target_link_libraries(inkview ${INKSCAPE_TARGET_LIBS}) diff --git a/src/Makefile.am b/src/Makefile.am index 7a37f13e8..27d4fb844 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -46,7 +46,6 @@ all_libs = \ $(FREETYPE_LIBS) \ $(kdeldadd) \ $(win32ldflags) \ - $(CARBON_LDFLAGS) \ $(LIBWPG_LIBS) \ $(LIBVISIO_LIBS) \ $(LIBCDR_LIBS) \ @@ -260,9 +259,7 @@ check-local: # the XFAIL_TESTS build target should be removed. # See the following Launchpad bugs: # -# LP #1202271 <cxxtest: preferences-test.h fails> # LP #1208013 <cxxtest: curve-test.h fails> -# LP #1208002 <cxxtest: svg-length-test.h fails> # LP #1208005 <cxxtest: svg-path-geom-test.h fails> # LP #1207502 <cxxtest: svg-affine-test.h fails> diff --git a/src/Makefile_insert b/src/Makefile_insert index 800752df4..b9723ac42 100644 --- a/src/Makefile_insert +++ b/src/Makefile_insert @@ -88,6 +88,7 @@ ink_common_sources += \ print.cpp print.h \ profile-manager.cpp profile-manager.h \ proj_pt.cpp proj_pt.h \ + pure-transform.cpp pure-transform.h \ removeoverlap.cpp removeoverlap.h \ rdf.cpp rdf.h \ resource-manager.cpp resource-manager.h \ diff --git a/src/attributes-test.h b/src/attributes-test.h index 411304ec3..1fc3972c0 100644 --- a/src/attributes-test.h +++ b/src/attributes-test.h @@ -43,6 +43,7 @@ public: SVG 2: text-decoration-fill, text-decoration-stroke SVG 2: solid-color, solid-opacity SVG 2: Hatches and Meshes + CSS 3: text-orientation CSS 3: font-variant-xxx, font-feature-settings */ struct {char const *attr; bool supported;} const all_attrs[] = { @@ -69,7 +70,6 @@ struct {char const *attr; bool supported;} const all_attrs[] = { {"baseProfile", false}, {"bbox", true}, {"bias", true}, - {"block-progression", true}, {"by", true}, {"calcMode", true}, {"cap-height", true}, @@ -334,6 +334,7 @@ struct {char const *attr; bool supported;} const all_attrs[] = { {"widths", true}, {"word-spacing", true}, {"writing-mode", true}, + {"text-orientation", true}, {"x", true}, {"x-height", true}, {"x1", true}, @@ -489,6 +490,7 @@ struct {char const *attr; bool supported;} const all_attrs[] = { {"showgrid", true}, // {"gridtype", true}, {"showguides", true}, +// {"inkscape:lockguides", false}, //not sure about uncomment {"gridtolerance", true}, {"guidetolerance", true}, {"objecttolerance", true}, diff --git a/src/attributes.cpp b/src/attributes.cpp index af19360c1..ad6a51c88 100644 --- a/src/attributes.cpp +++ b/src/attributes.cpp @@ -41,6 +41,7 @@ static SPStyleProp const props[] = { {SP_ATTR_TRANSFORM_CENTER_Y, "inkscape:transform-center-y"}, {SP_ATTR_INKSCAPE_PATH_EFFECT, "inkscape:path-effect"}, {SP_ATTR_INKSCAPE_HIGHLIGHT_COLOR, "inkscape:highlight-color"}, + {SP_ATTR_INKSCAPE_SPRAY_ORIGIN, "inkscape:spray-origin"}, /* SPAnchor */ {SP_ATTR_XLINK_HREF, "xlink:href"}, {SP_ATTR_XLINK_TYPE, "xlink:type"}, @@ -116,6 +117,7 @@ static SPStyleProp const props[] = { {SP_ATTR_INKSCAPE_SNAP_PAGE_BORDER, "inkscape:snap-page"}, {SP_ATTR_INKSCAPE_CURRENT_LAYER, "inkscape:current-layer"}, {SP_ATTR_INKSCAPE_DOCUMENT_UNITS, "inkscape:document-units"}, // This setting sets the Display units, *not* the units used in SVG + {SP_ATTR_INKSCAPE_LOCKGUIDES, "inkscape:lockguides"}, {SP_ATTR_UNITS, "units"}, {SP_ATTR_INKSCAPE_CONNECTOR_SPACING, "inkscape:connector-spacing"}, /* SPColorProfile */ @@ -125,6 +127,8 @@ static SPStyleProp const props[] = { /* SPGuide */ {SP_ATTR_ORIENTATION, "orientation"}, {SP_ATTR_POSITION, "position"}, + {SP_ATTR_INKSCAPE_COLOR, "inkscape:color"}, + {SP_ATTR_INKSCAPE_LOCKED, "inkscape:locked"}, /* SPImage */ {SP_ATTR_X, "x"}, {SP_ATTR_Y, "y"}, @@ -439,8 +443,8 @@ static SPStyleProp const props[] = { /* Text (css3) */ {SP_PROP_DIRECTION, "direction"}, - {SP_PROP_BLOCK_PROGRESSION, "block-progression"}, {SP_PROP_WRITING_MODE, "writing-mode"}, + {SP_PROP_TEXT_ORIENTATION, "text-orientation"}, {SP_PROP_UNICODE_BIDI, "unicode-bidi"}, {SP_PROP_ALIGNMENT_BASELINE, "alignment-baseline"}, {SP_PROP_BASELINE_SHIFT, "baseline-shift"}, diff --git a/src/attributes.h b/src/attributes.h index 7d6ea70a0..03df0cb94 100644 --- a/src/attributes.h +++ b/src/attributes.h @@ -41,6 +41,7 @@ enum SPAttributeEnum { SP_ATTR_TRANSFORM_CENTER_Y, SP_ATTR_INKSCAPE_PATH_EFFECT, SP_ATTR_INKSCAPE_HIGHLIGHT_COLOR, + SP_ATTR_INKSCAPE_SPRAY_ORIGIN, /* SPAnchor */ SP_ATTR_XLINK_HREF, SP_ATTR_XLINK_TYPE, @@ -118,6 +119,7 @@ enum SPAttributeEnum { SP_ATTR_INKSCAPE_SNAP_PAGE_BORDER, SP_ATTR_INKSCAPE_CURRENT_LAYER, SP_ATTR_INKSCAPE_DOCUMENT_UNITS, + SP_ATTR_INKSCAPE_LOCKGUIDES, SP_ATTR_UNITS, SP_ATTR_INKSCAPE_CONNECTOR_SPACING, /* SPColorProfile */ @@ -127,6 +129,8 @@ enum SPAttributeEnum { /* SPGuide */ SP_ATTR_ORIENTATION, SP_ATTR_POSITION, + SP_ATTR_INKSCAPE_COLOR, + SP_ATTR_INKSCAPE_LOCKED, /* SPImage */ SP_ATTR_X, SP_ATTR_Y, @@ -443,8 +447,8 @@ enum SPAttributeEnum { SP_PROP_TEXT_TRANSFORM, SP_PROP_DIRECTION, - SP_PROP_BLOCK_PROGRESSION, SP_PROP_WRITING_MODE, + SP_PROP_TEXT_ORIENTATION, SP_PROP_UNICODE_BIDI, SP_PROP_ALIGNMENT_BASELINE, SP_PROP_BASELINE_SHIFT, diff --git a/src/box3d.cpp b/src/box3d.cpp index dc04a2eb6..c4c2728e4 100644 --- a/src/box3d.cpp +++ b/src/box3d.cpp @@ -50,6 +50,11 @@ SPBox3D::SPBox3D() : SPGroup() { this->persp_href = NULL; this->persp_ref = new Persp3DReference(this); + + /* we initialize the z-orders to zero so that they are updated during dragging */ + for (int i = 0; i < 6; ++i) { + z_orders[i] = 0; + } } SPBox3D::~SPBox3D() { @@ -902,7 +907,7 @@ box3d_swap_sides(int z_orders[6], Box3D::Axis axis) { } } - if (pos1 != -1){ + if ((pos1 != -1) && (pos2 != -1)){ int tmp = z_orders[pos1]; z_orders[pos1] = z_orders[pos2]; z_orders[pos2] = tmp; diff --git a/src/conn-avoid-ref.cpp b/src/conn-avoid-ref.cpp index ec9aba793..4c9665fa0 100644 --- a/src/conn-avoid-ref.cpp +++ b/src/conn-avoid-ref.cpp @@ -253,7 +253,7 @@ static std::vector<Geom::Point> approxItemWithPoints(SPItem const *item, const G SPGroup* group = SP_GROUP(item); // consider all first-order children std::vector<SPItem*> itemlist = sp_item_group_item_list(group); - for (std::vector<SPItem*>::const_iterator i = itemlist.begin(); i != itemlist.end(); i++) { + for (std::vector<SPItem*>::const_iterator i = itemlist.begin(); i != itemlist.end(); ++i) { SPItem* child_item = *i; std::vector<Geom::Point> child_points = approxItemWithPoints(child_item, item_transform * child_item->transform); poly_points.insert(poly_points.end(), child_points.begin(), child_points.end()); diff --git a/src/desktop-events.cpp b/src/desktop-events.cpp index b685dacbf..99bc4f7ae 100644 --- a/src/desktop-events.cpp +++ b/src/desktop-events.cpp @@ -50,6 +50,8 @@ #include "ui/tools-switch.h" #include "verbs.h" #include "widgets/desktop-widget.h" +#include "sp-cursor.h" +#include "pixmaps/cursor-select.xpm" #include "xml/repr.h" using Inkscape::DocumentUndo; @@ -514,14 +516,18 @@ gint sp_dt_guide_event(SPCanvasItem *item, GdkEvent *event, gpointer data) break; case GDK_ENTER_NOTIFY: { - sp_guideline_set_color(SP_GUIDELINE(item), guide->getHiColor()); - + if (!guide->getLocked()) { + sp_guideline_set_color(SP_GUIDELINE(item), guide->getHiColor()); + } // set move or rotate cursor Geom::Point const event_w(event->crossing.x, event->crossing.y); if ((event->crossing.state & GDK_SHIFT_MASK) && (drag_type != SP_DRAG_MOVE_ORIGIN)) { GdkCursor *guide_cursor; guide_cursor = gdk_cursor_new (GDK_EXCHANGE); + if(guide->getLocked()){ + guide_cursor = sp_cursor_new_from_xpm(cursor_select_xpm , 1, 1); + } gdk_window_set_cursor(gtk_widget_get_window (GTK_WIDGET(desktop->getCanvas())), guide_cursor); #if GTK_CHECK_VERSION(3,0,0) g_object_unref(guide_cursor); @@ -531,6 +537,9 @@ gint sp_dt_guide_event(SPCanvasItem *item, GdkEvent *event, gpointer data) } else { GdkCursor *guide_cursor; guide_cursor = gdk_cursor_new (GDK_HAND1); + if(guide->getLocked()){ + guide_cursor = sp_cursor_new_from_xpm(cursor_select_xpm , 1, 1); + } gdk_window_set_cursor(gtk_widget_get_window (GTK_WIDGET(desktop->getCanvas())), guide_cursor); #if GTK_CHECK_VERSION(3,0,0) g_object_unref(guide_cursor); diff --git a/src/desktop-style.cpp b/src/desktop-style.cpp index 02c18339b..67c0687b7 100644 --- a/src/desktop-style.cpp +++ b/src/desktop-style.cpp @@ -195,7 +195,7 @@ sp_desktop_set_style(SPDesktop *desktop, SPCSSAttr *css, bool change, bool write sp_css_attr_unset_uris(css_write); prefs->mergeStyle("/desktop/style", css_write); std::vector<SPItem*> const itemlist = desktop->selection->itemList(); - for (std::vector<SPItem*>::const_iterator i = itemlist.begin(); i!= itemlist.end(); i++) { + for (std::vector<SPItem*>::const_iterator i = itemlist.begin(); i!= itemlist.end(); ++i) { /* last used styles for 3D box faces are stored separately */ SPObject *obj = *i; Box3DSide *side = dynamic_cast<Box3DSide *>(obj); @@ -235,7 +235,7 @@ sp_desktop_set_style(SPDesktop *desktop, SPCSSAttr *css, bool change, bool write css_no_text = sp_css_attr_unset_text(css_no_text); std::vector<SPItem*> const itemlist = desktop->selection->itemList(); - for (std::vector<SPItem*>::const_iterator i = itemlist.begin(); i!= itemlist.end(); i++) { + for (std::vector<SPItem*>::const_iterator i = itemlist.begin(); i!= itemlist.end(); ++i) { SPItem *item = *i; // If not text, don't apply text attributes (can a group have text attributes? Yes! FIXME) @@ -447,7 +447,7 @@ stroke_average_width (const std::vector<SPItem*> &objects) gdouble avgwidth = 0.0; bool notstroked = true; int n_notstroked = 0; - for (std::vector<SPItem*>::const_iterator i = objects.begin(); i != objects.end(); i++) { + for (std::vector<SPItem*>::const_iterator i = objects.begin(); i != objects.end(); ++i) { SPItem *item = *i; if (!item) { continue; @@ -500,7 +500,7 @@ objects_query_fillstroke (const std::vector<SPItem*> &objects, SPStyle *style_re SPIPaint *paint_res = isfill? &style_res->fill : &style_res->stroke; bool paintImpossible = true; - paint_res->set = TRUE; + paint_res->set = true; SVGICCColor* iccColor = 0; @@ -513,7 +513,7 @@ objects_query_fillstroke (const std::vector<SPItem*> &objects, SPStyle *style_re prev[0] = prev[1] = prev[2] = 0.0; bool same_color = true; - for (std::vector<SPItem*>::const_iterator i = objects.begin(); i!= objects.end(); i++) { + for (std::vector<SPItem*>::const_iterator i = objects.begin(); i!= objects.end(); ++i) { SPObject *obj = *i; if (!obj) { continue; @@ -697,7 +697,7 @@ objects_query_opacity (const std::vector<SPItem*> &objects, SPStyle *style_res) guint opacity_items = 0; - for (std::vector<SPItem*>::const_iterator i = objects.begin(); i != objects.end(); i++) { + for (std::vector<SPItem*>::const_iterator i = objects.begin(); i != objects.end(); ++i) { SPObject *obj = *i; if (!obj) { continue; @@ -753,7 +753,7 @@ objects_query_strokewidth (const std::vector<SPItem*> &objects, SPStyle *style_r int n_stroked = 0; - for (std::vector<SPItem*>::const_iterator i = objects.begin(); i != objects.end(); i++) { + for (std::vector<SPItem*>::const_iterator i = objects.begin(); i != objects.end(); ++i) { SPObject *obj = *i; if (!obj) { continue; @@ -827,7 +827,7 @@ objects_query_miterlimit (const std::vector<SPItem*> &objects, SPStyle *style_re gdouble prev_ml = -1; bool same_ml = true; - for (std::vector<SPItem*>::const_iterator i = objects.begin(); i != objects.end(); i++) { + for (std::vector<SPItem*>::const_iterator i = objects.begin(); i != objects.end(); ++i) { SPObject *obj = *i; if (!dynamic_cast<SPItem *>(obj)) { continue; @@ -886,7 +886,7 @@ objects_query_strokecap (const std::vector<SPItem*> &objects, SPStyle *style_res bool same_cap = true; int n_stroked = 0; - for (std::vector<SPItem*>::const_iterator i = objects.begin(); i != objects.end(); i++) { + for (std::vector<SPItem*>::const_iterator i = objects.begin(); i != objects.end(); ++i) { SPObject *obj = *i; if (!dynamic_cast<SPItem *>(obj)) { continue; @@ -940,7 +940,7 @@ objects_query_strokejoin (const std::vector<SPItem*> &objects, SPStyle *style_re bool same_join = true; int n_stroked = 0; - for (std::vector<SPItem*>::const_iterator i = objects.begin(); i != objects.end(); i++) { + for (std::vector<SPItem*>::const_iterator i = objects.begin(); i != objects.end(); ++i) { SPObject *obj = *i; if (!dynamic_cast<SPItem *>(obj)) { continue; @@ -1003,7 +1003,7 @@ objects_query_fontnumbers (const std::vector<SPItem*> &objects, SPStyle *style_r int texts = 0; int no_size = 0; - for (std::vector<SPItem*>::const_iterator i = objects.begin(); i != objects.end(); i++) { + for (std::vector<SPItem*>::const_iterator i = objects.begin(); i != objects.end(); ++i) { SPObject *obj = *i; if (!isTextualItem(obj)) { @@ -1122,7 +1122,7 @@ objects_query_fontstyle (const std::vector<SPItem*> &objects, SPStyle *style_res int texts = 0; - for (std::vector<SPItem*>::const_iterator i = objects.begin(); i != objects.end(); i++) { + for (std::vector<SPItem*>::const_iterator i = objects.begin(); i != objects.end(); ++i) { SPObject *obj = *i; if (!isTextualItem(obj)) { @@ -1144,7 +1144,7 @@ objects_query_fontstyle (const std::vector<SPItem*> &objects, SPStyle *style_res different = true; // different styles } - set = TRUE; + set = true; style_res->font_weight.value = style_res->font_weight.computed = style->font_weight.computed; style_res->font_style.value = style_res->font_style.computed = style->font_style.computed; style_res->font_stretch.value = style_res->font_stretch.computed = style->font_stretch.computed; @@ -1192,7 +1192,7 @@ objects_query_fontvariants (const std::vector<SPItem*> &objects, SPStyle *style_ caps_res->value = 0; numeric_res->value = 0; - for (std::vector<SPItem*>::const_iterator i = objects.begin(); i != objects.end(); i++) { + for (std::vector<SPItem*>::const_iterator i = objects.begin(); i != objects.end(); ++i) { SPObject *obj = *i; if (!isTextualItem(obj)) { @@ -1256,6 +1256,56 @@ objects_query_fontvariants (const std::vector<SPItem*> &objects, SPStyle *style_ } +/** + * Write to style_res the average writing modes style of objects. + */ +int +objects_query_writing_modes (const std::vector<SPItem*> &objects, SPStyle *style_res) +{ + bool different = false; + bool set = false; + + int texts = 0; + + for (std::vector<SPItem*>::const_iterator i = objects.begin(); i != objects.end(); i++) { + SPObject *obj = *i; + + if (!isTextualItem(obj)) { + continue; + } + + SPStyle *style = obj->style; + if (!style) { + continue; + } + + texts ++; + + if (set && + ( ( style_res->writing_mode.computed != style->writing_mode.computed ) || + ( style_res->text_orientation.computed != style->text_orientation.computed ) ) ) { + different = true; // different styles + } + + set = true; + style_res->writing_mode.computed = style->writing_mode.computed; + style_res->text_orientation.computed = style->text_orientation.computed; + } + + if (texts == 0 || !set) + return QUERY_STYLE_NOTHING; + + if (texts > 1) { + if (different) { + return QUERY_STYLE_MULTIPLE_DIFFERENT; + } else { + return QUERY_STYLE_MULTIPLE_SAME; + } + } else { + return QUERY_STYLE_SINGLE; + } +} + int objects_query_fontfeaturesettings (const std::vector<SPItem*> &objects, SPStyle *style_res) { @@ -1268,7 +1318,7 @@ objects_query_fontfeaturesettings (const std::vector<SPItem*> &objects, SPStyle } style_res->font_feature_settings.set = FALSE; - for (std::vector<SPItem*>::const_iterator i = objects.begin(); i != objects.end(); i++) { + for (std::vector<SPItem*>::const_iterator i = objects.begin(); i != objects.end(); ++i) { SPObject *obj = *i; // std::cout << " " << reinterpret_cast<SPObject*>(i->data)->getId() << std::endl; @@ -1293,7 +1343,7 @@ objects_query_fontfeaturesettings (const std::vector<SPItem*> &objects, SPStyle style_res->font_feature_settings.value = NULL; } - style_res->font_feature_settings.set = TRUE; + style_res->font_feature_settings.set = true; style_res->font_feature_settings.value = g_strdup(style->font_feature_settings.value); } @@ -1336,7 +1386,7 @@ objects_query_baselines (const std::vector<SPItem*> &objects, SPStyle *style_res int texts = 0; - for (std::vector<SPItem*>::const_iterator i = objects.begin(); i != objects.end(); i++) { + for (std::vector<SPItem*>::const_iterator i = objects.begin(); i != objects.end(); ++i) { SPObject *obj = *i; if (!isTextualItem(obj)) { @@ -1424,7 +1474,7 @@ objects_query_fontfamily (const std::vector<SPItem*> &objects, SPStyle *style_re } style_res->font_family.set = FALSE; - for (std::vector<SPItem*>::const_iterator i = objects.begin(); i != objects.end(); i++) { + for (std::vector<SPItem*>::const_iterator i = objects.begin(); i != objects.end(); ++i) { SPObject *obj = *i; // std::cout << " " << reinterpret_cast<SPObject*>(i->data)->getId() << std::endl; @@ -1449,7 +1499,7 @@ objects_query_fontfamily (const std::vector<SPItem*> &objects, SPStyle *style_re style_res->font_family.value = NULL; } - style_res->font_family.set = TRUE; + style_res->font_family.set = true; style_res->font_family.value = g_strdup(style->font_family.value); } @@ -1480,7 +1530,7 @@ objects_query_fontspecification (const std::vector<SPItem*> &objects, SPStyle *s } style_res->font_specification.set = FALSE; - for (std::vector<SPItem*>::const_iterator i = objects.begin(); i != objects.end(); i++) { + for (std::vector<SPItem*>::const_iterator i = objects.begin(); i != objects.end(); ++i) { SPObject *obj = *i; // std::cout << " " << reinterpret_cast<SPObject*>(i->data)->getId() << std::endl; @@ -1508,7 +1558,7 @@ objects_query_fontspecification (const std::vector<SPItem*> &objects, SPStyle *s style_res->font_specification.value = NULL; } - style_res->font_specification.set = TRUE; + style_res->font_specification.set = true; style_res->font_specification.value = g_strdup(style->font_specification.value); } } @@ -1538,7 +1588,7 @@ objects_query_blend (const std::vector<SPItem*> &objects, SPStyle *style_res) bool same_blend = true; guint items = 0; - for (std::vector<SPItem*>::const_iterator i = objects.begin(); i != objects.end(); i++) { + for (std::vector<SPItem*>::const_iterator i = objects.begin(); i != objects.end(); ++i) { SPObject *obj = *i; if (!obj) { continue; @@ -1628,7 +1678,7 @@ objects_query_blur (const std::vector<SPItem*> &objects, SPStyle *style_res) guint blur_items = 0; guint items = 0; - for (std::vector<SPItem*>::const_iterator i = objects.begin(); i != objects.end(); i++) { + for (std::vector<SPItem*>::const_iterator i = objects.begin(); i != objects.end(); ++i) { SPObject *obj = *i; if (!obj) { continue; @@ -1728,6 +1778,8 @@ sp_desktop_query_style_from_list (const std::vector<SPItem*> &list, SPStyle *sty return objects_query_fontfeaturesettings (list, style); } else if (property == QUERY_STYLE_PROPERTY_FONTNUMBERS) { return objects_query_fontnumbers (list, style); + } else if (property == QUERY_STYLE_PROPERTY_WRITINGMODES) { + return objects_query_writing_modes (list, style); } else if (property == QUERY_STYLE_PROPERTY_BASELINES) { return objects_query_baselines (list, style); diff --git a/src/desktop-style.h b/src/desktop-style.h index 95c434844..b9199b615 100644 --- a/src/desktop-style.h +++ b/src/desktop-style.h @@ -51,6 +51,7 @@ enum { // which property was queried (add when you need more) QUERY_STYLE_PROPERTY_FONTFEATURESETTINGS, // font feature settings (OpenType features) QUERY_STYLE_PROPERTY_FONTNUMBERS, // size, spacings QUERY_STYLE_PROPERTY_BASELINES, // baseline-shift + QUERY_STYLE_PROPERTY_WRITINGMODES, // writing-mode, text-orientation QUERY_STYLE_PROPERTY_MASTEROPACITY, // opacity QUERY_STYLE_PROPERTY_BLEND, // blend QUERY_STYLE_PROPERTY_BLUR // blur diff --git a/src/desktop.cpp b/src/desktop.cpp index 02df50c6b..ae92c058a 100644 --- a/src/desktop.cpp +++ b/src/desktop.cpp @@ -1467,6 +1467,11 @@ void SPDesktop::toggleColorProfAdjust() _widget->toggleColorProfAdjust(); } +void SPDesktop::toggleGuidesLock() +{ + _widget->toggleGuidesLock(); +} + bool SPDesktop::colorProfAdjustEnabled() { return _widget->colorProfAdjustEnabled(); @@ -1876,6 +1881,8 @@ SPDesktop::show_dialogs() mapVerbPreference.insert(std::make_pair ("ObjectProperties", "/dialogs/object") ); mapVerbPreference.insert(std::make_pair ("SpellCheck", "/dialogs/spellcheck") ); mapVerbPreference.insert(std::make_pair ("Symbols", "/dialogs/symbols") ); + mapVerbPreference.insert(std::make_pair ("ObjectsPanel", "/dialogs/objects") ); + mapVerbPreference.insert(std::make_pair ("TagsPanel", "/dialogs/tags") ); for (std::map<Glib::ustring, Glib::ustring>::const_iterator iter = mapVerbPreference.begin(); iter != mapVerbPreference.end(); ++iter) { Glib::ustring pref = iter->second; diff --git a/src/desktop.h b/src/desktop.h index 754e09766..f1444ba7b 100644 --- a/src/desktop.h +++ b/src/desktop.h @@ -383,6 +383,8 @@ public: void clearWaitingCursor(); bool isWaitingCursor() const { return waiting_cursor; }; + void toggleGuidesLock(); + void toggleColorProfAdjust(); bool colorProfAdjustEnabled(); diff --git a/src/display/canvas-text.cpp b/src/display/canvas-text.cpp index 5ad87b4ef..7c019caf5 100644 --- a/src/display/canvas-text.cpp +++ b/src/display/canvas-text.cpp @@ -266,10 +266,10 @@ sp_canvastext_set_coords (SPCanvasText *ct, gdouble x0, gdouble y0) void sp_canvastext_set_coords (SPCanvasText *ct, const Geom::Point start) { - Geom::Point pos = ct->desktop->doc2dt(start); - - g_return_if_fail (ct != NULL); + g_return_if_fail (ct && ct->desktop); g_return_if_fail (SP_IS_CANVASTEXT (ct)); + + Geom::Point pos = ct->desktop->doc2dt(start); if (DIFFER (pos[0], ct->s[Geom::X]) || DIFFER (pos[1], ct->s[Geom::Y])) { ct->s[Geom::X] = pos[0]; diff --git a/src/display/curve.cpp b/src/display/curve.cpp index 3024d1276..b6c387034 100644 --- a/src/display/curve.cpp +++ b/src/display/curve.cpp @@ -496,7 +496,7 @@ SPCurve::append(SPCurve const *curve2, _pathv.push_back( (*it) ); } - for (it++; it != curve2->_pathv.end(); ++it) { + for (++it; it != curve2->_pathv.end(); ++it) { _pathv.push_back( (*it) ); } } else { diff --git a/src/display/drawing-image.cpp b/src/display/drawing-image.cpp index 1594614ac..2a943d16c 100644 --- a/src/display/drawing-image.cpp +++ b/src/display/drawing-image.cpp @@ -132,7 +132,7 @@ unsigned DrawingImage::_renderItem(DrawingContext &dc, Geom::IntRect const &/*ar } } - dc.paint(_opacity); + dc.paint(1); } else { // outline; draw a rect instead diff --git a/src/display/guideline.cpp b/src/display/guideline.cpp index 44bbd14bd..4b7ea59ab 100644 --- a/src/display/guideline.cpp +++ b/src/display/guideline.cpp @@ -53,6 +53,7 @@ static void sp_guideline_init(SPGuideLine *gl) { gl->rgba = 0x0000ff7f; + gl->locked = false; gl->normal_to_line = Geom::Point(0,1); gl->angle = 3.14159265358979323846/2; gl->point_on_line = Geom::Point(0,0); @@ -177,9 +178,16 @@ static void sp_guideline_update(SPCanvasItem *item, Geom::Affine const &affine, gl->affine = affine; + if (gl->locked) { + sp_ctrlpoint_set_circle(gl->origin, false); + sp_ctrlpoint_set_lenght(gl->origin, 6); + } else { + sp_ctrlpoint_set_circle(gl->origin, true); + sp_ctrlpoint_set_lenght(gl->origin, 4); + } sp_ctrlpoint_set_coords(gl->origin, gl->point_on_line); sp_canvas_item_request_update(SP_CANVAS_ITEM (gl->origin)); - + Geom::Point pol_transformed = gl->point_on_line*affine; if (gl->is_horizontal()) { sp_canvas_update_bbox (item, -1000000, round(pol_transformed[Geom::Y] - 16), 1000000, round(pol_transformed[Geom::Y] + 1)); @@ -189,6 +197,7 @@ static void sp_guideline_update(SPCanvasItem *item, Geom::Affine const &affine, //TODO: labels in angled guidelines are not showing up for some reason. sp_canvas_update_bbox (item, -1000000, -1000000, 1000000, 1000000); } + } // Returns 0.0 if point is on the guideline @@ -219,6 +228,7 @@ SPCanvasItem *sp_guideline_new(SPCanvasGroup *parent, char* label, Geom::Point p normal.normalize(); gl->label = label; + gl->locked = false; gl->normal_to_line = normal; gl->angle = tan( -gl->normal_to_line[Geom::X] / gl->normal_to_line[Geom::Y]); sp_guideline_set_position(gl, point_on_line); @@ -238,6 +248,12 @@ void sp_guideline_set_label(SPGuideLine *gl, const char* label) sp_canvas_item_request_update(SP_CANVAS_ITEM (gl)); } +void sp_guideline_set_locked(SPGuideLine *gl, const bool locked) +{ + gl->locked = locked; + sp_canvas_item_request_update(SP_CANVAS_ITEM (gl)); +} + void sp_guideline_set_position(SPGuideLine *gl, Geom::Point point_on_line) { gl->point_on_line = point_on_line; diff --git a/src/display/guideline.h b/src/display/guideline.h index 2d9a87d9b..778517f1d 100644 --- a/src/display/guideline.h +++ b/src/display/guideline.h @@ -32,6 +32,7 @@ struct SPGuideLine { guint32 rgba; char* label; + bool locked; Geom::Point normal_to_line; Geom::Point point_on_line; double angle; @@ -51,6 +52,7 @@ GType sp_guideline_get_type(); SPCanvasItem *sp_guideline_new(SPCanvasGroup *parent, char* label, Geom::Point point_on_line, Geom::Point normal); void sp_guideline_set_label(SPGuideLine *gl, const char* label); +void sp_guideline_set_locked(SPGuideLine *gl, const bool locked); void sp_guideline_set_position(SPGuideLine *gl, Geom::Point point_on_line); void sp_guideline_set_normal(SPGuideLine *gl, Geom::Point normal_to_line); void sp_guideline_set_color(SPGuideLine *gl, unsigned int rgba); diff --git a/src/display/nr-filter-image.cpp b/src/display/nr-filter-image.cpp index 179ba0e0a..af89d98e0 100644 --- a/src/display/nr-filter-image.cpp +++ b/src/display/nr-filter-image.cpp @@ -56,6 +56,8 @@ void FilterImage::render_cairo(FilterSlot &slot) // Note: viewport calculation in non-trivial. Do not rely // on get_matrix_primitiveunits2pb(). Geom::Rect vp = filter_primitive_area( slot.get_units() ); + slot.set_primitive_area(_output, vp); // Needed for tiling + double feImageX = vp.min()[Geom::X]; double feImageY = vp.min()[Geom::Y]; double feImageWidth = vp.width(); diff --git a/src/display/nr-filter-offset.cpp b/src/display/nr-filter-offset.cpp index af1081abe..93bab7d39 100644 --- a/src/display/nr-filter-offset.cpp +++ b/src/display/nr-filter-offset.cpp @@ -37,9 +37,11 @@ void FilterOffset::render_cairo(FilterSlot &slot) cairo_surface_t *out = ink_cairo_surface_create_identical(in); // color_interpolation_filters for out same as in. See spec (DisplacementMap). copy_cairo_surface_ci(in, out); - cairo_t *ct = cairo_create(out); + Geom::Rect vp = filter_primitive_area( slot.get_units() ); + slot.set_primitive_area(_output, vp); // Needed for tiling + // Handle bounding box case double x = dx; double y = dy; diff --git a/src/display/nr-filter-primitive.cpp b/src/display/nr-filter-primitive.cpp index c8b569036..ea72efff0 100644 --- a/src/display/nr-filter-primitive.cpp +++ b/src/display/nr-filter-primitive.cpp @@ -110,17 +110,12 @@ void FilterPrimitive::set_subregion(SVGLength const &x, SVGLength const &y, Geom::Rect FilterPrimitive::filter_primitive_area(FilterUnits const &units) { - Geom::OptRect const bb_opt = units.get_item_bbox(); Geom::OptRect const fa_opt = units.get_filter_area(); - Geom::Rect bb; - Geom::Rect fa; - if (!bb_opt || !fa_opt) { + if (!fa_opt) { + std::cerr << "FilterPrimitive::filter_primitive_area: filter area undefined." << std::endl; return Geom::Rect (Geom::Point(0.,0.), Geom::Point(0.,0.)); - } else { - bb = *bb_opt; - fa = *fa_opt; } - + Geom::Rect fa = *fa_opt; // x, y, width, and height are independently defined (i.e. one can be defined, by default, to // the filter area (via default value ) while another is defined relative to the bounding @@ -138,6 +133,14 @@ Geom::Rect FilterPrimitive::filter_primitive_area(FilterUnits const &units) if( units.get_primitive_units() == SP_FILTER_UNITS_OBJECTBOUNDINGBOX ) { + Geom::OptRect const bb_opt = units.get_item_bbox(); + if (!bb_opt) { + std::cerr << "FilterPrimitive::filter_primitive_area: bounding box undefined and 'primitiveUnits' is 'objectBoundingBox'." << std::endl; + return Geom::Rect (Geom::Point(0.,0.), Geom::Point(0.,0.)); + } + Geom::Rect bb = *bb_opt; + + // Update computed values for ex, em, %. // For %, assumes primitive unit is objectBoundingBox. // TODO: fetch somehow the object ex and em lengths; 12, 6 are just dummy values. diff --git a/src/display/nr-filter-slot.cpp b/src/display/nr-filter-slot.cpp index e4c2f048e..a6e0c5c4e 100644 --- a/src/display/nr-filter-slot.cpp +++ b/src/display/nr-filter-slot.cpp @@ -232,6 +232,27 @@ void FilterSlot::set(int slot_nr, cairo_surface_t *surface) _last_out = slot_nr; } +void FilterSlot::set_primitive_area(int slot_nr, Geom::Rect &area) +{ + if (slot_nr == NR_FILTER_SLOT_NOT_SET) + slot_nr = NR_FILTER_UNNAMED_SLOT; + + _primitiveAreas[slot_nr] = area; +} + +Geom::Rect FilterSlot::get_primitive_area(int slot_nr) +{ + if (slot_nr == NR_FILTER_SLOT_NOT_SET) + slot_nr = _last_out; + + PrimitiveAreaMap::iterator s = _primitiveAreas.find(slot_nr); + + if (s == _primitiveAreas.end()) { + return *(_units.get_filter_area()); + } + return s->second; +} + int FilterSlot::get_slot_count() { return _slots.size(); diff --git a/src/display/nr-filter-slot.h b/src/display/nr-filter-slot.h index 987dedfd1..166b2e718 100644 --- a/src/display/nr-filter-slot.h +++ b/src/display/nr-filter-slot.h @@ -54,6 +54,9 @@ public: cairo_surface_t *get_result(int slot_nr); + void set_primitive_area(int slot, Geom::Rect &area); + Geom::Rect get_primitive_area(int slot); + /** Returns the number of slots in use. */ int get_slot_count(); @@ -75,6 +78,11 @@ public: private: typedef std::map<int, cairo_surface_t *> SlotMap; SlotMap _slots; + + // We need to keep track of the primitive area as this is needed in feTile + typedef std::map<int, Geom::Rect> PrimitiveAreaMap; + PrimitiveAreaMap _primitiveAreas; + DrawingItem *_item; //Geom::Rect _source_bbox; ///< bounding box of source graphic surface diff --git a/src/display/nr-filter-tile.cpp b/src/display/nr-filter-tile.cpp index 93ca50210..913812828 100644 --- a/src/display/nr-filter-tile.cpp +++ b/src/display/nr-filter-tile.cpp @@ -10,6 +10,8 @@ */ #include <glib.h> + +#include "display/cairo-utils.h" #include "display/nr-filter-tile.h" #include "display/nr-filter-slot.h" #include "display/nr-filter-units.h" @@ -30,16 +32,105 @@ FilterTile::~FilterTile() void FilterTile::render_cairo(FilterSlot &slot) { + // FIX ME! static bool tile_warning = false; - -//IMPLEMENT ME! if (!tile_warning) { - g_warning("Renderer for feTile is not implemented."); + g_warning("Renderer for feTile has non-optimal implementation, expect slowness and bugs."); tile_warning = true; } + // Fixing isn't so easy as the Inkscape renderer breaks the canvas into "rendering" tiles for + // faster rendering. (The "rendering" tiles are not the same as the tiles in this primitive.) + // Only if the the feTile tile source falls inside the current "rendering" tile will the tile + // image be available. + + // This input source contains only the "rendering" tile. cairo_surface_t *in = slot.getcairo(_input); - slot.set(_output, in); + + // For debugging + // static int i = 0; + // ++i; + // std::stringstream filename; + // filename << "dump." << i << ".png"; + // cairo_surface_write_to_png( in, filename.str().c_str() ); + + // This is the feTile source area as determined by the input primitive area (see SVG spec). + Geom::Rect tile_area = slot.get_primitive_area(_input); + + if( tile_area.width() == 0.0 || tile_area.height() == 0.0 ) { + + slot.set(_output, in); + std::cerr << "FileTile::render_cairo: tile has zero width or height" << std::endl; + + } else { + + cairo_surface_t *out = ink_cairo_surface_create_identical(in); + // color_interpolation_filters for out same as in. + copy_cairo_surface_ci(in, out); + cairo_t *ct = cairo_create(out); + + // The rectangle of the "rendering" tile. + Geom::Rect sa = slot.get_slot_area(); + + Geom::Affine trans = slot.get_units().get_matrix_user2pb(); + + // Create feTile tile ---------------- + + // Get tile area in pixbuf units (tile transformed). + Geom::Rect tt = tile_area * trans; + + // Shift between "rendering" tile and feTile tile + Geom::Point shift = sa.min() - tt.min(); + + // Create feTile tile surface + cairo_surface_t *tile = cairo_surface_create_similar(in, cairo_surface_get_content(in), + tt.width(), tt.height()); + cairo_t *ct_tile = cairo_create(tile); + cairo_set_source_surface(ct_tile, in, shift[Geom::X], shift[Geom::Y]); + cairo_paint(ct_tile); + + // Paint tiles ------------------ + + // For debugging + // std::stringstream filename; + // filename << "tile." << i << ".png"; + // cairo_surface_write_to_png( tile, filename.str().c_str() ); + + // Determine number of feTile rows and columns + Geom::Rect pr = filter_primitive_area( slot.get_units() ); + int tile_cols = ceil( pr.width() / tile_area.width() ); + int tile_rows = ceil( pr.height() / tile_area.height() ); + + // Do tiling (TO DO: restrict to slot area.) + for( int col=0; col < tile_cols; ++col ) { + for( int row=0; row < tile_rows; ++row ) { + + Geom::Point offset( col*tile_area.width(), row*tile_area.height() ); + offset *= trans; + offset[Geom::X] -= trans[4]; + offset[Geom::Y] -= trans[5]; + + cairo_set_source_surface(ct, tile, offset[Geom::X], offset[Geom::Y]); + cairo_paint(ct); + } + } + slot.set(_output, out); + + // Clean up + cairo_destroy(ct); + cairo_surface_destroy(out); + cairo_destroy(ct_tile); + cairo_surface_destroy(tile); + } +} + +void FilterTile::area_enlarge(Geom::IntRect &area, Geom::Affine const &trans) +{ + // We need to enlarge enough to get tile source... we don't the area of the source tile in this + // function so we guess. This is VERY inefficient. + Geom::Point enlarge(200, 200); + enlarge *= trans; + area.expandBy( enlarge[Geom::X] < 100 ? 100: enlarge[Geom::X] ); } double FilterTile::complexity(Geom::Affine const &) diff --git a/src/display/nr-filter-tile.h b/src/display/nr-filter-tile.h index 29087f2d6..239ecff4b 100644 --- a/src/display/nr-filter-tile.h +++ b/src/display/nr-filter-tile.h @@ -26,6 +26,7 @@ public: virtual ~FilterTile(); virtual void render_cairo(FilterSlot &slot); + virtual void area_enlarge(Geom::IntRect &area, Geom::Affine const &trans); virtual double complexity(Geom::Affine const &ctm); }; diff --git a/src/display/nr-style.cpp b/src/display/nr-style.cpp index 1740785e2..8b82a1dff 100644 --- a/src/display/nr-style.cpp +++ b/src/display/nr-style.cpp @@ -68,7 +68,6 @@ NRStyle::NRStyle() , tspan_width(0) , ascender(0) , descender(0) - , line_gap(0) , underline_thickness(0) , underline_position(0) , line_through_thickness(0) @@ -330,7 +329,6 @@ void NRStyle::set(SPStyle *style, SPStyle *context_style) tspan_width = style->text_decoration_data.tspan_width; ascender = style->text_decoration_data.ascender; descender = style->text_decoration_data.descender; - line_gap = style->text_decoration_data.line_gap; underline_thickness = style->text_decoration_data.underline_thickness; underline_position = style->text_decoration_data.underline_position; line_through_thickness = style->text_decoration_data.line_through_thickness; diff --git a/src/display/nr-style.h b/src/display/nr-style.h index 5f78795d3..6c652311a 100644 --- a/src/display/nr-style.h +++ b/src/display/nr-style.h @@ -115,7 +115,6 @@ struct NRStyle { float tspan_width; float ascender; float descender; - float line_gap; float underline_thickness; float underline_position; float line_through_thickness; diff --git a/src/display/sp-ctrlpoint.cpp b/src/display/sp-ctrlpoint.cpp index 1082cb1b3..19dbbc130 100644 --- a/src/display/sp-ctrlpoint.cpp +++ b/src/display/sp-ctrlpoint.cpp @@ -42,7 +42,8 @@ sp_ctrlpoint_init (SPCtrlPoint *ctrlpoint) ctrlpoint->rgba = 0x0000ff7f; ctrlpoint->pt[Geom::X] = ctrlpoint->pt[Geom::Y] = 0.0; ctrlpoint->item=NULL; - ctrlpoint->radius = 2; + ctrlpoint->lenght = 4; + ctrlpoint->is_circle = true; } static void sp_ctrlpoint_destroy(SPCanvasItem *object) @@ -75,8 +76,11 @@ sp_ctrlpoint_render (SPCanvasItem *item, SPCanvasBuf *buf) cairo_new_path(buf->ct); Geom::Point pt = cp->pt * cp->affine; - - cairo_arc(buf->ct, pt[Geom::X] - buf->rect.left(), pt[Geom::Y] - buf->rect.top(), cp->radius, 0.0, 2 * M_PI); + if( cp->is_circle ) { + cairo_arc(buf->ct, pt[Geom::X] - buf->rect.left(), pt[Geom::Y] - buf->rect.top(), cp->lenght/2.0, 0.0, 2 * M_PI); + } else { + cairo_rectangle(buf->ct, pt[Geom::X] - buf->rect.left() - cp->lenght/2.0, pt[Geom::Y] - buf->rect.top() - cp->lenght/2.0 , cp->lenght, cp->lenght); + } cairo_stroke(buf->ct); } @@ -96,10 +100,10 @@ static void sp_ctrlpoint_update(SPCanvasItem *item, Geom::Affine const &affine, Geom::Point pt = cp->pt * affine; - item->x1 = pt[Geom::X] - cp->radius; - item->y1 = pt[Geom::Y] - cp->radius; - item->x2 = pt[Geom::X] + cp->radius; - item->y2 = pt[Geom::Y] + cp->radius; + item->x1 = pt[Geom::X] - cp->lenght; + item->y1 = pt[Geom::Y] - cp->lenght; + item->x2 = pt[Geom::X] + cp->lenght; + item->y2 = pt[Geom::Y] + cp->lenght; item->canvas->requestRedraw((int)item->x1 - 15, (int)item->y1 - 15, (int)item->x1 + 15, (int)item->y1 + 15); @@ -142,9 +146,15 @@ sp_ctrlpoint_set_coords (SPCtrlPoint *cp, const Geom::Point pt) } void -sp_ctrlpoint_set_radius (SPCtrlPoint *cp, const double r) +sp_ctrlpoint_set_lenght (SPCtrlPoint *cp, const double r) +{ + cp->lenght = r; +} + +void +sp_ctrlpoint_set_circle (SPCtrlPoint *cp, const bool circle) { - cp->radius = r; + cp->is_circle = circle; } /* diff --git a/src/display/sp-ctrlpoint.h b/src/display/sp-ctrlpoint.h index a7a5475b7..02e61caf0 100644 --- a/src/display/sp-ctrlpoint.h +++ b/src/display/sp-ctrlpoint.h @@ -25,7 +25,8 @@ struct SPCtrlPoint : public SPCanvasItem { guint32 rgba; Geom::Point pt; Geom::Affine affine; - double radius; + double lenght; + bool is_circle; }; struct SPCtrlPointClass : public SPCanvasItemClass{}; @@ -34,7 +35,8 @@ GType sp_ctrlpoint_get_type (void); void sp_ctrlpoint_set_color (SPCtrlPoint *cp, guint32 rgba); void sp_ctrlpoint_set_coords (SPCtrlPoint *cp, const gdouble x, const gdouble y); void sp_ctrlpoint_set_coords (SPCtrlPoint *cp, const Geom::Point pt); -void sp_ctrlpoint_set_radius (SPCtrlPoint *cp, const double r); +void sp_ctrlpoint_set_lenght (SPCtrlPoint *cp, const double r); +void sp_ctrlpoint_set_circle (SPCtrlPoint *cp, const bool circle); diff --git a/src/document.cpp b/src/document.cpp index 2ea969910..23d99d78c 100644 --- a/src/document.cpp +++ b/src/document.cpp @@ -1335,51 +1335,64 @@ SPItem *SPDocument::getItemFromListAtPointBottom(unsigned int dkey, SPGroup *gro } /** -Returns the topmost (in z-order) item from the descendants of group (recursively) which -is at the point p, or NULL if none. Honors into_groups on whether to recurse into -non-layer groups or not. Honors take_insensitive on whether to return insensitive -items. If upto != NULL, then if item upto is encountered (at any level), stops searching -upwards in z-order and returns what it has found so far (i.e. the found item is -guaranteed to be lower than upto). - */ -static SPItem *find_item_at_point(unsigned int dkey, SPGroup *group, Geom::Point const &p, gboolean into_groups, bool take_insensitive = false, SPItem *upto = NULL) +Turn the SVG DOM into a flat list of nodes that can be searched from top-down. +The list can be persisted, which improves "find at multiple points" speed. +Returns true if upto is reached. +*/ +static bool build_flat_item_list(std::deque<SPItem*> *nodes, unsigned int dkey, SPGroup *group, gboolean into_groups, bool take_insensitive = false, SPItem *upto = NULL) { - SPItem *seen = NULL; - SPItem *newseen = NULL; - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - gdouble delta = prefs->getDouble("/options/cursortolerance/value", 1.0); - + bool found_upto = false; for ( SPObject *o = group->firstChild() ; o ; o = o->getNext() ) { if (!SP_IS_ITEM(o)) { continue; } if (upto && SP_ITEM(o) == upto) { + found_upto = true; break; } if (SP_IS_GROUP(o) && (SP_GROUP(o)->effectiveLayerMode(dkey) == SPGroup::LAYER || into_groups)) { - // if nothing found yet, recurse into the group - newseen = find_item_at_point(dkey, SP_GROUP(o), p, into_groups, take_insensitive, upto); - if (newseen) { - seen = newseen; - newseen = NULL; - } - - if (item_is_in_group(upto, SP_GROUP(o))) { + found_upto = build_flat_item_list(nodes, dkey, SP_GROUP(o), into_groups, take_insensitive, upto); + if (found_upto) break; - } } else { SPItem *child = SP_ITEM(o); - Inkscape::DrawingItem *arenaitem = child->get_arenaitem(dkey); - // seen remembers the last (topmost) of items pickable at this point - if (arenaitem && arenaitem->pick(p, delta, 1) != NULL - && (take_insensitive || child->isVisibleAndUnlocked(dkey))) { - seen = child; + if (take_insensitive || child->isVisibleAndUnlocked(dkey)) { + nodes->push_front(child); } } } + return found_upto; +} + +/** +Returns the topmost (in z-order) item from the descendants of group (recursively) which +is at the point p, or NULL if none. Honors into_groups on whether to recurse into +non-layer groups or not. Honors take_insensitive on whether to return insensitive +items. If upto != NULL, then if item upto is encountered (at any level), stops searching +upwards in z-order and returns what it has found so far (i.e. the found item is +guaranteed to be lower than upto). Requires a list of nodes built by +build_flat_item_list. + */ +static SPItem *find_item_at_point(std::deque<SPItem*> *nodes, unsigned int dkey, Geom::Point const &p) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + gdouble delta = prefs->getDouble("/options/cursortolerance/value", 1.0); + + SPItem *seen = NULL; + SPItem *child; + for (unsigned long i = 0; i < nodes->size(); ++i) { + child = nodes->at(i); + Inkscape::DrawingItem *arenaitem = child->get_arenaitem(dkey); + + if (arenaitem && arenaitem->pick(p, delta, 1) != NULL) { + seen = child; + break; + } + } + return seen; } @@ -1443,7 +1456,7 @@ std::vector<SPItem*> SPDocument::getItemsPartiallyInBox(unsigned int dkey, Geom: return find_items_in_area(x, SP_GROUP(this->root), dkey, box, overlaps); } -std::vector<SPItem*> SPDocument::getItemsAtPoints(unsigned const key, std::vector<Geom::Point> points) const +std::vector<SPItem*> SPDocument::getItemsAtPoints(unsigned const key, std::vector<Geom::Point> points, bool all_layers, size_t limit) const { std::vector<SPItem*> items; Inkscape::Preferences *prefs = Inkscape::Preferences::get(); @@ -1454,11 +1467,28 @@ std::vector<SPItem*> SPDocument::getItemsAtPoints(unsigned const key, std::vecto gdouble saved_delta = prefs->getDouble("/options/cursortolerance/value", 1.0); prefs->setDouble("/options/cursortolerance/value", 0.25); + // Cache a flattened SVG DOM to speed up selection. + std::deque<SPItem*> nodes; + build_flat_item_list(&nodes, key, SP_GROUP(this->root), true, false, NULL); + SPObject *current_layer = SP_ACTIVE_DESKTOP->currentLayer(); + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + Inkscape::LayerModel *layer_model = NULL; + if(desktop){ + layer_model = desktop->layers; + } + size_t item_counter = 0; for(int i = points.size()-1;i>=0; i--) { - SPItem *item = getItemAtPoint(key, points[i], - false, NULL); + SPItem *item = find_item_at_point(&nodes, key, points[i]); if (item && items.end()==find(items.begin(),items.end(), item)) - items.push_back(item); + if(all_layers || (layer_model && layer_model->layerForObject(item) == current_layer)){ + items.push_back(item); + item_counter++; + //limit 0 = no limit + if(item_counter == limit){ + prefs->setDouble("/options/cursortolerance/value", saved_delta); + return items; + } + } } // and now we restore it back @@ -1472,7 +1502,11 @@ SPItem *SPDocument::getItemAtPoint( unsigned const key, Geom::Point const &p, { g_return_val_if_fail(this->priv != NULL, NULL); - return find_item_at_point(key, SP_GROUP(this->root), p, into_groups, false, upto); + // Build a flattened SVG DOM for find_item_at_point. + std::deque<SPItem*> nodes; + build_flat_item_list(&nodes, key, SP_GROUP(this->root), into_groups, false, upto); + + return find_item_at_point(&nodes, key, p); } SPItem *SPDocument::getGroupAtPoint(unsigned int key, Geom::Point const &p) const @@ -1482,7 +1516,6 @@ SPItem *SPDocument::getGroupAtPoint(unsigned int key, Geom::Point const &p) cons return find_group_at_point(key, SP_GROUP(this->root), p); } - // Resource management bool SPDocument::addResource(gchar const *key, SPObject *object) @@ -1501,7 +1534,15 @@ bool SPDocument::addResource(gchar const *key, SPObject *object) g_hash_table_insert(priv->resources, (gpointer) key, rlist); GQuark q = g_quark_from_string(key); - priv->resources_changed_signals[q].emit(); + + /*in general, do not send signal if the object has no id (yet), + it means the object is not completely built. + (happens when pasting swatches across documents, cf bug 1495106) + [this check should be more generally presend on emit() calls since + the backtrace is unusable with crashed from this cause] + */ + if(object->getId() || dynamic_cast<SPGroup*>(object) ) + priv->resources_changed_signals[q].emit(); result = true; } diff --git a/src/document.h b/src/document.h index dd1e295a2..be3f106d8 100644 --- a/src/document.h +++ b/src/document.h @@ -262,7 +262,7 @@ public: std::vector<SPItem*> getItemsInBox(unsigned int dkey, Geom::Rect const &box) const; std::vector<SPItem*> getItemsPartiallyInBox(unsigned int dkey, Geom::Rect const &box) const; SPItem *getItemAtPoint(unsigned int key, Geom::Point const &p, bool into_groups, SPItem *upto = NULL) const; - std::vector<SPItem*> getItemsAtPoints(unsigned const key, std::vector<Geom::Point> points) const; + std::vector<SPItem*> getItemsAtPoints(unsigned const key, std::vector<Geom::Point> points, bool all_layers = true, size_t limit = 0) const; SPItem *getGroupAtPoint(unsigned int key, Geom::Point const &p) const; void changeUriAndHrefs(char const *uri); diff --git a/src/extension/execution-env.cpp b/src/extension/execution-env.cpp index 29c2b5537..27d19fdff 100644 --- a/src/extension/execution-env.cpp +++ b/src/extension/execution-env.cpp @@ -61,7 +61,7 @@ ExecutionEnv::ExecutionEnv (Effect * effect, Inkscape::UI::View::View * doc, Imp if (desktop != NULL) { std::vector<SPItem*> selected = desktop->getSelection()->itemList(); - for(std::vector<SPItem*>::const_iterator x = selected.begin(); x != selected.end(); x++){ + for(std::vector<SPItem*>::const_iterator x = selected.begin(); x != selected.end(); ++x){ Glib::ustring selected_id; selected_id = (*x)->getId(); _selected.insert(_selected.end(), selected_id); diff --git a/src/extension/implementation/script.cpp b/src/extension/implementation/script.cpp index e07a3963c..52cc7a2ca 100644 --- a/src/extension/implementation/script.cpp +++ b/src/extension/implementation/script.cpp @@ -691,7 +691,7 @@ void Script::effect(Inkscape::Extension::Effect *module, std::vector<SPItem*> selected = desktop->getSelection()->itemList(); //desktop should not be NULL since doc was checked and desktop is a casted pointer - for(std::vector<SPItem*>::const_iterator x = selected.begin(); x != selected.end(); x++){ + for(std::vector<SPItem*>::const_iterator x = selected.begin(); x != selected.end(); ++x){ Glib::ustring selected_id; selected_id += "--id="; selected_id += (*x)->getId(); diff --git a/src/extension/internal/bitmap/imagemagick.cpp b/src/extension/internal/bitmap/imagemagick.cpp index bc0dd8e33..40d548a24 100644 --- a/src/extension/internal/bitmap/imagemagick.cpp +++ b/src/extension/internal/bitmap/imagemagick.cpp @@ -79,7 +79,7 @@ ImageMagickDocCache::ImageMagickDocCache(Inkscape::UI::View::View * view) : _imageItems = new SPItem*[selectCount]; // Loop through selected items - for (std::vector<SPItem*>::const_iterator i = selectedItemList.begin(); i != selectedItemList.end(); i++) { + for (std::vector<SPItem*>::const_iterator i = selectedItemList.begin(); i != selectedItemList.end(); ++i) { SPItem *item = *i; Inkscape::XML::Node *node = reinterpret_cast<Inkscape::XML::Node *>(item->getRepr()); if (!strcmp(node->name(), "image") || !strcmp(node->name(), "svg:image")) diff --git a/src/extension/internal/cairo-render-context.cpp b/src/extension/internal/cairo-render-context.cpp index c3e416184..97b84606f 100644 --- a/src/extension/internal/cairo-render-context.cpp +++ b/src/extension/internal/cairo-render-context.cpp @@ -1182,7 +1182,7 @@ CairoRenderContext::_createHatchPainter(SPPaintServer const *const paintserver, std::vector<SPHatchPath *> children(evil->hatchPaths()); for (int i = 0; i < overflow_steps; i++) { - for (std::vector<SPHatchPath *>::iterator iter = children.begin(); iter != children.end(); iter++) { + for (std::vector<SPHatchPath *>::iterator iter = children.begin(); iter != children.end(); ++iter) { SPHatchPath *path = *iter; _renderer->renderHatchPath(pattern_ctx, *path, dkey); } @@ -1677,8 +1677,8 @@ CairoRenderContext::renderGlyphtext(PangoFont *font, Geom::Affine const &font_ma cairo_save(_cr); cairo_set_font_face(_cr, font_face); - if (fc_pattern && FcPatternGetDouble(fc_pattern, FC_PIXEL_SIZE, 0, &size) != FcResultMatch) - size = 12.0; + //if (fc_pattern && FcPatternGetDouble(fc_pattern, FC_PIXEL_SIZE, 0, &size) != FcResultMatch) + // size = 12.0; // set the given font matrix cairo_matrix_t matrix; diff --git a/src/extension/internal/cairo-renderer.cpp b/src/extension/internal/cairo-renderer.cpp index 5a5553e97..a4561fd11 100644 --- a/src/extension/internal/cairo-renderer.cpp +++ b/src/extension/internal/cairo-renderer.cpp @@ -295,7 +295,7 @@ static void sp_group_render(SPGroup *group, CairoRenderContext *ctx) TRACE(("sp_group_render opacity: %f\n", SP_SCALE24_TO_FLOAT(item->style->opacity.value))); std::vector<SPObject*> l(group->childList(false)); - for(std::vector<SPObject*>::const_iterator x = l.begin(); x!= l.end(); x++){ + for(std::vector<SPObject*>::const_iterator x = l.begin(); x!= l.end(); ++x){ SPItem *item = dynamic_cast<SPItem*>(*x); if (item) { renderer->renderItem(ctx, item); diff --git a/src/extension/internal/emf-inout.cpp b/src/extension/internal/emf-inout.cpp index e88cf3d42..68b38f5ee 100644 --- a/src/extension/internal/emf-inout.cpp +++ b/src/extension/internal/emf-inout.cpp @@ -1174,10 +1174,7 @@ Emf::select_extpen(PEMF_CALLBACK_DATA d, int index) if (!d->dc[d->level].style.stroke_dasharray.values.empty() && (d->level==0 || (d->level>0 && d->dc[d->level].style.stroke_dasharray.values!=d->dc[d->level-1].style.stroke_dasharray.values))) d->dc[d->level].style.stroke_dasharray.values.clear(); for (unsigned int i=0; i<pEmr->elp.elpNumEntries; i++) { -// Doing it this way typically results in a pattern that is tiny, better to assume the array -// is the same scale as for dot/dash below, that is, no scaling should be applied -// double dash_length = pix_to_abs_size( d, pEmr->elp.elpStyleEntry[i] ); - double dash_length = pEmr->elp.elpStyleEntry[i]; + double dash_length = pix_to_abs_size( d, pEmr->elp.elpStyleEntry[i] ); d->dc[d->level].style.stroke_dasharray.values.push_back(dash_length); } d->dc[d->level].style.stroke_dasharray.set = 1; diff --git a/src/extension/internal/emf-print.cpp b/src/extension/internal/emf-print.cpp index 5b8aae655..cc798cc5f 100644 --- a/src/extension/internal/emf-print.cpp +++ b/src/extension/internal/emf-print.cpp @@ -708,7 +708,7 @@ int PrintEmf::create_pen(SPStyle const *style, const Geom::Affine &transform) n_dash = style->stroke_dasharray.values.size(); dash = new uint32_t[n_dash]; for (i = 0; i < n_dash; i++) { - dash[i] = style->stroke_dasharray.values[i]; + dash[i] = MAX(1, (uint32_t) round(scale * style->stroke_dasharray.values[i] * PX2WORLD)); } } } diff --git a/src/extension/internal/gdkpixbuf-input.cpp b/src/extension/internal/gdkpixbuf-input.cpp index f5fab1fa2..c15e28854 100644 --- a/src/extension/internal/gdkpixbuf-input.cpp +++ b/src/extension/internal/gdkpixbuf-input.cpp @@ -86,8 +86,13 @@ GdkpixbufInput::open(Inkscape::Extension::Input *mod, char const *uri) ir = new ImageResolution(uri); } if (ir && ir->ok()) { - xscale = 960.0 / floor(10.*ir->x() + .5); // round-off to 0.1 dpi - yscale = 960.0 / floor(10.*ir->y() + .5); + xscale = 960.0 / round(10.*ir->x()); // round-off to 0.1 dpi + yscale = 960.0 / round(10.*ir->y()); + // prevent crash on image with too small dpi (bug 1479193) + if (ir->x() <= .05) + xscale = 960.0; + if (ir->y() <= .05) + yscale = 960.0; } else { xscale = 96.0 / defaultxdpi; yscale = 96.0 / defaultxdpi; diff --git a/src/extension/internal/latex-text-renderer.cpp b/src/extension/internal/latex-text-renderer.cpp index 5933dd526..dec75aeb6 100644 --- a/src/extension/internal/latex-text-renderer.cpp +++ b/src/extension/internal/latex-text-renderer.cpp @@ -229,7 +229,7 @@ LaTeXTextRenderer::writePostamble() void LaTeXTextRenderer::sp_group_render(SPGroup *group) { std::vector<SPObject*> l = (group->childList(false)); - for(std::vector<SPObject*>::const_iterator x = l.begin(); x != l.end(); x++){ + for(std::vector<SPObject*>::const_iterator x = l.begin(); x != l.end(); ++x){ SPItem *item = dynamic_cast<SPItem*>(*x); if (item) { renderItem(item); diff --git a/src/extension/internal/metafile-print.cpp b/src/extension/internal/metafile-print.cpp index 2fb36be85..47ba5971c 100644 --- a/src/extension/internal/metafile-print.cpp +++ b/src/extension/internal/metafile-print.cpp @@ -285,8 +285,8 @@ void PrintMetafile::brush_classify(SPObject *parent, int depth, Inkscape::Pixbuf return; } char temp[32]; // large enough - temp[31] = '\0'; - strncpy(temp, pat_i->getAttribute("id"), 31); // Some names may be longer than [EW]MFhatch#_###### + strncpy(temp, pat_i->getAttribute("id"), sizeof(temp)-1); // Some names may be longer than [EW]MFhatch#_###### + temp[sizeof(temp)-1] = '\0'; hatch_classify(temp, hatchType, hatchColor, bkColor); if (*hatchType != -1) { return; diff --git a/src/extension/internal/pdfinput/pdf-input.cpp b/src/extension/internal/pdfinput/pdf-input.cpp index 363061734..c1940b16a 100644 --- a/src/extension/internal/pdfinput/pdf-input.cpp +++ b/src/extension/internal/pdfinput/pdf-input.cpp @@ -223,6 +223,7 @@ PdfImportDialog::PdfImportDialog(PDFDoc *doc, const gchar */*uri*/) _importViaInternal->set_can_focus(); _importViaInternal->set_relief(Gtk::RELIEF_NORMAL); _importViaInternal->set_mode(true); + _importViaInternal->set_active(true); _labelViaPoppler->set_line_wrap(true); _labelViaInternal->set_line_wrap(true); #endif diff --git a/src/extension/internal/pdfinput/svg-builder.cpp b/src/extension/internal/pdfinput/svg-builder.cpp index 58e2030d9..a448be639 100644 --- a/src/extension/internal/pdfinput/svg-builder.cpp +++ b/src/extension/internal/pdfinput/svg-builder.cpp @@ -498,6 +498,7 @@ void SvgBuilder::addShadedFill(GfxShading *shading, double *matrix, GfxPath *pat // Obtain clipping path's id from the URL gchar clip_path_id[32]; strncpy(clip_path_id, clip_path_url + 5, strlen(clip_path_url) - 6); + clip_path_id[sizeof (clip_path_id) - 1] = '\0'; SPObject *clip_obj = _doc->getObjectById(clip_path_id); if (clip_obj) { clip_obj->deleteObject(); diff --git a/src/file.cpp b/src/file.cpp index 984bf7e08..7ae7d238a 100644 --- a/src/file.cpp +++ b/src/file.cpp @@ -1068,6 +1068,7 @@ void sp_import_document(SPDesktop *desktop, SPDocument *clipdoc, bool in_place) // copy definitions desktop->doc()->importDefs(clipdoc); + Inkscape::XML::Node* clipboard = NULL; // copy objects std::vector<Inkscape::XML::Node*> pasted_objects; for (Inkscape::XML::Node *obj = root->firstChild() ; obj ; obj = obj->next()) { @@ -1082,6 +1083,7 @@ void sp_import_document(SPDesktop *desktop, SPDocument *clipdoc, bool in_place) continue; } if (!strcmp(obj->name(), "inkscape:clipboard")) { + clipboard = obj; continue; } Inkscape::XML::Node *obj_copy = obj->duplicate(target_document->getReprDoc()); @@ -1090,12 +1092,32 @@ void sp_import_document(SPDesktop *desktop, SPDocument *clipdoc, bool in_place) pasted_objects.push_back(obj_copy); } - // Change the selection to the freshly pasted objects + + /* take that stuff into account: + * if( use && selection->includes(use->get_original()) ){//we are copying something whose parent is also copied (!) + * transform = ((SPItem*)(use->get_original()->parent))->i2doc_affine().inverse() * transform; + * } + * + */ + std::vector<Inkscape::XML::Node*> pasted_objects_not; + if(clipboard) + for (Inkscape::XML::Node *obj = clipboard->firstChild() ; obj ; obj = obj->next()) { + if(target_document->getObjectById(obj->attribute("id"))) continue; + Inkscape::XML::Node *obj_copy = obj->duplicate(target_document->getReprDoc()); + target_parent->appendChild(obj_copy); + Inkscape::GC::release(obj_copy); + pasted_objects_not.push_back(obj_copy); + } Inkscape::Selection *selection = desktop->getSelection(); + selection->setReprList(pasted_objects_not); + Geom::Affine doc2parent = SP_ITEM(desktop->currentLayer())->i2doc_affine().inverse(); + sp_selection_apply_affine(selection, desktop->dt2doc() * doc2parent * desktop->doc2dt(), true, false, false); + sp_selection_delete(desktop); + + // Change the selection to the freshly pasted objects selection->setReprList(pasted_objects); // Apply inverse of parent transform - Geom::Affine doc2parent = SP_ITEM(desktop->currentLayer())->i2doc_affine().inverse(); sp_selection_apply_affine(selection, desktop->dt2doc() * doc2parent * desktop->doc2dt(), true, false, false); // Update (among other things) all curves in paths, for bounds() to work diff --git a/src/gradient-chemistry.cpp b/src/gradient-chemistry.cpp index 409e9f0e6..886bf484d 100644 --- a/src/gradient-chemistry.cpp +++ b/src/gradient-chemistry.cpp @@ -1571,7 +1571,7 @@ void sp_gradient_invert_selected_gradients(SPDesktop *desktop, Inkscape::PaintTa Inkscape::Selection *selection = desktop->getSelection(); const std::vector<SPItem*> list=selection->itemList(); - for (std::vector<SPItem*>::const_iterator i = list.begin(); i != list.end(); i++) { + for (std::vector<SPItem*>::const_iterator i = list.begin(); i != list.end(); ++i) { sp_item_gradient_invert_vector_color(*i, fill_or_stroke); } @@ -1596,7 +1596,7 @@ void sp_gradient_reverse_selected_gradients(SPDesktop *desktop) drag->selected_reverse_vector(); } else { // If no drag or no dragger selected, act on selection (both fill and stroke gradients) const std::vector<SPItem*> list=selection->itemList(); - for (std::vector<SPItem*>::const_iterator i = list.begin(); i != list.end(); i++) { + for (std::vector<SPItem*>::const_iterator i = list.begin(); i != list.end(); ++i) { sp_item_gradient_reverse_vector(*i, Inkscape::FOR_FILL); sp_item_gradient_reverse_vector(*i, Inkscape::FOR_STROKE); } diff --git a/src/gradient-drag.cpp b/src/gradient-drag.cpp index b5a988729..f94ffb838 100644 --- a/src/gradient-drag.cpp +++ b/src/gradient-drag.cpp @@ -2083,7 +2083,7 @@ void GrDrag::updateDraggers() g_return_if_fail(this->selection != NULL); std::vector<SPItem*> list = this->selection->itemList(); - for (std::vector<SPItem*>::const_iterator i = list.begin(); i != list.end(); i++) { + for (std::vector<SPItem*>::const_iterator i = list.begin(); i != list.end(); ++i) { SPItem *item = *i; SPStyle *style = item->style; @@ -2152,7 +2152,7 @@ void GrDrag::updateLines() g_return_if_fail(this->selection != NULL); std::vector<SPItem*> list = this->selection->itemList(); - for (std::vector<SPItem*>::const_iterator i = list.begin(); i != list.end(); i++) { + for (std::vector<SPItem*>::const_iterator i = list.begin(); i != list.end(); ++i) { SPItem *item = *i; SPStyle *style = item->style; @@ -2296,7 +2296,7 @@ void GrDrag::updateLevels() g_return_if_fail (this->selection != NULL); std::vector<SPItem*> list = this->selection->itemList(); - for (std::vector<SPItem*>::const_iterator i = list.begin(); i != list.end(); i++) { + for (std::vector<SPItem*>::const_iterator i = list.begin(); i != list.end(); ++i) { SPItem *item = *i; Geom::OptRect rect = item->desktopVisualBounds(); if (rect) { diff --git a/src/graphlayout.cpp b/src/graphlayout.cpp index 40994347c..9b67ba0b5 100644 --- a/src/graphlayout.cpp +++ b/src/graphlayout.cpp @@ -89,7 +89,7 @@ struct CheckProgress : TestConvergence { * not connectors in filtered */ void filterConnectors(std::vector<SPItem*> const &items, list<SPItem *> &filtered) { - for(std::vector<SPItem*>::const_iterator i = items.begin();i !=items.end(); i++){ + for(std::vector<SPItem*>::const_iterator i = items.begin();i !=items.end(); ++i){ SPItem *item = *i; if(!isConnector(item)) { filtered.push_back(item); diff --git a/src/helper/png-write.cpp b/src/helper/png-write.cpp index fc365c435..9430feeff 100644 --- a/src/helper/png-write.cpp +++ b/src/helper/png-write.cpp @@ -128,6 +128,9 @@ sp_png_write_rgba_striped(SPDocument *doc, int (* get_rows)(guchar const **rows, void **to_free, int row, int num_rows, void *data), void *data) { + g_return_val_if_fail(filename != NULL, false); + g_return_val_if_fail(data != NULL, false); + struct SPEBP *ebp = (struct SPEBP *) data; FILE *fp; png_structp png_ptr; @@ -135,9 +138,6 @@ sp_png_write_rgba_striped(SPDocument *doc, png_color_8 sig_bit; png_uint_32 r; - g_return_val_if_fail(filename != NULL, false); - g_return_val_if_fail(data != NULL, false); - /* open the file */ Inkscape::IO::dump_fopen_call(filename, "M"); diff --git a/src/io/streamtest.cpp b/src/io/streamtest.cpp index 2030e6a85..ec59ac4a6 100644 --- a/src/io/streamtest.cpp +++ b/src/io/streamtest.cpp @@ -202,6 +202,7 @@ void path_init(char *path, char *name) exit(1); } strncpy(ptr+1,name,strlen(name)+1); + path[PATH_MAX-1] = '\0'; printf("'%s'\n",path); } diff --git a/src/knot-holder-entity.h b/src/knot-holder-entity.h index 43ab25e5c..63a068cab 100644 --- a/src/knot-holder-entity.h +++ b/src/knot-holder-entity.h @@ -44,7 +44,10 @@ public: item(NULL), desktop(NULL), parent_holder(NULL), - my_counter(0) + my_counter(0), + handler_id(0), + _click_handler_id(0), + _ungrab_handler_id(0) {} virtual ~KnotHolderEntity(); diff --git a/src/libcroco/cr-additional-sel.c b/src/libcroco/cr-additional-sel.c index 5a37eba6c..c34b8d243 100644 --- a/src/libcroco/cr-additional-sel.c +++ b/src/libcroco/cr-additional-sel.c @@ -247,7 +247,7 @@ cr_additional_sel_to_string (CRAdditionalSel const * a_this) guchar *name = NULL; if (cur->content.class_name) { - name = g_strndup + name = (guchar *) g_strndup (cur->content.class_name->stryng->str, cur->content.class_name->stryng->len); @@ -266,8 +266,8 @@ cr_additional_sel_to_string (CRAdditionalSel const * a_this) { guchar *name = NULL; - if (cur->content.class_name) { - name = g_strndup + if (cur->content.id_name) { + name = (guchar *) g_strndup (cur->content.id_name->stryng->str, cur->content.id_name->stryng->len); @@ -323,7 +323,7 @@ cr_additional_sel_to_string (CRAdditionalSel const * a_this) } if (str_buf) { - result = str_buf->str; + result = (guchar *) str_buf->str; g_string_free (str_buf, FALSE); str_buf = NULL; } @@ -347,7 +347,7 @@ cr_additional_sel_one_to_string (CRAdditionalSel const *a_this) guchar *name = NULL; if (a_this->content.class_name) { - name = g_strndup + name = (guchar *) g_strndup (a_this->content.class_name->stryng->str, a_this->content.class_name->stryng->len); @@ -366,8 +366,8 @@ cr_additional_sel_one_to_string (CRAdditionalSel const *a_this) { guchar *name = NULL; - if (a_this->content.class_name) { - name = g_strndup + if (a_this->content.id_name) { + name = (guchar *) g_strndup (a_this->content.id_name->stryng->str, a_this->content.id_name->stryng->len); @@ -422,7 +422,7 @@ cr_additional_sel_one_to_string (CRAdditionalSel const *a_this) } if (str_buf) { - result = str_buf->str; + result = (guchar *) str_buf->str; g_string_free (str_buf, FALSE); str_buf = NULL; } diff --git a/src/libcroco/cr-attr-sel.c b/src/libcroco/cr-attr-sel.c index 7976ff1f8..31d9da579 100644 --- a/src/libcroco/cr-attr-sel.c +++ b/src/libcroco/cr-attr-sel.c @@ -123,10 +123,10 @@ cr_attr_sel_to_string (CRAttrSel const * a_this) if (cur->name) { guchar *name = NULL; - name = g_strndup (cur->name->stryng->str, + name = (guchar *) g_strndup (cur->name->stryng->str, cur->name->stryng->len); if (name) { - g_string_append (str_buf, name); + g_string_append (str_buf, (const gchar *) name); g_free (name); name = NULL; } @@ -135,7 +135,7 @@ cr_attr_sel_to_string (CRAttrSel const * a_this) if (cur->value) { guchar *value = NULL; - value = g_strndup (cur->value->stryng->str, + value = (guchar *) g_strndup (cur->value->stryng->str, cur->value->stryng->len); if (value) { switch (cur->match_way) { @@ -168,7 +168,7 @@ cr_attr_sel_to_string (CRAttrSel const * a_this) } if (str_buf) { - result = str_buf->str; + result = (guchar *) str_buf->str; g_string_free (str_buf, FALSE); } diff --git a/src/libcroco/cr-cascade.c b/src/libcroco/cr-cascade.c index 31e938bb7..9f8dbdf8d 100644 --- a/src/libcroco/cr-cascade.c +++ b/src/libcroco/cr-cascade.c @@ -75,8 +75,8 @@ cr_cascade_new (CRStyleSheet * a_author_sheet, PRIVATE (result) = g_try_malloc (sizeof (CRCascadePriv)); if (!PRIVATE (result)) { - g_free(result); cr_utils_trace_info ("Out of memory"); + g_free (result); return NULL; } memset (PRIVATE (result), 0, sizeof (CRCascadePriv)); diff --git a/src/libcroco/cr-declaration.c b/src/libcroco/cr-declaration.c index ab150a9e4..69c24b376 100644 --- a/src/libcroco/cr-declaration.c +++ b/src/libcroco/cr-declaration.c @@ -48,7 +48,7 @@ dump (CRDeclaration const * a_this, FILE * a_fp, glong a_indent) g_return_if_fail (a_this); - str = cr_declaration_to_string (a_this, a_indent); + str = (guchar *) cr_declaration_to_string (a_this, a_indent); if (str) { fprintf (a_fp, "%s", str); g_free (str); @@ -130,7 +130,7 @@ cr_declaration_parse_from_buf (CRStatement * a_statement, g_return_val_if_fail (a_statement->type == RULESET_STMT, NULL); - parser = cr_parser_new_from_buf ((guchar*)a_str, strlen (a_str), a_enc, FALSE); + parser = cr_parser_new_from_buf ((guchar*)a_str, strlen ((const char *) a_str), a_enc, FALSE); g_return_val_if_fail (parser, NULL); status = cr_parser_try_to_skip_spaces_and_comments (parser); @@ -194,7 +194,7 @@ cr_declaration_parse_list_from_buf (const guchar * a_str, g_return_val_if_fail (a_str, NULL); - parser = cr_parser_new_from_buf ((guchar*)a_str, strlen (a_str), a_enc, FALSE); + parser = cr_parser_new_from_buf ((guchar*)a_str, strlen ((const char *) a_str), a_enc, FALSE); g_return_val_if_fail (parser, NULL); status = cr_parser_get_tknzr (parser, &tokenizer); if (status != CR_OK || !tokenizer) { @@ -243,10 +243,10 @@ cr_declaration_parse_list_from_buf (const guchar * a_str, if (status != CR_OK || !property) { if (status == CR_END_OF_INPUT_ERROR) { status = CR_OK; // simply the end of input, do not delete what we got so far, just finish - break; + break; } else { continue; // even if one declaration is broken, it's no reason to discard others (see http://www.w3.org/TR/CSS21/syndata.html#declaration) - } + } } cur_decl = cr_declaration_new (NULL, property, value); if (cur_decl) { @@ -504,7 +504,7 @@ cr_declaration_to_string (CRDeclaration const * a_this, gulong a_indent) { GString *stringue = NULL; - guchar *str = NULL, + gchar *str = NULL, *result = NULL; g_return_val_if_fail (a_this, NULL); @@ -581,7 +581,7 @@ cr_declaration_list_to_string (CRDeclaration const * a_this, gulong a_indent) stringue = g_string_new (NULL); for (cur = a_this; cur; cur = cur->next) { - str = cr_declaration_to_string (cur, a_indent); + str = (guchar *) cr_declaration_to_string (cur, a_indent); if (str) { g_string_append_printf (stringue, "%s;", str); g_free (str); @@ -589,7 +589,7 @@ cr_declaration_list_to_string (CRDeclaration const * a_this, gulong a_indent) break; } if (stringue && stringue->str) { - result = stringue->str; + result = (guchar *) stringue->str; g_string_free (stringue, FALSE); } @@ -620,7 +620,7 @@ cr_declaration_list_to_string2 (CRDeclaration const * a_this, stringue = g_string_new (NULL); for (cur = a_this; cur; cur = cur->next) { - str = cr_declaration_to_string (cur, a_indent); + str = (guchar *) cr_declaration_to_string (cur, a_indent); if (str) { if (a_one_decl_per_line == TRUE) { if (cur->next) @@ -628,21 +628,21 @@ cr_declaration_list_to_string2 (CRDeclaration const * a_this, "%s;\n", str); else g_string_append (stringue, - str); + (const gchar *) str); } else { if (cur->next) g_string_append_printf (stringue, "%s;", str); else g_string_append (stringue, - str); + (const gchar *) str); } g_free (str); } else break; } if (stringue && stringue->str) { - result = stringue->str; + result = (guchar *) stringue->str; g_string_free (stringue, FALSE); } @@ -714,7 +714,7 @@ cr_declaration_get_by_prop_name (CRDeclaration * a_this, && cur->property->stryng && cur->property->stryng->str) { if (!strcmp (cur->property->stryng->str, - a_prop)) { + (const char *) a_prop)) { return cur; } } diff --git a/src/libcroco/cr-enc-handler.c b/src/libcroco/cr-enc-handler.c index b3e5b7eba..646bf1fe2 100644 --- a/src/libcroco/cr-enc-handler.c +++ b/src/libcroco/cr-enc-handler.c @@ -122,7 +122,7 @@ cr_enc_handler_resolve_enc_alias (const guchar * a_alias_name, g_ascii_strup (alias_name_up, -1); for (i = 0; gv_default_aliases[i].name; i++) { - if (!strcmp (gv_default_aliases[i].name, alias_name_up)) { + if (!strcmp (gv_default_aliases[i].name, (const gchar *) alias_name_up)) { *a_enc = gv_default_aliases[i].encoding; status = CR_OK; break; diff --git a/src/libcroco/cr-fonts.c b/src/libcroco/cr-fonts.c index 10f26c99c..78e261149 100644 --- a/src/libcroco/cr-fonts.c +++ b/src/libcroco/cr-fonts.c @@ -78,7 +78,7 @@ cr_font_family_to_string_real (CRFontFamily const * a_this, if (a_this->prev) { g_string_append_printf (*a_string, ", %s", name); } else { - g_string_append (*a_string, name); + g_string_append (*a_string, (const gchar *) name); } } if (a_walk_list == TRUE && a_this->next) { @@ -187,7 +187,7 @@ cr_font_family_to_string (CRFontFamily const * a_this, GString *stringue = NULL; if (!a_this) { - result = g_strdup ("NULL"); + result = (guchar *) g_strdup ("NULL"); g_return_val_if_fail (result, NULL); return result; } @@ -196,7 +196,7 @@ cr_font_family_to_string (CRFontFamily const * a_this, &stringue); if (status == CR_OK && stringue) { - result = stringue->str; + result = (guchar *) stringue->str; g_string_free (stringue, FALSE); stringue = NULL; @@ -420,7 +420,7 @@ cr_font_size_set_predefined_absolute_font_size (CRFontSize *a_this, enum CRPredefinedAbsoluteFontSize a_predefined) { g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ; - g_return_val_if_fail ((unsigned)a_predefined < NB_FONT_SIZE_TYPE, + g_return_val_if_fail ((unsigned)a_predefined < NB_PREDEFINED_ABSOLUTE_FONT_SIZES, CR_BAD_PARAM_ERROR) ; a_this->type = PREDEFINED_ABSOLUTE_FONT_SIZE ; @@ -526,7 +526,7 @@ cr_font_size_to_string (CRFontSize const * a_this) (a_this->value.predefined)); break; case ABSOLUTE_FONT_SIZE: - str = cr_num_to_string (&a_this->value.absolute); + str = (gchar *) cr_num_to_string (&a_this->value.absolute); break; case RELATIVE_FONT_SIZE: str = g_strdup (cr_relative_font_size_to_string @@ -683,7 +683,7 @@ cr_font_size_adjust_to_string (CRFontSizeAdjust const * a_this) break; case FONT_SIZE_ADJUST_NUMBER: if (a_this->num) - str = cr_num_to_string (a_this->num); + str = (gchar *) cr_num_to_string (a_this->num); else str = g_strdup ("unknow font-size-adjust property value"); /* Should raise an error no?*/ break; diff --git a/src/libcroco/cr-input.c b/src/libcroco/cr-input.c index 3cc283e01..5395ae214 100644 --- a/src/libcroco/cr-input.c +++ b/src/libcroco/cr-input.c @@ -746,7 +746,7 @@ enum CRStatus cr_input_peek_char (CRInput const * a_this, guint32 * a_char) { enum CRStatus status = CR_OK; - glong consumed = 0, + gulong consumed = 0, nb_bytes_left = 0; g_return_val_if_fail (a_this && PRIVATE (a_this) diff --git a/src/libcroco/cr-num.c b/src/libcroco/cr-num.c index a5c320bf2..6cc5150a1 100644 --- a/src/libcroco/cr-num.c +++ b/src/libcroco/cr-num.c @@ -105,7 +105,7 @@ cr_num_to_string (CRNum const * a_this) test_val = a_this->val - (glong) a_this->val; if (!test_val) { - tmp_char1 = g_strdup_printf ("%ld", (glong) a_this->val); + tmp_char1 = (guchar *) g_strdup_printf ("%ld", (glong) a_this->val); } else { /* We can't use g_ascii_dtostr, because that sometimes uses e notation (which wouldn't be a valid number in CSS). */ @@ -195,7 +195,7 @@ cr_num_to_string (CRNum const * a_this) } if (tmp_char2) { - result = g_strconcat (tmp_char1, tmp_char2, NULL); + result = (guchar *) g_strconcat ((gchar *) tmp_char1, tmp_char2, NULL); g_free (tmp_char1); } else { result = tmp_char1; diff --git a/src/libcroco/cr-om-parser.c b/src/libcroco/cr-om-parser.c index c1acb855c..596cd6e6b 100644 --- a/src/libcroco/cr-om-parser.c +++ b/src/libcroco/cr-om-parser.c @@ -39,9 +39,6 @@ struct _CROMParserPriv { #define PRIVATE(a_this) ((a_this)->priv) -// Unfortunately, C does not allow unnamed function arguments, so use this macro instead... -#define UNUSED(x) (void)(x) - /* *Forward declaration of a type defined later *in this file. @@ -210,12 +207,12 @@ static void start_font_face (CRDocHandler * a_this, CRParsingLocation *a_location) { - UNUSED(a_location); - enum CRStatus status = CR_OK; ParsingContext *ctxt = NULL; ParsingContext **ctxtptr = NULL; + (void) a_location; + g_return_if_fail (a_this); g_return_if_fail (a_this); @@ -307,8 +304,6 @@ static void charset (CRDocHandler * a_this, CRString * a_charset, CRParsingLocation *a_location) { - UNUSED(a_location); - enum CRStatus status = CR_OK; CRStatement *stmt = NULL, *stmt2 = NULL; @@ -317,6 +312,8 @@ charset (CRDocHandler * a_this, CRString * a_charset, ParsingContext *ctxt = NULL; ParsingContext **ctxtptr = NULL; + (void) a_location; + g_return_if_fail (a_this); ctxtptr = &ctxt; status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr); @@ -347,12 +344,12 @@ start_page (CRDocHandler * a_this, CRString * a_pseudo, CRParsingLocation *a_location) { - UNUSED(a_location); - enum CRStatus status = CR_OK; ParsingContext *ctxt = NULL; ParsingContext **ctxtptr = NULL; + (void) a_location; + g_return_if_fail (a_this); ctxtptr = &ctxt; status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr); @@ -390,18 +387,21 @@ end_page (CRDocHandler * a_this, CRString * a_page, CRString * a_pseudo_page) { - UNUSED(a_page); - UNUSED(a_pseudo_page); - enum CRStatus status = CR_OK; ParsingContext *ctxt = NULL; ParsingContext **ctxtptr = NULL; CRStatement *stmt = NULL; + (void) a_page; + (void) a_pseudo_page; + g_return_if_fail (a_this); + ctxtptr = &ctxt; status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr); + g_return_if_fail (status == CR_OK && ctxt); + g_return_if_fail (ctxt->cur_stmt && ctxt->cur_stmt->type == AT_PAGE_RULE_STMT && ctxt->stylesheet); @@ -419,6 +419,8 @@ end_page (CRDocHandler * a_this, cr_statement_destroy (ctxt->cur_stmt); ctxt->cur_stmt = NULL; } + a_page = NULL; /*keep compiler happy */ + a_pseudo_page = NULL; /*keep compiler happy */ } static void @@ -426,13 +428,13 @@ start_media (CRDocHandler * a_this, GList * a_media_list, CRParsingLocation *a_location) { - UNUSED(a_location); - enum CRStatus status = CR_OK; ParsingContext *ctxt = NULL; ParsingContext **ctxtptr = NULL; GList *media_list = NULL; + (void) a_location; + g_return_if_fail (a_this); ctxtptr = &ctxt; status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr); @@ -456,17 +458,20 @@ start_media (CRDocHandler * a_this, static void end_media (CRDocHandler * a_this, GList * a_media_list) { - UNUSED(a_media_list); - enum CRStatus status = CR_OK; ParsingContext *ctxt = NULL; ParsingContext **ctxtptr = NULL; CRStatement *stmts = NULL; + (void) a_media_list; + g_return_if_fail (a_this); + ctxtptr = &ctxt; status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr); + g_return_if_fail (status == CR_OK && ctxt); + g_return_if_fail (ctxt && ctxt->cur_media_stmt && ctxt->cur_media_stmt->type == AT_MEDIA_RULE_STMT @@ -474,6 +479,7 @@ end_media (CRDocHandler * a_this, GList * a_media_list) stmts = cr_statement_append (ctxt->stylesheet->statements, ctxt->cur_media_stmt); + if (!stmts) { cr_statement_destroy (ctxt->cur_media_stmt); ctxt->cur_media_stmt = NULL; @@ -484,6 +490,7 @@ end_media (CRDocHandler * a_this, GList * a_media_list) ctxt->cur_stmt = NULL ; ctxt->cur_media_stmt = NULL ; + a_media_list = NULL; } static void @@ -493,9 +500,6 @@ import_style (CRDocHandler * a_this, CRString * a_uri_default_ns, CRParsingLocation *a_location) { - UNUSED(a_uri_default_ns); - UNUSED(a_location); - enum CRStatus status = CR_OK; CRString *uri = NULL; CRStatement *stmt = NULL, @@ -504,17 +508,26 @@ import_style (CRDocHandler * a_this, ParsingContext **ctxtptr = NULL; GList *media_list = NULL ; + (void) a_uri_default_ns; + (void) a_location; + g_return_if_fail (a_this); + ctxtptr = &ctxt; status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr); + g_return_if_fail (status == CR_OK && ctxt); + g_return_if_fail (ctxt->stylesheet); uri = cr_string_dup (a_uri) ; + if (a_media_list) media_list = cr_utils_dup_glist_of_cr_string (a_media_list) ; + stmt = cr_statement_new_at_import_rule (ctxt->stylesheet, uri, media_list, NULL); + if (!stmt) goto error; @@ -546,6 +559,7 @@ import_style (CRDocHandler * a_this, cr_statement_destroy (stmt); stmt = NULL; } + a_uri_default_ns = NULL; /*keep compiler happy */ } static void @@ -572,16 +586,19 @@ start_selector (CRDocHandler * a_this, CRSelector * a_selector_list) static void end_selector (CRDocHandler * a_this, CRSelector * a_selector_list) { - UNUSED(a_selector_list); - enum CRStatus status = CR_OK; ParsingContext *ctxt = NULL; ParsingContext **ctxtptr = NULL; + (void) a_selector_list; + g_return_if_fail (a_this); + ctxtptr = &ctxt; status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr); + g_return_if_fail (status == CR_OK && ctxt); + g_return_if_fail (ctxt->cur_stmt && ctxt->stylesheet); if (ctxt->cur_stmt) { @@ -621,6 +638,8 @@ end_selector (CRDocHandler * a_this, CRSelector * a_selector_list) } } + + a_selector_list = NULL; /*keep compiler happy */ } static void diff --git a/src/libcroco/cr-parser.c b/src/libcroco/cr-parser.c index 69b521496..544b35ab0 100644 --- a/src/libcroco/cr-parser.c +++ b/src/libcroco/cr-parser.c @@ -78,7 +78,7 @@ typedef struct _CRParserError CRParserError; *parsing routines. */ struct _CRParserError { - gchar *msg; + guchar *msg; enum CRStatus status; glong line; glong column; @@ -197,9 +197,9 @@ if ((a_status) != CR_OK) \ */ #define PEEK_NEXT_CHAR(a_this, a_to_char) \ {\ -enum CRStatus status ; \ -status = cr_tknzr_peek_char (PRIVATE (a_this)->tknzr, a_to_char) ; \ -CHECK_PARSING_STATUS (status, TRUE) \ +enum CRStatus pnc_status ; \ +pnc_status = cr_tknzr_peek_char (PRIVATE (a_this)->tknzr, a_to_char) ; \ +CHECK_PARSING_STATUS (pnc_status, TRUE) \ } /** @@ -374,11 +374,11 @@ static enum CRStatus cr_parser_parse_simple_selector (CRParser * a_this, static enum CRStatus cr_parser_parse_simple_sels (CRParser * a_this, CRSimpleSel ** a_sel); -static CRParserError *cr_parser_error_new (const gchar * a_msg, +static CRParserError *cr_parser_error_new (const guchar * a_msg, enum CRStatus); static void cr_parser_error_set_msg (CRParserError * a_this, - const gchar * a_msg); + const guchar * a_msg); static void cr_parser_error_dump (CRParserError * a_this); @@ -392,7 +392,7 @@ static void cr_parser_error_destroy (CRParserError * a_this); static enum CRStatus cr_parser_push_error (CRParser * a_this, - const gchar * a_msg, + const guchar * a_msg, enum CRStatus a_status); static enum CRStatus cr_parser_dump_err_stack (CRParser * a_this, @@ -411,7 +411,7 @@ static enum CRStatus *@return the newly built instance of #CRParserError. */ static CRParserError * -cr_parser_error_new (const gchar * a_msg, enum CRStatus a_status) +cr_parser_error_new (const guchar * a_msg, enum CRStatus a_status) { CRParserError *result = NULL; @@ -436,7 +436,7 @@ cr_parser_error_new (const gchar * a_msg, enum CRStatus a_status) *@param a_msg the new message. */ static void -cr_parser_error_set_msg (CRParserError * a_this, const gchar * a_msg) +cr_parser_error_set_msg (CRParserError * a_this, const guchar * a_msg) { g_return_if_fail (a_this); @@ -444,7 +444,7 @@ cr_parser_error_set_msg (CRParserError * a_this, const gchar * a_msg) g_free (a_this->msg); } - a_this->msg = g_strdup (a_msg); + a_this->msg = (guchar *) g_strdup ((const gchar *) a_msg); } /** @@ -515,7 +515,7 @@ cr_parser_error_destroy (CRParserError * a_this) */ static enum CRStatus cr_parser_push_error (CRParser * a_this, - const gchar * a_msg, enum CRStatus a_status) + const guchar * a_msg, enum CRStatus a_status) { enum CRStatus status = CR_OK; @@ -733,7 +733,7 @@ cr_parser_parse_stylesheet_core (CRParser * a_this) error: cr_parser_push_error - (a_this, "could not recognize next production", CR_ERROR); + (a_this, (const guchar *) "could not recognize next production", CR_ERROR); cr_parser_dump_err_stack (a_this, TRUE); @@ -1688,14 +1688,12 @@ cr_parser_parse_simple_selector (CRParser * a_this, CRSimpleSel ** a_sel) && token->u.unichar == '*') { int comb = (int)sel->type_mask | (int) UNIVERSAL_SELECTOR; sel->type_mask = (enum SimpleSelectorType)comb; - //sel->type_mask |= UNIVERSAL_SELECTOR; sel->name = cr_string_new_from_string ("*"); found_sel = TRUE; } else if (token && token->type == IDENT_TK) { sel->name = token->u.str; int comb = (int)sel->type_mask | (int) TYPE_SELECTOR; sel->type_mask = (enum SimpleSelectorType)comb; - //sel->type_mask |= TYPE_SELECTOR; token->u.str = NULL; found_sel = TRUE; } else { @@ -2707,7 +2705,7 @@ cr_parser_parse_stylesheet (CRParser * a_this) } cr_parser_push_error - (a_this, "could not recognize next production", CR_ERROR); + (a_this, (const guchar *) "could not recognize next production", CR_ERROR); if (PRIVATE (a_this)->sac_handler && PRIVATE (a_this)->sac_handler->unrecoverable_error) { @@ -3193,7 +3191,7 @@ cr_parser_parse_declaration (CRParser * a_this, CHECK_PARSING_STATUS_ERR (a_this, status, FALSE, - "while parsing declaration: next property is malformed", + (const guchar *) "while parsing declaration: next property is malformed", CR_SYNTAX_ERROR); READ_NEXT_CHAR (a_this, &cur_char); @@ -3202,7 +3200,7 @@ cr_parser_parse_declaration (CRParser * a_this, status = CR_PARSING_ERROR; cr_parser_push_error (a_this, - "while parsing declaration: this char must be ':'", + (const guchar *) "while parsing declaration: this char must be ':'", CR_SYNTAX_ERROR); goto error; } @@ -3213,7 +3211,7 @@ cr_parser_parse_declaration (CRParser * a_this, CHECK_PARSING_STATUS_ERR (a_this, status, FALSE, - "while parsing declaration: next expression is malformed", + (const guchar *) "while parsing declaration: next expression is malformed", CR_SYNTAX_ERROR); cr_parser_try_to_skip_spaces_and_comments (a_this); @@ -3353,7 +3351,7 @@ cr_parser_parse_ruleset (CRParser * a_this) ENSURE_PARSING_COND_ERR (a_this, cur_char == '{', - "while parsing rulset: current char should be '{'", + (const guchar *) "while parsing rulset: current char should be '{'", CR_SYNTAX_ERROR); if (PRIVATE (a_this)->sac_handler @@ -3417,7 +3415,7 @@ cr_parser_parse_ruleset (CRParser * a_this) } CHECK_PARSING_STATUS_ERR (a_this, status, FALSE, - "while parsing ruleset: next construction should be a declaration", + (const guchar *) "while parsing ruleset: next construction should be a declaration", CR_SYNTAX_ERROR); for (;;) { @@ -3459,7 +3457,7 @@ cr_parser_parse_ruleset (CRParser * a_this) READ_NEXT_CHAR (a_this, &cur_char); ENSURE_PARSING_COND_ERR (a_this, cur_char == '}', - "while parsing rulset: current char must be a '}'", + (const guchar *) "while parsing rulset: current char must be a '}'", CR_SYNTAX_ERROR); selector->location = end_parsing_location; diff --git a/src/libcroco/cr-pseudo.c b/src/libcroco/cr-pseudo.c index a46e69ed0..cee3fc869 100644 --- a/src/libcroco/cr-pseudo.c +++ b/src/libcroco/cr-pseudo.c @@ -68,11 +68,11 @@ cr_pseudo_to_string (CRPseudo const * a_this) goto error; } - name = g_strndup (a_this->name->stryng->str, + name = (guchar *) g_strndup (a_this->name->stryng->str, a_this->name->stryng->len); if (name) { - g_string_append (str_buf, name); + g_string_append (str_buf, (const gchar *) name); g_free (name); name = NULL; } @@ -83,11 +83,11 @@ cr_pseudo_to_string (CRPseudo const * a_this) if (a_this->name == NULL) goto error; - name = g_strndup (a_this->name->stryng->str, + name = (guchar *) g_strndup (a_this->name->stryng->str, a_this->name->stryng->len); if (a_this->extra) { - arg = g_strndup (a_this->extra->stryng->str, + arg = (guchar *) g_strndup (a_this->extra->stryng->str, a_this->extra->stryng->len); } @@ -97,7 +97,7 @@ cr_pseudo_to_string (CRPseudo const * a_this) name = NULL; if (arg) { - g_string_append (str_buf, arg); + g_string_append (str_buf, (const gchar *) arg); g_free (arg); arg = NULL; } @@ -107,7 +107,7 @@ cr_pseudo_to_string (CRPseudo const * a_this) } if (str_buf) { - result = str_buf->str; + result = (guchar *) str_buf->str; g_string_free (str_buf, FALSE); str_buf = NULL; } diff --git a/src/libcroco/cr-rgb.c b/src/libcroco/cr-rgb.c index 537343579..889f248b6 100644 --- a/src/libcroco/cr-rgb.c +++ b/src/libcroco/cr-rgb.c @@ -275,7 +275,7 @@ cr_rgb_to_string (CRRgb const * a_this) } if (str_buf) { - result = str_buf->str; + result = (guchar *) str_buf->str; g_string_free (str_buf, FALSE); } @@ -507,7 +507,7 @@ cr_rgb_set_from_hex_str (CRRgb * a_this, const guchar * a_hex) g_return_val_if_fail (a_this && a_hex, CR_BAD_PARAM_ERROR); - if (strlen (a_hex) == 3) { + if (strlen ((const char *) a_hex) == 3) { for (i = 0; i < 3; i++) { if (a_hex[i] >= '0' && a_hex[i] <= '9') { colors[i] = a_hex[i] - '0'; @@ -522,7 +522,7 @@ cr_rgb_set_from_hex_str (CRRgb * a_this, const guchar * a_hex) status = CR_UNKNOWN_TYPE_ERROR; } } - } else if (strlen (a_hex) == 6) { + } else if (strlen ((const char *) a_hex) == 6) { for (i = 0; i < 6; i++) { if (a_hex[i] >= '0' && a_hex[i] <= '9') { colors[i / 2] <<= 4; @@ -587,7 +587,7 @@ cr_rgb_set_from_term (CRRgb *a_this, const struct _CRTerm *a_value) } else { status = cr_rgb_set_from_name (a_this, - a_value->content.str->stryng->str) ; + (const guchar *) a_value->content.str->stryng->str) ; } } else { cr_utils_trace_info @@ -600,7 +600,7 @@ cr_rgb_set_from_term (CRRgb *a_this, const struct _CRTerm *a_value) && a_value->content.str->stryng->str) { status = cr_rgb_set_from_hex_str (a_this, - a_value->content.str->stryng->str) ; + (const guchar *) a_value->content.str->stryng->str) ; } else { cr_utils_trace_info ("a_value has NULL string value") ; @@ -656,8 +656,7 @@ cr_rgb_parse_from_buf (const guchar *a_str, g_return_val_if_fail (a_str, NULL); - parser = cr_parser_new_from_buf ((guchar*)a_str, strlen (a_str), - a_enc, FALSE) ; + parser = cr_parser_new_from_buf ((guchar *) a_str, strlen ((const char *) a_str), a_enc, FALSE); g_return_val_if_fail (parser, NULL); diff --git a/src/libcroco/cr-sel-eng.c b/src/libcroco/cr-sel-eng.c index 4f501ee05..ed40de393 100644 --- a/src/libcroco/cr-sel-eng.c +++ b/src/libcroco/cr-sel-eng.c @@ -37,7 +37,7 @@ #define PRIVATE(a_this) (a_this)->priv struct CRPseudoClassSelHandlerEntry { - char *name; + guchar *name; enum CRPseudoType type; CRPseudoClassSelectorHandler handler; }; @@ -149,8 +149,8 @@ lang_pseudo_class_handler (CRSelEng *const a_this, || a_sel->content.pseudo->extra->stryng->len < 2) return FALSE; for (; node; node = get_next_parent_element_node (node_iface, node)) { - char *val = node_iface->getProp (node, "lang"); - if (!val) val = node_iface->getProp (node, "xml:lang"); + char *val = node_iface->getProp (node, (const xmlChar *) "lang"); + if (!val) val = node_iface->getProp (node, (const xmlChar *) "xml:lang"); if (val) { if (!strcasecmp(val, a_sel->content.pseudo->extra->stryng->str)) { result = TRUE; @@ -209,7 +209,7 @@ pseudo_class_add_sel_matches_node (CRSelEng * a_this, && a_node, FALSE); status = cr_sel_eng_get_pseudo_class_selector_handler - (a_this, a_add_sel->content.pseudo->name->stryng->str, + (a_this, (guchar *) a_add_sel->content.pseudo->name->stryng->str, a_add_sel->content.pseudo->type, &handler); if (status != CR_OK || !handler) return FALSE; @@ -237,7 +237,7 @@ class_add_sel_matches_node (CRAdditionalSel * a_add_sel, && a_add_sel->content.class_name->stryng->str && a_node, FALSE); - klass = a_node_iface->getProp (a_node, "class"); + klass = a_node_iface->getProp (a_node, (const xmlChar *) "class"); if (klass) { char const *cur; for (cur = klass; cur && *cur; cur++) { @@ -246,7 +246,7 @@ class_add_sel_matches_node (CRAdditionalSel * a_add_sel, == TRUE) cur++; - if (!strncmp (cur, + if (!strncmp ((const char *) cur, a_add_sel->content.class_name->stryng->str, a_add_sel->content.class_name->stryng->len)) { cur += a_add_sel->content.class_name->stryng->len; @@ -291,9 +291,9 @@ id_add_sel_matches_node (CRAdditionalSel * a_add_sel, && a_add_sel->type == ID_ADD_SELECTOR && a_node, FALSE); - id = a_node_iface->getProp (a_node, "id"); + id = a_node_iface->getProp (a_node, (const xmlChar *) "id"); if (id) { - if (!strqcmp (id, a_add_sel->content.id_name->stryng->str, + if (!strqcmp ((const char *) id, a_add_sel->content.id_name->stryng->str, a_add_sel->content.id_name->stryng->len)) { result = TRUE; } @@ -324,7 +324,7 @@ attr_add_sel_matches_node (CRAdditionalSel * a_add_sel, for (cur_sel = a_add_sel->content.attr_sel; cur_sel; cur_sel = cur_sel->next) { - if (!cur_sel->name + if (!cur_sel->name || !cur_sel->name->stryng || !cur_sel->name->stryng->str) return FALSE; @@ -384,7 +384,7 @@ attr_add_sel_matches_node (CRAdditionalSel * a_add_sel, ptr2 = cur; if (!strncmp - (ptr1, + ((const char *) ptr1, cur_sel->value->stryng->str, ptr2 - ptr1 + 1)) { found = TRUE; @@ -422,7 +422,7 @@ attr_add_sel_matches_node (CRAdditionalSel * a_add_sel, ptr2 = cur; if (g_strstr_len - (ptr1, ptr2 - ptr1 + 1, + ((const gchar *) ptr1, ptr2 - ptr1 + 1, cur_sel->value->stryng->str) == ptr1) { found = TRUE; @@ -635,7 +635,7 @@ sel_matches_node_real (CRSelEng * a_this, CRSimpleSel * a_sel, && cur_sel->name->stryng && cur_sel->name->stryng->str) && (!strcmp (cur_sel->name->stryng->str, - node_iface->getLocalName(cur_node)))) + (const char *) node_iface->getLocalName(cur_node)))) || (cur_sel->type_mask & UNIVERSAL_SELECTOR)) { /* *this simple selector @@ -1121,11 +1121,11 @@ cr_sel_eng_new (void) } memset (PRIVATE (result), 0, sizeof (CRSelEngPriv)); cr_sel_eng_register_pseudo_class_sel_handler - (result, "first-child", + (result, (guchar *) "first-child", IDENT_PSEUDO, /*(CRPseudoClassSelectorHandler)*/ first_child_pseudo_class_handler); cr_sel_eng_register_pseudo_class_sel_handler - (result, "lang", + (result, (guchar *) "lang", FUNCTION_PSEUDO, /*(CRPseudoClassSelectorHandler)*/ lang_pseudo_class_handler); @@ -1146,7 +1146,7 @@ cr_sel_eng_new (void) */ enum CRStatus cr_sel_eng_register_pseudo_class_sel_handler (CRSelEng * a_this, - char * a_name, + guchar * a_name, enum CRPseudoType a_type, CRPseudoClassSelectorHandler a_handler) @@ -1164,7 +1164,7 @@ cr_sel_eng_register_pseudo_class_sel_handler (CRSelEng * a_this, } memset (handler_entry, 0, sizeof (struct CRPseudoClassSelHandlerEntry)); - handler_entry->name = g_strdup (a_name); + handler_entry->name = (guchar *) g_strdup ((const gchar *) a_name); handler_entry->type = a_type; handler_entry->handler = a_handler; list = g_list_append (PRIVATE (a_this)->pcs_handlers, handler_entry); @@ -1177,7 +1177,7 @@ cr_sel_eng_register_pseudo_class_sel_handler (CRSelEng * a_this, enum CRStatus cr_sel_eng_unregister_pseudo_class_sel_handler (CRSelEng * a_this, - char * a_name, + guchar * a_name, enum CRPseudoType a_type) { GList *elem = NULL, @@ -1190,7 +1190,7 @@ cr_sel_eng_unregister_pseudo_class_sel_handler (CRSelEng * a_this, for (elem = PRIVATE (a_this)->pcs_handlers; elem; elem = g_list_next (elem)) { entry = (struct CRPseudoClassSelHandlerEntry *) elem->data; - if (!strcmp (entry->name, a_name) + if (!strcmp ((const char *) entry->name, (const char *) a_name) && entry->type == a_type) { found = TRUE; break; @@ -1250,7 +1250,7 @@ cr_sel_eng_unregister_all_pseudo_class_sel_handlers (CRSelEng * a_this) enum CRStatus cr_sel_eng_get_pseudo_class_selector_handler (CRSelEng * a_this, - char * a_name, + guchar * a_name, enum CRPseudoType a_type, CRPseudoClassSelectorHandler * a_handler) @@ -1265,7 +1265,7 @@ cr_sel_eng_get_pseudo_class_selector_handler (CRSelEng * a_this, for (elem = PRIVATE (a_this)->pcs_handlers; elem; elem = g_list_next (elem)) { entry = (struct CRPseudoClassSelHandlerEntry *) elem->data; - if (!strcmp (a_name, entry->name) + if (!strcmp ((const char *) a_name, (const char *) entry->name) && entry->type == a_type) { found = TRUE; break; diff --git a/src/libcroco/cr-sel-eng.h b/src/libcroco/cr-sel-eng.h index 4d09f9c95..564debc8d 100644 --- a/src/libcroco/cr-sel-eng.h +++ b/src/libcroco/cr-sel-eng.h @@ -65,18 +65,18 @@ typedef gboolean (*CRPseudoClassSelectorHandler) (CRSelEng* a_this, CRSelEng * cr_sel_eng_new (void) ; enum CRStatus cr_sel_eng_register_pseudo_class_sel_handler (CRSelEng *a_this, - char *a_pseudo_class_sel_name, + guchar *a_pseudo_class_sel_name, enum CRPseudoType a_pseudo_class_type, CRPseudoClassSelectorHandler a_handler) ; enum CRStatus cr_sel_eng_unregister_pseudo_class_sel_handler (CRSelEng *a_this, - char *a_pseudo_class_sel_name, + guchar *a_pseudo_class_sel_name, enum CRPseudoType a_pseudo_class_type) ; enum CRStatus cr_sel_eng_unregister_all_pseudo_class_sel_handlers (CRSelEng *a_this) ; enum CRStatus cr_sel_eng_get_pseudo_class_selector_handler (CRSelEng *a_this, - char *a_pseudo_class_sel_name, + guchar *a_pseudo_class_sel_name, enum CRPseudoType a_pseudo_class_type, CRPseudoClassSelectorHandler *a_handler) ; diff --git a/src/libcroco/cr-selector.c b/src/libcroco/cr-selector.c index 43a3bd914..c56c43fda 100644 --- a/src/libcroco/cr-selector.c +++ b/src/libcroco/cr-selector.c @@ -38,7 +38,10 @@ CRSelector * cr_selector_new (CRSimpleSel * a_simple_sel) { - CRSelector *result = (CRSelector *)g_try_malloc (sizeof (CRSelector)); + CRSelector *result = NULL; + + result = (CRSelector *) g_try_malloc (sizeof (CRSelector)); + if (!result) { cr_utils_trace_info ("Out of memory"); return NULL; @@ -55,8 +58,7 @@ cr_selector_parse_from_buf (const guchar * a_char_buf, enum CREncoding a_enc) g_return_val_if_fail (a_char_buf, NULL); - parser = cr_parser_new_from_buf ((guchar*)a_char_buf, - strlen ((char *)a_char_buf), + parser = cr_parser_new_from_buf ((guchar*)a_char_buf, strlen ((const char *) a_char_buf), a_enc, FALSE); g_return_val_if_fail (parser, NULL); @@ -140,8 +142,9 @@ guchar * cr_selector_to_string (CRSelector const * a_this) { guchar *result = NULL; + GString *str_buf = NULL; - GString *str_buf = (GString *)g_string_new (NULL); + str_buf = (GString *) g_string_new (NULL); g_return_val_if_fail (str_buf, NULL); if (a_this) { @@ -159,7 +162,7 @@ cr_selector_to_string (CRSelector const * a_this) g_string_append (str_buf, ", "); - g_string_append (str_buf, (gchar *)tmp_str); + g_string_append (str_buf, (const gchar *) tmp_str); g_free (tmp_str); tmp_str = NULL; @@ -169,7 +172,7 @@ cr_selector_to_string (CRSelector const * a_this) } if (str_buf) { - result = (guchar *)str_buf->str; + result = (guchar *) str_buf->str; g_string_free (str_buf, FALSE); str_buf = NULL; } diff --git a/src/libcroco/cr-simple-sel.c b/src/libcroco/cr-simple-sel.c index 4f5ac965a..a4670fe88 100644 --- a/src/libcroco/cr-simple-sel.c +++ b/src/libcroco/cr-simple-sel.c @@ -35,7 +35,9 @@ CRSimpleSel * cr_simple_sel_new (void) { - CRSimpleSel *result = (CRSimpleSel *)g_try_malloc (sizeof (CRSimpleSel)); + CRSimpleSel *result = NULL; + + result = (CRSimpleSel *) g_try_malloc (sizeof (CRSimpleSel)); if (!result) { cr_utils_trace_info ("Out of memory"); return NULL; @@ -110,7 +112,7 @@ cr_simple_sel_to_string (CRSimpleSel const * a_this) str_buf = g_string_new (NULL); for (cur = a_this; cur; cur = cur->next) { if (cur->name) { - gchar *str = g_strndup (cur->name->stryng->str, + guchar *str = (guchar *) g_strndup (cur->name->stryng->str, cur->name->stryng->len); if (str) { @@ -131,17 +133,18 @@ cr_simple_sel_to_string (CRSimpleSel const * a_this) break; } - g_string_append (str_buf, str); + g_string_append (str_buf, (const gchar *) str); g_free (str); str = NULL; } } if (cur->add_sel) { + guchar *tmp_str = NULL; - gchar *tmp_str = (gchar *)cr_additional_sel_to_string (cur->add_sel); + tmp_str = cr_additional_sel_to_string (cur->add_sel); if (tmp_str) { - g_string_append (str_buf, tmp_str); + g_string_append (str_buf, (const gchar *) tmp_str); g_free (tmp_str); tmp_str = NULL; } @@ -149,7 +152,7 @@ cr_simple_sel_to_string (CRSimpleSel const * a_this) } if (str_buf) { - result = (guchar *)str_buf->str; + result = (guchar *) str_buf->str; g_string_free (str_buf, FALSE); str_buf = NULL; } @@ -168,7 +171,7 @@ cr_simple_sel_one_to_string (CRSimpleSel const * a_this) str_buf = g_string_new (NULL); if (a_this->name) { - gchar *str = g_strndup (a_this->name->stryng->str, + guchar *str = (guchar *) g_strndup (a_this->name->stryng->str, a_this->name->stryng->len); if (str) { @@ -179,8 +182,9 @@ cr_simple_sel_one_to_string (CRSimpleSel const * a_this) } if (a_this->add_sel) { + guchar *tmp_str = NULL; - gchar *tmp_str = (gchar *)cr_additional_sel_to_string (a_this->add_sel); + tmp_str = cr_additional_sel_to_string (a_this->add_sel); if (tmp_str) { g_string_append_printf (str_buf, "%s", tmp_str); @@ -190,7 +194,7 @@ cr_simple_sel_one_to_string (CRSimpleSel const * a_this) } if (str_buf) { - result = (guchar *)str_buf->str; + result = (guchar *) str_buf->str; g_string_free (str_buf, FALSE); str_buf = NULL; } diff --git a/src/libcroco/cr-statement.c b/src/libcroco/cr-statement.c index 4666f26ec..e31123aec 100644 --- a/src/libcroco/cr-statement.c +++ b/src/libcroco/cr-statement.c @@ -25,8 +25,6 @@ #include "cr-statement.h" #include "cr-parser.h" -#define UNUSED(_param) ((void)(_param)) - /** *@file *Definition of the #CRStatement class. @@ -38,12 +36,12 @@ static void cr_statement_clear (CRStatement * a_this); static void parse_font_face_start_font_face_cb (CRDocHandler * a_this, - CRParsingLocation * a_location) + CRParsingLocation *a_location) { CRStatement *stmt = NULL; enum CRStatus status = CR_OK; - UNUSED(a_location); + (void) a_location; stmt = cr_statement_new_at_font_face_rule (NULL, NULL); g_return_if_fail (stmt); @@ -86,7 +84,7 @@ parse_font_face_property_cb (CRDocHandler * a_this, CRStatement *stmt = NULL; CRStatement **stmtptr = NULL; - UNUSED(a_important); + (void) a_important; g_return_if_fail (a_this && a_name); @@ -144,13 +142,13 @@ static void parse_page_start_page_cb (CRDocHandler * a_this, CRString * a_name, CRString * a_pseudo_page, - CRParsingLocation * a_location) + CRParsingLocation *a_location) { CRStatement *stmt = NULL; enum CRStatus status = CR_OK; CRString *page_name = NULL, *pseudo_name = NULL ; - UNUSED(a_location); + (void) a_location; if (a_name) page_name = cr_string_dup (a_name) ; @@ -225,8 +223,8 @@ parse_page_end_page_cb (CRDocHandler * a_this, CRStatement *stmt = NULL; CRStatement **stmtptr = NULL; - UNUSED(a_name); - UNUSED(a_pseudo_page); + (void) a_name; + (void) a_pseudo_page; stmtptr = &stmt; status = cr_doc_handler_get_ctxt (a_this, (gpointer *) stmtptr); @@ -240,13 +238,13 @@ parse_page_end_page_cb (CRDocHandler * a_this, static void parse_at_media_start_media_cb (CRDocHandler * a_this, GList * a_media_list, - CRParsingLocation * a_location) + CRParsingLocation *a_location) { enum CRStatus status = CR_OK; CRStatement *at_media = NULL; GList *media_list = NULL; - UNUSED(a_location); + (void) a_location; g_return_if_fail (a_this && a_this->priv); @@ -380,7 +378,7 @@ parse_at_media_end_media_cb (CRDocHandler * a_this, CRStatement *at_media = NULL; CRStatement **at_media_ptr = NULL; - UNUSED(a_media_list); + (void) a_media_list; g_return_if_fail (a_this && a_this->priv); @@ -603,12 +601,13 @@ cr_statement_clear (CRStatement * a_this) static gchar * cr_statement_ruleset_to_string (CRStatement const * a_this, glong a_indent) { + GString *stringue = NULL; gchar *tmp_str = NULL, *result = NULL; g_return_val_if_fail (a_this && a_this->type == RULESET_STMT, NULL); - GString * stringue = (GString *)g_string_new (NULL); + stringue = (GString *) g_string_new (NULL); if (!stringue) { return result; } @@ -617,8 +616,8 @@ cr_statement_ruleset_to_string (CRStatement const * a_this, glong a_indent) if (a_indent) cr_utils_dump_n_chars2 (' ', stringue, a_indent); - tmp_str = (gchar *) - cr_selector_to_string (a_this->kind.ruleset-> + tmp_str = + (gchar *) cr_selector_to_string (a_this->kind.ruleset-> sel_list); if (tmp_str) { g_string_append (stringue, tmp_str); @@ -628,7 +627,7 @@ cr_statement_ruleset_to_string (CRStatement const * a_this, glong a_indent) } g_string_append (stringue, " {\n"); if (a_this->kind.ruleset->decl_list) { - tmp_str = (gchar *)cr_declaration_list_to_string2 + tmp_str = (gchar *) cr_declaration_list_to_string2 (a_this->kind.ruleset->decl_list, a_indent + DECLARATION_INDENT_NB, TRUE); if (tmp_str) { @@ -677,13 +676,13 @@ cr_statement_font_face_rule_to_string (CRStatement const * a_this, NULL); if (a_this->kind.font_face_rule->decl_list) { - stringue = (GString *)g_string_new (NULL) ; + stringue = (GString *) g_string_new (NULL) ; g_return_val_if_fail (stringue, NULL) ; if (a_indent) cr_utils_dump_n_chars2 (' ', stringue, a_indent); g_string_append (stringue, "@font-face {\n"); - tmp_str = (gchar *)cr_declaration_list_to_string2 + tmp_str = (gchar *) cr_declaration_list_to_string2 (a_this->kind.font_face_rule->decl_list, a_indent + DECLARATION_INDENT_NB, TRUE) ; if (tmp_str) { @@ -762,9 +761,10 @@ static gchar * cr_statement_at_page_rule_to_string (CRStatement const *a_this, gulong a_indent) { + GString *stringue = NULL; gchar *result = NULL ; - GString *stringue = (GString *)g_string_new (NULL) ; + stringue = (GString *) g_string_new (NULL) ; cr_utils_dump_n_chars2 (' ', stringue, a_indent) ; g_string_append (stringue, "@page"); @@ -785,7 +785,7 @@ cr_statement_at_page_rule_to_string (CRStatement const *a_this, if (a_this->kind.page_rule->decl_list) { gchar *str = NULL ; g_string_append (stringue, " {\n"); - str = (gchar *)cr_declaration_list_to_string2 + str = (gchar *) cr_declaration_list_to_string2 (a_this->kind.page_rule->decl_list, a_indent + DECLARATION_INDENT_NB, TRUE) ; if (str) { @@ -821,17 +821,17 @@ cr_statement_media_rule_to_string (CRStatement const *a_this, NULL); if (a_this->kind.media_rule) { - stringue = (GString *)g_string_new (NULL) ; + stringue = (GString *) g_string_new (NULL) ; cr_utils_dump_n_chars2 (' ', stringue, a_indent); g_string_append (stringue, "@media"); for (cur = a_this->kind.media_rule->media_list; cur; cur = cur->next) { if (cur->data) { - gchar *str = cr_string_dup2 + gchar *str2 = cr_string_dup2 ((CRString const *) cur->data); - if (str) { + if (str2) { if (cur->prev) { g_string_append (stringue, @@ -839,9 +839,9 @@ cr_statement_media_rule_to_string (CRStatement const *a_this, } g_string_append_printf (stringue, - " %s", str); - g_free (str); - str = NULL; + " %s", str2); + g_free (str2); + str2 = NULL; } } } @@ -878,7 +878,7 @@ cr_statement_import_rule_to_string (CRStatement const *a_this, if (a_this->kind.import_rule->url && a_this->kind.import_rule->url->stryng) { - stringue = (GString *)g_string_new (NULL) ; + stringue = (GString *) g_string_new (NULL) ; g_return_val_if_fail (stringue, NULL) ; str = g_strndup (a_this->kind.import_rule->url->stryng->str, a_this->kind.import_rule->url->stryng->len); @@ -950,8 +950,7 @@ cr_statement_does_buf_parses_against_core (const guchar * a_buf, enum CRStatus status = CR_OK; gboolean result = FALSE; - parser = cr_parser_new_from_buf ((guchar*)a_buf, - strlen ((char *)a_buf), + parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen ((const char *) a_buf), a_encoding, FALSE); g_return_val_if_fail (parser, FALSE); @@ -1071,8 +1070,7 @@ cr_statement_ruleset_parse_from_buf (const guchar * a_buf, g_return_val_if_fail (a_buf, NULL); - parser = cr_parser_new_from_buf ((guchar*)a_buf, - strlen ((char *)a_buf), + parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen ((const char *) a_buf), a_enc, FALSE); g_return_val_if_fail (parser, NULL); @@ -1138,6 +1136,8 @@ cr_statement_new_ruleset (CRStyleSheet * a_sheet, CRDeclaration * a_decl_list, CRStatement * a_parent_media_rule) { + CRStatement *result = NULL; + g_return_val_if_fail (a_sel_list, NULL); if (a_parent_media_rule) { @@ -1148,7 +1148,7 @@ cr_statement_new_ruleset (CRStyleSheet * a_sheet, NULL); } - CRStatement *result = (CRStatement *)g_try_malloc (sizeof (CRStatement)); + result = (CRStatement *) g_try_malloc (sizeof (CRStatement)); if (!result) { cr_utils_trace_info ("Out of memory"); @@ -1157,7 +1157,7 @@ cr_statement_new_ruleset (CRStyleSheet * a_sheet, memset (result, 0, sizeof (CRStatement)); result->type = RULESET_STMT; - result->kind.ruleset = (CRRuleSet *)g_try_malloc (sizeof (CRRuleSet)); + result->kind.ruleset = (CRRuleSet *) g_try_malloc (sizeof (CRRuleSet)); if (!result->kind.ruleset) { cr_utils_trace_info ("Out of memory"); @@ -1207,8 +1207,7 @@ cr_statement_at_media_rule_parse_from_buf (const guchar * a_buf, CRDocHandler *sac_handler = NULL; enum CRStatus status = CR_OK; - parser = cr_parser_new_from_buf ((guchar*)a_buf, - strlen ((char *)a_buf), + parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen ((const char *) a_buf), a_enc, FALSE); if (!parser) { cr_utils_trace_info ("Instanciation of the parser failed"); @@ -1278,12 +1277,13 @@ CRStatement * cr_statement_new_at_media_rule (CRStyleSheet * a_sheet, CRStatement * a_rulesets, GList * a_media) { - CRStatement *cur = NULL; + CRStatement *result = NULL, + *cur = NULL; if (a_rulesets) g_return_val_if_fail (a_rulesets->type == RULESET_STMT, NULL); - CRStatement *result = (CRStatement *)g_try_malloc (sizeof (CRStatement)); + result = (CRStatement *) g_try_malloc (sizeof (CRStatement)); if (!result) { cr_utils_trace_info ("Out of memory"); @@ -1293,7 +1293,7 @@ cr_statement_new_at_media_rule (CRStyleSheet * a_sheet, memset (result, 0, sizeof (CRStatement)); result->type = AT_MEDIA_RULE_STMT; - result->kind.media_rule = (CRAtMediaRule *)g_try_malloc (sizeof (CRAtMediaRule)); + result->kind.media_rule = (CRAtMediaRule *) g_try_malloc (sizeof (CRAtMediaRule)); if (!result->kind.media_rule) { cr_utils_trace_info ("Out of memory"); g_free (result); @@ -1340,7 +1340,9 @@ cr_statement_new_at_import_rule (CRStyleSheet * a_container_sheet, GList * a_media_list, CRStyleSheet * a_imported_sheet) { - CRStatement *result = (CRStatement *)g_try_malloc (sizeof (CRStatement)); + CRStatement *result = NULL; + + result = (CRStatement *) g_try_malloc (sizeof (CRStatement)); if (!result) { cr_utils_trace_info ("Out of memory"); @@ -1350,7 +1352,7 @@ cr_statement_new_at_import_rule (CRStyleSheet * a_container_sheet, memset (result, 0, sizeof (CRStatement)); result->type = AT_IMPORT_RULE_STMT; - result->kind.import_rule = (CRAtImportRule *)g_try_malloc (sizeof (CRAtImportRule)); + result->kind.import_rule = (CRAtImportRule *) g_try_malloc (sizeof (CRAtImportRule)); if (!result->kind.import_rule) { cr_utils_trace_info ("Out of memory"); @@ -1391,8 +1393,7 @@ cr_statement_at_import_rule_parse_from_buf (const guchar * a_buf, CRString *import_string = NULL; CRParsingLocation location = {0,0,0} ; - parser = cr_parser_new_from_buf ((guchar*)a_buf, - strlen ((char *)a_buf), + parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen ((const char *) a_buf), a_encoding, FALSE); if (!parser) { cr_utils_trace_info ("Instanciation of parser failed."); @@ -1425,8 +1426,7 @@ cr_statement_at_import_rule_parse_from_buf (const guchar * a_buf, parser = NULL; } if (media_list) { - GList *cur = NULL; - for (cur = media_list; media_list; + for (; media_list; media_list = g_list_next (media_list)) { if (media_list->data) { cr_string_destroy ((CRString*)media_list->data); @@ -1463,7 +1463,9 @@ cr_statement_new_at_page_rule (CRStyleSheet * a_sheet, CRDeclaration * a_decl_list, CRString * a_name, CRString * a_pseudo) { - CRStatement *result = (CRStatement *)g_try_malloc (sizeof (CRStatement)); + CRStatement *result = NULL; + + result = (CRStatement *) g_try_malloc (sizeof (CRStatement)); if (!result) { cr_utils_trace_info ("Out of memory"); @@ -1473,7 +1475,7 @@ cr_statement_new_at_page_rule (CRStyleSheet * a_sheet, memset (result, 0, sizeof (CRStatement)); result->type = AT_PAGE_RULE_STMT; - result->kind.page_rule = (CRAtPageRule *)g_try_malloc (sizeof (CRAtPageRule)); + result->kind.page_rule = (CRAtPageRule *) g_try_malloc (sizeof (CRAtPageRule)); if (!result->kind.page_rule) { cr_utils_trace_info ("Out of memory"); @@ -1511,14 +1513,14 @@ cr_statement_at_page_rule_parse_from_buf (const guchar * a_buf, enum CREncoding a_encoding) { enum CRStatus status = CR_OK; + CRParser *parser = NULL; CRDocHandler *sac_handler = NULL; CRStatement *result = NULL; CRStatement **resultptr = NULL; g_return_val_if_fail (a_buf, NULL); - CRParser *parser = cr_parser_new_from_buf ((guchar*)a_buf, - strlen ((char *)a_buf), + parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen ((const char *) a_buf), a_encoding, FALSE); if (!parser) { cr_utils_trace_info ("Instanciation of the parser failed."); @@ -1584,9 +1586,11 @@ CRStatement * cr_statement_new_at_charset_rule (CRStyleSheet * a_sheet, CRString * a_charset) { + CRStatement *result = NULL; + g_return_val_if_fail (a_charset, NULL); - CRStatement *result = (CRStatement *)g_try_malloc (sizeof (CRStatement)); + result = (CRStatement *) g_try_malloc (sizeof (CRStatement)); if (!result) { cr_utils_trace_info ("Out of memory"); @@ -1596,7 +1600,7 @@ cr_statement_new_at_charset_rule (CRStyleSheet * a_sheet, memset (result, 0, sizeof (CRStatement)); result->type = AT_CHARSET_RULE_STMT; - result->kind.charset_rule = (CRAtCharsetRule *)g_try_malloc (sizeof (CRAtCharsetRule)); + result->kind.charset_rule = (CRAtCharsetRule *) g_try_malloc (sizeof (CRAtCharsetRule)); if (!result->kind.charset_rule) { cr_utils_trace_info ("Out of memory"); @@ -1626,13 +1630,13 @@ cr_statement_at_charset_rule_parse_from_buf (const guchar * a_buf, enum CREncoding a_encoding) { enum CRStatus status = CR_OK; + CRParser *parser = NULL; CRStatement *result = NULL; CRString *charset = NULL; g_return_val_if_fail (a_buf, NULL); - CRParser *parser = cr_parser_new_from_buf ((guchar*)a_buf, - strlen ((char *)a_buf), + parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen ((const char *) a_buf), a_encoding, FALSE); if (!parser) { cr_utils_trace_info ("Instanciation of the parser failed."); @@ -1678,7 +1682,9 @@ CRStatement * cr_statement_new_at_font_face_rule (CRStyleSheet * a_sheet, CRDeclaration * a_font_decls) { - CRStatement *result = (CRStatement *)g_try_malloc (sizeof (CRStatement)); + CRStatement *result = NULL; + + result = (CRStatement *) g_try_malloc (sizeof (CRStatement)); if (!result) { cr_utils_trace_info ("Out of memory"); @@ -1687,7 +1693,7 @@ cr_statement_new_at_font_face_rule (CRStyleSheet * a_sheet, memset (result, 0, sizeof (CRStatement)); result->type = AT_FONT_FACE_RULE_STMT; - result->kind.font_face_rule = (CRAtFontFaceRule *)g_try_malloc + result->kind.font_face_rule = (CRAtFontFaceRule *) g_try_malloc (sizeof (CRAtFontFaceRule)); if (!result->kind.font_face_rule) { @@ -1723,12 +1729,11 @@ cr_statement_font_face_rule_parse_from_buf (const guchar * a_buf, { CRStatement *result = NULL; CRStatement **resultptr = NULL; + CRParser *parser = NULL; CRDocHandler *sac_handler = NULL; enum CRStatus status = CR_OK; - CRParser *parser = (CRParser *)cr_parser_new_from_buf ( - (guchar*)a_buf, - strlen ((char *)a_buf), + parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen ((const char *) a_buf), a_encoding, FALSE); if (!parser) goto cleanup; @@ -2614,8 +2619,10 @@ cr_statement_dump (CRStatement const * a_this, FILE * a_fp, gulong a_indent) void cr_statement_dump_ruleset (CRStatement const * a_this, FILE * a_fp, glong a_indent) { + gchar *str = NULL; + g_return_if_fail (a_fp && a_this); - gchar *str = cr_statement_ruleset_to_string (a_this, a_indent); + str = cr_statement_ruleset_to_string (a_this, a_indent); if (str) { fprintf (a_fp, "%s", str); g_free (str); @@ -2661,9 +2668,11 @@ cr_statement_dump_font_face_rule (CRStatement const * a_this, FILE * a_fp, void cr_statement_dump_charset (CRStatement const * a_this, FILE * a_fp, gulong a_indent) { + gchar *str = NULL; + g_return_if_fail (a_this && a_this->type == AT_CHARSET_RULE_STMT); - gchar *str = cr_statement_charset_to_string (a_this, + str = cr_statement_charset_to_string (a_this, a_indent) ; if (str) { fprintf (a_fp, "%s", str) ; @@ -2685,11 +2694,13 @@ cr_statement_dump_charset (CRStatement const * a_this, FILE * a_fp, gulong a_ind void cr_statement_dump_page (CRStatement const * a_this, FILE * a_fp, gulong a_indent) { + gchar *str = NULL; + g_return_if_fail (a_this && a_this->type == AT_PAGE_RULE_STMT && a_this->kind.page_rule); - gchar *str = cr_statement_at_page_rule_to_string (a_this, a_indent) ; + str = cr_statement_at_page_rule_to_string (a_this, a_indent) ; if (str) { fprintf (a_fp, "%s", str); g_free (str) ; diff --git a/src/libcroco/cr-string.c b/src/libcroco/cr-string.c index 47d557d5b..86ad3432c 100644 --- a/src/libcroco/cr-string.c +++ b/src/libcroco/cr-string.c @@ -32,7 +32,9 @@ CRString * cr_string_new (void) { - CRString *result = (CRString *)g_try_malloc (sizeof (CRString)) ; + CRString *result = NULL ; + + result = (CRString *) g_try_malloc (sizeof (CRString)) ; if (!result) { cr_utils_trace_info ("Out of memory") ; return NULL ; @@ -51,7 +53,9 @@ cr_string_new (void) CRString * cr_string_new_from_string (const gchar * a_string) { - CRString *result = cr_string_new () ; + CRString *result = NULL ; + + result = cr_string_new () ; if (!result) { cr_utils_trace_info ("Out of memory") ; return NULL ; @@ -70,7 +74,9 @@ cr_string_new_from_string (const gchar * a_string) CRString * cr_string_new_from_gstring (GString const *a_string) { - CRString *result = cr_string_new () ; + CRString *result = NULL ; + + result = cr_string_new () ; if (!result) { cr_utils_trace_info ("Out of memory") ; return NULL ; @@ -87,9 +93,10 @@ cr_string_new_from_gstring (GString const *a_string) CRString * cr_string_dup (CRString const *a_this) { + CRString *result = NULL ; g_return_val_if_fail (a_this, NULL) ; - CRString *result = cr_string_new_from_gstring (a_this->stryng) ; + result = cr_string_new_from_gstring (a_this->stryng) ; if (!result) { cr_utils_trace_info ("Out of memory") ; return NULL ; diff --git a/src/libcroco/cr-style.c b/src/libcroco/cr-style.c index a9c5a5cec..2b865c248 100644 --- a/src/libcroco/cr-style.c +++ b/src/libcroco/cr-style.c @@ -140,9 +140,9 @@ static CRPropertyDesc gv_prop_table[] = { {"font-size", PROP_ID_FONT_SIZE}, {"font-style", PROP_ID_FONT_STYLE}, {"font-weight", PROP_ID_FONT_WEIGHT}, - {"white-space", PROP_ID_WHITE_SPACE}, + {"white-space", PROP_ID_WHITE_SPACE}, /*must be the last one */ - {NULL, (enum CRPropertyID)0} + {NULL, (enum CRPropertyID) 0} }; /** @@ -185,7 +185,7 @@ static struct CRNumPropEnumDumpInfo gv_num_props_dump_infos[] = { {NUM_PROP_MARGIN_BOTTOM, "margin-bottom"}, {NUM_PROP_MARGIN_LEFT, "margin-left"}, {NUM_PROP_WIDTH, "width"}, - {(enum CRNumProp)0, NULL} + {(enum CRNumProp) 0, NULL} }; struct CRRgbPropEnumDumpInfo { @@ -200,7 +200,7 @@ static struct CRRgbPropEnumDumpInfo gv_rgb_props_dump_infos[] = { {RGB_PROP_BORDER_LEFT_COLOR, "left-color"}, {RGB_PROP_COLOR, "color"}, {RGB_PROP_BACKGROUND_COLOR, "background-color"}, - {(enum CRRgbProp)0, NULL} + {(enum CRRgbProp) 0, NULL} }; struct CRBorderStylePropEnumDumpInfo { @@ -215,7 +215,7 @@ static struct CRBorderStylePropEnumDumpInfo gv_border_style_props_dump_infos[] {BORDER_STYLE_PROP_RIGHT, "border-style-right"}, {BORDER_STYLE_PROP_BOTTOM, "boder-style-bottom"}, {BORDER_STYLE_PROP_LEFT, "border-style-left"}, - {(enum CRBorderStyleProp)0, NULL} + {(enum CRBorderStyleProp) 0, NULL} }; static enum CRStatus @@ -319,9 +319,9 @@ set_prop_font_weight_from_value (CRStyle * a_style, CRTerm * a_value); static const gchar * num_prop_code_to_string (enum CRNumProp a_code) { - int len = sizeof (gv_num_props_dump_infos) / + guint len = sizeof (gv_num_props_dump_infos) / sizeof (struct CRNumPropEnumDumpInfo); - if ((int)a_code >= len) { + if (a_code >= len) { cr_utils_trace_info ("A field has been added " "to 'enum CRNumProp' and no matching" " entry has been " @@ -342,10 +342,10 @@ num_prop_code_to_string (enum CRNumProp a_code) static const gchar * rgb_prop_code_to_string (enum CRRgbProp a_code) { - int len = sizeof (gv_rgb_props_dump_infos) / + guint len = sizeof (gv_rgb_props_dump_infos) / sizeof (struct CRRgbPropEnumDumpInfo); - if ((int)a_code >= len) { + if (a_code >= len) { cr_utils_trace_info ("A field has been added " "to 'enum CRRgbProp' and no matching" " entry has been " @@ -366,10 +366,10 @@ rgb_prop_code_to_string (enum CRRgbProp a_code) static const gchar * border_style_prop_code_to_string (enum CRBorderStyleProp a_code) { - int len = sizeof (gv_border_style_props_dump_infos) / + guint len = sizeof (gv_border_style_props_dump_infos) / sizeof (struct CRBorderStylePropEnumDumpInfo); - if ((int)a_code >= len) { + if (a_code >= len) { cr_utils_trace_info ("A field has been added " "to 'enum CRBorderStyleProp' and no matching" " entry has been " @@ -421,7 +421,7 @@ cr_style_get_prop_id (const guchar * a_prop) cr_style_init_properties (); } - raw_id = (gpointer *)g_hash_table_lookup (gv_prop_hash, a_prop); + raw_id = (gpointer *) g_hash_table_lookup (gv_prop_hash, a_prop); if (!raw_id) { return PROP_ID_NOT_KNOWN; } @@ -465,7 +465,7 @@ set_prop_padding_x_from_value (CRStyle * a_style, if (a_value->content.str && a_value->content.str->stryng && a_value->content.str->stryng->str - && !strncmp ("inherit", + && !strncmp ((const char *) "inherit", a_value->content.str->stryng->str, sizeof ("inherit")-1)) { status = cr_num_set (num_val, 0.0, NUM_INHERIT); @@ -569,9 +569,10 @@ static enum CRStatus set_prop_border_width_from_value (CRStyle *a_style, CRTerm *a_value) { + CRTerm *cur_term = NULL ; g_return_val_if_fail (a_style && a_value, CR_BAD_PARAM_ERROR) ; - CRTerm *cur_term = a_value ; + cur_term = a_value ; if (!cur_term) return CR_ERROR ; @@ -579,7 +580,7 @@ set_prop_border_width_from_value (CRStyle *a_style, int dir; for (dir = (int) DIR_TOP ; dir < (int)NB_DIRS ; dir++) { enum CRDirection direction = (enum CRDirection)dir; - set_prop_border_x_width_from_value (a_style, + set_prop_border_x_width_from_value (a_style, cur_term, direction) ; } @@ -696,16 +697,18 @@ static enum CRStatus set_prop_border_style_from_value (CRStyle *a_style, CRTerm *a_value) { + CRTerm *cur_term = NULL ; + g_return_val_if_fail (a_style && a_value, CR_BAD_PARAM_ERROR) ; - CRTerm *cur_term = a_value ; + cur_term = a_value ; if (!cur_term || cur_term->type != TERM_IDENT) { return CR_ERROR ; } int dir; - for (dir = (int)DIR_TOP ; dir < (int)NB_DIRS ; dir++) { + for (dir = (int)DIR_TOP ; dir < (int)NB_DIRS ; dir++) { enum CRDirection direction = (enum CRDirection)dir; set_prop_border_x_style_from_value (a_style, cur_term, @@ -908,7 +911,7 @@ set_prop_position_from_value (CRStyle * a_style, CRTerm * a_value) break; } - return CR_OK; + return status; } static enum CRStatus @@ -1115,11 +1118,11 @@ set_prop_border_x_color_from_value (CRStyle * a_style, CRTerm * a_value, && a_value->content.str->stryng->str) { status = cr_rgb_set_from_name (rgb_color, - (guchar *)a_value->content.str->stryng->str); + (const guchar *) a_value->content.str->stryng->str); } if (status != CR_OK) { - cr_rgb_set_from_name (rgb_color, (guchar *)"black"); + cr_rgb_set_from_name (rgb_color, (const guchar *) "black"); } } else if (a_value->type == TERM_RGB) { if (a_value->content.rgb) { @@ -1354,7 +1357,7 @@ set_prop_font_family_from_value (CRStyle * a_style, CRTerm * a_value) && cur_term->content.str->stryng->str) { cur_ff = cr_font_family_new (FONT_FAMILY_NON_GENERIC, - (guchar *)cur_term->content.str->stryng->str); + (guchar *) cur_term->content.str->stryng->str); } } break; @@ -1707,7 +1710,9 @@ set_prop_white_space_from_value (CRStyle * a_style, CRTerm * a_value) CRStyle * cr_style_new (gboolean a_set_props_to_initial_values) { - CRStyle *result = (CRStyle *)g_try_malloc (sizeof (CRStyle)); + CRStyle *result = NULL; + + result = (CRStyle *) g_try_malloc (sizeof (CRStyle)); if (!result) { cr_utils_trace_info ("Out of memory"); return NULL; @@ -2018,7 +2023,7 @@ cr_style_set_style_from_decl (CRStyle * a_this, CRDeclaration * a_decl) CR_BAD_PARAM_ERROR); prop_id = cr_style_get_prop_id - ((guchar *)a_decl->property->stryng->str); + ((const guchar *) a_decl->property->stryng->str); value = a_decl->value; switch (prop_id) { @@ -2676,7 +2681,7 @@ cr_style_to_string (CRStyle * a_this, GString ** a_str, guint a_nb_indent) *before outputing it value */ cr_utils_dump_n_chars2 (' ', str, indent); - tmp_str = (gchar *) num_prop_code_to_string ((enum CRNumProp)i); + tmp_str = (gchar *) num_prop_code_to_string ((enum CRNumProp) i); if (tmp_str) { g_string_append_printf (str, "%s: ", tmp_str); } else { @@ -2690,7 +2695,7 @@ cr_style_to_string (CRStyle * a_this, GString ** a_str, guint a_nb_indent) } /*loop over the rgb_props and to_string() them all */ for (i = RGB_PROP_BORDER_TOP_COLOR; i < NB_RGB_PROPS; i++) { - tmp_str = (gchar *) rgb_prop_code_to_string ((enum CRRgbProp)i); + tmp_str = (gchar *) rgb_prop_code_to_string ((enum CRRgbProp) i); cr_utils_dump_n_chars2 (' ', str, indent); if (tmp_str) { g_string_append_printf (str, "%s: ", tmp_str); @@ -2705,8 +2710,7 @@ cr_style_to_string (CRStyle * a_this, GString ** a_str, guint a_nb_indent) } /*loop over the border_style_props and to_string() them */ for (i = BORDER_STYLE_PROP_TOP; i < NB_BORDER_STYLE_PROPS; i++) { - tmp_str = (gchar *) - border_style_prop_code_to_string ((enum CRBorderStyleProp)i); + tmp_str = (gchar *) border_style_prop_code_to_string ((enum CRBorderStyleProp) i); cr_utils_dump_n_chars2 (' ', str, indent); if (tmp_str) { g_string_append_printf (str, "%s: ", tmp_str); @@ -2741,7 +2745,7 @@ cr_style_to_string (CRStyle * a_this, GString ** a_str, guint a_nb_indent) cr_utils_dump_n_chars2 (' ', str, indent); g_string_append (str, "font-family: "); - tmp_str = (gchar *)cr_font_family_to_string (a_this->font_family, TRUE); + tmp_str = (gchar *) cr_font_family_to_string (a_this->font_family, TRUE); if (tmp_str) { g_string_append (str, tmp_str); g_free (tmp_str); diff --git a/src/libcroco/cr-stylesheet.c b/src/libcroco/cr-stylesheet.c index 1b26c64bf..cb5de6958 100644 --- a/src/libcroco/cr-stylesheet.c +++ b/src/libcroco/cr-stylesheet.c @@ -36,7 +36,9 @@ CRStyleSheet * cr_stylesheet_new (CRStatement * a_stmts) { - CRStyleSheet *result = (CRStyleSheet *)g_try_malloc (sizeof (CRStyleSheet)); + CRStyleSheet *result; + + result = (CRStyleSheet *) g_try_malloc (sizeof (CRStyleSheet)); if (!result) { cr_utils_trace_info ("Out of memory"); return NULL; diff --git a/src/libcroco/cr-term.c b/src/libcroco/cr-term.c index 09b6354db..1c50aed2a 100644 --- a/src/libcroco/cr-term.c +++ b/src/libcroco/cr-term.c @@ -84,7 +84,9 @@ cr_term_clear (CRTerm * a_this) CRTerm * cr_term_new (void) { - CRTerm *result = (CRTerm *)g_try_malloc (sizeof (CRTerm)); + CRTerm *result = NULL; + + result = (CRTerm *) g_try_malloc (sizeof (CRTerm)); if (!result) { cr_utils_trace_info ("Out of memory"); return NULL; @@ -104,15 +106,14 @@ CRTerm * cr_term_parse_expression_from_buf (const guchar * a_buf, enum CREncoding a_encoding) { + CRParser *parser = NULL; CRTerm *result = NULL; enum CRStatus status = CR_OK; g_return_val_if_fail (a_buf, NULL); - CRParser *parser = cr_parser_new_from_buf ( - (guchar*)a_buf, - strlen ((char *)a_buf), - a_encoding, FALSE); + parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen ((const char *) a_buf), + a_encoding, FALSE); g_return_val_if_fail (parser, NULL); status = cr_parser_try_to_skip_spaces_and_comments (parser); @@ -279,8 +280,8 @@ cr_term_to_string (CRTerm const * a_this) { GString *str_buf = NULL; CRTerm const *cur = NULL; - guchar *result = NULL; - gchar *content = NULL; + guchar *result = NULL, + *content = NULL; g_return_val_if_fail (a_this, NULL); @@ -329,11 +330,11 @@ cr_term_to_string (CRTerm const * a_this) switch (cur->type) { case TERM_NUMBER: if (cur->content.num) { - content = (gchar *)cr_num_to_string (cur->content.num); + content = cr_num_to_string (cur->content.num); } if (content) { - g_string_append (str_buf, content); + g_string_append (str_buf, (const gchar *) content); g_free (content); content = NULL; } @@ -342,7 +343,7 @@ cr_term_to_string (CRTerm const * a_this) case TERM_FUNCTION: if (cur->content.str) { - content = g_strndup + content = (guchar *) g_strndup (cur->content.str->stryng->str, cur->content.str->stryng->len); } @@ -360,22 +361,21 @@ cr_term_to_string (CRTerm const * a_this) if (tmp_str) { g_string_append (str_buf, - (gchar *)tmp_str); + (const gchar *) tmp_str); g_free (tmp_str); tmp_str = NULL; } - } + g_string_append (str_buf, ")"); g_free (content); content = NULL; - g_string_append (str_buf, ")"); } break; case TERM_STRING: if (cur->content.str) { - content = g_strndup + content = (guchar *) g_strndup (cur->content.str->stryng->str, cur->content.str->stryng->len); } @@ -390,13 +390,13 @@ cr_term_to_string (CRTerm const * a_this) case TERM_IDENT: if (cur->content.str) { - content = g_strndup + content = (guchar *) g_strndup (cur->content.str->stryng->str, cur->content.str->stryng->len); } if (content) { - g_string_append (str_buf, content); + g_string_append (str_buf, (const gchar *) content); g_free (content); content = NULL; } @@ -404,9 +404,9 @@ cr_term_to_string (CRTerm const * a_this) case TERM_URI: if (cur->content.str) { - content = g_strndup - (cur->content.str->stryng->str, - cur->content.str->stryng->len); + content = (guchar *) g_strndup + (cur->content.str->stryng->str, + cur->content.str->stryng->len); } if (content) { @@ -425,7 +425,7 @@ cr_term_to_string (CRTerm const * a_this) tmp_str = cr_rgb_to_string (cur->content.rgb); if (tmp_str) { - g_string_append (str_buf, (gchar *)tmp_str); + g_string_append (str_buf, (const gchar *) tmp_str); g_free (tmp_str); tmp_str = NULL; } @@ -442,7 +442,7 @@ cr_term_to_string (CRTerm const * a_this) case TERM_HASH: if (cur->content.str) { - content = g_strndup + content = (guchar *) g_strndup (cur->content.str->stryng->str, cur->content.str->stryng->len); } @@ -463,7 +463,7 @@ cr_term_to_string (CRTerm const * a_this) } if (str_buf) { - result = (guchar *)str_buf->str; + result =(guchar *) str_buf->str; g_string_free (str_buf, FALSE); str_buf = NULL; } @@ -475,8 +475,8 @@ guchar * cr_term_one_to_string (CRTerm const * a_this) { GString *str_buf = NULL; - guchar *result = NULL; - gchar *content = NULL; + guchar *result = NULL, + *content = NULL; g_return_val_if_fail (a_this, NULL); @@ -524,11 +524,11 @@ cr_term_one_to_string (CRTerm const * a_this) switch (a_this->type) { case TERM_NUMBER: if (a_this->content.num) { - content = (gchar *)cr_num_to_string (a_this->content.num); + content = cr_num_to_string (a_this->content.num); } if (content) { - g_string_append (str_buf, content); + g_string_append (str_buf, (const gchar *) content); g_free (content); content = NULL; } @@ -537,7 +537,7 @@ cr_term_one_to_string (CRTerm const * a_this) case TERM_FUNCTION: if (a_this->content.str) { - content = g_strndup + content = (guchar *) g_strndup (a_this->content.str->stryng->str, a_this->content.str->stryng->len); } @@ -571,7 +571,7 @@ cr_term_one_to_string (CRTerm const * a_this) case TERM_STRING: if (a_this->content.str) { - content = g_strndup + content = (guchar *) g_strndup (a_this->content.str->stryng->str, a_this->content.str->stryng->len); } @@ -586,13 +586,13 @@ cr_term_one_to_string (CRTerm const * a_this) case TERM_IDENT: if (a_this->content.str) { - content = g_strndup + content = (guchar *) g_strndup (a_this->content.str->stryng->str, a_this->content.str->stryng->len); } if (content) { - g_string_append (str_buf, content); + g_string_append (str_buf, (const gchar *) content); g_free (content); content = NULL; } @@ -600,7 +600,7 @@ cr_term_one_to_string (CRTerm const * a_this) case TERM_URI: if (a_this->content.str) { - content = g_strndup + content = (guchar *) g_strndup (a_this->content.str->stryng->str, a_this->content.str->stryng->len); } @@ -615,12 +615,13 @@ cr_term_one_to_string (CRTerm const * a_this) case TERM_RGB: if (a_this->content.rgb) { + guchar *tmp_str = NULL; g_string_append_printf (str_buf, "rgb("); - gchar *tmp_str = (gchar *)cr_rgb_to_string (a_this->content.rgb); + tmp_str = cr_rgb_to_string (a_this->content.rgb); if (tmp_str) { - g_string_append (str_buf, tmp_str); + g_string_append (str_buf, (const gchar *) tmp_str); g_free (tmp_str); tmp_str = NULL; } @@ -637,7 +638,7 @@ cr_term_one_to_string (CRTerm const * a_this) case TERM_HASH: if (a_this->content.str) { - content = g_strndup + content = (guchar *) g_strndup (a_this->content.str->stryng->str, a_this->content.str->stryng->len); } @@ -658,7 +659,7 @@ cr_term_one_to_string (CRTerm const * a_this) } if (str_buf) { - result = (guchar *)str_buf->str; + result = (guchar *) str_buf->str; g_string_free (str_buf, FALSE); str_buf = NULL; } diff --git a/src/libcroco/cr-tknzr.c b/src/libcroco/cr-tknzr.c index 1f762b5c5..228471bf9 100644 --- a/src/libcroco/cr-tknzr.c +++ b/src/libcroco/cr-tknzr.c @@ -1586,7 +1586,9 @@ cr_tknzr_parse_num (CRTknzr * a_this, CRTknzr * cr_tknzr_new (CRInput * a_input) { - CRTknzr *result = (CRTknzr *)g_try_malloc (sizeof (CRTknzr)); + CRTknzr *result = NULL; + + result = (CRTknzr *) g_try_malloc (sizeof (CRTknzr)); if (result == NULL) { cr_utils_trace_info ("Out of memory"); @@ -1636,7 +1638,9 @@ cr_tknzr_new_from_uri (const guchar * a_file_uri, enum CREncoding a_enc) { CRTknzr *result = NULL; - CRInput *input = cr_input_new_from_uri ((gchar *)a_file_uri, a_enc); + CRInput *input = NULL; + + input = cr_input_new_from_uri ((const gchar *) a_file_uri, a_enc); g_return_val_if_fail (input != NULL, NULL); result = cr_tknzr_new (input); @@ -1909,7 +1913,7 @@ cr_tknzr_consume_chars (CRTknzr * a_this, guint32 a_char, glong * a_nb_char) } return cr_input_consume_chars (PRIVATE (a_this)->input, - a_char, (gulong *)a_nb_char); + a_char, a_nb_char); } enum CRStatus @@ -2097,15 +2101,15 @@ cr_tknzr_get_next_token (CRTknzr * a_this, CRToken ** a_tk) if (BYTE (input, 2, NULL) == 'r' && BYTE (input, 3, NULL) == 'l' && BYTE (input, 4, NULL) == '(') { - CRString *str = NULL; + CRString *str2 = NULL; - status = cr_tknzr_parse_uri (a_this, &str); + status = cr_tknzr_parse_uri (a_this, &str2); if (status == CR_OK) { - status = cr_token_set_uri (token, str); + status = cr_token_set_uri (token, str2); CHECK_PARSING_STATUS (status, TRUE); - if (str) { + if (str2) { cr_parsing_location_copy (&token->location, - &str->location) ; + &str2->location) ; } goto done; } diff --git a/src/libcroco/cr-token.c b/src/libcroco/cr-token.c index 3dd73ac3e..dfe83e221 100644 --- a/src/libcroco/cr-token.c +++ b/src/libcroco/cr-token.c @@ -133,7 +133,9 @@ cr_token_clear (CRToken * a_this) CRToken * cr_token_new (void) { - CRToken *result = (CRToken *)g_try_malloc (sizeof (CRToken)); + CRToken *result = NULL; + + result = (CRToken *) g_try_malloc (sizeof (CRToken)); if (result == NULL) { cr_utils_trace_info ("Out of memory"); diff --git a/src/libcroco/cr-utils.c b/src/libcroco/cr-utils.c index a51c76920..bfb587017 100644 --- a/src/libcroco/cr-utils.c +++ b/src/libcroco/cr-utils.c @@ -429,9 +429,8 @@ cr_utils_read_char_from_utf8_buf (const guchar * a_in, gulong a_in_len, guint32 * a_out, gulong * a_consumed) { - gulong in_len = 0, - in_index = 0, - nb_bytes_2_decode = 0; + gulong in_index = 0, + nb_bytes_2_decode = 0; enum CRStatus status = CR_OK; /* @@ -448,8 +447,6 @@ cr_utils_read_char_from_utf8_buf (const guchar * a_in, goto end; } - in_len = a_in_len; - if (*a_in <= 0x7F) { /* *7 bits long char @@ -901,15 +898,10 @@ cr_utils_ucs1_to_utf8 (const guchar * a_in, if (*a_in_len == 0) { *a_out_len = 0 ; - return CR_OK ; + return status; } g_return_val_if_fail (a_out, CR_BAD_PARAM_ERROR) ; - if (*a_in_len < 1) { - status = CR_OK; - goto end; - } - in_len = *a_in_len; out_len = *a_out_len; @@ -930,11 +922,10 @@ cr_utils_ucs1_to_utf8 (const guchar * a_in, } } /*end for */ - end: *a_in_len = in_index; *a_out_len = out_index; - return CR_OK; + return status; } /** @@ -951,8 +942,7 @@ cr_utils_ucs1_str_to_utf8 (const guchar * a_in, gulong * a_in_len, guchar ** a_out, gulong * a_out_len) { - gulong in_len = 0, - out_len = 0; + gulong out_len = 0; enum CRStatus status = CR_OK; g_return_val_if_fail (a_in && a_in_len && a_out @@ -969,8 +959,6 @@ cr_utils_ucs1_str_to_utf8 (const guchar * a_in, g_return_val_if_fail (status == CR_OK, status); - in_len = *a_in_len; - *a_out = (guchar *) g_malloc0 (out_len); status = cr_utils_ucs1_to_utf8 (a_in, a_in_len, *a_out, &out_len); @@ -1023,7 +1011,6 @@ cr_utils_utf8_to_ucs1 (const guchar * a_in, && a_out && a_out_len, CR_BAD_PARAM_ERROR); if (*a_in_len < 1) { - status = CR_OK; goto end; } @@ -1102,7 +1089,6 @@ cr_utils_utf8_to_ucs1 (const guchar * a_in, *(if any) to get the current character. */ if (in_index + nb_bytes_2_decode - 1 >= in_len) { - status = CR_OK; goto end; } @@ -1136,7 +1122,7 @@ cr_utils_utf8_to_ucs1 (const guchar * a_in, *a_out_len = out_index; *a_in_len = in_index; - return CR_OK; + return status; } /** diff --git a/src/libgdl/CMakeLists.txt b/src/libgdl/CMakeLists.txt index d59d017f0..a452320f7 100644 --- a/src/libgdl/CMakeLists.txt +++ b/src/libgdl/CMakeLists.txt @@ -1,47 +1,50 @@ +if (NOT "${WITH_EXT_GDL}") -set(libgdl_SRC - gdl-dock-bar.c - gdl-dock-item-button-image.c - gdl-dock-item-grip.c - gdl-dock-item.c - gdl-dock-master.c - gdl-dock-notebook.c - gdl-dock-object.c - gdl-dock-paned.c - gdl-dock-placeholder.c - gdl-dock-tablabel.c - gdl-dock.c - gdl-i18n.c - gdl-switcher.c - libgdlmarshal.c - libgdltypebuiltins.c + set(libgdl_SRC + gdl-dock-bar.c + gdl-dock-item-button-image.c + gdl-dock-item-grip.c + gdl-dock-item.c + gdl-dock-master.c + gdl-dock-notebook.c + gdl-dock-object.c + gdl-dock-paned.c + gdl-dock-placeholder.c + gdl-dock-tablabel.c + gdl-dock.c + gdl-i18n.c + gdl-switcher.c + libgdlmarshal.c + libgdltypebuiltins.c - # ------- - # Headers - gdl-dock-bar.h - gdl-dock-item-button-image.h - gdl-dock-item-grip.h - gdl-dock-item.h - gdl-dock-master.h - gdl-dock-notebook.h - gdl-dock-object.h - gdl-dock-paned.h - gdl-dock-placeholder.h - gdl-dock-tablabel.h - gdl-dock.h - gdl-i18n.h - gdl-switcher.h - gdl.h - libgdlmarshal.h - libgdltypebuiltins.h -) + # ------- + # Headers + gdl-dock-bar.h + gdl-dock-item-button-image.h + gdl-dock-item-grip.h + gdl-dock-item.h + gdl-dock-master.h + gdl-dock-notebook.h + gdl-dock-object.h + gdl-dock-paned.h + gdl-dock-placeholder.h + gdl-dock-tablabel.h + gdl-dock.h + gdl-i18n.h + gdl-switcher.h + gdl.h + libgdlmarshal.h + libgdltypebuiltins.h + ) -if(WIN32) - list(APPEND libgdl_SRC - gdl-win32.c - gdl-win32.h - ) -endif() + if(WIN32) + list(APPEND libgdl_SRC + gdl-win32.c + gdl-win32.h + ) + endif() + + add_inkscape_lib(gdl_LIB "${libgdl_SRC}") -add_inkscape_lib(gdl_LIB "${libgdl_SRC}") +endif() diff --git a/src/libgdl/gdl-dock-item-grip.c b/src/libgdl/gdl-dock-item-grip.c index d23eb7f98..9b3810c20 100644 --- a/src/libgdl/gdl-dock-item-grip.c +++ b/src/libgdl/gdl-dock-item-grip.c @@ -149,6 +149,8 @@ gdl_dock_item_grip_expose (GtkWidget *widget, } +/* see bug #950556: may contribute to regression with GTK2/Quartz */ +#if !defined(GDK_WINDOWING_QUARTZ) if (gdl_dock_item_or_child_has_focus(grip->item)) { gtk_paint_focus (gtk_widget_get_style (widget), @@ -157,6 +159,7 @@ gdl_dock_item_grip_expose (GtkWidget *widget, &event->area, widget, NULL, 0, 0, -1, -1); } +#endif //GDK_WINDOWING_QUARTZ return GTK_WIDGET_CLASS (gdl_dock_item_grip_parent_class)->expose_event (widget, event); } diff --git a/src/libgdl/gdl-dock-item.c b/src/libgdl/gdl-dock-item.c index afcd4dfcb..af630e681 100644 --- a/src/libgdl/gdl-dock-item.c +++ b/src/libgdl/gdl-dock-item.c @@ -1064,8 +1064,11 @@ gdl_dock_item_paint (GtkWidget *widget, "dockitem", 0, 0, -1, -1); +/* see bug #950556: avoid regression with GTK2/Quartz */ +#if !defined(GDK_WINDOWING_QUARTZ) if (GTK_IS_WIDGET(item->_priv->grip)) gtk_widget_queue_draw (GTK_WIDGET(item->_priv->grip)); +#endif } static gint diff --git a/src/libnrtype/FontInstance.cpp b/src/libnrtype/FontInstance.cpp index a5572c517..7a16fc0c3 100644 --- a/src/libnrtype/FontInstance.cpp +++ b/src/libnrtype/FontInstance.cpp @@ -21,6 +21,7 @@ #include FT_BBOX_H #include FT_TRUETYPE_TAGS_H #include FT_TRUETYPE_TABLES_H +#include FT_GLYPH_H #include <pango/pangoft2.h> #include <2geom/pathvector.h> #include <2geom/path-sink.h> @@ -183,6 +184,20 @@ font_instance::font_instance(void) : theFace(0) { //printf("font instance born\n"); + _ascent = _ascent_max = 0.8; + _descent = _descent_max = 0.2; + _xheight = 0.5; + + // Default baseline values, alphabetic is reference + _baselines[ SP_CSS_BASELINE_AUTO ] = 0.0; + _baselines[ SP_CSS_BASELINE_ALPHABETIC ] = 0.0; + _baselines[ SP_CSS_BASELINE_IDEOGRAPHIC ] = -_descent; + _baselines[ SP_CSS_BASELINE_HANGING ] = 0.8 * _ascent; + _baselines[ SP_CSS_BASELINE_MATHEMATICAL ] = 0.8 * _xheight; + _baselines[ SP_CSS_BASELINE_CENTRAL ] = 0.5 - _descent; + _baselines[ SP_CSS_BASELINE_MIDDLE ] = 0.5 * _xheight; + _baselines[ SP_CSS_BASELINE_TEXT_BEFORE_EDGE ] = _ascent; + _baselines[ SP_CSS_BASELINE_TEXT_AFTER_EDGE ] = -_descent; } font_instance::~font_instance(void) @@ -259,6 +274,7 @@ void font_instance::InitTheFace() FT_Select_Charmap(theFace,ft_encoding_unicode) && FT_Select_Charmap(theFace,ft_encoding_symbol); } #endif + FindFontMetrics(); } } @@ -374,10 +390,10 @@ void font_instance::LoadGlyph(int glyph_id) GLYPHMETRICS metrics; DWORD bufferSize=GetGlyphOutline (parent->hScreenDC, glyph_id, GGO_GLYPH_INDEX | GGO_NATIVE | GGO_UNHINTED, &metrics, 0, NULL, &identity); double scale=1.0/parent->fontSize; - n_g.h_advance=metrics.gmCellIncX*scale; - n_g.v_advance=otm.otmTextMetrics.tmHeight*scale; - n_g.h_width=metrics.gmBlackBoxX*scale; - n_g.v_width=metrics.gmBlackBoxY*scale; + n_g.h_advance = metrics.gmCellIncX * scale; + n_g.v_advance = otm.otmTextMetrics.tmHeight * scale; + n_g.h_width = metrics.gmBlackBoxX * scale; + n_g.v_width = metrics.gmBlackBoxY * scale; if ( bufferSize == GDI_ERROR) { // shit happened } else if ( bufferSize == 0) { @@ -459,7 +475,13 @@ void font_instance::LoadGlyph(int glyph_id) n_g.v_advance=((double)theFace->glyph->metrics.vertAdvance)/((double)theFace->units_per_EM); n_g.v_width=((double)theFace->glyph->metrics.height)/((double)theFace->units_per_EM); } else { - n_g.v_width=n_g.v_advance=((double)theFace->height)/((double)theFace->units_per_EM); + // CSS3 Writing modes dictates that if vertical font metrics are missing we must + // synthisize them. No method is specified. The SVG 1.1 spec suggests using the em + // height (which is not theFace->height as that includes leading). The em height + // is ascender + descender (descender positive). Note: The "Requirements for + // Japanese Text Layout" W3C document says that Japanese kanji should be "set + // solid" which implies that vertical (and horizontal) advance should be 1em. + n_g.v_width=n_g.v_advance= 1.0; } if ( theFace->glyph->format == ft_glyph_format_outline ) { FT_Outline_Funcs ft2_outline_funcs = { @@ -501,7 +523,7 @@ void font_instance::LoadGlyph(int glyph_id) } } -bool font_instance::FontMetrics(double &ascent,double &descent,double &leading) +bool font_instance::FontMetrics(double &ascent,double &descent,double &xheight) { if ( pFont == NULL ) { return false; @@ -510,32 +532,17 @@ bool font_instance::FontMetrics(double &ascent,double &descent,double &leading) if ( theFace == NULL ) { return false; } -#ifdef USE_PANGO_WIN32 - OUTLINETEXTMETRIC otm; - if ( !GetOutlineTextMetrics(parent->hScreenDC,sizeof(otm),&otm) ) { - return false; - } - double scale=1.0/parent->fontSize; - ascent=fabs(otm.otmAscent*scale); - descent=fabs(otm.otmDescent*scale); - leading=fabs(otm.otmLineGap*scale); - //otmSubscriptSize, otmSubscriptOffset, otmSuperscriptSize, otmSuperscriptOffset, -#else - if ( theFace->units_per_EM == 0 ) { - return false; // bitmap font - } - ascent=fabs(((double)theFace->ascender)/((double)theFace->units_per_EM)); - descent=fabs(((double)theFace->descender)/((double)theFace->units_per_EM)); - leading=fabs(((double)theFace->height)/((double)theFace->units_per_EM)); - leading-=ascent+descent; -#endif + + ascent = _ascent; + descent = _descent; + xheight = _xheight; + return true; } -bool font_instance::FontDecoration( - double &underline_position, double &underline_thickness, - double &linethrough_position, double &linethrough_thickness -){ +bool font_instance::FontDecoration( double &underline_position, double &underline_thickness, + double &linethrough_position, double &linethrough_thickness) +{ if ( pFont == NULL ) { return false; } @@ -662,6 +669,179 @@ double font_instance::Advance(int glyph_id,bool vertical) return 0; } +// Internal function to find baselines +void font_instance::FindFontMetrics() { + + // CSS2 recommends using the OS/2 values sTypoAscender and sTypoDescender for the Typographic + // ascender and descender values: + // http://www.w3.org/TR/CSS2/visudet.html#sTypoAscender + // On Windows, the typographic ascender and descender are taken from the otmMacAscent and + // otmMacDescent values: + // http://microsoft.public.win32.programmer.gdi.narkive.com/LV6k4BDh/msdn-documentation-outlinetextmetrics-clarification + // The otmAscent and otmDescent values are the maxiumum ascent and maxiumum descent of all the + // glyphs in a font. + if ( theFace ) { + +#ifdef USE_PANGO_WIN32 + + if ( GetOutlineTextMetrics(parent->hScreenDC,sizeof(otm),&otm) ) { + double scale=1.0/parent->fontSize; + _ascent = fabs(otm.otmMacAscent * scale); + _descent = fabs(otm.otmMacDescent * scale); + _xheight = fabs(otm.otmXHeight * scale); + _ascent_max = fabs(otm.otmAscent * scale); + _descent_max = fabs(otm.otmDescent * scale); + + // In CSS em size is ascent + descent... which should be 1. If not, + // adjust so it is. + double em = _ascent + _descent; + if( em > 0 ) { + _ascent /= em; + _descent /= em; + } + + // May not be necessary but if OS/2 table missing or not version 2 or higher, + // xheight might be zero. + if( _xheight == 0.0 ) { + _xheight = 0.5; + } + + // Baselines defined relative to alphabetic. + _baselines[ SP_CSS_BASELINE_IDEOGRAPHIC ] = -_descent; // Recommendation + _baselines[ SP_CSS_BASELINE_HANGING ] = 0.8 * _ascent; // Guess + _baselines[ SP_CSS_BASELINE_MATHEMATICAL ] = 0.8 * _xheight; // Guess + _baselines[ SP_CSS_BASELINE_CENTRAL ] = 0.5 - _descent; // Definition + _baselines[ SP_CSS_BASELINE_MIDDLE ] = 0.5 * _xheight; // Definition + _baselines[ SP_CSS_BASELINE_TEXT_BEFORE_EDGE ] = _ascent; // Definition + _baselines[ SP_CSS_BASELINE_TEXT_AFTER_EDGE ] = -_descent; // Definition + + + MAT2 identity = {{0,1},{0,0},{0,0},{0,1}}; + GLYPHMETRICS metrics; + int retval; + + // Better math baseline: + // Try center of minus sign + retval = GetGlyphOutline (parent->hScreenDC, 0x2212, GGO_NATIVE | GGO_UNHINTED, &metrics, 0, NULL, &identity); + // If no minus sign, try hyphen + if( retval <= 0 ) + retval = GetGlyphOutline (parent->hScreenDC, '-', GGO_NATIVE | GGO_UNHINTED, &metrics, 0, NULL, &identity); + + if( retval > 0 ) { + double math = (metrics.gmptGlyphOrigin.y + 0.5 * metrics.gmBlackBoxY) * scale; + _baselines[ SP_CSS_BASELINE_MATHEMATICAL ] = math; + } + + // Find hanging baseline... assume it is at top of 'म'. + retval = GetGlyphOutline (parent->hScreenDC, 0x092E, GGO_NATIVE | GGO_UNHINTED, &metrics, 0, NULL, &identity); + if( retval > 0 ) { + double hanging = metrics.gmptGlyphOrigin.y * scale; + _baselines[ SP_CSS_BASELINE_MATHEMATICAL ] = hanging; + } + } + +#else + + if ( theFace->units_per_EM != 0 ) { // If zero then it's a bitmap font. + + TT_OS2* os2 = (TT_OS2*)FT_Get_Sfnt_Table( theFace, ft_sfnt_os2 ); + if( os2 ) { + _ascent = fabs(((double)os2->sTypoAscender) / ((double)theFace->units_per_EM)); + _descent = fabs(((double)os2->sTypoDescender)/ ((double)theFace->units_per_EM)); + } else { + _ascent = fabs(((double)theFace->ascender) / ((double)theFace->units_per_EM)); + _descent = fabs(((double)theFace->descender) / ((double)theFace->units_per_EM)); + } + _ascent_max = fabs(((double)theFace->ascender) / ((double)theFace->units_per_EM)); + _descent_max = fabs(((double)theFace->descender) / ((double)theFace->units_per_EM)); + + // In CSS em size is ascent + descent... which should be 1. If not, + // adjust so it is. + double em = _ascent + _descent; + if( em > 0 ) { + _ascent /= em; + _descent /= em; + } + + // x-height + if( os2 && os2->version >= 0x0002 && os2->version != 0xffffu ) { + // Only os/2 version 2 and above have sxHeight, 0xffff marks "old Mac fonts" without table + _xheight = fabs(((double)os2->sxHeight) / ((double)theFace->units_per_EM)); + } else { + // Measure 'x' height in font. Recommended option by XSL standard if no sxHeight. + FT_UInt index = FT_Get_Char_Index( theFace, 'x' ); + if( index != 0 ) { + FT_Load_Glyph( theFace, index, FT_LOAD_NO_SCALE ); + _xheight = (fabs)(((double)theFace->glyph->metrics.height/(double)theFace->units_per_EM)); + } else { + // No 'x' in font! + _xheight = 0.5; + } + } + + // Baselines defined relative to alphabetic. + _baselines[ SP_CSS_BASELINE_IDEOGRAPHIC ] = -_descent; // Recommendation + _baselines[ SP_CSS_BASELINE_HANGING ] = 0.8 * _ascent; // Guess + _baselines[ SP_CSS_BASELINE_MATHEMATICAL ] = 0.8 * _xheight; // Guess + _baselines[ SP_CSS_BASELINE_CENTRAL ] = 0.5 - _descent; // Definition + _baselines[ SP_CSS_BASELINE_MIDDLE ] = 0.5 * _xheight; // Definition + _baselines[ SP_CSS_BASELINE_TEXT_BEFORE_EDGE ] = _ascent; // Definition + _baselines[ SP_CSS_BASELINE_TEXT_AFTER_EDGE ] = -_descent; // Definition + + // Better math baseline: + // Try center of minus sign + FT_UInt index = FT_Get_Char_Index( theFace, 0x2212 ); //'−' + // If no minus sign, try hyphen + if( index == 0 ) + index = FT_Get_Char_Index( theFace, '-' ); + + if( index != 0 ) { + FT_Load_Glyph( theFace, index, FT_LOAD_NO_SCALE ); + FT_Glyph aglyph; + FT_Get_Glyph( theFace->glyph, &aglyph ); + FT_BBox acbox; + FT_Glyph_Get_CBox( aglyph, FT_GLYPH_BBOX_UNSCALED, &acbox ); + double math = (acbox.yMin + acbox.yMax)/2.0/(double)theFace->units_per_EM; + _baselines[ SP_CSS_BASELINE_MATHEMATICAL ] = math; + // std::cout << "Math baseline: - bbox: y_min: " << acbox.yMin + // << " y_max: " << acbox.yMax + // << " math: " << math << std::endl; + } + + // Find hanging baseline... assume it is at top of 'म'. + index = FT_Get_Char_Index( theFace, 0x092E ); // 'म' + if( index != 0 ) { + FT_Load_Glyph( theFace, index, FT_LOAD_NO_SCALE ); + FT_Glyph aglyph; + FT_Get_Glyph( theFace->glyph, &aglyph ); + FT_BBox acbox; + FT_Glyph_Get_CBox( aglyph, FT_GLYPH_BBOX_UNSCALED, &acbox ); + double hanging = (double)acbox.yMax/(double)theFace->units_per_EM; + _baselines[ SP_CSS_BASELINE_HANGING ] = hanging; + // std::cout << "Hanging baseline: प: " << hanging << std::endl; + } + } +#endif + // const gchar *family = pango_font_description_get_family(descr); + // std::cout << "Font: " << (family?family:"null") << std::endl; + // std::cout << " ascent: " << _ascent << std::endl; + // std::cout << " descent: " << _descent << std::endl; + // std::cout << " x-height: " << _xheight << std::endl; + // std::cout << " max ascent: " << _ascent_max << std::endl; + // std::cout << " max descent: " << _descent_max << std::endl; + // std::cout << " Baselines:" << std::endl; + // std::cout << " alphabetic: " << _baselines[ SP_CSS_BASELINE_ALPHABETIC ] << std::endl; + // std::cout << " ideographic: " << _baselines[ SP_CSS_BASELINE_IDEOGRAPHIC ] << std::endl; + // std::cout << " hanging: " << _baselines[ SP_CSS_BASELINE_HANGING ] << std::endl; + // std::cout << " math: " << _baselines[ SP_CSS_BASELINE_MATHEMATICAL ] << std::endl; + // std::cout << " central: " << _baselines[ SP_CSS_BASELINE_CENTRAL ] << std::endl; + // std::cout << " middle: " << _baselines[ SP_CSS_BASELINE_MIDDLE ] << std::endl; + // std::cout << " text_before: " << _baselines[ SP_CSS_BASELINE_TEXT_BEFORE_EDGE ] << std::endl; + // std::cout << " text_after: " << _baselines[ SP_CSS_BASELINE_TEXT_AFTER_EDGE ] << std::endl; + } +} + + /* Local Variables: mode:c++ diff --git a/src/libnrtype/Layout-TNG-Compute.cpp b/src/libnrtype/Layout-TNG-Compute.cpp index d81e1b6b4..e862f0657 100644 --- a/src/libnrtype/Layout-TNG-Compute.cpp +++ b/src/libnrtype/Layout-TNG-Compute.cpp @@ -23,17 +23,6 @@ namespace Text { #define TRACE(_args) IFTRACE(g_print _args) -// ******* enum conversion tables -static Layout::EnumConversionItem const enum_convert_spstyle_direction_to_pango_direction[] = { - {SP_CSS_WRITING_MODE_LR_TB, PANGO_DIRECTION_LTR}, - {SP_CSS_WRITING_MODE_RL_TB, PANGO_DIRECTION_RTL}, - {SP_CSS_WRITING_MODE_TB_LR, PANGO_DIRECTION_LTR}}; // this is correct - -static Layout::EnumConversionItem const enum_convert_spstyle_direction_to_my_direction[] = { - {SP_CSS_WRITING_MODE_LR_TB, Layout::LEFT_TO_RIGHT}, - {SP_CSS_WRITING_MODE_RL_TB, Layout::RIGHT_TO_LEFT}, - {SP_CSS_WRITING_MODE_TB_LR, Layout::LEFT_TO_RIGHT}}; // this is correct - /** \brief private to Layout. Does the real work of text flowing. This class does a standard greedy paragraph wrapping algorithm. @@ -124,9 +113,10 @@ class Layout::Calculator unsigned input_index; /// index into Layout::_input_stream Glib::ustring::const_iterator input_stream_first_character; double font_size; - LineHeight line_height; /// This is not the CSS line-height attribute! + FontMetrics line_height; /// This is not the CSS line-height attribute! double line_height_multiplier; /// calculated from the font-height css property double baseline_shift; /// calculated from the baseline-shift css property + SPCSSTextOrientation text_orientation; unsigned text_bytes; unsigned char_index_in_para; /// the index of the first character in this span in the paragraph, for looking up char_attributes SVGLength x, y, dx, dy, rotate; // these are reoriented copies of the <tspan> attributes. We change span when we encounter one. @@ -204,9 +194,8 @@ class Layout::Calculator void _buildPangoItemizationForPara(ParagraphInfo *para) const; - static void _computeFontLineHeight(font_instance *font, double font_size, - SPStyle const *style, LineHeight *line_height, - double *line_height_multiplier); + // Returns line_height_multiplier + static double _computeFontLineHeight( SPStyle const *style ); unsigned _buildSpansForPara(ParagraphInfo *para) const; @@ -254,7 +243,7 @@ static void dumpUnbrokenSpans(ParagraphInfo *para){ bool _goToNextWrapShape(); bool _findChunksForLine(ParagraphInfo const ¶, UnbrokenSpanPosition *start_span_pos, - std::vector<ChunkInfo> *chunk_info, LineHeight *line_height); + std::vector<ChunkInfo> *chunk_info, FontMetrics *line_box_height); static inline PangoLogAttr const &_charAttributes(ParagraphInfo const ¶, UnbrokenSpanPosition const &span_pos) @@ -266,7 +255,8 @@ static void dumpUnbrokenSpans(ParagraphInfo *para){ UnbrokenSpanPosition const &start_span_pos, ScanlineMaker::ScanRun const &scan_run, std::vector<ChunkInfo> *chunk_info, - LineHeight *line_height) const; + FontMetrics *line_height, + FontMetrics const *strut_height) const; /** computes the width of a single UnbrokenSpan (pointed to by span->start.iter_span) and outputs its vital statistics into the other fields of \a span. @@ -281,11 +271,15 @@ static void dumpUnbrokenSpans(ParagraphInfo *para){ or will be unaltered if there is none. */ bool _measureUnbrokenSpan(ParagraphInfo const ¶, BrokenSpan *span, BrokenSpan *last_break_span, BrokenSpan *last_emergency_break_span, double maximum_width) const { + TRACE((" start _measureUnbrokenSpan %g\n", maximum_width)); span->setZero(); if (span->start.iter_span->dx._set && span->start.char_byte == 0){ - if(para.direction == RIGHT_TO_LEFT){ span->width -= span->start.iter_span->dx.computed; } - else { span->width += span->start.iter_span->dx.computed; } + if(para.direction == RIGHT_TO_LEFT){ + span->width -= span->start.iter_span->dx.computed; + } else { + span->width += span->start.iter_span->dx.computed; + } } if (span->start.iter_span->pango_item_index == -1) { @@ -304,7 +298,7 @@ static void dumpUnbrokenSpans(ParagraphInfo *para){ if (control_code->code == ARBITRARY_GAP) { if (span->width + control_code->width > maximum_width) return false; - TRACE(("fitted control code, width = %f\n", control_code->width)); + TRACE((" fitted control code, width = %f\n", control_code->width)); span->width += control_code->width; span->end.increment(); } @@ -343,12 +337,14 @@ static void dumpUnbrokenSpans(ParagraphInfo *para){ PangoLogAttr const &char_attributes = _charAttributes(para, span->end); if (char_attributes.is_mandatory_break && span->end != span->start) { + TRACE((" is_mandatory_break ************\n")); *last_emergency_break_span = *last_break_span = *span; - TRACE(("span %ld end of para; width = %f chars = %d\n", span->start.iter_span - para.unbroken_spans.begin(), span->width, char_count)); + TRACE((" span %ld end of para; width = %f chars = %d\n", span->start.iter_span - para.unbroken_spans.begin(), span->width, char_count)); return false; } if (char_attributes.is_line_break) { + TRACE((" is_line_break ************\n")); // a suitable position to break at, record where we are *last_emergency_break_span = *last_break_span = *span; if (soft_hyphen_in_word) { @@ -366,10 +362,22 @@ static void dumpUnbrokenSpans(ParagraphInfo *para){ double char_width = 0.0; while (span->end_glyph_index < (unsigned)span->end.iter_span->glyph_string->num_glyphs && span->end.iter_span->glyph_string->log_clusters[span->end_glyph_index] <= (int)span->end.char_byte) { - if (_block_progression == LEFT_TO_RIGHT || _block_progression == RIGHT_TO_LEFT) - char_width += span->start.iter_span->font_size * para.pango_items[span->end.iter_span->pango_item_index].font->Advance(span->end.iter_span->glyph_string->glyphs[span->end_glyph_index].glyph, true); - else + if (_block_progression == LEFT_TO_RIGHT || _block_progression == RIGHT_TO_LEFT) { + // Vertical text + + if( text_source->style->text_orientation.computed == SP_CSS_TEXT_ORIENTATION_SIDEWAYS || + (text_source->style->text_orientation.computed == SP_CSS_TEXT_ORIENTATION_MIXED && + para.pango_items[span->end.iter_span->pango_item_index].item->analysis.gravity == 0) ) { + // Sideways orientation + char_width += span->start.iter_span->font_size * para.pango_items[span->end.iter_span->pango_item_index].font->Advance(span->end.iter_span->glyph_string->glyphs[span->end_glyph_index].glyph, false); + } else { + // Upright orientation + char_width += span->start.iter_span->font_size * para.pango_items[span->end.iter_span->pango_item_index].font->Advance(span->end.iter_span->glyph_string->glyphs[span->end_glyph_index].glyph, true); + } + } else { + // Horizontal text char_width += font_size_multiplier * span->end.iter_span->glyph_string->glyphs[span->end_glyph_index].geometry.width; + } span->end_glyph_index++; } if (char_attributes.is_cursor_position) @@ -401,13 +409,14 @@ static void dumpUnbrokenSpans(ParagraphInfo *para){ span->word_spacing = text_source->style->word_spacing.computed; if (test_width > maximum_width && !char_attributes.is_white) { // whitespaces don't matter, we can put as many as we want at eol - TRACE(("span %ld exceeded scanrun; width = %f chars = %d\n", span->start.iter_span - para.unbroken_spans.begin(), span->width, char_count)); + TRACE((" span %ld exceeded scanrun; width = %f chars = %d\n", span->start.iter_span - para.unbroken_spans.begin(), span->width, char_count)); return false; } } while (span->end.char_byte != 0); // while we haven't wrapped to the next span - TRACE(("fitted span %ld width = %f chars = %d\n", span->start.iter_span - para.unbroken_spans.begin(), span->width, char_count)); + TRACE((" fitted span %ld width = %f chars = %d\n", span->start.iter_span - para.unbroken_spans.begin(), span->width, char_count)); + TRACE((" end _measureUnbrokenSpan %g\n", maximum_width)); return true; } @@ -458,19 +467,33 @@ static void dumpUnbrokenSpans(ParagraphInfo *para){ are ready to output the final result to #_flow. This method takes its input parameters and does that. */ - void _outputLine(ParagraphInfo const ¶, LineHeight const &line_height, std::vector<ChunkInfo> const &chunk_info) + void _outputLine(ParagraphInfo const ¶, FontMetrics const &line_height, std::vector<ChunkInfo> const &chunk_info) { - TRACE(("Start _outputLine\n")); + TRACE((" Start _outputLine: ascent %f, descent %f, top of box %f\n", line_height.ascent, line_height.descent, _scanline_maker->yCoordinate() )); if (chunk_info.empty()) { - TRACE(("line too short to fit anything on it, go to next\n")); + TRACE((" line too short to fit anything on it, go to next\n")); return; } // we've finished fiddling about with ascents and descents: create the output - TRACE(("found line fit; creating output\n")); + TRACE((" found line fit; creating output\n")); Layout::Line new_line; new_line.in_paragraph = _flow._paragraphs.size() - 1; - new_line.baseline_y = _scanline_maker->yCoordinate() + line_height.ascent; + new_line.baseline_y = _scanline_maker->yCoordinate(); + + // The y coordinate is at the beginning edge of the line box (top for horizontal text, left + // edge for vertical lr text, right edge for vertical rl text. We align, by default to the + // alphabetic baseline for horizontal text and the central baseline for vertical text. + if( _block_progression == RIGHT_TO_LEFT ) { + // Vertical text, use em box center as baseline + new_line.baseline_y -= 0.5 * line_height.emSize(); + } else if ( _block_progression == LEFT_TO_RIGHT ) { + // Vertical text, use em box center as baseline + new_line.baseline_y += 0.5 * line_height.emSize(); + } else { + new_line.baseline_y += line_height.getTypoAscent(); + } + new_line.in_shape = _current_shape_index; _flow._lines.push_back(new_line); @@ -480,7 +503,7 @@ static void dumpUnbrokenSpans(ParagraphInfo *para){ // add the chunk to the list Layout::Chunk new_chunk; new_chunk.in_line = _flow._lines.size() - 1; - TRACE((" New chunk: in_line: %d\n", new_chunk.in_line)); + TRACE((" New chunk: in_line: %d\n", new_chunk.in_line)); new_chunk.left_x = _getChunkLeftWithAlignment(para, it_chunk, &add_to_each_whitespace); // we may also have y move orders to deal with here (dx, dy and rotate are done per span) @@ -511,17 +534,27 @@ static void dumpUnbrokenSpans(ParagraphInfo *para){ // If <tspan> "y" attribute is set, use it (initial "y" attributes in // <tspans> other than the first have already been stripped for <tspans> // marked with role="line", see sp-text.cpp: SPText::_buildLayoutInput). + // NOTE: for vertical text, "y" is the user-space "x" value. if( it_chunk->broken_spans.front().start.iter_span->y._set ) { // Use set "y" attribute new_line.baseline_y = it_chunk->broken_spans.front().start.iter_span->y.computed; - // Save baseline _flow._lines.back().baseline_y = new_line.baseline_y; - // Save new <tspan> y coordinate - _scanline_maker->setNewYCoordinate(new_line.baseline_y - line_height.ascent); - + double top_of_line_box = new_line.baseline_y; + if( _block_progression == RIGHT_TO_LEFT ) { + // Vertical text, use em box center as baseline + top_of_line_box += 0.5 * line_height.emSize(); + } else if (_block_progression == LEFT_TO_RIGHT ) { + // Vertical text, use em box center as baseline + top_of_line_box -= 0.5 * line_height.emSize(); + } else { + top_of_line_box -= line_height.getTypoAscent(); + } + TRACE((" y attribute set, next line top_of_line_box: %f\n", top_of_line_box )); + // Set the initial y coordinate of the next line (see above). + _scanline_maker->setNewYCoordinate(top_of_line_box); } // Reset relative y_offset ("dy" attribute is relative but should be reset at @@ -540,21 +573,21 @@ static void dumpUnbrokenSpans(ParagraphInfo *para){ } _flow._chunks.push_back(new_chunk); - double x; + double current_x; double direction_sign; Direction previous_direction = para.direction; double counter_directional_width_remaining = 0.0; float glyph_rotate = 0.0; if (para.direction == LEFT_TO_RIGHT) { direction_sign = +1.0; - x = 0.0; + current_x = 0.0; } else { direction_sign = -1.0; if (para.alignment == FULL && !_flow._input_wrap_shapes.empty()){ - x = it_chunk->scanrun_width; + current_x = it_chunk->scanrun_width; } else { - x = it_chunk->text_width; + current_x = it_chunk->text_width; } } @@ -567,7 +600,7 @@ static void dumpUnbrokenSpans(ParagraphInfo *para){ if (it_span->start.char_byte == 0) { // Start of an unbroken span, we might have dx, dy or rotate still to process // (x and y are done per chunk) - if (unbroken_span.dx._set) x += unbroken_span.dx.computed; + if (unbroken_span.dx._set) current_x += unbroken_span.dx.computed; if (unbroken_span.dy._set) _y_offset += unbroken_span.dy.computed; if (unbroken_span.rotate._set) glyph_rotate = unbroken_span.rotate.computed * (M_PI/180); } @@ -585,6 +618,7 @@ static void dumpUnbrokenSpans(ParagraphInfo *para){ new_span.in_input_stream_item = unbroken_span.input_index; new_span.baseline_shift = 0.0; new_span.block_progression = _block_progression; + new_span.text_orientation = unbroken_span.text_orientation; if ((_flow._input_stream[unbroken_span.input_index]->Type() == TEXT_SOURCE) && (new_span.font = para.pango_items[unbroken_span.pango_item_index].font)) { new_span.font->Ref(); @@ -593,12 +627,12 @@ static void dumpUnbrokenSpans(ParagraphInfo *para){ new_span.input_stream_first_character = Glib::ustring::const_iterator(unbroken_span.input_stream_first_character.base() + it_span->start.char_byte); } else { // a control code new_span.font = NULL; - new_span.font_size = new_span.line_height.ascent + new_span.line_height.descent; + new_span.font_size = new_span.line_height.emSize(); new_span.direction = para.direction; } if (new_span.direction == para.direction) { - x -= counter_directional_width_remaining; + current_x -= counter_directional_width_remaining; counter_directional_width_remaining = 0.0; } else if (new_span.direction != previous_direction) { // measure width of spans we need to switch round @@ -614,10 +648,10 @@ static void dumpUnbrokenSpans(ParagraphInfo *para){ } counter_directional_width_remaining += direction_sign * (it_following_span->width + it_following_span->whitespace_count * add_to_each_whitespace); } - x += counter_directional_width_remaining; + current_x += counter_directional_width_remaining; counter_directional_width_remaining = 0.0; // we want to go increasingly negative } - new_span.x_start = x; + new_span.x_start = current_x; if (_flow._input_stream[unbroken_span.input_index]->Type() == TEXT_SOURCE) { // the span is set up, push the glyphs and chars @@ -657,10 +691,12 @@ static void dumpUnbrokenSpans(ParagraphInfo *para){ } // create the Layout::Glyph + PangoGlyphInfo *unbroken_span_glyph_info = &unbroken_span.glyph_string->glyphs[glyph_index]; Layout::Glyph new_glyph; - new_glyph.glyph = unbroken_span.glyph_string->glyphs[glyph_index].glyph; + new_glyph.glyph = unbroken_span_glyph_info->glyph; new_glyph.in_character = _flow._characters.size(); new_glyph.rotation = glyph_rotate; + new_glyph.orientation = ORIENTATION_UPRIGHT; // Only effects vertical text // We may have scaled font size to fit textLength; now, if // @lengthAdjust=spacingAndGlyphs, this scaling must be only horizontal, @@ -670,30 +706,68 @@ static void dumpUnbrokenSpans(ParagraphInfo *para){ else new_glyph.vertical_scale = 1.0; - /* put something like this back in when we do glyph-rotation-horizontal/vertical - if (new_span.block_progression == LEFT_TO_RIGHT || new_span.block_progression == RIGHT_TO_LEFT) { - new_glyph.x += new_span.line_height.ascent; - new_glyph.y -= unbroken_span.glyph_string->glyphs[glyph_index].geometry.width * font_size_multiplier * 0.5; - new_glyph.width = new_span.line_height.ascent + new_span.line_height.descent; - } else */ + // Position glyph -------------------- + new_glyph.x = current_x + unbroken_span_glyph_info->geometry.x_offset * font_size_multiplier; + new_glyph.y =_y_offset; + + // y-coordinate is flipped between vertical and horizontal text... delta_y is common offset but applied with opposite sign + double delta_y = unbroken_span_glyph_info->geometry.y_offset * font_size_multiplier + unbroken_span.baseline_shift; + SPCSSBaseline dominant_baseline = _flow._blockBaseline(); if (_block_progression == LEFT_TO_RIGHT || _block_progression == RIGHT_TO_LEFT) { - new_glyph.x = x + unbroken_span.glyph_string->glyphs[glyph_index].geometry.x_offset * font_size_multiplier + new_span.line_height.ascent; - new_glyph.y = _y_offset - - unbroken_span.baseline_shift + - (unbroken_span.glyph_string->glyphs[glyph_index].geometry.y_offset - - unbroken_span.glyph_string->glyphs[glyph_index].geometry.width * 0.5) * font_size_multiplier; - new_glyph.width = new_span.font_size * para.pango_items[unbroken_span.pango_item_index].font->Advance(unbroken_span.glyph_string->glyphs[glyph_index].glyph, true); + // Vertical text + + // Default dominant baseline is determined by overall block (i.e. <text>) 'text-orientation' value. + if( _flow._blockTextOrientation() != SP_CSS_TEXT_ORIENTATION_SIDEWAYS ) { + if( dominant_baseline == SP_CSS_BASELINE_AUTO ) dominant_baseline = SP_CSS_BASELINE_CENTRAL; + } else { + if( dominant_baseline == SP_CSS_BASELINE_AUTO ) dominant_baseline = SP_CSS_BASELINE_ALPHABETIC; + } + + new_glyph.y += delta_y; + + // TODO: Should also check 'glyph_orientation_vertical' if 'text-orientation' is unset... + if( new_span.text_orientation == SP_CSS_TEXT_ORIENTATION_SIDEWAYS || + (new_span.text_orientation == SP_CSS_TEXT_ORIENTATION_MIXED && + para.pango_items[unbroken_span.pango_item_index].item->analysis.gravity == 0) ) { + + // Sideways orientation (Latin characters, CJK punctuation), 90deg rotation done at output stage. zzzzzzz + new_glyph.orientation = ORIENTATION_SIDEWAYS; + + new_glyph.y -= new_span.font_size * para.pango_items[unbroken_span.pango_item_index].font->GetBaselines()[ dominant_baseline ]; + new_glyph.width = new_span.font_size * para.pango_items[unbroken_span.pango_item_index].font->Advance(unbroken_span_glyph_info->glyph, false); + + } else { + // Upright orientation + + new_glyph.x += new_span.line_height.ascent; + + // Glyph reference point is center (shift: left edge to center glyph) + new_glyph.y -= unbroken_span_glyph_info->geometry.width * 0.5 * font_size_multiplier; + new_glyph.y -= new_span.font_size * (para.pango_items[unbroken_span.pango_item_index].font->GetBaselines()[ dominant_baseline ] - + para.pango_items[unbroken_span.pango_item_index].font->GetBaselines()[ SP_CSS_BASELINE_CENTRAL ] ); + + new_glyph.width = new_span.font_size * para.pango_items[unbroken_span.pango_item_index].font->Advance(unbroken_span_glyph_info->glyph, true); + if( new_glyph.width == 0 ) { + new_glyph.width = unbroken_span_glyph_info->geometry.width * font_size_multiplier; + } + + } } else { - new_glyph.x = x + unbroken_span.glyph_string->glyphs[glyph_index].geometry.x_offset * font_size_multiplier; - new_glyph.y = _y_offset - - unbroken_span.baseline_shift + - unbroken_span.glyph_string->glyphs[glyph_index].geometry.y_offset * font_size_multiplier; - new_glyph.width = unbroken_span.glyph_string->glyphs[glyph_index].geometry.width * font_size_multiplier; + // Horizontal text + + if( dominant_baseline == SP_CSS_BASELINE_AUTO ) dominant_baseline = SP_CSS_BASELINE_ALPHABETIC; + + new_glyph.y -= delta_y; + new_glyph.y += new_span.font_size * para.pango_items[unbroken_span.pango_item_index].font->GetBaselines()[ dominant_baseline ]; + + new_glyph.width = unbroken_span_glyph_info->geometry.width * font_size_multiplier; if ((new_glyph.width == 0) && (para.pango_items[unbroken_span.pango_item_index].font)) - new_glyph.width = new_span.font_size * para.pango_items[unbroken_span.pango_item_index].font->Advance(unbroken_span.glyph_string->glyphs[glyph_index].glyph, false); + new_glyph.width = new_span.font_size * para.pango_items[unbroken_span.pango_item_index].font->Advance(unbroken_span_glyph_info->glyph, false); // for some reason pango returns zero width for invalid glyph characters (those empty boxes), so go to freetype for the info } + + if (new_span.direction == RIGHT_TO_LEFT) { // pango wanted to give us glyphs in visual order but we refused, so we need to work // out where the cluster start is ourselves @@ -702,13 +776,15 @@ static void dumpUnbrokenSpans(ParagraphInfo *para){ if (unbroken_span.glyph_string->glyphs[rtl_index].attr.is_cluster_start && rtl_index != glyph_index) break; if (_block_progression == LEFT_TO_RIGHT || _block_progression == RIGHT_TO_LEFT) + // Vertical text cluster_width += new_span.font_size * para.pango_items[unbroken_span.pango_item_index].font->Advance(unbroken_span.glyph_string->glyphs[rtl_index].glyph, true); else + // Horizontal text cluster_width += font_size_multiplier * unbroken_span.glyph_string->glyphs[rtl_index].geometry.width; } new_glyph.x -= cluster_width; } - _flow._glyphs.push_back(new_glyph); + _flow._glyphs.push_back(new_glyph); // create the Layout::Character(s) double advance_width = new_glyph.width; @@ -765,15 +841,15 @@ static void dumpUnbrokenSpans(ParagraphInfo *para){ advance_width *= direction_sign; if (new_span.direction != para.direction) { counter_directional_width_remaining -= advance_width; - x -= advance_width; + current_x -= advance_width; x_in_span_last -= advance_width; } else { - x += advance_width; + current_x += advance_width; x_in_span_last += advance_width; } } } else if (_flow._input_stream[unbroken_span.input_index]->Type() == CONTROL_CODE) { - x += static_cast<InputStreamControlCode const *>(_flow._input_stream[unbroken_span.input_index])->width; + current_x += static_cast<InputStreamControlCode const *>(_flow._input_stream[unbroken_span.input_index])->width; } new_span.x_end = new_span.x_start + x_in_span_last; @@ -782,7 +858,7 @@ static void dumpUnbrokenSpans(ParagraphInfo *para){ } // end adding spans to the list, on to the next chunk... } - TRACE(("output done\n")); + TRACE((" End _outputLine\n")); } /* *********************************************************************************************************/ @@ -962,6 +1038,7 @@ void Layout::Calculator::_buildPangoItemizationForPara(ParagraphInfo *para) con #if PANGO_VERSION_CHECK(1,37,1) TRACE((" ... compiled for font features\n")); #endif + Glib::ustring para_text; PangoAttrList *attributes_list; unsigned input_index; @@ -983,10 +1060,10 @@ void Layout::Calculator::_buildPangoItemizationForPara(ParagraphInfo *para) con } else if (_flow._input_stream[input_index]->Type() == TEXT_SOURCE) { Layout::InputStreamTextSource *text_source = static_cast<Layout::InputStreamTextSource *>(_flow._input_stream[input_index]); - // create the font_instance - font_instance *font = text_source->styleGetFontInstance(); - if (font == NULL) - continue; // bad news: we'll have to ignore all this text because we know of no font to render it + // create the font_instance + font_instance *font = text_source->styleGetFontInstance(); + if (font == NULL) + continue; // bad news: we'll have to ignore all this text because we know of no font to render it PangoAttribute *attribute_font_description = pango_attr_font_desc_new(font->descr); attribute_font_description->start_index = para_text.bytes(); @@ -1012,25 +1089,22 @@ void Layout::Calculator::_buildPangoItemizationForPara(ParagraphInfo *para) con TRACE(("whole para: \"%s\"\n", para_text.data())); TRACE(("%d input sources used\n", input_index - para->first_input_index)); - // do the pango_itemize() GList *pango_items_glist = NULL; + para->direction = LEFT_TO_RIGHT; // CSS default if (_flow._input_stream[para->first_input_index]->Type() == TEXT_SOURCE) { Layout::InputStreamTextSource const *text_source = static_cast<Layout::InputStreamTextSource *>(_flow._input_stream[para->first_input_index]); - if (text_source->style->direction.set) { - PangoDirection pango_direction = (PangoDirection)_enum_converter(text_source->style->direction.computed, enum_convert_spstyle_direction_to_pango_direction, sizeof(enum_convert_spstyle_direction_to_pango_direction)/sizeof(enum_convert_spstyle_direction_to_pango_direction[0])); - pango_items_glist = pango_itemize_with_base_dir(_pango_context, pango_direction, para_text.data(), 0, para_text.bytes(), attributes_list, NULL); - para->direction = (Layout::Direction)_enum_converter(text_source->style->direction.computed, enum_convert_spstyle_direction_to_my_direction, sizeof(enum_convert_spstyle_direction_to_my_direction)/sizeof(enum_convert_spstyle_direction_to_my_direction[0])); - } + + para->direction = (text_source->style->direction.computed == SP_CSS_DIRECTION_LTR) ? LEFT_TO_RIGHT : RIGHT_TO_LEFT; + PangoDirection pango_direction = (text_source->style->direction.computed == SP_CSS_DIRECTION_LTR) ? PANGO_DIRECTION_LTR : PANGO_DIRECTION_RTL; + pango_items_glist = pango_itemize_with_base_dir(_pango_context, pango_direction, para_text.data(), 0, para_text.bytes(), attributes_list, NULL); } - if (pango_items_glist == NULL) { // no direction specified, guess it - pango_items_glist = pango_itemize(_pango_context, para_text.data(), 0, para_text.bytes(), attributes_list, NULL); - // I think according to the css spec this is wrong and we're never allowed to guess the directionality - // of a paragraph. Need to talk to an rtl speaker. - if (pango_items_glist == NULL || pango_items_glist->data == NULL) para->direction = LEFT_TO_RIGHT; - else para->direction = (((PangoItem*)pango_items_glist->data)->analysis.level & 1) ? RIGHT_TO_LEFT : LEFT_TO_RIGHT; + if( pango_items_glist == NULL ) { + // Type wasn't TEXT_SOURCE or direction was not set. + pango_items_glist = pango_itemize(_pango_context, para_text.data(), 0, para_text.bytes(), attributes_list, NULL); } + pango_attr_list_unref(attributes_list); // convert the GList to our vector<> and make the font_instance for each PangoItem at the same time @@ -1054,44 +1128,32 @@ void Layout::Calculator::_buildPangoItemizationForPara(ParagraphInfo *para) con } /** - * Gets the ascent, descent and leading for a font and the alteration that has to be performed - * according to the value specified by the line-height css property. The result of multiplying - * \a line_height by \a line_height_multiplier is the inline box height as specified in css2 - * section 10.8. + * Finds the value of line_height_multiplier given the 'line-height' property. The result of + * multiplying \a l by \a line_height_multiplier is the inline box height as specified in css2 + * section 10.8. http://www.w3.org/TR/CSS2/visudet.html#line-height + * + * The 'computed' value of 'line-height' does not have a consistent meaning. We need to find the + * 'used' value and divide that by the font size. */ -void Layout::Calculator::_computeFontLineHeight(font_instance *font, double font_size, - SPStyle const *style, LineHeight *line_height, - double *line_height_multiplier) +double Layout::Calculator::_computeFontLineHeight( SPStyle const *style ) { - if (font == NULL) { - line_height->setZero(); - *line_height_multiplier = 1.0; - } - else { - font->FontMetrics(line_height->ascent, line_height->descent, line_height->leading); - } - *line_height *= font_size; - // yet another borked SPStyle member that we're going to have to fix ourselves + // We shouldn't need to climb the element tree... for ( ; ; ) { if (style->line_height.set && !style->line_height.inherit) { if (style->line_height.normal) break; switch (style->line_height.unit) { case SP_CSS_UNIT_NONE: - *line_height_multiplier = style->line_height.computed * font_size / line_height->total(); - return; + return style->line_height.computed; case SP_CSS_UNIT_EX: - *line_height_multiplier = style->line_height.value * 0.5 * font_size / line_height->total(); + return style->line_height.value * 0.5; // 0.5 is an approximation of the x-height. Fixme. - return; case SP_CSS_UNIT_EM: case SP_CSS_UNIT_PERCENT: - *line_height_multiplier = style->line_height.value * font_size / line_height->total(); - return; + return style->line_height.value; default: // absolute values - *line_height_multiplier = style->line_height.computed / line_height->total(); - return; + return style->line_height.computed / style->font_size.computed; } break; } @@ -1099,7 +1161,7 @@ void Layout::Calculator::_computeFontLineHeight(font_instance *font, double font style = style->object->parent->style; if (style == NULL) break; } - *line_height_multiplier = LINE_HEIGHT_NORMAL * font_size / line_height->total(); + return (LINE_HEIGHT_NORMAL); } bool compareGlyphWidth(const PangoGlyphInfo &a, const PangoGlyphInfo &b) @@ -1139,7 +1201,6 @@ unsigned Layout::Calculator::_buildSpansForPara(ParagraphInfo *para) const new_span.input_index = input_index; new_span.line_height.ascent = control_code->ascent * _flow.getTextLengthMultiplierDue(); new_span.line_height.descent = control_code->descent * _flow.getTextLengthMultiplierDue(); - new_span.line_height.leading = 0.0; new_span.text_bytes = 0; new_span.char_index_in_para = char_index_in_para; para->unbroken_spans.push_back(new_span); @@ -1178,11 +1239,13 @@ unsigned Layout::Calculator::_buildSpansForPara(ParagraphInfo *para) const new_span.dy._set = false; new_span.rotate._set = false; if (_block_progression == TOP_TO_BOTTOM || _block_progression == BOTTOM_TO_TOP) { + // Horizontal text if (text_source->x.size() > char_index_in_source) new_span.x = text_source->x[char_index_in_source]; if (text_source->y.size() > char_index_in_source) new_span.y = text_source->y[char_index_in_source]; if (text_source->dx.size() > char_index_in_source) new_span.dx = text_source->dx[char_index_in_source].computed * _flow.getTextLengthMultiplierDue(); if (text_source->dy.size() > char_index_in_source) new_span.dy = text_source->dy[char_index_in_source].computed * _flow.getTextLengthMultiplierDue(); } else { + // Vertical text if (text_source->x.size() > char_index_in_source) new_span.y = text_source->x[char_index_in_source]; if (text_source->y.size() > char_index_in_source) new_span.x = text_source->y[char_index_in_source]; if (text_source->dx.size() > char_index_in_source) new_span.dy = text_source->dx[char_index_in_source].computed * _flow.getTextLengthMultiplierDue(); @@ -1215,7 +1278,7 @@ unsigned Layout::Calculator::_buildSpansForPara(ParagraphInfo *para) const } // now we know the length, do some final calculations and add the UnbrokenSpan to the list - new_span.font_size = text_source->styleComputeFontSize() * _flow.getTextLengthMultiplierDue(); + new_span.font_size = text_source->style->font_size.computed * _flow.getTextLengthMultiplierDue(); if (new_span.text_bytes) { new_span.glyph_string = pango_glyph_string_new(); /* Some assertions intended to help diagnose bug #1277746. */ @@ -1224,6 +1287,7 @@ unsigned Layout::Calculator::_buildSpansForPara(ParagraphInfo *para) const g_assert( span_start_byte_in_source + new_span.text_bytes <= text_source->text->bytes() ); g_assert( memchr(text_source->text->data() + span_start_byte_in_source, '\0', static_cast<size_t>(new_span.text_bytes)) == NULL ); + /* Notes as of 4/29/13. Pango_shape is not generating English language ligatures, but it is generating them for Hebrew (and probably other similar languages). In the case observed 3 unicode characters (a base and 2 Mark, nonspacings) are merged into two glyphs (the base + first Mn, the 2nd Mn). All of these map @@ -1231,6 +1295,8 @@ unsigned Layout::Calculator::_buildSpansForPara(ParagraphInfo *para) const characters and glyphs. A big chunk of the conditional code which immediately follows this call is there to clean up the resulting mess. */ + + // Convert characters to glyphs pango_shape(text_source->text->data() + span_start_byte_in_source, new_span.text_bytes, ¶->pango_items[pango_item_index].item->analysis, @@ -1308,11 +1374,14 @@ unsigned Layout::Calculator::_buildSpansForPara(ParagraphInfo *para) const /* glyphs[].x_offset values may be out of order within any log_clusters, apparently harmless */ } new_span.pango_item_index = pango_item_index; - _computeFontLineHeight(para->pango_items[pango_item_index].font, new_span.font_size, text_source->style, &new_span.line_height, &new_span.line_height_multiplier); + new_span.line_height_multiplier = _computeFontLineHeight( text_source->style ); + new_span.line_height.set( para->pango_items[pango_item_index].font ); + new_span.line_height *= new_span.font_size; // At some point we may want to calculate baseline_shift here (to take advantage // of otm features like superscript baseline), but for now we use style baseline_shift. new_span.baseline_shift = text_source->style->baseline_shift.computed; + new_span.text_orientation = (SPCSSTextOrientation)text_source->style->text_orientation.computed; // TODO: metrics for vertical text TRACE(("add text span %lu \"%s\"\n", para->unbroken_spans.size(), text_source->text->raw().substr(span_start_byte_in_source, new_span.text_bytes).c_str())); @@ -1322,11 +1391,13 @@ unsigned Layout::Calculator::_buildSpansForPara(ParagraphInfo *para) const new_span.pango_item_index = -1; font_instance *font = text_source->styleGetFontInstance(); if (font) { - _computeFontLineHeight(font, new_span.font_size, text_source->style, &new_span.line_height, &new_span.line_height_multiplier); + new_span.line_height_multiplier = _computeFontLineHeight( text_source->style ); + new_span.line_height.set( font ); + new_span.line_height *= new_span.font_size; font->Unref(); } else { - new_span.line_height.setZero(); - new_span.line_height_multiplier = 1.0; + new_span.line_height *= 0.0; // Set all to zero + new_span.line_height_multiplier = LINE_HEIGHT_NORMAL; } TRACE(("add style init span %lu\n", para->unbroken_spans.size())); } @@ -1376,60 +1447,54 @@ bool Layout::Calculator::_goToNextWrapShape() * bits of information that will prove useful when we come to output the * line to #_flow. Returns with \a start_span_pos set to the end of the * text that was fitted, \a chunk_info completely filled out and - * \a line_height set to the largest line box on the line. The return + * \a line_box_height set with the largest ascent and the largest + * descent (individually per CSS) on the line. The return * value is false only if we've run out of shapes to wrap inside (and * hence couldn't create any chunks). */ bool Layout::Calculator::_findChunksForLine(ParagraphInfo const ¶, UnbrokenSpanPosition *start_span_pos, std::vector<ChunkInfo> *chunk_info, - LineHeight *line_height) + FontMetrics *line_box_height) { - // init the initial line_height - if (start_span_pos->iter_span == para.unbroken_spans.end()) { - if (_flow._spans.empty()) { - // empty first para: create a font for the sole purpose of measuring it - InputStreamTextSource const *text_source = static_cast<InputStreamTextSource const *>(_flow._input_stream.front()); - font_instance *font = text_source->styleGetFontInstance(); - if (font) { - double font_size = text_source->styleComputeFontSize(); - double multiplier; - _computeFontLineHeight(font, font_size, text_source->style, line_height, &multiplier); - font->Unref(); - *line_height *= multiplier; - _scanline_maker->setNewYCoordinate(_scanline_maker->yCoordinate() - line_height->ascent); - } - } - // else empty subsequent para: keep the old line height + TRACE((" begin _findChunksForLine: chunks: %lu, em size: %f\n", chunk_info->size(), line_box_height->emSize() )); + + // CSS 2.1 dictates that the minimum line height (i.e. the strut height) is found from the block element. This, + // however, is not what the browsers seem to be doing. Instead, find the height from the first text source. + InputStreamTextSource const *text_source = static_cast<InputStreamTextSource const *>(_flow._input_stream.front()); + font_instance *font = text_source->styleGetFontInstance(); + if (font) { + double multiplier = _computeFontLineHeight(text_source->style); + line_box_height->set( font ); + *line_box_height *= text_source->style->font_size.computed; + font->Unref(); + line_box_height->computeEffective( multiplier ); } else { - if (_flow._input_wrap_shapes.empty()) { - // if we're not wrapping set the line_height big and negative so we can use negative line height - line_height->ascent = -1.0e10; - line_height->descent = -1.0e10; - line_height->leading = -1.0e10; - } - else - line_height->setZero(); + std::cerr << "Layout::Calculator::_findChunksForLine: Font not found." << std::endl; } + TRACE((" initial line_box_height (em size): %f\n", line_box_height->emSize() )); + + // Save strut height for use when recalculating line height after backing out chunks that don't fit. + FontMetrics strut_height = *line_box_height; UnbrokenSpanPosition span_pos; for( ; ; ) { std::vector<ScanlineMaker::ScanRun> scan_runs; - scan_runs = _scanline_maker->makeScanline(*line_height); // Only one line with "InfiniteScanlineMaker + scan_runs = _scanline_maker->makeScanline(*line_box_height); // Only one line with "InfiniteScanlineMaker while (scan_runs.empty()) { // Only used by ShapeScanlineMaker if (!_goToNextWrapShape()) return false; // no more shapes to wrap in to - scan_runs = _scanline_maker->makeScanline(*line_height); + scan_runs = _scanline_maker->makeScanline(*line_box_height); } - TRACE(("finding line fit y=%f, %lu scan runs\n", scan_runs.front().y, scan_runs.size())); + TRACE((" finding line fit y=%f, %lu scan runs\n", scan_runs.front().y, scan_runs.size())); chunk_info->clear(); chunk_info->reserve(scan_runs.size()); if (para.direction == RIGHT_TO_LEFT) std::reverse(scan_runs.begin(), scan_runs.end()); unsigned scan_run_index; span_pos = *start_span_pos; for (scan_run_index = 0 ; scan_run_index < scan_runs.size() ; scan_run_index++) { - if (!_buildChunksInScanRun(para, span_pos, scan_runs[scan_run_index], chunk_info, line_height)) + if (!_buildChunksInScanRun(para, span_pos, scan_runs[scan_run_index], chunk_info, line_box_height, &strut_height)) break; if (!chunk_info->empty() && !chunk_info->back().broken_spans.empty()) span_pos = chunk_info->back().broken_spans.back().end; @@ -1437,6 +1502,8 @@ bool Layout::Calculator::_findChunksForLine(ParagraphInfo const ¶, if (scan_run_index == scan_runs.size()) break; // ie when buildChunksInScanRun() succeeded } *start_span_pos = span_pos; + TRACE((" final line_box_height: %f\n", line_box_height->emSize() )); + TRACE((" end _findChunksForLine: chunks: %lu\n", chunk_info->size())); return true; } @@ -1458,8 +1525,11 @@ bool Layout::Calculator::_buildChunksInScanRun(ParagraphInfo const ¶, UnbrokenSpanPosition const &start_span_pos, ScanlineMaker::ScanRun const &scan_run, std::vector<ChunkInfo> *chunk_info, - LineHeight *line_height) const + FontMetrics *line_height, + FontMetrics const *strut_height) const { + TRACE((" begin _buildChunksInScanRun: chunks: %lu, em size: %f\n", chunk_info->size(), line_height->emSize() )); + ChunkInfo new_chunk; new_chunk.text_width = 0.0; new_chunk.whitespace_count = 0; @@ -1473,7 +1543,7 @@ bool Layout::Calculator::_buildChunksInScanRun(ParagraphInfo const ¶, last_span_at_emergency_break.start = start_span_pos; last_span_at_emergency_break.setZero(); - TRACE(("trying chunk from %f to %g\n", scan_run.x_start, scan_run.x_end)); + TRACE((" trying chunk from %f to %g\n", scan_run.x_start, scan_run.x_end)); BrokenSpan new_span; new_span.end = start_span_pos; while (new_span.end.iter_span != para.unbroken_spans.end()) { // this loops once for each UnbrokenSpan @@ -1495,16 +1565,17 @@ bool Layout::Calculator::_buildChunksInScanRun(ParagraphInfo const ¶, } // see if this span is too tall to fit on the current line - LineHeight total_height = new_span.start.iter_span->line_height; - total_height *= new_span.start.iter_span->line_height_multiplier; + FontMetrics new_span_height = new_span.start.iter_span->line_height; + new_span_height.computeEffective( new_span.start.iter_span->line_height_multiplier ); /* floating point 80-bit/64-bit rounding problems require epsilon. See discussion http://inkscape.gristle.org/2005-03-16.txt around 22:00 */ - if ( total_height.ascent > line_height->ascent + FLT_EPSILON - || total_height.descent > line_height->descent + FLT_EPSILON - || total_height.leading > line_height->leading + FLT_EPSILON) { - line_height->max(total_height); - if (!_scanline_maker->canExtendCurrentScanline(*line_height)) + if ( new_span_height.ascent > line_height->ascent + FLT_EPSILON || + new_span_height.descent > line_height->descent + FLT_EPSILON) { + // Take larger of each of the two ascents and two descents per CSS + line_height->max(new_span_height); + if (!_scanline_maker->canExtendCurrentScanline(*line_height)) { return false; + } } bool span_fitted = _measureUnbrokenSpan(para, &new_span, &last_span_at_break, &last_span_at_emergency_break, new_chunk.scanrun_width - new_chunk.text_width); @@ -1521,10 +1592,10 @@ bool Layout::Calculator::_buildChunksInScanRun(ParagraphInfo const ¶, } } - TRACE(("chunk complete, used %f width (%d whitespaces, %lu brokenspans)\n", new_chunk.text_width, new_chunk.whitespace_count, new_chunk.broken_spans.size())); + TRACE((" chunk complete, used %f width (%d whitespaces, %lu brokenspans)\n", new_chunk.text_width, new_chunk.whitespace_count, new_chunk.broken_spans.size())); chunk_info->push_back(new_chunk); - if (scan_run.width() >= 4.0 * line_height->total() && last_span_at_break.end == start_span_pos) { + if (scan_run.width() >= 4.0 * line_height->emSize() && last_span_at_break.end == start_span_pos) { /* **non-SVG spec bit**: See bug #1191102 If the user types a very long line with no spaces, the way the spec is written at the moment means that when the length of the text @@ -1559,12 +1630,25 @@ bool Layout::Calculator::_buildChunksInScanRun(ParagraphInfo const ¶, chunk_info->back().text_width += last_span_at_break.width; chunk_info->back().whitespace_count += last_span_at_break.whitespace_count; } - TRACE(("correction: fitted span %lu width = %f\n", last_span_at_break.start.iter_span - para.unbroken_spans.begin(), last_span_at_break.width)); + TRACE((" correction: fitted span %lu width = %f\n", last_span_at_break.start.iter_span - para.unbroken_spans.begin(), last_span_at_break.width)); + } + } + + // Recalculate line_box_height after backing out chunks + *line_height = *strut_height; + for (std::vector<ChunkInfo>::const_iterator it_chunk = chunk_info->begin() ; it_chunk != chunk_info->end() ; it_chunk++) { + for (std::vector<BrokenSpan>::const_iterator it_span = it_chunk->broken_spans.begin() ; it_span != it_chunk->broken_spans.end() ; it_span++) { + TRACE((" brokenspan line_height: %f\n", it_span->start.iter_span->line_height.emSize() )); + FontMetrics span_height = it_span->start.iter_span->line_height; + span_height.computeEffective( it_span->start.iter_span->line_height_multiplier ); + line_height->max( span_height ); } } + TRACE((" line_box_height: %f\n", line_height->emSize())); if (!chunk_info->empty() && !chunk_info->back().broken_spans.empty() && chunk_info->back().broken_spans.back().ends_with_whitespace) { // for justification we need to discard space occupied by the single whitespace at the end of the chunk + TRACE((" backing out whitespace\n")); chunk_info->back().broken_spans.back().ends_with_whitespace = false; chunk_info->back().broken_spans.back().width -= chunk_info->back().broken_spans.back().each_whitespace_width; chunk_info->back().broken_spans.back().whitespace_count--; @@ -1576,9 +1660,10 @@ bool Layout::Calculator::_buildChunksInScanRun(ParagraphInfo const ¶, // for justification we need to discard line-spacing and word-spacing at end of the chunk chunk_info->back().broken_spans.back().width -= chunk_info->back().broken_spans.back().letter_spacing; chunk_info->back().text_width -= chunk_info->back().broken_spans.back().letter_spacing; - TRACE(("width after subtracting last letter_spacing: %f\n", chunk_info->back().broken_spans.back().width)); + TRACE((" width after subtracting last letter_spacing: %f\n", chunk_info->back().broken_spans.back().width)); } + TRACE((" end _buildChunksInScanRun: chunks: %lu\n", chunk_info->size())); return true; } @@ -1598,19 +1683,32 @@ bool Layout::Calculator::calculate() g_warning("flow text is not of type TEXT_SOURCE. Abort."); return false; } - TRACE(("begin calculateFlow()\n")); + TRACE(("begin calculate()\n")); _flow._clearOutputObjects(); _pango_context = (font_factory::Default())->fontContext; + _font_factory_size_multiplier = (font_factory::Default())->fontSize; + // Reset gravity hint in case it was changed via previous use of 'text-orientation' + // (scripts take their natural gravity given base gravity). + pango_context_set_gravity_hint(_pango_context, PANGO_GRAVITY_HINT_NATURAL); + _block_progression = _flow._blockProgression(); + if( _block_progression == RIGHT_TO_LEFT || _block_progression == LEFT_TO_RIGHT ) { + // Vertical text, CJK + pango_context_set_base_gravity(_pango_context, PANGO_GRAVITY_EAST); + } else { + // Horizontal text + pango_context_set_base_gravity(_pango_context, PANGO_GRAVITY_AUTO); + } + _y_offset = 0.0; _createFirstScanlineMaker(); ParagraphInfo para; - LineHeight line_height; // needs to be maintained across paragraphs to be able to deal with blank paras + FontMetrics line_box_height; // needs to be maintained across paragraphs to be able to deal with blank paras for(para.first_input_index = 0 ; para.first_input_index < _flow._input_stream.size() ; ) { // jump to the next wrap shape if this is a SHAPE_BREAK control code if (_flow._input_stream[para.first_input_index]->Type() == CONTROL_CODE) { @@ -1624,7 +1722,10 @@ bool Layout::Calculator::calculate() if (_scanline_maker == NULL) break; // we're trying to flow past the last wrap shape - _buildPangoItemizationForPara(¶); + // Break things up into little pango units with unique direction, gravity, etc. + _buildPangoItemizationForPara(¶); + + // Do shaping (convert characters to glyphs) unsigned para_end_input_index = _buildSpansForPara(¶); if (_flow._input_stream[para.first_input_index]->Type() == TEXT_SOURCE) @@ -1647,11 +1748,13 @@ bool Layout::Calculator::calculate() do { // for each line in the paragraph TRACE(("begin line\n")); std::vector<ChunkInfo> line_chunk_info; - if (!_findChunksForLine(para, &span_pos, &line_chunk_info, &line_height)) + if (!_findChunksForLine(para, &span_pos, &line_chunk_info, &line_box_height)) break; // out of shapes to wrap in to - _outputLine(para, line_height, line_chunk_info); + _outputLine(para, line_box_height, line_chunk_info); + _scanline_maker->setLineHeight( line_box_height ); _scanline_maker->completeLine(); // Increments y by line height + TRACE(("end line\n")); } while (span_pos.iter_span != para.unbroken_spans.end()); TRACE(("para %lu end\n\n", _flow._paragraphs.size() - 1)); @@ -1663,8 +1766,8 @@ bool Layout::Calculator::calculate() Layout::Span new_span; if (_flow._spans.empty()) { new_span.font = NULL; - new_span.font_size = line_height.ascent + line_height.descent; - new_span.line_height = line_height; + new_span.font_size = line_box_height.emSize(); + new_span.line_height = line_box_height; new_span.x_end = 0.0; } else { new_span = _flow._spans.back(); @@ -1739,19 +1842,16 @@ void Layout::_calculateCursorShapeForEmpty() InputStreamTextSource const *text_source = static_cast<InputStreamTextSource const *>(_input_stream.front()); font_instance *font = text_source->styleGetFontInstance(); - double font_size = text_source->styleComputeFontSize(); + double font_size = text_source->style->font_size.computed; double caret_slope_run = 0.0, caret_slope_rise = 1.0; - LineHeight line_height; + FontMetrics line_height; if (font) { const_cast<font_instance*>(font)->FontSlope(caret_slope_run, caret_slope_rise); - font->FontMetrics(line_height.ascent, line_height.descent, line_height.leading); + font->FontMetrics(line_height.ascent, line_height.descent, line_height.xheight); line_height *= font_size; font->Unref(); - } else { - line_height.ascent = font_size * 0.85; // random guesses - line_height.descent = font_size * 0.15; - line_height.leading = 0.0; } + double caret_slope = atan2(caret_slope_run, caret_slope_rise); _empty_cursor_shape.height = font_size / cos(caret_slope); _empty_cursor_shape.rotation = caret_slope; @@ -1764,16 +1864,20 @@ void Layout::_calculateCursorShapeForEmpty() ShapeScanlineMaker scanline_maker(_input_wrap_shapes.front().shape, block_progression); std::vector<ScanlineMaker::ScanRun> scan_runs = scanline_maker.makeScanline(line_height); if (!scan_runs.empty()) { - if (block_progression == LEFT_TO_RIGHT || block_progression == RIGHT_TO_LEFT) + if (block_progression == LEFT_TO_RIGHT || block_progression == RIGHT_TO_LEFT) { + // Vertical text _empty_cursor_shape.position = Geom::Point(scan_runs.front().y + font_size, scan_runs.front().x_start); - else + } else { + // Horizontal text _empty_cursor_shape.position = Geom::Point(scan_runs.front().x_start, scan_runs.front().y + font_size); + } } } } bool Layout::calculateFlow() { + TRACE(("begin calculateFlow()\n")); Layout::Calculator calc = Calculator(this); bool result = calc.calculate(); if (textLengthIncrement != 0) { diff --git a/src/libnrtype/Layout-TNG-Input.cpp b/src/libnrtype/Layout-TNG-Input.cpp index 84f3f260e..6f5d4e5f8 100644 --- a/src/libnrtype/Layout-TNG-Input.cpp +++ b/src/libnrtype/Layout-TNG-Input.cpp @@ -126,89 +126,43 @@ int Layout::_enum_converter(int input, EnumConversionItem const *conversion_tabl return conversion_table[0].output; } -// ***** the style format interface -// this doesn't include all accesses to SPStyle, only the ones that are non-trivial - -static const float medium_font_size = 12.0; // more of a default if all else fails than anything else -float Layout::InputStreamTextSource::styleComputeFontSize() const +Layout::Direction Layout::InputStreamTextSource::styleGetBlockProgression() const { - return style->font_size.computed; - - // in case the computed value's not good enough, here's some manual code held in reserve: - SPStyle const *this_style = style; - float inherit_multiplier = 1.0; + switch( style->writing_mode.computed ) { - for ( ; ; ) { - if (this_style->font_size.set && !this_style->font_size.inherit) { - switch (this_style->font_size.type) { - case SP_FONT_SIZE_LITERAL: { - switch(this_style->font_size.literal) { // these multipliers are straight out of the CSS spec - case SP_CSS_FONT_SIZE_XX_SMALL: return medium_font_size * inherit_multiplier * (3.0/5.0); - case SP_CSS_FONT_SIZE_X_SMALL: return medium_font_size * inherit_multiplier * (3.0/4.0); - case SP_CSS_FONT_SIZE_SMALL: return medium_font_size * inherit_multiplier * (8.0/9.0); - default: - case SP_CSS_FONT_SIZE_MEDIUM: return medium_font_size * inherit_multiplier; - case SP_CSS_FONT_SIZE_LARGE: return medium_font_size * inherit_multiplier * (6.0/5.0); - case SP_CSS_FONT_SIZE_X_LARGE: return medium_font_size * inherit_multiplier * (3.0/2.0); - case SP_CSS_FONT_SIZE_XX_LARGE: return medium_font_size * inherit_multiplier * 2.0; - case SP_CSS_FONT_SIZE_SMALLER: inherit_multiplier *= 0.84; break; //not exactly according to spec - case SP_CSS_FONT_SIZE_LARGER: inherit_multiplier *= 1.26; break; //not exactly according to spec - } - break; - } - case SP_FONT_SIZE_PERCENTAGE: { // 'em' units should be in here, but aren't. Fix in style.cpp. - inherit_multiplier *= this_style->font_size.value; - break; - } - case SP_FONT_SIZE_LENGTH: { - return this_style->font_size.value * inherit_multiplier; - } - } - } - if (this_style->object == NULL || this_style->object->parent == NULL) break; - this_style = this_style->object->parent->style; - if (this_style == NULL) break; - } - return medium_font_size * inherit_multiplier; -} + case SP_CSS_WRITING_MODE_LR_TB: + case SP_CSS_WRITING_MODE_RL_TB: + return TOP_TO_BOTTOM; + + case SP_CSS_WRITING_MODE_TB_RL: + return RIGHT_TO_LEFT; -static const Layout::EnumConversionItem enum_convert_spstyle_block_progression_to_direction[] = { - {SP_CSS_BLOCK_PROGRESSION_TB, Layout::TOP_TO_BOTTOM}, - {SP_CSS_BLOCK_PROGRESSION_LR, Layout::LEFT_TO_RIGHT}, - {SP_CSS_BLOCK_PROGRESSION_RL, Layout::RIGHT_TO_LEFT}}; + case SP_CSS_WRITING_MODE_TB_LR: + return LEFT_TO_RIGHT; -static const Layout::EnumConversionItem enum_convert_spstyle_writing_mode_to_direction[] = { - {SP_CSS_WRITING_MODE_LR_TB, Layout::TOP_TO_BOTTOM}, - {SP_CSS_WRITING_MODE_RL_TB, Layout::TOP_TO_BOTTOM}, - {SP_CSS_WRITING_MODE_TB_RL, Layout::RIGHT_TO_LEFT}, - {SP_CSS_WRITING_MODE_TB_LR, Layout::LEFT_TO_RIGHT}}; + default: + std::cerr << "Layout::InputTextStream::styleGetBlockProgression: invalid writing mode." << std::endl; + } + return TOP_TO_BOTTOM; +} -Layout::Direction Layout::InputStreamTextSource::styleGetBlockProgression() const +SPCSSTextOrientation Layout::InputStreamTextSource::styleGetTextOrientation() const { - // this function shouldn't be necessary, but since style.cpp doesn't support - // shorthand properties yet, it is. - SPStyle const *this_style = style; - - for ( ; ; ) { - if (this_style->block_progression.set) - return (Layout::Direction)_enum_converter(this_style->block_progression.computed, enum_convert_spstyle_block_progression_to_direction, sizeof(enum_convert_spstyle_block_progression_to_direction)/sizeof(enum_convert_spstyle_block_progression_to_direction[0])); - if (this_style->writing_mode.set) - return (Layout::Direction)_enum_converter(this_style->writing_mode.computed, enum_convert_spstyle_writing_mode_to_direction, sizeof(enum_convert_spstyle_writing_mode_to_direction)/sizeof(enum_convert_spstyle_writing_mode_to_direction[0])); - if (this_style->object == NULL || this_style->object->parent == NULL) break; - this_style = this_style->object->parent->style; - if (this_style == NULL) break; - } - return TOP_TO_BOTTOM; + return ((SPCSSTextOrientation)style->text_orientation.computed); +} +SPCSSBaseline Layout::InputStreamTextSource::styleGetDominantBaseline() const +{ + return ((SPCSSBaseline)style->dominant_baseline.computed); } -static Layout::Alignment text_anchor_to_alignment(unsigned anchor, Layout::Direction /*para_direction*/) +static Layout::Alignment text_anchor_to_alignment(unsigned anchor, Layout::Direction para_direction) { switch (anchor) { default: - case SP_CSS_TEXT_ANCHOR_START: return Layout::LEFT; + case SP_CSS_TEXT_ANCHOR_START: return para_direction == Layout::LEFT_TO_RIGHT ? Layout::LEFT : Layout::RIGHT; case SP_CSS_TEXT_ANCHOR_MIDDLE: return Layout::CENTER; - case SP_CSS_TEXT_ANCHOR_END: return Layout::RIGHT; + case SP_CSS_TEXT_ANCHOR_END: return para_direction == Layout::LEFT_TO_RIGHT ? Layout::RIGHT : Layout::LEFT; } } diff --git a/src/libnrtype/Layout-TNG-OutIter.cpp b/src/libnrtype/Layout-TNG-OutIter.cpp index 707897f50..8c29b7dbc 100644 --- a/src/libnrtype/Layout-TNG-OutIter.cpp +++ b/src/libnrtype/Layout-TNG-OutIter.cpp @@ -120,7 +120,8 @@ Layout::iterator Layout::getNearestCursorPositionTo(double x, double y) const double best_y_range = DBL_MAX; double best_x_range = DBL_MAX; for (chunk_index = 0 ; chunk_index < _chunks.size() ; chunk_index++) { - LineHeight line_height = {0.0, 0.0, 0.0}; + FontMetrics line_height; + line_height *= 0.0; // Set all metrics to zero. double chunk_width = 0.0; for ( ; span_index < _spans.size() && _spans[span_index].in_chunk == chunk_index ; span_index++) { line_height.max(_spans[span_index].line_height); @@ -340,8 +341,8 @@ Geom::Rect Layout::characterBoundingBox(iterator const &it, double *rotation) co double baseline_y = _characters[char_index].line(this).baseline_y + _characters[char_index].span(this).baseline_shift; if (_directions_are_orthogonal(_blockProgression(), TOP_TO_BOTTOM)) { - double span_height = _spans[_characters[char_index].in_span].line_height.ascent + _spans[_characters[char_index].in_span].line_height.descent; - top_left[Geom::Y] = top_left[Geom::X]; + double span_height = _spans[_characters[char_index].in_span].line_height.emSize(); + top_left[Geom::Y] = top_left[Geom::X]; top_left[Geom::X] = baseline_y - span_height * 0.5; bottom_right[Geom::Y] = bottom_right[Geom::X]; bottom_right[Geom::X] = baseline_y + span_height * 0.5; @@ -404,7 +405,7 @@ std::vector<Geom::Point> Layout::createSelectionShape(iterator const &it_start, double vertical_scale = _glyphs.back().vertical_scale; if (_directions_are_orthogonal(_blockProgression(), TOP_TO_BOTTOM)) { - double span_height = vertical_scale * (_spans[span_index].line_height.ascent + _spans[span_index].line_height.descent); + double span_height = vertical_scale * _spans[span_index].line_height.emSize(); top_left[Geom::Y] = top_left[Geom::X]; top_left[Geom::X] = baseline_y - span_height * 0.5; bottom_right[Geom::Y] = bottom_right[Geom::X]; @@ -507,20 +508,22 @@ void Layout::queryCursorShape(iterator const &it, Geom::Point &position, double position[Geom::Y] = span->line(this).baseline_y + span->baseline_shift; } // up to now *position is the baseline point, not the final point which will be the bottom of the descent - double vertical_scale = _glyphs.back().vertical_scale; + double vertical_scale = _glyphs.empty() ? 1.0 : _glyphs.back().vertical_scale; if (_directions_are_orthogonal(_blockProgression(), TOP_TO_BOTTOM)) { - height = vertical_scale * span->line_height.ascent + span->line_height.descent; + // Vertical text + height = vertical_scale * span->line_height.emSize(); rotation += M_PI / 2; std::swap(position[Geom::X], position[Geom::Y]); position[Geom::X] -= vertical_scale * sin(rotation) * height * 0.5; position[Geom::Y] += vertical_scale * cos(rotation) * height * 0.5; } else { + // Horizontal text double caret_slope_run = 0.0, caret_slope_rise = 1.0; if (span->font) const_cast<font_instance*>(span->font)->FontSlope(caret_slope_run, caret_slope_rise); double caret_slope = atan2(caret_slope_run, caret_slope_rise); - height = vertical_scale * (span->line_height.ascent + span->line_height.descent) / cos(caret_slope); + height = vertical_scale * (span->line_height.emSize()) / cos(caret_slope); rotation += caret_slope; position[Geom::X] -= sin(rotation) * vertical_scale * span->line_height.descent; position[Geom::Y] += cos(rotation) * vertical_scale * span->line_height.descent; diff --git a/src/libnrtype/Layout-TNG-Output.cpp b/src/libnrtype/Layout-TNG-Output.cpp index 6e3faf33b..526319f35 100644 --- a/src/libnrtype/Layout-TNG-Output.cpp +++ b/src/libnrtype/Layout-TNG-Output.cpp @@ -93,26 +93,55 @@ void Layout::_clearOutputObjects() _path_fitted = NULL; } -void Layout::LineHeight::max(LineHeight const &other) +void Layout::FontMetrics::set(font_instance *font) { - if (other.ascent > ascent) ascent = other.ascent; - if (other.descent > descent) descent = other.descent; - if (other.leading > leading) leading = other.leading; + if( font != NULL ) { + ascent = font->GetTypoAscent(); + descent = font->GetTypoDescent(); + xheight = font->GetXHeight(); + ascent_max = font->GetMaxAscent(); + descent_max = font->GetMaxDescent(); + } +} + +void Layout::FontMetrics::max(FontMetrics const &other) +{ + if (other.ascent > ascent ) ascent = other.ascent; + if (other.descent > descent ) descent = other.descent; + if( other.xheight > xheight ) xheight = other.xheight; + if( other.ascent_max > ascent_max ) ascent_max = other.ascent_max; + if( other.descent_max > descent_max ) descent_max = other.descent_max; +} + +void Layout::FontMetrics::computeEffective( const double &line_height_multiplier ) { + double half_leading = 0.5 * (line_height_multiplier - 1.0) * emSize(); + ascent += half_leading; + descent += half_leading; } void Layout::_getGlyphTransformMatrix(int glyph_index, Geom::Affine *matrix) const { Span const &span = _glyphs[glyph_index].span(this); - double sin_rotation = sin(_glyphs[glyph_index].rotation); - double cos_rotation = cos(_glyphs[glyph_index].rotation); + double rotation = _glyphs[glyph_index].rotation; + if ( (span.block_progression == LEFT_TO_RIGHT || span.block_progression == RIGHT_TO_LEFT) && + _glyphs[glyph_index].orientation == ORIENTATION_SIDEWAYS ) { + // Vertical sideways text + rotation += M_PI/2.0; + } + double sin_rotation = sin(rotation); + double cos_rotation = cos(rotation); (*matrix)[0] = span.font_size * cos_rotation; (*matrix)[1] = span.font_size * sin_rotation; (*matrix)[2] = span.font_size * sin_rotation; (*matrix)[3] = -span.font_size * cos_rotation * (_glyphs[glyph_index].vertical_scale); // unscale vertically so the specified text height is preserved if lengthAdjust=spacingAndGlyphs if (span.block_progression == LEFT_TO_RIGHT || span.block_progression == RIGHT_TO_LEFT) { + // Vertical text + // This effectively swaps x for y which changes handedness of coordinate system. This is a bit strange + // and not what one would expect but the compute code already reverses y so OK. (*matrix)[4] = _lines[_chunks[span.in_chunk].in_line].baseline_y + _glyphs[glyph_index].y; (*matrix)[5] = _chunks[span.in_chunk].left_x + _glyphs[glyph_index].x; } else { + // Horizontal text (*matrix)[4] = _chunks[span.in_chunk].left_x + _glyphs[glyph_index].x; (*matrix)[5] = _lines[_chunks[span.in_chunk].in_line].baseline_y + _glyphs[glyph_index].y; } @@ -127,9 +156,9 @@ void Layout::show(DrawingGroup *in_arena, Geom::OptRect const &paintbox) const InputStreamTextSource const *text_source = static_cast<InputStreamTextSource const *>(_input_stream[_spans[span_index].in_input_stream_item]); text_source->style->text_decoration_data.tspan_width = _spans[span_index].width(); - text_source->style->text_decoration_data.ascender = _spans[span_index].line_height.getAscent(); - text_source->style->text_decoration_data.descender = _spans[span_index].line_height.getDescent(); - text_source->style->text_decoration_data.line_gap = _spans[span_index].line_height.getLeading(); + text_source->style->text_decoration_data.ascender = _spans[span_index].line_height.getTypoAscent(); + text_source->style->text_decoration_data.descender = _spans[span_index].line_height.getTypoDescent(); + if(!span_index || (_chunks[_spans[span_index].in_chunk].in_line != _chunks[_spans[span_index-1].in_chunk].in_line)){ text_source->style->text_decoration_data.tspan_line_start = true; @@ -170,11 +199,14 @@ void Layout::show(DrawingGroup *in_arena, Geom::OptRect const &paintbox) const first_line_glyph = false; phase0 = glyph_matrix.translation()[Geom::X]; } - // save the starting coordinates for the line - these are needed for figuring out dot/dash/wave phase + // Save the starting coordinates for the line - these are needed for figuring out + // dot/dash/wave phase. + // Use maximum ascent and descent to ensure glpyhs that extend outside the embox + // are fully drawn. (void) nr_text->addComponent(_spans[span_index].font, _glyphs[glyph_index].glyph, glyph_matrix, _glyphs[glyph_index].width, - _spans[span_index].line_height.getAscent(), - _spans[span_index].line_height.getDescent(), + _spans[span_index].line_height.getMaxAscent(), + _spans[span_index].line_height.getMaxDescent(), glyph_matrix.translation()[Geom::X] - phase0 ); } @@ -580,7 +612,7 @@ Glib::ustring Layout::dumpAsText() const result += Glib::ustring::compose(" font '%1' %2 %3 %4\n", sp_font_description_get_family(_spans[span_index].font->descr), _spans[span_index].font_size, style_to_text(pango_font_description_get_style(_spans[span_index].font->descr)), weight_to_text(pango_font_description_get_weight(_spans[span_index].font->descr))); } result += Glib::ustring::compose(" x_start = %1, x_end = %2\n", _spans[span_index].x_start, _spans[span_index].x_end) - + Glib::ustring::compose(" line height: ascent %1, descent %2 leading %3\n", _spans[span_index].line_height.ascent, _spans[span_index].line_height.descent, _spans[span_index].line_height.leading) + + Glib::ustring::compose(" line height: ascent %1, descent %2\n", _spans[span_index].line_height.ascent, _spans[span_index].line_height.descent) + Glib::ustring::compose(" direction %1, block-progression %2\n", direction_to_text(_spans[span_index].direction), direction_to_text(_spans[span_index].block_progression)) + " ** characters:\n"; Glib::ustring::const_iterator iter_char = _spans[span_index].input_stream_first_character; diff --git a/src/libnrtype/Layout-TNG-Scanline-Maker.h b/src/libnrtype/Layout-TNG-Scanline-Maker.h index d513d7cc1..7c90ea8cc 100644 --- a/src/libnrtype/Layout-TNG-Scanline-Maker.h +++ b/src/libnrtype/Layout-TNG-Scanline-Maker.h @@ -47,7 +47,7 @@ public: between calls if the new height too big to fit in the space remaining in this shape. Returns an empty vector if there is no space left in the current shape. */ - virtual std::vector<ScanRun> makeScanline(Layout::LineHeight const &line_height) =0; + virtual std::vector<ScanRun> makeScanline(Layout::FontMetrics const &line_height) =0; /** Indicates that the caller has successfully filled the current line and hence that the next call to makeScanline() should return lines on @@ -71,7 +71,12 @@ public: The metrics given here are considered to be the ones that are being used now, and hence is the line advance height used by completeLine(). */ - virtual bool canExtendCurrentScanline(Layout::LineHeight const &line_height) =0; + virtual bool canExtendCurrentScanline(Layout::FontMetrics const &line_height) =0; + + /** Sets current line block height. Call before completeLine() to correct for + actually used line height (in case some chunks with larger font-size rolled back). + */ + virtual void setLineHeight(Layout::FontMetrics const &line_height) =0; }; /** \brief private to Layout. Generates infinite scanlines for when you don't want wrapping @@ -90,7 +95,7 @@ public: virtual ~InfiniteScanlineMaker(); /** Returns a single infinite run at the current location */ - virtual std::vector<ScanRun> makeScanline(Layout::LineHeight const &line_height); + virtual std::vector<ScanRun> makeScanline(Layout::FontMetrics const &line_height); /** Increments the current y by the current line height */ virtual void completeLine(); @@ -102,11 +107,16 @@ public: virtual void setNewYCoordinate(double new_y); /** Always true, but has to save the new height */ - virtual bool canExtendCurrentScanline(Layout::LineHeight const &line_height); + virtual bool canExtendCurrentScanline(Layout::FontMetrics const &line_height); + + /** Sets current line block height. Call before completeLine() to correct for + actually used line height (in case some chunks with larger font-size rolled back). + */ + virtual void setLineHeight(Layout::FontMetrics const &line_height); private: double _x, _y; - Layout::LineHeight _current_line_height; + Layout::FontMetrics _current_line_height; bool _negative_block_progression; /// if true, indicates that completeLine() should decrement rather than increment, ie block-progression is either rl or bt }; @@ -122,7 +132,7 @@ public: ShapeScanlineMaker(Shape const *shape, Layout::Direction block_progression); virtual ~ShapeScanlineMaker(); - virtual std::vector<ScanRun> makeScanline(Layout::LineHeight const &line_height); + virtual std::vector<ScanRun> makeScanline(Layout::FontMetrics const &line_height); virtual void completeLine(); @@ -131,7 +141,13 @@ public: virtual void setNewYCoordinate(double new_y); /** never true */ - virtual bool canExtendCurrentScanline(Layout::LineHeight const &line_height); + virtual bool canExtendCurrentScanline(Layout::FontMetrics const &line_height); + + /** Sets current line block height. Call before completeLine() to correct for + actually used line height (in case some chunks with larger font-size rolled back). + */ + virtual void setLineHeight(Layout::FontMetrics const &line_height); + private: /** To generate scanlines for top-to-bottom text it is easiest if we simply rotate the given shape by a multiple of 90 degrees. This stores diff --git a/src/libnrtype/Layout-TNG-Scanline-Makers.cpp b/src/libnrtype/Layout-TNG-Scanline-Makers.cpp index 7144f3876..dcc973a24 100644 --- a/src/libnrtype/Layout-TNG-Scanline-Makers.cpp +++ b/src/libnrtype/Layout-TNG-Scanline-Makers.cpp @@ -19,9 +19,7 @@ namespace Text { Layout::InfiniteScanlineMaker::InfiniteScanlineMaker(double initial_x, double initial_y, Layout::Direction block_progression) { - _current_line_height.ascent = 0.0; - _current_line_height.descent = 0.0; - _current_line_height.leading = 0.0; + _current_line_height.setZero(); switch (block_progression) { case LEFT_TO_RIGHT: case RIGHT_TO_LEFT: @@ -41,7 +39,7 @@ Layout::InfiniteScanlineMaker::~InfiniteScanlineMaker() { } -std::vector<Layout::ScanlineMaker::ScanRun> Layout::InfiniteScanlineMaker::makeScanline(Layout::LineHeight const &line_height) +std::vector<Layout::ScanlineMaker::ScanRun> Layout::InfiniteScanlineMaker::makeScanline(Layout::FontMetrics const &line_height) { std::vector<ScanRun> runs(1); runs[0].x_start = _x; @@ -54,12 +52,10 @@ std::vector<Layout::ScanlineMaker::ScanRun> Layout::InfiniteScanlineMaker::makeS void Layout::InfiniteScanlineMaker::completeLine() { if (_negative_block_progression) - _y -= _current_line_height.total(); + _y -= _current_line_height.emSize(); else - _y += _current_line_height.total(); - _current_line_height.ascent = 0.0; - _current_line_height.descent = 0.0; - _current_line_height.leading = 0.0; + _y += _current_line_height.emSize(); + _current_line_height.setZero(); } void Layout::InfiniteScanlineMaker::setNewYCoordinate(double new_y) @@ -67,12 +63,17 @@ void Layout::InfiniteScanlineMaker::setNewYCoordinate(double new_y) _y = new_y; } -bool Layout::InfiniteScanlineMaker::canExtendCurrentScanline(Layout::LineHeight const &line_height) +bool Layout::InfiniteScanlineMaker::canExtendCurrentScanline(Layout::FontMetrics const &line_height) { _current_line_height = line_height; return true; } +void Layout::InfiniteScanlineMaker::setLineHeight(Layout::FontMetrics const &line_height) +{ + _current_line_height = line_height; +} + // *********************** real shapes version Layout::ShapeScanlineMaker::ShapeScanlineMaker(Shape const *shape, Layout::Direction block_progression) @@ -111,29 +112,29 @@ Layout::ShapeScanlineMaker::~ShapeScanlineMaker() delete _rotated_shape; } -std::vector<Layout::ScanlineMaker::ScanRun> Layout::ShapeScanlineMaker::makeScanline(Layout::LineHeight const &line_height) +std::vector<Layout::ScanlineMaker::ScanRun> Layout::ShapeScanlineMaker::makeScanline(Layout::FontMetrics const &line_height) { - FloatLigne line_rasterization; - FloatLigne line_decent_length_runs; - float line_text_height = (float)(line_height.ascent + line_height.descent); - if (_y > _bounding_box_bottom) return std::vector<ScanRun>(); if (_y < _bounding_box_top) _y = _bounding_box_top; + FloatLigne line_rasterization; + FloatLigne line_decent_length_runs; + float line_text_height = (float)(line_height.emSize()); if (line_text_height == 0.0) line_text_height = 0.001; // Scan() doesn't work for zero height so this will have to do - _current_line_height = (float)line_height.total(); + _current_line_height = (float)line_height.emSize(); // I think what's going on here is that we're moving the top of the scanline to the given position... _rotated_shape->Scan(_rasterizer_y, _current_rasterization_point, _y, line_text_height); // ...then actually retreiving the scanline (which alters the first two parameters) _rotated_shape->Scan(_rasterizer_y, _current_rasterization_point, _y + line_text_height , &line_rasterization, true, line_text_height); - // sanitise the raw rasterisation, which could have weird overlaps + // sanitise the raw rasterisation, which could have weird overlaps line_rasterization.Flatten(); + // line_rasterization.Affiche(); // cut out runs that cover less than 90% of the line line_decent_length_runs.Over(&line_rasterization, 0.9 * line_text_height); @@ -145,7 +146,7 @@ std::vector<Layout::ScanlineMaker::ScanRun> Layout::ShapeScanlineMaker::makeScan std::vector<ScanRun> result(1); result[0].x_start = line_rasterization.runs[0].st; result[0].x_end = line_rasterization.runs[0].st; - result[0].y = _negative_block_progression ? -_current_line_height - _y : _y; + result[0].y = _negative_block_progression ? - _y : _y; return result; } @@ -154,7 +155,7 @@ std::vector<Layout::ScanlineMaker::ScanRun> Layout::ShapeScanlineMaker::makeScan for (unsigned i = 0 ; i < result.size() ; i++) { result[i].x_start = line_decent_length_runs.runs[i].st; result[i].x_end = line_decent_length_runs.runs[i].en; - result[i].y = _negative_block_progression ? -_current_line_height - _y : _y; + result[i].y = _negative_block_progression ? - _y : _y; } return result; @@ -167,23 +168,28 @@ void Layout::ShapeScanlineMaker::completeLine() double Layout::ShapeScanlineMaker::yCoordinate() { - if (_negative_block_progression) return -_current_line_height - _y; + if (_negative_block_progression) return - _y; return _y; } void Layout::ShapeScanlineMaker::setNewYCoordinate(double new_y) { _y = (float)new_y; - if (_negative_block_progression) _y = -_current_line_height - _y; + if (_negative_block_progression) _y = - _y; // what will happen with the rasteriser if we move off the shape? // it's not an important question because <flowSpan> doesn't have a y attribute } -bool Layout::ShapeScanlineMaker::canExtendCurrentScanline(Layout::LineHeight const &/*line_height*/) +bool Layout::ShapeScanlineMaker::canExtendCurrentScanline(Layout::FontMetrics const &/*line_height*/) { //we actually could return true if only the leading changed, but that's too much effort for something that rarely happens return false; } +void Layout::ShapeScanlineMaker::setLineHeight(Layout::FontMetrics const &line_height) +{ + _current_line_height = line_height.emSize(); +} + }//namespace Text }//namespace Inkscape diff --git a/src/libnrtype/Layout-TNG.h b/src/libnrtype/Layout-TNG.h index 26db1fad9..97a05bde8 100644 --- a/src/libnrtype/Layout-TNG.h +++ b/src/libnrtype/Layout-TNG.h @@ -22,6 +22,7 @@ #include <vector> #include <boost/optional.hpp> #include <svg/svg-length.h> +#include "style-enums.h" #ifdef HAVE_CAIRO_PDF namespace Inkscape { @@ -157,6 +158,9 @@ public: both the 'direction' and 'block-progression' CSS attributes. */ enum Direction {LEFT_TO_RIGHT, RIGHT_TO_LEFT, TOP_TO_BOTTOM, BOTTOM_TO_TOP}; + /** Used to specify orientation of glyphs in vertical text. */ + enum Orientation {ORIENTATION_UPRIGHT, ORIENTATION_SIDEWAYS}; + /** Display alignment for shapes. See appendWrapShape(). */ enum DisplayAlign {DISPLAY_ALIGN_BEFORE, DISPLAY_ALIGN_CENTER, DISPLAY_ALIGN_AFTER}; @@ -603,19 +607,69 @@ public: //@} - /// it's useful for this to be public so that ScanlineMaker can use it - struct LineHeight { - double ascent; - double descent; - double leading; - inline double total() const {return ascent + descent + leading;} - inline void setZero() {ascent = descent = leading = 0.0;} - inline LineHeight& operator*=(double x) {ascent *= x; descent *= x; leading *= x; return *this;} - void max(LineHeight const &other); /// makes this object contain the largest of all three members between this object and other - inline double getAscent() const {return ascent; } - inline double getDescent() const {return descent; } - inline double getLeading() const {return leading; } - }; + + /** + * Keep track of font metrics. Two use cases: + * 1. Keep track of ascent, descent, and x-height of an individual font. + * 2. Keep track of effective ascent and descent that includes half-leading. + * + * Note: Leading refers to the "external" leading which is added (subtracted) due to + * a computed value of 'line-height' that differs from 'font-size'. "Internal" leading + * which is specified inside a font is not used in CSS. The 'font-size' is based on + * the font's em size which is 'ascent' + 'descent'. + * + * This structure was renamed (and modified) from "LineHeight". + * + * It's useful for this to be public so that ScanlineMaker can use it. + */ + class FontMetrics { + + public: + FontMetrics() { reset(); } + + void reset() { + ascent = 0.8; + descent = -0.2; + xheight = 0.5; + ascent_max = 0.8; + descent_max = 0.2; + } + + void set( font_instance *font ); + + // CSS 2.1 dictates that font-size is based on em-size which is defined as ascent + descent + inline double emSize() const {return ascent + descent;} + // Alternatively name function for use 2. + inline double lineSize() const { return ascent + descent; } + inline void setZero() {ascent = descent = xheight = ascent_max = descent_max = 0.0;} + + // For scaling for 'font-size'. + inline FontMetrics& operator*=(double x) { + ascent *= x; descent *= x; xheight *= x; ascent_max *= x; descent_max *= x; + return *this; + } + + /// Save the larger values of ascent and descent between this and other. Needed for laying + /// out a line with mixed font-sizes, fonts, or line spacings. + void max(FontMetrics const &other); + + /// Calculate the effective ascent and descent including half "leading". + void computeEffective( const double &line_height ); + + inline double getTypoAscent() const {return ascent; } + inline double getTypoDescent() const {return descent; } + inline double getXHeight() const {return xheight; } + inline double getMaxAscent() const {return ascent_max; } + inline double getMaxDescent() const {return descent_max; } + + // private: + double ascent; // Typographic ascent. + double descent; // Typographic descent. + double xheight; // Height of 'x' measured from alphabetic baseline. + double ascent_max; // Maximum ascent of all glyphs in font. + double descent_max; // Maximum descent of all glyphs in font. + + }; // End FontMetrics /// see _enum_converter() struct EnumConversionItem { @@ -664,11 +718,12 @@ private: LengthAdjust lengthAdjust; // a few functions for some of the more complicated style accesses - float styleComputeFontSize() const; /// The return value must be freed with pango_font_description_free() PangoFontDescription *styleGetFontDescription() const; font_instance *styleGetFontInstance() const; Direction styleGetBlockProgression() const; + SPCSSTextOrientation styleGetTextOrientation() const; + SPCSSBaseline styleGetDominantBaseline() const; Alignment styleGetAlignment(Direction para_direction, bool try_text_align) const; }; @@ -707,6 +762,22 @@ private: return TOP_TO_BOTTOM; } + /** The overall text-orientation of the whole flow. */ + inline SPCSSTextOrientation _blockTextOrientation() const + { + if(!_input_stream.empty()) + return static_cast<InputStreamTextSource*>(_input_stream.front())->styleGetTextOrientation(); + return SP_CSS_TEXT_ORIENTATION_MIXED; + } + + /** The overall text-orientation of the whole flow. */ + inline SPCSSBaseline _blockBaseline() const + { + if(!_input_stream.empty()) + return static_cast<InputStreamTextSource*>(_input_stream.front())->styleGetDominantBaseline(); + return SP_CSS_BASELINE_AUTO; + } + /** so that LEFT_TO_RIGHT == RIGHT_TO_LEFT but != TOP_TO_BOTTOM */ static bool _directions_are_orthogonal(Direction d1, Direction d2); @@ -748,6 +819,7 @@ private: float x; /// relative to the start of the chunk float y; /// relative to the current line's baseline float rotation; /// absolute, modulo any object transforms, which we don't know about + Orientation orientation; /// Orientation of glyph in vertical text float width; float vertical_scale; /// to implement lengthAdjust="spacingAndGlyphs" that must scale glyphs only horizontally; instead we change font size and then undo that change vertically only inline Span const & span(Layout const *l) const {return l->_spans[l->_characters[in_character].in_span];} @@ -772,8 +844,9 @@ private: float x_start; /// relative to the start of the chunk float x_end; /// relative to the start of the chunk inline float width() const {return std::abs(x_start - x_end);} - LineHeight line_height; + FontMetrics line_height; double baseline_shift; /// relative to the line's baseline + SPCSSTextOrientation text_orientation; Direction direction; /// See CSS3 section 3.2. Either rtl or ltr Direction block_progression; /// See CSS3 section 3.2. The direction in which lines go. unsigned in_input_stream_item; diff --git a/src/libnrtype/TextWrapper.cpp b/src/libnrtype/TextWrapper.cpp index 380e9ba3f..124f3f7b4 100644 --- a/src/libnrtype/TextWrapper.cpp +++ b/src/libnrtype/TextWrapper.cpp @@ -862,7 +862,7 @@ void text_wrapper::MeasureBoxes(void) for (int i = 0; i < nbBox; i++) { boxes[i].ascent = 0; boxes[i].descent = 0; - boxes[i].leading = 0; + boxes[i].xheight = 0; boxes[i].width = 0; PangoFont *curPF = glyph_text[boxes[i].g_st].font; @@ -870,7 +870,7 @@ void text_wrapper::MeasureBoxes(void) PangoFontDescription *pfd = pango_font_describe(curPF); font_instance *curF = f_src->Face(pfd); if ( curF ) { - curF->FontMetrics(boxes[i].ascent, boxes[i].descent, boxes[i].leading); + curF->FontMetrics(boxes[i].ascent, boxes[i].descent, boxes[i].xheight); curF->Unref(); } pango_font_description_free(pfd); diff --git a/src/libnrtype/font-instance.h b/src/libnrtype/font-instance.h index 5a71e353b..2fac7c19b 100644 --- a/src/libnrtype/font-instance.h +++ b/src/libnrtype/font-instance.h @@ -57,19 +57,31 @@ public: // nota: all coordinates returned by these functions are on a [0..1] scale; you need to multiply // by the fontsize to get the real sizes + + // Return 2geom pathvector for glyph. Deallocated when font instance dies. Geom::PathVector* PathVector(int glyph_id); - // returns the 2geom-type pathvector for this glyph. no refcounting needed, it's deallocated when the font_instance dies + + // Horizontal advance if 'vertical' is false, vertical advance if true. double Advance(int glyph_id, bool vertical); - // nominal advance of the font. + + double GetTypoAscent() { return _ascent; } + double GetTypoDescent() { return _descent; } + double GetXHeight() { return _xheight; } + double GetMaxAscent() { return _ascent_max; } + double GetMaxDescent() { return _descent_max; } + const double* GetBaselines() { return _baselines; } + bool FontMetrics(double &ascent, double &descent, double &leading); - bool FontDecoration(double &underline_position, double &underline_thickness, - double &linethrough_position, double &linethrough_thickness); + bool FontDecoration(double &underline_position, double &underline_thickness, + double &linethrough_position, double &linethrough_thickness); bool FontSlope(double &run, double &rise); // for generating slanted cursors for oblique fonts - Geom::OptRect BBox(int glyph_id); + Geom::OptRect BBox(int glyph_id); private: void FreeTheFace(); + // Find ascent, descent, x-height, and baselines. + void FindFontMetrics(); // Temp: make public public: @@ -81,6 +93,17 @@ public: // as long as pFont is valid, theFace is too #endif +private: + + // Font metrics in em-box units + double _ascent; // Typographic ascent. + double _descent; // Typographic descent. + double _xheight; // x-height of font. + double _ascent_max; // Maxiumum ascent of all glyphs in font. + double _descent_max; // Maxiumum descent of all glyphs in font. + + // Baselines + double _baselines[SP_CSS_BASELINE_SIZE]; }; diff --git a/src/libnrtype/font-lister.cpp b/src/libnrtype/font-lister.cpp index 70374864a..568a7c8cc 100644 --- a/src/libnrtype/font-lister.cpp +++ b/src/libnrtype/font-lister.cpp @@ -6,7 +6,6 @@ #include <gtkmm/treemodel.h> #include <libnrtype/font-instance.h> -#include <libnrtype/TextWrapper.h> #include <libnrtype/one-glyph.h> #include "font-lister.h" diff --git a/src/libnrtype/one-box.h b/src/libnrtype/one-box.h index c868cf23f..c3b36a3ce 100644 --- a/src/libnrtype/one-box.h +++ b/src/libnrtype/one-box.h @@ -9,7 +9,7 @@ // this time for sp-typeset struct one_box { int g_st, g_en; ///< First and last glyph of this word. - double ascent, descent, leading; + double ascent, descent, xheight; double width; bool word_start, word_end; }; diff --git a/src/libuemf/uemf.c b/src/libuemf/uemf.c index 3180c757c..afa116e75 100644 --- a/src/libuemf/uemf.c +++ b/src/libuemf/uemf.c @@ -1858,8 +1858,8 @@ U_LOGCOLORSPACEA logcolorspacea_set( lcsa.lcsIntent = lcsIntent; lcsa.lcsEndpoints = lcsEndpoints; lcsa.lcsGammaRGB = lcsGammaRGB; - memset(lcsa.lcsFilename,0,U_MAX_PATH); // zero out the Filename field strncpy(lcsa.lcsFilename,lcsFilename,U_MAX_PATH); + lcsa.lcsFilename[U_MAX_PATH-1] = '\0'; return(lcsa); } @@ -1889,6 +1889,7 @@ U_LOGCOLORSPACEW logcolorspacew_set( lcsa.lcsEndpoints = lcsEndpoints; lcsa.lcsGammaRGB = lcsGammaRGB; wchar16strncpypad(lcsa.lcsFilename,lcsFilename,U_MAX_PATH); + lcsa.lcsFilename[U_MAX_PATH-1] = '\0'; return(lcsa); } @@ -1983,6 +1984,7 @@ U_LOGFONT logfont_set( lf.lfQuality = lfQuality; lf.lfPitchAndFamily = lfPitchAndFamily; wchar16strncpypad(lf.lfFaceName, lfFaceName, U_LF_FACESIZE); // pad this one as the intial structure was not set to zero + lf.lfFaceName[U_LF_FACESIZE-1] = '\0'; return(lf); } @@ -2006,7 +2008,9 @@ U_LOGFONT_PANOSE logfont_panose_set( U_LOGFONT_PANOSE lfp; memset(&lfp,0,sizeof(U_LOGFONT_PANOSE)); // all fields zero unless needed. Many should be ignored or must be 0. wchar16strncpy(lfp.elfFullName, elfFullName, U_LF_FULLFACESIZE); + lfp.elfFullName[U_LF_FULLFACESIZE-1] = '\0'; wchar16strncpy(lfp.elfStyle, elfStyle, U_LF_FACESIZE); + lfp.elfStyle[U_LF_FACESIZE-1] = '\0'; lfp.elfLogFont = elfLogFont; lfp.elfStyleSize = elfStyleSize; lfp.elfPanose = elfPanose; diff --git a/src/live_effects/CMakeLists.txt b/src/live_effects/CMakeLists.txt index 8a097590a..9a2f06a76 100644 --- a/src/live_effects/CMakeLists.txt +++ b/src/live_effects/CMakeLists.txt @@ -6,6 +6,7 @@ set(live_effects_SRC lpe-bounding-box.cpp lpe-bspline.cpp lpe-circle_3pts.cpp + lpe-transform_2pts.cpp lpe-circle_with_radius.cpp lpe-clone-original.cpp lpe-constructgrid.cpp @@ -83,6 +84,7 @@ set(live_effects_SRC lpe-bounding-box.h lpe-bspline.h lpe-circle_3pts.h + lpe-transform_2pts.h lpe-circle_with_radius.h lpe-clone-original.h lpe-constructgrid.h diff --git a/src/live_effects/Makefile_insert b/src/live_effects/Makefile_insert index c2c2ce93c..b5bee55c8 100644 --- a/src/live_effects/Makefile_insert +++ b/src/live_effects/Makefile_insert @@ -74,6 +74,8 @@ ink_common_sources += \ live_effects/lpe-mirror_symmetry.h \ live_effects/lpe-circle_3pts.cpp \ live_effects/lpe-circle_3pts.h \ + live_effects/lpe-transform_2pts.cpp \ + live_effects/lpe-transform_2pts.h \ live_effects/lpe-angle_bisector.cpp \ live_effects/lpe-angle_bisector.h \ live_effects/lpe-parallel.cpp \ diff --git a/src/live_effects/effect-enum.h b/src/live_effects/effect-enum.h index 383eec19e..eea26184c 100644 --- a/src/live_effects/effect-enum.h +++ b/src/live_effects/effect-enum.h @@ -38,6 +38,7 @@ enum EffectType { TANGENT_TO_CURVE, MIRROR_SYMMETRY, CIRCLE_3PTS, + TRANSFORM_2PTS, ANGLE_BISECTOR, PARALLEL, COPY_ROTATE, diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp index 332d81777..fe7bf3a97 100644 --- a/src/live_effects/effect.cpp +++ b/src/live_effects/effect.cpp @@ -57,6 +57,7 @@ #include "live_effects/lpe-sketch.h" #include "live_effects/lpe-spiro.h" #include "live_effects/lpe-tangent_to_curve.h" +#include "live_effects/lpe-transform_2pts.h" #include "live_effects/lpe-taperstroke.h" #include "live_effects/lpe-test-doEffect-stack.h" #include "live_effects/lpe-text_label.h" @@ -150,6 +151,7 @@ const Util::EnumData<EffectType> LPETypeData[] = { {PERSPECTIVE_ENVELOPE, N_("Perspective/Envelope"), "perspective-envelope"}, {FILLET_CHAMFER, N_("Fillet/Chamfer"), "fillet-chamfer"}, {INTERPOLATE_POINTS, N_("Interpolate points"), "interpolate_points"}, + {TRANSFORM_2PTS, N_("Transform by 2 points"), "transform_2pts"}, }; const Util::EnumDataConverter<EffectType> LPETypeConverter(LPETypeData, sizeof(LPETypeData)/sizeof(*LPETypeData)); @@ -315,6 +317,9 @@ Effect::New(EffectType lpenr, LivePathEffectObject *lpeobj) case SHOW_HANDLES: neweffect = static_cast<Effect*> ( new LPEShowHandles(lpeobj) ); break; + case TRANSFORM_2PTS: + neweffect = static_cast<Effect*> ( new LPETransform2Pts(lpeobj) ); + break; default: g_warning("LivePathEffect::Effect::New called with invalid patheffect type (%d)", lpenr); neweffect = NULL; diff --git a/src/live_effects/lpe-bspline.cpp b/src/live_effects/lpe-bspline.cpp index d2da33aa9..7e92e767d 100644 --- a/src/live_effects/lpe-bspline.cpp +++ b/src/live_effects/lpe-bspline.cpp @@ -10,16 +10,18 @@ #include "svg/svg.h" #include "xml/repr.h" #include "preferences.h" +#include "document-undo.h" +#include "verbs.h" // TODO due to internal breakage in glibmm headers, this must be last: #include <glibmm/i18n.h> namespace Inkscape { namespace LivePathEffect { -const double HANDLE_CUBIC_GAP = 0.01; +const double HANDLE_CUBIC_GAP = 0.001; const double NO_POWER = 0.0; -const double DEFAULT_START_POWER = 0.3334; -const double DEFAULT_END_POWER = 0.6667; +const double DEFAULT_START_POWER = 0.333334; +const double DEFAULT_END_POWER = 0.666667; Geom::PathVector hp; void sp_bspline_drawHandle(Geom::Point p, double helper_size); @@ -27,23 +29,27 @@ LPEBSpline::LPEBSpline(LivePathEffectObject *lpeobject) : Effect(lpeobject), steps(_("Steps with CTRL:"), _("Change number of steps with CTRL pressed"), "steps", &wr, this, 2), helper_size(_("Helper size:"), _("Helper size"), "helper_size", &wr, this, 0), - ignore_cusp(_("Ignore cusp nodes"), _("Change ignoring cusp nodes"), "ignore_cusp", &wr, this, true), + apply_no_weight(_("Apply changes if weight = 0%"), _("Apply changes if weight = 0%"), "apply_no_weight", &wr, this, true), + apply_with_weight(_("Apply changes if weight > 0%"), _("Apply changes if weight > 0%"), "apply_with_weight", &wr, this, true), only_selected(_("Change only selected nodes"), _("Change only selected nodes"), "only_selected", &wr, this, false), - weight(_("Change weight:"), _("Change weight of the effect"), "weight", &wr, this, DEFAULT_START_POWER) + weight(_("Change weight %:"), _("Change weight percent of the effect"), "weight", &wr, this, DEFAULT_START_POWER * 100) { registerParameter(&weight); registerParameter(&steps); registerParameter(&helper_size); - registerParameter(&ignore_cusp); + registerParameter(&apply_no_weight); + registerParameter(&apply_with_weight); registerParameter(&only_selected); - weight.param_set_range(NO_POWER, 1); + weight.param_set_range(NO_POWER, 100.0); weight.param_set_increments(0.1, 0.1); weight.param_set_digits(4); + weight.param_overwrite_widget(true); steps.param_set_range(1, 10); steps.param_set_increments(1, 1); steps.param_set_digits(0); + steps.param_overwrite_widget(true); helper_size.param_set_range(0.0, 999.0); helper_size.param_set_increments(1, 1); @@ -111,15 +117,10 @@ Gtk::Widget *LPEBSpline::newWidget() Gtk::HBox * hbox_weight_steps = dynamic_cast<Gtk::HBox *>(widg); std::vector< Gtk::Widget* > childList = hbox_weight_steps->get_children(); Gtk::Entry* entry_widget = dynamic_cast<Gtk::Entry *>(childList[1]); - entry_widget->set_width_chars(6); + entry_widget->set_width_chars(9); } } - if (param->param_key == "only_selected") { - Gtk::CheckButton *widg_registered = - Gtk::manage(dynamic_cast<Gtk::CheckButton *>(widg)); - widg = dynamic_cast<Gtk::Widget *>(widg_registered); - } - if (param->param_key == "ignore_cusp") { + if (param->param_key == "only_selected" || param->param_key == "apply_no_weight" || param->param_key == "apply_with_weight") { Gtk::CheckButton *widg_registered = Gtk::manage(dynamic_cast<Gtk::CheckButton *>(widg)); widg = dynamic_cast<Gtk::Widget *>(widg_registered); @@ -143,17 +144,20 @@ Gtk::Widget *LPEBSpline::newWidget() void LPEBSpline::toDefaultWeight() { - changeWeight(DEFAULT_START_POWER); + changeWeight(DEFAULT_START_POWER * 100); + DocumentUndo::done(getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change to default weight")); } void LPEBSpline::toMakeCusp() { changeWeight(NO_POWER); + DocumentUndo::done(getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change to 0 weight")); } void LPEBSpline::toWeight() { changeWeight(weight); + DocumentUndo::done(getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change scalar parameter")); } void LPEBSpline::changeWeight(double weight_ammount) @@ -161,7 +165,7 @@ void LPEBSpline::changeWeight(double weight_ammount) SPPath *path = dynamic_cast<SPPath *>(sp_lpe_item); if(path) { SPCurve *curve = path->get_curve_for_edit(); - doBSplineFromWidget(curve, weight_ammount); + doBSplineFromWidget(curve, weight_ammount/100.0); gchar *str = sp_svg_write_path(curve->get_pathvector()); path->getRepr()->setAttribute("inkscape:original-d", str); } @@ -202,6 +206,18 @@ void sp_bspline_do_effect(SPCurve *curve, double helper_size) Geom::D2<Geom::SBasis> sbasis_helper; Geom::CubicBezier const *cubic = NULL; curve_n->moveto(curve_it1->initialPoint()); + if (path_it->closed()) { + const Geom::Curve &closingline = path_it->back_closed(); + // the closing line segment is always of type + // Geom::LineSegment. + if (are_near(closingline.initialPoint(), closingline.finalPoint())) { + // closingline.isDegenerate() did not work, because it only checks for + // *exact* zero length, which goes wrong for relative coordinates and + // rounding errors... + // the closing line segment has zero-length. So stop before that one! + curve_endit = path_it->end_open(); + } + } while (curve_it1 != curve_endit) { SPCurve *in = new SPCurve(); in->moveto(curve_it1->initialPoint()); @@ -357,6 +373,18 @@ void LPEBSpline::doBSplineFromWidget(SPCurve *curve, double weight_ammount) Geom::D2<Geom::SBasis> sbasis_out; Geom::CubicBezier const *cubic = NULL; curve_n->moveto(curve_it1->initialPoint()); + if (path_it->closed()) { + const Geom::Curve &closingline = path_it->back_closed(); + // the closing line segment is always of type + // Geom::LineSegment. + if (are_near(closingline.initialPoint(), closingline.finalPoint())) { + // closingline.isDegenerate() did not work, because it only checks for + // *exact* zero length, which goes wrong for relative coordinates and + // rounding errors... + // the closing line segment has zero-length. So stop before that one! + curve_endit = path_it->end_open(); + } + } while (curve_it1 != curve_endit) { SPCurve *in = new SPCurve(); in->moveto(curve_it1->initialPoint()); @@ -365,91 +393,61 @@ void LPEBSpline::doBSplineFromWidget(SPCurve *curve, double weight_ammount) point_at0 = in->first_segment()->initialPoint(); point_at3 = in->first_segment()->finalPoint(); sbasis_in = in->first_segment()->toSBasis(); - if (!only_selected) { - if (cubic) { - if (!ignore_cusp || !Geom::are_near((*cubic)[1], point_at0)) { + if (cubic) { + if ((apply_no_weight && apply_with_weight) || + (apply_no_weight && Geom::are_near((*cubic)[1], point_at0)) || + (apply_with_weight && !Geom::are_near((*cubic)[1], point_at0))) + { + if (isNodePointSelected(point_at0) || !only_selected) { point_at1 = sbasis_in.valueAt(weight_ammount); if (weight_ammount != NO_POWER) { point_at1 = Geom::Point(point_at1[X] + HANDLE_CUBIC_GAP, point_at1[Y] + HANDLE_CUBIC_GAP); } } else { - point_at1 = in->first_segment()->initialPoint(); - } - if (!ignore_cusp || !Geom::are_near((*cubic)[2], point_at3)) { - point_at2 = sbasis_in.valueAt(1 - weight_ammount); - if (weight_ammount != NO_POWER) { - point_at2 = - Geom::Point(point_at2[X] + HANDLE_CUBIC_GAP, point_at2[Y] + HANDLE_CUBIC_GAP); - } - } else { - point_at2 = in->first_segment()->finalPoint(); + point_at1 = (*cubic)[1]; } } else { - if (!ignore_cusp && weight_ammount != NO_POWER) { - point_at1 = sbasis_in.valueAt(weight_ammount); - if (weight_ammount != NO_POWER) { - point_at1 = - Geom::Point(point_at1[X] + HANDLE_CUBIC_GAP, point_at1[Y] + HANDLE_CUBIC_GAP); - } + point_at1 = (*cubic)[1]; + } + if ((apply_no_weight && apply_with_weight) || + (apply_no_weight && Geom::are_near((*cubic)[2], point_at3)) || + (apply_with_weight && !Geom::are_near((*cubic)[2], point_at3))) + { + if (isNodePointSelected(point_at3) || !only_selected) { point_at2 = sbasis_in.valueAt(1 - weight_ammount); if (weight_ammount != NO_POWER) { point_at2 = Geom::Point(point_at2[X] + HANDLE_CUBIC_GAP, point_at2[Y] + HANDLE_CUBIC_GAP); } } else { - point_at1 = in->first_segment()->initialPoint(); - point_at2 = in->first_segment()->finalPoint(); + point_at2 = (*cubic)[2]; } + } else { + point_at2 = (*cubic)[2]; } } else { - if (cubic) { - if (!ignore_cusp || !Geom::are_near((*cubic)[1], point_at0)) { - if (isNodePointSelected(point_at0)) { - point_at1 = sbasis_in.valueAt(weight_ammount); - if (weight_ammount != NO_POWER) { - point_at1 = - Geom::Point(point_at1[X] + HANDLE_CUBIC_GAP, point_at1[Y] + HANDLE_CUBIC_GAP); - } - } else { - point_at1 = (*cubic)[1]; - } + if ((apply_no_weight && apply_with_weight) || + (apply_no_weight && weight_ammount == NO_POWER) || + (apply_with_weight && weight_ammount != NO_POWER)) + { + if (isNodePointSelected(point_at0) || !only_selected) { + point_at1 = sbasis_in.valueAt(weight_ammount); + point_at1 = + Geom::Point(point_at1[X] + HANDLE_CUBIC_GAP, point_at1[Y] + HANDLE_CUBIC_GAP); } else { point_at1 = in->first_segment()->initialPoint(); } - if (!ignore_cusp || !Geom::are_near((*cubic)[2], point_at3)) { - if (isNodePointSelected(point_at3)) { - point_at2 = sbasis_in.valueAt(1 - weight_ammount); - if (weight_ammount != NO_POWER) { - point_at2 = - Geom::Point(point_at2[X] + HANDLE_CUBIC_GAP, point_at2[Y] + HANDLE_CUBIC_GAP); - } - } else { - point_at2 = (*cubic)[2]; - } + if (isNodePointSelected(point_at3) || !only_selected) { + point_at2 = sbasis_in.valueAt(1 - weight_ammount); + point_at2 = + Geom::Point(point_at2[X] + HANDLE_CUBIC_GAP, point_at2[Y] + HANDLE_CUBIC_GAP); } else { point_at2 = in->first_segment()->finalPoint(); } } else { - if (!ignore_cusp && weight_ammount != NO_POWER) { - if (isNodePointSelected(point_at0)) { - point_at1 = sbasis_in.valueAt(weight_ammount); - point_at1 = - Geom::Point(point_at1[X] + HANDLE_CUBIC_GAP, point_at1[Y] + HANDLE_CUBIC_GAP); - } else { - point_at1 = in->first_segment()->initialPoint(); - } - if (isNodePointSelected(point_at3)) { - point_at2 = sbasis_in.valueAt(weight_ammount); - point_at2 = - Geom::Point(point_at2[X] + HANDLE_CUBIC_GAP, point_at2[Y] + HANDLE_CUBIC_GAP); - } else { - point_at2 = in->first_segment()->finalPoint(); - } - } else { - point_at1 = in->first_segment()->initialPoint(); - point_at2 = in->first_segment()->finalPoint(); - } + point_at1 = in->first_segment()->initialPoint(); + point_at2 = in->first_segment()->finalPoint(); } } in->reset(); diff --git a/src/live_effects/lpe-bspline.h b/src/live_effects/lpe-bspline.h index 033e85cf0..7823f00f0 100644 --- a/src/live_effects/lpe-bspline.h +++ b/src/live_effects/lpe-bspline.h @@ -38,7 +38,8 @@ public: private: ScalarParam helper_size; - BoolParam ignore_cusp; + BoolParam apply_no_weight; + BoolParam apply_with_weight; BoolParam only_selected; ScalarParam weight; diff --git a/src/live_effects/lpe-fill-between-many.cpp b/src/live_effects/lpe-fill-between-many.cpp index 3e0810cfc..574ec3580 100644 --- a/src/live_effects/lpe-fill-between-many.cpp +++ b/src/live_effects/lpe-fill-between-many.cpp @@ -37,7 +37,7 @@ void LPEFillBetweenMany::doEffect (SPCurve * curve) { Geom::PathVector res_pathv; SPItem * firstObj = NULL; - for (std::vector<PathAndDirection*>::iterator iter = linked_paths._vector.begin(); iter != linked_paths._vector.end(); iter++) { + for (std::vector<PathAndDirection*>::iterator iter = linked_paths._vector.begin(); iter != linked_paths._vector.end(); ++iter) { SPObject *obj; if ((*iter)->ref.isAttached() && (obj = (*iter)->ref.getObject()) && SP_IS_ITEM(obj) && !(*iter)->_pathvector.empty()) { Geom::Path linked_path; diff --git a/src/live_effects/lpe-fillet-chamfer.cpp b/src/live_effects/lpe-fillet-chamfer.cpp index a9a96864a..209805da3 100644 --- a/src/live_effects/lpe-fillet-chamfer.cpp +++ b/src/live_effects/lpe-fillet-chamfer.cpp @@ -76,12 +76,15 @@ LPEFilletChamfer::LPEFilletChamfer(LivePathEffectObject *lpeobject) : radius.param_set_range(0., infinity()); radius.param_set_increments(1, 1); radius.param_set_digits(4); + radius.param_overwrite_widget(true); chamfer_steps.param_set_range(1, 999); chamfer_steps.param_set_increments(1, 1); chamfer_steps.param_set_digits(0); + chamfer_steps.param_overwrite_widget(true); helper_size.param_set_range(0, infinity()); helper_size.param_set_increments(5, 5); helper_size.param_set_digits(0); + helper_size.param_overwrite_widget(true); fillet_chamfer_values.set_chamfer_steps(3); } @@ -226,18 +229,21 @@ void LPEFilletChamfer::updateFillet() } Piecewise<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2(); doUpdateFillet(path_from_piecewise(pwd2, tolerance), power); + DocumentUndo::done(getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change scalar parameter")); } void LPEFilletChamfer::fillet() { Piecewise<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2(); doChangeType(path_from_piecewise(pwd2, tolerance), 1); + DocumentUndo::done(getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Convert to fillet")); } void LPEFilletChamfer::inverseFillet() { Piecewise<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2(); doChangeType(path_from_piecewise(pwd2, tolerance), 2); + DocumentUndo::done(getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Convert to inverse fillet")); } void LPEFilletChamfer::chamferSubdivisions() @@ -245,6 +251,7 @@ void LPEFilletChamfer::chamferSubdivisions() fillet_chamfer_values.set_chamfer_steps(chamfer_steps); Piecewise<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2(); doChangeType(path_from_piecewise(pwd2, tolerance), chamfer_steps + 5000); + DocumentUndo::done(getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change scalar parameter")); } void LPEFilletChamfer::chamfer() @@ -252,6 +259,7 @@ void LPEFilletChamfer::chamfer() fillet_chamfer_values.set_chamfer_steps(chamfer_steps); Piecewise<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2(); doChangeType(path_from_piecewise(pwd2, tolerance), chamfer_steps + 3000); + DocumentUndo::done(getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Convert to chamfer")); } void LPEFilletChamfer::inverseChamfer() @@ -259,6 +267,7 @@ void LPEFilletChamfer::inverseChamfer() fillet_chamfer_values.set_chamfer_steps(chamfer_steps); Piecewise<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2(); doChangeType(path_from_piecewise(pwd2, tolerance), chamfer_steps + 4000); + DocumentUndo::done(getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Convert to inverse fillet")); } void LPEFilletChamfer::refreshKnots() @@ -270,6 +279,7 @@ void LPEFilletChamfer::refreshKnots() tools_switch(desktop, TOOLS_SELECT); tools_switch(desktop, TOOLS_NODES); } + DocumentUndo::done(getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Knots and helper paths refreshed")); } void LPEFilletChamfer::doUpdateFillet(Geom::PathVector const &original_pathv, double power) diff --git a/src/live_effects/lpe-interpolate_points.cpp b/src/live_effects/lpe-interpolate_points.cpp index 4ac139752..cf70832ee 100644 --- a/src/live_effects/lpe-interpolate_points.cpp +++ b/src/live_effects/lpe-interpolate_points.cpp @@ -52,8 +52,11 @@ Geom::PathVector LPEInterpolatePoints::doEffect_path (Geom::PathVector const & path_in) { Geom::PathVector path_out; - +#if __cplusplus <= 199711L std::auto_ptr<Geom::Interpolate::Interpolator> interpolator( Geom::Interpolate::Interpolator::create(static_cast<Geom::Interpolate::InterpolatorType>(interpolator_type.get_value())) ); +#else + std::unique_ptr<Geom::Interpolate::Interpolator> interpolator( Geom::Interpolate::Interpolator::create(static_cast<Geom::Interpolate::InterpolatorType>(interpolator_type.get_value())) ); +#endif for(Geom::PathVector::const_iterator path_it = path_in.begin(); path_it != path_in.end(); ++path_it) { if (path_it->empty()) diff --git a/src/live_effects/lpe-knot.cpp b/src/live_effects/lpe-knot.cpp index c3000fe0d..bf84e645d 100644 --- a/src/live_effects/lpe-knot.cpp +++ b/src/live_effects/lpe-knot.cpp @@ -507,7 +507,7 @@ static void collectPathsAndWidths (SPLPEItem const *lpeitem, Geom::PathVector &paths, std::vector<double> &stroke_widths){ if (SP_IS_GROUP(lpeitem)) { std::vector<SPItem*> item_list = sp_item_group_item_list(SP_GROUP(lpeitem)); - for ( std::vector<SPItem*>::const_iterator iter = item_list.begin(); iter != item_list.end(); iter++) { + for ( std::vector<SPItem*>::const_iterator iter = item_list.begin(); iter != item_list.end(); ++iter) { SPObject *subitem = *iter; if (SP_IS_LPE_ITEM(subitem)) { collectPathsAndWidths(SP_LPE_ITEM(subitem), paths, stroke_widths); diff --git a/src/live_effects/lpe-powerstroke.cpp b/src/live_effects/lpe-powerstroke.cpp index f90d67d4e..03102a84a 100644 --- a/src/live_effects/lpe-powerstroke.cpp +++ b/src/live_effects/lpe-powerstroke.cpp @@ -102,12 +102,15 @@ static Circle touching_circle( D2<SBasis> const &curve, double t, double tol=0.0 { //Piecewise<SBasis> k = curvature(curve, tol); D2<SBasis> dM=derivative(curve); - if ( are_near(L2sq(dM(t)),0.) ) { + if ( are_near(L2sq(dM(t)),0.) && (dM[0].size() > 1) && (dM[1].size() > 1) ) { dM=derivative(dM); } - if ( are_near(L2sq(dM(t)),0.) ) { // try second time + if ( are_near(L2sq(dM(t)),0.) && (dM[0].size() > 1) && (dM[1].size() > 1) ) { // try second time dM=derivative(dM); } + if ( are_near(L2sq(dM(t)),0.) && (dM[0].size() > 1) && (dM[1].size() > 1) ) { // admit defeat + return Geom::Circle(Geom::Point(0., 0.), 0.); + } Piecewise<D2<SBasis> > unitv = unitVector(dM,tol); Piecewise<SBasis> dMlength = dot(Piecewise<D2<SBasis> >(dM),unitv); Piecewise<SBasis> k = cross(derivative(unitv),unitv); diff --git a/src/live_effects/lpe-roughen.cpp b/src/live_effects/lpe-roughen.cpp index 33ffd96d6..b4ee54f1a 100644 --- a/src/live_effects/lpe-roughen.cpp +++ b/src/live_effects/lpe-roughen.cpp @@ -18,7 +18,9 @@ #include "live_effects/lpe-roughen.h" #include "display/curve.h" #include "live_effects/parameter/parameter.h" +#include <boost/functional/hash.hpp> #include "helper/geom.h" +#include "sp-item-group.h" #include <glibmm/i18n.h> #include <cmath> @@ -32,13 +34,22 @@ static const Util::EnumData<DivisionMethod> DivisionMethodData[DM_END] = { static const Util::EnumDataConverter<DivisionMethod> DMConverter(DivisionMethodData, DM_END); +static const Util::EnumData<HandlesMethod> HandlesMethodData[HM_END] = { + { HM_ALONG_NODES, N_("Along nodes"), "along" }, + { HM_RAND, N_("Rand"), "rand" }, + { HM_RETRACT, N_("Retract"), "retract" }, + { HM_SMOOTH, N_("Smooth"), "smooth" } +}; +static const Util::EnumDataConverter<HandlesMethod> +HMConverter(HandlesMethodData, HM_END); + LPERoughen::LPERoughen(LivePathEffectObject *lpeobject) : Effect(lpeobject), // initialise your parameters here: method(_("Method"), _("Division method"), "method", DMConverter, &wr, this, DM_SEGMENTS), max_segment_size(_("Max. segment size"), _("Max. segment size"), - "max_segment_size", &wr, this, 10.), + "max_segment_size", &wr, this, 10), segments(_("Number of segments"), _("Number of segments"), "segments", &wr, this, 2), displace_x(_("Max. displacement in X"), _("Max. displacement in X"), @@ -47,10 +58,14 @@ LPERoughen::LPERoughen(LivePathEffectObject *lpeobject) "displace_y", &wr, this, 10.), global_randomize(_("Global randomize"), _("Global randomize"), "global_randomize", &wr, this, 1.), + handles(_("Handles"), _("Handles options"), "handles", HMConverter, &wr, + this, HM_ALONG_NODES), shift_nodes(_("Shift nodes"), _("Shift nodes"), "shift_nodes", &wr, this, true), - shift_node_handles(_("Shift node handles"), _("Shift node handles"), - "shift_node_handles", &wr, this, true) + fixed_displacement(_("Fixed displacement"), _("Fixed displacement, 1/3 of segment length"), + "fixed_displacement", &wr, this, false), + spray_tool_friendly(_("Spray Tool friendly"), _("For use with spray tool in copy mode"), + "spray_tool_friendly", &wr, this, false) { registerParameter(&method); registerParameter(&max_segment_size); @@ -58,8 +73,10 @@ LPERoughen::LPERoughen(LivePathEffectObject *lpeobject) registerParameter(&displace_x); registerParameter(&displace_y); registerParameter(&global_randomize); + registerParameter(&handles); registerParameter(&shift_nodes); - registerParameter(&shift_node_handles); + registerParameter(&fixed_displacement); + registerParameter(&spray_tool_friendly); displace_x.param_set_range(0., Geom::infinity()); displace_y.param_set_range(0., Geom::infinity()); global_randomize.param_set_range(0., Geom::infinity()); @@ -69,12 +86,18 @@ LPERoughen::LPERoughen(LivePathEffectObject *lpeobject) segments.param_set_range(1, Geom::infinity()); segments.param_set_increments(1, 1); segments.param_set_digits(0); + seed = 0; } LPERoughen::~LPERoughen() {} void LPERoughen::doBeforeEffect(SPLPEItem const *lpeitem) { + if(spray_tool_friendly && seed == 0 && SP_OBJECT(lpeitem)->getId()){ + std::string id_item(SP_OBJECT(lpeitem)->getId()); + long seed = static_cast<long>(boost::hash_value(id_item)); + global_randomize.param_set_value(global_randomize.get_value(), seed); + } displace_x.resetRandomizer(); displace_y.resetRandomizer(); global_randomize.resetRandomizer(); @@ -122,6 +145,15 @@ Gtk::Widget *LPERoughen::newWidget() vbox->pack_start(*Gtk::manage(new Gtk::HSeparator()), Gtk::PACK_EXPAND_WIDGET); } + if (param->param_key == "handles") { + Gtk::Label *options = Gtk::manage(new Gtk::Label( + Glib::ustring(_("<b>Options</b> Modify options to rough")), + Gtk::ALIGN_START)); + options->set_use_markup(true); + vbox->pack_start(*options, false, false, 2); + vbox->pack_start(*Gtk::manage(new Gtk::HSeparator()), + Gtk::PACK_EXPAND_WIDGET); + } Glib::ustring *tip = param->param_getTooltip(); if (widg) { vbox->pack_start(*widg, true, true, 2); @@ -133,7 +165,6 @@ Gtk::Widget *LPERoughen::newWidget() } } } - ++it; } return dynamic_cast<Gtk::Widget *>(vbox); @@ -147,19 +178,25 @@ double LPERoughen::sign(double random_number) return random_number; } -Geom::Point LPERoughen::randomize() +Geom::Point LPERoughen::randomize(double max_lenght, bool is_node) { - double displace_x_parsed = displace_x * global_randomize; - double displace_y_parsed = displace_y * global_randomize; - + double factor = 1.0/3.0; + if(is_node){ + factor = 1.0; + } + double displace_x_parsed = displace_x * global_randomize * factor; + double displace_y_parsed = displace_y * global_randomize * factor; Geom::Point output = Geom::Point(sign(displace_x_parsed), sign(displace_y_parsed)); + if( fixed_displacement ){ + Geom::Ray ray(Geom::Point(0,0),output); + output = Geom::Point::polar(ray.angle(), max_lenght); + } return output; } void LPERoughen::doEffect(SPCurve *curve) { - Geom::PathVector const original_pathv = - pathv_to_linear_and_cubic_beziers(curve->get_pathvector()); + Geom::PathVector const original_pathv = pathv_to_linear_and_cubic_beziers(curve->get_pathvector()); curve->reset(); for (Geom::PathVector::const_iterator path_it = original_pathv.begin(); path_it != original_pathv.end(); ++path_it) { @@ -170,41 +207,30 @@ void LPERoughen::doEffect(SPCurve *curve) Geom::Path::const_iterator curve_it2 = ++(path_it->begin()); Geom::Path::const_iterator curve_endit = path_it->end_default(); SPCurve *nCurve = new SPCurve(); + Geom::Point prev(0, 0); + Geom::Point last_move(0, 0); + nCurve->moveto(curve_it1->initialPoint()); if (path_it->closed()) { - const Geom::Curve &closingline = - path_it->back_closed(); - if (are_near(closingline.initialPoint(), closingline.finalPoint())) { - curve_endit = path_it->end_open(); - } - } - Geom::Point initialMove(0, 0); - if (shift_nodes) { - initialMove = randomize(); + const Geom::Curve &closingline = path_it->back_closed(); + // the closing line segment is always of type + // Geom::LineSegment. + if (are_near(closingline.initialPoint(), closingline.finalPoint())) { + // closingline.isDegenerate() did not work, because it only checks for + // *exact* zero length, which goes wrong for relative coordinates and + // rounding errors... + // the closing line segment has zero-length. So stop before that one! + curve_endit = path_it->end_open(); + } } - Geom::Point initialPoint = curve_it1->initialPoint() + initialMove; - nCurve->moveto(initialPoint); - Geom::Point point0(0, 0); - Geom::Point point1(0, 0); - Geom::Point point2(0, 0); - Geom::Point point3(0, 0); - bool first = true; while (curve_it1 != curve_endit) { Geom::CubicBezier const *cubic = NULL; - point0 = curve_it1->initialPoint(); - point1 = curve_it1->initialPoint(); - point2 = curve_it1->finalPoint(); - point3 = curve_it1->finalPoint(); cubic = dynamic_cast<Geom::CubicBezier const *>(&*curve_it1); if (cubic) { - point1 = (*cubic)[1]; - if (shift_nodes && first) { - point1 = (*cubic)[1] + initialMove; - } - point2 = (*cubic)[2]; - nCurve->curveto(point1, point2, point3); + nCurve->curveto((*cubic)[1] + last_move, (*cubic)[2], curve_it1->finalPoint()); } else { - nCurve->lineto(point3); + nCurve->lineto(curve_it1->finalPoint()); } + last_move = Geom::Point(0, 0); double length = curve_it1->length(0.001); std::size_t splits = 0; if (method == DM_SEGMENTS) { @@ -212,15 +238,21 @@ void LPERoughen::doEffect(SPCurve *curve) } else { splits = ceil(length / max_segment_size); } - for (unsigned int t = splits; t >= 1; t--) { - if (t == 1 && splits != 1) { + Geom::Curve const * original = nCurve->last_segment()->duplicate() ; + for (unsigned int t = 1; t <= splits; t++) { + if(t == splits && splits != 1){ continue; } - const SPCurve *tmp; + SPCurve const * tmp; if (splits == 1) { - tmp = jitter(nCurve->last_segment()); + tmp = jitter(nCurve->last_segment(), prev, last_move); } else { - tmp = addNodesAndJitter(nCurve->last_segment(), 1. / t); + bool last = false; + if(t == splits-1){ + last = true; + } + double time = Geom::nearest_time(original->pointAt((1. / (double)splits) * t), *nCurve->last_segment()); + tmp = addNodesAndJitter(nCurve->last_segment(), prev, last_move, time, last); } if (nCurve->get_segment_count() > 1) { nCurve->backspace(); @@ -231,12 +263,44 @@ void LPERoughen::doEffect(SPCurve *curve) delete tmp; } ++curve_it1; - if(curve_it2 != curve_endit) { - ++curve_it2; - } - first = false; + ++curve_it2; } if (path_it->closed()) { + if(handles == HM_SMOOTH && curve_it1 == curve_endit){ + SPCurve *out = new SPCurve(); + nCurve = nCurve->create_reverse(); + Geom::CubicBezier const *cubic_start = dynamic_cast<Geom::CubicBezier const *>(nCurve->first_segment()); + Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const *>(nCurve->last_segment()); + Geom::Point oposite = nCurve->first_segment()->pointAt(1.0/3.0); + if(cubic_start){ + Geom::Ray ray((*cubic_start)[1], (*cubic_start)[0]); + double dist = Geom::distance((*cubic_start)[1], (*cubic_start)[0]); + oposite = Geom::Point::polar(ray.angle(),dist) + (*cubic_start)[0]; + } + if(cubic){ + out->moveto((*cubic)[0]); + out->curveto((*cubic)[1], oposite, (*cubic)[3]); + } else { + out->moveto(nCurve->last_segment()->initialPoint()); + out->curveto(nCurve->last_segment()->initialPoint(), oposite, nCurve->last_segment()->finalPoint()); + } + nCurve->backspace(); + nCurve->append_continuous(out, 0.001); + nCurve = nCurve->create_reverse(); + } + if(handles == HM_ALONG_NODES && curve_it1 == curve_endit){ + SPCurve *out = new SPCurve(); + nCurve = nCurve->create_reverse(); + Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const *>(nCurve->last_segment()); + if(cubic){ + out->moveto((*cubic)[0]); + out->curveto((*cubic)[1], (*cubic)[2] - ((*cubic)[3] - nCurve->first_segment()->initialPoint()) , (*cubic)[3]); + nCurve->backspace(); + nCurve->append_continuous(out, 0.001); + } + nCurve = nCurve->create_reverse(); + } + nCurve->move_endpoints(nCurve->last_segment()->finalPoint(), nCurve->last_segment()->finalPoint()); nCurve->closepath_current(); } curve->append(nCurve, false); @@ -245,77 +309,211 @@ void LPERoughen::doEffect(SPCurve *curve) } } -SPCurve *LPERoughen::addNodesAndJitter(const Geom::Curve *A, double t) +SPCurve const * LPERoughen::addNodesAndJitter(Geom::Curve const * A, Geom::Point &prev, Geom::Point &last_move, double t, bool last) { SPCurve *out = new SPCurve(); Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const *>(&*A); - Geom::Point point1(0, 0); - Geom::Point point2(0, 0); - Geom::Point point3(0, 0); + double max_lenght = Geom::distance(A->initialPoint(),A->pointAt(t)) / 3.0; + Geom::Point point_a1(0, 0); + Geom::Point point_a2(0, 0); + Geom::Point point_a3(0, 0); Geom::Point point_b1(0, 0); Geom::Point point_b2(0, 0); Geom::Point point_b3(0, 0); if (shift_nodes) { - point3 = randomize(); - point_b3 = randomize(); + point_a3 = randomize(max_lenght, true); + if(last){ + point_b3 = randomize(max_lenght, true); + } } - if (shift_node_handles) { - point1 = randomize(); - point2 = randomize(); - point_b1 = randomize(); - point_b2 = randomize(); + if (handles == HM_RAND || handles == HM_SMOOTH) { + point_a1 = randomize(max_lenght); + point_a2 = randomize(max_lenght); + point_b1 = randomize(max_lenght); + if(last){ + point_b2 = randomize(max_lenght); + } } else { - point2 = point3; - point_b1 = point3; - point_b2 = point_b3; + point_a2 = point_a3; + point_b1 = point_a3; + if(last){ + point_b2 = point_b3; + } } - if (cubic) { - std::pair<Geom::CubicBezier, Geom::CubicBezier> div = cubic->subdivide(t); - std::vector<Geom::Point> seg1 = div.first.controlPoints(), - seg2 = div.second.controlPoints(); - out->moveto(seg1[0]); - out->curveto(seg1[1] + point1, seg1[2] + point2, seg1[3] + point3); - out->curveto(seg2[1] + point_b1, seg2[2], seg2[3]); - } else if (shift_node_handles) { - out->moveto(A->initialPoint()); - out->curveto(A->pointAt(t / 3) + point1, A->pointAt((t / 3) * 2) + point2, - A->pointAt(t) + point3); - out->curveto(A->pointAt(t + (t / 3)) + point_b1, A->pointAt(t + ((t / 3) * 2)), - A->finalPoint()); - } else { + if(handles == HM_SMOOTH){ + if(cubic) { + std::pair<Geom::CubicBezier, Geom::CubicBezier> div = cubic->subdivide(t); + std::vector<Geom::Point> seg1 = div.first.controlPoints(), + seg2 = div.second.controlPoints(); + Geom::Ray ray(seg1[3] + point_a3, seg2[1] + point_a3); + double lenght = max_lenght; + if(!fixed_displacement ){ + lenght = Geom::distance(seg1[3] + point_a3, seg2[1] + point_a3); + } + point_b1 = seg1[3] + point_a3 + Geom::Point::polar(ray.angle() , lenght); + point_b2 = seg2[2]; + point_b3 = seg2[3] + point_b3; + point_a3 = seg1[3] + point_a3; + ray.setPoints(prev,A->initialPoint()); + point_a1 = A->initialPoint() + Geom::Point::polar(ray.angle(), max_lenght); + if(prev == Geom::Point(0,0)){ + point_a1 = randomize(max_lenght); + } + if(last){ + Geom::Path b2(point_b3); + b2.appendNew<Geom::LineSegment>(point_a3); + lenght = max_lenght; + ray.setPoints(point_b3, point_b2); + if(!fixed_displacement ){ + lenght = Geom::distance(b2.pointAt(1.0/3.0), point_b3); + } + point_b2 = point_b3 + Geom::Point::polar(ray.angle() , lenght); + } + ray.setPoints(point_b1, point_a3); + point_a2 = point_a3 + Geom::Point::polar(ray.angle(), max_lenght); + if(last){ + prev = point_b2; + } else { + prev = point_a2; + } + out->moveto(seg1[0]); + out->curveto(point_a1,point_a2,point_a3); + out->curveto(point_b1, point_b2, point_b3); + } else { + Geom::Ray ray(A->pointAt(t) + point_a3, A->pointAt(t + (t / 3))); + double lenght = max_lenght; + if(!fixed_displacement ){ + lenght = Geom::distance(A->pointAt(t) + point_a3, A->pointAt(t + (t / 3))); + } + point_b1 = A->pointAt(t) + point_a3 + Geom::Point::polar(ray.angle() , lenght); + point_b2 = A->pointAt(t +((t / 3) * 2)); + point_b3 = A->finalPoint() + point_b3; + point_a3 = A->pointAt(t) + point_a3; + ray.setPoints(prev,A->initialPoint()); + point_a1 = A->initialPoint() + Geom::Point::polar(ray.angle(), max_lenght); + if(prev == Geom::Point(0,0)){ + point_a1 = randomize(max_lenght); + } + if(last){ + Geom::Path b2(point_b3); + b2.appendNew<Geom::LineSegment>(point_a3); + lenght = max_lenght; + ray.setPoints(point_b3, point_b2); + if(!fixed_displacement ){ + lenght = Geom::distance(b2.pointAt(1.0/3.0), point_b3); + } + point_b2 = point_b3 + Geom::Point::polar(ray.angle() , lenght); + } + ray.setPoints(point_b1, point_a3); + point_a2 = point_a3 + Geom::Point::polar(ray.angle(), max_lenght); + if(last){ + prev = point_b2; + } else { + prev = point_a2; + } + out->moveto(A->initialPoint()); + out->curveto(point_a1,point_a2,point_a3); + out->curveto(point_b1, point_b2, point_b3); + } + } else if(handles == HM_RETRACT){ out->moveto(A->initialPoint()); - out->lineto(A->pointAt(t) + point3); - out->lineto(A->finalPoint()); + out->lineto(A->pointAt(t) + point_a3); + if(cubic && !last){ + std::pair<Geom::CubicBezier, Geom::CubicBezier> div = cubic->subdivide(t); + std::vector<Geom::Point> seg2 = div.second.controlPoints(); + out->curveto(seg2[1], seg2[2], seg2[3]); + } else { + out->lineto(A->finalPoint() + point_b3); + } + } else if(handles == HM_ALONG_NODES){ + if (cubic) { + std::pair<Geom::CubicBezier, Geom::CubicBezier> div = cubic->subdivide(t); + std::vector<Geom::Point> seg1 = div.first.controlPoints(), + seg2 = div.second.controlPoints(); + out->moveto(seg1[0]); + out->curveto(seg1[1] + last_move, seg1[2] + point_a3, seg1[3] + point_a3); + last_move = point_a3; + if(last){ + last_move = point_b3; + } + out->curveto(seg2[1] + point_a3, seg2[2] + point_b3, seg2[3] + point_b3); + } else { + out->moveto(A->initialPoint()); + out->lineto(A->pointAt(t) + point_a3); + out->lineto(A->finalPoint() + point_b3); + } + } else if(handles == HM_RAND) { + if (cubic) { + std::pair<Geom::CubicBezier, Geom::CubicBezier> div = cubic->subdivide(t); + std::vector<Geom::Point> seg1 = div.first.controlPoints(), + seg2 = div.second.controlPoints(); + out->moveto(seg1[0]); + out->curveto(seg1[1] + point_a1, seg1[2] + point_a2 + point_a3, seg1[3] + point_a3); + out->curveto(seg2[1] + point_a3 + point_b1, seg2[2] + point_b2 + point_b3, seg2[3] + point_b3); + } else { + out->moveto(A->initialPoint()); + out->lineto(A->pointAt(t) + point_a3); + out->lineto(A->finalPoint() + point_b3); + } } return out; } -SPCurve *LPERoughen::jitter(const Geom::Curve *A) +SPCurve *LPERoughen::jitter(Geom::Curve const * A, Geom::Point &prev, Geom::Point &last_move) { SPCurve *out = new SPCurve(); Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const *>(&*A); - Geom::Point point1(0, 0); - Geom::Point point2(0, 0); - Geom::Point point3(0, 0); + double max_lenght = Geom::distance(A->initialPoint(),A->finalPoint()) / 3.0; + Geom::Point point_a1(0, 0); + Geom::Point point_a2(0, 0); + Geom::Point point_a3(0, 0); if (shift_nodes) { - point3 = randomize(); + point_a3 = randomize(max_lenght, true); } - if (shift_node_handles) { - point1 = randomize(); - point2 = randomize(); - } else { - point2 = point3; + if (handles == HM_RAND || handles == HM_SMOOTH) { + point_a1 = randomize(max_lenght); + point_a2 = randomize(max_lenght); } - if (cubic) { - out->moveto((*cubic)[0]); - out->curveto((*cubic)[1] + point1, (*cubic)[2] + point2, (*cubic)[3] + point3); - } else if (shift_node_handles) { + if(handles == HM_SMOOTH) { + if (cubic) { + Geom::Ray ray(prev,A->initialPoint()); + point_a1 = Geom::Point::polar(ray.angle(), max_lenght); + if(prev == Geom::Point(0,0)){ + point_a1 = A->pointAt(1.0/3.0) + randomize(max_lenght); + } + ray.setPoints((*cubic)[3] + point_a3, (*cubic)[2] + point_a3); + point_a2 = randomize(max_lenght, ray.angle()); + prev = (*cubic)[2] + point_a2; + out->moveto((*cubic)[0]); + out->curveto((*cubic)[0] + point_a1, (*cubic)[2] + point_a2 + point_a3, (*cubic)[3] + point_a3); + } else { + Geom::Ray ray(prev,A->initialPoint()); + point_a1 = Geom::Point::polar(ray.angle(), max_lenght); + if(prev==Geom::Point(0,0)){ + point_a1 = A->pointAt(1.0/3.0) + randomize(max_lenght); + } + ray.setPoints(A->finalPoint() + point_a3, A->pointAt((1.0/3.0) * 2) + point_a3); + point_a2 = randomize(max_lenght, ray.angle()); + prev = A->pointAt((1.0/3.0) * 2) + point_a2 + point_a3; + out->moveto(A->initialPoint()); + out->curveto(A->initialPoint() + point_a1, A->pointAt((1.0/3.0) * 2) + point_a2 + point_a3, A->finalPoint() + point_a3); + } + } else if(handles == HM_RETRACT){ out->moveto(A->initialPoint()); - out->curveto(A->pointAt(0.3333) + point1, A->pointAt(0.6666) + point2, - A->finalPoint() + point3); - } else { + out->lineto(A->finalPoint() + point_a3); + } else if (handles == HM_ALONG_NODES) { + if(cubic){ + out->moveto((*cubic)[0]); + out->curveto((*cubic)[1] + last_move, (*cubic)[2] + point_a3, (*cubic)[3] + point_a3); + last_move = point_a3; + } else { + out->moveto(A->initialPoint()); + out->lineto(A->finalPoint() + point_a3); + } + } else if (handles == HM_RAND) { out->moveto(A->initialPoint()); - out->lineto(A->finalPoint() + point3); + out->curveto(A->pointAt(0.3333) + point_a1, A->pointAt(0.6666) + point_a2 + point_a3, + A->finalPoint() + point_a3); } return out; } diff --git a/src/live_effects/lpe-roughen.h b/src/live_effects/lpe-roughen.h index 2b285cd40..44a723c89 100644 --- a/src/live_effects/lpe-roughen.h +++ b/src/live_effects/lpe-roughen.h @@ -28,6 +28,15 @@ enum DivisionMethod { DM_END }; +enum HandlesMethod { + HM_ALONG_NODES, + HM_RAND, + HM_RETRACT, + HM_SMOOTH, + HM_END +}; + + class LPERoughen : public Effect { public: @@ -36,10 +45,10 @@ public: virtual void doEffect(SPCurve *curve); virtual double sign(double randNumber); - virtual Geom::Point randomize(); + virtual Geom::Point randomize(double max_lenght, bool is_node = false); virtual void doBeforeEffect(SPLPEItem const * lpeitem); - virtual SPCurve *addNodesAndJitter(const Geom::Curve *A, double t); - virtual SPCurve *jitter(const Geom::Curve *A); + virtual SPCurve const * addNodesAndJitter(Geom::Curve const * A, Geom::Point &prev, Geom::Point &last_move, double t, bool last); + virtual SPCurve *jitter(Geom::Curve const * A, Geom::Point &prev, Geom::Point &last_move); virtual Geom::Point tPoint(Geom::Point A, Geom::Point B, double t = 0.5); virtual Gtk::Widget *newWidget(); @@ -50,9 +59,11 @@ private: RandomParam displace_x; RandomParam displace_y; RandomParam global_randomize; + EnumParam<HandlesMethod> handles; BoolParam shift_nodes; - BoolParam shift_node_handles; - + BoolParam fixed_displacement; + BoolParam spray_tool_friendly; + long seed; LPERoughen(const LPERoughen &); LPERoughen &operator=(const LPERoughen &); diff --git a/src/live_effects/lpe-simplify.cpp b/src/live_effects/lpe-simplify.cpp index f6842a030..a919756df 100644 --- a/src/live_effects/lpe-simplify.cpp +++ b/src/live_effects/lpe-simplify.cpp @@ -28,8 +28,8 @@ namespace LivePathEffect { LPESimplify::LPESimplify(LivePathEffectObject *lpeobject) : Effect(lpeobject), steps(_("Steps:"),_("Change number of simplify steps "), "steps", &wr, this,1), - threshold(_("Roughly threshold:"), _("Roughly threshold:"), "threshold", &wr, this, 0.003), - smooth_angles(_("Smooth angles:"), _("Max degree difference on handles to preform a smooth"), "smooth_angles", &wr, this, 20.), + threshold(_("Roughly threshold:"), _("Roughly threshold:"), "threshold", &wr, this, 0.002), + smooth_angles(_("Smooth angles:"), _("Max degree difference on handles to perform a smooth"), "smooth_angles", &wr, this, 0.), helper_size(_("Helper size:"), _("Helper size"), "helper_size", &wr, this, 5), simplify_individual_paths(_("Paths separately"), _("Simplifying paths (separately)"), "simplify_individual_paths", &wr, this, false, "", INKSCAPE_ICON("on"), INKSCAPE_ICON("off")), @@ -51,7 +51,7 @@ LPESimplify::LPESimplify(LivePathEffectObject *lpeobject) steps.param_set_increments(1, 1); steps.param_set_digits(0); - smooth_angles.param_set_range(0.0, 365.0); + smooth_angles.param_set_range(0.0, 360.0); smooth_angles.param_set_increments(10, 10); smooth_angles.param_set_digits(2); @@ -138,6 +138,7 @@ LPESimplify::doEffect(SPCurve *curve) if(simplify_individual_paths) { size = Geom::L2(Geom::bounds_fast(original_pathv)->dimensions()); } + size /= sp_lpe_item->i2doc_affine().descrim(); for (int unsigned i = 0; i < steps; i++) { if ( simplify_just_coalesce ) { pathliv->Coalesce(threshold * size); @@ -198,13 +199,15 @@ LPESimplify::generateHelperPathAndSmooth(Geom::PathVector &result) Geom::Point point_at2 = curve_it1->finalPoint(); Geom::Point point_at3 = curve_it1->finalPoint(); Geom::Point point_at4 = curve_it1->finalPoint(); + + if(start == Geom::Point(0,0)) { + start = point_at1; + } + if (cubic) { point_at1 = (*cubic)[1]; point_at2 = (*cubic)[2]; } - if(start == Geom::Point(0,0)) { - start = point_at1; - } if(path_it->closed() && curve_it2 == curve_endit) { point_at4 = start; @@ -219,11 +222,11 @@ LPESimplify::generateHelperPathAndSmooth(Geom::PathVector &result) Geom::Ray ray2(point_at3, point_at4); double angle1 = Geom::rad_to_deg(ray1.angle()); double angle2 = Geom::rad_to_deg(ray2.angle()); - if((smooth_angles >= angle2 - angle1) && !are_near(point_at4,point_at3) && !are_near(point_at2,point_at3)) { + if((smooth_angles >= std::abs(angle2 - angle1)) && !are_near(point_at4,point_at3) && !are_near(point_at2,point_at3)) { double dist = Geom::distance(point_at2,point_at3); Geom::Angle angleFixed = ray2.angle(); angleFixed -= Geom::Angle::from_degrees(180.0); - point_at2 = Geom::Point::polar(angleFixed,dist) + point_at3; + point_at2 = Geom::Point::polar(angleFixed, dist) + point_at3; } nCurve->curveto(point_at1, point_at2, curve_it1->finalPoint()); cubic = dynamic_cast<Geom::CubicBezier const *>(nCurve->last_segment()); diff --git a/src/live_effects/lpe-taperstroke.cpp b/src/live_effects/lpe-taperstroke.cpp index ef616f802..f2ddd4929 100644 --- a/src/live_effects/lpe-taperstroke.cpp +++ b/src/live_effects/lpe-taperstroke.cpp @@ -408,9 +408,8 @@ Piecewise<D2<SBasis> > stretch_along(Piecewise<D2<SBasis> > pwd2_in, Geom::Path n = force_continuity(remove_short_cuts(n,.1)); int nbCopies = 0; - double scaling = 1; + double scaling = (uskeleton.domain().extent() - toffset)/pattBndsX->extent(); nbCopies = 1; - scaling = (uskeleton.domain().extent() - toffset)/pattBndsX->extent(); double pattWidth = pattBndsX->extent() * scaling; diff --git a/src/live_effects/lpe-transform_2pts.cpp b/src/live_effects/lpe-transform_2pts.cpp new file mode 100644 index 000000000..f2b756567 --- /dev/null +++ b/src/live_effects/lpe-transform_2pts.cpp @@ -0,0 +1,462 @@ +/** \file + * LPE "Transform through 2 points" implementation + */ + +/* + * Authors: + * Jabier Arraiza Cenoz<jabier.arraiza@marker.es> + * + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include <gtkmm.h> + +#include "live_effects/lpe-transform_2pts.h" +#include "display/curve.h" +#include <2geom/transforms.h> +#include <2geom/pathvector.h> +#include "sp-path.h" +#include "ui/icon-names.h" +#include "svg/svg.h" +#include "verbs.h" +// TODO due to internal breakage in glibmm headers, this must be last: +#include <glibmm/i18n.h> + +namespace Inkscape { +namespace LivePathEffect { + +LPETransform2Pts::LPETransform2Pts(LivePathEffectObject *lpeobject) : + Effect(lpeobject), + elastic(_("Elastic"), _("Elastic transform mode"), "elastic", &wr, this, false,"", INKSCAPE_ICON("on"), INKSCAPE_ICON("off")), + from_original_width(_("From original width"), _("From original width"), "from_original_width", &wr, this, false,"", INKSCAPE_ICON("on"), INKSCAPE_ICON("off")), + lock_lenght(_("Lock length"), _("Lock length to current distance"), "lock_lenght", &wr, this, false,"", INKSCAPE_ICON("on"), INKSCAPE_ICON("off")), + lock_angle(_("Lock angle"), _("Lock angle"), "lock_angle", &wr, this, false,"", INKSCAPE_ICON("on"), INKSCAPE_ICON("off")), + flip_horizontal(_("Flip horizontal"), _("Flip horizontal"), "flip_horizontal", &wr, this, false,"", INKSCAPE_ICON("on"), INKSCAPE_ICON("off")), + flip_vertical(_("Flip vertical"), _("Flip vertical"), "flip_vertical", &wr, this, false,"", INKSCAPE_ICON("on"), INKSCAPE_ICON("off")), + start(_("Start"), _("Start point"), "start", &wr, this, "Start point"), + end(_("End"), _("End point"), "end", &wr, this, "End point"), + strech(_("Stretch"), _("Stretch the result"), "strech", &wr, this, 1), + offset(_("Offset"), _("Offset from knots"), "offset", &wr, this, 0), + first_knot(_("First Knot"), _("First Knot"), "first_knot", &wr, this, 1), + last_knot(_("Last Knot"), _("Last Knot"), "last_knot", &wr, this, 1), + helper_size(_("Helper size:"), _("Rotation helper size"), "helper_size", &wr, this, 3), + from_original_width_toggler(false), + point_a(Geom::Point()), + point_b(Geom::Point()), + pathvector(), + append_path(false), + previous_angle(Geom::deg_to_rad(0)), + previous_start(Geom::Point()), + previous_lenght(-1) +{ + + registerParameter(&first_knot); + registerParameter(&last_knot); + registerParameter(&helper_size); + registerParameter(&strech); + registerParameter(&offset); + registerParameter(&start); + registerParameter(&end); + registerParameter(&elastic); + registerParameter(&from_original_width); + registerParameter(&flip_vertical); + registerParameter(&flip_horizontal); + registerParameter(&lock_lenght); + registerParameter(&lock_angle); + + first_knot.param_make_integer(true); + first_knot.param_overwrite_widget(true); + last_knot.param_make_integer(true); + last_knot.param_overwrite_widget(true); + helper_size.param_set_range(0, 999); + helper_size.param_set_increments(1, 1); + helper_size.param_set_digits(0); + offset.param_set_range(-999999.0, 999999.0); + offset.param_set_increments(1, 1); + offset.param_set_digits(2); + strech.param_set_range(0, 999.0); + strech.param_set_increments(0.01, 0.01); + strech.param_set_digits(4); +} + +LPETransform2Pts::~LPETransform2Pts() +{ +} + +void +LPETransform2Pts::doOnApply(SPLPEItem const* lpeitem) +{ + using namespace Geom; + original_bbox(lpeitem); + + point_a = Point(boundingbox_X.min(), boundingbox_Y.middle()); + point_b = Point(boundingbox_X.max(), boundingbox_Y.middle()); + SPLPEItem * splpeitem = const_cast<SPLPEItem *>(lpeitem); + SPPath *sp_path = dynamic_cast<SPPath *>(splpeitem); + if (sp_path) { + pathvector = sp_path->get_original_curve()->get_pathvector(); + } + if(!pathvector.empty()) { + point_a = pathvector.initialPoint(); + point_b = pathvector.finalPoint(); + if(are_near(point_a,point_b)) { + point_b = pathvector.back().finalCurve().initialPoint(); + } + size_t nnodes = nodeCount(pathvector); + last_knot.param_set_value(nnodes); + } + + previous_lenght = Geom::distance(point_a,point_b); + Geom::Ray transformed(point_a,point_b); + previous_angle = transformed.angle(); + start.param_update_default(point_a); + start.param_set_default(); + end.param_update_default(point_b); + end.param_set_default(); +} + +void +LPETransform2Pts::doBeforeEffect (SPLPEItem const* lpeitem) +{ + using namespace Geom; + original_bbox(lpeitem); + point_a = Point(boundingbox_X.min(), boundingbox_Y.middle()); + point_b = Point(boundingbox_X.max(), boundingbox_Y.middle()); + + SPLPEItem * splpeitem = const_cast<SPLPEItem *>(lpeitem); + SPPath *sp_path = dynamic_cast<SPPath *>(splpeitem); + if (sp_path) { + pathvector = sp_path->get_original_curve()->get_pathvector(); + } + if(from_original_width_toggler != from_original_width) { + from_original_width_toggler = from_original_width; + reset(); + } + if(!pathvector.empty() && !from_original_width) { + append_path = false; + point_a = pointAtNodeIndex(pathvector,(size_t)first_knot-1); + point_b = pointAtNodeIndex(pathvector,(size_t)last_knot-1); + size_t nnodes = nodeCount(pathvector); + first_knot.param_set_range(1, last_knot-1); + last_knot.param_set_range(first_knot+1, nnodes); + from_original_width.param_setValue(false); + } else { + first_knot.param_set_value(1); + last_knot.param_set_value(2); + first_knot.param_set_range(1,1); + last_knot.param_set_range(2,2); + from_original_width.param_setValue(true); + append_path = false; + } + if(lock_lenght && !lock_angle && previous_lenght != -1) { + Geom::Ray transformed((Geom::Point)start,(Geom::Point)end); + if(previous_start == start || previous_angle == Geom::deg_to_rad(0)) { + previous_angle = transformed.angle(); + } + } else if(lock_angle && !lock_lenght && previous_angle != Geom::deg_to_rad(0)) { + if(previous_start == start){ + previous_lenght = Geom::distance((Geom::Point)start, (Geom::Point)end); + } + } + if(lock_lenght || lock_angle ) { + Geom::Point end_point = Geom::Point::polar(previous_angle, previous_lenght) + (Geom::Point)start; + end.param_setValue(end_point); + } + Geom::Ray transformed((Geom::Point)start,(Geom::Point)end); + previous_angle = transformed.angle(); + previous_lenght = Geom::distance((Geom::Point)start, (Geom::Point)end); + previous_start = start; + splpeitem->apply_to_clippath(splpeitem); + splpeitem->apply_to_mask(splpeitem); +} + +void +LPETransform2Pts::updateIndex() +{ + SPLPEItem * splpeitem = const_cast<SPLPEItem *>(sp_lpe_item); + SPPath *sp_path = dynamic_cast<SPPath *>(splpeitem); + if (sp_path) { + pathvector = sp_path->get_original_curve()->get_pathvector(); + } + if(pathvector.empty()) { + return; + } + if(!from_original_width) { + point_a = pointAtNodeIndex(pathvector,(size_t)first_knot-1); + point_b = pointAtNodeIndex(pathvector,(size_t)last_knot-1); + start.param_update_default(point_a); + start.param_set_default(); + end.param_update_default(point_b); + end.param_set_default(); + start.param_update_default(point_a); + end.param_update_default(point_b); + start.param_set_default(); + end.param_set_default(); + } + DocumentUndo::done(getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change index of knot")); +} +//todo migrate to PathVector class? +size_t +LPETransform2Pts::nodeCount(Geom::PathVector pathvector) const +{ + size_t n = 0; + for (Geom::PathVector::iterator it = pathvector.begin(); it != pathvector.end(); ++it) { + n += it->size_closed(); + } + return n; +} +//todo migrate to PathVector class? +Geom::Point +LPETransform2Pts::pointAtNodeIndex(Geom::PathVector pathvector, size_t index) const +{ + size_t n = 0; + for (Geom::PathVector::iterator pv_it = pathvector.begin(); pv_it != pathvector.end(); ++pv_it) { + for (Geom::Path::iterator curve_it = pv_it->begin(); curve_it != pv_it->end_closed(); ++curve_it) { + if(index == n) { + return curve_it->initialPoint(); + } + n++; + } + } + return Geom::Point(); +} +//todo migrate to PathVector class? Not used +Geom::Path +LPETransform2Pts::pathAtNodeIndex(Geom::PathVector pathvector, size_t index) const +{ + size_t n = 0; + for (Geom::PathVector::iterator pv_it = pathvector.begin(); pv_it != pathvector.end(); ++pv_it) { + for (Geom::Path::iterator curve_it = pv_it->begin(); curve_it != pv_it->end_closed(); ++curve_it) { + if(index == n) { + return *pv_it; + } + n++; + } + } + return Geom::Path(); +} + + +void +LPETransform2Pts::reset() +{ + point_a = Geom::Point(boundingbox_X.min(), boundingbox_Y.middle()); + point_b = Geom::Point(boundingbox_X.max(), boundingbox_Y.middle()); + if(!pathvector.empty() && !from_original_width) { + size_t nnodes = nodeCount(pathvector); + first_knot.param_set_range(1, last_knot-1); + last_knot.param_set_range(first_knot+1, nnodes); + first_knot.param_set_value(1); + last_knot.param_set_value(nnodes); + point_a = pathvector.initialPoint(); + point_b = pathvector.finalPoint(); + } else { + first_knot.param_set_value(1); + last_knot.param_set_value(2); + } + Geom::Ray transformed(point_a, point_b); + previous_angle = transformed.angle(); + previous_lenght = Geom::distance(point_a, point_b); + start.param_update_default(point_a); + end.param_update_default(point_b); + start.param_set_default(); + end.param_set_default(); +} + +Gtk::Widget *LPETransform2Pts::newWidget() +{ + // use manage here, because after deletion of Effect object, others might + // still be pointing to this widget. + Gtk::VBox *vbox = Gtk::manage(new Gtk::VBox(Effect::newWidget())); + + vbox->set_border_width(5); + vbox->set_homogeneous(false); + vbox->set_spacing(6); + + std::vector<Parameter *>::iterator it = param_vector.begin(); + Gtk::HBox * button1 = Gtk::manage(new Gtk::HBox(true,0)); + Gtk::HBox * button2 = Gtk::manage(new Gtk::HBox(true,0)); + Gtk::HBox * button3 = Gtk::manage(new Gtk::HBox(true,0)); + Gtk::HBox * button4 = Gtk::manage(new Gtk::HBox(true,0)); + while (it != param_vector.end()) { + if ((*it)->widget_is_visible) { + Parameter *param = *it; + Gtk::Widget *widg = dynamic_cast<Gtk::Widget *>(param->param_newWidget()); + Glib::ustring *tip = param->param_getTooltip(); + if (param->param_key == "first_knot" || param->param_key == "last_knot") { + Inkscape::UI::Widget::Scalar *registered_widget = Gtk::manage(dynamic_cast<Inkscape::UI::Widget::Scalar *>(widg)); + registered_widget->signal_value_changed().connect(sigc::mem_fun(*this, &LPETransform2Pts::updateIndex)); + widg = registered_widget; + if (widg) { + Gtk::HBox *hbox_scalar = dynamic_cast<Gtk::HBox *>(widg); + std::vector<Gtk::Widget *> child_list = hbox_scalar->get_children(); + Gtk::Entry *entry_widget = dynamic_cast<Gtk::Entry *>(child_list[1]); + entry_widget->set_width_chars(3); + vbox->pack_start(*widg, true, true, 2); + if (tip) { + widg->set_tooltip_text(*tip); + } else { + widg->set_tooltip_text(""); + widg->set_has_tooltip(false); + } + } + } else if (param->param_key == "from_original_width" || param->param_key == "elastic") { + Glib::ustring * tip = param->param_getTooltip(); + if (widg) { + button1->pack_start(*widg, true, true, 2); + if (tip) { + widg->set_tooltip_text(*tip); + } else { + widg->set_tooltip_text(""); + widg->set_has_tooltip(false); + } + } + } else if (param->param_key == "flip_horizontal" || param->param_key == "flip_vertical") { + Glib::ustring * tip = param->param_getTooltip(); + if (widg) { + button2->pack_start(*widg, true, true, 2); + if (tip) { + widg->set_tooltip_text(*tip); + } else { + widg->set_tooltip_text(""); + widg->set_has_tooltip(false); + } + } + } else if (param->param_key == "lock_angle" || param->param_key == "lock_lenght") { + Glib::ustring * tip = param->param_getTooltip(); + if (widg) { + button3->pack_start(*widg, true, true, 2); + if (tip) { + widg->set_tooltip_text(*tip); + } else { + widg->set_tooltip_text(""); + widg->set_has_tooltip(false); + } + } + } else if (widg) { + vbox->pack_start(*widg, true, true, 2); + if (tip) { + widg->set_tooltip_text(*tip); + } else { + widg->set_tooltip_text(""); + widg->set_has_tooltip(false); + } + } + } + + ++it; + } + Gtk::Button *reset = Gtk::manage(new Gtk::Button(Glib::ustring(_("Reset")))); + reset->signal_clicked().connect(sigc::mem_fun(*this, &LPETransform2Pts::reset)); + button4->pack_start(*reset, true, true, 2); + vbox->pack_start(*button1, true, true, 2); + vbox->pack_start(*button2, true, true, 2); + vbox->pack_start(*button3, true, true, 2); + vbox->pack_start(*button4, true, true, 2); + return dynamic_cast<Gtk::Widget *>(vbox); +} + +Geom::Piecewise<Geom::D2<Geom::SBasis> > +LPETransform2Pts::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in) +{ + Geom::Piecewise<Geom::D2<Geom::SBasis> > output; + double sca = Geom::distance((Geom::Point)start,(Geom::Point)end)/Geom::distance(point_a,point_b); + Geom::Ray original(point_a,point_b); + Geom::Ray transformed((Geom::Point)start,(Geom::Point)end); + double rot = transformed.angle() - original.angle(); + Geom::Path helper; + helper.start(point_a); + helper.appendNew<Geom::LineSegment>(point_b); + Geom::Affine m; + Geom::Angle original_angle = original.angle(); + if(flip_horizontal && flip_vertical){ + m *= Geom::Rotate(-original_angle); + m *= Geom::Scale(-1,-1); + m *= Geom::Rotate(original_angle); + } else if(flip_vertical){ + m *= Geom::Rotate(-original_angle); + m *= Geom::Scale(1,-1); + m *= Geom::Rotate(original_angle); + } else if(flip_horizontal){ + m *= Geom::Rotate(-original_angle); + m *= Geom::Scale(-1,1); + m *= Geom::Rotate(original_angle); + } + if(strech != 1){ + m *= Geom::Rotate(-original_angle); + m *= Geom::Scale(1,strech); + m *= Geom::Rotate(original_angle); + } + if(elastic) { + m *= Geom::Rotate(-original_angle); + if(sca > 1){ + m *= Geom::Scale(sca, 1.0); + } else { + m *= Geom::Scale(sca, 1.0-((1.0-sca)/2.0)); + } + m *= Geom::Rotate(transformed.angle()); + } else { + m *= Geom::Scale(sca); + m *= Geom::Rotate(rot); + } + helper *= m; + Geom::Point trans = (Geom::Point)start - helper.initialPoint(); + if(flip_horizontal){ + trans = (Geom::Point)end - helper.initialPoint(); + } + if(offset != 0){ + trans = Geom::Point::polar(transformed.angle() + Geom::deg_to_rad(-90),offset) + trans; + } + m *= Geom::Translate(trans); + + output.concat(pwd2_in * m); + + return output; +} + +void +LPETransform2Pts::addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector<Geom::PathVector> &hp_vec) +{ + using namespace Geom; + hp_vec.clear(); + Geom::Path hp; + hp.start((Geom::Point)start); + hp.appendNew<Geom::LineSegment>((Geom::Point)end); + Geom::PathVector pathv; + pathv.push_back(hp); + double r = helper_size*.1; + if(lock_lenght || lock_angle ) { + char const * svgd; + svgd = "M -5.39,8.78 -9.13,5.29 -10.38,10.28 Z M -7.22,7.07 -3.43,3.37 m -1.95,-12.16 -3.74,3.5 -1.26,-5 z m -1.83,1.71 3.78,3.7 M 5.24,8.78 8.98,5.29 10.24,10.28 Z M 7.07,7.07 3.29,3.37 M 5.24,-8.78 l 3.74,3.5 1.26,-5 z M 7.07,-7.07 3.29,-3.37"; + PathVector pathv_move = sp_svg_read_pathv(svgd); + pathv_move *= Affine(r,0,0,r,0,0) * Translate(Geom::Point(start)); + hp_vec.push_back(pathv_move); + } + if(!lock_angle && lock_lenght) { + char const * svgd; + svgd = "m 7.07,7.07 c -3.9,3.91 -10.24,3.91 -14.14,0 -3.91,-3.9 -3.91,-10.24 0,-14.14 3.9,-3.91 10.24,-3.91 14.14,0 l -2.83,-4.24 -0.7,2.12"; + PathVector pathv_turn = sp_svg_read_pathv(svgd); + pathv_turn *= Geom::Rotate(previous_angle); + pathv_turn *= Affine(r,0,0,r,0,0) * Translate(Geom::Point(end)); + hp_vec.push_back(pathv_turn); + } + hp_vec.push_back(pathv); +} + + +/* ######################## */ + +} //namespace LivePathEffect +} /* namespace Inkscape */ + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/live_effects/lpe-transform_2pts.h b/src/live_effects/lpe-transform_2pts.h new file mode 100644 index 000000000..c20d56206 --- /dev/null +++ b/src/live_effects/lpe-transform_2pts.h @@ -0,0 +1,91 @@ +#ifndef INKSCAPE_LPE_TRANSFORM_2PTS_H +#define INKSCAPE_LPE_TRANSFORM_2PTS_H + +/** \file + * LPE "Transform through 2 points" implementation + */ + +/* + * Authors: + * + * + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "live_effects/effect.h" +#include "live_effects/lpegroupbbox.h" +#include "live_effects/parameter/parameter.h" +#include "live_effects/parameter/togglebutton.h" +#include "live_effects/parameter/point.h" + +namespace Inkscape { +namespace LivePathEffect { + +class LPETransform2Pts : public Effect, GroupBBoxEffect { +public: + LPETransform2Pts(LivePathEffectObject *lpeobject); + virtual ~LPETransform2Pts(); + + virtual void doOnApply (SPLPEItem const* lpeitem); + + virtual Geom::Piecewise<Geom::D2<Geom::SBasis> > doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in); + + virtual void doBeforeEffect (SPLPEItem const* lpeitem); + + virtual Gtk::Widget *newWidget(); + + void updateIndex(); + + size_t nodeCount(Geom::PathVector pathvector) const; + + Geom::Point pointAtNodeIndex(Geom::PathVector pathvector, size_t index) const; + + Geom::Path pathAtNodeIndex(Geom::PathVector pathvector, size_t index) const; + + void reset(); + +protected: + virtual void addCanvasIndicators(SPLPEItem const *lpeitem, std::vector<Geom::PathVector> &hp_vec); + +private: + ToggleButtonParam elastic; + ToggleButtonParam from_original_width; + ToggleButtonParam lock_lenght; + ToggleButtonParam lock_angle; + ToggleButtonParam flip_horizontal; + ToggleButtonParam flip_vertical; + PointParam start; + PointParam end; + ScalarParam strech; + ScalarParam offset; + ScalarParam first_knot; + ScalarParam last_knot; + ScalarParam helper_size; + bool from_original_width_toggler; + Geom::Point point_a; + Geom::Point point_b; + Geom::PathVector pathvector; + bool append_path; + Geom::Angle previous_angle; + Geom::Point previous_start; + double previous_lenght; + LPETransform2Pts(const LPETransform2Pts&); + LPETransform2Pts& operator=(const LPETransform2Pts&); +}; + +} //namespace LivePathEffect +} //namespace Inkscape + +#endif + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/live_effects/parameter/bool.cpp b/src/live_effects/parameter/bool.cpp index c1e8f8a7b..9ecadbdeb 100644 --- a/src/live_effects/parameter/bool.cpp +++ b/src/live_effects/parameter/bool.cpp @@ -21,8 +21,8 @@ namespace LivePathEffect { BoolParam::BoolParam( const Glib::ustring& label, const Glib::ustring& tip, const Glib::ustring& key, Inkscape::UI::Widget::Registry* wr, - Effect* effect, bool default_value ) - : Parameter(label, tip, key, wr, effect), value(default_value), defvalue(default_value) + Effect* effect, bool default_value , bool no_widget) + : Parameter(label, tip, key, wr, effect), value(default_value), defvalue(default_value), hide_widget(no_widget) { } @@ -53,20 +53,24 @@ BoolParam::param_getSVGValue() const Gtk::Widget * BoolParam::param_newWidget() { - Inkscape::UI::Widget::RegisteredCheckButton * checkwdg = Gtk::manage( - new Inkscape::UI::Widget::RegisteredCheckButton( param_label, - param_tooltip, - param_key, - *param_wr, - false, - param_effect->getRepr(), - param_effect->getSPDoc()) ); + if(!hide_widget){ + Inkscape::UI::Widget::RegisteredCheckButton * checkwdg = Gtk::manage( + new Inkscape::UI::Widget::RegisteredCheckButton( param_label, + param_tooltip, + param_key, + *param_wr, + false, + param_effect->getRepr(), + param_effect->getSPDoc()) ); - checkwdg->setActive(value); - checkwdg->setProgrammatically = false; - checkwdg->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change bool parameter")); + checkwdg->setActive(value); + checkwdg->setProgrammatically = false; + checkwdg->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change bool parameter")); - return dynamic_cast<Gtk::Widget *> (checkwdg); + return dynamic_cast<Gtk::Widget *> (checkwdg); + } else { + return NULL; + } } void diff --git a/src/live_effects/parameter/bool.h b/src/live_effects/parameter/bool.h index b45eeb0b3..403dd0b87 100644 --- a/src/live_effects/parameter/bool.h +++ b/src/live_effects/parameter/bool.h @@ -25,7 +25,8 @@ public: const Glib::ustring& key, Inkscape::UI::Widget::Registry* wr, Effect* effect, - bool default_value = false); + bool default_value = false, + bool no_widget = false); virtual ~BoolParam(); virtual Gtk::Widget * param_newWidget(); @@ -46,6 +47,7 @@ private: bool value; bool defvalue; + bool hide_widget; }; diff --git a/src/live_effects/parameter/filletchamferpointarray.cpp b/src/live_effects/parameter/filletchamferpointarray.cpp index b089213fd..399307502 100644 --- a/src/live_effects/parameter/filletchamferpointarray.cpp +++ b/src/live_effects/parameter/filletchamferpointarray.cpp @@ -159,9 +159,8 @@ void FilletChamferPointArrayParam::recalculate_controlpoints_for_new_pwd2( //todo: if the path remove some nodes whith the result of a straight //line but with handles, the node inserted into dont fire the knot // because is not handle as cusp node by get_nodetype function - bool this_is_line = true; bool next_is_line = is_straight_curve(*curve_it1); - this_is_line = is_straight_curve((*path_it)[counterCurves - 1]); + bool this_is_line = is_straight_curve((*path_it)[counterCurves - 1]); nodetype = get_nodetype((*path_it)[counterCurves - 1], *curve_it1); if (this_is_line || next_is_line) { nodetype = NODE_CUSP; @@ -307,9 +306,8 @@ void FilletChamferPointArrayParam::recalculate_knots( nodetype = NODE_NONE; } } else { - bool this_is_line = true; bool next_is_line = is_straight_curve(*curve_it1); - this_is_line = is_straight_curve((*path_it)[counterCurves - 1]); + bool this_is_line = is_straight_curve((*path_it)[counterCurves - 1]); nodetype = get_nodetype((*path_it)[counterCurves - 1], *curve_it1); if (this_is_line || next_is_line) { nodetype = NODE_CUSP; @@ -467,12 +465,12 @@ double FilletChamferPointArrayParam::len_to_rad(int index, double len) Geom::Point endArcPoint = B->toSBasis().valueAt(times[2]); Curve *knotCurve1 = A->portion(times[0], times[1]); Curve *knotCurve2 = B->portion(times[2], 1); - Geom::CubicBezier const *cubic1 = dynamic_cast<Geom::CubicBezier const *>(&*knotCurve1); + Geom::CubicBezier const *cubic1 = dynamic_cast<Geom::CubicBezier const *>(knotCurve1); Ray ray1(startArcPoint, A->finalPoint()); if (cubic1) { ray1.setPoints((*cubic1)[2], startArcPoint); } - Geom::CubicBezier const *cubic2 = dynamic_cast<Geom::CubicBezier const *>(&*knotCurve2); + Geom::CubicBezier const *cubic2 = dynamic_cast<Geom::CubicBezier const *>(knotCurve2); Ray ray2(B->initialPoint(), endArcPoint); if (cubic2) { ray2.setPoints(endArcPoint, (*cubic2)[1]); diff --git a/src/live_effects/parameter/originalpatharray.cpp b/src/live_effects/parameter/originalpatharray.cpp index 78e061e66..7e3a6f5fe 100644 --- a/src/live_effects/parameter/originalpatharray.cpp +++ b/src/live_effects/parameter/originalpatharray.cpp @@ -215,7 +215,7 @@ void OriginalPathArrayParam::on_up_button_click() int i = -1; std::vector<PathAndDirection*>::iterator piter = _vector.begin(); - for (std::vector<PathAndDirection*>::iterator iter = _vector.begin(); iter != _vector.end(); piter = iter, i++, iter++) { + for (std::vector<PathAndDirection*>::iterator iter = _vector.begin(); iter != _vector.end(); piter = iter, i++, ++iter) { if (*iter == row[_model->_colObject]) { _vector.erase(iter); _vector.insert(piter, row[_model->_colObject]); @@ -241,11 +241,11 @@ void OriginalPathArrayParam::on_down_button_click() Gtk::TreeModel::Row row = *iter; int i = 0; - for (std::vector<PathAndDirection*>::iterator iter = _vector.begin(); iter != _vector.end(); i++, iter++) { + for (std::vector<PathAndDirection*>::iterator iter = _vector.begin(); iter != _vector.end(); i++, ++iter) { if (*iter == row[_model->_colObject]) { std::vector<PathAndDirection*>::iterator niter = _vector.erase(iter); if (niter != _vector.end()) { - niter++; + ++niter; i++; } _vector.insert(niter, row[_model->_colObject]); @@ -295,7 +295,7 @@ OriginalPathArrayParam::on_link_button_click() Inkscape::SVGOStringStream os; bool foundOne = false; - for (std::vector<PathAndDirection*>::const_iterator iter = _vector.begin(); iter != _vector.end(); iter++) { + for (std::vector<PathAndDirection*>::const_iterator iter = _vector.begin(); iter != _vector.end(); ++iter) { if (foundOne) { os << "|"; } else { @@ -330,7 +330,7 @@ void OriginalPathArrayParam::unlink(PathAndDirection* to) void OriginalPathArrayParam::remove_link(PathAndDirection* to) { unlink(to); - for (std::vector<PathAndDirection*>::iterator iter = _vector.begin(); iter != _vector.end(); iter++) { + for (std::vector<PathAndDirection*>::iterator iter = _vector.begin(); iter != _vector.end(); ++iter) { if (*iter == to) { PathAndDirection *w = *iter; _vector.erase(iter); @@ -455,7 +455,7 @@ gchar * OriginalPathArrayParam::param_getSVGValue() const { Inkscape::SVGOStringStream os; bool foundOne = false; - for (std::vector<PathAndDirection*>::const_iterator iter = _vector.begin(); iter != _vector.end(); iter++) { + for (std::vector<PathAndDirection*>::const_iterator iter = _vector.begin(); iter != _vector.end(); ++iter) { if (foundOne) { os << "|"; } else { diff --git a/src/live_effects/parameter/parameter.cpp b/src/live_effects/parameter/parameter.cpp index 527bc06fe..d4e213948 100644 --- a/src/live_effects/parameter/parameter.cpp +++ b/src/live_effects/parameter/parameter.cpp @@ -54,7 +54,7 @@ void Parameter::write_to_SVG(void) */ ScalarParam::ScalarParam( const Glib::ustring& label, const Glib::ustring& tip, const Glib::ustring& key, Inkscape::UI::Widget::Registry* wr, - Effect* effect, gdouble default_value) + Effect* effect, gdouble default_value, bool no_widget) : Parameter(label, tip, key, wr, effect), value(default_value), min(-SCALARPARAM_G_MAXDOUBLE), @@ -64,7 +64,9 @@ ScalarParam::ScalarParam( const Glib::ustring& label, const Glib::ustring& tip, digits(2), inc_step(0.1), inc_page(1), - add_slider(false) + add_slider(false), + overwrite_widget(false), + hide_widget(no_widget) { } @@ -143,24 +145,34 @@ ScalarParam::param_make_integer(bool yes) inc_page = 10; } +void +ScalarParam::param_overwrite_widget(bool overwrite_widget) +{ + this->overwrite_widget = overwrite_widget; +} + Gtk::Widget * ScalarParam::param_newWidget() { - Inkscape::UI::Widget::RegisteredScalar *rsu = Gtk::manage( new Inkscape::UI::Widget::RegisteredScalar( - param_label, param_tooltip, param_key, *param_wr, param_effect->getRepr(), param_effect->getSPDoc() ) ); - - rsu->setValue(value); - rsu->setDigits(digits); - rsu->setIncrements(inc_step, inc_page); - rsu->setRange(min, max); - rsu->setProgrammatically = false; - if (add_slider) { - rsu->addSlider(); + if(!hide_widget){ + Inkscape::UI::Widget::RegisteredScalar *rsu = Gtk::manage( new Inkscape::UI::Widget::RegisteredScalar( + param_label, param_tooltip, param_key, *param_wr, param_effect->getRepr(), param_effect->getSPDoc() ) ); + + rsu->setValue(value); + rsu->setDigits(digits); + rsu->setIncrements(inc_step, inc_page); + rsu->setRange(min, max); + rsu->setProgrammatically = false; + if (add_slider) { + rsu->addSlider(); + } + if(!overwrite_widget){ + rsu->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change scalar parameter")); + } + return dynamic_cast<Gtk::Widget *> (rsu); + } else { + return NULL; } - - rsu->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change scalar parameter")); - - return dynamic_cast<Gtk::Widget *> (rsu); } void diff --git a/src/live_effects/parameter/parameter.h b/src/live_effects/parameter/parameter.h index cc2c4f3d6..0ef28650a 100644 --- a/src/live_effects/parameter/parameter.h +++ b/src/live_effects/parameter/parameter.h @@ -102,7 +102,8 @@ public: const Glib::ustring& key, Inkscape::UI::Widget::Registry* wr, Effect* effect, - gdouble default_value = 1.0); + gdouble default_value = 1.0, + bool no_widget = false); virtual ~ScalarParam(); virtual bool param_readSVGValue(const gchar * strvalue); @@ -117,6 +118,7 @@ public: void addSlider(bool add_slider_widget) { add_slider = add_slider_widget; }; + void param_overwrite_widget(bool overwrite_widget); virtual Gtk::Widget * param_newWidget(); inline operator gdouble() const { return value; }; @@ -131,6 +133,8 @@ protected: double inc_step; double inc_page; bool add_slider; + bool overwrite_widget; + bool hide_widget; private: ScalarParam(const ScalarParam&); diff --git a/src/live_effects/parameter/togglebutton.cpp b/src/live_effects/parameter/togglebutton.cpp index c5da8b858..47a8b5615 100644 --- a/src/live_effects/parameter/togglebutton.cpp +++ b/src/live_effects/parameter/togglebutton.cpp @@ -119,6 +119,10 @@ ToggleButtonParam::param_newWidget() void ToggleButtonParam::refresh_button() { + if (!_toggled_connection.connected()) { + return; + } + if(!checkwdg){ return; } diff --git a/src/live_effects/spiro-converters.cpp b/src/live_effects/spiro-converters.cpp index f116d5256..ee214704c 100644 --- a/src/live_effects/spiro-converters.cpp +++ b/src/live_effects/spiro-converters.cpp @@ -21,43 +21,49 @@ namespace Spiro {
void
-ConverterSPCurve::moveto(double x, double y, bool is_open)
+ConverterSPCurve::moveto(double x, double y)
{
if ( IS_FINITE(x) && IS_FINITE(y) ) {
_curve.moveto(x, y);
- if (!is_open) {
- _curve.closepath();
- }
} else {
SPIRO_G_MESSAGE("Spiro: moveto not finite");
}
}
void
-ConverterSPCurve::lineto(double x, double y)
+ConverterSPCurve::lineto(double x, double y, bool close_last)
{
if ( IS_FINITE(x) && IS_FINITE(y) ) {
_curve.lineto(x, y);
+ if (close_last) {
+ _curve.closepath();
+ }
} else {
SPIRO_G_MESSAGE("Spiro: lineto not finite");
}
}
void
-ConverterSPCurve::quadto(double xm, double ym, double x3, double y3)
+ConverterSPCurve::quadto(double xm, double ym, double x3, double y3, bool close_last)
{
if ( IS_FINITE(xm) && IS_FINITE(ym) && IS_FINITE(x3) && IS_FINITE(y3) ) {
_curve.quadto(xm, ym, x3, y3);
+ if (close_last) {
+ _curve.closepath();
+ }
} else {
SPIRO_G_MESSAGE("Spiro: quadto not finite");
}
}
void
-ConverterSPCurve::curveto(double x1, double y1, double x2, double y2, double x3, double y3)
+ConverterSPCurve::curveto(double x1, double y1, double x2, double y2, double x3, double y3, bool close_last)
{
if ( IS_FINITE(x1) && IS_FINITE(y1) && IS_FINITE(x2) && IS_FINITE(y2) ) {
_curve.curveto(x1, y1, x2, y2, x3, y3);
+ if (close_last) {
+ _curve.closepath();
+ }
} else {
SPIRO_G_MESSAGE("Spiro: curveto not finite");
}
@@ -71,41 +77,43 @@ ConverterPath::ConverterPath(Geom::Path &path) }
void
-ConverterPath::moveto(double x, double y, bool is_open)
+ConverterPath::moveto(double x, double y)
{
if ( IS_FINITE(x) && IS_FINITE(y) ) {
_path.start(Geom::Point(x, y));
- _path.close(!is_open);
} else {
SPIRO_G_MESSAGE("spiro moveto not finite");
}
}
void
-ConverterPath::lineto(double x, double y)
+ConverterPath::lineto(double x, double y, bool close_last)
{
if ( IS_FINITE(x) && IS_FINITE(y) ) {
_path.appendNew<Geom::LineSegment>( Geom::Point(x, y) );
+ _path.close(close_last);
} else {
SPIRO_G_MESSAGE("spiro lineto not finite");
}
}
void
-ConverterPath::quadto(double xm, double ym, double x3, double y3)
+ConverterPath::quadto(double xm, double ym, double x3, double y3, bool close_last)
{
if ( IS_FINITE(xm) && IS_FINITE(ym) && IS_FINITE(x3) && IS_FINITE(y3) ) {
_path.appendNew<Geom::QuadraticBezier>(Geom::Point(xm, ym), Geom::Point(x3, y3));
+ _path.close(close_last);
} else {
SPIRO_G_MESSAGE("spiro quadto not finite");
}
}
void
-ConverterPath::curveto(double x1, double y1, double x2, double y2, double x3, double y3)
+ConverterPath::curveto(double x1, double y1, double x2, double y2, double x3, double y3, bool close_last)
{
if ( IS_FINITE(x1) && IS_FINITE(y1) && IS_FINITE(x2) && IS_FINITE(y2) ) {
_path.appendNew<Geom::CubicBezier>(Geom::Point(x1, y1), Geom::Point(x2, y2), Geom::Point(x3, y3));
+ _path.close(close_last);
} else {
SPIRO_G_MESSAGE("spiro curveto not finite");
}
diff --git a/src/live_effects/spiro-converters.h b/src/live_effects/spiro-converters.h index 90855d2d6..6182a5dcd 100644 --- a/src/live_effects/spiro-converters.h +++ b/src/live_effects/spiro-converters.h @@ -11,10 +11,10 @@ public: ConverterBase() {}; virtual ~ConverterBase() {}; - virtual void moveto(double x, double y, bool is_open) = 0; - virtual void lineto(double x, double y) = 0; - virtual void quadto(double x1, double y1, double x2, double y2) = 0; - virtual void curveto(double x1, double y1, double x2, double y2, double x3, double y3) = 0; + virtual void moveto(double x, double y) = 0; + virtual void lineto(double x, double y, bool close_last) = 0; + virtual void quadto(double x1, double y1, double x2, double y2, bool close_last) = 0; + virtual void curveto(double x1, double y1, double x2, double y2, double x3, double y3, bool close_last) = 0; }; @@ -27,10 +27,10 @@ public: : _curve(curve) {} - virtual void moveto(double x, double y, bool is_open); - virtual void lineto(double x, double y); - virtual void quadto(double x1, double y1, double x2, double y2); - virtual void curveto(double x1, double y1, double x2, double y2, double x3, double y3); + virtual void moveto(double x, double y); + virtual void lineto(double x, double y, bool close_last); + virtual void quadto(double x1, double y1, double x2, double y2, bool close_last); + virtual void curveto(double x1, double y1, double x2, double y2, double x3, double y3, bool close_last); private: SPCurve &_curve; @@ -47,10 +47,10 @@ class ConverterPath : public ConverterBase { public: ConverterPath(Geom::Path &path); - virtual void moveto(double x, double y, bool is_open); - virtual void lineto(double x, double y); - virtual void quadto(double x1, double y1, double x2, double y2); - virtual void curveto(double x1, double y1, double x2, double y2, double x3, double y3); + virtual void moveto(double x, double y); + virtual void lineto(double x, double y, bool close_last); + virtual void quadto(double x1, double y1, double x2, double y2, bool close_last); + virtual void curveto(double x1, double y1, double x2, double y2, double x3, double y3, bool close_last); private: Geom::Path &_path; diff --git a/src/live_effects/spiro.cpp b/src/live_effects/spiro.cpp index 46e53a0da..0ac2815bf 100644 --- a/src/live_effects/spiro.cpp +++ b/src/live_effects/spiro.cpp @@ -847,13 +847,13 @@ solve_spiro(spiro_seg *s, const int nseg) static void spiro_seg_to_otherpath(const double ks[4], double x0, double y0, double x1, double y1, - ConverterBase &bc, int depth) + ConverterBase &bc, int depth, bool close_last) { double bend = fabs(ks[0]) + fabs(.5 * ks[1]) + fabs(.125 * ks[2]) + fabs((1./48) * ks[3]); if (!(bend > 1e-8)) { - bc.lineto(x1, y1); + bc.lineto(x1, y1, close_last); } else { double seg_ch = hypot(x1 - x0, y1 - y0); double seg_th = atan2(y1 - y0, x1 - x0); @@ -876,7 +876,7 @@ spiro_seg_to_otherpath(const double ks[4], vl = (scale * (1./3)) * sin(th_even - th_odd); ur = (scale * (1./3)) * cos(th_even + th_odd); vr = (scale * (1./3)) * sin(th_even + th_odd); - bc.curveto(x0 + ul, y0 + vl, x1 - ur, y1 - vr, x1, y1); + bc.curveto(x0 + ul, y0 + vl, x1 - ur, y1 - vr, x1, y1, close_last); } else { /* subdivide */ double ksub[4]; @@ -895,11 +895,11 @@ spiro_seg_to_otherpath(const double ks[4], integrate_spiro(ksub, xysub); xmid = x0 + cth * xysub[0] - sth * xysub[1]; ymid = y0 + cth * xysub[1] + sth * xysub[0]; - spiro_seg_to_otherpath(ksub, x0, y0, xmid, ymid, bc, depth + 1); + spiro_seg_to_otherpath(ksub, x0, y0, xmid, ymid, bc, depth + 1, false); ksub[0] += .25 * ks[1] + (1./384) * ks[3]; ksub[1] += .125 * ks[2]; ksub[2] += (1./16) * ks[3]; - spiro_seg_to_otherpath(ksub, xmid, ymid, x1, y1, bc, depth + 1); + spiro_seg_to_otherpath(ksub, xmid, ymid, x1, y1, bc, depth + 1, close_last); } } } @@ -933,9 +933,10 @@ spiro_to_otherpath(const spiro_seg *s, int n, ConverterBase &bc) double y1 = s[i + 1].y; if (i == 0) { - bc.moveto(x0, y0, s[0].ty == '{'); + bc.moveto(x0, y0); } - spiro_seg_to_otherpath(s[i].ks, x0, y0, x1, y1, bc, 0); + // on the last segment, set the 'close_last' flag if path is closed + spiro_seg_to_otherpath(s[i].ks, x0, y0, x1, y1, bc, 0, (nsegs == n) && (i == n - 1)); } } diff --git a/src/main.cpp b/src/main.cpp index 26c25af02..840643a90 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -212,7 +212,7 @@ static gboolean sp_export_id_only = FALSE; static gchar *sp_export_svg = NULL; static gchar *sp_export_ps = NULL; static gchar *sp_export_eps = NULL; -static gint sp_export_ps_level = 2; +static gint sp_export_ps_level = 3; static gchar *sp_export_pdf = NULL; static gchar *sp_export_pdf_version = NULL; static gchar *sp_export_emf = NULL; @@ -260,7 +260,7 @@ static void resetCommandlineGlobals() { sp_export_svg = NULL; sp_export_ps = NULL; sp_export_eps = NULL; - sp_export_ps_level = 2; + sp_export_ps_level = 3; sp_export_pdf = NULL; sp_export_pdf_version = NULL; sp_export_emf = NULL; @@ -405,7 +405,7 @@ struct poptOption options[] = { {"export-ps-level", 0, POPT_ARG_INT, &sp_export_ps_level, SP_ARG_EXPORT_PS_LEVEL, N_("Choose the PostScript Level used to export. Possible choices are" - " 2 (the default) and 3"), + " 2 and 3 (the default)"), N_("PS Level")}, {"export-pdf", 'A', @@ -1045,6 +1045,10 @@ sp_main_gui(int argc, char const **argv) gchar *usericondir = Inkscape::Application::profile_path("icons"); gtk_icon_theme_append_search_path(gtk_icon_theme_get_default(), usericondir); gtk_icon_theme_append_search_path(gtk_icon_theme_get_default(), INKSCAPE_PIXMAPDIR); +#ifdef INKSCAPE_THEMEDIR + gtk_icon_theme_append_search_path(gtk_icon_theme_get_default(), INKSCAPE_THEMEDIR); + gtk_icon_theme_rescan_if_needed (gtk_icon_theme_get_default()); +#endif g_free(usericondir); gdk_event_handler_set((GdkEventFunc)snooper, NULL, NULL); diff --git a/src/menus-skeleton.h b/src/menus-skeleton.h index f5e815bf6..11070d390 100644 --- a/src/menus-skeleton.h +++ b/src/menus-skeleton.h @@ -1,7 +1,9 @@ #ifndef SEEN_MENUS_SKELETON_H #define SEEN_MENUS_SKELETON_H -#include "config.h" +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif #ifdef __cplusplus #undef N_ @@ -84,6 +86,7 @@ static char const menus_skeleton[] = " <verb verb-id=\"EditInvert\" />\n" " <verb verb-id=\"EditDeselect\" />\n" " <separator/>\n" +" <verb verb-id=\"EditGuidesToggleLock\" check=\"yes\" />\n" " <verb verb-id=\"EditGuidesAroundPage\" />\n" " <verb verb-id=\"EditRemoveAllGuides\" />\n" " <separator/>\n" @@ -221,7 +224,11 @@ static char const menus_skeleton[] = " <submenu name=\"" N_("_Path") "\">\n" " <verb verb-id=\"ObjectToPath\" />\n" " <verb verb-id=\"StrokeToPath\" />\n" + +#if HAVE_POTRACE " <verb verb-id=\"SelectionTrace\" />\n" +#endif + " <verb verb-id=\"SelectionPixelArt\" />\n" " <separator/>\n" " <verb verb-id=\"SelectionUnion\" />\n" @@ -284,7 +291,9 @@ static char const menus_skeleton[] = " <verb verb-id=\"TutorialsBasic\" />\n" " <verb verb-id=\"TutorialsShapes\" />\n" " <verb verb-id=\"TutorialsAdvanced\" />\n" +#if HAVE_POTRACE " <verb verb-id=\"TutorialsTracing\" />\n" +#endif " <verb verb-id=\"TutorialsTracingPixelArt\" />\n" " <verb verb-id=\"TutorialsCalligraphy\" />\n" " <verb verb-id=\"TutorialsInterpolate\" />\n" diff --git a/src/object-snapper.cpp b/src/object-snapper.cpp index 634d56aa6..5b7874c61 100644 --- a/src/object-snapper.cpp +++ b/src/object-snapper.cpp @@ -239,7 +239,7 @@ void Inkscape::ObjectSnapper::_collectNodes(SnapSourceType const &t, bool old_pref2 = _snapmanager->snapprefs.isTargetSnappable(SNAPTARGET_ROTATION_CENTER); if (old_pref2) { std::vector<SPItem*> rotationSource=_snapmanager->getRotationCenterSource(); - for ( std::vector<SPItem*>::const_iterator itemlist = rotationSource.begin(); itemlist != rotationSource.end(); itemlist++) { + for ( std::vector<SPItem*>::const_iterator itemlist = rotationSource.begin(); itemlist != rotationSource.end(); ++itemlist) { if ((*i).item == *itemlist) { // don't snap to this item's rotation center _snapmanager->snapprefs.setTargetSnappable(SNAPTARGET_ROTATION_CENTER, false); @@ -637,7 +637,6 @@ void Inkscape::ObjectSnapper::_snapPathsConstrained(IntermSnapResults &isr, constraint_line.appendNew<Geom::LineSegment>(p_max_on_cl); constraint_path.push_back(constraint_line); } - // Length of constraint_path will always be one bool strict_snapping = _snapmanager->snapprefs.getStrictSnapping(); @@ -646,45 +645,15 @@ void Inkscape::ObjectSnapper::_snapPathsConstrained(IntermSnapResults &isr, for (std::vector<SnapCandidatePath >::const_iterator k = _paths_to_snap_to->begin(); k != _paths_to_snap_to->end(); ++k) { if (k->path_vector && _allowSourceToSnapToTarget(p.getSourceType(), (*k).target_type, strict_snapping)) { // Do the intersection math - Geom::CrossingSet cs = Geom::crossings(constraint_path, *(k->path_vector)); - // Store the results as intersection points - unsigned int index = 0; - for (Geom::CrossingSet::const_iterator i = cs.begin(); i != cs.end(); ++i) { - if (index >= constraint_path.size()) { - break; - } - // Reconstruct and store the points of intersection - for (Geom::Crossings::const_iterator m = (*i).begin(); m != (*i).end(); ++m) { - intersections.push_back(constraint_path[index].pointAt((*m).ta)); - } - index++; - } - - //Geom::crossings will not consider the closing segment apparently, so we'll handle that separately here - //TODO: This should have been fixed in rev. #9859, which makes this workaround obsolete - for(Geom::PathVector::iterator it_pv = k->path_vector->begin(); it_pv != k->path_vector->end(); ++it_pv) { - if (it_pv->closed()) { - // Get the closing linesegment and convert it to a path - Geom::Path cls; - cls.close(false); - cls.append(it_pv->back_closed()); - // Intersect that closing path with the constrained path - Geom::Crossings cs = Geom::crossings(constraint_path.front(), cls); - // Reconstruct and store the points of intersection - index = 0; // assuming the constraint path vector has only one path - for (Geom::Crossings::const_iterator m = cs.begin(); m != cs.end(); ++m) { - intersections.push_back(constraint_path[index].pointAt((*m).ta)); - } - } - } + std::vector<Geom::PVIntersection> inters = constraint_path.intersect(*(k->path_vector)); - // Convert the collected points of intersection to snapped points - for (std::vector<Geom::Point>::iterator p_inters = intersections.begin(); p_inters != intersections.end(); ++p_inters) { + // Convert the collected intersections to snapped points + for (std::vector<Geom::PVIntersection>::const_iterator i = inters.begin(); i != inters.end(); ++i) { // Convert to desktop coordinates - (*p_inters) = dt->doc2dt(*p_inters); + Geom::Point p_inters = dt->doc2dt(i->point()); // 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, false, k->target_bbox); + 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, 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); diff --git a/src/path-chemistry.cpp b/src/path-chemistry.cpp index 7bd5b6298..7b52ac2e1 100644 --- a/src/path-chemistry.cpp +++ b/src/path-chemistry.cpp @@ -71,14 +71,14 @@ sp_selected_path_combine(SPDesktop *desktop) items = sp_degroup_list (items); // descend into any groups in selection std::vector<SPItem*> to_paths; - for (std::vector<SPItem*>::const_reverse_iterator i = items.rbegin(); i != items.rend(); i++) { + for (std::vector<SPItem*>::const_reverse_iterator i = items.rbegin(); i != items.rend(); ++i) { if (!dynamic_cast<SPPath *>(*i) && !dynamic_cast<SPGroup *>(*i)) { to_paths.push_back(*i); } } std::vector<Inkscape::XML::Node*> converted; bool did = sp_item_list_to_curves(to_paths, items, converted); - for (std::vector<Inkscape::XML::Node*>::const_iterator i = converted.begin(); i != converted.end(); i++) + for (std::vector<Inkscape::XML::Node*>::const_iterator i = converted.begin(); i != converted.end(); ++i) items.push_back((SPItem*)doc->getObjectByRepr(*i)); items = sp_degroup_list (items); // converting to path may have added more groups, descend again @@ -101,7 +101,7 @@ sp_selected_path_combine(SPDesktop *desktop) selection->clear(); } - for (std::vector<SPItem*>::const_reverse_iterator i = items.rbegin(); i != items.rend(); i++){ + for (std::vector<SPItem*>::const_reverse_iterator i = items.rbegin(); i != items.rend(); ++i){ SPItem *item = *i; SPPath *path = dynamic_cast<SPPath *>(item); @@ -204,7 +204,7 @@ sp_selected_path_break_apart(SPDesktop *desktop) bool did = false; std::vector<SPItem*> itemlist(selection->itemList()); - for (std::vector<SPItem*>::const_iterator i = itemlist.begin(); i != itemlist.end(); i++){ + for (std::vector<SPItem*>::const_iterator i = itemlist.begin(); i != itemlist.end(); ++i){ SPItem *item = *i; @@ -354,7 +354,7 @@ bool sp_item_list_to_curves(const std::vector<SPItem*> &items, std::vector<SPItem*>& selected, std::vector<Inkscape::XML::Node*> &to_select, bool skip_all_lpeitems) { bool did = false; - for (std::vector<SPItem*>::const_iterator i = items.begin(); i != items.end(); i++){ + for (std::vector<SPItem*>::const_iterator i = items.begin(); i != items.end(); ++i){ SPItem *item = *i; g_assert(item != NULL); SPDocument *document = item->document; @@ -474,7 +474,13 @@ sp_selected_item_to_curved_repr(SPItem *item, guint32 /*text_grouping_policy*/) // Special treatment for text: convert each glyph to separate path, then group the paths Inkscape::XML::Node *g_repr = xml_doc->createElement("svg:g"); - Glib::ustring original_text; // To save original text of accessibility. + // Save original text for accessibility. + Glib::ustring original_text = sp_te_get_string_multiline( item, + te_get_layout(item)->begin(), + te_get_layout(item)->end() ); + if( original_text.size() > 0 ) { + g_repr->setAttribute("aria-label", original_text.c_str() ); + } g_repr->setAttribute("transform", item->getRepr()->attribute("transform")); /* Mask */ @@ -494,10 +500,8 @@ sp_selected_item_to_curved_repr(SPItem *item, guint32 /*text_grouping_policy*/) item->style->write( SP_STYLE_FLAG_IFDIFF, item->parent ? item->parent->style : NULL); // TODO investigate posibility g_repr->setAttribute("style", style_str.c_str()); - Inkscape::Text::Layout::iterator iter = te_get_layout(item)->begin(); + Inkscape::Text::Layout::iterator iter = te_get_layout(item)->begin(); do { - original_text += (gunichar)te_get_layout(item)->characterAt( iter ); - Inkscape::Text::Layout::iterator iter_next = iter; iter_next.nextGlyph(); // iter_next is one glyph ahead from iter if (iter == iter_next) @@ -538,10 +542,6 @@ sp_selected_item_to_curved_repr(SPItem *item, guint32 /*text_grouping_policy*/) g_repr->appendChild(p_repr); - // For accessibility, store original string - if( original_text.size() > 0 ) { - g_repr->setAttribute("aria-label", original_text.c_str() ); - } Inkscape::GC::release(p_repr); if (iter == te_get_layout(item)->end()) @@ -621,7 +621,7 @@ sp_selected_path_reverse(SPDesktop *desktop) bool did = false; desktop->messageStack()->flash(Inkscape::IMMEDIATE_MESSAGE, _("Reversing paths...")); - for (std::vector<SPItem*>::const_iterator i = items.begin(); i != items.end(); i++){ + for (std::vector<SPItem*>::const_iterator i = items.begin(); i != items.end(); ++i){ SPPath *path = dynamic_cast<SPPath *>(*i); if (!path) { diff --git a/src/path-prefix.h b/src/path-prefix.h index 7042d5124..7f9bcec51 100644 --- a/src/path-prefix.h +++ b/src/path-prefix.h @@ -35,6 +35,7 @@ # define INKSCAPE_PATTERNSDIR BR_DATADIR( "/inkscape/patterns" ) # define INKSCAPE_SCREENSDIR BR_DATADIR( "/inkscape/screens" ) # define INKSCAPE_SYMBOLSDIR BR_DATADIR( "/inkscape/symbols" ) +# define INKSCAPE_THEMEDIR BR_DATADIR( "/icons" ) # define INKSCAPE_TUTORIALSDIR BR_DATADIR( "/inkscape/tutorials" ) # define INKSCAPE_TEMPLATESDIR BR_DATADIR( "/inkscape/templates" ) # define INKSCAPE_UIDIR BR_DATADIR( "/inkscape/ui" ) @@ -102,6 +103,7 @@ # define INKSCAPE_PATTERNSDIR INKSCAPE_DATADIR "/inkscape/patterns" # define INKSCAPE_SCREENSDIR INKSCAPE_DATADIR "/inkscape/screens" # define INKSCAPE_SYMBOLSDIR INKSCAPE_DATADIR "/inkscape/symbols" +# define INKSCAPE_THEMEDIR INKSCAPE_DATADIR "/icons" # define INKSCAPE_TUTORIALSDIR INKSCAPE_DATADIR "/inkscape/tutorials" # define INKSCAPE_TEMPLATESDIR INKSCAPE_DATADIR "/inkscape/templates" # define INKSCAPE_UIDIR INKSCAPE_DATADIR "/inkscape/ui" diff --git a/src/persp3d.cpp b/src/persp3d.cpp index dc0975d12..a48481145 100644 --- a/src/persp3d.cpp +++ b/src/persp3d.cpp @@ -36,10 +36,10 @@ static int global_counter = 0; /* Constructor/destructor for the internal class */ -Persp3DImpl::Persp3DImpl() { - tmat = Proj::TransfMat3x4 (); - document = NULL; - +Persp3DImpl::Persp3DImpl() : + tmat (Proj::TransfMat3x4 ()), + document (NULL) +{ my_counter = global_counter++; } diff --git a/src/pixmaps/cursor-select.xpm b/src/pixmaps/cursor-select.xpm new file mode 100644 index 000000000..569573618 --- /dev/null +++ b/src/pixmaps/cursor-select.xpm @@ -0,0 +1,38 @@ +/* XPM */ +static char const *cursor_select_xpm[] = { +"32 32 3 1", +" c None", +". c #000000", +"+ c #FFFFFF", +". ", +".. ", +".+. ", +".++. ", +".+++. ", +".++++. ", +".+++++. ", +".++++++. ", +".+++++++. ", +".++++++++. ", +".+++++++++. ", +".++++++..... ", +".++++++. ", +".++..++. ", +".+. .+++. ", +".. .++. ", +". .+++. ", +" .+. ", +" .. ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" "}; diff --git a/src/preferences-skeleton.h b/src/preferences-skeleton.h index f4a08b928..b428cbe7a 100644 --- a/src/preferences-skeleton.h +++ b/src/preferences-skeleton.h @@ -269,7 +269,7 @@ static char const preferences_skeleton[] = " <group id=\"zoomcorrection\" value=\"1.0\" unit=\"mm\"/>\n" " <group id=\"keyscroll\" value=\"15\"/>\n" " <group id=\"wheelscroll\" value=\"40\"/>\n" -" <group id=\"spacepans\" value=\"0\"/>\n" +" <group id=\"spacebarpans\" value=\"1\"/>\n" " <group id=\"wheelzooms\" value=\"0\"/>\n" " <group id=\"transientpolicy\" value=\"1\"/>\n" " <group id=\"scrollingacceleration\" value=\"0.4\"/>\n" diff --git a/src/pure-transform.cpp b/src/pure-transform.cpp new file mode 100644 index 000000000..9c7054b9f --- /dev/null +++ b/src/pure-transform.cpp @@ -0,0 +1,359 @@ +/* + * Class for pure transformations, such as translating, scaling, stretching, skewing, and rotating + * + * Authors: + * Diederik van Lierop <mail@diedenrezi.nl> + * + * Copyright (C) 2015 Diederik van Lierop + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "pure-transform.h" +#include "snap.h" + +namespace Inkscape + +{ + +void PureTransform::snap(::SnapManager *sm, std::vector<Inkscape::SnapCandidatePoint> const &points, Geom::Point const &pointer) { + std::vector<Inkscape::SnapCandidatePoint> transformed_points; + Geom::Rect bbox; + + long source_num = 0; + for (std::vector<Inkscape::SnapCandidatePoint>::const_iterator i = points.begin(); i != points.end(); ++i) { + + /* Work out the transformed version of this point */ + Geom::Point transformed = getTransformedPoint(*i); // _transformPoint(*i, transformation_type, transformation, origin, dim, uniform); + + // add the current transformed point to the box hulling all transformed points + if (i == points.begin()) { + bbox = Geom::Rect(transformed, transformed); + } else { + bbox.expandTo(transformed); + } + + transformed_points.push_back(Inkscape::SnapCandidatePoint(transformed, (*i).getSourceType(), source_num, Inkscape::SNAPTARGET_UNDEFINED, Geom::OptRect())); + source_num++; + } + + /* The current best metric for the best transformation; lower is better, whereas Geom::infinity() + ** means that we haven't snapped anything. + */ + Inkscape::SnapCandidatePoint best_original_point; + g_assert(best_snapped_point.getAlwaysSnap() == false); // Check initialization of snapped point + g_assert(best_snapped_point.getAtIntersection() == false); + g_assert(best_snapped_point.getSnapped() == false); // Check initialization to catch any regression + + std::vector<Inkscape::SnapCandidatePoint>::iterator j = transformed_points.begin(); + + // std::cout << std::endl; + bool first_free_snap = true; + + for (std::vector<Inkscape::SnapCandidatePoint>::const_iterator i = points.begin(); i != points.end(); ++i) { + + // If we have a collection of SnapCandidatePoints, with mixed constrained snapping and free snapping + // requirements (this can happen when scaling, see PureScale::snap()), then freeSnap might never see the + // SnapCandidatePoint with source_num == 0. The freeSnap() method in the object snapper depends on this, + // because only for source-num == 0 the target nodes will be collected. Therefore we enforce that the first + // SnapCandidatePoint that is to be freeSnapped always has source_num == 0; + // TODO: This is a bit ugly so fix this; do we need sourcenum for anything else? if we don't then get rid + // of it and explicitly communicate to the object snapper that this is a first point + if (first_free_snap) { + (*j).setSourceNum(0); + first_free_snap = false; + } + Inkscape::SnappedPoint snapped_point = snap(sm, *j, (*i).getPoint(), bbox); // Calls the snap() method of the derived classes + + // std::cout << "dist = " << snapped_point.getSnapDistance() << std::endl; + snapped_point.setPointerDistance(Geom::L2(pointer - (*i).getPoint())); + + /*Find the transformation that describes where the snapped point has + ** ended up, and also the metric for this transformation. + */ + + bool store_best_snap = false; + if (snapped_point.getSnapped()) { + // We snapped; keep track of the best snap + if (best_snapped_point.isOtherSnapBetter(snapped_point, true)) { + store_best_snap = true; + } + } else { + // So we didn't snap for this point + if (!best_snapped_point.getSnapped()) { + // ... and none of the points before snapped either + // We might still need to apply a constraint though, if we tried a constrained snap. And + // in case of a free snap we might have use for the transformed point, so let's return that + // point, whether it's constrained or not + if (best_snapped_point.isOtherSnapBetter(snapped_point, true) || points.size() == 1) { + // .. so we must keep track of the best non-snapped constrained point + store_best_snap = true; + } + } + } + + if (store_best_snap) { + best_original_point = (*i); + best_snapped_point = snapped_point; + } + + ++j; + } + + /* The current best transformation */ + //Geom::Point best_transformation = getResult(best_original_point, best_snapped_point); + storeTransform(best_original_point, best_snapped_point); + + Geom::Coord best_metric = best_snapped_point.getSnapDistance(); + + // Using " < 1e6" instead of " < Geom::infinity()" for catching some rounding errors + // These rounding errors might be caused by NRRects, see bug #1584301 + best_snapped_point.setSnapDistance(best_metric < 1e6 ? best_metric : Geom::infinity()); +} + + + + + +Geom::Point PureTranslate::getTransformedPoint(SnapCandidatePoint const &p) const { + return p.getPoint() + _vector; +} + +void PureTranslate::storeTransform(SnapCandidatePoint const original_point, SnappedPoint const snapped_point) { + /* Consider the case in which a box is almost aligned with a grid in both + * horizontal and vertical directions. The distance to the intersection of + * the grid lines will always be larger then the distance to a single grid + * line. If we prefer snapping to an intersection over to a single + * grid line, then we cannot use "metric = Geom::L2(result)". Therefore the + * snapped distance will be used as a metric. Please note that the snapped + * distance to an intersection is defined as the distance to the nearest line + * of the intersection, and not to the intersection itself! + */ + // Only for translations, the relevant metric will be the real snapped distance, + // so we don't have to do anything special here + _vector_snapped = snapped_point.getPoint() - original_point.getPoint(); +} + +SnappedPoint PureTranslate::snap(::SnapManager *sm, SnapCandidatePoint const &p, Geom::Point /*pt_orig*/, Geom::OptRect const &bbox_to_snap) const { + return sm->freeSnap(p, bbox_to_snap); +} + +SnappedPoint PureTranslateConstrained::snap(::SnapManager *sm, SnapCandidatePoint const &p, Geom::Point pt_orig, Geom::OptRect const &bbox_to_snap) const { + // Calculate a constraint dedicated for this specific point + // When doing a constrained translation, all points will move in the same direction, i.e. + // either horizontally or vertically. The lines along which they move are therefore all + // parallel, but might not be co-linear. Therefore we will have to specify the point through + // which the constraint-line runs here, for each point individually. + Snapper::SnapConstraint dedicated_constraint = Snapper::SnapConstraint(pt_orig, _direction); + return sm->constrainedSnap(p, dedicated_constraint, bbox_to_snap); +} + + + + + +Geom::Point PureScale::getTransformedPoint(SnapCandidatePoint const &p) const { + return (p.getPoint() - _origin) * _scale + _origin; +} + +void PureScale::storeTransform(SnapCandidatePoint const original_point, SnappedPoint snapped_point) { + _scale_snapped = Geom::Scale(Geom::infinity(), Geom::infinity()); + // If this point *i is horizontally or vertically aligned with + // the origin of the scaling, then it will scale purely in X or Y + // We can therefore only calculate the scaling in this direction + // and the scaling factor for the other direction should remain + // untouched (unless scaling is uniform of course) + Geom::Point const a = snapped_point.getPoint() - _origin; // vector to snapped point + Geom::Point const b = original_point.getPoint() - _origin; // vector to original point (not the transformed point!) + for (int index = 0; index < 2; index++) { + if (fabs(b[index]) > 1e-4) { // if SCALING CAN occur in this direction + if (fabs(fabs(a[index]/b[index]) - fabs(_scale[index])) > 1e-7) { // if SNAPPING DID occur in this direction + _scale_snapped[index] = a[index] / b[index]; // then calculate it! + // _scale_snapped will be (1,1) if we haven't snapped, because the snapped point equals the original point + } + // we might have left result[1-index] = Geom::infinity() if scaling didn't occur in the other direction + } + } + if (_uniform) { + // Lock the scaling the be uniform, but keep the sign such that we don't change which quadrant we have dragged into + if (fabs(_scale_snapped[0]) < fabs(_scale_snapped[1])) { + _scale_snapped[1] = fabs(_scale_snapped[0]) * Geom::sgn(_scale[1]); + } else { + _scale_snapped[0] = fabs(_scale_snapped[1]) * Geom::sgn(_scale[0]); + } + } + + // Don't ever exit with one of scaling components uninitialized + for (int index = 0; index < 2; index++) { + if (_scale_snapped[index] == Geom::infinity()) { + _scale_snapped[index] = _scale[index]; + } + } + + // Compare the resulting scaling with the desired scaling + Geom::Point scale_metric = _scale_snapped.vector() - _scale.vector(); + snapped_point.setSnapDistance(Geom::L2(scale_metric)); + snapped_point.setSecondSnapDistance(Geom::infinity()); +} + +// When scaling, a point aligned either horizontally or vertically with the origin can only +// move in that specific direction; therefore it should only snap in that direction, so this +// then becomes a constrained snap; otherwise we can use a free snap; +SnappedPoint PureScale::snap(::SnapManager *sm, SnapCandidatePoint const &p, Geom::Point pt_orig, Geom::OptRect const &bbox_to_snap) const { + Geom::Point const b = (pt_orig - _origin); // vector to original point (not the transformed point!) + bool const c1 = fabs(b[Geom::X]) < 1e-6; + bool const c2 = fabs(b[Geom::Y]) < 1e-6; + if ((c1 || c2) && !(c1 && c2)) { + Geom::Point cvec; cvec[c1] = 1.; + Snapper::SnapConstraint dedicated_constraint = Inkscape::Snapper::SnapConstraint(_origin, cvec); + return sm->constrainedSnap(p, dedicated_constraint, bbox_to_snap); + } else { + return sm->freeSnap(p, bbox_to_snap); + } +} + +SnappedPoint PureScaleConstrained::snap(::SnapManager *sm, SnapCandidatePoint const &p, Geom::Point pt_orig, Geom::OptRect const &bbox_to_snap) const { + // When constrained scaling, only uniform scaling is supported. + // When uniformly scaling, each point will have its own unique constraint line, + // running from the scaling origin to the original untransformed point. We will + // calculate that line here as a dedicated constraint + Geom::Point b = pt_orig - _origin; + Snapper::SnapConstraint dedicated_constraint = Inkscape::Snapper::SnapConstraint(_origin, b); + return sm->constrainedSnap(p, dedicated_constraint, bbox_to_snap); +} + + + + + +Geom::Point PureStretchConstrained::getTransformedPoint(SnapCandidatePoint const &p) const { + Geom::Scale s(1, 1); + if (_uniform) + s[Geom::X] = s[Geom::Y] = _magnitude; + else { + s[_direction] = _magnitude; + s[1 - _direction] = 1; + } + return ((p.getPoint() - _origin) * s) + _origin; +} + +SnappedPoint PureStretchConstrained::snap(::SnapManager *sm, SnapCandidatePoint const &p, Geom::Point pt_orig, Geom::OptRect const &bbox_to_snap) const { + Snapper::SnapConstraint dedicated_constraint; + if (_uniform) { + // When uniformly stretching, each point will have its own unique constraint line, + // running from the scaling origin to the original untransformed point. We will + // calculate that line here + Geom::Point b = pt_orig - _origin; + dedicated_constraint = Inkscape::Snapper::SnapConstraint(_origin, b); // dedicated constraint + } else { + Geom::Point cvec; cvec[_direction] = 1.; + dedicated_constraint = Inkscape::Snapper::SnapConstraint(pt_orig, cvec); + } + + return sm->constrainedSnap(p, dedicated_constraint, bbox_to_snap); +} + +void PureStretchConstrained::storeTransform(SnapCandidatePoint const original_point, SnappedPoint snapped_point) { + Geom::Point const a = snapped_point.getPoint() - _origin; // vector to snapped point + Geom::Point const b = original_point.getPoint() - _origin; // vector to original point (not the transformed point!) + + _stretch_snapped = Geom::Scale(Geom::infinity(), Geom::infinity()); + if (fabs(b[_direction]) > 1e-6) { // if STRETCHING will occur for this point + _stretch_snapped[_direction] = a[_direction] / b[_direction]; + _stretch_snapped[1-_direction] = _uniform ? _stretch_snapped[_direction] : 1; + } else { // STRETCHING might occur for this point, but only when the stretching is uniform + if (_uniform && fabs(b[1-_direction]) > 1e-6) { + _stretch_snapped[1-_direction] = a[1-_direction] / b[1-_direction]; + _stretch_snapped[_direction] = _stretch_snapped[1-_direction]; + } + } + + // _stretch_snapped might have one or both components at infinity! + + // Store the metric for this transformation as a virtual distance + snapped_point.setSnapDistance(std::abs(_stretch_snapped[_direction] - _magnitude)); + snapped_point.setSecondSnapDistance(Geom::infinity()); +} + + + + + +Geom::Point PureSkewConstrained::getTransformedPoint(SnapCandidatePoint const &p) const { + Geom::Point transformed; + // Apply the skew factor + transformed[_direction] = (p.getPoint())[_direction] + _skew * ((p.getPoint())[1 - _direction] - _origin[1 - _direction]); + // While skewing, mirroring and scaling (by integer multiples) in the opposite direction is also allowed. + // Apply that scale factor here + transformed[1-_direction] = (p.getPoint() - _origin)[1 - _direction] * _scale + _origin[1 - _direction]; + return transformed; +} + +SnappedPoint PureSkewConstrained::snap(::SnapManager *sm, SnapCandidatePoint const &p, Geom::Point pt_orig, Geom::OptRect const &bbox_to_snap) const { + // Snapping the nodes of the bounding box of a selection that is being transformed, will only work if + // the transformation of the bounding box is equal to the transformation of the individual nodes. This is + // NOT the case for example when rotating or skewing. The bounding box itself cannot possibly rotate or skew, + // so it's corners have a different transformation. The snappers cannot handle this, therefore snapping + // of bounding boxes is not allowed here. + g_assert(!(p.getSourceType() & Inkscape::SNAPSOURCE_BBOX_CATEGORY)); + + Geom::Point constraint_vector; + constraint_vector[1-_direction] = 0.0; + constraint_vector[_direction] = 1.0; + + return sm->constrainedSnap(p, Inkscape::Snapper::SnapConstraint(constraint_vector), bbox_to_snap); +} + +void PureSkewConstrained::storeTransform(SnapCandidatePoint const original_point, SnappedPoint snapped_point) { + Geom::Point const b = original_point.getPoint() - _origin; // vector to original point (not the transformed point!) + _skew_snapped = (snapped_point.getPoint()[_direction] - (original_point.getPoint())[_direction]) / b[1 - _direction]; // skew factor + + // Store the metric for this transformation as a virtual distance + snapped_point.setSnapDistance(std::abs(_skew_snapped - _skew)); + snapped_point.setSecondSnapDistance(Geom::infinity()); +} + + + + +Geom::Point PureRotateConstrained::getTransformedPoint(SnapCandidatePoint const &p) const { + return (p.getPoint() - _origin) * Geom::Rotate(_angle) + _origin; +} + +SnappedPoint PureRotateConstrained::snap(::SnapManager *sm, SnapCandidatePoint const &p, Geom::Point pt_orig, Geom::OptRect const &bbox_to_snap) const { + // Snapping the nodes of the bounding box of a selection that is being transformed, will only work if + // the transformation of the bounding box is equal to the transformation of the individual nodes. This is + // NOT the case for example when rotating or skewing. The bounding box itself cannot possibly rotate or skew, + // so it's corners have a different transformation. The snappers cannot handle this, therefore snapping + // of bounding boxes is not allowed here. + g_assert(!(p.getSourceType() & Inkscape::SNAPSOURCE_BBOX_CATEGORY)); + + // Calculate a constraint dedicated for this specific point + Geom::Point b = pt_orig - _origin; + Geom::Coord r = Geom::L2(b); // the radius of the circular constraint + Snapper::SnapConstraint dedicated_constraint = Inkscape::Snapper::SnapConstraint(_origin, b, r); + return sm->constrainedSnap(p, dedicated_constraint, bbox_to_snap); +} + +void PureRotateConstrained::storeTransform(SnapCandidatePoint const original_point, SnappedPoint snapped_point) { + Geom::Point const a = snapped_point.getPoint() - _origin; // vector to snapped point + Geom::Point const b = (original_point.getPoint() - _origin); // vector to original point (not the transformed point!) + // a is vector to snapped point; b is vector to original point; now lets calculate angle between a and b + _angle_snapped = atan2(Geom::dot(Geom::rot90(b), a), Geom::dot(b, a)); + if (Geom::L2(b) < 1e-9) { // points too close to the rotation center will not move. Don't try to snap these + // as they will always yield a perfect snap result if they're already snapped beforehand (e.g. + // when the transformation center has been snapped to a grid intersection in the selector tool) + snapped_point.setSnapDistance(Geom::infinity()); + // PS1: Apparently we don't have to do this for skewing, but why? + // PS2: We cannot easily filter these points upstream, e.g. in the grab() method (seltrans.cpp) + // because the rotation center will change when pressing shift, and grab() won't be recalled. + // Filtering could be done in handleRequest() (again in seltrans.cpp), by iterating through + // the snap candidates. But hey, we're iterating here anyway. + } else { + snapped_point.setSnapDistance(fabs(_angle_snapped - _angle)); + } + snapped_point.setSecondSnapDistance(Geom::infinity()); + +} + +} diff --git a/src/pure-transform.h b/src/pure-transform.h new file mode 100644 index 000000000..f973a95b1 --- /dev/null +++ b/src/pure-transform.h @@ -0,0 +1,228 @@ +/* + * Class for pure transformations, such as translating, scaling, stretching, skewing, and rotating. Pure means that they cannot + * be combined. This is what makes them different from affine transformations. Pure transformations are being used in the selector + * tool and node tool + * + * Authors: + * Diederik van Lierop <mail@diedenrezi.nl> + * + * Copyright (C) 2015 Diederik van Lierop + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifndef SEEN_PURE_TRANSFORM_H +#define SEEN_PURE_TRANSFORM_H + +#include <glib.h> // for g_warning +#include "snapper.h" // for SnapConstraint + +class SnapManager; + +namespace Inkscape { + +class PureTransform { + +protected: + virtual SnappedPoint snap(::SnapManager *sm, SnapCandidatePoint const &p, Geom::Point pt_orig, Geom::OptRect const &bbox_to_snap) const = 0; + virtual Geom::Point getTransformedPoint(SnapCandidatePoint const &p) const = 0; + virtual void storeTransform(SnapCandidatePoint const original_point, SnappedPoint snapped_point) = 0; + +public: + //PureTransform(); + virtual ~PureTransform() {}; +// virtual PureTransform * clone () const = 0; // https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Virtual_Constructor + + // Snap a group of points + SnappedPoint best_snapped_point; + void snap(::SnapManager *sm, std::vector<Inkscape::SnapCandidatePoint> const &points, Geom::Point const &pointer); +}; + +// ************************************************************************************************************** + +class PureTranslate: public PureTransform { + +protected: + Geom::Point _vector; + Geom::Point _vector_snapped; + + virtual SnappedPoint snap(::SnapManager *sm, SnapCandidatePoint const &p, Geom::Point pt_orig, Geom::OptRect const &bbox_to_snap) const; + virtual Geom::Point getTransformedPoint(SnapCandidatePoint const &p) const; + virtual void storeTransform(SnapCandidatePoint const original_point, SnappedPoint snapped_point); + +public: +// PureTranslate(); // Default constructor +// PureTranslate(PureTranslate const &); // Copy constructor + virtual ~PureTranslate() {}; + PureTranslate(Geom::Point vector = Geom::Point()) : _vector(vector), _vector_snapped(vector) {} + + Geom::Point getTranslationSnapped() {return _vector_snapped;} +// PureTranslate * clone () const {return new PureTranslate(*this);} +}; + + +class PureTranslateConstrained: public PureTranslate { + +protected: + Geom::Dim2 _direction; + virtual SnappedPoint snap(::SnapManager *sm, SnapCandidatePoint const &p, Geom::Point pt_orig, Geom::OptRect const &bbox_to_snap) const; + +public: + virtual ~PureTranslateConstrained() {}; + PureTranslateConstrained(Geom::Coord displacement, Geom::Dim2 direction): + PureTranslate() { + _vector[direction] = displacement; + _vector[1-direction] = 0.0; + _direction = direction; + } + // PureTranslateConstrained * clone () const {return new PureTranslateConstrained(*this);} +}; + +// ************************************************************************************************************** + +class PureScale: public PureTransform { + +protected: + Geom::Scale _scale; + Geom::Scale _scale_snapped; + Geom::Point _origin; + bool _uniform; + + virtual SnappedPoint snap(::SnapManager *sm, SnapCandidatePoint const &p, Geom::Point pt_orig, Geom::OptRect const &bbox_to_snap) const; + virtual Geom::Point getTransformedPoint(SnapCandidatePoint const &p) const; + virtual void storeTransform(SnapCandidatePoint const original_point, SnappedPoint snapped_point); + +public: +// PureScale(); // Default constructor +// PureScale(PureScale const &); // Copy constructor + virtual ~PureScale() {}; + + PureScale(Geom::Scale scale, Geom::Point origin, bool uniform) : + _scale (scale), + _scale_snapped (scale), + _origin (origin), + _uniform (uniform) + {} + + Geom::Scale getScaleSnapped() {return _scale_snapped;} +// PureScale * clone () const {return new PureScale (*this);} +}; + +class PureScaleConstrained: public PureScale { +//Magnitude of the scale components will be the same, but the sign could still be different () +protected: + virtual SnappedPoint snap(::SnapManager *sm, SnapCandidatePoint const &p, Geom::Point pt_orig, Geom::OptRect const &bbox_to_snap) const; + +public: + virtual ~PureScaleConstrained() {}; + PureScaleConstrained(Geom::Scale scale, Geom::Point origin): + PureScale(scale, origin, true) {}; // Non-uniform constrained scaling is not supported + +// PureScaleConstrained * clone () const {return new PureScaleConstrained(*this);} +}; + +// ************************************************************************************************************** + +class PureStretchConstrained: public PureTransform { +// A stretch is always implicitly constrained + +protected: + Geom::Coord _magnitude; + Geom::Scale _stretch_snapped; + Geom::Point _origin; + Geom::Dim2 _direction; + bool _uniform; + + virtual SnappedPoint snap(::SnapManager *sm, SnapCandidatePoint const &p, Geom::Point pt_orig, Geom::OptRect const &bbox_to_snap) const; + virtual Geom::Point getTransformedPoint(SnapCandidatePoint const &p) const; + virtual void storeTransform(SnapCandidatePoint const original_point, SnappedPoint snapped_point); + +public: + virtual ~PureStretchConstrained() {}; + PureStretchConstrained(Geom::Coord magnitude, Geom::Point origin, Geom::Dim2 direction, bool uniform) : + _magnitude (magnitude), + _stretch_snapped (Geom::Scale(magnitude, magnitude)), + _origin (origin), + _direction (direction), + _uniform (uniform) + { + if (not uniform) { + _stretch_snapped[1-direction] = 1.0; + } + } + + Geom::Scale getStretchSnapped() {return _stretch_snapped;} + Geom::Coord getMagnitude() {return _magnitude;} + Geom::Coord getMagnitudeSnapped() {return _stretch_snapped[_direction];} + +// PureStretchConstrained * clone () const {return new PureStretchConstrained(*this);} +}; + +// ************************************************************************************************************** + +class PureSkewConstrained: public PureTransform { +// A skew is always implicitly constrained + +protected: + Geom::Coord _skew; + Geom::Coord _skew_snapped; + Geom::Coord _scale; + Geom::Point _origin; + Geom::Dim2 _direction; + + virtual SnappedPoint snap(::SnapManager *sm, SnapCandidatePoint const &p, Geom::Point pt_orig, Geom::OptRect const &bbox_to_snap) const; + Geom::Point getTransformedPoint(SnapCandidatePoint const &p) const; + virtual void storeTransform(SnapCandidatePoint const original_point, SnappedPoint snapped_point); + +public: + virtual ~PureSkewConstrained() {}; + PureSkewConstrained(Geom::Coord skew, Geom::Coord scale, Geom::Point origin, Geom::Dim2 direction) : + _skew (skew), + _skew_snapped (skew), + _scale (scale), + _origin (origin), + _direction (direction) + {}; + + Geom::Coord getSkewSnapped() {return _skew_snapped;} + +// PureSkewConstrained * clone () const {return new PureSkewConstrained(*this);} +}; + +// ************************************************************************************************************** + +class PureRotateConstrained: public PureTransform { +// A rotation is always implicitly constrained, so we will hide the constructor by making it protected; devs should use PureRotateConstrained instead +// It's _constraint member variable though will be empty + +protected: + double _angle; // in radians + double _angle_snapped; + Geom::Point _origin; + bool _uniform; + + virtual SnappedPoint snap(::SnapManager *sm, SnapCandidatePoint const &p, Geom::Point pt_orig, Geom::OptRect const &bbox_to_snap) const; + virtual Geom::Point getTransformedPoint(SnapCandidatePoint const &p) const; + virtual void storeTransform(SnapCandidatePoint const original_point, SnappedPoint snapped_point); + +public: +// PureRotate(); // Default constructor +// PureRotate(PureRotate const &); // Copy constructor + virtual ~PureRotateConstrained() {}; + + PureRotateConstrained(double angle, Geom::Point origin) : + _angle (angle), // in radians! + _angle_snapped (angle), + _origin (origin), + _uniform (true) // We do not yet allow for simultaneous rotation and scaling + {} + + double getAngleSnapped() {return _angle_snapped;} + +// PureRotate * clone () const {return new PureRotate(*this);} +}; + +} + +#endif // !SEEN_PURE_TRANSFORM_H + diff --git a/src/resource-manager.cpp b/src/resource-manager.cpp index fe53eca4f..dbff27827 100644 --- a/src/resource-manager.cpp +++ b/src/resource-manager.cpp @@ -222,11 +222,15 @@ std::map<Glib::ustring, Glib::ustring> ResourceManagerImpl::locateLinks(Glib::us Glib::ustring uri = (*it)->get_uri(); std::string scheme = Glib::uri_parse_scheme(uri); if ( scheme == "file" ) { - std::string path = Glib::filename_from_uri(uri); - path = Glib::path_get_dirname(path); - if ( std::find(priorLocations.begin(), priorLocations.end(), path) == priorLocations.end() ) { - // TODO debug g_message(" ==>[%s]", path.c_str()); - priorLocations.push_back(path); + try { + std::string path = Glib::filename_from_uri(uri); + path = Glib::path_get_dirname(path); + if ( std::find(priorLocations.begin(), priorLocations.end(), path) == priorLocations.end() ) { + // TODO debug g_message(" ==>[%s]", path.c_str()); + priorLocations.push_back(path); + } + } catch (Glib::ConvertError e) { + g_warning("Bad URL ignored [%s]", uri.c_str()); } } } diff --git a/src/selcue.cpp b/src/selcue.cpp index c73219b7d..297b9fffc 100644 --- a/src/selcue.cpp +++ b/src/selcue.cpp @@ -104,7 +104,7 @@ void Inkscape::SelCue::_updateItemBboxes(gint mode, int prefs_bbox) int bcount = 0; std::vector<SPItem*> ll=_selection->itemList(); - for (std::vector<SPItem*>::const_iterator l = ll.begin(); l != ll.end(); l++) { + for (std::vector<SPItem*>::const_iterator l = ll.begin(); l != ll.end(); ++l) { SPItem *item = *l; SPCanvasItem* box = _item_bboxes[bcount ++]; @@ -147,7 +147,7 @@ void Inkscape::SelCue::_newItemBboxes() int prefs_bbox = prefs->getBool("/tools/bounding_box"); std::vector<SPItem*> ll=_selection->itemList(); - for (std::vector<SPItem*>::const_iterator l = ll.begin(); l != ll.end(); l++) { + for (std::vector<SPItem*>::const_iterator l = ll.begin(); l != ll.end(); ++l) { SPItem *item = *l; Geom::OptRect const b = (prefs_bbox == 0) ? @@ -202,7 +202,7 @@ void Inkscape::SelCue::_newTextBaselines() _text_baselines.clear(); std::vector<SPItem*> ll = _selection->itemList(); - for (std::vector<SPItem*>::const_iterator l=ll.begin();l!=ll.end();l++) { + for (std::vector<SPItem*>::const_iterator l=ll.begin();l!=ll.end();++l) { SPItem *item = *l; SPCanvasItem* baseline_point = NULL; diff --git a/src/selection-chemistry.cpp b/src/selection-chemistry.cpp index 3999156db..cdbc6a937 100644 --- a/src/selection-chemistry.cpp +++ b/src/selection-chemistry.cpp @@ -284,7 +284,7 @@ void SelectionHelper::fixSelection(SPDesktop *dt) std::vector<SPItem*> const selList = selection->itemList(); - for( std::vector<SPItem*>::const_reverse_iterator i = selList.rbegin(); i != selList.rend(); i++ ) { + for( std::vector<SPItem*>::const_reverse_iterator i = selList.rbegin(); i != selList.rend(); ++i ) { SPItem *item = *i; if( item && !dt->isLayer(item) && @@ -330,7 +330,7 @@ static void sp_selection_copy_impl(std::vector<SPItem*> const &items, std::vecto sort(sorted_items.begin(),sorted_items.end(),sp_object_compare_position_bool); // Copy item reprs: - for (std::vector<SPItem*>::const_iterator i = sorted_items.begin(); i != sorted_items.end(); i++) { + for (std::vector<SPItem*>::const_iterator i = sorted_items.begin(); i != sorted_items.end(); ++i) { SPItem *item = *i; if (item) { sp_selection_copy_one(item->getRepr(), item->i2doc_affine(), clip, xml_doc); @@ -351,7 +351,7 @@ static std::vector<Inkscape::XML::Node*> sp_selection_paste_impl(SPDocument *doc std::vector<Inkscape::XML::Node*> copied; // add objects to document - for (std::vector<Inkscape::XML::Node*>::const_iterator l = clip.begin(); l != clip.end(); l++) { + for (std::vector<Inkscape::XML::Node*>::const_iterator l = clip.begin(); l != clip.end(); ++l) { Inkscape::XML::Node *repr = *l; Inkscape::XML::Node *copy = repr->duplicate(xml_doc); @@ -378,10 +378,10 @@ static std::vector<Inkscape::XML::Node*> sp_selection_paste_impl(SPDocument *doc static void sp_selection_delete_impl(std::vector<SPItem*> const &items, bool propagate = true, bool propagate_descendants = true) { - for (std::vector<SPItem*>::const_iterator i = items.begin(); i != items.end(); i++) { + for (std::vector<SPItem*>::const_iterator i = items.begin(); i != items.end(); ++i) { sp_object_ref(*i, NULL); } - for (std::vector<SPItem*>::const_iterator i = items.begin(); i != items.end(); i++) { + for (std::vector<SPItem*>::const_iterator i = items.begin(); i != items.end(); ++i) { SPItem *item = *i; item->deleteObject(propagate, propagate_descendants); sp_object_unref(item, NULL); @@ -475,7 +475,7 @@ void sp_selection_duplicate(SPDesktop *desktop, bool suppressDone, bool duplicat bool relink_clones = prefs->getBool("/options/relinkclonesonduplicate/value"); const bool fork_livepatheffects = prefs->getBool("/options/forklpeonduplicate/value", true); - for(std::vector<Inkscape::XML::Node*>::const_iterator i=reprs.begin();i!=reprs.end();i++){ + for(std::vector<Inkscape::XML::Node*>::const_iterator i=reprs.begin();i!=reprs.end();++i){ Inkscape::XML::Node *old_repr = *i; Inkscape::XML::Node *parent = old_repr->parent(); Inkscape::XML::Node *copy = old_repr->duplicate(xml_doc); @@ -483,7 +483,7 @@ void sp_selection_duplicate(SPDesktop *desktop, bool suppressDone, bool duplicat if(! duplicateLayer) parent->appendChild(copy); else - parent->addChild(copy, old_repr); + parent->addChild(copy, old_repr); if (relink_clones) { SPObject *old_obj = doc->getObjectByRepr(old_repr); @@ -547,7 +547,7 @@ void sp_selection_duplicate(SPDesktop *desktop, bool suppressDone, bool duplicat if(!duplicateLayer) selection->setReprList(newsel); else{ - SPObject* new_layer = doc->getObjectByRepr(newsel[0]); + SPObject* new_layer = doc->getObjectByRepr(newsel[0]); gchar* name = g_strdup_printf(_("%s copy"), new_layer->label()); desktop->layer_manager->renameLayer( new_layer, name, TRUE ); g_free(name); @@ -638,7 +638,7 @@ static void sp_edit_select_all_full(SPDesktop *dt, bool force_all_layers, bool i std::vector<SPItem*> all_items = sp_item_group_item_list(dynamic_cast<SPGroup *>(dt->currentLayer())); - for (std::vector<SPItem*>::const_reverse_iterator i=all_items.rbegin();i!=all_items.rend();i++) { + for (std::vector<SPItem*>::const_reverse_iterator i=all_items.rbegin();i!=all_items.rend();++i) { SPItem *item = *i; if (item && (!onlysensitive || !item->isLocked())) { @@ -655,7 +655,7 @@ static void sp_edit_select_all_full(SPDesktop *dt, bool force_all_layers, bool i break; } case PREFS_SELECTION_LAYER_RECURSIVE: { - std::vector<SPItem*> x; + std::vector<SPItem*> x; items = get_all_items(x, dt->currentLayer(), dt, onlyvisible, onlysensitive, FALSE, exclude); break; } @@ -698,7 +698,7 @@ static void sp_selection_group_impl(std::vector<Inkscape::XML::Node*> p, Inkscap gint topmost = p.back()->position(); Inkscape::XML::Node *topmost_parent = p.back()->parent(); - for(std::vector<Inkscape::XML::Node*>::const_iterator i = p.begin(); i != p.end(); i++){ + for(std::vector<Inkscape::XML::Node*>::const_iterator i = p.begin(); i != p.end(); ++i){ Inkscape::XML::Node *current = *i; if (current->parent() == topmost_parent) { @@ -802,7 +802,7 @@ void sp_selection_ungroup(Inkscape::Selection *selection, SPDesktop *desktop) std::vector<SPItem*> old_select = selection->itemList(); std::vector<SPItem*> new_select; GSList *groups = NULL; - for (std::vector<SPItem*>::const_iterator item = old_select.begin(); item!=old_select.end(); item++) { + for (std::vector<SPItem*>::const_iterator item = old_select.begin(); item!=old_select.end(); ++item) { SPItem *obj = *item; if (dynamic_cast<SPGroup *>(obj)) { groups = g_slist_prepend(groups, obj); @@ -821,7 +821,7 @@ void sp_selection_ungroup(Inkscape::Selection *selection, SPDesktop *desktop) // If any of the clones refer to the groups, unlink them and replace them with successors // in the items list. GSList *clones_to_unlink = NULL; - for (std::vector<SPItem*>::const_iterator item = items.begin(); item != items.end(); item++) { + for (std::vector<SPItem*>::const_iterator item = items.begin(); item != items.end(); ++item) { SPUse *use = dynamic_cast<SPUse *>(*item); SPItem *original = use; @@ -847,12 +847,12 @@ void sp_selection_ungroup(Inkscape::Selection *selection, SPDesktop *desktop) g_slist_free(clones_to_unlink); // do the actual work - for (std::vector<SPItem*>::iterator item = items.begin(); item != items.end(); item++) { + for (std::vector<SPItem*>::iterator item = items.begin(); item != items.end(); ++item) { SPItem *obj = *item; // ungroup only the groups marked earlier if (g_slist_find(groups, *item) != NULL) { - std::vector<SPItem*> children; + std::vector<SPItem*> children; sp_item_group_ungroup(dynamic_cast<SPGroup *>(obj), children, false); // add the items resulting from ungrouping to the selection new_select.insert(new_select.end(),children.begin(),children.end()); @@ -873,16 +873,16 @@ void sp_selection_ungroup(Inkscape::Selection *selection, SPDesktop *desktop) std::vector<SPItem*> sp_degroup_list(std::vector<SPItem*> &items) { - std::vector<SPItem*> out; + std::vector<SPItem*> out; bool has_groups = false; - for (std::vector<SPItem*>::const_iterator item=items.begin();item!=items.end();item++) { + for (std::vector<SPItem*>::const_iterator item=items.begin();item!=items.end();++item) { SPGroup *group = dynamic_cast<SPGroup *>(*item); if (!group) { out.push_back(*item); } else { has_groups = true; std::vector<SPItem*> members = sp_item_group_item_list(group); - for (std::vector<SPItem*>::const_iterator member=members.begin();member!=members.end();member++) { + for (std::vector<SPItem*>::const_iterator member=members.begin();member!=members.end();++member) { out.push_back(*member); } members.clear(); @@ -899,7 +899,7 @@ sp_degroup_list(std::vector<SPItem*> &items) /** If items in the list have a common parent, return it, otherwise return NULL */ static SPGroup * -sp_item_list_common_parent_group(std::vector<SPItem*> const items) +sp_item_list_common_parent_group(std::vector<SPItem*> const &items) { if (items.empty()) { return NULL; @@ -909,8 +909,8 @@ sp_item_list_common_parent_group(std::vector<SPItem*> const items) if (!dynamic_cast<SPGroup *>(parent)) { return NULL; } - for (std::vector<SPItem*>::const_iterator item=items.begin();item!=items.end();item++) { - if((*item)==items[0])continue; + for (std::vector<SPItem*>::const_iterator item=items.begin();item!=items.end();++item) { + if((*item)==items[0])continue; if ((*item)->parent != parent) { return NULL; } @@ -926,7 +926,7 @@ enclose_items(std::vector<SPItem*> const &items) g_assert(!items.empty()); Geom::OptRect r; - for (std::vector<SPItem*>::const_iterator i = items.begin();i!=items.end();i++) { + for (std::vector<SPItem*>::const_iterator i = items.begin();i!=items.end();++i) { r.unionWith((*i)->desktopVisualBounds()); } return r; @@ -945,7 +945,7 @@ static SPObject *prev_sibling(SPObject *child) bool sp_item_repr_compare_position_bool(SPObject const *first, SPObject const *second) { return sp_repr_compare_position(((SPItem*)first)->getRepr(), - ((SPItem*)second)->getRepr())<0; + ((SPItem*)second)->getRepr())<0; } void @@ -974,7 +974,7 @@ sp_selection_raise(Inkscape::Selection *selection, SPDesktop *desktop) // Iterate over all objects in the selection (starting from top). if (selected) { - for (std::vector<SPItem*>::const_iterator item=rev.begin();item!=rev.end();item++) { + for (std::vector<SPItem*>::const_iterator item=rev.begin();item!=rev.end();++item) { SPObject *child = *item; // for each selected object, find the next sibling for (SPObject *newref = child->next; newref; newref = newref->next) { @@ -1019,7 +1019,7 @@ void sp_selection_raise_to_top(Inkscape::Selection *selection, SPDesktop *deskto std::vector<Inkscape::XML::Node*> rl(selection->reprList()); sort(rl.begin(),rl.end(),sp_repr_compare_position_bool); - for (std::vector<Inkscape::XML::Node*>::const_iterator l=rl.begin(); l!=rl.end();l++) { + for (std::vector<Inkscape::XML::Node*>::const_iterator l=rl.begin(); l!=rl.end();++l) { Inkscape::XML::Node *repr =(*l); repr->setPosition(-1); } @@ -1053,7 +1053,7 @@ void sp_selection_lower(Inkscape::Selection *selection, SPDesktop *desktop) // Iterate over all objects in the selection (starting from top). if (selected) { - for (std::vector<SPItem*>::const_reverse_iterator item=rev.rbegin();item!=rev.rend();item++) { + for (std::vector<SPItem*>::const_reverse_iterator item=rev.rbegin();item!=rev.rend();++item) { SPObject *child = *item; // for each selected object, find the prev sibling for (SPObject *newref = prev_sibling(child); newref; newref = prev_sibling(newref)) { @@ -1103,7 +1103,7 @@ void sp_selection_lower_to_bottom(Inkscape::Selection *selection, SPDesktop *des std::vector<Inkscape::XML::Node*> rl(selection->reprList()); sort(rl.begin(),rl.end(),sp_repr_compare_position_bool); - for (std::vector<Inkscape::XML::Node*>::const_reverse_iterator l=rl.rbegin();l!=rl.rend();l++) { + for (std::vector<Inkscape::XML::Node*>::const_reverse_iterator l=rl.rbegin();l!=rl.rend();++l) { gint minpos; SPObject *pp, *pc; Inkscape::XML::Node *repr = (*l); @@ -1256,7 +1256,7 @@ void sp_selection_remove_livepatheffect(SPDesktop *desktop) return; } std::vector<SPItem*> list=selection->itemList(); - for ( std::vector<SPItem*>::const_iterator itemlist=list.begin();itemlist!=list.end();itemlist++) { + for ( std::vector<SPItem*>::const_iterator itemlist=list.begin();itemlist!=list.end();++itemlist) { SPItem *item = *itemlist; sp_selection_remove_livepatheffect_impl(item); @@ -1313,7 +1313,7 @@ void sp_selection_paste_size_separately(SPDesktop *desktop, bool apply_x, bool a */ void sp_selection_change_layer_maintain_clones(std::vector<SPItem*> const &items,SPObject *where) { - for (std::vector<SPItem*>::const_iterator i = items.begin(); i != items.end(); i++) { + for (std::vector<SPItem*>::const_iterator i = items.begin(); i != items.end(); ++i) { SPItem *item = *i; if (item) { SPItem *oldparent = dynamic_cast<SPItem *>(item->parent); @@ -1472,7 +1472,7 @@ selection_contains_both_clone_and_original(Inkscape::Selection *selection) { bool clone_with_original = false; std::vector<SPItem*> items = selection->itemList(); - for (std::vector<SPItem*>::const_iterator l=items.begin();l!=items.end() ;l++) { + for (std::vector<SPItem*>::const_iterator l=items.begin();l!=items.end() ;++l) { SPItem *item = *l; if (item) { clone_with_original |= selection_contains_original(item, selection); @@ -1517,7 +1517,7 @@ void sp_selection_apply_affine(Inkscape::Selection *selection, Geom::Affine cons persp3d_apply_affine_transformation(transf_persp, affine); } std::vector<SPItem*> items = selection->itemList(); - for (std::vector<SPItem*>::const_iterator l=items.begin();l!=items.end() ;l++) { + for (std::vector<SPItem*>::const_iterator l=items.begin();l!=items.end() ;++l) { SPItem *item = *l; if( dynamic_cast<SPRoot *>(item) ) { @@ -1688,7 +1688,7 @@ void sp_selection_remove_transform(SPDesktop *desktop) Inkscape::Selection *selection = desktop->getSelection(); std::vector<Inkscape::XML::Node*> items = selection->reprList(); - for (std::vector<Inkscape::XML::Node*>::const_iterator l=items.begin();l!=items.end() ;l++) { + for (std::vector<Inkscape::XML::Node*>::const_iterator l=items.begin();l!=items.end() ;++l) { (*l)->setAttribute("transform", NULL, false); } @@ -1789,7 +1789,7 @@ void sp_selection_rotate_90(SPDesktop *desktop, bool ccw) std::vector<SPItem*> items = selection->itemList(); Geom::Rotate const rot_90(Geom::Point(0, ccw ? 1 : -1)); // pos. or neg. rotation, depending on the value of ccw - for (std::vector<SPItem*>::const_iterator l=items.begin();l!=items.end() ;l++) { + for (std::vector<SPItem*>::const_iterator l=items.begin();l!=items.end() ;++l) { SPItem *item = *l; if (item) { sp_item_rotate_rel(item, rot_90); @@ -1854,14 +1854,14 @@ void sp_select_same_fill_stroke_style(SPDesktop *desktop, gboolean fill, gboolea std::vector<SPItem*> items = selection->itemList(); std::vector<SPItem*> tmp; - for (std::vector<SPItem*>::const_iterator iter=all_list.begin();iter!=all_list.end();iter++) { + for (std::vector<SPItem*>::const_iterator iter=all_list.begin();iter!=all_list.end();++iter) { if(!SP_IS_GROUP(*iter)){ tmp.push_back(*iter); } } all_list=tmp; - for (std::vector<SPItem*>::const_iterator sel_iter=items.begin();sel_iter!=items.end();sel_iter++) { + for (std::vector<SPItem*>::const_iterator sel_iter=items.begin();sel_iter!=items.end();++sel_iter) { SPItem *sel = *sel_iter; std::vector<SPItem*> matches = all_list; if (fill && stroke && style) { @@ -1909,7 +1909,7 @@ void sp_select_same_object_type(SPDesktop *desktop) Inkscape::Selection *selection = desktop->getSelection(); std::vector<SPItem*> items=selection->itemList(); - for (std::vector<SPItem*>::const_iterator sel_iter=items.begin();sel_iter!=items.end();sel_iter++) { + for (std::vector<SPItem*>::const_iterator sel_iter=items.begin();sel_iter!=items.end();++sel_iter) { SPItem *sel = *sel_iter; if (sel) { matches = sp_get_same_object_type(sel, matches); @@ -1936,7 +1936,7 @@ std::vector<SPItem*> sp_get_same_fill_or_stroke_color(SPItem *sel, std::vector<S SPIPaint *sel_paint = (type == SP_FILL_COLOR) ? &(sel->style->fill) : &(sel->style->stroke); - for (std::vector<SPItem*>::const_reverse_iterator i=src.rbegin();i!=src.rend();i++) { + for (std::vector<SPItem*>::const_reverse_iterator i=src.rbegin();i!=src.rend();++i) { SPItem *iter = *i; if (iter) { SPIPaint *iter_paint = (type == SP_FILL_COLOR) ? &(iter->style->fill) : &(iter->style->stroke); @@ -2031,7 +2031,7 @@ std::vector<SPItem*> sp_get_same_object_type(SPItem *sel, std::vector<SPItem*> & { std::vector<SPItem*> matches; - for (std::vector<SPItem*>::const_reverse_iterator i=src.rbegin();i!=src.rend();i++) { + for (std::vector<SPItem*>::const_reverse_iterator i=src.rbegin();i!=src.rend();++i) { SPItem *item = *i; if (item && item_type_match(sel, item) && !item->cloned) { matches.push_back(item); @@ -2072,7 +2072,7 @@ std::vector<SPItem*> sp_get_same_style(SPItem *sel, std::vector<SPItem*> &src, S objects_query_strokewidth (objects, sel_style_for_width); } bool match_g; - for (std::vector<SPItem*>::const_iterator i=src.begin();i!=src.end();i++) { + for (std::vector<SPItem*>::const_iterator i=src.begin();i!=src.end();++i) { SPItem *iter = *i; if (iter) { match_g=true; @@ -2112,7 +2112,7 @@ std::vector<SPItem*> sp_get_same_style(SPItem *sel, std::vector<SPItem*> &src, S } } } - match_g = match_g && match; + match_g = match_g && match; if (match_g) { while (iter->cloned) iter=dynamic_cast<SPItem *>(iter->parent); matches.insert(matches.begin(),iter); @@ -2371,11 +2371,11 @@ SPItem *next_item(SPDesktop *desktop, GSList *path, SPObject *root, template <typename D> -SPItem *next_item_from_list(SPDesktop *desktop, std::vector<SPItem*> const items, +SPItem *next_item_from_list(SPDesktop *desktop, std::vector<SPItem*> const &items, SPObject *root, bool only_in_viewport, PrefsSelectionContext inlayer, bool onlyvisible, bool onlysensitive) { SPObject *current=root; - for(std::vector<SPItem*>::const_iterator i = items.begin();i!=items.end();i++) { + for(std::vector<SPItem*>::const_iterator i = items.begin();i!=items.end();++i) { SPItem *item = *i; if ( root->isAncestorOf(item) && ( !only_in_viewport || desktop->isWithinViewport(item) ) ) @@ -2577,8 +2577,8 @@ void sp_selection_clone(SPDesktop *desktop) std::vector<Inkscape::XML::Node*> newsel; - for(std::vector<Inkscape::XML::Node*>::const_iterator i=reprs.begin();i!=reprs.end();i++){ - Inkscape::XML::Node *sel_repr = *i; + for(std::vector<Inkscape::XML::Node*>::const_iterator i=reprs.begin();i!=reprs.end();++i){ + Inkscape::XML::Node *sel_repr = *i; Inkscape::XML::Node *parent = sel_repr->parent(); Inkscape::XML::Node *clone = xml_doc->createElement("svg:use"); @@ -2628,7 +2628,7 @@ sp_selection_relink(SPDesktop *desktop) // Get a copy of current selection. bool relinked = false; std::vector<SPItem*> items=selection->itemList(); - for (std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++){ + for (std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();++i){ SPItem *item = *i; if (dynamic_cast<SPUse *>(item)) { @@ -2666,7 +2666,7 @@ sp_selection_unlink(SPDesktop *desktop) std::vector<SPItem*> new_select; bool unlinked = false; std::vector<SPItem*> items=selection->itemList(); - for (std::vector<SPItem*>::const_reverse_iterator i=items.rbegin();i!=items.rend();i++){ + for (std::vector<SPItem*>::const_reverse_iterator i=items.rbegin();i!=items.rend();++i){ SPItem *item = *i; if (dynamic_cast<SPText *>(item)) { @@ -2831,7 +2831,7 @@ void sp_selection_clone_original_path_lpe(SPDesktop *desktop) Inkscape::SVGOStringStream os; SPObject * firstItem = NULL; std::vector<SPItem*> items=selection->itemList(); - for (std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++){ + for (std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();++i){ if (SP_IS_SHAPE(*i) || SP_IS_TEXT(*i)) { if (firstItem) { os << "|"; @@ -2934,7 +2934,7 @@ void sp_selection_to_marker(SPDesktop *desktop, bool apply) // Create a list of duplicates, to be pasted inside marker element. std::vector<Inkscape::XML::Node*> repr_copies; - for (std::vector<SPItem*>::const_reverse_iterator i=items.rbegin();i!=items.rend();i++){ + for (std::vector<SPItem*>::const_reverse_iterator i=items.rbegin();i!=items.rend();++i){ Inkscape::XML::Node *dup = (*i)->getRepr()->duplicate(xml_doc); repr_copies.push_back(dup); } @@ -2944,7 +2944,7 @@ void sp_selection_to_marker(SPDesktop *desktop, bool apply) if (apply) { // Delete objects so that their clones don't get alerted; // the objects will be restored inside the marker element. - for (std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++){ + for (std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();++i){ SPObject *item = *i; item->deleteObject(false); } @@ -2973,7 +2973,7 @@ static void sp_selection_to_guides_recursive(SPItem *item, bool wholegroups) { SPGroup *group = dynamic_cast<SPGroup *>(item); if (group && !dynamic_cast<SPBox3D *>(item) && !wholegroups) { std::vector<SPItem*> items=sp_item_group_item_list(group); - for (std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++){ + for (std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();++i){ sp_selection_to_guides_recursive(*i, wholegroups); } } else { @@ -3004,7 +3004,7 @@ void sp_selection_to_guides(SPDesktop *desktop) // and its entry in the selection list is invalid (crash). // Therefore: first convert all, then delete all. - for (std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++){ + for (std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();++i){ sp_selection_to_guides_recursive(*i, wholegroups); } @@ -3056,6 +3056,7 @@ void sp_selection_symbol(SPDesktop *desktop, bool /*apply*/ ) doc->ensureUpToDate(); std::vector<SPObject*> items(selection->list()); + sort(items.begin(),items.end(),sp_object_compare_position_bool); // Keep track of parent, this is where <use> will be inserted. Inkscape::XML::Node *the_first_repr = items[0]->getRepr(); @@ -3105,7 +3106,9 @@ void sp_selection_symbol(SPDesktop *desktop, bool /*apply*/ ) symbol_repr->setAttribute("style", the_group->getAttribute("style")); symbol_repr->setAttribute("class", the_group->getAttribute("class")); - symbol_repr->setAttribute("id", the_group->getAttribute("id") ); + Glib::ustring id = the_group->getAttribute("id"); + the_group->setAttribute("id", id + "_transform"); + symbol_repr->setAttribute("id", id); // This should eventually be replaced by 'refX' and 'refY' once SVG WG approves it. // It is done here for round-tripping @@ -3115,14 +3118,11 @@ void sp_selection_symbol(SPDesktop *desktop, bool /*apply*/ ) the_group->getAttribute("inkscape:transform-center-y")); the_group->setAttribute("style", NULL); - Glib::ustring id = symbol_repr->attribute("id"); - id += "_transform"; - the_group->setAttribute("id", id); } // Move selected items to new <symbol> - for (std::vector<SPObject*>::const_iterator i=items.begin();i!=items.end();i++){ + for (std::vector<SPObject*>::const_reverse_iterator i=items.rbegin();i!=items.rend();++i){ Inkscape::XML::Node *repr = (*i)->getRepr(); repr->parent()->removeChild(repr); symbol_repr->addChild(repr,NULL); @@ -3206,7 +3206,7 @@ void sp_selection_unsymbol(SPDesktop *desktop) } } - for (std::vector<SPObject*>::const_reverse_iterator i=children.rbegin();i!=children.rend();i++){ + for (std::vector<SPObject*>::const_reverse_iterator i=children.rbegin();i!=children.rend();++i){ Inkscape::XML::Node *repr = (*i)->getRepr(); repr->parent()->removeChild(repr); group->addChild(repr,NULL); @@ -3290,7 +3290,7 @@ sp_selection_tile(SPDesktop *desktop, bool apply) // create a list of duplicates std::vector<Inkscape::XML::Node*> repr_copies; - for (std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++){ + for (std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();++i){ Inkscape::XML::Node *dup = (*i)->getRepr()->duplicate(xml_doc); repr_copies.push_back(dup); } @@ -3299,7 +3299,7 @@ sp_selection_tile(SPDesktop *desktop, bool apply) if (apply) { // delete objects so that their clones don't get alerted; this object will be restored shortly - for (std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++){ + for (std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();++i){ SPObject *item = *i; item->deleteObject(false); } @@ -3373,7 +3373,7 @@ void sp_selection_untile(SPDesktop *desktop) bool did = false; std::vector<SPItem*> items(selection->itemList()); - for (std::vector<SPItem*>::const_reverse_iterator i=items.rbegin();i!=items.rend();i++){ + for (std::vector<SPItem*>::const_reverse_iterator i=items.rbegin();i!=items.rend();++i){ SPItem *item = *i; SPStyle *style = item->style; @@ -3442,7 +3442,7 @@ void sp_selection_get_export_hints(Inkscape::Selection *selection, Glib::ustring bool xdpi_search = TRUE; bool ydpi_search = TRUE; - for (std::vector<Inkscape::XML::Node*>::const_iterator i=reprlst.begin();filename_search&&xdpi_search&&ydpi_search&&i!=reprlst.end();i++){ + for (std::vector<Inkscape::XML::Node*>::const_iterator i=reprlst.begin();filename_search&&xdpi_search&&ydpi_search&&i!=reprlst.end();++i){ gchar const *dpi_string; Inkscape::XML::Node *repr = *i; @@ -3493,7 +3493,6 @@ void sp_document_get_export_hints(SPDocument *doc, Glib::ustring &filename, floa *xdpi = atof(dpi_string); } - dpi_string = NULL; dpi_string = repr->attribute("inkscape:export-ydpi"); if (dpi_string != NULL) { *ydpi = atof(dpi_string); @@ -3743,8 +3742,8 @@ void sp_selection_set_clipgroup(SPDesktop *desktop) Inkscape::XML::Node *inner = xml_doc->createElement("svg:g"); inner->setAttribute("inkscape:label", "Clip"); - for(std::vector<Inkscape::XML::Node*>::const_iterator i=p.begin();i!=p.end();i++){ - Inkscape::XML::Node *current = *i; + for(std::vector<Inkscape::XML::Node*>::const_iterator i=p.begin();i!=p.end();++i){ + Inkscape::XML::Node *current = *i; if (current->parent() == topmost_parent) { Inkscape::XML::Node *spnew = current->duplicate(xml_doc); @@ -3879,12 +3878,12 @@ void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_ apply_to_items.push_back(SP_ITEM(desktop->currentLayer())); } - for (std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++) { + for (std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();++i) { if((!topmost && !apply_to_layer && *i == items.front()) || (topmost && !apply_to_layer && *i == items.back()) - || apply_to_layer){ + || apply_to_layer){ - Geom::Affine oldtr=(*i)->transform; + Geom::Affine oldtr=(*i)->transform; (*i)->doWriteTransform((*i)->getRepr(), (*i)->i2doc_affine()); Inkscape::XML::Node *dup = (*i)->getRepr()->duplicate(xml_doc); (*i)->doWriteTransform((*i)->getRepr(), oldtr); @@ -3896,7 +3895,7 @@ void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_ else { items_to_select.push_back(*i); } - continue; + continue; }else{ apply_to_items.push_back(*i); items_to_select.push_back(*i); @@ -3914,7 +3913,7 @@ void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_ group->setAttribute("inkscape:groupmode", "maskhelper"); std::vector<Inkscape::XML::Node*> reprs_to_group; - for (std::vector<SPItem*>::const_iterator i = apply_to_items.begin(); i != apply_to_items.end(); i++) { + for (std::vector<SPItem*>::const_iterator i = apply_to_items.begin(); i != apply_to_items.end(); ++i) { reprs_to_group.push_back(static_cast<SPObject*>(*i)->getRepr()); } items_to_select.clear(); @@ -3935,13 +3934,13 @@ void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_ gchar const *attributeName = apply_clip_path ? "clip-path" : "mask"; - for (std::vector<SPItem*>::const_reverse_iterator i = apply_to_items.rbegin(); i != apply_to_items.rend(); i++) { + for (std::vector<SPItem*>::const_reverse_iterator i = apply_to_items.rbegin(); i != apply_to_items.rend(); ++i) { SPItem *item = reinterpret_cast<SPItem *>(*i); // inverted object transform should be applied to a mask object, // as mask is calculated in user space (after applying transform) std::vector<Inkscape::XML::Node*> mask_items_dup; - for(std::vector<Inkscape::XML::Node*>::const_iterator it=mask_items.begin();it!=mask_items.end();it++) - mask_items_dup.push_back((*it)->duplicate(xml_doc)); + for(std::vector<Inkscape::XML::Node*>::const_iterator it=mask_items.begin();it!=mask_items.end();++it) + mask_items_dup.push_back((*it)->duplicate(xml_doc)); Inkscape::XML::Node *current = SP_OBJECT(*i)->getRepr(); // Node to apply mask to Inkscape::XML::Node *apply_mask_to = current; @@ -3980,7 +3979,7 @@ void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_ } - for (std::vector<SPItem*>::const_iterator i = items_to_delete.begin(); i != items_to_delete.end(); i++) { + for (std::vector<SPItem*>::const_iterator i = items_to_delete.begin(); i != items_to_delete.end(); ++i) { SPObject *item = reinterpret_cast<SPObject*>(*i); item->deleteObject(false); items_to_select.erase(remove(items_to_select.begin(), items_to_select.end(), item), items_to_select.end()); @@ -4027,7 +4026,7 @@ void sp_selection_unset_mask(SPDesktop *desktop, bool apply_clip_path) { // SPObject* refers to a group containing the clipped path or mask itself, // whereas SPItem* refers to the item being clipped or masked - for (std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++){ + for (std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();++i){ if (remove_original) { // remember referenced mask/clippath, so orphaned masks can be moved back to document SPItem *item = *i; diff --git a/src/selection-describer.cpp b/src/selection-describer.cpp index 8304db684..ddc7a0d10 100644 --- a/src/selection-describer.cpp +++ b/src/selection-describer.cpp @@ -46,7 +46,7 @@ char* collect_terms (const std::vector<SPItem*> &items) std::stringstream ss; bool first = true; - for ( std::vector<SPItem*>::const_iterator iter=items.begin();iter!=items.end();iter++ ) { + for ( std::vector<SPItem*>::const_iterator iter=items.begin();iter!=items.end();++iter ) { SPItem *item = *iter; if (item) { const char *term = item->displayName(); @@ -65,7 +65,7 @@ static int count_terms (const std::vector<SPItem*> &items) { GSList *check = NULL; int count=0; - for ( std::vector<SPItem*>::const_iterator iter=items.begin();iter!=items.end();iter++ ) { + for ( std::vector<SPItem*>::const_iterator iter=items.begin();iter!=items.end();++iter ) { SPItem *item = *iter; if (item) { const char *term = item->displayName(); @@ -82,7 +82,7 @@ static int count_terms (const std::vector<SPItem*> &items) static int count_filtered (const std::vector<SPItem*> &items) { int count=0; - for ( std::vector<SPItem*>::const_iterator iter=items.begin();iter!=items.end();iter++ ) { + for ( std::vector<SPItem*>::const_iterator iter=items.begin();iter!=items.end();++iter ) { SPItem *item = *iter; if (item) { count += item->isFiltered(); diff --git a/src/selection.cpp b/src/selection.cpp index 77a507eec..020912381 100644 --- a/src/selection.cpp +++ b/src/selection.cpp @@ -255,7 +255,7 @@ void Selection::addList(std::vector<SPItem*> const &list) { _invalidateCachedLists(); - for ( std::vector<SPItem*>::const_iterator iter=list.begin();iter!=list.end();iter++ ) { + for ( std::vector<SPItem*>::const_iterator iter=list.begin();iter!=list.end(); ++iter) { SPObject *obj = *iter; if (includes(obj)) continue; _add (obj); @@ -267,7 +267,7 @@ void Selection::addList(std::vector<SPItem*> const &list) { void Selection::setReprList(std::vector<XML::Node*> const &list) { _clear(); - for ( std::vector<XML::Node*>::const_reverse_iterator iter=list.rbegin();iter!=list.rend();iter++ ) { + for ( std::vector<XML::Node*>::const_reverse_iterator iter=list.rbegin();iter!=list.rend(); ++iter) { SPObject *obj=_objectForXMLNode(*iter); if (obj) { _add(obj); @@ -286,7 +286,7 @@ std::vector<SPObject*> const &Selection::list() { if(!_objs_vector.empty()) return _objs_vector; - for ( std::list<SPObject*>::const_iterator iter=_objs.begin();iter!=_objs.end();iter++ ) { + for ( std::list<SPObject*>::const_iterator iter=_objs.begin();iter!=_objs.end(); ++iter) { _objs_vector.push_back(*iter); } return _objs_vector; @@ -298,7 +298,7 @@ std::vector<SPItem*> const &Selection::itemList() { return _items; } - for ( std::list<SPObject*>::const_iterator iter=_objs.begin();iter!=_objs.end();iter++ ) { + for ( std::list<SPObject*>::const_iterator iter=_objs.begin();iter!=_objs.end(); ++iter) { SPObject *obj=*iter; if (SP_IS_ITEM(obj)) { _items.push_back(SP_ITEM(obj)); @@ -310,7 +310,7 @@ std::vector<SPItem*> const &Selection::itemList() { std::vector<XML::Node*> const &Selection::reprList() { if (!_reprs.empty()) { return _reprs; } std::vector<SPItem*> list = itemList(); - for ( std::vector<SPItem*>::const_iterator iter=list.begin();iter!=list.end();iter++ ) { + for ( std::vector<SPItem*>::const_iterator iter=list.begin();iter!=list.end(); ++iter) { SPObject *obj = *iter; _reprs.push_back(obj->getRepr()); } @@ -372,7 +372,7 @@ SPItem *Selection::_sizeistItem(bool sml, Selection::CompareSize compare) { gdouble max = sml ? 1e18 : 0; SPItem *ist = NULL; - for ( std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++ ) { + for ( std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end(); ++i) { Geom::OptRect obox = SP_ITEM(*i)->desktopPreferredBounds(); if (!obox || obox.isEmpty()) continue; Geom::Rect bbox = *obox; @@ -404,7 +404,7 @@ Geom::OptRect Selection::geometricBounds() const std::vector<SPItem*> const items = const_cast<Selection *>(this)->itemList(); Geom::OptRect bbox; - for ( std::vector<SPItem*>::const_iterator iter=items.begin();iter!=items.end();iter++ ) { + for ( std::vector<SPItem*>::const_iterator iter=items.begin();iter!=items.end(); ++iter) { bbox.unionWith(SP_ITEM(*iter)->desktopGeometricBounds()); } return bbox; @@ -415,7 +415,7 @@ Geom::OptRect Selection::visualBounds() const std::vector<SPItem*> const items = const_cast<Selection *>(this)->itemList(); Geom::OptRect bbox; - for ( std::vector<SPItem*>::const_iterator iter=items.begin();iter!=items.end();iter++ ) { + for ( std::vector<SPItem*>::const_iterator iter=items.begin();iter!=items.end(); ++iter) { bbox.unionWith(SP_ITEM(*iter)->desktopVisualBounds()); } return bbox; @@ -436,7 +436,7 @@ Geom::OptRect Selection::documentBounds(SPItem::BBoxType type) const std::vector<SPItem*> const items = const_cast<Selection *>(this)->itemList(); if (items.empty()) return bbox; - for ( std::vector<SPItem*>::const_iterator iter=items.begin();iter!=items.end();iter++ ) { + for ( std::vector<SPItem*>::const_iterator iter=items.begin();iter!=items.end(); ++iter) { SPItem *item = SP_ITEM(*iter); bbox |= item->documentBounds(type); } @@ -463,19 +463,21 @@ boost::optional<Geom::Point> Selection::center() const { } std::vector<Inkscape::SnapCandidatePoint> Selection::getSnapPoints(SnapPreferences const *snapprefs) const { - std::vector<SPItem*> const items = const_cast<Selection *>(this)->itemList(); - - SnapPreferences snapprefs_dummy = *snapprefs; // create a local copy of the snapping prefs - snapprefs_dummy.setTargetSnappable(Inkscape::SNAPTARGET_ROTATION_CENTER, false); // locally disable snapping to the item center std::vector<Inkscape::SnapCandidatePoint> p; - for ( std::vector<SPItem*>::const_iterator iter=items.begin();iter!=items.end();iter++ ) { - SPItem *this_item = *iter; - this_item->getSnappoints(p, &snapprefs_dummy); - - //Include the transformation origin for snapping - //For a selection or group only the overall center is considered, not for each item individually - if (snapprefs != NULL && snapprefs->isTargetSnappable(Inkscape::SNAPTARGET_ROTATION_CENTER)) { - p.push_back(Inkscape::SnapCandidatePoint(this_item->getCenter(), SNAPSOURCE_ROTATION_CENTER)); + + if (snapprefs != NULL){ + SnapPreferences snapprefs_dummy = *snapprefs; // create a local copy of the snapping prefs + snapprefs_dummy.setTargetSnappable(Inkscape::SNAPTARGET_ROTATION_CENTER, false); // locally disable snapping to the item center + std::vector<SPItem*> const items = const_cast<Selection *>(this)->itemList(); + for ( std::vector<SPItem*>::const_iterator iter=items.begin();iter!=items.end(); ++iter) { + SPItem *this_item = *iter; + this_item->getSnappoints(p, &snapprefs_dummy); + + //Include the transformation origin for snapping + //For a selection or group only the overall center is considered, not for each item individually + if (snapprefs->isTargetSnappable(Inkscape::SNAPTARGET_ROTATION_CENTER)) { + p.push_back(Inkscape::SnapCandidatePoint(this_item->getCenter(), SNAPSOURCE_ROTATION_CENTER)); + } } } @@ -484,7 +486,7 @@ std::vector<Inkscape::SnapCandidatePoint> Selection::getSnapPoints(SnapPreferenc void Selection::_removeObjectDescendants(SPObject *obj) { std::vector<SPObject*> toremove; - for ( std::list<SPObject*>::const_iterator iter=_objs.begin();iter!=_objs.end();iter++ ) { + for ( std::list<SPObject*>::const_iterator iter=_objs.begin();iter!=_objs.end(); ++iter) { SPObject *sel_obj= dynamic_cast<SPObject*>(*iter); SPObject *parent = sel_obj->parent; while (parent) { @@ -495,7 +497,7 @@ void Selection::_removeObjectDescendants(SPObject *obj) { parent = parent->parent; } } - for ( std::vector<SPObject*>::const_iterator iter=toremove.begin();iter!=toremove.end();iter++ ) { + for ( std::vector<SPObject*>::const_iterator iter=toremove.begin();iter!=toremove.end(); ++iter) { _remove(*iter); } } @@ -522,7 +524,7 @@ SPObject *Selection::_objectForXMLNode(Inkscape::XML::Node *repr) const { size_t Selection::numberOfLayers() { std::vector<SPItem*> const items = const_cast<Selection *>(this)->itemList(); std::set<SPObject*> layers; - for ( std::vector<SPItem*>::const_iterator iter=items.begin();iter!=items.end();iter++ ) { + for ( std::vector<SPItem*>::const_iterator iter=items.begin();iter!=items.end(); ++iter) { SPObject *layer = _layers->layerForObject(*iter); layers.insert(layer); } @@ -532,7 +534,7 @@ size_t Selection::numberOfLayers() { size_t Selection::numberOfParents() { std::vector<SPItem*> const items = const_cast<Selection *>(this)->itemList(); std::set<SPObject*> parents; - for ( std::vector<SPItem*>::const_iterator iter=items.begin();iter!=items.end();iter++ ) { + for ( std::vector<SPItem*>::const_iterator iter=items.begin();iter!=items.end(); ++iter) { SPObject *parent = (*iter)->parent; parents.insert(parent); } diff --git a/src/seltrans.cpp b/src/seltrans.cpp index f7562923f..f010a687d 100644 --- a/src/seltrans.cpp +++ b/src/seltrans.cpp @@ -31,6 +31,7 @@ #include "knot.h" #include "message-stack.h" #include "snap.h" +#include "pure-transform.h" #include "selection.h" #include "ui/tools/select-tool.h" #include "sp-item.h" @@ -240,7 +241,7 @@ void Inkscape::SelTrans::setCenter(Geom::Point const &p) // Write the new center position into all selected items std::vector<SPItem*> items=_desktop->selection->itemList(); - for ( std::vector<SPItem*>::const_iterator iter=items.begin();iter!=items.end();iter++ ) { + for ( std::vector<SPItem*>::const_iterator iter=items.begin();iter!=items.end(); ++iter) { SPItem *it = SP_ITEM(*iter); it->setCenter(p); // only set the value; updating repr and document_done will be done once, on ungrab @@ -270,7 +271,7 @@ void Inkscape::SelTrans::grab(Geom::Point const &p, gdouble x, gdouble y, bool s } std::vector<SPItem*> items=_desktop->selection->itemList(); - for ( std::vector<SPItem*>::const_iterator iter=items.begin();iter!=items.end();iter++ ) { + for ( std::vector<SPItem*>::const_iterator iter=items.begin();iter!=items.end(); ++iter) { SPItem *it = static_cast<SPItem*>(sp_object_ref(*iter, NULL)); _items.push_back(it); _items_const.push_back(it); @@ -492,7 +493,7 @@ void Inkscape::SelTrans::ungrab() if (_center_is_set) { // we were dragging center; update reprs and commit undoable action std::vector<SPItem*> items=_desktop->selection->itemList(); - for ( std::vector<SPItem*>::const_iterator iter=items.begin();iter!=items.end();iter++ ) { + for ( std::vector<SPItem*>::const_iterator iter=items.begin();iter!=items.end(); ++iter) { SPItem *it = *iter; it->updateRepr(); } @@ -533,7 +534,7 @@ void Inkscape::SelTrans::stamp() _stamp_cache = l; } - for(std::vector<SPItem*>::const_iterator x=l.begin();x!=l.end();x++) { + for(std::vector<SPItem*>::const_iterator x=l.begin();x!=l.end(); ++x) { SPItem *original_item = *x; Inkscape::XML::Node *original_repr = original_item->getRepr(); @@ -711,7 +712,7 @@ void Inkscape::SelTrans::handleClick(SPKnot */*knot*/, guint state, SPSelTransHa if (state & GDK_SHIFT_MASK) { // Unset the center position for all selected items std::vector<SPItem*> items=_desktop->selection->itemList(); - for ( std::vector<SPItem*>::const_iterator iter=items.begin();iter!=items.end();iter++ ) { + for ( std::vector<SPItem*>::const_iterator iter=items.begin();iter!=items.end(); ++iter) { SPItem *it = *iter; it->unsetCenter(); it->updateRepr(); @@ -897,10 +898,7 @@ gboolean Inkscape::SelTrans::scaleRequest(Geom::Point &pt, guint state) // When scaling by an integer, snapping is not needed } else { // In all other cases we should try to snap now - SnapManager &m = _desktop->namedview->snap_manager; - m.setup(_desktop, false, _items_const); - - Inkscape::SnappedPoint bb, sn; + Inkscape::PureScale *bb, *sn; if ((state & GDK_CONTROL_MASK) || _desktop->isToolboxButtonActive ("lock")) { // Scale is locked to a 1:1 aspect ratio, so that s[X] must be made to equal s[Y]. @@ -915,30 +913,37 @@ gboolean Inkscape::SelTrans::scaleRequest(Geom::Point &pt, guint state) } // Snap along a suitable constraint vector from the origin. - bb = m.constrainedSnapScale(_bbox_points, _point, default_scale, _origin_for_bboxpoints); - sn = m.constrainedSnapScale(_snap_points, _point, geom_scale, _origin_for_specpoints); + + bb = new Inkscape::PureScaleConstrained(default_scale, _origin_for_bboxpoints); + sn = new Inkscape::PureScaleConstrained(geom_scale, _origin_for_specpoints); } else { /* Scale aspect ratio is unlocked */ - bb = m.freeSnapScale(_bbox_points, _point, default_scale, _origin_for_bboxpoints); - sn = m.freeSnapScale(_snap_points, _point, geom_scale, _origin_for_specpoints); + bb = new Inkscape::PureScale(default_scale, _origin_for_bboxpoints, false); + sn = new Inkscape::PureScale(geom_scale, _origin_for_specpoints, false); } + SnapManager &m = _desktop->namedview->snap_manager; + m.setup(_desktop, false, _items_const); + m.snapTransformed(_bbox_points, _point, (*bb)); + m.snapTransformed(_snap_points, _point, (*sn)); + m.unSetup(); // These lines below are duplicated in stretchRequest - if (bb.getSnapped() || sn.getSnapped()) { - if (bb.getSnapped()) { - if (!bb.isOtherSnapBetter(sn, false)) { + //TODO: Eliminate this code duplication + if (bb->best_snapped_point.getSnapped() || sn->best_snapped_point.getSnapped()) { + if (bb->best_snapped_point.getSnapped()) { + if (!bb->best_snapped_point.isOtherSnapBetter(sn->best_snapped_point, false)) { // We snapped the bbox (which is either visual or geometric) - _desktop->snapindicator->set_new_snaptarget(bb); - default_scale = Geom::Scale(bb.getTransformation()); + _desktop->snapindicator->set_new_snaptarget(bb->best_snapped_point); + default_scale = bb->getScaleSnapped(); // Calculate the new transformation and update the handle position pt = _calcAbsAffineDefault(default_scale); } - } else if (sn.getSnapped()) { - _desktop->snapindicator->set_new_snaptarget(sn); + } else if (sn->best_snapped_point.getSnapped()) { + _desktop->snapindicator->set_new_snaptarget(sn->best_snapped_point); // We snapped the special points (e.g. nodes), which are not at the visual bbox // The handle location however (pt) might however be at the visual bbox, so we // will have to calculate pt taking the stroke width into account - geom_scale = Geom::Scale(sn.getTransformation()); + geom_scale = sn->getScaleSnapped(); pt = _calcAbsAffineGeom(geom_scale); } } else { @@ -946,7 +951,9 @@ gboolean Inkscape::SelTrans::scaleRequest(Geom::Point &pt, guint state) _calcAbsAffineDefault(default_scale); _desktop->snapindicator->remove_snaptarget(); } - m.unSetup(); + + delete bb; + delete sn; } /* Status text */ @@ -1003,21 +1010,22 @@ gboolean Inkscape::SelTrans::stretchRequest(SPSelTransHandle const &handle, Geom SnapManager &m = _desktop->namedview->snap_manager; m.setup(_desktop, false, _items_const); - Inkscape::SnappedPoint bb, sn; - g_assert(bb.getSnapped() == false); // Check initialization to catch any regression - bool symmetrical = state & GDK_CONTROL_MASK; - bb = m.constrainedSnapStretch(_bbox_points, _point, Geom::Coord(default_scale[axis]), _origin_for_bboxpoints, Geom::Dim2(axis), symmetrical); - sn = m.constrainedSnapStretch(_snap_points, _point, Geom::Coord(geom_scale[axis]), _origin_for_specpoints, Geom::Dim2(axis), symmetrical); + Inkscape::PureStretchConstrained bb = Inkscape::PureStretchConstrained(Geom::Coord(default_scale[axis]), _origin_for_bboxpoints, Geom::Dim2(axis), symmetrical); + Inkscape::PureStretchConstrained sn = Inkscape::PureStretchConstrained(Geom::Coord(geom_scale[axis]), _origin_for_specpoints, Geom::Dim2(axis), symmetrical); - if (bb.getSnapped()) { + m.snapTransformed(_bbox_points, _point, bb); + m.snapTransformed(_snap_points, _point, sn); + m.unSetup(); + + if (bb.best_snapped_point.getSnapped()) { // We snapped the bbox (which is either visual or geometric) - default_scale[axis] = bb.getTransformation()[axis]; + default_scale[axis] = bb.getMagnitude(); } - if (sn.getSnapped()) { - geom_scale[axis] = sn.getTransformation()[axis]; + if (sn.best_snapped_point.getSnapped()) { + geom_scale[axis] = sn.getMagnitude(); } if (symmetrical) { @@ -1028,21 +1036,21 @@ gboolean Inkscape::SelTrans::stretchRequest(SPSelTransHandle const &handle, Geom } // These lines below are duplicated in scaleRequest - if (bb.getSnapped() || sn.getSnapped()) { - if (bb.getSnapped()) { - if (!bb.isOtherSnapBetter(sn, false)) { + if (bb.best_snapped_point.getSnapped() || sn.best_snapped_point.getSnapped()) { + if (bb.best_snapped_point.getSnapped()) { + if (!bb.best_snapped_point.isOtherSnapBetter(sn.best_snapped_point, false)) { // We snapped the bbox (which is either visual or geometric) - _desktop->snapindicator->set_new_snaptarget(bb); - default_scale = Geom::Scale(bb.getTransformation()); + _desktop->snapindicator->set_new_snaptarget(bb.best_snapped_point); + default_scale = bb.getStretchSnapped(); // Calculate the new transformation and update the handle position pt = _calcAbsAffineDefault(default_scale); } - } else if (sn.getSnapped()) { - _desktop->snapindicator->set_new_snaptarget(sn); + } else if (sn.best_snapped_point.getSnapped()) { + _desktop->snapindicator->set_new_snaptarget(sn.best_snapped_point); // We snapped the special points (e.g. nodes), which are not at the visual bbox // The handle location however (pt) might however be at the visual bbox, so we // will have to calculate pt taking the stroke width into account - geom_scale = Geom::Scale(sn.getTransformation()); + geom_scale = sn.getStretchSnapped(); pt = _calcAbsAffineGeom(geom_scale); } } else { @@ -1050,8 +1058,6 @@ gboolean Inkscape::SelTrans::stretchRequest(SPSelTransHandle const &handle, Geom _calcAbsAffineDefault(default_scale); _desktop->snapindicator->remove_snaptarget(); } - - m.unSetup(); } // status text @@ -1156,16 +1162,14 @@ gboolean Inkscape::SelTrans::skewRequest(SPSelTransHandle const &handle, Geom::P SnapManager &m = _desktop->namedview->snap_manager; m.setup(_desktop, false, _items_const); - Geom::Point cvec; cvec[dim_b] = 1.; - Inkscape::Snapper::SnapConstraint const constraint(cvec); - // When skewing, we cannot snap the corners of the bounding box, see the comment in "constrainedSnapSkew" for details - Geom::Point const s(skew[dim_a], scale[dim_a]); - Inkscape::SnappedPoint sn = m.constrainedSnapSkew(_snap_points, _point, constraint, s, _origin, Geom::Dim2(dim_b)); + // When skewing, we cannot snap the corners of the bounding box, see the comment in PureSkewConstrained for details + Inkscape::PureSkewConstrained sn = Inkscape::PureSkewConstrained(skew[dim_a], scale[dim_a], _origin, Geom::Dim2(dim_b)); + m.snapTransformed(_snap_points, _point, sn); - if (sn.getSnapped()) { + if (sn.best_snapped_point.getSnapped()) { // We snapped something, so change the skew to reflect it - skew[dim_a] = sn.getTransformation()[0]; - _desktop->snapindicator->set_new_snaptarget(sn); + skew[dim_a] = sn.getSkewSnapped(); + _desktop->snapindicator->set_new_snaptarget(sn.best_snapped_point); } else { _desktop->snapindicator->remove_snaptarget(); } @@ -1243,13 +1247,14 @@ gboolean Inkscape::SelTrans::rotateRequest(Geom::Point &pt, guint state) SnapManager &m = _desktop->namedview->snap_manager; m.setup(_desktop, false, _items_const); // When rotating, we cannot snap the corners of the bounding box, see the comment in "constrainedSnapRotate" for details - Inkscape::SnappedPoint sn = m.constrainedSnapRotate(_snap_points, _point, radians, _origin); + Inkscape::PureRotateConstrained sn = Inkscape::PureRotateConstrained(radians, _origin); + m.snapTransformed(_snap_points, _point, sn); m.unSetup(); - if (sn.getSnapped()) { - _desktop->snapindicator->set_new_snaptarget(sn); + if (sn.best_snapped_point.getSnapped()) { + _desktop->snapindicator->set_new_snaptarget(sn.best_snapped_point); // We snapped something, so change the rotation to reflect it - radians = sn.getTransformation()[0]; + radians = sn.getAngleSnapped(); r1 = Geom::Rotate(0); r2 = Geom::Rotate(radians); } else { @@ -1352,30 +1357,19 @@ void Inkscape::SelTrans::moveTo(Geom::Point const &xy, guint state) bool const control = (state & GDK_CONTROL_MASK); bool const shift = (state & GDK_SHIFT_MASK); - if (alt) { - - // Alt pressed means: move only by integer multiples of the grid spacing - - if (control) { // ... if also constrained to the orthogonal axes - if (fabs(dxy[Geom::X]) > fabs(dxy[Geom::Y])) { - dxy[Geom::Y] = 0; - } else { - dxy[Geom::X] = 0; - } + if (control) { // constrained to the orthogonal axes + if (fabs(dxy[Geom::X]) > fabs(dxy[Geom::Y])) { + dxy[Geom::Y] = 0; + } else { + dxy[Geom::X] = 0; } + } + + if (alt) {// Alt pressed means: move only by integer multiples of the grid spacing m.setup(_desktop, true, _items_const); dxy = m.multipleOfGridPitch(dxy, _point); m.unSetup(); - } else if (shift) { - if (control) { // shift & control: constrained movement without snapping - if (fabs(dxy[Geom::X]) > fabs(dxy[Geom::Y])) { - dxy[Geom::Y] = 0; - } else { - dxy[Geom::X] = 0; - } - } - } else { //!shift: with snapping - + } else if (!shift) { //!shift: with snapping /* We're snapping to things, possibly with a constraint to horizontal or ** vertical movement. Obtain a list of possible translations and then ** pick the smallest. @@ -1386,52 +1380,55 @@ void Inkscape::SelTrans::moveTo(Geom::Point const &xy, guint state) /* This will be our list of possible translations */ std::list<Inkscape::SnappedPoint> s; + Inkscape::PureTranslate *bb, *sn; + if (control) { // constrained movement with snapping /* Snap to things, and also constrain to horizontal or vertical movement */ - unsigned int dim = fabs(dxy[Geom::X]) > fabs(dxy[Geom::Y]) ? Geom::X : Geom::Y; + Geom::Dim2 dim = fabs(dxy[Geom::X]) > fabs(dxy[Geom::Y]) ? Geom::X : Geom::Y; // When doing a constrained translation, all points will move in the same direction, i.e. // either horizontally or vertically. Therefore we only have to specify the direction of // the constraint-line once. The constraint lines are parallel, but might not be colinear. // Therefore we will have to set the point through which the constraint-line runs - // individually for each point to be snapped; this will be handled however by _snapTransformed() - Geom::Point cvec; cvec[dim] = 1.; - s.push_back(m.constrainedSnapTranslate(_bbox_points, - _point, - Inkscape::Snapper::SnapConstraint(cvec), - dxy)); - - s.push_back(m.constrainedSnapTranslate(_snap_points, - _point, - Inkscape::Snapper::SnapConstraint(cvec), - dxy)); + // individually for each point to be snapped; this will be handled however by snapTransformed() + bb = new Inkscape::PureTranslateConstrained(dxy[dim], dim); + sn = new Inkscape::PureTranslateConstrained(dxy[dim], dim); } else { // !control - - // Let's leave this timer code here for a while. I'll probably need it in the near future (Diederik van Lierop) - /* GTimeVal starttime; - GTimeVal endtime; - g_get_current_time(&starttime); */ - /* Snap to things with no constraint */ - s.push_back(m.freeSnapTranslate(_bbox_points, _point, dxy)); - s.push_back(m.freeSnapTranslate(_snap_points, _point, dxy)); - - /*g_get_current_time(&endtime); - double elapsed = ((((double)endtime.tv_sec - starttime.tv_sec) * G_USEC_PER_SEC + (endtime.tv_usec - starttime.tv_usec))) / 1000.0; - std::cout << "Time spent snapping: " << elapsed << std::endl; */ + bb = new Inkscape::PureTranslate(dxy); + sn = new Inkscape::PureTranslate(dxy); } + // Let's leave this timer code here for a while. I'll probably need it in the near future (Diederik van Lierop) + /* GTimeVal starttime; + GTimeVal endtime; + g_get_current_time(&starttime); */ + + m.snapTransformed(_bbox_points, _point, (*bb)); + m.snapTransformed(_snap_points, _point, (*sn)); m.unSetup(); + /*g_get_current_time(&endtime); + double elapsed = ((((double)endtime.tv_sec - starttime.tv_sec) * G_USEC_PER_SEC + (endtime.tv_usec - starttime.tv_usec))) / 1000.0; + std::cout << "Time spent snapping: " << elapsed << std::endl; */ + /* Pick one */ Inkscape::SnappedPoint best_snapped_point; - for (std::list<Inkscape::SnappedPoint>::const_iterator i = s.begin(); i != s.end(); ++i) { - if (i->getSnapped()) { - if (best_snapped_point.isOtherSnapBetter(*i, true)) { - best_snapped_point = *i; - dxy = i->getTransformation(); - } - } + + bool sn_is_best = sn->best_snapped_point.getSnapped(); + bool bb_is_best = bb->best_snapped_point.getSnapped(); + + if (bb_is_best && sn_is_best) { + sn_is_best = bb->best_snapped_point.isOtherSnapBetter(sn->best_snapped_point, true); + bb_is_best = !sn_is_best; + } + + if (sn_is_best) { + best_snapped_point = sn->best_snapped_point; + dxy = sn->getTranslationSnapped(); + } else if (bb_is_best) { + best_snapped_point = bb->best_snapped_point; + dxy = bb->getTranslationSnapped(); } if (best_snapped_point.getSnapped()) { @@ -1609,7 +1606,7 @@ void Inkscape::SelTrans::_keepClosestPointOnly(Geom::Point const &p) } } - +// TODO: This code is duplicated in transform-handle-set.cpp; fix this! void Inkscape::SelTrans::getNextClosestPoint(bool reverse) { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); @@ -1635,6 +1632,12 @@ void Inkscape::SelTrans::getNextClosestPoint(bool reverse) } else { _snap_points.push_back(*_all_snap_sources_iter); } + + // Show the updated snap source now; otherwise it won't be shown until the selection is being moved again + SnapManager &m = _desktop->namedview->snap_manager; + m.setup(_desktop); + m.displaySnapsource(*_all_snap_sources_iter); + m.unSetup(); } } } diff --git a/src/shortcuts.cpp b/src/shortcuts.cpp index e72c16de0..194d4d2a4 100644 --- a/src/shortcuts.cpp +++ b/src/shortcuts.cpp @@ -575,7 +575,14 @@ static void read_shortcuts_file(char const *filename, bool const is_user_set) { } Inkscape::Verb *verb=Inkscape::Verb::getbyid(verb_name); - if (!verb) { + if (!verb +#if !HAVE_POTRACE + // Squash warning about disabled features + && strcmp(verb_name, "ToolPaintBucket") != 0 + && strcmp(verb_name, "SelectionTrace") != 0 + && strcmp(verb_name, "PaintBucketPrefs") != 0 +#endif + ) { g_warning("Unknown verb name: %s", verb_name); continue; } diff --git a/src/snap.cpp b/src/snap.cpp index 5a308777c..4721283c3 100644 --- a/src/snap.cpp +++ b/src/snap.cpp @@ -23,6 +23,7 @@ #include "snap-enums.h" #include "snapped-line.h" #include "snapped-curve.h" +#include "pure-transform.h" #include "display/canvas-grid.h" #include "display/snap-indicator.h" @@ -442,16 +443,11 @@ void SnapManager::guideConstrainedSnap(Geom::Point &p, SPGuide const &guideline) s.getPointIfSnapped(p); } -Inkscape::SnappedPoint SnapManager::_snapTransformed( +void SnapManager::snapTransformed( std::vector<Inkscape::SnapCandidatePoint> const &points, Geom::Point const &pointer, - bool constrained, - Inkscape::Snapper::SnapConstraint const &constraint, - Transformation transformation_type, - Geom::Point const &transformation, - Geom::Point const &origin, - Geom::Dim2 dim, - bool uniform) + Inkscape::PureTransform &transform + ) { /* We have a list of points, which we are proposing to transform in some way. We need to see ** if any of these points, when transformed, snap to anything. If they do, we return the @@ -459,47 +455,8 @@ Inkscape::SnappedPoint SnapManager::_snapTransformed( */ if (points.size() == 0) { - return Inkscape::SnappedPoint(pointer); - } - - std::vector<Inkscape::SnapCandidatePoint> transformed_points; - Geom::Rect bbox; - - long source_num = 0; - for (std::vector<Inkscape::SnapCandidatePoint>::const_iterator i = points.begin(); i != points.end(); ++i) { - - /* Work out the transformed version of this point */ - Geom::Point transformed = _transformPoint(*i, transformation_type, transformation, origin, dim, uniform); - - // add the current transformed point to the box hulling all transformed points - if (i == points.begin()) { - bbox = Geom::Rect(transformed, transformed); - } else { - bbox.expandTo(transformed); - } - - transformed_points.push_back(Inkscape::SnapCandidatePoint(transformed, (*i).getSourceType(), source_num, Inkscape::SNAPTARGET_UNDEFINED, Geom::OptRect())); - source_num++; - } - - /* The current best transformation */ - Geom::Point best_transformation = transformation; - - /* The current best metric for the best transformation; lower is better, Geom::infinity() - ** means that we haven't snapped anything. - */ - Inkscape::SnappedPoint best_snapped_point; - g_assert(best_snapped_point.getAlwaysSnap() == false); // Check initialization of snapped point - g_assert(best_snapped_point.getAtIntersection() == false); - - // Warnings for the devs - if (constrained && transformation_type == SCALE && !uniform) { - g_warning("Non-uniform constrained scaling is not supported!"); - } - - if (!constrained && transformation_type == ROTATE) { - // We do not yet allow for simultaneous rotation and scaling - g_warning("Unconstrained rotation is not supported!"); + transform.best_snapped_point = Inkscape::SnappedPoint(pointer); + return; } // We will try to snap a set of points, but we don't want to have a snap indicator displayed @@ -508,349 +465,22 @@ Inkscape::SnappedPoint SnapManager::_snapTransformed( bool _orig_snapindicator_status = _snapindicator; _snapindicator = false; - std::vector<Inkscape::SnapCandidatePoint>::iterator j = transformed_points.begin(); - - // std::cout << std::endl; - bool first_free_snap = true; - - for (std::vector<Inkscape::SnapCandidatePoint>::const_iterator i = points.begin(); i != points.end(); ++i) { - - /* Snap it */ - Inkscape::SnappedPoint snapped_point; - Inkscape::Snapper::SnapConstraint dedicated_constraint = constraint; - Geom::Point const b = ((*i).getPoint() - origin); // vector to original point (not the transformed point! required for rotations!) - - if (constrained) { - if (((transformation_type == SCALE || transformation_type == STRETCH) && uniform)) { - // When uniformly scaling, each point will have its own unique constraint line, - // running from the scaling origin to the original untransformed point. We will - // calculate that line here - dedicated_constraint = Inkscape::Snapper::SnapConstraint(origin, b); - } else if (transformation_type == ROTATE) { - Geom::Coord r = Geom::L2(b); // the radius of the circular constraint - dedicated_constraint = Inkscape::Snapper::SnapConstraint(origin, b, r); - } else if (transformation_type == STRETCH) { // when non-uniform stretching { - Geom::Point cvec; cvec[dim] = 1.; - dedicated_constraint = Inkscape::Snapper::SnapConstraint((*i).getPoint(), cvec); - } else if (transformation_type == TRANSLATE) { - // When doing a constrained translation, all points will move in the same direction, i.e. - // either horizontally or vertically. The lines along which they move are therefore all - // parallel, but might not be colinear. Therefore we will have to specify the point through - // which the constraint-line runs here, for each point individually. (we could also have done this - // earlier on, e.g. in seltrans.cpp but we're being lazy there and don't want to add an iteration loop) - dedicated_constraint = Inkscape::Snapper::SnapConstraint((*i).getPoint(), constraint.getDirection()); - } // else: leave the original constraint, e.g. for skewing - snapped_point = constrainedSnap(*j, dedicated_constraint, bbox); - } else { - bool const c1 = fabs(b[Geom::X]) < 1e-6; - bool const c2 = fabs(b[Geom::Y]) < 1e-6; - if (transformation_type == SCALE && (c1 || c2) && !(c1 && c2)) { - // When scaling, a point aligned either horizontally or vertically with the origin can only - // move in that specific direction; therefore it should only snap in that direction, otherwise - // we will get snapped points with an invalid transformation - Geom::Point cvec; cvec[c1] = 1.; - dedicated_constraint = Inkscape::Snapper::SnapConstraint(origin, cvec); - snapped_point = constrainedSnap(*j, dedicated_constraint, bbox); - } else { - // If we have a collection of SnapCandidatePoints, with mixed constrained snapping and free snapping - // requirements, then freeSnap might never see the SnapCandidatePoint with source_num == 0. The freeSnap() - // method in the object snapper depends on this, because only for source-num == 0 the target nodes will - // be collected. Therefore we enforce that the first SnapCandidatePoint that is to be freeSnapped always - // has source_num == 0; - // TODO: This is a bit ugly so fix this; do we need sourcenum for anything else? if we don't then get rid - // of it and explicitly communicate to the object snapper that this is a first point - if (first_free_snap) { - (*j).setSourceNum(0); - first_free_snap = false; - } - snapped_point = freeSnap(*j, bbox); - } - } - // std::cout << "dist = " << snapped_point.getSnapDistance() << std::endl; - snapped_point.setPointerDistance(Geom::L2(pointer - (*i).getPoint())); - - // Allow the snapindicator to be displayed again - _snapindicator = _orig_snapindicator_status; - - Geom::Point result; - - /*Find the transformation that describes where the snapped point has - ** ended up, and also the metric for this transformation. - */ - Geom::Point const a = snapped_point.getPoint() - origin; // vector to snapped point - //Geom::Point const b = (*i - origin); // vector to original point - - switch (transformation_type) { - case TRANSLATE: - result = snapped_point.getPoint() - (*i).getPoint(); - /* Consider the case in which a box is almost aligned with a grid in both - * horizontal and vertical directions. The distance to the intersection of - * the grid lines will always be larger then the distance to a single grid - * line. If we prefer snapping to an intersection over to a single - * grid line, then we cannot use "metric = Geom::L2(result)". Therefore the - * snapped distance will be used as a metric. Please note that the snapped - * distance to an intersection is defined as the distance to the nearest line - * of the intersection, and not to the intersection itself! - */ - // Only for translations, the relevant metric will be the real snapped distance, - // so we don't have to do anything special here - break; - case SCALE: - { - result = Geom::Point(Geom::infinity(), Geom::infinity()); - // If this point *i is horizontally or vertically aligned with - // the origin of the scaling, then it will scale purely in X or Y - // We can therefore only calculate the scaling in this direction - // and the scaling factor for the other direction should remain - // untouched (unless scaling is uniform of course) - for (int index = 0; index < 2; index++) { - if (fabs(b[index]) > 1e-4) { // if SCALING CAN occur in this direction - if (fabs(fabs(a[index]/b[index]) - fabs(transformation[index])) > 1e-7) { // if SNAPPING DID occur in this direction - result[index] = a[index] / b[index]; // then calculate it! - } - // we might have left result[1-index] = Geom::infinity() - // if scaling didn't occur in the other direction - } - } - if (uniform) { - if (fabs(result[0]) < fabs(result[1])) { - result[1] = result[0]; - } else { - result[0] = result[1]; - } - } - - // Compare the resulting scaling with the desired scaling - Geom::Point scale_metric = result - transformation; // One or both of its components might be Geom::infinity() - scale_metric[0] = fabs(scale_metric[0]); - scale_metric[1] = fabs(scale_metric[1]); - if (scale_metric[0] == Geom::infinity() || scale_metric[1] == Geom::infinity()) { - snapped_point.setSnapDistance(std::min(scale_metric[0], scale_metric[1])); - } else { - snapped_point.setSnapDistance(Geom::L2(scale_metric)); - } - snapped_point.setSecondSnapDistance(Geom::infinity()); - break; - } - case STRETCH: - result = Geom::Point(Geom::infinity(), Geom::infinity()); - if (fabs(b[dim]) > 1e-6) { // if STRETCHING will occur for this point - result[dim] = a[dim] / b[dim]; - result[1-dim] = uniform ? result[dim] : 1; - } else { // STRETCHING might occur for this point, but only when the stretching is uniform - if (uniform && fabs(b[1-dim]) > 1e-6) { - result[1-dim] = a[1-dim] / b[1-dim]; - result[dim] = result[1-dim]; - } - } - // Store the metric for this transformation as a virtual distance - snapped_point.setSnapDistance(std::abs(result[dim] - transformation[dim])); - snapped_point.setSecondSnapDistance(Geom::infinity()); - break; - case SKEW: - result[0] = (snapped_point.getPoint()[dim] - ((*i).getPoint())[dim]) / b[1 - dim]; // skew factor - result[1] = transformation[1]; // scale factor - // Store the metric for this transformation as a virtual distance - snapped_point.setSnapDistance(std::abs(result[0] - transformation[0])); - snapped_point.setSecondSnapDistance(Geom::infinity()); - break; - case ROTATE: - // a is vector to snapped point; b is vector to original point; now lets calculate angle between a and b - result[0] = atan2(Geom::dot(Geom::rot90(b), a), Geom::dot(b, a)); - result[1] = result[0]; // dummy value; how else should we store an angle in a point ;-) - if (Geom::L2(b) < 1e-9) { // points too close to the rotation center will not move. Don't try to snap these - // as they will always yield a perfect snap result if they're already snapped beforehand (e.g. - // when the transformation center has been snapped to a grid intersection in the selector tool) - snapped_point.setSnapDistance(Geom::infinity()); - // PS1: Apparently we don't have to do this for skewing, but why? - // PS2: We cannot easily filter these points upstream, e.g. in the grab() method (seltrans.cpp) - // because the rotation center will change when pressing shift, and grab() won't be recalled. - // Filtering could be done in handleRequest() (again in seltrans.cpp), by iterating through - // the snap candidates. But hey, we're iterating here anyway. - } else { - snapped_point.setSnapDistance(std::abs(result[0] - transformation[0])); - } - snapped_point.setSecondSnapDistance(Geom::infinity()); - break; - default: - g_assert_not_reached(); - } - - if (snapped_point.getSnapped()) { - // We snapped; keep track of the best snap - if (best_snapped_point.isOtherSnapBetter(snapped_point, true)) { - best_transformation = result; - best_snapped_point = snapped_point; - } - } else { - // So we didn't snap for this point - if (!best_snapped_point.getSnapped()) { - // ... and none of the points before snapped either - // We might still need to apply a constraint though, if we tried a constrained snap. And - // in case of a free snap we might have use for the transformed point, so let's return that - // point, whether it's constrained or not - if (best_snapped_point.isOtherSnapBetter(snapped_point, true) || points.size() == 1) { - // .. so we must keep track of the best non-snapped constrained point - best_transformation = result; - best_snapped_point = snapped_point; - } - } - } - - ++j; - } - - Geom::Coord best_metric; - if (transformation_type == SCALE) { - // When scaling, don't ever exit with one of scaling components uninitialized - for (int index = 0; index < 2; index++) { - if (fabs(best_transformation[index]) == Geom::infinity()) { - if (uniform && fabs(best_transformation[1-index]) < Geom::infinity()) { - best_transformation[index] = best_transformation[1-index]; - } else { - best_transformation[index] = transformation[index]; - } - } - } - } + transform.snap(this, points, pointer); - best_metric = best_snapped_point.getSnapDistance(); - best_snapped_point.setTransformation(best_transformation); - // Using " < 1e6" instead of " < Geom::infinity()" for catching some rounding errors - // These rounding errors might be caused by NRRects, see bug #1584301 - best_snapped_point.setSnapDistance(best_metric < 1e6 ? best_metric : Geom::infinity()); + // Allow the snapindicator to be displayed again + _snapindicator = _orig_snapindicator_status; if (_snapindicator) { - if (best_snapped_point.getSnapped()) { - _desktop->snapindicator->set_new_snaptarget(best_snapped_point); + if (transform.best_snapped_point.getSnapped()) { + _desktop->snapindicator->set_new_snaptarget(transform.best_snapped_point); } else { _desktop->snapindicator->remove_snaptarget(); } } - return best_snapped_point; -} - - -Inkscape::SnappedPoint SnapManager::freeSnapTranslate(std::vector<Inkscape::SnapCandidatePoint> const &p, - Geom::Point const &pointer, - Geom::Point const &tr) -{ - Inkscape::SnappedPoint result = _snapTransformed(p, pointer, false, Geom::Point(0,0), TRANSLATE, tr, Geom::Point(0,0), Geom::X, false); - - if (p.size() == 1) { - displaySnapsource(Inkscape::SnapCandidatePoint(result.getPoint(), p.at(0).getSourceType())); - } - return result; -} - -Inkscape::SnappedPoint SnapManager::constrainedSnapTranslate(std::vector<Inkscape::SnapCandidatePoint> const &p, - Geom::Point const &pointer, - Inkscape::Snapper::SnapConstraint const &constraint, - Geom::Point const &tr) -{ - Inkscape::SnappedPoint result = _snapTransformed(p, pointer, true, constraint, TRANSLATE, tr, Geom::Point(0,0), Geom::X, false); - - if (p.size() == 1) { - displaySnapsource(Inkscape::SnapCandidatePoint(result.getPoint(), p.at(0).getSourceType())); - } - - return result; -} - - -Inkscape::SnappedPoint SnapManager::freeSnapScale(std::vector<Inkscape::SnapCandidatePoint> const &p, - Geom::Point const &pointer, - Geom::Scale const &s, - Geom::Point const &o) -{ - Inkscape::SnappedPoint result = _snapTransformed(p, pointer, false, Geom::Point(0,0), SCALE, Geom::Point(s[Geom::X], s[Geom::Y]), o, Geom::X, false); - - if (p.size() == 1) { - displaySnapsource(Inkscape::SnapCandidatePoint(result.getPoint(), p.at(0).getSourceType())); - } - - return result; -} - - -Inkscape::SnappedPoint SnapManager::constrainedSnapScale(std::vector<Inkscape::SnapCandidatePoint> const &p, - Geom::Point const &pointer, - Geom::Scale const &s, - Geom::Point const &o) -{ - // When constrained scaling, only uniform scaling is supported. - Inkscape::SnappedPoint result = _snapTransformed(p, pointer, true, Geom::Point(0,0), SCALE, Geom::Point(s[Geom::X], s[Geom::Y]), o, Geom::X, true); - - if (p.size() == 1) { - displaySnapsource(Inkscape::SnapCandidatePoint(result.getPoint(), p.at(0).getSourceType())); - } - - return result; -} - -Inkscape::SnappedPoint SnapManager::constrainedSnapStretch(std::vector<Inkscape::SnapCandidatePoint> const &p, - Geom::Point const &pointer, - Geom::Coord const &s, - Geom::Point const &o, - Geom::Dim2 d, - bool u) -{ - Inkscape::SnappedPoint result = _snapTransformed(p, pointer, true, Geom::Point(0,0), STRETCH, Geom::Point(s, s), o, d, u); - - if (p.size() == 1) { - displaySnapsource(Inkscape::SnapCandidatePoint(result.getPoint(), p.at(0).getSourceType())); - } - - return result; -} - -Inkscape::SnappedPoint SnapManager::constrainedSnapSkew(std::vector<Inkscape::SnapCandidatePoint> const &p, - Geom::Point const &pointer, - Inkscape::Snapper::SnapConstraint const &constraint, - Geom::Point const &s, - Geom::Point const &o, - Geom::Dim2 d) -{ - // "s" contains skew factor in s[0], and scale factor in s[1] - - // Snapping the nodes of the bounding box of a selection that is being transformed, will only work if - // the transformation of the bounding box is equal to the transformation of the individual nodes. This is - // NOT the case for example when rotating or skewing. The bounding box itself cannot possibly rotate or skew, - // so it's corners have a different transformation. The snappers cannot handle this, therefore snapping - // of bounding boxes is not allowed here. - if (!p.empty()) { - g_assert(!(p.at(0).getSourceType() & Inkscape::SNAPSOURCE_BBOX_CATEGORY)); - } - - Inkscape::SnappedPoint result = _snapTransformed(p, pointer, true, constraint, SKEW, s, o, d, false); - - if (p.size() == 1) { - displaySnapsource(Inkscape::SnapCandidatePoint(result.getPoint(), p.at(0).getSourceType())); - } - - return result; -} - -Inkscape::SnappedPoint SnapManager::constrainedSnapRotate(std::vector<Inkscape::SnapCandidatePoint> const &p, - Geom::Point const &pointer, - Geom::Coord const &angle, - Geom::Point const &o) -{ - // Snapping the nodes of the bounding box of a selection that is being transformed, will only work if - // the transformation of the bounding box is equal to the transformation of the individual nodes. This is - // NOT the case for example when rotating or skewing. The bounding box itself cannot possibly rotate or skew, - // so it's corners have a different transformation. The snappers cannot handle this, therefore snapping - // of bounding boxes is not allowed here. - - Inkscape::SnappedPoint result = _snapTransformed(p, pointer, true, Geom::Point(0,0), ROTATE, Geom::Point(angle, angle), o, Geom::X, false); - - if (p.size() == 1) { - displaySnapsource(Inkscape::SnapCandidatePoint(result.getPoint(), p.at(0).getSourceType())); + if (points.size() == 1) { + displaySnapsource(Inkscape::SnapCandidatePoint(transform.best_snapped_point.getPoint(), points.at(0).getSourceType())); } - - return result; - } Inkscape::SnappedPoint SnapManager::findBestSnap(Inkscape::SnapCandidatePoint const &p, @@ -1080,7 +710,7 @@ void SnapManager::setupIgnoreSelection(SPDesktop const *desktop, Inkscape::Selection *sel = _desktop->selection; std::vector<SPItem*> const items = sel->itemList(); - for (std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++) { + for (std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();++i) { _items_to_ignore.push_back(*i); } } @@ -1090,51 +720,51 @@ SPDocument *SnapManager::getDocument() const return _named_view->document; } -Geom::Point SnapManager::_transformPoint(Inkscape::SnapCandidatePoint const &p, - Transformation const transformation_type, - Geom::Point const &transformation, - Geom::Point const &origin, - Geom::Dim2 const dim, - bool const uniform) const -{ - /* Work out the transformed version of this point */ - Geom::Point transformed; - switch (transformation_type) { - case TRANSLATE: - transformed = p.getPoint() + transformation; - break; - case SCALE: - transformed = (p.getPoint() - origin) * Geom::Scale(transformation[Geom::X], transformation[Geom::Y]) + origin; - break; - case STRETCH: - { - Geom::Scale s(1, 1); - if (uniform) - s[Geom::X] = s[Geom::Y] = transformation[dim]; - else { - s[dim] = transformation[dim]; - s[1 - dim] = 1; - } - transformed = ((p.getPoint() - origin) * s) + origin; - break; - } - case SKEW: - // Apply the skew factor - transformed[dim] = (p.getPoint())[dim] + transformation[0] * ((p.getPoint())[1 - dim] - origin[1 - dim]); - // While skewing, mirroring and scaling (by integer multiples) in the opposite direction is also allowed. - // Apply that scale factor here - transformed[1-dim] = (p.getPoint() - origin)[1 - dim] * transformation[1] + origin[1 - dim]; - break; - case ROTATE: - // for rotations: transformation[0] stores the angle in radians - transformed = (p.getPoint() - origin) * Geom::Rotate(transformation[0]) + origin; - break; - default: - g_assert_not_reached(); - } - - return transformed; -} +//Geom::Point SnapManager::_transformPoint(Inkscape::SnapCandidatePoint const &p, +// Transformation const transformation_type, +// Geom::Point const &transformation, +// Geom::Point const &origin, +// Geom::Dim2 const dim, +// bool const uniform) const +//{ +// /* Work out the transformed version of this point */ +// Geom::Point transformed; +// switch (transformation_type) { +// case TRANSLATE: +// transformed = p.getPoint() + transformation; +// break; +// case SCALE: +// transformed = (p.getPoint() - origin) * Geom::Scale(transformation[Geom::X], transformation[Geom::Y]) + origin; +// break; +// case STRETCH: +// { +// Geom::Scale s(1, 1); +// if (uniform) +// s[Geom::X] = s[Geom::Y] = transformation[dim]; +// else { +// s[dim] = transformation[dim]; +// s[1 - dim] = 1; +// } +// transformed = ((p.getPoint() - origin) * s) + origin; +// break; +// } +// case SKEW: +// // Apply the skew factor +// transformed[dim] = (p.getPoint())[dim] + transformation[0] * ((p.getPoint())[1 - dim] - origin[1 - dim]); +// // While skewing, mirroring and scaling (by integer multiples) in the opposite direction is also allowed. +// // Apply that scale factor here +// transformed[1-dim] = (p.getPoint() - origin)[1 - dim] * transformation[1] + origin[1 - dim]; +// break; +// case ROTATE: +// // for rotations: transformation[0] stores the angle in radians +// transformed = (p.getPoint() - origin) * Geom::Rotate(transformation[0]) + origin; +// break; +// default: +// g_assert_not_reached(); +// } +// +// return transformed; +//} /** * Mark the location of the snap source (not the snap target!) on the canvas by drawing a symbol. diff --git a/src/snap.h b/src/snap.h index 944c49b3e..c4dd67b4c 100644 --- a/src/snap.h +++ b/src/snap.h @@ -21,6 +21,8 @@ #include "guide-snapper.h" #include "object-snapper.h" #include "snap-preferences.h" +//#include "pure-transform.h" + // Guides enum SPGuideDragType { // used both here and in desktop-events.cpp @@ -32,6 +34,11 @@ enum SPGuideDragType { // used both here and in desktop-events.cpp class SPGuide; class SPNamedView; + +namespace Inkscape { + class PureTransform; +} + typedef struct _GSList GSList; /** @@ -327,110 +334,6 @@ public: */ void guideConstrainedSnap(Geom::Point &p, SPGuide const &guideline) const; - /** - * Apply a translation to a set of points and try to snap freely in 2 degrees-of-freedom. - * - * @param p Collection of points to snap (snap sources), at their untransformed position, all points undergoing the same transformation. Paired with an identifier of the type of the snap source. - * @param pointer Location of the mouse pointer at the time dragging started (i.e. when the selection was still untransformed). - * @param tr Proposed translation; the final translation can only be calculated after snapping has occurred. - * @return An instance of the SnappedPoint class, which holds data on the snap source, snap target, and various metrics. - */ - Inkscape::SnappedPoint freeSnapTranslate(std::vector<Inkscape::SnapCandidatePoint> const &p, - Geom::Point const &pointer, - Geom::Point const &tr); - - /** - * Apply a translation to a set of points and try to snap along a constraint. - * - * @param p Collection of points to snap (snap sources), at their untransformed position, all points undergoing the same transformation. Paired with an identifier of the type of the snap source. - * @param pointer Location of the mouse pointer at the time dragging started (i.e. when the selection was still untransformed). - * @param constraint The direction or line along which snapping must occur. - * @param tr Proposed translation; the final translation can only be calculated after snapping has occurred. - * @return An instance of the SnappedPoint class, which holds data on the snap source, snap target, and various metrics. - */ - Inkscape::SnappedPoint constrainedSnapTranslate(std::vector<Inkscape::SnapCandidatePoint> const &p, - Geom::Point const &pointer, - Inkscape::Snapper::SnapConstraint const &constraint, - Geom::Point const &tr); - - /** - * Apply a scaling to a set of points and try to snap freely in 2 degrees-of-freedom. - * - * @param p Collection of points to snap (snap sources), at their untransformed position, all points undergoing the same transformation. Paired with an identifier of the type of the snap source. - * @param pointer Location of the mouse pointer at the time dragging started (i.e. when the selection was still untransformed). - * @param s Proposed scaling; the final scaling can only be calculated after snapping has occurred. - * @param o Origin of the scaling. - * @return An instance of the SnappedPoint class, which holds data on the snap source, snap target, and various metrics. - */ - Inkscape::SnappedPoint freeSnapScale(std::vector<Inkscape::SnapCandidatePoint> const &p, - Geom::Point const &pointer, - Geom::Scale const &s, - Geom::Point const &o); - - /** - * Apply a scaling to a set of points and snap such that the aspect ratio of the selection is preserved. - * - * @param p Collection of points to snap (snap sources), at their untransformed position, all points undergoing the same transformation. Paired with an identifier of the type of the snap source. - * @param pointer Location of the mouse pointer at the time dragging started (i.e. when the selection was still untransformed). - * @param s Proposed scaling; the final scaling can only be calculated after snapping has occurred. - * @param o Origin of the scaling. - * @return An instance of the SnappedPoint class, which holds data on the snap source, snap target, and various metrics. - */ - Inkscape::SnappedPoint constrainedSnapScale(std::vector<Inkscape::SnapCandidatePoint> const &p, - Geom::Point const &pointer, - Geom::Scale const &s, - Geom::Point const &o); - - /** - * Apply a stretch to a set of points and snap such that the direction of the stretch is preserved. - * - * @param p Collection of points to snap (snap sources), at their untransformed position, all points undergoing the same transformation. Paired with an identifier of the type of the snap source. - * @param pointer Location of the mouse pointer at the time dragging started (i.e. when the selection was still untransformed). - * @param s Proposed stretch; the final stretch can only be calculated after snapping has occurred. - * @param o Origin of the stretching. - * @param d Dimension in which to apply proposed stretch. - * @param u true if the stretch should be uniform (i.e. to be applied equally in both dimensions). - * @return An instance of the SnappedPoint class, which holds data on the snap source, snap target, and various metrics. - */ - Inkscape::SnappedPoint constrainedSnapStretch(std::vector<Inkscape::SnapCandidatePoint> const &p, - Geom::Point const &pointer, - Geom::Coord const &s, - Geom::Point const &o, - Geom::Dim2 d, - bool uniform); - - /** - * Apply a skew to a set of points and snap such that the direction of the skew is preserved. - * - * @param p Collection of points to snap (snap sources), at their untransformed position, all points undergoing the same transformation. Paired with an identifier of the type of the snap source. - * @param pointer Location of the mouse pointer at the time dragging started (i.e. when the selection was still untransformed). - * @param constraint The direction or line along which snapping must occur. - * @param s Proposed skew; the final skew can only be calculated after snapping has occurred. - * @param o Origin of the proposed skew. - * @param d Dimension in which to apply proposed skew. - * @return An instance of the SnappedPoint class, which holds data on the snap source, snap target, and various metrics. - */ - Inkscape::SnappedPoint constrainedSnapSkew(std::vector<Inkscape::SnapCandidatePoint> const &p, - Geom::Point const &pointer, - Inkscape::Snapper::SnapConstraint const &constraint, - Geom::Point const &s, // s[0] = skew factor, s[1] = scale factor - Geom::Point const &o, - Geom::Dim2 d); - - /** - * Apply a rotation to a set of points and snap, without scaling. - * - * @param p Collection of points to snap (snap sources), at their untransformed position, all points undergoing the same transformation. Paired with an identifier of the type of the snap source. - * @param pointer Location of the mouse pointer at the time dragging started (i.e. when the selection was still untransformed). - * @param angle Proposed rotation (in radians); the final rotation can only be calculated after snapping has occurred. - * @param o Origin of the rotation. - * @return An instance of the SnappedPoint class, which holds data on the snap source, snap target, and various metrics. - */ - Inkscape::SnappedPoint constrainedSnapRotate(std::vector<Inkscape::SnapCandidatePoint> const &p, - Geom::Point const &pointer, - Geom::Coord const &angle, - Geom::Point const &o); - Inkscape::GuideSnapper guide; ///< guide snapper Inkscape::ObjectSnapper object; ///< snapper to other objects Inkscape::SnapPreferences snapprefs; @@ -490,17 +393,6 @@ public: */ void displaySnapsource(Inkscape::SnapCandidatePoint const &p) const; -protected: - SPNamedView const *_named_view; - -private: - std::vector<SPItem const *> _items_to_ignore; ///< Items that should not be snapped to, for example the items that are currently being dragged. Set using the setup() method - std::vector<SPItem*> _rotation_center_source_items; // to avoid snapping a rotation center to itself - SPGuide *_guide_to_ignore; ///< A guide that should not be snapped to, e.g. the guide that is currently being dragged - SPDesktop const *_desktop; - bool _snapindicator; ///< When true, an indicator will be drawn at the position that was being snapped to - std::vector<Inkscape::SnapCandidatePoint> *_unselected_nodes; ///< Nodes of the path that is currently being edited and which have not been selected and which will therefore be stationary. Only these nodes will be considered for snapping to. Of each unselected node both the position (Geom::Point) and the type (Inkscape::SnapTargetType) will be stored - /** * Method for snapping sets of points while they are being transformed. * @@ -518,42 +410,22 @@ private: * * @param points Collection of points to snap (snap sources), at their untransformed position, all points undergoing the same transformation. Paired with an identifier of the type of the snap source. * @param pointer Location of the mouse pointer at the time dragging started (i.e. when the selection was still untransformed). - * @param constrained true if the snap is constrained, e.g. for stretching or for purely horizontal translation. - * @param constraint The direction or line along which snapping must occur, if 'constrained' is true; otherwise undefined. - * @param transformation_type Type of transformation to apply to points before trying to snap them. - * @param transformation Description of the transformation; details depend on the type. - * @param origin Origin of the transformation, if applicable. - * @param dim Dimension to which the transformation applies, if applicable. - * @param uniform true if the transformation should be uniform; only applicable for stretching and scaling. - * @return An instance of the SnappedPoint class, which holds data on the snap source, snap target, and various metrics. + * @param transform Describes the type of transformation, it's parameters, and any additional constraints */ - Inkscape::SnappedPoint _snapTransformed(std::vector<Inkscape::SnapCandidatePoint> const &points, + void snapTransformed(std::vector<Inkscape::SnapCandidatePoint> const &points, Geom::Point const &pointer, - bool constrained, - Inkscape::Snapper::SnapConstraint const &constraint, - Transformation transformation_type, - Geom::Point const &transformation, - Geom::Point const &origin, - Geom::Dim2 dim, - bool uniform); + Inkscape::PureTransform &transform); - /** - * Takes an untransformed point, applies the given transformation, and returns the transformed point. Eliminates lots of duplicated code. - * - * @param p The untransformed position of the point, paired with an identifier of the type of the snap source. - * @param transformation_type Type of transformation to apply. - * @param transformation Mathematical description of the transformation; details depend on the type. - * @param origin Origin of the transformation, if applicable. - * @param dim Dimension to which the transformation applies, if applicable. - * @param uniform true if the transformation should be uniform; only applicable for stretching and scaling. - * @return The position of the point after transformation. - */ - Geom::Point _transformPoint(Inkscape::SnapCandidatePoint const &p, - Transformation const transformation_type, - Geom::Point const &transformation, - Geom::Point const &origin, - Geom::Dim2 const dim, - bool const uniform) const; +protected: + SPNamedView const *_named_view; + +private: + std::vector<SPItem const *> _items_to_ignore; ///< Items that should not be snapped to, for example the items that are currently being dragged. Set using the setup() method + std::vector<SPItem*> _rotation_center_source_items; // to avoid snapping a rotation center to itself + SPGuide *_guide_to_ignore; ///< A guide that should not be snapped to, e.g. the guide that is currently being dragged + SPDesktop const *_desktop; + bool _snapindicator; ///< When true, an indicator will be drawn at the position that was being snapped to + std::vector<Inkscape::SnapCandidatePoint> *_unselected_nodes; ///< Nodes of the path that is currently being edited and which have not been selected and which will therefore be stationary. Only these nodes will be considered for snapping to. Of each unselected node both the position (Geom::Point) and the type (Inkscape::SnapTargetType) will be stored }; diff --git a/src/snapped-point.cpp b/src/snapped-point.cpp index ab545bd5f..f826211fa 100644 --- a/src/snapped-point.cpp +++ b/src/snapped-point.cpp @@ -29,7 +29,6 @@ Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p, SnapSourceType const _second_distance (Geom::infinity()), _second_tolerance (1), _second_always_snap (false), - _transformation (Geom::Point(1,1)), _target_bbox(target_bbox), _pointer_distance (Geom::infinity()) { @@ -50,7 +49,6 @@ Inkscape::SnappedPoint::SnappedPoint(Inkscape::SnapCandidatePoint const &p, Snap _second_distance (Geom::infinity()), _second_tolerance (1), _second_always_snap (false), - _transformation (Geom::Point(1,1)), _target_bbox (p.getTargetBBox()), _pointer_distance (Geom::infinity()) { @@ -73,7 +71,6 @@ Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p, SnapSourceType const _second_always_snap(a2), // tolerance should never be smaller than 1 px, as it is used for normalization in // isOtherSnapBetter. We don't want a division by zero. - _transformation (Geom::Point(1,1)), _target_bbox (Geom::OptRect()), _pointer_distance (Geom::infinity()) { @@ -94,7 +91,6 @@ Inkscape::SnappedPoint::SnappedPoint(): _second_distance (Geom::infinity()), _second_tolerance (1), _second_always_snap (false), - _transformation (Geom::Point(1,1)), _target_bbox (Geom::OptRect()), _pointer_distance (Geom::infinity()) { @@ -115,7 +111,6 @@ Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p): _second_distance (Geom::infinity()), _second_tolerance (1), _second_always_snap (false), - _transformation (Geom::Point(1,1)), _target_bbox (Geom::OptRect()), _pointer_distance (Geom::infinity()) { diff --git a/src/snapped-point.h b/src/snapped-point.h index 9d77ab162..cf3a15c3b 100644 --- a/src/snapped-point.h +++ b/src/snapped-point.h @@ -66,8 +66,6 @@ public: bool getFullyConstrained() const {return _fully_constrained;} bool getConstrainedSnap() const {return _constrained_snap;} bool getSnapped() const {return _distance < Geom::infinity();} - Geom::Point getTransformation() const {return _transformation;} - void setTransformation(Geom::Point const &t) {_transformation = t;} void setTarget(SnapTargetType const target) {_target = target;} SnapTargetType getTarget() const {return _target;} void setTargetBBox(Geom::OptRect const target) {_target_bbox = target;} @@ -122,8 +120,6 @@ protected: Geom::Coord _second_tolerance; /* If true then "Always snap" is on */ bool _second_always_snap; - /* The transformation (translation, scale, skew, or stretch) from the original point to the snapped point */ - Geom::Point _transformation; /* The bounding box we've snapped to (when applicable); will be used by the snapindicator */ Geom::OptRect _target_bbox; /* Distance from the un-transformed point to the mouse pointer, measured at the point in time when dragging started */ diff --git a/src/snapper.h b/src/snapper.h index 9616d0954..6c7995045 100644 --- a/src/snapper.h +++ b/src/snapper.h @@ -76,6 +76,8 @@ public: SnapConstraint(Geom::Point const &d) : _point(), _direction(d), _radius(0), _type(DIRECTION) {} // Constructs a linear constraint SnapConstraint(Geom::Point const &p, Geom::Point const &d) : _point(p), _direction(d), _radius(0), _type(LINE) {} + // Orthogonal version + SnapConstraint(Geom::Point const &p, Geom::Dim2 const &d) : _point(p), _direction(), _radius(0), _type(LINE) {_direction[d] = 1.;} SnapConstraint(Geom::Line const &l) : _point(l.origin()), _direction(l.versor()), _radius(0), _type(LINE) {} // Constructs a circular constraint SnapConstraint(Geom::Point const &p, Geom::Point const &d, Geom::Coord const &r) : _point(p), _direction(d), _radius(r), _type(CIRCLE) {} diff --git a/src/sp-clippath.cpp b/src/sp-clippath.cpp index d66508eae..0c07d1b3d 100644 --- a/src/sp-clippath.cpp +++ b/src/sp-clippath.cpp @@ -308,7 +308,7 @@ const gchar *SPClipPath::create (std::vector<Inkscape::XML::Node*> &reprs, SPDoc const gchar *id = repr->attribute("id"); SPObject *clip_path_object = document->getObjectById(id); - for (std::vector<Inkscape::XML::Node*>::const_iterator it = reprs.begin(); it != reprs.end(); it++) { + for (std::vector<Inkscape::XML::Node*>::const_iterator it = reprs.begin(); it != reprs.end(); ++it) { Inkscape::XML::Node *node = (*it); SPItem *item = SP_ITEM(clip_path_object->appendChildRepr(node)); diff --git a/src/sp-clippath.h b/src/sp-clippath.h index c9a8c68df..8abe97f3f 100644 --- a/src/sp-clippath.h +++ b/src/sp-clippath.h @@ -93,10 +93,10 @@ protected: Inkscape::XML::Node * const owner_repr = owner->getRepr(); //XML Tree being used directly here while it shouldn't be... Inkscape::XML::Node * const obj_repr = obj->getRepr(); - char const * owner_name = NULL; - char const * owner_clippath = NULL; - char const * obj_name = NULL; - char const * obj_id = NULL; + char const * owner_name = ""; + char const * owner_clippath = ""; + char const * obj_name = ""; + char const * obj_id = ""; if (owner_repr != NULL) { owner_name = owner_repr->name(); owner_clippath = owner_repr->attribute("clippath"); diff --git a/src/sp-conn-end.cpp b/src/sp-conn-end.cpp index fa5a57529..75cce4374 100644 --- a/src/sp-conn-end.cpp +++ b/src/sp-conn-end.cpp @@ -51,7 +51,7 @@ static bool try_get_intersect_point_with_item_recursive(Geom::PathVector& conn_p // consider all first-order children double child_pos = 0.0; std::vector<SPItem*> g = sp_item_group_item_list(group); - for (std::vector<SPItem*>::const_iterator i = g.begin();i!=g.end();i++) { + for (std::vector<SPItem*>::const_iterator i = g.begin();i!=g.end();++i) { SPItem* child_item = *i; try_get_intersect_point_with_item_recursive(conn_pv, child_item, item_transform * child_item->transform, child_pos); diff --git a/src/sp-defs.cpp b/src/sp-defs.cpp index 2e341d3c6..dd779c0da 100644 --- a/src/sp-defs.cpp +++ b/src/sp-defs.cpp @@ -37,7 +37,7 @@ void SPDefs::update(SPCtx *ctx, guint flags) { flags &= SP_OBJECT_MODIFIED_CASCADE; std::vector<SPObject*> l(this->childList(true)); - for(std::vector<SPObject*>::const_iterator i=l.begin();i!=l.end();i++){ + for(std::vector<SPObject*>::const_iterator i=l.begin();i!=l.end();++i){ SPObject *child = *i; if (flags || (child->uflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) { child->updateDisplay(ctx, flags); diff --git a/src/sp-factory.cpp b/src/sp-factory.cpp index 84329eaaf..20472d425 100644 --- a/src/sp-factory.cpp +++ b/src/sp-factory.cpp @@ -294,6 +294,8 @@ SPObject *SPFactory::createObject(std::string const& id) {} else if (id == "inkscape:clipboard") // SP node not necessary {} + else if (id == "inkscape:_templateinfo") // ? + {} else if (id.empty()) // comments {} else { diff --git a/src/sp-filter.cpp b/src/sp-filter.cpp index 1bde69dd1..c17c67fc5 100644 --- a/src/sp-filter.cpp +++ b/src/sp-filter.cpp @@ -246,7 +246,7 @@ void SPFilter::update(SPCtx *ctx, guint flags) { } childflags &= SP_OBJECT_MODIFIED_CASCADE; std::vector<SPObject*> l(this->childList(true, SPObject::ActionUpdate)); - for(std::vector<SPObject*>::const_iterator i=l.begin();i!=l.end();i++){ + for(std::vector<SPObject*>::const_iterator i=l.begin();i!=l.end();++i){ SPObject *child = *i; if( SP_IS_FILTER_PRIMITIVE( child ) ) { child->updateDisplay(ctx, childflags); diff --git a/src/sp-flowtext.cpp b/src/sp-flowtext.cpp index cac3cc61d..b87507e18 100644 --- a/src/sp-flowtext.cpp +++ b/src/sp-flowtext.cpp @@ -34,8 +34,10 @@ #include "display/drawing-text.h" -SPFlowtext::SPFlowtext() : SPItem() { - this->par_indent = 0; +SPFlowtext::SPFlowtext() : SPItem(), + par_indent(0), + _optimizeScaledText(false) +{ } SPFlowtext::~SPFlowtext() { diff --git a/src/sp-guide.cpp b/src/sp-guide.cpp index 4e1c5913d..fd07f76ef 100644 --- a/src/sp-guide.cpp +++ b/src/sp-guide.cpp @@ -26,6 +26,7 @@ #include "display/sp-canvas.h" #include "display/guideline.h" #include "svg/svg.h" +#include "svg/svg-color.h" #include "svg/stringstream.h" #include "attributes.h" #include "sp-guide.h" @@ -42,6 +43,7 @@ #include <2geom/angle.h> #include "document.h" #include "document-undo.h" +#include "helper-fns.h" #include "verbs.h" using Inkscape::DocumentUndo; @@ -50,6 +52,7 @@ using std::vector; SPGuide::SPGuide() : SPObject() , label(NULL) + , locked(0) , views(NULL) , normal_to_line(Geom::Point(0.,1.)) , point_on_line(Geom::Point(0.,0.)) @@ -70,7 +73,9 @@ void SPGuide::build(SPDocument *document, Inkscape::XML::Node *repr) { SPObject::build(document, repr); + this->readAttr( "inkscape:color" ); this->readAttr( "inkscape:label" ); + this->readAttr( "inkscape:locked" ); this->readAttr( "orientation" ); this->readAttr( "position" ); @@ -95,9 +100,14 @@ void SPGuide::release() void SPGuide::set(unsigned int key, const gchar *value) { switch (key) { + case SP_ATTR_INKSCAPE_COLOR: + if (value) { + this->setColor(sp_svg_read_color(value, 0x0000ff00) | 0x7f); + } + break; case SP_ATTR_INKSCAPE_LABEL: - if (this->label) g_free(this->label); - + // this->label already freed in sp_guideline_set_label (src/display/guideline.cpp) + // see bug #1498444, bug #1469514 if (value) { this->label = g_strdup(value); } else { @@ -106,6 +116,12 @@ void SPGuide::set(unsigned int key, const gchar *value) { this->set_label(this->label, false); break; + case SP_ATTR_INKSCAPE_LOCKED: + this->locked = helperfns_read_bool(value, false); + if (value) { + this->set_locked(this->locked, false); + } + break; case SP_ATTR_ORIENTATION: { if (value && !strcmp(value, "horizontal")) { @@ -332,6 +348,9 @@ double SPGuide::getDistanceFrom(Geom::Point const &pt) const */ void SPGuide::moveto(Geom::Point const point_on_line, bool const commit) { + if(this->locked) { + return; + } for (GSList *l = views; l != NULL; l = l->next) { sp_guideline_set_position(SP_GUIDELINE(l->data), point_on_line); } @@ -378,6 +397,9 @@ void SPGuide::moveto(Geom::Point const point_on_line, bool const commit) */ void SPGuide::set_normal(Geom::Point const normal_to_line, bool const commit) { + if(this->locked) { + return; + } for (GSList *l = this->views; l != NULL; l = l->next) { sp_guideline_set_normal(SP_GUIDELINE(l->data), normal_to_line); } @@ -416,6 +438,18 @@ void SPGuide::set_color(const unsigned r, const unsigned g, const unsigned b, bo } } +void SPGuide::set_locked(const bool locked, bool const commit) +{ + this->locked = locked; + if (views) { + sp_guideline_set_locked(SP_GUIDELINE(views->data), locked); + } + + if (commit) { + getRepr()->setAttribute("inkscape:locked", g_strdup(locked ? "true" : "false")); + } +} + void SPGuide::set_label(const char* label, bool const commit) { if (views) { @@ -475,6 +509,7 @@ char* SPGuide::description(bool const verbose) const descr = g_strconcat(oldDescr, shortcuts, NULL); g_free(oldDescr); } + g_free(shortcuts); } diff --git a/src/sp-guide.h b/src/sp-guide.h index 382ea56f0..1ad415e85 100644 --- a/src/sp-guide.h +++ b/src/sp-guide.h @@ -53,6 +53,9 @@ public: void set_label(const char* label, bool const commit); char const* getLabel() const { return label; } + void set_locked(const bool locked, bool const commit); + bool getLocked() const { return locked; } + static SPGuide *createSPGuide(SPDocument *doc, Geom::Point const &pt1, Geom::Point const &pt2); void showSPGuide(SPCanvasGroup *group, GCallback handler); @@ -77,6 +80,7 @@ protected: virtual void set(unsigned int key, const char* value); char* label; + bool locked; GSList *views; // contains an object of type SPGuideline (see display/guideline.cpp for definition) Geom::Point normal_to_line; Geom::Point point_on_line; diff --git a/src/sp-hatch.cpp b/src/sp-hatch.cpp index ea4c5865a..2d938618c 100644 --- a/src/sp-hatch.cpp +++ b/src/sp-hatch.cpp @@ -113,7 +113,7 @@ void SPHatch::child_added(Inkscape::XML::Node* child, Inkscape::XML::Node* ref) SPHatchPath *path_child = dynamic_cast<SPHatchPath *>(document->getObjectByRepr(child)); if (path_child) { - for (ViewIterator iter = _display.begin(); iter != _display.end(); iter++) { + for (ViewIterator iter = _display.begin(); iter != _display.end(); ++iter) { Geom::OptInterval extents = _calculateStripExtents(iter->bbox); Inkscape::DrawingItem *ac = path_child->show(iter->arenaitem->drawing(), iter->key, extents); diff --git a/src/sp-item-group.cpp b/src/sp-item-group.cpp index 72cd5d7fa..83d67cf5a 100644 --- a/src/sp-item-group.cpp +++ b/src/sp-item-group.cpp @@ -58,8 +58,11 @@ using Inkscape::DocumentUndo; static void sp_group_perform_patheffect(SPGroup *group, SPGroup *topgroup, bool write); -SPGroup::SPGroup() : SPLPEItem() { - this->_layer_mode = SPGroup::GROUP; +SPGroup::SPGroup() : SPLPEItem(), + _expanded(false), + _insertBottom(false), + _layer_mode(SPGroup::GROUP) +{ } SPGroup::~SPGroup() { @@ -90,10 +93,9 @@ void SPGroup::child_added(Inkscape::XML::Node* child, Inkscape::XML::Node* ref) if ( item ) { /* TODO: this should be moved into SPItem somehow */ SPItemView *v; - Inkscape::DrawingItem *ac; for (v = this->display; v != NULL; v = v->next) { - ac = item->invoke_show (v->arenaitem->drawing(), v->key, v->flags); + Inkscape::DrawingItem *ac = item->invoke_show (v->arenaitem->drawing(), v->key, v->flags); if (ac) { v->arenaitem->appendChild(ac); @@ -105,12 +107,10 @@ void SPGroup::child_added(Inkscape::XML::Node* child, Inkscape::XML::Node* ref) if ( item ) { /* TODO: this should be moved into SPItem somehow */ SPItemView *v; - Inkscape::DrawingItem *ac; - unsigned position = item->pos_in_parent(); for (v = this->display; v != NULL; v = v->next) { - ac = item->invoke_show (v->arenaitem->drawing(), v->key, v->flags); + Inkscape::DrawingItem *ac = item->invoke_show (v->arenaitem->drawing(), v->key, v->flags); if (ac) { v->arenaitem->prependChild(ac); @@ -162,7 +162,7 @@ void SPGroup::update(SPCtx *ctx, unsigned int flags) { } childflags &= SP_OBJECT_MODIFIED_CASCADE; std::vector<SPObject*> l=this->childList(true, SPObject::ActionUpdate); - for(std::vector<SPObject*> ::const_iterator i=l.begin();i!=l.end();i++){ + for(std::vector<SPObject*> ::const_iterator i=l.begin();i!=l.end();++i){ SPObject *child = *i; if (childflags || (child->uflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) { @@ -206,7 +206,7 @@ void SPGroup::modified(guint flags) { flags &= SP_OBJECT_MODIFIED_CASCADE; std::vector<SPObject*> l=this->childList(true); - for(std::vector<SPObject*>::const_iterator i=l.begin();i!=l.end();i++){ + for(std::vector<SPObject*>::const_iterator i=l.begin();i!=l.end();++i){ SPObject *child = *i; if (flags || (child->mflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) { @@ -280,7 +280,7 @@ Geom::OptRect SPGroup::bbox(Geom::Affine const &transform, SPItem::BBoxType bbox // TODO CPPIFY: replace this const_cast later std::vector<SPObject*> l = const_cast<SPGroup*>(this)->childList(false, SPObject::ActionBBox); - for(std::vector<SPObject*>::const_iterator i=l.begin();i!=l.end();i++){ + for(std::vector<SPObject*>::const_iterator i=l.begin();i!=l.end();++i){ SPObject *o = *i; SPItem *item = dynamic_cast<SPItem *>(o); if (item && !item->isHidden()) { @@ -294,7 +294,7 @@ Geom::OptRect SPGroup::bbox(Geom::Affine const &transform, SPItem::BBoxType bbox void SPGroup::print(SPPrintContext *ctx) { std::vector<SPObject*> l=this->childList(false); - for(std::vector<SPObject*>::const_iterator i=l.begin();i!=l.end();i++){ + for(std::vector<SPObject*>::const_iterator i=l.begin();i!=l.end();++i){ SPObject *o = *i; SPItem *item = dynamic_cast<SPItem *>(o); if (item) { @@ -348,7 +348,7 @@ Inkscape::DrawingItem *SPGroup::show (Inkscape::Drawing &drawing, unsigned int k void SPGroup::hide (unsigned int key) { std::vector<SPObject*> l=this->childList(false, SPObject::ActionShow); - for(std::vector<SPObject*>::const_iterator i=l.begin();i!=l.end();i++){ + for(std::vector<SPObject*>::const_iterator i=l.begin();i!=l.end();++i){ SPObject *o = *i; SPItem *item = dynamic_cast<SPItem *>(o); @@ -373,7 +373,7 @@ void SPGroup::snappoints(std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape: void sp_item_group_ungroup_handle_clones(SPItem *parent, Geom::Affine const g) { - for(std::list<SPObject*>::const_iterator refd=parent->hrefList.begin();refd!=parent->hrefList.end();refd++){ + for(std::list<SPObject*>::const_iterator refd=parent->hrefList.begin();refd!=parent->hrefList.end();++refd){ SPItem *citem = dynamic_cast<SPItem *>(*refd); if (citem && !citem->cloned) { SPUse *useitem = dynamic_cast<SPUse *>(citem); @@ -465,7 +465,7 @@ sp_item_group_ungroup (SPGroup *group, std::vector<SPItem*> &children, bool do_d Inkscape::XML::Node *nrepr = child->getRepr()->duplicate(prepr->document()); // Merging transform - Geom::Affine ctrans; + Geom::Affine ctrans = citem->transform * g; // We should not apply the group's transformation to both a linked offset AND to its source if (dynamic_cast<SPOffset *>(citem)) { // Do we have an offset at hand (whether it's dynamic or linked)? SPItem *source = sp_offset_get_source(dynamic_cast<SPOffset *>(citem)); @@ -476,13 +476,9 @@ sp_item_group_ungroup (SPGroup *group, std::vector<SPItem*> &children, bool do_d source = sp_offset_get_source(dynamic_cast<SPOffset *>(source)); } if (source != NULL && // If true then we must be dealing with a linked offset ... - group->isAncestorOf(source) == false) { // ... of which the source is not in the same group - ctrans = citem->transform * g; // then we should apply the transformation of the group to the offset - } else { - ctrans = citem->transform; + group->isAncestorOf(source) ) { // ... of which the source is in the same group + ctrans = citem->transform; // then we should apply the transformation of the group to the offset } - } else { - ctrans = citem->transform * g; } // FIXME: constructing a transform that would fully preserve the appearance of a @@ -785,7 +781,7 @@ gint SPGroup::getItemCount() const { void SPGroup::_showChildren (Inkscape::Drawing &drawing, Inkscape::DrawingItem *ai, unsigned int key, unsigned int flags) { Inkscape::DrawingItem *ac = NULL; std::vector<SPObject*> l=this->childList(false, SPObject::ActionShow); - for(std::vector<SPObject*>::const_iterator i=l.begin();i!=l.end();i++){ + for(std::vector<SPObject*>::const_iterator i=l.begin();i!=l.end();++i){ SPObject *o = *i; SPItem * child = dynamic_cast<SPItem *>(o); if (child) { @@ -804,7 +800,7 @@ void SPGroup::update_patheffect(bool write) { std::vector<SPItem*> const item_list = sp_item_group_item_list(this); - for ( std::vector<SPItem*>::const_iterator iter=item_list.begin();iter!=item_list.end();iter++) { + for ( std::vector<SPItem*>::const_iterator iter=item_list.begin();iter!=item_list.end();++iter) { SPObject *subitem = *iter; SPLPEItem *lpeItem = dynamic_cast<SPLPEItem *>(subitem); @@ -814,7 +810,7 @@ void SPGroup::update_patheffect(bool write) { } if (hasPathEffect() && pathEffectsEnabled()) { - for (PathEffectList::iterator it = this->path_effect_list->begin(); it != this->path_effect_list->end(); it++) + for (PathEffectList::iterator it = this->path_effect_list->begin(); it != this->path_effect_list->end(); ++it) { LivePathEffectObject *lpeobj = (*it)->lpeobject; @@ -832,7 +828,7 @@ sp_group_perform_patheffect(SPGroup *group, SPGroup *topgroup, bool write) { 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++) { + for ( std::vector<SPItem*>::const_iterator iter=item_list.begin();iter!=item_list.end();++iter) { SPObject *subitem = *iter; SPGroup *subGroup = dynamic_cast<SPGroup *>(subitem); diff --git a/src/sp-lpe-item.cpp b/src/sp-lpe-item.cpp index 9befd2a2b..98b77cfe8 100644 --- a/src/sp-lpe-item.cpp +++ b/src/sp-lpe-item.cpp @@ -354,7 +354,7 @@ sp_lpe_item_create_original_path_recursive(SPLPEItem *lpeitem) } if (SP_IS_GROUP(lpeitem)) { std::vector<SPItem*> item_list = sp_item_group_item_list(SP_GROUP(lpeitem)); - for ( std::vector<SPItem*>::const_iterator iter=item_list.begin();iter!=item_list.end();iter++) { + for ( std::vector<SPItem*>::const_iterator iter=item_list.begin();iter!=item_list.end();++iter) { SPObject *subitem = *iter; if (SP_IS_LPE_ITEM(subitem)) { sp_lpe_item_create_original_path_recursive(SP_LPE_ITEM(subitem)); @@ -388,7 +388,7 @@ sp_lpe_item_cleanup_original_path_recursive(SPLPEItem *lpeitem) } } std::vector<SPItem*> item_list = sp_item_group_item_list(SP_GROUP(lpeitem)); - for ( std::vector<SPItem*>::const_iterator iter=item_list.begin();iter!=item_list.end();iter++) { + for ( std::vector<SPItem*>::const_iterator iter=item_list.begin();iter!=item_list.end();++iter) { SPObject *subitem = *iter; if (SP_IS_LPE_ITEM(subitem)) { sp_lpe_item_cleanup_original_path_recursive(SP_LPE_ITEM(subitem)); @@ -681,7 +681,7 @@ SPLPEItem::apply_to_clippath(SPItem *item) } if(SP_IS_GROUP(item)){ std::vector<SPItem*> item_list = sp_item_group_item_list(SP_GROUP(item)); - for ( std::vector<SPItem*>::const_iterator iter=item_list.begin();iter!=item_list.end();iter++) { + for ( std::vector<SPItem*>::const_iterator iter=item_list.begin();iter!=item_list.end();++iter) { SPObject *subitem = *iter; apply_to_clippath(SP_ITEM(subitem)); } @@ -733,7 +733,7 @@ SPLPEItem::apply_to_mask(SPItem *item) } if(SP_IS_GROUP(item)){ std::vector<SPItem*> item_list = sp_item_group_item_list(SP_GROUP(item)); - for ( std::vector<SPItem*>::const_iterator iter=item_list.begin();iter!=item_list.end();iter++) { + for ( std::vector<SPItem*>::const_iterator iter=item_list.begin();iter!=item_list.end();++iter) { SPObject *subitem = *iter; apply_to_mask(SP_ITEM(subitem)); } @@ -747,7 +747,7 @@ SPLPEItem::apply_to_clip_or_mask_group(SPItem *group, SPItem *item) return; } std::vector<SPItem*> item_list = sp_item_group_item_list(SP_GROUP(group)); - for ( std::vector<SPItem*>::const_iterator iter=item_list.begin();iter!=item_list.end();iter++) { + for ( std::vector<SPItem*>::const_iterator iter=item_list.begin();iter!=item_list.end();++iter) { SPObject *subitem = *iter; if (SP_IS_GROUP(subitem)) { apply_to_clip_or_mask_group(SP_ITEM(subitem), item); diff --git a/src/sp-lpe-item.h b/src/sp-lpe-item.h index 902271430..c35ad8411 100644 --- a/src/sp-lpe-item.h +++ b/src/sp-lpe-item.h @@ -26,21 +26,21 @@ class SPCurve; class SPDesktop; namespace Inkscape{ -namespace Display { - class TemporaryItem; -} -namespace LivePathEffect{ - class LPEObjectReference; - class Effect; -} + namespace Display { + class TemporaryItem; + } + namespace LivePathEffect{ + class LPEObjectReference; + class Effect; + } } typedef std::list<Inkscape::LivePathEffect::LPEObjectReference *> PathEffectList; class SPLPEItem : public SPItem { public: - SPLPEItem(); - virtual ~SPLPEItem(); + SPLPEItem(); + virtual ~SPLPEItem(); int path_effects_enabled; @@ -54,20 +54,20 @@ public: std::vector<LivePathEffectObject const *> const &new_lpeobjs ); - virtual void build(SPDocument* doc, Inkscape::XML::Node* repr); - virtual void release(); + virtual void build(SPDocument* doc, Inkscape::XML::Node* repr); + virtual void release(); - virtual void set(unsigned int key, char const* value); + virtual void set(unsigned int key, char const* value); - virtual void update(SPCtx* ctx, unsigned int flags); - virtual void modified(unsigned int flags); + virtual void update(SPCtx* ctx, unsigned int flags); + virtual void modified(unsigned int flags); - virtual void child_added(Inkscape::XML::Node* child, Inkscape::XML::Node* ref); - virtual void remove_child(Inkscape::XML::Node* child); + virtual void child_added(Inkscape::XML::Node* child, Inkscape::XML::Node* ref); + virtual void remove_child(Inkscape::XML::Node* child); - virtual Inkscape::XML::Node* write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, unsigned int flags); + virtual Inkscape::XML::Node* write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, unsigned int flags); - virtual void update_patheffect(bool write); + virtual void update_patheffect(bool write); bool performPathEffect(SPCurve *curve); diff --git a/src/sp-marker.cpp b/src/sp-marker.cpp index 9334614dc..88dfbe04e 100644 --- a/src/sp-marker.cpp +++ b/src/sp-marker.cpp @@ -43,14 +43,18 @@ public: std::vector<Inkscape::DrawingItem *> items; }; -SPMarker::SPMarker() : SPGroup(), SPViewBox() { - - this->markerUnits = 0; - this->markerUnits_set = 0; - - this->orient_mode = MARKER_ORIENT_ANGLE; - this->orient_set = 0; - this->orient = 0; +SPMarker::SPMarker() : SPGroup(), SPViewBox(), + markerUnits_set(0), + markerUnits(0), + refX(), + refY(), + markerWidth(), + markerHeight(), + orient_set(0), + orient_mode(MARKER_ORIENT_ANGLE) +{ + // cppcheck-suppress useInitializationList + orient = 0; } /** @@ -442,7 +446,7 @@ const gchar *generate_marker(std::vector<Inkscape::XML::Node*> &reprs, Geom::Rec const gchar *mark_id = repr->attribute("id"); SPObject *mark_object = document->getObjectById(mark_id); - for (std::vector<Inkscape::XML::Node*>::const_iterator i=reprs.begin();i!=reprs.end();i++){ + for (std::vector<Inkscape::XML::Node*>::const_iterator i=reprs.begin();i!=reprs.end();++i){ Inkscape::XML::Node *node = *i; SPItem *copy = SP_ITEM(mark_object->appendChildRepr(node)); diff --git a/src/sp-mask.cpp b/src/sp-mask.cpp index f8fb7aff4..5f7a2ec26 100644 --- a/src/sp-mask.cpp +++ b/src/sp-mask.cpp @@ -221,7 +221,7 @@ sp_mask_create (std::vector<Inkscape::XML::Node*> &reprs, SPDocument *document, const gchar *mask_id = repr->attribute("id"); SPObject *mask_object = document->getObjectById(mask_id); - for (std::vector<Inkscape::XML::Node*>::const_iterator it = reprs.begin(); it != reprs.end(); it++) { + for (std::vector<Inkscape::XML::Node*>::const_iterator it = reprs.begin(); it != reprs.end(); ++it) { Inkscape::XML::Node *node = (*it); SPItem *item = SP_ITEM(mask_object->appendChildRepr(node)); diff --git a/src/sp-mask.h b/src/sp-mask.h index 74bd4d66e..19786b1fd 100644 --- a/src/sp-mask.h +++ b/src/sp-mask.h @@ -86,10 +86,10 @@ protected: Inkscape::XML::Node * const owner_repr = owner->getRepr(); //XML Tree being used directly here while it shouldn't be... Inkscape::XML::Node * const obj_repr = obj->getRepr(); - char const * owner_name = NULL; - char const * owner_mask = NULL; - char const * obj_name = NULL; - char const * obj_id = NULL; + char const * owner_name = ""; + char const * owner_mask = ""; + char const * obj_name = ""; + char const * obj_id = ""; if (owner_repr != NULL) { owner_name = owner_repr->name(); owner_mask = owner_repr->attribute("mask"); diff --git a/src/sp-mesh-array.cpp b/src/sp-mesh-array.cpp index 445c9a8f6..355150893 100644 --- a/src/sp-mesh-array.cpp +++ b/src/sp-mesh-array.cpp @@ -313,7 +313,7 @@ bool SPMeshPatchI::tensorIsSet( unsigned int i ) { /** Return tensor control point for "corner" i. - If not sest, returns calculated (Coons) point. + If not set, returns calculated (Coons) point. */ Geom::Point SPMeshPatchI::getTensorPoint( guint k ) { @@ -1058,11 +1058,11 @@ void SPMeshNodeArray::create( SPMesh *mg, SPItem *item, Geom::OptRect bbox ) { Geom::Point center = bbox->midpoint(); // Must keep repr and array in sync. We have two choices: - // Build the repr first and the "read" it. - // Construct the array and the "write" it. + // Build the repr first and then "read" it. + // Construct the array and then "write" it. // We'll do the second. - // Remove any existing mesh. We could chose to simply scale an existing mesh... + // Remove any existing mesh. We could choose to simply scale an existing mesh... //clear(); // We get called twice when a new mesh is created...WHY? @@ -2265,10 +2265,12 @@ guint SPMeshNodeArray::color_pick( std::vector<guint> icorners, SPItem* item ) { // Region to average over Geom::Point p = n->p; - // std::cout << " p: " << p << std::endl; + // std::cout << " before transform: p: " << p << std::endl; p *= gr->gradientTransform; - // std::cout << " p: " << p << std::endl; - + // std::cout << " after transform: p: " << p << std::endl; + p *= item->i2doc_affine(); + // std::cout << " after transform: p: " << p << std::endl; + // If on edge, move inward guint cols = patch_columns()+1; guint rows = patch_rows()+1; @@ -2277,7 +2279,7 @@ guint SPMeshNodeArray::color_pick( std::vector<guint> icorners, SPItem* item ) { guint ncol = col * 3; guint nrow = row * 3; - double size = 3.0; + const double size = 3.0; // Top edge if( row == 0 ) { @@ -2328,6 +2330,7 @@ guint SPMeshNodeArray::color_pick( std::vector<guint> icorners, SPItem* item ) { pick_doc->getRoot()->invoke_hide(pick_visionkey); delete pick_drawing; + picked = 1; // Picking always happens if( picked > 0 ) built = false; return picked; } diff --git a/src/sp-namedview.cpp b/src/sp-namedview.cpp index 12c2cdf8e..22effd93c 100644 --- a/src/sp-namedview.cpp +++ b/src/sp-namedview.cpp @@ -51,7 +51,9 @@ using Inkscape::Util::unit_table; #define DEFAULTPAGECOLOR 0xffffff00 static void sp_namedview_setup_guides(SPNamedView * nv); +static void sp_namedview_lock_guides(SPNamedView * nv); static void sp_namedview_show_single_guide(SPGuide* guide, bool show); +static void sp_namedview_lock_single_guide(SPGuide* guide, bool show); static gboolean sp_str_to_bool(const gchar *str); static gboolean sp_nv_read_opacity(const gchar *str, guint32 *color); @@ -79,6 +81,7 @@ SPNamedView::SPNamedView() : SPObjectGroup(), snap_manager(this) { this->editable = TRUE; this->showguides = TRUE; + this->lockguides = false; this->grids_visible = false; this->showborder = TRUE; this->showpageshadow = TRUE; @@ -240,6 +243,7 @@ void SPNamedView::build(SPDocument *document, Inkscape::XML::Node *repr) { this->readAttr( "inkscape:snap-page" ); this->readAttr( "inkscape:current-layer" ); this->readAttr( "inkscape:connector-spacing" ); + this->readAttr( "inkscape:lockguides" ); /* Construct guideline list */ for (SPObject *o = this->firstChild() ; o; o = o->getNext() ) { @@ -249,6 +253,7 @@ void SPNamedView::build(SPDocument *document, Inkscape::XML::Node *repr) { //g_object_set(G_OBJECT(g), "color", nv->guidecolor, "hicolor", nv->guidehicolor, NULL); g->setColor(this->guidecolor); g->setHiColor(this->guidehicolor); + g->readAttr( "inkscape:color" ); } } @@ -325,8 +330,9 @@ void SPNamedView::set(unsigned int key, const gchar* value) { } for (GSList *l = this->guides; l != NULL; l = l->next) { - //g_object_set(G_OBJECT(l->data), "color", nv->guidecolor, NULL); - SP_GUIDE(l->data)->setColor(this->guidecolor); + SPGuide * g = SP_GUIDE(l->data); + g->setColor(this->guidecolor); + g->readAttr("inkscape:color"); } this->requestModified(SP_OBJECT_MODIFIED_FLAG); @@ -336,8 +342,9 @@ void SPNamedView::set(unsigned int key, const gchar* value) { sp_nv_read_opacity(value, &this->guidecolor); for (GSList *l = this->guides; l != NULL; l = l->next) { - //g_object_set(G_OBJECT(l->data), "color", nv->guidecolor, NULL); - SP_GUIDE(l->data)->setColor(this->guidecolor); + SPGuide * g = SP_GUIDE(l->data); + g->setColor(this->guidecolor); + g->readAttr("inkscape:color"); } this->requestModified(SP_OBJECT_MODIFIED_FLAG); @@ -597,6 +604,11 @@ void SPNamedView::set(unsigned int key, const gchar* value) { this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; } + case SP_ATTR_INKSCAPE_LOCKGUIDES: + this->lockguides = value ? sp_str_to_bool(value) : FALSE; + sp_namedview_lock_guides(this); + this->requestModified(SP_OBJECT_MODIFIED_FLAG); + break; default: SPObjectGroup::set(key, value); break; @@ -662,6 +674,7 @@ void SPNamedView::child_added(Inkscape::XML::Node *child, Inkscape::XML::Node *r //g_object_set(G_OBJECT(g), "color", this->guidecolor, "hicolor", this->guidehicolor, NULL); g->setColor(this->guidecolor); g->setHiColor(this->guidehicolor); + g->readAttr("inkscape:color"); if (this->editable) { for (GSList *l = this->views; l != NULL; l = l->next) { @@ -672,6 +685,7 @@ void SPNamedView::child_added(Inkscape::XML::Node *child, Inkscape::XML::Node *r } sp_namedview_show_single_guide(SP_GUIDE(g), this->showguides); + sp_namedview_lock_single_guide(SP_GUIDE(g), this->lockguides); } } } @@ -729,6 +743,7 @@ void SPNamedView::show(SPDesktop *desktop) SP_GUIDE(l->data)->sensitize(desktop->getCanvas(), TRUE); } sp_namedview_show_single_guide(SP_GUIDE(l->data), showguides); + sp_namedview_lock_single_guide(SP_GUIDE(l->data), lockguides); } views = g_slist_prepend(views, desktop); @@ -948,6 +963,13 @@ static void sp_namedview_setup_guides(SPNamedView *nv) } } +static void sp_namedview_lock_guides(SPNamedView *nv) +{ + for (GSList *l = nv->guides; l != NULL; l = l->next) { + sp_namedview_lock_single_guide(SP_GUIDE(l->data), nv->lockguides); + } +} + static void sp_namedview_show_single_guide(SPGuide* guide, bool show) { if (show) { @@ -957,6 +979,11 @@ static void sp_namedview_show_single_guide(SPGuide* guide, bool show) } } +static void sp_namedview_lock_single_guide(SPGuide* guide, bool locked) +{ + guide->set_locked(locked, true); +} + void sp_namedview_toggle_guides(SPDocument *doc, Inkscape::XML::Node *repr) { unsigned int v; @@ -975,6 +1002,23 @@ void sp_namedview_toggle_guides(SPDocument *doc, Inkscape::XML::Node *repr) doc->setModifiedSinceSave(); } +void sp_namedview_guides_toggle_lock(SPDocument *doc, Inkscape::XML::Node *repr) +{ + unsigned int v; + unsigned int set = sp_repr_get_boolean(repr, "inkscape:lockguides", &v); + if (!set) { // hide guides if not specified, for backwards compatibility + v = true; + } else { + v = !v; + } + + bool saved = DocumentUndo::getUndoSensitive(doc); + DocumentUndo::setUndoSensitive(doc, false); + sp_repr_set_boolean(repr, "inkscape:lockguides", v); + DocumentUndo::setUndoSensitive(doc, saved); + doc->setModifiedSinceSave(); +} + void sp_namedview_show_grids(SPNamedView * namedview, bool show, bool dirty_document) { namedview->grids_visible = show; @@ -1073,6 +1117,7 @@ void SPNamedView::setGuides(bool v) g_assert(this->getRepr() != NULL); sp_repr_set_boolean(this->getRepr(), "showguides", v); sp_repr_set_boolean(this->getRepr(), "inkscape:guide-bbox", v); + sp_repr_set_boolean(this->getRepr(), "inkscape:locked", false); } bool SPNamedView::getGuides() diff --git a/src/sp-namedview.h b/src/sp-namedview.h index f1ecc12d3..d95da1254 100644 --- a/src/sp-namedview.h +++ b/src/sp-namedview.h @@ -44,6 +44,7 @@ public: unsigned int editable : 1; unsigned int showguides : 1; + unsigned int lockguides : 1; unsigned int showborder : 1; unsigned int showpageshadow : 1; unsigned int borderlayer : 2; @@ -122,6 +123,7 @@ void sp_namedview_document_from_window(SPDesktop *desktop); void sp_namedview_update_layers_from_document (SPDesktop *desktop); void sp_namedview_toggle_guides(SPDocument *doc, Inkscape::XML::Node *repr); +void sp_namedview_guides_toggle_lock(SPDocument *doc, Inkscape::XML::Node *repr); void sp_namedview_show_grids(SPNamedView *namedview, bool show, bool dirty_document); Inkscape::CanvasGrid * sp_namedview_get_first_enabled_grid(SPNamedView *namedview); diff --git a/src/sp-paint-server.cpp b/src/sp-paint-server.cpp index c3416c6c8..d445ca0a7 100644 --- a/src/sp-paint-server.cpp +++ b/src/sp-paint-server.cpp @@ -39,7 +39,9 @@ SPPaintServer::~SPPaintServer() { bool SPPaintServer::isSwatch() const { - return swatch; + if( this ) // Protect against assumption that "vector" always exists. + return swatch; + return( false ); } diff --git a/src/sp-path.cpp b/src/sp-path.cpp index cabed0467..c4d24c503 100644 --- a/src/sp-path.cpp +++ b/src/sp-path.cpp @@ -294,8 +294,9 @@ Geom::Affine SPPath::set_transform(Geom::Affine const &transform) { // Transform the original-d path if this is a valid LPE this, other else the (ordinary) path if (_curve_before_lpe && hasPathEffectRecursive()) { - if (this->hasPathEffectOfType(Inkscape::LivePathEffect::CLONE_ORIGINAL)) { + if (this->hasPathEffectOfType(Inkscape::LivePathEffect::CLONE_ORIGINAL) || this->hasPathEffectOfType(Inkscape::LivePathEffect::BEND_PATH)) { // if path has the CLONE_ORIGINAL LPE applied, don't write the transform to the pathdata, but write it 'unoptimized' + // also if the effect is type BEND PATH to fix bug #179842 return transform; } else { _curve_before_lpe->transform(transform); diff --git a/src/sp-pattern.cpp b/src/sp-pattern.cpp index 755d3d162..dd351a8d5 100644 --- a/src/sp-pattern.cpp +++ b/src/sp-pattern.cpp @@ -244,7 +244,7 @@ void SPPattern::update(SPCtx *ctx, unsigned int flags) std::list<SPObject *> l; _getChildren(l); - for (SPObjectIterator it = l.begin(); it != l.end(); it++) { + for (SPObjectIterator it = l.begin(); it != l.end(); ++it) { SPObject *child = *it; sp_object_ref(child, NULL); @@ -270,7 +270,7 @@ void SPPattern::modified(unsigned int flags) std::list<SPObject *> l; _getChildren(l); - for (SPObjectIterator it = l.begin(); it != l.end(); it++) { + for (SPObjectIterator it = l.begin(); it != l.end(); ++it) { SPObject *child = *it; sp_object_ref(child, NULL); @@ -398,7 +398,7 @@ const gchar *SPPattern::produce(const std::vector<Inkscape::XML::Node *> &reprs, const gchar *pat_id = repr->attribute("id"); SPObject *pat_object = document->getObjectById(pat_id); - for (NodePtrIterator i = reprs.begin(); i != reprs.end(); i++) { + for (NodePtrIterator i = reprs.begin(); i != reprs.end(); ++i) { Inkscape::XML::Node *node = *i; SPItem *copy = SP_ITEM(pat_object->appendChildRepr(node)); diff --git a/src/sp-rect.cpp b/src/sp-rect.cpp index e17d7373c..2ba9a7023 100644 --- a/src/sp-rect.cpp +++ b/src/sp-rect.cpp @@ -61,13 +61,13 @@ void SPRect::set(unsigned key, gchar const *value) { switch (key) { case SP_ATTR_X: this->x.readOrUnset(value); - this->x.update( ex, em, w ); + this->x.update( em, ex, w ); this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_Y: this->y.readOrUnset(value); - this->y.update( ex, em, h ); + this->y.update( em, ex, h ); this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; @@ -75,7 +75,7 @@ void SPRect::set(unsigned key, gchar const *value) { if (!this->width.read(value) || this->width.value < 0.0) { this->width.unset(); } - this->width.update( ex, em, w ); + this->width.update( em, ex, w ); this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; @@ -83,7 +83,7 @@ void SPRect::set(unsigned key, gchar const *value) { if (!this->height.read(value) || this->height.value < 0.0) { this->height.unset(); } - this->height.update( ex, em, h ); + this->height.update( em, ex, h ); this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; @@ -91,7 +91,7 @@ void SPRect::set(unsigned key, gchar const *value) { if (!this->rx.read(value) || this->rx.value <= 0.0) { this->rx.unset(); } - this->rx.update( ex, em, w ); + this->rx.update( em, ex, w ); this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; @@ -99,7 +99,7 @@ void SPRect::set(unsigned key, gchar const *value) { if (!this->ry.read(value) || this->ry.value <= 0.0) { this->ry.unset(); } - this->ry.update( ex, em, h ); + this->ry.update( em, ex, h ); this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); break; diff --git a/src/sp-star.cpp b/src/sp-star.cpp index 51d5e6254..8a1956e3b 100644 --- a/src/sp-star.cpp +++ b/src/sp-star.cpp @@ -32,15 +32,16 @@ #include "sp-star.h" -SPStar::SPStar() : SPPolygon() { - this->sides = 5; - this->center = Geom::Point(0, 0); +SPStar::SPStar() : SPPolygon() , + sides(5), + center(0, 0), + flatsided(0), + rounded(0.0), + randomized(0.0) +{ this->r[0] = 1.0; this->r[1] = 0.001; this->arg[0] = this->arg[1] = 0.0; - this->flatsided = 0; - this->rounded = 0.0; - this->randomized = 0.0; } SPStar::~SPStar() { diff --git a/src/sp-switch.cpp b/src/sp-switch.cpp index cfc0e7d8b..d2dcde15d 100644 --- a/src/sp-switch.cpp +++ b/src/sp-switch.cpp @@ -97,7 +97,7 @@ void SPSwitch::_reevaluate(bool /*add_to_drawing*/) { _releaseLastItem(_cached_item); std::vector<SPObject*> item_list = _childList(false, SPObject::ActionShow); - for ( std::vector<SPObject*>::const_reverse_iterator iter=item_list.rbegin();iter!=item_list.rend();iter++) { + for ( std::vector<SPObject*>::const_reverse_iterator iter=item_list.rbegin();iter!=item_list.rend();++iter) { SPObject *o = *iter; if ( !SP_IS_ITEM (o) ) { continue; @@ -132,7 +132,7 @@ void SPSwitch::_showChildren (Inkscape::Drawing &drawing, Inkscape::DrawingItem std::vector<SPObject*> l = this->_childList(false, SPObject::ActionShow); - for ( std::vector<SPObject*>::const_reverse_iterator iter=l.rbegin();iter!=l.rend();iter++) { + for ( std::vector<SPObject*>::const_reverse_iterator iter=l.rbegin();iter!=l.rend();++iter) { SPObject *o = *iter; if (SP_IS_ITEM (o)) { diff --git a/src/sp-text.cpp b/src/sp-text.cpp index d351e58e3..c7dfdd694 100644 --- a/src/sp-text.cpp +++ b/src/sp-text.cpp @@ -93,7 +93,7 @@ void SPText::release() { void SPText::set(unsigned int key, const gchar* value) { //std::cout << "SPText::set: " << sp_attribute_name( key ) << ": " << (value?value:"Null") << std::endl; - if (this->attributes.readSingleAttribute(key, value)) { + if (this->attributes.readSingleAttribute(key, value, style, &viewport)) { this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); } else { switch (key) { @@ -181,6 +181,16 @@ void SPText::update(SPCtx *ctx, guint flags) { SP_OBJECT_CHILD_MODIFIED_FLAG | SP_TEXT_LAYOUT_MODIFIED_FLAG ) ) { + + SPItemCtx const *ictx = reinterpret_cast<SPItemCtx const *>(ctx); + + double const w = ictx->viewport.width(); + double const h = ictx->viewport.height(); + double const em = style->font_size.computed; + double const ex = 0.5 * em; // fixme: get x height from pango or libnrtype. + + attributes.update( em, ex, w, h ); + /* fixme: It is not nice to have it here, but otherwise children content changes does not work */ /* fixme: Even now it may not work, as we are delayed */ /* fixme: So check modification flag everywhere immediate state is used */ @@ -576,7 +586,7 @@ unsigned SPText::_buildLayoutInput(SPObject *root, Inkscape::Text::Layout::Optio SPString *str = dynamic_cast<SPString *>(child); if (str) { Glib::ustring const &string = str->string; - // std::cout << " Appending: " << string << std::endl; + // std::cout << " Appending: >" << string << "<" << std::endl; layout.appendText(string, root->style, child, &optional_attrs, child_attrs_offset + length); length += string.length(); } else if (!sp_repr_is_meta_element(child->getRepr())) { @@ -671,25 +681,30 @@ void SPText::_clearFlow(Inkscape::DrawingGroup *in_arena) * TextTagAttributes implementation */ -void TextTagAttributes::readFrom(Inkscape::XML::Node const *node) -{ - readSingleAttribute(SP_ATTR_X, node->attribute("x")); - readSingleAttribute(SP_ATTR_Y, node->attribute("y")); - readSingleAttribute(SP_ATTR_DX, node->attribute("dx")); - readSingleAttribute(SP_ATTR_DY, node->attribute("dy")); - readSingleAttribute(SP_ATTR_ROTATE, node->attribute("rotate")); - readSingleAttribute(SP_ATTR_TEXTLENGTH, node->attribute("textLength")); - readSingleAttribute(SP_ATTR_LENGTHADJUST, node->attribute("lengthAdjust")); -} - -bool TextTagAttributes::readSingleAttribute(unsigned key, gchar const *value) +// Not used. +// void TextTagAttributes::readFrom(Inkscape::XML::Node const *node) +// { +// readSingleAttribute(SP_ATTR_X, node->attribute("x")); +// readSingleAttribute(SP_ATTR_Y, node->attribute("y")); +// readSingleAttribute(SP_ATTR_DX, node->attribute("dx")); +// readSingleAttribute(SP_ATTR_DY, node->attribute("dy")); +// readSingleAttribute(SP_ATTR_ROTATE, node->attribute("rotate")); +// readSingleAttribute(SP_ATTR_TEXTLENGTH, node->attribute("textLength")); +// readSingleAttribute(SP_ATTR_LENGTHADJUST, node->attribute("lengthAdjust")); +// } + +bool TextTagAttributes::readSingleAttribute(unsigned key, gchar const *value, SPStyle const *style, Geom::Rect const *viewport) { + // std::cout << "TextTagAttributes::readSingleAttribute: key: " << key + // << " value: " << (value?value:"Null") << std::endl; std::vector<SVGLength> *attr_vector; + bool update_x = false; + bool update_y = false; switch (key) { - case SP_ATTR_X: attr_vector = &attributes.x; break; - case SP_ATTR_Y: attr_vector = &attributes.y; break; - case SP_ATTR_DX: attr_vector = &attributes.dx; break; - case SP_ATTR_DY: attr_vector = &attributes.dy; break; + case SP_ATTR_X: attr_vector = &attributes.x; update_x = true; break; + case SP_ATTR_Y: attr_vector = &attributes.y; update_y = true; break; + case SP_ATTR_DX: attr_vector = &attributes.dx; update_x = true; break; + case SP_ATTR_DY: attr_vector = &attributes.dy; update_y = true; break; case SP_ATTR_ROTATE: attr_vector = &attributes.rotate; break; case SP_ATTR_TEXTLENGTH: attributes.textLength.readOrUnset(value); @@ -706,6 +721,19 @@ bool TextTagAttributes::readSingleAttribute(unsigned key, gchar const *value) // FIXME: sp_svg_length_list_read() amalgamates repeated separators. This prevents unset values. *attr_vector = sp_svg_length_list_read(value); + + if( (update_x || update_y) && style != NULL && viewport != NULL ) { + double const w = viewport->width(); + double const h = viewport->height(); + double const em = style->font_size.computed; + double const ex = em * 0.5; + for(std::vector<SVGLength>::iterator it = attr_vector->begin(); it != attr_vector->end(); ++it) { + if( update_x ) + it->update( em, ex, w ); + if( update_y ) + it->update( em, ex, h ); + } + } return true; } @@ -728,12 +756,26 @@ void TextTagAttributes::writeTo(Inkscape::XML::Node *node) const } } +void TextTagAttributes::update( double em, double ex, double w, double h ) +{ + for(std::vector<SVGLength>::iterator it = attributes.x.begin(); it != attributes.x.end(); ++it) { + it->update( em, ex, w ); + } + for(std::vector<SVGLength>::iterator it = attributes.y.begin(); it != attributes.y.end(); ++it) { + it->update( em, ex, h ); + } + for(std::vector<SVGLength>::iterator it = attributes.dx.begin(); it != attributes.dx.end(); ++it) { + it->update( em, ex, w ); + } + for(std::vector<SVGLength>::iterator it = attributes.dy.begin(); it != attributes.dy.end(); ++it) { + it->update( em, ex, h ); + } +} + void TextTagAttributes::writeSingleAttributeLength(Inkscape::XML::Node *node, gchar const *key, const SVGLength &length) { if (length._set) { - gchar single_value_string[32]; - g_ascii_formatd(single_value_string, sizeof (single_value_string), "%.8g", length.computed); - node->setAttribute(key, single_value_string); + node->setAttribute(key, length.write().c_str()); } else node->setAttribute(key, NULL); } @@ -744,13 +786,11 @@ void TextTagAttributes::writeSingleAttributeVector(Inkscape::XML::Node *node, gc node->setAttribute(key, NULL); else { Glib::ustring string; - gchar single_value_string[32]; // FIXME: this has no concept of unset values because sp_svg_length_list_read() can't read them back in for (std::vector<SVGLength>::const_iterator it = attr_vector.begin() ; it != attr_vector.end() ; ++it) { - g_ascii_formatd(single_value_string, sizeof (single_value_string), "%.8g", it->computed); if (!string.empty()) string += ' '; - string += single_value_string; + string += it->write(); } node->setAttribute(key, string.c_str()); } diff --git a/src/sp-tref.cpp b/src/sp-tref.cpp index aef18462a..ba592058b 100644 --- a/src/sp-tref.cpp +++ b/src/sp-tref.cpp @@ -92,7 +92,7 @@ void SPTRef::set(unsigned int key, const gchar* value) { debug("0x%p %s(%u): '%s'",this, sp_attribute_name(key),key,value ? value : "<no value>"); - if (this->attributes.readSingleAttribute(key, value)) { // x, y, dx, dy, rotate + if (this->attributes.readSingleAttribute(key, value, style, &viewport)) { // x, y, dx, dy, rotate this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); } else if (key == SP_ATTR_XLINK_HREF) { // xlink:href if ( !value ) { diff --git a/src/sp-tspan.cpp b/src/sp-tspan.cpp index 7582cb9e6..05f8430ba 100644 --- a/src/sp-tspan.cpp +++ b/src/sp-tspan.cpp @@ -70,7 +70,7 @@ void SPTSpan::release() { } void SPTSpan::set(unsigned int key, const gchar* value) { - if (this->attributes.readSingleAttribute(key, value)) { + if (this->attributes.readSingleAttribute(key, value, style, &viewport)) { this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); } else { switch (key) { @@ -103,6 +103,20 @@ void SPTSpan::update(SPCtx *ctx, guint flags) { } SPItem::update(ctx, flags); + + if (flags & ( SP_OBJECT_STYLE_MODIFIED_FLAG | + SP_OBJECT_CHILD_MODIFIED_FLAG | + SP_TEXT_LAYOUT_MODIFIED_FLAG ) ) + { + SPItemCtx const *ictx = reinterpret_cast<SPItemCtx const *>(ctx); + + double const w = ictx->viewport.width(); + double const h = ictx->viewport.height(); + double const em = style->font_size.computed; + double const ex = 0.5 * em; // fixme: get x height from pango or libnrtype. + + attributes.update( em, ex, w, h ); + } } void SPTSpan::modified(unsigned int flags) { @@ -264,7 +278,7 @@ void SPTextPath::release() { } void SPTextPath::set(unsigned int key, const gchar* value) { - if (this->attributes.readSingleAttribute(key, value)) { + if (this->attributes.readSingleAttribute(key, value, style, &viewport)) { this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); } else { switch (key) { @@ -304,6 +318,20 @@ void SPTextPath::update(SPCtx *ctx, guint flags) { ochild->updateDisplay(ctx, flags); } } + + if (flags & ( SP_OBJECT_STYLE_MODIFIED_FLAG | + SP_OBJECT_CHILD_MODIFIED_FLAG | + SP_TEXT_LAYOUT_MODIFIED_FLAG ) ) + { + SPItemCtx const *ictx = reinterpret_cast<SPItemCtx const *>(ctx); + + double const w = ictx->viewport.width(); + double const h = ictx->viewport.height(); + double const em = style->font_size.computed; + double const ex = 0.5 * em; // fixme: get x height from pango or libnrtype. + + attributes.update( em, ex, w, h ); + } } diff --git a/src/style-enums.h b/src/style-enums.h index dfc99282c..06207852c 100644 --- a/src/style-enums.h +++ b/src/style-enums.h @@ -163,12 +163,6 @@ enum SPCSSDirection { SP_CSS_DIRECTION_RTL }; -enum SPCSSBlockProgression { - SP_CSS_BLOCK_PROGRESSION_TB, - SP_CSS_BLOCK_PROGRESSION_RL, - SP_CSS_BLOCK_PROGRESSION_LR -}; - enum SPCSSWritingMode { SP_CSS_WRITING_MODE_LR_TB, SP_CSS_WRITING_MODE_RL_TB, @@ -176,6 +170,13 @@ enum SPCSSWritingMode { SP_CSS_WRITING_MODE_TB_LR }; +// CSS WRITING MODES 3 +enum SPCSSTextOrientation { + SP_CSS_TEXT_ORIENTATION_MIXED, + SP_CSS_TEXT_ORIENTATION_UPRIGHT, + SP_CSS_TEXT_ORIENTATION_SIDEWAYS +}; + enum SPTextAnchor { SP_CSS_TEXT_ANCHOR_START, SP_CSS_TEXT_ANCHOR_MIDDLE, @@ -190,10 +191,24 @@ enum SPWhiteSpace { SP_CSS_WHITE_SPACE_PRELINE }; +// Not complete list +enum SPCSSBaseline { + SP_CSS_BASELINE_AUTO, + SP_CSS_BASELINE_ALPHABETIC, + SP_CSS_BASELINE_IDEOGRAPHIC, + SP_CSS_BASELINE_HANGING, + SP_CSS_BASELINE_MATHEMATICAL, + SP_CSS_BASELINE_CENTRAL, + SP_CSS_BASELINE_MIDDLE, + SP_CSS_BASELINE_TEXT_BEFORE_EDGE, + SP_CSS_BASELINE_TEXT_AFTER_EDGE, + SP_CSS_BASELINE_SIZE // Size of enum, keep last. +}; + enum SPCSSBaselineShift { - SP_CSS_BASELINE_SHIFT_BASELINE, - SP_CSS_BASELINE_SHIFT_SUB, - SP_CSS_BASELINE_SHIFT_SUPER + SP_CSS_BASELINE_SHIFT_BASELINE, + SP_CSS_BASELINE_SHIFT_SUB, + SP_CSS_BASELINE_SHIFT_SUPER }; enum SPVisibility { @@ -489,13 +504,6 @@ static SPStyleEnum const enum_direction[] = { {NULL, -1} }; -static SPStyleEnum const enum_block_progression[] = { - {"tb", SP_CSS_BLOCK_PROGRESSION_TB}, - {"rl", SP_CSS_BLOCK_PROGRESSION_RL}, - {"lr", SP_CSS_BLOCK_PROGRESSION_LR}, - {NULL, -1} -}; - static SPStyleEnum const enum_writing_mode[] = { /* Note that using the same enumerator for lr as lr-tb means we write as lr-tb even if the * input file said lr. We prefer writing lr-tb on the grounds that the spec says the initial @@ -504,12 +512,38 @@ static SPStyleEnum const enum_writing_mode[] = { * ECMA scripts may be surprised to find tb-rl in DOM if they set the attribute to rl, so * sharing enumerators for different strings may be a bug (once we support ecma script). */ + // SVG 1.1 Deprecated but still must be supported in SVG 2. {"lr-tb", SP_CSS_WRITING_MODE_LR_TB}, {"rl-tb", SP_CSS_WRITING_MODE_RL_TB}, {"tb-rl", SP_CSS_WRITING_MODE_TB_RL}, {"lr", SP_CSS_WRITING_MODE_LR_TB}, {"rl", SP_CSS_WRITING_MODE_RL_TB}, {"tb", SP_CSS_WRITING_MODE_TB_RL}, + // SVG 2 & CSS 3 Writing Modes + {"horizontal-tb", SP_CSS_WRITING_MODE_LR_TB}, // This is correct, 'direction' distinguishes between 'lr' and 'rl'. + {"vertical-rl", SP_CSS_WRITING_MODE_TB_RL}, + {"vertical-lr", SP_CSS_WRITING_MODE_TB_LR}, + {NULL, -1} +}; + +// CSS WRITING MODES 3 +static SPStyleEnum const enum_text_orientation[] = { + {"mixed", SP_CSS_TEXT_ORIENTATION_MIXED}, // Default + {"upright", SP_CSS_TEXT_ORIENTATION_UPRIGHT}, + {"sideways", SP_CSS_TEXT_ORIENTATION_SIDEWAYS}, + {NULL, -1} +}; + +static SPStyleEnum const enum_baseline[] = { + {"auto", SP_CSS_BASELINE_AUTO}, // Default + {"alphabetic", SP_CSS_BASELINE_ALPHABETIC}, + {"ideographic", SP_CSS_BASELINE_IDEOGRAPHIC}, + {"hanging", SP_CSS_BASELINE_HANGING}, + {"mathematical", SP_CSS_BASELINE_MATHEMATICAL}, + {"central", SP_CSS_BASELINE_CENTRAL}, + {"middle", SP_CSS_BASELINE_MIDDLE}, + {"text-before-edge", SP_CSS_BASELINE_TEXT_BEFORE_EDGE}, + {"text-after-edge", SP_CSS_BASELINE_TEXT_AFTER_EDGE}, {NULL, -1} }; diff --git a/src/style-internal.h b/src/style-internal.h index 1ddab30f1..889292454 100644 --- a/src/style-internal.h +++ b/src/style-internal.h @@ -1260,7 +1260,6 @@ struct SPITextDecorationData { float tspan_width; // from libnrtype, when it calculates spans float ascender; // the rest from tspan's font float descender; - float line_gap; float underline_thickness; float underline_position; float line_through_thickness; diff --git a/src/style.cpp b/src/style.cpp index d8402e08a..2a216e940 100644 --- a/src/style.cpp +++ b/src/style.cpp @@ -113,7 +113,7 @@ SPStyle::SPStyle(SPDocument *document_in, SPObject *object_in) : font_weight( "font-weight", enum_font_weight, SP_CSS_FONT_WEIGHT_NORMAL, SP_CSS_FONT_WEIGHT_400 ), font_stretch( "font-stretch", enum_font_stretch, SP_CSS_FONT_STRETCH_NORMAL ), font_size(), - line_height( "line-height", 1.0 ), // SPILengthOrNormal + line_height( "line-height", 1.25 ), // SPILengthOrNormal font_family( "font-family", "sans-serif" ), // SPIString w/default font(), // SPIFont font_specification( "-inkscape-font-specification" ), // SPIString @@ -136,8 +136,9 @@ SPStyle::SPStyle(SPDocument *document_in, SPObject *object_in) : text_transform( "text-transform", enum_text_transform, SP_CSS_TEXT_TRANSFORM_NONE ), direction( "direction", enum_direction, SP_CSS_DIRECTION_LTR ), - block_progression("block-progression", enum_block_progression, SP_CSS_BLOCK_PROGRESSION_TB), writing_mode( "writing-mode", enum_writing_mode, SP_CSS_WRITING_MODE_LR_TB ), + text_orientation( "text-orientation",enum_text_orientation,SP_CSS_TEXT_ORIENTATION_MIXED ), + dominant_baseline("dominant-baseline",enum_baseline, SP_CSS_BASELINE_AUTO ), baseline_shift(), text_anchor( "text-anchor", enum_text_anchor, SP_CSS_TEXT_ANCHOR_START ), white_space( "white-space", enum_white_space, SP_CSS_WHITE_SPACE_NORMAL ), @@ -318,9 +319,10 @@ SPStyle::SPStyle(SPDocument *document_in, SPObject *object_in) : _properties.push_back( &word_spacing ); _properties.push_back( &text_transform ); - _properties.push_back( &direction ); - _properties.push_back( &block_progression ); _properties.push_back( &writing_mode ); + _properties.push_back( &direction ); + _properties.push_back( &text_orientation ); + _properties.push_back( &dominant_baseline ); _properties.push_back( &baseline_shift ); _properties.push_back( &text_anchor ); _properties.push_back( &white_space ); @@ -413,8 +415,9 @@ SPStyle::SPStyle(SPDocument *document_in, SPObject *object_in) : // _propmap.insert( std::make_pair( text_transform.name, reinterpret_cast<SPIBasePtr>(&SPStyle::text_transform ) ) ); // _propmap.insert( std::make_pair( direction.name, reinterpret_cast<SPIBasePtr>(&SPStyle::direction ) ) ); - // _propmap.insert( std::make_pair( block_progression.name, reinterpret_cast<SPIBasePtr>(&SPStyle::block_progression ) ) ); // _propmap.insert( std::make_pair( writing_mode.name, reinterpret_cast<SPIBasePtr>(&SPStyle::writing_mode ) ) ); + // _propmap.insert( std::make_pair( text_orientation.name, reinterpret_cast<SPIBasePtr>(&SPStyle::text_orientation ) ) ); + // _propmap.insert( std::make_pair( dominant_baseline.name, reinterpret_cast<SPIBasePtr>(&SPStyle::dominant_baseline ) ) ); // _propmap.insert( std::make_pair( baseline_shift.name, reinterpret_cast<SPIBasePtr>(&SPStyle::baseline_shift ) ) ); // _propmap.insert( std::make_pair( text_anchor.name, reinterpret_cast<SPIBasePtr>(&SPStyle::text_anchor ) ) ); // _propmap.insert( std::make_pair( white_space.name, reinterpret_cast<SPIBasePtr>(&SPStyle::white_space ) ) ); @@ -778,12 +781,12 @@ SPStyle::readIfUnset( gint id, gchar const *val ) { case SP_PROP_DIRECTION: direction.readIfUnset( val ); break; - case SP_PROP_BLOCK_PROGRESSION: - block_progression.readIfUnset( val ); - break; case SP_PROP_WRITING_MODE: writing_mode.readIfUnset( val ); break; + case SP_PROP_TEXT_ORIENTATION: + text_orientation.readIfUnset( val ); + break; case SP_PROP_TEXT_ANCHOR: text_anchor.readIfUnset( val ); break; @@ -796,6 +799,9 @@ SPStyle::readIfUnset( gint id, gchar const *val ) { case SP_PROP_SHAPE_PADDING: shape_padding.readIfUnset( val ); break; + case SP_PROP_DOMINANT_BASELINE: + dominant_baseline.readIfUnset( val ); + break; case SP_PROP_BASELINE_SHIFT: baseline_shift.readIfUnset( val ); break; @@ -805,9 +811,6 @@ SPStyle::readIfUnset( gint id, gchar const *val ) { case SP_PROP_ALIGNMENT_BASELINE: g_warning("Unimplemented style property SP_PROP_ALIGNMENT_BASELINE: value: %s", val); break; - case SP_PROP_DOMINANT_BASELINE: - g_warning("Unimplemented style property SP_PROP_DOMINANT_BASELINE: value: %s", val); - break; case SP_PROP_GLYPH_ORIENTATION_HORIZONTAL: g_warning("Unimplemented style property SP_PROP_ORIENTATION_HORIZONTAL: value: %s", val); break; @@ -1258,7 +1261,7 @@ SPStyle::getFontFeatureString() { if( font_variant_east_asian.value & SP_CSS_FONT_VARIANT_EAST_ASIAN_RUBY ) feature_string += "ruby, "; - if ( strcmp( font_feature_settings.value, "normal") ) { + if ( font_feature_settings.value && strcmp( font_feature_settings.value, "normal") ) { // We do no sanity checking... feature_string += font_feature_settings.value; feature_string += ", "; @@ -1689,16 +1692,19 @@ sp_style_unset_property_attrs(SPObject *o) repr->setAttribute("text-anchor", NULL); } if (style->white_space.set) { - repr->setAttribute("white_space", NULL); + repr->setAttribute("white-space", NULL); } if (style->shape_inside.set) { - repr->setAttribute("shape_inside", NULL); + repr->setAttribute("shape-inside", NULL); } if (style->shape_padding.set) { - repr->setAttribute("shape_padding", NULL); + repr->setAttribute("shape-padding", NULL); } if (style->writing_mode.set) { - repr->setAttribute("writing_mode", NULL); + repr->setAttribute("writing-mode", NULL); + } + if (style->text_orientation.set) { + repr->setAttribute("text-orientation", NULL); } if (style->filter.set) { repr->setAttribute("filter", NULL); @@ -1781,8 +1787,8 @@ sp_css_attr_unset_text(SPCSSAttr *css) sp_repr_css_set_property(css, "word-spacing", NULL); sp_repr_css_set_property(css, "text-transform", NULL); sp_repr_css_set_property(css, "direction", NULL); - sp_repr_css_set_property(css, "block-progression", NULL); sp_repr_css_set_property(css, "writing-mode", NULL); + sp_repr_css_set_property(css, "text-orientation", NULL); sp_repr_css_set_property(css, "text-anchor", NULL); sp_repr_css_set_property(css, "white-space", NULL); sp_repr_css_set_property(css, "shape-inside", NULL); diff --git a/src/style.h b/src/style.h index 02432d3e7..0e8e34145 100644 --- a/src/style.h +++ b/src/style.h @@ -142,12 +142,14 @@ public: SPIEnum text_transform; /* CSS3 Text */ - /** text direction (css3 text 3.2) */ + /** text direction (svg1.1) */ SPIEnum direction; - /** block progression (css3 text 3.2) */ - SPIEnum block_progression; - /** Writing mode (css3 text 3.2 and svg1.1 10.7.2) */ + /** Writing mode (svg1.1 10.7.2, CSS Writing Modes 3) */ SPIEnum writing_mode; + /** Text orientation (CSS Writing Modes 3) */ + SPIEnum text_orientation; + /** Dominant baseline (svg1.1) */ + SPIEnum dominant_baseline; /** Baseline shift (svg1.1 10.9.2) */ SPIBaselineShift baseline_shift; diff --git a/src/svg/CMakeLists.txt b/src/svg/CMakeLists.txt index f9d0bc52d..ff4bb63ab 100644 --- a/src/svg/CMakeLists.txt +++ b/src/svg/CMakeLists.txt @@ -2,7 +2,7 @@ set(svg_SRC css-ostringstream.cpp path-string.cpp - sp-svg.def + #sp-svg.def stringstream.cpp strip-trailing-zeros.cpp svg-affine.cpp diff --git a/src/svg/svg-length.cpp b/src/svg/svg-length.cpp index edbc59c36..cd995582d 100644 --- a/src/svg/svg-length.cpp +++ b/src/svg/svg-length.cpp @@ -463,7 +463,7 @@ unsigned int sp_svg_length_read_ldd(gchar const *str, SVGLength::Unit *unit, dou return r; } -std::string const SVGLength::write() +std::string SVGLength::write() const { return sp_svg_length_write_with_units(*this); } diff --git a/src/svg/svg-length.h b/src/svg/svg-length.h index 84056dd5f..2aaf248b1 100644 --- a/src/svg/svg-length.h +++ b/src/svg/svg-length.h @@ -57,7 +57,7 @@ public: bool read(char const *str); void readOrUnset(char const *str, Unit u = NONE, float v = 0, float c = 0); bool readAbsolute(char const *str); - std::string const write(); + std::string write() const; // To set 'v' use '=' void set(Unit u, float v); // Sets computed value based on u and v. void set(Unit u, float v, float c); // Sets all three values. diff --git a/src/text-chemistry.cpp b/src/text-chemistry.cpp index 9fc862ad2..fbbbe5807 100644 --- a/src/text-chemistry.cpp +++ b/src/text-chemistry.cpp @@ -44,7 +44,7 @@ static SPItem * flowtext_in_selection(Inkscape::Selection *selection) { std::vector<SPItem*> items = selection->itemList(); - for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++){ + for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();++i){ if (SP_IS_FLOWTEXT(*i)) return *i; } @@ -55,7 +55,7 @@ static SPItem * text_or_flowtext_in_selection(Inkscape::Selection *selection) { std::vector<SPItem*> items = selection->itemList(); - for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++){ + for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();++i){ if (SP_IS_TEXT(*i) || SP_IS_FLOWTEXT(*i)) return *i; } @@ -66,7 +66,7 @@ static SPItem * shape_in_selection(Inkscape::Selection *selection) { std::vector<SPItem*> items = selection->itemList(); - for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++){ + for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();++i){ if (SP_IS_SHAPE(*i)) return *i; } @@ -197,7 +197,7 @@ text_remove_from_path() bool did = false; std::vector<SPItem*> items(selection->itemList()); - for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++){ + for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();++i){ SPObject *obj = *i; if (SP_IS_TEXT_TEXTPATH(obj)) { @@ -261,7 +261,7 @@ text_remove_all_kerns() bool did = false; std::vector<SPItem*> items = selection->itemList(); - for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++){ + for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();++i){ SPObject *obj = *i; if (!SP_IS_TEXT(obj) && !SP_IS_TSPAN(obj) && !SP_IS_FLOWTEXT(obj)) { @@ -321,7 +321,7 @@ text_flow_into_shape() /* Add clones */ std::vector<SPItem*> items = selection->itemList(); - for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++){ + for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();++i){ SPItem *item = *i; if (SP_IS_SHAPE(item)){ Inkscape::XML::Node *clone = xml_doc->createElement("svg:use"); @@ -396,7 +396,7 @@ text_unflow () GSList *old_objs = NULL; std::vector<SPItem*> items = selection->itemList(); - for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++){ + for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();++i){ if (!SP_IS_FLOWTEXT(*i)) { continue; @@ -481,7 +481,7 @@ flowtext_to_text() std::vector<Inkscape::XML::Node*> reprs; std::vector<SPItem*> items(selection->itemList()); - for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++){ + for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();++i){ SPItem *item = *i; diff --git a/src/text-editing.cpp b/src/text-editing.cpp index d9cebc625..057523b1e 100644 --- a/src/text-editing.cpp +++ b/src/text-editing.cpp @@ -68,7 +68,7 @@ void te_update_layout_now_recursive(SPItem *item) { if (SP_IS_GROUP(item)) { std::vector<SPItem*> item_list = sp_item_group_item_list(SP_GROUP(item)); - for(std::vector<SPItem*>::const_iterator i=item_list.begin();i!=item_list.end();i++){ + for(std::vector<SPItem*>::const_iterator i=item_list.begin();i!=item_list.end();++i){ SPItem* list_item = *i; te_update_layout_now_recursive(list_item); } diff --git a/src/text-tag-attributes.h b/src/text-tag-attributes.h index 7a389ed39..2cf7a8bde 100644 --- a/src/text-tag-attributes.h +++ b/src/text-tag-attributes.h @@ -31,11 +31,14 @@ public: /** Process the parameters from the set() function of SPObject. Returns true if \a key was a recognised attribute. */ - bool readSingleAttribute(unsigned key, gchar const *value); + bool readSingleAttribute(unsigned key, gchar const *value, SPStyle const *style, Geom::Rect const *viewport); /// Write out all the contents of #attributes to the given node. void writeTo(Inkscape::XML::Node *node) const; + /// Update relative values + void update( double em, double ex, double w, double h ); + /** For tspan role=line elements we should not use the set x,y coordinates since that would overrule the values calculated by the text layout engine, however if there are more than one element in diff --git a/src/trace/CMakeLists.txt b/src/trace/CMakeLists.txt index bf7cfa276..12cf495f6 100644 --- a/src/trace/CMakeLists.txt +++ b/src/trace/CMakeLists.txt @@ -1,3 +1,4 @@ +if (${HAVE_POTRACE}) set(trace_SRC filterset.cpp @@ -7,14 +8,7 @@ set(trace_SRC siox.cpp trace.cpp - potrace/curve.cpp - potrace/decompose.cpp - potrace/greymap.cpp potrace/inkscape-potrace.cpp - potrace/potracelib.cpp - potrace/render.cpp - potrace/trace.cpp - # ------- # Headers @@ -26,19 +20,11 @@ set(trace_SRC siox.h trace.h - potrace/auxiliary.h potrace/bitmap.h - potrace/bitops.h - potrace/curve.h - potrace/decompose.h - potrace/greymap.h potrace/inkscape-potrace.h - potrace/lists.h - potrace/potracelib.h - potrace/progress.h - potrace/render.h - potrace/trace.h ) # add_inkscape_lib(trace_LIB "${trace_SRC}") add_inkscape_source("${trace_SRC}") + +endif() diff --git a/src/trace/Makefile_insert b/src/trace/Makefile_insert index 21ec4ac0c..27353df15 100644 --- a/src/trace/Makefile_insert +++ b/src/trace/Makefile_insert @@ -1,5 +1,7 @@ ## Makefile.am fragment sourced by src/Makefile.am. +if HAVE_POTRACE + ink_common_sources += \ trace/pool.h \ trace/trace.h \ @@ -14,21 +16,8 @@ ink_common_sources += \ trace/filterset.cpp \ trace/siox.h \ trace/siox.cpp \ - trace/potrace/auxiliary.h \ - trace/potrace/bitmap.h \ - trace/potrace/curve.cpp \ - trace/potrace/curve.h \ - trace/potrace/decompose.cpp \ - trace/potrace/decompose.h \ - trace/potrace/greymap.cpp \ - trace/potrace/greymap.h \ - trace/potrace/lists.h \ - trace/potrace/potracelib.cpp \ - trace/potrace/potracelib.h \ - trace/potrace/progress.h \ - trace/potrace/render.cpp \ - trace/potrace/render.h \ - trace/potrace/trace.cpp \ - trace/potrace/trace.h \ + trace/potrace/bitmap.h \ trace/potrace/inkscape-potrace.cpp \ trace/potrace/inkscape-potrace.h + +endif diff --git a/src/trace/potrace/auxiliary.h b/src/trace/potrace/auxiliary.h deleted file mode 100644 index dbf124d7c..000000000 --- a/src/trace/potrace/auxiliary.h +++ /dev/null @@ -1,80 +0,0 @@ -/* Copyright (C) 2001-2015 Peter Selinger. - This file is part of Potrace. It is free software and it is covered - by the GNU General Public License. See the file COPYING for details. */ - -/* This header file collects some general-purpose macros (and static - inline functions) that are used in various places. */ - -#ifndef AUXILIARY_H -#define AUXILIARY_H - -#include <stdlib.h> - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -/* ---------------------------------------------------------------------- */ -/* point arithmetic */ - -#include "potracelib.h" - -struct point_s { - long x; - long y; -}; -typedef struct point_s point_t; - -typedef potrace_dpoint_t dpoint_t; - -/* convert point_t to dpoint_t */ -static inline dpoint_t dpoint(point_t p) { - dpoint_t res; - res.x = p.x; - res.y = p.y; - return res; -} - -/* range over the straight line segment [a,b] when lambda ranges over [0,1] */ -static inline dpoint_t interval(double lambda, dpoint_t a, dpoint_t b) { - dpoint_t res; - - res.x = a.x + lambda * (b.x - a.x); - res.y = a.y + lambda * (b.y - a.y); - return res; -} - -/* ---------------------------------------------------------------------- */ -/* some useful macros. Note: the "mod" macro works correctly for - negative a. Also note that the test for a>=n, while redundant, - speeds up the mod function by 70% in the average case (significant - since the program spends about 16% of its time here - or 40% - without the test). The "floordiv" macro returns the largest integer - <= a/n, and again this works correctly for negative a, as long as - a,n are integers and n>0. */ - -/* integer arithmetic */ - -static inline int mod(int a, int n) { - return a>=n ? a%n : a>=0 ? a : n-1-(-1-a)%n; -} - -static inline int floordiv(int a, int n) { - return a>=0 ? a/n : -1-(-1-a)/n; -} - -/* Note: the following work for integers and other numeric types. */ -#undef sign -#undef abs -#undef min -#undef max -#undef sq -#undef cu -#define sign(x) ((x)>0 ? 1 : (x)<0 ? -1 : 0) -#define abs(a) ((a)>0 ? (a) : -(a)) -#define min(a,b) ((a)<(b) ? (a) : (b)) -#define max(a,b) ((a)>(b) ? (a) : (b)) -#define sq(a) ((a)*(a)) -#define cu(a) ((a)*(a)*(a)) - -#endif /* AUXILIARY_H */ diff --git a/src/trace/potrace/bitmap.h b/src/trace/potrace/bitmap.h index 086bbb046..7b5a94bb1 100644 --- a/src/trace/potrace/bitmap.h +++ b/src/trace/potrace/bitmap.h @@ -8,6 +8,7 @@ #include <string.h> #include <stdlib.h> #include <errno.h> +#include <stddef.h> /* The bitmap type is defined in potracelib.h */ #include "potracelib.h" @@ -28,7 +29,7 @@ /* macros for accessing pixel at index (x,y). U* macros omit the bounds check. */ -#define bm_scanline(bm, y) ((bm)->map + (ssize_t)(y)*(ssize_t)(bm)->dy) +#define bm_scanline(bm, y) ((bm)->map + (ptrdiff_t)(y)*(ptrdiff_t)(bm)->dy) #define bm_index(bm, x, y) (&bm_scanline(bm, y)[(x)/BM_WORDBITS]) #define bm_mask(x) (BM_HIBIT >> ((x) & (BM_WORDBITS-1))) #define bm_range(x, a) ((int)(x) >= 0 && (int)(x) < (a)) @@ -57,10 +58,10 @@ static inline void bm_free(potrace_bitmap_t *bm) { static inline potrace_bitmap_t *bm_new(int w, int h) { potrace_bitmap_t *bm; int dy = w == 0 ? 0 : (w - 1) / BM_WORDBITS + 1; - ssize_t size = (ssize_t)dy * (ssize_t)h * (ssize_t)BM_WORDSIZE; + ptrdiff_t size = (ptrdiff_t)dy * (ptrdiff_t)h * (ptrdiff_t)BM_WORDSIZE; /* check for overflow error */ - if (size < 0 || size / h / dy != BM_WORDSIZE) { + if (size < 0 || (h != 0 && dy != 0 && size / h / dy != BM_WORDSIZE)) { errno = ENOMEM; return NULL; } @@ -83,15 +84,15 @@ static inline potrace_bitmap_t *bm_new(int w, int h) { /* clear the given bitmap. Set all bits to c. */ static inline void bm_clear(potrace_bitmap_t *bm, int c) { /* Note: if the bitmap was created with bm_new, then it is - guaranteed that size will fit into the ssize_t type. */ - ssize_t size = (ssize_t)bm->dy * (ssize_t)bm->h * (ssize_t)BM_WORDSIZE; + guaranteed that size will fit into the ptrdiff_t type. */ + ptrdiff_t size = (ptrdiff_t)bm->dy * (ptrdiff_t)bm->h * (ptrdiff_t)BM_WORDSIZE; memset(bm->map, c ? -1 : 0, size); } /* duplicate the given bitmap. Return NULL on error with errno set. */ static inline potrace_bitmap_t *bm_dup(const potrace_bitmap_t *bm) { potrace_bitmap_t *bm1 = bm_new(bm->w, bm->h); - ssize_t size = (ssize_t)bm->dy * (ssize_t)bm->h * (ssize_t)BM_WORDSIZE; + ptrdiff_t size = (ptrdiff_t)bm->dy * (ptrdiff_t)bm->h * (ptrdiff_t)BM_WORDSIZE; if (!bm1) { return NULL; } @@ -101,8 +102,8 @@ static inline potrace_bitmap_t *bm_dup(const potrace_bitmap_t *bm) { /* invert the given bitmap. */ static inline void bm_invert(potrace_bitmap_t *bm) { - ssize_t i; - ssize_t size = (ssize_t)bm->dy * (ssize_t)bm->h; + ptrdiff_t i; + ptrdiff_t size = (ptrdiff_t)bm->dy * (ptrdiff_t)bm->h; for (i = 0; i < size; i++) { bm->map[i] ^= BM_ALLBITS; diff --git a/src/trace/potrace/bitops.h b/src/trace/potrace/bitops.h deleted file mode 100644 index cff734a46..000000000 --- a/src/trace/potrace/bitops.h +++ /dev/null @@ -1,83 +0,0 @@ -/* Copyright (C) 2001-2015 Peter Selinger. - This file is part of Potrace. It is free software and it is covered - by the GNU General Public License. See the file COPYING for details. */ - - -/* bits.h: this file defines some macros for bit manipulations. We - provide a generic implementation, as well as machine- and - compiler-specific fast implementations */ - -/* lobit: return the position of the rightmost "1" bit of an int, or - 32 if none. hibit: return 1 + the position of the leftmost "1" bit - of an int, or 0 if none. Note: these functions work on 32-bit - integers. */ - -#ifndef BITOPS_H -#define BITOPS_H - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -/* ---------------------------------------------------------------------- */ -/* machine specific macros */ - -#if defined(HAVE_I386) - -static inline unsigned int lobit(unsigned int x) { - unsigned int res; - asm ("bsf %1,%0\n\t" - "jnz 0f\n\t" - "movl $32,%0\n" - "0:" - : "=r" (res) - : "r" (x) - : "cc"); - return res; -} - -static inline unsigned int hibit(unsigned int x) { - unsigned int res; - - asm ("bsr %1,%0\n\t" - "jnz 0f\n\t" - "movl $-1,%0\n" - "0:" - : "=r" (res) - : "r" (x) - : "cc"); - return res+1; -} - -/* ---------------------------------------------------------------------- */ -#else /* generic macros */ - -static inline unsigned int lobit(unsigned int x) { - unsigned int res = 32; - while (x & 0xffffff) { - x <<= 8; - res -= 8; - } - while (x) { - x <<= 1; - res -= 1; - } - return res; -} - -static inline unsigned int hibit(unsigned int x) { - unsigned int res = 0; - while (x > 0xff) { - x >>= 8; - res += 8; - } - while (x) { - x >>= 1; - res += 1; - } - return res; -} - -#endif - -#endif /* BITOPS_H */ diff --git a/src/trace/potrace/curve.cpp b/src/trace/potrace/curve.cpp deleted file mode 100644 index e6a9a4721..000000000 --- a/src/trace/potrace/curve.cpp +++ /dev/null @@ -1,108 +0,0 @@ -/* Copyright (C) 2001-2015 Peter Selinger. - This file is part of Potrace. It is free software and it is covered - by the GNU General Public License. See the file COPYING for details. */ - -/* private part of the path and curve data structures */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "potracelib.h" -#include "lists.h" -#include "curve.h" - -#define SAFE_CALLOC(var, n, typ) \ - if ((var = (typ *)calloc(n, sizeof(typ))) == NULL) goto calloc_error - -/* ---------------------------------------------------------------------- */ -/* allocate and free path objects */ - -path_t *path_new(void) { - path_t *p = NULL; - privpath_t *priv = NULL; - - SAFE_CALLOC(p, 1, path_t); - memset(p, 0, sizeof(path_t)); - SAFE_CALLOC(priv, 1, privpath_t); - memset(priv, 0, sizeof(privpath_t)); - p->priv = priv; - return p; - - calloc_error: - free(p); - free(priv); - return NULL; -} - -/* free the members of the given curve structure. Leave errno unchanged. */ -static void privcurve_free_members(privcurve_t *curve) { - free(curve->tag); - free(curve->c); - free(curve->vertex); - free(curve->alpha); - free(curve->alpha0); - free(curve->beta); -} - -/* free a path. Leave errno untouched. */ -void path_free(path_t *p) { - if (p) { - if (p->priv) { - free(p->priv->pt); - free(p->priv->lon); - free(p->priv->sums); - free(p->priv->po); - privcurve_free_members(&p->priv->curve); - privcurve_free_members(&p->priv->ocurve); - } - free(p->priv); - /* do not free p->fcurve ! */ - } - free(p); -} - -/* free a pathlist, leaving errno untouched. */ -void pathlist_free(path_t *plist) { - path_t *p; - - list_forall_unlink(p, plist) { - path_free(p); - } -} - -/* ---------------------------------------------------------------------- */ -/* initialize and finalize curve structures */ - -typedef dpoint_t dpoint3_t[3]; - -/* initialize the members of the given curve structure to size m. - Return 0 on success, 1 on error with errno set. */ -int privcurve_init(privcurve_t *curve, int n) { - memset(curve, 0, sizeof(privcurve_t)); - curve->n = n; - SAFE_CALLOC(curve->tag, n, int); - SAFE_CALLOC(curve->c, n, dpoint3_t); - SAFE_CALLOC(curve->vertex, n, dpoint_t); - SAFE_CALLOC(curve->alpha, n, double); - SAFE_CALLOC(curve->alpha0, n, double); - SAFE_CALLOC(curve->beta, n, double); - return 0; - - calloc_error: - free(curve->tag); - free(curve->c); - free(curve->vertex); - free(curve->alpha); - free(curve->alpha0); - free(curve->beta); - return 1; -} - -/* copy private to public curve structure */ -void privcurve_to_curve(privcurve_t *pc, potrace_curve_t *c) { - c->n = pc->n; - c->tag = pc->tag; - c->c = pc->c; -} - diff --git a/src/trace/potrace/curve.h b/src/trace/potrace/curve.h deleted file mode 100644 index feb95b39b..000000000 --- a/src/trace/potrace/curve.h +++ /dev/null @@ -1,77 +0,0 @@ -/* Copyright (C) 2001-2015 Peter Selinger. - This file is part of Potrace. It is free software and it is covered - by the GNU General Public License. See the file COPYING for details. */ - -#ifndef CURVE_H -#define CURVE_H - -#include "auxiliary.h" - -/* vertex is c[1] for tag=POTRACE_CORNER, and the intersection of - .c[-1][2]..c[0] and c[1]..c[2] for tag=POTRACE_CURVETO. alpha is only - defined for tag=POTRACE_CURVETO and is the alpha parameter of the curve: - .c[-1][2]..c[0] = alpha*(.c[-1][2]..vertex), and - c[2]..c[1] = alpha*(c[2]..vertex). - Beta is so that (.beta[i])[.vertex[i],.vertex[i+1]] = .c[i][2]. -*/ - -struct privcurve_s { - int n; /* number of segments */ - int *tag; /* tag[n]: POTRACE_CORNER or POTRACE_CURVETO */ - dpoint_t (*c)[3]; /* c[n][i]: control points. - c[n][0] is unused for tag[n]=POTRACE_CORNER */ - /* the remainder of this structure is special to privcurve, and is - used in EPS debug output and special EPS "short coding". These - fields are valid only if "alphacurve" is set. */ - int alphacurve; /* have the following fields been initialized? */ - dpoint_t *vertex; /* for POTRACE_CORNER, this equals c[1] */ - double *alpha; /* only for POTRACE_CURVETO */ - double *alpha0; /* "uncropped" alpha parameter - for debug output only */ - double *beta; -}; -typedef struct privcurve_s privcurve_t; - -struct sums_s { - double x; - double y; - double x2; - double xy; - double y2; -}; -typedef struct sums_s sums_t; - -/* the path structure is filled in with information about a given path - as it is accumulated and passed through the different stages of the - Potrace algorithm. Backends only need to read the fcurve and fm - fields of this data structure, but debugging backends may read - other fields. */ -struct potrace_privpath_s { - int len; - point_t *pt; /* pt[len]: path as extracted from bitmap */ - int *lon; /* lon[len]: (i,lon[i]) = longest straight line from i */ - - int x0, y0; /* origin for sums */ - sums_t *sums; /* sums[len+1]: cache for fast summing */ - - int m; /* length of optimal polygon */ - int *po; /* po[m]: optimal polygon */ - - privcurve_t curve; /* curve[m]: array of curve elements */ - privcurve_t ocurve; /* ocurve[om]: array of curve elements */ - privcurve_t *fcurve; /* final curve: this points to either curve or - ocurve. Do not free this separately. */ -}; -typedef struct potrace_privpath_s potrace_privpath_t; - -/* shorter names */ -typedef potrace_privpath_t privpath_t; -typedef potrace_path_t path_t; - -path_t *path_new(void); -void path_free(path_t *p); -void pathlist_free(path_t *plist); -int privcurve_init(privcurve_t *curve, int n); -void privcurve_to_curve(privcurve_t *pc, potrace_curve_t *c); - -#endif /* CURVE_H */ - diff --git a/src/trace/potrace/decompose.cpp b/src/trace/potrace/decompose.cpp deleted file mode 100644 index 7628b202d..000000000 --- a/src/trace/potrace/decompose.cpp +++ /dev/null @@ -1,511 +0,0 @@ -/* Copyright (C) 2001-2015 Peter Selinger. - This file is part of Potrace. It is free software and it is covered - by the GNU General Public License. See the file COPYING for details. */ - - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <limits.h> - -#include "potracelib.h" -#include "curve.h" -#include "lists.h" -#include "bitmap.h" -#include "decompose.h" -#include "progress.h" - -/* ---------------------------------------------------------------------- */ -/* deterministically and efficiently hash (x,y) into a pseudo-random bit */ - -static inline int detrand(int x, int y) { - unsigned int z; - static const unsigned char t[256] = { - /* non-linear sequence: constant term of inverse in GF(8), - mod x^8+x^4+x^3+x+1 */ - 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, - 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, - 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, - 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, - 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, - 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, - 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, - 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, - 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, - 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, - 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, - }; - - /* 0x04b3e375 and 0x05a8ef93 are chosen to contain every possible - 5-bit sequence */ - z = ((0x04b3e375 * x) ^ y) * 0x05a8ef93; - z = t[z & 0xff] ^ t[(z>>8) & 0xff] ^ t[(z>>16) & 0xff] ^ t[(z>>24) & 0xff]; - return z; -} - -/* ---------------------------------------------------------------------- */ -/* auxiliary bitmap manipulations */ - -/* set the excess padding to 0 */ -static void bm_clearexcess(potrace_bitmap_t *bm) { - if (bm->w % BM_WORDBITS != 0) { - potrace_word mask = BM_ALLBITS << (BM_WORDBITS - (bm->w % BM_WORDBITS)); - for (int y=0; y<bm->h; y++) { - *bm_index(bm, bm->w, y) &= mask; - } - } -} - -struct bbox_s { - int x0, x1, y0, y1; /* bounding box */ -}; -typedef struct bbox_s bbox_t; - -/* clear the bm, assuming the bounding box is set correctly (faster - than clearing the whole bitmap) */ -static void clear_bm_with_bbox(potrace_bitmap_t *bm, bbox_t *bbox) { - int imin = (bbox->x0 / BM_WORDBITS); - int imax = ((bbox->x1 + BM_WORDBITS-1) / BM_WORDBITS); - int i, y; - - for (y=bbox->y0; y<bbox->y1; y++) { - for (i=imin; i<imax; i++) { - bm_scanline(bm, y)[i] = 0; - } - } -} - -/* ---------------------------------------------------------------------- */ -/* auxiliary functions */ - -/* return the "majority" value of bitmap bm at intersection (x,y). We - assume that the bitmap is balanced at "radius" 1. */ -static int majority(potrace_bitmap_t *bm, int x, int y) { - int i, a, ct; - - for (i=2; i<5; i++) { /* check at "radius" i */ - ct = 0; - for (a=-i+1; a<=i-1; a++) { - ct += BM_GET(bm, x+a, y+i-1) ? 1 : -1; - ct += BM_GET(bm, x+i-1, y+a-1) ? 1 : -1; - ct += BM_GET(bm, x+a-1, y-i) ? 1 : -1; - ct += BM_GET(bm, x-i, y+a) ? 1 : -1; - } - if (ct>0) { - return 1; - } else if (ct<0) { - return 0; - } - } - return 0; -} - -/* ---------------------------------------------------------------------- */ -/* decompose image into paths */ - -/* efficiently invert bits [x,infty) and [xa,infty) in line y. Here xa - must be a multiple of BM_WORDBITS. */ -static void xor_to_ref(potrace_bitmap_t *bm, int x, int y, int xa) { - int xhi = x & -BM_WORDBITS; - int xlo = x & (BM_WORDBITS-1); /* = x % BM_WORDBITS */ - int i; - - if (xhi<xa) { - for (i = xhi; i < xa; i+=BM_WORDBITS) { - *bm_index(bm, i, y) ^= BM_ALLBITS; - } - } else { - for (i = xa; i < xhi; i+=BM_WORDBITS) { - *bm_index(bm, i, y) ^= BM_ALLBITS; - } - } - /* note: the following "if" is needed because x86 treats a<<b as - a<<(b&31). I spent hours looking for this bug. */ - if (xlo) { - *bm_index(bm, xhi, y) ^= (BM_ALLBITS << (BM_WORDBITS - xlo)); - } -} - -/* a path is represented as an array of points, which are thought to - lie on the corners of pixels (not on their centers). The path point - (x,y) is the lower left corner of the pixel (x,y). Paths are - represented by the len/pt components of a path_t object (which - also stores other information about the path) */ - -/* xor the given pixmap with the interior of the given path. Note: the - path must be within the dimensions of the pixmap. */ -static void xor_path(potrace_bitmap_t *bm, path_t *p) { - int xa, x, y, k, y1; - - if (p->priv->len <= 0) { /* a path of length 0 is silly, but legal */ - return; - } - - y1 = p->priv->pt[p->priv->len-1].y; - - xa = p->priv->pt[0].x & -BM_WORDBITS; - for (k=0; k<p->priv->len; k++) { - x = p->priv->pt[k].x; - y = p->priv->pt[k].y; - - if (y != y1) { - /* efficiently invert the rectangle [x,xa] x [y,y1] */ - xor_to_ref(bm, x, min(y,y1), xa); - y1 = y; - } - } -} - -/* Find the bounding box of a given path. Path is assumed to be of - non-zero length. */ -static void setbbox_path(bbox_t *bbox, path_t *p) { - int x, y; - int k; - - bbox->y0 = INT_MAX; - bbox->y1 = 0; - bbox->x0 = INT_MAX; - bbox->x1 = 0; - - for (k=0; k<p->priv->len; k++) { - x = p->priv->pt[k].x; - y = p->priv->pt[k].y; - - if (x < bbox->x0) { - bbox->x0 = x; - } - if (x > bbox->x1) { - bbox->x1 = x; - } - if (y < bbox->y0) { - bbox->y0 = y; - } - if (y > bbox->y1) { - bbox->y1 = y; - } - } -} - -/* compute a path in the given pixmap, separating black from white. - Start path at the point (x0,x1), which must be an upper left corner - of the path. Also compute the area enclosed by the path. Return a - new path_t object, or NULL on error (note that a legitimate path - cannot have length 0). Sign is required for correct interpretation - of turnpolicies. */ -static path_t *findpath(potrace_bitmap_t *bm, int x0, int y0, int sign, int turnpolicy) { - int x, y, dirx, diry, len, size, area; - int c, d, tmp; - point_t *pt, *pt1; - path_t *p = NULL; - - x = x0; - y = y0; - dirx = 0; - diry = -1; - - len = size = 0; - pt = NULL; - area = 0; - - while (1) { - /* add point to path */ - if (len>=size) { - size += 100; - size = (int)(1.3 * size); - pt1 = (point_t *)realloc(pt, size * sizeof(point_t)); - if (!pt1) { - goto error; - } - pt = pt1; - } - pt[len].x = x; - pt[len].y = y; - len++; - - /* move to next point */ - x += dirx; - y += diry; - area += x*diry; - - /* path complete? */ - if (x==x0 && y==y0) { - break; - } - - /* determine next direction */ - c = BM_GET(bm, x + (dirx+diry-1)/2, y + (diry-dirx-1)/2); - d = BM_GET(bm, x + (dirx-diry-1)/2, y + (diry+dirx-1)/2); - - if (c && !d) { /* ambiguous turn */ - if (turnpolicy == POTRACE_TURNPOLICY_RIGHT - || (turnpolicy == POTRACE_TURNPOLICY_BLACK && sign == '+') - || (turnpolicy == POTRACE_TURNPOLICY_WHITE && sign == '-') - || (turnpolicy == POTRACE_TURNPOLICY_RANDOM && detrand(x,y)) - || (turnpolicy == POTRACE_TURNPOLICY_MAJORITY && majority(bm, x, y)) - || (turnpolicy == POTRACE_TURNPOLICY_MINORITY && !majority(bm, x, y))) { - tmp = dirx; /* right turn */ - dirx = diry; - diry = -tmp; - } else { - tmp = dirx; /* left turn */ - dirx = -diry; - diry = tmp; - } - } else if (c) { /* right turn */ - tmp = dirx; - dirx = diry; - diry = -tmp; - } else if (!d) { /* left turn */ - tmp = dirx; - dirx = -diry; - diry = tmp; - } - } /* while this path */ - - /* allocate new path object */ - p = path_new(); - if (!p) { - goto error; - } - - p->priv->pt = pt; - p->priv->len = len; - p->area = area; - p->sign = sign; - - return p; - - error: - free(pt); - return NULL; -} - -/* Give a tree structure to the given path list, based on "insideness" - testing. I.e., path A is considered "below" path B if it is inside - path B. The input pathlist is assumed to be ordered so that "outer" - paths occur before "inner" paths. The tree structure is stored in - the "childlist" and "sibling" components of the path_t - structure. The linked list structure is also changed so that - negative path components are listed immediately after their - positive parent. Note: some backends may ignore the tree - structure, others may use it e.g. to group path components. We - assume that in the input, point 0 of each path is an "upper left" - corner of the path, as returned by bm_to_pathlist. This makes it - easy to find an "interior" point. The bm argument should be a - bitmap of the correct size (large enough to hold all the paths), - and will be used as scratch space. Return 0 on success or -1 on - error with errno set. */ - -static void pathlist_to_tree(path_t *plist, potrace_bitmap_t *bm) { - path_t *p, *p1; - path_t *heap, *heap1; - path_t *cur; - path_t *head; - path_t **plist_hook; /* for fast appending to linked list */ - path_t **hook_in, **hook_out; /* for fast appending to linked list */ - bbox_t bbox; - - bm_clear(bm, 0); - - /* save original "next" pointers */ - list_forall(p, plist) { - p->sibling = p->next; - p->childlist = NULL; - } - - heap = plist; - - /* the heap holds a list of lists of paths. Use "childlist" field - for outer list, "next" field for inner list. Each of the sublists - is to be turned into a tree. This code is messy, but it is - actually fast. Each path is rendered exactly once. We use the - heap to get a tail recursive algorithm: the heap holds a list of - pathlists which still need to be transformed. */ - - while (heap) { - /* unlink first sublist */ - cur = heap; - heap = heap->childlist; - cur->childlist = NULL; - - /* unlink first path */ - head = cur; - cur = cur->next; - head->next = NULL; - - /* render path */ - xor_path(bm, head); - setbbox_path(&bbox, head); - - /* now do insideness test for each element of cur; append it to - head->childlist if it's inside head, else append it to - head->next. */ - hook_in=&head->childlist; - hook_out=&head->next; - list_forall_unlink(p, cur) { - if (p->priv->pt[0].y <= bbox.y0) { - list_insert_beforehook(p, hook_out); - /* append the remainder of the list to hook_out */ - *hook_out = cur; - break; - } - if (BM_GET(bm, p->priv->pt[0].x, p->priv->pt[0].y-1)) { - list_insert_beforehook(p, hook_in); - } else { - list_insert_beforehook(p, hook_out); - } - } - - /* clear bm */ - clear_bm_with_bbox(bm, &bbox); - - /* now schedule head->childlist and head->next for further - processing */ - if (head->next) { - head->next->childlist = heap; - heap = head->next; - } - if (head->childlist) { - head->childlist->childlist = heap; - heap = head->childlist; - } - } - - /* copy sibling structure from "next" to "sibling" component */ - p = plist; - while (p) { - p1 = p->sibling; - p->sibling = p->next; - p = p1; - } - - /* reconstruct a new linked list ("next") structure from tree - ("childlist", "sibling") structure. This code is slightly messy, - because we use a heap to make it tail recursive: the heap - contains a list of childlists which still need to be - processed. */ - heap = plist; - if (heap) { - heap->next = NULL; /* heap is a linked list of childlists */ - } - plist = NULL; - plist_hook = &plist; - while (heap) { - heap1 = heap->next; - for (p=heap; p; p=p->sibling) { - /* p is a positive path */ - /* append to linked list */ - list_insert_beforehook(p, plist_hook); - - /* go through its children */ - for (p1=p->childlist; p1; p1=p1->sibling) { - /* append to linked list */ - list_insert_beforehook(p1, plist_hook); - /* append its childlist to heap, if non-empty */ - if (p1->childlist) { - list_append(path_t, heap1, p1->childlist); - } - } - } - heap = heap1; - } - - return; -} - -/* find the next set pixel in a row <= y. Pixels are searched first - left-to-right, then top-down. In other words, (x,y)<(x',y') if y>y' - or y=y' and x<x'. If found, return 0 and store pixel in - (*xp,*yp). Else return 1. Note that this function assumes that - excess bytes have been cleared with bm_clearexcess. */ -static int findnext(potrace_bitmap_t *bm, int *xp, int *yp) { - int x; - int y; - int x0; - - x0 = (*xp) & ~(BM_WORDBITS-1); - - for (y=*yp; y>=0; y--) { - for (x=x0; x<bm->w; x+=BM_WORDBITS) { - if (*bm_index(bm, x, y)) { - while (!BM_GET(bm, x, y)) { - x++; - } - /* found */ - *xp = x; - *yp = y; - return 0; - } - } - x0 = 0; - } - /* not found */ - return 1; -} - -/* Decompose the given bitmap into paths. Returns a linked list of - path_t objects with the fields len, pt, area, sign filled - in. Returns 0 on success with plistp set, or -1 on error with errno - set. */ - -int bm_to_pathlist(const potrace_bitmap_t *bm, path_t **plistp, const potrace_param_t *param, progress_t *progress) { - int x; - int y; - path_t *p; - path_t *plist = NULL; /* linked list of path objects */ - path_t **plist_hook = &plist; /* used to speed up appending to linked list */ - potrace_bitmap_t *bm1 = NULL; - int sign; - - bm1 = bm_dup(bm); - if (!bm1) { - goto error; - } - - /* be sure the byte padding on the right is set to 0, as the fast - pixel search below relies on it */ - bm_clearexcess(bm1); - - /* iterate through components */ - x = 0; - y = bm1->h - 1; - while (findnext(bm1, &x, &y) == 0) { - /* calculate the sign by looking at the original */ - sign = BM_GET(bm, x, y) ? '+' : '-'; - - /* calculate the path */ - p = findpath(bm1, x, y+1, sign, param->turnpolicy); - if (p==NULL) { - goto error; - } - - /* update buffered image */ - xor_path(bm1, p); - - /* if it's a turd, eliminate it, else append it to the list */ - if (p->area <= param->turdsize) { - path_free(p); - } else { - list_insert_beforehook(p, plist_hook); - } - - if (bm1->h > 0) { /* to be sure */ - progress_update(1-y/(double)bm1->h, progress); - } - } - - pathlist_to_tree(plist, bm1); - bm_free(bm1); - *plistp = plist; - - progress_update(1.0, progress); - - return 0; - - error: - bm_free(bm1); - list_forall_unlink(p, plist) { - path_free(p); - } - return -1; -} diff --git a/src/trace/potrace/decompose.h b/src/trace/potrace/decompose.h deleted file mode 100644 index 8ae89b8ad..000000000 --- a/src/trace/potrace/decompose.h +++ /dev/null @@ -1,16 +0,0 @@ -/* Copyright (C) 2001-2015 Peter Selinger. - This file is part of Potrace. It is free software and it is covered - by the GNU General Public License. See the file COPYING for details. */ - - -#ifndef DECOMPOSE_H -#define DECOMPOSE_H - -#include "potracelib.h" -#include "progress.h" -#include "curve.h" - -int bm_to_pathlist(const potrace_bitmap_t *bm, path_t **plistp, const potrace_param_t *param, progress_t *progress); - -#endif /* DECOMPOSE_H */ - diff --git a/src/trace/potrace/greymap.cpp b/src/trace/potrace/greymap.cpp deleted file mode 100644 index 4ef2ec8df..000000000 --- a/src/trace/potrace/greymap.cpp +++ /dev/null @@ -1,941 +0,0 @@ -/* Copyright (C) 2001-2015 Peter Selinger. - This file is part of Potrace. It is free software and it is covered - by the GNU General Public License. See the file COPYING for details. */ - - -/* Routines for manipulating greymaps, including reading pgm files. We - only deal with greymaps of depth 8 bits. */ - -#include <stdlib.h> -#include <string.h> -#include <math.h> -#include <errno.h> - -#include "greymap.h" -#include "bitops.h" - -#define INTBITS (8*sizeof(int)) - -#define mod(a,n) ((a)>=(n) ? (a)%(n) : (a)>=0 ? (a) : (n)-1-(-1-(a))%(n)) - -static int gm_readbody_pnm(FILE *f, greymap_t **gmp, int magic); -static int gm_readbody_bmp(FILE *f, greymap_t **gmp); - -/* ---------------------------------------------------------------------- */ -/* basic greymap routines */ - -/* return new un-initialized greymap. NULL with errno on error. - Assumes w, h >= 0. */ -greymap_t *gm_new(int w, int h) { - greymap_t *gm; - ssize_t size = (ssize_t)w * (ssize_t)h * (ssize_t)sizeof(signed short int); - - /* check for overflow error */ - if (size < 0 || size / w / h != sizeof(signed short int)) { - errno = ENOMEM; - return NULL; - } - - gm = (greymap_t *) malloc(sizeof(greymap_t)); - if (!gm) { - return NULL; - } - gm->w = w; - gm->h = h; - gm->map = (signed short int *) malloc(size); - if (!gm->map) { - free(gm); - return NULL; - } - return gm; -} - -/* free the given greymap */ -void gm_free(greymap_t *gm) { - if (gm) { - free(gm->map); - } - free(gm); -} - -/* duplicate the given greymap. Return NULL on error with errno set. */ -greymap_t *gm_dup(greymap_t *gm) { - greymap_t *gm1 = gm_new(gm->w, gm->h); - if (!gm1) { - return NULL; - } - memcpy(gm1->map, gm->map, gm->w*gm->h*sizeof(signed short int)); - return gm1; -} - -/* clear the given greymap to color b. */ -void gm_clear(greymap_t *gm, int b) { - if (b==0) { - memset(gm->map, 0, gm->w*gm->h*sizeof(signed short int)); - } else { - for (int i=0; i<gm->w*gm->h; i++) { - gm->map[i] = b; - } - } -} - -/* ---------------------------------------------------------------------- */ -/* routines for reading pnm streams */ - -/* read next character after whitespace and comments. Return EOF on - end of file or error. */ -static int fgetc_ws(FILE *f) { - int c; - - while (1) { - c = fgetc(f); - if (c=='#') { - while (1) { - c = fgetc(f); - if (c=='\n' || c==EOF) { - break; - } - } - } - /* space, tab, line feed, carriage return, form-feed */ - if (c!=' ' && c!='\t' && c!='\r' && c!='\n' && c!=12) { - return c; - } - } -} - -/* skip whitespace and comments, then read a non-negative decimal - number from a stream. Return -1 on EOF. Tolerate other errors (skip - bad characters). Do not the read any characters following the - number (put next character back into the stream) */ - -static int readnum(FILE *f) { - int c; - int acc; - - /* skip whitespace and comments */ - while (1) { - c = fgetc_ws(f); - if (c==EOF) { - return -1; - } - if (c>='0' && c<='9') { - break; - } - } - - /* first digit is already in c */ - acc = c-'0'; - while (1) { - c = fgetc(f); - if (c==EOF) { - break; - } - if (c<'0' || c>'9') { - ungetc(c, f); - break; - } - acc *= 10; - acc += c-'0'; - } - return acc; -} - -/* similar to readnum, but read only a single 0 or 1, and do not read - any characters after it. */ - -static int readbit(FILE *f) { - int c; - - /* skip whitespace and comments */ - while (1) { - c = fgetc_ws(f); - if (c==EOF) { - return -1; - } - if (c>='0' && c<='1') { - break; - } - } - - return c-'0'; -} - -/* ---------------------------------------------------------------------- */ - -/* read a PNM stream: P1-P6 format (see pnm(5)), or a BMP stream, and - convert the output to a greymap. Return greymap in *gmp. Return 0 - on success, -1 on error with errno set, -2 on bad file format (with - error message in gm_read_error), and 1 on premature end of file, -3 - on empty file (including files with only whitespace and comments), - -4 if wrong magic number. If the return value is >=0, *gmp is - valid. */ - -char const *gm_read_error = NULL; - -int gm_read(FILE *f, greymap_t **gmp) { - int magic[2]; - - /* read magic number. We ignore whitespace and comments before the - magic, for the benefit of concatenated files in P1-P3 format. - Multiple P1-P3 images in a single file are not formally allowed - by the PNM standard, but there is no harm in being lenient. */ - - magic[0] = fgetc_ws(f); - if (magic[0] == EOF) { - /* files which contain only comments and whitespace count as "empty" */ - return -3; - } - magic[1] = fgetc(f); - if (magic[0] == 'P' && magic[1] >= '1' && magic[1] <= '6') { - return gm_readbody_pnm(f, gmp, magic[1]); - } - if (magic[0] == 'B' && magic[1] == 'M') { - return gm_readbody_bmp(f, gmp); - } - return -4; -} - -/* ---------------------------------------------------------------------- */ -/* read PNM format */ - -/* read PNM stream after magic number. Return values as for gm_read */ -static int gm_readbody_pnm(FILE *f, greymap_t **gmp, int magic) { - greymap_t *gm; - int x, y, i, j, b, b1, sum; - int bpr; /* bytes per row (as opposed to 4*gm->c) */ - int w, h, max; - - gm = NULL; - - w = readnum(f); - if (w<0) { - goto format_error; - } - - h = readnum(f); - if (h<0) { - goto format_error; - } - - /* allocate greymap */ - gm = gm_new(w, h); - if (!gm) { - return -1; - } - - /* zero it out */ - gm_clear(gm, 0); - - switch (magic) { - default: - /* not reached */ - goto format_error; - - case '1': - /* read P1 format: PBM ascii */ - - for (y=h-1; y>=0; y--) { - for (x=0; x<w; x++) { - b = readbit(f); - if (b<0) { - goto eof; - } - GM_UPUT(gm, x, y, b ? 0 : 255); - } - } - break; - - case '2': - /* read P2 format: PGM ascii */ - - max = readnum(f); - if (max<1) { - goto format_error; - } - - for (y=h-1; y>=0; y--) { - for (x=0; x<w; x++) { - b = readnum(f); - if (b<0) { - goto eof; - } - GM_UPUT(gm, x, y, b*255/max); - } - } - break; - - case '3': - /* read P3 format: PPM ascii */ - - max = readnum(f); - if (max<1) { - goto format_error; - } - - for (y=h-1; y>=0; y--) { - for (x=0; x<w; x++) { - sum = 0; - for (i=0; i<3; i++) { - b = readnum(f); - if (b<0) { - goto eof; - } - sum += b; - } - GM_UPUT(gm, x, y, sum*(255/3)/max); - } - } - break; - - case '4': - /* read P4 format: PBM raw */ - - b = fgetc(f); /* read single white-space character after height */ - if (b==EOF) { - goto format_error; - } - - bpr = (w+7)/8; - - for (y=h-1; y>=0; y--) { - for (i=0; i<bpr; i++) { - b = fgetc(f); - if (b==EOF) { - goto eof; - } - for (j=0; j<8; j++) { - GM_PUT(gm, i*8+j, y, b & (0x80 >> j) ? 0 : 255); - } - } - } - break; - - case '5': - /* read P5 format: PGM raw */ - - max = readnum(f); - if (max<1) { - goto format_error; - } - - b = fgetc(f); /* read single white-space character after max */ - if (b==EOF) { - goto format_error; - } - - for (y=h-1; y>=0; y--) { - for (x=0; x<w; x++) { - b = fgetc(f); - if (b==EOF) - goto eof; - if (max>=256) { - b <<= 8; - b1 = fgetc(f); - if (b1==EOF) - goto eof; - b |= b1; - } - GM_UPUT(gm, x, y, b*255/max); - } - } - break; - - case '6': - /* read P6 format: PPM raw */ - - max = readnum(f); - if (max<1) { - goto format_error; - } - - b = fgetc(f); /* read single white-space character after max */ - if (b==EOF) { - goto format_error; - } - - for (y=h-1; y>=0; y--) { - for (x=0; x<w; x++) { - sum = 0; - for (i=0; i<3; i++) { - b = fgetc(f); - if (b==EOF) { - goto eof; - } - if (max>=256) { - b <<= 8; - b1 = fgetc(f); - if (b1==EOF) - goto eof; - b |= b1; - } - sum += b; - } - GM_UPUT(gm, x, y, sum*(255/3)/max); - } - } - break; - } - - *gmp = gm; - return 0; - - eof: - *gmp = gm; - return 1; - - format_error: - gm_free(gm); - if (magic == '1' || magic == '4') { - gm_read_error = "invalid pbm file"; - } else if (magic == '2' || magic == '5') { - gm_read_error = "invalid pgm file"; - } else { - gm_read_error = "invalid ppm file"; - } - return -2; -} - -/* ---------------------------------------------------------------------- */ -/* read BMP format */ - -struct bmp_info_s { - unsigned int FileSize; - unsigned int reserved; - unsigned int DataOffset; - unsigned int InfoSize; - unsigned int w; /* width */ - unsigned int h; /* height */ - unsigned int Planes; - unsigned int bits; /* bits per sample */ - unsigned int comp; /* compression mode */ - unsigned int ImageSize; - unsigned int XpixelsPerM; - unsigned int YpixelsPerM; - unsigned int ncolors; /* number of colors in palette */ - unsigned int ColorsImportant; - unsigned int RedMask; - unsigned int GreenMask; - unsigned int BlueMask; - unsigned int AlphaMask; - unsigned int ctbits; /* sample size for color table */ - int topdown; /* top-down mode? */ -}; -typedef struct bmp_info_s bmp_info_t; - -/* auxiliary */ - -static int bmp_count = 0; /* counter for byte padding */ -static int bmp_pos = 0; /* counter from start of BMP data */ - -/* read n-byte little-endian integer. Return 1 on EOF or error, else - 0. Assume n<=4. */ -static int bmp_readint(FILE *f, int n, unsigned int *p) { - int i; - unsigned int sum = 0; - int b; - - for (i=0; i<n; i++) { - b = fgetc(f); - if (b==EOF) { - return 1; - } - sum += b << (8*i); - } - bmp_count += n; - bmp_pos += n; - *p = sum; - return 0; -} - -/* reset padding boundary */ -static void bmp_pad_reset(void) { - bmp_count = 0; -} - -/* read padding bytes to 4-byte boundary. Return 1 on EOF or error, - else 0. */ -static int bmp_pad(FILE *f) { - int c, i, b; - - c = (-bmp_count) & 3; - for (i=0; i<c; i++) { - b = fgetc(f); - if (b==EOF) { - return 1; - } - } - bmp_pos += c; - bmp_count = 0; - return 0; -} - -/* forward to the new file position. Return 1 on EOF or error, else 0 */ -static int bmp_forward(FILE *f, int pos) { - int b; - - while (bmp_pos < pos) { - b = fgetc(f); - if (b==EOF) { - return 1; - } - bmp_pos++; - bmp_count++; - } - return 0; -} - -#define TRY(x) if (x) goto try_error -#define TRY_EOF(x) if (x) goto eof - -/* correct y-coordinate for top-down format */ -#define ycorr(y) (bmpinfo.topdown ? bmpinfo.h-1-y : y) - -/* read BMP stream after magic number. Return values as for gm_read. - We choose to be as permissive as possible, since there are many - programs out there which produce BMP. For instance, ppmtobmp can - produce codings with anywhere from 1-8 or 24 bits per sample, - although most specifications only allow 1,4,8,24,32. We can also - read both the old and new OS/2 BMP formats in addition to the - Windows BMP format. */ -static int gm_readbody_bmp(FILE *f, greymap_t **gmp) { - bmp_info_t bmpinfo; - int *coltable; - unsigned int b, c; - unsigned int i, j; - greymap_t *gm; - unsigned int x, y; - int col[2]; - unsigned int bitbuf; - unsigned int n; - unsigned int redshift, greenshift, blueshift; - - gm_read_error = NULL; - gm = NULL; - coltable = NULL; - - bmp_pos = 2; /* set file position */ - - /* file header (minus magic number) */ - TRY(bmp_readint(f, 4, &bmpinfo.FileSize)); - TRY(bmp_readint(f, 4, &bmpinfo.reserved)); - TRY(bmp_readint(f, 4, &bmpinfo.DataOffset)); - - /* info header */ - TRY(bmp_readint(f, 4, &bmpinfo.InfoSize)); - if (bmpinfo.InfoSize == 40 || bmpinfo.InfoSize == 64 - || bmpinfo.InfoSize == 108 || bmpinfo.InfoSize == 124) { - /* Windows or new OS/2 format */ - bmpinfo.ctbits = 32; /* sample size in color table */ - TRY(bmp_readint(f, 4, &bmpinfo.w)); - TRY(bmp_readint(f, 4, &bmpinfo.h)); - TRY(bmp_readint(f, 2, &bmpinfo.Planes)); - TRY(bmp_readint(f, 2, &bmpinfo.bits)); - TRY(bmp_readint(f, 4, &bmpinfo.comp)); - TRY(bmp_readint(f, 4, &bmpinfo.ImageSize)); - TRY(bmp_readint(f, 4, &bmpinfo.XpixelsPerM)); - TRY(bmp_readint(f, 4, &bmpinfo.YpixelsPerM)); - TRY(bmp_readint(f, 4, &bmpinfo.ncolors)); - TRY(bmp_readint(f, 4, &bmpinfo.ColorsImportant)); - if (bmpinfo.InfoSize >= 108) { /* V4 and V5 bitmaps */ - TRY(bmp_readint(f, 4, &bmpinfo.RedMask)); - TRY(bmp_readint(f, 4, &bmpinfo.GreenMask)); - TRY(bmp_readint(f, 4, &bmpinfo.BlueMask)); - TRY(bmp_readint(f, 4, &bmpinfo.AlphaMask)); - } - if (bmpinfo.w > 0x7fffffff) { - goto format_error; - } - if (bmpinfo.h > 0x7fffffff) { - bmpinfo.h = (-bmpinfo.h) & 0xffffffff; - bmpinfo.topdown = 1; - } else { - bmpinfo.topdown = 0; - } - if (bmpinfo.h > 0x7fffffff) { - goto format_error; - } - } else if (bmpinfo.InfoSize == 12) { - /* old OS/2 format */ - bmpinfo.ctbits = 24; /* sample size in color table */ - TRY(bmp_readint(f, 2, &bmpinfo.w)); - TRY(bmp_readint(f, 2, &bmpinfo.h)); - TRY(bmp_readint(f, 2, &bmpinfo.Planes)); - TRY(bmp_readint(f, 2, &bmpinfo.bits)); - bmpinfo.comp = 0; - bmpinfo.ncolors = 0; - bmpinfo.topdown = 0; - } else { - goto format_error; - } - - if (bmpinfo.comp == 3 && bmpinfo.InfoSize < 108) { - /* bitfield feature is only understood with V4 and V5 format */ - goto format_error; - } - - /* forward to color table (e.g., if bmpinfo.InfoSize == 64) */ - TRY(bmp_forward(f, 14+bmpinfo.InfoSize)); - - if (bmpinfo.Planes != 1) { - gm_read_error = "cannot handle bmp planes"; - goto format_error; /* can't handle planes */ - } - - if (bmpinfo.ncolors == 0) { - bmpinfo.ncolors = 1 << bmpinfo.bits; - } - - /* color table, present only if bmpinfo.bits <= 8. */ - if (bmpinfo.bits <= 8) { - coltable = (int *) calloc(bmpinfo.ncolors, sizeof(int)); - if (!coltable) { - goto std_error; - } - /* NOTE: since we are reading a greymap, we can immediately convert - the color table entries to grey values. */ - for (i=0; i<bmpinfo.ncolors; i++) { - TRY(bmp_readint(f, bmpinfo.ctbits/8, &c)); - c = ((c>>16) & 0xff) + ((c>>8) & 0xff) + (c & 0xff); - coltable[i] = c/3; - } - } - - /* forward to data */ - if (bmpinfo.InfoSize != 12) { /* not old OS/2 format */ - TRY(bmp_forward(f, bmpinfo.DataOffset)); - } - - /* allocate greymap */ - gm = gm_new(bmpinfo.w, bmpinfo.h); - if (!gm) { - goto std_error; - } - - /* zero it out */ - gm_clear(gm, 0); - - switch (bmpinfo.bits + 0x100*bmpinfo.comp) { - - default: - goto format_error; - break; - - case 0x001: /* monochrome palette */ - - /* raster data */ - for (y=0; y<bmpinfo.h; y++) { - bmp_pad_reset(); - for (i=0; 8*i<bmpinfo.w; i++) { - TRY_EOF(bmp_readint(f, 1, &b)); - for (j=0; j<8; j++) { - GM_PUT(gm, i*8+j, ycorr(y), b & (0x80 >> j) ? coltable[1] : coltable[0]); - } - } - TRY(bmp_pad(f)); - } - break; - - case 0x002: /* 2-bit to 8-bit palettes */ - case 0x003: - case 0x004: - case 0x005: - case 0x006: - case 0x007: - case 0x008: - for (y=0; y<bmpinfo.h; y++) { - bmp_pad_reset(); - bitbuf = 0; /* bit buffer: bits in buffer are high-aligned */ - n = 0; /* number of bits currently in bitbuffer */ - for (x=0; x<bmpinfo.w; x++) { - if (n < bmpinfo.bits) { - TRY_EOF(bmp_readint(f, 1, &b)); - bitbuf |= b << (INTBITS - 8 - n); - n += 8; - } - b = bitbuf >> (INTBITS - bmpinfo.bits); - bitbuf <<= bmpinfo.bits; - n -= bmpinfo.bits; - GM_UPUT(gm, x, ycorr(y), coltable[b]); - } - TRY(bmp_pad(f)); - } - break; - - case 0x010: /* 16-bit encoding */ - /* can't do this format because it is not well-documented and I - don't have any samples */ - gm_read_error = "cannot handle bmp 16-bit coding"; - goto format_error; - break; - - case 0x018: /* 24-bit encoding */ - case 0x020: /* 32-bit encoding */ - for (y=0; y<bmpinfo.h; y++) { - bmp_pad_reset(); - for (x=0; x<bmpinfo.w; x++) { - TRY_EOF(bmp_readint(f, bmpinfo.bits/8, &c)); - c = ((c>>16) & 0xff) + ((c>>8) & 0xff) + (c & 0xff); - GM_UPUT(gm, x, ycorr(y), c/3); - } - TRY(bmp_pad(f)); - } - break; - - case 0x320: /* 32-bit encoding with bitfields */ - redshift = lobit(bmpinfo.RedMask); - greenshift = lobit(bmpinfo.GreenMask); - blueshift = lobit(bmpinfo.BlueMask); - - for (y=0; y<bmpinfo.h; y++) { - bmp_pad_reset(); - for (x=0; x<bmpinfo.w; x++) { - TRY_EOF(bmp_readint(f, bmpinfo.bits/8, &c)); - c = ((c & bmpinfo.RedMask) >> redshift) + ((c & bmpinfo.GreenMask) >> greenshift) + ((c & bmpinfo.BlueMask) >> blueshift); - GM_UPUT(gm, x, ycorr(y), c/3); - } - TRY(bmp_pad(f)); - } - break; - - case 0x204: /* 4-bit runlength compressed encoding (RLE4) */ - x = 0; - y = 0; - while (1) { - TRY_EOF(bmp_readint(f, 1, &b)); /* opcode */ - TRY_EOF(bmp_readint(f, 1, &c)); /* argument */ - if (b>0) { - /* repeat count */ - col[0] = coltable[(c>>4) & 0xf]; - col[1] = coltable[c & 0xf]; - for (i=0; i<b && x<bmpinfo.w; i++) { - if (x>=bmpinfo.w) { - x=0; - y++; - } - if (y>=bmpinfo.h) { - break; - } - GM_UPUT(gm, x, ycorr(y), col[i&1]); - x++; - } - } else if (c == 0) { - /* end of line */ - y++; - x = 0; - } else if (c == 1) { - /* end of greymap */ - break; - } else if (c == 2) { - /* "delta": skip pixels in x and y directions */ - TRY_EOF(bmp_readint(f, 1, &b)); /* x offset */ - TRY_EOF(bmp_readint(f, 1, &c)); /* y offset */ - x += b; - y += c; - } else { - /* verbatim segment */ - for (i=0; i<c; i++) { - if ((i&1)==0) { - TRY_EOF(bmp_readint(f, 1, &b)); - } - if (x>=bmpinfo.w) { - x=0; - y++; - } - if (y>=bmpinfo.h) { - break; - } - GM_PUT(gm, x, ycorr(y), coltable[(b>>(4-4*(i&1))) & 0xf]); - x++; - } - if ((c+1) & 2) { - /* pad to 16-bit boundary */ - TRY_EOF(bmp_readint(f, 1, &b)); - } - } - } - break; - - case 0x108: /* 8-bit runlength compressed encoding (RLE8) */ - x = 0; - y = 0; - while (1) { - TRY_EOF(bmp_readint(f, 1, &b)); /* opcode */ - TRY_EOF(bmp_readint(f, 1, &c)); /* argument */ - if (b>0) { - /* repeat count */ - for (i=0; i<b; i++) { - if (x>=bmpinfo.w) { - x=0; - y++; - } - if (y>=bmpinfo.h) { - break; - } - GM_UPUT(gm, x, ycorr(y), coltable[c]); - x++; - } - } else if (c == 0) { - /* end of line */ - y++; - x = 0; - } else if (c == 1) { - /* end of greymap */ - break; - } else if (c == 2) { - /* "delta": skip pixels in x and y directions */ - TRY_EOF(bmp_readint(f, 1, &b)); /* x offset */ - TRY_EOF(bmp_readint(f, 1, &c)); /* y offset */ - x += b; - y += c; - } else { - /* verbatim segment */ - for (i=0; i<c; i++) { - TRY_EOF(bmp_readint(f, 1, &b)); - if (x>=bmpinfo.w) { - x=0; - y++; - } - if (y>=bmpinfo.h) { - break; - } - GM_PUT(gm, x, ycorr(y), coltable[b]); - x++; - } - if (c & 1) { - /* pad input to 16-bit boundary */ - TRY_EOF(bmp_readint(f, 1, &b)); - } - } - } - break; - - } /* switch */ - - /* skip any potential junk after the data section, but don't - complain in case EOF is encountered */ - bmp_forward(f, bmpinfo.FileSize); - - free(coltable); - *gmp = gm; - return 0; - - eof: - free(coltable); - *gmp = gm; - return 1; - - format_error: - try_error: - free(coltable); - free(gm); - if (!gm_read_error) { - gm_read_error = "invalid bmp file"; - } - return -2; - - std_error: - free(coltable); - free(gm); - return -1; -} - -/* ---------------------------------------------------------------------- */ - -/* write a pgm stream, either P2 or (if raw != 0) P5 format. Include - one-line comment if non-NULL. Mode determines how out-of-range - color values are converted. Gamma is the desired gamma correction, - if any (set to 2.2 if the image is to look optimal on a CRT monitor, - 2.8 for LCD). Set to 1.0 for no gamma correction */ - -int gm_writepgm(FILE *f, greymap_t *gm, char *comment, int raw, int mode, double gamma) { - int x, y, v; - int gammatable[256]; - - /* prepare gamma correction lookup table */ - if (gamma != 1.0) { - gammatable[0] = 0; - for (v=1; v<256; v++) { - gammatable[v] = (int)(255 * exp(log(v/255.0)/gamma) + 0.5); - } - } else { - for (v=0; v<256; v++) { - gammatable[v] = v; - } - } - - fprintf(f, raw ? "P5\n" : "P2\n"); - if (comment && *comment) { - fprintf(f, "# %s\n", comment); - } - fprintf(f, "%d %d 255\n", gm->w, gm->h); - for (y=gm->h-1; y>=0; y--) { - for (x=0; x<gm->w; x++) { - v = GM_UGET(gm, x, y); - if (mode == GM_MODE_NONZERO) { - if (v > 255) { - v = 510 - v; - } - if (v < 0) { - v = 0; - } - } else if (mode == GM_MODE_ODD) { - v = mod(v, 510); - if (v > 255) { - v = 510 - v; - } - } else if (mode == GM_MODE_POSITIVE) { - if (v < 0) { - v = 0; - } else if (v > 255) { - v = 255; - } - } else if (mode == GM_MODE_NEGATIVE) { - v = 510 - v; - if (v < 0) { - v = 0; - } else if (v > 255) { - v = 255; - } - } - v = gammatable[v]; - - if (raw) { - fputc(v, f); - } else { - fprintf(f, x == gm->w-1 ? "%d\n" : "%d ", v); - } - } - } - return 0; -} - -/* ---------------------------------------------------------------------- */ -/* output - for primitive debugging purposes only! */ - -/* print greymap to screen */ -int gm_print(FILE *f, greymap_t *gm) { - int x, y; - int xx, yy; - int d, t; - int sw, sh; - - sw = gm->w < 79 ? gm->w : 79; - sh = gm->w < 79 ? gm->h : gm->h*sw*44/(79*gm->w); - - for (yy=sh-1; yy>=0; yy--) { - for (xx=0; xx<sw; xx++) { - d=0; - t=0; - for (x=xx*gm->w/sw; x<(xx+1)*gm->w/sw; x++) { - for (y=yy*gm->h/sh; y<(yy+1)*gm->h/sh; y++) { - d += GM_GET(gm, x, y); - t += 256; - } - } - fputc("*#=- "[5*d/t], f); /* what a cute trick :) */ - } - fputc('\n', f); - } - return 0; -} diff --git a/src/trace/potrace/greymap.h b/src/trace/potrace/greymap.h deleted file mode 100644 index 8c9db9bbf..000000000 --- a/src/trace/potrace/greymap.h +++ /dev/null @@ -1,58 +0,0 @@ -/* Copyright (C) 2001-2015 Peter Selinger. - This file is part of Potrace. It is free software and it is covered - by the GNU General Public License. See the file COPYING for details. */ - - -#ifndef GREYMAP_H -#define GREYMAP_H - -#include <stdio.h> -#include <stdlib.h> - -/* internal format for greymaps. Note: in this format, rows are - ordered from bottom to top. The pixels in each row are given from - left to right. */ - -struct greymap_s { - int w; /* width, in pixels */ - int h; /* height, in pixels */ - signed short int *map; /* raw data, w*h values */ -}; -typedef struct greymap_s greymap_t; - -/* macros for accessing pixel at index (x,y). Note that the origin is - in the *lower* left corner. U* macros omit the bounds check. */ - -#define gm_index(gm, x, y) (&(gm)->map[(x)+(y)*(ssize_t)(gm)->w]) -#define gm_safe(gm, x, y) ((int)(x)>=0 && (int)(x)<(gm)->w && (int)(y)>=0 && (int)(y)<(gm)->h) -#define gm_bound(x, m) ((x)<0 ? 0 : (x)>=(m) ? (m)-1 : (x)) -#define GM_UGET(gm, x, y) (*gm_index(gm, x, y)) -#define GM_UINC(gm, x, y, b) (*gm_index(gm, x, y) += (short int)(b)) -#define GM_UINV(gm, x, y) (*gm_index(gm, x, y) = 255 - *gm_index(gm, x, y)) -#define GM_UPUT(gm, x, y, b) (*gm_index(gm, x, y) = (short int)(b)) -#define GM_GET(gm, x, y) (gm_safe(gm, x, y) ? GM_UGET(gm, x, y) : 0) -#define GM_INC(gm, x, y, b) (gm_safe(gm, x, y) ? GM_UINC(gm, x, y, b) : 0) -#define GM_INV(gm, x, y) (gm_safe(gm, x, y) ? GM_UINV(gm, x, y) : 0) -#define GM_PUT(gm, x, y, b) (gm_safe(gm, x, y) ? GM_UPUT(gm, x, y, b) : 0) -#define GM_BGET(gm, x, y) GM_UGET(gm, gm_bound(x, gm->w), gm_bound(y, gm->h)) - -/* modes for cutting off out-of-range values. The following names - refer to winding numbers. I.e., make a pixel black if winding - number is nonzero, odd, or positive, respectively. We assume that 0 - winding number corresponds to white (255). */ -#define GM_MODE_NONZERO 1 -#define GM_MODE_ODD 2 -#define GM_MODE_POSITIVE 3 -#define GM_MODE_NEGATIVE 4 - -extern char const *gm_read_error; - -greymap_t *gm_new(int w, int h); -greymap_t *gm_dup(greymap_t *gm); -void gm_free(greymap_t *gm); -void gm_clear(greymap_t *gm, int b); -int gm_read(FILE *f, greymap_t **gmp); -int gm_writepgm(FILE *f, greymap_t *gm, char *comment, int raw, int mode, double gamma); -int gm_print(FILE *f, greymap_t *gm); - -#endif /* GREYMAP_H */ diff --git a/src/trace/potrace/inkscape-potrace.cpp b/src/trace/potrace/inkscape-potrace.cpp index 8f3bb7bdf..a0b0df1f6 100644 --- a/src/trace/potrace/inkscape-potrace.cpp +++ b/src/trace/potrace/inkscape-potrace.cpp @@ -29,7 +29,6 @@ #include "message-stack.h" #include <sp-path.h> #include <svg/path-string.h> -#include "curve.h" #include "bitmap.h" using Glib::ustring; @@ -128,7 +127,7 @@ static bool hasPoint(std::vector<Point> &points, double x, double y) /** - * Recursively descend the path_t node tree, writing paths in SVG + * Recursively descend the potrace_path_t node tree, writing paths in SVG * format into the output stream. The Point vector is used to prevent * redundant paths. Returns number of paths processed. */ @@ -144,7 +143,7 @@ static long writePaths(PotraceTracingEngine *engine, potrace_path_t *plist, //g_message("node->fm:%d\n", node->fm); if (!curve->n) continue; - dpoint_t *pt = curve->c[curve->n - 1]; + const potrace_dpoint_t *pt = curve->c[curve->n - 1]; double x0 = 0.0; double y0 = 0.0; double x1 = 0.0; @@ -192,7 +191,7 @@ static long writePaths(PotraceTracingEngine *engine, potrace_path_t *plist, } data.closePath(); - for (path_t *child=node->childlist; child ; child=child->sibling) + for (potrace_path_t *child=node->childlist; child ; child=child->sibling) { nodeCount += writePaths(engine, child, data, points); } diff --git a/src/trace/potrace/inkscape-potrace.h b/src/trace/potrace/inkscape-potrace.h index 88da56abb..e8e654973 100644 --- a/src/trace/potrace/inkscape-potrace.h +++ b/src/trace/potrace/inkscape-potrace.h @@ -18,7 +18,7 @@ #define __INKSCAPE_POTRACE_H__ #include <trace/trace.h> -#include "potracelib.h" +#include <potracelib.h> struct GrayMap_def; typedef GrayMap_def GrayMap; diff --git a/src/trace/potrace/lists.h b/src/trace/potrace/lists.h deleted file mode 100644 index 394262c23..000000000 --- a/src/trace/potrace/lists.h +++ /dev/null @@ -1,285 +0,0 @@ -/* Copyright (C) 2001-2015 Peter Selinger. - This file is part of Potrace. It is free software and it is covered - by the GNU General Public License. See the file COPYING for details. */ - - -#ifndef _PS_LISTS_H -#define _PS_LISTS_H - -/* here we define some general list macros. Because they are macros, - they should work on any datatype with a "->next" component. Some of - them use a "hook". If elt and list are of type t* then hook is of - type t**. A hook stands for an insertion point in the list, i.e., - either before the first element, or between two elements, or after - the last element. If an operation "sets the hook" for an element, - then the hook is set to just before the element. One can insert - something at a hook. One can also unlink at a hook: this means, - unlink the element just after the hook. By "to unlink", we mean the - element is removed from the list, but not deleted. Thus, it and its - components still need to be freed. */ - -/* Note: these macros are somewhat experimental. Only the ones that - are actually *used* have been tested. So be careful to test any - that you use. Looking at the output of the preprocessor, "gcc -E" - (possibly piped though "indent"), might help too. Also: these - macros define some internal (local) variables that start with - "_". */ - -/* we enclose macro definitions whose body consists of more than one - statement in MACRO_BEGIN and MACRO_END, rather than '{' and '}'. The - reason is that we want to be able to use the macro in a context - such as "if (...) macro(...); else ...". If we didn't use this obscure - trick, we'd have to omit the ";" in such cases. */ - -#define MACRO_BEGIN do { -#define MACRO_END } while (0) - -/* ---------------------------------------------------------------------- */ -/* macros for singly-linked lists */ - -/* traverse list. At the end, elt is set to NULL. */ -#define list_forall(elt, list) for (elt=list; elt!=NULL; elt=elt->next) - -/* set elt to the first element of list satisfying boolean condition - c, or NULL if not found */ -#define list_find(elt, list, c) \ - MACRO_BEGIN list_forall(elt, list) if (c) break; MACRO_END - -/* like forall, except also set hook for elt. */ -#define list_forall2(elt, list, hook) \ - for (elt=list, hook=&list; elt!=NULL; hook=&elt->next, elt=elt->next) - -/* same as list_find, except also set hook for elt. */ -#define list_find2(elt, list, c, hook) \ - MACRO_BEGIN list_forall2(elt, list, hook) if (c) break; MACRO_END - -/* same, except only use hook. */ -#define _list_forall_hook(list, hook) \ - for (hook=&list; *hook!=NULL; hook=&(*hook)->next) - -/* same, except only use hook. Note: c may only refer to *hook, not elt. */ -#define _list_find_hook(list, c, hook) \ - MACRO_BEGIN _list_forall_hook(list, hook) if (c) break; MACRO_END - -/* insert element after hook */ -#define list_insert_athook(elt, hook) \ - MACRO_BEGIN elt->next = *hook; *hook = elt; MACRO_END - -/* insert element before hook */ -#define list_insert_beforehook(elt, hook) \ - MACRO_BEGIN elt->next = *hook; *hook = elt; hook=&elt->next; MACRO_END - -/* unlink element after hook, let elt be unlinked element, or NULL. - hook remains. */ -#define list_unlink_athook(list, elt, hook) \ - MACRO_BEGIN \ - elt = hook ? *hook : NULL; if (elt) { *hook = elt->next; elt->next = NULL; }\ - MACRO_END - -/* unlink the specific element, if it is in the list. Otherwise, set - elt to NULL */ -#define list_unlink(listtype, list, elt) \ - MACRO_BEGIN \ - listtype **_hook; \ - _list_find_hook(list, *_hook==elt, _hook); \ - list_unlink_athook(list, elt, _hook); \ - MACRO_END - -/* prepend elt to list */ -#define list_prepend(list, elt) \ - MACRO_BEGIN elt->next = list; list = elt; MACRO_END - -/* append elt to list. */ -#define list_append(listtype, list, elt) \ - MACRO_BEGIN \ - listtype **_hook; \ - _list_forall_hook(list, _hook) {} \ - list_insert_athook(elt, _hook); \ - MACRO_END - -/* unlink the first element that satisfies the condition. */ -#define list_unlink_cond(listtype, list, elt, c) \ - MACRO_BEGIN \ - listtype **_hook; \ - list_find2(elt, list, c, _hook); \ - list_unlink_athook(list, elt, _hook); \ - MACRO_END - -/* let elt be the nth element of the list, starting to count from 0. - Return NULL if out of bounds. */ -#define list_nth(elt, list, n) \ - MACRO_BEGIN \ - int _x; /* only evaluate n once */ \ - for (_x=(n), elt=list; _x && elt; _x--, elt=elt->next) {} \ - MACRO_END - -/* let elt be the nth element of the list, starting to count from 0. - Return NULL if out of bounds. */ -#define list_nth_hook(elt, list, n, hook) \ - MACRO_BEGIN \ - int _x; /* only evaluate n once */ \ - for (_x=(n), elt=list, hook=&list; _x && elt; _x--, hook=&elt->next, elt=elt->next) {} \ - MACRO_END - -/* set n to the length of the list */ -#define list_length(listtype, list, n) \ - MACRO_BEGIN \ - listtype *_elt; \ - n=0; \ - list_forall(_elt, list) \ - n++; \ - MACRO_END - -/* set n to the index of the first element satisfying cond, or -1 if - none found. Also set elt to the element, or NULL if none found. */ -#define list_index(list, n, elt, c) \ - MACRO_BEGIN \ - n=0; \ - list_forall(elt, list) { \ - if (c) break; \ - n++; \ - } \ - if (!elt) \ - n=-1; \ - MACRO_END - -/* set n to the number of elements in the list that satisfy condition c */ -#define list_count(list, n, elt, c) \ - MACRO_BEGIN \ - n=0; \ - list_forall(elt, list) { \ - if (c) n++; \ - } \ - MACRO_END - -/* let elt be each element of the list, unlinked. At the end, set list=NULL. */ -#define list_forall_unlink(elt, list) \ - for (elt=list; elt ? (list=elt->next, elt->next=NULL), 1 : 0; elt=list) - -/* reverse a list (efficient) */ -#define list_reverse(listtype, list) \ - MACRO_BEGIN \ - listtype *_list1=NULL, *elt; \ - list_forall_unlink(elt, list) \ - list_prepend(_list1, elt); \ - list = _list1; \ - MACRO_END - -/* insert the element ELT just before the first element TMP of the - list for which COND holds. Here COND must be a condition of ELT and - TMP. Typical usage is to insert an element into an ordered list: - for instance, list_insert_ordered(listtype, list, elt, tmp, - elt->size <= tmp->size). Note: if we give a "less than or equal" - condition, the new element will be inserted just before a sequence - of equal elements. If we give a "less than" condition, the new - element will be inserted just after a list of equal elements. - Note: it is much more efficient to construct a list with - list_prepend and then order it with list_merge_sort, than to - construct it with list_insert_ordered. */ -#define list_insert_ordered(listtype, list, elt, tmp, cond) \ - MACRO_BEGIN \ - listtype **_hook; \ - _list_find_hook(list, (tmp=*_hook, (cond)), _hook); \ - list_insert_athook(elt, _hook); \ - MACRO_END - -/* sort the given list, according to the comparison condition. - Typical usage is list_sort(listtype, list, a, b, a->size < - b->size). Note: if we give "less than or equal" condition, each - segment of equal elements will be reversed in order. If we give a - "less than" condition, each segment of equal elements will retain - the original order. The latter is slower but sometimes - prettier. Average running time: n*n/2. */ -#define list_sort(listtype, list, a, b, cond) \ - MACRO_BEGIN \ - listtype *_newlist=NULL; \ - list_forall_unlink(a, list) \ - list_insert_ordered(listtype, _newlist, a, b, cond); \ - list = _newlist; \ - MACRO_END - -/* a much faster sort algorithm (merge sort, n log n worst case). It - is required that the list type has an additional, unused next1 - component. Note there is no curious reversal of order of equal - elements as for list_sort. */ - -#define list_mergesort(listtype, list, a, b, cond) \ - MACRO_BEGIN \ - listtype *_elt, **_hook1; \ - \ - for (_elt=list; _elt; _elt=_elt->next1) { \ - _elt->next1 = _elt->next; \ - _elt->next = NULL; \ - } \ - do { \ - _hook1 = &(list); \ - while ((a = *_hook1) != NULL && (b = a->next1) != NULL ) { \ - _elt = b->next1; \ - _list_merge_cond(listtype, a, b, cond, *_hook1); \ - _hook1 = &((*_hook1)->next1); \ - *_hook1 = _elt; \ - } \ - } while (_hook1 != &(list)); \ - MACRO_END - -/* merge two sorted lists. Store result at &result */ -#define _list_merge_cond(listtype, a, b, cond, result) \ - MACRO_BEGIN \ - listtype **_hook; \ - _hook = &(result); \ - while (1) { \ - if (a==NULL) { \ - *_hook = b; \ - break; \ - } else if (b==NULL) { \ - *_hook = a; \ - break; \ - } else if (cond) { \ - *_hook = a; \ - _hook = &(a->next); \ - a = a->next; \ - } else { \ - *_hook = b; \ - _hook = &(b->next); \ - b = b->next; \ - } \ - } \ - MACRO_END - -/* ---------------------------------------------------------------------- */ -/* macros for doubly-linked lists */ - -#define dlist_append(head, end, elt) \ - MACRO_BEGIN \ - elt->prev = end; \ - elt->next = NULL; \ - if (end) { \ - end->next = elt; \ - } else { \ - head = elt; \ - } \ - end = elt; \ - MACRO_END - -/* let elt be each element of the list, unlinked. At the end, set list=NULL. */ -#define dlist_forall_unlink(elt, head, end) \ - for (elt=head; elt ? (head=elt->next, elt->next=NULL, elt->prev=NULL), 1 : (end=NULL, 0); elt=head) - -/* unlink the first element of the list */ -#define dlist_unlink_first(head, end, elt) \ - MACRO_BEGIN \ - elt = head; \ - if (head) { \ - head = head->next; \ - if (head) { \ - head->prev = NULL; \ - } else { \ - end = NULL; \ - } \ - elt->prev = NULL; \ - elt->next = NULL; \ - } \ - MACRO_END - -#endif /* _PS_LISTS_H */ - diff --git a/src/trace/potrace/potracelib.cpp b/src/trace/potrace/potracelib.cpp deleted file mode 100644 index b5463d676..000000000 --- a/src/trace/potrace/potracelib.cpp +++ /dev/null @@ -1,128 +0,0 @@ -/* Copyright (C) 2001-2015 Peter Selinger. - This file is part of Potrace. It is free software and it is covered - by the GNU General Public License. See the file COPYING for details. */ - -#include <stdlib.h> -#include <string.h> -#include <glib.h> - -#include "potracelib.h" -#include "inkscape-version.h" -#include "curve.h" -#include "decompose.h" -#include "trace.h" -#include "progress.h" - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -/* default parameters */ -static const potrace_param_t param_default = { - 2, /* turdsize */ - POTRACE_TURNPOLICY_MINORITY, /* turnpolicy */ - 1.0, /* alphamax */ - 1, /* opticurve */ - 0.2, /* opttolerance */ - { - NULL, /* callback function */ - NULL, /* callback data */ - 0.0, 1.0, /* progress range */ - 0.0, /* granularity */ - }, -}; - -/* Return a fresh copy of the set of default parameters, or NULL on - failure with errno set. */ -potrace_param_t *potrace_param_default(void) { - potrace_param_t *p; - - p = (potrace_param_t *) malloc(sizeof(potrace_param_t)); - if (!p) { - return NULL; - } - memcpy(p, ¶m_default, sizeof(potrace_param_t)); - return p; -} - -/* On success, returns a Potrace state st with st->status == - POTRACE_STATUS_OK. On failure, returns NULL if no Potrace state - could be created (with errno set), or returns an incomplete Potrace - state (with st->status == POTRACE_STATUS_INCOMPLETE, and with errno - set). Complete or incomplete Potrace state can be freed with - potrace_state_free(). */ -potrace_state_t *potrace_trace(const potrace_param_t *param, const potrace_bitmap_t *bm) { - int r; - path_t *plist = NULL; - potrace_state_t *st; - progress_t prog; - progress_t subprog; - - /* prepare private progress bar state */ - prog.callback = param->progress.callback; - prog.data = param->progress.data; - prog.min = param->progress.min; - prog.max = param->progress.max; - prog.epsilon = param->progress.epsilon; - prog.d_prev = param->progress.min; - - /* allocate state object */ - st = (potrace_state_t *)malloc(sizeof(potrace_state_t)); - if (!st) { - return NULL; - } - - progress_subrange_start(0.0, 0.1, &prog, &subprog); - - /* process the image */ - r = bm_to_pathlist(bm, &plist, param, &subprog); - if (r) { - free(st); - return NULL; - } - - st->status = POTRACE_STATUS_OK; - st->plist = plist; - st->priv = NULL; /* private state currently unused */ - - progress_subrange_end(&prog, &subprog); - - progress_subrange_start(0.1, 1.0, &prog, &subprog); - - /* partial success. */ - r = process_path(plist, param, &subprog); - if (r) { - st->status = POTRACE_STATUS_INCOMPLETE; - } - - progress_subrange_end(&prog, &subprog); - - return st; -} - -/* free a Potrace state, without disturbing errno. */ -void potrace_state_free(potrace_state_t *st) { - pathlist_free(st->plist); - free(st); -} - -/* free a parameter list, without disturbing errno. */ -void potrace_param_free(potrace_param_t *p) { - free(p); -} - -char *potrace_version(void) { - static char *ver = g_strdup_printf("potracelib %s", Inkscape::version_string); - return ver; -} - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/trace/potrace/potracelib.h b/src/trace/potrace/potracelib.h deleted file mode 100644 index 0a6ddbf1f..000000000 --- a/src/trace/potrace/potracelib.h +++ /dev/null @@ -1,139 +0,0 @@ -/* Copyright (C) 2001-2015 Peter Selinger. - This file is part of Potrace. It is free software and it is covered - by the GNU General Public License. See the file COPYING for details. */ - -#ifndef POTRACELIB_H -#define POTRACELIB_H - -/* this file defines the API for the core Potrace library. For a more - detailed description of the API, see potracelib.pdf */ - -#ifdef __cplusplus -extern "C" { -#endif - -/* ---------------------------------------------------------------------- */ -/* tracing parameters */ - -/* turn policies */ -#define POTRACE_TURNPOLICY_BLACK 0 -#define POTRACE_TURNPOLICY_WHITE 1 -#define POTRACE_TURNPOLICY_LEFT 2 -#define POTRACE_TURNPOLICY_RIGHT 3 -#define POTRACE_TURNPOLICY_MINORITY 4 -#define POTRACE_TURNPOLICY_MAJORITY 5 -#define POTRACE_TURNPOLICY_RANDOM 6 - -/* structure to hold progress bar callback data */ -struct potrace_progress_s { - void (*callback)(double progress, void *privdata); /* callback fn */ - void *data; /* callback function's private data */ - double min, max; /* desired range of progress, e.g. 0.0 to 1.0 */ - double epsilon; /* granularity: can skip smaller increments */ -}; -typedef struct potrace_progress_s potrace_progress_t; - -/* structure to hold tracing parameters */ -struct potrace_param_s { - int turdsize; /* area of largest path to be ignored */ - int turnpolicy; /* resolves ambiguous turns in path decomposition */ - double alphamax; /* corner threshold */ - int opticurve; /* use curve optimization? */ - double opttolerance; /* curve optimization tolerance */ - potrace_progress_t progress; /* progress callback function */ -}; -typedef struct potrace_param_s potrace_param_t; - -/* ---------------------------------------------------------------------- */ -/* bitmaps */ - -/* native word size */ -typedef unsigned long potrace_word; - -/* Internal bitmap format. The n-th scanline starts at scanline(n) = - (map + n*dy). Raster data is stored as a sequence of potrace_words - (NOT bytes). The leftmost bit of scanline n is the most significant - bit of scanline(n)[0]. */ -struct potrace_bitmap_s { - int w, h; /* width and height, in pixels */ - int dy; /* words per scanline (not bytes) */ - potrace_word *map; /* raw data, dy*h words */ -}; -typedef struct potrace_bitmap_s potrace_bitmap_t; - -/* ---------------------------------------------------------------------- */ -/* curves */ - -/* point */ -struct potrace_dpoint_s { - double x, y; -}; -typedef struct potrace_dpoint_s potrace_dpoint_t; - -/* segment tags */ -#define POTRACE_CURVETO 1 -#define POTRACE_CORNER 2 - -/* closed curve segment */ -struct potrace_curve_s { - int n; /* number of segments */ - int *tag; /* tag[n]: POTRACE_CURVETO or POTRACE_CORNER */ - potrace_dpoint_t (*c)[3]; /* c[n][3]: control points. - c[n][0] is unused for tag[n]=POTRACE_CORNER */ -}; -typedef struct potrace_curve_s potrace_curve_t; - -/* Linked list of signed curve segments. Also carries a tree structure. */ -struct potrace_path_s { - int area; /* area of the bitmap path */ - int sign; /* '+' or '-', depending on orientation */ - potrace_curve_t curve; /* this path's vector data */ - - struct potrace_path_s *next; /* linked list structure */ - - struct potrace_path_s *childlist; /* tree structure */ - struct potrace_path_s *sibling; /* tree structure */ - - struct potrace_privpath_s *priv; /* private state */ -}; -typedef struct potrace_path_s potrace_path_t; - -/* ---------------------------------------------------------------------- */ -/* Potrace state */ - -#define POTRACE_STATUS_OK 0 -#define POTRACE_STATUS_INCOMPLETE 1 - -struct potrace_state_s { - int status; - potrace_path_t *plist; /* vector data */ - - struct potrace_privstate_s *priv; /* private state */ -}; -typedef struct potrace_state_s potrace_state_t; - -/* ---------------------------------------------------------------------- */ -/* API functions */ - -/* get default parameters */ -potrace_param_t *potrace_param_default(void); - -/* free parameter set */ -void potrace_param_free(potrace_param_t *p); - -/* trace a bitmap*/ -potrace_state_t *potrace_trace(const potrace_param_t *param, - const potrace_bitmap_t *bm); - -/* free a Potrace state */ -void potrace_state_free(potrace_state_t *st); - -/* return a static plain text version string identifying this version - of potracelib */ -char *potrace_version(void); - -#ifdef __cplusplus -} /* end of extern "C" */ -#endif - -#endif /* POTRACELIB_H */ diff --git a/src/trace/potrace/progress.h b/src/trace/potrace/progress.h deleted file mode 100644 index ecc2ba217..000000000 --- a/src/trace/potrace/progress.h +++ /dev/null @@ -1,77 +0,0 @@ -/* Copyright (C) 2001-2015 Peter Selinger. - This file is part of Potrace. It is free software and it is covered - by the GNU General Public License. See the file COPYING for details. */ - -/* operations on potrace_progress_t objects, which are defined in - potracelib.h. Note: the code attempts to minimize runtime overhead - when no progress monitoring was requested. It also tries to - minimize excessive progress calculations beneath the "epsilon" - threshold. */ - -#ifndef PROGRESS_H -#define PROGRESS_H - -/* structure to hold progress bar callback data */ -struct progress_s { - void (*callback)(double progress, void *privdata); /* callback fn */ - void *data; /* callback function's private data */ - double min, max; /* desired range of progress, e.g. 0.0 to 1.0 */ - double epsilon; /* granularity: can skip smaller increments */ - double b; /* upper limit of subrange in superrange units */ - double d_prev; /* previous value of d */ -}; -typedef struct progress_s progress_t; - -/* notify given progress object of current progress. Note that d is - given in the 0.0-1.0 range, which will be scaled and translated to - the progress object's range. */ -static inline void progress_update(double d, progress_t *prog) { - if (prog != NULL && prog->callback != NULL) { - double d_scaled = prog->min * (1-d) + prog->max * d; - if (d == 1.0 || d_scaled >= prog->d_prev + prog->epsilon) { - prog->callback(prog->min * (1-d) + prog->max * d, prog->data); - prog->d_prev = d_scaled; - } - } -} - -/* start a subrange of the given progress object. The range is - narrowed to [a..b], relative to 0.0-1.0 coordinates. If new range - is below granularity threshold, disable further subdivisions. */ -static inline void progress_subrange_start(double a, double b, const progress_t *prog, progress_t *sub) { - double min, max; - - if (prog == NULL || prog->callback == NULL) { - sub->callback = NULL; - return; - } - - min = prog->min * (1-a) + prog->max * a; - max = prog->min * (1-b) + prog->max * b; - - if (max - min < prog->epsilon) { - sub->callback = NULL; /* no further progress info in subrange */ - sub->b = b; - return; - } - sub->callback = prog->callback; - sub->data = prog->data; - sub->epsilon = prog->epsilon; - sub->min = min; - sub->max = max; - sub->d_prev = prog->d_prev; - return; -} - -static inline void progress_subrange_end(progress_t *prog, progress_t *sub) { - if (prog != NULL && prog->callback != NULL) { - if (sub->callback == NULL) { - progress_update(sub->b, prog); - } else { - prog->d_prev = sub->d_prev; - } - } -} - -#endif /* PROGRESS_H */ - diff --git a/src/trace/potrace/render.cpp b/src/trace/potrace/render.cpp deleted file mode 100644 index 4f44ae6a6..000000000 --- a/src/trace/potrace/render.cpp +++ /dev/null @@ -1,243 +0,0 @@ -/* Copyright (C) 2001-2015 Peter Selinger. - This file is part of Potrace. It is free software and it is covered - by the GNU General Public License. See the file COPYING for details. */ - - -#include <stdio.h> -#include <stdlib.h> -#include <math.h> -#include <string.h> - -#include "render.h" -#include "greymap.h" -#include "auxiliary.h" - -/* ---------------------------------------------------------------------- */ -/* routines for anti-aliased rendering of curves */ - -/* we use the following method. Given a point (x,y) (with real-valued - coordinates) in the plane, let (xi,yi) be the integer part of the - coordinates, i.e., xi=floor(x), yi=floor(y). Define a path from - (x,y) to infinity as follows: path(x,y) = - (x,y)--(xi+1,y)--(xi+1,yi)--(+infty,yi). Now as the point (x,y) - moves smoothly across the plane, the path path(x,y) sweeps - (non-smoothly) across a certain area. We proportionately blacken - the area as the path moves "downward", and we whiten the area as - the path moves "upward". This way, after the point has traversed a - closed curve, the interior of the curve has been darkened - (counterclockwise movement) or lightened (clockwise movement). (The - "grey shift" is actually proportional to the winding number). By - choosing the above path with mostly integer coordinates, we achieve - that only pixels close to (x,y) receive grey values and are subject - to round-off errors. The grey value of pixels far away from (x,y) - is always in "integer" (where 0=black, 1=white). As a special - trick, we keep an accumulator rm->a1, which holds a double value to - be added to the grey value to be added to the current pixel - (xi,yi). Only when changing "current" pixels, we convert this - double value to an integer. This way we avoid round-off errors at - the meeting points of line segments. Another speedup measure is - that we sometimes use the rm->incrow_buf array to postpone - incrementing or decrementing an entire row. If incrow_buf[y]=x+1!=0, - then all the pixels (x,y),(x+1,y),(x+2,y),... are scheduled to be - incremented/decremented (which one is the case will be clear from - context). This keeps the greymap operations reasonably local. */ - -/* allocate a new rendering state */ -render_t *render_new(greymap_t *gm) { - render_t *rm; - - rm = (render_t *) malloc(sizeof(render_t)); - if (!rm) { - return NULL; - } - memset(rm, 0, sizeof(render_t)); - rm->gm = gm; - rm->incrow_buf = (int *) calloc(gm->h, sizeof(int)); - if (!rm->incrow_buf) { - free(rm); - return NULL; - } - memset(rm->incrow_buf, 0, gm->h * sizeof(int)); - return rm; -} - -/* free a given rendering state. Note: this does not free the - underlying greymap. */ -void render_free(render_t *rm) { - free(rm->incrow_buf); - free(rm); -} - -/* close path */ -void render_close(render_t *rm) { - if (rm->x0 != rm->x1 || rm->y0 != rm->y1) { - render_lineto(rm, rm->x0, rm->y0); - } - GM_INC(rm->gm, rm->x0i, rm->y0i, (rm->a0+rm->a1)*255); - - /* assert (rm->x0i != rm->x1i || rm->y0i != rm->y1i); */ - - /* the persistent state is now undefined */ -} - -/* move point */ -void render_moveto(render_t *rm, double x, double y) { - /* close the previous path */ - render_close(rm); - - rm->x0 = rm->x1 = x; - rm->y0 = rm->y1 = y; - rm->x0i = (int)floor(rm->x0); - rm->x1i = (int)floor(rm->x1); - rm->y0i = (int)floor(rm->y0); - rm->y1i = (int)floor(rm->y1); - rm->a0 = rm->a1 = 0; -} - -/* add b to pixels (x,y) and all pixels to the right of it. However, - use rm->incrow_buf as a buffer to economize on multiple calls */ -static void incrow(render_t *rm, int x, int y, int b) { - int i, x0; - - if (y < 0 || y >= rm->gm->h) { - return; - } - - if (x < 0) { - x = 0; - } else if (x > rm->gm->w) { - x = rm->gm->w; - } - if (rm->incrow_buf[y] == 0) { - rm->incrow_buf[y] = x+1; /* store x+1 so that we can use 0 for "vacant" */ - return; - } - x0 = rm->incrow_buf[y]-1; - rm->incrow_buf[y] = 0; - if (x0 < x) { - for (i=x0; i<x; i++) { - GM_INC(rm->gm, i, y, -b); - } - } else { - for (i=x; i<x0; i++) { - GM_INC(rm->gm, i, y, b); - } - } -} - -/* render a straight line */ -void render_lineto(render_t *rm, double x2, double y2) { - int x2i, y2i; - double t0=2, s0=2; - int sn, tn; - double ss=2, ts=2; - double r0, r1; - int i, j; - int rxi, ryi; - int s; - - x2i = (int)floor(x2); - y2i = (int)floor(y2); - - sn = abs(x2i - rm->x1i); - tn = abs(y2i - rm->y1i); - - if (sn) { - s0 = ((x2>rm->x1 ? rm->x1i+1 : rm->x1i) - rm->x1)/(x2-rm->x1); - ss = fabs(1.0/(x2-rm->x1)); - } - if (tn) { - t0 = ((y2>rm->y1 ? rm->y1i+1 : rm->y1i) - rm->y1)/(y2-rm->y1); - ts = fabs(1.0/(y2-rm->y1)); - } - - r0 = 0; - - i = 0; - j = 0; - - rxi = rm->x1i; - ryi = rm->y1i; - - while (i<sn || j<tn) { - if (j>=tn || (i<sn && s0+i*ss < t0+j*ts)) { - r1 = s0+i*ss; - i++; - s = 1; - } else { - r1 = t0+j*ts; - j++; - s = 0; - } - /* render line from r0 to r1 segment of (rm->x1,rm->y1)..(x2,y2) */ - - /* move point to r1 */ - rm->a1 += (r1-r0)*(y2-rm->y1)*(rxi+1-((r0+r1)/2.0*(x2-rm->x1)+rm->x1)); - - /* move point across pixel boundary */ - if (s && x2>rm->x1) { - GM_INC(rm->gm, rxi, ryi, rm->a1*255); - rm->a1 = 0; - rxi++; - rm->a1 += rm->y1+r1*(y2-rm->y1)-ryi; - } else if (!s && y2>rm->y1) { - GM_INC(rm->gm, rxi, ryi, rm->a1*255); - rm->a1 = 0; - incrow(rm, rxi+1, ryi, 255); - ryi++; - } else if (s && x2<=rm->x1) { - rm->a1 -= rm->y1+r1*(y2-rm->y1)-ryi; - GM_INC(rm->gm, rxi, ryi, rm->a1*255); - rm->a1 = 0; - rxi--; - } else if (!s && y2<=rm->y1) { - GM_INC(rm->gm, rxi, ryi, rm->a1*255); - rm->a1 = 0; - ryi--; - incrow(rm, rxi+1, ryi, -255); - } - - r0 = r1; - } - - /* move point to (x2,y2) */ - - r1 = 1; - rm->a1 += (r1-r0)*(y2-rm->y1)*(rxi+1-((r0+r1)/2.0*(x2-rm->x1)+rm->x1)); - - rm->x1i = x2i; - rm->y1i = y2i; - rm->x1 = x2; - rm->y1 = y2; - - /* assert (rxi != rm->x1i || ryi != rm->y1i); */ -} - -/* render a Bezier curve. */ -void render_curveto(render_t *rm, double x2, double y2, double x3, double y3, double x4, double y4) { - double x1, y1, dd0, dd1, dd, delta, e2, epsilon, t; - - x1 = rm->x1; /* starting point */ - y1 = rm->y1; - - /* we approximate the curve by small line segments. The interval - size, epsilon, is determined on the fly so that the distance - between the true curve and its approximation does not exceed the - desired accuracy delta. */ - - delta = .1; /* desired accuracy, in pixels */ - - /* let dd = maximal value of 2nd derivative over curve - this must - occur at an endpoint. */ - dd0 = sq(x1-2*x2+x3) + sq(y1-2*y2+y3); - dd1 = sq(x2-2*x3+x4) + sq(y2-2*y3+y4); - dd = 6*sqrt(max(dd0, dd1)); - e2 = 8*delta <= dd ? 8*delta/dd : 1; - epsilon = sqrt(e2); /* necessary interval size */ - - for (t=epsilon; t<1; t+=epsilon) { - render_lineto(rm, x1*cu(1-t)+3*x2*sq(1-t)*t+3*x3*(1-t)*sq(t)+x4*cu(t), - y1*cu(1-t)+3*y2*sq(1-t)*t+3*y3*(1-t)*sq(t)+y4*cu(t)); - } - render_lineto(rm, x4, y4); -} diff --git a/src/trace/potrace/render.h b/src/trace/potrace/render.h deleted file mode 100644 index 0caaedff6..000000000 --- a/src/trace/potrace/render.h +++ /dev/null @@ -1,27 +0,0 @@ -/* Copyright (C) 2001-2015 Peter Selinger. - This file is part of Potrace. It is free software and it is covered - by the GNU General Public License. See the file COPYING for details. */ - - -#ifndef RENDER_H -#define RENDER_H - -#include "greymap.h" - -struct render_s { - greymap_t *gm; - double x0, y0, x1, y1; - int x0i, y0i, x1i, y1i; - double a0, a1; - int *incrow_buf; -}; -typedef struct render_s render_t; - -render_t *render_new(greymap_t *gm); -void render_free(render_t *rm); -void render_close(render_t *rm); -void render_moveto(render_t *rm, double x, double y); -void render_lineto(render_t *rm, double x, double y); -void render_curveto(render_t *rm, double x2, double y2, double x3, double y3, double x4, double y4); - -#endif /* RENDER_H */ diff --git a/src/trace/potrace/trace.cpp b/src/trace/potrace/trace.cpp deleted file mode 100644 index 469262b67..000000000 --- a/src/trace/potrace/trace.cpp +++ /dev/null @@ -1,1245 +0,0 @@ -/* Copyright (C) 2001-2015 Peter Selinger. - This file is part of Potrace. It is free software and it is covered - by the GNU General Public License. See the file COPYING for details. */ - -/* transform jaggy paths into smooth curves */ - -#include <stdio.h> -#include <math.h> -#include <stdlib.h> -#include <string.h> - -#include "potracelib.h" -#include "curve.h" -#include "lists.h" -#include "auxiliary.h" -#include "trace.h" -#include "progress.h" - -#define INFTY 10000000 /* it suffices that this is longer than any - path; it need not be really infinite */ -#define COS179 -0.999847695156 /* the cosine of 179 degrees */ - -/* ---------------------------------------------------------------------- */ -#define SAFE_CALLOC(var, n, typ) \ - if ((var = (typ *)calloc(n, sizeof(typ))) == NULL) goto calloc_error - -/* ---------------------------------------------------------------------- */ -/* auxiliary functions */ - -/* return a direction that is 90 degrees counterclockwise from p2-p0, - but then restricted to one of the major wind directions (n, nw, w, etc) */ -static inline point_t dorth_infty(dpoint_t p0, dpoint_t p2) { - point_t r; - - r.y = sign(p2.x-p0.x); - r.x = -sign(p2.y-p0.y); - - return r; -} - -/* return (p1-p0)x(p2-p0), the area of the parallelogram */ -static inline double dpara(dpoint_t p0, dpoint_t p1, dpoint_t p2) { - double x1, y1, x2, y2; - - x1 = p1.x-p0.x; - y1 = p1.y-p0.y; - x2 = p2.x-p0.x; - y2 = p2.y-p0.y; - - return x1*y2 - x2*y1; -} - -/* ddenom/dpara have the property that the square of radius 1 centered - at p1 intersects the line p0p2 iff |dpara(p0,p1,p2)| <= ddenom(p0,p2) */ -static inline double ddenom(dpoint_t p0, dpoint_t p2) { - point_t r = dorth_infty(p0, p2); - - return r.y*(p2.x-p0.x) - r.x*(p2.y-p0.y); -} - -/* return 1 if a <= b < c < a, in a cyclic sense (mod n) */ -static inline int cyclic(int a, int b, int c) { - if (a<=c) { - return (a<=b && b<c); - } else { - return (a<=b || b<c); - } -} - -/* determine the center and slope of the line i..j. Assume i<j. Needs - "sum" components of p to be set. */ -static void pointslope(privpath_t *pp, int i, int j, dpoint_t *ctr, dpoint_t *dir) { - /* assume i<j */ - - int n = pp->len; - sums_t *sums = pp->sums; - - double x, y, x2, xy, y2; - double k; - double a, b, c, lambda2, l; - int r=0; /* rotations from i to j */ - - while (j>=n) { - j-=n; - r+=1; - } - while (i>=n) { - i-=n; - r-=1; - } - while (j<0) { - j+=n; - r-=1; - } - while (i<0) { - i+=n; - r+=1; - } - - x = sums[j+1].x-sums[i].x+r*sums[n].x; - y = sums[j+1].y-sums[i].y+r*sums[n].y; - x2 = sums[j+1].x2-sums[i].x2+r*sums[n].x2; - xy = sums[j+1].xy-sums[i].xy+r*sums[n].xy; - y2 = sums[j+1].y2-sums[i].y2+r*sums[n].y2; - k = j+1-i+r*n; - - ctr->x = x/k; - ctr->y = y/k; - - a = (x2-(double)x*x/k)/k; - b = (xy-(double)x*y/k)/k; - c = (y2-(double)y*y/k)/k; - - lambda2 = (a+c+sqrt((a-c)*(a-c)+4*b*b))/2; /* larger e.value */ - - /* now find e.vector for lambda2 */ - a -= lambda2; - c -= lambda2; - - if (fabs(a) >= fabs(c)) { - l = sqrt(a*a+b*b); - if (l!=0) { - dir->x = -b/l; - dir->y = a/l; - } - } else { - l = sqrt(c*c+b*b); - if (l!=0) { - dir->x = -c/l; - dir->y = b/l; - } - } - if (l==0) { - dir->x = dir->y = 0; /* sometimes this can happen when k=4: - the two eigenvalues coincide */ - } -} - -/* the type of (affine) quadratic forms, represented as symmetric 3x3 - matrices. The value of the quadratic form at a vector (x,y) is v^t - Q v, where v = (x,y,1)^t. */ -typedef double quadform_t[3][3]; - -/* Apply quadratic form Q to vector w = (w.x,w.y) */ -static inline double quadform(quadform_t Q, dpoint_t w) { - double v[3]; - int i, j; - double sum; - - v[0] = w.x; - v[1] = w.y; - v[2] = 1; - sum = 0.0; - - for (i=0; i<3; i++) { - for (j=0; j<3; j++) { - sum += v[i] * Q[i][j] * v[j]; - } - } - return sum; -} - -/* calculate p1 x p2 */ -static inline int xprod(point_t p1, point_t p2) { - return p1.x*p2.y - p1.y*p2.x; -} - -/* calculate (p1-p0)x(p3-p2) */ -static inline double cprod(dpoint_t p0, dpoint_t p1, dpoint_t p2, dpoint_t p3) { - double x1, y1, x2, y2; - - x1 = p1.x - p0.x; - y1 = p1.y - p0.y; - x2 = p3.x - p2.x; - y2 = p3.y - p2.y; - - return x1*y2 - x2*y1; -} - -/* calculate (p1-p0)*(p2-p0) */ -static inline double iprod(dpoint_t p0, dpoint_t p1, dpoint_t p2) { - double x1, y1, x2, y2; - - x1 = p1.x - p0.x; - y1 = p1.y - p0.y; - x2 = p2.x - p0.x; - y2 = p2.y - p0.y; - - return x1*x2 + y1*y2; -} - -/* calculate (p1-p0)*(p3-p2) */ -static inline double iprod1(dpoint_t p0, dpoint_t p1, dpoint_t p2, dpoint_t p3) { - double x1, y1, x2, y2; - - x1 = p1.x - p0.x; - y1 = p1.y - p0.y; - x2 = p3.x - p2.x; - y2 = p3.y - p2.y; - - return x1*x2 + y1*y2; -} - -/* calculate distance between two points */ -static inline double ddist(dpoint_t p, dpoint_t q) { - return sqrt(sq(p.x-q.x)+sq(p.y-q.y)); -} - -/* calculate point of a bezier curve */ -static inline dpoint_t bezier(double t, dpoint_t p0, dpoint_t p1, dpoint_t p2, dpoint_t p3) { - double s = 1-t; - dpoint_t res; - - /* Note: a good optimizing compiler (such as gcc-3) reduces the - following to 16 multiplications, using common subexpression - elimination. */ - - res.x = s*s*s*p0.x + 3*(s*s*t)*p1.x + 3*(t*t*s)*p2.x + t*t*t*p3.x; - res.y = s*s*s*p0.y + 3*(s*s*t)*p1.y + 3*(t*t*s)*p2.y + t*t*t*p3.y; - - return res; -} - -/* calculate the point t in [0..1] on the (convex) bezier curve - (p0,p1,p2,p3) which is tangent to q1-q0. Return -1.0 if there is no - solution in [0..1]. */ -static double tangent(dpoint_t p0, dpoint_t p1, dpoint_t p2, dpoint_t p3, dpoint_t q0, dpoint_t q1) { - double A, B, C; /* (1-t)^2 A + 2(1-t)t B + t^2 C = 0 */ - double a, b, c; /* a t^2 + b t + c = 0 */ - double d, s, r1, r2; - - A = cprod(p0, p1, q0, q1); - B = cprod(p1, p2, q0, q1); - C = cprod(p2, p3, q0, q1); - - a = A - 2*B + C; - b = -2*A + 2*B; - c = A; - - d = b*b - 4*a*c; - - if (a==0 || d<0) { - return -1.0; - } - - s = sqrt(d); - - r1 = (-b + s) / (2 * a); - r2 = (-b - s) / (2 * a); - - if (r1 >= 0 && r1 <= 1) { - return r1; - } else if (r2 >= 0 && r2 <= 1) { - return r2; - } else { - return -1.0; - } -} - -/* ---------------------------------------------------------------------- */ -/* Preparation: fill in the sum* fields of a path (used for later - rapid summing). Return 0 on success, 1 with errno set on - failure. */ -static int calc_sums(privpath_t *pp) { - int i, x, y; - int n = pp->len; - - SAFE_CALLOC(pp->sums, pp->len+1, sums_t); - - /* origin */ - pp->x0 = pp->pt[0].x; - pp->y0 = pp->pt[0].y; - - /* preparatory computation for later fast summing */ - pp->sums[0].x2 = pp->sums[0].xy = pp->sums[0].y2 = pp->sums[0].x = pp->sums[0].y = 0; - for (i=0; i<n; i++) { - x = pp->pt[i].x - pp->x0; - y = pp->pt[i].y - pp->y0; - pp->sums[i+1].x = pp->sums[i].x + x; - pp->sums[i+1].y = pp->sums[i].y + y; - pp->sums[i+1].x2 = pp->sums[i].x2 + x*x; - pp->sums[i+1].xy = pp->sums[i].xy + x*y; - pp->sums[i+1].y2 = pp->sums[i].y2 + y*y; - } - return 0; - - calloc_error: - return 1; -} - -/* ---------------------------------------------------------------------- */ -/* Stage 1: determine the straight subpaths (Sec. 2.2.1). Fill in the - "lon" component of a path object (based on pt/len). For each i, - lon[i] is the furthest index such that a straight line can be drawn - from i to lon[i]. Return 1 on error with errno set, else 0. */ - -/* this algorithm depends on the fact that the existence of straight - subpaths is a triplewise property. I.e., there exists a straight - line through squares i0,...,in iff there exists a straight line - through i,j,k, for all i0<=i<j<k<=in. (Proof?) */ - -/* this implementation of calc_lon is O(n^2). It replaces an older - O(n^3) version. A "constraint" means that future points must - satisfy xprod(constraint[0], cur) >= 0 and xprod(constraint[1], - cur) <= 0. */ - -/* Remark for Potrace 1.1: the current implementation of calc_lon is - more complex than the implementation found in Potrace 1.0, but it - is considerably faster. The introduction of the "nc" data structure - means that we only have to test the constraints for "corner" - points. On a typical input file, this speeds up the calc_lon - function by a factor of 31.2, thereby decreasing its time share - within the overall Potrace algorithm from 72.6% to 7.82%, and - speeding up the overall algorithm by a factor of 3.36. On another - input file, calc_lon was sped up by a factor of 6.7, decreasing its - time share from 51.4% to 13.61%, and speeding up the overall - algorithm by a factor of 1.78. In any case, the savings are - substantial. */ - -/* returns 0 on success, 1 on error with errno set */ -static int calc_lon(privpath_t *pp) { - point_t *pt = pp->pt; - int n = pp->len; - int i, j, k, k1; - int ct[4], dir; - point_t constraint[2]; - point_t cur; - point_t off; - int *pivk = NULL; /* pivk[n] */ - int *nc = NULL; /* nc[n]: next corner */ - point_t dk; /* direction of k-k1 */ - int a, b, c, d; - - SAFE_CALLOC(pivk, n, int); - SAFE_CALLOC(nc, n, int); - - /* initialize the nc data structure. Point from each point to the - furthest future point to which it is connected by a vertical or - horizontal segment. We take advantage of the fact that there is - always a direction change at 0 (due to the path decomposition - algorithm). But even if this were not so, there is no harm, as - in practice, correctness does not depend on the word "furthest" - above. */ - k = 0; - for (i=n-1; i>=0; i--) { - if (pt[i].x != pt[k].x && pt[i].y != pt[k].y) { - k = i+1; /* necessarily i<n-1 in this case */ - } - nc[i] = k; - } - - SAFE_CALLOC(pp->lon, n, int); - - /* determine pivot points: for each i, let pivk[i] be the furthest k - such that all j with i<j<k lie on a line connecting i,k. */ - - for (i=n-1; i>=0; i--) { - ct[0] = ct[1] = ct[2] = ct[3] = 0; - - /* keep track of "directions" that have occurred */ - dir = (3+3*(pt[mod(i+1,n)].x-pt[i].x)+(pt[mod(i+1,n)].y-pt[i].y))/2; - ct[dir]++; - - constraint[0].x = 0; - constraint[0].y = 0; - constraint[1].x = 0; - constraint[1].y = 0; - - /* find the next k such that no straight line from i to k */ - k = nc[i]; - k1 = i; - while (1) { - - dir = (3+3*sign(pt[k].x-pt[k1].x)+sign(pt[k].y-pt[k1].y))/2; - ct[dir]++; - - /* if all four "directions" have occurred, cut this path */ - if (ct[0] && ct[1] && ct[2] && ct[3]) { - pivk[i] = k1; - goto foundk; - } - - cur.x = pt[k].x - pt[i].x; - cur.y = pt[k].y - pt[i].y; - - /* see if current constraint is violated */ - if (xprod(constraint[0], cur) < 0 || xprod(constraint[1], cur) > 0) { - goto constraint_viol; - } - - /* else, update constraint */ - if (abs(cur.x) <= 1 && abs(cur.y) <= 1) { - /* no constraint */ - } else { - off.x = cur.x + ((cur.y>=0 && (cur.y>0 || cur.x<0)) ? 1 : -1); - off.y = cur.y + ((cur.x<=0 && (cur.x<0 || cur.y<0)) ? 1 : -1); - if (xprod(constraint[0], off) >= 0) { - constraint[0] = off; - } - off.x = cur.x + ((cur.y<=0 && (cur.y<0 || cur.x<0)) ? 1 : -1); - off.y = cur.y + ((cur.x>=0 && (cur.x>0 || cur.y<0)) ? 1 : -1); - if (xprod(constraint[1], off) <= 0) { - constraint[1] = off; - } - } - k1 = k; - k = nc[k1]; - if (!cyclic(k,i,k1)) { - break; - } - } - constraint_viol: - /* k1 was the last "corner" satisfying the current constraint, and - k is the first one violating it. We now need to find the last - point along k1..k which satisfied the constraint. */ - dk.x = sign(pt[k].x-pt[k1].x); - dk.y = sign(pt[k].y-pt[k1].y); - cur.x = pt[k1].x - pt[i].x; - cur.y = pt[k1].y - pt[i].y; - /* find largest integer j such that xprod(constraint[0], cur+j*dk) - >= 0 and xprod(constraint[1], cur+j*dk) <= 0. Use bilinearity - of xprod. */ - a = xprod(constraint[0], cur); - b = xprod(constraint[0], dk); - c = xprod(constraint[1], cur); - d = xprod(constraint[1], dk); - /* find largest integer j such that a+j*b>=0 and c+j*d<=0. This - can be solved with integer arithmetic. */ - j = INFTY; - if (b<0) { - j = floordiv(a,-b); - } - if (d>0) { - j = min(j, floordiv(-c,d)); - } - pivk[i] = mod(k1+j,n); - foundk: - ; - } /* for i */ - - /* clean up: for each i, let lon[i] be the largest k such that for - all i' with i<=i'<k, i'<k<=pivk[i']. */ - - j=pivk[n-1]; - pp->lon[n-1]=j; - for (i=n-2; i>=0; i--) { - if (cyclic(i+1,pivk[i],j)) { - j=pivk[i]; - } - pp->lon[i]=j; - } - - for (i=n-1; cyclic(mod(i+1,n),j,pp->lon[i]); i--) { - pp->lon[i] = j; - } - - free(pivk); - free(nc); - return 0; - - calloc_error: - free(pivk); - free(nc); - return 1; -} - - -/* ---------------------------------------------------------------------- */ -/* Stage 2: calculate the optimal polygon (Sec. 2.2.2-2.2.4). */ - -/* Auxiliary function: calculate the penalty of an edge from i to j in - the given path. This needs the "lon" and "sum*" data. */ - -static double penalty3(privpath_t *pp, int i, int j) { - int n = pp->len; - point_t *pt = pp->pt; - sums_t *sums = pp->sums; - - /* assume 0<=i<j<=n */ - double x, y, x2, xy, y2; - double k; - double a, b, c, s; - double px, py, ex, ey; - - int r = 0; /* rotations from i to j */ - - if (j>=n) { - j -= n; - r = 1; - } - - /* critical inner loop: the "if" gives a 4.6 percent speedup */ - if (r == 0) { - x = sums[j+1].x - sums[i].x; - y = sums[j+1].y - sums[i].y; - x2 = sums[j+1].x2 - sums[i].x2; - xy = sums[j+1].xy - sums[i].xy; - y2 = sums[j+1].y2 - sums[i].y2; - k = j+1 - i; - } else { - x = sums[j+1].x - sums[i].x + sums[n].x; - y = sums[j+1].y - sums[i].y + sums[n].y; - x2 = sums[j+1].x2 - sums[i].x2 + sums[n].x2; - xy = sums[j+1].xy - sums[i].xy + sums[n].xy; - y2 = sums[j+1].y2 - sums[i].y2 + sums[n].y2; - k = j+1 - i + n; - } - - px = (pt[i].x + pt[j].x) / 2.0 - pt[0].x; - py = (pt[i].y + pt[j].y) / 2.0 - pt[0].y; - ey = (pt[j].x - pt[i].x); - ex = -(pt[j].y - pt[i].y); - - a = ((x2 - 2*x*px) / k + px*px); - b = ((xy - x*py - y*px) / k + px*py); - c = ((y2 - 2*y*py) / k + py*py); - - s = ex*ex*a + 2*ex*ey*b + ey*ey*c; - - return sqrt(s); -} - -/* find the optimal polygon. Fill in the m and po components. Return 1 - on failure with errno set, else 0. Non-cyclic version: assumes i=0 - is in the polygon. Fixme: implement cyclic version. */ -static int bestpolygon(privpath_t *pp) -{ - int i, j, m, k; - int n = pp->len; - double *pen = NULL; /* pen[n+1]: penalty vector */ - int *prev = NULL; /* prev[n+1]: best path pointer vector */ - int *clip0 = NULL; /* clip0[n]: longest segment pointer, non-cyclic */ - int *clip1 = NULL; /* clip1[n+1]: backwards segment pointer, non-cyclic */ - int *seg0 = NULL; /* seg0[m+1]: forward segment bounds, m<=n */ - int *seg1 = NULL; /* seg1[m+1]: backward segment bounds, m<=n */ - double thispen; - double best; - int c; - - SAFE_CALLOC(pen, n+1, double); - SAFE_CALLOC(prev, n+1, int); - SAFE_CALLOC(clip0, n, int); - SAFE_CALLOC(clip1, n+1, int); - SAFE_CALLOC(seg0, n+1, int); - SAFE_CALLOC(seg1, n+1, int); - - /* calculate clipped paths */ - for (i=0; i<n; i++) { - c = mod(pp->lon[mod(i-1,n)]-1,n); - if (c == i) { - c = mod(i+1,n); - } - if (c < i) { - clip0[i] = n; - } else { - clip0[i] = c; - } - } - - /* calculate backwards path clipping, non-cyclic. j <= clip0[i] iff - clip1[j] <= i, for i,j=0..n. */ - j = 1; - for (i=0; i<n; i++) { - while (j <= clip0[i]) { - clip1[j] = i; - j++; - } - } - - /* calculate seg0[j] = longest path from 0 with j segments */ - i = 0; - for (j=0; i<n; j++) { - seg0[j] = i; - i = clip0[i]; - } - seg0[j] = n; - m = j; - - /* calculate seg1[j] = longest path to n with m-j segments */ - i = n; - for (j=m; j>0; j--) { - seg1[j] = i; - i = clip1[i]; - } - seg1[0] = 0; - - /* now find the shortest path with m segments, based on penalty3 */ - /* note: the outer 2 loops jointly have at most n iterations, thus - the worst-case behavior here is quadratic. In practice, it is - close to linear since the inner loop tends to be short. */ - pen[0]=0; - for (j=1; j<=m; j++) { - for (i=seg1[j]; i<=seg0[j]; i++) { - best = -1; - for (k=seg0[j-1]; k>=clip1[i]; k--) { - thispen = penalty3(pp, k, i) + pen[k]; - if (best < 0 || thispen < best) { - prev[i] = k; - best = thispen; - } - } - pen[i] = best; - } - } - - pp->m = m; - SAFE_CALLOC(pp->po, m, int); - - /* read off shortest path */ - for (i=n, j=m-1; i>0; j--) { - i = prev[i]; - pp->po[j] = i; - } - - free(pen); - free(prev); - free(clip0); - free(clip1); - free(seg0); - free(seg1); - return 0; - - calloc_error: - free(pen); - free(prev); - free(clip0); - free(clip1); - free(seg0); - free(seg1); - return 1; -} - -/* ---------------------------------------------------------------------- */ -/* Stage 3: vertex adjustment (Sec. 2.3.1). */ - -/* Adjust vertices of optimal polygon: calculate the intersection of - the two "optimal" line segments, then move it into the unit square - if it lies outside. Return 1 with errno set on error; 0 on - success. */ - -static int adjust_vertices(privpath_t *pp) { - int m = pp->m; - int *po = pp->po; - int n = pp->len; - point_t *pt = pp->pt; - int x0 = pp->x0; - int y0 = pp->y0; - - dpoint_t *ctr = NULL; /* ctr[m] */ - dpoint_t *dir = NULL; /* dir[m] */ - quadform_t *q = NULL; /* q[m] */ - double v[3]; - double d; - int i, j, k, l; - dpoint_t s; - int r; - - SAFE_CALLOC(ctr, m, dpoint_t); - SAFE_CALLOC(dir, m, dpoint_t); - SAFE_CALLOC(q, m, quadform_t); - - r = privcurve_init(&pp->curve, m); - if (r) { - goto calloc_error; - } - - /* calculate "optimal" point-slope representation for each line - segment */ - for (i=0; i<m; i++) { - j = po[mod(i+1,m)]; - j = mod(j-po[i],n)+po[i]; - pointslope(pp, po[i], j, &ctr[i], &dir[i]); - } - - /* represent each line segment as a singular quadratic form; the - distance of a point (x,y) from the line segment will be - (x,y,1)Q(x,y,1)^t, where Q=q[i]. */ - for (i=0; i<m; i++) { - d = sq(dir[i].x) + sq(dir[i].y); - if (d == 0.0) { - for (j=0; j<3; j++) { - for (k=0; k<3; k++) { - q[i][j][k] = 0; - } - } - } else { - v[0] = dir[i].y; - v[1] = -dir[i].x; - v[2] = - v[1] * ctr[i].y - v[0] * ctr[i].x; - for (l=0; l<3; l++) { - for (k=0; k<3; k++) { - q[i][l][k] = v[l] * v[k] / d; - } - } - } - } - - /* now calculate the "intersections" of consecutive segments. - Instead of using the actual intersection, we find the point - within a given unit square which minimizes the square distance to - the two lines. */ - for (i=0; i<m; i++) { - quadform_t Q; - dpoint_t w; - double dx, dy; - double det; - double min, cand; /* minimum and candidate for minimum of quad. form */ - double xmin, ymin; /* coordinates of minimum */ - int z; - - /* let s be the vertex, in coordinates relative to x0/y0 */ - s.x = pt[po[i]].x-x0; - s.y = pt[po[i]].y-y0; - - /* intersect segments i-1 and i */ - - j = mod(i-1,m); - - /* add quadratic forms */ - for (l=0; l<3; l++) { - for (k=0; k<3; k++) { - Q[l][k] = q[j][l][k] + q[i][l][k]; - } - } - - while(1) { - /* minimize the quadratic form Q on the unit square */ - /* find intersection */ - -#ifdef HAVE_GCC_LOOP_BUG - /* work around gcc bug #12243 */ - free(NULL); -#endif - - det = Q[0][0]*Q[1][1] - Q[0][1]*Q[1][0]; - if (det != 0.0) { - w.x = (-Q[0][2]*Q[1][1] + Q[1][2]*Q[0][1]) / det; - w.y = ( Q[0][2]*Q[1][0] - Q[1][2]*Q[0][0]) / det; - break; - } - - /* matrix is singular - lines are parallel. Add another, - orthogonal axis, through the center of the unit square */ - if (Q[0][0]>Q[1][1]) { - v[0] = -Q[0][1]; - v[1] = Q[0][0]; - } else if (Q[1][1]) { - v[0] = -Q[1][1]; - v[1] = Q[1][0]; - } else { - v[0] = 1; - v[1] = 0; - } - d = sq(v[0]) + sq(v[1]); - v[2] = - v[1] * s.y - v[0] * s.x; - for (l=0; l<3; l++) { - for (k=0; k<3; k++) { - Q[l][k] += v[l] * v[k] / d; - } - } - } - dx = fabs(w.x-s.x); - dy = fabs(w.y-s.y); - if (dx <= .5 && dy <= .5) { - pp->curve.vertex[i].x = w.x+x0; - pp->curve.vertex[i].y = w.y+y0; - continue; - } - - /* the minimum was not in the unit square; now minimize quadratic - on boundary of square */ - min = quadform(Q, s); - xmin = s.x; - ymin = s.y; - - if (Q[0][0] == 0.0) { - goto fixx; - } - for (z=0; z<2; z++) { /* value of the y-coordinate */ - w.y = s.y-0.5+z; - w.x = - (Q[0][1] * w.y + Q[0][2]) / Q[0][0]; - dx = fabs(w.x-s.x); - cand = quadform(Q, w); - if (dx <= .5 && cand < min) { - min = cand; - xmin = w.x; - ymin = w.y; - } - } - fixx: - if (Q[1][1] == 0.0) { - goto corners; - } - for (z=0; z<2; z++) { /* value of the x-coordinate */ - w.x = s.x-0.5+z; - w.y = - (Q[1][0] * w.x + Q[1][2]) / Q[1][1]; - dy = fabs(w.y-s.y); - cand = quadform(Q, w); - if (dy <= .5 && cand < min) { - min = cand; - xmin = w.x; - ymin = w.y; - } - } - corners: - /* check four corners */ - for (l=0; l<2; l++) { - for (k=0; k<2; k++) { - w.x = s.x-0.5+l; - w.y = s.y-0.5+k; - cand = quadform(Q, w); - if (cand < min) { - min = cand; - xmin = w.x; - ymin = w.y; - } - } - } - - pp->curve.vertex[i].x = xmin + x0; - pp->curve.vertex[i].y = ymin + y0; - continue; - } - - free(ctr); - free(dir); - free(q); - return 0; - - calloc_error: - free(ctr); - free(dir); - free(q); - return 1; -} - -/* ---------------------------------------------------------------------- */ -/* Stage 4: smoothing and corner analysis (Sec. 2.3.3) */ - -/* reverse orientation of a path */ -static void reverse(privcurve_t *curve) { - int m = curve->n; - int i, j; - dpoint_t tmp; - - for (i=0, j=m-1; i<j; i++, j--) { - tmp = curve->vertex[i]; - curve->vertex[i] = curve->vertex[j]; - curve->vertex[j] = tmp; - } -} - -/* Always succeeds */ -static void smooth(privcurve_t *curve, double alphamax) { - int m = curve->n; - - int i, j, k; - double dd, denom, alpha; - dpoint_t p2, p3, p4; - - /* examine each vertex and find its best fit */ - for (i=0; i<m; i++) { - j = mod(i+1, m); - k = mod(i+2, m); - p4 = interval(1/2.0, curve->vertex[k], curve->vertex[j]); - - denom = ddenom(curve->vertex[i], curve->vertex[k]); - if (denom != 0.0) { - dd = dpara(curve->vertex[i], curve->vertex[j], curve->vertex[k]) / denom; - dd = fabs(dd); - alpha = dd>1 ? (1 - 1.0/dd) : 0; - alpha = alpha / 0.75; - } else { - alpha = 4/3.0; - } - curve->alpha0[j] = alpha; /* remember "original" value of alpha */ - - if (alpha >= alphamax) { /* pointed corner */ - curve->tag[j] = POTRACE_CORNER; - curve->c[j][1] = curve->vertex[j]; - curve->c[j][2] = p4; - } else { - if (alpha < 0.55) { - alpha = 0.55; - } else if (alpha > 1) { - alpha = 1; - } - p2 = interval(.5+.5*alpha, curve->vertex[i], curve->vertex[j]); - p3 = interval(.5+.5*alpha, curve->vertex[k], curve->vertex[j]); - curve->tag[j] = POTRACE_CURVETO; - curve->c[j][0] = p2; - curve->c[j][1] = p3; - curve->c[j][2] = p4; - } - curve->alpha[j] = alpha; /* store the "cropped" value of alpha */ - curve->beta[j] = 0.5; - } - curve->alphacurve = 1; - - return; -} - -/* ---------------------------------------------------------------------- */ -/* Stage 5: Curve optimization (Sec. 2.4) */ - -/* a private type for the result of opti_penalty */ -struct opti_s { - double pen; /* penalty */ - dpoint_t c[2]; /* curve parameters */ - double t, s; /* curve parameters */ - double alpha; /* curve parameter */ -}; -typedef struct opti_s opti_t; - -/* calculate best fit from i+.5 to j+.5. Assume i<j (cyclically). - Return 0 and set badness and parameters (alpha, beta), if - possible. Return 1 if impossible. */ -static int opti_penalty(privpath_t *pp, int i, int j, opti_t *res, double opttolerance, int *convc, double *areac) { - int m = pp->curve.n; - int k, k1, k2, conv, i1; - double area, alpha, d, d1, d2; - dpoint_t p0, p1, p2, p3, pt; - double A, R, A1, A2, A3, A4; - double s, t; - - /* check convexity, corner-freeness, and maximum bend < 179 degrees */ - - if (i==j) { /* sanity - a full loop can never be an opticurve */ - return 1; - } - - k = i; - i1 = mod(i+1, m); - k1 = mod(k+1, m); - conv = convc[k1]; - if (conv == 0) { - return 1; - } - d = ddist(pp->curve.vertex[i], pp->curve.vertex[i1]); - for (k=k1; k!=j; k=k1) { - k1 = mod(k+1, m); - k2 = mod(k+2, m); - if (convc[k1] != conv) { - return 1; - } - if (sign(cprod(pp->curve.vertex[i], pp->curve.vertex[i1], pp->curve.vertex[k1], pp->curve.vertex[k2])) != conv) { - return 1; - } - if (iprod1(pp->curve.vertex[i], pp->curve.vertex[i1], pp->curve.vertex[k1], pp->curve.vertex[k2]) < d * ddist(pp->curve.vertex[k1], pp->curve.vertex[k2]) * COS179) { - return 1; - } - } - - /* the curve we're working in: */ - p0 = pp->curve.c[mod(i,m)][2]; - p1 = pp->curve.vertex[mod(i+1,m)]; - p2 = pp->curve.vertex[mod(j,m)]; - p3 = pp->curve.c[mod(j,m)][2]; - - /* determine its area */ - area = areac[j] - areac[i]; - area -= dpara(pp->curve.vertex[0], pp->curve.c[i][2], pp->curve.c[j][2])/2; - if (i>=j) { - area += areac[m]; - } - - /* find intersection o of p0p1 and p2p3. Let t,s such that o = - interval(t,p0,p1) = interval(s,p3,p2). Let A be the area of the - triangle (p0,o,p3). */ - - A1 = dpara(p0, p1, p2); - A2 = dpara(p0, p1, p3); - A3 = dpara(p0, p2, p3); - /* A4 = dpara(p1, p2, p3); */ - A4 = A1+A3-A2; - - if (A2 == A1) { /* this should never happen */ - return 1; - } - - t = A3/(A3-A4); - s = A2/(A2-A1); - A = A2 * t / 2.0; - - if (A == 0.0) { /* this should never happen */ - return 1; - } - - R = area / A; /* relative area */ - alpha = 2 - sqrt(4 - R / 0.3); /* overall alpha for p0-o-p3 curve */ - - res->c[0] = interval(t * alpha, p0, p1); - res->c[1] = interval(s * alpha, p3, p2); - res->alpha = alpha; - res->t = t; - res->s = s; - - p1 = res->c[0]; - p2 = res->c[1]; /* the proposed curve is now (p0,p1,p2,p3) */ - - res->pen = 0; - - /* calculate penalty */ - /* check tangency with edges */ - for (k=mod(i+1,m); k!=j; k=k1) { - k1 = mod(k+1,m); - t = tangent(p0, p1, p2, p3, pp->curve.vertex[k], pp->curve.vertex[k1]); - if (t<-.5) { - return 1; - } - pt = bezier(t, p0, p1, p2, p3); - d = ddist(pp->curve.vertex[k], pp->curve.vertex[k1]); - if (d == 0.0) { /* this should never happen */ - return 1; - } - d1 = dpara(pp->curve.vertex[k], pp->curve.vertex[k1], pt) / d; - if (fabs(d1) > opttolerance) { - return 1; - } - if (iprod(pp->curve.vertex[k], pp->curve.vertex[k1], pt) < 0 || iprod(pp->curve.vertex[k1], pp->curve.vertex[k], pt) < 0) { - return 1; - } - res->pen += sq(d1); - } - - /* check corners */ - for (k=i; k!=j; k=k1) { - k1 = mod(k+1,m); - t = tangent(p0, p1, p2, p3, pp->curve.c[k][2], pp->curve.c[k1][2]); - if (t<-.5) { - return 1; - } - pt = bezier(t, p0, p1, p2, p3); - d = ddist(pp->curve.c[k][2], pp->curve.c[k1][2]); - if (d == 0.0) { /* this should never happen */ - return 1; - } - d1 = dpara(pp->curve.c[k][2], pp->curve.c[k1][2], pt) / d; - d2 = dpara(pp->curve.c[k][2], pp->curve.c[k1][2], pp->curve.vertex[k1]) / d; - d2 *= 0.75 * pp->curve.alpha[k1]; - if (d2 < 0) { - d1 = -d1; - d2 = -d2; - } - if (d1 < d2 - opttolerance) { - return 1; - } - if (d1 < d2) { - res->pen += sq(d1 - d2); - } - } - - return 0; -} - -/* optimize the path p, replacing sequences of Bezier segments by a - single segment when possible. Return 0 on success, 1 with errno set - on failure. */ -static int opticurve(privpath_t *pp, double opttolerance) { - int m = pp->curve.n; - int *pt = NULL; /* pt[m+1] */ - double *pen = NULL; /* pen[m+1] */ - int *len = NULL; /* len[m+1] */ - opti_t *opt = NULL; /* opt[m+1] */ - int om; - int i,j,r; - opti_t o; - dpoint_t p0; - int i1; - double area; - double alpha; - double *s = NULL; - double *t = NULL; - - int *convc = NULL; /* conv[m]: pre-computed convexities */ - double *areac = NULL; /* cumarea[m+1]: cache for fast area computation */ - - SAFE_CALLOC(pt, m+1, int); - SAFE_CALLOC(pen, m+1, double); - SAFE_CALLOC(len, m+1, int); - SAFE_CALLOC(opt, m+1, opti_t); - SAFE_CALLOC(convc, m, int); - SAFE_CALLOC(areac, m+1, double); - - /* pre-calculate convexity: +1 = right turn, -1 = left turn, 0 = corner */ - for (i=0; i<m; i++) { - if (pp->curve.tag[i] == POTRACE_CURVETO) { - convc[i] = sign(dpara(pp->curve.vertex[mod(i-1,m)], pp->curve.vertex[i], pp->curve.vertex[mod(i+1,m)])); - } else { - convc[i] = 0; - } - } - - /* pre-calculate areas */ - area = 0.0; - areac[0] = 0.0; - p0 = pp->curve.vertex[0]; - for (i=0; i<m; i++) { - i1 = mod(i+1, m); - if (pp->curve.tag[i1] == POTRACE_CURVETO) { - alpha = pp->curve.alpha[i1]; - area += 0.3*alpha*(4-alpha)*dpara(pp->curve.c[i][2], pp->curve.vertex[i1], pp->curve.c[i1][2])/2; - area += dpara(p0, pp->curve.c[i][2], pp->curve.c[i1][2])/2; - } - areac[i+1] = area; - } - - pt[0] = -1; - pen[0] = 0; - len[0] = 0; - - /* Fixme: we always start from a fixed point -- should find the best - curve cyclically */ - - for (j=1; j<=m; j++) { - /* calculate best path from 0 to j */ - pt[j] = j-1; - pen[j] = pen[j-1]; - len[j] = len[j-1]+1; - - for (i=j-2; i>=0; i--) { - r = opti_penalty(pp, i, mod(j,m), &o, opttolerance, convc, areac); - if (r) { - break; - } - if (len[j] > len[i]+1 || (len[j] == len[i]+1 && pen[j] > pen[i] + o.pen)) { - pt[j] = i; - pen[j] = pen[i] + o.pen; - len[j] = len[i] + 1; - opt[j] = o; - } - } - } - om = len[m]; - r = privcurve_init(&pp->ocurve, om); - if (r) { - goto calloc_error; - } - SAFE_CALLOC(s, om, double); - SAFE_CALLOC(t, om, double); - - j = m; - for (i=om-1; i>=0; i--) { - if (pt[j]==j-1) { - pp->ocurve.tag[i] = pp->curve.tag[mod(j,m)]; - pp->ocurve.c[i][0] = pp->curve.c[mod(j,m)][0]; - pp->ocurve.c[i][1] = pp->curve.c[mod(j,m)][1]; - pp->ocurve.c[i][2] = pp->curve.c[mod(j,m)][2]; - pp->ocurve.vertex[i] = pp->curve.vertex[mod(j,m)]; - pp->ocurve.alpha[i] = pp->curve.alpha[mod(j,m)]; - pp->ocurve.alpha0[i] = pp->curve.alpha0[mod(j,m)]; - pp->ocurve.beta[i] = pp->curve.beta[mod(j,m)]; - s[i] = t[i] = 1.0; - } else { - pp->ocurve.tag[i] = POTRACE_CURVETO; - pp->ocurve.c[i][0] = opt[j].c[0]; - pp->ocurve.c[i][1] = opt[j].c[1]; - pp->ocurve.c[i][2] = pp->curve.c[mod(j,m)][2]; - pp->ocurve.vertex[i] = interval(opt[j].s, pp->curve.c[mod(j,m)][2], pp->curve.vertex[mod(j,m)]); - pp->ocurve.alpha[i] = opt[j].alpha; - pp->ocurve.alpha0[i] = opt[j].alpha; - s[i] = opt[j].s; - t[i] = opt[j].t; - } - j = pt[j]; - } - - /* calculate beta parameters */ - for (i=0; i<om; i++) { - i1 = mod(i+1,om); - pp->ocurve.beta[i] = s[i] / (s[i] + t[i1]); - } - pp->ocurve.alphacurve = 1; - - free(pt); - free(pen); - free(len); - free(opt); - free(s); - free(t); - free(convc); - free(areac); - return 0; - - calloc_error: - free(pt); - free(pen); - free(len); - free(opt); - free(s); - free(t); - free(convc); - free(areac); - return 1; -} - -/* ---------------------------------------------------------------------- */ - -#define TRY(x) if (x) goto try_error - -/* return 0 on success, 1 on error with errno set. */ -int process_path(path_t *plist, const potrace_param_t *param, progress_t *progress) { - path_t *p; - double nn = 0, cn = 0; - - if (progress->callback) { - /* precompute task size for progress estimates */ - nn = 0; - list_forall (p, plist) { - nn += p->priv->len; - } - cn = 0; - } - - /* call downstream function with each path */ - list_forall (p, plist) { - TRY(calc_sums(p->priv)); - TRY(calc_lon(p->priv)); - TRY(bestpolygon(p->priv)); - TRY(adjust_vertices(p->priv)); - if (p->sign == '-') { /* reverse orientation of negative paths */ - reverse(&p->priv->curve); - } - smooth(&p->priv->curve, param->alphamax); - if (param->opticurve) { - TRY(opticurve(p->priv, param->opttolerance)); - p->priv->fcurve = &p->priv->ocurve; - } else { - p->priv->fcurve = &p->priv->curve; - } - privcurve_to_curve(p->priv->fcurve, &p->curve); - - if (progress->callback) { - cn += p->priv->len; - progress_update(cn/nn, progress); - } - } - - progress_update(1.0, progress); - - return 0; - - try_error: - return 1; -} diff --git a/src/trace/potrace/trace.h b/src/trace/potrace/trace.h deleted file mode 100644 index c53cdd10f..000000000 --- a/src/trace/potrace/trace.h +++ /dev/null @@ -1,15 +0,0 @@ -/* Copyright (C) 2001-2015 Peter Selinger. - This file is part of Potrace. It is free software and it is covered - by the GNU General Public License. See the file COPYING for details. */ - - -#ifndef TRACE_H -#define TRACE_H - -#include "potracelib.h" -#include "progress.h" -#include "curve.h" - -int process_path(path_t *plist, const potrace_param_t *param, progress_t *progress); - -#endif /* TRACE_H */ diff --git a/src/trace/trace.cpp b/src/trace/trace.cpp index 91c230920..18f03aa1b 100644 --- a/src/trace/trace.cpp +++ b/src/trace/trace.cpp @@ -74,7 +74,7 @@ SPImage *Tracer::getSelectedSPImage() them as bottom-to-top so that we can discover the image and any SPItems above it */ - for (std::vector<SPItem*>::const_iterator i=list.begin() ; list.end()!=i ; i++) + for (std::vector<SPItem*>::const_iterator i=list.begin() ; list.end()!=i ; ++i) { if (!SP_IS_ITEM(*i)) { diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt index 58af7d935..46b0af6bb 100644 --- a/src/ui/CMakeLists.txt +++ b/src/ui/CMakeLists.txt @@ -34,7 +34,6 @@ set(ui_SRC tools/dropper-tool.cpp tools/dynamic-base.cpp tools/eraser-tool.cpp - tools/flood-tool.cpp tools/freehand-base.cpp tools/gradient-tool.cpp tools/lpe-tool.cpp @@ -107,7 +106,6 @@ set(ui_SRC dialog/template-widget.cpp dialog/text-edit.cpp dialog/tile.cpp - dialog/tracedialog.cpp dialog/transformation.cpp dialog/undo-history.cpp dialog/xml-tree.cpp @@ -248,7 +246,6 @@ set(ui_SRC dialog/template-widget.h dialog/text-edit.h dialog/tile.h - dialog/tracedialog.h dialog/transformation.h dialog/undo-history.h dialog/xml-tree.h @@ -276,7 +273,6 @@ set(ui_SRC tools/dropper-tool.h tools/dynamic-base.h tools/eraser-tool.h - tools/flood-tool.h tools/freehand-base.h tools/gradient-tool.h tools/lpe-tool.h @@ -364,3 +360,14 @@ endif() # add_inkscape_lib(ui_LIB "${ui_SRC}") add_inkscape_source("${ui_SRC}") + +set ( ui_flood_and_trace_SRC + tools/flood-tool.h + tools/flood-tool.cpp + dialog/tracedialog.cpp + dialog/tracedialog.h +) + +if ("${HAVE_POTRACE}") + add_inkscape_source("${ui_flood_and_trace_SRC}") +endif() diff --git a/src/ui/clipboard.cpp b/src/ui/clipboard.cpp index d6cf1f980..f04d8a591 100644 --- a/src/ui/clipboard.cpp +++ b/src/ui/clipboard.cpp @@ -154,6 +154,7 @@ private: Inkscape::XML::Node *_root; ///< Reference to the clipboard's root node Inkscape::XML::Node *_clipnode; ///< The node that holds extra information Inkscape::XML::Document *_doc; ///< Reference to the clipboard's Inkscape::XML::Document + std::set<SPItem*> cloned_elements; // we need a way to copy plain text AND remember its style; // the standard _clipnode is only available in an SVG tree, hence this special storage @@ -239,7 +240,7 @@ void ClipboardManagerImpl::copy(SPDesktop *desktop) // Special case for when the color picker ("dropper") is active - copies color under cursor if (tools_isactive(desktop, TOOLS_DROPPER)) { //_setClipboardColor(sp_dropper_context_get_color(desktop->event_context)); - _setClipboardColor(SP_DROPPER_CONTEXT(desktop->event_context)->get_color()); + _setClipboardColor(SP_DROPPER_CONTEXT(desktop->event_context)->get_color()); _discardInternalClipboard(); return; } @@ -523,8 +524,8 @@ bool ClipboardManagerImpl::pasteSize(SPDesktop *desktop, bool separately, bool a // resize each object in the selection if (separately) { - std::vector<SPItem*> itemlist=selection->itemList(); - for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + std::vector<SPItem*> itemlist=selection->itemList(); + for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();++i){ SPItem *item = *i; if (item) { Geom::OptRect obj_size = item->desktopVisualBounds(); @@ -564,7 +565,7 @@ bool ClipboardManagerImpl::pastePathEffect(SPDesktop *desktop) } Inkscape::Selection *selection = desktop->getSelection(); - if (selection && selection->isEmpty()) { + if (!selection || selection->isEmpty()) { _userWarn(desktop, _("Select <b>object(s)</b> to paste live path effect to.")); return false; } @@ -580,7 +581,7 @@ bool ClipboardManagerImpl::pastePathEffect(SPDesktop *desktop) // make sure all selected items are converted to paths first (i.e. rectangles) sp_selected_to_lpeitems(desktop); std::vector<SPItem*> itemlist=selection->itemList(); - for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();++i){ SPItem *item = *i; _applyPathEffect(item, effectstack); } @@ -630,7 +631,7 @@ Glib::ustring ClipboardManagerImpl::getShapeOrTextObjectId(SPDesktop *desktop) // at the first object to be <svg:path> or <svg:text>. // but that could then return the id of the object's // clip path or mask, not the original path! - + SPDocument *tempdoc = _retrieveClipboard(); // any target will do here if ( tempdoc == NULL ) { _userWarn(desktop, _("Nothing on the clipboard.")); @@ -662,8 +663,9 @@ Glib::ustring ClipboardManagerImpl::getShapeOrTextObjectId(SPDesktop *desktop) void ClipboardManagerImpl::_copySelection(Inkscape::Selection *selection) { // copy the defs used by all items - std::vector<SPItem*> itemlist=selection->itemList(); - for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + std::vector<SPItem*> itemlist=selection->itemList(); + cloned_elements.clear(); + for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();++i){ SPItem *item = *i; if (item) { _copyUsedDefs(item); @@ -673,14 +675,33 @@ void ClipboardManagerImpl::_copySelection(Inkscape::Selection *selection) } // copy the representation of the items - std::vector<SPItem*> sorted_items(itemlist); + std::vector<SPObject*> sorted_items; + for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();++i) + sorted_items.push_back(*i); sort(sorted_items.begin(),sorted_items.end(),sp_object_compare_position_bool); - for(std::vector<SPItem*>::const_iterator i=sorted_items.begin();i!=sorted_items.end();i++){ - SPItem *item = *i; + //remove already copied elements from cloned_elements + std::vector<SPItem*>tr; + for(std::set<SPItem*>::iterator it = cloned_elements.begin();it!=cloned_elements.end();++it){ + if(std::find(sorted_items.begin(),sorted_items.end(),*it)!=sorted_items.end()) + tr.push_back(*it); + } + for(std::vector<SPItem*>::iterator it = tr.begin();it!=tr.end();++it){ + cloned_elements.erase(*it); + } + + sorted_items.insert(sorted_items.end(),cloned_elements.begin(),cloned_elements.end()); + + for(std::vector<SPObject*>::const_iterator i=sorted_items.begin();i!=sorted_items.end();++i){ + SPItem *item = dynamic_cast<SPItem*>(*i); if (item) { Inkscape::XML::Node *obj = item->getRepr(); - Inkscape::XML::Node *obj_copy = _copyNode(obj, _doc, _root); + Inkscape::XML::Node *obj_copy; + if(cloned_elements.find(item)==cloned_elements.end()) + obj_copy = _copyNode(obj, _doc, _root); + else + obj_copy = _copyNode(obj, _doc, _clipnode); + // copy complete inherited style SPCSSAttr *css = sp_repr_css_attr_inherited(obj, "style"); @@ -737,6 +758,12 @@ void ClipboardManagerImpl::_copySelection(Inkscape::Selection *selection) */ void ClipboardManagerImpl::_copyUsedDefs(SPItem *item) { + SPUse *use=dynamic_cast<SPUse *>(item); + if(use){ + if(cloned_elements.insert(use->get_original()).second) + _copyUsedDefs(use->get_original()); + } + // copy fill and stroke styles (patterns and gradients) SPStyle *style = item->style; diff --git a/src/ui/control-manager.cpp b/src/ui/control-manager.cpp index 5a3c5a496..7a5620684 100644 --- a/src/ui/control-manager.cpp +++ b/src/ui/control-manager.cpp @@ -298,7 +298,11 @@ void ControlManagerImpl::updateItem(SPCanvasItem *item) double target = _sizeTable[item->ctrlType][_size - 1]; if ((item->ctrlType == CTRL_TYPE_ORIGIN) && SP_IS_CTRLPOINT(item)) { - sp_ctrlpoint_set_radius(SP_CTRLPOINT(item), target / 2.0); + if (SP_CTRLPOINT(item)->is_circle ) { + sp_ctrlpoint_set_lenght(SP_CTRLPOINT(item), target ); + } else { + sp_ctrlpoint_set_lenght(SP_CTRLPOINT(item), target + 2 ); + } } else { if (_sizeChangers.count(item->ctrlType) && _manager.isSelected(item)) { target += 2; diff --git a/src/ui/control-manager.h b/src/ui/control-manager.h index 05a53f6a0..964ad0a29 100644 --- a/src/ui/control-manager.h +++ b/src/ui/control-manager.h @@ -74,9 +74,11 @@ public: private: ControlManager(); - +#if __cplusplus <= 199711L std::auto_ptr<ControlManagerImpl> _impl; - +#else + std::unique_ptr<ControlManagerImpl> _impl; +#endif friend class ControlManagerImpl; }; diff --git a/src/ui/dialog/Makefile_insert b/src/ui/dialog/Makefile_insert index cbdae1cb0..793988a7d 100644 --- a/src/ui/dialog/Makefile_insert +++ b/src/ui/dialog/Makefile_insert @@ -106,8 +106,6 @@ ink_common_sources += \ ui/dialog/text-edit.h \ ui/dialog/tile.cpp \ ui/dialog/tile.h \ - ui/dialog/tracedialog.cpp \ - ui/dialog/tracedialog.h \ ui/dialog/pixelartdialog.cpp \ ui/dialog/pixelartdialog.h \ ui/dialog/transformation.cpp \ @@ -123,3 +121,11 @@ ink_common_sources += \ ui/dialog/lpe-fillet-chamfer-properties.cpp \ ui/dialog/lpe-fillet-chamfer-properties.h \ $(inkboard_dialogs) + +if HAVE_POTRACE + +ink_common_sources += \ + ui/dialog/tracedialog.cpp \ + ui/dialog/tracedialog.h + +endif diff --git a/src/ui/dialog/align-and-distribute.cpp b/src/ui/dialog/align-and-distribute.cpp index 882427912..6a9c3db6b 100644 --- a/src/ui/dialog/align-and-distribute.cpp +++ b/src/ui/dialog/align-and-distribute.cpp @@ -535,7 +535,7 @@ private : if (length_a != length_b) return (length_a > length_b); } // Last criteria: Sort according to the z-coordinate - return (a->isSiblingOf(b)); + return sp_item_repr_compare_position(a,b)<0; } virtual void on_button_click() diff --git a/src/ui/dialog/clonetiler.cpp b/src/ui/dialog/clonetiler.cpp index f84a2ffd6..fbd050f8e 100644 --- a/src/ui/dialog/clonetiler.cpp +++ b/src/ui/dialog/clonetiler.cpp @@ -85,7 +85,7 @@ CloneTiler::CloneTiler () : { Gtk::Box *contents = _getContents(); contents->set_spacing(0); - + { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); @@ -101,7 +101,7 @@ CloneTiler::CloneTiler () : contents->pack_start (*Gtk::manage(Glib::wrap(mainbox)), true, true, 0); - GtkWidget *nb = gtk_notebook_new (); + nb = gtk_notebook_new (); gtk_box_pack_start (GTK_BOX (mainbox), nb, FALSE, FALSE, 0); @@ -662,7 +662,7 @@ CloneTiler::CloneTiler () : gtk_box_pack_start (GTK_BOX (hb), l, FALSE, FALSE, 0); guint32 rgba = 0x000000ff | sp_svg_read_color (prefs->getString(prefs_path + "initial_color").data(), 0x000000ff); - color_picker = new Inkscape::UI::Widget::ColorPicker (*new Glib::ustring(_("Initial color of tiled clones")), *new Glib::ustring(_("Initial color for clones (works only if the original has unset fill or stroke)")), rgba, false); + color_picker = new Inkscape::UI::Widget::ColorPicker (*new Glib::ustring(_("Initial color of tiled clones")), *new Glib::ustring(_("Initial color for clones (works only if the original has unset fill or stroke or on spray tool in copy mode)")), rgba, false); color_changed_connection = color_picker->connectChanged (sigc::ptr_fun(on_picker_color_changed)); gtk_box_pack_start (GTK_BOX (hb), reinterpret_cast<GtkWidget*>(color_picker->gobj()), FALSE, FALSE, 0); @@ -776,8 +776,6 @@ CloneTiler::CloneTiler () : // Trace { GtkWidget *vb = clonetiler_new_tab (nb, _("_Trace")); - - { #if GTK_CHECK_VERSION(3,0,0) GtkWidget *hb = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, VB_MARGIN); @@ -787,11 +785,11 @@ CloneTiler::CloneTiler () : #endif gtk_box_pack_start (GTK_BOX (vb), hb, FALSE, FALSE, 0); - GtkWidget *b = gtk_check_button_new_with_label (_("Trace the drawing under the tiles")); + b = gtk_check_button_new_with_label (_("Trace the drawing under the clones/sprayed items")); g_object_set_data (G_OBJECT(b), "uncheckable", GINT_TO_POINTER(TRUE)); bool old = prefs->getBool(prefs_path + "dotrace"); gtk_toggle_button_set_active ((GtkToggleButton *) b, old); - gtk_widget_set_tooltip_text (b, _("For each clone, pick a value from the drawing in that clone's location and apply it to the clone")); + gtk_widget_set_tooltip_text (b, _("For each clone/sprayed item, pick a value from the drawing in its location and apply it")); gtk_box_pack_start (GTK_BOX (hb), b, FALSE, FALSE, 0); g_signal_connect(G_OBJECT(b), "toggled", @@ -1001,6 +999,18 @@ CloneTiler::CloneTiler () : } } + { +#if GTK_CHECK_VERSION(3,0,0) + GtkWidget *hb = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, VB_MARGIN); + gtk_box_set_homogeneous(GTK_BOX(hb), FALSE); +#else + GtkWidget *hb = gtk_hbox_new(FALSE, VB_MARGIN); +#endif + gtk_box_pack_start (GTK_BOX (mainbox), hb, FALSE, FALSE, 0); + GtkWidget *l = gtk_label_new(_("")); + gtk_label_set_markup (GTK_LABEL(l), _("Apply to tiled clones:")); + gtk_box_pack_start (GTK_BOX (hb), l, FALSE, FALSE, 0); + } // Rows/columns, width/height { #if GTK_CHECK_VERSION(3,0,0) @@ -1289,7 +1299,6 @@ CloneTiler::CloneTiler () : } gtk_widget_show_all (mainbox); - } show_all(); @@ -2479,7 +2488,7 @@ void CloneTiler::clonetiler_apply(GtkWidget */*widget*/, GtkWidget *dlg) // Trace tab if (dotrace) { - Geom::Rect bbox_t = transform_rect (bbox_original, t); + Geom::Rect bbox_t = transform_rect (bbox_original, t*Geom::Scale(1.0/scale_units)); guint32 rgba = clonetiler_trace_pick (bbox_t); float r = SP_RGBA32_R_F(rgba); @@ -3005,6 +3014,13 @@ void CloneTiler::clonetiler_do_pick_toggled(GtkToggleButton *tb, GtkWidget *dlg) } } +void CloneTiler::show_page_trace() +{ + gtk_notebook_set_current_page(GTK_NOTEBOOK(nb),6); + gtk_toggle_button_set_active ((GtkToggleButton *) b, false); +} + + } } } diff --git a/src/ui/dialog/clonetiler.h b/src/ui/dialog/clonetiler.h index e5f5638b2..a8f1df0a0 100644 --- a/src/ui/dialog/clonetiler.h +++ b/src/ui/dialog/clonetiler.h @@ -31,7 +31,7 @@ public: virtual ~CloneTiler(); static CloneTiler &getInstance() { return *new CloneTiler(); } - + void show_page_trace(); protected: GtkWidget * clonetiler_new_tab(GtkWidget *nb, const gchar *label); @@ -113,6 +113,8 @@ private: CloneTiler& operator=(CloneTiler const &d); GtkWidget *dlg; + GtkWidget *nb; + GtkWidget *b; SPDesktop *desktop; DesktopTracker deskTrack; Inkscape::UI::Widget::ColorPicker *color_picker; diff --git a/src/ui/dialog/dialog-manager.cpp b/src/ui/dialog/dialog-manager.cpp index 7b1b36908..49853277c 100644 --- a/src/ui/dialog/dialog-manager.cpp +++ b/src/ui/dialog/dialog-manager.cpp @@ -34,7 +34,11 @@ #include "ui/dialog/messages.h" #include "ui/dialog/symbols.h" #include "ui/dialog/tile.h" -#include "ui/dialog/tracedialog.h" + +#if HAVE_POTRACE +# include "ui/dialog/tracedialog.h" +#endif + #include "ui/dialog/pixelartdialog.h" #include "ui/dialog/transformation.h" #include "ui/dialog/undo-history.h" @@ -124,7 +128,11 @@ DialogManager::DialogManager() { registerFactory("Swatches", &create<SwatchesPanel, FloatingBehavior>); registerFactory("TileDialog", &create<ArrangeDialog, FloatingBehavior>); registerFactory("Symbols", &create<SymbolsDialog, FloatingBehavior>); + +#if HAVE_POTRACE registerFactory("Trace", &create<TraceDialog, FloatingBehavior>); +#endif + registerFactory("PixelArt", &create<PixelArtDialog, FloatingBehavior>); registerFactory("Transformation", &create<Transformation, FloatingBehavior>); registerFactory("UndoHistory", &create<UndoHistory, FloatingBehavior>); @@ -159,7 +167,11 @@ DialogManager::DialogManager() { registerFactory("Swatches", &create<SwatchesPanel, DockBehavior>); registerFactory("TileDialog", &create<ArrangeDialog, DockBehavior>); registerFactory("Symbols", &create<SymbolsDialog, DockBehavior>); + +#if HAVE_POTRACE registerFactory("Trace", &create<TraceDialog, DockBehavior>); +#endif + registerFactory("PixelArt", &create<PixelArtDialog, DockBehavior>); registerFactory("Transformation", &create<Transformation, DockBehavior>); registerFactory("UndoHistory", &create<UndoHistory, DockBehavior>); diff --git a/src/ui/dialog/export.cpp b/src/ui/dialog/export.cpp index 1edfdfe80..2fb5f9e3b 100644 --- a/src/ui/dialog/export.cpp +++ b/src/ui/dialog/export.cpp @@ -474,7 +474,14 @@ void Export::set_default_filename () { doc_export_name = filename_entry.get_text(); } + else if ( SP_ACTIVE_DOCUMENT ) + { + Glib::ustring filename = create_filepath_from_id (_("bitmap"), filename_entry.get_text()); + filename_entry.set_text(filename); + filename_entry.set_position(filename.length()); + doc_export_name = filename_entry.get_text(); + } } #if WITH_GTKMM_3_0 @@ -814,7 +821,7 @@ void Export::onAreaToggled () if (filename.empty()) { const gchar * id = "object"; const std::vector<XML::Node*> reprlst = SP_ACTIVE_DESKTOP->getSelection()->reprList(); - for(std::vector<XML::Node*>::const_iterator i=reprlst.begin(); reprlst.end() != i; i++) { + for(std::vector<XML::Node*>::const_iterator i=reprlst.begin(); reprlst.end() != i; ++i) { Inkscape::XML::Node * repr = *i; if (repr->attribute("id")) { id = repr->attribute("id"); @@ -1023,7 +1030,7 @@ void Export::onExport () gint export_count = 0; std::vector<SPItem*> itemlist=desktop->getSelection()->itemList(); - for(std::vector<SPItem*>::const_iterator i = itemlist.begin();i!=itemlist.end() && !interrupted ;i++){ + for(std::vector<SPItem*>::const_iterator i = itemlist.begin();i!=itemlist.end() && !interrupted ;++i){ SPItem *item = *i; prog_dlg->set_data("current", GINT_TO_POINTER(n)); @@ -1232,7 +1239,7 @@ void Export::onExport () DocumentUndo::setUndoSensitive(doc, false); reprlst = desktop->getSelection()->reprList(); - for(std::vector<Inkscape::XML::Node*>::const_iterator i=reprlst.begin(); reprlst.end() != i; i++) { + for(std::vector<Inkscape::XML::Node*>::const_iterator i=reprlst.begin(); reprlst.end() != i; ++i) { Inkscape::XML::Node * repr = *i; const gchar * temp_string; Glib::ustring dir = Glib::path_get_dirname(filename.c_str()); diff --git a/src/ui/dialog/filedialogimpl-gtkmm.cpp b/src/ui/dialog/filedialogimpl-gtkmm.cpp index 17cf835cd..042637d22 100644 --- a/src/ui/dialog/filedialogimpl-gtkmm.cpp +++ b/src/ui/dialog/filedialogimpl-gtkmm.cpp @@ -199,37 +199,9 @@ void SVGPreview::showImage(Glib::ustring &theFileName) // files so we assume they are well formed. // std::cout << "SVGPreview::showImage: " << theFileName << std::endl; - std::ifstream input(theFileName.c_str()); - std::string width; std::string height; - if( !input ) { - std::cerr << "SVGPreview::showImage: Failed to open file: " << theFileName << std::endl; - } else { - - std::string token; - - Glib::MatchInfo match_info; - Glib::RefPtr<Glib::Regex> regex1 = Glib::Regex::create("width=\"(.*)\""); - Glib::RefPtr<Glib::Regex> regex2 = Glib::Regex::create("height=\"(.*)\""); - - while( !input.eof() && (height.empty() || width.empty()) ) { - - input >> token; - // std::cout << "|" << token << "|" << std::endl; - - if (regex1->match(token, match_info)) { - width = match_info.fetch(1).raw(); - } - - if (regex2->match(token, match_info)) { - height = match_info.fetch(1).raw(); - } - - } - } - /*##################################### # LET'S HAVE SOME FUN WITH SVG! # Instead of just loading an image, why @@ -265,6 +237,46 @@ void SVGPreview::showImage(Glib::ustring &theFileName) gint imgWidth = img->get_width(); gint imgHeight = img->get_height(); + + Glib::ustring svg = ".svg"; + if (hasSuffix(fileName, svg)) { + std::ifstream input(theFileName.c_str()); + if( !input ) { + std::cerr << "SVGPreview::showImage: Failed to open file: " << theFileName << std::endl; + } else { + + std::string token; + + Glib::MatchInfo match_info; + Glib::RefPtr<Glib::Regex> regex1 = Glib::Regex::create("width=\"(.*)\""); + Glib::RefPtr<Glib::Regex> regex2 = Glib::Regex::create("height=\"(.*)\""); + + while( !input.eof() && (height.empty() || width.empty()) ) { + + input >> token; + // std::cout << "|" << token << "|" << std::endl; + + if (regex1->match(token, match_info)) { + width = match_info.fetch(1).raw(); + } + + if (regex2->match(token, match_info)) { + height = match_info.fetch(1).raw(); + } + + } + } + } + + // TODO: replace int to string conversion with std::to_string when fully C++11 compliant + if (height.empty() || width.empty()) { + std::ostringstream s_width; + std::ostringstream s_height; + s_width << imgWidth; + s_height << imgHeight; + width = s_width.str(); + height = s_height.str(); + } // Find the minimum scale to fit the image inside the preview area double scaleFactorX = (0.9 * (double)previewWidth) / ((double)imgWidth); diff --git a/src/ui/dialog/filter-effects-dialog.cpp b/src/ui/dialog/filter-effects-dialog.cpp index 1ff9e4a1b..08a58291d 100644 --- a/src/ui/dialog/filter-effects-dialog.cpp +++ b/src/ui/dialog/filter-effects-dialog.cpp @@ -1474,7 +1474,7 @@ void FilterEffectsDialog::FilterModifier::update_selection(Selection *sel) std::set<SPObject*> used; std::vector<SPItem*> itemlist=sel->itemList(); - for(std::vector<SPItem*>::const_iterator i=itemlist.begin(); itemlist.end() != i; i++) { + for(std::vector<SPItem*>::const_iterator i=itemlist.begin(); itemlist.end() != i; ++i) { SPObject *obj = *i; SPStyle *style = obj->style; if (!style || !SP_IS_ITEM(obj)) { @@ -1555,7 +1555,7 @@ void FilterEffectsDialog::FilterModifier::on_selection_toggled(const Glib::ustri filter = 0; std::vector<SPItem*> itemlist=sel->itemList(); - for(std::vector<SPItem*>::const_iterator i=itemlist.begin(); itemlist.end() != i; i++) { + for(std::vector<SPItem*>::const_iterator i=itemlist.begin(); itemlist.end() != i; ++i) { SPItem * item = *i; SPStyle *style = item->style; g_assert(style != NULL); @@ -1669,7 +1669,7 @@ void FilterEffectsDialog::FilterModifier::remove_filter() // Delete all references to this filter std::vector<SPItem*> x,y; std::vector<SPItem*> all = get_all_items(x, _desktop->currentRoot(), _desktop, false, false, true, y); - for(std::vector<SPItem*>::const_iterator i=all.begin(); all.end() != i; i++) { + for(std::vector<SPItem*>::const_iterator i=all.begin(); all.end() != i; ++i) { if (!SP_IS_ITEM(*i)) { continue; } @@ -2756,8 +2756,6 @@ FilterEffectsDialog::FilterEffectsDialog() _sizegroup = Gtk::SizeGroup::create(Gtk::SIZE_GROUP_HORIZONTAL); _sizegroup->set_ignore_hidden(); - _add_primitive_type.remove_row(NR_FILTER_TILE); - // Initialize widget hierarchy #if WITH_GTKMM_3_0 Gtk::Paned* hpaned = Gtk::manage(new Gtk::Paned); @@ -2925,7 +2923,7 @@ void FilterEffectsDialog::init_settings_widgets() _settings->add_lightsource(); _settings->type(NR_FILTER_TILE); - _settings->add_notimplemented(); + _settings->add_no_params(); _settings->type(NR_FILTER_TURBULENCE); // _settings->add_checkbutton(false, SP_ATTR_STITCHTILES, _("Stitch Tiles"), "stitch", "noStitch"); @@ -3017,7 +3015,7 @@ void FilterEffectsDialog::update_primitive_infobox() break; case(NR_FILTER_TILE): _infobox_icon.set_from_icon_name("feTile-icon", Gtk::ICON_SIZE_DIALOG); - _infobox_desc.set_markup(_("The <b>feTile</b> filter primitive tiles a region with its input graphic")); + _infobox_desc.set_markup(_("The <b>feTile</b> filter primitive tiles a region with an input graphic. The source tile is defined by the filter primitive subregion of the input.")); break; case(NR_FILTER_TURBULENCE): _infobox_icon.set_from_icon_name("feTurbulence-icon", Gtk::ICON_SIZE_DIALOG); diff --git a/src/ui/dialog/filter-effects-dialog.h b/src/ui/dialog/filter-effects-dialog.h index a067cd70c..283abb5b0 100644 --- a/src/ui/dialog/filter-effects-dialog.h +++ b/src/ui/dialog/filter-effects-dialog.h @@ -127,7 +127,11 @@ private: Gtk::Button _add; Glib::RefPtr<Gtk::Menu> _menu; sigc::signal<void> _signal_filter_changed; +#if __cplusplus <= 199711L std::auto_ptr<Inkscape::XML::SignalObserver> _observer; +#else + std::unique_ptr<Inkscape::XML::SignalObserver> _observer; +#endif }; class PrimitiveColumns : public Gtk::TreeModel::ColumnRecord @@ -243,7 +247,11 @@ private: sigc::connection _scroll_connection; int _autoscroll_y; int _autoscroll_x; +#if __cplusplus <= 199711L std::auto_ptr<Inkscape::XML::SignalObserver> _observer; +#else + std::unique_ptr<Inkscape::XML::SignalObserver> _observer; +#endif int _input_type_width; int _input_type_height; }; diff --git a/src/ui/dialog/find.cpp b/src/ui/dialog/find.cpp index a8ac42a1b..0f368c5ac 100644 --- a/src/ui/dialog/find.cpp +++ b/src/ui/dialog/find.cpp @@ -561,7 +561,7 @@ std::vector<SPItem*> Find::filter_fields (std::vector<SPItem*> &l, bool exact, b std::vector<SPItem*> out; if (check_searchin_text.get_active()) { - for(std::vector<SPItem*>::const_reverse_iterator i=in.rbegin(); in.rend() != i; i++) { + for(std::vector<SPItem*>::const_reverse_iterator i=in.rbegin(); in.rend() != i; ++i) { SPObject *obj = *i; SPItem *item = dynamic_cast<SPItem *>(obj); g_assert(item != NULL); @@ -584,7 +584,7 @@ std::vector<SPItem*> Find::filter_fields (std::vector<SPItem*> &l, bool exact, b bool attrvalue = check_attributevalue.get_active(); if (ids) { - for(std::vector<SPItem*>::const_reverse_iterator i=in.rbegin(); in.rend() != i; i++) { + for(std::vector<SPItem*>::const_reverse_iterator i=in.rbegin(); in.rend() != i; ++i) { SPObject *obj = *i; SPItem *item = dynamic_cast<SPItem *>(obj); if (item_id_match(item, text, exact, casematch)) { @@ -600,7 +600,7 @@ std::vector<SPItem*> Find::filter_fields (std::vector<SPItem*> &l, bool exact, b if (style) { - for(std::vector<SPItem*>::const_reverse_iterator i=in.rbegin(); in.rend() != i; i++) { + for(std::vector<SPItem*>::const_reverse_iterator i=in.rbegin(); in.rend() != i; ++i) { SPObject *obj = *i; SPItem *item = dynamic_cast<SPItem *>(obj); g_assert(item != NULL); @@ -617,7 +617,7 @@ std::vector<SPItem*> Find::filter_fields (std::vector<SPItem*> &l, bool exact, b if (attrname) { - for(std::vector<SPItem*>::const_reverse_iterator i=in.rbegin(); in.rend() != i; i++) { + for(std::vector<SPItem*>::const_reverse_iterator i=in.rbegin(); in.rend() != i; ++i) { SPObject *obj = *i; SPItem *item = dynamic_cast<SPItem *>(obj); g_assert(item != NULL); @@ -634,7 +634,7 @@ std::vector<SPItem*> Find::filter_fields (std::vector<SPItem*> &l, bool exact, b if (attrvalue) { - for(std::vector<SPItem*>::const_reverse_iterator i=in.rbegin(); in.rend() != i; i++) { + for(std::vector<SPItem*>::const_reverse_iterator i=in.rbegin(); in.rend() != i; ++i) { SPObject *obj = *i; SPItem *item = dynamic_cast<SPItem *>(obj); g_assert(item != NULL); @@ -651,7 +651,7 @@ std::vector<SPItem*> Find::filter_fields (std::vector<SPItem*> &l, bool exact, b if (font) { - for(std::vector<SPItem*>::const_reverse_iterator i=in.rbegin(); in.rend() != i; i++) { + for(std::vector<SPItem*>::const_reverse_iterator i=in.rbegin(); in.rend() != i; ++i) { SPObject *obj = *i; SPItem *item = dynamic_cast<SPItem *>(obj); g_assert(item != NULL); @@ -718,7 +718,7 @@ bool Find::item_type_match (SPItem *item) std::vector<SPItem*> Find::filter_types (std::vector<SPItem*> &l) { std::vector<SPItem*> n; - for(std::vector<SPItem*>::const_reverse_iterator i=l.rbegin(); l.rend() != i; i++) { + for(std::vector<SPItem*>::const_reverse_iterator i=l.rbegin(); l.rend() != i; ++i) { SPObject *obj = *i; SPItem *item = dynamic_cast<SPItem *>(obj); g_assert(item != NULL); @@ -762,7 +762,7 @@ std::vector<SPItem*> &Find::all_items (SPObject *r, std::vector<SPItem*> &l, boo std::vector<SPItem*> &Find::all_selection_items (Inkscape::Selection *s, std::vector<SPItem*> &l, SPObject *ancestor, bool hidden, bool locked) { std::vector<SPItem*> itemlist=s->itemList(); - for(std::vector<SPItem*>::const_reverse_iterator i=itemlist.rbegin(); itemlist.rend() != i; i++) { + for(std::vector<SPItem*>::const_reverse_iterator i=itemlist.rbegin(); itemlist.rend() != i; ++i) { SPObject *obj = *i; SPItem *item = dynamic_cast<SPItem *>(obj); g_assert(item != NULL); diff --git a/src/ui/dialog/font-substitution.cpp b/src/ui/dialog/font-substitution.cpp index 19506c6a3..f219f3db6 100644 --- a/src/ui/dialog/font-substitution.cpp +++ b/src/ui/dialog/font-substitution.cpp @@ -154,7 +154,7 @@ std::vector<SPItem*> FontSubstitution::getFontReplacedItems(SPDocument* doc, Gli std::map<SPItem *, Glib::ustring> mapFontStyles; allList = get_all_items(x, doc->getRoot(), desktop, false, false, true, y); - for(std::vector<SPItem*>::const_iterator i = allList.begin();i!=allList.end();i++){ + for(std::vector<SPItem*>::const_iterator i = allList.begin();i!=allList.end();++i){ SPItem *item = *i; SPStyle *style = item->style; Glib::ustring family = ""; diff --git a/src/ui/dialog/glyphs.cpp b/src/ui/dialog/glyphs.cpp index 7ca277ea2..56b001291 100644 --- a/src/ui/dialog/glyphs.cpp +++ b/src/ui/dialog/glyphs.cpp @@ -579,7 +579,7 @@ void GlyphsPanel::insertText() { SPItem *textItem = 0; std::vector<SPItem*> itemlist=targetDesktop->selection->itemList(); - for(std::vector<SPItem*>::const_iterator i=itemlist.begin(); itemlist.end() != i; i++) { + for(std::vector<SPItem*>::const_iterator i=itemlist.begin(); itemlist.end() != i; ++i) { if (SP_IS_TEXT(*i) || SP_IS_FLOWTEXT(*i)) { textItem = *i; break; @@ -689,7 +689,7 @@ void GlyphsPanel::calcCanInsert() { int items = 0; std::vector<SPItem*> itemlist=targetDesktop->selection->itemList(); - for(std::vector<SPItem*>::const_iterator i=itemlist.begin(); itemlist.end() != i; i++) { + for(std::vector<SPItem*>::const_iterator i=itemlist.begin(); itemlist.end() != i; ++i) { if (SP_IS_TEXT(*i) || SP_IS_FLOWTEXT(*i)) { ++items; } diff --git a/src/ui/dialog/grid-arrange-tab.cpp b/src/ui/dialog/grid-arrange-tab.cpp index ccd23a572..639e463ea 100644 --- a/src/ui/dialog/grid-arrange-tab.cpp +++ b/src/ui/dialog/grid-arrange-tab.cpp @@ -75,16 +75,10 @@ static bool sp_compare_x_position(SPItem *first, SPItem *second) a_in_b_vert = false; } - if (!a_in_b_vert) { - return true; - } - if (a_in_b_vert && a->min()[X] > b->min()[X]) { - return false; + if (!a_in_b_vert) { // a and b are not in the same row + return (a->min()[Y] < b->min()[Y]); } - if (a_in_b_vert && a->min()[X] < b->min()[X]) { - return true; - } - return false; + return (a->min()[X] < b->min()[X]); } /* @@ -170,7 +164,7 @@ void GridArrangeTab::arrange() Inkscape::Selection *selection = desktop->getSelection(); const std::vector<SPItem*> items = selection ? selection->itemList() : std::vector<SPItem*>(); - for(std::vector<SPItem*>::const_iterator i = items.begin();i!=items.end();i++){ + for(std::vector<SPItem*>::const_iterator i = items.begin();i!=items.end(); ++i){ SPItem *item = *i; Geom::OptRect b = item->documentVisualBounds(); if (!b) { @@ -208,7 +202,7 @@ void GridArrangeTab::arrange() cnt=0; const std::vector<SPItem*> sizes(sorted); - for (std::vector<SPItem*>::const_iterator i = sizes.begin();i!=sizes.end();i++) { + for (std::vector<SPItem*>::const_iterator i = sizes.begin();i!=sizes.end(); ++i) { SPItem *item = *i; Geom::OptRect b = item->documentVisualBounds(); if (b) { @@ -307,11 +301,11 @@ g_print("\n row = %f col = %f selection x= %f selection y = %f", total_row_h cnt=0; std::vector<SPItem*>::iterator it = sorted.begin(); - for (row_cnt=0; ((it != sorted.end()) && (row_cnt<NoOfRows)); row_cnt++) { + for (row_cnt=0; ((it != sorted.end()) && (row_cnt<NoOfRows)); ++row_cnt) { GSList *current_row = NULL; col_cnt = 0; - for(;it!=sorted.end()&&col_cnt<NoOfCols;it++) { + for(;it!=sorted.end()&&col_cnt<NoOfCols;++it) { current_row = g_slist_append (current_row, *it); col_cnt++; } diff --git a/src/ui/dialog/guides.cpp b/src/ui/dialog/guides.cpp index af8e2cc31..e0efcde36 100644 --- a/src/ui/dialog/guides.cpp +++ b/src/ui/dialog/guides.cpp @@ -44,6 +44,7 @@ namespace Dialogs { GuidelinePropertiesDialog::GuidelinePropertiesDialog(SPGuide *guide, SPDesktop *desktop) : _desktop(desktop), _guide(guide), + _locked_toggle(_("Lo_cked"), _("Lock the movement of guides")), _relative_toggle(_("Rela_tive change"), _("Move and/or rotate the guide relative to current settings")), _spin_button_x(C_("Guides", "_X:"), "", UNIT_TYPE_LINEAR, "", "", &_unit_menu), _spin_button_y(C_("Guides", "_Y:"), "", UNIT_TYPE_LINEAR, "", "", &_unit_menu), @@ -100,6 +101,9 @@ void GuidelinePropertiesDialog::_onOK() double rad_angle = Geom::deg_to_rad( deg_angle ); normal = Geom::rot90(Geom::Point::polar(rad_angle, 1.0)); } + //To allow reposition from dialog + _guide->set_locked(false, true); + _guide->set_normal(normal, true); double const points_x = _spin_button_x.getValue("px"); @@ -113,6 +117,11 @@ void GuidelinePropertiesDialog::_onOK() const gchar* name = g_strdup( _label_entry.getEntry()->get_text().c_str() ); _guide->set_label(name, true); + + const bool locked = _locked_toggle.get_active(); + + _guide->set_locked(locked, true); + g_free((gpointer) name); #if WITH_GTKMM_3_0 @@ -269,6 +278,12 @@ void GuidelinePropertiesDialog::_setup() { _relative_toggle.set_valign(Gtk::ALIGN_FILL); _relative_toggle.set_hexpand(); _layout_table.attach(_relative_toggle, 1, 7, 2, 1); + + // locked radio button + _locked_toggle.set_halign(Gtk::ALIGN_FILL); + _locked_toggle.set_valign(Gtk::ALIGN_FILL); + _locked_toggle.set_hexpand(); + _layout_table.attach(_locked_toggle, 1, 8, 2, 1); #else _layout_table.attach(_spin_angle, 1, 3, 6, 7, Gtk::EXPAND | Gtk::FILL, Gtk::FILL); @@ -276,11 +291,21 @@ void GuidelinePropertiesDialog::_setup() { // mode radio button _layout_table.attach(_relative_toggle, 1, 3, 7, 8, Gtk::EXPAND | Gtk::FILL, Gtk::FILL); + + // locked radio button + _layout_table.attach(_locked_toggle, + 1, 3, 8, 9, Gtk::EXPAND | Gtk::FILL, Gtk::FILL); #endif _relative_toggle.signal_toggled().connect(sigc::mem_fun(*this, &GuidelinePropertiesDialog::_modeChanged)); _relative_toggle.set_active(_relative_toggle_status); + bool global_guides_lock = _desktop->namedview->lockguides; + if(global_guides_lock){ + _locked_toggle.set_sensitive(false); + } + _locked_toggle.set_active(_guide->getLocked()); + // don't know what this exactly does, but it results in that the dialog closes when entering a value and pressing enter (see LP bug 484187) g_signal_connect_swapped(G_OBJECT(_spin_button_x.getWidget()->gobj()), "activate", G_CALLBACK(gtk_window_activate_default), gobj()); diff --git a/src/ui/dialog/guides.h b/src/ui/dialog/guides.h index 4ff7b4fde..5dce0d6ed 100644 --- a/src/ui/dialog/guides.h +++ b/src/ui/dialog/guides.h @@ -79,6 +79,7 @@ private: Gtk::Label _label_name; Gtk::Label _label_descr; + Inkscape::UI::Widget::CheckButton _locked_toggle; Inkscape::UI::Widget::CheckButton _relative_toggle; static bool _relative_toggle_status; // remember the status of the _relative_toggle_status button across instances Inkscape::UI::Widget::UnitMenu _unit_menu; diff --git a/src/ui/dialog/icon-preview.cpp b/src/ui/dialog/icon-preview.cpp index 77f120e1a..83656a1f2 100644 --- a/src/ui/dialog/icon-preview.cpp +++ b/src/ui/dialog/icon-preview.cpp @@ -363,7 +363,7 @@ void IconPreviewPanel::refreshPreview() //g_message("found a selection to play with"); std::vector<SPItem*> const items = sel->itemList(); - for(std::vector<SPItem*>::const_iterator i=items.begin();!target && i!=items.end();i++){ + for(std::vector<SPItem*>::const_iterator i=items.begin();!target && i!=items.end();++i){ SPItem* item = *i; gchar const *id = item->getId(); if ( id ) { diff --git a/src/ui/dialog/inkscape-preferences.cpp b/src/ui/dialog/inkscape-preferences.cpp index 2bfec2ad7..b6d7e25ec 100644 --- a/src/ui/dialog/inkscape-preferences.cpp +++ b/src/ui/dialog/inkscape-preferences.cpp @@ -478,10 +478,12 @@ void InkscapePreferences::initPageTools() this->AddPage(_page_eraser, _("Eraser"), iter_tools, PREFS_PAGE_TOOLS_ERASER); this->AddNewObjectsStyle(_page_eraser, "/tools/eraser"); +#if HAVE_POTRACE //Paint Bucket this->AddPage(_page_paintbucket, _("Paint Bucket"), iter_tools, PREFS_PAGE_TOOLS_PAINTBUCKET); this->AddSelcueCheckbox(_page_paintbucket, "/tools/paintbucket", false); this->AddNewObjectsStyle(_page_paintbucket, "/tools/paintbucket"); +#endif //Gradient this->AddPage(_page_gradient, _("Gradient"), iter_tools, PREFS_PAGE_TOOLS_GRADIENT); @@ -522,22 +524,54 @@ void InkscapePreferences::initPageUI() Gtk::TreeModel::iterator iter_ui = this->AddPage(_page_ui, _("Interface"), PREFS_PAGE_UI); _path_ui = _page_list.get_model()->get_path(iter_ui); - Glib::ustring languages[] = {_("System default"), _("Albanian (sq)"), _("Amharic (am)"), _("Arabic (ar)"), _("Armenian (hy)"), _("Assamese (as)"), _("Azerbaijani (az)"), _("Basque (eu)"), _("Belarusian (be)"), - _("Bulgarian (bg)"), _("Bengali (bn)"), _("Bengali/Bangladesh (bn_BD)"), _("Breton (br)"), _("Catalan (ca)"), _("Valencian Catalan (ca@valencia)"), _("Chinese/China (zh_CN)"), - _("Chinese/Taiwan (zh_TW)"), _("Croatian (hr)"), _("Czech (cs)"), - _("Danish (da)"), _("Dogri (doi)"), _("Dutch (nl)"), _("Dzongkha (dz)"), _("German (de)"), _("Greek (el)"), _("English (en)"), _("English/Australia (en_AU)"), - _("English/Canada (en_CA)"), _("English/Great Britain (en_GB)"), _("Pig Latin (en_US@piglatin)"), - _("Esperanto (eo)"), _("Estonian (et)"), _("Farsi (fa)"), _("Finnish (fi)"), - _("French (fr)"), _("Irish (ga)"), _("Galician (gl)"), _("Gujarati (gu)"), _("Hebrew (he)"), _("Hindi (hi)"), _("Hungarian (hu)"), - _("Indonesian (id)"), _("Icelandic (is)"), _("Italian (it)"), _("Japanese (ja)"), _("Khmer (km)"), _("Kinyarwanda (rw)"), _("Korean (ko)"), _("Lithuanian (lt)"), _("Latvian (lv)"), _("Macedonian (mk)"), - _("Mongolian (mn)"), _("Nepali (ne)"), _("Norwegian Bokmål (nb)"), _("Norwegian Nynorsk (nn)"), _("Odia (or)"), _("Panjabi (pa)"), - _("Polish (pl)"), _("Portuguese (pt)"), _("Portuguese/Brazil (pt_BR)"), _("Romanian (ro)"), _("Russian (ru)"), _("Santali in Devnagari script (sat@deva)"), _("Santali in Ol-Chiki script (sat@olck)"), - _("Serbian (sr)"), _("Serbian in Latin script (sr@latin)"), _("Slovak (sk)"), _("Slovenian (sl)"), _("Spanish (es)"), _("Spanish/Mexico (es_MX)"), - _("Swedish (sv)"), _("Tamil (ta)"), _("Telugu (te)"), _("Thai (th)"), _("Turkish (tr)"), _("Ukrainian (uk)"), _("Vietnamese (vi)")}; - Glib::ustring langValues[] = {"", "sq", "am", "ar", "hy", "as", "az", "eu", "be", "bg", "bn", "bn_BD", "br", "ca", "ca@valencia", "zh_CN", "zh_TW", "hr", "cs", "da", "doi", "nl", - "dz", "de", "el", "en", "en_AU", "en_CA", "en_GB", "en_US@piglatin", "eo", "et", "fa", "fi", "fr", "ga", - "gl", "gu", "he", "hi", "hu", "id", "is", "it", "ja", "km", "rw", "ko", "lt", "lv", "mk", "mn", "ne", "nb", "nn", "or", "pa", - "pl", "pt", "pt_BR", "ro", "ru", "sat@deva", "sat@olck", "sr", "sr@latin", "sk", "sl", "es", "es_MX", "sv", "ta", "te", "th", "tr", "uk", "vi" }; + Glib::ustring languages[] = {_("System default"), + _("Albanian (sq)"), _("Amharic (am)"), _("Arabic (ar)"), _("Armenian (hy)"), _("Assamese (as)"), _("Azerbaijani (az)"), + _("Basque (eu)"), _("Belarusian (be)"), _("Bulgarian (bg)"), _("Bengali (bn)"), _("Bengali/Bangladesh (bn_BD)"), _("Bodo (brx)"), _("Breton (br)"), + _("Catalan (ca)"), _("Valencian Catalan (ca@valencia)"), _("Chinese/China (zh_CN)"), _("Chinese/Taiwan (zh_TW)"), _("Croatian (hr)"), _("Czech (cs)"), + _("Danish (da)"), _("Dogri (doi)"), _("Dutch (nl)"), _("Dzongkha (dz)"), + _("German (de)"), _("Greek (el)"), + _("English (en)"), _("English/Australia (en_AU)"), _("English/Canada (en_CA)"), _("English/Great Britain (en_GB)"), _("Pig Latin (en_US@piglatin)"), _("Esperanto (eo)"), _("Estonian (et)"), + _("Farsi (fa)"), _("Finnish (fi)"), _("French (fr)"), + _("Galician (gl)"), _("Gujarati (gu)"), + _("Hebrew (he)"), _("Hindi (hi)"), _("Hungarian (hu)"), + _("Icelandic (is)"), _("Indonesian (id)"), _("Irish (ga)"), _("Italian (it)"), + _("Japanese (ja)"), + _("Kannada (kn)"), _("Kashmiri in Peso-Arabic script (ks@aran)"), _("Kashmiri in Devanagari script (ks@deva)"), _("Khmer (km)"), _("Kinyarwanda (rw)"), _("Konkani (kok)"), _("Konkani in Latin script (kok@latin)"), _("Korean (ko)"), + _("Latvian (lv)"), _("Lithuanian (lt)"), + _("Macedonian (mk)"), _("Maithili (mai)"), _("Malayalam (ml)"), _("Manipuri (mni)"), _("Manipuri in Bengali script (mni@beng)"), _("Marathi (mr)"), _("Mongolian (mn)"), + _("Nepali (ne)"), _("Norwegian Bokmål (nb)"), _("Norwegian Nynorsk (nn)"), + _("Odia (or)"), + _("Panjabi (pa)"), _("Polish (pl)"), _("Portuguese (pt)"), _("Portuguese/Brazil (pt_BR)"), + _("Romanian (ro)"), _("Russian (ru)"), + _("Sanskrit (sa)"), _("Santali (sat)"), _("Santali in Devanagari script (sat@deva)"), _("Serbian (sr)"), _("Serbian in Latin script (sr@latin)"), + _("Sindhi (sd)"), _("Sindhi in Devanagari script (sd@deva)"), _("Slovak (sk)"), _("Slovenian (sl)"), _("Spanish (es)"), _("Spanish/Mexico (es_MX)"), _("Swedish (sv)"), + _("Tamil (ta)"), _("Telugu (te)"), _("Thai (th)"), _("Turkish (tr)"), + _("Ukrainian (uk)"), _("Urdu (ur)"), + _("Vietnamese (vi)")}; + Glib::ustring langValues[] = {"", + "sq", "am", "ar", "hy", "as", "az", + "eu", "be", "bg", "bn", "bn_BD", "brx", "br", + "ca", "ca@valencia", "zh_CN", "zh_TW", "hr", "cs", + "da", "doi", "nl", "dz", + "de", "el", + "en", "en_AU", "en_CA", "en_GB", "en_US@piglatin", "eo", "et", + "fa", "fi", "fr", + "gl", "gu", + "he", "hi", "hu", + "is", "id", "ga", "it", + "ja", + "kn", "ks@aran", "ks@deva", "km", "rw", "kok", "kok@latin", "ko", + "lv", "lt", + "mk", "mai", "ml", "mni", "mni@beng", "mr", "mn", + "ne", "nb", "nn", + "or", + "pa", "pl", "pt", "pt_BR", + "ro", "ru", + "sa", "sat", "sat@deva", "sr", "sr@latin", + "sd", "sd@deva", "sk", "sl", "es", "es_MX", "sv", + "ta", "te", "th", "tr", + "uk", "ur", + "vi" }; { // sorting languages according to translated name @@ -569,7 +603,7 @@ void InkscapePreferences::initPageUI() _("Set the language for menus and number formats"), false); { - Glib::ustring sizeLabels[] = {_("Large"), _("Small"), _("Smaller")}; + Glib::ustring sizeLabels[] = {C_("Icon size", "Large"), C_("Icon size", "Small"), C_("Icon size", "Smaller")}; int sizeValues[] = {0, 1, 2}; _misc_small_tools.init( "/toolbox/tools/small", sizeLabels, sizeValues, G_N_ELEMENTS(sizeLabels), 0 ); @@ -654,7 +688,7 @@ void InkscapePreferences::initPageUI() _win_ontop_agressive.init ( _("Aggressive"), "/options/transientpolicy/value", 2, false, &_win_ontop_none); { - Glib::ustring defaultSizeLabels[] = {_("Small"), _("Large"), _("Maximized")}; + Glib::ustring defaultSizeLabels[] = {C_("Window size", "Small"), C_("Window size", "Large"), C_("Window size", "Maximized")}; int defaultSizeValues[] = {0, 1, 2}; _win_default_size.init( "/options/defaultwindowsize/value", defaultSizeLabels, defaultSizeValues, G_N_ELEMENTS(defaultSizeLabels), 1 ); @@ -1218,11 +1252,9 @@ void InkscapePreferences::initPageBehavior() _scroll_auto_thres.init ( "/options/autoscrolldistance/value", -600.0, 600.0, 1.0, 1.0, -10.0, true, false); _page_scrolling.add_line( true, _("_Threshold:"), _scroll_auto_thres, _("pixels"), _("How far (in screen pixels) you need to be from the canvas edge to trigger autoscroll; positive is outside the canvas, negative is within the canvas"), false); -/* - _scroll_space.init ( _("Left mouse button pans when Space is pressed"), "/options/spacepans/value", false); - _page_scrolling.add_line( false, "", _scroll_space, "", - _("When on, pressing and holding Space and dragging with left mouse button pans canvas (as in Adobe Illustrator); when off, Space temporarily switches to Selector tool (default)")); -*/ + _scroll_space.init ( _("Mouse move pans when Space is pressed"), "/options/spacebarpans/value", true); + _page_scrolling.add_line( true, "", _scroll_space, "", + _("When on, pressing and holding Space and dragging pans canvas")); _wheel_zoom.init ( _("Mouse wheel zooms by default"), "/options/wheelzooms/value", false); _page_scrolling.add_line( false, "", _wheel_zoom, "", _("When on, mouse wheel zooms without Ctrl and scrolls canvas with Ctrl; when off, it zooms with Ctrl and scrolls without Ctrl")); diff --git a/src/ui/dialog/inkscape-preferences.h b/src/ui/dialog/inkscape-preferences.h index 7e0184c55..b7696ab8c 100644 --- a/src/ui/dialog/inkscape-preferences.h +++ b/src/ui/dialog/inkscape-preferences.h @@ -15,6 +15,10 @@ #ifndef INKSCAPE_UI_DIALOG_INKSCAPE_PREFERENCES_H #define INKSCAPE_UI_DIALOG_INKSCAPE_PREFERENCES_H +#if HAVE_CONFIG_H +# include "config.h" +#endif + #include <iostream> #include <vector> #include "ui/widget/preferences-widget.h" @@ -56,7 +60,11 @@ enum { PREFS_PAGE_TOOLS_TEXT, PREFS_PAGE_TOOLS_SPRAY, PREFS_PAGE_TOOLS_ERASER, + +#if HAVE_POTRACE PREFS_PAGE_TOOLS_PAINTBUCKET, +#endif + PREFS_PAGE_TOOLS_GRADIENT, PREFS_PAGE_TOOLS_DROPPER, PREFS_PAGE_TOOLS_CONNECTOR, diff --git a/src/ui/dialog/objects.cpp b/src/ui/dialog/objects.cpp index 835ecf35b..726df9a61 100644 --- a/src/ui/dialog/objects.cpp +++ b/src/ui/dialog/objects.cpp @@ -479,7 +479,7 @@ void ObjectsPanel::_objectsSelected( Selection *sel ) { _tree.get_selection()->unselect_all(); SPItem *item = NULL; std::vector<SPItem*> const items = sel->itemList(); - for(std::vector<SPItem*>::const_iterator i=items.begin(); i!=items.end();i++){ + for(std::vector<SPItem*>::const_iterator i=items.begin(); i!=items.end(); ++i){ item = *i; if (setOpacity) { @@ -1614,11 +1614,11 @@ ObjectsPanel::ObjectsPanel() : _pending(0), _toggleEvent(0), _defer_target(), - _visibleHeader(_("V")), - _lockHeader(_("L")), - _typeHeader(_("T")), - _clipmaskHeader(_("CM")), - _highlightHeader(_("HL")), + _visibleHeader(C_("Visibility", "V")), + _lockHeader(C_("Lock", "L")), + _typeHeader(C_("Type", "T")), + _clipmaskHeader(C_("Clip and mask", "CM")), + _highlightHeader(C_("Highlight", "HL")), _nameHeader(_("Label")), _composite_vbox(false, 0), _opacity_vbox(false, 0), diff --git a/src/ui/dialog/pixelartdialog.cpp b/src/ui/dialog/pixelartdialog.cpp index 760391df6..f557ff0fc 100644 --- a/src/ui/dialog/pixelartdialog.cpp +++ b/src/ui/dialog/pixelartdialog.cpp @@ -373,7 +373,7 @@ void PixelArtDialogImpl::vectorize() } std::vector<SPItem*> const items = desktop->selection->itemList(); - for(std::vector<SPItem*>::const_iterator i=items.begin(); i!=items.end();i++){ + for(std::vector<SPItem*>::const_iterator i=items.begin(); i!=items.end();++i){ if ( !SP_IS_IMAGE(*i) ) continue; diff --git a/src/ui/dialog/polar-arrange-tab.cpp b/src/ui/dialog/polar-arrange-tab.cpp index af1386e27..5ec1285c1 100644 --- a/src/ui/dialog/polar-arrange-tab.cpp +++ b/src/ui/dialog/polar-arrange-tab.cpp @@ -304,7 +304,7 @@ void PolarArrangeTab::arrange() bool arrangeOnFirstEllipse = arrangeOnEllipse && arrangeOnFirstCircleRadio.get_active(); int count = 0; - for(std::vector<SPItem*>::const_iterator i=tmp.begin();i!=tmp.end();i++) + for(std::vector<SPItem*>::const_iterator i=tmp.begin();i!=tmp.end();++i) { if(arrangeOnEllipse) { @@ -373,7 +373,7 @@ void PolarArrangeTab::arrange() Geom::Point realCenter = Geom::Point(cx, cy) * transformation; int i = 0; - for(std::vector<SPItem*>::const_iterator it=tmp.begin();it!=tmp.end();it++) + for(std::vector<SPItem*>::const_iterator it=tmp.begin();it!=tmp.end(); ++it) { SPItem *item = *it; diff --git a/src/ui/dialog/tags.cpp b/src/ui/dialog/tags.cpp index f36e3f18d..9b6f3219f 100644 --- a/src/ui/dialog/tags.cpp +++ b/src/ui/dialog/tags.cpp @@ -353,7 +353,7 @@ void TagsPanel::_objectsSelected( Selection *sel ) { _selectedConnection.block(); _tree.get_selection()->unselect_all(); std::vector<SPObject*> tmp=sel->list(); - for(std::vector<SPObject*>::const_iterator i=tmp.begin();i!=tmp.end();i++) + for(std::vector<SPObject*>::const_iterator i=tmp.begin();i!=tmp.end();++i) { SPObject *obj = *i; _store->foreach(sigc::bind<SPObject *>( sigc::mem_fun(*this, &TagsPanel::_checkForSelected), obj)); @@ -651,7 +651,7 @@ bool TagsPanel::_handleButtonEvent(GdkEventButton* event) if (SP_IS_TAG(obj)) { bool wasadded = false; std::vector<SPItem*> items=_desktop->selection->itemList(); - for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++){ + for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();++i){ SPObject *newobj = *i; bool addchild = true; for ( SPObject *child = obj->children; child != NULL; child = child->next) { diff --git a/src/ui/dialog/text-edit.cpp b/src/ui/dialog/text-edit.cpp index 7575cc854..05cf3a388 100644 --- a/src/ui/dialog/text-edit.cpp +++ b/src/ui/dialog/text-edit.cpp @@ -175,6 +175,19 @@ TextEdit::TextEdit() gtk_text_view_set_wrap_mode ((GtkTextView *) text_view, GTK_WRAP_WORD); #ifdef WITH_GTKSPELL +#ifdef WITH_GTKMM_3_0 +/* + TODO: Use computed xml:lang attribute of relevant element, if present, to specify the + language (either as 2nd arg of gtkspell_new_attach, or with explicit + gtkspell_set_language call in; see advanced.c example in gtkspell docs). + onReadSelection looks like a suitable place. +*/ + GtkSpellChecker * speller = gtk_spell_checker_new(); + + if (! gtk_spell_checker_attach(speller, GTK_TEXT_VIEW(text_view))) { + g_print("gtkspell error:\n"); + } +#else GError *error = NULL; /* @@ -188,6 +201,7 @@ TextEdit::TextEdit() g_error_free(error); } #endif +#endif gtk_widget_set_size_request (text_view, -1, 64); gtk_text_view_set_editable (GTK_TEXT_VIEW (text_view), TRUE); @@ -430,7 +444,7 @@ SPItem *TextEdit::getSelectedTextItem (void) return NULL; std::vector<SPItem*> tmp=SP_ACTIVE_DESKTOP->getSelection()->itemList(); - for(std::vector<SPItem*>::const_iterator i=tmp.begin();i!=tmp.end();i++) + for(std::vector<SPItem*>::const_iterator i=tmp.begin();i!=tmp.end();++i) { if (SP_IS_TEXT(*i) || SP_IS_FLOWTEXT(*i)) return *i; @@ -448,7 +462,7 @@ unsigned TextEdit::getSelectedTextCount (void) unsigned int items = 0; std::vector<SPItem*> tmp=SP_ACTIVE_DESKTOP->getSelection()->itemList(); - for(std::vector<SPItem*>::const_iterator i=tmp.begin();i!=tmp.end();i++) + for(std::vector<SPItem*>::const_iterator i=tmp.begin();i!=tmp.end();++i) { if (SP_IS_TEXT(*i) || SP_IS_FLOWTEXT(*i)) ++items; @@ -558,7 +572,7 @@ void TextEdit::onApply() SPCSSAttr *css = fillTextStyle (); sp_desktop_set_style(desktop, css, true); - for(std::vector<SPItem*>::const_iterator i=item_list.begin();i!=item_list.end();i++){ + for(std::vector<SPItem*>::const_iterator i=item_list.begin();i!=item_list.end();++i){ // apply style to the reprs of all text objects in the selection if (SP_IS_TEXT (*i)) { diff --git a/src/ui/dialog/transformation.cpp b/src/ui/dialog/transformation.cpp index 498ad7822..ae972bbbd 100644 --- a/src/ui/dialog/transformation.cpp +++ b/src/ui/dialog/transformation.cpp @@ -812,7 +812,7 @@ void Transformation::applyPageScale(Inkscape::Selection *selection) bool preserve = prefs->getBool("/options/preservetransform/value", false); if (prefs->getBool("/dialogs/transformation/applyseparately")) { std::vector<SPItem*> tmp=selection->itemList(); - for(std::vector<SPItem*>::const_iterator i=tmp.begin();i!=tmp.end();i++){ + for(std::vector<SPItem*>::const_iterator i=tmp.begin();i!=tmp.end();++i){ SPItem *item = *i; Geom::OptRect bbox_pref = item->desktopPreferredBounds(); Geom::OptRect bbox_geom = item->desktopGeometricBounds(); @@ -876,7 +876,7 @@ void Transformation::applyPageRotate(Inkscape::Selection *selection) if (prefs->getBool("/dialogs/transformation/applyseparately")) { std::vector<SPItem*> tmp=selection->itemList(); - for(std::vector<SPItem*>::const_iterator i=tmp.begin();i!=tmp.end();i++){ + for(std::vector<SPItem*>::const_iterator i=tmp.begin();i!=tmp.end();++i){ SPItem *item = *i; sp_item_rotate_rel(item, Geom::Rotate (angle*M_PI/180.0)); } @@ -896,7 +896,7 @@ void Transformation::applyPageSkew(Inkscape::Selection *selection) Inkscape::Preferences *prefs = Inkscape::Preferences::get(); if (prefs->getBool("/dialogs/transformation/applyseparately")) { std::vector<SPItem*> items=selection->itemList(); - for(std::vector<SPItem*>::const_iterator i = items.begin();i!=items.end();i++){ + for(std::vector<SPItem*>::const_iterator i = items.begin();i!=items.end();++i){ SPItem *item = *i; if (!_units_skew.isAbsolute()) { // percentage @@ -998,7 +998,7 @@ void Transformation::applyPageTransform(Inkscape::Selection *selection) if (_check_replace_matrix.get_active()) { std::vector<SPItem*> tmp=selection->itemList(); - for(std::vector<SPItem*>::const_iterator i=tmp.begin();i!=tmp.end();i++){ + for(std::vector<SPItem*>::const_iterator i=tmp.begin();i!=tmp.end();++i){ SPItem *item = *i; item->set_item_transform(displayed); item->updateRepr(); @@ -1170,6 +1170,9 @@ void Transformation::onReplaceMatrixToggled() void Transformation::onScaleProportionalToggled() { onScaleXValueChanged(); + if (_scalar_scale_vertical.setProgrammatically) { + _scalar_scale_vertical.setProgrammatically = false; + } } diff --git a/src/ui/interface.cpp b/src/ui/interface.cpp index a129d4b92..91301fb60 100644 --- a/src/ui/interface.cpp +++ b/src/ui/interface.cpp @@ -239,7 +239,7 @@ sp_create_window(SPViewWidget *vw, bool editable) } int pos = nui_drop_target_entries; - for (std::vector<gchar*>::iterator it = types.begin() ; it != types.end() ; it++) { + for (std::vector<gchar*>::iterator it = types.begin() ; it != types.end() ; ++it) { completeDropTargets[pos].target = *it; completeDropTargets[pos].flags = 0; completeDropTargets[pos].info = IMAGE_DATA; @@ -577,6 +577,9 @@ static gboolean checkitem_update(GtkWidget *widget, GdkEventExpose * /*event*/, if (!strcmp(action->id, "ToggleGrid")) { ison = dt->gridsEnabled(); } + else if (!strcmp(action->id, "EditGuidesToggleLock")) { + ison = dt->namedview->lockguides; + } else if (!strcmp(action->id, "ToggleGuides")) { ison = dt->namedview->getGuides(); } @@ -846,13 +849,11 @@ static void sp_ui_build_dyn_menus(Inkscape::XML::Node *menus, GtkWidget *menu, I #endif } } else if (menu_pntr->attribute("check") != NULL) { - SPAction *action = NULL; if (verb->get_code() != SP_VERB_NONE) { - action = verb->get_action(Inkscape::ActionContext(view)); - } - sp_ui_menu_append_check_item_from_verb(GTK_MENU(menu), view, action->name, action->tip, NULL, + SPAction *action = verb->get_action(Inkscape::ActionContext(view)); + sp_ui_menu_append_check_item_from_verb(GTK_MENU(menu), view, action->name, action->tip, NULL, checkitem_toggled, checkitem_update, verb); - + } } else { sp_ui_menu_append_item_from_verb(GTK_MENU(menu), verb, view); group = NULL; @@ -868,11 +869,7 @@ static void sp_ui_build_dyn_menus(Inkscape::XML::Node *menus, GtkWidget *menu, I } continue; } - if (!strcmp(menu_pntr->name(), "separator") - // This was spelt wrong in the original version - // and so this is for backward compatibility. It can - // probably be dropped after the 0.44 release. - || !strcmp(menu_pntr->name(), "seperator")) { + if (!strcmp(menu_pntr->name(), "separator")) { GtkWidget *item = gtk_separator_menu_item_new(); gtk_widget_show(item); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); @@ -2076,7 +2073,7 @@ void ContextMenu::ImageEdit(void) #endif std::vector<SPItem*> itemlist=_desktop->selection->itemList(); - for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();++i){ Inkscape::XML::Node *ir = (*i)->getRepr(); const gchar *href = ir->attribute("xlink:href"); diff --git a/src/ui/object-edit.cpp b/src/ui/object-edit.cpp index 0a6c792dc..459acf002 100644 --- a/src/ui/object-edit.cpp +++ b/src/ui/object-edit.cpp @@ -1364,13 +1364,15 @@ public: }; void -OffsetKnotHolderEntity::knot_set(Geom::Point const &p, Geom::Point const &/*origin*/, unsigned int /*state*/) +OffsetKnotHolderEntity::knot_set(Geom::Point const &p, Geom::Point const &/*origin*/, unsigned int state) { SPOffset *offset = dynamic_cast<SPOffset *>(item); g_assert(offset != NULL); - offset->rad = sp_offset_distance_to_original(offset, p); - offset->knot = p; + Geom::Point const p_snapped = snap_knot_position(p, state); + + offset->rad = sp_offset_distance_to_original(offset, p_snapped); + offset->knot = p_snapped; offset->knotSet = true; offset->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); diff --git a/src/ui/tool-factory.cpp b/src/ui/tool-factory.cpp index 700bd40ce..c6c579c9e 100644 --- a/src/ui/tool-factory.cpp +++ b/src/ui/tool-factory.cpp @@ -16,7 +16,11 @@ #include "ui/tools/connector-tool.h" #include "ui/tools/dropper-tool.h" #include "ui/tools/eraser-tool.h" -#include "ui/tools/flood-tool.h" + +#if HAVE_POTRACE +# include "ui/tools/flood-tool.h" +#endif + #include "ui/tools/gradient-tool.h" #include "ui/tools/lpe-tool.h" #include "ui/tools/measure-tool.h" @@ -52,8 +56,10 @@ ToolBase *ToolFactory::createObject(std::string const& id) tool = new DropperTool; else if (id == "/tools/eraser") tool = new EraserTool; +#if HAVE_POTRACE else if (id == "/tools/paintbucket") tool = new FloodTool; +#endif else if (id == "/tools/gradient") tool = new GradientTool; else if (id == "/tools/lpetool") diff --git a/src/ui/tool/multi-path-manipulator.cpp b/src/ui/tool/multi-path-manipulator.cpp index 46c6246a1..9ec6f733f 100644 --- a/src/ui/tool/multi-path-manipulator.cpp +++ b/src/ui/tool/multi-path-manipulator.cpp @@ -683,13 +683,14 @@ bool MultiPathManipulator::event(Inkscape::UI::Tools::ToolBase *event_context, G //if the trace is bspline ( mode 2) if(mode==2){ // is this correct ? - if(del_preserves_shape ^ held_control(event->key)) + if(del_preserves_shape ^ held_control(event->key)){ deleteNodes(false); - else + } else { deleteNodes(true); - } - else + } + } else { deleteNodes(del_preserves_shape ^ held_control(event->key)); + } // Delete any selected gradient nodes as well event_context->deleteSelectedDrag(held_control(event->key)); diff --git a/src/ui/tool/node.cpp b/src/ui/tool/node.cpp index ca6f5abb1..06e49dc7f 100644 --- a/src/ui/tool/node.cpp +++ b/src/ui/tool/node.cpp @@ -60,10 +60,8 @@ Inkscape::ControlType nodeTypeToCtrlType(Inkscape::UI::NodeType type) namespace Inkscape { namespace UI { -/*const double handleCubicGap = 0.01;*/ -const double noPower = 0.0; -const double defaultStartPower = 0.3334; -/*const double defaultEndPower = 0.6667;*/ +const double NO_POWER = 0.0; +const double DEFAULT_START_POWER = 0.333334; ControlPoint::ColorSet Node::node_colors = { {0xbfbfbf00, 0x000000ff}, // normal fill, stroke @@ -142,6 +140,7 @@ void Handle::move(Geom::Point const &new_pos) Node *node_away = _parent->nodeAwayFrom(this); // node in the opposite direction Handle *towards = node_towards ? node_towards->handleAwayFrom(_parent) : NULL; Handle *towards_second = node_towards ? node_towards->handleToward(_parent) : NULL; + double bspline_weight = 0.0; if (Geom::are_near(new_pos, _parent->position())) { // The handle becomes degenerate. @@ -176,8 +175,9 @@ void Handle::move(Geom::Point const &new_pos) //move the handler and its oposite the same proportion if(_pm()._isBSpline()){ - setPosition(_pm()._bsplineHandleReposition(this,this)); - this->other()->setPosition(_pm()._bsplineHandleReposition(this->other(),this)); + setPosition(_pm()._bsplineHandleReposition(this, false)); + bspline_weight = _pm()._bsplineHandlePosition(this, false); + this->other()->setPosition(_pm()._bsplineHandleReposition(this->other(), bspline_weight)); } return; } @@ -193,8 +193,9 @@ void Handle::move(Geom::Point const &new_pos) //move the handler and its oposite the same proportion if(_pm()._isBSpline()){ - setPosition(_pm()._bsplineHandleReposition(this,this)); - this->other()->setPosition(_pm()._bsplineHandleReposition(this->other(),this)); + setPosition(_pm()._bsplineHandleReposition(this, false)); + bspline_weight = _pm()._bsplineHandlePosition(this, false); + this->other()->setPosition(_pm()._bsplineHandleReposition(this->other(), bspline_weight)); } return; @@ -219,8 +220,9 @@ void Handle::move(Geom::Point const &new_pos) // moves the handler and its oposite the same proportion if(_pm()._isBSpline()){ - setPosition(_pm()._bsplineHandleReposition(this,this)); - this->other()->setPosition(_pm()._bsplineHandleReposition(this->other(),this)); + setPosition(_pm()._bsplineHandleReposition(this, false)); + bspline_weight = _pm()._bsplineHandlePosition(this, false); + this->other()->setPosition(_pm()._bsplineHandleReposition(this->other(), bspline_weight)); } } @@ -299,7 +301,7 @@ bool Handle::_eventHandler(Inkscape::UI::Tools::ToolBase *event_context, GdkEven default: break; } break; - // new double click event to set the handlers of a node to the default proportion, defaultStartPower% + // new double click event to set the handlers of a node to the default proportion, DEFAULT_START_POWER% case GDK_2BUTTON_PRESS: handle_2button_press(); break; @@ -310,11 +312,11 @@ bool Handle::_eventHandler(Inkscape::UI::Tools::ToolBase *event_context, GdkEven return ControlPoint::_eventHandler(event_context, event); } -//this function moves the handler and its oposite to the default proportion of defaultStartPower +//this function moves the handler and its oposite to the default proportion of DEFAULT_START_POWER void Handle::handle_2button_press(){ if(_pm()._isBSpline()){ - setPosition(_pm()._bsplineHandleReposition(this,defaultStartPower)); - this->other()->setPosition(_pm()._bsplineHandleReposition(this->other(),defaultStartPower)); + setPosition(_pm()._bsplineHandleReposition(this, DEFAULT_START_POWER)); + this->other()->setPosition(_pm()._bsplineHandleReposition(this->other(), DEFAULT_START_POWER)); _pm().update(); } } @@ -375,7 +377,7 @@ void Handle::dragged(Geom::Point &new_pos, GdkEventMotion *event) if(_pm()._isBSpline()){ setPosition(new_pos); int steps = _pm()._bsplineGetSteps(); - new_pos=_pm()._bsplineHandleReposition(this,ceilf(_pm()._bsplineHandlePosition(this,this)*steps)/steps); + new_pos=_pm()._bsplineHandleReposition(this,ceilf(_pm()._bsplineHandlePosition(this, false)*steps)/steps); } } @@ -549,7 +551,7 @@ Glib::ustring Handle::_getTip(unsigned state) const "<b>Auto node handle</b>: drag to convert to smooth node (%s)"), more); }else{ return format_tip(C_("Path handle tip", - "<b>BSpline node handle</b>: Shift to drag, double click to reset (%s). %g power"),more,_pm()._bsplineHandlePosition(h,NULL)); + "<b>BSpline node handle</b>: Shift to drag, double click to reset (%s). %g power"),more,_pm()._bsplineHandlePosition(h)); } } } @@ -627,22 +629,18 @@ void Node::move(Geom::Point const &new_pos) Geom::Point delta = new_pos - position(); // save the previous nodes strength to apply it again once the node is moved - double nodeWeight = noPower; - double nextNodeWeight = noPower; - double prevNodeWeight = noPower; + double nodeWeight = NO_POWER; + double nextNodeWeight = NO_POWER; + double prevNodeWeight = NO_POWER; Node *n = this; Node * nextNode = n->nodeToward(n->front()); Node * prevNode = n->nodeToward(n->back()); - nodeWeight = fmax(_pm()._bsplineHandlePosition(n->front()),_pm()._bsplineHandlePosition(n->back())); + nodeWeight = fmax(_pm()._bsplineHandlePosition(n->front(), false),_pm()._bsplineHandlePosition(n->back(), false)); if(prevNode){ - if(prevNode->isEndNode()){ - prevNodeWeight = _pm()._bsplineHandlePosition(prevNode->front(),prevNode->front()); - } + prevNodeWeight = _pm()._bsplineHandlePosition(prevNode->front()); } if(nextNode){ - if(nextNode->isEndNode()){ - nextNodeWeight = _pm()._bsplineHandlePosition(nextNode->back(),nextNode->back()); - } + nextNodeWeight = _pm()._bsplineHandlePosition(nextNode->back()); } setPosition(new_pos); @@ -659,18 +657,10 @@ void Node::move(Geom::Point const &new_pos) _front.setPosition(_pm()._bsplineHandleReposition(this->front(),nodeWeight)); _back.setPosition(_pm()._bsplineHandleReposition(this->back(),nodeWeight)); if(prevNode){ - if(prevNode->isEndNode()){ - prevNode->front()->setPosition(_pm()._bsplineHandleReposition(prevNode->front(),prevNodeWeight)); - }else{ - prevNode->front()->setPosition(_pm()._bsplineHandleReposition(prevNode->front(),prevNode->back())); - } + prevNode->front()->setPosition(_pm()._bsplineHandleReposition(prevNode->front(), prevNodeWeight)); } if(nextNode){ - if(nextNode->isEndNode()){ - nextNode->back()->setPosition(_pm()._bsplineHandleReposition(nextNode->back(),nextNodeWeight)); - }else{ - nextNode->back()->setPosition(_pm()._bsplineHandleReposition(nextNode->back(),nextNode->front())); - } + nextNode->back()->setPosition(_pm()._bsplineHandleReposition(nextNode->back(), nextNodeWeight)); } } } @@ -681,22 +671,18 @@ void Node::transform(Geom::Affine const &m) Geom::Point old_pos = position(); // save the previous nodes strength to apply it again once the node is moved - double nodeWeight = noPower; - double nextNodeWeight = noPower; - double prevNodeWeight = noPower; + double nodeWeight = NO_POWER; + double nextNodeWeight = NO_POWER; + double prevNodeWeight = NO_POWER; Node *n = this; Node * nextNode = n->nodeToward(n->front()); Node * prevNode = n->nodeToward(n->back()); nodeWeight = _pm()._bsplineHandlePosition(n->front()); if(prevNode){ - if(prevNode->isEndNode()){ - prevNodeWeight = _pm()._bsplineHandlePosition(prevNode->front(),prevNode->front()); - } + prevNodeWeight = _pm()._bsplineHandlePosition(prevNode->front()); } if(nextNode){ - if(nextNode->isEndNode()){ - nextNodeWeight = _pm()._bsplineHandlePosition(nextNode->back(),nextNode->back()); - } + nextNodeWeight = _pm()._bsplineHandlePosition(nextNode->back()); } setPosition(position() * m); @@ -709,21 +695,13 @@ void Node::transform(Geom::Affine const &m) // move the involved handlers, first the node ones, later the adjoining ones if(_pm()._isBSpline()){ - _front.setPosition(_pm()._bsplineHandleReposition(this->front(),nodeWeight)); - _back.setPosition(_pm()._bsplineHandleReposition(this->back(),nodeWeight)); + _front.setPosition(_pm()._bsplineHandleReposition(this->front(), nodeWeight)); + _back.setPosition(_pm()._bsplineHandleReposition(this->back(), nodeWeight)); if(prevNode){ - if(prevNode->isEndNode()){ - prevNode->front()->setPosition(_pm()._bsplineHandleReposition(prevNode->front(),prevNodeWeight)); - }else{ - prevNode->front()->setPosition(_pm()._bsplineHandleReposition(prevNode->front(),prevNode->back())); - } + prevNode->front()->setPosition(_pm()._bsplineHandleReposition(prevNode->front(), prevNodeWeight)); } if(nextNode){ - if(nextNode->isEndNode()){ - nextNode->back()->setPosition(_pm()._bsplineHandleReposition(nextNode->back(),nextNodeWeight)); - }else{ - nextNode->back()->setPosition(_pm()._bsplineHandleReposition(nextNode->back(),nextNode->front())); - } + nextNode->back()->setPosition(_pm()._bsplineHandleReposition(nextNode->back(), nextNodeWeight)); } } } @@ -913,15 +891,15 @@ void Node::setType(NodeType type, bool update_handles) break; default: break; } - /* in node type changes, about bspline traces, we can mantain them with noPower power in border mode, + /* in node type changes, about bspline traces, we can mantain them with NO_POWER power in border mode, or we give them the default power in curve mode */ if(_pm()._isBSpline()){ - double weight = noPower; - if(_pm()._bsplineHandlePosition(this->front()) != noPower ){ - weight = defaultStartPower; + double weight = NO_POWER; + if(_pm()._bsplineHandlePosition(this->front()) != NO_POWER ){ + weight = DEFAULT_START_POWER; } - _front.setPosition(_pm()._bsplineHandleReposition(this->front(),weight)); - _back.setPosition(_pm()._bsplineHandleReposition(this->back(),weight)); + _front.setPosition(_pm()._bsplineHandleReposition(this->front(), weight)); + _back.setPosition(_pm()._bsplineHandleReposition(this->back(), weight)); } } _type = type; @@ -1435,7 +1413,6 @@ Glib::ustring Node::_getTip(unsigned state) const { bool isBSpline = _pm()._isBSpline(); Handle *h = const_cast<Handle *>(&_front); - Handle *h2 = const_cast<Handle *>(&_back); if (state_held_shift(state)) { bool can_drag_out = (_next() && _front.isDegenerate()) || (_prev() && _back.isDegenerate()); if (can_drag_out) { @@ -1464,7 +1441,7 @@ Glib::ustring Node::_getTip(unsigned state) const // No modifiers: assemble tip from node type char const *nodetype = node_type_to_localized_string(_type); - double power = _pm()._bsplineHandlePosition(h,h2); + double power = _pm()._bsplineHandlePosition(h); if (_selection.transformHandlesEnabled() && selected()) { if (_selection.size() == 1 && !isBSpline) { return format_tip(C_("Path node tip", diff --git a/src/ui/tool/path-manipulator.cpp b/src/ui/tool/path-manipulator.cpp index 848b10373..fb9e2c070 100644 --- a/src/ui/tool/path-manipulator.cpp +++ b/src/ui/tool/path-manipulator.cpp @@ -56,9 +56,9 @@ enum PathChange { }; } // anonymous namespace -const double HANDLE_CUBIC_GAP = 0.01; +const double HANDLE_CUBIC_GAP = 0.001; const double NO_POWER = 0.0; -const double defaultStartPower = 0.3334; +const double DEFAULT_START_POWER = 0.333334; /** @@ -695,10 +695,12 @@ unsigned PathManipulator::_deleteStretch(NodeList::iterator start, NodeList::ite // if we are removing, we readjust the handlers if(_isBSpline()){ if(start.prev()){ - start.prev()->front()->setPosition(_bsplineHandleReposition(start.prev()->front(),start.prev()->back())); + double bspline_weight = _bsplineHandlePosition(start.prev()->back(), false); + start.prev()->front()->setPosition(_bsplineHandleReposition(start.prev()->front(), bspline_weight)); } if(end){ - end->back()->setPosition(_bsplineHandleReposition(end->back(),end->front())); + double bspline_weight = _bsplineHandlePosition(end->front(), false); + end->back()->setPosition(_bsplineHandleReposition(end->back(),bspline_weight)); } } @@ -1033,7 +1035,7 @@ NodeList::iterator PathManipulator::subdivideSegment(NodeList::iterator first, d line_inside_nodes->moveto(n->position()); line_inside_nodes->lineto(second->position()); sbasis_inside_nodes = line_inside_nodes->first_segment()->toSBasis(); - Geom::Point next = sbasis_inside_nodes.valueAt(defaultStartPower); + Geom::Point next = sbasis_inside_nodes.valueAt(DEFAULT_START_POWER); next = Geom::Point(next[Geom::X] + HANDLE_CUBIC_GAP,next[Geom::Y] + HANDLE_CUBIC_GAP); line_inside_nodes->reset(); n->front()->setPosition(next); @@ -1044,7 +1046,7 @@ NodeList::iterator PathManipulator::subdivideSegment(NodeList::iterator first, d line_inside_nodes->moveto(n->position()); line_inside_nodes->lineto(first->position()); sbasis_inside_nodes = line_inside_nodes->first_segment()->toSBasis(); - Geom::Point previous = sbasis_inside_nodes.valueAt(defaultStartPower); + Geom::Point previous = sbasis_inside_nodes.valueAt(DEFAULT_START_POWER); previous = Geom::Point(previous[Geom::X] + HANDLE_CUBIC_GAP,previous[Geom::Y] + HANDLE_CUBIC_GAP); n->back()->setPosition(previous); }else{ @@ -1277,13 +1279,10 @@ bool PathManipulator::_isBSpline() const { } // returns the corresponding strength to the position of the handlers -double PathManipulator::_bsplineHandlePosition(Handle *h, Handle *h2) +double PathManipulator::_bsplineHandlePosition(Handle *h, bool check_other) { using Geom::X; using Geom::Y; - if(h2){ - h = h2; - } double pos = NO_POWER; Node *n = h->parent(); Node * next_node = NULL; @@ -1296,16 +1295,16 @@ double PathManipulator::_bsplineHandlePosition(Handle *h, Handle *h2) pos = Geom::nearest_time(Geom::Point(h->position()[X] - HANDLE_CUBIC_GAP, h->position()[Y] - HANDLE_CUBIC_GAP), *line_inside_nodes->first_segment()); } } - if (pos == NO_POWER && !h2){ - return _bsplineHandlePosition(h, h->other()); + if (pos == NO_POWER && check_other){ + return _bsplineHandlePosition(h->other(), false); } return pos; } // give the location for the handler in the corresponding position -Geom::Point PathManipulator::_bsplineHandleReposition(Handle *h, Handle *h2) +Geom::Point PathManipulator::_bsplineHandleReposition(Handle *h, bool check_other) { - double pos = this->_bsplineHandlePosition(h, h2); + double pos = this->_bsplineHandlePosition(h, check_other); return _bsplineHandleReposition(h,pos); } diff --git a/src/ui/tool/path-manipulator.h b/src/ui/tool/path-manipulator.h index 4c6f74ba4..283cb610a 100644 --- a/src/ui/tool/path-manipulator.h +++ b/src/ui/tool/path-manipulator.h @@ -111,8 +111,8 @@ private: void _recalculateIsBSpline(); bool _isBSpline() const; - double _bsplineHandlePosition(Handle *h, Handle *h2 = NULL); - Geom::Point _bsplineHandleReposition(Handle *h, Handle *h2 = NULL); + double _bsplineHandlePosition(Handle *h, bool check_other = true); + Geom::Point _bsplineHandleReposition(Handle *h, bool check_other = true); Geom::Point _bsplineHandleReposition(Handle *h, double pos); void _createGeometryFromControlPoints(bool alert_LPE = false); unsigned _deleteStretch(NodeList::iterator first, NodeList::iterator last, bool keep_shape); diff --git a/src/ui/tool/selector.cpp b/src/ui/tool/selector.cpp index 051cb41ae..9acf7de88 100644 --- a/src/ui/tool/selector.cpp +++ b/src/ui/tool/selector.cpp @@ -39,6 +39,7 @@ public: setVisible(false); _rubber = static_cast<CtrlRect*>(sp_canvas_item_new(_desktop->getControls(), SP_TYPE_CTRLRECT, NULL)); + _rubber->setShadow(1, 0xffffffff); sp_canvas_item_hide(_rubber); } diff --git a/src/ui/tool/transform-handle-set.cpp b/src/ui/tool/transform-handle-set.cpp index da2a54989..748b9d4cc 100644 --- a/src/ui/tool/transform-handle-set.cpp +++ b/src/ui/tool/transform-handle-set.cpp @@ -15,9 +15,11 @@ #include <glib/gi18n.h> #include <2geom/transforms.h> #include "desktop.h" +#include "sp-namedview.h" #include "display/sodipodi-ctrlrect.h" #include "preferences.h" +#include "pure-transform.h" #include "snap.h" #include "snap-candidate.h" #include "sp-namedview.h" @@ -93,6 +95,7 @@ TransformHandle::TransformHandle(TransformHandleSet &th, SPAnchorType anchor, Gl setVisible(false); } +// TODO: This code is duplicated in seltrans.cpp; fix this! void TransformHandle::getNextClosestPoint(bool reverse) { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); @@ -113,6 +116,11 @@ void TransformHandle::getNextClosestPoint(bool reverse) _snap_points.clear(); _snap_points.push_back(*_all_snap_sources_iter); + // Show the updated snap source now; otherwise it won't be shown until the selection is being moved again + SnapManager &m = _desktop->namedview->snap_manager; + m.setup(_desktop); + m.displaySnapsource(*_all_snap_sources_iter); + m.unSetup(); } } } @@ -247,7 +255,7 @@ protected: if (Geom::are_near(vold[Geom::X], 0) || Geom::are_near(vold[Geom::Y], 0)) return Geom::identity(); - double scale[2] = { vnew[Geom::X] / vold[Geom::X], vnew[Geom::Y] / vold[Geom::Y] }; + Geom::Scale scale = Geom::Scale(vnew[Geom::X] / vold[Geom::X], vnew[Geom::Y] / vold[Geom::Y]); if (held_alt(*event)) { for (unsigned i = 0; i < 2; ++i) { @@ -261,20 +269,21 @@ protected: SnapManager &m = _th._desktop->namedview->snap_manager; m.setupIgnoreSelection(_th._desktop, true, &_unselected_points); - Inkscape::SnappedPoint sp; + Inkscape::PureScale *ptr; if (held_control(*event)) { scale[0] = scale[1] = std::min(scale[0], scale[1]); - sp = m.constrainedSnapScale(_snap_points, _origin, Geom::Scale(scale[0], scale[1]), scc); + ptr = new Inkscape::PureScaleConstrained(Geom::Scale(scale[0], scale[1]), scc); } else { - sp = m.freeSnapScale(_snap_points, _origin, Geom::Scale(scale[0], scale[1]), scc); + ptr = new Inkscape::PureScale(Geom::Scale(scale[0], scale[1]), scc, false); } + m.snapTransformed(_snap_points, _origin, (*ptr)); m.unSetup(); - if (sp.getSnapped()) { - Geom::Point result = sp.getTransformation(); - scale[0] = result[0]; - scale[1] = result[1]; + if (ptr->best_snapped_point.getSnapped()) { + scale = ptr->getScaleSnapped(); } + + delete ptr; } _last_scale_x = scale[0]; @@ -349,11 +358,12 @@ protected: m.setupIgnoreSelection(_th._desktop, true, &_unselected_points); bool uniform = held_control(*event); - Inkscape::SnappedPoint sp = m.constrainedSnapStretch(_snap_points, _origin, vs[d1], scc, d1, uniform); + Inkscape::PureStretchConstrained psc = Inkscape::PureStretchConstrained(vs[d1], scc, d1, uniform); + m.snapTransformed(_snap_points, _origin, psc); m.unSetup(); - if (sp.getSnapped()) { - Geom::Point result = sp.getTransformation(); + if (psc.best_snapped_point.getSnapped()) { + Geom::Point result = psc.getStretchSnapped().vector(); //best_snapped_point.getTransformation(); vs[d1] = result[d1]; vs[d2] = result[d2]; } else { @@ -414,11 +424,12 @@ protected: } else { SnapManager &m = _th._desktop->namedview->snap_manager; m.setupIgnoreSelection(_th._desktop, true, &_unselected_points); - Inkscape::SnappedPoint sp = m.constrainedSnapRotate(_snap_points, _origin, angle, rotc); + Inkscape::PureRotateConstrained prc = Inkscape::PureRotateConstrained(angle, rotc); + m.snapTransformed(_snap_points, _origin, prc); m.unSetup(); - if (sp.getSnapped()) { - angle = sp.getTransformation()[0]; + if (prc.best_snapped_point.getSnapped()) { + angle = prc.getAngleSnapped(); //best_snapped_point.getTransformation()[0]; } } @@ -528,13 +539,12 @@ protected: SnapManager &m = _th._desktop->namedview->snap_manager; m.setupIgnoreSelection(_th._desktop, true, &_unselected_points); - Geom::Point cvec; cvec[d2] = 1.0; - Inkscape::Snapper::SnapConstraint const constraint(cvec); - Inkscape::SnappedPoint sp = m.constrainedSnapSkew(_snap_points, _origin, constraint, Geom::Point(skew[d1], scale[d1]), scc, d2); + Inkscape::PureSkewConstrained psc = Inkscape::PureSkewConstrained(skew[d1], scale[d1], scc, d2); + m.snapTransformed(_snap_points, _origin, psc); m.unSetup(); - if (sp.getSnapped()) { - skew[d1] = sp.getTransformation()[0]; + if (psc.best_snapped_point.getSnapped()) { + skew[d1] = psc.getSkewSnapped(); //best_snapped_point.getTransformation()[0]; } } diff --git a/src/ui/tools-switch.h b/src/ui/tools-switch.h index 280837e87..d396597ca 100644 --- a/src/ui/tools-switch.h +++ b/src/ui/tools-switch.h @@ -12,6 +12,10 @@ #ifndef SEEN_TOOLS_SWITCH_H #define SEEN_TOOLS_SWITCH_H +#if HAVE_CONFIG_H +# include "config.h" +#endif + class SPDesktop; class SPItem; namespace Geom { @@ -40,7 +44,11 @@ enum { TOOLS_MEASURE, TOOLS_DROPPER, TOOLS_CONNECTOR, + +#if HAVE_POTRACE TOOLS_PAINTBUCKET, +#endif + TOOLS_ERASER, TOOLS_LPETOOL }; diff --git a/src/ui/tools/Makefile_insert b/src/ui/tools/Makefile_insert index cd09a3230..686dfedd8 100644 --- a/src/ui/tools/Makefile_insert +++ b/src/ui/tools/Makefile_insert @@ -8,7 +8,6 @@ ink_common_sources += \ ui/tools/dropper-tool.cpp ui/tools/dropper-tool.h \ ui/tools/dynamic-base.cpp ui/tools/dynamic-base.h \ ui/tools/eraser-tool.cpp ui/tools/eraser-tool.h \ - ui/tools/flood-tool.cpp ui/tools/flood-tool.h \ ui/tools/freehand-base.cpp ui/tools/freehand-base.h \ ui/tools/gradient-tool.cpp ui/tools/gradient-tool.h \ ui/tools/lpe-tool.cpp ui/tools/lpe-tool.h \ @@ -25,4 +24,11 @@ ink_common_sources += \ ui/tools/text-tool.cpp ui/tools/text-tool.h \ ui/tools/tool-base.cpp ui/tools/tool-base.h \ ui/tools/tweak-tool.cpp ui/tools/tweak-tool.h \ - ui/tools/zoom-tool.cpp ui/tools/zoom-tool.h
\ No newline at end of file + ui/tools/zoom-tool.cpp ui/tools/zoom-tool.h + +if HAVE_POTRACE + +ink_common_sources += \ + ui/tools/flood-tool.cpp ui/tools/flood-tool.h + +endif diff --git a/src/ui/tools/connector-tool.cpp b/src/ui/tools/connector-tool.cpp index 0a36877ff..b84d16686 100644 --- a/src/ui/tools/connector-tool.cpp +++ b/src/ui/tools/connector-tool.cpp @@ -1307,7 +1307,7 @@ void cc_selection_set_avoid(bool const set_avoid) int changes = 0; std::vector<SPItem*> l = selection->itemList(); - for(std::vector<SPItem*>::const_iterator i=l.begin();i!=l.end();i++) { + for(std::vector<SPItem*>::const_iterator i=l.begin();i!=l.end(); ++i) { SPItem *item = *i; char const *value = (set_avoid) ? "true" : NULL; diff --git a/src/ui/tools/eraser-tool.cpp b/src/ui/tools/eraser-tool.cpp index e416fd7ef..83ecf7a0a 100644 --- a/src/ui/tools/eraser-tool.cpp +++ b/src/ui/tools/eraser-tool.cpp @@ -682,7 +682,7 @@ void EraserTool::set_to_accumulated() { if ( !toWorkOn.empty() ) { if ( eraserMode ) { - for (std::vector<SPItem*>::const_iterator i = toWorkOn.begin(); i != toWorkOn.end(); i++){ + for (std::vector<SPItem*>::const_iterator i = toWorkOn.begin(); i != toWorkOn.end(); ++i){ SPItem *item = *i; if ( eraserMode ) { @@ -701,7 +701,7 @@ void EraserTool::set_to_accumulated() { if ( !selection->isEmpty() ) { // If the item was not completely erased, track the new remainder. std::vector<SPItem*> nowSel(selection->itemList()); - for (std::vector<SPItem*>::const_iterator i2 = nowSel.begin();i2!=nowSel.end();i2++) { + for (std::vector<SPItem*>::const_iterator i2 = nowSel.begin();i2!=nowSel.end();++i2) { remainingItems.push_back(*i2); } } @@ -711,11 +711,11 @@ void EraserTool::set_to_accumulated() { } } } else { - for (std::vector<SPItem*> ::const_iterator i = toWorkOn.begin();i!=toWorkOn.end();i++) { + for (std::vector<SPItem*> ::const_iterator i = toWorkOn.begin();i!=toWorkOn.end();++i) { sp_object_ref( *i, 0 ); } - for (std::vector<SPItem*>::const_iterator i = toWorkOn.begin();i!=toWorkOn.end();i++) { + for (std::vector<SPItem*>::const_iterator i = toWorkOn.begin();i!=toWorkOn.end();++i) { SPItem *item = *i; item->deleteObject(true); sp_object_unref(item); diff --git a/src/ui/tools/gradient-tool.cpp b/src/ui/tools/gradient-tool.cpp index 603458983..bcb0b12b7 100644 --- a/src/ui/tools/gradient-tool.cpp +++ b/src/ui/tools/gradient-tool.cpp @@ -495,7 +495,7 @@ bool GradientTool::root_handler(GdkEvent* event) { sp_gradient_context_add_stop_near_point(this, SP_ITEM(selection->itemList().front()), this->mousepoint_doc, event->button.time); } else { std::vector<SPItem*> items=selection->itemList(); - for (std::vector<SPItem*>::const_iterator i = items.begin();i!=items.end();i++) { + for (std::vector<SPItem*>::const_iterator i = items.begin();i!=items.end();++i) { SPItem *item = *i; SPGradientType new_type = (SPGradientType) prefs->getInt("/tools/gradient/newgradient", SP_GRADIENT_TYPE_LINEAR); Inkscape::PaintTarget fsmode = (prefs->getInt("/tools/gradient/newfillorstroke", 1) != 0) ? Inkscape::FOR_FILL : Inkscape::FOR_STROKE; @@ -910,7 +910,7 @@ static void sp_gradient_drag(GradientTool &rc, Geom::Point const pt, guint /*sta sp_repr_css_set_property(css, "fill-opacity", "1.0"); std::vector<SPItem*> itemlist = selection->itemList(); - for (std::vector<SPItem*>::const_iterator i = itemlist.begin();i!=itemlist.end();i++) { + for (std::vector<SPItem*>::const_iterator i = itemlist.begin();i!=itemlist.end();++i) { //FIXME: see above sp_repr_css_change_recursive((*i)->getRepr(), css, "style"); diff --git a/src/ui/tools/lpe-tool.cpp b/src/ui/tools/lpe-tool.cpp index 13e47f3a6..9bbc1ac20 100644 --- a/src/ui/tools/lpe-tool.cpp +++ b/src/ui/tools/lpe-tool.cpp @@ -397,7 +397,7 @@ lpetool_create_measuring_items(LpeTool *lc, Inkscape::Selection *selection) gchar *arc_length; double lengthval; std::vector<SPItem*> items=selection->itemList(); - for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++){ + for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();++i){ if (SP_IS_PATH(*i)) { path = SP_PATH(*i); curve = path->getCurve(); diff --git a/src/ui/tools/measure-tool.cpp b/src/ui/tools/measure-tool.cpp index 570f3e796..4d17a7ed5 100644 --- a/src/ui/tools/measure-tool.cpp +++ b/src/ui/tools/measure-tool.cpp @@ -4,6 +4,7 @@ * Authors: * Felipe Correa da Silva Sanches <juca@members.fsf.org> * Jon A. Cruz <jon@joncruz.org> + * Jabiertxo Arraiza <jabier.arraiza@marker.es> * * Copyright (C) 2011 Authors * @@ -14,40 +15,57 @@ #include <gdk/gdkkeysyms.h> #include <boost/none_t.hpp> #include "util/units.h" -#include "macros.h" #include "display/curve.h" -#include "sp-shape.h" -#include "sp-text.h" -#include "sp-flowtext.h" -#include "text-editing.h" -#include "display/sp-ctrlline.h" #include "display/sodipodi-ctrl.h" +#include "display/sp-ctrlline.h" +#include "display/sp-canvas.h" #include "display/sp-canvas-item.h" #include "display/sp-canvas-util.h" -#include "desktop.h" -#include "document.h" -#include "pixmaps/cursor-measure.xpm" -#include "preferences.h" -#include "inkscape.h" - +#include "svg/svg.h" +#include "svg/svg-color.h" #include "ui/tools/measure-tool.h" #include "ui/tools/freehand-base.h" -#include "display/canvas-text.h" -#include "path-chemistry.h" -#include "2geom/line.h" +#include <2geom/line.h> #include <2geom/path-intersection.h> #include <2geom/pathvector.h> #include <2geom/crossing.h> #include <2geom/angle.h> -#include "snap.h" +#include <2geom/transforms.h> #include "sp-namedview.h" +#include "sp-shape.h" +#include "sp-text.h" +#include "sp-flowtext.h" +#include "sp-defs.h" +#include "sp-item.h" +#include "sp-root.h" +#include "macros.h" +#include "svg/stringstream.h" +#include "rubberband.h" +#include "path-chemistry.h" +#include "desktop.h" +#include "document.h" +#include "document-undo.h" +#include "viewbox.h" +#include "snap.h" +#include "text-editing.h" +#include "pixmaps/cursor-measure.xpm" +#include "preferences.h" +#include "inkscape.h" +#include "knot.h" #include "enums.h" -#include "ui/control-manager.h" #include "knot-enums.h" +#include "desktop-style.h" +#include "verbs.h" +#include <glibmm/i18n.h> using Inkscape::ControlManager; using Inkscape::CTLINE_SECONDARY; using Inkscape::Util::unit_table; +using Inkscape::DocumentUndo; + +#define MT_KNOT_COLOR_NORMAL 0xffffff00 +#define MT_KNOT_COLOR_MOUSEOVER 0xff000000 + namespace Inkscape { namespace UI { @@ -55,16 +73,14 @@ namespace Tools { std::vector<Inkscape::Display::TemporaryItem*> measure_tmp_items; -const std::string& MeasureTool::getPrefsPath() { - return MeasureTool::prefsPath; +const std::string& MeasureTool::getPrefsPath() +{ + return MeasureTool::prefsPath; } const std::string MeasureTool::prefsPath = "/tools/measure"; -namespace -{ - -gint const DIMENSION_OFFSET = 35; +namespace { /** * Simple class to use for removing label overlap. @@ -87,14 +103,16 @@ bool SortLabelPlacement(LabelPlacement const &first, LabelPlacement const &secon } } -void repositionOverlappingLabels(std::vector<LabelPlacement> &placements, SPDesktop *desktop, Geom::Point const &normal, double fontsize) +//precision is for give the number of decimal positions +//of the label to calculate label width +void repositionOverlappingLabels(std::vector<LabelPlacement> &placements, SPDesktop *desktop, Geom::Point const &normal, double fontsize, int precision) { std::sort(placements.begin(), placements.end(), SortLabelPlacement); double border = 3; Geom::Rect box; { - Geom::Point tmp(fontsize * 8 + (border * 2), fontsize + (border * 2)); + Geom::Point tmp(fontsize * (6 + precision) + (border * 2), fontsize + (border * 2)); tmp = desktop->w2d(tmp); box = Geom::Rect(-tmp[Geom::X] / 2, -tmp[Geom::Y] / 2, tmp[Geom::X] / 2, tmp[Geom::Y] / 2); } @@ -175,6 +193,76 @@ Geom::Point calcAngleDisplayAnchor(SPDesktop *desktop, double angle, double base } /** + * Create a measure iten in current document. + * + * @param pathv the path to create. + * @param markers, if the path resuts get markers. + * @param color of the stroke. + * @param measure_repr container element. + */ +void setMeasureItem(Geom::PathVector pathv, bool is_curve, bool markers, guint32 color, Inkscape::XML::Node *measure_repr) +{ + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + if(!desktop) { + return; + } + SPDocument *doc = desktop->getDocument(); + Inkscape::XML::Document *xml_doc = doc->getReprDoc(); + Inkscape::XML::Node *repr; + repr = xml_doc->createElement("svg:path"); + gchar *str = sp_svg_write_path(pathv); + SPCSSAttr *css = sp_repr_css_attr_new(); + Geom::Coord strokewidth = SP_ITEM(desktop->currentLayer())->i2doc_affine().inverse().expansionX(); + std::stringstream stroke_width; + stroke_width.imbue(std::locale::classic()); + if(measure_repr) { + stroke_width << strokewidth / desktop->current_zoom(); + } else { + stroke_width << strokewidth; + } + sp_repr_css_set_property (css, "stroke-width", stroke_width.str().c_str()); + sp_repr_css_set_property (css, "fill", "none"); + if(color) { + gchar color_line[64]; + sp_svg_write_color (color_line, sizeof(color_line), color); + sp_repr_css_set_property (css, "stroke", color_line); + } else { + sp_repr_css_set_property (css, "stroke", "#ff0000"); + } + char const * stroke_linecap = is_curve ? "butt" : "square"; + sp_repr_css_set_property (css, "stroke-linecap", stroke_linecap); + sp_repr_css_set_property (css, "stroke-linejoin", "miter"); + sp_repr_css_set_property (css, "stroke-miterlimit", "4"); + sp_repr_css_set_property (css, "stroke-dasharray", "none"); + if(measure_repr) { + sp_repr_css_set_property (css, "stroke-opacity", "0.5"); + } else { + sp_repr_css_set_property (css, "stroke-opacity", "1"); + } + if(markers) { + sp_repr_css_set_property (css, "marker-start", "url(#Arrow2Sstart)"); + sp_repr_css_set_property (css, "marker-end", "url(#Arrow2Send)"); + } + Glib::ustring css_str; + sp_repr_css_write_string(css,css_str); + repr->setAttribute("style", css_str.c_str()); + sp_repr_css_attr_unref (css); + g_assert( str != NULL ); + repr->setAttribute("d", str); + g_free(str); + if(measure_repr) { + measure_repr->addChild(repr, NULL); + Inkscape::GC::release(repr); + } else { + SPItem *item = SP_ITEM(desktop->currentLayer()->appendChildRepr(repr)); + Inkscape::GC::release(repr); + item->updateRepr(); + desktop->getSelection()->clear(); + desktop->getSelection()->add(item); + } +} + +/** * Given an angle, the arc center and edge point, draw an arc segment centered around that edge point. * * @param desktop the desktop that is being used. @@ -182,8 +270,9 @@ Geom::Point calcAngleDisplayAnchor(SPDesktop *desktop, double angle, double base * @param end the point that ends at the edge of the arc segment. * @param anchor the anchor point for displaying the text label. * @param angle the angle of the arc segment to draw. + * @param measure_rpr the container of the curve if converted to items. */ -void createAngleDisplayCurve(SPDesktop *desktop, Geom::Point const ¢er, Geom::Point const &end, Geom::Point const &anchor, double angle) +void createAngleDisplayCurve(SPDesktop *desktop, Geom::Point const ¢er, Geom::Point const &end, Geom::Point const &anchor, double angle, Inkscape::XML::Node *measure_repr = NULL) { // Given that we have a point on the arc's edge and the angle of the arc, we need to get the two endpoints. @@ -191,7 +280,7 @@ void createAngleDisplayCurve(SPDesktop *desktop, Geom::Point const ¢er, Geom double sideLen = std::abs((end - center).length()); if (sideLen > 0.0) { double factor = std::min(1.0, textLen / sideLen); - + // arc start Geom::Point p1 = end * (Geom::Affine(Geom::Translate(-center)) * Geom::Affine(Geom::Scale(factor)) @@ -221,22 +310,186 @@ void createAngleDisplayCurve(SPDesktop *desktop, Geom::Point const ¢er, Geom SPCtrlCurve *curve = ControlManager::getManager().createControlCurve(desktop->getTempGroup(), p1, p2, p3, p4, CTLINE_SECONDARY); measure_tmp_items.push_back(desktop->add_temporary_canvasitem(SP_CANVAS_ITEM(curve), 0, true)); + if(measure_repr) { + Geom::PathVector pathv; + Geom::Path path; + path.start(desktop->doc2dt(p1)); + path.appendNew<Geom::CubicBezier>(desktop->doc2dt(p2),desktop->doc2dt(p3),desktop->doc2dt(p4)); + pathv.push_back(path); + pathv *= SP_ITEM(desktop->currentLayer())->i2doc_affine().inverse(); + if(!pathv.empty()) { + setMeasureItem(pathv, true, false, 0xff00007f, measure_repr); + } + } } } } // namespace - MeasureTool::MeasureTool() : ToolBase(cursor_measure_xpm, 4, 4) , grabbed(NULL) { + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + start_p = readMeasurePoint(true); + end_p = readMeasurePoint(false); + dimension_offset = 35; + // create the knots + this->knot_start = new SPKnot(desktop, N_("Measure start")); + this->knot_start->setMode(SP_KNOT_MODE_XOR); + this->knot_start->setFill(MT_KNOT_COLOR_NORMAL, MT_KNOT_COLOR_MOUSEOVER, MT_KNOT_COLOR_MOUSEOVER); + this->knot_start->setStroke(0x0000007f, 0x0000007f, 0x0000007f); + this->knot_start->setShape(SP_KNOT_SHAPE_CIRCLE); + this->knot_start->updateCtrl(); + this->knot_end = new SPKnot(desktop, N_("Measure end")); + this->knot_end->setMode(SP_KNOT_MODE_XOR); + this->knot_end->setFill(MT_KNOT_COLOR_NORMAL, MT_KNOT_COLOR_MOUSEOVER, MT_KNOT_COLOR_MOUSEOVER); + this->knot_end->setStroke(0x0000007f, 0x0000007f, 0x0000007f); + this->knot_end->setShape(SP_KNOT_SHAPE_CIRCLE); + this->knot_end->updateCtrl(); + Geom::Rect display_area = desktop->get_display_area(); + if(display_area.interiorContains(start_p) && display_area.interiorContains(end_p) && end_p != Geom::Point()) { + this->knot_start->moveto(start_p); + this->knot_start->show(); + this->knot_end->moveto(end_p); + this->knot_end->show(); + showCanvasItems(); + } else { + start_p = Geom::Point(0,0); + end_p = Geom::Point(0,0); + writeMeasurePoint(start_p, true); + writeMeasurePoint(end_p, false); + } + + this->_knot_start_moved_connection = this->knot_start->moved_signal.connect(sigc::mem_fun(*this, &MeasureTool::knotStartMovedHandler)); + this->_knot_start_ungrabbed_connection = this->knot_start->ungrabbed_signal.connect(sigc::mem_fun(*this, &MeasureTool::knotUngrabbedHandler)); + this->_knot_end_moved_connection = this->knot_end->moved_signal.connect(sigc::mem_fun(*this, &MeasureTool::knotEndMovedHandler)); + this->_knot_end_ungrabbed_connection = this->knot_end->ungrabbed_signal.connect(sigc::mem_fun(*this, &MeasureTool::knotUngrabbedHandler)); + } -MeasureTool::~MeasureTool() { +MeasureTool::~MeasureTool() +{ + this->_knot_start_moved_connection.disconnect(); + this->_knot_start_ungrabbed_connection.disconnect(); + this->_knot_end_moved_connection.disconnect(); + this->_knot_end_ungrabbed_connection.disconnect(); + + /* unref should call destroy */ + knot_unref(this->knot_start); + knot_unref(this->knot_end); + for (size_t idx = 0; idx < measure_tmp_items.size(); ++idx) { + desktop->remove_temporary_canvasitem(measure_tmp_items[idx]); + } + measure_tmp_items.clear(); } -void MeasureTool::finish() { +Geom::Point MeasureTool::readMeasurePoint(bool is_start) { + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + SPNamedView *namedview = desktop->namedview; + if(!namedview) { + return Geom::Point(Geom::infinity(),Geom::infinity()); + } + char const * measure_point = is_start ? "inkscape:measure-start" : "inkscape:measure-end"; + char const * measure_point_data = namedview->getAttribute (measure_point); + if(!measure_point_data) { + measure_point_data = "0,0"; + namedview->setAttribute (measure_point, measure_point_data); + } + gchar ** strarray = g_strsplit(measure_point_data, ",", 2); + double newx, newy; + unsigned int success = sp_svg_number_read_d(strarray[0], &newx); + success += sp_svg_number_read_d(strarray[1], &newy); + g_strfreev (strarray); + if (success == 2) { + Geom::Point point_data(newx, newy); + return point_data; + } + return Geom::Point(Geom::infinity(),Geom::infinity()); + +} + +void MeasureTool::writeMeasurePoint(Geom::Point point, bool is_start) { + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + SPNamedView *namedview = desktop->namedview; + if(!namedview) { + return; + } + std::stringstream meassure_point_str; + meassure_point_str.imbue(std::locale::classic()); + meassure_point_str << point[Geom::X] << "," << point[Geom::Y]; + gchar const *measure_point = is_start ? "inkscape:measure-start" : "inkscape:measure-end"; + namedview->setAttribute (measure_point, meassure_point_str.str().c_str()); +} + +//This function is used to reverse the Measure, I do it in two steps because when move the knot the +//start_ or the end_p are overwrite so I need the original values. +void MeasureTool::reverseKnots() +{ + Geom::Point start = start_p; + Geom::Point end = end_p; + this->knot_start->moveto(end); + this->knot_start->show(); + this->knot_end->moveto(start); + this->knot_end->show(); + start_p = end; + end_p = start; + this->showCanvasItems(); +} + +void MeasureTool::knotStartMovedHandler(SPKnot */*knot*/, Geom::Point const &ppointer, guint state) +{ + Geom::Point point = this->knot_start->position(); + if (state & GDK_CONTROL_MASK) { + spdc_endpoint_snap_rotation(this, point, end_p, state); + } else if (!(state & GDK_SHIFT_MASK)) { + SnapManager &snap_manager = desktop->namedview->snap_manager; + snap_manager.setup(desktop); + Inkscape::SnapCandidatePoint scp(point, Inkscape::SNAPSOURCE_OTHER_HANDLE); + scp.addOrigin(this->knot_end->position()); + Inkscape::SnappedPoint sp = snap_manager.freeSnap(scp); + point = sp.getPoint(); + snap_manager.unSetup(); + } + if(start_p != point) { + start_p = point; + this->knot_start->moveto(start_p); + } + showCanvasItems(); +} + +void MeasureTool::knotEndMovedHandler(SPKnot */*knot*/, Geom::Point const &ppointer, guint state) +{ + Geom::Point point = this->knot_end->position(); + if (state & GDK_CONTROL_MASK) { + spdc_endpoint_snap_rotation(this, point, start_p, state); + } else if (!(state & GDK_SHIFT_MASK)) { + SnapManager &snap_manager = desktop->namedview->snap_manager; + snap_manager.setup(desktop); + Inkscape::SnapCandidatePoint scp(point, Inkscape::SNAPSOURCE_OTHER_HANDLE); + scp.addOrigin(this->knot_start->position()); + Inkscape::SnappedPoint sp = snap_manager.freeSnap(scp); + point = sp.getPoint(); + snap_manager.unSetup(); + } + if(end_p != point) { + end_p = point; + this->knot_end->moveto(end_p); + } + showCanvasItems(); +} + +void MeasureTool::knotUngrabbedHandler(SPKnot */*knot*/, unsigned int state) +{ + this->knot_start->moveto(start_p); + this->knot_end->moveto(end_p); + showCanvasItems(); +} + + + +void MeasureTool::finish() +{ this->enableGrDrag(false); if (this->grabbed) { @@ -247,498 +500,773 @@ void MeasureTool::finish() { ToolBase::finish(); } -//void MeasureTool::setup() { -// ToolBase* ec = this; -// -//// if (SP_EVENT_CONTEXT_CLASS(sp_measure_context_parent_class)->setup) { -//// SP_EVENT_CONTEXT_CLASS(sp_measure_context_parent_class)->setup(ec); -//// } -// ToolBase::setup(); -//} - -//gint MeasureTool::item_handler(SPItem* item, GdkEvent* event) { -// gint ret = FALSE; -// -//// if (SP_EVENT_CONTEXT_CLASS(sp_measure_context_parent_class)->item_handler) { -//// ret = SP_EVENT_CONTEXT_CLASS(sp_measure_context_parent_class)->item_handler(event_context, item, event); -//// } -// ret = ToolBase::item_handler(item, event); -// -// return ret; -//} - static void calculate_intersections(SPDesktop * /*desktop*/, SPItem* item, Geom::PathVector const &lineseg, SPCurve *curve, std::vector<double> &intersections) { - curve->transform(item->i2doc_affine()); // Find all intersections of the control-line with this shape Geom::CrossingSet cs = Geom::crossings(lineseg, curve->get_pathvector()); Geom::delete_duplicates(cs[0]); // Reconstruct and store the points of intersection + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + bool only_visible = prefs->getBool("/tools/measure/only_visible", false); + SPDesktop *desktop = SP_ACTIVE_DESKTOP; for (Geom::Crossings::const_iterator m = cs[0].begin(); m != cs[0].end(); ++m) { -#if 0 -//TODO: consider only visible intersections - Geom::Point intersection = lineseg[0].pointAt((*m).ta); - double eps = 0.0001; - SPDocument* doc = desktop->getDocument(); - if (((*m).ta > eps && - item == doc->getItemAtPoint(desktop->dkey, lineseg[0].pointAt((*m).ta - eps), false, NULL)) || + if(only_visible) { + double eps = 0.0001; + if (((*m).ta > eps && + item == desktop->getItemAtPoint(desktop->d2w(desktop->dt2doc(lineseg[0].pointAt((*m).ta - eps))), true, NULL)) || ((*m).ta + eps < 1 && - item == doc->getItemAtPoint(desktop->dkey, lineseg[0].pointAt((*m).ta + eps), false, NULL)) ) { + item == desktop->getItemAtPoint(desktop->d2w(desktop->dt2doc(lineseg[0].pointAt((*m).ta + eps))), true, NULL))) { + intersections.push_back((*m).ta); + } + } else { intersections.push_back((*m).ta); } -#else - intersections.push_back((*m).ta); - -#endif } } -bool MeasureTool::root_handler(GdkEvent* event) { - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - tolerance = prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100); - +bool MeasureTool::root_handler(GdkEvent* event) +{ gint ret = FALSE; switch (event->type) { - case GDK_BUTTON_PRESS: { - Geom::Point const button_w(event->button.x, event->button.y); - explicitBase = boost::none; - lastEnd = boost::none; - start_point = desktop->w2d(button_w); - - if (event->button.button == 1 && !this->space_panning) { - // save drag origin - xp = static_cast<gint>(event->button.x); - yp = static_cast<gint>(event->button.y); - within_tolerance = true; - - ret = TRUE; - } + case GDK_BUTTON_PRESS: { + this->knot_start->hide(); + this->knot_end->hide(); + Geom::Point const button_w(event->button.x, event->button.y); + explicitBase = boost::none; + last_end = boost::none; + start_p = desktop->w2d(button_w); + + if (event->button.button == 1 && !this->space_panning) { + // save drag origin + start_p = desktop->w2d(Geom::Point(event->button.x, event->button.y)); + within_tolerance = true; + + ret = TRUE; + } - SnapManager &m = desktop->namedview->snap_manager; - m.setup(desktop); - m.freeSnapReturnByRef(start_point, Inkscape::SNAPSOURCE_OTHER_HANDLE); - m.unSetup(); + SnapManager &snap_manager = desktop->namedview->snap_manager; + snap_manager.setup(desktop); + snap_manager.freeSnapReturnByRef(start_p, Inkscape::SNAPSOURCE_OTHER_HANDLE); + snap_manager.unSetup(); - sp_canvas_item_grab(SP_CANVAS_ITEM(desktop->acetate), - GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK, - NULL, event->button.time); - this->grabbed = SP_CANVAS_ITEM(desktop->acetate); - break; - } - case GDK_KEY_PRESS: { - if ((event->key.keyval == GDK_KEY_Shift_L) || (event->key.keyval == GDK_KEY_Shift_R)) { - if (lastEnd) { - explicitBase = lastEnd; - } - } - break; + sp_canvas_item_grab(SP_CANVAS_ITEM(desktop->acetate), + GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK, + NULL, event->button.time); + this->grabbed = SP_CANVAS_ITEM(desktop->acetate); + break; + } + case GDK_KEY_PRESS: { + if ((event->key.keyval == GDK_KEY_Shift_L) || (event->key.keyval == GDK_KEY_Shift_R)) { + explicitBase = end_p; } - case GDK_MOTION_NOTIFY: { - if (!((event->motion.state & GDK_BUTTON1_MASK) && !this->space_panning)) { - if (!(event->motion.state & GDK_SHIFT_MASK)) { - Geom::Point const motion_w(event->motion.x, event->motion.y); - Geom::Point const motion_dt(desktop->w2d(motion_w)); - - SnapManager &m = desktop->namedview->snap_manager; - m.setup(desktop); + break; + } + case GDK_MOTION_NOTIFY: { + if (!(event->motion.state & GDK_BUTTON1_MASK)) { + if(!(event->motion.state & GDK_SHIFT_MASK)) { + Geom::Point const motion_w(event->motion.x, event->motion.y); + Geom::Point const motion_dt(desktop->w2d(motion_w)); - Inkscape::SnapCandidatePoint scp(motion_dt, Inkscape::SNAPSOURCE_OTHER_HANDLE); - scp.addOrigin(start_point); + SnapManager &snap_manager = desktop->namedview->snap_manager; + snap_manager.setup(desktop); - m.preSnap(scp); - m.unSetup(); - } - } else { - ret = TRUE; + Inkscape::SnapCandidatePoint scp(motion_dt, Inkscape::SNAPSOURCE_OTHER_HANDLE); + scp.addOrigin(start_p); - if ( within_tolerance - && ( abs( static_cast<gint>(event->motion.x) - xp ) < tolerance ) - && ( abs( static_cast<gint>(event->motion.y) - yp ) < tolerance ) ) { - break; // do not drag if we're within tolerance from origin - } - // Once the user has moved farther than tolerance from the original location - // (indicating they intend to move the object, not click), then always process the - // motion notify coordinates as given (no snapping back to origin) - within_tolerance = false; - - //clear previous temporary canvas items, we'll draw new ones - for (size_t idx = 0; idx < measure_tmp_items.size(); ++idx) { - desktop->remove_temporary_canvasitem(measure_tmp_items[idx]); + snap_manager.preSnap(scp); + snap_manager.unSetup(); + } + } else { + ret = TRUE; + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + tolerance = prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100); + Geom::Point const motion_w(event->motion.x, event->motion.y); + if ( within_tolerance) { + if ( Geom::LInfty( motion_w - start_p ) < tolerance) { + return FALSE; // Do not drag if we're within tolerance from origin. } - - measure_tmp_items.clear(); - + } + // Once the user has moved farther than tolerance from the original location + // (indicating they intend to move the object, not click), then always process the + // motion notify coordinates as given (no snapping back to origin) + within_tolerance = false; + if(event->motion.time == 0 || !last_end || Geom::LInfty( motion_w - *last_end ) > (tolerance/4.0)) { Geom::Point const motion_w(event->motion.x, event->motion.y); Geom::Point const motion_dt(desktop->w2d(motion_w)); - Geom::Point end_point = motion_dt; + end_p = motion_dt; if (event->motion.state & GDK_CONTROL_MASK) { - spdc_endpoint_snap_rotation(this, end_point, start_point, event->motion.state); - } else { - if (!(event->motion.state & GDK_SHIFT_MASK)) { - SnapManager &m = desktop->namedview->snap_manager; - m.setup(desktop); - Inkscape::SnapCandidatePoint scp(end_point, Inkscape::SNAPSOURCE_OTHER_HANDLE); - scp.addOrigin(start_point); - Inkscape::SnappedPoint sp = m.freeSnap(scp); - end_point = sp.getPoint(); - m.unSetup(); - } - } - - Geom::PathVector lineseg; - Geom::Path p; - p.start(desktop->dt2doc(start_point)); - p.appendNew<Geom::LineSegment>(desktop->dt2doc(end_point)); - lineseg.push_back(p); - - double deltax = end_point[Geom::X] - start_point[Geom::X]; - double deltay = end_point[Geom::Y] - start_point[Geom::Y]; - double angle = atan2(deltay, deltax); - double baseAngle = 0; - - if (explicitBase) { - double deltax2 = explicitBase.get()[Geom::X] - start_point[Geom::X]; - double deltay2 = explicitBase.get()[Geom::Y] - start_point[Geom::Y]; - - baseAngle = atan2(deltay2, deltax2); - angle -= baseAngle; - - if (angle < -M_PI) { - angle += 2 * M_PI; - } else if (angle > M_PI) { - angle -= 2 * M_PI; - } + spdc_endpoint_snap_rotation(this, end_p, start_p, event->motion.state); + } else if (!(event->motion.state & GDK_SHIFT_MASK)) { + SnapManager &snap_manager = desktop->namedview->snap_manager; + snap_manager.setup(desktop); + Inkscape::SnapCandidatePoint scp(end_p, Inkscape::SNAPSOURCE_OTHER_HANDLE); + scp.addOrigin(start_p); + Inkscape::SnappedPoint sp = snap_manager.freeSnap(scp); + end_p = sp.getPoint(); + snap_manager.unSetup(); } + showCanvasItems(); + last_end = motion_w ; + } + gobble_motion_events(GDK_BUTTON1_MASK); + } + break; + } + case GDK_BUTTON_RELEASE: { + this->knot_start->moveto(start_p); + this->knot_start->show(); + if(last_end) { + end_p = desktop->w2d(*last_end); + if (event->button.state & GDK_CONTROL_MASK) { + spdc_endpoint_snap_rotation(this, end_p, start_p, event->motion.state); + } else if (!(event->button.state & GDK_SHIFT_MASK)) { + SnapManager &snap_manager = desktop->namedview->snap_manager; + snap_manager.setup(desktop); + Inkscape::SnapCandidatePoint scp(end_p, Inkscape::SNAPSOURCE_OTHER_HANDLE); + scp.addOrigin(start_p); + Inkscape::SnappedPoint sp = snap_manager.freeSnap(scp); + end_p = sp.getPoint(); + snap_manager.unSetup(); + } + } + this->knot_end->moveto(end_p); + this->knot_end->show(); + showCanvasItems(); -//TODO: calculate NPOINTS -//800 seems to be a good value for 800x600 resolution -#define NPOINTS 800 + if (this->grabbed) { + sp_canvas_item_ungrab(this->grabbed, event->button.time); + this->grabbed = NULL; + } + break; + } + default: + break; + } + if (!ret) { + ret = ToolBase::root_handler(event); + } - std::vector<Geom::Point> points; + return ret; +} - for (double i = 0; i < NPOINTS; i++) { - points.push_back(desktop->d2w(start_point + (i / NPOINTS) * (end_point - start_point))); - } +void MeasureTool::setMarkers() +{ + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + SPDocument *doc = desktop->getDocument(); + SPObject *arrowStart = doc->getObjectById("Arrow2Sstart"); + SPObject *arrowEnd = doc->getObjectById("Arrow2Send"); + if (!arrowStart) { + setMarker(true); + } + if(!arrowEnd) { + setMarker(false); + } +} +void MeasureTool::setMarker(bool isStart) +{ + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + SPDocument *doc = desktop->getDocument(); + SPDefs *defs = doc->getDefs(); + Inkscape::XML::Node *rmarker; + Inkscape::XML::Document *xml_doc = doc->getReprDoc(); + rmarker = xml_doc->createElement("svg:marker"); + rmarker->setAttribute("id", isStart ? "Arrow2Sstart" : "Arrow2Send"); + rmarker->setAttribute("inkscape:isstock", "true"); + rmarker->setAttribute("inkscape:stockid", isStart ? "Arrow2Sstart" : "Arrow2Send"); + rmarker->setAttribute("orient", "auto"); + rmarker->setAttribute("refX", "0.0"); + rmarker->setAttribute("refY", "0.0"); + rmarker->setAttribute("style", "overflow:visible;"); + SPItem *marker = SP_ITEM(defs->appendChildRepr(rmarker)); + Inkscape::GC::release(rmarker); + marker->updateRepr(); + Inkscape::XML::Node *rpath; + rpath = xml_doc->createElement("svg:path"); + rpath->setAttribute("d", "M 8.72,4.03 L -2.21,0.02 L 8.72,-4.00 C 6.97,-1.63 6.98,1.62 8.72,4.03 z"); + rpath->setAttribute("id", isStart ? "Arrow2SstartPath" : "Arrow2SendPath"); + SPCSSAttr *css = sp_repr_css_attr_new(); + sp_repr_css_set_property (css, "stroke", "none"); + sp_repr_css_set_property (css, "fill", "#000000"); + sp_repr_css_set_property (css, "fill-opacity", "1"); + Glib::ustring css_str; + sp_repr_css_write_string(css,css_str); + rpath->setAttribute("style", css_str.c_str()); + sp_repr_css_attr_unref (css); + rpath->setAttribute("transform", isStart ? "scale(0.3) translate(-2.3,0)" : "scale(0.3) rotate(180) translate(-2.3,0)"); + SPItem *path = SP_ITEM(marker->appendChildRepr(rpath)); + Inkscape::GC::release(rpath); + path->updateRepr(); +} - // TODO: Felipe, why don't you simply iterate over all items, and test whether their bounding boxes intersect - // with the measurement line, instead of interpolating over 800 points? E.g. bbox_of_measurement_line.intersects(*bbox_of_item). - // That's also how the object-snapper works, see _findCandidates() in object-snapper.cpp. - - // TODO switch to a different variable name. The single letter 'l' is easy to misread. - - //select elements crossed by line segment: - std::vector<SPItem*> items = desktop->getDocument()->getItemsAtPoints(desktop->dkey, points); - std::vector<double> intersection_times; - for (std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++) { - SPItem *item = *i; - - if (SP_IS_SHAPE(item)) { - calculate_intersections(desktop, item, lineseg, SP_SHAPE(item)->getCurve(), intersection_times); - } else { - if (SP_IS_TEXT(item) || SP_IS_FLOWTEXT(item)) { - Inkscape::Text::Layout::iterator iter = te_get_layout(item)->begin(); - do { - Inkscape::Text::Layout::iterator iter_next = iter; - iter_next.nextGlyph(); // iter_next is one glyph ahead from iter - if (iter == iter_next) { - break; - } - - // get path from iter to iter_next: - SPCurve *curve = te_get_layout(item)->convertToCurves(iter, iter_next); - iter = iter_next; // shift to next glyph - if (!curve) { - continue; // error converting this glyph - } - if (curve->is_empty()) { // whitespace glyph? - curve->unref(); - continue; - } - - curve->transform(item->i2doc_affine()); - - calculate_intersections(desktop, item, lineseg, curve, intersection_times); - - if (iter == te_get_layout(item)->end()) { - break; - } - } while (true); - } - } - } +void MeasureTool::toGuides() +{ + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + if(!desktop || !start_p.isFinite() || !end_p.isFinite() || start_p == end_p) { + return; + } + SPDocument *doc = desktop->getDocument(); + Geom::Point start = desktop->doc2dt(start_p) * desktop->doc2dt(); + Geom::Point end = desktop->doc2dt(end_p) * desktop->doc2dt(); + Geom::Ray ray(start,end); + SPNamedView *namedview = desktop->namedview; + if(!namedview) { + return; + } + setGuide(start,ray.angle(), _("Measure")); + if(explicitBase) { + explicitBase = *explicitBase * SP_ITEM(desktop->currentLayer())->i2doc_affine().inverse(); + ray.setPoints(start, *explicitBase); + if(ray.angle() != 0) { + setGuide(start,ray.angle(), _("Base")); + } + } + setGuide(start,0,""); + setGuide(start,Geom::deg_to_rad(90),_("Start")); + setGuide(end,0,_("End")); + setGuide(end,Geom::deg_to_rad(90),""); + showCanvasItems(true); + doc->ensureUpToDate(); + DocumentUndo::done(desktop->getDocument(), SP_VERB_CONTEXT_MEASURE,_("Add guides from measure tool")); +} - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - if (!prefs->getBool("/tools/measure/ignore_1st_and_last", true)) { - intersection_times.push_back(0); - intersection_times.push_back(1); - } +void MeasureTool::toItem() +{ + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + if(!desktop || !start_p.isFinite() || !end_p.isFinite() || start_p == end_p) { + return; + } + SPDocument *doc = desktop->getDocument(); + Geom::Ray ray(start_p,end_p); + guint32 line_color_primary = 0x0000ff7f; + Inkscape::XML::Document *xml_doc = desktop->doc()->getReprDoc(); + Inkscape::XML::Node *rgroup = xml_doc->createElement("svg:g"); + showCanvasItems(false, true, rgroup); + setLine(start_p,end_p, false, line_color_primary, rgroup); + SPItem *measure_item = SP_ITEM(desktop->currentLayer()->appendChildRepr(rgroup)); + Inkscape::GC::release(rgroup); + measure_item->updateRepr(); + doc->ensureUpToDate(); + DocumentUndo::done(desktop->getDocument(), SP_VERB_CONTEXT_MEASURE,_("Convert measure to items")); + reset(); +} - Glib::ustring unit_name = prefs->getString("/tools/measure/unit"); - if (!unit_name.compare("")) { - unit_name = "px"; - } +void MeasureTool::toMarkDimension() +{ + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + if(!desktop || !start_p.isFinite() || !end_p.isFinite() || start_p == end_p) { + return; + } + SPDocument *doc = desktop->getDocument(); + setMarkers(); + Geom::Ray ray(start_p,end_p); + Geom::Point start = start_p + Geom::Point::polar(ray.angle(), 5); + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + dimension_offset = prefs->getDouble("/tools/measure/offset", 5.0); + start = start + Geom::Point::polar(ray.angle() + Geom::deg_to_rad(90), -dimension_offset); + Geom::Point end = end_p + Geom::Point::polar(ray.angle(), -5); + end = end+ Geom::Point::polar(ray.angle() + Geom::deg_to_rad(90), -dimension_offset); + guint32 color = 0x000000ff; + setLine(start, end, true, color); + Glib::ustring unit_name = prefs->getString("/tools/measure/unit"); + if (!unit_name.compare("")) { + unit_name = "px"; + } + double fontsize = prefs->getDouble("/tools/measure/fontsize", 10.0); + int precision = prefs->getInt("/tools/measure/precision", 2); + std::stringstream precision_str; + precision_str.imbue(std::locale::classic()); + precision_str << "%." << precision << "f %s"; + Geom::Point middle = Geom::middle_point(start, end); + double totallengthval = (end_p - start_p).length(); + totallengthval = Inkscape::Util::Quantity::convert(totallengthval, "px", unit_name); + double scale = prefs->getDouble("/tools/measure/scale", 100.0) / 100.0; + gchar *totallength_str = g_strdup_printf(precision_str.str().c_str(), totallengthval * scale, unit_name.c_str()); + setLabelText(totallength_str, middle, fontsize, Geom::deg_to_rad(180) - ray.angle(), color); + g_free(totallength_str); + doc->ensureUpToDate(); + DocumentUndo::done(desktop->getDocument(), SP_VERB_CONTEXT_MEASURE,_("Add global measure line")); +} - double fontsize = prefs->getInt("/tools/measure/fontsize"); +void MeasureTool::setGuide(Geom::Point origin,double angle, const char *label) +{ + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + SPDocument *doc = desktop->getDocument(); + Inkscape::XML::Document *xml_doc = doc->getReprDoc(); + SPRoot const *root = doc->getRoot(); + Geom::Affine affine(Geom::identity()); + if(root) { + affine *= root->c2p.inverse(); + } + SPNamedView *namedview = desktop->namedview; + if(!namedview) { + return; + } + origin *= affine; + //measure angle + Inkscape::XML::Node *guide; + guide = xml_doc->createElement("sodipodi:guide"); + std::stringstream position; + position.imbue(std::locale::classic()); + position << origin[Geom::X] << "," << origin[Geom::Y]; + guide->setAttribute("position", position.str().c_str() ); + guide->setAttribute("inkscape:color", "rgb(167,0,255)"); + guide->setAttribute("inkscape:label", label); + Geom::Point unit_vector = Geom::rot90(origin.polar(angle)); + std::stringstream angle_str; + angle_str.imbue(std::locale::classic()); + angle_str << unit_vector[Geom::X] << "," << unit_vector[Geom::Y]; + guide->setAttribute("orientation", angle_str.str().c_str()); + namedview->appendChild(guide); + Inkscape::GC::release(guide); +} - // Normal will be used for lines and text - Geom::Point windowNormal = Geom::unit_vector(Geom::rot90(desktop->d2w(end_point - start_point))); - Geom::Point normal = desktop->w2d(windowNormal); +void MeasureTool::setLine(Geom::Point start_point,Geom::Point end_point, bool markers, guint32 color, Inkscape::XML::Node *measure_repr) +{ + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + if(!desktop || !start_p.isFinite() || !end_p.isFinite()) { + return; + } + Geom::PathVector pathv; + Geom::Path path; + path.start(desktop->doc2dt(start_point)); + path.appendNew<Geom::LineSegment>(desktop->doc2dt(end_point)); + pathv.push_back(path); + pathv *= SP_ITEM(desktop->currentLayer())->i2doc_affine().inverse(); + if(!pathv.empty()) { + setMeasureItem(pathv, false, markers, color, measure_repr); + } +} - std::vector<Geom::Point> intersections; - std::sort(intersection_times.begin(), intersection_times.end()); - for (std::vector<double>::iterator iter_t = intersection_times.begin(); iter_t != intersection_times.end(); iter_t++) { - intersections.push_back(lineseg[0].pointAt(*iter_t)); - } +void MeasureTool::setPoint(Geom::Point origin, Inkscape::XML::Node *measure_repr) +{ + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + if(!desktop || !origin.isFinite()) { + return; + } + char const * svgd; + svgd = "m 0.707,0.707 6.586,6.586 m 0,-6.586 -6.586,6.586"; + Geom::PathVector pathv = sp_svg_read_pathv(svgd); + Geom::Scale scale = Geom::Scale(desktop->current_zoom()).inverse(); + pathv *= Geom::Translate(Geom::Point(-3.5,-3.5)); + pathv *= scale; + pathv *= Geom::Translate(Geom::Point() - (scale.vector() * 0.5)); + pathv *= Geom::Translate(desktop->doc2dt(origin)); + pathv *= SP_ITEM(desktop->currentLayer())->i2doc_affine().inverse(); + if (!pathv.empty()) { + guint32 line_color_secondary = 0xff0000ff; + setMeasureItem(pathv, false, false, line_color_secondary, measure_repr); + } +} - std::vector<LabelPlacement> placements; - for (size_t idx = 1; idx < intersections.size(); ++idx) { - LabelPlacement placement; - placement.lengthVal = (intersections[idx] - intersections[idx - 1]).length(); - placement.lengthVal = Inkscape::Util::Quantity::convert(placement.lengthVal, "px", unit_name); - placement.offset = DIMENSION_OFFSET; - placement.start = desktop->doc2dt( (intersections[idx - 1] + intersections[idx]) / 2 ); - placement.end = placement.start - (normal * placement.offset); +void MeasureTool::setLabelText(const char *value, Geom::Point pos, double fontsize, Geom::Coord angle, guint32 background, Inkscape::XML::Node *measure_repr, CanvasTextAnchorPositionEnum text_anchor) +{ + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + Inkscape::XML::Document *xml_doc = desktop->doc()->getReprDoc(); + /* Create <text> */ + pos = desktop->doc2dt(pos); + Inkscape::XML::Node *rtext = xml_doc->createElement("svg:text"); + rtext->setAttribute("xml:space", "preserve"); + + + /* Set style */ + sp_desktop_apply_style_tool(desktop, rtext, "/tools/text", true); + if(measure_repr) { + sp_repr_set_svg_double(rtext, "x", 2); + sp_repr_set_svg_double(rtext, "y", 2); + } else { + sp_repr_set_svg_double(rtext, "x", 0); + sp_repr_set_svg_double(rtext, "y", 0); + } - placements.push_back(placement); - } + /* Create <tspan> */ + Inkscape::XML::Node *rtspan = xml_doc->createElement("svg:tspan"); + rtspan->setAttribute("sodipodi:role", "line"); + SPCSSAttr *css = sp_repr_css_attr_new(); + std::stringstream font_size; + font_size.imbue(std::locale::classic()); + if(measure_repr) { + font_size << fontsize; + } else { + font_size << fontsize << "pt"; + } + sp_repr_css_set_property (css, "font-size", font_size.str().c_str()); + sp_repr_css_set_property (css, "font-style", "normal"); + sp_repr_css_set_property (css, "font-weight", "normal"); + sp_repr_css_set_property (css, "line-height", "125%"); + sp_repr_css_set_property (css, "letter-spacing", "0"); + sp_repr_css_set_property (css, "word-spacing", "0"); + sp_repr_css_set_property (css, "text-align", "center"); + sp_repr_css_set_property (css, "text-anchor", "middle"); + if(measure_repr) { + sp_repr_css_set_property (css, "fill", "#FFFFFF"); + } else { + sp_repr_css_set_property (css, "fill", "#000000"); + } + sp_repr_css_set_property (css, "fill-opacity", "1"); + sp_repr_css_set_property (css, "stroke", "none"); + Glib::ustring css_str; + sp_repr_css_write_string(css,css_str); + rtspan->setAttribute("style", css_str.c_str()); + sp_repr_css_attr_unref (css); + rtext->addChild(rtspan, NULL); + Inkscape::GC::release(rtspan); + /* Create TEXT */ + Inkscape::XML::Node *rstring = xml_doc->createTextNode(value); + rtspan->addChild(rstring, NULL); + Inkscape::GC::release(rstring); + SPItem *text_item = SP_ITEM(desktop->currentLayer()->appendChildRepr(rtext)); + Inkscape::GC::release(rtext); + text_item->updateRepr(); + Geom::OptRect bbox = text_item->geometricBounds(); + if (!measure_repr && bbox) { + Geom::Point center = bbox->midpoint(); + text_item->transform *= Geom::Translate(center).inverse(); + pos += Geom::Point::polar(angle+ Geom::deg_to_rad(90), -bbox->height()); + } + if(measure_repr) { + /* Create <group> */ + Inkscape::XML::Node *rgroup = xml_doc->createElement("svg:g"); + /* Create <rect> */ + Inkscape::XML::Node *rrect = xml_doc->createElement("svg:rect"); + SPCSSAttr *css = sp_repr_css_attr_new (); + gchar color_line[64]; + sp_svg_write_color (color_line, sizeof(color_line), background); + sp_repr_css_set_property (css, "fill", color_line); + sp_repr_css_set_property (css, "fill-opacity", "0.5"); + sp_repr_css_set_property (css, "stroke-width", "0"); + Glib::ustring css_str; + sp_repr_css_write_string(css,css_str); + rrect->setAttribute("style", css_str.c_str()); + sp_repr_css_attr_unref (css); + sp_repr_set_svg_double(rgroup, "x", 0); + sp_repr_set_svg_double(rgroup, "y", 0); + sp_repr_set_svg_double(rrect, "x", -bbox->width()/2.0); + sp_repr_set_svg_double(rrect, "y", -bbox->height()); + sp_repr_set_svg_double(rrect, "width", bbox->width() + 6); + sp_repr_set_svg_double(rrect, "height", bbox->height() + 6); + Inkscape::XML::Node *rtextitem = text_item->getRepr(); + text_item->deleteObject(); + rgroup->addChild(rtextitem, NULL); + Inkscape::GC::release(rtextitem); + rgroup->addChild(rrect, NULL); + Inkscape::GC::release(rrect); + SPItem *text_item_box = SP_ITEM(desktop->currentLayer()->appendChildRepr(rgroup)); + Geom::Scale scale = Geom::Scale(desktop->current_zoom()).inverse(); + if(bbox && text_anchor == TEXT_ANCHOR_CENTER) { + text_item_box->transform *= Geom::Translate(bbox->midpoint() - Geom::Point(1.0,1.0)).inverse(); + } + text_item_box->transform *= scale; + text_item_box->transform *= Geom::Translate(Geom::Point() - (scale.vector() * 0.5)); + text_item_box->transform *= Geom::Translate(pos); + text_item_box->transform *= SP_ITEM(desktop->currentLayer())->i2doc_affine().inverse(); + text_item_box->updateRepr(); + text_item_box->doWriteTransform(text_item_box->getRepr(), text_item_box->transform, NULL, true); + Inkscape::XML::Node *rlabel = text_item_box->getRepr(); + text_item_box->deleteObject(); + measure_repr->addChild(rlabel, NULL); + Inkscape::GC::release(rlabel); + } else { + text_item->transform *= Geom::Rotate(angle); + text_item->transform *= Geom::Translate(pos); + text_item->transform *= SP_ITEM(desktop->currentLayer())->i2doc_affine().inverse(); + text_item->doWriteTransform(text_item->getRepr(), text_item->transform, NULL, true); + } +} - // Adjust positions - repositionOverlappingLabels(placements, desktop, windowNormal, fontsize); - - for (std::vector<LabelPlacement>::iterator it = placements.begin(); it != placements.end(); ++it) - { - LabelPlacement &place = *it; - - // TODO cleanup memory, Glib::ustring, etc.: - gchar *measure_str = g_strdup_printf("%.2f %s", place.lengthVal, unit_name.c_str()); - SPCanvasText *canvas_tooltip = sp_canvastext_new(desktop->getTempGroup(), - desktop, - place.end, - measure_str); - sp_canvastext_set_fontsize(canvas_tooltip, fontsize); - canvas_tooltip->rgba = 0xffffffff; - canvas_tooltip->rgba_background = 0x0000007f; - canvas_tooltip->outline = false; - canvas_tooltip->background = true; - canvas_tooltip->anchor_position = TEXT_ANCHOR_CENTER; - - measure_tmp_items.push_back(desktop->add_temporary_canvasitem(canvas_tooltip, 0)); - g_free(measure_str); - } +void MeasureTool::reset() +{ + this->knot_start->hide(); + this->knot_end->hide(); + for (size_t idx = 0; idx < measure_tmp_items.size(); ++idx) { + desktop->remove_temporary_canvasitem(measure_tmp_items[idx]); + } + measure_tmp_items.clear(); +} - Geom::Point angleDisplayPt = calcAngleDisplayAnchor(desktop, angle, baseAngle, - start_point, end_point, - fontsize); - - { - // TODO cleanup memory, Glib::ustring, etc.: - gchar *angle_str = g_strdup_printf("%.2f °", angle * 180/M_PI); - - SPCanvasText *canvas_tooltip = sp_canvastext_new(desktop->getTempGroup(), - desktop, - angleDisplayPt, - angle_str); - sp_canvastext_set_fontsize(canvas_tooltip, fontsize); - canvas_tooltip->rgba = 0xffffffff; - canvas_tooltip->rgba_background = 0x337f337f; - canvas_tooltip->outline = false; - canvas_tooltip->background = true; - canvas_tooltip->anchor_position = TEXT_ANCHOR_CENTER; - - measure_tmp_items.push_back(desktop->add_temporary_canvasitem(canvas_tooltip, 0)); - g_free(angle_str); - } +void MeasureTool::setMeasureCanvasText(bool is_angle, double precision, double amount, double fontsize, Glib::ustring unit_name, Geom::Point position, guint32 background, CanvasTextAnchorPositionEnum text_anchor, bool to_item, Inkscape::XML::Node *measure_repr) +{ + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + std::stringstream precision_str; + precision_str.imbue(std::locale::classic()); + if(is_angle){ + precision_str << "%." << precision << "f °"; + } else { + precision_str << "%." << precision << "f %s"; + } + gchar *measure_str = g_strdup_printf(precision_str.str().c_str(), amount, unit_name.c_str()); + SPCanvasText *canvas_tooltip = sp_canvastext_new(desktop->getTempGroup(), + desktop, + position, + measure_str); + sp_canvastext_set_fontsize(canvas_tooltip, fontsize); + canvas_tooltip->rgba = 0xffffffff; + canvas_tooltip->rgba_background = background; + canvas_tooltip->outline = false; + canvas_tooltip->background = true; + canvas_tooltip->anchor_position = text_anchor; + measure_tmp_items.push_back(desktop->add_temporary_canvasitem(canvas_tooltip, 0)); + if(to_item) { + setLabelText(measure_str, position, fontsize, 0, background, measure_repr); + } + g_free(measure_str); +} - { - double totallengthval = (end_point - start_point).length(); - totallengthval = Inkscape::Util::Quantity::convert(totallengthval, "px", unit_name); - - // TODO cleanup memory, Glib::ustring, etc.: - gchar *totallength_str = g_strdup_printf("%.2f %s", totallengthval, unit_name.c_str()); - SPCanvasText *canvas_tooltip = sp_canvastext_new(desktop->getTempGroup(), - desktop, - end_point + desktop->w2d(Geom::Point(3*fontsize, -fontsize)), - totallength_str); - sp_canvastext_set_fontsize(canvas_tooltip, fontsize); - canvas_tooltip->rgba = 0xffffffff; - canvas_tooltip->rgba_background = 0x3333337f; - canvas_tooltip->outline = false; - canvas_tooltip->background = true; - canvas_tooltip->anchor_position = TEXT_ANCHOR_LEFT; - - measure_tmp_items.push_back(desktop->add_temporary_canvasitem(canvas_tooltip, 0)); - g_free(totallength_str); - } +void MeasureTool::setMeasureCanvasItem(Geom::Point position, bool to_item, Inkscape::XML::Node *measure_repr){ + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + SPCanvasItem * canvasitem = sp_canvas_item_new(desktop->getTempGroup(), + SP_TYPE_CTRL, + "anchor", SP_ANCHOR_CENTER, + "size", 8.0, + "stroked", TRUE, + "stroke_color", 0xff0000ff, + "mode", SP_KNOT_MODE_XOR, + "shape", SP_KNOT_SHAPE_CROSS, + NULL ); + + SP_CTRL(canvasitem)->moveto(position); + measure_tmp_items.push_back(desktop->add_temporary_canvasitem(canvasitem, 0)); + if(to_item) { + setPoint(position, measure_repr); + } +} - if (intersections.size() > 2) { - double totallengthval = (intersections[intersections.size()-1] - intersections[0]).length(); - totallengthval = Inkscape::Util::Quantity::convert(totallengthval, "px", unit_name); - - // TODO cleanup memory, Glib::ustring, etc.: - gchar *total_str = g_strdup_printf("%.2f %s", totallengthval, unit_name.c_str()); - SPCanvasText *canvas_tooltip = sp_canvastext_new(desktop->getTempGroup(), - desktop, - desktop->doc2dt((intersections[0] + intersections[intersections.size()-1])/2) + normal * 60, - total_str); - sp_canvastext_set_fontsize(canvas_tooltip, fontsize); - canvas_tooltip->rgba = 0xffffffff; - canvas_tooltip->rgba_background = 0x33337f7f; - canvas_tooltip->outline = false; - canvas_tooltip->background = true; - canvas_tooltip->anchor_position = TEXT_ANCHOR_CENTER; - - measure_tmp_items.push_back(desktop->add_temporary_canvasitem(canvas_tooltip, 0)); - g_free(total_str); - } +void MeasureTool::setMeasureCanvasControlLine(Geom::Point start, Geom::Point end, bool to_item, Inkscape::CtrlLineType ctrl_line_type, Inkscape::XML::Node *measure_repr){ + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + SPCtrlLine *control_line = ControlManager::getManager().createControlLine(desktop->getTempGroup(), + start, + end, + ctrl_line_type); + measure_tmp_items.push_back(desktop->add_temporary_canvasitem(control_line, 0)); + gint32 color = ctrl_line_type == CTLINE_PRIMARY ? 0x0000ff7f : 0xff00007f; + if(to_item) { + setLine(start, + end, + false, + color, + measure_repr); + } +} - // Now that text has been added, we can add lines and controls so that they go underneath - - for (size_t idx = 0; idx < intersections.size(); ++idx) { - // Display the intersection indicator (i.e. the cross) - SPCanvasItem * canvasitem = sp_canvas_item_new(desktop->getTempGroup(), - SP_TYPE_CTRL, - "anchor", SP_ANCHOR_CENTER, - "size", 8.0, - "stroked", TRUE, - "stroke_color", 0xff0000ff, - "mode", SP_KNOT_MODE_XOR, - "shape", SP_KNOT_SHAPE_CROSS, - NULL ); - - SP_CTRL(canvasitem)->moveto(desktop->doc2dt(intersections[idx])); - measure_tmp_items.push_back(desktop->add_temporary_canvasitem(canvasitem, 0)); - } +void MeasureTool::showCanvasItems(bool to_guides, bool to_item, Inkscape::XML::Node *measure_repr) +{ + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + if(!desktop || !start_p.isFinite() || !end_p.isFinite() || start_p == end_p) { + return; + } + writeMeasurePoint(start_p, true); + writeMeasurePoint(end_p, false); + //clear previous temporary canvas items, we'll draw new ones + for (size_t idx = 0; idx < measure_tmp_items.size(); ++idx) { + desktop->remove_temporary_canvasitem(measure_tmp_items[idx]); + } + measure_tmp_items.clear(); + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + bool show_in_between = prefs->getBool("/tools/measure/show_in_between", true); + bool all_layers = prefs->getBool("/tools/measure/all_layers", true); + dimension_offset = 70; + Geom::PathVector lineseg; + Geom::Path p; + p.start(desktop->dt2doc(start_p)); + p.appendNew<Geom::LineSegment>(desktop->dt2doc(end_p)); + lineseg.push_back(p); + + double angle = atan2(end_p - start_p); + double baseAngle = 0; + + if (explicitBase) { + baseAngle = atan2(explicitBase.get() - start_p); + angle -= baseAngle; + } - // Since adding goes to the bottom, do all lines last. - - // draw main control line - { - SPCtrlLine *control_line = ControlManager::getManager().createControlLine(desktop->getTempGroup(), - start_point, - end_point); - measure_tmp_items.push_back(desktop->add_temporary_canvasitem(control_line, 0)); - - if ((end_point[Geom::X] != start_point[Geom::X]) && (end_point[Geom::Y] != start_point[Geom::Y])) { - double length = std::abs((end_point - start_point).length()); - Geom::Point anchorEnd = start_point; - anchorEnd[Geom::X] += length; - if (explicitBase) { - anchorEnd *= (Geom::Affine(Geom::Translate(-start_point)) - * Geom::Affine(Geom::Rotate(baseAngle)) - * Geom::Affine(Geom::Translate(start_point))); - } - - SPCtrlLine *control_line = ControlManager::getManager().createControlLine(desktop->getTempGroup(), - start_point, - anchorEnd, - CTLINE_SECONDARY); - measure_tmp_items.push_back(desktop->add_temporary_canvasitem(control_line, 0)); - - createAngleDisplayCurve(desktop, start_point, end_point, angleDisplayPt, angle); + std::vector<SPItem*> items; + Inkscape::Rubberband *r = Inkscape::Rubberband::get(desktop); + r->setMode(RUBBERBAND_MODE_TOUCHPATH); + if(!show_in_between) { + r->start(desktop,start_p); + r->move(end_p); + items = desktop->getDocument()->getItemsAtPoints(desktop->dkey, r->getPoints(), all_layers, 2); + r->stop(); + r->setMode(RUBBERBAND_MODE_TOUCHPATH); + r->start(desktop,end_p); + r->move(start_p); + std::vector<SPItem*> items_reverse = desktop->getDocument()->getItemsAtPoints(desktop->dkey, r->getPoints(), all_layers, 2); + r->stop(); + if(items_reverse.size() == 2 && items_reverse[1] != items[0] && items_reverse[1] != items[1]) { + items.push_back(items_reverse[1]); + } + if(items_reverse.size() >= 1 && items_reverse[0] != items[1]) { + items.push_back(items_reverse[0]); + } + } else { + r->start(desktop,start_p); + r->move(end_p); + items = desktop->getDocument()->getItemsAtPoints(desktop->dkey, r->getPoints(), all_layers); + r->stop(); + } + std::vector<double> intersection_times; + for (std::vector<SPItem*>::const_iterator i=items.begin(); i!=items.end(); ++i) { + SPItem *item = *i; + if (SP_IS_SHAPE(item)) { + calculate_intersections(desktop, item, lineseg, SP_SHAPE(item)->getCurve(), intersection_times); + } else { + if (SP_IS_TEXT(item) || SP_IS_FLOWTEXT(item)) { + Inkscape::Text::Layout::iterator iter = te_get_layout(item)->begin(); + do { + Inkscape::Text::Layout::iterator iter_next = iter; + iter_next.nextGlyph(); // iter_next is one glyph ahead from iter + if (iter == iter_next) { + break; } - } - - if (intersections.size() > 2) { - ControlManager &mgr = ControlManager::getManager(); - SPCtrlLine *control_line = 0; - control_line = mgr.createControlLine(desktop->getTempGroup(), - desktop->doc2dt(intersections[0]) + normal * 60, - desktop->doc2dt(intersections[intersections.size() - 1]) + normal * 60); - measure_tmp_items.push_back(desktop->add_temporary_canvasitem(control_line, 0)); - - control_line = mgr.createControlLine(desktop->getTempGroup(), - desktop->doc2dt(intersections[0]), - desktop->doc2dt(intersections[0]) + normal * 65); - measure_tmp_items.push_back(desktop->add_temporary_canvasitem(control_line, 0)); - - control_line = mgr.createControlLine(desktop->getTempGroup(), - desktop->doc2dt(intersections[intersections.size() - 1]), - desktop->doc2dt(intersections[intersections.size() - 1]) + normal * 65); - measure_tmp_items.push_back(desktop->add_temporary_canvasitem(control_line, 0)); - } - // call-out lines - for (std::vector<LabelPlacement>::iterator it = placements.begin(); it != placements.end(); ++it) - { - LabelPlacement &place = *it; - - ControlManager &mgr = ControlManager::getManager(); - SPCtrlLine *control_line = mgr.createControlLine(desktop->getTempGroup(), - place.start, - place.end, - CTLINE_SECONDARY); - measure_tmp_items.push_back(desktop->add_temporary_canvasitem(control_line, 0)); - } + // get path from iter to iter_next: + SPCurve *curve = te_get_layout(item)->convertToCurves(iter, iter_next); + iter = iter_next; // shift to next glyph + if (!curve) { + continue; // error converting this glyph + } + if (curve->is_empty()) { // whitespace glyph? + curve->unref(); + continue; + } - { - for (size_t idx = 1; idx < intersections.size(); ++idx) { - Geom::Point measure_text_pos = (intersections[idx - 1] + intersections[idx]) / 2; + curve->transform(item->i2doc_affine()); - ControlManager &mgr = ControlManager::getManager(); - SPCtrlLine *control_line = mgr.createControlLine(desktop->getTempGroup(), - desktop->doc2dt(measure_text_pos), - desktop->doc2dt(measure_text_pos) - (normal * DIMENSION_OFFSET), - CTLINE_SECONDARY); - measure_tmp_items.push_back(desktop->add_temporary_canvasitem(control_line, 0)); + calculate_intersections(desktop, item, lineseg, curve, intersection_times); + if (iter == te_get_layout(item)->end()) { + break; } - } + } while (true); + } + } + } + Glib::ustring unit_name = prefs->getString("/tools/measure/unit"); + if (!unit_name.compare("")) { + unit_name = "px"; + } + double scale = prefs->getDouble("/tools/measure/scale", 100.0) / 100.0; + double fontsize = prefs->getDouble("/tools/measure/fontsize", 10.0); + // Normal will be used for lines and text + Geom::Point windowNormal = Geom::unit_vector(Geom::rot90(desktop->d2w(end_p - start_p))); + Geom::Point normal = desktop->w2d(windowNormal); + + std::vector<Geom::Point> intersections; + std::sort(intersection_times.begin(), intersection_times.end()); + for (std::vector<double>::iterator iter_t = intersection_times.begin(); iter_t != intersection_times.end(); ++iter_t) { + if(show_in_between) { + intersections.push_back(lineseg[0].pointAt(*iter_t)); + } + } + if(!show_in_between && intersection_times.size() > 1) { + intersections.push_back(lineseg[0].pointAt(intersection_times[0])); + intersections.push_back(lineseg[0].pointAt(intersection_times[intersection_times.size()-1])); + } + if (!prefs->getBool("/tools/measure/ignore_1st_and_last", true)) { + intersections.insert(intersections.begin(),lineseg[0].pointAt(0)); + intersections.push_back(lineseg[0].pointAt(1)); + } + std::vector<LabelPlacement> placements; + for (size_t idx = 1; idx < intersections.size(); ++idx) { + LabelPlacement placement; + placement.lengthVal = (intersections[idx] - intersections[idx - 1]).length(); + placement.lengthVal = Inkscape::Util::Quantity::convert(placement.lengthVal, "px", unit_name); + placement.offset = dimension_offset / 2; + placement.start = desktop->doc2dt( (intersections[idx - 1] + intersections[idx]) / 2 ); + placement.end = placement.start - (normal * placement.offset); + + placements.push_back(placement); + } + int precision = prefs->getInt("/tools/measure/precision", 2); + // Adjust positions + repositionOverlappingLabels(placements, desktop, windowNormal, fontsize, precision); + for (std::vector<LabelPlacement>::iterator it = placements.begin(); it != placements.end(); ++it) { + LabelPlacement &place = *it; + setMeasureCanvasText(false, precision, place.lengthVal * scale, fontsize, unit_name, place.end, 0x0000007f, TEXT_ANCHOR_CENTER, to_item, measure_repr); + } + Geom::Point angleDisplayPt = calcAngleDisplayAnchor(desktop, angle, baseAngle, + start_p, end_p, + fontsize); + { + setMeasureCanvasText(true, precision, Geom::rad_to_deg(angle), fontsize, unit_name, angleDisplayPt, 0x337f337f, TEXT_ANCHOR_CENTER, to_item, measure_repr); + } - // Initial point - { - SPCanvasItem * canvasitem = sp_canvas_item_new(desktop->getTempGroup(), - SP_TYPE_CTRL, - "anchor", SP_ANCHOR_CENTER, - "size", 8.0, - "stroked", TRUE, - "stroke_color", 0xff0000ff, - "mode", SP_KNOT_MODE_XOR, - "shape", SP_KNOT_SHAPE_CROSS, - NULL ); - - SP_CTRL(canvasitem)->moveto(start_point); - measure_tmp_items.push_back(desktop->add_temporary_canvasitem(canvasitem, 0)); - } + { + double totallengthval = (end_p - start_p).length(); + totallengthval = Inkscape::Util::Quantity::convert(totallengthval, "px", unit_name); + Geom::Point origin = end_p + desktop->w2d(Geom::Point(3*fontsize, -fontsize)); + setMeasureCanvasText(false, precision, totallengthval * scale, fontsize, unit_name, origin, 0x3333337f, TEXT_ANCHOR_LEFT, to_item, measure_repr); + } - lastEnd = end_point; // track in case we get a anchoring key-press later + if (intersections.size() > 2) { + double totallengthval = (intersections[intersections.size()-1] - intersections[0]).length(); + totallengthval = Inkscape::Util::Quantity::convert(totallengthval, "px", unit_name); + Geom::Point origin = desktop->doc2dt((intersections[0] + intersections[intersections.size()-1])/2) + normal * dimension_offset; + setMeasureCanvasText(false, precision, totallengthval * scale, fontsize, unit_name, origin, 0x33337f7f, TEXT_ANCHOR_CENTER, to_item, measure_repr); + } + + // Initial point + { + setMeasureCanvasItem(start_p, false, measure_repr); + } - gobble_motion_events(GDK_BUTTON1_MASK); + // Now that text has been added, we can add lines and controls so that they go underneath + for (size_t idx = 0; idx < intersections.size(); ++idx) { + setMeasureCanvasItem(desktop->doc2dt(intersections[idx]), to_item, measure_repr); + if(to_guides) { + gchar *cross_number; + if (!prefs->getBool("/tools/measure/ignore_1st_and_last", true)) { + cross_number= g_strdup_printf(_("Crossing %d"), idx); + } else { + cross_number= g_strdup_printf(_("Crossing %d"), idx + 1); } - break; - } - case GDK_BUTTON_RELEASE: { - sp_event_context_discard_delayed_snap_event(this); - explicitBase = boost::none; - lastEnd = boost::none; - - //clear all temporary canvas items related to the measurement tool. - for (size_t idx = 0; idx < measure_tmp_items.size(); ++idx) { - desktop->remove_temporary_canvasitem(measure_tmp_items[idx]); + if (!prefs->getBool("/tools/measure/ignore_1st_and_last", true) && idx == 0) { + setGuide(desktop->doc2dt(intersections[idx]), angle + Geom::deg_to_rad(90), ""); + } else { + setGuide(desktop->doc2dt(intersections[idx]), angle + Geom::deg_to_rad(90), cross_number); } + g_free(cross_number); + } + } + // Since adding goes to the bottom, do all lines last. - measure_tmp_items.clear(); + // draw main control line + { + setMeasureCanvasControlLine(start_p, end_p, false, CTLINE_PRIMARY, measure_repr); + double length = std::abs((end_p - start_p).length()); + Geom::Point anchorEnd = start_p; + anchorEnd[Geom::X] += length; + if (explicitBase) { + anchorEnd *= (Geom::Affine(Geom::Translate(-start_p)) + * Geom::Affine(Geom::Rotate(baseAngle)) + * Geom::Affine(Geom::Translate(start_p))); + } + setMeasureCanvasControlLine(start_p, anchorEnd, to_item, CTLINE_SECONDARY, measure_repr); + createAngleDisplayCurve(desktop, start_p, end_p, angleDisplayPt, angle, measure_repr); + } - if (this->grabbed) { - sp_canvas_item_ungrab(this->grabbed, event->button.time); - this->grabbed = NULL; - } + if (intersections.size() > 2) { + setMeasureCanvasControlLine(desktop->doc2dt(intersections[0]) + normal * dimension_offset, desktop->doc2dt(intersections[intersections.size() - 1]) + normal * dimension_offset, to_item, CTLINE_PRIMARY , measure_repr); + + setMeasureCanvasControlLine(desktop->doc2dt(intersections[0]), desktop->doc2dt(intersections[0]) + normal * dimension_offset, to_item, CTLINE_PRIMARY , measure_repr); - xp = 0; - yp = 0; - break; - } - default: - break; + setMeasureCanvasControlLine(desktop->doc2dt(intersections[intersections.size() - 1]), desktop->doc2dt(intersections[intersections.size() - 1]) + normal * dimension_offset, to_item, CTLINE_PRIMARY , measure_repr); } - if (!ret) { - ret = ToolBase::root_handler(event); + // call-out lines + for (std::vector<LabelPlacement>::iterator it = placements.begin(); it != placements.end(); ++it) { + LabelPlacement &place = *it; + setMeasureCanvasControlLine(place.start, place.end, to_item, CTLINE_SECONDARY, measure_repr); } - return ret; + { + for (size_t idx = 1; idx < intersections.size(); ++idx) { + Geom::Point measure_text_pos = (intersections[idx - 1] + intersections[idx]) / 2; + setMeasureCanvasControlLine(desktop->doc2dt(measure_text_pos), desktop->doc2dt(measure_text_pos) - (normal * dimension_offset / 2), to_item, CTLINE_SECONDARY, measure_repr); + } + } } } diff --git a/src/ui/tools/measure-tool.h b/src/ui/tools/measure-tool.h index 9701ba6ea..3bdc9b9c4 100644 --- a/src/ui/tools/measure-tool.h +++ b/src/ui/tools/measure-tool.h @@ -6,41 +6,72 @@ * * Authors: * Felipe Correa da Silva Sanches <juca@members.fsf.org> - * + * Jabiertxo Arraiza <jabier.arraiza@marker.es> * Copyright (C) 2011 Authors * * Released under GNU GPL, read the file 'COPYING' for more information */ - +#include <stddef.h> +#include <sigc++/sigc++.h> #include "ui/tools/tool-base.h" #include <2geom/point.h> +#include "display/canvas-text.h" +#include "ui/control-manager.h" #include <boost/optional.hpp> #define SP_MEASURE_CONTEXT(obj) (dynamic_cast<Inkscape::UI::Tools::MeasureTool*>((Inkscape::UI::Tools::ToolBase*)obj)) #define SP_IS_MEASURE_CONTEXT(obj) (dynamic_cast<const Inkscape::UI::Tools::MeasureTool*>((const Inkscape::UI::Tools::ToolBase*)obj) != NULL) +class SPKnot; + namespace Inkscape { namespace UI { namespace Tools { class MeasureTool : public ToolBase { public: - MeasureTool(); - virtual ~MeasureTool(); - - static const std::string prefsPath; + MeasureTool(); + virtual ~MeasureTool(); - virtual void finish(); - virtual bool root_handler(GdkEvent* event); + static const std::string prefsPath; - virtual const std::string& getPrefsPath(); + virtual void finish(); + virtual bool root_handler(GdkEvent* event); + virtual void showCanvasItems(bool to_guides = false, bool to_item = false, Inkscape::XML::Node *measure_repr = NULL); + virtual void reverseKnots(); + virtual void toGuides(); + virtual void toMarkDimension(); + virtual void toItem(); + virtual void reset(); + virtual void setMarkers(); + virtual void setMarker(bool isStart); + virtual const std::string& getPrefsPath(); + Geom::Point readMeasurePoint(bool is_start); + void writeMeasurePoint(Geom::Point point, bool is_start); + void setGuide(Geom::Point origin, double angle, const char *label); + void setPoint(Geom::Point origin, Inkscape::XML::Node *measure_repr); + void setLine(Geom::Point start_point,Geom::Point end_point, bool markers, guint32 color, Inkscape::XML::Node *measure_repr = NULL); + void setMeasureCanvasText(bool is_angle, double precision, double amount, double fontsize, Glib::ustring unit_name, Geom::Point position, guint32 background, CanvasTextAnchorPositionEnum text_anchor, bool to_item, Inkscape::XML::Node *measure_repr); + void setMeasureCanvasItem(Geom::Point position, bool to_item, Inkscape::XML::Node *measure_repr); + void setMeasureCanvasControlLine(Geom::Point start, Geom::Point end, bool to_item, Inkscape::CtrlLineType ctrl_line_type, Inkscape::XML::Node *measure_repr); + void setLabelText(const char *value, Geom::Point pos, double fontsize, Geom::Coord angle, guint32 background , Inkscape::XML::Node *measure_repr = NULL, CanvasTextAnchorPositionEnum text_anchor = TEXT_ANCHOR_CENTER ); + void knotStartMovedHandler(SPKnot */*knot*/, Geom::Point const &ppointer, guint state); + void knotEndMovedHandler(SPKnot */*knot*/, Geom::Point const &ppointer, guint state); + void knotUngrabbedHandler(SPKnot */*knot*/, unsigned int /*state*/); private: - SPCanvasItem* grabbed; - - Geom::Point start_point; + SPCanvasItem* grabbed; boost::optional<Geom::Point> explicitBase; - boost::optional<Geom::Point> lastEnd; + boost::optional<Geom::Point> last_end; + SPKnot *knot_start; + SPKnot *knot_end; + gint dimension_offset; + Geom::Point start_p; + Geom::Point end_p; + sigc::connection _knot_start_moved_connection; + sigc::connection _knot_start_ungrabbed_connection; + sigc::connection _knot_end_moved_connection; + sigc::connection _knot_end_ungrabbed_connection; }; } @@ -48,3 +79,14 @@ private: } #endif // SEEN_SP_MEASURING_CONTEXT_H + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/ui/tools/mesh-tool.cpp b/src/ui/tools/mesh-tool.cpp index 813d6ae5b..56ba08789 100644 --- a/src/ui/tools/mesh-tool.cpp +++ b/src/ui/tools/mesh-tool.cpp @@ -57,7 +57,7 @@ namespace Inkscape { namespace UI { namespace Tools { -static void sp_mesh_drag(MeshTool &rc, Geom::Point const pt, guint state, guint32 etime); +static void sp_mesh_end_drag(MeshTool &rc); const std::string& MeshTool::getPrefsPath() { return MeshTool::prefsPath; @@ -316,7 +316,7 @@ static void sp_mesh_context_split_near_point(MeshTool *rc, SPItem *item, Geom:: /** Wrapper for various mesh operations that require a list of selected corner nodes. */ -static void +void sp_mesh_context_corner_operation (MeshTool *rc, MeshCornerOperation operation ) { @@ -471,7 +471,7 @@ bool MeshTool::root_handler(GdkEvent* event) { } else { // Create a new gradient with default coordinates. std::vector<SPItem*> items=selection->itemList(); - for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++){ + for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();++i){ SPItem *item = *i; SPGradientType new_type = SP_GRADIENT_TYPE_MESH; Inkscape::PaintTarget fsmode = (prefs->getInt("/tools/gradient/newfillorstroke", 1) != 0) ? Inkscape::FOR_FILL : Inkscape::FOR_STROKE; @@ -560,8 +560,9 @@ bool MeshTool::root_handler(GdkEvent* event) { Inkscape::Rubberband::get(desktop)->move(motion_dt); this->defaultMessageContext()->set(Inkscape::NORMAL_MESSAGE, _("<b>Draw around</b> handles to select them")); } else { - // Create new gradient with coordinates determined by drag. - sp_mesh_drag(*this, motion_dt, event->motion.state, event->motion.time); + // Do nothing. For a linear/radial gradient we follow the drag, updating the + // gradient as the end node is dragged. For a mesh gradient, the gradient is always + // created to fill the object when the drag ends. } gobble_motion_events(GDK_BUTTON1_MASK); @@ -649,7 +650,7 @@ bool MeshTool::root_handler(GdkEvent* event) { } if (!this->within_tolerance) { - // we've been dragging, either do nothing (grdrag handles that), + // we've been dragging, either create a new gradient // or rubberband-select if we have rubberband Inkscape::Rubberband *r = Inkscape::Rubberband::get(desktop); @@ -659,6 +660,9 @@ bool MeshTool::root_handler(GdkEvent* event) { Geom::OptRect const b = r->getRectangle(); drag->selectRect(*b); } + } else { + // Create a new mesh gradient + sp_mesh_end_drag(*this); } } else if (this->item_to_select) { if (over_line && line) { @@ -922,7 +926,7 @@ bool MeshTool::root_handler(GdkEvent* event) { return ret; } -static void sp_mesh_drag(MeshTool &rc, Geom::Point const /*pt*/, guint /*state*/, guint32 /*etime*/) { +static void sp_mesh_end_drag(MeshTool &rc) { SPDesktop *desktop = SP_EVENT_CONTEXT(&rc)->desktop; Inkscape::Selection *selection = desktop->getSelection(); SPDocument *document = desktop->getDocument(); @@ -952,7 +956,7 @@ static void sp_mesh_drag(MeshTool &rc, Geom::Point const /*pt*/, guint /*state*/ sp_repr_css_set_property(css, "fill-opacity", "1.0"); std::vector<SPItem*> items=selection->itemList(); - for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++){ + for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();++i){ //FIXME: see above sp_repr_css_change_recursive((*i)->getRepr(), css, "style"); @@ -963,19 +967,8 @@ static void sp_mesh_drag(MeshTool &rc, Geom::Point const /*pt*/, guint /*state*/ (*i)->requestModified(SP_OBJECT_MODIFIED_FLAG); } - // if (ec->_grdrag) { - // ec->_grdrag->updateDraggers(); - // // prevent regenerating draggers by selection modified signal, which sometimes - // // comes too late and thus destroys the knot which we will now grab: - // ec->_grdrag->local_change = true; - // // give the grab out-of-bounds values of xp/yp because we're already dragging - // // and therefore are already out of tolerance - // ec->_grdrag->grabKnot (SP_ITEM(selection->itemList()->data), - // type == SP_GRADIENT_TYPE_LINEAR? POINT_LG_END : POINT_RG_R1, - // -1, // ignore number (though it is always 1) - // fill_or_stroke, 99999, 99999, etime); - // } - // We did an undoable action, but SPDocumentUndo::done will be called by the knot when released + + DocumentUndo::done(desktop->getDocument(), SP_VERB_CONTEXT_MESH, _("Create mesh")); // status text; we do not track coords because this branch is run once, not all the time // during drag diff --git a/src/ui/tools/mesh-tool.h b/src/ui/tools/mesh-tool.h index d952c9010..91b35b3af 100644 --- a/src/ui/tools/mesh-tool.h +++ b/src/ui/tools/mesh-tool.h @@ -20,6 +20,7 @@ #include <stddef.h> #include <sigc++/sigc++.h> #include "ui/tools/tool-base.h" +#include "sp-mesh-array.h" #define SP_MESH_CONTEXT(obj) (dynamic_cast<Inkscape::UI::Tools::MeshTool*>((Inkscape::UI::Tools::ToolBase*)obj)) #define SP_IS_MESH_CONTEXT(obj) (dynamic_cast<const Inkscape::UI::Tools::MeshTool*>((const Inkscape::UI::Tools::ToolBase*)obj) != NULL) @@ -57,6 +58,7 @@ private: void sp_mesh_context_select_next(ToolBase *event_context); void sp_mesh_context_select_prev(ToolBase *event_context); +void sp_mesh_context_corner_operation(MeshTool *event_context, MeshCornerOperation operation ); } } diff --git a/src/ui/tools/node-tool.cpp b/src/ui/tools/node-tool.cpp index 6a6ca0b26..cceaca7cb 100644 --- a/src/ui/tools/node-tool.cpp +++ b/src/ui/tools/node-tool.cpp @@ -413,7 +413,7 @@ void NodeTool::selection_changed(Inkscape::Selection *sel) { std::set<ShapeRecord> shapes; std::vector<SPItem*> items=sel->itemList(); - for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++){ + for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();++i){ SPObject *obj = *i; if (SP_IS_ITEM(obj)) { diff --git a/src/ui/tools/pen-tool.cpp b/src/ui/tools/pen-tool.cpp index 6a3928f27..2ed366a7d 100644 --- a/src/ui/tools/pen-tool.cpp +++ b/src/ui/tools/pen-tool.cpp @@ -84,7 +84,7 @@ namespace Tools { static Geom::Point pen_drag_origin_w(0, 0); static bool pen_within_tolerance = false; static int pen_last_paraxial_dir = 0; // last used direction in horizontal/vertical mode; 0 = horizontal, 1 = vertical -const double HANDLE_CUBIC_GAP = 0.01; +const double HANDLE_CUBIC_GAP = 0.001; const std::string& PenTool::getPrefsPath() { return PenTool::prefsPath; @@ -382,11 +382,12 @@ bool PenTool::_handleButtonPress(GdkEventButton const &bevent) { if( anchor && anchor == this->sa && this->green_curve->is_empty()){ //remove the following line to avoid having one node on top of another _finishSegment(event_dt, bevent.state); - _finish( false); + _finish(true); return true; } return false; } + bool ret = false; if (bevent.button == 1 && !this->space_panning // make sure this is not the last click for a waiting LPE (otherwise we want to finish the path) @@ -860,7 +861,7 @@ bool PenTool::_handleButtonRelease(GdkEventButton const &revent) { bool PenTool::_handle2ButtonPress(GdkEventButton const &bevent) { bool ret = false; // only end on LMB double click. Otherwise horizontal scrolling causes ending of the path - if (this->npoints != 0 && bevent.button == 1) { + if (this->npoints != 0 && bevent.button == 1 && this->state != PenTool::CLOSE) { this->_finish(false); ret = true; } diff --git a/src/ui/tools/spray-tool.cpp b/src/ui/tools/spray-tool.cpp index e2be5ca4b..71cad5c0d 100644 --- a/src/ui/tools/spray-tool.cpp +++ b/src/ui/tools/spray-tool.cpp @@ -12,6 +12,7 @@ * Steren GIANNINI (steren.giannini@gmail.com) * Jon A. Cruz <jon@joncruz.org> * Abhishek Sharma + * Jabiertxo Arraiza <jabier.arraiza@marker.es> * * Copyright (C) 2009 authors * @@ -48,7 +49,15 @@ #include "sp-path.h" #include "path-chemistry.h" +// For color picking +#include "display/drawing.h" +#include "display/drawing-context.h" +#include "display/cairo-utils.h" +#include "desktop-style.h" +#include "svg/svg-color.h" + #include "sp-text.h" +#include "sp-root.h" #include "sp-flowtext.h" #include "display/sp-canvas.h" #include "display/canvas-bpath.h" @@ -88,6 +97,17 @@ namespace Inkscape { namespace UI { namespace Tools { +enum { + PICK_COLOR, + PICK_OPACITY, + PICK_R, + PICK_G, + PICK_B, + PICK_H, + PICK_S, + PICK_L +}; + const std::string& SprayTool::getPrefsPath() { return SprayTool::prefsPath; } @@ -133,7 +153,9 @@ SprayTool::SprayTool() : ToolBase(cursor_spray_xpm, 4, 4, false) , pressure(TC_DEFAULT_PRESSURE) , dragging(false) - , usepressure(false) + , usepressurewidth(false) + , usepressurepopulation(false) + , usepressurescale(false) , usetilt(false) , usetext(false) , width(0.2) @@ -151,6 +173,25 @@ SprayTool::SprayTool() , is_dilating(false) , has_dilated(false) , dilate_area(NULL) + , no_overlap(false) + , picker(false) + , pick_center(true) + , pick_inverse_value(false) + , pick_fill(false) + , pick_stroke(false) + , pick_no_overlap(false) + , over_transparent(true) + , over_no_transparent(true) + , offset(0) + , pick(0) + , do_trace(false) + , pick_to_size(false) + , pick_to_presence(false) + , pick_to_color(false) + , pick_to_opacity(false) + , invert_picked(false) + , gamma_picked(0) + , rand_picked(0) { } @@ -211,6 +252,15 @@ void SprayTool::setup() { this->is_drawing = false; + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setBool("/dialogs/clonetiler/dotrace", false); + if (prefs->getBool("/tools/spray/selcue")) { + this->enableSelectionCue(); + } + if (prefs->getBool("/tools/spray/gradientdrag")) { + this->enableGrDrag(); + } + sp_event_context_read(this, "distrib"); sp_event_context_read(this, "width"); sp_event_context_read(this, "ratio"); @@ -221,16 +271,33 @@ void SprayTool::setup() { sp_event_context_read(this, "population"); sp_event_context_read(this, "mean"); sp_event_context_read(this, "standard_deviation"); - sp_event_context_read(this, "usepressure"); + sp_event_context_read(this, "usepressurewidth"); + sp_event_context_read(this, "usepressurepopulation"); + sp_event_context_read(this, "usepressurescale"); sp_event_context_read(this, "Scale"); + sp_event_context_read(this, "offset"); + sp_event_context_read(this, "picker"); + sp_event_context_read(this, "pick_center"); + sp_event_context_read(this, "pick_inverse_value"); + sp_event_context_read(this, "pick_fill"); + sp_event_context_read(this, "pick_stroke"); + sp_event_context_read(this, "pick_no_overlap"); + sp_event_context_read(this, "over_no_transparent"); + sp_event_context_read(this, "over_transparent"); + sp_event_context_read(this, "no_overlap"); +} +void SprayTool::setCloneTilerPrefs() { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - if (prefs->getBool("/tools/spray/selcue")) { - this->enableSelectionCue(); - } - if (prefs->getBool("/tools/spray/gradientdrag")) { - this->enableGrDrag(); - } + this->do_trace = prefs->getBool("/dialogs/clonetiler/dotrace", false); + this->pick = prefs->getInt("/dialogs/clonetiler/pick"); + this->pick_to_size = prefs->getBool("/dialogs/clonetiler/pick_to_size", false); + this->pick_to_presence = prefs->getBool("/dialogs/clonetiler/pick_to_presence", false); + this->pick_to_color = prefs->getBool("/dialogs/clonetiler/pick_to_color", false); + this->pick_to_opacity = prefs->getBool("/dialogs/clonetiler/pick_to_opacity", false); + this->rand_picked = 0.01 * prefs->getDoubleLimited("/dialogs/clonetiler/rand_picked", 0, 0, 100); + this->invert_picked = prefs->getBool("/dialogs/clonetiler/invert_picked", false); + this->gamma_picked = prefs->getDoubleLimited("/dialogs/clonetiler/gamma_picked", 0, -10, 10); } void SprayTool::set(const Inkscape::Preferences::Entry& val) { @@ -241,8 +308,12 @@ void SprayTool::set(const Inkscape::Preferences::Entry& val) { this->update_cursor(false); } else if (path == "width") { this->width = 0.01 * CLAMP(val.getInt(10), 1, 100); - } else if (path == "usepressure") { - this->usepressure = val.getBool(); + } else if (path == "usepressurewidth") { + this->usepressurewidth = val.getBool(); + } else if (path == "usepressurepopulation") { + this->usepressurepopulation = val.getBool(); + } else if (path == "usepressurescale") { + this->usepressurescale = val.getBool(); } else if (path == "population") { this->population = 0.01 * CLAMP(val.getInt(10), 1, 100); } else if (path == "rotation_variation") { @@ -260,6 +331,26 @@ void SprayTool::set(const Inkscape::Preferences::Entry& val) { this->tilt = CLAMP(val.getDouble(0.1), 0, 1000.0); } else if (path == "ratio") { this->ratio = CLAMP(val.getDouble(), 0.0, 0.9); + } else if (path == "offset") { + this->offset = val.getDoubleLimited(100.0, 0, 1000.0); + } else if (path == "pick_center") { + this->pick_center = val.getBool(true); + } else if (path == "pick_inverse_value") { + this->pick_inverse_value = val.getBool(false); + } else if (path == "pick_fill") { + this->pick_fill = val.getBool(false); + } else if (path == "pick_stroke") { + this->pick_stroke = val.getBool(false); + } else if (path == "pick_no_overlap") { + this->pick_no_overlap = val.getBool(false); + } else if (path == "over_no_transparent") { + this->over_no_transparent = val.getBool(true); + } else if (path == "over_transparent") { + this->over_transparent = val.getBool(true); + } else if (path == "no_overlap") { + this->no_overlap = val.getBool(false); + } else if (path == "picker") { + this->picker = val.getBool(false); } } @@ -272,9 +363,15 @@ static void sp_spray_extinput(SprayTool *tc, GdkEvent *event) } } +static double get_width(SprayTool *tc) +{ + double pressure = (tc->usepressurewidth? tc->pressure / TC_DEFAULT_PRESSURE : 1); + return pressure * tc->width; +} + static double get_dilate_radius(SprayTool *tc) { - return 250 * tc->width/SP_EVENT_CONTEXT(tc)->desktop->current_zoom(); + return 250 * get_width(tc)/SP_EVENT_CONTEXT(tc)->desktop->current_zoom(); } static double get_path_mean(SprayTool *tc) @@ -289,11 +386,16 @@ static double get_path_standard_deviation(SprayTool *tc) static double get_population(SprayTool *tc) { - double pressure = (tc->usepressure? tc->pressure / TC_DEFAULT_PRESSURE : 1); - //g_warning("Pressure, population: %f, %f", pressure, pressure * tc->population); + double pressure = (tc->usepressurepopulation? tc->pressure / TC_DEFAULT_PRESSURE : 1); return pressure * tc->population; } +static double get_pressure(SprayTool *tc) +{ + double pressure = tc->pressure / TC_DEFAULT_PRESSURE; + return pressure; +} + static double get_move_mean(SprayTool *tc) { return tc->mean; @@ -332,6 +434,433 @@ static void random_position(double &radius, double &angle, double &a, double &s, } +static void sp_spray_transform_path(SPItem * item, Geom::Path &path, Geom::Affine affine, Geom::Point center){ + path *= i2anc_affine(static_cast<SPItem *>(item->parent), NULL).inverse(); + path *= item->transform.inverse(); + Geom::Affine dt2p; + if (item->parent) { + dt2p = static_cast<SPItem *>(item->parent)->i2dt_affine().inverse(); + } else { + SPDesktop *dt = SP_ACTIVE_DESKTOP; + dt2p = dt->dt2doc(); + } + Geom::Affine i2dt = item->i2dt_affine() * Geom::Translate(center).inverse() * affine * Geom::Translate(center); + path *= i2dt * dt2p; + path *= i2anc_affine(static_cast<SPItem *>(item->parent), NULL); +} + +/** +Randomizes \a val by \a rand, with 0 < val < 1 and all values (including 0, 1) having the same +probability of being displaced. + */ +double randomize01(double val, double rand) +{ + double base = MIN (val - rand, 1 - 2*rand); + if (base < 0) { + base = 0; + } + val = base + g_random_double_range (0, MIN (2 * rand, 1 - base)); + return CLAMP(val, 0, 1); // this should be unnecessary with the above provisions, but just in case... +} + +guint32 getPickerData(Geom::IntRect area){ + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + double R = 0, G = 0, B = 0, A = 0; + cairo_surface_t *s = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, area.width(), area.height()); + sp_canvas_arena_render_surface(SP_CANVAS_ARENA(desktop->getDrawing()), s, area); + ink_cairo_surface_average_color(s, R, G, B, A); + cairo_surface_destroy(s); + //this can fix the bug #1511998 if confirmed + if( A == 0 || A < 1e-6){ + R = 1; + G = 1; + B = 1; + } + return SP_RGBA32_F_COMPOSE(R, G, B, A); +} + +static void showHidden(std::vector<SPItem *> items_down){ + for (std::vector<SPItem *>::const_iterator k=items_down.begin(); k!=items_down.end(); ++k) { + SPItem *item_hidden = *k; + item_hidden->setHidden(false); + item_hidden->updateRepr(); + } +} +//todo: maybe move same parameter to preferences +static bool fit_item(SPDesktop *desktop, + SPItem *item, + Geom::OptRect bbox, + Geom::Point &move, + Geom::Point center, + gint mode, + double angle, + double &_scale, + double scale, + bool picker, + bool pick_center, + bool pick_inverse_value, + bool pick_fill, + bool pick_stroke, + bool pick_no_overlap, + bool over_no_transparent, + bool over_transparent, + bool no_overlap, + double offset, + SPCSSAttr *css, + bool trace_scale, + int pick, + bool do_trace, + bool pick_to_size, + bool pick_to_presence, + bool pick_to_color, + bool pick_to_opacity, + bool invert_picked, + double gamma_picked , + double rand_picked) +{ + SPDocument *doc = item->document; + double width = bbox->width(); + double height = bbox->height(); + double offset_width = (offset * width)/100.0 - (width); + if(offset_width < 0 ){ + offset_width = 0; + } + double offset_height = (offset * height)/100.0 - (height); + if(offset_height < 0 ){ + offset_height = 0; + } + if(picker && pick_to_size && !trace_scale && do_trace){ + _scale = 0.1; + } + Geom::OptRect bbox_procesed = Geom::Rect(Geom::Point(bbox->left() - offset_width, bbox->top() - offset_height),Geom::Point(bbox->right() + offset_width, bbox->bottom() + offset_height)); + Geom::Path path; + path.start(Geom::Point(bbox_procesed->left(), bbox_procesed->top())); + path.appendNew<Geom::LineSegment>(Geom::Point(bbox_procesed->right(), bbox_procesed->top())); + path.appendNew<Geom::LineSegment>(Geom::Point(bbox_procesed->right(), bbox_procesed->bottom())); + path.appendNew<Geom::LineSegment>(Geom::Point(bbox_procesed->left(), bbox_procesed->bottom())); + path.close(true); + sp_spray_transform_path(item, path, Geom::Scale(_scale), center); + sp_spray_transform_path(item, path, Geom::Scale(scale), center); + sp_spray_transform_path(item, path, Geom::Rotate(angle), center); + path *= Geom::Translate(move); + path *= desktop->doc2dt(); + bbox_procesed = path.boundsFast(); + double bbox_left_main = bbox_procesed->left(); + double bbox_right_main = bbox_procesed->right(); + double bbox_top_main = bbox_procesed->top(); + double bbox_bottom_main = bbox_procesed->bottom(); + double width_transformed = bbox_procesed->width(); + double height_transformed = bbox_procesed->height(); + Geom::Point mid_point = desktop->d2w(bbox_procesed->midpoint()); + Geom::IntRect area = Geom::IntRect::from_xywh(floor(mid_point[Geom::X]), floor(mid_point[Geom::Y]), 1, 1); + guint32 rgba = getPickerData(area); + guint32 rgba2 = 0xffffff00; + Geom::Rect rect_sprayed(desktop->d2w(Geom::Point(bbox_left_main,bbox_top_main)), desktop->d2w(Geom::Point(bbox_right_main,bbox_bottom_main))); + if (!rect_sprayed.hasZeroArea()) { + rgba2 = getPickerData(rect_sprayed.roundOutwards()); + } + if(pick_no_overlap) { + if(rgba != rgba2) { + if(mode != SPRAY_MODE_ERASER) { + return false; + } + } + } + if(!pick_center) { + rgba = rgba2; + } + if(!over_transparent && (SP_RGBA32_A_F(rgba) == 0 || SP_RGBA32_A_F(rgba) < 1e-6)) { + if(mode != SPRAY_MODE_ERASER) { + return false; + } + } + if(!over_no_transparent && SP_RGBA32_A_F(rgba) > 0) { + if(mode != SPRAY_MODE_ERASER) { + return false; + } + } + if(offset < 100 ) { + offset_width = ((99.0 - offset) * width_transformed)/100.0 - width_transformed; + offset_height = ((99.0 - offset) * height_transformed)/100.0 - height_transformed; + } else { + offset_width = 0; + offset_height = 0; + } + std::vector<SPItem*> items_down = desktop->getDocument()->getItemsPartiallyInBox(desktop->dkey, *bbox_procesed); + Inkscape::Selection *selection = desktop->getSelection(); + if (selection->isEmpty()) { + return false; + } + std::vector<SPItem*> const items_selected(selection->itemList()); + std::vector<SPItem*> items_down_erased; + for (std::vector<SPItem*>::const_iterator i=items_down.begin(); i!=items_down.end(); ++i) { + SPItem *item_down = *i; + Geom::OptRect bbox_down = item_down->documentVisualBounds(); + double bbox_left = bbox_down->left(); + double bbox_top = bbox_down->top(); + gchar const * item_down_sharp = g_strdup_printf("#%s", item_down->getId()); + items_down_erased.push_back(item_down); + for (std::vector<SPItem*>::const_iterator j=items_selected.begin(); j!=items_selected.end(); ++j) { + SPItem *item_selected = *j; + gchar const * spray_origin; + if(!item_selected->getAttribute("inkscape:spray-origin")){ + spray_origin = g_strdup_printf("#%s", item_selected->getId()); + } else { + spray_origin = item_selected->getAttribute("inkscape:spray-origin"); + } + if(strcmp(item_down_sharp, spray_origin) == 0 || + (item_down->getAttribute("inkscape:spray-origin") && + strcmp(item_down->getAttribute("inkscape:spray-origin"),spray_origin) == 0 )) + { + if(mode == SPRAY_MODE_ERASER) { + if(strcmp(item_down_sharp, spray_origin) != 0 && !selection->includes(item_down) ){ + item_down->deleteObject(); + items_down_erased.pop_back(); + break; + } + } else if(no_overlap) { + if(!(offset_width < 0 && offset_height < 0 && std::abs(bbox_left - bbox_left_main) > std::abs(offset_width) && + std::abs(bbox_top - bbox_top_main) > std::abs(offset_height))){ + if(!no_overlap && (picker || over_transparent || over_no_transparent)){ + showHidden(items_down); + } + return false; + } + } else if(picker || over_transparent || over_no_transparent) { + item_down->setHidden(true); + item_down->updateRepr(); + } + } + } + } + if(mode == SPRAY_MODE_ERASER){ + if(!no_overlap && (picker || over_transparent || over_no_transparent)){ + showHidden(items_down_erased); + } + return false; + } + if(picker || over_transparent || over_no_transparent){ + if(!no_overlap){ + doc->ensureUpToDate(); + rgba = getPickerData(area); + if (!rect_sprayed.hasZeroArea()) { + rgba2 = getPickerData(rect_sprayed.roundOutwards()); + } + } + if(pick_no_overlap){ + if(rgba != rgba2){ + if(!no_overlap && (picker || over_transparent || over_no_transparent)){ + showHidden(items_down); + } + return false; + } + } + if(!pick_center){ + rgba = rgba2; + } + double opacity = 1.0; + gchar color_string[32]; *color_string = 0; + float r = SP_RGBA32_R_F(rgba); + float g = SP_RGBA32_G_F(rgba); + float b = SP_RGBA32_B_F(rgba); + float a = SP_RGBA32_A_F(rgba); + if(!over_transparent && (a == 0 || a < 1e-6)){ + if(!no_overlap && (picker || over_transparent || over_no_transparent)){ + showHidden(items_down); + } + return false; + } + if(!over_no_transparent && a > 0){ + if(!no_overlap && (picker || over_transparent || over_no_transparent)){ + showHidden(items_down); + } + return false; + } + + if(picker && do_trace){ + float hsl[3]; + sp_color_rgb_to_hsl_floatv (hsl, r, g, b); + + gdouble val = 0; + switch (pick) { + case PICK_COLOR: + val = 1 - hsl[2]; // inverse lightness; to match other picks where black = max + break; + case PICK_OPACITY: + val = a; + break; + case PICK_R: + val = r; + break; + case PICK_G: + val = g; + break; + case PICK_B: + val = b; + break; + case PICK_H: + val = hsl[0]; + break; + case PICK_S: + val = hsl[1]; + break; + case PICK_L: + val = 1 - hsl[2]; + break; + default: + break; + } + + if (rand_picked > 0) { + val = randomize01 (val, rand_picked); + r = randomize01 (r, rand_picked); + g = randomize01 (g, rand_picked); + b = randomize01 (b, rand_picked); + } + + if (gamma_picked != 0) { + double power; + if (gamma_picked > 0) + power = 1/(1 + fabs(gamma_picked)); + else + power = 1 + fabs(gamma_picked); + + val = pow (val, power); + r = pow ((double)r, (double)power); + g = pow ((double)g, (double)power); + b = pow ((double)b, (double)power); + } + + if (invert_picked) { + val = 1 - val; + r = 1 - r; + g = 1 - g; + b = 1 - b; + } + + val = CLAMP (val, 0, 1); + r = CLAMP (r, 0, 1); + g = CLAMP (g, 0, 1); + b = CLAMP (b, 0, 1); + + // recompose tweaked color + rgba = SP_RGBA32_F_COMPOSE(r, g, b, a); + if (pick_to_size) { + if(!trace_scale){ + if(pick_inverse_value) { + _scale = 1.0 - val; + } else { + _scale = val; + } + if(_scale == 0.0) { + if(!no_overlap && (picker || over_transparent || over_no_transparent)){ + showHidden(items_down); + } + return false; + } + if(!fit_item(desktop + , item + , bbox + , move + , center + , mode + , angle + , _scale + , scale + , picker + , pick_center + , pick_inverse_value + , pick_fill + , pick_stroke + , pick_no_overlap + , over_no_transparent + , over_transparent + , no_overlap + , offset + , css + , true + , pick + , do_trace + , pick_to_size + , pick_to_presence + , pick_to_color + , pick_to_opacity + , invert_picked + , gamma_picked + , rand_picked) + ) + { + if(!no_overlap && (picker || over_transparent || over_no_transparent)){ + showHidden(items_down); + } + return false; + } + } + } + + if (pick_to_opacity) { + if(pick_inverse_value) { + opacity *= 1.0 - val; + } else { + opacity *= val; + } + std::stringstream opacity_str; + opacity_str.imbue(std::locale::classic()); + opacity_str << opacity; + sp_repr_css_set_property(css, "opacity", opacity_str.str().c_str()); + } + if (pick_to_presence) { + if (g_random_double_range (0, 1) > val) { + //Hidding the element is a way to retain original + //behaviour of tiled clones for presence option. + sp_repr_css_set_property(css, "opacity", "0"); + } + } + if (pick_to_color) { + sp_svg_write_color(color_string, sizeof(color_string), rgba); + if(pick_fill){ + sp_repr_css_set_property(css, "fill", color_string); + } + if(pick_stroke){ + sp_repr_css_set_property(css, "stroke", color_string); + } + } + if (opacity < 1e-6) { // invisibly transparent, skip + if(!no_overlap && (picker || over_transparent || over_no_transparent)){ + showHidden(items_down); + } + return false; + } + } + if(!do_trace){ + if(!pick_center){ + rgba = rgba2; + } + if (pick_inverse_value) { + r = 1 - SP_RGBA32_R_F(rgba); + g = 1 - SP_RGBA32_G_F(rgba); + b = 1 - SP_RGBA32_B_F(rgba); + } else { + r = SP_RGBA32_R_F(rgba); + g = SP_RGBA32_G_F(rgba); + b = SP_RGBA32_B_F(rgba); + } + rgba = SP_RGBA32_F_COMPOSE(r, g, b, a); + sp_svg_write_color(color_string, sizeof(color_string), rgba); + if(pick_fill){ + sp_repr_css_set_property(css, "fill", color_string); + } + if(pick_stroke){ + sp_repr_css_set_property(css, "stroke", color_string); + } + } + if(!no_overlap && (picker || over_transparent || over_no_transparent)){ + showHidden(items_down); + } + } + return true; +} + static bool sp_spray_recursive(SPDesktop *desktop, Inkscape::Selection *selection, SPItem *item, @@ -348,7 +877,28 @@ static bool sp_spray_recursive(SPDesktop *desktop, double ratio, double tilt, double rotation_variation, - gint _distrib) + gint _distrib, + bool no_overlap, + bool picker, + bool pick_center, + bool pick_inverse_value, + bool pick_fill, + bool pick_stroke, + bool pick_no_overlap, + bool over_no_transparent, + bool over_transparent, + double offset, + bool usepressurescale, + double pressure, + int pick, + bool do_trace, + bool pick_to_size, + bool pick_to_presence, + bool pick_to_color, + bool pick_to_opacity, + bool invert_picked, + double gamma_picked , + double rand_picked) { bool did = false; @@ -364,34 +914,83 @@ static bool sp_spray_recursive(SPDesktop *desktop, double _fid = g_random_double_range(0, 1); double angle = g_random_double_range( - rotation_variation / 100.0 * M_PI , rotation_variation / 100.0 * M_PI ); double _scale = g_random_double_range( 1.0 - scale_variation / 100.0, 1.0 + scale_variation / 100.0 ); + if(usepressurescale){ + _scale = pressure; + } double dr; double dp; random_position( dr, dp, mean, standard_deviation, _distrib ); dr=dr*radius; - if (mode == SPRAY_MODE_COPY) { + if (mode == SPRAY_MODE_COPY || mode == SPRAY_MODE_ERASER) { Geom::OptRect a = item->documentVisualBounds(); if (a) { - SPItem *item_copied; if(_fid <= population) { - // Duplicate SPDocument *doc = item->document; + gchar const * spray_origin; + if(!item->getAttribute("inkscape:spray-origin")){ + spray_origin = g_strdup_printf("#%s", item->getId()); + } else { + spray_origin = item->getAttribute("inkscape:spray-origin"); + } + Geom::Point center = item->getCenter(); + Geom::Point move = (Geom::Point(cos(tilt)*cos(dp)*dr/(1-ratio)+sin(tilt)*sin(dp)*dr/(1+ratio), -sin(tilt)*cos(dp)*dr/(1-ratio)+cos(tilt)*sin(dp)*dr/(1+ratio)))+(p-a->midpoint()); + SPCSSAttr *css = sp_repr_css_attr_new(); + if(no_overlap || picker || !over_transparent || !over_no_transparent){ + if(!fit_item(desktop + , item + , a + , move + , center + , mode + , angle + , _scale + , scale + , picker + , pick_center + , pick_inverse_value + , pick_fill + , pick_stroke + , pick_no_overlap + , over_no_transparent + , over_transparent + , no_overlap + , offset + , css + , false + , pick + , do_trace + , pick_to_size + , pick_to_presence + , pick_to_color + , pick_to_opacity + , invert_picked + , gamma_picked + , rand_picked)){ + return false; + } + } + SPItem *item_copied; + // Duplicate Inkscape::XML::Document* xml_doc = doc->getReprDoc(); Inkscape::XML::Node *old_repr = item->getRepr(); Inkscape::XML::Node *parent = old_repr->parent(); Inkscape::XML::Node *copy = old_repr->duplicate(xml_doc); + if(!copy->attribute("inkscape:spray-origin")){ + copy->setAttribute("inkscape:spray-origin", spray_origin); + } parent->appendChild(copy); - SPObject *new_obj = doc->getObjectByRepr(copy); item_copied = dynamic_cast<SPItem *>(new_obj); // Conversion object->item - Geom::Point center=item->getCenter(); - sp_spray_scale_rel(center,desktop, item_copied, Geom::Scale(_scale,_scale)); - sp_spray_scale_rel(center,desktop, item_copied, Geom::Scale(scale,scale)); - + sp_spray_scale_rel(center,desktop, item_copied, Geom::Scale(_scale)); + sp_spray_scale_rel(center,desktop, item_copied, Geom::Scale(scale)); sp_spray_rotate_rel(center,desktop,item_copied, Geom::Rotate(angle)); // Move the cursor p - Geom::Point move = (Geom::Point(cos(tilt)*cos(dp)*dr/(1-ratio)+sin(tilt)*sin(dp)*dr/(1+ratio), -sin(tilt)*cos(dp)*dr/(1-ratio)+cos(tilt)*sin(dp)*dr/(1+ratio)))+(p-a->midpoint()); sp_item_move_rel(item_copied, Geom::Translate(move[Geom::X], -move[Geom::Y])); + Inkscape::GC::release(copy); + if(picker){ + sp_desktop_apply_css_recursive(item_copied, css, true); + } did = true; } } @@ -404,7 +1003,7 @@ static bool sp_spray_recursive(SPDesktop *desktop, int i=1; std::vector<SPItem*> items=selection->itemList(); - for(std::vector<SPItem*>::const_iterator it=items.begin();it!=items.end();it++){ + for(std::vector<SPItem*>::const_iterator it=items.begin();it!=items.end(); ++it){ SPItem *item1 = *it; if (i == 1) { parent_item = item1; @@ -425,6 +1024,13 @@ static bool sp_spray_recursive(SPDesktop *desktop, if (_fid <= population) { // Rules the population of objects sprayed // Duplicates the parent item Inkscape::XML::Node *copy = old_repr->duplicate(xml_doc); + gchar const * spray_origin; + if(!copy->attribute("inkscape:spray-origin")){ + spray_origin = g_strdup_printf("#%s", old_repr->attribute("id")); + copy->setAttribute("inkscape:spray-origin", spray_origin); + } else { + spray_origin = copy->attribute("inkscape:spray-origin"); + } parent->appendChild(copy); SPObject *new_obj = doc->getObjectByRepr(copy); item_copied = dynamic_cast<SPItem *>(new_obj); @@ -456,8 +1062,52 @@ static bool sp_spray_recursive(SPDesktop *desktop, Geom::OptRect a = item->documentVisualBounds(); if (a) { if(_fid <= population) { - SPItem *item_copied; SPDocument *doc = item->document; + gchar const * spray_origin; + if(!item->getAttribute("inkscape:spray-origin")){ + spray_origin = g_strdup_printf("#%s", item->getId()); + } else { + spray_origin = item->getAttribute("inkscape:spray-origin"); + } + Geom::Point center=item->getCenter(); + Geom::Point move = (Geom::Point(cos(tilt)*cos(dp)*dr/(1-ratio)+sin(tilt)*sin(dp)*dr/(1+ratio), -sin(tilt)*cos(dp)*dr/(1-ratio)+cos(tilt)*sin(dp)*dr/(1+ratio)))+(p-a->midpoint()); + SPCSSAttr *css = sp_repr_css_attr_new(); + if(no_overlap || picker || !over_transparent || !over_no_transparent){ + if(!fit_item(desktop + , item + , a + , move + , center + , mode + , angle + , _scale + , scale + , picker + , pick_center + , pick_inverse_value + , pick_fill + , pick_stroke + , pick_no_overlap + , over_no_transparent + , over_transparent + , no_overlap + , offset + , css + , true + , pick + , do_trace + , pick_to_size + , pick_to_presence + , pick_to_color + , pick_to_opacity + , invert_picked + , gamma_picked + , rand_picked)) + { + return false; + } + } + SPItem *item_copied; Inkscape::XML::Document* xml_doc = doc->getReprDoc(); Inkscape::XML::Node *old_repr = item->getRepr(); Inkscape::XML::Node *parent = old_repr->parent(); @@ -467,6 +1117,9 @@ static bool sp_spray_recursive(SPDesktop *desktop, // Ad the clone to the list of the parent's children parent->appendChild(clone); // Generates the link between parent and child attributes + if(!clone->attribute("inkscape:spray-origin")){ + clone->setAttribute("inkscape:spray-origin", spray_origin); + } gchar *href_str = g_strdup_printf("#%s", old_repr->attribute("id")); clone->setAttribute("xlink:href", href_str, false); g_free(href_str); @@ -474,15 +1127,14 @@ static bool sp_spray_recursive(SPDesktop *desktop, SPObject *clone_object = doc->getObjectByRepr(clone); // Conversion object->item item_copied = dynamic_cast<SPItem *>(clone_object); - Geom::Point center = item->getCenter(); sp_spray_scale_rel(center, desktop, item_copied, Geom::Scale(_scale, _scale)); sp_spray_scale_rel(center, desktop, item_copied, Geom::Scale(scale, scale)); sp_spray_rotate_rel(center, desktop, item_copied, Geom::Rotate(angle)); - Geom::Point move = (Geom::Point(cos(tilt)*cos(dp)*dr/(1-ratio)+sin(tilt)*sin(dp)*dr/(1+ratio), -sin(tilt)*cos(dp)*dr/(1-ratio)+cos(tilt)*sin(dp)*dr/(1+ratio)))+(p-a->midpoint()); sp_item_move_rel(item_copied, Geom::Translate(move[Geom::X], -move[Geom::Y])); - + if(picker){ + sp_desktop_apply_css_recursive(item_copied, css, true); + } Inkscape::GC::release(clone); - did = true; } } @@ -520,22 +1172,57 @@ static bool sp_spray_dilate(SprayTool *tc, Geom::Point /*event_p*/, Geom::Point { std::vector<SPItem*> const items(selection->itemList()); - for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++){ + for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end(); ++i){ SPItem *item = *i; g_assert(item != NULL); sp_object_ref(item); } - for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++){ + for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end(); ++i){ SPItem *item = *i; g_assert(item != NULL); - - if (sp_spray_recursive(desktop, selection, item, p, vector, tc->mode, radius, population, tc->scale, tc->scale_variation, reverse, move_mean, move_standard_deviation, tc->ratio, tc->tilt, tc->rotation_variation, tc->distrib)) { + if (sp_spray_recursive(desktop + , selection + , item + , p, vector + , tc->mode + , radius + , population + , tc->scale + , tc->scale_variation + , reverse + , move_mean + , move_standard_deviation + , tc->ratio + , tc->tilt + , tc->rotation_variation + , tc->distrib + , tc->no_overlap + , tc->picker + , tc->pick_center + , tc->pick_inverse_value + , tc->pick_fill + , tc->pick_stroke + , tc->pick_no_overlap + , tc->over_no_transparent + , tc->over_transparent + , tc->offset + , tc->usepressurescale + , get_pressure(tc) + , tc->pick + , tc->do_trace + , tc->pick_to_size + , tc->pick_to_presence + , tc->pick_to_color + , tc->pick_to_opacity + , tc->invert_picked + , tc->gamma_picked + , tc->rand_picked)) { did = true; } } - for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++){ + for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end(); ++i){ SPItem *item = *i; g_assert(item != NULL); sp_object_unref(item); @@ -577,7 +1264,7 @@ bool SprayTool::root_handler(GdkEvent* event) { if (Inkscape::have_viable_layer(desktop, this->message_context) == false) { return TRUE; } - + this->setCloneTilerPrefs(); Geom::Point const motion_w(event->button.x, event->button.y); Geom::Point const motion_dt(desktop->w2d(motion_w)); this->last_push = desktop->dt2doc(motion_dt); diff --git a/src/ui/tools/spray-tool.h b/src/ui/tools/spray-tool.h index 8df730201..c81110b37 100644 --- a/src/ui/tools/spray-tool.h +++ b/src/ui/tools/spray-tool.h @@ -12,6 +12,7 @@ * Benoît LAVORATA * Vincent MONTAGNE * Pierre BARBRY-BLOT + * Jabiertxo ARRAIZA * * Copyright (C) 2009 authors * @@ -46,7 +47,8 @@ namespace Tools { enum { SPRAY_MODE_COPY, SPRAY_MODE_CLONE, - SPRAY_MODE_SINGLE_PATH, + SPRAY_MODE_SINGLE_PATH, + SPRAY_MODE_ERASER, SPRAY_OPTION, }; @@ -62,7 +64,9 @@ public: /* attributes */ bool dragging; /* mouse state: mouse is dragging */ - bool usepressure; + bool usepressurewidth; + bool usepressurepopulation; + bool usepressurescale; bool usetilt; bool usetext; @@ -86,13 +90,32 @@ public: bool has_dilated; Geom::Point last_push; SPCanvasItem *dilate_area; - + bool no_overlap; + bool picker; + bool pick_center; + bool pick_inverse_value; + bool pick_fill; + bool pick_stroke; + bool pick_no_overlap; + bool over_transparent; + bool over_no_transparent; + double offset; + int pick; + bool do_trace; + bool pick_to_size; + bool pick_to_presence; + bool pick_to_color; + bool pick_to_opacity; + bool invert_picked; + double gamma_picked; + double rand_picked; sigc::connection style_set_connection; static const std::string prefsPath; virtual void setup(); virtual void set(const Inkscape::Preferences::Entry& val); + virtual void setCloneTilerPrefs(); virtual bool root_handler(GdkEvent* event); virtual const std::string& getPrefsPath(); diff --git a/src/ui/tools/tool-base.cpp b/src/ui/tools/tool-base.cpp index 0f9b3ee7a..bf7b61b61 100644 --- a/src/ui/tools/tool-base.cpp +++ b/src/ui/tools/tool-base.cpp @@ -358,7 +358,7 @@ bool ToolBase::root_handler(GdkEvent* event) { /// @todo REmove redundant /value in preference keys tolerance = prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100); - + bool allow_panning = prefs->getBool("/options/spacebarpans/value"); gint ret = FALSE; switch (event->type) { @@ -582,7 +582,6 @@ bool ToolBase::root_handler(GdkEvent* event) { case GDK_KEY_PRESS: { double const acceleration = prefs->getDoubleLimited( "/options/scrollingacceleration/value", 0, 0, 6); - int const key_scroll = prefs->getIntLimited("/options/keyscroll/value", 10, 0, 1000); @@ -692,10 +691,10 @@ bool ToolBase::root_handler(GdkEvent* event) { break; case GDK_KEY_space: - xp = yp = 0; within_tolerance = true; + xp = yp = 0; + if (!allow_panning) break; panning = 4; - this->space_panning = true; this->message_context->set(Inkscape::INFORMATION_MESSAGE, _("<b>Space+mouse move</b> to pan canvas")); @@ -742,7 +741,7 @@ bool ToolBase::root_handler(GdkEvent* event) { switch (get_group0_keyval(&event->key)) { case GDK_KEY_space: - if (within_tolerance == true) { + if (within_tolerance) { // Space was pressed, but not panned sp_toggle_selector(desktop); diff --git a/src/ui/tools/tweak-tool.cpp b/src/ui/tools/tweak-tool.cpp index 94f7aa135..39a7a3f0b 100644 --- a/src/ui/tools/tweak-tool.cpp +++ b/src/ui/tools/tweak-tool.cpp @@ -1077,7 +1077,7 @@ sp_tweak_dilate (TweakTool *tc, Geom::Point event_p, Geom::Point p, Geom::Point double color_force = MIN(sqrt(path_force)/20.0, 1); std::vector<SPItem*> items=selection->itemList(); - for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++){ + for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end(); ++i){ SPItem *item = *i; if (is_color_mode (tc->mode)) { diff --git a/src/ui/uxmanager.cpp b/src/ui/uxmanager.cpp index 051df691e..036659661 100644 --- a/src/ui/uxmanager.cpp +++ b/src/ui/uxmanager.cpp @@ -244,12 +244,13 @@ void UXManagerImpl::delTrack( SPDesktopWidget* dtw ) void UXManagerImpl::connectToDesktop( vector<GtkWidget *> const & toolboxes, SPDesktop *desktop ) { - TrackItem &tracker = trackedBoxes[desktop]; - vector<GtkWidget*>& tracked = tracker.boxes; - if (desktop) + if (!desktop) { - tracker.destroyConn = desktop->connectDestroy(&desktopDestructHandler); + return; } + TrackItem &tracker = trackedBoxes[desktop]; + vector<GtkWidget*>& tracked = tracker.boxes; + tracker.destroyConn = desktop->connectDestroy(&desktopDestructHandler); for (vector<GtkWidget*>::const_iterator it = toolboxes.begin(); it != toolboxes.end(); ++it ) { GtkWidget* toolbox = *it; diff --git a/src/ui/view/edit-widget-interface.h b/src/ui/view/edit-widget-interface.h index 55683871d..fcba0c6da 100644 --- a/src/ui/view/edit-widget-interface.h +++ b/src/ui/view/edit-widget-interface.h @@ -116,6 +116,9 @@ struct EditWidgetInterface /// Toggle CMS on/off and set preference value accordingly virtual void toggleColorProfAdjust() = 0; + /// Toggle lock guides on/off and set namedview value accordingly + virtual void toggleGuidesLock() = 0; + /// Is CMS on/off virtual bool colorProfAdjustEnabled() = 0; diff --git a/src/ui/widget/color-entry.h b/src/ui/widget/color-entry.h index edabe1980..08537f26d 100644 --- a/src/ui/widget/color-entry.h +++ b/src/ui/widget/color-entry.h @@ -9,7 +9,7 @@ */ #ifndef SEEN_COLOR_ENTRY_H -#define SEEN_COLOR_ENTRY_H_ +#define SEEN_COLOR_ENTRY_H #include <gtkmm/entry.h> #include "ui/selected-color.h" diff --git a/src/ui/widget/font-variants.cpp b/src/ui/widget/font-variants.cpp index 5d1e40971..62598dead 100644 --- a/src/ui/widget/font-variants.cpp +++ b/src/ui/widget/font-variants.cpp @@ -35,41 +35,41 @@ namespace Widget { FontVariants::FontVariants () : Gtk::VBox (), - _ligatures_frame ( Glib::ustring(_("Ligatures" )) ), - _ligatures_common ( Glib::ustring(_("Common" )) ), - _ligatures_discretionary ( Glib::ustring(_("Discretionary")) ), - _ligatures_historical ( Glib::ustring(_("Historical" )) ), - _ligatures_contextual ( Glib::ustring(_("Contextual" )) ), - - _position_frame ( Glib::ustring(_("Position" )) ), - _position_normal ( Glib::ustring(_("Normal" )) ), - _position_sub ( Glib::ustring(_("Subscript" )) ), - _position_super ( Glib::ustring(_("Superscript" )) ), - - _caps_frame ( Glib::ustring(_("Capitals" )) ), - _caps_normal ( Glib::ustring(_("Normal" )) ), - _caps_small ( Glib::ustring(_("Small" )) ), - _caps_all_small ( Glib::ustring(_("All small" )) ), - _caps_petite ( Glib::ustring(_("Petite" )) ), - _caps_all_petite ( Glib::ustring(_("All petite" )) ), - _caps_unicase ( Glib::ustring(_("Unicase" )) ), - _caps_titling ( Glib::ustring(_("Titling" )) ), - - _numeric_frame ( Glib::ustring(_("Numeric" )) ), - _numeric_lining ( Glib::ustring(_("Lining" )) ), - _numeric_old_style ( Glib::ustring(_("Old Style" )) ), - _numeric_default_style ( Glib::ustring(_("Default Style")) ), - _numeric_proportional ( Glib::ustring(_("Proportional" )) ), - _numeric_tabular ( Glib::ustring(_("Tabular" )) ), - _numeric_default_width ( Glib::ustring(_("Default Width")) ), - _numeric_diagonal ( Glib::ustring(_("Diagonal" )) ), - _numeric_stacked ( Glib::ustring(_("Stacked" )) ), - _numeric_default_fractions( Glib::ustring(_("Default Fractions")) ), - _numeric_ordinal ( Glib::ustring(_("Ordinal" )) ), - _numeric_slashed_zero ( Glib::ustring(_("Slashed Zero" )) ), - - _feature_frame ( Glib::ustring(_("Feature Settings")) ), - _feature_label ( Glib::ustring(_("Selection has different Feature Settings!")) ), + _ligatures_frame ( Glib::ustring(C_("Font variant", "Ligatures" )) ), + _ligatures_common ( Glib::ustring(C_("Font variant", "Common" )) ), + _ligatures_discretionary ( Glib::ustring(C_("Font variant", "Discretionary")) ), + _ligatures_historical ( Glib::ustring(C_("Font variant", "Historical" )) ), + _ligatures_contextual ( Glib::ustring(C_("Font variant", "Contextual" )) ), + + _position_frame ( Glib::ustring(C_("Font variant", "Position" )) ), + _position_normal ( Glib::ustring(C_("Font variant", "Normal" )) ), + _position_sub ( Glib::ustring(C_("Font variant", "Subscript" )) ), + _position_super ( Glib::ustring(C_("Font variant", "Superscript" )) ), + + _caps_frame ( Glib::ustring(C_("Font variant", "Capitals" )) ), + _caps_normal ( Glib::ustring(C_("Font variant", "Normal" )) ), + _caps_small ( Glib::ustring(C_("Font variant", "Small" )) ), + _caps_all_small ( Glib::ustring(C_("Font variant", "All small" )) ), + _caps_petite ( Glib::ustring(C_("Font variant", "Petite" )) ), + _caps_all_petite ( Glib::ustring(C_("Font variant", "All petite" )) ), + _caps_unicase ( Glib::ustring(C_("Font variant", "Unicase" )) ), + _caps_titling ( Glib::ustring(C_("Font variant", "Titling" )) ), + + _numeric_frame ( Glib::ustring(C_("Font variant", "Numeric" )) ), + _numeric_lining ( Glib::ustring(C_("Font variant", "Lining" )) ), + _numeric_old_style ( Glib::ustring(C_("Font variant", "Old Style" )) ), + _numeric_default_style ( Glib::ustring(C_("Font variant", "Default Style")) ), + _numeric_proportional ( Glib::ustring(C_("Font variant", "Proportional" )) ), + _numeric_tabular ( Glib::ustring(C_("Font variant", "Tabular" )) ), + _numeric_default_width ( Glib::ustring(C_("Font variant", "Default Width")) ), + _numeric_diagonal ( Glib::ustring(C_("Font variant", "Diagonal" )) ), + _numeric_stacked ( Glib::ustring(C_("Font variant", "Stacked" )) ), + _numeric_default_fractions( Glib::ustring(C_("Font variant", "Default Fractions")) ), + _numeric_ordinal ( Glib::ustring(C_("Font variant", "Ordinal" )) ), + _numeric_slashed_zero ( Glib::ustring(C_("Font variant", "Slashed Zero" )) ), + + _feature_frame ( Glib::ustring(C_("Font variant", "Feature Settings")) ), + _feature_label ( Glib::ustring(C_("Font variant", "Selection has different Feature Settings!")) ), _ligatures_changed( false ), _position_changed( false ), diff --git a/src/unclump.cpp b/src/unclump.cpp index 81c958937..2c6840425 100644 --- a/src/unclump.cpp +++ b/src/unclump.cpp @@ -172,7 +172,7 @@ static double unclump_average (SPItem *item, std::list<SPItem*> &others) { int n = 0; double sum = 0; - for (std::list<SPItem*>::const_iterator i = others.begin(); i != others.end();i++) { + for (std::list<SPItem*>::const_iterator i = others.begin(); i != others.end();++i) { SPItem *other = *i; if (other == item) @@ -196,7 +196,7 @@ static SPItem *unclump_closest (SPItem *item, std::list<SPItem*> &others) double min = HUGE_VAL; SPItem *closest = NULL; - for (std::list<SPItem*>::const_iterator i = others.begin(); i != others.end();i++) { + for (std::list<SPItem*>::const_iterator i = others.begin(); i != others.end();++i) { SPItem *other = *i; if (other == item) @@ -219,7 +219,7 @@ static SPItem *unclump_farest (SPItem *item, std::list<SPItem*> &others) { double max = -HUGE_VAL; SPItem *farest = NULL; - for (std::list<SPItem*>::const_iterator i = others.begin(); i != others.end();i++) { + for (std::list<SPItem*>::const_iterator i = others.begin(); i != others.end();++i) { SPItem *other = *i; if (other == item) @@ -259,7 +259,7 @@ unclump_remove_behind (SPItem *item, SPItem *closest, std::list<SPItem*> &rest) double val_item = A * it[Geom::X] + B * it[Geom::Y] + C; std::vector<SPItem*> out; - for (std::list<SPItem*>::const_reverse_iterator i = rest.rbegin(); i != rest.rend();i++) { + for (std::list<SPItem*>::const_reverse_iterator i = rest.rbegin(); i != rest.rend();++i) { SPItem *other = *i; if (other == item) @@ -336,7 +336,7 @@ unclump (std::vector<SPItem*> &items) c_cache.clear(); wh_cache.clear(); - for (std::vector<SPItem*>::const_iterator i = items.begin(); i != items.end();i++) { // for each original/clone x: + for (std::vector<SPItem*>::const_iterator i = items.begin(); i != items.end();++i) { // for each original/clone x: SPItem *item = *i; std::list<SPItem*> nei; diff --git a/src/uri-references.cpp b/src/uri-references.cpp index 04f904d39..db46a156f 100644 --- a/src/uri-references.cpp +++ b/src/uri-references.cpp @@ -19,80 +19,105 @@ #include "uri.h" #include "uri-references.h" #include "extract-uri.h" - +#include "sp-tag-use.h" #include <glibmm/miscutils.h> #include <sigc++/functors/mem_fun.h> namespace Inkscape { URIReference::URIReference(SPObject *owner) - : _owner(owner), _owner_document(NULL), _obj(NULL), _uri(NULL) + : _owner(owner) + , _owner_document(NULL) + , _obj(NULL) + , _uri(NULL) { g_assert(_owner != NULL); /* FIXME !!! attach to owner's destroy signal to clean up in case */ } URIReference::URIReference(SPDocument *owner_document) - : _owner(NULL), _owner_document(owner_document), _obj(NULL), _uri(NULL) + : _owner(NULL) + , _owner_document(owner_document) + , _obj(NULL) + , _uri(NULL) { g_assert(_owner_document != NULL); } -URIReference::~URIReference() -{ - detach(); -} +URIReference::~URIReference() { detach(); } /* * The main ideas here are: * (1) "If we are inside a clone, then we can accept if and only if our "original thing" can accept the reference" - * (this caused problems when there are clones because a change in ids triggers signals for the object hrefing this id, but also its cloned reprs - * (descendants of <use> referencing an ancestor of the href'ing object)). The way it is done here is *atrocious*, but i could not find a better way. + * (this caused problems when there are clones because a change in ids triggers signals for the object hrefing this id, + *but also its cloned reprs + * (descendants of <use> referencing an ancestor of the href'ing object)). The way it is done here is *atrocious*, but i + *could not find a better way. * FIXME: find a better and safer way to find the "original object" of anyone with the flag ->cloned * - * (2) Once we have an (potential owner) object, it can accept a href to obj, iff the graph of objects where directed edges are + * (2) Once we have an (potential owner) object, it can accept a href to obj, iff the graph of objects where directed + *edges are * either parent->child relations , *** or href'ing to href'ed *** relations, stays acyclic. - * We can go either from owner and up in the tree, or from obj and down, in either case this will be in the worst case linear in the number of objects. - * There are no easy objects allowing to do the second proposition, while "hrefList" is a "list of objects href'ing us", so we'll take this. + * We can go either from owner and up in the tree, or from obj and down, in either case this will be in the worst case + *linear in the number of objects. + * There are no easy objects allowing to do the second proposition, while "hrefList" is a "list of objects href'ing us", + *so we'll take this. * Then we keep a set of already visited elements, and do a DFS on this graph. if we find obj, then BOOM. */ -bool URIReference::_acceptObject(SPObject *obj) const { - //we go back following hrefList and parent to find if the object already references ourselves indirectly - std::set<SPObject*> done; - SPObject * owner = getOwner(); - if(!owner)return true; - while(owner->cloned){ - std::vector<int> positions; - while(owner->cloned){ - int position=0; - SPObject* c = owner->parent->firstChild(); - while(c != owner && dynamic_cast<SPObject*>(c) ){position++;c=c->next;} - positions.push_back(position); - owner=owner->parent; - } - owner = ((SPUse*)owner)->get_original(); - for(int i=positions.size()-2;i>=0;i--)owner=owner->childList(false)[positions[i]]; - } - //once we have the "original" object (hopefully) we look at who is referencing it - std::list<SPObject*> todo(owner->hrefList); - todo.push_front(owner->parent); - while(!todo.empty()){ - SPObject* e = todo.front(); - todo.pop_front(); - if(!dynamic_cast<SPObject*>(e))continue; - if(done.insert(e).second){ - if(e==obj){return false;} - todo.push_front(e->parent); - todo.insert(todo.begin(),e->hrefList.begin(),e->hrefList.end()); - } - } +bool URIReference::_acceptObject(SPObject *obj) const +{ + // we go back following hrefList and parent to find if the object already references ourselves indirectly + std::set<SPObject *> done; + SPObject *owner = getOwner(); + if (!owner) + return true; + while (owner->cloned) { + std::vector<int> positions; + while (owner->cloned) { + int position = 0; + SPObject *c = owner->parent->firstChild(); + while (c != owner && dynamic_cast<SPObject *>(c)) { + position++; + c = c->next; + } + positions.push_back(position); + owner = owner->parent; + } + if (dynamic_cast<SPUse *>(owner)) + owner = ((SPUse *)owner)->get_original(); + else if (dynamic_cast<SPTagUse *>(owner)) + owner = ((SPTagUse *)owner)->get_original(); + else { + g_warning("cloned object with no known type\n"); + return false; + } + for (int i = positions.size() - 2; i >= 0; i--) + owner = owner->childList(false)[positions[i]]; + } + // once we have the "original" object (hopefully) we look at who is referencing it + if (obj == owner) + return false; + std::list<SPObject *> todo(owner->hrefList); + todo.push_front(owner->parent); + while (!todo.empty()) { + SPObject *e = todo.front(); + todo.pop_front(); + if (!dynamic_cast<SPObject *>(e)) + continue; + if (done.insert(e).second) { + if (e == obj) { + return false; + } + todo.push_front(e->parent); + todo.insert(todo.begin(), e->hrefList.begin(), e->hrefList.end()); + } + } return true; } - void URIReference::attach(const URI &uri) throw(BadURIException) { SPDocument *document = NULL; @@ -108,32 +133,30 @@ void URIReference::attach(const URI &uri) throw(BadURIException) // PNG and JPG files are allowed (in the case of feImage). gchar *filename = uri.toString(); bool skip = false; - if( g_str_has_suffix( filename, ".jpg" ) || - g_str_has_suffix( filename, ".JPG" ) || - g_str_has_suffix( filename, ".png" ) || - g_str_has_suffix( filename, ".PNG" ) ) { + if (g_str_has_suffix(filename, ".jpg") || g_str_has_suffix(filename, ".JPG") || + g_str_has_suffix(filename, ".png") || g_str_has_suffix(filename, ".PNG")) { skip = true; } - + // The path contains references to separate document files to load. - if(document && uri.getPath() && !skip ) { + if (document && uri.getPath() && !skip) { std::string base = document->getBase() ? document->getBase() : ""; std::string path = uri.getFullPath(base); - if(!path.empty()) { + if (!path.empty()) { document = document->createChildDoc(path); } else { document = NULL; } } - if(!document) { + if (!document) { g_warning("Can't get document for referenced URI: %s", filename); - g_free( filename ); + g_free(filename); return; } - g_free( filename ); + g_free(filename); gchar const *fragment = uri.getFragment(); - if ( !uri.isRelative() || uri.getQuery() || !fragment ) { + if (!uri.isRelative() || uri.getQuery() || !fragment) { throw UnsupportedURIException(); } @@ -148,9 +171,9 @@ void URIReference::attach(const URI &uri) throw(BadURIException) the strlen calculation and validity testing to before strdup, and copying just the id without the "))". -- pjrm */ if (!strncmp(fragment, "xpointer(id(", 12)) { - id = g_strdup(fragment+12); + id = g_strdup(fragment + 12); size_t const len = strlen(id); - if ( len < 3 || strcmp(id+len-2, "))") ) { + if (len < 3 || strcmp(id + len - 2, "))")) { g_free(id); throw MalformedURIException(); } @@ -183,13 +206,14 @@ void URIReference::detach() void URIReference::_setObject(SPObject *obj) { - if ( obj && !_acceptObject(obj) ) { + if (obj && !_acceptObject(obj)) { obj = NULL; } - if ( obj == _obj ) return; + if (obj == _obj) + return; - SPObject *old_obj=_obj; + SPObject *old_obj = _obj; _obj = obj; _release_connection.disconnect(); @@ -210,7 +234,7 @@ void URIReference::_setObject(SPObject *obj) */ void URIReference::_release(SPObject *obj) { - g_assert( _obj == obj ); + g_assert(_obj == obj); _setObject(NULL); } @@ -218,28 +242,27 @@ void URIReference::_release(SPObject *obj) -SPObject* sp_css_uri_reference_resolve( SPDocument *document, const gchar *uri ) +SPObject *sp_css_uri_reference_resolve(SPDocument *document, const gchar *uri) { - SPObject* ref = NULL; + SPObject *ref = NULL; - if ( document && uri && ( strncmp(uri, "url(", 4) == 0 ) ) { - gchar *trimmed = extract_uri( uri ); - if ( trimmed ) { - ref = sp_uri_reference_resolve( document, trimmed ); - g_free( trimmed ); + if (document && uri && (strncmp(uri, "url(", 4) == 0)) { + gchar *trimmed = extract_uri(uri); + if (trimmed) { + ref = sp_uri_reference_resolve(document, trimmed); + g_free(trimmed); } } return ref; } -SPObject * -sp_uri_reference_resolve (SPDocument *document, const gchar *uri) +SPObject *sp_uri_reference_resolve(SPDocument *document, const gchar *uri) { - SPObject* ref = NULL; + SPObject *ref = NULL; - if ( uri && (*uri == '#') ) { - ref = document->getObjectById( uri + 1 ); + if (uri && (*uri == '#')) { + ref = document->getObjectById(uri + 1); } return ref; diff --git a/src/uri.cpp b/src/uri.cpp index 2eaf4ecc1..49bdab63c 100644 --- a/src/uri.cpp +++ b/src/uri.cpp @@ -148,7 +148,7 @@ gchar *URI::to_native_filename(gchar const* uri) throw(BadURIException) * Does not check if the returned path is the local document's path (local) * and thus redundent. Caller is expected to check against the document's path. */ -const std::string URI::getFullPath(std::string const base) const { +const std::string URI::getFullPath(std::string const &base) const { if (!_impl->getPath()) { return ""; } @@ -104,7 +104,7 @@ public: static char *to_native_filename(char const* uri) throw(BadURIException); - const std::string getFullPath(std::string const base) const; + const std::string getFullPath(std::string const &base) const; char *toNativeFilename() const throw(BadURIException); diff --git a/src/vanishing-point.cpp b/src/vanishing-point.cpp index 553e3a31d..19750bd37 100644 --- a/src/vanishing-point.cpp +++ b/src/vanishing-point.cpp @@ -259,7 +259,7 @@ std::list<SPBox3D *> VanishingPoint::selectedBoxes(Inkscape::Selection *sel) { std::list<SPBox3D *> sel_boxes; std::vector<SPItem*> itemlist=sel->itemList(); - for (std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++) { + for (std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();++i) { SPItem *item = *i; SPBox3D *box = dynamic_cast<SPBox3D *>(item); if (box && this->hasBox(box)) { @@ -399,7 +399,7 @@ VPDragger::VPsOfSelectedBoxes() { // FIXME: Should we take the selection from the parent VPDrag? I guess it shouldn't make a difference. Inkscape::Selection *sel = SP_ACTIVE_DESKTOP->getSelection(); std::vector<SPItem*> itemlist=sel->itemList(); - for (std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++) { + for (std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();++i) { SPItem *item = *i; SPBox3D *box = dynamic_cast<SPBox3D *>(item); if (box) { @@ -582,7 +582,7 @@ VPDrag::updateDraggers () g_return_if_fail (this->selection != NULL); std::vector<SPItem*> itemlist=this->selection->itemList(); - for (std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++) { + for (std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();++i) { SPItem *item = *i; SPBox3D *box = dynamic_cast<SPBox3D *>(item); if (box) { @@ -615,7 +615,7 @@ VPDrag::updateLines () g_return_if_fail (this->selection != NULL); std::vector<SPItem*> itemlist=this->selection->itemList(); - for (std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++) { + for (std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();++i) { SPItem *item = *i; SPBox3D *box = dynamic_cast<SPBox3D *>(item); if (box) { diff --git a/src/verbs.cpp b/src/verbs.cpp index e0ef27b0d..ed4b1ceb0 100644 --- a/src/verbs.cpp +++ b/src/verbs.cpp @@ -832,7 +832,14 @@ Verb *Verb::getbyid(gchar const *id) verb = verb_found->second; } - if (verb == NULL) + if (verb == NULL +#if !HAVE_POTRACE + // Squash warning about disabled features + && strcmp(id, "ToolPaintBucket") != 0 + && strcmp(id, "SelectionTrace") != 0 + && strcmp(id, "PaintBucketPrefs") != 0 +#endif + ) printf("Unable to find: %s\n", id); return verb; @@ -945,6 +952,10 @@ void EditVerb::perform(SPAction *action, void *data) g_return_if_fail(ensure_desktop_valid(action)); SPDesktop *dt = sp_action_get_desktop(action); + SPDocument *doc = dt->getDocument(); + + Inkscape::XML::Node *repr = dt->namedview->getRepr(); + switch (reinterpret_cast<std::size_t>(data)) { case SP_VERB_EDIT_UNDO: sp_undo(dt, dt->getDocument()); @@ -1072,10 +1083,12 @@ void EditVerb::perform(SPAction *action, void *data) case SP_VERB_EDIT_DELETE_ALL_GUIDES: sp_guide_delete_all_guides(dt); break; + case SP_VERB_EDIT_GUIDES_TOGGLE_LOCK: + dt->toggleGuidesLock(); + break; case SP_VERB_EDIT_GUIDES_AROUND_PAGE: sp_guide_create_guides_around_page(dt); break; - case SP_VERB_EDIT_NEXT_PATHEFFECT_PARAMETER: sp_selection_next_patheffect_param(dt); break; @@ -1201,10 +1214,14 @@ void SelectionVerb::perform(SPAction *action, void *data) case SP_VERB_SELECTION_REVERSE: SelectionHelper::reverse(dt); break; + +#if HAVE_POTRACE case SP_VERB_SELECTION_TRACE: INKSCAPE.dialogs_unhide(); dt->_dlg_mgr->showDialog("Trace"); break; +#endif + case SP_VERB_SELECTION_PIXEL_ART: INKSCAPE.dialogs_unhide(); dt->_dlg_mgr->showDialog("PixelArt"); @@ -1606,7 +1623,7 @@ void ContextVerb::perform(SPAction *action, void *data) /** \todo !!! hopefully this can go away soon and actions can look after * themselves */ - for (vidx = SP_VERB_CONTEXT_SELECT; vidx <= SP_VERB_CONTEXT_PAINTBUCKET_PREFS; vidx++) + for (vidx = SP_VERB_CONTEXT_SELECT; vidx <= SP_VERB_CONTEXT_LPETOOL_PREFS; vidx++) { SPAction *tool_action= get((sp_verb_t)vidx)->get_action(action->context); if (tool_action) { @@ -1673,9 +1690,13 @@ void ContextVerb::perform(SPAction *action, void *data) case SP_VERB_CONTEXT_CONNECTOR: tools_switch(dt, TOOLS_CONNECTOR); break; + +#if HAVE_POTRACE case SP_VERB_CONTEXT_PAINTBUCKET: tools_switch(dt, TOOLS_PAINTBUCKET); break; +#endif + case SP_VERB_CONTEXT_ERASER: tools_switch(dt, TOOLS_ERASER); break; @@ -1759,10 +1780,14 @@ void ContextVerb::perform(SPAction *action, void *data) prefs->setInt("/dialogs/preferences/page", PREFS_PAGE_TOOLS_CONNECTOR); dt->_dlg_mgr->showDialog("InkscapePreferences"); break; + +#if HAVE_POTRACE case SP_VERB_CONTEXT_PAINTBUCKET_PREFS: prefs->setInt("/dialogs/preferences/page", PREFS_PAGE_TOOLS_PAINTBUCKET); dt->_dlg_mgr->showDialog("InkscapePreferences"); break; +#endif + case SP_VERB_CONTEXT_ERASER_PREFS: prefs->setInt("/dialogs/preferences/page", PREFS_PAGE_TOOLS_ERASER); dt->_dlg_mgr->showDialog("InkscapePreferences"); @@ -2160,10 +2185,14 @@ void TutorialVerb::perform(SPAction *action, void *data) // TRANSLATORS: See "tutorial-basic.svg" comment. sp_help_open_tutorial(NULL, (gpointer)_("tutorial-advanced.svg")); break; + +#if HAVE_POTRACE case SP_VERB_TUTORIAL_TRACING: // TRANSLATORS: See "tutorial-basic.svg" comment. sp_help_open_tutorial(NULL, (gpointer)_("tutorial-tracing.svg")); break; +#endif + case SP_VERB_TUTORIAL_TRACING_PIXELART: sp_help_open_tutorial(NULL, (gpointer)_("tutorial-tracing-pixelart.svg")); break; @@ -2517,6 +2546,7 @@ Verb *Verb::_base_verbs[] = { N_("Deselect any selected objects or nodes"), INKSCAPE_ICON("edit-select-none")), new EditVerb(SP_VERB_EDIT_DELETE_ALL_GUIDES, "EditRemoveAllGuides", N_("Delete All Guides"), N_("Delete all the guides in the document"), NULL), + new EditVerb(SP_VERB_EDIT_GUIDES_TOGGLE_LOCK, "EditGuidesToggleLock", N_("Lock All Guides"), N_("Toggle lock of all guides in the document"), NULL), new EditVerb(SP_VERB_EDIT_GUIDES_AROUND_PAGE, "EditGuidesAroundPage", N_("Create _Guides Around the Page"), N_("Create four guides aligned with the page borders"), NULL), new EditVerb(SP_VERB_EDIT_NEXT_PATHEFFECT_PARAMETER, "EditNextPathEffectParameter", N_("Next path effect parameter"), @@ -2593,9 +2623,13 @@ Verb *Verb::_base_verbs[] = { N_("Simplify selected paths (remove extra nodes)"), INKSCAPE_ICON("path-simplify")), new SelectionVerb(SP_VERB_SELECTION_REVERSE, "SelectionReverse", N_("_Reverse"), N_("Reverse the direction of selected paths (useful for flipping markers)"), INKSCAPE_ICON("path-reverse")), + +#if HAVE_POTRACE // TRANSLATORS: "to trace" means "to convert a bitmap to vector graphics" (to vectorize) new SelectionVerb(SP_VERB_SELECTION_TRACE, "SelectionTrace", N_("_Trace Bitmap..."), N_("Create one or more paths from a bitmap by tracing it"), INKSCAPE_ICON("bitmap-trace")), +#endif + new SelectionVerb(SP_VERB_SELECTION_PIXEL_ART, "SelectionPixelArt", N_("Trace Pixel Art..."), N_("Create paths using Kopf-Lischinski algorithm to vectorize pixel art"), INKSCAPE_ICON("pixelart-trace")), new SelectionVerb(SP_VERB_SELECTION_CREATE_BITMAP, "SelectionCreateBitmap", N_("Make a _Bitmap Copy"), @@ -2733,8 +2767,12 @@ Verb *Verb::_base_verbs[] = { N_("Pick colors from image"), INKSCAPE_ICON("color-picker")), new ContextVerb(SP_VERB_CONTEXT_CONNECTOR, "ToolConnector", NC_("ContextVerb", "Connector"), N_("Create diagram connectors"), INKSCAPE_ICON("draw-connector")), + +#if HAVE_POTRACE new ContextVerb(SP_VERB_CONTEXT_PAINTBUCKET, "ToolPaintBucket", NC_("ContextVerb", "Paint Bucket"), N_("Fill bounded areas"), INKSCAPE_ICON("color-fill")), +#endif + new ContextVerb(SP_VERB_CONTEXT_LPE, "ToolLPE", NC_("ContextVerb", "LPE Edit"), N_("Edit Path Effect parameters"), NULL), new ContextVerb(SP_VERB_CONTEXT_ERASER, "ToolEraser", NC_("ContextVerb", "Eraser"), @@ -2780,8 +2818,12 @@ Verb *Verb::_base_verbs[] = { N_("Open Preferences for the Dropper tool"), NULL), new ContextVerb(SP_VERB_CONTEXT_CONNECTOR_PREFS, "ConnectorPrefs", N_("Connector Preferences"), N_("Open Preferences for the Connector tool"), NULL), + +#if HAVE_POTRACE new ContextVerb(SP_VERB_CONTEXT_PAINTBUCKET_PREFS, "PaintBucketPrefs", N_("Paint Bucket Preferences"), N_("Open Preferences for the Paint Bucket tool"), NULL), +#endif + new ContextVerb(SP_VERB_CONTEXT_ERASER_PREFS, "EraserPrefs", N_("Eraser Preferences"), N_("Open Preferences for the Eraser tool"), NULL), new ContextVerb(SP_VERB_CONTEXT_LPETOOL_PREFS, "LPEToolPrefs", N_("LPE Tool Preferences"), @@ -2937,9 +2979,13 @@ Verb *Verb::_base_verbs[] = { N_("Using shape tools to create and edit shapes"), NULL), new TutorialVerb(SP_VERB_TUTORIAL_ADVANCED, "TutorialsAdvanced", N_("Inkscape: _Advanced"), N_("Advanced Inkscape topics"), NULL/*"tutorial_advanced"*/), + +#if HAVE_POTRACE // TRANSLATORS: "to trace" means "to convert a bitmap to vector graphics" (to vectorize) new TutorialVerb(SP_VERB_TUTORIAL_TRACING, "TutorialsTracing", N_("Inkscape: T_racing"), N_("Using bitmap tracing"), NULL/*"tutorial_tracing"*/), +#endif + new TutorialVerb(SP_VERB_TUTORIAL_TRACING_PIXELART, "TutorialsTracingPixelArt", N_("Inkscape: Tracing Pixel Art"), N_("Using Trace Pixel Art dialog"), NULL), new TutorialVerb(SP_VERB_TUTORIAL_CALLIGRAPHY, "TutorialsCalligraphy", N_("Inkscape: _Calligraphy"), diff --git a/src/verbs.h b/src/verbs.h index 06fc4fb05..e16acb2d1 100644 --- a/src/verbs.h +++ b/src/verbs.h @@ -107,6 +107,7 @@ enum { SP_VERB_EDIT_SELECT_PREV, SP_VERB_EDIT_DESELECT, SP_VERB_EDIT_DELETE_ALL_GUIDES, + SP_VERB_EDIT_GUIDES_TOGGLE_LOCK, SP_VERB_EDIT_GUIDES_AROUND_PAGE, SP_VERB_EDIT_NEXT_PATHEFFECT_PARAMETER, /* Selection */ @@ -136,7 +137,11 @@ enum { SP_VERB_SELECTION_OUTLINE, SP_VERB_SELECTION_SIMPLIFY, SP_VERB_SELECTION_REVERSE, + +#if HAVE_POTRACE SP_VERB_SELECTION_TRACE, +#endif + SP_VERB_SELECTION_PIXEL_ART, SP_VERB_SELECTION_CREATE_BITMAP, SP_VERB_SELECTION_COMBINE, @@ -203,7 +208,11 @@ enum { SP_VERB_CONTEXT_MEASURE, SP_VERB_CONTEXT_DROPPER, SP_VERB_CONTEXT_CONNECTOR, + +#if HAVE_POTRACE SP_VERB_CONTEXT_PAINTBUCKET, +#endif + SP_VERB_CONTEXT_LPE, /* not really a tool but used for editing LPE parameters on-canvas for example */ SP_VERB_CONTEXT_ERASER, SP_VERB_CONTEXT_LPETOOL, /* note that this is very different from SP_VERB_CONTEXT_LPE above! */ @@ -227,7 +236,11 @@ enum { SP_VERB_CONTEXT_MEASURE_PREFS, SP_VERB_CONTEXT_DROPPER_PREFS, SP_VERB_CONTEXT_CONNECTOR_PREFS, + +#if HAVE_POTRACE SP_VERB_CONTEXT_PAINTBUCKET_PREFS, +#endif + SP_VERB_CONTEXT_ERASER_PREFS, SP_VERB_CONTEXT_LPETOOL_PREFS, /* Zooming and desktop settings */ @@ -311,7 +324,11 @@ enum { SP_VERB_TUTORIAL_BASIC, SP_VERB_TUTORIAL_SHAPES, SP_VERB_TUTORIAL_ADVANCED, + +#if HAVE_POTRACE SP_VERB_TUTORIAL_TRACING, +#endif + SP_VERB_TUTORIAL_TRACING_PIXELART, SP_VERB_TUTORIAL_CALLIGRAPHY, SP_VERB_TUTORIAL_INTERPOLATE, diff --git a/src/widgets/CMakeLists.txt b/src/widgets/CMakeLists.txt index a3e9e14d0..c38bde5cf 100644 --- a/src/widgets/CMakeLists.txt +++ b/src/widgets/CMakeLists.txt @@ -11,7 +11,6 @@ set(widgets_SRC measure-toolbar.cpp mesh-toolbar.cpp node-toolbar.cpp - paintbucket-toolbar.cpp pencil-toolbar.cpp rect-toolbar.cpp spiral-toolbar.cpp @@ -67,7 +66,6 @@ set(widgets_SRC measure-toolbar.h mesh-toolbar.h node-toolbar.h - paintbucket-toolbar.h pencil-toolbar.h rect-toolbar.h spiral-toolbar.h @@ -114,3 +112,12 @@ set(widgets_SRC # add_inkscape_lib(widgets_LIB "${widgets_SRC}") add_inkscape_source("${widgets_SRC}") + +set ( widgets_paintbucket_SRC + paintbucket-toolbar.cpp + paintbucket-toolbar.h +) + +if ("${HAVE_POTRACE}") + add_inkscape_source("${widgets_paintbucket_SRC}") +endif() diff --git a/src/widgets/Makefile_insert b/src/widgets/Makefile_insert index f66be66ed..6913f4a58 100644 --- a/src/widgets/Makefile_insert +++ b/src/widgets/Makefile_insert @@ -58,8 +58,6 @@ ink_common_sources += \ widgets/node-toolbar.h \ widgets/paint-selector.cpp \ widgets/paint-selector.h \ - widgets/paintbucket-toolbar.cpp \ - widgets/paintbucket-toolbar.h \ widgets/pencil-toolbar.cpp \ widgets/pencil-toolbar.h \ widgets/rect-toolbar.cpp \ @@ -109,5 +107,13 @@ ink_common_sources += \ widgets/zoom-toolbar.h \ widgets/widget-sizes.h +if HAVE_POTRACE + +ink_common_sources += \ + widgets/paintbucket-toolbar.cpp \ + widgets/paintbucket-toolbar.h + +endif + widgets/button.$(OBJEXT): helper/sp-marshal.h widgets/menu.$(OBJEXT): helper/sp-marshal.h diff --git a/src/widgets/arc-toolbar.cpp b/src/widgets/arc-toolbar.cpp index 71418e238..7b872e8b1 100644 --- a/src/widgets/arc-toolbar.cpp +++ b/src/widgets/arc-toolbar.cpp @@ -98,7 +98,7 @@ sp_arctb_startend_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *v bool modmade = false; std::vector<SPItem*> itemlist=desktop->getSelection()->itemList(); - for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();++i){ SPItem *item = *i; if (SP_IS_GENERICELLIPSE(item)) { @@ -164,7 +164,7 @@ static void sp_arctb_open_state_changed( EgeSelectOneAction *act, GObject *tbl ) if ( ege_select_one_action_get_active(act) != 0 ) { std::vector<SPItem*> itemlist=desktop->getSelection()->itemList(); - for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();++i){ SPItem *item = *i; if (SP_IS_GENERICELLIPSE(item)) { Inkscape::XML::Node *repr = item->getRepr(); @@ -175,7 +175,7 @@ static void sp_arctb_open_state_changed( EgeSelectOneAction *act, GObject *tbl ) } } else { std::vector<SPItem*> itemlist=desktop->getSelection()->itemList(); - for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();++i){ SPItem *item = *i; if (SP_IS_GENERICELLIPSE(item)) { Inkscape::XML::Node *repr = item->getRepr(); @@ -265,7 +265,7 @@ static void sp_arc_toolbox_selection_changed(Inkscape::Selection *selection, GOb purge_repr_listener( tbl, tbl ); std::vector<SPItem*> itemlist=selection->itemList(); - for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();++i){ SPItem *item = *i; if (SP_IS_GENERICELLIPSE(item)) { n_selected++; diff --git a/src/widgets/connector-toolbar.cpp b/src/widgets/connector-toolbar.cpp index 1c99f283d..8cc254bd2 100644 --- a/src/widgets/connector-toolbar.cpp +++ b/src/widgets/connector-toolbar.cpp @@ -98,7 +98,7 @@ static void sp_connector_orthogonal_toggled( GtkToggleAction* act, GObject *tbl bool modmade = false; std::vector<SPItem*> itemlist=desktop->getSelection()->itemList(); - for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();++i){ SPItem *item = *i; if (Inkscape::UI::Tools::cc_item_is_connector(item)) { @@ -145,7 +145,7 @@ static void connector_curvature_changed(GtkAdjustment *adj, GObject* tbl) bool modmade = false; std::vector<SPItem*> itemlist=desktop->getSelection()->itemList(); - for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();++i){ SPItem *item = *i; if (Inkscape::UI::Tools::cc_item_is_connector(item)) { diff --git a/src/widgets/desktop-widget.cpp b/src/widgets/desktop-widget.cpp index e19f56e48..fd2847506 100644 --- a/src/widgets/desktop-widget.cpp +++ b/src/widgets/desktop-widget.cpp @@ -107,6 +107,7 @@ static void sp_desktop_widget_realize (GtkWidget *widget); static gint sp_desktop_widget_event (GtkWidget *widget, GdkEvent *event, SPDesktopWidget *dtw); static void sp_dtw_color_profile_event(EgeColorProfTracker *widget, SPDesktopWidget *dtw); +static void sp_update_guides_lock( GtkWidget *button, gpointer data ); #if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) static void cms_adjust_toggled( GtkWidget *button, gpointer data ); #endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) @@ -390,6 +391,21 @@ void SPDesktopWidget::init( SPDesktopWidget *dtw ) dtw->tool_toolbox = ToolboxFactory::createToolToolbox(); ToolboxFactory::setOrientation( dtw->tool_toolbox, GTK_ORIENTATION_VERTICAL ); gtk_box_pack_start( GTK_BOX(dtw->hbox), dtw->tool_toolbox, FALSE, TRUE, 0 ); + /* Lock all guides */ +#if GTK_CHECK_VERSION(3,0,0) + dtw->lock_and_hruler = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); +#else + dtw->lock_and_hruler = gtk_hbox_new (FALSE, 0); +#endif + // Lock guides button + dtw->guides_lock = sp_button_new_from_data( Inkscape::ICON_SIZE_DECORATION, + SP_BUTTON_TYPE_TOGGLE, + NULL, + INKSCAPE_ICON("object-locked"), + _("Toggle lock of all guides in the document")); + + gtk_box_pack_start (GTK_BOX (dtw->lock_and_hruler), dtw->guides_lock, FALSE, FALSE, 0); + g_signal_connect (G_OBJECT (dtw->guides_lock), "toggled", G_CALLBACK (sp_update_guides_lock), dtw); /* Horizontal ruler */ GtkWidget *eventbox = gtk_event_box_new (); @@ -399,6 +415,7 @@ void SPDesktopWidget::init( SPDesktopWidget *dtw ) sp_ruler_set_unit(SP_RULER(dtw->hruler), pt); gtk_widget_set_tooltip_text (dtw->hruler_box, gettext(pt->name_plural.c_str())); gtk_container_add (GTK_CONTAINER (eventbox), dtw->hruler); + gtk_container_add (GTK_CONTAINER (dtw->lock_and_hruler), eventbox); g_signal_connect (G_OBJECT (eventbox), "button_press_event", G_CALLBACK (sp_dt_hruler_event), dtw); g_signal_connect (G_OBJECT (eventbox), "button_release_event", G_CALLBACK (sp_dt_hruler_event), dtw); g_signal_connect (G_OBJECT (eventbox), "motion_notify_event", G_CALLBACK (sp_dt_hruler_event), dtw); @@ -407,23 +424,25 @@ void SPDesktopWidget::init( SPDesktopWidget *dtw ) GtkWidget *tbl = gtk_grid_new(); dtw->canvas_tbl = gtk_grid_new(); - gtk_grid_attach(GTK_GRID(dtw->canvas_tbl), eventbox, 1, 0, 1, 1); + gtk_grid_attach(GTK_GRID(dtw->canvas_tbl), dtw->lock_and_hruler, 0, 0, 1, 1); #else GtkWidget *tbl = gtk_table_new(2, 3, FALSE); dtw->canvas_tbl = gtk_table_new(3, 3, FALSE); gtk_table_attach(GTK_TABLE(dtw->canvas_tbl), - eventbox, - 1, 2, 0, 1, + dtw->lock_and_hruler, + 0, 2, 0, 1, GTK_FILL, GTK_FILL, 0, 0); #endif - + gtk_box_pack_start( GTK_BOX(dtw->hbox), tbl, TRUE, TRUE, 1 ); /* Vertical ruler */ eventbox = gtk_event_box_new (); dtw->vruler = sp_ruler_new(GTK_ORIENTATION_VERTICAL); + + /* Vertical ruler */ dtw->vruler_box = eventbox; sp_ruler_set_unit (SP_RULER (dtw->vruler), pt); gtk_widget_set_tooltip_text (dtw->vruler_box, gettext(pt->name_plural.c_str())); @@ -446,6 +465,9 @@ void SPDesktopWidget::init( SPDesktopWidget *dtw ) // Horizontal scrollbar dtw->hadj = GTK_ADJUSTMENT(gtk_adjustment_new(0.0, -4000.0, 4000.0, 10.0, 100.0, 4.0)); + + + #if GTK_CHECK_VERSION(3,0,0) dtw->hscrollbar = gtk_scrollbar_new(GTK_ORIENTATION_HORIZONTAL, GTK_ADJUSTMENT (dtw->hadj)); gtk_grid_attach(GTK_GRID(dtw->canvas_tbl), dtw->hscrollbar, 1, 2, 1, 1); @@ -1015,6 +1037,7 @@ sp_desktop_widget_event (GtkWidget *widget, GdkEvent *event, SPDesktopWidget *dt return FALSE; } + #if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) void sp_dtw_color_profile_event(EgeColorProfTracker */*tracker*/, SPDesktopWidget *dtw) { @@ -1036,6 +1059,27 @@ void sp_dtw_color_profile_event(EgeColorProfTracker */*tracker*/, SPDesktopWidge } #endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) +void sp_update_guides_lock( GtkWidget */*button*/, gpointer data ) +{ + SPDesktopWidget *dtw = SP_DESKTOP_WIDGET(data); + + bool down = SP_BUTTON_IS_DOWN(dtw->guides_lock); + + SPDocument *doc = dtw->desktop->getDocument(); + SPNamedView *nv = dtw->desktop->getNamedView(); + Inkscape::XML::Node *repr = nv->getRepr(); + + if ( down != nv->lockguides ) { + nv->lockguides = down; + sp_namedview_guides_toggle_lock(doc, repr); + if (down) { + dtw->setMessage (Inkscape::NORMAL_MESSAGE, _("Locked all guides")); + } else { + dtw->setMessage (Inkscape::NORMAL_MESSAGE, _("Unlocked all guides")); + } + } +} + #if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) void cms_adjust_toggled( GtkWidget */*button*/, gpointer data ) { @@ -1549,10 +1593,10 @@ void SPDesktopWidget::layoutWidgets() } if (!prefs->getBool(pref_root + "rulers/state", true)) { - gtk_widget_hide (dtw->hruler); + gtk_widget_hide (dtw->lock_and_hruler); gtk_widget_hide (dtw->vruler); } else { - gtk_widget_show_all (dtw->hruler); + gtk_widget_show_all (dtw->lock_and_hruler); gtk_widget_show_all (dtw->vruler); } } @@ -1684,6 +1728,7 @@ SPDesktopWidget* SPDesktopWidget::createInstance(SPNamedView *namedview) /* Once desktop is set, we can update rulers */ sp_desktop_widget_update_rulers (dtw); + sp_button_toggle_set_down( SP_BUTTON(dtw->guides_lock), namedview->lockguides ); sp_view_widget_set_view (SP_VIEW_WIDGET (dtw), dtw->desktop); @@ -2039,12 +2084,12 @@ void sp_desktop_widget_toggle_rulers (SPDesktopWidget *dtw) { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - if (gtk_widget_get_visible (dtw->hruler)) { - gtk_widget_hide (dtw->hruler); + if (gtk_widget_get_visible (dtw->lock_and_hruler)) { + gtk_widget_hide (dtw->lock_and_hruler); gtk_widget_hide (dtw->vruler); prefs->setBool(dtw->desktop->is_fullscreen() ? "/fullscreen/rulers/state" : "/window/rulers/state", false); } else { - gtk_widget_show_all (dtw->hruler); + gtk_widget_show_all (dtw->lock_and_hruler); gtk_widget_show_all (dtw->vruler); prefs->setBool(dtw->desktop->is_fullscreen() ? "/fullscreen/rulers/state" : "/window/rulers/state", true); } @@ -2075,7 +2120,6 @@ bool sp_desktop_widget_color_prof_adj_enabled( SPDesktopWidget *dtw ) void sp_desktop_widget_toggle_color_prof_adj( SPDesktopWidget *dtw ) { - if ( gtk_widget_get_sensitive( dtw->cms_adjust ) ) { if ( SP_BUTTON_IS_DOWN(dtw->cms_adjust) ) { sp_button_toggle_set_down( SP_BUTTON(dtw->cms_adjust), FALSE ); @@ -2085,6 +2129,14 @@ void sp_desktop_widget_toggle_color_prof_adj( SPDesktopWidget *dtw ) } } +void sp_desktop_widget_toggle_guides_lock( SPDesktopWidget *dtw ) +{ + if ( SP_BUTTON_IS_DOWN(dtw->guides_lock) ) { + sp_button_toggle_set_down( SP_BUTTON(dtw->guides_lock), FALSE ); + } else { + sp_button_toggle_set_down( SP_BUTTON(dtw->guides_lock), TRUE ); + } +} /* Unused void sp_spw_toggle_menubar (SPDesktopWidget *dtw, bool is_fullscreen) diff --git a/src/widgets/desktop-widget.h b/src/widgets/desktop-widget.h index 489217d9a..bb5834165 100644 --- a/src/widgets/desktop-widget.h +++ b/src/widgets/desktop-widget.h @@ -49,6 +49,7 @@ void sp_desktop_widget_toggle_rulers (SPDesktopWidget *dtw); void sp_desktop_widget_toggle_scrollbars (SPDesktopWidget *dtw); void sp_desktop_widget_update_scrollbars (SPDesktopWidget *dtw, double scale); void sp_desktop_widget_toggle_color_prof_adj( SPDesktopWidget *dtw ); +void sp_desktop_widget_toggle_guides_lock( SPDesktopWidget *dtw ); bool sp_desktop_widget_color_prof_adj_enabled( SPDesktopWidget *dtw ); void sp_dtw_desktop_activate (SPDesktopWidget *dtw); @@ -87,6 +88,8 @@ struct SPDesktopWidget { GtkWidget *hruler, *vruler; GtkWidget *hruler_box, *vruler_box; // eventboxes for setting tooltips + GtkWidget *guides_lock; + GtkWidget *lock_and_hruler; GtkWidget *sticky_zoom; GtkWidget *cms_adjust; GtkWidget *coord_status; @@ -181,6 +184,8 @@ struct SPDesktopWidget { { sp_desktop_widget_toggle_scrollbars (_dtw); } virtual void toggleColorProfAdjust() { sp_desktop_widget_toggle_color_prof_adj(_dtw); } + virtual void toggleGuidesLock() + { sp_desktop_widget_toggle_guides_lock(_dtw); } virtual bool colorProfAdjustEnabled() { return sp_desktop_widget_color_prof_adj_enabled(_dtw); } virtual void updateZoom() diff --git a/src/widgets/fill-style.cpp b/src/widgets/fill-style.cpp index fa5eabab4..a96776894 100644 --- a/src/widgets/fill-style.cpp +++ b/src/widgets/fill-style.cpp @@ -68,7 +68,7 @@ namespace Inkscape { class FillNStroke : public Gtk::VBox { public: - FillNStroke( FillOrStroke kind ); + FillNStroke( FillOrStroke k ); ~FillNStroke(); void setFillrule( SPPaintSelector::FillRule mode ); @@ -125,9 +125,9 @@ Gtk::Widget *Inkscape::Widgets::createStyleWidget( FillOrStroke kind ) return filler; } -FillNStroke::FillNStroke( FillOrStroke kind ) : +FillNStroke::FillNStroke( FillOrStroke k ) : Gtk::VBox(), - kind(kind), + kind(k), desktop(0), psel(0), lastDrag(0), @@ -570,7 +570,7 @@ void FillNStroke::updateFromPaint() } } - for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++){ + for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end(); ++i){ //FIXME: see above if (kind == FILL) { sp_repr_css_change_recursive((*i)->getRepr(), css, "style"); @@ -596,7 +596,7 @@ void FillNStroke::updateFromPaint() // We have changed from another gradient type, or modified spread/units within // this gradient type. vector = sp_gradient_ensure_vector_normalized(vector); - for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++){ + for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end(); ++i){ //FIXME: see above if (kind == FILL) { sp_repr_css_change_recursive((*i)->getRepr(), css, "style"); @@ -642,7 +642,7 @@ void FillNStroke::updateFromPaint() // cannot just call sp_desktop_set_style, because we don't want to touch those // objects who already have the same root pattern but through a different href // chain. FIXME: move this to a sp_item_set_pattern - for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++){ + for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end(); ++i){ Inkscape::XML::Node *selrepr = (*i)->getRepr(); if ( (kind == STROKE) && !selrepr) { continue; diff --git a/src/widgets/gradient-selector.cpp b/src/widgets/gradient-selector.cpp index 402f30846..63599f3f9 100644 --- a/src/widgets/gradient-selector.cpp +++ b/src/widgets/gradient-selector.cpp @@ -555,6 +555,10 @@ sp_gradient_selector_add_vector_clicked (GtkWidget */*w*/, SPGradientSelector *s if (gr) { repr = gr->getRepr()->duplicate(xml_doc); + // Rename the new gradients id to be similar to the cloned gradients + Glib::ustring old_id = gr->getId(); + rename_id(gr, old_id); + doc->getDefs()->getRepr()->addChild(repr, NULL); } else { repr = xml_doc->createElement("svg:linearGradient"); Inkscape::XML::Node *stop = xml_doc->createElement("svg:stop"); @@ -567,17 +571,10 @@ sp_gradient_selector_add_vector_clicked (GtkWidget */*w*/, SPGradientSelector *s stop->setAttribute("style", "stop-color:#fff;stop-opacity:1;"); repr->appendChild(stop); Inkscape::GC::release(stop); + doc->getDefs()->getRepr()->addChild(repr, NULL); + gr = SP_GRADIENT(doc->getObjectByRepr(repr)); } - - doc->getDefs()->getRepr()->addChild(repr, NULL); - - Glib::ustring old_id = gr->getId(); - - gr = SP_GRADIENT(doc->getObjectByRepr(repr)); - - // Rename the new gradients id to be similar to the cloned gradients - rename_id(gr, old_id); - + sp_gradient_vector_selector_set_gradient( SP_GRADIENT_VECTOR_SELECTOR (sel->vectors), doc, gr); sel->selectGradientInTree(gr); diff --git a/src/widgets/gradient-toolbar.cpp b/src/widgets/gradient-toolbar.cpp index 6743dd23a..b24615126 100644 --- a/src/widgets/gradient-toolbar.cpp +++ b/src/widgets/gradient-toolbar.cpp @@ -117,7 +117,7 @@ void gr_apply_gradient(Inkscape::Selection *selection, GrDrag *drag, SPGradient // If no drag or no dragger selected, act on selection std::vector<SPItem*> itemlist=selection->itemList(); - for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();++i){ gr_apply_gradient_to_item(*i, gr, initialType, initialMode, initialMode); } } @@ -219,7 +219,7 @@ void gr_get_dt_selected_gradient(Inkscape::Selection *selection, SPGradient *&gr SPGradient *gradient = 0; std::vector<SPItem*> itemlist=selection->itemList(); - for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();++i){ SPItem *item = *i;// get the items gradient, not the getVector() version SPStyle *style = item->style; SPPaintServer *server = 0; @@ -287,7 +287,7 @@ void gr_read_selection( Inkscape::Selection *selection, // If no selected dragger, read desktop selection std::vector<SPItem*> itemlist=selection->itemList(); - for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();++i){ SPItem *item = *i; SPStyle *style = item->style; diff --git a/src/widgets/gradient-vector.cpp b/src/widgets/gradient-vector.cpp index 259d4c9af..8e92f589a 100644 --- a/src/widgets/gradient-vector.cpp +++ b/src/widgets/gradient-vector.cpp @@ -842,7 +842,8 @@ static GtkWidget * sp_gradient_vector_widget_new(SPGradient *gradient, SPStop *s GtkWidget *vb, *w, *f; - g_return_val_if_fail(!gradient || SP_IS_GRADIENT(gradient), NULL); + g_return_val_if_fail(gradient != NULL, NULL); + g_return_val_if_fail(SP_IS_GRADIENT(gradient), NULL); #if GTK_CHECK_VERSION(3,0,0) vb = gtk_box_new(GTK_ORIENTATION_VERTICAL, PAD); diff --git a/src/widgets/measure-toolbar.cpp b/src/widgets/measure-toolbar.cpp index 5a4785b1f..67c128dd2 100644 --- a/src/widgets/measure-toolbar.cpp +++ b/src/widgets/measure-toolbar.cpp @@ -33,11 +33,16 @@ #include "measure-toolbar.h" #include "desktop.h" +#include "inkscape.h" +#include "message-stack.h" #include "document-undo.h" #include "widgets/ege-adjustment-action.h" #include "widgets/ege-output-action.h" #include "preferences.h" #include "toolbox.h" +#include "widgets/ink-action.h" +#include "ui/icon-names.h" +#include "ui/tools/measure-tool.h" #include "ui/widget/unit-tracker.h" using Inkscape::UI::Widget::UnitTracker; @@ -45,11 +50,26 @@ using Inkscape::Util::Unit; using Inkscape::DocumentUndo; using Inkscape::UI::ToolboxFactory; using Inkscape::UI::PrefPusher; +using Inkscape::UI::Tools::MeasureTool; //######################## //## Measure Toolbox ## //######################## +/** Temporary hack: Returns the node tool in the active desktop. + * Will go away during tool refactoring. */ +static MeasureTool *get_measure_tool() +{ + MeasureTool *tool = 0; + if (SP_ACTIVE_DESKTOP ) { + Inkscape::UI::Tools::ToolBase *ec = SP_ACTIVE_DESKTOP->event_context; + if (SP_IS_MEASURE_CONTEXT(ec)) { + tool = static_cast<MeasureTool*>(ec); + } + } + return tool; +} + static void sp_measure_fontsize_value_changed(GtkAdjustment *adj, GObject *tbl) { @@ -57,17 +77,176 @@ sp_measure_fontsize_value_changed(GtkAdjustment *adj, GObject *tbl) if (DocumentUndo::getUndoSensitive(desktop->getDocument())) { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setInt(Glib::ustring("/tools/measure/fontsize"), + prefs->setDouble(Glib::ustring("/tools/measure/fontsize"), + gtk_adjustment_get_value(adj)); + MeasureTool *mt = get_measure_tool(); + if (mt) { + mt->showCanvasItems(); + } + } +} + +static void +sp_measure_offset_value_changed(GtkAdjustment *adj, GObject *tbl) +{ + SPDesktop *desktop = static_cast<SPDesktop *>(g_object_get_data( tbl, "desktop" )); + + if (DocumentUndo::getUndoSensitive(desktop->getDocument())) { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setDouble(Glib::ustring("/tools/measure/offset"), gtk_adjustment_get_value(adj)); + MeasureTool *mt = get_measure_tool(); + if (mt) { + mt->showCanvasItems(); + } } } -static void measure_unit_changed(GtkAction* /*act*/, GObject* tbl) +static void sp_measure_scale_value_changed(GtkAdjustment *adj, GObject *tbl) +{ + SPDesktop *desktop = static_cast<SPDesktop *>(g_object_get_data( tbl, "desktop" )); + + if (DocumentUndo::getUndoSensitive(desktop->getDocument())) { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setDouble(Glib::ustring("/tools/measure/scale"), + gtk_adjustment_get_value(adj)); + MeasureTool *mt = get_measure_tool(); + if (mt) { + mt->showCanvasItems(); + } + } +} + +static void +sp_measure_precision_value_changed(GtkAdjustment *adj, GObject *tbl) +{ + SPDesktop *desktop = static_cast<SPDesktop *>(g_object_get_data( tbl, "desktop" )); + + if (DocumentUndo::getUndoSensitive(desktop->getDocument())) { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setInt(Glib::ustring("/tools/measure/precision"), + gtk_adjustment_get_value(adj)); + MeasureTool *mt = get_measure_tool(); + if (mt) { + mt->showCanvasItems(); + } + } +} + +static void +sp_measure_unit_changed(GtkAction* /*act*/, GObject* tbl) { UnitTracker* tracker = reinterpret_cast<UnitTracker*>(g_object_get_data(tbl, "tracker")); Glib::ustring const unit = tracker->getActiveUnit()->abbr; Inkscape::Preferences *prefs = Inkscape::Preferences::get(); prefs->setString("/tools/measure/unit", unit); + MeasureTool *mt = get_measure_tool(); + if (mt) { + mt->showCanvasItems(); + } +} + +static void +sp_toggle_ignore_1st_and_last( GtkToggleAction* act, gpointer data ) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + gboolean active = gtk_toggle_action_get_active(act); + prefs->setBool("/tools/measure/ignore_1st_and_last", active); + SPDesktop *desktop = static_cast<SPDesktop *>(data); + if ( active ) { + desktop->messageStack()->flash(Inkscape::INFORMATION_MESSAGE, _("Start and end measures inactive.")); + } else { + desktop->messageStack()->flash(Inkscape::INFORMATION_MESSAGE, _("Start and end measures active.")); + } + MeasureTool *mt = get_measure_tool(); + if (mt) { + mt->showCanvasItems(); + } +} + +static void +sp_toggle_only_visible( GtkToggleAction* act, gpointer data ) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + gboolean active = gtk_toggle_action_get_active(act); + prefs->setBool("/tools/measure/only_visible", active); + SPDesktop *desktop = static_cast<SPDesktop *>(data); + if ( active ) { + desktop->messageStack()->flash(Inkscape::INFORMATION_MESSAGE, _("Show only visible crossings.")); + } else { + desktop->messageStack()->flash(Inkscape::INFORMATION_MESSAGE, _("Show all crossings.")); + } + MeasureTool *mt = get_measure_tool(); + if (mt) { + mt->showCanvasItems(); + } +} + +static void +sp_toggle_all_layers( GtkToggleAction* act, gpointer data ) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + gboolean active = gtk_toggle_action_get_active(act); + prefs->setBool("/tools/measure/all_layers", active); + SPDesktop *desktop = static_cast<SPDesktop *>(data); + if ( active ) { + desktop->messageStack()->flash(Inkscape::INFORMATION_MESSAGE, _("Use all layers in the measure.")); + } else { + desktop->messageStack()->flash(Inkscape::INFORMATION_MESSAGE, _("Use current layer in the measure.")); + } + MeasureTool *mt = get_measure_tool(); + if (mt) { + mt->showCanvasItems(); + } +} + +static void +sp_toggle_show_in_between( GtkToggleAction* act, gpointer data ) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + gboolean active = gtk_toggle_action_get_active(act); + prefs->setBool("/tools/measure/show_in_between", active); + SPDesktop *desktop = static_cast<SPDesktop *>(data); + if ( active ) { + desktop->messageStack()->flash(Inkscape::INFORMATION_MESSAGE, _("Compute all elements.")); + } else { + desktop->messageStack()->flash(Inkscape::INFORMATION_MESSAGE, _("Compute max lenght.")); + } + MeasureTool *mt = get_measure_tool(); + if (mt) { + mt->showCanvasItems(); + } +} +static void +sp_reverse_knots(void){ + MeasureTool *mt = get_measure_tool(); + if (mt) { + mt->reverseKnots(); + } +} + +static void +sp_to_mark_dimension(void){ + MeasureTool *mt = get_measure_tool(); + if (mt) { + mt->toMarkDimension(); + } +} + +static void +sp_to_guides(void){ + MeasureTool *mt = get_measure_tool(); + if (mt) { + mt->toGuides(); + } +} + +static void +sp_to_item(void){ + MeasureTool *mt = get_measure_tool(); + if (mt) { + mt->toItem(); + } } void sp_measure_toolbox_prep(SPDesktop * desktop, GtkActionGroup* mainActions, GObject* holder) @@ -79,22 +258,22 @@ void sp_measure_toolbox_prep(SPDesktop * desktop, GtkActionGroup* mainActions, G g_object_set_data( holder, "tracker", tracker ); EgeAdjustmentAction *eact = 0; + Inkscape::IconSize secondarySize = ToolboxFactory::prefToSize("/toolbox/secondary", 1); /* Font Size */ { eact = create_adjustment_action( "MeasureFontSizeAction", _("Font Size"), _("Font Size:"), _("The font size to be used in the measurement labels"), - "/tools/measure/fontsize", 0.0, + "/tools/measure/fontsize", 10.0, GTK_WIDGET(desktop->canvas), holder, FALSE, NULL, - 10, 36, 1.0, 4.0, + 1.0, 36.0, 1.0, 4.0, 0, 0, 0, - sp_measure_fontsize_value_changed); - gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); + sp_measure_fontsize_value_changed, NULL, 0 , 2); + gtk_action_group_add_action( mainActions, GTK_ACTION(eact)); } - - // units label + /* units label */ { EgeOutputAction* act = ege_output_action_new( "measure_units_label", _("Units:"), _("The units to be used for the measurements"), 0 ); ege_output_action_set_use_markup( act, TRUE ); @@ -102,12 +281,136 @@ void sp_measure_toolbox_prep(SPDesktop * desktop, GtkActionGroup* mainActions, G gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); } - // units menu + /* units menu */ { GtkAction* act = tracker->createAction( "MeasureUnitsAction", _("Units:"), _("The units to be used for the measurements") ); - g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(measure_unit_changed), holder ); + g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_measure_unit_changed), holder ); gtk_action_group_add_action( mainActions, act ); } + + /* Precission */ + { + eact = create_adjustment_action( "MeasurePrecisionAction", + _("Precision"), _("Precision:"), + _("Decimal precision of measure"), + "/tools/measure/precision", 2, + GTK_WIDGET(desktop->canvas), holder, FALSE, NULL, + 0, 10, 1, 0, + 0, 0, 0, + sp_measure_precision_value_changed, NULL, 0 ,0); + gtk_action_group_add_action( mainActions, GTK_ACTION(eact)); + } + + /* Scale */ + { + eact = create_adjustment_action( "MeasureScaleAction", + _("Scale %"), _("Scale %:"), + _("Scale the results"), + "/tools/measure/scale", 100.0, + GTK_WIDGET(desktop->canvas), holder, FALSE, NULL, + 0.0, 90000.0, 1.0, 4.0, + 0, 0, 0, + sp_measure_scale_value_changed, NULL, 0 , 3); + gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); + } + + /* Offset */ + { + eact = create_adjustment_action( "MeasureOffsetAction", + _("Offset"), _("Offset:"), + _("The offset size"), + "/tools/measure/offset", 5.0, + GTK_WIDGET(desktop->canvas), holder, FALSE, NULL, + 0.0, 90000.0, 1.0, 4.0, + 0, 0, 0, + sp_measure_offset_value_changed, NULL, 0 , 2); + gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); + } + + /* ignore_1st_and_last */ + { + InkToggleAction* act = ink_toggle_action_new( "MeasureIgnore1stAndLast", + _("Ignore first and last"), + _("Ignore first and last"), + INKSCAPE_ICON("draw-geometry-line-segment"), + secondarySize ); + gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/measure/ignore_1st_and_last", true) ); + g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_toggle_ignore_1st_and_last), desktop) ; + gtk_action_group_add_action( mainActions, GTK_ACTION(act) ); + } + /* only visible */ + { + InkToggleAction* act = ink_toggle_action_new( "MeasureOnlyVisible", + _("Only visible intersections"), + _("Only visible intersections"), + INKSCAPE_ICON("zoom"), + secondarySize ); + gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/measure/only_visible", true) ); + g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_toggle_only_visible), desktop) ; + gtk_action_group_add_action( mainActions, GTK_ACTION(act) ); + } + /* measure imbetweens */ + { + InkToggleAction* act = ink_toggle_action_new( "MeasureInBettween", + _("Show measures between items"), + _("Show measures between items"), + INKSCAPE_ICON("distribute-randomize"), + secondarySize ); + gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/measure/show_in_between", true) ); + g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_toggle_show_in_between), desktop) ; + gtk_action_group_add_action( mainActions, GTK_ACTION(act) ); + } + /* measure only current layer */ + { + InkToggleAction* act = ink_toggle_action_new( "MeasureAllLayers", + _("Measure all layers"), + _("Measure all layers"), + INKSCAPE_ICON("dialog-layers"), + secondarySize ); + gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/measure/all_layers", true) ); + g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_toggle_all_layers), desktop) ; + gtk_action_group_add_action( mainActions, GTK_ACTION(act) ); + } + /* toogle start end */ + { + InkAction* act = ink_action_new( "MeasureReverse", + _("Reverse measure"), + _("Reverse measure"), + INKSCAPE_ICON("draw-geometry-mirror"), + secondarySize ); + g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(sp_reverse_knots), 0 ); + gtk_action_group_add_action( mainActions, GTK_ACTION(act) ); + } + /* to guides */ + { + InkAction* act = ink_action_new( "MeasureToGuides", + _("To guides"), + _("To guides"), + INKSCAPE_ICON("guides"), + secondarySize ); + g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(sp_to_guides), 0 ); + gtk_action_group_add_action( mainActions, GTK_ACTION(act) ); + } + /* to mark dimensions */ + { + InkAction* act = ink_action_new( "MeasureMarkDimension", + _("Mark Dimension"), + _("Mark Dimension"), + INKSCAPE_ICON("tool-pointer"), + secondarySize ); + g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(sp_to_mark_dimension), 0 ); + gtk_action_group_add_action( mainActions, GTK_ACTION(act) ); + } + /* to item */ + { + InkAction* act = ink_action_new( "MeasureToItem", + _("Convert to item"), + _("Convert to item"), + INKSCAPE_ICON("path-reverse"), + secondarySize ); + g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(sp_to_item), 0 ); + gtk_action_group_add_action( mainActions, GTK_ACTION(act) ); + } } // end of sp_measure_toolbox_prep() diff --git a/src/widgets/mesh-toolbar.cpp b/src/widgets/mesh-toolbar.cpp index 1af55d9cd..9937b23ed 100644 --- a/src/widgets/mesh-toolbar.cpp +++ b/src/widgets/mesh-toolbar.cpp @@ -34,6 +34,7 @@ #include "widgets/gradient-image.h" #include "style.h" +#include "inkscape.h" #include "preferences.h" #include "document-private.h" #include "document-undo.h" @@ -66,6 +67,7 @@ using Inkscape::DocumentUndo; using Inkscape::UI::ToolboxFactory; using Inkscape::UI::PrefPusher; +using Inkscape::UI::Tools::MeshTool; static bool blocked = false; @@ -88,7 +90,7 @@ void ms_read_selection( Inkscape::Selection *selection, ms_type = SP_MESH_TYPE_COONS; std::vector<SPItem*> itemlist=selection->itemList(); - for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();++i){ SPItem *item = *i; SPStyle *style = item->style; @@ -215,7 +217,7 @@ void ms_get_dt_selected_gradient(Inkscape::Selection *selection, SPMesh *&ms_sel SPMesh *gradient = 0; std::vector<SPItem*> itemlist=selection->itemList(); - for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();++i){ SPItem *item = *i;// get the items gradient, not the getVector() version SPStyle *style = item->style; SPPaintServer *server = 0; @@ -290,6 +292,9 @@ static void ms_col_changed(GtkAdjustment *adj, GObject * /*tbl*/ ) blocked = FALSE; } +/** + * Sets mesh type: Coons, Bicubic + */ static void ms_type_changed(EgeSelectOneAction *act, GtkWidget *widget) { // std::cout << "ms_type_changed" << std::endl; @@ -309,15 +314,54 @@ static void ms_type_changed(EgeSelectOneAction *act, GtkWidget *widget) gradient->type_set = true; gradient->updateRepr(); - DocumentUndo::done(desktop->getDocument(), SP_VERB_CONTEXT_GRADIENT, + DocumentUndo::done(desktop->getDocument(), SP_VERB_CONTEXT_MESH, _("Set mesh type")); } } +/** Temporary hack: Returns the mesh tool in the active desktop. + * Will go away during tool refactoring. */ +static MeshTool *get_mesh_tool() +{ + MeshTool *tool = 0; + if (SP_ACTIVE_DESKTOP ) { + Inkscape::UI::Tools::ToolBase *ec = SP_ACTIVE_DESKTOP->event_context; + if (SP_IS_MESH_CONTEXT(ec)) { + tool = static_cast<MeshTool*>(ec); + } + } + return tool; +} + +static void ms_toggle_sides(void) +{ + MeshTool *mt = get_mesh_tool(); + if (mt) { + sp_mesh_context_corner_operation( mt, MG_CORNER_SIDE_TOGGLE ); + } +} + +static void ms_make_elliptical(void) +{ + MeshTool *mt = get_mesh_tool(); + if (mt) { + sp_mesh_context_corner_operation( mt, MG_CORNER_SIDE_ARC ); + } +} + +static void ms_pick_colors(void) +{ + MeshTool *mt = get_mesh_tool(); + if (mt) { + sp_mesh_context_corner_operation( mt, MG_CORNER_COLOR_PICK ); + } +} + static void mesh_toolbox_watch_ec(SPDesktop* dt, Inkscape::UI::Tools::ToolBase* ec, GObject* holder); /** * Mesh auxiliary toolbar construction and setup. + * Don't forget to add to XML in widgets/toolbox.cpp! * */ void sp_mesh_toolbox_prep(SPDesktop * desktop, GtkActionGroup* mainActions, GObject* holder) @@ -466,7 +510,7 @@ void sp_mesh_toolbox_prep(SPDesktop * desktop, GtkActionGroup* mainActions, GObj gtk_action_group_add_action( mainActions, GTK_ACTION(act) ); } - /* Typeing method */ + /* Type */ { GtkListStore* model = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_INT ); @@ -487,6 +531,41 @@ void sp_mesh_toolbox_prep(SPDesktop * desktop, GtkActionGroup* mainActions, GObj gtk_action_group_add_action( mainActions, GTK_ACTION(act) ); g_object_set_data( holder, "mesh_select_type_action", act ); } + + { + InkAction* act = ink_action_new( "MeshToggleSidesAction", + _("Toggle Sides"), + _("Toggle selected sides between Beziers and lines."), + INKSCAPE_ICON("node-segment-line"), + secondarySize ); + g_object_set( act, "short_label", _("Toggle side:"), NULL ); + g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(ms_toggle_sides), 0 ); + gtk_action_group_add_action( mainActions, GTK_ACTION(act) ); + } + + { + InkAction* act = ink_action_new( "MeshMakeEllipticalAction", + _("Make elliptical"), + _("Make selected sides elliptical by changing length of handles. Works best if handles already approximate ellipse."), + INKSCAPE_ICON("node-segment-curve"), + secondarySize ); + g_object_set( act, "short_label", _("Make elliptical:"), NULL ); + g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(ms_make_elliptical), 0 ); + gtk_action_group_add_action( mainActions, GTK_ACTION(act) ); + } + + { + InkAction* act = ink_action_new( "MeshPickColorsAction", + _("Pick colors:"), + _("Pick colors for selected corner nodes from underneath mesh."), + INKSCAPE_ICON("color-picker"), + secondarySize ); + g_object_set( act, "short_label", _("Pick Color"), NULL ); + g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(ms_pick_colors), 0 ); + gtk_action_group_add_action( mainActions, GTK_ACTION(act) ); + } + + } static void mesh_toolbox_watch_ec(SPDesktop* desktop, Inkscape::UI::Tools::ToolBase* ec, GObject* holder) diff --git a/src/widgets/paint-selector.cpp b/src/widgets/paint-selector.cpp index 846ded511..d8d314834 100644 --- a/src/widgets/paint-selector.cpp +++ b/src/widgets/paint-selector.cpp @@ -972,7 +972,7 @@ ink_pattern_menu(GtkWidget *combo) } - // Select the first item that is not a seperator + // Select the first item that is not a separator if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL(store), &iter)) { gboolean sep = false; gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, COMBO_COL_SEP, &sep, -1); diff --git a/src/widgets/pencil-toolbar.cpp b/src/widgets/pencil-toolbar.cpp index 17c1d341d..aed80a66f 100644 --- a/src/widgets/pencil-toolbar.cpp +++ b/src/widgets/pencil-toolbar.cpp @@ -34,7 +34,6 @@ #include "pencil-toolbar.h" #include "desktop.h" -#include "document-undo.h" #include "widgets/ege-adjustment-action.h" #include "widgets/ege-select-one-action.h" #include "widgets/ink-action.h" @@ -57,7 +56,6 @@ #include "util/glib-list-iterators.h" using Inkscape::UI::UXManager; -using Inkscape::DocumentUndo; using Inkscape::UI::ToolboxFactory; using Inkscape::UI::PrefPusher; diff --git a/src/widgets/rect-toolbar.cpp b/src/widgets/rect-toolbar.cpp index 96ba699dc..bc27d003c 100644 --- a/src/widgets/rect-toolbar.cpp +++ b/src/widgets/rect-toolbar.cpp @@ -107,7 +107,7 @@ static void sp_rtb_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const * bool modmade = false; Inkscape::Selection *selection = desktop->getSelection(); std::vector<SPItem*> itemlist=selection->itemList(); - for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();++i){ if (SP_IS_RECT(*i)) { if (gtk_adjustment_get_value(adj) != 0) { (SP_RECT(*i)->*setter)(Quantity::convert(gtk_adjustment_get_value(adj), unit, "px")); @@ -244,7 +244,7 @@ static void sp_rect_toolbox_selection_changed(Inkscape::Selection *selection, GO purge_repr_listener( tbl, tbl ); std::vector<SPItem*> itemlist=selection->itemList(); - for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();++i){ if (SP_IS_RECT(*i)) { n_selected++; item = *i; diff --git a/src/widgets/sp-xmlview-attr-list.cpp b/src/widgets/sp-xmlview-attr-list.cpp index dd763aea5..a4c00db7c 100644 --- a/src/widgets/sp-xmlview-attr-list.cpp +++ b/src/widgets/sp-xmlview-attr-list.cpp @@ -145,6 +145,7 @@ void sp_xmlview_attr_list_select_row_by_key(SPXMLViewAttrList * list, const gcha break; } valid = gtk_tree_model_iter_next (GTK_TREE_MODEL(list->store), &iter); + // cppcheck-suppress nullPointer // a string was copied in n by gtk_tree_model_get if (n) { g_free(n); } @@ -181,6 +182,7 @@ event_attr_changed (Inkscape::XML::Node * /*repr*/, } row++; valid = gtk_tree_model_iter_next (GTK_TREE_MODEL(list->store), &iter); + // cppcheck-suppress nullPointer // a string was copied in n by gtk_tree_model_get if (n) { g_free(n); } diff --git a/src/widgets/spiral-toolbar.cpp b/src/widgets/spiral-toolbar.cpp index 751a60f06..7e7398091 100644 --- a/src/widgets/spiral-toolbar.cpp +++ b/src/widgets/spiral-toolbar.cpp @@ -80,7 +80,7 @@ static void sp_spl_tb_value_changed(GtkAdjustment *adj, GObject *tbl, Glib::ustr bool modmade = false; std::vector<SPItem*> itemlist=desktop->getSelection()->itemList(); - for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end(); ++i){ SPItem *item = *i; if (SP_IS_SPIRAL(item)) { Inkscape::XML::Node *repr = item->getRepr(); @@ -196,7 +196,7 @@ static void sp_spiral_toolbox_selection_changed(Inkscape::Selection *selection, purge_repr_listener( tbl, tbl ); std::vector<SPItem*> itemlist=selection->itemList(); - for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end(); ++i){ SPItem *item = *i; if (SP_IS_SPIRAL(item)) { n_selected++; diff --git a/src/widgets/spray-toolbar.cpp b/src/widgets/spray-toolbar.cpp index 183814b7e..30e9c6418 100644 --- a/src/widgets/spray-toolbar.cpp +++ b/src/widgets/spray-toolbar.cpp @@ -15,10 +15,11 @@ * Tavmjong Bah <tavmjong@free.fr> * Abhishek Sharma * Kris De Gussem <Kris.DeGussem@gmail.com> + * Jabiertxo Arraiza <jabier.arraiza@marker.es> * * Copyright (C) 2004 David Turner * Copyright (C) 2003 MenTaLguY - * Copyright (C) 1999-2011 authors + * Copyright (C) 1999-2015 authors * Copyright (C) 2001-2002 Ximian, Inc. * * Released under GNU GPL, read the file 'COPYING' for more information @@ -28,19 +29,23 @@ # include "config.h" #endif -#include <glibmm/i18n.h> +#include <gtkmm.h> #include "spray-toolbar.h" #include "desktop.h" -#include "document-undo.h" +#include "inkscape.h" #include "widgets/ege-adjustment-action.h" #include "widgets/ege-select-one-action.h" #include "widgets/ink-action.h" #include "preferences.h" #include "toolbox.h" +#include "ui/dialog/clonetiler.h" +#include "ui/dialog/dialog-manager.h" +#include "ui/dialog/panel-dialog.h" #include "ui/icon-names.h" -using Inkscape::DocumentUndo; +#include <glibmm/i18n.h> + using Inkscape::UI::ToolboxFactory; using Inkscape::UI::PrefPusher; @@ -53,6 +58,74 @@ using Inkscape::UI::PrefPusher; //## Spray ## //######################## +static void sp_stb_sensitivize( GObject *tbl ) +{ + GtkAction* offset = GTK_ACTION( g_object_get_data(tbl, "offset") ); + GtkAction* spray_scale = GTK_ACTION( g_object_get_data(tbl, "spray_scale") ); + GtkAdjustment *adj_offset = ege_adjustment_action_get_adjustment( EGE_ADJUSTMENT_ACTION(offset) ); + GtkAdjustment *adj_scale = ege_adjustment_action_get_adjustment( EGE_ADJUSTMENT_ACTION(spray_scale) ); + GtkToggleAction *no_overlap = GTK_TOGGLE_ACTION( g_object_get_data(tbl, "no_overlap") ); + GtkToggleAction *picker = GTK_TOGGLE_ACTION( g_object_get_data(tbl, "picker") ); + GtkAction* picker_action = GTK_ACTION( g_object_get_data(tbl, "picker") ); + GtkToggleAction *usepressurescale = GTK_TOGGLE_ACTION( g_object_get_data(tbl, "usepressurescale") ); + GtkAction *pick_fill = GTK_ACTION( g_object_get_data(tbl, "pick_fill") ); + GtkAction *pick_stroke = GTK_ACTION( g_object_get_data(tbl, "pick_stroke") ); + GtkAction *pick_inverse_value = GTK_ACTION( g_object_get_data(tbl, "pick_inverse_value") ); + GtkAction *pick_center = GTK_ACTION( g_object_get_data(tbl, "pick_center") ); + gtk_adjustment_set_value( adj_offset, 100.0 ); + if (gtk_toggle_action_get_active(no_overlap) && gtk_action_get_sensitive(picker_action)) { + gtk_action_set_sensitive( offset, TRUE ); + } else { + gtk_action_set_sensitive( offset, FALSE ); + } + if (gtk_toggle_action_get_active(usepressurescale)) { + gtk_adjustment_set_value( adj_scale, 0.0 ); + gtk_action_set_sensitive( spray_scale, FALSE ); + } else { + gtk_action_set_sensitive( spray_scale, TRUE ); + } + if(gtk_toggle_action_get_active(picker) && gtk_action_get_sensitive(picker_action)){ + gtk_action_set_sensitive( pick_fill, TRUE ); + gtk_action_set_sensitive( pick_stroke, TRUE ); + gtk_action_set_sensitive( pick_inverse_value, TRUE ); + gtk_action_set_sensitive( pick_center, TRUE ); + } else { + gtk_action_set_sensitive( pick_fill, FALSE ); + gtk_action_set_sensitive( pick_stroke, FALSE ); + gtk_action_set_sensitive( pick_inverse_value, FALSE ); + gtk_action_set_sensitive( pick_center, FALSE ); + } +} + +static void sp_spray_erase_sensitivize( GObject *tbl, bool sensitive){ + gtk_action_set_sensitive( GTK_ACTION( g_object_get_data(tbl, "no_overlap") ), sensitive ); + gtk_action_set_sensitive( GTK_ACTION( g_object_get_data(tbl, "over_no_transparent") ), sensitive ); + gtk_action_set_sensitive( GTK_ACTION( g_object_get_data(tbl, "over_transparent") ), sensitive ); + gtk_action_set_sensitive( GTK_ACTION( g_object_get_data(tbl, "pick_no_overlap") ), sensitive ); + gtk_action_set_sensitive( GTK_ACTION( g_object_get_data(tbl, "pick_stroke") ), sensitive ); + gtk_action_set_sensitive( GTK_ACTION( g_object_get_data(tbl, "pick_fill") ), sensitive ); + gtk_action_set_sensitive( GTK_ACTION( g_object_get_data(tbl, "pick_inverse_value") ), sensitive ); + gtk_action_set_sensitive( GTK_ACTION( g_object_get_data(tbl, "pick_center") ), sensitive ); + gtk_action_set_sensitive( GTK_ACTION( g_object_get_data(tbl, "picker") ), sensitive ); + gtk_action_set_sensitive( GTK_ACTION( g_object_get_data(tbl, "offset") ), sensitive ); + gtk_action_set_sensitive( GTK_ACTION( g_object_get_data(tbl, "spray_rotation") ), sensitive ); + sp_stb_sensitivize( tbl ); +} + +Inkscape::UI::Dialog::CloneTiler *get_clone_tiler_panel(SPDesktop *desktop) +{ + if (Inkscape::UI::Dialog::PanelDialogBase *panel_dialog = + dynamic_cast<Inkscape::UI::Dialog::PanelDialogBase *>(desktop->_dlg_mgr->getDialog("CloneTiler"))) { + try { + Inkscape::UI::Dialog::CloneTiler &clone_tiler = + dynamic_cast<Inkscape::UI::Dialog::CloneTiler &>(panel_dialog->getPanel()); + return &clone_tiler; + } catch (std::exception &e) { } + } + + return 0; +} + static void sp_spray_width_value_changed( GtkAdjustment *adj, GObject * /*tbl*/ ) { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); @@ -74,11 +147,16 @@ static void sp_spray_standard_deviation_value_changed( GtkAdjustment *adj, GObje gtk_adjustment_get_value(adj)); } -static void sp_spray_mode_changed( EgeSelectOneAction *act, GObject * /*tbl*/ ) +static void sp_spray_mode_changed( EgeSelectOneAction *act, GObject * tbl ) { int mode = ege_select_one_action_get_active( act ); Inkscape::Preferences *prefs = Inkscape::Preferences::get(); prefs->setInt("/tools/spray/mode", mode); + if(mode != 3){ + sp_spray_erase_sensitivize(tbl, true); + } else { + sp_spray_erase_sensitivize(tbl, false); + } } static void sp_spray_population_value_changed( GtkAdjustment *adj, GObject * /*tbl*/ ) @@ -102,12 +180,105 @@ static void sp_spray_scale_value_changed( GtkAdjustment *adj, GObject * /*tbl*/ gtk_adjustment_get_value(adj)); } +static void sp_spray_offset_value_changed( GtkAdjustment *adj, GObject * /*tbl*/ ) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setDouble( "/tools/spray/offset", + gtk_adjustment_get_value(adj)); +} + +static void sp_toggle_no_overlap( GtkToggleAction* act, gpointer data) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + gboolean active = gtk_toggle_action_get_active(act); + prefs->setBool("/tools/spray/no_overlap", active); + GObject *tbl = G_OBJECT(data); + sp_stb_sensitivize(tbl); +} + +static void sp_toggle_pressure_scale( GtkToggleAction* act, gpointer data) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + gboolean active = gtk_toggle_action_get_active(act); + prefs->setBool("/tools/spray/usepressurescale", active); + if(active == true){ + prefs->setDouble("/tools/spray/scale_variation", 0); + } + GObject *tbl = G_OBJECT(data); + sp_stb_sensitivize( tbl ); +} + +static void sp_toggle_over_no_transparent( GtkToggleAction* act, gpointer data) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + gboolean active = gtk_toggle_action_get_active(act); + prefs->setBool("/tools/spray/over_no_transparent", active); +} + +static void sp_toggle_over_transparent( GtkToggleAction* act, gpointer data) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + gboolean active = gtk_toggle_action_get_active(act); + prefs->setBool("/tools/spray/over_transparent", active); +} + + +static void sp_toggle_picker( GtkToggleAction* act, gpointer data ) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + gboolean active = gtk_toggle_action_get_active(act); + prefs->setBool("/tools/spray/picker", active); + if(active == true){ + prefs->setBool("/dialogs/clonetiler/dotrace", false); + SPDesktop *dt = SP_ACTIVE_DESKTOP; + if (Inkscape::UI::Dialog::CloneTiler *ct = get_clone_tiler_panel(dt)){ + dt->_dlg_mgr->showDialog("CloneTiler"); + ct->show_page_trace(); + } + } + GObject *tbl = G_OBJECT(data); + sp_stb_sensitivize(tbl); +} + +static void sp_toggle_pick_center( GtkToggleAction* act, gpointer data ) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + gboolean active = gtk_toggle_action_get_active(act); + prefs->setBool("/tools/spray/pick_center", active); +} + +static void sp_toggle_pick_fill( GtkToggleAction* act, gpointer data ) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + gboolean active = gtk_toggle_action_get_active(act); + prefs->setBool("/tools/spray/pick_fill", active); +} + +static void sp_toggle_pick_stroke( GtkToggleAction* act, gpointer data ) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + gboolean active = gtk_toggle_action_get_active(act); + prefs->setBool("/tools/spray/pick_stroke", active); +} + +static void sp_toggle_pick_no_overlap( GtkToggleAction* act, gpointer data ) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + gboolean active = gtk_toggle_action_get_active(act); + prefs->setBool("/tools/spray/pick_no_overlap", active); +} + +static void sp_toggle_pick_inverse_value( GtkToggleAction* act, gpointer data ) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + gboolean active = gtk_toggle_action_get_active(act); + prefs->setBool("/tools/spray/pick_inverse_value", active); +} void sp_spray_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder) { Inkscape::IconSize secondarySize = ToolboxFactory::prefToSize("/toolbox/secondary", 1); Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - { /* Width */ gchar const* labels[] = {_("(narrow spray)"), 0, 0, 0, _("(default)"), 0, 0, 0, 0, _("(broad spray)")}; @@ -123,7 +294,20 @@ void sp_spray_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObj gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); } + + /* Use Pressure Width button */ + { + InkToggleAction* act = ink_toggle_action_new( "SprayPressureWidthAction", + _("Pressure"), + _("Use the pressure of the input device to alter the width of spray area"), + INKSCAPE_ICON("draw-use-pressure"), + Inkscape::ICON_SIZE_DECORATION ); + gtk_action_group_add_action( mainActions, GTK_ACTION(act) ); + PrefPusher *pusher = new PrefPusher(GTK_TOGGLE_ACTION(act), "/tools/spray/usepressurewidth"); + g_signal_connect(holder, "destroy", G_CALLBACK(delete_prefspusher), pusher); + } + { /* Mean */ gchar const* labels[] = {_("(default)"), 0, 0, 0, 0, 0, 0, _("(maximum mean)")}; @@ -158,7 +342,7 @@ void sp_spray_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObj /* Mode */ { - GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING ); + GtkListStore* model = gtk_list_store_new( 4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING ); GtkTreeIter iter; gtk_list_store_append( model, &iter ); @@ -174,6 +358,7 @@ void sp_spray_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObj 1, _("Spray clones of the initial selection"), 2, INKSCAPE_ICON("spray-mode-clone"), -1 ); + #ifdef ENABLE_SPRAY_MODE_SINGLE_PATH gtk_list_store_append( model, &iter ); gtk_list_store_set( model, &iter, @@ -182,6 +367,14 @@ void sp_spray_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObj 2, INKSCAPE_ICON("spray-mode-union"), -1 ); #endif + + gtk_list_store_append( model, &iter ); + gtk_list_store_set( model, &iter, + 0, _("Delete sprayed items"), + 1, _("Delete sprayed items from selection"), + 2, INKSCAPE_ICON("draw-eraser"), + -1 ); + EgeSelectOneAction* act = ege_select_one_action_new( "SprayModeAction", _("Mode"), (""), NULL, GTK_TREE_MODEL(model) ); g_object_set( act, "short_label", _("Mode:"), NULL ); gtk_action_group_add_action( mainActions, GTK_ACTION(act) ); @@ -218,15 +411,15 @@ void sp_spray_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObj g_object_set_data( holder, "spray_population", eact ); } - /* Use Pressure button */ + /* Use Pressure Population button */ { - InkToggleAction* act = ink_toggle_action_new( "SprayPressureAction", + InkToggleAction* act = ink_toggle_action_new( "SprayPressurePopulationAction", _("Pressure"), _("Use the pressure of the input device to alter the amount of sprayed objects"), INKSCAPE_ICON("draw-use-pressure"), Inkscape::ICON_SIZE_DECORATION ); gtk_action_group_add_action( mainActions, GTK_ACTION(act) ); - PrefPusher *pusher = new PrefPusher(GTK_TOGGLE_ACTION(act), "/tools/spray/usepressure"); + PrefPusher *pusher = new PrefPusher(GTK_TOGGLE_ACTION(act), "/tools/spray/usepressurepopulation"); g_signal_connect(holder, "destroy", G_CALLBACK(delete_prefspusher), pusher); } @@ -267,8 +460,152 @@ void sp_spray_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObj g_object_set_data( holder, "spray_scale", eact ); } + /* Use Pressure Scale button */ + { + InkToggleAction* act = ink_toggle_action_new( "SprayPressureScaleAction", + _("Pressure"), + _("Use the pressure of the input device to alter the scale of new items"), + INKSCAPE_ICON("draw-use-pressure"), + Inkscape::ICON_SIZE_DECORATION); + gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/spray/usepressurescale", false) ); + g_object_set_data( holder, "usepressurescale", act ); + g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_toggle_pressure_scale), holder) ; + gtk_action_group_add_action( mainActions, GTK_ACTION(act) ); + } + + /* Picker */ + { + InkToggleAction* act = ink_toggle_action_new( "SprayPickColorAction", + _("Pick color from the drawing. You can use clonetiler trace dialog for avanced effects. In clone mode original fill or stroke colors must be unset."), + _("Pick color from the drawing. You can use clonetiler trace dialog for avanced effects. In clone mode original fill or stroke colors must be unset."), + INKSCAPE_ICON("color-picker"), + secondarySize ); + gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/spray/picker", false) ); + g_object_set_data( holder, "picker", act ); + g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_toggle_picker), holder) ; + gtk_action_group_add_action( mainActions, GTK_ACTION(act) ); + } + + /* Pick from center */ + { + InkToggleAction* act = ink_toggle_action_new( "SprayPickCenterAction", + _("Pick from center instead average area."), + _("Pick from center instead average area."), + INKSCAPE_ICON("snap-bounding-box-center"), + secondarySize ); + gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/spray/pick_center", true) ); + g_object_set_data( holder, "pick_center", act ); + g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_toggle_pick_center), holder) ; + gtk_action_group_add_action( mainActions, GTK_ACTION(act) ); + } + + /* Inverse Value Size */ + { + InkToggleAction* act = ink_toggle_action_new( "SprayPickInverseValueAction", + _("Inversed pick value, retaining color in advanced trace mode"), + _("Inversed pick value, retaining color in advanced trace mode"), + INKSCAPE_ICON("object-tweak-shrink"), + secondarySize ); + gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/spray/pick_inverse_value", false) ); + g_object_set_data( holder, "pick_inverse_value", act ); + g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_toggle_pick_inverse_value), holder) ; + gtk_action_group_add_action( mainActions, GTK_ACTION(act) ); + } + + /* Pick Fill */ + { + InkToggleAction* act = ink_toggle_action_new( "SprayPickFillAction", + _("Apply picked color to fill"), + _("Apply picked color to fill"), + INKSCAPE_ICON("paint-solid"), + secondarySize ); + gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/spray/pick_fill", false) ); + g_object_set_data( holder, "pick_fill", act ); + g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_toggle_pick_fill), holder) ; + gtk_action_group_add_action( mainActions, GTK_ACTION(act) ); + } + /* Pick Stroke */ + { + InkToggleAction* act = ink_toggle_action_new( "SprayPickStrokeAction", + _("Apply picked color to stroke"), + _("Apply picked color to stroke"), + INKSCAPE_ICON("no-marker"), + secondarySize ); + gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/spray/pick_stroke", false) ); + g_object_set_data( holder, "pick_stroke", act ); + g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_toggle_pick_stroke), holder) ; + gtk_action_group_add_action( mainActions, GTK_ACTION(act) ); + } + + /* Pick No Overlap */ + { + InkToggleAction* act = ink_toggle_action_new( "SprayPickNoOverlapAction", + _("No overlap between colors"), + _("No overlap between colors"), + INKSCAPE_ICON("symbol-bigger"), + secondarySize ); + gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/spray/pick_no_overlap", false) ); + g_object_set_data( holder, "pick_no_overlap", act ); + g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_toggle_pick_no_overlap), holder) ; + gtk_action_group_add_action( mainActions, GTK_ACTION(act) ); + } + /* Over Transparent */ + { + InkToggleAction* act = ink_toggle_action_new( "SprayOverTransparentAction", + _("Apply over transparent areas"), + _("Apply over transparent areas"), + INKSCAPE_ICON("object-hidden"), + secondarySize ); + gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/spray/over_transparent", true) ); + g_object_set_data( holder, "over_transparent", act ); + g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_toggle_over_transparent), holder) ; + gtk_action_group_add_action( mainActions, GTK_ACTION(act) ); + } + + /* Over No Transparent */ + { + InkToggleAction* act = ink_toggle_action_new( "SprayOverNoTransparentAction", + _("Apply over no transparent areas"), + _("Apply over no transparent areas"), + INKSCAPE_ICON("object-visible"), + secondarySize ); + gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/spray/over_no_transparent", true) ); + g_object_set_data( holder, "over_no_transparent", act ); + g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_toggle_over_no_transparent), holder) ; + gtk_action_group_add_action( mainActions, GTK_ACTION(act) ); + } + + /* Overlap */ + { + InkToggleAction* act = ink_toggle_action_new( "SprayNoOverlapAction", + _("Prevent overlapping objects"), + _("Prevent overlapping objects"), + INKSCAPE_ICON("distribute-randomize"), + secondarySize ); + gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/spray/no_overlap", false) ); + g_object_set_data( holder, "no_overlap", act ); + g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_toggle_no_overlap), holder) ; + gtk_action_group_add_action( mainActions, GTK_ACTION(act) ); + } + + /* Offset */ + { + gchar const* labels[] = {_("(minimum offset)"), 0, 0, 0, _("(default)"), 0, 0, _("(maximum offset)")}; + gdouble values[] = {0, 25, 50, 75, 100, 150, 200, 1000}; + EgeAdjustmentAction *eact = create_adjustment_action( "SprayToolOffsetAction", + _("Offset %"), _("Offset %:"), + _("Increase to segregate objects more (value in percent)"), + "/tools/spray/offset", 100, + GTK_WIDGET(desktop->canvas), holder, FALSE, NULL, + 0, 1000, 1, 4, + labels, values, G_N_ELEMENTS(labels), + sp_spray_offset_value_changed, NULL, 0 , 0); + g_object_set_data( holder, "offset", eact ); + gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); + } + sp_spray_erase_sensitivize(holder, prefs->getInt("/tools/spray/mode") != 3); } diff --git a/src/widgets/spray-toolbar.h b/src/widgets/spray-toolbar.h index d1d5c7b4c..30d8233ca 100644 --- a/src/widgets/spray-toolbar.h +++ b/src/widgets/spray-toolbar.h @@ -21,7 +21,7 @@ * * Copyright (C) 2004 David Turner * Copyright (C) 2003 MenTaLguY - * Copyright (C) 1999-2011 authors + * Copyright (C) 1999-2015 authors * Copyright (C) 2001-2002 Ximian, Inc. * * Released under GNU GPL, read the file 'COPYING' for more information diff --git a/src/widgets/star-toolbar.cpp b/src/widgets/star-toolbar.cpp index 96005d7df..741fd38ad 100644 --- a/src/widgets/star-toolbar.cpp +++ b/src/widgets/star-toolbar.cpp @@ -84,7 +84,7 @@ static void sp_stb_magnitude_value_changed( GtkAdjustment *adj, GObject *dataKlu Inkscape::Selection *selection = desktop->getSelection(); std::vector<SPItem*> itemlist=selection->itemList(); - for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();++i){ SPItem *item = *i; if (SP_IS_STAR(item)) { Inkscape::XML::Node *repr = item->getRepr(); @@ -129,7 +129,7 @@ static void sp_stb_proportion_value_changed( GtkAdjustment *adj, GObject *dataKl bool modmade = false; Inkscape::Selection *selection = desktop->getSelection(); std::vector<SPItem*> itemlist=selection->itemList(); - for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();++i){ SPItem *item = *i; if (SP_IS_STAR(item)) { Inkscape::XML::Node *repr = item->getRepr(); @@ -186,7 +186,7 @@ static void sp_stb_sides_flat_state_changed( EgeSelectOneAction *act, GObject *d } std::vector<SPItem*> itemlist=selection->itemList(); - for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();++i){ SPItem *item = *i; if (SP_IS_STAR(item)) { Inkscape::XML::Node *repr = item->getRepr(); @@ -225,7 +225,7 @@ static void sp_stb_rounded_value_changed( GtkAdjustment *adj, GObject *dataKludg Inkscape::Selection *selection = desktop->getSelection(); std::vector<SPItem*> itemlist=selection->itemList(); - for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();++i){ SPItem *item = *i; if (SP_IS_STAR(item)) { Inkscape::XML::Node *repr = item->getRepr(); @@ -265,7 +265,7 @@ static void sp_stb_randomized_value_changed( GtkAdjustment *adj, GObject *dataKl Inkscape::Selection *selection = desktop->getSelection(); std::vector<SPItem*> itemlist=selection->itemList(); - for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();++i){ SPItem *item = *i; if (SP_IS_STAR(item)) { Inkscape::XML::Node *repr = item->getRepr(); @@ -368,7 +368,7 @@ sp_star_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl) purge_repr_listener( tbl, tbl ); std::vector<SPItem*> itemlist=selection->itemList(); - for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();++i){ SPItem *item = *i; if (SP_IS_STAR(item)) { n_selected++; diff --git a/src/widgets/stroke-style.cpp b/src/widgets/stroke-style.cpp index d05b3b994..43dffec56 100644 --- a/src/widgets/stroke-style.cpp +++ b/src/widgets/stroke-style.cpp @@ -480,7 +480,7 @@ void StrokeStyle::markerSelectCB(MarkerComboBox *marker_combo, StrokeStyle *spw, Inkscape::Selection *selection = spw->desktop->getSelection(); std::vector<SPItem*> itemlist=selection->itemList(); - for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();++i){ SPItem *item = *i; if (!SP_IS_SHAPE(item) || SP_IS_RECT(item)) { // can't set marker to rect, until it's converted to using <path> continue; @@ -981,7 +981,7 @@ StrokeStyle::scaleLine() int ndash; dashSelector->get_dash(&ndash, &dash, &offset); - for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++){ + for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();++i){ /* Set stroke width */ double width; if (unit->type == Inkscape::Util::UNIT_TYPE_LINEAR) { @@ -1156,7 +1156,7 @@ StrokeStyle::updateAllMarkers(std::vector<SPItem*> const &objects) }; bool all_texts = true; - for(std::vector<SPItem*>::const_iterator i=objects.begin();i!=objects.end();i++){ + for(std::vector<SPItem*>::const_iterator i=objects.begin();i!=objects.end();++i){ if (!SP_IS_TEXT (*i)) { all_texts = false; break; diff --git a/src/widgets/text-toolbar.cpp b/src/widgets/text-toolbar.cpp index 7b22e4af7..c6cc7dc45 100644 --- a/src/widgets/text-toolbar.cpp +++ b/src/widgets/text-toolbar.cpp @@ -155,7 +155,7 @@ static void sp_text_fontfamily_value_changed( Ink_ComboBoxEntry_Action *act, GOb act->active = 0; // New family is always at top of list. } - std::pair<Glib::ustring,Glib::ustring> ui = fontlister->set_font_family( act->active ); + fontlister->set_font_family( act->active ); // active text set in sp_text_toolbox_selection_changed() SPCSSAttr *css = sp_repr_css_attr_new (); @@ -373,7 +373,7 @@ static void sp_text_align_mode_changed( EgeSelectOneAction *act, GObject *tbl ) // move the x of all texts to preserve the same bbox Inkscape::Selection *selection = desktop->getSelection(); std::vector<SPItem*> itemlist=selection->itemList(); - for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end(); ++i){ if (SP_IS_TEXT(*i)) { SPItem *item = *i; @@ -526,7 +526,7 @@ static void sp_text_lineheight_value_changed( GtkAdjustment *adj, GObject *tbl ) Inkscape::Selection *selection = desktop->getSelection(); bool modmade = false; std::vector<SPItem*> itemlist=selection->itemList(); - for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end(); ++i){ if (SP_IS_TEXT (*i)) { (*i)->getRepr()->setAttribute("sodipodi:linespacing", sp_repr_css_property (css, "line-height", NULL)); modmade = true; @@ -737,7 +737,7 @@ static void sp_text_rotation_value_changed( GtkAdjustment *adj, GObject *tbl ) g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); } -static void sp_text_orientation_mode_changed( EgeSelectOneAction *act, GObject *tbl ) +static void sp_writing_mode_changed( EgeSelectOneAction *act, GObject *tbl ) { // quit if run by the _changed callbacks if (g_object_get_data(G_OBJECT(tbl), "freeze")) { @@ -752,13 +752,73 @@ static void sp_text_orientation_mode_changed( EgeSelectOneAction *act, GObject * { case 0: { - sp_repr_css_set_property (css, "writing-mode", "lr"); + sp_repr_css_set_property (css, "writing-mode", "lr-tb"); break; } case 1: { - sp_repr_css_set_property (css, "writing-mode", "tb"); + sp_repr_css_set_property (css, "writing-mode", "tb-rl"); + break; + } + + case 2: + { + sp_repr_css_set_property (css, "writing-mode", "vertical-lr"); + break; + } +} + + SPStyle query(SP_ACTIVE_DOCUMENT); + int result_numbers = + sp_desktop_query_style (SP_ACTIVE_DESKTOP, &query, QUERY_STYLE_PROPERTY_FONTNUMBERS); + + // If querying returned nothing, update default style. + if (result_numbers == QUERY_STYLE_NOTHING) + { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->mergeStyle("/tools/text/style", css); + } + + sp_desktop_set_style (SP_ACTIVE_DESKTOP, css, true, true); + if(result_numbers != QUERY_STYLE_NOTHING) + { + DocumentUndo::done(SP_ACTIVE_DESKTOP->getDocument(), SP_VERB_CONTEXT_TEXT, + _("Text: Change writing mode")); + } + sp_repr_css_attr_unref (css); + + g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); +} + +static void sp_text_orientation_changed( EgeSelectOneAction *act, GObject *tbl ) +{ + // quit if run by the _changed callbacks + if (g_object_get_data(G_OBJECT(tbl), "freeze")) { + return; + } + g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) ); + + int mode = ege_select_one_action_get_active( act ); + + SPCSSAttr *css = sp_repr_css_attr_new (); + switch (mode) + { + case 0: + { + sp_repr_css_set_property (css, "text-orientation", "auto"); + break; + } + + case 1: + { + sp_repr_css_set_property (css, "text-orientation", "upright"); + break; + } + + case 2: + { + sp_repr_css_set_property (css, "text-orientation", "sideways"); break; } } @@ -871,7 +931,7 @@ static void sp_text_toolbox_selection_changed(Inkscape::Selection */*selection*/ // Find out if we have flowed text now so we can use it several places gboolean isFlow = false; std::vector<SPItem*> itemlist=SP_ACTIVE_DESKTOP->getSelection()->itemList(); - for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++){ + for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end(); ++i){ // const gchar* id = reinterpret_cast<SPItem *>(items->data)->getId(); // std::cout << " " << id << std::endl; if( SP_IS_FLOWTEXT(*i)) { @@ -893,13 +953,17 @@ static void sp_text_toolbox_selection_changed(Inkscape::Selection */*selection*/ int result_style = sp_desktop_query_style (SP_ACTIVE_DESKTOP, &query, QUERY_STYLE_PROPERTY_FONTSTYLE); int result_numbers = sp_desktop_query_style (SP_ACTIVE_DESKTOP, &query, QUERY_STYLE_PROPERTY_FONTNUMBERS); int result_baseline = sp_desktop_query_style (SP_ACTIVE_DESKTOP, &query, QUERY_STYLE_PROPERTY_BASELINES); + int result_wmode = sp_desktop_query_style (SP_ACTIVE_DESKTOP, &query, QUERY_STYLE_PROPERTY_WRITINGMODES); /* * If no text in selection (querying returned nothing), read the style from * the /tools/text preferencess (default style for new texts). Return if * tool bar already set to these preferences. */ - if (result_family == QUERY_STYLE_NOTHING || result_style == QUERY_STYLE_NOTHING || result_numbers == QUERY_STYLE_NOTHING) { + if (result_family == QUERY_STYLE_NOTHING || + result_style == QUERY_STYLE_NOTHING || + result_numbers == QUERY_STYLE_NOTHING || + result_wmode == QUERY_STYLE_NOTHING ) { // There are no texts in selection, read from preferences. query.readFromPrefs("/tools/text"); #ifdef DEBUG_TEXT @@ -1047,13 +1111,42 @@ static void sp_text_toolbox_selection_changed(Inkscape::Selection */*selection*/ gtk_adjustment_set_value( letterSpacingAdjustment, letterSpacing ); + // Writing mode + int activeButton2 = 0; + if (query.writing_mode.computed == SP_CSS_WRITING_MODE_LR_TB) activeButton2 = 0; + if (query.writing_mode.computed == SP_CSS_WRITING_MODE_TB_RL) activeButton2 = 1; + if (query.writing_mode.computed == SP_CSS_WRITING_MODE_TB_LR) activeButton2 = 2; + + EgeSelectOneAction* writingModeAction = + EGE_SELECT_ONE_ACTION( g_object_get_data( tbl, "TextWritingModeAction" ) ); + ege_select_one_action_set_active( writingModeAction, activeButton2 ); + // Orientation - int activeButton2 = (query.writing_mode.computed == SP_CSS_WRITING_MODE_LR_TB ? 0 : 1); + int activeButton3 = 0; + if (query.text_orientation.computed == SP_CSS_TEXT_ORIENTATION_MIXED ) activeButton3 = 0; + if (query.text_orientation.computed == SP_CSS_TEXT_ORIENTATION_UPRIGHT ) activeButton3 = 1; + if (query.text_orientation.computed == SP_CSS_TEXT_ORIENTATION_SIDEWAYS) activeButton3 = 2; EgeSelectOneAction* textOrientationAction = EGE_SELECT_ONE_ACTION( g_object_get_data( tbl, "TextOrientationAction" ) ); - ege_select_one_action_set_active( textOrientationAction, activeButton2 ); + ege_select_one_action_set_active( textOrientationAction, activeButton3 ); + + // Disable text orientation for horizontal text.. See above for why this nonsense + model = GTK_LIST_STORE( ege_select_one_action_get_model( textOrientationAction ) ); + path = gtk_tree_path_new_from_string("0"); + gtk_tree_model_get_iter( GTK_TREE_MODEL (model), &iter, path ); + gtk_list_store_set( model, &iter, /* column */ 3, activeButton2 != 0, -1 ); + + path = gtk_tree_path_new_from_string("1"); + gtk_tree_model_get_iter( GTK_TREE_MODEL (model), &iter, path ); + gtk_list_store_set( model, &iter, /* column */ 3, activeButton2 != 0, -1 ); + + path = gtk_tree_path_new_from_string("2"); + gtk_tree_model_get_iter( GTK_TREE_MODEL (model), &iter, path ); + gtk_list_store_set( model, &iter, /* column */ 3, activeButton2 != 0, -1 ); + + ege_select_one_action_update_sensitive( textOrientationAction ); } @@ -1165,7 +1258,7 @@ static void sp_text_toolbox_select_cb( GtkEntry* entry, GtkEntryIconPosition /*p SPDocument *document = desktop->getDocument(); std::vector<SPItem*> x,y; std::vector<SPItem*> allList = get_all_items(x, document->getRoot(), desktop, false, false, true, y); - for(std::vector<SPItem*>::const_reverse_iterator i=allList.rbegin();i!=allList.rend();i++){ + for(std::vector<SPItem*>::const_reverse_iterator i=allList.rbegin();i!=allList.rend(); ++i){ SPItem *item = *i; SPStyle *style = item->style; @@ -1387,7 +1480,7 @@ void sp_text_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObje g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_text_align_mode_changed), holder ); } - /* Orientation (Left to Right, Top to Bottom */ + /* Writing mode (Horizontal, Vertical-LR, Vertical-RL) */ { GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING ); @@ -1402,14 +1495,73 @@ void sp_text_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObje gtk_list_store_append( model, &iter ); gtk_list_store_set( model, &iter, - 0, _("Vertical"), - 1, _("Vertical text"), + 0, _("Vertical — RL"), + 1, _("Vertical text — lines: right to left"), 2, INKSCAPE_ICON("format-text-direction-vertical"), -1 ); + gtk_list_store_append( model, &iter ); + gtk_list_store_set( model, &iter, + 0, _("Vertical — LR"), + 1, _("Vertical text — lines: left to right"), // Mongolian! + 2, INKSCAPE_ICON("format-text-direction-vertical-lr"), + -1 ); + + EgeSelectOneAction* act = ege_select_one_action_new( "TextWritingModeAction", // Name + _("Writing mode"), // Label + _("Block progression"), // Tooltip + NULL, // Icon name + GTK_TREE_MODEL(model) ); // Model + + g_object_set( act, "short_label", "NotUsed", NULL ); + gtk_action_group_add_action( mainActions, GTK_ACTION(act) ); + g_object_set_data( holder, "TextWritingModeAction", act ); + + ege_select_one_action_set_appearance( act, "full" ); + ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE ); + g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL ); + ege_select_one_action_set_icon_column( act, 2 ); + ege_select_one_action_set_icon_size( act, secondarySize ); + ege_select_one_action_set_tooltip_column( act, 1 ); + + gint mode = prefs->getInt("/tools/text/writing_mode", 0); + ege_select_one_action_set_active( act, mode ); + g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_writing_mode_changed), holder ); + } + + /* Text (glyph) orientation (Auto (mixed), Upright, Sideways) */ + { + GtkListStore* model = gtk_list_store_new( 4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN ); + + GtkTreeIter iter; + + gtk_list_store_append( model, &iter ); + gtk_list_store_set( model, &iter, + 0, _("Auto"), + 1, _("Auto glyph orientation"), + 2, INKSCAPE_ICON("text-orientation-auto"), + 3, true, + -1 ); + + gtk_list_store_append( model, &iter ); + gtk_list_store_set( model, &iter, + 0, _("Upright"), + 1, _("Upright glyph orientation"), + 2, INKSCAPE_ICON("text-orientation-upright"), + 3, true, + -1 ); + + gtk_list_store_append( model, &iter ); + gtk_list_store_set( model, &iter, + 0, _("Sideways"), + 1, _("Sideways glyph orientation"), + 2, INKSCAPE_ICON("text-orientation-sideways"), + 3, true, + -1 ); + EgeSelectOneAction* act = ege_select_one_action_new( "TextOrientationAction", // Name - _("Orientation"), // Label - _("Text orientation"), // Tooltip + _("Text orientation"), // Label + _("Text (glyph) orientation in vertical text."), // Tooltip NULL, // Icon name GTK_TREE_MODEL(model) ); // Model @@ -1423,10 +1575,11 @@ void sp_text_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObje ege_select_one_action_set_icon_column( act, 2 ); ege_select_one_action_set_icon_size( act, secondarySize ); ege_select_one_action_set_tooltip_column( act, 1 ); + ege_select_one_action_set_sensitive_column( act, 3 ); - gint mode = prefs->getInt("/tools/text/orientation", 0); + gint mode = prefs->getInt("/tools/text/text_orientation", 0); ege_select_one_action_set_active( act, mode ); - g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_text_orientation_mode_changed), holder ); + g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_text_orientation_changed), holder ); } /* Line height */ diff --git a/src/widgets/toolbox.cpp b/src/widgets/toolbox.cpp index cdf39e9ef..b75cdb4be 100644 --- a/src/widgets/toolbox.cpp +++ b/src/widgets/toolbox.cpp @@ -16,10 +16,11 @@ * Tavmjong Bah <tavmjong@free.fr> * Abhishek Sharma * Kris De Gussem <Kris.DeGussem@gmail.com> + * Jabiertxo Arraiza <jabier.arraiza@marker.es> * * Copyright (C) 2004 David Turner * Copyright (C) 2003 MenTaLguY - * Copyright (C) 1999-2011 authors + * Copyright (C) 1999-2015 authors * Copyright (C) 2001-2002 Ximian, Inc. * * Released under GNU GPL, read the file 'COPYING' for more information @@ -78,7 +79,11 @@ #include "measure-toolbar.h" #include "node-toolbar.h" #include "rect-toolbar.h" -#include "paintbucket-toolbar.h" + +#if HAVE_POTRACE +# include "paintbucket-toolbar.h" +#endif + #include "pencil-toolbar.h" #include "select-toolbar.h" #include "spray-toolbar.h" @@ -150,7 +155,9 @@ static struct { { "/tools/calligraphic", "dyna_draw_tool", SP_VERB_CONTEXT_CALLIGRAPHIC, SP_VERB_CONTEXT_CALLIGRAPHIC_PREFS }, { "/tools/lpetool", "lpetool_tool", SP_VERB_CONTEXT_LPETOOL, SP_VERB_CONTEXT_LPETOOL_PREFS }, { "/tools/eraser", "eraser_tool", SP_VERB_CONTEXT_ERASER, SP_VERB_CONTEXT_ERASER_PREFS }, +#if HAVE_POTRACE { "/tools/paintbucket", "paintbucket_tool", SP_VERB_CONTEXT_PAINTBUCKET, SP_VERB_CONTEXT_PAINTBUCKET_PREFS }, +#endif { "/tools/text", "text_tool", SP_VERB_CONTEXT_TEXT, SP_VERB_CONTEXT_TEXT_PREFS }, { "/tools/connector","connector_tool", SP_VERB_CONTEXT_CONNECTOR, SP_VERB_CONTEXT_CONNECTOR_PREFS }, { "/tools/gradient", "gradient_tool", SP_VERB_CONTEXT_GRADIENT, SP_VERB_CONTEXT_GRADIENT_PREFS }, @@ -211,8 +218,10 @@ static struct { SP_VERB_INVALID, 0, 0}, { "/tools/mesh", "mesh_toolbox", 0, sp_mesh_toolbox_prep, "MeshToolbar", SP_VERB_INVALID, 0, 0}, +#if HAVE_POTRACE { "/tools/paintbucket", "paintbucket_toolbox", 0, sp_paintbucket_toolbox_prep, "PaintbucketToolbar", SP_VERB_CONTEXT_PAINTBUCKET_PREFS, "/tools/paintbucket", N_("Style of Paint Bucket fill objects")}, +#endif { NULL, NULL, NULL, NULL, NULL, SP_VERB_INVALID, NULL, NULL } }; @@ -309,14 +318,28 @@ static gchar const * ui_descr = " <toolitem action='SprayModeAction' />" " <separator />" " <toolitem action='SprayWidthAction' />" + " <toolitem action='SprayPressureWidthAction' />" " <toolitem action='SprayPopulationAction' />" - " <toolitem action='SprayPressureAction' />" + " <toolitem action='SprayPressurePopulationAction' />" " <separator />" " <toolitem action='SprayRotationAction' />" " <toolitem action='SprayScaleAction' />" + " <toolitem action='SprayPressureScaleAction' />" " <separator />" " <toolitem action='SprayStandard_deviationAction' />" " <toolitem action='SprayMeanAction' />" + " <separator />" + " <toolitem action='SprayOverNoTransparentAction' />" + " <toolitem action='SprayOverTransparentAction' />" + " <toolitem action='SprayPickNoOverlapAction' />" + " <toolitem action='SprayNoOverlapAction' />" + " <toolitem action='SprayToolOffsetAction' />" + " <separator />" + " <toolitem action='SprayPickColorAction' />" + " <toolitem action='SprayPickFillAction' />" + " <toolitem action='SprayPickStrokeAction' />" + " <toolitem action='SprayPickInverseValueAction' />" + " <toolitem action='SprayPickCenterAction' />" " </toolbar>" " <toolbar name='ZoomToolbar'>" @@ -339,9 +362,23 @@ static gchar const * ui_descr = " <toolbar name='MeasureToolbar'>" " <toolitem action='MeasureFontSizeAction' />" " <separator />" + " <toolitem action='MeasurePrecisionAction' />" + " <separator />" + " <toolitem action='MeasureScaleAction' />" + " <separator />" + " <toolitem action='MeasureOffsetAction' />" + " <separator />" " <toolitem action='measure_units_label' />" " <toolitem action='MeasureUnitsAction' />" - " </toolbar>" + " <toolitem action='MeasureIgnore1stAndLast' />" + " <toolitem action='MeasureInBettween' />" + " <toolitem action='MeasureOnlyVisible' />" + " <toolitem action='MeasureAllLayers' />" + " <toolitem action='MeasureReverse' />" + " <toolitem action='MeasureToGuides' />" + " <toolitem action='MeasureMarkDimension' />" + " <toolitem action='MeasureToItem' />" + " </toolbar>" " <toolbar name='StarToolbar'>" " <separator />" @@ -440,6 +477,7 @@ static gchar const * ui_descr = " <separator />" " </toolbar>" +#if HAVE_POTRACE " <toolbar name='PaintbucketToolbar'>" " <toolitem action='ChannelsAction' />" " <separator />" @@ -452,6 +490,7 @@ static gchar const * ui_descr = " <separator />" " <toolitem action='PaintbucketResetAction' />" " </toolbar>" +#endif " <toolbar name='EraserToolbar'>" " <toolitem action='EraserModeAction' />" @@ -478,6 +517,8 @@ static gchar const * ui_descr = " <toolitem action='TextDyAction' />" " <toolitem action='TextRotationAction' />" " <separator />" + " <toolitem action='TextWritingModeAction' />" + " <separator />" " <toolitem action='TextOrientationAction' />" " </toolbar>" @@ -519,9 +560,12 @@ static gchar const * ui_descr = // " <toolitem action='MeshEditFillAction' />" // " <toolitem action='MeshEditStrokeAction' />" // " <toolitem action='MeshShowHandlesAction' />" + " <toolitem action='MeshToggleSidesAction' />" + " <toolitem action='MeshMakeEllipticalAction' />" + " <toolitem action='MeshPickColorsAction' />" + " <separator />" " <toolitem action='MeshWarningAction' />" " <toolitem action='MeshSmoothAction' />" - " <separator />" " </toolbar>" " <toolbar name='DropperToolbar'>" @@ -899,8 +943,12 @@ static Glib::RefPtr<Gtk::ActionGroup> create_or_fetch_actions( SPDesktop* deskto }; Inkscape::IconSize toolboxSize = ToolboxFactory::prefToSize("/toolbox/small"); - Glib::RefPtr<Gtk::ActionGroup> mainActions; + if (desktop == NULL) + { + return mainActions; + } + if ( groups.find(desktop) != groups.end() ) { mainActions = groups[desktop]; } @@ -908,10 +956,7 @@ static Glib::RefPtr<Gtk::ActionGroup> create_or_fetch_actions( SPDesktop* deskto if ( !mainActions ) { mainActions = Gtk::ActionGroup::create("main"); groups[desktop] = mainActions; - if (desktop) - { - desktop->connectDestroy(&desktopDestructHandler); - } + desktop->connectDestroy(&desktopDestructHandler); } for ( guint i = 0; i < G_N_ELEMENTS(verbsToUse); i++ ) { @@ -1291,8 +1336,11 @@ void setup_tool_toolbox(GtkWidget *toolbox, SPDesktop *desktop) " <toolitem action='ToolSpray' />" " <toolitem action='ToolEraser' />" +#if HAVE_POTRACE " <!-- Fill -->" " <toolitem action='ToolPaintBucket' />" +#endif + " <toolitem action='ToolGradient' />" #ifdef WITH_MESH " <toolitem action='ToolMesh' />" @@ -1511,13 +1559,12 @@ static void toggle_snap_callback(GtkToggleAction *act, gpointer data) //data poi SPDesktop *dt = reinterpret_cast<SPDesktop*>(ptr); SPNamedView *nv = dt->getNamedView(); - SPDocument *doc = nv->document; - - if (dt == NULL || nv == NULL) { - g_warning("No desktop or namedview specified (in toggle_snap_callback)!"); + if (nv == NULL) { + g_warning("No namedview specified (in toggle_snap_callback)!"); return; } + SPDocument *doc = nv->document; Inkscape::XML::Node *repr = nv->getRepr(); if (repr == NULL) { diff --git a/src/widgets/tweak-toolbar.cpp b/src/widgets/tweak-toolbar.cpp index a5d90fc3d..e2c0daf6e 100644 --- a/src/widgets/tweak-toolbar.cpp +++ b/src/widgets/tweak-toolbar.cpp @@ -288,7 +288,7 @@ void sp_tweak_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObj NULL, Inkscape::ICON_SIZE_DECORATION ); //TRANSLATORS: "H" here stands for hue - g_object_set( act, "short_label", _("H"), NULL ); + g_object_set( act, "short_label", C_("Hue", "H"), NULL ); gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(tweak_toggle_doh), desktop ); gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/tweak/doh", true) ); @@ -304,7 +304,7 @@ void sp_tweak_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObj NULL, Inkscape::ICON_SIZE_DECORATION ); //TRANSLATORS: "S" here stands for Saturation - g_object_set( act, "short_label", _("S"), NULL ); + g_object_set( act, "short_label", C_("Saturation", "S"), NULL ); gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(tweak_toggle_dos), desktop ); gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/tweak/dos", true) ); @@ -320,7 +320,7 @@ void sp_tweak_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObj NULL, Inkscape::ICON_SIZE_DECORATION ); //TRANSLATORS: "L" here stands for Lightness - g_object_set( act, "short_label", _("L"), NULL ); + g_object_set( act, "short_label", C_("Lightness", "L"), NULL ); gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(tweak_toggle_dol), desktop ); gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/tweak/dol", true) ); @@ -336,7 +336,7 @@ void sp_tweak_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObj NULL, Inkscape::ICON_SIZE_DECORATION ); //TRANSLATORS: "O" here stands for Opacity - g_object_set( act, "short_label", _("O"), NULL ); + g_object_set( act, "short_label", C_("Opacity", "O"), NULL ); gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(tweak_toggle_doo), desktop ); gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/tweak/doo", true) ); diff --git a/src/xml/quote.cpp b/src/xml/quote.cpp index 02c12dfb0..b889b890d 100644 --- a/src/xml/quote.cpp +++ b/src/xml/quote.cpp @@ -1,81 +1,77 @@ /** \file - * XML quoting routines. - */ - -/* Based on Lauris' repr_quote_write in repr-io.cpp. - * - * Copyright (C) 1999-2002 Lauris Kaplinski - * Copyright (C) 2004 Monash University - * - * May be modified and/or redistributed under the terms of version 2 - * of the GNU General Public License: see the file `COPYING'. + * @brief XML quoting routines + *//* + * Authors: + * Krzysztof Kosiński <tweenk.pl@gmail.com> + * + * This file is in the public domain. */ +#include "xml/quote.h" #include <cstring> #include <glib.h> -#include "quote.h" - -/** \return strlen(xml_quote_strdup(\a val)) (without doing the malloc). - * \pre val != NULL - */ -size_t -xml_quoted_strlen(char const *val) +/// Returns the length of the string after quoting the characters <code>"&<></code>. +size_t xml_quoted_strlen(char const *val) { - size_t ret = 0; - if (val != NULL) { - for (; *val != '\0'; val++) { - switch (*val) { - case '"': ret += sizeof(""") - 1; break; - case '&': ret += sizeof("&") - 1; break; - case '<': ret += sizeof("<") - 1; break; - case '>': ret += sizeof(">") - 1; break; - default: ++ret; break; - } + if (!val) return 0; + size_t len = 0; + + for (char const *valp = val; *valp; ++valp) { + switch (*valp) { + case '"': + len += 6; // " + break; + case '&': + len += 5; // & + break; + case '<': + case '>': + len += 4; // < or > + break; + default: + ++len; + break; } } - return ret; + return len; } -/** Writes \a src (including the NUL byte) to \a dest, doing XML quoting as necessary. - * - * \pre \a src != NULL. - * \pre \a dest must have enough space for (xml_quoted_strlen(src) + 1) bytes. - */ -static void -xml_quote(char *dest, char const *src) +char *xml_quote_strdup(char const *src) { -#define COPY_LIT(_lit) do { \ - size_t cpylen = sizeof(_lit "") - 1; \ - memcpy(dest, _lit, cpylen); \ - dest += cpylen; \ - } while(0) + size_t len = xml_quoted_strlen(src); + char *result = static_cast<char*>(g_malloc(len + 1)); + char *resp = result; - for (; *src != '\0'; ++src) { - switch (*src) { - case '"': COPY_LIT("""); break; - case '&': COPY_LIT("&"); break; - case '<': COPY_LIT("<"); break; - case '>': COPY_LIT(">"); break; - default: *dest++ = *src; break; + for (char const *srcp = src; *srcp; ++srcp) { + switch(*srcp) { + case '"': + strcpy(resp, """); + resp += 6; + break; + case '&': + strcpy(resp, "&"); + resp += 5; + break; + case '<': + strcpy(resp, "<"); + resp += 4; + break; + case '>': + strcpy(resp, ">"); + resp += 4; + break; + default: + *resp++ = *srcp; + break; } } - *dest = '\0'; - -#undef COPY_LIT + *resp = 0; + return result; } -/** \return A g_malloc'd buffer containing an XML-quoted version of \a src. - * \pre src != NULL. - */ -char * -xml_quote_strdup(char const *src) -{ - size_t const quoted_size = xml_quoted_strlen(src) + 1; - char *ret = (char *) g_malloc(quoted_size); - xml_quote(ret, src); - return ret; -} +// quote: ", &, <, > + /* Local Variables: diff --git a/src/xml/repr-util.cpp b/src/xml/repr-util.cpp index f7a437163..ce93bccab 100644 --- a/src/xml/repr-util.cpp +++ b/src/xml/repr-util.cpp @@ -528,6 +528,7 @@ unsigned int sp_repr_set_svg_double(Inkscape::XML::Node *repr, gchar const *key, { g_return_val_if_fail(repr != NULL, FALSE); g_return_val_if_fail(key != NULL, FALSE); + g_return_val_if_fail(val==val, FALSE);//tests for nan Inkscape::SVGOStringStream os; os << val; |
