summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorsu_v <suv-sf@users.sourceforge.net>2014-09-19 00:07:09 +0000
committer~suv <suv-sf@users.sourceforge.net>2014-09-19 00:07:09 +0000
commit274a671c959becc8c989dc6a3561c608c173f6d3 (patch)
tree1ab36b51da49862d28ebebb8ed0db985735f6f5b /src
parentupdate to trunk (r13540) (diff)
parentFix build for fink on OS X 10.9 by including unistd.h (diff)
downloadinkscape-274a671c959becc8c989dc6a3561c608c173f6d3.tar.gz
inkscape-274a671c959becc8c989dc6a3561c608c173f6d3.zip
update to trunk (r13560)
(bzr r13398.1.10)
Diffstat (limited to 'src')
-rw-r--r--src/color-profile.cpp1
-rw-r--r--src/document.cpp1
-rw-r--r--src/extension/internal/emf-inout.cpp29
-rw-r--r--src/extension/internal/emf-inout.h3
-rw-r--r--src/extension/internal/emf-print.cpp187
-rw-r--r--src/extension/internal/emf-print.h4
-rw-r--r--src/extension/internal/metafile-inout.cpp2
-rw-r--r--src/extension/internal/metafile-print.h2
-rw-r--r--src/extension/internal/wmf-inout.cpp4
-rw-r--r--src/extension/internal/wmf-inout.h2
-rw-r--r--src/extension/prefdialog.cpp4
-rw-r--r--src/extension/system.cpp3
-rw-r--r--src/inkscape.cpp2
-rw-r--r--src/live_effects/lpe-powerstroke-interpolators.h90
-rw-r--r--src/live_effects/lpe-powerstroke.cpp14
-rw-r--r--src/live_effects/parameter/path.cpp2
-rw-r--r--src/live_effects/parameter/text.cpp2
-rw-r--r--src/object-snapper.cpp2
-rw-r--r--src/selection-chemistry.cpp2
-rw-r--r--src/sp-item-group.cpp33
-rw-r--r--src/sp-item-group.h2
-rw-r--r--src/ui/CMakeLists.txt4
-rw-r--r--src/ui/dialog/document-properties.cpp3
-rw-r--r--src/ui/dialog/inkscape-preferences.cpp4
-rw-r--r--src/ui/tools/freehand-base.cpp9
-rw-r--r--src/widgets/node-toolbar.cpp2
-rw-r--r--src/widgets/rect-toolbar.cpp2
27 files changed, 350 insertions, 65 deletions
diff --git a/src/color-profile.cpp b/src/color-profile.cpp
index aa0750c00..6f335b590 100644
--- a/src/color-profile.cpp
+++ b/src/color-profile.cpp
@@ -19,6 +19,7 @@
#include <gtk/gtk.h>
#endif // DEBUG_LCMS
+#include <unistd.h>
#include <cstring>
#include <string>
#include <io/sys.h>
diff --git a/src/document.cpp b/src/document.cpp
index f79a00178..f94a9f04f 100644
--- a/src/document.cpp
+++ b/src/document.cpp
@@ -229,7 +229,6 @@ SPDocument::~SPDocument() {
// This is at the end of the destructor, because preceding code adds new orphans to the queue
collectOrphans();
- //delete this->_whiteboard_session_manager;
}
sigc::connection SPDocument::connectDestroy(sigc::signal<void>::slot_type slot)
diff --git a/src/extension/internal/emf-inout.cpp b/src/extension/internal/emf-inout.cpp
index 084fbcd58..ee5e76969 100644
--- a/src/extension/internal/emf-inout.cpp
+++ b/src/extension/internal/emf-inout.cpp
@@ -63,6 +63,7 @@ namespace Internal {
static uint32_t ICMmode = 0; // not used yet, but code to read it from EMF implemented
static uint32_t BLTmode = 0;
+float faraway = 10000000; // used in "exclude" clips, hopefully well outside any real drawing!
Emf::Emf (void) // The null constructor
{
@@ -1040,13 +1041,30 @@ Emf::pix_to_abs_size(PEMF_CALLBACK_DATA d, double px)
return ppx;
}
-/* returns "x,y" (without the quotes) in inkscape coordinates for a pair of EMF x,y coordinates
+/* snaps coordinate pairs made up of values near +/-faraway, +/-faraway to exactly faraway.
+ This eliminates coordinate drift on repeated clipping cycles which use exclude.
+ It should not affect internals of normal drawings because the value of faraway is so large.
+*/
+void
+Emf::snap_to_faraway_pair(double *x, double *y)
+{
+ if((abs(abs(*x) - faraway)/faraway <= 1e-4) && (abs(abs(*y) - faraway)/faraway <= 1e-4)){
+ *x = (*x > 0 ? faraway : -faraway);
+ *y = (*y > 0 ? faraway : -faraway);
+ }
+}
+
+/* returns "x,y" (without the quotes) in inkscape coordinates for a pair of EMF x,y coordinates.
+ Since exclude clip can go through here, it calls snap_to_faraway_pair for numerical stability.
*/
std::string Emf::pix_to_xy(PEMF_CALLBACK_DATA d, double x, double y){
std::stringstream cxform;
- cxform << pix_to_x_point(d,x,y);
+ double tx = pix_to_x_point(d,x,y);
+ double ty = pix_to_y_point(d,x,y);
+ snap_to_faraway_pair(&tx,&ty);
+ cxform << tx;
cxform << ",";
- cxform << pix_to_y_point(d,x,y);
+ cxform << ty;
return(cxform.str());
}
@@ -2221,7 +2239,6 @@ std::cout << "BEFORE DRAW"
U_RECTL rc = pEmr->rclClip;
SVGOStringStream tmp_path;
- float faraway = 10000000; // hopefully well outside any real drawing!
//outer rect, clockwise
tmp_path << "M " << faraway << "," << faraway << " ";
tmp_path << "L " << faraway << "," << -faraway << " ";
@@ -3466,6 +3483,8 @@ Emf::open( Inkscape::Extension::Input * /*mod*/, const gchar *uri )
return NULL;
}
+ d.dc[0].font_name = strdup("Arial"); // Default font, set only on lowest level, it copies up from there EMF spec says device can pick whatever it wants
+
// set up the size default for patterns in defs. This might not be referenced if there are no patterns defined in the drawing.
d.defs += "\n";
@@ -3513,7 +3532,7 @@ Emf::open( Inkscape::Extension::Input * /*mod*/, const gchar *uri )
d.dc[0].style.stroke_dasharray.values.clear();
- for(int i=0; i<=d.level;i++){
+ for(int i=0; i<=EMF_MAX_DC; i++){
if(d.dc[i].font_name)free(d.dc[i].font_name);
}
diff --git a/src/extension/internal/emf-inout.h b/src/extension/internal/emf-inout.h
index 302d5c474..c64299093 100644
--- a/src/extension/internal/emf-inout.h
+++ b/src/extension/internal/emf-inout.h
@@ -65,7 +65,7 @@ typedef struct emf_device_context {
textAlign(0)
// worldTransform, cur
{
- font_name = strdup("Arial"); // Default font, EMF spec says device can pick whatever it wants
+ font_name = NULL;
sizeWnd = sizel_set( 0.0, 0.0 );
sizeView = sizel_set( 0.0, 0.0 );
winorg = point32_set( 0.0, 0.0 );
@@ -218,6 +218,7 @@ protected:
static double pix_to_x_point(PEMF_CALLBACK_DATA d, double px, double py);
static double pix_to_y_point(PEMF_CALLBACK_DATA d, double px, double py);
static double pix_to_abs_size(PEMF_CALLBACK_DATA d, double px);
+ static void snap_to_faraway_pair(double *x, double *y);
static std::string pix_to_xy(PEMF_CALLBACK_DATA d, double x, double y);
static void select_pen(PEMF_CALLBACK_DATA d, int index);
static void select_extpen(PEMF_CALLBACK_DATA d, int index);
diff --git a/src/extension/internal/emf-print.cpp b/src/extension/internal/emf-print.cpp
index e054829b5..0f43fbca1 100644
--- a/src/extension/internal/emf-print.cpp
+++ b/src/extension/internal/emf-print.cpp
@@ -55,6 +55,7 @@
#include "sp-radial-gradient.h"
#include "sp-linear-gradient.h"
#include "display/cairo-utils.h"
+#include "sp-shape.h"
#include "splivarot.h" // pieces for union on shapes
#include "2geom/svg-path-parser.h" // to get from SVG text to Geom::Path
@@ -143,6 +144,7 @@ unsigned int PrintEmf::begin(Inkscape::Extension::Print *mod, SPDocument *doc)
// width and height in px
_width = doc->getWidth().value("px");
_height = doc->getHeight().value("px");
+ _doc_unit_scale = Inkscape::Util::Quantity::convert(1, (doc->getDefaultUnit()), "px");
// initialize a few global variables
hbrush = hbrushOld = hpen = 0;
@@ -298,6 +300,7 @@ unsigned int PrintEmf::begin(Inkscape::Extension::Print *mod, SPDocument *doc)
unsigned int PrintEmf::finish(Inkscape::Extension::Print * /*mod*/)
{
+ do_clip_if_present(NULL); // Terminate any open clip.
char *rec;
if (!et) {
return 0;
@@ -969,19 +972,145 @@ U_TRIVERTEX PrintEmf::make_trivertex(Geom::Point Pt, U_COLORREF uc){
return(tv);
}
+/* Examine clip. If there is a (new) one then apply it. If there is one and it is the
+ same as the preceding one, leave the preceding one active. If style is NULL
+ terminate the current clip, if any, and return.
+*/
+void PrintEmf::do_clip_if_present(SPStyle const *style){
+ char *rec;
+ static SPClipPath *scpActive = NULL;
+ if(!style){
+ if(scpActive){ // clear the existing clip
+ rec = U_EMRRESTOREDC_set(-1);
+ if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintEmf::fill at U_EMRRESTOREDC_set");
+ }
+ scpActive=NULL;
+ }
+ } else {
+ /* The current implementation converts only one level of clipping. If there were more
+ clips further up the stack they should be combined with the pathvector using "and". Since this
+ comes up rarely, and would involve a lot of searching (all the way up the stack for every
+ draw operation), it has not yet been implemented.
+
+ Note, to debug this section of code use print statements on sp_svg_write_path(combined_pathvector).
+ */
+ /* find the first clip_ref at object or up the stack. There may not be one. */
+ SPClipPath *scp = NULL;
+ SPItem *item = SP_ITEM(style->object);
+ while(1) {
+ scp = (item->clip_ref ? item->clip_ref->getObject() : NULL);
+ if(scp)break;
+ item = SP_ITEM(item->parent);
+ if(!item || SP_IS_ROOT(item))break; // this will never be a clipping path
+ }
+
+ if(scp != scpActive){ // change or remove the clipping
+ if(scpActive){ // clear the existing clip
+ rec = U_EMRRESTOREDC_set(-1);
+ if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintEmf::fill at U_EMRRESTOREDC_set");
+ }
+ scpActive = NULL;
+ }
+
+ if (scp) { // set the new clip
+ /* because of units and who knows what other transforms that might be applied above we
+ need the full transform all the way to the root.
+ */
+ Geom::Affine tf = item->transform;
+ SPItem *scan_item = item;
+ while(1) {
+ scan_item = SP_ITEM(scan_item->parent);
+ if(!scan_item)break;
+ tf *= scan_item->transform;
+ }
+ tf *= Geom::Scale(_doc_unit_scale);; // Transform must be in PIXELS, no matter what the document unit is.
+
+ /* find the clipping path */
+ Geom::PathVector combined_pathvector;
+ Geom::Affine tfc; // clipping transform, generally not the same as item transform
+ for(item = SP_ITEM(scp->firstChild()); item; item=SP_ITEM(item->getNext())){
+ if (SP_IS_GROUP(item)) { // not implemented
+ // return sp_group_render(item);
+ combined_pathvector = merge_PathVector_with_group(combined_pathvector, item, tfc);
+ } else if (SP_IS_SHAPE(item)) {
+ combined_pathvector = merge_PathVector_with_shape(combined_pathvector, item, tfc);
+ } else { // not implemented
+ }
+ }
+
+ if (!combined_pathvector.empty()) { // if clipping path isn't empty, define EMF clipping record
+ scpActive = scp; // remember for next time
+ // the sole purpose of this SAVEDC is to let us clear the clipping region later.
+ rec = U_EMRSAVEDC_set();
+ if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintEmf::image at U_EMRSAVEDC_set");
+ }
+ (void) draw_pathv_to_EMF(combined_pathvector, tf);
+ rec = U_EMRSELECTCLIPPATH_set(U_RGN_OR);
+ if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
+ g_error("Fatal programming error in PrintEmf::do_clip_if_present at U_EMRSELECTCLIPPATH_set");
+ }
+ }
+ else {
+ scpActive = NULL; // no valid path available to draw, so no DC was saved, so no signal to restore
+ }
+ } // change or remove clipping
+ } // scp exists
+ } // style exists
+}
+
+Geom::PathVector PrintEmf::merge_PathVector_with_group(Geom::PathVector const &combined_pathvector, SPItem const *item, const Geom::Affine &transform)
+{
+ Geom::PathVector new_combined_pathvector;
+ if(!SP_IS_GROUP(item))return(new_combined_pathvector); // sanity test, only a group should be passed in, return empty if something else happens
+
+ new_combined_pathvector = combined_pathvector;
+ SPGroup *group = SP_GROUP(item);
+ Geom::Affine tfc = item->transform * transform;
+ for(SPItem *item = SP_ITEM(group->firstChild()); item; item=SP_ITEM(item->getNext())){
+ if (SP_IS_GROUP(item)) {
+ new_combined_pathvector = merge_PathVector_with_group(new_combined_pathvector, item, tfc); // could be endlessly recursive on a badly formed SVG
+ } else if (SP_IS_SHAPE(item)) {
+ new_combined_pathvector = merge_PathVector_with_shape(new_combined_pathvector, item, tfc);
+ } else { // not implemented
+ }
+ }
+ return new_combined_pathvector;
+}
+
+Geom::PathVector PrintEmf::merge_PathVector_with_shape(Geom::PathVector const &combined_pathvector, SPItem const *item, const Geom::Affine &transform)
+{
+ Geom::PathVector new_combined_pathvector;
+ if(!SP_IS_SHAPE(item))return(new_combined_pathvector); // sanity test, only a shape should be passed in, return empty if something else happens
+
+ Geom::Affine tfc = item->transform * transform;
+ SPShape *shape = SP_SHAPE(item);
+ if (shape->_curve) {
+ Geom::PathVector const & new_vect = shape->_curve->get_pathvector();
+ if(combined_pathvector.empty()){
+ new_combined_pathvector = new_vect * tfc;
+ }
+ else {
+ new_combined_pathvector = sp_pathvector_boolop(new_vect * tfc, combined_pathvector, bool_op_union , (FillRule) fill_oddEven, (FillRule) fill_oddEven);
+ }
+ }
+ return new_combined_pathvector;
+}
+
unsigned int PrintEmf::fill(
Inkscape::Extension::Print * /*mod*/,
Geom::PathVector const &pathv, Geom::Affine const & /*transform*/, SPStyle const *style,
Geom::OptRect const &/*pbox*/, Geom::OptRect const &/*dbox*/, Geom::OptRect const &/*bbox*/)
{
+ char *rec;
using Geom::X;
using Geom::Y;
-
- //SPItem *item = SP_ITEM(style->object);
- //SPClipPath *scp = (item->clip_ref ? item->clip_ref->getObject() : NULL);
-
Geom::Affine tf = m_tr_stack.top();
+ do_clip_if_present(style); // If clipping is needed set it up
+
use_fill = true;
use_stroke = false;
@@ -1095,7 +1224,6 @@ unsigned int PrintEmf::fill(
}
} else if (gv.mode == DRAW_LINEAR_GRADIENT) {
if(is_Rect){
- char *rec;
int gMode;
Geom::Point ul, ur, lr;
Geom::Point outUL, outLR; // UL,LR corners of a stop rectangle, in OUTPUT coordinates
@@ -1284,6 +1412,7 @@ unsigned int PrintEmf::stroke(
char *rec = NULL;
Geom::Affine tf = m_tr_stack.top();
+ do_clip_if_present(style); // If clipping is needed set it up
use_stroke = true;
// use_fill was set in ::fill, if it is needed
@@ -1568,12 +1697,14 @@ unsigned int PrintEmf::image(
unsigned int h, /** height of bitmap */
unsigned int rs, /** row stride (normally w*4) */
Geom::Affine const &tf_rect, /** affine transform only used for defining location and size of rect, for all other tranforms, use the one from m_tr_stack */
- SPStyle const * /*style*/) /** provides indirect link to image object */
+ SPStyle const *style) /** provides indirect link to image object */
{
double x1, y1, dw, dh;
char *rec = NULL;
Geom::Affine tf = m_tr_stack.top();
+ do_clip_if_present(style); // If clipping is needed set it up
+
rec = U_EMRSETSTRETCHBLTMODE_set(U_COLORONCOLOR);
if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
g_error("Fatal programming error in PrintEmf::image at EMRHEADER");
@@ -1658,28 +1789,14 @@ unsigned int PrintEmf::image(
return 0;
}
-// may also be called with a simple_shape or an empty path, whereupon it just returns without doing anything
-unsigned int PrintEmf::print_pathv(Geom::PathVector const &pathv, const Geom::Affine &transform)
-{
- Geom::Affine tf = transform;
- char *rec = NULL;
-
- simple_shape = print_simple_shape(pathv, tf);
- if (simple_shape || pathv.empty()) {
- if (use_fill) {
- destroy_brush(); // these must be cleared even if nothing is drawn or hbrush,hpen fill up
- }
- if (use_stroke) {
- destroy_pen();
- }
- return TRUE;
- }
+unsigned int PrintEmf::draw_pathv_to_EMF(Geom::PathVector const &pathv, const Geom::Affine &transform) {
+ char *rec;
/* inkscape to EMF scaling is done below, but NOT the rotation/translation transform,
that is handled by the EMF MODIFYWORLDTRANSFORM record
*/
-
- Geom::PathVector pv = pathv_to_linear_and_cubic_beziers(pathv * tf);
+
+ Geom::PathVector pv = pathv_to_linear_and_cubic_beziers(pathv * transform);
rec = U_EMRBEGINPATH_set();
if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
@@ -1781,6 +1898,27 @@ unsigned int PrintEmf::print_pathv(Geom::PathVector const &pathv, const Geom::Af
if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
g_error("Fatal programming error in PrintEmf::print_pathv at U_EMRENDPATH_set");
}
+ return(0);
+}
+
+// may also be called with a simple_shape or an empty path, whereupon it just returns without doing anything
+unsigned int PrintEmf::print_pathv(Geom::PathVector const &pathv, const Geom::Affine &transform)
+{
+ Geom::Affine tf = transform;
+ char *rec = NULL;
+
+ simple_shape = print_simple_shape(pathv, tf);
+ if (simple_shape || pathv.empty()) {
+ if (use_fill) {
+ destroy_brush(); // these must be cleared even if nothing is drawn or hbrush,hpen fill up
+ }
+ if (use_stroke) {
+ destroy_pen();
+ }
+ return TRUE;
+ }
+
+ (void) draw_pathv_to_EMF(pathv, tf);
// explicit FILL/STROKE commands are needed for each sub section of the path
if (use_fill && !use_stroke) {
@@ -1819,6 +1957,7 @@ unsigned int PrintEmf::text(Inkscape::Extension::Print * /*mod*/, char const *te
return 0;
}
+ do_clip_if_present(style); // If clipping is needed set it up
char *rec = NULL;
int ccount, newfont;
int fix90n = 0;
diff --git a/src/extension/internal/emf-print.h b/src/extension/internal/emf-print.h
index 9a1251b38..5bad48de5 100644
--- a/src/extension/internal/emf-print.h
+++ b/src/extension/internal/emf-print.h
@@ -69,6 +69,10 @@ public:
protected:
static void smuggle_adxkyrtl_out(const char *string, uint32_t **adx, double *ky, int *rtl, int *ndx, float scale);
+ void do_clip_if_present(SPStyle const *style);
+ Geom::PathVector merge_PathVector_with_group(Geom::PathVector const &combined_pathvector, SPItem const *item, const Geom::Affine &transform);
+ Geom::PathVector merge_PathVector_with_shape(Geom::PathVector const &combined_pathvector, SPItem const *item, const Geom::Affine &transform);
+ unsigned int draw_pathv_to_EMF(Geom::PathVector const &pathv, const Geom::Affine &transform);
Geom::Path pathv_to_simple_polygon(Geom::PathVector const &pathv, int *vertices);
Geom::Path pathv_to_rect(Geom::PathVector const &pathv, bool *is_rect, double *angle);
Geom::Point get_pathrect_corner(Geom::Path pathRect, double angle, int corner);
diff --git a/src/extension/internal/metafile-inout.cpp b/src/extension/internal/metafile-inout.cpp
index 162ad8b7d..28e9932b3 100644
--- a/src/extension/internal/metafile-inout.cpp
+++ b/src/extension/internal/metafile-inout.cpp
@@ -222,7 +222,7 @@ void Metafile::setViewBoxIfMissing(SPDocument *doc) {
prefs->setBool("/options/transform/pattern", true);
prefs->setBool("/options/transform/gradient", true);
- doc->getRoot()->scaleChildItemsRec(Geom::Scale(scale), Geom::Point(0, dh));
+ doc->getRoot()->scaleChildItemsRec(Geom::Scale(scale), Geom::Point(0, dh), true);
ShapeEditor::blockSetItem(false);
// restore options
diff --git a/src/extension/internal/metafile-print.h b/src/extension/internal/metafile-print.h
index a21f9de58..d184b72b7 100644
--- a/src/extension/internal/metafile-print.h
+++ b/src/extension/internal/metafile-print.h
@@ -69,6 +69,8 @@ protected:
double _width;
double _height;
+ double _doc_unit_scale; // to pixels, regardless of the document units
+
U_RECTL rc;
uint32_t htextalignment;
diff --git a/src/extension/internal/wmf-inout.cpp b/src/extension/internal/wmf-inout.cpp
index 5ccad678a..44d73ee8d 100644
--- a/src/extension/internal/wmf-inout.cpp
+++ b/src/extension/internal/wmf-inout.cpp
@@ -3062,6 +3062,8 @@ Wmf::open( Inkscape::Extension::Input * /*mod*/, const gchar *uri )
return NULL;
}
+ d.dc[0].font_name = strdup("Arial"); // Default font, set only on lowest level, it copies up from there WMF spec says device can pick whatever it wants
+
// set up the size default for patterns in defs. This might not be referenced if there are no patterns defined in the drawing.
d.defs += "\n";
@@ -3104,7 +3106,7 @@ Wmf::open( Inkscape::Extension::Input * /*mod*/, const gchar *uri )
d.dc[0].style.stroke_dasharray.values.clear();
- for(int i=0; i<=d.level;i++){
+ for(int i=0; i<=WMF_MAX_DC; i++){
if(d.dc[i].font_name)free(d.dc[i].font_name);
}
diff --git a/src/extension/internal/wmf-inout.h b/src/extension/internal/wmf-inout.h
index 27ec14358..5a0a760dd 100644
--- a/src/extension/internal/wmf-inout.h
+++ b/src/extension/internal/wmf-inout.h
@@ -65,7 +65,7 @@ typedef struct wmf_device_context {
textAlign(0)
// worldTransform, cur
{
- font_name = strdup("Arial"); // Default font, WMF spec says device can pick whatever it wants
+ font_name = NULL;
sizeWnd = point16_set( 0.0, 0.0 );
sizeView = point16_set( 0.0, 0.0 );
winorg = point16_set( 0.0, 0.0 );
diff --git a/src/extension/prefdialog.cpp b/src/extension/prefdialog.cpp
index d1f83701f..3a384257c 100644
--- a/src/extension/prefdialog.cpp
+++ b/src/extension/prefdialog.cpp
@@ -90,6 +90,10 @@ PrefDialog::PrefDialog (Glib::ustring name, gchar const * help, Gtk::Widget * co
if (_effect != NULL && !_effect->no_live_preview) {
if (_param_preview == NULL) {
XML::Document * doc = sp_repr_read_mem(live_param_xml, strlen(live_param_xml), NULL);
+ if (doc == NULL) {
+ std::cout << "Error encountered loading live parameter XML !!!" << std::endl;
+ return;
+ }
_param_preview = Parameter::make(doc->root(), _effect);
}
diff --git a/src/extension/system.cpp b/src/extension/system.cpp
index c244d9c16..45feb882f 100644
--- a/src/extension/system.cpp
+++ b/src/extension/system.cpp
@@ -556,7 +556,7 @@ build_from_file(gchar const *filename)
}
/**
- * \return The module created
+ * \return The module created, or NULL if buffer is invalid
* \brief This function creates a module from a buffer holding an
* XML description.
* \param buffer The buffer holding the XML description of the module.
@@ -568,6 +568,7 @@ Extension *
build_from_mem(gchar const *buffer, Implementation::Implementation *in_imp)
{
Inkscape::XML::Document *doc = sp_repr_read_mem(buffer, strlen(buffer), INKSCAPE_EXTENSION_URI);
+ g_return_val_if_fail(doc != NULL, NULL);
Extension *ext = build_from_reprdoc(doc, in_imp);
Inkscape::GC::release(doc);
return ext;
diff --git a/src/inkscape.cpp b/src/inkscape.cpp
index 4b4c8c678..e312e15b9 100644
--- a/src/inkscape.cpp
+++ b/src/inkscape.cpp
@@ -945,7 +945,7 @@ bool inkscape_load_menus( Inkscape::Application * inkscape )
inkscape->menus = sp_repr_read_mem(menus_skeleton, MENUS_SKELETON_SIZE, NULL);
}
- return (inkscape->menus != 0);
+ return (inkscape->menus != NULL);
}
diff --git a/src/live_effects/lpe-powerstroke-interpolators.h b/src/live_effects/lpe-powerstroke-interpolators.h
index 6f5b75af8..ee4951882 100644
--- a/src/live_effects/lpe-powerstroke-interpolators.h
+++ b/src/live_effects/lpe-powerstroke-interpolators.h
@@ -27,7 +27,8 @@ enum InterpolatorType {
INTERP_LINEAR,
INTERP_CUBICBEZIER,
INTERP_CUBICBEZIER_JOHAN,
- INTERP_SPIRO
+ INTERP_SPIRO,
+ INTERP_CENTRIPETAL_CATMULLROM
};
class Interpolator {
@@ -167,6 +168,91 @@ private:
SpiroInterpolator& operator=(const SpiroInterpolator&);
};
+class CentripetalCatmullRomInterpolator : public Interpolator {
+// the code in this class can certainly be optimized and made more terse, feel free
+public:
+ CentripetalCatmullRomInterpolator() {};
+ virtual ~CentripetalCatmullRomInterpolator() {};
+
+ virtual Path interpolateToPath(std::vector<Point> const &points) const {
+ unsigned int n_points = points.size();
+
+ Geom::Path fit(points.front());
+
+ if (n_points < 2) return fit;
+ if (n_points < 3) {
+ // if only 2 points, return linear segment
+ fit.appendNew<Geom::LineSegment>(points[1]);
+ return fit;
+ }
+
+ // return n_points-1 cubic segments
+
+ // duplicate first point
+ fit.append(calc_bezier(points[0],points[0],points[1],points[2]));
+
+ for (std::size_t i = 0; i < n_points-2; ++i) {
+ Point p0 = points[i];
+ Point p1 = points[i+1];
+ Point p2 = points[i+2];
+ Point p3 = (i < n_points-3) ? points[i+3] : points[i+2];
+
+ fit.append(calc_bezier(p0, p1, p2, p3));
+ // this is quite wasteful: the distances between the same points are repeatedly calculated by calc_bezier
+ }
+
+ return fit;
+ };
+
+private:
+ CubicBezier calc_bezier(Point p0, Point p1, Point p2, Point p3) const {
+ // create interpolating bezier between p1 and p2
+
+ // Part of the code comes from StackOverflow user eriatarka84
+ // http://stackoverflow.com/a/23980479/2929337
+
+ // calculate time coords (deltas) of points
+ // the factor 0.25 can be generalized for other Catmull-Rom interpolation types
+ // see alpha in Yuksel et al. "On the Parameterization of Catmull-Rom Curves",
+ // --> http://www.cemyuksel.com/research/catmullrom_param/catmullrom.pdf
+ double dt0 = powf(distanceSq(p0, p1), 0.25);
+ double dt1 = powf(distanceSq(p1, p2), 0.25);
+ double dt2 = powf(distanceSq(p2, p3), 0.25);
+
+
+ // safety check for repeated points
+ double eps = Geom::EPSILON;
+ if (dt1 < eps)
+ dt1 = 1.0;
+ if (dt0 < eps)
+ dt0 = dt1;
+ if (dt2 < eps)
+ dt2 = dt1;
+
+ // compute tangents when parameterized in [t1,t2]
+ Point tan1 = (p1 - p0) / dt0 - (p2 - p0) / (dt0 + dt1) + (p2 - p1) / dt1;
+ Point tan2 = (p2 - p1) / dt1 - (p3 - p1) / (dt1 + dt2) + (p3 - p2) / dt2;
+ // rescale tangents for parametrization in [0,1]
+ tan1 *= dt1;
+ tan2 *= dt1;
+
+ // create bezier from tangents (this is already in 2geom somewhere, or should be moved to it)
+ // the tangent of a bezier curve is: B'(t) = 3(1-t)^2 (b1 - b0) + 6(1-t)t(b2-b1) + 3t^2(b3-b2)
+ // So we have to make sure that B'(0) = tan1 and B'(1) = tan2, and we already know that b0=p1 and b3=p2
+ // tan1 = B'(0) = 3 (b1 - p1) --> p1 + (tan1)/3 = b1
+ // tan2 = B'(1) = 3 (p2 - b2) --> p2 - (tan2)/3 = b2
+
+ Point b0 = p1;
+ Point b1 = p1 + tan1 / 3;
+ Point b2 = p2 - tan2 / 3;
+ Point b3 = p2;
+
+ return CubicBezier(b0, b1, b2, b3);
+ }
+
+ CentripetalCatmullRomInterpolator(const CentripetalCatmullRomInterpolator&);
+ CentripetalCatmullRomInterpolator& operator=(const CentripetalCatmullRomInterpolator&);
+};
Interpolator*
Interpolator::create(InterpolatorType type) {
@@ -179,6 +265,8 @@ Interpolator::create(InterpolatorType type) {
return new Geom::Interpolate::CubicBezierJohan();
case INTERP_SPIRO:
return new Geom::Interpolate::SpiroInterpolator();
+ case INTERP_CENTRIPETAL_CATMULLROM:
+ return new Geom::Interpolate::CentripetalCatmullRomInterpolator();
default:
return new Geom::Interpolate::Linear();
}
diff --git a/src/live_effects/lpe-powerstroke.cpp b/src/live_effects/lpe-powerstroke.cpp
index 90b01aaa4..b8657e165 100644
--- a/src/live_effects/lpe-powerstroke.cpp
+++ b/src/live_effects/lpe-powerstroke.cpp
@@ -188,7 +188,8 @@ static const Util::EnumData<unsigned> InterpolatorTypeData[] = {
{Geom::Interpolate::INTERP_LINEAR , N_("Linear"), "Linear"},
{Geom::Interpolate::INTERP_CUBICBEZIER , N_("CubicBezierFit"), "CubicBezierFit"},
{Geom::Interpolate::INTERP_CUBICBEZIER_JOHAN , N_("CubicBezierJohan"), "CubicBezierJohan"},
- {Geom::Interpolate::INTERP_SPIRO , N_("SpiroInterpolator"), "SpiroInterpolator"}
+ {Geom::Interpolate::INTERP_SPIRO , N_("SpiroInterpolator"), "SpiroInterpolator"},
+ {Geom::Interpolate::INTERP_CENTRIPETAL_CATMULLROM , N_("Centripetal Catmull-Rom"), "CentripetalCatmullRom"}
};
static const Util::EnumDataConverter<unsigned> InterpolatorTypeConverter(InterpolatorTypeData, sizeof(InterpolatorTypeData)/sizeof(*InterpolatorTypeData));
@@ -219,12 +220,10 @@ enum LineJoinType {
static const Util::EnumData<unsigned> LineJoinTypeData[] = {
{LINEJOIN_BEVEL, N_("Beveled"), "bevel"},
{LINEJOIN_ROUND, N_("Rounded"), "round"},
- {LINEJOIN_EXTRP_MITER, N_("Extrapolated"), "extrapolated"},
+// {LINEJOIN_EXTRP_MITER, N_("Extrapolated"), "extrapolated"}, // disabled because doesn't work well
+ {LINEJOIN_EXTRP_MITER_ARC, N_("Extrapolated arc"), "extrp_arc"},
{LINEJOIN_MITER, N_("Miter"), "miter"},
{LINEJOIN_SPIRO, N_("Spiro"), "spiro"},
-#ifdef LPE_ENABLE_TEST_EFFECTS
- {LINEJOIN_EXTRP_MITER_ARC, N_("Extrapolated arc"), "extrp_arc"},
-#endif
};
static const Util::EnumDataConverter<unsigned> LineJoinTypeConverter(LineJoinTypeData, sizeof(LineJoinTypeData)/sizeof(*LineJoinTypeData));
@@ -406,8 +405,9 @@ static Geom::Path path_from_piecewise_fix_cusps( Geom::Piecewise<Geom::D2<Geom::
break;
}
case LINEJOIN_EXTRP_MITER_ARC: {
- Geom::Circle circle1 = Geom::touching_circle(reverse(B[prev_i]),0.);
- Geom::Circle circle2 = Geom::touching_circle(B[i],0.);
+ // Extrapolate using the curvature at the end of the path segments to join
+ Geom::Circle circle1 = Geom::touching_circle(reverse(B[prev_i]), 0.0);
+ Geom::Circle circle2 = Geom::touching_circle(B[i], 0.0);
Geom::Point points[2];
int solutions = circle_circle_intersection(circle1, circle2, points[0], points[1]);
if (solutions == 2) {
diff --git a/src/live_effects/parameter/path.cpp b/src/live_effects/parameter/path.cpp
index 8095056b7..89947034d 100644
--- a/src/live_effects/parameter/path.cpp
+++ b/src/live_effects/parameter/path.cpp
@@ -143,7 +143,7 @@ gchar *
PathParam::param_getSVGValue() const
{
if (href) {
- return href;
+ return g_strdup(href);
} else {
gchar * svgd = sp_svg_write_path( _pathvector );
return svgd;
diff --git a/src/live_effects/parameter/text.cpp b/src/live_effects/parameter/text.cpp
index fcb2fc9fc..956a001ad 100644
--- a/src/live_effects/parameter/text.cpp
+++ b/src/live_effects/parameter/text.cpp
@@ -85,7 +85,7 @@ TextParam::param_readSVGValue(const gchar * strvalue)
gchar *
TextParam::param_getSVGValue() const
{
- return (gchar *) value.c_str();
+ return g_strdup(value.c_str());
}
Gtk::Widget *
diff --git a/src/object-snapper.cpp b/src/object-snapper.cpp
index 0f7aa6368..9ff6df3bf 100644
--- a/src/object-snapper.cpp
+++ b/src/object-snapper.cpp
@@ -677,7 +677,7 @@ void Inkscape::ObjectSnapper::_snapPathsConstrained(IntermSnapResults &isr,
(*p_inters) = dt->doc2dt(*p_inters);
// Construct a snapped point
Geom::Coord dist = Geom::L2(p.getPoint() - *p_inters);
- SnappedPoint s = SnappedPoint(*p_inters, p.getSourceType(), p.getSourceNum(), k->target_type, dist, getSnapperTolerance(), getSnapperAlwaysSnap(), true, k->target_bbox);;
+ SnappedPoint s = SnappedPoint(*p_inters, p.getSourceType(), p.getSourceNum(), k->target_type, dist, getSnapperTolerance(), getSnapperAlwaysSnap(), true, false, k->target_bbox);
// Store the snapped point
if (dist <= tolerance) { // If the intersection is within snapping range, then we might snap to it
isr.points.push_back(s);
diff --git a/src/selection-chemistry.cpp b/src/selection-chemistry.cpp
index 01ce20509..83ae5a954 100644
--- a/src/selection-chemistry.cpp
+++ b/src/selection-chemistry.cpp
@@ -762,7 +762,7 @@ void sp_selection_group(Inkscape::Selection *selection, SPDesktop *desktop)
sp_selection_group_impl(p, group, xml_doc, doc);
DocumentUndo::done(doc, SP_VERB_SELECTION_GROUP,
- _("Group"));
+ C_("Verb", "Group"));
selection->set(group);
Inkscape::GC::release(group);
diff --git a/src/sp-item-group.cpp b/src/sp-item-group.cpp
index bb52b0c55..5936cfbe5 100644
--- a/src/sp-item-group.cpp
+++ b/src/sp-item-group.cpp
@@ -644,14 +644,41 @@ void SPGroup::translateChildItems(Geom::Translate const &tr)
}
}
-// Recursively scale child items around a point
-void SPGroup::scaleChildItemsRec(Geom::Scale const &sc, Geom::Point const &p)
+// Recursively (or not) scale child items around a point
+void SPGroup::scaleChildItemsRec(Geom::Scale const &sc, Geom::Point const &p, bool noRecurse)
{
if ( hasChildren() ) {
for (SPObject *o = firstChild() ; o ; o = o->getNext() ) {
if ( SP_IS_ITEM(o) ) {
if (SP_IS_GROUP(o) && !SP_IS_BOX3D(o)) {
- SP_GROUP(o)->scaleChildItemsRec(sc, p);
+ /* Using recursion breaks clipping because transforms are applied
+ in coordinates for draws but nothing in defs is changed
+ instead change the transform on the entire group, and the transform
+ is applied after any references to clipping paths. However NOT using
+ recursion apparently breaks as of r13544 other parts of Inkscape
+ involved with showing/modifying units. So offer both for use
+ in different contexts.
+ */
+ if(noRecurse) {
+ // used for EMF import
+ SPItem *item = SP_ITEM(o);
+ Geom::Translate const s(p);
+ Geom::Affine final = s.inverse() * sc * s;
+ Geom::Affine tAff = item->i2dt_affine() * final;
+ item->set_i2d_affine(tAff);
+ tAff = item->transform;
+ // Eliminate common rounding error affecting EMF/WMF input.
+ // When the rounding error persists it converts the simple
+ // transform=scale() to transform=matrix().
+ if(std::abs(tAff[4]) < 1.0e-5 && std::abs(tAff[5]) < 1.0e-5){
+ tAff[4] = 0.0;
+ tAff[5] = 0.0;
+ }
+ item->doWriteTransform(item->getRepr(), tAff, NULL, true);
+ } else {
+ // used for other import
+ SP_GROUP(o)->scaleChildItemsRec(sc, p, false);
+ }
} else {
SPItem *item = SP_ITEM(o);
Geom::OptRect bbox = item->desktopVisualBounds();
diff --git a/src/sp-item-group.h b/src/sp-item-group.h
index 2004a72b8..dd1e9317a 100644
--- a/src/sp-item-group.h
+++ b/src/sp-item-group.h
@@ -52,7 +52,7 @@ public:
LayerMode layerDisplayMode(unsigned int display_key) const;
void setLayerDisplayMode(unsigned int display_key, LayerMode mode);
void translateChildItems(Geom::Translate const &tr);
- void scaleChildItemsRec(Geom::Scale const &sc, Geom::Point const &p);
+ void scaleChildItemsRec(Geom::Scale const &sc, Geom::Point const &p, bool noRecurse);
gint getItemCount() const;
virtual void _showChildren (Inkscape::Drawing &drawing, Inkscape::DrawingItem *ai, unsigned int key, unsigned int flags);
diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt
index 7d80f1e36..2b9dd6e45 100644
--- a/src/ui/CMakeLists.txt
+++ b/src/ui/CMakeLists.txt
@@ -89,7 +89,6 @@ set(ui_SRC
dialog/print.cpp
dialog/symbols.cpp
dialog/xml-tree.cpp
- # dialog/session-player.cpp
dialog/spellcheck.cpp
dialog/svg-fonts-dialog.cpp
dialog/swatches.cpp
@@ -101,9 +100,6 @@ set(ui_SRC
dialog/pixelartdialog.cpp
dialog/transformation.cpp
dialog/undo-history.cpp
- # dialog/whiteboard-connect.cpp
- # dialog/whiteboard-sharewithchat.cpp
- # dialog/whiteboard-sharewithuser.cpp
widget/anchor-selector.cpp
widget/button.cpp
diff --git a/src/ui/dialog/document-properties.cpp b/src/ui/dialog/document-properties.cpp
index 2757a0ec9..1f220b246 100644
--- a/src/ui/dialog/document-properties.cpp
+++ b/src/ui/dialog/document-properties.cpp
@@ -1747,7 +1747,8 @@ void DocumentProperties::onDocUnitChange()
doc->getRoot()->scaleChildItemsRec(Geom::Scale(scale), Geom::Point(-viewscale*doc->getRoot()->viewBox.min()[Geom::X] +
(doc->getWidth().value("px") - viewscale*doc->getRoot()->viewBox.width())/2,
viewscale*doc->getRoot()->viewBox.min()[Geom::Y] +
- (doc->getHeight().value("px") + viewscale*doc->getRoot()->viewBox.height())/2));
+ (doc->getHeight().value("px") + viewscale*doc->getRoot()->viewBox.height())/2),
+ false);
ShapeEditor::blockSetItem(false);
}
prefs->setBool("/options/transform/stroke", transform_stroke);
diff --git a/src/ui/dialog/inkscape-preferences.cpp b/src/ui/dialog/inkscape-preferences.cpp
index 5d065dc60..7d43adc0f 100644
--- a/src/ui/dialog/inkscape-preferences.cpp
+++ b/src/ui/dialog/inkscape-preferences.cpp
@@ -19,6 +19,7 @@
#include "inkscape-preferences.h"
#include <glibmm/i18n.h>
+#include <glibmm/markup.h>
#include <glibmm/miscutils.h>
#include <gtkmm/main.h>
#include <gtkmm/frame.h>
@@ -2054,7 +2055,8 @@ void InkscapePreferences::on_pagelist_selection_changed()
if (!_init) {
prefs->setInt("/dialogs/preferences/page", row[_page_list_columns._col_id]);
}
- _page_title.set_markup("<span size='large'><b>" + row[_page_list_columns._col_name] + "</b></span>");
+ Glib::ustring col_name_escaped = Glib::Markup::escape_text( row[_page_list_columns._col_name] );
+ _page_title.set_markup("<span size='large'><b>" + col_name_escaped + "</b></span>");
_page_frame.add(*_current_page);
_current_page->show();
while (Gtk::Main::events_pending())
diff --git a/src/ui/tools/freehand-base.cpp b/src/ui/tools/freehand-base.cpp
index a90a23a3e..37a170bc9 100644
--- a/src/ui/tools/freehand-base.cpp
+++ b/src/ui/tools/freehand-base.cpp
@@ -247,8 +247,9 @@ static void spdc_apply_powerstroke_shape(const std::vector<Geom::Point> & points
sp_style_unref(style);
}
- char * width_str = new char[50];
- sprintf(width_str, "0,%f", stroke_width / 2.);
+ std::ostringstream s;
+ s.imbue(std::locale::classic());
+ s << "0," << stroke_width / 2.;
// write powerstroke parameters:
lpe->getRepr()->setAttribute("start_linecap_type", "zerowidth");
@@ -257,9 +258,7 @@ static void spdc_apply_powerstroke_shape(const std::vector<Geom::Point> & points
lpe->getRepr()->setAttribute("sort_points", "true");
lpe->getRepr()->setAttribute("interpolator_type", "CubicBezierJohan");
lpe->getRepr()->setAttribute("interpolator_beta", "0.2");
- lpe->getRepr()->setAttribute("offset_points", width_str);
-
- delete [] width_str;
+ lpe->getRepr()->setAttribute("offset_points", s.str().c_str());
}
static void spdc_check_for_and_apply_waiting_LPE(FreehandBase *dc, SPItem *item, SPCurve *curve)
diff --git a/src/widgets/node-toolbar.cpp b/src/widgets/node-toolbar.cpp
index 53161857a..39e0a9be0 100644
--- a/src/widgets/node-toolbar.cpp
+++ b/src/widgets/node-toolbar.cpp
@@ -270,7 +270,7 @@ static void sp_node_path_value_changed(GtkAdjustment *adj, GObject *tbl, Geom::D
}
// quit if run by the attr_changed listener
- if (g_object_get_data( tbl, "freeze" )) {
+ if (g_object_get_data( tbl, "freeze" ) || tracker->isUpdating()) {
return;
}
diff --git a/src/widgets/rect-toolbar.cpp b/src/widgets/rect-toolbar.cpp
index 6996786e3..908e6cc78 100644
--- a/src/widgets/rect-toolbar.cpp
+++ b/src/widgets/rect-toolbar.cpp
@@ -95,7 +95,7 @@ static void sp_rtb_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *
}
// quit if run by the attr_changed listener
- if (g_object_get_data( tbl, "freeze" )) {
+ if (g_object_get_data( tbl, "freeze" ) || tracker->isUpdating()) {
return;
}